123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503 |
- /* Copyright (C) 1996-2022 id Software LLC
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- See file, 'COPYING', for details.
- */
- /*
- */
- void (entity targ, entity inflictor, entity attacker, float damage) T_Damage;
- void () player_run;
- void(entity bomb, entity attacker, float rad, entity ignore) T_RadiusDamage;
- void(vector org, vector vel, float damage) SpawnBlood;
- void() SuperDamageSound;
- // called by worldspawn
- void() W_Precache =
- {
- precache_sound ("weapons/r_exp3.wav"); // new rocket explosion
- precache_sound ("weapons/rocket1i.wav"); // spike gun
- precache_sound ("weapons/sgun1.wav");
- precache_sound ("weapons/guncock.wav"); // player shotgun
- precache_sound ("weapons/ric1.wav"); // ricochet (used in c code)
- precache_sound ("weapons/ric2.wav"); // ricochet (used in c code)
- precache_sound ("weapons/ric3.wav"); // ricochet (used in c code)
- precache_sound ("weapons/spike2.wav"); // super spikes
- precache_sound ("weapons/tink1.wav"); // spikes tink (used in c code)
- precache_sound ("weapons/grenade.wav"); // grenade launcher
- precache_sound ("weapons/bounce.wav"); // grenade bounce
- precache_sound ("weapons/shotgn2.wav"); // super shotgun
- };
- float() crandom =
- {
- return 2*(random() - 0.5);
- };
- /*
- ================
- W_FireAxe
- ================
- */
- void() W_FireAxe =
- {
- local vector source;
- local vector org;
-
- makevectors (self.v_angle);
- source = self.origin + '0 0 16';
-
- traceline (source, source + v_forward*64, FALSE, self);
- if (trace_fraction == 1.0)
- return;
- org = trace_endpos - v_forward*4;
- if (trace_ent.takedamage && trace_ent.classname != "monster_boss") // yoder mod, Jan 05 2021
- {
- trace_ent.axhitme = 1;
- SpawnBlood (org, '0 0 0', 20);
- T_Damage (trace_ent, self, self, 20);
- }
- else
- { // hit wall
- sound (self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM);
- WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
- WriteByte (MSG_BROADCAST, TE_GUNSHOT);
- WriteCoord (MSG_BROADCAST, org_x);
- WriteCoord (MSG_BROADCAST, org_y);
- WriteCoord (MSG_BROADCAST, org_z);
- }
- };
- //============================================================================
- vector() wall_velocity =
- {
- local vector vel;
-
- vel = normalize (self.velocity);
- vel = normalize(vel + v_up*(random()- 0.5) + v_right*(random()- 0.5));
- vel = vel + 2*trace_plane_normal;
- vel = vel * 200;
-
- return vel;
- };
- /*
- ================
- SpawnMeatSpray
- ================
- */
- void(vector org, vector vel) SpawnMeatSpray =
- {
- local entity missile;
- missile = spawn ();
- missile.owner = self;
- missile.movetype = MOVETYPE_BOUNCE;
- missile.solid = SOLID_NOT;
- makevectors (self.angles);
- missile.velocity = vel;
- missile.velocity_z = missile.velocity_z + 250 + 50*random();
- missile.avelocity = '3000 1000 2000';
-
- // set missile duration
- missile.nextthink = time + 1;
- missile.think = SUB_Remove;
- setmodel (missile, "progs/zom_gib.mdl");
- setsize (missile, '0 0 0', '0 0 0');
- setorigin (missile, org);
- };
- /*
- ================
- SpawnBlood
- ================
- */
- void(vector org, vector vel, float damage) SpawnBlood =
- {
- particle (org, vel*0.1, 73, damage*2);
- };
- /*
- ================
- spawn_touchblood
- ================
- */
- void(float damage) spawn_touchblood =
- {
- local vector vel;
- vel = wall_velocity () * 0.2;
- SpawnBlood (self.origin + vel*0.01, vel, damage);
- };
- /*
- ================
- SpawnChunk
- ================
- */
- void(vector org, vector vel) SpawnChunk =
- {
- particle (org, vel*0.02, 0, 10);
- };
- /*
- ==============================================================================
- MULTI-DAMAGE
- Collects multiple small damages into a single damage
- ==============================================================================
- */
- entity multi_ent;
- float multi_damage;
- void() ClearMultiDamage =
- {
- multi_ent = world;
- multi_damage = 0;
- };
- void() ApplyMultiDamage =
- {
- if (!multi_ent)
- return;
- T_Damage (multi_ent, self, self, multi_damage);
- };
- void(entity hit, float damage) AddMultiDamage =
- {
- if (!hit)
- return;
-
- if (hit != multi_ent)
- {
- ApplyMultiDamage ();
- multi_damage = damage;
- multi_ent = hit;
- }
- else
- multi_damage = multi_damage + damage;
- };
- /*
- ==============================================================================
- BULLETS
- ==============================================================================
- */
- /*
- ================
- TraceAttack
- ================
- */
- void(float damage, vector dir) TraceAttack =
- {
- local vector vel, org;
-
- vel = normalize(dir + v_up*crandom() + v_right*crandom());
- vel = vel + 2*trace_plane_normal;
- vel = vel * 200;
- org = trace_endpos - dir*4;
- if (trace_ent.takedamage && trace_ent.classname != "monster_boss") // yoder mod, Jan 05 2021
- {
- SpawnBlood (org, vel*0.2, damage);
- AddMultiDamage (trace_ent, damage);
- }
- else
- {
- WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
- WriteByte (MSG_BROADCAST, TE_GUNSHOT);
- WriteCoord (MSG_BROADCAST, org_x);
- WriteCoord (MSG_BROADCAST, org_y);
- WriteCoord (MSG_BROADCAST, org_z);
- }
- };
- /*
- ================
- FireBullets
- Used by shotgun, super shotgun, and enemy soldier firing
- Go to the trouble of combining multiple pellets into a single damage call.
- ================
- */
- void(float shotcount, vector dir, vector spread) FireBullets =
- {
- local vector direction;
- local vector src;
-
- makevectors(self.v_angle);
- src = self.origin + v_forward*10;
- src_z = self.absmin_z + self.size_z * 0.7;
- ClearMultiDamage ();
- while (shotcount > 0)
- {
- direction = dir + crandom()*spread_x*v_right + crandom()*spread_y*v_up;
- traceline (src, src + direction*2048, FALSE, self);
- if (trace_fraction != 1.0)
- TraceAttack (4, direction);
- shotcount = shotcount - 1;
- }
- ApplyMultiDamage ();
- };
- /*
- ================
- W_FireShotgun
- ================
- */
- void() W_FireShotgun =
- {
- local vector dir;
- sound (self, CHAN_WEAPON, "weapons/guncock.wav", 1, ATTN_NORM);
- self.punchangle_x = -2;
-
- self.currentammo = self.ammo_shells = self.ammo_shells - 1;
- dir = aim (self, 100000);
- FireBullets (6, dir, '0.04 0.04 0');
- };
- /*
- ================
- W_FireSuperShotgun
- ================
- */
- void() W_FireSuperShotgun =
- {
- local vector dir;
- if (self.currentammo == 1)
- {
- W_FireShotgun ();
- return;
- }
-
- sound (self ,CHAN_WEAPON, "weapons/shotgn2.wav", 1, ATTN_NORM);
- self.punchangle_x = -4;
-
- self.currentammo = self.ammo_shells = self.ammo_shells - 2;
- dir = aim (self, 100000);
- FireBullets (14, dir, '0.14 0.08 0');
- };
- /*
- ==============================================================================
- ROCKETS
- ==============================================================================
- */
- void() s_explode1 = [0, s_explode2] {};
- void() s_explode2 = [1, s_explode3] {};
- void() s_explode3 = [2, s_explode4] {};
- void() s_explode4 = [3, s_explode5] {};
- void() s_explode5 = [4, s_explode6] {};
- void() s_explode6 = [5, SUB_Remove] {};
- void() BecomeExplosion =
- {
- self.movetype = MOVETYPE_NONE;
- self.velocity = '0 0 0';
- self.touch = SUB_Null;
- setmodel (self, "progs/s_explod.spr");
- self.solid = SOLID_NOT;
- s_explode1 ();
- };
- void() T_MissileTouch =
- {
- local float damg;
- if (other == self.owner)
- return; // don't explode on owner
- if (pointcontents(self.origin) == CONTENT_SKY)
- {
- remove(self);
- return;
- }
- damg = 100 + random()*20;
-
- if (other.health)
- {
- if (other.classname == "monster_shambler")
- damg = damg * 0.5; // mostly immune
- T_Damage (other, self, self.owner, damg );
- }
- // don't do radius damage to the other, because all the damage
- // was done in the impact
- T_RadiusDamage (self, self.owner, 120, other);
- // sound (self, CHAN_WEAPON, "weapons/r_exp3.wav", 1, ATTN_NORM);
- self.origin = self.origin - 8*normalize(self.velocity);
- WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
- WriteByte (MSG_BROADCAST, TE_EXPLOSION);
- WriteCoord (MSG_BROADCAST, self.origin_x);
- WriteCoord (MSG_BROADCAST, self.origin_y);
- WriteCoord (MSG_BROADCAST, self.origin_z);
- BecomeExplosion ();
- };
- /*
- ================
- W_FireRocket
- ================
- */
- void() W_FireRocket =
- {
- local entity missile;
-
- self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
-
- sound (self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM);
- self.punchangle_x = -2;
- missile = spawn ();
- missile.owner = self;
- missile.movetype = MOVETYPE_FLYMISSILE;
- missile.solid = SOLID_BBOX;
- missile.classname = "missile";
-
- // set missile speed
- makevectors (self.v_angle);
- missile.velocity = aim(self, 1000);
- missile.velocity = missile.velocity * 1000;
- missile.angles = vectoangles(missile.velocity);
-
- missile.touch = T_MissileTouch;
-
- // set missile duration
- missile.nextthink = time + 5;
- missile.think = SUB_Remove;
- setmodel (missile, "progs/missile.mdl");
- setsize (missile, '0 0 0', '0 0 0');
- setorigin (missile, self.origin + v_forward*8 + '0 0 16');
- };
- /*
- ===============================================================================
- LIGHTNING
- ===============================================================================
- */
- /*
- =================
- LightningDamage
- =================
- */
- void(vector p1, vector p2, entity from, float damage) LightningDamage =
- {
- local entity e1, e2;
- local vector f;
-
- f = p2 - p1;
- normalize (f);
- f_x = 0 - f_y;
- f_y = f_x;
- f_z = 0;
- f = f*16;
- e1 = e2 = world;
- traceline (p1, p2, FALSE, self);
- if (trace_ent.takedamage)
- {
- particle (trace_endpos, '0 0 100', 225, damage*4);
- T_Damage (trace_ent, from, from, damage);
- if (self.classname == "player")
- {
- if (other.classname == "player")
- trace_ent.velocity_z = trace_ent.velocity_z + 400;
- }
- }
- e1 = trace_ent;
- traceline (p1 + f, p2 + f, FALSE, self);
- if (trace_ent != e1 && trace_ent.takedamage)
- {
- particle (trace_endpos, '0 0 100', 225, damage*4);
- T_Damage (trace_ent, from, from, damage);
- }
- e2 = trace_ent;
- traceline (p1 - f, p2 - f, FALSE, self);
- if (trace_ent != e1 && trace_ent != e2 && trace_ent.takedamage)
- {
- particle (trace_endpos, '0 0 100', 225, damage*4);
- T_Damage (trace_ent, from, from, damage);
- }
- };
- void() W_FireLightning =
- {
- local vector org;
- local float cells;
- if (self.ammo_cells < 1)
- {
- self.weapon = W_BestWeapon ();
- W_SetCurrentAmmo ();
- return;
- }
- // explode if under water
- if (self.waterlevel > 1)
- {
- cells = self.ammo_cells;
- self.ammo_cells = 0;
- W_SetCurrentAmmo ();
- T_RadiusDamage (self, self, 35*cells, world);
- return;
- }
- if (self.t_width < time)
- {
- sound (self, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM);
- self.t_width = time + 0.6;
- }
- self.punchangle_x = -2;
- self.currentammo = self.ammo_cells = self.ammo_cells - 1;
- org = self.origin + '0 0 16';
-
- traceline (org, org + v_forward*600, TRUE, self);
- WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
- WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
- WriteEntity (MSG_BROADCAST, self);
- WriteCoord (MSG_BROADCAST, org_x);
- WriteCoord (MSG_BROADCAST, org_y);
- WriteCoord (MSG_BROADCAST, org_z);
- WriteCoord (MSG_BROADCAST, trace_endpos_x);
- WriteCoord (MSG_BROADCAST, trace_endpos_y);
- WriteCoord (MSG_BROADCAST, trace_endpos_z);
- LightningDamage (self.origin, trace_endpos + v_forward*4, self, 30);
- };
- //=============================================================================
- void() GrenadeExplode =
- {
- T_RadiusDamage (self, self.owner, self.dmg, world);
- WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
- WriteByte (MSG_BROADCAST, TE_EXPLOSION);
- WriteCoord (MSG_BROADCAST, self.origin_x);
- WriteCoord (MSG_BROADCAST, self.origin_y);
- WriteCoord (MSG_BROADCAST, self.origin_z);
- BecomeExplosion ();
- };
- void GrenadeThink()
- {
- self.cnt += 1;
- // Count to 50 at 20 ticks per second = 2.5 seconds until explosion
- if(self.cnt == 50)
- {
- GrenadeExplode();
- return;
- }
- float oldVel = vlen(self.oldorigin);
- float vel = vlen(self.velocity);
- if(vel == 0) //Stuck on downward slope?
- {
- if(oldVel > 120 && self.oldorigin_z < 0) //Were we moving downwards at a decent speed last tick?
- {
- // Trace straight down and find the normal of the surface it bounced off
- traceline(self.origin + '0 0 4', self.origin - '0 0 8', TRUE, self);
- if(trace_fraction < 1.0) // Hit something...
- {
- // dprint("reflected grenade bounce\n");
- // Reflect the previous velocity off that normal
- vector reflected = self.oldorigin - 2 * (self.oldorigin * trace_plane_normal) * trace_plane_normal;
-
- self.flags &~= FL_ONGROUND; //Remove FL_ONGROUND
- self.velocity = reflected * 0.6; // Scale it down a bit so it feels better
- self.avelocity = '400 400 400'; // Roll that sucker around
- }
- }
- }
- self.oldorigin = self.velocity;
- self.nextthink = time + 0.05;
- }
- void() GrenadeTouch =
- {
- if (other == self.owner)
- return; // don't explode on owner
- if (other.takedamage == DAMAGE_AIM)
- {
- GrenadeExplode();
- return;
- }
- if(self.velocity == '0 0 0')
- {
- self.avelocity = '0 0 0';
- }
- if(self.attack_finished < time)
- sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); // bounce sound
- self.attack_finished = time + 0.1;
- };
- /*
- ================
- W_FireGrenade
- ================
- */
- void W_FireGrenade(float damage, vector direction);
- void W_FireGrenadeLauncher()
- {
- float damage = 120;
- makevectors (self.v_angle);
- vector velocity;
- if (self.v_angle_x)
- velocity = v_forward*600 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;
- else
- {
- velocity = aim(self, 10000);
- velocity = velocity * 600;
- velocity_z = 200;
- }
- W_FireGrenade(damage, velocity) ;
- }
- void W_FireGrenade(float damage, vector direction)
- {
- local entity missile;
-
- self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
-
- sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
- self.punchangle_x = -2;
- missile = spawn ();
- missile.owner = self;
- missile.movetype = MOVETYPE_BOUNCE;
- missile.solid = SOLID_BBOX;
- missile.classname = "grenade";
- missile.dmg = damage;
-
- // set missile speed
- missile.velocity = direction;
- missile.oldorigin = direction;
- missile.avelocity = '300 300 300';
- missile.angles = vectoangles(missile.velocity);
-
- missile.touch = GrenadeTouch;
-
- #ifdef GRENADE_BOUNCE_FIX
- // set missile duration
- missile.nextthink = time + 0.05;
- missile.think = GrenadeThink;
- #else
- // Uncomment this to go back to old grenade behaviour with no slope bounce fix.
- missile.nextthink = time + 2.5;
- missile.think = GrenadeExplode;
- #endif //GRENADE_BOUNCE_FIX
-
- setmodel (missile, "progs/grenade.mdl");
- setsize (missile, '0 0 0', '0 0 0');
- setorigin (missile, self.origin);
- };
- //=============================================================================
- void() spike_touch;
- void() superspike_touch;
- /*
- ===============
- launch_spike
- Used for both the player and the ogre
- ===============
- */
- void(vector org, vector dir) launch_spike =
- {
- newmis = spawn ();
- newmis.owner = self;
- newmis.movetype = MOVETYPE_FLYMISSILE;
- newmis.solid = SOLID_BBOX;
- newmis.angles = vectoangles(dir);
-
- newmis.touch = spike_touch;
- newmis.classname = "spike";
- newmis.think = SUB_Remove;
- newmis.nextthink = time + 6;
- setmodel (newmis, "progs/spike.mdl");
- setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
- setorigin (newmis, org);
- newmis.velocity = dir * 1000;
- };
- void() W_FireSuperSpikes =
- {
- local vector dir;
-
- sound (self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM);
- self.attack_finished = time + 0.2;
- self.currentammo = self.ammo_nails = self.ammo_nails - 2;
- dir = aim (self, 1000);
- launch_spike (self.origin + '0 0 16', dir);
- newmis.touch = superspike_touch;
- setmodel (newmis, "progs/s_spike.mdl");
- setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
- self.punchangle_x = -2;
- };
- void(float ox) W_FireSpikes =
- {
- local vector dir;
-
- makevectors (self.v_angle);
-
- if (self.ammo_nails >= 2 && self.weapon == IT_SUPER_NAILGUN)
- {
- W_FireSuperSpikes ();
- return;
- }
- if (self.ammo_nails < 1)
- {
- self.weapon = W_BestWeapon ();
- W_SetCurrentAmmo ();
- return;
- }
- sound (self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM);
- self.attack_finished = time + 0.2;
- self.currentammo = self.ammo_nails = self.ammo_nails - 1;
- dir = aim (self, 1000);
- launch_spike (self.origin + '0 0 16' + v_right*ox, dir);
- self.punchangle_x = -2;
- };
- .float hit_z;
- void() spike_touch =
- {
- if (other == self.owner)
- return;
- if (other.solid == SOLID_TRIGGER)
- return; // trigger field, do nothing
- if (pointcontents(self.origin) == CONTENT_SKY)
- {
- remove(self);
- return;
- }
-
- // hit something that bleeds
- if (other.takedamage && other.classname != "monster_boss") // yoder mod, jan 05 2021
- {
- spawn_touchblood (9);
- T_Damage (other, self, self.owner, 9);
- }
- else
- {
- WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
-
- if (self.classname == "wizspike")
- WriteByte (MSG_BROADCAST, TE_WIZSPIKE);
- else if (self.classname == "knightspike")
- WriteByte (MSG_BROADCAST, TE_KNIGHTSPIKE);
- else
- WriteByte (MSG_BROADCAST, TE_SPIKE);
- WriteCoord (MSG_BROADCAST, self.origin_x);
- WriteCoord (MSG_BROADCAST, self.origin_y);
- WriteCoord (MSG_BROADCAST, self.origin_z);
- }
- remove(self);
- };
- void() superspike_touch =
- {
- if (other == self.owner)
- return;
- if (other.solid == SOLID_TRIGGER)
- return; // trigger field, do nothing
- if (pointcontents(self.origin) == CONTENT_SKY)
- {
- remove(self);
- return;
- }
-
- // hit something that bleeds
- if (other.takedamage && other.classname != "monster_boss") // yoder mod, Jan 05 2021
- {
- spawn_touchblood (18);
- T_Damage (other, self, self.owner, 18);
- }
- else
- {
- WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
- WriteByte (MSG_BROADCAST, TE_SUPERSPIKE);
- WriteCoord (MSG_BROADCAST, self.origin_x);
- WriteCoord (MSG_BROADCAST, self.origin_y);
- WriteCoord (MSG_BROADCAST, self.origin_z);
- }
- remove(self);
- };
- /*
- ===============================================================================
- PLAYER WEAPON USE
- ===============================================================================
- */
- void() W_SetCurrentAmmo =
- {
- player_run (); // get out of any weapon firing states
- self.items = self.items - ( self.items & (IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS) );
-
- if (self.weapon == IT_AXE)
- {
- self.currentammo = 0;
- self.weaponmodel = "progs/v_axe.mdl";
- self.weaponframe = 0;
- }
- else if (self.weapon == IT_SHOTGUN)
- {
- self.currentammo = self.ammo_shells;
- self.weaponmodel = "progs/v_shot.mdl";
- self.weaponframe = 0;
- self.items = self.items | IT_SHELLS;
- }
- else if (self.weapon == IT_SUPER_SHOTGUN)
- {
- self.currentammo = self.ammo_shells;
- self.weaponmodel = "progs/v_shot2.mdl";
- self.weaponframe = 0;
- self.items = self.items | IT_SHELLS;
- }
- else if (self.weapon == IT_NAILGUN)
- {
- self.currentammo = self.ammo_nails;
- self.weaponmodel = "progs/v_nail.mdl";
- self.weaponframe = 0;
- self.items = self.items | IT_NAILS;
- }
- else if (self.weapon == IT_SUPER_NAILGUN)
- {
- self.currentammo = self.ammo_nails;
- self.weaponmodel = "progs/v_nail2.mdl";
- self.weaponframe = 0;
- self.items = self.items | IT_NAILS;
- }
- else if (self.weapon == IT_GRENADE_LAUNCHER)
- {
- self.currentammo = self.ammo_rockets;
- self.weaponmodel = "progs/v_rock.mdl";
- self.weaponframe = 0;
- self.items = self.items | IT_ROCKETS;
- }
- else if (self.weapon == IT_ROCKET_LAUNCHER)
- {
- self.currentammo = self.ammo_rockets;
- self.weaponmodel = "progs/v_rock2.mdl";
- self.weaponframe = 0;
- self.items = self.items | IT_ROCKETS;
- }
- else if (self.weapon == IT_LIGHTNING)
- {
- self.currentammo = self.ammo_cells;
- self.weaponmodel = "progs/v_light.mdl";
- self.weaponframe = 0;
- self.items = self.items | IT_CELLS;
- }
- else
- {
- self.currentammo = 0;
- self.weaponmodel = string_null;
- self.weaponframe = 0;
- }
- };
- float() W_BestWeapon =
- {
- local float it;
-
- it = self.items;
- if (self.waterlevel <= 1 && self.ammo_cells >= 1 && (it & IT_LIGHTNING) )
- return IT_LIGHTNING;
- if(self.ammo_nails >= 2 && (it & IT_SUPER_NAILGUN) )
- return IT_SUPER_NAILGUN;
- if(self.ammo_shells >= 2 && (it & IT_SUPER_SHOTGUN) )
- return IT_SUPER_SHOTGUN;
- if(self.ammo_nails >= 1 && (it & IT_NAILGUN) )
- return IT_NAILGUN;
- if(self.ammo_shells >= 1 && (it & IT_SHOTGUN) )
- return IT_SHOTGUN;
- if(it & IT_AXE)
- return IT_AXE;
- //No weapon
- return 0;
- };
- float(entity playerEnt, float old, float new) W_WantsToChangeWeapon =
- {
- float playerFlags = CheckPlayerEXFlags(playerEnt);
- if((playerFlags & PEF_CHANGENEVER) != 0)
- {
- return 0;
- }
-
- if(((playerFlags & PEF_CHANGEONLYNEW) != 0) && old == new)
- {
- return 0;
- }
- return 1;
- };
- float() W_CheckNoAmmo =
- {
- if (self.currentammo > 0)
- return TRUE;
- if (self.weapon == IT_AXE)
- return TRUE;
-
- self.weapon = W_BestWeapon ();
- W_SetCurrentAmmo ();
-
- // drop the weapon down
- return FALSE;
- };
- /*
- ============
- W_Attack
- An attack impulse can be triggered now
- ============
- */
- void() player_axe1;
- void() player_axeb1;
- void() player_axec1;
- void() player_axed1;
- void() player_shot1;
- void() player_nail1;
- void() player_light1;
- void() player_rocket1;
- void() W_Attack =
- {
- local float r;
- if (!self.weapon)
- return;
- if (!W_CheckNoAmmo ())
- return;
- makevectors (self.v_angle); // calculate forward angle for velocity
- self.show_hostile = time + 1; // wake monsters up
- if (self.weapon == IT_AXE)
- {
- sound (self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM);
- r = random();
-
- if(cvar("horde") && (serverflags & SIGIL_E3)) // horde rune behavior
- {
- if ((self.axe_hit_chain >= 2) && (time < self.axe_hit_chain_time))
- {
- dprint("vertical chop: ");
- // vertical CHOP
- if (r < 0.5)
- {
- dprint(" axe1\n");
- player_axe1 ();
- }
- else
- {
- dprint(" axec1\n");
- player_axec1 ();
- }
- self.attack_finished = time + 0.8; // long recover
- }
- else
- {
- dprint("diagonal sweep:");
- // diagonal SWEEP
- if (r < 0.5)
- {
- dprint(" axeb1\n");
- player_axeb1 ();
- }
- else
- {
- dprint(" axed1\n");
- player_axed1 ();
- }
-
- if (self.axe_hit_chain > 1)
- self.attack_finished = time + 0.6;
- else
- self.attack_finished = time + 0.4;
-
- }
- }
- else // normal behavior
- {
- r = random();
- if (r < 0.25)
- {
- dprint("axe1\n");
- player_axe1 ();
- }
- else if (r<0.5)
- {
- dprint("axeb1\n");
- player_axeb1 ();
- }
- else if (r<0.75)
- {
- dprint("axec1\n");
- player_axec1 ();
- }
- else
- {
- dprint("axed1\n");
- player_axed1 ();
- }
- self.attack_finished = time + 0.5;
- }
-
- }
- else if (self.weapon == IT_SHOTGUN)
- {
- player_shot1 ();
- W_FireShotgun ();
- self.attack_finished = time + 0.5;
- }
- else if (self.weapon == IT_SUPER_SHOTGUN)
- {
- player_shot1 ();
- W_FireSuperShotgun ();
- self.attack_finished = time + 0.7;
- }
- else if (self.weapon == IT_NAILGUN)
- {
- player_nail1 ();
- }
- else if (self.weapon == IT_SUPER_NAILGUN)
- {
- player_nail1 ();
- }
- else if (self.weapon == IT_GRENADE_LAUNCHER)
- {
- player_rocket1();
- W_FireGrenadeLauncher();
- self.attack_finished = time + 0.6;
- }
- else if (self.weapon == IT_ROCKET_LAUNCHER)
- {
- player_rocket1();
- W_FireRocket();
- self.attack_finished = time + 0.8;
- }
- else if (self.weapon == IT_LIGHTNING)
- {
- player_light1();
- self.attack_finished = time + 0.1;
- sound (self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM);
- }
- };
- /*
- ============
- W_ChangeWeapon
- ============
- */
- void() W_ChangeWeapon =
- {
- local float it, am, fl;
-
- it = self.items;
- am = 0;
-
- if (self.impulse == 1)
- {
- fl = IT_AXE;
- }
- else if (self.impulse == 2)
- {
- fl = IT_SHOTGUN;
- if (self.ammo_shells < 1)
- am = 1;
- }
- else if (self.impulse == 3)
- {
- fl = IT_SUPER_SHOTGUN;
- if (self.ammo_shells < 2)
- am = 1;
- }
- else if (self.impulse == 4)
- {
- fl = IT_NAILGUN;
- if (self.ammo_nails < 1)
- am = 1;
- }
- else if (self.impulse == 5)
- {
- fl = IT_SUPER_NAILGUN;
- if (self.ammo_nails < 2)
- am = 1;
- }
- else if (self.impulse == 6)
- {
- fl = IT_GRENADE_LAUNCHER;
- if (self.ammo_rockets < 1)
- am = 1;
- }
- else if (self.impulse == 7)
- {
- fl = IT_ROCKET_LAUNCHER;
- if (self.ammo_rockets < 1)
- am = 1;
- }
- else if (self.impulse == 8)
- {
- fl = IT_LIGHTNING;
- if (self.ammo_cells < 1)
- am = 1;
- }
- self.impulse = 0;
-
- if (!(self.items & fl))
- { // don't have the weapon or the ammo
- sprint (self, "$qc_no_weapon");
- return;
- }
-
- if (am)
- { // don't have the ammo
- sprint (self, "$qc_not_enough_ammo");
- return;
- }
- //
- // set weapon, set ammo
- //
- self.weapon = fl;
- W_SetCurrentAmmo ();
- };
- /*
- ============
- CheatCommand
- ============
- */
- void(float NoKeys = FALSE) CheatCommand =
- {
- if ( ( deathmatch || coop ) && cheats_allowed == 0 ) { // mal: allow impulse 9 IF cheats allowed
- return;
- }
- self.ammo_rockets = 100;
- self.ammo_nails = 200;
- self.ammo_shells = 100;
- if(NoKeys)
- {
- self.items = self.items |
- IT_AXE |
- IT_SHOTGUN |
- IT_SUPER_SHOTGUN |
- IT_NAILGUN |
- IT_SUPER_NAILGUN |
- IT_GRENADE_LAUNCHER |
- IT_ROCKET_LAUNCHER;
- }
- else
- {
- self.items = self.items |
- IT_AXE |
- IT_SHOTGUN |
- IT_SUPER_SHOTGUN |
- IT_NAILGUN |
- IT_SUPER_NAILGUN |
- IT_GRENADE_LAUNCHER |
- IT_ROCKET_LAUNCHER |
- IT_KEY1 | IT_KEY2;
- }
- self.ammo_cells = 200;
- self.items = self.items | IT_LIGHTNING;
- self.weapon = IT_ROCKET_LAUNCHER;
- self.impulse = 0;
- W_SetCurrentAmmo ();
- };
- /*
- ============
- CycleWeaponCommand
- Go to the next weapon with ammo
- ============
- */
- void() CycleWeaponCommand =
- {
- local float it, am, wep;
-
- it = self.items;
- wep = self.weapon;
- self.impulse = 0;
- float cnt = 10;
- while (cnt)
- {
- am = 0;
- if(!wep)
- {
- wep = IT_AXE;
- }
- else if (wep == IT_LIGHTNING)
- {
- wep = IT_AXE;
- }
- else if (wep == IT_AXE)
- {
- wep = IT_SHOTGUN;
- if (self.ammo_shells < 1)
- am = 1;
- }
- else if (wep == IT_SHOTGUN)
- {
- wep = IT_SUPER_SHOTGUN;
- if (self.ammo_shells < 2)
- am = 1;
- }
- else if (wep == IT_SUPER_SHOTGUN)
- {
- wep = IT_NAILGUN;
- if (self.ammo_nails < 1)
- am = 1;
- }
- else if (wep == IT_NAILGUN)
- {
- wep = IT_SUPER_NAILGUN;
- if (self.ammo_nails < 2)
- am = 1;
- }
- else if (wep == IT_SUPER_NAILGUN)
- {
- wep = IT_GRENADE_LAUNCHER;
- if (self.ammo_rockets < 1)
- am = 1;
- }
- else if (wep == IT_GRENADE_LAUNCHER)
- {
- wep = IT_ROCKET_LAUNCHER;
- if (self.ammo_rockets < 1)
- am = 1;
- }
- else if (wep == IT_ROCKET_LAUNCHER)
- {
- wep = IT_LIGHTNING;
- if (self.ammo_cells < 1)
- am = 1;
- }
-
- if ( (it & wep) && am == 0)
- {
- self.weapon = wep;
- W_SetCurrentAmmo ();
- return;
- }
- cnt--;
- }
- };
- /*
- ============
- CycleWeaponReverseCommand
- Go to the prev weapon with ammo
- ============
- */
- void() CycleWeaponReverseCommand =
- {
- local float it, am, wep;
-
- it = self.items;
- wep = self.weapon;
- self.impulse = 0;
- float cnt = 10;
- while (cnt)
- {
- am = 0;
- if(!wep)
- {
- wep = IT_LIGHTNING;
- }
- else if (wep == IT_LIGHTNING)
- {
- wep = IT_ROCKET_LAUNCHER;
- if (self.ammo_rockets < 1)
- am = 1;
- }
- else if (wep == IT_ROCKET_LAUNCHER)
- {
- wep = IT_GRENADE_LAUNCHER;
- if (self.ammo_rockets < 1)
- am = 1;
- }
- else if (wep == IT_GRENADE_LAUNCHER)
- {
- wep = IT_SUPER_NAILGUN;
- if (self.ammo_nails < 2)
- am = 1;
- }
- else if (wep == IT_SUPER_NAILGUN)
- {
- wep = IT_NAILGUN;
- if (self.ammo_nails < 1)
- am = 1;
- }
- else if (wep == IT_NAILGUN)
- {
- wep = IT_SUPER_SHOTGUN;
- if (self.ammo_shells < 2)
- am = 1;
- }
- else if (wep == IT_SUPER_SHOTGUN)
- {
- wep = IT_SHOTGUN;
- if (self.ammo_shells < 1)
- am = 1;
- }
- else if (wep == IT_SHOTGUN)
- {
- wep = IT_AXE;
- }
- else if (wep == IT_AXE)
- {
- wep = IT_LIGHTNING;
- if (self.ammo_cells < 1)
- am = 1;
- }
-
- if ( (it & wep) && am == 0)
- {
- self.weapon = wep;
- W_SetCurrentAmmo ();
- return;
- }
- cnt--;
- }
- };
- /*
- ============
- ServerflagsCommand
- Just for development
- ============
- */
- void() ServerflagsCommand =
- {
- serverflags = serverflags * 2 + 1;
- };
- void() QuadCheat =
- {
- if (deathmatch || coop)
- return;
- self.super_time = 1;
- self.super_damage_finished = time + 30;
- self.items = self.items | IT_QUAD;
- dprint ("quad cheat\n");
- };
- void() Omnicide =
- {
- entity oself = self;
- self = nextent(world);
- while(self)
- {
- if(self.flags & (FL_MONSTER | FL_FUTUREMONSTER))
- {
- if(self.target || self.killtarget)
- {
- SUB_UseTargets();
- }
- SUB_Remove();
- }
- self = nextent(self);
- }
- self = oself;
- killed_monsters = total_monsters;
- WriteByte (MSG_ALL, SVC_UPDATESTAT);
- WriteByte(MSG_ALL, 14); // 14 = STAT_MONSTERS
- WriteLong(MSG_ALL, total_monsters);
- }
- /*
- ============
- ImpulseCommands
- ============
- */
- void() ImpulseCommands =
- {
- if (self.impulse >= 1 && self.impulse <= 8)
- W_ChangeWeapon ();
- else if (self.impulse == 9)
- CheatCommand ();
- else if (self.impulse == 99)
- CheatCommand (TRUE);
- else if (self.impulse == 10)
- CycleWeaponCommand ();
- else if (self.impulse == 11)
- ServerflagsCommand ();
- else if (self.impulse == 12)
- CycleWeaponReverseCommand ();
- else if (self.impulse == 255)
- QuadCheat ();
-
- else if (self.impulse == 219)
- Omnicide ();
-
- self.impulse = 0;
- };
- /*
- ============
- W_WeaponFrame
- Called every frame so impulse events can be handled as well as possible
- ============
- */
- void() W_WeaponFrame =
- {
- if (time < self.attack_finished)
- return;
- ImpulseCommands ();
-
- // check for attack
- if (self.button0)
- {
- SuperDamageSound ();
- W_Attack ();
- }
- };
- /*
- ========
- SuperDamageSound
- Plays sound if needed
- ========
- */
- void() SuperDamageSound =
- {
- if (self.super_damage_finished > time)
- {
- if (self.super_sound < time)
- {
- self.super_sound = time + 1;
- sound (self, CHAN_BODY, "items/damage3.wav", 1, ATTN_NORM);
- }
- }
- return;
- };
|