djcev.com

//

Git Repos / fte_dogmode / qc / monsters / wizard.qc

Last update to this file was on 2024-04-12 at 18:56.

Show wizard.qc

//==============================================================================
// WIZARD
//==============================================================================

//======================================================================
// constants
//======================================================================

const float WIZARD_HEALTH = 80; // id1 80

const vector WIZARD_HEAD_MINS = '-10.41 -8.66 -0.54';
const vector WIZARD_HEAD_MAXS = '6.52 10.82 30';

//======================================================================
// forward declarations
//======================================================================

// monster_wizard
// void() monster_wizard_attack_ranged; // AI & attacks
void() monster_wizard_attackfinished;
void() monster_wizard_sightsound;
void() monster_wizard_attacksound;
void() monster_wizard_idlesound;
float() monster_wizard_checkattack; // animation & thinking below
void() wiz_stand1; void() wiz_stand2; void() wiz_stand3; void() wiz_stand4;
void() wiz_stand5; void() wiz_stand6; void() wiz_stand7; void() wiz_stand8;
void() wiz_walk1; void() wiz_walk2; void() wiz_walk3; void() wiz_walk4;
void() wiz_walk5; void() wiz_walk6; void() wiz_walk7; void() wiz_walk8;
void() wiz_side1; void() wiz_side2; void() wiz_side3; void() wiz_side4;
void() wiz_side5; void() wiz_side6; void() wiz_side7; void() wiz_side8;
void() wiz_run1; void() wiz_run2; void() wiz_run3; void() wiz_run4;
void() wiz_run5; void() wiz_run6; void() wiz_run7; void() wiz_run8;
void() wiz_run9; void() wiz_run10; void() wiz_run11; void() wiz_run12;
void() wiz_run13; void() wiz_run14;
void() wiz_fast1; void() wiz_fast2; void() wiz_fast3; void() wiz_fast4;
void() wiz_fast5; void() wiz_fast6; void() wiz_fast7; void() wiz_fast8;
void() wiz_fast9; void() wiz_fast10;
void() wiz_pain1; void() wiz_pain2; void() wiz_pain3; void() wiz_pain4;
void() wiz_death1; void() wiz_death2; void() wiz_death3; void() wiz_death4;
void() wiz_death5; void() wiz_death6; void() wiz_death7; void() wiz_death8;
void(entity attacker, float damage) monster_wizard_pain; // interaction
void(vector dir) monster_wizard_destroy;
void(entity e) monster_wizard_init; // initialization
void() monster_wizard;

// gib_head_wizard
void(entity act, vector dir, float dmg) throw_gib_head_wizard;
void(entity e) gib_head_wizard_init;
void() gib_head_wizard;

// monster_dead_wizard
void() monster_dead_wizard;

//======================================================================
// frame macros
//======================================================================

$cd id1/models/a_wizard
$origin 0 0 24
$base wizbase
$skin wizbase

$frame hover1 hover2 hover3 hover4 hover5 hover6 hover7 hover8
$frame hover9 hover10 hover11 hover12 hover13 hover14 hover15

$frame fly1 fly2 fly3 fly4 fly5 fly6 fly7 fly8 fly9 fly10
$frame fly11 fly12 fly13 fly14

$frame magatt1 magatt2 magatt3 magatt4 magatt5 magatt6 magatt7
$frame magatt8 magatt9 magatt10 magatt11 magatt12 magatt13

$frame pain1 pain2 pain3 pain4

$frame death1 death2 death3 death4 death5 death6 death7 death8

//------------------------------------------------------------------------------

