void doppleganger_timeout(edict_t *self) { if (self->teamchain) { BecomeExplosion1(self->teamchain); } BecomeExplosion1(self); }
/*QUAKED func_explosive (0 .5 .8) ? Trigger_Spawn ANIMATED ANIMATED_FAST Any brush that you want to explode or break apart. If you want an ex0plosion, set dmg and it will do a radius explosion of that amount at the center of the bursh. If targeted it will not be shootable. health defaults to 100. mass defaults to 75. This determines how much debris is emitted when it explodes. You get one large chunk per 100 of mass (up to 8) and one small chunk per 25 of mass (up to 16). So 800 gives the most. */ void func_explosive_explode(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) { vec3_t origin; vec3_t chunkorigin; vec3_t size; int count; int mass; // bmodel origins are (0 0 0), we need to adjust that here VectorScale(self->size, 0.5f, size); VectorAdd(self->absmin, size, origin); VectorCopy(origin, self->s.origin); self->takedamage = DAMAGE_NO; if (self->dmg) T_RadiusDamage(self, attacker, self->dmg, NULL, self->dmg + 40, MOD_EXPLOSIVE); VectorSubtract(self->s.origin, inflictor->s.origin, self->velocity); VectorNormalize(self->velocity); VectorScale(self->velocity, 150, self->velocity); // start chunks towards the center VectorScale(size, 0.5f, size); mass = self->mass; if (!mass) mass = 75; // big chunks if (mass >= 100) { count = mass / 100; if (count > 8) count = 8; while (count--) { chunkorigin[0] = origin[0] + crandom() * size[0]; chunkorigin[1] = origin[1] + crandom() * size[1]; chunkorigin[2] = origin[2] + crandom() * size[2]; ThrowDebris(self, "models/objects/debris1/tris.md2", 1, chunkorigin); } } // small chunks count = mass / 25; if (count > 16) count = 16; while (count--) { chunkorigin[0] = origin[0] + crandom() * size[0]; chunkorigin[1] = origin[1] + crandom() * size[1]; chunkorigin[2] = origin[2] + crandom() * size[2]; ThrowDebris(self, "models/objects/debris2/tris.md2", 2, chunkorigin); } G_UseTargets(self, attacker); if (self->dmg) BecomeExplosion1(self); else G_FreeEdict(self); }
void model_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) { edict_t *e, *next; e = self->movewith_next; while(e) { next = e->movewith_next; if(e->solid == SOLID_NOT) { e->nextthink = 0; G_FreeEdict(e); } else BecomeExplosion1 (e); e = next; } BecomeExplosion1(self); }
void fixbot_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) { gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0); BecomeExplosion1(self); // shards }
// ================= // ================= void sphere_think_explode (edict_t *self) { if(self->owner && self->owner->client && !(self->spawnflags & SPHERE_DOPPLEGANGER)) { self->owner->client->owned_sphere = NULL; } BecomeExplosion1 (self); }
void hover_deadthink(edict_t *self) { if (!self->groundentity && level.time < self->timestamp) { self->nextthink = level.time + FRAMETIME; return; } BecomeExplosion1(self); }
void supplystation_explode (edict_t *self, char *message) { if (self->creator && self->creator->inuse) { safe_cprintf(self->creator, PRINT_HIGH, message); self->creator->supplystation = NULL; T_RadiusDamage(self, self->creator, 150, self, 150, MOD_SUPPLYSTATION); } BecomeExplosion1(self); }
void base_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) { if (self->creator && self->creator->inuse) { self->creator->num_sentries--; if (self->creator->num_sentries < 0) self->creator->num_sentries = 0; } BecomeExplosion1(self); }
void base_think (edict_t *self) { // make sure sentry has settled down if (!minisentry_checkposition(self)) { BecomeExplosion1(self); return; } self->nextthink = level.time + FRAMETIME; }
void model_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) { if(self->deathtarget) { self->target = self->deathtarget; G_UseTargets (self, attacker); } train_kill_children(self); BecomeExplosion1(self); }
//mxd void flyer_spawn_gibs(edict_t *self, int damage) { for (int n = 0; n < 6; n++) ThrowGib(self, "models/objects/gibs/sm_metal/tris.md2", damage, GIB_METALLIC); for (int n = 0; n < 4; n++) ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC); ThrowGib(self, "models/objects/gibs/skull/tris.md2", damage, GIB_ORGANIC); //mxd gi.sound(self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0); BecomeExplosion1(self); }
void flyer_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) { int n; // Knightmare- gibs! for (n= 0; n < 4; n++) ThrowGib (self, "models/objects/gibs/sm_metal/tris.md2", damage, GIB_METALLIC); for (n= 0; n < 2; n++) ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC); gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0); BecomeExplosion1(self); }
void flyer_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /* unused */, int damage /* unused */, vec3_t point /* unused */) { if (!self) { return; } gi.sound(self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0); BecomeExplosion1(self); }
void doppleganger_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker, int damage, vec3_t point) { edict_t *sphere; float dist; vec3_t dir; if (!self || !attacker) { return; } if ((self->enemy) && (self->enemy != self->teammaster)) { VectorSubtract(self->enemy->s.origin, self->s.origin, dir); dist = VectorLength(dir); if (dist > 768) { sphere = Sphere_Spawn(self, SPHERE_HUNTER | SPHERE_DOPPLEGANGER); sphere->pain(sphere, attacker, 0, 0); } else { sphere = Sphere_Spawn(self, SPHERE_VENGEANCE | SPHERE_DOPPLEGANGER); sphere->pain(sphere, attacker, 0, 0); } } if (self->teamchain) { BecomeExplosion1(self->teamchain); } BecomeExplosion1(self); }
/* ========== RemoveLaserDefense removes all lasers for this entity ========== */ void RemoveLaserDefense (edict_t *ent) { edict_t *e = NULL; while((e = G_Find(e, FOFS(classname), "laser_defense_gr")) != NULL) { if (e && (e->owner == ent)) { // remove the linked laser if (e->creator) G_FreeEdict(e->creator); // remove the grenade BecomeExplosion1(e); } } ent->num_lasers = 0; }
void Cmd_SpawnMagmine_f (edict_t *ent) { int talentLevel,cost=MAGMINE_COST; float skill_mult=1.0, cost_mult=1.0, delay_mult=1.0;//Talent: Rapid Assembly & Precision Tuning char *opt = gi.argv(1); if (ent->myskills.abilities[MAGMINE].disable) return; //Talent: Rapid Assembly talentLevel = getTalentLevel(ent, TALENT_RAPID_ASSEMBLY); if (talentLevel > 0) delay_mult -= 0.1 * talentLevel; //Talent: Precision Tuning else if ((talentLevel = getTalentLevel(ent, TALENT_PRECISION_TUNING)) > 0) { cost_mult += PRECISION_TUNING_COST_FACTOR * talentLevel; delay_mult += PRECISION_TUNING_DELAY_FACTOR * talentLevel; skill_mult += PRECISION_TUNING_SKILL_FACTOR * talentLevel; } cost *= cost_mult; if (!G_CanUseAbilities(ent, ent->myskills.abilities[MAGMINE].current_level, cost)) return; if (!strcmp(opt, "self")) { if (getTalentLevel(ent, TALENT_MAGMINESELF)) { ent->automag = !ent->automag; safe_cprintf(ent, PRINT_HIGH, "Auto Magmine %s\n", ent->automag? "enabled" : "disabled"); }else safe_cprintf(ent, PRINT_HIGH, "You haven't upgraded this talent.\n"); return; } if (ent->magmine && ent->magmine->inuse) { safe_cprintf(ent, PRINT_HIGH, "Removed mag mine.\n"); BecomeExplosion1(ent->magmine); ent->magmine = NULL; return; } magmine_spawn(ent, cost, skill_mult, delay_mult); }
void door_secret_blocked (edict_t *self, edict_t *other) { if (!(other->svflags & SVF_MONSTER) && (!other->client) ) { // give it a chance to go away on it's own terms (like gibs) T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH); // if it's still there, nuke it if (other) BecomeExplosion1 (other); return; } if (level.time < self->touch_debounce_time) return; self->touch_debounce_time = level.time + 0.5; T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH); }
void plat_blocked (edict_t *self, edict_t *other) { if (!(other->svflags & SVF_MONSTER) && (!other->client) ) { // give it a chance to go away on it's own terms (like gibs) T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH); // if it's still there, nuke it if (other) BecomeExplosion1 (other); return; } T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH); if (self->moveinfo.state == STATE_UP) plat_go_down (self); else if (self->moveinfo.state == STATE_DOWN) plat_go_up (self); }
void hover_deadthink (edict_t *self) { int n; if (!self->groundentity && level.time < self->timestamp) { self->nextthink = level.time + FRAMETIME; return; } // Knightmare- gibs! gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0); for (n= 0; n < 8; n++) ThrowGib (self, "models/objects/gibs/sm_metal/tris.md2", 200, GIB_METALLIC); for (n= 0; n < 2; n++) ThrowGib (self, "models/objects/gibs/gear/tris.md2", 200, GIB_METALLIC); for (n= 0; n < 2; n++) ThrowGib (self, "models/objects/gibs/bone/tris.md2", 200, GIB_ORGANIC); for (n= 0; n < 6; n++) ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", 200, GIB_ORGANIC); ThrowGib (self, "models/objects/gibs/head2/tris.md2", 200, GIB_ORGANIC); BecomeExplosion1(self); }
void Crane_blocked (edict_t *self, edict_t *other) { if ( (other->classname) && (other->movetype == MOVETYPE_PUSHABLE)) { // treat func_pushable like a world brush - attempt to stop // crane // This *shouldn't* be necessary, but I'm a pessimist Crane_Stop(self->crane_control); return; } if (self->crane_control->crane_hook == other) return; if (!(other->svflags & SVF_MONSTER) && (!other->client) ) { // give it a chance to go away on it's own terms (like gibs) T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH); // if it's still there, nuke it if (other) { // Lazarus: Some of our ents don't have origin near the model vec3_t save; VectorCopy(other->s.origin,save); VectorMA (other->absmin, 0.5, other->size, other->s.origin); BecomeExplosion1 (other); } return; } if (level.time < self->touch_debounce_time) return; if (!self->dmg) return; self->touch_debounce_time = level.time + 0.5; T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH); }
void flyer_detonate(edict_t *self) { int damage; if (self->radius_dmg) damage = (150 + 26 * self->monsterinfo.skill); else damage = (75 + 13 * self->monsterinfo.skill); if (self->radius_dmg && self->monsterinfo.ability & GIEX_MABILITY_DAMAGE) { damage *= 2; } T_RadiusDamage(NULL, self, self, damage, damage * 0.5, self, 120 + 5 * self->monsterinfo.skill, true, MOD_R_SPLASH); gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0); BecomeExplosion1(self); if (!(self->monsterinfo.aiflags & AI_GOOD_GUY)) { if (self->monsterinfo.ability & GIEX_MABILITY_STEALTH) { removeStealth(); } level.killed_monsters++; } }
void hover_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) { int n; self->s.skinnum |= 1; // check for gib if (self->health <= self->gib_health && !(self->spawnflags & SF_MONSTER_NOGIB)) { // Knightmare- more gibs! gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0); for (n= 0; n < 8; n++) ThrowGib (self, "models/objects/gibs/sm_metal/tris.md2", damage, GIB_METALLIC); for (n= 0; n < 2; n++) ThrowGib (self, "models/objects/gibs/gear/tris.md2", damage, GIB_METALLIC); for (n= 0; n < 2; n++) ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC); for (n= 0; n < 6; n++) ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC); ThrowGib (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC); BecomeExplosion1(self); //ThrowHead (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC); //self->deadflag = DEAD_DEAD; return; } if (self->deadflag == DEAD_DEAD) return; // regular death if (random() < 0.5) gi.sound (self, CHAN_VOICE, sound_death1, 1, ATTN_NORM, 0); else gi.sound (self, CHAN_VOICE, sound_death2, 1, ATTN_NORM, 0); self->deadflag = DEAD_DEAD; self->takedamage = DAMAGE_YES; self->monsterinfo.currentmove = &hover_move_death1; }
void door_blocked (edict_t *self, edict_t *other) { edict_t *ent; if (!(other->svflags & SVF_MONSTER) && (!other->client) ) { // give it a chance to go away on it's own terms (like gibs) T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH); // if it's still there, nuke it if (other) BecomeExplosion1 (other); return; } T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH); if (self->spawnflags & DOOR_CRUSHER) return; // if a door has a negative wait, it would never come back if blocked, // so let it just squash the object to death real fast if (self->moveinfo.wait >= 0) { if (self->moveinfo.state == STATE_DOWN) { for (ent = self->teammaster ; ent ; ent = ent->teamchain) door_go_up (ent, ent->activator); } else { for (ent = self->teammaster ; ent ; ent = ent->teamchain) door_go_down (ent); } } }
void barrel_explode (edict_t *self) { vec3_t org; float spd; vec3_t save; T_RadiusDamage (self, self->activator, self->dmg, NULL, self->dmg+40, MOD_BARREL); VectorCopy (self->s.origin, save); VectorMA (self->absmin, 0.5, self->size, self->s.origin); // a few big chunks spd = 1.5 * (float)self->dmg / 200.0; org[0] = self->s.origin[0] + crandom() * self->size[0]; org[1] = self->s.origin[1] + crandom() * self->size[1]; org[2] = self->s.origin[2] + crandom() * self->size[2]; ThrowDebris (self, "models/objects/debris1/tris.md2", spd, org); org[0] = self->s.origin[0] + crandom() * self->size[0]; org[1] = self->s.origin[1] + crandom() * self->size[1]; org[2] = self->s.origin[2] + crandom() * self->size[2]; ThrowDebris (self, "models/objects/debris1/tris.md2", spd, org); // bottom corners spd = 1.75 * (float)self->dmg / 200.0; VectorCopy (self->absmin, org); ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org); VectorCopy (self->absmin, org); org[0] += self->size[0]; ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org); VectorCopy (self->absmin, org); org[1] += self->size[1]; ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org); VectorCopy (self->absmin, org); org[0] += self->size[0]; org[1] += self->size[1]; ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org); // a bunch of little chunks spd = 2 * self->dmg / 200; org[0] = self->s.origin[0] + crandom() * self->size[0]; org[1] = self->s.origin[1] + crandom() * self->size[1]; org[2] = self->s.origin[2] + crandom() * self->size[2]; ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org); org[0] = self->s.origin[0] + crandom() * self->size[0]; org[1] = self->s.origin[1] + crandom() * self->size[1]; org[2] = self->s.origin[2] + crandom() * self->size[2]; ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org); org[0] = self->s.origin[0] + crandom() * self->size[0]; org[1] = self->s.origin[1] + crandom() * self->size[1]; org[2] = self->s.origin[2] + crandom() * self->size[2]; ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org); org[0] = self->s.origin[0] + crandom() * self->size[0]; org[1] = self->s.origin[1] + crandom() * self->size[1]; org[2] = self->s.origin[2] + crandom() * self->size[2]; ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org); org[0] = self->s.origin[0] + crandom() * self->size[0]; org[1] = self->s.origin[1] + crandom() * self->size[1]; org[2] = self->s.origin[2] + crandom() * self->size[2]; ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org); org[0] = self->s.origin[0] + crandom() * self->size[0]; org[1] = self->s.origin[1] + crandom() * self->size[1]; org[2] = self->s.origin[2] + crandom() * self->size[2]; ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org); org[0] = self->s.origin[0] + crandom() * self->size[0]; org[1] = self->s.origin[1] + crandom() * self->size[1]; org[2] = self->s.origin[2] + crandom() * self->size[2]; ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org); org[0] = self->s.origin[0] + crandom() * self->size[0]; org[1] = self->s.origin[1] + crandom() * self->size[1]; org[2] = self->s.origin[2] + crandom() * self->size[2]; ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org); VectorCopy (save, self->s.origin); if (self->groundentity) BecomeExplosion2 (self); else BecomeExplosion1 (self); }
/* ======================== func_explosive_objective ======================== */ void func_explosive_objective_explode (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) { vec3_t origin; vec3_t chunkorigin; vec3_t size; int count; int mass; int enemy; int otherteam; //gi.dprintf(DEVELOPER_MSG_GAME, "self: %s\ninflictor: %s\n attacker: %s\n", // self->classname, inflictor->classname, attacker->classname); if (!attacker->client || !attacker->client->resp.mos) return; // bmodel origins are (0 0 0), we need to adjust that here VectorScale (self->size, 0.5, size); VectorAdd (self->absmin, size, origin); VectorCopy (origin, self->s.origin); self->takedamage = DAMAGE_NO; if (self->dmg) T_RadiusDamage (self, attacker, self->dmg, NULL, self->dmg+40, MOD_EXPLOSIVE); VectorSubtract (self->s.origin, inflictor->s.origin, self->velocity); VectorNormalize (self->velocity); VectorScale (self->velocity, 150, self->velocity); // start chunks towards the center VectorScale (size, 0.5, size); mass = self->mass; if (!mass) mass = 75; // big chunks if (mass >= 100) { count = mass / 100; if (count > 8) count = 8; while(count--) { chunkorigin[0] = origin[0] + crandom() * size[0]; chunkorigin[1] = origin[1] + crandom() * size[1]; chunkorigin[2] = origin[2] + crandom() * size[2]; ThrowDebris (self, "models/objects/debris1/tris.md2", 1, chunkorigin); } } // small chunks count = mass / 25; if (count > 16) count = 16; while(count--) { chunkorigin[0] = origin[0] + crandom() * size[0]; chunkorigin[1] = origin[1] + crandom() * size[1]; chunkorigin[2] = origin[2] + crandom() * size[2]; ThrowDebris (self, "models/objects/debris2/tris.md2", 2, chunkorigin); } G_UseTargets (self, attacker); // hack for 2 team games if (self->obj_owner != 99) { team_list[self->obj_owner]->score -= self->obj_loss; enemy = (self->obj_owner) ? 0 : 1; } else enemy = 99; if (self->obj_owner != attacker->client->resp.team_on->index) team_list[attacker->client->resp.team_on->index]->score += self->obj_gain; else if (self->obj_owner == attacker->client->resp.team_on->index && enemy != 99) team_list[enemy]->score += self->obj_gain; if (dedicated->value) safe_cprintf(NULL, PRINT_HIGH, "%s destroyed by %s [%s]\n", self->obj_name, attacker->client->pers.netname, team_list[attacker->client->resp.team_on->index]->teamname); centerprintall("%s destroyed by:\n\n%s\n%s", self->obj_name, attacker->client->pers.netname, team_list[attacker->client->resp.team_on->index]->teamname); otherteam = (self->obj_owner+1)%2; if ((!team_list[otherteam]->kills_and_points && team_list[otherteam]->score < team_list[otherteam]->need_points) || (team_list[otherteam]->kills_and_points && team_list[otherteam]->kills < team_list[otherteam]->need_kills)) gi.sound(self, CHAN_NO_PHS_ADD, gi.soundindex(va("%s/objectives/touch_cap.wav", team_list[otherteam]->teamid)), 1, 0, 0); // gi.dprintf(DEVELOPER_MSG_GAME, "pts:%i ndpts:%i kills:%i ndkills:%i\n",team_list[(self->obj_owner+1)%2]->score,team_list[(self->obj_owner+1)%2]->need_points, //team_list[(self->obj_owner+1)%2]->kills,team_list[(self->obj_owner+1)%2]->need_kills); if (self->deathtarget) { self->target = self->deathtarget; if (self->target) G_UseTargets (self, attacker); } if (self->dmg) BecomeExplosion1 (self); else G_FreeEdict (self); }
void floater_die(edict_t * self, edict_t * inflictor, edict_t * attacker, int damage, vec3_t point) { gi.sound(self, CHAN_VOICE, sound_death1, 1, ATTN_NORM, 0); BecomeExplosion1(self); }
void pendulum_blocked (edict_t *self, edict_t *other) { trace_t trace; vec3_t angles; vec3_t forward, left, up; vec3_t dir; vec3_t f1, l1, u1; vec3_t point; vec3_t origin; vec3_t new_velocity; vec3_t new_origin; float speed; int damage; // Since this routine is called in response to being blocked, // the current s.angles is for the LAST frame, not the proposed // angles for the current frame. Since we're basically overriding // normal physics here, go ahead and move to new location. This // means that later on we have to move blocker NOW rather than // relying on its velocity to get it out of the way. // BUT... trouble is doing this with players ends up giving // goofy direction in some cases. For players/monsters, use old // angles but STILL move 'em out of the way immediately if(other->client || (other->svflags & SVF_MONSTER)) VectorCopy(self->s.angles,angles); else VectorMA(self->s.angles,FRAMETIME,self->avelocity,angles); AngleVectors(angles,forward,left,up); speed = fabs(self->avelocity[ROLL]) * M_PI / 180. * self->radius; if( (level.time > self->touch_debounce_time) && (speed > 200) ) { damage = (int)( self->dmg * (speed-200)/100 ); self->touch_debounce_time = level.time + 0.5; } else damage = 0; VectorAdd(other->s.origin,other->origin_offset,origin); VectorCopy(left,dir); if(self->avelocity[ROLL] > 0) VectorNegate(dir,dir); VectorScale(forward,self->move_origin[0],f1); VectorScale(left,-self->move_origin[1],l1); VectorScale(up,self->move_origin[2],u1); VectorAdd(self->s.origin,f1,point); VectorAdd(point,l1,point); VectorAdd(point,u1,point); VectorSubtract(origin,point,point); VectorNormalize(point); if(other->client || (other->svflags & SVF_MONSTER)) { if((point[2] < -0.7) && other->groundentity) { T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, DAMAGE_NO_PROTECTION, MOD_CRUSH); return; } dir[2] = max(1.0,fabs(dir[2])); VectorNormalize(dir); // Normal kickback takes too long to take effect and allows embedment. Move // the blocker NOW. // Give a minimum speed so we can get the poor fool out of the way speed = max(100,speed); VectorScale(dir,speed,new_velocity); VectorMA(other->s.origin,FRAMETIME,new_velocity,new_origin); other->solid = SOLID_NOT; gi.linkentity(other); trace = gi.trace(other->s.origin,other->mins,other->maxs,new_origin,self,other->clipmask); VectorCopy(trace.endpos,other->s.origin); VectorCopy(new_velocity,other->velocity); other->solid = SOLID_BBOX; gi.linkentity(other); T_Damage (other, self, self, dir, other->s.origin, vec3_origin, damage, 0, 0, MOD_CRUSH); } else if(other->solid == SOLID_BSP) { // Other is most likely a func_pushable, since almost all other bmodels aren't // clipped to MOVETYPE_PUSH vec3_t org, mins, maxs; vec3_t vn2; qboolean block; float e=self->attenuation; // coefficient of restitution float m=(float)(other->mass)/(float)(self->mass); float v11 = speed; float v21; // Initial speed of other in the impact direction float v12, v22; float new_rspeed; float sgor, time, wave; if(v11 >= 100) gi.sound (self, 0, self->noise_index, 1, 1, 0); // If other is on the ground, push it UP regardless of dir if(other->groundentity) dir[2] = max(1.0,fabs(dir[2])); VectorNormalize(dir); // If pendulum hits crate from above and crate is on the ground, // destroy the crate. This may not be realistic, but there's really // no other way since if we stop the pendulum we'd then have to // continously monitor whether the crate moved away or not. if((point[2] < -0.7) && (other->velocity[2] == 0)) { box_die (other, self, self, 100000, point); return; } if(e > 0) { v21 = VectorLength(other->velocity); if(v21 > 0) { VectorCopy(other->velocity,vn2); VectorNormalize(vn2); v21 *= DotProduct(dir,vn2); } v22 = ( e*(v11-v21) + v11 + m*v21 ) / (1.0 + m); v12 = v22 + e*(v21-v11); // gi.dprintf("v11=%g, v21=%g, v12=%g, v22=%g\n",v11,v21,v12,v22); // gi.dprintf("av[ROLL]=%g, roll=%g\n",self->avelocity[ROLL],angles[ROLL]); } else { v12 = v11; if(other->mass > self->mass) { block = true; VectorClear(self->avelocity); gi.linkentity(self); goto deadstop; } else v22 = v11 * (float)self->mass/(float)other->mass; } VectorScale(dir,v22,new_velocity); if(v12 < 0) { // Reverse rotation. new_rspeed = fabs(v12) / (M_PI / 180. * self->radius); if(self->avelocity[ROLL] > 0) self->avelocity[ROLL] = -new_rspeed; else self->avelocity[ROLL] = new_rspeed; } else { // Continuing to move in same direction, though slower. new_rspeed = v12 / (M_PI / 180. * self->radius); if(self->avelocity[ROLL] > 0) self->avelocity[ROLL] = new_rspeed; else self->avelocity[ROLL] = -new_rspeed; } sgor = sqrt( (float)sv_gravity->value / self->radius ); wave = fabs( self->avelocity[ROLL] / (angles[ROLL] * sgor) ); wave = atan(wave); if(self->avelocity[ROLL] >= 0) { if(angles[ROLL] > 0) wave = M_PI - wave; } else { if(angles[ROLL] > 0) wave = M_PI + wave; else wave = 2*M_PI - wave; } time = wave/sgor; self->startframe = level.framenum - time*10.; self->moveinfo.start_angles[ROLL] = -fabs(angles[ROLL] / cos(wave)); // Now we know the new pendulum velocity and crate velocity, *assuming* // nothing else is in the way. Now check to see if crate hits anything // else. VectorAdd(other->s.origin,other->origin_offset,org); VectorMA(org,FRAMETIME,new_velocity,new_origin); // Temporarily make crate nonsolid so we can ignore pendulum in our trace // (rather than crate) other->solid = SOLID_NOT; gi.linkentity(other); VectorSubtract(other->mins,other->origin_offset,mins); VectorSubtract(other->maxs,other->origin_offset,maxs); trace = gi.trace (org, mins, maxs, new_origin, self, other->clipmask); // restore solidity of crate other->solid = SOLID_BSP; if(trace.startsolid) { // Things are completely fouled up. Nuke other and go away. T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH); if (other) BecomeExplosion1 (other); return; } else if(trace.fraction < 1.0) { vec3_t vec; float dist; VectorSubtract(trace.endpos,org,vec); dist = VectorLength(vec); if( (trace.ent->client) || (trace.ent->flags & SVF_MONSTER)) { float delta=FRAMETIME*VectorLength(new_velocity); // If a player or monster is in the way of the crate, AND // the pendulum speed is > 100, throw 'em out of the way. // If pendulum tangential speed is < 100, give up. if(speed < 100) block = true; else { if(dist < delta) { VectorScale(new_velocity,1.25,trace.ent->velocity); VectorMA(trace.ent->s.origin,FRAMETIME,trace.ent->velocity,trace.ent->s.origin); gi.linkentity(trace.ent); } block = false; } } else { if(dist < speed*FRAMETIME) { block = true; VectorScale(vec,10.,other->velocity); VectorMA(other->s.origin,FRAMETIME,other->velocity,other->s.origin); } else block = false; } } else block = false; if(!block) { VectorCopy(new_velocity,other->velocity); VectorMA(other->s.origin,FRAMETIME,other->velocity,other->s.origin); } gi.linkentity(other); // Final checks: // 1) If pendulum after-impact speed is < 100, that's too damn slow. // Lie and say it's blocked // 2) If not blocked, in its new position test for intersection // of crate and pendulum. If they intersect, then most likely pendulum is // moving VERY slowly and we need to reverse direction NOW to prevent // embedment. if(!block) { if(fabs(v12) < 100) block = true; else { VectorAdd(other->s.origin,other->origin_offset,org); trace = gi.trace(org,mins,maxs,org,other,MASK_SOLID); if(trace.startsolid) block = true; } } deadstop: T_Damage (other, self, self, dir, other->s.origin, vec3_origin, damage, 0, 0, MOD_CRUSH); if( block ) { // Then this sucker will still be in the way. Reverse rotation, slow, or stop if(fabs(angles[ROLL]) > 2) { if(fabsf(angles[ROLL]) < 10) self->spawnflags |= SF_PENDULUM_SLOW; self->moveinfo.start_angles[ROLL] = angles[ROLL]; VectorClear(self->avelocity); self->startframe = 0; } else { self->spawnflags &= ~SF_PENDULUM_STARTON; self->moveinfo.start_angles[ROLL] = 0; VectorClear(self->s.angles); VectorClear(self->avelocity); } gi.linkentity(self); } else if((fabs(self->avelocity[ROLL]) < 10) && (fabs(self->s.angles[ROLL]) < 10)) { self->spawnflags |= SF_PENDULUM_SLOW; self->moveinfo.start_angles[ROLL] = angles[ROLL]; VectorClear(self->avelocity); self->startframe = 0; } } else { T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH); // if it's still there, nuke it if (other) BecomeExplosion1 (other); } }
void base_createturret (edict_t *self) { edict_t *sentry; vec3_t end; trace_t tr; int casterlevel, talentLevel; float ammo_mult=1.0; // make sure sentry has settled down if (!G_EntIsAlive(self->creator) || !minisentry_checkposition(self)) { if (self->creator) { self->creator->num_sentries--; if (self->creator->num_sentries < 0) self->creator->num_sentries = 0; } BecomeExplosion1(self); return; } self->movetype = MOVETYPE_NONE; // lock down base self->takedamage = DAMAGE_NO; // the base is invulnerable // 3.8 base bbox no longer necessary, turret takes over VectorClear(self->mins); VectorClear(self->maxs); self->solid = SOLID_NOT; // create basic ent for sentry sentry = G_Spawn(); sentry->creator = self->creator; sentry->owner = self; // the base becomes the owner VectorCopy(self->s.angles, sentry->s.angles); sentry->think = minisentry_think; sentry->nextthink = level.time + FRAMETIME; sentry->s.modelindex = gi.modelindex ("models/weapons/g_bfg/tris.md2"); sentry->s.renderfx |= RF_IR_VISIBLE; // who really wanted to chase sentries anyway // sentry->flags |= FL_CHASEABLE; // 3.65 indicates entity can be chase cammed sentry->solid = SOLID_BBOX; sentry->movetype = MOVETYPE_NONE; sentry->clipmask = MASK_MONSTERSOLID; sentry->mass = 100; sentry->classname = "msentrygun"; //sentry->viewheight = 16; sentry->takedamage = DAMAGE_AIM; sentry->mtype = M_MINISENTRY; sentry->touch = minisentry_touch; sentry->monsterinfo.power_armor_type = POWER_ARMOR_SHIELD; //Talent: Storage Upgrade talentLevel = getTalentLevel(self->creator, TALENT_STORAGE_UPGRADE); ammo_mult += 0.2 * talentLevel; // set ammo sentry->monsterinfo.jumpdn = SENTRY_MAX_AMMO * ammo_mult; // max ammo sentry->light_level = sentry->monsterinfo.jumpdn; // current ammo //get player's current_level for BUILD_SENTRY casterlevel = self->monsterinfo.level; sentry->monsterinfo.level = casterlevel; // used for adding monster exp sentry->monsterinfo.control_cost = 20; // used for adding monster exp //set health sentry->health = MINISENTRY_INITIAL_HEALTH + (MINISENTRY_ADDON_HEALTH * casterlevel); sentry->monsterinfo.power_armor_power = MINISENTRY_INITIAL_ARMOR + (MINISENTRY_ADDON_ARMOR * casterlevel); // if (sentry->health > MINISENTRY_MAX_HEALTH) // sentry->health = MINISENTRY_MAX_HEALTH; //if (sentry->monsterinfo.power_armor_power > MINISENTRY_MAX_ARMOR) // sentry->monsterinfo.power_armor_power = MINISENTRY_MAX_ARMOR; sentry->max_health = sentry->health; sentry->monsterinfo.max_armor = sentry->monsterinfo.power_armor_power; //set damage sentry->dmg = MINISENTRY_INITIAL_BULLET + (MINISENTRY_ADDON_BULLET * casterlevel);// bullet damage sentry->radius_dmg = MINISENTRY_INITIAL_ROCKET + (MINISENTRY_ADDON_ROCKET * casterlevel); // rocket damage if (sentry->dmg > MINISENTRY_MAX_BULLET) sentry->dmg = MINISENTRY_MAX_BULLET; if (sentry->radius_dmg > MINISENTRY_MAX_ROCKET) sentry->radius_dmg = MINISENTRY_MAX_ROCKET; sentry->die = minisentry_die; sentry->pain = minisentry_pain; sentry->yaw_speed = 5; if (self->style == SENTRY_UPRIGHT) { VectorSet(sentry->mins, -28, -28, -12); VectorSet(sentry->maxs, 28, 28, 24); VectorCopy(self->s.origin, end); //end[2] += self->maxs[2] + sentry->mins[2] + 1; end[2] += abs(sentry->mins[2])+1; } else { VectorSet(sentry->mins, -28, -28, -24); VectorSet(sentry->maxs, 28, 28, 12); VectorCopy(self->s.origin, end); //end[2] -= abs(self->mins[2]) + sentry->maxs[2] + 1; end[2] -= sentry->maxs[2]+1; } // make sure position is valid tr = gi.trace(end, sentry->mins, sentry->maxs, end, sentry, MASK_SHOT); if (tr.contents & MASK_SHOT) { if (self->creator) { self->creator->num_sentries--; if (self->creator->num_sentries < 0) self->creator->num_sentries = 0; } //gi.dprintf("%s\n", tr.ent?tr.ent->classname:"null"); BecomeExplosion1(self); BecomeExplosion1(sentry); return; } VectorCopy(tr.endpos, sentry->s.origin); VectorCopy(sentry->s.angles, sentry->move_angles);// save for idle animation gi.linkentity(sentry); gi.sound(sentry, CHAN_VOICE, gi.soundindex("weapons/turrset.wav"), 1, ATTN_NORM, 0); self->think = base_think; // base is done creating gun self->nextthink = level.time + FRAMETIME; }
static void func_explosive_explode( edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, const vec3_t point ) { vec3_t origin, bakorigin; vec3_t chunkorigin; vec3_t size; int count; int mass; // do not explode unless visible if( self->r.svflags & SVF_NOCLIENT ) return; self->takedamage = DAMAGE_NO; // bmodel origins are (0 0 0), we need to adjust that here VectorCopy( self->s.origin, bakorigin ); VectorScale( self->r.size, 0.5, size ); VectorAdd( self->r.absmin, size, origin ); VectorCopy( origin, self->s.origin ); if( self->projectileInfo.maxDamage ) G_RadiusDamage( self, attacker, NULL, NULL, MOD_EXPLOSIVE ); VectorSubtract( self->s.origin, inflictor->s.origin, self->velocity ); VectorNormalize( self->velocity ); VectorScale( self->velocity, 150, self->velocity ); // start chunks towards the center VectorScale( size, 0.5, size ); mass = self->projectileInfo.radius * 0.75; if( !mass ) mass = 75; // big chunks if( self->count > 0 ) { if( mass >= 100 ) { count = mass / 100; if( count > 8 ) count = 8; while( count-- ) { chunkorigin[0] = origin[0] + crandom() * size[0]; chunkorigin[1] = origin[1] + crandom() * size[1]; chunkorigin[2] = origin[2] + crandom() * size[2]; ThrowDebris( self, self->count, 1, chunkorigin ); } } } // small chunks if( self->viewheight > 0 ) { count = mass / 25; if( count > 16 ) count = 16; if( count < 1 ) count = 1; while( count-- ) { chunkorigin[0] = origin[0] + crandom() * size[0]; chunkorigin[1] = origin[1] + crandom() * size[1]; chunkorigin[2] = origin[2] + crandom() * size[2]; ThrowDebris( self, self->viewheight, 2, chunkorigin ); } } G_UseTargets( self, attacker ); if( self->projectileInfo.maxDamage ) { edict_t *explosion; explosion = G_Spawn(); VectorCopy( self->s.origin, explosion->s.origin ); explosion->projectileInfo = self->projectileInfo; BecomeExplosion1( explosion ); } if( self->use == NULL ) { G_FreeEdict( self ); return; } self->health = self->max_health; self->r.solid = SOLID_NOT; self->r.svflags |= SVF_NOCLIENT; VectorCopy( bakorigin, self->s.origin ); VectorClear( self->velocity ); GClip_LinkEntity( self ); }
void Trap_Think(edict_t *ent) { edict_t *target = NULL; edict_t *best = NULL; vec3_t vec; int len, i; int oldlen = 8000; vec3_t forward, right, up; if (!ent) { return; } if (ent->timestamp < level.time) { BecomeExplosion1(ent); return; } ent->nextthink = level.time + 0.1; if (!ent->groundentity) { return; } /* ok lets do the blood effect */ if (ent->s.frame > 4) { if (ent->s.frame == 5) { if (ent->wait == 64) { gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/trapdown.wav"), 1, ATTN_IDLE, 0); } ent->wait -= 2; ent->delay += level.time; for (i = 0; i < 3; i++) { best = G_Spawn(); if (strcmp(ent->enemy->classname, "monster_gekk") == 0) { best->s.modelindex = gi.modelindex("models/objects/gekkgib/torso/tris.md2"); best->s.effects |= TE_GREENBLOOD; } else if (ent->mass > 200) { best->s.modelindex = gi.modelindex("models/objects/gibs/chest/tris.md2"); best->s.effects |= TE_BLOOD; } else { best->s.modelindex = gi.modelindex("models/objects/gibs/sm_meat/tris.md2"); best->s.effects |= TE_BLOOD; } AngleVectors(ent->s.angles, forward, right, up); RotatePointAroundVector(vec, up, right, ((360.0 / 3) * i) + ent->delay); VectorMA(vec, ent->wait / 2, vec, vec); VectorAdd(vec, ent->s.origin, vec); VectorAdd(vec, forward, best->s.origin); best->s.origin[2] = ent->s.origin[2] + ent->wait; VectorCopy(ent->s.angles, best->s.angles); best->solid = SOLID_NOT; best->s.effects |= EF_GIB; best->takedamage = DAMAGE_YES; best->movetype = MOVETYPE_TOSS; best->svflags |= SVF_MONSTER; best->deadflag = DEAD_DEAD; VectorClear(best->mins); VectorClear(best->maxs); best->watertype = gi.pointcontents(best->s.origin); if (best->watertype & MASK_WATER) { best->waterlevel = 1; } best->nextthink = level.time + 0.1; best->think = G_FreeEdict; gi.linkentity(best); } if (ent->wait < 19) { ent->s.frame++; } return; } ent->s.frame++; if (ent->s.frame == 8) { ent->nextthink = level.time + 1.0; ent->think = G_FreeEdict; best = G_Spawn(); SP_item_foodcube(best); VectorCopy(ent->s.origin, best->s.origin); best->s.origin[2] += 16; best->velocity[2] = 400; best->count = ent->mass; gi.linkentity(best); return; } return; } ent->s.effects &= ~EF_TRAP; if (ent->s.frame >= 4) { ent->s.effects |= EF_TRAP; VectorClear(ent->mins); VectorClear(ent->maxs); } if (ent->s.frame < 4) { ent->s.frame++; } while ((target = findradius(target, ent->s.origin, 256)) != NULL) { if (target == ent) { continue; } if (!(target->svflags & SVF_MONSTER) && !target->client) { continue; } if (target->health <= 0) { continue; } if (!visible(ent, target)) { continue; } if (!best) { best = target; continue; } VectorSubtract(ent->s.origin, target->s.origin, vec); len = VectorLength(vec); if (len < oldlen) { oldlen = len; best = target; } } /* pull the enemy in */ if (best) { vec3_t forward; if (best->groundentity) { best->s.origin[2] += 1; best->groundentity = NULL; } VectorSubtract(ent->s.origin, best->s.origin, vec); len = VectorLength(vec); if (best->client) { VectorNormalize(vec); VectorMA(best->velocity, 250, vec, best->velocity); } else { best->ideal_yaw = vectoyaw(vec); M_ChangeYaw(best); AngleVectors(best->s.angles, forward, NULL, NULL); VectorScale(forward, 256, best->velocity); } gi.sound(ent, CHAN_VOICE, gi.soundindex( "weapons/trapsuck.wav"), 1, ATTN_IDLE, 0); if (len < 32) { if (best->mass < 400) { T_Damage(best, ent, ent->owner, vec3_origin, best->s.origin, vec3_origin, 100000, 1, 0, MOD_TRAP); ent->enemy = best; ent->wait = 64; VectorCopy(ent->s.origin, ent->s.old_origin); ent->timestamp = level.time + 30; if (deathmatch->value) { ent->mass = best->mass / 4; } else { ent->mass = best->mass / 10; } /* ok spawn the food cube */ ent->s.frame = 5; } else { BecomeExplosion1(ent); return; } } } }