djcev.com

//

Git Repos / fte_dogmode / qc / monsters / boss2.qc

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

Show boss2.qc

//==============================================================================
// BOSS-ONE
//==============================================================================

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

// supress lava splash effect when raising, lowering or gibbing -- dumptruck_ds
const float NO_LAVASPLASH = 2;

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

// monster_boss2
void() monster_boss2_face; // AI & firing
void(vector p) monster_boss2_missile;
void(vector dir) monster_boss2_gib; // thinking & animation below
void() boss2_idle1; void() boss2_idle2; void() boss2_idle3; void() boss2_idle4;
void() boss2_idle5; void() boss2_idle6; void() boss2_idle7; void() boss2_idle8;
void() boss2_idle9; void() boss2_idle10; void() boss2_idle11;
void() boss2_idle12; void() boss2_idle13; void() boss2_idle14;
void() boss2_idle15; void() boss2_idle16; void() boss2_idle17;
void() boss2_idle18; void() boss2_idle19; void() boss2_idle20;
void() boss2_idle21; void() boss2_idle22; void() boss2_idle23;
void() boss2_idle24; void() boss2_idle25; void() boss2_idle26;
void() boss2_idle27; void() boss2_idle28; void() boss2_idle29;
void() boss2_idle30; void() boss2_idle31;
void() boss2_rise1; void() boss2_rise2; void() boss2_rise3; void() boss2_rise4;
void() boss2_rise5; void() boss2_rise6; void() boss2_rise7; void() boss2_rise8;
void() boss2_rise9; void() boss2_rise10; void() boss2_rise11;
void() boss2_rise12; void() boss2_rise13; void() boss2_rise14;
void() boss2_rise15; void() boss2_rise16; void() boss2_rise17;
void() boss2_atk1; void() boss2_atk2; void() boss2_atk3; void() boss2_atk4;
void() boss2_atk5; void() boss2_atk6; void() boss2_atk7; void() boss2_atk8;
void() boss2_atk9; void() boss2_atk10; void() boss2_atk11; void() boss2_atk12;
void() boss2_atk13; void() boss2_atk14; void() boss2_atk15; void() boss2_atk16;
void() boss2_atk17; void() boss2_atk18; void() boss2_atk19; void() boss2_atk20;
void() boss2_atk21; void() boss2_atk22; void() boss2_atk23;
void() boss2_shocka1; void() boss2_shocka2; void() boss2_shocka3;
void() boss2_shocka4; void() boss2_shocka5; void() boss2_shocka6;
void() boss2_shocka7; void() boss2_shocka8; void() boss2_shocka9;
void() boss2_shocka10;
void() boss2_shockb1; void() boss2_shockb2; void() boss2_shockb3;
void() boss2_shockb4; void() boss2_shockb5; void() boss2_shockb6;
void() boss2_shockb7; void() boss2_shockb8; void() boss2_shockb9;
void() boss2_shockb10;
void() boss2_shockc1; void() boss2_shockc2; void() boss2_shockc3;
void() boss2_shockc4; void() boss2_shockc5; void() boss2_shockc6;
void() boss2_shockc7; void() boss2_shockc8; void() boss2_shockc9;
void() boss2_shockc10;
void() boss2_pain1; void() boss2_pain2; void() boss2_pain3; void() boss2_pain4;
void() boss2_pain5; void() boss2_pain6; void() boss2_pain7; void() boss2_pain8;
void() boss2_pain9;
void() boss2_death1; void() boss2_death2; void() boss2_death3;
void() boss2_death4; void() boss2_death5; void() boss2_death6;
void() boss2_death7; void() boss2_death8; void() boss2_death9;
void() boss2_death10;
void(entity attacker, float damage) monster_boss2_pain; // interaction
void(vector dir) monster_boss2_destroy;
void() monster_boss2_use;
void(entity e) monster_boss2_init; // initialization
void() monster_boss2;

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

$cd id1/models/boss1
$origin 0 0 -15
$base base
$skin skin
$scale 5

$frame rise1 rise2 rise3 rise4 rise5 rise6 rise7 rise8 rise9 rise10
$frame rise11 rise12 rise13 rise14 rise15 rise16 rise17