/*QUAKED monster_wizard (1 0 0) (-16 -16 -24) (16 16 40) AMBUSH X X TRIGGER_SPAWNED X X X X NOT_ON_EASY NOT_ON_NORMAL NOT_ON_HARD_OR_NIGHTMARE NOT_IN_DEATHMATCH NOT_IN_COOP NOT_IN_SINGLEPLAYER X NOT_ON_HARD_ONLY NOT_ON_NIGHTMARE_ONLY
{
model ("progs/wizard.mdl");
}
Wizard a.k.a. Scrag.

Default health = 80

snd_death(string) : "Path to custom death sound"
snd_pain(string) : "Path to custom pain sound"
snd_sight(string) : "Path to custom sight sound"
snd_attack(string) : "Path to custom attack sound"
snd_idle(string) : "Path to custom idle sound"
snd_misc(string) : "Path to custom sound (IDLE 2)"

mdl_head(string) : "Path to custom head model"
mdl_body(string) : "Path to custom body model"
skin_head(float) : "Skin index of custom head model"
mdl_gib1(string) : "Path to custom 1st gib model"
mdl_gib2(string) : "Path to custom 2nd gib model"
mdl_gib3(string) : "Path to custom 3rd gib model"

effects(choices) : "Add a visual effect to an entity"
0 : "None (Default)"
1 : "Brightfield (yellow particles)"
4 : "Bright light"
8 : "Dim light"

berserk(choices) "Skips certain pain animations similar to skill 3 (Makes a semi-nightmare monster!)"
0 : "Off (Default)"
1 : "Berserk (skip pain animations)"

delay(float) : "Delay spawn in for this amount of time"

wait(choices) : "Play an effect when trigger spawned?"
0 : "Teleport Effects (Default)"
1 : "Spawn Silently"

spawn_angry(Choices)
0 : "Only when trigger spawned, default behavior - not angry"
1 : "Only when trigger spawned, set to 1 to spawn angry at player"

infight_mode(Choices)
0 : "Default behavior, only with different classnames"
1 : "Infight with monsters with the same classname but a different mdl_body"
2 : "Infight with monsters with the same classname and model but a different skin"
3 : "Infight no matter what"

projexpl(choices) : "Exploding projectiles"
0 : "No explosions"
1 : "All projectiles explode"

health(integer) : "Set this to a custom health amount"
pain_target(string) : "Fire this target when pain_threshold is reached"
pain_threshold(integer) : "Fire pain_target when health drops below this amount"
sight_trigger(integer) : "1 = Fire target upon seeing the player instead of death"
skin(integer) : "Skin index (default 0) Use this when your custom model has more than one skin to select"
obit_name(string) : "When used with obit_method, this will set part of the text for a custom obituary. e.g. a Super Soldier! Using the examples here, the obituary would read: Player was eviscerated by a Super Solider!"
obit_method(string) : "When used with obit_name, will set part of the text for a custom obituary. e.g. eviscerated - If empty, defaults to killed."
damage_mod(float) : "USE WITH CAUTION! Multiply all damage from this monster by this number (e.g. 4 = Quad damage)"

*/
//----------------------------------------------------------------------
// class monster_wizard: base_flymonster
// {
/*
void() monster_wizard_attack_ranged =
{
base_monster_fire_wizardspell ();
};
*/

//--------------------------------------------------------------
// WizardAttackFinished
//--------------------------------------------------------------
void() monster_wizard_attackfinished =
{
if (enemy_range >= RANGE_MID || !enemy_vis)
{
self.attack_state = AS_STRAIGHT;
self.think = wiz_run1;
}
else
{
self.attack_state = AS_SLIDING;
self.think = wiz_side1;
}
};

//--------------------------------------------------------------
void() monster_wizard_sightsound =
{
sound_sight (self, CHAN_VOICE, "wizard/wsight.wav",
1, ATTN_NORM);
};

//--------------------------------------------------------------
// Wiz_AttackSound
//--------------------------------------------------------------
void() monster_wizard_attacksound =
{
// this is a hack to fix Wizard custom attack sounds
sound_attack (self, CHAN_AUTO, "wizard/wattack.wav",
1, ATTN_NORM);
};

