123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606 |
- // Copyright (c) ZeniMax Media Inc.
- // Licensed under the GNU General Public License 2.0.
- #include "../g_local.h"
- // RAFAEL
- void fire_blueblaster(edict_t *self, const vec3_t &start, const vec3_t &dir, int damage, int speed, effects_t effect)
- {
- edict_t *bolt;
- trace_t tr;
- bolt = G_Spawn();
- bolt->s.origin = start;
- bolt->s.old_origin = start;
- bolt->s.angles = vectoangles(dir);
- bolt->velocity = dir * speed;
- bolt->svflags |= SVF_PROJECTILE;
- bolt->movetype = MOVETYPE_FLYMISSILE;
- bolt->flags |= FL_DODGE;
- bolt->clipmask = MASK_PROJECTILE;
- bolt->solid = SOLID_BBOX;
- bolt->s.effects |= effect;
- bolt->s.modelindex = gi.modelindex("models/objects/laser/tris.md2");
- bolt->s.skinnum = 1;
- bolt->s.sound = gi.soundindex("misc/lasfly.wav");
- bolt->owner = self;
- bolt->touch = blaster_touch;
- bolt->nextthink = level.time + 2_sec;
- bolt->think = G_FreeEdict;
- bolt->dmg = damage;
- bolt->classname = "bolt";
- bolt->style = MOD_BLUEBLASTER;
- gi.linkentity(bolt);
- tr = gi.traceline(self->s.origin, bolt->s.origin, bolt, bolt->clipmask);
- if (tr.fraction < 1.0f)
- {
- bolt->s.origin = tr.endpos + (tr.plane.normal * 1.f);
- bolt->touch(bolt, tr.ent, tr, false);
- }
- }
- // RAFAEL
- /*
- fire_ionripper
- */
- THINK(ionripper_sparks) (edict_t *self) -> void
- {
- gi.WriteByte(svc_temp_entity);
- gi.WriteByte(TE_WELDING_SPARKS);
- gi.WriteByte(0);
- gi.WritePosition(self->s.origin);
- gi.WriteDir(vec3_origin);
- gi.WriteByte(irandom(0xe4, 0xe8));
- gi.multicast(self->s.origin, MULTICAST_PVS, false);
- G_FreeEdict(self);
- }
- // RAFAEL
- TOUCH(ionripper_touch) (edict_t *self, edict_t *other, const trace_t &tr, bool other_touching_self) -> void
- {
- if (other == self->owner)
- return;
- if (tr.surface && (tr.surface->flags & SURF_SKY))
- {
- G_FreeEdict(self);
- return;
- }
- if (self->owner->client)
- PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT);
- if (other->takedamage)
- {
- T_Damage(other, self, self->owner, self->velocity, self->s.origin, tr.plane.normal, self->dmg, 1, DAMAGE_ENERGY, MOD_RIPPER);
- }
- else
- {
- return;
- }
- G_FreeEdict(self);
- }
- // RAFAEL
- void fire_ionripper(edict_t *self, const vec3_t &start, const vec3_t &dir, int damage, int speed, effects_t effect)
- {
- edict_t *ion;
- trace_t tr;
- ion = G_Spawn();
- ion->s.origin = start;
- ion->s.old_origin = start;
- ion->s.angles = vectoangles(dir);
- ion->velocity = dir * speed;
- ion->movetype = MOVETYPE_WALLBOUNCE;
- ion->clipmask = MASK_PROJECTILE;
- // [Paril-KEX]
- if (self->client && !G_ShouldPlayersCollide(true))
- ion->clipmask &= ~CONTENTS_PLAYER;
- ion->solid = SOLID_BBOX;
- ion->s.effects |= effect;
- ion->svflags |= SVF_PROJECTILE;
- ion->flags |= FL_DODGE;
- ion->s.renderfx |= RF_FULLBRIGHT;
- ion->s.modelindex = gi.modelindex("models/objects/boomrang/tris.md2");
- ion->s.sound = gi.soundindex("misc/lasfly.wav");
- ion->owner = self;
- ion->touch = ionripper_touch;
- ion->nextthink = level.time + 3_sec;
- ion->think = ionripper_sparks;
- ion->dmg = damage;
- ion->dmg_radius = 100;
- gi.linkentity(ion);
- tr = gi.traceline(self->s.origin, ion->s.origin, ion, ion->clipmask);
- if (tr.fraction < 1.0f)
- {
- ion->s.origin = tr.endpos + (tr.plane.normal * 1.f);
- ion->touch(ion, tr.ent, tr, false);
- }
- }
- // RAFAEL
- /*
- fire_heat
- */
- THINK(heat_think) (edict_t *self) -> void
- {
- edict_t *target = nullptr;
- edict_t *acquire = nullptr;
- vec3_t vec;
- vec3_t oldang;
- float len;
- float oldlen = 0;
- float dot, olddot = 1;
- vec3_t fwd = AngleVectors(self->s.angles).forward;
- // acquire new target
- while ((target = findradius(target, self->s.origin, 1024)) != nullptr)
- {
- if (self->owner == target)
- continue;
- if (!target->client)
- continue;
- if (target->health <= 0)
- continue;
- if (!visible(self, target))
- continue;
- //if (!infront(self, target))
- // continue;
- vec = self->s.origin - target->s.origin;
- len = vec.length();
- dot = vec.normalized().dot(fwd);
- // targets that require us to turn less are preferred
- if (dot >= olddot)
- continue;
- if (acquire == nullptr || dot < olddot || len < oldlen)
- {
- acquire = target;
- oldlen = len;
- olddot = dot;
- }
- }
- if (acquire != nullptr)
- {
- oldang = self->s.angles;
- vec = (acquire->s.origin - self->s.origin).normalized();
- float t = self->accel;
- float d = self->movedir.dot(vec);
- if (d < 0.45f && d > -0.45f)
- vec = -vec;
- self->movedir = slerp(self->movedir, vec, t).normalized();
- self->s.angles = vectoangles(self->movedir);
- if (!self->enemy)
- {
- gi.sound(self, CHAN_WEAPON, gi.soundindex("weapons/railgr1a.wav"), 1.f, 0.25f, 0);
- self->enemy = acquire;
- }
- }
- else
- self->enemy = nullptr;
- self->velocity = self->movedir * self->speed;
- self->nextthink = level.time + FRAME_TIME_MS;
- }
- // RAFAEL
- void fire_heat(edict_t *self, const vec3_t &start, const vec3_t &dir, int damage, int speed, float damage_radius, int radius_damage, float turn_fraction)
- {
- edict_t *heat;
- heat = G_Spawn();
- heat->s.origin = start;
- heat->movedir = dir;
- heat->s.angles = vectoangles(dir);
- heat->velocity = dir * speed;
- heat->flags |= FL_DODGE;
- heat->movetype = MOVETYPE_FLYMISSILE;
- heat->svflags |= SVF_PROJECTILE;
- heat->clipmask = MASK_PROJECTILE;
- heat->solid = SOLID_BBOX;
- heat->s.effects |= EF_ROCKET;
- heat->s.modelindex = gi.modelindex("models/objects/rocket/tris.md2");
- heat->owner = self;
- heat->touch = rocket_touch;
- heat->speed = speed;
- heat->accel = turn_fraction;
- heat->nextthink = level.time + FRAME_TIME_MS;
- heat->think = heat_think;
- heat->dmg = damage;
- heat->radius_dmg = radius_damage;
- heat->dmg_radius = damage_radius;
- heat->s.sound = gi.soundindex("weapons/rockfly.wav");
- gi.linkentity(heat);
- }
- // RAFAEL
- /*
- fire_plasma
- */
- TOUCH(plasma_touch) (edict_t *ent, edict_t *other, const trace_t &tr, bool other_touching_self) -> void
- {
- vec3_t origin;
- if (other == ent->owner)
- return;
- if (tr.surface && (tr.surface->flags & SURF_SKY))
- {
- G_FreeEdict(ent);
- return;
- }
- if (ent->owner->client)
- PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT);
- // calculate position for the explosion entity
- origin = ent->s.origin + (ent->velocity * -0.02f);
- if (other->takedamage)
- {
- T_Damage(other, ent, ent->owner, ent->velocity, ent->s.origin, tr.plane.normal, ent->dmg, 0, DAMAGE_ENERGY, MOD_PHALANX);
- }
- T_RadiusDamage(ent, ent->owner, (float) ent->radius_dmg, other, ent->dmg_radius, DAMAGE_ENERGY, MOD_PHALANX);
- gi.WriteByte(svc_temp_entity);
- gi.WriteByte(TE_PLASMA_EXPLOSION);
- gi.WritePosition(origin);
- gi.multicast(ent->s.origin, MULTICAST_PHS, false);
- G_FreeEdict(ent);
- }
- // RAFAEL
- void fire_plasma(edict_t *self, const vec3_t &start, const vec3_t &dir, int damage, int speed, float damage_radius, int radius_damage)
- {
- edict_t *plasma;
- plasma = G_Spawn();
- plasma->s.origin = start;
- plasma->movedir = dir;
- plasma->s.angles = vectoangles(dir);
- plasma->velocity = dir * speed;
- plasma->movetype = MOVETYPE_FLYMISSILE;
- plasma->clipmask = MASK_PROJECTILE;
- // [Paril-KEX]
- if (self->client && !G_ShouldPlayersCollide(true))
- plasma->clipmask &= ~CONTENTS_PLAYER;
- plasma->solid = SOLID_BBOX;
- plasma->svflags |= SVF_PROJECTILE;
- plasma->flags |= FL_DODGE;
- plasma->owner = self;
- plasma->touch = plasma_touch;
- plasma->nextthink = level.time + gtime_t::from_sec(8000.f / speed);
- plasma->think = G_FreeEdict;
- plasma->dmg = damage;
- plasma->radius_dmg = radius_damage;
- plasma->dmg_radius = damage_radius;
- plasma->s.sound = gi.soundindex("weapons/rockfly.wav");
- plasma->s.modelindex = gi.modelindex("sprites/s_photon.sp2");
- plasma->s.effects |= EF_PLASMA | EF_ANIM_ALLFAST;
- gi.linkentity(plasma);
- }
- THINK(Trap_Gib_Think) (edict_t *ent) -> void
- {
- if (ent->owner->s.frame != 5)
- {
- G_FreeEdict(ent);
- return;
- }
- vec3_t forward, right, up;
- vec3_t vec;
- AngleVectors(ent->owner->s.angles, forward, right, up);
- // rotate us around the center
- float degrees = (150.f * gi.frame_time_s) + ent->owner->delay;
- vec3_t diff = ent->owner->s.origin - ent->s.origin;
- vec = RotatePointAroundVector(up, diff, degrees);
- ent->s.angles[1] += degrees;
- vec3_t new_origin = ent->owner->s.origin - vec;
- trace_t tr = gi.traceline(ent->s.origin, new_origin, ent, MASK_SOLID);
- ent->s.origin = tr.endpos;
-
- // pull us towards the trap's center
- diff.normalize();
- ent->s.origin += diff * (15.0f * gi.frame_time_s);
- ent->watertype = gi.pointcontents(ent->s.origin);
- if (ent->watertype & MASK_WATER)
- ent->waterlevel = WATER_FEET;
- ent->nextthink = level.time + FRAME_TIME_S;
- gi.linkentity(ent);
- }
- DIE(trap_die) (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, const vec3_t &point, const mod_t &mod) -> void
- {
- BecomeExplosion1(self);
- }
- // RAFAEL
- void SP_item_foodcube(edict_t *best);
- void SpawnDamage(int type, const vec3_t &origin, const vec3_t &normal, int damage);
- // RAFAEL
- THINK(Trap_Think) (edict_t *ent) -> void
- {
- edict_t *target = nullptr;
- edict_t *best = nullptr;
- vec3_t vec;
- float len;
- float oldlen = 8000;
- if (ent->timestamp < level.time)
- {
- BecomeExplosion1(ent);
- // note to self
- // cause explosion damage???
- return;
- }
- ent->nextthink = level.time + 10_hz;
- if (!ent->groundentity)
- return;
- // ok lets do the blood effect
- if (ent->s.frame > 4)
- {
- if (ent->s.frame == 5)
- {
- bool spawn = ent->wait == 64;
- ent->wait -= 2;
- if (spawn)
- gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/trapdown.wav"), 1, ATTN_IDLE, 0);
- ent->delay += 2.f;
- if (ent->wait < 19)
- ent->s.frame++;
- return;
- }
- ent->s.frame++;
- if (ent->s.frame == 8)
- {
- ent->nextthink = level.time + 1_sec;
- ent->think = G_FreeEdict;
- ent->s.effects &= ~EF_TRAP;
- best = G_Spawn();
- best->count = ent->mass;
- best->s.scale = 1.f + ((ent->accel - 100.f) / 300.f) * 1.0f;
- SP_item_foodcube(best);
- best->s.origin = ent->s.origin;
- best->s.origin[2] += 24 * best->s.scale;
- best->s.angles[YAW] = frandom() * 360;
- best->velocity[2] = 400;
- best->think(best);
- best->nextthink = 0_ms;
- best->s.old_origin = best->s.origin;
- gi.linkentity(best);
- gi.sound(best, CHAN_AUTO, gi.soundindex("misc/fhit3.wav"), 1.f, ATTN_NORM, 0.f);
- return;
- }
- return;
- }
- ent->s.effects &= ~EF_TRAP;
- if (ent->s.frame >= 4)
- {
- ent->s.effects |= EF_TRAP;
- // clear the owner if in deathmatch
- if (deathmatch->integer)
- ent->owner = nullptr;
- }
- if (ent->s.frame < 4)
- {
- ent->s.frame++;
- return;
- }
- while ((target = findradius(target, ent->s.origin, 256)) != nullptr)
- {
- if (target == ent)
- continue;
-
- // [Paril-KEX] don't allow traps to be placed near flags or teleporters
- // if it's a monster or player with health > 0
- // or it's a player start point
- // and we can see it
- // blow up
- if (target->classname && ((deathmatch->integer &&
- ((!strncmp(target->classname, "info_player_", 12)) ||
- (!strcmp(target->classname, "misc_teleporter_dest")) ||
- (!strncmp(target->classname, "item_flag_", 10))))) &&
- (visible(target, ent)))
- {
- BecomeExplosion1(ent);
- return;
- }
- if (!(target->svflags & SVF_MONSTER) && !target->client)
- continue;
- if (target != ent->teammaster && CheckTeamDamage(target, ent->teammaster))
- continue;
- // [Paril-KEX]
- if (!deathmatch->integer && target->client)
- continue;
- if (target->health <= 0)
- continue;
- if (!visible(ent, target))
- continue;
- vec = ent->s.origin - target->s.origin;
- len = vec.length();
- if (!best)
- {
- best = target;
- oldlen = len;
- continue;
- }
- if (len < oldlen)
- {
- oldlen = len;
- best = target;
- }
- }
- // pull the enemy in
- if (best)
- {
- if (best->groundentity)
- {
- best->s.origin[2] += 1;
- best->groundentity = nullptr;
- }
- vec = ent->s.origin - best->s.origin;
- len = vec.normalize();
- float max_speed = best->client ? 290.f : 150.f;
- best->velocity += (vec * clamp(max_speed - len, 64.f, max_speed));
- ent->s.sound = gi.soundindex("weapons/trapsuck.wav");
- if (len < 48)
- {
- if (best->mass < 400)
- {
- ent->takedamage = false;
- ent->solid = SOLID_NOT;
- ent->die = nullptr;
- T_Damage(best, ent, ent->teammaster, vec3_origin, best->s.origin, vec3_origin, 100000, 1, DAMAGE_NONE, MOD_TRAP);
- if (best->svflags & SVF_MONSTER)
- M_ProcessPain(best);
- ent->enemy = best;
- ent->wait = 64;
- ent->s.old_origin = ent->s.origin;
- ent->timestamp = level.time + 30_sec;
- ent->accel = best->mass;
- if (deathmatch->integer)
- ent->mass = best->mass / 4;
- else
- ent->mass = best->mass / 10;
- // ok spawn the food cube
- ent->s.frame = 5;
- // link up any gibs that this monster may have spawned
- for (uint32_t i = 0; i < globals.num_edicts; i++)
- {
- edict_t *e = &g_edicts[i];
- if (!e->inuse)
- continue;
- else if (strcmp(e->classname, "gib"))
- continue;
- else if ((e->s.origin - ent->s.origin).length() > 128.f)
- continue;
- e->movetype = MOVETYPE_NONE;
- e->nextthink = level.time + FRAME_TIME_S;
- e->think = Trap_Gib_Think;
- e->owner = ent;
- Trap_Gib_Think(e);
- }
- }
- else
- {
- BecomeExplosion1(ent);
- // note to self
- // cause explosion damage???
- return;
- }
- }
- }
- }
- // RAFAEL
- void fire_trap(edict_t *self, const vec3_t &start, const vec3_t &aimdir, int speed)
- {
- edict_t *trap;
- vec3_t dir;
- vec3_t forward, right, up;
- dir = vectoangles(aimdir);
- AngleVectors(dir, forward, right, up);
- trap = G_Spawn();
- trap->s.origin = start;
- trap->velocity = aimdir * speed;
- float gravityAdjustment = level.gravity / 800.f;
- trap->velocity += up * (200 + crandom() * 10.0f) * gravityAdjustment;
- trap->velocity += right * (crandom() * 10.0f);
- trap->avelocity = { 0, 300, 0 };
- trap->movetype = MOVETYPE_BOUNCE;
- trap->solid = SOLID_BBOX;
- trap->takedamage = true;
- trap->mins = { -4, -4, 0 };
- trap->maxs = { 4, 4, 8 };
- trap->die = trap_die;
- trap->health = 20;
- trap->s.modelindex = gi.modelindex("models/weapons/z_trap/tris.md2");
- trap->owner = trap->teammaster = self;
- trap->nextthink = level.time + 1_sec;
- trap->think = Trap_Think;
- trap->classname = "food_cube_trap";
- // RAFAEL 16-APR-98
- trap->s.sound = gi.soundindex("weapons/traploop.wav");
- // END 16-APR-98
- trap->flags |= ( FL_DAMAGEABLE | FL_MECHANICAL | FL_TRAP );
- trap->clipmask = MASK_PROJECTILE & ~CONTENTS_DEADMONSTER;
- // [Paril-KEX]
- if (self->client && !G_ShouldPlayersCollide(true))
- trap->clipmask &= ~CONTENTS_PLAYER;
- gi.linkentity(trap);
- trap->timestamp = level.time + 30_sec;
- }
|