kingpin-sdk/gamesrc/AI_BITCH.C
2000-03-27 00:00:00 +00:00

1375 lines
33 KiB
C

#include "g_local.h"
#include "ai_bitch.h"
#include "voice_bitch.h"
void bitch_end_kneel_attack( edict_t *self );
void bitch_talk( edict_t *self );
void bitch_end_stand( edict_t *self );
void bitch_kneel_shoot( edict_t *self );
void bitch_talk_think( edict_t *self );
void bitch_firegun( edict_t *self, vec3_t ofs );
void bitch_right_fire( edict_t *self );
void bitch_left_fire( edict_t *self );
void bitch_firegun_right( edict_t *self );
void bitch_firegun_left( edict_t *self );
void bitch_show_guns( edict_t *self );
void bitch_climb_loop( edict_t *self );
void bitch_melee( edict_t *self );
void bitch_evade_amb( edict_t *self );
void bitch_melee_bail (edict_t *self);
void bitch_evade_checkadjust (edict_t *self);
void bitch_evade_adjust( edict_t *self );
#define BITCH_MELEE 64 // spawnflag
#define BITCH_NOWEAPON 128
// =========================================================================
#include "ai_bitch_tables.h"
// =========================================================================
void bitch_backoff( edict_t *self, edict_t *other )
{
Voice_Random( self, other, f_backoff, F_NUM_BACKOFF );
}
void bitch_catch_fire( edict_t *self, edict_t *other )
{
self->enemy = NULL; // stop attacking
self->cast_info.currentmove = &bitch_move_run_on_fire;
}
void bitch_evade_amb( edict_t *self )
{
// self->cast_info.currentmove = &bitch_move_evade_amb;
self->cast_info.currentmove = &bitch_move_evd_amb;
}
void bitch_evade_checkadjust( edict_t *self )
{
if (self->enemy && !directly_infront(self, self->enemy ))
self->cast_info.currentmove = &bitch_move_evade_adjust;
}
void bitch_evade_adjust (edict_t *self )
{
vec3_t vec;
if (!self->enemy)
return;
VectorSubtract( self->enemy->s.origin, self->s.origin, vec );
VectorNormalize( vec );
self->ideal_yaw = vectoyaw( vec );
}
void bitch_end_kneel_attack( edict_t *self )
{
AI_EndAttack(self);
if (self->cast_info.currentmove == self->cast_info.move_stand)
// self->cast_info.currentmove = &bitch_move_kneel_up;
// we dont have a crouch kneel up
self->cast_info.currentmove = &bitch4_move_crch_amb_std;
}
void bitch_talk_think( edict_t *self )
{
AI_TalkThink( self, false );
}
void bitch_talk( edict_t *self )
{
float rnd;
// only make talking gesture if we've recently said something
if (!(self->cast_info.aiflags & AI_REPEAT_TALK_JESTURE) && self->last_talk_time < (level.time - 1.0))
{
self->cast_info.currentmove = self->cast_info.move_stand;
return;
}
if (self->cast_info.currentmove != self->cast_info.move_stand)
return;
rnd = random() * 10;
if (rnd < 1)
self->cast_info.currentmove = &bitch_move_leanlook;
else if (rnd < 2)
self->cast_info.currentmove = &bitch_move_whatsup;
else if (rnd < 3)
self->cast_info.currentmove = &bitch_move_talkme;
else if (rnd < 4)
self->cast_info.currentmove = &bitch_move_nonono;
else if (rnd < 5)
self->cast_info.currentmove = &bitch_move_comeon;
else if (rnd < 6)
self->cast_info.currentmove = &bitch_move_getdown;
else if (rnd < 7)
self->cast_info.currentmove = &bitch_move_whomw;
else if (rnd < 8)
self->cast_info.currentmove = &bitch_move_lookself;
else // if (rnd < 9)
self->cast_info.currentmove = &bitch_move_flirt;
}
void bitch_avoid ( edict_t *self, edict_t *other, qboolean face )
{
vec3_t vec;
if (self->health <= 0)
return;
if (!self->groundentity)
return;
self->cast_info.last_avoid = level.time;
self->cast_info.avoid_ent = NULL;
if (face)
{ // turn to face them
VectorSubtract( other->s.origin, self->s.origin, vec );
self->cast_info.avoid_ent = other;
}
else
{ // turn to face away from them
VectorSubtract( self->s.origin, other->s.origin, vec );
}
VectorNormalize( vec );
self->ideal_yaw = vectoyaw( vec );
if (self->maxs[2] > DUCKING_MAX_Z)
{
if (self->cast_info.aiflags & AI_NOWALK_FACE)
{
// if (face)
{
int side_result;
side_result = AI_SideTrace( self, 48, 90, SIDE_RANDOM );
if (side_result == AI_SideTrace( self, 48, 90 + (self->ideal_yaw - self->s.angles[YAW]), side_result ))
{
if (side_result < 0)
self->cast_info.currentmove = &bitch4_move_lside_step;
else
self->cast_info.currentmove = &bitch4_move_rside_step;
return;
}
// if no move set, just turn to face
M_ChangeYaw( self );
return;
}
}
if ((VectorDistance( self->s.origin, other->s.origin ) > 72) || !face)
self->cast_info.currentmove = &bitch_move_avoid_walk;
else
self->cast_info.currentmove = &bitch_move_avoid_reverse_walk;
}
else
{
self->cast_info.currentmove = &bitch_move_crch_avoid_walk;
}
}
void bitch_end_stand( edict_t *self )
{
if (self->cast_info.move_stand_evade && (self->last_stand_evade > (level.time - 3)))
return;
//if (self->cast_info.currentmove == self->cast_info.move_crstand)
// return;
// if ( ((!self->cast_group) && (random() < 0.8))
// || ((self->cast_group) && (random() < 0.3)))
{ // stand normally
self->cast_info.currentmove = self->cast_info.move_stand;
// return;
}
AI_CheckTalk(self);
}
void bitch_show_guns( edict_t *self )
{
self->s.model_parts[PART_GUN].invisible_objects = 0;
}
void bitch_kneel_shoot( edict_t *self )
{
// self->cast_info.currentmove = &bitch_move_knl_shoot;
self->cast_info.currentmove = &bitch4_move_crch_shoot;
}
void bitch_melee_bail (edict_t *self)
{
vec3_t vec;
float dist;
if (self->enemy)
{
VectorSubtract( self->enemy->s.origin, self->s.origin, vec );
dist = VectorNormalize( vec );
if (dist > 48)
{
// AI_EndAttack(self);
self->cast_info.currentmove = &bitch4_move_run_melee;
return;
}
}
}
void bitch_long_attack( edict_t *self )
{
int rnd;
// keep running, and try to fire if possible
if (self->maxs[2] < self->cast_info.standing_max_z)
return;
if (self->s.model_parts[PART_GUN].invisible_objects)
{ // pull guns out
// note to self dont have this animation yet
self->cast_info.currentmove = &bitch_move_pull_gun;
return;
}
//if (self->moral > MORAL_NORMAL)
rnd = rand()%10;
if (rnd > 8)
self->cast_info.currentmove = &bitch_move_shoot_stand;
else
self->cast_info.currentmove = &bitch_move_run_shoot;
}
qboolean bitch_attack( edict_t *self )
{
vec3_t vec;
float dist;
int rnd;
// this is where we would start some of the fancy side-ways or rolling attacks
if (self->maxs[2] < self->cast_info.standing_max_z)
{
if (self->cast_info.aiflags & AI_MELEE)
{ // try to stand at all costs
self->maxs[2] = self->cast_info.standing_max_z;
if (ValidBoxAtLoc( self->s.origin, self->mins, self->maxs, self, MASK_PLAYERSOLID ))
goto standing;
self->maxs[2] = DUCKING_MAX_Z;
return false; // can't attack
}
if (self->s.model_parts[PART_GUN].invisible_objects)
{ // pull guns out
self->s.model_parts[PART_GUN].invisible_objects = 0;
}
self->cast_info.currentmove = &bitch4_move_crch_shoot;
return true;
}
standing:
VectorSubtract( self->enemy->s.origin, self->s.origin, vec );
dist = VectorNormalize( vec );
if (self->cast_info.aiflags & AI_MELEE)
{
qboolean attack=false;
if (dist < 64)
{
attack = true;
}
else // are they running towards us?
{
VectorSubtract( self->enemy->s.origin, self->s.origin, vec );
VectorMA( vec, 0.5, self->enemy->velocity, vec );
dist = VectorNormalize( vec );
if (dist < 64)
{
attack = true;
}
}
if (attack)
{
int rnd;
self->ideal_yaw = vectoyaw(vec);
M_ChangeYaw( self );
Voice_Random( self, self->enemy, f_grunting, 5);
rnd = rand()%4;
switch (rnd)
{
case 0 :
self->cast_info.currentmove = &bitch4_move_melee1;
break;
case 1 :
self->cast_info.currentmove = &bitch4_move_melee3;
break;
/*
// moves are messed up
case 2 :
self->cast_info.currentmove = &bitch4_move_melee2;
break;
case 3 :
self->cast_info.currentmove = &bitch4_move_melee3;
break;
*/
}
if (self->maxs[2] > self->enemy->maxs[2] || self->s.origin[2] > self->enemy->s.origin[2])
self->cast_info.currentmove = &bitch4_move_low_melee1;
return true;
}
else if (dist < 128)
{
self->ideal_yaw = vectoyaw(vec);
M_ChangeYaw( self );
self->cast_info.currentmove = &bitch4_move_run_melee;
return true;
}
else if (dist < 400)
self->cast_info.aiflags |= AI_RUSH_THE_PLAYER;
return false;
}
// we can shoot and gun (not melee)
if (self->s.model_parts[PART_GUN].invisible_objects)
{ // pull guns out
self->cast_info.currentmove = &bitch_move_pull_gun;
return true;
}
if ( (dist < 384) // they're close
&& (self->enemy->client)
&& (self->enemy->client->pers.weapon)
&& (stricmp(self->enemy->client->pers.weapon->classname, "weapon_flamethrower") == 0))
{
int side_result;
// see if we can go backwards
if (side_result = AI_SideTrace( self, -64, 0, 1 ))
{
self->cast_info.currentmove = &bitch_move_reverse_run_shoot;
return true;
}
}
// if just popped out from a corner, just stand here
if (self->dont_takecover_time > (level.time - 2))
{
goto stand_shoot;
}
rnd = rand()%10;
/*
if (dist > AI_NOT_HOLSTERED_RANGE_1 && rnd < 9)
{
self->cast_info.currentmove = &bitch_move_shoot_stand;
return true;
}
else
*/
if ((skill->value > random()*2) && (self->cast_info.last_side_attack_time < (level.time - 1)) && (dist > 128))
{
int side_result, side_result2;
side_result = AI_SideTrace( self, 64, 90, -self->cast_info.last_side_attack );
if (side_result)
{
side_result2 = AI_SideTrace( self, 96, 90, side_result );
if (side_result2 == side_result)
{
if (side_result < 0)
self->cast_info.currentmove = &bitch_move_lside_run;
else
self->cast_info.currentmove = &bitch_move_rside_run;
self->ideal_yaw = vectoyaw(vec) + side_result * 90;
M_ChangeYaw( self );
self->cast_info.last_side_attack = side_result;
self->cast_info.last_side_attack_time = level.time;
return true;
}
}
}
if ( (dist > 512)
&& (rnd < 9)
&& (infront(self, self->enemy)))
{
self->cast_info.currentmove = &bitch_move_walk_shoot;
return true;
}
else
{
stand_shoot:
self->ideal_yaw = vectoyaw(vec);
M_ChangeYaw( self );
self->cast_info.currentmove = &bitch_move_shoot_stand;
// self->cast_info.currentmove = &bitch_move_walk_shoot;
return true;
}
return false;
}
void bitch_climb_loop(edict_t *self)
{
self->cast_info.currentmove = &bitch4_move_clmb_loop;
}
void bitch_melee( edict_t *self )
{
vec3_t start, offset;
vec3_t forward, right;
float damage = 10;
if (self->cast_info.currentmove == &bitch4_move_low_melee1)
damage *= 2; // double handed attack
// yell at them?
if (self->last_talk_time < (level.time - TALK_FIGHTING_DELAY))
Voice_Random( self, self->enemy, f_grunting, 5);
// VectorSet(offset, 0, 8, self->viewheight - 4);
VectorSet(offset, 0, 8, 16);
AngleVectors (self->s.angles, forward, right, NULL);
if (self->cast_info.currentmove == &bitch4_move_low_melee1)
forward[2] = -0.5;
G_ProjectSource (self->s.origin, offset, forward, right, start);
if (self->cast_info.currentmove == &bitch4_move_low_melee1)
start[2] -= 8;
// HACK, higher Moral does more damage
if (self->moral > 4)
damage *= 1.0 + (self->moral - 4)*0.25;
fire_blackjack( self, start, forward, damage, 10, MOD_BLACKJACK );
}
void bitch_firegun( edict_t *self, vec3_t ofs )
{
vec3_t start;
vec3_t forward, right;
vec3_t target;
vec3_t aim;
vec3_t offset;
int flash_number;
float dist;
if (self->cast_info.currentmove == &bitch4_move_crch_shoot)
{
/*
if (!directly_infront( self, self->enemy ))
{
self->cast_info.currentmove = &bitch4_move_crch_amb_std;
self->s.frame++; // skip the firing frame since it might have a muzzle flash
return;
}
self->cast_info.aiflags |= AI_FACE_ATTACK;
*/
}
else
{
// check for reload
if (self->duration++ > 12)
{
self->duration = 0;
self->cast_info.currentmove = &bitch_move_reload;
self->s.frame++; // skip the firing frame since it might have a muzzle flash
return;
}
}
if (!AI_BeginAttack( self ))
{
self->s.frame++; // skip the firing frame since it might have a muzzle flash
return;
}
self->cast_info.aiflags &= ~AI_FACE_ATTACK;
// yell at them?
if (self->last_talk_time < (level.time - TALK_FIGHTING_DELAY))
Voice_Random(self, self->enemy, f_fightsounds, F_NUM_FIGHTING);
// fire the gun
VectorSet(offset, 0 + ofs[0], 8 + ofs[1], self->viewheight-8 + ofs[2]);
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, offset, forward, right, start);
// project enemy back a bit and target there
VectorCopy (self->enemy->s.origin, target);
VectorMA (target, (-0.5 * (random()*0.8 + 0.2)) * (1.0 - (skill->value/4.0)), self->enemy->velocity, target);
target[2] += self->enemy->viewheight;
flash_number = MZ2_GUNNER_MACHINEGUN_1;
VectorSubtract (target, start, aim);
dist = VectorNormalize (aim);
self->ideal_yaw = vectoyaw( aim );
if ( dist > AI_NOT_HOLSTERED_RANGE_1)
if ( (dist < self->cast_info.max_attack_distance)
&& ( ((random() < 0.1) && (self->cast_info.last_side_attack_time < (level.time - 2)))
|| ( (!(self->cast_info.aiflags & AI_SIDE_ATTACK) || (self->cast_info.last_side_attack_time < (level.time - 2)))
&& (directly_infront( self->enemy, self))
&& (self->enemy->client)
&& (self->enemy->client->pers.weapon)
&& (self->enemy->client->pers.weapon->ammo)))) // if we are directly infront of them, try to strafe
{
if (self->cast_info.aiflags & AI_SIDE_ATTACK)
self->cast_info.currentmove = &bitch_move_run_shoot;
else
self->cast_info.attack( self );
}
/*
if (self->acc > ACC_NORMAL)
cast_fire_bullet (self, start, aim, self->cal, 0, 0.0, 0.0, flash_number);
else
cast_fire_bullet (self, start, aim, self->cal, 0, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
*/
if (self->acc)
cast_fire_bullet (self, start, aim, self->cal, 0, DEFAULT_BULLET_HSPREAD>>self->acc, DEFAULT_BULLET_VSPREAD>>self->acc, flash_number);
else
cast_fire_bullet (self, start, aim, self->cal, 0, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
gi.sound(self, CHAN_WEAPON, gi.soundindex("weapons/machinegun/machgf1b.wav"), 1, ATTN_NORM, 0);
}
void bitch_right_fire( edict_t *self )
{
static vec3_t ofs = {4, 0, 0};
bitch_firegun( self, ofs );
}
void bitch_left_fire( edict_t *self )
{
static vec3_t ofs = {-4, 0, 0};
bitch_firegun( self, ofs );
}
void bitch_firegun_right( edict_t *self )
{
vec3_t vec;
float oldyaw;
static vec3_t ofs = {0,0,0};
if (!self->enemy)
{
self->cast_info.currentmove = self->cast_info.move_stand;
return;
}
if (self->cast_info.aiflags & AI_TURN_BLOCKED)
{ // abort the side run
self->cast_info.aiflags &= ~AI_TURN_BLOCKED;
AI_EndAttack(self);
return;
}
// if the path ahead is not clear, abort
if (!AI_SideTrace( self, 96, 0, 1 ))
{
AI_EndAttack(self);
return;
}
oldyaw = self->s.angles[YAW];
VectorSubtract( self->enemy->s.origin, self->s.origin, vec );
VectorNormalize( vec );
self->s.angles[YAW] = vectoyaw( vec );
self->cast_info.aiflags |= AI_SIDE_ATTACK;
bitch_firegun(self, ofs);
self->cast_info.aiflags &= ~AI_SIDE_ATTACK;
// keep running to the side
self->ideal_yaw = self->s.angles[YAW] + 90;
self->s.angles[YAW] = oldyaw;
}
void bitch_firegun_left( edict_t *self )
{
vec3_t vec;
float oldyaw;
static vec3_t ofs = {0,0,0};
if (!self->enemy)
{
self->cast_info.currentmove = self->cast_info.move_stand;
return;
}
if (self->cast_info.aiflags & AI_TURN_BLOCKED)
{ // abort the side run
self->cast_info.aiflags &= ~AI_TURN_BLOCKED;
AI_EndAttack(self);
return;
}
// if the path ahead is not clear, abort
if (!AI_SideTrace( self, 96, 0, 1 ))
{
AI_EndAttack(self);
return;
}
oldyaw = self->s.angles[YAW];
VectorSubtract( self->enemy->s.origin, self->s.origin, vec );
VectorNormalize( vec );
self->s.angles[YAW] = vectoyaw( vec );
self->cast_info.aiflags |= AI_SIDE_ATTACK;
bitch_firegun(self, ofs);
self->cast_info.aiflags &= ~AI_SIDE_ATTACK;
// keep running to the side
self->ideal_yaw = self->s.angles[YAW] - 90;
self->s.angles[YAW] = oldyaw;
}
// JOSEPH 17-NOV-98
void think_playthud_bitch( edict_t *self )
{
char Temp[128];
strcpy ((char*)Temp, "actors/player/bodyfalls/");
if (self->thudsurf & SURF_FABRIC)
{
strcat((char*)&Temp[0], (char*)"rug");
}
else if (self->thudsurf & SURF_GRAVEL)
{
strcat((char*)&Temp[0], (char*)"gravel");
}
else if (self->thudsurf & SURF_METAL)
{
strcat((char*)&Temp[0], (char*)"metalh");
}
else if (self->thudsurf & SURF_METAL_L)
{
strcat((char*)&Temp[0], (char*)"metall");
}
else if (self->thudsurf & SURF_SNOW)
{
strcat((char*)&Temp[0], (char*)"tin");
}
else if (self->thudsurf & SURF_TILE)
{
strcat((char*)&Temp[0], (char*)"marble");
}
else if (self->thudsurf & SURF_WOOD)
{
strcat((char*)&Temp[0], (char*)"wood");
}
else
{
strcat((char*)&Temp[0], (char*)"pavement");
}
if (self->thudsnd == 1)
{
strcat((char*)&Temp[0], (char*)"d1.wav");
gi.positioned_sound (self->s.origin, self, CHAN_VOICE|CHAN_RELIABLE, gi.soundindex((char*)&Temp[0]),
1.0, ATTN_NORM, 0);
}
else
{
strcat((char*)&Temp[0], (char*)"d2.wav");
gi.positioned_sound (self->s.origin, self, CHAN_VOICE|CHAN_RELIABLE, gi.soundindex((char*)&Temp[0]),
1.0, ATTN_NORM, 0);
}
self->nextthink = level.time + (0.1*20.0);
self->think = G_FreeEdict;
}
// END JOSEPH
// JOSEPH 11-JUN-99-B
void bitch_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point, int mdx_part, int mdx_subobject)
{
trace_t tr;
vec3_t end;
edict_t *playthud1, *playthud2;
// self->s.modelindex2 = 0;
// regular death
self->takedamage = DAMAGE_YES;
if (DeathByGib(self, inflictor, attacker, damage))
{ // gib
self->deadflag = DEAD_DEAD;
GibEntity( self, inflictor, damage );
self->s.model_parts[PART_GUN].invisible_objects = (1<<0 | 1<<1);
return;
}
if (self->deadflag == DEAD_DEAD)
return;
self->deadflag = DEAD_DEAD;
if (!(self->cast_info.aiflags & AI_MELEE))
SpawnTheWeapon (self, "weapon_pistol_e");
// EP_SpecialEventDeath (self);
VectorCopy (self->s.origin, end);
end[2] -= 64;
tr = gi.trace (self->s.origin, self->mins, self->maxs, end, self, MASK_SHOT);
if (self->maxs[2] < self->cast_info.standing_max_z)
{
if ((rand()%100) > 50)
{
self->cast_info.currentmove = &bitch4_move_crch_dth1;
playthud1 = G_Spawn();
VectorCopy (self->s.origin, playthud1->s.origin);
playthud1->thudsurf = tr.surface->flags;
playthud1->thudsnd = 1;
playthud1->nextthink = level.time + (0.1*6.0);
playthud1->think = think_playthud_bitch;
gi.linkentity (playthud1);
playthud2 = G_Spawn();
VectorCopy (self->s.origin, playthud2->s.origin);
playthud2->thudsurf = tr.surface->flags;
playthud2->thudsnd = 2;
playthud2->nextthink = level.time + (0.1*9.0);
playthud2->think = think_playthud_bitch;
gi.linkentity (playthud2);
}
else if ((rand()%100) > 50)
{
self->cast_info.currentmove = &bitch4_move_crch_dth2;
playthud1 = G_Spawn();
VectorCopy (self->s.origin, playthud1->s.origin);
playthud1->thudsurf = tr.surface->flags;
playthud1->thudsnd = 1;
playthud1->nextthink = level.time + (0.1*7.0);
playthud1->think = think_playthud_bitch;
gi.linkentity (playthud1);
playthud2 = G_Spawn();
VectorCopy (self->s.origin, playthud2->s.origin);
playthud2->thudsurf = tr.surface->flags;
playthud2->thudsnd = 2;
playthud2->nextthink = level.time + (0.1*11.0);
playthud2->think = think_playthud_bitch;
gi.linkentity (playthud2);
}
else
{
self->cast_info.currentmove = &bitch4_move_crch_dth4;
playthud1 = G_Spawn();
VectorCopy (self->s.origin, playthud1->s.origin);
playthud1->thudsurf = tr.surface->flags;
playthud1->thudsnd = 1;
playthud1->nextthink = level.time + (0.1*6.0);
playthud1->think = think_playthud_bitch;
gi.linkentity (playthud1);
playthud2 = G_Spawn();
VectorCopy (self->s.origin, playthud2->s.origin);
playthud2->thudsurf = tr.surface->flags;
playthud2->thudsnd = 2;
playthud2->nextthink = level.time + (0.1*20.0);
playthud2->think = think_playthud_bitch;
gi.linkentity (playthud2);
}
// !!! TODO: use all 4 crouching deaths (which ones are played when?)
}
else if (mdx_part == PART_HEAD)
{
self->cast_info.currentmove = &bitch_move_death5;
playthud1 = G_Spawn();
VectorCopy (self->s.origin, playthud1->s.origin);
playthud1->thudsurf = tr.surface->flags;
playthud1->thudsnd = 1;
playthud1->nextthink = level.time + (0.1*7.0);
playthud1->think = think_playthud_bitch;
gi.linkentity (playthud1);
playthud2 = G_Spawn();
VectorCopy (self->s.origin, playthud2->s.origin);
playthud2->thudsurf = tr.surface->flags;
playthud2->thudsnd = 2;
playthud2->nextthink = level.time + (0.1*18.0);
playthud2->think = think_playthud_bitch;
gi.linkentity (playthud2);
}
//else if (self->maxs[2] < self->cast_info.standing_max_z)
//{
// self->cast_info.currentmove = &bitch_move_crch_dth;
//}
else
{
int n;
n = rand() % 5;
if (n == 0)
{
self->cast_info.currentmove = &bitch_move_death1;
playthud1 = G_Spawn();
VectorCopy (self->s.origin, playthud1->s.origin);
playthud1->thudsurf = tr.surface->flags;
playthud1->thudsnd = 1;
playthud1->nextthink = level.time + (0.1*7.0);
playthud1->think = think_playthud_bitch;
gi.linkentity (playthud1);
playthud2 = G_Spawn();
VectorCopy (self->s.origin, playthud2->s.origin);
playthud2->thudsurf = tr.surface->flags;
playthud2->thudsnd = 2;
playthud2->nextthink = level.time + (0.1*11.0);
playthud2->think = think_playthud_bitch;
gi.linkentity (playthud2);
}
else if (n == 1)
{
self->cast_info.currentmove = &bitch_move_death2;
playthud1 = G_Spawn();
VectorCopy (self->s.origin, playthud1->s.origin);
playthud1->thudsurf = tr.surface->flags;
playthud1->thudsnd = 1;
playthud1->nextthink = level.time + (0.1*6.0);
playthud1->think = think_playthud_bitch;
gi.linkentity (playthud1);
playthud2 = G_Spawn();
VectorCopy (self->s.origin, playthud2->s.origin);
playthud2->thudsurf = tr.surface->flags;
playthud2->thudsnd = 2;
playthud2->nextthink = level.time + (0.1*8.0);
playthud2->think = think_playthud_bitch;
gi.linkentity (playthud2);
}
else if (n == 2)
{
self->cast_info.currentmove = &bitch_move_death3;
playthud2 = G_Spawn();
VectorCopy (self->s.origin, playthud2->s.origin);
playthud2->thudsurf = tr.surface->flags;
playthud2->thudsnd = 2;
playthud2->nextthink = level.time + (0.1*6.0);
playthud2->think = think_playthud_bitch;
gi.linkentity (playthud2);
playthud2 = G_Spawn();
VectorCopy (self->s.origin, playthud2->s.origin);
playthud2->thudsurf = tr.surface->flags;
playthud2->thudsnd = 2;
playthud2->nextthink = level.time + (0.1*9.0);
playthud2->think = think_playthud_bitch;
gi.linkentity (playthud2);
}
else if (n == 3)
{
self->cast_info.currentmove = &bitch_move_death4;
playthud1 = G_Spawn();
VectorCopy (self->s.origin, playthud1->s.origin);
playthud1->thudsurf = tr.surface->flags;
playthud1->thudsnd = 1;
playthud1->nextthink = level.time + (0.1*7.0);
playthud1->think = think_playthud_bitch;
gi.linkentity (playthud1);
playthud2 = G_Spawn();
VectorCopy (self->s.origin, playthud2->s.origin);
playthud2->thudsurf = tr.surface->flags;
playthud2->thudsnd = 2;
playthud2->nextthink = level.time + (0.1*15.0);
playthud2->think = think_playthud_bitch;
gi.linkentity (playthud2);
}
else
{
self->cast_info.currentmove = &bitch_move_death5;
playthud1 = G_Spawn();
VectorCopy (self->s.origin, playthud1->s.origin);
playthud1->thudsurf = tr.surface->flags;
playthud1->thudsnd = 1;
playthud1->nextthink = level.time + (0.1*7.0);
playthud1->think = think_playthud_bitch;
gi.linkentity (playthud1);
playthud2 = G_Spawn();
VectorCopy (self->s.origin, playthud2->s.origin);
playthud2->thudsurf = tr.surface->flags;
playthud2->thudsnd = 2;
playthud2->nextthink = level.time + (0.1*18.0);
playthud2->think = think_playthud_bitch;
gi.linkentity (playthud2);
}
}
// gi.sound (self, CHAN_VOICE, gi.soundindex(va("*death%i.wav", (rand()%4)+1)), 1, ATTN_NORM, 0);
if (!self->onfiretime)
Voice_Random (self, attacker, &female_specific[4], 2);
// RAFAEL 01-25-99
self->s.model_parts[PART_GUN].invisible_objects = (1<<0 | 1<<1);
}
// END JOSEPH
void bitch_pain (edict_t *self, edict_t *other, float kick, int damage, int mdx_part, int mdx_subobject)
{
int orientation;
AI_CheckMakeEnemy( self, other );
if (level.time < self->pain_debounce_time)
return;
self->pain_debounce_time = level.time + 3 + random();
if (skill->value >= 3)
return; // no pain anims in nightmare
/*
if (rand() % 100 > 50)
gi.sound (self, CHAN_VOICE, gi.soundindex("actors/bitch/pain1.wav"), 1, ATTN_NORM, 0);
else
gi.sound (self, CHAN_VOICE, gi.soundindex("actors/bitch/pain2.wav"), 1, ATTN_NORM, 0);
*/
if (self->health < 25)
Voice_Specific (self, other, female_specific, 4);
else if (self->health < 50)
Voice_Specific (self, other, female_specific, 3);
else if (self->health < 75)
Voice_Specific (self, other, female_specific, 2);
else
Voice_Specific (self, other, female_specific, 1);
// Ridah, randomly don't play an animation, since it' leaves them WAY open to be killed
if (skill->value > 0 && rand()%2)
return;
if (self->maxs[2] < self->cast_info.standing_max_z)
{
self->cast_info.currentmove = &bitch_move_p_pain_crch;
return;
}
if (other->client || (other->svflags & SVF_MONSTER))
{
orientation = AI_GetOrientation( self, other );
}
else
{
orientation = ORIENTATION_CENTER;
}
if ( (mdx_part == PART_BODY)
|| (other->client && other->client->pers.weapon && !(other->client->pers.weapon->ammo) && (orientation = rand()%2+1)))
{
int rnd;
rnd = rand () % 2;
switch (orientation)
{
case ORIENTATION_CENTER :
{
self->cast_info.currentmove = &bitch_move_p_pain_chst;
break;
}
case ORIENTATION_LEFT :
{
if (rnd)
self->cast_info.currentmove = &bitch_move_p_pain_lshd;
else
self->cast_info.currentmove = &bitch_move_p_pain_lshd2;
break;
}
case ORIENTATION_RIGHT :
{
if (rnd)
self->cast_info.currentmove = &bitch_move_p_pain_rshd;
else
self->cast_info.currentmove = &bitch_move_p_pain_rshd2;
break;
}
}
}
else if (mdx_part == PART_LEGS)
{
int rnd;
switch (orientation)
{
case ORIENTATION_CENTER :
{
rnd = rand() % 2;
if (infront(self, other))
{
if (rnd == 1)
self->cast_info.currentmove = &bitch_move_p_pain_crch;
else
self->cast_info.currentmove = &bitch_move_p_pain_crch2;
}
else
{
if (rnd == 2)
self->cast_info.currentmove = &bitch_move_p_pain_butt;
else
self->cast_info.currentmove = &bitch_move_p_pain_butt2;
}
break;
}
case ORIENTATION_LEFT :
{
rnd = rand() * 2;
if (rnd)
self->cast_info.currentmove = &bitch_move_p_pain_lleg;
else
self->cast_info.currentmove = &bitch_move_p_pain_lleg2;
break;
}
case ORIENTATION_RIGHT :
{
rnd = rand() * 2;
if (rnd)
self->cast_info.currentmove = &bitch_move_p_pain_rleg;
else
self->cast_info.currentmove = &bitch_move_p_pain_rleg2;
break;
}
}
}
else if (mdx_part == PART_HEAD)
{
self->cast_info.currentmove = &bitch_move_p_pain_head2;
}
// else
// gi.dprintf ("what the fuck\n");
}
// =========================================================================
/*QUAKED cast_bitch (1 .5 0) (-16 -16 -24) (16 16 48) x TRIGGERED_START x x x IMMEDIATE_FOLLOW_PATH MELEE NOSHADOW
cast_group 0 neutral
cast_group 1 friendly
cast_group 2 or greater enemy
bitch with the pistol
head 1 = bald 2 = pony tail 0 or anything else is default
model="models\actors\bitch\"
*/
void SP_cast_bitch(edict_t *self)
{
int i;
char *head_skin, *body_skin, *legs_skin;
int skin;
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, 48);
self->s.skinnum = (self->skin-1) * 3;
if (self->art_skins)
{
// convert spaces to NULL's
for (i=0; i<11; i++)
if (self->art_skins[i] == ' ')
self->art_skins[i] = '\0';
head_skin = &self->art_skins[0];
body_skin = &self->art_skins[4];
legs_skin = &self->art_skins[8];
}
else
{
head_skin = body_skin = legs_skin = NULL;
}
// ------------------------------------------------------------------------
// initialize all model_part data
memset(&(self->s.model_parts[0]), 0, sizeof(model_part_t) * MAX_MODEL_PARTS);
self->s.num_parts++;
switch (self->head)
{
case 1:
self->s.model_parts[PART_HEAD].modelindex = gi.modelindex("models/actors/bitch/bald_head.mdx");
break;
case 2:
self->s.model_parts[PART_HEAD].modelindex = gi.modelindex("models/actors/bitch/pony_head.mdx");
break;
default:
self->s.model_parts[PART_HEAD].modelindex = gi.modelindex("models/actors/bitch/head.mdx");
break;
}
if (head_skin)
{
skin = gi.skinindex( self->s.model_parts[PART_HEAD].modelindex, head_skin );
}
else
skin = self->s.skinnum;
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
self->s.model_parts[PART_HEAD].baseskin = self->s.model_parts[PART_HEAD].skinnum[i] = skin;
gi.GetObjectBounds( "models/actors/bitch/head.mdx", &self->s.model_parts[PART_HEAD] );
self->s.num_parts++;
self->s.model_parts[PART_LEGS].modelindex = gi.modelindex("models/actors/bitch/legs.mdx");
if (head_skin)
skin = gi.skinindex( self->s.model_parts[PART_LEGS].modelindex, legs_skin );
else
skin = self->s.skinnum;
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
self->s.model_parts[PART_LEGS].baseskin = self->s.model_parts[PART_LEGS].skinnum[i] = skin;
gi.GetObjectBounds( "models/actors/bitch/legs.mdx", &self->s.model_parts[PART_LEGS] );
self->s.num_parts++;
self->s.model_parts[PART_BODY].modelindex = gi.modelindex("models/actors/bitch/body.mdx");
if (head_skin)
skin = gi.skinindex( self->s.model_parts[PART_BODY].modelindex, body_skin );
else
skin = self->s.skinnum;
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
self->s.model_parts[PART_BODY].baseskin = self->s.model_parts[PART_BODY].skinnum[i] = skin;
gi.GetObjectBounds( "models/actors/bitch/body.mdx", &self->s.model_parts[PART_BODY] );
if (self->spawnflags & BITCH_MELEE)
{
self->s.num_parts++;
self->s.model_parts[PART_GUN].modelindex = gi.modelindex("models/actors/bitch/pipe.mdx");
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
self->s.model_parts[PART_GUN].baseskin = self->s.model_parts[PART_GUN].skinnum[i] = 0; // self->s.skinnum;
gi.GetObjectBounds( "models/actors/bitch/pipe.mdx", &self->s.model_parts[PART_GUN] );
self->cast_info.aiflags |= AI_MELEE;
}
else
{
self->s.num_parts++;
self->s.model_parts[PART_GUN].modelindex = gi.modelindex("models/actors/bitch/gun.mdx");
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
self->s.model_parts[PART_GUN].baseskin = self->s.model_parts[PART_GUN].skinnum[i] = 0;// self->s.skinnum;
gi.GetObjectBounds( "models/actors/bitch/gun.mdx", &self->s.model_parts[PART_GUN] );
self->s.model_parts[PART_GUN].invisible_objects = (1<<0 | 1<<1);
}
// remove NULL's
if (self->art_skins)
self->art_skins[3] = self->art_skins[7] = ' ';
// ------------------------------------------------------------------------
if (!self->health)
self->health = 100;
self->gib_health = -200;
self->mass = 200;
self->gender = GENDER_FEMALE;
self->pain = bitch_pain;
self->die = bitch_die;
self->cast_info.checkattack = AI_CheckAttack;
self->cast_info.attack = bitch_attack;
self->cast_info.long_attack = bitch_long_attack;
self->cast_info.talk = bitch_talk;
self->cast_info.avoid = bitch_avoid;
self->cast_info.backoff = bitch_backoff;
self->cast_info.catch_fire = bitch_catch_fire;
self->cast_info.max_attack_distance = 2000;
self->cast_info.move_stand = &bitch_move_boredA; // ok
self->cast_info.move_crstand = &bitch4_move_crch_amb_std;
self->cast_info.move_run = &bitch_move_run_guns_dn; // ok
self->cast_info.move_runwalk = &bitch_move_walk_guns_dn; // ok
self->cast_info.move_crwalk = &bitch4_move_crch_walk;
self->cast_info.move_jump = &bitch4_move_jump;
// Betty walks away from you since she doesn't want to start any trouble
if (self->name && !stricmp( self->name, "Betty"))
self->cast_info.move_avoid_walk = &bitch_move_evd_walk;
else
self->cast_info.move_avoid_walk = &bitch_move_avoid_walk;
self->cast_info.move_avoid_run = &bitch_move_avoid_run;
self->cast_info.move_avoid_reverse_walk = &bitch_move_avoid_reverse_walk;
self->cast_info.move_avoid_reverse_run = &bitch_move_avoid_reverse_run;
//self->cast_info.move_avoid_crwalk = &bitch_move_crouch_avoid_walk;
self->cast_info.move_crouch_down = &bitch4_move_crch_knl_dn;
self->cast_info.move_stand_up = &bitch4_move_stand_up;
self->cast_info.move_lside_step = &bitch4_move_lside_step;
self->cast_info.move_rside_step = &bitch4_move_rside_step;
self->cast_info.move_start_climb = &bitch4_move_clmb_loop;
self->cast_info.move_end_climb = &bitch4_move_clmb_jmp;
//self->cast_info.move_end_climb = NULL;
self->cast_info.move_evade = &bitch_move_evd_walk;
self->cast_info.move_stand_evade = &bitch_move_evd_stand;
gi.linkentity (self);
self->cast_info.currentmove = self->cast_info.move_stand;
if (!self->cast_info.scale)
self->cast_info.scale = MODEL_SCALE;
self->s.scale = self->cast_info.scale - 1.0;
walking_cast_start (self);
// HACK THE BITCHES TO SEASONED
/*
if (!self->acc)
self->acc = ACC_NORMAL;
*/
if (!self->acc)
self->acc = 2;
// talk by default
self->cast_info.aiflags |= AI_TALK;
if (!self->cal) // weapon calibur
self->cal = 3;
if (self->spawnflags & 128)
self->s.renderfx2 |= RF2_NOSHADOW;
}