$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8
$frame walk9 walk10 walk11 walk12 walk13 walk14 walk15
$frame walk16 walk17 walk18 walk19 walk20 walk21 walk22
$frame walk23 walk24 walk25 walk26 walk27 walk28 walk29 walk30 walk31

$frame death1 death2 death3 death4 death5 death6 death7 death8 death9

$frame attack1 attack2 attack3 attack4 attack5 attack6 attack7 attack8
$frame attack9 attack10 attack11 attack12 attack13 attack14 attack15
$frame attack16 attack17 attack18 attack19 attack20 attack21 attack22
$frame attack23

$frame shocka1 shocka2 shocka3 shocka4 shocka5 shocka6 shocka7 shocka8
$frame shocka9 shocka10

$frame shockb1 shockb2 shockb3 shockb4 shockb5 shockb6

$frame shockc1 shockc2 shockc3 shockc4 shockc5 shockc6 shockc7 shockc8
$frame shockc9 shockc10

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

/*QUAKED monster_boss2 (1 0 0) (-128 -128 -24) (128 128 256)
*/
//----------------------------------------------------------------------
// class monster_boss2: base_monster
// {
//--------------------------------------------------------------
void() monster_boss2_face =
{
// go for another player if multi player
if (self.enemy.health <= 0 || random() < 0.02)
{
self.enemy = findfloat (self.enemy, classtype,
CT_PLAYER);
if (!self.enemy)
self.enemy = findfloat (self.enemy, classtype,
CT_PLAYER);
}
ai_face ();
};

//--------------------------------------------------------------
// boss2_missile
//--------------------------------------------------------------
void(vector p) monster_boss2_missile =
{
local vector org, d;
local float t;

makevectors (vectoangles(self.enemy.origin - self.origin));

org = self.origin + p_x * v_forward + p_y * v_right +
p_z * '0 0 1';

// lead the player on hard mode
if (skill > 1)
{
t = vlen(self.enemy.origin - org) / 300;
d = self.enemy.velocity;
d_z = 0;
d = self.enemy.origin + t * d;
}
else
{
d = self.enemy.origin;
}

base_monster_fire_lavaball (org, d - org, LAVABALL_SPEED);

sound_attack (self, CHAN_WEAPON, "boss1/throw.wav",
1, ATTN_NORM);

// check for dead enemy
if (self.enemy.health <= 0)
boss2_idle1 ();
};

//--------------------------------------------------------------
// GibBoss2
//--------------------------------------------------------------
void(vector dir) monster_boss2_gib =
{
sound (self, CHAN_VOICE, "player/udeath.wav", 1, ATTN_NORM);
// throw tons of meat chunks

local vector boss;
local float x, y, z;
local float r;
// local entity n;

boss = self.origin;
z = 16;
while (z <= 144)
{
x = -64;
while (x <= 64)
{
y = -64;
while (y <= 64)
{
self.origin_x = boss_x + x;
self.origin_y = boss_y + y;
self.origin_z = boss_z + z;

r = random ();
if (r < 0.3)
throw_gib_1 (self, dir, -120);
else if (r < 0.5)
throw_gib_2 (self, dir, -120);
// FIXME TODO CEV
// else if (r < 0.7)
// throw_gib ("progs/lavaball.mdl",
// -120);
else
throw_gib_3 (self, dir, -120);
y = y + 32;
}
x = x + 32;
}
z = z + 96;
}

local entity head;

head = spawn ();
head.origin = self.origin + '0 0 128';
head.velocity_z = 600; + (random() * 200);
head.velocity_x = -300 + (random() * 600);
head.velocity_y = -200 + (random() * 600);
head.avelocity_x = random() * 120;
head.avelocity_y = random() * 120;
head.avelocity_z = random() * 120;
head.flags = self.flags - (self.flags & FL_ONGROUND);
head.solid = SOLID_NOT;
head.movetype = MOVETYPE_BOUNCE;
head.takedamage = DAMAGE_NO;
// dumptruck_ds custom_mdls
if (self.mdl_head != "")
{
setmodel (head, self.mdl_head);
}
else
{
setmodel (head, "progs/h_boss.mdl");
}

// dumptruck_ds
if (!self.skin_head)
{
head.skin = self.skin_proj;
}
else
{
head.skin = 0;
}
setsize (head, '-67 -60 -6', '62 52 88');
// setsize (head, '-16 -16 0', '16 16 56');
head.touch = sub_null;
head.think = sub_remove;
head.nextthink = time + 120;
if !(self.spawnflags & NO_LAVASPLASH)
{
// done in combat.qc since self is now FL_MONSTER
// killed_monsters = killed_monsters + 1;
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_LAVASPLASH);
// done in combat.qc since self is now FL_MONSTER
// -- dumptruck_ds
// WriteByte (MSG_ALL, SVC_KILLEDMONSTER);
WriteCoord (MSG_BROADCAST, self.origin_x);
WriteCoord (MSG_BROADCAST, self.origin_y);
WriteCoord (MSG_BROADCAST, self.origin_z);
}
remove (self);
};

