mirror of
https://git.code.sf.net/p/quake/prozac-qfcc
synced 2024-11-24 13:11:43 +00:00
2072 lines
61 KiB
C++
2072 lines
61 KiB
C++
#include "defs.qh"
|
||
#include "ai.qh"
|
||
#include "monsters.qh"
|
||
/* ------------------------------------------------------------------------------------
|
||
** ------------------------------------GRUNTY(tm)--------------------------------------
|
||
** -- Your artificially intelligent mercenary from beyond the Void --
|
||
** -- Use with caution -
|
||
** -- Do not expose to excessive amounts of radiation -
|
||
** -- Share and Enjoy! --
|
||
** --- Copyright(c)2000 By Dwarven Star Interactive Industrial Industry Enterprises ---
|
||
** ----------------------------------------------------------------------------------*/
|
||
// OfN - Who the fuck coded this? it's cool!
|
||
// waypoint triggers were screwed in the version I started from though (chris6)
|
||
// lot of things changed, was VERY buggy. It made prozac server to crash like 5 times
|
||
|
||
/* ALREADY DEFINED IN MONSTERS.QC
|
||
|
||
#define WAYPOINT_TYPE_PRIMARY 0
|
||
#define WAYPOINT_TYPE_SECONDARY 1
|
||
#define WAYPOINT_TYPE_ENEMYLASTSEEN 2
|
||
|
||
*/
|
||
|
||
// Function Prototypes
|
||
// Whenever a function is added within the grunty, add it up here
|
||
|
||
void(entity wyp, entity soldier) RemoveWaypoint;
|
||
|
||
void () GruntyThink;
|
||
void () GRun;
|
||
void () GruntyScanTargets;
|
||
void () GruntyCheckFire;
|
||
void (entity targ) GetRank;
|
||
void () Grunty_Check_Frags;
|
||
void (float angle, float dist) botmovedist;
|
||
float () ReturnWeaponVelocity;
|
||
void () GruntyPayThink;
|
||
void () GruntyDrawPay;
|
||
|
||
|
||
// External Functions
|
||
// List all external functions used here
|
||
float () isMelee;
|
||
//entity (entity scanner) LookAround;
|
||
|
||
//=- OfN -=//
|
||
void(entity sld, entity player, string msg) PrintFromSoldier;
|
||
string(entity sld) GetOwnerMessage;
|
||
string(entity sld) GetFriendlyMessage;
|
||
entity (entity sold, entity viewpoint) ReturnEasyWaypoint;
|
||
string(entity thething) GetEnemyName;
|
||
void () CheckWaterJump;
|
||
|
||
|
||
// The Frames of Grunty
|
||
|
||
$cd /raid/quake/id1/models/player_4
|
||
$origin 0 -6 24
|
||
$base base
|
||
$skin skin
|
||
|
||
// Frames, from player.qc
|
||
|
||
//
|
||
// running
|
||
//
|
||
$frame axrun1 axrun2 axrun3 axrun4 axrun5 axrun6
|
||
|
||
$frame rockrun1 rockrun2 rockrun3 rockrun4 rockrun5 rockrun6
|
||
|
||
//
|
||
// standing
|
||
//
|
||
$frame stand1 stand2 stand3 stand4 stand5
|
||
|
||
$frame axstnd1 axstnd2 axstnd3 axstnd4 axstnd5 axstnd6
|
||
$frame axstnd7 axstnd8 axstnd9 axstnd10 axstnd11 axstnd12
|
||
|
||
|
||
//
|
||
// pain
|
||
//
|
||
$frame axpain1 axpain2 axpain3 axpain4 axpain5 axpain6
|
||
|
||
$frame pain1 pain2 pain3 pain4 pain5 pain6
|
||
|
||
|
||
//
|
||
// death
|
||
//
|
||
|
||
$frame axdeth1 axdeth2 axdeth3 axdeth4 axdeth5 axdeth6
|
||
$frame axdeth7 axdeth8 axdeth9
|
||
|
||
$frame deatha1 deatha2 deatha3 deatha4 deatha5 deatha6 deatha7 deatha8
|
||
$frame deatha9 deatha10 deatha11
|
||
|
||
$frame deathb1 deathb2 deathb3 deathb4 deathb5 deathb6 deathb7 deathb8
|
||
$frame deathb9
|
||
|
||
$frame deathc1 deathc2 deathc3 deathc4 deathc5 deathc6 deathc7 deathc8
|
||
$frame deathc9 deathc10 deathc11 deathc12 deathc13 deathc14 deathc15
|
||
|
||
$frame deathd1 deathd2 deathd3 deathd4 deathd5 deathd6 deathd7
|
||
$frame deathd8 deathd9
|
||
|
||
$frame deathe1 deathe2 deathe3 deathe4 deathe5 deathe6 deathe7
|
||
$frame deathe8 deathe9
|
||
|
||
//
|
||
// attacks
|
||
//
|
||
$frame nailatt1 nailatt2
|
||
|
||
$frame light1 light2
|
||
|
||
$frame rockatt1 rockatt2 rockatt3 rockatt4 rockatt5 rockatt6
|
||
|
||
$frame shotatt1 shotatt2 shotatt3 shotatt4 shotatt5 shotatt6
|
||
|
||
$frame axatt1 axatt2 axatt3 axatt4 axatt5 axatt6
|
||
|
||
$frame axattb1 axattb2 axattb3 axattb4 axattb5 axattb6
|
||
|
||
$frame axattc1 axattc2 axattc3 axattc4 axattc5 axattc6
|
||
|
||
$frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6
|
||
|
||
/* ---------------------------------------------------------------------------------- */
|
||
// The Fun Bit
|
||
|
||
/* ---------------------------------------------------------------------------------- */
|
||
// GRUNTY - PART ONE
|
||
// Standing Around
|
||
//
|
||
// Grunty is standing around having a good time
|
||
/* ---------------------------------------------------------------------------------- */
|
||
|
||
// Grunty is standing with his axe or other melee weapon
|
||
// Note that he must do a GruntyThink each frame
|
||
// (each frame is 0.05 seconds)
|
||
// However, he may only animate every 0.1 seconds, hence the flooring and odd incrementing
|
||
// of his frame variable. (0.05 animation is very smooth and twice as fast as normal)
|
||
|
||
void() grunty_run;
|
||
|
||
void() grunty_stand = // We need two stand sections for axe and weapon
|
||
{
|
||
//self.nextthink = time + 0.05; needed?? nope
|
||
if (self.health > 0) self.think = grunty_stand;
|
||
|
||
self.weaponframe = 0;
|
||
|
||
if (isMelee())
|
||
{
|
||
if (self.walkframe >= 12)
|
||
self.walkframe = 0;
|
||
self.frame = $axstnd1 + floor(self.walkframe);
|
||
}
|
||
else
|
||
{
|
||
if (self.walkframe >= 5)
|
||
self.walkframe = 0;
|
||
self.frame = $stand1 + floor(self.walkframe);
|
||
}
|
||
self.walkframe = self.walkframe + 0.5;
|
||
|
||
#ifdef VERBOSE_GRUNTY
|
||
if (self.super_time <= time)
|
||
{
|
||
sprint(self.real_owner, PRINT_HIGH, "Soldier in position and awaiting target.\n");
|
||
self.super_time = time + 5;
|
||
}
|
||
#endif
|
||
|
||
Grunty_Check_Frags();
|
||
|
||
if (self.goalentity != world)
|
||
{
|
||
self.walkframe = 0;
|
||
self.think = grunty_run;
|
||
//return;
|
||
}
|
||
|
||
GruntyThink();
|
||
//sprint(self.real_owner, PRINT_HIGH, "Done gruntythink in stand().\n");
|
||
};
|
||
/* ---------------------------------------------------------------------------------- */
|
||
// GRUNTY - PART TWO
|
||
// Running Around
|
||
//
|
||
// Grunty is charging about the place
|
||
/* ---------------------------------------------------------------------------------- */
|
||
|
||
// Again we have a choice of which animation to use
|
||
void() grunty_run =
|
||
{
|
||
if (self.health > 0) self.think = grunty_run;
|
||
|
||
self.weaponframe = 0; //needed?
|
||
|
||
if (isMelee())
|
||
{
|
||
if (self.walkframe >= 6)
|
||
self.walkframe = 0;
|
||
self.frame = $axrun1 + floor(self.walkframe);
|
||
}
|
||
else
|
||
{
|
||
if (self.walkframe >= 6)
|
||
self.walkframe = 0;
|
||
self.frame = $rockrun1 + floor(self.walkframe);
|
||
}
|
||
|
||
self.walkframe = self.walkframe + 0.5;
|
||
|
||
#ifdef VERBOSE_GRUNTY
|
||
if (self.super_time <= time)
|
||
{
|
||
sprint(self.real_owner, PRINT_HIGH, "Hello, commander! I am currently running at speed ");
|
||
st = ftos(self.custom_speed);
|
||
sprint(self.real_owner, PRINT_HIGH, st);
|
||
sprint(self.real_owner, PRINT_HIGH, " towards ");
|
||
sprint(self.real_owner, PRINT_HIGH, self.goalentity.netname);
|
||
sprint(self.real_owner, PRINT_HIGH, "\n");
|
||
self.super_time = time + 5;
|
||
}
|
||
#endif
|
||
|
||
if (self.goalentity == world)
|
||
{
|
||
self.walkframe = 0;
|
||
self.think = grunty_stand;
|
||
//return;
|
||
}
|
||
|
||
GruntyThink();
|
||
|
||
#ifdef VERBOSE_GRUNTY
|
||
sprint(self.real_owner, PRINT_HIGH, "I have just finished GruntyThink (self.enemy = ");
|
||
sprint(self.real_owner, PRINT_HIGH, self.enemy);
|
||
sprint(self.real_owner, PRINT_HIGH, ")\n");
|
||
#endif
|
||
|
||
GRun();
|
||
|
||
#ifdef VERBOSE_GRUNTY
|
||
sprint(self.real_owner, PRINT_HIGH, "I have just finished GRun (self.enemy = ");
|
||
sprint(self.real_owner, PRINT_HIGH, self.enemy);
|
||
sprint(self.real_owner, PRINT_HIGH, ")\n");
|
||
#endif
|
||
|
||
Grunty_Check_Frags();
|
||
};
|
||
|
||
void() stand_frames = //- ofn - used when soldier is following us, and when hes stuck and set to not jump
|
||
{
|
||
self.weaponframe=0;
|
||
|
||
if (isMelee())
|
||
{
|
||
if (self.walkframe >= 12)
|
||
self.walkframe = 0;
|
||
self.frame = $axstnd1 + floor(self.walkframe);
|
||
}
|
||
else
|
||
{
|
||
if (self.walkframe >= 5)
|
||
self.walkframe = 0;
|
||
self.frame = $stand1 + floor(self.walkframe);
|
||
}
|
||
self.walkframe = self.walkframe + 0.1;
|
||
};
|
||
|
||
/* ---------------------------------------------------------------------------------- */
|
||
// GRUNTY - PART THREE
|
||
// Axing People
|
||
//
|
||
// Grunty goes psycho
|
||
/* ---------------------------------------------------------------------------------- */
|
||
|
||
// Grunty's first axe attack
|
||
void() grunty_axeatta =
|
||
{
|
||
self.frame = $axatt1 + floor(self.weaponframe);
|
||
|
||
if (self.weaponframe == 1)
|
||
if (self.current_weapon == WEAP_AXE)
|
||
W_FireAxe();
|
||
else
|
||
W_FireSpanner();
|
||
|
||
self.weaponframe = self.weaponframe + 0.5;
|
||
GruntyThink();
|
||
GRun();
|
||
///self.nextthink = time + 0.05;
|
||
if (self.weaponframe > 3)
|
||
if (self.health > 0) self.think = grunty_run;
|
||
};
|
||
|
||
// Grunty's second axe attack
|
||
void() grunty_axeattb =
|
||
{
|
||
self.frame = $axattb1 + floor(self.weaponframe);
|
||
|
||
if (self.weaponframe == 2)
|
||
if (self.current_weapon == WEAP_AXE)
|
||
W_FireAxe();
|
||
else
|
||
W_FireSpanner();
|
||
|
||
self.weaponframe = self.weaponframe + 0.5;
|
||
GruntyThink();
|
||
GRun();
|
||
///self.nextthink = time + 0.05;
|
||
if (self.weaponframe > 3)
|
||
if (self.health > 0) self.think = grunty_run;
|
||
};
|
||
|
||
// Grunty's third axe attack
|
||
void() grunty_axeattc =
|
||
{
|
||
self.frame = $axattc1 + floor(self.weaponframe);
|
||
|
||
if (self.weaponframe == 2)
|
||
if (self.current_weapon == WEAP_AXE)
|
||
W_FireAxe();
|
||
else
|
||
W_FireSpanner();
|
||
|
||
self.weaponframe = self.weaponframe + 0.5;
|
||
GruntyThink();
|
||
GRun();
|
||
///self.nextthink = time + 0.05;
|
||
if (self.weaponframe > 3)
|
||
if (self.health > 0) self.think = grunty_run;
|
||
};
|
||
|
||
// Grunty's fourth axe attack
|
||
void() grunty_axeattd =
|
||
{
|
||
self.frame = $axattd1 + floor(self.weaponframe);
|
||
|
||
if (self.weaponframe == 2)
|
||
if (self.current_weapon == WEAP_AXE)
|
||
W_FireAxe();
|
||
else
|
||
W_FireSpanner();
|
||
|
||
self.weaponframe = self.weaponframe + 0.5;
|
||
GruntyThink();
|
||
GRun();
|
||
///self.nextthink = time + 0.05;
|
||
if (self.weaponframe > 3)
|
||
if (self.health > 0) self.think = grunty_run;
|
||
};
|
||
|
||
// Axe attack chooser
|
||
void() grunty_axeatt =
|
||
{
|
||
local float r;
|
||
|
||
self.walkframe = 0; // Reset walkframe to avoid freaky animations?
|
||
|
||
r = random();
|
||
|
||
if (r < 0.25)
|
||
grunty_axeatta();
|
||
else if (r < 0.5)
|
||
grunty_axeattb();
|
||
else if (r < 0.75)
|
||
grunty_axeattc();
|
||
else
|
||
grunty_axeattd();
|
||
};
|
||
|
||
/* ---------------------------------------------------------------------------------- */
|
||
// GRUNTY - PART FOUR
|
||
// Shooting Time
|
||
//
|
||
// Grunty goes postal
|
||
/* ---------------------------------------------------------------------------------- */
|
||
|
||
// Grunty uses the shotgun
|
||
// The firing is done after he chooses the attack
|
||
void() grunty_shotgun =
|
||
{
|
||
self.frame = $shotatt1 + floor(self.weaponframe);
|
||
|
||
if (self.weaponframe == 0)
|
||
self.effects = self.effects | EF_DIMLIGHT;
|
||
else if (self.weaponframe == 0.5)
|
||
self.effects = self.effects - (self.effects & EF_DIMLIGHT);
|
||
|
||
self.weaponframe = self.weaponframe + 0.5;
|
||
GruntyThink();
|
||
GRun();
|
||
///self.nextthink = time + 0.05;
|
||
if (self.weaponframe > 5)
|
||
{
|
||
self.walkframe = 0;
|
||
if (self.ammo_shells < 1)
|
||
PrintFromSoldier(self,self.real_owner,"i've run out of shells!\n");
|
||
if (self.health > 0) self.think = grunty_run;
|
||
}
|
||
};
|
||
|
||
// Grunty fires his rocket launcher! muahahahahaha
|
||
// The firing is done after he chooses the attack
|
||
void() grunty_rocket =
|
||
{
|
||
self.frame = $rockatt1 + floor(self.weaponframe);
|
||
|
||
if (self.weaponframe == 0)
|
||
self.effects = self.effects | EF_DIMLIGHT;
|
||
else if (self.weaponframe == 0.5)
|
||
self.effects = self.effects - (self.effects & EF_DIMLIGHT);
|
||
|
||
self.weaponframe = self.weaponframe + 0.5;
|
||
GruntyThink();
|
||
GRun();
|
||
///self.nextthink = time + 0.05;
|
||
if (self.weaponframe > 5)
|
||
{
|
||
self.walkframe = 0;
|
||
if (self.ammo_rockets < 1)
|
||
PrintFromSoldier(self,self.real_owner,"i've run out of rockets!\n");
|
||
if (self.health > 0) self.think = grunty_run;
|
||
}
|
||
};
|
||
|
||
//- ofn - this to compensate no prediction
|
||
//- GRUNTY'S NAILS GO FASTER AS HIS RANK IS INCREASED (upto 2200)-//
|
||
void(vector org, vector dir) grunty_spike =
|
||
{
|
||
newmis = spawn ();
|
||
newmis.owner = self;
|
||
newmis.movetype = MOVETYPE_FLYMISSILE;
|
||
newmis.solid = SOLID_BBOX;
|
||
|
||
newmis.angles = vectoangles(dir);
|
||
|
||
newmis.touch = spike_touch;
|
||
newmis.weapon = DMSG_NAILGUN;
|
||
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*(1100+1100*(self.has_sensor/17));
|
||
};
|
||
|
||
// Grunty uses the nailgun
|
||
void() grunty_nail1 = [$nailatt1, grunty_nail2]
|
||
{
|
||
GruntyThink(); GRun(); self.effects = self.effects | EF_DIMLIGHT;
|
||
if (self.ammo_nails > 0)
|
||
{
|
||
W_FireSpikes(4);
|
||
if (self.ammo_nails < 1) PrintFromSoldier(self,self.real_owner,"i've run out of nails!\n");
|
||
}
|
||
};
|
||
void() grunty_nail2 = [$nailatt1, grunty_nail3]
|
||
{
|
||
GruntyThink(); GRun(); self.effects = self.effects | EF_DIMLIGHT;
|
||
};
|
||
void() grunty_nail3 = [$nailatt2, grunty_nail4]
|
||
{
|
||
GruntyThink(); GRun(); self.effects = self.effects - (self.effects & EF_DIMLIGHT);
|
||
if (self.ammo_nails > 0)
|
||
{
|
||
W_FireSpikes(-4);
|
||
if (self.ammo_nails < 1) PrintFromSoldier(self,self.real_owner,"i've run out of nails!\n");
|
||
}
|
||
};
|
||
void() grunty_nail4 = [$nailatt2, grunty_nail1]
|
||
{
|
||
GruntyThink(); GRun(); self.effects = self.effects - (self.effects & EF_DIMLIGHT);
|
||
|
||
local float vis, dist;
|
||
|
||
vis = visible(self.enemy);
|
||
dist = vlen(self.origin - self.enemy.origin);
|
||
|
||
if (!vis || self.ammo_nails < 1 || self.enemy.health <= 0 || dist < 200 || random() < 0.025)
|
||
{
|
||
self.walkframe = 0;
|
||
grunty_run();
|
||
return;
|
||
}
|
||
};
|
||
|
||
vector () Grunty_LeadShot =
|
||
{
|
||
local vector pvel, dir, loc;
|
||
local vector src, targ;
|
||
|
||
src = self.origin + '0 0 16';
|
||
targ = self.enemy.origin;
|
||
|
||
|
||
pvel = '0 0 0'; // ofn - no prediction
|
||
|
||
/*if (self.enemy.classname == "player")
|
||
pvel='0 0 0';//pvel = self.enemy.velocity;
|
||
else if (self.enemy.classname == "monster_army")
|
||
{
|
||
makevectors(self.enemy.angles);
|
||
pvel = self.enemy.velocity + v_forward * self.enemy.custom_speed * 20;// * 10; //- ? was 20
|
||
}
|
||
else
|
||
pvel = '0 0 0';*/
|
||
|
||
//if (!self.enemy.flags & FL_ONGROUND)
|
||
// pvel_z = pvel_z / 20;
|
||
|
||
//lead = pvel * (vlen(src - targ) / ReturnWeaponVelocity());
|
||
loc = targ;// + lead;
|
||
|
||
// do the following do anything?-----//
|
||
//lead = pvel * (vlen(src - loc) / ReturnWeaponVelocity());
|
||
//lead_x = lead_x + (10 - random() * 20);
|
||
//lead_y = lead_y + (10 - random() * 20);
|
||
//------------------------------------// self.view_ofs
|
||
|
||
dir = normalize (loc - src);
|
||
|
||
traceline(src, targ, TRUE, self);
|
||
if (trace_fraction != 1.0)
|
||
{
|
||
loc_z = loc_z + self.enemy.maxs_z; // already commented
|
||
//if (self.current_weapon == WEAP_ROCKET_LAUNCHER)
|
||
// loc_z = loc_z + self.enemy.mins_z * -1;
|
||
}
|
||
else
|
||
{
|
||
if (self.current_weapon == WEAP_ROCKET_LAUNCHER && random() > 0.3)
|
||
loc_z = loc_z - self.enemy.maxs_z/2;
|
||
//- OFN - makes grunty aim to the ground with RL sometimes, so evil! ^_^
|
||
}
|
||
|
||
dir = normalize (loc - src);
|
||
|
||
return dir;
|
||
};
|
||
|
||
/* ---------------------------------------------------------------------------------- */
|
||
// GRUNTY - PART FIVE
|
||
// Thinking Skills
|
||
//
|
||
// Grunty reflects on what he has done
|
||
/* ---------------------------------------------------------------------------------- */
|
||
|
||
void() GruntyThink =
|
||
{
|
||
AI_Check_Contents(self);
|
||
|
||
if (self.health <= 0) return;
|
||
|
||
self.nextthink = time + 0.05; //was 0.05
|
||
|
||
// check for Follow Me Grunty's owner death
|
||
if (self.goalentity == self.real_owner)
|
||
if (self.goalentity.health <= 0)
|
||
self.goalentity = world;
|
||
|
||
|
||
// Check to buy
|
||
if (self.suicide_time <= time)
|
||
GruntyPayThink();
|
||
// scan for targets
|
||
|
||
GruntyScanTargets();
|
||
|
||
};
|
||
|
||
// LookAround for grunty
|
||
entity (entity scanner) LookAroundGrunty =
|
||
{
|
||
if (infokey(world,"ceasefire")=="on") //OfN
|
||
return scanner;
|
||
|
||
local entity scanner;
|
||
local entity client;
|
||
local float gotatarget;
|
||
|
||
client = findradius(scanner.origin, 2500);
|
||
|
||
while (client)
|
||
{
|
||
gotatarget = 0;
|
||
|
||
if (client != scanner && visible2(client, scanner))
|
||
{
|
||
|
||
#ifdef MAD_MONSTERS
|
||
|
||
if (client.classname == "player" && IsMonsterNonArmy(scanner)) gotatarget = 1;
|
||
|
||
#else
|
||
|
||
if (client.classname == "player" && !Teammate(client.team_no, scanner.real_owner.team_no))
|
||
{
|
||
gotatarget = Pharse_Client(client, scanner, 1, 0, 0, 0);
|
||
|
||
if (client.is_undercover)
|
||
if ((client.cutf_items & CUTF_JAMMER) || !(scanner.tf_items & NIT_SCANNER))
|
||
gotatarget=0;
|
||
if (client.modelindex == modelindex_null)
|
||
if ((client.cutf_items & CUTF_JAMMER) || !(scanner.tf_items & NIT_SCANNER))
|
||
gotatarget=0;
|
||
if (client.modelindex == modelindex_eyes)
|
||
if ((client.cutf_items & CUTF_JAMMER) || !(scanner.tf_items & NIT_SCANNER))
|
||
if (random() < 2 - scanner.has_tesla * random())
|
||
gotatarget=0;
|
||
}
|
||
|
||
#endif
|
||
|
||
else if (IsMonster(client))
|
||
{
|
||
if (!Teammate(client.real_owner.team_no,scanner.real_owner.team_no))
|
||
gotatarget = 1;
|
||
}
|
||
else if (client.classname == "grenade" && client.netname == "land_mine")
|
||
{
|
||
if (!Teammate(client.owner.team_no,scanner.real_owner.team_no))
|
||
gotatarget = 1;
|
||
}
|
||
else if (!Teammate(client.team_no, scanner.real_owner.team_no))
|
||
{ // && client.classname != "building_sentrygun_base"
|
||
if (IsOffenseBuilding(client)) // for teslas isoffensiveb only returns true if not cloaked
|
||
gotatarget = 1;
|
||
}
|
||
|
||
}
|
||
if (gotatarget)
|
||
return client;
|
||
|
||
client = client.chain;
|
||
}
|
||
return scanner;
|
||
};
|
||
|
||
|
||
entity () GruntyPharse =
|
||
{
|
||
local entity retarg = world;
|
||
local float r;
|
||
r = random();
|
||
|
||
#ifdef MAD_GRUNTY
|
||
|
||
if (r < 0.30 && (visible(self.real_owner)) && self.real_owner.health > 0)
|
||
retarg = self.real_owner;
|
||
|
||
#else
|
||
|
||
//- ofn - lot of shit changed in lookaround to make them target well
|
||
if (r < 0.30)
|
||
retarg = LookAroundGrunty(self);
|
||
|
||
#endif
|
||
|
||
return retarg;
|
||
};
|
||
|
||
void() GruntyScanTargets =
|
||
{
|
||
local entity targ; // our hapless foe
|
||
targ = world;
|
||
|
||
if (self.enemy != world)
|
||
if (self.enemy.health <= 0 || self.enemy.has_disconnected)
|
||
{
|
||
|
||
self.enemy = world;
|
||
self.goalentity = ReturnEasyWaypoint(self,self);
|
||
|
||
//// self.enemy = world;
|
||
//// self.goalentity = world;
|
||
if (self.demon_one != world)
|
||
{
|
||
RemoveWaypoint(self.demon_one,self);
|
||
self.demon_one = world;
|
||
}
|
||
|
||
self.has_teleporter = 0;
|
||
self.effects = self.effects - (self.effects & EF_DIMLIGHT);
|
||
return;
|
||
}
|
||
// If we have a target already
|
||
if (self.enemy != world)
|
||
{
|
||
local float vis;
|
||
vis = visible(self.enemy);
|
||
if (vis)
|
||
{
|
||
if (self.demon_one != world)
|
||
{
|
||
RemoveWaypoint(self.demon_one,self);
|
||
self.demon_one=world;
|
||
|
||
} //often =world
|
||
self.search_time = time + 3;
|
||
if (self.attack_finished <= time)
|
||
GruntyCheckFire();
|
||
}
|
||
else
|
||
{
|
||
if (self.is_malfunctioning==0 || self.is_malfunctioning==2)
|
||
{
|
||
self.enemy = world;
|
||
self.goalentity = ReturnEasyWaypoint(self,self);
|
||
|
||
self.has_teleporter = 0;
|
||
self.effects = self.effects - (self.effects & EF_DIMLIGHT);
|
||
|
||
return;
|
||
}
|
||
// tactic
|
||
|
||
if (self.demon_one == world) // if we don't have a enemy last seen marker
|
||
{
|
||
if (self.demon_one!=world)
|
||
{
|
||
RemoveWaypoint(self.demon_one,self);
|
||
}
|
||
|
||
self.demon_one = CreateWaypoint(self.enemy.origin - self.enemy.velocity * 0.05, WAYPOINT_AI_LIFE, WAYPOINT_TYPE_ENEMYLASTSEEN);
|
||
self.demon_one.goalentity = ReturnEasyWaypoint(self,self.demon_one);
|
||
self.goalentity = self.demon_one;
|
||
self.search_time = time + GRUNTY_SEEKTIME; // was 8
|
||
//- OfN -
|
||
self.has_teleporter = 0;
|
||
}
|
||
if (self.search_time <= time) // we seeked enemy for GRUNTY_SEEKTIME already so...
|
||
{
|
||
self.enemy = world;
|
||
self.goalentity = world;
|
||
|
||
if (self.demon_one != world) // d1 remove contingency check
|
||
{
|
||
RemoveWaypoint(self.demon_one,self);
|
||
self.demon_one = world;
|
||
self.goalentity = ReturnEasyWaypoint(self,self);
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
else // otherwise look for a target
|
||
{
|
||
targ=GruntyPharse();
|
||
|
||
if (targ == self)
|
||
return;
|
||
if (targ == world)
|
||
return;
|
||
|
||
if (!self.is_detpacking || infokey(world,"ceasefire")=="on")
|
||
{
|
||
if (!IsBuilding(targ) && self.super_time < time && targ.netname != "land_mine")
|
||
{
|
||
PrintFromSoldier(self,self.real_owner,"i can see ");
|
||
sprint(self.real_owner, PRINT_HIGH, targ.netname);
|
||
sprint(self.real_owner, PRINT_HIGH, " around there...\n");
|
||
self.super_time = time + 4;
|
||
}
|
||
return;
|
||
}
|
||
|
||
if (self.super_time < time)
|
||
{
|
||
local string targetstr;
|
||
targetstr=GetEnemyName(targ);//targ.netname;
|
||
|
||
PrintFromSoldier(self,self.real_owner,"Target ");
|
||
|
||
sprint(self.real_owner, PRINT_HIGH, targ.netname);
|
||
sprint(self.real_owner, PRINT_HIGH, " spotted!\n Engaging target...\n");
|
||
self.super_time = time + 2.5;
|
||
}
|
||
|
||
self.enemy = targ;
|
||
self.goalentity = self.enemy;
|
||
self.search_time = time + 3;
|
||
}
|
||
};
|
||
|
||
void() GruntyCheckFire =
|
||
{
|
||
local float dist, vis;
|
||
|
||
if (self.attack_finished > time)
|
||
return;
|
||
|
||
if (self.enemy == world)
|
||
return;
|
||
|
||
if (infokey(world,"ceasefire")=="on")
|
||
{
|
||
self.goalentity=ReturnEasyWaypoint(self,self);
|
||
self.enemy=world;
|
||
return;
|
||
}
|
||
|
||
vis = visible(self.enemy);
|
||
if (!vis)
|
||
{
|
||
#ifdef VERBOSE_GRUNTY
|
||
//if (self.super_time <= time)
|
||
//{
|
||
sprint(self.real_owner, PRINT_HIGH, "Target not visible! Cancelling firing...\n");
|
||
self.super_time = time + 5;
|
||
//}
|
||
#endif
|
||
|
||
//self.weaponframe = 0;
|
||
//self.think = grunty_run;
|
||
//self.nextthink = time + 0.05;
|
||
return;
|
||
}
|
||
|
||
//-- OFN --// no need as yaw is set in GRun
|
||
//enemy_yaw = vectoyaw(self.enemy.origin - self.origin);
|
||
//self.ideal_yaw = enemy_yaw;
|
||
//ChangeYaw();
|
||
//---------//
|
||
|
||
/*if (!FacingIdeal())
|
||
return; */
|
||
|
||
dist = vlen(self.origin - self.enemy.origin);
|
||
self.weaponframe = 0;
|
||
|
||
|
||
if (dist < 64 && self.weapons_carried & WEAP_AXE && self.cutf_items & CUTF_KNIFE)
|
||
{
|
||
self.current_weapon = WEAP_AXE;
|
||
/*if (self.cutf_items & CUTF_KNIFE)
|
||
self.attack_finished = time + 0.5;
|
||
else
|
||
self.attack_finished = time + 0.5;*/
|
||
Attack_Finished(0.5);
|
||
if (self.health > 0) self.think = grunty_axeatt;
|
||
#ifdef VERBOSE_GRUNTY
|
||
sprint(self.real_owner, PRINT_HIGH, "Attempting to knife...\n");
|
||
#endif
|
||
return;
|
||
}
|
||
if (dist < 200 && self.weapons_carried & WEAP_SUPER_SHOTGUN)
|
||
{
|
||
if (self.ammo_shells > 1)
|
||
{
|
||
self.current_weapon = WEAP_SUPER_SHOTGUN;
|
||
//self.attack_finished = time + 0.7;
|
||
Attack_Finished(0.7);
|
||
W_FireSuperShotgun();
|
||
if (self.health > 0) self.think = grunty_shotgun;
|
||
#ifdef VERBOSE_GRUNTY
|
||
sprint(self.real_owner, PRINT_HIGH, "Attempting to super shotgun...\n");
|
||
#endif
|
||
return;
|
||
}
|
||
}
|
||
if (dist < 64 && self.weapons_carried & WEAP_AXE)
|
||
{
|
||
self.current_weapon = WEAP_AXE;
|
||
/*if (self.cutf_items & CUTF_KNIFE)
|
||
self.attack_finished = time + 0.5;
|
||
else
|
||
self.attack_finished = time + 0.5;*/
|
||
Attack_Finished(0.5);
|
||
if (self.health > 0) self.think = grunty_axeatt;
|
||
#ifdef VERBOSE_GRUNTY
|
||
sprint(self.real_owner, PRINT_HIGH, "Attempting to axe...\n");
|
||
#endif
|
||
return;
|
||
} //was 800
|
||
if (dist > 200 && dist < 1100 && self.weapons_carried & WEAP_ROCKET_LAUNCHER)
|
||
{
|
||
if (self.ammo_rockets > 1)
|
||
{
|
||
self.current_weapon = WEAP_ROCKET_LAUNCHER;
|
||
//self.attack_finished = time + 0.8;
|
||
Attack_Finished(0.8);
|
||
W_FireRocket();
|
||
if (self.health > 0) self.think = grunty_rocket;
|
||
#ifdef VERBOSE_GRUNTY
|
||
sprint(self.real_owner, PRINT_HIGH, "Attempting to rocket...\n");
|
||
#endif
|
||
return;
|
||
}
|
||
}
|
||
if (dist < 1400 && self.weapons_carried & WEAP_ROCKET_LAUNCHER && random() > 0.75)
|
||
{
|
||
if (self.ammo_rockets > 1)
|
||
{
|
||
self.current_weapon = WEAP_ROCKET_LAUNCHER;
|
||
//self.attack_finished = time + 0.8;
|
||
Attack_Finished(0.8);
|
||
W_FireRocket();
|
||
if (self.health > 0) self.think = grunty_rocket;
|
||
return;
|
||
}
|
||
}
|
||
if (dist < 2000 && self.weapons_carried & WEAP_ROCKET_LAUNCHER && self.ammo_rockets > 1 && random() > 0.98)
|
||
{
|
||
self.current_weapon = WEAP_ROCKET_LAUNCHER;
|
||
//self.attack_finished = time + 0.8;
|
||
Attack_Finished(0.8);
|
||
W_FireRocket();
|
||
if (self.health > 0) self.think = grunty_rocket;
|
||
return;
|
||
}
|
||
|
||
//- OfN
|
||
if (dist < 400 && self.weapons_carried & WEAP_SHOTGUN && self.ammo_shells > 0)
|
||
{
|
||
//if (self.ammo_shells > 0)
|
||
//{
|
||
self.current_weapon = WEAP_SHOTGUN;
|
||
//self.attack_finished = time + 0.5; // TODO: MAKE ATTACK FINISHED
|
||
Attack_Finished(0.5);
|
||
W_FireShotgun();
|
||
if (self.health > 0) self.think = grunty_shotgun;
|
||
#ifdef VERBOSE_GRUNTY
|
||
sprint(self.real_owner, PRINT_HIGH, "Attempting to shotgun...\n");
|
||
#endif
|
||
// RPrint("SHOTGUN\n");
|
||
return;
|
||
//}
|
||
}
|
||
if (dist < 2000 && self.weapons_carried & WEAP_NAILGUN && self.ammo_nails > 0)
|
||
{
|
||
//if (self.ammo_nails > 0)
|
||
//{
|
||
self.current_weapon = WEAP_NAILGUN;
|
||
//self.attack_finished = time + 0.2;//+ 0.1;
|
||
Attack_Finished(0.2);
|
||
if (self.health > 0) self.think = grunty_nail1;
|
||
#ifdef VERBOSE_GRUNTY
|
||
sprint(self.real_owner, PRINT_HIGH, "Attempting to nail...\n");
|
||
#endif
|
||
// RPrint("NAIL\n");
|
||
return;
|
||
//}
|
||
}
|
||
else
|
||
{
|
||
// Do whatever you want
|
||
self.effects = self.effects - (self.effects & EF_DIMLIGHT);
|
||
//self.walkframe = 0; ofn
|
||
if (self.health > 0) self.think = grunty_run;
|
||
#ifdef VERBOSE_GRUNTY
|
||
sprint(self.real_owner, PRINT_HIGH, "GruntyCheckFire defaulting to none...\n");
|
||
#endif
|
||
// RPrint("NONE\n");
|
||
}
|
||
};
|
||
|
||
void() GRun =
|
||
{
|
||
local float dist;
|
||
local vector loc;
|
||
|
||
// ok, we're trying to get somewhere
|
||
// first look at where we are trying to go
|
||
// Version 1.0 of GruntyLead(tm)
|
||
if (self.enemy != world)
|
||
{
|
||
local vector pvel;
|
||
|
||
if (self.enemy.classname == "player")
|
||
pvel = self.enemy.velocity;
|
||
else if (self.enemy.classname == "monster_army")
|
||
{
|
||
makevectors(self.enemy.angles);
|
||
pvel = self.enemy.velocity + v_forward * self.enemy.custom_speed * 20;
|
||
}
|
||
else
|
||
pvel = '0 0 0';
|
||
if (ReturnWeaponVelocity() == 99999999)
|
||
pvel = '0 0 0';
|
||
loc = self.enemy.origin + pvel * (vlen(self.enemy.origin - self.origin) / ReturnWeaponVelocity());
|
||
self.ideal_yaw = vectoyaw(loc - self.origin);
|
||
self.ideal_yaw = anglemod(self.ideal_yaw);
|
||
}
|
||
else
|
||
{
|
||
if (self.goalentity!=world) //- OfN - dont change yaw if we r not after a goal
|
||
{
|
||
self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin);
|
||
self.ideal_yaw = anglemod(self.ideal_yaw);
|
||
}
|
||
}
|
||
|
||
ChangeYaw();
|
||
|
||
// makevectors sets the global vars v_forward, v_right and v_up
|
||
makevectors(self.angles);
|
||
|
||
dist = self.custom_speed;
|
||
|
||
if (self.tfstate & TFSTATE_TRANQUILISED)
|
||
dist = dist * (AI_TRANQ_FACTOR_UP / AI_TRANQ_FACTOR_DN); //Tranq
|
||
|
||
/* - OfN -if (self.enemy.classname == "monster_shambler" || self.enemy.weapons_carried & WEAP_ASSAULT_CANNON)
|
||
if (self.has_teleporter == 0)
|
||
self.has_teleporter = 3;*/
|
||
|
||
if (random() < 0.02) // to prevent us from strafing or whatever forever.
|
||
self.has_teleporter = 0;
|
||
|
||
// Test to see if we want to do an evasive maneuver
|
||
// If we're already doing a move, don't do another
|
||
if (self.has_teleporter == -1) // left dodge move
|
||
botmovedist(vectoyaw(v_right * -1), dist);// move left
|
||
|
||
else if (self.has_teleporter == 1) // right dodge move
|
||
botmovedist(vectoyaw(v_right), dist); // move right
|
||
|
||
else if (self.has_teleporter == 2) // jump!
|
||
{
|
||
if (self.flags & FL_ONGROUND) // only jump if we're on the ground
|
||
{
|
||
self.velocity_z = self.velocity_z + 270; // boing
|
||
sound (self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM);
|
||
}
|
||
self.has_teleporter = 0; // don't jump
|
||
}
|
||
else if (self.has_teleporter == 3) //(backwards)// HE'S AFTER US, RUN!@#$ HE WILL KILL US ALL!!@
|
||
botmovedist(vectoyaw(v_forward), dist * -1); // flee, I tell you!
|
||
|
||
else if (self.has_teleporter == 0) // no evasive, standard move (forward)
|
||
{
|
||
//- OfN - force move to forward if we r going to a last seen enemy waypoint
|
||
if (self.goalentity == self.demon_one && self.demon_one!=world)
|
||
{
|
||
self.has_teleporter = 0;
|
||
botmovedist(vectoyaw(v_forward), dist); // move
|
||
return;
|
||
}
|
||
|
||
botmovedist(vectoyaw(v_forward), dist); // move
|
||
if (random() * 20 < 1 && self.enemy != world) // if we get a score
|
||
{ // of one on a d20,
|
||
local float r; // special
|
||
r = random();
|
||
if (r < 0.25)
|
||
self.has_teleporter = -1; // left
|
||
else if (r < 0.5)
|
||
self.has_teleporter = 1; // right
|
||
else if (r < 0.75)
|
||
self.has_teleporter = 2; // jump!
|
||
else
|
||
self.has_teleporter = 3; // italian style!
|
||
}
|
||
}
|
||
};
|
||
|
||
void (float angle, float dist) botmovedist =
|
||
{
|
||
|
||
local float success;
|
||
|
||
//- OfN - Don't annoy owner if following him! heh
|
||
#ifndef MAD_GRUNTY
|
||
if (self.goalentity==self.real_owner) //if in "follow me!" state...
|
||
{
|
||
local float dist2;
|
||
|
||
dist2 = vlen(self.origin - self.real_owner.origin);
|
||
|
||
if (dist2<64)
|
||
{
|
||
stand_frames();
|
||
self.has_cheated = time + 0.5;
|
||
walkmove(angle, 0);
|
||
return;
|
||
}
|
||
}///////////////////////////////*/
|
||
#endif
|
||
|
||
/*if (pointcontents(self.origin) == CONTENT_EMPTY) // We're in open air
|
||
{*/
|
||
|
||
success = walkmove(angle, dist);
|
||
|
||
if (success) // We walked sucessfully, woohoo
|
||
{
|
||
self.has_cheated = time + 0.5;
|
||
return;
|
||
}
|
||
else // We just ran into something...
|
||
{
|
||
if (self.is_toffingadet==1) //if we r on stop on obstacles mode
|
||
{
|
||
self.has_cheated = time + 0.5;
|
||
if (self.attack_finished < time) stand_frames();
|
||
return;
|
||
}
|
||
|
||
if (self.has_cheated > time)
|
||
return;
|
||
self.has_teleporter = 0; // abort dodging
|
||
makevectors(self.angles);
|
||
// First, we'll see if jumping would be suitable
|
||
if (self.flags & FL_ONGROUND) // don't bother if we aren't on the ground
|
||
{
|
||
traceline(self.origin + '0 0 20', self.origin + '0 0 20' + v_forward * 10, FALSE, self);
|
||
if (trace_fraction == 1.0)
|
||
{
|
||
self.velocity = self.velocity + v_forward * self.custom_speed * 20;
|
||
self.velocity_z = self.velocity_z + 270;
|
||
sound (self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM);
|
||
self.has_cheated = time + 0.5;
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
/*}
|
||
else
|
||
{
|
||
self.velocity = normalize(self.goalentity.origin - self.origin) * self.custom_speed * 20;
|
||
if (self.teleport_time < time)
|
||
CheckWaterJump();
|
||
}*/
|
||
|
||
};
|
||
|
||
void () Grunty_StateInv =
|
||
{
|
||
local string talk;
|
||
|
||
talk = ftos(self.health);
|
||
sprint(self.real_owner, PRINT_HIGH, "Your <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> has ");
|
||
sprint(self.real_owner, PRINT_HIGH, talk);
|
||
talk = ftos(self.max_health);
|
||
sprint(self.real_owner, PRINT_HIGH, "<EFBFBD>");
|
||
sprint(self.real_owner, PRINT_HIGH, talk);
|
||
sprint(self.real_owner, PRINT_HIGH, " <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
|
||
if (self.weapons_carried & WEAP_AXE)
|
||
if (self.cutf_items & CUTF_KNIFE)
|
||
sprint(self.real_owner, PRINT_HIGH, ", a combat knife");
|
||
else
|
||
sprint(self.real_owner, PRINT_HIGH, ", an axe");
|
||
if (self.weapons_carried & WEAP_SHOTGUN)
|
||
sprint(self.real_owner, PRINT_HIGH, ", a shotgun");
|
||
if (self.weapons_carried & WEAP_NAILGUN)
|
||
sprint(self.real_owner, PRINT_HIGH, ", a nailgun");
|
||
if (self.weapons_carried & WEAP_SUPER_SHOTGUN)
|
||
sprint(self.real_owner, PRINT_HIGH, ", a double barreled shotgun");
|
||
if (self.weapons_carried & WEAP_ROCKET_LAUNCHER)
|
||
sprint(self.real_owner, PRINT_HIGH, ", a rocket launcher");
|
||
if (self.tf_items & NIT_SCANNER)
|
||
sprint(self.real_owner, PRINT_HIGH, ", a scanner");
|
||
talk = ftos(self.custom_speed * 20);
|
||
sprint(self.real_owner, PRINT_HIGH, ", moves at speed ");
|
||
sprint(self.real_owner, PRINT_HIGH, talk);
|
||
talk = ftos(self.money);
|
||
sprint(self.real_owner, PRINT_HIGH, " with $");
|
||
sprint(self.real_owner, PRINT_HIGH, talk);
|
||
sprint(self.real_owner, PRINT_HIGH, "\n");
|
||
|
||
sprint(self.real_owner, PRINT_HIGH, "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>: ");
|
||
|
||
talk = ftos(self.ammo_shells);
|
||
sprint(self.real_owner, PRINT_HIGH, talk);
|
||
sprint(self.real_owner, PRINT_HIGH, " shells, ");
|
||
|
||
talk = ftos(self.ammo_nails);
|
||
sprint(self.real_owner, PRINT_HIGH, talk);
|
||
sprint(self.real_owner, PRINT_HIGH, " nails and ");
|
||
|
||
/* talk = ftos(self.ammo_cells);
|
||
sprint(self.real_owner, PRINT_HIGH, talk);
|
||
sprint(self.real_owner, PRINT_HIGH, " cells\n");*/
|
||
|
||
talk = ftos(self.ammo_rockets);
|
||
sprint(self.real_owner, PRINT_HIGH, talk);
|
||
sprint(self.real_owner, PRINT_HIGH, " rockets\n");
|
||
};
|
||
|
||
/* ---------------------------------------------------------------------------------- */
|
||
// GRUNTY - PART SIX
|
||
// Time to Die
|
||
//
|
||
// Grunty sucks it down
|
||
/* ---------------------------------------------------------------------------------- */
|
||
|
||
void () gruntyDead =
|
||
{
|
||
self.think = SUB_Remove;
|
||
self.nextthink = time + 40 + 20*random();
|
||
};
|
||
|
||
|
||
void() grunty_diea1 = [ $deatha1, grunty_diea2 ] {};
|
||
void() grunty_diea2 = [ $deatha2, grunty_diea3 ] {};
|
||
void() grunty_diea3 = [ $deatha3, grunty_diea4 ] {};
|
||
void() grunty_diea4 = [ $deatha4, grunty_diea5 ] {};
|
||
void() grunty_diea5 = [ $deatha5, grunty_diea6 ] {};
|
||
void() grunty_diea6 = [ $deatha6, grunty_diea7 ] {};
|
||
void() grunty_diea7 = [ $deatha7, grunty_diea8 ] {};
|
||
void() grunty_diea8 = [ $deatha8, grunty_diea9 ] {};
|
||
void() grunty_diea9 = [ $deatha9, grunty_diea10 ] {};
|
||
void() grunty_diea10 = [ $deatha10, grunty_diea11 ] {};
|
||
void() grunty_diea11 = [ $deatha11, grunty_diea11 ] {gruntyDead();};
|
||
|
||
void() grunty_dieb1 = [ $deathb1, grunty_dieb2 ] {};
|
||
void() grunty_dieb2 = [ $deathb2, grunty_dieb3 ] {};
|
||
void() grunty_dieb3 = [ $deathb3, grunty_dieb4 ] {};
|
||
void() grunty_dieb4 = [ $deathb4, grunty_dieb5 ] {};
|
||
void() grunty_dieb5 = [ $deathb5, grunty_dieb6 ] {};
|
||
void() grunty_dieb6 = [ $deathb6, grunty_dieb7 ] {};
|
||
void() grunty_dieb7 = [ $deathb7, grunty_dieb8 ] {};
|
||
void() grunty_dieb8 = [ $deathb8, grunty_dieb9 ] {};
|
||
void() grunty_dieb9 = [ $deathb9, grunty_dieb9 ] {gruntyDead();};
|
||
|
||
void() grunty_diec1 = [ $deathc1, grunty_diec2 ] {};
|
||
void() grunty_diec2 = [ $deathc2, grunty_diec3 ] {};
|
||
void() grunty_diec3 = [ $deathc3, grunty_diec4 ] {};
|
||
void() grunty_diec4 = [ $deathc4, grunty_diec5 ] {};
|
||
void() grunty_diec5 = [ $deathc5, grunty_diec6 ] {};
|
||
void() grunty_diec6 = [ $deathc6, grunty_diec7 ] {};
|
||
void() grunty_diec7 = [ $deathc7, grunty_diec8 ] {};
|
||
void() grunty_diec8 = [ $deathc8, grunty_diec9 ] {};
|
||
void() grunty_diec9 = [ $deathc9, grunty_diec10 ] {};
|
||
void() grunty_diec10 = [ $deathc10, grunty_diec11 ] {};
|
||
void() grunty_diec11 = [ $deathc11, grunty_diec12 ] {};
|
||
void() grunty_diec12 = [ $deathc12, grunty_diec13 ] {};
|
||
void() grunty_diec13 = [ $deathc13, grunty_diec14 ] {};
|
||
void() grunty_diec14 = [ $deathc14, grunty_diec15 ] {};
|
||
void() grunty_diec15 = [ $deathc15, grunty_diec15 ] {gruntyDead();};
|
||
|
||
void() grunty_died1 = [ $deathd1, grunty_died2 ] {};
|
||
void() grunty_died2 = [ $deathd2, grunty_died3 ] {};
|
||
void() grunty_died3 = [ $deathd3, grunty_died4 ] {};
|
||
void() grunty_died4 = [ $deathd4, grunty_died5 ] {};
|
||
void() grunty_died5 = [ $deathd5, grunty_died6 ] {};
|
||
void() grunty_died6 = [ $deathd6, grunty_died7 ] {};
|
||
void() grunty_died7 = [ $deathd7, grunty_died8 ] {};
|
||
void() grunty_died8 = [ $deathd8, grunty_died9 ] {};
|
||
void() grunty_died9 = [ $deathd9, grunty_died9 ] {gruntyDead();};
|
||
|
||
void() grunty_diee1 = [ $deathe1, grunty_diee2 ] {};
|
||
void() grunty_diee2 = [ $deathe2, grunty_diee3 ] {};
|
||
void() grunty_diee3 = [ $deathe3, grunty_diee4 ] {};
|
||
void() grunty_diee4 = [ $deathe4, grunty_diee5 ] {};
|
||
void() grunty_diee5 = [ $deathe5, grunty_diee6 ] {};
|
||
void() grunty_diee6 = [ $deathe6, grunty_diee7 ] {};
|
||
void() grunty_diee7 = [ $deathe7, grunty_diee8 ] {};
|
||
void() grunty_diee8 = [ $deathe8, grunty_diee9 ] {};
|
||
void() grunty_diee9 = [ $deathe9, grunty_diee9 ] {gruntyDead();};
|
||
|
||
void() grunty_die_ax1 = [ $axdeth1, grunty_die_ax2 ] {};
|
||
void() grunty_die_ax2 = [ $axdeth2, grunty_die_ax3 ] {};
|
||
void() grunty_die_ax3 = [ $axdeth3, grunty_die_ax4 ] {};
|
||
void() grunty_die_ax4 = [ $axdeth4, grunty_die_ax5 ] {};
|
||
void() grunty_die_ax5 = [ $axdeth5, grunty_die_ax6 ] {};
|
||
void() grunty_die_ax6 = [ $axdeth6, grunty_die_ax7 ] {};
|
||
void() grunty_die_ax7 = [ $axdeth7, grunty_die_ax8 ] {};
|
||
void() grunty_die_ax8 = [ $axdeth8, grunty_die_ax9 ] {};
|
||
void() grunty_die_ax9 = [ $axdeth9, grunty_die_ax9 ] {gruntyDead();};
|
||
|
||
// For now we'll just have this
|
||
// Later we'll have hard and soft deaths
|
||
void() ArmyDeathSound;
|
||
|
||
void() custom_grunt_die =
|
||
{
|
||
self.effects=0;
|
||
|
||
if (self.real_owner.classname == "player")
|
||
{
|
||
sprint(self.real_owner,PRINT_HIGH,"Your soldier is dead.\n");
|
||
self.real_owner.job = self.real_owner.job - (self.real_owner.job & JOB_DEMON_OUT);
|
||
self.real_owner.job_finished = time + 2; //Can't summon streams of demons SB can so
|
||
self.real_owner.demon_one = world;
|
||
|
||
if (self.martyr_enemy != world)
|
||
RemoveWaypoint(self.martyr_enemy, self);
|
||
|
||
if (self.demon_one != world)
|
||
RemoveWaypoint(self.demon_one, self);
|
||
|
||
if (self.demon_two != world)
|
||
RemoveWaypoint(self.demon_two, self);
|
||
|
||
local entity oself;
|
||
oself=self;
|
||
self=self.real_owner;
|
||
SetArmyTimer();
|
||
self=oself;
|
||
}
|
||
|
||
if (self.health < -30)
|
||
{
|
||
sound (self, CHAN_VOICE, "player/udeath.wav", 1, ATTN_MONSTERDIE);
|
||
|
||
ThrowGib ("progs/h_guard.mdl", self.health);
|
||
ThrowGib ("progs/gib1.mdl", self.health);
|
||
ThrowGib ("progs/gib2.mdl", self.health);
|
||
ThrowGib ("progs/gib3.mdl", self.health);
|
||
//ThrowGib ("progs/gib3.mdl", self.health);
|
||
dremove(self);
|
||
return;
|
||
}
|
||
|
||
self.solid = SOLID_NOT;
|
||
|
||
ArmyDeathSound();
|
||
self.classname = "monster_corpse";
|
||
|
||
self.think=SUB_Null;
|
||
self.touch=SUB_Null;
|
||
|
||
if (isMelee())
|
||
{
|
||
grunty_die_ax1();
|
||
}
|
||
else
|
||
{
|
||
local float r;
|
||
r=random();
|
||
if (r<0.2)
|
||
grunty_diea1();
|
||
else if (r<0.4)
|
||
grunty_dieb1();
|
||
else if (r<0.6)
|
||
grunty_diec1();
|
||
else if (r<0.8)
|
||
grunty_died1();
|
||
else grunty_diee1();
|
||
}
|
||
|
||
};
|
||
|
||
void() ArmyDeathSound =
|
||
{
|
||
local float rs;
|
||
|
||
// water death sounds
|
||
if (self.waterlevel == 3)
|
||
{
|
||
DeathBubbles(10);
|
||
sound (self, CHAN_VOICE, "player/h2odeath.wav", 1, ATTN_MONSTERDIE);
|
||
return;
|
||
}
|
||
|
||
rs = rint ((random() * 4) + 1);
|
||
if (rs == 1)
|
||
self.noise = "player/death1.wav";
|
||
if (rs == 2)
|
||
self.noise = "player/death2.wav";
|
||
if (rs == 3)
|
||
self.noise = "player/death3.wav";
|
||
if (rs == 4)
|
||
self.noise = "player/death4.wav";
|
||
if (rs == 5)
|
||
self.noise = "player/death5.wav";
|
||
|
||
sound (self, CHAN_VOICE, self.noise, 1, ATTN_MONSTERDIE);
|
||
};
|
||
|
||
// We'll include pain here
|
||
|
||
void() grunty_pain1 = [$pain1, grunty_pain2] {PainSound();self.weaponframe=0;self.effects=0;};
|
||
void() grunty_pain2 = [$pain2, grunty_pain3] {};
|
||
void() grunty_pain3 = [$pain3, grunty_pain4] {};
|
||
void() grunty_pain4 = [$pain4, grunty_pain5] {};
|
||
void() grunty_pain5 = [$pain5, grunty_pain6] {};
|
||
void() grunty_pain6 = [$pain6, grunty_run] {self.walkframe = 0;};
|
||
|
||
void() grunty_axepain1 = [ $axpain1, grunty_axepain2 ] {PainSound();self.weaponframe=0;self.effects=0;};
|
||
void() grunty_axepain2 = [ $axpain2, grunty_axepain3 ] {};
|
||
void() grunty_axepain3 = [ $axpain3, grunty_axepain4 ] {};
|
||
void() grunty_axepain4 = [ $axpain4, grunty_axepain5 ] {};
|
||
void() grunty_axepain5 = [ $axpain5, grunty_axepain6 ] {};
|
||
void() grunty_axepain6 = [ $axpain6, grunty_run ]
|
||
{
|
||
self.walkframe = 0; // - 1)/16);
|
||
self.pain_finished = time + random()*1.5*(self.has_sensor/17);
|
||
};
|
||
|
||
void(entity attacker, float damage) grunty_pain =
|
||
{
|
||
//self.real_owner.StatusRefreshTime = time + 0.2;
|
||
//self.real_owner.StatusBarScreen = 3;
|
||
|
||
#ifdef VERBOSE_GRUNTY
|
||
// RPrint(self.real_owner, PRINT_HIGH, "Grunty PAIN!\n");
|
||
#endif
|
||
|
||
if (self.pain_finished > time)
|
||
return;
|
||
|
||
//if (random()*40 > damage) // random()*40+40*((self.has_sensor-1)/16)
|
||
if (random()*40 + 40*((self.has_sensor - 1)/16) > damage)
|
||
return;
|
||
|
||
if (isMelee())
|
||
grunty_axepain1();
|
||
else
|
||
grunty_pain1();
|
||
};
|
||
|
||
/* ---------------------------------------------------------------------------------- */
|
||
// GRUNTY - PART SEVEN
|
||
// Moving with style
|
||
//
|
||
// Grunty needs waypoints
|
||
/* ---------------------------------------------------------------------------------- */
|
||
|
||
/*void() Grunty_PhysUpdate =
|
||
{
|
||
setorigin(self, self.origin + self.velocity * 0.05);
|
||
};*/
|
||
|
||
void() Waypoint_Touch =
|
||
{
|
||
// If the toucher isn't a grunt, return.
|
||
if (other.classname != "monster_army")
|
||
return;
|
||
|
||
// If the toucher isn't trying to reach us, return.
|
||
// We could do this with self.owner but it might accidentally touch a home waypoint
|
||
// making this a bad option.
|
||
if (other.goalentity != self)
|
||
return;
|
||
|
||
if (self.has_sensor == WAYPOINT_TYPE_ENEMYLASTSEEN)
|
||
{
|
||
if (self.owner.demon_one.demon_one == self)
|
||
self.owner.demon_one.demon_one = world;
|
||
|
||
dremove(self);
|
||
return;
|
||
}
|
||
|
||
if (self.has_sensor == WAYPOINT_TYPE_PRIMARY)
|
||
{
|
||
self.owner.demon_one.job=2;
|
||
}
|
||
else if (self.has_sensor == WAYPOINT_TYPE_SECONDARY)
|
||
{
|
||
self.owner.demon_one.job=1;
|
||
}
|
||
|
||
self.num_mines = time + self.has_holo; // reset entity live time
|
||
//has_holo is the asigned life time in createwaypoint
|
||
|
||
|
||
other.goalentity = self.goalentity; // Set grunty's movement target
|
||
//if (!self.has_sensor) // If we're non-permanent (ie. a temporary goal)
|
||
// dremove(self); // remove ourself
|
||
};
|
||
|
||
void() Waypoint_DoNothing = // A waypoint checks for redundancy
|
||
{
|
||
self.nextthink = time + 5; // next check in 5 seconds
|
||
|
||
//if (self.owner.classname!="player") return; //- OfN - NO!! remove it..
|
||
|
||
//- OfN - remove waypoint entity?
|
||
if (self.owner.has_disconnected
|
||
|| !(self.owner.job & JOB_ARMY)
|
||
|| !(self.owner.job & JOB_DEMON_OUT)
|
||
|| self.owner.classname!="player")
|
||
{
|
||
dremove(self); // no pointer set to world needed cause soldier shouldnt be present on game
|
||
return;
|
||
}
|
||
|
||
if (self.num_mines < time) // if it wasnt touched for specified life-time remove it
|
||
{
|
||
if (self.has_sensor == WAYPOINT_TYPE_PRIMARY
|
||
&& self.owner.demon_one.martyr_enemy == self)
|
||
self.owner.demon_one.martyr_enemy = world;
|
||
if (self.has_sensor == WAYPOINT_TYPE_SECONDARY
|
||
&& self.owner.demon_one.demon_two == self)
|
||
self.owner.demon_one.demon_two = world;
|
||
if (self.has_sensor == WAYPOINT_TYPE_ENEMYLASTSEEN
|
||
&& self.owner.demon_one.demon_one == self)
|
||
self.owner.demon_one.demon_one = world;
|
||
|
||
dremove(self);
|
||
return;
|
||
}
|
||
};
|
||
|
||
/* CreateWaypoint
|
||
*
|
||
* Creates a waypoint for use by grunty
|
||
* waypoint.goalentity = next target
|
||
* waypoint.owner = owner grunt
|
||
*/
|
||
|
||
entity (vector location, float life, float type) CreateWaypoint =
|
||
{
|
||
newmis = spawn(); // Spawn a new entity (the waypoint)
|
||
|
||
//newmis.has_sensor = 1; // has_sensor means we're a permanent waypoint, which always are
|
||
// - OfN now has_sensor holds the type of waypoint, primary, second etc..
|
||
|
||
// set the origin.
|
||
setsize (newmis, '-20 -20 -20', '20 20 20'); // set the size of the waypoint
|
||
|
||
newmis.solid = SOLID_TRIGGER; // We're a solid trigger type - touch, but don't block
|
||
|
||
//newmis.netname = "grunty_waypoint"; // set the name so grunty can talk about us
|
||
newmis.classname = "grunty_waypoint";
|
||
newmis.touch = Waypoint_Touch; // Set the waypoint's touch function
|
||
newmis.think = Waypoint_DoNothing; // Set the waypoint's redundancy check function
|
||
newmis.nextthink = time + 2; // Think in 2 seconds
|
||
|
||
if (self.classname=="player")
|
||
newmis.owner=self;
|
||
else if (self.classname=="monster_army")
|
||
newmis.owner=self.real_owner;
|
||
|
||
newmis.num_mines = time + life; //WAYPOINT_LIFE;
|
||
newmis.has_holo = life;
|
||
newmis.has_sensor = type; // sets the type of waypoint to has_sensor
|
||
|
||
setorigin(newmis, location);
|
||
|
||
return newmis; // return the entity
|
||
};
|
||
|
||
/* ---------------------------------------------------------------------------------- */
|
||
// GRUNTY - PART EIGHT
|
||
// Life and Happiness
|
||
//
|
||
// Grunty earns hard cash
|
||
/* ---------------------------------------------------------------------------------- */
|
||
|
||
void (entity targ) GetRank =
|
||
{
|
||
if (targ.has_sensor == 1)
|
||
targ.undercover_name = "Private Class III ";
|
||
else if (targ.has_sensor == 2)
|
||
targ.undercover_name = "Private Class II ";
|
||
else if (targ.has_sensor == 3)
|
||
targ.undercover_name = "Private Class I ";
|
||
else if (targ.has_sensor == 4)
|
||
targ.undercover_name = "Lance Corporal ";
|
||
else if (targ.has_sensor == 5)
|
||
targ.undercover_name = "Corporal ";
|
||
else if (targ.has_sensor == 6)
|
||
targ.undercover_name = "Sergeant ";
|
||
else if (targ.has_sensor == 7)
|
||
targ.undercover_name = "Staff Sergeant ";
|
||
else if (targ.has_sensor == 8)
|
||
targ.undercover_name = "Warrant Officer II ";
|
||
else if (targ.has_sensor == 9)
|
||
targ.undercover_name = "Warrant Officer I ";
|
||
else if (targ.has_sensor == 10)
|
||
targ.undercover_name = "Lieutenant Class II ";
|
||
else if (targ.has_sensor == 11)
|
||
targ.undercover_name = "Lieutenant Class I ";
|
||
else if (targ.has_sensor == 12)
|
||
targ.undercover_name = "Captain ";
|
||
else if (targ.has_sensor == 13)
|
||
targ.undercover_name = "Major ";
|
||
else if (targ.has_sensor == 14)
|
||
targ.undercover_name = "Colonel ";
|
||
else if (targ.has_sensor == 15)
|
||
targ.undercover_name = "Brigadier ";
|
||
else if (targ.has_sensor == 16)
|
||
targ.undercover_name = "General ";
|
||
else if (targ.has_sensor == 17)
|
||
targ.undercover_name = "Field Marshal ";
|
||
else
|
||
targ.undercover_name = "Error producer ";
|
||
};
|
||
|
||
void() Grunty_Check_Frags =
|
||
{
|
||
if (self.frags >= self.has_sentry && self.has_sensor < 17)
|
||
{
|
||
self.has_tesla = self.has_tesla + 0.1;
|
||
self.has_sensor = self.has_sensor + 1;
|
||
self.has_sentry = self.has_sentry + 2;
|
||
//self.health = self.health + self.has_sensor * 25; //-this before
|
||
self.health = self.health + 20 + self.has_sensor * 12; //-this now
|
||
self.max_health = self.max_health + 20 + self.has_sensor * 16;//-was 25
|
||
|
||
//ofn
|
||
if (self.max_health > GRUNT_MAX_HP)
|
||
self.max_health = GRUNT_MAX_HP;
|
||
|
||
if (self.health > self.max_health)
|
||
self.health = self.max_health;
|
||
|
||
custom_demon_name(self);
|
||
|
||
GetRank(self);
|
||
|
||
sprint(self.real_owner, PRINT_HIGH, "Your soldier, ");
|
||
sprint(self.real_owner, PRINT_HIGH, self.netname);
|
||
sprint(self.real_owner, PRINT_HIGH, ", has reached the rank of ");
|
||
sprint(self.real_owner, PRINT_HIGH, self.undercover_name);
|
||
sprint(self.real_owner, PRINT_HIGH, "\n");
|
||
}
|
||
};
|
||
|
||
float () ReturnWeaponVelocity =
|
||
{
|
||
if (self.current_weapon == WEAP_NAILGUN)
|
||
// return 1250;
|
||
return 99999999;
|
||
else if (self.current_weapon == WEAP_ROCKET_LAUNCHER)
|
||
//return 1100;
|
||
return 99999999;
|
||
else
|
||
return 99999999;
|
||
};
|
||
|
||
#define GRUNTY_COST_HEALTHPACK 35 // was 20
|
||
#define GRUNTY_COST_SHOTGUN 100 // was 50
|
||
#define GRUNTY_COST_NAILGUN 300 // was 300
|
||
#define GRUNTY_COST_SUPER_SHOTGUN 500 // was 500
|
||
#define GRUNTY_COST_KNIFE 500 // was 700 // then 400
|
||
#define GRUNTY_COST_ROCKET_LAUNCHER 3000 // was 3000 // then 2000
|
||
#define GRUNTY_COST_SCANNER 1200 // was 1000 // then 800
|
||
#define GRUNTY_COST_SHELL 4 // was 2
|
||
#define GRUNTY_COST_NAIL 2 // was 1
|
||
#define GRUNTY_COST_ROCKET 12 // was 3
|
||
#define GRUNTY_COST_CELL 2
|
||
#define GRUNTY_COST_MAXHEALTH 120 // was 100
|
||
#define GRUNTY_COST_SPEED 800 // was 400 // then 400
|
||
#define GRUNTY_MAX_SPEED 13 //- was 30
|
||
|
||
void () GruntyPayThink =
|
||
{
|
||
local float chance;
|
||
local float r;
|
||
local float spendalloc;
|
||
// If it's salary time, draw pay
|
||
if (self.respawn_time < time)
|
||
{
|
||
GruntyDrawPay();
|
||
self.respawn_time = time + 20;
|
||
}
|
||
// Grunty is on a SHOPPING SPREE!
|
||
if (!(self.weapons_carried & WEAP_ROCKET_LAUNCHER))
|
||
spendalloc = self.money * 0.2; // amount to spend on health/speed upgrades
|
||
else
|
||
spendalloc = self.money;
|
||
// Consider buying more max health )//- added
|
||
if (spendalloc >= GRUNTY_COST_MAXHEALTH && self.max_health < GRUNT_MAX_HP)
|
||
{
|
||
if (self.weapons_carried & WEAP_ROCKET_LAUNCHER)
|
||
chance = 0.75; //- was 0.9
|
||
else
|
||
chance = 0.25;
|
||
|
||
r = random();
|
||
if (r < chance)
|
||
{
|
||
self.max_health = self.max_health + 25;
|
||
self.money = self.money - GRUNTY_COST_MAXHEALTH;
|
||
spendalloc = spendalloc - GRUNTY_COST_MAXHEALTH;
|
||
// #ifdef VERBOSE_GRUNTY
|
||
PrintFromSoldier(self,self.real_owner,"my health maximum has been increased!\n");
|
||
// sprint(self.real_owner, PRINT_HIGH, "BUYS more MAX HP\n");
|
||
// #endif
|
||
}
|
||
}
|
||
// Consider buying a health pack
|
||
if (self.health < self.max_health && self.money >= GRUNTY_COST_HEALTHPACK)
|
||
{
|
||
local float loops, bought;
|
||
bought=0;
|
||
|
||
while (loops < (0.75+(self.has_sensor/4)) && self.money >= GRUNTY_COST_HEALTHPACK && self.max_health > self.health)
|
||
{
|
||
if (self.health < self.max_health - 25)
|
||
chance = 1;
|
||
else if (self.health < self.max_health - 15)
|
||
chance = 0.25;
|
||
else
|
||
chance = 0.1;
|
||
|
||
r = random();
|
||
if (r < chance)
|
||
{
|
||
self.health = self.health + 25;
|
||
if (self.health > self.max_health)
|
||
self.health = self.max_health;
|
||
self.money = self.money - GRUNTY_COST_HEALTHPACK;
|
||
// #ifdef VERBOSE_GRUNTY
|
||
|
||
// sprint(self.real_owner, PRINT_HIGH, "BUYS A HEALTHPACK\n");
|
||
//PrintFromSoldier(self,self.real_owner,"i've bought a healthpack.\n");
|
||
bought=bought+1;
|
||
// #endif
|
||
}
|
||
loops = loops + 1;
|
||
}
|
||
|
||
if (bought>0)
|
||
{
|
||
if (bought==1)
|
||
PrintFromSoldier(self,self.real_owner,"i've bought a healthpack.\n");
|
||
else
|
||
{
|
||
local string tempst;
|
||
tempst=ftos(bought);
|
||
PrintFromSoldier(self,self.real_owner,"i've bought ");
|
||
sprint(self.real_owner,PRINT_HIGH,tempst);
|
||
sprint(self.real_owner,PRINT_HIGH," healthpacks.\n");
|
||
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
// Consider buying a shotgun
|
||
if (!(self.weapons_carried & WEAP_SHOTGUN))
|
||
if (self.money >= GRUNTY_COST_SHOTGUN)
|
||
{
|
||
r = random();
|
||
if (r < 0.5)
|
||
{
|
||
self.weapons_carried = self.weapons_carried | WEAP_SHOTGUN;
|
||
self.money = self.money - GRUNTY_COST_SHOTGUN;
|
||
PrintFromSoldier(self,self.real_owner,"i have bought a shotgun.\n");
|
||
//sprint(self.real_owner, PRINT_HIGH, "Your soldier has just purchased a shotgun.\n");
|
||
}
|
||
}
|
||
// Consider buying a knife
|
||
if (!(self.cutf_items & CUTF_KNIFE))
|
||
if (self.money >= GRUNTY_COST_KNIFE)
|
||
{
|
||
r = random();
|
||
if (r < 0.5)
|
||
{
|
||
self.cutf_items = self.cutf_items | CUTF_KNIFE;
|
||
self.money = self.money - GRUNTY_COST_KNIFE;
|
||
PrintFromSoldier(self,self.real_owner,"i have bought a knife.\n");
|
||
//sprint(self.real_owner, PRINT_HIGH, "Your soldier has just purchased a knife.\n");
|
||
}
|
||
}
|
||
// Consider buying a nailgun
|
||
if (!(self.weapons_carried & WEAP_NAILGUN))
|
||
if (self.money >= GRUNTY_COST_NAILGUN)
|
||
{
|
||
r = random();
|
||
if (r < 0.25)
|
||
{
|
||
self.weapons_carried = self.weapons_carried | WEAP_NAILGUN;
|
||
self.money = self.money - GRUNTY_COST_NAILGUN;
|
||
PrintFromSoldier(self,self.real_owner,"i now own a nailgun.\n");
|
||
//sprint(self.real_owner, PRINT_HIGH, "Your soldier now owns a nailgun.\n");
|
||
}
|
||
}
|
||
// Consider buying a double barrel
|
||
if (!(self.weapons_carried & WEAP_SUPER_SHOTGUN))
|
||
if (self.money >= GRUNTY_COST_SUPER_SHOTGUN)
|
||
{
|
||
r = random();
|
||
if (r < 0.25)
|
||
{
|
||
self.weapons_carried = self.weapons_carried | WEAP_SUPER_SHOTGUN;
|
||
self.money = self.money - GRUNTY_COST_SUPER_SHOTGUN;
|
||
PrintFromSoldier(self,self.real_owner,"i've just bought a super shotgun.\n");
|
||
//sprint(self.real_owner, PRINT_HIGH, "Your soldier just bought a super shotgun.\n");
|
||
|
||
}
|
||
}
|
||
// Consider buying a scanner
|
||
if (!(self.tf_items & NIT_SCANNER))
|
||
if (self.money >= GRUNTY_COST_SCANNER)
|
||
{
|
||
r = random();
|
||
if (r < 0.15)
|
||
{
|
||
self.tf_items = self.tf_items | NIT_SCANNER;
|
||
self.money = self.money - GRUNTY_COST_SCANNER;
|
||
PrintFromSoldier(self,self.real_owner,"i now own a scanner.\n");
|
||
//sprint(self.real_owner, PRINT_HIGH, "Your soldier now owns a scanner.\n");
|
||
}
|
||
}
|
||
// Consider buying...a rocket launcher.
|
||
if (!(self.weapons_carried & WEAP_ROCKET_LAUNCHER))
|
||
if (self.money >= GRUNTY_COST_ROCKET_LAUNCHER)
|
||
{
|
||
r = random();
|
||
if (r < 0.3) //- was 0.2
|
||
{
|
||
self.weapons_carried = self.weapons_carried | WEAP_ROCKET_LAUNCHER;
|
||
self.money = self.money - GRUNTY_COST_ROCKET_LAUNCHER;
|
||
PrintFromSoldier(self,self.real_owner,"i have bought a ROCKET LAUNCHER!! hehe\n");
|
||
//sprint(self.real_owner, PRINT_HIGH, "Your soldier is now the proud owner of a brand new rocket launcher.\n");
|
||
}
|
||
}
|
||
|
||
// Buy ammo
|
||
if ((self.weapons_carried & WEAP_ROCKET_LAUNCHER) && self.ammo_rockets < self.maxammo_rockets)
|
||
{
|
||
local float rocketstobuy;
|
||
|
||
rocketstobuy = self.maxammo_rockets - self.ammo_rockets;
|
||
if (rocketstobuy > 4)
|
||
rocketstobuy = 4;
|
||
if (self.money >= rocketstobuy * GRUNTY_COST_ROCKET)
|
||
{
|
||
self.ammo_rockets = self.ammo_rockets + rocketstobuy;
|
||
self.money = self.money - rocketstobuy * GRUNTY_COST_ROCKET;
|
||
|
||
// #ifdef VERBOSE_GRUNTY
|
||
PrintFromSoldier(self,self.real_owner,"i've bought some rockets.\n");
|
||
//sprint(self.real_owner, PRINT_HIGH, "BUYS SOME ROCKETS\n");
|
||
// #endif
|
||
}
|
||
}
|
||
|
||
if ((self.weapons_carried & WEAP_NAILGUN) && self.ammo_nails < self.maxammo_nails)
|
||
{
|
||
local float nailstobuy;
|
||
|
||
nailstobuy = self.maxammo_nails - self.ammo_nails;
|
||
if (nailstobuy > 50) // was 50
|
||
nailstobuy = 50;
|
||
if (self.money >= nailstobuy * GRUNTY_COST_NAIL)
|
||
{
|
||
self.ammo_nails = self.ammo_nails + nailstobuy;
|
||
self.money = self.money - nailstobuy * GRUNTY_COST_NAIL;
|
||
// #ifdef VERBOSE_GRUNTY
|
||
PrintFromSoldier(self,self.real_owner,"i've bought some nails.\n");
|
||
//sprint(self.real_owner, PRINT_HIGH, "BUYS SOME NAILS\n");
|
||
// #endif
|
||
|
||
}
|
||
}
|
||
|
||
if ((self.weapons_carried & WEAP_SHOTGUN ||
|
||
self.weapons_carried & WEAP_SUPER_SHOTGUN)
|
||
&& self.ammo_shells < self.maxammo_shells)
|
||
{
|
||
local float shellstobuy;
|
||
|
||
shellstobuy = self.maxammo_shells - self.ammo_shells;
|
||
if (shellstobuy > 15)
|
||
shellstobuy = 15;
|
||
if (self.money >= shellstobuy * GRUNTY_COST_SHELL)
|
||
{
|
||
self.ammo_shells = self.ammo_shells + shellstobuy;
|
||
self.money = self.money - shellstobuy * GRUNTY_COST_SHELL;
|
||
// #ifdef VERBOSE_GRUNTY
|
||
PrintFromSoldier(self,self.real_owner,"i've bought some shells.\n");
|
||
//sprint(self.real_owner, PRINT_HIGH, "BUYS SOME SHELLS\n");
|
||
// #endif
|
||
}
|
||
}
|
||
|
||
// Consider buying more speed
|
||
if (spendalloc >= GRUNTY_COST_SPEED)
|
||
{
|
||
if (self.custom_speed < GRUNTY_MAX_SPEED)
|
||
{
|
||
r = random();
|
||
if (r < 0.3)
|
||
{
|
||
self.custom_speed = self.custom_speed + 1;
|
||
self.money = self.money - GRUNTY_COST_SPEED;
|
||
spendalloc = spendalloc - GRUNTY_COST_SPEED;
|
||
|
||
PrintFromSoldier(self,self.real_owner,"i'm faster now.\n");
|
||
//sprint(self.real_owner, PRINT_HIGH, "Your soldier is now faster.\n");
|
||
}
|
||
}
|
||
}
|
||
|
||
//- OfteN: don't let grunt have more HP than GRUNT_MAX_HP -//
|
||
if (self.health > GRUNT_MAX_HP)
|
||
self.health = GRUNT_MAX_HP;
|
||
|
||
if (self.max_health > GRUNT_MAX_HP)
|
||
self.max_health = GRUNT_MAX_HP;
|
||
|
||
self.suicide_time = time + 10;
|
||
};
|
||
|
||
void () GruntyDrawPay =
|
||
{
|
||
self.money = self.money + 70 + floor((self.has_sensor/2)+1) * 25;//-was 30 and has_sensor wasnt/2 // then was 30 again
|
||
self.respawn_time = time + 20;
|
||
return;
|
||
};
|
||
|
||
//-----------------------------------------------------//
|
||
void() grunty_touch =
|
||
{
|
||
/*if (other.classname=="ammobox")
|
||
{
|
||
PrintFromSoldier(self,other,"AMMO?\n");
|
||
return;
|
||
}*/
|
||
|
||
if (other.classname=="player" && self.has_holo < time && self.enemy == world && self.health >= 0)
|
||
{
|
||
local string st;
|
||
|
||
if (self.real_owner==other)
|
||
{
|
||
st=GetOwnerMessage(self);
|
||
PrintFromSoldier(self,other,st);
|
||
|
||
self.has_holo=time+5;
|
||
}
|
||
else if (Teammate(self.real_owner.team_no, other.team_no))
|
||
{
|
||
local float rnum;
|
||
rnum=random();
|
||
|
||
if (rnum < 0.4)
|
||
{
|
||
PrintFromSoldier(self,other,"Hi ");
|
||
sprint(other,PRINT_HIGH,other.netname);
|
||
sprint(other,PRINT_HIGH,", I'm ");
|
||
sprint(other,PRINT_HIGH,self.netname);
|
||
sprint(other,PRINT_HIGH,", ");
|
||
sprint(other,PRINT_HIGH,self.real_owner.netname);
|
||
sprint(other,PRINT_HIGH,"'s soldier!\n");
|
||
|
||
}
|
||
else
|
||
{
|
||
st=GetFriendlyMessage(self);
|
||
PrintFromSoldier(self,other,st);
|
||
}
|
||
|
||
self.has_holo=time+5;
|
||
}
|
||
|
||
}
|
||
|
||
//self=other; // why this?
|
||
};
|
||
|
||
//========================================================================
|
||
// lets make the server to not crash when removing waypoints ok? :)
|
||
|
||
void(entity wyp, entity soldier) RemoveWaypoint =
|
||
{
|
||
if (wyp==world) return;
|
||
|
||
if (wyp.classname == "grunty_waypoint" && wyp.owner == soldier.real_owner)
|
||
{
|
||
if (wyp.owner.demon_one.martyr_enemy != world)
|
||
{
|
||
if (wyp.owner.demon_one.martyr_enemy.goalentity == wyp)
|
||
wyp.owner.demon_one.martyr_enemy.goalentity = world;
|
||
}
|
||
|
||
if (wyp.owner.demon_one.demon_two != world)
|
||
{
|
||
if (wyp.owner.demon_one.demon_two.goalentity == wyp)
|
||
wyp.owner.demon_one.demon_two.goalentity = world;
|
||
}
|
||
|
||
if (wyp.has_sensor == WAYPOINT_TYPE_PRIMARY
|
||
&& wyp.owner.demon_one.martyr_enemy == wyp)
|
||
wyp.owner.demon_one.martyr_enemy = world;
|
||
else if (wyp.has_sensor == WAYPOINT_TYPE_SECONDARY
|
||
&& wyp.owner.demon_one.demon_two == wyp)
|
||
wyp.owner.demon_one.demon_two = world;
|
||
else if (wyp.has_sensor == WAYPOINT_TYPE_ENEMYLASTSEEN
|
||
&& wyp.owner.demon_one.demon_one == wyp)
|
||
wyp.owner.demon_one.demon_one = world;
|
||
|
||
dremove(wyp);
|
||
}
|
||
};
|
||
|
||
//=======================================================================//
|
||
// OfN returns the goalentity the grunt should be going to if its able
|
||
|
||
entity(entity sold, entity viewpoint) ReturnEasyWaypoint =
|
||
{
|
||
if (sold.penance_time==2) return world;
|
||
if (sold.penance_time==0) return world;
|
||
|
||
if (sold.penance_time==1)
|
||
{
|
||
if (sold.real_owner.health <= 0)
|
||
{
|
||
sold.penance_time=0;
|
||
return world;
|
||
}
|
||
|
||
if (visible2(sold,sold.real_owner))
|
||
return sold.real_owner;
|
||
else
|
||
{
|
||
//sold.penance_time=0; // don't reset sold last "intention"
|
||
PrintFromSoldier(sold,sold.real_owner,"i was following you but i can't see you now!\n");
|
||
return world;
|
||
}
|
||
|
||
}
|
||
|
||
if (sold.martyr_enemy!=world && sold.job==1 && visible2(viewpoint,sold.martyr_enemy))
|
||
return sold.martyr_enemy;
|
||
|
||
if (sold.demon_two!=world && sold.job==2 && visible2(viewpoint,sold.demon_two))
|
||
return sold.demon_two;
|
||
|
||
// no last waypoint walk so lets see whats easier to reach...
|
||
|
||
local entity retENT;
|
||
retENT=world;
|
||
|
||
if (sold.demon_two!=world && sold.martyr_enemy!=world) // both waypoints assigned? ok...
|
||
{
|
||
if (visible2(viewpoint,sold.martyr_enemy) && visible2(viewpoint,sold.demon_two)) // both waypoints visible? lets see which one is closest...
|
||
{
|
||
local float dist1,dist2;
|
||
dist1 = vlen(viewpoint.origin - sold.martyr_enemy.origin);
|
||
dist2 = vlen(viewpoint.origin - sold.demon_two.origin);
|
||
|
||
if (dist1 > dist2) // which is the closest one?
|
||
{
|
||
retENT=sold.demon_two;
|
||
}
|
||
else
|
||
{
|
||
retENT=sold.martyr_enemy;
|
||
}
|
||
}
|
||
else if (visible2(viewpoint,sold.martyr_enemy)) // only primary wayp is visible?
|
||
retENT=sold.martyr_enemy;
|
||
else if (visible2(viewpoint,sold.demon_two)) // only secondary wayp is visible?
|
||
retENT=sold.demon_two;
|
||
}
|
||
else if (sold.demon_two!=world) // only secondary wayp is assigned?
|
||
{
|
||
if (visible2(viewpoint,sold.demon_two))
|
||
retENT=sold.demon_two;
|
||
}
|
||
else if (sold.martyr_enemy!=world) // only primary wayp is assigned?
|
||
{
|
||
if (visible2(viewpoint,sold.martyr_enemy))
|
||
retENT=sold.martyr_enemy;
|
||
}
|
||
|
||
if (sold.penance_time == 3 && retENT==world)
|
||
{
|
||
PrintFromSoldier(sold,sold.real_owner,"can't see my waypoints around here!\n");
|
||
//sold.penance_time = 0; // don't reset sold last "intention"
|
||
}
|
||
|
||
return retENT;
|
||
};
|
||
|
||
//== OfN, used when picking up ammo ==//
|
||
void(entity sld) grunty_boundammo =
|
||
{
|
||
if (sld.classname!="monster_army") return;
|
||
|
||
if (sld.ammo_nails > sld.maxammo_nails) sld.ammo_nails = sld.maxammo_nails;
|
||
if (sld.ammo_cells > sld.maxammo_cells) sld.ammo_cells = sld.maxammo_cells;
|
||
if (sld.ammo_shells > sld.maxammo_shells) sld.ammo_shells = sld.maxammo_shells;
|
||
if (sld.ammo_rockets > sld.maxammo_rockets) sld.ammo_rockets = sld.maxammo_rockets;
|
||
};
|