//--------------------------------------------------------------
// WizardIdleSound
//--------------------------------------------------------------
void() monster_wizard_idlesound =
{
local float wr = random() * 5;

if (self.fly_sound < time)
{
self.fly_sound = time + 2;
if (wr > 4.5)
sound_idle (self, CHAN_VOICE,
"wizard/widle1.wav", 1, ATTN_IDLE);
if (wr < 1.5)
sound_misc (self, CHAN_VOICE,
"wizard/widle2.wav", 1, ATTN_IDLE);
}
return;
};

//--------------------------------------------------------------
// WizardCheckAttack
//--------------------------------------------------------------
float() monster_wizard_checkattack =
{
local vector spot1, spot2;
local entity targ;
local float chance;

if (time < self.attack_finished)
return FALSE;
if (!enemy_vis)
return FALSE;

if (enemy_range == RANGE_FAR)
{
if (self.attack_state != AS_STRAIGHT)
{
self.attack_state = AS_STRAIGHT;
wiz_run1 ();
}
return FALSE;
}

targ = self.enemy;

// see if any entities are in the way of the shot
spot1 = self.origin + self.view_ofs;
spot2 = targ.origin + targ.view_ofs;

traceline (spot1, spot2, FALSE, self);

if (trace_ent != targ)
{ // don't have a clear shot, so move to a side
if (self.attack_state != AS_STRAIGHT)
{
self.attack_state = AS_STRAIGHT;
wiz_run1 ();
}
return FALSE;
}

if (enemy_range == RANGE_MELEE)
chance = 0.9;
else if (enemy_range == RANGE_NEAR)
chance = 0.6;
else if (enemy_range == RANGE_MID)
chance = 0.2;
else
chance = 0;

if (random () < chance)
{
self.attack_state = AS_MISSILE;
return TRUE;
}

if (enemy_range == RANGE_MID)
{
if (self.attack_state != AS_STRAIGHT)
{
self.attack_state = AS_STRAIGHT;
wiz_run1 ();
}
}
else
{
if (self.attack_state != AS_SLIDING)
{
self.attack_state = AS_SLIDING;
wiz_side1 ();
}
}

return FALSE;
};

//--------------------------------------------------------------
// Stationary wizard (?)
//--------------------------------------------------------------
void() wiz_stand1 = [$hover1, wiz_stand2] { ai_stand (); };
void() wiz_stand2 = [$hover2, wiz_stand3] { ai_stand (); };
void() wiz_stand3 = [$hover3, wiz_stand4] { ai_stand (); };
void() wiz_stand4 = [$hover4, wiz_stand5] { ai_stand (); };
void() wiz_stand5 = [$hover5, wiz_stand6] { ai_stand (); };
void() wiz_stand6 = [$hover6, wiz_stand7] { ai_stand (); };
void() wiz_stand7 = [$hover7, wiz_stand8] { ai_stand (); };
void() wiz_stand8 = [$hover8, wiz_stand1] { ai_stand (); };

//--------------------------------------------------------------
// Can a Wizard walk?
//--------------------------------------------------------------
void() wiz_walk1 = [$hover1, wiz_walk2]
{
ai_walk (8);
monster_wizard_idlesound ();
};
void() wiz_walk2 = [$hover2, wiz_walk3] { ai_walk (8); };
void() wiz_walk3 = [$hover3, wiz_walk4] { ai_walk (8); };
void() wiz_walk4 = [$hover4, wiz_walk5] { ai_walk (8); };
void() wiz_walk5 = [$hover5, wiz_walk6] { ai_walk (8); };
void() wiz_walk6 = [$hover6, wiz_walk7] { ai_walk (8); };
void() wiz_walk7 = [$hover7, wiz_walk8] { ai_walk (8); };
void() wiz_walk8 = [$hover8, wiz_walk1] { ai_walk (8); };

