//***********************************************************************************************
// 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();
	Sphere sphere;

	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.origin = actionPointPosition(io_weapon->obj, action.idx);
		sphere.radius = rad; 

		if(source != PlayerEntityHandle)
			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))
				{
					long HIT_SPARK = 0;
					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) {
								float ptime = std::min(dmgs * 1000.f, paralyse);
								ARX_SPELLS_Launch(SPELL_PARALYSE, weapon, SPELLCAST_FLAG_NOMANA | SPELLCAST_FLAG_NOCHECKCANCAST
												  , 5, content, (long)(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);

								Sphere sp;
								float power;
								power = (dmgs * ( 1.0f / 40 )) + 0.7f;
								Vec3f vect;
								vect.x = target->obj->vertexlist3[hitpoint].v.x - io_source->pos.x;
								vect.y = 0;
								vect.z = target->obj->vertexlist3[hitpoint].v.z - io_source->pos.z;
								vect = glm::normalize(vect);
								sp.origin.x = target->obj->vertexlist3[hitpoint].v.x + vect.x * 30.f;
								sp.origin.y = target->obj->vertexlist3[hitpoint].v.y;
								sp.origin.z = target->obj->vertexlist3[hitpoint].v.z + vect.z * 30.f;
								sp.radius = 3.5f * power * 20;

								if(CheckAnythingInSphere(sp, PlayerEntityHandle, CAS_NO_NPC_COL)) {
									Color3f rgb = color.to<float>();
									
									Sphere splatSphere;
									splatSphere.origin = sp.origin;
									splatSphere.radius = 30.f;
									SpawnGroundSplat(splatSphere, rgb, 1);
								}
							}

							ARX_PARTICLES_Spawn_Blood2(pos, dmgs, color, target);
						} else {
							if(target->ioflags & IO_ITEM)
								ARX_PARTICLES_Spawn_Spark(pos, Random::get(0, 3), SpawnSparkType_Default);
							else
								ARX_PARTICLES_Spawn_Spark(pos, Random::get(0, 30), SpawnSparkType_Default);

							ARX_NPC_SpawnAudibleSound(pos, io_source);

							if(io_source == entities.player())
								HIT_SPARK = 1;
						}
					} 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::get(0, 3);
						else
							nb = 30;

						if(target->ioflags & IO_ITEM)
							nb = 1;

						ARX_PARTICLES_Spawn_Spark(pos, nb, SpawnSparkType_Default);
						ARX_NPC_SpawnAudibleSound(pos, io_source);
						target->spark_n_blood = SP_SPARKING;

						if(!(target->ioflags & IO_NPC))
							HIT_SPARK = 1;
					} 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::get(0, 3);
						else
							nb = 30;

						if(target->ioflags & IO_ITEM)
							nb = 1;

						ARX_PARTICLES_Spawn_Spark(pos, nb, SpawnSparkType_Default);
						ARX_NPC_SpawnAudibleSound(pos, io_source);
						target->spark_n_blood = SP_SPARKING;

						if (!(target->ioflags & IO_NPC))
							HIT_SPARK = 1;
					}

					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;
								}

								char bkg_material[128];

								if(ARX_MATERIAL_GetNameById(target->material, bkg_material))
									ARX_SOUND_PlayCollision(*weapon_material, bkg_material, 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);
				}
			}

			ARX_PARTICLES_Spawn_Spark(sphere.origin, Random::get(0, 10), SpawnSparkType_Default);
			ARX_NPC_SpawnAudibleSound(sphere.origin, io_source);
		}
	}

	return ret;
}
Example #2
0
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);
		}
		}
	}
}