Esempio n. 1
0
// source = -1 no source but valid pos
// source = 0  player
// source > 0  IO
static void ARX_DAMAGES_UpdateDamage(DamageHandle j, float tim) {
	
	DAMAGE_INFO & damage = damages[j];
	
	if(!damage.exist) {
		return;
	}
		
	if(damage.params.flags & DAMAGE_FLAG_FOLLOW_SOURCE) {
		if(damage.params.source == PlayerEntityHandle) {
			damage.params.pos = player.pos;
		} else if (ValidIONum(damage.params.source)) {
			damage.params.pos = entities[damage.params.source]->pos;
		}
	}
	
	float dmg;
	if(damage.params.flags & DAMAGE_NOT_FRAME_DEPENDANT) {
		dmg = damage.params.damages;
	} else if(damage.params.duration == -1) {
		dmg = damage.params.damages;
	} else {
		float FD = (float)framedelay;
		
		if(tim > damage.start_time + damage.params.duration) {
			FD -= damage.start_time + damage.params.duration - tim;
		}
		
		dmg = damage.params.damages * FD * ( 1.0f / 1000 );
	}
	
	bool validsource = ValidIONum(damage.params.source);
	float divradius = 1.f / damage.params.radius;
	
	// checking for IO damages
	for(size_t i = 0; i < entities.size(); i++) {
		const EntityHandle handle = EntityHandle(i);
		Entity * io = entities[handle];
		
		if(io
		   && (io->gameFlags & GFLAG_ISINTREATZONE)
		   && (io->show == SHOW_FLAG_IN_SCENE)
		   && (damage.params.source != long(i)
		   || (damage.params.source == long(i) && !(damage.params.flags & DAMAGE_FLAG_DONT_HURT_SOURCE)))
		){
			if(io->ioflags & IO_NPC) {
				if(   i != 0
				   && damage.params.source != PlayerEntityHandle
				   && validsource
				   && HaveCommonGroup(io, entities[damage.params.source])
				) {
					continue;
				}
				
				Sphere sphere;
				sphere.origin = damage.params.pos;
				sphere.radius = damage.params.radius - 10.f;
				
				if(CheckIOInSphere(sphere, EntityHandle(i), true)) {
					Vec3f sub = io->pos + Vec3f(0.f, -60.f, 0.f);
					
					float dist = fdist(damage.params.pos, sub);
					
					if(damage.params.type & DAMAGE_TYPE_FIELD) {
						if(float(arxtime) > io->collide_door_time + 500) {
							EVENT_SENDER = NULL;
							io->collide_door_time = (unsigned long)(arxtime); 
							char param[64];
							param[0] = 0;
							
							if(damage.params.type & DAMAGE_TYPE_FIRE)
								strcpy(param, "fire");
							
							if(damage.params.type & DAMAGE_TYPE_COLD)
								strcpy(param, "cold");
							
							SendIOScriptEvent(io, SM_COLLIDE_FIELD, param);
						}
					}
					
					switch(damage.params.area) {
						case DAMAGE_AREA: {
							float ratio = (damage.params.radius - dist) * divradius;
							ratio = glm::clamp(ratio, 0.f, 1.f);
							dmg = dmg * ratio + 1.f;
						}
						break;
						case DAMAGE_AREAHALF: {
							float ratio = (damage.params.radius - (dist * ( 1.0f / 2 ))) * divradius;
							ratio = glm::clamp(ratio, 0.f, 1.f);
							dmg = dmg * ratio + 1.f;
						}
						break;
						case DAMAGE_FULL:
						break;
					}
					
					if(dmg <= 0.f)
						continue;
					
					if(   (damage.params.flags & DAMAGE_FLAG_ADD_VISUAL_FX)
					   && (entities[handle]->ioflags & IO_NPC)
					   && (entities[handle]->_npcdata->lifePool.current > 0.f)
					) {
						ARX_DAMAGES_AddVisual(&damage, &sub, dmg, entities[handle]);
					}
					
					if(damage.params.type & DAMAGE_TYPE_DRAIN_MANA) {
						float manadrained;
						
						if(i == 0) {
							manadrained = std::min(dmg, player.manaPool.current);
							player.manaPool.current -= manadrained;
						} else {
							manadrained = dmg;
							
							if(io && io->_npcdata) {
								manadrained = std::min(dmg, io->_npcdata->manaPool.current);
								io->_npcdata->manaPool.current -= manadrained;
							}
						}
						
						if (damage.params.source == PlayerEntityHandle) {
							player.manaPool.current = std::min(player.manaPool.current + manadrained, player.Full_maxmana);
						} else {
							if(ValidIONum(damage.params.source) && (entities[damage.params.source]->_npcdata)) {
								entities[damage.params.source]->_npcdata->manaPool.current = std::min(entities[damage.params.source]->_npcdata->manaPool.current + manadrained, entities[damage.params.source]->_npcdata->manaPool.max);
							}
						}
					} else {
						float damagesdone;
						
						// TODO copy-paste
						if(i == 0) {
							if(damage.params.type & DAMAGE_TYPE_POISON) {
								if(rnd() * 100.f > player.m_misc.resistPoison) {
									// Failed Saving Throw
									damagesdone = dmg; 
									player.poison += damagesdone;
								} else {
									damagesdone = 0;
								}
							} else {
								if(   (damage.params.type & DAMAGE_TYPE_MAGICAL)
								   && !(damage.params.type & DAMAGE_TYPE_FIRE)
								   && !(damage.params.type & DAMAGE_TYPE_COLD)
								) {
									dmg -= player.m_miscFull.resistMagic * ( 1.0f / 100 ) * dmg;
									dmg = std::max(0.0f, dmg);
								}
								if(damage.params.type & DAMAGE_TYPE_FIRE) {
									dmg = ARX_SPELLS_ApplyFireProtection(entities.player(), dmg);
									ARX_DAMAGES_IgnitIO(entities.player(), dmg);
								}
								if(damage.params.type & DAMAGE_TYPE_COLD) {
									dmg = ARX_SPELLS_ApplyColdProtection(entities.player(), dmg);
								}
								damagesdone = ARX_DAMAGES_DamagePlayer(dmg, damage.params.type, damage.params.source);
							}
						} else {
							if(   (entities[handle]->ioflags & IO_NPC)
							   && (damage.params.type & DAMAGE_TYPE_POISON)
							) {
								if(rnd() * 100.f > entities[handle]->_npcdata->resist_poison) {
									// Failed Saving Throw
									damagesdone = dmg; 
									entities[handle]->_npcdata->poisonned += damagesdone;
								} else {
									damagesdone = 0;
								}
							} else {
								if(damage.params.type & DAMAGE_TYPE_FIRE) {
									dmg = ARX_SPELLS_ApplyFireProtection(entities[handle], dmg);
									ARX_DAMAGES_IgnitIO(entities[handle], dmg);
								}
								if(   (damage.params.type & DAMAGE_TYPE_MAGICAL)
								   && !(damage.params.type & DAMAGE_TYPE_FIRE)
								   && !(damage.params.type & DAMAGE_TYPE_COLD)
								) {
									dmg -= entities[handle]->_npcdata->resist_magic * ( 1.0f / 100 ) * dmg;
									dmg = std::max(0.0f, dmg);
								}
								if(damage.params.type & DAMAGE_TYPE_COLD) {
									dmg = ARX_SPELLS_ApplyColdProtection(entities[handle], dmg);
								}
								damagesdone = ARX_DAMAGES_DamageNPC(entities[handle], dmg, damage.params.source, true, &damage.params.pos);
							}
							if(damagesdone > 0 && (damage.params.flags & DAMAGE_SPAWN_BLOOD)) {
								ARX_PARTICLES_Spawn_Blood(&damage.params.pos, damagesdone, damage.params.source);
							}
						}
						if(damage.params.type & DAMAGE_TYPE_DRAIN_LIFE) {
							if(ValidIONum(damage.params.source))
								ARX_DAMAGES_HealInter(entities[damage.params.source], damagesdone);
						}
					}
				}
			} else if((io->ioflags & IO_FIX) && !(damage.params.type & DAMAGE_TYPE_NO_FIX)) {
				Sphere sphere;
				sphere.origin = damage.params.pos;
				sphere.radius = damage.params.radius + 15.f;
				
				if(CheckIOInSphere(sphere, EntityHandle(i))) {
					ARX_DAMAGES_DamageFIX(io, dmg, damage.params.source, true);
				}
			}
		}
	}
	
	if(damage.params.duration == -1)
		damage.exist = false;
	else if(tim > damage.start_time + damage.params.duration)
		damage.exist = false;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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;
}