//--------------------------------------------------------------
// Wizards _can_ move side-to-side...
//--------------------------------------------------------------
void() wiz_side1 = [$hover1, wiz_side2]
{
ai_run (8);
monster_wizard_idlesound ();
};
void() wiz_side2 = [$hover2, wiz_side3] { ai_run (8); };
void() wiz_side3 = [$hover3, wiz_side4] { ai_run (8); };
void() wiz_side4 = [$hover4, wiz_side5] { ai_run (8); };
void() wiz_side5 = [$hover5, wiz_side6] { ai_run (8); };
void() wiz_side6 = [$hover6, wiz_side7] { ai_run (8); };
void() wiz_side7 = [$hover7, wiz_side8] { ai_run (8); };
void() wiz_side8 = [$hover8, wiz_side1] { ai_run (8); };

//--------------------------------------------------------------
// Wizard workout
//--------------------------------------------------------------
void() wiz_run1 = [$fly1, wiz_run2]
{
ai_run (16);
monster_wizard_idlesound ();
};
void() wiz_run2 = [$fly2, wiz_run3] { ai_run (16); };
void() wiz_run3 = [$fly3, wiz_run4] { ai_run (16); };
void() wiz_run4 = [$fly4, wiz_run5] { ai_run (16); };
void() wiz_run5 = [$fly5, wiz_run6] { ai_run (16); };
void() wiz_run6 = [$fly6, wiz_run7] { ai_run (16); };
void() wiz_run7 = [$fly7, wiz_run8] { ai_run (16); };
void() wiz_run8 = [$fly8, wiz_run9] { ai_run (16); };
void() wiz_run9 = [$fly9, wiz_run10] { ai_run (16); };
void() wiz_run10 = [$fly10, wiz_run11] { ai_run (16); };
void() wiz_run11 = [$fly11, wiz_run12] { ai_run (16); };
void() wiz_run12 = [$fly12, wiz_run13] { ai_run (16); };
void() wiz_run13 = [$fly13, wiz_run14] { ai_run (16); };
void() wiz_run14 = [$fly14, wiz_run1] { ai_run (16); };

//--------------------------------------------------------------
// ~Fast~ Wizards
//--------------------------------------------------------------
void() wiz_fast1 = [$magatt1, wiz_fast2]
{
ai_face ();
base_monster_fire_wizardspell ();
monster_wizard_attacksound ();
};
void() wiz_fast2 = [$magatt2, wiz_fast3] { ai_face (); };
void() wiz_fast3 = [$magatt3, wiz_fast4] { ai_face (); };
void() wiz_fast4 = [$magatt4, wiz_fast5] { ai_face (); };
void() wiz_fast5 = [$magatt5, wiz_fast6] { ai_face (); };
void() wiz_fast6 = [$magatt6, wiz_fast7] { ai_face (); };
void() wiz_fast7 = [$magatt5, wiz_fast8]
{
ai_face ();
monster_wizard_attacksound ();
};
void() wiz_fast8 = [$magatt4, wiz_fast9] { ai_face (); };
void() wiz_fast9 = [$magatt3, wiz_fast10] { ai_face (); };
void() wiz_fast10 = [$magatt2, wiz_run1]
{
ai_face ();
sub_attackfinished (2);
monster_wizard_attackfinished ();
};

//--------------------------------------------------------------
// Wizard Pain State
//--------------------------------------------------------------
void() wiz_pain1 = [$pain1, wiz_pain2] { };
void() wiz_pain2 = [$pain2, wiz_pain3] { };
void() wiz_pain3 = [$pain3, wiz_pain4] { };
void() wiz_pain4 = [$pain4, wiz_run1] { };

//--------------------------------------------------------------
// Wizard Death State
//--------------------------------------------------------------
void() wiz_death1 = [$death1, wiz_death2]
{
self.velocity_x = -200 + 400 * random ();
self.velocity_y = -200 + 400 * random ();
self.velocity_z = 100 + 100 * random ();
self.flags = self.flags - (self.flags & FL_ONGROUND);
sound_death (self, CHAN_VOICE, "wizard/wdeath.wav",
1, ATTN_NORM);
};
void() wiz_death2 = [$death2, wiz_death3] { };
void() wiz_death3 = [$death3, wiz_death4] { self.solid = SOLID_NOT; };
void() wiz_death4 = [$death4, wiz_death5] { };
void() wiz_death5 = [$death5, wiz_death6] { };
void() wiz_death6 = [$death6, wiz_death7] { };
void() wiz_death7 = [$death7, wiz_death8] { };
void() wiz_death8 = [$death8, wiz_death8] { };