//--------------------------------------------------------------
// Chthon Idle functions
//--------------------------------------------------------------
void() boss2_idle1 = [$walk1, boss2_idle2]
{
// look for other players
};
void() boss2_idle2 = [$walk2, boss2_idle3] { monster_boss2_face (); };
void() boss2_idle3 = [$walk3, boss2_idle4] { monster_boss2_face (); };
void() boss2_idle4 = [$walk4, boss2_idle5] { monster_boss2_face (); };
void() boss2_idle5 = [$walk5, boss2_idle6] { monster_boss2_face (); };
void() boss2_idle6 = [$walk6, boss2_idle7] { monster_boss2_face (); };
void() boss2_idle7 = [$walk7, boss2_idle8] { monster_boss2_face (); };
void() boss2_idle8 = [$walk8, boss2_idle9] { monster_boss2_face (); };
void() boss2_idle9 = [$walk9, boss2_idle10] { monster_boss2_face (); };
void() boss2_idle10 = [$walk10, boss2_idle11] { monster_boss2_face ();};
void() boss2_idle11 = [$walk11, boss2_idle12] { monster_boss2_face ();};
void() boss2_idle12 = [$walk12, boss2_idle13] { monster_boss2_face ();};
void() boss2_idle13 = [$walk13, boss2_idle14] { monster_boss2_face ();};
void() boss2_idle14 = [$walk14, boss2_idle15] { monster_boss2_face ();};
void() boss2_idle15 = [$walk15, boss2_idle16] { monster_boss2_face ();};
void() boss2_idle16 = [$walk16, boss2_idle17] { monster_boss2_face ();};
void() boss2_idle17 = [$walk17, boss2_idle18] { monster_boss2_face ();};
void() boss2_idle18 = [$walk18, boss2_idle19] { monster_boss2_face ();};
void() boss2_idle19 = [$walk19, boss2_idle20] { monster_boss2_face ();};
void() boss2_idle20 = [$walk20, boss2_idle21] { monster_boss2_face ();};
void() boss2_idle21 = [$walk21, boss2_idle22] { monster_boss2_face ();};
void() boss2_idle22 = [$walk22, boss2_idle23] { monster_boss2_face ();};
void() boss2_idle23 = [$walk23, boss2_idle24] { monster_boss2_face ();};
void() boss2_idle24 = [$walk24, boss2_idle25] { monster_boss2_face ();};
void() boss2_idle25 = [$walk25, boss2_idle26] { monster_boss2_face ();};
void() boss2_idle26 = [$walk26, boss2_idle27] { monster_boss2_face ();};
void() boss2_idle27 = [$walk27, boss2_idle28] { monster_boss2_face ();};
void() boss2_idle28 = [$walk28, boss2_idle29] { monster_boss2_face ();};
void() boss2_idle29 = [$walk29, boss2_idle30] { monster_boss2_face ();};
void() boss2_idle30 = [$walk30, boss2_idle31] { monster_boss2_face ();};
void() boss2_idle31 = [$walk31, boss2_idle1] { monster_boss2_face (); };

