Files
quakemapping/mod_xj18/my_progs/misc_targetdummy.qc
2020-01-07 11:54:38 +01:00

411 lines
14 KiB
Plaintext

/*======================================================================
/*QUAKED misc_targetdummy (0 .5 .5) (-32 -32 -24) (32 32 64) KNIGHT WIZARD OGRE HELL_KNIGHT ZOMBIE DEMON SHALRATH SHAMBLER
Target practice dummy
------- KEYS --------
noise1 : Targetnumber tracking weapon used
noise2 : Targetnumber tracking enemy distance
noise3 : Targetnumber tracking damage
noise4 : Targetnumber tracking % efficency
wait : Impact marker removal time (def=2)
-------- SPAWNFLAGS --------
KNIGHT : Knight model
WIZARD : Wizard model
OGRE : Ogre model
HELL_KNIGHT : Hell Knight model
ZOMBIE : Zombie model
DEMON : Demon model
SHALRATH : Shalrath model
SHAMBLER : Shambler model
------- NOTES --------
Target practice dummy
======================================================================*/
float MISC_TARGKNIGHT = 1;
float MISC_TARGWIZARD = 2;
float MISC_TARGOGRE = 4;
float MISC_TARGHELLKNIGHT = 8;
float MISC_TARGZOMBIE = 16;
float MISC_TARGDEMON = 32;
float MISC_TARGSHALRATH = 64;
float MISC_TARGSHAMBLER = 128;
//----------------------------------------------------------------------
void(float tvalue, string tdstr) misc_targetdummy_trigger =
{
local entity tdfind, tself, tother;
if (tdstr == "") return;
self.targetnumber = tvalue;
tdfind = find(world, targetname, tdstr);
if (tdfind.classtype == CT_TARGETNUMBER) {
tself = self; tother = other;
self = tdfind; other = tself;
self.use();
self = tself; other = tother;
}
};
//----------------------------------------------------------------------
void() misc_targetdummy_stand =
{
// Cycle around standing animation
self.frame = self.frame + 1;
if (self.frame == self.pos1_y) self.frame = self.pos1_x;
self.nextthink = time + 0.1;
// Check for any accumulating damage totals
if (self.attack_finished < time) {
dprint("Wpn (");
if (self.weapon & IT_SHOTGUN) dprint("Shotgun");
else if (self.weapon & IT_SUPER_SHOTGUN && self.moditems & IT_UPGRADE_SSG)
dprint("Shotgun Upgrade");
else if (self.weapon & IT_SUPER_SHOTGUN) dprint("Super Shotgun");
else if (self.weapon & IT_NAILGUN) dprint("Nail Gun");
else if (self.weapon & IT_SUPER_NAILGUN) dprint("Super Nail Gun");
else if (self.weapon & IT_GRENADE_LAUNCHER) dprint("Grenade Launcher");
else if (self.weapon & IT_ROCKET_LAUNCHER) dprint("Rocket Launcher");
else if (self.weapon & IT_LIGHTNING && self.moditems & IT_UPGRADE_LG)
dprint("Lightning Upgrade");
else if (self.weapon & IT_LIGHTNING) dprint("Lightning Gun");
else dprint("Unknown");
dprint(") Dist ("); dprint(ftos(self.enemydist));
dprint(") Dmg ("); dprint(ftos(self.dmg));
dprint(") % (");
if (self.weapon & IT_SHOTGUN || self.weapon & IT_SUPER_SHOTGUN) {
if (self.weapon & IT_SHOTGUN) self.cnt = self.dmg / 28;
else if (self.moditems & IT_UPGRADE_SSG) self.cnt = self.dmg / 84;
else self.cnt = self.dmg / 56;
self.cnt = self.cnt * 100;
}
else self.cnt = 100;
dprint(ftos(self.cnt));
dprint(")\n");
misc_targetdummy_trigger(self.weapon, self.noise1);
misc_targetdummy_trigger(self.enemydist, self.noise2);
misc_targetdummy_trigger(self.dmg, self.noise3);
misc_targetdummy_trigger(self.cnt, self.noise4);
// Reset health, damage timer and total
self.health = self.max_health;
self.attack_finished = LARGE_TIMER;
self.dmg = 0;
}
};
//----------------------------------------------------------------------
void(entity inflictor, entity attacker, float damage) misc_targetdummy_pain =
{
// want all damage to go through pain function, reset timer
self.pain_finished = 0;
// Play a pain sound every second
if (self.pain_check < time) {
sound (self, CHAN_VOICE, self.pain_sound, 1, ATTN_NORM);
self.pain_check = time + 1;
}
// If the attacker is a player, record details
if (attacker.flags & FL_CLIENT) {
self.weapon = attacker.weapon;
self.items = attacker.items;
self.moditems = attacker.moditems;
self.enemydist = range_distance(attacker, TRUE);
}
else self.weapon = self.enemydist = 0;
// The damage value is different depending on projectile type
if (inflictor.classgroup == CG_PROJSHELLS) self.dmg = damage;
else self.dmg = self.dmg + damage;
// reset timer for accumulating damage over time
self.attack_finished = time + 0.5;
// Spawn a marker to show impact location
// Will remove self after certain amount of time
newmis = spawn();
newmis.classtype = CT_DEVMARKER;
newmis.movetype = MOVETYPE_NONE;
newmis.solid = SOLID_NOT;
setmodel(newmis, MODEL_IMPACT);
// Randomize between 8 yellow skins
newmis.skin = rint(random()*7);
// Take projectile impact location
setorigin(newmis, inflictor.origin);
setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
newmis.think = SUB_Remove;
newmis.nextthink = time + self.wait;
};
//----------------------------------------------------------------------
void() misc_targetdummy =
{
// Always reset Ammo Resistance to be consistent
self.resist_shells = self.resist_nails = 0;
self.resist_rockets = self.resist_cells = 0;
if (self.spawnflags & MISC_TARGKNIGHT) {
self.mdl = "progs/mon_knight.mdl";
self.headmdl = "progs/targd_short.mdl";
self.pain_sound = "knight/khurt.wav";
self.t_width = FALSE;
self.bboxtype = BBOX_SHORT;
self.pos1 = '0 9 0'; // stand1-9
}
else if (self.spawnflags & MISC_TARGWIZARD) {
self.mdl = "progs/mon_wizard.mdl";
self.headmdl = "progs/targd_tall.mdl";
self.pain_sound = "wizard/wpain.wav";
self.t_width = FALSE;
self.bboxtype = BBOX_TALL;
self.pos1 = '0 8 0'; // hover1-8
}
else if (self.spawnflags & MISC_TARGOGRE) {
self.mdl = "progs/ogre.mdl";
self.headmdl = "progs/targd_wide.mdl";
self.pain_sound = "ogre/ogpain1.wav";
self.t_width = TRUE;
self.bboxtype = BBOX_WIDE;
self.pos1 = '0 9 0'; // stand1-9
}
else if (self.spawnflags & MISC_TARGHELLKNIGHT) {
self.mdl = "progs/mon_hknight.mdl";
self.headmdl = "progs/targd_tall.mdl";
self.pain_sound = "hknight/pain1.wav";
self.t_width = FALSE;
self.bboxtype = BBOX_TALL;
self.pos1 = '0 9 0'; // stand1-9
}
else if (self.spawnflags & MISC_TARGZOMBIE) {
self.mdl = "progs/mon_zombie.mdl";
self.headmdl = "progs/targd_short.mdl";
self.pain_sound = "zombie/z_pain.wav";
self.t_width = FALSE;
self.bboxtype = BBOX_SHORT;
self.pos1 = '0 15 0'; // stand 1-15
}
else if (self.spawnflags & MISC_TARGDEMON) {
self.mdl = "progs/demon.mdl";
self.headmdl = "progs/targd_wide.mdl";
self.pain_sound = "demon/dpain1.wav";
self.t_width = TRUE;
self.bboxtype = BBOX_WIDE;
self.pos1 = '0 13 0'; // stand 1-13
}
else if (self.spawnflags & MISC_TARGSHALRATH) {
self.mdl = "progs/mon_shalrath.mdl";
self.headmdl = "progs/targd_wide.mdl";
self.pain_sound = "shalrath/pain.wav";
self.t_width = TRUE;
self.bboxtype = BBOX_WIDE;
self.pos1 = '0 1 0'; // stand 1
}
else if (self.spawnflags & MISC_TARGSHAMBLER) {
self.mdl = "progs/shambler.mdl";
self.headmdl = "progs/targd_massive.mdl";
self.pain_sound = "shambler/shurt2.wav";
self.t_width = FALSE;
self.bboxtype = BBOX_MASSIVE;
self.pos1 = '0 17 0'; // stand1-17
self.resist_rockets = 0.5;
}
else { remove(self); return; }
precache_model (self.mdl);
precache_model (self.headmdl);
precache_sound (self.pain_sound);
precache_model (MODEL_IMPACT); // Impact model marker
self.classtype = CT_TARGETDUMMY;
self.classgroup = CG_MONSTERS;
self.health = self.max_health = 100000;
self.solid = SOLID_SLIDEBOX;
self.movetype = MOVETYPE_NONE;
self.movespeed = 0; // Never move monster
if (self.wait < 1) self.wait = 2; // impact marker removal time
self.pain_finished = 0; // Always reset this
self.pain_flinch = 1; // Always pass flinch test
self.dmg = 0; // Accumulated damage per frame
self.attack_finished = LARGE_TIMER; // Reset timer for checks
self.view_ofs = '0 0 24'; // Default monster offset
self.takedamage = DAMAGE_AIM; // Always take damage
monster_bbox(); // Setup bounding box
setmodel(self, self.mdl); // Display model
setsize (self, self.bbmins, self.bbmaxs); // Update bbox
// Spawn projectile bounding box visual marker
self.attachment = spawn();
self.attachment.solid = SOLID_NOT;
self.attachment.movetype = MOVETYPE_NONE;
setmodel(self.attachment, self.headmdl);
setorigin(self.attachment, self.origin-self.view_ofs);
self.attachment.alpha = 0.3;
// Spawn Hull2 bounding box visual marker
if (self.t_width) {
self.noise = "progs/targd_hull2.mdl";
precache_model(self.noise);
self.attachment2 = spawn();
self.attachment2.solid = SOLID_NOT;
self.attachment2.movetype = MOVETYPE_NONE;
setmodel(self.attachment2, self.noise);
setorigin(self.attachment2, self.origin-self.view_ofs);
self.attachment2.alpha = 0.15;
}
// Intercept all AI states
self.th_pain = misc_targetdummy_pain;
self.th_stand = misc_targetdummy_stand;
self.th_walk = misc_targetdummy_stand;
self.th_run = misc_targetdummy_stand;
self.th_melee = misc_targetdummy_stand;
// Stand around and wait for the pain!
self.think = self.th_stand;
self.nextthink = time + 0.5 + random();
};
/*======================================================================
/*QUAKED misc_targetnumber (.5 .5 0) (-4 -4 -8) (4 4 8) x
target number to display ingame
------- KEYS --------
targetname : required for numbers to updated
pos1 : X= top digit quantity, Y=Lower digit quantity
-------- SPAWNFLAGS --------
------- NOTES --------
target number to display ingame
======================================================================*/
void() misc_targetnumber_dispno =
{
local float str_counter, str_pow, str_result, str_low;
str_counter = self.pos1_x; // Upper number length
str_pow = pow10(self.pos1_x); // Setup initial base 10 power for checking
// If number larger than fixed length? - truncate number
if (self.count > str_pow)
self.count = self.count - (floor(self.count / str_pow) * str_pow);
// Loop through lower part of number
while(str_counter > 0) {
// Move down one pow digit
str_pow = str_pow / 10;
// Divide number by pow to get divider
str_result = floor(self.count / str_pow);
if (str_counter == 4) self.tno8.skin = str_result;
else if (str_counter == 3) self.tno7.skin = str_result;
else if (str_counter == 2) self.tno6.skin = str_result;
else if (str_counter == 1) self.tno5.skin = str_result;
// remove top part of number, decrease str length counter
self.count = self.count - (str_result * str_pow);
str_counter = str_counter - 1;
}
// Shift the lower part of the number upwards
str_low = str_counter = self.pos1_y;
str_pow = pow10(self.pos1_y);
while (str_low > 0) {
self.count = self.count * 10;
str_low = str_low - 1;
}
// Loop through lower part of number
while(str_counter > 0) {
// Move down one pow digit
str_pow = str_pow / 10;
// Divide number by pow to get divider
str_result = floor(self.count / str_pow);
if (str_counter == 3) self.tno3.skin = str_result;
else if (str_counter == 2) self.tno2.skin = str_result;
else if (str_counter == 1) self.tno1.skin = str_result;
// remove top part of number, decrease str length counter
self.count = self.count - (str_result * str_pow);
str_counter = str_counter - 1;
}
};
//----------------------------------------------------------------------
void() misc_targetnumber_use =
{
self.count = fabs(other.targetnumber);
misc_targetnumber_dispno();
};
//----------------------------------------------------------------------
entity(float offset, float startno) misc_targetnumber_spawn =
{
local entity tnoent;
tnoent = spawn();
tnoent.classtype = CT_TARGETNUMBER;
tnoent.solid = SOLID_NOT;
tnoent.movetype = MOVETYPE_NONE;
makevectors(self.angles);
setmodel(tnoent, self.mdl);
setorigin(tnoent, self.origin + v_right*(8*offset));
setsize(tnoent, VEC_ORIGIN, VEC_ORIGIN);
tnoent.skin = startno;
tnoent.angles = self.angles;
return tnoent;
};
//----------------------------------------------------------------------
void() misc_targetnumber =
{
self.mdl = "progs/misc_digit.mdl";
precache_model (self.mdl);
self.classtype = CT_TARGETNUMBER;
self.solid = SOLID_NOT;
self.movetype = MOVETYPE_NONE;
// Setup lower part of number (1-3 decimal places, 4=dot always)
if (self.pos1_y > 0) {
if (self.pos1_y == 1)
self.tno1 = misc_targetnumber_spawn(0, 0);
else if (self.pos1_y == 2) {
self.tno1 = misc_targetnumber_spawn(0, 0);
self.tno2 = misc_targetnumber_spawn(1, 0);
}
else {
self.pos1_y = 3;
self.tno1 = misc_targetnumber_spawn(0, 0);
self.tno2 = misc_targetnumber_spawn(1, 0);
self.tno3 = misc_targetnumber_spawn(2, 0);
}
// Decimal place is always tno4
self.tno4 = misc_targetnumber_spawn(self.pos1_y, 10);
self.pos1_z = self.pos1_y +1;
}
else self.pos1_z = 0;
// Setup upper part of number (1-4 digits only, min 1 digit)
if (self.pos1_x < 1) self.pos1_x = 1;
if (self.pos1_x == 1)
self.tno5 = misc_targetnumber_spawn(self.pos1_z, 0);
else if (self.pos1_x == 2) {
self.tno5 = misc_targetnumber_spawn(self.pos1_z, 0);
self.tno6 = misc_targetnumber_spawn(self.pos1_z+1, 0);
}
else if (self.pos1_x == 3) {
self.tno5 = misc_targetnumber_spawn(self.pos1_z, 0);
self.tno6 = misc_targetnumber_spawn(self.pos1_z+1, 0);
self.tno7 = misc_targetnumber_spawn(self.pos1_z+2, 0);
}
else {
self.pos1_x = 4;
self.tno5 = misc_targetnumber_spawn(self.pos1_z, 0);
self.tno6 = misc_targetnumber_spawn(self.pos1_z+1, 0);
self.tno7 = misc_targetnumber_spawn(self.pos1_z+2, 0);
self.tno8 = misc_targetnumber_spawn(self.pos1_z+3, 0);
}
// Setup trigger function for number update
if (self.targetname != "") self.use = misc_targetnumber_use;
};