From 4e9e5692d3fce94eaee0f7214c4f7e2120f4364c Mon Sep 17 00:00:00 2001 From: archive Date: Thu, 22 Sep 2005 00:00:00 +0000 Subject: [PATCH] as released 2005-09-22 --- AI.c | 897 +++++++++++++++ AMTEST.c | 85 ++ BUTTONS.c | 143 +++ CLIENT.c | 2032 +++++++++++++++++++++++++++++++++ COMBAT.c | 424 +++++++ DEFS.c | 705 ++++++++++++ DOORS.c | 834 ++++++++++++++ EXPLBRSH.c | 117 ++ FIGHT.c | 435 +++++++ ITEMS.c | 2739 ++++++++++++++++++++++++++++++++++++++++++++ Iceman.c | 792 +++++++++++++ LITENING.c | 311 +++++ MINES.c | 80 ++ MISC.c | 747 ++++++++++++ MODELS.c | 585 ++++++++++ MONSTERS.c | 283 +++++ PARTICLE.c | 50 + PLATS.c | 368 ++++++ PLAYER.c | 1181 +++++++++++++++++++ Progs.src | 63 + SPRITES.c | 26 + SUBS.c | 332 ++++++ TRIGGERS.c | 686 +++++++++++ WEAPONS.c | 3169 +++++++++++++++++++++++++++++++++++++++++++++++++++ WORLD.c | 650 +++++++++++ X_SELCH.c | 47 + X_SPWPN.c | 1135 ++++++++++++++++++ X_TRIG.c | 43 + X_VARS.c | 159 +++ angel.c | 579 ++++++++++ appy.c | 475 ++++++++ apsmall.c | 478 ++++++++ beast.c | 621 ++++++++++ bishop.c | 323 ++++++ cannon.c | 308 +++++ cannon2.c | 114 ++ cyclops.c | 419 +++++++ gambit.c | 456 ++++++++ geometry.c | 72 ++ phoenix.c | 502 ++++++++ progdefs.h | 143 +++ psylocke.c | 388 +++++++ rogue.c | 275 +++++ sinister.c | 645 +++++++++++ skeleton.c | 102 ++ storm.c | 575 ++++++++++ tripwire.c | 145 +++ wgun.c | 51 + wolvie.c | 736 ++++++++++++ x_ambient.c | 53 + x_cam.c | 103 ++ x_debug.c | 63 + x_misc.c | 476 ++++++++ x_sound.c | 150 +++ x_tech.c | 190 +++ 55 files changed, 27560 insertions(+) create mode 100644 AI.c create mode 100644 AMTEST.c create mode 100644 BUTTONS.c create mode 100644 CLIENT.c create mode 100644 COMBAT.c create mode 100644 DEFS.c create mode 100644 DOORS.c create mode 100644 EXPLBRSH.c create mode 100644 FIGHT.c create mode 100644 ITEMS.c create mode 100644 Iceman.c create mode 100644 LITENING.c create mode 100644 MINES.c create mode 100644 MISC.c create mode 100644 MODELS.c create mode 100644 MONSTERS.c create mode 100644 PARTICLE.c create mode 100644 PLATS.c create mode 100644 PLAYER.c create mode 100644 Progs.src create mode 100644 SPRITES.c create mode 100644 SUBS.c create mode 100644 TRIGGERS.c create mode 100644 WEAPONS.c create mode 100644 WORLD.c create mode 100644 X_SELCH.c create mode 100644 X_SPWPN.c create mode 100644 X_TRIG.c create mode 100644 X_VARS.c create mode 100644 angel.c create mode 100644 appy.c create mode 100644 apsmall.c create mode 100644 beast.c create mode 100644 bishop.c create mode 100644 cannon.c create mode 100644 cannon2.c create mode 100644 cyclops.c create mode 100644 gambit.c create mode 100644 geometry.c create mode 100644 phoenix.c create mode 100644 progdefs.h create mode 100644 psylocke.c create mode 100644 rogue.c create mode 100644 sinister.c create mode 100644 skeleton.c create mode 100644 storm.c create mode 100644 tripwire.c create mode 100644 wgun.c create mode 100644 wolvie.c create mode 100644 x_ambient.c create mode 100644 x_cam.c create mode 100644 x_debug.c create mode 100644 x_misc.c create mode 100644 x_sound.c create mode 100644 x_tech.c diff --git a/AI.c b/AI.c new file mode 100644 index 0000000..69b6e89 --- /dev/null +++ b/AI.c @@ -0,0 +1,897 @@ +void() movetarget_f; +void() t_movetarget; +void() knight_walk1; +void() wiz_guard1; +void() AngelPitch; +void(entity etemp, entity stemp, entity stemp, float dmg) T_Damage; +/* + +.enemy +Will be world if not currently angry at anyone. + +.movetarget +The next path spot to walk toward. If .enemy, ignore .movetarget. +When an enemy is killed, the monster will try to return to it's path. + +.huntt_ime +Set to time + something when the player is in sight, but movement straight for +him is blocked. This causes the monster to use wall following code for +movement direction instead of sighting on the player. + +.ideal_yaw +A yaw angle of the intended direction, which will be turned towards at up +to 45 deg / state. If the enemy is in view and hunt_time is not active, +this will be the exact line towards the enemy. + +.pausetime +A monster will leave it's stand state and head towards it's .movetarget when +time > .pausetime. + +walkmove(angle, speed) primitive is all or nothing +*/ + + +// +// globals +// +float current_yaw; + +float walking; + +// +// when a monster becomes angry at a player, that monster will be used +// as the sight target the next frame so that monsters near that one +// will wake up even if they wouldn't have noticed the player +// +entity sight_entity; +float sight_entity_time; + +float(float v) anglemod = +{ + while (v >= 360) + v = v - 360; + while (v < 0) + v = v + 360; + return v; +}; + +/* +============================================================================== + +MOVETARGET CODE + +The angle of the movetarget effects standing and bowing direction, but has no effect on movement, which allways heads to the next target. + +targetname +must be present. The name of this movetarget. + +target +the next spot to move to. If not present, stop here for good. + +pausetime +The number of seconds to spend standing or bowing for path_stand or path_bow + +============================================================================== +*/ + + +void() movetarget_f = +{ + if (!self.targetname) + objerror ("monster_movetarget: no targetname"); + + self.solid = SOLID_TRIGGER; + self.touch = t_movetarget; + setsize (self, '-8 -8 -8', '8 8 8'); + +}; + +/*QUAKED path_corner (0.5 0.3 0) (-8 -8 -8) (8 8 8) +Monsters will continue walking towards the next target corner. +*/ +void() path_corner = +{ + movetarget_f (); +}; + + +/* +============= +t_movetarget + +Something has bumped into a movetarget. If it is a monster +moving towards it, change the next destination and continue. +============== +*/ +void() t_movetarget = +{ +local entity temp; + + if (other.movetarget != self) + return; + + if (other.enemy) + return; // fighting, not following a path + + temp = self; + self = other; + other = temp; + + if (self.classname == "xmen_rogue") + sound (self, CHAN_VOICE, "ogre/ogdrag.wav", 1, ATTN_IDLE);// play chainsaw drag sound + +//dprint ("t_movetarget\n"); + self.goalentity = self.movetarget = find (world, targetname, other.target); + self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); + if (!self.movetarget) + { + self.pausetime = time + 999999; + self.th_stand (); + return; + } +}; + + + +//============================================================================ + +/* +============= +range + +returns the range catagorization of an entity reletive to self +0 melee range, will become hostile even if back is turned +1 visibility and infront, or visibility and show hostile +2 infront and show hostile +3 only triggered by damage +============= +*/ +float(entity targ) range = +{ +local vector spot1, spot2; +local float r; + spot1 = self.origin + self.view_ofs; + spot2 = targ.origin + targ.view_ofs; + + r = vlen (spot1 - spot2); + if (r < 80) + return RANGE_MELEE; + if (r < 400) + return RANGE_NEAR; + if (r < 1300) + return RANGE_MID; + return RANGE_FAR; +}; + +/* +============= +visible + +returns 1 if the entity is visible to self, even if not infront () +============= +*/ +float (entity targ) visible = +{ + local vector spot1, spot2; + + spot1 = self.origin + self.view_ofs; + spot2 = targ.origin + targ.view_ofs; + traceline (spot1, spot2, FALSE, self); // see through other monsters + + if (trace_inopen && trace_inwater) + return FALSE; // sight line crossed contents + + if ((trace_fraction == 1) || (trace_ent == targ)) + return TRUE; + return FALSE; +}; + + +/* +============= +infront + +returns 1 if the entity is in front (in sight) of self +============= +*/ +float(entity targ) infront = +{ + local vector vec; + local float dot; + + makevectors (self.angles); + vec = normalize (targ.origin - self.origin); + + if (self.enemy != world) { // original id sight code + dot = vec * v_forward; + + if ( dot > 0.3) + { + return TRUE; + } + } + else { // X-Men: allow for sideways sighting + + dot = vlen(vec + v_forward); + + if ( dot > 0.75) + { + return TRUE; + } + } + + return FALSE; +}; + + +//============================================================================ + +/* +=========== +ChangeYaw + +Turns towards self.ideal_yaw at self.yaw_speed +Sets the global variable current_yaw +Called every 0.1 sec by monsters +============ +*/ +/* + +void() ChangeYaw = +{ + local float ideal, move; + +//current_yaw = self.ideal_yaw; +// mod down the current angle + current_yaw = anglemod( self.angles_y ); + ideal = self.ideal_yaw; + + if (current_yaw == ideal) + return; + + move = ideal - current_yaw; + if (ideal > current_yaw) + { + if (move > 180) + move = move - 360; + } + else + { + if (move < -180) + move = move + 360; + } + + if (move > 0) + { + if (move > self.yaw_speed) + move = self.yaw_speed; + } + else + { + if (move < 0-self.yaw_speed ) + move = 0-self.yaw_speed; + } + + current_yaw = anglemod (current_yaw + move); + + self.angles_y = current_yaw; +}; + +*/ + + +//============================================================================ + +void() HuntTarget = +{ + self.goalentity = self.enemy; + self.think = self.th_run; + self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin); + self.nextthink = time + 0.1; + SUB_AttackFinished (1); // wait a while before first attack +}; + +void() SightSound = +{ +local float rsnd; + + rsnd = random(); + + if (self.classname == "xmen_psylocke") + FemaleSightSound(); + else if (self.classname == "xmen_storm") + FemaleSightSound(); + else if (self.classname == "xmen_rogue") + FemaleSightSound(); + else if (self.classname == "xmen_phoenix") + FemaleSightSound(); + else if (self.classname == "xmen_wolverine") + MaleSightSound(1); + else if (self.classname == "xmen_cyclops") + MaleSightSound(2); + else if (self.classname == "xmen_beast") + MaleSightSound(1); + else if (self.classname == "xmen_bishop") + MaleSightSound(2); + else if (self.classname == "xmen_angel") + MaleSightSound(2); + else if (self.classname == "xmen_iceman") + MaleSightSound(2); + else if (self.classname == "xmen_gambit") + MaleSightSound(2); + else if (self.classname == "xmen_cannonball") + MaleSightSound(2); +}; + +void() FoundTarget = +{ + if (self.enemy.classname == "player") + { // let other monsters see this monster for a while + sight_entity = self; + sight_entity_time = time; + } + + self.show_hostile = time + 1; // wake up other monsters + + SightSound (); + HuntTarget (); +}; + +/* +=========== +FindTarget + +Self is currently not attacking anything, so try to find a target + +Returns TRUE if an enemy was sighted + +When a player fires a missile, the point of impact becomes a fakeplayer so +that monsters that see the impact will respond as if they had seen the +player. + +To avoid spending too much time, only a single client (or fakeclient) is +checked each frame. This means multi player games will have slightly +slower noticing monsters. +============ +*/ +float() FindTarget = +{ + local entity client; + local float r; + local vector vect; + + if (self.spawnflags & SPAWNFLAG_CLONE) + return; + +// if the first spawnflag bit is set, the monster will only wake up on +// really seeing the player, not another monster getting angry + +// spawnflags & 3 is a big hack, because zombie crucified used the first +// spawn flag prior to the ambush flag, and I forgot about it, so the second +// spawn flag works as well + if (sight_entity_time >= time - 0.1 && !(self.spawnflags & 3) ) + { + client = sight_entity; + if (client.enemy == self.enemy) + return; + } + else + { + client = checkclient (); + if (!client) + return FALSE; // current check entity isn't in PVS + } + + if (client == self.enemy) + return FALSE; + + if (client.flags & FL_NOTARGET) + return FALSE; + if (client.items & IT_INVISIBILITY) + return FALSE; + + r = range (client); + if (r == RANGE_FAR) + return FALSE; + + + if (r != RANGE_MELEE) { + if (!visible (client)) + return FALSE; + + if (!infront(client)) + return FALSE; + + if (r == RANGE_NEAR) + { + if (client.show_hostile > time) + return FALSE; + } + } + + // x-men: 3rd bit of spawnflag disables attacking a player on sight, unless really close + traceline(self.origin, client.origin, FALSE, self); + if ((self.spawnflags & 4) && ((vlen(self.origin - client.origin) > 96) || (trace_ent != client))) + return FALSE; + +// +// got one +// + self.enemy = client; + if (self.enemy.classname != "player") + { + self.enemy = self.enemy.enemy; + if (self.enemy.classname != "player") + { + self.enemy = world; + return FALSE; + } + } + + FoundTarget (); + + return TRUE; +}; + + +//============================================================================= + +float(float dist) ai_forward = +{ + return walkmove (self.angles_y, dist); +}; + +float(float dist) ai_back = +{ + return walkmove ( (self.angles_y+180), dist); +}; + + +/* +============= +ai_pain + +stagger back a bit +============= +*/ +void(float dist) ai_pain = +{ + ai_back (dist); +/* + local float away; + + away = anglemod (vectoyaw (self.origin - self.enemy.origin) + + 180*(random()- 0.5) ); + + walkmove (away, dist); +*/ +}; + +/* +============= +ai_painforward + +stagger back a bit +============= +*/ +void(float dist) ai_painforward = +{ + walkmove (self.ideal_yaw, dist); +}; + +/* +============= +ai_walk + +The monster is walking it's beat +============= +*/ +void(float dist) ai_run; +void(float dist) ai_walk = +{ + local vector mtemp; + + movedist = dist; + + if ((self.classname == "xmen_wolverine") && + (self.last_health_regen < (time - 1))) + { + self.health = self.health + 2; + self.last_health_regen = time; + } + + if (self.enemy == world) { + // check for noticing a player + if (FindTarget ()) + return; + + movetogoal (dist); + } + else { // in walking frames, but still angry at someone + walking = TRUE; + ai_run(dist); + walking = FALSE; + + mtemp = self.origin - self.enemy.origin; + mtemp_z = 0; + + traceline(self.origin, self.enemy.origin, TRUE, self.enemy); + + if (trace_fraction < 1) // enemy is getting away, so start running + self.think = self.th_run; + + if ((self.classname == "xmen_wolverine") || + (self.classname == "xmen_storm")) + self.nextthink = time + 0.05; + } +}; + + +/* +============= +ai_stand + +The monster is staying in one place for a while, with slight angle turns +============= +*/ +void() ai_stand = +{ + if (self.parallize_time > time) + { + return; + } + + if (FindTarget ()) + return; + + if (time > self.pausetime) + { + self.th_walk (); + return; + } + +// change angle slightly + +}; + +/* +============= +ai_turn + +don't move, but turn towards ideal_yaw +============= +*/ +void() ai_turn = +{ + if (FindTarget ()) + return; + + ChangeYaw (); +}; + +//============================================================================= + +/* +============= +ChooseTurn +============= +*/ +void(vector dest3) ChooseTurn = +{ + local vector dir, newdir; + + dir = self.origin - dest3; + + newdir_x = trace_plane_normal_y; + newdir_y = 0 - trace_plane_normal_x; + newdir_z = 0; + + if (dir * newdir > 0) + { + dir_x = 0 - trace_plane_normal_y; + dir_y = trace_plane_normal_x; + } + else + { + dir_x = trace_plane_normal_y; + dir_y = 0 - trace_plane_normal_x; + } + + dir_z = 0; + self.ideal_yaw = vectoyaw(dir); +}; + +/* +============ +FacingIdeal + +============ +*/ +float() FacingIdeal = +{ + local float delta; + + delta = anglemod(self.angles_y - self.ideal_yaw); + if (delta > 45 && delta < 315) + return FALSE; + return TRUE; +}; + + +//============================================================================= + +float() StormCheckAttack; +float() WizardCheckAttack; +float() beastCheckAttack; +float() GambitCheckAttack; +float() PsylockeCheckAttack; + +float() CheckAnyAttack = +{ + local float ca; // xmen cl2 + + if (!enemy_vis) + return; + if (self.classname == "xmen_bishop") + return SoldierCheckAttack (); + if (self.classname == "xmen_rogue") + return OgreCheckAttack (); + if (self.classname == "xmen_storm") + return StormCheckAttack (); + if (self.classname == "xmen_wolverine") + return DemonCheckAttack (); + if (self.classname == "xmen_beast") + return beastCheckAttack (); + if (self.classname == "xmen_angel") + return WizardCheckAttack (); + if (self.classname == "xmen_gambit") + return GambitCheckAttack (); + if (self.classname == "xmen_psylocke") + return PsylockeCheckAttack (); + + // begin xmen (cl2) + ca = CheckAttack (); + if (self.classname == "xmen_iceman") self.count = 1; + return (ca); + // End xmen (cl2) + +}; + + +/* +============= +ai_run_melee + +Turn and close until within an angle to launch a melee attack +============= +*/ +void() ai_run_melee = +{ + self.ideal_yaw = enemy_yaw; + ChangeYaw (); + + if (FacingIdeal()) + { + self.th_melee (); + self.attack_state = AS_STRAIGHT; + } +}; + + +/* +============= +ai_run_missile + +Turn in place until within an angle to launch a missile attack +============= +*/ +void() ai_run_missile = +{ + self.ideal_yaw = enemy_yaw; + ChangeYaw (); + if (FacingIdeal()) + { + self.th_missile (); + self.attack_state = AS_STRAIGHT; + } +}; + + +/* +============= +ai_run_slide + +Strafe sideways, but stay at aproximately the same range +============= +*/ +void() ai_run_slide = +{ + local float ofs; + + self.ideal_yaw = enemy_yaw; + ChangeYaw (); + if (self.lefty) + ofs = 90; + else + ofs = -90; + + if (walkmove (self.ideal_yaw + ofs, movedist)) + return; + + self.lefty = 1 - self.lefty; + + walkmove (self.ideal_yaw - ofs, movedist); +}; + + +/* +============= +ai_run + +The monster has an enemy it is trying to kill +============= +*/ +void() skeleton_animate; +void(float dist) ai_run = +{ + local vector delta, vect; + local float axis, cont; + local float direct, ang_rint, ang_floor, ang_ceil; + local entity oenemy; + + if (self.spawnflags & SPAWNFLAG_CLONE) + self.th_stand(); + + if (self.classname == "xmen_skeleton") { + skeleton_animate(); + return; + } + + if (self.parallize_time > time) + { + return; + } + + movedist = dist; +// see if the enemy is dead + if (self.enemy.health <= 0) + { + self.enemy = world; + // FIXME: look all around for other targets + if (self.oldenemy.health > 0) + { + self.enemy = self.oldenemy; + HuntTarget (); + } + else + { + if (self.movetarget) + self.th_walk (); + else + self.th_stand (); + return; + } + } + + // check if in Lava + cont = pointcontents(self.origin); + if ((cont == CONTENT_LAVA) || + (cont == CONTENT_SLIME)) { + T_Damage(self, world, world, 100); + } + + + self.show_hostile = time + 1; // wake up other monsters + +// check knowledge of enemy + enemy_vis = visible(self.enemy); + if (enemy_vis) + self.search_time = time + 5; + +// look for other coop players + if (coop && self.search_time < time) + { + if (FindTarget ()) + return; + } + + enemy_infront = infront(self.enemy); + enemy_range = range(self.enemy); + enemy_yaw = vectoyaw(self.enemy.origin - self.origin); + + if (self.guard_flag) { + if (self.th_guard) { + self.th_guard(); + self.guard_flag = FALSE; + return; + } + } + + if (self.flags & FL_FLY) { + // do pitching + AngelPitch(); + ai_face(); + } + + if (self.attack_state == AS_MISSILE) + { +//dprint ("ai_run_missile\n"); + ai_run_missile (); + return; + } + if (self.attack_state == AS_MELEE) + { +//dprint ("ai_run_melee\n"); + ai_run_melee (); + return; + } + + if (CheckAnyAttack ()) + return; // beginning an attack + + if (self.attack_state == AS_SLIDING) + { + ai_run_slide (); +// return; + dist = dist / 2; + } + + if ((self.classname == "xmen_angel")) { + if (vlen(self.origin - self.enemy.origin) < 256) { + + // FIXME: check there is at least 196 units behind + vect = vectoangles(self.angles); + traceline(self.origin, self.origin - vect*196, TRUE, self); + if (trace_fraction < 1) + dist = 0; + else { + dist = dist * -1; + + if (self.attack_state != AS_SLIDING) + dist = dist * 0.5; + } + } + + } + + if (self.flags & FL_FLY) { + // check that we haven't gone TOO close to the player, and sare sitting on their head + if (vlen(self.enemy.origin - self.origin) < 60) { + ai_back(5); + return; + } + else if (vlen(self.enemy.origin - self.origin) < 68) { + return; + } + } + + // remove z_ofs (Storm) + self.origin_z = self.origin_z - self.z_ofs; + +// head straight in + self.oldorigin = self.origin; + +//if (self.classname == "xmen_cannonball") bprint("ai_run: movetogoal\n"); + movetogoal (dist); + + if ((self.origin == self.oldorigin) && (vlen(self.enemy.origin - self.origin) < 70)) { + ai_face(); + } + + // re-apply z_ofs (Storm) + self.origin_z = self.origin_z + self.z_ofs; + + // walk if really close + if ((!walking) && + (self.classname == "xmen_wolverine")) { + delta = self.enemy.origin - self.origin; + delta_z = 0; + if (vlen(delta) < 128) + self.think = self.th_walk; + } + + if ((self.classname == "xmen_wolverine") || + (self.classname == "xmen_storm")) + self.nextthink = time + 0.05; +}; + diff --git a/AMTEST.c b/AMTEST.c new file mode 100644 index 0000000..97f9592 --- /dev/null +++ b/AMTEST.c @@ -0,0 +1,85 @@ +/*~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~> +~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~*/ + +void() test_teleport_touch; +void() tele_done; + +/*QUAKED test_teleport (0 .5 .8) ? +Teleporter testing +*/ +void() test_teleport = +{ + precache_model ("sprites/s_aball.spr"); + setsize (self, self.mins, self.maxs); + self.touch = test_teleport_touch; + self.solid = 1; + + if (!self.target) + objerror ("no target\n"); +}; + +void() test_teleport_touch = +{ +local entity oldself; + other.movetype = MOVETYPE_TOSS; +// other.solid = SOLID_NOT; + other.dest = '256 -128 -128'; + oldself = self; + self = other; +// SUB_CalcMove (self.dest, 200, tele_done); + self.velocity = '1000 0 0 '; + self = oldself; +}; + +void() tele_done = +{ + self.movetype = MOVETYPE_WALK; + self.solid = SOLID_SLIDEBOX; +}; + +/*~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~> +~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~*/ + +void() test_goaway; +void() test_spawn; + +/*QUAKED test_fodder (0 .5 .8) ? +beating guy +*/ +void() test_fodder = +{ + self.nextthink = time + 3; + self.think = test_spawn; +}; + +void() test_spawn = +{ +local entity body; + makevectors (self.angles); + + body = spawn(); + setmodel (body, "progs/soldier.mdl"); + setorigin (body, self.origin); + body.classname = "player"; + body.health = 1000; + body.frags = 0; + body.takedamage = DAMAGE_AIM; + body.solid = SOLID_SLIDEBOX; + body.movetype = MOVETYPE_WALK; + body.show_hostile = 0; + body.weapon = 1; + body.velocity = v_forward * 200; + + body.nextthink = time + 5; + body.think = test_goaway; + +self.nextthink = time + 3; +self.think = test_spawn; + +}; + +void() test_goaway = +{ + remove (self); +}; + diff --git a/BUTTONS.c b/BUTTONS.c new file mode 100644 index 0000000..086971a --- /dev/null +++ b/BUTTONS.c @@ -0,0 +1,143 @@ +// button and multiple button + +void() button_wait; +void() button_return; + +void() button_wait = +{ + self.state = STATE_TOP; + self.nextthink = self.ltime + self.wait; + self.think = button_return; + activator = self.enemy; + SUB_UseTargets(); + self.frame = 1; // use alternate textures +}; + +void() button_done = +{ + self.state = STATE_BOTTOM; +}; + +void() button_return = +{ + self.state = STATE_DOWN; + SUB_CalcMove (self.pos1, self.speed, button_done); + self.frame = 0; // use normal textures + if (self.health) + self.takedamage = DAMAGE_YES; // can be shot again +}; + + +void() button_blocked = +{ // do nothing, just don't ome all the way back out +}; + + +void() button_fire = +{ + if (self.state == STATE_UP || self.state == STATE_TOP) + return; + +//bprint("button triggered\n"); + + sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); + + self.state = STATE_UP; + SUB_CalcMove (self.pos2, self.speed, button_wait); +}; + + +void() button_use = +{ + self.enemy = activator; + button_fire (); +}; + +void() button_touch = +{ + if (other.classname != "player") + return; + self.enemy = other; + button_fire (); +}; + +void() button_killed = +{ + self.enemy = damage_attacker; + self.health = self.max_health; + self.takedamage = DAMAGE_NO; // wil be reset upon return + button_fire (); +}; + + +/*QUAKED func_button (0 .5 .8) ? +When a button is touched, it moves some distance in the direction of it's angle, triggers all of it's targets, waits some time, then returns to it's original position where it can be triggered again. + +"angle" determines the opening direction +"target" all entities with a matching targetname will be used +"speed" override the default 40 speed +"wait" override the default 1 second wait (-1 = never return) +"lip" override the default 4 pixel lip remaining at end of move +"health" if set, the button must be killed instead of touched +"sounds" +0) steam metal +1) wooden clunk +2) metallic click +3) in-out +*/ +void() func_button = +{ +local float gtemp, ftemp; + + if (self.sounds == 0) + { + precache_sound ("buttons/airbut1.wav"); + self.noise = "buttons/airbut1.wav"; + } + if (self.sounds == 1) + { + precache_sound ("buttons/switch21.wav"); + self.noise = "buttons/switch21.wav"; + } + if (self.sounds == 2) + { + precache_sound ("buttons/switch02.wav"); + self.noise = "buttons/switch02.wav"; + } + if (self.sounds == 3) + { + precache_sound ("buttons/switch04.wav"); + self.noise = "buttons/switch04.wav"; + } + + SetMovedir (); + + self.movetype = MOVETYPE_PUSH; + self.solid = SOLID_BSP; + setmodel (self, self.model); + + self.blocked = button_blocked; + self.use = button_use; + + if (self.health) + { + self.max_health = self.health; + self.th_die = button_killed; + self.takedamage = DAMAGE_YES; + } + else + self.touch = button_touch; + + if (!self.speed) + self.speed = 40; + if (!self.wait) + self.wait = 1; + if (!self.lip) + self.lip = 4; + + self.state = STATE_BOTTOM; + + self.pos1 = self.origin; + self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip); +}; + diff --git a/CLIENT.c b/CLIENT.c new file mode 100644 index 0000000..8e288d3 --- /dev/null +++ b/CLIENT.c @@ -0,0 +1,2032 @@ + +// prototypes +void () W_WeaponFrame; +void() W_SetCurrentAmmo; +void() player_pain; +void() player_stand1; +void (vector org) spawn_tfog; +void (vector org, entity death_owner) spawn_tdeath; + +.float modelindex_eyes, modelindex_player; + + +/* +============================================================================= + + LEVEL CHANGING / INTERMISSION + +============================================================================= +*/ + +/*QUAKED info_intermission (1 0.5 0.5) (-16 -16 -16) (16 16 16) +This is the camera point for the intermission. +Use mangle instead of angle, so you can set pitch or roll as well as yaw. 'pitch roll yaw' +*/ +void() info_intermission = +{ +}; + + +void() SetChangeParms = +{ + if (self.health <= 0) + { + SetNewParms (); + return; + } + +// remove items + self.items = self.items - (self.items & + (IT_KEY1 | IT_KEY2 | IT_INVISIBILITY | IT_INVULNERABILITY | IT_SUIT | IT_QUAD) ); + +// cap super health + if (self.health > 100) + self.health = 100; + if (self.health < 50) + self.health = 50; + parm1 = self.items; + parm2 = self.health; + parm3 = self.armorvalue; + if (self.ammo_shells < 25) + parm4 = 25; + else + parm4 = self.ammo_shells; + parm5 = self.ammo_nails; + parm6 = self.ammo_rockets; + parm7 = self.ammo_cells; + parm8 = self.weapon; + parm9 = self.armortype * 100; + + parm10 = self.weapon_parts; +}; + +void() SetNewParms = +{ + if (deathmatch == DM_SPECIAL_POWERS) + parm1 = IT_AXE; + else + parm1 = IT_SHOTGUN | IT_AXE | IT_SUPER_SHOTGUN | IT_NAILGUN | IT_SUPER_NAILGUN | IT_ROCKET_LAUNCHER | IT_GRENADE_LAUNCHER | IT_LIGHTNING; + + parm2 = 100; + parm3 = 0; + parm5 = 0; + parm6 = 0; + parm7 = 0; + if (deathmatch == DM_SPECIAL_POWERS) { + parm4 = 0; + parm8 = IT_AXE; + } + else { + parm4 = 25; + parm8 = IT_SHOTGUN; + } + parm9 = 0; + + parm10 = 0; +}; + +void() DecodeLevelParms = +{ + if (serverflags) + { + if (world.model == "maps/start.bsp") + SetNewParms (); // take away all stuff on starting new episode + } + + self.items = parm1; + + if (deathmatch != 10) { + self.items = self.items | IT_SHOTGUN | IT_AXE | IT_SUPER_SHOTGUN | IT_NAILGUN | IT_SUPER_NAILGUN | IT_ROCKET_LAUNCHER | IT_GRENADE_LAUNCHER | IT_LIGHTNING; + self.weapon = parm8; + } + else { + self.weapon = IT_AXE; + } + + self.health = parm2; + self.armorvalue = parm3; + self.ammo_shells = parm4; + self.ammo_nails = parm5; + self.ammo_rockets = parm6; + self.ammo_cells = parm7; + self.armortype = parm9 * 0.01; + + self.weapon_parts = parm10; +}; + +/* +============ +FindIntermission + +Returns the entity to view from +============ +*/ +entity() FindIntermission = +{ + local entity spot; + local float cyc; + +// look for info_intermission first + spot = find (world, classname, "info_intermission"); + if (spot) + { // pick a random one + cyc = random() * 4; + while (cyc > 1) + { + spot = find (spot, classname, "info_intermission"); + if (!spot) + spot = find (spot, classname, "info_intermission"); + cyc = cyc - 1; + } + return spot; + } + +// then look for the start position + spot = find (world, classname, "info_player_start"); + if (spot) + return spot; + +// testinfo_player_start is only found in regioned levels + spot = find (world, classname, "testplayerstart"); + if (spot) + return spot; + + objerror ("FindIntermission: no spot"); +}; + + +string nextmap; +void() GotoNextMap = +{ + if (cvar("samelevel")) // if samelevel is set, stay on same level + changelevel (mapname); + else + changelevel (nextmap); +}; + +float finale_index; // used to show multiple finale stories + +void() ExitIntermission = +{ +// skip any text in deathmatch + if (deathmatch) + { + GotoNextMap (); + return; + } + + intermission_exittime = time + 1; + intermission_running = intermission_running + 1; + +// +// run some text if at the end of an episode +// + if (intermission_running == 2) + { + if (world.model == "maps/x1end.bsp") + { + WriteByte (MSG_ALL, SVC_FINALE); + WriteString (MSG_ALL, "Acknowledging defeat, Apocalypse tells\nyou that although you have defeated\nhim, there is another to carry on his\nwork. Indeed, without Apocalypse to\nkeep him in check, this sinister\ncharacter will undoubtedly increase\nhis determination to destroy and take\nover the world.\n\nYou have done well to destroy\nApocalypse's cloning factory, but there\nis still the matter of the clones that\nhave already been dispatched. Critical\nlocations must be contained in an\nattempt to lessen the damage caused to\nthe world as a whole.\n\nYou must defeat this evil genius before\nthe world falls before him..."); + + serverflags = serverflags - (serverflags & 15); + +/* +Acknowledging defeat, Apocalypse tells\n +you that although you have defeated\n +him, there is another to carry on his\n +work. Indeed, without Apocalypse to\n +keep him in check, this sinister\n +character will undoubtedly increase\n +his determination to destroy and take\n +over the world.\n\n +You have done well to destroy\n +Apocalypse's cloning factory, but there\n +is still the matter of the clones that\n +have already been dispatched. Critical\n +locations must be contained in an\n +attempt to lessen the damage caused to\n +the world as a whole.\n\n +You must defeat this evil genius before\n +the world falls before him..."); +*/ + return; + } + else if (world.model == "maps/x2end.bsp") + { + WriteByte (MSG_ALL, SVC_FINALE); + WriteString (MSG_ALL, "Sinister, realizing that his demise is\nat hand, teleports away to places\nunknown. You have thwarted his evil\nplans, and although he lives to see\nanother day, it will take a long time\nfor him to create such devious and\ndestructive ways of conquering the\nEarth again.\n\nMagneto now has the upper hand, and can\nensure the quick and ruthless\ntermination of any other such plans,\nfor in his self-deluded superiority, he\nalone is worthy of world domination.\n\nIt will take time for the population to\nrebuild their shattered lives, but you\nhave done your part in ensuring the\nworld's safety... for now.."); + + serverflags = serverflags - (serverflags & 15); +/* +Sinister, realizing that his demise is\n +at hand, teleports away to places\n +unknown. You have thwarted his evil\n +plans, and although he lives to see\n +another day, it will take a long time\n +for him to create such devious and\n +destructive ways of conquering the\n +Earth again.\n\n +Magneto now has the upper hand, and can\n +ensure the quick and ruthless\n +termination of any other such plans,\n +for in his self-deluded superiority, he\n +alone is worthy of world domination.\n\n +It will take time for the population to\n +rebuild their shattered lives, but you\n +have done your part in ensuring the\n +world's safety...\n\n +..for now.. +*/ + return; + } + + GotoNextMap(); + } + + if (intermission_running == 3) + { + if (!cvar("registered")) + { // shareware episode has been completed, go to sell screen + WriteByte (MSG_ALL, SVC_SELLSCREEN); + return; + } + + if ( (serverflags&15) == 15) + { + WriteByte (MSG_ALL, SVC_FINALE); + WriteString (MSG_ALL, "Now, you have all four Runes. You sense tremendous invisible forces moving to unseal ancient barriers. Shub-Niggurath had hoped to use the Runes Herself to clear off the Earth, but now instead, you will use them to enter her home and confront her as an avatar of avenging Earth-life. If you defeat her, you will be remembered forever as the savior of the planet. If she conquers, it will be as if you had never been born."); + return; + } + + } + + GotoNextMap(); +}; + +/* +============ +IntermissionThink + +When the player presses attack or jump, change to the next level +============ +*/ +void() IntermissionThink = +{ + if (time < intermission_exittime) + return; + + if (!self.button0 && !self.button1 && !self.button2) + return; + + ExitIntermission (); +}; + +void() execute_changelevel = +{ + local entity pos; + + intermission_running = 1; + +// enforce a wait time before allowing changelevel + if (deathmatch) + intermission_exittime = time + 5; + else + intermission_exittime = time + 3; + + WriteByte (MSG_ALL, SVC_CDTRACK); + WriteByte (MSG_ALL, 3); + WriteByte (MSG_ALL, 3); + + pos = FindIntermission (); + + other = find (world, classname, "player"); + while (other != world) + { + other.view_ofs = '0 0 0'; + other.angles = other.v_angle = pos.mangle; + other.fixangle = TRUE; // turn this way immediately + other.nextthink = time + 0.5; + other.takedamage = DAMAGE_NO; + other.solid = SOLID_NOT; + other.movetype = MOVETYPE_NONE; + other.modelindex = 0; + setorigin (other, pos.origin); + other = find (other, classname, "player"); + } + + WriteByte (MSG_ALL, SVC_INTERMISSION); +}; + + +void() changelevel_touch = +{ + local entity pos, magneto; + + if (other.classname != "player") + return; + + if (cvar("noexit")) + { + T_Damage (other, self, self, 50000); + return; + } + bprint (other.netname); + bprint (" exited the level\n"); + + magneto = find(world, classname, "magneto_sprite"); + if (magneto != world) + remove(magneto); + + nextmap = self.map; + + SUB_UseTargets (); + + if ( (self.spawnflags & 1) && (deathmatch == 0) ) + { // NO_INTERMISSION + GotoNextMap(); + return; + } + + self.touch = SUB_Null; + +// we can't move people right now, because touch functions are called +// in the middle of C movement code, so set a think time to do it + self.think = execute_changelevel; + self.nextthink = time + 0.1; +}; + +/*QUAKED trigger_changelevel (0.5 0.5 0.5) ? NO_INTERMISSION +When the player touches this, he gets sent to the map listed in the "map" variable. Unless the NO_INTERMISSION flag is set, the view will go to the info_intermission spot and display stats. +*/ +void() trigger_changelevel = +{ + if (!self.map) + objerror ("changelevel trigger doesn't have map"); + + InitTrigger (); + self.touch = changelevel_touch; +}; + +// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + +void() gateway_teleport_think = +{ + self.frame = self.frame + 1; + if (self.frame > 5) + self.frame = 1; + + self.nextthink = time + 0.1; +}; + +void() WhipThink = +{ + local vector vect; + + self.skin = self.skin + 1; + if (self.skin > 7) + self.skin = 0; + + self.frame = self.frame + 1; + if (self.frame > 2) + self.frame = 0; + + makevectors(self.owner.angles); + setorigin(self, self.owner.origin + v_forward * 40 + v_up * 30 - v_right * 13); + + if (self.last_flame < (time - self.last_flame_sound)) { + // shoot out some random lightning + makevectors(self.angles); + vect = (v_right * (random() * -4)) + (v_up * random() * 4); + vect = normalize(vect); + traceline(self.origin, self.origin + vect * 512, FALSE, self); + + sound (self, CHAN_AUTO, "storm/l_attack.wav", 0.2, 1); + + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_LIGHTNING3); + WriteEntity (MSG_BROADCAST, self); + WriteCoord (MSG_BROADCAST, self.origin_x); + WriteCoord (MSG_BROADCAST, self.origin_y); + WriteCoord (MSG_BROADCAST, self.origin_z); + WriteCoord (MSG_BROADCAST, trace_endpos_x); + WriteCoord (MSG_BROADCAST, trace_endpos_y); + WriteCoord (MSG_BROADCAST, trace_endpos_z); + + self.last_flame_sound = 0.3 + random() * 0.8; + self.last_flame = time; + } + + self.nextthink = time + 0.1; +}; + +void() SpawnGatewayWhip = +{ + local entity whip; + + whip = spawn(); + whip.classname = "gateway_whip"; + whip.owner = self; + whip.angles = self.angles; + setmodel(whip, "progs/whip.mdl"); + + makevectors(self.angles); + setorigin(whip, self.origin + v_forward * 40 + v_up * 30 - v_right * 13); + + whip.think = WhipThink; + whip.nextthink = time + 0.1; +}; + +void() xmen_teleport = +{ + local vector o; + local string str; + + if (!self.map) + objerror ("changelevel trigger (xmen_teleport) doesn't have map"); + + setsize(self, VEC_HULL2_MIN + '0 0 8', VEC_HULL2_MAX); + if (!droptofloor()) { + bprint("xmen_teleport fell out of level at "); + str = vtos(self.origin); + bprint(str); + bprint(" "); + remove(self); + return; + } + + precache_model("progs/gateway2.mdl"); + precache_model("progs/whip.mdl"); + + setmodel(self, "progs/gateway2.mdl"); + + SpawnGatewayWhip(); + + self.solid = SOLID_TRIGGER; + + setorigin(self, self.origin + '0 0 1'); + self.touch = changelevel_touch; + + self.think = gateway_teleport_think; + self.nextthink = time + 0.05; +}; + +// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + + +/* +============================================================================= + + PLAYER GAME EDGE FUNCTIONS + +============================================================================= +*/ + +void() set_suicide_frame; + +// called by ClientKill and DeadThink +void() respawn = +{ + if ((coop) && (num_clients > 1)) + { + // make a copy of the dead body for appearances sake + CopyToBodyQue (self); + // get the spawn parms as they were at level start + setspawnparms (self); + // respawn + PutClientInServer (); + } + else if (deathmatch) + { + // make a copy of the dead body for appearances sake + CopyToBodyQue (self); + // set default spawn parms + SetNewParms (); + // respawn + PutClientInServer (); + } + else + { // restart the entire server + localcmd ("restart\n"); + } +}; + + +void(entity plyr) KillFlameEntities = +{ + if (plyr.flame_ent1 == world) + return; + + remove(plyr.flame_ent1); + remove(plyr.flame_ent2); + remove(plyr.flame_ent3); + + plyr.flame_ent1 = world; + plyr.flame_ent2 = world; + plyr.flame_ent3 = world; +}; + + +/* +============ +ClientKill + +Player entered the suicide command +============ +*/ +void() ClientKill = +{ + bprint (self.netname); + bprint (" suicides\n"); + + KillFlameEntities(self); + + set_suicide_frame (); + self.modelindex = self.modelindex_player; + self.frags = self.frags - 2; // extra penalty + respawn (); +}; + +float(vector v) CheckSpawnPoint = +{ + return FALSE; +}; + +/* +============ +SelectSpawnPoint + +Returns the entity to spawn at +============ +*/ +entity() SelectSpawnPoint = +{ + local entity spot; + local vector oldorg; + local float nospot, i; + +//spot = spawn(); +//spot.classname = "info_player_start"; +//spot.origin = '0 0 0'; + +// testinfo_player_start is only found in regioned levels + spot = find (world, classname, "testplayerstart"); + if (spot) + return spot; + +// choose a info_player_deathmatch point + if (coop) + { + lastspawn = find(lastspawn, classname, "info_player_coop"); + if (lastspawn == world) + lastspawn = find (lastspawn, classname, "info_player_start"); + if (lastspawn != world) + return lastspawn; + } + else if (deathmatch) + { + i = 0; + oldorg = self.origin; + nospot = FALSE; + + while (!nospot && (i < 16)) { + lastspawn = find(lastspawn, classname, "info_player_deathmatch"); + if (lastspawn == world) { + lastspawn = find (lastspawn, classname, "info_player_deathmatch"); + } + + if (lastspawn != world) { + setorigin(self, lastspawn.origin + '0 0 1'); + + if (droptofloor()) { + setorigin(self, oldorg); + return lastspawn; + } + } + else { + nospot = TRUE; + } + + i = i + 1; + } + } + + if (serverflags) + { // return with a rune to start + spot = find (world, classname, "info_player_start2"); + if (spot) + return spot; + } + + spot = find (world, classname, "info_player_start"); + if (!spot) + error ("PutClientInServer: no info_player_start on level"); + + return spot; +}; + +entity() spawn_flame_ent = +{ + local entity new_flame_ent; + + new_flame_ent = spawn(); + new_flame_ent.owner = self; + setorigin(new_flame_ent, self.origin); +// setmodel(new_flame_ent, "progs/eyes.mdl"); + new_flame_ent.think = flame_ent_think; + new_flame_ent.nextthink = -1; + + return new_flame_ent; +}; + +void() MirrorThink = +{ + makevectors(self.owner.angles); + setorigin(self, self.owner.origin + v_forward * 64); + + self.angles = self.owner.angles; + self.angles_y = anglemod(self.owner.angles_y + 180); + + self.frame = self.owner.frame; + self.nextthink = time + 0.01; +}; + +void() SpawnMirrorPlayer = +{ + local entity ent; + + ent = spawn(); + ent.classname = "player_mirror"; + setmodel(ent, self.model); + makevectors(self.angles); + setorigin(ent, self.origin + v_forward * 64); + ent.owner = self; + ent.think = MirrorThink; + ent.nextthink = time + 0.05; +}; + +void() SetDeathmatchModel = +{ + if (self.team == CHAR_WOLVERINE) { + setmodel(self, "progs/dmwolvy.mdl"); + self.char_type = CT_MALE_NORMAL; + } + else if (self.team == CHAR_STORM) { + setmodel(self, "progs/dmstorm2.mdl"); + self.char_type = CT_FEMALE; + } + else if (self.team == CHAR_ICEMAN) { + setmodel(self, "progs/dmice.mdl"); + self.char_type = CT_MALE_NORMAL; + } + else if (self.team == CHAR_CYCLOPS) { + setmodel(self, "progs/dmcyclop.mdl"); + self.char_type = CT_MALE_NORMAL; + } + else if (self.team == CHAR_PSYLOCKE) { + setmodel(self, "progs/dmpsy.mdl"); + self.char_type = CT_FEMALE; + } + else if (self.team == CHAR_ANGEL) { + setmodel(self, "progs/dmangel.mdl"); + self.char_type = CT_MALE_NORMAL; + } + else if (self.team == CHAR_BEAST) { + setmodel(self, "progs/dmbeast.mdl"); + self.char_type = CT_MALE_LARGE; + } + else if (self.team == CHAR_GAMBIT) { + setmodel(self, "progs/dmgambit.mdl"); + self.char_type = CT_MALE_NORMAL; + } + else if (self.team == CHAR_BISHOP) { + setmodel(self, "progs/dmbishop.mdl"); + self.char_type = CT_MALE_LARGE; + } + else if (self.team == CHAR_ROGUE) { + setmodel(self, "progs/dmrogue.mdl"); + self.char_type = CT_FEMALE; + } + else if (self.team == CHAR_CANNONBALL) { + setmodel(self, "progs/dmcannon.mdl"); + self.char_type = CT_MALE_NORMAL; + } + else if (self.team == CHAR_PHOENIX) { + setmodel(self, "progs/dmphoen.mdl"); + self.char_type = CT_FEMALE; + } + else { // select a random character + self.team = rint(random() * CHAR_PHOENIX); + self.character = self.team; + SetDeathmatchModel(); + } +}; + + +/* +---------------- +ClientMessagesThink + +Used to send Clear V_CSHIFT messages, etc to client upon start a level +---------------- +*/ +void() ClientMessagesThink = +{ + stuffcmd(self.owner, "cl\n"); + stuffcmd(self.owner, "host_framerate 0\n"); // if user quits while in slow-motion in X1END, this will put it back + stuffcmd(self.owner, "bf\n"); // this is a hack, but fixes Lava Death, screen stays red upon respawn + + if (self.owner.chasecam == world) + { + stuffcmd(self.owner, "cl_bobup 1\n"); + stuffcmd(self.owner, "r_drawviewmodel 1\n"); + } + else + { + stuffcmd(self.owner, "cl_bobup 0\n"); + stuffcmd(self.owner, "r_drawviewmodel 0\n"); + } + + if (executable == "glQuake") + stuffcmd(self.owner, "r_wateralpha 0.5\n"); + + remove(self); +}; + + +/* +=========== +PutClientInServer + +called each time a player is spawned +============ +*/ +void() DecodeLevelParms; +void() PlayerDie; + +void() PutClientInServer = +{ + local entity spot, thinker; + + self.classname = "player"; + self.health = self.start_health = 100; + self.takedamage = DAMAGE_AIM; + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_WALK; + self.show_hostile = 0; + self.max_health = 100; + self.flags = FL_CLIENT; + self.x_flags = 0; + self.air_finished = time + 12; + self.dmg = 2; // initial water damage + self.super_damage_finished = 0; + self.radsuit_finished = 0; + self.invisible_finished = 0; + self.invincible_finished = 0; + self.effects = 0; + self.invincible_time = 0; + + serverflags = serverflags | (cvar("temp1") / 2); + + self.spawn_time = time; + + setmodel (self, "progs/eyes.mdl"); + self.modelindex_eyes = self.modelindex; + + if (self.character == 0) { + if (deathmatch || coop) { + setmodel(self, "progs/dmskel.mdl"); + index_skeleton = self.modelindex; + + self.character = self.team; + SetDeathmatchModel(); + } + else { + setmodel (self, "progs/cyborg.mdl"); + } + self.modelindex_player = self.modelindex; + } + + DecodeLevelParms (); + + if (self.weapon != IT_AXE) { + if (self.weapon == IT_LIGHTNING) + self.weapon_idleframe = 2; + else + self.weapon_idleframe = 5; + } + else + self.weapon_idleframe = 6; + + W_SetCurrentAmmo (); + + self.attack_finished = time; + self.th_pain = player_pain; + self.th_die = PlayerDie; + + self.deadflag = DEAD_NO; +// paustime is set by teleporters to keep the player from moving a while + self.pausetime = 0; + + setsize (self, VEC_HULL_MIN, VEC_HULL_MAX); + + spot = SelectSpawnPoint (); + + self.origin = spot.origin + '0 0 1'; +// setorigin(self, spot.origin + '0 0 1'); + self.angles = spot.angles; + self.fixangle = TRUE; // turn this way immediately + +/* +bprint("Player spawned at: "); +bprint(vtos(self.origin)); +bprint("\n"); +*/ + + setsize (self, VEC_HULL_MIN, VEC_HULL_MAX); + + self.view_ofs = '0 0 22'; + if (self.character == CHAR_STORM) + self.view_ofs_z = self.view_ofs_z + STORM_VOFS_Z; + + player_stand1 (); + + if (deathmatch || coop) + { + makevectors(self.angles); + spawn_tfog (self.origin + v_forward*20); + } + + spawn_tdeath (self.origin, self); + + self.weapon_flags = self.weapon_flags - (self.weapon_flags & W_RELOADING); + self.change_weapon_status = 0; + + if (self.flame_ent1 == world) { + // create flamethrower entities + self.flame_ent1 = spawn_flame_ent(); + self.flame_ent2 = spawn_flame_ent(); + self.flame_ent3 = spawn_flame_ent(); + } + + // create laser beam junctions +// self.beam_ent = spawn(); +// self.beam_ent.beam_ent = spawn(); + + // Morph into current weapon + self.change_weapon_status = CW_FADEIN; + self.weaponframe = 0; + self.fadein_endframe = 5; + + // Create a thinker that sends client messages out after 0.5 seconds + thinker = spawn(); + thinker.owner = self; + thinker.think = ClientMessagesThink; + thinker.nextthink = time + 0.5; + + if (deathmatch == 69) { + // Spawn a mirror image of the player for testing + SpawnMirrorPlayer(); + } + +// Chase_cam_level_start(); +// Start_chase_cam(self); + +}; + + +/* +============================================================================= + + QUAKED FUNCTIONS + +============================================================================= +*/ + +void() shootrockets = +{ + self.currentammo = self.ammo_rockets = 50; + W_FireGuidedRockets(); + + self.nextthink = time + 5; +}; + + +/*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 24) +The normal starting point for a level. +*/ +void() info_player_start = +{ +// self.v_angle = self.angles; +// self.think = shootrockets; +// self.nextthink = time + 5; +}; + + +/*QUAKED info_player_start2 (1 0 0) (-16 -16 -24) (16 16 24) +Only used on start map for the return point from an episode. +*/ +void() info_player_start2 = +{ +}; + + +/* +saved out by quaked in region mode +*/ +void() testplayerstart = +{ +}; + +/*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 24) +potential spawning position for deathmatch games +*/ +void() info_player_deathmatch = +{ +}; + +/*QUAKED info_player_coop (1 0 1) (-16 -16 -24) (16 16 24) +potential spawning position for coop games +*/ +void() info_player_coop = +{ +}; + +/* +=============================================================================== + +RULES + +=============================================================================== +*/ + +/* +go to the next level for deathmatch +only called if a time or frag limit has expired +*/ +void() NextLevel = +{ + local entity o; + + if (mapname == "start") + { + if (!cvar("registered")) + { + mapname = "e1m1"; + } + else if (!(serverflags & 1)) + { + mapname = "e1m1"; + serverflags = serverflags + 1; + } + else if (!(serverflags & 2)) + { + mapname = "e2m1"; + serverflags = serverflags + 2; + } + else if (!(serverflags & 4)) + { + mapname = "e3m1"; + serverflags = serverflags + 4; + } + else if (!(serverflags & 8)) + { + mapname = "e4m1"; + serverflags = serverflags + 8; + } + else + { + mapname = "start"; + serverflags = serverflags - 15; + } + + o = spawn(); + o.map = mapname; + } + else + { + // find a trigger changelevel + o = find(world, classname, "trigger_changelevel"); + + // go back to start if no trigger_changelevel + if (!o) + { + mapname = "start"; + o = spawn(); + o.map = mapname; + } + } + + nextmap = o.map; + gameover = TRUE; + + if (o.nextthink < time) + { + o.think = execute_changelevel; + o.nextthink = time + 0.1; + } +}; + +/* +============ +CheckRules + +Exit deathmatch games upon conditions +============ +*/ +void() CheckRules = +{ + local float timelimit; + local float fraglimit; + + if (gameover) // someone else quit the game already + return; + + timelimit = cvar("timelimit") * 60; + fraglimit = cvar("fraglimit"); + + if (timelimit && time >= timelimit) + { + NextLevel (); + return; + } + + if (fraglimit && self.frags >= fraglimit) + { + NextLevel (); + return; + } +}; + +//============================================================================ + +void() PlayerDeathThink = +{ + local entity old_self; + local float forward; + + if ((self.flags & FL_ONGROUND)) + { + forward = vlen (self.velocity); + forward = forward - 20; + if (forward <= 0) + self.velocity = '0 0 0'; + else + self.velocity = forward * normalize(self.velocity); + } + +// wait for all buttons released + if (self.deadflag == DEAD_DEAD) + { + if (self.button2 || self.button1 || self.button0) + return; + self.deadflag = DEAD_RESPAWNABLE; + return; + } + +// wait for any button down + if (!self.button2 && !self.button1 && !self.button0) + return; + + self.button0 = 0; + self.button1 = 0; + self.button2 = 0; + respawn(); +}; + + +void() RandomFlapSound; +void() PlayerJump = +{ + local vector start, end; + + if (self.flags & FL_WATERJUMP) + return; + + if (self.waterlevel >= 2) + { + if (self.watertype == CONTENT_WATER) + self.velocity_z = 100; + else if (self.watertype == CONTENT_SLIME) + self.velocity_z = 80; + else + self.velocity_z = 50; + +// play swiming sound + if (self.swim_flag < time) + { + self.swim_flag = time + 1; + if (random() < 0.5) + sound (self, CHAN_BODY, "misc/water1.wav", 1, ATTN_NORM); + else + sound (self, CHAN_BODY, "misc/water2.wav", 1, ATTN_NORM); + } + + return; + } + + if (!(self.flags & FL_ONGROUND) && (self.character != CHAR_ANGEL)) + return; + + if ( !(self.flags & FL_JUMPRELEASED) ) { // still holding jump + if ((self.character != CHAR_ANGEL) || ((self.origin_z > self.last_jump_z) || (self.velocity_z > 0))) + return; // don't pogo stick + } + else { // just pressed jump + self.last_jump_z = self.origin_z; + } + + self.flags = self.flags - (self.flags & FL_JUMPRELEASED); + + if (self.character != CHAR_ANGEL) + self.flags = self.flags - (self.flags & FL_ONGROUND); // don't stairwalk + else if (self.last_jump > (time - 0.5)) { // prevent flapping too fast + return; + } + + self.last_jump = time; + + self.button2 = 0; +// player jumping sound + if (self.character != CHAR_ANGEL) { +// sound (self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM); + self.velocity_z = self.velocity_z + 270; + + self.x_flags = self.x_flags | X_JUMP_PRESSED; + } + else { + RandomFlapSound(); + self.velocity_z = self.velocity_z + 380; + if (self.velocity_z > 500) + self.velocity_z = 500; + +/* + start = self.velocity; + start_z = 0; + if (vlen(start) < 200) { + if (vlen(start) > 20) + start = normalize(start) * 200; + } +// if (vlen(start) > 200) { +// start = normalize(start) * 200; +// } + + self.velocity_x = start_x; + self.velocity_y = start_y; +*/ + } +}; + + +/* +=========== +WaterMove + +============ +*/ +.float dmgtime; + +void() WaterMove = +{ +//dprint (ftos(self.waterlevel)); + if (self.movetype == MOVETYPE_NOCLIP) + return; + if (self.health < 0) + return; + + if (self.waterlevel != 3) + { +// if (self.air_finished < time) +// sound (self, CHAN_VOICE, "player/gasp2.wav", 1, ATTN_NORM); +// else if (self.air_finished < time + 9) +// sound (self, CHAN_VOICE, "player/gasp1.wav", 1, ATTN_NORM); + self.air_finished = time + 12; + self.dmg = 2; + } + else if (self.air_finished < time) + { // drown! + if (self.pain_finished < time) + { + self.dmg = self.dmg + 2; + if (self.dmg > 15) + self.dmg = 10; + T_Damage (self, world, world, self.dmg); + self.pain_finished = time + 1; + } + } + + if (!self.waterlevel) + { + if (self.flags & FL_INWATER) + { + // play leave water sound + sound (self, CHAN_BODY, "misc/outwater.wav", 1, ATTN_NORM); + self.flags = self.flags - FL_INWATER; + } + return; + } + + if (self.watertype == CONTENT_LAVA) + { // do damage + if (self.dmgtime < time) + { + if (self.radsuit_finished > time) + self.dmgtime = time + 1; + else + self.dmgtime = time + 0.2; + + T_Damage (self, world, world, 10*self.waterlevel); + } + } + else if (self.watertype == CONTENT_SLIME) + { // do damage + if (self.dmgtime < time && self.radsuit_finished < time) + { + self.dmgtime = time + 1; + T_Damage (self, world, world, 4*self.waterlevel); + } + } + + if ( !(self.flags & FL_INWATER) ) + { + +// player enter water sound + +// if (self.watertype == CONTENT_LAVA) +// sound (self, CHAN_BODY, "player/inlava.wav", 1, ATTN_NORM); + if (self.watertype == CONTENT_WATER) + sound (self, CHAN_BODY, "player/h2ojump.wav", 1, ATTN_NORM); +// if (self.watertype == CONTENT_SLIME) +// sound (self, CHAN_BODY, "player/slimbrn2.wav", 1, ATTN_NORM); + + self.flags = self.flags + FL_INWATER; + self.dmgtime = 0; + } + + if (! (self.flags & FL_WATERJUMP) ) + self.velocity = self.velocity - 0.8*self.waterlevel*frametime*self.velocity; +}; + +void() CheckWaterJump = +{ + local vector start, end; + +// check for a jump-out-of-water + makevectors (self.angles); + start = self.origin; + start_z = start_z + 8; + v_forward_z = 0; + normalize(v_forward); + end = start + v_forward*24; + traceline (start, end, TRUE, self); + if (trace_fraction < 1) + { // solid at waist + start_z = start_z + self.maxs_z - 8; + end = start + v_forward*24; + self.movedir = trace_plane_normal * -50; + traceline (start, end, TRUE, self); + if (trace_fraction == 1) + { // open at eye level + self.flags = self.flags | FL_WATERJUMP; + self.velocity_z = 225; + self.flags = self.flags - (self.flags & FL_JUMPRELEASED); + self.teleport_time = time + 2; // safety net + return; + } + } +}; + + +/* +================ +PlayerPreThink + +Called every frame before physics are run +================ +*/ + +void() PlayerPreThink = +{ + local float mspeed, aspeed; + local float r; + local string str; + +//bprint(ftos(self.weaponframe)); +//bprint(" "); + +//bprint("> "); +//bprint(vtos(self.origin)); +//bprint("\n"); + + if (intermission_running) + { + IntermissionThink (); // otherwise a button could be missed between + return; // the think tics + } + + if (self.view_ofs == '0 0 0') + return; // intermission or finale + + if ((self.modelindex == index_skeleton) && (self.health >= 100)) { + self.modelindex = self.modelindex_player; + if (self.chasecam == world) + stuffcmd(self, "r_drawviewmodel 1\n"); + } + + // check beast power view shake + if ((self.view_ofs != '0 0 22') && + (find(world, classname, "beast_power") == world) && + (self.health > 0)) { + self.view_ofs = '0 0 22'; + } + + // check for GOD mode cheating + if (!deathmatch && !coop && (self.flags & FL_GODMODE) && !(self.x_flags & X_GODCHEAT)) { + self.flags = self.flags - FL_GODMODE; + sprint(self, "Sinister has changed the cheat codes\n"); + sound(self, CHAN_BODY, "misc/snicker1.wav", 1, ATTN_NORM); +// T_Damage(self, world, world, self.health - 1); + } + + if (self.x_flags & X_FLYING) + self.velocity = self.old_velocity; +/* + else if ((self.x_flags & X_ANGEL_DEFENSE) && !(self.x_flags & X_TRACTOR_BEAM_HOLD)) { + if (vlen(self.old_velocity) > ((320 * frametime) + 50)) + self.velocity = self.old_velocity - (normalize(self.old_velocity) * 320 * frametime); + else + self.velocity = '0 0 0'; + } +*/ + if ((self.character == CHAR_WOLVERINE) && + (self.health < 100) && + (self.health > 0) && + (self.last_health_regen < (time - 2))) + { + self.health = self.health + 1; + + if (self.health > 100) + self.health = 100; + + self.last_health_regen = time; + } + + if ((self.x_flags & X_RAPID_FIRE) && (self.rapid_time < time)) { + self.x_flags = self.x_flags - X_RAPID_FIRE; + self.items = self.items - (self.items & IT_INVISIBILITY); + self.x_flags = self.x_flags - (self.x_flags & X_RAPID_WARNING); + } + else if ((self.x_flags & X_RAPID_FIRE) && !(self.x_flags & X_RAPID_WARNING) && + (self.rapid_time < (time + 3))) { + self.x_flags = self.x_flags | X_RAPID_WARNING; + sound(self, CHAN_ITEM, "misc/rapidout.wav", 1, ATTN_NORM); + sprint(self, "Rapid Fire is running out!\n"); + } + + makevectors (self.v_angle); // is this still used + + CheckRules (); + WaterMove (); + + if (self.waterlevel == 2) + CheckWaterJump (); + + if (self.deadflag >= DEAD_DEAD) + { + PlayerDeathThink (); + return; + } + + if (self.deadflag == DEAD_DYING) + return; // dying, so do nothing + + if ((self.button2) && (self.health > 0) && (self.parallize_time < time) && !(self.x_flags & X_ANGEL_DEFENSE)) + { + PlayerJump (); + } + else + self.flags = self.flags | FL_JUMPRELEASED; + +// X-Men: Phoenix Tractor Beam + if (self.x_flags & X_TRACTOR_BEAM_HOLD) { +// if (self.start_tractor_time < (time - 4)) +// self.x_flags = self.x_flags - X_TRACTOR_BEAM_HOLD; +// else + self.velocity = self.tractor_vel; + } +// done + +// teleporters can force a non-moving pause time + if (time < self.pausetime) + self.velocity = '0 0 0'; + + if (self.x_flags & X_PARALLIZED) { + self.button0 = FALSE; + if (self.flags & FL_ONGROUND) { + // set velocity + self.velocity = self.parallized_velocity; + } + } + else { + if ((deathmatch || coop) && (self.skin != 0)) + self.skin = 0; + + if (self.last_clear < (time - 2)) { // make sure the screen doesn't stay v_cshift'ed + stuffcmd(self, "cl\n"); + self.last_clear = time; + } + } + + if ((deathmatch || coop) && ((self.character == CHAR_ANGEL) || (self.character == CHAR_STORM))) { + if (self.velocity_z < 0) { + if ((self.old_velocity_z - self.velocity_z) > (cvar("sv_gravity") * frametime * 0.25)) + self.velocity_z = self.old_velocity_z - (cvar("sv_gravity") * frametime * 0.25); + } + } + + self.old_velocity = self.velocity; + + if ((capture) && (last_capture <= (time - 0.05))) { + if (capture_count >= 100) { + capture_count = 0; + capture_index = capture_index + 1; + return; + } + + str = ftos(capture_index); + stuffcmd(self, "ss"); + stuffcmd(self, str); + stuffcmd(self, "\n"); + + last_capture = time; + capture_count = capture_count + 1; + } +}; + +/* +================ +CheckPowerups + +Check for turning off powerups +================ +*/ +void() CheckPowerups = +{ + if (self.health <= 0) + return; + + if (self.modelindex == index_skeleton) + return; + +// invisibility + if (self.invisible_finished) + { +// sound and screen flash when items starts to run out + if (self.invisible_sound < time) + { + sound (self, CHAN_AUTO, "items/inv3.wav", 0.5, ATTN_IDLE); + self.invisible_sound = time + ((random() * 3) + 1); + } + + + if (self.invisible_finished < time + 3) + { + if (self.invisible_time == 1) + { + sprint (self, "Ring of Shadows magic is fading\n"); + stuffcmd (self, "bf\n"); + sound (self, CHAN_AUTO, "items/inv2.wav", 1, ATTN_NORM); + self.invisible_time = time + 1; + } + + if (self.invisible_time < time) + { + self.invisible_time = time + 1; + stuffcmd (self, "bf\n"); + } + } + + if (self.invisible_finished < time) + { // just stopped + self.items = self.items - IT_INVISIBILITY; + self.invisible_finished = 0; + self.invisible_time = 0; + } + + // use the eyes + self.frame = 0; + self.modelindex = self.modelindex_eyes; + } + else + self.modelindex = self.modelindex_player; // don't use eyes + +// invincibility + if (self.invincible_finished) + { +// sound and screen flash when items starts to run out + if (self.invincible_finished < time + 3) + { + if (self.invincible_time == 1) + { + sprint (self, "Ruby of Cyttorak is almost worn out\n"); + stuffcmd (self, "bf\n"); + sound (self, CHAN_AUTO, "items/protect2.wav", 1, ATTN_NORM); + self.invincible_time = time + 1; + } + + if (self.invincible_time < time) + { + self.invincible_time = time + 1; + stuffcmd (self, "bf\n"); + } + } + + if (self.invincible_finished < time) + { // just stopped + self.items = self.items - (self.items & IT_INVULNERABILITY); + self.invincible_time = 0; + self.invincible_finished = 0; + } + if (self.invincible_finished > time) + self.effects = self.effects | EF_DIMLIGHT; + else + self.effects = self.effects - (self.effects & EF_DIMLIGHT); + } + +// super damage + if (self.super_damage_finished) + { + +// sound and screen flash when items starts to run out + + if (self.super_damage_finished < time + 3) + { + if (self.super_time == 1) + { + sprint (self, "Superpower is wearing off\n"); + stuffcmd (self, "bf\n"); + sound (self, CHAN_AUTO, "items/damage2.wav", 1, ATTN_NORM); + self.super_time = time + 1; + } + + if (self.super_time < time) + { + self.super_time = time + 1; + stuffcmd (self, "bf\n"); + } + } + + if (self.super_damage_finished < time) + { // just stopped + self.items = self.items - IT_QUAD; + self.super_damage_finished = 0; + self.super_time = 0; + } + if (self.super_damage_finished > time) + self.effects = self.effects | EF_DIMLIGHT; + else + self.effects = self.effects - (self.effects & EF_DIMLIGHT); + } + +// suit + if (self.radsuit_finished) + { + self.air_finished = time + 12; // don't drown + +// sound and screen flash when items starts to run out + if (self.radsuit_finished < time + 3) + { + if (self.rad_time == 1) + { + sprint (self, "Air supply in Biosuit expiring\n"); + stuffcmd (self, "bf\n"); + sound (self, CHAN_AUTO, "items/suit2.wav", 1, ATTN_NORM); + self.rad_time = time + 1; + } + + if (self.rad_time < time) + { + self.rad_time = time + 1; + stuffcmd (self, "bf\n"); + } + } + + if (self.radsuit_finished < time) + { // just stopped + self.items = self.items - IT_SUIT; + self.rad_time = 0; + self.radsuit_finished = 0; + } + } + +}; + + +/* +================ +PlayerPostThink + +Called every frame after physics are run +================ +*/ +void() PlayerPostThink = +{ + local float mspeed, aspeed; + local float r, vol; + + if (self.view_ofs == '0 0 0') + return; // intermission or finale + if (self.deadflag) + return; + + if (self.colormap != 0) { + self.colormap = 0; + +// if (deathmatch && (self.spawn_time < (time - 2))) +// sprint(self, "You must re-connect to use the new character\n"); + } + +/* + if ((self.parallize_time > time) && (self.flags & FL_ONGROUND)) { + setorigin(self, self.oldorigin); + } + else +*/ + if ((self.parallize_time < time) && (self.x_flags & X_PARALLIZED)) { + self.x_flags = self.x_flags - X_PARALLIZED; + stuffcmd(self, "cl\n"); + stuffcmd(self, "bf\n"); + } + +// do weapon stuff + if (!(self.x_flags & X_PARALLIZED)) + W_WeaponFrame (); + +// check to see if player landed and play landing sound + if ((self.jump_flag < -100) && (self.flags & FL_ONGROUND) && (self.health > 0)) + { + if ((self.modelindex == index_skeleton) && (self.jump_flag < -500)) { + T_Damage (self, world, world, self.health + 20); + } + + if (self.watertype == CONTENT_WATER) + sound (self, CHAN_BODY, "player/h2ojump.wav", 1, ATTN_NORM); + else if (self.jump_flag < -650) + { + T_Damage (self, world, world, 5); + if (!deathmatch && !coop) { + r = random() * 4; + if (r < 1) + sound (self, CHAN_VOICE, "player/land1.wav", 1, ATTN_NORM); + else if (r < 3) + sound (self, CHAN_VOICE, "player/land3.wav", 1, ATTN_NORM); + else if (r < 4) + sound (self, CHAN_VOICE, "player/land4.wav", 1, ATTN_NORM); + } + self.deathtype = "falling"; + } + else { + if (!deathmatch && !coop) { + vol = ((-1 * self.jump_flag) - 100) / 550; + vol = vol * vol; // reduce sound somewhat + + if (vol < 0.1) + vol = 0.1; + + r = random() * 4; + if (r < 1) + sound (self, CHAN_VOICE, "player/land1.wav", vol, ATTN_NORM); + else if (r < 3) + sound (self, CHAN_VOICE, "player/land3.wav", vol, ATTN_NORM); + else if (r < 4) + sound (self, CHAN_VOICE, "player/land4.wav", vol, ATTN_NORM); + } + } + + self.jump_flag = 0; + } + + if (!(self.flags & FL_ONGROUND)) + self.jump_flag = self.velocity_z; + + CheckPowerups (); +/* + if (self.chasecam != world) { + self = self.chasecam; + self.think(); + self = self.owner; + } +*/ + if (self.character == CHAR_ANGEL) + self.flags = self.flags | FL_ONGROUND; + + if (self.chasecam != world) { + self = self.chasecam; + CamThink(); + self = self.owner; + } + +}; + + +/* +=========== +ClientConnect + +called when a player connects to a server +============ +*/ +void() ClientConnect = +{ + bprint (self.netname); + bprint (" entered the game as "); + bprint(GetCharacterString(self.team)); + bprint ("\n"); + + num_clients = num_clients + 1; + +// a client connecting during an intermission can cause problems + if (intermission_running) + ExitIntermission (); +}; + + +/* +=========== +ClientDisconnect + +called when a player disconnects from a server +============ +*/ +void() ClientDisconnect = +{ + if (gameover) + return; + // if the level end trigger has been activated, just return + // since they aren't *really* leaving + + KillFlameEntities(self); + + // attempt to clear the screen of any c_shift stuff (doesn't work very well, but worth a shot) + stuffcmd(self, "cl\n"); + + // let everyone else know + bprint (self.netname); + bprint (" left the game with "); + bprint (ftos(self.frags)); + bprint (" frags\n"); + sound (self, CHAN_BODY, "skeleton/crunch.wav", 1, ATTN_NONE); + set_suicide_frame (); +}; + +/* +=========== +ClientObituary + +called when a player dies +============ +*/ +void(entity targ, entity attacker) ClientObituary = +{ + local float rnum; + local string deathstring, deathstring2; + rnum = random(); + + if (targ.classname == "player") + { + if (attacker.classname == "teledeath") + { + bprint (targ.netname); + bprint (" was telefragged by "); + bprint (attacker.owner.netname); + bprint ("\n"); + + attacker.owner.frags = attacker.owner.frags + 1; + return; + } + + if (attacker.classname == "teledeath2") + { + bprint ("Satan's power deflects "); + bprint (targ.netname); + bprint ("'s telefrag\n"); + + targ.frags = targ.frags - 1; + return; + } + + if (attacker.classname == "player") + { + if (targ == attacker) + { + // killed self + attacker.frags = attacker.frags - 1; + bprint (targ.netname); + + if (targ.weapon == 64 && targ.waterlevel > 1) + { + bprint (" discharges into the water.\n"); + return; + } + if (targ.weapon == IT_GRENADE_LAUNCHER) + bprint (" tries to put the pin back in\n"); + else + bprint (" becomes bored with life\n"); + return; + } + else if ( (teamplay == 2) && (targ.team > 0)&&(targ.team == attacker.team) ) + { + if (rnum < 0.25) + deathstring = " mows down a teammate\n"; + else if (rnum < 0.50) + deathstring = " checks his glasses\n"; + else if (rnum < 0.75) + deathstring = " gets a frag for the other team\n"; + else + deathstring = " loses another friend\n"; + bprint (attacker.netname); + bprint (deathstring); + attacker.frags = attacker.frags - 1; + return; + } + else + { + attacker.frags = attacker.frags + 1; + + rnum = attacker.weapon; + if (rnum == IT_AXE) + { + deathstring = " was killed by "; + deathstring2 = "\n"; + } + if (rnum == IT_SHOTGUN) + { + deathstring = " was blasted by "; + deathstring2 = "'s shotgun\n"; + } + if (rnum == IT_SUPER_SHOTGUN) + { + deathstring = " was mowed down by "; + deathstring2 = "'s chaingun\n"; + } + if (rnum == IT_NAILGUN) + { + deathstring = " was burnt by "; + deathstring2 = "'s flameball\n"; + } + if (rnum == IT_SUPER_NAILGUN) + { + deathstring = " sucked down "; + deathstring2 = "'s flamethrower\n"; + } + if (rnum == IT_GRENADE_LAUNCHER) + { + deathstring = " ate "; + deathstring2 = "'s orb\n"; + } + if (rnum == IT_ROCKET_LAUNCHER) + { + deathstring = " couldn't avoid "; + deathstring2 = "'s smart rocket\n"; + } + if (rnum == IT_LIGHTNING) + { + deathstring = " was obliterated by "; + deathstring2 = "'s energy ball\n"; + } + bprint (targ.netname); + bprint (deathstring); + bprint (attacker.netname); + bprint (deathstring2); + } + return; + } + else + { + + // killed by a montser? + if (attacker.flags & FL_MONSTER) + { + bprint(self.netname); + + if (attacker.classname == "xmen_bishop") + bprint (" was shot by a Bishop X-Clone\n"); + if (attacker.classname == "xmen_wolverine") + bprint (" was clawed by a Wolverine X-Clone\n"); + if (attacker.classname == "xmen_beast") + bprint (" was thumped by a Beast X-Clone\n"); + if (attacker.classname == "xmen_cyclops") + bprint (" was blasted by a Cyclops X-Clone\n"); + if (attacker.classname == "xmen_gambit") + bprint (" was slain by a Gambit X-Clone\n"); + if (attacker.classname == "xmen_psylocke") + bprint (" succumbed to a Psylocke X-Clone's martial artistry\n"); + if (attacker.classname == "xmen_rogue") + bprint (" was killed by a Rogue X-Clone\n"); + if (attacker.classname == "xmen_phoenix") + bprint (" was killed by a Phoenix X-Clone\n"); + if (attacker.classname == "xmen_storm") + bprint (" was fried by a Storm X-Clone's bolt\n"); + if (attacker.classname == "xmen_angel") + bprint (" was feathered by an Arch-Angel X-Clone\n"); + if (attacker.classname == "xmen_iceman") + bprint (" was iced by an Iceman X-Clone\n"); + if (attacker.classname == "xmen_cannonball") + bprint (" was killed by a Cannonball X-Clone\n"); + if (attacker.classname == "xmen_apocalypse") + bprint (" was killed by Apocalypse\n"); + if (attacker.classname == "apocalypse_small") + bprint (" was killed by Apocalypse\n"); + if (attacker.classname == "xmen_sinister") + bprint (" was killed by Sinister\n"); + + return; + } + + targ.frags = targ.frags - 1; + bprint (targ.netname); + + // tricks and traps + // Begin Xmen (cl2) + if (attacker.classname == "tripwire_endpoint" || attacker.classname == "tripwire_startpoint") + { + bprint (" was blown to pieces\n"); + return; + } + if (attacker.classname == "info_lightning") + { + bprint (" was fried by a lightning bolt\n"); + return; + } + // End Xmen + + if (attacker.classname == "explo_box") + { + bprint (" blew up\n"); + return; + } + if (attacker.solid == SOLID_BSP && attacker != world) + { + bprint (" was squished\n"); + return; + } + if (attacker.classname == "trap_shooter" || attacker.classname == "trap_spikeshooter") + { + bprint (" was spiked\n"); + return; + } + if (attacker.classname == "fireball") + { + bprint (" ate a lavaball\n"); + return; + } + if (attacker.classname == "trigger_changelevel") + { + bprint (" tried to leave\n"); + return; + } + + // in-water deaths + rnum = targ.watertype; + if (rnum == -3) + { + if (random() < 0.5) + bprint (" sleeps with the fishes\n"); + else + bprint (" sucks it down\n"); + return; + } + else if (rnum == -4) + { + if (random() < 0.5) + bprint (" gulped a load of slime\n"); + else + bprint (" can't exist on slime alone\n"); + return; + } + else if (rnum == -5) + { + if (targ.health < -15) + { + bprint (" burst into flames\n"); + return; + } + if (random() < 0.5) + bprint (" turned into hot slag\n"); + else + bprint (" visits the Volcano God\n"); + return; + } + + // fell to their death? + if (targ.deathtype == "falling") + { + targ.deathtype = ""; + bprint (" fell to their death\n"); + return; + } + + // hell if I know; he's just dead!!! + bprint (" died\n"); + } + } +}; diff --git a/COMBAT.c b/COMBAT.c new file mode 100644 index 0000000..91c8f1f --- /dev/null +++ b/COMBAT.c @@ -0,0 +1,424 @@ + +void() T_MissileTouch; +void() info_player_start; +void(entity targ, entity attacker) ClientObituary; + +void() monster_death_use; + +//============================================================================ + +/* +============ +CanDamage + +Returns true if the inflictor can directly damage the target. Used for +explosions and melee attacks. +============ +*/ +float(entity targ, entity inflictor) CanDamage = +{ + // X-Men: Lightning Bolts cannot harm Storm + if ((inflictor.classname == "info_lightning") && + ((targ.classname == "xmen_storm") || (targ.classname == "apocalypse_small") || (targ.classname == "apoc_torso"))) { + return FALSE; + } + // end + +// bmodels need special checking because their origin is 0,0,0 + if (targ.movetype == MOVETYPE_PUSH) + { + traceline(inflictor.origin, 0.5 * (targ.absmin + targ.absmax), TRUE, self); + if (trace_fraction == 1) + return TRUE; + if (trace_ent == targ) + return TRUE; + return FALSE; + } + + traceline(inflictor.origin, targ.origin, TRUE, self); + if (trace_fraction == 1) + return TRUE; + traceline(inflictor.origin, targ.origin + '15 15 0', TRUE, self); + if (trace_fraction == 1) + return TRUE; + traceline(inflictor.origin, targ.origin + '-15 -15 0', TRUE, self); + if (trace_fraction == 1) + return TRUE; + traceline(inflictor.origin, targ.origin + '-15 15 0', TRUE, self); + if (trace_fraction == 1) + return TRUE; + traceline(inflictor.origin, targ.origin + '15 -15 0', TRUE, self); + if (trace_fraction == 1) + return TRUE; + + return FALSE; +}; + + +/* +============ +Killed +============ +*/ +void(entity targ, entity attacker) Killed = +{ + local entity oself; + + oself = self; + self = targ; + + if (self.health < -99) + self.health = -99; // don't let sbar look bad if a player + + if (self.movetype == MOVETYPE_PUSH || self.movetype == MOVETYPE_NONE) + { // doors, triggers, etc + self.th_die (); + self = oself; + return; + } + + self.enemy = attacker; + + // check for Apocalypse laugh + if ((attacker.classname == "xmen_apocalypse") && + (targ.classname == "player")) { + sound(self, CHAN_VOICE, "apoc/alaugh.wav", 1, ATTN_NONE); + } + +// bump the monster counter + if ((self.flags & FL_MONSTER) && (!(self.spawnflags & SPAWNFLAG_CLONE)) && (self.classname != "xmen_wolverine") && !(self.x_flags & X_MEGA_HIT) && (self.classname != "xmen_sinister") && (self.classname != "xmen_apocalypse") && (self.classname != "apocalypse_small") && ((self.classname != "xmen_wolverine"))) + { + self.angles_z = 0; + + if (!(self.spawnflags & SPAWNFLAG_CLONE)) { + killed_monsters = killed_monsters + 1; + WriteByte (MSG_ALL, SVC_KILLEDMONSTER); + } + + self.skin = 3; // death skin + } + + ClientObituary(self, attacker); + + self.takedamage = DAMAGE_NO; + self.touch = SUB_Null; + + if (self.classname != "xmen_techdude") + monster_death_use(); + + self.th_die (); + + self = oself; +}; + + +/* +============ +T_Damage + +The damage is coming from inflictor, but get mad at attacker +This should be the only function that ever reduces health. +============ +*/ +void(entity e) skeleton_morph; +void(entity e) iceman_melt; +void() phoenix_xattc12; +void() player_run; +void() DM_PhoenixBeamEnd; +void(entity targ, entity inflictor, entity attacker, float damage) T_Damage= +{ + local vector dir; + local entity oldself; + local float save; + local float take; + +//bprint("T_Damage\n"); + + damage_inflictor = inflictor; + + // Apocalype: if hurting torso entity, change target to owner + if (targ.classname == "apoc_torso") { + targ = targ.owner; + } + +// if (((targ.flags & FL_MONSTER) || (targ.classname == "player")) && (targ.health <= 0)) +// return; + + if (!targ.takedamage) + return; + + + // don't hurt clones of same type + if ((attacker.flags & FL_MONSTER) && (attacker.classname == targ.classname)) + return; + + if (((inflictor.classname == "proximity_ball") || (inflictor.classname == "prox_missile")) && + (targ.classname == "xmen_bishop")) + return; + +// used by buttons and triggers to set activator for target firing + damage_attacker = attacker; + + if ((targ.model == "progs/skel.mdl") && (damage_attacker.weapon == IT_SUPER_NAILGUN)) { +// self.health = 1; + return; + } + +// check for quad damage powerup on the attacker + if (attacker.super_damage_finished > time) + damage = damage * 2; + +// Bishop not get hurt as much by Plasma and NERD + if ((targ.character == CHAR_BISHOP) && + ((inflictor.classname == "flameball") || + (inflictor.classname == "prox_missile") || + (inflictor.classname == "proximity_ball"))) { + damage = damage / 2; + } + +// save damage based on the target's armor level + + save = ceil(targ.armortype*damage); + if (save >= targ.armorvalue) + { + save = targ.armorvalue; + targ.armortype = 0; // lost all armor + targ.items = targ.items - (targ.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)); + } + + targ.armorvalue = targ.armorvalue - save; + take = ceil(damage-save); + +// add to the damage total for clients, which will be sent as a single +// message at the end of the frame +// FIXME: remove after combining shotgun blasts? + if (targ.flags & FL_CLIENT) + { + targ.dmg_take = targ.dmg_take + take; + targ.dmg_save = targ.dmg_save + save; + targ.dmg_inflictor = inflictor; + } + +// figure momentum add + if ( (inflictor != world) && (targ.movetype == MOVETYPE_WALK) ) + { + dir = targ.origin - (inflictor.absmin + inflictor.absmax) * 0.5; + dir = normalize(dir); + if (!deathmatch) + dir_z = 0; + targ.velocity = targ.velocity + (dir*damage*8); + } + +// check for godmode or invincibility + if (targ.flags & FL_GODMODE) { + + // first check for Pheonix abort while in Tractor Beam + if (((targ.classname == "xmen_phoenix") || (targ.character == CHAR_PHOENIX)) && (targ.start_tractor_time < (time - 0.75))) { + + if ((targ.character == CHAR_PHOENIX) && (targ.move_ent != world)) { + oldself = self; + self = targ; + + DM_PhoenixBeamEnd(); + + self = oldself; + } + + if (targ.classname == "xmen_phoenix") { + targ.enemy.x_flags = targ.enemy.x_flags - (targ.enemy.x_flags & X_TRACTOR_BEAM_HOLD); + targ.enemy.velocity = normalize(targ.enemy.origin - targ.origin) * 250 + '0 0 100'; + targ.think = phoenix_xattc12; + } + } + + return; + } + + // Check for DM Angel wing defense + if ((targ.x_flags & X_ANGEL_DEFENSE) && ((inflictor.classname == "guided_rocket") || (inflictor.classname == "orb"))) + return; + + if (targ.invincible_finished >= time) + { + if (self.invincible_sound < time) + { + sound (targ, CHAN_ITEM, "items/protect3.wav", 1, ATTN_NORM); + self.invincible_sound = time + 2; + } + return; + } + +// team play damage avoidance + if ( (teamplay == 1) && (targ.team > 0)&&(targ.team == attacker.team) ) + return; + +//bprint("doing damage..\n"); + +// do the damage + targ.health = targ.health - take; + + if ((targ.classname == "player") && (targ.armorvalue <= 0) && (targ.health < 50)) { + if (attacker.weapon == IT_SUPER_NAILGUN) { + if (targ.model != "progs/skel.mdl") { + targ.health = 1; + targ.modelindex = index_skeleton; + + targ.weaponmodel = ""; + targ.think = player_run; + + centerprint(targ, "You have been torched!"); + } + } + } + + if (targ.health <= 0) + { + if (deathmatch || coop) { + if (attacker.weapon == IT_SUPER_NAILGUN) { // skeleton time! +// targ.health = 1; + targ.modelindex = index_skeleton; + + targ.weaponmodel = ""; + targ.think = player_run; + + centerprint(targ, "You have been torched!"); + } + else + Killed (targ, attacker); + } + else if ((attacker.weapon == IT_SUPER_NAILGUN) && (targ.classname != "xmen_wolverine") && ((targ.flags & FL_MONSTER) || (targ.classname == "xmen_techdude")) && (targ.classname != "xmen_sinister") && (targ.classname != "apocalypse_small")) { + if ((targ.classname != "xmen_iceman") ) { + if (targ.model != "progs/skel.mdl") + skeleton_morph(targ); + } + else + iceman_melt(targ); + } + else + Killed (targ, attacker); + + return; + } + else { + SetDamageSkin(targ); + } + +// react to the damage + oldself = self; + self = targ; + + if ( (self.parallize_time < time) && (self.flags & FL_MONSTER) && (attacker != world) && !(attacker.flags & FL_MONSTER) && (!(self.spawnflags & SPAWNFLAG_CLONE))) + { + // get mad unless of the same class (except for soldiers) + if (self != attacker && attacker != self.enemy) + { + if (self.classname != attacker.classname) + { + if (self.enemy.classname == "player") { + self.oldenemy = self.enemy; + } + + // bosses only attack player + if ((self.classname != "xmen_apocalypse") || (self.classname != "apocalypse_small") || (self.classname != "xmen_sinister")) { + if (attacker.classname == "player") { + self.enemy = attacker; + FoundTarget (); + } + } + else { // other monsters attack anything + self.enemy = attacker; + FoundTarget (); + } + } + } + } + + if (self.th_pain) + { + if ((!(self.weapon_flags & W_RELOADING)) && !(self.change_weapon_status)) { + self.th_pain (attacker, take); + // nightmare mode monsters don't go into pain frames often + if (skill == 3) + self.pain_finished = time + 5; + } + } + + self = oldself; +}; + +/* +============ +T_RadiusDamage +============ +*/ +void(entity inflictor, entity attacker, float damage, entity ignore) T_RadiusDamage = +{ + local float points; + local entity head; + local vector org; + + head = findradius(inflictor.origin, damage+40); + + while (head) + { + if (head != ignore) + { + if (head.takedamage) + { + org = head.origin + (head.mins + head.maxs)*0.5; + points = 0.5*vlen (inflictor.origin - org); + if (points < 0) + points = 0; + points = damage - points; + if (head == attacker) + points = points * 0.5; + if (points > 0) + { + if (CanDamage (head, inflictor)) + { // shambler takes half damage from all explosions + T_Damage (head, inflictor, attacker, points); + } + } + } + } + head = head.chain; + } +}; + +/* +============ +T_BeamDamage +============ +*/ +void(entity attacker, float damage) T_BeamDamage = +{ + local float points; + local entity head; + + head = findradius(attacker.origin, damage+40); + + while (head) + { + if (head.takedamage) + { + points = 0.5*vlen (attacker.origin - head.origin); + if (points < 0) + points = 0; + points = damage - points; + if (head == attacker) + points = points * 0.5; + if (points > 0) + { + if (CanDamage (head, attacker)) + { + if (head.classname == "xmen_storm") + T_Damage (head, attacker, attacker, points*0.5); + else + T_Damage (head, attacker, attacker, points); + } + } + } + head = head.chain; + } +}; + diff --git a/DEFS.c b/DEFS.c new file mode 100644 index 0000000..a34d47b --- /dev/null +++ b/DEFS.c @@ -0,0 +1,705 @@ + +/* +============================================================================== + + SOURCE FOR GLOBALVARS_T C STRUCTURE + +============================================================================== +*/ + +// +// system globals +// +entity self; +entity other; +entity world; +float time; +float frametime; + +float force_retouch; // force all entities to touch triggers + // next frame. this is needed because + // non-moving things don't normally scan + // for triggers, and when a trigger is + // created (like a teleport trigger), it + // needs to catch everything. + // decremented each frame, so set to 2 + // to guarantee everything is touched +string mapname; + +float deathmatch; +float coop; +float teamplay; + +float serverflags; // propagated from level to level, used to + // keep track of completed episodes + +float total_secrets; +float total_monsters; + +float found_secrets; // number of secrets found +float killed_monsters; // number of monsters killed + + +// spawnparms are used to encode information about clients across server +// level changes +float parm1, parm2, parm3, parm4, parm5, parm6, parm7, parm8, parm9, parm10, parm11, parm12, parm13, parm14, parm15, parm16; + +// +// global variables set by built in functions +// +vector v_forward, v_up, v_right; // set by makevectors() + +// set by traceline / tracebox +float trace_allsolid; +float trace_startsolid; +float trace_fraction; +vector trace_endpos; +vector trace_plane_normal; +float trace_plane_dist; +entity trace_ent; +float trace_inopen; +float trace_inwater; + +entity msg_entity; // destination of single entity writes + +// +// required prog functions +// +void() main; // only for testing + +void() StartFrame; + +void() PlayerPreThink; +void() PlayerPostThink; + +void() ClientKill; +void() ClientConnect; +void() PutClientInServer; // call after setting the parm1... parms +void() ClientDisconnect; + +void() SetNewParms; // called when a client first connects to + // a server. sets parms so they can be + // saved off for restarts + +void() SetChangeParms; // call to set parms for self so they can + // be saved for a level transition + + +//================================================ +void end_sys_globals; // flag for structure dumping +//================================================ + +/* +============================================================================== + + SOURCE FOR ENTVARS_T C STRUCTURE + +============================================================================== +*/ + +// +// system fields (*** = do not set in prog code, maintained by C code) +// +.float modelindex; // *** model index in the precached list +.vector absmin, absmax; // *** origin + mins / maxs + +.float ltime; // local time for entity +.float movetype; +.float solid; + +.vector origin; // *** +.vector oldorigin; // *** +.vector velocity; +.vector angles; +.vector avelocity; + +.vector punchangle; // temp angle adjust from damage or recoil + +.string classname; // spawn function +.string model; +.float frame; +.float skin; +.float effects; + +.vector mins, maxs; // bounding box extents reletive to origin +.vector size; // maxs - mins + +.void() touch; +.void() use; +.void() think; +.void() blocked; // for doors or plats, called when can't push other + +.float nextthink; +.entity groundentity; + +// stats +.float health; +.float frags; +.float weapon; // one of the SHOTGUN, etc flags +.string weaponmodel; +.float weaponframe; +.float currentammo; +.float ammo_shells, ammo_nails, ammo_rockets, ammo_cells; + +.float items; // bit flags + +.float takedamage; +.entity chain; +.float deadflag; + +.vector view_ofs; // add to origin to get eye point + + +.float button0; // fire +.float button1; // use +.float button2; // jump + +.float impulse; // weapon changes + +.float fixangle; +.vector v_angle; // view / targeting angle for players +.float idealpitch; // calculated pitch angle for lookup up slopes + + +.string netname; + +.entity enemy; + +.float flags; + +.float colormap; +.float team; + +.float max_health; // players maximum health is stored here + +.float teleport_time; // don't back up + +.float armortype; // save this fraction of incoming damage +.float armorvalue; + +.float waterlevel; // 0 = not in, 1 = feet, 2 = wast, 3 = eyes +.float watertype; // a contents value + +.float ideal_yaw; +.float yaw_speed; + +.entity aiment; + +.entity goalentity; // a movetarget or an enemy + +.float spawnflags; + +.string target; +.string targetname; + +// damage is accumulated through a frame. and sent as one single +// message, so the super shotgun doesn't generate huge messages +.float dmg_take; +.float dmg_save; +.entity dmg_inflictor; + +.entity owner; // who launched a missile +.vector movedir; // mostly for doors, but also used for waterjump + +.string message; // trigger messages + +.float sounds; // either a cd track number or sound number + +.string noise, noise1, noise2, noise3; // contains names of wavs to play + +//================================================ +void end_sys_fields; // flag for structure dumping +//================================================ + +.float respawn_time; // used for Wolvie/Demon respawn + +/* +============================================================================== + + VARS NOT REFERENCED BY C CODE + +============================================================================== +*/ + + +// +// constants +// + +float FALSE = 0; +float TRUE = 1; + +// edict.flags +float FL_FLY = 1; +float FL_SWIM = 2; +float FL_CLIENT = 8; // set for all client edicts +float FL_INWATER = 16; // for enter / leave water splash +float FL_MONSTER = 32; +float FL_GODMODE = 64; // player cheat +float FL_NOTARGET = 128; // player cheat +float FL_ITEM = 256; // extra wide size for bonus items +float FL_ONGROUND = 512; // standing on something +float FL_PARTIALGROUND = 1024; // not all corners are valid +float FL_WATERJUMP = 2048; // player jumping out of water +float FL_JUMPRELEASED = 4096; // for jump debouncing +float FL_FLAMEON = 8192; // set when flamethrower is ON + +// edict.movetype values +float MOVETYPE_NONE = 0; // never moves +//float MOVETYPE_ANGLENOCLIP = 1; +//float MOVETYPE_ANGLECLIP = 2; +float MOVETYPE_WALK = 3; // players only +float MOVETYPE_STEP = 4; // discrete, not real time unless fall +float MOVETYPE_FLY = 5; +float MOVETYPE_TOSS = 6; // gravity +float MOVETYPE_PUSH = 7; // no clip to world, push and crush +float MOVETYPE_NOCLIP = 8; +float MOVETYPE_FLYMISSILE = 9; // fly with extra size against monsters +float MOVETYPE_BOUNCE = 10; +float MOVETYPE_BOUNCEMISSILE = 11; // bounce with extra size + +// edict.solid values +float SOLID_NOT = 0; // no interaction with other objects +float SOLID_TRIGGER = 1; // touch on edge, but not blocking +float SOLID_BBOX = 2; // touch on edge, block +float SOLID_SLIDEBOX = 3; // touch on edge, but not an onground +float SOLID_BSP = 4; // bsp clip, touch on edge, block + +// range values +float RANGE_MELEE = 0; +float RANGE_NEAR = 1; +float RANGE_MID = 2; +float RANGE_FAR = 3; + +// deadflag values + +float DEAD_NO = 0; +float DEAD_DYING = 1; +float DEAD_DEAD = 2; +float DEAD_RESPAWNABLE = 3; + +// takedamage values + +float DAMAGE_NO = 0; +float DAMAGE_YES = 1; +float DAMAGE_AIM = 2; + +// items +float IT_AXE = 4096; +float IT_SHOTGUN = 1; +float IT_SUPER_SHOTGUN = 2; +float IT_NAILGUN = 4; +float IT_SUPER_NAILGUN = 8; +float IT_GRENADE_LAUNCHER = 16; +float IT_ROCKET_LAUNCHER = 32; +float IT_LIGHTNING = 64; +float IT_SPECIAL_WEAPON = 128; + +float IT_SHELLS = 256; +float IT_NAILS = 512; +float IT_ROCKETS = 1024; +float IT_CELLS = 2048; + +float IT_ARMOR1 = 8192; +float IT_ARMOR2 = 16384; +float IT_ARMOR3 = 32768; +float IT_SUPERHEALTH = 65536; + +float IT_KEY1 = 131072; +float IT_KEY2 = 262144; + +float IT_INVISIBILITY = 524288; +float IT_INVULNERABILITY = 1048576; +float IT_SUIT = 2097152; +float IT_QUAD = 4194304; + +// point content values + +float CONTENT_EMPTY = -1; +float CONTENT_SOLID = -2; +float CONTENT_WATER = -3; +float CONTENT_SLIME = -4; +float CONTENT_LAVA = -5; +float CONTENT_SKY = -6; + +float STATE_TOP = 0; +float STATE_BOTTOM = 1; +float STATE_UP = 2; +float STATE_DOWN = 3; + +vector VEC_ORIGIN = '0 0 0'; +vector VEC_HULL_MIN = '-16 -16 -24'; +vector VEC_HULL_MAX = '16 16 32'; + +vector VEC_HULL2_MIN = '-32 -32 -24'; +vector VEC_HULL2_MAX = '32 32 64'; + +// protocol bytes +float SVC_TEMPENTITY = 23; +float SVC_KILLEDMONSTER = 27; +float SVC_FOUNDSECRET = 28; +float SVC_INTERMISSION = 30; +float SVC_FINALE = 31; +float SVC_CDTRACK = 32; +float SVC_SELLSCREEN = 33; + + +float TE_SPIKE = 0; +float TE_SUPERSPIKE = 1; +float TE_GUNSHOT = 2; +float TE_EXPLOSION = 3; +float TE_TAREXPLOSION = 4; +float TE_LIGHTNING1 = 5; +float TE_LIGHTNING2 = 6; +float TE_WIZSPIKE = 7; +float TE_KNIGHTSPIKE = 8; +float TE_LIGHTNING3 = 9; +float TE_LAVASPLASH = 10; +float TE_TELEPORT = 11; + +// sound channels +// channel 0 never willingly overrides +// other channels (1-7) allways override a playing sound on that channel +float CHAN_AUTO = 0; +float CHAN_WEAPON = 1; +float CHAN_VOICE = 2; +float CHAN_ITEM = 3; +float CHAN_BODY = 4; + +float ATTN_NONE = 0; +float ATTN_NORM = 1; +float ATTN_IDLE = 2; +float ATTN_STATIC = 3; + +// update types + +float UPDATE_GENERAL = 0; +float UPDATE_STATIC = 1; +float UPDATE_BINARY = 2; +float UPDATE_TEMP = 3; + +// entity effects + +float EF_BRIGHTFIELD = 1; +float EF_MUZZLEFLASH = 2; +float EF_BRIGHTLIGHT = 4; +float EF_DIMLIGHT = 8; + + +// messages +float MSG_BROADCAST = 0; // unreliable to all +float MSG_ONE = 1; // reliable to one (msg_entity) +float MSG_ALL = 2; // reliable to all +float MSG_INIT = 3; // write to the init string + +//================================================ + +// +// globals +// +float movedist; +float gameover; // set when a rule exits + +string string_null; // null string, nothing should be held here +float empty_float; + +entity newmis; // launch_spike sets this after spawning it + +entity activator; // the entity that activated a trigger or brush + +entity damage_attacker; // set by T_Damage +float framecount; + +float skill; + +float intermission_running; +float intermission_exittime; + +//================================================ + +// +// world fields (FIXME: make globals) +// +.string wad; +.string map; +.float worldtype; // 0=medieval 1=metal 2=base + +//================================================ + +.string killtarget; + +// +// quakeed fields +// +.float light_lev; // not used by game, but parsed by light util +.float style; + + +// +// monster ai +// +.void() th_stand; +.void() th_walk; +.void() th_run; +.void() th_missile; +.void() th_melee; +.void(entity attacker, float damage) th_pain; +.void() th_die; + +.entity oldenemy; // mad at this player before taking damage + +.float speed; + +.float lefty; + +.float search_time; +.float attack_state; + +float AS_STRAIGHT = 1; +float AS_SLIDING = 2; +float AS_MELEE = 3; +float AS_MISSILE = 4; + +// +// player only fields +// +.float walkframe; + +.float attack_finished; +.float pain_finished; + +.float invincible_finished; +.float invisible_finished; +.float super_damage_finished; +.float radsuit_finished; + +.float invincible_time, invincible_sound; +.float invisible_time, invisible_sound; +.float super_time, super_sound; +.float rad_time; +.float fly_sound; + +.float axhitme; + +.float show_hostile; // set to time+0.2 whenever a client fires a + // weapon or takes damage. Used to alert + // monsters that otherwise would let the player go +.float jump_flag; // player jump flag +.float swim_flag; // player swimming sound flag +.float air_finished; // when time > air_finished, start drowning +.float bubble_count; // keeps track of the number of bubbles +.string deathtype; // keeps track of how the player died + +// +// object stuff +// +.string mdl; +.vector mangle; // angle at start + +.vector oldorigin; // only used by secret door + +.float t_length, t_width; + + +// +// doors, etc +// +.vector dest, dest1, dest2; +.float wait; // time from firing to restarting +.float delay; // time from activation to firing +.entity trigger_field; // door's trigger entity +.string noise4; + +// +// monsters +// +.float pausetime; +.entity movetarget; + +// x-men monsters +.float last_health_regen; +.float last_guided_search; + +// x-men environmental stuff +.float last_blood_think; + +// +// doors +// +.float aflag; +.float dmg; // damage done by door when hit + +// +// misc +// +.float cnt; // misc flag + +// +// subs +// +.void() think1; +.vector finaldest, finalangle; + +// +// triggers +// +.float count; // for counting triggers + + +// +// plats / doors / buttons +// +.float lip; +.float state; +.vector pos1, pos2; // top and bottom positions +.float height; + +// +// sounds +// +.float waitmin, waitmax; +.float distance; +.float volume; + + + + +//=========================================================================== + + +// +// builtin functions +// + +void(vector ang) makevectors = #1; // sets v_forward, etc globals +void(entity e, vector o) setorigin = #2; +void(entity e, string m) setmodel = #3; // set movetype and solid first +void(entity e, vector min, vector max) setsize = #4; +// #5 was removed +void() break = #6; +float() random = #7; // returns 0 - 1 +void(entity e, float chan, string samp, float vol, float atten) sound = #8; +vector(vector v) normalize = #9; +void(string e) error = #10; +void(string e) objerror = #11; +float(vector v) vlen = #12; +float(vector v) vectoyaw = #13; +entity() spawn = #14; +void(entity e) remove = #15; + +// sets trace_* globals +// nomonsters can be: +// An entity will also be ignored for testing if forent == test, +// forent->owner == test, or test->owner == forent +// a forent of world is ignored +void(vector v1, vector v2, float nomonsters, entity forent) traceline = #16; + +entity() checkclient = #17; // returns a client to look for +entity(entity start, .string fld, string match) find = #18; +string(string s) precache_sound = #19; +string(string s) precache_model = #20; +void(entity client, string s)stuffcmd = #21; +entity(vector org, float rad) findradius = #22; +void(string s) bprint = #23; +void(entity client, string s) sprint = #24; +void(string s) dprint = #25; +string(float f) ftos = #26; +string(vector v) vtos = #27; +void() coredump = #28; // prints all edicts +void() traceon = #29; // turns statment trace on +void() traceoff = #30; +void(entity e) eprint = #31; // prints an entire edict +float(float yaw, float dist) walkmove = #32; // returns TRUE or FALSE +// #33 was removed +float(float yaw, float dist) droptofloor= #34; // TRUE if landed on floor +void(float style, string value) lightstyle = #35; +float(float v) rint = #36; // round to nearest int +float(float v) floor = #37; // largest integer <= v +float(float v) ceil = #38; // smallest integer >= v +// #39 was removed +float(entity e) checkbottom = #40; // true if self is on ground +float(vector v) pointcontents = #41; // returns a CONTENT_* +// #42 was removed +float(float f) fabs = #43; +vector(entity e, float speed) aim = #44; // returns the shooting vector +float(string s) cvar = #45; // return cvar.value +void(string s) localcmd = #46; // put string into local que +entity(entity e) nextent = #47; // for looping through all ents +void(vector o, vector d, float color, float count) particle = #48;// start a particle effect +void() ChangeYaw = #49; // turn towards self.ideal_yaw + // at self.yaw_speed +// #50 was removed +vector(vector v) vectoangles = #51; + +// +// direct client message generation +// +void(float to, float f) WriteByte = #52; +void(float to, float f) WriteChar = #53; +void(float to, float f) WriteShort = #54; +void(float to, float f) WriteLong = #55; +void(float to, float f) WriteCoord = #56; +void(float to, float f) WriteAngle = #57; +void(float to, string s) WriteString = #58; +void(float to, entity s) WriteEntity = #59; + +// +// broadcast client message generation +// + +// void(float f) bWriteByte = #59; +// void(float f) bWriteChar = #60; +// void(float f) bWriteShort = #61; +// void(float f) bWriteLong = #62; +// void(float f) bWriteCoord = #63; +// void(float f) bWriteAngle = #64; +// void(string s) bWriteString = #65; +// void(entity e) bWriteEntity = #66; + +void(float step) movetogoal = #67; + +string(string s) precache_file = #68; // no effect except for -copy +void(entity e) makestatic = #69; +void(string s) changelevel = #70; + +//#71 was removed + +void(string var, string val) cvar_set = #72; // sets cvar.value + +void(entity client, string s) do_centerprint = #73; // sprint, but in middle + +void(vector pos, string samp, float vol, float atten) ambientsound = #74; + +string(string s) precache_model2 = #75; // registered version only +string(string s) precache_sound2 = #76; // registered version only +string(string s) precache_file2 = #77; // registered version only + +void(entity e) setspawnparms = #78; // set parm1... to the + // values at level start + // for coop respawn + +//============================================================================ + +// +// subs.qc +// +void(vector tdest, float tspeed, void() func) SUB_CalcMove; +void(entity ent, vector tdest, float tspeed, void() func) SUB_CalcMoveEnt; +void(vector destangle, float tspeed, void() func) SUB_CalcAngleMove; +void() SUB_CalcMoveDone; +void() SUB_CalcAngleMoveDone; +void() SUB_Null; +void() SUB_UseTargets; +void() SUB_Remove; + +// +// combat.qc +// +void(entity targ, entity inflictor, entity attacker, float damage) T_Damage; + + +float (entity e, float healamount, float ignore) T_Heal; // health function + +float(entity targ, entity inflictor) CanDamage; + + diff --git a/DOORS.c b/DOORS.c new file mode 100644 index 0000000..653eecc --- /dev/null +++ b/DOORS.c @@ -0,0 +1,834 @@ + +float DOOR_START_OPEN = 1; +float DOOR_DONT_LINK = 4; +float DOOR_GOLD_KEY = 8; +float DOOR_SILVER_KEY = 16; +float DOOR_TOGGLE = 32; + +/* + +Doors are similar to buttons, but can spawn a fat trigger field around them +to open without a touch, and they link together to form simultanious +double/quad doors. + +Door.owner is the master door. If there is only one door, it points to itself. +If multiple doors, all will point to a single one. + +Door.enemy chains from the master door through all doors linked in the chain. + +*/ + +/* +============================================================================= + +THINK FUNCTIONS + +============================================================================= +*/ + +void() door_go_down; +void() door_go_up; + +void() door_blocked = +{ + T_Damage (other, self, self, self.dmg); + +// 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.wait >= 0) + { + if (self.state == STATE_DOWN) + door_go_up (); + else + door_go_down (); + } +}; + + +void() door_hit_top = +{ + sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); + self.state = STATE_TOP; + if (self.spawnflags & DOOR_TOGGLE) + return; // don't come down automatically + self.think = door_go_down; + self.nextthink = self.ltime + self.wait; +}; + +void() door_hit_bottom = +{ + sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); + self.state = STATE_BOTTOM; +}; + +void() door_go_down = +{ + sound (self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); + if (self.max_health) + { + self.takedamage = DAMAGE_YES; + self.health = self.max_health; + } + + self.state = STATE_DOWN; + SUB_CalcMove (self.pos1, self.speed, door_hit_bottom); +}; + +void() door_go_up = +{ + if (self.state == STATE_UP) + return; // allready going up + + if (self.state == STATE_TOP) + { // reset top wait time + self.nextthink = self.ltime + self.wait; + return; + } + + sound (self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); + self.state = STATE_UP; + SUB_CalcMove (self.pos2, self.speed, door_hit_top); + + SUB_UseTargets(); +}; + + +/* +============================================================================= + +ACTIVATION FUNCTIONS + +============================================================================= +*/ + +void() door_fire = +{ + local entity oself; + local entity starte; + + if (self.owner != self) + objerror ("door_fire: self.owner != self"); + +// play use key sound + + if (self.items) + sound (self, CHAN_VOICE, self.noise4, 1, ATTN_NORM); + + self.message = string_null; // no more message + oself = self; + + if (self.spawnflags & DOOR_TOGGLE) + { + if (self.state == STATE_UP || self.state == STATE_TOP) + { + starte = self; + do + { + door_go_down (); + self = self.enemy; + } while ( (self != starte) && (self != world) ); + self = oself; + return; + } + } + +// trigger all paired doors + starte = self; + do + { + door_go_up (); + self = self.enemy; + } while ( (self != starte) && (self != world) ); + self = oself; +}; + +float() avatar_door = +{ + local entity spot; + local float cyc; + + cyc = 50; + spot = world; + while (cyc > 1) + { + spot = find (spot, classname, "door"); + if (spot) { + if ((spot != self) && (spot.frags > 0)) + cyc = 0; + } + else { + bprint("avatar_door: Unable to locate matching door\n"); + return; + } + + } + + if ((self.state == 0) && (spot.state == 0)) + { + local entity oself; + + spot.message = ""; + spot.owner.message = ""; + spot.enemy.message = ""; + oself = self; + self = spot.owner; + door_fire (); + self = oself; + } +}; + +void() elevator_door_think = +{ + local entity lift, corner; + + // door has been touched, keep checking to see if lift has arrived + corner = find(world, targetname, self.target); +}; + +void() door_use = +{ + local entity oself; + + if (self.frags > 0) + { + avatar_door(); + if (self.state != 1) + return; + } + + self.message = ""; // door message are for touch only + self.owner.message = ""; + self.enemy.message = ""; + oself = self; + self = self.owner; + door_fire (); + self = oself; +}; + + +void() door_trigger_touch = +{ + if (other.health <= 0) + return; + + if (time < self.attack_finished) + return; + self.attack_finished = time + 1; + + activator = other; + + self = self.owner; + door_use (); +}; + + +void() door_killed = +{ + local entity oself; + + oself = self; + self = self.owner; + self.health = self.max_health; + self.takedamage = DAMAGE_NO; // wil be reset upon return + door_use (); + self = oself; +}; + + +/* +================ +door_touch + +Prints messages and opens key doors +================ +*/ +void() door_touch = +{ + if (other.classname != "player") + return; + if (self.owner.attack_finished > time) + return; + + self.owner.attack_finished = time + 2; + + if (self.owner.message != "") + { + centerprint (other, self.owner.message); + sound (other, CHAN_VOICE, "misc/talk.wav", 1, ATTN_NORM); + } + +// key door stuff + if (!self.items) + return; + +// FIXME: blink key on player's status bar + if ( (self.items & other.items) != self.items ) + { + if (self.owner.items == IT_KEY1) + { + if (world.worldtype == 2) + { + centerprint (other, "You need the silver keycard"); + sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); + } + else if (world.worldtype == 1) + { + centerprint (other, "You need the silver runekey"); + sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); + } + else if (world.worldtype == 0) + { + centerprint (other, "You need the silver key"); + sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); + } + } + else + { + if (world.worldtype == 2) + { + centerprint (other, "You need the gold keycard"); + sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); + } + else if (world.worldtype == 1) + { + centerprint (other, "You need the gold runekey"); + sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); + } + else if (world.worldtype == 0) + { + centerprint (other, "You need the gold key"); + sound (self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); + } + } + return; + } + + other.items = other.items - self.items; + self.touch = SUB_Null; + if (self.enemy) + self.enemy.touch = SUB_Null; // get paired door + door_use (); +}; + +/* +============================================================================= + +SPAWNING FUNCTIONS + +============================================================================= +*/ + + +entity(vector fmins, vector fmaxs) spawn_field = +{ + local entity trigger; + local vector t1, t2; + + trigger = spawn(); + trigger.movetype = MOVETYPE_NONE; + trigger.solid = SOLID_TRIGGER; + trigger.owner = self; + trigger.touch = door_trigger_touch; + + t1 = fmins; + t2 = fmaxs; + setsize (trigger, t1 - '60 60 8', t2 + '60 60 8'); + return (trigger); +}; + + +float (entity e1, entity e2) EntitiesTouching = +{ + if (e1.mins_x > e2.maxs_x) + return FALSE; + if (e1.mins_y > e2.maxs_y) + return FALSE; + if (e1.mins_z > e2.maxs_z) + return FALSE; + if (e1.maxs_x < e2.mins_x) + return FALSE; + if (e1.maxs_y < e2.mins_y) + return FALSE; + if (e1.maxs_z < e2.mins_z) + return FALSE; + return TRUE; +}; + + +/* +============= +LinkDoors + + +============= +*/ +void() LinkDoors = +{ + local entity t, starte; + local vector cmins, cmaxs; + + if (self.enemy) + return; // already linked by another door + if (self.spawnflags & 4) + { + self.owner = self.enemy = self; + return; // don't want to link this door + } + + cmins = self.mins; + cmaxs = self.maxs; + + starte = self; + t = self; + + do + { + self.owner = starte; // master door + + if (self.health) + starte.health = self.health; + if (self.targetname) + starte.targetname = self.targetname; + if (self.message != "") + starte.message = self.message; + + t = find (t, classname, self.classname); + if (!t) + { + self.enemy = starte; // make the chain a loop + + // shootable, fired, or key doors just needed the owner/enemy links, + // they don't spawn a field + + self = self.owner; + + if (self.health) + return; + if (self.targetname) + return; + if (self.items) + return; + + self.owner.trigger_field = spawn_field(cmins, cmaxs); + + return; + } + + if (EntitiesTouching(self,t)) + { + if (t.enemy) + objerror ("cross connected doors"); + + self.enemy = t; + self = t; + + if (t.mins_x < cmins_x) + cmins_x = t.mins_x; + if (t.mins_y < cmins_y) + cmins_y = t.mins_y; + if (t.mins_z < cmins_z) + cmins_z = t.mins_z; + if (t.maxs_x > cmaxs_x) + cmaxs_x = t.maxs_x; + if (t.maxs_y > cmaxs_y) + cmaxs_y = t.maxs_y; + if (t.maxs_z > cmaxs_z) + cmaxs_z = t.maxs_z; + } + } while (1 ); + +}; + + +/*QUAKED func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK GOLD_KEY SILVER_KEY TOGGLE +if two doors touch, they are assumed to be connected and operate as a unit. + +TOGGLE causes the door to wait in both the start and end states for a trigger event. + +START_OPEN causes the door to move to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not usefull for touch or takedamage doors). + +Key doors are allways wait -1. + +"message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet +"angle" determines the opening direction +"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door. +"health" if set, door must be shot open +"speed" movement speed (100 default) +"wait" wait before returning (3 default, -1 = never return) +"lip" lip remaining at end of move (8 default) +"dmg" damage to inflict when blocked (2 default) +"sounds" +0) no sound +1) stone +2) base +3) stone chain +4) screechy metal +*/ + +void() func_door = + +{ + + if (world.worldtype == 0) + { + precache_sound ("doors/medtry.wav"); + precache_sound ("doors/meduse.wav"); + self.noise3 = "doors/medtry.wav"; + self.noise4 = "doors/meduse.wav"; + } + else if (world.worldtype == 1) + { + precache_sound ("doors/runetry.wav"); + precache_sound ("doors/runeuse.wav"); + self.noise3 = "doors/runetry.wav"; + self.noise4 = "doors/runeuse.wav"; + } + else if (world.worldtype == 2) + { + precache_sound ("doors/basetry.wav"); + precache_sound ("doors/baseuse.wav"); + self.noise3 = "doors/basetry.wav"; + self.noise4 = "doors/baseuse.wav"; + } + else + { + dprint ("no worldtype set!\n"); + } + if (self.sounds == 0) + { + precache_sound ("misc/null.wav"); + precache_sound ("misc/null.wav"); + self.noise1 = "misc/null.wav"; + self.noise2 = "misc/null.wav"; + } + if (self.sounds == 1) + { + precache_sound ("doors/drclos4.wav"); + precache_sound ("doors/doormv1.wav"); + self.noise1 = "doors/drclos4.wav"; + self.noise2 = "doors/doormv1.wav"; + } + if (self.sounds == 2) + { + precache_sound ("doors/hydro1.wav"); + precache_sound ("doors/hydro2.wav"); + self.noise2 = "doors/hydro1.wav"; + self.noise1 = "doors/hydro2.wav"; + } + if (self.sounds == 3) + { + precache_sound ("doors/stndr1.wav"); + precache_sound ("doors/stndr2.wav"); + self.noise2 = "doors/stndr1.wav"; + self.noise1 = "doors/stndr2.wav"; + } + if (self.sounds == 4) + { + precache_sound ("doors/ddoor1.wav"); + precache_sound ("doors/ddoor2.wav"); + self.noise1 = "doors/ddoor2.wav"; + self.noise2 = "doors/ddoor1.wav"; + } + if (self.sounds == 5) // X-Men: drill sound + { + precache_sound ("doors/ddoor1.wav"); + precache_sound ("ambience/drill_x.wav"); + self.noise1 = "doors/ddoor2.wav"; + self.noise2 = "ambience/drill_x.wav"; + } + + + SetMovedir (); + + self.max_health = self.health; + self.solid = SOLID_BSP; + self.movetype = MOVETYPE_PUSH; + setorigin (self, self.origin); + setmodel (self, self.model); + self.classname = "door"; + + self.blocked = door_blocked; + self.use = door_use; + + if (self.spawnflags & DOOR_SILVER_KEY) + self.items = IT_KEY1; + if (self.spawnflags & DOOR_GOLD_KEY) + self.items = IT_KEY2; + + if (!self.speed) + self.speed = 100; + if (!self.wait) + self.wait = 3; + if (!self.lip) + self.lip = 8; + if (!self.dmg) + self.dmg = 2; + + self.pos1 = self.origin; + self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip); + +// DOOR_START_OPEN is to allow an entity to be lighted in the closed position +// but spawn in the open position + if (self.spawnflags & DOOR_START_OPEN) + { + setorigin (self, self.pos2); + self.pos2 = self.pos1; + self.pos1 = self.origin; + } + + self.state = STATE_BOTTOM; + + if (self.health) + { + self.takedamage = DAMAGE_YES; + self.th_die = door_killed; + } + + if (self.items) + self.wait = -1; + + self.touch = door_touch; + +// LinkDoors can't be done until all of the doors have been spawned, so +// the sizes can be detected properly. + self.think = LinkDoors; + self.nextthink = self.ltime + 0.1; +}; + +/* +============================================================================= + +SECRET DOORS + +============================================================================= +*/ + +void() fd_secret_move1; +void() fd_secret_move2; +void() fd_secret_move3; +void() fd_secret_move4; +void() fd_secret_move5; +void() fd_secret_move6; +void() fd_secret_done; + +float SECRET_OPEN_ONCE = 1; // stays open +float SECRET_1ST_LEFT = 2; // 1st move is left of arrow +float SECRET_1ST_DOWN = 4; // 1st move is down from arrow +float SECRET_NO_SHOOT = 8; // only opened by trigger +float SECRET_YES_SHOOT = 16; // shootable even if targeted + + +void () fd_secret_use = +{ + local float temp; + + self.health = 10000; + + // exit if still moving around... + if (self.origin != self.oldorigin) + return; + + self.message = string_null; // no more message + + SUB_UseTargets(); // fire all targets / killtargets + + if (!(self.spawnflags & SECRET_NO_SHOOT)) + { + self.th_pain = SUB_Null; + self.takedamage = DAMAGE_NO; + } + self.velocity = '0 0 0'; + + // Make a sound, wait a little... + + sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); + self.nextthink = self.ltime + 0.1; + + temp = 1 - (self.spawnflags & SECRET_1ST_LEFT); // 1 or -1 + makevectors(self.mangle); + + if (!self.t_width) + { + if (self.spawnflags & SECRET_1ST_DOWN) + self. t_width = fabs(v_up * self.size); + else + self. t_width = fabs(v_right * self.size); + } + + if (!self.t_length) + self. t_length = fabs(v_forward * self.size); + + if (self.spawnflags & SECRET_1ST_DOWN) + self.dest1 = self.origin - v_up * self.t_width; + else + self.dest1 = self.origin + v_right * (self.t_width * temp); + + self.dest2 = self.dest1 + v_forward * self.t_length; + SUB_CalcMove(self.dest1, self.speed, fd_secret_move1); + sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); +}; + +// Wait after first movement... +void () fd_secret_move1 = +{ + self.nextthink = self.ltime + 1.0; + self.think = fd_secret_move2; + sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); +}; + +// Start moving sideways w/sound... +void () fd_secret_move2 = +{ + sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); + SUB_CalcMove(self.dest2, self.speed, fd_secret_move3); +}; + +// Wait here until time to go back... +void () fd_secret_move3 = +{ + sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); + if (!(self.spawnflags & SECRET_OPEN_ONCE)) + { + self.nextthink = self.ltime + self.wait; + self.think = fd_secret_move4; + } +}; + +// Move backward... +void () fd_secret_move4 = +{ + sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); + SUB_CalcMove(self.dest1, self.speed, fd_secret_move5); +}; + +// Wait 1 second... +void () fd_secret_move5 = +{ + self.nextthink = self.ltime + 1.0; + self.think = fd_secret_move6; + sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); +}; + +void () fd_secret_move6 = +{ + sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); + SUB_CalcMove(self.oldorigin, self.speed, fd_secret_done); +}; + +void () fd_secret_done = +{ + if (!self.targetname || self.spawnflags&SECRET_YES_SHOOT) + { + self.health = 10000; + self.takedamage = DAMAGE_YES; + self.th_pain = fd_secret_use; + } + sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM); +}; + +void () secret_blocked = +{ + if (time < self.attack_finished) + return; + self.attack_finished = time + 0.5; + T_Damage (other, self, self, self.dmg); +}; + +/* +================ +secret_touch + +Prints messages +================ +*/ +void() secret_touch = +{ + if (other.classname != "player") + return; + if (self.attack_finished > time) + return; + + self.attack_finished = time + 2; + + if (self.message) + { + centerprint (other, self.message); + sound (other, CHAN_BODY, "misc/talk.wav", 1, ATTN_NORM); + } +}; + + +/*QUAKED func_door_secret (0 .5 .8) ? open_once 1st_left 1st_down no_shoot always_shoot +Basic secret door. Slides back, then to the side. Angle determines direction. +wait = # of seconds before coming back +1st_left = 1st move is left of arrow +1st_down = 1st move is down from arrow +always_shoot = even if targeted, keep shootable +t_width = override WIDTH to move back (or height if going down) +t_length = override LENGTH to move sideways +"dmg" damage to inflict when blocked (2 default) + +If a secret door has a targetname, it will only be opened by it's botton or trigger, not by damage. +"sounds" +1) medieval +2) metal +3) base +*/ + +void () func_door_secret = +{ + if (self.sounds == 0) + self.sounds = 3; + if (self.sounds == 1) + { + precache_sound ("doors/latch2.wav"); + precache_sound ("doors/winch2.wav"); + precache_sound ("doors/drclos4.wav"); + self.noise1 = "doors/latch2.wav"; + self.noise2 = "doors/winch2.wav"; + self.noise3 = "doors/drclos4.wav"; + } + if (self.sounds == 2) + { + precache_sound ("doors/airdoor1.wav"); + precache_sound ("doors/airdoor2.wav"); + self.noise2 = "doors/airdoor1.wav"; + self.noise1 = "doors/airdoor2.wav"; + self.noise3 = "doors/airdoor2.wav"; + } + if (self.sounds == 3) + { + precache_sound ("doors/basesec1.wav"); + precache_sound ("doors/basesec2.wav"); + self.noise2 = "doors/basesec1.wav"; + self.noise1 = "doors/basesec2.wav"; + self.noise3 = "doors/basesec2.wav"; + } + + if (!self.dmg) + self.dmg = 2; + + // Magic formula... + self.mangle = self.angles; + self.angles = '0 0 0'; + self.solid = SOLID_BSP; + self.movetype = MOVETYPE_PUSH; + self.classname = "door"; + setmodel (self, self.model); + setorigin (self, self.origin); + + self.touch = secret_touch; + self.blocked = secret_blocked; + self.speed = 50; + self.use = fd_secret_use; + if ( !self.targetname || self.spawnflags&SECRET_YES_SHOOT) + { + self.health = 10000; + self.takedamage = DAMAGE_YES; + self.th_pain = fd_secret_use; + self.th_die = fd_secret_use; + } + self.oldorigin = self.origin; + if (!self.wait) + self.wait = 5; // 5 seconds before closing +}; diff --git a/EXPLBRSH.c b/EXPLBRSH.c new file mode 100644 index 0000000..02a36fd --- /dev/null +++ b/EXPLBRSH.c @@ -0,0 +1,117 @@ +/* + Begin Xmen - cl2 + Exploding Brushes + */ + +void () fe_boom = +{ + local float num, r, mass; + local vector neworgs, vect; + local entity targ, oself; + + vect = self.absmax - self.absmin; + mass = (vect_x / 10) * (vect_y / 10) * (vect_z / 10); + + self.solid = SOLID_NOT; + neworgs = self.absmax - self.absmin; + self.origin_x = self.absmin_x + neworgs_x * random(); + self.origin_y = self.absmin_y + neworgs_y * random(); + self.origin_z = self.absmin_z + neworgs_z * random(); + + num = floor(mass / 100) + 5; + if (num > 12) + num = 12; + + while (num >= 0) { + r = random (); + if (r < 0.2) { + ThrowGib ("progs/rubble1.mdl", random () * -50); + } else if (r < 0.4) { + ThrowGib ("progs/rubble2.mdl", random () * -50); + } else if (r < 0.6) { + ThrowGib ("progs/rubble3.mdl", random () * -50); + } else if (r < 0.8) { + ThrowGib ("progs/rubble4.mdl", random () * -50); + } else { + ThrowGib ("progs/rubble5.mdl", random () * -50); + } + num = num - 1; + } + T_RadiusDamage (self, self, 100, world); + sound (self, CHAN_WEAPON, "weapons/r_exp3.wav", 1, ATTN_NORM); + BecomeExplosion (); + + SUB_UseTargets(); +}; + +void () fe_touch = +{ + local entity oself; + + if ((other.classname != "guided_rocket") && + (other.classname != "orb")) + return; + + if (self.targetname != "") + return; + + if (other.classname == "orb") { + oself = self; + self = other; + GrenadeExplode(); + self = oself; + } + + fe_boom (); +}; + +void () fe_use = +{ + self.think = fe_boom; + self.nextthink = time + 0.1; +}; + +void () func_explode = +{ +if (deathmatch) { + remove(self); + return; +} + + if (!self.state) + self.state = 1; // FIXME + + precache_model ("progs/rubble1.mdl"); + precache_model ("progs/rubble2.mdl"); + precache_model ("progs/rubble3.mdl"); + precache_model ("progs/rubble4.mdl"); + precache_model ("progs/rubble5.mdl"); + self.movetype = MOVETYPE_PUSH; + self.solid = SOLID_BSP; + setmodel (self, self.model); + self.use = fe_use; + self.touch = fe_touch; + self.health = 0; + self.takedamage = DAMAGE_NO; + + // set speed (skin) according to "mdl" field + if (self.mdl == "computer1") + self.speed = 0; + else if (self.mdl == "ewall") + self.speed = 1; + else if (self.mdl == "grass") + self.speed = 2; + else if (self.mdl == "bb016") + self.speed = 3; + else if (self.mdl == "steel") + self.speed = 4; + else if (self.mdl == "metal") + self.speed = 5; + else if (self.mdl == "redpan") + self.speed = 6; + else if (self.mdl == "conpanel") + self.speed = 7; + else if (self.mdl == "egyptwall") + self.speed = 8; + +}; diff --git a/FIGHT.c b/FIGHT.c new file mode 100644 index 0000000..f07b16e --- /dev/null +++ b/FIGHT.c @@ -0,0 +1,435 @@ + +/* + +A monster is in fight mode if it thinks it can effectively attack its +enemy. + +When it decides it can't attack, it goes into hunt mode. + +*/ + +float(float v) anglemod; + +void() knight_atk; +void() knight_runattack; + +float() DemonCheckAttack; +void(float side) Demon_Melee; + +void(vector dest) ChooseTurn; + +void() ai_face; + + +float enemy_vis, enemy_infront, enemy_range; +float enemy_yaw; + + +void() knight_attack = +{ + local float len; + +// decide if now is a good swing time + len = vlen(self.enemy.origin+self.enemy.view_ofs - (self.origin+self.view_ofs)); + + if (len<80) + knight_atk (); + else { + knight_runattack (); + } +}; + +//============================================================================= + +/* +=========== +CheckAttack + +The player is in view, so decide to move or launch an attack +Returns FALSE if movement should continue +============ +*/ +float() CheckAttack = +{ + local vector spot1, spot2; + local entity targ; + local float chance; + + if (!(enemy_infront)) + return FALSE; + + targ = self.enemy; + +// see if any entities are in the way of the shot + spot1 = self.origin + self.view_ofs; + spot2 = targ.origin + targ.view_ofs; + + traceline (spot1, spot2, FALSE, self); + + if (trace_ent != targ) + return FALSE; // don't have a clear shot + + if (trace_inopen && trace_inwater) + return FALSE; // sight line crossed contents + + if (enemy_range == RANGE_MELEE) + { // melee attack + if (self.th_melee) + { + if (self.classname == "xmen_psylocke") + knight_attack (); + else + self.th_melee (); + return TRUE; + } + } + +// missile attack + if (!self.th_missile) + return FALSE; + + if (time < self.attack_finished) + return FALSE; + + if (enemy_range == RANGE_FAR) + return FALSE; + + if (enemy_range == RANGE_MELEE) + { + chance = 0.9; + self.attack_finished = 0; + } + else if (enemy_range == RANGE_NEAR) + { + if (self.th_melee) + chance = 0.2; + else + chance = 0.4; + } + else if (enemy_range == RANGE_MID) + { + if (self.th_melee) + chance = 0.05; + else + chance = 0.1; + } + else + chance = 0; + + if (random () < chance) + { + self.th_missile (); + SUB_AttackFinished (2*random()); + return TRUE; + } + + return FALSE; +}; + + +/* +============= +ai_face + +Stay facing the enemy +============= +*/ +void() ai_face = +{ + local float diff; + + self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin); + + if (self.flags & FL_FLY) { + diff = angle_diff(self.angles_y, self.ideal_yaw); + + if (diff < -10) + self.angles_z = self.angles_z - 2; + else if (diff > 10) + self.angles_z = self.angles_z + 2; + else { + if (fabs(self.angles_z) < 2) + self.angles_z = 0; + else if (self.angles_z > 0) + self.angles_z = self.angles_z - 2; + else + self.angles_z = self.angles_z + 2; + } + + if (self.angles_z > 30) + self.angles_z = 30; + else if (self.angles_z < -30) + self.angles_z = -30; + } + + ChangeYaw (); +}; + +/* +============= +ai_charge + +The monster is in a melee attack, so get as close as possible to .enemy +============= +*/ +float (entity targ) visible; +float(entity targ) infront; +float(entity targ) range; + +void(float d) ai_charge = +{ + ai_face (); + movetogoal (d); // done in C code... + + if (self.classname == "xmen_wolverine") + self.nextthink = time + 0.05; +}; + +void() ai_charge_side = +{ + local vector dtemp; + local float heading; + +// aim to the left of the enemy for a flyby + + self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin); + ChangeYaw (); + + makevectors (self.angles); + dtemp = self.enemy.origin - 30*v_right; + heading = vectoyaw(dtemp - self.origin); + + walkmove(heading, 20); +}; + + +/* +============= +ai_melee + +============= +*/ +void() ai_melee = +{ + local vector delta; + local float ldmg; + + if (!self.enemy) + return; // removed before stroke + + delta = self.enemy.origin - self.origin; + + if (vlen(delta) > 60) + return; + + ldmg = (random() + random() + random()) * 3; + T_Damage (self.enemy, self, self, ldmg); +}; + + +void() ai_melee_side = +{ + local vector delta; + local float ldmg; + + if (!self.enemy) + return; // removed before stroke + + ai_charge_side(); + + delta = self.enemy.origin - self.origin; + + if (vlen(delta) > 60) + return; + if (!CanDamage (self.enemy, self)) + return; + ldmg = (random() + random() + random()) * 3; + T_Damage (self.enemy, self, self, ldmg); +}; + + +//============================================================================= + +/* +=========== +SoldierCheckAttack + +The player is in view, so decide to move or launch an attack +Returns FALSE if movement should continue +============ +*/ +float() SoldierCheckAttack = +{ + local vector spot1, spot2; + local entity targ; + local float chance; + + targ = self.enemy; + +// see if any entities are in the way of the shot + spot1 = self.origin + self.view_ofs; + spot2 = targ.origin + targ.view_ofs; + + traceline (spot1, spot2, FALSE, self); + + if (trace_inopen && trace_inwater) + return FALSE; // sight line crossed contents + + if (trace_ent != targ) + return FALSE; // don't have a clear shot + + +// missile attack + if (time < self.attack_finished) + return FALSE; + + if (enemy_range == RANGE_FAR) + return FALSE; + + if (enemy_range == RANGE_MELEE) + chance = 0.9; + else if (enemy_range == RANGE_NEAR) + chance = 0.4; + else if (enemy_range == RANGE_MID) + chance = 0.05; + else + chance = 0; + + if (random () < chance) + { + self.th_missile (); + SUB_AttackFinished (1 + random()); + if (random() < 0.3) + self.lefty = !self.lefty; + + return TRUE; + } + + return FALSE; +}; +//============================================================================= + +/* +=========== +ShamCheckAttack + +The player is in view, so decide to move or launch an attack +Returns FALSE if movement should continue +============ +*/ +float() ShamCheckAttack = +{ + local vector spot1, spot2; + local entity targ; + local float chance; + local float enemy_yaw; + + if (enemy_range == RANGE_MELEE) + { + if (CanDamage (self.enemy, self)) + { + self.attack_state = AS_MELEE; + return TRUE; + } + } + + if (time < self.attack_finished) + return FALSE; + + if (!enemy_vis) + return FALSE; + + targ = self.enemy; + +// see if any entities are in the way of the shot + spot1 = self.origin + self.view_ofs; + spot2 = targ.origin + targ.view_ofs; + + if (vlen(spot1 - spot2) > 600) + return FALSE; + + traceline (spot1, spot2, FALSE, self); + + if (trace_inopen && trace_inwater) + return FALSE; // sight line crossed contents + + if (trace_ent != targ) + { + return FALSE; // don't have a clear shot + } + +// missile attack + if (enemy_range == RANGE_FAR) + return FALSE; + + self.attack_state = AS_MISSILE; + SUB_AttackFinished (2 + 2*random()); + return TRUE; +}; + +//============================================================================ + +/* +=========== +OgreCheckAttack + +The player is in view, so decide to move or launch an attack +Returns FALSE if movement should continue +============ +*/ +float() OgreCheckAttack = +{ + local vector spot1, spot2; + local entity targ; + local float chance; + + if (enemy_range == RANGE_MELEE) + { + if (CanDamage (self.enemy, self)) + { + self.attack_state = AS_MELEE; + return TRUE; + } + } + + if (time < self.attack_finished) + return FALSE; + + if (!enemy_vis) + return FALSE; + + targ = self.enemy; + +// see if any entities are in the way of the shot + spot1 = self.origin + self.view_ofs; + spot2 = targ.origin + targ.view_ofs; + + traceline (spot1, spot2, FALSE, self); + + if (trace_inopen && trace_inwater) + return FALSE; // sight line crossed contents + + if (trace_ent != targ) + { + return FALSE; // don't have a clear shot + } + +// missile attack + if (time < self.attack_finished) + return FALSE; + + if (enemy_range == RANGE_FAR) + return FALSE; + + else if (enemy_range == RANGE_NEAR) + chance = 0.10; + else if (enemy_range == RANGE_MID) + chance = 0.05; + else + chance = 0; + + self.attack_state = AS_MISSILE; + SUB_AttackFinished (1 + 2*random()); + return TRUE; +}; + diff --git a/ITEMS.c b/ITEMS.c new file mode 100644 index 0000000..330ee02 --- /dev/null +++ b/ITEMS.c @@ -0,0 +1,2739 @@ +void() W_SetCurrentAmmo; +void(float wpn) SetNewWeapon; + +/* ALL LIGHTS SHOULD BE 0 1 0 IN COLOR ALL OTHER ITEMS SHOULD + +BE .8 .3 .4 IN COLOR */ + +.float healamount, healtype; + +void() item_animate_think = +{ + self.skin = 1 - self.skin; + self.nextthink = time + 0.5; +}; + +/* +void() superh_think = +{ + self.frame = self.frame + 1; + if (self.frame > 5) + self.frame = 0; + + self.nextthink = time + 0.1; +}; +*/ + + +void() SUB_regen = + +{ + + self.model = self.mdl; // restore original model + + self.solid = SOLID_TRIGGER; // allow it to be touched again + + sound (self, CHAN_VOICE, "items/itembk2.wav", 1, ATTN_NORM); // play respawn sound + + setorigin (self, self.origin); + + if (self.x_flags & X_AMMO_ANIMATE) { + self.think = item_animate_think; + self.nextthink = time + 0.5; + } +// else if (self.healtype == 2) { +// self.think = superh_think; +// self.nextthink = time + 0.1; +// } + +}; + + + + + + + +/*QUAKED noclass (0 0 0) (-8 -8 -8) (8 8 8) + +prints a warning message when spawned + +*/ + +void() noclass = + +{ + + dprint ("noclass spawned at"); + + dprint (vtos(self.origin)); + + dprint ("\n"); + + remove (self); + +}; + + + + + + +/* + +============ + +PlaceItem + + + +plants the object on the floor + +============ + +*/ + +void() PlaceItem = + +{ + + local float oldz; + + + + self.mdl = self.model; // so it can be restored on respawn + + self.flags = FL_ITEM; // make extra wide + + self.solid = SOLID_TRIGGER; + + self.movetype = MOVETYPE_TOSS; + + self.velocity = '0 0 0'; + + self.origin_z = self.origin_z + 6; + + oldz = self.origin_z; + + if (!droptofloor()) + + { + + dprint ("Bonus item fell out of level at "); + + dprint (vtos(self.origin)); + + dprint ("\n"); + + remove(self); + + return; + + } + + + if (self.x_flags & X_AMMO_ANIMATE) { + self.think = item_animate_think; + self.nextthink = time + 0.5; + } +// else if (self.healtype == 2) { +// self.think = superh_think; +// self.nextthink = time + 0.1; +// } + + +}; + + + +/* + +============ + +StartItem + + + +Sets the clipping size and plants the object on the floor + +============ + +*/ + +void() weapon_touch; +void() ammo_touch; + + +void() StartItem = + +{ + + if ((deathmatch == DM_SPECIAL_POWERS) && + ((self.touch == weapon_touch) || + (self.touch == ammo_touch))) { + remove(self); + return; + } + + self.nextthink = time + 0.2; // items start after other solids + + self.think = PlaceItem; + +}; + + +/* + +========================================================================= + + + +HEALTH BOX + + + +========================================================================= + +*/ + +// + +// T_Heal: add health to an entity, limiting health to max_health + +// "ignore" will ignore max_health limit + +// + +float (entity e, float healamt, float ignore) T_Heal = + +{ + + if (e.health <= 0) + + return 0; + + if ((!ignore) && (e.health >= other.max_health)) + + return 0; + + healamt = ceil(healamt); + + + + e.health = e.health + healamt; + + if ((!ignore) && (e.health >= other.max_health)) + + e.health = other.max_health; + + + + if (e.health > 250) + + e.health = 250; + + return 1; + +}; + + + + +/*QUAKED item_health (.3 .3 1) (0 0 0) (32 32 32) rotten megahealth + +Health box. Normally gives 25 points. + +Rotten box heals 5-10 points, + +megahealth will add 100 health, then + +rot you down to your maximum health limit, + +one point per second. + +*/ + + + +float H_ROTTEN = 1; + +float H_MEGA = 2; + +void() health_touch; + +void() item_megahealth_rot; + + + +void() item_health = + +{ + + self.touch = health_touch; + + + + if (self.spawnflags & H_ROTTEN) + + { + + precache_model ("progs/health1.mdl"); + + precache_sound("items/r_item1.wav"); + + setmodel (self, "progs/health1.mdl"); + + self.noise = "items/r_item1.wav"; + + self.healamount = 15; + + self.healtype = 0; + + self.x_flags = self.x_flags | X_AMMO_ANIMATE; + } + + else + + if (self.spawnflags & H_MEGA) + + { + + precache_model ("progs/superh.mdl"); + + precache_sound("items/r_item2.wav"); + + setmodel(self, "progs/superh.mdl"); + + self.noise = "items/r_item2.wav"; + + self.healamount = 100; + + self.healtype = 2; + + self.x_flags = self.x_flags | X_AMMO_ANIMATE; + } + + else + + { + + precache_model ("progs/health2.mdl"); + + precache_sound("items/health1.wav"); + + setmodel(self, "progs/health2.mdl"); + + self.noise = "items/health1.wav"; + + self.healamount = 25; + + self.healtype = 1; + + self.x_flags = self.x_flags | X_AMMO_ANIMATE; + } + + setsize (self, '0 0 0', '32 32 56'); + + StartItem (); + +}; + + + + +void() health_touch = + +{ + + local float amount; + + local string s; + + + + if (other.classname != "player") + + return; + + + + if (self.healtype == 2) // Megahealth? Ignore max_health... + + { + + if (other.health >= 250) + + return; + + if (!T_Heal(other, self.healamount, 1)) + + return; + + sprint(other, "You got the Supercharge!\n"); + + } + + else + + { + + if (!T_Heal(other, self.healamount, 0)) + + return; + + sprint(other, "You receive "); + + s = ftos(self.healamount); + + sprint(other, s); + + sprint(other, " health\n"); + } + + + + +// health touch sound + + sound(other, CHAN_ITEM, self.noise, 1, ATTN_NORM); + + + + stuffcmd (other, "bf\n"); + + + + self.model = string_null; + + self.solid = SOLID_NOT; + + self.nextthink = -1; + + + // Megahealth = rot down the player's super health + + if (self.healtype == 2) + + { + + other.items = other.items | IT_SUPERHEALTH; + + self.nextthink = time + 5; + + self.think = item_megahealth_rot; + + self.owner = other; + + } + + else + + { + + if (deathmatch != 2) // deathmatch 2 is the silly old rules + + { + + if (deathmatch) + + self.nextthink = time + 20; + + self.think = SUB_regen; + + } + + } + + + + activator = other; + + SUB_UseTargets(); // fire all targets / killtargets + +}; + + + +void() item_megahealth_rot = + +{ + + other = self.owner; + + + + if (other.health > other.max_health) + + { + + other.health = other.health - 1; + + self.nextthink = time + 1; + + return; + + } + + + +// it is possible for a player to die and respawn between rots, so don't + +// just blindly subtract the flag off + + other.items = other.items - (other.items & IT_SUPERHEALTH); + + + + if (deathmatch == 1) // deathmatch 2 is silly old rules + + { + + self.nextthink = time + 20; + + self.think = SUB_regen; + + } + +}; + + +/* + +=============================================================================== + + + +ARMOR + + + +=============================================================================== + +*/ + + + +void() armor_touch; + + + +void() armor_touch = + +{ + + local float type, value, bit; + + + + if (other.health <= 0) + + return; + + if (other.classname != "player") + + return; + + + + if (self.classname == "item_armor1") + + { + + type = 0.3; + + value = 100; + + bit = IT_ARMOR1; + + } + + if (self.classname == "item_armor2") + + { + + type = 0.6; + + value = 150; + + bit = IT_ARMOR2; + + } + + if (self.classname == "item_armorInv") + + { + + type = 0.8; + + value = 200; + + bit = IT_ARMOR3; + + } + + if (other.armortype*other.armorvalue >= type*value) + + return; + + + + other.armortype = type; + + other.armorvalue = value; + + other.items = other.items - (other.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) + bit; + + + + self.solid = SOLID_NOT; + + self.model = string_null; + + if (deathmatch == 1) + + self.nextthink = time + 20; + + self.think = SUB_regen; + + + + sprint(other, "You got armor\n"); + +// armor touch sound + + sound(other, CHAN_ITEM, "items/armor1.wav", 1, ATTN_NORM); + + stuffcmd (other, "bf\n"); + + + + activator = other; + + SUB_UseTargets(); // fire all targets / killtargets + +}; + + + + + +/*QUAKED item_armor1 (0 .5 .8) (-16 -16 0) (16 16 32) + +*/ + + + +void() item_armor1 = + +{ + + self.touch = armor_touch; + + precache_model ("progs/armor1.mdl"); + + setmodel (self, "progs/armor1.mdl"); + +// self.skin = 0; + + setsize (self, '-16 -16 0', '16 16 56'); + + StartItem (); + +}; + + + +/*QUAKED item_armor2 (0 .5 .8) (-16 -16 0) (16 16 32) + +*/ + + + +void() item_armor2 = + +{ + + self.touch = armor_touch; + + precache_model ("progs/armor2.mdl"); + + setmodel (self, "progs/armor2.mdl"); + +// self.skin = 1; + + setsize (self, '-16 -16 0', '16 16 56'); + + StartItem (); + +}; + + + +/*QUAKED item_armorInv (0 .5 .8) (-16 -16 0) (16 16 32) + +*/ + + + +void() item_armorInv = + +{ + + self.touch = armor_touch; + + precache_model ("progs/armor3.mdl"); + + setmodel (self, "progs/armor3.mdl"); + +// self.skin = 2; + + setsize (self, '-16 -16 0', '16 16 56'); + + StartItem (); + +}; + + + +/* + +=============================================================================== + + + +WEAPONS + + + +=============================================================================== + +*/ + + + +void() bound_other_ammo = + +{ + + if (other.ammo_shells > 150) + + other.ammo_shells = 150; + + if (other.ammo_nails > 200) + + other.ammo_nails = 200; + + if (other.ammo_rockets > 100) + + other.ammo_rockets = 100; + + if (other.ammo_cells > 100) + + other.ammo_cells = 100; + +}; + + + + + +float(float w) RankForWeapon = + +{ + + if (w == IT_LIGHTNING) + + return 1; + + if (w == IT_ROCKET_LAUNCHER) + + return 2; + + if (w == IT_SUPER_NAILGUN) + + return 3; + + if (w == IT_GRENADE_LAUNCHER) + + return 4; + + if (w == IT_SUPER_SHOTGUN) + + return 5; + + if (w == IT_NAILGUN) + + return 6; + + return 7; + +}; + + + +/* + +============= + +Deathmatch_Weapon + + + +Deathmatch weapon change rules for picking up a weapon + + + +.float ammo_shells, ammo_nails, ammo_rockets, ammo_cells; + +============= + +*/ + +void(float old, float new) Deathmatch_Weapon = + +{ + + local float or, nr; + + + +// change self.weapon if desired + + or = RankForWeapon (self.weapon); + + nr = RankForWeapon (new); + + if ( nr < or ) + + SetNewWeapon(new); +// self.weapon = new; + +}; + + + +/* + +=============================================================================== + + + +AMMO + + + +=============================================================================== + +*/ + +float() W_BestWeapon; + + +void() ammo_touch = + +{ + +local entity stemp; + +local float best; + + + if (other.classname != "player") + + return; + + if (other.health <= 0) + + return; + + + +// if the player was using his best weapon, change up to the new one if better +/* + stemp = self; + + self = other; + + best = W_BestWeapon(); + + self = stemp; +*/ + + + + +// shotgun + + if (self.weapon == 1) + + { + + if (other.ammo_shells >= 150) + + return; + + other.ammo_shells = other.ammo_shells + self.aflag * 3; + + } + + + +// spikes + + if (self.weapon == 2) + + { + + if (other.ammo_nails >= 200) + + return; + + other.ammo_nails = other.ammo_nails + self.aflag * 2; + + } + + + +// rockets + + if (self.weapon == 3) + + { + + if (other.ammo_rockets >= 100) + + return; + + other.ammo_rockets = other.ammo_rockets + self.aflag * 2; + + } + + + +// cells + + if (self.weapon == 4) + + { + + if (other.ammo_cells >= 100) + + return; + + other.ammo_cells = other.ammo_cells + self.aflag * 6; + + if (other.ammo_cells >= 200) + other.ammo_cells = 200; + } + + + + bound_other_ammo (); + + + + sprint (other, "You got the "); + + sprint (other, self.netname); + + sprint (other, "\n"); + +// ammo touch sound + + sound (other, CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM); + + stuffcmd (other, "bf\n"); + + + +// change to a better weapon if appropriate + + + + if ( other.weapon == best ) + + { + + stemp = self; + + self = other; + + best = W_BestWeapon(); + + if (best != self.weapon) + SetNewWeapon(best); + +// W_SetCurrentAmmo (); + + self = stemp; + + } + + + +// if changed current ammo, update it + + stemp = self; + + self = other; + + W_SetCurrentAmmo(); + + self = stemp; + + + +// remove it in single player, or setup for respawning in deathmatch + + self.model = string_null; + + self.solid = SOLID_NOT; + + self.nextthink = -1; + + if (deathmatch) + + self.nextthink = time + 30; + + self.think = SUB_regen; + + + + activator = other; + + SUB_UseTargets(); // fire all targets / killtargets + +}; + + + + + + + +float WEAPON_BIG2 = 1; + + + +/*QUAKED item_shells (0 .5 .8) (0 0 0) (32 32 32) big + +*/ + + + +void() item_shells = + +{ + + self.touch = ammo_touch; + + + + if (self.spawnflags & WEAPON_BIG2) + + { + + precache_model ("progs/shell2.mdl"); + setmodel (self, "progs/shell2.mdl"); + self.aflag = 40; + + } + + else + + { + + precache_model ("progs/shell1.mdl"); + setmodel (self, "progs/shell1.mdl"); + + self.aflag = 20; + + } + + self.weapon = 1; + + self.netname = "shells"; + + setsize (self, '0 0 0', '32 32 56'); + + StartItem (); + + self.x_flags = self.x_flags | X_AMMO_ANIMATE; + +}; + + + +/*QUAKED item_spikes (0 .5 .8) (0 0 0) (32 32 32) big + +*/ + + + +void() item_spikes = + +{ + + self.touch = ammo_touch; + + + + if (self.spawnflags & WEAPON_BIG2) + + { + + precache_model ("progs/fire2.mdl"); + setmodel (self, "progs/fire2.mdl"); + + self.aflag = 50; + + } + + else + + { + + precache_model ("progs/fire1.mdl"); + setmodel (self, "progs/fire1.mdl"); + + self.aflag = 25; + + } + + self.weapon = 2; + + self.netname = "fuel packs"; + + setsize (self, '0 0 0', '32 32 56'); + + StartItem (); + + self.x_flags = self.x_flags | X_AMMO_ANIMATE; + +}; + + + +/*QUAKED item_rockets (0 .5 .8) (0 0 0) (32 32 32) big + +*/ + + + +void() item_rockets = + +{ + + self.touch = ammo_touch; + + + + if (self.spawnflags & WEAPON_BIG2) + + { + + precache_model ("progs/rock2.mdl"); + setmodel (self, "progs/rock2.mdl"); + + self.aflag = 10; + + } + + else + + { + + precache_model ("progs/rock1.mdl"); + setmodel (self, "progs/rock1.mdl"); + + self.aflag = 5; + + } + + self.weapon = 3; + + self.netname = "rockets"; + + setsize (self, '0 0 0', '32 32 56'); + + StartItem (); + + self.x_flags = self.x_flags | X_AMMO_ANIMATE; + +}; + + + + + +/*QUAKED item_cells (0 .5 .8) (0 0 0) (32 32 32) big + +*/ + + + +void() item_cells = + +{ + + self.touch = ammo_touch; + + + + if (self.spawnflags & WEAPON_BIG2) + + { + + precache_model ("progs/cell2.mdl"); + setmodel (self, "progs/cell2.mdl"); + + self.aflag = 12; + + } + + else + + { + + precache_model ("progs/cell1.mdl"); + setmodel (self, "progs/cell1.mdl"); + + self.aflag = 6; + + } + + self.weapon = 4; + + self.netname = "cells"; + + setsize (self, '0 0 0', '32 32 56'); + + StartItem (); + + self.x_flags = self.x_flags | X_AMMO_ANIMATE; +}; + + + +/* + +============= + +weapon_touch + +============= + +*/ + + +void() weapon_touch = + +{ + + local float hadammo, best, new, old; + + local entity stemp; + + local float leave; + + + + if (!(other.flags & FL_CLIENT)) + + return; + + + +// if the player was using his best weapon, change up to the new one if better + + stemp = self; + + self = other; + + best = W_BestWeapon(); + + self = stemp; + + + + if (deathmatch == 2 || coop) + leave = 1; + else + leave = 0; + + if (self.classname == "weapon_nailgun") + + { + + if (leave && (other.items & IT_NAILGUN) ) + + return; + + hadammo = other.ammo_nails; + + new = IT_NAILGUN; + + other.ammo_nails = other.ammo_nails + 30; + + } + + else if (self.classname == "weapon_supernailgun") + + { + + if (leave && (other.items & IT_SUPER_NAILGUN) ) + + return; + + hadammo = other.ammo_rockets; + + new = IT_SUPER_NAILGUN; + + other.ammo_nails = other.ammo_nails + 30; + + } + + else if (self.classname == "weapon_supershotgun") + + { + + if (leave && (other.items & IT_SUPER_SHOTGUN) ) + + return; + + hadammo = other.ammo_rockets; + + new = IT_SUPER_SHOTGUN; + + other.ammo_shells = other.ammo_shells + 5; + + } + + else if (self.classname == "weapon_rocketlauncher") + + { + + if (leave && (other.items & IT_ROCKET_LAUNCHER) ) + + return; + + hadammo = other.ammo_rockets; + + new = IT_ROCKET_LAUNCHER; + + other.ammo_rockets = other.ammo_rockets + 5; + + } + + else if (self.classname == "weapon_grenadelauncher") + + { + + if (leave && (other.items & IT_GRENADE_LAUNCHER) ) + + return; + + hadammo = other.ammo_rockets; + + new = IT_GRENADE_LAUNCHER; + + other.ammo_rockets = other.ammo_rockets + 5; + + } + + else if (self.classname == "weapon_lightning") + + { + + if (leave && (other.items & IT_LIGHTNING) ) + + return; + + hadammo = other.ammo_rockets; + + new = IT_LIGHTNING; + + other.ammo_cells = other.ammo_cells + 15; + + } + + else + + objerror ("weapon_touch: unknown classname"); + + + + sprint (other, "You got the "); + + sprint (other, self.netname); + + sprint (other, "\n"); + +// weapon touch sound + + sound (other, CHAN_ITEM, "weapons/pkup.wav", 1, ATTN_NORM); + + stuffcmd (other, "bf\n"); + + + + bound_other_ammo (); + + + +// change to the weapon + + old = other.items; + + other.items = other.items | new; + + + + stemp = self; + + self = other; + + + + if (!deathmatch) + + SetNewWeapon(new); +// self.weapon = new; + + else + + Deathmatch_Weapon (old, new); + + +// W_SetCurrentAmmo(); + + + + self = stemp; + + + + if (leave) + + return; + + +// remove it in single player, or setup for respawning in deathmatch + + self.model = string_null; + + self.solid = SOLID_NOT; + + if (deathmatch == 1) + + self.nextthink = time + 30; + + self.think = SUB_regen; + + + + activator = other; + + SUB_UseTargets(); // fire all targets / killtargets + +}; + + + + + +/*QUAKED weapon_supershotgun (0 .5 .8) (-16 -16 0) (16 16 32) + +*/ + + + +void() weapon_supershotgun = + +{ +self.classname = "item_shells"; +item_shells(); +return; + + precache_model ("progs/g_shot.mdl"); + + setmodel (self, "progs/g_shot.mdl"); + + self.weapon = IT_SUPER_SHOTGUN; + + self.netname = "Double-barrelled Shotgun"; + + self.touch = weapon_touch; + + setsize (self, '-16 -16 0', '16 16 56'); + + StartItem (); + +}; + + + +/*QUAKED weapon_nailgun (0 .5 .8) (-16 -16 0) (16 16 32) + +*/ + + + +void() weapon_nailgun = + +{ +self.classname = "item_spikes"; +item_spikes(); +return; + + precache_model ("progs/g_nail.mdl"); + + setmodel (self, "progs/g_nail.mdl"); + + self.weapon = IT_NAILGUN; + + self.netname = "nailgun"; + + self.touch = weapon_touch; + + setsize (self, '-16 -16 0', '16 16 56'); + + StartItem (); + +}; + + + +/*QUAKED weapon_supernailgun (0 .5 .8) (-16 -16 0) (16 16 32) + +*/ + + + +void() weapon_supernailgun = + +{ +self.classname = "item_spikes"; +item_spikes(); +return; + + precache_model ("progs/g_nail2.mdl"); + + setmodel (self, "progs/g_nail2.mdl"); + + self.weapon = IT_SUPER_NAILGUN; + + self.netname = "Super Nailgun"; + + self.touch = weapon_touch; + + setsize (self, '-16 -16 0', '16 16 56'); + + StartItem (); + +}; + + + +/*QUAKED weapon_grenadelauncher (0 .5 .8) (-16 -16 0) (16 16 32) + +*/ + + + +void() weapon_grenadelauncher = + +{ +self.classname = "item_rockets"; +item_rockets(); +return; + + precache_model ("progs/g_rock.mdl"); + + setmodel (self, "progs/g_rock.mdl"); + + self.weapon = 3; + + self.netname = "Grenade Launcher"; + + self.touch = weapon_touch; + + setsize (self, '-16 -16 0', '16 16 56'); + + StartItem (); + +}; + + + +/*QUAKED weapon_rocketlauncher (0 .5 .8) (-16 -16 0) (16 16 32) + +*/ + + + +void() weapon_rocketlauncher = + +{ +self.classname = "item_rockets"; +item_rockets(); +return; + + precache_model ("progs/g_rock2.mdl"); + + setmodel (self, "progs/g_rock2.mdl"); + + self.weapon = 3; + + self.netname = "Rocket Launcher"; + + self.touch = weapon_touch; + + setsize (self, '-16 -16 0', '16 16 56'); + + StartItem (); + +}; + + + + + +/*QUAKED weapon_lightning (0 .5 .8) (-16 -16 0) (16 16 32) + +*/ + + + +void() weapon_lightning = + +{ +self.classname = "item_cells"; +item_cells(); +return; + + precache_model ("progs/g_light.mdl"); + + setmodel (self, "progs/g_light.mdl"); + + self.weapon = 3; + + self.netname = "Thunderbolt"; + + self.touch = weapon_touch; + + setsize (self, '-16 -16 0', '16 16 56'); + + StartItem (); + +}; + + + + +/*QUAKED item_weapon (0 .5 .8) (0 0 0) (32 32 32) shotgun rocket spikes big + +DO NOT USE THIS!!!! IT WILL BE REMOVED! + +*/ + + + +float WEAPON_SHOTGUN = 1; + +float WEAPON_ROCKET = 2; + +float WEAPON_SPIKES = 4; + +float WEAPON_BIG = 8; + +void() item_weapon = + +{ + + self.touch = ammo_touch; + + + + if (self.spawnflags & WEAPON_SHOTGUN) + + { + + if (self.spawnflags & WEAPON_BIG) + + { + + precache_model ("maps/b_shell1.bsp"); + + setmodel (self, "maps/b_shell1.bsp"); + + self.aflag = 40; + + } + + else + + { + + precache_model ("maps/b_shell0.bsp"); + + setmodel (self, "maps/b_shell0.bsp"); + + self.aflag = 20; + + } + + self.weapon = 1; + + self.netname = "shells"; + + } + + + + if (self.spawnflags & WEAPON_SPIKES) + + { + + if (self.spawnflags & WEAPON_BIG) + + { + + precache_model ("maps/b_nail1.bsp"); + + setmodel (self, "maps/b_nail1.bsp"); + + self.aflag = 40; + + } + + else + + { + + precache_model ("maps/b_nail0.bsp"); + + setmodel (self, "maps/b_nail0.bsp"); + + self.aflag = 20; + + } + + self.weapon = 2; + + self.netname = "spikes"; + + } + + + + if (self.spawnflags & WEAPON_ROCKET) + + { + + if (self.spawnflags & WEAPON_BIG) + + { + + precache_model ("maps/b_rock1.bsp"); + + setmodel (self, "maps/b_rock1.bsp"); + + self.aflag = 10; + + } + + else + + { + + precache_model ("maps/b_rock0.bsp"); + + setmodel (self, "maps/b_rock0.bsp"); + + self.aflag = 5; + + } + + self.weapon = 3; + + self.netname = "rockets"; + + } + + + + setsize (self, '0 0 0', '32 32 56'); + + StartItem (); + +}; + + + + + +/* + +=============================================================================== + + + +KEYS + + + +=============================================================================== + +*/ + + + +void() key_touch = + +{ + +local entity stemp; + +local float best; + + + + if (other.classname != "player") + + return; + + if (other.health <= 0) + + return; + + if (other.items & self.items) + + return; + + + + sprint (other, "You got the "); + + sprint (other, self.netname); + + sprint (other,"\n"); + + + + sound (other, CHAN_ITEM, self.noise, 1, ATTN_NORM); + + stuffcmd (other, "bf\n"); + + other.items = other.items | self.items; + + + + if (!coop) + + { + + self.solid = SOLID_NOT; + + self.model = string_null; + + } + + + + activator = other; + + SUB_UseTargets(); // fire all targets / killtargets + +}; + + + + + +void() key_setsounds = + +{ + + if (world.worldtype == 0) + + { + + precache_sound ("misc/medkey.wav"); + + self.noise = "misc/medkey.wav"; + + } + + if (world.worldtype == 1) + + { + + precache_sound ("misc/runekey.wav"); + + self.noise = "misc/runekey.wav"; + + } + + if (world.worldtype == 2) + + { + + precache_sound2 ("misc/basekey.wav"); + + self.noise = "misc/basekey.wav"; + + } + +}; + + +/*QUAKED item_key1 (0 .5 .8) (-16 -16 -24) (16 16 32) + +SILVER key + +In order for keys to work + +you MUST set your maps + +worldtype to one of the + +following: + +0: medieval + +1: metal + +2: base + +*/ + + + +void() item_key1 = + +{ + + if (world.worldtype == 0) + + { + + precache_model ("progs/w_s_key.mdl"); + + setmodel (self, "progs/w_s_key.mdl"); + + self.netname = "silver key"; + + } + + else if (world.worldtype == 1) + + { + + precache_model ("progs/m_s_key.mdl"); + + setmodel (self, "progs/m_s_key.mdl"); + + self.netname = "silver runekey"; + + } + + else if (world.worldtype == 2) + + { + + precache_model2 ("progs/b_s_key.mdl"); + + setmodel (self, "progs/b_s_key.mdl"); + + self.netname = "silver keycard"; + + } + + key_setsounds(); + + self.touch = key_touch; + + self.items = IT_KEY1; + + setsize (self, '-16 -16 -24', '16 16 32'); + + StartItem (); + +}; + + + +/*QUAKED item_key2 (0 .5 .8) (-16 -16 -24) (16 16 32) + +GOLD key + +In order for keys to work + +you MUST set your maps + +worldtype to one of the + +following: + +0: medieval + +1: metal + +2: base + +*/ + + + +void() item_key2 = + +{ + + if (world.worldtype == 0) + + { + + precache_model ("progs/w_g_key.mdl"); + + setmodel (self, "progs/w_g_key.mdl"); + + self.netname = "gold key"; + + } + + if (world.worldtype == 1) + + { + + precache_model ("progs/m_g_key.mdl"); + + setmodel (self, "progs/m_g_key.mdl"); + + self.netname = "gold runekey"; + + } + + if (world.worldtype == 2) + + { + + precache_model2 ("progs/b_g_key.mdl"); + + setmodel (self, "progs/b_g_key.mdl"); + + self.netname = "gold keycard"; + + } + + key_setsounds(); + + self.touch = key_touch; + + self.items = IT_KEY2; + + setsize (self, '-16 -16 -24', '16 16 32'); + + StartItem (); + +}; + + + + + + + +/* + +=============================================================================== + + + +END OF LEVEL RUNES + + + +=============================================================================== + +*/ + + + +void() sigil_touch = + +{ + +local entity stemp; + +local float best; + + + + if (other.classname != "player") + + return; + + if (other.health <= 0) + + return; + + + + centerprint (other, "You got the rune!"); + + + + sound (other, CHAN_ITEM, self.noise, 1, ATTN_NORM); + + stuffcmd (other, "bf\n"); + + self.solid = SOLID_NOT; + + self.model = string_null; + + serverflags = serverflags | (self.spawnflags & 15); + + self.classname = ""; // so rune doors won't find it + + + + activator = other; + + SUB_UseTargets(); // fire all targets / killtargets + +}; + + + + + +/*QUAKED item_sigil (0 .5 .8) (-16 -16 -24) (16 16 32) E1 E2 E3 E4 + +End of level sigil, pick up to end episode and return to jrstart. + +*/ + + + +void() item_sigil = + +{ + + if (!self.spawnflags) + + objerror ("no spawnflags"); + + + + precache_sound ("misc/runekey.wav"); + + self.noise = "misc/runekey.wav"; + + + + if (self.spawnflags & 1) + + { + + precache_model ("progs/end1.mdl"); + + setmodel (self, "progs/end1.mdl"); + + } + + if (self.spawnflags & 2) + + { + + precache_model2 ("progs/end2.mdl"); + + setmodel (self, "progs/end2.mdl"); + + } + + if (self.spawnflags & 4) + + { + + precache_model2 ("progs/end3.mdl"); + + setmodel (self, "progs/end3.mdl"); + + } + + if (self.spawnflags & 8) + + { + + precache_model2 ("progs/end4.mdl"); + + setmodel (self, "progs/end4.mdl"); + + } + + + + self.touch = sigil_touch; + + setsize (self, '-16 -16 -24', '16 16 32'); + + StartItem (); + +}; + + +/* + +=============================================================================== + + + +POWERUPS + + + +=============================================================================== + +*/ + + + +void() powerup_touch; + + + + + +void() powerup_touch = + +{ + +local entity stemp; + +local float best; + + + + if (other.classname != "player") + + return; + + if (other.health <= 0) + + return; + + + + sprint (other, "You got the "); + + sprint (other, self.netname); + + sprint (other,"\n"); + + + + if (deathmatch) + + { + + self.mdl = self.model; + + + + if ((self.classname == "item_artifact_invulnerability") || + + (self.classname == "item_artifact_invisibility")) + + self.nextthink = time + 60*5; + + else + + self.nextthink = time + 60; + + + + self.think = SUB_regen; + + } + + + + sound (other, CHAN_VOICE, self.noise, 1, ATTN_NORM); + + stuffcmd (other, "bf\n"); + + self.solid = SOLID_NOT; + + other.items = other.items | self.items; + + self.model = string_null; + + + +// do the apropriate action + + if (self.classname == "item_artifact_envirosuit") + + { + + other.rad_time = 1; + + other.radsuit_finished = time + 30; + + } + + + + if (self.classname == "item_artifact_invulnerability") + + { + + other.invincible_time = 1; + + other.invincible_finished = time + 30; + + } + + + + if (self.classname == "item_artifact_invisibility") + + { + + other.invisible_time = 1; + + other.invisible_finished = time + 30; + + } + + + + if (self.classname == "item_artifact_super_damage") + + { + + other.super_time = 1; + + other.super_damage_finished = time + 30; + + } + + + + activator = other; + + SUB_UseTargets(); // fire all targets / killtargets + +}; + + + + + + + +/*QUAKED item_artifact_invulnerability (0 .5 .8) (-16 -16 -24) (16 16 32) + +Player is invulnerable for 30 seconds + +*/ + +void() item_artifact_invulnerability = + +{ + + self.touch = powerup_touch; + + + + precache_model ("progs/invulner.mdl"); + + precache_sound ("items/protect.wav"); + + precache_sound ("items/protect2.wav"); + + precache_sound ("items/protect3.wav"); + + self.noise = "items/protect.wav"; + + setmodel (self, "progs/invulner.mdl"); + + self.netname = "Ruby of Cyttorak"; + + self.items = IT_INVULNERABILITY; + + setsize (self, '-16 -16 -24', '16 16 32'); + + StartItem (); + +}; + + + +/*QUAKED item_artifact_envirosuit (0 .5 .8) (-16 -16 -24) (16 16 32) + +Player takes no damage from water or slime for 30 seconds + +*/ + +void() item_artifact_envirosuit = + +{ + + self.touch = powerup_touch; + + + + precache_model ("progs/suit.mdl"); + + precache_sound ("items/suit.wav"); + + precache_sound ("items/suit2.wav"); + + self.noise = "items/suit.wav"; + + setmodel (self, "progs/suit.mdl"); + + self.netname = "Biosuit"; + + self.items = IT_SUIT; + + setsize (self, '-16 -16 -24', '16 16 32'); + + StartItem (); + +}; + + + + + +/*QUAKED item_artifact_invisibility (0 .5 .8) (-16 -16 -24) (16 16 32) + +Player is invisible for 30 seconds + +*/ + +void() item_artifact_invisibility = + +{ + + self.touch = powerup_touch; + + + + precache_model ("progs/invisibl.mdl"); + + precache_sound ("items/inv1.wav"); + + precache_sound ("items/inv2.wav"); + + precache_sound ("items/inv3.wav"); + + self.noise = "items/inv1.wav"; + + setmodel (self, "progs/invisibl.mdl"); + + self.netname = "Ring of Shadows"; + + self.items = IT_INVISIBILITY; + + setsize (self, '-16 -16 -24', '16 16 32'); + + StartItem (); + +}; + + + + + +/*QUAKED item_artifact_super_damage (0 .5 .8) (-16 -16 -24) (16 16 32) + +The next attack from the player will do 4x damage + +*/ + +void() item_artifact_super_damage = + +{ + + if (find(world, classname, "item_rapid_fire") == world) { + item_rapid_fire(); + return; + } + + self.touch = powerup_touch; + + + + precache_model ("progs/quaddama.mdl"); + + precache_sound ("items/damage.wav"); + + precache_sound ("items/damage2.wav"); + + precache_sound ("items/damage3.wav"); + + self.noise = "items/damage.wav"; + + setmodel (self, "progs/quaddama.mdl"); + + self.netname = "Superpower"; + + self.items = IT_QUAD; + + setsize (self, '-16 -16 -24', '16 16 32'); + + StartItem (); + +}; + + + + + + + +/* + +=============================================================================== + + + +PLAYER BACKPACKS + + + +=============================================================================== + +*/ + + + +void() BackpackTouch = + +{ + + local string s; + + local float best, old, new; + + local entity stemp; + + + + if (other.classname != "player") + + return; + + if (other.health <= 0) + + return; + + + +// if the player was using his best weapon, change up to the new one if better + + stemp = self; + + self = other; + + best = W_BestWeapon(); + + self = stemp; + + + +// change weapons + + other.ammo_shells = other.ammo_shells + self.ammo_shells; + + other.ammo_nails = other.ammo_nails + self.ammo_nails; + + other.ammo_rockets = other.ammo_rockets + self.ammo_rockets; + + other.ammo_cells = other.ammo_cells + self.ammo_cells; + + + + new = self.items; + + if (!new) + + new = other.weapon; + + old = other.items; + + other.items = other.items | new; + + + + bound_other_ammo (); + + + + sprint (other, "You get "); + + + + if (self.ammo_shells) + + { + + s = ftos(self.ammo_shells); + + sprint (other, s); + + sprint (other, " shells "); + + } + + if (self.ammo_nails) + + { + + s = ftos(self.ammo_nails); + + sprint (other, s); + + sprint (other, " nails "); + + } + + if (self.ammo_rockets) + + { + + s = ftos(self.ammo_rockets); + + sprint (other, s); + + sprint (other, " rockets "); + + } + + if (self.ammo_cells) + + { + + s = ftos(self.ammo_cells); + + sprint (other, s); + + sprint (other, " cells "); + + } + + + + sprint (other, "\n"); + +// backpack touch sound + + sound (other, CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM); + + stuffcmd (other, "bf\n"); + + + +// remove the backpack, change self to the player + + remove(self); + + self = other; + + + +// change to the weapon + + if (!deathmatch) + + SetNewWeapon(new); +// self.weapon = new; + + else + + Deathmatch_Weapon (old, new); + + + + W_SetCurrentAmmo (); + +}; + + + +/* + +=============== + +DropBackpack + +=============== + +*/ + +void() DropBackpack = + +{ + local entity item; + + + + if (!(self.ammo_shells + self.ammo_nails + self.ammo_rockets + self.ammo_cells)) + + return; // nothing in it + + + + item = spawn(); + + item.origin = self.origin - '0 0 24'; + + + + item.items = self.weapon; + + + + item.ammo_shells = self.ammo_shells; + + item.ammo_nails = self.ammo_nails; + + item.ammo_rockets = self.ammo_rockets; + + item.ammo_cells = self.ammo_cells; + + + + item.velocity_z = 300; + + item.velocity_x = -100 + (random() * 200); + + item.velocity_y = -100 + (random() * 200); + + + + item.flags = FL_ITEM; + + item.solid = SOLID_TRIGGER; + + item.movetype = MOVETYPE_TOSS; + + setmodel (item, "progs/backpack.mdl"); + + setsize (item, '-16 -16 0', '16 16 56'); + + item.touch = BackpackTouch; + + + + item.nextthink = time + 120; // remove after 2 minutes + + item.think = SUB_Remove; + +}; + + diff --git a/Iceman.c b/Iceman.c new file mode 100644 index 0000000..c288479 --- /dev/null +++ b/Iceman.c @@ -0,0 +1,792 @@ +/* +============================================================================== + +iceman + +============================================================================== +*/ + +$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9 +$frame stand10 stand11 stand12 stand13 + +$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 walk9 walk10 +$frame walk11 walk12 + +$frame run1 run2 run3 run4 run5 run6 + +$frame pain1 pain2 pain3 pain4 pain5 pain6 + +$frame paina1 paina2 paina3 paina4 paina5 paina6 paina7 paina8 paina9 paina10 +$frame paina11 paina12 paina13 paina14 paina15 paina16 paina17 paina18 paina19 paina20 +$frame paina21 paina22 paina23 paina24 paina25 paina26 paina27 paina28 paina29 + +$frame death1 death2 death3 death4 death5 death6 death7 death8 death9 death10 +$frame death11 death12 death13 death14 death15 death16 + +$frame rise1 rise2 rise3 rise4 rise5 rise6 rise7 rise8 rise9 +$frame rise10 rise11 rise12 rise13 rise14 rise15 rise16 rise17 rise18 rise19 + +$frame melt1 melt2 melt3 melt4 melt5 melt6 melt7 melt8 + +$frame satta1 satta2 satta3 satta4 satta5 satta6 satta7 satta8 +$frame satta9 satta10 satta11 satta12 + +$frame sattb1 sattb2 sattb3 sattb4 sattb5 sattb6 sattb7 sattb8 +$frame sattb9 sattb10 sattb11 sattb12 + +$frame xatta1 xatta2 xatta3 xatta4 xatta5 xatta6 xatta7 xatta8 +$frame xatta9 xatta10 xatta11 xatta12 + + +void() iceman_Laser_Touch = +{ + local vector org; + + if (other == self.owner) + return; // don't explode on owner + + if (pointcontents(self.origin) == CONTENT_SKY) + { + remove(self); + return; + } + + org = self.origin - 8*normalize(self.velocity); + + if (other.health) + { + SpawnBlood (org, self.velocity*0.2, 15); + T_Damage (other, self, self.owner, 10); + } + 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); + } + + remove(self); +}; + +void(vector org, vector vec) Ice_LaunchShard = +{ + local vector vec; + + + vec = normalize(vec); + + newmis = spawn(); + newmis.owner = self; + newmis.movetype = MOVETYPE_FLY; + newmis.solid = SOLID_BBOX; + newmis.effects = EF_DIMLIGHT; + + setmodel (newmis, "progs/iceshard.mdl"); + setsize (newmis, '0 0 0', '0 0 0'); + + setorigin (newmis, org); + + newmis.velocity = vec * 600; + newmis.angles = vectoangles(newmis.velocity); + + newmis.nextthink = time + 3; + newmis.think = SUB_Remove; + newmis.touch = iceman_Laser_Touch; +}; + + +void() ice_atkb1; +void() ice_xatk1; + +void() ShardTouch = +{ + local vector t1, t2, vec; + vec = self.old_velocity; + if (other == self.owner) + return; + if (other == world) + { + if (random() < 0.5) + sound(self, CHAN_AUTO, "weapons/tink1.wav", 1, 3); + + self.state = 0; + self.avelocity_x = random()*500; + self.avelocity_y = random()*500; + self.avelocity_z = random()*500; + + // give seom random upwards velocity + self.velocity_z = random() * 500 - 100; + } + + if (other.takedamage == DAMAGE_AIM) + { + spawn_touchblood (20); + T_Damage(other, self, self.owner, 3); + remove(self); + return; + } + + self.last_touch = time; + + if (self.velocity == '0 0 0') + remove(self); + +}; + +void(vector org, vector dir) spawn_shard = +{ + local entity missile, mpuff; + local vector vect; + + missile = spawn (); + missile.owner = self; + missile.movetype = MOVETYPE_BOUNCE; + missile.state = 1; + missile.solid = SOLID_SLIDEBOX; + missile.classname = "shard"; + +// set missile speed + + vect = normalize(dir); + + missile.velocity = vect * 1000; +// missile.velocity_z = 0; + + missile.angles = vectoangles(missile.velocity); + missile.old_velocity = missile.velocity; + + missile.touch = ShardTouch; + +// set missile duration +// missile.last_idle = time; + + missile.last_touch = 0; + missile.oldorigin = missile.origin; + missile.nextthink = time + 2.8; +// missile.think = GrenadeExplode; + missile.think = SUB_Remove; + + setmodel (missile, "progs/iceshard.mdl"); + setsize (missile, '0 0 0', '0 0 0'); + setorigin (missile, org); + self.old_velocity = self.velocity; +}; + + +void(float offs) iceman_fire = +{ + local vector org, vect, ang; + + ang = self.angles; + ang_y = anglemod(ang_y + offs); + + makevectors (ang); + vect = v_forward; + + org = self.origin + '0 0 12'; + + spawn_shard(org, vect); +}; + +void() iceballTouch = +{ + if (other == self.owner) + return; + + if (((other.classname == "player") || (coop && (other.flags & FL_MONSTER))) && (other.parallize_time < (time - 4))) + { + if (!deathmatch && (other.flags & FL_CLIENT)) + other.parallize_time = time + 2; + else + other.parallize_time = time + 3; + + other.x_flags = other.x_flags | X_PARALLIZED; + other.parallized_velocity = '0 0 0'; + + if (other.flags & FL_CLIENT) + { + centerprint(other, "You have been iced!"); + stuffcmd(other, "v_cshift 128 128 256 180\n"); + } + else + { + other.think = other.th_stand; + other.enemy = world; + } + + sound(other, CHAN_BODY, "generic/frozen1.wav", 1, ATTN_NORM); + + if (deathmatch) + other.skin = 1; + + remove(self); + return; + } + + remove(self); + +}; + +void(vector org, vector dir) spawn_iceball = +{ + local entity missile, mpuff; + local vector vect; + + missile = spawn (); + missile.owner = self; + missile.movetype = MOVETYPE_FLYMISSILE; + missile.solid = SOLID_BBOX; + missile.classname = "iceblast"; + +// set missile speed + + vect = normalize(dir); + + if (self.flags & FL_MONSTER) + missile.velocity = ProjectVelocity(1400, '0 0 0'); + else + missile.velocity = vect * 1400; + + missile.angles = vectoangles(missile.velocity); + missile.old_velocity = missile.velocity; + + missile.touch = iceballTouch; + +// set missile duration +// missile.last_idle = time; + + missile.last_touch = 0; + missile.oldorigin = missile.origin; + missile.nextthink = time + 2; +// missile.think = GrenadeExplode; + missile.think = SUB_Remove; + missile.avelocity_z = 300; + + setmodel (missile, "progs/iceblast.mdl"); + setsize (missile, '0 0 0', '0 0 0'); + setorigin (missile, org); +}; + + +void () ice_fire_iceball = +{ + local vector org,o2; + + makevectors (self.angles); + + org = self.origin + v_forward * 1 + '0 0 12'; + + o2 = self.enemy.origin + v_right * ((random() * 64) - 32); + spawn_iceball(org, o2 - self.origin); + +}; +//============================================================================ + +void() ice_stand1 =[ $stand1, ice_stand2 ] {ai_stand();}; +void() ice_stand2 =[ $stand2, ice_stand3 ] {ai_stand();}; +void() ice_stand3 =[ $stand3, ice_stand4 ] {ai_stand();}; +void() ice_stand4 =[ $stand4, ice_stand5 ] {ai_stand();}; +void() ice_stand5 =[ $stand5, ice_stand6 ] {ai_stand();}; +void() ice_stand6 =[ $stand6, ice_stand7 ] {ai_stand();}; +void() ice_stand7 =[ $stand7, ice_stand8 ] {ai_stand();}; +void() ice_stand8 =[ $stand8, ice_stand9 ] {ai_stand();}; +void() ice_stand9 =[ $stand9, ice_stand10 ] {ai_stand();}; +void() ice_stand10 =[ $stand10, ice_stand11 ] {ai_stand();}; +void() ice_stand11 =[ $stand11, ice_stand12 ] {ai_stand();}; +void() ice_stand12 =[ $stand12, ice_stand13 ] {ai_stand();}; +void() ice_stand13 =[ $stand13, ice_stand1 ] {ai_stand();}; + +void() ice_walk1 =[ $walk1 , ice_walk2 ] {ai_walk(7);}; +void() ice_walk2 =[ $walk2 , ice_walk3 ] {ai_walk(4);}; +void() ice_walk3 =[ $walk3 , ice_walk4 ] {ai_walk(4);}; +void() ice_walk4 =[ $walk4 , ice_walk5 ] {ai_walk(4);}; +void() ice_walk5 =[ $walk5 , ice_walk6 ] {ai_walk(4);}; +void() ice_walk6 =[ $walk6 , ice_walk7 ] {ai_walk(5);}; +void() ice_walk7 =[ $walk7 , ice_walk8 ] {ai_walk(5);}; +void() ice_walk8 =[ $walk8 , ice_walk9 ] {ai_walk(4);}; +void() ice_walk9 =[ $walk9 , ice_walk10 ] {ai_walk(7);}; +void() ice_walk10 =[ $walk10, ice_walk11 ] {ai_walk(4);}; +void() ice_walk11 =[ $walk11, ice_walk12 ] {ai_walk(0);}; +void() ice_walk12 =[ $walk12, ice_walk1 ] {ai_walk(5);}; + +void() ice_run1 =[ $run1 , ice_run2 ] { +ai_run(14);}; +void() ice_run2 =[ $run2 , ice_run3 ] {ai_run(16);}; +void() ice_run3 =[ $run3 , ice_run4 ] {ai_run(16);}; +void() ice_run4 =[ $run4 , ice_run5 ] {ai_run(16);}; +void() ice_run5 =[ $run5 , ice_run6 ] {ai_run(16);}; +void() ice_run6 =[ $run6 , ice_run1 ] {ai_run(16);}; + +void() ice_pain1 =[ $pain1, ice_pain2 ] {}; +void() ice_pain2 =[ $pain2, ice_pain3 ] {}; +void() ice_pain3 =[ $pain3, ice_pain4 ] {}; +void() ice_pain4 =[ $pain4, ice_pain5 ] {}; +void() ice_pain5 =[ $pain5, ice_pain6 ] {}; +void() ice_pain6 =[ $pain6, ice_run1 ] {}; + +void() ice_melt1 =[ $melt1, ice_melt2 ] {}; +void() ice_melt2 =[ $melt2, ice_melt3 ] {}; +void() ice_melt3 =[ $melt3, ice_melt4 ] {}; +void() ice_melt4 =[ $melt4, ice_melt5 ] {}; +void() ice_melt5 =[ $melt5, ice_melt6 ] {}; +void() ice_melt6 =[ $melt6, ice_melt7 ] {}; +void() ice_melt7 =[ $melt7, ice_melt8 ] {}; +void() ice_melt8 =[ $melt8, ice_melt8 ] { + + setmodel(self, "progs/puddle.mdl"); + self.skin = 0; + self.solid = SOLID_NOT; + self.deadflag = DEAD_DEAD; + self.think = SUB_Remove; + self.nextthink = time + 120 + random() * 30; +}; + +void() ice_paina1 =[ $paina1, ice_paina2 ] {}; +void() ice_paina2 =[ $paina2, ice_paina3 ] {}; +void() ice_paina3 =[ $paina3, ice_paina4 ] {}; +void() ice_paina4 =[ $paina4, ice_paina5 ] {}; +void() ice_paina5 =[ $paina5, ice_paina6 ] {}; +void() ice_paina6 =[ $paina6, ice_paina7 ] {}; +void() ice_paina7 =[ $paina7, ice_paina8 ] {}; +void() ice_paina8 =[ $paina8, ice_paina9 ] {}; +void() ice_paina9 =[ $paina9, ice_paina10 ] {}; +void() ice_paina10 =[ $paina10, ice_paina11 ] {}; +void() ice_paina11 =[ $paina11, ice_paina12 ] {}; +void() ice_paina12 =[ $paina12, ice_paina13 ] {}; +void() ice_paina13 =[ $paina12, ice_paina14 ] {}; +void() ice_paina14 =[ $paina12, ice_paina15 ] {}; +void() ice_paina15 =[ $paina13, ice_paina16 ] {}; +void() ice_paina16 =[ $paina14, ice_paina17 ] {}; +void() ice_paina17 =[ $paina15, ice_paina18 ] {}; +void() ice_paina18 =[ $paina16, ice_paina19 ] {}; +void() ice_paina19 =[ $paina16, ice_paina20 ] {}; +void() ice_paina20 =[ $paina16, ice_paina21 ] {}; +void() ice_paina21 =[ $paina17, ice_paina22 ] {}; +void() ice_paina22 =[ $paina18, ice_paina23 ] {}; +void() ice_paina23 =[ $paina19, ice_paina24 ] {}; +void() ice_paina24 =[ $paina20, ice_paina25 ] {}; +void() ice_paina25 =[ $paina21, ice_paina26 ] {}; +void() ice_paina26 =[ $paina22, ice_paina27 ] {}; +void() ice_paina27 =[ $paina23, ice_paina28 ] {}; +void() ice_paina28 =[ $paina24, ice_paina29 ] {}; +void() ice_paina29 =[ $paina25, ice_paina30 ] {}; +void() ice_paina30 =[ $paina26, ice_paina31 ] {}; +void() ice_paina31 =[ $paina27, ice_paina32 ] {}; +void() ice_paina32 =[ $paina28, ice_paina33 ] {}; +void() ice_paina33 =[ $paina29, ice_run1 ] {}; + + +//============================================================================ + + +void(entity attacker, float damage) ice_pain; +void() ice_atk1 =[ $satta1, ice_atk2 ] + { + ai_face(); + self.start_attack_health = self.health; + if (self.count) ai_forward(24); + }; + +void() ice_atk2 =[ $satta2, ice_atk3 ] + { + ai_face(); + iceman_fire(-15); + if (self.count) ai_forward(14); + }; + +void() ice_atk3 =[ $satta3, ice_atk4 ] + { + ai_face(); + iceman_fire(-9); + if (self.count) ai_forward(8); + }; + +void() ice_atk4 =[ $satta4, ice_atk5 ] + { + ai_face(); + iceman_fire(-3); + if (self.count) ai_forward(4); + }; + +void() ice_atk5 =[ $satta5, ice_atk6 ] + { + ai_face(); + iceman_fire(3); + if (self.count) ai_forward(2); + self.count = 0; + }; +void() ice_atk6 =[ $satta6, ice_atk7 ] {iceman_fire(9);}; +void() ice_atk7 =[ $satta7, ice_atk8 ] +{ +iceman_fire(15); +if (self.health < self.start_attack_health) + { + ice_pain(self.enemy, self.start_attack_health - self.health); + } +}; + +void() ice_atk8 =[ $satta8, ice_atk9 ] {}; +void() ice_atk9 =[ $satta9, ice_atk10 ] {}; +void() ice_atk10 =[ $satta10, ice_atk11 ] {}; +void() ice_atk11 =[ $satta11, ice_atk12 ] {}; +void() ice_atk12 =[ $satta12, ice_run1 ] {}; + +void() ice_xatk1 =[ $xatta1, ice_xatk2 ] + { + ai_face(); + self.start_attack_health = self.health; + if (self.count) ai_forward(24); + }; +void() ice_xatk2 =[ $xatta2, ice_xatk3 ] + { + ai_face(); + if (self.count) ai_forward(14); + }; +void() ice_xatk3 =[ $xatta3, ice_xatk4 ] + { + ai_face(); + if (self.count) ai_forward(8); + }; +void() ice_xatk4 =[ $xatta4, ice_xatk5 ] + { + ai_face(); + if (self.count) ai_forward(4); + }; +void() ice_xatk5 =[ $xatta5, ice_xatk6 ] + { + ai_face(); + if (self.count) ai_forward(2); + self.count = 0; + }; +void() ice_xatk6 =[ $xatta6, ice_xatk7 ] {ai_face();}; +void() ice_xatk7 =[ $xatta7, ice_xatk8 ] +{ai_face(); + if (self.health < self.start_attack_health) { + ice_pain(self.enemy, self.start_attack_health - self.health); + } +}; +void() ice_xatk8 =[ $xatta8, ice_xatk9 ] {ai_face();}; +void() ice_xatk9 =[ $xatta9, ice_xatk10 ] {ai_face();}; +void() ice_xatk10 =[ $xatta10, ice_xatk11 ] {ai_face();}; +void() ice_xatk11 =[ $xatta11, ice_xatk12 ] {ai_face();}; +void() ice_xatk12 =[ $xatta12, ice_run1 ] {ai_face(); +ice_fire_iceball(); +}; + + +void(entity attacker, float damage) ice_pain = +{ + local float r; + + if (self.enemy.weapon == IT_SUPER_NAILGUN) + return; + + r = random (); + if (self.pain_finished > time) + return; + + + + if (random()*40 > damage) + return; // didn't flinch + + MalePainSound(2); + + if ((random()*10 < 8) || ((damage > 50) && (random() < 0.5))) + { + self.pain_finished = time + 2; + ice_pain1 (); + } + else + { + self.pain_finished = time + 4; + ice_paina1 (); + } +}; + +void() ice_atkb1 =[ $sattb1, ice_atkb2 ] + { + ai_face(); + self.start_attack_health = self.health; + if (self.count) ai_forward(32); + }; + +void() ice_atkb2 =[ $sattb2, ice_atkb3 ] + { + ai_face(); + iceman_fire(15); + if (self.count) ai_forward(24); + }; + +void() ice_atkb3 =[ $sattb3, ice_atkb4 ] + { + ai_face(); + iceman_fire(9); + if (self.count) ai_forward(16); + }; + +void() ice_atkb4 =[ $sattb4, ice_atkb5 ] + { + ai_face(); + iceman_fire(3); + if (self.count) ai_forward(8); + }; +void() ice_atkb5 =[ $sattb5, ice_atkb6 ] +{ + ai_face(); +iceman_fire(-3); +if (self.count) ai_forward(8); +self.count = 0; +}; +void() ice_atkb6 =[ $sattb6, ice_atkb7 ] {iceman_fire(-9);}; +void() ice_atkb7 =[ $sattb7, ice_atkb8 ] { + if (self.health < self.start_attack_health) { + ice_pain(self.enemy, self.start_attack_health - self.health); + iceman_fire(-15); + } +}; +void() ice_atkb8 =[ $sattb8, ice_atkb9 ] {}; +void() ice_atkb9 =[ $sattb9, ice_atkb10 ] {}; +void() ice_atkb10 =[ $sattb10, ice_atkb11 ] {}; +void() ice_atkb11 =[ $sattb11, ice_atkb12 ] {}; +void() ice_atkb12 =[ $sattb12, ice_run1 ] {}; + +void() ice_attack = +{ + local float rnd; + + rnd = random(); + if (rnd < 0.3) + ice_atk1(); + else if (rnd < 0.6) + ice_atkb1(); + else if (self.last_special < (time - 8)) { + self.last_special = time; + ice_xatk1(); + } + else { + ice_atk1(); + } +}; + +//============================================================================ + +void () iceman_melt_go = +{ +self.deadflag = DEAD_DYING; +self.pain_finished = time + 99; +ice_melt1(); +}; + +void (entity e) iceman_melt = +{ + //e.health = 1; + e.think = iceman_melt_go; + e.nextthink = time + 0.1; + + // up the kill count, since he is now officially DEAD + killed_monsters = killed_monsters + 1; + WriteByte (MSG_ALL, SVC_KILLEDMONSTER); +}; + +void () ice_getup = +{ +self.takedamage = DAMAGE_AIM; +self.solid = SOLID_SLIDEBOX; +if (!walkmove(0,0)) + { + self.think = ice_getup; + self.solid = SOLID_NOT; + self.nextthink = time + 0.5; + return; + } +self.health = self.start_health; +ice_run1(); +}; + +void() ice_rise1 =[ $rise1, ice_rise2 ] +{ + self.solid = SOLID_SLIDEBOX; + if (!walkmove(0,0)) + { + self.think = ice_rise1; + self.solid = SOLID_NOT; + self.nextthink = time + 0.5; + return; + } +}; +void() ice_rise2 =[ $rise2, ice_rise3 ] {}; +void() ice_rise3 =[ $rise3, ice_rise4 ] {}; +void() ice_rise4 =[ $rise4, ice_rise5 ] {}; +void() ice_rise5 =[ $rise5, ice_rise6 ] {}; +void() ice_rise6 =[ $rise6, ice_rise7 ] {}; +void() ice_rise7 =[ $rise7, ice_rise8 ] {}; +void() ice_rise8 =[ $rise8, ice_rise9 ] {}; +void() ice_rise9 =[ $rise9, ice_rise10 ] {}; +void() ice_rise10 =[ $rise10, ice_rise11 ] {}; +void() ice_rise11 =[ $rise11, ice_rise12 ] {}; +void() ice_rise12 =[ $rise12, ice_rise13 ] {}; +void() ice_rise13 =[ $rise13, ice_rise14 ] {}; +void() ice_rise14 =[ $rise14, ice_rise15 ] {}; +void() ice_rise15 =[ $rise15, ice_rise16 ] {}; +void() ice_rise16 =[ $rise16, ice_rise17 ] {}; +void() ice_rise17 =[ $rise17, ice_rise18 ] {}; +void() ice_rise18 =[ $rise18, ice_rise19 ] {}; +void() ice_rise19 =[ $rise19, ice_getup ] {}; + +void() ice_die1 =[ $death1, ice_die2 ] {}; +void() ice_die2 =[ $death2, ice_die3 ] {}; +void() ice_die3 =[ $death3, ice_die4 ] {self.solid = SOLID_NOT;self.ammo_cells = 5;}; +void() ice_die4 =[ $death4, ice_die5 ] {}; +void() ice_die5 =[ $death5, ice_die6 ] {}; +void() ice_die6 =[ $death6, ice_die7 ] {}; +void() ice_die7 =[ $death7, ice_die8 ] {}; +void() ice_die8 =[ $death8, ice_die9 ] {}; +void() ice_die9 =[ $death9, ice_die10 ] {}; +void() ice_die10 =[ $death10, ice_die11 ] {}; +void() ice_die11 =[ $death11, ice_die12 ] {}; +void() ice_die12 =[ $death12, ice_die13 ] {}; +void() ice_die13 =[ $death13, ice_die14 ] {}; +void() ice_die14 =[ $death14, ice_die15 ] {}; +void() ice_die15 =[ $death15, ice_die16 ] {}; +void() ice_die16 =[ $death16, ice_die16 ] { + if (!(self.spawnflags & SPAWNFLAG_CLONE)) { + self.solid = SOLID_NOT; + self.think = ice_rise1; + self.takedamage = DAMAGE_NO; + self.nextthink = time + 20 + random() * 20; + } +}; + + +void() GibShardThink = +{ + if (self.velocity_z == 0) + remove(self); + else + self.nextthink = time + 0.2; +}; + +void(entity ent, float num_gibs) IcemanShardGib = +{ + local entity shard; + local float num; + local vector vect; + + if (damage_inflictor.classname == "guided_rocket") { + vect = normalize(damage_inflictor.velocity); + } + else { + vect = '0 0 0'; + } + + num = num_gibs; + + while (num > 0) { + shard = spawn(); + shard.movetype = MOVETYPE_BOUNCE; + + shard.velocity_x = random() * 150 - 75; + shard.velocity_y = random() * 150 - 75; + shard.velocity_z = 220 + random() * 150; + + shard.velocity = shard.velocity + vect * 200; + + shard.angles = shard.velocity; + shard.avelocity = '200 200 200'; + + setsize(shard, '0 0 0', '0 0 0'); + setmodel(shard, "progs/iceshard.mdl"); + setorigin(shard, ent.origin + shard.velocity * 0.1); + + shard.frame = 1; + + shard.think = GibShardThink; + shard.nextthink = time + 1; + + num = num - 1; + } +}; + +void() ice_die = +{ + // check for shard gib + if ((damage_inflictor.classname == "guided_rocket") || + (damage_inflictor.classname == "orb") || + (damage_inflictor.classname == "prox_missile") || + (damage_inflictor.classname == "proximity_ball")) { + IcemanShardGib(self, 15); + remove(self); + return; + } + + ice_die1 (); +}; + + +/*QUAKED monster_iceman (1 0 0) (-16 -16 -24) (16 16 40) Ambush + +*/ +void() monster_zombie = +{ + remove(self); +}; + +void() xmen_iceman = +{ + if ((deathmatch) || (self.spawnflags & 1)) + { + remove(self); + return; + } + precache_model2 ("progs/iceshard.mdl"); + precache_model2 ("progs/puddle.mdl"); + precache_model2 ("progs/iceblast.mdl"); + + precache_sound ("generic/frozen1.wav"); + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + + if ((self.map == "green") || (self.map == "")) + { + precache_model2("progs/ice1.mdl"); + setmodel (self, "progs/ice1.mdl"); + } + if (self.map == "blue") + { + precache_model2("progs/ice2.mdl"); + setmodel (self, "progs/ice2.mdl"); + } + if (self.map == "purple") + { + precache_model2("progs/ice3.mdl"); + setmodel (self, "progs/ice3.mdl"); + } + if (self.map == "brown") + { + precache_model2("progs/ice4.mdl"); + setmodel (self, "progs/ice4.mdl"); + } + if (self.map == "gold") + { + precache_model2("progs/ice5.mdl"); + setmodel (self, "progs/ice5.mdl"); + } + setsize (self, '-16 -16 -24', '16 16 40'); + self.health = 80 + cvar("skill") * 10; + + + self.th_stand = ice_stand1; + self.th_walk = ice_walk1; + self.th_run = ice_run1; + self.th_pain = ice_pain; + self.th_die = ice_die; + + self.th_missile = ice_attack; + self.count = 0; + + walkmonster_start(); +}; \ No newline at end of file diff --git a/LITENING.c b/LITENING.c new file mode 100644 index 0000000..688e941 --- /dev/null +++ b/LITENING.c @@ -0,0 +1,311 @@ +/* Begin Xmen +Lightning revision 2 +-cl2- + +Revisions: +2: Added some safeguards to make lightning work right + Fixed error messages + +Files involved: + +litening.qc (this file) + +How to implement in a map file: + +Place a info_lightning somewhere. Give it a style. +Place other lightning_waypoints all with the same style as startpoint. +String 'em together via 'target' and 'targetname' and voila... lightning. I hope. + +"style" : light style it affects (12-31) +"waitmin" : min. time between flashes (default = 3) +"waitmax" : max. time between flashes (default = 10) +"spawnflags" : if 1, bolt will randomly fork off at junctions (default = 0) +"distance" : how long the forks can be (default = 64) + Does looking at other people's code give you a headache, too? ;) +*/ + +void() lightning_trigger; + +float(entity e1, entity e2, float dam) DoABolt = +{ + +// traceline(e1.origin, e2.origin, FALSE, world); + + FillBetweenPoints(e1.origin, e2.origin, "progs/bolt3.mdl", '0 0 0', 0.2); + + if (trace_fraction < 1) { + if (world.model == "maps/x1end.bsp") { + T_RadiusDamage(e2, self, dam, world); + } + else if (trace_ent.classname == "player") + T_Damage(trace_ent, self, self, dam); + + return FALSE; + } + + return TRUE; +/* +local entity bolt; + +bolt = spawn(); +WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); +WriteByte (MSG_BROADCAST, TE_LIGHTNING1); +WriteEntity (MSG_BROADCAST, bolt); +WriteCoord (MSG_BROADCAST, e1.origin_x); +WriteCoord (MSG_BROADCAST, e1.origin_y); +WriteCoord (MSG_BROADCAST, e1.origin_z); +WriteCoord (MSG_BROADCAST, e2.origin_x); +WriteCoord (MSG_BROADCAST, e2.origin_y); +WriteCoord (MSG_BROADCAST, e2.origin_z); +bolt.think = SUB_Remove; +bolt.nextthink = time + 0.2; +*/ +}; + +// randomly create a fork + +void(entity e) forkbolt = +{ +local entity bolt; +local vector vec,org; + +if (random() * 10 < 4) return; + +bolt = spawn(); // spawn the bolt +vec = normalize(e.owner.origin - e.origin); +bolt.angles = vectoangles(vec); +makevectors(bolt.angles); +// do some complicated stuff to make sure the fork goes roughly the right +// direction, and doesnt look 'fake' (random in a controlled way?) +org = e.origin + v_forward*(random()*self.distance); +org = org + v_right*(random()*(self.distance*2)-self.distance); +org = org + v_up*(random()*(self.distance*2)-self.distance); +traceline(e.origin, org, TRUE, self); +WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); // make some lightning +WriteByte (MSG_BROADCAST, TE_LIGHTNING2); +WriteEntity (MSG_BROADCAST, bolt); +WriteCoord (MSG_BROADCAST, e.origin_x); +WriteCoord (MSG_BROADCAST, e.origin_y); +WriteCoord (MSG_BROADCAST, e.origin_z); +WriteCoord (MSG_BROADCAST, trace_endpos_x); +WriteCoord (MSG_BROADCAST, trace_endpos_y); +WriteCoord (MSG_BROADCAST, trace_endpos_z); +bolt.think = SUB_Remove; +bolt.nextthink = time + 0.5; +}; + +// O.k. enough freakin' lightning, already. +void() lightning_finish = +{ +if (self.style >= 12) + lightstyle(self.style, "a"); + +self.think = lightning_trigger; +if (self.targetname == "") + self.nextthink = time + self.waitmin + random() * (self.waitmax - self.waitmin); +}; + +float(entity parent, float lcount) randomRecursive = +{ + local float dist, rnd, longbolt, newcount, dosecond; + local vector dir; + local entity newchild; + + if (lcount > 4) + return lcount; + else + newcount = lcount + 1; + + dosecond = TRUE; + if (newcount == 1) // don't fork on first bolt + dosecond = FALSE; + + // create a left hand branch + rnd = random(); + dist = 128 * floor(1 + rnd * 4); + + dir = '0 0 -1'; + dir_x = (random() * 1) - 0.5; + dir_y = (random() * 1) - 0.5; + dir = normalize(dir); + + traceline(parent.origin, parent.origin + (dir * dist), FALSE, world); + + // create the new endpoint entity + newchild = spawn(); + newchild.classname = "lightning_bolt"; + newchild.owner = parent; + newchild.origin = trace_endpos; + newchild.think = SUB_Remove; + newchild.nextthink = time + 0.1; + + // draw the lightning bolt + DoABolt(parent, newchild, self.dmg); + + if (trace_fraction == 1) { // no intersection, do another bolt from the new child + newcount = randomRecursive(newchild, newcount); + } + + if (!dosecond) + return newcount; + + longbolt = FALSE; + if (random() < 0.3) + longbolt = TRUE; + + // do right hand branch + rnd = random(); + dist = 128 * floor(1 + (3 * longbolt) + rnd * 4); + + dir = '0 0 -1'; + dir_x = (random() * 1) - 0.5; + dir_y = (random() * 1) - 0.5; + dir = normalize(dir); + + traceline(parent.origin, parent.origin + (dir * dist), FALSE, world); + + // create the new endpoint entity + newchild = spawn(); + newchild.classname = "lightning_bolt"; + newchild.owner = parent; + newchild.origin = trace_endpos; + newchild.think = SUB_Remove; + newchild.nextthink = time + 0.1; + + // draw the lightning bolt + DoABolt(parent, newchild, self.dmg); + + if ((trace_fraction == 1) && (longbolt)) { // no intersection, do another bolt from the new child + newcount = randomRecursive(newchild, newcount); + } + + return newcount; +}; + +// Lets see some action, dammit! +void() lightning_trigger = +{ +local entity lpos; +local float done; + + // Sound should go here! + if (self.x_flags == 1) + sound (self, CHAN_AUTO, "ambience/elect.wav", 1, ATTN_NORM); + else + sound (self, CHAN_AUTO, "ambience/thunder1.wav", 0.7, ATTN_NORM); + +//return; + +if (!self.target) { + // randomize the lightning bolts + randomRecursive(self, 0); +} +else { + done = FALSE; + + traceline(self.origin, self.owner.origin, FALSE, world); + DoABolt(self,self.owner, self.dmg); + // inefficient, but since find() can only match string fields... + lpos = find(world, classname, "lightning_waypoint"); + while ((lpos != world) && !(done)) + { + if (lpos.style == self.style) + if (lpos.owner != world) + { + if (self.spawnflags & 1) forkbolt(lpos); + + traceline(lpos.origin, lpos.owner.origin, FALSE, world); + if (!DoABolt(lpos, lpos.owner, self.dmg)) + done = TRUE; + } + + lpos = find(lpos, classname, "lightning_waypoint"); + + } +} + +if (self.style >= 12) + lightstyle(self.style, "z"); +self.think = lightning_finish; +self.nextthink = time + 0.3; +}; + +// Lightning endpoint spawn + +void() lightning_ep_start = +{ +local entity shnook; + +if (self.target) + { + shnook = world; + do + { + shnook = find(shnook, targetname, self.target); + } while (shnook.classname != "lightning_waypoint"); + self.owner = shnook; + } +else self.owner = world; +}; + +void() lightning_waypoint = +{ +self.think = lightning_ep_start; +self.nextthink = time + 0.2; +}; + +// Lightning startpoint spawn + +void() lightning_sp_start = +{ +local entity shnook; + +if (self.target) { + shnook = world; + do + { + shnook = find(shnook, targetname, self.target); + } while (shnook.classname != "lightning_waypoint"); + // Safety measure in case map designer assigns lights target too... +} + +self.owner = shnook; +self.think = self.use = lightning_trigger; +if (self.targetname == "") + self.nextthink = time + self.waitmin + random() * (self.waitmax - self.waitmin); +}; + +void() info_lightning = +{ +if (deathmatch) { + remove(self); + return; +} + +//if (!self.style) +// objerror("info_lightning has no style"); +if (self.style && (self.style < 12)) + objerror("info_lightning has invalid style"); + +// Ridah: target no longer required, but used if present +//if (!self.target) +// objerror("info_lightning has no target"); + +if (!self.waitmin) self.waitmin = 3; +if (!self.waitmax) self.waitmax = 10; +if (!self.distance) self.distance = 64; +if (!self.dmg) self.dmg = 50; + +if (self.style >= 12) + lightstyle(self.style, "a"); + +if (self.x_flags == 1) + precache_sound ("ambience/elect.wav"); +else + precache_sound ("ambience/thunder1.wav"); + +self.think = lightning_sp_start; // wait for all our buddies to spawn +self.nextthink = time + 0.2; +}; + +// End Xmen diff --git a/MINES.c b/MINES.c new file mode 100644 index 0000000..7d208a0 --- /dev/null +++ b/MINES.c @@ -0,0 +1,80 @@ +/* Begin Xmen +Mines revision 1 +-cl2- + +Files involved: + +mines.qc (this file) +client.qc (obituaries) +tripwire.qc (explosion function) + +How to implement in a .map file: +Stick a 'mine' wherever you want a mine. Just like any other object or monster, +it should be placed just above the floor. + +Some optional fields are "dmg", the maximum damage the mine inflicts, +and "distance", the distance the mine scans. For a normal mine, just omit them. +*/ + +// Just waitin' for someone to start with us... ;) + +void() mine_scan = +{ +local entity shnook; + +shnook = findradius(self.origin, self.distance); +while(shnook) + { + if(shnook.health) // Should this only trip off for players? + { + self.think = BlowMeUp; + self.nextthink = time + 0.1; + return; + } + shnook = shnook.chain; + } +self.nextthink = time + 0.1; +}; + +// Mine start (mine has to start after world) + +void() mine_start = +{ +self.velocity = '0 0 0'; +self.movetype = MOVETYPE_TOSS; +if (!droptofloor()) + { + dprint ("Mine fell out of level at "); + dprint (vtos(self.origin)); + dprint ("\n"); + remove(self); + return; + } + + self.health = 1; + self.th_die = BlowMeUp; + self.takedamage = DAMAGE_YES; + +self.think = mine_scan; +self.nextthink = time + 0.1; +}; + +// Mine spawn + +void() mine = +{ +if (deathmatch) { + remove(self); + return; +} + +if (!self.distance) self.distance = 64; +if (!self.dmg) self.dmg = 120; +precache_model("progs/mine.mdl"); +setmodel(self, "progs/mine.mdl"); +setsize(self, '-4 -4 0', '4 4 4'); +self.think = mine_start; +self.nextthink = time + 0.2; // Put it in after world spawns (droptofloor) +}; + +// End Xmen diff --git a/MISC.c b/MISC.c new file mode 100644 index 0000000..4982daf --- /dev/null +++ b/MISC.c @@ -0,0 +1,747 @@ + +/*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4) +Used as a positional target for spotlights, etc. +*/ +void() info_null = +{ + remove(self); +}; + +/*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4) +Used as a positional target for lightning. +*/ +void() info_notnull = +{ +}; + +//============================================================================ + +float START_OFF = 1; + +void() light_use = +{ + if (self.spawnflags & START_OFF) + { + lightstyle(self.style, "m"); + self.spawnflags = self.spawnflags - START_OFF; + } + else + { + lightstyle(self.style, "a"); + self.spawnflags = self.spawnflags + START_OFF; + } +}; + +/*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) START_OFF +Non-displayed light. +Default light value is 300 +Default style is 0 +If targeted, it will toggle between on or off. +*/ +void() light = +{ + if (!self.targetname) + { // inert light + remove(self); + return; + } + + if (self.style >= 32) + { + self.use = light_use; + if (self.spawnflags & START_OFF) + lightstyle(self.style, "a"); + else + lightstyle(self.style, "m"); + } +}; + +/*QUAKED light_fluoro (0 1 0) (-8 -8 -8) (8 8 8) START_OFF +Non-displayed light. +Default light value is 300 +Default style is 0 +If targeted, it will toggle between on or off. +Makes steady fluorescent humming sound +*/ +void() light_fluoro = +{ + if (self.style >= 32) + { + self.use = light_use; + if (self.spawnflags & START_OFF) + lightstyle(self.style, "a"); + else + lightstyle(self.style, "m"); + } + + precache_sound ("ambience/fl_hum1.wav"); + ambientsound (self.origin, "ambience/fl_hum1.wav", 0.5, ATTN_STATIC); +}; + +/*QUAKED light_fluorospark (0 1 0) (-8 -8 -8) (8 8 8) +Non-displayed light. +Default light value is 300 +Default style is 10 +Makes sparking, broken fluorescent sound +*/ +void() light_fluorospark = +{ + if (!self.style) + self.style = 10; + + precache_sound ("ambience/buzz1.wav"); + ambientsound (self.origin, "ambience/buzz1.wav", 0.5, ATTN_STATIC); +}; + +/*QUAKED light_globe (0 1 0) (-8 -8 -8) (8 8 8) +Sphere globe light. +Default light value is 300 +Default style is 0 +*/ +void() light_globe = +{ + precache_model ("progs/s_light.spr"); + setmodel (self, "progs/s_light.spr"); + makestatic (self); +}; + +void() FireAmbient = +{ + precache_sound ("ambience/fire1.wav"); +// attenuate fast + ambientsound (self.origin, "ambience/fire1.wav", 0.2, 3); +}; + +/*QUAKED light_torch_small_walltorch (0 .5 0) (-10 -10 -20) (10 10 20) +Short wall torch +Default light value is 200 +Default style is 0 +*/ +void() light_torch_small_walltorch = +{ + precache_model ("progs/flame.mdl"); + setmodel (self, "progs/flame.mdl"); + FireAmbient (); + makestatic (self); +}; + +/*QUAKED light_flame_large_yellow (0 1 0) (-10 -10 -12) (12 12 18) +Large yellow flame ball +*/ +void() light_flame_large_yellow = +{ + precache_model ("progs/flame2.mdl"); + setmodel (self, "progs/flame2.mdl"); + self.frame = 1; + FireAmbient (); + makestatic (self); +}; + +/*QUAKED light_flame_small_yellow (0 1 0) (-8 -8 -8) (8 8 8) START_OFF +Small yellow flame ball +*/ +void() light_flame_small_yellow = +{ + precache_model ("progs/flame2.mdl"); + setmodel (self, "progs/flame2.mdl"); + FireAmbient (); + makestatic (self); +}; + +/*QUAKED light_flame_small_white (0 1 0) (-10 -10 -40) (10 10 40) START_OFF +Small white flame ball +*/ +void() light_flame_small_white = +{ + precache_model ("progs/flame2.mdl"); + setmodel (self, "progs/flame2.mdl"); + FireAmbient (); + makestatic (self); +}; + +//============================================================================ + + +/*QUAKED misc_fireball (0 .5 .8) (-8 -8 -8) (8 8 8) +Lava Balls +*/ + +void() fire_fly; +void() fire_touch; +void() misc_fireball = +{ +remove(self); +return; +/* + precache_model ("progs/lavaball.mdl"); + self.classname = "fireball"; + self.nextthink = time + (random() * 5); + self.think = fire_fly; + if (!self.speed) + self.speed == 1000; +*/ +}; + +void() fire_fly = +{ +local entity fireball; + + fireball = spawn(); + fireball.solid = SOLID_TRIGGER; + fireball.movetype = MOVETYPE_TOSS; + fireball.velocity = '0 0 1000'; + fireball.velocity_x = (random() * 100) - 50; + fireball.velocity_y = (random() * 100) - 50; + fireball.velocity_z = self.speed + (random() * 200); + fireball.classname = "fireball"; + setmodel (fireball, "progs/lavaball.mdl"); + setsize (fireball, '0 0 0', '0 0 0'); + setorigin (fireball, self.origin); + fireball.nextthink = time + 5; + fireball.think = SUB_Remove; + fireball.touch = fire_touch; + + self.nextthink = time + (random() * 5) + 3; + self.think = fire_fly; +}; + + +void() fire_touch = +{ + T_Damage (other, self, self, 20); + remove(self); +}; + +//============================================================================ + + +void() barrel_explode = +{ + self.takedamage = DAMAGE_NO; + self.classname = "explo_box"; + // did say self.owner + T_RadiusDamage (self, self, 160, world); + sound (self, CHAN_VOICE, "weapons/r_exp3.wav", 1, ATTN_NORM); + particle (self.origin, '0 0 0', 75, 255); + + self.origin_z = self.origin_z + 32; + BecomeExplosion (); +}; + + + +/*QUAKED misc_explobox (0 .5 .8) (0 0 0) (32 32 64) +TESTING THING +*/ + +void() misc_explobox = +{ + local float oldz; + + self.solid = SOLID_BBOX; + self.movetype = MOVETYPE_NONE; + precache_model ("maps/b_explob.bsp"); + setmodel (self, "maps/b_explob.bsp"); + precache_sound ("weapons/r_exp3.wav"); + self.health = 20; + self.th_die = barrel_explode; + self.takedamage = DAMAGE_AIM; + + self.origin_z = self.origin_z + 2; + oldz = self.origin_z; + droptofloor(); + if (oldz - self.origin_z > 250) + { + dprint ("item fell out of level at "); + dprint (vtos(self.origin)); + dprint ("\n"); + remove(self); + } +}; + + + + +/*QUAKED misc_explobox2 (0 .5 .8) (0 0 0) (32 32 64) +Smaller exploding box, REGISTERED ONLY +*/ + +void() misc_explobox2 = +{ + local float oldz; + + self.solid = SOLID_BBOX; + self.movetype = MOVETYPE_NONE; + precache_model2 ("maps/b_exbox2.bsp"); + setmodel (self, "maps/b_exbox2.bsp"); + precache_sound ("weapons/r_exp3.wav"); + self.health = 20; + self.th_die = barrel_explode; + self.takedamage = DAMAGE_AIM; + + self.origin_z = self.origin_z + 2; + oldz = self.origin_z; + droptofloor(); + if (oldz - self.origin_z > 250) + { + dprint ("item fell out of level at "); + dprint (vtos(self.origin)); + dprint ("\n"); + remove(self); + } +}; + +//============================================================================ + +float SPAWNFLAG_SUPERSPIKE = 1; +float SPAWNFLAG_LASER = 2; + + + +/*QUAKED trap_spikeshooter (0 .5 .8) (-8 -8 -8) (8 8 8) superspike laser +When triggered, fires a spike in the direction set in QuakeEd. +Laser is only for REGISTERED. +*/ + +void() trap_spikeshooter = +{ +remove(self); +}; + + +/*QUAKED trap_shooter (0 .5 .8) (-8 -8 -8) (8 8 8) superspike laser +Continuously fires spikes. +"wait" time between spike (1.0 default) +"nextthink" delay before firing first spike, so multiple shooters can be stagered. +*/ +void() trap_shooter = +{ +remove(self); +}; + + +//--------------------------------------------------------------- +// X-Men: Flame-thrower trap +//--------------------------------------------------------------- + +void() flamethrower_think = +{ + if (self.attack_finished < time) { + if (self.flags & FL_FLAMEON) { + // stop the flame, and set next think to start flame + self.flags = self.flags - (self.flags & FL_FLAMEON); + + if (self.classname == "trap_flamethrower_constant") { + self.nextthink = time + self.pausetime; + // set next firing finish time + self.attack_finished = self.nextthink + self.delay; + } + else { + self.nextthink = -1; + } + + // restart at starting angle + self.v_angle = self.angles; + return; + } + } + + if (self.flags & FL_FLAMEON) { + self.v_angle_y = self.v_angle_y + (self.speed * (time - self.last_flame)); + if (self.speed > 0) { + if ((self.v_angle_y - self.angles_y) > self.sway_range) { + self.speed = -1 * self.speed; + } + } + else { + if ((self.v_angle_y - self.angles_y) < (-1 * self.sway_range)) { + self.speed = -1 * self.speed; + } + } + } + else { + sound(self, CHAN_BODY, "weapons/f_start.wav", 1, ATTN_NORM); + } + + W_FireFlameThrower(); + self.flags = self.flags | FL_FLAMEON; + + self.nextthink = time + 0.05; +}; + +/* Trap Flamethrower, fires constantly, with a break every + "delay" seconds (default 1), pausing for + "pausetime" seconds (default = 1) before firing again. Also use + "sway_range" to set left/right swaying range (default 0), and + "speed" = degrees per second at which the flamethrower rotates (default 120)*/ +void() trap_flamethrower_constant = +{ + + // create flamethrower entities + self.flame_ent1 = spawn_flame_ent(); + self.flame_ent2 = spawn_flame_ent(); + self.flame_ent3 = spawn_flame_ent(); + + self.v_angle = self.angles; + if ((self.sway_range) && (self.speed == 0)) { + self.speed = 120; + } + + if (self.pausetime == 0) + self.pausetime = 1; + + if (self.delay == 0) + self.delay = 1; + + self.weapon = IT_SUPER_NAILGUN; // so monsters get torched + + self.nextthink = time + random() + self.wait; + self.think = flamethrower_think; +}; + +// **************************************** + +void() trap_flamethrower_use = +{ + // give 1 second of flames + self.attack_finished = time + 1; + if (self.nextthink == -1) // restart thinker + self.nextthink = time + 0.05; +}; + +// Triggerable verison of flamethrower +void() trap_flamethrower = +{ + + // create flamethrower entities + self.flame_ent1 = spawn_flame_ent(); + self.flame_ent2 = spawn_flame_ent(); + self.flame_ent3 = spawn_flame_ent(); + + self.v_angle = self.angles; + if ((self.sway_range) && (self.speed == 0)) { + self.speed = 120; + } + + self.weapon = IT_SUPER_NAILGUN; // so monsters get torched + + self.nextthink = -1; + self.think = flamethrower_think; + self.use = trap_flamethrower_use; +}; + +//--------------------------------------------------------------- + + +/* +=============================================================================== + + +=============================================================================== +*/ + + +void() make_bubbles; +void() bubble_remove; +void() bubble_bob; + +/*QUAKED air_bubbles (0 .5 .8) (-8 -8 -8) (8 8 8) + +testing air bubbles +*/ + +void() air_bubbles = + +{ + if (deathmatch) + { + remove (self); + return; + } + precache_model ("progs/s_bubble.spr"); + self.nextthink = time + 1; + self.think = make_bubbles; +}; + +void() make_bubbles = +{ +local entity bubble; + + bubble = spawn(); + setmodel (bubble, "progs/s_bubble.spr"); + setorigin (bubble, self.origin); + bubble.movetype = MOVETYPE_NOCLIP; + bubble.solid = SOLID_NOT; + bubble.velocity = '0 0 15'; + bubble.nextthink = time + 0.5; + bubble.think = bubble_bob; + bubble.touch = bubble_remove; + bubble.classname = "bubble"; + bubble.frame = 0; + bubble.cnt = 0; + setsize (bubble, '-8 -8 -8', '8 8 8'); + self.nextthink = time + random() + 0.5; + self.think = make_bubbles; +}; + +void() bubble_split = +{ +local entity bubble; + bubble = spawn(); + setmodel (bubble, "progs/s_bubble.spr"); + setorigin (bubble, self.origin); + bubble.movetype = MOVETYPE_NOCLIP; + bubble.solid = SOLID_NOT; + bubble.velocity = self.velocity; + bubble.nextthink = time + 0.5; + bubble.think = bubble_bob; + bubble.touch = bubble_remove; + bubble.classname = "bubble"; + bubble.frame = 1; + bubble.cnt = 10; + setsize (bubble, '-8 -8 -8', '8 8 8'); + self.frame = 1; + self.cnt = 10; + if (self.waterlevel != 3) + remove (self); +}; + +void() bubble_remove = +{ + if (other.classname == self.classname) + { +// dprint ("bump"); + return; + } + remove(self); +}; + +void() bubble_bob = +{ +local float rnd1, rnd2, rnd3; +local vector vtmp1, modi; + + self.cnt = self.cnt + 1; + if (self.cnt == 4) + bubble_split(); + if (self.cnt == 20) + remove(self); + + rnd1 = self.velocity_x + (-10 + (random() * 20)); + rnd2 = self.velocity_y + (-10 + (random() * 20)); + rnd3 = self.velocity_z + 10 + random() * 10; + + if (rnd1 > 10) + rnd1 = 5; + if (rnd1 < -10) + rnd1 = -5; + + if (rnd2 > 10) + rnd2 = 5; + if (rnd2 < -10) + rnd2 = -5; + + if (rnd3 < 10) + rnd3 = 15; + if (rnd3 > 30) + rnd3 = 25; + + self.velocity_x = rnd1; + self.velocity_y = rnd2; + self.velocity_z = rnd3; + + self.nextthink = time + 0.5; + self.think = bubble_bob; +}; + +/*~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~> +~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~<~>~*/ + +/*QUAKED viewthing (0 .5 .8) (-8 -8 -8) (8 8 8) + +Just for the debugging level. Don't use +*/ + +void() viewthing = + +{ + self.movetype = MOVETYPE_NONE; + self.solid = SOLID_NOT; + precache_model ("progs/player.mdl"); + setmodel (self, "progs/player.mdl"); +}; + + +/* +============================================================================== + +SIMPLE BMODELS + +============================================================================== +*/ + +void() func_wall_use = +{ // change to alternate textures + self.frame = 1 - self.frame; +}; + +/*QUAKED func_wall (0 .5 .8) ? +This is just a solid wall if not inhibitted +*/ +void() func_wall = +{ + self.angles = '0 0 0'; + self.movetype = MOVETYPE_PUSH; // so it doesn't get pushed by anything + self.solid = SOLID_BSP; + self.use = func_wall_use; + setmodel (self, self.model); +}; + + +/*QUAKED func_illusionary (0 .5 .8) ? +A simple entity that looks solid but lets you walk through it. +*/ +void() func_illusionary = + +{ + self.angles = '0 0 0'; + self.movetype = MOVETYPE_NONE; + self.solid = SOLID_NOT; + setmodel (self, self.model); + makestatic (); +}; + +/*QUAKED func_episodegate (0 .5 .8) ? E1 E2 E3 E4 +This bmodel will appear if the episode has allready been completed, so players can't reenter it. +*/ +void() func_episodegate = + +{ + if (!(serverflags & self.spawnflags)) + return; // can still enter episode + + self.angles = '0 0 0'; + self.movetype = MOVETYPE_PUSH; // so it doesn't get pushed by anything + self.solid = SOLID_BSP; + self.use = func_wall_use; + setmodel (self, self.model); +}; + +/*QUAKED func_bossgate (0 .5 .8) ? +This bmodel appears unless players have all of the episode sigils. +*/ +void() func_bossgate = + +{ + if ( (serverflags & 15) == 15) + return; // all episodes completed + self.angles = '0 0 0'; + self.movetype = MOVETYPE_PUSH; // so it doesn't get pushed by anything + self.solid = SOLID_BSP; + self.use = func_wall_use; + setmodel (self, self.model); +}; + +//============================================================================ +/*QUAKED ambient_suck_wind (0.3 0.1 0.6) (-10 -10 -8) (10 10 8) +*/ +void() ambient_suck_wind = +{ + precache_sound ("ambience/suck1.wav"); + ambientsound (self.origin, "ambience/suck1.wav", 1, ATTN_STATIC); +}; + +/*QUAKED ambient_drone (0.3 0.1 0.6) (-10 -10 -8) (10 10 8) +*/ +void() ambient_drone = +{ + precache_sound ("ambience/drone6.wav"); + ambientsound (self.origin, "ambience/drone6.wav", 0.5, ATTN_STATIC); +}; + +/*QUAKED ambient_flouro_buzz (0.3 0.1 0.6) (-10 -10 -8) (10 10 8) +*/ +void() ambient_flouro_buzz = +{ + precache_sound ("ambience/buzz1.wav"); + ambientsound (self.origin, "ambience/buzz1.wav", 1, ATTN_STATIC); +}; +/*QUAKED ambient_drip (0.3 0.1 0.6) (-10 -10 -8) (10 10 8) +*/ +void() ambient_drip = +{ + precache_sound ("ambience/drip1.wav"); + ambientsound (self.origin, "ambience/drip1.wav", 0.5, ATTN_STATIC); +}; +/*QUAKED ambient_comp_hum (0.3 0.1 0.6) (-10 -10 -8) (10 10 8) +*/ +void() ambient_comp_hum = +{ + precache_sound ("ambience/comp1.wav"); + ambientsound (self.origin, "ambience/comp1.wav", 1, ATTN_STATIC); +}; +/*QUAKED ambient_thunder (0.3 0.1 0.6) (-10 -10 -8) (10 10 8) +*/ +void() ambient_thunder = +{ + precache_sound ("ambience/thunder1.wav"); + ambientsound (self.origin, "ambience/thunder1.wav", 0.5, ATTN_STATIC); +}; +/*QUAKED ambient_light_buzz (0.3 0.1 0.6) (-10 -10 -8) (10 10 8) +*/ +void() ambient_light_buzz = +{ + precache_sound ("ambience/fl_hum1.wav"); + ambientsound (self.origin, "ambience/fl_hum1.wav", 0.5, ATTN_STATIC); +}; +/*QUAKED ambient_swamp1 (0.3 0.1 0.6) (-10 -10 -8) (10 10 8) +*/ +void() ambient_swamp1 = +{ + precache_sound ("ambience/swamp1.wav"); + ambientsound (self.origin, "ambience/swamp1.wav", 0.5, ATTN_STATIC); +}; +/*QUAKED ambient_swamp2 (0.3 0.1 0.6) (-10 -10 -8) (10 10 8) +*/ +void() ambient_swamp2 = +{ + precache_sound ("ambience/swamp2.wav"); + ambientsound (self.origin, "ambience/swamp2.wav", 0.5, ATTN_STATIC); +}; + +//============================================================================ + +void() noise_think = +{ + self.nextthink = time + 0.5; + sound (self, 1, "enforcer/enfire.wav", 1, ATTN_NORM); + sound (self, 2, "enforcer/enfstop.wav", 1, ATTN_NORM); + sound (self, 3, "enforcer/sight1.wav", 1, ATTN_NORM); + sound (self, 4, "enforcer/sight2.wav", 1, ATTN_NORM); + sound (self, 5, "enforcer/sight3.wav", 1, ATTN_NORM); + sound (self, 6, "enforcer/sight4.wav", 1, ATTN_NORM); + sound (self, 7, "enforcer/pain1.wav", 1, ATTN_NORM); +}; + +/*QUAKED misc_noisemaker (1 0.5 0) (-10 -10 -10) (10 10 10) + +For optimzation testing, starts a lot of sounds. +*/ + +void() misc_noisemaker = + +{ + precache_sound2 ("enforcer/enfire.wav"); + precache_sound2 ("enforcer/enfstop.wav"); + precache_sound2 ("enforcer/sight1.wav"); + precache_sound2 ("enforcer/sight2.wav"); + precache_sound2 ("enforcer/sight3.wav"); + precache_sound2 ("enforcer/sight4.wav"); + precache_sound2 ("enforcer/pain1.wav"); + precache_sound2 ("enforcer/pain2.wav"); + precache_sound2 ("enforcer/death1.wav"); + precache_sound2 ("enforcer/idle1.wav"); + + self.nextthink = time + 0.1 + random(); + self.think = noise_think; +}; diff --git a/MODELS.c b/MODELS.c new file mode 100644 index 0000000..70e273c --- /dev/null +++ b/MODELS.c @@ -0,0 +1,585 @@ + +/* +=============================================================================== + +WORLD WEAPONS + +=============================================================================== +*/ + +$modelname g_shot +$cd id1/models/g_shot +$origin 0 0 -24 +$flags 8 // client side rotate +$base base +$skin skin +$frame shot1 + + +$modelname g_nail +$cd id1/models/g_nail +$flags 8 // client side rotate +$origin 0 0 -24 +$base base +$skin skin +$frame shot1 + + +$modelname g_nail2 +$cd id1/models/g_nail2 +$flags 8 // client side rotate +$origin 0 0 -24 +$base base +$skin skin +$frame shot2 + + +$modelname g_rock +$cd id1/models/g_rock +$flags 8 // client side rotate +$origin 0 0 -24 +$base base +$skin skin +$frame shot1 + + +$modelname g_rock2 +$cd id1/models/g_rock2 +$flags 8 // client side rotate +$origin 0 0 -24 +$base base +$skin skin +$frame shot1 + +$modelname g_light +$cd id1/models/g_light +$flags 8 // client side rotate +$origin 0 0 -24 +$base base +$skin skin +$frame shot1 + +/* +=============================================================================== + +VIEW WEAPONS + +=============================================================================== +*/ + +$modelname v_axe +$cd id1/models/v_axe +$origin 0 5 54 +$base base +$skin skin +$frame frame1 frame2 frame3 frame4 frame5 frame6 frame7 frame8 frame9 + + +$modelname v_shot +$cd id1/models/v_shot +$origin 0 0 54 +$base base +$skin skin +$frame shot1 shot2 shot3 shot4 shot5 shot6 shot7 + + +$modelname v_shot2 +$cd id1/models/v_shot2 +$origin 0 0 56 +$base base +$skin skin +$frame shot1 shot2 shot3 shot4 shot5 shot6 shot7 + + +$modelname v_rock2 +$cd id1/models/v_rock2 +$origin 0 0 54 +$base base +$skin skin +$frame shot1 shot2 shot3 shot4 shot5 shot6 shot6 + + +$modelname v_rock +$cd id1/models/v_rock +$origin 0 0 54 +$base base +$skin skin +$frame shot1 shot2 shot3 shot4 shot5 shot6 shot7 + + +$modelname v_nail2 +$cd id1/models/v_nail2 +$origin 0 0 54 +$base base +$skin skin +$frame shot1 shot2 shot3 shot4 shot5 shot6 shot7 shot8 shot9 + + +$modelname v_nail +$cd id1/models/v_nail +$origin 0 0 54 +$base base +$skin skin +$frame shot1 shot2 shot3 shot4 shot5 shot6 shot7 shot8 shot9 + +$modelname v_light +$cd id1/models/v_light +$origin 0 0 54 +$base base +$skin skin +$frame shot1 shot2 shot3 shot4 shot5 + + +/* +=============================================================================== + +ITEMS + +=============================================================================== +*/ + +$modelname w_g_key +$cd id1/models/w_g_key +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname w_s_key +$cd id1/models/w_s_key +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname m_g_key +$cd id1/models/m_g_key +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname m_s_key +$cd id1/models/m_s_key +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname b_g_key +$cd id1/models/b_g_key +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname b_s_key +$cd id1/models/b_s_key +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + + +$modelname quaddama +$cd id1/models/quaddama +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname invisibl +$cd id1/models/invisibl +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname invulner +$flags 8 // client side rotate +$cd id1/models/invulner +$base base +$skin skin +$frame frame1 + +//modelname jetpack +//cd id1/models/jetpack +//flags 8 // client side rotate +//base base +//skin skin +//frame frame1 + +$modelname cube +$cd id1/models/cube +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname suit +$cd id1/models/suit +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname boots +$cd id1/models/boots +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname end1 +$cd id1/models/end1 +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname end2 +$cd id1/models/end2 +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname end3 +$cd id1/models/end3 +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + +$modelname end4 +$cd id1/models/end4 +$flags 8 // client side rotate +$base base +$skin skin +$frame frame1 + + +/* +=============================================================================== + +GIBS + +=============================================================================== +*/ + +$modelname gib1 +$cd id1/models/gib1 +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + + +// torso +$modelname gib2 +$cd id1/models/gib2 +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname gib3 +$cd id1/models/gib3 +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + + +// heads + +$modelname h_player +$cd id1/models/h_player +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname h_dog +$cd id1/models/h_dog +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname h_mega +$cd id1/models/h_mega +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname h_guard +$cd id1/models/h_guard +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname h_wizard +$cd id1/models/h_wizard +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname h_knight +$cd id1/models/h_knight +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname h_hellkn +$cd id1/models/h_hellkn +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname h_zombie +$cd id1/models/h_zombie +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname h_shams +$cd id1/models/h_shams +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname h_shal +$cd id1/models/h_shal +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname h_ogre +$cd id1/models/h_ogre +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname h_demon +$cd id1/models/h_demon +$flags 4 // EF_GIB +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +/* +=============================================================================== + +MISC + +=============================================================================== +*/ + +$modelname armor +$cd id1/models/armor +$flags 8 // client side rotate +$origin 0 0 -8 +$base base +$skin skin +$skin skin2 +$skin skin3 +$frame armor + +$modelname s_light // shambler lightning ready +$cd id1/models/s_light +$origin 0 0 24 +$base base +$skin skin +$frame frame1 frame2 frame3 + +$modelname bolt3 // lightning towar bolts +$cd id1/models/bolt2 +$origin 0 0 0 +$base base +$scale 4 +$skin skin +$frame light + +$modelname bolt2 +$cd id1/models/bolt2 +$origin 0 0 0 +$base base +$skin skin +$frame light + +$modelname bolt +$cd id1/models/bolt +$origin 0 0 0 +$base light +$skin light +$frame light + +$modelname laser +$cd id1/models/laser +$base base +$skin skin +$scale 2 +$frame frame1 + +$modelname flame // with torch +$cd id1/models/flame +$origin 0 0 12 +$base base +$skin skin +$framegroupstart +$frame flame1 0.1 +$frame flame2 0.1 +$frame flame3 0.1 +$frame flame4 0.1 +$frame flame5 0.1 +$frame flame6 0.1 +$framegroupend + +$modelname flame2 // standing flame, no torch +$cd id1/models/flame2 +$origin 0 0 12 +$base base +$skin skin +$framegroupstart +$frame flame1 0.1 +$frame flame2 0.1 +$frame flame3 0.1 +$frame flame4 0.1 +$frame flame5 0.1 +$frame flame6 0.1 +$framegroupend +$framegroupstart +$frame flameb1 +$frame flameb2 +$frame flameb3 +$frame flameb4 +$frame flameb5 +$frame flameb6 +$frame flameb7 +$frame flameb8 +$frame flameb9 +$frame flameb10 +$frame flameb11 +$framegroupend + +$modelname zom_gib +$cd id1/models/zom_gib +$flags 32 // EF_ZOMGIB +$base base +$skin skin +$frame frame1 + +$modelname eyes +$cd id1/models/eyes +$origin 0 0 -24 +$base base +$skin skin +$frame frame1 + +$modelname spike +$cd id1/models/spike +$origin 0 0 0 +$base spike +$skin skin +$frame spike + +$modelname s_spike +$cd id1/models/s_spike +$origin 0 0 0 +$base spike +$skin skin +$frame spike + +$modelname v_spike +$cd id1/models/v_spike +$flags 128 // EF_TRACER3 +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname w_spike +$cd id1/models/w_spike +$flags 16 // EF_TRACER +$origin 0 0 0 +$base base +$skin skin +$framegroupstart +$frame frame1 0.1 +$frame frame2 0.1 +$frame frame3 0.1 +$frame frame4 0.1 +$framegroupend + +$modelname k_spike +$cd id1/models/k_spike +$flags 64 // EF_TRACER2 +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname backpack +$cd id1/models/backpack +$flags 8 // EF_ROTATE +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname grenade +$cd id1/models/grenade2 +$flags 2 // EF_GRENADE +$origin 0 0 0 +$base base +$skin skin +$frame grenade + +$modelname missile +$cd id1/models/missile +$flags 1 // EF_ROCKET +$origin 0 0 0 +$base base +$skin skin +$frame missile + +$modelname lavaball +$cd id1/models/lavaball +$flags 1 // EF_ROCKET +$origin 0 0 0 +$base base +$skin skin +$frame frame1 + +$modelname teleport +$cd id1/models/teleport +$origin 0 0 24 +$base base +$skin skin +$frame frame1 + diff --git a/MONSTERS.c b/MONSTERS.c new file mode 100644 index 0000000..c7bbd3c --- /dev/null +++ b/MONSTERS.c @@ -0,0 +1,283 @@ +/* ALL MONSTERS SHOULD BE 1 0 0 IN COLOR */ + +// name =[framenum, nexttime, nextthink] {code} +// expands to: +// name () +// { +// self.frame=framenum; +// self.nextthink = time + nexttime; +// self.think = nextthink +// +// }; + + +/* +================ +monster_use + +Using a monster makes it angry at the current activator +================ +*/ +void() monster_use = +{ + if (self.enemy) + return; + if (self.health <= 0) + return; + if (activator.items & IT_INVISIBILITY) + return; + if (activator.flags & FL_NOTARGET) + return; + if (activator.classname != "player") + return; + +// delay reaction so if the monster is teleported, its sound is still +// heard + self.enemy = activator; + self.nextthink = time + 0.1; + self.think = FoundTarget; +}; + +/* +================ +monster_death_use + +When a mosnter dies, it fires all of its targets with the current +enemy as activator. +================ +*/ +void() monster_death_use = +{ + local entity ent, otemp, stemp; + +// fall to ground + if (self.flags & FL_FLY) + self.flags = self.flags - FL_FLY; + if (self.flags & FL_SWIM) + self.flags = self.flags - FL_SWIM; + + if (!self.target) + return; + + activator = self.enemy; + SUB_UseTargets (); +}; + + +//============================================================================ + +void() walkmonster_start_go = +{ +local string stemp; +local entity etemp; + + self.origin_z = self.origin_z + 1; // raise off floor a bit + droptofloor(); + + if (!walkmove(0,0) && (self.classname != "apocalypse_small")) + { + bprint(self.classname); + bprint (" in wall at: "); + bprint (vtos(self.origin)); + bprint ("\n"); + } + + // X-Men: increase strength of monsters depending on skill + if (self.health > 50) { + if ((self.health > 160) && (self.health < 500) && (self.classname != "xmen_wolverine")) + self.health = 160; + + self.health = self.health + (cvar("skill") - 2) * 10; + if (cvar("skill") > 1) + self.health = self.health + cvar("skill") + 15; + } + // end + + // X-Men: set starting health + self.start_health = self.health; + // end + + self.takedamage = DAMAGE_AIM; + + self.ideal_yaw = self.angles * '0 1 0'; + if (!self.yaw_speed) + self.yaw_speed = 20; + self.view_ofs = '0 0 25'; + self.use = monster_use; + + self.flags = self.flags | FL_MONSTER; + + if (self.target) + { + self.goalentity = self.movetarget = find(world, targetname, self.target); + self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); + if (!self.movetarget) + { + dprint ("Monster can't find target at "); + dprint (vtos(self.origin)); + dprint ("\n"); + } +// this used to be an objerror + if (self.movetarget.classname == "path_corner") + self.th_walk (); + else + self.pausetime = 99999999; + self.th_stand (); + } + else + { + self.pausetime = 99999999; + self.th_stand (); + } + +// spread think times so they don't all happen at same time + self.nextthink = self.nextthink + random()*0.5; +}; + + +void() walkmonster_start = +{ +// delay drop to floor to make sure all doors have been spawned +// spread think times so they don't all happen at same time + self.nextthink = self.nextthink + random()*0.5; + self.think = walkmonster_start_go; + + if ((self.classname != "xmen_wolverine") && (!(self.spawnflags & SPAWNFLAG_CLONE)) && (self.classname != "xmen_apocalypse") && (self.classname != "apocalypse_small") && (self.classname != "xmen_sinister")) + total_monsters = total_monsters + 1; +}; + + + +void() flymonster_start_go = +{ + + // X-Men: increase strength of monsters depending on skill + if (self.health > 50) { + if ((self.health > 160) && (self.health < 500) && (self.classname != "xmen_wolverine")) + self.health = 160; + + self.health = self.health + (cvar("skill") - 2) * 10; + if (cvar("skill") > 1) + self.health = self.health + cvar("skill") + 15; + } + // end + + // X-Men: set starting health + self.start_health = self.health; + // end + + self.takedamage = DAMAGE_AIM; + + self.ideal_yaw = self.angles * '0 1 0'; + if (!self.yaw_speed) + self.yaw_speed = 10; + self.view_ofs = '0 0 25'; + self.use = monster_use; + + self.flags = self.flags | FL_FLY; + self.flags = self.flags | FL_MONSTER; + + if (!walkmove(0,0)) + { + dprint ("flymonster in wall at: "); + dprint (vtos(self.origin)); + dprint ("\n"); + } + + if (self.target) + { + self.goalentity = self.movetarget = find(world, targetname, self.target); + if (!self.movetarget) + { + dprint ("Monster can't find target at "); + dprint (vtos(self.origin)); + dprint ("\n"); + } +// this used to be an objerror + if (self.movetarget.classname == "path_corner") + self.th_walk (); + else + self.pausetime = 99999999; + self.th_stand (); + } + else + { + self.pausetime = 99999999; + self.th_stand (); + } +}; + +void() flymonster_start = +{ +// spread think times so they don't all happen at same time + self.nextthink = self.nextthink + random()*0.5; + self.think = flymonster_start_go; + + if ((self.classname != "xmen_wolverine") && (!(self.spawnflags & SPAWNFLAG_CLONE))) + total_monsters = total_monsters + 1; +}; + + +void() swimmonster_start_go = +{ + if (deathmatch) + { + remove(self); + return; + } + + + // X-Men: increase strength of monsters (this is a hack) + if (self.health > 50) + self.health = self.health + 40; + // end + + // X-Men: set starting health + self.start_health = self.health; + // end + + self.takedamage = DAMAGE_AIM; + + self.ideal_yaw = self.angles * '0 1 0'; + if (!self.yaw_speed) + self.yaw_speed = 10; + self.view_ofs = '0 0 10'; + self.use = monster_use; + + self.flags = self.flags | FL_SWIM; + self.flags = self.flags | FL_MONSTER; + + if (self.target) + { + self.goalentity = self.movetarget = find(world, targetname, self.target); + if (!self.movetarget) + { + dprint ("Monster can't find target at "); + dprint (vtos(self.origin)); + dprint ("\n"); + } +// this used to be an objerror + self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); + self.th_walk (); + } + else + { + self.pausetime = 99999999; + self.th_stand (); + } + +// spread think times so they don't all happen at same time + self.nextthink = self.nextthink + random()*0.5; +}; + +void() swimmonster_start = +{ +// spread think times so they don't all happen at same time + self.nextthink = self.nextthink + random()*0.5; + self.think = swimmonster_start_go; + + if ((self.classname != "xmen_wolverine") && (!(self.spawnflags & SPAWNFLAG_CLONE))) + total_monsters = total_monsters + 1; +}; + + diff --git a/PARTICLE.c b/PARTICLE.c new file mode 100644 index 0000000..f6b679d --- /dev/null +++ b/PARTICLE.c @@ -0,0 +1,50 @@ +/* Begin Xmen +Particle Throwers revision 2 +-cl2- + +Additions: +r2: Cleaned up the code + +Files involved: +particle.qc (this file) + +How to implement in a .map file: +Stick a 'misc_particles' wherever you want the particles to come from. +set "angles" to whatever VECTOR you want the particles to shoot at, and +"count" to how many particles to shoot. (for density) +Another neat thing I figured I'd add (why not?) was you can also specify +"wait" if you want there to be a wait in between 'particle spurts'. If no +wait is specified, it will be a continuous stream. + +"style" is the color index # of the particles thrown. + +If anyone has a need for a random "wait" period (maybe for electrical +sparks or something?) let me know and I can throw it in very easily. +Same goes for toggle-able particle throwers. Just say the werd. + +Remember self.angles is actually a VECTOR, which means "180 0 0" shoots +particles at 180 units/sec to the right. +Vector axes are x,y,z, in that order. If the player's yaw is 90 degrees, +x is left/right, y is forward/back, z is up/down. +*/ + +// Throw some particles around + +void() particle_throw = +{ +particle(self.origin, self.angles, self.style, self.count); +self.nextthink = time + self.wait; +}; + +// particle init.. duh. + +void() misc_particles = +{ +if (!self.wait) self.wait = 0.1; +if (!self.style) self.style = 1; +if (!self.count) self.count = 50; // nice round default number. +self.think = particle_throw; +self.nextthink = time + self.wait; +}; + +// End Xmen diff --git a/PLATS.c b/PLATS.c new file mode 100644 index 0000000..3f10b57 --- /dev/null +++ b/PLATS.c @@ -0,0 +1,368 @@ + + +void() plat_center_touch; +void() plat_outside_touch; +void() plat_trigger_use; +void() plat_go_up; +void() plat_go_down; +void() plat_crush; +float PLAT_LOW_TRIGGER = 1; + +void() plat_spawn_inside_trigger = +{ + local entity trigger; + local vector tmin, tmax; + +// +// middle trigger +// + trigger = spawn(); + trigger.touch = plat_center_touch; + trigger.movetype = MOVETYPE_NONE; + trigger.solid = SOLID_TRIGGER; + trigger.enemy = self; + + tmin = self.mins + '25 25 0'; + tmax = self.maxs - '25 25 -8'; + tmin_z = tmax_z - (self.pos1_z - self.pos2_z + 8); + if (self.spawnflags & PLAT_LOW_TRIGGER) + tmax_z = tmin_z + 8; + + if (self.size_x <= 50) + { + tmin_x = (self.mins_x + self.maxs_x) / 2; + tmax_x = tmin_x + 1; + } + if (self.size_y <= 50) + { + tmin_y = (self.mins_y + self.maxs_y) / 2; + tmax_y = tmin_y + 1; + } + + setsize (trigger, tmin, tmax); +}; + +void() plat_hit_top = +{ + sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); + self.state = STATE_TOP; + self.think = plat_go_down; + self.nextthink = self.ltime + 3; +}; + +void() plat_hit_bottom = +{ + sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); + self.state = STATE_BOTTOM; +}; + +void() plat_go_down = +{ + sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); + self.state = STATE_DOWN; + SUB_CalcMove (self.pos2, self.speed, plat_hit_bottom); +}; + +void() plat_go_up = +{ + sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); + self.state = STATE_UP; + SUB_CalcMove (self.pos1, self.speed, plat_hit_top); +}; + +void() plat_center_touch = +{ + if (other.classname != "player") + return; + + if (other.health <= 0) + return; + + self = self.enemy; + if (self.state == STATE_BOTTOM) + plat_go_up (); + else if (self.state == STATE_TOP) + self.nextthink = self.ltime + 1; // delay going down +}; + +void() plat_outside_touch = +{ + if (other.classname != "player") + return; + + if (other.health <= 0) + return; + +//dprint ("plat_outside_touch\n"); + self = self.enemy; + if (self.state == STATE_TOP) + plat_go_down (); +}; + +void() plat_trigger_use = +{ + if (self.think) + return; // allready activated + plat_go_down(); +}; + + +void() plat_crush = +{ +//dprint ("plat_crush\n"); + + T_Damage (other, self, self, 1); + + if (self.state == STATE_UP) + plat_go_down (); + else if (self.state == STATE_DOWN) + plat_go_up (); + else + objerror ("plat_crush: bad self.state\n"); +}; + +void() plat_use = +{ + self.use = SUB_Null; + if (self.state != STATE_UP) + objerror ("plat_use: not in up state"); + plat_go_down(); +}; + + +/*QUAKED func_plat (0 .5 .8) ? PLAT_LOW_TRIGGER +speed default 150 + +Plats are always drawn in the extended position, so they will light correctly. + +If the plat is the target of another trigger or button, it will start out disabled in the extended position until it is trigger, when it will lower and become a normal plat. + +If the "height" key is set, that will determine the amount the plat moves, instead of being implicitly determined by the model's height. +Set "sounds" to one of the following: +1) base fast +2) chain slow +*/ + + +void() func_plat = + +{ +local entity t; + + if (!self.t_length) + self.t_length = 80; + if (!self.t_width) + self.t_width = 10; + + if (self.sounds == 0) + self.sounds = 2; +// FIX THIS TO LOAD A GENERIC PLAT SOUND + if (self.sounds == 1) + { + precache_sound ("plats/plat1.wav"); + precache_sound ("plats/plat2.wav"); + self.noise = "plats/plat1.wav"; + self.noise1 = "plats/plat2.wav"; + } + else //if (self.sounds == 2) + { + precache_sound ("plats/medplat1.wav"); + precache_sound ("plats/medplat2.wav"); + self.noise = "plats/medplat1.wav"; + self.noise1 = "plats/medplat2.wav"; + } + + + self.mangle = self.angles; + self.angles = '0 0 0'; + + self.classname = "plat"; + self.solid = SOLID_BSP; + self.movetype = MOVETYPE_PUSH; + setorigin (self, self.origin); + setmodel (self, self.model); + setsize (self, self.mins , self.maxs); + + self.blocked = plat_crush; + if (!self.speed) + self.speed = 150; + +// pos1 is the top position, pos2 is the bottom + self.pos1 = self.origin; + self.pos2 = self.origin; + if (self.height) + self.pos2_z = self.origin_z - self.height; + else + self.pos2_z = self.origin_z - self.size_z + 8; + + self.use = plat_trigger_use; + + plat_spawn_inside_trigger (); // the "start moving" trigger + + if (self.targetname) + { + self.state = STATE_UP; + self.use = plat_use; + } + else + { + setorigin (self, self.pos2); + self.state = STATE_BOTTOM; + } +}; + +//============================================================================ + +void() train_next; +void() func_train_find; + +void() train_blocked = +{ + if (time < self.attack_finished) + return; + self.attack_finished = time + 0.5; + T_Damage (other, self, self, self.dmg); +}; +void() train_use = +{ + if (self.think != func_train_find) + return; // already activated + + train_next(); +}; + +void() train_wait = +{ + if (self.wait) + { + self.nextthink = self.ltime + self.wait; + sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); + } + else + self.nextthink = self.ltime + 0.1; + + if (self.wait == -1) { + self.think = func_train_find; + return; + } + + self.think = train_next; +}; + +void() train_next = +{ + local entity targ; + + targ = find (world, targetname, self.target); + self.target = targ.target; + if (!self.target) + objerror ("train_next: no next target"); + if (targ.wait) + self.wait = targ.wait; + else + self.wait = 0; + sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); + SUB_CalcMove (targ.origin - self.mins, self.speed, train_wait); +}; + +void() func_train_find = + +{ + local entity targ; + + targ = find (world, targetname, self.target); + self.target = targ.target; + setorigin (self, targ.origin - self.mins); + if (!self.targetname) + { // not triggered, so start immediately + self.nextthink = self.ltime + 0.1; + self.think = train_next; + } +}; + +/*QUAKED func_train (0 .5 .8) ? +Trains are moving platforms that players can ride. +The targets origin specifies the min point of the train at each corner. +The train spawns at the first target it is pointing at. +If the train is the target of a button or trigger, it will not begin moving until activated. +speed default 100 +dmg default 2 +sounds +1) ratchet metal + +*/ +void() func_train = +{ + if (!self.speed) + self.speed = 100; + if (!self.target) + objerror ("func_train without a target"); + if (!self.dmg) + self.dmg = 2; + + if (self.sounds == 0) + { + self.noise = ("misc/null.wav"); + precache_sound ("misc/null.wav"); + self.noise1 = ("misc/null.wav"); + precache_sound ("misc/null.wav"); + } + + if (self.sounds == 1) + { + self.noise = ("plats/train2.wav"); + precache_sound ("plats/train2.wav"); + self.noise1 = ("plats/train1.wav"); + precache_sound ("plats/train1.wav"); + } + + self.cnt = 1; + self.solid = SOLID_BSP; + self.movetype = MOVETYPE_PUSH; + self.blocked = train_blocked; + self.use = train_use; + self.classname = "train"; + + setmodel (self, self.model); + setsize (self, self.mins , self.maxs); + setorigin (self, self.origin); + +// start trains on the second frame, to make sure their targets have had +// a chance to spawn + self.nextthink = self.ltime + 0.1; + self.think = func_train_find; +}; + +/*QUAKED misc_teleporttrain (0 .5 .8) (-8 -8 -8) (8 8 8) +This is used for the final bos +*/ +void() misc_teleporttrain = +{ + if (!self.speed) + self.speed = 100; + if (!self.target) + objerror ("func_train without a target"); + + self.cnt = 1; + self.solid = SOLID_NOT; + self.movetype = MOVETYPE_PUSH; + self.blocked = train_blocked; + self.use = train_use; + self.avelocity = '100 200 300'; + + self.noise = ("misc/null.wav"); + precache_sound ("misc/null.wav"); + self.noise1 = ("misc/null.wav"); + precache_sound ("misc/null.wav"); + + precache_model2 ("progs/teleport.mdl"); + setmodel (self, "progs/teleport.mdl"); + setsize (self, self.mins , self.maxs); + setorigin (self, self.origin); + +// start trains on the second frame, to make sure their targets have had +// a chance to spawn + self.nextthink = self.ltime + 0.1; + self.think = func_train_find; +}; + diff --git a/PLAYER.c b/PLAYER.c new file mode 100644 index 0000000..7e31a62 --- /dev/null +++ b/PLAYER.c @@ -0,0 +1,1181 @@ + +void() bubble_bob; + +/* +============================================================================== + +PLAYER + +============================================================================== +*/ + +$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9 +$frame stand10 stand11 stand12 stand13 + +$frame stgun1 stgun2 stgun3 stgun4 stgun5 stgun6 stgun7 stgun8 stgun9 +$frame stgun10 stgun11 stgun12 stgun13 + +$frame run1 run2 run3 run4 run5 run6 + +$frame rungun1 rungun2 rungun3 rungun4 rungun5 rungun6 + +$frame pain1 pain2 pain3 pain4 pain5 pain6 + +$frame pgun1 pgun2 pgun3 pgun4 pgun5 pgun6 + +$frame deatha1 deatha2 deatha3 deatha4 deatha5 deatha6 deatha7 deatha8 deatha9 +$frame deatha10 deatha11 deatha12 + +$frame dguna1 dguna2 dguna3 dguna4 dguna5 dguna6 dguna7 dguna8 dguna9 +$frame dguna10 dguna11 dguna12 + +$frame deathb1 deathb2 deathb3 deathb4 deathb5 deathb6 deathb7 deathb8 deathb9 +$frame deathb10 deathb11 deathb12 + +$frame dgunb1 dgunb2 dgunb3 dgunb4 dgunb5 dgunb6 dgunb7 dgunb8 dgunb9 +$frame dgunb10 dgunb11 dgunb12 + +$frame shot1 shot2 shot3 shot4 shot5 shot6 shot7 shot8 shot9 +$frame shot10 shot11 shot12 shot13 shot14 shot15 shot16 shot17 shot18 + +$frame rock1 rock2 rock3 rock4 rock5 rock6 rock7 rock8 rock9 +$frame rock10 rock11 rock12 rock13 rock14 rock15 rock16 rock17 rock18 + +$frame chain1 chain2 chain3 chain4 chain5 chain6 + +$frame bolt1 bolt2 bolt3 bolt4 bolt5 bolt6 + +$frame xatta1 xatta2 xatta3 xatta4 xatta5 xatta6 xatta7 xatta8 xatta9 xatta10 +$frame xatta11 xatta12 + +$frame xattb1 xattb2 xattb3 xattb4 xattb5 xattb6 xattb7 xattb8 +$frame xattb9 xattb10 xattb11 xattb12 + +$frame swim1 swim2 swim3 swim4 swim5 swim6 + +$frame jump1 jump2 jump3 jump4 jump5 jump6 + +/* +============================================================================== +PLAYER +============================================================================== +*/ + +void() player_run; + +void() player_stand1 =[ $stand1, player_stand1 ] +{ + local float oldframe; + + if (self.velocity_x || self.velocity_y || self.velocity_z) + { + self.walkframe=0; + player_run(); + return; + } + + if ((self.weapon == IT_AXE) || ((self.modelindex == index_skeleton) && (self.x_flags & X_STGUN))) + { + if (self.walkframe >= 13) + self.walkframe = 0; + + if ((self.waterlevel >= 2) && !deathmatch && !coop) + self.frame = $swim1 + self.walkframe; + else + self.frame = $stand1 + self.walkframe; + } + else + { + if (self.walkframe >= 13) + self.walkframe = 0; + + if ((self.waterlevel >= 2) && !deathmatch && !coop) + self.frame = $swim1 + self.walkframe; + else + self.frame = $stgun1 + self.walkframe; + } + self.walkframe = self.walkframe + 1; + + self.weapon_flags = self.weapon_flags - (self.weapon_flags & W_RELOADING); + + if (self.change_weapon_status == CW_DONE) { + if (self.weapon == IT_SUPER_NAILGUN) { + if ((!self.change_weapon_status) && (self.weaponframe < 16)) + self.weaponframe = 18; + + if ((self.weaponframe >= 16) && (self.weaponframe <= 18)) { + self.weaponframe = self.weaponframe + 1; + if (self.weaponframe > 18) + self.weaponframe = 16; + } + } + else if (!deathmatch && !coop && (self.weapon == IT_AXE)) { +// if ((!self.change_weapon_status) && (self.weaponframe < 23)) { +// self.weaponframe = 23; +// } + + oldframe = self.weaponframe; + while (self.weaponframe == oldframe) + self.weaponframe = 23 + rint(random() * 6); //self.weaponframe + 1; +// if (self.weaponframe > 29) +// self.weaponframe = 23; + } + else { + self.weaponframe=self.weapon_idleframe; + } + } +}; + +void() player_run =[ $run1, player_run ] +{ + local float oldframe; + + if (!self.velocity_x && !self.velocity_y && !self.velocity_z) + { + if (self.modelindex == index_skeleton) { + // use stgun or stand frames? + if (random() < 0.5) + self.x_flags = self.x_flags | X_STGUN; + else + self.x_flags = self.x_flags - (self.x_flags & X_STGUN); + } + + self.walkframe=0; + player_stand1(); + return; + } + + if (self.x_flags & X_JUMP_PRESSED) { + if ((self.last_jump > (time - 0.2)) && (self.waterlevel < 2)) { + self.frame = $jump1; + self.walkframe = self.frame - 1; + } + + self.x_flags = self.x_flags - X_JUMP_PRESSED; + } + else { + if (self.walkframe >= $jump1 ) { + if (!(self.flags & FL_ONGROUND)) { // still in the air + self.frame = self.walkframe + 1; + + if (self.walkframe >= $jump5 ) + self.walkframe = $jump4; + } + else { // landed + self.frame = self.walkframe; + if (self.walkframe >= $jump6 ) + self.walkframe = 0; + } + } + else if (self.weapon == IT_AXE) + { + if (self.walkframe >= 6) + self.walkframe = 0; + + if ((self.waterlevel >= 2) && !deathmatch && !coop) + self.frame = $swim1 + self.walkframe; + else + self.frame = $run1 + self.walkframe; + } + else + { + if (self.walkframe >= 6) + self.walkframe = 0; + + if ((self.waterlevel >= 2) && !deathmatch && !coop) + self.frame = $swim1 + self.walkframe; + else + self.frame = $rungun1 + self.walkframe; + } + } + self.walkframe = self.walkframe + 1; + + self.weapon_flags = self.weapon_flags - (self.weapon_flags & W_RELOADING); + + if (self.change_weapon_status == CW_DONE) { + if (self.weapon == IT_SUPER_NAILGUN) { + if ((!self.change_weapon_status) && (self.weaponframe < 16)) { + self.weaponframe = 18; + } + + if ((self.weaponframe >= 16) && (self.weaponframe <= 18)) { + self.weaponframe = self.weaponframe + 1; + if (self.weaponframe > 18) + self.weaponframe = 16; + } + } + else if (!deathmatch && !coop && (self.weapon == IT_AXE)) { +// if ((!self.change_weapon_status) && (self.weaponframe < 23)) { +// self.weaponframe = 23; +// } + + oldframe = self.weaponframe; + while (self.weaponframe == oldframe) + self.weaponframe = 23 + rint(random() * 6); //self.weaponframe + 1; +// if (self.weaponframe > 29) +// self.weaponframe = 23; + } + else { + self.weaponframe=self.weapon_idleframe; + } + } + +}; + +//============================================================================ + +void() PlayerPunch = +{ +local vector delta; +local float ldmg; +local entity plyr; + + makevectors(self.v_angle); + if ((plyr = FindSightEnemy(self.origin, v_forward, 60, 40, "all", self)) == world) { + traceline(self.origin + '0 0 16', self.origin + '0 0 16' + v_forward * 48, TRUE, self); + + if (trace_fraction < 1) { + sound(self, CHAN_WEAPON, "generic/punch1.wav", 1, ATTN_NORM); + + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_GUNSHOT); + WriteCoord (MSG_BROADCAST, trace_endpos_x); + WriteCoord (MSG_BROADCAST, trace_endpos_y); + WriteCoord (MSG_BROADCAST, trace_endpos_z); + } + + return; + } + + delta = plyr.origin - self.origin; + + if (vlen(delta) > 60) + return; + + if (plyr.classname == "xmen_iceman") + IcemanShardGib(plyr, 3); + else if ((plyr.classname != "xmen_sinister") || (plyr.x_flags & X_MEGA_HIT)) + SpawnBlood(self.origin + v_forward * 16 + '0 0 16', '0 0 0', 9); + + ldmg = 9 + random() * 3; + T_Damage (plyr, self, self, ldmg); + + if ((plyr.flags & FL_MONSTER) && + (plyr.classname != "xmen_sinister") && + (plyr.classname != "apocalypse_small")) { + plyr.velocity = normalize(plyr.origin - self.origin) * 150 + '0 0 100'; + plyr.flags = plyr.flags - (plyr.flags & FL_ONGROUND); + setorigin(plyr, plyr.origin + '0 0 1'); + } + + if (random() < 0.5) + sound(self, CHAN_WEAPON, "generic/punch2.wav", 1, ATTN_NORM); + else + sound(self, CHAN_WEAPON, "generic/punch3.wav", 1, ATTN_NORM); +}; + +void() player_fist = +{ + self.weapon_flags = self.weapon_flags | W_RELOADING; + + if (self.weaponframe >= 15) { + self.weaponframe = self.weapon_idleframe; + } + + self.weaponframe = self.weaponframe + 1; + + self.frame = $xatta1 + (self.weaponframe - 5); + + self.think = player_fist; + + if (self.weaponframe == 8) { + SuperDamageSound(); + PlayerPunch(); + } + + if ((self.weaponframe >= 14) && ((!self.button0) || (self.remember_impulse))) { + self.weapon_flags = self.weapon_flags - (self.weapon_flags & W_RELOADING); + self.think = player_run; + self.weaponframe = self.weapon_idleframe; + } + + self.nextthink = time + 0.05; +}; + +//============================================================================ + +void() DoSpecialWeaponStuff; +void() player_att1 = +{ + self.weapon_flags = self.weapon_flags | W_RELOADING; + + if (self.weaponframe > 18) + self.weaponframe = self.weaponframe - 12; + + if (self.weaponframe >= 18) { // still holding down fire + if (!((self.character == CHAR_CANNONBALL) && (self.special_weapon) && (self.last_special2 > (time - 2)) )) + self.weaponframe = 6; + } + + self.weaponframe = self.weaponframe + 1; + + self.think = player_att1; + + DoSpecialWeaponStuff(); + + if ((self.weaponframe >= 18) && ((!self.button0) || (self.remember_impulse))) { + self.weapon_flags = self.weapon_flags - (self.weapon_flags & W_RELOADING); + self.think = player_run; + self.weaponframe = 6; + } + + if ((!self.special_weapon && self.character != CHAR_WOLVERINE) || + (self.special_weapon && self.character == CHAR_WOLVERINE)) + self.frame = $xatta1 + (self.weaponframe - 7); + else { + self.frame = $xattb1 + (self.weaponframe - 7); + self.weaponframe = self.weaponframe + 12; + } + + if (self.x_flags & X_RAPID_FIRE) { + if ((self.character == CHAR_BISHOP) && (!self.special_weapon)) { + // skip frames to go faster + + if ((self.weaponframe == 11) || + (self.weaponframe == 16)) { + self.weaponframe = self.weaponframe + 1; + } + } + + self.nextthink = time + 0.05; + } + else if ((self.character == CHAR_BISHOP) && (!self.special_weapon)) { + self.nextthink = time + 0.05; + } + else { + self.nextthink = time + 0.1; + } + +}; + +//============================================================================ + +void() player_laser1 =[$bolt1, player_laser1 ] +{ + self.effects = self.effects | EF_MUZZLEFLASH; + + if ((!self.button0) || (!W_CheckNoAmmo ()) || (self.change_weapon_status)) + { + self.weaponframe = 5; + player_run (); + return; + } + + if ((self.w_pausetime < time) || (self.x_flags & X_RAPID_FIRE)) { + + self.weaponframe = self.weaponframe + 1; + if (self.weaponframe > 14) + self.weaponframe = 6; + + self.walkframe = self.walkframe + 1; + if (self.walkframe > 5) + self.walkframe = 0; + + self.fire_reload_frames = self.fire_reload_frames - 1; + + if ((self.last_fire_laser > (time - 0.4)) && (self.weaponframe == 6) && !(self.x_flags & X_RAPID_FIRE)) { + self.w_pausetime = time + 0.5; + self.consecutive_count = 0; + self.weaponframe = 5; + + self.walkframe = 1; + } + else { + + if (self.fire_reload_frames <= 0) { + if (self.waterlevel < 3) { // can't fire while underwater + SuperDamageSound(); + W_FireFlameball (8); + } + + self.last_fire_laser = time; + self.attack_finished = time + 0.2; + + self.fire_reload_frames = 3; + } + else { + self.nextthink = time + 0.05; + } + } + + } + + self.frame = self.frame + self.walkframe; + +}; + +void() player_shotgun1 = [$shot1, player_shotgun1 ] +{ + if (self.weaponframe == 5) { + + if ((!(self.weapon_flags & W_RELOADING)) && + ((self.change_weapon_status) || + (!self.button0) || + (!W_CheckNoAmmo()))) { + + player_run (); + return; + } + + self.effects = self.effects | EF_MUZZLEFLASH; + self.walkframe = -1; + W_FireSuperShotgun(); + + self.weapon_flags = self.weapon_flags | W_RELOADING; + } + + if (self.change_weapon_status) + return; + + self.walkframe = self.walkframe + 1; + if (self.walkframe > 17) + self.walkframe = 17; + self.frame = self.frame + self.walkframe; + + self.weaponframe = self.weaponframe + 1; + + if ((self.weaponframe > 22) || ((self.weaponframe > 8) && !(self.weapon_flags & W_SHOTRELOAD))) { + self.weaponframe = 5; + + if (!(self.weapon_flags & W_SHOTRELOAD) && !(self.x_flags & X_RAPID_FIRE)) + self.weapon_flags = self.weapon_flags | W_SHOTRELOAD; + else + self.weapon_flags = self.weapon_flags - (self.weapon_flags & W_SHOTRELOAD); + + self.weapon_flags = self.weapon_flags - (self.weapon_flags & W_RELOADING); + } + else if (self.weaponframe == 10) { + sound (self ,CHAN_ITEM, "weapons/reload.wav", 1, ATTN_NORM); + } + else if (self.weaponframe > 8) + self.nextthink = time + 0.05; + +}; + +void(float ox) W_FireSuperSpikes; + +void() player_chain1 = [$chain1, player_chain1 ] +{ + if (self.change_weapon_status) { + self.weaponframe = 5; + player_run (); + return; + } + +// self.nextthink = time + 0.05; + + if ((!self.button0) || (!W_CheckNoAmmo ())) { + self.weaponframe = 5; + player_run (); + return; + } + + self.walkframe = self.walkframe + 1; + if (self.walkframe > 5) + self.walkframe = 0; + self.frame = self.frame + self.walkframe; + + if ((self.w_pausetime < time) || (self.x_flags & X_RAPID_FIRE)) { + + self.weaponframe = self.weaponframe + 1; + if (self.weaponframe > 11) + self.weaponframe = 6; + + self.effects = self.effects | EF_MUZZLEFLASH; + + SuperDamageSound(); + W_FireSuperSpikes (-8); + + self.consecutive_count = self.consecutive_count + 1; + + if (self.consecutive_count >= 15) { // let gun cool down + self.w_pausetime = time + 0.5; +/* + self.w_pausetime = time + self.last_pausetime + 0.5; + self.last_pausetime = self.last_pausetime + 0.2; + if (self.last_pausetime > 1.5) + self.last_pausetime = 1.5; +*/ + + self.consecutive_count = 0; + self.weaponframe = 5; + } + + } + + self.attack_finished = time + 0.2; +}; + +/**************** NOT USED **************************** +void() player_nail1 =[$nailatt1, player_nail2 ] +{ + self.effects = self.effects | EF_MUZZLEFLASH; + + if (!self.button0) + {player_run ();return;} + self.weaponframe = self.weaponframe + 1; + if (self.weaponframe == 9) + self.weaponframe = 1; + SuperDamageSound(); + W_FireSpikes (4); + self.attack_finished = time + 0.2; +}; +void() player_nail2 =[$nailatt2, player_nail1 ] +{ + self.effects = self.effects | EF_MUZZLEFLASH; + + if (!self.button0) + {player_run ();return;} + self.weaponframe = self.weaponframe + 1; + if (self.weaponframe == 9) + self.weaponframe = 1; + SuperDamageSound(); + W_FireSpikes (-4); + self.attack_finished = time + 0.2; +}; +********************************************************/ + +//============================================================================ + +void() player_mega =[$chain1, player_mega ] +{ +// self.effects = self.effects | EF_MUZZLEFLASH; + + if ((!self.button0) || (!W_CheckNoAmmo ()) || (self.change_weapon_status)) { + player_run (); + return; + } + + self.walkframe = self.walkframe + 1; + if (self.walkframe > 5) + self.walkframe = 0; + self.frame = self.frame + self.walkframe; + + self.weaponframe = self.weaponframe + 1; + if (self.weaponframe > 17) + self.weaponframe = 12; + + if ((self.weaponframe == 12) && (random() < 0.4)) + sound (self, CHAN_AUTO, "weapons/mega.wav", 1, ATTN_NONE); + + W_FireLightning(); + self.attack_finished = time + 0.2; +}; + +void() player_prox1 =[$chain1, player_prox1 ] +{ +// self.effects = self.effects | EF_MUZZLEFLASH; +//bprint("player_prox\n"); + + if (((!self.button0) || (self.change_weapon_status)) && (self.weaponframe < 11) && (self.weaponframe > 5)) { + SuperDamageSound(); + W_FireProximity(); + + self.weaponframe = 11; + + self.think = player_run; + W_CheckNoAmmo(); + + return; + } + + if (self.weaponframe == 5) { +// if (self.prox_ent == world) { + self.prox_power = 0; + StartProximity(); +// } + } + + if (self.weaponframe < 10) { + self.weaponframe = self.weaponframe + 1; + } + else if (self.weaponframe >= 11) { + self.weaponframe = self.weaponframe + 1; + + if (self.weaponframe > 15) { + player_run(); + return; + } + } + + self.walkframe = self.walkframe + 1; + if (self.walkframe > 5) + self.walkframe = 0; + self.frame = self.frame + self.walkframe; + + self.attack_finished = time + 0.2; + self.last_prox_think = time; +}; + +void() player_flame1 =[$bolt1, player_flame1 ] +{ +// self.effects = self.effects | EF_MUZZLEFLASH; + + if ((!self.button0) || (!W_CheckNoAmmo ()) || (self.change_weapon_status)) { + player_run (); + self.flags = self.flags - (self.flags & FL_FLAMEON); + return; + } + + self.walkframe = self.walkframe + 1; + if (self.walkframe > 5) + self.walkframe = 0; + self.frame = self.frame + self.walkframe; + + self.weaponframe = self.weaponframe + 1; + if (self.weaponframe > 8) + self.weaponframe = 6; + + SuperDamageSound(); +// W_FireLightning(); + W_FireFlameThrower(); + self.attack_finished = time + 0.2; +}; + +void() player_orb =[$rock1, player_orb ] +{ +// self.effects = self.effects | EF_MUZZLEFLASH; + if ((((self.weaponframe == 5) || (self.weaponframe == 11)) && (!self.button0)) || + (!W_CheckNoAmmo ()) || (self.change_weapon_status)) { + self.weaponframe = 5; + player_run (); + return; + } + + self.walkframe = self.walkframe + 1; + if (self.walkframe > 12) + self.walkframe = 0; + self.frame = self.frame + self.walkframe; + + self.weaponframe = self.weaponframe + 1; + if (self.weaponframe > 17) { + self.weaponframe = 5; + } + + if ((self.weaponframe == 6) || (self.weaponframe == 12)) { + SuperDamageSound(); + W_FireGrenade(); + self.attack_finished = time + 0.7; + } + else if ((self.weaponframe > 12) && (!(self.x_flags & X_RAPID_FIRE))) { + self.nextthink = time + 0.15; + } + else + self.nextthink = time + 0.05; + +}; + +//============================================================================ + +void() player_rocket16; + +void() player_rocket1 =[$rock1, player_rocket2 ] {self.weaponframe=6; +self.effects = self.effects | EF_MUZZLEFLASH; +self.weapon_flags = self.weapon_flags | W_RELOADING;}; +void() player_rocket2 =[$rock2, player_rocket3 ] {self.weaponframe=7;}; +void() player_rocket3 =[$rock3, player_rocket4 ] {self.weaponframe=8;}; +void() player_rocket4 =[$rock4, player_rocket5 ] {self.weaponframe=9;}; +void() player_rocket5 =[$rock5, player_rocket6 ] {self.weaponframe=10;}; +void() player_rocket6 =[$rock6, player_rocket7 ] +{ + self.weaponframe=11; + + if (self.x_flags & X_RAPID_FIRE) + self.think = player_rocket16; +}; +void() player_rocket7 =[$rock7, player_rocket8 ] {self.weaponframe=12; self.nextthink = time + 0.05;}; +void() player_rocket8 =[$rock8, player_rocket9 ] {self.weaponframe=13; self.nextthink = time + 0.05;}; +void() player_rocket9 =[$rock9, player_rocket10 ] {self.weaponframe=14; self.nextthink = time + 0.05;}; +void() player_rocket10 =[$rock10, player_rocket11 ] {self.weaponframe=15; self.nextthink = time + 0.05;}; +void() player_rocket11 =[$rock11, player_rocket12 ] {self.weaponframe=16; self.nextthink = time + 0.05;}; +void() player_rocket12 =[$rock12, player_rocket13 ] {self.weaponframe=1; self.nextthink = time + 0.05;}; +void() player_rocket13 =[$rock13, player_rocket14 ] {self.weaponframe=2; self.nextthink = time + 0.05;}; +void() player_rocket14 =[$rock14, player_rocket15 ] {self.weaponframe=3; self.nextthink = time + 0.05;}; +void() player_rocket15 =[$rock15, player_rocket16 ] {self.weaponframe=4; self.nextthink = time + 0.05;}; +void() player_rocket16 =[$rock16, player_run ] {self.weaponframe=5; +self.weapon_flags = self.weapon_flags - (self.weapon_flags & W_RELOADING); +self.attack_finished = time; +}; +void(float num_bubbles) DeathBubbles; + +void() PainSound = +{ +local float rs; + + if (self.health < 0) + return; + + if (damage_attacker.classname == "teledeath") + { + sound (self, CHAN_VOICE, "player/teledth1.wav", 1, ATTN_NONE); + return; + } + + if (!deathmatch && !coop) { + // water pain sounds + if (self.watertype == CONTENT_WATER && self.waterlevel == 3) + { + DeathBubbles(1); + if (random() > 0.5) + sound (self, CHAN_VOICE, "player/drown1.wav", 1, ATTN_NORM); + else + sound (self, CHAN_VOICE, "player/drown2.wav", 1, ATTN_NORM); + return; + } + + if (self.watertype == CONTENT_LAVA) + { + if (random() > 0.5) + sound (self, CHAN_VOICE, "player/lburn1.wav", 1, ATTN_NORM); + else + sound (self, CHAN_VOICE, "player/lburn2.wav", 1, ATTN_NORM); + return; + } + } + + if (self.pain_finished > time) + { + self.axhitme = 0; + return; + } + self.pain_finished = time + 0.5; + +// don't make multiple pain sounds right after each other + + if (deathmatch || coop) { + if (self.char_type == CT_FEMALE) + FemalePainSound(); + else + MalePainSound(self.char_type); + } + else { + rs = random() * 4; + + if (rs < 1) + sound(self, CHAN_VOICE, "player/pain1.wav", 1, ATTN_NORM); + else if (rs < 2) + sound(self, CHAN_VOICE, "player/pain2.wav", 1, ATTN_NORM); + else if (rs < 3) + sound(self, CHAN_VOICE, "player/pain3.wav", 1, ATTN_NORM); + else + sound(self, CHAN_VOICE, "player/pain4.wav", 1, ATTN_NORM); + } + +}; + +void() player_pain1 = [ $pgun1, player_pain2 ] {}; +void() player_pain2 = [ $pgun2, player_pain3 ] {}; +void() player_pain3 = [ $pgun3, player_pain4 ] {}; +void() player_pain4 = [ $pgun4, player_pain5 ] {}; +void() player_pain5 = [ $pgun5, player_pain6 ] {}; +void() player_pain6 = [ $pgun6, player_run ] {}; + +void() player_painaxe1 = [ $pain1, player_painaxe2 ] {}; +void() player_painaxe2 = [ $pain2, player_painaxe3 ] {}; +void() player_painaxe3 = [ $pain3, player_painaxe4 ] {}; +void() player_painaxe4 = [ $pain4, player_painaxe5 ] {}; +void() player_painaxe5 = [ $pain5, player_painaxe6 ] {}; +void() player_painaxe6 = [ $pain6, player_run ] {}; + +void() player_pain = +{ + if (self.invisible_finished > time) + return; // eyes don't have pain frames + + PainSound(); + + if (self.weaponframe != self.weapon_idleframe) + return; + + if (self.prox_ent != world) + return; + + if (self.weapon == IT_AXE) + player_painaxe1 (); + else + player_pain1 (); +}; + +void() player_diea1; +void() player_dieb1; +void() player_dguna1; +void() player_dgunb1; + +void() DeathBubblesSpawn = +{ +local entity bubble; + if (self.owner.waterlevel != 3) + return; + bubble = spawn(); + setmodel (bubble, "progs/s_bubble.spr"); + setorigin (bubble, self.owner.origin + '0 0 24'); + bubble.movetype = MOVETYPE_NOCLIP; + bubble.solid = SOLID_NOT; + bubble.velocity = '0 0 15'; + bubble.nextthink = time + 0.5; + bubble.think = bubble_bob; + bubble.classname = "bubble"; + bubble.frame = 0; + bubble.cnt = 0; + setsize (bubble, '-8 -8 -8', '8 8 8'); + self.nextthink = time + 0.1; + self.think = DeathBubblesSpawn; + self.air_finished = self.air_finished + 1; + if (self.air_finished >= self.bubble_count) + remove(self); +}; + +void(float num_bubbles) DeathBubbles = +{ +local entity bubble_spawner; + + bubble_spawner = spawn(); + setorigin (bubble_spawner, self.origin); + bubble_spawner.movetype = MOVETYPE_NONE; + bubble_spawner.solid = SOLID_NOT; + bubble_spawner.nextthink = time + 0.1; + bubble_spawner.think = DeathBubblesSpawn; + bubble_spawner.air_finished = 0; + bubble_spawner.owner = self; + bubble_spawner.bubble_count = num_bubbles; + return; +}; + + +void() DeathSound = +{ +local float rs; + + // water death sounds + if (self.waterlevel == 3) + { + DeathBubbles(20); + sound (self, CHAN_VOICE, "player/h2odeath.wav", 1, ATTN_NONE); + return; + } + + if (deathmatch || coop) { + if (self.char_type == CT_FEMALE) + FemaleDeathSound(); + else + MaleDeathSound(self.char_type); + } +// else +// MaleDeathSound(1); + + return; +}; + + +void() PlayerDead = +{ + self.nextthink = -1; +// allow respawn after a certain time + self.deadflag = DEAD_DEAD; +}; + +vector(float dm) VelocityForDamage = +{ + local vector v; + + if (damage_attacker.classname == "player") + { + if (vlen(damage_inflictor.velocity) > 0) + v = 0.5 * damage_inflictor.velocity; + v = v + (400 * normalize(self.origin-damage_attacker.origin)); + v = v * random(); + v_z = 100 + 240 * random(); + v_x = v_x + (100 * crandom()); + v_y = v_y + (100 * crandom()); +//bprint ("Velocity gib\n"); + } + else + { + v_x = 100 * crandom(); + v_y = 100 * crandom(); + v_z = 200 + 100 * random(); + } + +// v_x = 200 * crandom(); +// v_y = 200 * crandom(); +// v_z = 400 + 100 * random(); + + if (dm > -30) + { +// dprint ("level 1\n"); + v = v * 1; + } + else if (dm > -80) + { +// dprint ("level 3\n"); + v = v * 1.5; + } + else + v = v * 3; + + return v; +}; + +void() GibThink = +{ + if ((self.angles_x != 0) && (self.velocity == '0 0 0')) { + self.angles_x = 0; + self.angles_z = 0; + self.avelocity = '0 0 0'; + self.movetype = MOVETYPE_NONE; + + if (self.model == "progs/gib01.mdl") + setorigin(self, self.origin + '0 0 4'); + + self.think = SUB_Remove; + self.nextthink = time + 5 + random()*5; + + return; + } + + self.nextthink = time + 0.1; + + if (self.ltime < time) + remove(self); + +}; + +void(string gibname, float dm) ThrowGib = +{ + local entity new; + + new = spawn(); + new.origin = self.origin; + setmodel (new, gibname); + setsize (new, '0 0 0', '0 0 0'); + new.velocity = VelocityForDamage (dm); + new.movetype = MOVETYPE_BOUNCE; + new.solid = SOLID_TRIGGER; + new.avelocity_x = random()*600; + new.avelocity_y = random()*600; + new.avelocity_z = random()*600; + new.think = GibThink; + new.ltime = time + 10 + random() * 5; + new.nextthink = time + 0.1; + new.frame = 0; + new.flags = 0; + + if (self.classname == "func_explode") + new.skin = self.speed; +}; + +void(string gibname, float dm) ThrowBodyPart = +{ + local entity new; + + new = spawn(); + new.origin = self.origin; + setmodel (new, gibname); + setsize (new, '-4 -4 -4', '4 4 4'); + new.velocity = VelocityForDamage (dm); + new.movetype = MOVETYPE_BOUNCE; + self.solid = SOLID_NOT; + new.avelocity_x = random()*600; + new.avelocity_y = random()*600; + new.avelocity_z = random()*600; + new.think = SUB_Remove; + new.ltime = time + 5 + random() * 5; + new.nextthink = time + 10 + random()*10; + new.frame = 0; + new.flags = 0; + + new.think = GibThink; + new.nextthink = time + 0.2; +}; + +void(string gibname, float dm) ThrowHead = +{ + setmodel (self, gibname); + self.frame = 0; + self.nextthink = -1; + self.movetype = MOVETYPE_BOUNCE; + self.takedamage = DAMAGE_NO; + self.solid = SOLID_TRIGGER; + self.view_ofs = '0 0 8'; + setsize (self, '-16 -16 -8', VEC_HULL_MAX); + self.velocity = VelocityForDamage (dm * 2); +// self.origin_z = self.origin_z + ; + self.flags = self.flags - (self.flags & FL_ONGROUND); + self.avelocity = crandom() * '200 600 200'; + +// self.think = GibThink; +// self.nextthink = time + 0.2; +}; + + +void() GibPlayer = +{ + ThrowHead ("progs/gib01.mdl", self.health); + ThrowGib ("progs/gib02.mdl", self.health); + ThrowGib ("progs/gib02.mdl", self.health); + ThrowGib ("progs/gib02.mdl", self.health); + ThrowGib ("progs/gib03.mdl", self.health); + ThrowGib ("progs/gib03.mdl", self.health); + ThrowGib ("progs/gib03.mdl", self.health); + + self.deadflag = DEAD_DEAD; + + if (damage_attacker.classname == "teledeath") + { + sound (self, CHAN_VOICE, "player/teledth1.wav", 1, ATTN_NONE); + return; + } + + if (damage_attacker.classname == "teledeath2") + { + sound (self, CHAN_VOICE, "player/teledth1.wav", 1, ATTN_NONE); + return; + } + + sound(self, CHAN_BODY, "skeleton/crunch.wav", 1, ATTN_NORM); +}; + +void() PlayerDie = +{ + local float i; + local string str; + + self.items = self.items - (self.items & IT_INVISIBILITY); + self.invisible_finished = 0; // don't die as eyes + self.invincible_finished = 0; + self.super_damage_finished = 0; + self.radsuit_finished = 0; + + if (self.modelindex != index_skeleton) + self.modelindex = self.modelindex_player; // don't use eyes + + if (deathmatch && (deathmatch != DM_SPECIAL_POWERS) && (self.modelindex != index_skeleton)) + DropBackpack(); + + self.weaponmodel=""; + self.view_ofs = '0 0 -8'; + self.deadflag = DEAD_DYING; + self.solid = SOLID_NOT; + self.flags = self.flags - (self.flags & FL_ONGROUND); + self.flags = self.flags - (self.flags & FL_FLAMEON); + + self.x_flags = self.x_flags - (self.x_flags & X_FLYING); + self.x_flags = self.x_flags - (self.x_flags & X_RAPID_FIRE); + self.x_flags = self.x_flags - (self.x_flags & X_PARALLIZED); + + self.effects = self.effects - (self.effects & EF_DIMLIGHT); + self.movetype = MOVETYPE_TOSS; + if (self.velocity_z < 10) + self.velocity_z = self.velocity_z + random()*300; + + if (self.modelindex == index_skeleton) + { + GibPlayer (); + return; + } + + DeathSound(); + + self.angles_x = 0; + self.angles_z = 0; + + i = 1 + floor(random()*2); + + if (self.weapon == IT_AXE) + { + if (i == 1) + player_diea1(); + else if (i == 2) + player_dieb1(); + + return; + } + + if (i == 1) + player_dguna1(); + else if (i == 2) + player_dgunb1(); + +}; + +void() set_suicide_frame = +{ // used by klill command and diconnect command + if (self.deadflag == DEAD_DEAD) + return; // allready gibbed + + self.flags = self.flags - (self.flags & FL_FLAMEON); + + self.x_flags = self.x_flags - (self.x_flags & X_FLYING); + self.x_flags = self.x_flags - (self.x_flags & X_RAPID_FIRE); + self.x_flags = self.x_flags - (self.x_flags & X_PARALLIZED); + + self.frame = $deatha11; + self.solid = SOLID_NOT; + self.movetype = MOVETYPE_TOSS; + self.deadflag = DEAD_DEAD; + self.nextthink = -1; +}; + + +void() player_diea1 = [ $deatha1, player_diea2 ] {}; +void() player_diea2 = [ $deatha2, player_diea3 ] {}; +void() player_diea3 = [ $deatha3, player_diea4 ] {}; +void() player_diea4 = [ $deatha4, player_diea5 ] {}; +void() player_diea5 = [ $deatha5, player_diea6 ] {}; +void() player_diea6 = [ $deatha6, player_diea7 ] {}; +void() player_diea7 = [ $deatha7, player_diea8 ] {}; +void() player_diea8 = [ $deatha8, player_diea9 ] {}; +void() player_diea9 = [ $deatha9, player_diea10 ] {}; +void() player_diea10 = [ $deatha10, player_diea11 ] {}; +void() player_diea11 = [ $deatha11, player_diea12 ] {}; +void() player_diea12 = [ $deatha12, player_diea12 ] {PlayerDead();}; + +void() player_dieb1 = [ $deathb1, player_dieb2 ] {}; +void() player_dieb2 = [ $deathb2, player_dieb3 ] {}; +void() player_dieb3 = [ $deathb3, player_dieb4 ] {}; +void() player_dieb4 = [ $deathb4, player_dieb5 ] {}; +void() player_dieb5 = [ $deathb5, player_dieb6 ] {}; +void() player_dieb6 = [ $deathb6, player_dieb7 ] {}; +void() player_dieb7 = [ $deathb7, player_dieb8 ] {}; +void() player_dieb8 = [ $deathb8, player_dieb9 ] {}; +void() player_dieb9 = [ $deathb9, player_dieb10 ] {}; +void() player_dieb10 = [ $deathb10, player_dieb11 ] {}; +void() player_dieb11 = [ $deathb11, player_dieb12 ] {}; +void() player_dieb12 = [ $deathb12, player_dieb12 ] {PlayerDead();}; + +void() player_dguna1 = [ $dguna1, player_dguna2 ] {}; +void() player_dguna2 = [ $dguna2, player_dguna3 ] {}; +void() player_dguna3 = [ $dguna3, player_dguna4 ] {}; +void() player_dguna4 = [ $dguna4, player_dguna5 ] {}; +void() player_dguna5 = [ $dguna5, player_dguna6 ] {}; +void() player_dguna6 = [ $dguna6, player_dguna7 ] {}; +void() player_dguna7 = [ $dguna7, player_dguna8 ] {}; +void() player_dguna8 = [ $dguna8, player_dguna9 ] {}; +void() player_dguna9 = [ $dguna9, player_dguna10 ] {}; +void() player_dguna10 = [ $dguna10, player_dguna11 ] {}; +void() player_dguna11 = [ $dguna11, player_dguna12 ] {}; +void() player_dguna12 = [ $dguna12, player_dguna12 ] {PlayerDead();}; + +void() player_dgunb1 = [ $dgunb1, player_dgunb2 ] {}; +void() player_dgunb2 = [ $dgunb2, player_dgunb3 ] {}; +void() player_dgunb3 = [ $dgunb3, player_dgunb4 ] {}; +void() player_dgunb4 = [ $dgunb4, player_dgunb5 ] {}; +void() player_dgunb5 = [ $dgunb5, player_dgunb6 ] {}; +void() player_dgunb6 = [ $dgunb6, player_dgunb7 ] {}; +void() player_dgunb7 = [ $dgunb7, player_dgunb8 ] {}; +void() player_dgunb8 = [ $dgunb8, player_dgunb9 ] {}; +void() player_dgunb9 = [ $dgunb9, player_dgunb10 ] {}; +void() player_dgunb10 = [ $dgunb10, player_dgunb11 ] {}; +void() player_dgunb11 = [ $dgunb11, player_dgunb12 ] {}; +void() player_dgunb12 = [ $dgunb12, player_dgunb12 ] {PlayerDead();}; + diff --git a/Progs.src b/Progs.src new file mode 100644 index 0000000..0de7f8d --- /dev/null +++ b/Progs.src @@ -0,0 +1,63 @@ +../progs.dat + +defs.c +x_vars.c +x_cam.c +x_misc.c +x_sound.c +geometry.c +subs.c +fight.c +ai.c +combat.c +items.c +weapons.c +x_spwpn.c +world.c +client.c +player.c +monsters.c +doors.c +buttons.c +tripwire.c // xmen (cl2): Laser Tripwire Code +particle.c // xmen (cl2): Particle Throwers +mines.c // xmen (cl2): Mines +litening.c // xmen (cl2): Lightning +triggers.c +x_trig.c // xmen (cl2): trigger_constant +plats.c +misc.c + +explbrsh.c // xmen (cl2): Exploding brush code + +x_selch.c // xmen : select character stuff +x_tech.c // xmen : tech dude +x_ambient.c // xmen : ambient sounds + +skeleton.c + +// X-Men characters (implemented) +wolvie.c +storm.c +cyclops.c +beast.c +psylocke.c +angel.c +gambit.c +bishop.c +rogue.c +cannon.c +cannon2.c +phoenix.c +iceman.c + +// X-Men Bosses +apsmall.c +appy.c + +sinister.c + +// Id's untouched monsters +//boss.c + +x_debug.c diff --git a/SPRITES.c b/SPRITES.c new file mode 100644 index 0000000..6874f59 --- /dev/null +++ b/SPRITES.c @@ -0,0 +1,26 @@ + +// these are the only sprites still in the game... + +$spritename s_explod +$type vp_parallel +$load id1/gfx/sprites/explod03.lbm +$frame 24 24 56 56 +$frame 120 24 56 56 +$frame 216 24 56 56 +$frame 24 88 56 56 +$frame 120 88 56 56 +$frame 216 88 56 56 + + +$spritename s_bubble +$type vp_parallel +$load id1/gfx/sprites/bubble.lbm +$frame 16 16 16 16 +$frame 40 16 16 16 + + +$spritename s_light +$type vp_parallel +$load id1/gfx/sprites/light.lbm +$frame 104 32 32 32 + diff --git a/SUBS.c b/SUBS.c new file mode 100644 index 0000000..de6d6eb --- /dev/null +++ b/SUBS.c @@ -0,0 +1,332 @@ + + +void() SUB_Null = {}; + +void() SUB_Remove = {remove(self);}; + + +/* +QuakeEd only writes a single float for angles (bad idea), so up and down are +just constant angles. +*/ +vector() SetMovedir = +{ + if (self.angles == '0 -1 0') + self.movedir = '0 0 1'; + else if (self.angles == '0 -2 0') + self.movedir = '0 0 -1'; + else + { + makevectors (self.angles); + self.movedir = v_forward; + } + + self.angles = '0 0 0'; +}; + +/* +================ +InitTrigger +================ +*/ +void() InitTrigger = +{ +// trigger angles are used for one-way touches. An angle of 0 is assumed +// to mean no restrictions, so use a yaw of 360 instead. + if (self.angles != '0 0 0') + SetMovedir (); + self.solid = SOLID_TRIGGER; + setmodel (self, self.model); // set size and link into world + self.movetype = MOVETYPE_NONE; + self.modelindex = 0; + self.model = ""; +}; + +/* +============= +SUB_CalcMove + +calculate self.velocity and self.nextthink to reach dest from +self.origin traveling at speed +=============== +*/ +void(entity ent, vector tdest, float tspeed, void() func) SUB_CalcMoveEnt = +{ +local entity stemp; + stemp = self; + self = ent; + + SUB_CalcMove (tdest, tspeed, func); + self = stemp; +}; + +void(vector tdest, float tspeed, void() func) SUB_CalcMove = +{ +local vector vdestdelta; +local float len, traveltime; + + if (!tspeed) + objerror("No speed is defined!"); + + self.think1 = func; + self.finaldest = tdest; + self.think = SUB_CalcMoveDone; + + if (tdest == self.origin) + { + self.velocity = '0 0 0'; + self.nextthink = self.ltime + 0.1; + return; + } + +// set destdelta to the vector needed to move + vdestdelta = tdest - self.origin; + +// calculate length of vector + len = vlen (vdestdelta); + +// divide by speed to get time to reach dest + traveltime = len / tspeed; + + if (traveltime < 0.1) + { + self.velocity = '0 0 0'; + self.nextthink = self.ltime + 0.1; + return; + } + +// set nextthink to trigger a think when dest is reached + self.nextthink = self.ltime + traveltime; + +// scale the destdelta vector by the time spent traveling to get velocity + self.velocity = vdestdelta * (1/traveltime); // qcc won't take vec/float +}; + +/* +============ +After moving, set origin to exact final destination +============ +*/ +void() SUB_CalcMoveDone = +{ + setorigin(self, self.finaldest); + self.velocity = '0 0 0'; + self.nextthink = -1; + if (self.think1) + self.think1(); +}; + + +/* +============= +SUB_CalcAngleMove + +calculate self.avelocity and self.nextthink to reach destangle from +self.angles rotating + +The calling function should make sure self.think is valid +=============== +*/ +void(entity ent, vector destangle, float tspeed, void() func) SUB_CalcAngleMoveEnt = +{ +local entity stemp; + stemp = self; + self = ent; + SUB_CalcAngleMove (destangle, tspeed, func); + self = stemp; +}; + +void(vector destangle, float tspeed, void() func) SUB_CalcAngleMove = +{ +local vector destdelta; +local float len, traveltime; + + if (!tspeed) + objerror("No speed is defined!"); + +// set destdelta to the vector needed to move + destdelta = destangle - self.angles; + +// calculate length of vector + len = vlen (destdelta); + +// divide by speed to get time to reach dest + traveltime = len / tspeed; + +// set nextthink to trigger a think when dest is reached + self.nextthink = self.ltime + traveltime; + +// scale the destdelta vector by the time spent traveling to get velocity + self.avelocity = destdelta * (1 / traveltime); + + self.think1 = func; + self.finalangle = destangle; + self.think = SUB_CalcAngleMoveDone; +}; + +/* +============ +After rotating, set angle to exact final angle +============ +*/ +void() SUB_CalcAngleMoveDone = +{ + self.angles = self.finalangle; + self.avelocity = '0 0 0'; + self.nextthink = -1; + if (self.think1) + self.think1(); +}; + + +//============================================================================= + +void() DelayThink = +{ + activator = self.enemy; + SUB_UseTargets (); + remove(self); +}; + +/* +============================== +SUB_UseTargets + +the global "activator" should be set to the entity that initiated the firing. + +If self.delay is set, a DelayedUse entity will be created that will actually +do the SUB_UseTargets after that many seconds have passed. + +Centerprints any self.message to the activator. + +Removes all entities with a targetname that match self.killtarget, +and removes them, so some events can remove other triggers. + +Search for (string)targetname in all entities that +match (string)self.target and call their .use function + +============================== +*/ +void() SUB_UseTargets = +{ + local entity t, stemp, otemp, act; + +// +// check for a delay +// + if (self.delay) + { + // create a temp object to fire at a later time + t = spawn(); + t.classname = "DelayedUse"; + t.nextthink = time + self.delay; + t.think = DelayThink; + t.enemy = activator; + t.message = self.message; + t.weapon_parts = self.weapon_parts; + t.killtarget = self.killtarget; + t.target = self.target; + return; + } + + +// +// print the message +// + if ((activator.classname == "player") && (self.message != "") && + ((self.weapon_parts == 0) || + ((self.weapon_parts == 1) && !(serverflags & 1)) || + ((self.weapon_parts == 2) && !(serverflags & 2)) || + ((self.weapon_parts == 3) && !(serverflags & 4)) || + ((self.weapon_parts == 4) && !(serverflags & 8)) )) + { + activator.last_centerprint = self.message; + centerprint (activator, self.message); + if (!self.noise) + sound (activator, CHAN_VOICE, "misc/talk.wav", 1, ATTN_NORM); + } + +// +// kill the killtagets +// + if (self.killtarget) + { + t = world; + do + { + t = find (t, targetname, self.killtarget); + if (!t) + return; + remove (t); + } while ( 1 ); + } + +// +// fire targets +// + if (self.target) + { + + act = activator; + t = world; + do + { + t = find (t, targetname, self.target); + if (!t) + { + return; + } + + + stemp = self; + otemp = other; + self = t; + other = stemp; + if (self.use != SUB_Null) + { + if (self.use) { + self.use (); +/* +bprint("firing: "); +bprint(t.targetname); +bprint("\n"); +*/ + } + } + self = stemp; + other = otemp; + activator = act; + } while ( 1 ); + } + + +}; + + +/* + +in nightmare mode, all attack_finished times become 0 +some monsters refire twice automatically + +*/ + +void(float normal) SUB_AttackFinished = +{ + self.cnt = 0; // refire count for nightmare + if (skill != 3) + self.attack_finished = time + normal; +}; + +float (entity targ) visible; + +void (void() thinkst) SUB_CheckRefire = +{ + if (skill != 3) + return; + if (self.cnt == 1) + return; + if (!visible (self.enemy)) + return; + self.cnt = 1; + self.think = thinkst; +}; diff --git a/TRIGGERS.c b/TRIGGERS.c new file mode 100644 index 0000000..65a27b8 --- /dev/null +++ b/TRIGGERS.c @@ -0,0 +1,686 @@ + +entity stemp, otemp, s, old; + + +void() trigger_reactivate = +{ + self.solid = SOLID_TRIGGER; +}; + +//============================================================================= + +float SPAWNFLAG_NOMESSAGE = 1; +float SPAWNFLAG_NOTOUCH = 1; + +// the wait time has passed, so set back up for another activation +void() multi_wait = +{ + if (self.max_health) + { + self.health = self.max_health; + self.takedamage = DAMAGE_YES; + self.solid = SOLID_BBOX; + } +}; + + +// the trigger was just touched/killed/used +// self.enemy should be set to the activator so it can be held through a delay +// so wait for the delay time before firing +void() multi_trigger = +{ + if (self.nextthink > time) + { + return; // allready been triggered + } + + if (self.classname == "trigger_secret") + { + if (self.enemy.classname != "player") + return; + found_secrets = found_secrets + 1; + WriteByte (MSG_ALL, SVC_FOUNDSECRET); + } + + if (self.noise) + sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); + +// don't trigger again until reset + self.takedamage = DAMAGE_NO; + + activator = self.enemy; + + SUB_UseTargets(); + + if (self.wait > 0) + { + self.think = multi_wait; + self.nextthink = time + self.wait; + } + else + { // we can't just remove (self) here, because this is a touch function + // called wheil C code is looping through area links... + self.touch = SUB_Null; + self.nextthink = time + 0.1; + self.think = SUB_Remove; + } +}; + +void() multi_killed = +{ + self.enemy = damage_attacker; + multi_trigger(); +}; + +void() multi_use = +{ + self.enemy = activator; + multi_trigger(); +}; + +void() multi_touch = +{ + if (other.classname != "player") + return; + +// if the trigger has an angles field, check player's facing direction + if (self.movedir != '0 0 0') + { + makevectors (other.angles); + if (v_forward * self.movedir < 0) + return; // not facing the right way + } + + // check for weapon part warning message +// if (other.classname == "player" && self.message != "" && (other.weapon_parts < self.weapon_parts)) +// return; + + self.enemy = other; + multi_trigger (); +}; + +/*QUAKED trigger_multiple (.5 .5 .5) ? notouch +Variable sized repeatable trigger. Must be targeted at one or more entities. If "health" is set, the trigger must be killed to activate each time. +If "delay" is set, the trigger waits some time after activating before firing. +"wait" : Seconds between triggerings. (.2 default) +If notouch is set, the trigger is only fired by other entities, not by touching. +NOTOUCH has been obsoleted by trigger_relay! +sounds +1) secret +2) beep beep +3) large switch +4) +set "message" to text string +*/ +void() trigger_multiple = +{ + if (deathmatch && self.weapon_parts) { + remove(self); + return; + } + + if (self.sounds == 1) + { + precache_sound ("misc/secret.wav"); + self.noise = "misc/secret.wav"; + } + else if (self.sounds == 2) + { + precache_sound ("misc/talk.wav"); + self.noise = "misc/talk.wav"; + } + else if (self.sounds == 3) + { + precache_sound ("misc/trigger1.wav"); + self.noise = "misc/trigger1.wav"; + } + + if (!self.wait) + self.wait = 0.2; + self.use = multi_use; + + InitTrigger (); + + if (self.health) + { + if (self.spawnflags & SPAWNFLAG_NOTOUCH) + objerror ("health and notouch don't make sense\n"); + self.max_health = self.health; + self.th_die = multi_killed; + self.takedamage = DAMAGE_YES; + self.solid = SOLID_BBOX; + setorigin (self, self.origin); // make sure it links into the world + } + else + { + if ( !(self.spawnflags & SPAWNFLAG_NOTOUCH) ) + { + self.touch = multi_touch; + } + } +}; + + +/*QUAKED trigger_once (.5 .5 .5) ? notouch +Variable sized trigger. Triggers once, then removes itself. You must set the key "target" to the name of another object in the level that has a matching +"targetname". If "health" is set, the trigger must be killed to activate. +If notouch is set, the trigger is only fired by other entities, not by touching. +if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired. +if "angle" is set, the trigger will only fire when someone is facing the direction of the angle. Use "360" for an angle of 0. +sounds +1) secret +2) beep beep +3) large switch +4) +set "message" to text string +*/ +void() trigger_once = +{ + if ((deathmatch) && (self.message != "")) { + remove(self); + return; + } + + self.wait = -1; + trigger_multiple(); +}; + +//============================================================================= + +/*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8) +This fixed size trigger cannot be touched, it can only be fired by other events. It can contain killtargets, targets, delays, and messages. +*/ +void() trigger_relay = +{ + self.use = SUB_UseTargets; +}; + + +//============================================================================= + +/*QUAKED trigger_secret (.5 .5 .5) ? +secret counter trigger +sounds +1) secret +2) beep beep +3) +4) +set "message" to text string +*/ +void() trigger_secret = +{ + total_secrets = total_secrets + 1; + self.wait = -1; + if (!self.message) + self.message = "You found a secret area!"; + if (!self.sounds) + self.sounds = 1; + + if (self.sounds == 1) + { + precache_sound ("misc/secret.wav"); + self.noise = "misc/secret.wav"; + } + else if (self.sounds == 2) + { + precache_sound ("misc/talk.wav"); + self.noise = "misc/talk.wav"; + } + + trigger_multiple (); +}; + +//============================================================================= + + +void() counter_use = +{ + local string junk; + + self.count = self.count - 1; + if (self.count < 0) + return; + + if (self.count != 0) + { + if (activator.classname == "player" + && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0) + { + if (self.count >= 4) + centerprint (activator, "There are more to go..."); + else if (self.count == 3) + centerprint (activator, "Only 3 more to go..."); + else if (self.count == 2) + centerprint (activator, "Only 2 more to go..."); + else + centerprint (activator, "Only 1 more to go..."); + } + return; + } + + if (activator.classname == "player" + && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0) + centerprint(activator, "Sequence completed!"); + self.enemy = activator; + multi_trigger (); +}; + +/*QUAKED trigger_counter (.5 .5 .5) ? nomessage +Acts as an intermediary for an action that takes multiple inputs. + +If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished. + +After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself. +*/ +void() trigger_counter = +{ + self.wait = -1; + if (!self.count) + self.count = 2; + + self.use = counter_use; +}; + + +/* +============================================================================== + +TELEPORT TRIGGERS + +============================================================================== +*/ + +float PLAYER_ONLY = 1; +float SILENT = 2; + +void() play_teleport = +{ + local float v; + local string tmpstr; + + v = random() * 5; + if (v < 1) + tmpstr = "misc/r_tele1.wav"; + else if (v < 2) + tmpstr = "misc/r_tele2.wav"; + else if (v < 3) + tmpstr = "misc/r_tele3.wav"; + else if (v < 4) + tmpstr = "misc/r_tele4.wav"; + else + tmpstr = "misc/r_tele5.wav"; + + sound (self, CHAN_VOICE, tmpstr, 1, ATTN_NORM); + remove (self); +}; + +void(vector org) spawn_tfog = +{ + s = spawn (); + s.origin = org; + s.nextthink = time + 0.2; + s.think = play_teleport; + + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_TELEPORT); + WriteCoord (MSG_BROADCAST, org_x); + WriteCoord (MSG_BROADCAST, org_y); + WriteCoord (MSG_BROADCAST, org_z); +}; + + +void() tdeath_touch = +{ + if (other == self.owner) + return; + +// frag anyone who teleports in on top of an invincible player + if (other.classname == "player") + { + if (other.invincible_finished > time) + self.classname = "teledeath2"; + if (self.owner.classname != "player") + { // other monsters explode themselves + T_Damage (self.owner, self, self, 50000); + return; + } + + } + + if (other.health) + { + T_Damage (other, self, self, 50000); + } +}; + + +void(vector org, entity death_owner) spawn_tdeath = +{ +local entity death; + + death = spawn(); + death.classname = "teledeath"; + death.movetype = MOVETYPE_NONE; + death.solid = SOLID_TRIGGER; + death.angles = '0 0 0'; + setsize (death, death_owner.mins - '1 1 1', death_owner.maxs + '1 1 1'); + setorigin (death, org); + death.touch = tdeath_touch; + death.nextthink = time + 0.2; + death.think = SUB_Remove; + death.owner = death_owner; + + force_retouch = 2; // make sure even still objects get hit +}; + +void() teleport_touch = +{ +local entity t; +local vector org; + + if (self.targetname) + { + if (self.nextthink < time) + { + return; // not fired yet + } + } + + if (self.spawnflags & PLAYER_ONLY) + { + if (other.classname != "player") + return; + } + +// only teleport living creatures + if (other.health <= 0 || other.solid != SOLID_SLIDEBOX) + return; + + SUB_UseTargets (); + +// put a tfog where the player was + spawn_tfog (other.origin); + + t = find (world, targetname, self.target); + if (!t) + objerror ("couldn't find target"); + +// spawn a tfog flash in front of the destination + makevectors (t.mangle); + org = t.origin + 32 * v_forward; + + spawn_tfog (org); + spawn_tdeath(t.origin, other); + +// move the player and lock him down for a little while + if (!other.health) + { + other.origin = t.origin; + other.velocity = (v_forward * other.velocity_x) + (v_forward * other.velocity_y); + return; + } + + setorigin (other, t.origin); + other.angles = t.mangle; + if (other.classname == "player") + { + other.fixangle = 1; // turn this way immediately + other.teleport_time = time + 0.7; + if (other.flags & FL_ONGROUND) + other.flags = other.flags - FL_ONGROUND; + other.velocity = v_forward * 300; + } + other.flags = other.flags - other.flags & FL_ONGROUND; +}; + +/*QUAKED info_teleport_destination (.5 .5 .5) (-8 -8 -8) (8 8 32) +This is the destination marker for a teleporter. It should have a "targetname" field with the same value as a teleporter's "target" field. +*/ +void() info_teleport_destination = +{ +// this does nothing, just serves as a target spot + self.mangle = self.angles; + self.angles = '0 0 0'; + self.model = ""; + self.origin = self.origin + '0 0 27'; + if (!self.targetname) + objerror ("no targetname"); +}; + +void() teleport_use = +{ + self.nextthink = time + 0.2; + force_retouch = 2; // make sure even still objects get hit + self.think = SUB_Null; +}; + +/*QUAKED trigger_teleport (.5 .5 .5) ? PLAYER_ONLY SILENT +Any object touching this will be transported to the corresponding info_teleport_destination entity. You must set the "target" field, and create an object with a "targetname" field that matches. + +If the trigger_teleport has a targetname, it will only teleport entities when it has been fired. +*/ +void() trigger_teleport = +{ + local vector o; + + InitTrigger (); + self.touch = teleport_touch; + // find the destination + if (!self.target) + objerror ("no target"); + self.use = teleport_use; + + if (!(self.spawnflags & SILENT)) + { + precache_sound ("ambience/hum1.wav"); + o = (self.mins + self.maxs)*0.5; + ambientsound (o, "ambience/hum1.wav",0.5 , ATTN_STATIC); + } +}; + + + +/* +============================================================================== + +trigger_setskill + +============================================================================== +*/ + +void() trigger_skill_touch = +{ + if (other.classname != "player") + return; + + cvar_set ("skill", self.message); +}; + +/*QUAKED trigger_setskill (.5 .5 .5) ? +sets skill level to the value of "message". +Only used on start map. +*/ +void() trigger_setskill = +{ + InitTrigger (); + self.touch = trigger_skill_touch; +}; + + +/* +============================================================================== + +ONLY REGISTERED TRIGGERS + +============================================================================== +*/ + +void() trigger_onlyregistered_touch = +{ + if (other.classname != "player") + return; + if (self.attack_finished > time) + return; + + self.attack_finished = time + 2; + if (cvar("registered")) + { + self.message = ""; + SUB_UseTargets (); + remove (self); + } + else + { + if (self.message != "") + { + centerprint (other, self.message); + sound (other, CHAN_BODY, "misc/talk.wav", 1, ATTN_NORM); + } + } +}; + +/*QUAKED trigger_onlyregistered (.5 .5 .5) ? +Only fires if playing the registered version, otherwise prints the message +*/ +void() trigger_onlyregistered = +{ + precache_sound ("misc/talk.wav"); + InitTrigger (); + self.touch = trigger_onlyregistered_touch; +}; + +//============================================================================ + +void() hurt_on = +{ + self.solid = SOLID_TRIGGER; + self.nextthink = -1; +}; + +void() hurt_touch = +{ + if ((self.flags & FL_MONSTER) && (other.flags & FL_MONSTER)) + return; // don't hurt monsters + + if (other.takedamage) + { + self.solid = SOLID_NOT; + T_Damage (other, self, self, self.dmg); + self.think = hurt_on; + self.nextthink = time + 1; + } + + return; +}; + +/*QUAKED trigger_hurt (.5 .5 .5) ? +Any object touching this will be hurt +set dmg to damage amount +defalt dmg = 5 +*/ +void() trigger_hurt = +{ + InitTrigger (); + self.touch = hurt_touch; + if (!self.dmg) + self.dmg = 5; +}; + +//============================================================================ + +float PUSH_ONCE = 1; +void() trigger_push_touch = +{ + if (other.classname == "grenade") + other.velocity = self.speed * self.movedir * 10; + else if (other.health > 0) + { + other.velocity = self.speed * self.movedir * 10; + if (other.classname == "player") + { + if (other.fly_sound < time ) + // Begin Xmen - cl2 + + + + + + + + + if (!(self.spawnflags & 2)) // 2 = silent spawnflag + + + + + + + + + // End Xmen - cl2 + + + + + + + + + { + other.fly_sound = time + 1.5; + sound (other, CHAN_AUTO, "ambience/windfly.wav", 1, ATTN_NORM); + } + } + } + if (self.spawnflags & PUSH_ONCE) + remove(self); +}; + + +/*QUAKED trigger_push (.5 .5 .5) ? PUSH_ONCE +Pushes the player +*/ +void() trigger_push = +{ + InitTrigger (); + precache_sound ("ambience/windfly.wav"); + self.touch = trigger_push_touch; + if (!self.speed) + self.speed = 1000; +}; + +//============================================================================ + +void() trigger_monsterjump_touch = +{ + if ( other.flags & (FL_MONSTER | FL_FLY | FL_SWIM) != FL_MONSTER ) + return; + +// set XY even if not on ground, so the jump will clear lips + other.velocity_x = self.movedir_x * self.speed; + other.velocity_y = self.movedir_y * self.speed; + + if ( !(other.flags & FL_ONGROUND) ) + return; + + other.flags = other.flags - FL_ONGROUND; + + other.velocity_z = self.height; +}; + +/*QUAKED trigger_monsterjump (.5 .5 .5) ? +Walking monsters that touch this will jump in the direction of the trigger's angle +"speed" default to 200, the speed thrown forward +"height" default to 200, the speed thrown upwards +*/ +void() trigger_monsterjump = +{ + if (!self.speed) + self.speed = 200; + if (!self.height) + self.height = 200; + if (self.angles == '0 0 0') + self.angles = '0 360 0'; + InitTrigger (); + self.touch = trigger_monsterjump_touch; +}; \ No newline at end of file diff --git a/WEAPONS.c b/WEAPONS.c new file mode 100644 index 0000000..469404b --- /dev/null +++ b/WEAPONS.c @@ -0,0 +1,3169 @@ +/* +*/ +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; + +void() player_stand1; + +// entity values for chasecam purposes +.vector last_roll; +.entity chasecam; +.float tracking_speed; +.float chasecam_zoom; +.float last_weapon_channel; + +float DEFAULT_TRACKING_SPEED = 0; +vector CHASECAM_CLOSE = '16 0 16'; +//vector CHASECAM_FAR = '20 0 48'; +float chasecam_alt, chasecam_dist = 16, chasecam_zofs = 6; + + +// 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; + + self.punchangle_y = -8; + self.punchangle_x = -4; + self.punchangle_z = 0; + + 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.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; +*/ + makevectors(other.angles); + vel = normalize(v_forward*(random() - 0.85) + v_up*(random() - 0.5) + v_right*(random() - 0.5)); + vel = vel * 300; + + return vel; +}; + +//float SLIDE_SPEED = 1; + +void() BloodWallSlide = +{ + local vector pt1; + + if (self.attack_finished < time) { + remove(self); + return; + } + + pt1 = self.origin + self.v_angle*8; + traceline(pt1, pt1 - '0 0 0.5', TRUE, self); + if (trace_fraction < 1) { + remove(self); + return; + } + + pt1 = trace_endpos; + traceline(pt1, pt1 - (self.v_angle*12), TRUE, self); + setorigin(self, trace_endpos); +//bprint("blood wall slide\n"); + self.last_blood_think = time; + self.nextthink = time + 0.1; +}; + +void() BloodTouch = +{ + local vector dir; + + if (other != world) { + remove(self); + return; + } + +//bprint("blood touch\n"); + + dir = normalize(self.velocity); + makevectors(dir); + traceline(self.origin - dir*4, self.origin + dir*12, TRUE, self); + if ((trace_fraction < 1) && (fabs(trace_plane_normal_z) < 0.2)) { + // start sliding down wall + self.movetype = MOVETYPE_NONE; + self.velocity = '0 0 0'; + self.v_angle = trace_plane_normal; + self.last_blood_think = time; + self.frame = self.frame + 1; + self.think = BloodWallSlide; + self.nextthink = time + 0.1; + self.attack_finished = time + 7; + self.angles = vectoangles(trace_plane_normal); + } +}; + +/* +================ +SpawnMeatSpray +================ +*/ +void(vector org, vector vel) SpawnMeatSpray = +{ + local entity missile, mpuff; + local vector org; + + missile = spawn (); + missile.owner = self; + missile.movetype = MOVETYPE_BOUNCE; + missile.solid = SOLID_BBOX; + + makevectors (self.angles); + + missile.velocity = vel; + missile.velocity_z = missile.velocity_z + 150 + 50*random(); + + missile.avelocity = '300 100 200'; + + missile.touch = BloodTouch; + +// set missile duration + missile.nextthink = time + 5; + missile.think = SUB_Remove; + + setmodel (missile, "progs/blood.mdl"); + setsize (missile, '0 0 0', '0 0 0'); + setorigin (missile, org); +}; + +/* +================ +SpawnBlood +================ +*/ +void(vector org, vector vel, float damage) SpawnBlood = +{ + local vector vrand, vect; + local float num_gibs; + + particle (org, vel* -0.1, 73, damage*2); + + if (deathmatch) { // preserve bandwidth + return; + } + + num_gibs = ceil(damage / 15); + + while (num_gibs > 0) { + vrand = '8 0 0' * random() + '0 8 0' * random() + '0 0 4' * random() - '4 4 2'; + vect = normalize(vrand + vel); + SpawnMeatSpray(org + vect*24, vect*(100 + random()*400)); + num_gibs = num_gibs - 1; + } +}; + +/* +================ +spawn_touchblood +================ +*/ +void(float damage) spawn_touchblood = +{ + local vector vel, vrand; + local float num_gibs; + + vel = wall_velocity () * 0.2; + + if (deathmatch) { + SpawnBlood (self.origin + vel*0.01, vel, damage); + return; + } + + num_gibs = damage / 10; + + while (num_gibs > 0) { + vrand = '8 0 0' * random() + '0 8 0' * random() + '0 0 4' * random() - '4 4 2'; + SpawnMeatSpray(self.origin + vrand + vel*0.01, vel + vrand*20); + num_gibs = num_gibs - 1; + } +}; + + +/* +================ +SpawnChunk +================ +*/ +void(vector org, vector vel) SpawnChunk = +{ +// particle (org, vel*0.02, 0, 10); + SpawnBlood(org, vel*0.02, 5); +}; + +/* +============================================================================== + +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(entity ent, float num_gibs) IcemanShardGib; +void(float damage, vector dir) TraceAttack = +{ + local vector vel, org; + + vel = normalize(dir*5 + v_up*random() + v_right*crandom()); +// vel = vel + 2*trace_plane_normal; +// vel = normalize(vel); + + org = trace_endpos - dir*4; + + if (trace_ent.takedamage) + { + org = trace_ent.origin; + if ((trace_ent.classname != "xmen_sinister") || (trace_ent.x_flags & X_MEGA_HIT)) { + if ((trace_ent.classname != "xmen_iceman") && (trace_ent.character != CHAR_ICEMAN)) { + if ((trace_ent.flags & FL_MONSTER) || + (trace_ent.flags & FL_CLIENT)) { + if (random() < 0.8) + SpawnBlood (org, vel * 12, damage); + else + SpawnBlood (org, vel * -2, damage); + } + } + else { + IcemanShardGib(trace_ent, damage / 6); + } + } + + 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 + '0 0 12'; + 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 float rnd; + local vector dir; + + if (self.currentammo <= 1) + self.currentammo = self.ammo_shells = 0; + else + self.currentammo = self.ammo_shells = self.ammo_shells - 1; + + sound (self ,CHAN_WEAPON, "weapons/shotfir6.wav", 1, ATTN_NORM); + + self.punchangle_x = -8; + + dir = aim (self, 100000); + FireBullets (7, dir, '0.06 0.06 0'); + + if (vlen(self.velocity) < 10) { // add some bounce if stationery + self.velocity = self.velocity + '0 0 150'; + } + + v_forward_z = 0; + self.velocity = self.velocity - (v_forward * 40); + +}; + + +/* +============================================================================== + +ROCKETS + +============================================================================== +*/ + +void() s_explode1 = [0, s_explode2] {}; +void() s_explode2 = [1, s_explode3] {self.effects = self.effects | EF_DIMLIGHT;}; +void() s_explode3 = [2, s_explode4] {}; +void() s_explode4 = [3, s_explode5] {self.effects = self.effects - EF_DIMLIGHT;}; +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 == "xmen_storm") + 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 (); +}; + +void() cannon_xatta16; +void() T_GuidedMissileTouch = +{ + local float damg; + + if (other == self.owner) + return; // don't explode on owner + + if (pointcontents(self.origin) == CONTENT_SKY) + { + remove(self); + return; + } + + if (self.dmg == 0) + damg = 35 + random()*5; + else + damg = self.dmg; + + if (self.classname == "dm_phoenix_blast") + damg = damg / 2; + + if (self.classname == "phoenix_blast") + damg = damg / 2; + + if ((other.classname == "xmen_cannonball") && (other.flags & FL_GODMODE)) { + if (other.last_rocket_hit > (time - 0.5)) { + other.x_flags = other.x_flags | X_CANNONFLYABORT; +// other.think = cannon_xatta16; + } + + } + + if (other != world) + other.last_rocket_hit = time; + + if (other.health) + { + if (!(other.x_flags & X_ANGEL_DEFENSE)) + T_Damage (other, self, self.owner, damg ); + + if ((other.movetype) && (other.flags & FL_ONGROUND) && (other.classname != "apocalypse_small") && (other.classname != "xmen_sinister")) { // give some velocity + other.velocity = other.velocity + normalize(self.velocity) * 180; + if (other.velocity_z < 140) + other.velocity_z = 140; + other.flags = other.flags - (other.flags & FL_ONGROUND); + setorigin(other, other.origin + '0 0 1'); + } + } + + if (self.classname != "phoenix_blast") { + // don't do radius damage to the other, because all the damage + // was done in the impact + T_RadiusDamage (self, self.owner, 40, other); + } + + sound (self, CHAN_WEAPON, "weapons/r_exp3.wav", 0.6, ATTN_NORM); + self.origin = self.origin - 8*normalize(self.velocity); + + BecomeExplosion (); +}; + +/******************************* + FindSightEnemy + Returns an entity that is within "angle_range" of "dir" + use filter_classname to exclude all entitys with the given classname + from being returned (use "world" to for to include all classes) + *******************************/ + +entity(vector org, vector dir, float dist, float angle_range, string filter_class, entity ignore) FindSightEnemy = +{ + local entity trav; + local float trav_yaw, dir_yaw; + + dir_yaw = vectoyaw(dir); + + trav = findradius(org, dist); + + while (trav != world) { + if (((filter_class == "all") || (filter_class == trav.classname)) && (trav != ignore) && ((ignore != world) && (trav != ignore.owner))) { + if ((trav.takedamage == DAMAGE_AIM) + && (trav.health > 0)) { + + // make sure trav is within the angle_range + trav_yaw = vectoyaw(trav.origin - org); + if (fabs(angle_diff(dir_yaw, trav_yaw)) <= angle_range) { + // check there is a clear line of sight + traceline(org, trav.origin, TRUE, world); + if (trace_fraction == 1) { + return trav; + } + } + } + } + + trav = trav.chain; + } + + return trav; +}; + +void() T_MissileTouch; + +// lower weight, means more accurate +void(vector target_org, float weight) RocketSeek = +{ + local float current_speed; + local vector target_vector, vel, unit_velocity; + + current_speed = vlen(self.velocity); + + target_vector = normalize(target_org - self.origin); + unit_velocity = normalize(self.velocity); + self.velocity = normalize(target_vector + unit_velocity*weight) * current_speed; + vel = normalize(self.velocity); + self.angles = vectoangles(vel); + + self.nextthink = time + 0.05; +}; + +void() GuidedRocketThink = +{ + local vector dir, new_targ, reflect, endpos; + local float interdist; + + if (self.attack_finished < time) { + remove(self); + return; + } + + dir = normalize(self.velocity); + self.angles = vectoangles(dir); + self.angles_x = -1 * self.angles_x; + + if (self.classname == "prox_missile") + particle(self.origin, self.velocity * 0.5, 44, 10); + + if (self.enemy != world) { + if ((self.enemy.health <= 0) || + ((self.enemy.classname == "xmen_phoenix") && + (self.enemy.flags & FL_GODMODE))) { + self.enemy = world; + } + else + { + traceline(self.origin, self.enemy.origin, TRUE, self); + if (trace_fraction == 1) { // clear path + if (self.classname == "prox_missile") + RocketSeek(self.enemy.origin, 0.5); + else if (self.classname == "dm_phoenix_blast") + RocketSeek(self.enemy.origin, 8); + else + RocketSeek(self.enemy.origin, 5); + return; + } + } + } + else if ((self.enemy == world) && (self.last_guided_search < (time - 0.2))) // search for a new target every 0.5 seconds + { + makevectors(self.angles); + dir = v_forward; + + if (self.classname == "pheonix_blast") + self.enemy = FindSightEnemy(self.origin, dir, 1500, 30, "player", self); + else + self.enemy = FindSightEnemy(self.origin, dir, 1500, 30, "all", self); + self.last_guided_search = time; + } + + // avoid walls + dir = normalize(self.velocity); + traceline(self.origin, self.origin + dir*256, TRUE, self); + if ((trace_fraction < 1) && (trace_ent == world)) { // heading for a wall + endpos = trace_endpos; + interdist = 256 * trace_fraction; +// reflect = GetReflectionVect(trace_endpos, dir, trace_plane_normal); + new_targ = endpos + trace_plane_normal * interdist; + RocketSeek(new_targ, 3); + return; + } + + self.nextthink = time + 0.05; +}; + +void() GuidedRocketStart = +{ + local entity missile_enemy; + local vector dir; + + dir = normalize(self.velocity); + + if (self.enemy == world) { + if ((missile_enemy = FindSightEnemy(self.origin, dir, 1500, 30, "all", self.owner)) != world) { + self.enemy = missile_enemy; + + if (missile_enemy.th_guard) { + if (missile_enemy.enemy == self.owner) { // alert Enemy + missile_enemy.guard_flag = TRUE; + } + } + } + else { + self.velocity = self.old_velocity + normalize(self.velocity) * 3; + self.velocity = normalize(self.velocity); + self.angles = vectoangles(self.velocity); + self.angles_x = -1 * self.angles_x; + self.velocity = self.velocity * 500; + } + } + + self.think = GuidedRocketThink; + self.nextthink = time + 0.05; +}; + +void(vector origdir, vector ofs) GuidedMissile = +{ + local entity missile, missile_enemy; + local vector dir; + + missile = spawn (); + missile.classname = "guided_rocket"; + missile.attack_finished = time + 3; + missile.owner = self; + missile.movetype = MOVETYPE_FLYMISSILE; + missile.solid = SOLID_BBOX; + +// dir = normalize(origdir); + + dir = v_forward; + + if ((missile_enemy = FindSightEnemy(missile.origin, dir, 1500, 30, "all", self)) != world) { + self.enemy = missile_enemy; + + if (missile_enemy.th_guard) { + if (missile_enemy.enemy == self) { // alert Enemy + missile_enemy.guard_flag = TRUE; + } + } + } + missile.think = GuidedRocketStart; + missile.last_guided_search = time; + missile.nextthink = time + 0.3; + + missile.old_velocity = normalize(origdir); + +// set missile speed + + missile.velocity = dir; + missile.velocity = missile.velocity * 500; + missile.angles = vectoangles(missile.velocity); + + missile.touch = T_GuidedMissileTouch; + + setmodel (missile, "progs/missmall.mdl"); + setsize (missile, '0 0 0', '0 0 0'); + setorigin (missile, self.origin + origdir + ofs + v_forward * 8 + '0 0 16'); +}; + +void() W_FireGuidedRockets = +{ + if (self.ammo_rockets <= 2) + self.currentammo = self.ammo_rockets = 0; + else + self.currentammo = self.ammo_rockets = self.ammo_rockets - 2; + + sound (self, CHAN_WEAPON, "weapons/guidfire.wav", 1, ATTN_NORM); + self.punchangle_x = -12; + + makevectors (self.v_angle); +/* + GuidedMissile(v_forward*3 + v_up); + GuidedMissile(v_forward*3 + v_right); + GuidedMissile(v_forward*3 - v_right); +*/ +// GuidedMissile(v_forward*5 - v_right); +// GuidedMissile(v_forward*5 + v_right); + GuidedMissile(v_right * 2, v_right * 6); + GuidedMissile(v_right * -2, v_right * 6); +}; + +/* +================ +W_FireRocket +================ +*/ +void() W_FireRocket = +{ + local entity missile, mpuff; + +// self.currentammo = self.ammo_rockets = self.ammo_rockets - 3; + +// 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'); + + W_FireGuidedRockets(); +}; + +/* +=============================================================================== + +LIGHTNING + +=============================================================================== +*/ + +.float remove_time; + +void() bolt_think = +{ + self.angles_z = random() * 340 - 170; + + if (self.remove_time < time) + { + remove(self); + return; + } + + self.frame = self.speed; + self.nextthink = time + 0.05; +}; + +void(vector start, vector end, string modelstr, vector angle_ofs, float bolt_life) FillBetweenPoints = +{ + local vector org, dir, dir_angle; + local float dist; + local entity newbolt; + + dist = vlen(start - end); + dir = normalize(end - start); + dir_angle = vectoangles(dir); + org = start; + + while (vlen(org - start) < dist) + { +//bprint("b"); + newbolt = spawn(); + setmodel(newbolt, modelstr); + setorigin(newbolt, org); + newbolt.frame = 0; //frame_num; + newbolt.speed = 0; //frame_num; + newbolt.angles = dir_angle + angle_ofs; + newbolt.angles_z = random() * 340 - 170; + newbolt.remove_time = time + bolt_life; //0.07; + newbolt.think = bolt_think; + newbolt.nextthink = time + 0.05; + + if (modelstr == "progs/bolt3.mdl") + org = org + dir*128; + else + org = org + dir*32; + + } +//bprint("\n"); +}; + +/* +================= +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(vector org_start, vector dir_start) ReflectLightning = +{ + local float reflect_count, NUM_REFLECTIONS, frac, total_dist, MAX_DIST, length; + local vector org, dir, normal, endpos; + local entity ent, junction; +local string str; + + NUM_REFLECTIONS = 2; + MAX_DIST = 800; + + org = org_start; + dir = dir_start; + reflect_count = 0; + total_dist = 0; + junction = self; + + while (reflect_count <= NUM_REFLECTIONS) { + traceline (org, org + dir*600, FALSE, self); + frac = trace_fraction; + ent = trace_ent; + normal = trace_plane_normal; + endpos = trace_endpos; + + length = vlen(endpos - org); + if ((total_dist + length) > MAX_DIST) { + endpos = org + dir * (MAX_DIST - total_dist); + reflect_count = NUM_REFLECTIONS; + } + +// if (trace_fraction < 0.05) +// return; + + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_LIGHTNING2); + WriteEntity (MSG_BROADCAST, junction); + WriteCoord (MSG_BROADCAST, org_x); + WriteCoord (MSG_BROADCAST, org_y); + WriteCoord (MSG_BROADCAST, org_z); + WriteCoord (MSG_BROADCAST, endpos_x); + WriteCoord (MSG_BROADCAST, endpos_y); + WriteCoord (MSG_BROADCAST, endpos_z); + + LightningDamage (org, endpos + dir*4, self, 30 * (1 - (total_dist/480))); // lose power over distance + +//str = ftos(frac); +//bprint(str); +//bprint("\n"); + if ((frac < 1) && (ent == world)) { + org = endpos; + dir = GetReflectionVect(org, dir, normal); + + reflect_count = reflect_count + 1; + } + else { + reflect_count = NUM_REFLECTIONS + 1; + total_dist = MAX_DIST; + } + +// junction = junction.beam_ent; + } +}; + +void() W_FireLightning = +{ + local vector org; + local float cells; + + stuffcmd(self, "bf\n"); + self.punchangle = '-10 0 0' + '10 0 0' * random() + '0 10 0' * random() + '0 0 10' * random() - '5 5 5'; + +// self.currentammo = self.ammo_cells = self.ammo_cells - 1; + + org = self.origin + '0 0 16'; + + makevectors(self.v_angle); + + traceline(org, org + v_forward * 1000, FALSE, 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); + + if ((trace_ent != world) && + !(trace_ent.x_flags & X_MEGA_HIT) && + ((trace_ent.owner.classname == "xmen_apocalypse") || + (trace_ent.classname == "xmen_sinister"))) { + T_Damage(trace_ent, self, self, 5000); + } + +}; + +void() ProximityAttack = +{ + local vector vect; + local float dist; + local entity ent, oself; + + if (other == world) { + remove(self); + return; + } + + if (other != self.enemy) + return; + + ent = self.enemy; + +// oself = self; +// self = self.owner; + + vect = normalize(ent.origin - self.oldorigin); + dist = vlen(ent.origin - self.oldorigin); + + if (dist > 200) + dist = 200; + + if ((ent.classname != "apocalypse_small") && (ent.classname != "xmen_sinister")) + ent.velocity = ent.velocity + vect * (200 - dist) + '0 0 180'; + + ent.flags = ent.flags - (ent.flags & FL_ONGROUND); + + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_EXPLOSION); + WriteCoord (MSG_BROADCAST, ent.origin_x); + WriteCoord (MSG_BROADCAST, ent.origin_y); + WriteCoord (MSG_BROADCAST, ent.origin_z); + + SpawnBlood (ent.origin, '0 0 0', 20); + + if ((ent.classname == "xmen_sinister") || (ent.classname == "apocalypse_small")) + self.prox_power = self.prox_power / 5; + + T_Damage(ent, self, self.owner, ent.start_health * (self.prox_power / 100) + 10); + +// self = oself; + remove(self); +}; + +void() ProximityThink = +{ + // remove if player is dead + if ((self.owner.health <= 0) || (self.modelindex == index_skeleton) || (intermission_running)) { + self.owner.prox_ent = world; + remove(self); + return; + } + + if (self.owner.last_prox_think < (time - 5)) { + self.owner.prox_ent = world; + remove(self); + return; + } + + self.frame = self.frame + 1; + if (self.frame > 5) + self.frame = 0; + + if (self.last_flame_sound < (time - 0.75)) { + if (random() < 0.5) + sound(self, CHAN_AUTO, "weapons/prox1.wav", self.owner.prox_power / 100, ATTN_NORM); + else + sound(self, CHAN_AUTO, "weapons/prox2.wav", self.owner.prox_power / 100, ATTN_NORM); + + self.last_flame_sound = time; + } + + if (self.last_flame < (time - 0.05)) { // increase power + if ((self.owner.currentammo > 0) && (self.owner.prox_power < 100)) { + self.owner.currentammo = self.owner.ammo_cells = self.owner.ammo_cells - 1; + self.owner.prox_power = self.owner.prox_power + 1; + + if ((self.owner.currentammo > 0) && (self.owner.prox_power < 100)) { + self.owner.currentammo = self.owner.ammo_cells = self.owner.ammo_cells - 1; + self.owner.prox_power = self.owner.prox_power + 1; + } + if ((self.owner.currentammo > 0) && (self.owner.prox_power < 100)) { + self.owner.currentammo = self.owner.ammo_cells = self.owner.ammo_cells - 1; + self.owner.prox_power = self.owner.prox_power + 1; + } + + // faster under rapid fire + if ((self.owner.x_flags & X_RAPID_FIRE) && (self.owner.currentammo > 0) && (self.owner.prox_power < 100)) { + self.owner.currentammo = self.owner.ammo_cells = self.owner.ammo_cells - 1; + self.owner.prox_power = self.owner.prox_power + 1; + } + if ((self.owner.x_flags & X_RAPID_FIRE) && (self.owner.currentammo > 0) && (self.owner.prox_power < 100)) { + self.owner.currentammo = self.owner.ammo_cells = self.owner.ammo_cells - 1; + self.owner.prox_power = self.owner.prox_power + 1; + } + + if ((self.model == "progs/atom1.mdl") && (self.owner.prox_power > 40)) + setmodel(self, "progs/atom2.mdl"); + else if ((self.model == "progs/atom2.mdl") && (self.owner.prox_power > 70)) + setmodel(self, "progs/atom3.mdl"); + + self.last_flame = time; + } + else if ((self.owner.prox_power >= 50) && (self.last_flame < (time - 3))) { + T_Damage(self.owner, world, world, 2); + self.last_flame = time - 2; // next hurt after 1 seconds only + } + } + + if (self.movetype != MOVETYPE_BOUNCE) { + // align with owner + makevectors(self.owner.v_angle); + setorigin(self, self.owner.origin + v_forward * 24 + '0 0 22'); + } + + self.nextthink = time + 0.01; +}; + +void() StartProximity = +{ + local entity prox; + + if (self.prox_ent != world) { + remove(self.prox_ent); + self.prox_ent = world; + } + + prox = spawn(); + self.prox_ent = prox; + prox.classname = "proximity_ball"; + prox.owner = self; + prox.spawn_time = time; + + prox.movetype = MOVETYPE_FLY; + prox.avelocity = '100 0 0' * random() + '0 100 0' * random() + '0 0 100' * random() - '50 50 50'; + + setmodel(prox, "progs/atom1.mdl"); + + self.last_prox_think = time; + + prox.think = ProximityThink; + self = prox; + ProximityThink(); + self = self.owner; +}; + +void(entity targ) SpawnProxMissile = +{ + local entity missile; + local vector dir, vect; + + missile = spawn (); + missile.classname = "prox_missile"; + missile.attack_finished = time + 3; + missile.owner = self.owner; + missile.oldorigin = self.origin; + missile.movetype = MOVETYPE_FLYMISSILE; + missile.solid = SOLID_BBOX; + + missile.prox_power = self.owner.prox_power; + + dir = normalize(targ.origin - self.origin); + + dir = normalize('0 0 1' + dir * 5); + + missile.enemy = targ; + + missile.think = GuidedRocketStart; + missile.nextthink = time + 0.05; + + missile.old_velocity = dir; + +// set missile speed + + missile.velocity = dir; + missile.velocity = missile.velocity * 750; + missile.angles = vectoangles(missile.velocity); + + missile.touch = ProximityAttack; + + setmodel (missile, "progs/atomshot.mdl"); + setsize (missile, '0 0 0', '0 0 0'); + vect = normalize(self.velocity); + setorigin (missile, self.origin - vect * 8); +}; + +void() ProximityTouch = +{ + local entity trav, expthink; + local float num; + + if (other == self.owner) + return; + + sound(self, CHAN_ITEM, "items/damage2.wav", 1, ATTN_NORM); +// sound(self, CHAN_BODY, "weapons/r_exp3.wav", 0.4, ATTN_NORM); + + num = rint(6 * (self.prox_power / 100)) + 2; + + trav = findradius(self.origin, 800); + while ((trav != world) && (num > 0)) { + if ((trav.takedamage) && (trav != self.owner)) { + // check visibility + traceline(self.origin, trav.origin, TRUE, trav); + if ((trace_fraction == 1) || (trace_ent == trav)) { + + if (((trav.classname != "xmen_sinister") || (self.x_flags & X_MEGA_HIT)) && + (trav.classname != "xmen_apocalypse")) { + SpawnProxMissile(trav); + num = num - 1; + } +/* + expthink = spawn(); + expthink.enemy = trav; + expthink.owner = self.owner; + expthink.prox_power = self.prox_power; + expthink.think = ProximityAttack; + expthink.nextthink = time + vlen(trav.origin - self.origin) / 400; +*/ +// ProximityAttack(trav); + } + } + + trav = trav.chain; + } + + if (other.takedamage) + T_Damage(other, self, self, self.owner.prox_power); + + 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 (); + + self.owner.prox_ent = world; +}; + +void() W_FireProximity = +{ + local vector org; + local float cells; + local entity trav, expthink; + +/* + if (self.ammo_cells < 1) + { + self.weapon = W_BestWeapon (); + W_SetCurrentAmmo (); + return; + } + + if (self.ammo_cells > 50) { + cells = 50; + self.currentammo = self.ammo_cells = self.ammo_cells - 50; + } + else { + cells = self.ammo_cells; + self.currentammo = self.ammo_cells = 0; + } +*/ + + if (self.prox_ent == world) // nothing to throw + return; + + // Throw the proxmity ball + self.prox_ent.solid = SOLID_TRIGGER; + self.prox_ent.movetype = MOVETYPE_FLYMISSILE; + setsize(self.prox_ent, '0 0 0', '0 0 0'); + self.prox_ent.touch = ProximityTouch; + self.prox_ent.prox_power = self.prox_power; + self.prox_ent.think = SUB_Null; + + makevectors(self.v_angle); +// self.prox_ent.velocity = self.velocity + (v_forward*2 + v_up*0.5) * 50 + '0 0 80'; + self.prox_ent.velocity = v_forward * 750; + + self.attack_finished = time + 2; + +// stuffcmd(self, "bf\n"); + + sound(self, CHAN_ITEM, "cannon/takeoff.wav", 1, ATTN_NORM); + +/* + sound(self, CHAN_WEAPON, "items/damage2.wav", 1, ATTN_NORM); + sound(self, CHAN_BODY, "weapons/r_exp3.wav", 0.4, ATTN_NORM); + + trav = findradius(self.origin, 800); + while (trav != world) { + if ((trav.takedamage) && (trav != self)) { + // check visibility + traceline(self.origin, trav.origin, TRUE, trav); + if ((trace_fraction == 1) || (trace_ent == trav)) { + expthink = spawn(); + expthink.enemy = trav; + expthink.owner = self; + expthink.think = ProximityAttack; + expthink.nextthink = time + vlen(trav.origin - self.origin) / 400; + +// ProximityAttack(trav); + } + } + + trav = trav.chain; + } +*/ +}; + +//============================================================================= + + +void() GrenadeExplode = +{ + T_RadiusDamage (self, self.owner, 60, 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); +*/ + if ((other.movetype) && (other.flags & FL_ONGROUND) && (other.classname != "xmen_sinister") && (other.classname != "apocalypse_small")) { // give some velocity + other.velocity = other.velocity + normalize(self.velocity) * 100 + '0 0 220'; + other.flags = other.flags - (other.flags & FL_ONGROUND); + setorigin(other, other.origin + '0 0 1'); + } + + sound(self, CHAN_WEAPON, "weapons/r_exp3.wav", 1, ATTN_NORM); + + BecomeExplosion (); +}; + +void() GrenadeTouch = +{ + if (other == self.owner) + return; // don't explode on owner + + if ((other.classname == "xmen_phoenix") && + (other.flags & FL_GODMODE)) + return; + + if ((other.takedamage == DAMAGE_AIM) && !(other.x_flags & X_ANGEL_DEFENSE)) + { + GrenadeExplode(); + return; + } + + sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); // bounce sound + if (self.velocity == '0 0 0') + self.avelocity = '0 0 0'; +}; + +/* +================ +W_FireGrenade +================ +*/ +void() W_FireGrenade = +{ + local entity missile, mpuff, phoenix; + + if (self.ammo_rockets > 0) + 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 = "orb"; + +// set missile speed + + makevectors (self.v_angle); + + if (self.v_angle_x) + missile.velocity = v_forward*900 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10; + else + { + missile.velocity = aim(self, 10000); + missile.velocity = missile.velocity * 900; + missile.velocity_z = 200; + } + + missile.avelocity = '300 300 300'; + + missile.angles = vectoangles(missile.velocity); + + missile.touch = GrenadeTouch; + +// set missile duration + missile.nextthink = time + 2.5; + missile.think = GrenadeExplode; + + setmodel (missile, "progs/orb1.mdl"); + setsize (missile, '0 0 0', '0 0 0'); + setorigin (missile, self.origin + v_right * 6 + v_forward * 16); + + missile.old_velocity = missile.velocity; + + // check for Pheonix defence + phoenix = find(world, classname, "xmen_phoenix"); + while (phoenix != world) { + if (phoenix.enemy == self) + phoenix.guard_flag = TRUE; + + phoenix = find(phoenix, classname, "xmen_phoenix"); + } + +}; + + +//============================================================================= + +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(float ox) W_FireSuperSpikes = +{ + local vector dir; + local entity old; + local string sample; + local float shells; + + sample = "weapons/chnfire5.wav"; + + if (self.last_weapon_channel != CHAN_WEAPON) { + sound (self, CHAN_WEAPON, sample, 1, ATTN_NORM); + self.last_weapon_channel = CHAN_WEAPON; + } else { + sound (self, CHAN_ITEM, sample, 1, ATTN_NORM); + self.last_weapon_channel = CHAN_ITEM; + } + + self.attack_finished = time + 0.2; + + if (random() < 0.5) + shells = 1; + else + shells = 2; + + dir = aim (self, 100000); + + if (self.ammo_shells <= shells) { + self.currentammo = self.ammo_shells = 0; + } + else { + self.currentammo = self.ammo_shells = self.ammo_shells - shells; + } + + FireBullets (shells, dir, '0.04 0.04 0'); + +/* + self.currentammo = self.ammo_shells = self.ammo_shells - 1; + dir = aim (self, 1000); + launch_spike (self.origin + '0 0 16' + ox * v_right, 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; + local entity old; + + makevectors (self.v_angle); + + if (self.weapon == IT_SHOTGUN) + { + 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; +}; + + +/* +=============== + Lazer Gun stuff +=============== +*/ +void() Flameball_Touch = +{ + local vector org; + + if (other == self.owner) + return; // don't explode on owner + + if (pointcontents(self.origin) == CONTENT_SKY) + { + remove(self); + return; + } + +// sound (self, CHAN_WEAPON, "enforcer/enfstop.wav", 1, ATTN_STATIC); + org = self.origin - 8*normalize(self.velocity); + if ((other.health) && (other.classname != "xmen_bishop")) + { + SpawnBlood (org, self.velocity*0.2, 12); + T_Damage (other, self, self.owner, 12); + } + 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); + } + + self.origin = self.origin - 8*normalize(self.velocity); + + BecomeExplosion (); + +}; + + +void() FlameballThink = +{ + self.angles_z = (random() * 360) - 180; + + if (self.spawn_time < (time - 6)) { + remove(self); + return; + } + + self.nextthink = time + 0.1; +}; + +void(vector org, vector dir) Launch_Flameball = +{ + newmis = spawn (); + newmis.owner = self; + newmis.movetype = MOVETYPE_FLYMISSILE; + newmis.solid = SOLID_BBOX; + + newmis.angles = vectoangles(dir); + + newmis.touch = Flameball_Touch; + newmis.classname = "flameball"; + newmis.think = FlameballThink; + newmis.nextthink = time + 0.1; + setmodel (newmis, "progs/flamball.mdl"); + setsize (newmis, VEC_ORIGIN, VEC_ORIGIN); + setorigin (newmis, org); + newmis.spawn_time = time; + newmis.angles_z = (random() * 360) - 180; + + newmis.velocity = dir * 1500; +}; + + + +// X-Men: fires a laser projectile +void(float ox) W_FireFlameball = +{ + local vector dir; + local entity old; + local string sample; + + makevectors (self.v_angle); + + sample = "weapons/f_start.wav"; + + if (self.last_weapon_channel != CHAN_WEAPON) { + sound (self, CHAN_WEAPON, sample, 1, ATTN_NORM); + self.last_weapon_channel = CHAN_WEAPON; + } else { + sound (self, CHAN_ITEM, sample, 1, ATTN_NORM); + self.last_weapon_channel = CHAN_ITEM; + } + + if (self.ammo_nails < 1) + { + self.weapon = W_BestWeapon (); + W_SetCurrentAmmo (); + return; + } + +// sound (self, CHAN_WEAPON, "enforcer/enfire.wav", 1, ATTN_NORM); + self.attack_finished = time + 0.2; + self.currentammo = self.ammo_nails = self.ammo_nails - 1; + dir = v_forward; + Launch_Flameball (self.origin + '0 0 16' + v_right*4, dir); + + self.punchangle_x = -2; +}; + + +.float hit_z; +void() spike_touch = +{ +local float rand, damg; + local vector vect; + + if ((other == self.owner) || (other.owner == 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) + { + if (!self.dmg) + damg = 9; + else + damg = self.dmg; + + spawn_touchblood (damg); + T_Damage (other, self, self.owner, damg); + + remove(self); + return; + } + else if (self.classname == "angel_dart") { + vect = normalize(self.velocity); + setorigin(self, self.origin + vect*2); + + self.velocity = '0 0 0'; + self.solid = SOLID_NOT; + self.movetype = MOVETYPE_NONE; + + self.think = SUB_Remove; + self.nextthink = time + 5; + + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_SPIKE); + WriteCoord (MSG_BROADCAST, self.origin_x); + WriteCoord (MSG_BROADCAST, self.origin_y); + WriteCoord (MSG_BROADCAST, self.origin_z); + + return; + } + + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + + if (self.classname == "wizspike") + WriteByte (MSG_BROADCAST, TE_WIZSPIKE); + else if (self.classname == "gambit_card") + 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 = +{ +local float rand; + 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) + { + 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); + +}; + +/* +================ +W_FireFlameThrower +================ +*/ + +void(float num_bubbles) DeathBubbles; +void() W_FireFlameThrower = +{ + local string sample; + + if (self.classname == "player") { + if (self.ammo_nails < 1) + { + self.weapon = W_BestWeapon (); + W_SetCurrentAmmo (); + return; + } + + if (self.ammo_nails < 4) + self.ammo_nails = 0; + else + self.ammo_nails = self.ammo_nails - 4; + + self.currentammo = self.ammo_nails; + + if (self.waterlevel >= 3) { // can't fire while underwater + self.flags = self.flags - (self.flags & FL_FLAMEON); + self.water_flame_flag = TRUE; + DeathBubbles(1); + return; + } + } + + sample = "weapons/flame.wav"; + + if (self.last_flame_sound < (time - SNDLEN_FLAME)) { + if (self.last_weapon_channel != CHAN_WEAPON) { + sound (self, CHAN_WEAPON, sample, 1, ATTN_NORM); + self.last_weapon_channel = CHAN_WEAPON; + } else { + sound (self, CHAN_ITEM, sample, 1, ATTN_NORM); + self.last_weapon_channel = CHAN_ITEM; + } + + self.last_flame_sound = time + (random() * 0.2) - 0.05; + } + + if (!(self.flags & FL_FLAMEON)) + { +//bprint("starting flame..\n"); + setorigin(self.flame_ent1, self.origin + v_forward * 16); + setorigin(self.flame_ent2, self.origin + v_forward * 16); + setorigin(self.flame_ent3, self.origin + v_forward * 96); + self.flame_ent1.nextthink = time + 0.05; + self.flame_ent1.speed = 0; + self.flame_ent2.speed = 0; + self.flame_ent3.speed = 0; + + setmodel(self.flame_ent1, "progs/fl_th1.mdl"); + setmodel(self.flame_ent2, "progs/null.spr"); + setmodel(self.flame_ent3, "progs/fl_th5.mdl"); + } + + if (self.water_flame_flag) { + self.flags = self.flags | FL_FLAMEON; + self.water_flame_flag = FALSE; + } + + self.last_flame = time; +}; + +void(entity ent, vector pos, float dist) movetopos = +{ + local vector vect; + + if (vlen(ent.origin - pos) > dist) { + vect = normalize(pos - ent.origin); + setorigin(ent, ent.origin + vect * dist); + } + else + { + setorigin(ent, pos); + } +}; + +void(vector p1, vector p2) FlameParticles = +{ + local float rcol, rnd; + local vector vect, avect, rvect, org, vel; + + // random color between 228 - 233 + rnd = random(); + rcol = 228 + floor(rnd * 2); + + // do vector stuff + vect = normalize(p2 - p1); + avect = vectoangles(vect); + avect_x = -1 * vect_x; + + makevectors(avect); + + rvect = ('1 0 0' * random()) + ('0 1 0' * random()) + ('0 0 1' * random()) - '0.5 0.5 0.5'; + + org = p1 + + v_forward * 32 + + v_forward * rnd * FLAME_DIST * 0.5; + + vel = normalize(v_forward + (rvect * 0.3) + '0 0 0.2') * 20; + + particle( org, v_forward * 10, 235, 20); + particle( org, vel, rcol, 50); + + // flame_ent_think() requires the following line.. + makevectors(self.owner.v_angle); +}; + +void() flame_ent_think = +{ + local entity ent, ent_parent; + local vector vect, ideal_pnt, ofs, oldangles; + local float this_dist, this_speed, dist_from, dist1, dist2, short_flag; + local entity ent_burn; + + short_flag = FALSE; + + // set flame distance + if (!(self.owner.flags & FL_FLAMEON)) { +//bprint("stopping flame..\n"); +// if ((vlen(self.origin - self.owner.origin) < 32) || +// (self.owner.last_flame < (time - 1))) { // flame has run out + + setmodel(self.owner.flame_ent1, string_null); + setmodel(self.owner.flame_ent2, string_null); + setmodel(self.owner.flame_ent3, string_null); + + self.owner.flame_ent1.effects = 0; + self.owner.flame_ent2.effects = 0; + self.owner.flame_ent3.effects = 0; + + self.nextthink = -1; + return; +// } + + this_dist = -2 * FLAME_DIST; + + self.speed = self.speed - (FLAME_ENT_SPEED * frametime * 0.5); + if (self.speed < 0) + self.speed = 0; + } + else { + this_dist = FLAME_DIST; + } + + self.nextthink = time + 0.05; + + ent_burn = world; + makevectors(self.owner.v_angle); + + ofs = v_forward * 32 + v_right * 10 + '0 0 36' - v_up * 28; + if (self.owner.character == CHAR_STORM) + ofs_z = ofs_z + STORM_VOFS_Z; + +// move 1st junction to ideal position **************************************************** + ent = self; + ent_parent = self.owner; + traceline(ent_parent.origin + ofs - v_forward * 32, ent_parent.origin + ofs + v_forward * this_dist * 0.5, FALSE, self.owner); + + dist_from = vlen(ent.origin - trace_endpos); + +// ent.angles = vectoangles(v_forward); +// ent.angles_z = (360 * random()) - 180; + ent.angles = self.owner.v_angle; + ent.angles_x = -1 * ent.angles_x; + ent.angles_z = random() * 360 - 180; + + movetopos(ent, trace_endpos, FLAME_ENT_SPEED * frametime); + +/* + FlameParticles(ent.owner.origin + ofs * 2 - '0 0 4', ent.origin); + FlameParticles(ent.owner.origin + ofs * 2 - '0 0 4', ent.origin); + FlameParticles(ent.owner.origin + ofs * 2 - '0 0 4', ent.origin); +*/ + + // fill with flame bits +// FillBetweenPoints(ent_parent.origin + ofs, ent.origin, "progs/fl_th1.mdl", '0 0 0', 0.07); +// ent.effects = ent.effects | EF_MUZZLEFLASH; + if (ent.speed < FLAME_DIST) { + ent.speed = ent.speed + (FLAME_ENT_SPEED * frametime * 0.5); + if (ent.speed > FLAME_DIST) + ent.speed = FLAME_DIST; + } + if (trace_fraction < 1) { + setorigin(self.owner.flame_ent2, ent.origin); + self.owner.flame_ent2.speed = 0; + setorigin(self.owner.flame_ent3, ent.origin); + self.owner.flame_ent3.speed = 0; + + if ((trace_ent != world) && (trace_ent.takedamage)) { + ent_burn = trace_ent; + } + + short_flag = TRUE; + } + +// T_RadiusDamage(ent, self.owner, 10, self.owner); + +// move 2nd junction to ideal position **************************************************** + ent_parent = self.owner.flame_ent1; + ent = self.owner.flame_ent2; + traceline(ent_parent.origin - v_forward * 2, ent_parent.origin + v_forward * this_dist, FALSE, self.owner); + + dist_from = vlen(ent.origin - trace_endpos); + + if (dist_from < 4) + ent.angles = vectoangles('0 0 1'); + else { + vect = normalize(ent.origin - trace_endpos); + ent.angles = vectoangles(vect); + } + + ent.angles_z = (360 * random()) - 180; + + this_speed = FLAME_ENT_SPEED * (dist_from / 64); + + if (this_speed > (FLAME_ENT_SPEED * 2)) + this_speed = FLAME_ENT_SPEED*2; + + movetopos(ent, trace_endpos, dist_from / 2); //this_speed * frametime); +// movetopos(ent, trace_endpos, this_speed * frametime); + + if (trace_fraction == 1) { + vect = normalize(ent.origin - ent_parent.origin); + setorigin(ent, ent_parent.origin + (vect * ent.speed)); + } + +// FlameParticles(ent.owner.origin, ent.origin); + + // fill with flame bits + dist_from = vlen(ent.origin - ent_parent.origin); + if (dist_from > 32) + FillBetweenPoints(ent_parent.origin, ent.origin - v_forward * 30, "progs/fl_th2.mdl", '0 0 0', 0.07); + ent.effects = ent.effects | EF_DIMLIGHT; + if (ent.speed < FLAME_DIST) { + ent.speed = ent.speed + (FLAME_ENT_SPEED * frametime * 0.5); + if (ent.speed > FLAME_DIST * 0.75) + ent.speed = FLAME_DIST * 0.75; + } + + if (trace_fraction < 1) { + setorigin(self.owner.flame_ent3, ent.origin); + self.owner.flame_ent3.speed = 0; + + if ((trace_ent != world) && (trace_ent.takedamage)) { + ent_burn = trace_ent; + } + + short_flag = TRUE; + } + + if (deathmatch) + T_RadiusDamage(ent, self.owner, 15, self.owner); + else + T_RadiusDamage(ent, self.owner, 10, self.owner); + + +// move 3rd junction to ideal position **************************************************** + v_forward = vect; + + ent_parent = self.owner.flame_ent2; + ent = self.owner.flame_ent3; + ideal_pnt = ent_parent.origin + v_forward * this_dist * 0.75; + traceline(ent_parent.origin - v_forward * 2, ideal_pnt, FALSE, self.owner); + + dist_from = vlen(ent.origin - trace_endpos); + +// if (dist_from < 4) +// ent.angles = vectoangles('0 0 1'); +// else { +// vect = normalize(ent.origin - trace_endpos); +// ent.angles = vectoangles(vect); +// } + +// ent.angles_z = (360 * random()) - 180; + + ent.frame = random() * 5.9; + ent.frame = floor(ent.frame); + + + dist_from = vlen(ent.origin - ideal_pnt); //trace_endpos); + this_speed = FLAME_ENT_SPEED * (dist_from / 256); + + if (this_speed > (FLAME_ENT_SPEED * 2)) + this_speed = FLAME_ENT_SPEED*2; + + this_speed = this_speed * 3; + + ent.oldorigin = ent.origin; + movetopos(ent, trace_endpos, dist_from / 3); //this_speed * frametime); + + if (vlen(ent.origin - ent_parent.origin) > this_dist * 0.75) { + vect = normalize(ent.origin - ent_parent.origin); + setorigin(ent, ent_parent.origin + (vect * this_dist * 0.75)); + } + + oldangles = ent.angles; + if ((trace_fraction == 1) && (!short_flag)) { + vect = normalize(ent.origin - ent_parent.origin); + ent.angles = vectoangles(vect); + if (ent.model != "progs/fl_th5.mdl") + setmodel(ent, "progs/fl_th5.mdl"); + } + else { + vect = normalize(ent.origin - self.owner.origin); + ent.angles = vectoangles(vect); +// ent.angles_x = ent.angles_x + 45; + if (ent.model != "progs/fl_th6.mdl") + setmodel(ent, "progs/fl_th6.mdl"); + } + +// ent.angles_x = -1 * ent.angles_x; + + // calculate Z rotation to match "sway" movement + makevectors(ent.angles); + vect = ent.origin - ent.oldorigin; + dist1 = vlen(vect + v_right); + dist2 = vlen(vect - v_right); + if ((!short_flag) && (vlen(vect) > 4)) { + if ((dist1 - dist2) > 0) { // moving towards RIGHT + ent.angles_z = MoveToAngle(oldangles_z, 320, 500); + } + else if ((dist1 - dist2) < 0) { // moving towards LEFT + ent.angles_z = MoveToAngle(oldangles_z, 40, 500); + } + } + else { // move towards 0 + ent.angles_z = MoveToAngle(oldangles_z, 0, 500); + } + + vect = normalize(ent.origin - ent.owner.origin); + dist_from = vlen(vect); + +/* + if ((vlen(ent.origin - self.owner.origin) > FLAME_DIST) || (trace_fraction < 1)) { +// if (trace_fraction == 1) { +// vect = normalize(ent.origin - ent_parent.origin); +// setorigin(ent, ent_parent.origin + (vect * ent.speed)); +// } + + if (ent.model != "progs/fl_th3.mdl") + setmodel(ent, "progs/fl_th3.mdl"); + } + else { + if (ent.model != "progs/fl_th2.mdl") + setmodel(ent, "progs/fl_th2.mdl"); + } +*/ +// FlameParticles(ent.owner.origin, ent.origin); + + // fill with flame bits +// FillBetweenPoints(ent_parent.origin + vect * (dist_from / 2), ent.origin, "progs/fl_th3.mdl", '45 0 0', 0.07); + ent.effects = ent.effects | EF_DIMLIGHT; + if (ent.speed < FLAME_DIST) { + ent.speed = ent.speed + (FLAME_ENT_SPEED * frametime * 0.5); + if (ent.speed > FLAME_DIST * 0.5) + ent.speed = FLAME_DIST * 0.5; + } + + if ((trace_ent != world) && (trace_ent.takedamage)) { + ent_burn = trace_ent; + } + + if (deathmatch) + T_RadiusDamage(ent, self.owner, 20, self.owner); + else + T_RadiusDamage(ent, self.owner, 13, self.owner); + + if (ent_burn != world && deathmatch) { + T_Damage(trace_ent, self.owner, self.owner, 8); + } + +}; + +void() SetSpecialWeaponModel = +{ + if (self.character == CHAR_WOLVERINE) { + self.weaponmodel = "progs/v_wol.mdl"; + } + else if (self.character == CHAR_STORM) { + self.weaponmodel = "progs/v_sto.mdl"; + } + else if (self.character == CHAR_CYCLOPS) { + self.weaponmodel = "progs/v_cyc.mdl"; + } + else if (self.character == CHAR_PSYLOCKE) { + self.weaponmodel = "progs/v_psy.mdl"; + } + else if (self.character == CHAR_ANGEL) { + self.weaponmodel = "progs/v_ang.mdl"; + } + else if (self.character == CHAR_BEAST) { + self.weaponmodel = "progs/v_bea.mdl"; + } + else if (self.character == CHAR_GAMBIT) { + self.weaponmodel = "progs/v_gam.mdl"; + } + else if (self.character == CHAR_ICEMAN) { + self.weaponmodel = "progs/v_ice.mdl"; + } + else if (self.character == CHAR_BISHOP) { + self.weaponmodel = "progs/v_bis.mdl"; + } + else if (self.character == CHAR_ROGUE) { + self.weaponmodel = "progs/v_rog.mdl"; + } + else if (self.character == CHAR_CANNONBALL) { + self.weaponmodel = "progs/v_can.mdl"; + } + else if (self.character == CHAR_PHOENIX) { + self.weaponmodel = "progs/v_pho.mdl"; + } + else { + self.weaponmodel = ""; + sprint(self, "ERROR: Unknown character setting\n"); + } +}; + +/* +=============================================================================== + +PLAYER WEAPON USE + +=============================================================================== +*/ + +void() SpecialWeaponChange; +void() W_SetCurrentAmmo = +{ +// player_run (); // get out of any weapon firing states + + if (self.modelindex == index_skeleton) + return; + + self.items = self.items - ( self.items & (IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS) ); + + if (self.weapon == IT_AXE) + { + self.currentammo = 0; + + if (deathmatch || coop) { + SetSpecialWeaponModel(); + } + else { + self.weaponmodel = "progs/v_xfist.mdl"; + } + } + else if (self.weapon == IT_SHOTGUN) + { + self.currentammo = self.ammo_shells; + self.weaponmodel = "progs/v_xshot1.mdl"; + self.items = self.items | IT_SHELLS; + } + else if (self.weapon == IT_SUPER_SHOTGUN) + { + self.currentammo = self.ammo_shells; + self.weaponmodel = "progs/v_xchain.mdl"; + self.items = self.items | IT_SHELLS; + } + else if (self.weapon == IT_NAILGUN) + { + self.currentammo = self.ammo_nails; + self.weaponmodel = "progs/v_xfire1.mdl"; + self.items = self.items | IT_NAILS; + } + else if (self.weapon == IT_SUPER_NAILGUN) + { + self.currentammo = self.ammo_nails; + self.weaponmodel = "progs/v_xflame.mdl"; + self.items = self.items | IT_NAILS; + } + else if (self.weapon == IT_GRENADE_LAUNCHER) + { + self.currentammo = self.ammo_rockets; + self.weaponmodel = "progs/v_xorb.mdl"; + self.items = self.items | IT_ROCKETS; + } + else if (self.weapon == IT_ROCKET_LAUNCHER) + { + self.currentammo = self.ammo_rockets; + self.weaponmodel = "progs/v_xrock.mdl"; + self.items = self.items | IT_ROCKETS; + } + else if (self.weapon == IT_LIGHTNING) + { + self.currentammo = self.ammo_cells; + self.weaponmodel = "progs/v_xshock.mdl"; + self.items = self.items | IT_CELLS; + } + else if (self.weapon == IT_SPECIAL_WEAPON) + { + self.currentammo = self.ammo_special; + self.weaponmodel = "progs/v_xmega.mdl"; + self.items = self.items | IT_CELLS; + } + else + { + self.currentammo = 0; + self.weaponmodel = ""; + } +}; + +float() W_BestWeapon = +{ + local float it; + + it = self.items; + + if(self.ammo_cells >= 1 && (it & IT_LIGHTNING) ) + return IT_LIGHTNING; + else if(self.ammo_rockets >= 1 && (it & IT_ROCKET_LAUNCHER) ) + return IT_ROCKET_LAUNCHER; + else if(self.ammo_rockets >= 1 && (it & IT_GRENADE_LAUNCHER) ) + return IT_GRENADE_LAUNCHER; + else if (self.ammo_nails >= 2 && (it & IT_SUPER_NAILGUN) ) + return IT_SUPER_NAILGUN; + else if(self.ammo_shells >= 2 && (it & IT_SUPER_SHOTGUN) ) + return IT_SUPER_SHOTGUN; + else if(self.ammo_nails >= 1 && (it & IT_NAILGUN) ) + return IT_NAILGUN; + else if(self.ammo_shells >= 1 && (it & IT_SHOTGUN) ) + return IT_SHOTGUN; + + return IT_AXE; +}; + +float() W_CheckNoAmmo = +{ + local float best; + + if (self.currentammo > 0) + return TRUE; + + if (self.weapon == IT_AXE) + return TRUE; + +// self.nextweapon = W_BestWeapon (); + +// best = W_BestWeapon (); +// SetNewWeapon(best); + +// W_SetCurrentAmmo (); + +// drop the weapon down + return FALSE; +}; + +/* +============ +W_Attack + +An attack impulse can be triggered now +============ +*/ +void() player_att1; +void() player_laser1; +void() player_flame1; +void() player_prox1; +void() player_orb; +void() player_rocket1; + +void() player_shotgun1; +void() player_chain1; +void() player_fist; +void() player_mega; + +void() W_Attack = +{ + local float r, best; + + if (self.modelindex == index_skeleton) + return; + + if (self.change_weapon_status) { // no firing during fading +// sprint(self, "can't fire, changing weapons\n"); + return; + } + + if (self.weapon_flags & W_RELOADING) { +// sprint(self, "can't fire, reloading\n"); + return; + } + + if (!W_CheckNoAmmo ()) { + best = W_BestWeapon (); + SetNewWeapon(best); + + return; + } + +/* + if ((self.weapon == IT_NAILGUN) && (self.num_lasers >= 5)) + return; + else if ((self.num_lasers > 0) && (self.weapon != IT_NAILGUN)) + self.num_lasers = 0; +*/ + + makevectors (self.v_angle); // calculate forward angle for velocity + self.show_hostile = time + 1; // wake monsters up + + if (self.weapon == IT_AXE) + { + if (deathmatch || coop) { + if ((!(self.weapon_flags & W_RELOADING)) && + ((self.character != CHAR_CANNONBALL) || (self.last_special2 < (time - 1.5)))) { + player_att1 (); + } + } + else { + player_fist(); + } + +// self.attack_finished = time + 0.5; + } + else if (self.weapon == IT_SHOTGUN) + { + if (self.think != player_shotgun1) { + self.weaponframe = 5; + player_shotgun1 (); + } + self.attack_finished = time + 0.3; + } + else if (self.weapon == IT_SUPER_SHOTGUN) + { + if (self.weaponframe > 11) + self.weaponframe = 6; + + if (time > self.w_pausetime) + self.last_pausetime = 0; + + player_chain1 (); + } + else if (self.weapon == IT_NAILGUN) + { +// self.weaponmodel = "progs/v_xlas2.mdl"; + +// player_nail1 (); + + self.fire_reload_frames = 0; + player_laser1 (); + } + else if (self.weapon == IT_SUPER_NAILGUN) + { + player_flame1(); + self.attack_finished = time + 0.1; + if (self.waterlevel < 3) { // can't fire while underwater + if (!(self.flags & FL_FLAMEON)) + sound(self, CHAN_BODY, "weapons/f_start.wav", 1, ATTN_NORM); + + self.flags = self.flags | FL_FLAMEON; + } + } + else if (self.weapon == IT_GRENADE_LAUNCHER) + { + player_orb(); +// W_FireGrenade(); + } + else if (self.weapon == IT_ROCKET_LAUNCHER) + { + player_rocket1(); +// W_FireRocket(); + W_FireGuidedRockets(); + self.attack_finished = time + 1.6; + } + else if (self.weapon == IT_LIGHTNING) + { +// if (self.prox_ent != world) +// return; + + player_prox1(); + self.attack_finished = time + 0.2; +// sound (self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM); + } + else if (self.weapon == IT_SPECIAL_WEAPON) + { + player_mega(); + self.attack_finished = time + 0.2; + sound (self, CHAN_ITEM, "weapons/m_start.wav", 1, ATTN_NORM); + sound (self, CHAN_WEAPON, "weapons/mega.wav", 1, ATTN_NONE); + } +}; + +float(float wpn) GetLastMoveFrame = +{ + if (wpn == IT_SHOTGUN) return 25; + if (wpn == IT_SUPER_SHOTGUN) return 12; + if (wpn == IT_NAILGUN) return 15; + if (wpn == IT_SUPER_NAILGUN) return 9; + if (wpn == IT_GRENADE_LAUNCHER) return 18; + if (wpn == IT_LIGHTNING) return 0; + if (wpn == IT_ROCKET_LAUNCHER) return 17; + if (wpn == IT_AXE) + if (deathmatch || coop) + return 0; + else + return 16; + + return 0; +}; + +float(float wpn) GetFirstMoveFrame = +{ + if (wpn == IT_SHOTGUN) return 30; // NOTE: frame 31 = frame 1 + if (wpn == IT_SUPER_SHOTGUN) return 17; + if (wpn == IT_NAILGUN) return 20; + if (wpn == IT_SUPER_NAILGUN) return 15; + if (wpn == IT_GRENADE_LAUNCHER) return 23; + if (wpn == IT_LIGHTNING) return 4; + if (wpn == IT_ROCKET_LAUNCHER) return 23; + if (wpn == IT_AXE) + if (deathmatch || coop) + return 5; + else + return 22; + + return 0; +}; + +// Return true if next weapon is on a different hand to the current weapon +float() ChangingHands = +{ + if ((deathmatch || coop) && (self.nextweapon == IT_AXE) && (self.weapon != IT_AXE)) + return TRUE; + + if (self.nextweapon == IT_LIGHTNING) + return TRUE; + + if (self.nextweapon == IT_SPECIAL_WEAPON) + return TRUE; + + if ((self.nextweapon & (IT_SHOTGUN | IT_SUPER_SHOTGUN | IT_AXE)) && + (self.weapon & (IT_NAILGUN | IT_SUPER_NAILGUN | IT_ROCKET_LAUNCHER | IT_GRENADE_LAUNCHER))) { + return TRUE; + } + + if ((self.nextweapon & (IT_NAILGUN | IT_SUPER_NAILGUN | IT_ROCKET_LAUNCHER | IT_GRENADE_LAUNCHER)) && + (self.weapon & (IT_SHOTGUN | IT_SUPER_SHOTGUN | IT_AXE))) { + return TRUE; + } +}; + +/* + ================= + FADE WEAPON OUT + ================= +*/ +void() FadeWeaponOut = +{ + local float newframe; + local string str; + + if (self.weapon_flags & W_RELOADING) + return; + + if (self.chasecam != world) { // change immediately + self.weapon = self.nextweapon; + if (self.weapon == IT_AXE) + SpecialWeaponChange(); + W_SetCurrentAmmo (); + self.weaponframe = newframe; + self.change_weapon_status = CW_FADEIN; + } + + self.last_fade = time; + +//bprint("fade out\n"); + if (self.weapon & (IT_NAILGUN | IT_SUPER_NAILGUN | IT_ROCKET_LAUNCHER | IT_SHOTGUN | IT_SUPER_SHOTGUN | IT_AXE | IT_GRENADE_LAUNCHER)) { + self.weaponframe = self.weaponframe - 1; + + if (self.weaponframe <= self.fadeout_endframe) { + if ((self.fadeout_endframe == 0) && (ChangingHands()) && (GetLastMoveFrame(self.weapon) > 0)) { + self.fadeout_endframe = GetLastMoveFrame(self.weapon); + self.weaponframe = GetFirstMoveFrame(self.weapon); + return; + } + + // if we're still here then weapon must have completed fading out + if (ChangingHands()) { + newframe = GetLastMoveFrame(self.nextweapon); + self.fadein_endframe = GetFirstMoveFrame(self.nextweapon); + } + else { + newframe = 0; + self.fadein_endframe = 5; // all morphing animations end at frame 5 + } + + self.weapon = self.nextweapon; + if (self.weapon == IT_AXE) + SpecialWeaponChange(); + W_SetCurrentAmmo (); + self.weaponframe = newframe; + self.change_weapon_status = CW_FADEIN; + } + } + else { + self.weaponframe = 0; + self.weapon = self.nextweapon; + if (self.weapon == IT_AXE) + SpecialWeaponChange(); + W_SetCurrentAmmo (); + self.change_weapon_status = CW_FADEIN; + } +}; + +/* + ================= + FADE WEAPON IN + ================= +*/ +void() FadeWeaponIn = +{ + local string str; + + if (self.chasecam != world) { // change immediately + self.weaponframe = self.weapon_idleframe; + self.change_weapon_status = CW_DONE; + return; + } + + self.last_fade = time; + + if (self.weapon & (IT_SHOTGUN | IT_SUPER_SHOTGUN | IT_NAILGUN | IT_SUPER_NAILGUN | IT_AXE | IT_GRENADE_LAUNCHER | IT_ROCKET_LAUNCHER)) { + self.weaponframe = self.weaponframe + 1; + + if (self.weaponframe >= self.fadein_endframe) { + if (self.fadein_endframe >= 10) { // weapon has entered the screen + self.fadein_endframe = self.weapon_idleframe; + self.weaponframe = 0; + } + else { + self.change_weapon_status = CW_DONE; + } + } + } + else if (self.weapon == IT_SPECIAL_WEAPON) { + self.weaponframe = self.weaponframe + 1; + + if (self.weaponframe == 11) { + self.change_weapon_status = CW_DONE; + } + } + else { + self.weaponframe = self.weapon_idleframe; + self.change_weapon_status = CW_DONE; + } +}; + +// Starts the morphing towards the new weapon +void(float wpn) SetNewWeapon = +{ +// if (wpn & IT_LIGHTNING) { +// return; +// } + if (deathmatch == DM_SPECIAL_POWERS) { + self.weapon_idleframe = 6; + return; + } + + if ((self.think != player_run) && (self.think != player_stand1)) // only change if idle + return; + + if (wpn == self.weapon) + return; + + if ((self.weapon == IT_LIGHTNING) && + (self.prox_ent != world)) + return; + + // make sure we start at the idle frame + self.weaponframe = self.weapon_idleframe; + + if ((deathmatch || coop) && (wpn == IT_AXE)) { + self.weapon_idleframe = 6; + } + else { + self.weapon_idleframe = 5; + } + + self.nextweapon = wpn; + self.change_weapon_status = CW_FADEOUT; + self.fadeout_endframe = 0; + FadeWeaponOut(); +}; + +/* +============ +W_ChangeWeapon +============ +*/ +void() W_ChangeWeapon = +{ + local float it, am, fl, new_idle; + + if (self.modelindex == index_skeleton) + return; + + if ((deathmatch == DM_SPECIAL_POWERS) && (self.impulse != 1)) + return; + + it = self.items; + am = 0; + + if (self.impulse == 1) + { + fl = IT_AXE; + new_idle = 6; + + if ((deathmatch || coop) && (self.weapon == IT_AXE)) { + self.special_weapon = !self.special_weapon; + } + } + else if (self.impulse == 2) + { + fl = IT_SHOTGUN; + new_idle = 5; + if (self.ammo_shells < 2) + am = 1; + } + else if (self.impulse == 3) + { + fl = IT_SUPER_SHOTGUN; + new_idle = 5; + if (self.ammo_shells < 1) + am = 1; + } + else if (self.impulse == 4) + { + fl = IT_NAILGUN; + new_idle = 5; + 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; + new_idle = 5; + if (self.ammo_rockets < 1) + am = 1; // not available yet + } + else if (self.impulse == 7) + { + fl = IT_ROCKET_LAUNCHER; + new_idle = 5; + if (self.ammo_rockets < 1) + am = 1; + } + else if (self.impulse == 8) + { + fl = IT_LIGHTNING; + new_idle = 2; + if (self.ammo_cells < 1) + am = 1; + } + else if (self.impulse == 13) // mega-weapon + { + fl = IT_SPECIAL_WEAPON; + new_idle = 11; + if (self.ammo_special < 1) + am = 1; + } + + self.impulse = 0; + + if ((!(self.items & fl)) && (deathmatch || coop)) // X-Men: in singleplayer, weapons are already present + { // don't have the weapon or the ammo + sprint (self, "no weapon.\n"); + return; + } + + if (am) + { // don't have the ammo + sprint (self, "not enough ammo.\n"); + return; + } + +// +// set weapon, set ammo +// +// self.weapon_idleframe = new_idle; + + if (self.weapon != fl) + SetNewWeapon(fl); + else if (self.weapon == IT_AXE) { + self.weapon = fl; + SpecialWeaponChange(); + W_SetCurrentAmmo (); + } +}; + +/* +============ +CheatCommand +============ +*/ +void() CheatCommand = // cheats disabled +{ + if (deathmatch)// || coop) + return; + + self.ammo_rockets = 100; + self.ammo_nails = 200; + self.ammo_shells = 150; + 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; + +// SetNewWeapon(IT_ROCKET_LAUNCHER); + + +// self.weapon = IT_ROCKET_LAUNCHER; + self.impulse = 0; +// W_SetCurrentAmmo (); +}; + +/* +============ +CycleWeaponCommand + +Go to the next weapon with ammo +============ +*/ +void() CycleWeaponCommand = +{ + local float it, am, fl; + + if (self.modelindex == index_skeleton) + return; + + it = self.items; + self.impulse = 0; + fl = self.weapon; + + if (deathmatch == DM_SPECIAL_POWERS) { + self.special_weapon = !self.special_weapon; + self.weapon = fl; + SpecialWeaponChange(); + W_SetCurrentAmmo (); + + return; + } + + while (1) + { + am = 0; + + if (fl == IT_LIGHTNING) + { + fl = IT_AXE; + } + else if (fl == IT_AXE) + { + fl = IT_SHOTGUN; + if (self.ammo_shells < 1) + am = 1; + } + else if (fl == IT_SHOTGUN) + { + fl = IT_SUPER_SHOTGUN; + if (self.ammo_shells < 2) + am = 1; + } + else if (fl == IT_SUPER_SHOTGUN) + { + fl = IT_NAILGUN; + if (self.ammo_nails < 1) + am = 1; + } + else if (fl == IT_NAILGUN) + { + fl = IT_SUPER_NAILGUN; + if (self.ammo_nails < 2) + am = 1; + } + else if (fl == IT_SUPER_NAILGUN) + { + fl = IT_GRENADE_LAUNCHER; + if (self.ammo_rockets < 1) + am = 1; + } + else if (fl == IT_GRENADE_LAUNCHER) + { + fl = IT_ROCKET_LAUNCHER; + if (self.ammo_rockets < 1) + am = 1; + } + else if (fl == IT_ROCKET_LAUNCHER) + { + fl = IT_LIGHTNING; + if (self.ammo_cells < 1) + am = 1; + } + + if (am == 0) + { + SetNewWeapon(fl); + +// W_SetCurrentAmmo (); + return; + } + } + +}; + +/* +============ +CycleWeaponReverseCommand + +Go to the prev weapon with ammo +============ +*/ +void() CycleWeaponReverseCommand = +{ + local float it, am, fl; + + if (self.modelindex == index_skeleton) + return; + + it = self.items; + self.impulse = 0; + fl = self.weapon; + + if (deathmatch == DM_SPECIAL_POWERS) { + self.special_weapon = !self.special_weapon; + self.weapon = fl; + SpecialWeaponChange(); + W_SetCurrentAmmo (); + + return; + } + + while (1) + { + am = 0; + + if (fl == IT_LIGHTNING) + { + fl = IT_ROCKET_LAUNCHER; + if (self.ammo_rockets < 1) + am = 1; + } + else if (fl == IT_ROCKET_LAUNCHER) + { + fl = IT_GRENADE_LAUNCHER; + if (self.ammo_rockets < 1) + am = 1; + } + else if (fl == IT_GRENADE_LAUNCHER) + { + fl = IT_SUPER_NAILGUN; + if (self.ammo_nails < 2) + am = 1; + } + else if (fl == IT_SUPER_NAILGUN) + { + fl = IT_NAILGUN; + if (self.ammo_nails < 1) + am = 1; + } + else if (fl == IT_NAILGUN) + { + fl = IT_SUPER_SHOTGUN; + if (self.ammo_shells < 2) + am = 1; + } + else if (fl == IT_SUPER_SHOTGUN) + { + fl = IT_SHOTGUN; + if (self.ammo_shells < 1) + am = 1; + } + else if (fl == IT_SHOTGUN) + { + fl = IT_AXE; + } + else if (fl == IT_AXE) + { + fl = IT_LIGHTNING; + if (self.ammo_cells < 1) + am = 1; + } + + if (am == 0) + { + SetNewWeapon(fl); + +// W_SetCurrentAmmo (); + return; + } + } + +}; + +/* +============ +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"); +}; + +/* +============ +Impulse Commands + +============ +*/ +float capture, last_capture, capture_count, capture_index; + +void() ImpulseCommands = +{ + local float ftemp; + local string str; + + if (self.impulse == 248) { + capture = !capture; + capture_index = 0; + } + + if (!((self.change_weapon_status) || (self.weapon_flags & W_RELOADING) || ((self.think != player_run) && (self.think != player_stand1)))) { + // weapon is ready for changing + + if (self.remember_impulse && (self.remember_impulse != 13)) { // prevent from changing while waiting for mega-weapon to come up + self.impulse = self.remember_impulse; + self.remember_impulse = 0; + } + + if ((self.impulse >= 1 && self.impulse <= 8) || (self.impulse == 13)) + W_ChangeWeapon (); + else if (self.impulse == 10) + CycleWeaponCommand (); + else if (self.impulse == 12) + CycleWeaponReverseCommand (); + } + else { + if ((self.impulse <= 13) && (!self.remember_impulse)) + self.remember_impulse = self.impulse; + } + + if (!self.impulse) + return; + + else if (self.impulse == 11) + ServerflagsCommand (); + + else if (self.impulse == 20) // re-print last trigger_multiple/single message + centerprint(self, self.last_centerprint); + + else if (self.impulse == 40) // toggle chasecam + { + if (self.chasecam == world) + InitCam(self); + else + DisableCam(self); + } + + // any impulses > 200 are debuggin only + if (deathmatch) { + self.impulse = 0; + return; + } + + else if (self.impulse == 99) + CheatCommand (); + else if (self.impulse == 200) + show_damage = !show_damage; + + else if (self.impulse == 202) { // give all weapon parts + self.weapon_parts = 4; + serverflags = serverflags | 15; + } + + else if (self.impulse == 250) { + ftemp = cvar("coop") - 1; + if (ftemp < 1) ftemp = 12; + str = ftos(ftemp); + cvar_set("coop", str); + stuffcmd(self, "restart\n"); + } + else if (self.impulse == 251) { + ftemp = cvar("coop") + 1; + if (ftemp > 12) ftemp = 1; + str = ftos(ftemp); + cvar_set("coop", str); + stuffcmd(self, "restart\n"); + } + + else if (self.impulse == 222) { + if (self.x_flags & X_GODCHEAT) { + self.x_flags = self.x_flags - X_GODCHEAT; + self.flags = self.flags - (self.flags & FL_GODMODE); + stuffcmd(self, "bf\n"); + sprint(self, "Invincibility disabled\n"); + } + else { + self.x_flags = self.x_flags | X_GODCHEAT; + self.flags = self.flags | FL_GODMODE; + sprint(self, "Invincibility enabled\n"); + } + } + +// else if (self.impulse == 255) +// QuadCheat (); + + self.impulse = 0; +}; + +/* +============ +W_WeaponFrame + +Called every frame so impulse events can be handled as well as possible +============ +*/ +void() W_WeaponFrame = +{ + if ((self.change_weapon_status) && (self.last_fade < (time - 0.07))) { + if (self.change_weapon_status == CW_FADEOUT) + FadeWeaponOut(); + else + FadeWeaponIn(); + } + + ImpulseCommands (); + + if (time < self.attack_finished) + return; + + if (self.change_weapon_status) + return; + +// check for attack + if ((self.button0) && (self.modelindex != index_skeleton)) + { + SuperDamageSound (); + W_Attack (); + + if ((self.flags & FL_FLAMEON) && + (self.weapon != IT_SUPER_NAILGUN)) { + self.flags = self.flags - FL_FLAMEON; + } + } + else { + self.flags = self.flags - (self.flags & FL_FLAMEON); + } + +}; + +/* +======== +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; +}; diff --git a/WORLD.c b/WORLD.c new file mode 100644 index 0000000..97b8223 --- /dev/null +++ b/WORLD.c @@ -0,0 +1,650 @@ + +void() InitBodyQue; + + +void() main = +{ + dprint ("main function\n"); + +// these are just commands the the prog compiler to copy these files + + precache_file ("progs.dat"); + precache_file ("gfx.wad"); + precache_file ("quake.rc"); + precache_file ("default.cfg"); + + precache_file ("end1.bin"); + precache_file2 ("end2.bin"); + + precache_file ("demo1.dem"); + precache_file ("demo2.dem"); + precache_file ("demo3.dem"); + +// +// these are all of the lumps from the cached.ls files +// + precache_file ("gfx/palette.lmp"); + precache_file ("gfx/colormap.lmp"); + + precache_file2 ("gfx/pop.lmp"); + + precache_file ("gfx/complete.lmp"); + precache_file ("gfx/inter.lmp"); + + precache_file ("gfx/ranking.lmp"); + precache_file ("gfx/vidmodes.lmp"); + precache_file ("gfx/finale.lmp"); + precache_file ("gfx/conback.lmp"); + precache_file ("gfx/qplaque.lmp"); + + precache_file ("gfx/menudot1.lmp"); + precache_file ("gfx/menudot2.lmp"); + precache_file ("gfx/menudot3.lmp"); + precache_file ("gfx/menudot4.lmp"); + precache_file ("gfx/menudot5.lmp"); + precache_file ("gfx/menudot6.lmp"); + + precache_file ("gfx/menuplyr.lmp"); + precache_file ("gfx/bigbox.lmp"); + precache_file ("gfx/dim_modm.lmp"); + precache_file ("gfx/dim_drct.lmp"); + precache_file ("gfx/dim_ipx.lmp"); + precache_file ("gfx/dim_tcp.lmp"); + precache_file ("gfx/dim_mult.lmp"); + precache_file ("gfx/mainmenu.lmp"); + + precache_file ("gfx/box_tl.lmp"); + precache_file ("gfx/box_tm.lmp"); + precache_file ("gfx/box_tr.lmp"); + + precache_file ("gfx/box_ml.lmp"); + precache_file ("gfx/box_mm.lmp"); + precache_file ("gfx/box_mm2.lmp"); + precache_file ("gfx/box_mr.lmp"); + + precache_file ("gfx/box_bl.lmp"); + precache_file ("gfx/box_bm.lmp"); + precache_file ("gfx/box_br.lmp"); + + precache_file ("gfx/sp_menu.lmp"); + precache_file ("gfx/ttl_sgl.lmp"); + precache_file ("gfx/ttl_main.lmp"); + precache_file ("gfx/ttl_cstm.lmp"); + + precache_file ("gfx/mp_menu.lmp"); + + precache_file ("gfx/netmen1.lmp"); + precache_file ("gfx/netmen2.lmp"); + precache_file ("gfx/netmen3.lmp"); + precache_file ("gfx/netmen4.lmp"); + precache_file ("gfx/netmen5.lmp"); + + precache_file ("gfx/sell.lmp"); + + precache_file ("gfx/help0.lmp"); + precache_file ("gfx/help1.lmp"); + precache_file ("gfx/help2.lmp"); + precache_file ("gfx/help3.lmp"); + precache_file ("gfx/help4.lmp"); + precache_file ("gfx/help5.lmp"); + + precache_file ("gfx/pause.lmp"); + precache_file ("gfx/loading.lmp"); + + precache_file ("gfx/p_option.lmp"); + precache_file ("gfx/p_load.lmp"); + precache_file ("gfx/p_save.lmp"); + precache_file ("gfx/p_multi.lmp"); + +// sounds loaded by C code + precache_sound ("misc/menu1.wav"); + precache_sound ("misc/menu2.wav"); + precache_sound ("misc/menu3.wav"); + + precache_sound ("ambience/water1.wav"); + precache_sound ("ambience/wind2.wav"); + +// shareware + precache_file ("maps/start.bsp"); + + precache_file ("maps/e1m1.bsp"); + precache_file ("maps/e1m2.bsp"); + precache_file ("maps/e1m3.bsp"); + precache_file ("maps/e1m4.bsp"); + precache_file ("maps/e1m5.bsp"); + precache_file ("maps/e1m6.bsp"); + precache_file ("maps/e1m7.bsp"); + precache_file ("maps/e1m8.bsp"); + +// registered + precache_file2 ("gfx/pop.lmp"); + + precache_file2 ("maps/e2m1.bsp"); + precache_file2 ("maps/e2m2.bsp"); + precache_file2 ("maps/e2m3.bsp"); + precache_file2 ("maps/e2m4.bsp"); + precache_file2 ("maps/e2m5.bsp"); + precache_file2 ("maps/e2m6.bsp"); + precache_file2 ("maps/e2m7.bsp"); + + precache_file2 ("maps/e3m1.bsp"); + precache_file2 ("maps/e3m2.bsp"); + precache_file2 ("maps/e3m3.bsp"); + precache_file2 ("maps/e3m4.bsp"); + precache_file2 ("maps/e3m5.bsp"); + precache_file2 ("maps/e3m6.bsp"); + precache_file2 ("maps/e3m7.bsp"); + + precache_file2 ("maps/e4m1.bsp"); + precache_file2 ("maps/e4m2.bsp"); + precache_file2 ("maps/e4m3.bsp"); + precache_file2 ("maps/e4m4.bsp"); + precache_file2 ("maps/e4m5.bsp"); + precache_file2 ("maps/e4m6.bsp"); + precache_file2 ("maps/e4m7.bsp"); + precache_file2 ("maps/e4m8.bsp"); + + precache_file2 ("maps/end.bsp"); + + precache_file2 ("maps/dm1.bsp"); + precache_file2 ("maps/dm2.bsp"); + precache_file2 ("maps/dm3.bsp"); + precache_file2 ("maps/dm4.bsp"); + precache_file2 ("maps/dm5.bsp"); + precache_file2 ("maps/dm6.bsp"); +}; + + +entity lastspawn; + +//======================= +/*QUAKED worldspawn (0 0 0) ? +Only used for the world entity. +Set message to the level name. +Set sounds to the cd track to play. + +World Types: +0: medieval +1: metal +2: base +*/ +//======================= +void() worldspawn = +{ + lastspawn = world; + InitBodyQue (); + + num_clients = 0; + +// custom map attributes + if (self.model == "maps/e1m8.bsp") + cvar_set ("sv_gravity", "100"); + else + cvar_set ("sv_gravity", "800"); + + deathmatch = cvar("deathmatch"); + + executable = "dosQuake"; + if (cvar("temp1") & 1) + executable = "glQuake"; + +// the area based ambient sounds MUST be the first precache_sounds + +// player precaches + W_Precache (); // get weapon precaches + +// sounds used from C physics code + precache_sound ("demon/dland2.wav"); // landing thud + precache_sound ("misc/h2ohit1.wav"); // landing splash + +// setup precaches allways needed + precache_sound ("items/itembk2.wav"); // item respawn sound + precache_sound ("player/plyrjmp8.wav"); // player jump + precache_sound ("player/land1.wav"); // player landing + precache_sound ("player/land3.wav"); // player hurt landing + precache_sound ("player/land4.wav"); // player hurt landing + precache_sound ("player/drown1.wav"); // drowning pain + precache_sound ("player/drown2.wav"); // drowning pain + precache_sound ("player/gasp1.wav"); // gasping for air + precache_sound ("player/gasp2.wav"); // taking breath + precache_sound ("player/h2odeath.wav"); // drowning death + precache_sound ("player/h2ojump.wav"); + precache_sound ("player/what_1.wav"); // parallize sound + + precache_sound ("misc/talk.wav"); // talk + precache_sound ("player/teledth1.wav"); // telefrag + precache_sound ("misc/r_tele1.wav"); // teleport sounds + precache_sound ("misc/r_tele2.wav"); + precache_sound ("misc/r_tele3.wav"); + precache_sound ("misc/r_tele4.wav"); + precache_sound ("misc/r_tele5.wav"); + precache_sound ("weapons/lock4.wav"); // ammo pick up + precache_sound ("weapons/pkup.wav"); // weapon up + precache_sound ("items/armor1.wav"); // armor up + precache_sound ("weapons/lhit.wav"); //lightning + precache_sound ("weapons/lstart.wav"); //lightning start + precache_sound ("items/damage3.wav"); + precache_sound ("items/protect.wav"); + precache_sound ("cannon/takeoff.wav"); + + precache_sound ("doors/airdoor2.wav"); + precache_sound ("items/inv1.wav"); + + precache_sound ("misc/power.wav"); //lightning for boss + +// player gib sounds + precache_sound ("player/gib.wav"); // player gib sound + precache_sound ("player/udeath.wav"); // player gib sound + precache_sound ("player/tornoff2.wav"); // gib sound + +// player pain sounds + + precache_sound ("player/pain1.wav"); + precache_sound ("player/pain2.wav"); + precache_sound ("player/pain3.wav"); + precache_sound ("player/pain4.wav"); + +// player death sounds + precache_sound ("player/death1.wav"); + precache_sound ("player/death2.wav"); + precache_sound ("player/death3.wav"); + precache_sound ("player/death4.wav"); + precache_sound ("player/death5.wav"); + +// ax sounds + precache_sound ("weapons/ax1.wav"); // ax swoosh + precache_sound ("player/axhit1.wav"); // ax hit meat + precache_sound ("player/axhit2.wav"); // ax hit world + + precache_sound ("player/h2ojump.wav"); // player jumping into water + precache_sound ("player/slimbrn2.wav"); // player enter slime + precache_sound ("player/inh2o.wav"); // player enter water + precache_sound ("player/inlava.wav"); // player enter lava + precache_sound ("misc/outwater.wav"); // leaving water sound + + precache_sound ("player/lburn1.wav"); // lava burn + precache_sound ("player/lburn2.wav"); // lava burn + + precache_sound ("misc/water1.wav"); // swimming + precache_sound ("misc/water2.wav"); // swimming + +// X-Men: id sounds used in weapons (soon to be replaced) + precache_sound ("enforcer/enfire.wav"); + precache_sound ("enforcer/enfstop.wav"); +// end + +// X-Men sounds + precache_sound ("generic/punch1.wav"); + precache_sound ("generic/punch2.wav"); + precache_sound ("generic/punch3.wav"); + + precache_sound ("misc/snicker1.wav"); // GOD mode laugh + + if (cvar("deathmatch") || cvar("coop")) { + precache_sound ("angel/flap1.wav"); + precache_sound ("angel/flap2.wav"); + precache_sound ("angel/flap3.wav"); + precache_sound ("angel/flap4.wav"); + precache_sound ("angel/flap5.wav"); + precache_sound ("angel/flap6.wav"); + + precache_sound ("wizard/hit.wav"); // used by c code + precache_sound ("hknight/slash1.wav"); + + precache_sound ("doors/stndr1.wav"); + precache_sound ("boss1/throw.wav"); + precache_sound ("generic/swing1.wav"); + precache_sound ("generic/frozen1.wav"); + precache_sound ("zombie/z_hit.wav"); + precache_sound ("cannon/flyloop.wav"); + precache_sound ("cannon/takeoff.wav"); + } + + precache_sound ("weapons/guidfire.wav"); // guided missiles + precache_sound ("weapons/chnfire5.wav"); // chaingun + precache_sound ("weapons/shotfir6.wav"); + precache_sound ("weapons/flame.wav"); + precache_sound ("weapons/f_start.wav"); + precache_sound ("weapons/flamball.wav"); + precache_sound ("weapons/reload.wav"); + precache_sound ("weapons/prox1.wav"); + precache_sound ("weapons/prox2.wav"); + precache_sound ("weapons/mega.wav"); + precache_sound ("weapons/m_start.wav"); + + // skeleton + precache_sound ("zombie/idle_w2.wav"); + precache_sound ("skeleton/crunch.wav"); + + // character sounds used during deathmatch + precache_sound ("storm/w_attack.wav"); + precache_sound ("storm/l_attack.wav"); + + // deathmatch sounds + precache_sound ("demon/dhit2.wav"); + + // character/deathmatch sounds + precache_sound ("voice/male/pain1.wav"); + precache_sound ("voice/male/pain2.wav"); + precache_sound ("voice/male/pain3.wav"); + precache_sound ("voice/male/pain4.wav"); + precache_sound ("voice/male/pain5.wav"); + precache_sound ("voice/male/pain6.wav"); + precache_sound ("voice/male/pain7.wav"); + + precache_sound ("voice/male/diescrm1.wav"); + precache_sound ("voice/male/diescrm2.wav"); + precache_sound ("voice/male/diescrm3.wav"); + precache_sound ("voice/male/diescrm4.wav"); + precache_sound ("voice/male/diescrm5.wav"); + precache_sound ("voice/male/diescrm6.wav"); + + precache_sound ("voice/female/scream1.wav"); + precache_sound ("voice/female/scream2.wav"); + precache_sound ("voice/female/scream3.wav"); + precache_sound ("voice/female/scream4.wav"); + precache_sound ("voice/female/scream5.wav"); + precache_sound ("voice/female/no1.wav"); + + precache_sound ("voice/female/diescrm1.wav"); + precache_sound ("voice/female/diescrm2.wav"); + precache_sound ("voice/female/diescrm3.wav"); + precache_sound ("voice/female/diescrm4.wav"); + precache_sound ("voice/female/diescrm5.wav"); +/* + precache_sound ("voice/female/hey.wav"); + precache_sound ("voice/female/hey_you.wav"); + precache_sound ("voice/female/stop.wav"); + precache_sound ("voice/female/wait.wav"); + + precache_sound ("voice/male/growl.wav"); + precache_sound ("voice/male/grrr.wav"); + precache_sound ("voice/male/intruder.wav"); + precache_sound ("voice/male/stop01.wav"); + precache_sound ("voice/male/uh-a.wav"); + precache_sound ("voice/male/what.wav"); + precache_sound ("voice/male/what_the.wav"); + precache_sound ("voice/male/youthere.wav"); +*/ +// temp only, used for proximity weapon +precache_sound ("items/damage2.wav"); +// end + + precache_model ("progs/player.mdl"); + precache_model ("progs/cyborg.mdl"); + precache_model ("progs/eyes.mdl"); + precache_model ("progs/h_player.mdl"); + + // skeleton gibs + precache_model ("progs/gib01.mdl"); + precache_model ("progs/gib02.mdl"); + precache_model ("progs/gib03.mdl"); + + precache_model ("progs/s_bubble.spr"); // drowning bubbles + precache_model ("progs/s_explod.spr"); // sprite explosion + + precache_model ("progs/spike.mdl"); + +// X-Men: deathmatch models + if (cvar("deathmatch") || cvar("coop")) { + + // Characters + precache_model ("progs/dmskel.mdl"); + precache_model ("progs/dmwolvy.mdl"); + precache_model ("progs/dmstorm2.mdl"); + precache_model ("progs/dmice.mdl"); + precache_model ("progs/dmcyclop.mdl"); + precache_model ("progs/dmpsy.mdl"); + precache_model ("progs/dmangel.mdl"); + precache_model ("progs/dmbeast.mdl"); + precache_model ("progs/dmgambit.mdl"); + precache_model ("progs/dmbishop.mdl"); + precache_model ("progs/dmrogue.mdl"); + precache_model ("progs/dmcannon.mdl"); + precache_model ("progs/dmphoen.mdl"); + + // deathmatch special power weapons + precache_model ("progs/v_wol.mdl"); + precache_model ("progs/v_sto.mdl"); + precache_model ("progs/v_cyc.mdl"); + precache_model ("progs/v_psy.mdl"); + precache_model ("progs/v_ang.mdl"); + precache_model ("progs/v_bea.mdl"); + precache_model ("progs/v_gam.mdl"); + precache_model ("progs/v_ice.mdl"); + precache_model ("progs/v_bis.mdl"); + precache_model ("progs/v_rog.mdl"); + precache_model ("progs/v_can.mdl"); + precache_model ("progs/v_pho.mdl"); + + // Other Models + precache_model ("progs/claser1.mdl"); + precache_model ("progs/dart.mdl"); + precache_model ("progs/pow.mdl"); + precache_model ("progs/card.mdl"); + precache_model ("progs/iceshard.mdl"); + precache_model ("progs/iceblast.mdl"); + precache_model ("progs/bisblast.mdl"); + precache_model ("progs/beampart.mdl"); + precache_model ("progs/psyblast.mdl"); + + } +// end + +// X-Men: id models used in weapons + precache_model ("progs/laser.mdl"); +// end + +// X-Men view (weapon) models + precache_model ("progs/v_xfire1.mdl"); + precache_model ("progs/v_xrock.mdl"); + precache_model ("progs/v_xshot1.mdl"); + precache_model ("progs/v_xchain.mdl"); + precache_model ("progs/v_xorb.mdl"); + precache_model ("progs/v_xflame.mdl"); + precache_model ("progs/v_xshock.mdl"); + + if (!deathmatch && !coop) { + precache_model ("progs/v_xfist.mdl"); + } + precache_model ("progs/v_xmega.mdl"); +// end view models + + precache_model ("progs/atom1.mdl"); + precache_model ("progs/atom2.mdl"); + precache_model ("progs/atom3.mdl"); + precache_model ("progs/atomshot.mdl"); + + precache_model ("progs/bolt.mdl"); // for lightning gun + precache_model ("progs/bolt2.mdl"); // for lightning gun + precache_model ("progs/bolt3.mdl"); // for boss shock + precache_model ("progs/lavaball.mdl"); // for testing + + precache_model ("progs/missile.mdl"); + + precache_model ("progs/backpack.mdl"); + +// X-Men models + precache_model ("progs/blood.mdl"); + precache_model ("progs/missmall.mdl"); + precache_model ("progs/fl_th1.mdl"); +// precache_model ("progs/flame_sm.mdl"); + precache_model ("progs/fl_th2.mdl"); +// precache_model ("progs/fl_th3.mdl"); + precache_model ("progs/fl_th5.mdl"); + precache_model ("progs/fl_th6.mdl"); + precache_model ("progs/flamball.mdl"); + precache_model ("progs/skel.mdl"); + precache_model ("progs/orb1.mdl"); + precache_model ("progs/null.spr"); +// END + +// +// Setup light animation tables. 'a' is total darkness, 'z' is maxbright. +// + + // 0 normal + lightstyle(0, "m"); + + // 1 FLICKER (first variety) + lightstyle(1, "mmnmmommommnonmmonqnmmo"); + + // 2 SLOW STRONG PULSE + lightstyle(2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba"); + + // 3 CANDLE (first variety) + lightstyle(3, "mmmmmaaaaammmmmaaaaaabcdefgabcdefg"); + + // 4 FAST STROBE + lightstyle(4, "mamamamamama"); + + // 5 GENTLE PULSE 1 + lightstyle(5,"jklmnopqrstuvwxyzyxwvutsrqponmlkj"); + + // 6 FLICKER (second variety) + lightstyle(6, "nmonqnmomnmomomno"); + + // 7 CANDLE (second variety) + lightstyle(7, "mmmaaaabcdefgmmmmaaaammmaamm"); + + // 8 CANDLE (third variety) + lightstyle(8, "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa"); + + // 9 SLOW STROBE (fourth variety) + lightstyle(9, "aaaaaaaazzzzzzzz"); + + // 10 FLUORESCENT FLICKER + lightstyle(10, "mmamammmmammamamaaamammma"); + + // 11 SLOW PULSE NOT FADE TO BLACK + lightstyle(11, "abcdefghijklmnopqrrqponmlkjihgfedcba"); + + // styles 32-62 are assigned by the light program for switchable lights + + // 63 testing + lightstyle(63, "a"); + lightstyle(255, "a"); + +}; + +float last_explode; +void() StartFrame = +{ + local entity laser, orb, old_laser, trav; + local vector vect; + local float vspeed, cont; + + teamplay = cvar("teamplay"); + skill = cvar("skill"); + framecount = framecount + 1; + + // check all lasers + laser = find(world, classname, "laser"); + while (laser != world) { + + if (laser.origin == laser.oldorigin) { + old_laser = laser; + laser = find(laser, classname, "laser"); + + remove(old_laser); + } + else { + if (laser.last_touch != 0) { +/* + vect = normalize(laser.old_velocity); + vspeed = vlen(laser.old_velocity); + + traceline(laser.origin - (laser.old_velocity * 0.5), laser.origin + laser.old_velocity, TRUE, laser); + + laser.velocity = (GetReflectionVect(trace_endpos, vect, trace_plane_normal) * vspeed); +*/ + laser.old_velocity = laser.velocity; + vect = normalize(laser.old_velocity); + + laser.angles = vectoangles(vect); + laser.last_touch = 0; + + } + + laser.velocity_z = laser.old_velocity_z + cvar("sv_gravity")*frametime; + + laser.oldorigin = laser.origin; + + laser = find(laser, classname, "laser"); + } + + } + + // check orb for bounce + orb = world; + while ((orb = find(orb, classname, "orb")) != world) { + if ((orb.velocity_z > 0) && (orb.old_velocity_z <= 0)) { + orb.velocity_z = 300; + } + + orb.old_velocity = orb.velocity; + } + + // Ice shards too! + + laser = find(world, classname, "shard"); + while (laser != world) + { + if (laser.state) + { + laser.velocity_z = laser.velocity_z + cvar("sv_gravity")*frametime; + } + laser = find(laser, classname, "shard"); + } + +}; + +/* +============================================================================== + +BODY QUE + +============================================================================== +*/ + +entity bodyque_head; + +void() bodyque = +{ // just here so spawn functions don't complain after the world + // creates bodyques +}; + +void() InitBodyQue = +{ + local entity e; + + bodyque_head = spawn(); + bodyque_head.classname = "bodyque"; + bodyque_head.owner = spawn(); + bodyque_head.owner.classname = "bodyque"; + bodyque_head.owner.owner = spawn(); + bodyque_head.owner.owner.classname = "bodyque"; + bodyque_head.owner.owner.owner = spawn(); + bodyque_head.owner.owner.owner.classname = "bodyque"; + bodyque_head.owner.owner.owner.owner = bodyque_head; +}; + + +// make a body que entry for the given ent so the ent can be +// respawned elsewhere +void(entity ent) CopyToBodyQue = +{ + bodyque_head.angles = ent.angles; + bodyque_head.model = ent.model; + bodyque_head.modelindex = ent.modelindex; + bodyque_head.frame = ent.frame; + bodyque_head.colormap = ent.colormap; + bodyque_head.movetype = ent.movetype; + bodyque_head.velocity = ent.velocity; + bodyque_head.flags = 0; + setorigin (bodyque_head, ent.origin); + setsize (bodyque_head, ent.mins, ent.maxs); + bodyque_head = bodyque_head.owner; +}; + + diff --git a/X_SELCH.c b/X_SELCH.c new file mode 100644 index 0000000..fadd8bd --- /dev/null +++ b/X_SELCH.c @@ -0,0 +1,47 @@ +void() clone_touch = +{ + if (other.classname != "player") + return; + + if (self.classname == "xmen_wclone") { + stuffcmd(other, "color 0 0\n"); + } + else if (self.classname == "xmen_sclone") { + stuffcmd(other, "color 1 1\n"); + } + + stuffcmd(other, "connect\n"); +}; + +void() clone_think = +{ + self.frame = self.frame + 1; + if (self.frame > 12) + self.frame = 0; + + self.nextthink = time + 0.1; +}; + +void() xmen_wclone = +{ + self.touch = clone_touch; + setsize(self, '-8 -8 -8', '8 8 8'); + self.solid = SOLID_TRIGGER; + + precache_model("progs/wolvie2.mdl"); + setmodel(self, "progs/wolvie2.mdl"); + self.think = clone_think; + self.nextthink = time + 0.1; +}; + +void() xmen_sclone = +{ + self.touch = clone_touch; + setsize(self, '-8 -8 -8', '8 8 8'); + self.solid = SOLID_TRIGGER; + + precache_model("progs/storm2.mdl"); + setmodel(self, "progs/storm2.mdl"); + self.think = clone_think; + self.nextthink = time + 0.1; +}; \ No newline at end of file diff --git a/X_SPWPN.c b/X_SPWPN.c new file mode 100644 index 0000000..6b1a0b1 --- /dev/null +++ b/X_SPWPN.c @@ -0,0 +1,1135 @@ +// ------------------------------------------------------- +// Special Weapon code (Deathmatch only) +// +// The main procedure is at the end, this is called every +// frame during a special attack. +// ------------------------------------------------------- + +void() SpecialWeaponChange = +{ + if (self.character == CHAR_WOLVERINE) { + if (!self.special_weapon) + sprint(self, "Claw Attack selected.\n"); + else + sprint(self, "Jump Attack selected.\n"); + } + else if (self.character == CHAR_STORM) { + if (!self.special_weapon) + sprint(self, "Wind Attack selected.\n"); + else + sprint(self, "Lightning Attack selected.\n"); + } + else if (self.character == CHAR_CYCLOPS) { + if (!self.special_weapon) + sprint(self, "Fast Laser selected.\n"); + else + sprint(self, "Mega-Laser selected.\n"); + } + else if (self.character == CHAR_PSYLOCKE) { + if (!self.special_weapon) + sprint(self, "Sword Attack selected.\n"); + else + sprint(self, "Psychic Paralyze selected.\n"); + } + else if (self.character == CHAR_ANGEL) { + if (!self.special_weapon) + sprint(self, "Dart Spray selected.\n"); + else + sprint(self, "Wing Defense selected.\n"); + } + else if (self.character == CHAR_BEAST) { + if (!self.special_weapon) + sprint(self, "Triple Punch selected.\n"); + else + sprint(self, "Floor Pound selected.\n"); + } + else if (self.character == CHAR_GAMBIT) { + if (!self.special_weapon) + sprint(self, "Staff Attack selected.\n"); + else + sprint(self, "Throwing Cards selected.\n"); + } + else if (self.character == CHAR_ICEMAN) { + if (!self.special_weapon) + sprint(self, "Shard Attack selected.\n"); + else + sprint(self, "Freeze Blast selected.\n"); + } + else if (self.character == CHAR_BISHOP) { + if (!self.special_weapon) + sprint(self, "Gun Attack selected.\n"); + else + sprint(self, "Energy Blast selected.\n"); + } + else if (self.character == CHAR_ROGUE) { + if (!self.special_weapon) + sprint(self, "Single Punch selected.\n"); + else + sprint(self, "Super Punch selected.\n"); + } + else if (self.character == CHAR_CANNONBALL) { + if (!self.special_weapon) + sprint(self, "Punch Attack selected.\n"); + else + sprint(self, "Flying Punch selected.\n"); + } + else if (self.character == CHAR_PHOENIX) { + if (!self.special_weapon) + sprint(self, "Tractor Beam selected.\n"); + else + sprint(self, "Homing Blast selected.\n"); + } +}; + +void(float side) Wolvy_Melee = +{ + local entity other; + + makevectors (self.angles); + traceline(self.origin, self.origin + v_forward * 48, FALSE, self); + + if ((trace_ent != world) && (trace_ent.takedamage != DAMAGE_NO)) + other = trace_ent; + else + return; + + sound (self, CHAN_WEAPON, "demon/dhit2.wav", 1, ATTN_NORM); + T_Damage (other, self, self, 15); + + SpawnMeatSpray (self.origin + v_forward*16, side * v_right); +}; + + +void() Wolvy_JumpThink = +{ + local float ldmg; + local vector dir; + + if (self.health <= 0) + return; + + // check for enemy getting hit + makevectors(self.v_angle); + dir = v_forward; + traceline(self.origin, self.origin + dir * 128, FALSE, self); + if ((trace_ent != world) && (trace_ent.takedamage != DAMAGE_NO)) + { + ldmg = 8 + 5*random(); + T_Damage (trace_ent, self, self, ldmg); + trace_ent.punchangle_x = -10; + + sound (self, CHAN_WEAPON, "demon/dhit2.wav", 1, ATTN_NORM); + } +}; + +void() Wolvy_Jump = +{ + if (!(self.flags & FL_ONGROUND)) + return; + + makevectors (self.v_angle); + + self.origin_z = self.origin_z + 1; + self.velocity = v_forward * 700 + '0 0 210'; + if (self.velocity_z > 350) + self.velocity_z = 350; + + sound (self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM); + + if (self.flags & FL_ONGROUND) + self.flags = self.flags - FL_ONGROUND; +}; + +void() Storm_Lightning = +{ + local vector dir; + + self.effects = self.effects | EF_MUZZLEFLASH; + + makevectors(self.v_angle); + dir = v_forward; + + traceline (self.origin + '0 0 16', self.origin + dir*600 + '0 0 16', TRUE, self); + + msg_entity = self; + + WriteByte (MSG_ONE, SVC_TEMPENTITY); + WriteByte (MSG_ONE, TE_LIGHTNING1); + WriteEntity (MSG_ONE, self); + WriteCoord (MSG_ONE, self.origin_x); + WriteCoord (MSG_ONE, self.origin_y); + WriteCoord (MSG_ONE, self.origin_z + 8); + WriteCoord (MSG_ONE, trace_endpos_x); + WriteCoord (MSG_ONE, trace_endpos_y); + WriteCoord (MSG_ONE, trace_endpos_z); + + // show lightning differently for others + + msg_entity = find(msg_entity, classname, "player"); + if (msg_entity == world) + msg_entity = find(msg_entity, classname, "player"); + + while (msg_entity != self) { + WriteByte (MSG_ONE, SVC_TEMPENTITY); + WriteByte (MSG_ONE, TE_LIGHTNING1); + WriteEntity (MSG_ONE, self); + WriteCoord (MSG_ONE, self.origin_x); + WriteCoord (MSG_ONE, self.origin_y); + WriteCoord (MSG_ONE, self.origin_z + 20); + WriteCoord (MSG_ONE, trace_endpos_x); + WriteCoord (MSG_ONE, trace_endpos_y); + WriteCoord (MSG_ONE, trace_endpos_z); + + msg_entity = find(msg_entity, classname, "player"); + if (msg_entity == world) + msg_entity = find(msg_entity, classname, "player"); + } + + + LightningDamage (self.origin + '0 0 16', trace_endpos, self, 15); +}; + +void() Storm_Wind = +{ + local entity trav; + local float strength, dist; + local vector vect, vect_angle; + + sound (self, CHAN_WEAPON, "storm/w_attack.wav", 1, ATTN_NORM); + + trav = findradius(self.origin, 256); + while (trav != world) { + + // check that the object is damage-able and is infront of self + vect = normalize(trav.origin - self.origin); + vect_angle = vectoangles(vect); + + if ((trav != self) && + ((trav.takedamage) && (trav.movetype)) && + (fabs( angle_diff( vect_angle_y, self.angles_y)) < 35)) { // give em some wind + + strength = 200; + dist = vlen(trav.origin - self.origin); + if (dist > 128) { // reduce strength of blast + strength = ((dist - 128) / 128) * strength; + } + + // blast now + trav.flags = trav.flags - (trav.flags & FL_ONGROUND); + trav.velocity = (trav.velocity * 0.5) + (vect * 600); + trav.velocity_z = 300; + + trav.angles = trav.v_angle = self.angles; + trav.punchangle_x = -20; + trav.fixangle = TRUE; + + } + + trav = trav.chain; + } + + self.last_wind = time; +}; + +void() LaserTouch; +void() DM_Cyclops_Fast_Laser = +{ + local entity missile; + local vector vect; + + self.effects = self.effects | EF_MUZZLEFLASH; + stuffcmd(self, "rf\n"); // flash screen red + + sound (self, CHAN_VOICE, "items/inv1.wav", 1, ATTN_NORM); + + missile = spawn (); + missile.owner = self; + missile.movetype = MOVETYPE_BOUNCE; + missile.solid = SOLID_BBOX; + missile.classname = "laser"; + + makevectors(self.v_angle); + missile.velocity = v_forward * 1700; + + missile.angles = vectoangles(missile.velocity); + missile.old_velocity = missile.velocity; + + missile.touch = LaserTouch; + + missile.last_touch = 0; + missile.oldorigin = missile.origin; + missile.nextthink = time + 2; + missile.think = SUB_Remove; + + setmodel (missile, "progs/claser1.mdl"); + setsize (missile, '0 0 0', '0 0 0'); + setorigin (missile, self.origin + v_forward * 16 + '0 0 22'); +}; + +void() DM_Big_Laser_Touch = +{ + if (other == self.owner) + return; + + if (other.takedamage == DAMAGE_AIM) + { + spawn_touchblood (20); + T_Damage(other, self, self.owner, 30); + remove(self); + return; + } + + self.last_touch = time; + + sound (self, CHAN_WEAPON, "doors/airdoor2.wav", 1, ATTN_NORM); + if (self.velocity == '0 0 0') + remove(self); + +}; + +void() DM_Cyclops_Big_Laser = +{ + local entity missile; + local vector vect; + + self.effects = self.effects | EF_MUZZLEFLASH; + stuffcmd(self, "rf\n"); // flash screen red + + sound (self, CHAN_VOICE, "items/inv1.wav", 1, ATTN_NORM); + + missile = spawn (); + missile.owner = self; + missile.movetype = MOVETYPE_BOUNCE; + missile.solid = SOLID_BBOX; + missile.classname = "laser"; + + makevectors(self.v_angle); + missile.velocity = v_forward * 1200; + + missile.angles = vectoangles(missile.velocity); + missile.old_velocity = missile.velocity; + + missile.touch = DM_Big_Laser_Touch; + + missile.last_touch = 0; + missile.oldorigin = missile.origin; + missile.nextthink = time + 2; + missile.think = SUB_Remove; + + setmodel (missile, "progs/claser1.mdl"); + setsize (missile, '0 0 0', '0 0 0'); + setorigin (missile, self.origin + v_forward * 16 + '0 0 22'); +}; + +void() DM_Psylocke_Sword = +{ + local entity plyr; + local vector delta; + local float ldmg; + + makevectors(self.v_angle); + traceline(self.origin, self.origin + v_forward*55, FALSE, self); + + if (trace_ent.takedamage == DAMAGE_AIM) + plyr = trace_ent; + else + return; + +// if ((plyr = FindSightEnemy(self.origin, v_forward, 60, 40, "player", self)) == world) +// return; +/* + delta = plyr.origin - self.origin; + + if (vlen(delta) > 70) + return; +*/ + ldmg = 15 + random() * 5; + T_Damage (plyr, self, self, ldmg); +}; + + +void() DM_Psylocke_Parallize = +{ + makevectors(self.v_angle); + traceline(self.origin, self.origin + v_forward*48, FALSE, self); + + if (trace_ent.takedamage == DAMAGE_AIM) + { + // got 'em + sound(self, CHAN_WEAPON, "player/what_1.wav", 1, ATTN_NORM); + + trace_ent.parallize_time = time + 3; + trace_ent.x_flags = trace_ent.x_flags | X_PARALLIZED; + trace_ent.parallized_velocity = '0 0 0'; + centerprint(trace_ent, "You have been paralyzed"); + stuffcmd(trace_ent, "pl\n"); + } +}; + +void(float heading_ofs) DM_AngelFeather = +{ + local vector newangle, targ_vect; + local entity missile; + + newangle = self.v_angle; + newangle_y = anglemod(newangle_y + heading_ofs); + + newangle_x = newangle_x + (random() * 10) - 5; + + makevectors(newangle); + + launch_spike (self.origin + '0 0 16' + v_forward*14, v_forward); + newmis.classname = "angel_dart"; + setmodel (newmis, "progs/dart.mdl"); + setsize(newmis, '0 0 0', '0 0 0'); +}; + +void() DM_BeastPunch = +{ +local vector delta; +local float ldmg; +local entity plyr; + + makevectors(self.v_angle); + traceline(self.origin, self.origin + v_forward*55, FALSE, self); + + if (trace_ent.takedamage == DAMAGE_AIM) + plyr = trace_ent; + else + return; + + ldmg = 9 + random() * 3; + T_Damage (plyr, self, self, ldmg); + + if (random() < 0.5) + sound(self, CHAN_WEAPON, "generic/punch2.wav", 1, ATTN_NORM); + else + sound(self, CHAN_WEAPON, "generic/punch3.wav", 1, ATTN_NORM); +}; + +void() BeastPowTouch; +void() BeastPowThink; +void() DM_BeastPound = +{ + local entity trav, plyr; + local entity missile; + local vector vec; + + missile = spawn(); + missile.classname = "beast_power"; + missile.owner = self; + missile.solid = SOLID_TRIGGER; + missile.movetype = MOVETYPE_FLY; + + setsize(missile, '0 0 0', '0 0 0'); + setmodel(missile, "progs/pow.mdl"); + + makevectors(self.angles); + + if ((plyr = FindSightEnemy(self.origin, v_forward, 256, 20, "player", self)) != world) + missile.velocity = normalize(plyr.origin - self.origin + plyr.velocity * 0.5) * 750; + else { + missile.velocity = v_forward * 750; + } + missile.velocity_z = 0; + + setorigin(missile, self.origin + v_forward * 16); + + vec = missile.velocity; + traceline(missile.origin + vec*frametime*2 + '0 0 32', missile.origin + vec*frametime*2 - '0 0 48', TRUE, world); + if (trace_fraction <= 1) { + missile.velocity = normalize(trace_endpos + '0 0 24' - missile.origin) * 750; + + traceline(missile.origin + '0 0 32', missile.origin - '0 0 48', TRUE, world); + setorigin(missile, trace_endpos + '0 0 24'); + } + + missile.touch = BeastPowTouch; + missile.think = BeastPowThink; + missile.nextthink = time + 0.05; + missile.spawn_time = time; + + sound (self, CHAN_BODY, "weapons/r_exp3.wav", 0.4, ATTN_NORM); + sound (self, CHAN_WEAPON, "doors/stndr1.wav", 1, ATTN_NORM); + + // send players airbourne + trav = find(world, classname, "player"); + while (trav != world) { + if ((trav.flags & FL_ONGROUND) && (vlen(trav.origin - self.origin) < 256)) + trav.velocity_z = 200; + + trav = find(trav, classname, "player"); + } +}; + +void() DM_Gambit_Strike = +{ + local entity plyr; + local vector vect; + local float damg; + + makevectors(self.v_angle); + traceline(self.origin, self.origin + v_forward*55, FALSE, self); + + if (trace_ent.takedamage == DAMAGE_AIM) + plyr = trace_ent; + else + return; + + damg = 20 + random() * 5; + T_Damage (plyr, self, self, damg); +}; + +void(float heading_ofs, float zofs) DM_GambitCard = +{ + local vector newangle, targ_vect, ofs; + local entity missile; + + makevectors(self.v_angle); + targ_vect = v_forward; + newangle = vectoangles(targ_vect); + newangle_x = -1 * newangle_x; + newangle_y = anglemod(newangle_y + heading_ofs); + + makevectors(newangle); + + ofs = '0 0 0'; + ofs_z = zofs; + launch_spike (self.origin + ofs + v_forward*14, v_forward); + newmis.classname = "gambit_card"; + setmodel (newmis, "progs/card.mdl"); + setsize(newmis, '0 0 0', '0 0 0'); +}; + +void(vector org, vector dir) spawn_shard; +void(float offs) DM_Iceman_Shard = +{ + local vector org, vect, ang; + + ang = self.v_angle; + ang_y = anglemod(ang_y + offs); + + makevectors (ang); + vect = v_forward; + + org = self.origin + '0 0 12'; + + spawn_shard(org, vect); +}; + +void(vector org, vector dir) spawn_iceball; +void() DM_Iceman_Iceball = +{ + local vector org,o2; + + makevectors (self.v_angle); + + org = self.origin + v_forward * 12 + '0 0 16'; + + spawn_iceball(org, v_forward); +}; + + +void(float r_ofs) DM_Bishop_Shoot = +{ + local vector vect; + local entity missile; + + self.effects = self.effects | EF_MUZZLEFLASH; + + makevectors(self.v_angle); + + sound (self, CHAN_WEAPON, "doors/airdoor2.wav", 1, ATTN_NORM); + + launch_spike (self.origin + '0 0 10' + v_forward*14 + v_right * r_ofs, v_forward); + newmis.dmg = 15 + random() * 5; + newmis.classname = "bishop_laser"; + newmis.velocity = v_forward * 2000; + setmodel (newmis, "progs/laser.mdl"); + setsize(newmis, '0 0 0', '0 0 0'); +}; + +void() BishopSpecialTouch; +void() DM_Bishop_Special = +{ + local vector vect; + local entity missile; + + self.effects = self.effects | EF_MUZZLEFLASH; + + sound (self, CHAN_WEAPON, "boss1/throw.wav", 1, ATTN_NORM); + + makevectors(self.v_angle); + + vect = v_forward; + + launch_spike (self.origin + '0 0 12' + v_forward*14, vect); + newmis.velocity = newmis.velocity * 0.75; + newmis.classname = "bishop_special"; + newmis.touch = BishopSpecialTouch; + newmis.avelocity_z = 300; + setmodel (newmis, "progs/bisblast.mdl"); + setsize(newmis, '0 0 0', '0 0 0'); +}; + +void(float damage) DM_Rogue_Punch = +{ + local entity plyr; + local float damg; + + makevectors(self.v_angle); + traceline(self.origin, self.origin + v_forward*55, FALSE, self); + + if (trace_ent.takedamage == DAMAGE_AIM) + plyr = trace_ent; + else + return; + + // hurt enemy + T_Damage(plyr, self, self, damage); + + sound(self, CHAN_WEAPON, "zombie/z_hit.wav", 1, ATTN_NORM); +}; + +void() DM_Rogue_Fly = +{ + local float vspeed, maxspeed; + + makevectors(self.v_angle); + + vspeed = vlen(self.velocity); + maxspeed = cvar("sv_maxspeed"); + + if (vspeed < maxspeed) { + self.velocity = self.old_velocity + v_forward * 2000 * frametime; + if (vlen(self.velocity) > (maxspeed + 100)) + self.velocity = normalize(self.velocity) * (maxspeed + 50); + } + else { + self.velocity = v_forward * (maxspeed + 50); + } + + self.old_velocity = self.velocity; + + // check for punch + traceline(self.origin + '0 0 24', self.origin + '0 0 24' + v_forward*64, FALSE, self); + + if (trace_ent.takedamage == DAMAGE_AIM) { + T_Damage(trace_ent, self, self, 40 + random()*8); + sound(self, CHAN_WEAPON, "zombie/z_hit.wav", 1, ATTN_NORM); + } +}; + +void(float damage) DM_Cannon_Punch = +{ + local entity plyr; + local float damg; + + sound (self, CHAN_ITEM, "generic/swing1.wav", 1, ATTN_NORM); + + makevectors(self.v_angle); + traceline(self.origin, self.origin + v_forward*55, FALSE, self); + + if (trace_ent.takedamage == DAMAGE_AIM) + plyr = trace_ent; + else + return; + + // hurt enemy + T_Damage(plyr, self, self, damage); + + if (random() < 0.5) + sound(self, CHAN_WEAPON, "generic/punch2.wav", 1, ATTN_NORM); + else + sound(self, CHAN_WEAPON, "generic/punch3.wav", 1, ATTN_NORM); +}; + +void() DM_Cannon_Fly = +{ + local float vspeed, maxspeed; + + makevectors(self.v_angle); + + vspeed = vlen(self.velocity); + maxspeed = cvar("sv_maxspeed"); + + if (vspeed < maxspeed) { + self.velocity = self.old_velocity + v_forward * 2000 * frametime; + if (vlen(self.velocity) > (maxspeed + 100)) + self.velocity = normalize(self.velocity) * (maxspeed + 150); + } + else { + self.velocity = v_forward * (maxspeed + 150); + } + + if (self.last_flame_sound < (time - 0.75)) { + if (self.last_weapon_channel != CHAN_ITEM) { + sound (self, CHAN_ITEM, "cannon/flyloop.wav", 1, ATTN_NORM); + self.last_weapon_channel = CHAN_ITEM; + } else { + sound (self, CHAN_VOICE, "cannon/flyloop.wav", 1, ATTN_NORM); + self.last_weapon_channel = CHAN_VOICE; + } + + self.last_flame_sound = time; + } + + self.old_velocity = self.velocity; + + // check for punch + traceline(self.origin + '0 0 24', self.origin + '0 0 24' + v_forward*64, FALSE, self); + + if (trace_ent.takedamage == DAMAGE_AIM) { + T_Damage(trace_ent, self, self, 40 + random()*8); + sound (self, CHAN_BODY, "generic/swing1.wav", 1, ATTN_NORM); + + if (random() < 0.5) + sound(self, CHAN_WEAPON, "generic/punch2.wav", 1, ATTN_NORM); + else + sound(self, CHAN_WEAPON, "generic/punch3.wav", 1, ATTN_NORM); + } + + if (trace_fraction < 1) { + self.weaponframe = 14; // abort fly + } +}; + + +void() BeamPlayerTouch = +{ + local float vspeed, damg; + + if (self.last_wall_hit > (time - 1)) + return; + + if (other != world) + return; + + if (self.enemy.enemy != self) { + self.enemy = world; + self.touch = SUB_Null; + return; + } + + vspeed = vlen(self.velocity); + + if (vspeed < 100) + return; + + // make sure player is travelling somewhat sideways + if (fabs(self.velocity_z) > 40) + return; + + // find out which wall was likely to have been hit + traceline(self.origin, self.origin + self.velocity * 2, TRUE, self); + if (trace_fraction == 1) + return; + + if (fabs(trace_plane_normal_z) > 0.3) + return; + +//bprint(ftos(vspeed)); +//bprint("\n"); + + damg = vspeed / 200; + if (damg > 25) + damg = 25; + + // wall damage + T_Damage(self, self.enemy, self.enemy, damg); + self.last_wall_hit = time; +}; + +void() DM_TractorThink = +{ + local vector ideal_pos; + + makevectors(self.owner.v_angle); + + ideal_pos = self.owner.origin + v_forward * self.owner.tractor_dist; + + if (vlen(ideal_pos - self.owner.enemy.origin) > 8) + self.owner.enemy.velocity = self.owner.enemy.tractor_vel = (ideal_pos - self.owner.enemy.origin) * 4; + else + self.owner.enemy.velocity = self.owner.enemy.tractor_vel = '0 0 0'; + + self.owner.enemy.flags = self.owner.enemy.flags - (self.owner.enemy.flags & FL_ONGROUND); + + self.nextthink = time + 0.05; +}; + +void() TractorParticleThink; +void() DM_PhoenixStartBeam = +{ + // if player is already in a beam, abort attack + if ((self.enemy.x_flags & X_TRACTOR_BEAM_HOLD) && (self.enemy.flags & FL_GODMODE)) { + self.enemy = world; + return; + } + + sound(self.enemy, CHAN_WEAPON, "items/damage3.wav", 1, ATTN_NORM); + + self.flags = self.flags | FL_GODMODE; + self.last_special = time; + self.start_attack_health = self.health; + + self.tractor_dist = vlen(self.enemy.origin - self.origin); + + self.enemy.enemy = self; + self.enemy.touch = BeamPlayerTouch; + + self.enemy.x_flags = self.enemy.x_flags | X_TRACTOR_BEAM_HOLD; + self.enemy.velocity = self.enemy.tractor_vel = '0 0 100'; + setorigin(self.enemy, self.enemy.origin + '0 0 1'); + self.enemy.flags = self.enemy.flags - (self.enemy.flags & FL_ONGROUND); + + self.start_tractor_time = time; + self.enemy.start_tractor_time = time; + + self.move_ent = spawn(); + self.move_ent.owner = self; + + self = self.move_ent; + + self.flame_ent1 = spawn(); + self.flame_ent2 = spawn(); + self.flame_ent3 = spawn(); + + setmodel(self.flame_ent1, "progs/beampart.mdl"); + setmodel(self.flame_ent2, "progs/beampart.mdl"); + setmodel(self.flame_ent3, "progs/beampart.mdl"); + + setorigin(self.flame_ent1, self.origin); + setorigin(self.flame_ent2, self.origin); + setorigin(self.flame_ent3, self.origin); + + self.flame_ent1.nextthink = time + 0.05; + self.flame_ent2.nextthink = time + 0.05; + self.flame_ent3.nextthink = time + 0.05; + + // speed to travel + self.flame_ent1.speed = 800; + self.flame_ent2.speed = 400; + self.flame_ent3.speed = 200; + + // distance from Phoenix + self.flame_ent1.t_length = 0; + self.flame_ent2.t_length = 0; + self.flame_ent3.t_length = 0; + + // distance from center of tractor beam + self.flame_ent1.z_ofs = 10; + self.flame_ent2.z_ofs = 5; + self.flame_ent3.z_ofs = 0; + + // 1 = travelling away from center, -1 = travelling towards center + self.flame_ent1.z_ofs_vel = -2; + self.flame_ent2.z_ofs_vel = 2.5; + self.flame_ent3.z_ofs_vel = 1; + + self.flame_ent1.think = TractorParticleThink; + self.flame_ent2.think = TractorParticleThink; + self.flame_ent3.think = TractorParticleThink; + + self.flame_ent1.owner = self.owner; + self.flame_ent2.owner = self.owner; + self.flame_ent3.owner = self.owner; + + self.think = DM_TractorThink; + self.nextthink = time + 0.05; + + self = self.owner; +}; + +void() DM_PhoenixBeamEnd = +{ + if (self.enemy != world) { + self.enemy.x_flags = self.enemy.x_flags - (self.enemy.x_flags & X_TRACTOR_BEAM_HOLD); + self.enemy.velocity = normalize(self.enemy.origin - self.origin) * 250 + '0 0 100'; + + // hurt enemy +// damage is now inflicted by smashing them against a wall + T_Damage(self.enemy, self, self, 10); + self.enemy.touch = SUB_Null; + + self.enemy.punchangle_x = -8; + + self.enemy = world; + } + + if (self.move_ent != world) { + remove(self.move_ent.flame_ent1); + remove(self.move_ent.flame_ent2); + remove(self.move_ent.flame_ent3); + remove(self.move_ent); + + self.move_ent = world; + } +}; + +void() DM_PhoenixFireHoming = +{ + local entity missile, missile_enemy; + local vector dir; + + missile = spawn (); + missile.classname = "dm_phoenix_blast"; + missile.attack_finished = time + 3; + missile.owner = self; + missile.movetype = MOVETYPE_FLYMISSILE; + missile.solid = SOLID_BBOX; + + missile.think = GuidedRocketThink; + missile.last_guided_search = time; + missile.nextthink = time + 0.05; + + // set missile speed + makevectors(self.v_angle); + + missile.velocity = v_forward; + missile.velocity = missile.velocity * 800; + missile.angles = vectoangles(missile.velocity); + missile.angles_x = -1 * missile.angles_x; + + missile.touch = T_GuidedMissileTouch; + + missile.avelocity_z = 300; + + setmodel (missile, "progs/psyblast.mdl"); + setsize (missile, '0 0 0', '0 0 0'); + setorigin (missile, self.origin + dir*8 + '0 0 12'); + + sound(self, CHAN_WEAPON, "cannon/takeoff.wav", 1, ATTN_NORM); +}; + +// ************************************************************************** + +void() DoSpecialWeaponStuff = +{ + local float frame_num; + + frame_num = self.weaponframe - 6; + + if (self.character == CHAR_WOLVERINE) { + if (!self.special_weapon) { + if (frame_num == 5) + Wolvy_Melee(200); + else if (frame_num == 9) + Wolvy_Melee(-200); + } + else { + if (frame_num == 1) // jump now + Wolvy_Jump(); + else if ((frame_num >= 7) && (frame_num <= 10)) + Wolvy_JumpThink (); + } + } + else if (self.character == CHAR_STORM) { + if (!self.special_weapon) { + if (frame_num == 5) + Storm_Wind(); + } + else { + if ((frame_num >= 7) && (frame_num <= 10)) + Storm_Lightning(); + if (frame_num == 7) + sound (self, CHAN_WEAPON, "storm/l_attack.wav", 1, ATTN_NORM); + } + } + else if (self.character == CHAR_CYCLOPS) { + if (!self.special_weapon) { // Fast Laser + if ((frame_num == 2) || (frame_num == 7)) + DM_Cyclops_Fast_Laser(); + } + else { // Big Laser Blast + if (frame_num == 8) + DM_Cyclops_Big_Laser(); + } + } + else if (self.character == CHAR_PSYLOCKE) { + if (!self.special_weapon) { // Sword Attack + if ((frame_num == 2) || (frame_num == 7)) + DM_Psylocke_Sword(); + } + else { // Parallize Attack + if (frame_num == 8) + DM_Psylocke_Parallize(); + } + } + else if (self.character == CHAR_ANGEL) { + if (!self.special_weapon) { // Throw Darts + if ((frame_num >= 3) && (frame_num <= 9)) { + DM_AngelFeather( (frame_num - 6) * 5 ); + } + } + else { // Wing Defense + if (frame_num == 5) { + self.x_flags = self.x_flags | X_ANGEL_DEFENSE; + self.flags = self.flags | FL_GODMODE; + } + else if ((frame_num == 10) && (self.button0)) // stay at this frame while button down + self.weaponframe = self.weaponframe - 1; + else if (frame_num == 11) { + self.x_flags = self.x_flags - (self.x_flags & X_ANGEL_DEFENSE); + self.flags = self.flags - (self.flags & FL_GODMODE); + } + } + } + else if (self.character == CHAR_BEAST) { + if (!self.special_weapon) { // Double Punch + if ((frame_num == 4) || + (frame_num == 7) || + (frame_num == 10)) { + DM_BeastPunch(); + } + } + else { // Floor Pound + if (frame_num == 4) { // give some jump + if (self.flags & FL_ONGROUND) + self.velocity_z = 190; + } + else if (frame_num == 11) { + DM_BeastPound(); + } + } + } + else if (self.character == CHAR_GAMBIT) { + if (!self.special_weapon) { // Staff Attack + if (frame_num == 7) + DM_Gambit_Strike(); + else if (frame_num == 3) + sound (self, CHAN_WEAPON, "generic/swing1.wav", 1, ATTN_NORM); + } + else { // Throw Cards + if ((frame_num >= 5) && (frame_num <= 7)) { + DM_GambitCard( (frame_num - 6) * -5, 12 ); + } + if (frame_num == 4) + sound (self, CHAN_WEAPON, "boss1/throw.wav", 1, ATTN_NORM); + } + } + else if (self.character == CHAR_ICEMAN) { + if (!self.special_weapon) { // Small Shards + if ((frame_num >= 3) && (frame_num <= 8)) { + DM_Iceman_Shard( (frame_num - 6) * 4 ); + } + } + else { // Big Freeze + if (frame_num == 10) + DM_Iceman_Iceball(); + } + } + else if (self.character == CHAR_BISHOP) { + if (!self.special_weapon) { // Dual Guns + if (frame_num == 2) + DM_Bishop_Shoot(6); + else if (frame_num == 7) + DM_Bishop_Shoot(-6); + } + else { + if (frame_num == 5) + DM_Bishop_Special(); + } + } + else if (self.character == CHAR_ROGUE) { + if (!self.special_weapon) { // Dual Punch + if ((frame_num == 4) || + (frame_num == 10)) + DM_Rogue_Punch(10); + } + else { // Flying Punch + if (frame_num == 2) { + self.last_special = time; + } + else if (frame_num == 3) { + if (self.button0) { + self.x_flags = self.x_flags | X_FLYING; + self.flags = self.flags | FL_ONGROUND; + + DM_Rogue_Fly(); + + if (self.last_special > (time - 5) && (trace_ent.classname != "player")) + self.weaponframe = self.weaponframe - 1; + } + } + else if (frame_num == 6) { + self.x_flags = self.x_flags - (self.x_flags & X_FLYING); + } + } + } + else if (self.character == CHAR_CANNONBALL) { + if (!self.special_weapon) { // Punch + if (frame_num == 6) + DM_Cannon_Punch(10); + } + else { // Flying Punch + if (frame_num == 1) { + sound(self, CHAN_ITEM, "cannon/takeoff.wav", 1, ATTN_NORM); + } + + if (frame_num < 6) { + self.last_special = time; + self.x_flags = self.x_flags | X_FLYING; + self.effects = self.effects | EF_DIMLIGHT; + self.velocity_z = self.old_velocity_z = 100; + } + else if (frame_num < 9) { + self.flags = self.flags | FL_ONGROUND; + DM_Cannon_Fly(); + + if ((self.button0) && (trace_fraction == 1) && (frame_num == 8) && (self.last_special > (time - 5))) { + self.weaponframe = self.weaponframe - 3; + } + } + else if (frame_num == 9) { + self.last_special2 = time; + self.attack_finished = time + 2; + self.effects = self.effects - (self.effects & EF_DIMLIGHT); +// DM_Cannon_Punch(30 + random()*15); + self.x_flags = self.x_flags - (self.x_flags & X_FLYING); + } + } + } + else if (self.character == CHAR_PHOENIX) { + if (!self.special_weapon) { // Tractor Beam + if (frame_num == 1) + self.enemy = world; + else if (frame_num < 6) { + if (self.enemy == world) { + makevectors(self.v_angle); + traceline(self.origin + '0 0 16', self.origin + '0 0 16' + v_forward * 512, FALSE, self); + + if (((trace_ent.touch == ammo_touch) || + (trace_ent.classname == "guided_rocket") || + (trace_ent.classname == "orb") || + (trace_ent.flags & FL_MONSTER) || + (trace_ent.classname == "player")) && (trace_ent != self)) + self.enemy = trace_ent; + else + self.enemy = world; + } + } + else if (frame_num == 6) { + if (self.enemy != world) { + DM_PhoenixStartBeam(); + } + } + else if (frame_num == 8) { + if ((self.enemy != world) && (self.start_attack_health <= self.health) && (self.start_tractor_time > (time - 4)) && (self.button0) && (self.flags & FL_GODMODE)) { + traceline(self.origin, self.enemy.origin, TRUE, world); + if (trace_fraction == 1) + self.weaponframe = self.weaponframe - 1; + } + } + else if (frame_num == 9) { + DM_PhoenixBeamEnd(); + self.flags = self.flags - (self.flags & FL_GODMODE); + self.enemy = world; + } + } + else { // Homing missile + if (frame_num == 4) + DM_PhoenixFireHoming(); + } + } +}; diff --git a/X_TRIG.c b/X_TRIG.c new file mode 100644 index 0000000..a4d8300 --- /dev/null +++ b/X_TRIG.c @@ -0,0 +1,43 @@ +/* Begin Xmen +triggers revision 1 +-cl2- + +Files involved: + +x_trig.qc (this file) +*/ + +// trigger_constant +// triggers all is targets, waits for self.wait, repeats until triggered +// spawnflags: +// 1 : Starts off + +void() tc_go = +{ +activator = world; +SUB_UseTargets(); +self.nextthink = time + self.wait; +}; + +void() tc_use = +{ +self.state = 1 - self.state; +if (self.state) + { + self.think = tc_go; + self.nextthink = time + self.wait; + } +else self.nextthink = time + 9999999; +}; + +void() trigger_constant = +{ +self.use = tc_use; +if (!self.wait) self.wait = 0.2; +if (self.spawnflags & 1) self.state = 0; else self.state = 1; +if (self.state) + { + self.think = tc_go; + self.nextthink = time + 0.2; + } +}; diff --git a/X_VARS.c b/X_VARS.c new file mode 100644 index 0000000..aef3666 --- /dev/null +++ b/X_VARS.c @@ -0,0 +1,159 @@ +// General variables +.float last_special, last_special2; +.float x_flags; +.float start_health; +.float parallize_time; +.vector parallized_velocity; +.float guard_flag; +.float ammo_special; +.float weapon_parts; +.float char_type; // uses CT_* constants (see below) +.float tractor_dist; // how far enemy is from Phoenix player +.float last_clear; // used to clear screen of colors every few seconds +.float rapid_time; +.float last_wall_hit; // used for Phoenix Tractor beam smash into wall +.float last_prox_think; + +.vector respawn_point; + +.float prox_power; // builds up before releasing button with proximity weapon +.entity prox_ent; +.string last_centerprint; + +.void() th_guard; + +// this overrides the normal centerprint, so we can save each new centerprint +void(entity client, string s) centerprint; + +float X_PARALLIZED = 1; +float X_CANNONFLYABORT = 2; +float X_TRACTOR_BEAM_HOLD = 4; +float X_SINISTER_FINAL = 8; +float X_ANGEL_DEFENSE = 16; +float X_STGUN = 32; +float X_FLYING = 64; + +float X_RAPID_FIRE = 128; +float X_RAPID_WARNING = 512; + +float X_MEGA_HIT = 1024; + +float X_AMMO_ANIMATE = 2048; +float X_GODCHEAT = 4096; + +float X_JUMP_PRESSED = 8192; + +float CT_MALE_NORMAL = 1; +float CT_MALE_LARGE = 2; +float CT_FEMALE = 3; + +// Globals +entity damage_inflictor; +float index_skeleton; + +string executable; // use temp1 to set executable before entering game + // temp1: 0 = dos, 1 = glQuake, 2 = winQuake +float num_clients; + +// debugging toggles +float show_damage; // used in SetDamageSkin(), gives % readout + +// spawnflags +float SPAWNFLAG_CLONE = 8; + +// deathmatch vars +.float special_weapon; // 0 or 1, toggles with subsequent IMPULSE 1 commands +.float character; // one of CHAR_*, may only be set upon joining the game + // if 0, then player can't move and must select a character +.float last_jump_z; // Z value of origin when jump was pressed (used by Angel hovering) +.float last_jump; // time of last jump press + +float CHAR_WOLVERINE = 1; +float CHAR_STORM = 2; +float CHAR_CYCLOPS = 3; +float CHAR_PSYLOCKE = 4; +float CHAR_ANGEL = 5; +float CHAR_BEAST = 6; +float CHAR_GAMBIT = 7; +float CHAR_ICEMAN = 8; +float CHAR_BISHOP = 9; +float CHAR_ROGUE = 10; +float CHAR_CANNONBALL = 11; +float CHAR_PHOENIX = 12; + +float STORM_VOFS_Z = 0; + +float DM_SPECIAL_POWERS = 10; // set deathmatch = DM_SPECIAL_POWERS for no weapons + +// weapon stuff +.float nextweapon; +.float change_weapon_status; +.float fadeout_endframe; +.float fadein_endframe; +.float last_fade; +.float weapon_flags; +.float remember_impulse; // stores a change weapon impulse while changing weapons +.float weapon_idleframe; +.float water_flame_flag; +.float consecutive_count, w_pausetime, last_pausetime; // used to pause flame gun after 3 shots + +float W_RELOADING = 1; +float W_SHOTRELOAD = 2; +float DEATH_FLAG = 4; + +float CW_DONE = 0; +float CW_FADEOUT = 1; +float CW_FADEIN = 2; + +// Flame thrower vars +float FLAME_DIST = 112; // distance between each junction +float FLAME_ENT_SPEED = 650; // speed of movement towards ideal position + +float SNDLEN_FLAME = 0.2; + +.entity flame_ent1; // trail of 3 flamethrower junction entities +.entity flame_ent2; +.entity flame_ent3; + +.float last_flame; +.float last_flame_sound; + +// Laser gun vars +.float fire_reload_frames; +.float last_fire_laser; +.float spawn_time; + +// Storm vars +float MAX_Z_OFS = 20; + +.float last_wind; +.float z_ofs; +.float z_ofs_vel; + +// Cyclops +.float start_attack_health; +.float last_touch; +.vector old_velocity; // also used for Player as Angel in deathmatch for floating downwards + +// tech dude +.float start_frame, last_frame; +.float tech_state; + +float TECH_IDLE = 0; +float TECH_WALKING = 1; +float TECH_HIDING = 2; + + +// Pheonix +.entity move_ent; +.float start_tractor_time; +.vector tractor_vel; + +// Trap Flamethrower +.float sway_range; + +// Apocalypse +.entity leg; // main legs entity, displays appy1.mdl + +// Cannonball +.float last_rocket_hit; diff --git a/angel.c b/angel.c new file mode 100644 index 0000000..eaeca1c --- /dev/null +++ b/angel.c @@ -0,0 +1,579 @@ +/* +============================================================================== + +WIZARD + +============================================================================== +*/ + +$frame hover1 hover2 hover3 hover4 hover5 hover6 hover7 hover8 hover9 +$frame hover10 hover11 hover12 hover13 + +$frame slow1 slow2 slow3 slow4 slow5 slow6 slow7 slow8 slow9 +$frame slow10 slow11 slow12 slow13 + +$frame fast1 fast2 fast3 fast4 fast5 fast6 fast7 fast8 + +$frame pain1 pain2 pain3 pain4 pain5 pain6 + +$frame guard1 guard2 guard3 guard4 guard5 guard6 guard7 guard8 guard9 +$frame guard10 guard11 guard12 + +$frame death1 death2 death3 death4 death5 death6 death7 death8 death9 death10 +$frame death11 death12 death13 death14 death15 death16 death17 death18 death19 death20 + +$frame deatha1 deatha2 deatha3 deatha4 deatha5 deatha6 deatha7 deatha8 deatha9 deatha10 +$frame deatha11 deatha12 deatha13 deatha14 deatha15 deatha16 deatha17 deatha18 deatha19 deatha20 + +$frame attack1 attack2 attack3 attack4 attack5 attack6 attack7 attack8 +$frame attack9 attack10 attack11 attack12 attack13 + +/* +============================================================================== + +WIZARD + +If the player moves behind cover before the missile is launched, launch it +at the last visible spot with no velocity leading, in hopes that the player +will duck back out and catch it. +============================================================================== +*/ + +/* +============= +LaunchMissile + +Sets the given entities velocity and angles so that it will hit self.enemy +if self.enemy maintains it's current velocity +0.1 is moderately accurate, 0.0 is totally accurate +============= +*/ +void(entity missile, float mspeed, float accuracy) LaunchMissile = +{ + local vector vec, move; + local float fly; + + makevectors (self.angles); + +// set missile speed + vec = self.enemy.origin + self.enemy.mins + self.enemy.size * 0.7 - missile.origin; + +// calc aproximate time for missile to reach vec + fly = vlen (vec) / mspeed; + +// get the entities xy velocity + move = self.enemy.velocity; + move_z = 0; + +// project the target forward in time + vec = vec + move * fly; + + vec = normalize(vec); + vec = vec + accuracy*v_up*(random()- 0.5) + accuracy*v_right*(random()- 0.5); + + missile.velocity = vec * mspeed; + + missile.angles = '0 0 0'; + missile.angles_y = vectoyaw(missile.velocity); + +// set missile duration + missile.nextthink = time + 5; + missile.think = SUB_Remove; +}; + + +void() wiz_run1; +void() wiz_side1; + +/* +================= +WizardCheckAttack +================= +*/ +float() WizardCheckAttack = +{ + local vector spot1, spot2; + local entity targ; + local float chance; + + if (time < self.attack_finished) + return FALSE; + if (!enemy_vis) + return FALSE; + + if (enemy_range == RANGE_FAR) + { + if (self.attack_state != AS_STRAIGHT) + { + self.attack_state = AS_STRAIGHT; + wiz_run1 (); + } + return FALSE; + } + + targ = self.enemy; + +// see if any entities are in the way of the shot + spot1 = self.origin + self.view_ofs; + spot2 = targ.origin + targ.view_ofs; + + traceline (spot1, spot2, FALSE, self); + + if (trace_ent != targ) + { // don't have a clear shot, so move to a side + if (self.attack_state != AS_STRAIGHT) + { + self.attack_state = AS_STRAIGHT; + wiz_run1 (); + } + return FALSE; + } + + if (enemy_range == RANGE_MELEE) + chance = 0.9; + else if (enemy_range == RANGE_NEAR) + chance = 0.6; + else if (enemy_range == RANGE_MID) + chance = 0.2; + else + chance = 0; + + if (random () < chance) + { + self.attack_state = AS_MISSILE; + return TRUE; + } + + if ((enemy_range == RANGE_MID) && (vlen(self.origin - self.enemy.origin) > 256)) // keep at a distance + { + if (self.attack_state != AS_STRAIGHT) + { + self.attack_state = AS_STRAIGHT; + wiz_run1 (); + } + } + else + { + if (self.attack_state != AS_SLIDING) + { + self.attack_state = AS_SLIDING; + wiz_side1 (); + } + } + + return FALSE; +}; + +/* +================= +WizardAttackFinished +================= +*/ +float() WizardAttackFinished = +{ + if (enemy_range >= RANGE_MID || !enemy_vis) + { + self.attack_state = AS_STRAIGHT; + self.think = wiz_run1; + } + else + { + self.attack_state = AS_SLIDING; + self.think = wiz_side1; + } +}; + +/* +============================================================================== + +FAST ATTACKS + +============================================================================== +*/ + +void() Wiz_FastFire = +{ + local vector vec; + local vector dst; + + if (self.owner.health > 0) + { + self.owner.effects = self.owner.effects | EF_MUZZLEFLASH; + + makevectors (self.enemy.angles); + dst = self.enemy.origin - 13*self.movedir + (self.enemy.velocity * 0.3); + + vec = normalize(dst - self.origin); + launch_spike (self.origin, vec); + newmis.velocity = vec*600; + newmis.owner = self.owner; + newmis.classname = "angel_dart"; + setmodel (newmis, "progs/dart.mdl"); + setsize (newmis, VEC_ORIGIN, VEC_ORIGIN); + } + + remove (self); +}; + + +void() Wiz_StartFast = +{ + local entity missile; + + self.v_angle = self.angles; + makevectors (self.angles); + + missile = spawn (); + missile.owner = self; + missile.nextthink = time + 0.6; + setsize (missile, '0 0 0', '0 0 0'); + setorigin (missile, self.origin + '0 0 30' + v_forward*14 + v_right*14); + missile.enemy = self.enemy; + missile.nextthink = time + 0.8; + missile.think = Wiz_FastFire; + missile.movedir = v_right; + + missile = spawn (); + missile.owner = self; + missile.nextthink = time + 1; + setsize (missile, '0 0 0', '0 0 0'); + setorigin (missile, self.origin + '0 0 30' + v_forward*14 + v_right* -14); + missile.enemy = self.enemy; + missile.nextthink = time + 0.3; + missile.think = Wiz_FastFire; + missile.movedir = VEC_ORIGIN - v_right; +}; + +void(float heading_ofs) AngelFeather = +{ + local vector newangle, targ_vect; + local entity missile; + + newangle = self.angles; + newangle_y = anglemod(newangle_y + heading_ofs); + + targ_vect = normalize(self.enemy.origin - (self.origin + '0 0 30')); + targ_vect = vectoangles(targ_vect); + newangle_x = -1 * targ_vect_x; + newangle_x = newangle_x + (random() * 20) - 10; + + makevectors(newangle); + + launch_spike (self.origin + '0 0 30' + v_forward*14, v_forward); + newmis.classname = "angel_dart"; + setmodel (newmis, "progs/dart.mdl"); + setsize(newmis, '0 0 0', '0 0 0'); +}; + + +void() Wiz_idlesound = +{ +local float wr; + + return; +}; + +void() AngelPitch = +{ + local vector vect; + + if (self.enemy != world) + vect = normalize(self.enemy.origin - self.origin); + else + vect = '1 0 0'; + + vect = vectoangles(vect); + vect_x = -1 * vect_x; + + if (vect_x < -25) vect_x = -25; + else if (vect_x > 40) vect_x = 40; + + vect_x = anglemod(vect_x); + self.angles_x = anglemod(self.angles_x); + + if (self.solid != SOLID_NOT) + self.angles_x = MoveToAngle(self.angles_x, vect_x, 45); + else + self.angles_x = MoveToAngle(self.angles_x, vect_x, 180); + + if (self.angles_x > 180) + self.angles_x = self.angles_x - 360; +}; + + +void() RandomFlapSound = +{ + local float rnd; + + rnd = random() * 6; + + if (rnd < 1) + self.noise = "angel/flap1.wav"; + else if (rnd < 2) + self.noise = "angel/flap2.wav"; + else if (rnd < 3) + self.noise = "angel/flap3.wav"; + else if (rnd < 4) + self.noise = "angel/flap4.wav"; + else if (rnd < 5) + self.noise = "angel/flap5.wav"; + else if (rnd < 6) + self.noise = "angel/flap6.wav"; + + sound(self, CHAN_BODY, self.noise, 1, 3); +}; + + +void() wiz_stand1 =[ $hover1, wiz_stand2 ] {ai_stand();}; +void() wiz_stand2 =[ $hover2, wiz_stand3 ] {ai_stand();}; +void() wiz_stand3 =[ $hover3, wiz_stand4 ] {ai_stand();}; +void() wiz_stand4 =[ $hover4, wiz_stand5 ] {ai_stand();}; +void() wiz_stand5 =[ $hover5, wiz_stand6 ] {ai_stand(); RandomFlapSound();}; +void() wiz_stand6 =[ $hover6, wiz_stand7 ] {ai_stand();}; +void() wiz_stand7 =[ $hover7, wiz_stand8 ] {ai_stand();}; +void() wiz_stand8 =[ $hover8, wiz_stand9 ] {ai_stand();}; +void() wiz_stand9 =[ $hover9, wiz_stand10 ] {ai_stand();}; +void() wiz_stand10 =[ $hover10, wiz_stand11 ] {ai_stand();}; +void() wiz_stand11 =[ $hover11, wiz_stand12 ] {ai_stand();}; +void() wiz_stand12 =[ $hover12, wiz_stand13 ] {ai_stand();}; +void() wiz_stand13 =[ $hover13, wiz_stand1 ] {ai_stand();}; + +void() wiz_walk1 =[ $slow1, wiz_walk2 ] {ai_walk(10);}; +void() wiz_walk2 =[ $slow2, wiz_walk3 ] {ai_walk(10);}; +void() wiz_walk3 =[ $slow3, wiz_walk4 ] {ai_walk(10); RandomFlapSound();}; +void() wiz_walk4 =[ $slow4, wiz_walk5 ] {ai_walk(10);}; +void() wiz_walk5 =[ $slow5, wiz_walk6 ] {ai_walk(10);}; +void() wiz_walk6 =[ $slow6, wiz_walk7 ] {ai_walk(10);}; +void() wiz_walk7 =[ $slow7, wiz_walk8 ] {ai_walk(10);}; +void() wiz_walk8 =[ $slow8, wiz_walk9 ] {ai_walk(10);}; +void() wiz_walk9 =[ $slow9, wiz_walk10 ] {ai_walk(10);}; +void() wiz_walk10 =[ $slow10, wiz_walk11 ] {ai_walk(10);}; +void() wiz_walk11 =[ $slow11, wiz_walk12 ] {ai_walk(10);}; +void() wiz_walk12 =[ $slow12, wiz_walk13 ] {ai_walk(10);}; +void() wiz_walk13 =[ $slow13, wiz_walk1 ] {ai_walk(10);}; + +void() wiz_side1 =[ $slow1, wiz_side2 ] {ai_run(14);}; +void() wiz_side2 =[ $slow2, wiz_side3 ] {ai_run(14);}; +void() wiz_side3 =[ $slow3, wiz_side4 ] {ai_run(14); RandomFlapSound();}; +void() wiz_side4 =[ $slow4, wiz_side5 ] {ai_run(14);}; +void() wiz_side5 =[ $slow5, wiz_side6 ] {ai_run(14);}; +void() wiz_side6 =[ $slow6, wiz_side7 ] {ai_run(14);}; +void() wiz_side7 =[ $slow7, wiz_side8 ] {ai_run(14);}; +void() wiz_side8 =[ $slow8, wiz_side9 ] {ai_run(14);}; +void() wiz_side9 =[ $slow9, wiz_side10 ] {ai_run(14);}; +void() wiz_side10 =[ $slow10, wiz_side11 ] {ai_run(14);}; +void() wiz_side11 =[ $slow11, wiz_side12 ] {ai_run(14);}; +void() wiz_side12 =[ $slow12, wiz_side13 ] {ai_run(14);}; +void() wiz_side13 =[ $slow13, wiz_side1 ] {ai_run(14);}; + +void() wiz_run1 =[ $slow1, wiz_run2 ] {ai_run(20);}; +void() wiz_run2 =[ $slow2, wiz_run3 ] {ai_run(20);}; +void() wiz_run3 =[ $slow3, wiz_run4 ] {ai_run(20);}; +void() wiz_run4 =[ $slow4, wiz_run5 ] {ai_run(20);}; +void() wiz_run5 =[ $slow5, wiz_run6 ] {ai_run(20);}; +void() wiz_run6 =[ $slow6, wiz_run7 ] {ai_run(20);}; +void() wiz_run7 =[ $slow7, wiz_run8 ] {ai_run(20);}; +void() wiz_run8 =[ $slow8, wiz_run9 ] {ai_run(20);}; +void() wiz_run9 =[ $slow9, wiz_run10 ] {ai_run(20);}; +void() wiz_run10 =[ $slow10, wiz_run11 ] {ai_run(20);}; +void() wiz_run11 =[ $slow11, wiz_run12 ] {ai_run(20);}; +void() wiz_run12 =[ $slow12, wiz_run13 ] {ai_run(20);}; +void() wiz_run13 =[ $slow13, wiz_run1 ] {ai_run(20);}; + +float() AngelCheckGuard = +{ + local entity trav; + + trav = world; + while ((trav = find(trav, classname, "guided_rocket")) != world) { + + // check that rocket is targetted for self + if (trav.enemy == self) { // uh oh + return TRUE; + } + + } + + // dangerous rocket not found + self.think = self.th_run; + + self.flags = self.flags - (self.flags & FL_GODMODE); + + return FALSE; +}; + +void() wiz_guard1 =[ $guard1, wiz_guard2 ] {self.nextthink = time + 0.05;}; +void() wiz_guard2 =[ $guard2, wiz_guard3 ] {self.nextthink = time + 0.05;}; +void() wiz_guard3 =[ $guard3, wiz_guard4 ] {self.nextthink = time + 0.05;}; +void() wiz_guard4 =[ $guard4, wiz_guard5 ] {self.nextthink = time + 0.05;}; +void() wiz_guard5 =[ $guard5, wiz_guard6 ] {self.nextthink = time + 0.05;}; +void() wiz_guard6 =[ $guard6, wiz_guard7 ] {self.flags = self.flags | FL_GODMODE;}; +void() wiz_guard7 =[ $guard7, wiz_guard8 ] {}; +void() wiz_guard8 =[ $guard8, wiz_guard9 ] {}; +void() wiz_guard9 =[ $guard9, wiz_guard10 ] {}; +void() wiz_guard10 =[ $guard10, wiz_guard11 ] {}; +void() wiz_guard11 =[ $guard11, wiz_guard12 ] {}; +void() wiz_guard12 =[ $guard12, wiz_guard12 ] {AngelCheckGuard();}; + +void() wiz_attack1 =[ $attack1, wiz_attack2 ] {ai_face();}; +void() wiz_attack2 =[ $attack2, wiz_attack3 ] {}; +void() wiz_attack3 =[ $attack3, wiz_attack4 ] {ai_face(); RandomFlapSound();}; +void() wiz_attack4 =[ $attack4, wiz_attack5 ] {}; +void() wiz_attack5 =[ $attack5, wiz_attack6 ] { +//sound(self, CHAN_WEAPON, "hknight/slash1.wav", 1, ATTN_NORM); +ai_face();}; +void() wiz_attack6 =[ $attack6, wiz_attack7 ] {AngelFeather(-25);AngelFeather(-20);}; +void() wiz_attack7 =[ $attack7, wiz_attack8 ] {AngelFeather(-15);AngelFeather(-10);}; +void() wiz_attack8 =[ $attack8, wiz_attack9 ] {AngelFeather(-5);AngelFeather(0);}; +void() wiz_attack9 =[ $attack9, wiz_attack10 ] {AngelFeather(5);AngelFeather(10);}; +void() wiz_attack10 =[ $attack10, wiz_attack11 ] {AngelFeather(15);AngelFeather(20);}; +void() wiz_attack11 =[ $attack11, wiz_attack12 ] {ai_face();}; +void() wiz_attack12 =[ $attack12, wiz_attack13 ] {ai_face();}; +void() wiz_attack13 =[ $attack13, wiz_run1 ] {SUB_AttackFinished(2);WizardAttackFinished ();}; + +void() wiz_pain1 =[ $pain1, wiz_pain2 ] {}; +void() wiz_pain2 =[ $pain2, wiz_pain3 ] {}; +void() wiz_pain3 =[ $pain3, wiz_pain4 ] {}; +void() wiz_pain4 =[ $pain4, wiz_pain5 ] {}; +void() wiz_pain5 =[ $pain5, wiz_pain6 ] {}; +void() wiz_pain6 =[ $pain6, wiz_run1 ] {}; + +void() wiz_death1 =[ $death1, wiz_death2 ] { +self.velocity_x = -200 + 400*random(); +self.velocity_y = -200 + 400*random(); +self.velocity_z = 100 + 100*random(); +self.flags = self.flags - (self.flags & FL_ONGROUND); +self.enemy = world; +}; +void() wiz_death2 =[ $death2, wiz_death3 ] {}; +void() wiz_death3 =[ $death3, wiz_death4 ]{self.solid = SOLID_NOT;}; +void() wiz_death4 =[ $death4, wiz_death5 ] {}; +void() wiz_death5 =[ $death5, wiz_death6 ] {}; +void() wiz_death6 =[ $death6, wiz_death7 ] {}; +void() wiz_death7 =[ $death7, wiz_death8 ] {}; +void() wiz_death8 =[ $death8, wiz_death9 ] {}; +void() wiz_death9 =[ $death9, wiz_death10 ] {}; +void() wiz_death10 =[ $death10, wiz_death11 ] {}; +void() wiz_death11 =[ $death11, wiz_death12 ] {}; +void() wiz_death12 =[ $death12, wiz_death13 ] {}; +void() wiz_death13 =[ $death13, wiz_death14 ] {}; +void() wiz_death14 =[ $death14, wiz_death15 ] {}; +void() wiz_death15 =[ $death15, wiz_death16 ] {}; +void() wiz_death16 =[ $death16, wiz_death17 ] {}; +void() wiz_death17 =[ $death17, wiz_death18 ] {}; +void() wiz_death18 =[ $death18, wiz_death19 ] {}; +void() wiz_death19 =[ $death19, wiz_death20 ] {}; +void() wiz_death20 =[ $death20, wiz_death20 ] {if (self.angles_x != 0) AngelPitch();}; + +void() wiz_deatha1 =[ $deatha1, wiz_deatha2 ] { +self.velocity_x = -200 + 400*random(); +self.velocity_y = -200 + 400*random(); +self.velocity_z = 100 + 100*random(); +self.flags = self.flags - (self.flags & FL_ONGROUND); +self.enemy = world; +}; +void() wiz_deatha2 =[ $deatha2, wiz_deatha3 ] {}; +void() wiz_deatha3 =[ $deatha3, wiz_deatha4 ]{self.solid = SOLID_NOT;}; +void() wiz_deatha4 =[ $deatha4, wiz_deatha5 ] {}; +void() wiz_deatha5 =[ $deatha5, wiz_deatha6 ] {}; +void() wiz_deatha6 =[ $deatha6, wiz_deatha7 ] {}; +void() wiz_deatha7 =[ $deatha7, wiz_deatha8 ] {}; +void() wiz_deatha8 =[ $deatha8, wiz_deatha9 ] {}; +void() wiz_deatha9 =[ $deatha9, wiz_deatha10 ] {}; +void() wiz_deatha10 =[ $deatha10, wiz_deatha11 ] {}; +void() wiz_deatha11 =[ $deatha11, wiz_deatha12 ] {}; +void() wiz_deatha12 =[ $deatha12, wiz_deatha13 ] {}; +void() wiz_deatha13 =[ $deatha13, wiz_deatha14 ] {}; +void() wiz_deatha14 =[ $deatha14, wiz_deatha15 ] {}; +void() wiz_deatha15 =[ $deatha15, wiz_deatha16 ] {}; +void() wiz_deatha16 =[ $deatha16, wiz_deatha17 ] {}; +void() wiz_deatha17 =[ $deatha17, wiz_deatha18 ] {}; +void() wiz_deatha18 =[ $deatha18, wiz_deatha19 ] {}; +void() wiz_deatha19 =[ $deatha19, wiz_deatha20 ] {}; +void() wiz_deatha20 =[ $deatha20, wiz_deatha20 ] {if (self.angles_x != 0) AngelPitch();}; + +void() wiz_die = +{ + MaleDeathSound(2); + + if (random() < 0.5) + wiz_death1 (); + else + wiz_deatha1 (); +}; + + +void(entity attacker, float damage) Wiz_Pain = +{ + + if (self.pain_finished > time) + return; + + MalePainSound(2); + + if (random()*40 > damage) + return; // didn't flinch + + self.pain_finished = time + 2; + + wiz_pain1 (); +}; + + +void() Wiz_Missile = +{ + wiz_attack1(); +}; + +/*QUAKED xmen_angel (1 0 0) (-16 -16 -24) (16 16 40) Ambush +*/ +void() xmen_angel = +{ + if (deathmatch) + { + remove(self); + return; + } + precache_model ("progs/angel1.mdl"); + +// precache_model ("progs/h_wizard.mdl"); + precache_model ("progs/dart.mdl"); + + // XMen matched ID sounds +// precache_sound ("hknight/slash1.wav"); + + precache_sound ("angel/flap1.wav"); + precache_sound ("angel/flap2.wav"); + precache_sound ("angel/flap3.wav"); + precache_sound ("angel/flap4.wav"); + precache_sound ("angel/flap5.wav"); + precache_sound ("angel/flap6.wav"); + + precache_sound ("wizard/hit.wav"); // used by c code + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + + setmodel (self, "progs/angel1.mdl"); + + setsize (self, '-16 -16 -24', '16 16 40'); + self.health = 110 + cvar("skill")*10; + + self.yaw_speed = 9; + + self.th_stand = wiz_stand1; + self.th_walk = wiz_walk1; + self.th_run = wiz_run1; + self.th_missile = Wiz_Missile; + self.th_pain = Wiz_Pain; + self.th_die = wiz_die; + + self.th_guard = wiz_guard1; + + flymonster_start (); +}; + +void() monster_wizard = +{ + remove(self); +}; \ No newline at end of file diff --git a/appy.c b/appy.c new file mode 100644 index 0000000..3d074d4 --- /dev/null +++ b/appy.c @@ -0,0 +1,475 @@ +/************************************************************************* + + Apocalypse - Episode 1 Boss + +**************************************************************************/ + +$frame stand101 + +$frame atta101 atta102 atta103 atta104 atta105 atta106 atta107 +$frame atta108 atta109 atta110 atta111 atta112 + +$frame attb101 attb102 attb103 attb104 attb105 attb106 attb107 +$frame attb108 attb109 attb110 attb111 attb112 + +$frame attc101 attc102 attc103 attc104 attc105 attc106 attc107 +$frame attc108 attc109 attc110 attc111 attc112 + +$frame stomp101 stomp102 stomp103 stomp104 stomp105 stomp106 stomp107 +$frame stomp108 stomp109 stomp110 + +$frame pain101 pain102 pain103 pain104 pain105 pain106 pain107 pain108 pain109 pain110 +$frame pain111 pain112 pain113 pain114 pain115 pain116 pain117 pain118 pain119 pain120 +$frame pain121 pain122 pain123 pain124 pain125 pain126 pain127 pain128 pain129 pain130 +$frame pain131 pain132 pain133 pain134 pain135 pain136 pain137 pain138 pain139 pain140 +$frame pain141 pain142 pain143 pain144 pain145 pain146 pain147 pain148 pain149 pain150 + +//==================================================================================== + +void() apoc_stand1 = [ $stomp101, apoc_stand1 ] +{ + if (self.spawn_time < (time - 1)) { + ai_stand(); + + if (self.enemy != world) { + self.last_flame = time; + cvar_set("host_framerate", "0.02"); + } + } +}; + +//==================================================================================== + +void() apoc_stomp = +{ + local vector vect, vecta; + local float old_yaw, old_yaw_body; + + + if (vlen(self.enemy.origin - self.origin) < 32) { // in-between legs +// apoc_attb1(); + return; + } + + vect = normalize(self.enemy.origin - self.origin); + vecta = vectoangles(vect); + + // rotate legs + self = self.leg; + old_yaw = self.angles_y; + + self.ideal_yaw = self.owner.ideal_yaw; + ChangeYaw(); + self = self.owner; + + // move body according to the leg movement + self.angles_y = anglemod(self.angles_y + (self.leg.angles_y - old_yaw)); + + // set frame according to the direction of rotation + if (old_yaw < self.leg.angles_y) + self.frame = self.frame + 1; + else + self.frame = self.frame - 1; + + if (self.frame > $stomp110 ) + self.frame = $stomp101; + else if (self.frame < $stomp101 ) + self.frame = $stomp110; + + // rotate body + old_yaw_body = self.angles_y; + self.ideal_yaw = vecta_y; + + self.angles_y = anglemod(self.angles_y + (self.leg.angles_y - old_yaw)); +// ChangeYaw(); + if (fabs(angle_diff(self.angles_y, self.leg.angles_y)) > 75) { + self.angles_y = old_yaw_body; + } + +}; + +//==================================================================================== + +// this keeps apocalypse facing the player, unless the player goes out of the angle range +void() apoc_face = +{ + local vector vect, vecta; + + if (vlen(self.enemy.origin - self.origin) < 32) { // in-between legs + return; + } + + vect = normalize(self.enemy.origin - self.origin); + vecta = vectoangles(vect); + + self.ideal_yaw = vecta_y; + + if (fabs(angle_diff(self.ideal_yaw, self.leg.angles_y)) < 75) { + ChangeYaw(); + } + +}; + +void() earth_quake_think = +{ + local vector vec; + local float ratio; + + if (self.last_flame < (time - 0.75)) { + remove(self); + return; + } + + // shake view + vec = '12 0 0' * random() + '0 12 0' * random() + '0 0 22' * random() - '6 6 14'; + ratio = (vlen(self.enemy.origin - self.origin) / 256); + if (ratio > 1) + ratio = 1; + vec = vec * ratio; + self.enemy.punchangle = vec * (0.75 - (time - self.last_flame)); +}; + +void() apoc_thump = +{ + local entity thinker; + + makevectors(self.angles); + if (vlen(self.origin + (v_forward * 128) - self.enemy.origin) < 128) + T_Damage(self.enemy, self, self, 40); + + sound(self, CHAN_BODY, "apoc/thump.wav", 1, ATTN_NONE); + + thinker = spawn(); + thinker.enemy = self.enemy; + thinker.last_flame = time; + thinker.think = earth_quake_think; + thinker.nextthink = time + 0.05; + + self.nextthink = time + 0.05; +}; + +void() apoc_atta1 = [ $atta101, apoc_atta2 ] {apoc_face();}; +void() apoc_atta2 = [ $atta102, apoc_atta3 ] {apoc_face();}; +void() apoc_atta3 = [ $atta103, apoc_atta4 ] {apoc_face();}; +void() apoc_atta4 = [ $atta104, apoc_atta5 ] {apoc_face();}; +void() apoc_atta5 = [ $atta105, apoc_atta6 ] {apoc_face();}; +void() apoc_atta6 = [ $atta106, apoc_atta7 ] {apoc_face(); apoc_thump();}; +void() apoc_atta7 = [ $atta107, apoc_atta8 ] {apoc_face();}; +void() apoc_atta8 = [ $atta108, apoc_atta9 ] {apoc_face();}; +void() apoc_atta9 = [ $atta109, apoc_atta10 ] {apoc_face();}; +void() apoc_atta10 = [ $atta110, apoc_atta11 ] {apoc_face();}; +void() apoc_atta11 = [ $atta111, apoc_atta12 ] {apoc_face();}; +void() apoc_atta12 = [ $atta112, apoc_melee ] {apoc_face();}; + +void() apoc_swipe = +{ + local vector vect; + local float ang; + + vect = normalize(self.enemy.origin - self.origin); + vect = vectoangles(vect); + + ang = angle_diff(self.angles_y, vect_y); + + if ((fabs(ang) < 90) && (vlen(self.enemy.origin - self.origin) < 300)) { + if (!(self.enemy.x_flags & X_PARALLIZED)) + self.enemy.x_flags = self.enemy.x_flags | X_PARALLIZED; + + makevectors(self.angles); + if (vlen(self.origin + (v_forward * 128) - self.enemy.origin) > 16) + self.enemy.parallized_velocity = normalize(self.origin + (v_forward * 128) - self.enemy.origin) * 200; + else + self.enemy.parallized_velocity = '0 0 0'; + + T_Damage(self.enemy, self, self, 2); + } +}; + +void() apoc_attb1 = [ $attb101, apoc_attb2 ] {apoc_face();}; +void() apoc_attb2 = [ $attb102, apoc_attb3 ] {apoc_face();}; +void() apoc_attb3 = [ $attb103, apoc_attb4 ] {apoc_face();}; +void() apoc_attb4 = [ $attb104, apoc_attb5 ] {apoc_face(); sound(self, CHAN_ITEM, "apoc/swipe.wav", 1, ATTN_NONE);}; +void() apoc_attb5 = [ $attb105, apoc_attb6 ] {apoc_face(); apoc_swipe();}; +void() apoc_attb6 = [ $attb106, apoc_attb7 ] {apoc_face(); apoc_swipe();}; +void() apoc_attb7 = [ $attb107, apoc_attb8 ] {apoc_face(); apoc_swipe();}; +void() apoc_attb8 = [ $attb108, apoc_attb9 ] {apoc_face(); apoc_swipe();}; +void() apoc_attb9 = [ $attb109, apoc_attb10 ] {apoc_face(); apoc_swipe();}; +void() apoc_attb10 = [ $attb110, apoc_attb11 ] {apoc_face(); apoc_swipe();}; +void() apoc_attb11 = [ $attb111, apoc_attb12 ] {apoc_face(); apoc_swipe();}; +void() apoc_attb12 = [ $attb112, apoc_melee ] +{ + apoc_face(); + + if (self.enemy.x_flags & X_PARALLIZED) + self.enemy.x_flags = self.enemy.x_flags - X_PARALLIZED; +}; + +void() apoc_spike = +{ + if (vlen(self.origin - self.enemy.origin) < 96) + T_Damage(self.enemy, self, self, 10); + + sound(self, CHAN_BODY, "apoc/spike.wav", 1, ATTN_NONE); +}; + +void() apoc_attc1 = [ $attc101, apoc_attc2 ] {apoc_face();}; +void() apoc_attc2 = [ $attc102, apoc_attc3 ] {apoc_face();}; +void() apoc_attc3 = [ $attc103, apoc_attc4 ] {apoc_face(); apoc_spike();}; +void() apoc_attc4 = [ $attc104, apoc_attc5 ] {apoc_face();}; +void() apoc_attc5 = [ $attc105, apoc_attc6 ] {apoc_face();}; +void() apoc_attc6 = [ $attc106, apoc_attc7 ] {apoc_face(); apoc_spike();}; +void() apoc_attc7 = [ $attc107, apoc_attc8 ] {apoc_face();}; +void() apoc_attc8 = [ $attc108, apoc_attc9 ] {apoc_face();}; +void() apoc_attc9 = [ $attc109, apoc_attc10 ] {apoc_face(); apoc_spike();}; +void() apoc_attc10 = [ $attc110, apoc_attc11 ] {apoc_face();}; +void() apoc_attc11 = [ $attc111, apoc_attc12 ] {apoc_face();}; +void() apoc_attc12 = [ $attc112, apoc_melee ] {apoc_face();}; + +void() apoc_melee = +{ + local vector vect, vecta; + + if (self.last_flame > (time - 2.3)) { +// apoc_face(); + if ((self.spawn_time != 99) && (self.last_flame > (time - 0.2))) { // found an enemy + sound(self, CHAN_VOICE, "apoc/astart.wav", 1, ATTN_NONE); + self.spawn_time = 99; + } + + self.nextthink = time + 0.2; + return; + } + else if (self.spawn_time == 99) { + cvar_set("host_framerate", "0"); + self.spawn_time = 0; + } + + // first check if stomping (aligning legs with arms) is required + if (vlen(self.enemy.origin - self.origin) > 64) { + vect = normalize(self.enemy.origin - self.origin); + vecta = vectoangles(vect); + + if (fabs(angle_diff(vecta_y, self.leg.angles_y)) > 30) { + // stomp!! + apoc_stomp(); + self.nextthink = time + 0.05; + return; + } + } + + + if (vlen(self.enemy.origin - self.origin) < 96) + apoc_attc1(); + else if (fabs(angle_diff(vecta_y, self.angles_y)) > 10) + apoc_attb1(); + else + apoc_atta1(); +}; + +//==================================================================================== + +void() apoc_pain101 = [ $pain101, apoc_die ] +{ + local entity trav, last; + + sound(self, CHAN_VOICE, "apoc/apocno.wav", 1, ATTN_NORM); + + // prevent torso from taking damage + trav = find(world, classname, "apoc_torso"); + if (trav != world) { + trav.solid = SOLID_NOT; + trav.takedamage = DAMAGE_NO; + } + + // remove the bounding boxes for legs + remove(self.leg.leg.leg); + remove(self.leg.leg); + + self.leg.leg = world; + + self.x_flags = self.x_flags | X_MEGA_HIT; + + self.enemy.currentammo = self.enemy.ammo_special = 0; +}; + +void() apoc_die = +{ + local entity trav; + + self.frame = self.frame + 1; + + self.skin = 1 - self.skin; + self.leg.skin = 1 - self.leg.skin; + + if (self.frame == $pain150 ) { + + remove(self.leg); + + trav = find(world, classname, "apoc_torso"); + if (trav != world) + remove(trav); + + // this is where the new smaller version of Apocalypse will kick in + ApocSmallSpawn(); + + self.think = SUB_Remove; + self.nextthink = time + 0.05; + } + + self.nextthink = time + 0.1; +}; + +//==================================================================================== + +void() apoc_pain = +{ +//bprint("apoc pain: "); +//bprint(ftos(self.health)); +//bprint("\n"); + // special weapon does 1000+ damage per strike + + if (self.health > 99000) + self.health = 99999; +}; + +//==================================================================================== + +void() ApocLegsThink = +{ + // sync frames with body + self.frame = self.owner.frame; + + if (self.leg != world) { + // move leg bounding boxes + makevectors(self.angles); + setorigin(self.leg, self.origin + (v_right * 58)); + setorigin(self.leg.leg, self.origin - (v_right * 58)); + } + + self.nextthink = time + 0.05; +}; + +void() SpawnApocLegs = +{ + local entity ent; + + ent = spawn(); + ent.owner = self; + + setmodel(ent, "progs/appy1.mdl"); + + traceline(self.origin, self.origin - '0 0 1024', TRUE, world); + setorigin(ent, trace_endpos + '0 0 24'); + ent.angles = self.angles; + ent.yaw_speed = 5; + + ent.think = ApocLegsThink; + ent.nextthink = time + 0.1; + + self.leg = ent; + + // now make the two solid leg boxes + + // left + ent = spawn(); + ent.owner = self.leg; + ent.classname = "apoc_leg"; + + ent.solid = SOLID_BBOX; + setsize(ent, VEC_HULL_MIN, VEC_HULL_MAX); + + self.leg.leg = ent; + + // right + ent = spawn(); + ent.owner = self.leg; + ent.classname = "apoc_leg"; + + ent.solid = SOLID_BBOX; + setsize(ent, VEC_HULL_MIN, VEC_HULL_MAX); + + self.leg.leg.leg = ent; +}; + +void() SpawnApocTorso = +{ + local entity ent; + + ent = spawn(); + ent.classname = "apoc_torso"; + ent.owner = self; + + ent.solid = SOLID_BBOX; + ent.takedamage = DAMAGE_AIM; + ent.health = 99999; + setorigin(ent, self.origin + '0 0 330'); + setsize(ent, '-138 -138 -300', '138 138 100'); + +}; + +//==================================================================================== + +void() xmen_apocalypse = +{ + if (deathmatch) { + remove(self); + return; + } + + precache_model("progs/appy1.mdl"); + precache_model("progs/appy2.mdl"); + precache_model("progs/apoc.mdl"); + + precache_model("progs/apblast.mdl"); + + precache_sound("apoc/thump.wav"); + precache_sound("apoc/spike.wav"); + precache_sound("apoc/swipe.wav"); + + precache_sound("apoc/astart.wav"); + precache_sound("apoc/alaugh.wav"); + precache_sound("apoc/apain2.wav"); + precache_sound("apoc/apain4.wav"); + precache_sound("apoc/apain5.wav"); + precache_sound("apoc/apocno.wav"); + precache_sound("apoc/miniapoc.wav"); + precache_sound("apoc/aattack2.wav"); + precache_sound("apoc/aattack3.wav"); + precache_sound("apoc/aattack4.wav"); + precache_sound("apoc/ahit.wav"); + + SpawnApocLegs(); + SpawnApocTorso(); + +// self.solid = SOLID_BBOX; + + setsize (self, '-128 -128 -24', '128 128 256'); + setmodel(self, "progs/appy2.mdl"); + self.health = 99999; + + setorigin(self, self.leg.origin); + + self.yaw_speed = 6; + self.takedamage = DAMAGE_AIM; + + self.ideal_yaw = self.angles * '0 1 0'; + self.view_ofs = '0 0 25'; + + self.spawn_time = time; + + self.flags = self.flags | FL_MONSTER; + + self.th_stand = apoc_stand1; +// self.th_walk = apoc_stand1; + self.th_run = apoc_melee; + self.th_pain = apoc_pain; + self.th_die = apoc_pain101; + self.th_melee = apoc_melee; + self.th_missile = apoc_melee; + + self.pausetime = 99999999; + + self.think = apoc_stand1; + self.nextthink = time + 0.1; + +}; \ No newline at end of file diff --git a/apsmall.c b/apsmall.c new file mode 100644 index 0000000..90dce71 --- /dev/null +++ b/apsmall.c @@ -0,0 +1,478 @@ +$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9 stand10 +$frame stand11 stand12 stand13 + +$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 walk9 walk10 +$frame walk11 walk12 + +$frame pain1 pain2 pain3 pain4 pain5 pain6 pain7 pain8 pain9 pain10 +$frame pain11 pain12 + +$frame guard1 guard2 guard3 guard4 guard5 guard6 guard7 guard8 +$frame guard9 guard10 guard11 guard12 + +$frame atta0 atta1 atta2 atta3 atta4 atta5 atta6 atta7 atta8 +$frame atta9 atta10 atta11 atta12 + +$frame attb1 attb2 attb3 attb4 attb5 attb6 attb7 attb8 +$frame attb9 attb10 attb11 attb12 + +$frame xatta1 xatta2 xatta3 xatta4 xatta5 xatta6 xatta7 xatta8 +$frame xatta9 xatta10 xatta11 xatta12 + +$frame xattb1 xattb2 xattb3 xattb4 xattb5 xattb6 xattb7 xattb8 +$frame xattb9 xattb10 xattb11 xattb12 + +$frame deatha1 deatha2 deatha3 deatha4 deatha5 deatha6 deatha7 deatha8 deatha9 deatha10 +$frame deatha11 deatha12 deatha13 deatha14 deatha15 deatha16 deatha17 deatha18 deatha19 deatha20 +$frame deatha21 deatha22 deatha23 deatha24 deatha25 deatha26 deatha27 deatha28 deatha29 deatha30 + +$frame pant1 pant2 pant3 pant4 pant5 pant6 pant7 pant8 pant9 pant10 + +//==================================================================================== + +void() apsmall_clone1 = [$stand1, apsmall_clone2 ] {}; +void() apsmall_clone2 = [$stand2, apsmall_clone3 ] {}; +void() apsmall_clone3 = [$stand3, apsmall_clone4 ] {}; +void() apsmall_clone4 = [$stand4, apsmall_clone5 ] {}; +void() apsmall_clone5 = [$stand5, apsmall_clone6 ] {}; +void() apsmall_clone6 = [$stand6, apsmall_clone7 ] {}; +void() apsmall_clone7 = [$stand7, apsmall_clone8 ] {}; +void() apsmall_clone8 = [$stand8, apsmall_clone9 ] {}; +void() apsmall_clone9 = [$stand9, apsmall_clone10 ] {}; +void() apsmall_clone10 = [$stand10, apsmall_clone11 ] {}; +void() apsmall_clone11 = [$stand11, apsmall_clone12 ] {}; +void() apsmall_clone12 = [$stand12, apsmall_clone13 ] {}; +void() apsmall_clone13 = [$stand13, apsmall_clone1 ] {}; + +//==================================================================================== + +void() apsmall_stand = [$walk1, apsmall_stand ] {}; + +void() apsmall_walk = [$walk1, apsmall_walk ] +{ + self.walkframe = self.walkframe + 1; + if (self.walkframe >= 11) + self.walkframe = 0; + + if (self.walkframe == 0) ai_run(9); + else if (self.walkframe == 1) ai_run(6); + else if (self.walkframe == 2) ai_run(7); + else if (self.walkframe == 3) ai_run(8); + else if (self.walkframe == 4) ai_run(8); + else if (self.walkframe == 5) ai_run(9); + else if (self.walkframe == 6) ai_run(14); + else if (self.walkframe == 7) ai_run(6); + else if (self.walkframe == 8) ai_run(5); + else if (self.walkframe == 9) ai_run(7); + else if (self.walkframe == 10) ai_run(7); + else if (self.walkframe == 11) ai_run(8); + +// ai_face(); + + self.frame = self.frame + self.walkframe; +}; + +//==================================================================================== + +void() apsmall_pain = [$pain1, apsmall_pain ] +{ + self.walkframe = self.walkframe + 1; + if (self.walkframe == 11) { + self.think = self.th_run; + } + + self.frame = self.frame + self.walkframe; +}; + +void(entity attacker, float damage) ApocSmallPain = +{ + if (self.spawnflags & SPAWNFLAG_CLONE) { + self.health = 99999; + return; + } + + if (self.pain_finished > time) + return; + + if (random() * 100 > damage) + return; + + if (random() * 80 < damage) + sound(self, CHAN_BODY, "apoc/apain2.wav", 1, ATTN_NORM); + else if (random() < 0.5) + sound(self, CHAN_BODY, "apoc/apain4.wav", 1, ATTN_NORM); + else + sound(self, CHAN_BODY, "apoc/apain5.wav", 1, ATTN_NORM); + + self.walkframe = -1; + self.pain_finished = time + 3; + apsmall_pain(); +}; + +//==================================================================================== + +void() ApocCheckGuard = +{ + local entity trav; + + trav = world; + while ((trav = find(trav, classname, "guided_rocket")) != world) { + + // check that rocket is targetted for self + if (trav.enemy == self) { // uh oh + return; + } + + } + + // dangerous rocket not found + self.flags = self.flags - (self.flags & FL_GODMODE); + self.walkframe = 8; +}; + +void() apsmall_guard = [$guard1, apsmall_guard ] +{ + self.walkframe = self.walkframe + 1; + if (self.walkframe == 11) + self.think = self.th_run; + else if (self.walkframe == 3) + self.flags = self.flags | FL_GODMODE; + else if (self.walkframe == 8) { + self.walkframe = 7; + ApocCheckGuard(); + } + + self.frame = self.frame + self.walkframe; +}; + +void() ApocSmallGuardStart = +{ + self.walkframe = -1; + apsmall_guard(); +}; + +//==================================================================================== + +void() apsmall_atta = [$atta0, apsmall_atta ] +{ + local vector vec1; + local float frame_diff; + + self.walkframe = self.walkframe + 1; + if (self.walkframe == 12) + self.think = self.th_run; + + self.frame = self.frame + self.walkframe; + + frame_diff = fabs(self.frame - $atta7 ); + if (frame_diff <= 3) { + makevectors(self.angles); + vec1 = normalize(self.enemy.origin - self.origin); + + if (vlen(v_forward - vec1) < 0.2) { + if (vlen(self.enemy.origin - self.origin) < (128 - ((frame_diff / 3) * 64))) + T_Damage(self.enemy, self, self, 12); + } + } + + self.nextthink = time + 0.05; +}; + +void() apsmall_attb = [$attb1, apsmall_attb ] +{ + ai_face(); + ai_forward(8); + + self.walkframe = self.walkframe + 1; + if (self.walkframe == 11) + self.think = self.th_run; + + self.frame = self.frame + self.walkframe; + + if ((self.frame == $attb3 ) || + (self.frame == $attb8 )) { + if (infront(self.enemy)) { + if (vlen(self.enemy.origin - self.origin) < 85) { + sound(self, CHAN_BODY, "apoc/ahit.wav", 1, ATTN_NORM); + + T_Damage(self.enemy, self, self, 20); + + makevectors(self.angles); + if (!(self.enemy.flags & FL_ONGROUND)) + self.enemy.velocity = v_forward * 200 + '0 0 235'; + else + self.enemy.velocity = '0 0 235'; + self.enemy.punchangle_x = -10; + } + } + } +}; + +void() ApocSmallMelee = +{ + self.walkframe = -1; + apsmall_attb(); +}; + +//==================================================================================== + +void() ApocBallTouch = +{ + if (other == self.owner) + return; + + 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); + + if (other.takedamage == DAMAGE_AIM) + { + spawn_touchblood (10); + T_Damage(other, self, self.owner, 10); + + if (other.classname == "player") { + other.velocity = other.velocity + (self.velocity * 0.2) + '0 0 180'; + other.flags = other.flags - (other.flags & FL_ONGROUND); + } + } + + remove(self); +}; + +void(vector org) spawn_apocball = +{ + local entity missile, mpuff; + local vector vect; + + missile = spawn (); + missile.owner = self; + missile.movetype = MOVETYPE_FLYMISSILE; + missile.solid = SOLID_BBOX; + missile.classname = "apocball"; + + missile.velocity = ProjectVelocity(1100, '0 0 0'); + + missile.angles = vectoangles(missile.velocity); + missile.old_velocity = missile.velocity; + + missile.touch = ApocBallTouch; + + missile.last_touch = 0; + missile.oldorigin = missile.origin; + missile.nextthink = time + 20; + missile.think = SUB_Remove; + + setmodel (missile, "progs/apblast.mdl"); + setsize (missile, '0 0 0', '0 0 0'); + setorigin (missile, org); +}; + +void() apsmall_xatta = [$xatta1, apsmall_xatta ] +{ + ai_face(); + + self.walkframe = self.walkframe + 1; + if (self.walkframe == 11) + self.think = self.th_run; + else if (self.walkframe == 4) { + makevectors(self.angles); + spawn_apocball(self.origin); + } + + self.frame = self.frame + self.walkframe; +}; + +void() apsmall_xattb = [$xattb1, apsmall_xattb ] +{ + ai_face(); + + self.walkframe = self.walkframe + 1; + if (self.walkframe == 11) + self.think = self.th_run; + else if (self.walkframe == 5) { + makevectors(self.angles); + spawn_apocball(self.origin + v_right * 3); + spawn_apocball(self.origin - v_right * 3); + } + + self.frame = self.frame + self.walkframe; +}; + +void() ApocSmallMissile = +{ + local float rnd; + + if (self.spawn_time > (time - 4.5)) // don't attack for 4.5 seconds after shrinking + return; + + if (self.last_special > (time - 3)) { + if (vlen(self.origin - self.enemy.origin) < 160) { + self.walkframe = -1; + apsmall_atta(); + } + else { + self.walkframe = -1; + self.last_special2 = time; + apsmall_xatta(); + } + } + else { + self.walkframe = -1; + self.last_special = time; + apsmall_xattb(); + } + + rnd = random() * 5; + if (rnd < 1) + sound(self, CHAN_VOICE, "apoc/aattack2.wav", 1, ATTN_NORM); + else if (rnd < 2) + sound(self, CHAN_VOICE, "apoc/aattack3.wav", 1, ATTN_NORM); + else if (rnd < 3) + sound(self, CHAN_VOICE, "apoc/aattack4.wav", 1, ATTN_NORM); + +}; + +//==================================================================================== + +void() apoc_pant = [ $pant1, apoc_pant ] +{ + self.walkframe = self.walkframe + 1; + if (self.walkframe > 9) + self.walkframe = 0; + + self.frame = self.frame + self.walkframe; +}; + +void() apsmall_death = [$deatha1, apsmall_death ] +{ + local entity trav; + local vector vec1; + + if (self.walkframe < 30) + self.walkframe = self.walkframe + 1; +/* + else if (self.walkframe == 35) { + makevectors(self.angles); + vec1 = normalize(self.enemy.origin - self.origin); + + if (vlen(self.enemy.origin - self.origin) < 90) { + if (vlen(v_forward - vec1) < 0.2) { + T_Damage(self.enemy, self, self, 25); + } + } + } +*/ + else if ((self.walkframe == 30) && (self.enemy.health > 0)) { // show completed episode 1 sequence + + killed_monsters = killed_monsters + 1; + WriteByte (MSG_ALL, SVC_KILLEDMONSTER); // FIXME: reliable broadcast + + trav = find (world, classname, "player"); + while (trav != world) + { + trav.view_ofs = '0 0 0'; + trav.nextthink = time + 0.5; + trav.takedamage = DAMAGE_NO; + trav.solid = SOLID_NOT; + trav.movetype = MOVETYPE_NONE; + trav.weapon_parts = 0; + + trav = find (trav, classname, "player"); + } + + WriteByte (MSG_ALL, SVC_INTERMISSION); + nextmap = "x2m1"; + + serverflags = serverflags - (serverflags & 15); // remove rune items from the consol + intermission_running = 1; + + SUB_UseTargets (); + + self.think = apoc_pant; + self.nextthink = time + 0.1; + } + + self.frame = self.frame + self.walkframe; +}; + +void() ApocSmallDie = +{ + self.walkframe = -1; + apsmall_death(); + sound(self, CHAN_VOICE, "apoc/apain2.wav", 1, ATTN_NORM); +}; + +//==================================================================================== + +void(vector org) ApocSmallSpawn = +{ + local entity apoc, oself; + + apoc = spawn(); + apoc.classname = "apocalypse_small"; + + setorigin(apoc, self.origin); + + apoc.solid = SOLID_SLIDEBOX; + apoc.movetype = MOVETYPE_STEP; + apoc.takedamage = DAMAGE_AIM; + + setmodel (apoc, "progs/apoc.mdl"); + + setsize (apoc, VEC_HULL2_MIN, VEC_HULL2_MAX); + apoc.health = 600; + apoc.yaw_speed = 20; + + apoc.th_stand = apsmall_stand; + apoc.th_walk = apsmall_stand; + apoc.th_run = apsmall_walk; + apoc.th_pain = ApocSmallPain; + apoc.th_die = ApocSmallDie; + apoc.th_melee = ApocSmallMelee; + apoc.th_missile = ApocSmallMissile; + + apoc.th_guard = ApocSmallGuardStart; + apoc.x_flags = apoc.x_flags | X_MEGA_HIT; + + oself = self; + self = apoc; + walkmonster_start_go(); + self = oself; + + apoc.enemy = apoc.goalentity = self.enemy; + apoc.think = apoc.th_run; + apoc.nextthink = time + 0.1; + apoc.frame = $walk1; + apoc.spawn_time = time; + + sound(self, CHAN_VOICE, "apoc/miniapoc.wav", 1, ATTN_NORM); + +}; + +void() xmen_apocalypse_small = +{ + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_NONE; + + precache_model("progs/apoc.mdl"); + setmodel (self, "progs/apoc.mdl"); + + setsize (self, VEC_HULL2_MIN, VEC_HULL2_MAX); + self.health = 99999; + + self.th_stand = apsmall_clone1; + self.th_walk = apsmall_clone1; + self.th_run = apsmall_clone1; + self.th_pain = ApocSmallPain; + self.th_die = apsmall_clone1; + + if (self.spawnflags & SPAWNFLAG_CLONE) { + self.flags = self.flags & FL_GODMODE; + droptofloor(); + + self.think = self.th_stand; + self.nextthink = time + 0.1; + } +}; \ No newline at end of file diff --git a/beast.c b/beast.c new file mode 100644 index 0000000..6e33bd5 --- /dev/null +++ b/beast.c @@ -0,0 +1,621 @@ +/* +============================================================================== + +beast + +============================================================================== +*/ +$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9 +$frame stand10 stand11 stand12 stand13 + +$frame runa1 runa2 runa3 runa4 runa5 runa6 runa7 runa8 runa9 runa10 +$frame runa11 runa12 + +$frame runb1 runb2 runb3 runb4 runb5 runb6 runb7 runb8 runb9 runb10 +$frame runb11 runb12 + +$frame runc1 runc2 runc3 runc4 runc5 runc6 runc7 runc8 runc9 runc10 +$frame runc11 runc12 + +$frame pain1 pain2 pain3 pain4 pain5 pain6 + +$frame death1 death2 death3 death4 death5 death6 death7 death8 death9 death10 +$frame death11 death12 + +$frame deata1 deata2 deata3 deata4 deata5 deata6 deata7 deata8 deata9 deata10 +$frame deata11 deata12 + +$frame atta1 atta2 atta3 atta4 atta5 atta6 atta7 atta8 +$frame atta9 atta10 atta11 atta12 + +$frame attb1 attb2 attb3 attb4 attb5 attb6 attb7 attb8 +$frame attb9 attb10 attb11 attb12 + +$frame xatta1 xatta2 xatta3 xatta4 xatta5 xatta6 xatta7 xatta8 +$frame xatta9 xatta10 xatta11 xatta12 xatta13 xatta14 xatta15 xatta16 xatta17 xatta18 + + +void() beast_atta1; +void() beast_atta8; +void() beast_runa1; + +/* +================ +beast_bite + +================ +*/ +void() beast_bite = +{ +local vector delta; +local float ldmg; +local entity plyr; + + makevectors(self.v_angle); + if ((plyr = FindSightEnemy(self.origin, v_forward, 60, 40, "all", self)) == world) + return; + + delta = plyr.origin - self.origin; + + if (vlen(delta) > 60) + return; + + ldmg = 9 + random() * 3; + T_Damage (plyr, self, self, ldmg); + + if (self.frame >= $attb1 ) { + if (random() < 0.5) + sound(self, CHAN_WEAPON, "generic/punch2.wav", 1, ATTN_NORM); + else + sound(self, CHAN_WEAPON, "generic/punch3.wav", 1, ATTN_NORM); + } + else + sound(self, CHAN_WEAPON, "generic/punch1.wav", 1, ATTN_NORM); + +}; + +/* +void() beast_JumpTouch = +{ + local float ldmg; + + if (self.health <= 0) + return; + + if (other.takedamage) + { + if ( vlen(self.velocity) > 300 ) + { + ldmg = 15 + 10*random(); + T_Damage (other, self, self, ldmg); + } + } + + if (!checkbottom(self)) + { + if (self.flags & FL_ONGROUND) + { // jump randomly to not get hung up +//bprint ("popjump\n"); + self.touch = SUB_Null; + self.think = beast_atta1; + self.nextthink = time + 0.1; + +// self.velocity_x = (random() - 0.5) * 600; +// self.velocity_y = (random() - 0.5) * 600; +// self.velocity_z = 200; +// self.flags = self.flags - FL_ONGROUND; + } + return; // not on ground yet + } + + self.touch = SUB_Null; + self.think = beast_atta8; + self.nextthink = time + 0.05; +}; +*/ + +void() beast_stand1 =[ $stand1, beast_stand2 ] {ai_stand();}; +void() beast_stand2 =[ $stand2, beast_stand3 ] {ai_stand();}; +void() beast_stand3 =[ $stand3, beast_stand4 ] {ai_stand();}; +void() beast_stand4 =[ $stand4, beast_stand5 ] {ai_stand();}; +void() beast_stand5 =[ $stand5, beast_stand6 ] {ai_stand();}; +void() beast_stand6 =[ $stand6, beast_stand7 ] {ai_stand();}; +void() beast_stand7 =[ $stand7, beast_stand8 ] {ai_stand();}; +void() beast_stand8 =[ $stand8, beast_stand9 ] {ai_stand();}; +void() beast_stand9 =[ $stand9, beast_stand10 ] {ai_stand();}; +void() beast_stand10 =[ $stand10, beast_stand11 ] {ai_stand();}; +void() beast_stand11 =[ $stand11, beast_stand12 ] {ai_stand();}; +void() beast_stand12 =[ $stand12, beast_stand13 ] {ai_stand();}; +void() beast_stand13 =[ $stand13, beast_stand1 ] {ai_stand();}; + +/* +void() beast_walk1 =[ $walk1 , beast_walk2 ] { +ai_walk(8);}; +void() beast_walk2 =[ $walk2 , beast_walk3 ] {ai_walk(8);}; +void() beast_walk3 =[ $walk3 , beast_walk4 ] {ai_walk(8);}; +void() beast_walk4 =[ $walk4 , beast_walk5 ] {ai_walk(8);}; +void() beast_walk5 =[ $walk5 , beast_walk6 ] {ai_walk(8);}; +void() beast_walk6 =[ $walk6 , beast_walk7 ] {ai_walk(8);}; +void() beast_walk7 =[ $walk7 , beast_walk8 ] {ai_walk(8);}; +void() beast_walk8 =[ $walk8 , beast_walk1 ] {ai_walk(8);}; +*/ + +void() beast_random_run; + +void() beast_runa1 =[ $runa1 , beast_runa2 ] { +ai_run(32);}; +void() beast_runa2 =[ $runa2 , beast_runa3 ] {ai_run(32);}; +void() beast_runa3 =[ $runa3 , beast_runa4 ] {ai_run(32);}; +void() beast_runa4 =[ $runa4 , beast_runa5 ] {ai_run(20);}; +void() beast_runa5 =[ $runa5 , beast_runa6 ] {ai_run(32);}; +void() beast_runa6 =[ $runa6 , beast_runa7 ] {ai_run(32);}; +void() beast_runa7 =[ $runa7 , beast_runa8 ] {ai_run(26);}; +void() beast_runa8 =[ $runa8 , beast_runa9 ] {ai_run(32);}; +void() beast_runa9 =[ $runa9 , beast_runa10 ] {ai_run(32);}; +void() beast_runa10 =[ $runa10 , beast_runa11 ] {ai_run(20);}; +void() beast_runa11 =[ $runa11 , beast_runa12 ] {ai_run(32);}; +void() beast_runa12 =[ $runa12 , beast_runa1 ] +{ + ai_run(32); + beast_random_run(); +}; + +void() beast_runb1 =[ $runb1 , beast_runb2 ] { +ai_run(32);}; +void() beast_runb2 =[ $runb2 , beast_runb3 ] {ai_run(32);}; +void() beast_runb3 =[ $runb3 , beast_runb4 ] {ai_run(32);}; +void() beast_runb4 =[ $runb4 , beast_runb5 ] {ai_run(20);}; +void() beast_runb5 =[ $runb5 , beast_runb6 ] {ai_run(32);}; +void() beast_runb6 =[ $runb6 , beast_runb7 ] {ai_run(32);}; +void() beast_runb7 =[ $runb7 , beast_runb8 ] {ai_run(26);}; +void() beast_runb8 =[ $runb8 , beast_runb9 ] {ai_run(32);}; +void() beast_runb9 =[ $runb9 , beast_runb10 ] {ai_run(32);}; +void() beast_runb10 =[ $runb10 , beast_runb11 ] {ai_run(20);}; +void() beast_runb11 =[ $runb11 , beast_runb12 ] {ai_run(32);}; +void() beast_runb12 =[ $runb12 , beast_runb1 ] +{ + ai_run(32); + beast_random_run(); +}; + +void() beast_runc1 =[ $runc1 , beast_runc2 ] { +ai_run(32);}; +void() beast_runc2 =[ $runc2 , beast_runc3 ] {ai_run(32);}; +void() beast_runc3 =[ $runc3 , beast_runc4 ] {ai_run(32);}; +void() beast_runc4 =[ $runc4 , beast_runc5 ] {ai_run(20);}; +void() beast_runc5 =[ $runc5 , beast_runc6 ] {ai_run(32);}; +void() beast_runc6 =[ $runc6 , beast_runc7 ] {ai_run(32);}; +void() beast_runc7 =[ $runc7 , beast_runc8 ] {ai_run(26);}; +void() beast_runc8 =[ $runc8 , beast_runc9 ] {ai_run(32);}; +void() beast_runc9 =[ $runc9 , beast_runc10 ] {ai_run(32);}; +void() beast_runc10 =[ $runc10 , beast_runc11 ] {ai_run(20);}; +void() beast_runc11 =[ $runc11 , beast_runc12 ] {ai_run(32);}; +void() beast_runc12 =[ $runc12 , beast_runc1 ] +{ + ai_run(32); + beast_random_run(); +}; + +void() beast_random_run = +{ + local float rnd; + + rnd = random() * 3; + + if (rnd < 1) + self.think = beast_runa1; + else if (rnd < 2) + self.think = beast_runb1; + else + self.think = beast_runc1; +}; + +float() CheckbeastMelee; + +void() beast_attb1 =[ $attb1, beast_attb2 ] {ai_charge(10);}; +void() beast_attb2 =[ $attb2, beast_attb3 ] {ai_charge(10);}; +void() beast_attb3 =[ $attb3, beast_attb4 ] {ai_charge(10);}; +void() beast_attb4 =[ $attb4, beast_attb5 ] { +beast_bite();}; +void() beast_attb5 =[ $attb5, beast_attb6 ] {ai_charge(10);}; +void() beast_attb6 =[ $attb6, beast_attb7 ] +{ + ai_charge(10); + + // check if enemy is still in striking distance + if (!CheckbeastMelee()) + beast_runa1(); +}; +void() beast_attb7 =[ $attb7, beast_attb8 ] { +beast_bite();}; +void() beast_attb8 =[ $attb8, beast_attb9 ] {ai_charge(10);}; +void() beast_attb9 =[ $attb9, beast_attb10 ] {ai_charge(10);}; +void() beast_attb10 =[ $attb10, beast_attb11 ] { +beast_bite();}; +void() beast_attb11 =[ $attb11, beast_attb12 ] {ai_charge(10);}; +void() beast_attb12 =[ $attb12, beast_runa1 ] {ai_charge(10);}; + +void() beast_atta1 =[ $atta1, beast_atta2 ] {ai_charge(10);}; +void() beast_atta2 =[ $atta2, beast_atta3 ] {ai_charge(10);}; +void() beast_atta3 =[ $atta3, beast_atta4 ] {ai_charge(10);}; +void() beast_atta4 =[ $atta4, beast_atta5 ] {ai_charge(10);}; +void() beast_atta5 =[ $atta5, beast_atta6 ] {ai_charge(10);}; +void() beast_atta6 =[ $atta6, beast_atta7 ] {ai_charge(10);}; +void() beast_atta7 =[ $atta7, beast_atta8 ] {ai_charge(10);}; +void() beast_atta8 =[ $atta8, beast_atta9 ] {ai_charge(10);}; +void() beast_atta9 =[ $atta9, beast_atta10 ] { +beast_bite(); +beast_bite(); +ai_charge(10);}; +void() beast_atta10 =[ $atta10, beast_atta11 ] {ai_charge(10);}; +void() beast_atta11 =[ $atta11, beast_atta12 ] {ai_charge(10);}; +void() beast_atta12 =[ $atta12, beast_runa1 ] {ai_charge(10);}; + +void() beast_melee = +{ + if (random() < 0.5) + beast_atta1(); + else + beast_attb1(); +}; + + +// special attack +void() BeastPowTouch = +{ + local float damg; + + if ((other == self.owner) || (other == world)) + return; + + damg = 25 + random()*10; + + if (other.health) + { + T_Damage (other, self, self.owner, damg ); + } + + other.velocity = other.velocity + self.velocity + '0 0 200'; + other.flags = other.flags - (other.flags & FL_ONGROUND); + setorigin(other, other.origin + '0 0 1'); + + sound (self.owner, CHAN_WEAPON, "weapons/r_exp3.wav", 0.2, 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 (); + remove(self); +}; + +void() BeastPowThink = +{ + local entity trav; + local vector vec; + local float dist, ratio; + + if ((self.spawn_time < (time - 3)) || (self.origin == self.oldorigin)) { + sound (self.owner, CHAN_WEAPON, "weapons/r_exp3.wav", 0.2, ATTN_NORM); + remove(self); + return; + } + + self.frame = self.frame + 1; + if (self.frame >= 8) + self.frame = 0; + + vec = self.velocity; + + traceline(self.origin + vec*frametime*2 + '0 0 32', self.origin + vec*frametime*2 - '0 0 48', TRUE, world); + if (trace_fraction == 1) { + sound (self.owner, CHAN_WEAPON, "weapons/r_exp3.wav", 0, ATTN_NORM); + remove(self); + return; + } + else { + self.velocity = normalize(trace_endpos + '0 0 24' - self.origin) * 750; + + self.flags = self.flags - (self.flags & FL_ONGROUND); + + traceline(self.origin + '0 0 32', self.origin - '0 0 48', TRUE, world); + setorigin(self, trace_endpos + '0 0 24'); + } + + // earth-shake + trav = findradius(self.origin, 512); + while (trav != world) { + if (trav.classname == "player") { + // shake view + vec = '12 0 0' * random() + '0 12 0' * random() + '0 0 22' * random() - '6 6 14'; + ratio = 1 - (vlen(trav.origin - self.origin) / 512); + if (ratio > 1) + ratio = 1; + vec = vec * ratio; + trav.view_ofs = '0 0 22' + vec; + trav.punchangle = vec * 0.5; + if (trav.view_ofs == '0 0 0') + trav.view_ofs = '0 0 1'; + } + + trav = trav.chain; + } + + self.oldorigin = self.origin; + + self.nextthink = time + 0.05; +}; + +void() BeastSpecialAttack = +{ + local entity trav; + local entity missile; + + missile = spawn(); + missile.classname = "beast_power"; + missile.owner = self; + missile.solid = SOLID_TRIGGER; + missile.movetype = MOVETYPE_FLY; + + setsize(missile, '0 0 0', '0 0 0'); + setmodel(missile, "progs/pow.mdl"); + missile.velocity = normalize(self.enemy.origin - self.origin + self.enemy.velocity * 0.5) * 750; + missile.velocity_z = 0; + missile.old_velocity = missile.velocity; + + makevectors(self.angles); + + setorigin(missile, self.origin + v_forward * 16); + + missile.touch = BeastPowTouch; + missile.think = BeastPowThink; + missile.spawn_time = time; + missile.nextthink = time + 0.05; + +/* + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_EXPLOSION); + WriteCoord (MSG_BROADCAST, missile.origin_x); + WriteCoord (MSG_BROADCAST, missile.origin_y); + WriteCoord (MSG_BROADCAST, missile.origin_z); +*/ + + sound (self, CHAN_BODY, "weapons/r_exp3.wav", 0.4, ATTN_NORM); + sound (self, CHAN_WEAPON, "doors/stndr1.wav", 1, ATTN_NORM); + + // send players airbourne + trav = find(world, classname, "player"); + while (trav != world) { + if ((trav.flags & FL_ONGROUND) && (vlen(trav.origin - self.origin) < 256)) + trav.velocity_z = 225; + + trav = find(trav, classname, "player"); + } +}; + +void() beast_xatta1 =[ $xatta1, beast_xatta2 ] {self.last_special = time;}; +void() beast_xatta2 =[ $xatta2, beast_xatta3 ] {}; +void() beast_xatta3 =[ $xatta3, beast_xatta4 ] {}; +void() beast_xatta4 =[ $xatta4, beast_xatta5 ] {}; +void() beast_xatta5 =[ $xatta5, beast_xatta6 ] {}; +void() beast_xatta6 =[ $xatta6, beast_xatta7 ] {}; +void() beast_xatta7 =[ $xatta7, beast_xatta8 ] {}; +void() beast_xatta8 =[ $xatta8, beast_xatta9 ] {}; +void() beast_xatta9 =[ $xatta9, beast_xatta10 ] {}; +void() beast_xatta10 =[ $xatta10, beast_xatta11 ] {}; +void() beast_xatta11 =[ $xatta11, beast_xatta12 ] {BeastSpecialAttack();}; +void() beast_xatta12 =[ $xatta12, beast_xatta13 ] {}; +void() beast_xatta13 =[ $xatta13, beast_xatta14 ] {}; +void() beast_xatta14 =[ $xatta14, beast_xatta15 ] {}; +void() beast_xatta15 =[ $xatta15, beast_xatta16 ] {}; +void() beast_xatta16 =[ $xatta16, beast_xatta17 ] {}; +void() beast_xatta17 =[ $xatta17, beast_xatta18 ] {}; +void() beast_xatta18 =[ $xatta18, beast_runa1 ] {}; + + +void() beast_pain1 =[ $pain1 , beast_pain2 ] {}; +void() beast_pain2 =[ $pain2 , beast_pain3 ] {}; +void() beast_pain3 =[ $pain3 , beast_pain4 ] {}; +void() beast_pain4 =[ $pain4 , beast_pain5 ] {}; +void() beast_pain5 =[ $pain5 , beast_pain6 ] {}; +void() beast_pain6 =[ $pain6 , beast_runa1 ] {}; + +void(entity attacker, float damage) beast_pain = +{ + if (self.pain_finished > time) + return; + + MalePainSound(1); + + if (random()*100 > damage) + return; + + self.pain_finished = time + 2; + beast_pain1 (); +}; + +void() beast_die1 =[ $death1, beast_die2 ] {}; +void() beast_die2 =[ $death2, beast_die3 ] {}; +void() beast_die3 =[ $death3, beast_die4 ] {}; +void() beast_die4 =[ $death4, beast_die5 ] {}; +void() beast_die5 =[ $death5, beast_die6 ] {}; +void() beast_die6 =[ $death6, beast_die7 ] {}; +void() beast_die7 =[ $death7, beast_die8 ] {}; +void() beast_die8 =[ $death8, beast_die9 ] {}; +void() beast_die9 =[ $death9, beast_die10 ] {}; +void() beast_die10 =[ $death10, beast_die11 ] {}; +void() beast_die11 =[ $death11, beast_die12 ] {}; +void() beast_die12 =[ $death12, beast_die12 ] {}; + +void() beast_diea1 =[ $deata1, beast_diea2 ] {}; +void() beast_diea2 =[ $deata2, beast_diea3 ] {}; +void() beast_diea3 =[ $deata3, beast_diea4 ] {}; +void() beast_diea4 =[ $deata4, beast_diea5 ] {}; +void() beast_diea5 =[ $deata5, beast_diea6 ] {}; +void() beast_diea6 =[ $deata6, beast_diea7 ] {}; +void() beast_diea7 =[ $deata7, beast_diea8 ] {}; +void() beast_diea8 =[ $deata8, beast_diea9 ] {}; +void() beast_diea9 =[ $deata9, beast_diea10 ] {}; +void() beast_diea10 =[ $deata10, beast_diea11 ] {}; +void() beast_diea11 =[ $deata11, beast_diea12 ] {}; +void() beast_diea12 =[ $deata12, beast_diea12 ] {}; + + +void() beast_die = +{ +// regular death + MaleDeathSound(1); + self.solid = SOLID_NOT; + + if (random() > 0.5) + beast_die1 (); + else + beast_diea1 (); +}; + +//============================================================================ + +/* +============== +CheckbeastMelee + +Returns TRUE if a melee attack would hit right now +============== +*/ +float() CheckbeastMelee = +{ + if ((enemy_range == RANGE_MELEE) && (vlen(self.origin - self.enemy.origin) < 96)) + { // FIXME: check canreach + self.attack_state = AS_MELEE; + return TRUE; + } + return FALSE; +}; + +/* +============== +CheckbeastJump + +============== +*/ +float() CheckbeastJump = +{ + local vector dist, p1, p2; + local float d; + + if (self.last_special > (time - 4)) + return FALSE; + + // check for head room + traceline(self.origin, self.origin + '0 0 64', TRUE, self); + if (trace_fraction < 1) + return FALSE; + + // check if on same level as enemy + traceline(self.origin, self.origin - '0 0 64', TRUE, self); + p1 = trace_endpos; + + traceline(self.enemy.origin, self.enemy.origin - '0 0 64', TRUE, self); + p2 = trace_endpos; + + if (p1_z != p2_z) + return FALSE; + + // now, check line of sight (between p1 and p2) + p1 = p1 + '0 0 1'; + p2 = p2 + '0 0 1'; + + traceline(p1, p2, TRUE, world); + + if (trace_fraction < 1) + return FALSE; + + dist = self.enemy.origin - self.origin; + dist_z = 0; + + d = vlen(dist); + + if (d < 80) + return FALSE; + + if (d > 256) + return FALSE; + + return TRUE; +}; + +float() beastCheckAttack = +{ + local vector vec; + +// if close enough for slashing, go for it + if (CheckbeastMelee ()) + { + self.attack_state = AS_MELEE; + return TRUE; + } + + if (CheckbeastJump ()) + { + self.attack_state = AS_MISSILE; + return TRUE; + } + + return FALSE; +}; + + +//=========================================================================== + +/*QUAKED monster_beast (1 0 0) (-32 -32 -24) (32 32 40) Ambush + +*/ + +void() monster_dog = +{ + remove(self); +}; + +void() xmen_beast = +{ + if (deathmatch) + { + remove(self); + return; + } + precache_model ("progs/beast.mdl"); + precache_model ("progs/pow.mdl"); + + // XMen matched ID sounds +// precache_sound ("zombie/z_hit.wav"); + precache_sound ("zombie/z_miss.wav"); + precache_sound ("doors/stndr1.wav"); + + precache_sound ("generic/punch1.wav"); + precache_sound ("generic/punch2.wav"); + precache_sound ("generic/punch3.wav"); + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + + setmodel (self, "progs/beast.mdl"); + + setsize (self, VEC_HULL_MIN, VEC_HULL_MAX); + self.health = 100 + cvar("skill")*10; + + self.th_stand = beast_stand1; + self.th_walk = beast_stand1; + self.th_run = beast_runa1; + self.th_pain = beast_pain; + self.th_die = beast_die; + self.th_melee = beast_melee; + self.th_missile = beast_xatta1; + + walkmonster_start(); +}; diff --git a/bishop.c b/bishop.c new file mode 100644 index 0000000..437808c --- /dev/null +++ b/bishop.c @@ -0,0 +1,323 @@ +/* +============================================================================== + +Bishop + +============================================================================== + +Attack : Bishop enjoys using a BIG gun, He also has the ability to +absorb energy, allowing him to redirect it back towards his attacker. +Bishops main weapon is two cool futuristic laser type guns. If the +player uses an energy weapon against him, Bishop will not be effected, +but will store up energy for a special (magic) attack. +Bishop will do his special attack at random times. This will be a +huge energy burst from his hands. + +Defence : The ability to Store energy attacks + +Best weapon to use : Chaingun. +Worst weapon to use : Lazer will not be effectual +*/ + +$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9 +$frame stand10 stand11 stand12 stand13 + +$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 walk9 walk10 +$frame walk11 walk12 + +$frame run1 run2 run3 run4 run5 run6 run7 run8 + +$frame pain1 pain2 pain3 pain4 pain5 pain6 pain7 pain8 pain9 + +$frame paina1 paina2 paina3 paina4 paina5 paina6 paina7 paina8 paina9 paina10 +$frame paina11 paina12 paina13 paina14 paina15 paina16 paina17 paina18 paina19 paina20 +$frame paina21 paina22 paina23 + +$frame death1 death2 death3 death4 death5 death6 death7 death8 death9 death10 +$frame death11 death12 death13 death14 death15 death16 + +$frame shoot1 shoot2 shoot3 shoot4 shoot5 shoot6 shoot7 shoot8 + +$frame xatta1 xatta2 xatta3 xatta4 xatta5 xatta6 xatta7 xatta8 +$frame xatta9 xatta10 xatta11 xatta12 + +void(float r_ofs) bishop_fire; +void() bishop_specialfire; + +void() bishop_stand1 =[ $stand1, bishop_stand2 ] {ai_stand();}; +void() bishop_stand2 =[ $stand2, bishop_stand3 ] {ai_stand();}; +void() bishop_stand3 =[ $stand3, bishop_stand4 ] {ai_stand();}; +void() bishop_stand4 =[ $stand4, bishop_stand5 ] {ai_stand();}; +void() bishop_stand5 =[ $stand5, bishop_stand6 ] {ai_stand();}; +void() bishop_stand6 =[ $stand6, bishop_stand7 ] {ai_stand();}; +void() bishop_stand7 =[ $stand7, bishop_stand8 ] {ai_stand();}; +void() bishop_stand8 =[ $stand8, bishop_stand9 ] {ai_stand();}; +void() bishop_stand9 =[ $stand9, bishop_stand10 ] {ai_stand();}; +void() bishop_stand10 =[ $stand10, bishop_stand11 ] {ai_stand();}; +void() bishop_stand11 =[ $stand11, bishop_stand12 ] {ai_stand();}; +void() bishop_stand12 =[ $stand12, bishop_stand13 ] {ai_stand();}; +void() bishop_stand13 =[ $stand13, bishop_stand1 ] {ai_stand();}; + +void() bishop_walk1 =[ $walk1, bishop_walk2 ] { +//if (random() < 0.2) +// sound (self, CHAN_VOICE, "soldier/idle.wav", 1, ATTN_IDLE); +ai_walk(6);}; +void() bishop_walk2 =[ $walk2, bishop_walk3 ] {ai_walk(6);}; +void() bishop_walk3 =[ $walk3, bishop_walk4 ] {ai_walk(6);}; +void() bishop_walk4 =[ $walk4, bishop_walk5 ] {ai_walk(6);}; +void() bishop_walk5 =[ $walk5, bishop_walk6 ] {ai_walk(7);}; +void() bishop_walk6 =[ $walk6, bishop_walk7 ] {ai_walk(7);}; +void() bishop_walk7 =[ $walk7, bishop_walk8 ] {ai_walk(8);}; +void() bishop_walk8 =[ $walk8, bishop_walk9 ] {ai_walk(7);}; +void() bishop_walk9 =[ $walk9, bishop_walk10 ] {ai_walk(5);}; +void() bishop_walk10 =[ $walk10, bishop_walk11 ] {ai_walk(5);}; +void() bishop_walk11 =[ $walk11, bishop_walk12 ] {ai_walk(6);}; +void() bishop_walk12 =[ $walk12, bishop_walk1 ] {ai_walk(7);}; + +void() bishop_run1 =[ $run1, bishop_run2 ] { +//if (random() < 0.2) +// sound (self, CHAN_VOICE, "soldier/idle.wav", 1, ATTN_IDLE); +ai_run(14);}; +void() bishop_run2 =[ $run2, bishop_run3 ] {ai_run(16);}; +void() bishop_run3 =[ $run3, bishop_run4 ] {ai_run(12);}; +void() bishop_run4 =[ $run4, bishop_run5 ] {ai_run(12);}; +void() bishop_run5 =[ $run5, bishop_run6 ] {ai_run(10);}; +void() bishop_run6 =[ $run6, bishop_run7 ] {ai_run(14);}; +void() bishop_run7 =[ $run7, bishop_run8 ] {ai_run(12);}; +void() bishop_run8 =[ $run8, bishop_run1 ] {ai_run(10);}; + +void() bishop_xatta1 =[ $xatta1, bishop_xatta2 ] {ai_face();}; +void() bishop_xatta2 =[ $xatta2, bishop_xatta3 ] {ai_face();}; +void() bishop_xatta3 =[ $xatta3, bishop_xatta4 ] {ai_face();}; +void() bishop_xatta4 =[ $xatta4, bishop_xatta5 ] {ai_face();}; +void() bishop_xatta5 =[ $xatta5, bishop_xatta6 ] {ai_face();}; +void() bishop_xatta6 =[ $xatta6, bishop_xatta7 ] {bishop_specialfire();}; +void() bishop_xatta7 =[ $xatta7, bishop_xatta8 ] {}; +void() bishop_xatta8 =[ $xatta8, bishop_xatta9 ] {}; +void() bishop_xatta9 =[ $xatta9, bishop_xatta10 ] {}; +void() bishop_xatta10 =[ $xatta10, bishop_xatta11 ] {}; +void() bishop_xatta11 =[ $xatta11, bishop_xatta12 ] {}; +void() bishop_xatta12 =[ $xatta12, bishop_run1 ] {}; + +void() bishop_shoot1 =[ $shoot1, bishop_shoot2 ] +{ + ai_face(); + + if ((self.last_special < (time - 5)) && (enemy_range >= RANGE_NEAR) && (enemy_range <= RANGE_MID) && (random() < 0.4)) { + self.last_special = time; + bishop_xatta1(); + return; + } + +}; +void() bishop_shoot2 =[ $shoot2, bishop_shoot3 ] {ai_face();bishop_fire(6);}; +void() bishop_shoot3 =[ $shoot3, bishop_shoot4 ] {ai_face();}; +void() bishop_shoot4 =[ $shoot4, bishop_shoot5 ] {ai_face();}; +void() bishop_shoot5 =[ $shoot5, bishop_shoot6 ] {ai_face();}; +void() bishop_shoot6 =[ $shoot6, bishop_shoot7 ] {ai_face();bishop_fire(-6);}; +void() bishop_shoot7 =[ $shoot7, bishop_shoot8 ] {ai_face();}; +void() bishop_shoot8 =[ $shoot8, bishop_run1 ] {ai_face();SUB_CheckRefire (bishop_shoot1);}; + + +void() bishop_pain1 =[ $pain1, bishop_pain2 ] {}; +void() bishop_pain2 =[ $pain2, bishop_pain3 ] {}; +void() bishop_pain3 =[ $pain3, bishop_pain4 ] {}; +void() bishop_pain4 =[ $pain4, bishop_pain5 ] {}; +void() bishop_pain5 =[ $pain5, bishop_pain6 ] {}; +void() bishop_pain6 =[ $pain6, bishop_pain7 ] {}; +void() bishop_pain7 =[ $pain7, bishop_pain8 ] {}; +void() bishop_pain8 =[ $pain8, bishop_pain9 ] {}; +void() bishop_pain9 =[ $pain9, bishop_run1 ] {}; + +void() bishop_paina1 =[ $paina1, bishop_paina2 ] {}; +void() bishop_paina2 =[ $paina2, bishop_paina3 ] {}; +void() bishop_paina3 =[ $paina3, bishop_paina4 ] {}; +void() bishop_paina4 =[ $paina4, bishop_paina5 ] {}; +void() bishop_paina5 =[ $paina5, bishop_paina6 ] {}; +void() bishop_paina6 =[ $paina6, bishop_paina7 ] {}; +void() bishop_paina7 =[ $paina7, bishop_paina8 ] {}; +void() bishop_paina8 =[ $paina8, bishop_paina9 ] {}; +void() bishop_paina9 =[ $paina9, bishop_paina10 ] {}; +void() bishop_paina10 =[ $paina10, bishop_paina11 ] {}; +void() bishop_paina11 =[ $paina11, bishop_paina12 ] {}; +void() bishop_paina12 =[ $paina12, bishop_paina13 ] {}; +void() bishop_paina13 =[ $paina13, bishop_paina14 ] {}; +void() bishop_paina14 =[ $paina14, bishop_paina15 ] {}; +void() bishop_paina15 =[ $paina15, bishop_paina16 ] {}; +void() bishop_paina16 =[ $paina16, bishop_paina17 ] {}; +void() bishop_paina17 =[ $paina17, bishop_paina18 ] {}; +void() bishop_paina18 =[ $paina18, bishop_paina19 ] {}; +void() bishop_paina19 =[ $paina19, bishop_paina20 ] {}; +void() bishop_paina20 =[ $paina20, bishop_paina21 ] {}; +void() bishop_paina21 =[ $paina21, bishop_paina22 ] {}; +void() bishop_paina22 =[ $paina22, bishop_paina23 ] {}; +void() bishop_paina23 =[ $paina23, bishop_run1 ] {}; + +void(entity attacker, float damage) bishop_pain = +{ + local float r; + + if (self.pain_finished > time) + return; + + MalePainSound(1); + + r = random(); + if (r < 0.8) + { + self.pain_finished = time + 3; + bishop_pain1 (); + } + else + { + self.pain_finished = time + 6; + bishop_paina1 (); + } +}; + + +void(float r_ofs) bishop_fire = +{ + local vector vect; + local entity missile; + + ai_face(); + self.effects = self.effects | EF_MUZZLEFLASH; + + makevectors(self.angles); + + // allow for up/down aiming + vect = normalize(self.enemy.origin - self.origin); + v_forward_z = vect_z; + v_forward = normalize(v_forward); + + sound (self, CHAN_WEAPON, "doors/airdoor2.wav", 1, ATTN_NORM); + + launch_spike (self.origin + '0 0 8' + v_forward*14 + v_right * r_ofs, v_forward); + newmis.classname = "gambit_card"; + setmodel (newmis, "progs/laser.mdl"); + setsize(newmis, '0 0 0', '0 0 0'); +}; + +void() BishopSpecialTouch = +{ + if (other == self.owner) + return; + + if (other.takedamage == DAMAGE_AIM) + { + spawn_touchblood (30); + T_Damage(other, self, self.owner, 20); + } + + T_RadiusDamage(self, self.owner, 20, other); + + 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); + + remove(self); + +}; + +void() bishop_specialfire = +{ + local vector vect; + local entity missile; + + self.effects = self.effects | EF_MUZZLEFLASH; + + sound (self, CHAN_WEAPON, "boss1/throw.wav", 1, ATTN_NORM); + + vect = (self.enemy.origin - self.origin) + self.enemy.velocity * (vlen(self.enemy.origin - self.origin) / 750); + vect = normalize(vect); + + launch_spike (self.origin + '0 0 8' + v_forward*14, vect); + newmis.velocity = newmis.velocity * 0.75; + newmis.classname = "bishop_special"; + newmis.touch = BishopSpecialTouch; + newmis.avelocity_z = 300; + setmodel (newmis, "progs/bisblast.mdl"); + setsize(newmis, '0 0 0', '0 0 0'); +}; + + +void() bishop_die1 =[ $death1, bishop_die2 ] {}; +void() bishop_die2 =[ $death2, bishop_die3 ] {}; +void() bishop_die3 =[ $death3, bishop_die4 ] {self.solid = SOLID_NOT;}; +void() bishop_die4 =[ $death4, bishop_die5 ] {}; +void() bishop_die5 =[ $death5, bishop_die6 ] {}; +void() bishop_die6 =[ $death6, bishop_die7 ] {}; +void() bishop_die7 =[ $death7, bishop_die8 ] {}; +void() bishop_die8 =[ $death8, bishop_die9 ] {}; +void() bishop_die9 =[ $death9, bishop_die10 ] {}; +void() bishop_die10 =[ $death10, bishop_die11 ] {}; +void() bishop_die11 =[ $death11, bishop_die12 ] {}; +void() bishop_die12 =[ $death12, bishop_die13 ] {}; +void() bishop_die13 =[ $death13, bishop_die14 ] {}; +void() bishop_die14 =[ $death14, bishop_die15 ] {}; +void() bishop_die15 =[ $death15, bishop_die16 ] {}; +void() bishop_die16 =[ $death16, bishop_die16 ] {}; + +void() bishop_die = +{ + +// regular death + MaleDeathSound(1); + bishop_die1 (); +}; + + +/*QUAKED monster_army (1 0 0) (-16 -16 -24) (16 16 40) Ambush +*/ +void() monster_army = +{ + remove(self); +}; + +void() xmen_bishop = +{ + if (deathmatch) + { + remove(self); + return; + } + precache_model ("progs/bishop.mdl"); + precache_model ("progs/laser.mdl"); + precache_model ("progs/bisblast.mdl"); + + // Xmen Sounds: matched ID sounds + precache_sound ("boss1/throw.wav"); + precache_sound2 ("doors/airdoor2.wav"); + +/* + // Old Soldier sounds + precache_sound ("soldier/death1.wav"); + precache_sound ("soldier/idle.wav"); + precache_sound ("soldier/pain1.wav"); + precache_sound ("soldier/pain2.wav"); + precache_sound ("soldier/sattck1.wav"); + precache_sound ("soldier/sight1.wav"); +*/ + + precache_sound ("player/udeath.wav"); // gib death + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + + setmodel (self, "progs/bishop.mdl"); + + setsize (self, '-16 -16 -24', '16 16 40'); + self.health = 180; + + self.th_stand = bishop_stand1; + self.th_walk = bishop_walk1; + self.th_run = bishop_run1; + self.th_missile = bishop_shoot1; + self.th_pain = bishop_pain; + self.th_die = bishop_die; + + walkmonster_start (); +}; \ No newline at end of file diff --git a/cannon.c b/cannon.c new file mode 100644 index 0000000..2c16abd --- /dev/null +++ b/cannon.c @@ -0,0 +1,308 @@ +/*========================================================================== + + CANNONBALL + +==========================================================================*/ + +$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9 +$frame stand10 stand11 stand12 stand13 + +$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 walk9 walk10 +$frame walk11 walk12 + +$frame run1 run2 run3 run4 run5 run6 run7 run8 + +$frame pain1 pain2 pain3 pain4 pain5 pain6 + +$frame paina1 paina2 paina3 paina4 paina5 paina6 paina7 paina8 paina9 paina10 +$frame paina11 paina12 paina13 paina14 paina15 paina16 paina17 paina18 paina19 paina20 +$frame paina21 paina22 paina23 paina24 paina25 paina26 paina27 paina28 paina29 + +$frame death1 death2 death3 death4 death5 death6 death7 death8 death9 death10 +$frame death11 death12 death13 death14 death15 death16 + +$frame atta1 atta2 atta3 atta4 atta5 atta6 atta7 atta8 atta9 + + +$frame xatta1 xatta2 xatta3 xatta4 xatta5 +$frame xatta24 xatta25 xatta26 xatta27 + + +void() cannon_stand1 = [ $stand1, cannon_stand2 ] {ai_stand();}; +void() cannon_stand2 = [ $stand2, cannon_stand3 ] {ai_stand();}; +void() cannon_stand3 = [ $stand3, cannon_stand4 ] {ai_stand();}; +void() cannon_stand4 = [ $stand4, cannon_stand5 ] {ai_stand();}; +void() cannon_stand5 = [ $stand5, cannon_stand6 ] {ai_stand();}; +void() cannon_stand6 = [ $stand6, cannon_stand7 ] {ai_stand();}; +void() cannon_stand7 = [ $stand7, cannon_stand8 ] {ai_stand();}; +void() cannon_stand8 = [ $stand8, cannon_stand9 ] {ai_stand();}; +void() cannon_stand9 = [ $stand9, cannon_stand10 ] {ai_stand();}; +void() cannon_stand10 = [ $stand10, cannon_stand11 ] {ai_stand();}; +void() cannon_stand11 = [ $stand11, cannon_stand12 ] {ai_stand();}; +void() cannon_stand12 = [ $stand12, cannon_stand13 ] {ai_stand();}; +void() cannon_stand13 = [ $stand13, cannon_stand1 ] {ai_stand();}; + +void() cannon_walk1 = [ $walk1, cannon_walk2 ] {ai_walk(6);}; +void() cannon_walk2 = [ $walk2, cannon_walk3 ] {ai_walk(4);}; +void() cannon_walk3 = [ $walk3, cannon_walk4 ] {ai_walk(4);}; +void() cannon_walk4 = [ $walk4, cannon_walk5 ] {ai_walk(4);}; +void() cannon_walk5 = [ $walk5, cannon_walk6 ] {ai_walk(6);}; +void() cannon_walk6 = [ $walk6, cannon_walk7 ] {ai_walk(7);}; +void() cannon_walk7 = [ $walk7, cannon_walk8 ] {ai_walk(7);}; +void() cannon_walk8 = [ $walk8, cannon_walk9 ] {ai_walk(4);}; +void() cannon_walk9 = [ $walk9, cannon_walk10 ] {ai_walk(4);}; +void() cannon_walk10 = [ $walk10, cannon_walk11 ] {ai_walk(5);}; +void() cannon_walk11 = [ $walk11, cannon_walk12 ] {ai_walk(6);}; +void() cannon_walk12 = [ $walk12, cannon_walk1 ] {ai_walk(7);}; + +void() cannon_run1 = [ $run1, cannon_run2 ] {ai_run(16);}; +void() cannon_run2 = [ $run2, cannon_run3 ] {ai_run(16);}; +void() cannon_run3 = [ $run3, cannon_run4 ] {ai_run(16);}; +void() cannon_run4 = [ $run4, cannon_run5 ] {ai_run(16);}; +void() cannon_run5 = [ $run5, cannon_run6 ] {ai_run(16);}; +void() cannon_run6 = [ $run6, cannon_run7 ] {ai_run(16);}; +void() cannon_run7 = [ $run7, cannon_run8 ] {ai_run(16);}; +void() cannon_run8 = [ $run8, cannon_run1 ] {ai_run(16);}; + +//============================================================================ + +void() cannon_pain1 = [ $pain1, cannon_pain2 ] {}; +void() cannon_pain2 = [ $pain2, cannon_pain3 ] {}; +void() cannon_pain3 = [ $pain3, cannon_pain4 ] {}; +void() cannon_pain4 = [ $pain4, cannon_pain5 ] {}; +void() cannon_pain5 = [ $pain5, cannon_pain6 ] {}; +void() cannon_pain6 = [ $pain6, cannon_run1 ] {}; + +void() cannon_paina1 = [ $paina1, cannon_paina2 ] {}; +void() cannon_paina2 = [ $paina2, cannon_paina3 ] {}; +void() cannon_paina3 = [ $paina3, cannon_paina4 ] {}; +void() cannon_paina4 = [ $paina4, cannon_paina5 ] {}; +void() cannon_paina5 = [ $paina5, cannon_paina6 ] {}; +void() cannon_paina6 = [ $paina6, cannon_paina7 ] {}; +void() cannon_paina7 = [ $paina7, cannon_paina8 ] {}; +void() cannon_paina8 = [ $paina8, cannon_paina9 ] {}; +void() cannon_paina9 = [ $paina9, cannon_paina10 ] {}; +void() cannon_paina10 = [ $paina10, cannon_paina11 ] {}; +void() cannon_paina11 = [ $paina11, cannon_paina12 ] {}; +void() cannon_paina12 = [ $paina12, cannon_paina13 ] {}; +void() cannon_paina13 = [ $paina13, cannon_paina14 ] {sound(self, CHAN_BODY, "cannon/flyloop.wav", 1, ATTN_NORM);}; +void() cannon_paina14 = [ $paina14, cannon_paina15 ] {}; +void() cannon_paina15 = [ $paina15, cannon_paina16 ] {}; +void() cannon_paina16 = [ $paina16, cannon_paina17 ] {}; +void() cannon_paina17 = [ $paina17, cannon_paina18 ] {}; +void() cannon_paina18 = [ $paina18, cannon_paina19 ] {}; +void() cannon_paina19 = [ $paina19, cannon_paina20 ] {}; +void() cannon_paina20 = [ $paina20, cannon_paina21 ] {}; +void() cannon_paina21 = [ $paina21, cannon_paina22 ] {}; +void() cannon_paina22 = [ $paina22, cannon_paina23 ] {}; +void() cannon_paina23 = [ $paina23, cannon_paina24 ] {}; +void() cannon_paina24 = [ $paina24, cannon_paina25 ] {}; +void() cannon_paina25 = [ $paina25, cannon_paina26 ] {}; +void() cannon_paina26 = [ $paina26, cannon_paina27 ] {}; +void() cannon_paina27 = [ $paina27, cannon_paina28 ] {}; +void() cannon_paina28 = [ $paina28, cannon_paina29 ] {}; +void() cannon_paina29 = [ $paina29, cannon_run1 ] {}; + +void(entity attacker, float damage) CannonPain = +{ + if (self.pain_finished > time) + return; + + MalePainSound(2); + + if (self.model != "progs/cannon1.mdl") + return; + + if (self.health <= 0) + return; + + if ((damage > 10) && (random() < 0.4)) { + self.pain_finished = time + 3; + cannon_paina1(); + } + else { + self.pain_finished = time + 3; + cannon_pain1(); + } +}; + +//============================================================================ + +void() cannon_death1 = [ $death1, cannon_death2 ] {}; +void() cannon_death2 = [ $death2, cannon_death3 ] {}; +void() cannon_death3 = [ $death3, cannon_death4 ] {self.solid = SOLID_NOT;}; +void() cannon_death4 = [ $death4, cannon_death5 ] {}; +void() cannon_death5 = [ $death5, cannon_death6 ] {}; +void() cannon_death6 = [ $death6, cannon_death7 ] {}; +void() cannon_death7 = [ $death7, cannon_death8 ] {}; +void() cannon_death8 = [ $death8, cannon_death9 ] {}; +void() cannon_death9 = [ $death9, cannon_death10 ] {}; +void() cannon_death10 = [ $death10, cannon_death11 ] {}; +void() cannon_death11 = [ $death11, cannon_death12 ] {}; +void() cannon_death12 = [ $death12, cannon_death13 ] {}; +void() cannon_death13 = [ $death13, cannon_death14 ] {}; +void() cannon_death14 = [ $death14, cannon_death15 ] {}; +void() cannon_death15 = [ $death15, cannon_death16 ] {}; +void() cannon_death16 = [ $death16, cannon_death16 ] {if (self.angles_x != 0) AngelPitch();}; + +void() cannon_xatta24; +void() CannonDie = +{ + if (self.model != "progs/cannon1.mdl") { + cannon_xatta24(); + return; + } + + MaleDeathSound(2); + + cannon_death1(); +}; + +//============================================================================ + +void() CannonPunch = +{ + local vector vect; + + if (!infront(self.enemy)) + return; + + if (vlen(self.enemy.origin - self.origin) > 64) + return; + + T_Damage(self.enemy, self, self, 15); + + self.enemy.punchangle_x = -15; +}; + +void() cannon_atta1 = [ $atta1, cannon_atta2 ] {ai_charge(4);}; +void() cannon_atta2 = [ $atta2, cannon_atta3 ] {ai_charge(4);sound (self, CHAN_WEAPON, "generic/swing1.wav", 1, ATTN_NORM);}; +void() cannon_atta3 = [ $atta3, cannon_atta4 ] {ai_charge(4);}; +void() cannon_atta4 = [ $atta4, cannon_atta5 ] {ai_charge(4);CannonPunch();}; +void() cannon_atta5 = [ $atta5, cannon_atta6 ] {}; +void() cannon_atta6 = [ $atta6, cannon_atta7 ] {}; +void() cannon_atta7 = [ $atta7, cannon_atta8 ] {}; +void() cannon_atta8 = [ $atta8, cannon_atta9 ] {}; +void() cannon_atta9 = [ $atta9, cannon_run1 ] {}; + +//============================================================================ + +void() xmen_cannonball; + +void() cannon_xatta1 = [ $xatta1, cannon_xatta2 ] {sound(self, CHAN_ITEM, "cannon/takeoff.wav", 1, ATTN_NORM); self.flags = self.flags | FL_GODMODE;}; +void() cannon_xatta2 = [ $xatta2, cannon_xatta3 ] {}; +void() cannon_xatta3 = [ $xatta3, cannon_xatta4 ] {}; +void() cannon_xatta4 = [ $xatta4, cannon_xatta5 ] {sound(self, CHAN_BODY, "cannon/flyloop.wav", 1, ATTN_NORM);}; +void() cannon_xatta5 = [ $xatta5, cannon_xatta7 ] {self.flags = self.flags | FL_FLY; self.yaw_speed = 8;}; + +/* see cannon2.qc for flying attack frames */ + +void() cannon_xatta24 = [ $xatta24, cannon_xatta25 ] +{ + setmodel(self, "progs/cannon1.mdl"); + setsize (self, VEC_HULL_MIN, VEC_HULL_MAX); + setorigin(self, self.origin + '0 0 1'); + + self.flags = self.flags - FL_FLY; + self.flags = self.flags - (self.flags & FL_ONGROUND); + + self.angles_x = 0; + self.angles_z = 0; +}; +void() cannon_xatta25 = [ $xatta25, cannon_xatta26 ] {}; +void() cannon_xatta26 = [ $xatta26, cannon_xatta27 ] {}; +void() cannon_xatta27 = [ $xatta27, cannon_xatta27 ] +{ + local entity new, oself; + + if (self.origin == self.oldorigin) { + +/* + new = spawn(); + new.classname = "xmen_cannonball"; + new.health = 99; + setorigin(new, self.origin); + new.angles = self.angles; + + self.solid = SOLID_NOT; + + oself = self; + self = new; + xmen_cannonball(); + walkmonster_start_go(); + self = oself; + + new.last_special = self.last_special; + new.frame = self.frame; + + new.health = self.health; + new.pausetime = 0; + new.enemy = new.goalentity = self.enemy; + + remove(self); + + self = new; +*/ + + setmodel (self, "progs/cannon1.mdl"); + setsize (self, VEC_HULL_MIN, VEC_HULL_MAX); + + self.flags = self.flags - (self.flags & FL_GODMODE); + + self.th_run(); + } + else { + self.oldorigin = self.origin; + } +}; + +//============================================================================ + +void() CannonCheckSpecial = +{ + if (self.last_special < (time - 8)) + cannon_xatta1(); +}; + +void() xmen_cannonball = +{ + if (deathmatch) + { + remove(self); + return; + } + + if (self.health == 0) { + // Xmen Sounds: matched ID sounds +// precache_sound ("boss1/throw.wav"); + + precache_sound ("cannon/takeoff.wav"); + precache_sound ("cannon/flyloop.wav"); + precache_sound ("generic/swing1.wav"); + precache_sound ("generic/punch2.wav"); + precache_sound ("generic/crash1.wav"); + + precache_model ("progs/cannon1.mdl"); + precache_model ("progs/cannon2.mdl"); + } + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + + setmodel (self, "progs/cannon1.mdl"); + setsize (self, VEC_HULL_MIN, VEC_HULL_MAX); + self.health = 120 + cvar("skill")*10; + + self.yaw_speed = 20; + + self.th_stand = cannon_stand1; + self.th_walk = cannon_walk1; + self.th_run = cannon_run1; + self.th_die = CannonDie; + self.th_pain = CannonPain; + self.th_melee = cannon_atta1; + self.th_missile = CannonCheckSpecial; + + self.think = walkmonster_start; + self.nextthink = time + 0.1 + random ()*0.1; +}; \ No newline at end of file diff --git a/cannon2.c b/cannon2.c new file mode 100644 index 0000000..712e7cd --- /dev/null +++ b/cannon2.c @@ -0,0 +1,114 @@ +// Cannonball's Special attack code + +$frame xatta6 xatta7 xatta8 xatta9 xatta10 xatta11 xatta12 xatta13 +$frame xatta14 xatta15 xatta16 xatta17 xatta18 xatta19 xatta20 xatta21 +$frame xatta22 xatta23 + +$frame fly1 fly2 fly3 + +void() cannon_xatta16; +void() cannon_xatta18; + +void() CannonFlyTouch = +{ + self.velocity = '0 0 0'; + + if (other != self.enemy) { // abort attack + sound(self, CHAN_BODY, "generic/crash1.wav", 1, ATTN_NORM); + self.x_flags = self.x_flags | X_CANNONFLYABORT; + +// cannon_xatta19(); + return; + } + + cannon_xatta16(); +}; + +void() CannonFlyThink = +{ + if (self.x_flags & X_CANNONFLYABORT) { + cannon_xatta18(); + return; + } + + ai_face(); + + if (!ai_forward(20)) { + if (self.oldorigin != '0 0 0') + setorigin(self, self.oldorigin); + + other = world; + + if (infront(self.enemy) && (vlen(self.enemy.origin - self.origin) < 80)) + other = self.enemy; + + CannonFlyTouch(); + } + else { + self.oldorigin = self.origin; + } + + if (self.last_flame_sound < (time - 0.75)) { + if (self.last_weapon_channel != CHAN_WEAPON) { + sound (self, CHAN_WEAPON, "cannon/flyloop.wav", 1, ATTN_NORM); + self.last_weapon_channel = CHAN_WEAPON; + } else { + sound (self, CHAN_BODY, "cannon/flyloop.wav", 1, ATTN_NORM); + self.last_weapon_channel = CHAN_BODY; + } + + self.last_flame_sound = time; + } + + ai_face(); + + self.nextthink = time + 0.05; +}; + +void() cannon_xatta7 = [ $xatta7, cannon_xatta8 ] +{ + setmodel(self, "progs/cannon2.mdl"); + self.flags = self.flags | FL_GODMODE; + ai_forward(3); +}; +void() cannon_xatta8 = [ $xatta8, cannon_xatta9 ] {ai_forward(6); ai_face();}; +void() cannon_xatta9 = [ $xatta9, cannon_xatta10 ] {ai_forward(9); ai_face();}; +void() cannon_xatta10 = [ $xatta10, cannon_xatta11 ] {ai_forward(12); ai_face();}; +void() cannon_xatta11 = [ $xatta11, cannon_xatta12 ] {ai_forward(15); ai_face();}; +void() cannon_xatta12 = [ $xatta12, cannon_xatta13 ] +{ + ai_forward(18); + self.oldorigin = '0 0 0'; + self.x_flags = self.x_flags - (self.x_flags & X_CANNONFLYABORT); +}; +void() cannon_xatta13 = [ $xatta13, cannon_xatta14 ] {CannonFlyThink();}; +void() cannon_xatta14 = [ $xatta14, cannon_xatta15 ] {CannonFlyThink();}; +void() cannon_xatta15 = [ $xatta15, cannon_xatta13 ] {CannonFlyThink();}; +void() cannon_xatta16 = [ $xatta16, cannon_xatta17 ] {ai_forward(15); sound (self, CHAN_ITEM, "generic/swing1.wav", 1, ATTN_NORM);}; +void() cannon_xatta17 = [ $xatta17, cannon_xatta18 ] {ai_forward(10);}; +void() cannon_xatta18 = [ $xatta18, cannon_xatta19 ] +{ + local vector vect; + + if (self.x_flags & X_CANNONFLYABORT) { + self.x_flags = self.x_flags - X_CANNONFLYABORT; + return; + } + + self.last_special = time; + + // do some damage + T_Damage(self.enemy, self, self, 30); + + sound (self, CHAN_WEAPON, "generic/punch2.wav", 1, ATTN_NORM); + + vect = normalize(self.enemy.origin - self.origin); + self.enemy.velocity = vect * 300; + self.enemy.velocity_z = 300; + self.enemy.punchangle_x = -15; +}; +void() cannon_xatta19 = [ $xatta19, cannon_xatta20 ] {self.angles_x = 0; self.angles_z = 0;}; +void() cannon_xatta20 = [ $xatta20, cannon_xatta21 ] {}; +void() cannon_xatta21 = [ $xatta21, cannon_xatta22 ] {}; +void() cannon_xatta22 = [ $xatta22, cannon_xatta23 ] {}; +void() cannon_xatta23 = [ $xatta23, cannon_xatta24 ] {}; diff --git a/cyclops.c b/cyclops.c new file mode 100644 index 0000000..c575039 --- /dev/null +++ b/cyclops.c @@ -0,0 +1,419 @@ +/* +============================================================================== + +CYCLOPS + +============================================================================== +*/ + +$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9 +$frame stand10 stand11 stand12 stand13 + +$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 walk9 walk10 walk11 walk12 + +$frame run1 run2 run3 run4 run5 run6 run7 run8 run9 run10 + +$frame pain1 pain2 pain3 pain4 pain5 pain6 + +$frame paina1 paina2 paina3 paina4 paina5 paina6 paina7 paina8 paina9 paina10 +$frame paina11 paina12 paina13 paina14 paina15 paina16 paina17 paina18 paina19 paina20 +$frame paina21 paina22 paina23 paina24 paina25 paina26 paina27 paina28 paina29 paina30 + +$frame death1 death2 death3 death4 death5 death6 death7 death8 death9 death10 +$frame death11 death12 death13 death14 death15 death16 death17 death18 death19 death20 + +$frame deata1 deata2 deata3 deata4 deata5 deata6 deata7 deata8 deata9 deata10 +$frame deata11 deata12 deata13 deata14 deata15 deata16 deata17 deata18 deata19 deata20 +$frame deata21 deata22 deata23 deata24 deata25 deata26 deata27 deata28 deata29 deata30 +$frame deata31 deata32 deata33 deata34 deata35 deata36 + +$frame attack1 attack2 attack3 attack4 attack5 attack6 attack7 attack8 +$frame attack9 attack10 attack11 attack12 + +/* +void() Cyclops_Laser_Touch = +{ + local vector org; + + if (other == self.owner) + return; // don't explode on owner + + if (pointcontents(self.origin) == CONTENT_SKY) + { + remove(self); + return; + } + + sound (self, CHAN_WEAPON, "enforcer/enfstop.wav", 1, ATTN_STATIC); + org = self.origin - 8*normalize(self.velocity); + + if (other.health) + { + SpawnBlood (org, self.velocity*0.2, 15); + T_Damage (other, self, self.owner, 15); + } + 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); + } + + remove(self); +}; + +void(vector org, vector vec) LaunchLaser = +{ + local vector vec; + + if (self.classname == "monster_enforcer") + sound (self, CHAN_WEAPON, "enforcer/enfire.wav", 1, ATTN_NORM); + + vec = normalize(vec); + + newmis = spawn(); + newmis.owner = self; + newmis.movetype = MOVETYPE_FLY; + newmis.solid = SOLID_BBOX; + newmis.effects = EF_DIMLIGHT; + + setmodel (newmis, "progs/claser1.mdl"); + setsize (newmis, '0 0 0', '0 0 0'); + + setorigin (newmis, org); + + newmis.velocity = vec * 600; + newmis.angles = vectoangles(newmis.velocity); + + newmis.nextthink = time + 5; + newmis.think = SUB_Remove; + newmis.touch = Cyclops_Laser_Touch; +}; +*/ + +void() LaserTouch = +{ + if (other == self.owner) + return; + + if (other.takedamage == DAMAGE_AIM) + { + spawn_touchblood (10); + T_Damage(other, self, self.owner, 10); + remove(self); + return; + } + + self.last_touch = time; + + sound (self, CHAN_WEAPON, "doors/airdoor2.wav", 1, ATTN_NORM); + if (self.velocity == '0 0 0') + remove(self); + +}; + +void(vector org, vector dir) spawn_laser = +{ + local entity missile, mpuff; + local vector vect; + + missile = spawn (); + missile.owner = self; + missile.movetype = MOVETYPE_BOUNCE; + missile.solid = SOLID_BBOX; + missile.classname = "laser"; + +// set missile speed + + vect = normalize(dir); + + missile.velocity = ProjectVelocity(1000, '0 0 -16'); + + missile.angles = vectoangles(missile.velocity); + missile.old_velocity = missile.velocity; + + missile.touch = LaserTouch; + +// set missile duration +// missile.last_idle = time; + + missile.last_touch = 0; + missile.oldorigin = missile.origin; + missile.nextthink = time + 2; +// missile.think = GrenadeExplode; + missile.think = SUB_Remove; + + setmodel (missile, "progs/claser1.mdl"); + setsize (missile, '0 0 0', '0 0 0'); + setorigin (missile, org); +}; + + +void() enforcer_fire = +{ + local vector org; + + self.effects = self.effects | EF_MUZZLEFLASH; + makevectors (self.angles); + + sound (self, CHAN_VOICE, "items/inv1.wav", 1, ATTN_NORM); + + org = self.origin + v_forward * 1 + '0 0 24'; + + spawn_laser(org, self.enemy.origin - self.origin); +}; + +//============================================================================ + +void() enf_stand1 =[ $stand1, enf_stand2 ] {ai_stand();}; +void() enf_stand2 =[ $stand2, enf_stand3 ] {ai_stand();}; +void() enf_stand3 =[ $stand3, enf_stand4 ] {ai_stand();}; +void() enf_stand4 =[ $stand4, enf_stand5 ] {ai_stand();}; +void() enf_stand5 =[ $stand5, enf_stand6 ] {ai_stand();}; +void() enf_stand6 =[ $stand6, enf_stand7 ] {ai_stand();}; +void() enf_stand7 =[ $stand7, enf_stand8 ] {ai_stand();}; +void() enf_stand8 =[ $stand8, enf_stand9 ] {ai_stand();}; +void() enf_stand9 =[ $stand9, enf_stand10 ] {ai_stand();}; +void() enf_stand10 =[ $stand10, enf_stand11 ] {ai_stand();}; +void() enf_stand11 =[ $stand11, enf_stand12 ] {ai_stand();}; +void() enf_stand12 =[ $stand12, enf_stand13 ] {ai_stand();}; +void() enf_stand13 =[ $stand13, enf_stand1 ] {ai_stand();}; + +void() enf_walk1 =[ $walk1 , enf_walk2 ] { +//if (random() < 0.2) +// sound (self, CHAN_VOICE, "enforcer/idle1.wav", 1, ATTN_IDLE); +ai_walk(6);}; +void() enf_walk2 =[ $walk2 , enf_walk3 ] {ai_walk(8);}; +void() enf_walk3 =[ $walk3 , enf_walk4 ] {ai_walk(7);}; +void() enf_walk4 =[ $walk4 , enf_walk5 ] {ai_walk(7);}; +void() enf_walk5 =[ $walk5 , enf_walk6 ] {ai_walk(7);}; +void() enf_walk6 =[ $walk6 , enf_walk7 ] {ai_walk(6);}; +void() enf_walk7 =[ $walk7 , enf_walk8 ] {ai_walk(4);}; +void() enf_walk8 =[ $walk8 , enf_walk9 ] {ai_walk(7);}; +void() enf_walk9 =[ $walk9 , enf_walk10 ] {ai_walk(7);}; +void() enf_walk10 =[ $walk10, enf_walk11 ] {ai_walk(6);}; +void() enf_walk11 =[ $walk11, enf_walk12 ] {ai_walk(6);}; +void() enf_walk12 =[ $walk12, enf_walk1 ] {ai_walk(7);}; + +void() enf_run1 =[ $run1 , enf_run2 ] { +//if (random() < 0.2) +// sound (self, CHAN_VOICE, "enforcer/idle1.wav", 1, ATTN_IDLE); +ai_run(12);}; +void() enf_run2 =[ $run2 , enf_run3 ] {ai_run(12);}; +void() enf_run3 =[ $run3 , enf_run4 ] {ai_run(11);}; +void() enf_run4 =[ $run4 , enf_run5 ] {ai_run(14);}; +void() enf_run5 =[ $run5 , enf_run6 ] {ai_run(13);}; +void() enf_run6 =[ $run6 , enf_run7 ] {ai_run(12);}; +void() enf_run7 =[ $run7 , enf_run8 ] {ai_run(14);}; +void() enf_run8 =[ $run8 , enf_run9 ] {ai_run(16);}; +void() enf_run9 =[ $run9 , enf_run10 ] {ai_run(13);}; +void() enf_run10 =[ $run10 , enf_run1 ] {ai_run(14);}; + +void() enf_pain1 =[ $pain1, enf_pain2 ] {}; +void() enf_pain2 =[ $pain2, enf_pain3 ] {}; +void() enf_pain3 =[ $pain3, enf_pain4 ] {}; +void() enf_pain4 =[ $pain4, enf_pain5 ] {}; +void() enf_pain5 =[ $pain5, enf_pain6 ] {}; +void() enf_pain6 =[ $pain6, enf_run1 ] {}; + +void() enf_paina1 =[ $paina1, enf_paina2 ] {self.nextthink = time + 0.05;}; +void() enf_paina2 =[ $paina2, enf_paina3 ] {self.nextthink = time + 0.05;}; +void() enf_paina3 =[ $paina3, enf_paina4 ] {self.nextthink = time + 0.05;}; +void() enf_paina4 =[ $paina4, enf_paina5 ] {self.nextthink = time + 0.05;}; +void() enf_paina5 =[ $paina5, enf_paina6 ] {self.nextthink = time + 0.05;}; +void() enf_paina6 =[ $paina6, enf_paina7 ] {self.nextthink = time + 0.05;}; +void() enf_paina7 =[ $paina7, enf_paina8 ] {self.nextthink = time + 0.05;}; +void() enf_paina8 =[ $paina8, enf_paina9 ] {self.nextthink = time + 0.05;}; +void() enf_paina9 =[ $paina9, enf_paina10 ] {self.nextthink = time + 0.05;}; +void() enf_paina10 =[ $paina10, enf_paina11 ] {self.nextthink = time + 0.05;}; +void() enf_paina11 =[ $paina11, enf_paina12 ] {self.nextthink = time + 0.05;}; +void() enf_paina12 =[ $paina12, enf_paina13 ] {self.nextthink = time + 0.05;}; +void() enf_paina13 =[ $paina13, enf_paina14 ] {self.nextthink = time + 0.05;}; +void() enf_paina14 =[ $paina14, enf_paina15 ] {self.nextthink = time + 0.05;}; +void() enf_paina15 =[ $paina15, enf_paina16 ] {self.nextthink = time + 0.05;}; +void() enf_paina16 =[ $paina16, enf_paina17 ] {self.nextthink = time + 0.05;}; +void() enf_paina17 =[ $paina17, enf_paina18 ] {self.nextthink = time + 0.05;}; +void() enf_paina18 =[ $paina18, enf_paina19 ] {self.nextthink = time + 0.05;}; +void() enf_paina19 =[ $paina19, enf_paina20 ] {self.nextthink = time + 0.05;}; +void() enf_paina20 =[ $paina20, enf_paina21 ] {self.nextthink = time + 0.05;}; +void() enf_paina21 =[ $paina21, enf_paina22 ] {self.nextthink = time + 0.05;}; +void() enf_paina22 =[ $paina22, enf_paina23 ] {self.nextthink = time + 0.05;}; +void() enf_paina23 =[ $paina23, enf_paina24 ] {self.nextthink = time + 0.05;}; +void() enf_paina24 =[ $paina24, enf_paina25 ] {self.nextthink = time + 0.05;}; +void() enf_paina25 =[ $paina25, enf_paina26 ] {self.nextthink = time + 0.05;}; +void() enf_paina26 =[ $paina26, enf_paina27 ] {self.nextthink = time + 0.05;}; +void() enf_paina27 =[ $paina27, enf_paina28 ] {self.nextthink = time + 0.05;}; +void() enf_paina28 =[ $paina28, enf_paina29 ] {self.nextthink = time + 0.05;}; +void() enf_paina29 =[ $paina29, enf_paina30 ] {self.nextthink = time + 0.05;}; +void() enf_paina30 =[ $paina30, enf_run1 ] {self.nextthink = time + 0.05;}; + + +void(entity attacker, float damage) enf_pain; +void() enf_atk1 =[ $attack1, enf_atk2 ] {ai_face(); self.start_attack_health = self.health;}; +void() enf_atk2 =[ $attack2, enf_atk3 ] {ai_face();}; +void() enf_atk3 =[ $attack3, enf_atk4 ] {ai_face();}; +void() enf_atk4 =[ $attack4, enf_atk5 ] {ai_face();}; +void() enf_atk5 =[ $attack5, enf_atk6 ] {ai_face();}; +void() enf_atk6 =[ $attack6, enf_atk7 ] {ai_face();}; +void() enf_atk7 =[ $attack7, enf_atk8 ] {ai_face(); + if (self.health < self.start_attack_health) { + enf_pain(self.enemy, self.start_attack_health - self.health); + } +}; +void() enf_atk8 =[ $attack8, enf_atk9 ] {ai_face();}; +void() enf_atk9 =[ $attack9, enf_atk10 ] {enforcer_fire();}; +void() enf_atk10 =[ $attack10, enf_atk11 ] {ai_face();}; +void() enf_atk11 =[ $attack11, enf_atk12 ] {ai_face();}; +void() enf_atk12 =[ $attack12, enf_run1 ] {ai_face(); +SUB_CheckRefire (enf_atk1); +}; + +void(entity attacker, float damage) enf_pain = +{ + local float r; + +/* +bprint("enforcer pain: "); +bprint(ftos(damage)); +bprint("\n"); +*/ + + r = random (); + if (self.pain_finished > time) + return; + + if (random()*200 > damage) + return; // didn't flinch + + if ((random()*10 < 8) || ((damage > 50) && (random() < 0.5))) + { + MalePainSound(2); + self.pain_finished = time + 1; + enf_paina1 (); + } + else + { + MalePainSound(2); + self.pain_finished = time + 4; + enf_paina1 (); + } +}; + +//============================================================================ + + + + +void() enf_die1 =[ $death1, enf_die2 ] {}; +void() enf_die2 =[ $death2, enf_die3 ] {}; +void() enf_die3 =[ $death3, enf_die4 ] {self.solid = SOLID_NOT;self.ammo_cells = 5;}; +void() enf_die4 =[ $death4, enf_die5 ] {}; +void() enf_die5 =[ $death5, enf_die6 ] {}; +void() enf_die6 =[ $death6, enf_die7 ] {}; +void() enf_die7 =[ $death7, enf_die8 ] {}; +void() enf_die8 =[ $death8, enf_die9 ] {}; +void() enf_die9 =[ $death9, enf_die10 ] {}; +void() enf_die10 =[ $death10, enf_die11 ] {}; +void() enf_die11 =[ $death11, enf_die12 ] {}; +void() enf_die12 =[ $death12, enf_die13 ] {}; +void() enf_die13 =[ $death13, enf_die14 ] {}; +void() enf_die14 =[ $death14, enf_die15 ] {}; +void() enf_die15 =[ $death15, enf_die16 ] {}; +void() enf_die16 =[ $death16, enf_die17 ] {}; +void() enf_die17 =[ $death17, enf_die18 ] {}; +void() enf_die18 =[ $death18, enf_die19 ] {}; +void() enf_die19 =[ $death19, enf_die20 ] {}; +void() enf_die20 =[ $death20, enf_die20 ] {}; + +void() enf_fdie1 =[ $deata1, enf_fdie2 ] {}; +void() enf_fdie2 =[ $deata2, enf_fdie3 ] {}; +void() enf_fdie3 =[ $deata3, enf_fdie4 ] +{self.solid = SOLID_NOT;self.ammo_cells = 5;}; +void() enf_fdie4 =[ $deata4, enf_fdie5 ] {}; +void() enf_fdie5 =[ $deata5, enf_fdie6 ] {}; +void() enf_fdie6 =[ $deata6, enf_fdie7 ] {}; +void() enf_fdie7 =[ $deata7, enf_fdie8 ] {}; +void() enf_fdie8 =[ $deata8, enf_fdie9 ] {}; +void() enf_fdie9 =[ $deata9, enf_fdie10 ] {}; +void() enf_fdie10 =[ $deata10, enf_fdie11 ] {}; +void() enf_fdie11 =[ $deata11, enf_fdie12 ] {}; +void() enf_fdie12 =[ $deata12, enf_fdie13 ] {}; +void() enf_fdie13 =[ $deata13, enf_fdie14 ] {}; +void() enf_fdie14 =[ $deata14, enf_fdie15 ] {}; +void() enf_fdie15 =[ $deata15, enf_fdie16 ] {}; +void() enf_fdie16 =[ $deata16, enf_fdie17 ] {}; +void() enf_fdie17 =[ $deata17, enf_fdie18 ] {}; +void() enf_fdie18 =[ $deata18, enf_fdie19 ] {}; +void() enf_fdie19 =[ $deata19, enf_fdie20 ] {}; +void() enf_fdie20 =[ $deata20, enf_fdie21 ] {}; +void() enf_fdie21 =[ $deata21, enf_fdie22 ] {}; +void() enf_fdie22 =[ $deata22, enf_fdie23 ] {}; +void() enf_fdie23 =[ $deata23, enf_fdie24 ] {}; +void() enf_fdie24 =[ $deata24, enf_fdie25 ] {}; +void() enf_fdie25 =[ $deata25, enf_fdie26 ] {}; +void() enf_fdie26 =[ $deata26, enf_fdie27 ] {}; +void() enf_fdie27 =[ $deata27, enf_fdie28 ] {}; +void() enf_fdie28 =[ $deata28, enf_fdie29 ] {}; +void() enf_fdie29 =[ $deata29, enf_fdie30 ] {}; +void() enf_fdie30 =[ $deata30, enf_fdie31 ] {}; +void() enf_fdie31 =[ $deata31, enf_fdie32 ] {}; +void() enf_fdie32 =[ $deata32, enf_fdie33 ] {}; +void() enf_fdie33 =[ $deata33, enf_fdie34 ] {}; +void() enf_fdie34 =[ $deata34, enf_fdie35 ] {}; +void() enf_fdie35 =[ $deata35, enf_fdie36 ] {}; +void() enf_fdie36 =[ $deata36, enf_fdie36 ] {}; + +void() enf_die = +{ +// regular death + MaleDeathSound(2); + if (random() >= 0.4) + enf_die1 (); + else + enf_fdie1 (); +}; + + +/*QUAKED monster_enforcer (1 0 0) (-16 -16 -24) (16 16 40) Ambush + +*/ +void() monster_enforcer = +{ + remove(self); +}; + +void() xmen_cyclops = +{ + if (deathmatch) + { + remove(self); + return; + } + precache_model2 ("progs/cyclops.mdl"); + precache_model2 ("progs/claser1.mdl"); + + // XMen matched ID sounds + precache_sound2 ("items/inv1.wav"); + precache_sound2 ("doors/airdoor2.wav"); + + // Unmatched sounds + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + + setmodel (self, "progs/cyclops.mdl"); + + setsize (self, '-16 -16 -24', '16 16 40'); + self.health = 90 + cvar("skill")*10; + + self.th_stand = enf_stand1; + self.th_walk = enf_walk1; + self.th_run = enf_run1; + self.th_pain = enf_pain; + self.th_die = enf_die; + self.th_missile = enf_atk1; + + walkmonster_start(); +}; \ No newline at end of file diff --git a/gambit.c b/gambit.c new file mode 100644 index 0000000..b522958 --- /dev/null +++ b/gambit.c @@ -0,0 +1,456 @@ +/* +============================================================================== + +Gambit + +============================================================================== +*/ + +$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9 +$frame stand10 stand11 stand12 stand13 + +$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 walk9 walk10 +$frame walk11 walk12 + +$frame run1 run2 run3 run4 run5 run6 run7 run8 + +$frame pain1 pain2 pain3 pain4 pain5 pain6 + +$frame paina1 paina2 paina3 paina4 paina5 paina6 paina7 paina8 paina9 paina10 +$frame paina11 paina12 paina13 paina14 paina15 paina16 paina17 paina18 paina19 paina20 +$frame paina21 paina22 paina23 paina24 paina25 paina26 + +$frame death1 death2 death3 death4 death5 death6 death7 death8 death9 death10 +$frame death11 death12 death13 death14 death15 death16 death17 death18 + +$frame jump1 jump2 jump3 jump4 jump5 jump6 jump7 jump8 jump9 jump10 +$frame jump11 jump12 jump13 jump14 + +$frame satta1 satta2 satta3 satta4 satta5 satta6 satta7 satta8 +$frame satta9 satta10 satta11 satta12 + +$frame xatta1 xatta2 xatta3 xatta4 xatta5 xatta6 xatta7 xatta8 xatta9 xatta10 +$frame xatta11 xatta12 xatta13 xatta14 + +$frame xattb1 xattb2 xattb3 xattb4 xattb5 xattb6 xattb7 xattb8 xattb9 xattb10 +$frame xattb11 xattb12 + +void() gambit_stand1 =[ $stand1, gambit_stand2 ] {ai_stand();}; +void() gambit_stand2 =[ $stand2, gambit_stand3 ] {ai_stand();}; +void() gambit_stand3 =[ $stand3, gambit_stand4 ] {ai_stand();}; +void() gambit_stand4 =[ $stand4, gambit_stand5 ] {ai_stand();}; +void() gambit_stand5 =[ $stand5, gambit_stand6 ] {ai_stand();}; +void() gambit_stand6 =[ $stand6, gambit_stand7 ] {ai_stand();}; +void() gambit_stand7 =[ $stand7, gambit_stand8 ] {ai_stand();}; +void() gambit_stand8 =[ $stand8, gambit_stand9 ] {ai_stand();}; +void() gambit_stand9 =[ $stand9, gambit_stand10 ] {ai_stand();}; +void() gambit_stand10 =[ $stand10, gambit_stand11 ] {ai_stand();}; +void() gambit_stand11 =[ $stand11, gambit_stand12 ] {ai_stand();}; +void() gambit_stand12 =[ $stand12, gambit_stand13 ] {ai_stand();}; +void() gambit_stand13 =[ $stand13, gambit_stand1 ] {ai_stand();}; + +//=========================================================================== + +void() gambit_walk1 =[ $walk1, gambit_walk2 ] {ai_walk(5);}; +void() gambit_walk2 =[ $walk2, gambit_walk3 ] {ai_walk(5);}; +void() gambit_walk3 =[ $walk3, gambit_walk4 ] {ai_walk(4);}; +void() gambit_walk4 =[ $walk4, gambit_walk5 ] {ai_walk(4);}; +void() gambit_walk5 =[ $walk5, gambit_walk6 ] {ai_walk(4);}; +void() gambit_walk6 =[ $walk6, gambit_walk7 ] {ai_walk(5);}; +void() gambit_walk7 =[ $walk7, gambit_walk8 ] {ai_walk(6);}; +void() gambit_walk8 =[ $walk8, gambit_walk9 ] {ai_walk(6);}; +void() gambit_walk9 =[ $walk9, gambit_walk10 ] {ai_walk(4);}; +void() gambit_walk10 =[ $walk10, gambit_walk11 ] {ai_walk(4);}; +void() gambit_walk11 =[ $walk11, gambit_walk12 ] {ai_walk(4);}; +void() gambit_walk12 =[ $walk12, gambit_walk1 ] {ai_walk(4);}; + +//=========================================================================== + +void() gambit_run1 =[ $run1, gambit_run2 ] {ai_run (20);}; +void() gambit_run2 =[ $run2, gambit_run3 ] {ai_run(25);}; +void() gambit_run3 =[ $run3, gambit_run4 ] {ai_run(18);}; +void() gambit_run4 =[ $run4, gambit_run5 ] {ai_run(16);}; +void() gambit_run5 =[ $run5, gambit_run6 ] {ai_run(14);}; +void() gambit_run6 =[ $run6, gambit_run7 ] {ai_run(25);}; +void() gambit_run7 =[ $run7, gambit_run8 ] {ai_run(21);}; +void() gambit_run8 =[ $run8, gambit_run1 ] {ai_run(13);}; + +void() gambit_jump1; +void() gambit_jump12; +void() GambitJumpTouch = +{ + if (!checkbottom(self)) + { + if (self.flags & FL_ONGROUND) + { // jump randomly to not get hung up + self.touch = SUB_Null; + self.think = gambit_jump1; + self.nextthink = time + 0.1; + } + return; // not on ground yet + } + + self.touch = SUB_Null; + self.think = gambit_jump12; + self.nextthink = time + 0.1; +}; + +void() gambit_jump1 =[ $jump1, gambit_jump2 ] +{ + makevectors(self.angles); + self.velocity = v_forward * 300; + self.velocity_z = 200; + self.flags = self.flags - (self.flags & FL_ONGROUND); + setorigin(self, self.origin + '0 0 1'); + + self.touch = GambitJumpTouch; + + self.nextthink = time + 0.05; +}; +void() gambit_jump2 =[ $jump2, gambit_jump3 ] {self.nextthink = time + 0.05;}; +void() gambit_jump3 =[ $jump3, gambit_jump4 ] {self.nextthink = time + 0.05;}; +void() gambit_jump4 =[ $jump4, gambit_jump5 ] {self.nextthink = time + 0.05;}; +void() gambit_jump5 =[ $jump5, gambit_jump6 ] {self.nextthink = time + 0.05;}; +void() gambit_jump6 =[ $jump6, gambit_jump7 ] {self.nextthink = time + 0.05;}; +void() gambit_jump7 =[ $jump7, gambit_jump8 ] {self.nextthink = time + 0.05;}; +void() gambit_jump8 =[ $jump8, gambit_jump9 ] {self.nextthink = time + 0.05;}; +void() gambit_jump9 =[ $jump9, gambit_jump10 ] {self.nextthink = time + 0.05;}; +void() gambit_jump10 =[ $jump10, gambit_jump11 ] {self.nextthink = time + 0.05;}; +void() gambit_jump11 =[ $jump11, gambit_jump11 ] {self.nextthink = time + 0.05;}; // stay on this frame until landing +void() gambit_jump12 =[ $jump12, gambit_jump13 ] {ai_forward(10);}; +void() gambit_jump13 =[ $jump13, gambit_jump14 ] {ai_forward(6);}; +void() gambit_jump14 =[ $jump14, gambit_run1 ] {}; + +//============================================================================ + +void() gambit_pain1 =[ $pain1, gambit_pain2 ] {}; +void() gambit_pain2 =[ $pain2, gambit_pain3 ] {}; +void() gambit_pain3 =[ $pain3, gambit_pain4 ] {}; +void() gambit_pain4 =[ $pain4, gambit_pain5 ] {}; +void() gambit_pain5 =[ $pain5, gambit_pain6 ] {}; +void() gambit_pain6 =[ $pain6, gambit_run1 ] {}; + +void() gambit_paina1 =[ $paina1, gambit_paina2 ] {}; +void() gambit_paina2 =[ $paina2, gambit_paina3 ] {}; +void() gambit_paina3 =[ $paina3, gambit_paina4 ] {}; +void() gambit_paina4 =[ $paina4, gambit_paina5 ] {}; +void() gambit_paina5 =[ $paina5, gambit_paina6 ] {}; +void() gambit_paina6 =[ $paina6, gambit_paina7 ] {}; +void() gambit_paina7 =[ $paina7, gambit_paina8 ] {}; +void() gambit_paina8 =[ $paina8, gambit_paina9 ] {}; +void() gambit_paina9 =[ $paina9, gambit_paina10 ] {}; +void() gambit_paina10 =[ $paina10, gambit_paina11 ] {}; +void() gambit_paina11 =[ $paina11, gambit_paina12 ] {}; +void() gambit_paina12 =[ $paina12, gambit_paina13 ] {}; +void() gambit_paina13 =[ $paina13, gambit_paina14 ] {}; +void() gambit_paina14 =[ $paina14, gambit_paina15 ] {}; +void() gambit_paina15 =[ $paina15, gambit_paina16 ] {}; +void() gambit_paina16 =[ $paina16, gambit_paina17 ] {}; +void() gambit_paina17 =[ $paina17, gambit_paina18 ] {}; +void() gambit_paina18 =[ $paina18, gambit_paina19 ] {}; +void() gambit_paina19 =[ $paina19, gambit_paina20 ] {}; +void() gambit_paina20 =[ $paina20, gambit_paina21 ] {}; +void() gambit_paina21 =[ $paina21, gambit_paina22 ] {}; +void() gambit_paina22 =[ $paina22, gambit_paina23 ] {}; +void() gambit_paina23 =[ $paina23, gambit_paina24 ] {}; +void() gambit_paina24 =[ $paina24, gambit_paina25 ] {}; +void() gambit_paina25 =[ $paina25, gambit_paina26 ] {}; +void() gambit_paina26 =[ $paina26, gambit_run1 ] {}; + +//============================================================================ + +void() gambit_die1 =[ $death1, gambit_die2 ] {}; +void() gambit_die2 =[ $death2, gambit_die3 ] {}; +void() gambit_die3 =[ $death3, gambit_die4 ] {self.solid = SOLID_NOT;}; +void() gambit_die4 =[ $death4, gambit_die5 ] {}; +void() gambit_die5 =[ $death5, gambit_die6 ] {}; +void() gambit_die6 =[ $death6, gambit_die7 ] {}; +void() gambit_die7 =[ $death7, gambit_die8 ] {}; +void() gambit_die8 =[ $death8, gambit_die9 ] {}; +void() gambit_die9 =[ $death9, gambit_die10 ] {}; +void() gambit_die10 =[ $death10, gambit_die11 ] {}; +void() gambit_die11 =[ $death11, gambit_die12 ] {}; +void() gambit_die12 =[ $death12, gambit_die13 ] {}; +void() gambit_die13 =[ $death13, gambit_die14 ] {}; +void() gambit_die14 =[ $death14, gambit_die15 ] {}; +void() gambit_die15 =[ $death15, gambit_die16 ] {}; +void() gambit_die16 =[ $death16, gambit_die17 ] {}; +void() gambit_die17 =[ $death17, gambit_die18 ] {}; +void() gambit_die18 =[ $death18, gambit_die18 ] {}; + +void() gambit_die = +{ + MaleDeathSound(2); + gambit_die1 (); +}; + +//============================================================================ + + +void(entity attacker, float damage) gambit_pain = +{ + if (self.pain_finished > time) + return; + + MalePainSound(2); + + if (time - self.pain_finished > 8) + { // always go into pain frame if it has been a while + gambit_pain1 (); + self.pain_finished = time + 3; + return; + } + + if (random() < 0.75) { + self.pain_finished = time + 3; + gambit_pain1 (); + } + else { + self.pain_finished = time + 5; + gambit_paina1 (); + } +}; + +//============================================================================ + +void() GambitStrike = +{ + local vector vect; + local float damg; + + if (vlen(self.enemy.origin - self.origin) > 64) + return; + + if (!infront(self.enemy)) + return; + + // hurt enemy + damg = 15 + random() * 5; + T_Damage(self.enemy, self, self, damg); +}; + +void() gambit_satta1 =[ $satta1, gambit_satta2 ] {ai_charge(4);}; +void() gambit_satta2 =[ $satta2, gambit_satta3 ] {ai_charge(8);}; +void() gambit_satta3 =[ $satta3, gambit_satta4 ] {ai_charge(8);}; +void() gambit_satta4 =[ $satta4, gambit_satta5 ] {ai_charge(8);}; +void() gambit_satta5 =[ $satta5, gambit_satta6 ] {ai_charge(4);}; +void() gambit_satta6 =[ $satta6, gambit_satta7 ] {}; +void() gambit_satta7 =[ $satta7, gambit_satta8 ] {GambitStrike();}; +void() gambit_satta8 =[ $satta8, gambit_satta9 ] {}; +void() gambit_satta9 =[ $satta9, gambit_satta10 ] {ai_forward(4);}; +void() gambit_satta10 =[ $satta10, gambit_satta11 ] {ai_forward(8);}; +void() gambit_satta11 =[ $satta11, gambit_satta12 ] {ai_forward(8);}; +void() gambit_satta12 =[ $satta12, gambit_run1 ] {ai_forward(4);}; + +void() gambit_melee = +{ + sound (self, CHAN_WEAPON, "generic/swing1.wav", 1, ATTN_NORM); + gambit_satta1 (); +}; + +//============================================================================ + +void(float heading_ofs, float zofs) GambitCard = +{ + local vector newangle, targ_vect, ofs; + local entity missile; + + targ_vect = normalize(self.enemy.origin - self.origin); + newangle = vectoangles(targ_vect); + newangle_y = anglemod(newangle_y + heading_ofs); + newangle_x = -1 * newangle_x; + + makevectors(newangle); + + ofs = '0 0 0'; + ofs_z = zofs; + launch_spike (self.origin + ofs + v_forward*14, v_forward); + newmis.classname = "gambit_card"; + setmodel (newmis, "progs/card.mdl"); + setsize(newmis, '0 0 0', '0 0 0'); +}; + +void() gambit_xatta1 =[ $xatta1, gambit_xatta2 ] {ai_forward(4);}; +void() gambit_xatta2 =[ $xatta2, gambit_xatta3 ] {ai_forward(8);}; +void() gambit_xatta3 =[ $xatta3, gambit_xatta4 ] {ai_forward(8);}; +void() gambit_xatta4 =[ $xatta4, gambit_xatta5 ] {ai_forward(8);ai_face();}; +void() gambit_xatta5 =[ $xatta5, gambit_xatta6 ] {ai_forward(10);ai_face();}; +void() gambit_xatta6 =[ $xatta6, gambit_xatta7 ] {ai_forward(10);ai_face();}; +void() gambit_xatta7 =[ $xatta7, gambit_xatta8 ] {ai_forward(10);ai_face();}; +void() gambit_xatta8 =[ $xatta8, gambit_xatta9 ] {ai_forward(8);ai_face();}; +void() gambit_xatta9 =[ $xatta9, gambit_xatta10 ] {ai_forward(8);sound (self, CHAN_WEAPON, "boss1/throw.wav", 1, ATTN_NORM);GambitCard(-5, 16);}; +void() gambit_xatta10 =[ $xatta10, gambit_xatta11 ] {ai_forward(8);GambitCard( 0, 16);}; +void() gambit_xatta11 =[ $xatta11, gambit_xatta12 ] {ai_forward(8);GambitCard( 5, 16);}; +void() gambit_xatta12 =[ $xatta12, gambit_xatta13 ] {ai_forward(6);}; +void() gambit_xatta13 =[ $xatta13, gambit_xatta14 ] {ai_forward(4);}; +void() gambit_xatta14 =[ $xatta14, gambit_run1 ] {ai_forward(2);}; + +void() gambit_xattb1 =[ $xattb1, gambit_xattb2 ] {ai_forward(-1);}; +void() gambit_xattb2 =[ $xattb2, gambit_xattb3 ] {ai_forward(-1);sound (self, CHAN_WEAPON, "boss1/throw.wav", 1, ATTN_NORM);GambitCard(-6, 4);}; +void() gambit_xattb3 =[ $xattb3, gambit_xattb4 ] {ai_forward(-3);GambitCard(-3, 4);}; +void() gambit_xattb4 =[ $xattb4, gambit_xattb5 ] {ai_forward(-8);GambitCard( 0, 4);}; +void() gambit_xattb5 =[ $xattb5, gambit_xattb6 ] {ai_forward(-10);GambitCard( 3, 4);}; +void() gambit_xattb6 =[ $xattb6, gambit_xattb7 ] {ai_forward(-10);GambitCard( 6, 4);}; +void() gambit_xattb7 =[ $xattb7, gambit_xattb8 ] {ai_forward(-10);}; +void() gambit_xattb8 =[ $xattb8, gambit_xattb9 ] {ai_forward(-8);}; +void() gambit_xattb9 =[ $xattb9, gambit_xattb10 ] {ai_forward(-8);}; +void() gambit_xattb10 =[ $xattb10, gambit_xattb11 ] {ai_forward(-8);}; +void() gambit_xattb11 =[ $xattb11, gambit_xattb12 ] {ai_forward(-4);}; +void() gambit_xattb12 =[ $xattb12, gambit_run1 ] {}; + +void() gambit_special = +{ + if (self.last_special > (time - 2)) + return; + + self.last_special = time; + + // check head-room + traceline(self.origin, self.origin + '0 0 54', TRUE, self); + if (trace_fraction < 1) + gambit_xatta1(); + else { + if (random() < 0.5) + gambit_xatta1(); + else + gambit_xattb1(); + } + +}; + +//============================================================================ + +float() CheckGambitMelee = +{ + local vector vect; + + if ((enemy_range == RANGE_MELEE) && (vlen(self.origin - self.enemy.origin) < 96)) + { // FIXME: check canreach + self.attack_state = AS_MELEE; + return TRUE; + } + return FALSE; +}; + +/* +============== +CheckGambitSpecial + +============== +*/ +float() CheckGambitSpecial = +{ + local vector dist, p1, p2, vect; + local float d; + + if (self.last_special > (time - 4)) { + makevectors(self.angles); + + if (random() < 0.1) { // jump if looking at player + vect = normalize(self.enemy.origin - self.origin); + if (vlen(v_forward - vect) < 0.5) + gambit_jump1(); + } + + return FALSE; + } + + // now, check line of sight (between p1 and p2) + p1 = self.origin; + p2 = self.enemy.origin; + + traceline(p1, p2, FALSE, self); + + if ((trace_fraction < 1) && (trace_ent != self.enemy)) + return FALSE; + + dist = self.enemy.origin - self.origin; + dist_z = 0; + + d = vlen(dist); + + if (d < 100) + return FALSE; + + if (d > 312) + return FALSE; + + return TRUE; +}; + +float() GambitCheckAttack = +{ + local vector vec; + +// if close enough for slashing, go for it + if (CheckGambitMelee ()) + { + self.attack_state = AS_MELEE; + return TRUE; + } + + if (CheckGambitSpecial ()) + { + self.attack_state = AS_MISSILE; + return TRUE; + } + + return FALSE; +}; + +//============================================================================ + +/*QUAKED monster_hell_knight (1 0 0) (-16 -16 -24) (16 16 40) Ambush +*/ +void() monster_hell_knight = +{ + remove(self); +}; + +void() xmen_gambit = +{ + if (deathmatch) + { + remove(self); + return; + } + precache_model2 ("progs/gambit1.mdl"); + precache_model2 ("progs/card.mdl"); + + // Xmen Sounds: matched ID sounds + precache_sound ("boss1/throw.wav"); + + precache_sound ("generic/swing1.wav"); + +/* + // Unmatched HKnight sounds + precache_sound2 ("hknight/attack1.wav"); + precache_sound2 ("hknight/death1.wav"); + precache_sound2 ("hknight/pain1.wav"); + precache_sound2 ("hknight/sight1.wav"); + precache_sound ("hknight/hit.wav"); // used by C code, so don't sound2 + precache_sound2 ("hknight/idle.wav"); + precache_sound2 ("hknight/grunt.wav"); + + precache_sound ("knight/sword1.wav"); + precache_sound ("knight/sword2.wav"); +*/ + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + + setmodel (self, "progs/gambit1.mdl"); + + setsize (self, '-16 -16 -24', '16 16 40'); + self.health = 120 + cvar("skill")*10; + + self.th_stand = gambit_stand1; + self.th_walk = gambit_walk1; + self.th_run = gambit_run1; + self.th_melee = gambit_melee; + self.th_missile = gambit_special; + self.th_pain = gambit_pain; + self.th_die = gambit_die; + + walkmonster_start (); +}; diff --git a/geometry.c b/geometry.c new file mode 100644 index 0000000..a9b3888 --- /dev/null +++ b/geometry.c @@ -0,0 +1,72 @@ +// Just a handy proc for finding the angle between two vectors +// v1 and v2 must be in range 0 - 360 +// answer is heading (Y) angle going from v1 to v2 +float(float a1, float a2) angle_diff = +{ + if (a2 > a1) { + if ((a2 - a1) > 180) { + return (a1 - (a2 - 360)); + } + else { + return (a1 - a2); + } + } + else { + if ((a1 - a2) > 180) { + return (a1 - (a2 + 360)); + } + else { + return (a1 - a2); + } + } +}; + +// Calculates and returns the reflection vector of the intersection +// of the vector "dir" with a "wall_normal" at position "org" +vector(vector org, vector dir, vector wall_normal) GetReflectionVect = +{ + local vector first_wallpoint, second_wallpoint, first_linepoint, second_linepoint; + local float wall_dist; + + first_linepoint = org - dir*4; + traceline(first_linepoint, first_linepoint - wall_normal*8, TRUE, world); + + first_wallpoint = trace_endpos; + + second_wallpoint = org - (first_wallpoint - org); + second_linepoint = second_wallpoint + wall_normal * 4; + + second_linepoint = normalize(second_linepoint - org); + + return second_linepoint; +}; + +float(float s_angle, float e_angle, float rate) MoveToAngle = +{ + local float result; + + if ((s_angle > e_angle) && + ((s_angle - e_angle) > 180)) { + e_angle = e_angle + 360; + } + else if ((e_angle > s_angle) && + ((e_angle - s_angle) > 180)) { + s_angle = s_angle + 360; + } + + if (s_angle > e_angle) { + result = s_angle - rate*frametime; + + if (result < e_angle) result = e_angle; + } + else { + result = s_angle + rate*frametime; + + if (result > e_angle) result = e_angle; + } + + if (result >= 360) result = result - 360; + if (result < 0) result = result + 360; + + return result; +}; diff --git a/phoenix.c b/phoenix.c new file mode 100644 index 0000000..22f544d --- /dev/null +++ b/phoenix.c @@ -0,0 +1,502 @@ +/*========================================================================== + + phoenix + +==========================================================================*/ + +$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9 +$frame stand10 stand11 stand12 stand13 + +$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 walk9 walk10 +$frame walk11 walk12 + +$frame run1 run2 run3 run4 run5 run6 run7 run8 + +$frame pain1 pain2 pain3 pain4 pain5 pain6 + +$frame paina1 paina2 paina3 paina4 paina5 paina6 paina7 paina8 paina9 paina10 +$frame paina11 paina12 paina13 paina14 paina15 paina16 paina17 paina18 paina19 paina20 +$frame paina21 paina22 paina23 paina24 + +$frame death1 death2 death3 death4 death5 death6 death7 death8 death9 death10 +$frame death11 death12 death13 death14 death15 death16 death17 death18 death19 death20 + +$frame guard1 guard2 guard3 guard4 guard5 guard6 guard7 guard8 guard9 +$frame guard10 guard11 guard12 + +$frame xatta1 xatta2 xatta3 xatta4 xatta5 xatta6 xatta7 xatta8 xatta9 xatta10 +$frame xatta11 xatta12 + +$frame xattb1 xattb2 xattb3 xattb4 xattb5 xattb6 xattb7 xattb8 xattb9 xattb10 +$frame xattb11 xattb12 + +$frame xattc1 xattc2 xattc3 xattc4 xattc5 xattc6 xattc7 xattc8 xattc9 xattc10 +$frame xattc11 xattc12 xattc13 xattc14 xattc15 xattc16 xattc17 + +void() phoenix_stand1 = [ $stand1, phoenix_stand2 ] {ai_stand();}; +void() phoenix_stand2 = [ $stand2, phoenix_stand3 ] {ai_stand();}; +void() phoenix_stand3 = [ $stand3, phoenix_stand4 ] {ai_stand();}; +void() phoenix_stand4 = [ $stand4, phoenix_stand5 ] {ai_stand();}; +void() phoenix_stand5 = [ $stand5, phoenix_stand6 ] {ai_stand();}; +void() phoenix_stand6 = [ $stand6, phoenix_stand7 ] {ai_stand();}; +void() phoenix_stand7 = [ $stand7, phoenix_stand8 ] {ai_stand();}; +void() phoenix_stand8 = [ $stand8, phoenix_stand9 ] {ai_stand();}; +void() phoenix_stand9 = [ $stand9, phoenix_stand10 ] {ai_stand();}; +void() phoenix_stand10 = [ $stand10, phoenix_stand11 ] {ai_stand();}; +void() phoenix_stand11 = [ $stand11, phoenix_stand12 ] {ai_stand();}; +void() phoenix_stand12 = [ $stand12, phoenix_stand13 ] {ai_stand();}; +void() phoenix_stand13 = [ $stand13, phoenix_stand1 ] {ai_stand();}; + +void() phoenix_walk1 = [ $walk1, phoenix_walk2 ] {ai_walk(5);}; +void() phoenix_walk2 = [ $walk2, phoenix_walk3 ] {ai_walk(4);}; +void() phoenix_walk3 = [ $walk3, phoenix_walk4 ] {ai_walk(4);}; +void() phoenix_walk4 = [ $walk4, phoenix_walk5 ] {ai_walk(5);}; +void() phoenix_walk5 = [ $walk5, phoenix_walk6 ] {ai_walk(5);}; +void() phoenix_walk6 = [ $walk6, phoenix_walk7 ] {ai_walk(6);}; +void() phoenix_walk7 = [ $walk7, phoenix_walk8 ] {ai_walk(6);}; +void() phoenix_walk8 = [ $walk8, phoenix_walk9 ] {ai_walk(4);}; +void() phoenix_walk9 = [ $walk9, phoenix_walk10 ] {ai_walk(4);}; +void() phoenix_walk10 = [ $walk10, phoenix_walk11 ] {ai_walk(5);}; +void() phoenix_walk11 = [ $walk11, phoenix_walk12 ] {ai_walk(5);}; +void() phoenix_walk12 = [ $walk12, phoenix_walk1 ] {ai_walk(6);}; + +void() phoenix_runwalk1; +void() phoenix_run1 = [ $run1, phoenix_run2 ] +{ + if (vlen(self.enemy.origin - self.origin) < 196) { + phoenix_runwalk1(); + return; + } + + ai_run(19); +}; +void() phoenix_run2 = [ $run2, phoenix_run3 ] {ai_run(19);}; +void() phoenix_run3 = [ $run3, phoenix_run4 ] {ai_run(18);}; +void() phoenix_run4 = [ $run4, phoenix_run5 ] {ai_run(18);}; +void() phoenix_run5 = [ $run5, phoenix_run6 ] {ai_run(19);}; +void() phoenix_run6 = [ $run6, phoenix_run7 ] {ai_run(19);}; +void() phoenix_run7 = [ $run7, phoenix_run8 ] {ai_run(18);}; +void() phoenix_run8 = [ $run8, phoenix_run1 ] {ai_run(18);}; + +void() phoenix_runwalk1 = [ $walk1, phoenix_runwalk2 ] +{ + if (vlen(self.enemy.origin - self.origin) > 256) { + phoenix_run1(); + return; + } + + ai_run(4); +}; +void() phoenix_runwalk2 = [ $walk2, phoenix_runwalk3 ] {ai_run(4);}; +void() phoenix_runwalk3 = [ $walk3, phoenix_runwalk4 ] {ai_run(3);}; +void() phoenix_runwalk4 = [ $walk4, phoenix_runwalk5 ] {ai_run(4);}; +void() phoenix_runwalk5 = [ $walk5, phoenix_runwalk6 ] {ai_run(4);}; +void() phoenix_runwalk6 = [ $walk6, phoenix_runwalk7 ] {ai_run(3);}; +void() phoenix_runwalk7 = [ $walk7, phoenix_runwalk8 ] {ai_run(3);}; +void() phoenix_runwalk8 = [ $walk8, phoenix_runwalk9 ] {ai_run(4);}; +void() phoenix_runwalk9 = [ $walk9, phoenix_runwalk10 ] {ai_run(4);}; +void() phoenix_runwalk10 = [ $walk10, phoenix_runwalk11 ] {ai_run(3);}; +void() phoenix_runwalk11 = [ $walk11, phoenix_runwalk12 ] {ai_run(4);}; +void() phoenix_runwalk12 = [ $walk12, phoenix_runwalk1 ] {ai_run(4);}; + +//============================================================================ + +void() phoenix_pain1 = [ $pain1, phoenix_pain2 ] {}; +void() phoenix_pain2 = [ $pain2, phoenix_pain3 ] {}; +void() phoenix_pain3 = [ $pain3, phoenix_pain4 ] {}; +void() phoenix_pain4 = [ $pain4, phoenix_pain5 ] {}; +void() phoenix_pain5 = [ $pain5, phoenix_pain6 ] {}; +void() phoenix_pain6 = [ $pain6, phoenix_run1 ] {}; + +void() phoenix_paina1 = [ $paina1, phoenix_paina2 ] {}; +void() phoenix_paina2 = [ $paina2, phoenix_paina3 ] {}; +void() phoenix_paina3 = [ $paina3, phoenix_paina4 ] {}; +void() phoenix_paina4 = [ $paina4, phoenix_paina5 ] {}; +void() phoenix_paina5 = [ $paina5, phoenix_paina6 ] {}; +void() phoenix_paina6 = [ $paina6, phoenix_paina7 ] {}; +void() phoenix_paina7 = [ $paina7, phoenix_paina8 ] {}; +void() phoenix_paina8 = [ $paina8, phoenix_paina9 ] {}; +void() phoenix_paina9 = [ $paina9, phoenix_paina10 ] {}; +void() phoenix_paina10 = [ $paina10, phoenix_paina11 ] {}; +void() phoenix_paina11 = [ $paina11, phoenix_paina12 ] {}; +void() phoenix_paina12 = [ $paina12, phoenix_paina13 ] {}; +void() phoenix_paina13 = [ $paina13, phoenix_paina14 ] {}; +void() phoenix_paina14 = [ $paina14, phoenix_paina15 ] {}; +void() phoenix_paina15 = [ $paina15, phoenix_paina16 ] {}; +void() phoenix_paina16 = [ $paina16, phoenix_paina17 ] {}; +void() phoenix_paina17 = [ $paina17, phoenix_paina18 ] {}; +void() phoenix_paina18 = [ $paina18, phoenix_paina19 ] {}; +void() phoenix_paina19 = [ $paina19, phoenix_paina20 ] {}; +void() phoenix_paina20 = [ $paina20, phoenix_paina21 ] {}; +void() phoenix_paina21 = [ $paina21, phoenix_paina22 ] {}; +void() phoenix_paina22 = [ $paina22, phoenix_paina23 ] {}; +void() phoenix_paina23 = [ $paina23, phoenix_paina24 ] {}; +void() phoenix_paina24 = [ $paina24, phoenix_run1 ] {}; + +void(entity attacker, float damage) PhoenixPain = +{ + if (self.pain_finished > time) + return; + + if (self.health <= 0) + return; + + FemalePainSound(); + + if ((damage > 10) && (random() < 0.4)) { + sound(self, CHAN_AUTO, "items/protect3.wav", 1, ATTN_NORM); + self.pain_finished = time + 2; + phoenix_paina1(); + } + else { + self.pain_finished = time + 5; + phoenix_pain1(); + } +}; + +//============================================================================ + +void() phoenix_death1 = [ $death1, phoenix_death2 ] {}; +void() phoenix_death2 = [ $death2, phoenix_death3 ] {}; +void() phoenix_death3 = [ $death3, phoenix_death4 ] {self.solid = SOLID_NOT;}; +void() phoenix_death4 = [ $death4, phoenix_death5 ] {}; +void() phoenix_death5 = [ $death5, phoenix_death6 ] {}; +void() phoenix_death6 = [ $death6, phoenix_death7 ] {}; +void() phoenix_death7 = [ $death7, phoenix_death8 ] {}; +void() phoenix_death8 = [ $death8, phoenix_death9 ] {}; +void() phoenix_death9 = [ $death9, phoenix_death10 ] {}; +void() phoenix_death10 = [ $death10, phoenix_death11 ] {}; +void() phoenix_death11 = [ $death11, phoenix_death12 ] {}; +void() phoenix_death12 = [ $death12, phoenix_death13 ] {}; +void() phoenix_death13 = [ $death13, phoenix_death14 ] {}; +void() phoenix_death14 = [ $death14, phoenix_death15 ] {}; +void() phoenix_death15 = [ $death15, phoenix_death16 ] {}; +void() phoenix_death16 = [ $death16, phoenix_death17 ] {}; +void() phoenix_death17 = [ $death17, phoenix_death18 ] {}; +void() phoenix_death18 = [ $death18, phoenix_death19 ] {}; +void() phoenix_death19 = [ $death19, phoenix_death20 ] {}; +void() phoenix_death20 = [ $death20, phoenix_death20 ] {if (self.angles_x != 0) AngelPitch();}; + +void() PhoenixDie = +{ + FemaleDeathSound(); + + phoenix_death1(); +}; + +//============================================================================ + +void() phoenix_guard1 = [ $guard1, phoenix_guard2 ] {self.nextthink = time + 0.05;}; +void() phoenix_guard2 = [ $guard2, phoenix_guard3 ] {self.nextthink = time + 0.05;}; +void() phoenix_guard3 = [ $guard3, phoenix_guard4 ] {self.nextthink = time + 0.05;}; +void() phoenix_guard4 = [ $guard4, phoenix_guard5 ] { +sound(self, CHAN_BODY, "items/protect3.wav", 1, ATTN_NORM); +self.flags = self.flags | FL_GODMODE;}; +void() phoenix_guard5 = [ $guard5, phoenix_guard6 ] {}; +void() phoenix_guard6 = [ $guard6, phoenix_guard7 ] {}; +void() phoenix_guard7 = [ $guard7, phoenix_guard8 ] {}; +void() phoenix_guard8 = [ $guard8, phoenix_guard9 ] {}; +void() phoenix_guard9 = [ $guard9, phoenix_guard10 ] {}; +void() phoenix_guard10 = [ $guard10, phoenix_guard11 ] {}; +void() phoenix_guard11 = [ $guard11, phoenix_guard12 ] {}; +void() phoenix_guard12 = [ $guard12, phoenix_run1 ] {self.flags = self.flags - FL_GODMODE;}; + +//============================================================================ + +void() PhoenixFireHoming = +{ + local entity missile, missile_enemy; + local vector dir; + + missile = spawn (); + missile.classname = "phoenix_blast"; + missile.attack_finished = time + 3; + missile.owner = self; + missile.movetype = MOVETYPE_FLYMISSILE; + missile.solid = SOLID_BBOX; + + missile.enemy = self.enemy; + missile.think = GuidedRocketThink; + missile.last_guided_search = time; + missile.nextthink = time + 0.05; + + // set missile speed + makevectors(self.angles); + + missile.velocity = v_forward; + missile.velocity = missile.velocity * 800; + missile.angles = vectoangles(missile.velocity); + + missile.touch = T_GuidedMissileTouch; + + missile.avelocity_z = 300; + + setmodel (missile, "progs/psyblast.mdl"); + setsize (missile, '0 0 0', '0 0 0'); + setorigin (missile, self.origin + dir*8 + '0 0 12'); + +}; + +void() phoenix_xatta1 = [ $xatta1, phoenix_xatta2 ] {ai_face();}; +void() phoenix_xatta2 = [ $xatta2, phoenix_xatta3 ] {ai_face();}; +void() phoenix_xatta3 = [ $xatta3, phoenix_xatta4 ] {ai_face();}; +void() phoenix_xatta4 = [ $xatta4, phoenix_xatta5 ] {ai_face();}; +void() phoenix_xatta5 = [ $xatta5, phoenix_xatta6 ] {PhoenixFireHoming();}; +void() phoenix_xatta6 = [ $xatta6, phoenix_xatta7 ] {}; +void() phoenix_xatta7 = [ $xatta7, phoenix_xatta8 ] {}; +void() phoenix_xatta8 = [ $xatta8, phoenix_xatta9 ] {}; +void() phoenix_xatta9 = [ $xatta9, phoenix_xatta10 ] {}; +void() phoenix_xatta10 = [ $xatta10, phoenix_xatta11 ] {}; +void() phoenix_xatta11 = [ $xatta11, phoenix_xatta12 ] {}; +void() phoenix_xatta12 = [ $xatta12, phoenix_run1 ] {}; + +void() phoenix_xattb1 = [ $xattb1, phoenix_xattb2 ] {ai_face();}; +void() phoenix_xattb2 = [ $xattb2, phoenix_xattb3 ] {ai_face();}; +void() phoenix_xattb3 = [ $xattb3, phoenix_xattb4 ] {ai_face();}; +void() phoenix_xattb4 = [ $xattb4, phoenix_xattb5 ] {ai_face();}; +void() phoenix_xattb5 = [ $xattb5, phoenix_xattb6 ] {ai_face();}; +void() phoenix_xattb6 = [ $xattb6, phoenix_xattb7 ] {ai_face();}; +void() phoenix_xattb7 = [ $xattb7, phoenix_xattb8 ] {ai_face();}; +void() phoenix_xattb8 = [ $xattb8, phoenix_xattb9 ] +{ + // hurt enemy + T_Damage(self.enemy, self, self, 10); + self.enemy.punchangle_x = -8; + + self.last_special2 = time; +}; +void() phoenix_xattb9 = [ $xattb9, phoenix_xattb10 ] {}; +void() phoenix_xattb10 = [ $xattb10, phoenix_xattb11 ] {}; +void() phoenix_xattb11 = [ $xattb11, phoenix_xattb12 ] {}; +void() phoenix_xattb12 = [ $xattb12, phoenix_run1 ] {}; + +void() TractorParticleThink = +{ + local float dist, r; + local vector vect; + + if (!(self.owner.enemy.x_flags & X_TRACTOR_BEAM_HOLD)) { + setmodel(self, ""); + self.nextthink = -1; + return; + } + + vect = self.owner.enemy.origin - self.owner.origin; + dist = vlen(vect); + vect = normalize(vect); + + self.t_length = self.t_length + self.speed * (time - self.last_special); + if (self.t_length >= dist - 48) + self.t_length = 0; + + if (self == self.owner.flame_ent2) // rotate in other direction + self.angles_z = anglemod(self.angles_z - self.speed * (time - self.last_special)); + else + self.angles_z = anglemod(self.angles_z + self.speed * (time - self.last_special)); + + self.z_ofs = self.z_ofs + self.z_ofs_vel; + if ((self.z_ofs <= -30) || (self.z_ofs >= 30)) { + self.z_ofs = -1 * self.z_ofs; + } + + + makevectors(self.angles); + setorigin(self, self.owner.origin + vect * self.t_length + v_up * self.z_ofs); + + // random colored particle +// r = random() * 3.9; +// r = floor(r); + particle(self.origin, vect * 10, 241, 10 + r*5); + + self.last_special = time; + self.nextthink = time + 0.05; +}; + +void() PhoenixStartBeam = +{ + // if player is already in a beam, abort attack + if (self.enemy.x_flags & X_TRACTOR_BEAM_HOLD) { + self.th_run(); + return; + } + + self.flags = self.flags | FL_GODMODE; + + sound(self.enemy, CHAN_WEAPON, "items/damage3.wav", 1, ATTN_NORM); + + self.last_special = time; + + self.enemy.x_flags = self.enemy.x_flags | X_TRACTOR_BEAM_HOLD; + self.enemy.tractor_vel = '0 0 10'; + setorigin(self.enemy, self.enemy.origin + '0 0 1'); + self.enemy.flags = self.enemy.flags - (self.enemy.flags & FL_ONGROUND); + + self.start_tractor_time = time; + self.enemy.start_tractor_time = time; + + setmodel(self.flame_ent1, "progs/beampart.mdl"); + setmodel(self.flame_ent2, "progs/beampart.mdl"); + setmodel(self.flame_ent3, "progs/beampart.mdl"); + + setorigin(self.flame_ent1, self.origin); + setorigin(self.flame_ent2, self.origin); + setorigin(self.flame_ent3, self.origin); + + self.flame_ent1.nextthink = time + 0.05; + self.flame_ent2.nextthink = time + 0.05; + self.flame_ent3.nextthink = time + 0.05; + + // speed to travel + self.flame_ent1.speed = 800; + self.flame_ent2.speed = 400; + self.flame_ent3.speed = 200; + + // distance from Phoenix + self.flame_ent1.t_length = 0; + self.flame_ent2.t_length = 0; + self.flame_ent3.t_length = 0; + + // distance from center of tractor beam + self.flame_ent1.z_ofs = 10; + self.flame_ent2.z_ofs = 5; + self.flame_ent3.z_ofs = 0; + + // 1 = travelling away from center, -1 = travelling towards center + self.flame_ent1.z_ofs_vel = -2; + self.flame_ent2.z_ofs_vel = 2.5; + self.flame_ent3.z_ofs_vel = 1; +}; + +void() phoenix_xattc9; +void() PhoenixBeamThink = +{ + self.enemy.tractor_vel_z = self.enemy.tractor_vel_z + 50; + if (self.enemy.tractor_vel_z > 100) + self.enemy.tractor_vel_z = 100; + +/* + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_LIGHTNING2); + WriteEntity (MSG_BROADCAST, self.enemy); + WriteCoord (MSG_BROADCAST, self.enemy.origin_x); + WriteCoord (MSG_BROADCAST, self.enemy.origin_y); + WriteCoord (MSG_BROADCAST, self.enemy.origin_z); + WriteCoord (MSG_BROADCAST, self.origin_x); + WriteCoord (MSG_BROADCAST, self.origin_y); + WriteCoord (MSG_BROADCAST, self.origin_z); +*/ + + traceline(self.origin, self.enemy.origin, TRUE, self); + + if ((self.start_tractor_time < (time - 3)) || (trace_fraction < 1)) { + phoenix_xattc9(); + } +}; + +void() PhoenixBeamEnd = +{ + self.enemy.x_flags = self.enemy.x_flags - (self.enemy.x_flags & X_TRACTOR_BEAM_HOLD); + self.enemy.velocity = normalize(self.enemy.origin - self.origin) * 250 + '0 0 100'; + + // hurt enemy + T_Damage(self.enemy, self, self, 10); + self.enemy.punchangle_x = -8; + + self.flags = self.flags - (self.flags & FL_GODMODE); +}; + +void() phoenix_xattc1 = [ $xattc1, phoenix_xattc2 ] {ai_face(); self.start_attack_health = self.health;}; +void() phoenix_xattc2 = [ $xattc2, phoenix_xattc3 ] {ai_face(); self.nextthink = time + 0.2;}; +void() phoenix_xattc3 = [ $xattc3, phoenix_xattc4 ] {ai_face(); self.nextthink = time + 0.2;}; +void() phoenix_xattc4 = [ $xattc4, phoenix_xattc5 ] +{ + ai_face(); + if (self.start_attack_health == self.health) + PhoenixStartBeam(); + else + self.th_run; +}; +void() phoenix_xattc5 = [ $xattc5, phoenix_xattc6 ] {PhoenixBeamThink();}; +void() phoenix_xattc6 = [ $xattc6, phoenix_xattc7 ] {PhoenixBeamThink();}; +void() phoenix_xattc7 = [ $xattc7, phoenix_xattc8 ] {PhoenixBeamThink();}; +void() phoenix_xattc8 = [ $xattc8, phoenix_xattc5 ] {PhoenixBeamThink();}; +void() phoenix_xattc9 = [ $xattc9, phoenix_xattc10 ] {}; +void() phoenix_xattc10 = [ $xattc10, phoenix_xattc11 ] {}; +void() phoenix_xattc11 = [ $xattc11, phoenix_xattc12 ] {}; +void() phoenix_xattc12 = [ $xattc12, phoenix_xattc13 ] {PhoenixBeamEnd();}; +void() phoenix_xattc13 = [ $xattc13, phoenix_xattc14 ] {}; +void() phoenix_xattc14 = [ $xattc14, phoenix_xattc15 ] {}; +void() phoenix_xattc15 = [ $xattc15, phoenix_xattc16 ] {}; +void() phoenix_xattc16 = [ $xattc16, phoenix_xattc17 ] {}; +void() phoenix_xattc17 = [ $xattc17, phoenix_run1 ] {}; + +void() PhoenixMissile = +{ + local float rnd; + + rnd = random(); + if ((rnd < 0.3) && (self.last_special2 < (time - 6))) + phoenix_xattb1(); + else if ((vlen(self.origin - self.enemy.origin) > 128) && (rnd < 0.8) && (self.last_special < (time - 4))) + phoenix_xattc1(); + else + phoenix_xatta1(); +}; + +//============================================================================ + +void() monster_shalrath = +{ + remove(self); + return; +}; + +void() xmen_phoenix = +{ + if (deathmatch) + { + remove(self); + return; + } + precache_model ("progs/phoenix.mdl"); + precache_model ("progs/psyblast.mdl"); + + // XMen matched ID sounds + precache_sound ("items/protect3.wav"); + + precache_sound ("items/damage3.wav"); + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + + setmodel (self, "progs/phoenix.mdl"); + + setsize (self, VEC_HULL_MIN, VEC_HULL_MAX); + self.health = 180 + cvar("skill")*10; + + self.th_stand = phoenix_stand1; + self.th_walk = phoenix_walk1; + self.th_run = phoenix_run1; + self.th_pain = PhoenixPain; + self.th_die = PhoenixDie; + self.th_missile = PhoenixMissile; + + self.th_guard = phoenix_guard1; + + walkmonster_start(); + + precache_model("progs/beampart.mdl"); + + // create beam entities + self.flame_ent1 = spawn(); + self.flame_ent2 = spawn(); + self.flame_ent3 = spawn(); + + self.flame_ent1.think = TractorParticleThink; + self.flame_ent2.think = TractorParticleThink; + self.flame_ent3.think = TractorParticleThink; + + self.flame_ent1.owner = self; + self.flame_ent2.owner = self; + self.flame_ent3.owner = self; +}; \ No newline at end of file diff --git a/progdefs.h b/progdefs.h new file mode 100644 index 0000000..c976cf8 --- /dev/null +++ b/progdefs.h @@ -0,0 +1,143 @@ + +/* file generated by qcc, do not modify */ + +typedef struct +{ int pad[28]; + int self; + int other; + int world; + float time; + float frametime; + float force_retouch; + string_t mapname; + float deathmatch; + float coop; + float teamplay; + float serverflags; + float total_secrets; + float total_monsters; + float found_secrets; + float killed_monsters; + float parm1; + float parm2; + float parm3; + float parm4; + float parm5; + float parm6; + float parm7; + float parm8; + float parm9; + float parm10; + float parm11; + float parm12; + float parm13; + float parm14; + float parm15; + float parm16; + vec3_t v_forward; + vec3_t v_up; + vec3_t v_right; + float trace_allsolid; + float trace_startsolid; + float trace_fraction; + vec3_t trace_endpos; + vec3_t trace_plane_normal; + float trace_plane_dist; + int trace_ent; + float trace_inopen; + float trace_inwater; + int msg_entity; + func_t main; + func_t StartFrame; + func_t PlayerPreThink; + func_t PlayerPostThink; + func_t ClientKill; + func_t ClientConnect; + func_t PutClientInServer; + func_t ClientDisconnect; + func_t SetNewParms; + func_t SetChangeParms; +} globalvars_t; + +typedef struct +{ + float modelindex; + vec3_t absmin; + vec3_t absmax; + float ltime; + float movetype; + float solid; + vec3_t origin; + vec3_t oldorigin; + vec3_t velocity; + vec3_t angles; + vec3_t avelocity; + vec3_t punchangle; + string_t classname; + string_t model; + float frame; + float skin; + float effects; + vec3_t mins; + vec3_t maxs; + vec3_t size; + func_t touch; + func_t use; + func_t think; + func_t blocked; + float nextthink; + int groundentity; + float health; + float frags; + float weapon; + string_t weaponmodel; + float weaponframe; + float currentammo; + float ammo_shells; + float ammo_nails; + float ammo_rockets; + float ammo_cells; + float items; + float takedamage; + int chain; + float deadflag; + vec3_t view_ofs; + float button0; + float button1; + float button2; + float impulse; + float fixangle; + vec3_t v_angle; + float idealpitch; + string_t netname; + int enemy; + float flags; + float colormap; + float team; + float max_health; + float teleport_time; + float armortype; + float armorvalue; + float waterlevel; + float watertype; + float ideal_yaw; + float yaw_speed; + int aiment; + int goalentity; + float spawnflags; + string_t target; + string_t targetname; + float dmg_take; + float dmg_save; + int dmg_inflictor; + int owner; + vec3_t movedir; + string_t message; + float sounds; + string_t noise; + string_t noise1; + string_t noise2; + string_t noise3; +} entvars_t; + +#define PROGHEADER_CRC 5927 diff --git a/psylocke.c b/psylocke.c new file mode 100644 index 0000000..04c9e72 --- /dev/null +++ b/psylocke.c @@ -0,0 +1,388 @@ +/* +============================================================================== + +Psyloche + +============================================================================== +*/ + +$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9 +$frame stand10 stand11 stand12 stand13 + +$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 walk9 walk10 walk11 walk12 + +$frame run1 run2 run3 run4 run5 run6 + +$frame pain1 pain2 pain3 pain4 pain5 pain6 + +$frame paina1 paina2 paina3 paina4 paina5 paina6 paina7 paina8 paina9 paina10 +$frame paina11 paina12 paina13 paina14 paina15 paina16 paina17 paina18 paina19 paina20 +$frame paina21 paina22 paina23 paina24 paina25 paina26 paina27 paina28 paina29 + +$frame death1 death2 death3 death4 death5 death6 death7 death8 death9 death10 +$frame death11 death12 death13 death14 death15 death16 + +$frame jatta1 jatta2 jatta3 jatta4 jatta5 jatta6 jatta7 jatta8 +$frame jatta9 jatta10 jatta11 jatta12 + +$frame jattb1 jattb2 jattb3 jattb4 jattb5 jattb6 jattb7 jattb8 +$frame jattb9 jattb10 jattb11 jattb12 + +$frame satta1 satta2 satta3 satta4 satta5 satta6 satta7 satta8 +$frame satta9 satta10 satta11 satta12 + +$frame sattb1 sattb2 sattb3 sattb4 sattb5 sattb6 sattb7 sattb8 +$frame sattb9 sattb10 sattb11 sattb12 + +$frame sattc1 sattc2 sattc3 sattc4 sattc5 sattc6 sattc7 sattc8 +$frame sattc9 sattc10 sattc11 sattc12 + +$frame sattd1 sattd2 sattd3 sattd4 sattd5 sattd6 sattd7 sattd8 +$frame sattd9 sattd10 sattd11 sattd12 + +$frame xatt1 xatt2 xatt3 xatt4 xatt5 xatt6 xatt7 xatt8 +$frame xatt9 xatt10 xatt11 xatt12 + +void() knight_stand1 =[ $stand1, knight_stand2 ] {ai_stand();}; +void() knight_stand2 =[ $stand2, knight_stand3 ] {ai_stand();}; +void() knight_stand3 =[ $stand3, knight_stand4 ] {ai_stand();}; +void() knight_stand4 =[ $stand4, knight_stand5 ] {ai_stand();}; +void() knight_stand5 =[ $stand5, knight_stand6 ] {ai_stand();}; +void() knight_stand6 =[ $stand6, knight_stand7 ] {ai_stand();}; +void() knight_stand7 =[ $stand7, knight_stand8 ] {ai_stand();}; +void() knight_stand8 =[ $stand8, knight_stand9 ] {ai_stand();}; +void() knight_stand9 =[ $stand9, knight_stand10 ] {ai_stand();}; +void() knight_stand10 =[ $stand10, knight_stand11 ] {ai_stand();}; +void() knight_stand11 =[ $stand11, knight_stand12 ] {ai_stand();}; +void() knight_stand12 =[ $stand12, knight_stand13 ] {ai_stand();}; +void() knight_stand13 =[ $stand13, knight_stand1 ] {ai_stand();}; + +void() knight_walk1 =[ $walk1, knight_walk2 ] {ai_walk(7);}; +void() knight_walk2 =[ $walk2, knight_walk3 ] {ai_walk(6);}; +void() knight_walk3 =[ $walk3, knight_walk4 ] {ai_walk(5);}; +void() knight_walk4 =[ $walk4, knight_walk5 ] {ai_walk(5);}; +void() knight_walk5 =[ $walk5, knight_walk6 ] {ai_walk(5);}; +void() knight_walk6 =[ $walk6, knight_walk7 ] {ai_walk(6);}; +void() knight_walk7 =[ $walk7, knight_walk8 ] {ai_walk(8);}; +void() knight_walk8 =[ $walk8, knight_walk9 ] {ai_walk(8);}; +void() knight_walk9 =[ $walk9, knight_walk10 ] {ai_walk(6);}; +void() knight_walk10 =[ $walk10, knight_walk11 ] {ai_walk(5);}; +void() knight_walk11 =[ $walk11, knight_walk12 ] {ai_walk(4);}; +void() knight_walk12 =[ $walk12, knight_walk1 ] {ai_walk(5);}; + + +void() knight_run1 =[ $run1, knight_run2 ] {ai_run(24);}; +void() knight_run2 =[ $run2, knight_run3 ] {ai_run(30);}; +void() knight_run3 =[ $run3, knight_run4 ] {ai_run(20);}; +void() knight_run4 =[ $run4, knight_run5 ] {ai_run(13);}; +void() knight_run5 =[ $run5, knight_run6 ] {ai_run(22);}; +void() knight_run6 =[ $run6, knight_run1 ] {ai_run(30);}; + + +void() knight_runatk1 =[ $jatta1, knight_runatk2 ] +{ +sound (self, CHAN_WEAPON, "voice/female/attack1.wav", 1, ATTN_NORM); +ai_charge(20); +}; +void() knight_runatk2 =[ $jatta2, knight_runatk3 ] {ai_charge_side();}; +void() knight_runatk3 =[ $jatta3, knight_runatk4 ] {ai_charge_side();}; +void() knight_runatk4 =[ $jatta4, knight_runatk5 ] {ai_charge_side();}; +void() knight_runatk5 =[ $jatta5, knight_runatk6 ] {ai_melee_side();}; +void() knight_runatk6 =[ $jatta6, knight_runatk7 ] {ai_melee_side();}; +void() knight_runatk7 =[ $jatta7, knight_runatk8 ] {ai_melee_side();}; +void() knight_runatk8 =[ $jatta8, knight_runatk9 ] {ai_melee_side();}; +void() knight_runatk9 =[ $jatta9, knight_runatk10 ] {ai_melee_side();}; +void() knight_runatk10 =[ $jatta10, knight_runatk11 ] {ai_charge_side();}; +void() knight_runatk11 =[ $jatta11, knight_runatk12 ] {ai_charge(10);}; +void() knight_runatk12 =[ $jatta12, knight_run1 ] {ai_charge(10);}; + +void() knight_runatkb1 =[ $jattb1, knight_runatkb2 ] +{ +if (random() > 0.5) + sound (self, CHAN_WEAPON, "knight/sword2.wav", 1, ATTN_NORM); +else + sound (self, CHAN_WEAPON, "knight/sword1.wav", 1, ATTN_NORM); +ai_charge(20); +}; +void() knight_runatkb2 =[ $jattb2, knight_runatkb3 ] {ai_charge_side();}; +void() knight_runatkb3 =[ $jattb3, knight_runatkb4 ] {ai_charge_side();}; +void() knight_runatkb4 =[ $jattb4, knight_runatkb5 ] {ai_charge_side();}; +void() knight_runatkb5 =[ $jattb5, knight_runatkb6 ] {ai_melee_side();}; +void() knight_runatkb6 =[ $jattb6, knight_runatkb7 ] {ai_melee_side();}; +void() knight_runatkb7 =[ $jattb7, knight_runatkb8 ] {ai_melee_side();}; +void() knight_runatkb8 =[ $jattb8, knight_runatkb9 ] {ai_melee_side();}; +void() knight_runatkb9 =[ $jattb9, knight_runatkb10 ] {ai_melee_side();}; +void() knight_runatkb10 =[ $jattb10, knight_runatkb11 ] {ai_charge_side();}; +void() knight_runatkb11 =[ $jattb11, knight_runatkb12 ] {ai_charge(10);}; +void() knight_runatkb12 =[ $jattb12, knight_run1 ] {ai_charge(10);}; + +void() knight_runattack = +{ + if (random() < 0.5) + knight_runatk1(); + else + knight_runatkb1(); +}; + + + +void() knight_atk1 =[ $satta1, knight_atk2 ] +{ +sound (self, CHAN_WEAPON, "voice/female/attack1.wav", 1, ATTN_NORM); +ai_charge(0);}; +void() knight_atk2 =[ $satta2, knight_atk3 ] {ai_charge(7);}; +void() knight_atk3 =[ $satta3, knight_atk4 ] {ai_charge(4);}; +void() knight_atk4 =[ $satta4, knight_atk5 ] {ai_charge(0);}; +void() knight_atk5 =[ $satta5, knight_atk6 ] {ai_charge(3);}; +void() knight_atk6 =[ $satta6, knight_atk7 ] {ai_charge(4); ai_melee();}; +void() knight_atk7 =[ $satta7, knight_atk8 ] {ai_charge(1); ai_melee();}; +void() knight_atk8 =[ $satta8, knight_atk9 ] {ai_charge(3); ai_melee();}; +void() knight_atk9 =[ $satta9, knight_atk10] {ai_charge(1);}; +void() knight_atk10=[ $satta10, knight_atk11 ] {ai_charge(5);}; +void() knight_atk11=[ $satta11, knight_atk12 ] {ai_charge(5);}; +void() knight_atk12=[ $satta12, knight_run1 ] {ai_charge(5);}; + +void() knight_atkb1 =[ $sattb1, knight_atkb2 ] +{ +sound (self, CHAN_WEAPON, "knight/sword1.wav", 1, ATTN_NORM); +ai_charge(0);}; +void() knight_atkb2 =[ $sattb2, knight_atkb3 ] {ai_charge(7);}; +void() knight_atkb3 =[ $sattb3, knight_atkb4 ] {ai_charge(4);}; +void() knight_atkb4 =[ $sattb4, knight_atkb5 ] {ai_charge(0);}; +void() knight_atkb5 =[ $sattb5, knight_atkb6 ] {ai_charge(3);}; +void() knight_atkb6 =[ $sattb6, knight_atkb7 ] {ai_charge(4); ai_melee();}; +void() knight_atkb7 =[ $sattb7, knight_atkb8 ] {ai_charge(1); ai_melee();}; +void() knight_atkb8 =[ $sattb8, knight_atkb9 ] {ai_charge(3); ai_melee();}; +void() knight_atkb9 =[ $sattb9, knight_atkb10] {ai_charge(1);}; +void() knight_atkb10=[ $sattb10, knight_atkb11 ] {ai_charge(5);}; +void() knight_atkb11=[ $sattb11, knight_atkb12 ] {ai_charge(5);}; +void() knight_atkb12=[ $sattb12, knight_run1 ] {ai_charge(5);}; + +void() knight_atkc1 =[ $sattc1, knight_atkc2 ] +{ +sound (self, CHAN_WEAPON, "voice/female/attack1.wav", 1, ATTN_NORM); +ai_charge(0);}; +void() knight_atkc2 =[ $sattc2, knight_atkc3 ] {ai_charge(7);}; +void() knight_atkc3 =[ $sattc3, knight_atkc4 ] {ai_charge(4);}; +void() knight_atkc4 =[ $sattc4, knight_atkc5 ] {ai_charge(0);}; +void() knight_atkc5 =[ $sattc5, knight_atkc6 ] {ai_charge(3);}; +void() knight_atkc6 =[ $sattc6, knight_atkc7 ] {ai_charge(4); ai_melee();}; +void() knight_atkc7 =[ $sattc7, knight_atkc8 ] {ai_charge(1); ai_melee();}; +void() knight_atkc8 =[ $sattc8, knight_atkc9 ] {ai_charge(3); ai_melee();}; +void() knight_atkc9 =[ $sattc9, knight_atkc10] {ai_charge(1);}; +void() knight_atkc10=[ $sattc10, knight_atkc11 ] {ai_charge(5);}; +void() knight_atkc11=[ $sattc11, knight_atkc12 ] {ai_charge(5);}; +void() knight_atkc12=[ $sattc12, knight_run1 ] {ai_charge(5);}; + +void() knight_atkd1 =[ $sattd1, knight_atkd2 ] +{ +sound (self, CHAN_WEAPON, "knight/sword1.wav", 1, ATTN_NORM); +ai_charge(0);}; +void() knight_atkd2 =[ $sattd2, knight_atkd3 ] {ai_charge(7);}; +void() knight_atkd3 =[ $sattd3, knight_atkd4 ] {ai_charge(4);}; +void() knight_atkd4 =[ $sattd4, knight_atkd5 ] {ai_charge(0);}; +void() knight_atkd5 =[ $sattd5, knight_atkd6 ] {ai_charge(3);}; +void() knight_atkd6 =[ $sattd6, knight_atkd7 ] {ai_charge(4); ai_melee();}; +void() knight_atkd7 =[ $sattd7, knight_atkd8 ] {ai_charge(1); ai_melee();}; +void() knight_atkd8 =[ $sattd8, knight_atkd9 ] {ai_charge(3); ai_melee();}; +void() knight_atkd9 =[ $sattd9, knight_atkd10] {ai_charge(1);}; +void() knight_atkd10=[ $sattd10, knight_atkd11 ] {ai_charge(5);}; +void() knight_atkd11=[ $sattd11, knight_atkd12 ] {ai_charge(5);}; +void() knight_atkd12=[ $sattd12, knight_run1 ] {ai_charge(5);}; + +// Psyloche's special parallise attack +void() knight_special = +{ + makevectors(self.angles); + traceline(self.origin, self.origin + v_forward*48, FALSE, self); + + if ((trace_ent == self.enemy) && (self.enemy.classname == "player")) { + // got 'em + sound(self, CHAN_WEAPON, "player/what_1.wav", 1, ATTN_NORM); + + self.enemy.parallize_time = time + 2 + random(); + self.enemy.x_flags = self.enemy.x_flags | X_PARALLIZED; + self.enemy.parallized_velocity = '0 0 0'; + centerprint(self.enemy, "You have been paralyzed"); + stuffcmd(self.enemy, "v_cshift 0 0 0 180\n"); + } +}; + +void() knight_xatk1 =[ $xatt1, knight_xatk2 ] +{ +sound (self, CHAN_WEAPON, "knight/sword1.wav", 1, ATTN_NORM); +ai_charge(0); +self.nextthink = time + 0.05;}; +void() knight_xatk2 =[ $xatt2, knight_xatk3 ] {ai_charge(0);self.nextthink = time + 0.05;}; +void() knight_xatk3 =[ $xatt3, knight_xatk4 ] {ai_charge(0);self.nextthink = time + 0.05;}; +void() knight_xatk4 =[ $xatt4, knight_xatk5 ] {ai_charge(0);self.nextthink = time + 0.05;}; +void() knight_xatk5 =[ $xatt5, knight_xatk6 ] {ai_charge(0);self.nextthink = time + 0.05;}; +void() knight_xatk6 =[ $xatt6, knight_xatk7 ] {ai_charge(0);self.nextthink = time + 0.05;}; +void() knight_xatk7 =[ $xatt7, knight_xatk8 ] {ai_charge(3);self.nextthink = time + 0.05;}; +void() knight_xatk8 =[ $xatt8, knight_xatk9 ] {ai_charge(5);self.nextthink = time + 0.05;}; +void() knight_xatk9 =[ $xatt9, knight_xatk10] {ai_charge(10); knight_special();}; +void() knight_xatk10=[ $xatt10, knight_xatk11 ] {ai_charge(0);}; +void() knight_xatk11=[ $xatt11, knight_xatk12 ] {ai_charge(0);}; +void() knight_xatk12=[ $xatt12, knight_run1 ] {ai_charge(0);}; + +void() knight_atk = +{ + local float rnd; + + // check for special attack + if ((vlen(self.enemy.velocity) < 20) && (self.last_special < (time - 5)) && (self.enemy.classname == "player")) { + self.last_special = time; + knight_xatk1(); + return; + } + + rnd = random() * 4; + if (rnd < 1) + knight_atk1(); + else if (rnd < 2) + knight_atkb1(); + else if (rnd < 3) + knight_atkc1(); + else + knight_atkd1(); +}; + + +float() PsylockeCheckAttack = +{ + local float dist; + + dist = vlen(self.enemy.origin - self.origin); + if (dist > 256) + return FALSE; + + if (!infront(self.enemy)) + return FALSE; + + if (dist > 96) { + self.attack_state = AS_MISSILE; + } + else { + self.attack_state = AS_MELEE; + } + + return TRUE; +}; + + +//=========================================================================== + +void() knight_pain1 =[ $pain1, knight_pain2 ] {}; +void() knight_pain2 =[ $pain2, knight_pain3 ] {}; +void() knight_pain3 =[ $pain3, knight_pain4 ] {}; +void() knight_pain4 =[ $pain4, knight_pain5 ] {}; +void() knight_pain5 =[ $pain5, knight_pain6 ] {}; +void() knight_pain6 =[ $pain6, knight_run1 ] {}; + +void() knight_paina = +{ + self.frame = self.frame + 1; + + if (self.frame > $paina29 ) + knight_run1(); + else { + self.think = knight_paina; + self.nextthink = time + 0.05; + } + +}; + +void(entity attacker, float damage) knight_pain = +{ + local float r; + + if (self.pain_finished > time) + return; + + r = random(); + + FemalePainSound(); + + if (r < 0.85) + { + knight_pain1 (); + self.pain_finished = time + 2; + } + else + { + self.frame = $paina1 - 1; + knight_paina (); + self.pain_finished = time + 5; + } + +}; + + +void() knight_die1 =[ $death1, knight_die2 ] {}; +void() knight_die2 =[ $death2, knight_die3 ] {}; +void() knight_die3 =[ $death3, knight_die4 ] +{self.solid = SOLID_NOT;}; +void() knight_die4 =[ $death4, knight_die5 ] {}; +void() knight_die5 =[ $death5, knight_die6 ] {}; +void() knight_die6 =[ $death6, knight_die7 ] {}; +void() knight_die7 =[ $death7, knight_die8 ] {}; +void() knight_die8 =[ $death8, knight_die9 ] {}; +void() knight_die9 =[ $death9, knight_die10] {}; +void() knight_die10=[ $death10, knight_die11] {}; +void() knight_die11=[ $death11, knight_die12] {}; +void() knight_die12=[ $death12, knight_die13] {}; +void() knight_die13=[ $death13, knight_die14] {}; +void() knight_die14=[ $death14, knight_die15] {}; +void() knight_die15=[ $death15, knight_die16] {}; +void() knight_die16=[ $death16, knight_die16] {}; + +void() knight_die = +{ + FemaleDeathSound(); + + knight_die1 (); +}; + + +/*QUAKED monster_knight (1 0 0) (-16 -16 -24) (16 16 40) Ambush +*/ +void() monster_knight = +{ + remove(self); +}; + +void() xmen_psylocke = +{ + if (deathmatch) + { + remove(self); + return; + } + + precache_model ("progs/psy1.mdl"); +// precache_model ("progs/h_knight.mdl"); + + precache_sound ("voice/female/attack1.wav"); + + // XMen Matched ID sounds + precache_sound ("knight/sword1.wav"); + precache_sound ("knight/sword2.wav"); + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + + setmodel (self, "progs/psy1.mdl"); + + setsize (self, '-16 -16 -24', '16 16 40'); + self.health = 150 + cvar("skill")*10; + + self.th_stand = knight_stand1; + self.th_walk = knight_walk1; + self.th_run = knight_run1; + self.th_melee = knight_atk; + self.th_missile = knight_runattack; + self.th_pain = knight_pain; + self.th_die = knight_die; + + walkmonster_start (); +}; \ No newline at end of file diff --git a/rogue.c b/rogue.c new file mode 100644 index 0000000..20c7323 --- /dev/null +++ b/rogue.c @@ -0,0 +1,275 @@ +/* +============================================================================== + +Rogue + +============================================================================== +*/ +$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9 +$frame stand10 stand11 stand12 stand13 + +$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 walk9 walk10 +$frame walk11 walk12 walk13 + +$frame run1 run2 run3 run4 run5 run6 run7 run8 run9 run10 run11 run12 + +$frame pain1 pain2 pain3 pain4 pain5 pain6 + +$frame death1 death2 death3 death4 death5 death6 death7 death8 death9 death10 +$frame death11 death12 + +$frame deata1 deata2 deata3 deata4 deata5 deata6 deata7 deata8 deata9 deata10 +$frame deata11 deata12 + +$frame punch1 punch2 punch3 punch4 punch5 punch6 punch7 punch8 +$frame punch9 punch10 punch11 punch12 + +$frame atta1 atta2 atta3 atta4 atta5 atta6 atta7 atta8 +$frame atta9 atta10 atta11 atta12 + +//===================================================================== + +void() rogue_stand1 = [ $stand1, rogue_stand2 ] {ai_stand();}; +void() rogue_stand2 = [ $stand2, rogue_stand3 ] {ai_stand();}; +void() rogue_stand3 = [ $stand3, rogue_stand4 ] {ai_stand();}; +void() rogue_stand4 = [ $stand4, rogue_stand5 ] {ai_stand();}; +void() rogue_stand5 = [ $stand5, rogue_stand6 ] {ai_stand();}; +void() rogue_stand6 = [ $stand6, rogue_stand7 ] {ai_stand();}; +void() rogue_stand7 = [ $stand7, rogue_stand8 ] {ai_stand();}; +void() rogue_stand8 = [ $stand8, rogue_stand9 ] {ai_stand();}; +void() rogue_stand9 = [ $stand9, rogue_stand10 ] {ai_stand();}; +void() rogue_stand10 = [ $stand10, rogue_stand11 ] {ai_stand();}; +void() rogue_stand11 = [ $stand11, rogue_stand12 ] {ai_stand();}; +void() rogue_stand12 = [ $stand12, rogue_stand13 ] {ai_stand();}; +void() rogue_stand13 = [ $stand13, rogue_stand1 ] {ai_stand();}; + +//===================================================================== + +void() rogue_walk1 = [ $walk1, rogue_walk2 ] {ai_walk(10);}; +void() rogue_walk2 = [ $walk2, rogue_walk3 ] {ai_walk(10);}; +void() rogue_walk3 = [ $walk3, rogue_walk4 ] {ai_walk(10);}; +void() rogue_walk4 = [ $walk4, rogue_walk5 ] {ai_walk(10);}; +void() rogue_walk5 = [ $walk5, rogue_walk6 ] {ai_walk(10);}; +void() rogue_walk6 = [ $walk6, rogue_walk7 ] {ai_walk(10);}; +void() rogue_walk7 = [ $walk7, rogue_walk8 ] {ai_walk(10);}; +void() rogue_walk8 = [ $walk8, rogue_walk9 ] {ai_walk(10);}; +void() rogue_walk9 = [ $walk9, rogue_walk10 ] {ai_walk(10);}; +void() rogue_walk10 = [ $walk10, rogue_walk11 ] {ai_walk(10);}; +void() rogue_walk11 = [ $walk11, rogue_walk12 ] {ai_walk(10);}; +void() rogue_walk12 = [ $walk12, rogue_walk13 ] {ai_walk(10);}; +void() rogue_walk13 = [ $walk13, rogue_walk1 ] {ai_walk(10);}; + +//===================================================================== + +void() rogue_run1 = [ $run1, rogue_run2 ] {ai_run(15);}; +void() rogue_run2 = [ $run2, rogue_run3 ] {ai_run(15);}; +void() rogue_run3 = [ $run3, rogue_run4 ] {ai_run(15);}; +void() rogue_run4 = [ $run4, rogue_run5 ] {ai_run(15);}; +void() rogue_run5 = [ $run5, rogue_run6 ] {ai_run(15);}; +void() rogue_run6 = [ $run6, rogue_run7 ] {ai_run(15);}; +void() rogue_run7 = [ $run7, rogue_run8 ] {ai_run(15);}; +void() rogue_run8 = [ $run8, rogue_run9 ] {ai_run(15);}; +void() rogue_run9 = [ $run9, rogue_run10 ] {ai_run(15);}; +void() rogue_run10 = [ $run10, rogue_run11 ] {ai_run(15);}; +void() rogue_run11 = [ $run11, rogue_run12 ] {ai_run(15);}; +void() rogue_run12 = [ $run12, rogue_run1 ] {ai_run(15);}; + +//===================================================================== + +void() rogue_pain1 = [ $pain1, rogue_pain2 ] {}; +void() rogue_pain2 = [ $pain2, rogue_pain3 ] {}; +void() rogue_pain3 = [ $pain3, rogue_pain4 ] {}; +void() rogue_pain4 = [ $pain4, rogue_pain5 ] {}; +void() rogue_pain5 = [ $pain5, rogue_pain6 ] {}; +void() rogue_pain6 = [ $pain6, rogue_run1 ] {}; + +void() rogue_pain = +{ + if (self.pain_finished > time) + return; + + // play a sound here + FemalePainSound(); + + self.pain_finished = time + 2.5; + rogue_pain1(); +}; + +//===================================================================== + +void() rogue_death1 = [ $death1, rogue_death2 ] {}; +void() rogue_death2 = [ $death2, rogue_death3 ] {}; +void() rogue_death3 = [ $death3, rogue_death4 ] {self.solid = SOLID_NOT;}; +void() rogue_death4 = [ $death4, rogue_death5 ] {}; +void() rogue_death5 = [ $death5, rogue_death6 ] {}; +void() rogue_death6 = [ $death6, rogue_death7 ] {}; +void() rogue_death7 = [ $death7, rogue_death8 ] {}; +void() rogue_death8 = [ $death8, rogue_death9 ] {}; +void() rogue_death9 = [ $death9, rogue_death10 ] {}; +void() rogue_death10 = [ $death10, rogue_death11 ] {}; +void() rogue_death11 = [ $death11, rogue_death12 ] {}; +void() rogue_death12 = [ $death12, rogue_death12 ] {if (self.angles_x != 0) AngelPitch();}; + +void() rogue_deata1 = [ $deata1, rogue_deata2 ] {}; +void() rogue_deata2 = [ $deata2, rogue_deata3 ] {}; +void() rogue_deata3 = [ $deata3, rogue_deata4 ] {self.solid = SOLID_NOT;}; +void() rogue_deata4 = [ $deata4, rogue_deata5 ] {}; +void() rogue_deata5 = [ $deata5, rogue_deata6 ] {}; +void() rogue_deata6 = [ $deata6, rogue_deata7 ] {}; +void() rogue_deata7 = [ $deata7, rogue_deata8 ] {}; +void() rogue_deata8 = [ $deata8, rogue_deata9 ] {}; +void() rogue_deata9 = [ $deata9, rogue_deata10 ] {}; +void() rogue_deata10 = [ $deata10, rogue_deata11 ] {}; +void() rogue_deata11 = [ $deata11, rogue_deata12 ] {}; +void() rogue_deata12 = [ $deata12, rogue_deata12 ] {if (self.angles_x != 0) AngelPitch();}; + +void() rogue_die = +{ + + FemaleDeathSound(); + + self.velocity_x = -200 + 400*random(); + self.velocity_y = -200 + 400*random(); + self.velocity_z = 100 + 100*random(); + self.flags = self.flags - (self.flags & FL_ONGROUND); + self.enemy = world; + + if (random() < 0.5) + rogue_death1 (); + else + rogue_deata1 (); + +}; + +//===================================================================== + +void() rogue_punch4; +float(float move_dist) RogueCheckPunch = +{ + ai_face(); + + if (!ai_forward(move_dist)) { // abort + self.think = self.th_run; + return FALSE; + } + + self.nextthink = time + 0.05; + + if (!infront(self.enemy)) { // abort attack + self.think = self.th_run; + return FALSE; + } + + if (vlen(self.enemy.origin - self.origin) > 96) + return FALSE; + + // striking distance! + return TRUE; +}; + +void() RoguePunchPosition = +{ + local float distance1; + + distance1 = vlen(self.enemy.origin - self.origin); + ai_back(5); +}; + +void() rogue_punch1 = [ $punch1, rogue_punch2 ] {RoguePunchPosition(); self.attack_finished = time + 4;}; +void() rogue_punch2 = [ $punch2, rogue_punch3 ] {RoguePunchPosition();}; +void() rogue_punch3 = [ $punch3, rogue_punch3 ] {if (RogueCheckPunch(35)) rogue_punch4();}; +void() rogue_punch4 = [ $punch4, rogue_punch5 ] {ai_forward(15); ai_face();}; +void() rogue_punch5 = [ $punch5, rogue_punch6 ] {ai_forward(12); ai_face();}; +void() rogue_punch6 = [ $punch6, rogue_punch7 ] {ai_forward(8); ai_face();}; +void() rogue_punch7 = [ $punch7, rogue_punch8 ] +{ + local vector vect; + + if (RogueCheckPunch(0)) { + // hit em + sound(self, CHAN_WEAPON, "generic/punch2.wav", 1, ATTN_NORM); + + T_Damage(self.enemy, self, self, 25); + + vect = normalize(self.enemy.origin - self.origin); + self.enemy.velocity = vect * 300; + self.enemy.velocity_z = 300; + self.enemy.punchangle_x = -15; + } +}; +void() rogue_punch8 = [ $punch8, rogue_punch9 ] {}; +void() rogue_punch9 = [ $punch9, rogue_punch10 ] {}; +void() rogue_punch10 = [ $punch10, rogue_punch11 ] {}; +void() rogue_punch11 = [ $punch11, rogue_punch12 ] {}; +void() rogue_punch12 = [ $punch12, rogue_run1 ] {}; + +//================================================================= + +void() rogue_atta1 = [ $atta1, rogue_atta2 ] +{ + ai_face(); + if (vlen(self.enemy.origin - self.origin) < 64) + ai_forward(-10); +}; +void() rogue_atta2 = [ $atta2, rogue_atta3 ] {ai_face();}; +void() rogue_atta3 = [ $atta3, rogue_atta4 ] {ai_face();}; +void() rogue_atta4 = [ $atta4, rogue_atta5 ] {ai_face();}; +void() rogue_atta5 = [ $atta5, rogue_atta6 ] {ai_face();}; +void() rogue_atta6 = [ $atta6, rogue_atta7 ] {ai_face();}; +void() rogue_atta7 = [ $atta7, rogue_atta8 ] +{ + ai_face(); + + if (RogueCheckPunch(0)) { + sound(self, CHAN_WEAPON, "generic/punch2.wav", 1, ATTN_NORM); + self.enemy.punchangle_x = -7; + T_Damage(self.enemy, self, self, 10); + } +}; +void() rogue_atta8 = [ $atta8, rogue_atta9 ] {ai_face();}; +void() rogue_atta9 = [ $atta9, rogue_atta10 ] {ai_face();}; +void() rogue_atta10 = [ $atta10, rogue_atta11 ] {ai_face();}; +void() rogue_atta11 = [ $atta11, rogue_atta12 ] {ai_face();}; +void() rogue_atta12 = [ $atta12, rogue_run1 ] {ai_face();}; + +//================================================================= + +/*QUAKED monster_ogre (1 0 0) (-32 -32 -24) (32 32 48) Ambush +*/ +void() monster_ogre = +{ + remove(self); +}; + +void() xmen_rogue = +{ + if (deathmatch) + { + remove(self); + return; + } + + precache_model ("progs/rogue.mdl"); + + precache_sound ("generic/punch2.wav"); + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + + setmodel (self, "progs/rogue.mdl"); + setsize (self, VEC_HULL_MIN, VEC_HULL_MAX); + self.health = 210 + cvar("skill")*10; + + self.yaw_speed = 10; + + self.th_stand = rogue_stand1; + self.th_walk = rogue_walk1; + self.th_run = rogue_run1; + self.th_die = rogue_die; + self.th_pain = rogue_pain; + self.th_melee = rogue_atta1; + self.th_missile = rogue_punch1; + + self.think = flymonster_start; + self.nextthink = time + 0.1 + random ()*0.1; +}; \ No newline at end of file diff --git a/sinister.c b/sinister.c new file mode 100644 index 0000000..ad8c0d0 --- /dev/null +++ b/sinister.c @@ -0,0 +1,645 @@ +/**************************************************************************** + + SINISTER (2nd Episode boss) + + ****************************************************************************/ + +$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9 stand10 +$frame stand11 stand12 stand13 + +$frame laugh1 laugh2 laugh3 laugh4 laugh5 laugh6 laugh7 laugh8 laugh9 laugh10 +$frame laugh11 laugh12 + +$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 walk9 walk10 +$frame walk11 walk12 + +$frame pain1 pain2 pain3 pain4 pain5 pain6 pain7 pain8 pain9 + +$frame guard1 guard2 guard3 guard4 guard5 guard6 guard7 guard8 +$frame guard9 guard10 guard11 guard12 + +$frame xatta1 xatta2 xatta3 xatta4 xatta5 xatta6 xatta7 xatta8 +$frame xatta9 xatta10 xatta11 xatta12 + +$frame xattb1 xattb2 xattb3 xattb4 xattb5 xattb6 xattb7 xattb8 +$frame xattb9 xattb10 xattb11 xattb12 + +$frame diss1 diss2 diss3 diss4 diss5 diss6 + +$frame death1 death2 death3 death4 death5 death6 death7 death8 death9 death10 +$frame death11 death12 death13 death14 death15 death16 death17 death18 death19 death20 +$frame death21 death22 death23 death24 death25 death26 death27 death28 death29 death30 +$frame death31 death32 death33 death34 + +//============================================================================ + +void() CheckPlayerSight = +{ + local entity sin, current; + + if (self.spawnflags & SPAWNFLAG_CLONE) + return; + + if (self.enemy == world) + self.enemy = self.goalentity = find(world, classname, "player"); + + if (self.enemy.health <= 0) { + return; + } + + if (self.enemy != world) { + traceline(self.origin + '0 0 40', self.enemy.origin + '0 0 40', TRUE, world); + + if (trace_fraction == 1) { + self.th_run(); + + if (self.x_flags & X_SINISTER_FINAL) { + + // remove all other sinisters still in the map + sin = find(world, classname, "xmen_sinister"); + while (sin != world) { + current = sin; + + if (sin != self) + remove(sin); + + sin = find(current, classname, "xmen_sinister"); + } + + self.last_flame = time; + sound(self, CHAN_ITEM, "sinister/mrsin1.wav", 1, ATTN_NONE); + + } + } + } +}; + +void() sin_laugh1; + +void() sin_stand1 = [ $stand1, sin_stand2 ] {CheckPlayerSight();}; +void() sin_stand2 = [ $stand2, sin_stand3 ] {CheckPlayerSight();}; +void() sin_stand3 = [ $stand3, sin_stand4 ] {CheckPlayerSight();}; +void() sin_stand4 = [ $stand4, sin_stand5 ] {CheckPlayerSight();}; +void() sin_stand5 = [ $stand5, sin_stand6 ] {CheckPlayerSight();}; +void() sin_stand6 = [ $stand6, sin_stand7 ] {CheckPlayerSight();}; +void() sin_stand7 = [ $stand7, sin_stand8 ] {CheckPlayerSight();}; +void() sin_stand8 = [ $stand8, sin_stand9 ] {CheckPlayerSight();}; +void() sin_stand9 = [ $stand9, sin_stand10 ] {CheckPlayerSight();}; +void() sin_stand10 = [ $stand10, sin_stand11 ] {CheckPlayerSight();}; +void() sin_stand11 = [ $stand11, sin_stand12 ] {CheckPlayerSight();}; +void() sin_stand12 = [ $stand12, sin_stand13 ] {CheckPlayerSight();}; +void() sin_stand13 = [ $stand13, sin_stand1 ] +{ + if (!(self.x_flags & X_SINISTER_FINAL)) { + self.count = self.count + 1; + if ((random() < 0.4) || (self.count == 3)) { + self.count = 0; + self.think = sin_laugh1; + } + } +}; + +void() sin_laugh1 = [ $laugh1, sin_laugh2 ] +{ + local float rnd; + + if ((self.count == 0) && (self.last_flame < (time - 4))) { + rnd = random() * 8; + if (rnd < 1) + sound(self, CHAN_VOICE, "sinister/laugh1.wav", 1, 2); + else if (rnd < 2) + sound(self, CHAN_VOICE, "sinister/laugh2.wav", 1, 2); + else if (rnd < 2) + sound(self, CHAN_VOICE, "sinister/cackle1.wav", 1, 2); + else if (rnd < 4) + sound(self, CHAN_VOICE, "sinister/cackle2.wav", 1, 2); + else if (rnd < 5) + sound(self, CHAN_VOICE, "sinister/cackle3.wav", 1, 2); + else if (rnd < 6) + sound(self, CHAN_VOICE, "sinister/threat1.wav", 1, 2); + else if (rnd < 7) + sound(self, CHAN_VOICE, "sinister/threat2.wav", 1, 2); + else + sound(self, CHAN_VOICE, "sinister/threat3.wav", 1, 2); + } +}; +void() sin_laugh2 = [ $laugh2, sin_laugh3 ] {CheckPlayerSight();}; +void() sin_laugh3 = [ $laugh3, sin_laugh4 ] {CheckPlayerSight();}; +void() sin_laugh4 = [ $laugh4, sin_laugh5 ] {CheckPlayerSight();}; +void() sin_laugh5 = [ $laugh5, sin_laugh6 ] {CheckPlayerSight();}; +void() sin_laugh6 = [ $laugh6, sin_laugh7 ] {CheckPlayerSight();}; +void() sin_laugh7 = [ $laugh7, sin_laugh8 ] {CheckPlayerSight();}; +void() sin_laugh8 = [ $laugh8, sin_laugh9 ] {CheckPlayerSight();}; +void() sin_laugh9 = [ $laugh9, sin_laugh10 ] {CheckPlayerSight();}; +void() sin_laugh10 = [ $laugh10, sin_laugh11 ] {CheckPlayerSight();}; +void() sin_laugh11 = [ $laugh11, sin_laugh12 ] {CheckPlayerSight();}; +void() sin_laugh12 = [ $laugh12, sin_laugh1 ] +{ + self.count = self.count + 1; + if (self.count >= 4) { + self.count = 0; + self.think = sin_stand1; + } +}; + +//============================================================================ + +void() SinisterMissile; +void() sin_sightlaugh1 = [ $laugh1, sin_sightlaugh2 ] +{ + local float rnd; + + if (self.count == 0) { + rnd = random() * 8; + if (rnd < 1) + sound(self, CHAN_VOICE, "sinister/laugh1.wav", 1, 2); + else if (rnd < 2) + sound(self, CHAN_VOICE, "sinister/laugh2.wav", 1, 2); + else if (rnd < 2) + sound(self, CHAN_VOICE, "sinister/cackle1.wav", 1, 2); + else if (rnd < 4) + sound(self, CHAN_VOICE, "sinister/cackle2.wav", 1, 2); + else if (rnd < 5) + sound(self, CHAN_VOICE, "sinister/cackle3.wav", 1, 2); + else if (rnd < 6) + sound(self, CHAN_VOICE, "sinister/threat1.wav", 1, 2); + else if (rnd < 7) + sound(self, CHAN_VOICE, "sinister/threat2.wav", 1, 2); + else + sound(self, CHAN_VOICE, "sinister/threat3.wav", 1, 2); + } +}; +void() sin_sightlaugh2 = [ $laugh2, sin_sightlaugh3 ] {}; +void() sin_sightlaugh3 = [ $laugh3, sin_sightlaugh4 ] {}; +void() sin_sightlaugh4 = [ $laugh4, sin_sightlaugh5 ] {}; +void() sin_sightlaugh5 = [ $laugh5, sin_sightlaugh6 ] {}; +void() sin_sightlaugh6 = [ $laugh6, sin_sightlaugh7 ] {}; +void() sin_sightlaugh7 = [ $laugh7, sin_sightlaugh8 ] {}; +void() sin_sightlaugh8 = [ $laugh8, sin_sightlaugh9 ] {}; +void() sin_sightlaugh9 = [ $laugh9, sin_sightlaugh10 ] {}; +void() sin_sightlaugh10 = [ $laugh10, sin_sightlaugh11 ] {}; +void() sin_sightlaugh11 = [ $laugh11, sin_sightlaugh12 ] {}; +void() sin_sightlaugh12 = [ $laugh12, sin_sightlaugh1 ] +{ + self.count = self.count + 1; + if (self.count >= 4) { + self.count = 0; + self.think = SinisterMissile; + } +}; + +void() sin_walk1 = [ $walk1, sin_walk2 ] {ai_run(3);}; +void() sin_walk2 = [ $walk2, sin_walk3 ] {ai_run(2);}; +void() sin_walk3 = [ $walk3, sin_walk4 ] {ai_run(3);}; +void() sin_walk4 = [ $walk4, sin_walk5 ] {ai_run(5);}; +void() sin_walk5 = [ $walk5, sin_walk6 ] {ai_run(6);}; +void() sin_walk6 = [ $walk6, sin_walk7 ] {ai_run(6);}; +void() sin_walk7 = [ $walk7, sin_walk8 ] {ai_run(5);}; +void() sin_walk8 = [ $walk8, sin_walk9 ] {ai_run(3);}; +void() sin_walk9 = [ $walk9, sin_walk10 ] {ai_run(3);}; +void() sin_walk10 = [ $walk10, sin_walk11 ] {ai_run(4);}; +void() sin_walk11 = [ $walk11, sin_walk12 ] {ai_run(5);}; +void() sin_walk12 = [ $walk12, sin_walk1 ] {ai_run(6);}; + +//============================================================================ + +void() sin_pain1 = [ $pain1, sin_pain2 ] {}; +void() sin_pain2 = [ $pain2, sin_pain3 ] {}; +void() sin_pain3 = [ $pain3, sin_pain4 ] {}; +void() sin_pain4 = [ $pain4, sin_pain5 ] {}; +void() sin_pain5 = [ $pain5, sin_pain6 ] {}; +void() sin_pain6 = [ $pain6, sin_pain7 ] {}; +void() sin_pain7 = [ $pain7, sin_pain8 ] {}; +void() sin_pain8 = [ $pain8, sin_pain9 ] {}; +void() sin_pain9 = [ $pain9, sin_walk1 ] {}; + +void() sin_diss1; +void(entity attacker, float damage) SinisterPain = +{ + local float best; + local entity stemp; + + if (self.spawnflags & SPAWNFLAG_CLONE) { + self.health = 99999; + return; + } + + if (self.x_flags & X_SINISTER_FINAL) { +//self.health =1; +//return; + + if (attacker.weapon == IT_SPECIAL_WEAPON) { + if (self.health < 10000) { // special weapon has removed invulnerability + self.health = self.start_health = 500; + self.x_flags = self.x_flags | X_MEGA_HIT; + + attacker.currentammo = attacker.ammo_special = 0; + + self.th_run(); + + return; + } + + if (self.pain_finished > time) + return; + + self.pain_finished = time + 5; +// sin_pain1(); + return; + } + + if (!(self.x_flags & X_MEGA_HIT)) { + self.health = 99999; + return; + } + + if (self.pain_finished > time) + return; + + if ((random() * 20) > damage) // don't flinch + return; + + self.pain_finished = time + 2; + sin_pain1(); + return; + } + else { // move to next spot + sin_diss1(); + } + + self.health = 99999; +}; + +//============================================================================ +void() sin_guard8; + +void() sin_guard1 = [ $guard1, sin_guard2 ] {}; +void() sin_guard2 = [ $guard2, sin_guard3 ] {}; +void() sin_guard3 = [ $guard3, sin_guard4 ] {}; +void() sin_guard4 = [ $guard4, sin_guard5 ] {}; +void() sin_guard5 = [ $guard5, sin_guard6 ] {}; +void() sin_guard6 = [ $guard6, sin_guard7 ] {self.flags = self.flags | FL_GODMODE;}; +void() sin_guard7 = [ $guard7, sin_guard7 ] +{ + local entity trav; + + trav = world; + while ((trav = find(trav, classname, "guided_rocket")) != world) { + + // check that rocket is targetted for self + if (trav.enemy == self) { // uh oh + return; + } + + } + + // dangerous rocket not found + self.flags = self.flags - (self.flags & FL_GODMODE); + self.think = sin_guard8; +}; +void() sin_guard8 = [ $guard8, sin_guard9 ] {}; +void() sin_guard9 = [ $guard9, sin_guard10 ] {}; +void() sin_guard10 = [ $guard10, sin_guard11 ] {}; +void() sin_guard11 = [ $guard11, sin_guard12 ] {}; +void() sin_guard12 = [ $guard12, sin_walk1 ] {}; + +//============================================================================ +void() SinisterMissile; + +void() SinMissileTouch = +{ + if (other == self.owner) + return; + + 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); + + if (other.takedamage == DAMAGE_AIM) + { + spawn_touchblood (5); + T_Damage(other, self, self.owner, 5); + } + + remove(self); +}; + +void(vector org) spawn_sinister_missile = +{ + local entity missile, mpuff; + local vector vect; + + missile = spawn (); + missile.owner = self; + missile.movetype = MOVETYPE_FLYMISSILE; + missile.solid = SOLID_BBOX; + missile.classname = "sin_missile"; + + missile.velocity = ProjectVelocity(750, '0 0 0'); + + missile.angles = vectoangles(missile.velocity); + missile.old_velocity = missile.velocity; + + missile.touch = SinMissileTouch; + + missile.last_touch = 0; + missile.oldorigin = missile.origin; + missile.nextthink = time + 10; + missile.think = SUB_Remove; + + setmodel (missile, "progs/sinblast.mdl"); + setsize (missile, '0 0 0', '0 0 0'); + setorigin (missile, org); +}; + + +void() sin_xatta1 = [ $xatta1, sin_xatta2 ] {ai_face();}; +void() sin_xatta2 = [ $xatta2, sin_xatta3 ] {ai_face();}; +void() sin_xatta3 = [ $xatta3, sin_xatta4 ] {ai_face();}; +void() sin_xatta4 = [ $xatta4, sin_xatta5 ] {ai_face();}; +void() sin_xatta5 = [ $xatta5, sin_xatta6 ] +{ + ai_face(); + + makevectors(self.angles); + spawn_sinister_missile(self.origin + v_right * 4); + spawn_sinister_missile(self.origin + v_right * -4); +}; +void() sin_xatta6 = [ $xatta6, sin_xatta7 ] {ai_face();}; +void() sin_xatta7 = [ $xatta7, sin_xatta8 ] {ai_face();}; +void() sin_xatta8 = [ $xatta8, sin_xatta9 ] {ai_face();}; +void() sin_xatta9 = [ $xatta9, sin_xatta10 ] {ai_face();}; +void() sin_xatta10 = [ $xatta10, sin_xatta11 ] {ai_face();}; +void() sin_xatta11 = [ $xatta11, sin_xatta12 ] {ai_face();}; +void() sin_xatta12 = [ $xatta12, sin_walk1 ] +{ + if (!(self.x_flags & X_SINISTER_FINAL)) + SinisterMissile(); +}; + + +void() sin_xattb1 = [ $xattb1, sin_xattb2 ] {ai_face();}; +void() sin_xattb2 = [ $xattb2, sin_xattb3 ] {ai_face();}; +void() sin_xattb3 = [ $xattb3, sin_xattb4 ] +{ + ai_face(); + + makevectors(self.angles); + spawn_sinister_missile(self.origin + v_right * 4); +}; +void() sin_xattb4 = [ $xattb4, sin_xattb5 ] {ai_face();}; +void() sin_xattb5 = [ $xattb5, sin_xattb6 ] {ai_face();}; +void() sin_xattb6 = [ $xattb6, sin_xattb7 ] +{ + ai_face(); + + makevectors(self.angles); + spawn_sinister_missile(self.origin + v_right * -4); +}; +void() sin_xattb7 = [ $xattb7, sin_xattb8 ] {ai_face();}; +void() sin_xattb8 = [ $xattb8, sin_xattb9 ] {ai_face();}; +void() sin_xattb9 = [ $xattb9, sin_xattb10 ] +{ + ai_face(); + + makevectors(self.angles); + spawn_sinister_missile(self.origin + v_right * 4); +}; +void() sin_xattb10 = [ $xattb10, sin_xattb11 ] {ai_face();}; +void() sin_xattb11 = [ $xattb11, sin_xattb12 ] {ai_face();}; +void() sin_xattb12 = [ $xattb12, sin_walk1 ] +{ + if (!(self.x_flags & X_SINISTER_FINAL)) + SinisterMissile(); +}; + +void() SinisterMissile = +{ + if ((self.x_flags & X_SINISTER_FINAL) && !(self.x_flags & X_MEGA_HIT) && (random() < 0.9)) { + self.count = 0; + sin_sightlaugh1(); + return; + } + + if (random() < 0.7) + sin_xatta1(); + else + sin_xattb1(); +}; + +//============================================================================ + +void() SinNextSpot = +{ + local entity stemp, trav; + + if (!(self.x_flags & X_SINISTER_FINAL)) { + self.state = self.state + 1; + self.enemy = world; + + stemp = find(world, classname, "xmen_sinister_spot"); + while (stemp != world) { + if (stemp.state == self.state) { + spawn_tfog(stemp.origin); + setorigin(self, stemp.origin); + droptofloor(); + self.angles = stemp.angles; + self.velocity = '0 0 0'; + + self.th_stand(); + + return; + } + else + stemp = find(stemp, classname, "xmen_sinister_spot"); + } + + // no spot found, so disappear altogether + remove(self); + } + else { // random teleport + + stemp = find(world, classname, "xmen_sinister_teleport"); + while (stemp != world) { + if ((random() < 0.1) && (vlen(stemp.origin - self.origin) > 128)) { + + self.oldorigin = self.origin; + setorigin(self, stemp.origin); + droptofloor(); + + if (!walkmove(0,0)) { + setorigin(self, self.oldorigin); + } + else { + spawn_tfog(stemp.origin); + + self.angles = stemp.angles; + self.velocity = '0 0 0'; + + self.th_run(); + + trav = find(world, classname, "guided_rocket"); + while (trav != world) { + if (trav.enemy == self) + trav.enemy = world; + + trav = find(trav, classname, "guided_rocket"); + } + + return; + } + } + else { + stemp = find(stemp, classname, "xmen_sinister_teleport"); + if (stemp == world) { + stemp = find(world, classname, "xmen_sinister_teleport"); + } + } + } + + } +}; + +void() sin_diss1 = [ $diss1, sin_diss2 ] {}; +void() sin_diss2 = [ $diss2, sin_diss3 ] {}; +void() sin_diss3 = [ $diss3, sin_diss4 ] {}; +void() sin_diss4 = [ $diss4, sin_diss5 ] {}; +void() sin_diss5 = [ $diss5, sin_diss6 ] {}; +void() sin_diss6 = [ $diss6, SinNextSpot ] {spawn_tfog(self.origin);}; + +//============================================================================ + +void() sin_death1 = [ $death1, sin_death2 ] {}; +void() sin_death2 = [ $death2, sin_death3 ] {}; +void() sin_death3 = [ $death3, sin_death4 ] {}; +void() sin_death4 = [ $death4, sin_death5 ] {}; +void() sin_death5 = [ $death5, sin_death6 ] {}; +void() sin_death6 = [ $death6, sin_death7 ] {}; +void() sin_death7 = [ $death7, sin_death8 ] {}; +void() sin_death8 = [ $death8, sin_death9 ] {}; +void() sin_death9 = [ $death9, sin_death10 ] {}; +void() sin_death10 = [ $death10, sin_death11 ] {}; +void() sin_death11 = [ $death11, sin_death12 ] {}; +void() sin_death12 = [ $death12, sin_death13 ] {}; +void() sin_death13 = [ $death13, sin_death14 ] {}; +void() sin_death14 = [ $death14, sin_death15 ] {}; +void() sin_death15 = [ $death15, sin_death16 ] {}; +void() sin_death16 = [ $death16, sin_death17 ] {}; +void() sin_death17 = [ $death17, sin_death18 ] {}; +void() sin_death18 = [ $death18, sin_death19 ] {}; +void() sin_death19 = [ $death19, sin_death20 ] {}; +void() sin_death20 = [ $death20, sin_death21 ] {}; +void() sin_death21 = [ $death21, sin_death22 ] {}; +void() sin_death22 = [ $death22, sin_death23 ] {}; +void() sin_death23 = [ $death23, sin_death24 ] {}; +void() sin_death24 = [ $death24, sin_death25 ] {}; +void() sin_death25 = [ $death25, sin_death26 ] {}; +void() sin_death26 = [ $death26, sin_death27 ] {}; +void() sin_death27 = [ $death27, sin_death28 ] {}; +void() sin_death28 = [ $death28, sin_death29 ] {}; +void() sin_death29 = [ $death29, sin_death30 ] {}; +void() sin_death30 = [ $death30, sin_death31 ] {sound(self, CHAN_VOICE, "sinister/cackle2.wav", 1, 0);}; +void() sin_death31 = [ $death31, sin_death32 ] {}; +void() sin_death32 = [ $death32, sin_death33 ] {}; +void() sin_death33 = [ $death33, sin_death34 ] {spawn_tfog(self.origin);}; +void() sin_death34 = [ $death34, sin_death34 ] +{ + local entity trav; + + killed_monsters = killed_monsters + 1; + WriteByte (MSG_ALL, SVC_KILLEDMONSTER); // FIXME: reliable broadcast + + trav = find (world, classname, "player"); + while (trav != world) + { + trav.view_ofs = '0 0 0'; + trav.nextthink = time + 0.5; + trav.takedamage = DAMAGE_NO; + trav.solid = SOLID_NOT; + trav.movetype = MOVETYPE_NONE; + trav.modelindex = 0; + trav = find (trav, classname, "player"); + } + + WriteByte (MSG_ALL, SVC_INTERMISSION); + nextmap = "start"; + + intermission_running = 1; + + SUB_UseTargets (); + remove (self); +}; + +//============================================================================ + +// Sinister teleport destination, use self.state to set sequence +void() xmen_sinister; +void() xmen_sinister_spot = +{ + self.classname = "xmen_sinister"; + xmen_sinister(); +}; + +//============================================================================ + +void() xmen_sinister = +{ + if (deathmatch) + { + remove(self); + return; + } + + precache_model ("progs/sinister.mdl"); + precache_model ("progs/sinblast.mdl"); + + precache_sound ("sinister/laugh1.wav"); + precache_sound ("sinister/laugh2.wav"); + precache_sound ("sinister/cackle1.wav"); + precache_sound ("sinister/cackle2.wav"); + precache_sound ("sinister/cackle3.wav"); + precache_sound ("sinister/mrsin1.wav"); + + precache_sound ("sinister/threat1.wav"); + precache_sound ("sinister/threat2.wav"); + precache_sound ("sinister/threat3.wav"); + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + + setmodel (self, "progs/sinister.mdl"); + + setsize (self, VEC_HULL_MIN, VEC_HULL_MAX); + self.health = 99999; + + self.th_stand = sin_stand1; + self.th_walk = sin_stand1; + self.th_run = sin_sightlaugh1; + self.th_pain = SinisterPain; + self.th_die = sin_death1; + self.th_missile = SinisterMissile; + + if (!(self.spawnflags & SPAWNFLAG_CLONE)) + walkmonster_start(); + else { + self.flags = self.flags | FL_GODMODE; + self.think = self.th_stand; + self.nextthink = time + 0.1; + } + + self.health = 99999; +}; + +void() xmen_sinister_final = +{ + self.x_flags = self.x_flags | X_SINISTER_FINAL; + self.classname = "xmen_sinister"; + xmen_sinister(); + + self.th_guard = sin_diss5; + self.th_run = sin_walk1; +}; + +void() xmen_sinister_teleport = {}; \ No newline at end of file diff --git a/skeleton.c b/skeleton.c new file mode 100644 index 0000000..d5f7829 --- /dev/null +++ b/skeleton.c @@ -0,0 +1,102 @@ +/* + -------- + Skeleton + -------- + + All monsters killed with a Flamethrower change to a skeleton to be "finished off" +*/ + +void () skeleton_animate = +{ + self.frame = self.frame + 1; + if (self.frame > (self.start_frame + 12)) + self.frame = self.start_frame; + + self.skin = self.skin + 1; + if (self.skin > 3) + self.skin = 0; + + if (random()*100 < 1) + sound (self, CHAN_AUTO, "zombie/idle_w2.wav", 1, ATTN_STATIC); + + self.think = skeleton_animate; + self.nextthink = time + 0.1; +}; + +void() skeleton_die = +{ + + // play crunch sound, and spawn some bone parts + sound(self, CHAN_BODY, "skeleton/crunch.wav", 1, ATTN_NORM); + + ThrowGib ("progs/gib01.mdl", self.health); + + ThrowGib ("progs/gib02.mdl", self.health); + ThrowGib ("progs/gib02.mdl", self.health); + ThrowGib ("progs/gib02.mdl", self.health); + ThrowGib ("progs/gib02.mdl", self.health); + + ThrowGib ("progs/gib03.mdl", self.health); + ThrowGib ("progs/gib03.mdl", self.health); + ThrowGib ("progs/gib03.mdl", self.health); + ThrowGib ("progs/gib03.mdl", self.health); + + remove(self); +}; + +void(entity e) skeleton_morph = +{ + local float rnd; + + e.classname = "xmen_skeleton"; + setmodel(e, "progs/skel.mdl"); + + // fall from the air + if (e.flags & FL_FLY) { +// e.velocity_z = 100; + +// setmodel(e, "progs/skel.mdl"); + setsize(e, VEC_HULL_MIN, VEC_HULL_MAX); +// setorigin(e, e.origin + '0 0 1'); + + e.flags = e.flags - (e.flags & FL_ONGROUND); + e.flags = e.flags - (e.flags & FL_FLY); + + e.angles_x = 0; + e.angles_z = 0; + } + else { + setsize(e, VEC_HULL_MIN, VEC_HULL_MAX); + setorigin(e, e.origin - '0 0 1' * e.z_ofs); + } + + e.flags = e.flags - (e.flags & FL_GODMODE); + e.x_flags = e.x_flags - (e.x_flags & X_ANGEL_DEFENSE); + + rnd = random() * 3; + if (rnd < 1) { + e.start_frame = 0; + } + else if (rnd < 2) { + e.start_frame = 13; + } + else { + e.start_frame = 26; + } + e.frame = e.start_frame; + + e.health = 1; + + e.think = skeleton_animate; + e.nextthink = time + 0.1; + + e.th_die = skeleton_die; + e.th_pain = skeleton_animate; + e.th_guard = skeleton_animate; + e.th_stand = skeleton_animate; + e.th_melee = skeleton_animate; + e.th_missile = skeleton_animate; + e.th_walk = skeleton_animate; + e.th_run = skeleton_animate; + e.th_guard = SUB_Null; +}; \ No newline at end of file diff --git a/storm.c b/storm.c new file mode 100644 index 0000000..a9144f9 --- /dev/null +++ b/storm.c @@ -0,0 +1,575 @@ +/* +============================================================================== + +Storm + +============================================================================== +*/ + +$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9 +$frame stand10 stand11 stand12 stand13 + +$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 walk9 walk10 walk11 walk12 + +$frame run1 run2 run3 run4 run5 run6 + +$frame wind1 wind2 wind3 wind4 wind5 wind6 wind7 wind8 wind9 +$frame wind10 wind11 wind12 wind13 wind14 wind15 wind16 + +$frame attack1 attack2 attack3 attack4 attack5 attack6 attack7 attack8 attack9 attack10 +$frame attack11 attack12 attack13 attack14 attack15 attack16 attack17 attack18 attack19 attack20 + +$frame paina1 paina2 paina3 paina4 paina5 paina6 + +$frame pain1 pain2 pain3 pain4 pain5 pain6 pain7 pain8 pain9 pain10 +$frame pain11 pain12 pain13 pain14 pain15 pain16 pain17 pain18 pain19 pain20 +$frame pain21 pain22 pain23 pain24 pain25 pain26 pain27 pain28 pain29 pain30 +$frame pain31 pain32 pain33 pain34 pain35 pain36 pain37 pain38 pain39 pain40 + +$frame death1 death2 death3 death4 death5 death6 death7 death8 death9 +$frame death10 death11 death12 death13 death14 death15 death16 + +$frame deata1 deata2 deata3 deata4 deata5 deata6 deata7 deata8 deata9 +$frame deata10 deata11 deata12 deata13 deata14 deata15 deata16 deata17 + +/* +$frame hover1 hover2 hover3 hover4 hover5 hover6 hover7 hover8 +$frame hover9 hover10 hover11 hover12 hover13 hover14 hover15 + +$frame fly1 fly2 fly3 fly4 fly5 fly6 fly7 fly8 fly9 fly10 +$frame fly11 fly12 fly13 fly14 + +$frame magatt1 magatt2 magatt3 magatt4 magatt5 magatt6 magatt7 +$frame magatt8 magatt9 magatt10 magatt11 magatt12 magatt13 + +$frame pain1 pain2 pain3 pain4 + +$frame death1 death2 death3 death4 death5 death6 death7 death8 +*/ + +/* +============================================================================== + +Storm + +If the player moves behind cover before the missile is launched, launch it +at the last visible spot with no velocity leading, in hopes that the player +will duck back out and catch it. +============================================================================== +*/ + +void() storm_run1; +void() storm_wind1; + +float(float drange) DangerousEntityInRange = +{ + local entity trav; + local float strength, dist; + local vector vect, vect_angle; + + trav = findradius(self.origin, drange); + while (trav != world) { + + // check that the object is damage-able and is infront of self + vect = normalize(trav.origin - self.origin); + vect_angle = vectoangles(vect); + + if ((trav != self) && + (trav.movetype) && + (fabs( angle_diff( vect_angle_y, self.angles_y)) < 60)) { // dangerous in range + return TRUE; + } + + trav = trav.chain; + } + + return FALSE; +}; + + +/* +================= +StormCheckAttack +================= +*/ +float() StormCheckAttack = +{ + local vector spot1, spot2; + local entity targ, trav; + local float chance; + + if (time < self.attack_finished) + return FALSE; + if (!enemy_vis) + return FALSE; + + // look for a rocket in close vicinity + if ((self.last_wind < (time - 3)) && (DangerousEntityInRange(128))) { + self.attack_state = AS_SLIDING; + storm_wind1 (); + return FALSE; + } + + if (enemy_range == RANGE_FAR) + { + if (self.attack_state != AS_STRAIGHT) + { + self.attack_state = AS_STRAIGHT; + storm_run1 (); + } + return FALSE; + } + + targ = self.enemy; + +// see if any entities are in the way of the shot + spot1 = self.origin + self.view_ofs; + spot2 = targ.origin + targ.view_ofs; + + traceline (spot1, spot2, FALSE, self); + + if (trace_ent != targ) + { // don't have a clear shot, so move to a side + if (self.attack_state != AS_STRAIGHT) + { + self.attack_state = AS_STRAIGHT; + storm_run1 (); + } + return FALSE; + } + + if ((self.last_wind < (time - 3)) && (vlen(self.enemy.origin - self.origin) < 196)) { + self.attack_state = AS_SLIDING; + storm_wind1 (); + return FALSE; + } + + if (enemy_range == RANGE_MELEE) + chance = 0.4; + else if (enemy_range == RANGE_NEAR) + chance = 0.2; + else if (enemy_range == RANGE_MID) + chance = 0.1; + else + chance = 0; + + if (random () < chance) + { + self.attack_state = AS_MISSILE; + return TRUE; + } + + if (enemy_range == RANGE_MID) + { + if (self.attack_state != AS_STRAIGHT) + { + self.attack_state = AS_STRAIGHT; + storm_run1 (); + } + } + else + { + if (self.attack_state != AS_SLIDING) + { + self.attack_state = AS_SLIDING; + } + } + + return FALSE; +}; + +/* +================= +StormAttackFinished +================= +*/ +float() StormAttackFinished = +{ + if (enemy_range >= RANGE_MID || !enemy_vis) + { + self.attack_state = AS_STRAIGHT; + self.think = storm_run1; + } + else if (self.last_wind < (time - 3)) + { + self.attack_state = AS_SLIDING; + self.think = storm_wind1; + } +}; + +/* +============================================================================== + +FAST ATTACKS + +============================================================================== +*/ + +void() storm_idlesound = +{ +local float wr; + +return; + + wr = random() * 5; + + if (self.waitmin < time) + { + self.waitmin = time + 2; + if (wr > 4.5) + sound (self, CHAN_VOICE, "wizard/widle1.wav", 1, ATTN_IDLE); + if (wr < 1.5) + sound (self, CHAN_VOICE, "wizard/widle2.wav", 1, ATTN_IDLE); + } + return; +}; + +void() storm_stand1 =[ $stand1, storm_stand2 ] {ai_stand();}; +void() storm_stand2 =[ $stand2, storm_stand3 ] {ai_stand();}; +void() storm_stand3 =[ $stand3, storm_stand4 ] {ai_stand();}; +void() storm_stand4 =[ $stand4, storm_stand5 ] {ai_stand();}; +void() storm_stand5 =[ $stand5, storm_stand6 ] {ai_stand();}; +void() storm_stand6 =[ $stand6, storm_stand7 ] {ai_stand();}; +void() storm_stand7 =[ $stand7, storm_stand8 ] {ai_stand();}; +void() storm_stand8 =[ $stand8, storm_stand9 ] {ai_stand();}; +void() storm_stand9 =[ $stand9, storm_stand10 ] {ai_stand();}; +void() storm_stand10 =[ $stand10, storm_stand11 ] {ai_stand();}; +void() storm_stand11 =[ $stand11, storm_stand12 ] {ai_stand();}; +void() storm_stand12 =[ $stand12, storm_stand13 ] {ai_stand();}; +void() storm_stand13 =[ $stand13, storm_stand1 ] {ai_stand();}; + +void() storm_walk1 =[ $walk1, storm_walk2 ] {ai_walk(8); +storm_idlesound();}; +void() storm_walk2 =[ $walk2, storm_walk3 ] {ai_walk(8);}; +void() storm_walk3 =[ $walk3, storm_walk4 ] {ai_walk(8);}; +void() storm_walk4 =[ $walk4, storm_walk5 ] {ai_walk(8);}; +void() storm_walk5 =[ $walk5, storm_walk6 ] {ai_walk(8);}; +void() storm_walk6 =[ $walk6, storm_walk7 ] {ai_walk(8);}; +void() storm_walk7 =[ $walk7, storm_walk8 ] {ai_walk(8);}; +void() storm_walk8 =[ $walk8, storm_walk9 ] {ai_walk(8);}; +void() storm_walk9 =[ $walk9, storm_walk10 ] {ai_walk(8);}; +void() storm_walk10 =[ $walk10, storm_walk11 ] {ai_walk(8);}; +void() storm_walk11 =[ $walk11, storm_walk12 ] {ai_walk(8);}; +void() storm_walk12 =[ $walk12, storm_walk1 ] {ai_walk(8);}; + +void() set_offset = +{ + self.origin_z = self.origin_z - self.z_ofs; + self.z_ofs = self.z_ofs + (self.z_ofs_vel * random() * 2); + + if (self.z_ofs >= (MAX_Z_OFS)) { + self.z_ofs_vel = -1 * self.z_ofs_vel; + self.z_ofs = MAX_Z_OFS; + } + else if (self.z_ofs <= 0) { + self.z_ofs_vel = -1 * self.z_ofs_vel; + self.z_ofs = 0; + } + else { // add some randomness + if (random() <= 0.1) + self.z_ofs_vel = -1 * self.z_ofs_vel; + } + + self.origin_z = self.origin_z + self.z_ofs; +}; + +void() storm_run1 =[ $run1, storm_run2 ] { +set_offset(); +ai_run(6); +storm_idlesound();}; +void() storm_run2 =[ $run2, storm_run3 ] {ai_run(6);set_offset();}; +void() storm_run3 =[ $run3, storm_run4 ] {ai_run(6);set_offset();}; +void() storm_run4 =[ $run4, storm_run5 ] {ai_run(6);set_offset();}; +void() storm_run5 =[ $run5, storm_run6 ] {ai_run(6);set_offset();}; +void() storm_run6 =[ $run6, storm_run1 ] {ai_run(6);set_offset();}; + +void() storm_Wind = +{ + local entity trav; + local float strength, dist; + local vector vect, vect_angle; + + trav = findradius(self.origin, 256); + while (trav != world) { + + // check that the object is damage-able and is infront of self + vect = normalize(trav.origin - self.origin); + vect_angle = vectoangles(vect); + + if ((trav != self) && + (trav.classname == "player") && + (fabs( angle_diff( vect_angle_y, self.angles_y)) < 35)) { // give em some wind + + strength = 200; + dist = vlen(trav.origin - self.origin); + if (dist > 128) { // reduce strength of blast + strength = ((dist - 128) / 128) * strength; + } + + // blast now + trav.flags = trav.flags - (trav.flags & FL_ONGROUND); + trav.velocity = (trav.velocity * 0.5) + (vect * 600); + trav.velocity_z = 300; + + trav.angles = trav.v_angle = self.angles; + trav.punchangle_x = -20; + trav.fixangle = TRUE; + } + + trav = trav.chain; + } + + self.last_wind = time; +}; + +void() storm_wind1 =[ $wind1, storm_wind2 ] {ai_face(); self.nextthink = time + 0.05;}; +void() storm_wind2 =[ $wind2, storm_wind3 ] {ai_face(); self.nextthink = time + 0.05;}; +void() storm_wind3 =[ $wind3, storm_wind4 ] {ai_face(); self.nextthink = time + 0.05;}; +void() storm_wind4 =[ $wind4, storm_wind5 ] {ai_face(); self.nextthink = time + 0.05;}; +void() storm_wind5 =[ $wind5, storm_wind6 ] {ai_face(); self.nextthink = time + 0.05;}; +void() storm_wind6 =[ $wind6, storm_wind7 ] {ai_face(); self.nextthink = time + 0.05;}; +void() storm_wind7 =[ $wind7, storm_wind8 ] {ai_face(); sound (self, CHAN_WEAPON, "storm/w_attack.wav", 1, ATTN_NORM); self.nextthink = time + 0.05;}; +void() storm_wind8 =[ $wind8, storm_wind9 ] {ai_face(); self.nextthink = time + 0.05;}; +void() storm_wind9 =[ $wind9, storm_wind10 ] {ai_face(); self.nextthink = time + 0.05;}; +void() storm_wind10 =[ $wind10, storm_wind11 ] {ai_face(); storm_Wind(); self.nextthink = time + 0.05;}; +void() storm_wind11 =[ $wind11, storm_wind12 ] {ai_face(); self.nextthink = time + 0.05;}; +void() storm_wind12 =[ $wind12, storm_wind13 ] {ai_face(); self.nextthink = time + 0.05;}; +void() storm_wind13 =[ $wind13, storm_wind14 ] {ai_face(); self.nextthink = time + 0.05;}; +void() storm_wind14 =[ $wind14, storm_wind15 ] {ai_face(); self.nextthink = time + 0.05;}; +void() storm_wind15 =[ $wind15, storm_wind16 ] {ai_face(); self.nextthink = time + 0.05;}; +void() storm_wind16 =[ $wind16, storm_run1 ] {ai_face(); self.nextthink = time + 0.05;}; + +void() StormCastLightning = +{ + local vector org, dir; + + self.effects = self.effects | EF_MUZZLEFLASH; + + ai_face (); + + org = self.origin + '0 0 40'; + + dir = self.enemy.origin + '0 0 16' - org - (self.enemy.velocity * 0.5); + dir = normalize (dir); + + traceline (org, self.origin + dir*1200, FALSE, self); + sound (self, CHAN_WEAPON, "storm/l_attack.wav", 1, ATTN_NORM); + + WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); + WriteByte (MSG_BROADCAST, TE_LIGHTNING3); + WriteEntity (MSG_BROADCAST, self); + WriteCoord (MSG_BROADCAST, org_x); + WriteCoord (MSG_BROADCAST, org_y); + WriteCoord (MSG_BROADCAST, org_z - 20); + WriteCoord (MSG_BROADCAST, trace_endpos_x); + WriteCoord (MSG_BROADCAST, trace_endpos_y); + WriteCoord (MSG_BROADCAST, trace_endpos_z); + + LightningDamage (org, trace_endpos + dir * 8, self, 20); +}; + +void() storm_fast1 =[ $attack1, storm_fast2 ] {ai_face();}; +void() storm_fast2 =[ $attack2, storm_fast3 ] {ai_face();}; +void() storm_fast3 =[ $attack3, storm_fast4 ] {ai_face();}; +void() storm_fast4 =[ $attack4, storm_fast5 ] {ai_face();}; +void() storm_fast5 =[ $attack5, storm_fast6 ] {ai_face();}; +void() storm_fast6 =[ $attack6, storm_fast7 ] {ai_face();}; +void() storm_fast7 =[ $attack7, storm_fast8 ] {ai_face();}; +void() storm_fast8 =[ $attack8, storm_fast9 ] {ai_face();}; +void() storm_fast9 =[ $attack9, storm_fast10 ] {ai_face();}; +void() storm_fast10 =[ $attack10, storm_fast11 ] {ai_face();}; +void() storm_fast11 =[ $attack11, storm_fast12 ] {ai_face(); StormCastLightning();}; +void() storm_fast12 =[ $attack12, storm_fast13 ] {ai_face();}; +void() storm_fast13 =[ $attack13, storm_fast14 ] {ai_face();}; +void() storm_fast14 =[ $attack14, storm_fast15 ] {ai_face();}; +void() storm_fast15 =[ $attack15, storm_fast16 ] {ai_face();}; +void() storm_fast16 =[ $attack16, storm_fast17 ] {ai_face();}; +void() storm_fast17 =[ $attack17, storm_fast18 ] {ai_face();}; +void() storm_fast18 =[ $attack18, storm_fast19 ] {ai_face();}; +void() storm_fast19 =[ $attack19, storm_fast20 ] {ai_face();}; +void() storm_fast20 =[ $attack20, storm_run1 ] {ai_face();SUB_AttackFinished(2);StormAttackFinished ();}; + +void() storm_pain1 =[ $pain1, storm_pain2 ] {self.nextthink = time + 0.05;}; +void() storm_pain2 =[ $pain2, storm_pain3 ] {self.nextthink = time + 0.05;}; +void() storm_pain3 =[ $pain3, storm_pain4 ] {self.nextthink = time + 0.05;}; +void() storm_pain4 =[ $pain4, storm_pain5 ] {self.nextthink = time + 0.05;}; +void() storm_pain5 =[ $pain5, storm_pain6 ] {self.nextthink = time + 0.05;}; +void() storm_pain6 =[ $pain6, storm_pain7 ] {self.nextthink = time + 0.05;}; +void() storm_pain7 =[ $pain7, storm_pain8 ] {self.nextthink = time + 0.05;}; +void() storm_pain8 =[ $pain8, storm_pain9 ] {self.nextthink = time + 0.05;}; +void() storm_pain9 =[ $pain9, storm_pain10 ] {self.nextthink = time + 0.05;}; +void() storm_pain10 =[ $pain10, storm_pain11 ] {self.nextthink = time + 0.05;}; +void() storm_pain11 =[ $pain11, storm_pain12 ] {self.nextthink = time + 0.05;}; +void() storm_pain12 =[ $pain12, storm_pain13 ] {self.nextthink = time + 0.05;}; +void() storm_pain13 =[ $pain13, storm_pain14 ] {self.nextthink = time + 0.05;}; +void() storm_pain14 =[ $pain14, storm_pain15 ] {self.nextthink = time + 0.05;}; +void() storm_pain15 =[ $pain15, storm_pain16 ] {self.nextthink = time + 0.05;}; +void() storm_pain16 =[ $pain16, storm_pain17 ] {self.nextthink = time + 0.05;}; +void() storm_pain17 =[ $pain17, storm_pain18 ] {self.nextthink = time + 0.05;}; +void() storm_pain18 =[ $pain18, storm_pain19 ] {self.nextthink = time + 0.05;}; +void() storm_pain19 =[ $pain19, storm_pain20 ] {self.nextthink = time + 0.05;}; +void() storm_pain20 =[ $pain20, storm_pain21 ] {self.nextthink = time + 0.05;}; +void() storm_pain21 =[ $pain21, storm_pain22 ] {self.nextthink = time + 0.05;}; +void() storm_pain22 =[ $pain22, storm_pain23 ] {self.nextthink = time + 0.05;}; +void() storm_pain23 =[ $pain23, storm_pain24 ] {self.nextthink = time + 0.05;}; +void() storm_pain24 =[ $pain24, storm_pain25 ] {self.nextthink = time + 0.05;}; +void() storm_pain25 =[ $pain25, storm_pain26 ] {self.nextthink = time + 0.05;}; +void() storm_pain26 =[ $pain26, storm_pain27 ] {self.nextthink = time + 0.05;}; +void() storm_pain27 =[ $pain27, storm_pain28 ] {self.nextthink = time + 0.05;}; +void() storm_pain28 =[ $pain28, storm_pain29 ] {self.nextthink = time + 0.05;}; +void() storm_pain29 =[ $pain29, storm_pain30 ] {self.nextthink = time + 0.05;}; +void() storm_pain30 =[ $pain30, storm_pain31 ] {self.in_pain = FALSE;self.nextthink = time + 0.05;}; +void() storm_pain31 =[ $pain31, storm_pain32 ] {self.nextthink = time + 0.05;}; +void() storm_pain32 =[ $pain32, storm_pain33 ] {self.nextthink = time + 0.05;}; +void() storm_pain33 =[ $pain33, storm_pain34 ] {self.nextthink = time + 0.05;}; +void() storm_pain34 =[ $pain34, storm_pain35 ] {self.nextthink = time + 0.05;}; +void() storm_pain35 =[ $pain35, storm_pain36 ] {self.nextthink = time + 0.05;}; +void() storm_pain36 =[ $pain36, storm_pain37 ] {self.nextthink = time + 0.05;}; +void() storm_pain37 =[ $pain37, storm_pain38 ] {self.nextthink = time + 0.05;}; +void() storm_pain38 =[ $pain38, storm_pain39 ] {self.nextthink = time + 0.05;}; +void() storm_pain39 =[ $pain39, storm_pain40 ] {self.nextthink = time + 0.05;}; +void() storm_pain40 =[ $pain40, storm_run1 ] {self.nextthink = time + 0.05;}; + +void() storm_painb1 =[ $paina1, storm_painb2 ] {}; +void() storm_painb2 =[ $paina2, storm_painb3 ] {}; +void() storm_painb3 =[ $paina3, storm_painb4 ] {}; +void() storm_painb4 =[ $paina4, storm_painb5 ] {}; +void() storm_painb5 =[ $paina5, storm_painb6 ] {}; +void() storm_painb6 =[ $paina6, storm_run1 ] {}; + + +void() storm_death1 =[ $death1, storm_death2 ] { + +self.velocity_x = -200 + 400*random(); +self.velocity_y = -200 + 400*random(); +self.velocity_z = 100 + 100*random(); +self.flags = self.flags - (self.flags & FL_ONGROUND); +self.angles_x = 0; +self.angles_z = 0; +}; +void() storm_death2 =[ $death2, storm_death3 ] {}; +void() storm_death3 =[ $death3, storm_death4 ]{self.solid = SOLID_NOT;}; +void() storm_death4 =[ $death4, storm_death5 ] {}; +void() storm_death5 =[ $death5, storm_death6 ] {}; +void() storm_death6 =[ $death6, storm_death7 ] {}; +void() storm_death7 =[ $death7, storm_death8 ] {}; +void() storm_death8 =[ $death8, storm_death9 ] {}; +void() storm_death9 =[ $death9, storm_death10 ] {}; +void() storm_death10 =[ $death10, storm_death11 ] {}; +void() storm_death11 =[ $death11, storm_death12 ] {}; +void() storm_death12 =[ $death12, storm_death13 ] {}; +void() storm_death13 =[ $death13, storm_death14 ] {}; +void() storm_death14 =[ $death14, storm_death15 ] {}; +void() storm_death15 =[ $death15, storm_death16 ] {}; +void() storm_death16 =[ $death16, storm_death16 ] {}; + +void() storm_deata1 =[ $deata1, storm_deata2 ] { + +self.velocity_x = -200 + 400*random(); +self.velocity_y = -200 + 400*random(); +self.velocity_z = 100 + 100*random(); +self.flags = self.flags - (self.flags & FL_ONGROUND); +self.angles_x = 0; +self.angles_z = 0; +}; +void() storm_deata2 =[ $deata2, storm_deata3 ] {}; +void() storm_deata3 =[ $deata3, storm_deata4 ]{self.solid = SOLID_NOT;}; +void() storm_deata4 =[ $deata4, storm_deata5 ] {}; +void() storm_deata5 =[ $deata5, storm_deata6 ] {}; +void() storm_deata6 =[ $deata6, storm_deata7 ] {}; +void() storm_deata7 =[ $deata7, storm_deata8 ] {}; +void() storm_deata8 =[ $deata8, storm_deata9 ] {}; +void() storm_deata9 =[ $deata9, storm_deata10 ] {}; +void() storm_deata10 =[ $deata10, storm_deata11 ] {}; +void() storm_deata11 =[ $deata11, storm_deata12 ] {}; +void() storm_deata12 =[ $deata12, storm_deata13 ] {}; +void() storm_deata13 =[ $deata13, storm_deata14 ] {}; +void() storm_deata14 =[ $deata14, storm_deata15 ] {}; +void() storm_deata15 =[ $deata15, storm_deata16 ] {}; +void() storm_deata16 =[ $deata16, storm_deata17 ] {}; +void() storm_deata17 =[ $deata17, storm_deata17 ] {}; + +void() storm_die = +{ + + FemaleDeathSound(); + + if (!(self.deadflag == DEAD_DEAD)) { + if (random() < 0.5) + storm_death1 (); + else + storm_deata1 (); + } + + self.deadflag = DEAD_DEAD; +}; + + +void(entity attacker, float damage) storm_Pain = +{ + + if (self.in_pain) { + return; + } + + self.in_pain = TRUE; + + FemalePainSound(); + + if (random()*70 > damage) + return; // didn't flinch + + if ((damage > 30) && (random() < 0.3)) + storm_pain1 (); + else + storm_painb1 (); +}; + + +void() storm_Missile = +{ + storm_fast1(); +}; + +/*QUAKED monster_shambler (1 0 0) (-16 -16 -24) (16 16 40) Ambush +*/ +void() monster_shambler = +{ + remove(self); +}; + +void() xmen_storm = +{ + if (deathmatch) + { + remove(self); + return; + } + + precache_model ("progs/storm2.mdl"); + + precache_sound ("wizard/hit.wav"); // used by c code + precache_sound ("storm/l_attack.wav"); + precache_sound ("storm/w_attack.wav"); + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + + setmodel (self, "progs/storm2.mdl"); + + setsize (self, '-16 -16 -24', '16 16 64'); + self.health = 150 + cvar("skill")*10; + + self.th_stand = storm_stand1; + self.th_walk = storm_walk1; + self.th_run = storm_run1; + self.th_missile = storm_Missile; + self.th_pain = storm_Pain; + self.th_die = storm_die; + + self.z_ofs = 0; + self.z_ofs_vel = 1; + +// flymonster_start (); + walkmonster_start (); +}; \ No newline at end of file diff --git a/tripwire.c b/tripwire.c new file mode 100644 index 0000000..ced1f0b --- /dev/null +++ b/tripwire.c @@ -0,0 +1,145 @@ +/* Begin Xmen +Laser Tripwire code revision 2 +-cl2- + +Additions: +r2: + Cleaned up the code + Changed BlowMeUp() to use self.dmg and to call BecomeExplosion() + +Files involved: +tripwire.qc (this file) +client.qc (obituaries) + +How to implement in a .map file: +There are two entities that make up a trip wire: +"tripwire_startpoint" and "tripwire_endpoint". +tripwire_startpoint should have a "target" field equal to it's respective +tripwire_endpoint's "targetname" field. (i.e. the endpoint is targeted by the startpoint) + +Just stick the two entities near walls (within 64 units). Although it is not *essential*, +the two entities should have an unobstructed view of each other, otherwise the 'laser beam' +effect will not be too believable ;) +*/ + +void () BlowMeUp = +{ +local entity oldself; + +if (self.deadflag) + return; + +self.deadflag = DEAD_DEAD; + +T_RadiusDamage (self, self, self.dmg, self); +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(); +}; + +// Tripwire scan - watch for some dummy to cross the line. +void () tripwire_scan = +{ +traceline(self.origin, self.owner.origin, FALSE, self); +if (trace_fraction != 1) + { + self.owner.think = BlowMeUp; + self.owner.nextthink = time + 0.1; + self.think = BlowMeUp; + self.nextthink = time + 0.1; + return; + } +self.nextthink = time + 0.1; +}; + +// Tripwire init +void () tripwire_kickit = +{ +local entity endpoint; +local vector vec,org; +local vector norm; + +endpoint = find(world, targetname, self.target); +// Im using self.owner to knock out a find() in tripwire_scan... +self.owner = endpoint; +vec = normalize(endpoint.origin - self.origin); + +traceline(self.origin, self.origin - vec * 64, TRUE, self); +norm = trace_plane_normal; +org = trace_endpos; +self.angles = vectoangles(norm); +makevectors(self.angles); +setorigin(self, org); + +self.health = 1; +self.th_die = BlowMeUp; +self.takedamage = DAMAGE_YES; +self.solid = SOLID_BBOX; +setsize(self, '-8 -8 -8', '8 8 8'); + + +traceline(endpoint.origin, endpoint.origin + vec * 64, TRUE, self); +norm = trace_plane_normal; +org = trace_endpos; +endpoint.angles = vectoangles(norm); +makevectors(endpoint.angles); +setorigin(endpoint, org); + +endpoint.health = 1; +endpoint.th_die = BlowMeUp; +endpoint.takedamage = DAMAGE_YES; +endpoint.solid = SOLID_BBOX; +setsize(endpoint, '-8 -8 -8', '8 8 8'); + +self.nextthink = time + 0.1; +self.think = tripwire_scan; +}; + +// Tripwire endpoint spawn + +void () tripwire_endpoint = +{ +if (deathmatch) { + remove(self); + return; +} + +if (!self.dmg) self.dmg = 120; +if (!self.targetname) + { + objerror("Tripwire_endpoint has no targetname.\n"); + } + +precache_model("progs/tripwire.mdl"); +setmodel(self, "progs/tripwire.mdl"); +}; + +// Tripwire startpoint spawn + +void () tripwire_startpoint = +{ +if (deathmatch) { + remove(self); + return; +} + +if (!self.dmg) self.dmg = 120; +if (!self.target) + { + objerror("Tripwire_startpoint has no target.\n"); + } + +precache_model("progs/tripwire.mdl"); +setmodel(self, "progs/tripwire.mdl"); + +self.skin = 1; + +self.nextthink = time + 0.1; +self.think = tripwire_kickit; // Give tripwire_endpoint a chance to spawn +}; + +// End Xmen + diff --git a/wgun.c b/wgun.c new file mode 100644 index 0000000..f2be75a --- /dev/null +++ b/wgun.c @@ -0,0 +1,51 @@ +$modelname wgun +$cd \games\quake\editors\util3d\meshes\wgun +$scale 2.884615 +$origin 0 -6 -5 +$base wgunbase +$skin wgunbase +$skin wgunbas2 +$skin wgunbas3 +$skin wgunbas4 + +$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9 +$frame stand10 stand11 stand12 stand13 + +$frame stgun1 stgun2 stgun3 stgun4 stgun5 stgun6 stgun7 stgun8 stgun9 +$frame stgun10 stgun11 stgun12 stgun13 + +$frame run1 run2 run3 run4 run5 run6 + +$frame rungun1 rungun2 rungun3 rungun4 rungun5 rungun6 + +$frame pain1 pain2 pain3 pain4 pain5 pain6 + +$frame pgun1 pgun2 pgun3 pgun4 pgun5 pgun6 + +$frame deatha1 deatha2 deatha3 deatha4 deatha5 deatha6 deatha7 deatha8 deatha9 +$frame deatha10 deatha11 deatha12 + +$frame dguna1 dguna2 dguna3 dguna4 dguna5 dguna6 dguna7 dguna8 dguna9 +$frame dguna10 dguna11 dguna12 + +$frame deathb1 deathb2 deathb3 deathb4 deathb5 deathb6 deathb7 deathb8 deathb9 +$frame deathb10 deathb11 deathb12 + +$frame dgunb1 dgunb2 dgunb3 dgunb4 dgunb5 dgunb6 dgunb7 dgunb8 dgunb9 +$frame dgunb10 dgunb11 dgunb12 + +$frame shot1 shot2 shot3 shot4 shot5 shot6 shot7 shot8 shot9 +$frame shot10 shot11 shot12 shot13 shot14 shot15 shot16 shot17 shot18 + +$frame rock1 rock2 rock3 rock4 rock5 rock6 rock7 rock8 rock9 +$frame rock10 rock11 rock12 + +$frame chain1 chain2 chain3 chain4 chain5 chain6 + +$frame bolt1 bolt2 bolt3 bolt4 bolt5 bolt6 + +$frame xatta1 xatta2 xatta3 xatta4 xatta5 xatta6 xatta7 xatta8 xatta9 xatta10 +$frame xatta11 xatta12 + +$frame xattb1 xattb2 xattb3 xattb4 xattb5 xattb6 xattb7 xattb8 +$frame xattb9 xattb10 xattb11 xattb12 \ No newline at end of file diff --git a/wolvie.c b/wolvie.c new file mode 100644 index 0000000..1d7035d --- /dev/null +++ b/wolvie.c @@ -0,0 +1,736 @@ +/* +============================================================================== + +WOLVERINE + +============================================================================== +*/ + +$cd id1/models/demon3 +$scale 0.8 +$origin 0 0 24 +$base base +$skin base + +.float in_pain; + +$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9 +$frame stand10 stand11 stand12 stand13 + +$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 + +$frame run1 run2 run3 run4 run5 run6 + +$frame leap1 leap2 leap3 leap4 leap5 leap6 leap7 leap8 leap9 leap10 +$frame leap11 leap12 + +$frame pain1 pain2 pain3 pain4 pain5 pain6 + +$frame paina1 paina2 paina3 paina4 paina5 paina6 paina7 paina8 paina9 paina10 +$frame paina11 paina12 paina13 paina14 paina15 paina16 paina17 paina18 paina19 paina20 +$frame paina21 paina22 paina23 paina24 paina25 paina26 paina27 paina28 paina29 paina30 +$frame paina31 paina32 paina33 paina34 paina35 paina36 paina37 paina38 + +$frame death1 death2 death3 death4 death5 death6 death7 death8 death9 +$frame death10 death11 death12 death13 death14 death15 death16 death17 + +$frame rise1 rise2 rise3 rise4 rise5 rise6 rise7 rise8 rise9 +$frame rise10 rise11 rise12 rise13 rise14 rise15 rise16 rise17 rise18 rise19 rise20 +$frame rise21 rise22 rise23 rise24 rise25 rise26 rise27 rise28 rise29 rise30 rise31 + +$frame deata1 deata2 deata3 deata4 deata5 deata6 deata7 deata8 deata9 deata10 +$frame deata11 deata12 deata13 deata14 deata15 deata16 deata17 deata18 deata19 deata20 +$frame deata21 deata22 deata23 deata24 deata25 deata26 deata27 deata28 deata29 deata30 +$frame deata31 deata32 deata33 deata34 deata35 deata36 deata37 deata38 deata39 deata40 +$frame deata41 deata42 deata43 deata44 deata45 deata46 deata47 deata48 deata49 + +$frame risea1 risea2 risea3 risea4 risea5 risea6 risea7 risea8 risea9 risea10 +$frame risea11 risea12 risea13 risea14 risea15 risea16 risea17 risea18 risea19 risea20 +$frame risea21 risea22 risea23 risea24 risea25 risea26 risea27 risea28 risea29 risea30 +$frame risea31 risea32 risea33 risea34 risea35 risea36 risea37 risea38 risea39 risea40 +$frame risea41 risea42 risea43 risea44 risea45 risea46 risea47 risea48 risea49 risea50 +$frame risea51 risea52 + +$frame attacka1 attacka2 attacka3 attacka4 attacka5 attacka6 attacka7 attacka8 +$frame attacka9 attacka10 attacka11 attacka12 attacka13 attacka14 attacka15 + +//============================================================================ + +void() Demon_JumpTouch; + +void() demon1_stand1 =[ $stand1, demon1_stand2 ] { + ai_stand(); + sound(self, CHAN_AUTO, "wolvie/breath.wav", 1, 3);}; +void() demon1_stand2 =[ $stand2, demon1_stand3 ] {ai_stand();}; +void() demon1_stand3 =[ $stand3, demon1_stand4 ] {ai_stand();}; +void() demon1_stand4 =[ $stand4, demon1_stand5 ] {ai_stand();}; +void() demon1_stand5 =[ $stand5, demon1_stand6 ] {ai_stand();}; +void() demon1_stand6 =[ $stand6, demon1_stand7 ] {ai_stand();}; +void() demon1_stand7 =[ $stand7, demon1_stand8 ] {ai_stand();}; +void() demon1_stand8 =[ $stand8, demon1_stand9 ] {ai_stand();}; +void() demon1_stand9 =[ $stand9, demon1_stand10 ] {ai_stand();}; +void() demon1_stand10 =[ $stand10, demon1_stand11 ] {ai_stand();}; +void() demon1_stand11 =[ $stand11, demon1_stand12 ] {ai_stand();}; +void() demon1_stand12 =[ $stand12, demon1_stand13 ] {ai_stand();}; +void() demon1_stand13 =[ $stand13, demon1_stand1 ] {ai_stand();}; + +void() demon1_walk1 =[ $walk1, demon1_walk2 ] {ai_walk(3);}; +void() demon1_walk2 =[ $walk2, demon1_walk3 ] {ai_walk(10);}; +void() demon1_walk3 =[ $walk3, demon1_walk4 ] {ai_walk(9);}; +void() demon1_walk4 =[ $walk4, demon1_walk5 ] {ai_walk(10);}; +void() demon1_walk5 =[ $walk5, demon1_walk6 ] {ai_walk(3);}; +void() demon1_walk6 =[ $walk6, demon1_walk7 ] {ai_walk(8);}; +void() demon1_walk7 =[ $walk7, demon1_walk8 ] {ai_walk(7);}; +void() demon1_walk8 =[ $walk8, demon1_walk1 ] {ai_walk(10);}; + +void() demon1_run1 =[ $run1, demon1_run2 ] { + ai_run(15); + /*sound(self, CHAN_AUTO, "wolvie/step.wav", 1, ATTN_NORM);*/}; +void() demon1_run2 =[ $run2, demon1_run3 ] {ai_run(12);}; +void() demon1_run3 =[ $run3, demon1_run4 ] {ai_run(28);}; +void() demon1_run4 =[ $run4, demon1_run5 ] {ai_run(15);}; +void() demon1_run5 =[ $run5, demon1_run6 ] { + ai_run(12); + /*sound(self, CHAN_AUTO, "wolvie/step.wav", 1, ATTN_NORM);*/}; +void() demon1_run6 =[ $run6, demon1_run1 ] {ai_run(28);}; + +void() SetJumpAngle = +{ + local vector vel; + + vel = normalize(self.velocity); + self.angles = vectoangles(vel); + if (self.angles_x < 0) + self.angles_x = 0; +}; + +void() demon1_jump1 =[ $leap1, demon1_jump2 ] {ai_face();}; +void() demon1_jump2 =[ $leap2, demon1_jump3 ] {ai_face();}; +void() demon1_jump3 =[ $leap3, demon1_jump4 ] {ai_face();}; +void() demon1_jump4 =[ $leap4, demon1_jump5 ] +{ + + ai_face(); + + self.touch = Demon_JumpTouch; + + self.angles = vectoangles(self.enemy.origin - self.origin); + self.angles_x = 0; + makevectors (self.angles); + + self.origin_z = self.origin_z + 1; + v_forward_z = -1 * v_forward_z; + self.velocity = v_forward * 700 + '0 0 150'; + if (self.flags & FL_ONGROUND) + self.flags = self.flags - FL_ONGROUND; +}; +void() demon1_jump5 =[ $leap5, demon1_jump6 ] {SetJumpAngle();}; +void() demon1_jump6 =[ $leap6, demon1_jump7 ] {SetJumpAngle();}; +void() demon1_jump7 =[ $leap7, demon1_jump8 ] {SetJumpAngle();}; +void() demon1_jump8 =[ $leap8, demon1_jump9 ] {SetJumpAngle();}; +void() demon1_jump9 =[ $leap9, demon1_jump10 ] +{ + SetJumpAngle(); +}; +void() demon1_jump10 =[ $leap10, demon1_jump1 ] { +self.nextthink = time + 3; +// if three seconds pass, assume demon is stuck and jump again +}; + +void() demon1_jump11 =[ $leap11, demon1_jump12 ] {}; +void() demon1_jump12 =[ $leap12, demon1_walk1 ] {self.angles_x = 0;}; + +float() CheckDemonMelee; +void() demon1_atta1 =[ $attacka1, demon1_atta2 ] {ai_charge(5);}; +void() demon1_atta2 =[ $attacka2, demon1_atta3 ] {ai_charge(5);}; +void() demon1_atta3 =[ $attacka3, demon1_atta4 ] {ai_charge(5);}; +void() demon1_atta4 =[ $attacka4, demon1_atta5 ] {ai_charge(5);}; +void() demon1_atta5 =[ $attacka5, demon1_atta6 ] {ai_charge(5); Demon_Melee(200);}; +void() demon1_atta6 =[ $attacka6, demon1_atta7 ] {ai_charge(5);}; +void() demon1_atta7 =[ $attacka7, demon1_atta8 ] +{ + ai_charge(5); + + if (vlen(self.enemy.origin - self.origin) > 100) { // abort attack + self.think = self.th_run; + } +}; +void() demon1_atta8 =[ $attacka8, demon1_atta9 ] {ai_charge(5);}; +void() demon1_atta9 =[ $attacka9, demon1_atta10] {ai_charge(5);}; +void() demon1_atta10 =[ $attacka10, demon1_atta11] {ai_charge(5);}; +void() demon1_atta11 =[ $attacka11, demon1_atta12] +{ + local float rnd; + + Demon_Melee(-200); +}; +void() demon1_atta12 =[ $attacka12, demon1_atta13] {ai_charge(5);}; +void() demon1_atta13 =[ $attacka13, demon1_atta14] {ai_charge(5);}; +void() demon1_atta14 =[ $attacka14, demon1_atta15] {ai_charge(5);}; +void() demon1_atta15 =[ $attacka15, demon1_run1] { + ai_charge(5); + if (CheckDemonMelee()) { + if (self.enemy.health > 0) + self.think = demon1_atta1; + else + self.think = self.th_walk; + } +}; + +void() demon1_pain1 =[ $pain1, demon1_pain2 ] {self.in_pain = TRUE;}; +void() demon1_pain2 =[ $pain2, demon1_pain3 ] {}; +void() demon1_pain3 =[ $pain3, demon1_pain4 ] {}; +void() demon1_pain4 =[ $pain4, demon1_pain5 ] {}; +void() demon1_pain5 =[ $pain5, demon1_pain6 ] {}; +void() demon1_pain6 =[ $pain6, demon1_run1 ] {self.in_pain = FALSE;}; + +void() demon1_paina1 =[ $paina1, demon1_paina2 ] {self.in_pain = TRUE;}; +void() demon1_paina2 =[ $paina2, demon1_paina3 ] {}; +void() demon1_paina3 =[ $paina3, demon1_paina4 ] {}; +void() demon1_paina4 =[ $paina4, demon1_paina5 ] {}; +void() demon1_paina5 =[ $paina5, demon1_paina6 ] {}; +void() demon1_paina6 =[ $paina6, demon1_paina7 ] {}; +void() demon1_paina7 =[ $paina7, demon1_paina8 ] {}; +void() demon1_paina8 =[ $paina8, demon1_paina9 ] {}; +void() demon1_paina9 =[ $paina9, demon1_paina10 ] {}; +void() demon1_paina10 =[ $paina10, demon1_paina11 ] {}; +void() demon1_paina11 =[ $paina11, demon1_paina12 ] {}; +void() demon1_paina12 =[ $paina12, demon1_paina13 ] {}; +void() demon1_paina13 =[ $paina13, demon1_paina14 ] {}; +void() demon1_paina14 =[ $paina14, demon1_paina15 ] {}; +void() demon1_paina15 =[ $paina15, demon1_paina16 ] {}; +void() demon1_paina16 =[ $paina16, demon1_paina17 ] {}; +void() demon1_paina17 =[ $paina17, demon1_paina18 ] {}; +void() demon1_paina18 =[ $paina18, demon1_paina19 ] {}; +void() demon1_paina19 =[ $paina19, demon1_paina20 ] {}; +void() demon1_paina20 =[ $paina20, demon1_paina21 ] {}; +void() demon1_paina21 =[ $paina21, demon1_paina22 ] {}; +void() demon1_paina22 =[ $paina22, demon1_paina23 ] {}; +void() demon1_paina23 =[ $paina23, demon1_paina24 ] {}; +void() demon1_paina24 =[ $paina24, demon1_paina25 ] {}; +void() demon1_paina25 =[ $paina25, demon1_paina26 ] {}; +void() demon1_paina26 =[ $paina26, demon1_paina27 ] {}; +void() demon1_paina27 =[ $paina27, demon1_paina28 ] {}; +void() demon1_paina28 =[ $paina28, demon1_paina29 ] {}; +void() demon1_paina29 =[ $paina29, demon1_paina30 ] {}; +void() demon1_paina30 =[ $paina30, demon1_paina31 ] {}; +void() demon1_paina31 =[ $paina31, demon1_paina32 ] {}; +void() demon1_paina32 =[ $paina32, demon1_paina33 ] {}; +void() demon1_paina33 =[ $paina33, demon1_paina34 ] {}; +void() demon1_paina34 =[ $paina34, demon1_paina35 ] {}; +void() demon1_paina35 =[ $paina35, demon1_paina36 ] {}; +void() demon1_paina36 =[ $paina36, demon1_paina37 ] {}; +void() demon1_paina37 =[ $paina37, demon1_run1 ] {self.in_pain = FALSE;}; + +void(entity attacker, float damage) demon1_pain = +{ + local vector vect; + local float rnd; + + if (self.touch == Demon_JumpTouch) + return; + + if (self.pain_finished > time) + return; + + self.pain_finished = time + 1; + + MalePainSound(2); + + if (random()*200 > damage) + return; // didn't flinch + + if (attacker.classname == "player") { + self.enemy = attacker; + } + + if (self.in_pain) + return; + + if (damage > 60) + demon1_paina1 (); + else + demon1_pain1 (); +}; + +void() demon1_die17; +void() demon1_rise1 =[ $rise1, demon1_rise2] +{ + self.solid = SOLID_SLIDEBOX; + if (!walkmove(0,0)) { + self.think = demon1_rise1; + self.solid = SOLID_NOT; + self.nextthink = time + 1; // try again in 1 second + + return; + } + + self.skin = 0; + + self.speed = self.speed - 0.35; + self.health = self.start_health * self.speed; + SetDamageSkin(self); +}; +void() demon1_rise2 =[ $rise2, demon1_rise3] {}; +void() demon1_rise3 =[ $rise3, demon1_rise4] {}; +void() demon1_rise4 =[ $rise4, demon1_rise5] {}; +void() demon1_rise5 =[ $rise5, demon1_rise6] {}; +void() demon1_rise6 =[ $rise6, demon1_rise7] {}; +void() demon1_rise7 =[ $rise7, demon1_rise8] {}; +void() demon1_rise8 =[ $rise8, demon1_rise9] {}; +void() demon1_rise9 =[ $rise9, demon1_rise10] {}; +void() demon1_rise10 =[ $rise10, demon1_rise11] {}; +void() demon1_rise11 =[ $rise11, demon1_rise12] {}; +void() demon1_rise12 =[ $rise12, demon1_rise13] {}; +void() demon1_rise13 =[ $rise13, demon1_rise14] {}; +void() demon1_rise14 =[ $rise14, demon1_rise15] {}; +void() demon1_rise15 =[ $rise15, demon1_rise16] {}; +void() demon1_rise16 =[ $rise16, demon1_rise17] {}; +void() demon1_rise17 =[ $rise17, demon1_rise18] {}; +void() demon1_rise18 =[ $rise18, demon1_rise19] {}; +void() demon1_rise19 =[ $rise19, demon1_rise20] {}; +void() demon1_rise20 =[ $rise20, demon1_rise21] {}; +void() demon1_rise21 =[ $rise21, demon1_rise22] {}; +void() demon1_rise22 =[ $rise22, demon1_rise23] {}; +void() demon1_rise23 =[ $rise23, demon1_rise24] {}; +void() demon1_rise24 =[ $rise24, demon1_rise25] {}; +void() demon1_rise25 =[ $rise25, demon1_rise26] {}; +void() demon1_rise26 =[ $rise26, demon1_rise27] {}; +void() demon1_rise27 =[ $rise27, demon1_rise28] {}; +void() demon1_rise28 =[ $rise28, demon1_rise29] {}; +void() demon1_rise29 =[ $rise29, demon1_rise30] {}; +void() demon1_rise30 =[ $rise30, demon1_rise31] {}; +void() demon1_rise31 =[ $rise31, demon1_run1] +{ +// self.solid = SOLID_SLIDEBOX; +// self.movetype = MOVETYPE_STEP; +// self.enemy = world; + self.takedamage = DAMAGE_AIM; +}; + +void() demon1_die1 =[ $death1, demon1_die2 ] {}; +void() demon1_die2 =[ $death2, demon1_die3 ] {}; +void() demon1_die3 =[ $death3, demon1_die4 ] {}; +void() demon1_die4 =[ $death4, demon1_die5 ] {}; +void() demon1_die5 =[ $death5, demon1_die6 ] {}; +void() demon1_die6 =[ $death6, demon1_die7 ] {self.solid = SOLID_NOT;}; +void() demon1_die7 =[ $death7, demon1_die8 ] {}; +void() demon1_die8 =[ $death8, demon1_die9 ] {}; +void() demon1_die9 =[ $death9, demon1_die10 ] {}; +void() demon1_die10 =[ $death10, demon1_die11 ] {}; +void() demon1_die11 =[ $death11, demon1_die12 ] {}; +void() demon1_die12 =[ $death12, demon1_die13 ] {}; +void() demon1_die13 =[ $death13, demon1_die14 ] {}; +void() demon1_die14 =[ $death14, demon1_die15 ] {}; +void() demon1_die15 =[ $death15, demon1_die16 ] {}; +void() demon1_die16 =[ $death16, demon1_die17 ] {}; +void() demon1_die17 =[ $death17, demon1_die17 ] +{ + if (self.speed < 0.4) + return; + + self.in_pain = FALSE; + + if (!(self.spawnflags & SPAWNFLAG_CLONE)) { + self.think = demon1_rise1; + self.nextthink = time + 20* random() + 20; + } +}; + +void() demon1_risea1; +void() demon1_diea1 =[ $deata1, demon1_diea2 ] {}; +void() demon1_diea2 =[ $deata2, demon1_diea3 ] {}; +void() demon1_diea3 =[ $deata3, demon1_diea4 ] {}; +void() demon1_diea4 =[ $deata4, demon1_diea5 ] {}; +void() demon1_diea5 =[ $deata5, demon1_diea6 ] {self.solid = SOLID_NOT;}; +void() demon1_diea6 =[ $deata6, demon1_diea7 ] {}; +void() demon1_diea7 =[ $deata7, demon1_diea8 ] {}; +void() demon1_diea8 =[ $deata8, demon1_diea9 ] {}; +void() demon1_diea9 =[ $deata9, demon1_diea10 ] {}; +void() demon1_diea10 =[ $deata10, demon1_diea11 ] {}; +void() demon1_diea11 =[ $deata11, demon1_diea12 ] {}; +void() demon1_diea12 =[ $deata12, demon1_diea13 ] {}; +void() demon1_diea13 =[ $deata13, demon1_diea14 ] {}; +void() demon1_diea14 =[ $deata14, demon1_diea15 ] {}; +void() demon1_diea15 =[ $deata15, demon1_diea16 ] {}; +void() demon1_diea16 =[ $deata16, demon1_diea17 ] {}; +void() demon1_diea17 =[ $deata17, demon1_diea18 ] {}; +void() demon1_diea18 =[ $deata18, demon1_diea19 ] {}; +void() demon1_diea19 =[ $deata19, demon1_diea20 ] {}; +void() demon1_diea20 =[ $deata20, demon1_diea21 ] {}; +void() demon1_diea21 =[ $deata21, demon1_diea22 ] {}; +void() demon1_diea22 =[ $deata22, demon1_diea23 ] {}; +void() demon1_diea23 =[ $deata23, demon1_diea24 ] {}; +void() demon1_diea24 =[ $deata24, demon1_diea25 ] {}; +void() demon1_diea25 =[ $deata25, demon1_diea26 ] {}; +void() demon1_diea26 =[ $deata26, demon1_diea27 ] {}; +void() demon1_diea27 =[ $deata27, demon1_diea28 ] {}; +void() demon1_diea28 =[ $deata28, demon1_diea29 ] {}; +void() demon1_diea29 =[ $deata29, demon1_diea30 ] {}; +void() demon1_diea30 =[ $deata30, demon1_diea31 ] {}; +void() demon1_diea31 =[ $deata31, demon1_diea32 ] {}; +void() demon1_diea32 =[ $deata32, demon1_diea33 ] {}; +void() demon1_diea33 =[ $deata33, demon1_diea34 ] {}; +void() demon1_diea34 =[ $deata34, demon1_diea35 ] {}; +void() demon1_diea35 =[ $deata35, demon1_diea36 ] {}; +void() demon1_diea36 =[ $deata36, demon1_diea37 ] {}; +void() demon1_diea37 =[ $deata37, demon1_diea38 ] {}; +void() demon1_diea38 =[ $deata38, demon1_diea39 ] {}; +void() demon1_diea39 =[ $deata39, demon1_diea40 ] {}; +void() demon1_diea40 =[ $deata40, demon1_diea41 ] {}; +void() demon1_diea41 =[ $deata41, demon1_diea42 ] {}; +void() demon1_diea42 =[ $deata42, demon1_diea43 ] {}; +void() demon1_diea43 =[ $deata43, demon1_diea44 ] {}; +void() demon1_diea44 =[ $deata44, demon1_diea45 ] {}; +void() demon1_diea45 =[ $deata45, demon1_diea46 ] {}; +void() demon1_diea46 =[ $deata46, demon1_diea47 ] {}; +void() demon1_diea47 =[ $deata47, demon1_diea48 ] {}; +void() demon1_diea48 =[ $deata48, demon1_diea49 ] {}; +void() demon1_diea49 =[ $deata49, demon1_diea49 ] +{ + local float rise_delay; + + if (self.speed < 0.4) + return; + + self.in_pain = FALSE; + + if (!(self.spawnflags & SPAWNFLAG_CLONE)) { + self.think = demon1_risea1; + rise_delay = (-0.5 * self.health) + 15; + if (rise_delay > 45) rise_delay = 45; + else if (rise_delay < 20) rise_delay = 20; + self.nextthink = time + rise_delay; + } +}; + +void() demon1_risea1 =[ $risea1, demon1_risea2 ] +{ + self.solid = SOLID_SLIDEBOX; + if (!walkmove(0,0)) { + self.think = demon1_risea1; + self.solid = SOLID_NOT; + self.nextthink = time + 1; // try again in 1 second + + return; + } + + self.skin = 0; + + self.speed = self.speed - 0.35; + self.health = self.start_health * self.speed; + SetDamageSkin(self); + +}; +void() demon1_risea2 =[ $risea2, demon1_risea3 ] {}; +void() demon1_risea3 =[ $risea3, demon1_risea4 ] {}; +void() demon1_risea4 =[ $risea4, demon1_risea5 ] {}; +void() demon1_risea5 =[ $risea5, demon1_risea6 ] {}; +void() demon1_risea6 =[ $risea6, demon1_risea7 ] {}; +void() demon1_risea7 =[ $risea7, demon1_risea8 ] {}; +void() demon1_risea8 =[ $risea8, demon1_risea9 ] {}; +void() demon1_risea9 =[ $risea9, demon1_risea10 ] {}; +void() demon1_risea10 =[ $risea10, demon1_risea11 ] {}; +void() demon1_risea11 =[ $risea11, demon1_risea12 ] {}; +void() demon1_risea12 =[ $risea12, demon1_risea13 ] {}; +void() demon1_risea13 =[ $risea13, demon1_risea14 ] {}; +void() demon1_risea14 =[ $risea14, demon1_risea15 ] {}; +void() demon1_risea15 =[ $risea15, demon1_risea16 ] {}; +void() demon1_risea16 =[ $risea16, demon1_risea17 ] {}; +void() demon1_risea17 =[ $risea17, demon1_risea18 ] {}; +void() demon1_risea18 =[ $risea18, demon1_risea19 ] {}; +void() demon1_risea19 =[ $risea19, demon1_risea20 ] {}; +void() demon1_risea20 =[ $risea20, demon1_risea21 ] {}; +void() demon1_risea21 =[ $risea21, demon1_risea22 ] {}; +void() demon1_risea22 =[ $risea22, demon1_risea23 ] {}; +void() demon1_risea23 =[ $risea23, demon1_risea24 ] {}; +void() demon1_risea24 =[ $risea24, demon1_risea25 ] {}; +void() demon1_risea25 =[ $risea25, demon1_risea26 ] {}; +void() demon1_risea26 =[ $risea26, demon1_risea27 ] {}; +void() demon1_risea27 =[ $risea27, demon1_risea28 ] {}; +void() demon1_risea28 =[ $risea28, demon1_risea29 ] {}; +void() demon1_risea29 =[ $risea29, demon1_risea30 ] {}; +void() demon1_risea30 =[ $risea30, demon1_risea31 ] {}; +void() demon1_risea31 =[ $risea31, demon1_risea32 ] {}; +void() demon1_risea32 =[ $risea32, demon1_risea33 ] {}; +void() demon1_risea33 =[ $risea33, demon1_risea34 ] {}; +void() demon1_risea34 =[ $risea34, demon1_risea35 ] {}; +void() demon1_risea35 =[ $risea35, demon1_risea36 ] {}; +void() demon1_risea36 =[ $risea36, demon1_risea37 ] {}; +void() demon1_risea37 =[ $risea37, demon1_risea38 ] {}; +void() demon1_risea38 =[ $risea38, demon1_risea39 ] {}; +void() demon1_risea39 =[ $risea39, demon1_risea40 ] {}; +void() demon1_risea40 =[ $risea40, demon1_risea41 ] {}; +void() demon1_risea41 =[ $risea41, demon1_risea42 ] {}; +void() demon1_risea42 =[ $risea42, demon1_risea43 ] {}; +void() demon1_risea43 =[ $risea43, demon1_risea44 ] {}; +void() demon1_risea44 =[ $risea44, demon1_risea45 ] {}; +void() demon1_risea45 =[ $risea45, demon1_risea46 ] {}; +void() demon1_risea46 =[ $risea46, demon1_risea47 ] {}; +void() demon1_risea47 =[ $risea47, demon1_risea48 ] {}; +void() demon1_risea48 =[ $risea48, demon1_risea49 ] {}; +void() demon1_risea49 =[ $risea49, demon1_risea50 ] {}; +void() demon1_risea50 =[ $risea50, demon1_risea51 ] {}; +void() demon1_risea51 =[ $risea51, demon1_risea52 ] {}; +void() demon1_risea52 =[ $risea52, demon1_run1 ] +{ + self.takedamage = DAMAGE_AIM; +}; + + +void() demon_die = +{ + local float rnd; + + self.angles_x = 0; + self.skin = 3; + + MaleDeathSound(2); + +// regular death + rnd = random(); + if ((self.health < -20) && (rnd < 0.7)) + demon1_diea1 (); + else if (rnd < 0.3) + demon1_diea1 (); + else + demon1_die1 (); +}; + + +void() Demon_MeleeAttack = +{ + demon1_atta1 (); +}; + + +/*QUAKED monster_demon1 (1 0 0) (-32 -32 -24) (32 32 64) Ambush + +*/ +void() monster_demon1 = +{ + remove(self); +}; + + +void() xmen_wolverine = +{ + if (deathmatch) + { + remove(self); + return; + } + precache_model ("progs/wolvie2.mdl"); + +// precache_model ("progs/h_demon.mdl"); + + + // XMen Matched ID sounds +// precache_sound ("hknight/sight1.wav"); + + precache_sound ("demon/dhit2.wav"); +// precache_sound ("demon/djump.wav"); +// precache_sound ("demon/idle1.wav"); + +// Wolvie sounds + precache_sound ("wolvie/breath.wav"); +// end + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + + setmodel (self, "progs/wolvie2.mdl"); + setsize (self, VEC_HULL_MIN, VEC_HULL_MAX); + + self.health = 210 + cvar("skill")*10; + self.speed = 1; // used to reduce health for each regen. + + self.in_pain = FALSE; + + self.th_stand = demon1_stand1; + self.th_walk = demon1_walk1; + self.th_run = demon1_run1; + self.th_die = demon_die; + self.th_melee = Demon_MeleeAttack; // one of two attacks + self.th_missile = demon1_jump1; // jump attack + self.th_pain = demon1_pain; + + walkmonster_start(); +}; + +/* +============================================================================== + +DEMON + +============================================================================== +*/ + +/* +============== +CheckDemonMelee + +Returns TRUE if a melee attack would hit right now +============== +*/ +float() CheckDemonMelee = +{ +// if (enemy_range == RANGE_MELEE) +// { // FIXME: check canreach + if (vlen(self.enemy.origin - self.origin) < 128) { + self.attack_state = AS_MELEE; + return TRUE; + } +// } + + return FALSE; +}; + +/* +============== +CheckDemonJump + +============== +*/ +float() CheckDemonJump = +{ + local vector dist; + local float d; + + if (random() < 0.9) + return FALSE; + + if (vlen(self.origin - self.enemy.origin) > 512) + return FALSE; + + if (self.origin_z + self.mins_z > self.enemy.origin_z + self.enemy.mins_z + + 0.75 * self.enemy.size_z) + return FALSE; + + if (self.origin_z + self.maxs_z < self.enemy.origin_z + self.enemy.mins_z + + 0.25 * self.enemy.size_z) + return FALSE; + + traceline(self.origin, self.enemy.origin, TRUE, self); + if (trace_fraction < 1) + return FALSE; + +/* + dist = self.enemy.origin - self.origin; + dist_z = 0; + + d = vlen(dist); + + if (d < 100) + return FALSE; + + if (d > 200) + { +// if (random() < 0.9) + return FALSE; + } +*/ + + return TRUE; +}; + +float() DemonCheckAttack = +{ + local vector vec; + local float rnd; + +// if close enough for slashing, go for it + if ((CheckDemonMelee ()) && (self.health > 50)) + { + self.attack_state = AS_MELEE; + return TRUE; + } + + if (CheckDemonJump ()) + { + self.attack_state = AS_MISSILE; + + return TRUE; + } + + return FALSE; +}; + + +//=========================================================================== + +void(float side) Demon_Melee = +{ + local float ldmg; + local vector delta; + + ai_face (); + walkmove (self.ideal_yaw, 12); // allow a little closing + + delta = self.enemy.origin - self.origin; + + if (vlen(delta) > 64) + return; + if (!CanDamage (self.enemy, self)) + return; + + ldmg = 4 + random() * 2; + ldmg = rint(ldmg); + + sound (self, CHAN_WEAPON, "demon/dhit2.wav", 1, ATTN_NORM); + T_Damage (self.enemy, self, self, ldmg); + + makevectors (self.angles); + SpawnMeatSpray (self.origin + v_forward*16, side * v_right); +}; + + +void() Demon_JumpTouch = +{ + + local float ldmg; + local vector dir; + + if (self.health <= 0) + return; + + // check for enemy getting hit + dir = normalize(self.velocity); + traceline(self.origin, self.origin + dir * 64, FALSE, self); + if ((trace_ent != world) && (trace_ent == self.enemy)) { + ldmg = (5 * cvar("skill")) + 10*random(); + T_Damage (other, self, self, ldmg); + trace_ent.punchangle_x = -10; + } + +// if (other.takedamage) +// { +// if ( vlen(self.velocity) > 400 ) +// { +// ldmg = (5 * cvar("skill")) + 10*random(); +// T_Damage (other, self, self, ldmg); +// } +// } + + if (!checkbottom(self)) + { + if (self.flags & FL_ONGROUND) + { // jump randomly to not get hung up +//dprint ("popjump\n"); + self.touch = SUB_Null; + self.think = demon1_jump1; + self.nextthink = time + 0.1; + +// self.velocity_x = (random() - 0.5) * 600; +// self.velocity_y = (random() - 0.5) * 600; +// self.velocity_z = 200; +// self.flags = self.flags - FL_ONGROUND; + } + return; // not on ground yet + } + + self.touch = SUB_Null; + self.think = demon1_jump11; + self.nextthink = time + 0.1; +}; + diff --git a/x_ambient.c b/x_ambient.c new file mode 100644 index 0000000..dd64e3f --- /dev/null +++ b/x_ambient.c @@ -0,0 +1,53 @@ +void() ambient_water_leaky_pipe = +{ + precache_sound ("ambience/water/leakpipe.wav"); + ambientsound (self.origin, "ambience/water/leaky_pipe.wav", 1, ATTN_STATIC); +}; + +void() ambient_water_sewer = +{ + precache_sound ("ambience/water/sewer.wav"); + ambientsound (self.origin, "ambience/water/sewer.wav", 1, ATTN_STATIC); +}; + +void() ambient_water_flow_light = +{ + precache_sound ("ambience/water/flowlght.wav"); + ambientsound (self.origin, "ambience/water/flowlght.wav", 1, ATTN_STATIC); +}; + +void() ambient_water_stream_heavy = +{ + precache_sound ("ambience/water/strmhvy.wav"); + ambientsound (self.origin, "ambience/water/strmhvy.wav", 1, ATTN_STATIC); +}; + +void() ambient_water_stream_light = +{ + precache_sound ("ambience/water/strmlght.wav"); + ambientsound (self.origin, "ambience/water/strmlght.wav", 1, ATTN_STATIC); +}; + +void() ambient_water_tunnel_light = +{ + precache_sound ("ambience/water/tnnl_lt.wav"); + ambientsound (self.origin, "ambience/water/tnnl_lt.wav", 1, ATTN_STATIC); +}; + +void() ambient_airhose = +{ + precache_sound ("ambience/airhose.wav"); + ambientsound (self.origin, "ambience/airhose.wav", 1, ATTN_STATIC); +}; + +void() ambient_drill = +{ + precache_sound ("ambience/drill_x.wav"); + ambientsound (self.origin, "ambience/drill_x.wav", 1, ATTN_STATIC); +}; + +void() xmen_ambient = +{ + precache_sound (self.noise); + ambientsound (self.origin, self.noise, 1, ATTN_STATIC); +}; \ No newline at end of file diff --git a/x_cam.c b/x_cam.c new file mode 100644 index 0000000..ebed4ac --- /dev/null +++ b/x_cam.c @@ -0,0 +1,103 @@ +// X-Men chase-cam + +float SVC_SETVIEWPORT = 5; +.entity chasecam; + +vector CAM_OFFSET = '-36 0 6'; // forward, right, up +vector CAM_ORIGIN_OFFSET = '-8 0 8'; +float CAM_TRACKSPEED = 0.5; + +void(entity player) DisableCam = +{ + if (player.chasecam == world) + return; + + msg_entity = player; // target of message + WriteByte (MSG_ONE, SVC_SETVIEWPORT); + WriteEntity (MSG_ONE, player); // view port + + stuffcmd(player, "cl_bobup 1\n"); + stuffcmd(player, "r_drawviewmodel 1\n"); + + remove(player.chasecam); + player.chasecam = world; +}; + +void(entity player) InitCam = +{ + local entity cam; + + if (player.chasecam != world) + return; + + cam = spawn(); + player.chasecam = cam; + cam.owner=player; + + cam.solid = SOLID_NOT; + cam.movetype = MOVETYPE_NONE; + + cam.angles = cam.owner.angles; + + setmodel (cam, "progs/eyes.mdl" ); + setsize (cam, '0 0 0', '0 0 0'); + setorigin( cam, cam.owner.origin ); + cam.classname = "cam"; + + msg_entity = cam.owner; // target of message + WriteByte (MSG_ONE, SVC_SETVIEWPORT); + WriteEntity (MSG_ONE, cam); // view port + + stuffcmd(player, "cl_bobup 0\n"); + stuffcmd(player, "r_drawviewmodel 0\n"); +}; + +void() CamThink = +{ + local vector pos, vec, org, angle; + local float dist; + + angle = self.owner.v_angle; + + angle_x = 0; + makevectors(angle); + org = self.owner.origin + v_up * CAM_ORIGIN_OFFSET_z + + v_forward * CAM_ORIGIN_OFFSET_x; + + makevectors(self.owner.v_angle); + pos = org + v_forward * CAM_OFFSET_x + + v_right * CAM_OFFSET_y + + v_up * CAM_OFFSET_z; + + if ((self.owner.character == CHAR_STORM) || + (self.owner.character == CHAR_ANGEL)) + { + pos = pos + v_up * 12; + } + + vec = normalize(pos - org); + traceline(org, pos, TRUE, world); + + dist = vlen(pos - self.origin); + + if (trace_fraction == 1) { // check ceiling + traceline(org, pos + '0 0 32', TRUE, world); + + if (trace_fraction < 1) + trace_endpos = trace_endpos - '0 0 32'; + } + + if (trace_fraction < 1) { + if (trace_ent == world) // move away from wall + setorigin(self, trace_endpos + trace_plane_normal * 8); + else + setorigin(self, trace_endpos - vec * 4); + } + else { // move towards ideal pos + if (vlen((pos - self.origin) * frametime * dist * CAM_TRACKSPEED) < dist) + setorigin(self, self.origin + ((pos - self.origin) * frametime * dist * CAM_TRACKSPEED)); + else + setorigin(self, pos); + } + +}; \ No newline at end of file diff --git a/x_debug.c b/x_debug.c new file mode 100644 index 0000000..abe6095 --- /dev/null +++ b/x_debug.c @@ -0,0 +1,63 @@ +void() xmen_monster_test = +{ + if (cvar("coop") == 1) + { + self.classname = "xmen_wolverine"; + xmen_wolverine(); + } + else if (cvar("coop") == 2) + { + self.classname = "xmen_storm"; + xmen_storm(); + } + else if (cvar("coop") == 3) + { + self.classname = "xmen_cyclops"; + xmen_cyclops(); + } + else if (cvar("coop") == 4) + { + self.classname = "xmen_psylocke"; + xmen_psylocke(); + } + else if (cvar("coop") == 5) + { + self.classname = "xmen_angel"; + xmen_angel(); + } + else if (cvar("coop") == 6) + { + self.classname = "xmen_beast"; + xmen_beast(); + } + else if (cvar("coop") == 7) + { + self.classname = "xmen_gambit"; + xmen_gambit(); + } + else if (cvar("coop") == 8) { + self.map = "brown"; + self.classname = "xmen_iceman"; + xmen_iceman(); + } + else if (cvar("coop") == 9) + { + self.classname = "xmen_bishop"; + xmen_bishop(); + } + else if (cvar("coop") == 10) + { + self.classname = "xmen_rogue"; + xmen_rogue(); + } + else if (cvar("coop") == 11) + { + self.classname = "xmen_cannonball"; + xmen_cannonball(); + } + else if (cvar("coop") == 12) + { + self.classname = "xmen_phoenix"; + xmen_phoenix(); + } +}; \ No newline at end of file diff --git a/x_misc.c b/x_misc.c new file mode 100644 index 0000000..04e235d --- /dev/null +++ b/x_misc.c @@ -0,0 +1,476 @@ +string(float char) GetCharacterString = +{ + if (char == CHAR_WOLVERINE) + return "Wolverine"; + if (char == CHAR_STORM) + return "Storm"; + if (char == CHAR_CYCLOPS) + return "Cyclops"; + if (char == CHAR_PSYLOCKE) + return "Psylocke"; + if (char == CHAR_ANGEL) + return "Angel"; + if (char == CHAR_BEAST) + return "Beast"; + if (char == CHAR_GAMBIT) + return "Gambit"; + if (char == CHAR_ICEMAN) + return "Iceman"; + if (char == CHAR_BISHOP) + return "Bishop"; + if (char == CHAR_ROGUE) + return "Rogue"; + if (char == CHAR_CANNONBALL) + return "Cannonball"; + if (char == CHAR_PHOENIX) + return "Phoenix"; +}; + +// This is an adaption of the Wizard missile prediction code +vector(float mspeed, vector target_offset) ProjectVelocity = +{ + local vector vec, move; + local float fly; + + makevectors (self.angles); + +// set missile speed + vec = self.enemy.origin - self.origin + target_offset; + +// calc aproximate time for missile to reach vec + fly = vlen (vec) / mspeed; + +// get the entities xy velocity + move = self.enemy.velocity; + move_z = 0; + +// project the target forward in time + vec = vec + move * (fly * 0.75); + + vec = normalize(vec); + + return (vec * mspeed); +}; + +//========================================================================== + +void() xmen_post = +{ + if (self.style == 1) { + precache_model ("progs/posta.spr"); + setmodel(self, "progs/posta.spr"); + } + else if (self.style == 2) { + precache_model ("progs/postb.spr"); + setmodel(self, "progs/postb.spr"); + } + else if (self.style == 3) { + precache_model ("progs/postc.spr"); + setmodel(self, "progs/postc.spr"); + } + else if (self.style == 4) { + precache_model ("progs/postd.spr"); + setmodel(self, "progs/postd.spr"); + } +}; + +//========================================================================== +// Special Weapon stuff + +void() MagnetoThink = +{ + local vector ang; + + makevectors(self.owner.v_angle); + + setorigin(self, self.owner.origin + v_forward * 70 + '0 0 22'); + + ang = self.owner.v_angle; //vectoangles(v_forward * 1); + + if (executable == "glQuake") // fixes upside-down magneto sprite + ang_z = 180; + +// ang_x = -1 * ang_x; + self.angles = ang; + + if (random() < 0.5) + self.frame = rint(random() * 7); + + self.nextthink = time + 0.01; +}; + +void() WeaponMessage = +{ + local entity magneto; + + if (/*(self.last_flame < (time - 24)) ||*/ ((self.last_flame < (time - 3)) && (self.owner.button2))) { + magneto = find(world, classname, "magneto_sprite"); + if (magneto != world) + remove(magneto); + + centerprint(self.owner, ""); + remove(self); + return; + } + + if (self.speed) + centerprint(self.owner, self.noise1); + else + centerprint(self.owner, self.noise); + + self.nextthink = time + 0.1; +}; + +void(float newwpn) SetNewWeapon; +void() ImpulseCommands; +void() weapon_piece_touch = +{ + local entity magneto, oself; + + if (other.classname != "player") + return; + + self.owner = other; + + other.weapon_parts = other.weapon_parts + 1; + + sound (other, CHAN_ITEM, "items/protect.wav", 1, ATTN_NORM); + stuffcmd (other, "bf\n"); + self.solid = SOLID_NOT; + self.model = string_null; + self.classname = ""; // so rune doors won't find it + + serverflags = serverflags | self.items; + + if ((world.model == "maps/x1end.bsp") || (world.model == "maps/x2end.bsp")) // must be the final weapon component, so activate the Mega-Weapon! + { + + // make sure they have all the components + if (serverflags & 15) { + + other.items = other.items | IT_SPECIAL_WEAPON; + + oself = self; + self = other; + + self.ammo_special = 255; +// SetNewWeapon(IT_SPECIAL_WEAPON); + self.impulse = 13; + ImpulseCommands(); + self.currentammo = self.ammo_special; + + self = oself; + + } + + } + +// centerprint(other, self.noise); + if (self.speed == other.weapon_parts) + self.speed = 0; + + self.last_flame = time; + self.think = WeaponMessage; + self.nextthink = time + 0.1; + + // spawn magneto sprite thinker + magneto = spawn(); + magneto.classname = "magneto_sprite"; + magneto.owner = other; + setmodel(magneto, "progs/magneto.spr"); + magneto.think = MagnetoThink; + magneto.nextthink = time + 0.01; +}; + +void() StartItem; +void() xmen_weapon_part = +{ + if (deathmatch) { + remove(self); + return; + } + + if (world.model == "maps/x1m1.bsp") { + precache_model("progs/comp1_1.mdl"); + setmodel(self, "progs/comp1_1.mdl"); + self.items = 1; + self.noise = "Well done. You have found the\nfirst part of the only weapon\nable to defeat Apocalypse.\n\nYou will find other components\nthat have been seperated and\nhidden by Apocalypse. If you\nare unsuccessful the age of\nApocalypse will be unavoidable...\n\nGood luck.\n\n(press JUMP when ready)"; +/* +Well done. You have found the +first part of the only weapon +able to defeat Apocalypse.\n +You will find other components +that have\nbeen seperated and +hidden by Apocalypse. If you +are unsuccessful the age of +Apocalypse will be unavoidable...\n +Good luck.\n\n(press JUMP when ready) +*/ + } + else if (world.model == "maps/x1m2.bsp") { + precache_model("progs/comp1_2.mdl"); + setmodel(self, "progs/comp1_2.mdl"); + self.items = 2; + self.noise = "You have done well. your quest\nbecomes more important by the\nhour. Even as I speak Apocalypses\nclones are taking over every\nworld power. You are earth's\nonly hope for survival.\n\n(press JUMP when ready)"; +/* +You have done well. your quest\n +becomes more important by the\n +hour. Even as I speak Apocalypses\n +clones are taking over every\n +world power. You are earth's\n +only hope for survival.\n\n(press JUMP when ready) +*/ + } + else if (world.model == "maps/x1m3.bsp") { + precache_model("progs/comp1_3.mdl"); + setmodel(self, "progs/comp1_3.mdl"); + self.items = 4; + self.noise = "By destroying the cloning\ncomputer you have successfully\nstopped the production of this\nevil army of clones. You have\ngreatly threatened Apocalypses\nplans, but you must still rid\nthe world of the remaining\nclones and ensure that Apocalypse\ncan never attempt this again.\n\n(press JUMP when ready)"; + +/* +By destroying the cloning\n +computer you have successfully\n +stopped the production of this\n +evil army of clones. You have\n +greatly threatened Apocalypses\n +plans, but you must still rid\n +the world of the remaining\n +clones and ensure that Apocalypse\n +can never attempt this again.\n\n(press JUMP when ready) +*/ + } + else if (world.model == "maps/x1m4.bsp") { + precache_model("progs/comp1_4.mdl"); + setmodel(self, "progs/comp1_4.mdl"); + self.items = 8; + self.speed = 4; + self.noise = "You are getting closer to\nApocalypses sanctuary. You now\nhave all the weapon components.\nAll you need now is enough power\nto activate it. Step carefully.\nApocalypse is bound to have many\ndefences surrounding his lair.\n\n(press JUMP when ready)"; +/* +You are getting closer to\n +Apocalypses sanctuary. You now\n +have all the weapon components.\n +All you need now is enough power\n +to activate it. Step carefully.\n +Apocalypse is bound to have many\n +defences surrounding his lair.\n\n(press JUMP when ready) +*/ + + self.noise1 = "You are getting closer to\nApocalypse's sanctuary. You\nhave the final weapon component,\nbut you will need to get all the\nothers to defeat Apocalypse. Step\ncarefully. Apocalypse is bound to\nhave many defenses surrounding\nhis lair.\n\n(press JUMP when ready)"; +/* +You are getting closer to\n +Apocalypse's sanctuary. You\n +have the final weapon component,\n +but you will need to get all the\n +others to defeat Apocalypse. Step\n +carefully. Apocalypse is bound to\n +have many defenses surrounding\n +his lair.\n +*/ + } + else if (world.model == "maps/x1end.bsp") { + precache_model("progs/comp1_5.mdl"); + setmodel(self, "progs/comp1_5.mdl"); + self.speed = 5; + self.noise = "You have found a power pack\ncapable of activating the\nweapon for a short time. Use it\nwisely.\n\n(press JUMP when ready)"; + + self.noise1 = "You have found a power pack\ncapable of activating the\nweapon for a short time.\n\nUnfortunately you have not\ngot all the weapon components.\n\nYou will need to go back to\nget them before being able to\ndefeat Apocalypse.\n\n(press JUMP when ready)"; +/* +You have found a power pack\n +capable of activating the\n +weapon for a short time.\n +Unfortunately you have not\n +got all the weapon components.\n +You will need to go back to\n +get them before being able to\n +defeat Apocalypse. +*/ + } + + else if (world.model == "maps/x2m1.bsp") { + precache_model("progs/comp2_1.mdl"); + setmodel(self, "progs/comp2_1.mdl"); + self.items = 1; + self.noise = "Now that you have defeated\nApocalypse you must find the\nother 3 components of the weapon\nthat must be used to defeat\nApocalypses sinister accomplice.\n\n(press JUMP when ready)"; +/* +Now that you have defeated\n +Apocalypse you must find the\n +other 3 components of the weapon\n +that must be used to defeat\n +Apocalypses sinister accomplis.\n\n(press JUMP when ready) +*/ + + } + else if (world.model == "maps/x2m2.bsp") { + precache_model("progs/comp2_2.mdl"); + setmodel(self, "progs/comp2_2.mdl"); + self.items = 2; + self.speed = 2; + self.noise = "You are doing well. There are\nonly 2 more components to be\nfound. Keep an eye out for clues\nalong your journey.\n\n(press JUMP when ready)"; +/* +You are doing well. There are\n +only 2 more components to be\n +found. Keep an eye out for clues\n +along your journey.\n\n(press JUMP when ready) +*/ + + self.noise1 = "You are doing well. You have\nmissed one of the weapon\ncomponents, you will need\nto have it before completing\nyour quest. Keep an eye out\nfor clues along the way.\n\n(press JUMP when ready)"; +/* +You are doing well. You have\n +missed one of the weapon\n +components, you will need\n +to have it before completing\n +your quest. Keep an eye out\n +for clues along the way. +*/ + } + else if (world.model == "maps/x2m3.bsp") { + precache_model("progs/comp2_3.mdl"); + setmodel(self, "progs/comp2_3.mdl"); + self.items = 4; + self.noise = "The weapon components were\nscattered farther than I had\nhoped. This is a minor set back.\nYou are getting closer to\nfinding Apocalypses evil\npartner.\n\n(press JUMP when ready)"; +/* +The weapon components were\n +scattered farther than I had\n +hoped. This is a minor set back.\n +You are getting closer to\n +finding Apocalypses evil\n +partner.\n\n(press JUMP when ready) +*/ + } + else if (world.model == "maps/x2m4.bsp") { + precache_model("progs/comp2_4.mdl"); + setmodel(self, "progs/comp2_4.mdl"); + self.items = 8; + self.speed = 4; + self.noise = "You are very close now I feel.\nNow that you have found the 4\nparts to the weapon, you must\nagain\nfind sufficient power to\nactivate it.\n\n(press JUMP when ready)"; +/* +You are very close now I feel.\n +Now that you have found the 4\n +parts to the weapon, you must\n +again\nfind sufficient power to\n +activate it.\n\n(press JUMP when ready)"; +*/ + self.noise1 = "You are very close now, I feel,\nbut you have not got all 4\nparts to the weapon. Once you\nhave, you must again find\nsufficient power to activate it.\n\n(press JUMP when ready)"; +/* +You are very close now, I feel,\n +but you have not got all 4\n +parts to the weapon. Once you\n +have, you must again find\n +sufficient power to activate it. +*/ + } + else if (world.model == "maps/x2end.bsp") { + precache_model("progs/comp2_5.mdl"); + setmodel(self, "progs/comp2_5.mdl"); + self.speed = 5; + self.noise = "The weapon is now functional.\n\nUse it well.\n\n(press JUMP when ready)"; + self.noise1 = "You have the power pack,\nbut not all of the weapon\ncomponents. You must find\nthese before defeating Mr\nSinister.\n\n(press JUMP when ready)"; +/* +You have the power pack,\n +but not all of the weapon\n +components. You must find\n +these before defeating Mr\n +Sinister. +*/ + } + else { + precache_model("progs/comp1_1.mdl"); + setmodel(self, "progs/comp1_1.mdl"); + self.noise = "Special Weapon: unknown level name"; + } + + precache_model("progs/magneto.spr"); + + self.touch = weapon_piece_touch; + setsize (self, '-8 -8 0', '8 8 32'); + StartItem (); +}; + +//========================================================================== +void(entity ent) SetDamageSkin = +{ + if (deathmatch) + return; + + if (ent.classname == "player") + return; + + if (ent.classname == "xmen_techdude") + return; + + if (((ent.classname == "xmen_sinister") || (ent.classname == "apocalypse_small")) && !(ent.x_flags & X_MEGA_HIT)) + return; + + if (show_damage) { + bprint(ftos((ent.health * 100) / ent.start_health)); + bprint("% damage\n"); + } + + // set damage skin + if ((ent.health / ent.start_health) < 0.33) + ent.skin = 2; + else if ((ent.health / ent.start_health) < 0.66) + ent.skin = 1; + else + ent.skin = 0; +}; + +//========================================================================== + +void() item_furniture = +{ + precache_model(self.model); + setmodel(self, self.model); +}; + +//========================================================================== +void() SUB_regen; +void() RapidTouch = +{ + if (other.classname != "player") + return; + + if (other.health <= 0) + return; + + sprint(other, "You got the Rapid Fire!\n"); + + sound(other, CHAN_ITEM, "misc/rapid.wav", 1, ATTN_NORM); + + other.rapid_time = time + 25; + other.x_flags = other.x_flags | X_RAPID_FIRE; +// other.items = other.items | IT_INVISIBILITY; + + stuffcmd (other, "bf\n"); + self.solid = SOLID_NOT; + self.mdl = self.model; + self.model = string_null; + + if (deathmatch) { + self.nextthink = time + 40; + self.think = SUB_regen; + } + +}; + +void() item_rapid_fire = +{ + precache_model("progs/rapid.mdl"); + + precache_sound("misc/rapid.wav"); + precache_sound("misc/rapidout.wav"); + + setmodel(self, "progs/rapid.mdl"); + + setsize (self, '-16 -16 -24', '16 16 32'); + + self.touch = RapidTouch; + + StartItem(); +}; + +void(entity client, string s) centerprint = +{ + client.last_centerprint = s; + do_centerprint(client, s); +}; \ No newline at end of file diff --git a/x_sound.c b/x_sound.c new file mode 100644 index 0000000..99e53ba --- /dev/null +++ b/x_sound.c @@ -0,0 +1,150 @@ +// type = 1 for big characters like Beast and Bishop, 2 for normal/smaller characters +void(float type) MalePainSound = +{ + local float rnd; + + if (type == 1) { + rnd = random() * 5; + + if (rnd < 1) + sound(self, CHAN_BODY, "voice/male/pain1.wav", 1, ATTN_NORM); + else if (rnd < 2) + sound(self, CHAN_BODY, "voice/male/pain2.wav", 1, ATTN_NORM); + else if (rnd < 3) + sound(self, CHAN_BODY, "voice/male/pain3.wav", 1, ATTN_NORM); + else if (rnd < 4) + sound(self, CHAN_BODY, "voice/male/pain4.wav", 1, ATTN_NORM); + else + sound(self, CHAN_BODY, "voice/male/pain5.wav", 1, ATTN_NORM); + + } + else if (type == 2) { + rnd = random() * 2; + + if (rnd < 1) + sound(self, CHAN_BODY, "voice/male/pain6.wav", 1, ATTN_NORM); + else + sound(self, CHAN_BODY, "voice/male/pain7.wav", 1, ATTN_NORM); + + } +}; + +// type = 1 for big characters like Beast and Bishop, 2 for normal/smaller characters +void(float type) MaleDeathSound = +{ + local float rnd; + + if (type == 1) { + rnd = random() * 3; + + if (rnd < 1) + sound(self, CHAN_BODY, "voice/male/diescrm1.wav", 1, ATTN_NORM); + else if (rnd < 2) + sound(self, CHAN_BODY, "voice/male/diescrm2.wav", 1, ATTN_NORM); + else if (rnd < 3) + sound(self, CHAN_BODY, "voice/male/diescrm3.wav", 1, ATTN_NORM); + + } + else if (type == 2) { + rnd = random() * 3; + + if (rnd < 1) + sound(self, CHAN_BODY, "voice/male/diescrm4.wav", 1, ATTN_NORM); + else if (rnd < 2) + sound(self, CHAN_BODY, "voice/male/diescrm5.wav", 1, ATTN_NORM); + else if (rnd < 3) + sound(self, CHAN_BODY, "voice/male/diescrm6.wav", 1, ATTN_NORM); + + } +}; + +// type = 1 for big characters like Beast and Bishop, 2 for normal/smaller characters +void(float type) MaleSightSound = +{ + local float rnd; + +return; // disable all ICU sounds + + if (type == 1) { + rnd = random() * 2; + + if (rnd < 1) + sound(self, CHAN_BODY, "voice/male/growl.wav", 1, ATTN_NORM); + else if (rnd < 2) + sound(self, CHAN_BODY, "voice/male/grrr.wav", 1, ATTN_NORM); + + } + else if (type == 2) { + rnd = random() * 6; + + if (rnd < 1) + sound(self, CHAN_BODY, "voice/male/intruder.wav", 1, ATTN_NORM); + else if (rnd < 2) + sound(self, CHAN_BODY, "voice/male/stop01.wav", 1, ATTN_NORM); + else if (rnd < 3) + sound(self, CHAN_BODY, "voice/male/uh-a.wav", 1, ATTN_NORM); + else if (rnd < 4) + sound(self, CHAN_BODY, "voice/male/what.wav", 1, ATTN_NORM); + else if (rnd < 5) + sound(self, CHAN_BODY, "voice/male/what_the.wav", 1, ATTN_NORM); + else if (rnd < 6) + sound(self, CHAN_BODY, "voice/male/youthere.wav", 1, ATTN_NORM); + + } +}; + +void() FemalePainSound = +{ + local float rnd; + + rnd = random() * 6; + + if (rnd < 1) + sound(self, CHAN_BODY, "voice/female/scream1.wav", 1, ATTN_NORM); + else if (rnd < 2) + sound(self, CHAN_BODY, "voice/female/scream2.wav", 1, ATTN_NORM); + else if (rnd < 3) + sound(self, CHAN_BODY, "voice/female/scream3.wav", 1, ATTN_NORM); + else if (rnd < 4) + sound(self, CHAN_BODY, "voice/female/no1.wav", 1, ATTN_NORM); + else if (rnd < 5) + sound(self, CHAN_BODY, "voice/female/scream4.wav", 1, ATTN_NORM); + else if (rnd < 6) + sound(self, CHAN_BODY, "voice/female/scream5.wav", 1, ATTN_NORM); +}; + +void() FemaleDeathSound = +{ + local float rnd; + + rnd = random() * 3; + + if (rnd < 1) + sound(self, CHAN_BODY, "voice/female/diescrm1.wav", 1, ATTN_NORM); + else if (rnd < 2) + sound(self, CHAN_BODY, "voice/female/diescrm2.wav", 1, ATTN_NORM); + else if (rnd < 3) + sound(self, CHAN_BODY, "voice/female/diescrm3.wav", 1, ATTN_NORM); + else if (rnd < 4) + sound(self, CHAN_BODY, "voice/female/diescrm4.wav", 1, ATTN_NORM); + else if (rnd < 5) + sound(self, CHAN_BODY, "voice/female/diescrm5.wav", 1, ATTN_NORM); +}; + +void() FemaleSightSound = +{ + local float rnd; + +return; // disable all ICU sounds + + rnd = random() * 4; + + if (rnd < 1) + sound(self, CHAN_BODY, "voice/female/hey.wav", 1, ATTN_NORM); + else if (rnd < 2) + sound(self, CHAN_BODY, "voice/female/hey_you.wav", 1, ATTN_NORM); + else if (rnd < 3) + sound(self, CHAN_BODY, "voice/female/stop.wav", 1, ATTN_NORM); + else if (rnd < 4) + sound(self, CHAN_BODY, "voice/female/wait.wav", 1, ATTN_NORM); +}; \ No newline at end of file diff --git a/x_tech.c b/x_tech.c new file mode 100644 index 0000000..dbcbb38 --- /dev/null +++ b/x_tech.c @@ -0,0 +1,190 @@ +$frame a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 +$frame b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 +$frame d1 d2 d3 d4 d5 d6 d7 d8 d9 d10 +$frame d11 d12 d13 d14 d15 d16 d17 d18 d19 d20 +$frame d21 d22 d23 d24 d25 d26 d27 d28 d29 d30 +$frame d31 d32 d33 d34 d35 d36 d37 d38 d39 d40 +$frame d41 d42 d43 d44 d45 d46 + +$frame death1 death2 death3 death4 death5 death6 death7 death8 death9 death10 death11 death12 + +$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 walk9 walk10 +$frame walk11 walk12 + +$frame walka1 walka2 walka3 walka4 walka5 walka6 walka7 walka8 walka9 walka10 +$frame walka11 walka12 + +$frame duck1 duck2 duck3 duck4 duck5 duck6 + +$frame cower1 cower2 +void() tech_die = +{ + self.deadflag = DEAD_DEAD; + self.solid = SOLID_NOT; + self.takedamage = DAMAGE_NO; + if ((self.frame < $death1 ) || (self.frame > $death12 )) + self.frame = $death1; + else + self.frame = self.frame + 1; + + if (self.frame == $death12 ) { + self.nextthink = -1; + return; + } + + self.think = tech_die; + self.nextthink = time + 0.1; +}; + +void() tech_hide1 = [ $duck1, tech_hide2 ] {}; +void() tech_hide2 = [ $duck2, tech_hide3 ] {}; +void() tech_hide3 = [ $duck3, tech_hide4 ] {}; +void() tech_hide4 = [ $duck4, tech_hide5 ] {}; +void() tech_hide5 = [ $duck5, tech_hide6 ] {}; +void() tech_hide6 = [ $duck6, tech_cower1 ] {}; +void() tech_cower1 = [ $cower1, tech_cower2 ] {}; +void() tech_cower2 = [ $cower2, tech_cower1 ] {}; + +void() tech_think = +{ + local entity plyr, btn, oself; + local vector oldpos, vectmove, anglemove; + + self.frame = self.frame + 1; + if (self.frame > self.last_frame) { + self.frame = self.start_frame; + if ((self.tech_state != TECH_WALKING) && (random() < 0.5)) // somewhat randomize the speed of animation + self.speed = 0.1; + else + self.speed = 0.05; + } + + if (self.tech_state == TECH_WALKING) { // move towards target switch + oldpos = self.origin; + movetogoal(6); + vectmove = normalize(self.origin - oldpos); + anglemove = vectoangles(vectmove); + self.ideal_yaw = anglemove_y; + + ChangeYaw(); + + if (vlen(self.origin - self.movetarget.origin) < 64) { // fire button, start hiding +//bprint("tech firing target\n"); + oself = self; + activator = self; + self = self.movetarget.owner; + if (self.use) + self.use(); +// else { +// objerror("Technician target doesn't have a use function\n"); +// } + self = oself; + + remove(self.movetarget); + self.tech_state = TECH_HIDING; + tech_hide1(); + return; + } + } + else if ((self.tech_state == TECH_IDLE) && (self.target != "") && (self.frame == self.start_frame)) { // check for sighting intruder + plyr = world; + while ((plyr = find(plyr, classname, "player")) != world) { + + // check if visible + traceline(self.origin + '0 0 16', plyr.origin + '0 0 16', TRUE, world); + + if (trace_fraction == 1) { // player is visible + if ((btn = find(world, targetname, self.target)) == world) { + bprint("xmen_techdude: cannot find target\n"); + } + else { + self.movetarget = spawn(); + self.enemy = self.goalentity = self.movetarget; + self.movetarget.owner = btn; + self.movetarget.origin = btn.absmin + ((btn.absmax - btn.absmin) * 0.5); + } + + self.speed = 0.05; + self.tech_state = TECH_WALKING; + +// if (random() < 0.5) { + self.start_frame = self.frame = $walk1; + self.last_frame = $walk12; +// } +// else { +// self.start_frame = self.frame = $walka1; +// self.last_frame = $walka12; +// } + } + + } + } + + self.nextthink = time + self.speed; +}; + +void() tech_pain = +{ + self.health = self.health; // should we play a sound here? +}; + +void() tech_drop = +{ + droptofloor(); +/* + if (!walkmove(0,0)) { + bprint("xmen_techdude fell out of level at "); + bprint(vtos(self.origin)); + bprint("\n"); + } +*/ + self.think = tech_think; + self.nextthink = time + self.speed; +}; + +void() xmen_techdude = +{ + local string str; + local float rnd; + + if (deathmatch) { + remove(self); + return; + } + + precache_model("progs/tech.mdl"); + + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_STEP; + + setmodel(self, "progs/tech.mdl"); + setsize(self, VEC_HULL_MIN, VEC_HULL_MAX); + + rnd = random() * 3; + if (rnd <= 1) { + self.start_frame = $a1; + self.last_frame = $a16; + } + else if (rnd <= 2) { + self.start_frame = $b1; + self.last_frame = $b10; + } + else { + self.start_frame = $d1; + self.last_frame = $d46; + } + + self.tech_state = TECH_IDLE; + self.yaw_speed = 90; + + self.takedamage = DAMAGE_AIM; + self.health = self.start_health = 25; + + self.th_die = tech_die; + self.th_pain = tech_pain; + + self.speed = 0.1; // speed of animation + + self.think = tech_drop; + self.nextthink = time + 0.2; +}; \ No newline at end of file