//--------------------------------------------------------------
// Chthon Rises
//--------------------------------------------------------------
void() boss2_rise1 = [$rise1, boss2_rise2]
{
sound_move (self, CHAN_WEAPON, "boss1/out1.wav", 1, ATTN_NORM);
};
void() boss2_rise2 = [$rise2, boss2_rise3]
{
sound_sight (self, CHAN_VOICE, "boss1/sight1.wav", 1,ATTN_NORM);
};
void() boss2_rise3 = [$rise3, boss2_rise4] { };
void() boss2_rise4 = [$rise4, boss2_rise5] { };
void() boss2_rise5 = [$rise5, boss2_rise6] { };
void() boss2_rise6 = [$rise6, boss2_rise7] { };
void() boss2_rise7 = [$rise7, boss2_rise8] { };
void() boss2_rise8 = [$rise8, boss2_rise9] { };
void() boss2_rise9 = [$rise9, boss2_rise10] { };
void() boss2_rise10 = [$rise10, boss2_rise11] { };
void() boss2_rise11 = [$rise11, boss2_rise12] { };
void() boss2_rise12 = [$rise12, boss2_rise13] { };
void() boss2_rise13 = [$rise13, boss2_rise14] { };
void() boss2_rise14 = [$rise14, boss2_rise15] { };
void() boss2_rise15 = [$rise15, boss2_rise16] { };
void() boss2_rise16 = [$rise16, boss2_rise17] { };
void() boss2_rise17 = [$rise17, boss2_atk1] { };

//--------------------------------------------------------------
// Chthon Attack Lavaball
//--------------------------------------------------------------
void() boss2_atk1 = [$attack1, boss2_atk2] { monster_boss2_face (); };
void() boss2_atk2 = [$attack2, boss2_atk3] { monster_boss2_face (); };
void() boss2_atk3 = [$attack3, boss2_atk4] { monster_boss2_face (); };
void() boss2_atk4 = [$attack4, boss2_atk5] { monster_boss2_face (); };
void() boss2_atk5 = [$attack5, boss2_atk6] { monster_boss2_face (); };
void() boss2_atk6 = [$attack6, boss2_atk7] { monster_boss2_face (); };
void() boss2_atk7 = [$attack7, boss2_atk8] { monster_boss2_face (); };
void() boss2_atk8 = [$attack8, boss2_atk9] { monster_boss2_face (); };
void() boss2_atk9 = [$attack9, boss2_atk10]
{
monster_boss2_missile ('100 100 200');
};
void() boss2_atk10 = [$attack10, boss2_atk11] { monster_boss2_face ();};
void() boss2_atk11 = [$attack11, boss2_atk12] { monster_boss2_face ();};
void() boss2_atk12 = [$attack12, boss2_atk13] { monster_boss2_face ();};
void() boss2_atk13 = [$attack13, boss2_atk14] { monster_boss2_face ();};
void() boss2_atk14 = [$attack14, boss2_atk15] { monster_boss2_face ();};
void() boss2_atk15 = [$attack15, boss2_atk16] { monster_boss2_face ();};
void() boss2_atk16 = [$attack16, boss2_atk17] { monster_boss2_face ();};
void() boss2_atk17 = [$attack17, boss2_atk18] { monster_boss2_face ();};
void() boss2_atk18 = [$attack18, boss2_atk19] { monster_boss2_face ();};
void() boss2_atk19 = [$attack19, boss2_atk20] { monster_boss2_face ();};
void() boss2_atk20 = [$attack20, boss2_atk21]
{
monster_boss2_missile ('100 -100 200');
};
void() boss2_atk21 = [$attack21, boss2_atk22] { monster_boss2_face ();};
void() boss2_atk22 = [$attack22, boss2_atk23] { monster_boss2_face ();};
void() boss2_atk23 = [$attack23, boss2_atk1] { monster_boss2_face (); };

