uint8 CombatManager::_executeAttack(CreatureObject* attacker,CreatureObject* defender,ObjectControllerCmdProperties *cmdProperties,Weapon* weapon) { uint8 randomHitPool = 100; //uint8 randomPoolHitChance = 100; uint8 stateApplied = 0; int32 multipliedDamage = 0; BString combatSpam = "melee"; // first see if we actually hit our target uint8 attackResult = _hitCheck(attacker,defender,cmdProperties,weapon); // only proceed, if so if(!attackResult) { // TODO: retrieve from weapon int32 baseMinDamage = 50; int32 baseMaxDamage = 100; // NOTE: Some weapon data just for tesing and to give the npc a fair chance... if (weapon->hasAttribute("cat_wpn_damage.wpn_damage_min")) { baseMinDamage = weapon->getAttribute<int32>("cat_wpn_damage.wpn_damage_min"); } if (weapon->hasAttribute("cat_wpn_damage.wpn_damage_max")) { baseMaxDamage = weapon->getAttribute<int32>("cat_wpn_damage.wpn_damage_max"); } //Sanity checks of db data if (baseMinDamage < 1) baseMinDamage = 1; if (baseMaxDamage < 1) baseMaxDamage = 1; if(baseMaxDamage <= baseMinDamage) { baseMaxDamage = baseMinDamage +1; } int32 baseDamage = -((gRandom->getRand()%(baseMaxDamage - baseMinDamage)) + baseMinDamage); // apply damage multiplier if(cmdProperties->mDamageMultiplier) { multipliedDamage = static_cast<uint32>(static_cast<float>(baseDamage) * cmdProperties->mDamageMultiplier); } else { multipliedDamage = baseDamage; } // mitigation multipliedDamage = _mitigateDamage(attacker,defender,cmdProperties,multipliedDamage,weapon); // state effects stateApplied = _tryStateEffects(attacker,defender,cmdProperties,weapon); // Here is the deal. When a player makes damage to a npc, we have to register the player, its group, damage done and what (kind of) weapon used. NPCObject* npc = dynamic_cast<NPCObject*>(defender); if (!defender->isDead() && npc) { PlayerObject* player = dynamic_cast<PlayerObject*>(attacker); if (player) { npc->updateDamage(player->getId(), player->getGroupId(), weapon->getGroup(), -multipliedDamage, player->GetPosture(), glm::distance(defender->mPosition, player->mPosition)); } } // ham damage // if no target pool set, pick a random one if(!cmdProperties->mHealthHitChance && !cmdProperties->mActionHitChance && !cmdProperties->mMindHitChance) { switch(gRandom->getRand()%3) { case 0: randomHitPool = HamBar_Health; break; case 1: randomHitPool = HamBar_Action; break; case 2: randomHitPool = HamBar_Mind; break; default: randomHitPool = 0; break; } } auto ham = gWorldManager->getKernel()->GetServiceManager()->GetService<swganh::ham::HamService>("HamService"); //this is pure idiocy in my eyes. Why for gods sake should an object be a creature ? // is there precedent through SOE??????????? if (defender->getCreoGroup() != CreoGroup_AttackableObject) { // random pool attack if(randomHitPool != 100) { ham->UpdateCurrentHitpoints(defender,randomHitPool,multipliedDamage); //defender->getHam()->updatePropertyValue(randomHitPool,HamProperty_CurrentHitpoints,multipliedDamage,true); } // direct pool attack else { // health hit if(cmdProperties->mHealthHitChance) { ham->UpdateCurrentHitpoints(defender,HamBar_Health,multipliedDamage); //defender->getHam()->updatePropertyValue(HamBar_Health,HamProperty_CurrentHitpoints,multipliedDamage,true); } // action hit else if(cmdProperties->mActionHitChance) { ham->UpdateCurrentHitpoints(defender,HamBar_Action,multipliedDamage); //defender->getHam()->updatePropertyValue(HamBar_Action,HamProperty_CurrentHitpoints,multipliedDamage,true); } // mind hit else if(cmdProperties->mMindHitChance) { ham->UpdateCurrentHitpoints(defender,HamBar_Mind,multipliedDamage); //defender->getHam()->updatePropertyValue(HamBar_Mind,HamProperty_CurrentHitpoints,multipliedDamage,true); } } } else { ham->UpdateCurrentHitpoints(defender,HamBar_Health,multipliedDamage); //defender->getHam()->updateSingleHam(multipliedDamage, true); } if (defender->isIncapacitated()) { PlayerObject* playerAttacker = dynamic_cast<PlayerObject*>(attacker); if (playerAttacker && playerAttacker->isConnected()) { gMessageLib->SendSystemMessage(::common::OutOfBand("base_player", "prose_target_incap", 0, defender->getId(), 0), playerAttacker); } } if (defender->isDead()) { PlayerObject* playerAttacker = dynamic_cast<PlayerObject*>(attacker); if (playerAttacker && playerAttacker->isConnected()) { gMessageLib->SendSystemMessage(::common::OutOfBand("base_player", "killer_target_dead"), playerAttacker, true); } } } // fly text and animations // default attack(s) if(cmdProperties->mCmdCrc == 0xa8fef90a) { uint32 animCrc = getDefaultAttackAnimation(weapon->getGroup()); switch(attackResult) { // hit case 0: case 2: case 3: case 4: { gMessageLib->sendCombatAction(attacker,defender,animCrc,0,0,1); } break; // miss case 1: { gMessageLib->sendCombatAction(attacker,defender,animCrc); } break; } } // special attack else { switch(attackResult) { // hit case 0: case 2: case 3: case 4: { gMessageLib->sendCombatAction(attacker,defender,cmdProperties->mAnimationCrc,cmdProperties->mTrail1,cmdProperties->mTrail2,1); } break; //miss case 1: { gMessageLib->sendCombatAction(attacker,defender,cmdProperties->mAnimationCrc,cmdProperties->mTrail1,cmdProperties->mTrail2); } break; } } switch(attackResult) { case 0: { // Defender got hit. } break; case 1: { gMessageLib->sendFlyText(defender,"combat_effects","miss",255,255,255); } break; case 2: // We cant block yet, can we? { gMessageLib->sendFlyText(defender,"combat_effects","block",0,255,0); gMessageLib->sendCombatAction(defender,attacker,0xe430ff04); } break; case 3: { gMessageLib->sendFlyText(defender,"combat_effects","dodge",0,255,0); gMessageLib->sendCombatAction(defender,attacker,0xe430ff04); // Dodge } break; case 4: { gMessageLib->sendFlyText(defender,"combat_effects","counterattack",0,255,0); // I can's see this effect working? } break; } // send combat spam // default attack if(cmdProperties->mCmdCrc == 0xa8fef90a) { combatSpam = getDefaultSpam(weapon->getGroup()); } // special attack else { if(cmdProperties->mCbtSpam.getLength()) { combatSpam = cmdProperties->mCbtSpam.getAnsi(); } } switch(attackResult) { case 0: combatSpam << "_hit"; break; case 1: combatSpam << "_miss"; break; case 2: combatSpam << "_block"; break; case 3: combatSpam << "_evade"; break; case 4: combatSpam << "_counter"; break; default: break; } gMessageLib->sendCombatSpam(attacker,defender,-multipliedDamage,"cbt_spam",combatSpam); return(0); }
// uint8 CombatManager::_executeAttack(CreatureObject* attacker,CreatureObject* defender,ObjectControllerCmdProperties *cmdProperties,Weapon* weapon) uint8 NpcManager::_executeAttack(CreatureObject* attacker,CreatureObject* defender,Weapon* weapon) { uint8 randomHitPool = 100; //uint8 randomPoolHitChance = 100; //uint8 stateApplied = 0; int32 multipliedDamage = 0; BString combatSpam = "melee"; // first see if we actually hit our target // uint8 attackResult = _hitCheck(attacker,defender,cmdProperties,weapon); uint8 attackResult = _hitCheck(attacker,defender,weapon); // only proceed, if so if (!attackResult) { // TODO: retrieve from weapon AttackableCreature* attackerNpc = dynamic_cast<AttackableCreature*>(attacker); if (!attackerNpc) { return 0; } int32 baseMinDamage = attackerNpc->getMinDamage(); int32 baseMaxDamage = attackerNpc->getMaxDamage(); int32 baseDamage = -((gRandom->getRand()%(baseMaxDamage - baseMinDamage)) + baseMinDamage); // apply damage multiplier /* if(cmdProperties->mDamageMultiplier) { multipliedDamage = baseDamage * cmdProperties->mDamageMultiplier; } else { multipliedDamage = baseDamage; } */ multipliedDamage = baseDamage; // mitigation // multipliedDamage = _mitigateDamage(attacker,defender,cmdProperties,multipliedDamage,weapon); // state effects // stateApplied = _tryStateEffects(attacker,defender,cmdProperties,weapon); // ham damage // if no target pool set, pick a random one // if (!cmdProperties->mHealthHitChance && !cmdProperties->mActionHitChance && !cmdProperties->mMindHitChance) { switch(gRandom->getRand()%3) { case 0: randomHitPool = HamBar_Health; break; case 1: randomHitPool = HamBar_Action; break; case 2: randomHitPool = HamBar_Mind; break; default: randomHitPool = 0; break; } } auto ham = gWorldManager->getKernel()->GetServiceManager()->GetService<swganh::ham::HamService>("HamService"); if (defender->getCreoGroup() != CreoGroup_AttackableObject) { // random pool attack if(randomHitPool != 100) { ham->UpdateCurrentHitpoints(defender, randomHitPool, multipliedDamage); } // direct pool attack /* else { // health hit if(cmdProperties->mHealthHitChance) { defender->getHam()->updatePropertyValue(HamBar_Health,HamProperty_CurrentHitpoints,multipliedDamage,true); } // action hit else if(cmdProperties->mActionHitChance) { defender->getHam()->updatePropertyValue(HamBar_Action,HamProperty_CurrentHitpoints,multipliedDamage,true); } // mind hit else if(cmdProperties->mMindHitChance) { defender->getHam()->updatePropertyValue(HamBar_Mind,HamProperty_CurrentHitpoints,multipliedDamage,true); } } */ } else { ham->UpdateCurrentHitpoints(defender, HamBar_Health, multipliedDamage); } /* if (defender->isIncapacitated()) { PlayerObject* playerAttacker = dynamic_cast<PlayerObject*>(attacker); if (playerAttacker && playerAttacker->isConnected()) { if (defender->getType() == ObjType_Player) { int8 str[128]; if (defender->getLastName().getLength()) { sprintf(str,"%s %s", defender->getFirstName().getAnsi(), defender->getLastName().getAnsi()); } else { sprintf(str,"%s", defender->getFirstName().getAnsi()); } BString playerName(str); playerName.convert(BSTRType_Unicode16); gMessageLib->sendSystemMessage(playerAttacker,L"","base_player","prose_target_incap", "", "", L"", 0, "", "", playerName); } else { gMessageLib->sendSystemMessage(playerAttacker,L"","base_player","prose_target_incap", "", "", L"", 0, defender->getSpeciesGroup(), defender->getSpeciesString()); } } } if (defender->isDead()) { PlayerObject* playerAttacker = dynamic_cast<PlayerObject*>(attacker); if (playerAttacker && playerAttacker->isConnected()) { if (defender->getType() == ObjType_Player) { int8 str[128]; if (defender->getLastName().getLength()) { sprintf(str,"%s %s", defender->getFirstName().getAnsi(), defender->getLastName().getAnsi()); } else { sprintf(str,"%s", defender->getFirstName().getAnsi()); } BString playerName(str); playerName.convert(BSTRType_Unicode16); gMessageLib->sendSystemMessage(playerAttacker,L"","base_player","prose_target_dead", "", "", L"", 0, "", "", playerName); } else { gMessageLib->sendSystemMessage(playerAttacker,L"","base_player","prose_target_dead", "", "", L"", 0, defender->getSpeciesGroup(), defender->getSpeciesString()); } } } */ } // fly text and animations // default attack(s) // Assume we only use the default attack for now. // if (cmdProperties->mCmdCrc == 0xa8fef90a) { // This is just a temp fix, we need to solve how to differ creatures from human npc's. uint32 animCrc; if (gWorldConfig->isTutorial()) { animCrc = gCombatManager->getDefaultAttackAnimation(weapon->getGroup()); } else { // creature_attack_light animCrc = 0x8BF5B8B6; } // creature_attack_light 0xB6B8F58B (reversed from WIKI 0x8BF5B8B6) // creature_attack_medium 0x48CBE352 ( 0x52E3CB48 ) // creature_attack_special_1_medium 0x24AEEF7A // creature_attack_special_1_light 0x13E6B2DE // creature_attack_special_2_medium 0x7ACB0D96 // creature_attack_special_2_light 0x205E4B0F // creature_attack_ranged_light 0x8D49FC90 // creature_attack_ranged_medium 0x59E0483C switch(attackResult) { // hit case 0: case 2: case 3: case 4: { gMessageLib->sendCombatAction(attacker,defender,animCrc,0,0,1); } break; // miss case 1: { gMessageLib->sendCombatAction(attacker,defender,animCrc); } break; } } // special attack /* else { switch(attackResult) { // hit case 0:case 2:case 3:case 4: { gMessageLib->sendCombatAction(attacker,defender,cmdProperties->mAnimationCrc,cmdProperties->mTrail1,cmdProperties->mTrail2,1); } break; //miss case 1: { gMessageLib->sendCombatAction(attacker,defender,cmdProperties->mAnimationCrc,cmdProperties->mTrail1,cmdProperties->mTrail2); } break; } } */ switch(attackResult) { case 0: { // Defender got hit. } break; case 1: { gMessageLib->sendFlyText(defender,"combat_effects","miss",255,255,255); } break; case 2: // We cant block yet, can we? { // gMessageLib->sendFlyText(defender,"combat_effects","block",0,255,0); } // break; case 3: { gMessageLib->sendFlyText(defender,"combat_effects","dodge",0,255,0); gMessageLib->sendCombatAction(defender,attacker,0xe430ff04); // Dodge } break; case 4: { gMessageLib->sendFlyText(defender,"combat_effects","counterattack",0,255,0); // I can's see this effect working? } break; } // send combat spam // default attack // if(cmdProperties->mCmdCrc == 0xa8fef90a) { // combatSpam = gCombatManager->getDefaultSpam(weapon->getGroup()); combatSpam = "creature"; } // special attack /* else { if(cmdProperties->mCbtSpam.getLength()) { combatSpam = cmdProperties->mCbtSpam.getAnsi(); } } */ switch(attackResult) { case 0: combatSpam << "_hit"; break; case 1: combatSpam << "_miss"; break; case 2: combatSpam << "_block"; break; case 3: combatSpam << "_evade"; break; case 4: combatSpam << "_counter"; break; default: break; } gMessageLib->sendCombatSpam(attacker,defender,-multipliedDamage,"cbt_spam",combatSpam); return(0); }