//==============================================================
// Interaction
//==============================================================

//--------------------------------------------------------------
// Wiz_Pain
//--------------------------------------------------------------
void(entity attacker, float damage) monster_wizard_pain =
{
sound_pain (self, CHAN_VOICE, "wizard/wpain.wav",
1, ATTN_NORM);

if (random() * 70 > damage)
// didn't flinch
return;

wiz_pain1 ();
};

//--------------------------------------------------------------
// wiz_die
//--------------------------------------------------------------
void(vector dir) monster_wizard_destroy =
{
// check for gib
if (self.health < -40)
{
sound (self, CHAN_VOICE, "player/udeath.wav",
1, ATTN_NORM);

throw_gib_head_wizard (self, dir, self.health);

// custom models -- dumptruck_ds
if (self.mdl_gib1 != "")
throw_gib_1 (self, dir, self.health);
else
throw_gib_2 (self, dir, self.health);

if (self.mdl_gib2 != "")
throw_gib_2 (self, dir, self.health);
else
throw_gib_2 (self, dir, self.health);

if (self.mdl_gib3 != "")
throw_gib_3 (self, dir, self.health);
else
throw_gib_2 (self, dir, self.health);

base_item_drop_stuff (self);
return;
}

base_item_drop_stuff (self);
wiz_death1 ();
};

//==============================================================
// Initialization
//==============================================================

//--------------------------------------------------------------
void(entity e) monster_wizard_init =
{
if (e.spawnflags & I_AM_TURRET)
objerror("Incompatible spawnflag: TURRET_MODE\n");

if (deathmatch)
{
remove (e);
return;
}

e.classname = "monster_wizard";
e.classtype = CT_MONSTER_SCRAG;

if (!e.mdl_proj)
e.mdl_proj = "progs/w_spike.mdl";

// dumptruck_ds custom_mdls
precache_body_model (e, "progs/wizard.mdl");
precache_head_model (e, "progs/h_wizard.mdl");
precache_proj_model (e, "progs/w_spike.mdl");
// dumptruck_ds
// wizard/hit used by c code
precache_sound_hit (e, "wizard/hit.wav");
precache_sound_attack (e, "wizard/wattack.wav");
precache_sound_death (e, "wizard/wdeath.wav");
precache_sound_idle (e, "wizard/widle1.wav");
precache_sound_misc (e, "wizard/widle2.wav");
precache_sound_pain (e, "wizard/wpain.wav");
precache_sound_sight (e, "wizard/wsight.wav");

precache_gib1 (e, "progs/gib1.mdl");
precache_gib2 (e, "progs/gib2.mdl");
precache_gib3 (e, "progs/gib3.mdl");

e.solid = SOLID_SLIDEBOX;
e.movetype = MOVETYPE_STEP;

body_model (e, "progs/wizard.mdl");
// setmodel (e, "progs/wizard.mdl"); //dumptruck_ds

setsize (e, '-16 -16 -24', '16 16 40');

if (!e.proj_speed_mod)
e.proj_speed_mod = 1;

if (!e.health)
// thanks RennyC -- dumptruck_ds
e.health = WIZARD_HEALTH;

e.checkattack = monster_wizard_checkattack;
e.sightsound = monster_wizard_sightsound;
e.think_stand = wiz_stand1;
e.think_walk = wiz_walk1;
e.think_run = wiz_run1;
e.think_missile = wiz_fast1;
// Berserk test from
// http://celephais.net/board/view_thread.php?id=4&start=3465
// -- dumptruck_ds
if !(e.berserk)
e.pain = monster_wizard_pain;
else
e.pain = sub_nullpain;
e.destroy = monster_wizard_destroy;

// flymonster_starts
base_flymonster_init (e);
};