//--------------------------------------------------------------
// Chthon Shock! A
//--------------------------------------------------------------
void() boss2_shocka1 = [$shocka1, boss2_shocka2] { };
void() boss2_shocka2 = [$shocka2, boss2_shocka3] { };
void() boss2_shocka3 = [$shocka3, boss2_shocka4] { };
void() boss2_shocka4 = [$shocka4, boss2_shocka5] { };
void() boss2_shocka5 = [$shocka5, boss2_shocka6] { };
void() boss2_shocka6 = [$shocka6, boss2_shocka7] { };
void() boss2_shocka7 = [$shocka7, boss2_shocka8] { };
void() boss2_shocka8 = [$shocka8, boss2_shocka9] { };
void() boss2_shocka9 = [$shocka9, boss2_shocka10] { };
void() boss2_shocka10 = [$shocka10, boss2_atk1] { };

//--------------------------------------------------------------
// Chthon Shock! B
//--------------------------------------------------------------
void() boss2_shockb1 = [$shockb1, boss2_shockb2] { };
void() boss2_shockb2 = [$shockb2, boss2_shockb3] { };
void() boss2_shockb3 = [$shockb3, boss2_shockb4] { };
void() boss2_shockb4 = [$shockb4, boss2_shockb5] { };
void() boss2_shockb5 = [$shockb5, boss2_shockb6] { };
void() boss2_shockb6 = [$shockb6, boss2_shockb7] { };
void() boss2_shockb7 = [$shockb1, boss2_shockb8] { };
void() boss2_shockb8 = [$shockb2, boss2_shockb9] { };
void() boss2_shockb9 = [$shockb3, boss2_shockb10] { };
void() boss2_shockb10 = [$shockb4, boss2_atk1] { };

//--------------------------------------------------------------
// Chthon Shock! C
//--------------------------------------------------------------
void() boss2_shockc1 = [$shockc1, boss2_shockc2] { };
void() boss2_shockc2 = [$shockc2, boss2_shockc3] { };
void() boss2_shockc3 = [$shockc3, boss2_shockc4] { };
void() boss2_shockc4 = [$shockc4, boss2_shockc5] { };
void() boss2_shockc5 = [$shockc5, boss2_shockc6] { };
void() boss2_shockc6 = [$shockc6, boss2_shockc7] { };
void() boss2_shockc7 = [$shockc7, boss2_shockc8] { };
void() boss2_shockc8 = [$shockc8, boss2_shockc9] { };
void() boss2_shockc9 = [$shockc9, boss2_shockc10] { };
void() boss2_shockc10 = [$shockc10, boss2_death1] { };

//--------------------------------------------------------------
// Chthon Pain state
//--------------------------------------------------------------
void() boss2_pain1 = [$shocka1, boss2_pain2] { };
void() boss2_pain2 = [$shocka2, boss2_pain3] { };
void() boss2_pain3 = [$shocka3, boss2_pain4] { };
void() boss2_pain4 = [$shocka4, boss2_pain5]
{
// pain noise
sound_pain (self, CHAN_VOICE, "boss1/pain.wav", 1, ATTN_NORM);
};
void() boss2_pain5 = [$shocka5, boss2_pain6] { };
void() boss2_pain6 = [$shocka6, boss2_pain7] { };
void() boss2_pain7 = [$shocka7, boss2_pain8] { };
void() boss2_pain8 = [$shocka8, boss2_pain9] { };
void() boss2_pain9 = [$shocka9, boss2_atk1]
{
// auto shoot a lavaball (by advancing to next think state)
};

//--------------------------------------------------------------
// Chthon Death state
//--------------------------------------------------------------
void() boss2_death1 = [$death1, boss2_death2]
{
sound_death (self, CHAN_VOICE, "boss1/death.wav", 1, ATTN_NORM);
};
void() boss2_death2 = [$death2, boss2_death3] { };
void() boss2_death3 = [$death3, boss2_death4] { };
void() boss2_death4 = [$death4, boss2_death5] { };
void() boss2_death5 = [$death5, boss2_death6] { };
void() boss2_death6 = [$death6, boss2_death7] { };
void() boss2_death7 = [$death7, boss2_death8] { };
void() boss2_death8 = [$death8, boss2_death9] { };
void() boss2_death9 = [$death9, boss2_death10]
{
sound_move (self, CHAN_BODY, "boss1/out1.wav", 1, ATTN_NORM);
if !(self.spawnflags & NO_LAVASPLASH)
{
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_LAVASPLASH);
WriteCoord (MSG_BROADCAST, self.origin_x);
WriteCoord (MSG_BROADCAST, self.origin_y);
WriteCoord (MSG_BROADCAST, self.origin_z);
}
};
void() boss2_death10 = [$death9, boss2_death10]
{
// unlike the code for the original monster_boss, this
// function doesn't need to increment killed_monsters
// or call SUB_UseTargets(); this entity gets killed
// by regular damage and has FL_MONSTER, so the Killed()
// function (in combat.qc) will already have taken care
// of those things -- iw
remove (self);
};

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

