void ARX_PARTICLES_Update(EERIE_CAMERA * cam) { ARX_PROFILE_FUNC(); if(!ACTIVEBKG) { return; } if(ParticleCount == 0) { return; } const ArxInstant now = arxtime.now(); long pcc = ParticleCount; for(size_t i = 0; i < MAX_PARTICLES && pcc > 0; i++) { PARTICLE_DEF * part = &particle[i]; if(!part->exist) { continue; } long framediff = part->timcreation + part->tolive - now; long framediff2 = now - part->timcreation; if(framediff2 < long(part->delay)) { continue; } if(part->delay > 0) { part->timcreation += part->delay; part->delay=0; if((part->m_flags & DELAY_FOLLOW_SOURCE) && part->sourceionum != EntityHandle() && entities[part->sourceionum]) { part->ov = *part->source; Entity * target = entities[part->sourceionum]; Vec3f vector = (part->ov - target->pos) * Vec3f(1.f, 0.5f, 1.f); vector = glm::normalize(vector); part->move = vector * Vec3f(18.f, 5.f, 18.f) + randomVec(-0.5f, 0.5f); } continue; } if(!part->is2D) { EERIE_BKG_INFO * bkgData = getFastBackgroundData(part->ov.x, part->ov.z); if(!bkgData || !bkgData->treat) { part->exist = false; ParticleCount--; continue; } } if(framediff <= 0) { if((part->m_flags & FIRE_TO_SMOKE) && Random::getf() > 0.7f) { part->ov += part->move; part->tolive = part->tolive * 1.375f; part->m_flags &= ~FIRE_TO_SMOKE; part->tc = smokeparticle; part->scale = glm::abs(part->scale * 2.4f); part->rgb = Color3f::gray(.45f); part->move *= 0.5f; part->siz *= 1.f / 3; part->timcreation = now; framediff = part->tolive; } else { part->exist = false; ParticleCount--; continue; } } float val = (part->tolive - framediff) * 0.01f; Vec3f in = part->ov + part->move * val; Vec3f inn = in; if(part->m_flags & GRAVITY) { in.y = inn.y = inn.y + 1.47f * val * val; } float fd = float(framediff2) / float(part->tolive); float r = 1.f - fd; if(part->m_flags & FADE_IN_AND_OUT) { long t = part->tolive / 2; if(framediff2 <= t) { r = float(framediff2) / float(t); } else { r = 1.f - float(framediff2 - t) / float(t); } } if(!part->is2D) { Sphere sp; sp.origin = in; TexturedVertex out; EE_RTP(inn, out); if(out.rhw < 0 || out.p.z > cam->cdepth * fZFogEnd) { continue; } if(part->m_flags & SPLAT_GROUND) { float siz = part->siz + part->scale.x * fd; sp.radius = siz * 10.f; if(CheckAnythingInSphere(sp, EntityHandle_Player, CAS_NO_NPC_COL)) { if(Random::getf() < 0.9f) { Color3f rgb = part->rgb; PolyBoomAddSplat(sp, rgb, 0); } part->exist = false; ParticleCount--; continue; } } if(part->m_flags & SPLAT_WATER) { float siz = part->siz + part->scale.x * fd; sp.radius = siz * Random::getf(10.f, 30.f); if(CheckAnythingInSphere(sp, EntityHandle_Player, CAS_NO_NPC_COL)) { if(Random::getf() < 0.9f) { Color3f rgb = part->rgb * 0.5f; PolyBoomAddSplat(sp, rgb, 2); } part->exist = false; ParticleCount--; continue; } } if((part->m_flags & DISSIPATING) && out.p.z < 0.05f) { out.p.z *= 20.f; r *= out.p.z; } } if(r <= 0.f) { pcc--; continue; } if(part->m_flags & PARTICLE_GOLDRAIN) { float v = Random::getf(-0.1f, 0.1f); if(part->rgb.r + v <= 1.f && part->rgb.r + v > 0.f && part->rgb.g + v <= 1.f && part->rgb.g + v > 0.f && part->rgb.b + v <= 1.f && part->rgb.b + v > 0.f) { part->rgb = Color3f(part->rgb.r + v, part->rgb.g + v, part->rgb.b + v); } } Color color = (part->rgb * r).to<u8>(); if(player.m_improve) { color.g = 0; } TextureContainer * tc = part->tc; if(tc == explo[0] && (part->m_flags & PARTICLE_ANIMATED)) { long animrange = part->cval2 - part->cval1; long num = long(float(framediff2) / float(part->tolive) * animrange); num = glm::clamp(num, long(part->cval1), long(part->cval2)); tc = explo[num]; } float siz = part->siz + part->scale.x * fd; RenderMaterial mat; mat.setTexture(tc); mat.setDepthTest(!(part->m_flags & PARTICLE_NOZBUFFER)); if(part->m_flags & PARTICLE_SUB2) { mat.setBlendType(RenderMaterial::Subtractive2); color.a = glm::clamp(r * 1.5f, 0.f, 1.f) * 255; } else if(part->m_flags & SUBSTRACT) { mat.setBlendType(RenderMaterial::Subtractive); } else { mat.setBlendType(RenderMaterial::Additive); } if(part->m_flags & ROTATING) { if(!part->is2D) { float rott = MAKEANGLE(float(now + framediff2) * part->m_rotation); float temp = (part->zdec) ? 0.0001f : 2.f; float size = std::max(siz, 0.f); EERIEAddSprite(mat, in, size, color, temp, rott); } } else if(part->is2D) { float siz2 = part->siz + part->scale.y * fd; EERIEAddBitmap(mat, in, siz, siz2, tc, color); } else { float temp = (part->zdec) ? 0.0001f : 2.f; EERIEAddSprite(mat, in, siz, color, temp); } pcc--; } }
//TODO Move somewhere else void Cedric_ApplyLightingFirstPartRefactor(Entity *io) { if(!io) return; io->special_color = Color3f::white; float poisonpercent = 0.f; float trappercent = 0.f; float secretpercent = 0.f; if((io->ioflags & IO_NPC) && io->_npcdata->poisonned > 0.f) { poisonpercent = io->_npcdata->poisonned * ( 1.0f / 20 ); if(poisonpercent > 1.f) poisonpercent = 1.f; } if((io->ioflags & IO_ITEM) && io->poisonous > 0.f && io->poisonous_count) { poisonpercent = io->poisonous * (1.0f / 20); if(poisonpercent > 1.f) poisonpercent = 1.f; } if((io->ioflags & IO_FIX) && io->_fixdata->trapvalue > -1) { trappercent = player.TRAP_DETECT - io->_fixdata->trapvalue; if(trappercent > 0.f) { trappercent = 0.6f + trappercent * ( 1.0f / 100 ); trappercent = glm::clamp(trappercent, 0.6f, 1.f); } } if((io->ioflags & IO_FIX) && io->secretvalue > -1) { secretpercent = player.TRAP_SECRET - io->secretvalue; if(secretpercent > 0.f) { secretpercent = 0.6f + secretpercent * ( 1.0f / 100 ); secretpercent = glm::clamp(secretpercent, 0.6f, 1.f); } } if(poisonpercent > 0.f) { io->special_color = Color3f::green; } if(trappercent > 0.f) { io->special_color = Color3f(trappercent, 1.f - trappercent, 1.f - trappercent); } if(secretpercent > 0.f) { io->special_color = Color3f(1.f - secretpercent, 1.f - secretpercent, secretpercent); } if(io->ioflags & IO_FREEZESCRIPT) { io->special_color = Color3f::blue; } if(io->sfx_flag & SFX_TYPE_YLSIDE_DEATH) { if(io->show == SHOW_FLAG_TELEPORTING) { io->sfx_time = io->sfx_time + ArxDurationMs(g_framedelay); if (io->sfx_time >= arxtime.now()) io->sfx_time = arxtime.now(); } else { const ArxDuration elapsed = arxtime.now() - io->sfx_time; if(elapsed > ArxDuration_ZERO) { if(elapsed < ArxDurationMs(3000)) { // 5 seconds to red float ratio = toMs(elapsed) * (1.0f / 3000); io->special_color = Color3f(1.f, 1.f - ratio, 1.f - ratio); io->highlightColor += Color3f(std::max(ratio - 0.5f, 0.f), 0.f, 0.f) * 255; AddRandomSmoke(io, 1); } else if(elapsed < ArxDurationMs(6000)) { // 5 seconds to White float ratio = toMs(elapsed) * (1.0f / 3000); io->special_color = Color3f::red; io->highlightColor += Color3f(std::max(ratio - 0.5f, 0.f), 0.f, 0.f) * 255; AddRandomSmoke(io, 2); } else { // SFX finish io->sfx_time = ArxInstant_ZERO; if(io->ioflags & IO_NPC) { MakePlayerAppearsFX(io); AddRandomSmoke(io, 50); Color3f rgb = io->_npcdata->blood_color.to<float>(); Sphere sp = Sphere(io->pos, 200.f); long count = 6; while(count--) { Sphere splatSphere = Sphere(sp.origin, Random::getf(30.f, 60.f)); PolyBoomAddSplat(splatSphere, rgb, 1); sp.origin.y -= Random::getf(0.f, 150.f); ARX_PARTICLES_Spawn_Splat(sp.origin, 200.f, io->_npcdata->blood_color); sp.origin = io->pos + randomVec3f() * Vec3f(200.f, 20.f,200.f) - Vec3f(100.f, 10.f, 100.f); sp.radius = Random::getf(100.f, 200.f); } EERIE_LIGHT * light = dynLightCreate(); if(light) { light->intensity = Random::getf(0.7f, 2.7f); light->fallend = 600.f; light->fallstart = 400.f; light->rgb = Color3f(1.0f, 0.8f, 0.f); light->pos = io->pos + Vec3f(0.f, -80.f, 0.f); light->duration = ArxDurationMs(600); } if(io->sfx_flag & SFX_TYPE_INCINERATE) { io->sfx_flag &= ~SFX_TYPE_INCINERATE; io->sfx_flag &= ~SFX_TYPE_YLSIDE_DEATH; SpellBase * spell = spells.getSpellOnTarget(io->index(), SPELL_INCINERATE); if(!spell) spell = spells.getSpellOnTarget(io->index(), SPELL_MASS_INCINERATE); if(spell) { spells.endSpell(spell); float damages = 20 * spell->m_level; damages = ARX_SPELLS_ApplyFireProtection(io, damages); if (ValidIONum(spell->m_caster)) ARX_DAMAGES_DamageNPC(io, damages, spell->m_caster, true, &entities[spell->m_caster]->pos); else ARX_DAMAGES_DamageNPC(io, damages, spell->m_caster, true, &io->pos); ARX_SOUND_PlaySFX(SND_SPELL_FIRE_HIT, &io->pos); } } else { io->sfx_flag &= ~SFX_TYPE_YLSIDE_DEATH; ARX_INTERACTIVE_DestroyIOdelayed(io); } } } } } } }
//*********************************************************************************************** // flags & 1 = blood spawn only //----------------------------------------------------------------------------------------------- //*********************************************************************************************** bool ARX_EQUIPMENT_Strike_Check(Entity * io_source, Entity * io_weapon, float ratioaim, long flags, EntityHandle targ) { ARX_PROFILE_FUNC(); arx_assert(io_source); arx_assert(io_weapon); bool ret = false; EntityHandle source = io_source->index(); EntityHandle weapon = io_weapon->index(); EXCEPTIONS_LIST_Pos = 0; float drain_life = ARX_EQUIPMENT_GetSpecialValue(io_weapon, IO_SPECIAL_ELEM_DRAIN_LIFE); float paralyse = ARX_EQUIPMENT_GetSpecialValue(io_weapon, IO_SPECIAL_ELEM_PARALYZE); BOOST_FOREACH(const EERIE_ACTIONLIST & action, io_weapon->obj->actionlist) { float rad = GetHitValue(action.name); if(rad == -1) continue; Sphere sphere; sphere.origin = actionPointPosition(io_weapon->obj, action.idx); sphere.radius = rad; if(source != EntityHandle_Player) sphere.radius += 15.f; std::vector<EntityHandle> sphereContent; if(CheckEverythingInSphere(sphere, source, targ, sphereContent)) { BOOST_FOREACH(const EntityHandle & content, sphereContent) { if(ValidIONum(content) && !(entities[content]->ioflags & IO_BODY_CHUNK)) { bool HIT_SPARK = false; EXCEPTIONS_LIST[EXCEPTIONS_LIST_Pos] = content; EXCEPTIONS_LIST_Pos++; if(EXCEPTIONS_LIST_Pos >= MAX_IN_SPHERE) EXCEPTIONS_LIST_Pos--; Entity * target = entities[content]; Vec3f pos; Color color = Color::white; long hitpoint = -1; float curdist = 999999.f; Vec3f vector = (sphere.origin - target->pos) * Vec3f(1.f, 0.5f, 1.f); vector = glm::normalize(vector); for(size_t ii = 0; ii < target->obj->facelist.size(); ii++) { if(target->obj->facelist[ii].facetype & POLY_HIDE) continue; float d = glm::distance(sphere.origin, target->obj->vertexlist3[target->obj->facelist[ii].vid[0]].v); if(d < curdist) { hitpoint = target->obj->facelist[ii].vid[0]; curdist = d; } } if(hitpoint >= 0) { color = (target->ioflags & IO_NPC) ? target->_npcdata->blood_color : Color::white; pos = target->obj->vertexlist3[hitpoint].v; } else ARX_DEAD_CODE(); float dmgs = 0.f; if(!(flags & 1)) { Vec3f posi; if(hitpoint >= 0) { posi = target->obj->vertexlist3[hitpoint].v; dmgs = ARX_EQUIPMENT_ComputeDamages(io_source, target, ratioaim, &posi); } else { dmgs = ARX_EQUIPMENT_ComputeDamages(io_source, target, ratioaim); } if(target->ioflags & IO_NPC) { ret = true; target->spark_n_blood = 0; target->_npcdata->SPLAT_TOT_NB = 0; if(drain_life > 0.f) { float life_gain = std::min(dmgs, drain_life); life_gain = std::min(life_gain, target->_npcdata->lifePool.current); life_gain = std::max(life_gain, 0.f); ARX_DAMAGES_HealInter(io_source, life_gain); } if(paralyse > 0.f) { ArxDuration ptime = ArxDurationMs(std::min(dmgs * 1000.f, paralyse)); ARX_SPELLS_Launch(SPELL_PARALYSE, weapon, SPELLCAST_FLAG_NOMANA | SPELLCAST_FLAG_NOCHECKCANCAST, 5, content, ptime); } } if(io_source == entities.player()) ARX_DAMAGES_DurabilityCheck(io_weapon, 0.2f); } if(dmgs > 0.f || ((target->ioflags & IO_NPC) && target->spark_n_blood == SP_BLOODY)) { if(target->ioflags & IO_NPC) { target->spark_n_blood = SP_BLOODY; if(!(flags & 1)) { ARX_PARTICLES_Spawn_Splat(pos, dmgs, color); Vec3f vertPos = target->obj->vertexlist3[hitpoint].v; float power = (dmgs * ( 1.0f / 40 )) + 0.7f; Vec3f vect; vect.x = vertPos.x - io_source->pos.x; vect.y = 0; vect.z = vertPos.z - io_source->pos.z; vect = glm::normalize(vect); Sphere sp; sp.origin.x = vertPos.x + vect.x * 30.f; sp.origin.y = vertPos.y; sp.origin.z = vertPos.z + vect.z * 30.f; sp.radius = 3.5f * power * 20; if(CheckAnythingInSphere(sp, EntityHandle_Player, CAS_NO_NPC_COL)) { Color3f rgb = color.to<float>(); Sphere splatSphere; splatSphere.origin = sp.origin; splatSphere.radius = 30.f; PolyBoomAddSplat(splatSphere, rgb, 1); } } ARX_PARTICLES_Spawn_Blood2(pos, dmgs, color, target); } else { if(target->ioflags & IO_ITEM) ParticleSparkSpawn(pos, Random::getu(0, 3), SpawnSparkType_Default); else ParticleSparkSpawn(pos, Random::getu(0, 30), SpawnSparkType_Default); ARX_NPC_SpawnAudibleSound(pos, io_source); if(io_source == entities.player()) HIT_SPARK = true; } } else if((target->ioflags & IO_NPC) && (dmgs <= 0.f || target->spark_n_blood == SP_SPARKING)) { unsigned int nb; if(target->spark_n_blood == SP_SPARKING) nb = Random::getu(0, 3); else nb = 30; if(target->ioflags & IO_ITEM) nb = 1; ParticleSparkSpawn(pos, nb, SpawnSparkType_Default); ARX_NPC_SpawnAudibleSound(pos, io_source); target->spark_n_blood = SP_SPARKING; if(!(target->ioflags & IO_NPC)) HIT_SPARK = true; } else if(dmgs <= 0.f && ((target->ioflags & IO_FIX) || (target->ioflags & IO_ITEM))) { unsigned int nb; if(target->spark_n_blood == SP_SPARKING) nb = Random::getu(0, 3); else nb = 30; if(target->ioflags & IO_ITEM) nb = 1; ParticleSparkSpawn(pos, nb, SpawnSparkType_Default); ARX_NPC_SpawnAudibleSound(pos, io_source); target->spark_n_blood = SP_SPARKING; if (!(target->ioflags & IO_NPC)) HIT_SPARK = true; } if(HIT_SPARK) { if(!io_source->isHit) { ARX_DAMAGES_DurabilityCheck(io_weapon, 1.f); io_source->isHit = true; std::string _weapon_material = "metal"; const std::string * weapon_material = &_weapon_material; if(!io_weapon->weaponmaterial.empty()) { weapon_material = &io_weapon->weaponmaterial; } if(target->material != MATERIAL_NONE) { const char * matStr = ARX_MATERIAL_GetNameById(target->material); ARX_SOUND_PlayCollision(*weapon_material, matStr, 1.f, 1.f, sphere.origin, NULL); } } } } } } const EERIEPOLY * ep = CheckBackgroundInSphere(sphere); if(ep) { if(io_source == entities.player()) { if(!io_source->isHit) { ARX_DAMAGES_DurabilityCheck(io_weapon, 1.f); io_source->isHit = true; std::string _weapon_material = "metal"; const std::string * weapon_material = &_weapon_material; if(!io_weapon->weaponmaterial.empty()) { weapon_material = &io_weapon->weaponmaterial; } std::string bkg_material = "earth"; if(ep && ep->tex && !ep->tex->m_texName.empty()) bkg_material = GetMaterialString(ep->tex->m_texName); ARX_SOUND_PlayCollision(*weapon_material, bkg_material, 1.f, 1.f, sphere.origin, io_source); } } ParticleSparkSpawn(sphere.origin, Random::getu(0, 10), SpawnSparkType_Default); ARX_NPC_SpawnAudibleSound(sphere.origin, io_source); } } return ret; }