//--------------------------------------------------------------
void() monster_wizard =
{
// new spawnflags for all entities -- iw
if (SUB_Inhibit())
return;

monster_wizard_init (self);
};
// };

//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Scenic Dead Monster Patch stuff here from DeadStuff mod -- dumptruck_ds
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

/*QUAKED gib_head_wizard (0 0.5 0.8) (-16 -16 0) (16 16 56) SOLID X X X X X X X NOT_ON_EASY NOT_ON_NORMAL NOT_ON_HARD_OR_NIGHTMARE NOT_IN_DEATHMATCH NOT_IN_COOP NOT_IN_SINGLEPLAYER X NOT_ON_HARD_ONLY NOT_ON_NIGHTMARE_ONLY
{
model ("progs/h_wizard.mdl");
}*/
//----------------------------------------------------------------------
// class gib_head_wizard: base_gib_head
// {
//--------------------------------------------------------------
// ThrowHead
//--------------------------------------------------------------
void(entity act, vector dir, float dmg) throw_gib_head_wizard =
{
base_gib_head_throw (act, dir, dmg, gib_head_wizard_init);
};

//--------------------------------------------------------------
void(entity e) gib_head_wizard_init =
{
e.classname = "gib_head_wizard";
e.classtype = CT_GORE_HEAD_WIZARD;

// gib_init interprets spawnflags and will set .solid -- CEV
base_gib_head_init (e);

if (e.mdl_head != "")
{
precache_model (e.mdl_head);
setmodel (e, e.mdl_head);
}
else
{
precache_model ("progs/h_wizard.mdl");
setmodel (e, "progs/h_wizard.mdl");
if (e.solid == SOLID_BBOX)
setsize (e, WIZARD_HEAD_MINS,
WIZARD_HEAD_MAXS);
else if (e.solid == SOLID_TRIGGER)
setsize (e, '-16 -16 0', '16 16 56');
}

e.frame = 0;
};

//--------------------------------------------------------------
void() gib_head_wizard =
{
// new spawnflags for all entities -- iw
if (SUB_Inhibit())
return;

gib_head_wizard_init (self);
};
// };

/*QUAKED monster_dead_wizard (0 0.5 0.8) (-16 -16 -24) (16 16 32) SOLID X X X X X X X NOT_ON_EASY NOT_ON_NORMAL NOT_ON_HARD_OR_NIGHTMARE NOT_IN_DEATHMATCH NOT_IN_COOP NOT_IN_SINGLEPLAYER X NOT_ON_HARD_ONLY NOT_ON_NIGHTMARE_ONLY
{
model ({"path":"progs/wizard.mdl","frame":53});
}
*/
void() monster_dead_wizard =
{
// new spawnflags for all entities -- iw
if (SUB_Inhibit())
return;

precache_model ("progs/wizard.mdl");
setmodel (self, "progs/wizard.mdl");
self.frame = $death8;

if (self.spawnflags & 1)
{
self.solid = SOLID_BBOX;
setsize (self,'-50.75 -27.46 -55.19','31.81 33.61 30');
}
else
{
self.solid = SOLID_NOT;
}
};

Return to the top of this page or return to the overview of this repo.

Log wizard.qc

Date Commit Message Author + -
2024-04-12 Moveable gibs, heads, some bugfixes cev +81 -19
2024-04-05 Player footsteps, shareware monsters, misc? cev +234 -201
2024-02-18 Client/player, projectiles, entrypoints refactor cev +8 -108
2024-01-31 Class based monster refactor & start projectiles cev +468 -417
2024-01-13 Refactored items into classes, fix teleporttrain cev +2 -2
2024-01-09 Continue OO / Class-based refactor cev +2 -2
2023-10-13 New movement code based on SV_RunClientCommand cev +580 -580
2023-10-13 Rename "qc-server" dir to "qc" cev +580  

Return to the top of this page or return to the overview of this repo.