void pkCU::calculateDamage(bool hasCrit) { const pokemon_nonvolatile& cPKNV = getPKNV(); const pokemon_nonvolatile& tPKNV = getTPKNV(); const move_nonvolatile& cMNV = cPKNV.getMove(getICAction()); fpType partitionEnvironmentProbability = (1.0 / (fpType) numRandomEnvironments); damageComponents_t& cDMG = getDamageComponent(); uint32_t power = (hasCrit)?cDMG.damageCrit:cDMG.damage; boost::array<size_t, 2> iREnv = {{ SIZE_MAX, getIBase() }}; for (size_t iEnv = 0; iEnv != numRandomEnvironments; ++iEnv ) { if (numRandomEnvironments > 1) { if ((iEnv + 1) == numRandomEnvironments) { iREnv[1] = getIBase(); } else { duplicateState(iREnv, partitionEnvironmentProbability); } }; // find the mean random value for this partition of the random environment fpType randomValue = (iEnv / (fpType)numRandomEnvironments) + ( 1.0 / (fpType)numRandomEnvironments / 2.0); // scale our random value modifier to 0.85..1.0 randomValue = deScale(randomValue, 1.0, 0.85); uint32_t& actualDamage = getDamageComponent(iREnv[1]).damage; actualDamage = (uint32_t)((fpType)power * randomValue); int result = 0; CALLPLUGIN(result, PLUGIN_ON_CALCULATEDAMAGE, onSetPower_rawType, *this, cMNV, cPKNV, tPKNV, getTMV(), getTTMV(), getPKV(), getTPKV(), actualDamage); // inflict damage caused upon the targetPokemon: getTTMV(iREnv[1]).cModHP(getTPKNV(), -1 * actualDamage); } }
void do_trace_by_pid(Monitor* mon, gpid_t pid) { printf("%d, %d\n", mterp_initIBase(pid, getIBase(pid)), disableJitInitGetCodeAddr(pid, getGetCodeAddrAddress(pid))); printf("[%d],[%d]\n", addMterpOpcodesRange(pid, 0, 0xFFFFFFFF), addDisableJitRange(pid, 0, 0xFFFFFFFF)); gTracingPID = pid; }
void pkCU::evaluateMove_damage() { assert(getStackStage() == STAGE_MOVEBASE); assert(getTPKV().isAlive() && getPKV().isAlive()); // the floor of the stack: everything below this stack value has been evaluated size_t baseFloor = iBase, baseCeil = getStack().size(); const pokemon_nonvolatile& cPKNV = getPKNV(); const pokemon_nonvolatile& tPKNV = getTPKNV(); const move_nonvolatile& cMNV = cPKNV.getMove(getICAction()); const pokemon_base& cPKB = cPKNV.getBase(); const pokemon_base& tPKB = tPKNV.getBase(); const move& cMove = cMNV.getBase(); //Source: http://www.smogon.com/dp/articles/damage_formula /*BasePower = HH × BP × IT × CHG × (MS × WS) × UA × FA*/ // set basePower: //for (/*iBase = baseFloor, baseCeil = getStack().size()*/; iBase != baseCeil; ++iBase) { //if (getStackStage() != STAGE_MOVEBASE) { continue; } advanceStackStage(); uint32_t& basePower = getDamageComponent().damage; basePower = cMove.getPower(); int result = (basePower != UINT8_MAX)?1:0; CALLPLUGIN(result, PLUGIN_ON_SETBASEPOWER, onSetPower_rawType, *this, cMNV, cPKNV, tPKNV, getTMV(), getTTMV(), getPKV(), getTPKV(), basePower); assert(result > 0 && basePower > 0); } // calculate this move's type: for (iBase = baseFloor, baseCeil = getStack().size(); iBase != baseCeil; ++iBase) { if (getStackStage() != STAGE_SETBASEPOWER) { continue; } advanceStackStage(); const type*& cType = getDamageComponent().mType; cType = &cMove.getType(); int result = 0; CALLPLUGIN(result, PLUGIN_ON_SETMOVETYPE, onModifyMoveType_rawType, *this, cMNV, cPKNV, tPKNV, getTMV(), getTTMV(), getPKV(), getTPKV(), cType); } // modify basePower: for (iBase = baseFloor, baseCeil = getStack().size(); iBase != baseCeil; ++iBase) { if (getStackStage() != STAGE_SETMOVETYPE) { continue; } advanceStackStage(); uint32_t& basePower = getDamageComponent().damage; fpType baseModifier = 1.0; int result = 0; CALLPLUGIN(result, PLUGIN_ON_MODIFYBASEPOWER, onModifyPower_rawType, *this, cMNV, cPKNV, tPKNV, getTMV(), getTTMV(), getPKV(), getTPKV(), baseModifier); basePower = (uint32_t)(basePower * baseModifier); } // calculate attack and damage modifiers: uint32_t levelModifier = ((cPKNV.getLevel() * 2) / 5) + 2; for (iBase = baseFloor, baseCeil = getStack().size(); iBase != baseCeil; ++iBase) { if (getStackStage() != STAGE_MODIFYBASEPOWER) { continue; } advanceStackStage(); damageComponents_t& cDamage = getDamageComponent(); size_t attackType; size_t defenseType; if (cMove.getDamageType() == ATK_PHYSICAL) { attackType = FV_ATTACK; defenseType = FV_DEFENSE; } else { attackType = FV_SPATTACK; defenseType = FV_SPDEFENSE; } uint32_t attackPower = getTMV().cGetFV_boosted(cPKNV, attackType); uint32_t attackPowerCrit = std::max(cPKNV.getFV_base(attackType), attackPower); uint32_t defensePower = getTTMV().cGetFV_boosted(tPKNV, defenseType); uint32_t defensePowerCrit = std::min(tPKNV.getFV_base(defenseType), defensePower); // calculate crit first: cDamage.damageCrit = ((levelModifier * cDamage.damage * attackPowerCrit) / 50) / defensePowerCrit; // and regular damage: cDamage.damage = ((levelModifier * cDamage.damage * attackPower) / 50) / defensePower; /* Mod1 = BRN × RL × TVT × SR × FF */ // modifier1: fpType attackPowerModifier = 1.0; int result = 0; CALLPLUGIN(result, PLUGIN_ON_MODIFYATTACKPOWER, onModifyPower_rawType, *this, cMNV, cPKNV, tPKNV, getTMV(), getTTMV(), getPKV(), getTPKV(), attackPowerModifier); // incorporate attack power modifier: cDamage.damage = (uint32_t)(cDamage.damage * attackPowerModifier) + 2; cDamage.damageCrit = (uint32_t)(cDamage.damageCrit * attackPowerModifier) + 2; } // calculate critical hit modifiers: for (iBase = baseFloor, baseCeil = getStack().size(); iBase != baseCeil; ++iBase) { if (getStackStage() != STAGE_MODIFYATTACKPOWER) { continue; } advanceStackStage(); damageComponents_t& cDamage = getDamageComponent(); /* CH - Critical Hit modifier 3 if has sniper ability AND critical hit (mult 1.5) 2 if critical hit (mult 1.0) 1 else */ fpType criticalHitModifier = 2.0; int result = 0; CALLPLUGIN(result, PLUGIN_ON_MODIFYCRITICALPOWER, onModifyPower_rawType, *this, cMNV, cPKNV, tPKNV, getTMV(), getTTMV(), getPKV(), getTPKV(), criticalHitModifier); // incorporate critical power modifier: cDamage.damageCrit = (uint32_t)(cDamage.damageCrit * criticalHitModifier); } // calculate raw damage modifiers: for (iBase = baseFloor, baseCeil = getStack().size(); iBase != baseCeil; ++iBase) { if (getStackStage() != STAGE_MODIFYCRITICALPOWER) { continue; } advanceStackStage(); damageComponents_t& cDamage = getDamageComponent(); /* Mod2 = Other modifier 1.3 if item = life orb 1+.1*n if item = metronome and used the same move n previous times, to a max of n=10 1.5 if attacking with Me First and attacks first (NOTE: SPECIAL BEHAVIOR with life orb / metronome!) 1 else */ fpType rawDamageMultiplier = 1.0; int result = 0; CALLPLUGIN(result, PLUGIN_ON_MODIFYRAWDAMAGE, onModifyPower_rawType, *this, cMNV, cPKNV, tPKNV, getTMV(), getTTMV(), getPKV(), getTPKV(), rawDamageMultiplier); // incorporate critical power modifier: cDamage.damage = (uint32_t)(cDamage.damage * rawDamageMultiplier); cDamage.damageCrit = (uint32_t)(cDamage.damageCrit * rawDamageMultiplier); } // calculate this move's STAB: for (iBase = baseFloor, baseCeil = getStack().size(); iBase != baseCeil; ++iBase) { if (getStackStage() != STAGE_MODIFYRAWDAMAGE) { continue; } advanceStackStage(); damageComponents_t& cDamage = getDamageComponent(); bool hasStab = ((&cPKB.getType(0) == cDamage.mType) || (&cPKB.getType(1) == cDamage.mType)); fpType STABMultiplier = hasStab?1.5:1.0; int result = 0; CALLPLUGIN(result, PLUGIN_ON_MODIFYSTAB, onModifyPower_rawType, *this, cMNV, cPKNV, tPKNV, getTMV(), getTTMV(), getPKV(), getTPKV(), STABMultiplier); // incorporate STAB modifier: cDamage.damage = (uint32_t)(cDamage.damage * STABMultiplier); cDamage.damageCrit = (uint32_t)(cDamage.damageCrit * STABMultiplier); } // calculate the enemy pokemon's type resistance: for (iBase = baseFloor, baseCeil = getStack().size(); iBase != baseCeil; ++iBase) { if (getStackStage() != STAGE_MODIFYSTAB) { continue; } advanceStackStage(); damageComponents_t& cDamage = getDamageComponent(); fpType typeModifier = 1.0; { // type1: typeModifier *= cDamage.mType->getModifier(tPKB.getType(0)); // type 2: typeModifier *= cDamage.mType->getModifier(tPKB.getType(1)); } int result = 0; CALLPLUGIN(result, PLUGIN_ON_SETDEFENSETYPE, onModifyTypePower_rawType, *this, cMNV, cPKNV, tPKNV, *cDamage.mType, getTMV(), getTTMV(), getPKV(), getTPKV(), typeModifier); // incorporate type modifier: cDamage.damage = (uint32_t)(cDamage.damage * typeModifier); cDamage.damageCrit = (uint32_t)(cDamage.damageCrit * typeModifier); } // calculate item resistance modifiers: for (iBase = baseFloor, baseCeil = getStack().size(); iBase != baseCeil; ++iBase) { if (getStackStage() != STAGE_MODIFYTYPERESISTANCE) { continue; } advanceStackStage(); damageComponents_t& cDamage = getDamageComponent(); /* Mod3 = SRF × EB × TL × TRB */ fpType itemModifier = 1.0; int result = 0; CALLPLUGIN(result, PLUGIN_ON_MODIFYITEMPOWER, onModifyPower_rawType, *this, cMNV, cPKNV, tPKNV, getTMV(), getTTMV(), getPKV(), getTPKV(), itemModifier); // incorporate type modifier: cDamage.damage = (uint32_t)(cDamage.damage * itemModifier); cDamage.damageCrit = (uint32_t)(cDamage.damageCrit * itemModifier); } /* Damage Formula = (((((((Level × 2 ÷ 5) + 2) × BasePower × [Sp]Atk ÷ 50) ÷ [Sp]Def) × Mod1) + 2) × CH × Mod2 × R ÷ 100) × STAB × Type1 × Type2 × Mod3 */ // calculate probability to hit, miss: for (iBase = baseFloor, baseCeil = getStack().size(); iBase != baseCeil; ++iBase) { if (getStackStage() != STAGE_MODIFYITEMPOWER) { continue; } advanceStackStage(); fpType& probabilityToHit = getDamageComponent().tProbability; /* probability to hit enemy pokemon */ probabilityToHit = getTMV().cGetAccuracy_boosted(FV_ACCURACY) // lowest is 33% or 1/3 * getTTMV().cGetAccuracy_boosted(FV_EVASION) // highest is 300% or 3 * cMove.getPrimaryAccuracy(); // lowest is 30% // to-hit modifying values: int result = 0; CALLPLUGIN(result, PLUGIN_ON_MODIFYHITPROBABILITY, onModifyPower_rawType, *this, cMNV, cPKNV, tPKNV, getTMV(), getTTMV(), getPKV(), getTPKV(), probabilityToHit); } // evaluate miss(1), hit(0): for (iBase = baseFloor, baseCeil = getStack().size(); iBase != baseCeil; ++iBase) { if (getStackStage() != STAGE_MODIFYHITCHANCE) { continue; } advanceStackStage(); fpType& probabilityToHit = getDamageComponent().tProbability; // bound at MIN 0.033~ ... MAX 1.0 probabilityToHit = std::max(std::min(probabilityToHit, (fpType)1.0), (fpType)0.0); boost::array<size_t, 2> iHEnv = {{ getIBase(), SIZE_MAX }}; // did the move hit its target? Is it possible for the move to miss? if (mostlyGT(probabilityToHit, 0.0)) { // if there's a chance the primary effect will not occur: if (mostlyLT(probabilityToHit, 1.0)) { // duplicate the environment (duplicated environment is the miss environment): duplicateState(iHEnv, (1.0 - probabilityToHit)); } // modify bitmask as the hit effect occuring: getStack()[iHEnv[0]].setHit(getICTeam()); } // end of primary attack hits, and secondary attack is not assured else { // pass-through: no chance to hit or crit stackStage[iBase] = STAGE_POSTDAMAGE; } } // calculate probability to crit: for (iBase = baseFloor, baseCeil = getStack().size(); iBase != baseCeil; ++iBase) { if (getStackStage() != STAGE_EVALUATEHITCHANCE) { continue; } advanceStackStage(); // don't continue to evaluate a stage that has not hit the enemy team: if (!getBase().hasHit(getICTeam())) { stackStage[iBase] = STAGE_POSTDAMAGE; continue; } fpType& probabilityToCrit = getDamageComponent().tProbability; /* Probability to critical hit, if the move has already hit */ probabilityToCrit = getTMV().cGetAccuracy_boosted(FV_CRITICALHIT); // to-crit modifying values: int result = 0; CALLPLUGIN(result, PLUGIN_ON_MODIFYCRITPROBABILITY, onModifyPower_rawType, *this, cMNV, cPKNV, tPKNV, getTMV(), getTTMV(), getPKV(), getTPKV(), probabilityToCrit); } // evaluate crit(2): for (iBase = baseFloor, baseCeil = getStack().size(); iBase != baseCeil; ++iBase) { if (getStackStage() != STAGE_MODIFYCRITCHANCE) { continue; } advanceStackStage(); fpType& probabilityToCrit = getDamageComponent().tProbability; // determine the possibility that the move crit: boost::array<size_t, 2> iCEnv = {{ SIZE_MAX, getIBase() }}; if (mostlyGT(probabilityToCrit, 0.0) ) { if (mostlyLT(probabilityToCrit, 1.0)) { // duplicate the environment (duplicated environment is the crit environment): duplicateState(iCEnv, probabilityToCrit); } // modify bitmask as the crit effect occuring: getStack()[iCEnv[1]].setCrit(getICTeam()); } // even with no chance to crit there's still the possibility of damage } // perform actual damage calculation for (iBase = baseFloor, baseCeil = getStack().size(); iBase != baseCeil; ++iBase) { if (getStackStage() != STAGE_PREDAMAGE) { continue; } advanceStackStage(); if (!getBase().hasHit(getICTeam())) { continue; } calculateDamage(getBase().hasCrit(getICTeam())); } } // end of evaluateMove_damage
void pkCU::evaluateMove_postMove() { assert(getStackStage() == STAGE_POSTMOVE); // the floor of the stack: everything below this stack value has been evaluated size_t baseFloor = iBase, baseCeil = getStack().size(); // the current environment we are evaluating upon. Will be copied, modified and pushed back eventually const pokemon_nonvolatile& cPKNV = getPKNV(); const pokemon_nonvolatile& tPKNV = getTPKNV(); const move_nonvolatile& cMNV = cPKNV.getMove(getICAction()); const move& cMove = cMNV.getBase(); size_t iCTeam = getICTeam(); // effects which occur regardless of a secondary effect occuring, but only if the move hit: //for (/*iBase = baseFloor, baseCeil = getStack().size()*/; iBase != baseCeil; ++iBase) { //if (getStackStage() != STAGE_POSTMOVE) { continue; } advanceStackStage(); int result = 0; CALLPLUGIN(result, PLUGIN_ON_ENDOFMOVE, onEvaluateMove_rawType, *this, cMNV, cPKNV, tPKNV, getTMV(), getTTMV(), getPKV(), getTPKV()); } // POSSIBLE THAT POKEMON MIGHT HAVE DIED IN PREVIOUS STEP // calculate probability to perform secondary: for (iBase = baseFloor, baseCeil = getStack().size(); iBase != baseCeil; ++iBase) { if (getStackStage() != STAGE_PRESECONDARY) { continue; } advanceStackStage(); // special behavior if the teammate is dead: (cannot compute secondary effects) if (!getPKV().isAlive()) { stackStage[iBase] = STAGE_POSTTURN; continue; } // does this move even have a secondary effect? (this check is in-loop because multiple environments could arise from previous call) if (!mostlyGT(cMove.getSecondaryAccuracy(), 0.0)) { stackStage[iBase] = STAGE_POSTSECONDARY; continue; } fpType& secondaryHitProbability = getDamageComponent().tProbability; /* probability to inflict secondary condition*/ secondaryHitProbability = cMove.getSecondaryAccuracy(); // lowest is 10% // to-hit modifying values: int result = 0; CALLPLUGIN(result, PLUGIN_ON_MODIFYSECONDARYPROBABILITY, onModifyPower_rawType, *this, cMNV, cPKNV, tPKNV, getTMV(), getTTMV(), getPKV(), getTPKV(), secondaryHitProbability); } // endOf calculate secondary probability // split environments based on their secondary chance: for (iBase = baseFloor, baseCeil = getStack().size(); iBase != baseCeil; ++iBase) { if (getStackStage() != STAGE_MODIFYSECONDARYHITCHANCE) { continue; } advanceStackStage(); boost::array<size_t, 2> iREnv = {{ getIBase() , SIZE_MAX }}; fpType& secondaryHitProbability = getDamageComponent().tProbability; secondaryHitProbability = std::max(std::min(secondaryHitProbability, (fpType)1.0), (fpType)0.0); // did the ability hit its target? Is it possible for the secondary ability to miss? if (getBase().hasHit(iCTeam) && (mostlyGT(secondaryHitProbability, 0.0))) { // if there's a chance the secondary effect will not occur: if (mostlyLT(secondaryHitProbability, 1.0)) { // duplicate the environment (duplicated environment is the secondary effect missed): duplicateState(iREnv, (1.0 - secondaryHitProbability)); } // modify bitmask as secondary effect occuring: getStack()[iREnv[0]].setSecondary(iCTeam); } // end of primary attack hits, and secondary attack is not assured else { // pass-through: no chance to secondary stackStage[iBase] = STAGE_POSTSECONDARY; continue; } } // calculate effect of secondary, if it occured: for (iBase = baseFloor, baseCeil = getStack().size(); iBase != baseCeil; ++iBase) { if (getStackStage() != STAGE_SECONDARY) { continue; } advanceStackStage(); // add extra effects to the move, such as secondaries and trigger effects if (!getBase().hasSecondary(iCTeam)) { continue; } // parse secondary effect plugins: int result = 0; CALLPLUGIN(result, PLUGIN_ON_SECONDARYEFFECT, onEvaluateMove_rawType, *this, cMNV, cPKNV, tPKNV, getTMV(), getTTMV(), getPKV(), getTPKV()); } // endOf if primary and secondary attacks hit } // endOf evaluateMove_postMove
void pkCU::evaluateMove_script() { assert(getStackStage() == STAGE_MOVEBASE); assert(getTPKV().isAlive() && getPKV().isAlive()); const pokemon_nonvolatile& cPKNV = getPKNV(); const pokemon_nonvolatile& tPKNV = getTPKNV(); const move_nonvolatile& cMNV = cPKNV.getMove(getICAction()); const move& cMove = cMNV.getBase(); // the floor of the stack: everything below this stack value has been evaluated size_t baseFloor = iBase, baseCeil = getStack().size(); // calculate probability to hit, miss: //for (iBase = baseFloor, baseCeil = getStack().size(); iBase != baseCeil; ++iBase) { //if (getStackStage() != STAGE_MOVEBASE) { continue; } stackStage[iBase] = STAGE_MODIFYHITCHANCE; fpType& probabilityToHit = getDamageComponent().tProbability; // TODO: take target into account when calculating probability to hit! /* probability to hit enemy pokemon */ if (cMove.targetsEnemy()) { probabilityToHit = getTMV().cGetAccuracy_boosted(FV_ACCURACY) // lowest is 33% or 3333 / 10000 * getTTMV().cGetAccuracy_boosted(FV_EVASION) // highest is 300% or 3 * cMove.getPrimaryAccuracy(); // lowest is 30% or 30 / 100 } else { probabilityToHit = cMove.getPrimaryAccuracy(); } // to-hit modifying values: int result = 0; CALLPLUGIN(result, PLUGIN_ON_MODIFYHITPROBABILITY, onModifyPower_rawType, *this, cMNV, cPKNV, tPKNV, getTMV(), getTTMV(), getPKV(), getTPKV(), probabilityToHit); } // evaluate miss(1), hit(0), for (iBase = baseFloor, baseCeil = getStack().size(); iBase != baseCeil; ++iBase) { if (getStackStage() != STAGE_MODIFYHITCHANCE) { continue; } stackStage[iBase] = STAGE_PREDAMAGE; fpType& probabilityToHit = getDamageComponent().tProbability; // bound at MIN 0.033~ ... MAX 1.0 probabilityToHit = std::max(std::min(probabilityToHit, (fpType)1.0), (fpType)0.0); boost::array<size_t, 2> iHEnv = {{ getIBase(), SIZE_MAX }}; // did the move hit its target? Is it possible for the move to miss? if (mostlyGT(probabilityToHit, 0.0)) { // if there's a chance the primary effect will not occur: if (mostlyLT(probabilityToHit, 1.0)) { // duplicate the environment (duplicated environment is the miss environment): duplicateState(iHEnv, (1.0 - probabilityToHit)); } // modify bitmask as the hit effect occuring: getStack()[iHEnv[0]].setHit(getICTeam()); } // end of primary attack hits, and secondary attack is not assured else { // pass-through: no chance to hit stackStage[iBase] = STAGE_POSTDAMAGE; } } // perform script: for (iBase = baseFloor, baseCeil = getStack().size(); iBase != baseCeil; ++iBase) { if (getStackStage() != STAGE_PREDAMAGE) { continue; } advanceStackStage(); if (!getBase().hasHit(getICTeam())) { continue; } // parse alternative move plugins: int result = getPKNV().getMove_base(getICAction()).isImplemented()?1:0; // TODO: this check isn't working! CALLPLUGIN(result, PLUGIN_ON_EVALUATEMOVE, onEvaluateMove_rawType, *this, getPKNV().getMove(getICAction()), getPKNV(), getTPKNV(), getTMV(), getTTMV(), getPKV(), getTPKV()); } return; }