static void ARX_TEMPORARY_TrySound(Entity * source, Material collisionMaterial, float volume) { if(source->ioflags & IO_BODY_CHUNK) return; ArxInstant now = arxtime.now(); if(now > source->soundtime) { source->soundcount++; if(source->soundcount < 5) { Material material; if(EEIsUnderWater(source->pos)) material = MATERIAL_WATER; else if(source->material) material = source->material; else material = MATERIAL_STONE; if(volume > 1.f) volume = 1.f; long soundLength = ARX_SOUND_PlayCollision(material, collisionMaterial, volume, 1.f, source->pos, source); source->soundtime = now + ArxDurationMs(soundLength >> 4) + ArxDurationMs(50); }
//----------------------------------------------------------------------------- // Updates all currently launched projectiles void ARX_MISSILES_Update() { TextureContainer * tc = TC_fire; unsigned long tim = (unsigned long)(arxtime); for(unsigned long i(0); i < MAX_MISSILES; i++) { if(missiles[i].type == MISSILE_NONE) continue; long framediff = missiles[i].timecreation + missiles[i].tolive - tim; if(framediff < 0) { ARX_MISSILES_Kill(i); continue; } long framediff3 = tim - missiles[i].timecreation; switch(missiles[i].type) { case MISSILE_NONE: break; case MISSILE_FIREBALL: { Vec3f pos; pos = missiles[i].startpos + missiles[i].velocity * Vec3f(framediff3); if(missiles[i].longinfo != -1) { DynLight[missiles[i].longinfo].pos = pos; } Vec3f orgn = missiles[i].lastpos; Vec3f dest = pos; Vec3f tro = Vec3f(70.f); EERIEPOLY *ep = GetMinPoly(dest.x, dest.y, dest.z); EERIEPOLY *epp = GetMaxPoly(dest.x, dest.y, dest.z); if(closerThan(player.pos, pos, 200.f)) { ARX_MISSILES_Kill(i); ARX_BOOMS_Add(&pos); Add3DBoom(&pos); DoSphericDamage(&dest, 180.0F, 200.0F, DAMAGE_AREAHALF, DAMAGE_TYPE_FIRE | DAMAGE_TYPE_MAGICAL); break; } if(ep && ep->center.y < dest.y) { ARX_MISSILES_Kill(i); ARX_BOOMS_Add(&dest); Add3DBoom(&dest); DoSphericDamage(&dest, 180.0F, 200.0F, DAMAGE_AREAHALF, DAMAGE_TYPE_FIRE | DAMAGE_TYPE_MAGICAL); break; } if(epp && epp->center.y > dest.y) { ARX_MISSILES_Kill(i); ARX_BOOMS_Add(&dest); Add3DBoom(&dest); DoSphericDamage(&dest, 180.0F, 200.0F, DAMAGE_AREAHALF, DAMAGE_TYPE_FIRE | DAMAGE_TYPE_MAGICAL); break; } Vec3f hit; EERIEPOLY *tp = NULL; if(EERIELaunchRay3(&orgn, &dest, &hit, tp, 1)) { ARX_MISSILES_Kill(i); ARX_BOOMS_Add(&hit); Add3DBoom(&hit); DoSphericDamage(&dest, 180.0F, 200.0F, DAMAGE_AREAHALF, DAMAGE_TYPE_FIRE | DAMAGE_TYPE_MAGICAL); break; } if(!EECheckInPoly(&dest) || EEIsUnderWater(&dest)) { ARX_MISSILES_Kill(i); ARX_BOOMS_Add(&dest); Add3DBoom(&dest); DoSphericDamage(&dest, 180.0F, 200.0F, DAMAGE_AREAHALF, DAMAGE_TYPE_FIRE | DAMAGE_TYPE_MAGICAL); break; } long ici = IsCollidingAnyInter(dest.x, dest.y, dest.z, &tro); if(ici != -1 && ici != missiles[i].owner) { ARX_MISSILES_Kill(i); ARX_BOOMS_Add(&dest); Add3DBoom(&dest); DoSphericDamage(&dest, 180.0F, 200.0F, DAMAGE_AREAHALF, DAMAGE_TYPE_FIRE | DAMAGE_TYPE_MAGICAL); break; } PARTICLE_DEF * pd = createParticle(); if(pd) { pd->ov = pos; pd->move = missiles[i].velocity; pd->move += Vec3f(3.f - 6.f * rnd(), 4.f - 12.f * rnd(), 3.f - 6.f * rnd()); pd->tolive = Random::get(500, 1000); pd->tc = tc; pd->siz = 12.f * float(missiles[i].tolive - framediff3) * (1.f / 4000); pd->scale = randomVec(15.f, 20.f); pd->special = FIRE_TO_SMOKE; } missiles[i].lastpos = pos; break; } } missiles[i].lastupdate = tim; } }
//----------------------------------------------------------------------------- // Updates all currently launched projectiles void ARX_MISSILES_Update() { ARX_PROFILE_FUNC(); TextureContainer * tc = TC_fire; unsigned long tim = (unsigned long)(arxtime); for(unsigned long i(0); i < MAX_MISSILES; i++) { if(missiles[i].type == MISSILE_NONE) continue; long framediff = missiles[i].timecreation + missiles[i].tolive - tim; if(framediff < 0) { ARX_MISSILES_Kill(i); continue; } long framediff3 = tim - missiles[i].timecreation; switch(missiles[i].type) { case MISSILE_NONE: break; case MISSILE_FIREBALL: { Vec3f pos; pos = missiles[i].startpos + missiles[i].velocity * Vec3f(framediff3); if(lightHandleIsValid(missiles[i].longinfo)) { EERIE_LIGHT * light = lightHandleGet(missiles[i].longinfo); light->pos = pos; } Vec3f orgn = missiles[i].lastpos; Vec3f dest = pos; Vec3f tro = Vec3f(70.f); EERIEPOLY *ep = GetMinPoly(dest); EERIEPOLY *epp = GetMaxPoly(dest); if(closerThan(player.pos, pos, 200.f)) { ARX_MISSILES_Kill(i); ARX_BOOMS_Add(pos); Add3DBoom(pos); DoSphericDamage(Sphere(dest, 200.0F), 180.0F, DAMAGE_AREAHALF, DAMAGE_TYPE_FIRE | DAMAGE_TYPE_MAGICAL); break; } if(ep && ep->center.y < dest.y) { ARX_MISSILES_Kill(i); ARX_BOOMS_Add(dest); Add3DBoom(dest); DoSphericDamage(Sphere(dest, 200.0F), 180.0F, DAMAGE_AREAHALF, DAMAGE_TYPE_FIRE | DAMAGE_TYPE_MAGICAL); break; } if(epp && epp->center.y > dest.y) { ARX_MISSILES_Kill(i); ARX_BOOMS_Add(dest); Add3DBoom(dest); DoSphericDamage(Sphere(dest, 200.0F), 180.0F, DAMAGE_AREAHALF, DAMAGE_TYPE_FIRE | DAMAGE_TYPE_MAGICAL); break; } Vec3f hit; if(EERIELaunchRay3(orgn, dest, hit, 1)) { ARX_MISSILES_Kill(i); ARX_BOOMS_Add(hit); Add3DBoom(hit); DoSphericDamage(Sphere(dest, 200.0F), 180.0F, DAMAGE_AREAHALF, DAMAGE_TYPE_FIRE | DAMAGE_TYPE_MAGICAL); break; } if(!CheckInPoly(dest) || EEIsUnderWater(dest)) { ARX_MISSILES_Kill(i); ARX_BOOMS_Add(dest); Add3DBoom(dest); DoSphericDamage(Sphere(dest, 200.0F), 180.0F, DAMAGE_AREAHALF, DAMAGE_TYPE_FIRE | DAMAGE_TYPE_MAGICAL); break; } EntityHandle ici = IsCollidingAnyInter(dest, tro); if(ici != EntityHandle() && ici != missiles[i].owner) { ARX_MISSILES_Kill(i); ARX_BOOMS_Add(dest); Add3DBoom(dest); DoSphericDamage(Sphere(dest, 200.0F), 180.0F, DAMAGE_AREAHALF, DAMAGE_TYPE_FIRE | DAMAGE_TYPE_MAGICAL); break; } PARTICLE_DEF * pd = createParticle(); if(pd) { pd->ov = pos; pd->move = missiles[i].velocity; pd->move += Vec3f(3.f, 4.f, 3.f) + Vec3f(-6.f, -12.f, -6.f) * randomVec3f(); pd->tolive = Random::get(500, 1000); pd->tc = tc; pd->siz = 12.f * float(missiles[i].tolive - framediff3) * (1.f / 4000); pd->scale = randomVec(15.f, 20.f); pd->special = FIRE_TO_SMOKE; } missiles[i].lastpos = pos; break; } } missiles[i].lastupdate = tim; } }
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); } } } }
//----------------------------------------------------------------------------- // Updates all currently launched projectiles void ARX_MISSILES_Update() { long framediff, framediff3; Vec3f orgn, dest, hit; TextureContainer * tc = TC_fire; EERIEPOLY *tp = NULL; unsigned long tim = ARXTimeUL(); for (unsigned long i(0); i < MAX_MISSILES; i++) { if (missiles[i].type == MISSILE_NONE) continue; framediff = missiles[i].timecreation + missiles[i].tolive - tim; if (framediff < 0) { ARX_MISSILES_Kill(i); continue; } framediff3 = tim - missiles[i].timecreation; switch (missiles[i].type) { case MISSILE_NONE: break; case MISSILE_FIREBALL: { Vec3f pos; pos = missiles[i].startpos + missiles[i].velocity * framediff3; if (missiles[i].longinfo != -1) { DynLight[missiles[i].longinfo].pos = pos; } #ifdef BUILD_EDITOR if (USE_COLLISIONS) #endif { orgn = missiles[i].lastpos; dest = pos; EERIEPOLY *ep; EERIEPOLY *epp; Vec3f tro; tro.x = 70.0F; tro.y = 70.0F; tro.z = 70.0F; CURRENTINTER = NULL; ep = GetMinPoly(dest.x, dest.y, dest.z); epp = GetMaxPoly(dest.x, dest.y, dest.z); if(closerThan(player.pos, pos, 200.f)) { ARX_MISSILES_Kill(i); ARX_BOOMS_Add(&pos); Add3DBoom(&pos); DoSphericDamage(&dest, 180.0F, 200.0F, DAMAGE_AREAHALF, DAMAGE_TYPE_FIRE | DAMAGE_TYPE_MAGICAL); break; } if (ep && ep->center.y < dest.y) { ARX_MISSILES_Kill(i); ARX_BOOMS_Add(&dest); Add3DBoom(&dest); DoSphericDamage(&dest, 180.0F, 200.0F, DAMAGE_AREAHALF, DAMAGE_TYPE_FIRE | DAMAGE_TYPE_MAGICAL); break; } if (epp && epp->center.y > dest.y) { ARX_MISSILES_Kill(i); ARX_BOOMS_Add(&dest); Add3DBoom(&dest); DoSphericDamage(&dest, 180.0F, 200.0F, DAMAGE_AREAHALF, DAMAGE_TYPE_FIRE | DAMAGE_TYPE_MAGICAL); break; } if (EERIELaunchRay3(&orgn, &dest, &hit, tp, 1)) { ARX_MISSILES_Kill(i); ARX_BOOMS_Add(&hit); Add3DBoom(&hit); DoSphericDamage(&dest, 180.0F, 200.0F, DAMAGE_AREAHALF, DAMAGE_TYPE_FIRE | DAMAGE_TYPE_MAGICAL); break; } if ( !EECheckInPoly(&dest) || EEIsUnderWater(&dest) ) { ARX_MISSILES_Kill(i); ARX_BOOMS_Add(&dest); Add3DBoom(&dest); DoSphericDamage(&dest, 180.0F, 200.0F, DAMAGE_AREAHALF, DAMAGE_TYPE_FIRE | DAMAGE_TYPE_MAGICAL); break; } long ici = IsCollidingAnyInter(dest.x, dest.y, dest.z, &tro); if (ici != -1 && ici != missiles[i].owner) { ARX_MISSILES_Kill(i); ARX_BOOMS_Add(&dest); Add3DBoom(&dest); DoSphericDamage(&dest, 180.0F, 200.0F, DAMAGE_AREAHALF, DAMAGE_TYPE_FIRE | DAMAGE_TYPE_MAGICAL); break; } } long j = ARX_PARTICLES_GetFree(); if (j != -1 && !ARXPausedTimer) { ParticleCount++; particle[j].exist = true; particle[j].zdec = 0; particle[j].ov.x = pos.x; particle[j].ov.y = pos.y; particle[j].ov.z = pos.z; particle[j].move.x = missiles[i].velocity.x + 3.0f - 6.0F * rnd(); particle[j].move.y = missiles[i].velocity.y + 4.0F - 12.0F * rnd(); particle[j].move.z = missiles[i].velocity.z + 3.0F - 6.0F * rnd(); particle[j].timcreation = tim; particle[j].tolive = 500 + (unsigned long)(rnd() * 500.f); particle[j].tc = tc; particle[j].siz = 12.0F * (float)(missiles[i].tolive - framediff3) * ( 1.0f / 4000 ); particle[j].scale.x = 15.0F + rnd() * 5.0F; particle[j].scale.y = 15.0F + rnd() * 5.0F; particle[j].scale.z = 15.0F + rnd() * 5.0F; particle[j].special = FIRE_TO_SMOKE; } missiles[i].lastpos.x = pos.x; missiles[i].lastpos.y = pos.y; missiles[i].lastpos.z = pos.z; break; } } missiles[i].lastupdate = tim; } }