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; }
void ARX_THROWN_OBJECT_Manage(unsigned long time_offset) { for(size_t i = 0; i < MAX_THROWN_OBJECTS; i++) { ARX_THROWN_OBJECT *thrownObj = &Thrown[i]; if(!(thrownObj->flags & ATO_EXIST)) continue; { // Is Object Visible & Near ? EERIE_BKG_INFO * bkgData = getFastBackgroundData(thrownObj->position.x, thrownObj->position.z); if(!bkgData || !bkgData->treat) { continue; } // Now render object ! if(!thrownObj->obj) continue; TransformInfo t(thrownObj->position, thrownObj->quat); DrawEERIEInter_ModelTransform(thrownObj->obj, t); if((thrownObj->flags & ATO_FIERY) && (thrownObj->flags & ATO_MOVING) && !(thrownObj->flags & ATO_UNDERWATER)) { LightHandle id = GetFreeDynLight(); if(lightHandleIsValid(id) && framedelay > 0) { EERIE_LIGHT * light = lightHandleGet(id); light->intensity = 1.f; light->fallstart = 100.f; light->fallend = 240.f; light->rgb = Color3f(1.f, .8f, .6f) - randomColor3f() * Color3f(.2f, .2f, .2f); light->pos = thrownObj->position; light->ex_flaresize = 40.f; light->extras |= EXTRAS_FLARE; light->duration = static_cast<long>(framedelay * 0.5f); } float p = 3.f; while(p > 0.f) { p -= 0.5f; if(thrownObj->obj) { long notok = 10; std::vector<EERIE_FACE>::iterator it; while(notok-- > 0) { it = Random::getIterator(thrownObj->obj->facelist); arx_assert(it != thrownObj->obj->facelist.end()); if(it->facetype & POLY_HIDE) continue; notok = -1; } if(notok < 0) { Vec3f pos = thrownObj->obj->vertexlist3[it->vid[0]].v; createFireParticles(pos, 2, 180); } } } } if(thrownObj->pRuban) { thrownObj->pRuban->SetNextPosition(thrownObj->position); thrownObj->pRuban->Update(time_offset); } Vec3f original_pos; if(thrownObj->flags & ATO_MOVING) { long need_kill = 0; float mod = (float)time_offset * thrownObj->velocity; original_pos = thrownObj->position; thrownObj->position.x += thrownObj->vector.x * mod; float gmod = 1.f - thrownObj->velocity; gmod = glm::clamp(gmod, 0.f, 1.f); thrownObj->position.y += thrownObj->vector.y * mod + (time_offset * gmod); thrownObj->position.z += thrownObj->vector.z * mod; CheckForIgnition(Sphere(original_pos, 10.f), 0, 2); Vec3f wpos = thrownObj->position; wpos.y += 20.f; EERIEPOLY * ep = EEIsUnderWater(wpos); if(thrownObj->flags & ATO_UNDERWATER) { if(!ep) { thrownObj->flags &= ~ATO_UNDERWATER; ARX_SOUND_PlaySFX(SND_PLOUF, &thrownObj->position); } } else if(ep) { thrownObj->flags |= ATO_UNDERWATER; ARX_SOUND_PlaySFX(SND_PLOUF, &thrownObj->position); } // Check for collision MUST be done after DRAWING !!!! long nbact = thrownObj->obj->actionlist.size(); for(long j = 0; j < nbact; j++) { float rad = GetHitValue(thrownObj->obj->actionlist[j].name); if(rad == -1) continue; rad *= .5f; const Vec3f v0 = thrownObj->obj->vertexlist3[thrownObj->obj->actionlist[j].idx].v; Vec3f dest = original_pos + thrownObj->vector * 95.f; Vec3f orgn = original_pos - thrownObj->vector * 25.f; EERIEPOLY * ep = CheckArrowPolyCollision(orgn, dest); if(ep) { ARX_PARTICLES_Spawn_Spark(v0, 14, 0); CheckExp(i); if(ValidIONum(thrownObj->source)) ARX_NPC_SpawnAudibleSound(v0, entities[thrownObj->source]); thrownObj->flags &= ~ATO_MOVING; thrownObj->velocity = 0.f; std::string bkg_material = "earth"; if(ep && ep->tex && !ep->tex->m_texName.empty()) bkg_material = GetMaterialString(ep->tex->m_texName); if(ValidIONum(thrownObj->source)) { char weapon_material[64] = "dagger"; ARX_SOUND_PlayCollision(weapon_material, bkg_material, 1.f, 1.f, v0, entities[thrownObj->source]); } thrownObj->position = original_pos; j = 200; } else if(IsPointInField(v0)) { ARX_PARTICLES_Spawn_Spark(v0, 24, 0); CheckExp(i); if (ValidIONum(thrownObj->source)) ARX_NPC_SpawnAudibleSound(v0, entities[thrownObj->source]); thrownObj->flags &= ~ATO_MOVING; thrownObj->velocity = 0.f; if(ValidIONum(thrownObj->source)) { char weapon_material[64] = "dagger"; char bkg_material[64] = "earth"; ARX_SOUND_PlayCollision(weapon_material, bkg_material, 1.f, 1.f, v0, entities[thrownObj->source]); } thrownObj->position = original_pos; j = 200; need_kill = 1; } else { for(float precision = 0.5f; precision <= 6.f; precision += 0.5f) { Sphere sphere; sphere.origin = v0 + thrownObj->vector * precision * 4.5f; sphere.radius = rad + 3.f; std::vector<EntityHandle> sphereContent; if(CheckEverythingInSphere(sphere, thrownObj->source, EntityHandle::Invalid, sphereContent)) { for(size_t jj = 0; jj < sphereContent.size(); jj++) { if(ValidIONum(sphereContent[jj]) && sphereContent[jj] != thrownObj->source) { Entity * target = entities[sphereContent[jj]]; if(target->ioflags & IO_NPC) { Vec3f pos; Color color = Color::none; long hitpoint = -1; float curdist = 999999.f; for(size_t ii = 0 ; ii < target->obj->facelist.size() ; ii++) { if(target->obj->facelist[ii].facetype & POLY_HIDE) continue; short vid = target->obj->facelist[ii].vid[0]; float d = glm::distance(sphere.origin, target->obj->vertexlist3[vid].v); if(d < curdist) { hitpoint = target->obj->facelist[ii].vid[0]; curdist = d; } } if(hitpoint >= 0) { color = target->_npcdata->blood_color; pos = target->obj->vertexlist3[hitpoint].v; } if(thrownObj->source == 0) { float damages = ARX_THROWN_ComputeDamages(i, thrownObj->source, sphereContent[jj]); if(damages > 0.f) { arx_assert(hitpoint >= 0); if(target->ioflags & IO_NPC) { target->_npcdata->SPLAT_TOT_NB = 0; ARX_PARTICLES_Spawn_Blood2(original_pos, damages, color, target); } ARX_PARTICLES_Spawn_Blood2(pos, damages, color, target); ARX_DAMAGES_DamageNPC(target, damages, thrownObj->source, false, &pos); if(Random::getf(0.f, 100.f) > target->_npcdata->resist_poison) { target->_npcdata->poisonned += thrownObj->poisonous; } CheckExp(i); } else { ARX_PARTICLES_Spawn_Spark(v0, 14, 0); ARX_NPC_SpawnAudibleSound(v0, entities[thrownObj->source]); } } } else { // not NPC if(target->ioflags & IO_FIX) { if(ValidIONum(thrownObj->source)) ARX_DAMAGES_DamageFIX(target, 0.1f, thrownObj->source, false); } ARX_PARTICLES_Spawn_Spark(v0, 14, 0); if(ValidIONum(thrownObj->source)) ARX_NPC_SpawnAudibleSound(v0, entities[thrownObj->source]); CheckExp(i); } // Need to deal damages ! thrownObj->flags &= ~ATO_MOVING; thrownObj->velocity = 0.f; need_kill = 1; precision = 500.f; j = 200; } } } } } } if(need_kill) ARX_THROWN_OBJECT_Kill(i); } } } }
void DouseSpell::Launch() { m_duration = ArxDurationMs(500); Vec3f target; if(m_hand_group != ActionPoint()) { target = m_hand_pos; } else { target = m_caster_pos; target.y -= 50.f; } float fPerimeter = 400.f + m_level * 30.f; CheckForIgnition(Sphere(target, fPerimeter), 0, 1); for(size_t ii = 0; ii < g_staticLightsMax; ii++) { EERIE_LIGHT * light = g_staticLights[ii]; if(!light || !(light->extras & EXTRAS_EXTINGUISHABLE)) { continue; } if(!(light->extras & EXTRAS_SEMIDYNAMIC) && !(light->extras & EXTRAS_SPAWNFIRE) && !(light->extras & EXTRAS_SPAWNSMOKE)) { continue; } if(!light->m_ignitionStatus) { continue; } if(!fartherThan(target, light->pos, fPerimeter)) { m_lights.push_back(ii); } } if(player.torch && closerThan(target, player.pos, fPerimeter)) { ARX_PLAYER_ClickedOnTorch(player.torch); } for(size_t k = 0; k < MAX_SPELLS; k++) { SpellBase * spell = spells[SpellHandle(k)]; if(!spell) { continue; } switch(spell->m_type) { case SPELL_FIREBALL: { Vec3f pos = spell->getPosition(); float radius = std::max(m_level * 2.f, 12.f); if(closerThan(target, pos, fPerimeter + radius)) { spell->m_level -= m_level; if(spell->m_level < 1) { spells.endSpell(spell); } } break; } case SPELL_FIRE_FIELD: { Vec3f pos = spell->getPosition(); if(closerThan(target, pos, fPerimeter + 200)) { spell->m_level -= m_level; if(spell->m_level < 1) { spells.endSpell(spell); } } break; } default: break; } } }
void IgnitSpell::Launch() { m_duration = ArxDurationMs(500); if(m_hand_group != ActionPoint()) { m_srcPos = m_hand_pos; } else { m_srcPos = m_caster_pos - Vec3f(0.f, 50.f, 0.f); } EERIE_LIGHT * light = dynLightCreate(); if(light) { light->intensity = 1.8f; light->fallend = 450.f; light->fallstart = 380.f; light->rgb = Color3f(1.f, 0.75f, 0.5f); light->pos = m_srcPos; light->duration = ArxDurationMs(300); } float fPerimeter = 400.f + m_level * 30.f; m_lights.clear(); m_elapsed = ArxDuration_ZERO; CheckForIgnition(Sphere(m_srcPos, fPerimeter), 1, 1); for(size_t ii = 0; ii < g_staticLightsMax; ii++) { EERIE_LIGHT * light = g_staticLights[ii]; if(!light || !(light->extras & EXTRAS_EXTINGUISHABLE)) { continue; } if(m_caster == EntityHandle_Player && (light->extras & EXTRAS_NO_IGNIT)) { continue; } if(!(light->extras & EXTRAS_SEMIDYNAMIC) && !(light->extras & EXTRAS_SPAWNFIRE) && !(light->extras & EXTRAS_SPAWNSMOKE)) { continue; } if(light->m_ignitionStatus) { continue; } if(!fartherThan(m_srcPos, light->pos, fPerimeter)) { T_LINKLIGHTTOFX entry; entry.m_targetLight = ii; EERIE_LIGHT * light = dynLightCreate(entry.m_effectLight); if(light) { light->intensity = Random::getf(0.7f, 2.7f); light->fallend = 400.f; light->fallstart = 300.f; light->rgb = Color3f(1.f, 1.f, 1.f); light->pos = light->pos; } m_lights.push_back(entry); } } for(size_t n = 0; n < MAX_SPELLS; n++) { SpellBase * spell = spells[SpellHandle(n)]; if(!spell) { continue; } if(spell->m_type == SPELL_FIREBALL) { Vec3f pos = static_cast<FireballSpell *>(spell)->getPosition(); float radius = std::max(m_level * 2.f, 12.f); if(closerThan(m_srcPos, pos, fPerimeter + radius)) { spell->m_level += 1; } } } }
void DouseSpell::Launch() { m_duration = 500; Vec3f target; if(m_hand_group >= 0) { target = m_hand_pos; } else { target = m_caster_pos; target.y -= 50.f; } float fPerimeter = 400.f + m_level * 30.f; CheckForIgnition(target, fPerimeter, 0, 1); for(size_t ii = 0; ii < MAX_LIGHTS; ii++) { EERIE_LIGHT * light = GLight[ii]; if(!light || !(light->extras & EXTRAS_EXTINGUISHABLE)) { continue; } if(!(light->extras & EXTRAS_SEMIDYNAMIC) && !(light->extras & EXTRAS_SPAWNFIRE) && !(light->extras & EXTRAS_SPAWNSMOKE)) { continue; } if(!light->m_ignitionStatus) { continue; } if(!fartherThan(target, light->pos, fPerimeter)) { T_LINKLIGHTTOFX entry; entry.iLightNum = ii; entry.poslight = light->pos; m_lights.push_back(entry); } } if(player.torch && closerThan(target, player.pos, fPerimeter)) { ARX_PLAYER_ClickedOnTorch(player.torch); } for(size_t k = 0; k < MAX_SPELLS; k++) { SpellBase * spell = spells[SpellHandle(k)]; if(!spell) { continue; } switch(spell->m_type) { case SPELL_FIREBALL: { CSpellFx * pCSpellFX = spell->m_pSpellFx; if(pCSpellFX) { CFireBall * pCF = (CFireBall *)pCSpellFX; float radius = std::max(m_level * 2.f, 12.f); if(closerThan(target, pCF->eCurPos, fPerimeter + radius)) { spell->m_level -= m_level; if(spell->m_level < 1) { spells.endSpell(spell); } } } break; } case SPELL_FIRE_FIELD: { Vec3f pos; if(GetSpellPosition(&pos, spell)) { if(closerThan(target, pos, fPerimeter + 200)) { spell->m_level -= m_level; if(spell->m_level < 1) { spells.endSpell(spell); } } } break; } default: break; } } }
void IgnitSpell::Launch() { m_duration = 500; if(m_hand_group != -1) { m_srcPos = m_hand_pos; } else { m_srcPos = m_caster_pos - Vec3f(0.f, 50.f, 0.f); } LightHandle id = GetFreeDynLight(); if(lightHandleIsValid(id)) { EERIE_LIGHT * light = lightHandleGet(id); light->intensity = 1.8f; light->fallend = 450.f; light->fallstart = 380.f; light->rgb = Color3f(1.f, 0.75f, 0.5f); light->pos = m_srcPos; light->duration = 300; } float fPerimeter = 400.f + m_level * 30.f; m_lights.clear(); m_elapsed = 0; CheckForIgnition(m_srcPos, fPerimeter, 1, 1); for(size_t ii = 0; ii < MAX_LIGHTS; ii++) { EERIE_LIGHT * light = GLight[ii]; if(!light || !(light->extras & EXTRAS_EXTINGUISHABLE)) { continue; } if(m_caster == PlayerEntityHandle && (light->extras & EXTRAS_NO_IGNIT)) { continue; } if(!(light->extras & EXTRAS_SEMIDYNAMIC) && !(light->extras & EXTRAS_SPAWNFIRE) && !(light->extras & EXTRAS_SPAWNSMOKE)) { continue; } if(light->m_ignitionStatus) { continue; } if(!fartherThan(m_srcPos, light->pos, fPerimeter)) { T_LINKLIGHTTOFX entry; entry.iLightNum = ii; entry.poslight = light->pos; entry.idl = GetFreeDynLight(); if(lightHandleIsValid(entry.idl)) { EERIE_LIGHT * light = lightHandleGet(entry.idl); light->intensity = 0.7f + 2.f * rnd(); light->fallend = 400.f; light->fallstart = 300.f; light->rgb = Color3f(1.f, 1.f, 1.f); light->pos = entry.poslight; } m_lights.push_back(entry); } } for(size_t n = 0; n < MAX_SPELLS; n++) { SpellBase * spell = spells[SpellHandle(n)]; if(!spell) { continue; } if(spell->m_type == SPELL_FIREBALL) { CSpellFx * pCSpellFX = spell->m_pSpellFx; if(pCSpellFX) { CFireBall * pCF = (CFireBall *)pCSpellFX; float radius = std::max(m_level * 2.f, 12.f); if(closerThan(m_srcPos, pCF->eCurPos, fPerimeter + radius)) { spell->m_level += 1; } } } } }