#include "g_local.h"
bool CanDamage(edict_t *targ, edict_t *inflictor) {
vec3_t dest;
trace_t trace;
if(targ->movetype == MOVETYPE_PUSH) {
VectorAdd(targ->absmin, targ->absmax, dest);
VectorScale(dest, 0.5, dest);
trace =
gi.trace(inflictor->s.cmodel_index, inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
if(trace.fraction == 1.0)
return true;
if(trace.ent == targ)
return true;
return false;
}
trace = gi.trace(inflictor->s.cmodel_index, inflictor->s.origin, vec3_origin, vec3_origin, targ->s.origin, inflictor,
MASK_SOLID);
if(trace.fraction == 1.0)
return true;
VectorCopy(targ->s.origin, dest);
dest[0] += 15.0;
dest[1] += 15.0;
trace =
gi.trace(inflictor->s.cmodel_index, inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
if(trace.fraction == 1.0)
return true;
VectorCopy(targ->s.origin, dest);
dest[0] += 15.0;
dest[1] -= 15.0;
trace =
gi.trace(inflictor->s.cmodel_index, inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
if(trace.fraction == 1.0)
return true;
VectorCopy(targ->s.origin, dest);
dest[0] -= 15.0;
dest[1] += 15.0;
trace =
gi.trace(inflictor->s.cmodel_index, inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
if(trace.fraction == 1.0)
return true;
VectorCopy(targ->s.origin, dest);
dest[0] -= 15.0;
dest[1] -= 15.0;
trace =
gi.trace(inflictor->s.cmodel_index, inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID);
if(trace.fraction == 1.0)
return true;
return false;
}
void Killed(edict_t *targ, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) {
if(ent_read_health(targ)->value < -999) {
dv_set(ent_write_health(targ), -999);
}
targ->enemy = attacker;
if((targ->svflags & SVF_MONSTER) && (targ->deadflag != DEAD_DEAD)) {
if(!(targ->monsterinfo.aiflags & AI_GOOD_GUY)) {
level.killed_monsters++;
if(coop->value && attacker->client)
attacker->client->resp.score++;
if(strcmp(attacker->classname, "monster_medic") == 0)
targ->owner = attacker;
}
}
if(targ->movetype == MOVETYPE_PUSH || targ->movetype == MOVETYPE_STOP ||
targ->movetype == MOVETYPE_NONE) { targ->die(targ, inflictor, attacker, damage, point);
return;
}
if((targ->svflags & SVF_MONSTER) && (targ->deadflag != DEAD_DEAD)) {
targ->touch = NULL;
monster_death_use(targ);
}
targ->die(targ, inflictor, attacker, damage, point);
}
void SpawnDamage(int type, int cmodel_index, vec3_t origin, vec3_t normal, int damage) {
if(damage > 255)
damage = 255;
gi.WriteByte(svc_temp_entity);
gi.WriteByte(type);
gi.WritePosition(origin);
gi.WriteDir(normal);
gi.multicast(cmodel_index, origin, MULTICAST_PVS);
}
static int CheckPowerArmor(edict_t *ent, vec3_t point, vec3_t normal, int damage, int dflags) {
gclient_t *client;
int save;
int power_armor_type;
int index;
int damagePerCell;
int pa_te_type;
int power;
int power_used;
if(!damage)
return 0;
client = ent->client;
if(dflags & DAMAGE_NO_ARMOR)
return 0;
if(client) {
power_armor_type = PowerArmorType(ent);
if(power_armor_type != POWER_ARMOR_NONE) {
index = ITEM_INDEX(FindItem("Cells"));
power = client->pers.inventory[index];
}
} else if(ent->svflags & SVF_MONSTER) {
power_armor_type = ent->monsterinfo.power_armor_type;
power = ent->monsterinfo.power_armor_power;
} else
return 0;
if(power_armor_type == POWER_ARMOR_NONE)
return 0;
if(!power)
return 0;
if(power_armor_type == POWER_ARMOR_SCREEN) {
vec3_t vec;
float dot;
vec3_t forward;
AngleVectors(ent->s.angles, forward, NULL, NULL);
VectorSubtract(point, ent->s.origin, vec);
VectorNormalize(vec);
dot = DotProduct(vec, forward);
if(dot <= 0.3)
return 0;
damagePerCell = 1;
pa_te_type = TE_SCREEN_SPARKS;
damage = damage / 3;
} else {
damagePerCell = 2;
pa_te_type = TE_SHIELD_SPARKS;
damage = (2 * damage) / 3;
}
save = power * damagePerCell;
if(!save)
return 0;
if(save > damage)
save = damage;
SpawnDamage(pa_te_type, ent->s.cmodel_index, point, normal, save);
ent->powerarmor_time = level.time + 0.2;
power_used = save / damagePerCell;
if(client)
client->pers.inventory[index] -= power_used;
else
ent->monsterinfo.power_armor_power -= power_used;
return save;
}
static int CheckArmor(edict_t *ent, vec3_t point, vec3_t normal, int damage, int te_sparks, int dflags) {
gclient_t *client;
int save;
int index;
gitem_t *armor;
if(!damage)
return 0;
client = ent->client;
if(!client)
return 0;
if(dflags & DAMAGE_NO_ARMOR)
return 0;
index = ArmorIndex(ent);
if(!index)
return 0;
armor = GetItemByIndex(index);
if(dflags & DAMAGE_ENERGY)
save = ceil(((gitem_armor_t *)armor->info)->energy_protection * damage);
else
save = ceil(((gitem_armor_t *)armor->info)->normal_protection * damage);
if(save >= client->pers.inventory[index])
save = client->pers.inventory[index];
if(!save)
return 0;
client->pers.inventory[index] -= save;
SpawnDamage(te_sparks, ent->s.cmodel_index, point, normal, save);
return save;
}
void M_ReactToDamage(edict_t *targ, edict_t *attacker) {
if(!(attacker->client) && !(attacker->svflags & SVF_MONSTER))
return;
if(attacker == targ || attacker == targ->enemy)
return;
if(targ->monsterinfo.aiflags & AI_GOOD_GUY) {
if(attacker->client || (attacker->monsterinfo.aiflags & AI_GOOD_GUY))
return;
}
if(attacker->client) {
targ->monsterinfo.aiflags &= ~AI_SOUND_TARGET;
if(targ->enemy && targ->enemy->client) {
if(visible(targ, targ->enemy)) {
targ->oldenemy = attacker;
return;
}
targ->oldenemy = targ->enemy;
}
targ->enemy = attacker;
if(!(targ->monsterinfo.aiflags & AI_DUCKED))
FoundTarget(targ);
return;
}
if(((targ->flags & (FL_FLY | FL_SWIM)) == (attacker->flags & (FL_FLY | FL_SWIM))) &&
(strcmp(targ->classname, attacker->classname) != 0) && (strcmp(attacker->classname, "monster_tank") != 0) &&
(strcmp(attacker->classname, "monster_supertank") != 0) && (strcmp(attacker->classname, "monster_makron") != 0) &&
(strcmp(attacker->classname, "monster_jorg") != 0)) {
if(targ->enemy && targ->enemy->client)
targ->oldenemy = targ->enemy;
targ->enemy = attacker;
if(!(targ->monsterinfo.aiflags & AI_DUCKED))
FoundTarget(targ);
}
else if(attacker->enemy == targ) {
if(targ->enemy && targ->enemy->client)
targ->oldenemy = targ->enemy;
targ->enemy = attacker;
if(!(targ->monsterinfo.aiflags & AI_DUCKED))
FoundTarget(targ);
}
else if(attacker->enemy && attacker->enemy != targ) {
if(targ->enemy && targ->enemy->client)
targ->oldenemy = targ->enemy;
targ->enemy = attacker->enemy;
if(!(targ->monsterinfo.aiflags & AI_DUCKED))
FoundTarget(targ);
}
}
bool CheckTeamDamage(edict_t *targ, edict_t *attacker) {
return false;
}
void T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, int damage,
int knockback, int dflags, int mod) {
gclient_t *client;
int take;
int save;
int asave;
int psave;
int te_sparks;
if(!targ->takedamage)
return;
if((targ != attacker) &&
((deathmatch->value && ((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS))) || coop->value)) {
if(OnSameTeam(targ, attacker)) {
if((int)(dmflags->value) & DF_NO_FRIENDLY_FIRE)
damage = 0;
else
mod |= MOD_FRIENDLY_FIRE;
}
}
meansOfDeath = mod;
if(skill->value == 0 && deathmatch->value == 0 && targ->client) {
damage *= 0.5;
if(!damage)
damage = 1;
}
client = targ->client;
if(dflags & DAMAGE_BULLET)
te_sparks = TE_BULLET_SPARKS;
else
te_sparks = TE_SPARKS;
VectorNormalize(dir);
if(!(dflags & DAMAGE_RADIUS) && (targ->svflags & SVF_MONSTER) && (attacker->client) && (!targ->enemy) &&
(ent_read_health(targ)->value > 0))
damage *= 2;
if(targ->flags & FL_NO_KNOCKBACK)
knockback = 0;
if(!(dflags & DAMAGE_NO_KNOCKBACK)) {
if((knockback) && (targ->movetype != MOVETYPE_NONE) && (targ->movetype != MOVETYPE_BOUNCE) &&
(targ->movetype != MOVETYPE_PUSH) && (targ->movetype != MOVETYPE_STOP)) {
vec3_t kvel;
float mass;
if(targ->mass < 50)
mass = 50;
else
mass = targ->mass;
if(targ->client && attacker == targ)
VectorScale(dir, 1600.0 * (float)knockback / mass, kvel); else
VectorScale(dir, 500.0 * (float)knockback / mass, kvel);
VectorAdd(targ->velocity, kvel, targ->velocity);
}
}
take = damage;
save = 0;
if((targ->flags & FL_GODMODE) && !(dflags & DAMAGE_NO_PROTECTION)) {
take = 0;
save = damage;
SpawnDamage(te_sparks, targ->s.cmodel_index, point, normal, save);
}
if((client && client->invincible_framenum > level.framenum) && !(dflags & DAMAGE_NO_PROTECTION)) {
if(targ->pain_debounce_time < level.time) {
gi.sound(targ, CHAN_ITEM, gi.soundindex("items/protect4.wav"), 1, ATTN_NORM, 0);
targ->pain_debounce_time = level.time + 2;
}
take = 0;
save = damage;
}
psave = CheckPowerArmor(targ, point, normal, take, dflags);
take -= psave;
asave = CheckArmor(targ, point, normal, take, te_sparks, dflags);
take -= asave;
asave += save;
if(!(dflags & DAMAGE_NO_PROTECTION) && CheckTeamDamage(targ, attacker))
return;
if(take) {
if((targ->svflags & SVF_MONSTER) || (client))
SpawnDamage(TE_BLOOD, targ->s.cmodel_index, point, normal, take);
else
SpawnDamage(te_sparks, targ->s.cmodel_index, point, normal, take);
dv_adjust(ent_write_health(targ), level.time, -take, cv_get(ent_read_max_health(targ)));
if(ent_read_health(targ)->value <= 0) {
if((targ->svflags & SVF_MONSTER) || (client))
targ->flags |= FL_NO_KNOCKBACK;
Killed(targ, inflictor, attacker, take, point);
return;
}
}
if(targ->svflags & SVF_MONSTER) {
M_ReactToDamage(targ, attacker);
if(!(targ->monsterinfo.aiflags & AI_DUCKED) && (take)) {
targ->pain(targ, attacker, knockback, take);
if(skill->value == 3)
targ->pain_debounce_time = level.time + 5;
}
} else if(client) {
if(!(targ->flags & FL_GODMODE) && (take))
targ->pain(targ, attacker, knockback, take);
} else if(take) {
if(targ->pain)
targ->pain(targ, attacker, knockback, take);
}
if(client) {
client->damage_parmor += psave;
client->damage_armor += asave;
client->damage_blood += take;
client->damage_knockback += knockback;
VectorCopy(point, client->damage_from);
}
}
void T_RadiusDamage(edict_t *inflictor, edict_t *attacker, float damage, edict_t *ignore, float radius, int mod) {
float points;
edict_t *ent = NULL;
vec3_t v;
vec3_t dir;
while((ent = findradius(ent, inflictor->s.origin, radius)) != NULL) {
if(ent == ignore)
continue;
if(!ent->takedamage)
continue;
VectorAdd(ent->mins, ent->maxs, v);
VectorMA(ent->s.origin, 0.5, v, v);
VectorSubtract(inflictor->s.origin, v, v);
points = damage - 0.5 * VectorLength(v);
if(ent == attacker)
points = points * 0.5;
if(points > 0) {
if(CanDamage(ent, inflictor)) {
VectorSubtract(ent->s.origin, inflictor->s.origin, dir);
T_Damage(ent, inflictor, attacker, dir, inflictor->s.origin, vec3_origin, (int)points, (int)points,
DAMAGE_RADIUS, mod);
}
}
}
}