class baseCharacter{ constructor( aRole, skills, gender, name, experience, gempukku ){ if( aRole in roleSkills ) this.role = aRole; else this.role = randomFromAssociative(roleSkills); this.gempukku = gempukku || 0; this.stamina = (this.rank() < 1)? 1 : 2 ; this.willpower = (this.rank() < 1)? 1 : 2 ; this.perception = (this.rank() < 1)? 1 : 2 ; this.strength = (this.rank() < 1)? 1 : 2 ; this.reflexes = (this.rank() < 1)? 1 : 2 ; this.awarness = (this.rank() < 1)? 1 : 2 ; this.agility = (this.rank() < 1)? 1 : 2 ; this.intelligence = (this.rank() < 1)? 1 : 2 ; this.void = (this.rank() < 1)? 1 : 2 ; this.skills = ( typeof skills === "object")? skills : {}; this.gender = (typeof gender !== "undefined")? gender : r_gender(); this.name = (name !== "undefined")? { "name" : name, "gender" : gender}: names.randomFromFilters([{ filter : "gender", value : this.gender },{ filter : "gender", value : "n" }]) ; this.experience = (typeof experience === "undefined")? 25 : experience ; this.expandedExperience = 0; this.malus = 0 ; this.actualizeWounds(); this.currentWounds = this.maxWounds; this.actions[ 'attack' ] = { actionType : "complex" }; this.actions[ 'unarmed attack' ] = { actionType : "complex" }; this.actions[ 'move' ] = { actionType : "simple" }; this.actions[ 'draw small' ] = { actionType : "free" }; this.actions[ 'draw medium' ] = { actionType : "simple" }; this.actions[ 'draw large' ] = { actionType : "simple" }; } actions = new Array(); tatoos = new Array(); earth () { return ( this.stamina < this.willpower)? this.stamina : this.willpower ;} water () { return ( this.strength < this.perception)? this.strength : this.perception ;} air () { return ( this.reflexes < this.awarness)? this.reflexes : this.awarness ;} fire () { return ( this.agility < this.intelligence)? this.agility : this.intelligence ;} insight(){ let resultat = (this.earth() + this.water() + this.air() + this.fire() + this.void) * 10 ; if(typeof this.skills == "object") for(let i in this.skills) resultat += parseInt(this.skills[i]); return resultat; } rank(){ let insight = this.insight(); switch( insight ){ case( !this.gempukku ): return 0; break; case ( insight > 150 ): return 1; default : return Math.round((insight - 125)/25); } } skills = {}; skillsFromAction(){ } actionPoints = 2 ; freeAction = false; complexAction(){ if (this.actionPoints >= 2){ this.actionPoints -= 2 ; return true; } return false; } simpleAction(){ if(this.actionPoints > 1){ this.actionPoints -= 1; return true } } freeAction(){ if( this.freeAction ){ return false; }else{ return this.freeAction = true ; } } chooseTatoo(){ }; weapons = { "wakizachi" : weapons["wakizachi"] }; armors = []; equippedArmor = "kimono"; equippedArrow = "willow leaf"; rollMade = {}; baseGetTN(){ let armorTN = 0; let modifier = 0; switch(this.stance){ case "full attack": modifier = -10; break; case "full defense": modifier = this.rollMade["defense"]; break; case "defense": modifier = this.air() + this.getSkillRank( 'defense' ); break; } if ( typeof armors[ this.equippedArmor ].TN !== "undefined") armorTN = armors[ this.equippedArmor ].TN; return 5 + armorTN + (this.reflexes * 5) + modifier; } naturalDR = 0; getName(){ return capitalize( this.name.familly ) + " " + capitalize( this.name.name ); } dr(){ let armorDR = 0; for (var armor in this.equippedArmor) if ( typeof armor.DR !== "undefined") armorDR = armor.DR; return this.naturalDR + armorDR; } addWeapon( weapon ){ if( typeof this.weapons[ weapon ] === "objects" ) return null; this.weapons[ weapon ] = weapons[ weapon ]; }; advantages = []; addAdvantages ( newAdvantage ){ if( typeof this.advantages.find(element => element == newAdvantage ) === "undefined" ){ return null; } let cost; for( advantage in advantages[ newAdvantage ] ) if( this.name.familly in advantages[ newAdvantage ] ){ cost = advantages[ newAdvantage ][ this.name.familly ]; } else if ( this.clan in advantages[ newAdvantage ] ){ advantages[ newAdvantage ][ this.clan ]; } else if ( this.clan in advantages[ newAdvantage ] ){ advantages[ newAdvantage ][ this.role ]; } else { cost = advantages[ newAdvantage ][ "default" ]; } } hasAdvantage( advantage){ if( typeof this.advantages.find(element => element == advantage ) === "undefined" ){ return 0; } return 1; } act( action ){ if( this.actions.indexOf( action ) == -1){ return this.complexAction(); }else{ return this[ actions[ action ].actionType + 'Action' ](); } } baseAttack( attackType ){ let modifier_r = 0; let modifier_k = 0; if( this.stance = "full attack"){ modifier_r = 2; modifier_k = 1; }; if( typeof attackType !== "undefined" ){ }else if( (typeof defaultAttacks === "undefined") || (typeof defaultAttacks.expandedExperience === "undefined") || (defaultAttacks.expandedExperience < this.expandedExperience)){ let attack = Object.keys(this.updateAttacks())[0]; if( attack == "jiujutsu" ){ return {"r" : this.strength + modifier_r, "k" : 1 + modifier_k}; }else{ let skill = 0; if((skill = this.skills[ this.weapons[ attack ].skill ]) in this.skills){ return {"r" : skill[0] + modifier_r, "k" : skill[1] + modifier_k}; } return {"r" : this[skills[weapons[ attack ].skill].trait] + modifier_r, "k" : this[skills[weapons[ attack ].skill].trait] + modifier_k, "x" : 11}; } } return { "r" : this.defaultAttacks[ Object.keys(this.defaultAttacks)[0] ]['attack'].r + modifier_r, "k" : this.defaultAttacks[ Object.keys(this.defaultAttacks)[0] ]['attack'].k + modifier_k }; } attackFromWeapon( weapon ){ let trait = parseInt( this[skills[ this.weapons[weapon].skill ].trait], 10); let skill = parseInt( this.skills[ this.weapons[weapon].skill ], 10) || 0; return({ "r" : trait + skill, "k" : trait, "x" : (skill)? 10: 11}); } damageFromWeapon( weapon ){ if( weapons[ weapon ].type == "bow"){ let arrow = arrows[ this.equippedArrow ]; return { "r" : arrow.r + ( weapon.strength <= this.strength )? weapon.strength : this.strength, "k" : arrow.k} } return({ "r" : parseInt(this.strength, 10) + parseInt(weapons[ weapon ].damage.split("G")[0], 10) , "k" : parseInt(weapons[ weapon ].damage.split("G")[1], 10) }); } damage(){ if( (typeof defaultAttacks === "undefined") || (typeof defaultAttacks.expandedExperience === "undefined") || (defaultAttacks.expandedExperience < this.expandedExperience)){ let weapon = Object.keys(this.updateAttacks())[0] if( weapon == "jiujutsu") return {"r" : this.strength, "k" : 1}; else if( weapon.type == "bow"){ let arrow = arrows[ this.equippedArrow ]; return { "r" : arrow.r + ( bow_strength <= this.strength )? weapon.strength : this.strength, "k" : arrow.k } }else{ let damage = weapons[ weapon ]['damage'].split("G"); return {"r" :damage[0], "k" : damage[1]}; } } return this.defaultAttacks[ (Object.keys( this.defaultAttacks)[0]) ]; } initiative(){ return { "r" : this.rank() + this.reflexes , "k" : this.reflexes }; } getAttack(){ let roll = this.attack(); let modifier_r = 0; let modifier_k = 0; if( this.stance = "full attack"){ modifier_r = 2; modifier_k = 1; } return RNG.rk10(roll.r, roll.k, this.malus); } getInitiative(){ let roll = this.initiative(); return RNG.rk10(roll.r, roll.k); } getDamage(){ let roll = this.damage(); return RNG.rk10(roll.r, roll.k); } getSkillRank( aSkill ){ return this.skills[ aSkill ] || 0; } allAttacks(){ let result = {}; if( "jiujutsu" in this.skills ){ result['jiujutsu'] = { "attack" : { "r" : parseInt(this.agility, 10) + parseInt(this.skills[ 'jiujutsu' ], 10), "k": this.agility }, "damage" : { "r" : this.strength, "k" : 1} }; } for(let i in this.weapons){ result[ i ] = { "attack" : this.attackFromWeapon( i ), "damage" : this.damageFromWeapon( i ) }; } /*(result)*/ return result; } attacking( charac ){ if( this.getAttack() > charac.getTN()){ charac.getWounded ( this.getDamage() ); } } defaultAttacks = {}; attacks(){ if( (typeof defaultAttacks === "undefined") || (typeof defaultAttacks.expandedExperience === "undefined") || (defaultAttacks.expandedExperience < this.expandedExperience)) return this.updateAttacks(); return this.defaultAttacks[1]['attack']; } updateAttacks(){ let bestAttack = 0; let bestDamage = 0; let attacks = this.allAttacks(); for(let i in attacks){ if( !bestAttack ) bestAttack = i ; if( (attacks[i].k > attacks[ bestAttack ].k ) || ((attacks[i].k = attacks[ bestAttack ]) && (attacks[i].r < attacks[ bestAttack ].r )) || ( attacks[i].r < (attacks[ bestAttack ].r + 2 ))){ bestAttack = i ; }; if( !bestDamage ) bestDamage = i ; if( (attacks[i].k > attacks[ bestDamage ].k ) || ((attacks[i].k = attacks[ bestDamage ]) && (attacks[i].r < attacks[ bestDamage ]).r ) || ( attacks[i].r < (attacks[ bestDamage ].r + 2 ))){ bestDamage = i ; }; if( !bestDamage ) bestDamage = i ; } this.defaultAttacks[bestAttack] = attacks[ bestAttack ]; this.defaultAttacks[bestDamage] = attacks[ bestDamage ]; this.defaultAttacks['expandedExperience'] = this.expandedExperience; return this.defaultAttacks; } expanseExperience( value ){ if(!this.experience){ this.experience = 0; return 0; }else if ( value > this.experience){ return 0; } if( typeof value == "undefined"){ this.experience = this.experience - 1; this.expandedExperience = this.expandedExperience + 1; }else{ this.experience = this.experience - value; this.expandedExperience = this.expandedExperience + value; } return value || 1; } increaseSkill( skill ){ if(( typeof this.skills[ skill ] === "number" ) && ( this.skills[ skill ] < 10 )){ var cost = this.skills[ skill ] + 1; if( (this.experience - cost) >= 0 ){ this.expanseExperience( cost ); return this.skills[ skill ]++; } } else { if( this.experience > 0){ this.expanseExperience(); return this.skills[ skill ] = 1; } } return 0; } increaseTrait( trait ){ let factor = ( trait == "void")? 12 : 6 ; let cost = (this[ trait ] + 1) * factor; this.actualizeWounds(); if(this.expanseExperience( cost )) this[ trait ]++; }; actualizeWounds(){ this.maxWounds = 17 * this.earth(); return this.fullHeal; }; fullHeal(){ return this.currentWounds = this.maxWounds; } actualizeMalus(){ switch(this.state){ case "healthy" : this.malus = 0; break; case "nicked" : this.malus = ( this.hasAdvantage( "strength of the earth" ) )? 0 : 3 ; break; case "grazed" : this.malus = ( this.hasAdvantage( "strength of the earth" ) )? 2 : 5 ; break; case "hurt" : this.malus = ( this.hasAdvantage( "strength of the earth" ) )? 7 : 10 ; break; case "injured" : this.malus = ( this.hasAdvantage( "strength of the earth" ) )? 12 : 15 ; break; case "crippled" : this.malus = ( this.hasAdvantage( "strength of the earth" ) )? 17 : 20 ; break; case "down" : this.malus = ( this.hasAdvantage( "strength of the earth" ) )? 37 : 40 ; break; case "out" : this.malus = 100 ; break; case "dead" : this.malus = 1000 ; break; } }; getWounded( wounds ){ let inflicted = wounds - this.dr(); this.currentWounds = this.currentWounds - inflicted; if( this.currentWounds < 1 ) this.state = "dead"; else if( this.currentWounds < (5 * this.earth()) ) this.state = "out"; else if( this.currentWounds < (7 * this.earth()) ) this.state = "down"; else if( this.currentWounds < (9 * this.earth()) ) this.state = "crippled"; else if( this.currentWounds < (11 * this.earth()) ) this.state = "injured"; else if( this.currentWounds < (13 * this.earth()) ) this.state = "hurt"; else if( this.currentWounds < (15 * this.earth()) ) this.state = "grazed"; else if( this.currentWounds < (17 * this.earth()) ) this.state = "nicked"; else if( this.currentWounds < (7 * this.earth()) ) this.state = "healthy"; this.actualizeMalus(); return inflicted; } getHeal( value ){ this.currentWounds = ( value < this.maxWounds)? this.currentWounds + value : this.maxWounds; this.actualizeMalus(); } fullHeal(){ this.currentWounds = this.maxWounds; this.actualizeMalus(); } generate( level, role ){ this.role =( typeof role === "undefined" )? this.role : role ; this.experience = 25 + Math.round(level * 30 + Math.pow(15, level/10)); this.randomTraits( level ); this.randomSkill( level ); this.armedFromSkills(); } getWeaponsKeyword( keyword ){ let result = []; for(let i = 0; i < weapons.length ; i++){ if( keyword in weapons[i].keyword ) result.push( weapons[i] ); } return result ; } getWeaponKeyword( keyword ){ let weapons = getWeaponsKeyword( keyword ); let hasIt = 1; while( hasIt ){ let index = random( weapons.length ); hasIt = this.weapons[ weapons[ index ] ]; if( !hasIt ) this.weapons.push( weapons[ index ] ); } } getRandomWeaponFromSkill( skill ){ if( typeof skill == "unsigned") return null; let results = {}; let atLeastOne = false; for(let weapon in weapons){ if((typeof weapon != "undefined") && (typeof weapons[weapon].skill != "undefined")){ if(weapons[weapon].skill == skill){ atLeastOne = true; results[weapon] = weapons[weapon]; } } } return ( atLeastOne)? randomFromAssociative( results ) : null ; } getWeaponsFromSkills( skills ){ let result = {}; for(let skill in skills){ let weapon = this.getRandomWeaponFromSkill( skill ); if(weapon) Object.assign( result, weapon ); } return result; } armedFromSkills(){ Object.assign( this.weapons, this.getWeaponsFromSkills( this.skills )) ; } allSkills(){ let skillList = roleSkills[ this.role ]; for(let skill in skillList){ skillList[skill].occurrence *= 10; } return Object.assign({}, skillList, skills); } randomSkill(){ let hasMain = 0; let skill ; let skillList = this.allSkills(); while( this.experience > 2 ){ skill = randomFromWeight( skillList ); if( hasMain ){ if( skill == hasMain ){ if(!this.increaseSkill( Object.keys(skill)[0] )){ skill = Object.keys( randomFromWeight( skillList ))[0]; for(let i = 0 ; !this.increaseSkill( skill ) && (i < arrayLength( skillList)); i++ ){ skill = Object.keys( randomFromWeight( skillList ))[0]; }; }; } } else if(( typeof skill !== "undefined" ) && ( skill !== null )){ if( typeof skill.main !== "undefined"){ hasMain = skill; this.increaseSkill( Object.keys(skill)[0] ) ; } } else { this.increaseSkill( Object.keys(skill)[0] ) ; } } } randomFromWeight( skills ){ let weight = []; for(skill in skills) if(typeof skill.occurence !== "undefined") /*size +=*/; } randomTraits( level ){ let pass = level * random(2) + random(2); switch( this.role ){ case "bushi" : while(pass){ let asset = random(3); switch( asset ){ case 0 : if( this.experience >= ((6 * this.increaseTrait("stamina") + (6 * this.increaseTrait("willpower"))))){ this.increaseTrait("willpower"); this.increaseTrait("stamina"); }else this.increaseTrait("void") break; case 1 : this.increaseTrait("strength") ; break; case 2 : this.increaseTrait("reflexes"); break; case 3 : this.increaseTrait("agility"); break; }; pass--; } break; case "shugenja" : switch( random(3) ){ case 0 : while(pass){ this.increaseTrait("stamina") ; this.increaseTrait("willpower");} break; case 1 : while(pass){ this.increaseTrait("perception"); this.increaseTrait("strength") ;} break; case 2 : while(pass){ this.increaseTrait("reflexes") ; this.increaseTrait("awarness") ;} break; case 3 : while(pass){ this.increaseTrait("intelligence") ; this.increaseTrait("agility") ;} break; } break; case "monk" : while(pass){ let asset = random(3); switch( asset ){ case 0 : this.increaseTrait("void") ; break; case 1 : this.increaseTrait("strength") ; this.increaseTrait("agility"); break; case 2 : this.increaseTrait("awarness"); this.increaseTrait("reflexes"); break; case 3 : this.increaseTrait("void"); this.increaseTrait("strength"); break; }; pass--; } break; case "scout" : while(pass){ let asset = random(2); switch( asset ){ case 0 : this.increaseTrait("perception"); this.increaseTrait("strength"); break; case 1 : this.increaseTrait("agility"); break; case 2 : this.increaseTrait("reflexes"); break; }; pass--; } break; case "ninja" : while(pass){ let asset = random(2); switch( asset ){ case 0 : this.increaseTrait("void") break; case 1 : this.increaseTrait("agility") ; break; case 2 : this.increaseTrait("reflexes"); break; }; pass--; } break; } this.actualizeWounds(); } getWounds(){ return this.currentWounds ; } stance = "attack"; switchStance( aStance ){ if( stances.includes( aStance ) ){ this.stance = aStance; }else if( typeof aStance === "undefined" ){ let nextStanceIndex = stances.indexOf( this.stance ) + 1; nextStanceIndex = (nextStanceIndex >= stances.length )? 0 : nextStanceIndex; this.stance = stances[ nextStanceIndex ]; } if( this.stance == "full defense") this.rollMade["defense"] = this.skillRoll( "defense" ) ; } skillRoll( skill ){ let skillRank = this.getSkillRank( "defense" ); let traitRank = this[ skills[skill].trait ]; return RNG.rk10( traitRank + skillRank, traitRank ); } } class Character extends baseCharacter{ constructor( aRole, skills, gender, name, experience, gempukku ){ super( aRole, skills, gender, name, experience, gempukku ); } getTN(){ return this.baseGetTN(); } attack(){ return this.baseAttack(); } } class Samourai extends Character { constructor( aRole, gender, name, familly, school, experience, gempukku, skills){ super( aRole, skills, gender, name, experience, gempukku ); this.setFamilly( familly ); this.setBasicSchool( school ); this.autoWearArmor(); } setFamilly( familly_name ){ let familly = famillies[ familly_name ]; this[ familly.trait ]++; this.name['familly'] = familly_name; } setBasicSchool( school_name ){ let school = basicSchool[ school_name ]; this[ school.trait ]++; for(let i = 0 ; i < school.outfit.weapon.length ; i++){ let weapon = (school.outfit.weapon[ i ] == "any")? Object.keys( randomFromAssociative( weapons ) ) : school.outfit.weapon[ i ]; if( !(weapon in this.weapons) ) this.weapons[ weapon ] = weapons[ weapon ]; } this.armors = school.outfit.armor || this.armors; for( let i = 0; i < school.skills.length ; i++ ){ if( !(school.skills[i] in this.skills) ) this.skills[ school.skills[i] ] = 1; } } autoWearArmor(){ let maxArmor = "kimono"; for(let i = 0 ; i < this.armors.length ; i++){ if( armors[ this.armors[ i ] ].TN > armors[ maxArmor ].TN ){ maxArmor = this.armors[i]; } }; this.equippedArmor = maxArmor; } } class People extends Samourai { constructor( gender, name, familly, school, experience, skills){ super( "people", gender, name, familly, school, experience, 0, skills ); } }