bool DoSphericDamage(const Vec3f & pos, float dmg, float radius, DamageArea flags, DamageType typ, EntityHandle numsource) { bool damagesdone = false; if(radius <= 0.f) return damagesdone; float rad = 1.f / radius; bool validsource = ValidIONum(numsource); for(size_t i = 0; i < entities.size(); i++) { const EntityHandle handle = EntityHandle(i); Entity * ioo = entities[handle]; if(!ioo || long(i) == numsource || !ioo->obj) continue; if ((i != 0) && (numsource != PlayerEntityHandle) && validsource && (HaveCommonGroup(ioo, entities[numsource]))) continue; if((ioo->ioflags & IO_CAMERA) || (ioo->ioflags & IO_MARKER)) continue; long count = 0; long count2 = 0; float mindist = std::numeric_limits<float>::max(); for(size_t k = 0; k < ioo->obj->vertexlist.size(); k += 1) { if(ioo->obj->vertexlist.size() < 120) { for(size_t kk = 0; kk < ioo->obj->vertexlist.size(); kk += 1) { if(kk != k) { Vec3f posi = (entities[handle]->obj->vertexlist3[k].v + entities[handle]->obj->vertexlist3[kk].v) * 0.5f; float dist = fdist(pos, posi); if(dist <= radius) { count2++; if(dist < mindist) mindist = dist; } } } } { float dist = fdist(pos, entities[handle]->obj->vertexlist3[k].v); if(dist <= radius) { count++; if(dist < mindist) mindist = dist; } } } float ratio = ((float)count / ((float)ioo->obj->vertexlist.size() * ( 1.0f / 2 ))); if(count2 > count) ratio = ((float)count2 / ((float)ioo->obj->vertexlist.size() * ( 1.0f / 2 ))); if(ratio > 2.f) ratio = 2.f; if(ioo->ioflags & IO_NPC) { if(mindist <= radius + 30.f) { switch (flags) { case DAMAGE_AREA: dmg = dmg * (radius + 30 - mindist) * rad; break; case DAMAGE_AREAHALF: dmg = dmg * (radius + 30 - mindist * ( 1.0f / 2 )) * rad; break; case DAMAGE_FULL: break; } if(i == 0) { if(typ & DAMAGE_TYPE_FIRE) { dmg = ARX_SPELLS_ApplyFireProtection(ioo, dmg); ARX_DAMAGES_IgnitIO(entities.player(), dmg); } if(typ & DAMAGE_TYPE_COLD) { dmg = ARX_SPELLS_ApplyColdProtection(ioo, dmg); } ARX_DAMAGES_DamagePlayer(dmg, typ, numsource); ARX_DAMAGES_DamagePlayerEquipment(dmg); } else { if(typ & DAMAGE_TYPE_FIRE) { dmg = ARX_SPELLS_ApplyFireProtection(ioo, dmg * ratio); ARX_DAMAGES_IgnitIO(ioo, dmg); } if(typ & DAMAGE_TYPE_COLD) { dmg = ARX_SPELLS_ApplyColdProtection(ioo, dmg * ratio); } ARX_DAMAGES_DamageNPC(ioo, dmg * ratio, numsource, true, &pos); } if(dmg > 1) damagesdone = true; } } else { if(mindist <= radius + 30.f) { if(typ & DAMAGE_TYPE_FIRE) { dmg = ARX_SPELLS_ApplyFireProtection(ioo, dmg * ratio); ARX_DAMAGES_IgnitIO(entities[handle], dmg); } if(typ & DAMAGE_TYPE_COLD) { dmg = ARX_SPELLS_ApplyColdProtection(ioo, dmg * ratio); } if(entities[handle]->ioflags & IO_FIX) ARX_DAMAGES_DamageFIX(entities[handle], dmg * ratio, numsource, true); if(dmg > 0.2f) damagesdone = true; } } } if (typ & DAMAGE_TYPE_FIRE) CheckForIgnition(pos, radius, 1); return damagesdone; }
float ARX_DAMAGES_DealDamages(EntityHandle target, float dmg, EntityHandle source, DamageType flags, Vec3f * pos) { if(!ValidIONum(target) || !ValidIONum(source)) return 0; Entity * io_target = entities[target]; Entity * io_source = entities[source]; float damagesdone; if(flags & DAMAGE_TYPE_PER_SECOND) { dmg = dmg * framedelay * ( 1.0f / 1000 ); } if(target == 0) { if(flags & DAMAGE_TYPE_POISON) { if(rnd() * 100.f > player.m_misc.resistPoison) { damagesdone = dmg; player.poison += damagesdone; } else { damagesdone = 0; } } else { if(flags & DAMAGE_TYPE_DRAIN_MANA) { damagesdone = ARX_DAMAGES_DrainMana(io_target, dmg); } else { ARX_DAMAGES_DamagePlayerEquipment(dmg); damagesdone = ARX_DAMAGES_DamagePlayer(dmg, flags, source); } } if(flags & DAMAGE_TYPE_FIRE) ARX_DAMAGES_IgnitIO(io_target, damagesdone); if(flags & DAMAGE_TYPE_DRAIN_LIFE) ARX_DAMAGES_HealInter(io_source, damagesdone); if(flags & DAMAGE_TYPE_DRAIN_MANA) ARX_DAMAGES_HealManaInter(io_source, damagesdone); if(flags & DAMAGE_TYPE_PUSH) ARX_DAMAGES_PushIO(io_target, source, damagesdone * ( 1.0f / 2 )); if((flags & DAMAGE_TYPE_MAGICAL) && !(flags & (DAMAGE_TYPE_FIRE | DAMAGE_TYPE_COLD))) { damagesdone -= player.m_miscFull.resistMagic * ( 1.0f / 100 ) * damagesdone; damagesdone = std::max(0.0f, damagesdone); } return damagesdone; } else { if(io_target->ioflags & IO_NPC) { if(flags & DAMAGE_TYPE_POISON) { if(rnd() * 100.f > io_target->_npcdata->resist_poison) { damagesdone = dmg; io_target->_npcdata->poisonned += damagesdone; } else { damagesdone = 0; } } else { if(flags & DAMAGE_TYPE_FIRE) { if(rnd() * 100.f <= io_target->_npcdata->resist_fire) dmg = 0; ARX_DAMAGES_IgnitIO(io_target, dmg); } if(flags & DAMAGE_TYPE_DRAIN_MANA) { damagesdone = ARX_DAMAGES_DrainMana(io_target, dmg); } else { damagesdone = ARX_DAMAGES_DamageNPC(io_target, dmg, source, true, pos); } } if(flags & DAMAGE_TYPE_DRAIN_LIFE) ARX_DAMAGES_HealInter(io_source, damagesdone); if(flags & DAMAGE_TYPE_DRAIN_MANA) ARX_DAMAGES_HealManaInter(io_source, damagesdone); if(flags & DAMAGE_TYPE_PUSH) ARX_DAMAGES_PushIO(io_target, source, damagesdone * ( 1.0f / 2 )); if((flags & DAMAGE_TYPE_MAGICAL) && !(flags & (DAMAGE_TYPE_FIRE | DAMAGE_TYPE_COLD))) { damagesdone -= io_target->_npcdata->resist_magic * ( 1.0f / 100 ) * damagesdone; damagesdone = std::max(0.0f, damagesdone); } return damagesdone; } } return 0; }
float ARX_EQUIPMENT_ComputeDamages(Entity * io_source, Entity * io_target, float ratioaim, Vec3f * position) { EVENT_SENDER = io_source; SendIOScriptEvent(io_target, SM_AGGRESSION); if(!io_source || !io_target) return 0.f; if(!(io_target->ioflags & IO_NPC)) { if(io_target->ioflags & IO_FIX) { if (io_source == entities.player()) ARX_DAMAGES_DamageFIX(io_target, player.m_miscFull.damages, PlayerEntityHandle, false); else if (io_source->ioflags & IO_NPC) ARX_DAMAGES_DamageFIX(io_target, io_source->_npcdata->damages, io_source->index(), false); else ARX_DAMAGES_DamageFIX(io_target, 1, io_source->index(), false); } return 0.f; } float attack, ac, damages; float backstab = 1.f; std::string _wmat = "bare"; const std::string * wmat = &_wmat; std::string _amat = "flesh"; const std::string * amat = &_amat; bool critical = false; if(io_source == entities.player()) { if(ValidIONum(player.equiped[EQUIP_SLOT_WEAPON])) { Entity * io = entities[player.equiped[EQUIP_SLOT_WEAPON]]; if(io && !io->weaponmaterial.empty()) { wmat = &io->weaponmaterial; } } attack = player.m_miscFull.damages; if(Random::getf(0.f, 100.f) <= player.m_miscFull.criticalHit) { if(SendIOScriptEvent(io_source, SM_CRITICAL) != REFUSE) critical = true; } else critical = false; damages = attack * ratioaim; if(io_target->_npcdata->npcflags & NPCFLAG_BACKSTAB) { if(Random::getf(0.f, 100.f) <= player.m_skillFull.stealth * ( 1.0f / 2 )) { if(SendIOScriptEvent(io_source, SM_BACKSTAB) != REFUSE) backstab = 1.5f; } } } else { if(!(io_source->ioflags & IO_NPC)) // no NPC source... return 0.f; if(!io_source->weaponmaterial.empty()) { wmat = &io_source->weaponmaterial; } if(io_source->_npcdata->weapon) { Entity * iow = io_source->_npcdata->weapon; if(!iow->weaponmaterial.empty()) { wmat = &iow->weaponmaterial; } } attack = io_source->_npcdata->tohit; damages = io_source->_npcdata->damages * ratioaim * Random::getf(0.5f, 1.0f); SpellBase * spell = spells.getSpellOnTarget(io_source->index(), SPELL_CURSE); if(spell) { damages *= (1 - spell->m_level * 0.05f); } if(Random::getf(0.f, 100) <= io_source->_npcdata->critical) { if(SendIOScriptEvent(io_source, SM_CRITICAL) != REFUSE) critical = true; } else critical = false; if(Random::getf(0.f, 100.f) <= (float)io_source->_npcdata->backstab_skill) { if(SendIOScriptEvent(io_source, SM_BACKSTAB) != REFUSE) backstab = 1.5f; } } float absorb; if(io_target == entities.player()) { ac = player.m_miscFull.armorClass; absorb = player.m_skillFull.defense * ( 1.0f / 2 ); } else { ac = ARX_INTERACTIVE_GetArmorClass(io_target); absorb = io_target->_npcdata->absorb; SpellBase * spell = spells.getSpellOnTarget(io_target->index(), SPELL_CURSE); if(spell) { float modif = (1 - spell->m_level * 0.05f); ac *= modif; absorb *= modif; } } if(!io_target->armormaterial.empty()) { amat = &io_target->armormaterial; } if(io_target == entities.player()) { if(ValidIONum(player.equiped[EQUIP_SLOT_ARMOR])) { Entity * io = entities[player.equiped[EQUIP_SLOT_ARMOR]]; if(io && !io->armormaterial.empty()) { amat = &io->armormaterial; } } } float dmgs = damages * backstab; dmgs -= dmgs * absorb * 0.01f; Vec3f pos = io_target->pos; float power = std::min(1.f, dmgs * 0.05f) * 0.1f + 0.9f; ARX_SOUND_PlayCollision(*amat, *wmat, power, 1.f, pos, io_source); float chance = 100.f - (ac - attack); if(Random::getf(0.f, 100.f) > chance) { return 0.f; } ARX_SOUND_PlayCollision("flesh", *wmat, power, 1.f, pos, io_source); if(dmgs > 0.f) { if(critical) { dmgs *= 1.5f; } if(io_target == entities.player()) { // TODO should this be player.pos - player.baseOffset() = player.basePosition()? Vec3f ppos = io_source->pos - (player.pos + player.baseOffset()); ppos = glm::normalize(ppos); // Push the player PUSH_PLAYER_FORCE += ppos * -dmgs * Vec3f(1.0f / 11, 1.0f / 30, 1.0f / 11); ARX_DAMAGES_DamagePlayer(dmgs, 0, io_source->index()); ARX_DAMAGES_DamagePlayerEquipment(dmgs); } else { Vec3f ppos = io_source->pos - io_target->pos; ppos = glm::normalize(ppos); // Push the NPC io_target->forcedmove += ppos * -dmgs; Vec3f * pos = position ? position : &io_target->pos; ARX_DAMAGES_DamageNPC(io_target, dmgs, io_source->index(), false, pos); } } return dmgs; }