From: Jakob MG Date: Mon, 10 Oct 2011 15:56:49 +0000 (+0200) Subject: Moar things to attic X-Git-Tag: xonotic-v0.6.0~40^2~60^2~1 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=b0496369a8515a33f5a3af11aa2561a5e3cc8d21;p=xonotic%2Fxonotic-data.pk3dir.git Moar things to attic --- diff --git a/qcsrc/server/attic/ai.qc b/qcsrc/server/attic/ai.qc deleted file mode 100644 index 59989e7a8..000000000 --- a/qcsrc/server/attic/ai.qc +++ /dev/null @@ -1,891 +0,0 @@ -void() movetarget_f; -void() t_movetarget; -void() FoundTarget; - -float MONSTER_WANDER = 64; // disable wandering around -float MONSTER_APPEAR = 128; // spawn invisible, and appear when triggered - -.float ismonster; -.float monsterawaitingteleport; // avoid awaking monsters in teleport rooms - -// when a monster becomes angry at a player, that monster will be used -// as the sight target the next frame so that monsters near that one -// will wake up even if they wouldn't have noticed the player -// -entity sight_entity; -float sight_entity_time; - -/* - -.enemy -Will be world if not currently angry at anyone. - -.movetarget -The next path spot to walk toward. If .enemy, ignore .movetarget. -When an enemy is killed, the monster will try to return to it's path. - -.huntt_ime -Set to time + something when the player is in sight, but movement straight for -him is blocked. This causes the monster to use wall following code for -movement direction instead of sighting on the player. - -.ideal_yaw -A yaw angle of the intended direction, which will be turned towards at up -to 45 deg / state. If the enemy is in view and hunt_time is not active, -this will be the exact line towards the enemy. - -.pausetime -A monster will leave it's stand state and head towards it's .movetarget when -time > .pausetime. - -walkmove(angle, speed) primitive is all or nothing -*/ - - -// -// globals -// -//float current_yaw; - -float(float v) anglemod = -{ - v = v - 360 * floor(v / 360); - return v; -} - -/* -============================================================================== - -MOVETARGET CODE - -The angle of the movetarget effects standing and bowing direction, but has no effect on movement, which allways heads to the next target. - -targetname -must be present. The name of this movetarget. - -target -the next spot to move to. If not present, stop here for good. - -pausetime -The number of seconds to spend standing or bowing for path_stand or path_bow - -============================================================================== -*/ - - -void() movetarget_f = -{ - if (!self.targetname) - objerror ("monster_movetarget: no targetname"); - - self.solid = SOLID_TRIGGER; - self.touch = t_movetarget; - setsize (self, '-8 -8 -8', '8 8 8'); -} - -/*QUAKED path_corner (0.5 0.3 0) (-8 -8 -8) (8 8 8) -Monsters will continue walking towards the next target corner. -*/ -void() path_corner = -{ - movetarget_f (); -} - -/* -============= -t_movetarget - -Something has bumped into a movetarget. If it is a monster -moving towards it, change the next destination and continue. -============== -*/ -void() t_movetarget = -{ - entity temp; - - if (other.health < 1) - return; - if (other.movetarget != self) - return; - - if (other.enemy) - return; // fighting, not following a path - - temp = self; - self = other; - other = temp; - - /* PLEASE FIX THE SOUND CHANNEL BEFORE ACTIVATING THIS - if (self.classname == "monster_ogre") - sound (self, CHAN_VOICE, "ogre/ogdrag.wav", 1, ATTN_IDLE);// play chainsaw drag sound - */ - -//dprint ("t_movetarget\n"); - self.goalentity = self.movetarget = find (world, targetname, other.target); - self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); - if (!self.movetarget) - { - self.pausetime = time + 999999; - self.th_stand (); - return; - } -} - -void() monster_wanderpaththink = -{ - vector v, v1; - float b, c; - self.nextthink = time + random() * 10 + 1; - if (self.owner.health < 1) // dead, also handled in death code - { - self.owner.movetarget = world; - remove(self); - return; - } - b = -1; - c = 10; - while (c > 0) - { - c = c - 1; - v = randomvec(); - traceline(self.owner.origin, v * 1024 + self.owner.origin, FALSE, self); - v = trace_endpos - (normalize(v) * 16) - self.owner.origin; - if (vlen(v) > b) - { - b = vlen(v); - v1 = v; - } - } - setorigin(self, v1 + self.owner.origin); - self.owner.ideal_yaw = vectoyaw(self.origin - self.owner.origin); -} - -void() monster_wanderpathtouch = -{ - if (other.health < 1) - return; - if (other.movetarget != self) - return; - - if (other.enemy) - return; // fighting, not following a path - - /* PLEASE FIX THE SOUND CHANNEL BEFORE ACTIVATING THIS - if (other.classname == "monster_ogre") - sound (other, CHAN_VOICE, "ogre/ogdrag.wav", 1, ATTN_IDLE);// play chainsaw drag sound - */ - monster_wanderpaththink(); -} - -void() monster_spawnwanderpath = -{ - newmis = spawn(); - newmis.classname = "monster_wanderpath"; - newmis.solid = SOLID_TRIGGER; - newmis.touch = monster_wanderpathtouch; - setsize (newmis, '-8 -8 -8', '8 8 8'); - newmis.think = monster_wanderpaththink; - newmis.nextthink = time + random() * 10 + 1; - newmis.owner = self; - self.goalentity = self.movetarget = newmis; -} - -void() monster_checkbossflag = -{ -//#NO AUTOCVARS START -#if 0 - float healthboost; - float r; - - // monsterbosses cvar or spawnflag 64 causes a monster to be a miniboss - if ((self.spawnflags & 64) || (random() * 100 < cvar("monsterbosspercent"))) - { - self.radsuit_finished = time + 1000000000; - r = random() * 4; - if (r < 2) - { - self.super_damage_finished = time + 1000000000; - healthboost = 30 + self.health * 0.5; - self.effects = self.effects | (EF_FULLBRIGHT | EF_BLUE); - } - if (r >= 1) - { - healthboost = 30 + self.health * bound(0.5, skill * 0.5, 1.5); - self.effects = self.effects | (EF_FULLBRIGHT | EF_RED); - self.healthregen = max(self.healthregen, min(skill * 10, 30)); - } - self.health = self.health + healthboost; - self.max_health = self.health; - self.bodyhealth = self.bodyhealth * 2 + healthboost; - do - { - self.colormod_x = random(); - self.colormod_y = random(); - self.colormod_z = random(); - self.colormod = normalize(self.colormod); - } - while (self.colormod_x > 0.6 && self.colormod_y > 0.6 && self.colormod_z > 0.6); - } -#endif -//#NO AUTOCVARS END -} - - -//============================================================================ - -/* -============= -range - -returns the range catagorization of an entity reletive to self -0 melee range, will become hostile even if back is turned -1 visibility and infront, or visibility and show hostile -2 infront and show hostile -3 only triggered by damage -============= -*/ -float(entity targ) range = -{ - float r; - r = vlen ((self.origin + self.view_ofs) - (targ.origin + targ.view_ofs)); - if (r < 120) - return RANGE_MELEE; - if (r < 500) - return RANGE_NEAR; - if (r < 2000) // increased from 1000 for DP - return RANGE_MID; - return RANGE_FAR; -} - -/* -============= -visible - -returns 1 if the entity is visible to self, even if not infront () -============= -*/ -float (entity targ) visible = -{ - if (vlen(targ.origin - self.origin) > 5000) // long traces are slow - return FALSE; - - traceline ((self.origin + self.view_ofs), (targ.origin + targ.view_ofs), TRUE, self); // see through other monsters - - if (trace_inopen && trace_inwater) - return FALSE; // sight line crossed contents - - if (trace_fraction == 1) - return TRUE; - return FALSE; -} - - -/* -============= -infront - -returns 1 if the entity is in front (in sight) of self -============= -*/ -float(entity targ) infront = -{ - float dot; - - makevectors (self.angles); - dot = normalize (targ.origin - self.origin) * v_forward; - - return (dot > 0.3); -} -// returns 0 if not infront, or the dotproduct if infront -float(vector dir, entity targ) infront2 = -{ - float dot; - - dir = normalize(dir); - dot = normalize (targ.origin - self.origin) * dir; - - if (dot >= 0.3) return dot; // infront - return 0; -} - - -//============================================================================ - -/* -=========== -ChangeYaw - -Turns towards self.ideal_yaw at self.yaw_speed -Sets the global variable current_yaw -Called every 0.1 sec by monsters -============ -*/ -/* - -void() ChangeYaw = -{ - float ideal, move; - -//current_yaw = self.ideal_yaw; -// mod down the current angle - current_yaw = anglemod( self.angles_y ); - ideal = self.ideal_yaw; - - if (current_yaw == ideal) - return; - - move = ideal - current_yaw; - if (ideal > current_yaw) - { - if (move > 180) - move = move - 360; - } - else - { - if (move < -180) - move = move + 360; - } - - if (move > 0) - { - if (move > self.yaw_speed) - move = self.yaw_speed; - } - else - { - if (move < 0-self.yaw_speed ) - move = 0-self.yaw_speed; - } - - current_yaw = anglemod (current_yaw + move); - - self.angles_y = current_yaw; -} - -*/ - - -//============================================================================ - -void() HuntTarget = -{ - self.goalentity = self.enemy; - self.think = self.th_run; - self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin); - self.nextthink = time + 0.1; - SUB_AttackFinished (1); // wait a while before first attack -} - -.void() th_sightsound; - -void() SightSound = -{ - if (self.health < 1) - return; - // skill 5 does not play sight sounds, instead you only hear the appear sound as they are about to attack - if (skill >= 5) - if (self.classname != "monster_hellfish") - return; - - if (self.th_sightsound) - self.th_sightsound(); -} - -void() FoundTarget = -{ - if (self.health < 1 || !self.th_run) - return; - if (self.enemy.health < 1 || !self.enemy.takedamage) - return; - if (self.enemy.classname == "player") - { - // let other monsters see this monster for a while - sight_entity = self; - sight_entity_time = time + 0.1; - } - - self.show_hostile = time + 1; // wake up other monsters - - SightSound (); - HuntTarget (); -} - -/* -//float checkplayertime; -entity lastcheckplayer; -entity havocbot_list; - - -entity() checkplayer = -{ - entity check; - float worldcount; - // we can just fallback on checkclient if there are no bots - if (!havocbot_list) - return checkclient(); -*/ - /* - if (time < checkplayertime) - { - traceline(self.origin + self.view_ofs, lastcheckplayer.origin + lastcheckplayer.view_ofs, TRUE, self); - if (trace_fraction == 1) - return lastcheckplayer; - if (trace_ent == lastcheckplayer) - return lastcheckplayer; - } - checkplayertime = time + 0.1; - */ -/* - check = lastcheckplayer; - worldcount = 0; - c = 0; - do - { - c = c + 1; - check = findfloat(check, havocattack, TRUE); - if (check.classname == "player" || check.classname == "turretbase") - { - traceline(self.origin + self.view_ofs, check.origin + check.view_ofs, TRUE, self); - if (trace_fraction == 1) - return lastcheckplayer = check; - if (trace_ent == check) - return lastcheckplayer = check; - } - else if (check == world) - { - worldcount = worldcount + 1; - if (worldcount >= 2) - return lastcheckplayer = check; - } - } - while(check != lastcheckplayer && c < 100); - return world; -} -*/ - -/* -=========== -FindTarget - -Self is currently not attacking anything, so try to find a target - -Returns TRUE if an enemy was sighted - -When a player fires a missile, the point of impact becomes a fakeplayer so -that monsters that see the impact will respond as if they had seen the -player. - -To avoid spending too much time, only a single client (or fakeclient) is -checked each frame. This means multi player games will have slightly -slower noticing monsters. -============ -*/ -.float findtarget; -float() FindTarget = -{ - entity client; - float r; - - if (self.health < 1) - return FALSE; - - // if the first or second spawnflag bit is set, the monster will only - // wake up on really seeing the player, not another monster getting angry - - if (self.spawnflags & 3) - { - // don't wake up on seeing another monster getting angry - client = checkclient (); - if (!client) - return FALSE; // current check entity isn't in PVS - } - else - { - if (sight_entity_time >= time) - { - client = sight_entity; - if (client.enemy == self.enemy) - return TRUE; - } - else - { - client = checkclient (); - if (!client) - return FALSE; // current check entity isn't in PVS - } - } - - if (client == self.enemy) - return FALSE; - - if (client.flags & FL_NOTARGET) - return FALSE; - -#if 0 - if (client.items & IT_INVISIBILITY) - return FALSE; -#endif - - // on skill 5 the monsters usually ignore the player and remain ghostlike - if (skill >= 5) - if (self.classname != "monster_hellfish") - if (random() < 0.99) - return FALSE; - - r = range(client); - if (r == RANGE_FAR) - return FALSE; - - if (!visible (client)) - return FALSE; - - if (r == RANGE_NEAR) - { - if (client.show_hostile < time && !infront (client)) - return FALSE; - } - else if (r == RANGE_MID) - { - // LordHavoc: was if ( /* client.show_hostile < time || */ !infront (client)) - if (client.show_hostile < time && !infront (client)) - return FALSE; - } - - // - // got one - // - - if (client.model == "") - return FALSE; - self.enemy = client; - if (self.enemy.classname != "player" && self.enemy.classname != "turretbase") - { - self.enemy = self.enemy.enemy; - if (self.enemy.classname != "player" && self.enemy.classname != "turretbase") - { - self.enemy = world; - return FALSE; - } - } - - FoundTarget (); - - return TRUE; -} - - -//============================================================================= - -void(float dist) ai_forward = -{ - walkmove (self.angles_y, dist); -} - -void(float dist) ai_back = -{ - walkmove ( (self.angles_y+180), dist); -} - - -void(float a) monster_setalpha; - -/* -============= -ai_pain - -stagger back a bit -============= -*/ -void(float dist) ai_pain = -{ - if (self.health < 1) - return; - ai_back (dist); -} - -/* -============= -ai_painforward - -stagger back a bit -============= -*/ -void(float dist) ai_painforward = -{ - if (self.health < 1) - return; - walkmove (self.ideal_yaw, dist); -} - -/* -============= -ai_walk - -The monster is walking it's beat -============= -*/ -void(float dist) ai_walk = -{ - if (self.health < 1) - return; - - movedist = dist; - - // check for noticing a player - if (self.oldenemy.takedamage) - if (self.oldenemy.health >= 1) - { - self.enemy = self.oldenemy; - self.oldenemy = world; - FoundTarget(); - monster_setalpha(0); - return; - } - if (self.enemy) - { - if (self.enemy.takedamage) - { - if (self.enemy.health >= 1) - { - FoundTarget(); - monster_setalpha(0); - return; - } - else - self.enemy = world; - } - else - self.enemy = world; - } - - self.findtarget = TRUE; - - movetogoal (dist); - monster_setalpha(0); -} - - -/* -============= -ai_stand - -The monster is staying in one place for a while, with slight angle turns -============= -*/ -void() ai_stand = -{ - if (self.health < 1) - return; - if (self.enemy) - { - if (self.enemy.takedamage) - { - if (self.enemy.health >= 1) - { - FoundTarget(); - monster_setalpha(0); - return; - } - else - self.enemy = world; - } - else - self.enemy = world; - } - self.findtarget = TRUE; - - if (time > self.pausetime) - { - self.th_walk (); - monster_setalpha(0); - return; - } - -// change angle slightly - - monster_setalpha(0); -} - -/* -============= -ai_turn - -don't move, but turn towards ideal_yaw -============= -*/ -void() ai_turn = -{ - if (self.enemy) - { - if (self.enemy.takedamage) - { - if (self.enemy.health >= 1) - { - FoundTarget(); - monster_setalpha(0); - return; - } - else - self.enemy = world; - } - else - self.enemy = world; - } - self.findtarget = TRUE; - - ChangeYaw (); - monster_setalpha(0); -} - -//============================================================================= - -/* -============= -ChooseTurn -============= -*/ -void(vector pDestvec) ChooseTurn = -{ - vector dir, newdir; - - dir = self.origin - pDestvec; - - newdir_x = trace_plane_normal_y; - newdir_y = 0 - trace_plane_normal_x; - newdir_z = 0; - - if (dir * newdir > 0) - { - dir_x = 0 - trace_plane_normal_y; - dir_y = trace_plane_normal_x; - } - else - { - dir_x = trace_plane_normal_y; - dir_y = 0 - trace_plane_normal_x; - } - - dir_z = 0; - self.ideal_yaw = vectoyaw(dir); -} - -/* -============ -FacingIdeal - -============ -*/ -float() FacingIdeal = -{ - float delta; - - delta = anglemod(self.angles_y - self.ideal_yaw); - if (delta > 45 && delta < 315) - return FALSE; - return TRUE; -} - - -//============================================================================= - -.float() th_checkattack; - - - -/* -============= -ai_run - -The monster has an enemy it is trying to kill -============= -*/ -void(float dist) ai_run = -{ - float ofs; - if (self.health < 1) - return; - movedist = dist; - // see if the enemy is dead - if (self.enemy.health < 1 || self.enemy.takedamage == DAMAGE_NO) - { - self.enemy = world; - // FIXME: look all around for other targets - if (self.oldenemy.health >= 1 && self.oldenemy.takedamage) - { - self.enemy = self.oldenemy; - self.oldenemy = world; - HuntTarget (); - } - else - { - if (self.movetarget) - self.th_walk (); - else - self.th_stand (); - return; - } - } - - // wake up other monsters - self.show_hostile = time + 1; - - // check knowledge of enemy - enemy_range = range(self.enemy); - - self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin); - ChangeYaw (); - - if (self.attack_state == AS_MELEE) - { - //dprint ("ai_run_melee\n"); - //Turn and close until within an angle to launch a melee attack - if (FacingIdeal()) - { - self.th_melee (); - self.attack_state = AS_STRAIGHT; - } - return; - } - else if (self.attack_state == AS_MISSILE) - { - //dprint ("ai_run_missile\n"); - //Turn in place until within an angle to launch a missile attack - if (FacingIdeal()) - if (self.th_missile ()) - self.attack_state = AS_STRAIGHT; - return; - } - - if (self.th_checkattack()) - return; // beginning an attack - - if (visible(self.enemy)) - self.search_time = time + 5; - else if (coop) - { - // look for other coop players - if (self.search_time < time) - self.findtarget = TRUE; - } - - if (self.attack_state == AS_SLIDING) - { - //dprint ("ai_run_slide\n"); - //Strafe sideways, but stay at aproximately the same range - if (self.lefty) - ofs = 90; - else - ofs = -90; - - if (walkmove (self.ideal_yaw + ofs, movedist)) - return; - - self.lefty = !self.lefty; - - walkmove (self.ideal_yaw - ofs, movedist); - } - - // head straight in - movetogoal (dist); // done in C code... -} - diff --git a/qcsrc/server/attic/defs.qc b/qcsrc/server/attic/defs.qc deleted file mode 100644 index 19821429c..000000000 --- a/qcsrc/server/attic/defs.qc +++ /dev/null @@ -1,55 +0,0 @@ -.entity movetarget; -.float pausetime; - -.void() th_stand; -.void() th_walk; -.void() th_run; -.float() th_missile; // LordHavoc: changed from void() to float(), returns true if attacking -.void() th_melee; -//.void(entity attacker, float damage, float damgtype, string dethtype) th_pain; // TODO Xonotic uses event_damage -//.void() th_die; // TODO never called directly by Xonotic -.entity oldenemy; // mad at this player before taking damage -entity newmis; // launch_spike sets this after spawning it - -// range values -float RANGE_MELEE = 0; -float RANGE_NEAR = 1; -float RANGE_MID = 2; -float RANGE_FAR = 3; - -float DMG_KNIGHT_MELEE_BASE = 0; -float DMG_KNIGHT_MELEE_RANDOM1 = 3; -float DMG_KNIGHT_MELEE_RANDOM2 = 3; -float DMG_KNIGHT_MELEE_RANDOM3 = 3; - -.float show_hostile; - // set to time+0.2 whenever a client fires a - // weapon or takes damage. Used to alert - // monsters that otherwise would let the player go - -float movedist; -.float lefty; -.float search_time; -.float attack_state; - -float AS_STRAIGHT = 1; -float AS_SLIDING = 2; -float AS_MELEE = 3; -float AS_MISSILE = 4; - -float SKILL4_MINALPHA = 0.4; - -float monsterwander; -//#NO AUTOCVARS START -/* - monsterwander = cvar("monsterwander"); - // monsterwander is always on in skill 5 - if (skill >= 5) - monsterwander = TRUE; -*/ -//#NO AUTOCVARS END - -.float candrown; - -.void(vector org, float bodydamage, float armordamage, vector vel, float damgtype) bleedfunc; -void(vector org, float bodydamage, float armordamage, vector vel, float damgtype) genericbleedfunc; diff --git a/qcsrc/server/attic/fight.qc b/qcsrc/server/attic/fight.qc deleted file mode 100644 index a8fcd8e70..000000000 --- a/qcsrc/server/attic/fight.qc +++ /dev/null @@ -1,252 +0,0 @@ - -/* - -A monster is in fight mode if it thinks it can effectively attack its -enemy. - -When it decides it can't attack, it goes into hunt mode. - -*/ - -void SUB_AttackFinished (float normal) -{ - self.cnt = 0; // refire count for nightmare - if (skill < 3) - ATTACK_FINISHED(self) = time + normal; -} - -float CanDamage(entity targ, entity inflictor) -{ - if (targ.movetype == MOVETYPE_PUSH) - { - traceline(inflictor.origin, 0.5 * (targ.absmin + targ.absmax), TRUE, self); - if (trace_fraction == 1) - return TRUE; - if (trace_ent == targ) - return TRUE; - return FALSE; - } - - traceline(inflictor.origin, targ.origin, TRUE, self); - if (trace_fraction == 1) - return TRUE; - traceline(inflictor.origin, targ.origin + '15 15 0', TRUE, self); - if (trace_fraction == 1) - return TRUE; - traceline(inflictor.origin, targ.origin + '-15 -15 0', TRUE, self); - if (trace_fraction == 1) - return TRUE; - traceline(inflictor.origin, targ.origin + '-15 15 0', TRUE, self); - if (trace_fraction == 1) - return TRUE; - traceline(inflictor.origin, targ.origin + '15 -15 0', TRUE, self); - if (trace_fraction == 1) - return TRUE; - - return FALSE; -} - -float(float v) anglemod; - -void(vector dest) ChooseTurn; - -void() ai_face; - - -float enemy_range; - - -//============================================================================= - -/* -=========== -GenericCheckAttack - -The player is in view, so decide to move or launch an attack -Returns FALSE if movement should continue -============ -*/ -float() GenericCheckAttack = -{ - vector spot1, spot2; - entity targ; - float chance; - - if (self.health < 1) - return FALSE; - targ = self.enemy; - - if (vlen(targ.origin - self.origin) > 5000) // long traces are slow - return FALSE; - -// 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) - return FALSE; // don't have a clear shot - - if (trace_inopen && trace_inwater) - return FALSE; // sight line crossed contents - - if (enemy_range == RANGE_MELEE) - { // melee attack - if (self.th_melee) - { - self.th_melee (); - return TRUE; - } - } - -// missile attack - if (time < ATTACK_FINISHED(self)) - return FALSE; - - if (!self.th_missile) - return FALSE; - - if (enemy_range == RANGE_FAR) - return FALSE; - - if (enemy_range == RANGE_MELEE) - { - chance = 0.9; - ATTACK_FINISHED(self) = 0; - } - else if (enemy_range == RANGE_NEAR) - { - if (self.th_melee) - chance = 0.2; - else - chance = 0.4; - } - else if (enemy_range == RANGE_MID) - { - if (self.th_melee) - chance = 0.05; - else - chance = 0.1; - } - else - chance = 0; - - if (random () < chance) - if (self.th_missile ()) - { - SUB_AttackFinished (2*random()); - return TRUE; - } - - return FALSE; -} - - -/* -============= -ai_face - -Stay facing the enemy -============= -*/ -void() ai_face = -{ - self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin); - ChangeYaw (); -} - -/* -============= -ai_charge - -The monster is in a melee attack, so get as close as possible to .enemy -============= -*/ -float (entity targ) visible; -float(entity targ) infront; -float(entity targ) range; - -void(float d) ai_charge = -{ - if (self.health < 1) - return; - ai_face (); - movetogoal (d); // done in C code... -} - -void() ai_charge_side = -{ - if (self.health < 1) - return; - vector dtemp; - float heading; - -// aim to the left of the enemy for a flyby - - self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin); - ChangeYaw (); - - makevectors (self.angles); - dtemp = self.enemy.origin - 30*v_right; - heading = vectoyaw(dtemp - self.origin); - - walkmove(heading, 20); -} - - -/* -============= -ai_melee - -============= -*/ -void() ai_melee = -{ - vector delta; - float ldmg; - - if (self.health < 1) - return; - if (!self.enemy) - return; // removed before stroke - - delta = self.enemy.origin - self.origin; - - if (vlen(delta) > 60) - return; - - ldmg = DMG_KNIGHT_MELEE_BASE + DMG_KNIGHT_MELEE_RANDOM1 * random(); - ldmg = ldmg + DMG_KNIGHT_MELEE_RANDOM2 * random(); - ldmg = ldmg + DMG_KNIGHT_MELEE_RANDOM3 * random(); - traceline(self.origin, self.enemy.origin, FALSE, self); - - Damage (self.enemy, self, self, ldmg, self.projectiledeathtype, trace_endpos, '0 0 0'); // TODO add force to monster melee attacks? -} - - -void() ai_melee_side = -{ - vector delta; - float ldmg; - - if (self.health < 1) - return; - if (!self.enemy) - return; // removed before stroke - - ai_charge_side(); - - delta = self.enemy.origin - self.origin; - - if (vlen(delta) > 60) - return; - if (!CanDamage (self.enemy, self)) - return; - ldmg = DMG_KNIGHT_MELEE_BASE + DMG_KNIGHT_MELEE_RANDOM1 * random(); - ldmg = ldmg + DMG_KNIGHT_MELEE_RANDOM2 * random(); - ldmg = ldmg + DMG_KNIGHT_MELEE_RANDOM3 * random(); - traceline(self.origin, self.enemy.origin, FALSE, self); - Damage (self.enemy, self, self, ldmg, self.projectiledeathtype, trace_endpos, '0 0 0'); -} - diff --git a/qcsrc/server/attic/m_monsters.qc b/qcsrc/server/attic/m_monsters.qc deleted file mode 100644 index 3e160d97b..000000000 --- a/qcsrc/server/attic/m_monsters.qc +++ /dev/null @@ -1,475 +0,0 @@ -/* ALL MONSTERS SHOULD BE 1 0 0 IN COLOR */ - -// name =[framenum, nexttime, nextthink] {code} -// expands to: -// name () -// { -// self.frame=framenum; -// self.nextthink = time + nexttime; -// self.think = nextthink -// -// } - -.float ismonster; - -.float modelindex2; - -/* -================ -monster_use - -Using a monster makes it angry at the current activator -LordHavoc: using a monster with the spawnflag 'Appear' makes it appear -================ -*/ -void() monster_use = -{ - if (self.enemy) - return; - if (self.health < 1) - return; - if (self.mdl) - if (self.spawnflags & MONSTER_APPEAR) - { - self.nextthink = time + 0.1; - self.spawnflags = self.spawnflags - MONSTER_APPEAR; - self.solid = SOLID_SLIDEBOX; - self.takedamage = DAMAGE_AIM; - //self.movetype = MOVETYPE_STEP; - self.model = self.mdl; - self.mdl = ""; - self.modelindex = self.modelindex2; - self.modelindex2 = 0; - //setorigin(self, self.origin + '0 0 1'); - spawn_tdeath(self.origin, self, self.origin); - return; - } - -#if 0 - if (activator.items & IT_INVISIBILITY) - return; -#endif - if (activator.flags & FL_NOTARGET) - return; - if (activator.classname != "player") - return; - - // delay reaction so if the monster is teleported, its sound is still heard - self.enemy = activator; - self.nextthink = time + 0.1; - self.think = FoundTarget; -} - -void() monster_appearsetup = -{ - if ((self.spawnflags & MONSTER_APPEAR) == 0) - return; - self.mdl = self.model; - self.modelindex2 = self.modelindex; - self.modelindex = 0; - self.solid = SOLID_NOT; - self.takedamage = DAMAGE_NO; - //self.movetype = MOVETYPE_NONE; - self.nextthink = -1; - self.model = ""; -} - -/* -================ -monster_setalpha - -Sets relative alpha of monster in skill 4 mode. -================ -*/ -void(float a) monster_setalpha = -{ - if (skill < 4 || self.classname == "monster_hellfish") - { - self.alpha = 1.0; - return; - } - - if (skill >= 5) - { - // randomly forget enemy, this makes monsters randomly return to their normal ghostlike state - if (a == 0) - if (self.enemy) - if (random() < 0.1) - self.enemy = world; - // randomly blink (playing the same alarming sound as if attacking) - if (self.enemy == world) - { - a = 0; - if (time >= 0.3) // don't blink during the init process because it might become permanent - if (random() < 0.005) - { - // blink for an instant, this causes the appear sound, alarming the player as if under attack - /* PLEASE FIX THE SOUND CHANNEL BEFORE ACTIVATING THIS - sound(self, CHAN_AUTO, "wizard/wsight.wav", 1, ATTN_NORM); - */ - a = 1; - } - } - // if ghosted, become non-solid and immune to damage - if (a <= 0 || self.enemy == world) - { - self.solid = SOLID_NOT; - self.takedamage = DAMAGE_NO; - } - else - { - // if unghosting, make sure we have an enemy, otherwise stay ghosted (even if blinking) so we can't be shot while blinking - /* PLEASE FIX THE SOUND CHANNEL BEFORE ACTIVATING THIS - if (self.solid != SOLID_SLIDEBOX) - sound(self, CHAN_AUTO, "wizard/wsight.wav", 1, ATTN_NORM); - */ - self.solid = SOLID_SLIDEBOX; - self.takedamage = DAMAGE_AIM; - } - } - self.alpha = SKILL4_MINALPHA + (1 - SKILL4_MINALPHA) * bound(0, a, 1); -} - -/* -================ -monster_death_use - -When a mosnter dies, it fires all of its targets with the current -enemy as activator. -================ -*/ -void() monster_death_use = -{ -// fall to ground - if (self.flags & FL_FLY) - self.flags = self.flags - FL_FLY; - if (self.flags & FL_SWIM) - self.flags = self.flags - FL_SWIM; - - if (!self.target) - return; - - activator = self.enemy; - SUB_UseTargets (); -} - - -void() monsterinwall = -{ - entity e; - if (!autocvar_developer) - return; - // this is handy for level designers, - // puts a spikey ball where the error is... - e = spawn(); - setorigin(e, self.origin); - setmodel (e, "models/ebomb.mdl"); - e.movetype = MOVETYPE_NONE; - e.solid = SOLID_NOT; - e.think = SUB_Null; - e.nextthink = -1; - e.scale = 16; -} - -//============================================================================ - -void() walkmonster_start_go = -{ - self.origin_z = self.origin_z + 1; // raise off floor a bit - - tracebox(self.origin, self.mins, self.maxs, self.origin, TRUE, self); - if (trace_startsolid) - { - dprint("walkmonster in wall at: "); - dprint(vtos(self.origin)); - dprint("\n"); - monsterinwall(); - droptofloor(); - } - else - { - droptofloor(); - if (!walkmove(0,0)) - { - dprint("walkmonster in wall at: "); - dprint(vtos(self.origin)); - dprint("\n"); - monsterinwall(); - } - } - - //self.cantrigger = TRUE; - - self.takedamage = DAMAGE_AIM; - - self.ideal_yaw = self.angles * '0 1 0'; - if (!self.yaw_speed) - self.yaw_speed = 20; - self.view_ofs = '0 0 25'; - self.use = monster_use; - - self.flags = self.flags | FL_MONSTER; - - if (monsterwander) - self.spawnflags = self.spawnflags | MONSTER_WANDER; - - if (self.target) - { - self.goalentity = self.movetarget = find(world, targetname, self.target); - self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); - if (!self.movetarget) - { - dprint("Monster can't find target at "); - dprint(vtos(self.origin)); - dprint("\n"); - } - // this used to be an objerror - if (self.movetarget.classname == "path_corner") - self.th_walk (); - else - { - if ((self.spawnflags & MONSTER_WANDER) && (!self.monsterawaitingteleport) && (self.spawnflags & 3) == 0 && (world.model != "maps/e1m7.bsp")) - { - monster_spawnwanderpath(); - self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); - self.th_walk (); - } - else - { - self.pausetime = 99999999; - self.th_stand (); - } - } - } - else - { - if ((self.spawnflags & MONSTER_WANDER) && (!self.monsterawaitingteleport) && (self.spawnflags & 3) == 0 && (world.model != "maps/e1m7.bsp")) - { - monster_spawnwanderpath(); - self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); - self.th_walk (); - } - else - { - self.pausetime = 99999999; - self.th_stand (); - } - } - -// spread think times so they don't all happen at same time - self.nextthink = self.nextthink + random()*0.5 + 0.1; - self.iscreature = TRUE; - self.damagedbycontents = TRUE; - - force_retouch = 2; // mainly to detect teleports - - monster_appearsetup(); -} - - -void() walkmonster_start = -{ - self.candrown = 1; // this is turned off by some monsters like zombies - // delay drop to floor to make sure all doors have been spawned - // spread think times so they don't all happen at same time - self.nextthink = time + random()*0.5 + 0.3; - self.think = walkmonster_start_go; - total_monsters = total_monsters + 1; - self.bot_attack = TRUE; - self.frags = 2; // actually just used to get havocbots to attack it... - self.bleedfunc = genericbleedfunc; - self.ismonster = TRUE; - - monster_setalpha (0); -} - - - -void() flymonster_start_go = -{ - self.takedamage = DAMAGE_AIM; - - self.ideal_yaw = self.angles * '0 1 0'; - if (!self.yaw_speed) - self.yaw_speed = 10; - self.view_ofs = '0 0 25'; - self.use = monster_use; - - self.flags = self.flags | FL_FLY; - self.flags = self.flags | FL_MONSTER; - - if (!walkmove(0,0)) - { - dprint("flymonster in wall at: "); - dprint(vtos(self.origin)); - dprint("\n"); - monsterinwall(); - } - - //self.cantrigger = TRUE; - - if (monsterwander) - self.spawnflags = self.spawnflags | MONSTER_WANDER; - - if (self.target) - { - self.goalentity = self.movetarget = find(world, targetname, self.target); - if (!self.movetarget) - { - dprint("Monster can't find target at "); - dprint(vtos(self.origin)); - dprint("\n"); - } - // this used to be an objerror - if (self.movetarget.classname == "path_corner") - self.th_walk (); - else - { - if ((self.spawnflags & MONSTER_WANDER) && (!self.monsterawaitingteleport) && (self.spawnflags & 3) == 0 && (world.model != "maps/e1m7.bsp")) - { - monster_spawnwanderpath(); - self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); - self.th_walk (); - } - else - { - self.pausetime = 99999999; - self.th_stand (); - } - } - } - else - { - if ((self.spawnflags & MONSTER_WANDER) && (!self.monsterawaitingteleport) && (self.spawnflags & 3) == 0 && (world.model != "maps/e1m7.bsp")) - { - monster_spawnwanderpath(); - self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); - self.th_walk (); - } - else - { - self.pausetime = 99999999; - self.th_stand (); - } - } - self.iscreature = TRUE; - self.damagedbycontents = TRUE; - - force_retouch = 2; // mainly to detect teleports - - monster_appearsetup(); -} - -void() flymonster_start = -{ - self.candrown = 1; - // spread think times so they don't all happen at same time - self.nextthink = time + random()*0.5 + 0.1; - self.think = flymonster_start_go; - total_monsters = total_monsters + 1; - self.bot_attack = TRUE; - self.frags = 2; // actually just used to get havocbots to attack it... - self.bleedfunc = genericbleedfunc; - self.ismonster = TRUE; - - monster_setalpha (0); -} - - -void() swimmonster_start_go = -{ - if (deathmatch) - { - remove(self); - return; - } - - //self.cantrigger = TRUE; - - self.takedamage = DAMAGE_AIM; - - self.ideal_yaw = self.angles * '0 1 0'; - if (!self.yaw_speed) - self.yaw_speed = 10; - self.view_ofs = '0 0 10'; - self.use = monster_use; - - self.flags = self.flags | FL_SWIM; - self.flags = self.flags | FL_MONSTER; - - if (monsterwander) - self.spawnflags = self.spawnflags | MONSTER_WANDER; - - if (self.target) - { - self.goalentity = self.movetarget = find(world, targetname, self.target); - if (!self.movetarget) - { - dprint("Monster can't find target at "); - dprint(vtos(self.origin)); - dprint("\n"); - } - // this used to be an objerror - if (self.movetarget.classname == "path_corner") - self.th_walk (); - else - { - if ((self.spawnflags & MONSTER_WANDER) && (!self.monsterawaitingteleport) && (self.spawnflags & 3) == 0 && (world.model != "maps/e1m7.bsp")) - { - monster_spawnwanderpath(); - self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); - self.th_walk (); - } - else - { - self.pausetime = 99999999; - self.th_stand (); - } - } - } - else - { - if ((self.spawnflags & MONSTER_WANDER) && (!self.monsterawaitingteleport) && (self.spawnflags & 3) == 0 && (world.model != "maps/e1m7.bsp")) - { - monster_spawnwanderpath(); - self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); - self.th_walk (); - } - else - { - self.pausetime = 99999999; - self.th_stand (); - } - } - self.iscreature = TRUE; - self.damagedbycontents = TRUE; - - force_retouch = 2; // mainly to detect teleports - - monster_appearsetup(); -} - -void() swimmonster_start = -{ - // spread think times so they don't all happen at same time - self.candrown = 0; - self.nextthink = time + random()*0.5 + 0.1; - self.think = swimmonster_start_go; - total_monsters = total_monsters + 1; - self.bot_attack = TRUE; - self.frags = 2; // actually just used to get havocbots to attack it... - self.bleedfunc = genericbleedfunc; - self.ismonster = TRUE; - - monster_setalpha(0); -} - -void(vector org, float bodydamage, float armordamage, vector force, float damgtype) genericbleedfunc = -{ - vector v; - v = '0 0 0' - force * 0.05; - if (armordamage > 0) - te_spark(org, v, armordamage * 3); - if (bodydamage > 0) - te_blood(org, v, bodydamage); -} diff --git a/qcsrc/server/attic/monster_zombie.qc b/qcsrc/server/attic/monster_zombie.qc deleted file mode 100644 index c95c2eaf2..000000000 --- a/qcsrc/server/attic/monster_zombie.qc +++ /dev/null @@ -1,575 +0,0 @@ -//#define MONSTES_ENABLED -#ifdef MONSTES_ENABLED - -float autocvar_g_monster_zombie_attack_run_damage; -float autocvar_g_monster_zombie_attack_run_delay; -float autocvar_g_monster_zombie_attack_run_force; -float autocvar_g_monster_zombie_attack_run_hitrange; -float autocvar_g_monster_zombie_attack_run_range; -float autocvar_g_monster_zombie_attack_stand_damage; -float autocvar_g_monster_zombie_attack_stand_delay; -float autocvar_g_monster_zombie_attack_stand_force; -float autocvar_g_monster_zombie_attack_stand_range; -float autocvar_g_monster_zombie_health; -float autocvar_g_monster_zombie_idle_timer_max; -float autocvar_g_monster_zombie_idle_timer_min; -float autocvar_g_monster_zombie_movespeed; -float autocvar_g_monster_zombie_respawntime; -float autocvar_g_monster_zombie_stopspeed; -float autocvar_g_monster_zombie_targetrange; -float autocvar_g_monster_zombie_turnspeed; -float autocvar_g_monsters; - - -#define zombie_anim_attackleap 0 -#define zombie_anim_attackrun1 1 -#define zombie_anim_attackrun2 2 -#define zombie_anim_attackrun3 3 -#define zombie_anim_attackstanding1 4 -#define zombie_anim_attackstanding2 5 -#define zombie_anim_attackstanding3 6 -#define zombie_anim_blockend 7 -#define zombie_anim_blockstart 8 -#define zombie_anim_deathback1 9 -#define zombie_anim_deathback2 10 -#define zombie_anim_deathback3 11 -#define zombie_anim_deathfront1 12 -#define zombie_anim_deathfront2 13 -#define zombie_anim_deathfront3 14 -#define zombie_anim_deathleft1 15 -#define zombie_anim_deathleft2 16 -#define zombie_anim_deathright1 17 -#define zombie_anim_deathright2 18 -#define zombie_anim_idle 19 -#define zombie_anim_painback1 20 -#define zombie_anim_painback2 21 -#define zombie_anim_painfront1 22 -#define zombie_anim_painfront2 23 -#define zombie_anim_runbackwards 24 -#define zombie_anim_runbackwardsleft 25 -#define zombie_anim_runbackwardsright 26 -#define zombie_anim_runforward 27 -#define zombie_anim_runforwardleft 28 -#define zombie_anim_runforwardright 29 -#define zombie_anim_spawn 30 - -#define ZOMBIE_MIN '-18 -18 -25' -#define ZOMBIE_MAX '18 18 47' - -#define ZV_IDLE 10 - -#define ZV_PATH 100 -#define ZV_HUNT 200 - -#define ZV_ATTACK_FIND 10 -#define ZV_ATTACK_RUN 20 -#define ZV_ATTACK_STAND 30 - -#define ZV_PATH2 10000 - -//.entity verbs_idle; -//.entity verbs_attack; -//.entity verbs_move; - -//.float state_timeout; -//.void() monster_state; -#define MONSTERFLAG_NORESPAWN 2 - -void zombie_spawn(); - -float zombie_scoretarget(entity trg) -{ - float tmp; - vector ang1; - - if (trg.takedamage == DAMAGE_AIM) - if not (trg.flags & FL_NOTARGET) - if (trg.deadflag == DEAD_NO) - if (trg.team != self.team) - { - if((self.origin_z - trg.origin_z) < 128) - { - ang1 = normalize(self.origin - trg.origin); - tmp = vlen(ang1 - v_forward); - if(tmp > 1.5) - { - traceline(self.origin + '0 0 47',trg.origin + '0 0 32',MOVE_NORMAL,self); - if(trace_ent != trg) - return 0; - - return (autocvar_g_monster_zombie_targetrange - vlen(self.origin - trg.origin)) * tmp; - } - else if(self.enemy == trg) - return (autocvar_g_monster_zombie_targetrange - vlen(self.origin - trg.origin)) * tmp; - } - } - - return 0; -} - -void zombie_corpse_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) -{ - //dprint("zombie_corpse_damage\n"); - Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, self, attacker); - - self.health -= damage; - - if(self.health < 0) - { - Violence_GibSplash(self, 1, 1, attacker); - remove(self); - } -} - -void zombie_die(vector dir) -{ - vector v; - float f; - - entity dummy; - - dummy = spawn(); - setmodel(dummy,"models/monsters/zombie.dpm"); - setorigin(dummy, self.origin); - dummy.velocity = self.velocity; - dummy.movetype = MOVETYPE_BOUNCE; - dummy.think = SUB_Remove; - dummy.nextthink = time + 3; - dummy.health = 50; - dummy.takedamage = DAMAGE_YES; - dummy.event_damage = zombie_corpse_damage; - dummy.solid = SOLID_CORPSE; - setsize(dummy,self.mins,self.maxs); - - SUB_SetFade(dummy,time + 5,2); - - - v = normalize(self.origin - dir); - f = vlen(v_forward - v) - 1; - if(f > 0.5) - dummy.frame = zombie_anim_deathfront1 + rint(random() * 2); - else if(f < 0.5) - dummy.frame = zombie_anim_deathback1 + rint(random() * 2); - else - { - f = vlen(v_right - v) - 1; - if(f > 0.5) - dummy.frame = zombie_anim_deathright1 + rint(random() * 2); - else if(f < 0.5) - dummy.frame = zombie_anim_deathleft1 + rint(random() * 2); - } - - - if(self.spawnflags & MONSTERFLAG_NORESPAWN) - { - self.think = SUB_Remove; - self.nextthink = time; - return; - } - - setmodel(self,""); - self.solid = SOLID_NOT; - self.takedamage = DAMAGE_NO; - self.event_damage = SUB_Null; - self.enemy = world; - self.think = zombie_spawn; - self.nextthink = time + autocvar_g_monster_zombie_respawntime; - self.pain_finished = self.nextthink; -} - -void zombie_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) -{ - - vector v; - float f; - - v = normalize(self.origin - hitloc); - f = vlen(v_forward - v) - 1; - - - self.health -= damage; - self.velocity = self.velocity + force; - if(self.health <= 0) - { - zombie_die(hitloc); - return; - } - - Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, self, attacker); - - if (damage > 50) - Violence_GibSplash_At(hitloc, force * -0.1, 3, 1, self, attacker); - if (damage > 100) - Violence_GibSplash_At(hitloc, force * -0.2, 3, 1, self, attacker); - - if (time > self.pain_finished) - { - if(f < 0.5) - { - if(random() < 0.5) - self.frame = zombie_anim_painback1; - else - self.frame = zombie_anim_painback2; - } - else - { - if(random() < 0.5) - self.frame = zombie_anim_painfront1; - else - self.frame = zombie_anim_painfront2; - } - - self.pain_finished = time + 0.36; - } -} - -.vector bvec; -.float bvec_time; - -void zombie_move() -{ - vector real_angle; - float vz, tdiff, tspeed; - - tdiff = time - self.zoomstate; - tspeed = tdiff * autocvar_g_monster_zombie_turnspeed; - vz = self.velocity_z; - self.zoomstate = time; - - if(self.bvec_time < time) - { - self.bvec_time = time + 0.2; - self.bvec = steerlib_beamsteer(steerlib_attract2(self.moveto,0.5,500,0.95),512,32,34,64); - } - - if(self.enemy) - self.moveto = self.enemy.origin; - else - self.moveto = self.origin + v_forward; - - self.steerto = normalize(steerlib_attract2(self.moveto,0.5,500,0.95) + self.bvec); - - self.angles_y = safeangle(self.angles_y); - real_angle = vectoangles(self.steerto) - self.angles; - self.angles_y += bound(-10, real_angle_y, 10); - - if(vlen(self.origin - self.moveto) > 64) - { - movelib_move_simple(v_forward ,autocvar_g_monster_zombie_movespeed,0.6); - if(time > self.pain_finished) - if(self.attack_finished_single < time) - self.frame = zombie_anim_runforward; - } - else - { - movelib_beak_simple(autocvar_g_monster_zombie_stopspeed); - if(time > self.pain_finished) - if(self.attack_finished_single < time) - self.frame = zombie_anim_idle; - } - - self.velocity_z = vz; - self.steerto = self.origin; -} - -float zombie_verb_idle_roam(float eval) -{ - switch (eval) - { - case VCM_EVAL: - - if(self.enemy) - return VS_CALL_NO; - - return verb.verb_static_value; - - case VCM_DO: - - self.moveto = v_forward * 128; - self.steerto = v_forward; //steerlib_beamsteer(v_forward,512,32,34,64); - - return VS_CALL_YES_DOING; - } - - return VS_CALL_YES_DONE; -} - -float zombie_verb_idle_stand(float eval) -{ - switch (eval) - { - case VCM_EVAL: - - if(self.enemy) - return VS_CALL_NO; - - return verb.verb_static_value; - - case VCM_DO: - - self.moveto = self.origin; - self.frame = zombie_anim_idle; - self.velocity = '0 0 0'; - - return VS_CALL_YES_DOING; - } - - return VS_CALL_YES_DONE; -} - -float zombie_verb_idle(float eval) -{ - switch (eval) - { - case VCM_EVAL: - - if(self.enemy) - return VS_CALL_NO; - - return verb.verb_static_value; - - case VCM_DO: - float t; - - t = autocvar_g_monster_zombie_idle_timer_max - autocvar_g_monster_zombie_idle_timer_min; - t = autocvar_g_monster_zombie_idle_timer_min + (random() * t); - - if(random() < 0.5) - verbstack_push(self.verbs_idle, zombie_verb_idle_roam, ZV_IDLE + 1, t, self); - else - verbstack_push(self.verbs_idle, zombie_verb_idle_stand, ZV_IDLE + 1, 0.1, self); - - return VS_CALL_YES_DOING; - } - - return VS_CALL_YES_DONE; -} - -float zombie_verb_attack_findtarget(float eval) -{ - switch (eval) - { - case VCM_EVAL: - if(self.enemy) - return VS_CALL_NO; - - return verb.verb_static_value; - - case VCM_DO: - - entity trg, best_trg; - float trg_score, best_trg_score; - - trg = findradius(self.origin,autocvar_g_monster_zombie_targetrange); - while(trg) - { - trg_score = zombie_scoretarget(trg); - if(trg_score > best_trg_score) - { - best_trg = trg; - best_trg_score = trg_score; - } - - trg = trg.chain; - } - - if(best_trg) - { - self.enemy = best_trg; - dprint("Selected: ",best_trg.netname, " as target.\n"); - } - - return VS_CALL_YES_DOING; - } - - return VS_CALL_YES_DONE; -} - -void zombie_runattack_damage() -{ - entity oldself; - oldself = self; - self = self.owner; - - if(vlen(self.origin - self.enemy.origin) > autocvar_g_monster_zombie_attack_run_hitrange) - return; - - if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.6) - return; - - Damage(self.enemy, self, self, autocvar_g_monster_zombie_attack_run_damage, DEATH_TURRET, self.enemy.origin, normalize(self.enemy.origin - self.origin) * autocvar_g_monster_zombie_attack_run_force); - - self = oldself; - self.think = SUB_Remove; - self.nextthink = time; -} - -float zombie_verb_attack_run(float eval) -{ - switch (eval) - { - case VCM_EVAL: - if not (self.enemy) - return VS_CALL_NO; - - if(self.attack_finished_single > time) - return VS_CALL_NO; - - if(vlen(self.origin - self.enemy.origin) > autocvar_g_monster_zombie_attack_run_range) - return VS_CALL_NO; - - if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.6) - return VS_CALL_NO; - - return verb.verb_static_value; - - case VCM_DO: - entity pain; - pain = spawn(); - pain.owner = self; - pain.think = zombie_runattack_damage; - pain.nextthink = time + autocvar_g_monster_zombie_attack_run_delay; - - self.attack_finished_single = time + 0.7; - self.frame = zombie_anim_attackrun1 + rint(random() * 2); - - return VS_CALL_YES_DOING; - } - - return VS_CALL_YES_DONE; -} - -void zombie_standattack_damage() -{ - //entity oldself; - //oldself = self; - //self = self.owner; - - setorigin(self,self.owner.origin + v_forward * 32); - RadiusDamage(self, self.owner, autocvar_g_monster_zombie_attack_stand_damage,autocvar_g_monster_zombie_attack_stand_damage,16,self, autocvar_g_monster_zombie_attack_stand_force,DEATH_TURRET,world); - //float RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity ignore, float forceintensity, float deathtype, entity directhitentity) - - - //self = oldself; - self.think = SUB_Remove; - self.nextthink = time; -} - -float zombie_verb_attack_stand(float eval) -{ - switch (eval) - { - case VCM_EVAL: - if not (self.enemy) - return VS_CALL_NO; - - if(self.attack_finished_single > time) - return VS_CALL_NO; - - if(vlen(self.origin - self.enemy.origin) > autocvar_g_monster_zombie_attack_stand_range) - return VS_CALL_NO; - - if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.8) - return VS_CALL_NO; - - return verb.verb_static_value; - - case VCM_DO: - entity pain; - pain = spawn(); - pain.owner = self; - pain.think = zombie_runattack_damage; - pain.nextthink = time + autocvar_g_monster_zombie_attack_stand_delay; - - self.attack_finished_single = time + 0.7; - self.frame = zombie_anim_attackstanding1 + rint(random() * 1); - dprint("frame:",ftos(self.frame),"\n"); - - return VS_CALL_YES_DOING; - } - - return VS_CALL_YES_DONE; -} - -void zombie_think() -{ - self.angles_x *= -1; - makevectors(self.angles); - self.angles_x *= -1; - - if (zombie_scoretarget(self.enemy) == 0) - self.enemy = world; - - verbstack_pop(self.verbs_attack); - //verbstack_pop(self.verbs_move); - - if not (self.enemy) - verbstack_pop(self.verbs_idle); - - zombie_move(); - - if(self.enemy) - self.nextthink = time; - else - self.nextthink = time + 0.2; -} - -void zombie_spawn() -{ - setmodel(self,"models/monsters/zombie.dpm"); - - self.solid = SOLID_BBOX; - self.takedamage = DAMAGE_AIM; - self.event_damage = zombie_damage; - self.enemy = world; - self.frame = zombie_anim_spawn; - self.think = zombie_think; - self.nextthink = time + 2.1; - self.pain_finished = self.nextthink; - self.movetype = MOVETYPE_WALK; - self.health = autocvar_g_monster_zombie_health; - self.velocity = '0 0 0'; - self.angles = self.pos2; - self.moveto = self.origin; - self.flags = FL_MONSTER; - - setorigin(self,self.pos1); - setsize(self,ZOMBIE_MIN,ZOMBIE_MAX); -} - - -void spawnfunc_monster_zombie() -{ - if not(autocvar_g_monsters) - { - remove(self); - return; - } - - precache_model("models/monsters/zombie.dpm"); - - - self.verbs_idle = spawn(); - self.verbs_attack = spawn(); - - self.verbs_idle.owner = self; - self.verbs_attack.owner = self; - - self.think = zombie_spawn; - self.nextthink = time + 2; - - traceline(self.origin + '0 0 10', self.origin - '0 0 32', MOVE_WORLDONLY, self); - - self.pos1 = trace_endpos; - self.pos2 = self.angles; - self.team = MAX_SHOT_DISTANCE -1; - - verbstack_push(self.verbs_idle, zombie_verb_idle, ZV_IDLE,0 , self); - - verbstack_push(self.verbs_attack, zombie_verb_attack_findtarget, ZV_ATTACK_FIND,0 , self); - verbstack_push(self.verbs_attack, zombie_verb_attack_run, ZV_ATTACK_RUN,0 , self); - verbstack_push(self.verbs_attack, zombie_verb_attack_stand, ZV_ATTACK_STAND,0 , self); - -} - -#endif // MONSTES_ENABLED diff --git a/qcsrc/server/attic/monsters/ai.qc b/qcsrc/server/attic/monsters/ai.qc new file mode 100644 index 000000000..59989e7a8 --- /dev/null +++ b/qcsrc/server/attic/monsters/ai.qc @@ -0,0 +1,891 @@ +void() movetarget_f; +void() t_movetarget; +void() FoundTarget; + +float MONSTER_WANDER = 64; // disable wandering around +float MONSTER_APPEAR = 128; // spawn invisible, and appear when triggered + +.float ismonster; +.float monsterawaitingteleport; // avoid awaking monsters in teleport rooms + +// when a monster becomes angry at a player, that monster will be used +// as the sight target the next frame so that monsters near that one +// will wake up even if they wouldn't have noticed the player +// +entity sight_entity; +float sight_entity_time; + +/* + +.enemy +Will be world if not currently angry at anyone. + +.movetarget +The next path spot to walk toward. If .enemy, ignore .movetarget. +When an enemy is killed, the monster will try to return to it's path. + +.huntt_ime +Set to time + something when the player is in sight, but movement straight for +him is blocked. This causes the monster to use wall following code for +movement direction instead of sighting on the player. + +.ideal_yaw +A yaw angle of the intended direction, which will be turned towards at up +to 45 deg / state. If the enemy is in view and hunt_time is not active, +this will be the exact line towards the enemy. + +.pausetime +A monster will leave it's stand state and head towards it's .movetarget when +time > .pausetime. + +walkmove(angle, speed) primitive is all or nothing +*/ + + +// +// globals +// +//float current_yaw; + +float(float v) anglemod = +{ + v = v - 360 * floor(v / 360); + return v; +} + +/* +============================================================================== + +MOVETARGET CODE + +The angle of the movetarget effects standing and bowing direction, but has no effect on movement, which allways heads to the next target. + +targetname +must be present. The name of this movetarget. + +target +the next spot to move to. If not present, stop here for good. + +pausetime +The number of seconds to spend standing or bowing for path_stand or path_bow + +============================================================================== +*/ + + +void() movetarget_f = +{ + if (!self.targetname) + objerror ("monster_movetarget: no targetname"); + + self.solid = SOLID_TRIGGER; + self.touch = t_movetarget; + setsize (self, '-8 -8 -8', '8 8 8'); +} + +/*QUAKED path_corner (0.5 0.3 0) (-8 -8 -8) (8 8 8) +Monsters will continue walking towards the next target corner. +*/ +void() path_corner = +{ + movetarget_f (); +} + +/* +============= +t_movetarget + +Something has bumped into a movetarget. If it is a monster +moving towards it, change the next destination and continue. +============== +*/ +void() t_movetarget = +{ + entity temp; + + if (other.health < 1) + return; + if (other.movetarget != self) + return; + + if (other.enemy) + return; // fighting, not following a path + + temp = self; + self = other; + other = temp; + + /* PLEASE FIX THE SOUND CHANNEL BEFORE ACTIVATING THIS + if (self.classname == "monster_ogre") + sound (self, CHAN_VOICE, "ogre/ogdrag.wav", 1, ATTN_IDLE);// play chainsaw drag sound + */ + +//dprint ("t_movetarget\n"); + self.goalentity = self.movetarget = find (world, targetname, other.target); + self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); + if (!self.movetarget) + { + self.pausetime = time + 999999; + self.th_stand (); + return; + } +} + +void() monster_wanderpaththink = +{ + vector v, v1; + float b, c; + self.nextthink = time + random() * 10 + 1; + if (self.owner.health < 1) // dead, also handled in death code + { + self.owner.movetarget = world; + remove(self); + return; + } + b = -1; + c = 10; + while (c > 0) + { + c = c - 1; + v = randomvec(); + traceline(self.owner.origin, v * 1024 + self.owner.origin, FALSE, self); + v = trace_endpos - (normalize(v) * 16) - self.owner.origin; + if (vlen(v) > b) + { + b = vlen(v); + v1 = v; + } + } + setorigin(self, v1 + self.owner.origin); + self.owner.ideal_yaw = vectoyaw(self.origin - self.owner.origin); +} + +void() monster_wanderpathtouch = +{ + if (other.health < 1) + return; + if (other.movetarget != self) + return; + + if (other.enemy) + return; // fighting, not following a path + + /* PLEASE FIX THE SOUND CHANNEL BEFORE ACTIVATING THIS + if (other.classname == "monster_ogre") + sound (other, CHAN_VOICE, "ogre/ogdrag.wav", 1, ATTN_IDLE);// play chainsaw drag sound + */ + monster_wanderpaththink(); +} + +void() monster_spawnwanderpath = +{ + newmis = spawn(); + newmis.classname = "monster_wanderpath"; + newmis.solid = SOLID_TRIGGER; + newmis.touch = monster_wanderpathtouch; + setsize (newmis, '-8 -8 -8', '8 8 8'); + newmis.think = monster_wanderpaththink; + newmis.nextthink = time + random() * 10 + 1; + newmis.owner = self; + self.goalentity = self.movetarget = newmis; +} + +void() monster_checkbossflag = +{ +//#NO AUTOCVARS START +#if 0 + float healthboost; + float r; + + // monsterbosses cvar or spawnflag 64 causes a monster to be a miniboss + if ((self.spawnflags & 64) || (random() * 100 < cvar("monsterbosspercent"))) + { + self.radsuit_finished = time + 1000000000; + r = random() * 4; + if (r < 2) + { + self.super_damage_finished = time + 1000000000; + healthboost = 30 + self.health * 0.5; + self.effects = self.effects | (EF_FULLBRIGHT | EF_BLUE); + } + if (r >= 1) + { + healthboost = 30 + self.health * bound(0.5, skill * 0.5, 1.5); + self.effects = self.effects | (EF_FULLBRIGHT | EF_RED); + self.healthregen = max(self.healthregen, min(skill * 10, 30)); + } + self.health = self.health + healthboost; + self.max_health = self.health; + self.bodyhealth = self.bodyhealth * 2 + healthboost; + do + { + self.colormod_x = random(); + self.colormod_y = random(); + self.colormod_z = random(); + self.colormod = normalize(self.colormod); + } + while (self.colormod_x > 0.6 && self.colormod_y > 0.6 && self.colormod_z > 0.6); + } +#endif +//#NO AUTOCVARS END +} + + +//============================================================================ + +/* +============= +range + +returns the range catagorization of an entity reletive to self +0 melee range, will become hostile even if back is turned +1 visibility and infront, or visibility and show hostile +2 infront and show hostile +3 only triggered by damage +============= +*/ +float(entity targ) range = +{ + float r; + r = vlen ((self.origin + self.view_ofs) - (targ.origin + targ.view_ofs)); + if (r < 120) + return RANGE_MELEE; + if (r < 500) + return RANGE_NEAR; + if (r < 2000) // increased from 1000 for DP + return RANGE_MID; + return RANGE_FAR; +} + +/* +============= +visible + +returns 1 if the entity is visible to self, even if not infront () +============= +*/ +float (entity targ) visible = +{ + if (vlen(targ.origin - self.origin) > 5000) // long traces are slow + return FALSE; + + traceline ((self.origin + self.view_ofs), (targ.origin + targ.view_ofs), TRUE, self); // see through other monsters + + if (trace_inopen && trace_inwater) + return FALSE; // sight line crossed contents + + if (trace_fraction == 1) + return TRUE; + return FALSE; +} + + +/* +============= +infront + +returns 1 if the entity is in front (in sight) of self +============= +*/ +float(entity targ) infront = +{ + float dot; + + makevectors (self.angles); + dot = normalize (targ.origin - self.origin) * v_forward; + + return (dot > 0.3); +} +// returns 0 if not infront, or the dotproduct if infront +float(vector dir, entity targ) infront2 = +{ + float dot; + + dir = normalize(dir); + dot = normalize (targ.origin - self.origin) * dir; + + if (dot >= 0.3) return dot; // infront + return 0; +} + + +//============================================================================ + +/* +=========== +ChangeYaw + +Turns towards self.ideal_yaw at self.yaw_speed +Sets the global variable current_yaw +Called every 0.1 sec by monsters +============ +*/ +/* + +void() ChangeYaw = +{ + float ideal, move; + +//current_yaw = self.ideal_yaw; +// mod down the current angle + current_yaw = anglemod( self.angles_y ); + ideal = self.ideal_yaw; + + if (current_yaw == ideal) + return; + + move = ideal - current_yaw; + if (ideal > current_yaw) + { + if (move > 180) + move = move - 360; + } + else + { + if (move < -180) + move = move + 360; + } + + if (move > 0) + { + if (move > self.yaw_speed) + move = self.yaw_speed; + } + else + { + if (move < 0-self.yaw_speed ) + move = 0-self.yaw_speed; + } + + current_yaw = anglemod (current_yaw + move); + + self.angles_y = current_yaw; +} + +*/ + + +//============================================================================ + +void() HuntTarget = +{ + self.goalentity = self.enemy; + self.think = self.th_run; + self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin); + self.nextthink = time + 0.1; + SUB_AttackFinished (1); // wait a while before first attack +} + +.void() th_sightsound; + +void() SightSound = +{ + if (self.health < 1) + return; + // skill 5 does not play sight sounds, instead you only hear the appear sound as they are about to attack + if (skill >= 5) + if (self.classname != "monster_hellfish") + return; + + if (self.th_sightsound) + self.th_sightsound(); +} + +void() FoundTarget = +{ + if (self.health < 1 || !self.th_run) + return; + if (self.enemy.health < 1 || !self.enemy.takedamage) + return; + if (self.enemy.classname == "player") + { + // let other monsters see this monster for a while + sight_entity = self; + sight_entity_time = time + 0.1; + } + + self.show_hostile = time + 1; // wake up other monsters + + SightSound (); + HuntTarget (); +} + +/* +//float checkplayertime; +entity lastcheckplayer; +entity havocbot_list; + + +entity() checkplayer = +{ + entity check; + float worldcount; + // we can just fallback on checkclient if there are no bots + if (!havocbot_list) + return checkclient(); +*/ + /* + if (time < checkplayertime) + { + traceline(self.origin + self.view_ofs, lastcheckplayer.origin + lastcheckplayer.view_ofs, TRUE, self); + if (trace_fraction == 1) + return lastcheckplayer; + if (trace_ent == lastcheckplayer) + return lastcheckplayer; + } + checkplayertime = time + 0.1; + */ +/* + check = lastcheckplayer; + worldcount = 0; + c = 0; + do + { + c = c + 1; + check = findfloat(check, havocattack, TRUE); + if (check.classname == "player" || check.classname == "turretbase") + { + traceline(self.origin + self.view_ofs, check.origin + check.view_ofs, TRUE, self); + if (trace_fraction == 1) + return lastcheckplayer = check; + if (trace_ent == check) + return lastcheckplayer = check; + } + else if (check == world) + { + worldcount = worldcount + 1; + if (worldcount >= 2) + return lastcheckplayer = check; + } + } + while(check != lastcheckplayer && c < 100); + return world; +} +*/ + +/* +=========== +FindTarget + +Self is currently not attacking anything, so try to find a target + +Returns TRUE if an enemy was sighted + +When a player fires a missile, the point of impact becomes a fakeplayer so +that monsters that see the impact will respond as if they had seen the +player. + +To avoid spending too much time, only a single client (or fakeclient) is +checked each frame. This means multi player games will have slightly +slower noticing monsters. +============ +*/ +.float findtarget; +float() FindTarget = +{ + entity client; + float r; + + if (self.health < 1) + return FALSE; + + // if the first or second spawnflag bit is set, the monster will only + // wake up on really seeing the player, not another monster getting angry + + if (self.spawnflags & 3) + { + // don't wake up on seeing another monster getting angry + client = checkclient (); + if (!client) + return FALSE; // current check entity isn't in PVS + } + else + { + if (sight_entity_time >= time) + { + client = sight_entity; + if (client.enemy == self.enemy) + return TRUE; + } + else + { + client = checkclient (); + if (!client) + return FALSE; // current check entity isn't in PVS + } + } + + if (client == self.enemy) + return FALSE; + + if (client.flags & FL_NOTARGET) + return FALSE; + +#if 0 + if (client.items & IT_INVISIBILITY) + return FALSE; +#endif + + // on skill 5 the monsters usually ignore the player and remain ghostlike + if (skill >= 5) + if (self.classname != "monster_hellfish") + if (random() < 0.99) + return FALSE; + + r = range(client); + if (r == RANGE_FAR) + return FALSE; + + if (!visible (client)) + return FALSE; + + if (r == RANGE_NEAR) + { + if (client.show_hostile < time && !infront (client)) + return FALSE; + } + else if (r == RANGE_MID) + { + // LordHavoc: was if ( /* client.show_hostile < time || */ !infront (client)) + if (client.show_hostile < time && !infront (client)) + return FALSE; + } + + // + // got one + // + + if (client.model == "") + return FALSE; + self.enemy = client; + if (self.enemy.classname != "player" && self.enemy.classname != "turretbase") + { + self.enemy = self.enemy.enemy; + if (self.enemy.classname != "player" && self.enemy.classname != "turretbase") + { + self.enemy = world; + return FALSE; + } + } + + FoundTarget (); + + return TRUE; +} + + +//============================================================================= + +void(float dist) ai_forward = +{ + walkmove (self.angles_y, dist); +} + +void(float dist) ai_back = +{ + walkmove ( (self.angles_y+180), dist); +} + + +void(float a) monster_setalpha; + +/* +============= +ai_pain + +stagger back a bit +============= +*/ +void(float dist) ai_pain = +{ + if (self.health < 1) + return; + ai_back (dist); +} + +/* +============= +ai_painforward + +stagger back a bit +============= +*/ +void(float dist) ai_painforward = +{ + if (self.health < 1) + return; + walkmove (self.ideal_yaw, dist); +} + +/* +============= +ai_walk + +The monster is walking it's beat +============= +*/ +void(float dist) ai_walk = +{ + if (self.health < 1) + return; + + movedist = dist; + + // check for noticing a player + if (self.oldenemy.takedamage) + if (self.oldenemy.health >= 1) + { + self.enemy = self.oldenemy; + self.oldenemy = world; + FoundTarget(); + monster_setalpha(0); + return; + } + if (self.enemy) + { + if (self.enemy.takedamage) + { + if (self.enemy.health >= 1) + { + FoundTarget(); + monster_setalpha(0); + return; + } + else + self.enemy = world; + } + else + self.enemy = world; + } + + self.findtarget = TRUE; + + movetogoal (dist); + monster_setalpha(0); +} + + +/* +============= +ai_stand + +The monster is staying in one place for a while, with slight angle turns +============= +*/ +void() ai_stand = +{ + if (self.health < 1) + return; + if (self.enemy) + { + if (self.enemy.takedamage) + { + if (self.enemy.health >= 1) + { + FoundTarget(); + monster_setalpha(0); + return; + } + else + self.enemy = world; + } + else + self.enemy = world; + } + self.findtarget = TRUE; + + if (time > self.pausetime) + { + self.th_walk (); + monster_setalpha(0); + return; + } + +// change angle slightly + + monster_setalpha(0); +} + +/* +============= +ai_turn + +don't move, but turn towards ideal_yaw +============= +*/ +void() ai_turn = +{ + if (self.enemy) + { + if (self.enemy.takedamage) + { + if (self.enemy.health >= 1) + { + FoundTarget(); + monster_setalpha(0); + return; + } + else + self.enemy = world; + } + else + self.enemy = world; + } + self.findtarget = TRUE; + + ChangeYaw (); + monster_setalpha(0); +} + +//============================================================================= + +/* +============= +ChooseTurn +============= +*/ +void(vector pDestvec) ChooseTurn = +{ + vector dir, newdir; + + dir = self.origin - pDestvec; + + newdir_x = trace_plane_normal_y; + newdir_y = 0 - trace_plane_normal_x; + newdir_z = 0; + + if (dir * newdir > 0) + { + dir_x = 0 - trace_plane_normal_y; + dir_y = trace_plane_normal_x; + } + else + { + dir_x = trace_plane_normal_y; + dir_y = 0 - trace_plane_normal_x; + } + + dir_z = 0; + self.ideal_yaw = vectoyaw(dir); +} + +/* +============ +FacingIdeal + +============ +*/ +float() FacingIdeal = +{ + float delta; + + delta = anglemod(self.angles_y - self.ideal_yaw); + if (delta > 45 && delta < 315) + return FALSE; + return TRUE; +} + + +//============================================================================= + +.float() th_checkattack; + + + +/* +============= +ai_run + +The monster has an enemy it is trying to kill +============= +*/ +void(float dist) ai_run = +{ + float ofs; + if (self.health < 1) + return; + movedist = dist; + // see if the enemy is dead + if (self.enemy.health < 1 || self.enemy.takedamage == DAMAGE_NO) + { + self.enemy = world; + // FIXME: look all around for other targets + if (self.oldenemy.health >= 1 && self.oldenemy.takedamage) + { + self.enemy = self.oldenemy; + self.oldenemy = world; + HuntTarget (); + } + else + { + if (self.movetarget) + self.th_walk (); + else + self.th_stand (); + return; + } + } + + // wake up other monsters + self.show_hostile = time + 1; + + // check knowledge of enemy + enemy_range = range(self.enemy); + + self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin); + ChangeYaw (); + + if (self.attack_state == AS_MELEE) + { + //dprint ("ai_run_melee\n"); + //Turn and close until within an angle to launch a melee attack + if (FacingIdeal()) + { + self.th_melee (); + self.attack_state = AS_STRAIGHT; + } + return; + } + else if (self.attack_state == AS_MISSILE) + { + //dprint ("ai_run_missile\n"); + //Turn in place until within an angle to launch a missile attack + if (FacingIdeal()) + if (self.th_missile ()) + self.attack_state = AS_STRAIGHT; + return; + } + + if (self.th_checkattack()) + return; // beginning an attack + + if (visible(self.enemy)) + self.search_time = time + 5; + else if (coop) + { + // look for other coop players + if (self.search_time < time) + self.findtarget = TRUE; + } + + if (self.attack_state == AS_SLIDING) + { + //dprint ("ai_run_slide\n"); + //Strafe sideways, but stay at aproximately the same range + if (self.lefty) + ofs = 90; + else + ofs = -90; + + if (walkmove (self.ideal_yaw + ofs, movedist)) + return; + + self.lefty = !self.lefty; + + walkmove (self.ideal_yaw - ofs, movedist); + } + + // head straight in + movetogoal (dist); // done in C code... +} + diff --git a/qcsrc/server/attic/monsters/defs.qc b/qcsrc/server/attic/monsters/defs.qc new file mode 100644 index 000000000..19821429c --- /dev/null +++ b/qcsrc/server/attic/monsters/defs.qc @@ -0,0 +1,55 @@ +.entity movetarget; +.float pausetime; + +.void() th_stand; +.void() th_walk; +.void() th_run; +.float() th_missile; // LordHavoc: changed from void() to float(), returns true if attacking +.void() th_melee; +//.void(entity attacker, float damage, float damgtype, string dethtype) th_pain; // TODO Xonotic uses event_damage +//.void() th_die; // TODO never called directly by Xonotic +.entity oldenemy; // mad at this player before taking damage +entity newmis; // launch_spike sets this after spawning it + +// range values +float RANGE_MELEE = 0; +float RANGE_NEAR = 1; +float RANGE_MID = 2; +float RANGE_FAR = 3; + +float DMG_KNIGHT_MELEE_BASE = 0; +float DMG_KNIGHT_MELEE_RANDOM1 = 3; +float DMG_KNIGHT_MELEE_RANDOM2 = 3; +float DMG_KNIGHT_MELEE_RANDOM3 = 3; + +.float show_hostile; + // set to time+0.2 whenever a client fires a + // weapon or takes damage. Used to alert + // monsters that otherwise would let the player go + +float movedist; +.float lefty; +.float search_time; +.float attack_state; + +float AS_STRAIGHT = 1; +float AS_SLIDING = 2; +float AS_MELEE = 3; +float AS_MISSILE = 4; + +float SKILL4_MINALPHA = 0.4; + +float monsterwander; +//#NO AUTOCVARS START +/* + monsterwander = cvar("monsterwander"); + // monsterwander is always on in skill 5 + if (skill >= 5) + monsterwander = TRUE; +*/ +//#NO AUTOCVARS END + +.float candrown; + +.void(vector org, float bodydamage, float armordamage, vector vel, float damgtype) bleedfunc; +void(vector org, float bodydamage, float armordamage, vector vel, float damgtype) genericbleedfunc; diff --git a/qcsrc/server/attic/monsters/fight.qc b/qcsrc/server/attic/monsters/fight.qc new file mode 100644 index 000000000..a8fcd8e70 --- /dev/null +++ b/qcsrc/server/attic/monsters/fight.qc @@ -0,0 +1,252 @@ + +/* + +A monster is in fight mode if it thinks it can effectively attack its +enemy. + +When it decides it can't attack, it goes into hunt mode. + +*/ + +void SUB_AttackFinished (float normal) +{ + self.cnt = 0; // refire count for nightmare + if (skill < 3) + ATTACK_FINISHED(self) = time + normal; +} + +float CanDamage(entity targ, entity inflictor) +{ + if (targ.movetype == MOVETYPE_PUSH) + { + traceline(inflictor.origin, 0.5 * (targ.absmin + targ.absmax), TRUE, self); + if (trace_fraction == 1) + return TRUE; + if (trace_ent == targ) + return TRUE; + return FALSE; + } + + traceline(inflictor.origin, targ.origin, TRUE, self); + if (trace_fraction == 1) + return TRUE; + traceline(inflictor.origin, targ.origin + '15 15 0', TRUE, self); + if (trace_fraction == 1) + return TRUE; + traceline(inflictor.origin, targ.origin + '-15 -15 0', TRUE, self); + if (trace_fraction == 1) + return TRUE; + traceline(inflictor.origin, targ.origin + '-15 15 0', TRUE, self); + if (trace_fraction == 1) + return TRUE; + traceline(inflictor.origin, targ.origin + '15 -15 0', TRUE, self); + if (trace_fraction == 1) + return TRUE; + + return FALSE; +} + +float(float v) anglemod; + +void(vector dest) ChooseTurn; + +void() ai_face; + + +float enemy_range; + + +//============================================================================= + +/* +=========== +GenericCheckAttack + +The player is in view, so decide to move or launch an attack +Returns FALSE if movement should continue +============ +*/ +float() GenericCheckAttack = +{ + vector spot1, spot2; + entity targ; + float chance; + + if (self.health < 1) + return FALSE; + targ = self.enemy; + + if (vlen(targ.origin - self.origin) > 5000) // long traces are slow + return FALSE; + +// 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) + return FALSE; // don't have a clear shot + + if (trace_inopen && trace_inwater) + return FALSE; // sight line crossed contents + + if (enemy_range == RANGE_MELEE) + { // melee attack + if (self.th_melee) + { + self.th_melee (); + return TRUE; + } + } + +// missile attack + if (time < ATTACK_FINISHED(self)) + return FALSE; + + if (!self.th_missile) + return FALSE; + + if (enemy_range == RANGE_FAR) + return FALSE; + + if (enemy_range == RANGE_MELEE) + { + chance = 0.9; + ATTACK_FINISHED(self) = 0; + } + else if (enemy_range == RANGE_NEAR) + { + if (self.th_melee) + chance = 0.2; + else + chance = 0.4; + } + else if (enemy_range == RANGE_MID) + { + if (self.th_melee) + chance = 0.05; + else + chance = 0.1; + } + else + chance = 0; + + if (random () < chance) + if (self.th_missile ()) + { + SUB_AttackFinished (2*random()); + return TRUE; + } + + return FALSE; +} + + +/* +============= +ai_face + +Stay facing the enemy +============= +*/ +void() ai_face = +{ + self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin); + ChangeYaw (); +} + +/* +============= +ai_charge + +The monster is in a melee attack, so get as close as possible to .enemy +============= +*/ +float (entity targ) visible; +float(entity targ) infront; +float(entity targ) range; + +void(float d) ai_charge = +{ + if (self.health < 1) + return; + ai_face (); + movetogoal (d); // done in C code... +} + +void() ai_charge_side = +{ + if (self.health < 1) + return; + vector dtemp; + float heading; + +// aim to the left of the enemy for a flyby + + self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin); + ChangeYaw (); + + makevectors (self.angles); + dtemp = self.enemy.origin - 30*v_right; + heading = vectoyaw(dtemp - self.origin); + + walkmove(heading, 20); +} + + +/* +============= +ai_melee + +============= +*/ +void() ai_melee = +{ + vector delta; + float ldmg; + + if (self.health < 1) + return; + if (!self.enemy) + return; // removed before stroke + + delta = self.enemy.origin - self.origin; + + if (vlen(delta) > 60) + return; + + ldmg = DMG_KNIGHT_MELEE_BASE + DMG_KNIGHT_MELEE_RANDOM1 * random(); + ldmg = ldmg + DMG_KNIGHT_MELEE_RANDOM2 * random(); + ldmg = ldmg + DMG_KNIGHT_MELEE_RANDOM3 * random(); + traceline(self.origin, self.enemy.origin, FALSE, self); + + Damage (self.enemy, self, self, ldmg, self.projectiledeathtype, trace_endpos, '0 0 0'); // TODO add force to monster melee attacks? +} + + +void() ai_melee_side = +{ + vector delta; + float ldmg; + + if (self.health < 1) + return; + if (!self.enemy) + return; // removed before stroke + + ai_charge_side(); + + delta = self.enemy.origin - self.origin; + + if (vlen(delta) > 60) + return; + if (!CanDamage (self.enemy, self)) + return; + ldmg = DMG_KNIGHT_MELEE_BASE + DMG_KNIGHT_MELEE_RANDOM1 * random(); + ldmg = ldmg + DMG_KNIGHT_MELEE_RANDOM2 * random(); + ldmg = ldmg + DMG_KNIGHT_MELEE_RANDOM3 * random(); + traceline(self.origin, self.enemy.origin, FALSE, self); + Damage (self.enemy, self, self, ldmg, self.projectiledeathtype, trace_endpos, '0 0 0'); +} + diff --git a/qcsrc/server/attic/monsters/m_monsters.qc b/qcsrc/server/attic/monsters/m_monsters.qc new file mode 100644 index 000000000..3e160d97b --- /dev/null +++ b/qcsrc/server/attic/monsters/m_monsters.qc @@ -0,0 +1,475 @@ +/* ALL MONSTERS SHOULD BE 1 0 0 IN COLOR */ + +// name =[framenum, nexttime, nextthink] {code} +// expands to: +// name () +// { +// self.frame=framenum; +// self.nextthink = time + nexttime; +// self.think = nextthink +// +// } + +.float ismonster; + +.float modelindex2; + +/* +================ +monster_use + +Using a monster makes it angry at the current activator +LordHavoc: using a monster with the spawnflag 'Appear' makes it appear +================ +*/ +void() monster_use = +{ + if (self.enemy) + return; + if (self.health < 1) + return; + if (self.mdl) + if (self.spawnflags & MONSTER_APPEAR) + { + self.nextthink = time + 0.1; + self.spawnflags = self.spawnflags - MONSTER_APPEAR; + self.solid = SOLID_SLIDEBOX; + self.takedamage = DAMAGE_AIM; + //self.movetype = MOVETYPE_STEP; + self.model = self.mdl; + self.mdl = ""; + self.modelindex = self.modelindex2; + self.modelindex2 = 0; + //setorigin(self, self.origin + '0 0 1'); + spawn_tdeath(self.origin, self, self.origin); + return; + } + +#if 0 + if (activator.items & IT_INVISIBILITY) + return; +#endif + if (activator.flags & FL_NOTARGET) + return; + if (activator.classname != "player") + return; + + // delay reaction so if the monster is teleported, its sound is still heard + self.enemy = activator; + self.nextthink = time + 0.1; + self.think = FoundTarget; +} + +void() monster_appearsetup = +{ + if ((self.spawnflags & MONSTER_APPEAR) == 0) + return; + self.mdl = self.model; + self.modelindex2 = self.modelindex; + self.modelindex = 0; + self.solid = SOLID_NOT; + self.takedamage = DAMAGE_NO; + //self.movetype = MOVETYPE_NONE; + self.nextthink = -1; + self.model = ""; +} + +/* +================ +monster_setalpha + +Sets relative alpha of monster in skill 4 mode. +================ +*/ +void(float a) monster_setalpha = +{ + if (skill < 4 || self.classname == "monster_hellfish") + { + self.alpha = 1.0; + return; + } + + if (skill >= 5) + { + // randomly forget enemy, this makes monsters randomly return to their normal ghostlike state + if (a == 0) + if (self.enemy) + if (random() < 0.1) + self.enemy = world; + // randomly blink (playing the same alarming sound as if attacking) + if (self.enemy == world) + { + a = 0; + if (time >= 0.3) // don't blink during the init process because it might become permanent + if (random() < 0.005) + { + // blink for an instant, this causes the appear sound, alarming the player as if under attack + /* PLEASE FIX THE SOUND CHANNEL BEFORE ACTIVATING THIS + sound(self, CHAN_AUTO, "wizard/wsight.wav", 1, ATTN_NORM); + */ + a = 1; + } + } + // if ghosted, become non-solid and immune to damage + if (a <= 0 || self.enemy == world) + { + self.solid = SOLID_NOT; + self.takedamage = DAMAGE_NO; + } + else + { + // if unghosting, make sure we have an enemy, otherwise stay ghosted (even if blinking) so we can't be shot while blinking + /* PLEASE FIX THE SOUND CHANNEL BEFORE ACTIVATING THIS + if (self.solid != SOLID_SLIDEBOX) + sound(self, CHAN_AUTO, "wizard/wsight.wav", 1, ATTN_NORM); + */ + self.solid = SOLID_SLIDEBOX; + self.takedamage = DAMAGE_AIM; + } + } + self.alpha = SKILL4_MINALPHA + (1 - SKILL4_MINALPHA) * bound(0, a, 1); +} + +/* +================ +monster_death_use + +When a mosnter dies, it fires all of its targets with the current +enemy as activator. +================ +*/ +void() monster_death_use = +{ +// fall to ground + if (self.flags & FL_FLY) + self.flags = self.flags - FL_FLY; + if (self.flags & FL_SWIM) + self.flags = self.flags - FL_SWIM; + + if (!self.target) + return; + + activator = self.enemy; + SUB_UseTargets (); +} + + +void() monsterinwall = +{ + entity e; + if (!autocvar_developer) + return; + // this is handy for level designers, + // puts a spikey ball where the error is... + e = spawn(); + setorigin(e, self.origin); + setmodel (e, "models/ebomb.mdl"); + e.movetype = MOVETYPE_NONE; + e.solid = SOLID_NOT; + e.think = SUB_Null; + e.nextthink = -1; + e.scale = 16; +} + +//============================================================================ + +void() walkmonster_start_go = +{ + self.origin_z = self.origin_z + 1; // raise off floor a bit + + tracebox(self.origin, self.mins, self.maxs, self.origin, TRUE, self); + if (trace_startsolid) + { + dprint("walkmonster in wall at: "); + dprint(vtos(self.origin)); + dprint("\n"); + monsterinwall(); + droptofloor(); + } + else + { + droptofloor(); + if (!walkmove(0,0)) + { + dprint("walkmonster in wall at: "); + dprint(vtos(self.origin)); + dprint("\n"); + monsterinwall(); + } + } + + //self.cantrigger = TRUE; + + self.takedamage = DAMAGE_AIM; + + self.ideal_yaw = self.angles * '0 1 0'; + if (!self.yaw_speed) + self.yaw_speed = 20; + self.view_ofs = '0 0 25'; + self.use = monster_use; + + self.flags = self.flags | FL_MONSTER; + + if (monsterwander) + self.spawnflags = self.spawnflags | MONSTER_WANDER; + + if (self.target) + { + self.goalentity = self.movetarget = find(world, targetname, self.target); + self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); + if (!self.movetarget) + { + dprint("Monster can't find target at "); + dprint(vtos(self.origin)); + dprint("\n"); + } + // this used to be an objerror + if (self.movetarget.classname == "path_corner") + self.th_walk (); + else + { + if ((self.spawnflags & MONSTER_WANDER) && (!self.monsterawaitingteleport) && (self.spawnflags & 3) == 0 && (world.model != "maps/e1m7.bsp")) + { + monster_spawnwanderpath(); + self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); + self.th_walk (); + } + else + { + self.pausetime = 99999999; + self.th_stand (); + } + } + } + else + { + if ((self.spawnflags & MONSTER_WANDER) && (!self.monsterawaitingteleport) && (self.spawnflags & 3) == 0 && (world.model != "maps/e1m7.bsp")) + { + monster_spawnwanderpath(); + self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); + self.th_walk (); + } + else + { + self.pausetime = 99999999; + self.th_stand (); + } + } + +// spread think times so they don't all happen at same time + self.nextthink = self.nextthink + random()*0.5 + 0.1; + self.iscreature = TRUE; + self.damagedbycontents = TRUE; + + force_retouch = 2; // mainly to detect teleports + + monster_appearsetup(); +} + + +void() walkmonster_start = +{ + self.candrown = 1; // this is turned off by some monsters like zombies + // delay drop to floor to make sure all doors have been spawned + // spread think times so they don't all happen at same time + self.nextthink = time + random()*0.5 + 0.3; + self.think = walkmonster_start_go; + total_monsters = total_monsters + 1; + self.bot_attack = TRUE; + self.frags = 2; // actually just used to get havocbots to attack it... + self.bleedfunc = genericbleedfunc; + self.ismonster = TRUE; + + monster_setalpha (0); +} + + + +void() flymonster_start_go = +{ + self.takedamage = DAMAGE_AIM; + + self.ideal_yaw = self.angles * '0 1 0'; + if (!self.yaw_speed) + self.yaw_speed = 10; + self.view_ofs = '0 0 25'; + self.use = monster_use; + + self.flags = self.flags | FL_FLY; + self.flags = self.flags | FL_MONSTER; + + if (!walkmove(0,0)) + { + dprint("flymonster in wall at: "); + dprint(vtos(self.origin)); + dprint("\n"); + monsterinwall(); + } + + //self.cantrigger = TRUE; + + if (monsterwander) + self.spawnflags = self.spawnflags | MONSTER_WANDER; + + if (self.target) + { + self.goalentity = self.movetarget = find(world, targetname, self.target); + if (!self.movetarget) + { + dprint("Monster can't find target at "); + dprint(vtos(self.origin)); + dprint("\n"); + } + // this used to be an objerror + if (self.movetarget.classname == "path_corner") + self.th_walk (); + else + { + if ((self.spawnflags & MONSTER_WANDER) && (!self.monsterawaitingteleport) && (self.spawnflags & 3) == 0 && (world.model != "maps/e1m7.bsp")) + { + monster_spawnwanderpath(); + self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); + self.th_walk (); + } + else + { + self.pausetime = 99999999; + self.th_stand (); + } + } + } + else + { + if ((self.spawnflags & MONSTER_WANDER) && (!self.monsterawaitingteleport) && (self.spawnflags & 3) == 0 && (world.model != "maps/e1m7.bsp")) + { + monster_spawnwanderpath(); + self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); + self.th_walk (); + } + else + { + self.pausetime = 99999999; + self.th_stand (); + } + } + self.iscreature = TRUE; + self.damagedbycontents = TRUE; + + force_retouch = 2; // mainly to detect teleports + + monster_appearsetup(); +} + +void() flymonster_start = +{ + self.candrown = 1; + // spread think times so they don't all happen at same time + self.nextthink = time + random()*0.5 + 0.1; + self.think = flymonster_start_go; + total_monsters = total_monsters + 1; + self.bot_attack = TRUE; + self.frags = 2; // actually just used to get havocbots to attack it... + self.bleedfunc = genericbleedfunc; + self.ismonster = TRUE; + + monster_setalpha (0); +} + + +void() swimmonster_start_go = +{ + if (deathmatch) + { + remove(self); + return; + } + + //self.cantrigger = TRUE; + + self.takedamage = DAMAGE_AIM; + + self.ideal_yaw = self.angles * '0 1 0'; + if (!self.yaw_speed) + self.yaw_speed = 10; + self.view_ofs = '0 0 10'; + self.use = monster_use; + + self.flags = self.flags | FL_SWIM; + self.flags = self.flags | FL_MONSTER; + + if (monsterwander) + self.spawnflags = self.spawnflags | MONSTER_WANDER; + + if (self.target) + { + self.goalentity = self.movetarget = find(world, targetname, self.target); + if (!self.movetarget) + { + dprint("Monster can't find target at "); + dprint(vtos(self.origin)); + dprint("\n"); + } + // this used to be an objerror + if (self.movetarget.classname == "path_corner") + self.th_walk (); + else + { + if ((self.spawnflags & MONSTER_WANDER) && (!self.monsterawaitingteleport) && (self.spawnflags & 3) == 0 && (world.model != "maps/e1m7.bsp")) + { + monster_spawnwanderpath(); + self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); + self.th_walk (); + } + else + { + self.pausetime = 99999999; + self.th_stand (); + } + } + } + else + { + if ((self.spawnflags & MONSTER_WANDER) && (!self.monsterawaitingteleport) && (self.spawnflags & 3) == 0 && (world.model != "maps/e1m7.bsp")) + { + monster_spawnwanderpath(); + self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin); + self.th_walk (); + } + else + { + self.pausetime = 99999999; + self.th_stand (); + } + } + self.iscreature = TRUE; + self.damagedbycontents = TRUE; + + force_retouch = 2; // mainly to detect teleports + + monster_appearsetup(); +} + +void() swimmonster_start = +{ + // spread think times so they don't all happen at same time + self.candrown = 0; + self.nextthink = time + random()*0.5 + 0.1; + self.think = swimmonster_start_go; + total_monsters = total_monsters + 1; + self.bot_attack = TRUE; + self.frags = 2; // actually just used to get havocbots to attack it... + self.bleedfunc = genericbleedfunc; + self.ismonster = TRUE; + + monster_setalpha(0); +} + +void(vector org, float bodydamage, float armordamage, vector force, float damgtype) genericbleedfunc = +{ + vector v; + v = '0 0 0' - force * 0.05; + if (armordamage > 0) + te_spark(org, v, armordamage * 3); + if (bodydamage > 0) + te_blood(org, v, bodydamage); +} diff --git a/qcsrc/server/attic/monsters/monster_zombie.qc b/qcsrc/server/attic/monsters/monster_zombie.qc new file mode 100644 index 000000000..c95c2eaf2 --- /dev/null +++ b/qcsrc/server/attic/monsters/monster_zombie.qc @@ -0,0 +1,575 @@ +//#define MONSTES_ENABLED +#ifdef MONSTES_ENABLED + +float autocvar_g_monster_zombie_attack_run_damage; +float autocvar_g_monster_zombie_attack_run_delay; +float autocvar_g_monster_zombie_attack_run_force; +float autocvar_g_monster_zombie_attack_run_hitrange; +float autocvar_g_monster_zombie_attack_run_range; +float autocvar_g_monster_zombie_attack_stand_damage; +float autocvar_g_monster_zombie_attack_stand_delay; +float autocvar_g_monster_zombie_attack_stand_force; +float autocvar_g_monster_zombie_attack_stand_range; +float autocvar_g_monster_zombie_health; +float autocvar_g_monster_zombie_idle_timer_max; +float autocvar_g_monster_zombie_idle_timer_min; +float autocvar_g_monster_zombie_movespeed; +float autocvar_g_monster_zombie_respawntime; +float autocvar_g_monster_zombie_stopspeed; +float autocvar_g_monster_zombie_targetrange; +float autocvar_g_monster_zombie_turnspeed; +float autocvar_g_monsters; + + +#define zombie_anim_attackleap 0 +#define zombie_anim_attackrun1 1 +#define zombie_anim_attackrun2 2 +#define zombie_anim_attackrun3 3 +#define zombie_anim_attackstanding1 4 +#define zombie_anim_attackstanding2 5 +#define zombie_anim_attackstanding3 6 +#define zombie_anim_blockend 7 +#define zombie_anim_blockstart 8 +#define zombie_anim_deathback1 9 +#define zombie_anim_deathback2 10 +#define zombie_anim_deathback3 11 +#define zombie_anim_deathfront1 12 +#define zombie_anim_deathfront2 13 +#define zombie_anim_deathfront3 14 +#define zombie_anim_deathleft1 15 +#define zombie_anim_deathleft2 16 +#define zombie_anim_deathright1 17 +#define zombie_anim_deathright2 18 +#define zombie_anim_idle 19 +#define zombie_anim_painback1 20 +#define zombie_anim_painback2 21 +#define zombie_anim_painfront1 22 +#define zombie_anim_painfront2 23 +#define zombie_anim_runbackwards 24 +#define zombie_anim_runbackwardsleft 25 +#define zombie_anim_runbackwardsright 26 +#define zombie_anim_runforward 27 +#define zombie_anim_runforwardleft 28 +#define zombie_anim_runforwardright 29 +#define zombie_anim_spawn 30 + +#define ZOMBIE_MIN '-18 -18 -25' +#define ZOMBIE_MAX '18 18 47' + +#define ZV_IDLE 10 + +#define ZV_PATH 100 +#define ZV_HUNT 200 + +#define ZV_ATTACK_FIND 10 +#define ZV_ATTACK_RUN 20 +#define ZV_ATTACK_STAND 30 + +#define ZV_PATH2 10000 + +//.entity verbs_idle; +//.entity verbs_attack; +//.entity verbs_move; + +//.float state_timeout; +//.void() monster_state; +#define MONSTERFLAG_NORESPAWN 2 + +void zombie_spawn(); + +float zombie_scoretarget(entity trg) +{ + float tmp; + vector ang1; + + if (trg.takedamage == DAMAGE_AIM) + if not (trg.flags & FL_NOTARGET) + if (trg.deadflag == DEAD_NO) + if (trg.team != self.team) + { + if((self.origin_z - trg.origin_z) < 128) + { + ang1 = normalize(self.origin - trg.origin); + tmp = vlen(ang1 - v_forward); + if(tmp > 1.5) + { + traceline(self.origin + '0 0 47',trg.origin + '0 0 32',MOVE_NORMAL,self); + if(trace_ent != trg) + return 0; + + return (autocvar_g_monster_zombie_targetrange - vlen(self.origin - trg.origin)) * tmp; + } + else if(self.enemy == trg) + return (autocvar_g_monster_zombie_targetrange - vlen(self.origin - trg.origin)) * tmp; + } + } + + return 0; +} + +void zombie_corpse_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) +{ + //dprint("zombie_corpse_damage\n"); + Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, self, attacker); + + self.health -= damage; + + if(self.health < 0) + { + Violence_GibSplash(self, 1, 1, attacker); + remove(self); + } +} + +void zombie_die(vector dir) +{ + vector v; + float f; + + entity dummy; + + dummy = spawn(); + setmodel(dummy,"models/monsters/zombie.dpm"); + setorigin(dummy, self.origin); + dummy.velocity = self.velocity; + dummy.movetype = MOVETYPE_BOUNCE; + dummy.think = SUB_Remove; + dummy.nextthink = time + 3; + dummy.health = 50; + dummy.takedamage = DAMAGE_YES; + dummy.event_damage = zombie_corpse_damage; + dummy.solid = SOLID_CORPSE; + setsize(dummy,self.mins,self.maxs); + + SUB_SetFade(dummy,time + 5,2); + + + v = normalize(self.origin - dir); + f = vlen(v_forward - v) - 1; + if(f > 0.5) + dummy.frame = zombie_anim_deathfront1 + rint(random() * 2); + else if(f < 0.5) + dummy.frame = zombie_anim_deathback1 + rint(random() * 2); + else + { + f = vlen(v_right - v) - 1; + if(f > 0.5) + dummy.frame = zombie_anim_deathright1 + rint(random() * 2); + else if(f < 0.5) + dummy.frame = zombie_anim_deathleft1 + rint(random() * 2); + } + + + if(self.spawnflags & MONSTERFLAG_NORESPAWN) + { + self.think = SUB_Remove; + self.nextthink = time; + return; + } + + setmodel(self,""); + self.solid = SOLID_NOT; + self.takedamage = DAMAGE_NO; + self.event_damage = SUB_Null; + self.enemy = world; + self.think = zombie_spawn; + self.nextthink = time + autocvar_g_monster_zombie_respawntime; + self.pain_finished = self.nextthink; +} + +void zombie_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) +{ + + vector v; + float f; + + v = normalize(self.origin - hitloc); + f = vlen(v_forward - v) - 1; + + + self.health -= damage; + self.velocity = self.velocity + force; + if(self.health <= 0) + { + zombie_die(hitloc); + return; + } + + Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, self, attacker); + + if (damage > 50) + Violence_GibSplash_At(hitloc, force * -0.1, 3, 1, self, attacker); + if (damage > 100) + Violence_GibSplash_At(hitloc, force * -0.2, 3, 1, self, attacker); + + if (time > self.pain_finished) + { + if(f < 0.5) + { + if(random() < 0.5) + self.frame = zombie_anim_painback1; + else + self.frame = zombie_anim_painback2; + } + else + { + if(random() < 0.5) + self.frame = zombie_anim_painfront1; + else + self.frame = zombie_anim_painfront2; + } + + self.pain_finished = time + 0.36; + } +} + +.vector bvec; +.float bvec_time; + +void zombie_move() +{ + vector real_angle; + float vz, tdiff, tspeed; + + tdiff = time - self.zoomstate; + tspeed = tdiff * autocvar_g_monster_zombie_turnspeed; + vz = self.velocity_z; + self.zoomstate = time; + + if(self.bvec_time < time) + { + self.bvec_time = time + 0.2; + self.bvec = steerlib_beamsteer(steerlib_attract2(self.moveto,0.5,500,0.95),512,32,34,64); + } + + if(self.enemy) + self.moveto = self.enemy.origin; + else + self.moveto = self.origin + v_forward; + + self.steerto = normalize(steerlib_attract2(self.moveto,0.5,500,0.95) + self.bvec); + + self.angles_y = safeangle(self.angles_y); + real_angle = vectoangles(self.steerto) - self.angles; + self.angles_y += bound(-10, real_angle_y, 10); + + if(vlen(self.origin - self.moveto) > 64) + { + movelib_move_simple(v_forward ,autocvar_g_monster_zombie_movespeed,0.6); + if(time > self.pain_finished) + if(self.attack_finished_single < time) + self.frame = zombie_anim_runforward; + } + else + { + movelib_beak_simple(autocvar_g_monster_zombie_stopspeed); + if(time > self.pain_finished) + if(self.attack_finished_single < time) + self.frame = zombie_anim_idle; + } + + self.velocity_z = vz; + self.steerto = self.origin; +} + +float zombie_verb_idle_roam(float eval) +{ + switch (eval) + { + case VCM_EVAL: + + if(self.enemy) + return VS_CALL_NO; + + return verb.verb_static_value; + + case VCM_DO: + + self.moveto = v_forward * 128; + self.steerto = v_forward; //steerlib_beamsteer(v_forward,512,32,34,64); + + return VS_CALL_YES_DOING; + } + + return VS_CALL_YES_DONE; +} + +float zombie_verb_idle_stand(float eval) +{ + switch (eval) + { + case VCM_EVAL: + + if(self.enemy) + return VS_CALL_NO; + + return verb.verb_static_value; + + case VCM_DO: + + self.moveto = self.origin; + self.frame = zombie_anim_idle; + self.velocity = '0 0 0'; + + return VS_CALL_YES_DOING; + } + + return VS_CALL_YES_DONE; +} + +float zombie_verb_idle(float eval) +{ + switch (eval) + { + case VCM_EVAL: + + if(self.enemy) + return VS_CALL_NO; + + return verb.verb_static_value; + + case VCM_DO: + float t; + + t = autocvar_g_monster_zombie_idle_timer_max - autocvar_g_monster_zombie_idle_timer_min; + t = autocvar_g_monster_zombie_idle_timer_min + (random() * t); + + if(random() < 0.5) + verbstack_push(self.verbs_idle, zombie_verb_idle_roam, ZV_IDLE + 1, t, self); + else + verbstack_push(self.verbs_idle, zombie_verb_idle_stand, ZV_IDLE + 1, 0.1, self); + + return VS_CALL_YES_DOING; + } + + return VS_CALL_YES_DONE; +} + +float zombie_verb_attack_findtarget(float eval) +{ + switch (eval) + { + case VCM_EVAL: + if(self.enemy) + return VS_CALL_NO; + + return verb.verb_static_value; + + case VCM_DO: + + entity trg, best_trg; + float trg_score, best_trg_score; + + trg = findradius(self.origin,autocvar_g_monster_zombie_targetrange); + while(trg) + { + trg_score = zombie_scoretarget(trg); + if(trg_score > best_trg_score) + { + best_trg = trg; + best_trg_score = trg_score; + } + + trg = trg.chain; + } + + if(best_trg) + { + self.enemy = best_trg; + dprint("Selected: ",best_trg.netname, " as target.\n"); + } + + return VS_CALL_YES_DOING; + } + + return VS_CALL_YES_DONE; +} + +void zombie_runattack_damage() +{ + entity oldself; + oldself = self; + self = self.owner; + + if(vlen(self.origin - self.enemy.origin) > autocvar_g_monster_zombie_attack_run_hitrange) + return; + + if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.6) + return; + + Damage(self.enemy, self, self, autocvar_g_monster_zombie_attack_run_damage, DEATH_TURRET, self.enemy.origin, normalize(self.enemy.origin - self.origin) * autocvar_g_monster_zombie_attack_run_force); + + self = oldself; + self.think = SUB_Remove; + self.nextthink = time; +} + +float zombie_verb_attack_run(float eval) +{ + switch (eval) + { + case VCM_EVAL: + if not (self.enemy) + return VS_CALL_NO; + + if(self.attack_finished_single > time) + return VS_CALL_NO; + + if(vlen(self.origin - self.enemy.origin) > autocvar_g_monster_zombie_attack_run_range) + return VS_CALL_NO; + + if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.6) + return VS_CALL_NO; + + return verb.verb_static_value; + + case VCM_DO: + entity pain; + pain = spawn(); + pain.owner = self; + pain.think = zombie_runattack_damage; + pain.nextthink = time + autocvar_g_monster_zombie_attack_run_delay; + + self.attack_finished_single = time + 0.7; + self.frame = zombie_anim_attackrun1 + rint(random() * 2); + + return VS_CALL_YES_DOING; + } + + return VS_CALL_YES_DONE; +} + +void zombie_standattack_damage() +{ + //entity oldself; + //oldself = self; + //self = self.owner; + + setorigin(self,self.owner.origin + v_forward * 32); + RadiusDamage(self, self.owner, autocvar_g_monster_zombie_attack_stand_damage,autocvar_g_monster_zombie_attack_stand_damage,16,self, autocvar_g_monster_zombie_attack_stand_force,DEATH_TURRET,world); + //float RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity ignore, float forceintensity, float deathtype, entity directhitentity) + + + //self = oldself; + self.think = SUB_Remove; + self.nextthink = time; +} + +float zombie_verb_attack_stand(float eval) +{ + switch (eval) + { + case VCM_EVAL: + if not (self.enemy) + return VS_CALL_NO; + + if(self.attack_finished_single > time) + return VS_CALL_NO; + + if(vlen(self.origin - self.enemy.origin) > autocvar_g_monster_zombie_attack_stand_range) + return VS_CALL_NO; + + if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.8) + return VS_CALL_NO; + + return verb.verb_static_value; + + case VCM_DO: + entity pain; + pain = spawn(); + pain.owner = self; + pain.think = zombie_runattack_damage; + pain.nextthink = time + autocvar_g_monster_zombie_attack_stand_delay; + + self.attack_finished_single = time + 0.7; + self.frame = zombie_anim_attackstanding1 + rint(random() * 1); + dprint("frame:",ftos(self.frame),"\n"); + + return VS_CALL_YES_DOING; + } + + return VS_CALL_YES_DONE; +} + +void zombie_think() +{ + self.angles_x *= -1; + makevectors(self.angles); + self.angles_x *= -1; + + if (zombie_scoretarget(self.enemy) == 0) + self.enemy = world; + + verbstack_pop(self.verbs_attack); + //verbstack_pop(self.verbs_move); + + if not (self.enemy) + verbstack_pop(self.verbs_idle); + + zombie_move(); + + if(self.enemy) + self.nextthink = time; + else + self.nextthink = time + 0.2; +} + +void zombie_spawn() +{ + setmodel(self,"models/monsters/zombie.dpm"); + + self.solid = SOLID_BBOX; + self.takedamage = DAMAGE_AIM; + self.event_damage = zombie_damage; + self.enemy = world; + self.frame = zombie_anim_spawn; + self.think = zombie_think; + self.nextthink = time + 2.1; + self.pain_finished = self.nextthink; + self.movetype = MOVETYPE_WALK; + self.health = autocvar_g_monster_zombie_health; + self.velocity = '0 0 0'; + self.angles = self.pos2; + self.moveto = self.origin; + self.flags = FL_MONSTER; + + setorigin(self,self.pos1); + setsize(self,ZOMBIE_MIN,ZOMBIE_MAX); +} + + +void spawnfunc_monster_zombie() +{ + if not(autocvar_g_monsters) + { + remove(self); + return; + } + + precache_model("models/monsters/zombie.dpm"); + + + self.verbs_idle = spawn(); + self.verbs_attack = spawn(); + + self.verbs_idle.owner = self; + self.verbs_attack.owner = self; + + self.think = zombie_spawn; + self.nextthink = time + 2; + + traceline(self.origin + '0 0 10', self.origin - '0 0 32', MOVE_WORLDONLY, self); + + self.pos1 = trace_endpos; + self.pos2 = self.angles; + self.team = MAX_SHOT_DISTANCE -1; + + verbstack_push(self.verbs_idle, zombie_verb_idle, ZV_IDLE,0 , self); + + verbstack_push(self.verbs_attack, zombie_verb_attack_findtarget, ZV_ATTACK_FIND,0 , self); + verbstack_push(self.verbs_attack, zombie_verb_attack_run, ZV_ATTACK_RUN,0 , self); + verbstack_push(self.verbs_attack, zombie_verb_attack_stand, ZV_ATTACK_STAND,0 , self); + +} + +#endif // MONSTES_ENABLED diff --git a/qcsrc/server/attic/vehicles/bumblebee.qc b/qcsrc/server/attic/vehicles/bumblebee.qc new file mode 100644 index 000000000..f78456371 --- /dev/null +++ b/qcsrc/server/attic/vehicles/bumblebee.qc @@ -0,0 +1,371 @@ +#ifdef SVQC +// Auto cvars +float autocvar_g_vehicle_bumblebee_speed_forward; +float autocvar_g_vehicle_bumblebee_speed_strafe; +float autocvar_g_vehicle_bumblebee_speed_up; +float autocvar_g_vehicle_bumblebee_speed_down; +float autocvar_g_vehicle_bumblebee_turnspeed; +float autocvar_g_vehicle_bumblebee_pitchspeed; +float autocvar_g_vehicle_bumblebee_pitchlimit; +float autocvar_g_vehicle_bumblebee_friction; + +float autocvar_g_vehicle_bumblebee_energy; +float autocvar_g_vehicle_bumblebee_energy_regen; +float autocvar_g_vehicle_bumblebee_energy_regen_pause; + +float autocvar_g_vehicle_bumblebee_health; +float autocvar_g_vehicle_bumblebee_health_regen; +float autocvar_g_vehicle_bumblebee_health_regen_pause; + +float autocvar_g_vehicle_bumblebee_shield; +float autocvar_g_vehicle_bumblebee_shield_regen; +float autocvar_g_vehicle_bumblebee_shield_regen_pause; + +float autocvar_g_vehicle_bumblebee_cannon_cost; +float autocvar_g_vehicle_bumblebee_cannon_damage; +float autocvar_g_vehicle_bumblebee_cannon_radius; +float autocvar_g_vehicle_bumblebee_cannon_refire; +float autocvar_g_vehicle_bumblebee_cannon_speed; +float autocvar_g_vehicle_bumblebee_cannon_spread; +float autocvar_g_vehicle_bumblebee_cannon_force; + +float autocvar_g_vehicle_bumblebee_cannon_turnspeed; +float autocvar_g_vehicle_bumblebee_cannon_pitchlimit_down; +float autocvar_g_vehicle_bumblebee_cannon_pitchlimit_up; +float autocvar_g_vehicle_bumblebee_cannon_turnlimit_in; +float autocvar_g_vehicle_bumblebee_cannon_turnlimit_out; + +float autocvar_g_vehicle_bumblebee_respawntime; + +float autocvar_g_vehicle_bumblebee_blowup_radius; +float autocvar_g_vehicle_bumblebee_blowup_coredamage; +float autocvar_g_vehicle_bumblebee_blowup_edgedamage; +float autocvar_g_vehicle_bumblebee_blowup_forceintensity; + +#define BUMB_MIN '-120 -120 -40' +#define BUMB_MAX '120 120 40' + +.entity gunner1; +//.entity gunner2; +.vector lastaim; +float bumb_gunner_frame() +{ + entity vehic, gun, gunner; + float ftmp, ftmp2; + vector vtmp; + + vehic = self.vehicle; + gun = self.vehicle.gun1; + gunner = self; + + self = vehic; + vehic.solid = SOLID_NOT; + crosshair_trace(gunner); + + //vtmp = gettaginfo(vehic, gettagindexvehic, "tag_hardpoint01")); + vtmp = gettaginfo(gun, gettagindex(gun, "muzzle")); + vtmp = vectoangles(normalize(trace_endpos - vtmp)); // Find the direction & angle + vtmp = shortangle_vxy(vtmp - (vehic.angles + gun.angles), vehic.angles + gun.angles); // Find aim offset + + // Bind to aimspeed + ftmp2 = autocvar_g_vehicle_bumblebee_cannon_turnspeed * frametime; ftmp = -ftmp2; + vtmp_x = bound(ftmp, vtmp_x, ftmp2); + vtmp_y = bound(ftmp, vtmp_y, ftmp2); + // Bind to limts + gun.angles_x = bound(-autocvar_g_vehicle_bumblebee_cannon_pitchlimit_down, vtmp_x + gun.angles_x, autocvar_g_vehicle_bumblebee_cannon_pitchlimit_up); + gun.angles_y = bound(-autocvar_g_vehicle_bumblebee_cannon_turnlimit_in, vtmp_y + gun.angles_y, autocvar_g_vehicle_bumblebee_cannon_turnlimit_out); + + if(gunner.BUTTON_ATCK && gun.cnt <= time) + { + vtmp = gettaginfo(gun, gettagindex(gun, "muzzle")); + v_forward = normalize(v_forward); + vtmp += v_forward * 50; + + fireBullet (vtmp, v_forward, autocvar_g_vehicle_spiderbot_minigun_spread, autocvar_g_vehicle_spiderbot_minigun_damage, + autocvar_g_vehicle_spiderbot_minigun_spread, DEATH_SBMINIGUN, 0); + + gun.cnt = time + 0.1; + } + + setorigin(gunner, vehic.origin); + gunner.velocity = vehic.velocity; + + vehic.solid = SOLID_BBOX; + gunner.BUTTON_ATCK = gunner.BUTTON_ATCK2 = gunner.BUTTON_CROUCH = 0; + self = gunner; + return 1; +} + +void bumb_gunner_enter() +{ + if(self.gunner1 != world) + return; + + self.gunner1 = other; + self.gunner1.vehicle = self; + + msg_entity = other; + WriteByte (MSG_ONE, SVC_SETVIEWPORT); + WriteEntity(MSG_ONE, self.gun1); + WriteByte (MSG_ONE, SVC_SETVIEWANGLES); + if(self.tur_head) + { + WriteAngle(MSG_ONE, self.gun1.angles_x + self.angles_x); // tilt + WriteAngle(MSG_ONE, self.gun1.angles_y + self.angles_y); // yaw + WriteAngle(MSG_ONE, 0); // roll + } + other.PlayerPhysplug = bumb_gunner_frame; +} + +float bumb_pilot_frame() +{ + entity pilot, gunner, vehic; + vector newvel; + + pilot = self; + vehic = self.vehicle; + self = vehic; + + if(pilot.BUTTON_USE && vehic.deadflag == DEAD_NO) + { + self = vehic; + vehicles_exit(VHEF_NORMAL); + self = pilot; + return 0; + } + + if(vehic.deadflag != DEAD_NO) + { + self = pilot; + pilot.BUTTON_ATCK = pilot.BUTTON_ATCK2 = 0; + return 1; + } + + crosshair_trace(pilot); + + vector vang; + float ftmp; + + vang = vehic.angles; + newvel = vectoangles(normalize(trace_endpos - self.origin + '0 0 32')); + vang_x *= -1; + newvel_x *= -1; + if(newvel_x > 180) newvel_x -= 360; + if(newvel_x < -180) newvel_x += 360; + if(newvel_y > 180) newvel_y -= 360; + if(newvel_y < -180) newvel_y += 360; + + ftmp = shortangle_f(pilot.v_angle_y - vang_y, vang_y); + if(ftmp > 180) ftmp -= 360; if(ftmp < -180) ftmp += 360; + vehic.avelocity_y = bound(-autocvar_g_vehicle_bumblebee_turnspeed, ftmp + vehic.avelocity_y * 0.9, autocvar_g_vehicle_bumblebee_turnspeed); + + // Pitch + ftmp = 0; + if(pilot.movement_x > 0 && vang_x < autocvar_g_vehicle_bumblebee_pitchlimit) ftmp = 5; + else if(pilot.movement_x < 0 && vang_x > -autocvar_g_vehicle_bumblebee_pitchlimit) ftmp = -20; + + newvel_x = bound(-autocvar_g_vehicle_bumblebee_pitchlimit, newvel_x , autocvar_g_vehicle_bumblebee_pitchlimit); + ftmp = vang_x - bound(-autocvar_g_vehicle_bumblebee_pitchlimit, newvel_x + ftmp, autocvar_g_vehicle_bumblebee_pitchlimit); + vehic.avelocity_x = bound(-autocvar_g_vehicle_bumblebee_pitchspeed, ftmp + vehic.avelocity_x * 0.9, autocvar_g_vehicle_bumblebee_pitchspeed); + + vehic.angles_x = anglemods(vehic.angles_x); + vehic.angles_y = anglemods(vehic.angles_y); + vehic.angles_z = anglemods(vehic.angles_z); + + makevectors('0 1 0' * vehic.angles_y); + newvel = vehic.velocity * -autocvar_g_vehicle_bumblebee_friction; + + if(pilot.movement_x != 0) + { + if(pilot.movement_x > 0) + newvel += v_forward * autocvar_g_vehicle_bumblebee_speed_forward; + else if(pilot.movement_x < 0) + newvel -= v_forward * autocvar_g_vehicle_bumblebee_speed_forward; + } + + if(pilot.movement_y != 0) + { + if(pilot.movement_y < 0) + newvel -= v_right * autocvar_g_vehicle_bumblebee_speed_strafe; + else if(pilot.movement_y > 0) + newvel += v_right * autocvar_g_vehicle_bumblebee_speed_strafe; + ftmp = newvel * v_right; + ftmp *= frametime * 0.1; + vehic.angles_z = bound(-15, vehic.angles_z + ftmp, 15); + } + else + { + vehic.angles_z *= 0.95; + if(vehic.angles_z >= -1 && vehic.angles_z <= -1) + vehic.angles_z = 0; + } + + if(pilot.BUTTON_CROUCH) + newvel -= v_up * autocvar_g_vehicle_bumblebee_speed_down; + else if (pilot.BUTTON_JUMP) + newvel += v_up * autocvar_g_vehicle_bumblebee_speed_up; + + vehic.velocity += newvel * frametime; + pilot.velocity = pilot.movement = vehic.velocity; + setorigin(pilot,vehic.origin + '0 0 32'); + + + if(vehic.vehicle_flags & VHF_SHIELDREGEN) + vehicles_regen(dmg_time, vehicle_shield, autocvar_g_vehicle_bumblebee_shield, autocvar_g_vehicle_bumblebee_shield_regen_pause, autocvar_g_vehicle_bumblebee_shield_regen, frametime); + + if(vehic.vehicle_flags & VHF_HEALTHREGEN) + vehicles_regen(dmg_time, vehicle_health, autocvar_g_vehicle_bumblebee_health, autocvar_g_vehicle_bumblebee_health_regen_pause, autocvar_g_vehicle_bumblebee_health_regen, frametime); + + if(vehic.vehicle_flags & VHF_ENERGYREGEN) + vehicles_regen(cnt, vehicle_energy, autocvar_g_vehicle_bumblebee_energy, autocvar_g_vehicle_bumblebee_energy_regen_pause, autocvar_g_vehicle_bumblebee_energy_regen, frametime); + + VEHICLE_UPDATE_PLAYER(health, bumblebee); + VEHICLE_UPDATE_PLAYER(energy, bumblebee); + if(vehic.vehicle_flags & VHF_HASSHIELD) + VEHICLE_UPDATE_PLAYER(shield, bumblebee); + + pilot.BUTTON_ATCK = pilot.BUTTON_ATCK2 = pilot.BUTTON_CROUCH = 0; + self = pilot; + + return 1; +} + +void bumb_think() +{ + self.velocity = self.velocity * 0.99; + self.nextthink = time + 0.1; +} + +void bumb_enter() +{ + self.touch = bumb_gunner_enter; +} + +void bumb_exit(float eject) +{ + self.owner = world; + self.touch = vehicles_touch; +} + +void bumb_spawn() +{ + self.vehicle_health = autocvar_g_vehicle_bumblebee_health; + self.vehicle_shield = autocvar_g_vehicle_bumblebee_shield; + self.movetype = MOVETYPE_TOSS; + self.solid = SOLID_BBOX; + //self.vehicle_energy = 1; + self.movetype = MOVETYPE_FLY; + setorigin(self, self.origin + '0 0 25'); +} + +void bumb_die() +{ + self.health = 0; + self.event_damage = SUB_Null; + self.solid = SOLID_CORPSE; + self.takedamage = DAMAGE_NO; + self.deadflag = DEAD_DYING; + self.movetype = MOVETYPE_BOUNCE; + + pointparticles(particleeffectnum("rocket_explode"), findbetterlocation (self.origin, 16), '0 0 0', 1); +} + +void bumb_dinit() +{ + if not (vehicle_initialize( + "Bumblebee", + "models/vehicles/bumblebee_body.dpm", + "", + "models/vehicles/spiderbot_cockpit.dpm", + "", "", "tag_viewport", + HUD_BUMBLEBEE, + BUMB_MIN, BUMB_MAX, + FALSE, + bumb_spawn, autocvar_g_vehicle_bumblebee_respawntime, + bumb_pilot_frame, + bumb_enter, bumb_exit, + bumb_die, bumb_think, + FALSE)) + { + remove(self); + return; + } + self.gun1 = spawn(); + setmodel(self.gun1, "models/vehicles/bumblebee_ray.dpm"); + setattachment(self.gun1, self, "tag_hardpoint03"); + + self.gun1 = spawn(); + self.gun2 = spawn(); + + self.gun1.owner = self; + self.gun2.owner = self; + + setmodel(self.gun1, "models/vehicles/bumblebee_plasma_right.dpm"); + setmodel(self.gun2, "models/vehicles/bumblebee_plasma_left.dpm"); + + setattachment(self.gun1, self, "tag_hardpoint01"); + setattachment(self.gun2, self, "tag_hardpoint02"); + + vector ofs; + ofs = gettaginfo(self, gettagindex(self, "tag_hardpoint01")); + ofs -= self.origin; + setattachment(self.gun1, self, ""); + setorigin(self.gun1, ofs); + + ofs = gettaginfo(self, gettagindex(self, "tag_hardpoint02")); + ofs -= self.origin; + setattachment(self.gun2, self, ""); + setorigin(self.gun2, ofs); + + +} + +void spawnfunc_vehicle_bumblebee() +{ + + precache_model ("models/vehicles/bumblebee_body.dpm"); + precache_model ("models/vehicles/bumblebee_plasma_left.dpm"); + precache_model ("models/vehicles/bumblebee_plasma_right.dpm"); + precache_model ("models/vehicles/bumblebee_ray.dpm"); + + //vehicles_configcheck("vehicle_bumblebee.cfg", autocvar_g_vehicle_bumblebee_health); + + if(autocvar_g_vehicle_bumblebee_energy) + if(autocvar_g_vehicle_bumblebee_energy_regen) + self.vehicle_flags |= VHF_ENERGYREGEN; + + if(autocvar_g_vehicle_bumblebee_shield) + self.vehicle_flags |= VHF_HASSHIELD; + + if(autocvar_g_vehicle_bumblebee_shield_regen) + self.vehicle_flags |= VHF_SHIELDREGEN; + + if(autocvar_g_vehicle_bumblebee_health_regen) + self.vehicle_flags |= VHF_HEALTHREGEN; + + self.think = bumb_dinit; + self.nextthink = time + 1; +} +#endif // SVQC + +#ifdef CSQC +void bumblebee_draw() +{ + +} + +void bumblebee_draw2d() +{ + +} + +void bumblebee_read_extra() +{ + +} + +void vehicle_bumblebee_assemble() +{ + +} +#endif //CSQC diff --git a/qcsrc/server/attic/vehicles/collision.qc b/qcsrc/server/attic/vehicles/collision.qc new file mode 100644 index 000000000..11488a0d5 --- /dev/null +++ b/qcsrc/server/attic/vehicles/collision.qc @@ -0,0 +1,55 @@ +vector collision_force; +vector collision_angle; + +vector bb1[9]; +vector bb2[9]; + +float collision_run() +{ + vector vtmp, vmin, vmax, vrot, vforce, vtmp2, vtmp3; + float i, fvel, bcol; + + + // Extract the 8 bbox corners from mins/maxs for self + vmax = self.maxs; + vmin = self.mins; + bb1[0] = vmax; + vtmp = vmax; vtmp_x = vmin_x; bb1[1] = vtmp; + vtmp = vmax; vtmp_y = vmin_y; bb1[2] = vtmp; + vtmp = vmin; vtmp_z = vmax_z; bb1[3] = vtmp; + bb1[4] = vmin; + vtmp = vmin; vtmp_x = vmax_x; bb1[5] = vtmp; + vtmp = vmin; vtmp_y = vmax_y; bb1[6] = vtmp; + vtmp = vmax; vtmp_z = vmin_z; bb1[7] = vtmp; + + makevectors(self.angles + '-2 0 0' * self.angles_x); + bcol = 0; + + // Pass1: Transform by rotation, ajust points by impact/s + for(i = 8; i >= 0; --i) + { + vtmp = bb1[i]; + vtmp = self.origin + vtmp_x * v_forward - vtmp_y * v_right + vtmp_z * v_up; + traceline(self.origin, vtmp, MOVE_WORLDONLY, self); + te_lightning1(world,self.origin,vtmp); + if(trace_fraction != 1.0) + { + vforce += (trace_endpos - vtmp); + vtmp3 = self.origin + self.velocity * frametime; + vtmp2 = vectoangles(normalize(vtmp - vtmp3)); + vrot += (vectoangles(normalize(trace_endpos - vtmp3)) - vtmp2); + bcol += 1; + } + } + + if(bcol) + { + + vtmp = self.origin + self.velocity * frametime; + self.angles += vrot * frametime; + self.velocity += vforce * frametime; + + } + +} + diff --git a/qcsrc/server/attic/vehicles/network.qc b/qcsrc/server/attic/vehicles/network.qc new file mode 100644 index 000000000..688aa7ca2 --- /dev/null +++ b/qcsrc/server/attic/vehicles/network.qc @@ -0,0 +1,237 @@ +#ifdef VEHICLES_CSQC +// SendFlags +float VSF_SETUP = 1; /// Send vehicle type etc +float VSF_ORIGIN = 2; /// Send location +float VSF_MOVEMENT = 4; /// Send movement update (and angles) +float VSF_AVEL = 8; /// Send Angular velocity +float VSF_STATS = 16; /// Send ammo, health etc +float VSF_EXTRA = 32; /// Send additional data (turret rotations etc). Handeld per vehicle type. +float VSF_ANIMINFO = 64; /// Animation info +float VSF_FULL_UPDATE = 16777215; /// Send everything + +float VSX_FAR = 1; +float VSX_OWNER = 2; +float VSX_GUN1 = 4; +float VSX_GUN2 = 8; + +#ifdef SVQC +#define VSX_FARDISTANCE 2000 +float send_vehile(entity to, float sf) +{ + float dist, xf; + + var void WriteFunc(float, float); + + dist = vlen(self.origin - to.origin); + if(to == self.owner) + xf |= VSX_OWNER; + else if(dist > VSX_FARDISTANCE) + xf |= VSX_FAR; + + // Always send a movement and origin to owner + if(to == self.owner) + sf |= VSF_ORIGIN | VSF_MOVEMENT; + + WriteByte(MSG_ENTITY, ENT_CLIENT_VEHICLE); + + // We need to know client-side what was sent + WriteByte(MSG_ENTITY, sf); + WriteByte(MSG_ENTITY, xf); + + if(sf & VSF_SETUP) + { + WriteByte(MSG_ENTITY, self.hud); //vehicle type = hud + WriteByte(MSG_ENTITY, self.team); + WriteShort(MSG_ENTITY, self.colormap); + WriteShort(MSG_ENTITY, self.vehicle_flags); + } + + if(sf & VSF_ORIGIN) + { + WriteFunc = ((xf & VSX_FAR) ? WriteShort : WriteCoord); + WriteFunc(MSG_ENTITY, self.origin_x); + WriteFunc(MSG_ENTITY, self.origin_y); + WriteFunc(MSG_ENTITY, self.origin_z); + } + + if(sf & VSF_MOVEMENT) + { + WriteFunc = ((xf & VSX_FAR) ? WriteShort : WriteCoord); + WriteFunc(MSG_ENTITY, self.velocity_x); + WriteFunc(MSG_ENTITY, self.velocity_y); + WriteFunc(MSG_ENTITY, self.velocity_z); + + WriteFunc = ((xf & VSX_FAR) ? WriteShort : WriteAngle); + WriteFunc(MSG_ENTITY, self.angles_x); + WriteFunc(MSG_ENTITY, self.angles_y); + WriteFunc(MSG_ENTITY, self.angles_z); + } + + if(sf & VSF_AVEL) + { + WriteFunc = ((xf & VSX_FAR) ? WriteShort : WriteCoord); + WriteFunc(MSG_ENTITY, self.avelocity_x); + WriteFunc(MSG_ENTITY, self.avelocity_y); + WriteFunc(MSG_ENTITY, self.avelocity_z); + } + + if(sf & VSF_STATS) + { + WriteByte(MSG_ENTITY, self.vehicle_health); + if(xf & VSX_OWNER) + { + WriteByte(MSG_ENTITY, self.vehicle_shield); + WriteByte(MSG_ENTITY, self.vehicle_energy); + + WriteByte(MSG_ENTITY, self.vehicle_ammo1); + WriteByte(MSG_ENTITY, self.vehicle_reload1); + + WriteByte(MSG_ENTITY, self.vehicle_ammo2); + WriteByte(MSG_ENTITY, self.vehicle_reload2); + + } + } + + if(sf & VSF_EXTRA) + self.vehile_send_exta(to, sf); + + return TRUE; +} + +void net_link_vehile() +{ + self.SendFlags = 0xFFFFFF; + Net_LinkEntity(self, FALSE, 0, send_vehile); +} +#endif // SVQC + +#ifdef CSQC +void vehicle_spiderbot_assemble() +{ + +} + +void vehicle_raptor_assemble() +{ + +} + +void vehicle_bumblebee_assemble() +{ + +} + +.float lastupdate; +void read_vehicle(float bIsNew) +{ + float sf, xf; + var float ReadFunc(); + + sf = ReadByte(); + xf = ReadByte(); + + if(xf & VSX_OWNER) + vehicle = self; + + if(sf & VSF_SETUP) + { + self.vehicle_hud = ReadByte(); + self.team = ReadByte(); + self.colormap = ReadShort(); + self.vehicle_flags = ReadShort(); + + switch(self.vehicle_hud) + { + case HUD_WAKIZASHI: + vehicle_racer_assemble(); + break; + case HUD_SPIDERBOT: + vehicle_spiderbot_assemble(); + break; + case HUD_RAPTOR: + vehicle_raptor_assemble(); + break; + case HUD_BUMBLEBEE: + vehicle_bumblebee_assemble(); + break; + default: + break; + } + } + + if(self.vehicle_hud == HUD_WAKIZASHI && xf & VSX_OWNER) + { + + vehicle_hudmodel.owner = self; + } + + //if(xf & VSX_FAR) + // dprint("Client vehicle faaar set\n"); + + if(sf & VSF_ORIGIN) + { + ReadFunc = ((xf & VSX_FAR) ? ReadShort : ReadCoord); + self.origin_x = ReadFunc(); + self.origin_y = ReadFunc(); + self.origin_z = ReadFunc(); + + setorigin(self, self.origin); + //self.lastupdate = time; + } + + if(sf & VSF_MOVEMENT) + { + ReadFunc = ((xf & VSX_FAR) ? ReadShort : ReadCoord); + self.velocity_x = ReadFunc(); + self.velocity_y = ReadFunc(); + self.velocity_z = ReadFunc(); + + ReadFunc = ((sf & VSX_FAR) ? ReadShort : ReadAngle); + self.angles_x = ReadFunc(); + self.angles_y = ReadFunc(); + self.angles_z = ReadFunc(); + + //self.lastupdate = time; + // self.move_velocity = self.velocity; + // self.move_angles = self.angles; + } + + if(sf & VSF_AVEL) + { + ReadFunc = ((xf & VSX_FAR) ? ReadShort : ReadCoord); + self.avelocity_x = ReadFunc(); + self.avelocity_y = ReadFunc(); + self.avelocity_z = ReadFunc(); + + // self.move_avelocity = self.avelocity; + } + + if(sf & VSF_STATS) + { + self.vehicle_health = ReadByte(); + if(xf & VSX_OWNER) + { + self.vehicle_shield = ReadByte(); + self.vehicle_energy = ReadByte(); + self.vehicle_ammo1 = ReadByte(); + self.vehicle_reload1 = ReadByte(); + self.vehicle_ammo2 = ReadByte(); + self.vehicle_reload2 = ReadByte(); + } + } + + if(sf & VSF_EXTRA) + self.vehile_read_exta(sf); + +} + +#endif // CSQC +#else +#ifdef CSQC +.float lastupdate; +void read_vehicle(float bIsNew) +{ + +} +#endif +#endif // VEHICLES_CSQC diff --git a/qcsrc/server/attic/verbstack.qc b/qcsrc/server/attic/verbstack.qc new file mode 100644 index 000000000..b0601afe6 --- /dev/null +++ b/qcsrc/server/attic/verbstack.qc @@ -0,0 +1,274 @@ +/// Some default stacks. +.entity verbs_idle; +.entity verbs_attack; +.entity verbs_move; +//.entity vchain; + +/// This global gets set to the verb in question each time the stack manager calls verb_call +entity verb; +//.entity current_verb; +//.float verb_done; + +/// Execure this verb +#define VCM_DO 0 +/// Return the value of this verb. Return VS_CALL_REMOVE to delete it. +#define VCM_EVAL 1 +/// This verb is beeing removed NOW (not sent when verb_call returns VS_CALL_REMOVE) +#define VCM_REMOVE 2 + +/// Verb callback +.float(float message) verb_call; + +/// Points to this verb's stack. +.entity verbstack; + +/// Static value of this verb +.float verb_static_value; + +/// verb_call returns this when a verb in not doable +#define VS_CALL_NO 0 +/// verb_call(VCM_DO) returns this when a verb is executing +#define VS_CALL_YES_DOING -1 +/// verb_call(VCM_DO) returns this when a verb did execure and is done +#define VS_CALL_YES_DONE -2 +/// verb_call(VCM_DO) returns this when a verb should be deleted by the stack manager +#define VS_CALL_REMOVE -3 + +/* +void verbstack_updatechain(entity stack) +{ + entity vrb, v; + if not (stack) + return; + + dprint("verbstack_updatechain\n"); + + vrb = findchainentity(verbstack, stack); + if not (vrb) + { + stack.vchain = world; + return; + } + + stack.vchain = vrb; + v = vrb; + + while(vrb) + { + vrb = vrb.chain; + + + } +} + +void verbstack_remove(entity vverb) +{ + entity vstack; + dprint("verbstack_remove\n"); + + vstack = verb.verbstack; + remove(vverb); + vverb.verbstack = world; + verbstack_updatechain(vstack); + + //vverb.think = SUB_Remove; + //vverb.nextthink = time; +} + +void verbstack_thinkremove() +{ + dprint("verbstack_thinkremove\n"); + verbstack_remove(self); +} +*/ + +/** + Push a new verb onto the specified stack. Set vrb_life to make it time-limited. +**/ +entity verbstack_push(entity stack, float(float eval) vrb_call, float val_static, float vrb_life,entity verb_owner) +{ + entity vrb; + + if not(stack) + return world; + + if not(vrb_call) + return world; + + vrb = spawn(); + vrb.owner = verb_owner; + vrb.verbstack = stack; + vrb.verb_call = vrb_call; + vrb.verb_static_value = val_static; + + vrb.classname = "verb"; + stack.classname = "verbstack"; + + if(vrb_life) + { + //vrb.think = verbstack_thinkremove; + vrb.think = SUB_Remove; + vrb.nextthink = time + vrb_life; + } + + //verbstack_updatechain(stack); + + return vrb; +} + +/** + Find the best verb in this stack and execurte it. + ALso remove any verbs returning VS_CALL_REMOVE on VCM_EVAL or VCM_DO +**/ +float verbstack_pop(entity stack) +{ + entity vrb, bestverb, oldself; + float value, bestvalue; + + oldself = self; + + vrb = findchainentity(verbstack,stack); + //vrb = stack.vchain; + //dprint("owner:", stack.owner.classname, " vsn:", stack.classname,"\n"); + while(vrb) + { + //dprint("vn:", vrb.classname,"\n"); + verb = vrb; + vrb = vrb.chain; + self = verb.owner; + value = verb.verb_call(VCM_EVAL); + + if(value < 0) + { + if(value == VS_CALL_REMOVE) + remove(verb); + } + else + { + if(value > bestvalue) + { + bestverb = verb; + bestvalue = value; + } + } + } + + if(bestverb) + { + verb = bestverb; + self = verb.owner; + value = verb.verb_call(VCM_DO); + + if(value == VS_CALL_REMOVE) + remove(bestverb); + } + + self = oldself; + + return value; +} + +float verbstack_popfifo(entity stack) +{ + entity oldself; + float ret; + + oldself = self; + verb = findentity(stack,verbstack,stack); + if not (verb) + ret = 0; + else + { + self = verb.owner; + ret = verb.verb_call(VCM_DO); + + if(ret == VS_CALL_REMOVE) + remove(verb); + } + + self = oldself; + return ret; +} + +/** + Find the best verb in this stack and return it. + ALso remove any verbs returning VS_CALL_REMOVE on VCM_EVAL. +**/ +entity verbstack_pull(entity stack) +{ + entity vrb; + entity bestverb, oldself; + float value, bestvalue; + + oldself = self; + + vrb = findchainentity(verbstack,stack); + while(vrb) + { + self = vrb.owner; + + verb = vrb; + vrb = vrb.chain; + value = verb.verb_call(VCM_EVAL); + + if(value < 0) + { + if(value == VS_CALL_REMOVE) + remove(verb); + } + else + { + if(value > bestvalue) + { + bestverb = verb; + bestvalue = value; + } + } + } + + self = oldself; + + return bestverb; +} + +entity verbstack_pullfifo(entity stack) +{ + return findentity(stack,verbstack,stack); +} + +/** + Delete every verb on this stack, signaling them with VCM_REMOVE first. +**/ +void verbstack_flush(entity stack) +{ + entity vrb, oldself; + + oldself = self; + + vrb = findchainentity(verbstack,stack); + while(vrb) + { + self = vrb.owner; + + verb = vrb; + vrb = vrb.chain; + verb.verb_call(VCM_REMOVE); + remove(verb); + } + + self = oldself; + + //stack.vchain = world; +} + +void verbstack_doverb(entity vrb) +{ + float value; + + verb = vrb; + self = verb.owner; + value = verb.verb_call(VCM_DO); + + if(value == VS_CALL_REMOVE) + remove(vrb); +} diff --git a/qcsrc/server/vehicles/bumblebee.qc b/qcsrc/server/vehicles/bumblebee.qc deleted file mode 100644 index f78456371..000000000 --- a/qcsrc/server/vehicles/bumblebee.qc +++ /dev/null @@ -1,371 +0,0 @@ -#ifdef SVQC -// Auto cvars -float autocvar_g_vehicle_bumblebee_speed_forward; -float autocvar_g_vehicle_bumblebee_speed_strafe; -float autocvar_g_vehicle_bumblebee_speed_up; -float autocvar_g_vehicle_bumblebee_speed_down; -float autocvar_g_vehicle_bumblebee_turnspeed; -float autocvar_g_vehicle_bumblebee_pitchspeed; -float autocvar_g_vehicle_bumblebee_pitchlimit; -float autocvar_g_vehicle_bumblebee_friction; - -float autocvar_g_vehicle_bumblebee_energy; -float autocvar_g_vehicle_bumblebee_energy_regen; -float autocvar_g_vehicle_bumblebee_energy_regen_pause; - -float autocvar_g_vehicle_bumblebee_health; -float autocvar_g_vehicle_bumblebee_health_regen; -float autocvar_g_vehicle_bumblebee_health_regen_pause; - -float autocvar_g_vehicle_bumblebee_shield; -float autocvar_g_vehicle_bumblebee_shield_regen; -float autocvar_g_vehicle_bumblebee_shield_regen_pause; - -float autocvar_g_vehicle_bumblebee_cannon_cost; -float autocvar_g_vehicle_bumblebee_cannon_damage; -float autocvar_g_vehicle_bumblebee_cannon_radius; -float autocvar_g_vehicle_bumblebee_cannon_refire; -float autocvar_g_vehicle_bumblebee_cannon_speed; -float autocvar_g_vehicle_bumblebee_cannon_spread; -float autocvar_g_vehicle_bumblebee_cannon_force; - -float autocvar_g_vehicle_bumblebee_cannon_turnspeed; -float autocvar_g_vehicle_bumblebee_cannon_pitchlimit_down; -float autocvar_g_vehicle_bumblebee_cannon_pitchlimit_up; -float autocvar_g_vehicle_bumblebee_cannon_turnlimit_in; -float autocvar_g_vehicle_bumblebee_cannon_turnlimit_out; - -float autocvar_g_vehicle_bumblebee_respawntime; - -float autocvar_g_vehicle_bumblebee_blowup_radius; -float autocvar_g_vehicle_bumblebee_blowup_coredamage; -float autocvar_g_vehicle_bumblebee_blowup_edgedamage; -float autocvar_g_vehicle_bumblebee_blowup_forceintensity; - -#define BUMB_MIN '-120 -120 -40' -#define BUMB_MAX '120 120 40' - -.entity gunner1; -//.entity gunner2; -.vector lastaim; -float bumb_gunner_frame() -{ - entity vehic, gun, gunner; - float ftmp, ftmp2; - vector vtmp; - - vehic = self.vehicle; - gun = self.vehicle.gun1; - gunner = self; - - self = vehic; - vehic.solid = SOLID_NOT; - crosshair_trace(gunner); - - //vtmp = gettaginfo(vehic, gettagindexvehic, "tag_hardpoint01")); - vtmp = gettaginfo(gun, gettagindex(gun, "muzzle")); - vtmp = vectoangles(normalize(trace_endpos - vtmp)); // Find the direction & angle - vtmp = shortangle_vxy(vtmp - (vehic.angles + gun.angles), vehic.angles + gun.angles); // Find aim offset - - // Bind to aimspeed - ftmp2 = autocvar_g_vehicle_bumblebee_cannon_turnspeed * frametime; ftmp = -ftmp2; - vtmp_x = bound(ftmp, vtmp_x, ftmp2); - vtmp_y = bound(ftmp, vtmp_y, ftmp2); - // Bind to limts - gun.angles_x = bound(-autocvar_g_vehicle_bumblebee_cannon_pitchlimit_down, vtmp_x + gun.angles_x, autocvar_g_vehicle_bumblebee_cannon_pitchlimit_up); - gun.angles_y = bound(-autocvar_g_vehicle_bumblebee_cannon_turnlimit_in, vtmp_y + gun.angles_y, autocvar_g_vehicle_bumblebee_cannon_turnlimit_out); - - if(gunner.BUTTON_ATCK && gun.cnt <= time) - { - vtmp = gettaginfo(gun, gettagindex(gun, "muzzle")); - v_forward = normalize(v_forward); - vtmp += v_forward * 50; - - fireBullet (vtmp, v_forward, autocvar_g_vehicle_spiderbot_minigun_spread, autocvar_g_vehicle_spiderbot_minigun_damage, - autocvar_g_vehicle_spiderbot_minigun_spread, DEATH_SBMINIGUN, 0); - - gun.cnt = time + 0.1; - } - - setorigin(gunner, vehic.origin); - gunner.velocity = vehic.velocity; - - vehic.solid = SOLID_BBOX; - gunner.BUTTON_ATCK = gunner.BUTTON_ATCK2 = gunner.BUTTON_CROUCH = 0; - self = gunner; - return 1; -} - -void bumb_gunner_enter() -{ - if(self.gunner1 != world) - return; - - self.gunner1 = other; - self.gunner1.vehicle = self; - - msg_entity = other; - WriteByte (MSG_ONE, SVC_SETVIEWPORT); - WriteEntity(MSG_ONE, self.gun1); - WriteByte (MSG_ONE, SVC_SETVIEWANGLES); - if(self.tur_head) - { - WriteAngle(MSG_ONE, self.gun1.angles_x + self.angles_x); // tilt - WriteAngle(MSG_ONE, self.gun1.angles_y + self.angles_y); // yaw - WriteAngle(MSG_ONE, 0); // roll - } - other.PlayerPhysplug = bumb_gunner_frame; -} - -float bumb_pilot_frame() -{ - entity pilot, gunner, vehic; - vector newvel; - - pilot = self; - vehic = self.vehicle; - self = vehic; - - if(pilot.BUTTON_USE && vehic.deadflag == DEAD_NO) - { - self = vehic; - vehicles_exit(VHEF_NORMAL); - self = pilot; - return 0; - } - - if(vehic.deadflag != DEAD_NO) - { - self = pilot; - pilot.BUTTON_ATCK = pilot.BUTTON_ATCK2 = 0; - return 1; - } - - crosshair_trace(pilot); - - vector vang; - float ftmp; - - vang = vehic.angles; - newvel = vectoangles(normalize(trace_endpos - self.origin + '0 0 32')); - vang_x *= -1; - newvel_x *= -1; - if(newvel_x > 180) newvel_x -= 360; - if(newvel_x < -180) newvel_x += 360; - if(newvel_y > 180) newvel_y -= 360; - if(newvel_y < -180) newvel_y += 360; - - ftmp = shortangle_f(pilot.v_angle_y - vang_y, vang_y); - if(ftmp > 180) ftmp -= 360; if(ftmp < -180) ftmp += 360; - vehic.avelocity_y = bound(-autocvar_g_vehicle_bumblebee_turnspeed, ftmp + vehic.avelocity_y * 0.9, autocvar_g_vehicle_bumblebee_turnspeed); - - // Pitch - ftmp = 0; - if(pilot.movement_x > 0 && vang_x < autocvar_g_vehicle_bumblebee_pitchlimit) ftmp = 5; - else if(pilot.movement_x < 0 && vang_x > -autocvar_g_vehicle_bumblebee_pitchlimit) ftmp = -20; - - newvel_x = bound(-autocvar_g_vehicle_bumblebee_pitchlimit, newvel_x , autocvar_g_vehicle_bumblebee_pitchlimit); - ftmp = vang_x - bound(-autocvar_g_vehicle_bumblebee_pitchlimit, newvel_x + ftmp, autocvar_g_vehicle_bumblebee_pitchlimit); - vehic.avelocity_x = bound(-autocvar_g_vehicle_bumblebee_pitchspeed, ftmp + vehic.avelocity_x * 0.9, autocvar_g_vehicle_bumblebee_pitchspeed); - - vehic.angles_x = anglemods(vehic.angles_x); - vehic.angles_y = anglemods(vehic.angles_y); - vehic.angles_z = anglemods(vehic.angles_z); - - makevectors('0 1 0' * vehic.angles_y); - newvel = vehic.velocity * -autocvar_g_vehicle_bumblebee_friction; - - if(pilot.movement_x != 0) - { - if(pilot.movement_x > 0) - newvel += v_forward * autocvar_g_vehicle_bumblebee_speed_forward; - else if(pilot.movement_x < 0) - newvel -= v_forward * autocvar_g_vehicle_bumblebee_speed_forward; - } - - if(pilot.movement_y != 0) - { - if(pilot.movement_y < 0) - newvel -= v_right * autocvar_g_vehicle_bumblebee_speed_strafe; - else if(pilot.movement_y > 0) - newvel += v_right * autocvar_g_vehicle_bumblebee_speed_strafe; - ftmp = newvel * v_right; - ftmp *= frametime * 0.1; - vehic.angles_z = bound(-15, vehic.angles_z + ftmp, 15); - } - else - { - vehic.angles_z *= 0.95; - if(vehic.angles_z >= -1 && vehic.angles_z <= -1) - vehic.angles_z = 0; - } - - if(pilot.BUTTON_CROUCH) - newvel -= v_up * autocvar_g_vehicle_bumblebee_speed_down; - else if (pilot.BUTTON_JUMP) - newvel += v_up * autocvar_g_vehicle_bumblebee_speed_up; - - vehic.velocity += newvel * frametime; - pilot.velocity = pilot.movement = vehic.velocity; - setorigin(pilot,vehic.origin + '0 0 32'); - - - if(vehic.vehicle_flags & VHF_SHIELDREGEN) - vehicles_regen(dmg_time, vehicle_shield, autocvar_g_vehicle_bumblebee_shield, autocvar_g_vehicle_bumblebee_shield_regen_pause, autocvar_g_vehicle_bumblebee_shield_regen, frametime); - - if(vehic.vehicle_flags & VHF_HEALTHREGEN) - vehicles_regen(dmg_time, vehicle_health, autocvar_g_vehicle_bumblebee_health, autocvar_g_vehicle_bumblebee_health_regen_pause, autocvar_g_vehicle_bumblebee_health_regen, frametime); - - if(vehic.vehicle_flags & VHF_ENERGYREGEN) - vehicles_regen(cnt, vehicle_energy, autocvar_g_vehicle_bumblebee_energy, autocvar_g_vehicle_bumblebee_energy_regen_pause, autocvar_g_vehicle_bumblebee_energy_regen, frametime); - - VEHICLE_UPDATE_PLAYER(health, bumblebee); - VEHICLE_UPDATE_PLAYER(energy, bumblebee); - if(vehic.vehicle_flags & VHF_HASSHIELD) - VEHICLE_UPDATE_PLAYER(shield, bumblebee); - - pilot.BUTTON_ATCK = pilot.BUTTON_ATCK2 = pilot.BUTTON_CROUCH = 0; - self = pilot; - - return 1; -} - -void bumb_think() -{ - self.velocity = self.velocity * 0.99; - self.nextthink = time + 0.1; -} - -void bumb_enter() -{ - self.touch = bumb_gunner_enter; -} - -void bumb_exit(float eject) -{ - self.owner = world; - self.touch = vehicles_touch; -} - -void bumb_spawn() -{ - self.vehicle_health = autocvar_g_vehicle_bumblebee_health; - self.vehicle_shield = autocvar_g_vehicle_bumblebee_shield; - self.movetype = MOVETYPE_TOSS; - self.solid = SOLID_BBOX; - //self.vehicle_energy = 1; - self.movetype = MOVETYPE_FLY; - setorigin(self, self.origin + '0 0 25'); -} - -void bumb_die() -{ - self.health = 0; - self.event_damage = SUB_Null; - self.solid = SOLID_CORPSE; - self.takedamage = DAMAGE_NO; - self.deadflag = DEAD_DYING; - self.movetype = MOVETYPE_BOUNCE; - - pointparticles(particleeffectnum("rocket_explode"), findbetterlocation (self.origin, 16), '0 0 0', 1); -} - -void bumb_dinit() -{ - if not (vehicle_initialize( - "Bumblebee", - "models/vehicles/bumblebee_body.dpm", - "", - "models/vehicles/spiderbot_cockpit.dpm", - "", "", "tag_viewport", - HUD_BUMBLEBEE, - BUMB_MIN, BUMB_MAX, - FALSE, - bumb_spawn, autocvar_g_vehicle_bumblebee_respawntime, - bumb_pilot_frame, - bumb_enter, bumb_exit, - bumb_die, bumb_think, - FALSE)) - { - remove(self); - return; - } - self.gun1 = spawn(); - setmodel(self.gun1, "models/vehicles/bumblebee_ray.dpm"); - setattachment(self.gun1, self, "tag_hardpoint03"); - - self.gun1 = spawn(); - self.gun2 = spawn(); - - self.gun1.owner = self; - self.gun2.owner = self; - - setmodel(self.gun1, "models/vehicles/bumblebee_plasma_right.dpm"); - setmodel(self.gun2, "models/vehicles/bumblebee_plasma_left.dpm"); - - setattachment(self.gun1, self, "tag_hardpoint01"); - setattachment(self.gun2, self, "tag_hardpoint02"); - - vector ofs; - ofs = gettaginfo(self, gettagindex(self, "tag_hardpoint01")); - ofs -= self.origin; - setattachment(self.gun1, self, ""); - setorigin(self.gun1, ofs); - - ofs = gettaginfo(self, gettagindex(self, "tag_hardpoint02")); - ofs -= self.origin; - setattachment(self.gun2, self, ""); - setorigin(self.gun2, ofs); - - -} - -void spawnfunc_vehicle_bumblebee() -{ - - precache_model ("models/vehicles/bumblebee_body.dpm"); - precache_model ("models/vehicles/bumblebee_plasma_left.dpm"); - precache_model ("models/vehicles/bumblebee_plasma_right.dpm"); - precache_model ("models/vehicles/bumblebee_ray.dpm"); - - //vehicles_configcheck("vehicle_bumblebee.cfg", autocvar_g_vehicle_bumblebee_health); - - if(autocvar_g_vehicle_bumblebee_energy) - if(autocvar_g_vehicle_bumblebee_energy_regen) - self.vehicle_flags |= VHF_ENERGYREGEN; - - if(autocvar_g_vehicle_bumblebee_shield) - self.vehicle_flags |= VHF_HASSHIELD; - - if(autocvar_g_vehicle_bumblebee_shield_regen) - self.vehicle_flags |= VHF_SHIELDREGEN; - - if(autocvar_g_vehicle_bumblebee_health_regen) - self.vehicle_flags |= VHF_HEALTHREGEN; - - self.think = bumb_dinit; - self.nextthink = time + 1; -} -#endif // SVQC - -#ifdef CSQC -void bumblebee_draw() -{ - -} - -void bumblebee_draw2d() -{ - -} - -void bumblebee_read_extra() -{ - -} - -void vehicle_bumblebee_assemble() -{ - -} -#endif //CSQC diff --git a/qcsrc/server/vehicles/collision.qc b/qcsrc/server/vehicles/collision.qc deleted file mode 100644 index 11488a0d5..000000000 --- a/qcsrc/server/vehicles/collision.qc +++ /dev/null @@ -1,55 +0,0 @@ -vector collision_force; -vector collision_angle; - -vector bb1[9]; -vector bb2[9]; - -float collision_run() -{ - vector vtmp, vmin, vmax, vrot, vforce, vtmp2, vtmp3; - float i, fvel, bcol; - - - // Extract the 8 bbox corners from mins/maxs for self - vmax = self.maxs; - vmin = self.mins; - bb1[0] = vmax; - vtmp = vmax; vtmp_x = vmin_x; bb1[1] = vtmp; - vtmp = vmax; vtmp_y = vmin_y; bb1[2] = vtmp; - vtmp = vmin; vtmp_z = vmax_z; bb1[3] = vtmp; - bb1[4] = vmin; - vtmp = vmin; vtmp_x = vmax_x; bb1[5] = vtmp; - vtmp = vmin; vtmp_y = vmax_y; bb1[6] = vtmp; - vtmp = vmax; vtmp_z = vmin_z; bb1[7] = vtmp; - - makevectors(self.angles + '-2 0 0' * self.angles_x); - bcol = 0; - - // Pass1: Transform by rotation, ajust points by impact/s - for(i = 8; i >= 0; --i) - { - vtmp = bb1[i]; - vtmp = self.origin + vtmp_x * v_forward - vtmp_y * v_right + vtmp_z * v_up; - traceline(self.origin, vtmp, MOVE_WORLDONLY, self); - te_lightning1(world,self.origin,vtmp); - if(trace_fraction != 1.0) - { - vforce += (trace_endpos - vtmp); - vtmp3 = self.origin + self.velocity * frametime; - vtmp2 = vectoangles(normalize(vtmp - vtmp3)); - vrot += (vectoangles(normalize(trace_endpos - vtmp3)) - vtmp2); - bcol += 1; - } - } - - if(bcol) - { - - vtmp = self.origin + self.velocity * frametime; - self.angles += vrot * frametime; - self.velocity += vforce * frametime; - - } - -} - diff --git a/qcsrc/server/vehicles/network.qc b/qcsrc/server/vehicles/network.qc deleted file mode 100644 index 688aa7ca2..000000000 --- a/qcsrc/server/vehicles/network.qc +++ /dev/null @@ -1,237 +0,0 @@ -#ifdef VEHICLES_CSQC -// SendFlags -float VSF_SETUP = 1; /// Send vehicle type etc -float VSF_ORIGIN = 2; /// Send location -float VSF_MOVEMENT = 4; /// Send movement update (and angles) -float VSF_AVEL = 8; /// Send Angular velocity -float VSF_STATS = 16; /// Send ammo, health etc -float VSF_EXTRA = 32; /// Send additional data (turret rotations etc). Handeld per vehicle type. -float VSF_ANIMINFO = 64; /// Animation info -float VSF_FULL_UPDATE = 16777215; /// Send everything - -float VSX_FAR = 1; -float VSX_OWNER = 2; -float VSX_GUN1 = 4; -float VSX_GUN2 = 8; - -#ifdef SVQC -#define VSX_FARDISTANCE 2000 -float send_vehile(entity to, float sf) -{ - float dist, xf; - - var void WriteFunc(float, float); - - dist = vlen(self.origin - to.origin); - if(to == self.owner) - xf |= VSX_OWNER; - else if(dist > VSX_FARDISTANCE) - xf |= VSX_FAR; - - // Always send a movement and origin to owner - if(to == self.owner) - sf |= VSF_ORIGIN | VSF_MOVEMENT; - - WriteByte(MSG_ENTITY, ENT_CLIENT_VEHICLE); - - // We need to know client-side what was sent - WriteByte(MSG_ENTITY, sf); - WriteByte(MSG_ENTITY, xf); - - if(sf & VSF_SETUP) - { - WriteByte(MSG_ENTITY, self.hud); //vehicle type = hud - WriteByte(MSG_ENTITY, self.team); - WriteShort(MSG_ENTITY, self.colormap); - WriteShort(MSG_ENTITY, self.vehicle_flags); - } - - if(sf & VSF_ORIGIN) - { - WriteFunc = ((xf & VSX_FAR) ? WriteShort : WriteCoord); - WriteFunc(MSG_ENTITY, self.origin_x); - WriteFunc(MSG_ENTITY, self.origin_y); - WriteFunc(MSG_ENTITY, self.origin_z); - } - - if(sf & VSF_MOVEMENT) - { - WriteFunc = ((xf & VSX_FAR) ? WriteShort : WriteCoord); - WriteFunc(MSG_ENTITY, self.velocity_x); - WriteFunc(MSG_ENTITY, self.velocity_y); - WriteFunc(MSG_ENTITY, self.velocity_z); - - WriteFunc = ((xf & VSX_FAR) ? WriteShort : WriteAngle); - WriteFunc(MSG_ENTITY, self.angles_x); - WriteFunc(MSG_ENTITY, self.angles_y); - WriteFunc(MSG_ENTITY, self.angles_z); - } - - if(sf & VSF_AVEL) - { - WriteFunc = ((xf & VSX_FAR) ? WriteShort : WriteCoord); - WriteFunc(MSG_ENTITY, self.avelocity_x); - WriteFunc(MSG_ENTITY, self.avelocity_y); - WriteFunc(MSG_ENTITY, self.avelocity_z); - } - - if(sf & VSF_STATS) - { - WriteByte(MSG_ENTITY, self.vehicle_health); - if(xf & VSX_OWNER) - { - WriteByte(MSG_ENTITY, self.vehicle_shield); - WriteByte(MSG_ENTITY, self.vehicle_energy); - - WriteByte(MSG_ENTITY, self.vehicle_ammo1); - WriteByte(MSG_ENTITY, self.vehicle_reload1); - - WriteByte(MSG_ENTITY, self.vehicle_ammo2); - WriteByte(MSG_ENTITY, self.vehicle_reload2); - - } - } - - if(sf & VSF_EXTRA) - self.vehile_send_exta(to, sf); - - return TRUE; -} - -void net_link_vehile() -{ - self.SendFlags = 0xFFFFFF; - Net_LinkEntity(self, FALSE, 0, send_vehile); -} -#endif // SVQC - -#ifdef CSQC -void vehicle_spiderbot_assemble() -{ - -} - -void vehicle_raptor_assemble() -{ - -} - -void vehicle_bumblebee_assemble() -{ - -} - -.float lastupdate; -void read_vehicle(float bIsNew) -{ - float sf, xf; - var float ReadFunc(); - - sf = ReadByte(); - xf = ReadByte(); - - if(xf & VSX_OWNER) - vehicle = self; - - if(sf & VSF_SETUP) - { - self.vehicle_hud = ReadByte(); - self.team = ReadByte(); - self.colormap = ReadShort(); - self.vehicle_flags = ReadShort(); - - switch(self.vehicle_hud) - { - case HUD_WAKIZASHI: - vehicle_racer_assemble(); - break; - case HUD_SPIDERBOT: - vehicle_spiderbot_assemble(); - break; - case HUD_RAPTOR: - vehicle_raptor_assemble(); - break; - case HUD_BUMBLEBEE: - vehicle_bumblebee_assemble(); - break; - default: - break; - } - } - - if(self.vehicle_hud == HUD_WAKIZASHI && xf & VSX_OWNER) - { - - vehicle_hudmodel.owner = self; - } - - //if(xf & VSX_FAR) - // dprint("Client vehicle faaar set\n"); - - if(sf & VSF_ORIGIN) - { - ReadFunc = ((xf & VSX_FAR) ? ReadShort : ReadCoord); - self.origin_x = ReadFunc(); - self.origin_y = ReadFunc(); - self.origin_z = ReadFunc(); - - setorigin(self, self.origin); - //self.lastupdate = time; - } - - if(sf & VSF_MOVEMENT) - { - ReadFunc = ((xf & VSX_FAR) ? ReadShort : ReadCoord); - self.velocity_x = ReadFunc(); - self.velocity_y = ReadFunc(); - self.velocity_z = ReadFunc(); - - ReadFunc = ((sf & VSX_FAR) ? ReadShort : ReadAngle); - self.angles_x = ReadFunc(); - self.angles_y = ReadFunc(); - self.angles_z = ReadFunc(); - - //self.lastupdate = time; - // self.move_velocity = self.velocity; - // self.move_angles = self.angles; - } - - if(sf & VSF_AVEL) - { - ReadFunc = ((xf & VSX_FAR) ? ReadShort : ReadCoord); - self.avelocity_x = ReadFunc(); - self.avelocity_y = ReadFunc(); - self.avelocity_z = ReadFunc(); - - // self.move_avelocity = self.avelocity; - } - - if(sf & VSF_STATS) - { - self.vehicle_health = ReadByte(); - if(xf & VSX_OWNER) - { - self.vehicle_shield = ReadByte(); - self.vehicle_energy = ReadByte(); - self.vehicle_ammo1 = ReadByte(); - self.vehicle_reload1 = ReadByte(); - self.vehicle_ammo2 = ReadByte(); - self.vehicle_reload2 = ReadByte(); - } - } - - if(sf & VSF_EXTRA) - self.vehile_read_exta(sf); - -} - -#endif // CSQC -#else -#ifdef CSQC -.float lastupdate; -void read_vehicle(float bIsNew) -{ - -} -#endif -#endif // VEHICLES_CSQC diff --git a/qcsrc/server/verbstack.qc b/qcsrc/server/verbstack.qc deleted file mode 100644 index b0601afe6..000000000 --- a/qcsrc/server/verbstack.qc +++ /dev/null @@ -1,274 +0,0 @@ -/// Some default stacks. -.entity verbs_idle; -.entity verbs_attack; -.entity verbs_move; -//.entity vchain; - -/// This global gets set to the verb in question each time the stack manager calls verb_call -entity verb; -//.entity current_verb; -//.float verb_done; - -/// Execure this verb -#define VCM_DO 0 -/// Return the value of this verb. Return VS_CALL_REMOVE to delete it. -#define VCM_EVAL 1 -/// This verb is beeing removed NOW (not sent when verb_call returns VS_CALL_REMOVE) -#define VCM_REMOVE 2 - -/// Verb callback -.float(float message) verb_call; - -/// Points to this verb's stack. -.entity verbstack; - -/// Static value of this verb -.float verb_static_value; - -/// verb_call returns this when a verb in not doable -#define VS_CALL_NO 0 -/// verb_call(VCM_DO) returns this when a verb is executing -#define VS_CALL_YES_DOING -1 -/// verb_call(VCM_DO) returns this when a verb did execure and is done -#define VS_CALL_YES_DONE -2 -/// verb_call(VCM_DO) returns this when a verb should be deleted by the stack manager -#define VS_CALL_REMOVE -3 - -/* -void verbstack_updatechain(entity stack) -{ - entity vrb, v; - if not (stack) - return; - - dprint("verbstack_updatechain\n"); - - vrb = findchainentity(verbstack, stack); - if not (vrb) - { - stack.vchain = world; - return; - } - - stack.vchain = vrb; - v = vrb; - - while(vrb) - { - vrb = vrb.chain; - - - } -} - -void verbstack_remove(entity vverb) -{ - entity vstack; - dprint("verbstack_remove\n"); - - vstack = verb.verbstack; - remove(vverb); - vverb.verbstack = world; - verbstack_updatechain(vstack); - - //vverb.think = SUB_Remove; - //vverb.nextthink = time; -} - -void verbstack_thinkremove() -{ - dprint("verbstack_thinkremove\n"); - verbstack_remove(self); -} -*/ - -/** - Push a new verb onto the specified stack. Set vrb_life to make it time-limited. -**/ -entity verbstack_push(entity stack, float(float eval) vrb_call, float val_static, float vrb_life,entity verb_owner) -{ - entity vrb; - - if not(stack) - return world; - - if not(vrb_call) - return world; - - vrb = spawn(); - vrb.owner = verb_owner; - vrb.verbstack = stack; - vrb.verb_call = vrb_call; - vrb.verb_static_value = val_static; - - vrb.classname = "verb"; - stack.classname = "verbstack"; - - if(vrb_life) - { - //vrb.think = verbstack_thinkremove; - vrb.think = SUB_Remove; - vrb.nextthink = time + vrb_life; - } - - //verbstack_updatechain(stack); - - return vrb; -} - -/** - Find the best verb in this stack and execurte it. - ALso remove any verbs returning VS_CALL_REMOVE on VCM_EVAL or VCM_DO -**/ -float verbstack_pop(entity stack) -{ - entity vrb, bestverb, oldself; - float value, bestvalue; - - oldself = self; - - vrb = findchainentity(verbstack,stack); - //vrb = stack.vchain; - //dprint("owner:", stack.owner.classname, " vsn:", stack.classname,"\n"); - while(vrb) - { - //dprint("vn:", vrb.classname,"\n"); - verb = vrb; - vrb = vrb.chain; - self = verb.owner; - value = verb.verb_call(VCM_EVAL); - - if(value < 0) - { - if(value == VS_CALL_REMOVE) - remove(verb); - } - else - { - if(value > bestvalue) - { - bestverb = verb; - bestvalue = value; - } - } - } - - if(bestverb) - { - verb = bestverb; - self = verb.owner; - value = verb.verb_call(VCM_DO); - - if(value == VS_CALL_REMOVE) - remove(bestverb); - } - - self = oldself; - - return value; -} - -float verbstack_popfifo(entity stack) -{ - entity oldself; - float ret; - - oldself = self; - verb = findentity(stack,verbstack,stack); - if not (verb) - ret = 0; - else - { - self = verb.owner; - ret = verb.verb_call(VCM_DO); - - if(ret == VS_CALL_REMOVE) - remove(verb); - } - - self = oldself; - return ret; -} - -/** - Find the best verb in this stack and return it. - ALso remove any verbs returning VS_CALL_REMOVE on VCM_EVAL. -**/ -entity verbstack_pull(entity stack) -{ - entity vrb; - entity bestverb, oldself; - float value, bestvalue; - - oldself = self; - - vrb = findchainentity(verbstack,stack); - while(vrb) - { - self = vrb.owner; - - verb = vrb; - vrb = vrb.chain; - value = verb.verb_call(VCM_EVAL); - - if(value < 0) - { - if(value == VS_CALL_REMOVE) - remove(verb); - } - else - { - if(value > bestvalue) - { - bestverb = verb; - bestvalue = value; - } - } - } - - self = oldself; - - return bestverb; -} - -entity verbstack_pullfifo(entity stack) -{ - return findentity(stack,verbstack,stack); -} - -/** - Delete every verb on this stack, signaling them with VCM_REMOVE first. -**/ -void verbstack_flush(entity stack) -{ - entity vrb, oldself; - - oldself = self; - - vrb = findchainentity(verbstack,stack); - while(vrb) - { - self = vrb.owner; - - verb = vrb; - vrb = vrb.chain; - verb.verb_call(VCM_REMOVE); - remove(verb); - } - - self = oldself; - - //stack.vchain = world; -} - -void verbstack_doverb(entity vrb) -{ - float value; - - verb = vrb; - self = verb.owner; - value = verb.verb_call(VCM_DO); - - if(value == VS_CALL_REMOVE) - remove(vrb); -}