home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-11-26 | 79.8 KB | 2,595 lines |
- /*══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ CUJO BOT ver 1.2 ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- // distance from player before cujo initiates a teleport
- float teleport_dist = 1500;
-
- // Prototypes
-
- float () CUJO_FindTarget; //
- void () CUJO_ai_stand; //
- void () CUJO_pain; //
- void () CUJO_die; //
- void () CUJO_SightSound; //
- void () CUJO_FoundTarget;//
- void () CUJO_HuntTarget; //
- void (float dist) CUJO_ai_walk; //
- void () CUJO_ai_turn; //
- void (float dist) CUJO_ai_run; //
- void (float dist) CUJO_ai_follow; //
- void () CUJO_ai_face;
- void (float d) CUJO_ai_charge;
- void (void () thinkst) CUJO_CheckRefire;//
- void () CUJO_SelfDeactivate;//
-
- void () CUJO_TeleportToOwner;//
- vector () CUJO_SpawnPos;
- float (vector SpawnPos) CUJO_CheckSpawnPos;
-
- // Cujo Prototypes - called by player
-
- void () CUJO_Precache;
- void () CUJO_Activate; // Activate Cujo
- void () CUJO_Deactivate; // DeActivate Cujo
- void () CUJO_Toggle; // Toggle Cujo on and off
- void () CUJO_AttackToggle; // Toggle Cujo's auto-firing in auto mode
- /*
- void () CUJO_Attack; // Have Cujo fire at its current target in auto mode
- */
- void () CUJO_TeleportHome; // Have Cujo teleport back to its owner
- void () CUJO_LightToggle; // Have Cujo teleport back to its owner
- void () CUJO_SetDogView;
- void () CUJO_SetPlayerView;
-
- // Global Variables
-
- float goal_range;
- float goal_vis;
- float goal_infront;
- float goal_yaw;
- vector old_player_angles;
-
- // new for Cujo jumping AI
- float forward_jump_vel;
- float upward_jump_vel;
-
- // Constants
-
- float nextthinktime = 0.01;
-
- $cd /raid/quake/id1/models/dog
- $origin 0 0 24
- $base base
- $skin skin
-
- $frame attack1 attack2 attack3 attack4 attack5 attack6 attack7 attack8
-
- $frame death1 death2 death3 death4 death5 death6 death7 death8 death9
-
- $frame deathb1 deathb2 deathb3 deathb4 deathb5 deathb6 deathb7 deathb8
- $frame deathb9
-
- $frame pain1 pain2 pain3 pain4 pain5 pain6
-
- $frame painb1 painb2 painb3 painb4 painb5 painb6 painb7 painb8 painb9 painb10
- $frame painb11 painb12 painb13 painb14 painb15 painb16
-
- $frame run1 run2 run3 run4 run5 run6 run7 run8 run9 run10 run11 run12
-
- $frame leap1 leap2 leap3 leap4 leap5 leap6 leap7 leap8 leap9
-
- $frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9
-
- $frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8
-
-
- void() dog_leap1;
- void() dog_run1;
-
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Routines called by Cujo, self = Cujo ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ CUJO_PrintCujoStatus ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void () CUJO_PrintCujoStatus =
-
- {
- if (!deathmatch)
- sprint (self, "Cujo is not here.\n");
- else
- {
- if (self.Cujo_avail)
- sprint (self, "Cujo is not here.\n");
- else
- sprint (self, "Cujo is not available.\n");
- }
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ CUJO_ResetGoalEntity ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void () CUJO_ResetGoalEntity =
-
- {
- self.oldenemy = self.enemy;
- self.enemy = world;
-
- self.goalentity = self.owner;
- self.movetarget = self.owner;
- };
-
- /*╔═══════════════════════════════════╗
- ║ ║
- ║ Cujo_bite ║
- ║ ║
- ╚═══════════════════════════════════╝*/
-
- void() CUJO_bite =
- {
- local vector delta;
- local float ldmg;
-
- if (!self.enemy) return;
-
- CUJO_ai_charge(10);
-
- if (!CanDamage (self.enemy, self)) return;
-
- delta = self.enemy.origin - self.origin;
-
- if (vlen(delta) > 100) return;
-
- // does twice the damage of a normal dog and has a random chance
- // of gibbing!
-
- if ((self.enemy.health < 10) && (random () < 0.1))
- {
- {
- ldmg = 50 * random ();
- }
- }
- else
- {
- ldmg = (random() + random() + random()) * 16;
- }
-
- T_Damage (self.enemy, self, self, ldmg);
- };
-
- /*╔═══════════════════════════════════╗
- ║ ║
- ║ Cujo_ChangeYaw ║
- ║ ║
- ╚═══════════════════════════════════╝*/
-
- void() CUJO_ChangeYaw =
- {
- local float ideal, move;
-
- 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);
- if (fabs (ideal - current_yaw) < self.yaw_speed)
- current_yaw = ideal;
-
-
- self.angles_y = current_yaw;
- };
-
- /*╔═══════════════════════════════════╗
- ║ ║
- ║ Cujo_jumptouch ║
- ║ ║
- ╚═══════════════════════════════════╝*/
-
- void() CUJO_JumpTouch =
- {
- local float ldmg;
-
- if (self.health <= 0) return;
-
- if (other.takedamage)
- {
- if ( vlen(self.velocity) > 300 )
- {
- // Cujo now has a chance to gib on a jumping attack
- ldmg = 20 + 20*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 = dog_leap1;
- self.nextthink = time + nextthinktime;
- }
- return; // not on ground yet
- }
- */
- self.touch = SUB_Null;
- self.think = dog_run1;
- self.nextthink = time + nextthinktime;
- };
-
-
- void() CUJO_stand1 =[ $stand1, CUJO_stand2 ] {CUJO_ai_stand();};
- void() CUJO_stand2 =[ $stand2, CUJO_stand3 ] {CUJO_ai_stand();};
- void() CUJO_stand3 =[ $stand3, CUJO_stand4 ] {CUJO_ai_stand();};
- void() CUJO_stand4 =[ $stand4, CUJO_stand5 ] {CUJO_ai_stand();};
- void() CUJO_stand5 =[ $stand5, CUJO_stand6 ] {CUJO_ai_stand();};
- void() CUJO_stand6 =[ $stand6, CUJO_stand7 ] {CUJO_ai_stand();};
- void() CUJO_stand7 =[ $stand7, CUJO_stand8 ] {CUJO_ai_stand();};
- void() CUJO_stand8 =[ $stand8, CUJO_stand9 ] {CUJO_ai_stand();};
- void() CUJO_stand9 =[ $stand9, CUJO_stand1 ] {CUJO_ai_stand();};
-
- /*╔═══════════════════════════════════╗
- ║ ║
- ║ Cujo_walk1 ║
- ║ ║
- ╚═══════════════════════════════════╝*/
-
-
- void() CUJO_walk1 =[ $walk1 , CUJO_walk2 ]
- {
- if (random() < 0.2)
- sound (self, CHAN_VOICE, "dog/idle.wav", 1, ATTN_IDLE);
-
- CUJO_ai_walk (8);
- };
-
-
- void() CUJO_walk2 =[ $walk2 , CUJO_walk3 ] {CUJO_ai_walk(8);};
- void() CUJO_walk3 =[ $walk3 , CUJO_walk4 ] {CUJO_ai_walk(8);};
- void() CUJO_walk4 =[ $walk4 , CUJO_walk5 ] {CUJO_ai_walk(8);};
- void() CUJO_walk5 =[ $walk5 , CUJO_walk6 ] {CUJO_ai_walk(8);};
- void() CUJO_walk6 =[ $walk6 , CUJO_walk7 ] {CUJO_ai_walk(8);};
- void() CUJO_walk7 =[ $walk7 , CUJO_walk8 ] {CUJO_ai_walk(8);};
- void() CUJO_walk8 =[ $walk8 , CUJO_walk1 ] {CUJO_ai_walk(8);};
-
- /*╔═══════════════════════════════════╗
- ║ ║
- ║ Cujo_run1 ║
- ║ ║
- ╚═══════════════════════════════════╝*/
-
- void() CUJO_run1 =[ $run1 , CUJO_run2 ]
- {
- if (random() < 0.2)
- sound (self, CHAN_VOICE, "dog/idle.wav", 1, ATTN_IDLE);
-
- CUJO_ai_run (16);
- };
-
- void() CUJO_run2 =[ $run2 , CUJO_run3 ] {CUJO_ai_run(32);};
- void() CUJO_run3 =[ $run3 , CUJO_run4 ] {CUJO_ai_run(32);};
- void() CUJO_run4 =[ $run4 , CUJO_run5 ] {CUJO_ai_run(20);};
- void() CUJO_run5 =[ $run5 , CUJO_run6 ] {CUJO_ai_run(64);};
- void() CUJO_run6 =[ $run6 , CUJO_run7 ] {CUJO_ai_run(32);};
- void() CUJO_run7 =[ $run7 , CUJO_run8 ] {CUJO_ai_run(16);};
- void() CUJO_run8 =[ $run8 , CUJO_run9 ] {CUJO_ai_run(32);};
- void() CUJO_run9 =[ $run9 , CUJO_run10 ] {CUJO_ai_run(32);};
- void() CUJO_run10 =[ $run10 , CUJO_run11 ] {CUJO_ai_run(20);};
- void() CUJO_run11 =[ $run11 , CUJO_run12 ] {CUJO_ai_run(64);};
- void() CUJO_run12 =[ $run12 , CUJO_run1 ] {CUJO_ai_run(32);};
-
- void() CUJO_follow1 =[ $run1 , CUJO_follow2 ]
- {
- if (random() < 0.2)
- sound (self, CHAN_VOICE, "dog/idle.wav", 1, ATTN_IDLE);
-
- CUJO_ResetGoalEntity ();
-
- CUJO_ai_follow (18);
- };
- void() CUJO_follow2 =[ $run2 , CUJO_follow3 ] {CUJO_ai_follow (32);};
- void() CUJO_follow3 =[ $run3 , CUJO_follow4 ] {CUJO_ai_follow (32);};
- void() CUJO_follow4 =[ $run4 , CUJO_follow5 ] {CUJO_ai_follow (20);};
- void() CUJO_follow5 =[ $run5 , CUJO_follow6 ] {CUJO_ai_follow (64);};
- void() CUJO_follow6 =[ $run6 , CUJO_follow7 ] {CUJO_ai_follow (32);};
- void() CUJO_follow7 =[ $run7 , CUJO_follow8 ] {CUJO_ai_follow (16);};
- void() CUJO_follow8 =[ $run8 , CUJO_follow9 ] {CUJO_ai_follow (32);};
- void() CUJO_follow9 =[ $run9 , CUJO_follow10 ] {CUJO_ai_follow(32);};
- void() CUJO_follow10 =[ $run10 , CUJO_follow11 ] {CUJO_ai_follow(20);};
- void() CUJO_follow11 =[ $run11 , CUJO_follow12 ] {CUJO_ai_follow(64);};
- void() CUJO_follow12 =[ $run12 , CUJO_follow1 ] {CUJO_ai_follow(32);};
-
-
- /*╔═══════════════════════════════════╗
- ║ ║
- ║ Cujo_atta1 ║
- ║ ║
- ╚═══════════════════════════════════╝*/
-
-
- void() CUJO_atta1 =[ $attack1, CUJO_atta2 ] {ai_charge(10);};
- void() CUJO_atta2 =[ $attack2, CUJO_atta3 ] {ai_charge(10);};
- void() CUJO_atta3 =[ $attack3, CUJO_atta4 ] {ai_charge(10);};
-
- void() CUJO_atta4 =[ $attack4, CUJO_atta5 ]
- {
- sound (self, CHAN_VOICE, "dog/dattack1.wav", 1, ATTN_NORM);
- CUJO_bite();
- };
-
- void() CUJO_atta5 =[ $attack5, CUJO_atta6 ] {ai_charge(10);};
- void() CUJO_atta6 =[ $attack6, CUJO_atta7 ] {ai_charge(10);};
- void() CUJO_atta7 =[ $attack7, CUJO_atta8 ] {ai_charge(10);};
- void() CUJO_atta8 =[ $attack8, CUJO_run1 ]
- {
- local float r;
-
- if (self.goalentity.classname == "dog_food")
- {
- // CUJO 1.3 - fix for BodyQue bug
- // don't remove a cujo or a player head, because they are in the
- // body que, simply change their classname to "head" and model to
- // "" and cujo will ignore them
- if ((self.goalentity.model == "progs/h_cujo.mdl") ||
- (self.goalentity.model == "progs/player.mdl"))
- {
- self.goalentity.classname = "head";
- setmodel (self.goalentity, "");
- }
- else
- remove (self.goalentity);
- self.health = self.health + 15;
-
- if ((deathmatch) && (self.health > 100))
- self.health = 100;
- else if (self.health > 200)
- self.health = 200;
-
- r = random ();
-
- if (r < 0.25)
- sprint (self.owner, "Cujo likes his Gibby-chow!\n");
- else if (r < 0.5)
- sprint (self.owner, "Dogs love a Gibby-Treat!\n");
- else if (r < 0.75)
- sprint (self.owner, "Cujo ate some gibs.\n");
- else
- sprint (self.owner, "Cujo's eating his enemies again...\n");
-
- }
- else
- CUJO_ai_charge (10);
-
- CUJO_CheckRefire (CUJO_atta1);
- };
-
- /*╔═══════════════════════════════════╗
- ║ ║
- ║ Cujo_leap1 ║
- ║ ║
- ╚═══════════════════════════════════╝*/
-
- void() CUJO_leap1 =[ $leap1, CUJO_leap2 ] {ai_face();};
- void() CUJO_leap2 =[ $leap2, CUJO_leap3 ]
- {
- CUJO_ai_face();
- self.touch = CUJO_JumpTouch;
-
- makevectors (self.angles);
-
- self.origin_z = self.origin_z + 1;
- self.velocity = v_forward * forward_jump_vel + v_up * upward_jump_vel;
- /*
- bprint ("fv=");
- bprint (ftos (forward_jump_vel));
- bprint (", uv=");
- bprint (ftos (upward_jump_vel));
- bprint ("\n");
- */
- if (self.flags & FL_ONGROUND)
- self.flags = self.flags - FL_ONGROUND;
- };
-
- void() CUJO_leap3 =[ $leap3, CUJO_leap4 ] {};
- void() CUJO_leap4 =[ $leap4, CUJO_leap5 ] {};
- void() CUJO_leap5 =[ $leap5, CUJO_leap6 ] {};
- void() CUJO_leap6 =[ $leap6, CUJO_leap7 ] {};
- void() CUJO_leap7 =[ $leap7, CUJO_leap8 ] {};
- void() CUJO_leap8 =[ $leap8, CUJO_leap9 ] {};
- void() CUJO_leap9 =[ $leap9, CUJO_leap9 ] {};
-
- /*╔═══════════════════════════════════╗
- ║ ║
- ║ Cujo_pain1 ║
- ║ ║
- ╚═══════════════════════════════════╝*/
-
- void() CUJO_pain1 =[ $pain1 , CUJO_pain2 ] {};
- void() CUJO_pain2 =[ $pain2 , CUJO_pain3 ] {};
- void() CUJO_pain3 =[ $pain3 , CUJO_pain4 ] {};
- void() CUJO_pain4 =[ $pain4 , CUJO_pain5 ] {};
- void() CUJO_pain5 =[ $pain5 , CUJO_pain6 ] {};
- void() CUJO_pain6 =[ $pain6 , CUJO_run1 ] {};
-
- void() CUJO_painb1 =[ $painb1 , CUJO_painb2 ] {};
- void() CUJO_painb2 =[ $painb2 , CUJO_painb3 ] {};
- void() CUJO_painb3 =[ $painb3 , CUJO_painb4 ] {ai_pain(4);};
- void() CUJO_painb4 =[ $painb4 , CUJO_painb5 ] {ai_pain(12);};
- void() CUJO_painb5 =[ $painb5 , CUJO_painb6 ] {ai_pain(12);};
- void() CUJO_painb6 =[ $painb6 , CUJO_painb7 ] {ai_pain(2);};
- void() CUJO_painb7 =[ $painb7 , CUJO_painb8 ] {};
- void() CUJO_painb8 =[ $painb8 , CUJO_painb9 ] {ai_pain(4);};
- void() CUJO_painb9 =[ $painb9 , CUJO_painb10 ] {};
- void() CUJO_painb10 =[ $painb10 , CUJO_painb11 ] {ai_pain(10);};
- void() CUJO_painb11 =[ $painb11 , CUJO_painb12 ] {};
- void() CUJO_painb12 =[ $painb12 , CUJO_painb13 ] {};
- void() CUJO_painb13 =[ $painb13 , CUJO_painb14 ] {};
- void() CUJO_painb14 =[ $painb14 , CUJO_painb15 ] {};
- void() CUJO_painb15 =[ $painb15 , CUJO_painb16 ] {};
- void() CUJO_painb16 =[ $painb16 , CUJO_run1 ] {};
-
- void() CUJO_pain =
- {
- if (self.dmg_inflictor.classname == "fire")
- {
- if (random() > 0.5)
- {
- if (self.pain_finished > time)
- return;
-
- if (random () > 0.2)
- {
- CUJO_pain1 ();
- self.pain_finished = time + 0.6;
- }
- else
- {
- self.pain_finished = time + 1.6;
- CUJO_painb1 ();
- }
-
- sound (self, CHAN_VOICE, "dog/dpain1.wav", 1, ATTN_NORM);
- }
- }
- else
- {
- sound (self, CHAN_VOICE, "dog/dpain1.wav", 1, ATTN_NORM);
-
- if (random() > 0.5)
- CUJO_pain1 ();
- else
- CUJO_painb1 ();
- }
- };
-
- /*╔═══════════════════════════════════╗
- ║ ║
- ║ Cujo_die ║
- ║ ║
- ║ Cujo deactivates self in last ║
- ║ frame ║
- ║ ║
- ╚═══════════════════════════════════╝*/
-
- void() CUJO_die1 =[ $death1, CUJO_die2 ] {};
- void() CUJO_die2 =[ $death2, CUJO_die3 ] {};
- void() CUJO_die3 =[ $death3, CUJO_die4 ] {};
- void() CUJO_die4 =[ $death4, CUJO_die5 ] {};
- void() CUJO_die5 =[ $death5, CUJO_die6 ] {};
- void() CUJO_die6 =[ $death6, CUJO_die7 ] {};
- void() CUJO_die7 =[ $death7, CUJO_die8 ] {};
- void() CUJO_die8 =[ $death8, CUJO_die9 ] {};
- void() CUJO_die9 =[ $death9, CUJO_die9 ] {CUJO_SelfDeactivate ();};
- /*
- // used to set the dead-entity body to the correct final death frame
- // then set up the next think to make the body disappear
- void() CUJO_die10 =[ $death9, CUJO_die10 ]
- {
- self.nextthink = time + 120; // wait 2 minutes till body disappears
- self.think = SUB_Remove;
- };
- */
- void() CUJO_dieb1 =[ $deathb1, CUJO_dieb2 ] {};
- void() CUJO_dieb2 =[ $deathb2, CUJO_dieb3 ] {};
- void() CUJO_dieb3 =[ $deathb3, CUJO_dieb4 ] {};
- void() CUJO_dieb4 =[ $deathb4, CUJO_dieb5 ] {};
- void() CUJO_dieb5 =[ $deathb5, CUJO_dieb6 ] {};
- void() CUJO_dieb6 =[ $deathb6, CUJO_dieb7 ] {};
- void() CUJO_dieb7 =[ $deathb7, CUJO_dieb8 ] {};
- void() CUJO_dieb8 =[ $deathb8, CUJO_dieb9 ] {};
- void() CUJO_dieb9 =[ $deathb9, CUJO_dieb9 ] {CUJO_SelfDeactivate ();};
- /*
- // used to set the dead-entity body to the correct final death frame
- // then set up the next think to make the body disappear
- void() CUJO_dieb10 =[ $deathb9, CUJO_dieb10 ]
- {
- self.nextthink = time + 120; // wait 2 minutes till body disappears
- self.think = SUB_Remove;
- };
- */
-
- void() CUJO_die =
- {
- // check for gib
- if (self.health < -35)
- {
- sound (self, CHAN_VOICE, "player/udeath.wav", 1, ATTN_NORM);
- ThrowGib ("progs/gib3.mdl", self.health);
- ThrowGib ("progs/gib3.mdl", self.health);
- ThrowGib ("progs/gib3.mdl", self.health);
-
- ThrowHead ("progs/h_cujo.mdl", self.health);
-
- // Cujo heads only lay around for 2 minutes, then POOF!
- // self.nextthink = time + 120;
- // self.think = SUB_Remove;
-
- CUJO_SelfDeactivate ();
-
- return;
- }
-
- // regular death
- sound (self, CHAN_VOICE, "dog/ddeath.wav", 1, ATTN_NORM);
- self.solid = SOLID_NOT;
-
- self.deadflag = DEAD_DYING;
-
- if (random() > 0.5)
- CUJO_die1 ();
- else
- CUJO_dieb1 ();
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_checkmelee ║
- ║ ║
- ║ Returns TRUE if a melee attack would hit right now ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- float() CUJO_CheckMelee =
- {
- local float dist;
-
- dist = vlen (self.goalentity.origin - self.origin);
-
- if ( ((self.goalentity.classname == "dog_food") && (dist < 100)) ||
- ((self.goalentity.classname != "dog_food") && (dist < 50)) )
- // if (goal_range == RANGE_MELEE)
- {
- self.attack_state = AS_MELEE;
-
- // bprint ("CUJO_CheckMelee says TRUE!\n");
-
- return TRUE;
- }
-
- return FALSE;
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_checkjump ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- float() CUJO_CheckJump =
- {
- local vector dist;
- local float d;
-
- if (self.origin_z + self.mins_z > self.goalentity.origin_z + self.goalentity.mins_z
- + 0.75 * self.goalentity.size_z)
- return FALSE;
-
- if (self.origin_z + self.maxs_z < self.goalentity.origin_z + self.goalentity.mins_z
- + 0.25 * self.goalentity.size_z)
- return FALSE;
-
- dist = self.goalentity.origin - self.origin;
- dist_z = 0;
-
- d = vlen(dist);
-
- if (d < 80) return FALSE;
-
- if (d > 150) return FALSE;
-
- return TRUE;
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ CUJO_SpawnMarker ║
- ║ ║
- ║ For debugging: spawns a temporary marker at the passed location ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void (vector org, string mdl_name) CUJO_SpawnMarker =
- {
- local entity marker;
-
- marker = spawn ();
-
- marker.solid = SOLID_NOT;
- marker.movetype = MOVETYPE_NONE;
- marker.think = SUB_Remove;
- marker.nextthink = time + 10;
- marker.takedamage = DAMAGE_NO;
- marker.classname = "debug_marker";
-
- setsize (marker, '0 0 0', '0 0 0');
- setorigin (marker, org);
- setmodel (marker, mdl_name);
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ CUJO_FindWater ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- float () CUJO_FindWater =
-
- {
- local float i, found_water, highest;
- local vector org, end;
-
- makevectors (self.angles);
-
- // check to see if cujo is already in water
- org = self.origin;
- end = org - (v_up * 1000);
- traceline (org, end, TRUE, self);
- if ((trace_inwater) && (!trace_inopen))
- return 0;
-
- found_water = FALSE;
- i = 0;
- while ((i <= 270) && (!found_water))
- {
- // check the four corners of a 30x30 unit square i units in front of cujo
- // upper right corner
-
- org = self.origin + (v_forward * (i + 30)) + (v_right * 15);
- end = org - (v_up * 1000);
- traceline (org, end, FALSE, self);
- highest = trace_fraction;
-
- if (trace_inwater)
- {
- // upper left corner
- org = self.origin + (v_forward * (i + 30)) - (v_right * 15);
- end = org - (v_up * 1000);
- traceline (org, end, FALSE, self);
- if (trace_fraction < highest) highest = trace_fraction;
-
- if (trace_inwater)
- {
- // lower right corner
- org = self.origin + (v_forward * i) + (v_right * 15);
- end = org - (v_up * 1000);
- traceline (org, end, FALSE, self);
- if (trace_fraction < highest) highest = trace_fraction;
-
- if (trace_inwater)
- {
- // lower left corner
- org = self.origin + (v_forward * i) - (v_right * 15);
- end = org - (v_up * 1000);
- traceline (org, end, FALSE, self);
- if (trace_fraction < highest) highest = trace_fraction;
-
- if (trace_inwater)
- {
- // center
- org = self.origin + (v_forward * (i + 15));
- end = org - (v_up * 1000);
- traceline (org, end, FALSE, self);
- if (trace_fraction < highest) highest = trace_fraction;
-
- if (trace_inwater)
- {
- // half way between center and left back corner
- org = self.origin + (v_forward * (i + 7.5)) - (v_right * 7.5);
- end = org - (v_up * 1000);
- traceline (org, end, FALSE, self);
- if (trace_fraction < highest) highest = trace_fraction;
-
- if (trace_inwater)
- {
- // half way between center and right back corner
- org = self.origin + (v_forward * (i + 7.5)) + (v_right * 7.5);
- end = org - (v_up * 1000);
- traceline (org, end, FALSE, self);
- if (trace_fraction < highest) highest = trace_fraction;
-
- if (trace_inwater) found_water = TRUE;
- }
- }
- }
- }
- }
- }
- i = i + 12;
- }
-
- if (found_water)
- {
- // bprint ("water ");
- // bprint (ftos (i));
- // bprint (", ");
-
- return i;
- }
- else
- return 0;
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ CUJO_Findgap ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- float () CUJO_FindGap =
-
- {
- local float i, found_gap, gap_depth, min_depth, max_depth, grade, trace_depth;
- local vector org, end;
-
- makevectors (self.angles);
-
- found_gap = FALSE;
- gap_depth = 0.016;
- trace_depth = 1000;
-
- i = 0;
- while ((i <= 270) && (!found_gap))
- {
- // check the four corners of a 30x30 unit square i units in front of cujo
- // upper right corner
- org = self.origin + (v_forward * (i + 30)) + (v_right * 15);
- end = org - (v_up * trace_depth);
- traceline (org, end, FALSE, self);
- max_depth = trace_fraction;
- min_depth = trace_fraction;
-
- if (trace_fraction > gap_depth)
- {
- // upper left corner
- org = self.origin + (v_forward * (i + 30)) - (v_right * 15);
- end = org - (v_up * trace_depth);
- traceline (org, end, FALSE, self);
- if (trace_fraction < min_depth) min_depth = trace_fraction;
- if (trace_fraction > max_depth) max_depth = trace_fraction;
-
- if (trace_fraction > gap_depth)
- {
- // lower right corner
- org = self.origin + (v_forward * i) + (v_right * 15);
- end = org - (v_up * trace_depth);
- traceline (org, end, FALSE, self);
- if (trace_fraction < min_depth) min_depth = trace_fraction;
- if (trace_fraction > max_depth) max_depth = trace_fraction;
-
- if (trace_fraction > gap_depth)
- {
- // lower left corner
- org = self.origin + (v_forward * i) - (v_right * 15);
- end = org - (v_up * trace_depth);
- traceline (org, end, FALSE, self);
- if (trace_fraction < min_depth) min_depth = trace_fraction;
- if (trace_fraction > max_depth) max_depth = trace_fraction;
-
- if (trace_fraction > gap_depth)
- {
- // center
- org = self.origin + (v_forward * (i + 15));
- end = org - (v_up * trace_depth);
- traceline (org, end, FALSE, self);
- if (trace_fraction < min_depth) min_depth = trace_fraction;
- if (trace_fraction > max_depth) max_depth = trace_fraction;
-
- if (trace_fraction > gap_depth)
- {
- // half way between center and left back corner
- org = self.origin + (v_forward * (i + 7.5)) - (v_right * 7.5);
- end = org - (v_up * trace_depth);
- traceline (org, end, FALSE, self);
- if (trace_fraction < min_depth) min_depth = trace_fraction;
- if (trace_fraction > max_depth) max_depth = trace_fraction;
-
- if (trace_fraction > gap_depth)
- {
- // half way between center and right back corner
- org = self.origin + (v_forward * (i + 7.5)) + (v_right * 7.5);
- end = org - (v_up * trace_depth);
- traceline (org, end, FALSE, self);
- if (trace_fraction < min_depth) min_depth = trace_fraction;
- if (trace_fraction > max_depth) max_depth = trace_fraction;
-
- if (trace_fraction > gap_depth)
- {
- max_depth = max_depth * trace_depth;
- min_depth = min_depth * trace_depth;
- grade = (max_depth - min_depth) / 30;
-
- if (grade > 1.5)
- found_gap = TRUE;
- }
- }
- }
- }
- }
- }
- }
- i = i + 30;
- }
-
- if (found_gap)
- {
- /*
- bprint ("gap=");
- bprint (ftos (i));
- bprint (" min=");
- bprint (ftos(min_depth));
- bprint (" max=");
- bprint (ftos(max_depth));
- bprint (", ");
- */
- return i;
- }
- else
- {
- /*
- bprint ("gap=");
- bprint (ftos (i));
- bprint (" min=");
- bprint (ftos(min_depth));
- bprint (" max=");
- bprint (ftos(max_depth));
- bprint (", ");
- */
- return 0;
- }
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ CUJO_FindLedge ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- float (float start_dist) CUJO_FindLedge =
-
- {
- local float i;
- local vector org, end, above_org;
- local float highest, pc;
- local float found_ledge;
- local float ledge_height;
-
- if (start_dist > 440)
- return 0;
-
- makevectors (self.angles);
- // start origin is 48 units above Cujo's origin
- above_org = self.origin + (v_up * 48);
-
- ledge_height = 0.096;
- found_ledge = FALSE;
- i = start_dist + 30;
-
- while ((i <= 440) && (!found_ledge))
- {
- // check the four corners of a 30x30 unit square i units in front of cujo
- // upper right corner
- org = above_org + (v_forward * (i + 30)) + (v_right * 15);
- end = org - (v_up * 1000);
- traceline (org, end, FALSE, self);
- highest = trace_fraction;
-
- // upper left corner
- if (trace_fraction <= ledge_height)
- {
- org = above_org + (v_forward * (i + 30)) - (v_right * 15);
- end = org - (v_up * 1000);
- traceline (org, end, FALSE, self);
- if (trace_fraction < highest) highest = trace_fraction;
-
- if (trace_fraction <= ledge_height)
- {
- // lower right corner
- org = above_org + (v_forward * i) + (v_right * 15);
- end = org - (v_up * 1000);
- traceline (org, end, FALSE, self);
- if (trace_fraction < highest) highest = trace_fraction;
-
- if (trace_fraction <= ledge_height)
- {
- // lower corner
- org = above_org + (v_forward * i) - (v_right * 15);
- end = org - (v_up * 1000);
- traceline (org, end, FALSE, self);
- if (trace_fraction < highest) highest = trace_fraction;
-
- if (trace_fraction <= ledge_height)
- {
- // center
- org = above_org + (v_forward * (i + 15));
- end = org - (v_up * 1000);
- traceline (org, end, FALSE, self);
- if (trace_fraction < highest) highest = trace_fraction;
-
- if (trace_fraction <= ledge_height)
- {
- // half way between center and left back corner
- org = above_org + (v_forward * (i + 7.5)) - (v_right * 7.5);
- end = org - (v_up * 1000);
- traceline (org, end, FALSE, self);
- if (trace_fraction < highest) highest = trace_fraction;
-
- if (trace_fraction <= ledge_height)
- {
- // half way between center and right back corner
- org = above_org + (v_forward * (i + 7.5)) + (v_right * 7.5);
- end = org - (v_up * 1000);
- traceline (org, end, FALSE, self);
- if (trace_fraction < highest) highest = trace_fraction;
-
- if (trace_fraction <= ledge_height) found_ledge = TRUE;
- }
- }
- }
- }
- }
- }
- i = i + 30;
- }
-
- if (found_ledge)
- {
- // bprint ("ledge ");
- // bprint (ftos (i));
- // bprint (", ");
-
- //FIXME: predict velocities based on server gravity
-
- highest = highest * 1000;
- // is ledge above Cujo's origin?
- if (highest < 48)
- {
- // bprint ("-above");
- upward_jump_vel = 270;
- forward_jump_vel = i * 1.5;
- }
- else
- {
- upward_jump_vel = 270;
- forward_jump_vel = i * 1.5;
- return i;
- }
- }
- else
- return 0;
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ CUJO_JumpObstructed ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- float (float dist) CUJO_JumpObstructed =
-
- {
- local vector org, end;
- local float pc;
-
- makevectors (self.angles);
- org = self.origin;
- end = self.origin + (v_forward * dist);
-
- traceline (org, end, FALSE, self);
- pc = pointcontents (trace_endpos);
-
- if ((trace_fraction < 1.0) || (pc == CONTENT_SOLID))
- return TRUE;
- else
- return FALSE;
- };
-
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ CUJO_JumpAI ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void () CUJO_JumpAI =
- {
- local vector dir, org, end;
- local float dist;
-
- if (!checkbottom (self) || (self.think == self.th_missile))
- return;
-
- org = self.origin;
- end = self.goalentity.origin;
-
- if (self.dmg_inflictor.classname == "fire")
- {
- dist = CUJO_FindWater ();
-
- if ((dist > 0) && (dist < 125) && (!CUJO_JumpObstructed (dist)))
- {
- // Cujo found water he can jump into
- // FIX: base velocities on server gravity
- upward_jump_vel = 230;
- forward_jump_vel = dist * 1.9;
- self.nextthink = time + 0.1;
- self.think = self.th_missile;
-
- sprint (self.owner, "Swim, Cujo! Swim!\n");
- // bprint ("\n");
- return TRUE;
- }
- bprint ("\n");
- }
- else if (org_z - end_z > 48)
- {
- // bprint ("JumpDown:");
- dist = CUJO_FindWater ();
-
- if (dist == 0)
- dist = CUJO_FindGap ();
-
- if ((dist) && (dist < 125) && (!CUJO_JumpObstructed (dist)))
- {
- // Cujo found water or a gap he can jump into
- upward_jump_vel = 230;
- forward_jump_vel = dist * 1.9;
- self.nextthink = time + 0.1;
- self.think = self.th_missile;
-
- // bprint ("\n");
- return TRUE;
- }
- // bprint ("\n");
- }
- else if ((org_z - end_z <= 48) && (self.ideal_yaw == anglemod (self.angles_y)))
- {
- // bprint ("JumpAcross:");
-
- // turn Cujo to _exactly_ the direction of his goal entity
- dir = self.goalentity.origin - self.origin;
- dir = normalize (dir);
- self.angles_y = vectoyaw (dir);
- self.ideal_yaw = vectoyaw (dir);
-
- dist = CUJO_FindWater ();
-
- if (dist <= 0)
- dist = CUJO_FindGap ();
-
- if ((dist > 0) && (dist < 150) && (vlen (self.goalentity.origin - self.origin) >= dist))
- {
- dist = CUJO_FindLedge (dist);
-
- // if ((!CUJO_JumpObstructed (dist)) && (dist > 0))
- if (dist > 0)
- {
- // bprint ("jump\n");
-
- // Cujo found a barrier he needs to jump
- self.nextthink = time + 0.1;
- self.think = self.th_missile;
-
- return TRUE;
- }
- }
- // bprint ("\n");
- }
-
- return FALSE;
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_checkattack ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- // this checks the attack against self.goalentity not self.enemy!
-
- float() CUJO_CheckAttack =
- {
- local vector vec;
-
- if ((((self.goalentity == self.owner) || (self.goalentity.classname == "monster_zombie"))
- || (self.Cujo_attack == FALSE)) && (self.goalentity.classname != "dog_food"))
- {
- CUJO_ResetGoalEntity ();
-
- self.think = self.th_stand;
- self.nextthink = time + nextthinktime;
-
- return FALSE;
- }
-
- if (CUJO_CheckMelee ())
- {
- self.attack_state = AS_MELEE;
- return TRUE;
- }
-
- if (self.goalentity.classname != "dog_food")
- {
- if (CUJO_CheckJump ())
- {
- self.attack_state = AS_MISSILE;
- return TRUE;
- }
- }
-
- return FALSE;
-
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ CUJO_ai_run_melee ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void() CUJO_ai_run_melee =
- {
- CUJO_ai_face ();
-
- if (FacingIdeal())
- {
- self.th_melee ();
- self.attack_state = AS_STRAIGHT;
- }
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ CUJO_ai_run_missile ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void() CUJO_ai_run_missile =
- {
- CUJO_ai_face ();
-
- if (FacingIdeal())
- {
- upward_jump_vel = 270;
- forward_jump_vel = 360;
- self.th_missile ();
- self.attack_state = AS_STRAIGHT;
- }
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_ai_run ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void(float dist) CUJO_ai_run =
- {
- local vector delta;
- local float axis;
- local float direct, ang_rint, ang_floor, ang_ceil, f_temp;
- local string str_temp;
-
- // sprint (self.owner, "-- enter ai_run --\n");
-
- movedist = dist;
-
- // sprint (self.owner, "Enemy is ");
- // sprint (self.owner, self.enemy.classname);
- // sprint (self.owner, "\n");
- // sprint (self.owner, "Goalentity is ");
- // sprint (self.owner, self.goalentity.classname);
- // sprint (self.owner, "\n");
-
- if ((self.goalentity.classname != "dog_food") && (self.goalentity.health <= 0))
- {
- CUJO_ResetGoalEntity ();
-
- //sprint (self.owner, "CUJO_ai_run: reset goalentity\n");
-
- if (self.oldenemy.health > 0)
- {
- self.enemy = self.oldenemy;
- self.goalentity = self.oldenemy;
-
- CUJO_HuntTarget ();
- }
- else
- {
- if (CUJO_FindTarget()) return;
- else
- {
- CUJO_ResetGoalEntity ();
-
- //sprint (self.owner, "CUJO_ai_run #2: reset goalentity\n");
-
- self.th_walk ();
-
- // sprint (self.owner, "-- Left ai_run at return 1 --\n");
- return;
- }
- }
-
- // sprint (self.owner, "-- Left ai_run at return 2 --\n");
- return;
- }
-
- if (self.goalentity.classname != "dog_food")
- self.show_hostile = time + 1; // wake up other monsters
-
- goal_vis = visible(self.goalentity);
- if (goal_vis) self.search_time = time + 5;
-
- goal_infront = infront (self.goalentity);
- goal_range = range (self.goalentity);
- goal_yaw = vectoyaw (self.goalentity.origin - self.origin);
-
- if ((self.attack_state == AS_MISSILE) && (self.goalentity.classname != "dog_food"))
- {
- CUJO_ai_run_missile ();
- return;
- }
- if (self.attack_state == AS_MELEE)
- {
-
- // for debugging
- // f_temp = vlen (self.origin - self.goalentity.origin);
- // str_temp = ftos (f_temp);
-
- // sprint (self.owner, "Cujo is ");
- // sprint (self.owner, str_temp);
- // sprint (self.owner, " units from ");
- // sprint (self.owner, self.goalentity.classname);
- // sprint (self.owner, ".\n");
-
- CUJO_ai_run_melee ();
-
- return;
- }
-
- if (CUJO_JumpAI ()) return; // needs to jump to goal
- if (CUJO_CheckAttack ()) return; // beginning an attack
-
- movetogoal (dist); // done in C code...
-
- // sprint (self.owner, "-- exit ai_run --\n");
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_SightSound ║
- ║ ║
- ║ dog stands in place until target acquired or paustime is exceeded ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void() CUJO_SightSound =
- {
- sound (self, CHAN_VOICE, "dog/dsight.wav", 1, ATTN_NORM);
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_HuntTarget ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void() CUJO_HuntTarget =
- {
- // for debugging
- //sprint (self.owner, "CUJO_HuntTarget: ");
- //sprint (self.owner, self.goalentity.classname);
- //sprint (self.owner, "\n");
-
- self.think = self.th_run;
- self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin);
- self.nextthink = time + nextthinktime;
-
- SUB_AttackFinished (0.1);
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_FoundTarget ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void() CUJO_FoundTarget =
- {
- local float f_dist;
- local string s_dist;
- local float r;
-
- f_dist = vlen (self.goalentity.origin - self.origin);
- s_dist = ftos (f_dist);
-
- self.show_hostile = time + 1; // wake up other monsters
-
- r = random ();
-
- if (r < 0.5)
- sprint (self.owner, "rrrrRROOF!\n");
- else
- sprint (self.owner, "grrrrllll...\n");
-
- // for debugging
- //sprint (self.owner, "Cujo seeking target");
- //sprint (self.owner, self.goalentity.classname);
- //sprint (self.owner, "\n");
-
- CUJO_SightSound ();
-
- CUJO_HuntTarget ();
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_FindTarget ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- float() CUJO_FindTarget =
- {
- local entity head, selected;
- local entity food;
- local float dist, lastd;
- local float food_dist, food_lastd;
-
- // check for any enemies visible to Cujo
- dist = 600;
- food_dist = 600;
- selected = world;
- food = world;
-
- head = findradius(self.origin, dist);
-
- // CUJO 1.3 - trace_plane_dist was always equal to zero for some
- // unknown reason, so the code that used it was replaced
- while(head)
- {
- // search for food
- if ((head.classname == "dog_food") && (visible (head)))
- {
- if ((head != self) && (head != self.owner))
- {
- food_lastd = vlen (self.origin - head.origin);
- if (food_lastd < food_dist)
- // for efficiency's sake, go after the closest gib
- {
- food = head;
- food_dist = food_lastd;
- }
- }
- }
-
- // search for enemy
- if(!(head.flags & FL_NOTARGET) && ((head.flags & FL_CLIENT) || (head.flags & FL_MONSTER)))
- if (((teamplay) && (head.team != self.owner.team)) || (!teamplay))
- if ((head.health > 0) && (head != self) && (head != self.owner))
- if ((visible(head)) && (head.classname != "monster_zombie"))
- {
- lastd = vlen (self.origin - head.origin);
- if (lastd < dist)
- {
- selected = head;
- dist = lastd;
- }
- }
- head = head.chain;
- }
-
- self.enemy = selected;
-
- if ((food != world) && (food != self.owner) && (self.Cujo_attack)
- && ((self.health < 50) || ((deathmatch) && (self.health < 25))))
- {
- self.goalentity = food;
- self.enemy = food;
-
- CUJO_FoundTarget ();
-
- return TRUE;
- }
- else if ((self.enemy == world) || (self.enemy == self.owner))
- {
- if ((food != world) && (food != self.owner) && ((self.health < 191) &&
- (self.Cujo_attack)))
- {
- self.goalentity = food;
- self.enemy = food;
-
- CUJO_FoundTarget ();
-
- return TRUE;
- }
-
- return FALSE;
- }
- else // an enemy target has been sighted
- {
- if (!(self.Cujo_attack) || (self.enemy.classname == "dog_food"))
- // if not supposed to attack, just growl
- {
- if (random () < 0.10)
- {
- // make Cujo bark or growl
- if (random () < 0.5)
- sound (self, CHAN_VOICE, "dog/dsight.wav", 1, ATTN_NORM);
- else
- sound (self, CHAN_VOICE, "dog/dattack1.wav", 1, ATTN_NORM);
- }
-
- CUJO_ResetGoalEntity ();
-
- return FALSE;
- }
-
- // if Cujo is staying, make him attack!
- self.Cujo_stay = FALSE;
-
- self.goalentity = self.enemy;
-
- CUJO_FoundTarget();
-
- return TRUE;
- }
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ CUJO_ai_face ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void() CUJO_ai_face =
- {
- self.ideal_yaw = vectoyaw (self.goalentity.origin - self.origin);
- CUJO_ChangeYaw ();
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ CUJO_ai_charge ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void (float d) CUJO_ai_charge =
- {
- CUJO_ai_face ();
-
- movetogoal (d); // done in C code...
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_ai_stand ║
- ║ ║
- ║ dog stands in place until target acquired or paustime is exceeded ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void() CUJO_ai_stand =
- {
- if (CUJO_FindTarget ()) return;
-
- if (vlen (self.origin - self.owner.origin) > teleport_dist)
- {
- CUJO_TeleportToOwner ();
- }
- else if (vlen (self.origin - self.owner.origin) > 100)
- {
- // if Cujo is staying, then he shouldn't run in place!
- if (self.Cujo_stay == TRUE) return;
-
- CUJO_follow1 ();
-
- return;
- }
-
- if (CUJO_JumpAI ()) return;
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_ai_walk ║
- ║ ║
- ║ Cujo is walking and searching for targets ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void(float dist) CUJO_ai_walk =
- {
- if (CUJO_FindTarget ()) return;
-
- if (vlen (self.origin - self.owner.origin) > 100)
- {
- CUJO_follow1();
-
- return;
- }
- else if (vlen (self.origin - self.owner.origin) > teleport_dist)
- {
- CUJO_TeleportToOwner ();
- }
-
- if (CUJO_JumpAI ()) return;
-
- movetogoal (dist); // this is done in C code
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_ai_follow ║
- ║ ║
- ║ Cujo is following player and searching for targets ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void(float dist) CUJO_ai_follow =
- {
- if (CUJO_FindTarget ()) return;
-
- //sprint (self.owner, "Following owner.\n");
- //sprint (self.owner, "Goalentity is ");
- //sprint (self.owner, self.goalentity.classname);
- //sprint (self.owner, "\n");
- //sprint (self.owner, "Enemy is ");
- //sprint (self.owner, self.enemy.classname);
- //sprint (self.owner, "\n");
- //sprint (self.owner, "Movetarget is ");
- //sprint (self.owner, self.movetarget.classname);
- //sprint (self.owner, "\n");
-
- // if Cujo is in STAY mode then do not follow the player!
-
- if ((vlen (self.origin - self.owner.origin) <= 100) || (self.Cujo_stay))
- {
- self.pausetime = time + 2;
-
- self.th_stand ();
-
- return;
- }
- else if ((vlen (self.origin - self.owner.origin) > teleport_dist) &&
- (!intermission_running))
- {
- CUJO_TeleportToOwner ();
- }
-
- if (CUJO_JumpAI ()) return;
-
- movetogoal (dist); // done in C code
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_ai_turn ║
- ║ ║
- ║ Turn Cujo towards ideal_yaw if no enemies were sighted ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void() CUJO_ai_turn =
- {
- if (CUJO_FindTarget ()) return;
-
- CUJO_ChangeYaw ();
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_CheckRefire ║
- ║ ║
- ║ Determine if the enemy is still visible for attack ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void (void () thinkst) CUJO_CheckRefire =
- {
- if (!visible (self.goalentity) || (self.goalentity.health <= 0))
- {
- CUJO_ResetGoalEntity ();
-
- self.think = self.th_stand;
- self.nextthink = time + nextthinktime;
-
- return;
- }
-
- // self.think = thinkst; // was thinkst
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ CUJO_CorpsePain ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void () CUJO_CorpsePain =
- {
- SpawnMeatSpray (self.origin, crandom() * 100 * v_right);
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ CUJO_CorpseDie; ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void () CUJO_CorpseDie =
- {
- local float i;
- local float j;
-
- sound (self, CHAN_VOICE, "player/udeath.wav", 1, ATTN_NORM);
-
- bprint ("gibbed ");
- bprint (self.classname);
- bprint ("\n");
-
- // throw the head -- can be a player head or a cujo head only in this version!
- ThrowHead (self.weaponmodel, self.health);
-
- i = 0;
-
- while(i<3)
- {
- j = random();
-
- if(j > 0.6)
- ThrowGib ("progs/gib1.mdl", self.health);
- else if(j > 0.3)
- ThrowGib ("progs/gib2.mdl", self.health);
- else
- ThrowGib ("progs/gib3.mdl", self.health);
-
- i = i + 1;
- }
-
- // Cujo's head only stays around for 2 minutes...
- // self.nextthink = time + 120;
- // self.think = SUB_Remove;
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_SelfDeactivate ║
- ║ ║
- ║ Cujo deactivates himself (when he is killed, basically) ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void () CUJO_SelfDeactivate =
- {
- local entity temp_self;
-
- temp_self = self;
- self = self.owner;
-
- if (self.Cujo_view)
- CUJO_SetPlayerView ();
-
- self = temp_self;
-
- // create a dummy Cujo body... this alleviates the problem of the
- // original Cujo entity becoming lost if the player reactivates Cujo
- // before the body has disappeared
-
- // self.classname = "cujo_body";
-
- // create a body in the que which is solid
- self.weaponmodel = "progs/h_cujo.mdl";
- CopyToBodyQue (self);
-
- if (self.enemy == self.owner)
- {
- if (self.health < -35)
- {
- centerprint (self.owner, "You just turned Cujo into puppy chow.\n");
- }
- else
- {
- centerprint (self.owner, "You buried your dog.\n");
- }
- }
- else
- {
- if (self.health < -35)
- {
- centerprint (self.owner, "Cujo is kibbles and bits.\n");
- }
- else
- {
- centerprint (self.owner, "Cujo went to dog heaven.\n");
- }
- }
-
- self.owner.Cujo_flag = FALSE;
- remove (self);
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_TeleportPos ║
- ║ ║
- ║ Determines the best position for Cujo to spawn in ║
- ║ This procedure is to be called from Cujo's routines, not the player's ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- vector () CUJO_TeleportPos =
- {
- local vector org, temp, right, front;
-
- org = self.owner.origin;
-
- makevectors (self.owner.angles);
-
- // make front equal 50 units in front of the player
- front = 50 * normalize (v_forward);
- // and right equal fifty units to the right
- right = 50 * normalize (v_right);
-
-
- // right of player
-
- temp = org + right;
- if (CUJO_CheckSpawnPos (temp)) return temp;
-
- // left of player
-
- temp = org - right;
- if (CUJO_CheckSpawnPos (temp)) return temp;
-
- // in front of player
-
- temp = org + front;
- if (CUJO_CheckSpawnPos (temp)) return temp;
-
- // behind player
-
- temp = org - front;
- if (CUJO_CheckSpawnPos (temp)) return temp;
-
- };
-
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_TeleportToOwner ║
- ║ ║
- ║ Cujo teleports to his owner, the player ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void () CUJO_TeleportToOwner =
- {
- local vector org;
-
- // exit if in intermission
- if (intermission_running) return;
-
- // Check to see if there is room to teleport Cujo here, if not, say so and
- // exit.
- org = CUJO_TeleportPos ();
- if (org == '0 0 0')
- return;
-
- sprint (self.owner, "Whoof!\n");
- sound (self, CHAN_BODY, "dog/dsight.wav", 1, ATTN_NORM);
-
- spawn_tfog (self.origin);
-
- self.ideal_yaw = self.angles * '0 1 0';
- self.pausetime = time + 5;
- self.nextthink = time + nextthinktime;
- self.think = self.Cujo.th_stand;
-
- setorigin(self, org);
-
- spawn_tfog (self.origin);
- self.nextthink = time + nextthinktime;
- self.think = self.th_stand;
-
- return;
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Routines called by player, self=player ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_Precache ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void () CUJO_Precache =
- {
- // Precache Cujo's sounds
- precache_model2 ("progs/h_cujo.mdl");
- precache_model2 ("progs/cujo.mdl");
-
- precache_sound2 ("dog/dattack1.wav");
- precache_sound2 ("dog/ddeath.wav");
- precache_sound2 ("dog/dpain1.wav");
- precache_sound2 ("dog/dsight.wav");
- precache_sound2 ("dog/idle.wav");
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_CheckSpawnPos ║
- ║ ║
- ║ Returns true if Cujo's bounding box area around SpawnPos is free of ║
- ║ solid objects ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- float (vector SpawnPos) CUJO_CheckSpawnPos =
- {
- local vector XVector, YVector, ZPosVec, ZNegVec;
- local vector HalfYVec, HalfXVec, HalfZPosVec, HalfZNegVec;
- local float pc;
-
- // These vector offsets match Cujo's current size, but do not match
- // the exact size of the Dog model (which was too big to follow the
- // player some places), so the dog may at times look like his head
- // is in a wall, but he shouldn't get stuck (we hope).
-
- XVector = '16 0 0';
- HalfXVec = '8 0 0';
-
- YVector = '0 16 0';
- HalfYVec = '0 16 0';
-
- ZPosVec = '0 0 16';
- HalfZPosVec = '0 0 8';
- ZNegVec = '0 0 -24';
- HalfZNegVec = '0 0 -12';
-
- // check the very center of the box, just in case something is floating
- // there (for example, the moving "key cubes" at the end of e1m2)
-
- pc = pointcontents (SpawnPos);
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- // check half the distance to each face of the box. Again, this is
- // for floating or thin objects which might fit in between the face
- // edge and the center of the face
-
- pc = pointcontents (SpawnPos + HalfXVec);
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos - HalfXVec);
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos + HalfYVec);
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos - HalfYVec);
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos + HalfZPosVec);
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos + HalfZNegVec);
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
-
- // this checks the six faces of each side of Cujo's bounding box
-
- pc = pointcontents (SpawnPos + XVector);
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos - XVector);
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos + YVector);
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos - YVector);
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos + ZPosVec);
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos + ZNegVec);
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
-
- // Check the eight vertices of Cujo's bounding box
-
- pc = pointcontents (SpawnPos + XVector + YVector + ZPosVec);
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos + XVector + YVector + ZNegVec);
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos + XVector - YVector + ZPosVec);
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos + XVector - YVector + ZNegVec);
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos - XVector + YVector + ZPosVec);
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos - XVector + YVector + ZNegVec);
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos - XVector - YVector + ZPosVec);
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos - XVector - YVector + ZNegVec);
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
-
- // check the center of each edge of the box for content type
- // first check the center of the top 4 edges of the bounding box
-
- pc = pointcontents (SpawnPos + (YVector + ZPosVec));
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos - (YVector + ZPosVec));
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos + (XVector + ZPosVec));
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos - (XVector + ZPosVec));
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- // now check the center of the middle 4 edges of the bounding box
-
- pc = pointcontents (SpawnPos - (XVector + YVector));
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos - (XVector - YVector));
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos + (XVector + YVector));
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos + (XVector - YVector));
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- // now check the center of the bottom 4 edges of the bounding box
-
- pc = pointcontents (SpawnPos + (YVector + ZNegVec));
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos - (YVector + ZNegVec));
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos + (XVector + ZNegVec));
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- pc = pointcontents (SpawnPos - (XVector + ZNegVec));
- if (pc != CONTENT_EMPTY && pc != CONTENT_WATER) return FALSE;
-
- // if that doesn't check enough spots, then that's just too bad.
-
- return TRUE;
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_SpawnPos ║
- ║ ║
- ║ Determines the best position for Cujo to spawn in ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- vector () CUJO_SpawnPos =
- {
- local vector org, temp, right, front;
-
- org = self.origin;
-
- makevectors (self.angles);
-
- // make front equal 50 units in front of the player
- front = 50 * normalize (v_forward);
- // and right equal fifty units to the right
- right = 50 * normalize (v_right);
-
-
- // right of player
-
- temp = org + right;
- if (CUJO_CheckSpawnPos (temp)) return temp;
-
- // left of player
-
- temp = org - right;
- if (CUJO_CheckSpawnPos (temp)) return temp;
-
- // in front of player
-
- temp = org + front;
- if (CUJO_CheckSpawnPos (temp)) return temp;
-
- // behind player
-
- temp = org - front;
- if (CUJO_CheckSpawnPos (temp)) return temp;
-
- };
-
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_Activate ║
- ║ ║
- ║ Called by player, self = player ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void () CUJO_Activate =
- {
- local entity dogbot;
- local vector org;
- local float bit;
-
- // Check to see if there is room to spawn Cujo here, if not, say so and
- // exit.
-
- org = CUJO_SpawnPos ();
- if (org == '0 0 0')
- {
- centerprint (self, "There is no room for Cujo here.\n");
- return;
- }
-
- // Spawn Cujo
-
- dogbot = spawn();
- dogbot.solid = SOLID_BBOX;
- dogbot.movetype = MOVETYPE_STEP;
-
- dogbot.angles = self.angles;
- dogbot.classname = "cujo";
- dogbot.owner=self;
- self.Cujo=dogbot;
- self.Cujo_flag = TRUE;
- self.Cujo_auto = TRUE;
- self.Cujo_view = FALSE;
- self.Cujo.Cujo_attack = TRUE;
- self.Cujo.Cujo_stay = FALSE;
-
- dogbot.takedamage = DAMAGE_AIM;
- dogbot.goalentity = self;
- dogbot.movetarget = self;
- dogbot.pausetime = time + 5;
- dogbot.ideal_yaw = dogbot.angles * '0 1 0';
- dogbot.yaw_speed = 20; // was 30 for a normal dog, looks really odd from Cujo's view
-
- // lowered Cujo's view offset to 15 above the center of it's bounding box
- // (I have no idea if this is exactly right...)
-
- dogbot.view_ofs = '0 0 15';
-
- // this dog has some badass armor
-
- dogbot.health = 200;
- bit = IT_ARMOR3;
- dogbot.armortype = 0.8;
- dogbot.armorvalue = 200;
- dogbot.items = other.items - (other.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) + bit;
-
- // Set to automatic mode sequences at startup
-
- dogbot.th_stand = CUJO_stand1;
- dogbot.th_walk = CUJO_walk1;
- dogbot.th_run = CUJO_run1;
- dogbot.th_pain = CUJO_pain;
- dogbot.th_die = CUJO_die;
- dogbot.th_melee = CUJO_atta1;
- dogbot.th_missile = CUJO_leap1;
- dogbot.team = self.team;
- dogbot.deadflag = DEAD_NO;
-
- setmodel (dogbot, "progs/cujo.mdl");
-
- // Cujo's size was made the same as the player, (except for his height)
- // because he was having trouble getting though some narrow doorways
- // and halls.
-
- setsize (dogbot, '-16 -16 -24', '16 16 16');
- setorigin(dogbot, org);
-
- spawn_tfog (dogbot.origin);
-
- sound (self, CHAN_BODY, "dog/dattack1.wav", 1, ATTN_NORM);
- centerprint(self, "Cujo is here.\n");
-
- dogbot.nextthink = time + nextthinktime;
- dogbot.think = dogbot.th_stand;
-
- // remove powerup status from player
- self.Cujo_avail = 0;
-
- // used to determine if Cujo's think is a jumping frame
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_Deactivate ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void () CUJO_Deactivate =
- {
- spawn_tfog (self.Cujo.origin);
-
- if (self.Cujo_view)
- CUJO_SetPlayerView ();
-
- // prevents fire from continuing on the next cujo spawned if he
- // was burning but not dead when he was deactivated
- blaze_extinguishentity (self.Cujo);
-
- self.Cujo.nextthink = time + nextthinktime;
- self.Cujo.think = SUB_Remove;
- self.Cujo_flag = FALSE;
-
- centerprint (self, "Cujo went back to his doghouse.\n");
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_Toggle ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- // ver 1.2 - Changed spawning rule for deathmatch
- // ver 1.2 - uhhh... fixed spawning rules for deathmatch :)
-
- void () CUJO_Toggle =
- {
- if ((self.Cujo_flag) && (self.Cujo.deadflag == DEAD_DYING)) return;
-
- if (deathmatch)
- {
- if (self.Cujo_flag)
- {
- if ((self.deadflag == DEAD_DYING) || (self.deadflag == DEAD_DEAD))
- {
- CUJO_Deactivate ();
- }
- else
- sprint (self, "Cujo can't be sent away in deathmatch.\n");
- }
- else if (self.Cujo_avail)
- {
- CUJO_Activate ();
- }
- else
- sprint (self, "Cujo is not available.\n");
- }
- else
- {
- if (!(self.Cujo_flag))
- CUJO_Activate();
- else
- CUJO_Deactivate();
- }
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_AttackToggle ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void () CUJO_AttackToggle =
- {
- if (!(self.Cujo_flag))
- {
- CUJO_PrintCujoStatus ();
-
- return;
- }
-
- if (self.Cujo.Cujo_attack == TRUE)
- {
- self.Cujo.Cujo_attack = FALSE;
- sprint (self, "Cujo will not attack.\n");
-
- // reset Cujo's enemy so he doesn't whine even when the enemy goes
- // out of view.
-
- self.Cujo.enemy = world;
- self.Cujo.oldenemy = world;
- self.Cujo.goalentity = self;
- self.Cujo.movetarget = self;
-
- self.Cujo.think = self.Cujo.th_stand;
- self.Cujo.nextthink = time + nextthinktime;
- }
- else
- {
- self.Cujo.Cujo_attack = TRUE;
- sprint (self, "Cujo wants blood!\n");
- }
-
- return;
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_Attack ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
- /*
- void () CUJO_Attack =
- {
- local entity oldself;
- local vector org;
-
- if (!(self.Cujo_flag))
- {
- CUJO_PrintCujoStatus ();
-
- return;
- }
-
- oldself = self;
- self = self.Cujo;
-
- if (self.owner.Cujo_auto && self.enemy != world && self.enemy.health > 1
- && !(self.enemy.items & IT_INVISIBILITY) && visible(self.enemy))
- {
- }
- else
- {
- }
-
- self = oldself;
-
- return;
- };
- */
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_TeleportHome ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- void () CUJO_TeleportHome =
- {
- local vector org;
-
- if (!(self.Cujo_flag))
- {
- CUJO_PrintCujoStatus ();
-
- return;
- }
- if (self.Cujo_flag)
- if (self.Cujo.deadflag == DEAD_DYING) return;
-
- spawn_tfog (self.Cujo.origin);
- self.Cujo.ideal_yaw = self.angles * '0 1 0';
- self.Cujo.pausetime = time + 2;
- self.Cujo.nextthink = time + nextthinktime;
- self.Cujo.think = self.Cujo.th_stand;
-
- org = self.origin + '0 0 0';
- setorigin(self.Cujo, org);
-
- spawn_tfog (self.Cujo.origin);
- self.Cujo.nextthink = time + nextthinktime;
- self.Cujo.think = self.Cujo.th_stand;
-
- return;
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_LightToggle ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
-
- // This will always be called from the players code, so self is always
- // expected to be the player
-
- void () CUJO_LightToggle =
- {
- local float effect;
- local float bitmask;
-
- if (self.Cujo_flag)
- {
- effect = EF_DIMLIGHT;
-
- bitmask = (effect) & self.Cujo.effects;
-
- if (bitmask == 0)
- {
- self.Cujo.effects = self.Cujo.effects | effect;
- }
- else
- {
- bitmask = !(bitmask);
- self.Cujo.effects = (self.Cujo.effects) & bitmask;
- }
- }
- else
- CUJO_PrintCujoStatus ();
-
- return;
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_SetDogView ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- // This will always be called from the players code, so self is always
- // expected to be the player
-
- void () CUJO_SetDogView =
- {
- if (self.Cujo_flag)
- {
- // Set view point
- msg_entity = self;
- WriteByte (MSG_ONE, 5); // SVC, set the viewport
- WriteEntity (MSG_ONE, self.Cujo);
-
- // set the view angles to Cujo's view angles
- // WriteByte (MSG_ONE, 10); // SVC, set view angles
- // WriteAngle(MSG_ONE, self.Cujo.angles_x);
- // WriteAngle(MSG_ONE, self.Cujo.angles_y);
- // WriteAngle(MSG_ONE, self.Cujo.angles_z);
-
- self.weaponmodel = "";
- self.weaponframe = 0;
-
- self.Cujo_view = TRUE;
-
- old_player_angles = self.angles;
-
- // turn to Cujo's angles... I guess
- self.angles = self.Cujo.angles;
- self.fixangle = TRUE; // turn this way immediately
-
- }
- else
- CUJO_PrintCujoStatus ();
-
- return;
-
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_SetPlayerView ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
-
- // This will always be called from the players code, so self is always
- // expected to be the player
-
- void () CUJO_SetPlayerView =
- {
- if (self.Cujo_flag)
- {
- // Set view point
- msg_entity = self;
- WriteByte (MSG_ONE, 5); // service, set the viewport
- WriteEntity (MSG_ONE, self);
-
- // WriteByte (MSG_ONE, 10); // SVC, set view angles
- // WriteAngle(MSG_ONE, self.angles_x); // tilt
- // WriteAngle(MSG_ONE, self.angles_y); // yaw
- // WriteAngle(MSG_ONE, self.angles_z); // flip
-
- // reset the players weapon model
- self.Cujo_view = FALSE;
- W_SetCurrentAmmo ();
-
- self.angles = old_player_angles;
- self.fixangle = TRUE; // turn this way immediately
- }
- else
- CUJO_PrintCujoStatus ();
-
- return;
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_Stay ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- // always called from player code. Toggles self.Cujo.Cujo_stay which
- // is used in follow routines to determine if Cujo should stay or follow
-
- void () CUJO_Stay =
- {
- if (self.Cujo_flag)
- {
- // toggle Cujo's stay flag
- if (self.Cujo.Cujo_stay == TRUE)
- {
- self.Cujo.Cujo_stay = FALSE;
- sprint (self, "Cujo is following.\n");
- }
- else
- {
- self.Cujo.Cujo_stay = TRUE;
- sprint (self, "Cujo is staying.\n");
- }
-
- }
- else
- CUJO_PrintCujoStatus ();
-
- return;
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_GiveStatus ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- // called from player code, ie. self = player
-
- void () CUJO_GiveStatus =
- {
- local string str_temp;
- local float ftemp;
-
- if (self.Cujo_flag)
- {
- if (visible (self.Cujo))
- {
- sprint (self, "Cujo's health is ");
-
- if (!deathmatch)
- ftemp = self.Cujo.health / 2;
- else
- ftemp = self.Cujo.health;
-
- str_temp = ftos (ftemp);
- sprint (self, str_temp);
- sprint (self, "%.\n");
-
- sprint (self, "His armor is ");
-
- if (!deathmatch)
- ftemp = self.Cujo.armorvalue / 2;
- else
- ftemp = self.Cujo.armorvalue / 1.5;
-
- str_temp = ftos (ftemp);
- sprint (self, str_temp);
- sprint (self, "%.\n");
- }
- else
- {
- sprint (self, "You must be able to see Cujo to determine his status.\n");
- }
- }
- else
- CUJO_PrintCujoStatus ();
-
- return;
- };
-
- /*╔═══════════════════════════════════════════════════════════════════════╗
- ║ ║
- ║ Cujo_KillAllMonsters ║
- ║ ║
- ╚═══════════════════════════════════════════════════════════════════════╝*/
-
- // to make debugging maps easier -- no having to fight stuff
-
- void () CUJO_KillAllMonsters =
- {
- local entity head;
-
- head = nextent (world);
-
- while (head)
- {
- if ((head.classname == "monster_army")
- || (head.classname == "monster_demon1")
- || (head.classname == "monster_dog")
- || (head.classname == "monster_dragon")
- || (head.classname == "monster_enforcer")
- || (head.classname == "monster_fish")
- || (head.classname == "monster_hell_knight")
- || (head.classname == "monster_knight")
- || (head.classname == "monster_ogre")
- || (head.classname == "monster_oldone")
- || (head.classname == "monster_shalrath")
- || (head.classname == "monster_shambler")
- || (head.classname == "monster_tarbaby")
- || (head.classname == "monster_vomit")
- || (head.classname == "monster_wizard"))
- {
- if (random () < 0.2)
- T_Damage (head, self, self, head.health + 100);
- else
- T_Damage (head, self, self, head.health + 1);
- bprint ("kill ");
- }
- else if (head.classname == "monster_zombie")
- T_Damage (head, self, self, head.health + 50);
-
- head = nextent (head);
- }
- bprint ("Everything is dead.\n");
- };
-