//--------------------------------------------------------------
// boss2_pain_go
//--------------------------------------------------------------
void(entity attacker, float damage) monster_boss2_pain =
{
if (self.pain_finished > time)
return;

boss2_pain1 ();
self.pain_finished = time + 4;
};

//--------------------------------------------------------------
// boss2_die
//--------------------------------------------------------------
void(vector dir) monster_boss2_destroy =
{
if (self.health < -50)
{
// if health under -15
monster_boss2_gib (dir);
return;
}
else
{
// otherwise normal death
boss2_death1 ();
return;
}
};

//--------------------------------------------------------------
// boss2_awake
//--------------------------------------------------------------
void() monster_boss2_use =
{
self.solid = SOLID_SLIDEBOX;
self.movetype = MOVETYPE_STEP;
self.takedamage = DAMAGE_AIM;

body_model (self, "progs/boss.mdl");
// setmodel (self, "progs/boss.mdl");
setsize (self, '-128 -128 -24', '128 128 256');

if (!self.health)
{
if (skill == 0)
self.health = 1000;
else
self.health = 3000;
}

// note that self.th_run has to be set in order to avoid a
// "NULL function" Host_Error in the case where T_Damage()
// calls FoundTarget(), which calls HuntTarget(), which
// uses self.th_run as the next self.think -- iw
self.think_run = boss2_atk1;

self.pain = monster_boss2_pain;
self.destroy = monster_boss2_destroy;

// give the boss a couple of seconds to finish rising
// before allowing it to go into its pain animation -- iw
self.pain_finished = time + 2;

self.enemy = activator;

if !(self.spawnflags & NO_LAVASPLASH)
{
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_LAVASPLASH);
WriteCoord (MSG_BROADCAST, self.origin_x);
WriteCoord (MSG_BROADCAST, self.origin_y);
WriteCoord (MSG_BROADCAST, self.origin_z);
}

self.yaw_speed = 20;
boss2_rise1 ();
};

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

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

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

e.classname = "monster_boss2";
e.classtype = CT_MONSTER_BOSS_CHTHON2;
base_monster_init (e);

// custom sounds and models -- dumptruck_ds
precache_body_model (e, "progs/boss.mdl");
precache_head_model (e, "progs/h_boss.mdl");
precache_model ("progs/lavaball.mdl");
// precache_model ("progs/boss.mdl");
precache_model ("progs/h_boss.mdl");

precache_sound ("weapons/rocket1i.wav");
precache_sound_move (e, "boss1/out1.wav");
precache_sound_sight (e, "boss1/sight1.wav");
precache_sound ("misc/power.wav");
precache_sound_attack (e, "boss1/throw.wav");
precache_sound_pain (e, "boss1/pain.wav");
precache_sound_death (e, "boss1/death.wav");

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

total_monsters = total_monsters + 1;
e.flags = FL_MONSTER;
e.use = monster_boss2_use;
};

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

monster_boss2_init (self);
};
// };

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

Log boss2.qc

Date Commit Message Author + -
2024-04-12 Moveable gibs, heads, some bugfixes cev +12 -49
2024-04-05 Player footsteps, shareware monsters, misc? cev +295 -228
2024-02-18 Client/player, projectiles, entrypoints refactor cev +7 -35
2024-01-31 Class based monster refactor & start projectiles cev +497 -400
2024-01-09 Continue OO / Class-based refactor cev +2 -2
2023-10-13 Rename "qc-server" dir to "qc" cev +491  

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