first commit

This commit is contained in:
2019-12-30 17:23:05 +01:00
commit 7fe19ee89f
1149 changed files with 271279 additions and 0 deletions

View File

@@ -0,0 +1,912 @@
/*QUAKED path_corner (0.5 0.3 0) (-8 -8 -8) (8 8 8) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
If a monster targets a path_corner, they will move towards it.
Once a monster hits a path_corner, they will move to the next targeted path_corner.
You can set "pausetime" on a path_corner to enforce a delay before the monster moves
to the next target.
*/
void() path_corner =
{
if (!self.targetname)
{
objerror ("path_corner: no targetname");
remove(self);
return;
}
self.movetype = MOVETYPE_NONE;
self.solid = SOLID_TRIGGER;
setsize (self, '-8 -8 -8', '8 8 8');
};
//============================================================================
/*
=============
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 = vlen (self.origin + self.view_ofs - targ.origin + targ.view_ofs);
if (r < 500)
{
if (r < 120)
return RANGE_MELEE;
else
return RANGE_NEAR;
}
else
{
if (r < 1000)
return RANGE_MID;
else
return RANGE_FAR;
}
};
/*
=============
visible
returns 1 if the entity is visible to self, even if not infront ()
=============
*/
float (entity targ) visible =
{
traceline (self.origin + self.view_ofs, targ.origin + targ.view_ofs, TRUE, self);
if (trace_inwater)
{
if (trace_inopen)
return FALSE;
}
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 =
{
makevectors (self.angles);
vector vec = normalize (targ.origin - self.origin);
float dot = vec * v_forward;
if (dot > 0.3)
return TRUE;
else
return FALSE;
};
void() HuntTarget =
{
self.goalentity = self.enemy;
self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin);
self.think = self.th_run;
self.nextthink = time + 0.1;
SUB_AttackFinished(1); // wait a while before first attack
};
void() SightSound =
{
if (self.classname == "monster_ogre")
sound (self, CHAN_BODY, "ogre/ogwake.wav", 1, ATTN_NORM);
else if (self.classname == "monster_knight")
sound (self, CHAN_BODY, "knight/ksight.wav", 1, ATTN_NORM);
else if (self.classname == "monster_shambler")
sound (self, CHAN_BODY, "shambler/ssight.wav", 1, ATTN_NORM);
else if (self.classname == "monster_demon1")
sound (self, CHAN_BODY, "demon/sight2.wav", 1, ATTN_NORM);
else if (self.classname == "monster_wizard")
sound (self, CHAN_BODY, "wizard/wsight.wav", 1, ATTN_NORM);
else if (self.classname == "monster_zombie")
sound (self, CHAN_BODY, "zombie/z_idle.wav", 1, ATTN_NORM);
else if (self.classname == "monster_dog")
sound (self, CHAN_BODY, "dog/dsight.wav", 1, ATTN_NORM);
else if (self.classname == "monster_hell_knight")
sound (self, CHAN_BODY, "hknight/sight1.wav", 1, ATTN_NORM);
else if (self.classname == "monster_tarbaby")
sound (self, CHAN_BODY, "blob/sight1.wav", 1, ATTN_NORM);
else if (self.classname == "monster_enforcer")
{
float r = randomrange(4);
if (r == 0)
sound (self, CHAN_BODY, "enforcer/sight1.wav", 1, ATTN_NORM);
else if (r == 1)
sound (self, CHAN_BODY, "enforcer/sight2.wav", 1, ATTN_NORM);
else if (r == 2)
sound (self, CHAN_BODY, "enforcer/sight3.wav", 1, ATTN_NORM);
else
sound (self, CHAN_BODY, "enforcer/sight4.wav", 1, ATTN_NORM);
}
else if (self.classname == "monster_army")
sound (self, CHAN_BODY, "soldier/sight1.wav", 1, ATTN_NORM);
else if (self.classname == "monster_shalrath")
sound (self, CHAN_BODY, "shalrath/sight.wav", 1, ATTN_NORM);
};
void() FoundTarget =
{
if (self.enemy.classname == "player")
{
sight_entity = self;
sight_entity_time = time;
}
self.show_hostile = time + 1; // wake up other monsters
SightSound ();
HuntTarget ();
};
/*==========
FindTarget
==========*/
float() FindTarget =
{
if (intermission_running)
return FALSE;
if (sight_entity_time >= time - 0.1 && !(self.spawnflags & MONSTER_AMBUSH) )
{
entity client = sight_entity;
if (client.enemy == self.enemy)
return FALSE;
}
else
{
client = checkclient ();
if (!client)
return FALSE;
}
if (client == self.enemy)
return FALSE;
if (client.flags & FL_NOTARGET)
return FALSE;
if (client.items & IT_INVISIBILITY)
return FALSE;
float 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)
{
if (!infront (client))
return FALSE;
}
//
// got one
//
self.enemy = client;
if (self.enemy.classname != "player")
{
self.enemy = self.enemy.enemy;
if (self.enemy.classname != "player")
{
self.enemy = world;
return FALSE;
}
}
FoundTarget ();
return TRUE;
};
//=============================================================================
/*==========
ai_movetogoal
==========*/
float (float dist) SV_CloseEnough =
{
if (self.goalentity.absmin.x > self.absmax.x + dist)
return FALSE;
if (self.goalentity.absmax.x < self.absmin.x - dist)
return FALSE;
if (self.goalentity.absmin.y > self.absmax.y + dist)
return FALSE;
if (self.goalentity.absmax.y < self.absmin.y - dist)
return FALSE;
if (self.goalentity.absmin.z > self.absmax.z + dist)
return FALSE;
if (self.goalentity.absmax.z < self.absmin.z - dist)
return FALSE;
return TRUE;
};
//.float blocked_time;
//.float blocked_count;
void(entity goal, float dist) ai_movetogoal =
{
// new target
if (self.goalentity != goal)
{
self.goalentity = goal;
self.ideal_yaw = vectoyaw(goal.origin - self.origin);
}
vector oldorigin = self.origin;
movetogoal(dist);
if (self.origin != oldorigin)
return;
if (SV_CloseEnough(dist))
{
//dprint("SV_CloseEnough\n");
self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin);
changeyaw();
if (walkmove(self.angles_y, dist))
return;
float ofs;
if (self.lefty)
ofs = 45;
else
ofs = -45;
if (walkmove(self.angles_y + ofs, dist))
return;
self.lefty = 1 - self.lefty;
walkmove(self.angles_y - ofs, dist);
}
/*
if (self.blocked_count > 10)
{
self.blocked_count = 0;
self.blocked_time = time + 5;
}
if (self.blocked_time > time)
{
movetogoal(dist);
return;
}
self.ideal_yaw = vectoyaw(goal.origin - self.origin);
changeyaw();
if (walkmove(self.angles_y, dist))
return;
self.blocked_count = self.blocked_count + 1;
float ofs;
if (self.lefty)
ofs = 45;
else
ofs = -45;
if (walkmove(self.angles_y + ofs, dist))
return;
self.lefty = 1 - self.lefty;
walkmove(self.angles_y - ofs, dist);*/
};
void(float dist) ai_forward =
{
walkmove(self.angles_y, dist);
};
void(float dist) ai_back =
{
walkmove(self.angles_y + 180, dist);
};
void(float dist) ai_pain =
{
ai_back(dist);
};
void(float dist) ai_painforward =
{
ai_forward(dist);
};
void(float dist) ai_walk =
{
if (FindTarget())
return;
ai_movetogoal(self.movetarget, dist);
if (vlen(self.origin - self.movetarget.origin) < 32)
{
entity targ = find(world, targetname, self.movetarget.target);
if (targ.classname == "path_corner")
{
self.movetarget = self.goalentity = targ;
self.ideal_yaw = vectoyaw(targ.origin - self.origin);
if (targ.pausetime > 0)
{
self.think = self.th_stand;
self.pausetime = time + targ.pausetime;
}
}
else
{
self.think = self.th_stand;
self.pausetime = -1;
}
}
};
void() ai_stand =
{
if (FindTarget())
return;
if (time > self.pausetime && self.pausetime > 0)
{
if (self.movetarget)
{
self.th_walk();
return;
}
}
// random angle turns
if (time > self.search_time)
{
self.search_time = time + 1 + random() * 2;
if (self.angles_y != self.ideal_yaw)
self.angles_y = self.ideal_yaw;
else
{
if (random() < 0.5)
self.angles_y = self.ideal_yaw + random() * 30;
else
self.angles_y = self.ideal_yaw - random() * 30;
}
}
};
void() ai_turn =
{
if (FindTarget())
return;
changeyaw ();
};
float(float ang) FacingIdeal =
{
float delta = angcomp(self.ideal_yaw, self.angles_y);
if (delta > ang)
return FALSE;
if (delta < -ang)
return FALSE;
/*float delta = anglemod(self.angles_y - self.ideal_yaw);
if (delta > 45 && delta < 315)
return FALSE;
*/
return TRUE;
};
//=============================================================================
float() WizardCheckAttack;
float() DogCheckAttack;
float() CheckAnyAttack =
{
if (self.classname == "monster_ogre")
return OgreCheckAttack ();
if (!enemy_vis)
return FALSE;
if (self.classname == "monster_army")
return SoldierCheckAttack ();
if (self.classname == "monster_shambler")
return ShamCheckAttack ();
if (self.classname == "monster_demon1")
return DemonCheckAttack ();
if (self.classname == "monster_dog")
return DogCheckAttack ();
if (self.classname == "monster_wizard")
return WizardCheckAttack ();
return CheckAttack ();
};
/*==========
ai_run_melee
Turn until facing enemy then launch melee attack
==========
*/
void() ai_run_melee =
{
self.ideal_yaw = enemy_yaw;
changeyaw();
if (FacingIdeal(90))
{
self.th_melee ();
self.attack_state = AS_STRAIGHT;
}
};
/*==============
ai_run_missile
Turn until facing enemy then launch missile attack
==========*/
void() ai_run_missile =
{
if (self.attack_state == AS_SPAM)
{
self.ideal_yaw = vectoyaw(self.enemy_last - self.origin);
changeyaw();
}
else
{
self.ideal_yaw = enemy_yaw;
changeyaw();
// if the enemy has dropped out of sight, cancel the attack
if (!enemy_vis)
{
dprint("ai_run_missile: not visible\n");
self.attack_state = AS_STRAIGHT;
return;
}
}
if (FacingIdeal(90))
{
if (self.attack_state == AS_SPAM)
self.th_spam();
else
self.th_missile();
self.attack_state = AS_STRAIGHT;
}
};
/*==========
ai_run_slide
Face the enemy and strafe sideways
==========*/
void(float dist) ai_run_slide =
{
self.ideal_yaw = enemy_yaw;
changeyaw();
float ofs;
if (self.lefty)
ofs = 90;
else
ofs = -90;
if (walkmove (self.ideal_yaw + ofs, dist))
return;
self.lefty = 1 - self.lefty;
walkmove (self.ideal_yaw - ofs, dist);
};
#define ROUTE_MAX 256
float route_busy;
.float route;
.entity route_table[ROUTE_MAX];
.float distance;
.float route_time;
/*============
ClearRoute
clear the monsters current route
============*/
void() ClearRoute =
{
self.route = -1;
for (float i = 0; i < ROUTE_MAX; i = i + 1)
self.route_table[i] = world;
};
/*============
ClearWayTable
clear the waypoint table (which is shared between all monsters)
marks all waypoints as not visited and infinite distance
============*/
void() ClearWayTable =
{
entity e = way_head;
while (e)
{
e.state = -1;
e.distance = -1;
e.last_way = world;
e = e._next;
}
};
/*==========
CheckDoors
check if a door is in the way of two waypoints while checking a route
==========*/
float(entity e) CheckDoors =
{
traceline(self.enemy.origin, e.origin, TRUE, self.enemy);
if (trace_fraction == 1)
return TRUE;
if (trace_ent == e)
return TRUE;
if (trace_ent.classname == "door")
{
// we check .owner because it's the master door
if (trace_ent.owner.items) // key door
return FALSE;
if (trace_ent.owner.health) // shootable door
return FALSE;
if (trace_ent.owner.targetname != "") // triggered door
return FALSE;
return TRUE; // regular door with a trigger field
}
dprint("CheckDoors: \n");
dprint(trace_ent.classname);
dprint("\n");
return FALSE; // something else in the way
};
/*==========
CheckRoute
called from RouteThink to update the distances between the waypoints
==========*/
void(entity e) CheckRoute =
{
if (!e)
return;
if (e.state > 0)
return;
if (!CheckDoors(e))
return;
float dist = self.enemy.distance;
dist = dist + vlen(self.enemy.origin - e.origin);
dist = dist + random() * 32; // add some fuzzyness
if ((e.distance == -1) || (dist < e.distance))
{
e.distance = dist;
e.last_way = self.enemy;
}
};
/*==========
RouteThink
return the shortest path to the goal waypoint
==========*/
void() RouteThink =
{
entity e;
// the monster died while calculating a route - free up the table
if (self.owner.health <= 0)
{
route_busy = 0;
remove(self);
fixer = world;
return;
}
// visit all waypoints linking to current waypoint and update their distance
CheckRoute(self.enemy.target1);
CheckRoute(self.enemy.target2);
CheckRoute(self.enemy.target3);
CheckRoute(self.enemy.target4);
// mark this waypoint as visited
self.enemy.state = 1;
// found route
if (self.goalentity.state == 1)
{
//dprint("RouteThink: found route\n");
e = self.goalentity;
float i = 0;
while (e)
{
self.owner.route_table[i] = e;
e = e.last_way;
if (e) // don't count the final waypoint, as it's the one the monster is already at
i = i + 1;
}
self.owner.route = i - 1; // because route_table is a zero indexed array
self.owner.route_time = time + 5;
route_busy = FALSE;
remove(self);
fixer = world;
return;
}
// find the nearest, unvisited waypoint
entity best = world;
float bdist = -1;
e = way_head;
while (e)
{
if (e.state == -1) // not visited
{
if (e.distance > 0) // we use -1 for "infinite distance"
{
if (e.distance < bdist || bdist == -1)
{
best = e;
bdist = e.distance;
}
}
}
e = e._next;
}
// no valid route exists between the two waypoints
if (best == world)
{
//dprint("RouteThink: no valid route exists\n");
route_busy = FALSE;
remove(self);
fixer = world;
return;
}
// update the next waypoint
self.enemy = best;
self.think = RouteThink;
self.nextthink = time;
};
/*============
StartRoute
called by monsters when they want to find a path between waypoint A and B
uses thinks to avoid tripping the runaway counter (RouteThink)
============*/
void(entity e1, entity e2) StartRoute =
{
// no waypoints exist in map
if (!waypoints)
return;
// another monster is already calculating a route
if (route_busy)
return;
// sanity check
if (e1 == world || e2 == world || e1 == e2)
return;
//dprint("StartRoute\n");
// mark the table as busy and clear it for use
route_busy = TRUE;
ClearWayTable();
// the first waypoint is always distance zero
e1.distance = 0;
if (!fixer)
fixer = spawn();
fixer.owner = self;
fixer.enemy = e1; // start waypoint
fixer.goalentity = e2; // end waypoint
fixer.nextthink = time;
fixer.think = RouteThink;
};
/*==========
FindWaypoint
==========*/
entity(entity monster, entity start) FindWaypoint =
{
if (!waypoints)
return world;
if (start != world)
{
float best_dist = vlen(start.origin - monster.origin);
entity best = start;
}
else
{
best_dist = -1;
best = world;
}
if (best_dist < 20)
return best;
entity w = way_head;
while(w)
{
float way_dist = vlen(w.origin - monster.origin);
if (way_dist < best_dist || best_dist == -1)
{
if (wisible(monster, w))
{
best_dist = way_dist;
best = w;
}
}
w = w._next;
}
if (best_dist < 256)
{
//dprint("FindWaypoint: found\n");
return best;
}
else
{
//dprint("FindWaypoint: world\n");
return world;
}
};
/*
=============
ai_run
The monster has an enemy it is trying to kill
=============
*/
void(float dist) ai_run =
{
// stop all attacks during the intermission
if (intermission_running)
{
ClearRoute();
self.enemy = self.goalentity = world;
self.th_stand();
return;
}
// our enemy has died, so look for a new one
if (self.enemy.health <= 0)
{
ClearRoute();
self.enemy = self.goalentity = world;
// look for previous enemy
if (self.oldenemy.health > 0)
{
self.enemy = self.oldenemy;
HuntTarget();
}
else
{
self.th_stand();
return;
}
}
// FIXME: get rid of globals
enemy_vis = visible(self.enemy);
enemy_infront = infront(self.enemy);
enemy_range = range(self.enemy);
enemy_yaw = vectoyaw(self.enemy.origin - self.origin);
if (enemy_vis)
{
self.enemy_last = self.enemy.origin + self.enemy.view_ofs;
self.search_time = time + 5;
}
// look for other players in co-op
if (coop && self.search_time < time)
{
if (FindTarget())
return;
}
// we've started an attack, so make sure we're facing the right way before launching
if (self.attack_state == AS_MISSILE || self.attack_state == AS_SPAM)
{
ai_run_missile();
return;
}
if (self.attack_state == AS_MELEE)
{
ai_run_melee();
return;
}
// check for beginning an attack
if (CheckAnyAttack())
return;
// used by scrags
if (self.attack_state == AS_SLIDING)
{
ai_run_slide(dist);
return;
}
// no waypoints in map, so just use regular movement
if (waypoint_mode < WM_LOADED || !waypoints)
{
ai_movetogoal(self.enemy, dist);
return;
}
// we have an enemy, but no route, so find a route to the enemy
if (self.route < 0)
{
//dprint("Finding route\n");
self.current_way = FindWaypoint(self, self.current_way);
self.enemy.current_way = FindWaypoint(self.enemy, self.enemy.current_way);
StartRoute(self.current_way, self.enemy.current_way);
ai_movetogoal(self.enemy, dist);
return;
}
// monster has failed to move to the next waypoint, so drop the route
if (time > self.route_time)
{
//dprint("Dropping route\n");
ClearRoute();
ai_movetogoal(self.enemy, dist);
return;
}
// periodically refresh enemy waypoint
if (!route_busy)
{
self.enemy.current_way = FindWaypoint(self.enemy, self.enemy.current_way);
if (self.route_table[0] != self.enemy.current_way)
StartRoute(self.current_way, self.enemy.current_way);
}
// move to the next waypoint
entity w = self.route_table[self.route];
ai_movetogoal(w, dist);
// hit next waypoint
if (vlen(self.origin - w.origin) < 64)
{
self.route_time = time + 5;
self.current_way = self.route_table[self.route];
self.route = self.route - 1;
// hit last waypoint
if (self.route < 0)
{
dprint("Hit last waypoint\n");
ClearRoute();
}
}
};

View File

@@ -0,0 +1,174 @@
/*==========
spawn_ambient
==========*/
void(float soundnum, vector org, float vol, float atn) spawn_ambient =
{
WriteByte(MSG_ALL, SVC_SPAWNSTATICSOUND);
WriteCoord(MSG_ALL, org_x);
WriteCoord(MSG_ALL, org_y);
WriteCoord(MSG_ALL, org_z);
WriteByte(MSG_ALL, soundnum);
WriteByte(MSG_ALL, vol * 255);
WriteByte(MSG_ALL, atn * 64);
};
/*==========
ambient_start
==========*/
void(string s, float vol, float atn) ambient_start =
{
precache_sound(s);
ambientsound(self.origin, s, vol, atn);
};
/*QUAKED ambient_custom (0.3 0.1 0.6) (-8 -8 -8) (8 8 8)
Customisable ambient sound.
Keys:
"noise" - Ambient sound to play.
"volume" - Set the volume of the sound. Range 0-1. Default 0.5.
"distance" - Set the attenuation of the ambient sound:
0 - static (default, usual for ambient sounds)
1 - idle (usually used for monster idle sounds)
2 - normal (normal attenuation)
3 - none (no attenuation, audible throughout entire map)
*/
void() ambient_custom =
{
if (!self.noise)
{
objerror("no noise specified\n");
remove(self);
return;
}
if (self.volume > 1)
self.volume = 1;
if (self.volume <= 0)
self.volume = 0.5;
if (self.distance < 0)
self.distance = 0;
if (self.distance > 3)
self.distance = 3;
float atn = 0;
switch (self.distance)
{
case 0:
default:
atn = ATTN_STATIC;
break;
case 1:
atn = ATTN_IDLE;
break;
case 2:
atn = ATTN_NORM;
break;
case 3:
atn = ATTN_NONE;
break;
}
ambient_start(self.noise, self.volume, atn);
};
/*QUAKED ambient_comp_hum (0.3 0.1 0.6) (-8 -8 -8) (8 8 8)
Ambient computer hum.
*/
void() ambient_comp_hum =
{
ambient_start("ambience/comp1.wav", 0.5, ATTN_STATIC);
};
/*QUAKED ambient_drip (0.3 0.1 0.6) (-8 -8 -8) (8 8 8)
Ambient water drip.
*/
void() ambient_drip =
{
ambient_start("ambience/drip1.wav", 0.5, ATTN_STATIC);
};
/*QUAKED ambient_drone (0.3 0.1 0.6) (-8 -8 -8) (8 8 8)
Ambient drone.
*/
void() ambient_drone =
{
ambient_start("ambience/drone6.wav", 0.5, ATTN_STATIC);
};
/*QUAKED ambient_fire (0.3 0.1 0.6) (-8 -8 -8) (8 8 8)
Ambient fire crackling.
*/
void() ambient_fire =
{
ambient_start("ambience/fire1.wav", 0.5, ATTN_STATIC);
};
/*QUAKED ambient_flouro_buzz (0.3 0.1 0.6) (-8 -8 -8) (8 8 8)
Ambient flourescent light buzzing.
*/
void() ambient_flouro_buzz =
{
ambient_start("ambience/buzz1.wav", 0.5, ATTN_STATIC);
};
/*QUAKED ambient_light_buzz (0.3 0.1 0.6) (-8 -8 -8) (8 8 8)
Ambient light buzz.
*/
void() ambient_light_buzz =
{
ambient_start("ambience/fl_hum1.wav", 0.5, ATTN_STATIC);
};
/*QUAKED ambient_suck_wind (0.3 0.1 0.6) (-8 -8 -8) (8 8 8)
Ambient sucking wind.
*/
void() ambient_suck_wind =
{
ambient_start("ambience/suck1.wav", 0.5, ATTN_STATIC);
};
/*QUAKED ambient_swamp1 (0.3 0.1 0.6) (-8 -8 -8) (8 8 8)
Ambient swamp - 1st variation.
*/
void() ambient_swamp1 =
{
ambient_start("ambience/swamp1.wav", 0.5, ATTN_STATIC);
};
/*QUAKED ambient_swamp2 (0.3 0.1 0.6) (-8 -8 -8) (8 8 8)
Ambient swamp - 2nd variation.
*/
void() ambient_swamp2 =
{
ambient_start("ambience/swamp2.wav", 0.5, ATTN_STATIC);
};
/*QUAKED ambient_teleport (0.3 0.1 0.6) (-8 -8 -8) (8 8 8)
Ambient teleporter hum.
*/
void() ambient_teleport =
{
ambient_start("ambience/hum1.wav", 0.5, ATTN_STATIC);
};
/*QUAKED ambient_thunder (0.3 0.1 0.6) (-8 -8 -8) (8 8 8)
Ambient thunder.
*/
void() ambient_thunder =
{
ambient_start("ambience/thunder1.wav", 0.5, ATTN_STATIC);
};
/*QUAKED ambient_water (0.3 0.1 0.6) (-8 -8 -8) (8 8 8)
Ambient water.
*/
void() ambient_water =
{
ambient_start("ambience/water1.wav", 0.5, ATTN_STATIC);
};
/*QUAKED ambient_wind (0.3 0.1 0.6) (-8 -8 -8) (8 8 8)
Ambient wind.
*/
void() ambient_wind =
{
ambient_start("ambience/wind2.wav", 0.5, ATTN_STATIC);
};

View File

@@ -0,0 +1,84 @@
/*==========
wall_use
==========*/
void() wall_use =
{
self.frame = 1 - self.frame;
};
/*QUAKED func_wall (0 .5 .8) ? X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
Simple solid bmodel
Keys:
"targetname" - if triggered, the bmodel will toggle its frame/animation sequence from +0 -> +9 to +a -> +j
*/
void() func_wall =
{
self.angles = '0 0 0';
self.movetype = MOVETYPE_PUSH;
self.solid = SOLID_BSP;
self.use = wall_use;
setmodel (self, self.model);
};
/*QUAKED func_illusionary (0 .5 .8) ? X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
A simple bmodel that looks solid but lets the player walk through it
Keys:
"targetname" - if triggered, the bmodel will toggle its frame/animation sequence from +0 -> +9 to +a -> +j
*/
void() func_illusionary =
{
self.angles = '0 0 0';
self.movetype = MOVETYPE_NONE;
self.solid = SOLID_NOT;
setmodel (self, self.model);
if (self.targetname != "")
self.use = wall_use;
else
makestatic(self);
};
/*QUAKED func_episodegate (0 .5 .8) ? E1 E2 E3 E4 X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
This bmodel will only appear if the episode has already been completed.
Keys:
"targetname" - if triggered, the bmodel will toggle its frame/animation sequence from +0 -> +9 to +a -> +j
Spawnflags:
E1, E2, E3, E4
*/
void() func_episodegate =
{
if (!(serverflags & self.spawnflags))
{
remove(self);
return;
}
self.angles = '0 0 0';
self.movetype = MOVETYPE_PUSH;
self.solid = SOLID_BSP;
self.use = wall_use;
setmodel (self, self.model);
};
/*QUAKED func_bossgate (0 .5 .8) ? X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
This bmodel appears unless the player has all of the episode runes.
Keys:
"targetname" - if triggered, the bmodel will toggle its frame/animation sequence from +0 -> +9 to +a -> +j
*/
void() func_bossgate =
{
if ((serverflags & 15) == 15)
{
remove(self);
return;
}
self.angles = '0 0 0';
self.movetype = MOVETYPE_PUSH;
self.solid = SOLID_BSP;
self.use = wall_use;
setmodel (self, self.model);
};

View File

@@ -0,0 +1,39 @@
entity bodyque_head;
void() bodyque = {};
void() InitBodyQue =
{
float count = 10;
bodyque_head = world;
entity prev = world;
entity corpse = world;
while (count)
{
corpse = spawn();
corpse.classname = "bodyque";
if (bodyque_head == world)
bodyque_head = corpse;
if (prev != world)
prev.owner = corpse;
prev = corpse;
count = count - 1;
}
corpse.owner = bodyque_head;
};
void(entity ent) CopyToBodyQue =
{
bodyque_head.angles = ent.angles;
bodyque_head.model = ent.model;
bodyque_head.modelindex = ent.modelindex;
bodyque_head.frame = ent.frame;
bodyque_head.colormap = ent.colormap;
bodyque_head.movetype = ent.movetype;
bodyque_head.velocity = ent.velocity;
bodyque_head.flags = 0;
setorigin (bodyque_head, ent.origin);
setsize (bodyque_head, ent.mins, ent.maxs);
bodyque_head = bodyque_head.owner;
};

View File

@@ -0,0 +1,322 @@
static enumflags { EXPLODE, NO_EXPLOSION_SPRITE, NO_EXPLOSION_SOUND, SPAWN_SMOKE };
/*==========
breakable_pain
==========*/
static void(entity attacker, float damage) breakable_pain =
{
// play impact sound if set
if (self.noise2 != "")
sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
};
/*==========
breakable_think
==========*/
static void() breakable_think =
{
// hack to drop to ground if something below us was removed
if (self.flags & FL_ONGROUND)
self.flags = self.flags - FL_ONGROUND;
// fade out when self.attack_finished is up
if (time > self.attack_finished)
{
if (self.alpha == 0)
self.alpha = 1;
self.alpha = self.alpha - 0.1;
if (self.alpha <= 0)
{
remove(self);
return;
}
}
self.think = breakable_think;
self.nextthink = time + 0.1;
};
/*==========
breakable_touch
==========*/
static void() breakable_touch =
{
if (other != world)
return;
if (self.count)
return;
if (random() < 0.5)
return;
self.count = 1;
if (self.noise2 != "")
sound(self, CHAN_VOICE, self.noise2, 0.5, ATTN_IDLE);
};
/*==========
breakable_smoke
==========*/
static void(vector org) breakable_smoke =
{
entity smoke = spawn();
smoke.classname = "smoke";
smoke.solid = SOLID_NOT;
smoke.movetype = MOVETYPE_TOSS;
setmodel(smoke, "progs/smoke.mdl");
setorigin(smoke, org);
setsize(smoke, '0 0 0', '0 0 0');
smoke.velocity = [crandom()*200, crandom()*200, random()*100 + 100];
smoke.think = SUB_Remove;
smoke.nextthink = time + 1;
};
/*==========
breakable_spawn_debris
==========*/
static void(vector org, vector sz, vector dir) breakable_spawn_debris =
{
entity debris = spawn();
debris.classname = "debris";
debris.solid = SOLID_TRIGGER;
debris.movetype = MOVETYPE_BOUNCE;
setorigin(debris, [org.x + random() * sz.x, org.y + random() * sz.y, org.z + random() * sz.z]);
float r = random();
if (r < 0.33)
setmodel(debris, self.mdl1);
else if (r < 0.66)
setmodel(debris, self.mdl2);
else
setmodel(debris, self.mdl3);
// spawn some smoke particles
if (self.spawnflags & SPAWN_SMOKE)
if (random() < 0.5)
breakable_smoke(debris.origin);
debris.angles_y = random() * 360;
debris.velocity = dir * (50 + random() * 50);
debris.velocity_z = 50 + random() * 50;
if (self.health < -40)
debris.velocity = debris.velocity * 2;
debris.avelocity = randomvec() * 100;
debris.noise2 = self.noise2;
debris.touch = breakable_touch;
debris.think = breakable_think;
debris.nextthink = time + 0.1;
debris.attack_finished = time + 10 + random() * 10;
};
/*==========
breakable_explode
==========*/
static void() breakable_explode =
{
setorigin(self, realorigin(self)); // fix bmodel origin
if (self.dmg > 0)
RadiusDamage (self, self, self.dmg, world);
if (self.spawnflags & NO_EXPLOSION_SOUND)
{
// vanilla hack to get explosion particles with no sound/light
particle (self.origin, '0 0 0', 0, 255);
}
else
{
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_EXPLOSION);
WriteCoord (MSG_BROADCAST, self.origin_x);
WriteCoord (MSG_BROADCAST, self.origin_y);
WriteCoord (MSG_BROADCAST, self.origin_z);
}
if (self.spawnflags & NO_EXPLOSION_SPRITE)
remove(self);
else
BecomeExplosion ();
};
/*==========
breakable_break
==========*/
static void(entity inflictor) breakable_break =
{
self.takedamage = DAMAGE_NO;
self.use = SUB_Null;
// play sound, if set
if (self.noise1 != "")
sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
// turn shadow off, supported by ericw-tools
if (self.switchshadstyle >= 32)
lightstyle(self.switchshadstyle, "m");
// the debris moves away from the direction of attack
// if movedir is set, this always overrides the direction
while (self.count > 0)
{
vector dir;
if (self.movedir)
dir = self.movedir;
else
{
if (inflictor == world)
dir = randomvec();
else
dir = normalize((self.absmin + self.absmax) * 0.5 - inflictor.origin);
}
breakable_spawn_debris(self.absmin, self.size, dir);
self.count = self.count - 1;
}
if (self.spawnflags & EXPLODE)
self.think = breakable_explode;
else
self.think = SUB_Remove;
self.nextthink = self.ltime + 0.01; // use ltime because it's MOVETYPE_PUSH
// fire targets
activator = self.enemy;
UseTargets();
};
/*==========
breakable_die
==========*/
static void(entity inflictor, entity attacker) breakable_die =
{
self.enemy = attacker;
breakable_break(inflictor);
};
/*==========
breakable_use
==========*/
static void() breakable_use =
{
self.enemy = activator;
breakable_break(world);
};
/*QUAKED func_breakable (0 .5 .8) ? EXPLODE NO_EXPLOSION_SPRITE NO_EXPLOSION_SOUND SPAWN_SMOKE X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
Breakable brush model
Spawnflags:
EXPLODE - will explode upon destruction. Set the dmg key to the force of the explosion.
You can set dmg to 0 for just the explosion effects.
NO_EXPLOSION_SPRITE - don't show explosion sprite.
NO_EXPLOSION_SOUND - don't make explosion sound or light.
SPAWN_SMOKE - will spawn some additional smoke upon destuction
Keys:
"style" "n"
Preset style, 1=base crates, 2=stone/brick
Sets debris model, particle color and sounds automatically
If mdl1-3, noise or colour are set they will override the preset
"mdl1", "mdl2", "mdl3" "name"
custom models for debris chunks
"color" "n"
particle color for damage, range 0-254 (from palette)
"noise1", "noise2" "name"
custom sound for break / damage
"health" "n"
damage required to destroy. default 30.
"targetname" "name"
if set, the breakable must be triggered to destroy it
"count" "n"
number of pieces of debris to spawn. default 8.
"angle" "n"
If set, overrides the direction debris moves in. Use -1 and -2 for up/down. Use 360 for a yaw of 0.
"dmg" "n"
Amount of explosive damage to deal. Default 60.
*/
void() func_breakable =
{
// turn shadow on, supported by ericw-tools
if (self.switchshadstyle >= 32)
lightstyle(self.switchshadstyle, "a");
// pre-set styles
// 1 - base crate
if (self.style == 1)
{
if (!self.mdl1)
self.mdl1 = "maps/crate1.bsp";
if (!self.mdl2)
self.mdl2 = "maps/crate2.bsp";
if (!self.mdl3)
self.mdl3 = "maps/crate3.bsp";
if (!self.noise1)
self.noise1 = "break/metbrk.wav";
if (!self.noise2)
self.noise2 = "break/methit.wav";
if (!self.colour)
self.colour = 24;
}
// 2 - stone/brick
else if (self.style == 2)
{
if (!self.mdl1)
self.mdl1 = "maps/brick1.bsp";
if (!self.mdl2)
self.mdl2 = "maps/brick2.bsp";
if (!self.mdl3)
self.mdl3 = "maps/brick3.bsp";
if (!self.noise1)
self.noise1 = "break/stonebrk.wav";
if (!self.noise2)
self.noise2 = "break/stonehit.wav";
if (!self.colour)
self.colour = 16;
}
if (!self.mdl1 || !self.mdl2 || !self.mdl3)
{
objerror("mdl1, mdl2 or mdl3 not set\n");
remove(self);
return;
}
precache_model(self.mdl1);
precache_model(self.mdl2);
precache_model(self.mdl3);
// destruction and impact noises - optional
if (self.noise1 != "")
precache_sound(self.noise1);
if (self.noise2 != "")
precache_sound(self.noise2);
SetPositiveDefault(count, 8);
SetPositiveDefault(dmg, 8);
if (self.angles)
SetMovedir();
self.movetype = MOVETYPE_PUSH;
self.solid = SOLID_BSP;
setmodel (self, self.model);
// shootable, not triggered
if (!self.targetname)
{
SetPositiveDefault(health, 30);
self.takedamage = DAMAGE_YES;
self.th_pain = breakable_pain;
self.th_die = breakable_die;
}
else
self.use = breakable_use;
};

View File

@@ -0,0 +1,111 @@
void() make_bubbles;
void() bubble_remove;
void() bubble_bob;
/*QUAKED air_bubbles (0 .5 .8) (-8 -8 -8) (8 8 8)
testing air bubbles
*/
void() air_bubbles =
{
if (deathmatch)
{
remove (self);
return;
}
precache_model ("progs/s_bubble.spr");
self.nextthink = time + 1;
self.think = make_bubbles;
};
void() make_bubbles =
{
local entity bubble;
bubble = spawn();
setmodel (bubble, "progs/s_bubble.spr");
setorigin (bubble, self.origin);
bubble.movetype = MOVETYPE_NOCLIP;
bubble.solid = SOLID_NOT;
bubble.velocity = '0 0 15';
bubble.nextthink = time + 0.5;
bubble.think = bubble_bob;
bubble.touch = bubble_remove;
bubble.classname = "bubble";
bubble.frame = 0;
bubble.cnt = 0;
setsize (bubble, '-8 -8 -8', '8 8 8');
self.nextthink = time + random() + 0.5;
self.think = make_bubbles;
};
void() bubble_split =
{
local entity bubble;
bubble = spawn();
setmodel (bubble, "progs/s_bubble.spr");
setorigin (bubble, self.origin);
bubble.movetype = MOVETYPE_NOCLIP;
bubble.solid = SOLID_NOT;
bubble.velocity = self.velocity;
bubble.nextthink = time + 0.5;
bubble.think = bubble_bob;
bubble.touch = bubble_remove;
bubble.classname = "bubble";
bubble.frame = 1;
bubble.cnt = 10;
setsize (bubble, '-8 -8 -8', '8 8 8');
self.frame = 1;
self.cnt = 10;
if (self.waterlevel != 3)
remove (self);
};
void() bubble_remove =
{
if (other.classname == self.classname)
{
// dprint ("bump");
return;
}
remove(self);
};
void() bubble_bob =
{
local float rnd1, rnd2, rnd3;
self.cnt = self.cnt + 1;
if (self.cnt == 4)
bubble_split();
if (self.cnt == 20)
remove(self);
rnd1 = self.velocity_x + (-10 + (random() * 20));
rnd2 = self.velocity_y + (-10 + (random() * 20));
rnd3 = self.velocity_z + 10 + random() * 10;
if (rnd1 > 10)
rnd1 = 5;
if (rnd1 < -10)
rnd1 = -5;
if (rnd2 > 10)
rnd2 = 5;
if (rnd2 < -10)
rnd2 = -5;
if (rnd3 < 10)
rnd3 = 15;
if (rnd3 > 30)
rnd3 = 25;
self.velocity_x = rnd1;
self.velocity_y = rnd2;
self.velocity_z = rnd3;
self.nextthink = time + 0.5;
self.think = bubble_bob;
};

View File

@@ -0,0 +1,239 @@
static enumflags { BUTTON_START_OFF };
/*==========
button_done
the button is back in its original position
==========*/
static void() button_done =
{
self.state = STATE_BOTTOM;
};
/*==========
button_return
the button starts to return to its original position
==========*/
static void() button_return =
{
self.state = STATE_DOWN;
// use normal textures
self.frame = 0;
// can be shot again
if (self.max_health)
{
self.health = self.max_health;
self.takedamage = DAMAGE_YES;
}
SUB_CalcMove (self.pos1, self.speed, button_done);
};
/*==========
button_wait
the button has reached it's secondary position
==========*/
static void() button_wait =
{
self.state = STATE_TOP;
// use alternatve textures
self.frame = 1;
// fire targets
activator = self.enemy;
UseTargets();
// return after a delay of self.wait
if (self.wait > 0)
{
self.think = button_return;
self.nextthink = self.ltime + self.wait;
}
// never return
else
{
self.think = SUB_Null;
self.nextthink = -1;
}
};
/*==========
button_fire
the button has been activated by trigger, touch or damage
==========*/
static void() button_fire =
{
// already activated
if (self.state == STATE_UP || self.state == STATE_TOP)
return;
sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
self.state = STATE_UP;
SUB_CalcMove (self.pos2, self.speed, button_wait);
};
/*==========
button_touch
==========*/
static void() button_touch =
{
if (other.classname != "player")
return;
if (other.health <= 0)
return;
self.enemy = other;
button_fire ();
};
/*==========
button_killed
the button has been shot
==========*/
static void(entity inflictor, entity attacker) button_killed =
{
self.takedamage = DAMAGE_NO; // will be restored upon return
self.enemy = attacker;
button_fire();
};
/*==========
button_activate
enable the button for pushing or shooting
==========*/
static void() button_activate =
{
// use normal texture
self.frame = 0;
// shootable button
if (self.health > 0)
{
self.max_health = self.health;
self.takedamage = DAMAGE_YES;
self.th_die = button_killed;
}
// pushable button
else
self.touch = button_touch;
};
/*==========
button_use
the button has been triggered
==========*/
static void() button_use =
{
// if the button starts disabled, using it enables it
if (self.spawnflags & BUTTON_START_OFF)
{
self.spawnflags = self.spawnflags - BUTTON_START_OFF;
button_activate();
return;
}
self.enemy = activator;
button_fire();
};
/*==========
button_blocked
do nothing
==========*/
static void() button_blocked =
{
};
/*QUAKED func_button (0 .5 .8) ? START_OFF X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
A button that can either be pushed or shot.
When a button is activated, it moves the distance of its size,
in the direction of its angle, leaving a "lip" at the end of the move.
Alternatively, you can specify a set "distance" to move.
When the move is completed, it triggers all of its targets, waits some time,
then returns to its original position where it can be pushed or shot again.
Spawnflags:
START_OFF - the button starts in a disabled state, and it must be triggered to enable it.
Once enabled, it acts like any other button.
Keys:
"target" - entities with a matching targetname will be triggered.
"killtarget" - entities with a matching targetname will be removed.
"targetname" - if triggered, the button will fire, unless it's already in motion
or switched off. if switched off, it will enable itself.
"message" - message to print to player on activation.
"delay" - button will wait some time before triggering its targets.
"angle" - direction of movement. use -1 for up and -2 for down.
"speed" - speed of movement. default 40.
"wait" - wait before returning. default 1 second. use -1 to never return.
"lip" - number of units to leave at end of the move. default 4.
"distance" - manually specify the distance to move, ignoring the size and lip
"health" - if set, the button must be shot rather than pushed.
"sounds" -
-1) custom sound
0) steam metal
1) wooden clunk
2) metallic click
3) in-out
"noise" - custom sound to use for button activation
*/
void() func_button =
{
if (self.sounds == 0)
self.noise = "buttons/airbut1.wav";
else if (self.sounds == 1)
self.noise = "buttons/switch21.wav";
else if (self.sounds == 2)
self.noise = "buttons/switch02.wav";
else if (self.sounds == 3)
self.noise = "buttons/switch04.wav";
if (!self.noise)
{
objerror("noise must be set for custom sound\n");
remove(self);
return;
}
precache_sound (self.noise);
SetPositiveDefault(health, 0);
SetPositiveDefault(speed, 40);
SetFloatDefault(wait, 1);
SetFloatDefault(lip, 4);
self.colour = 192;
self.movetype = MOVETYPE_PUSH;
self.solid = SOLID_BSP;
setmodel (self, self.model);
// calculate starting and secondary position
SetMovedir();
self.state = STATE_BOTTOM;
self.pos1 = self.origin;
if (self.distance > 0)
self.pos2 = self.pos1 + (self.movedir * self.distance);
else
self.pos2 = self.pos1 + self.movedir * (fabs(self.movedir*self.size) - self.lip);
self.blocked = button_blocked;
self.use = button_use;
if (self.spawnflags & BUTTON_START_OFF)
{
dprint("potential button with erroneous spawnflag at ");
dprint(vtos(realorigin(self)));
dprint("\n");
self.frame = 1; // use alternative texture
return;
}
button_activate();
};

View File

@@ -0,0 +1,962 @@
// prototypes
void(entity attacker, float damage) player_pain;
void() player_stand;
void (vector org) spawn_tfog;
void (vector org, entity death_owner) spawn_tdeath;
float modelindex_eyes, modelindex_player;
/*
=============================================================================
LEVEL CHANGING / INTERMISSION
=============================================================================
*/
void() SetChangeParms =
{
// player was dead during the intermission
if (self.health <= 0)
{
SetNewParms();
return;
}
// items
// remove powerups and keys
self.items = self.items - (self.items &
(IT_SUPERHEALTH | IT_KEY1 | IT_KEY2 | IT_INVISIBILITY | IT_INVULNERABILITY | IT_SUIT | IT_QUAD));
parm1 = self.items;
// cap super health
if (self.health > 100)
self.health = 100;
if (self.health < 50)
self.health = 50;
parm2 = self.health;
// weapons and ammo
parm3 = self.weapon;
if (self.ammo_shells < 25)
self.ammo_shells = 25;
parm4 = self.ammo_shells;
parm5 = self.ammo_nails;
parm6 = self.ammo_rockets;
parm7 = self.ammo_cells;
// armor
parm8 = self.armorvalue;
parm9 = self.armortype;
};
void() SetNewParms =
{
parm1 = IT_AXE | IT_SHOTGUN; // items
parm2 = 100; // health
parm3 = IT_SHOTGUN; // weapon
parm4 = 25; // shells
parm5 = 0; // nails
parm6 = 0; // rockets
parm7 = 0; // cells
parm8 = 0; // armorvalue
parm9 = 0; // armortype
};
void() DecodeLevelParms =
{
// take away all items on starting a new episode
if ((!deathmatch) && (mapname == "start"))
SetNewParms();
self.items = parm1;
self.health = parm2;
self.weapon = parm3;
self.ammo_shells = parm4;
self.ammo_nails = parm5;
self.ammo_rockets = parm6;
self.ammo_cells = parm7;
self.armorvalue = parm8;
self.armortype = parm9;
};
/*
=============================================================================
PLAYER GAME EDGE FUNCTIONS
=============================================================================
*/
// called by ClientKill and DeadThink
void() respawn =
{
if (coop)
{
// make a copy of the dead body for appearances sake
CopyToBodyQue (self);
// get the spawn parms as they were at level start
setspawnparms (self);
// respawn
PutClientInServer ();
}
else if (deathmatch)
{
// make a copy of the dead body for appearances sake
CopyToBodyQue (self);
// set default spawn parms
SetNewParms ();
// respawn
PutClientInServer ();
}
else
{ // restart the entire server
localcmd ("restart\n");
}
};
/*
============
ClientKill
Player entered the suicide command
============
*/
void() ClientKill =
{
// don't allow suicide during the intermission
// the engine aleady blocks it when dead
if (intermission_running)
return;
/*
bprint (self.netname);
bprint (" suicides\n");
*/
self.frags = self.frags - 1; // extra penalty
self.health = 0;
Killed(self, self, self);
};
/*
============
SelectSpawnPoint
Returns the entity to spawn at
============
*/
entity() SelectSpawnPoint =
{
local entity spot;
local entity thing;
local float pcount;
if (developer)
{
spot = find (world, classname, "info_player_test");
if (spot)
return spot;
}
if (coop)
{
lastspawn = find(lastspawn, classname, "info_player_coop");
if (lastspawn == world)
lastspawn = find (lastspawn, classname, "info_player_start");
if (lastspawn != world)
return lastspawn;
}
else if (deathmatch)
{
spot = lastspawn;
while (1)
{
spot = find(spot, classname, "info_player_deathmatch");
if (spot)
{
if (spot == lastspawn)
return lastspawn;
pcount = 0;
thing = findradius(spot.origin, 32);
while(thing)
{
if (thing.classname == "player")
pcount = pcount + 1;
thing = thing.chain;
}
if (pcount == 0)
{
lastspawn = spot;
return spot;
}
}
else
{
spot = find (world, classname, "info_player_start");
if (!spot)
error ("PutClientInServer: no info_player_start on level");
return spot;
}
}
}
if (serverflags)
{ // return with a rune to start
spot = find (world, classname, "info_player_start2");
if (spot)
return spot;
}
spot = find (world, classname, "info_player_start");
if (!spot)
error ("PutClientInServer: no info_player_start on level");
return spot;
};
/*
===========
PutClientInServer
called each time a player is spawned
============
*/
void() DecodeLevelParms;
void(entity inflictor, entity attacker) PlayerDie;
/*
void() PutClientInServer =
{
self.classname = "player";
self.health = 100;
self.solid = SOLID_NOT;
self.movetype = MOVETYPE_NONE;
entity spot = SelectSpawnPoint ();
self.origin = self.oldorigin = spot.origin + '0 0 128';
self.angles = [0, -90, 0];
self.fixangle = TRUE;
setmodel (self, "progs/s_null.spr");
setsize (self, [0, 0, 0], [0, 0, 0]);
};
*/
void() PutClientInServer =
{
self.classname = "player";
self.health = self.max_health = 100;
self.headmodel = "progs/h_player.mdl";
self.deadflag = DEAD_NO;
self.takedamage = DAMAGE_AIM;
self.solid = SOLID_SLIDEBOX;
self.movetype = MOVETYPE_WALK;
self.flags = FL_CLIENT;
self.th_pain = player_pain;
self.th_die = PlayerDie;
self.view_ofs = '0 0 22';
// liquid stuff
self.air_finished = time + 12;
self.dmg = 2;
// powerups
self.effects = 0;
self.super_damage_finished = 0;
self.radsuit_finished = 0;
self.invisible_finished = 0;
self.invincible_finished = 0;
self.invincible_time = 0;
// get items from parms and update weapon
DecodeLevelParms();
W_UpdateWeapon(self);
self.show_hostile = 0;
self.attack_finished = time;
// put the player on the spawn spot
entity spot = SelectSpawnPoint ();
self.origin = self.oldorigin = spot.origin + '0 0 1';
self.angles = spot.angles;
self.fixangle = TRUE;
self.pausetime = 0;
self.velocity = '0 0 0';
setmodel (self, "progs/eyes.mdl");
modelindex_eyes = self.modelindex;
setmodel (self, "progs/player.mdl");
modelindex_player = self.modelindex;
setsize (self, VEC_HULL_MIN, VEC_HULL_MAX);
player_stand();
if (deathmatch || coop)
{
makevectors(self.angles);
spawn_tfog (self.origin + v_forward*20);
}
spawn_tdeath (self.origin, self);
};
/*
===============================================================================
RULES
===============================================================================
*/
/*
go to the next level for deathmatch
only called if a time or frag limit has expired
*/
void() NextLevel =
{
local entity o;
if (mapname == "start")
{
if (!cvar("registered"))
{
mapname = "e1m1";
}
else if (!(serverflags & 1))
{
mapname = "e1m1";
serverflags = serverflags | 1;
}
else if (!(serverflags & 2))
{
mapname = "e2m1";
serverflags = serverflags | 2;
}
else if (!(serverflags & 4))
{
mapname = "e3m1";
serverflags = serverflags | 4;
}
else if (!(serverflags & 8))
{
mapname = "e4m1";
serverflags = serverflags - 7;
}
o = spawn();
o.map = mapname;
}
else
{
// find a trigger changelevel
o = find(world, classname, "trigger_changelevel");
// go back to start if no trigger_changelevel
if (!o)
{
mapname = "start";
o = spawn();
o.map = mapname;
}
}
nextmap = o.map;
gameover = TRUE;
if (o.nextthink < time)
{
o.think = StartIntermission;
o.nextthink = time + 0.1;
}
};
/*
============
CheckRules
Exit deathmatch games upon conditions
============
*/
void() CheckRules =
{
local float timelimit;
local float fraglimit;
if (gameover) // someone else quit the game already
return;
timelimit = cvar("timelimit") * 60;
fraglimit = cvar("fraglimit");
if (timelimit && time >= timelimit)
{
NextLevel ();
return;
}
if (fraglimit && self.frags >= fraglimit)
{
NextLevel ();
return;
}
};
//============================================================================
void() PlayerDeathThink =
{
if (self.deadflag == DEAD_DYING)
return;
// come to a stop
if (self.flags & FL_ONGROUND)
{
float forward = vlen(self.velocity);
forward = forward - 20;
if (forward <= 0)
self.velocity = '0 0 0';
else
self.velocity = forward * normalize(self.velocity);
}
// wait for button down
if (self.deadflag == DEAD_DEAD)
{
if (self.button0 || self.button2)
self.deadflag = DEAD_RESPAWNABLE;
return;
}
// wait for button release
if (!self.button0 && !self.button2)
respawn();
};
void() PlayerJump =
{
if (self.flags & FL_WATERJUMP)
return;
if (self.waterlevel >= 2)
{
if (self.watertype == CONTENT_WATER)
self.velocity_z = 100;
else if (self.watertype == CONTENT_SLIME)
self.velocity_z = 80;
else
self.velocity_z = 50;
// play swiming sound
if (self.swim_flag < time)
{
self.swim_flag = time + 1;
if (random() < 0.5)
sound (self, CHAN_BODY, "misc/water1.wav", 1, ATTN_NORM);
else
sound (self, CHAN_BODY, "misc/water2.wav", 1, ATTN_NORM);
}
return;
}
if (!(self.flags & FL_ONGROUND))
return;
if ( !(self.flags & FL_JUMPRELEASED) )
return; // don't pogo stick
self.flags = self.flags - (self.flags & FL_JUMPRELEASED);
self.flags = self.flags - FL_ONGROUND; // don't stairwalk
self.button2 = 0;
// player jumping sound
sound (self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM);
self.velocity_z = self.velocity_z + 270;
};
/*
===========
WaterMove
============
*/
.float dmgtime;
void() CheckWaterJump =
{
local vector start, end;
// check for a jump-out-of-water
makevectors (self.angles);
start = self.origin;
start_z = start_z + 8;
v_forward_z = 0;
normalize(v_forward);
end = start + v_forward*24;
traceline (start, end, TRUE, self);
if (trace_fraction < 1)
{ // solid at waist
start_z = start_z + self.maxs_z - 8;
end = start + v_forward*24;
self.movedir = trace_plane_normal * -50;
traceline (start, end, TRUE, self);
if (trace_fraction == 1)
{ // open at eye level
self.flags = self.flags | FL_WATERJUMP;
self.velocity_z = 225;
self.flags = self.flags - (self.flags & FL_JUMPRELEASED);
self.teleport_time = time + 2; // safety net
return;
}
}
};
void() WaterMove =
{
// don't drown if no clip...
if (self.movetype == MOVETYPE_NOCLIP)
{
self.air_finished = time + 12;
self.dmg = 2;
return;
}
if (self.waterlevel == 2)
CheckWaterJump ();
if (self.waterlevel != 3)
{
if (self.air_finished < time)
sound (self, CHAN_VOICE, "player/gasp2.wav", 1, ATTN_NORM);
else if (self.air_finished < time + 9)
sound (self, CHAN_VOICE, "player/gasp1.wav", 1, ATTN_NORM);
self.air_finished = time + 12;
self.dmg = 2;
}
else if (self.air_finished < time)
{ // drown!
if (self.pain_finished < time)
{
self.dmg = self.dmg + 2;
if (self.dmg > 15)
self.dmg = 10;
Damage (self, world, world, self.dmg);
self.pain_finished = time + 1;
}
}
if (!self.waterlevel)
{
if (self.flags & FL_INWATER)
{
// play leave water sound
sound (self, CHAN_BODY, "misc/outwater.wav", 1, ATTN_NORM);
self.flags = self.flags - FL_INWATER;
}
return;
}
if (self.watertype == CONTENT_LAVA)
{ // do damage
if (self.dmgtime < time)
{
if (self.radsuit_finished > time)
self.dmgtime = time + 1;
else
self.dmgtime = time + 0.2;
Damage (self, world, world, 10*self.waterlevel);
}
}
else if (self.watertype == CONTENT_SLIME)
{ // do damage
if (self.dmgtime < time && self.radsuit_finished < time)
{
self.dmgtime = time + 1;
Damage (self, world, world, 4*self.waterlevel);
}
}
if ( !(self.flags & FL_INWATER) )
{
// player enter water sound
if (self.watertype == CONTENT_LAVA)
sound (self, CHAN_BODY, "player/inlava.wav", 1, ATTN_NORM);
if (self.watertype == CONTENT_WATER)
sound (self, CHAN_BODY, "player/inh2o.wav", 1, ATTN_NORM);
if (self.watertype == CONTENT_SLIME)
sound (self, CHAN_BODY, "player/slimbrn2.wav", 1, ATTN_NORM);
self.flags = self.flags + FL_INWATER;
self.dmgtime = 0;
}
if (! (self.flags & FL_WATERJUMP) )
self.velocity = self.velocity - 0.8*self.waterlevel*frametime*self.velocity;
};
/*
================
PlayerPreThink
Called every frame before physics are run
================
*/
.float ladder_sound;
.float ladder_time;
void() PlayerPreThink =
{
if (intermission_running)
{
IntermissionThink();
return;
}
if (self.deadflag)
{
PlayerDeathThink();
return;
}
WaypointPreFrame();
CheckRules ();
WaterMove ();
if (self.flags2 & FL2_ONLADDER)
{
self.flags2 = self.flags2 - FL2_ONLADDER;
// climb
if (self.button2)
{
// don't pogo stick if we drop off
self.flags = self.flags - self.flags & FL_JUMPRELEASED;
self.velocity = '0 0 160';
if (time > self.ladder_time)
{
self.ladder_time = time + 0.5;
self.ladder_sound = self.ladder_sound + 1;
if (self.ladder_sound > 4)
self.ladder_sound = 0;
if (self.ladder_sound == 0)
sound(self, CHAN_BODY, "player/ladder1.wav", 1, ATTN_IDLE);
if (self.ladder_sound == 1)
sound(self, CHAN_BODY, "player/ladder2.wav", 1, ATTN_IDLE);
if (self.ladder_sound == 2)
sound(self, CHAN_BODY, "player/ladder3.wav", 1, ATTN_IDLE);
if (self.ladder_sound == 3)
sound(self, CHAN_BODY, "player/ladder4.wav", 1, ATTN_IDLE);
if (self.ladder_sound == 4)
sound(self, CHAN_BODY, "player/ladder5.wav", 1, ATTN_IDLE);
}
}
else
{
self.flags = self.flags | FL_JUMPRELEASED;
// restrict horizontal movement
self.velocity = 0.9 * self.velocity;
self.velocity_z = 0;
}
}
else
{
self.gravity = 1;
if (self.button2)
PlayerJump ();
else
self.flags = self.flags | FL_JUMPRELEASED;
}
// teleporters can force a non-moving pause time
if (time < self.pausetime)
self.velocity = '0 0 0';
// check weapon ammo
if (time > self.attack_finished && !W_CheckNoAmmo(self))
{
self.weapon = W_BestWeapon(self);
W_UpdateWeapon(self);
}
};
/*
================
CheckPowerups
Check for turning off powerups
================
*/
void() CheckPowerups =
{
// megahelth
if (self.items & IT_SUPERHEALTH)
{
if (self.health <= self.max_health)
{
self.items = self.items - IT_SUPERHEALTH;
}
else if (time > self.health_rot_time)
{
self.health = self.health - 1;
self.health_rot_time = time + 1;
}
}
// invisibility
if (self.invisible_finished)
{
// sound and screen flash when items starts to run out
if (self.invisible_sound < time)
{
sound (self, CHAN_AUTO, "items/inv3.wav", 0.5, ATTN_IDLE);
self.invisible_sound = time + ((random() * 3) + 1);
}
if (self.invisible_finished < time + 3)
{
if (self.invisible_time == 1)
{
sprint (self, "Ring of Shadows magic is fading\n");
stuffcmd (self, "bf\n");
sound (self, CHAN_AUTO, "items/inv2.wav", 1, ATTN_NORM);
self.invisible_time = time + 1;
}
if (self.invisible_time < time)
{
self.invisible_time = time + 1;
stuffcmd (self, "bf\n");
}
}
if (self.invisible_finished < time)
{ // just stopped
self.items = self.items - IT_INVISIBILITY;
self.invisible_finished = 0;
self.invisible_time = 0;
}
// use the eyes
self.frame = 0;
self.modelindex = modelindex_eyes;
}
else
self.modelindex = modelindex_player; // don't use eyes
// invincibility
if (self.invincible_finished)
{
// sound and screen flash when items starts to run out
if (self.invincible_finished < time + 3)
{
if (self.invincible_time == 1)
{
sprint (self, "Protection is almost burned out\n");
stuffcmd (self, "bf\n");
sound (self, CHAN_AUTO, "items/protect2.wav", 1, ATTN_NORM);
self.invincible_time = time + 1;
}
if (self.invincible_time < time)
{
self.invincible_time = time + 1;
stuffcmd (self, "bf\n");
}
}
if (self.invincible_finished < time)
{ // just stopped
self.items = self.items - IT_INVULNERABILITY;
self.invincible_time = 0;
self.invincible_finished = 0;
}
if (self.invincible_finished > time)
self.effects = self.effects | EF_DIMLIGHT;
else
self.effects = self.effects - (self.effects & EF_DIMLIGHT);
}
// super damage
if (self.super_damage_finished)
{
// sound and screen flash when items starts to run out
if (self.super_damage_finished < time + 3)
{
if (self.super_time == 1)
{
sprint (self, "Quad Damage is wearing off\n");
stuffcmd (self, "bf\n");
sound (self, CHAN_AUTO, "items/damage2.wav", 1, ATTN_NORM);
self.super_time = time + 1;
}
if (self.super_time < time)
{
self.super_time = time + 1;
stuffcmd (self, "bf\n");
}
}
if (self.super_damage_finished < time)
{ // just stopped
self.items = self.items - IT_QUAD;
self.super_damage_finished = 0;
self.super_time = 0;
}
if (self.super_damage_finished > time)
self.effects = self.effects | EF_DIMLIGHT;
else
self.effects = self.effects - (self.effects & EF_DIMLIGHT);
}
// suit
if (self.radsuit_finished)
{
self.air_finished = time + 12; // don't drown
// sound and screen flash when items starts to run out
if (self.radsuit_finished < time + 3)
{
if (self.rad_time == 1)
{
sprint (self, "Air supply in Biosuit expiring\n");
stuffcmd (self, "bf\n");
sound (self, CHAN_AUTO, "items/suit2.wav", 1, ATTN_NORM);
self.rad_time = time + 1;
}
if (self.rad_time < time)
{
self.rad_time = time + 1;
stuffcmd (self, "bf\n");
}
}
if (self.radsuit_finished < time)
{ // just stopped
self.items = self.items - IT_SUIT;
self.rad_time = 0;
self.radsuit_finished = 0;
}
}
};
/*
================
PlayerPostThink
Called every frame after physics are run
================
*/
void() PlayerPostThink =
{
if (intermission_running || self.deadflag)
return;
WaypointPostFrame();
W_WeaponFrame ();
if ((self.jump_flag < -300) && (self.flags & FL_ONGROUND) && (self.health > 0))
{
if (self.watertype == CONTENT_WATER)
sound (self, CHAN_BODY, "player/h2ojump.wav", 1, ATTN_NORM);
else if (self.jump_flag < -650)
{
Damage (self, world, world, 5);
sound (self, CHAN_VOICE, "player/land2.wav", 1, ATTN_NORM);
self.deathtype = "falling";
}
else
sound (self, CHAN_VOICE, "player/land.wav", 1, ATTN_NORM);
self.jump_flag = 0;
}
if (!(self.flags & FL_ONGROUND))
self.jump_flag = self.velocity_z;
CheckPowerups ();
};
/*
===========
ClientConnect
called when a player connects to a server
============
*/
void() ClientConnect =
{
bprint (self.netname);
bprint (" entered the game\n");
// a client connecting during an intermission can cause problems
if (intermission_running)
ExitIntermission();
};
/*
===========
ClientDisconnect
called when a player disconnects from a server
============
*/
void() ClientDisconnect =
{
// if the level end trigger has been activated, just return
// since they aren't *really* leaving
if (gameover)
return;
self.classname = string_null;
self.health = 0;
sound (self, CHAN_BODY, "player/tornoff2.wav", 1, ATTN_NONE);
// let everyone else know
bprint (self.netname);
bprint (" left the game with ");
bprint (ftos(self.frags));
if (self.frags == 1)
bprint (" frag\n");
else
bprint (" frags");
// already gibbed?
if (self.model == "progs/h_player.mdl")
return;
self.effects = 0;
self.modelindex = modelindex_player;
self.frame = 60; // $deatha11
self.solid = SOLID_NOT;
self.movetype = MOVETYPE_TOSS;
self.deadflag = DEAD_DEAD;
self.think = SUB_Null;
self.nextthink = -1;
};

View File

@@ -0,0 +1,215 @@
/*==========
CanDamage
used for explosions and melee attacks
==========*/
float(entity targ, entity inflictor) CanDamage =
{
// bmodels need special checking because their origin is 0,0,0
if (targ.movetype == MOVETYPE_PUSH)
{
traceline(inflictor.origin, realorigin(targ), 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;
};
/*==========
Killed
==========*/
void(entity targ, entity inflictor, entity attacker) Killed =
{
entity oself = self;
self = targ;
// doors, triggers, etc
if (self.movetype == MOVETYPE_PUSH || self.movetype == MOVETYPE_NONE)
{
self.th_die(inflictor, attacker);
self = oself;
return;
}
if (self.flags & FL_CLIENT)
{
// don't let sbar look bad
if (self.health < -99)
self.health = -99;
// display obituary text
Obituary(self, attacker, inflictor);
}
if (self.flags & FL_MONSTER)
monster_death_use();
self.takedamage = DAMAGE_NO;
self.touch = SUB_Null;
self.th_die (inflictor, attacker);
self = oself;
};
/*==========
Damage
==========*/
void(entity targ, entity inflictor, entity attacker, float damage) Damage =
{
if (!targ.takedamage)
return;
// check for quad damage
if (attacker.items & IT_QUAD)
damage = damage * 4;
// save damage based upon armor
float save, take;
save = ceil(targ.armortype * damage);
// lost all armor
if (save >= targ.armorvalue)
{
save = targ.armorvalue;
targ.armortype = 0;
targ.items = targ.items - (targ.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3));
}
targ.armorvalue = targ.armorvalue - save;
take = ceil(damage - save);
if (targ.flags & FL_CLIENT)
{
// add to the damage total for clients, which will be sent as a single
// message at the end of the frame
targ.dmg_take = targ.dmg_take + take;
targ.dmg_save = targ.dmg_save + save;
targ.dmg_inflictor = inflictor;
}
// push players around
if ( (inflictor != world) && (targ.movetype == MOVETYPE_WALK) )
{
vector dir = targ.origin - realorigin(inflictor);
dir = normalize(dir);
targ.velocity = targ.velocity + dir*damage*8;
}
// check for godmode or pent
if (targ.flags & FL_GODMODE)
return;
if (targ.items & IT_INVULNERABILITY)
{
if (targ.invincible_sound < time)
{
sound (targ, CHAN_ITEM, "items/protect3.wav", 1, ATTN_NORM);
targ.invincible_sound = time + 2;
}
return;
}
// team play damage avoidance
if ((teamplay == 1) && (targ.team > 0) && (targ.team == attacker.team))
return;
// do the damage
targ.health = targ.health - take;
if (targ.health <= 0)
{
Killed (targ, inflictor, attacker);
return;
}
// react to the damage
entity oself = self;
self = targ;
// monsters get mad, unless of the same class (except for grunts)
if ( (self.flags & FL_MONSTER) && (attacker.flags & FL_CLIENT | FL_MONSTER) )
{
if (self != attacker && attacker != self.enemy)
{
if ( (self.classname != attacker.classname) || (self.classname == "monster_army" ) )
{
if (self.enemy.classname == "player")
self.oldenemy = self.enemy;
self.enemy = attacker;
FoundTarget();
}
}
}
if (self.th_pain)
{
self.th_pain (attacker, take);
// nightmare mode monsters don't go into pain frames often
if (skill == 3 && self.flags & FL_MONSTER)
self.pain_finished = time + 5;
}
self = oself;
};
/*==========
RadiusDamage
==========*/
void(entity inflictor, entity attacker, float damage, entity ignore) RadiusDamage =
{
float attacker_damaged = FALSE;
float attacker_points = 0;
entity head = findradius(inflictor.origin, damage + 40);
while (head)
{
if (head != ignore)
{
if (head.takedamage)
{
vector org = realorigin(head);
float points = 0.5*vlen (inflictor.origin - org);
if (points < 0)
points = 0;
points = damage - points;
if (points > 0)
{
if (CanDamage (head, inflictor))
{
if (head == attacker)
{
attacker_damaged = TRUE;
attacker_points = points * 0.5;
}
else
{
if (head.classname == "monster_shambler")
Damage (head, inflictor, attacker, points * 0.5);
else
Damage (head, inflictor, attacker, points);
}
}
}
}
}
head = head.chain;
}
if (attacker_damaged)
Damage (attacker, inflictor, attacker, attacker_points);
};

View File

@@ -0,0 +1,470 @@
/*========================================
defs.qc
========================================*/
/*==========
System Globals
==========*/
entity self, other, world;
float time, frametime, force_retouch;
string mapname;
float deathmatch, coop, teamplay, serverflags;
float total_secrets, total_monsters, found_secrets, killed_monsters;
float parm1, parm2, parm3, parm4, parm5, parm6, parm7, parm8,
parm9, parm10, parm11, parm12, parm13, parm14, parm15, parm16;
vector v_forward, v_up, v_right;
float trace_allsolid, trace_startsolid, trace_fraction;
vector trace_endpos, trace_plane_normal;
float trace_plane_dist;
entity trace_ent;
float trace_inopen, trace_inwater;
entity msg_entity;
void() main, StartFrame, PlayerPreThink, PlayerPostThink, ClientKill, ClientConnect,
PutClientInServer, ClientDisconnect, SetNewParms, SetChangeParms;
void end_sys_globals;
/*==========
System Fields
==========*/
.float modelindex;
.vector absmin, absmax;
.float ltime;
.float movetype;
.float solid;
.vector origin;
.vector oldorigin;
.vector velocity;
.vector angles;
.vector avelocity;
.vector punchangle;
.string classname;
.string model;
.float frame;
.float skin;
.float effects;
.vector mins, maxs;
.vector size;
.void() touch;
.void() use;
.void() think;
.void() blocked;
.float nextthink;
.entity groundentity;
.float health;
.float frags;
.float weapon;
.string weaponmodel;
.float weaponframe;
.float currentammo;
.float ammo_shells, ammo_nails, ammo_rockets, ammo_cells;
.float items;
.float takedamage;
.entity chain;
.float deadflag;
.vector view_ofs;
.float button0;
.float button1;
.float button2;
.float impulse;
.float fixangle;
.vector v_angle;
.float idealpitch;
.string netname;
.entity enemy;
.float flags;
.float colormap;
.float team;
.float max_health;
.float teleport_time;
.float armortype;
.float armorvalue;
.float waterlevel;
.float watertype;
.float ideal_yaw;
.float yaw_speed;
.entity aiment;
.entity goalentity;
.float spawnflags;
.string target;
.string targetname;
.float dmg_take;
.float dmg_save;
.entity dmg_inflictor;
.entity owner;
.vector movedir;
.string message;
.float sounds;
.string noise, noise1, noise2, noise3;
void end_sys_fields;
/*==========
Builtins
==========*/
__used void(vector ang) makevectors = #1;
__used void(entity e, vector o) setorigin = #2;
__used void(entity e, string m) setmodel = #3;
__used void(entity e, vector min, vector max) setsize = #4;
__used void() break = #6;
__used float() random = #7;
__used void(entity e, float chan, string samp, float vol, float atten) sound = #8;
__used vector(vector v) normalize = #9;
__used void(string e) error = #10;
__used void(string e) objerror = #11;
__used float(vector v) vlen = #12;
__used float(vector v) vectoyaw = #13;
__used entity() spawn = #14;
__used void(entity e) remove = #15;
__used void(vector v1, vector v2, float nomonsters, entity forent) traceline = #16;
__used entity() checkclient = #17;
__used entity(entity start, .string fld, string match) find = #18;
__used string(string s) precache_sound = #19;
__used string(string s) precache_model = #20;
__used void(entity client, string s) stuffcmd = #21;
__used entity(vector org, float rad) findradius = #22;
__used void(string s) bprint = #23;
__used void(entity client, string s, optional string s2) sprint = #24;
__used void(string s) dprint = #25;
__used string(float f) ftos = #26;
__used string(vector v) vtos = #27;
__used void() coredump = #28;
__used void() traceon = #29;
__used void() traceoff = #30;
__used void(entity e) eprint = #31;
__used float(float yaw, float dist) walkmove = #32;
__used float() droptofloor= #34;
__used void(float style, string value) lightstyle = #35;
__used float(float v) rint = #36;
__used float(float v) floor = #37;
__used float(float v) ceil = #38;
__used float(entity e) checkbottom = #40;
__used float(vector v) pointcontents = #41;
__used float(float f) fabs = #43;
__used vector(entity e, float speed) aim = #44;
__used float(string s) cvar = #45;
__used void(string s) localcmd = #46;
__used entity(entity e) nextent = #47;
__used void particle(vector o, vector d, float color, float count) = #48;
__used void() changeyaw = #49;
__used vector(vector v) vectoangles = #51;
__used void(float to, float f) WriteByte = #52;
__used void(float to, float f) WriteChar = #53;
__used void(float to, float f) WriteShort = #54;
__used void(float to, float f) WriteLong = #55;
__used void(float to, float f) WriteCoord = #56;
__used void(float to, float f) WriteAngle = #57;
__used void(float to, string s) WriteString = #58;
__used void(float to, entity s) WriteEntity = #59;
__used void(float step) movetogoal = #67;
__used string(string s) precache_file = #68;
__used void(entity e) makestatic = #69;
__used void(string s) changelevel = #70;
__used void(string var, string val) cvar_set = #72;
__used void(entity client, string s1, optional string s2, optional string s3,
optional string s4, optional string s5, optional string s6, optional string s7) centerprint = #73;
__used void(vector pos, string samp, float vol, float atten) ambientsound = #74;
__used string(string s) precache_model2 = #75;
__used string(string s) precache_sound2 = #76;
__used string(string s) precache_file2 = #77;
__used void(entity e) setspawnparms = #78;
/*==========
Constants
==========*/
// booleans
const float FALSE = 0;
const float TRUE = 1;
// flags
float FL_FLY = 1;
float FL_SWIM = 2;
// 4 is unused
float FL_CLIENT = 8;
float FL_INWATER = 16;
float FL_MONSTER = 32;
float FL_GODMODE = 64;
float FL_NOTARGET = 128;
float FL_ITEM = 256;
float FL_ONGROUND = 512;
float FL_PARTIALGROUND = 1024;
float FL_WATERJUMP = 2048;
float FL_JUMPRELEASED = 4096;
// movetype
float MOVETYPE_NONE = 0;
float MOVETYPE_WALK = 3;
float MOVETYPE_STEP = 4;
float MOVETYPE_FLY = 5;
float MOVETYPE_TOSS = 6;
float MOVETYPE_PUSH = 7;
float MOVETYPE_NOCLIP = 8;
float MOVETYPE_FLYMISSILE = 9;
float MOVETYPE_BOUNCE = 10;
// solid
float SOLID_NOT = 0;
float SOLID_TRIGGER = 1;
float SOLID_BBOX = 2;
float SOLID_SLIDEBOX = 3;
float SOLID_BSP = 4;
// range
float RANGE_MELEE = 0;
float RANGE_NEAR = 1;
float RANGE_MID = 2;
float RANGE_FAR = 3;
// deadflag
float DEAD_NO = 0;
float DEAD_DYING = 1;
float DEAD_DEAD = 2;
float DEAD_RESPAWNABLE = 4;
// takedamage
float DAMAGE_NO = 0;
float DAMAGE_YES = 1;
float DAMAGE_AIM = 2;
// items
float IT_SHOTGUN = 1;
float IT_SUPER_SHOTGUN = 2;
float IT_NAILGUN = 4;
float IT_SUPER_NAILGUN = 8;
float IT_GRENADE_LAUNCHER = 16;
float IT_ROCKET_LAUNCHER = 32;
float IT_LIGHTNING = 64;
float IT_EXTRA_WEAPON = 128;
float IT_SHELLS = 256;
float IT_NAILS = 512;
float IT_ROCKETS = 1024;
float IT_CELLS = 2048;
float IT_AXE = 4096;
float IT_ARMOR1 = 8192;
float IT_ARMOR2 = 16384;
float IT_ARMOR3 = 32768;
float IT_SUPERHEALTH = 65536;
float IT_KEY1 = 131072;
float IT_KEY2 = 262144;
float IT_INVISIBILITY = 524288;
float IT_INVULNERABILITY = 1048576;
float IT_SUIT = 2097152;
float IT_QUAD = 4194304;
// content
float CONTENT_EMPTY = -1;
float CONTENT_SOLID = -2;
float CONTENT_WATER = -3;
float CONTENT_SLIME = -4;
float CONTENT_LAVA = -5;
float CONTENT_SKY = -6;
// state
float STATE_TOP = 0;
float STATE_BOTTOM = 1;
float STATE_UP = 2;
float STATE_DOWN = 3;
// hull sizes
vector VEC_ORIGIN = '0 0 0';
vector VEC_HULL_MIN = '-16 -16 -24';
vector VEC_HULL_MAX = '16 16 32';
vector VEC_HULL2_MIN = '-32 -32 -24';
vector VEC_HULL2_MAX = '32 32 64';
// protocol bytes
float SVC_BAD = 0;
float SVC_NOP = 1;
float SVC_DISCONNECT = 2;
float SVC_UPDATESTAT = 3;
float SVC_VERSION = 4;
float SVC_SETVIEW = 5;
float SVC_SOUND = 6;
float SVC_TIME = 7;
float SVC_PRINT = 8;
float SVC_STUFFTEXT = 9;
float SVC_SETANGLE = 10;
float SVC_SERVERINFO = 11;
float SVC_LIGHTSTYLE = 12;
float SVC_UPDATENAME = 13;
float SVC_UPDATEFRAGS = 14;
float SVC_CLIENTDATA = 15;
float SVC_STOPSOUND = 16;
float SVC_UPDATECOLORS = 17;
float SVC_PARTICLE = 18;
float SVC_DAMAGE = 19;
float SVC_SPAWNSTATIC = 20;
float SVC_SPAWNBINARY = 21;
float SVC_SPAWNBASELINE = 22;
float SVC_TEMPENTITY = 23;
float SVC_SETPAUSE = 24;
float SVC_SIGNONNUM = 25;
float SVC_CENTERPRINT = 26;
float SVC_KILLEDMONSTER = 27;
float SVC_FOUNDSECRET = 28;
float SVC_SPAWNSTATICSOUND= 29;
float SVC_INTERMISSION = 30;
float SVC_FINALE = 31;
float SVC_CDTRACK = 32;
float SVC_SELLSCREEN = 33;
float SVC_CUTSCENE = 34;
// stats
float STAT_HEALTH = 0;
float STAT_FRAGS = 1;
float STAT_WEAPON = 2;
float STAT_AMMO = 3;
float STAT_ARMOR = 4;
float STAT_WEAPONFRAME = 5;
float STAT_SHELLS = 6;
float STAT_NAILS = 7;
float STAT_ROCKETS = 8;
float STAT_CELLS = 9;
float STAT_ACTIVEWEAPON = 10;
float STAT_TOTALSECRETS = 11;
float STAT_TOTALMONSTERS = 12;
float STAT_SECRETS = 13;
float STAT_MONSTERS = 14;
// temp ents
float TE_SPIKE = 0;
float TE_SUPERSPIKE = 1;
float TE_GUNSHOT = 2;
float TE_EXPLOSION = 3;
float TE_TAREXPLOSION = 4;
float TE_LIGHTNING1 = 5;
float TE_LIGHTNING2 = 6;
float TE_WIZSPIKE = 7;
float TE_KNIGHTSPIKE = 8;
float TE_LIGHTNING3 = 9;
float TE_LAVASPLASH = 10;
float TE_TELEPORT = 11;
float TE_EXPLOSION2 = 12;
float TE_BEAM = 13;
// sound channels
float CHAN_AUTO = 0;
float CHAN_WEAPON = 1;
float CHAN_VOICE = 2;
float CHAN_ITEM = 3;
float CHAN_BODY = 4;
// sound attenuation
float ATTN_NONE = 0;
float ATTN_NORM = 1;
float ATTN_IDLE = 2;
float ATTN_STATIC = 3;
// update types
float UPDATE_GENERAL = 0;
float UPDATE_STATIC = 1;
float UPDATE_BINARY = 2;
float UPDATE_TEMP = 3;
// effects
float EF_BRIGHTFIELD = 1;
float EF_MUZZLEFLASH = 2;
float EF_BRIGHTLIGHT = 4;
float EF_DIMLIGHT = 8;
// messages
float MSG_BROADCAST = 0;
float MSG_ONE = 1;
float MSG_ALL = 2;
float MSG_INIT = 3;
// attack styles
float AS_STRAIGHT = 1;
float AS_SLIDING = 2;
float AS_MELEE = 3;
float AS_MISSILE = 4;
float AS_SPAM = 5;
// traceline flags
float MOVE_NORMAL = 0;
float MOVE_NOMONSTERS = 1;
float MOVE_MISSILE = 2;
// flags2
float FL2_ONLADDER = 1;
float FL2_PROJECTILE = 2;
/*==========
Globals
==========*/
string string_null;
entity newmis;
entity activator;
float framecount;
float skill;
entity lastspawn;
float developer;
float sv_gravity;
float gameover, intermission_running, intermission_exittime;
string nextmap;
/*==========
Fields
==========*/
// not used by gamecode, but used by map compiling utilities, so included to stop console warnings
__used .float light_lev;
__used .string wad;
// pain and death
.void(entity inflictor, entity attacker) th_die;
.void(entity attacker, float damage) th_pain;
// monster AI
.void() th_stand;
.void() th_walk;
.void() th_run;
.void() th_missile;
.void() th_melee;
.void() th_spam;
.float alpha;
.vector finaldest;
.float gravity;
.string killtarget;
.string map;
.float style;
.float style2;
.float switchshadstyle;
.void() think1;
.float worldtype;
.entity trigger_field;
.float cnt, colour, count, delay, distance, dmg, height, lip, pausetime, speed, state, volume, wait;
.float t_length, t_width;
.string mdl, mdl1, mdl2, mdl3, headmodel;
.string noise4;
.vector dest1, dest2;
.vector pos1, pos2;
.vector mangle, oldorigin;
.float attack_finished, pain_finished;
.float attack_state;
.entity movetarget, oldenemy;
.float lefty;
.float search_time;
.float show_hostile;
.float air_finished, fly_sound, health_rot_time, hurt_time, jump_flag, swim_flag, walkframe;
.string deathtype;
.float flags2;
// powerups
.float invincible_finished, invincible_time, invincible_sound;
.float invisible_finished, invisible_time, invisible_sound;
.float super_damage_finished, super_time, super_sound;
.float radsuit_finished, rad_time;
/*==========
Prototypes
==========*/
void() monster_death_use;
void() FoundTarget;
void(vector org, entity who) spawn_tdeath;
void(vector org) spawn_tfog;

View File

@@ -0,0 +1,795 @@
float DOOR_START_OPEN = 1;
float DOOR_DONT_LINK = 4;
float DOOR_GOLD_KEY = 8;
float DOOR_SILVER_KEY = 16;
float DOOR_TOGGLE = 32;
/*
Doors are similar to buttons, but can spawn a fat trigger field around them
to open without a touch, and they link together to form simultanious
double/quad doors.
Door.owner is the master door. If there is only one door, it points to itself.
If multiple doors, all will point to a single one.
Door.enemy chains from the master door through all doors linked in the chain.
*/
/*
=============================================================================
THINK FUNCTIONS
=============================================================================
*/
void() door_go_down;
void() door_go_up;
void() door_blocked =
{
Damage (other, self, self, self.dmg);
// if a door has a negative wait, it would never come back if blocked,
// so let it just squash the object to death real fast
if (self.wait >= 0)
{
if (self.state == STATE_DOWN)
door_go_up ();
else
door_go_down ();
}
};
void() door_hit_top =
{
sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
self.state = STATE_TOP;
if (self.spawnflags & DOOR_TOGGLE)
return; // don't come down automatically
self.think = door_go_down;
self.nextthink = self.ltime + self.wait;
};
void() door_hit_bottom =
{
sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
self.state = STATE_BOTTOM;
};
void() door_go_down =
{
sound (self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
if (self.max_health)
{
self.takedamage = DAMAGE_YES;
self.health = self.max_health;
}
self.state = STATE_DOWN;
SUB_CalcMove (self.pos1, self.speed, door_hit_bottom);
};
void() door_go_up =
{
if (self.state == STATE_UP)
return; // allready going up
if (self.state == STATE_TOP)
{ // reset top wait time
self.nextthink = self.ltime + self.wait;
return;
}
sound (self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
self.state = STATE_UP;
SUB_CalcMove (self.pos2, self.speed, door_hit_top);
UseTargets();
};
/*
=============================================================================
ACTIVATION FUNCTIONS
=============================================================================
*/
void() door_fire =
{
local entity oself;
local entity starte;
if (self.owner != self)
objerror ("door_fire: self.owner != self");
// play use key sound
if (self.items)
sound (self, CHAN_ITEM, self.noise4, 1, ATTN_NORM);
self.message = string_null; // no more message
oself = self;
if (self.spawnflags & DOOR_TOGGLE)
{
if (self.state == STATE_UP || self.state == STATE_TOP)
{
starte = self;
do
{
door_go_down ();
self = self.enemy;
} while ( (self != starte) && (self != world) );
self = oself;
return;
}
}
// trigger all paired doors
starte = self;
do
{
door_go_up ();
self = self.enemy;
} while ( (self != starte) && (self != world) );
self = oself;
};
void() door_use =
{
local entity oself;
self.message = ""; // door message are for touch only
self.owner.message = "";
self.enemy.message = "";
oself = self;
self = self.owner;
door_fire ();
self = oself;
};
void() door_trigger_touch =
{
if (other.health <= 0)
return;
if (time < self.attack_finished)
return;
self.attack_finished = time + 1;
activator = other;
self = self.owner;
door_use ();
};
void(entity inflictor, entity attacker) door_killed =
{
local entity oself;
oself = self;
self = self.owner;
self.health = self.max_health;
self.takedamage = DAMAGE_NO; // wil be reset upon return
door_use ();
self = oself;
};
/*
================
door_touch
Prints messages and opens key doors
================
*/
void() door_touch =
{
if (other.classname != "player")
return;
if (self.owner.attack_finished > time)
return;
self.owner.attack_finished = time + 2;
if (self.owner.message != "")
{
centerprint (other, self.owner.message);
sound (other, CHAN_VOICE, "misc/talk.wav", 1, ATTN_NORM);
}
// key door stuff
if (!self.items)
return;
// FIXME: blink key on player's status bar
if ( (self.items & other.items) != self.items )
{
if (self.owner.items == IT_KEY1)
{
if (world.worldtype == 2)
{
centerprint (other, "You need the silver keycard");
sound (self, CHAN_ITEM, self.noise3, 1, ATTN_NORM);
}
else if (world.worldtype == 1)
{
centerprint (other, "You need the silver runekey");
sound (self, CHAN_ITEM, self.noise3, 1, ATTN_NORM);
}
else if (world.worldtype == 0)
{
centerprint (other, "You need the silver key");
sound (self, CHAN_ITEM, self.noise3, 1, ATTN_NORM);
}
}
else
{
if (world.worldtype == 2)
{
centerprint (other, "You need the gold keycard");
sound (self, CHAN_ITEM, self.noise3, 1, ATTN_NORM);
}
else if (world.worldtype == 1)
{
centerprint (other, "You need the gold runekey");
sound (self, CHAN_ITEM, self.noise3, 1, ATTN_NORM);
}
else if (world.worldtype == 0)
{
centerprint (other, "You need the gold key");
sound (self, CHAN_ITEM, self.noise3, 1, ATTN_NORM);
}
}
return;
}
other.items = other.items - self.items;
self.touch = SUB_Null;
if (self.enemy)
self.enemy.touch = SUB_Null; // get paired door
door_use ();
};
/*
=============================================================================
SPAWNING FUNCTIONS
=============================================================================
*/
entity(vector fmins, vector fmaxs) spawn_field =
{
local entity trigger;
local vector t1, t2;
trigger = spawn();
trigger.movetype = MOVETYPE_NONE;
trigger.solid = SOLID_TRIGGER;
trigger.owner = self;
trigger.touch = door_trigger_touch;
t1 = fmins;
t2 = fmaxs;
setsize (trigger, t1 - '60 60 8', t2 + '60 60 8');
return (trigger);
};
float (entity e1, entity e2) EntitiesTouching =
{
if (e1.mins_x > e2.maxs_x)
return FALSE;
if (e1.mins_y > e2.maxs_y)
return FALSE;
if (e1.mins_z > e2.maxs_z)
return FALSE;
if (e1.maxs_x < e2.mins_x)
return FALSE;
if (e1.maxs_y < e2.mins_y)
return FALSE;
if (e1.maxs_z < e2.mins_z)
return FALSE;
return TRUE;
};
/*
=============
LinkDoors
=============
*/
void() LinkDoors =
{
local entity t, starte;
local vector cmins, cmaxs;
if (self.enemy)
return; // already linked by another door
if (self.spawnflags & 4)
{
self.owner = self.enemy = self;
return; // don't want to link this door
}
cmins = self.mins;
cmaxs = self.maxs;
starte = self;
t = self;
do
{
self.owner = starte; // master door
if (self.health)
starte.health = self.health;
if (self.targetname != "")
starte.targetname = self.targetname;
if (self.message != "")
starte.message = self.message;
t = find (t, classname, self.classname);
if (!t)
{
self.enemy = starte; // make the chain a loop
// shootable, fired, or key doors just needed the owner/enemy links,
// they don't spawn a field
self = self.owner;
if (self.health)
return;
if (self.targetname != "")
return;
if (self.items)
return;
self.owner.trigger_field = spawn_field(cmins, cmaxs);
return;
}
if (EntitiesTouching(self,t))
{
if (t.enemy)
objerror ("cross connected doors");
self.enemy = t;
self = t;
if (t.mins_x < cmins_x)
cmins_x = t.mins_x;
if (t.mins_y < cmins_y)
cmins_y = t.mins_y;
if (t.mins_z < cmins_z)
cmins_z = t.mins_z;
if (t.maxs_x > cmaxs_x)
cmaxs_x = t.maxs_x;
if (t.maxs_y > cmaxs_y)
cmaxs_y = t.maxs_y;
if (t.maxs_z > cmaxs_z)
cmaxs_z = t.maxs_z;
}
} while (1 );
};
/*QUAKED func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK GOLD_KEY SILVER_KEY TOGGLE
if two doors touch, they are assumed to be connected and operate as a unit.
TOGGLE causes the door to wait in both the start and end states for a trigger event.
START_OPEN causes the door to move to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not usefull for touch or takedamage doors).
Key doors are allways wait -1.
"message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet
"angle" determines the opening direction
"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
"health" if set, door must be shot open
"speed" movement speed (100 default)
"wait" wait before returning (3 default, -1 = never return)
"lip" lip remaining at end of move (8 default)
"dmg" damage to inflict when blocked (2 default)
"sounds"
0) no sound
1) stone
2) base
3) stone chain
4) screechy metal
*/
void() func_door =
{
if (world.worldtype == 0)
{
precache_sound ("doors/medtry.wav");
precache_sound ("doors/meduse.wav");
self.noise3 = "doors/medtry.wav";
self.noise4 = "doors/meduse.wav";
}
else if (world.worldtype == 1)
{
precache_sound ("doors/runetry.wav");
precache_sound ("doors/runeuse.wav");
self.noise3 = "doors/runetry.wav";
self.noise4 = "doors/runeuse.wav";
}
else if (world.worldtype == 2)
{
precache_sound ("doors/basetry.wav");
precache_sound ("doors/baseuse.wav");
self.noise3 = "doors/basetry.wav";
self.noise4 = "doors/baseuse.wav";
}
else
{
dprint ("no worldtype set!\n");
}
if (self.sounds == 0)
{
precache_sound ("misc/null.wav");
precache_sound ("misc/null.wav");
self.noise1 = "misc/null.wav";
self.noise2 = "misc/null.wav";
}
if (self.sounds == 1)
{
precache_sound ("doors/drclos4.wav");
precache_sound ("doors/doormv1.wav");
self.noise1 = "doors/drclos4.wav";
self.noise2 = "doors/doormv1.wav";
}
if (self.sounds == 2)
{
precache_sound ("doors/hydro1.wav");
precache_sound ("doors/hydro2.wav");
self.noise2 = "doors/hydro1.wav";
self.noise1 = "doors/hydro2.wav";
}
if (self.sounds == 3)
{
precache_sound ("doors/stndr1.wav");
precache_sound ("doors/stndr2.wav");
self.noise2 = "doors/stndr1.wav";
self.noise1 = "doors/stndr2.wav";
}
if (self.sounds == 4)
{
precache_sound ("doors/ddoor1.wav");
precache_sound ("doors/ddoor2.wav");
self.noise1 = "doors/ddoor2.wav";
self.noise2 = "doors/ddoor1.wav";
}
SetMovedir ();
self.max_health = self.health;
self.solid = SOLID_BSP;
self.movetype = MOVETYPE_PUSH;
setorigin (self, self.origin);
setmodel (self, self.model);
self.classname = "door";
self.blocked = door_blocked;
self.use = door_use;
if (self.spawnflags & DOOR_SILVER_KEY)
self.items = IT_KEY1;
if (self.spawnflags & DOOR_GOLD_KEY)
self.items = IT_KEY2;
if (!self.speed)
self.speed = 100;
if (!self.wait)
self.wait = 3;
if (!self.lip)
self.lip = 8;
if (!self.dmg)
self.dmg = 2;
self.colour = 192;
self.pos1 = self.origin;
self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip);
// DOOR_START_OPEN is to allow an entity to be lighted in the closed position
// but spawn in the open position
if (self.spawnflags & DOOR_START_OPEN)
{
setorigin (self, self.pos2);
self.pos2 = self.pos1;
self.pos1 = self.origin;
}
self.state = STATE_BOTTOM;
if (self.health)
{
self.takedamage = DAMAGE_YES;
self.th_die = door_killed;
}
if (self.items)
self.wait = -1;
self.touch = door_touch;
// LinkDoors can't be done until all of the doors have been spawned, so
// the sizes can be detected properly.
self.think = LinkDoors;
self.nextthink = self.ltime + 0.1;
};
/*
=============================================================================
SECRET DOORS
=============================================================================
*/
void() fd_secret_move1;
void() fd_secret_move2;
void() fd_secret_move3;
void() fd_secret_move4;
void() fd_secret_move5;
void() fd_secret_move6;
void() fd_secret_done;
float SECRET_OPEN_ONCE = 1; // stays open
float SECRET_1ST_LEFT = 2; // 1st move is left of arrow
float SECRET_1ST_DOWN = 4; // 1st move is down from arrow
float SECRET_NO_SHOOT = 8; // only opened by trigger
float SECRET_YES_SHOOT = 16; // shootable even if targeted
void () fd_secret_use =
{
local float temp;
self.health = 10000;
// exit if still moving around...
if (self.origin != self.oldorigin)
return;
self.message = string_null; // no more message
UseTargets(); // fire all targets / killtargets
if (!(self.spawnflags & SECRET_NO_SHOOT))
{
self.th_pain = SUB_PainNull;
self.takedamage = DAMAGE_NO;
}
self.velocity = '0 0 0';
// Make a sound, wait a little...
sound(self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
self.nextthink = self.ltime + 0.1;
temp = 1 - (self.spawnflags & SECRET_1ST_LEFT); // 1 or -1
makevectors(self.mangle);
if (!self.t_width)
{
if (self.spawnflags & SECRET_1ST_DOWN)
self. t_width = fabs(v_up * self.size);
else
self. t_width = fabs(v_right * self.size);
}
if (!self.t_length)
self. t_length = fabs(v_forward * self.size);
if (self.spawnflags & SECRET_1ST_DOWN)
self.dest1 = self.origin - v_up * self.t_width;
else
self.dest1 = self.origin + v_right * (self.t_width * temp);
self.dest2 = self.dest1 + v_forward * self.t_length;
SUB_CalcMove(self.dest1, self.speed, fd_secret_move1);
sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
};
void(entity attacker, float damage) fd_secret_pain =
{
fd_secret_use();
};
void(entity inflictor, entity attacker) fd_secret_die =
{
fd_secret_use();
};
// Wait after first movement...
void () fd_secret_move1 =
{
self.nextthink = self.ltime + 1.0;
self.think = fd_secret_move2;
sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
};
// Start moving sideways w/sound...
void () fd_secret_move2 =
{
sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
SUB_CalcMove(self.dest2, self.speed, fd_secret_move3);
};
// Wait here until time to go back...
void () fd_secret_move3 =
{
sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
if (!(self.spawnflags & SECRET_OPEN_ONCE))
{
self.nextthink = self.ltime + self.wait;
self.think = fd_secret_move4;
}
};
// Move backward...
void () fd_secret_move4 =
{
sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
SUB_CalcMove(self.dest1, self.speed, fd_secret_move5);
};
// Wait 1 second...
void () fd_secret_move5 =
{
self.nextthink = self.ltime + 1.0;
self.think = fd_secret_move6;
sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
};
void () fd_secret_move6 =
{
sound(self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
SUB_CalcMove(self.oldorigin, self.speed, fd_secret_done);
};
void () fd_secret_done =
{
if (!self.targetname || self.spawnflags&SECRET_YES_SHOOT)
{
self.health = 10000;
self.takedamage = DAMAGE_YES;
self.th_pain = fd_secret_pain;
}
sound(self, CHAN_VOICE, self.noise3, 1, ATTN_NORM);
};
void () secret_blocked =
{
if (time < self.attack_finished)
return;
self.attack_finished = time + 0.5;
Damage (other, self, self, self.dmg);
};
/*
================
secret_touch
Prints messages
================
*/
void() secret_touch =
{
if (other.classname != "player")
return;
if (self.attack_finished > time)
return;
self.attack_finished = time + 2;
if (self.message != "")
{
centerprint (other, self.message);
sound (other, CHAN_BODY, "misc/talk.wav", 1, ATTN_NORM);
}
};
/*QUAKED func_door_secret (0 .5 .8) ? open_once 1st_left 1st_down no_shoot always_shoot
Basic secret door. Slides back, then to the side. Angle determines direction.
wait = # of seconds before coming back
1st_left = 1st move is left of arrow
1st_down = 1st move is down from arrow
always_shoot = even if targeted, keep shootable
t_width = override WIDTH to move back (or height if going down)
t_length = override LENGTH to move sideways
"dmg" damage to inflict when blocked (2 default)
If a secret door has a targetname, it will only be opened by it's botton or trigger, not by damage.
"sounds"
1) medieval
2) metal
3) base
*/
void () func_door_secret =
{
if (self.sounds == 0)
self.sounds = 3;
if (self.sounds == 1)
{
precache_sound ("doors/latch2.wav");
precache_sound ("doors/winch2.wav");
precache_sound ("doors/drclos4.wav");
self.noise1 = "doors/latch2.wav";
self.noise2 = "doors/winch2.wav";
self.noise3 = "doors/drclos4.wav";
}
if (self.sounds == 2)
{
precache_sound ("doors/airdoor1.wav");
precache_sound ("doors/airdoor2.wav");
self.noise2 = "doors/airdoor1.wav";
self.noise1 = "doors/airdoor2.wav";
self.noise3 = "doors/airdoor2.wav";
}
if (self.sounds == 3)
{
precache_sound ("doors/basesec1.wav");
precache_sound ("doors/basesec2.wav");
self.noise2 = "doors/basesec1.wav";
self.noise1 = "doors/basesec2.wav";
self.noise3 = "doors/basesec2.wav";
}
if (!self.dmg)
self.dmg = 2;
self.colour = 192;
// Magic formula...
self.mangle = self.angles;
self.angles = '0 0 0';
self.solid = SOLID_BSP;
self.movetype = MOVETYPE_PUSH;
self.classname = "door";
setmodel (self, self.model);
setorigin (self, self.origin);
self.touch = secret_touch;
self.blocked = secret_blocked;
self.speed = 50;
self.use = fd_secret_use;
if ( !self.targetname || self.spawnflags&SECRET_YES_SHOOT)
{
self.health = 10000;
self.takedamage = DAMAGE_YES;
self.th_pain = fd_secret_pain;
self.th_die = fd_secret_die;
}
self.oldorigin = self.origin;
if (!self.wait)
self.wait = 5; // 5 seconds before closing
};

View File

@@ -0,0 +1,422 @@
/*
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.
*/
float(float v) anglemod;
void() knight_atk1;
void() knight_runatk1;
void() ogre_smash1;
void() ogre_swing1;
void() sham_smash1;
void() sham_swingr1;
void() sham_swingl1;
float() DemonCheckAttack;
void(float side) Demon_Melee;
void() ai_face;
float enemy_vis, enemy_infront, enemy_range;
float enemy_yaw;
entity sight_entity;
float sight_entity_time;
.vector enemy_last;
//=============================================================================
/*
===========
CheckAttack
The player is in view, so decide to move or launch an attack
Returns FALSE if movement should continue
============
*/
float() CheckAttack =
{
local vector spot1, spot2;
local entity targ;
local float chance;
targ = self.enemy;
// see if any entities are in the way of the shot
spot1 = self.origin + self.view_ofs;
spot2 = targ.origin + targ.view_ofs;
traceline (spot1, spot2, FALSE, self);
if (trace_ent != targ)
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 (!self.th_missile)
return FALSE;
if (time < self.attack_finished)
return FALSE;
if (enemy_range == RANGE_FAR)
return FALSE;
if (enemy_range == RANGE_MELEE)
{
chance = 0.9;
self.attack_finished = 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)
{
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();
};
void() ai_face_last =
{
self.ideal_yaw = vectoyaw(self.enemy_last - 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 =
{
ai_face ();
walkmove(self.angles_y, d);
};
void() ai_charge_side =
{
local vector dtemp;
local 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 =
{
local vector delta;
local float ldmg;
if (!self.enemy)
return; // removed before stroke
delta = self.enemy.origin - self.origin;
if (vlen(delta) > 60)
return;
ldmg = (random() + random() + random()) * 3;
Damage (self.enemy, self, self, ldmg);
};
void() ai_melee_side =
{
local vector delta;
local float ldmg;
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 = (random() + random() + random()) * 3;
Damage (self.enemy, self, self, ldmg);
};
//=============================================================================
/*
===========
SoldierCheckAttack
The player is in view, so decide to move or launch an attack
Returns FALSE if movement should continue
============
*/
float() SoldierCheckAttack =
{
local vector spot1, spot2;
local entity targ;
local float chance;
targ = self.enemy;
// see if any entities are in the way of the shot
spot1 = self.origin + self.view_ofs;
spot2 = targ.origin + targ.view_ofs;
traceline (spot1, spot2, FALSE, self);
if (trace_inopen && trace_inwater)
return FALSE; // sight line crossed contents
if (trace_ent != targ)
return FALSE; // don't have a clear shot
// missile attack
if (time < self.attack_finished)
return FALSE;
if (enemy_range == RANGE_FAR)
return FALSE;
if (enemy_range == RANGE_MELEE)
chance = 0.9;
else if (enemy_range == RANGE_NEAR)
chance = 0.4;
else if (enemy_range == RANGE_MID)
chance = 0.05;
else
chance = 0;
if (random () < chance)
{
self.attack_state = AS_MISSILE;
SUB_AttackFinished (1 + random());
return TRUE;
}
return FALSE;
};
//=============================================================================
/*
===========
ShamCheckAttack
The player is in view, so decide to move or launch an attack
Returns FALSE if movement should continue
============
*/
float() ShamCheckAttack =
{
local vector spot1, spot2;
local entity targ;
//local float enemy_yaw;
if (enemy_range == RANGE_MELEE)
{
if (CanDamage (self.enemy, self))
{
self.attack_state = AS_MELEE;
return TRUE;
}
}
if (time < self.attack_finished)
return FALSE;
if (!enemy_vis)
return FALSE;
targ = self.enemy;
// see if any entities are in the way of the shot
spot1 = self.origin + self.view_ofs;
spot2 = targ.origin + targ.view_ofs;
if (vlen(spot1 - spot2) > 600)
return FALSE;
traceline (spot1, spot2, FALSE, self);
if (trace_inopen && trace_inwater)
return FALSE; // sight line crossed contents
if (trace_ent != targ)
{
return FALSE; // don't have a clear shot
}
// missile attack
if (enemy_range == RANGE_FAR)
return FALSE;
self.attack_state = AS_MISSILE;
SUB_AttackFinished (2 + 2*random());
return TRUE;
};
//============================================================================
/*
===========
OgreCheckAttack
The player is in view, so decide to move or launch an attack
Returns FALSE if movement should continue
============
*/
float() OgreCheckAttack =
{
if (enemy_range == RANGE_MELEE)
{
if (CanDamage (self.enemy, self))
{
self.attack_state = AS_MELEE;
return TRUE;
}
}
if (time < self.attack_finished)
return FALSE;
// aim at last known location on hard and nightmare
if (!enemy_vis)
{
if (skill > 1)
{
if (time < self.search_time)
{
vector spot1 = self.origin;
vector spot2 = self.enemy_last;
traceline(spot1, spot2, MOVE_MISSILE, self);
if (trace_ent != world)
if (trace_ent.solid != SOLID_BSP)
return FALSE;
float chance = 0;
if (vlen(self.origin - self.enemy_last) < 500)
chance = 0.4;
else
chance = 0.1;
if (random() < chance)
{
self.attack_state = AS_SPAM;
SUB_AttackFinished (1 + 2*random());
return TRUE;
}
else
{
self.attack_finished = time + 0.5;
return FALSE;
}
}
}
return FALSE;
}
spot1 = self.origin;
spot2 = self.enemy.origin + self.enemy.view_ofs;
traceline (spot1, spot2, MOVE_MISSILE, self);
if (trace_inwater)
if (trace_inopen)
return FALSE;
if (trace_ent != self.enemy)
return FALSE;
// missile attack
chance = 0;
if (enemy_range == RANGE_NEAR)
chance = 0.5;
else if (enemy_range == RANGE_MID)
chance = 0.3;
if (random() < chance)
{
self.attack_state = AS_MISSILE;
SUB_AttackFinished (1 + 2*random());
return TRUE;
}
else
{
self.attack_finished = time + 0.5;
return FALSE;
}
};

View File

@@ -0,0 +1,240 @@
optimisation t default # c = a*b is performed in one operation rather than two, and can
# cause older decompilers to fail.
optimisation i default # if (!a) was traditionally compiled in two statements. This optimisation
# does it in one, but can cause some decompilers to get confused.
optimisation p default # In the original qcc, function parameters were specified as a vector
# store even for floats. This fixes that.
optimisation c default # This optimisation strips out the names of constants (but not strings)
# from your progs, resulting in smaller files. It makes decompilers
# leave out names or fabricate numerical ones.
optimisation cs default # This optimisation strips out the names of string constants from
# your progs. However, this can break addons, so don't use it in
# those cases.
optimisation d default # This will merge definitions of constants which are the same value.
# Pay extra attention to assignment to constant warnings.
optimisation s default # This will compact the string table that is stored in the progs.
# It will be considerably smaller with this.
optimisation l on # Strips out local names and definitions. Most decompiles will break
# on this.
optimisation n on # This strips out the names of functions which are never called.
# Doesn't make much of an impact though.
optimisation f on # This strips out the filenames of the progs. This can confuse the
# really old decompilers, but is nothing to the more recent ones.
optimisation u default # Removes the entries of unreferenced variables. Doesn't make a
# difference in well maintained code.
optimisation r default # Optimises the pr_globals count by overlapping temporaries. In
# QC, every multiplication, division or operation in general produces
# a temporary variable. This optimisation prevents excess, and in
# the case of Hexen2's gamecode, reduces the count by 50k. This
# is the most important optimisation, ever.
optimisation a default # 5*6 actually emits an operation into the progs. This prevents
# that happening, effectivly making the compiler see 30
optimisation pf default # Strip out stuff wasted used in function calls and strings to the
# precache_file builtin (which is actually a stub in quake).
optimisation ro default # Functions ending in a return statement do not need a done statement
# at the end of the function. This can confuse some decompilers,
# making functions appear larger than they were.
optimisation cj default # This optimisation plays an effect mostly with nested if/else statements,
# instead of jumping to an unconditional jump statement, it'll jump
# to the final destination instead. This will bewilder decompilers.
optimisation sf default # Strips out the 'defs' of functions that were only ever called
# directly. This does not affect saved games, but will prevent FTE_MULTIPROGS/mutators
# from being able to hook functions.
optimisation lo default # Store all locals in a single section of the pr_globals. Vastly
# reducing it. This effectivly does the job of overlaptemps.
# However, locals are no longer automatically initialised to 0 (and
# never were in the case of recursion, but at least then its the
# same type).
# If locals appear uninitialised, fteqcc will disable this optimisation
# for the affected functions, you can optionally get a warning about
# these locals using: #pragma warning enable F302
optimisation vc default # Where a function is called with just a vector, this causes the
# function call to store three floats instead of one vector. This
# can save a good number of pr_globals where those vectors contain
# many duplicate coordinates but do not match entirly.
optimisation cf default # Strip class field names. This will harm debugging and can result
# in 'gibberish' names appearing in saved games. Has no effect on
# engines other than FTEQW, which will not recognise these anyway.
optimisation uf default # Strips any fields that have no references. This may result in
# extra warnings at load time, or disabling support for mapper-specified
# alpha in engines that do not provide that. FIXME: this is a little
# pointless until relocs are properly implemented.
keyword asm true # Disables the 'asm' keyword. Use the writeasm flag to see an example
# of the asm.
keyword break true # Disables the 'break' keyword.
keyword case true # Disables the 'case' keyword.
keyword class true # Disables the 'class' keyword.
keyword const true # Disables the 'const' keyword.
keyword continue true # Disables the 'continue' keyword.
keyword default true # Disables the 'default' keyword.
keyword entity true # Disables the 'entity' keyword.
keyword enum true # Disables the 'enum' keyword.
keyword enumflags true # Disables the 'enumflags' keyword.
keyword extern true # Disables the 'extern' keyword. Use only on functions inside addons.
keyword float true # Disables the 'float' keyword. (Disables the float keyword without
# 'local' preceeding it)
keyword for true # Disables the 'for' keyword. Syntax: for(assignment; while; increment)
# {codeblock;}
keyword goto true # Disables the 'goto' keyword.
keyword int true # Disables the 'int' keyword.
keyword integer true # Disables the 'integer' keyword.
keyword noref true # Disables the 'noref' keyword.
keyword unused false # Disables the 'unused' keyword. 'unused' means that the variable
# is unused, you're aware that its unused, and you'd rather not
# know about all the warnings this results in.
keyword used false # Disables the 'used' keyword. 'used' means that the variable is
# used even if the qcc can't see how - thus preventing it from ever
# being stripped.
keyword static true # Disables the 'static' keyword. 'static' means that a variable
# has altered scope. On globals, the variable is visible only to
# the current .qc file. On locals, the variable's value does not
# change between calls to the function. On class variables, specifies
# that the field is a scoped global instead of a local. On class
# functions, specifies that 'this' is expected to be invalid and
# that the function will access any memembers via it.
keyword nonstatic true # Disables the 'nonstatic' keyword. 'nonstatic' acts upon globals+functions,
# reverting the defaultstatic pragma on a per-variable basis. For
# use by people who prefer to keep their APIs explicit.
keyword ignore false # Disables the 'ignore' keyword. 'ignore' is expected to typically
# be hidden behind a 'csqconly' define, and in such a context can
# be used to conditionally compile functions a little more gracefully.
# The opposite of the 'used' keyword. These variables/functions/members
# are ALWAYS stripped, and effectively ignored.
keyword nosave true # Disables the 'nosave' keyword.
keyword inline true # Disables the 'inline' keyword.
keyword strip true # Disables the 'strip' keyword.
keyword shared true # Disables the 'shared' keyword.
keyword state false # Disables the 'state' keyword.
keyword optional true # Disables the 'optional' keyword.
keyword inout false # Disables the 'inout' keyword.
keyword string true # Disables the 'string' keyword.
keyword struct true # Disables the 'struct' keyword.
keyword switch true # Disables the 'switch' keyword.
keyword thinktime false # Disables the 'thinktime' keyword which is used in HexenC
keyword until false # Disables the 'until' keyword which is used in HexenC
keyword loop false # Disables the 'loop' keyword which is used in HexenC
keyword typedef true # Disables the 'typedef' keyword.
keyword union true # Disables the 'union' keyword.
keyword var true # Disables the 'var' keyword.
keyword vector true # Disables the 'vector' keyword.
keyword wrap true # Disables the 'wrap' keyword.
keyword weak true # Disables the 'weak' keyword.
keyword accumulate false # Disables the 'accumulate' keyword.
flag acc false # Reacc is a pascall like compiler. It was released before the Quake
# source was released. This flag has a few effects. It sorts all
# qc files in the current directory into alphabetical order to compile
# them. It also allows Reacc global/field distinctions, as well
# as allows | for linebreaks. Whilst case insensitivity and lax
# type checking are supported by reacc, they are seperate compiler
# flags in fteqcc.
flag qccx false # WARNING: This syntax makes mods inherantly engine specific.
# Do NOT use unless you know what you're doing.This is provided
# for compatibility only
# Any entity hacks will be unsupported in FTEQW, DP, and others,
# resulting in engine crashes if the code in question is executed.
flag kce true # If you want keywords to NOT be disabled when they a variable by
# the same name is defined, check here.
flag parms false # if PARM0 PARM1 etc should be defined by the compiler. These are
# useful if you make use of the asm keyword for function calls,
# or you wish to create your own variable arguments. This is an
# easy way to break decompilers.
flag autoproto false # Causes compilation to take two passes instead of one. The first
# pass, only the definitions are read. The second pass actually
# compiles your code. This means you never have to remember to prototype
# functions again.
flag wasm false # Writes out a qc.asm which contains all your functions but in assembler.
# This is a great way to look for bugs in fteqcc, but can also be
# used to see exactly what your functions turn into, and thus how
# to optimise statements better.
flag annotate false # Annotate source code with assembler statements on compile (requires
# gui).
flag nullemptystr false # Empty string immediates will have the raw value 0 instead of 1.
flag ifstring false # Causes if(string) to behave identically to if(string!=) This is
# most useful with addons of course, but also has adverse effects
# with FRIK_FILE's fgets, where it becomes impossible to determin
# the end of the file. In such a case, you can still use asm {IF
# string 2;RETURN} to detect eof and leave the function.
flag iffloat false # Fixes certain floating point logic.
flag ifvector true # Fixes conditional vector logic.
flag vectorlogic true # Fixes conditional vector logic.
flag brokenarray false # Treat references to arrays as references to the first index of
# said array, to replicate an old fteqcc bug.
flag rootconstructor false # When enabled, the root constructor should be called first like
# in c++.
flag caseinsens false # Causes fteqcc to become case insensitive whilst compiling names.
# It's generally not advised to use this as it compiles a little
# more slowly and provides little benefit. However, it is required
# for full reacc support.
flag lax false # Disables many errors (generating warnings instead) when function
# calls or operations refer to two normally incompatible types.
# This is required for reacc support, and can also allow certain
# (evil) mods to compile that were originally written for frikqcc.
flag hashonly false # Allows use of only #constant for precompiler constants, allows
# certain preqcc using mods to compile
flag lo false # This changes the behaviour of your code. It generates additional
# if operations to early-out in if statements. With this flag, the
# line if (0 && somefunction()) will never call the function. It
# can thus be considered an optimisation. However, due to the change
# of behaviour, it is not considered so by fteqcc. Note that due
# to inprecisions with floats, this flag can cause runaway loop
# errors within the player walk and run functions (without iffloat
# also enabled). This code is advised:
# player_stand1:
# if (self.velocity_x || self.velocity_y)
# player_run
# if (!(self.velocity_x || self.velocity_y))
flag msvcstyle false # Generates warning and error messages in a format that msvc understands,
# to facilitate ide integration.
flag debugmacros false # Print out the contents of macros that are expanded. This can help
# look inside macros that are expanded and is especially handy if
# people are using preprocessor hacks.
flag filetimes false # Recompiles the progs only if the file times are modified.
flag fastarrays false # Generates extra instructions inside array handling functions to
# detect engine and use extension opcodes only in supporting engines.
# Adds a global which is set by the engine if the engine supports
# the extra opcodes. Note that this applies to all arrays or none.
flag assumeint false # Numerical constants are assumed to be integers, instead of floats.
flag subscope false # Restrict the scope of locals to the block they are actually defined
# within, as in C.
flag verbose false # Lots of extra compiler messages.
flag typeexplicit false # All type conversions must be explicit or directly supported by
# instruction set.
flag boundchecks true # Disable array index checks, speeding up array access but can result
# in your code misbehaving.
flag attributes false # WARNING: This syntax conflicts with vector constructors.
flag assumevar false # Initialised globals will be considered non-const by default.
flag ssp false # Treat ** as an operator for exponents, instead of multiplying
# by a dereferenced pointer.
flag cpriority false # QC treats !a&&b as equivelent to !(a&&b). When this is set, behaviour
# will be (!a)&&b as in C. Other operators are also affected in
# similar ways.
flag allowuninit false # Permit optimisations that may result in locals being uninitialised.
# This may allow for greater reductions in temps.
flag nofileline false # Ignores #pragma file(foo) and #pragma line(foo), so that errors
# and symbols reflect the actual lines, instead of the original
# source.
flag utf8 false # String immediates will use utf-8 encoding, instead of quake's
# encoding.
flag embedsrc false # Write the sourcecode into the output file. The resulting .dat
# can be opened as a standard zip archive (or by fteqccgui).
# Good for GPL compliance!
showall off # Show all keyword options in the gui
compileonstart off # Recompile on GUI startup
log off # Write out a compile log
enginebinary fteqw.exe # Location of the engine binary to run. Change this to something
# else to run a different engine, but not all support debugging.
basedir ../.. # The base directory of the game that contains your sub directory
engineargs "-window -game waypoint +developer 1 +map test"
# The engine commandline to use when debugging. You'll likely want
# to ensure this contains -window as well as the appropriate -game
# argument.
srcfile progs.src # The progs.src file to load to find ordering of other qc files.
src # Additional subdir to read qc files from. Typically blank (ie:
# the working directory).
tabsize 8 # Specifies the size of tabs in scintilla windows.
extramargins off # Enables line number and folding margins.
hexen2 off # Enable the extra tweaks needed for compatibility with hexen2 engines.
extendedopcodes off # Utilise an extended instruction set, providing support for pointers
# and faster arrays and other speedups.
parameters # Other additional parameters that are not supported by the gui.
# Likely including -DFOO

View File

@@ -0,0 +1,165 @@
/*==========
GibTouch
squelch, splat
==========*/
static void() GibTouch =
{
if (other != world)
return;
// don't sound more than once per gib
if (self.count)
return;
// don't always sound
if (random() < 0.5)
return;
self.count = 1;
float r = random();
if (r < 0.2)
sound (self, CHAN_VOICE, "zombie/z_miss.wav", 0.5, ATTN_IDLE);
else
sound (self, CHAN_VOICE, "player/tornoff2.wav", 0.5, ATTN_IDLE);
};
/*==========
GibVelocity
==========*/
static vector(float dm) GibVelocity =
{
vector v = [100 * crandom(), 100 * crandom(), 200 + 100 * random()];
if (dm > -50)
return v * 0.7;
else if (dm > -200)
return v * 2;
else
return v * 10;
};
/*==========
SpawnGib
==========*/
void(string gibname) SpawnGib =
{
entity gib = spawn();
gib.classname = "gib";
gib.owner = self;
gib.solid = SOLID_TRIGGER;
gib.movetype = MOVETYPE_BOUNCE;
setmodel (gib, gibname);
setsize (gib, '0 0 0', '0 0 0');
vector org = self.origin;
setorigin (gib, [org_x + crandom() * 0.5 * self.size_x, org_y + crandom() * 0.5 * self.size_y, org_z + crandom() * 0.5 * self.size_z]);
gib.velocity = GibVelocity(self.health);
gib.avelocity = randomvec() * 100;
gib.frame = randomrange(10);
gib.touch = GibTouch;
gib.think = SUB_Remove;
gib.nextthink = time + 10 + random() * 10;
};
/*==========
GibSound
==========*/
static void() GibSound =
{
float r = randomrange(4);
// player death sounds have no attenuation
float attn;
if (self.classname == "player")
attn = ATTN_NONE;
else
attn = ATTN_NORM;
if (r == 0)
sound (self, CHAN_VOICE, "player/udeath.wav", 1, attn);
else if (r == 1)
sound (self, CHAN_VOICE, "player/teledth1.wav", 1, attn);
else if (r == 2)
sound (self, CHAN_VOICE, "player/gib.wav", 1, attn);
else if (r == 4)
sound (self, CHAN_VOICE, "player/tornoff2.wav", 1, attn);
};
/*==========
BecomeGibs
==========*/
void() BecomeGibs =
{
GibSound();
self.think = SUB_Null;
self.nextthink = -1;
self.deadflag = DEAD_DEAD;
self.takedamage = DAMAGE_NO;
self.frame = 0;
self.flags = self.flags - (self.flags & FL_ONGROUND);
self.solid = SOLID_NOT;
self.movetype = MOVETYPE_BOUNCE;
setmodel (self, self.headmodel);
setsize (self, '-16 -16 0', '16 16 16');
setorigin(self, self.origin + self.view_ofs + '0 0 8');
self.view_ofs = '0 0 8';
self.velocity = GibVelocity(self.health);
self.avelocity = [0, crandom() * 600, 0];
};
/*==========
SpawnMeatSpray
==========*/
void(vector org, vector vel) SpawnMeatSpray =
{
entity gib = spawn();
gib.classname = "gib";
gib.owner = self;
gib.solid = SOLID_NOT;
gib.movetype = MOVETYPE_TOSS;
setmodel (gib, "progs/zom_gib.mdl");
setsize (gib, '0 0 0', '0 0 0');
setorigin (gib, org);
gib.velocity = vel;
gib.velocity_z = gib.velocity_z + 250 + 50 * random();
gib.avelocity = '3000 1000 2000';
gib.touch = SUB_Remove;
gib.think = SUB_Remove;
gib.nextthink = time + 1;
};
/*==========
SpawnBlood
==========*/
void(vector org, vector vel, float damage) SpawnBlood =
{
particle(org, vel, 66, damage);
particle(org, vel, 73, damage);
};
/*==========
SpawnTouchParticles
==========*/
void(float damage, float col) SpawnTouchParticles =
{
vector vel = normalize(self.velocity);
vector org = self.origin - 4 * vel;
makevectors(vel);
vel = v_right * crandom() + v_up * crandom();
vel = vel * random() * 4;
particle(org, vel, col, damage);
};
/*==========
SpawnTouchblood
==========*/
void(float damage) SpawnTouchblood =
{
SpawnTouchParticles(damage, 66);
SpawnTouchParticles(damage, 73);
};

View File

@@ -0,0 +1,77 @@
/*QUAKED info_null (.5 .5 .5) (-8 -8 -8) (8 8 8)
Used as a positional target for spotlights, etc.
*/
void() info_null =
{
remove(self);
};
/*==========
info_notnull
bad maphack, bad!
==========*/
void() info_notnull =
{
remove(self);
};
/*QUAKED info_intermission (1 0.5 0.5) (-8 -8 -8) (8 8 8)
This is the camera point for the intermission.
Use mangle instead of angle, so you can set pitch and roll as well as yaw.
*/
void() info_intermission = {};
/*QUAKED info_player_start (0 .5 0) (-16 -16 -24) (16 16 32)
{
model ({"path" : "progs/player.mdl", "frame" : 12});
}
The normal starting point for a level.
*/
void() info_player_start = {};
/*QUAKED info_player_start2 (0 .5 0) (-16 -16 -24) (16 16 32)
{
model ({"path" : "progs/player.mdl", "frame" : 12});
}
Used as the return point from an episode. Players will spawn here if they have any runes.
*/
void() info_player_start2 = {};
/*QUAKED info_player_test (0 .5 0) (-16 -16 -24) (16 16 32)
{
model ({"path" : "progs/player.mdl", "frame" : 12});
}
For debugging only. If developer mode is active, player will always spawn here.
*/
void() info_player_test = {};
/*QUAKED info_player_deathmatch (0 .5 0) (-16 -16 -24) (16 16 32)
{
model ({"path" : "progs/player.mdl", "frame" : 12});
}
Spawning position for deathmatch games.
*/
void() info_player_deathmatch = {};
/*QUAKED info_player_coop (0 .5 0) (-16 -16 -24) (16 16 32)
{
model ({"path" : "progs/player.mdl", "frame" : 12});
}
Spawning position for coop games.
*/
void() info_player_coop = {};
/*QUAKED info_teleport_destination (.5 .5 .5) (-16 -16 0) (16 16 56)
This is the destination marker for a teleporter.
It should have a "targetname" field with the same value as a trigger_teleport "target" field.
Set "angle" to the direction the player should face when arriving at the destination.
*/
void() info_teleport_destination =
{
if (!self.targetname)
{
objerror ("no targetname");
remove(self);
}
};

View File

@@ -0,0 +1,223 @@
/*==========
GotoNextMap
========*/
void() GotoNextMap =
{
if (cvar("samelevel") && (deathmatch || coop))
changelevel (mapname);
else
changelevel (nextmap);
};
/*==========
ExitIntermission
==========*/
void() ExitIntermission =
{
if (deathmatch)
{
GotoNextMap();
return;
}
intermission_exittime = time + 1;
intermission_running = intermission_running + 1;
//
// run some text if at the end of an episode
//
if (intermission_running == 2)
{
if (world.model == "maps/e1m7.bsp")
{
WriteByte (MSG_ALL, SVC_CDTRACK);
WriteByte (MSG_ALL, 2);
WriteByte (MSG_ALL, 3);
if (!cvar("registered"))
{
WriteByte (MSG_ALL, SVC_FINALE);
WriteString (MSG_ALL, "As the corpse of the monstrous entity\nChthon sinks back into the lava whence\nit rose, you grip the Rune of Earth\nMagic tightly. Now that you have\nconquered the Dimension of the Doomed,\nrealm of Earth Magic, you are ready to\ncomplete your task in the other three\nhaunted lands of Quake. Or are you? If\nyou don't register Quake, you'll never\nknow what awaits you in the Realm of\nBlack Magic, the Netherworld, and the\nElder World!");
}
else
{
WriteByte (MSG_ALL, SVC_FINALE);
WriteString (MSG_ALL, "As the corpse of the monstrous entity\nChthon sinks back into the lava whence\nit rose, you grip the Rune of Earth\nMagic tightly. Now that you have\nconquered the Dimension of the Doomed,\nrealm of Earth Magic, you are ready to\ncomplete your task. A Rune of magic\npower lies at the end of each haunted\nland of Quake. Go forth, seek the\ntotality of the four Runes!");
}
return;
}
else if (world.model == "maps/e2m6.bsp")
{
WriteByte (MSG_ALL, SVC_CDTRACK);
WriteByte (MSG_ALL, 2);
WriteByte (MSG_ALL, 3);
WriteByte (MSG_ALL, SVC_FINALE);
WriteString (MSG_ALL, "The Rune of Black Magic throbs evilly in\nyour hand and whispers dark thoughts\ninto your brain. You learn the inmost\nlore of the Hell-Mother; Shub-Niggurath!\nYou now know that she is behind all the\nterrible plotting which has led to so\nmuch death and horror. But she is not\ninviolate! Armed with this Rune, you\nrealize that once all four Runes are\ncombined, the gate to Shub-Niggurath's\nPit will open, and you can face the\nWitch-Goddess herself in her frightful\notherworld cathedral.");
return;
}
else if (world.model == "maps/e3m6.bsp")
{
WriteByte (MSG_ALL, SVC_CDTRACK);
WriteByte (MSG_ALL, 2);
WriteByte (MSG_ALL, 3);
WriteByte (MSG_ALL, SVC_FINALE);
WriteString (MSG_ALL, "The charred viscera of diabolic horrors\nbubble viscously as you seize the Rune\nof Hell Magic. Its heat scorches your\nhand, and its terrible secrets blight\nyour mind. Gathering the shreds of your\ncourage, you shake the devil's shackles\nfrom your soul, and become ever more\nhard and determined to destroy the\nhideous creatures whose mere existence\nthreatens the souls and psyches of all\nthe population of Earth.");
return;
}
else if (world.model == "maps/e4m7.bsp")
{
WriteByte (MSG_ALL, SVC_CDTRACK);
WriteByte (MSG_ALL, 2);
WriteByte (MSG_ALL, 3);
WriteByte (MSG_ALL, SVC_FINALE);
WriteString (MSG_ALL, "Despite the awful might of the Elder\nWorld, you have achieved the Rune of\nElder Magic, capstone of all types of\narcane wisdom. Beyond good and evil,\nbeyond life and death, the Rune\npulsates, heavy with import. Patient and\npotent, the Elder Being Shub-Niggurath\nweaves her dire plans to clear off all\nlife from the Earth, and bring her own\nfoul offspring to our world! For all the\ndwellers in these nightmare dimensions\nare her descendants! Once all Runes of\nmagic power are united, the energy\nbehind them will blast open the Gateway\nto Shub-Niggurath, and you can travel\nthere to foil the Hell-Mother's plots\nin person.");
return;
}
GotoNextMap();
}
if (intermission_running == 3)
{
if (!cvar("registered"))
{ // shareware episode has been completed, go to sell screen
WriteByte (MSG_ALL, SVC_SELLSCREEN);
return;
}
if ( (serverflags & 15) == 15)
{
WriteByte (MSG_ALL, SVC_FINALE);
WriteString (MSG_ALL, "Now, you have all four Runes. You sense\ntremendous invisible forces moving to\nunseal ancient barriers. Shub-Niggurath\nhad hoped to use the Runes Herself to\nclear off the Earth, but now instead,\nyou will use them to enter her home and\nconfront her as an avatar of avenging\nEarth-life. If you defeat her, you will\nbe remembered forever as the savior of\nthe planet. If she conquers, it will be\nas if you had never been born.");
return;
}
}
GotoNextMap();
};
/*==========
IntermissionChangeSpot
==========*/
static void() IntermissionChangeSpot =
{
if (!(self.flags & FL_JUMPRELEASED))
return;
self.flags = self.flags - FL_JUMPRELEASED;
// move to the next spot, if available
entity nextspot = self.enemy.enemy;
if (!nextspot)
return;
self.enemy = nextspot;
self.angles = self.v_angle = nextspot.mangle;
self.fixangle = TRUE;
setorigin (self, nextspot.origin);
};
/*==========
IntermissionThink
called by players from PlayerPreThink
==========*/
void() IntermissionThink =
{
if (self.button2)
IntermissionChangeSpot();
else
self.flags = self.flags | FL_JUMPRELEASED;
if (time < intermission_exittime || intermission_exittime == -1)
return;
if (!self.button0)
return;
ExitIntermission();
};
/*==========
FindIntermission
==========*/
static entity() FindIntermission =
{
// count the number of intermission spots in the map,
// and put them into a linked list
float count = 0;
entity first = world;
entity last = world;
entity spot = find(world, classname, "info_intermission");
while (spot)
{
if (!first)
first = spot;
if (last != world)
last.enemy = spot;
last = spot;
count = count + 1;
spot = find(spot, classname, "info_intermission");
}
// no intermission spots found in map, so try and use player start instead
if (!count)
{
spot = find (world, classname, "info_player_start");
if (spot)
return spot;
error("no intermission spot found");
}
last.enemy = first; // make it a loop
// pick a random spot
float pick = randomrange(count) + 1;
spot = world;
while (pick)
{
spot = find(spot, classname, "info_intermission");
pick = pick - 1;
}
return spot;
};
/*==========
StartIntermission
==========*/
void() StartIntermission =
{
intermission_running = 1;
if (deathmatch)
intermission_exittime = time + 5;
else
intermission_exittime = time + 2;
// change cd track
WriteByte (MSG_ALL, SVC_CDTRACK);
WriteByte (MSG_ALL, 3);
WriteByte (MSG_ALL, 3);
// find the intermission spot and move all players to it
entity pos = FindIntermission();
other = find (world, classname, "player");
while (other != world)
{
other.enemy = pos;
other.view_ofs = '0 0 0';
other.angles = other.v_angle = pos.mangle;
other.fixangle = TRUE;
other.think = SUB_Null;
other.nextthink = time + 0.1;
other.takedamage = DAMAGE_NO;
other.solid = SOLID_NOT;
other.movetype = MOVETYPE_NONE;
// we have to use a null sprite, because the
// server won't update players with no modelindex, and
// we now support intermission spot cycling
setmodel (other, "progs/s_null.spr");
setsize (other, '0 0 0', '0 0 0');
setorigin (other, pos.origin);
other = find (other, classname, "player");
}
// remove sbar and put up end of level stats
WriteByte (MSG_ALL, SVC_INTERMISSION);
};

View File

@@ -0,0 +1,223 @@
static enumflags { AMMO_BIG };
/*==========
ammo_touch
==========*/
static void() ammo_touch =
{
if (other.classname != "player")
return;
if (other.health <= 0)
return;
float count = 0;
if (self.items == IT_SHELLS)
{
if (other.ammo_shells >= 100)
return;
other.ammo_shells = other.ammo_shells + self.ammo_shells;
count = self.ammo_shells;
}
if (self.items == IT_NAILS)
{
if (other.ammo_nails >= 200)
return;
other.ammo_nails = other.ammo_nails + self.ammo_nails;
count = self.ammo_nails;
}
if (self.items == IT_ROCKETS)
{
if (other.ammo_rockets >= 100)
return;
other.ammo_rockets = other.ammo_rockets + self.ammo_rockets;
count = self.ammo_rockets;
}
if (self.items == IT_CELLS)
{
if (other.ammo_cells >= 100)
return;
other.ammo_cells = other.ammo_cells + self.ammo_cells;
count = self.ammo_cells;
}
W_BoundAmmo(other);
W_SetCurrentAmmo(other);
sound (other, CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM);
stuffcmd (other, "bf\n");
sprint (other, "You got ");
sprint (other, ftos(count));
sprint (other, " ");
sprint (other, self.netname);
sprint (other, "\n");
self.model = string_null;
self.solid = SOLID_NOT;
if (deathmatch)
{
self.think = ItemRespawn;
self.nextthink = time + 30;
}
// fire all targets
activator = other;
UseTargets();
};
/*QUAKED item_shells (0 0 1) (0 0 0) (32 32 56) AMMO_BIG X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ( {{ spawnflags & 1 -> { "path" : "maps/b_shell1.bsp" }, "maps/b_shell0.bsp" }} );
}
Nox of 20 shells.
AMMO_BIG is a box of 40 shells.
*/
void() item_shells =
{
self.touch = ammo_touch;
if (self.spawnflags & AMMO_BIG)
{
precache_model ("maps/b_shell1.bsp");
setmodel (self, "maps/b_shell1.bsp");
self.ammo_shells = 40;
}
else
{
precache_model ("maps/b_shell0.bsp");
setmodel (self, "maps/b_shell0.bsp");
self.ammo_shells = 20;
}
self.items = IT_SHELLS;
self.netname = "shells";
setsize (self, '0 0 0', '32 32 56');
StartItem ();
};
/*QUAKED item_spikes (0 0 1) (0 0 0) (32 32 56) AMMO_BIG X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ( {{ spawnflags & 1 -> { "path" : "maps/b_nail1.bsp" }, "maps/b_nail0.bsp" }} );
}
Nox of 25 nails.
AMMO_BIG is a box of 50 nails.
*/
void() item_spikes =
{
self.touch = ammo_touch;
if (self.spawnflags & AMMO_BIG)
{
precache_model ("maps/b_nail1.bsp");
setmodel (self, "maps/b_nail1.bsp");
self.ammo_nails = 50;
}
else
{
precache_model ("maps/b_nail0.bsp");
setmodel (self, "maps/b_nail0.bsp");
self.ammo_nails = 25;
}
self.items = IT_NAILS;
self.netname = "nails";
setsize (self, '0 0 0', '32 32 56');
StartItem ();
};
/*QUAKED item_rockets (0 0 1) (0 0 0) (32 32 56) AMMO_BIG X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ( {{ spawnflags & 1 -> { "path" : "maps/b_rock1.bsp" }, "maps/b_rock0.bsp" }} );
}
Nox of 5 rockets.
AMMO_BIG is a box of 10 rockets.
*/
void() item_rockets =
{
self.touch = ammo_touch;
if (self.spawnflags & AMMO_BIG)
{
precache_model ("maps/b_rock1.bsp");
setmodel (self, "maps/b_rock1.bsp");
self.ammo_rockets = 10;
}
else
{
precache_model ("maps/b_rock0.bsp");
setmodel (self, "maps/b_rock0.bsp");
self.ammo_rockets = 5;
}
self.items = IT_ROCKETS;
self.netname = "rockets";
setsize (self, '0 0 0', '32 32 56');
StartItem ();
};
/*QUAKED item_cells (0 0 1) (0 0 0) (32 32 56) AMMO_BIG X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ( {{ spawnflags & 1 -> { "path" : "maps/b_batt1.bsp" }, "maps/b_batt0.bsp" }} );
}
Nox of 6 cells.
AMMO_BIG is a box of 12 cells.
*/
void() item_cells =
{
self.touch = ammo_touch;
if (self.spawnflags & AMMO_BIG)
{
precache_model ("maps/b_batt1.bsp");
setmodel (self, "maps/b_batt1.bsp");
self.ammo_cells = 12;
}
else
{
precache_model ("maps/b_batt0.bsp");
setmodel (self, "maps/b_batt0.bsp");
self.ammo_cells = 6;
}
self.items = IT_CELLS;
self.netname = "cells";
setsize (self, '0 0 0', '32 32 56');
StartItem ();
};
/*==========
item_weapon
Stupid remnant that is deprecated but used in id1 on dm5, dm6,
e2m2 and e3m7. despite the name, it's an ammo box. the vanilla item
contains a couple of bugs, for example nails are called spikes and don't
match the ammo count of the normal item.
prints a warning and converts itself to the correct entity upon spawn.
==========*/
static enumflags { ITW_SHELLS, ITW_ROCKETS, ITW_NAILS, ITW_BIG };
void() item_weapon =
{
dprint("warning: item_weapon is deprecated!\n");
if (!(self.spawnflags & (ITW_SHELLS | ITW_ROCKETS | ITW_NAILS)))
{
objerror("invalid spawnflags");
remove(self);
return;
}
// convert into correct item
if (self.spawnflags & ITW_BIG)
self.spawnflags = self.spawnflags - ITW_BIG + AMMO_BIG;
if (self.spawnflags & ITW_SHELLS)
{
self.spawnflags = self.spawnflags - ITW_SHELLS;
self.classname = "item_shells";
item_shells();
}
else if (self.spawnflags & ITW_ROCKETS)
{
self.spawnflags = self.spawnflags - ITW_ROCKETS;
self.classname = "item_rockets";
item_rockets();
}
else if (self.spawnflags & ITW_NAILS)
{
self.spawnflags = self.spawnflags - ITW_NAILS;
self.classname = "item_spikes";
item_spikes();
}
};

View File

@@ -0,0 +1,96 @@
/*==========
armor_touch
==========*/
static void() armor_touch =
{
if (other.classname != "player")
return;
if (other.health <= 0)
return;
// player already has better armor
if (other.armortype*other.armorvalue >= self.armortype*self.armorvalue)
return;
sprint(other, "You got the ");
sprint(other, self.netname);
sprint(other, "\n");
sound(other, CHAN_ITEM, "items/armor1.wav", 1, ATTN_NORM);
stuffcmd (other, "bf\n");
other.armortype = self.armortype;
other.armorvalue = self.armorvalue;
other.items = other.items - (other.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3)) + self.items;
self.solid = SOLID_NOT;
self.model = string_null;
if (deathmatch || self.spawnflags & ITEM_RESPAWN)
{
self.think = ItemRespawn;
self.nextthink = time + self.teleport_time;
}
// fire targets
activator = other;
UseTargets();
};
/*==========
armor_start
==========*/
static void() armor_start =
{
SetPositiveDefault(teleport_time, 20);
self.touch = armor_touch;
precache_model ("progs/armor.mdl");
setmodel (self, "progs/armor.mdl");
setsize (self, '-16 -16 0', '16 16 56');
StartItem ();
};
/*QUAKED item_armor1 (0 0 1) (-16 -16 0) (16 16 56) X X X X DONT_DROP RESPAWN X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ({"path" : "progs/armor.mdl", "skin" : 0});
}
Green armor. 100 points, saves 30% of damage.
*/
void() item_armor1 =
{
self.items = IT_ARMOR1;
self.armortype = 0.3;
self.armorvalue = 100;
self.netname = "Green Armor";
armor_start();
};
/*QUAKED item_armor2 (0 0 1) (-16 -16 0) (16 16 56) X X X X DONT_DROP RESPAWN X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ({"path" : "progs/armor.mdl", "skin" : 1});
}
Yellow armor. 150 points, saves 60% of damage.
*/
void() item_armor2 =
{
self.skin = 1;
self.items = IT_ARMOR2;
self.armortype = 0.6;
self.armorvalue = 150;
self.netname = "Yellow Armor";
armor_start();
};
/*QUAKED item_armorInv (0 0 1) (-16 -16 0) (16 16 56) X X X X DONT_DROP RESPAWN X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ({"path" : "progs/armor.mdl", "skin" : 2});
}
Red armor. 200 points, saves 80% of damage.
*/
void() item_armorInv =
{
self.skin = 2;
self.items = IT_ARMOR3;
self.armortype = 0.8;
self.armorvalue = 200;
self.netname = "Red Armor";
armor_start();
};

View File

@@ -0,0 +1,218 @@
/*==========
backpack_touch
==========*/
void() backpack_touch =
{
if (other.classname != "player")
return;
if (other.health <= 0)
return;
other.ammo_shells = other.ammo_shells + self.ammo_shells;
other.ammo_nails = other.ammo_nails + self.ammo_nails;
other.ammo_rockets = other.ammo_rockets + self.ammo_rockets;
other.ammo_cells = other.ammo_cells + self.ammo_cells;
W_BoundAmmo(other);
W_SetCurrentAmmo(other);
sound (other, CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM);
stuffcmd (other, "bf\n");
// tell the player what's inside
float comma = FALSE;
sprint (other, "You get ");
if (self.items)
{
if (self.items & IT_AXE)
{
sprint(other, "the Axe");
comma = TRUE;
}
if (self.items & IT_SHOTGUN)
{
if (comma) sprint(other, ", ");
sprint(other, "the Shotgun");
comma = TRUE;
}
if (self.items & IT_SUPER_SHOTGUN)
{
if (comma) sprint(other, ", ");
sprint(other, "the Double-barrelled Shotgun");
comma = TRUE;
}
if (self.items & IT_NAILGUN)
{
if (comma) sprint(other, ", ");
sprint(other, "the Nailgun");
comma = TRUE;
}
if (self.items & IT_SUPER_NAILGUN)
{
if (comma) sprint(other, ", ");
sprint(other, "the Perforator");
comma = TRUE;
}
if (self.items & IT_GRENADE_LAUNCHER)
{
if (comma) sprint(other, ", ");
sprint(other, "the Grenade Launcher");
comma = TRUE;
}
if (self.items & IT_ROCKET_LAUNCHER)
{
if (comma) sprint(other, ", ");
sprint(other, "the Rocket Launcher");
comma = TRUE;
}
if (self.items & IT_LIGHTNING)
{
if (comma) sprint(other, ", ");
sprint(other, "the Thunderbolt");
comma = TRUE;
}
}
if (self.ammo_shells)
{
if (comma) sprint(other, ", ");
comma = TRUE;
sprint (other, ftos(self.ammo_shells));
sprint (other, " shells");
}
if (self.ammo_nails)
{
if (comma) sprint(other, ", ");
comma = TRUE;
sprint (other, ftos(self.ammo_nails));
sprint (other, " nails");
}
if (self.ammo_rockets)
{
if (comma) sprint(other, ", ");
comma = TRUE;
sprint (other, ftos(self.ammo_rockets));
sprint (other, " rockets");
}
if (self.ammo_cells)
{
if (comma) sprint(other, ", ");
comma = TRUE;
sprint (other, ftos(self.ammo_cells));
sprint (other, " cells");
}
sprint (other, "\n");
if (self.items)
{
if (other.items & self.items == 0)
{
other.items = other.items | self.items;
if (!other.weaponframe)
{
other.weapon = self.items;
W_UpdateWeapon(other);
}
}
}
self.solid = SOLID_NOT;
self.model = string_null;
// set up for respawn
if (self.classname == "item_backpack" && deathmatch) // map item, not dropped backpack
{
self.think = ItemRespawn;
self.nextthink = time + self.teleport_time;
}
else
{
self.think = SUB_Remove;
self.nextthink = time + 0.01;
}
// fire all targets
activator = other;
UseTargets();
};
/*==========
DropBackpack
called by players and monsters upon death
drops a backpack containing current weapon and ammo
==========*/
void() DropBackpack =
{
// nothing to drop
if (!(self.ammo_shells + self.ammo_nails + self.ammo_rockets + self.ammo_cells))
return;
entity backpack = spawn();
backpack.classname = "backpack";
backpack.items = self.weapon;
backpack.ammo_shells = self.ammo_shells;
backpack.ammo_nails = self.ammo_nails;
backpack.ammo_rockets = self.ammo_rockets;
backpack.ammo_cells = self.ammo_cells;
backpack.flags = FL_ITEM;
backpack.solid = SOLID_TRIGGER;
backpack.movetype = MOVETYPE_TOSS;
setmodel (backpack, "progs/backpack.mdl");
setsize (backpack, '-16 -16 0', '16 16 56');
setorigin (backpack, self.origin - '0 0 24');
backpack.touch = backpack_touch;
backpack.velocity = [crandom() * 100, crandom() * 100, 300];
backpack.nextthink = time + 120;
backpack.think = SUB_Remove;
};
/*QUAKED item_backpack (0 0 1) (-16 -16 0) (16 16 56) X X X X DONT_DROP RESPAWN X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{ model("progs/backpack.mdl"); }
Backpack pickup. Contains 40 shells, 50 nails, 10 rockets and 12 cells.
Keys:
items - set to one of a combination of the IT_SHOTGUN etc values to make the backpack contain weapons
ammo_shells, ammo_nails, ammo_rockets, ammo_cells - set to override ammo defaults. set to -1 to not give ANY ammo of that type.
teleport_time - time in seconds to respawn (default 120)
Spawnflags:
DONT_DROP - don't drop to floor on map load
RESPAWN - respawn automatically
*/
void() item_backpack =
{
precache_model ("progs/backpack.mdl");
precache_sound ("weapons/lock4.wav");
setmodel (self, "progs/backpack.mdl");
setsize (self, '-16 -16 0', '16 16 56');
self.touch = backpack_touch;
SetPositiveDefault(teleport_time, 120);
// remove anything that isn't a weapon
self.items = self.items & (IT_AXE | IT_SHOTGUN | IT_SUPER_SHOTGUN | IT_NAILGUN | IT_SUPER_NAILGUN |
IT_GRENADE_LAUNCHER | IT_ROCKET_LAUNCHER | IT_LIGHTNING);
if (!self.ammo_shells)
self.ammo_shells = 40;
if (self.ammo_shells < 0)
self.ammo_shells = 0;
if (!self.ammo_nails)
self.ammo_nails = 50;
if (self.ammo_nails < 0)
self.ammo_nails = 0;
if (!self.ammo_rockets)
self.ammo_rockets = 10;
if (self.ammo_rockets < 0)
self.ammo_rockets = 0;
if (!self.ammo_cells)
self.ammo_cells = 12;
if (self.ammo_cells < 0)
self.ammo_cells = 0;
StartItem();
};

View File

@@ -0,0 +1,92 @@
enumflags { H_ROTTEN, H_MEGA };
/*==========
health_touch
==========*/
void() health_touch =
{
if (other.classname != "player")
return;
if (other.health <= 0)
return;
// already at max health?
if (other.health >= other.max_health)
if (self.health < 100)
return;
// absolute max health
if (other.health >= 250)
return;
// give health and cap it
other.health = other.health + self.health;
if (other.health > other.max_health)
if (self.health < 100)
other.health = other.max_health;
if (other.health > 250)
other.health = 250;
sprint(other, "You receive ");
sprint(other, ftos(self.health));
sprint(other, " health\n");
sound(other, CHAN_ITEM, self.noise, 1, ATTN_NORM);
stuffcmd (other, "bf\n");
if (self.health == 100)
{
other.items = other.items | IT_SUPERHEALTH;
other.health_rot_time = time + 5;
}
self.model = string_null;
self.solid = SOLID_NOT;
if (deathmatch)
{
self.think = ItemRespawn;
self.nextthink = time + 20;
}
// fire targets
activator = other;
UseTargets();
};
/*QUAKED item_health (0 0 1) (0 0 0) (32 32 56) Rotten Megahealth X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ( {{ spawnflags & 1 -> { "path" : "maps/b_bh10.bsp" }, spawnflags & 2 -> { "path" : "maps/b_bh100.bsp" },
"maps/b_bh25.bsp" }} );
}
Health box. Normally gives 25 points.
Rotten box heals 15 points.
Megahealth will add 100 health, then start to
rot the player back down to 100 health after 5 seconds.
*/
void() item_health =
{
if (self.spawnflags & H_ROTTEN)
{
precache_model("maps/b_bh10.bsp");
setmodel(self, "maps/b_bh10.bsp");
self.noise = "items/r_item1.wav";
self.health = 15;
}
else if (self.spawnflags & H_MEGA)
{
precache_model("maps/b_bh100.bsp");
setmodel(self, "maps/b_bh100.bsp");
self.noise = "items/r_item2.wav";
self.health = 100;
}
else
{
precache_model("maps/b_bh25.bsp");
setmodel(self, "maps/b_bh25.bsp");
self.noise = "items/health1.wav";
self.health = 25;
}
precache_sound(self.noise);
self.touch = health_touch;
setsize (self, '0 0 0', '32 32 56');
StartItem ();
};

View File

@@ -0,0 +1,201 @@
/*========================================
it_keys.qc
========================================*/
/*==========
key_touch
==========*/
void() key_touch =
{
if (other.classname != "player")
return;
if (other.health <= 0)
return;
if (other.items & self.items)
return;
sprint (other, "You got the ");
sprint (other, self.netname);
sprint (other,"\n");
sound (other, CHAN_ITEM, self.noise, 1, ATTN_NORM);
stuffcmd (other, "bf\n");
other.items = other.items | self.items;
self.solid = SOLID_NOT;
self.model = string_null;
// fire targets
activator = other;
UseTargets();
};
/*==========
key_setmodel
==========*/
void() key_setmodel =
{
if (world.worldtype == 0)
{
precache_model ("progs/key_med.mdl");
setmodel (self, "progs/key_med.mdl");
}
else if (world.worldtype == 1)
{
precache_model ("progs/key_rune.mdl");
setmodel (self, "progs/key_rune.mdl");
}
else if (world.worldtype == 2)
{
precache_model2 ("progs/key_base.mdl");
setmodel (self, "progs/key_base.mdl");
}
};
/*==========
key_setsounds
==========*/
void() key_setsounds =
{
if (world.worldtype == 0)
self.noise = "misc/medkey.wav";
if (world.worldtype == 1)
self.noise = "misc/runekey.wav";
if (world.worldtype == 2)
self.noise = "misc/basekey.wav";
precache_sound(self.noise);
};
/*QUAKED item_key1 (0 0 1) (-16 -16 -24) (16 16 32) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{ model("progs/key_med.mdl"); }
SILVER key
In order for keys to work
you MUST set your maps
worldtype to one of the
following:
0: medieval
1: metal
2: base
*/
void() item_key1 =
{
if (world.worldtype == 0)
self.netname = "silver key";
else if (world.worldtype == 1)
self.netname = "silver runekey";
else if (world.worldtype == 2)
self.netname = "silver keycard";
key_setmodel();
key_setsounds();
self.touch = key_touch;
self.items = IT_KEY1;
setsize (self, '-16 -16 -24', '16 16 32');
StartItem ();
};
/*QUAKED item_key2 (0 0 1) (-16 -16 -24) (16 16 32) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ({"path" : "progs/key_med.mdl", "skin" : 1});
}
GOLD key
In order for keys to work
you MUST set your maps
worldtype to one of the
following:
0: medieval
1: metal
2: base
*/
void() item_key2 =
{
if (world.worldtype == 0)
self.netname = "gold key";
else if (world.worldtype == 1)
self.netname = "gold runekey";
else if (world.worldtype == 2)
self.netname = "gold keycard";
key_setmodel();
key_setsounds();
self.skin = 1;
self.touch = key_touch;
self.items = IT_KEY2;
setsize (self, '-16 -16 -24', '16 16 32');
StartItem ();
};
/*==========
sigil_touch
==========*/
void() sigil_touch =
{
if (other.classname != "player")
return;
if (other.health <= 0)
return;
serverflags = serverflags | (self.spawnflags & 15);
centerprint (other, "You got the Rune of ", self.netname, " Magic!");
sound (other, CHAN_ITEM, self.noise, 1, ATTN_NORM);
stuffcmd (other, "bf\n");
self.solid = SOLID_NOT;
self.model = string_null;
// fire targets
activator = other;
UseTargets();
};
/*QUAKED item_sigil (0 0 1) (-16 -16 -24) (16 16 32) E1 E2 E3 E4 X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ( {{ spawnflags & 1 -> { "path" : "progs/end1.mdl" }, spawnflags & 2 -> { "path" : "progs/end2.mdl" },
spawnflags & 4 -> { "path" : "progs/end3.mdl" }, spawnflags & 8 -> { "path" : "progs/end4.mdl" },
"progs/end1.mdl" }} );
}
End of episode rune. Use in conjuction with func_bossgate and func_episodegate.
Spawnflag must be set to the appropriate episode.
Episode 1 - Dimension of the Doomed - Rune of Earth Magic
Episode 2 - The Realm of Black Magic - Rune of Black Magic
Episode 3 - The Netherworld - Rune of Hell Magic
Episode 4 - The Elder World - Run of Elder Magic
*/
void() item_sigil =
{
self.noise = "misc/runekey.wav";
precache_sound(self.noise);
if (self.spawnflags & 1)
{
self.netname = "Earth";
precache_model ("progs/end1.mdl");
setmodel (self, "progs/end1.mdl");
}
else if (self.spawnflags & 2)
{
self.netname = "Black";
precache_model2 ("progs/end2.mdl");
setmodel (self, "progs/end2.mdl");
}
else if (self.spawnflags & 4)
{
self.netname = "Hell";
precache_model2 ("progs/end3.mdl");
setmodel (self, "progs/end3.mdl");
}
else if (self.spawnflags & 8)
{
self.netname = "Elder";
precache_model2 ("progs/end4.mdl");
setmodel (self, "progs/end4.mdl");
}
else
{
objerror("invalid spawnflags\n");
remove(self);
return;
}
self.touch = sigil_touch;
setsize (self, '-16 -16 -24', '16 16 32');
StartItem ();
};

View File

@@ -0,0 +1,109 @@
/*==========
powerup_touch
==========*/
void() powerup_touch =
{
if (other.classname != "player")
return;
if (other.health <= 0)
return;
sprint (other, "You got the ");
sprint (other, self.netname);
sprint (other,"\n");
sound (other, CHAN_VOICE, self.noise, 1, ATTN_NORM);
stuffcmd (other, "bf\n");
self.model = string_null;
self.solid = SOLID_NOT;
other.items = other.items | self.items;
if (self.classname == "item_artifact_envirosuit")
{
other.rad_time = 1;
other.radsuit_finished = time + 30;
}
if (self.classname == "item_artifact_invulnerability")
{
other.invincible_time = 1;
other.invincible_finished = time + 30;
}
if (self.classname == "item_artifact_invisibility")
{
other.invisible_time = 1;
other.invisible_finished = time + 30;
}
if (self.classname == "item_artifact_super_damage")
{
other.super_time = 1;
other.super_damage_finished = time + 30;
}
if (deathmatch || self.spawnflags & ITEM_RESPAWN)
{
self.think = ItemRespawn;
self.nextthink = time + self.teleport_time;
}
// fire targets
activator = other;
UseTargets();
};
/*===========
powerup_start
==========*/
static void(string mod, string snd, string name, float it, float respawn) powerup_start =
{
precache_model (mod);
setmodel (self, mod);
precache_sound (snd);
self.noise = snd;
SetPositiveDefault(teleport_time, respawn);
self.netname = name;
self.items = it;
setsize (self, '-16 -16 -24', '16 16 32');
self.touch = powerup_touch;
StartItem();
};
/*QUAKED item_artifact_invulnerability (0 0 1) (-16 -16 -24) (16 16 32) X X X X DONT_DROP RESPAWN X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{ model("progs/invulner.mdl"); }
Pentagram of Protection
Player is invulnerable for 30 seconds
*/
void() item_artifact_invulnerability =
{
powerup_start("progs/invulner.mdl", "items/protect.wav", "Pentagram of Protection", IT_INVULNERABILITY, 300);
};
/*QUAKED item_artifact_envirosuit (0 0 1) (-16 -16 -24) (16 16 32) X X X X DONT_DROP RESPAWN X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{ model("progs/suit.mdl"); }
Biosuit
Player takes no damage from water or slime for 30 seconds
*/
void() item_artifact_envirosuit =
{
powerup_start("progs/suit.mdl", "items/suit.wav", "Biosuit", IT_SUIT, 60);
};
/*QUAKED item_artifact_invisibility (0 0 1) (-16 -16 -24) (16 16 32) X X X X DONT_DROP RESPAWN X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{ model("progs/invisibl.mdl"); }
Ring of Shadows
Player is invisible for 30 seconds
*/
void() item_artifact_invisibility =
{
powerup_start("progs/invisibl.mdl", "items/inv1.wav", "Ring of Shadows", IT_INVISIBILITY, 300);
};
/*QUAKED item_artifact_super_damage (0 0 1) (-16 -16 -24) (16 16 32) X X X X DONT_DROP RESPAWN X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{ model("progs/quaddama.mdl"); }
Quad Damage
Player does 4x damage for 30 seconds
*/
void() item_artifact_super_damage =
{
powerup_start("progs/quaddama.mdl", "items/damage.wav", "Quad Damage", IT_QUAD, 60);
};

View File

@@ -0,0 +1,153 @@
/*==========
weapon_touch
==========*/
static void() weapon_touch =
{
if (other.classname != "player")
return;
if (other.health <= 0)
return;
if (coop && (other.items & self.weapon))
{
// fire targets in coop even if all players already have the weapon
if (!self.count)
{
activator = other;
UseTargets();
}
self.count = 1;
return;
}
other.ammo_shells = other.ammo_shells + self.ammo_shells;
other.ammo_nails = other.ammo_nails + self.ammo_nails;
other.ammo_rockets = other.ammo_rockets + self.ammo_rockets;
other.ammo_cells = other.ammo_cells + self.ammo_cells;
W_BoundAmmo(other);
W_SetCurrentAmmo(other);
sprint (other, "You got the ");
sprint (other, self.netname);
sprint (other, "\n");
sound (other, CHAN_ITEM, "weapons/pkup.wav", 1, ATTN_NORM);
stuffcmd (other, "bf\n");
self.model = string_null;
self.solid = SOLID_NOT;
if (deathmatch)
{
self.think = ItemRespawn;
self.nextthink = time + 30;
}
if (!(other.items & self.weapon))
{
other.items = other.items | self.weapon;
if (!other.weaponframe)
{
other.weapon = self.weapon;
W_UpdateWeapon(other);
}
}
// fire targets
activator = other;
UseTargets();
};
/*QUAKED weapon_supershotgun (0 0 1) (-16 -16 0) (16 16 56) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{ model("progs/g_shot.mdl"); }
Double-barrelled Shotgun
*/
void() weapon_supershotgun =
{
precache_model ("progs/g_shot.mdl");
setmodel (self, "progs/g_shot.mdl");
self.weapon = IT_SUPER_SHOTGUN;
self.netname = "Double-barrelled Shotgun";
self.ammo_shells = 5;
self.touch = weapon_touch;
setsize (self, '-16 -16 0', '16 16 56');
StartItem ();
};
/*QUAKED weapon_nailgun (0 0 1) (-16 -16 0) (16 16 56) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{ model("progs/g_nail.mdl"); }
Nailgun
*/
void() weapon_nailgun =
{
precache_model ("progs/g_nail.mdl");
setmodel (self, "progs/g_nail.mdl");
self.weapon = IT_NAILGUN;
self.netname = "nailgun";
self.ammo_nails = 30;
self.touch = weapon_touch;
setsize (self, '-16 -16 0', '16 16 56');
StartItem ();
};
/*QUAKED weapon_supernailgun (0 0 1) (-16 -16 0) (16 16 56) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{ model("progs/g_nail2.mdl"); }
Perforator
*/
void() weapon_supernailgun =
{
precache_model ("progs/g_nail2.mdl");
setmodel (self, "progs/g_nail2.mdl");
self.weapon = IT_SUPER_NAILGUN;
self.netname = "Super Nailgun";
self.ammo_nails = 30;
self.touch = weapon_touch;
setsize (self, '-16 -16 0', '16 16 56');
StartItem ();
};
/*QUAKED weapon_grenadelauncher (0 0 1) (-16 -16 0) (16 16 56) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{ model("progs/g_rock.mdl"); }
Grenade Launcher
*/
void() weapon_grenadelauncher =
{
precache_model ("progs/g_rock.mdl");
setmodel (self, "progs/g_rock.mdl");
self.weapon = IT_GRENADE_LAUNCHER;
self.netname = "Grenade Launcher";
self.ammo_rockets = 5;
self.touch = weapon_touch;
setsize (self, '-16 -16 0', '16 16 56');
StartItem ();
};
/*QUAKED weapon_rocketlauncher (0 0 1) (-16 -16 0) (16 16 56) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{ model("progs/g_rock2.mdl"); }
Rocket Launcher
*/
void() weapon_rocketlauncher =
{
precache_model ("progs/g_rock2.mdl");
setmodel (self, "progs/g_rock2.mdl");
self.weapon = IT_ROCKET_LAUNCHER;
self.netname = "Rocket Launcher";
self.ammo_rockets = 5;
self.touch = weapon_touch;
setsize (self, '-16 -16 0', '16 16 56');
StartItem ();
};
/*QUAKED weapon_lightning (0 0 1) (-16 -16 0) (16 16 56) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{ model("progs/g_light.mdl"); }
Thunderbolt
*/
void() weapon_lightning =
{
precache_model ("progs/g_light.mdl");
setmodel (self, "progs/g_light.mdl");
self.weapon = IT_LIGHTNING;
self.netname = "Thunderbolt";
self.ammo_cells = 15;
self.touch = weapon_touch;
setsize (self, '-16 -16 0', '16 16 56');
StartItem();
};

View File

@@ -0,0 +1,59 @@
enumflags { ITEM_DONT_DROP=16, ITEM_RESPAWN };
/*==========
ItemRespawn
==========*/
void() ItemRespawn =
{
sound (self, CHAN_VOICE, "items/itembk2.wav", 1, ATTN_NORM);
self.model = self.mdl;
self.solid = SOLID_TRIGGER;
setorigin (self, self.origin); // link back into world
};
/*==========
PlaceItem
==========*/
void() PlaceItem =
{
self.mdl = self.model;
self.flags = FL_ITEM;
self.solid = SOLID_TRIGGER;
if (self.spawnflags & ITEM_DONT_DROP)
{
self.movetype = MOVETYPE_NONE;
setorigin(self, self.origin);
}
else
{
self.movetype = MOVETYPE_TOSS;
setorigin(self, self.origin + '0 0 6');
if (!droptofloor())
{
dprint(self.classname);
dprint (" fell out of level at ");
dprint (vtos(self.origin));
dprint ("\n");
remove(self);
}
}
};
/*==========
StartItem
==========*/
void() StartItem =
{
if (self.spawnflags & (ITEM_DONT_DROP | ITEM_RESPAWN))
{
dprint("potential ");
dprint(self.classname);
dprint(" with erroneous spawnflag at ");
dprint(vtos(self.origin));
dprint("\n");
}
self.think = PlaceItem;
self.nextthink = time + 0.2;
};

View File

@@ -0,0 +1,373 @@
/*========================================
lights.qc
========================================*/
static enumflags { LIGHT_START_OFF, LIGHT_FADE, LIGHT_NO_SOUND };
#define FADE_RAMP 13
static string abc[FADE_RAMP] = { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m" };
#define NUM_LIGHTSTYLES 13
static string lightstyles[NUM_LIGHTSTYLES] =
{
// 0 NORMAL
"m",
// 1 FLICKER (first variety)
"mmnmmommommnonmmonqnmmo",
// 2 SLOW STRONG PULSE
"abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba",
// 3 CANDLE (first variety)
"mmmmmaaaaammmmmaaaaaabcdefgabcdefg",
// 4 FAST STROBE
"mamamamamama",
// 5 GENTLE PULSE 1
"jklmnopqrstuvwxyzyxwvutsrqponmlkj",
// 6 FLICKER (second variety)
"nmonqnmomnmomomno",
// 7 CANDLE (second variety)
"mmmaaaabcdefgmmmmaaaammmaamm",
// 8 CANDLE (third variety)
"mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa",
// 9 SLOW STROBE (fourth variety)
"aaaaaaaazzzzzzzz",
// 10 FLUORESCENT FLICKER
"mmamammmmammamamaaamammma",
// 11 SLOW PULSE NOT FADE TO BLACK
"abcdefghijklmnopqrrqponmlkjihgfedcba",
// 12 BLINK OFF / ON (can be combined with animated textures, e.g. +0light, +1light, +alight)
"aamm"
};
/*==========
lightstyle_lookup
look up a style by it's number and return the correct animation string
==========*/
static string(float num) lightstyle_lookup =
{
if (num > NUM_LIGHTSTYLES - 1)
num = NUM_LIGHTSTYLES - 1;
if (num < 0)
num = 0;
return lightstyles[num];
};
/*==========
lightstyle_fade_lookup
==========*/
static string(float num) lightstyle_fade_lookup =
{
if (num > FADE_RAMP - 1)
num = FADE_RAMP - 1;
if (num < 0)
num = 0;
return abc[num];
};
/*==========
setup_lightstyles
Setup light animation tables. 'a' is total darkness, 'z' is maxbright.
Styles 32+ are assigned by the light compiler for switchable lights.
==========*/
void() setup_lightstyles =
{
for (float i = 0; i < NUM_LIGHTSTYLES - 1; i++)
{
lightstyle(i, lightstyle_lookup(i));
}
};
/*==========
light_fade_in
==========*/
static void() light_fade_in =
{
lightstyle(self.style, lightstyle_fade_lookup(self.count));
self.count = self.count + 1;
if (self.count > FADE_RAMP - 1)
{
self.count = FADE_RAMP - 1;
return;
}
self.think = light_fade_in;
self.nextthink = time + self.speed;
};
/*==========
light_fade_out
==========*/
static void() light_fade_out =
{
lightstyle(self.style, lightstyle_fade_lookup(self.count));
self.count = self.count - 1;
if (self.count < 0)
{
self.count = 0;
return;
}
self.think = light_fade_out;
self.nextthink = time + self.speed;
};
/*==========
light_use
using a light will turn it on and off
==========*/
static void() light_use =
{
if (self.spawnflags & LIGHT_START_OFF)
{
if (self.mdl != "")
setmodel(self, self.mdl);
if (self.noise1 != "")
sound(self, CHAN_VOICE, self.noise2, 0.5, ATTN_IDLE);
self.spawnflags = self.spawnflags - LIGHT_START_OFF;
if (self.spawnflags & LIGHT_FADE && !self.style2)
light_fade_in();
else
lightstyle(self.style, lightstyle_lookup(self.style2));
}
else
{
if (self.mdl != "")
self.modelindex = 0;
if (self.noise1 != "")
sound(self, CHAN_VOICE, self.noise1, 0.5, ATTN_IDLE);
self.spawnflags = self.spawnflags + LIGHT_START_OFF;
if (self.spawnflags & LIGHT_FADE && !self.style2)
light_fade_out();
else
lightstyle(self.style, "a");
}
};
/*QUAKED light (1 1 0) (-8 -8 -8) (8 8 8) START_OFF FADE NO_SOUND
Non-displayed light
Please see your compiling utility documentation for full details,
this entry only describes things controlled by the QuakeC.
==========
Keys
==========
"targetname" "name"
Turns the light into a switchable light. You must target it to toggle it.
"speed" "n"
If the light is switchable and FADE_IN_OUT is set, the speed at which the light transitions from off to on and vice versa. Default 0.1.
"style" "n"
Set the animated light style. Default 0.
0 NORMAL
1 FLICKER (first variety)
2 SLOW STRONG PULSE
3 CANDLE (first variety)
4 FAST STROBE
5 GENTLE PULSE 1
6 FLICKER (second variety)
7 CANDLE (second variety)
8 CANDLE (third variety)
9 SLOW STROBE (fourth variety)
10 FLUORESCENT FLICKER
11 SLOW PULSE NOT FADE TO BLACK
12 BLINK OFF / ON (can be synced with animated textures, e.g. +0light, +1light, +alight)
"style2" "n"
Set the animated light style for a switchable light.
This is because "style" will be set by your compiling utility to a value in the range 32+,
so we need to tell the QuakeC what actual style to use.
==========
Spawnflags
==========
START_OFF - switchable lights only - light is switched off at map start - default is on
FADE - switchable lights only - light fades in and out when switched. you can't combine this with an animated style.
*/
static void() light =
{
if (self.mdl != "")
{
if (!(self.spawnflags & LIGHT_START_OFF))
setmodel(self, self.mdl);
}
// non-switchable light
if (!self.targetname)
{
//remove(self);
return;
}
// default fade speed
if (self.speed <= 0)
self.speed = 0.1;
// switchable light
if (self.style >= 32)
{
self.use = light_use;
if (self.spawnflags & LIGHT_START_OFF)
{
self.count = 0;
lightstyle(self.style, "a");
}
else
{
self.count = FADE_RAMP - 1;
lightstyle(self.style, lightstyle_lookup(self.style2));
}
}
};
/*QUAKED light_fluoro (1 1 0) (-8 -8 -8) (8 8 8) START_OFF FADE NO_SOUND
Non-displayed light
Makes steady fluorescent humming sound
*/
static void() light_fluoro =
{
ambient_light_buzz();
remove(self);
};
/*QUAKED light_fluorospark (1 1 0) (-8 -8 -8) (8 8 8) START_OFF FADE NO_SOUND
Non-displayed light
Makes sparking, broken fluorescent sound
*/
static void() light_fluorospark =
{
ambient_flouro_buzz();
remove(self);
};
/*QUAKED light_globe (1 1 0) (-8 -8 -8) (8 8 8) START_OFF FADE NO_SOUND
Sprite globe light
*/
static void() light_globe =
{
precache_model("progs/s_light.spr");
setmodel(self, "progs/s_light.spr");
makestatic(self);
};
/*QUAKED light_torch_small_walltorch (1 1 0) (-4 -4 -16) (4 4 32) START_OFF FADE NO_SOUND
{ model ("progs/flame.mdl"); }
Short wall torch
Makes crackling fire noise unless NO_SOUND is set
*/
static void() light_torch_small_walltorch =
{
precache_model("progs/flame.mdl");
setmodel(self, "progs/flame.mdl");
if (!(self.spawnflags & LIGHT_NO_SOUND))
ambient_fire();
makestatic(self);
};
/*QUAKED light_torch_long_walltorch (1 1 0) (-8 -8 -48) (8 8 24) START_OFF FADE NO_SOUND
{ model ("progs/flame3.mdl"); }
Long wall torch
Makes crackling fire noise unless NO_SOUND is set
*/
static void() light_torch_long_walltorch =
{
precache_model("progs/flame3.mdl");
setmodel(self, "progs/flame3.mdl");
if (!(self.spawnflags & LIGHT_NO_SOUND))
ambient_fire();
makestatic(self);
};
/*QUAKED light_flame_small_yellow (1 1 0) (-4 -4 -12) (4 4 16) START_OFF FADE NO_SOUND
{ model ("progs/flame2.mdl"); }
Small yellow flame
Makes crackling fire noise unless NO_SOUND is set
*/
static void() light_flame_small_yellow =
{
precache_model("progs/flame2.mdl");
setmodel(self, "progs/flame2.mdl");
if (!(self.spawnflags & LIGHT_NO_SOUND))
ambient_fire();
makestatic(self);
};
/*==========
light_flame_small_white
For compatability only.
==========*/
static void() light_flame_small_white =
{
self.classname = "light_flame_small_yellow";
light_flame_small_yellow();
};
/*QUAKED light_flame_large_yellow (1 1 0) (-8 -8 -12) (8 8 40) START_OFF FADE NO_SOUND
{ model ( { "path" : "progs/flame2.mdl", "frame" : 1 } ); }
Large yellow flame
Makes crackling fire noise unless NO_SOUND is set
*/
static void() light_flame_large_yellow =
{
precache_model("progs/flame2.mdl");
setmodel (self, "progs/flame2.mdl");
self.frame = 1;
if (!(self.spawnflags & LIGHT_NO_SOUND))
ambient_fire();
makestatic(self);
};
/*==========
s_flame
==========*/
static void() s_flame =
{
self.frame = self.frame + 1;
if (self.frame > 13)
self.frame = 0;
self.think = s_flame;
self.nextthink = time + 0.05;
};
/*QUAKED light_flame_sprite (1 1 0) (-16 -16 0) (16 16 40) START_OFF FADE NO_SOUND
Large yellow flame sprite
Makes crackling fire noise
See the "light" entity for a full description
*/
static void() light_flame_sprite =
{
self.mdl = "progs/s_flame.spr";
precache_model(self.mdl);
self.noise = "ambience/fire1.wav";
precache_sound(self.noise);
self.noise1 = "misc/torchoff.wav";
precache_sound(self.noise1);
self.noise2 = "misc/torchon1.wav";
precache_sound(self.noise2);
if (!(self.spawnflags & LIGHT_NO_SOUND))
ambient_fire();
light();
// assume any sensible engine that implements pr_checkextension
// also has working spritegroups, so we can use
// makestatic and reduce network traffic
if (cvar("pr_checkextension"))
{
self.frame = 14; // frame 14 is a spritegroup which contains 14 frames
//makestatic(self);
}
else
{
self.think = s_flame; // animate frames 0-13 manually
self.nextthink = time + 0.01 + random() * 0.5;
}
};

View File

@@ -0,0 +1,466 @@
enumflags { MISC_MODEL_SOLID };
/*QUAKED misc_model (0 0 1) (-16 -16 -16) (16 16 16) SOLID X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ({"path" : mdl, "skin" : skin, "frame": frame});
}
Custom map object. Non-solid by default.
Keys:
"mdl" "name" - model to load, e.g. "progs/grenade.mdl"
"pos1", "pos2" "vector" - bounding box size. if not defined it will default to '-16 -16 -16', '16 16 16'
"skin" "n" - model or sprite skin
"frame" "n" - model or sprite frame
Spawnflags:
SOLID - Model is solid
*/
void() misc_model =
{
if (!self.mdl)
{
objerror("no mdl");
remove(self);
return;
}
precache_model(self.mdl);
self.movetype = MOVETYPE_NONE;
if (self.spawnflags & MISC_MODEL_SOLID)
self.solid = SOLID_BBOX;
else
self.solid = SOLID_NOT;
setmodel(self, self.mdl);
if (self.pos1 && self.pos2)
setsize(self, self.pos1, self.pos2);
else
setsize(self, '-16 -16 -16', '16 16 16');
if (!(self.spawnflags & MISC_MODEL_SOLID))
makestatic(self);
};
/*QUAKED misc_demon_dead (1 0 0) (-32 -32 -24) (32 32 0) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ({"path":"progs/demon.mdl","frame":53});
}
Dead Fiend
*/
void() misc_demon_dead =
{
self.mdl = "progs/demon.mdl";
self.pos1 = '-32 -32 -24';
self.pos2 = '32 32 0';
self.frame = 53;
misc_model();
};
/*QUAKED misc_demon_head (1 0 0) (-16 -16 0) (16 16 16) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ("progs/h_demon.mdl");
}
Fiend Head
*/
void() misc_demon_head =
{
self.mdl = "progs/h_demon.mdl";
self.pos1 = '-16 -16 0';
self.pos2 = '16 16 16';
misc_model();
};
/*QUAKED misc_dog_dead_1 (1 0 0) (-16 -16 -24) (16 16 0) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ({"path":"progs/dog.mdl","frame":16});
}
Dead dog
*/
void() misc_dog_dead_1 =
{
self.mdl = "progs/dog.mdl";
self.pos1 = '-16 -16 -24';
self.pos2 = '16 16 0';
self.frame = 16;
misc_model();
};
/*QUAKED misc_dog_dead_2 (1 0 0) (-16 -16 -24) (16 16 0) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ({"path":"progs/dog.mdl","frame":25});
}
Dead dog
*/
void() misc_dog_dead_2 =
{
self.mdl = "progs/dog.mdl";
self.pos1 = '-16 -16 -24';
self.pos2 = '16 16 0';
self.frame = 25;
misc_model();
};
/*QUAKED misc_dog_head (1 0 0) (-16 -16 0) (16 16 16) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ("progs/h_dog.mdl");
}
dog Head
*/
void() misc_dog_head =
{
self.mdl = "progs/h_dog.mdl";
self.pos1 = '-16 -16 0';
self.pos2 = '16 16 16';
misc_model();
};
/*QUAKED misc_enforcer_dead_1 (1 0 0) (-16 -16 -24) (16 16 0) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ({"path":"progs/enforcer.mdl","frame":54});
}
Dead Enforcer
*/
void() misc_enforcer_dead_1 =
{
self.mdl = "progs/enforcer.mdl";
self.pos1 = '-16 -16 -24';
self.pos2 = '16 16 0';
self.frame = 54;
misc_model();
};
/*QUAKED misc_enforcer_dead_2 (1 0 0) (-16 -16 -24) (16 16 0) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ({"path":"progs/enforcer.mdl","frame":65});
}
Dead Enforcer
*/
void() misc_enforcer_dead_2 =
{
self.mdl = "progs/enforcer.mdl";
self.pos1 = '-16 -16 -24';
self.pos2 = '16 16 0';
self.frame = 65;
misc_model();
};
/*QUAKED misc_enforcer_head (1 0 0) (-16 -16 0) (16 16 16) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ("progs/h_mega.mdl");
}
Enforcer Head
*/
void() misc_enforcer_head =
{
self.mdl = "progs/h_mega.mdl";
self.pos1 = '-16 -16 0';
self.pos2 = '16 16 16';
misc_model();
};
/*QUAKED misc_fish_dead (1 0 0) (-16 -16 -24) (16 16 0) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ({"path":"progs/fish.mdl","frame":38});
}
Dead Fish
*/
void() misc_fish_dead =
{
self.mdl = "progs/fish.mdl";
self.pos1 = '-16 -16 -24';
self.pos2 = '16 16 0';
self.frame = 38;
misc_model();
};
/*QUAKED misc_hknight_dead_1 (1 0 0) (-16 -16 -24) (16 16 0) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ({"path":"progs/hknight.mdl","frame":53});
}
Dead Death Knight
*/
void() misc_hknight_dead_1 =
{
self.mdl = "progs/hknight.mdl";
self.pos1 = '-16 -16 -24';
self.pos2 = '16 16 0';
self.frame = 53;
misc_model();
};
/*QUAKED misc_hknight_dead_2 (1 0 0) (-16 -16 -24) (16 16 0) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ({"path":"progs/hknight.mdl","frame":62});
}
Dead Death Knight
*/
void() misc_hknight_dead_2 =
{
self.mdl = "progs/hknight.mdl";
self.pos1 = '-16 -16 -24';
self.pos2 = '16 16 0';
self.frame = 62;
misc_model();
};
/*QUAKED misc_hknight_head (1 0 0) (-16 -16 0) (16 16 16) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ("progs/h_hellkn.mdl");
}
Death Knight Head
*/
void() misc_hknight_head =
{
self.mdl = "progs/h_hellkn.mdl";
self.pos1 = '-16 -16 0';
self.pos2 = '16 16 16';
misc_model();
};
/*QUAKED misc_knight_dead_1 (1 0 0) (-16 -16 -24) (16 16 0) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ({"path":"progs/knight.mdl","frame":85});
}
Dead Knight
*/
void() misc_knight_dead_1 =
{
self.mdl = "progs/knight.mdl";
self.pos1 = '-16 -16 -24';
self.pos2 = '16 16 0';
self.frame = 85;
misc_model();
};
/*QUAKED misc_knight_dead_2 (1 0 0) (-16 -16 -24) (16 16 0) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ({"path":"progs/knight.mdl","frame":96});
}
Dead Knight
*/
void() misc_knight_dead_2 =
{
self.mdl = "progs/knight.mdl";
self.pos1 = '-16 -16 -24';
self.pos2 = '16 16 0';
self.frame = 96;
misc_model();
};
/*QUAKED misc_knight_head (1 0 0) (-16 -16 0) (16 16 16) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ("progs/h_knight.mdl");
}
Knight Head
*/
void() misc_knight_head =
{
self.mdl = "progs/h_knight.mdl";
self.pos1 = '-16 -16 0';
self.pos2 = '16 16 16';
misc_model();
};
/*QUAKED misc_ogre_dead_1 (1 0 0) (-32 -32 -24) (32 32 0) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ({"path":"progs/ogre.mdl","frame":125});
}
Dead Ogre
*/
void() misc_ogre_dead_1 =
{
self.mdl = "progs/ogre.mdl";
self.pos1 = '-32 -32 -24';
self.pos2 = '32 32 0';
self.frame = 125;
misc_model();
};
/*QUAKED misc_ogre_dead_2 (1 0 0) (-32 -32 -24) (32 32 0) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ({"path":"progs/ogre.mdl","frame":135});
}
Dead Ogre
*/
void() misc_ogre_dead_2 =
{
self.mdl = "progs/ogre.mdl";
self.pos1 = '-32 -32 -24';
self.pos2 = '32 32 0';
self.frame = 135;
misc_model();
};
/*QUAKED misc_ogre_head (1 0 0) (-16 -16 0) (16 16 16) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ("progs/h_ogre.mdl");
}
Ogre Head
*/
void() misc_ogre_head =
{
self.mdl = "progs/h_ogre.mdl";
self.pos1 = '-16 -16 0';
self.pos2 = '16 16 16';
misc_model();
};
/*QUAKED misc_shalrath_dead (1 0 0) (-32 -32 -24) (32 32 0) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ({"path":"progs/shalrath.mdl","frame":22});
}
Dead Vore
*/
void() misc_shalrath_dead =
{
self.mdl = "progs/shalrath.mdl";
self.pos1 = '-32 -32 -24';
self.pos2 = '32 32 0';
self.frame = 22;
misc_model();
};
/*QUAKED misc_shalrath_head (1 0 0) (-16 -16 0) (16 16 16) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ("progs/h_shal.mdl");
}
Vore Head
*/
void() misc_shalrath_head =
{
self.mdl = "progs/h_shal.mdl";
self.pos1 = '-16 -16 0';
self.pos2 = '16 16 16';
misc_model();
};
/*QUAKED misc_shambler_dead (1 0 0) (-32 -32 -24) (32 32 0) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ({"path":"progs/shambler.mdl","frame":93});
}
Dead Shambler
*/
void() misc_shambler_dead =
{
self.mdl = "progs/shambler.mdl";
self.pos1 = '-32 -32 -24';
self.pos2 = '32 32 0';
self.frame = 93;
misc_model();
};
/*QUAKED misc_shambler_head (1 0 0) (-16 -16 0) (16 16 16) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ("progs/h_shams.mdl");
}
Shambler Head
*/
void() misc_shambler_head =
{
self.mdl = "progs/h_shams.mdl";
self.pos1 = '-16 -16 0';
self.pos2 = '16 16 16';
misc_model();
};
/*QUAKED misc_soldier_dead_1 (1 0 0) (-16 -16 -24) (16 16 0) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ({"path":"progs/soldier.mdl","frame":28});
}
Dead Grunt
*/
void() misc_soldier_dead_1 =
{
self.mdl = "progs/soldier.mdl";
self.pos1 = '-16 -16 -24';
self.pos2 = '16 16 0';
self.frame = 17;
misc_model();
};
/*QUAKED misc_soldier_dead_2 (1 0 0) (-16 -16 -24) (16 16 0) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ({"path":"progs/soldier.mdl","frame":28});
}
Dead Grunt
*/
void() misc_soldier_dead_2 =
{
self.mdl = "progs/soldier.mdl";
self.pos1 = '-16 -16 -24';
self.pos2 = '16 16 0';
self.frame = 28;
misc_model();
};
/*QUAKED misc_soldier_head (1 0 0) (-16 -16 0) (16 16 16) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ("progs/h_guard.mdl");
}
Grunt Head
*/
void() misc_soldier_head =
{
self.mdl = "progs/h_guard.mdl";
self.pos1 = '-16 -16 0';
self.pos2 = '16 16 16';
misc_model();
};
/*QUAKED misc_wizard_dead (1 0 0) (-16 -16 -24) (16 16 0) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ({"path":"progs/wizard.mdl","frame":53});
}
Dead Scrag
*/
void() misc_wizard_dead =
{
self.mdl = "progs/wizard.mdl";
self.pos1 = '-16 -16 -24';
self.pos2 = '16 16 0';
self.frame = 53;
misc_model();
};
/*QUAKED misc_wizard_head (1 0 0) (-16 -16 0) (16 16 16) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ("progs/h_wizard.mdl");
}
Scrag Head
*/
void() misc_wizard_head =
{
self.mdl = "progs/h_wizard.mdl";
self.pos1 = '-16 -16 0';
self.pos2 = '16 16 16';
misc_model();
};
/*QUAKED misc_zombie_dead (1 0 0) (-16 -16 -24) (16 16 0) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ({"path":"progs/zombie.mdl","frame":172});
}
Dead Zombie
*/
void() misc_zombie_dead =
{
self.mdl = "progs/zombie.mdl";
self.pos1 = '-16 -16 -24';
self.pos2 = '16 16 0';
self.frame = 172;
misc_model();
};
/*QUAKED misc_zombie_head (1 0 0) (-16 -16 0) (16 16 16) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model ("progs/h_zombie.mdl");
}
Zombie Head
*/
void() misc_zombie_head =
{
self.mdl = "progs/h_zombie.mdl";
self.pos1 = '-16 -16 0';
self.pos2 = '16 16 16';
misc_model();
};

View File

@@ -0,0 +1,189 @@
enumflags { MONSTER_AMBUSH, MONSTER_TELEPORT=4 };
/*==========
monster_death_use
when a monster dies, it fires it's targets with its enemy as the activator
==========*/
void() monster_death_use =
{
// drop to floor
if (self.flags & FL_FLY)
self.flags = self.flags - FL_FLY;
if (self.flags & FL_SWIM)
self.flags = self.flags - FL_SWIM;
// use targets
activator = self.enemy;
UseTargets();
// bump monster counter
killed_monsters = killed_monsters + 1;
WriteByte (MSG_ALL, SVC_KILLEDMONSTER);
};
/*==========
monster_use
using a monster makes it angry if the activator is a player
==========*/
static void() monster_use =
{
if (self.enemy)
return;
if (self.health <= 0)
return;
if (activator.classname != "player")
return;
if (activator.items & IT_INVISIBILITY)
return;
if (activator.flags & FL_NOTARGET)
return;
self.enemy = activator;
self.nextthink = time + 0.1;
self.think = FoundTarget;
};
/*==========
monster_start_go
==========*/
static void() monster_start_go =
{
// only walkmonsters drop to the floor
if (self.flags & (FL_MONSTER | FL_FLY | FL_SWIM) == FL_MONSTER)
{
self.origin_z = self.origin_z + 1;
droptofloor();
}
// print console warning if we're stuck in a wall
if (!walkmove(0, 0))
{
dprint(self.classname);
dprint(" in wall at: ");
dprint(vtos(self.origin));
dprint("\n");
}
self.think = self.th_stand;
self.nextthink = time + 0.01 + random() * 0.5;
// if the monster targets a path corner, they will move towards it
// otherwise, they will fire their targets upon death
if (self.target != "")
{
entity t = find(world, targetname, self.target);
if (!t)
{
dprint(self.classname);
dprint (" can't find target at: ");
dprint (vtos(self.origin));
dprint ("\n");
return;
}
if (t.classname == "path_corner")
{
self.movetarget = self.goalentity = t;
self.ideal_yaw = vectoyaw(t.origin - self.origin);
self.think = self.th_walk;
}
}
};
/*==========
monster_teleport_use
using a monster with the teleport flag spawns it in
==========*/
static void() monster_teleport_use =
{
self.use = monster_use;
self.takedamage = DAMAGE_AIM;
self.solid = SOLID_SLIDEBOX;
self.movetype = MOVETYPE_STEP;
setmodel(self, self.mdl);
setsize(self, self.pos1, self.pos2);
spawn_tdeath(self.origin, self);
spawn_tfog(self.origin);
self.think = self.th_stand;
self.nextthink = time + 0.1;
// if a player activated the monster,
// get mad unless they're invisible or notarget
if (activator.classname == "player")
{
if (activator.flags & FL_NOTARGET)
return;
if (activator.items & IT_INVISIBILITY)
return;
self.enemy = activator;
self.think = FoundTarget;
self.nextthink = time + 0.1;
}
};
/*==========
monster_start
==========*/
void(string mod, string hmod, float hp, float fl, vector min, vector max) monster_start =
{
total_monsters = total_monsters + 1;
self.flags = FL_MONSTER + fl; // FL_FLY or FL_SWIM
self.headmodel = hmod;
self.health = hp;
if (self.flags & FL_FLY)
{
self.yaw_speed = 20;
self.view_ofs = '0 0 25';
}
else if (self.flags & FL_SWIM)
{
self.yaw_speed = 10;
self.view_ofs = '0 0 10';
}
else
{
self.yaw_speed = 30;
self.view_ofs = '0 0 25';
}
self.ideal_yaw = self.angles_y;
// teleport flag
if (self.spawnflags & MONSTER_TELEPORT)
{
if (!self.targetname)
{
total_monsters = total_monsters - 1;
objerror("teleporting monsters must have a targetname\n");
remove(self);
return;
}
self.use = monster_teleport_use;
self.solid = SOLID_NOT;
self.movetype = MOVETYPE_NONE;
setsize(self, min, max);
// save off fields so we can restore them later
self.pos1 = min;
self.pos2 = max;
self.mdl = mod;
return;
}
self.solid = SOLID_SLIDEBOX;
self.movetype = MOVETYPE_STEP;
setmodel (self, mod);
setsize (self, min, max);
self.use = monster_use;
self.takedamage = DAMAGE_AIM;
self.think = monster_start_go;
self.nextthink = time + 0.01 + random() * 0.5;
};

View File

@@ -0,0 +1,381 @@
$frame rise1 rise2 rise3 rise4 rise5 rise6 rise7 rise8 rise9 rise10
$frame rise11 rise12 rise13 rise14 rise15 rise16 rise17
$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8
$frame walk9 walk10 walk11 walk12 walk13 walk14 walk15
$frame walk16 walk17 walk18 walk19 walk20 walk21 walk22
$frame walk23 walk24 walk25 walk26 walk27 walk28 walk29 walk30 walk31
$frame death1 death2 death3 death4 death5 death6 death7 death8 death9
$frame attack1 attack2 attack3 attack4 attack5 attack6 attack7 attack8
$frame attack9 attack10 attack11 attack12 attack13 attack14 attack15
$frame attack16 attack17 attack18 attack19 attack20 attack21 attack22
$frame attack23
$frame shocka1 shocka2 shocka3 shocka4 shocka5 shocka6 shocka7 shocka8
$frame shocka9 shocka10
$frame shockb1 shockb2 shockb3 shockb4 shockb5 shockb6
$frame shockc1 shockc2 shockc3 shockc4 shockc5 shockc6 shockc7 shockc8
$frame shockc9 shockc10
#define CHTHON_M_VEL 300
void() boss_missile1;
/*==========
boss_idle
==========*/
void() boss_idle =
{
// look for a new player in co-op
if (coop)
{
entity client = checkclient();
if (client)
{
if (visible(client))
{
self.enemy = client;
boss_missile1();
return;
}
}
}
self.walkframe = self.walkframe + 1;
if (self.walkframe > 30)
self.walkframe = 0;
self.frame = $walk1 + self.walkframe;
self.think = boss_idle;
self.nextthink = time + 0.1;
};
void() boss_rise1 =[ $rise1, boss_rise2 ] {te_lavasplash(self.origin);sound(self, CHAN_BODY, "boss1/out1.wav", 1, ATTN_NORM);};
void() boss_rise2 =[ $rise2, boss_rise3 ] {};
void() boss_rise3 =[ $rise3, boss_rise4 ] {};
void() boss_rise4 =[ $rise4, boss_rise5 ] {};
void() boss_rise5 =[ $rise5, boss_rise6 ] {sound (self, CHAN_VOICE, "boss1/sight1.wav", 1, ATTN_NORM);};
void() boss_rise6 =[ $rise6, boss_rise7 ] {};
void() boss_rise7 =[ $rise7, boss_rise8 ] {};
void() boss_rise8 =[ $rise8, boss_rise9 ] {};
void() boss_rise9 =[ $rise9, boss_rise10 ] {};
void() boss_rise10 =[ $rise10, boss_rise11 ] {};
void() boss_rise11 =[ $rise11, boss_rise12 ] {};
void() boss_rise12 =[ $rise12, boss_rise13 ] {};
void() boss_rise13 =[ $rise13, boss_rise14 ] {};
void() boss_rise14 =[ $rise14, boss_rise15 ] {};
void() boss_rise15 =[ $rise15, boss_rise16 ] {};
void() boss_rise16 =[ $rise16, boss_rise17 ] {};
void() boss_rise17 =[ $rise17, boss_missile1 ] {};
/*==========
boss_missile
==========*/
void(float ofs) boss_missile =
{
sound (self, CHAN_WEAPON, "boss1/throw.wav", 1, ATTN_NORM);
makevectors(self.angles);
vector org = self.origin + v_forward * 100 + v_right * ofs + v_up * self.view_ofs_z;
vector d;
// lead the player on hard mode
if (skill > 1)
{
float t = vlen(self.enemy.origin + self.enemy.view_ofs - org) / CHTHON_M_VEL;
vector vec = self.enemy.velocity;
vec_z = 0;
d = self.enemy.origin + self.enemy.view_ofs + (t * vec);
}
else
d = self.enemy.origin + self.enemy.view_ofs;
vec = normalize(d - org);
launch_spike (org, vec);
setmodel (newmis, "progs/lavaball.mdl");
setsize (newmis, '0 0 0', '0 0 0');
newmis.avelocity = '200 100 300';
newmis.velocity = vec * CHTHON_M_VEL;
newmis.touch = T_MissileTouch;
};
/*==========
boss_check_enemy
==========*/
void() boss_check_enemy =
{
// look for a new player in coop
if (coop)
{
// randomly switch, or switch when player is dead
if (random() < 0.5 || self.enemy.health <= 0)
{
entity client = checkclient();
if (!client)
{
if (self.enemy.health > 0)
return;
// go to idle, no live players found
self.enemy = world;
boss_idle();
return;
}
self.enemy = client;
}
return;
}
// go to idle in single player if the player is dead
if (self.enemy.health <= 0)
{
self.enemy = world;
boss_idle();
}
};
void() boss_missile1 =[ $attack1, boss_missile2 ] {ai_face();};
void() boss_missile2 =[ $attack2, boss_missile3 ] {ai_face();};
void() boss_missile3 =[ $attack3, boss_missile4 ] {ai_face();};
void() boss_missile4 =[ $attack4, boss_missile5 ] {ai_face();};
void() boss_missile5 =[ $attack5, boss_missile6 ] {ai_face();};
void() boss_missile6 =[ $attack6, boss_missile7 ] {ai_face();};
void() boss_missile7 =[ $attack7, boss_missile8 ] {ai_face();boss_missile(100);};
void() boss_missile8 =[ $attack8, boss_missile9 ] {ai_face();};
void() boss_missile9 =[ $attack9, boss_missile10 ] {ai_face();};
void() boss_missile10 =[ $attack10, boss_missile11 ] {ai_face();};
void() boss_missile11 =[ $attack11, boss_missile12 ] {ai_face();};
void() boss_missile12 =[ $attack12, boss_missile13 ] {ai_face();};
void() boss_missile13 =[ $attack13, boss_missile14 ] {ai_face();};
void() boss_missile14 =[ $attack14, boss_missile15 ] {ai_face();};
void() boss_missile15 =[ $attack15, boss_missile16 ] {ai_face();};
void() boss_missile16 =[ $attack16, boss_missile17 ] {ai_face();};
void() boss_missile17 =[ $attack17, boss_missile18 ] {ai_face();};
void() boss_missile18 =[ $attack18, boss_missile19 ] {ai_face();boss_missile(-100);};
void() boss_missile19 =[ $attack19, boss_missile20 ] {ai_face();};
void() boss_missile20 =[ $attack20, boss_missile21 ] {ai_face();};
void() boss_missile21 =[ $attack21, boss_missile22 ] {ai_face();};
void() boss_missile22 =[ $attack22, boss_missile23 ] {ai_face();};
void() boss_missile23 =[ $attack23, boss_missile1 ] {ai_face();boss_check_enemy();};
void() boss_shocka1 =[ $shocka1, boss_shocka2 ] {};
void() boss_shocka2 =[ $shocka2, boss_shocka3 ] {};
void() boss_shocka3 =[ $shocka3, boss_shocka4 ] {};
void() boss_shocka4 =[ $shocka4, boss_shocka5 ] {};
void() boss_shocka5 =[ $shocka5, boss_shocka6 ] {};
void() boss_shocka6 =[ $shocka6, boss_shocka7 ] {};
void() boss_shocka7 =[ $shocka7, boss_shocka8 ] {};
void() boss_shocka8 =[ $shocka8, boss_shocka9 ] {};
void() boss_shocka9 =[ $shocka9, boss_shocka10 ] {};
void() boss_shocka10 =[ $shocka10, boss_missile1 ] {};
void() boss_shockb1 =[ $shockb1, boss_shockb2 ] {};
void() boss_shockb2 =[ $shockb2, boss_shockb3 ] {};
void() boss_shockb3 =[ $shockb3, boss_shockb4 ] {};
void() boss_shockb4 =[ $shockb4, boss_shockb5 ] {};
void() boss_shockb5 =[ $shockb5, boss_shockb6 ] {};
void() boss_shockb6 =[ $shockb6, boss_shockb7 ] {};
void() boss_shockb7 =[ $shockb1, boss_shockb8 ] {};
void() boss_shockb8 =[ $shockb2, boss_shockb9 ] {};
void() boss_shockb9 =[ $shockb3, boss_shockb10 ] {};
void() boss_shockb10 =[ $shockb4, boss_missile1 ] {};
void() boss_shockc1 =[ $shockc1, boss_shockc2 ] {};
void() boss_shockc2 =[ $shockc2, boss_shockc3 ] {};
void() boss_shockc3 =[ $shockc3, boss_shockc4 ] {};
void() boss_shockc4 =[ $shockc4, boss_shockc5 ] {};
void() boss_shockc5 =[ $shockc5, boss_shockc6 ] {};
void() boss_shockc6 =[ $shockc6, boss_shockc7 ] {};
void() boss_shockc7 =[ $shockc7, boss_shockc8 ] {};
void() boss_shockc8 =[ $shockc8, boss_shockc9 ] {};
void() boss_shockc9 =[ $shockc9, boss_shockc10 ] {};
void() boss_shockc10 =[ $shockc10, boss_death1 ] {};
void() boss_death1 = [$death1, boss_death2] {sound (self, CHAN_VOICE, "boss1/death.wav", 1, ATTN_NORM);};
void() boss_death2 = [$death2, boss_death3] {};
void() boss_death3 = [$death3, boss_death4] {};
void() boss_death4 = [$death4, boss_death5] {};
void() boss_death5 = [$death5, boss_death6] {};
void() boss_death6 = [$death6, boss_death7] {};
void() boss_death7 = [$death7, boss_death8] {};
void() boss_death8 = [$death8, boss_death9] {te_lavasplash(self.origin);sound (self, CHAN_BODY, "boss1/out1.wav", 1, ATTN_NORM);};
void() boss_death9 = [$death9, boss_death10] {};
void() boss_death10 = [$death9, boss_death10]
{
// bump kill counter
killed_monsters = killed_monsters + 1;
WriteByte (MSG_ALL, SVC_KILLEDMONSTER);
// use targets
activator = self.enemy;
UseTargets();
remove(self);
};
/*==========
boss_awake
==========*/
void() boss_awake =
{
self.health = skill + 1;
self.yaw_speed = 20;
self.view_ofs = '0 0 200';
if (activator.classname == "player")
self.enemy = activator;
self.solid = SOLID_SLIDEBOX;
self.movetype = MOVETYPE_STEP;
self.takedamage = DAMAGE_NO;
setmodel (self, "progs/boss.mdl");
setsize (self, '-128 -128 -24', '128 128 256');
boss_rise1();
};
/*QUAKED monster_boss (1 0 0) (-128 -128 -24) (128 128 256)
{
model ("progs/boss.mdl");
}
Chthon, for Boss levels.
Must be triggered to activate.
*/
void() monster_boss =
{
if (deathmatch)
{
remove(self);
return;
}
precache_model ("progs/boss.mdl");
precache_model ("progs/lavaball.mdl");
precache_sound ("boss1/out1.wav");
precache_sound ("boss1/sight1.wav");
precache_sound ("boss1/throw.wav");
precache_sound ("boss1/pain.wav");
precache_sound ("boss1/death.wav");
precache_sound ("misc/power.wav");
total_monsters = total_monsters + 1;
self.use = boss_awake;
};
//===========================================================================
void() lightning_use;
/*==========
lightning_fire
==========*/
void() lightning_fire =
{
// return electrodes when the bolt is done
if (time >= self.attack_finished)
{
self.state = 0;
entity oself = self;
self = self.target1;
door_go_down ();
self = oself.target2;
door_go_down ();
return;
}
// use two beams that meet in the middle, rather than the
// hack of making a single beam shorter
te_lightning3(self.pos1, self.pos2, self.target1);
te_lightning3(self.pos2, self.origin, self.target2);
self.nextthink = time + 0.1;
self.think = lightning_fire;
};
/*==========
lightning_use
==========*/
void() lightning_use =
{
if (self.state)
return;
// check the electrodes are aligned and not moving
if (self.target1.state != self.target2.state)
return;
if (self.target1.state != STATE_BOTTOM && self.target1.state != STATE_TOP)
return;
self.state = 1;
// don't let the electrodes go back up until the bolt is done
self.target1.nextthink = -1;
self.target2.nextthink = -1;
self.attack_finished = time + 1;
// find the position of the electrodes and then move the
// event_lightning entity to the middle of the electrodes.
// this is because e1m7 annoyingly has it positioned to the left of the
// button so the sound of the lightning is always panned incorrectly!
self.pos1 = (self.target1.mins + self.target1.maxs) * 0.5;
self.pos1_z = self.target1.absmin_z - 16;
self.pos2 = (self.target2.mins + self.target2.maxs) * 0.5;
self.pos2_z = self.target2.absmin_z - 16;
float len = vlen(self.pos2 - self.pos1);
vector dir = normalize(self.pos2 - self.pos1);
setorigin(self, self.pos1 + dir * len * 0.5);
sound (self, CHAN_VOICE, "misc/power.wav", 1, ATTN_NONE); // no attenuation
lightning_fire();
// decrease chthon health
entity chthon = find (world, classname, "monster_boss");
if (!chthon)
return;
if (self.target1.state == STATE_TOP && chthon.health > 0)
{
self = chthon;
self.enemy = activator;
sound (self, CHAN_VOICE, "boss1/pain.wav", 1, ATTN_NORM);
self.health = self.health - 1;
if (self.health > 1)
boss_shocka1();
else if (self.health == 1)
boss_shockb1();
else if (self.health == 0)
boss_shockc1();
}
};
/*==========
event_lightning_go
==========*/
void() event_lightning_go =
{
// find electrodes
self.target1 = find(world, target, "lightning");
self.target2 = find(self.target1, target, "lightning");
if (!self.target1 || !self.target2)
{
objerror("unable to find lightning targets");
remove(self);
return;
}
self.use = lightning_use;
};
/*QUAKED event_lightning (0 1 1) (-8 -8 -8) (8 8 8)
Triggerable lightning event for Chthon only.
You must have two func_door's in the level which both contain a target of "lightning" (not targetname!)
*/
void() event_lightning =
{
precache_sound ("misc/power.wav");
self.think = event_lightning_go;
self.nextthink = time + 0.2;
};

View File

@@ -0,0 +1,297 @@
$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9
$frame stand10 stand11 stand12 stand13
$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8
$frame run1 run2 run3 run4 run5 run6
$frame leap1 leap2 leap3 leap4 leap5 leap6 leap7 leap8 leap9 leap10
$frame leap11 leap12
$frame pain1 pain2 pain3 pain4 pain5 pain6
$frame death1 death2 death3 death4 death5 death6 death7 death8 death9
$frame attacka1 attacka2 attacka3 attacka4 attacka5 attacka6 attacka7 attacka8
$frame attacka9 attacka10 attacka11 attacka12 attacka13 attacka14 attacka15
void() demon1_stand1 =[ $stand1, demon1_stand2 ] {ai_stand();
if (random() < 0.1)
sound (self, CHAN_VOICE, "demon/idle1.wav", 1, ATTN_IDLE);
};
void() demon1_stand2 =[ $stand2, demon1_stand3 ] {ai_stand();};
void() demon1_stand3 =[ $stand3, demon1_stand4 ] {ai_stand();};
void() demon1_stand4 =[ $stand4, demon1_stand5 ] {ai_stand();};
void() demon1_stand5 =[ $stand5, demon1_stand6 ] {ai_stand();};
void() demon1_stand6 =[ $stand6, demon1_stand7 ] {ai_stand();};
void() demon1_stand7 =[ $stand7, demon1_stand8 ] {ai_stand();};
void() demon1_stand8 =[ $stand8, demon1_stand9 ] {ai_stand();};
void() demon1_stand9 =[ $stand9, demon1_stand10 ] {ai_stand();};
void() demon1_stand10 =[ $stand10, demon1_stand11 ] {ai_stand();};
void() demon1_stand11 =[ $stand11, demon1_stand12 ] {ai_stand();};
void() demon1_stand12 =[ $stand12, demon1_stand13 ] {ai_stand();};
void() demon1_stand13 =[ $stand13, demon1_stand1 ] {ai_stand();};
void() demon1_walk1 =[ $walk1, demon1_walk2 ] {
if (random() < 0.2)
sound (self, CHAN_VOICE, "demon/idle1.wav", 1, ATTN_IDLE);
ai_walk(8);
};
void() demon1_walk2 =[ $walk2, demon1_walk3 ] {ai_walk(6);};
void() demon1_walk3 =[ $walk3, demon1_walk4 ] {ai_walk(6);};
void() demon1_walk4 =[ $walk4, demon1_walk5 ] {ai_walk(7);};
void() demon1_walk5 =[ $walk5, demon1_walk6 ] {ai_walk(4);};
void() demon1_walk6 =[ $walk6, demon1_walk7 ] {ai_walk(6);};
void() demon1_walk7 =[ $walk7, demon1_walk8 ] {ai_walk(10);};
void() demon1_walk8 =[ $walk8, demon1_walk1 ] {ai_walk(10);};
void() demon1_run1 =[ $run1, demon1_run2 ] {
if (random() < 0.2)
sound (self, CHAN_VOICE, "demon/idle1.wav", 1, ATTN_IDLE);
ai_run(20);};
void() demon1_run2 =[ $run2, demon1_run3 ] {ai_run(15);};
void() demon1_run3 =[ $run3, demon1_run4 ] {ai_run(36);};
void() demon1_run4 =[ $run4, demon1_run5 ] {ai_run(20);};
void() demon1_run5 =[ $run5, demon1_run6 ] {ai_run(15);};
void() demon1_run6 =[ $run6, demon1_run1 ] {ai_run(36);};
void() demon1_jump1;
void() demon1_jump11;
void() Demon_JumpTouch =
{
if (self.health <= 0)
return;
if (other.takedamage)
{
if (vlen(self.velocity) > 400)
{
float ldmg = 40 + 10 * random();
Damage (other, self, self, ldmg);
}
}
if (!checkbottom(self))
{
if (self.flags & FL_ONGROUND)
{
self.touch = SUB_Null;
self.think = demon1_jump1;
self.nextthink = time + 0.1;
}
return;
}
self.touch = SUB_Null;
self.think = demon1_jump11;
self.nextthink = time + 0.1;
};
void() demon1_jump1 =[ $leap1, demon1_jump2 ] {ai_face();};
void() demon1_jump2 =[ $leap2, demon1_jump3 ] {ai_face();};
void() demon1_jump3 =[ $leap3, demon1_jump4 ] {ai_face();};
void() demon1_jump4 =[ $leap4, demon1_jump5 ]
{
ai_face();
self.touch = Demon_JumpTouch;
makevectors (self.angles);
self.origin_z = self.origin_z + 1;
self.velocity = v_forward * 600 + '0 0 250';
if (self.flags & FL_ONGROUND)
self.flags = self.flags - FL_ONGROUND;
};
void() demon1_jump5 =[ $leap5, demon1_jump6 ] {};
void() demon1_jump6 =[ $leap6, demon1_jump7 ] {};
void() demon1_jump7 =[ $leap7, demon1_jump8 ] {};
void() demon1_jump8 =[ $leap8, demon1_jump9 ] {};
void() demon1_jump9 =[ $leap9, demon1_jump10 ] {};
void() demon1_jump10 =[ $leap10, demon1_jump1 ] {self.nextthink = time + 3;};
void() demon1_jump11 =[ $leap11, demon1_jump12 ] {};
void() demon1_jump12 =[ $leap12, demon1_run1 ] {};
void(float side) Demon_Melee =
{
ai_face ();
walkmove (self.ideal_yaw, 12);
if (vlen(self.enemy.origin - self.origin) > 100)
return;
if (!CanDamage (self.enemy, self))
return;
sound (self, CHAN_WEAPON, "demon/dhit2.wav", 1, ATTN_NORM);
float ldmg = 10 + 5 * random();
Damage (self.enemy, self, self, ldmg);
makevectors (self.angles);
SpawnMeatSpray (self.origin + v_forward*16, side * v_right);
};
void() demon1_atta1 =[ $attacka1, demon1_atta2 ] {ai_charge(4);};
void() demon1_atta2 =[ $attacka2, demon1_atta3 ] {ai_charge(0);};
void() demon1_atta3 =[ $attacka3, demon1_atta4 ] {ai_charge(0);};
void() demon1_atta4 =[ $attacka4, demon1_atta5 ] {ai_charge(1);};
void() demon1_atta5 =[ $attacka5, demon1_atta6 ] {ai_charge(2); Demon_Melee(200);};
void() demon1_atta6 =[ $attacka6, demon1_atta7 ] {ai_charge(1);};
void() demon1_atta7 =[ $attacka7, demon1_atta8 ] {ai_charge(6);};
void() demon1_atta8 =[ $attacka8, demon1_atta9 ] {ai_charge(8);};
void() demon1_atta9 =[ $attacka9, demon1_atta10 ] {ai_charge(4);};
void() demon1_atta10 =[ $attacka10, demon1_atta11 ] {ai_charge(2);};
void() demon1_atta11 =[ $attacka11, demon1_atta12 ] {Demon_Melee(-200);};
void() demon1_atta12 =[ $attacka12, demon1_atta13 ] {ai_charge(5);};
void() demon1_atta13 =[ $attacka13, demon1_atta14 ] {ai_charge(8);};
void() demon1_atta14 =[ $attacka14, demon1_atta15 ] {ai_charge(4);};
void() demon1_atta15 =[ $attacka15, demon1_run1 ] {ai_charge(4);};
void() demon1_pain1 =[ $pain1, demon1_pain2 ] {};
void() demon1_pain2 =[ $pain2, demon1_pain3 ] {};
void() demon1_pain3 =[ $pain3, demon1_pain4 ] {};
void() demon1_pain4 =[ $pain4, demon1_pain5 ] {};
void() demon1_pain5 =[ $pain5, demon1_pain6 ] {};
void() demon1_pain6 =[ $pain6, demon1_run1 ] {};
void(entity attacker, float damage) demon_pain =
{
if (self.touch == Demon_JumpTouch)
return;
if (self.pain_finished > time)
return;
self.pain_finished = time + 1;
sound (self, CHAN_VOICE, "demon/dpain1.wav", 1, ATTN_NORM);
if (random()*200 > damage)
return; // didn't flinch
demon1_pain1 ();
};
void() demon1_die1 =[ $death1, demon1_die2 ] {};
void() demon1_die2 =[ $death2, demon1_die3 ] {};
void() demon1_die3 =[ $death3, demon1_die4 ] {};
void() demon1_die4 =[ $death4, demon1_die5 ] {};
void() demon1_die5 =[ $death5, demon1_die6 ] {};
void() demon1_die6 =[ $death6, demon1_die7 ] {};
void() demon1_die7 =[ $death7, demon1_die8 ] {};
void() demon1_die8 =[ $death8, demon1_die9 ] {};
void() demon1_die9 =[ $death9, demon1_die9 ] {};
void(entity inflictor, entity attacker) demon_die =
{
if (self.health < -80)
{
SpawnGib("progs/gib3.mdl");
SpawnGib("progs/gib3.mdl");
SpawnGib("progs/gib4.mdl");
SpawnGib("progs/gib5.mdl");
SpawnGib("progs/blood.mdl");
SpawnGib("progs/blood.mdl");
BecomeGibs();
return;
}
sound (self, CHAN_VOICE, "demon/ddeath.wav", 1, ATTN_NORM);
self.solid = SOLID_NOT;
demon1_die1 ();
};
void() Demon_MeleeAttack =
{
sound (self, CHAN_VOICE, "demon/idle1.wav", 1, ATTN_NORM);
demon1_atta1 ();
};
/*QUAKED monster_demon1 (1 0 0) (-32 -32 -24) (32 32 64) Ambush
{
model ("progs/demon.mdl");
}
Fiend.
*/
void() monster_demon1 =
{
if (deathmatch)
{
remove(self);
return;
}
precache_model ("progs/demon.mdl");
precache_model ("progs/h_demon.mdl");
precache_sound ("demon/ddeath.wav");
precache_sound ("demon/dhit2.wav");
precache_sound ("demon/djump.wav");
precache_sound ("demon/dpain1.wav");
precache_sound ("demon/idle1.wav");
precache_sound ("demon/sight2.wav");
self.th_stand = demon1_stand1;
self.th_walk = demon1_walk1;
self.th_run = demon1_run1;
self.th_die = demon_die;
self.th_melee = Demon_MeleeAttack;
self.th_missile = demon1_jump1;
self.th_pain = demon_pain;
monster_start("progs/demon.mdl", "progs/h_demon.mdl", 300, 0, VEC_HULL2_MIN, VEC_HULL2_MAX);
};
float() CheckDemonJump =
{
vector spot1 = self.origin;
vector spot2 = self.enemy.origin;
traceline (spot1, spot2, MOVE_MISSILE, self);
if (trace_inwater)
if (trace_inopen)
return FALSE;
if (trace_ent != self.enemy)
return FALSE;
// too high above player
if (self.origin_z + self.mins_z > self.enemy.origin_z + self.enemy.mins_z + 0.75 * self.enemy.size_z)
return FALSE;
// too low below player
if (self.origin_z + self.maxs_z < self.enemy.origin_z + self.enemy.mins_z + 0.25 * self.enemy.size_z)
return FALSE;
vector dist = self.enemy.origin - self.origin;
dist_z = 0;
float len = vlen(dist);
if (len < 100)
return FALSE;
if (len > 200)
{
if (random() < 0.9)
return FALSE;
}
return TRUE;
};
float() DemonCheckAttack =
{
if (enemy_range == RANGE_MELEE)
{
if (CanDamage(self.enemy, self))
{
self.attack_state = AS_MELEE;
return TRUE;
}
}
if (enemy_range == RANGE_FAR)
return FALSE;
if (CheckDemonJump())
{
sound (self, CHAN_VOICE, "demon/djump.wav", 1, ATTN_NORM);
self.attack_state = AS_MISSILE;
return TRUE;
}
return FALSE;
};

View File

@@ -0,0 +1,357 @@
/*
==============================================================================
DOG
==============================================================================
*/
$cd id1/models/dog
$origin 0 0 24
$base base
$skin skin
$frame attack1 attack2 attack3 attack4 attack5 attack6 attack7 attack8
$frame death1 death2 death3 death4 death5 death6 death7 death8 death9
$frame deathb1 deathb2 deathb3 deathb4 deathb5 deathb6 deathb7 deathb8
$frame deathb9
$frame pain1 pain2 pain3 pain4 pain5 pain6
$frame painb1 painb2 painb3 painb4 painb5 painb6 painb7 painb8 painb9 painb10
$frame painb11 painb12 painb13 painb14 painb15 painb16
$frame run1 run2 run3 run4 run5 run6 run7 run8 run9 run10 run11 run12
$frame leap1 leap2 leap3 leap4 leap5 leap6 leap7 leap8 leap9
$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9
$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8
void() dog_leap1;
void() dog_run1;
/*
================
dog_bite
================
*/
void() dog_bite =
{
local vector delta;
local float ldmg;
if (!self.enemy)
return;
ai_charge(10);
if (!CanDamage (self.enemy, self))
return;
delta = self.enemy.origin - self.origin;
if (vlen(delta) > 100)
return;
ldmg = (random() + random() + random()) * 8;
Damage (self.enemy, self, self, ldmg);
};
void() Dog_JumpTouch =
{
local float ldmg;
if (self.health <= 0)
return;
if (other.takedamage)
{
if ( vlen(self.velocity) > 300 )
{
ldmg = 10 + 10*random();
Damage (other, self, self, ldmg);
}
}
if (!checkbottom(self))
{
if (self.flags & FL_ONGROUND)
{ // jump randomly to not get hung up
//dprint ("popjump\n");
self.touch = SUB_Null;
self.think = dog_leap1;
self.nextthink = time + 0.1;
// self.velocity_x = (random() - 0.5) * 600;
// self.velocity_y = (random() - 0.5) * 600;
// self.velocity_z = 200;
// self.flags = self.flags - FL_ONGROUND;
}
return; // not on ground yet
}
self.touch = SUB_Null;
self.think = dog_run1;
self.nextthink = time + 0.1;
};
void() dog_stand1 =[ $stand1, dog_stand2 ] {ai_stand();};
void() dog_stand2 =[ $stand2, dog_stand3 ] {ai_stand();};
void() dog_stand3 =[ $stand3, dog_stand4 ] {ai_stand();};
void() dog_stand4 =[ $stand4, dog_stand5 ] {ai_stand();};
void() dog_stand5 =[ $stand5, dog_stand6 ] {ai_stand();};
void() dog_stand6 =[ $stand6, dog_stand7 ] {ai_stand();};
void() dog_stand7 =[ $stand7, dog_stand8 ] {ai_stand();};
void() dog_stand8 =[ $stand8, dog_stand9 ] {ai_stand();};
void() dog_stand9 =[ $stand9, dog_stand1 ] {ai_stand();};
void() dog_walk1 =[ $walk1 , dog_walk2 ] {
if (random() < 0.2)
sound (self, CHAN_VOICE, "dog/idle.wav", 1, ATTN_IDLE);
ai_walk(8);};
void() dog_walk2 =[ $walk2 , dog_walk3 ] {ai_walk(8);};
void() dog_walk3 =[ $walk3 , dog_walk4 ] {ai_walk(8);};
void() dog_walk4 =[ $walk4 , dog_walk5 ] {ai_walk(8);};
void() dog_walk5 =[ $walk5 , dog_walk6 ] {ai_walk(8);};
void() dog_walk6 =[ $walk6 , dog_walk7 ] {ai_walk(8);};
void() dog_walk7 =[ $walk7 , dog_walk8 ] {ai_walk(8);};
void() dog_walk8 =[ $walk8 , dog_walk1 ] {ai_walk(8);};
void() dog_run1 =[ $run1 , dog_run2 ] {
if (random() < 0.2)
sound (self, CHAN_VOICE, "dog/idle.wav", 1, ATTN_IDLE);
ai_run(16);};
void() dog_run2 =[ $run2 , dog_run3 ] {ai_run(32);};
void() dog_run3 =[ $run3 , dog_run4 ] {ai_run(32);};
void() dog_run4 =[ $run4 , dog_run5 ] {ai_run(20);};
void() dog_run5 =[ $run5 , dog_run6 ] {ai_run(64);};
void() dog_run6 =[ $run6 , dog_run7 ] {ai_run(32);};
void() dog_run7 =[ $run7 , dog_run8 ] {ai_run(16);};
void() dog_run8 =[ $run8 , dog_run9 ] {ai_run(32);};
void() dog_run9 =[ $run9 , dog_run10 ] {ai_run(32);};
void() dog_run10 =[ $run10 , dog_run11 ] {ai_run(20);};
void() dog_run11 =[ $run11 , dog_run12 ] {ai_run(64);};
void() dog_run12 =[ $run12 , dog_run1 ] {ai_run(32);};
void() dog_atta1 =[ $attack1, dog_atta2 ] {ai_charge(10);};
void() dog_atta2 =[ $attack2, dog_atta3 ] {ai_charge(10);};
void() dog_atta3 =[ $attack3, dog_atta4 ] {ai_charge(10);};
void() dog_atta4 =[ $attack4, dog_atta5 ] {
sound (self, CHAN_VOICE, "dog/dattack1.wav", 1, ATTN_NORM);
dog_bite();};
void() dog_atta5 =[ $attack5, dog_atta6 ] {ai_charge(10);};
void() dog_atta6 =[ $attack6, dog_atta7 ] {ai_charge(10);};
void() dog_atta7 =[ $attack7, dog_atta8 ] {ai_charge(10);};
void() dog_atta8 =[ $attack8, dog_run1 ] {ai_charge(10);};
void() dog_leap1 =[ $leap1, dog_leap2 ] {ai_face();};
void() dog_leap2 =[ $leap2, dog_leap3 ]
{
ai_face();
self.touch = Dog_JumpTouch;
makevectors (self.angles);
self.origin_z = self.origin_z + 1;
self.velocity = v_forward * 300 + '0 0 200';
if (self.flags & FL_ONGROUND)
self.flags = self.flags - FL_ONGROUND;
};
void() dog_leap3 =[ $leap3, dog_leap4 ] {};
void() dog_leap4 =[ $leap4, dog_leap5 ] {};
void() dog_leap5 =[ $leap5, dog_leap6 ] {};
void() dog_leap6 =[ $leap6, dog_leap7 ] {};
void() dog_leap7 =[ $leap7, dog_leap8 ] {};
void() dog_leap8 =[ $leap8, dog_leap9 ] {};
void() dog_leap9 =[ $leap9, dog_leap9 ] {};
void() dog_pain1 =[ $pain1 , dog_pain2 ] {};
void() dog_pain2 =[ $pain2 , dog_pain3 ] {};
void() dog_pain3 =[ $pain3 , dog_pain4 ] {};
void() dog_pain4 =[ $pain4 , dog_pain5 ] {};
void() dog_pain5 =[ $pain5 , dog_pain6 ] {};
void() dog_pain6 =[ $pain6 , dog_run1 ] {};
void() dog_painb1 =[ $painb1 , dog_painb2 ] {};
void() dog_painb2 =[ $painb2 , dog_painb3 ] {};
void() dog_painb3 =[ $painb3 , dog_painb4 ] {ai_pain(4);};
void() dog_painb4 =[ $painb4 , dog_painb5 ] {ai_pain(12);};
void() dog_painb5 =[ $painb5 , dog_painb6 ] {ai_pain(12);};
void() dog_painb6 =[ $painb6 , dog_painb7 ] {ai_pain(2);};
void() dog_painb7 =[ $painb7 , dog_painb8 ] {};
void() dog_painb8 =[ $painb8 , dog_painb9 ] {ai_pain(4);};
void() dog_painb9 =[ $painb9 , dog_painb10 ] {};
void() dog_painb10 =[ $painb10 , dog_painb11 ] {ai_pain(10);};
void() dog_painb11 =[ $painb11 , dog_painb12 ] {};
void() dog_painb12 =[ $painb12 , dog_painb13 ] {};
void() dog_painb13 =[ $painb13 , dog_painb14 ] {};
void() dog_painb14 =[ $painb14 , dog_painb15 ] {};
void() dog_painb15 =[ $painb15 , dog_painb16 ] {};
void() dog_painb16 =[ $painb16 , dog_run1 ] {};
void(entity attacker, float damage) dog_pain =
{
sound (self, CHAN_VOICE, "dog/dpain1.wav", 1, ATTN_NORM);
if (random() > 0.5)
dog_pain1 ();
else
dog_painb1 ();
};
void() dog_die1 =[ $death1, dog_die2 ] {};
void() dog_die2 =[ $death2, dog_die3 ] {};
void() dog_die3 =[ $death3, dog_die4 ] {};
void() dog_die4 =[ $death4, dog_die5 ] {};
void() dog_die5 =[ $death5, dog_die6 ] {};
void() dog_die6 =[ $death6, dog_die7 ] {};
void() dog_die7 =[ $death7, dog_die8 ] {};
void() dog_die8 =[ $death8, dog_die9 ] {};
void() dog_die9 =[ $death9, dog_die9 ] {};
void() dog_dieb1 =[ $deathb1, dog_dieb2 ] {};
void() dog_dieb2 =[ $deathb2, dog_dieb3 ] {};
void() dog_dieb3 =[ $deathb3, dog_dieb4 ] {};
void() dog_dieb4 =[ $deathb4, dog_dieb5 ] {};
void() dog_dieb5 =[ $deathb5, dog_dieb6 ] {};
void() dog_dieb6 =[ $deathb6, dog_dieb7 ] {};
void() dog_dieb7 =[ $deathb7, dog_dieb8 ] {};
void() dog_dieb8 =[ $deathb8, dog_dieb9 ] {};
void() dog_dieb9 =[ $deathb9, dog_dieb9 ] {};
void(entity inflictor, entity attacker) dog_die =
{
// check for gib
if (self.health < -35)
{
SpawnGib ("progs/gib3.mdl");
SpawnGib ("progs/gib3.mdl");
SpawnGib ("progs/gib4.mdl");
SpawnGib ("progs/gib5.mdl");
SpawnGib ("progs/blood.mdl");
SpawnGib ("progs/blood.mdl");
BecomeGibs ();
return;
}
// regular death
sound (self, CHAN_VOICE, "dog/ddeath.wav", 1, ATTN_NORM);
self.solid = SOLID_NOT;
if (random() < 0.5)
dog_die1 ();
else
dog_dieb1 ();
};
//============================================================================
/*
==============
CheckDogMelee
Returns TRUE if a melee attack would hit right now
==============
*/
float() CheckDogMelee =
{
if (enemy_range == RANGE_MELEE)
{ // FIXME: check canreach
self.attack_state = AS_MELEE;
return TRUE;
}
return FALSE;
};
/*
==============
CheckDogJump
==============
*/
float() CheckDogJump =
{
local vector dist;
local float d;
if (self.origin_z + self.mins_z > self.enemy.origin_z + self.enemy.mins_z
+ 0.75 * self.enemy.size_z)
return FALSE;
if (self.origin_z + self.maxs_z < self.enemy.origin_z + self.enemy.mins_z
+ 0.25 * self.enemy.size_z)
return FALSE;
dist = self.enemy.origin - self.origin;
dist_z = 0;
d = vlen(dist);
if (d < 80)
return FALSE;
if (d > 150)
return FALSE;
return TRUE;
};
float() DogCheckAttack =
{
// if close enough for slashing, go for it
if (CheckDogMelee ())
{
self.attack_state = AS_MELEE;
return TRUE;
}
if (CheckDogJump ())
{
self.attack_state = AS_MISSILE;
return TRUE;
}
return FALSE;
};
//===========================================================================
/*QUAKED monster_dog (1 0 0) (-32 -32 -24) (32 32 40) Ambush
{
model ("progs/dog.mdl");
}
Rottweiler.
*/
void() monster_dog =
{
if (deathmatch)
{
remove(self);
return;
}
precache_model ("progs/dog.mdl");
precache_model ("progs/h_dog.mdl");
precache_sound ("dog/dattack1.wav");
precache_sound ("dog/ddeath.wav");
precache_sound ("dog/dpain1.wav");
precache_sound ("dog/dsight.wav");
precache_sound ("dog/idle.wav");
self.th_stand = dog_stand1;
self.th_walk = dog_walk1;
self.th_run = dog_run1;
self.th_pain = dog_pain;
self.th_die = dog_die;
self.th_melee = dog_atta1;
self.th_missile = dog_leap1;
monster_start("progs/dog.mdl", "progs/h_dog.mdl", 25, 0, '-32 -32 -24', '32 32 40');
};

View File

@@ -0,0 +1,310 @@
$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7
$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 walk9 walk10
$frame walk11 walk12 walk13 walk14 walk15 walk16
$frame run1 run2 run3 run4 run5 run6 run7 run8
$frame attack1 attack2 attack3 attack4 attack5 attack6
$frame attack7 attack8 attack9 attack10
$frame death1 death2 death3 death4 death5 death6 death7 death8
$frame death9 death10 death11 death12 death13 death14
$frame fdeath1 fdeath2 fdeath3 fdeath4 fdeath5 fdeath6 fdeath7 fdeath8
$frame fdeath9 fdeath10 fdeath11
$frame paina1 paina2 paina3 paina4
$frame painb1 painb2 painb3 painb4 painb5
$frame painc1 painc2 painc3 painc4 painc5 painc6 painc7 painc8
$frame paind1 paind2 paind3 paind4 paind5 paind6 paind7 paind8
$frame paind9 paind10 paind11 paind12 paind13 paind14 paind15 paind16
$frame paind17 paind18 paind19
void() Laser_Touch =
{
if (pointcontents(self.origin) == CONTENT_SKY)
{
remove(self);
return;
}
sound (self, CHAN_WEAPON, "enforcer/enfstop.wav", 1, ATTN_STATIC);
if (other.takedamage)
{
if (other.classname == "func_breakable")
SpawnTouchParticles(15, other.colour);
else
SpawnTouchblood(15);
Damage (other, self, self.owner, 15);
}
else
{
vector org = self.origin - 8*normalize(self.velocity);
te_gunshot(org);
}
remove(self);
};
void(vector org, vector vec) LaunchLaser =
{
if (self.classname == "monster_enforcer")
sound (self, CHAN_WEAPON, "enforcer/enfire.wav", 1, ATTN_NORM);
vec = normalize(vec);
newmis = spawn();
newmis.owner = self;
newmis.movetype = MOVETYPE_FLY;
newmis.solid = SOLID_BBOX;
newmis.effects = EF_DIMLIGHT;
setmodel (newmis, "progs/laser.mdl");
setsize (newmis, '0 0 0', '0 0 0');
setorigin (newmis, org);
newmis.velocity = vec * 600;
newmis.angles = vectoangles(newmis.velocity);
newmis.nextthink = time + 5;
newmis.think = SUB_Remove;
newmis.touch = Laser_Touch;
};
void() enforcer_fire =
{
self.effects = self.effects | EF_MUZZLEFLASH;
makevectors (self.angles);
vector org = self.origin + v_forward * 30 + v_right * 8.5 + '0 0 16';
LaunchLaser(org, self.enemy.origin - self.origin);
};
void() enf_stand1 =[ $stand1, enf_stand2 ] {ai_stand();};
void() enf_stand2 =[ $stand2, enf_stand3 ] {ai_stand();};
void() enf_stand3 =[ $stand3, enf_stand4 ] {ai_stand();};
void() enf_stand4 =[ $stand4, enf_stand5 ] {ai_stand();};
void() enf_stand5 =[ $stand5, enf_stand6 ] {ai_stand();};
void() enf_stand6 =[ $stand6, enf_stand7 ] {ai_stand();};
void() enf_stand7 =[ $stand7, enf_stand1 ] {ai_stand();};
void() enf_walk1 =[ $walk1 , enf_walk2 ]
{
if (random() < 0.2)
sound (self, CHAN_VOICE, "enforcer/idle1.wav", 1, ATTN_IDLE);
ai_walk(2);
};
void() enf_walk2 =[ $walk2 , enf_walk3 ] {ai_walk(4);};
void() enf_walk3 =[ $walk3 , enf_walk4 ] {ai_walk(4);};
void() enf_walk4 =[ $walk4 , enf_walk5 ] {ai_walk(3);};
void() enf_walk5 =[ $walk5 , enf_walk6 ] {ai_walk(1);};
void() enf_walk6 =[ $walk6 , enf_walk7 ] {ai_walk(2);};
void() enf_walk7 =[ $walk7 , enf_walk8 ] {ai_walk(2);};
void() enf_walk8 =[ $walk8 , enf_walk9 ] {ai_walk(1);};
void() enf_walk9 =[ $walk9 , enf_walk10 ] {ai_walk(2);};
void() enf_walk10 =[ $walk10, enf_walk11 ] {ai_walk(4);};
void() enf_walk11 =[ $walk11, enf_walk12 ] {ai_walk(4);};
void() enf_walk12 =[ $walk12, enf_walk13 ] {ai_walk(1);};
void() enf_walk13 =[ $walk13, enf_walk14 ] {ai_walk(2);};
void() enf_walk14 =[ $walk14, enf_walk15 ] {ai_walk(3);};
void() enf_walk15 =[ $walk15, enf_walk16 ] {ai_walk(4);};
void() enf_walk16 =[ $walk16, enf_walk1 ] {ai_walk(2);};
void() enf_run1 =[ $run1 , enf_run2 ]
{
if (random() < 0.2)
sound (self, CHAN_VOICE, "enforcer/idle1.wav", 1, ATTN_IDLE);
ai_run(18);
};
void() enf_run2 =[ $run2 , enf_run3 ] {ai_run(14);};
void() enf_run3 =[ $run3 , enf_run4 ] {ai_run(7);};
void() enf_run4 =[ $run4 , enf_run5 ] {ai_run(12);};
void() enf_run5 =[ $run5 , enf_run6 ] {ai_run(14);};
void() enf_run6 =[ $run6 , enf_run7 ] {ai_run(14);};
void() enf_run7 =[ $run7 , enf_run8 ] {ai_run(7);};
void() enf_run8 =[ $run8 , enf_run1 ] {ai_run(11);};
void() enf_atk1 =[ $attack1, enf_atk2 ] {ai_face();};
void() enf_atk2 =[ $attack2, enf_atk3 ] {ai_face();};
void() enf_atk3 =[ $attack3, enf_atk4 ] {ai_face();};
void() enf_atk4 =[ $attack4, enf_atk5 ] {ai_face();};
void() enf_atk5 =[ $attack5, enf_atk6 ] {ai_face();};
void() enf_atk6 =[ $attack6, enf_atk7 ] {enforcer_fire();};
void() enf_atk7 =[ $attack7, enf_atk8 ] {ai_face();};
void() enf_atk8 =[ $attack8, enf_atk9 ] {ai_face();};
void() enf_atk9 =[ $attack9, enf_atk10 ] {ai_face();};
void() enf_atk10 =[ $attack10, enf_run1 ] {ai_face();if(visible(self.enemy)) if (FacingIdeal(30)) enf_atk4();};
void() enf_paina1 =[ $paina1, enf_paina2 ] {};
void() enf_paina2 =[ $paina2, enf_paina3 ] {};
void() enf_paina3 =[ $paina3, enf_paina4 ] {};
void() enf_paina4 =[ $paina4, enf_run1 ] {};
void() enf_painb1 =[ $painb1, enf_painb2 ] {};
void() enf_painb2 =[ $painb2, enf_painb3 ] {};
void() enf_painb3 =[ $painb3, enf_painb4 ] {};
void() enf_painb4 =[ $painb4, enf_painb5 ] {};
void() enf_painb5 =[ $painb5, enf_run1 ] {};
void() enf_painc1 =[ $painc1, enf_painc2 ] {};
void() enf_painc2 =[ $painc2, enf_painc3 ] {};
void() enf_painc3 =[ $painc3, enf_painc4 ] {};
void() enf_painc4 =[ $painc4, enf_painc5 ] {};
void() enf_painc5 =[ $painc5, enf_painc6 ] {};
void() enf_painc6 =[ $painc6, enf_painc7 ] {};
void() enf_painc7 =[ $painc7, enf_painc8 ] {};
void() enf_painc8 =[ $painc8, enf_run1 ] {};
void() enf_paind1 =[ $paind1, enf_paind2 ] {};
void() enf_paind2 =[ $paind2, enf_paind3 ] {};
void() enf_paind3 =[ $paind3, enf_paind4 ] {};
void() enf_paind4 =[ $paind4, enf_paind5 ] {ai_painforward(2);};
void() enf_paind5 =[ $paind5, enf_paind6 ] {ai_painforward(1);};
void() enf_paind6 =[ $paind6, enf_paind7 ] {};
void() enf_paind7 =[ $paind7, enf_paind8 ] {};
void() enf_paind8 =[ $paind8, enf_paind9 ] {};
void() enf_paind9 =[ $paind9, enf_paind10 ] {};
void() enf_paind10 =[ $paind10, enf_paind11 ] {};
void() enf_paind11 =[ $paind11, enf_paind12 ] {ai_painforward(1);};
void() enf_paind12 =[ $paind12, enf_paind13 ] {ai_painforward(1);};
void() enf_paind13 =[ $paind13, enf_paind14 ] {ai_painforward(1);};
void() enf_paind14 =[ $paind14, enf_paind15 ] {};
void() enf_paind15 =[ $paind15, enf_paind16 ] {};
void() enf_paind16 =[ $paind16, enf_paind17 ] {ai_pain(1);};
void() enf_paind17 =[ $paind17, enf_paind18 ] {ai_pain(1);};
void() enf_paind18 =[ $paind18, enf_paind19 ] {};
void() enf_paind19 =[ $paind19, enf_run1 ] {};
void(entity attacker, float damage) enf_pain =
{
if (self.pain_finished > time)
return;
float r = random();
if (r < 0.5)
sound (self, CHAN_VOICE, "enforcer/pain1.wav", 1, ATTN_NORM);
else
sound (self, CHAN_VOICE, "enforcer/pain2.wav", 1, ATTN_NORM);
r = random();
if (r < 0.2)
{
self.pain_finished = time + 1;
enf_paina1 ();
}
else if (r < 0.4)
{
self.pain_finished = time + 1;
enf_painb1 ();
}
else if (r < 0.7)
{
self.pain_finished = time + 1;
enf_painc1 ();
}
else
{
self.pain_finished = time + 2;
enf_paind1 ();
}
};
void() enf_die1 =[ $death1, enf_die2 ] {};
void() enf_die2 =[ $death2, enf_die3 ] {};
void() enf_die3 =[ $death3, enf_die4 ]
{self.solid = SOLID_NOT;self.ammo_cells = 5;DropBackpack();};
void() enf_die4 =[ $death4, enf_die5 ] {ai_forward(14);};
void() enf_die5 =[ $death5, enf_die6 ] {ai_forward(2);};
void() enf_die6 =[ $death6, enf_die7 ] {};
void() enf_die7 =[ $death7, enf_die8 ] {};
void() enf_die8 =[ $death8, enf_die9 ] {};
void() enf_die9 =[ $death9, enf_die10 ] {ai_forward(3);};
void() enf_die10 =[ $death10, enf_die11 ] {ai_forward(5);};
void() enf_die11 =[ $death11, enf_die12 ] {ai_forward(5);};
void() enf_die12 =[ $death12, enf_die13 ] {ai_forward(5);};
void() enf_die13 =[ $death13, enf_die14 ] {};
void() enf_die14 =[ $death14, enf_die14 ] {};
void() enf_fdie1 =[ $fdeath1, enf_fdie2 ] {};
void() enf_fdie2 =[ $fdeath2, enf_fdie3 ] {};
void() enf_fdie3 =[ $fdeath3, enf_fdie4 ] {DropBackpack();};
void() enf_fdie4 =[ $fdeath4, enf_fdie5 ] {};
void() enf_fdie5 =[ $fdeath5, enf_fdie6 ] {};
void() enf_fdie6 =[ $fdeath6, enf_fdie7 ] {};
void() enf_fdie7 =[ $fdeath7, enf_fdie8 ] {};
void() enf_fdie8 =[ $fdeath8, enf_fdie9 ] {};
void() enf_fdie9 =[ $fdeath9, enf_fdie10 ] {};
void() enf_fdie10 =[ $fdeath10, enf_fdie11 ] {};
void() enf_fdie11 =[ $fdeath11, enf_fdie11 ] {};
void(entity inflictor, entity attacker) enf_die =
{
// check for gib
if (self.health < -35)
{
SpawnGib("progs/gib1.mdl");
SpawnGib("progs/gib2.mdl");
SpawnGib("progs/gib3.mdl");
SpawnGib("progs/gib4.mdl");
SpawnGib("progs/gib5.mdl");
SpawnGib("progs/blood.mdl");
SpawnGib("progs/blood.mdl");
BecomeGibs();
return;
}
// regular death
sound (self, CHAN_VOICE, "enforcer/death1.wav", 1, ATTN_NORM);
self.solid = SOLID_NOT;
if (random() > 0.5)
enf_die1 ();
else
enf_fdie1 ();
};
/*QUAKED monster_enforcer (1 0 0) (-16 -16 -24) (16 16 40) AMBUSH
{
model ("progs/enforcer.mdl");
}
Enforcer.
Grunt, Mark Two. Grunts who are surlier and beefier than the rest get outfitted in combat armor and built-in blasters.
*/
void() monster_enforcer =
{
if (deathmatch)
{
remove(self);
return;
}
precache_model2 ("progs/enforcer.mdl");
precache_model2 ("progs/h_mega.mdl");
precache_model2 ("progs/laser.mdl");
precache_sound2 ("enforcer/death1.wav");
precache_sound2 ("enforcer/enfire.wav");
precache_sound2 ("enforcer/enfstop.wav");
precache_sound2 ("enforcer/idle1.wav");
precache_sound2 ("enforcer/pain1.wav");
precache_sound2 ("enforcer/pain2.wav");
precache_sound2 ("enforcer/sight1.wav");
precache_sound2 ("enforcer/sight2.wav");
precache_sound2 ("enforcer/sight3.wav");
precache_sound2 ("enforcer/sight4.wav");
self.th_stand = enf_stand1;
self.th_walk = enf_walk1;
self.th_run = enf_run1;
self.th_pain = enf_pain;
self.th_die = enf_die;
self.th_missile = enf_atk1;
self.ammo_cells = 5;
monster_start("progs/enforcer.mdl", "progs/h_mega.mdl", 80, 0, '-16 -16 -24', '16 16 40');
};

View File

@@ -0,0 +1,181 @@
$cd id1/models/fish
$origin 0 0 24
$base base
$skin skin
$frame attack1 attack2 attack3 attack4 attack5 attack6
$frame attack7 attack8 attack9 attack10 attack11 attack12 attack13
$frame attack14 attack15 attack16 attack17 attack18
$frame death1 death2 death3 death4 death5 death6 death7
$frame death8 death9 death10 death11 death12 death13 death14 death15
$frame death16 death17 death18 death19 death20 death21
$frame swim1 swim2 swim3 swim4 swim5 swim6 swim7 swim8
$frame swim9 swim10 swim11 swim12 swim13 swim14 swim15 swim16 swim17
$frame swim18
$frame pain1 pain2 pain3 pain4 pain5 pain6 pain7 pain8
$frame pain9
void() f_stand1 =[ $swim1, f_stand2 ] {ai_stand();};
void() f_stand2 =[ $swim2, f_stand3 ] {ai_stand();};
void() f_stand3 =[ $swim3, f_stand4 ] {ai_stand();};
void() f_stand4 =[ $swim4, f_stand5 ] {ai_stand();};
void() f_stand5 =[ $swim5, f_stand6 ] {ai_stand();};
void() f_stand6 =[ $swim6, f_stand7 ] {ai_stand();};
void() f_stand7 =[ $swim7, f_stand8 ] {ai_stand();};
void() f_stand8 =[ $swim8, f_stand9 ] {ai_stand();};
void() f_stand9 =[ $swim9, f_stand10 ] {ai_stand();};
void() f_stand10 =[ $swim10, f_stand11 ] {ai_stand();};
void() f_stand11 =[ $swim11, f_stand12 ] {ai_stand();};
void() f_stand12 =[ $swim12, f_stand13 ] {ai_stand();};
void() f_stand13 =[ $swim13, f_stand14 ] {ai_stand();};
void() f_stand14 =[ $swim14, f_stand15 ] {ai_stand();};
void() f_stand15 =[ $swim15, f_stand16 ] {ai_stand();};
void() f_stand16 =[ $swim16, f_stand17 ] {ai_stand();};
void() f_stand17 =[ $swim17, f_stand18 ] {ai_stand();};
void() f_stand18 =[ $swim18, f_stand1 ] {ai_stand();};
void() f_walk1 =[ $swim1, f_walk2 ] {ai_walk(8);};
void() f_walk2 =[ $swim2, f_walk3 ] {ai_walk(8);};
void() f_walk3 =[ $swim3, f_walk4 ] {ai_walk(8);};
void() f_walk4 =[ $swim4, f_walk5 ] {ai_walk(8);};
void() f_walk5 =[ $swim5, f_walk6 ] {ai_walk(8);};
void() f_walk6 =[ $swim6, f_walk7 ] {ai_walk(8);};
void() f_walk7 =[ $swim7, f_walk8 ] {ai_walk(8);};
void() f_walk8 =[ $swim8, f_walk9 ] {ai_walk(8);};
void() f_walk9 =[ $swim9, f_walk10 ] {ai_walk(8);};
void() f_walk10 =[ $swim10, f_walk11 ] {ai_walk(8);};
void() f_walk11 =[ $swim11, f_walk12 ] {ai_walk(8);};
void() f_walk12 =[ $swim12, f_walk13 ] {ai_walk(8);};
void() f_walk13 =[ $swim13, f_walk14 ] {ai_walk(8);};
void() f_walk14 =[ $swim14, f_walk15 ] {ai_walk(8);};
void() f_walk15 =[ $swim15, f_walk16 ] {ai_walk(8);};
void() f_walk16 =[ $swim16, f_walk17 ] {ai_walk(8);};
void() f_walk17 =[ $swim17, f_walk18 ] {ai_walk(8);};
void() f_walk18 =[ $swim18, f_walk1 ] {ai_walk(8);};
void() f_run1 =[ $swim1, f_run2 ] {ai_run(12);
if (random() < 0.5)
sound (self, CHAN_VOICE, "fish/idle.wav", 1, ATTN_NORM);
};
void() f_run2 =[ $swim3, f_run3 ] {ai_run(12);};
void() f_run3 =[ $swim5, f_run4 ] {ai_run(12);};
void() f_run4 =[ $swim7, f_run5 ] {ai_run(12);};
void() f_run5 =[ $swim9, f_run6 ] {ai_run(12);};
void() f_run6 =[ $swim11, f_run7 ] {ai_run(12);};
void() f_run7 =[ $swim13, f_run8 ] {ai_run(12);};
void() f_run8 =[ $swim15, f_run9 ] {ai_run(12);};
void() f_run9 =[ $swim17, f_run1 ] {ai_run(12);};
void() fish_melee =
{
local vector delta;
local float ldmg;
if (!self.enemy)
return; // removed before stroke
delta = self.enemy.origin - self.origin;
if (vlen(delta) > 60)
return;
sound (self, CHAN_VOICE, "fish/bite.wav", 1, ATTN_NORM);
ldmg = (random() + random()) * 3;
Damage (self.enemy, self, self, ldmg);
};
void() f_attack1 =[ $attack1, f_attack2 ] {ai_charge(10);};
void() f_attack2 =[ $attack2, f_attack3 ] {ai_charge(10);};
void() f_attack3 =[ $attack3, f_attack4 ] {fish_melee();};
void() f_attack4 =[ $attack4, f_attack5 ] {ai_charge(10);};
void() f_attack5 =[ $attack5, f_attack6 ] {ai_charge(10);};
void() f_attack6 =[ $attack6, f_attack7 ] {ai_charge(10);};
void() f_attack7 =[ $attack7, f_attack8 ] {ai_charge(10);};
void() f_attack8 =[ $attack8, f_attack9 ] {ai_charge(10);};
void() f_attack9 =[ $attack9, f_attack10] {fish_melee();};
void() f_attack10 =[ $attack10, f_attack11] {ai_charge(10);};
void() f_attack11 =[ $attack11, f_attack12] {ai_charge(10);};
void() f_attack12 =[ $attack12, f_attack13] {ai_charge(10);};
void() f_attack13 =[ $attack13, f_attack14] {ai_charge(10);};
void() f_attack14 =[ $attack14, f_attack15] {ai_charge(10);};
void() f_attack15 =[ $attack15, f_attack16] {fish_melee();};
void() f_attack16 =[ $attack16, f_attack17] {ai_charge(10);};
void() f_attack17 =[ $attack17, f_attack18] {ai_charge(10);};
void() f_attack18 =[ $attack18, f_run1 ] {ai_charge(10);};
void() f_death1 =[ $death1, f_death2 ] {sound (self, CHAN_VOICE, "fish/death.wav", 1, ATTN_NORM);};
void() f_death2 =[ $death2, f_death3 ] {};
void() f_death3 =[ $death3, f_death4 ] {};
void() f_death4 =[ $death4, f_death5 ] {};
void() f_death5 =[ $death5, f_death6 ] {};
void() f_death6 =[ $death6, f_death7 ] {};
void() f_death7 =[ $death7, f_death8 ] {};
void() f_death8 =[ $death8, f_death9 ] {};
void() f_death9 =[ $death9, f_death10 ] {};
void() f_death10 =[ $death10, f_death11 ] {};
void() f_death11 =[ $death11, f_death12 ] {};
void() f_death12 =[ $death12, f_death13 ] {};
void() f_death13 =[ $death13, f_death14 ] {};
void() f_death14 =[ $death14, f_death15 ] {};
void() f_death15 =[ $death15, f_death16 ] {};
void() f_death16 =[ $death16, f_death17 ] {};
void() f_death17 =[ $death17, f_death18 ] {};
void() f_death18 =[ $death18, f_death19 ] {};
void() f_death19 =[ $death19, f_death20 ] {};
void() f_death20 =[ $death20, f_death21 ] {};
void() f_death21 =[ $death21, f_death21 ] {};
void(entity inflictor, entity attacker) f_death =
{
self.solid = SOLID_NOT;
f_death1();
};
void() f_pain1 =[ $pain1, f_pain2 ] {};
void() f_pain2 =[ $pain2, f_pain3 ] {ai_pain(6);};
void() f_pain3 =[ $pain3, f_pain4 ] {ai_pain(6);};
void() f_pain4 =[ $pain4, f_pain5 ] {ai_pain(6);};
void() f_pain5 =[ $pain5, f_pain6 ] {ai_pain(6);};
void() f_pain6 =[ $pain6, f_pain7 ] {ai_pain(6);};
void() f_pain7 =[ $pain7, f_pain8 ] {ai_pain(6);};
void() f_pain8 =[ $pain8, f_pain9 ] {ai_pain(6);};
void() f_pain9 =[ $pain9, f_run1 ] {ai_pain(6);};
void(entity attacker, float damage) fish_pain =
{
// fish allways do pain frames
f_pain1 ();
};
/*QUAKED monster_fish (1 0 0) (-16 -16 -24) (16 16 24) Ambush
{
model ("progs/fish.mdl");
}
Rotfish.
*/
void() monster_fish =
{
if (deathmatch)
{
remove(self);
return;
}
precache_model2 ("progs/fish.mdl");
precache_sound2 ("fish/death.wav");
precache_sound2 ("fish/bite.wav");
precache_sound2 ("fish/idle.wav");
self.th_stand = f_stand1;
self.th_walk = f_walk1;
self.th_run = f_run1;
self.th_die = f_death;
self.th_pain = fish_pain;
self.th_melee = f_attack1;
monster_start("progs/fish.mdl", "progs/gib3.mdl", 25, FL_SWIM, '-16 -16 -24', '16 16 24');
};

View File

@@ -0,0 +1,426 @@
$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9
$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 walk9
$frame walk10 walk11 walk12 walk13 walk14 walk15 walk16 walk17
$frame walk18 walk19 walk20
$frame run1 run2 run3 run4 run5 run6 run7 run8
$frame pain1 pain2 pain3 pain4 pain5
$frame death1 death2 death3 death4 death5 death6 death7 death8
$frame death9 death10 death11 death12
$frame deathb1 deathb2 deathb3 deathb4 deathb5 deathb6 deathb7 deathb8
$frame deathb9
$frame char_a1 char_a2 char_a3 char_a4 char_a5 char_a6 char_a7 char_a8
$frame char_a9 char_a10 char_a11 char_a12 char_a13 char_a14 char_a15 char_a16
$frame magica1 magica2 magica3 magica4 magica5 magica6 magica7 magica8
$frame magica9 magica10 magica11 magica12 magica13 magica14
$frame magicb1 magicb2 magicb3 magicb4 magicb5 magicb6 magicb7 magicb8
$frame magicb9 magicb10 magicb11 magicb12 magicb13
$frame char_b1 char_b2 char_b3 char_b4 char_b5 char_b6
$frame slice1 slice2 slice3 slice4 slice5 slice6 slice7 slice8 slice9 slice10
$frame smash1 smash2 smash3 smash4 smash5 smash6 smash7 smash8 smash9 smash10
$frame smash11
$frame w_attack1 w_attack2 w_attack3 w_attack4 w_attack5 w_attack6 w_attack7
$frame w_attack8 w_attack9 w_attack10 w_attack11 w_attack12 w_attack13 w_attack14
$frame w_attack15 w_attack16 w_attack17 w_attack18 w_attack19 w_attack20
$frame w_attack21 w_attack22
$frame magicc1 magicc2 magicc3 magicc4 magicc5 magicc6 magicc7 magicc8
$frame magicc9 magicc10 magicc11
void() hknight_char_a1;
void() hknight_run1;
void() hk_idle_sound;
void(float offset) hknight_shot =
{
local vector offang;
local vector org, vec;
offang = vectoangles (self.enemy.origin - self.origin);
offang_y = offang_y + offset * 6;
makevectors (offang);
org = self.origin + self.mins + self.size*0.5 + v_forward * 20;
// set missile speed
vec = normalize (v_forward);
vec_z = 0 - vec_z + (random() - 0.5)*0.1;
launch_spike (org, vec);
newmis.classname = "knightspike";
setmodel (newmis, "progs/k_spike.mdl");
setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
newmis.velocity = vec*300;
sound (self, CHAN_WEAPON, "hknight/attack1.wav", 1, ATTN_NORM);
};
void() CheckForCharge =
{
// check for mad charge
if (!enemy_vis)
return;
if (time < self.attack_finished)
return;
if ( fabs(self.origin_z - self.enemy.origin_z) > 20)
return; // too much height change
if ( vlen (self.origin - self.enemy.origin) < 80)
return; // use regular attack
// charge
SUB_AttackFinished (2);
hknight_char_a1 ();
};
void() CheckContinueCharge =
{
if (time > self.attack_finished)
{
SUB_AttackFinished (3);
hknight_run1 ();
return; // done charging
}
if (random() > 0.5)
sound (self, CHAN_WEAPON, "knight/sword2.wav", 1, ATTN_NORM);
else
sound (self, CHAN_WEAPON, "knight/sword1.wav", 1, ATTN_NORM);
};
//===========================================================================
void() hknight_stand1 =[ $stand1, hknight_stand2 ] {ai_stand();};
void() hknight_stand2 =[ $stand2, hknight_stand3 ] {ai_stand();};
void() hknight_stand3 =[ $stand3, hknight_stand4 ] {ai_stand();};
void() hknight_stand4 =[ $stand4, hknight_stand5 ] {ai_stand();};
void() hknight_stand5 =[ $stand5, hknight_stand6 ] {ai_stand();};
void() hknight_stand6 =[ $stand6, hknight_stand7 ] {ai_stand();};
void() hknight_stand7 =[ $stand7, hknight_stand8 ] {ai_stand();};
void() hknight_stand8 =[ $stand8, hknight_stand9 ] {ai_stand();};
void() hknight_stand9 =[ $stand9, hknight_stand1 ] {ai_stand();};
//===========================================================================
void() hknight_walk1 =[ $walk1, hknight_walk2 ] {
hk_idle_sound();
ai_walk(2);};
void() hknight_walk2 =[ $walk2, hknight_walk3 ] {ai_walk(5);};
void() hknight_walk3 =[ $walk3, hknight_walk4 ] {ai_walk(5);};
void() hknight_walk4 =[ $walk4, hknight_walk5 ] {ai_walk(4);};
void() hknight_walk5 =[ $walk5, hknight_walk6 ] {ai_walk(4);};
void() hknight_walk6 =[ $walk6, hknight_walk7 ] {ai_walk(2);};
void() hknight_walk7 =[ $walk7, hknight_walk8 ] {ai_walk(2);};
void() hknight_walk8 =[ $walk8, hknight_walk9 ] {ai_walk(3);};
void() hknight_walk9 =[ $walk9, hknight_walk10 ] {ai_walk(3);};
void() hknight_walk10 =[ $walk10, hknight_walk11 ] {ai_walk(4);};
void() hknight_walk11 =[ $walk11, hknight_walk12 ] {ai_walk(3);};
void() hknight_walk12 =[ $walk12, hknight_walk13 ] {ai_walk(4);};
void() hknight_walk13 =[ $walk13, hknight_walk14 ] {ai_walk(6);};
void() hknight_walk14 =[ $walk14, hknight_walk15 ] {ai_walk(2);};
void() hknight_walk15 =[ $walk15, hknight_walk16 ] {ai_walk(2);};
void() hknight_walk16 =[ $walk16, hknight_walk17 ] {ai_walk(4);};
void() hknight_walk17 =[ $walk17, hknight_walk18 ] {ai_walk(3);};
void() hknight_walk18 =[ $walk18, hknight_walk19 ] {ai_walk(3);};
void() hknight_walk19 =[ $walk19, hknight_walk20 ] {ai_walk(3);};
void() hknight_walk20 =[ $walk20, hknight_walk1 ] {ai_walk(2);};
//===========================================================================
void() hknight_run1 =[ $run1, hknight_run2 ] {
hk_idle_sound();
ai_run (20); CheckForCharge (); };
void() hknight_run2 =[ $run2, hknight_run3 ] {ai_run(25);};
void() hknight_run3 =[ $run3, hknight_run4 ] {ai_run(18);};
void() hknight_run4 =[ $run4, hknight_run5 ] {ai_run(16);};
void() hknight_run5 =[ $run5, hknight_run6 ] {ai_run(14);};
void() hknight_run6 =[ $run6, hknight_run7 ] {ai_run(25);};
void() hknight_run7 =[ $run7, hknight_run8 ] {ai_run(21);};
void() hknight_run8 =[ $run8, hknight_run1 ] {ai_run(13);};
//============================================================================
void() hknight_pain1 =[ $pain1, hknight_pain2 ] {sound (self, CHAN_VOICE, "hknight/pain1.wav", 1, ATTN_NORM);};
void() hknight_pain2 =[ $pain2, hknight_pain3 ] {};
void() hknight_pain3 =[ $pain3, hknight_pain4 ] {};
void() hknight_pain4 =[ $pain4, hknight_pain5 ] {};
void() hknight_pain5 =[ $pain5, hknight_run1 ] {};
//============================================================================
void() hknight_die1 =[ $death1, hknight_die2 ] {ai_forward(10);};
void() hknight_die2 =[ $death2, hknight_die3 ] {ai_forward(8);};
void() hknight_die3 =[ $death3, hknight_die4 ] {ai_forward(7);};
void() hknight_die4 =[ $death4, hknight_die5 ] {};
void() hknight_die5 =[ $death5, hknight_die6 ] {};
void() hknight_die6 =[ $death6, hknight_die7 ] {};
void() hknight_die7 =[ $death7, hknight_die8 ] {};
void() hknight_die8 =[ $death8, hknight_die9 ] {ai_forward(10);};
void() hknight_die9 =[ $death9, hknight_die10 ] {ai_forward(11);};
void() hknight_die10 =[ $death10, hknight_die11 ] {};
void() hknight_die11 =[ $death11, hknight_die12 ] {};
void() hknight_die12 =[ $death12, hknight_die12 ] {};
void() hknight_dieb1 =[ $deathb1, hknight_dieb2 ] {};
void() hknight_dieb2 =[ $deathb2, hknight_dieb3 ] {};
void() hknight_dieb3 =[ $deathb3, hknight_dieb4 ] {};
void() hknight_dieb4 =[ $deathb4, hknight_dieb5 ] {};
void() hknight_dieb5 =[ $deathb5, hknight_dieb6 ] {};
void() hknight_dieb6 =[ $deathb6, hknight_dieb7 ] {};
void() hknight_dieb7 =[ $deathb7, hknight_dieb8 ] {};
void() hknight_dieb8 =[ $deathb8, hknight_dieb9 ] {};
void() hknight_dieb9 =[ $deathb9, hknight_dieb9 ] {};
void(entity inflictor, entity attacker) hknight_die =
{
// check for gib
if (self.health < -40)
{
SpawnGib("progs/gib1.mdl");
SpawnGib("progs/gib2.mdl");
SpawnGib("progs/gib3.mdl");
SpawnGib("progs/gib4.mdl");
SpawnGib("progs/gib5.mdl");
SpawnGib("progs/blood.mdl");
SpawnGib("progs/blood.mdl");
BecomeGibs();
return;
}
// regular death
sound (self, CHAN_VOICE, "hknight/death1.wav", 1, ATTN_NORM);
self.solid = SOLID_NOT;
if (random() > 0.5)
hknight_die1();
else
hknight_dieb1();
};
//============================================================================
void() hknight_magica1 =[ $magica1, hknight_magica2 ] {ai_face();};
void() hknight_magica2 =[ $magica2, hknight_magica3 ] {ai_face();};
void() hknight_magica3 =[ $magica3, hknight_magica4 ] {ai_face();};
void() hknight_magica4 =[ $magica4, hknight_magica5 ] {ai_face();};
void() hknight_magica5 =[ $magica5, hknight_magica6 ] {ai_face();};
void() hknight_magica6 =[ $magica6, hknight_magica7 ] {ai_face();};
void() hknight_magica7 =[ $magica7, hknight_magica8 ] {hknight_shot(-2);};
void() hknight_magica8 =[ $magica8, hknight_magica9 ] {hknight_shot(-1);};
void() hknight_magica9 =[ $magica9, hknight_magica10] {hknight_shot(0);};
void() hknight_magica10 =[ $magica10, hknight_magica11] {hknight_shot(1);};
void() hknight_magica11 =[ $magica11, hknight_magica12] {hknight_shot(2);};
void() hknight_magica12 =[ $magica12, hknight_magica13] {hknight_shot(3);};
void() hknight_magica13 =[ $magica13, hknight_magica14] {ai_face();};
void() hknight_magica14 =[ $magica14, hknight_run1 ] {ai_face();};
//============================================================================
void() hknight_magicb1 =[ $magicb1, hknight_magicb2 ] {ai_face();};
void() hknight_magicb2 =[ $magicb2, hknight_magicb3 ] {ai_face();};
void() hknight_magicb3 =[ $magicb3, hknight_magicb4 ] {ai_face();};
void() hknight_magicb4 =[ $magicb4, hknight_magicb5 ] {ai_face();};
void() hknight_magicb5 =[ $magicb5, hknight_magicb6 ] {ai_face();};
void() hknight_magicb6 =[ $magicb6, hknight_magicb7 ] {ai_face();};
void() hknight_magicb7 =[ $magicb7, hknight_magicb8 ] {hknight_shot(-2);};
void() hknight_magicb8 =[ $magicb8, hknight_magicb9 ] {hknight_shot(-1);};
void() hknight_magicb9 =[ $magicb9, hknight_magicb10] {hknight_shot(0);};
void() hknight_magicb10 =[ $magicb10, hknight_magicb11] {hknight_shot(1);};
void() hknight_magicb11 =[ $magicb11, hknight_magicb12] {hknight_shot(2);};
void() hknight_magicb12 =[ $magicb12, hknight_magicb13] {hknight_shot(3);};
void() hknight_magicb13 =[ $magicb13, hknight_run1] {ai_face();};
//============================================================================
void() hknight_magicc1 =[ $magicc1, hknight_magicc2 ] {ai_face();};
void() hknight_magicc2 =[ $magicc2, hknight_magicc3 ] {ai_face();};
void() hknight_magicc3 =[ $magicc3, hknight_magicc4 ] {ai_face();};
void() hknight_magicc4 =[ $magicc4, hknight_magicc5 ] {ai_face();};
void() hknight_magicc5 =[ $magicc5, hknight_magicc6 ] {ai_face();};
void() hknight_magicc6 =[ $magicc6, hknight_magicc7 ] {hknight_shot(-2);};
void() hknight_magicc7 =[ $magicc7, hknight_magicc8 ] {hknight_shot(-1);};
void() hknight_magicc8 =[ $magicc8, hknight_magicc9 ] {hknight_shot(0);};
void() hknight_magicc9 =[ $magicc9, hknight_magicc10] {hknight_shot(1);};
void() hknight_magicc10 =[ $magicc10, hknight_magicc11] {hknight_shot(2);};
void() hknight_magicc11 =[ $magicc11, hknight_run1] {hknight_shot(3);};
//===========================================================================
void() hknight_char_a1 =[ $char_a1, hknight_char_a2 ] {ai_charge(20);};
void() hknight_char_a2 =[ $char_a2, hknight_char_a3 ] {ai_charge(25);};
void() hknight_char_a3 =[ $char_a3, hknight_char_a4 ] {ai_charge(18);};
void() hknight_char_a4 =[ $char_a4, hknight_char_a5 ] {ai_charge(16);};
void() hknight_char_a5 =[ $char_a5, hknight_char_a6 ] {ai_charge(14);};
void() hknight_char_a6 =[ $char_a6, hknight_char_a7 ] {ai_charge(20); ai_melee();};
void() hknight_char_a7 =[ $char_a7, hknight_char_a8 ] {ai_charge(21); ai_melee();};
void() hknight_char_a8 =[ $char_a8, hknight_char_a9 ] {ai_charge(13); ai_melee();};
void() hknight_char_a9 =[ $char_a9, hknight_char_a10 ] {ai_charge(20); ai_melee();};
void() hknight_char_a10=[ $char_a10, hknight_char_a11 ] {ai_charge(20); ai_melee();};
void() hknight_char_a11=[ $char_a11, hknight_char_a12 ] {ai_charge(18); ai_melee();};
void() hknight_char_a12=[ $char_a12, hknight_char_a13 ] {ai_charge(16);};
void() hknight_char_a13=[ $char_a13, hknight_char_a14 ] {ai_charge(14);};
void() hknight_char_a14=[ $char_a14, hknight_char_a15 ] {ai_charge(25);};
void() hknight_char_a15=[ $char_a15, hknight_char_a16 ] {ai_charge(21);};
void() hknight_char_a16=[ $char_a16, hknight_run1 ] {ai_charge(13);};
//===========================================================================
void() hknight_char_b1 =[ $char_b1, hknight_char_b2 ]
{CheckContinueCharge (); ai_charge(23); ai_melee();};
void() hknight_char_b2 =[ $char_b2, hknight_char_b3 ] {ai_charge(17); ai_melee();};
void() hknight_char_b3 =[ $char_b3, hknight_char_b4 ] {ai_charge(12); ai_melee();};
void() hknight_char_b4 =[ $char_b4, hknight_char_b5 ] {ai_charge(22); ai_melee();};
void() hknight_char_b5 =[ $char_b5, hknight_char_b6 ] {ai_charge(18); ai_melee();};
void() hknight_char_b6 =[ $char_b6, hknight_char_b1 ] {ai_charge(8); ai_melee();};
//===========================================================================
void() hknight_slice1 =[ $slice1, hknight_slice2 ] {ai_charge(9);};
void() hknight_slice2 =[ $slice2, hknight_slice3 ] {ai_charge(6);};
void() hknight_slice3 =[ $slice3, hknight_slice4 ] {ai_charge(13);};
void() hknight_slice4 =[ $slice4, hknight_slice5 ] {ai_charge(4);};
void() hknight_slice5 =[ $slice5, hknight_slice6 ] {ai_charge(7); ai_melee();};
void() hknight_slice6 =[ $slice6, hknight_slice7 ] {ai_charge(15); ai_melee();};
void() hknight_slice7 =[ $slice7, hknight_slice8 ] {ai_charge(8); ai_melee();};
void() hknight_slice8 =[ $slice8, hknight_slice9 ] {ai_charge(2); ai_melee();};
void() hknight_slice9 =[ $slice9, hknight_slice10 ] {ai_melee();};
void() hknight_slice10 =[ $slice10, hknight_run1 ] {ai_charge(3);};
//===========================================================================
void() hknight_smash1 =[ $smash1, hknight_smash2 ] {ai_charge(1);};
void() hknight_smash2 =[ $smash2, hknight_smash3 ] {ai_charge(13);};
void() hknight_smash3 =[ $smash3, hknight_smash4 ] {ai_charge(9);};
void() hknight_smash4 =[ $smash4, hknight_smash5 ] {ai_charge(11);};
void() hknight_smash5 =[ $smash5, hknight_smash6 ] {ai_charge(10); ai_melee();};
void() hknight_smash6 =[ $smash6, hknight_smash7 ] {ai_charge(7); ai_melee();};
void() hknight_smash7 =[ $smash7, hknight_smash8 ] {ai_charge(12); ai_melee();};
void() hknight_smash8 =[ $smash8, hknight_smash9 ] {ai_charge(2); ai_melee();};
void() hknight_smash9 =[ $smash9, hknight_smash10 ] {ai_charge(3); ai_melee();};
void() hknight_smash10 =[ $smash10, hknight_smash11 ] {ai_charge(0);};
void() hknight_smash11 =[ $smash11, hknight_run1 ] {ai_charge(0);};
//============================================================================
void() hknight_watk1 =[ $w_attack1, hknight_watk2 ] {ai_charge(2);};
void() hknight_watk2 =[ $w_attack2, hknight_watk3 ] {ai_charge(0);};
void() hknight_watk3 =[ $w_attack3, hknight_watk4 ] {ai_charge(0);};
void() hknight_watk4 =[ $w_attack4, hknight_watk5 ] {ai_melee();};
void() hknight_watk5 =[ $w_attack5, hknight_watk6 ] {ai_melee();};
void() hknight_watk6 =[ $w_attack6, hknight_watk7 ] {ai_melee();};
void() hknight_watk7 =[ $w_attack7, hknight_watk8 ] {ai_charge(1);};
void() hknight_watk8 =[ $w_attack8, hknight_watk9 ] {ai_charge(4);};
void() hknight_watk9 =[ $w_attack9, hknight_watk10 ] {ai_charge(5);};
void() hknight_watk10 =[ $w_attack10, hknight_watk11 ] {ai_charge(3); ai_melee();};
void() hknight_watk11 =[ $w_attack11, hknight_watk12 ] {ai_charge(2); ai_melee();};
void() hknight_watk12 =[ $w_attack12, hknight_watk13 ] {ai_charge(2); ai_melee();};
void() hknight_watk13 =[ $w_attack13, hknight_watk14 ] {ai_charge(0);};
void() hknight_watk14 =[ $w_attack14, hknight_watk15 ] {ai_charge(0);};
void() hknight_watk15 =[ $w_attack15, hknight_watk16 ] {ai_charge(0);};
void() hknight_watk16 =[ $w_attack16, hknight_watk17 ] {ai_charge(1);};
void() hknight_watk17 =[ $w_attack17, hknight_watk18 ] {ai_charge(1); ai_melee();};
void() hknight_watk18 =[ $w_attack18, hknight_watk19 ] {ai_charge(3); ai_melee();};
void() hknight_watk19 =[ $w_attack19, hknight_watk20 ] {ai_charge(4); ai_melee();};
void() hknight_watk20 =[ $w_attack20, hknight_watk21 ] {ai_charge(6);};
void() hknight_watk21 =[ $w_attack21, hknight_watk22 ] {ai_charge(7);};
void() hknight_watk22 =[ $w_attack22, hknight_run1 ] {ai_charge(3);};
//============================================================================
void() hk_idle_sound =
{
if (random() < 0.2)
sound (self, CHAN_VOICE, "hknight/idle.wav", 1, ATTN_NORM);
};
void(entity attacker, float damage) hknight_pain =
{
if (self.pain_finished > time)
return;
if (random() < 0.6)
sound (self, CHAN_VOICE, "hknight/pain1.wav", 1, ATTN_NORM);
else
sound (self, CHAN_VOICE, "hknight/grunt.wav", 1, ATTN_NORM);
if (time - self.pain_finished > 5)
{ // allways go into pain frame if it has been a while
hknight_pain1 ();
self.pain_finished = time + 1;
return;
}
if ((random()*30 > damage) )
return; // didn't flinch
self.pain_finished = time + 1;
hknight_pain1 ();
};
float hknight_type;
void() hknight_melee =
{
hknight_type = hknight_type + 1;
sound (self, CHAN_WEAPON, "hknight/slash1.wav", 1, ATTN_NORM);
if (hknight_type == 1)
hknight_slice1 ();
else if (hknight_type == 2)
hknight_smash1 ();
else if (hknight_type == 3)
{
hknight_watk1 ();
hknight_type = 0;
}
};
/*QUAKED monster_hell_knight (1 0 0) (-16 -16 -24) (16 16 40) Ambush
{
model ("progs/hknight.mdl");
}
Death knight.
*/
void() monster_hell_knight =
{
if (deathmatch)
{
remove(self);
return;
}
precache_model2 ("progs/hknight.mdl");
precache_model2 ("progs/h_hellkn.mdl");
precache_model2 ("progs/k_spike.mdl");
precache_sound2 ("hknight/attack1.wav");
precache_sound2 ("hknight/death1.wav");
precache_sound2 ("hknight/pain1.wav");
precache_sound2 ("hknight/sight1.wav");
precache_sound2 ("hknight/slash1.wav");
precache_sound2 ("hknight/idle.wav");
precache_sound2 ("hknight/grunt.wav");
precache_sound ("hknight/hit.wav");
precache_sound ("knight/sword1.wav");
precache_sound ("knight/sword2.wav");
self.th_stand = hknight_stand1;
self.th_walk = hknight_walk1;
self.th_run = hknight_run1;
self.th_melee = hknight_melee;
self.th_missile = hknight_magicc1;
self.th_pain = hknight_pain;
self.th_die = hknight_die;
monster_start("progs/hknight.mdl", "progs/h_hellkn.mdl", 250, 0, '-16 -16 -24', '16 16 40');
};

View File

@@ -0,0 +1,241 @@
$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9
$frame runb1 runb2 runb3 runb4 runb5 runb6 runb7 runb8
$frame runattack1 runattack2 runattack3 runattack4 runattack5
$frame runattack6 runattack7 runattack8 runattack9 runattack10
$frame runattack11
$frame pain1 pain2 pain3
$frame painb1 painb2 painb3 painb4 painb5 painb6 painb7 painb8 painb9
$frame painb10 painb11
$frame attackx1
$frame attackb1 attackb2 attackb3 attackb4 attackb5
$frame attackb6 attackb7 attackb8 attackb9 attackb10
$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 walk9
$frame walk10 walk11 walk12 walk13 walk14
$frame kneel1 kneel2 kneel3 kneel4 kneel5
$frame standing1 standing2 standing3 standing4
$frame death1 death2 death3 death4 death5 death6 death7 death8
$frame death9 death10 death11
$frame deathb1 deathb2 deathb3 deathb4 deathb5 deathb6 deathb7 deathb8
$frame deathb9 deathb10
void() knight_stand1 =[ $stand1, knight_stand2 ] {ai_stand();};
void() knight_stand2 =[ $stand2, knight_stand3 ] {ai_stand();};
void() knight_stand3 =[ $stand3, knight_stand4 ] {ai_stand();};
void() knight_stand4 =[ $stand4, knight_stand5 ] {ai_stand();};
void() knight_stand5 =[ $stand5, knight_stand6 ] {ai_stand();};
void() knight_stand6 =[ $stand6, knight_stand7 ] {ai_stand();};
void() knight_stand7 =[ $stand7, knight_stand8 ] {ai_stand();};
void() knight_stand8 =[ $stand8, knight_stand9 ] {ai_stand();};
void() knight_stand9 =[ $stand9, knight_stand1 ] {ai_stand();};
void() knight_walk1 =[ $walk1, knight_walk2 ] {
if (random() < 0.2)
sound (self, CHAN_VOICE, "knight/idle.wav", 1, ATTN_IDLE);
ai_walk(3);};
void() knight_walk2 =[ $walk2, knight_walk3 ] {ai_walk(2);};
void() knight_walk3 =[ $walk3, knight_walk4 ] {ai_walk(3);};
void() knight_walk4 =[ $walk4, knight_walk5 ] {ai_walk(4);};
void() knight_walk5 =[ $walk5, knight_walk6 ] {ai_walk(3);};
void() knight_walk6 =[ $walk6, knight_walk7 ] {ai_walk(3);};
void() knight_walk7 =[ $walk7, knight_walk8 ] {ai_walk(3);};
void() knight_walk8 =[ $walk8, knight_walk9 ] {ai_walk(4);};
void() knight_walk9 =[ $walk9, knight_walk10 ] {ai_walk(3);};
void() knight_walk10 =[ $walk10, knight_walk11 ] {ai_walk(3);};
void() knight_walk11 =[ $walk11, knight_walk12 ] {ai_walk(2);};
void() knight_walk12 =[ $walk12, knight_walk13 ] {ai_walk(3);};
void() knight_walk13 =[ $walk13, knight_walk14 ] {ai_walk(4);};
void() knight_walk14 =[ $walk14, knight_walk1 ] {ai_walk(3);};
void() knight_run1 =[ $runb1, knight_run2 ] {
if (random() < 0.2)
sound (self, CHAN_VOICE, "knight/idle.wav", 1, ATTN_IDLE);
ai_run(16);};
void() knight_run2 =[ $runb2, knight_run3 ] {ai_run(20);};
void() knight_run3 =[ $runb3, knight_run4 ] {ai_run(13);};
void() knight_run4 =[ $runb4, knight_run5 ] {ai_run(7);};
void() knight_run5 =[ $runb5, knight_run6 ] {ai_run(16);};
void() knight_run6 =[ $runb6, knight_run7 ] {ai_run(20);};
void() knight_run7 =[ $runb7, knight_run8 ] {ai_run(14);};
void() knight_run8 =[ $runb8, knight_run1 ] {ai_run(6);};
void() knight_runatk1 =[ $runattack1, knight_runatk2 ]
{
if (random() > 0.5)
sound (self, CHAN_WEAPON, "knight/sword2.wav", 1, ATTN_NORM);
else
sound (self, CHAN_WEAPON, "knight/sword1.wav", 1, ATTN_NORM);
ai_charge(20);
};
void() knight_runatk2 =[ $runattack2, knight_runatk3 ] {ai_charge_side();};
void() knight_runatk3 =[ $runattack3, knight_runatk4 ] {ai_charge_side();};
void() knight_runatk4 =[ $runattack4, knight_runatk5 ] {ai_charge_side();};
void() knight_runatk5 =[ $runattack5, knight_runatk6 ] {ai_melee_side();};
void() knight_runatk6 =[ $runattack6, knight_runatk7 ] {ai_melee_side();};
void() knight_runatk7 =[ $runattack7, knight_runatk8 ] {ai_melee_side();};
void() knight_runatk8 =[ $runattack8, knight_runatk9 ] {ai_melee_side();};
void() knight_runatk9 =[ $runattack9, knight_runatk10 ] {ai_melee_side();};
void() knight_runatk10 =[ $runattack10, knight_runatk11 ] {ai_charge_side();};
void() knight_runatk11 =[ $runattack11, knight_run1 ] {ai_charge(10);};
void() knight_atk1 =[ $attackb1, knight_atk2 ]
{
sound (self, CHAN_WEAPON, "knight/sword1.wav", 1, ATTN_NORM);
ai_charge(0);};
void() knight_atk2 =[ $attackb2, knight_atk3 ] {ai_charge(7);};
void() knight_atk3 =[ $attackb3, knight_atk4 ] {ai_charge(4);};
void() knight_atk4 =[ $attackb4, knight_atk5 ] {ai_charge(0);};
void() knight_atk5 =[ $attackb5, knight_atk6 ] {ai_charge(3);};
void() knight_atk6 =[ $attackb6, knight_atk7 ] {ai_charge(4); ai_melee();};
void() knight_atk7 =[ $attackb7, knight_atk8 ] {ai_charge(1); ai_melee();};
void() knight_atk8 =[ $attackb8, knight_atk9 ] {ai_charge(3); ai_melee();};
void() knight_atk9 =[ $attackb9, knight_atk10] {ai_charge(1);};
void() knight_atk10=[ $attackb10, knight_run1 ] {ai_charge(5);};
void() knight_attack =
{
local float len;
// decide if now is a good swing time
len = vlen(self.enemy.origin+self.enemy.view_ofs - (self.origin+self.view_ofs));
if (len<80)
knight_atk1 ();
else
knight_runatk1 ();
};
void() knight_pain1 =[ $pain1, knight_pain2 ] {};
void() knight_pain2 =[ $pain2, knight_pain3 ] {};
void() knight_pain3 =[ $pain3, knight_run1 ] {};
void() knight_painb1 =[ $painb1, knight_painb2 ] {ai_painforward(0);};
void() knight_painb2 =[ $painb2, knight_painb3 ] {ai_painforward(3);};
void() knight_painb3 =[ $painb3, knight_painb4 ] {};
void() knight_painb4 =[ $painb4, knight_painb5 ] {};
void() knight_painb5 =[ $painb5, knight_painb6 ] {ai_painforward(2);};
void() knight_painb6 =[ $painb6, knight_painb7 ] {ai_painforward(4);};
void() knight_painb7 =[ $painb7, knight_painb8 ] {ai_painforward(2);};
void() knight_painb8 =[ $painb8, knight_painb9 ] {ai_painforward(5);};
void() knight_painb9 =[ $painb9, knight_painb10 ] {ai_painforward(5);};
void() knight_painb10 =[ $painb10, knight_painb11 ] {ai_painforward(0);};
void() knight_painb11 =[ $painb11, knight_run1 ] {};
void(entity attacker, float damage) knight_pain =
{
if (self.pain_finished > time)
return;
if (random() < 0.8)
sound (self, CHAN_VOICE, "knight/khurt.wav", 1, ATTN_NORM);
else
sound (self, CHAN_VOICE, "hknight/grunt.wav", 1, ATTN_NORM);
float r = random();
if (r < 0.85)
{
knight_pain1 ();
self.pain_finished = time + 1;
}
else
{
knight_painb1 ();
self.pain_finished = time + 1;
}
};
void() knight_die1 =[ $death1, knight_die2 ] {};
void() knight_die2 =[ $death2, knight_die3 ] {};
void() knight_die3 =[ $death3, knight_die4 ] {};
void() knight_die4 =[ $death4, knight_die5 ] {};
void() knight_die5 =[ $death5, knight_die6 ] {};
void() knight_die6 =[ $death6, knight_die7 ] {};
void() knight_die7 =[ $death7, knight_die8 ] {};
void() knight_die8 =[ $death8, knight_die9 ] {};
void() knight_die9 =[ $death9, knight_die10] {};
void() knight_die10=[ $death10, knight_die10] {};
void() knight_die11=[ $death11, knight_die11] {};
void() knight_dieb1 =[ $deathb1, knight_dieb2 ] {};
void() knight_dieb2 =[ $deathb2, knight_dieb3 ] {};
void() knight_dieb3 =[ $deathb3, knight_dieb4 ] {};
void() knight_dieb4 =[ $deathb4, knight_dieb5 ] {};
void() knight_dieb5 =[ $deathb5, knight_dieb6 ] {};
void() knight_dieb6 =[ $deathb6, knight_dieb7 ] {};
void() knight_dieb7 =[ $deathb7, knight_dieb8 ] {};
void() knight_dieb8 =[ $deathb8, knight_dieb9 ] {};
void() knight_dieb9 =[ $deathb9, knight_dieb10] {};
void() knight_dieb10 = [ $deathb10, knight_dieb10] {};
void(entity inflictor, entity attacker) knight_die =
{
// check for gib
if (self.health < -40)
{
SpawnGib ("progs/gib1.mdl");
SpawnGib ("progs/gib2.mdl");
SpawnGib ("progs/gib3.mdl");
SpawnGib ("progs/gib4.mdl");
SpawnGib ("progs/gib5.mdl");
SpawnGib ("progs/blood.mdl");
SpawnGib ("progs/blood.mdl");
BecomeGibs ();
return;
}
// regular death
self.solid = SOLID_NOT;
sound (self, CHAN_VOICE, "knight/kdeath.wav", 1, ATTN_NORM);
if (random() < 0.5)
knight_die1();
else
knight_dieb1();
};
/*QUAKED monster_knight (1 0 0) (-16 -16 -24) (16 16 40) Ambush
{
model ("progs/knight.mdl");
}
Knight.
*/
void() monster_knight =
{
if (deathmatch)
{
remove(self);
return;
}
precache_model ("progs/knight.mdl");
precache_model ("progs/h_knight.mdl");
precache_sound ("knight/kdeath.wav");
precache_sound ("knight/khurt.wav");
precache_sound ("knight/ksight.wav");
precache_sound ("knight/sword1.wav");
precache_sound ("knight/sword2.wav");
precache_sound ("knight/idle.wav");
precache_sound ("hknight/grunt.wav");
self.th_stand = knight_stand1;
self.th_walk = knight_walk1;
self.th_run = knight_run1;
self.th_melee = knight_attack;
self.th_pain = knight_pain;
self.th_die = knight_die;
self.skin = randomrange(4);
monster_start("progs/knight.mdl", "progs/h_knight.mdl", 75, 0, '-16 -16 -24', '16 16 40');
};

View File

@@ -0,0 +1,485 @@
$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9
$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7
$frame walk8 walk9 walk10 walk11 walk12 walk13 walk14 walk15 walk16
$frame run1 run2 run3 run4 run5 run6 run7 run8
$frame swing1 swing2 swing3 swing4 swing5 swing6 swing7
$frame swing8 swing9 swing10 swing11 swing12 swing13 swing14
$frame smash1 smash2 smash3 smash4 smash5 smash6 smash7
$frame smash8 smash9 smash10 smash11 smash12 smash13 smash14
$frame shoot1 shoot2 shoot3 shoot4 shoot5 shoot6
$frame pain1 pain2 pain3 pain4 pain5
$frame painb1 painb2 painb3
$frame painc1 painc2 painc3 painc4 painc5 painc6
$frame paind1 paind2 paind3 paind4 paind5 paind6 paind7 paind8 paind9 paind10
$frame paind11 paind12 paind13 paind14 paind15 paind16
$frame paine1 paine2 paine3 paine4 paine5 paine6 paine7 paine8 paine9 paine10
$frame paine11 paine12 paine13 paine14 paine15
$frame death1 death2 death3 death4 death5 death6
$frame death7 death8 death9 death10 death11 death12
$frame death13 death14
$frame bdeath1 bdeath2 bdeath3 bdeath4 bdeath5 bdeath6
$frame bdeath7 bdeath8 bdeath9 bdeath10
$frame pull1 pull2 pull3 pull4 pull5 pull6 pull7 pull8 pull9 pull10 pull11
#define OGRE_G_VEL 600
#define OGRE_DEFAULT_ELEVATION 45
/*==========
OgreGrenadeExplode
==========*/
void() OgreGrenadeExplode =
{
RadiusDamage(self, self.owner, 40, world);
te_explosion(self.origin);
BecomeExplosion();
};
/*==========
OgreGrenadeTouch
==========*/
void() OgreGrenadeTouch =
{
if (other.takedamage == DAMAGE_AIM)
{
OgreGrenadeExplode();
return;
}
sound(self, CHAN_VOICE, "weapons/bounce.wav", 1, ATTN_NORM);
};
/*==========
OgreIterateElevation
==========*/
float(float theta, vector dest, vector org) OgreIterateElevation =
{
vector ofs = dest - org;
float z = ofs_z;
ofs_z = 0;
float y = vlen(ofs);
float a = 0.5 * sv_gravity * y * y / (OGRE_G_VEL * OGRE_G_VEL);
float b = -y;
float c = a + z;
// can't reach target
if (b * b < 4 * a * c)
{
dprint("OGRE_DEFAULT_ELEVATION\n");
return OGRE_DEFAULT_ELEVATION;
}
float tan_theta = tan(theta);
theta = atan2(a * tan_theta * tan_theta - c, 2 * a * tan_theta + b);
while (theta > 90)
theta = theta - 180;
return theta;
};
/*==========
OgreFireGrenade
==========*/
void(float spam) OgreFireGrenade =
{
self.effects = self.effects | EF_MUZZLEFLASH;
sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
vector org = self.origin;
entity missile = spawn ();
missile.owner = self;
missile.movetype = MOVETYPE_BOUNCE;
missile.solid = SOLID_BBOX;
setmodel (missile, "progs/grenade.mdl");
setsize (missile, '0 0 0', '0 0 0');
setorigin (missile, org);
// chose where to aim
vector dest;
// aim at last known enemy location
if (spam)
{
dest = self.enemy_last;
spawn_debug_marker(dest);
}
// aim at enemy
else
{
// lead player on hard
/*if (skill > 1)
{
vector ofs = self.enemy.origin + self.enemy.view_ofs - org;
float t = vlen(ofs) / OGRE_G_VEL;
vector vel = self.enemy.velocity;
vel_z = 0;
dest = self.enemy.origin + self.enemy.view_ofs + (t * vel);
}
// aim at enemy position
else
*/
dest = self.enemy.origin + self.enemy.view_ofs;
}
float elevation = OgreIterateElevation(OGRE_DEFAULT_ELEVATION, dest, org);
elevation = OgreIterateElevation(elevation, dest, org);
elevation = OgreIterateElevation(elevation, dest, org);
elevation = OgreIterateElevation(elevation, dest, org);
vector ang = normalize(dest - org);
ang = vectoangles(ang);
ang_x = -elevation;
makevectors(ang);
missile.velocity = v_forward * OGRE_G_VEL;
missile.avelocity = '300 300 300';
missile.angles = vectoangles(missile.velocity);
missile.touch = OgreGrenadeTouch;
missile.nextthink = time + 2.5;
missile.think = OgreGrenadeExplode;
};
void() ogre_grenade1 =[ $shoot1, ogre_grenade2 ] {ai_face();};
void() ogre_grenade2 =[ $shoot2, ogre_grenade3 ] {ai_face();};
void() ogre_grenade3 =[ $shoot2, ogre_grenade4 ] {ai_face();};
void() ogre_grenade4 =[ $shoot3, ogre_grenade5 ] {ai_face();OgreFireGrenade(FALSE);};
void() ogre_grenade5 =[ $shoot4, ogre_grenade6 ] {ai_face();};
void() ogre_grenade6 =[ $shoot5, ogre_grenade7 ] {ai_face();};
void() ogre_grenade7 =[ $shoot6, ogre_run1 ] {ai_face();};
void() ogre_spam1 =[ $shoot1, ogre_spam2 ] {ai_face_last();};
void() ogre_spam2 =[ $shoot2, ogre_spam3 ] {ai_face_last();};
void() ogre_spam3 =[ $shoot2, ogre_spam4 ] {ai_face_last();};
void() ogre_spam4 =[ $shoot3, ogre_spam5 ] {ai_face_last();OgreFireGrenade(TRUE);};
void() ogre_spam5 =[ $shoot4, ogre_spam6 ] {ai_face_last();};
void() ogre_spam6 =[ $shoot5, ogre_spam7 ] {ai_face_last();};
void() ogre_spam7 =[ $shoot6, ogre_run1 ] {ai_face_last();};
/*==========
OgreChainsaw
==========*/
void() OgreChainsaw =
{
float delta = vlen(self.enemy.origin - self.origin);
if (delta > 100)
return;
if (!CanDamage(self.enemy, self))
return;
float ldmg = (random() + random() + random()) * 4;
Damage (self.enemy, self, self, ldmg);
SpawnBlood(trace_endpos, randomvec() * 8, 12);
if (random() < 0.1)
{
makevectors (self.angles);
if (random() < 0.5)
SpawnMeatSpray (self.origin + v_forward*16, v_right * 200 + v_up * 50);
else
SpawnMeatSpray (self.origin + v_forward*16, v_up * 50 - v_right * 200);
}
};
void() ogre_swing1 =[ $swing1, ogre_swing2 ] {ai_charge(11);};
void() ogre_swing2 =[ $swing2, ogre_swing3 ] {ai_charge(1);};
void() ogre_swing3 =[ $swing3, ogre_swing4 ] {ai_charge(4);};
void() ogre_swing4 =[ $swing4, ogre_swing5 ] {ai_charge(13);};
void() ogre_swing5 =[ $swing5, ogre_swing6 ] {ai_charge(19);OgreChainsaw();};
void() ogre_swing6 =[ $swing6, ogre_swing7 ] {ai_charge(10);OgreChainsaw();};
void() ogre_swing7 =[ $swing7, ogre_swing8 ] {ai_charge(10);OgreChainsaw();};
void() ogre_swing8 =[ $swing8, ogre_swing9 ] {ai_charge(10);OgreChainsaw();};
void() ogre_swing9 =[ $swing9, ogre_swing10] {ai_charge(10);OgreChainsaw();};
void() ogre_swing10 =[ $swing10, ogre_swing11] {ai_charge(10);OgreChainsaw();};
void() ogre_swing11 =[ $swing11, ogre_swing12] {ai_charge(10);OgreChainsaw();};
void() ogre_swing12 =[ $swing12, ogre_swing13] {ai_charge(3);};
void() ogre_swing13 =[ $swing13, ogre_swing14] {ai_charge(8);};
void() ogre_swing14 =[ $swing14, ogre_run1 ] {ai_charge(9);};
void() ogre_smash1 =[ $smash1, ogre_smash2 ] {ai_charge(6);};
void() ogre_smash2 =[ $smash2, ogre_smash3 ] {ai_charge(0);};
void() ogre_smash3 =[ $smash3, ogre_smash4 ] {ai_charge(0);};
void() ogre_smash4 =[ $smash4, ogre_smash5 ] {ai_charge(1);};
void() ogre_smash5 =[ $smash5, ogre_smash6 ] {ai_charge(4);};
void() ogre_smash6 =[ $smash6, ogre_smash7 ] {ai_charge(14);OgreChainsaw();};
void() ogre_smash7 =[ $smash7, ogre_smash8 ] {ai_charge(14);OgreChainsaw();};
void() ogre_smash8 =[ $smash8, ogre_smash9 ] {ai_charge(20);OgreChainsaw();};
void() ogre_smash9 =[ $smash9, ogre_smash10] {ai_charge(23);OgreChainsaw();};
void() ogre_smash10 =[ $smash10, ogre_smash11] {ai_charge(10);OgreChainsaw();};
void() ogre_smash11 =[ $smash11, ogre_smash12]
{
ai_charge(12);
OgreChainsaw();
self.nextthink = self.nextthink + random()*0.2;
};
void() ogre_smash12 =[ $smash12, ogre_smash13 ] {ai_charge(0);};
void() ogre_smash13 =[ $smash13, ogre_smash14 ] {ai_charge(4);};
void() ogre_smash14 =[ $smash14, ogre_run1 ] {ai_charge(12);};
/*==========
ogre_melee
==========*/
void() ogre_melee =
{
sound (self, CHAN_WEAPON, "ogre/ogsawatk.wav", 1, ATTN_NORM);
if (random() < 0.5)
ogre_smash1();
else
ogre_swing1();
};
void() ogre_stand1 =[ $stand1, ogre_stand2 ] {ai_stand();};
void() ogre_stand2 =[ $stand2, ogre_stand3 ] {ai_stand();};
void() ogre_stand3 =[ $stand3, ogre_stand4 ] {ai_stand();};
void() ogre_stand4 =[ $stand4, ogre_stand5 ] {ai_stand();};
void() ogre_stand5 =[ $stand5, ogre_stand6 ] {
if (random() < 0.2)
sound (self, CHAN_VOICE, "ogre/ogidle.wav", 1, ATTN_IDLE);
ai_stand();
};
void() ogre_stand6 =[ $stand6, ogre_stand7 ] {ai_stand();};
void() ogre_stand7 =[ $stand7, ogre_stand8 ] {ai_stand();};
void() ogre_stand8 =[ $stand8, ogre_stand9 ] {ai_stand();};
void() ogre_stand9 =[ $stand9, ogre_stand1 ] {ai_stand();};
void() ogre_walk1 =[ $walk1, ogre_walk2 ] {ai_walk(3);};
void() ogre_walk2 =[ $walk2, ogre_walk3 ] {ai_walk(2);};
void() ogre_walk3 =[ $walk3, ogre_walk4 ] {ai_walk(2);
if (random() < 0.2)
sound (self, CHAN_VOICE, "ogre/ogidle.wav", 1, ATTN_IDLE);
};
void() ogre_walk4 =[ $walk4, ogre_walk5 ] {ai_walk(2);};
void() ogre_walk5 =[ $walk5, ogre_walk6 ] {ai_walk(2);};
void() ogre_walk6 =[ $walk6, ogre_walk7 ] {ai_walk(5);
if (random() < 0.1)
sound (self, CHAN_VOICE, "ogre/ogdrag.wav", 1, ATTN_IDLE);
};
void() ogre_walk7 =[ $walk7, ogre_walk8 ] {ai_walk(3);};
void() ogre_walk8 =[ $walk8, ogre_walk9 ] {ai_walk(2);};
void() ogre_walk9 =[ $walk9, ogre_walk10 ] {ai_walk(3);};
void() ogre_walk10 =[ $walk10, ogre_walk11 ] {ai_walk(1);};
void() ogre_walk11 =[ $walk11, ogre_walk12 ] {ai_walk(2);};
void() ogre_walk12 =[ $walk12, ogre_walk13 ] {ai_walk(3);};
void() ogre_walk13 =[ $walk13, ogre_walk14 ] {ai_walk(3);};
void() ogre_walk14 =[ $walk14, ogre_walk15 ] {ai_walk(3);};
void() ogre_walk15 =[ $walk15, ogre_walk16 ] {ai_walk(3);};
void() ogre_walk16 =[ $walk16, ogre_walk1 ] {ai_walk(4);};
void() ogre_run1 =[ $run1, ogre_run2 ] {ai_run(9);
if (random() < 0.2)
sound (self, CHAN_VOICE, "ogre/ogidle2.wav", 1, ATTN_IDLE);
};
void() ogre_run2 =[ $run2, ogre_run3 ] {ai_run(12);};
void() ogre_run3 =[ $run3, ogre_run4 ] {ai_run(8);};
void() ogre_run4 =[ $run4, ogre_run5 ] {ai_run(22);};
void() ogre_run5 =[ $run5, ogre_run6 ] {ai_run(16);};
void() ogre_run6 =[ $run6, ogre_run7 ] {ai_run(4);};
void() ogre_run7 =[ $run7, ogre_run8 ] {ai_run(13);};
void() ogre_run8 =[ $run8, ogre_run1 ] {ai_run(24);};
void() ogre_pain1 =[ $pain1, ogre_pain2 ] {};
void() ogre_pain2 =[ $pain2, ogre_pain3 ] {};
void() ogre_pain3 =[ $pain3, ogre_pain4 ] {};
void() ogre_pain4 =[ $pain4, ogre_pain5 ] {};
void() ogre_pain5 =[ $pain5, ogre_run1 ] {};
void() ogre_painb1 =[ $painb1, ogre_painb2 ] {};
void() ogre_painb2 =[ $painb2, ogre_painb3 ] {};
void() ogre_painb3 =[ $painb3, ogre_run1 ] {};
void() ogre_painc1 =[ $painc1, ogre_painc2 ] {};
void() ogre_painc2 =[ $painc2, ogre_painc3 ] {};
void() ogre_painc3 =[ $painc3, ogre_painc4 ] {};
void() ogre_painc4 =[ $painc4, ogre_painc5 ] {};
void() ogre_painc5 =[ $painc5, ogre_painc6 ] {};
void() ogre_painc6 =[ $painc6, ogre_run1 ] {};
void() ogre_paind1 =[ $paind1, ogre_paind2 ] {};
void() ogre_paind2 =[ $paind2, ogre_paind3 ] {ai_pain(10);};
void() ogre_paind3 =[ $paind3, ogre_paind4 ] {ai_pain(9);};
void() ogre_paind4 =[ $paind4, ogre_paind5 ] {ai_pain(4);};
void() ogre_paind5 =[ $paind5, ogre_paind6 ] {};
void() ogre_paind6 =[ $paind6, ogre_paind7 ] {};
void() ogre_paind7 =[ $paind7, ogre_paind8 ] {};
void() ogre_paind8 =[ $paind8, ogre_paind9 ] {};
void() ogre_paind9 =[ $paind9, ogre_paind10] {};
void() ogre_paind10=[ $paind10, ogre_paind11] {};
void() ogre_paind11=[ $paind11, ogre_paind12] {};
void() ogre_paind12=[ $paind12, ogre_paind13] {};
void() ogre_paind13=[ $paind13, ogre_paind14] {};
void() ogre_paind14=[ $paind14, ogre_paind15] {};
void() ogre_paind15=[ $paind15, ogre_paind16] {};
void() ogre_paind16=[ $paind16, ogre_run1 ] {};
void() ogre_paine1 =[ $paine1, ogre_paine2 ] {};
void() ogre_paine2 =[ $paine2, ogre_paine3 ] {ai_pain(10);};
void() ogre_paine3 =[ $paine3, ogre_paine4 ] {ai_pain(9);};
void() ogre_paine4 =[ $paine4, ogre_paine5 ] {ai_pain(4);};
void() ogre_paine5 =[ $paine5, ogre_paine6 ] {};
void() ogre_paine6 =[ $paine6, ogre_paine7 ] {};
void() ogre_paine7 =[ $paine7, ogre_paine8 ] {};
void() ogre_paine8 =[ $paine8, ogre_paine9 ] {};
void() ogre_paine9 =[ $paine9, ogre_paine10] {};
void() ogre_paine10=[ $paine10, ogre_paine11] {};
void() ogre_paine11=[ $paine11, ogre_paine12] {};
void() ogre_paine12=[ $paine12, ogre_paine13] {};
void() ogre_paine13=[ $paine13, ogre_paine14] {};
void() ogre_paine14=[ $paine14, ogre_paine15] {};
void() ogre_paine15=[ $paine15, ogre_run1 ] {};
/*==========
ogre_pain
==========*/
void(entity attacker, float damage) ogre_pain =
{
if (self.pain_finished > time)
return;
sound (self, CHAN_VOICE, "ogre/ogpain1.wav", 1, ATTN_NORM);
float r = randomrange(4);
if (r == 0)
{
ogre_pain1 ();
self.pain_finished = time + 1;
}
else if (r == 1)
{
ogre_painb1 ();
self.pain_finished = time + 1;
}
else if (r == 2)
{
ogre_painc1 ();
self.pain_finished = time + 1;
}
else
{
r = random();
if (r < 0.5)
{
ogre_paind1 ();
self.pain_finished = time + 2;
}
else
{
ogre_paine1 ();
self.pain_finished = time + 2;
}
}
};
void() ogre_die1 =[ $death1, ogre_die2 ] {};
void() ogre_die2 =[ $death2, ogre_die3 ] {};
void() ogre_die3 =[ $death3, ogre_die4 ] {DropBackpack();};
void() ogre_die4 =[ $death4, ogre_die5 ] {};
void() ogre_die5 =[ $death5, ogre_die6 ] {};
void() ogre_die6 =[ $death6, ogre_die7 ] {};
void() ogre_die7 =[ $death7, ogre_die8 ] {};
void() ogre_die8 =[ $death8, ogre_die9 ] {};
void() ogre_die9 =[ $death9, ogre_die10 ] {};
void() ogre_die10 =[ $death10, ogre_die11 ] {};
void() ogre_die11 =[ $death11, ogre_die12 ] {};
void() ogre_die12 =[ $death12, ogre_die13 ] {};
void() ogre_die13 =[ $death13, ogre_die14 ] {};
void() ogre_die14 =[ $death14, ogre_die14 ] {};
void() ogre_bdie1 =[ $bdeath1, ogre_bdie2 ] {};
void() ogre_bdie2 =[ $bdeath2, ogre_bdie3 ] {ai_forward(5);};
void() ogre_bdie3 =[ $bdeath3, ogre_bdie4 ] {DropBackpack();};
void() ogre_bdie4 =[ $bdeath4, ogre_bdie5 ] {ai_forward(1);};
void() ogre_bdie5 =[ $bdeath5, ogre_bdie6 ] {ai_forward(3);};
void() ogre_bdie6 =[ $bdeath6, ogre_bdie7 ] {ai_forward(7);};
void() ogre_bdie7 =[ $bdeath7, ogre_bdie8 ] {ai_forward(25);};
void() ogre_bdie8 =[ $bdeath8, ogre_bdie9 ] {};
void() ogre_bdie9 =[ $bdeath9, ogre_bdie10 ] {};
void() ogre_bdie10 =[ $bdeath10, ogre_bdie10 ] {};
/*==========
ogre_die
==========*/
void(entity inflictor, entity attacker) ogre_die =
{
if (self.health < -80)
{
SpawnGib ("progs/gib3.mdl");
SpawnGib ("progs/gib3.mdl");
SpawnGib ("progs/gib3.mdl");
SpawnGib ("progs/gib4.mdl");
SpawnGib ("progs/gib5.mdl");
SpawnGib ("progs/blood.mdl");
SpawnGib ("progs/blood.mdl");
BecomeGibs ();
return;
}
self.solid = SOLID_NOT;
sound (self, CHAN_VOICE, "ogre/ogdth.wav", 1, ATTN_NORM);
if (random() < 0.5)
ogre_die1 ();
else
ogre_bdie1 ();
};
/*QUAKED monster_ogre (1 0 0) (-32 -32 -24) (32 32 64) Ambush
{
model ("progs/ogre.mdl");
}
Ogre.
*/
void() monster_ogre =
{
if (deathmatch)
{
remove(self);
return;
}
precache_model ("progs/ogre.mdl");
precache_model ("progs/h_ogre.mdl");
precache_model ("progs/grenade.mdl");
precache_sound ("ogre/ogdrag.wav");
precache_sound ("ogre/ogdth.wav");
precache_sound ("ogre/ogidle.wav");
precache_sound ("ogre/ogidle2.wav");
precache_sound ("ogre/ogpain1.wav");
precache_sound ("ogre/ogsawatk.wav");
precache_sound ("ogre/ogwake.wav");
self.th_stand = ogre_stand1;
self.th_walk = ogre_walk1;
self.th_run = ogre_run1;
self.th_die = ogre_die;
self.th_melee = ogre_melee;
self.th_missile = ogre_grenade1;
self.th_spam = ogre_spam1;
self.th_pain = ogre_pain;
if (random() < 0.3)
self.skin = 1;
self.ammo_rockets = 2;
monster_start("progs/ogre.mdl", "progs/h_ogre.mdl", 200, 0, VEC_HULL2_MIN, VEC_HULL2_MAX);
};
/*==========
monster_ogre_marksman
For compatibility only.
==========*/
void() monster_ogre_marksman =
{
self.classname = "monster_ogre";
monster_ogre ();
};

View File

@@ -0,0 +1,241 @@
$frame old1 old2 old3 old4 old5 old6 old7 old8 old9
$frame old10 old11 old12 old13 old14 old15 old16 old17 old18 old19
$frame old20 old21 old22 old23 old24 old25 old26 old27 old28 old29
$frame old30 old31 old32 old33 old34 old35 old36 old37 old38 old39
$frame old40 old41 old42 old43 old44 old45 old46
$frame shake1 shake2 shake3 shake4 shake5 shake6 shake7 shake8
$frame shake9 shake10 shake11 shake12 shake13 shake14
$frame shake15 shake16 shake17 shake18 shake19 shake20 shake21
entity shub;
/*==========
shub_awake
==========*/
void() shub_awake =
{
self.frame = self.frame + 1;
if (self.frame > $old46)
self.frame = $old1;
self.think = shub_awake;
self.nextthink = time + 0.1;
if (time < self.attack_finished)
return;
sound(self, CHAN_VOICE, "boss2/idle.wav", 1, ATTN_IDLE);
self.attack_finished = time + 2 + random() * 2;
};
/*==========
shub_idle
==========*/
void() shub_idle =
{
self.frame = self.frame + 1;
if (self.frame > $old46)
self.frame = $old1;
// look for a player
entity client = checkclient();
if (client)
{
if (visible(client))
{
self.enemy = client;
sound(self, CHAN_BODY, "boss2/sight.wav", 1, ATTN_NONE); // no attenuation
self.attack_finished = time + 3;
self.think = shub_awake;
self.nextthink = time + 0.1;
return;
}
}
self.think = shub_idle;
self.nextthink = time + 0.1;
};
/*==========
shub_finale_3
==========*/
void() shub_finale_3 =
{
// switch cd track
WriteByte (MSG_ALL, SVC_CDTRACK);
WriteByte (MSG_ALL, 3);
WriteByte (MSG_ALL, 3);
// turn lights back on and spawn a load of gibs
lightstyle (0, "m");
sound (self, CHAN_VOICE, "boss2/pop2.wav", 1, ATTN_NONE); // no attenuation
for (float i = 0; i < 20; i++)
{
SpawnGib("progs/gib3.mdl");
SpawnGib("progs/gib4.mdl");
SpawnGib("progs/gib5.mdl");
SpawnGib("progs/blood.mdl");
}
// start the end text
WriteByte (MSG_ALL, SVC_FINALE);
WriteString (MSG_ALL, "Congratulations and well done! You have\nbeaten the hideous Shub-Niggurath, and\nher hundreds of ugly changelings and\nmonsters. You have proven that your\nskill and your cunning are greater than\nall the powers of Quake. You are the\nmaster now. Id Software salutes you.");
// find the intermission spot
entity pos = find (world, classname, "info_intermission");
if (!pos)
error ("no info_intermission");
// put a player model down and face it towards the intermission spot
entity p = spawn();
p.solid = SOLID_NOT;
p.movetype = MOVETYPE_NONE;
setmodel (p, "progs/dplayer.mdl");
makevectors(self.angles);
setorigin (p, self.origin + v_forward * 128);
p.angles_y = vectoyaw(pos.origin - p.origin);
// remove shub
remove (self);
};
void() shub_thrash1 =[ $shake1, shub_thrash2 ] {lightstyle(0, "m");};
void() shub_thrash2 =[ $shake2, shub_thrash3 ] {lightstyle(0, "k");};
void() shub_thrash3 =[ $shake3, shub_thrash4 ] {lightstyle(0, "k");};
void() shub_thrash4 =[ $shake4, shub_thrash5 ] {lightstyle(0, "i");};
void() shub_thrash5 =[ $shake5, shub_thrash6 ] {lightstyle(0, "g");};
void() shub_thrash6 =[ $shake6, shub_thrash7 ] {lightstyle(0, "e");};
void() shub_thrash7 =[ $shake7, shub_thrash8 ] {lightstyle(0, "c");};
void() shub_thrash8 =[ $shake8, shub_thrash9 ] {lightstyle(0, "a");};
void() shub_thrash9 =[ $shake9, shub_thrash10 ] {lightstyle(0, "c");};
void() shub_thrash10 =[ $shake10, shub_thrash11 ] {lightstyle(0, "e");};
void() shub_thrash11 =[ $shake11, shub_thrash12 ] {lightstyle(0, "g");};
void() shub_thrash12 =[ $shake12, shub_thrash13 ] {lightstyle(0, "i");};
void() shub_thrash13 =[ $shake13, shub_thrash14 ] {lightstyle(0, "k");};
void() shub_thrash14 =[ $shake14, shub_thrash15 ] {lightstyle(0, "m");};
void() shub_thrash15 =[ $shake15, shub_thrash16 ]
{
lightstyle(0, "m");
self.count = self.count + 1;
if (self.count < 3)
self.think = shub_thrash1;
};
void() shub_thrash16 =[ $shake16, shub_thrash17 ] {lightstyle(0, "g");};
void() shub_thrash17 =[ $shake17, shub_thrash18 ] {lightstyle(0, "c");};
void() shub_thrash18 =[ $shake18, shub_thrash19 ] {lightstyle(0, "b");};
void() shub_thrash19 =[ $shake19, shub_thrash20 ] {lightstyle(0, "a");};
void() shub_thrash20 =[ $shake20, shub_thrash21 ] {lightstyle(0, "a");};
void() shub_thrash21 =[ $shake21, shub_thrash21 ] {shub_finale_3();};
/*==========
shub_finale_3
==========*/
void() shub_finale_2 =
{
shub.think = shub_thrash1;
sound(shub, CHAN_VOICE, "boss2/death.wav", 1, ATTN_NONE); // no attenuation
remove(self);
};
/*==========
shub_finale_2
==========*/
void() shub_finale_1 =
{
// start a teleport splash inside shub
te_teleport(shub.origin + [0, 0, 192]);
sound(shub, CHAN_VOICE, "misc/r_tele1.wav", 1, ATTN_NONE); // no attenuation
// wait for 2 seconds
self.nextthink = time + 2;
self.think = shub_finale_2;
};
/*==========
shub_die
==========*/
void(entity inflictor, entity attacker) shub_die =
{
// bump the kill counter
killed_monsters = killed_monsters + 1;
WriteByte (MSG_ALL, SVC_KILLEDMONSTER);
// put up the end of level scoreboard
intermission_running = 1;
intermission_exittime = -1;
WriteByte (MSG_ALL, SVC_INTERMISSION);
// find the intermission spot
entity pos = find (world, classname, "info_intermission");
if (!pos)
error("no info_intermission");
// move all players to the intermission spot
entity p = find (world, classname, "player");
while (p != world)
{
p.view_ofs = '0 0 0';
p.angles = other.v_angle = pos.mangle;
p.fixangle = TRUE;
p.think = SUB_Null;
p.nextthink = time + 0.1;
p.takedamage = DAMAGE_NO;
p.solid = SOLID_NOT;
p.movetype = MOVETYPE_NONE;
p.modelindex = 0;
setorigin(p, pos.origin);
p = find(p, classname, "player");
}
// wait for 1 second
entity timer = spawn();
timer.think = shub_finale_1;
timer.nextthink = time + 1;
};
/*==========
shub_pain
==========*/
void (entity attacker, float damage) shub_pain =
{
self.health = 40000;
};
/*QUAKED monster_oldone (1 0 0) (-160 -128 -24) (128 128 256)
{ model ("progs/oldone.mdl"); }
Shub-Niggurath.
*/
void() monster_oldone =
{
if (deathmatch)
{
remove(self);
return;
}
precache_model2 ("progs/oldone.mdl");
precache_model ("progs/dplayer.mdl");
precache_sound2 ("boss2/death.wav");
precache_sound2 ("boss2/idle.wav");
precache_sound2 ("boss2/sight.wav");
precache_sound2 ("boss2/pop2.wav");
self.solid = SOLID_SLIDEBOX;
self.movetype = MOVETYPE_STEP;
setmodel (self, "progs/oldone.mdl");
setsize (self, '-160 -128 -24', '160 128 256');
self.health = 40000; // kill by telefrag
self.takedamage = DAMAGE_YES;
self.th_pain = shub_pain;
self.th_die = shub_die;
shub = self;
total_monsters = total_monsters + 1;
self.think = shub_idle;
self.nextthink = time + 0.1;
};

View File

@@ -0,0 +1,229 @@
/*
==============================================================================
SHAL-RATH
==============================================================================
*/
$cd id1/models/shalrath
$origin 0 0 24
$base base
$skin skin
$scale 0.7
$frame attack1 attack2 attack3 attack4 attack5 attack6 attack7 attack8
$frame attack9 attack10 attack11
$frame pain1 pain2 pain3 pain4 pain5
$frame death1 death2 death3 death4 death5 death6 death7
$frame idle1 idle2 idle3 idle4 idle5 idle6 idle7 idle8 idle9
$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 walk9 walk10
$frame walk11 walk12
void(entity attacker, float damage) shalrath_pain;
void() ShalMissile;
void() shal_stand1 =[ $idle1, shal_stand2 ] {ai_stand();};
void() shal_stand2 =[ $idle2, shal_stand3 ] {ai_stand();};
void() shal_stand3 =[ $idle3, shal_stand4 ] {ai_stand();};
void() shal_stand4 =[ $idle4, shal_stand5 ] {ai_stand();};
void() shal_stand5 =[ $idle5, shal_stand6 ] {ai_stand();};
void() shal_stand6 =[ $idle6, shal_stand7 ] {ai_stand();};
void() shal_stand7 =[ $idle7, shal_stand8 ] {ai_stand();};
void() shal_stand8 =[ $idle8, shal_stand9 ] {ai_stand();};
void() shal_stand9 =[ $idle9, shal_stand1 ] {ai_stand();};
void() shal_walk1 =[ $walk1, shal_walk2 ] {ai_walk(5);};
void() shal_walk2 =[ $walk2, shal_walk3 ] {if (random() < 0.2) sound (self, CHAN_VOICE, "shalrath/idle.wav", 1, ATTN_IDLE);ai_walk(6);};
void() shal_walk3 =[ $walk3, shal_walk4 ] {ai_walk(4);};
void() shal_walk4 =[ $walk4, shal_walk5 ] {ai_walk(0);};
void() shal_walk5 =[ $walk5, shal_walk6 ] {ai_walk(0);};
void() shal_walk6 =[ $walk6, shal_walk7 ] {ai_walk(0);};
void() shal_walk7 =[ $walk7, shal_walk8 ] {ai_walk(0);};
void() shal_walk8 =[ $walk8, shal_walk9 ] {ai_walk(5);};
void() shal_walk9 =[ $walk9, shal_walk10 ] {ai_walk(6);};
void() shal_walk10 =[ $walk10, shal_walk11 ] {ai_walk(5);};
void() shal_walk11 =[ $walk11, shal_walk12 ] {ai_walk(0);};
void() shal_walk12 =[ $walk12, shal_walk1 ] {ai_walk(4);};
void() shal_run1 =[ $walk1, shal_run2 ] {ai_run(5);};
void() shal_run2 =[ $walk2, shal_run3 ] {
if (random() < 0.2)
sound (self, CHAN_VOICE, "shalrath/idle.wav", 1, ATTN_IDLE);
ai_run(6);};
void() shal_run3 =[ $walk3, shal_run4 ] {ai_run(4);};
void() shal_run4 =[ $walk4, shal_run5 ] {ai_run(0);};
void() shal_run5 =[ $walk5, shal_run6 ] {ai_run(0);};
void() shal_run6 =[ $walk6, shal_run7 ] {ai_run(0);};
void() shal_run7 =[ $walk7, shal_run8 ] {ai_run(0);};
void() shal_run8 =[ $walk8, shal_run9 ] {ai_run(5);};
void() shal_run9 =[ $walk9, shal_run10 ] {ai_run(6);};
void() shal_run10 =[ $walk10, shal_run11 ] {ai_run(5);};
void() shal_run11 =[ $walk11, shal_run12 ] {ai_run(0);};
void() shal_run12 =[ $walk12, shal_run1 ] {ai_run(4);};
void() shal_attack1 =[ $attack1, shal_attack2 ] {
sound (self, CHAN_VOICE, "shalrath/attack.wav", 1, ATTN_NORM);
ai_face();
};
void() shal_attack2 =[ $attack2, shal_attack3 ] {ai_face();};
void() shal_attack3 =[ $attack3, shal_attack4 ] {ai_face();};
void() shal_attack4 =[ $attack4, shal_attack5 ] {ai_face();};
void() shal_attack5 =[ $attack5, shal_attack6 ] {ai_face();};
void() shal_attack6 =[ $attack6, shal_attack7 ] {ai_face();};
void() shal_attack7 =[ $attack7, shal_attack8 ] {ai_face();};
void() shal_attack8 =[ $attack8, shal_attack9 ] {ai_face();};
void() shal_attack9 =[ $attack9, shal_attack10 ] {ShalMissile();};
void() shal_attack10 =[ $attack10, shal_attack11 ] {ai_face();};
void() shal_attack11 =[ $attack11, shal_run1 ] {};
void() shal_pain1 =[ $pain1, shal_pain2 ] {};
void() shal_pain2 =[ $pain2, shal_pain3 ] {};
void() shal_pain3 =[ $pain3, shal_pain4 ] {};
void() shal_pain4 =[ $pain4, shal_pain5 ] {};
void() shal_pain5 =[ $pain5, shal_run1 ] {};
void() shal_death1 =[ $death1, shal_death2 ] {};
void() shal_death2 =[ $death2, shal_death3 ] {};
void() shal_death3 =[ $death3, shal_death4 ] {};
void() shal_death4 =[ $death4, shal_death5 ] {};
void() shal_death5 =[ $death5, shal_death6 ] {};
void() shal_death6 =[ $death6, shal_death7 ] {};
void() shal_death7 =[ $death7, shal_death7 ] {};
void(entity attacker, float damage) shalrath_pain =
{
if (self.pain_finished > time)
return;
sound (self, CHAN_VOICE, "shalrath/pain.wav", 1, ATTN_NORM);
self.pain_finished = time + 3;
shal_pain1();
};
void(entity inflictor, entity attacker) shalrath_die =
{
// check for gib
if (self.health < -90)
{
SpawnGib("progs/gib1.mdl");
SpawnGib("progs/gib2.mdl");
SpawnGib("progs/gib3.mdl");
SpawnGib("progs/gib4.mdl");
SpawnGib("progs/gib5.mdl");
SpawnGib("progs/blood.mdl");
SpawnGib("progs/blood.mdl");
BecomeGibs();
return;
}
// regular death
sound (self, CHAN_VOICE, "shalrath/death.wav", 1, ATTN_NORM);
self.solid = SOLID_NOT;
shal_death1();
};
/*
================
ShalMissile
================
*/
void() ShalMissileTouch;
void() ShalHome;
void() ShalMissile =
{
local entity missile;
local vector dir;
local float dist, flytime;
dir = normalize((self.enemy.origin + '0 0 10') - self.origin);
dist = vlen (self.enemy.origin - self.origin);
flytime = dist * 0.002;
if (flytime < 0.1)
flytime = 0.1;
self.effects = self.effects | EF_MUZZLEFLASH;
sound (self, CHAN_WEAPON, "shalrath/attack2.wav", 1, ATTN_NORM);
missile = spawn ();
missile.owner = self;
missile.solid = SOLID_BBOX;
missile.movetype = MOVETYPE_FLYMISSILE;
setmodel (missile, "progs/v_spike.mdl");
setsize (missile, '0 0 0', '0 0 0');
missile.origin = self.origin + '0 8 20';
missile.velocity = dir * 400;
missile.avelocity = '300 300 300';
missile.think = ShalHome;
missile.nextthink = time + flytime;
missile.enemy = self.enemy;
missile.touch = ShalMissileTouch;
};
void() ShalHome =
{
if (self.enemy.health <= 0)
return;
if (self.owner.health <= 0 && skill < 2)
return;
vector dir = normalize(self.enemy.origin + '0 0 10' - self.origin);
if (skill == 3)
self.velocity = dir * 350;
else
self.velocity = dir * 250;
self.nextthink = time + 0.2;
self.think = ShalHome;
};
void() ShalMissileTouch =
{
RadiusDamage (self, self.owner, 40, world);
te_tarexplosion(self.origin);
remove(self);
};
//=================================================================
/*QUAKED monster_shalrath (1 0 0) (-32 -32 -24) (32 32 48) Ambush
{
model ({ "path" : "progs/shalrath.mdl", "frame": 23 });
}
Vore.
*/
void() monster_shalrath =
{
if (deathmatch)
{
remove(self);
return;
}
precache_model2 ("progs/shalrath.mdl");
precache_model2 ("progs/h_shal.mdl");
precache_model2 ("progs/v_spike.mdl");
precache_sound2 ("shalrath/attack.wav");
precache_sound2 ("shalrath/attack2.wav");
precache_sound2 ("shalrath/death.wav");
precache_sound2 ("shalrath/idle.wav");
precache_sound2 ("shalrath/pain.wav");
precache_sound2 ("shalrath/sight.wav");
self.th_stand = shal_stand1;
self.th_walk = shal_walk1;
self.th_run = shal_run1;
self.th_die = shalrath_die;
self.th_pain = shalrath_pain;
self.th_missile = shal_attack1;
monster_start("progs/shalrath.mdl", "progs/h_shal.mdl", 400, 0, VEC_HULL2_MIN, VEC_HULL2_MAX);
};

View File

@@ -0,0 +1,352 @@
/*
==============================================================================
SHAMBLER
==============================================================================
*/
$cd id1/models/shams
$origin 0 0 24
$base base
$skin base
$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8 stand9
$frame stand10 stand11 stand12 stand13 stand14 stand15 stand16 stand17
$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7
$frame walk8 walk9 walk10 walk11 walk12
$frame run1 run2 run3 run4 run5 run6
$frame smash1 smash2 smash3 smash4 smash5 smash6 smash7
$frame smash8 smash9 smash10 smash11 smash12
$frame swingr1 swingr2 swingr3 swingr4 swingr5
$frame swingr6 swingr7 swingr8 swingr9
$frame swingl1 swingl2 swingl3 swingl4 swingl5
$frame swingl6 swingl7 swingl8 swingl9
$frame magic1 magic2 magic3 magic4 magic5
$frame magic6 magic7 magic8 magic9 magic10 magic11 magic12
$frame pain1 pain2 pain3 pain4 pain5 pain6
$frame death1 death2 death3 death4 death5 death6
$frame death7 death8 death9 death10 death11
void() sham_stand1 =[ $stand1, sham_stand2 ] {ai_stand();};
void() sham_stand2 =[ $stand2, sham_stand3 ] {ai_stand();};
void() sham_stand3 =[ $stand3, sham_stand4 ] {ai_stand();};
void() sham_stand4 =[ $stand4, sham_stand5 ] {ai_stand();};
void() sham_stand5 =[ $stand5, sham_stand6 ] {ai_stand();};
void() sham_stand6 =[ $stand6, sham_stand7 ] {ai_stand();};
void() sham_stand7 =[ $stand7, sham_stand8 ] {ai_stand();};
void() sham_stand8 =[ $stand8, sham_stand9 ] {ai_stand();};
void() sham_stand9 =[ $stand9, sham_stand10] {ai_stand();};
void() sham_stand10 =[ $stand10, sham_stand11] {ai_stand();};
void() sham_stand11 =[ $stand11, sham_stand12] {ai_stand();};
void() sham_stand12 =[ $stand12, sham_stand13] {ai_stand();};
void() sham_stand13 =[ $stand13, sham_stand14] {ai_stand();};
void() sham_stand14 =[ $stand14, sham_stand15] {ai_stand();};
void() sham_stand15 =[ $stand15, sham_stand16] {ai_stand();};
void() sham_stand16 =[ $stand16, sham_stand17] {ai_stand();};
void() sham_stand17 =[ $stand17, sham_stand1 ] {ai_stand();};
void() sham_walk1 =[ $walk1, sham_walk2 ] {ai_walk(10);};
void() sham_walk2 =[ $walk2, sham_walk3 ] {ai_walk(9);};
void() sham_walk3 =[ $walk3, sham_walk4 ] {ai_walk(9);};
void() sham_walk4 =[ $walk4, sham_walk5 ] {ai_walk(5);};
void() sham_walk5 =[ $walk5, sham_walk6 ] {ai_walk(6);};
void() sham_walk6 =[ $walk6, sham_walk7 ] {ai_walk(12);};
void() sham_walk7 =[ $walk7, sham_walk8 ] {ai_walk(8);};
void() sham_walk8 =[ $walk8, sham_walk9 ] {ai_walk(3);};
void() sham_walk9 =[ $walk9, sham_walk10] {ai_walk(13);};
void() sham_walk10 =[ $walk10, sham_walk11] {ai_walk(9);};
void() sham_walk11 =[ $walk11, sham_walk12] {ai_walk(7);};
void() sham_walk12 =[ $walk12, sham_walk1 ] {ai_walk(7);
if (random() > 0.8)
sound (self, CHAN_VOICE, "shambler/sidle.wav", 1, ATTN_IDLE);};
void() sham_run1 =[ $run1, sham_run2 ] {ai_run(20);};
void() sham_run2 =[ $run2, sham_run3 ] {ai_run(24);};
void() sham_run3 =[ $run3, sham_run4 ] {ai_run(20);};
void() sham_run4 =[ $run4, sham_run5 ] {ai_run(20);};
void() sham_run5 =[ $run5, sham_run6 ] {ai_run(24);};
void() sham_run6 =[ $run6, sham_run1 ] {ai_run(20);
if (random() > 0.8)
sound (self, CHAN_VOICE, "shambler/sidle.wav", 1, ATTN_IDLE);
};
void() sham_smash1 =[ $smash1, sham_smash2 ] {
sound (self, CHAN_VOICE, "shambler/melee1.wav", 1, ATTN_NORM);
ai_charge(2);};
void() sham_smash2 =[ $smash2, sham_smash3 ] {ai_charge(6);};
void() sham_smash3 =[ $smash3, sham_smash4 ] {ai_charge(6);};
void() sham_smash4 =[ $smash4, sham_smash5 ] {ai_charge(5);};
void() sham_smash5 =[ $smash5, sham_smash6 ] {ai_charge(4);};
void() sham_smash6 =[ $smash6, sham_smash7 ] {ai_charge(1);};
void() sham_smash7 =[ $smash7, sham_smash8 ] {ai_charge(0);};
void() sham_smash8 =[ $smash8, sham_smash9 ] {ai_charge(0);};
void() sham_smash9 =[ $smash9, sham_smash10 ] {ai_charge(0);};
void() sham_smash10 =[ $smash10, sham_smash11 ] {
local vector delta;
local float ldmg;
if (!self.enemy)
return;
ai_charge(0);
delta = self.enemy.origin - self.origin;
if (vlen(delta) > 100)
return;
if (!CanDamage (self.enemy, self))
return;
ldmg = (random() + random() + random()) * 40;
Damage (self.enemy, self, self, ldmg);
sound (self, CHAN_VOICE, "shambler/smack.wav", 1, ATTN_NORM);
SpawnMeatSpray (self.origin + v_forward*16, crandom() * 100 * v_right);
SpawnMeatSpray (self.origin + v_forward*16, crandom() * 100 * v_right);
};
void() sham_smash11 =[ $smash11, sham_smash12 ] {ai_charge(5);};
void() sham_smash12 =[ $smash12, sham_run1 ] {ai_charge(4);};
void() sham_swingr1;
void(float side) ShamClaw =
{
local vector delta;
local float ldmg;
if (!self.enemy)
return;
ai_charge(10);
delta = self.enemy.origin - self.origin;
if (vlen(delta) > 100)
return;
ldmg = (random() + random() + random()) * 20;
Damage (self.enemy, self, self, ldmg);
sound (self, CHAN_VOICE, "shambler/smack.wav", 1, ATTN_NORM);
if (side)
{
makevectors (self.angles);
SpawnMeatSpray (self.origin + v_forward*16, side * v_right);
}
};
void() sham_swingl1 =[ $swingl1, sham_swingl2 ] {
sound (self, CHAN_VOICE, "shambler/melee2.wav", 1, ATTN_NORM);
ai_charge(5);};
void() sham_swingl2 =[ $swingl2, sham_swingl3 ] {ai_charge(3);};
void() sham_swingl3 =[ $swingl3, sham_swingl4 ] {ai_charge(7);};
void() sham_swingl4 =[ $swingl4, sham_swingl5 ] {ai_charge(3);};
void() sham_swingl5 =[ $swingl5, sham_swingl6 ] {ai_charge(7);};
void() sham_swingl6 =[ $swingl6, sham_swingl7 ] {ai_charge(9);};
void() sham_swingl7 =[ $swingl7, sham_swingl8 ] {ai_charge(5); ShamClaw(250);};
void() sham_swingl8 =[ $swingl8, sham_swingl9 ] {ai_charge(4);};
void() sham_swingl9 =[ $swingl9, sham_run1 ] {
ai_charge(8);
if (random()<0.5)
self.think = sham_swingr1;
};
void() sham_swingr1 =[ $swingr1, sham_swingr2 ] {
sound (self, CHAN_VOICE, "shambler/melee1.wav", 1, ATTN_NORM);
ai_charge(1);};
void() sham_swingr2 =[ $swingr2, sham_swingr3 ] {ai_charge(8);};
void() sham_swingr3 =[ $swingr3, sham_swingr4 ] {ai_charge(14);};
void() sham_swingr4 =[ $swingr4, sham_swingr5 ] {ai_charge(7);};
void() sham_swingr5 =[ $swingr5, sham_swingr6 ] {ai_charge(3);};
void() sham_swingr6 =[ $swingr6, sham_swingr7 ] {ai_charge(6);};
void() sham_swingr7 =[ $swingr7, sham_swingr8 ] {ai_charge(6); ShamClaw(-250);};
void() sham_swingr8 =[ $swingr8, sham_swingr9 ] {ai_charge(3);};
void() sham_swingr9 =[ $swingr9, sham_run1 ] {ai_charge(1);
ai_charge(10);
if (random()<0.5)
self.think = sham_swingl1;
};
void() sham_melee =
{
local float chance;
chance = random();
if (chance > 0.6 || self.health == 600)
sham_smash1 ();
else if (chance > 0.3)
sham_swingr1 ();
else
sham_swingl1 ();
};
//============================================================================
void() CastLightning =
{
local vector org, dir;
self.effects = self.effects | EF_MUZZLEFLASH;
ai_face ();
org = self.origin + '0 0 40';
dir = self.enemy.origin + '0 0 16' - org;
dir = normalize (dir);
traceline (org, self.origin + dir*600, TRUE, self);
te_lightning1(org, trace_endpos, self);
LightningDamage (org, trace_endpos, self, 10);
};
void() sham_magic1 =[ $magic1, sham_magic2 ] {ai_face();
sound (self, CHAN_WEAPON, "shambler/sattck1.wav", 1, ATTN_NORM);
};
void() sham_magic2 =[ $magic2, sham_magic3 ] {ai_face();};
void() sham_magic3 =[ $magic3, sham_magic4 ] {ai_face();self.nextthink = self.nextthink + 0.2;
self.effects = self.effects | EF_MUZZLEFLASH;
ai_face();
self.aiment = spawn();
setmodel (self.aiment, "progs/s_light.mdl");
setorigin (self.aiment, self.origin);
self.aiment.angles = self.angles;
self.aiment.think = SUB_Remove;
self.aiment.nextthink = time + 0.3;
};
void() sham_magic4 =[ $magic4, sham_magic5 ]
{
self.effects = self.effects | EF_MUZZLEFLASH;
self.aiment.frame = 1;
self.aiment.nextthink = time + 0.2;
};
void() sham_magic5 =[ $magic5, sham_magic6 ]
{
self.effects = self.effects | EF_MUZZLEFLASH;
self.aiment.frame = 2;
self.aiment.nextthink = time + 0.2;
};
void() sham_magic6 =[ $magic6, sham_magic9 ]
{
remove (self.aiment);
CastLightning();
sound (self, CHAN_WEAPON, "shambler/sboom.wav", 1, ATTN_NORM);
};
void() sham_magic9 =[ $magic9, sham_magic10 ]
{CastLightning();};
void() sham_magic10 =[ $magic10, sham_magic11 ]
{CastLightning();};
void() sham_magic11 =[ $magic11, sham_magic12 ]
{
if (skill == 3)
CastLightning();
};
void() sham_magic12 =[ $magic12, sham_run1 ] {};
void() sham_pain1 =[ $pain1, sham_pain2 ] {};
void() sham_pain2 =[ $pain2, sham_pain3 ] {};
void() sham_pain3 =[ $pain3, sham_pain4 ] {};
void() sham_pain4 =[ $pain4, sham_pain5 ] {};
void() sham_pain5 =[ $pain5, sham_pain6 ] {};
void() sham_pain6 =[ $pain6, sham_run1 ] {};
void(entity attacker, float damage) sham_pain =
{
if (random()*400 > damage)
return;
if (self.pain_finished > time)
return;
sound (self, CHAN_VOICE, "shambler/shurt2.wav", 1, ATTN_NORM);
self.pain_finished = time + 2;
sham_pain1();
};
//============================================================================
void() sham_death1 =[ $death1, sham_death2 ] {};
void() sham_death2 =[ $death2, sham_death3 ] {};
void() sham_death3 =[ $death3, sham_death4 ] {};
void() sham_death4 =[ $death4, sham_death5 ] {};
void() sham_death5 =[ $death5, sham_death6 ] {};
void() sham_death6 =[ $death6, sham_death7 ] {};
void() sham_death7 =[ $death7, sham_death8 ] {};
void() sham_death8 =[ $death8, sham_death9 ] {};
void() sham_death9 =[ $death9, sham_death10 ] {};
void() sham_death10 =[ $death10, sham_death11 ] {};
void() sham_death11 =[ $death11, sham_death11 ] {};
void(entity inflictor, entity attacker) sham_die =
{
// check for gib
if (self.health < -60)
{
SpawnGib("progs/gib3.mdl");
SpawnGib("progs/gib3.mdl");
SpawnGib("progs/gib3.mdl");
SpawnGib("progs/gib4.mdl");
SpawnGib("progs/gib5.mdl");
SpawnGib("progs/blood.mdl");
SpawnGib("progs/blood.mdl");
BecomeGibs();
return;
}
// regular death
self.solid = SOLID_NOT;
sound(self, CHAN_VOICE, "shambler/sdeath.wav", 1, ATTN_NORM);
sham_death1();
};
//============================================================================
/*QUAKED monster_shambler (1 0 0) (-32 -32 -24) (32 32 64) Ambush
{
model ("progs/shambler.mdl");
}
Shambler.
*/
void() monster_shambler =
{
if (deathmatch)
{
remove(self);
return;
}
precache_model ("progs/shambler.mdl");
precache_model ("progs/s_light.mdl");
precache_model ("progs/h_shams.mdl");
precache_model ("progs/bolt.mdl");
precache_sound ("shambler/sattck1.wav");
precache_sound ("shambler/sboom.wav");
precache_sound ("shambler/sdeath.wav");
precache_sound ("shambler/shurt2.wav");
precache_sound ("shambler/sidle.wav");
precache_sound ("shambler/ssight.wav");
precache_sound ("shambler/melee1.wav");
precache_sound ("shambler/melee2.wav");
precache_sound ("shambler/smack.wav");
self.th_stand = sham_stand1;
self.th_walk = sham_walk1;
self.th_run = sham_run1;
self.th_die = sham_die;
self.th_melee = sham_melee;
self.th_missile = sham_magic1;
self.th_pain = sham_pain;
monster_start("progs/shambler.mdl", "progs/h_shams.mdl", 600, 0, VEC_HULL2_MIN, VEC_HULL2_MAX);
};

View File

@@ -0,0 +1,244 @@
$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8
$frame death1 death2 death3 death4 death5 death6 death7 death8
$frame death9 death10
$frame deathc1 deathc2 deathc3 deathc4 deathc5 deathc6 deathc7 deathc8
$frame deathc9 deathc10 deathc11
$frame load1 load2 load3 load4 load5 load6 load7 load8 load9 load10 load11
$frame pain1 pain2 pain3 pain4 pain5 pain6
$frame painb1 painb2 painb3 painb4 painb5 painb6 painb7 painb8 painb9 painb10
$frame painb11 painb12 painb13 painb14
$frame painc1 painc2 painc3 painc4 painc5 painc6 painc7 painc8 painc9 painc10
$frame painc11 painc12 painc13
$frame run1 run2 run3 run4 run5 run6 run7 run8
$frame shoot1 shoot2 shoot3 shoot4 shoot5 shoot6 shoot7 shoot8 shoot9
$frame prowl_1 prowl_2 prowl_3 prowl_4 prowl_5 prowl_6 prowl_7 prowl_8
$frame prowl_9 prowl_10 prowl_11 prowl_12 prowl_13 prowl_14 prowl_15 prowl_16
$frame prowl_17 prowl_18 prowl_19 prowl_20 prowl_21 prowl_22 prowl_23 prowl_24
void() army_stand1 =[ $stand1, army_stand2 ] {
if (random() < 0.1)
sound (self, CHAN_VOICE, "soldier/idle.wav", 1, ATTN_IDLE);
ai_stand();};
void() army_stand2 =[ $stand2, army_stand3 ] {ai_stand();};
void() army_stand3 =[ $stand3, army_stand4 ] {ai_stand();};
void() army_stand4 =[ $stand4, army_stand5 ] {ai_stand();};
void() army_stand5 =[ $stand5, army_stand6 ] {ai_stand();};
void() army_stand6 =[ $stand6, army_stand7 ] {ai_stand();};
void() army_stand7 =[ $stand7, army_stand8 ] {ai_stand();};
void() army_stand8 =[ $stand8, army_stand1 ] {ai_stand();};
void() army_walk1 =[ $prowl_1, army_walk2 ] {
if (random() < 0.2)
sound (self, CHAN_VOICE, "soldier/idle.wav", 1, ATTN_IDLE);
ai_walk(1);};
void() army_walk2 =[ $prowl_2, army_walk3 ] {ai_walk(1);};
void() army_walk3 =[ $prowl_3, army_walk4 ] {ai_walk(1);};
void() army_walk4 =[ $prowl_4, army_walk5 ] {ai_walk(1);};
void() army_walk5 =[ $prowl_5, army_walk6 ] {ai_walk(2);};
void() army_walk6 =[ $prowl_6, army_walk7 ] {ai_walk(3);};
void() army_walk7 =[ $prowl_7, army_walk8 ] {ai_walk(4);};
void() army_walk8 =[ $prowl_8, army_walk9 ] {ai_walk(4);};
void() army_walk9 =[ $prowl_9, army_walk10 ] {ai_walk(2);};
void() army_walk10 =[ $prowl_10, army_walk11 ] {ai_walk(2);};
void() army_walk11 =[ $prowl_11, army_walk12 ] {ai_walk(2);};
void() army_walk12 =[ $prowl_12, army_walk13 ] {ai_walk(1);};
void() army_walk13 =[ $prowl_13, army_walk14 ] {ai_walk(0);};
void() army_walk14 =[ $prowl_14, army_walk15 ] {ai_walk(1);};
void() army_walk15 =[ $prowl_15, army_walk16 ] {ai_walk(1);};
void() army_walk16 =[ $prowl_16, army_walk17 ] {ai_walk(1);};
void() army_walk17 =[ $prowl_17, army_walk18 ] {ai_walk(3);};
void() army_walk18 =[ $prowl_18, army_walk19 ] {ai_walk(3);};
void() army_walk19 =[ $prowl_19, army_walk20 ] {ai_walk(3);};
void() army_walk20 =[ $prowl_20, army_walk21 ] {ai_walk(3);};
void() army_walk21 =[ $prowl_21, army_walk22 ] {ai_walk(2);};
void() army_walk22 =[ $prowl_22, army_walk23 ] {ai_walk(1);};
void() army_walk23 =[ $prowl_23, army_walk24 ] {ai_walk(1);};
void() army_walk24 =[ $prowl_24, army_walk1 ] {ai_walk(1);};
void() army_run1 =[ $run1, army_run2 ] {
if (random() < 0.1)
sound (self, CHAN_VOICE, "soldier/idle.wav", 1, ATTN_IDLE);
ai_run(11);};
void() army_run2 =[ $run2, army_run3 ] {ai_run(15);};
void() army_run3 =[ $run3, army_run4 ] {ai_run(10);};
void() army_run4 =[ $run4, army_run5 ] {ai_run(10);};
void() army_run5 =[ $run5, army_run6 ] {ai_run(8);};
void() army_run6 =[ $run6, army_run7 ] {ai_run(15);};
void() army_run7 =[ $run7, army_run8 ] {ai_run(10);};
void() army_run8 =[ $run8, army_run1 ] {ai_run(8);};
void() army_fire =
{
self.effects = self.effects | EF_MUZZLEFLASH;
sound (self, CHAN_WEAPON, "weapons/guncock.wav", 1, ATTN_NORM);
vector dir = self.enemy.origin - self.enemy.velocity * 0.2;
dir = normalize (dir - self.origin);
FireBullets (4, dir, '0.1 0.1 0');
};
void() army_atk1 =[ $shoot1, army_atk2 ] {ai_face();};
void() army_atk2 =[ $shoot2, army_atk3 ] {ai_face();};
void() army_atk3 =[ $shoot3, army_atk4 ] {ai_face();};
void() army_atk4 =[ $shoot4, army_atk5 ] {ai_face();};
void() army_atk5 =[ $shoot5, army_atk6 ] {ai_face();army_fire();};
void() army_atk6 =[ $shoot6, army_atk7 ] {ai_face();};
void() army_atk7 =[ $shoot7, army_atk8 ] {ai_face();};
void() army_atk8 =[ $shoot8, army_atk9 ] {ai_face();};
void() army_atk9 =[ $shoot9, army_run1 ] {ai_face();};
void() army_pain1 =[ $pain1, army_pain2 ] {};
void() army_pain2 =[ $pain2, army_pain3 ] {};
void() army_pain3 =[ $pain3, army_pain4 ] {};
void() army_pain4 =[ $pain4, army_pain5 ] {};
void() army_pain5 =[ $pain5, army_pain6 ] {};
void() army_pain6 =[ $pain6, army_run1 ] {ai_pain(1);};
void() army_painb1 =[ $painb1, army_painb2 ] {};
void() army_painb2 =[ $painb2, army_painb3 ] {ai_painforward(13);};
void() army_painb3 =[ $painb3, army_painb4 ] {ai_painforward(9);};
void() army_painb4 =[ $painb4, army_painb5 ] {};
void() army_painb5 =[ $painb5, army_painb6 ] {};
void() army_painb6 =[ $painb6, army_painb7 ] {};
void() army_painb7 =[ $painb7, army_painb8 ] {};
void() army_painb8 =[ $painb8, army_painb9 ] {};
void() army_painb9 =[ $painb9, army_painb10] {};
void() army_painb10=[ $painb10, army_painb11] {};
void() army_painb11=[ $painb11, army_painb12] {};
void() army_painb12=[ $painb12, army_painb13] {ai_pain(2);};
void() army_painb13=[ $painb13, army_painb14] {};
void() army_painb14=[ $painb14, army_run1 ] {};
void() army_painc1 =[ $painc1, army_painc2 ] {};
void() army_painc2 =[ $painc2, army_painc3 ] {ai_pain(1);};
void() army_painc3 =[ $painc3, army_painc4 ] {};
void() army_painc4 =[ $painc4, army_painc5 ] {};
void() army_painc5 =[ $painc5, army_painc6 ] {ai_painforward(1);};
void() army_painc6 =[ $painc6, army_painc7 ] {ai_painforward(1);};
void() army_painc7 =[ $painc7, army_painc8 ] {};
void() army_painc8 =[ $painc8, army_painc9 ] {ai_pain(1);};
void() army_painc9 =[ $painc9, army_painc10] {ai_painforward(4);};
void() army_painc10=[ $painc10, army_painc11] {ai_painforward(3);};
void() army_painc11=[ $painc11, army_painc12] {ai_painforward(6);};
void() army_painc12=[ $painc12, army_painc13] {ai_painforward(8);};
void() army_painc13=[ $painc13, army_run1] {};
void(entity attacker, float damage) army_pain =
{
if (self.pain_finished > time)
return;
float r = random();
if (r < 0.2)
{
self.pain_finished = time + 0.6;
army_pain1 ();
sound (self, CHAN_VOICE, "soldier/pain1.wav", 1, ATTN_NORM);
}
else if (r < 0.6)
{
self.pain_finished = time + 1.1;
army_painb1 ();
sound (self, CHAN_VOICE, "soldier/pain2.wav", 1, ATTN_NORM);
}
else
{
self.pain_finished = time + 1.1;
army_painc1 ();
sound (self, CHAN_VOICE, "soldier/pain2.wav", 1, ATTN_NORM);
}
};
void() army_die1 =[ $death1, army_die2 ] {};
void() army_die2 =[ $death2, army_die3 ] {};
void() army_die3 =[ $death3, army_die4 ] {DropBackpack();};
void() army_die4 =[ $death4, army_die5 ] {};
void() army_die5 =[ $death5, army_die6 ] {};
void() army_die6 =[ $death6, army_die7 ] {};
void() army_die7 =[ $death7, army_die8 ] {};
void() army_die8 =[ $death8, army_die9 ] {};
void() army_die9 =[ $death9, army_die10 ] {};
void() army_die10 =[ $death10, army_die10 ] {};
void() army_cdie1 =[ $deathc1, army_cdie2 ] {};
void() army_cdie2 =[ $deathc2, army_cdie3 ] {ai_back(5);};
void() army_cdie3 =[ $deathc3, army_cdie4 ] {DropBackpack();ai_back(4);};
void() army_cdie4 =[ $deathc4, army_cdie5 ] {ai_back(13);};
void() army_cdie5 =[ $deathc5, army_cdie6 ] {ai_back(3);};
void() army_cdie6 =[ $deathc6, army_cdie7 ] {ai_back(4);};
void() army_cdie7 =[ $deathc7, army_cdie8 ] {};
void() army_cdie8 =[ $deathc8, army_cdie9 ] {};
void() army_cdie9 =[ $deathc9, army_cdie10 ] {};
void() army_cdie10 =[ $deathc10, army_cdie11 ] {};
void() army_cdie11 =[ $deathc11, army_cdie11 ] {};
void(entity inflictor, entity attacker) army_die =
{
// check for gib
if (self.health < -35)
{
SpawnGib("progs/gib1.mdl");
SpawnGib("progs/gib2.mdl");
SpawnGib("progs/gib3.mdl");
SpawnGib("progs/gib4.mdl");
SpawnGib("progs/gib5.mdl");
SpawnGib("progs/blood.mdl");
BecomeGibs();
return;
}
// regular death
sound (self, CHAN_VOICE, "soldier/death1.wav", 1, ATTN_NORM);
self.solid = SOLID_NOT;
if (random() < 0.5)
army_die1 ();
else
army_cdie1 ();
};
/*QUAKED monster_army (1 0 0) (-16 -16 -24) (16 16 40) Ambush
{
model ("progs/soldier.mdl");
}
Grunt.
*/
void() monster_army =
{
if (deathmatch)
{
remove(self);
return;
}
precache_model ("progs/soldier.mdl");
precache_model ("progs/h_guard.mdl");
precache_sound ("soldier/death1.wav");
precache_sound ("soldier/idle.wav");
precache_sound ("soldier/pain1.wav");
precache_sound ("soldier/pain2.wav");
precache_sound ("soldier/sight1.wav");
precache_sound ("weapons/guncock.wav");
self.th_stand = army_stand1;
self.th_walk = army_walk1;
self.th_run = army_run1;
self.th_missile = army_atk1;
self.th_pain = army_pain;
self.th_die = army_die;
self.ammo_shells = 5;
monster_start("progs/soldier.mdl", "progs/h_guard.mdl", 30, 0, '-16 -16 -24', '16 16 40');
};

View File

@@ -0,0 +1,221 @@
/*
==============================================================================
BLOB
==============================================================================
*/
$cd id1/models/tarbaby
$origin 0 0 24
$base base
$skin skin
$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 walk9 walk10
$frame walk11 walk12 walk13 walk14 walk15 walk16 walk17 walk18 walk19
$frame walk20 walk21 walk22 walk23 walk24 walk25
$frame run1 run2 run3 run4 run5 run6 run7 run8 run9 run10 run11 run12 run13
$frame run14 run15 run16 run17 run18 run19 run20 run21 run22 run23
$frame run24 run25
$frame jump1 jump2 jump3 jump4 jump5 jump6
$frame fly1 fly2 fly3 fly4
$frame exp
void() tbaby_stand1 =[ $walk1, tbaby_stand1 ] {ai_stand();};
void() tbaby_hang1 =[ $walk1, tbaby_hang1 ] {ai_stand();};
void() tbaby_walk1 =[ $walk1, tbaby_walk2 ] {ai_turn();};
void() tbaby_walk2 =[ $walk2, tbaby_walk3 ] {ai_turn();};
void() tbaby_walk3 =[ $walk3, tbaby_walk4 ] {ai_turn();};
void() tbaby_walk4 =[ $walk4, tbaby_walk5 ] {ai_turn();};
void() tbaby_walk5 =[ $walk5, tbaby_walk6 ] {ai_turn();};
void() tbaby_walk6 =[ $walk6, tbaby_walk7 ] {ai_turn();};
void() tbaby_walk7 =[ $walk7, tbaby_walk8 ] {ai_turn();};
void() tbaby_walk8 =[ $walk8, tbaby_walk9 ] {ai_turn();};
void() tbaby_walk9 =[ $walk9, tbaby_walk10 ] {ai_turn();};
void() tbaby_walk10 =[ $walk10, tbaby_walk11 ] {ai_turn();};
void() tbaby_walk11 =[ $walk11, tbaby_walk12 ] {ai_walk(2);};
void() tbaby_walk12 =[ $walk12, tbaby_walk13 ] {ai_walk(2);};
void() tbaby_walk13 =[ $walk13, tbaby_walk14 ] {ai_walk(2);};
void() tbaby_walk14 =[ $walk14, tbaby_walk15 ] {ai_walk(2);};
void() tbaby_walk15 =[ $walk15, tbaby_walk16 ] {ai_walk(2);};
void() tbaby_walk16 =[ $walk16, tbaby_walk17 ] {ai_walk(2);};
void() tbaby_walk17 =[ $walk17, tbaby_walk18 ] {ai_walk(2);};
void() tbaby_walk18 =[ $walk18, tbaby_walk19 ] {ai_walk(2);};
void() tbaby_walk19 =[ $walk19, tbaby_walk20 ] {ai_walk(2);};
void() tbaby_walk20 =[ $walk20, tbaby_walk21 ] {ai_walk(2);};
void() tbaby_walk21 =[ $walk21, tbaby_walk22 ] {ai_walk(2);};
void() tbaby_walk22 =[ $walk22, tbaby_walk23 ] {ai_walk(2);};
void() tbaby_walk23 =[ $walk23, tbaby_walk24 ] {ai_walk(2);};
void() tbaby_walk24 =[ $walk24, tbaby_walk25 ] {ai_walk(2);};
void() tbaby_walk25 =[ $walk25, tbaby_walk1 ] {ai_walk(2);};
void() tbaby_run1 =[ $run1, tbaby_run2 ] {ai_face();};
void() tbaby_run2 =[ $run2, tbaby_run3 ] {ai_face();};
void() tbaby_run3 =[ $run3, tbaby_run4 ] {ai_face();};
void() tbaby_run4 =[ $run4, tbaby_run5 ] {ai_face();};
void() tbaby_run5 =[ $run5, tbaby_run6 ] {ai_face();};
void() tbaby_run6 =[ $run6, tbaby_run7 ] {ai_face();};
void() tbaby_run7 =[ $run7, tbaby_run8 ] {ai_face();};
void() tbaby_run8 =[ $run8, tbaby_run9 ] {ai_face();};
void() tbaby_run9 =[ $run9, tbaby_run10 ] {ai_face();};
void() tbaby_run10 =[ $run10, tbaby_run11 ] {ai_face();};
void() tbaby_run11 =[ $run11, tbaby_run12 ] {ai_run(2);};
void() tbaby_run12 =[ $run12, tbaby_run13 ] {ai_run(2);};
void() tbaby_run13 =[ $run13, tbaby_run14 ] {ai_run(2);};
void() tbaby_run14 =[ $run14, tbaby_run15 ] {ai_run(2);};
void() tbaby_run15 =[ $run15, tbaby_run16 ] {ai_run(2);};
void() tbaby_run16 =[ $run16, tbaby_run17 ] {ai_run(2);};
void() tbaby_run17 =[ $run17, tbaby_run18 ] {ai_run(2);};
void() tbaby_run18 =[ $run18, tbaby_run19 ] {ai_run(2);};
void() tbaby_run19 =[ $run19, tbaby_run20 ] {ai_run(2);};
void() tbaby_run20 =[ $run20, tbaby_run21 ] {ai_run(2);};
void() tbaby_run21 =[ $run21, tbaby_run22 ] {ai_run(2);};
void() tbaby_run22 =[ $run22, tbaby_run23 ] {ai_run(2);};
void() tbaby_run23 =[ $run23, tbaby_run24 ] {ai_run(2);};
void() tbaby_run24 =[ $run24, tbaby_run25 ] {ai_run(2);};
void() tbaby_run25 =[ $run25, tbaby_run1 ] {ai_run(2);};
//============================================================================
void() tbaby_jump1;
void() Tar_JumpTouch =
{
local float ldmg;
if (other.takedamage && other.classname != self.classname)
{
if ( vlen(self.velocity) > 400 )
{
ldmg = 10 + 10*random();
Damage (other, self, self, ldmg);
sound (self, CHAN_WEAPON, "blob/hit1.wav", 1, ATTN_NORM);
}
}
else
sound (self, CHAN_WEAPON, "blob/land1.wav", 1, ATTN_NORM);
if (!checkbottom(self))
{
if (self.flags & FL_ONGROUND)
{ // jump randomly to not get hung up
//dprint ("popjump\n");
self.touch = SUB_Null;
self.think = tbaby_run1;
self.movetype = MOVETYPE_STEP;
self.nextthink = time + 0.1;
// self.velocity_x = (random() - 0.5) * 600;
// self.velocity_y = (random() - 0.5) * 600;
// self.velocity_z = 200;
// self.flags = self.flags - FL_ONGROUND;
}
return; // not on ground yet
}
self.touch = SUB_Null;
self.think = tbaby_jump1;
self.nextthink = time + 0.1;
};
void() tbaby_jump5;
void() tbaby_fly1 =[ $fly1, tbaby_fly2 ] {};
void() tbaby_fly2 =[ $fly2, tbaby_fly3 ] {};
void() tbaby_fly3 =[ $fly3, tbaby_fly4 ] {};
void() tbaby_fly4 =[ $fly4, tbaby_fly1 ] {
self.cnt = self.cnt + 1;
if (self.cnt == 4)
{
//dprint ("spawn hop\n");
tbaby_jump5 ();
}
};
void() tbaby_jump1 =[ $jump1, tbaby_jump2 ] {ai_face();};
void() tbaby_jump2 =[ $jump2, tbaby_jump3 ] {ai_face();};
void() tbaby_jump3 =[ $jump3, tbaby_jump4 ] {ai_face();};
void() tbaby_jump4 =[ $jump4, tbaby_jump5 ] {ai_face();};
void() tbaby_jump5 =[ $jump5, tbaby_jump6 ]
{
self.movetype = MOVETYPE_BOUNCE;
self.touch = Tar_JumpTouch;
makevectors (self.angles);
self.origin_z = self.origin_z + 1;
self.velocity = v_forward * 600 + '0 0 200';
self.velocity_z = self.velocity_z + random()*150;
if (self.flags & FL_ONGROUND)
self.flags = self.flags - FL_ONGROUND;
self.cnt = 0;
};
void() tbaby_jump6 =[ $jump6,tbaby_fly1 ] {};
//=============================================================================
void() tbaby_die1 =[ $exp, tbaby_die2 ] {self.takedamage = DAMAGE_NO;};
void() tbaby_die2 =[ $exp, tbaby_run1 ]
{
RadiusDamage (self, self, 120, world);
sound (self, CHAN_VOICE, "blob/death1.wav", 1, ATTN_NORM);
self.origin = self.origin - 8*normalize(self.velocity);
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_TAREXPLOSION);
WriteCoord (MSG_BROADCAST, self.origin_x);
WriteCoord (MSG_BROADCAST, self.origin_y);
WriteCoord (MSG_BROADCAST, self.origin_z);
BecomeExplosion ();
};
void(entity inflictor, entity attacker) tbaby_die =
{
tbaby_die1();
};
//=============================================================================
/*QUAKED monster_tarbaby (1 0 0) (-16 -16 -24) (16 16 24) Ambush
{
model ("progs/tarbaby.mdl");
}
Spawn.
*/
void() monster_tarbaby =
{
if (deathmatch)
{
remove(self);
return;
}
precache_model2 ("progs/tarbaby.mdl");
precache_sound2 ("blob/death1.wav");
precache_sound2 ("blob/hit1.wav");
precache_sound2 ("blob/land1.wav");
precache_sound2 ("blob/sight1.wav");
self.th_stand = tbaby_stand1;
self.th_walk = tbaby_walk1;
self.th_run = tbaby_run1;
self.th_missile = tbaby_jump1;
self.th_melee = tbaby_jump1;
self.th_die = tbaby_die;
monster_start("progs/tarbaby.mdl", "", 80, 0, '-16 -16 -24', '16 16 40');
};

View File

@@ -0,0 +1,409 @@
/*
==============================================================================
WIZARD
==============================================================================
*/
$cd id1/models/a_wizard
$origin 0 0 24
$base wizbase
$skin wizbase
$frame hover1 hover2 hover3 hover4 hover5 hover6 hover7 hover8
$frame hover9 hover10 hover11 hover12 hover13 hover14 hover15
$frame fly1 fly2 fly3 fly4 fly5 fly6 fly7 fly8 fly9 fly10
$frame fly11 fly12 fly13 fly14
$frame magatt1 magatt2 magatt3 magatt4 magatt5 magatt6 magatt7
$frame magatt8 magatt9 magatt10 magatt11 magatt12 magatt13
$frame pain1 pain2 pain3 pain4
$frame death1 death2 death3 death4 death5 death6 death7 death8
/*
==============================================================================
WIZARD
If the player moves behind cover before the missile is launched, launch it
at the last visible spot with no velocity leading, in hopes that the player
will duck back out and catch it.
==============================================================================
*/
/*
=============
LaunchMissile
Sets the given entities velocity and angles so that it will hit self.enemy
if self.enemy maintains it's current velocity
0.1 is moderately accurate, 0.0 is totally accurate
=============
*/
void(entity missile, float mspeed, float accuracy) LaunchMissile =
{
local vector vec, move;
local float fly;
makevectors (self.angles);
// set missile speed
vec = self.enemy.origin + self.enemy.mins + self.enemy.size * 0.7 - missile.origin;
// calc aproximate time for missile to reach vec
fly = vlen (vec) / mspeed;
// get the entities xy velocity
move = self.enemy.velocity;
move_z = 0;
// project the target forward in time
vec = vec + move * fly;
vec = normalize(vec);
vec = vec + accuracy*v_up*(random()- 0.5) + accuracy*v_right*(random()- 0.5);
missile.velocity = vec * mspeed;
missile.angles = '0 0 0';
missile.angles_y = vectoyaw(missile.velocity);
// set missile duration
missile.nextthink = time + 5;
missile.think = SUB_Remove;
};
void() wiz_run1;
void() wiz_side1;
/*
=================
WizardCheckAttack
=================
*/
float() WizardCheckAttack =
{
local vector spot1, spot2;
local entity targ;
local float chance;
if (time < self.attack_finished)
return FALSE;
if (!enemy_vis)
return FALSE;
if (enemy_range == RANGE_FAR)
{
if (self.attack_state != AS_STRAIGHT)
{
self.attack_state = AS_STRAIGHT;
wiz_run1 ();
}
return FALSE;
}
targ = self.enemy;
// see if any entities are in the way of the shot
spot1 = self.origin + self.view_ofs;
spot2 = targ.origin + targ.view_ofs;
traceline (spot1, spot2, FALSE, self);
if (trace_ent != targ)
{ // don't have a clear shot, so move to a side
if (self.attack_state != AS_STRAIGHT)
{
self.attack_state = AS_STRAIGHT;
wiz_run1 ();
}
return FALSE;
}
if (enemy_range == RANGE_MELEE)
chance = 0.9;
else if (enemy_range == RANGE_NEAR)
chance = 0.6;
else if (enemy_range == RANGE_MID)
chance = 0.2;
else
chance = 0;
if (random () < chance)
{
self.attack_state = AS_MISSILE;
return TRUE;
}
if (enemy_range == RANGE_MID)
{
if (self.attack_state != AS_STRAIGHT)
{
self.attack_state = AS_STRAIGHT;
wiz_run1 ();
}
}
else
{
if (self.attack_state != AS_SLIDING)
{
self.attack_state = AS_SLIDING;
wiz_side1 ();
}
}
return FALSE;
};
/*
=================
WizardAttackFinished
=================
*/
void() WizardAttackFinished =
{
if (enemy_range >= RANGE_MID || !enemy_vis)
{
self.attack_state = AS_STRAIGHT;
self.think = wiz_run1;
}
else
{
self.attack_state = AS_SLIDING;
self.think = wiz_side1;
}
};
/*
==============================================================================
FAST ATTACKS
==============================================================================
*/
void() Wiz_FastFire =
{
local vector vec;
local vector dst;
if (self.owner.health > 0)
{
self.owner.effects = self.owner.effects | EF_MUZZLEFLASH;
makevectors (self.enemy.angles);
dst = self.enemy.origin - 13*self.movedir;
vec = normalize(dst - self.origin);
sound (self, CHAN_WEAPON, "wizard/wattack.wav", 1, ATTN_NORM);
launch_spike (self.origin, vec);
newmis.velocity = vec*600;
newmis.owner = self.owner;
newmis.classname = "wizspike";
setmodel (newmis, "progs/w_spike.mdl");
setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
}
remove (self);
};
void() Wiz_StartFast =
{
local entity missile;
sound (self, CHAN_WEAPON, "wizard/wattack.wav", 1, ATTN_NORM);
self.v_angle = self.angles;
makevectors (self.angles);
missile = spawn ();
missile.owner = self;
missile.nextthink = time + 0.6;
setsize (missile, '0 0 0', '0 0 0');
setorigin (missile, self.origin + '0 0 30' + v_forward*14 + v_right*14);
missile.enemy = self.enemy;
missile.nextthink = time + 0.8;
missile.think = Wiz_FastFire;
missile.movedir = v_right;
missile = spawn ();
missile.owner = self;
missile.nextthink = time + 1;
setsize (missile, '0 0 0', '0 0 0');
setorigin (missile, self.origin + '0 0 30' + v_forward*14 + v_right* -14);
missile.enemy = self.enemy;
missile.nextthink = time + 0.3;
missile.think = Wiz_FastFire;
missile.movedir = VEC_ORIGIN - v_right;
};
void() Wiz_idlesound =
{
local float wr;
wr = random() * 5;
if (self.wait < time)
{
self.wait = time + 2;
if (wr > 4.5)
sound (self, CHAN_VOICE, "wizard/widle1.wav", 1, ATTN_IDLE);
if (wr < 1.5)
sound (self, CHAN_VOICE, "wizard/widle2.wav", 1, ATTN_IDLE);
}
return;
};
void() wiz_stand1 =[ $hover1, wiz_stand2 ] {ai_stand();};
void() wiz_stand2 =[ $hover2, wiz_stand3 ] {ai_stand();};
void() wiz_stand3 =[ $hover3, wiz_stand4 ] {ai_stand();};
void() wiz_stand4 =[ $hover4, wiz_stand5 ] {ai_stand();};
void() wiz_stand5 =[ $hover5, wiz_stand6 ] {ai_stand();};
void() wiz_stand6 =[ $hover6, wiz_stand7 ] {ai_stand();};
void() wiz_stand7 =[ $hover7, wiz_stand8 ] {ai_stand();};
void() wiz_stand8 =[ $hover8, wiz_stand1 ] {ai_stand();};
void() wiz_walk1 =[ $hover1, wiz_walk2 ] {ai_walk(8);
Wiz_idlesound();};
void() wiz_walk2 =[ $hover2, wiz_walk3 ] {ai_walk(8);};
void() wiz_walk3 =[ $hover3, wiz_walk4 ] {ai_walk(8);};
void() wiz_walk4 =[ $hover4, wiz_walk5 ] {ai_walk(8);};
void() wiz_walk5 =[ $hover5, wiz_walk6 ] {ai_walk(8);};
void() wiz_walk6 =[ $hover6, wiz_walk7 ] {ai_walk(8);};
void() wiz_walk7 =[ $hover7, wiz_walk8 ] {ai_walk(8);};
void() wiz_walk8 =[ $hover8, wiz_walk1 ] {ai_walk(8);};
void() wiz_side1 =[ $hover1, wiz_side2 ] {ai_run(8);
Wiz_idlesound();};
void() wiz_side2 =[ $hover2, wiz_side3 ] {ai_run(8);};
void() wiz_side3 =[ $hover3, wiz_side4 ] {ai_run(8);};
void() wiz_side4 =[ $hover4, wiz_side5 ] {ai_run(8);};
void() wiz_side5 =[ $hover5, wiz_side6 ] {ai_run(8);};
void() wiz_side6 =[ $hover6, wiz_side7 ] {ai_run(8);};
void() wiz_side7 =[ $hover7, wiz_side8 ] {ai_run(8);};
void() wiz_side8 =[ $hover8, wiz_side1 ] {ai_run(8);};
void() wiz_run1 =[ $fly1, wiz_run2 ] {ai_run(16);
Wiz_idlesound();
};
void() wiz_run2 =[ $fly2, wiz_run3 ] {ai_run(16);};
void() wiz_run3 =[ $fly3, wiz_run4 ] {ai_run(16);};
void() wiz_run4 =[ $fly4, wiz_run5 ] {ai_run(16);};
void() wiz_run5 =[ $fly5, wiz_run6 ] {ai_run(16);};
void() wiz_run6 =[ $fly6, wiz_run7 ] {ai_run(16);};
void() wiz_run7 =[ $fly7, wiz_run8 ] {ai_run(16);};
void() wiz_run8 =[ $fly8, wiz_run9 ] {ai_run(16);};
void() wiz_run9 =[ $fly9, wiz_run10 ] {ai_run(16);};
void() wiz_run10 =[ $fly10, wiz_run11 ] {ai_run(16);};
void() wiz_run11 =[ $fly11, wiz_run12 ] {ai_run(16);};
void() wiz_run12 =[ $fly12, wiz_run13 ] {ai_run(16);};
void() wiz_run13 =[ $fly13, wiz_run14 ] {ai_run(16);};
void() wiz_run14 =[ $fly14, wiz_run1 ] {ai_run(16);};
void() wiz_fast1 =[ $magatt1, wiz_fast2 ] {ai_face();Wiz_StartFast();};
void() wiz_fast2 =[ $magatt2, wiz_fast3 ] {ai_face();};
void() wiz_fast3 =[ $magatt3, wiz_fast4 ] {ai_face();};
void() wiz_fast4 =[ $magatt4, wiz_fast5 ] {ai_face();};
void() wiz_fast5 =[ $magatt5, wiz_fast6 ] {ai_face();};
void() wiz_fast6 =[ $magatt6, wiz_fast7 ] {ai_face();};
void() wiz_fast7 =[ $magatt5, wiz_fast8 ] {ai_face();};
void() wiz_fast8 =[ $magatt4, wiz_fast9 ] {ai_face();};
void() wiz_fast9 =[ $magatt3, wiz_fast10 ] {ai_face();};
void() wiz_fast10 =[ $magatt2, wiz_run1 ] {ai_face();SUB_AttackFinished(2);WizardAttackFinished ();};
void() wiz_pain1 =[ $pain1, wiz_pain2 ] {};
void() wiz_pain2 =[ $pain2, wiz_pain3 ] {};
void() wiz_pain3 =[ $pain3, wiz_pain4 ] {};
void() wiz_pain4 =[ $pain4, wiz_run1 ] {};
void() wiz_death1 =[ $death1, wiz_death2 ] {};
void() wiz_death2 =[ $death2, wiz_death3 ] {};
void() wiz_death3 =[ $death3, wiz_death4 ] {};
void() wiz_death4 =[ $death4, wiz_death5 ] {};
void() wiz_death5 =[ $death5, wiz_death6 ] {};
void() wiz_death6 =[ $death6, wiz_death7 ] {};
void() wiz_death7 =[ $death7, wiz_death8 ] {};
void() wiz_death8 =[ $death8, wiz_death8 ] {};
void(entity inflictor, entity attacker) wiz_die =
{
// check for gib
if (self.health < -40)
{
SpawnGib("progs/gib3.mdl");
SpawnGib("progs/gib4.mdl");
SpawnGib("progs/gib5.mdl");
SpawnGib("progs/blood.mdl");
SpawnGib("progs/blood.mdl");
BecomeGibs();
return;
}
sound (self, CHAN_VOICE, "wizard/wdeath.wav", 1, ATTN_NORM);
self.solid = SOLID_NOT;
self.velocity_x = crandom() * 200;
self.velocity_y = crandom() * 200;
self.velocity_z = 100 + 100 * random();
self.flags = self.flags - (self.flags & FL_ONGROUND);
wiz_death1 ();
};
void(entity attacker, float damage) Wiz_Pain =
{
if (random()*70 > damage)
return;
if (self.pain_finished > time)
return;
sound (self, CHAN_VOICE, "wizard/wpain.wav", 1, ATTN_NORM);
self.pain_finished = time + 0.4;
wiz_pain1 ();
};
void() Wiz_Missile =
{
wiz_fast1();
};
/*QUAKED monster_wizard (1 0 0) (-16 -16 -24) (16 16 40) Ambush
{
model ("progs/wizard.mdl");
}
Scrag.
*/
void() monster_wizard =
{
if (deathmatch)
{
remove(self);
return;
}
precache_model ("progs/wizard.mdl");
precache_model ("progs/h_wizard.mdl");
precache_model ("progs/w_spike.mdl");
precache_sound ("wizard/hit.wav");
precache_sound ("wizard/wattack.wav");
precache_sound ("wizard/wdeath.wav");
precache_sound ("wizard/widle1.wav");
precache_sound ("wizard/widle2.wav");
precache_sound ("wizard/wpain.wav");
precache_sound ("wizard/wsight.wav");
self.th_stand = wiz_stand1;
self.th_walk = wiz_walk1;
self.th_run = wiz_run1;
self.th_missile = Wiz_Missile;
self.th_pain = Wiz_Pain;
self.th_die = wiz_die;
monster_start("progs/wizard.mdl", "progs/h_wizard.mdl", 80, FL_FLY, '-16 -16 -24', '16 16 40');
};

View File

@@ -0,0 +1,508 @@
static enumflags { ZOMBIE_CRUCIFIED, ZOMBIE_AMBUSH };
$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8
$frame stand9 stand10 stand11 stand12 stand13 stand14 stand15
$frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 walk9 walk10 walk11
$frame walk12 walk13 walk14 walk15 walk16 walk17 walk18 walk19
$frame run1 run2 run3 run4 run5 run6 run7 run8 run9 run10 run11 run12
$frame run13 run14 run15 run16 run17 run18
$frame atta1 atta2 atta3 atta4 atta5 atta6 atta7 atta8 atta9 atta10 atta11
$frame atta12 atta13
$frame attb1 attb2 attb3 attb4 attb5 attb6 attb7 attb8 attb9 attb10 attb11
$frame attb12 attb13 attb14
$frame attc1 attc2 attc3 attc4 attc5 attc6 attc7 attc8 attc9 attc10 attc11
$frame attc12
$frame paina1 paina2 paina3 paina4 paina5 paina6 paina7 paina8 paina9 paina10
$frame paina11 paina12
$frame painb1 painb2 painb3 painb4 painb5 painb6 painb7 painb8 painb9 painb10
$frame painb11 painb12 painb13 painb14 painb15 painb16 painb17 painb18 painb19
$frame painb20 painb21 painb22 painb23 painb24 painb25 painb26 painb27 painb28
$frame painc1 painc2 painc3 painc4 painc5 painc6 painc7 painc8 painc9 painc10
$frame painc11 painc12 painc13 painc14 painc15 painc16 painc17 painc18
$frame paind1 paind2 paind3 paind4 paind5 paind6 paind7 paind8 paind9 paind10
$frame paind11 paind12 paind13
$frame paine1 paine2 paine3 paine4 paine5 paine6 paine7 paine8 paine9 paine10
$frame paine11 paine12 paine13 paine14 paine15 paine16 paine17 paine18 paine19
$frame paine20 paine21 paine22 paine23 paine24 paine25 paine26 paine27 paine28
$frame paine29 paine30
$frame cruc_1 cruc_2 cruc_3 cruc_4 cruc_5 cruc_6
//=============================================================================
.float inpain;
void() zombie_idle_sound =
{
if (random() > 0.2)
return;
float r = randomrange(3);
if (r == 0)
sound (self, CHAN_VOICE, "zombie/idle_w2.wav", 1, ATTN_IDLE);
else if (r == 1)
sound (self, CHAN_VOICE, "zombie/z_idle.wav", 1, ATTN_IDLE);
else
sound (self, CHAN_VOICE, "zombie/z_idle1.wav", 1, ATTN_IDLE);
};
void() zombie_stand1 =[ $stand1, zombie_stand2 ] {ai_stand();};
void() zombie_stand2 =[ $stand2, zombie_stand3 ] {ai_stand();};
void() zombie_stand3 =[ $stand3, zombie_stand4 ] {ai_stand();};
void() zombie_stand4 =[ $stand4, zombie_stand5 ] {ai_stand();};
void() zombie_stand5 =[ $stand5, zombie_stand6 ] {ai_stand();};
void() zombie_stand6 =[ $stand6, zombie_stand7 ] {ai_stand();};
void() zombie_stand7 =[ $stand7, zombie_stand8 ] {ai_stand();};
void() zombie_stand8 =[ $stand8, zombie_stand9 ] {ai_stand();};
void() zombie_stand9 =[ $stand9, zombie_stand10 ] {ai_stand();};
void() zombie_stand10 =[ $stand10, zombie_stand11 ] {ai_stand();};
void() zombie_stand11 =[ $stand11, zombie_stand12 ] {ai_stand();};
void() zombie_stand12 =[ $stand12, zombie_stand13 ] {ai_stand();};
void() zombie_stand13 =[ $stand13, zombie_stand14 ] {ai_stand();};
void() zombie_stand14 =[ $stand14, zombie_stand15 ] {ai_stand();};
void() zombie_stand15 =[ $stand15, zombie_stand1 ] {ai_stand();};
void() zombie_cruc1 = [ $cruc_1, zombie_cruc2 ] {zombie_idle_sound();self.nextthink = time + 0.1 + random()*0.1;};
void() zombie_cruc2 = [ $cruc_2, zombie_cruc3 ] {self.nextthink = time + 0.1 + random()*0.1;};
void() zombie_cruc3 = [ $cruc_3, zombie_cruc4 ] {self.nextthink = time + 0.1 + random()*0.1;};
void() zombie_cruc4 = [ $cruc_4, zombie_cruc5 ] {self.nextthink = time + 0.1 + random()*0.1;};
void() zombie_cruc5 = [ $cruc_5, zombie_cruc6 ] {self.nextthink = time + 0.1 + random()*0.1;};
void() zombie_cruc6 = [ $cruc_6, zombie_cruc1 ] {self.nextthink = time + 0.1 + random()*0.1;};
void() zombie_walk1 =[ $walk1, zombie_walk2 ] {ai_walk(0);};
void() zombie_walk2 =[ $walk2, zombie_walk3 ] {ai_walk(2);};
void() zombie_walk3 =[ $walk3, zombie_walk4 ] {ai_walk(3);};
void() zombie_walk4 =[ $walk4, zombie_walk5 ] {ai_walk(2);};
void() zombie_walk5 =[ $walk5, zombie_walk6 ] {ai_walk(1);};
void() zombie_walk6 =[ $walk6, zombie_walk7 ] {ai_walk(0);};
void() zombie_walk7 =[ $walk7, zombie_walk8 ] {ai_walk(0);};
void() zombie_walk8 =[ $walk8, zombie_walk9 ] {ai_walk(0);};
void() zombie_walk9 =[ $walk9, zombie_walk10 ] {ai_walk(0);};
void() zombie_walk10 =[ $walk10, zombie_walk11 ] {ai_walk(0);};
void() zombie_walk11 =[ $walk11, zombie_walk12 ] {ai_walk(2);};
void() zombie_walk12 =[ $walk12, zombie_walk13 ] {ai_walk(2);};
void() zombie_walk13 =[ $walk13, zombie_walk14 ] {ai_walk(1);};
void() zombie_walk14 =[ $walk14, zombie_walk15 ] {ai_walk(0);};
void() zombie_walk15 =[ $walk15, zombie_walk16 ] {ai_walk(0);};
void() zombie_walk16 =[ $walk16, zombie_walk17 ] {ai_walk(0);};
void() zombie_walk17 =[ $walk17, zombie_walk18 ] {ai_walk(0);};
void() zombie_walk18 =[ $walk18, zombie_walk19 ] {ai_walk(0);};
void() zombie_walk19 =[ $walk19, zombie_walk1 ] {ai_walk(0);zombie_idle_sound();};
void() zombie_run1 =[ $run1, zombie_run2 ] {ai_run(1);self.inpain = 0;};
void() zombie_run2 =[ $run2, zombie_run3 ] {ai_run(1);};
void() zombie_run3 =[ $run3, zombie_run4 ] {ai_run(0);};
void() zombie_run4 =[ $run4, zombie_run5 ] {ai_run(1);};
void() zombie_run5 =[ $run5, zombie_run6 ] {ai_run(2);};
void() zombie_run6 =[ $run6, zombie_run7 ] {ai_run(3);};
void() zombie_run7 =[ $run7, zombie_run8 ] {ai_run(4);};
void() zombie_run8 =[ $run8, zombie_run9 ] {ai_run(4);};
void() zombie_run9 =[ $run9, zombie_run10 ] {ai_run(2);};
void() zombie_run10 =[ $run10, zombie_run11 ] {ai_run(0);};
void() zombie_run11 =[ $run11, zombie_run12 ] {ai_run(0);};
void() zombie_run12 =[ $run12, zombie_run13 ] {ai_run(0);};
void() zombie_run13 =[ $run13, zombie_run14 ] {ai_run(2);};
void() zombie_run14 =[ $run14, zombie_run15 ] {ai_run(4);};
void() zombie_run15 =[ $run15, zombie_run16 ] {ai_run(6);};
void() zombie_run16 =[ $run16, zombie_run17 ] {ai_run(7);};
void() zombie_run17 =[ $run17, zombie_run18 ] {ai_run(3);};
void() zombie_run18 =[ $run18, zombie_run1 ] {ai_run(8);zombie_idle_sound();};
/*
=============================================================================
ATTACKS
=============================================================================
*/
void() ZombieGrenadeTouch =
{
SpawnTouchblood(32);
if (other.takedamage)
{
Damage (other, self, self.owner, 10);
sound (self, CHAN_WEAPON, "zombie/z_hit.wav", 1, ATTN_NORM);
remove(self);
return;
}
sound (self, CHAN_WEAPON, "zombie/z_miss.wav", 1, ATTN_NORM);
self.touch = SUB_Null;
self.velocity = '0 0 0';
self.think = SUB_Fade;
self.nextthink = time + 2 + random()*2;
};
/*
================
ZombieFireGrenade
================
*/
void(vector st) ZombieFireGrenade =
{
local entity missile;
local vector org;
sound (self, CHAN_WEAPON, "zombie/z_shot1.wav", 1, ATTN_NORM);
missile = spawn ();
missile.owner = self;
missile.movetype = MOVETYPE_TOSS;
missile.solid = SOLID_BBOX;
// calc org
org = self.origin + st_x * v_forward + st_y * v_right + (st_z - 24) * v_up;
// set missile speed
makevectors (self.angles);
missile.velocity = normalize(self.enemy.origin - org);
missile.velocity = missile.velocity * 600;
missile.velocity_z = 200;
missile.avelocity = '3000 1000 2000';
missile.touch = ZombieGrenadeTouch;
// set missile duration
missile.nextthink = time + 2.5;
missile.think = SUB_Remove;
setmodel (missile, "progs/zom_gib.mdl");
setsize (missile, '0 0 0', '0 0 0');
setorigin (missile, org);
};
void() zombie_atta1 =[ $atta1, zombie_atta2 ] {ai_face();};
void() zombie_atta2 =[ $atta2, zombie_atta3 ] {ai_face();};
void() zombie_atta3 =[ $atta3, zombie_atta4 ] {ai_face();};
void() zombie_atta4 =[ $atta4, zombie_atta5 ] {ai_face();};
void() zombie_atta5 =[ $atta5, zombie_atta6 ] {ai_face();};
void() zombie_atta6 =[ $atta6, zombie_atta7 ] {ai_face();};
void() zombie_atta7 =[ $atta7, zombie_atta8 ] {ai_face();};
void() zombie_atta8 =[ $atta8, zombie_atta9 ] {ai_face();};
void() zombie_atta9 =[ $atta9, zombie_atta10 ] {ai_face();};
void() zombie_atta10 =[ $atta10, zombie_atta11 ] {ai_face();};
void() zombie_atta11 =[ $atta11, zombie_atta12 ] {ai_face();};
void() zombie_atta12 =[ $atta12, zombie_atta13 ] {ai_face();};
void() zombie_atta13 =[ $atta13, zombie_run1 ] {ai_face();ZombieFireGrenade('-10 -22 30');};
void() zombie_attb1 =[ $attb1, zombie_attb2 ] {ai_face();};
void() zombie_attb2 =[ $attb2, zombie_attb3 ] {ai_face();};
void() zombie_attb3 =[ $attb3, zombie_attb4 ] {ai_face();};
void() zombie_attb4 =[ $attb4, zombie_attb5 ] {ai_face();};
void() zombie_attb5 =[ $attb5, zombie_attb6 ] {ai_face();};
void() zombie_attb6 =[ $attb6, zombie_attb7 ] {ai_face();};
void() zombie_attb7 =[ $attb7, zombie_attb8 ] {ai_face();};
void() zombie_attb8 =[ $attb8, zombie_attb9 ] {ai_face();};
void() zombie_attb9 =[ $attb9, zombie_attb10 ] {ai_face();};
void() zombie_attb10 =[ $attb10, zombie_attb11 ] {ai_face();};
void() zombie_attb11 =[ $attb11, zombie_attb12 ] {ai_face();};
void() zombie_attb12 =[ $attb12, zombie_attb13 ] {ai_face();};
void() zombie_attb13 =[ $attb13, zombie_attb14 ] {ai_face();};
void() zombie_attb14 =[ $attb13, zombie_run1 ] {ai_face();ZombieFireGrenade('-10 -24 29');};
void() zombie_attc1 =[ $attc1, zombie_attc2 ] {ai_face();};
void() zombie_attc2 =[ $attc2, zombie_attc3 ] {ai_face();};
void() zombie_attc3 =[ $attc3, zombie_attc4 ] {ai_face();};
void() zombie_attc4 =[ $attc4, zombie_attc5 ] {ai_face();};
void() zombie_attc5 =[ $attc5, zombie_attc6 ] {ai_face();};
void() zombie_attc6 =[ $attc6, zombie_attc7 ] {ai_face();};
void() zombie_attc7 =[ $attc7, zombie_attc8 ] {ai_face();};
void() zombie_attc8 =[ $attc8, zombie_attc9 ] {ai_face();};
void() zombie_attc9 =[ $attc9, zombie_attc10 ] {ai_face();};
void() zombie_attc10 =[ $attc10, zombie_attc11 ] {ai_face();};
void() zombie_attc11 =[ $attc11, zombie_attc12 ] {ai_face();};
void() zombie_attc12 =[ $attc12, zombie_run1 ] {ai_face();ZombieFireGrenade('-12 -19 29');};
void() zombie_missile =
{
local float r;
r = random();
if (r < 0.3)
zombie_atta1 ();
else if (r < 0.6)
zombie_attb1 ();
else
zombie_attc1 ();
};
/*
=============================================================================
PAIN
=============================================================================
*/
void() zombie_paina1 =[ $paina1, zombie_paina2 ] {sound (self, CHAN_VOICE, "zombie/z_pain.wav", 1, ATTN_NORM);};
void() zombie_paina2 =[ $paina2, zombie_paina3 ] {ai_painforward(3);};
void() zombie_paina3 =[ $paina3, zombie_paina4 ] {ai_painforward(1);};
void() zombie_paina4 =[ $paina4, zombie_paina5 ] {ai_pain(1);};
void() zombie_paina5 =[ $paina5, zombie_paina6 ] {ai_pain(3);};
void() zombie_paina6 =[ $paina6, zombie_paina7 ] {ai_pain(1);};
void() zombie_paina7 =[ $paina7, zombie_paina8 ] {};
void() zombie_paina8 =[ $paina8, zombie_paina9 ] {};
void() zombie_paina9 =[ $paina9, zombie_paina10 ] {};
void() zombie_paina10 =[ $paina10, zombie_paina11 ] {};
void() zombie_paina11 =[ $paina11, zombie_paina12 ] {};
void() zombie_paina12 =[ $paina12, zombie_run1 ] {};
void() zombie_painb1 =[ $painb1, zombie_painb2 ] {sound (self, CHAN_VOICE, "zombie/z_pain1.wav", 1, ATTN_NORM);};
void() zombie_painb2 =[ $painb2, zombie_painb3 ] {ai_pain(2);};
void() zombie_painb3 =[ $painb3, zombie_painb4 ] {ai_pain(8);};
void() zombie_painb4 =[ $painb4, zombie_painb5 ] {ai_pain(6);};
void() zombie_painb5 =[ $painb5, zombie_painb6 ] {ai_pain(2);};
void() zombie_painb6 =[ $painb6, zombie_painb7 ] {};
void() zombie_painb7 =[ $painb7, zombie_painb8 ] {};
void() zombie_painb8 =[ $painb8, zombie_painb9 ] {};
void() zombie_painb9 =[ $painb9, zombie_painb10 ] {sound (self, CHAN_BODY, "zombie/z_fall.wav", 1, ATTN_NORM);};
void() zombie_painb10 =[ $painb10, zombie_painb11 ] {};
void() zombie_painb11 =[ $painb11, zombie_painb12 ] {};
void() zombie_painb12 =[ $painb12, zombie_painb13 ] {};
void() zombie_painb13 =[ $painb13, zombie_painb14 ] {};
void() zombie_painb14 =[ $painb14, zombie_painb15 ] {};
void() zombie_painb15 =[ $painb15, zombie_painb16 ] {};
void() zombie_painb16 =[ $painb16, zombie_painb17 ] {};
void() zombie_painb17 =[ $painb17, zombie_painb18 ] {};
void() zombie_painb18 =[ $painb18, zombie_painb19 ] {};
void() zombie_painb19 =[ $painb19, zombie_painb20 ] {};
void() zombie_painb20 =[ $painb20, zombie_painb21 ] {};
void() zombie_painb21 =[ $painb21, zombie_painb22 ] {};
void() zombie_painb22 =[ $painb22, zombie_painb23 ] {};
void() zombie_painb23 =[ $painb23, zombie_painb24 ] {};
void() zombie_painb24 =[ $painb24, zombie_painb25 ] {};
void() zombie_painb25 =[ $painb25, zombie_painb26 ] {ai_painforward(1);};
void() zombie_painb26 =[ $painb26, zombie_painb27 ] {};
void() zombie_painb27 =[ $painb27, zombie_painb28 ] {};
void() zombie_painb28 =[ $painb28, zombie_run1 ] {};
void() zombie_painc1 =[ $painc1, zombie_painc2 ] {sound (self, CHAN_VOICE, "zombie/z_pain1.wav", 1, ATTN_NORM);};
void() zombie_painc2 =[ $painc2, zombie_painc3 ] {};
void() zombie_painc3 =[ $painc3, zombie_painc4 ] {ai_pain(3);};
void() zombie_painc4 =[ $painc4, zombie_painc5 ] {ai_pain(1);};
void() zombie_painc5 =[ $painc5, zombie_painc6 ] {};
void() zombie_painc6 =[ $painc6, zombie_painc7 ] {};
void() zombie_painc7 =[ $painc7, zombie_painc8 ] {};
void() zombie_painc8 =[ $painc8, zombie_painc9 ] {};
void() zombie_painc9 =[ $painc9, zombie_painc10 ] {};
void() zombie_painc10 =[ $painc10, zombie_painc11 ] {};
void() zombie_painc11 =[ $painc11, zombie_painc12 ] {ai_painforward(1);};
void() zombie_painc12 =[ $painc12, zombie_painc13 ] {ai_painforward(1);};
void() zombie_painc13 =[ $painc13, zombie_painc14 ] {};
void() zombie_painc14 =[ $painc14, zombie_painc15 ] {};
void() zombie_painc15 =[ $painc15, zombie_painc16 ] {};
void() zombie_painc16 =[ $painc16, zombie_painc17 ] {};
void() zombie_painc17 =[ $painc17, zombie_painc18 ] {};
void() zombie_painc18 =[ $painc18, zombie_run1 ] {};
void() zombie_paind1 =[ $paind1, zombie_paind2 ] {sound (self, CHAN_VOICE, "zombie/z_pain.wav", 1, ATTN_NORM);};
void() zombie_paind2 =[ $paind2, zombie_paind3 ] {};
void() zombie_paind3 =[ $paind3, zombie_paind4 ] {};
void() zombie_paind4 =[ $paind4, zombie_paind5 ] {};
void() zombie_paind5 =[ $paind5, zombie_paind6 ] {};
void() zombie_paind6 =[ $paind6, zombie_paind7 ] {};
void() zombie_paind7 =[ $paind7, zombie_paind8 ] {};
void() zombie_paind8 =[ $paind8, zombie_paind9 ] {};
void() zombie_paind9 =[ $paind9, zombie_paind10 ] {ai_pain(1);};
void() zombie_paind10 =[ $paind10, zombie_paind11 ] {};
void() zombie_paind11 =[ $paind11, zombie_paind12 ] {};
void() zombie_paind12 =[ $paind12, zombie_paind13 ] {};
void() zombie_paind13 =[ $paind13, zombie_run1 ] {};
void() zombie_paine1 =[ $paine1, zombie_paine2 ] {sound (self, CHAN_VOICE, "zombie/z_pain.wav", 1, ATTN_NORM);self.health = 60;};
void() zombie_paine2 =[ $paine2, zombie_paine3 ] {ai_pain(8);};
void() zombie_paine3 =[ $paine3, zombie_paine4 ] {ai_pain(5);};
void() zombie_paine4 =[ $paine4, zombie_paine5 ] {ai_pain(3);};
void() zombie_paine5 =[ $paine5, zombie_paine6 ] {ai_pain(1);};
void() zombie_paine6 =[ $paine6, zombie_paine7 ] {ai_pain(2);};
void() zombie_paine7 =[ $paine7, zombie_paine8 ] {ai_pain(1);};
void() zombie_paine8 =[ $paine8, zombie_paine9 ] {ai_pain(1);};
void() zombie_paine9 =[ $paine9, zombie_paine10 ] {ai_pain(2);};
void() zombie_paine10 =[ $paine10, zombie_paine11 ] {
sound (self, CHAN_BODY, "zombie/z_fall.wav", 1, ATTN_NORM);
self.solid = SOLID_NOT;
};
void() zombie_paine11 =[ $paine11, zombie_paine12 ] {self.nextthink = self.nextthink + 5;self.health = 60;};
void() zombie_paine12 =[ $paine12, zombie_paine13 ]{
// see if ok to stand up
self.health = 60;
sound (self, CHAN_VOICE, "zombie/z_idle.wav", 1, ATTN_IDLE);
self.solid = SOLID_SLIDEBOX;
if (!walkmove (0, 0))
{
self.think = zombie_paine11;
self.solid = SOLID_NOT;
return;
}
};
void() zombie_paine13 =[ $paine13, zombie_paine14 ] {};
void() zombie_paine14 =[ $paine14, zombie_paine15 ] {};
void() zombie_paine15 =[ $paine15, zombie_paine16 ] {};
void() zombie_paine16 =[ $paine16, zombie_paine17 ] {};
void() zombie_paine17 =[ $paine17, zombie_paine18 ] {};
void() zombie_paine18 =[ $paine18, zombie_paine19 ] {};
void() zombie_paine19 =[ $paine19, zombie_paine20 ] {};
void() zombie_paine20 =[ $paine20, zombie_paine21 ] {};
void() zombie_paine21 =[ $paine21, zombie_paine22 ] {};
void() zombie_paine22 =[ $paine22, zombie_paine23 ] {};
void() zombie_paine23 =[ $paine23, zombie_paine24 ] {};
void() zombie_paine24 =[ $paine24, zombie_paine25 ] {};
void() zombie_paine25 =[ $paine25, zombie_paine26 ] {ai_painforward(5);};
void() zombie_paine26 =[ $paine26, zombie_paine27 ] {ai_painforward(3);};
void() zombie_paine27 =[ $paine27, zombie_paine28 ] {ai_painforward(1);};
void() zombie_paine28 =[ $paine28, zombie_paine29 ] {ai_pain(1);};
void() zombie_paine29 =[ $paine29, zombie_paine30 ] {};
void() zombie_paine30 =[ $paine30, zombie_run1 ] {};
void(entity inflictor, entity attacker) zombie_die =
{
SpawnGib("progs/gib1.mdl");
SpawnGib("progs/gib2.mdl");
SpawnGib("progs/gib3.mdl");
SpawnGib("progs/gib4.mdl");
SpawnGib("progs/gib5.mdl");
SpawnGib("progs/blood.mdl");
SpawnGib("progs/blood.mdl");
BecomeGibs();
};
/*
=================
zombie_pain
Zombies can only be killed (gibbed) by doing 60 hit points of damage
in a single frame (rockets, grenades, quad shotgun, quad nailgun).
A hit of 25 points or more (super shotgun, quad nailgun) will allways put it
down to the ground.
A hit of from 10 to 40 points in one frame will cause it to go down if it
has been twice in two seconds, otherwise it goes into one of the four
fast pain frames.
A hit of less than 10 points of damage (winged by a shotgun) will be ignored.
FIXME: don't use pain_finished because of nightmare hack
=================
*/
void(entity attacker, float take) zombie_pain =
{
local float r;
self.health = 60; // allways reset health
if (take < 9)
return; // totally ignore
if (self.inpain == 2)
return; // down on ground, so don't reset any counters
// go down immediately if a big enough hit
if (take >= 25)
{
self.inpain = 2;
zombie_paine1 ();
return;
}
if (self.inpain)
{
// if hit again in next gre seconds while not in pain frames, definately drop
self.pain_finished = time + 3;
return; // currently going through an animation, don't change
}
if (self.pain_finished > time)
{
// hit again, so drop down
self.inpain = 2;
zombie_paine1 ();
return;
}
// gp into one of the fast pain animations
self.inpain = 1;
r = random();
if (r < 0.25)
zombie_paina1 ();
else if (r < 0.5)
zombie_painb1 ();
else if (r < 0.75)
zombie_painc1 ();
else
zombie_paind1 ();
};
//============================================================================
/*QUAKED monster_zombie (1 0 0) (-16 -16 -24) (16 16 32) CRUCIFIED AMBUSH TELEPORT X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD
{
model ( {{ spawnflags & 2 -> { "path" : "progs/zombie.mdl", "frame" : 192 }, "progs/zombie.mdl" }} );
}
Zombie.
*/
void() monster_zombie =
{
if (deathmatch)
{
remove(self);
return;
}
precache_model ("progs/zombie.mdl");
precache_model ("progs/h_zombie.mdl");
precache_model ("progs/zom_gib.mdl");
precache_sound ("zombie/z_idle.wav");
precache_sound ("zombie/z_idle1.wav");
precache_sound ("zombie/z_shot1.wav");
precache_sound ("zombie/z_gib.wav");
precache_sound ("zombie/z_pain.wav");
precache_sound ("zombie/z_pain1.wav");
precache_sound ("zombie/z_fall.wav");
precache_sound ("zombie/z_miss.wav");
precache_sound ("zombie/z_hit.wav");
precache_sound ("zombie/idle_w2.wav");
if (self.spawnflags & ZOMBIE_CRUCIFIED)
{
self.spawnflags = self.spawnflags - ZOMBIE_CRUCIFIED;
self.solid = SOLID_NOT;
self.movetype = MOVETYPE_NONE;
setmodel (self, "progs/zombie.mdl");
setsize (self, '-16 -16 -24', '16 16 40');
zombie_cruc1();
}
else
{
if (self.spawnflags & ZOMBIE_AMBUSH)
self.spawnflags = self.spawnflags - ZOMBIE_AMBUSH + MONSTER_AMBUSH;
self.th_stand = zombie_stand1;
self.th_walk = zombie_walk1;
self.th_run = zombie_run1;
self.th_pain = zombie_pain;
self.th_die = zombie_die;
self.th_missile = zombie_missile;
monster_start("progs/zombie.mdl", "progs/h_zombie.mdl", 60, 0, '-16 -16 -24', '16 16 40');
}
};

View File

@@ -0,0 +1,266 @@
/*==========
Obituary
==========*/
void(entity targ, entity attacker, entity inflictor) Obituary =
{
string deathstring, deathstring2;
float rnum = random();
// regular telefrag
if (attacker.classname == "teledeath")
{
bprint (targ.netname);
bprint (" was telefragged by ");
bprint (attacker.owner.netname);
bprint ("\n");
attacker.owner.frags = attacker.owner.frags + 1;
return;
}
// inverse pentagram telefrag
if (attacker.classname == "teledeath2")
{
bprint ("Satan's power deflects ");
bprint (targ.netname);
bprint ("'s telefrag\n");
targ.frags = targ.frags - 1;
return;
}
// double pentagram telefrag
if (attacker.classname == "teledeath3")
{
bprint (targ.netname);
bprint (" was telefragged by ");
bprint (attacker.owner.netname);
bprint ("'s Satan power\n");
attacker.owner.frags = attacker.owner.frags + 1;
return;
}
if (attacker.classname == "player")
{
// killed self
if (targ == attacker)
{
attacker.frags = attacker.frags - 1;
bprint (targ.netname);
if (targ.weapon == IT_LIGHTNING && targ.waterlevel > 1)
{
bprint (" discharges into the water.\n");
return;
}
if (inflictor.classname == "grenade")
bprint (" tries to put the pin back in\n");
else
bprint (" becomes bored with life\n");
return;
}
// killed a team mate
else if ( (teamplay == 2) && (targ.team > 0) && (targ.team == attacker.team) )
{
bprint (attacker.netname);
if (rnum < 0.25)
deathstring = " mows down a teammate\n";
else if (rnum < 0.50)
deathstring = " checks his glasses\n";
else if (rnum < 0.75)
deathstring = " gets a frag for the other team\n";
else
deathstring = " loses another friend\n";
bprint (deathstring);
attacker.frags = attacker.frags - 1;
return;
}
else
{
attacker.frags = attacker.frags + 1;
rnum = attacker.weapon;
if (rnum == IT_AXE)
{
deathstring = " was ax-murdered by ";
deathstring2 = "\n";
}
if (rnum == IT_SHOTGUN)
{
deathstring = " chewed on ";
deathstring2 = "'s boomstick\n";
}
if (rnum == IT_SUPER_SHOTGUN)
{
deathstring = " ate 2 loads of ";
deathstring2 = "'s buckshot\n";
}
if (rnum == IT_NAILGUN)
{
deathstring = " was nailed by ";
deathstring2 = "\n";
}
if (rnum == IT_SUPER_NAILGUN)
{
deathstring = " was punctured by ";
deathstring2 = "\n";
}
if (rnum == IT_GRENADE_LAUNCHER)
{
deathstring = " eats ";
deathstring2 = "'s pineapple\n";
if (targ.health < -40)
{
deathstring = " was gibbed by ";
deathstring2 = "'s grenade\n";
}
}
if (rnum == IT_ROCKET_LAUNCHER)
{
deathstring = " rides ";
deathstring2 = "'s rocket\n";
if (targ.health < -40)
{
deathstring = " was gibbed by ";
deathstring2 = "'s rocket\n" ;
}
}
if (rnum == IT_LIGHTNING)
{
deathstring = " accepts ";
if (attacker.waterlevel > 1)
deathstring2 = "'s discharge\n";
else
deathstring2 = "'s shaft\n";
}
bprint (targ.netname);
bprint (deathstring);
bprint (attacker.netname);
bprint (deathstring2);
}
return;
}
else
{
targ.frags = targ.frags - 1;
bprint (targ.netname);
// killed by a monster?
if (attacker.flags & FL_MONSTER)
{
if (attacker.classname == "monster_army")
bprint (" was shot by a Grunt\n");
if (attacker.classname == "monster_boss")
bprint (" became one with Chthon\n");
if (attacker.classname == "monster_demon1")
bprint (" was eviscerated by a Fiend\n");
if (attacker.classname == "monster_dog")
bprint (" was mauled by a Rottweiler\n");
if (attacker.classname == "monster_enforcer")
bprint (" was blasted by an Enforcer\n");
if (attacker.classname == "monster_fish")
bprint (" was fed to the Rotfish\n");
if (attacker.classname == "monster_hell_knight")
bprint (" was slain by a Death Knight\n");
if (attacker.classname == "monster_knight")
bprint (" was slashed by a Knight\n");
if (attacker.classname == "monster_ogre")
bprint (" was destroyed by an Ogre\n");
if (attacker.classname == "monster_shalrath")
bprint (" was exploded by a Vore\n");
if (attacker.classname == "monster_shambler")
bprint (" was smashed by a Shambler\n");
if (attacker.classname == "monster_tarbaby")
bprint (" was slimed by a Spawn\n");
if (attacker.classname == "monster_wizard")
bprint (" was scragged by a Scrag\n");
if (attacker.classname == "monster_zombie")
bprint (" joins the Zombies\n");
return;
}
// tricks and traps
if (attacker.classname == "explobox")
{
bprint (" blew up\n");
return;
}
if (attacker.solid == SOLID_BSP && attacker != world)
{
bprint (" was squished\n");
return;
}
if (attacker.classname == "trap_shooter" || attacker.classname == "trap_spikeshooter")
{
bprint (" was spiked\n");
return;
}
if (attacker.classname == "fireball")
{
bprint (" ate a lavaball\n");
return;
}
if (attacker.classname == "trigger_changelevel")
{
bprint (" tried to leave\n");
return;
}
if (attacker.classname == "trigger_hurt")
{
bprint (" was in the wrong place at the wrong time\n");
return;
}
if (attacker.classname == "trigger_void")
{
bprint (" touched the void\n");
return;
}
// in-water deaths
rnum = targ.watertype;
if (rnum == CONTENT_WATER)
{
if (random() < 0.5)
bprint (" sleeps with the fishes\n");
else
bprint (" sucks it down\n");
return;
}
else if (rnum == CONTENT_SLIME)
{
if (random() < 0.5)
bprint (" gulped a load of slime\n");
else
bprint (" can't exist on slime alone\n");
return;
}
else if (rnum == CONTENT_LAVA)
{
if (targ.health < -15)
{
bprint (" burst into flames\n");
return;
}
if (random() < 0.5)
bprint (" turned into hot slag\n");
else
bprint (" visits the Volcano God\n");
return;
}
// fell to their death?
if (targ.deathtype == "falling")
{
targ.deathtype = "";
bprint (" fell to his death\n");
return;
}
// hell if I know; he's just dead!!!
bprint (" died\n");
}
};

View File

@@ -0,0 +1,220 @@
static enumflags { PLAT_LOW_TRIGGER };
/*==========
plat_hit_bottom
==========*/
static void() plat_hit_bottom =
{
sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
self.state = STATE_BOTTOM;
};
/*==========
plat_go_down
==========*/
static void() plat_go_down =
{
sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
self.state = STATE_DOWN;
SUB_CalcMove (self.pos2, self.speed, plat_hit_bottom);
};
/*==========
plat_hit_top
==========*/
static void() plat_hit_top =
{
sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
self.state = STATE_TOP;
self.think = plat_go_down;
self.nextthink = self.ltime + self.wait;
};
/*==========
plat_go_up
==========*/
static void() plat_go_up =
{
sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
self.state = STATE_UP;
SUB_CalcMove (self.pos1, self.speed, plat_hit_top);
};
/*==========
plat_use
==========*/
static void() plat_use =
{
self.use = SUB_Null;
plat_go_down();
};
/*==========
plat_crush
something has blocked the plat -
cause some damage and reverse the plats movement
==========*/
static void() plat_crush =
{
Damage(other, self, self, self.dmg);
if (self.state == STATE_UP)
plat_go_down ();
else if (self.state == STATE_DOWN)
plat_go_up ();
};
/*==========
plat_trigger_touch
when the trigger field is touched, the plat moves to the "up" position
==========*/
static void() plat_trigger_touch =
{
if (other.classname != "player")
return;
if (other.health <= 0)
return;
if (self.owner.use == plat_use) // plat has a targetname and is still waiting to be triggered
return;
self = self.owner;
if (self.state == STATE_BOTTOM)
plat_go_up();
else if (self.state == STATE_TOP)
self.nextthink = self.ltime + 1; // delay going down if player is stood on the plat
};
/*==========
plat_spawn_trigger
spawn a trigger that activates the plat when touched
plats are never activated directly by touching the plat itself
==========*/
static void() plat_spawn_trigger =
{
entity trigger = spawn();
trigger.classname = "func_plat_trigger";
trigger.owner = self;
self.trigger_field = trigger;
trigger.touch = plat_trigger_touch;
trigger.movetype = MOVETYPE_NONE;
trigger.solid = SOLID_TRIGGER;
vector tmin, tmax;
tmin = self.mins + [25, 25, self.lip];
tmax = self.maxs - [25, 25, -self.lip];
if (self.spawnflags & PLAT_LOW_TRIGGER)
tmax_z = tmin_z + self.lip;
if (self.size_x <= 50)
{
tmin_x = self.mins_x;
tmax_x = self.maxs_x;
}
if (self.size_y <= 50)
{
tmin_y = self.mins_y;
tmax_y = self.maxs_y;
}
setsize (trigger, tmin, tmax);
};
/*QUAKED func_plat (0 .5 .8) ? LOW_TRIGGER X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
A platform that moves vertically up and down.
Plats are always drawn in the map editor in the "up" position, so they will light correctly.
They are then moved to the down position on map load.
Plats spawn a trigger field that cause the plat to rise when a player touches it. By default
this trigger field spans the entire height of the plat. The plat will stay in the up position as
long as the player is touching the trigger and will fall again when they step off.
The plat will move a distance of its "height" minus any "lip".
If the plat has a "targetname", it will start disabled in the up position until
it is triggered, when it will lower and behave like a normal plat.
Spawnflags:
LOW_TRIGGER - the plat trigger field is spawned only at the bottom of the plat.
Keys:
"dmg" - damage to deal if blocked. default 1.
"speed" - speed of movement. default 150.
"lip" - amount of height to leave at end of move. this should usually be
the height of the component of your plat that a player can step upon. default 8.
"height" - override the movement distance, which by default
is calculated from the height of the actual brush minus any lip.
"wait" - time to wait at top before returning. default 3.
"sounds" -
-1) custom, see below
0) chain slow
1) base fast
2) chain slow (default)
3) base alternative
"noise" - sound to play at start of plat movement. tip: can contain looped segments.
"noise1" - sound to play at end of plat movement.
*/
void() func_plat =
{
self.solid = SOLID_BSP;
self.movetype = MOVETYPE_PUSH;
setmodel (self, self.model);
// sounds
// -1 custom, 1 = base, 2 = medieval (default), 3 = base alternative
SetFloatDefault(sounds, 2);
if (self.sounds == 1)
{
self.noise = "plats/plat1.wav";
self.noise1 = "plats/plat2.wav";
}
else if (self.sounds == 2)
{
self.noise = "plats/medplat1.wav";
self.noise1 = "plats/medplat2.wav";
}
else if (self.sounds == 3)
{
self.noise = "plats/plat3.wav";
self.noise1 = "plats/plat4.wav";
}
if (!self.noise || !self.noise1)
{
objerror("noise and noise1 must be set for custom sound\n");
remove(self);
return;
}
precache_sound(self.noise);
precache_sound(self.noise1);
// defaults
SetPositiveDefault(dmg, 1);
SetPositiveDefault(speed, 150);
SetPositiveDefault(lip, 8);
SetPositiveDefault(wait, 3);
SetFloatDefault(height, self.size_z - self.lip);
self.blocked = plat_crush;
// pos1 is the top position, pos2 is the bottom
self.pos1 = self.origin;
self.pos2 = self.origin;
self.pos2_z = self.pos2_z - self.height;
plat_spawn_trigger();
// if a plat has a targetname, the
// plat must be triggered to lower it
if (self.targetname != "")
{
self.use = plat_use;
self.state = STATE_TOP;
setorigin (self, self.pos1);
}
else
{
self.state = STATE_BOTTOM;
setorigin (self, self.pos2);
}
};

View File

@@ -0,0 +1,516 @@
$frame axrun1 axrun2 axrun3 axrun4 axrun5 axrun6
$frame rockrun1 rockrun2 rockrun3 rockrun4 rockrun5 rockrun6
$frame stand1 stand2 stand3 stand4 stand5
$frame axstnd1 axstnd2 axstnd3 axstnd4 axstnd5 axstnd6
$frame axstnd7 axstnd8 axstnd9 axstnd10 axstnd11 axstnd12
$frame axpain1 axpain2 axpain3 axpain4 axpain5 axpain6
$frame pain1 pain2 pain3 pain4 pain5 pain6
$frame axdeth1 axdeth2 axdeth3 axdeth4 axdeth5 axdeth6
$frame axdeth7 axdeth8 axdeth9
$frame deatha1 deatha2 deatha3 deatha4 deatha5 deatha6 deatha7 deatha8
$frame deatha9 deatha10 deatha11
$frame deathb1 deathb2 deathb3 deathb4 deathb5 deathb6 deathb7 deathb8
$frame deathb9
$frame deathc1 deathc2 deathc3 deathc4 deathc5 deathc6 deathc7 deathc8
$frame deathc9 deathc10 deathc11 deathc12 deathc13 deathc14 deathc15
$frame deathd1 deathd2 deathd3 deathd4 deathd5 deathd6 deathd7
$frame deathd8 deathd9
$frame deathe1 deathe2 deathe3 deathe4 deathe5 deathe6 deathe7
$frame deathe8 deathe9
$frame nailatt1 nailatt2
$frame light1 light2
$frame rockatt1 rockatt2 rockatt3 rockatt4 rockatt5 rockatt6
$frame shotatt1 shotatt2 shotatt3 shotatt4 shotatt5 shotatt6
$frame axatt1 axatt2 axatt3 axatt4 axatt5 axatt6
$frame axattb1 axattb2 axattb3 axattb4 axattb5 axattb6
$frame axattc1 axattc2 axattc3 axattc4 axattc5 axattc6
$frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6
void() player_run;
/*==========
player_stand
==========*/
void() player_stand =
{
self.weaponframe = 0;
if (self.velocity_x || self.velocity_y)
{
player_run();
return;
}
if (self.weapon == IT_AXE)
{
if (self.walkframe >= 12)
self.walkframe = 0;
self.frame = $axstnd1 + self.walkframe;
}
else
{
if (self.walkframe >= 5)
self.walkframe = 0;
self.frame = $stand1 + self.walkframe;
}
self.walkframe = self.walkframe + 1;
self.think = player_stand;
self.nextthink = time + 0.1;
};
/*==========
player_run
==========*/
void() player_run =
{
self.weaponframe = 0;
if (!self.velocity_x && !self.velocity_y)
{
player_stand();
return;
}
if (self.weapon == IT_AXE)
{
if (self.walkframe >= 6)
self.walkframe = 0;
self.frame = $axrun1 + self.walkframe;
}
else
{
if (self.walkframe >= 6)
self.walkframe = 0;
self.frame = $rockrun1 + self.walkframe;
}
self.walkframe = self.walkframe + 1;
self.think = player_run;
self.nextthink = time + 0.1;
};
void() player_axe1 = [$axatt1, player_axe2 ] {self.weaponframe=1;};
void() player_axe2 = [$axatt2, player_axe3 ] {self.weaponframe=2;};
void() player_axe3 = [$axatt3, player_axe4 ] {self.weaponframe=3;W_FireAxe();};
void() player_axe4 = [$axatt4, player_run ] {self.weaponframe=4;};
void() player_axeb1 = [$axattb1, player_axeb2 ] {self.weaponframe=5;};
void() player_axeb2 = [$axattb2, player_axeb3 ] {self.weaponframe=6;};
void() player_axeb3 = [$axattb3, player_axeb4 ] {self.weaponframe=7;W_FireAxe();};
void() player_axeb4 = [$axattb4, player_run ] {self.weaponframe=8;};
void() player_axec1 = [$axattc1, player_axec2 ] {self.weaponframe=1;};
void() player_axec2 = [$axattc2, player_axec3 ] {self.weaponframe=2;};
void() player_axec3 = [$axattc3, player_axec4 ] {self.weaponframe=3;W_FireAxe();};
void() player_axec4 = [$axattc4, player_run ] {self.weaponframe=4;};
void() player_axed1 = [$axattd1, player_axed2 ] {self.weaponframe=5;};
void() player_axed2 = [$axattd2, player_axed3 ] {self.weaponframe=6;};
void() player_axed3 = [$axattd3, player_axed4 ] {self.weaponframe=7;W_FireAxe();};
void() player_axed4 = [$axattd4, player_run ] {self.weaponframe=8;};
void() player_shot1 = [$shotatt1, player_shot2 ] {self.weaponframe=1;self.effects = self.effects | EF_MUZZLEFLASH;};
void() player_shot2 = [$shotatt2, player_shot3 ] {self.weaponframe=2;};
void() player_shot3 = [$shotatt3, player_shot4 ] {self.weaponframe=3;};
void() player_shot4 = [$shotatt4, player_shot5 ] {self.weaponframe=4;};
void() player_shot5 = [$shotatt5, player_shot6 ] {self.weaponframe=5;};
void() player_shot6 = [$shotatt6, player_run ] {self.weaponframe=6;};
/*==========
player_nail
==========*/
void() player_nail =
{
if (!self.button0)
{
player_run();
return;
}
self.effects = self.effects | EF_MUZZLEFLASH;
self.weaponframe = self.weaponframe + 1;
if (self.weaponframe > 8)
self.weaponframe = 1;
W_QuadDamageSound();
if (self.frame == $nailatt1)
{
self.frame = $nailatt2;
W_FireSpikes(-4);
}
else
{
self.frame = $nailatt1;
W_FireSpikes(4);
}
self.attack_finished = time + 0.2;
self.think = player_nail;
self.nextthink = time + 0.1;
};
void() player_rocket1 =[$rockatt1, player_rocket2 ] {self.weaponframe=1;self.effects = self.effects | EF_MUZZLEFLASH;};
void() player_rocket2 =[$rockatt2, player_rocket3 ] {self.weaponframe=2;};
void() player_rocket3 =[$rockatt3, player_rocket4 ] {self.weaponframe=3;};
void() player_rocket4 =[$rockatt4, player_rocket5 ] {self.weaponframe=4;};
void() player_rocket5 =[$rockatt5, player_rocket6 ] {self.weaponframe=5;};
void() player_rocket6 =[$rockatt6, player_run ] {self.weaponframe=6;};
/*==========
player_lightning
==========*/
void() player_lightning =
{
if (!self.button0)
{
player_run();
return;
}
if (self.frame == $light1)
self.frame = $light2;
else
self.frame = $light1;
self.effects = self.effects | EF_MUZZLEFLASH;
self.weaponframe = self.weaponframe + 1;
if (self.weaponframe > 4)
self.weaponframe = 1;
W_QuadDamageSound();
W_FireLightning();
self.attack_finished = time + 0.2;
self.think = player_lightning;
self.nextthink = time + 0.1;
};
/*==========
PlayerDeathBubblesSpawn
==========*/
static void() PlayerDeathBubblesSpawn =
{
if (self.owner.waterlevel != 3)
{
remove(self);
return;
}
if (self.count <= 0)
{
remove(self);
return;
}
self.count = self.count - 1;
self.think = PlayerDeathBubblesSpawn;
self.nextthink = time + 0.01;
entity bubble = spawn();
bubble.classname = "bubble";
bubble.owner = self.owner;
bubble.solid = SOLID_NOT;
bubble.movetype = MOVETYPE_NOCLIP;
setmodel (bubble, "progs/s_bubble.spr");
setsize (bubble, '-8 -8 -8', '8 8 8');
setorigin (bubble, self.owner.origin + self.owner.view_ofs);
bubble.velocity = '0 0 15';
bubble.think = bubble_bob;
bubble.nextthink = time + 0.5;
};
/*==========
PlayerDeathBubbles
==========*/
static void(float num) PlayerDeathBubbles =
{
entity e = spawn();
e.classname = "bubblespawner";
e.owner = self;
setorigin (e, self.origin);
e.movetype = MOVETYPE_NONE;
e.solid = SOLID_NOT;
e.count = num;
e.think = PlayerDeathBubblesSpawn;
e.nextthink = time + 0.01;
};
/*==========
PlayerPainSound
==========*/
void(entity attacker) PlayerPainSound =
{
// liquid pain sounds
if (self.watertype == CONTENT_WATER)
{
if (self.waterlevel == 3)
{
PlayerDeathBubbles(1);
if (random() < 0.5)
sound (self, CHAN_VOICE, "player/drown1.wav", 1, ATTN_NORM);
else
sound (self, CHAN_VOICE, "player/drown2.wav", 1, ATTN_NORM);
return;
}
}
if (self.watertype == CONTENT_SLIME)
{
if (random() < 0.5)
sound (self, CHAN_VOICE, "player/lburn1.wav", 1, ATTN_NORM);
else
sound (self, CHAN_VOICE, "player/lburn2.wav", 1, ATTN_NORM);
return;
}
if (self.watertype == CONTENT_LAVA)
{
if (random() < 0.5)
sound (self, CHAN_VOICE, "player/lburn1.wav", 1, ATTN_NORM);
else
sound (self, CHAN_VOICE, "player/lburn2.wav", 1, ATTN_NORM);
return;
}
if (self.pain_finished > time)
return;
self.pain_finished = time + 0.5;
/*if (self.axhitme == 1)
{
self.axhitme = 0;
sound (self, CHAN_VOICE, "player/axhit1.wav", 1, ATTN_NORM);
return;
}*/
float r = randomrange(6);
if (r == 0)
sound (self, CHAN_VOICE, "player/pain1.wav", 1, ATTN_NORM);
else if (r == 1)
sound (self, CHAN_VOICE, "player/pain2.wav", 1, ATTN_NORM);
else if (r == 2)
sound (self, CHAN_VOICE, "player/pain3.wav", 1, ATTN_NORM);
else if (r == 3)
sound (self, CHAN_VOICE, "player/pain4.wav", 1, ATTN_NORM);
else if (r == 4)
sound (self, CHAN_VOICE, "player/pain5.wav", 1, ATTN_NORM);
else
sound (self, CHAN_VOICE, "player/pain6.wav", 1, ATTN_NORM);
};
void() player_pain1 = [ $pain1, player_pain2 ] {};
void() player_pain2 = [ $pain2, player_pain3 ] {};
void() player_pain3 = [ $pain3, player_pain4 ] {};
void() player_pain4 = [ $pain4, player_pain5 ] {};
void() player_pain5 = [ $pain5, player_pain6 ] {};
void() player_pain6 = [ $pain6, player_run ] {};
void() player_axpain1 = [ $axpain1, player_axpain2 ] {};
void() player_axpain2 = [ $axpain2, player_axpain3 ] {};
void() player_axpain3 = [ $axpain3, player_axpain4 ] {};
void() player_axpain4 = [ $axpain4, player_axpain5 ] {};
void() player_axpain5 = [ $axpain5, player_axpain6 ] {};
void() player_axpain6 = [ $axpain6, player_run ] {};
/*==========
player_pain
==========*/
void(entity attacker, float damage) player_pain =
{
if (self.weaponframe)
return;
if (self.items & IT_INVISIBILITY)
return;
PlayerPainSound(attacker);
if (self.weapon == IT_AXE)
player_axpain1 ();
else
player_pain1 ();
};
/*==========
PlayerDeathSound
==========*/
static void() PlayerDeathSound =
{
// water death sounds
if (self.waterlevel == 3)
{
PlayerDeathBubbles(20);
sound (self, CHAN_VOICE, "player/h2odeath.wav", 1, ATTN_NONE);
return;
}
float r = randomrange(5);
if (r == 0)
self.noise = "player/death1.wav";
else if (r == 1)
self.noise = "player/death2.wav";
else if (r == 2)
self.noise = "player/death3.wav";
else if (r == 3)
self.noise = "player/death4.wav";
else
self.noise = "player/death5.wav";
sound (self, CHAN_VOICE, self.noise, 1, ATTN_NONE);
};
/*==========
PlayerDead
==========*/
static void() PlayerDead =
{
self.think = SUB_Null;
self.nextthink = -1;
self.deadflag = DEAD_DEAD;
};
void() player_diea1 = [ $deatha1, player_diea2 ] {};
void() player_diea2 = [ $deatha2, player_diea3 ] {};
void() player_diea3 = [ $deatha3, player_diea4 ] {};
void() player_diea4 = [ $deatha4, player_diea5 ] {};
void() player_diea5 = [ $deatha5, player_diea6 ] {};
void() player_diea6 = [ $deatha6, player_diea7 ] {};
void() player_diea7 = [ $deatha7, player_diea8 ] {};
void() player_diea8 = [ $deatha8, player_diea9 ] {};
void() player_diea9 = [ $deatha9, player_diea10 ] {};
void() player_diea10 = [ $deatha10, player_diea11 ] {};
void() player_diea11 = [ $deatha11, player_diea11 ] {PlayerDead();};
void() player_dieb1 = [ $deathb1, player_dieb2 ] {};
void() player_dieb2 = [ $deathb2, player_dieb3 ] {};
void() player_dieb3 = [ $deathb3, player_dieb4 ] {};
void() player_dieb4 = [ $deathb4, player_dieb5 ] {};
void() player_dieb5 = [ $deathb5, player_dieb6 ] {};
void() player_dieb6 = [ $deathb6, player_dieb7 ] {};
void() player_dieb7 = [ $deathb7, player_dieb8 ] {};
void() player_dieb8 = [ $deathb8, player_dieb9 ] {};
void() player_dieb9 = [ $deathb9, player_dieb9 ] {PlayerDead();};
void() player_diec1 = [ $deathc1, player_diec2 ] {};
void() player_diec2 = [ $deathc2, player_diec3 ] {};
void() player_diec3 = [ $deathc3, player_diec4 ] {};
void() player_diec4 = [ $deathc4, player_diec5 ] {};
void() player_diec5 = [ $deathc5, player_diec6 ] {};
void() player_diec6 = [ $deathc6, player_diec7 ] {};
void() player_diec7 = [ $deathc7, player_diec8 ] {};
void() player_diec8 = [ $deathc8, player_diec9 ] {};
void() player_diec9 = [ $deathc9, player_diec10 ] {};
void() player_diec10 = [ $deathc10, player_diec11 ] {};
void() player_diec11 = [ $deathc11, player_diec12 ] {};
void() player_diec12 = [ $deathc12, player_diec13 ] {};
void() player_diec13 = [ $deathc13, player_diec14 ] {};
void() player_diec14 = [ $deathc14, player_diec15 ] {};
void() player_diec15 = [ $deathc15, player_diec15 ] {PlayerDead();};
void() player_died1 = [ $deathd1, player_died2 ] {};
void() player_died2 = [ $deathd2, player_died3 ] {};
void() player_died3 = [ $deathd3, player_died4 ] {};
void() player_died4 = [ $deathd4, player_died5 ] {};
void() player_died5 = [ $deathd5, player_died6 ] {};
void() player_died6 = [ $deathd6, player_died7 ] {};
void() player_died7 = [ $deathd7, player_died8 ] {};
void() player_died8 = [ $deathd8, player_died9 ] {};
void() player_died9 = [ $deathd9, player_died9 ] {PlayerDead();};
void() player_diee1 = [ $deathe1, player_diee2 ] {};
void() player_diee2 = [ $deathe2, player_diee3 ] {};
void() player_diee3 = [ $deathe3, player_diee4 ] {};
void() player_diee4 = [ $deathe4, player_diee5 ] {};
void() player_diee5 = [ $deathe5, player_diee6 ] {};
void() player_diee6 = [ $deathe6, player_diee7 ] {};
void() player_diee7 = [ $deathe7, player_diee8 ] {};
void() player_diee8 = [ $deathe8, player_diee9 ] {};
void() player_diee9 = [ $deathe9, player_diee9 ] {PlayerDead();};
void() player_die_ax1 = [ $axdeth1, player_die_ax2 ] {};
void() player_die_ax2 = [ $axdeth2, player_die_ax3 ] {};
void() player_die_ax3 = [ $axdeth3, player_die_ax4 ] {};
void() player_die_ax4 = [ $axdeth4, player_die_ax5 ] {};
void() player_die_ax5 = [ $axdeth5, player_die_ax6 ] {};
void() player_die_ax6 = [ $axdeth6, player_die_ax7 ] {};
void() player_die_ax7 = [ $axdeth7, player_die_ax8 ] {};
void() player_die_ax8 = [ $axdeth8, player_die_ax9 ] {};
void() player_die_ax9 = [ $axdeth9, player_die_ax9 ] {PlayerDead();};
/*==========
PlayerDie
==========*/
void(entity inflictor, entity attacker) PlayerDie =
{
// remove any powerups
self.effects = 0;
self.items = self.items - (self.items &
(IT_SUPERHEALTH | IT_INVISIBILITY | IT_INVULNERABILITY | IT_SUIT | IT_QUAD) );
self.modelindex = modelindex_player;
if (deathmatch || coop)
DropBackpack();
self.weaponmodel = "";
// check for gib
if (self.health < -40)
{
SpawnGib("progs/gib1.mdl");
SpawnGib("progs/gib2.mdl");
SpawnGib("progs/gib3.mdl");
SpawnGib("progs/gib4.mdl");
SpawnGib("progs/gib5.mdl");
SpawnGib("progs/blood.mdl");
SpawnGib("progs/blood.mdl");
BecomeGibs();
return;
}
// remove any pitch and roll and set eye position
self.angles_x = 0;
self.angles_z = 0;
self.view_ofs = '0 0 -8';
self.deadflag = DEAD_DYING;
self.solid = SOLID_NOT;
self.movetype = MOVETYPE_TOSS;
// give a dying player an upward push
self.flags = self.flags - (self.flags & FL_ONGROUND);
if (self.velocity_z < 10)
self.velocity_z = self.velocity_z + random()*300;
// choose death animation
PlayerDeathSound();
if (self.weapon == IT_AXE)
{
player_die_ax1 ();
return;
}
float i = randomrange(5);
if (i == 0)
player_diea1();
else if (i == 1)
player_dieb1();
else if (i == 2)
player_diec1();
else if (i == 3)
player_died1();
else
player_diee1();
};

View File

@@ -0,0 +1,78 @@
../../progs.dat
#pragma optimise 1
#pragma optimise strip_unused_fields
#copyright Michael Coburn (c0burn) - michael.s.coburn@gmail.com
defs.qc
subs.qc
util.qc
targets.qc
tempents.qc
obituary.qc
damage.qc
gore.qc
projectiles.qc
w_shotguns.qc
weapons.qc
waypoints.qc
monsters.qc
fight.qc
ai.qc
items.qc
it_ammo.qc
it_armor.qc
it_backpack.qc
it_health.qc
it_keys.qc
it_powerups.qc
it_weapons.qc
ambient.qc
bodyque.qc
bmodel.qc
breakable.qc
bubbles.qc
buttons.qc
doors.qc
info.qc
lights.qc
misc.qc
plats.qc
trains.qc
trap_explobox.qc
trap_fireball.qc
trap_shooter.qc
triggers.qc
trigger_changelevel.qc
trigger_hurt.qc
trigger_ladder.qc
trigger_monsterjump.qc
trigger_push.qc
trigger_teleport.qc
world.qc
intermission.qc
client.qc
player.qc
monsters/ogre.qc
monsters/demon.qc
monsters/shambler.qc
monsters/knight.qc
monsters/soldier.qc
monsters/wizard.qc
monsters/dog.qc
monsters/zombie.qc
monsters/boss.qc
monsters/tarbaby.qc
monsters/hknight.qc
monsters/fish.qc
monsters/shalrath.qc
monsters/enforcer.qc
monsters/oldone.qc

View File

@@ -0,0 +1,144 @@
void() s_explode1 = [0, s_explode2] {};
void() s_explode2 = [1, s_explode3] {};
void() s_explode3 = [2, s_explode4] {};
void() s_explode4 = [3, s_explode5] {};
void() s_explode5 = [4, s_explode6] {};
void() s_explode6 = [5, SUB_Remove] {};
/*==========
BecomeExplosion
==========*/
void() BecomeExplosion =
{
self.solid = SOLID_NOT;
self.movetype = MOVETYPE_NONE;
self.velocity = '0 0 0';
self.touch = SUB_Null;
setmodel (self, "progs/s_explod.spr");
s_explode1();
};
/*==========
grenade_explode
==========*/
static void() grenade_explode =
{
RadiusDamage (self, self.owner, self.dmg, world);
te_explosion(self.origin);
BecomeExplosion();
};
/*==========
grenade_touch
==========*/
static void() grenade_touch =
{
if (pointcontents(self.origin) == CONTENT_SKY)
{
remove(self);
return;
}
if (other.takedamage == DAMAGE_AIM)
{
grenade_explode();
return;
}
sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);
};
/*==========
launch_grenade
used for player, zombie and ogre grenades
==========*/
void(vector org, vector dir, float spd, float dam) launch_grenade =
{
newmis = spawn();
newmis.classname = "grenade";
newmis.owner = self;
newmis.solid = SOLID_BBOX;
newmis.movetype = MOVETYPE_BOUNCE;
setmodel (newmis, "progs/grenade.mdl");
setsize (newmis, '0 0 0', '0 0 0');
setorigin (newmis, org);
newmis.dmg = dam;
newmis.touch = grenade_touch;
newmis.angles = vectoangles(dir);
newmis.velocity = dir * spd;
newmis.think = grenade_explode;
newmis.nextthink = time + 2.5;
};
/*==========
spike_touch
==========*/
static void() spike_touch2 =
{
if (pointcontents(self.origin) == CONTENT_SKY)
{
remove(self);
return;
}
// move out of the wall / floor slightly
self.origin = self.origin - 8*normalize(self.velocity);
// lasers always play an impact sound
if (self.classname == "laser")
sound (self, CHAN_WEAPON, "enforcer/enfstop.wav", 1, ATTN_IDLE);
if (other.takedamage)
{
Damage(other, self, self.owner, self.dmg);
if (other.solid == SOLID_BSP)
SpawnTouchParticles(self.dmg, 192);
else
SpawnTouchblood(self.dmg);
}
else
{
if (self.classname == "laser")
te_gunshot(self.origin);
else if (self.classname == "spike")
te_spike(self.origin);
else if (self.classname == "superspike")
te_superspike(self.origin);
else if (self.classname == "wizspike")
te_wizspike(self.origin);
else if (self.classname == "knightspike")
te_knightspike(self.origin);
}
remove(self);
};
/*==========
launch_spike
used for nails, lasers, scrag spit and hellknight fire
==========*/
void(string name, string mod, vector org, vector dir, float spd, float dam) launch_spike2 =
{
newmis = spawn();
newmis.classname = name; // spike, superspike, laser, knightspike, wizspike
newmis.owner = self;
newmis.solid = SOLID_BBOX;
newmis.movetype = MOVETYPE_FLYMISSILE;
setmodel (newmis, mod);
setsize (newmis, '0 0 0', '0 0 0');
setorigin (newmis, org);
newmis.dmg = dam;
newmis.touch = spike_touch2;
newmis.angles = vectoangles(dir);
newmis.velocity = dir * spd;
newmis.think = SUB_Remove;
newmis.nextthink = time + 10;
};

View File

@@ -0,0 +1,119 @@
/*==========
SUB_PainNull
==========*/
void(entity attacker, float damage) SUB_PainNull = {};
/*==========
SUB_Null
==========*/
void() SUB_Null = {};
/*==========
SUB_Remove
==========*/
void() SUB_Remove = {remove(self);};
/*==========
SUB_Fade
==========*/
void() SUB_Fade =
{
if (self.alpha == 0)
self.alpha = 1;
self.alpha = self.alpha - 0.1;
if (self.alpha <= 0)
{
remove(self);
return;
}
self.think = SUB_Fade;
self.nextthink = time + 0.1;
};
/*==========
SetMoveDir
the angle field in map editors is a single float, so up and down are constant values
==========*/
void() SetMovedir =
{
if (self.angles == '0 -1 0') // up
self.movedir = '0 0 1';
else if (self.angles == '0 -2 0') // down
self.movedir = '0 0 -1';
else
{
makevectors (self.angles);
self.movedir = v_forward;
}
self.angles = '0 0 0';
};
/*==========
SUB_CalcMoveDone
After moving, set origin to exact final destination and run think1
==========*/
void() SUB_CalcMoveDone =
{
setorigin(self, self.finaldest);
self.velocity = '0 0 0';
self.think = SUB_Null;
self.nextthink = -1;
if (self.think1)
self.think1();
};
/*==========
SUB_CalcMove
calculate self.velocity and self.nextthink to reach dest from
self.origin traveling at speed
==========*/
void(vector dst, float spd, void() thnk) SUB_CalcMove =
{
if (!spd)
{
objerror("SUB_CalcMove: no speed defined");
return;
}
self.think = SUB_CalcMoveDone;
self.think1 = thnk;
self.finaldest = dst;
if (dst == self.origin)
{
self.velocity = '0 0 0';
if (self.movetype == MOVETYPE_PUSH)
self.nextthink = self.ltime + 0.01;
else
self.nextthink = time + 0.01;
return;
}
vector delta = dst - self.origin;
float traveltime = vlen(delta) / spd;
if (traveltime < 0.01)
{
self.velocity = '0 0 0';
if (self.movetype == MOVETYPE_PUSH)
self.nextthink = self.ltime + 0.01;
else
self.nextthink = time + 0.01;
return;
}
self.velocity = delta / traveltime;
if (self.movetype == MOVETYPE_PUSH)
self.nextthink = self.ltime + traveltime;
else
self.nextthink = time + traveltime;
};
void(float normal) SUB_AttackFinished =
{
self.cnt = 0; // refire count for nightmare
if (skill != 3)
self.attack_finished = time + normal;
};

View File

@@ -0,0 +1,130 @@
void() UseTargets;
/*==========
DelayUseTargets
use targets after a delay
==========*/
void() DelayUseTargets =
{
activator = self.enemy;
UseTargets();
remove(self); // temporary entity
};
/*==========
DelayKillTargets
actually removes any kiltargets
==========*/
void() DelayKillTargets =
{
entity e = world;
while (1)
{
e = find(e, targetname, self.killtarget);
if (!e)
break;
remove(e);
}
remove(self); // temporary entity
};
/*==========
UseTargets
"activator" should be set to the entity that initiated the firing
Centerprints any "message" to the "activator"
Removes all entities with a "targetname" that matches "killtarget"
Finds all entities with a "targetname" that matches "target" and calls their "use" function
If "delay" is set, a temporary entity will be created that will only fire the targets after the delay
==========*/
void() UseTargets =
{
entity e, act;
// if delay is set, create a temporary entity to fire later
if (self.delay > 0)
{
e = spawn();
e.classname = "DelayUseTargets";
e.enemy = activator;
e.message = self.message;
e.target = self.target;
e.killtarget = self.killtarget;
e.think = DelayUseTargets;
e.nextthink = time + self.delay;
return;
}
// print any message if the activator is a player
if (activator.classname == "player" && self.message != "")
{
centerprint (activator, self.message);
if (!self.noise)
sound (activator, CHAN_VOICE, "misc/talk.wav", 1, ATTN_NORM);
}
// remove any killtargets. we now support setting both target and killtarget on entities.
if (self.killtarget != "")
{
// we use a think to remove the killtargets because we could be in the
// middle of a touch function, which can cause crashes in vanilla engines
// without fixed SV_TouchLinks
e = spawn();
e.classname = "DelayKillTargets";
e.killtarget = self.killtarget;
e.think = DelayKillTargets;
e.nextthink = time; // do it on the next frame
// clear out some essential fields to stop it being used before the actual removal
e = world;
while (1)
{
e = find(e, targetname, self.killtarget);
if (!e)
break;
e.use = SUB_Null;
e.touch = SUB_Null;
e.think = SUB_Null;
e.nextthink = -1;
}
// workaround for various maps that have triggers which contains both "target" and "killtarget"
// set to identical values
if (self.target == self.killtarget)
return;
}
// fire any targets
if (self.target != "")
{
act = activator;
e = world;
while (1)
{
e = find (e, targetname, self.target);
if (!e)
break;
// save globals
// set self to the entity being triggered and other to the activator
entity stemp = self;
entity otemp = other;
self = e;
other = stemp;
if (self.use)
self.use();
// restore globals
self = stemp;
other = otemp;
activator = act;
}
}
};

View File

@@ -0,0 +1,185 @@
/*==========
te_teleport
==========*/
void(vector org) te_teleport =
{
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_TELEPORT);
WriteCoord (MSG_BROADCAST, org_x);
WriteCoord (MSG_BROADCAST, org_y);
WriteCoord (MSG_BROADCAST, org_z);
};
/*==========
te_teleport
==========*/
void(vector org) te_explosion =
{
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_EXPLOSION);
WriteCoord (MSG_BROADCAST, org_x);
WriteCoord (MSG_BROADCAST, org_y);
WriteCoord (MSG_BROADCAST, org_z);
};
/*==========
te_explosion2
==========*/
void(vector org, float col, float len) te_explosion2 =
{
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_EXPLOSION2);
WriteCoord (MSG_BROADCAST, org_x);
WriteCoord (MSG_BROADCAST, org_y);
WriteCoord (MSG_BROADCAST, org_z);
WriteByte (MSG_BROADCAST, col);
WriteByte (MSG_BROADCAST, len);
};
/*==========
te_tarexplosion
==========*/
void(vector org) te_tarexplosion =
{
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_TAREXPLOSION);
WriteCoord (MSG_BROADCAST, org_x);
WriteCoord (MSG_BROADCAST, org_y);
WriteCoord (MSG_BROADCAST, org_z);
};
/*==========
te_gunshot
==========*/
void(vector org) te_gunshot =
{
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_GUNSHOT);
WriteCoord (MSG_BROADCAST, org_x);
WriteCoord (MSG_BROADCAST, org_y);
WriteCoord (MSG_BROADCAST, org_z);
};
/*==========
te_spike
==========*/
void(vector org) te_spike =
{
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_SPIKE);
WriteCoord (MSG_BROADCAST, org_x);
WriteCoord (MSG_BROADCAST, org_y);
WriteCoord (MSG_BROADCAST, org_z);
};
/*==========
te_superspike
==========*/
void(vector org) te_superspike =
{
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_SUPERSPIKE);
WriteCoord (MSG_BROADCAST, org_x);
WriteCoord (MSG_BROADCAST, org_y);
WriteCoord (MSG_BROADCAST, org_z);
};
/*==========
te_wizspike
==========*/
void(vector org) te_wizspike =
{
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_WIZSPIKE);
WriteCoord (MSG_BROADCAST, org_x);
WriteCoord (MSG_BROADCAST, org_y);
WriteCoord (MSG_BROADCAST, org_z);
};
/*==========
te_knightspike
==========*/
void(vector org) te_knightspike =
{
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_KNIGHTSPIKE);
WriteCoord (MSG_BROADCAST, org_x);
WriteCoord (MSG_BROADCAST, org_y);
WriteCoord (MSG_BROADCAST, org_z);
};
/*==========
te_lightning1
==========*/
void(vector v1, vector v2, entity ent) te_lightning1 =
{
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_LIGHTNING1);
WriteEntity (MSG_BROADCAST, ent);
WriteCoord (MSG_BROADCAST, v1_x);
WriteCoord (MSG_BROADCAST, v1_y);
WriteCoord (MSG_BROADCAST, v1_z);
WriteCoord (MSG_BROADCAST, v2_x);
WriteCoord (MSG_BROADCAST, v2_y);
WriteCoord (MSG_BROADCAST, v2_z);
};
/*==========
te_lightning2
==========*/
void(vector v1, vector v2, entity ent) te_lightning2 =
{
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
WriteEntity (MSG_BROADCAST, ent);
WriteCoord (MSG_BROADCAST, v1_x);
WriteCoord (MSG_BROADCAST, v1_y);
WriteCoord (MSG_BROADCAST, v1_z);
WriteCoord (MSG_BROADCAST, v2_x);
WriteCoord (MSG_BROADCAST, v2_y);
WriteCoord (MSG_BROADCAST, v2_z);
};
/*==========
te_lightning3
==========*/
void(vector v1, vector v2, entity ent) te_lightning3 =
{
WriteByte (MSG_ALL, SVC_TEMPENTITY);
WriteByte (MSG_ALL, TE_LIGHTNING3);
WriteEntity (MSG_ALL, ent);
WriteCoord (MSG_ALL, v1_x);
WriteCoord (MSG_ALL, v1_y);
WriteCoord (MSG_ALL, v1_z);
WriteCoord (MSG_ALL, v2_x);
WriteCoord (MSG_ALL, v2_y);
WriteCoord (MSG_ALL, v2_z);
};
/*==========
te_beam
==========*/
void(vector v1, vector v2, entity ent) te_beam =
{
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_BEAM);
WriteEntity (MSG_BROADCAST, ent);
WriteCoord (MSG_BROADCAST, v1_x);
WriteCoord (MSG_BROADCAST, v1_y);
WriteCoord (MSG_BROADCAST, v1_z);
WriteCoord (MSG_BROADCAST, v2_x);
WriteCoord (MSG_BROADCAST, v2_y);
WriteCoord (MSG_BROADCAST, v2_z);
};
/*==========
te_lavasplash
==========*/
void(vector org) te_lavasplash =
{
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_LAVASPLASH);
WriteCoord (MSG_BROADCAST, org_x);
WriteCoord (MSG_BROADCAST, org_y);
WriteCoord (MSG_BROADCAST, org_z);
};

View File

@@ -0,0 +1,159 @@
void() train_next;
void() train_blocked =
{
if (time < self.attack_finished)
return;
self.attack_finished = time + 0.5;
Damage (other, self, self, self.dmg);
};
void() train_wait =
{
self.think = train_next;
if (self.wait > 0)
{
if (self.movetype == MOVETYPE_PUSH)
self.nextthink = self.ltime + self.wait;
else
self.nextthink = time + self.wait;
if (self.noise != "")
sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
}
else
{
if (self.movetype == MOVETYPE_PUSH)
self.nextthink = self.ltime + 0.1;
else
self.nextthink = time + 0.1;
}
};
void() train_next =
{
entity targ = find(world, targetname, self.target);
self.target = targ.target;
if (!self.target)
{
self.velocity = '0 0 0';
self.think = SUB_Null;
self.nextthink = -1;
objerror("train_next: no next target");
return;
}
if (targ.wait > 0)
self.wait = targ.wait;
else
self.wait = 0;
if (self.noise1 != "")
sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
SUB_CalcMove (targ.origin - self.mins, self.speed, train_wait);
};
void() train_use =
{
self.use = SUB_Null;
train_next();
};
void() train_find =
{
entity targ = find(world, targetname, self.target);
self.target = targ.target;
setorigin (self, targ.origin - self.mins);
if (!self.targetname)
{
if (self.movetype == MOVETYPE_PUSH)
self.nextthink = self.ltime + 0.1;
else
self.nextthink = time + 0.1;
self.think = train_next;
}
else
self.use = train_use;
};
/*QUAKED func_train (0 .5 .8) ?
Trains are moving platforms that players can ride.
Must target a series of 'path_corner' entities.
The targets origin specifies the min point of the train at each corner.
It will always position itself on its first target at map load.
If a targetname is set, it must be triggered to start moving, otherwise it will start immediately.
speed default 100
dmg default 2
sounds
-1) custom, set "noise" and "noise1"
0) none
1) ratchet metal
*/
void() func_train =
{
if (!self.target)
{
objerror ("func_train without a target");
remove(self);
return;
}
self.solid = SOLID_BSP;
self.movetype = MOVETYPE_PUSH;
self.blocked = train_blocked;
setmodel (self, self.model);
setsize (self, self.mins, self.maxs);
setorigin (self, self.origin);
SetPositiveDefault(speed, 100);
SetPositiveDefault(dmg, 2);
if (self.sounds == 0)
{
self.noise = "";
self.noise1 = "";
}
else if (self.sounds == 1)
{
self.noise = "plats/train2.wav";
self.noise1 = "plats/train1.wav";
}
if (self.noise != "")
precache_sound (self.noise);
if (self.noise1 != "")
precache_sound (self.noise1);
self.think = train_find;
self.nextthink = self.ltime + 0.1;
};
/*QUAKED misc_teleporttrain (.5 .5 .5) (-16 -16 -16) (16 16 16) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{ model("progs/teleport.mdl"); }
Floating teleporter target for final boss level. Must target a series of 'path_corner' entities.
It will always position itself on its first target at map load.
If a targetname is set, it must be triggered to start moving, otherwise it will start immediately.
speed default 100
*/
void() misc_teleporttrain =
{
if (!self.target)
{
objerror ("misc_teleporttrain without a target");
remove(self);
return;
}
self.solid = SOLID_NOT;
self.movetype = MOVETYPE_NOCLIP;
precache_model ("progs/teleport.mdl");
setmodel (self, "progs/teleport.mdl");
setsize (self, '-16 -16 -16', '16 16 16');
SetPositiveDefault(speed, 100);
self.avelocity = '20 40 80';
self.think = train_find;
self.nextthink = time + 0.1;
};

View File

@@ -0,0 +1,143 @@
/*==========
explobox_explode
==========*/
static void() explobox_explode =
{
setorigin(self, realorigin(self)); // fix our origin as we're a bmodel
RadiusDamage (self, self, self.dmg, world);
te_explosion(self.origin);
BecomeExplosion();
// fire targets
activator = self.enemy;
UseTargets();
};
/*==========
explobox_die
==========*/
static void(entity inflictor, entity attacker) explobox_die =
{
self.enemy = attacker; // for firing targets
self.solid = SOLID_NOT;
self.takedamage = DAMAGE_NO;
self.think = explobox_explode;
self.nextthink = self.ltime + 0.1;
};
/*==========
explobox_use
==========*/
static static void() explobox_use =
{
self.enemy = activator; // for firing targets
self.use = SUB_Null;
self.think = explobox_explode;
self.nextthink = self.ltime + 0.1;
};
/*==========
explobox_drop
==========*/
static float() explobox_drop =
{
self.origin_z = self.origin_z + 2;
if (!droptofloor())
{
dprint (self.classname);
dprint (" fell out of level at ");
dprint (vtos(realorigin(self)));
dprint ("\n");
remove(self);
return TRUE;
}
return FALSE;
};
/*==========
explobox_start
==========*/
static void() explobox_start =
{
self.solid = SOLID_BSP;
self.movetype = MOVETYPE_PUSH;
if (self.classname == "misc_explobox2")
{
precache_model2 ("maps/b_exbox2.bsp");
setmodel (self, "maps/b_exbox2.bsp");
setsize(self, '0 0 0', '32 32 32');
if (explobox_drop())
return;
}
else if (self.classname == "misc_explobox")
{
precache_model ("maps/b_explob.bsp");
setmodel (self, "maps/b_explob.bsp");
setsize(self, '0 0 0', '32 32 64');
if (explobox_drop())
return;
}
else
setmodel (self, self.model);
self.classname = "explobox";
SetPositiveDefault(dmg, 160);
self.colour = 192;
// if targetname is set, it must be triggered
if (self.targetname != "")
self.use = explobox_use;
else
{
SetPositiveDefault(health, 20);
self.takedamage = DAMAGE_AIM;
self.th_die = explobox_die;
}
};
/*QUAKED misc_explobox (1 .5 0) (0 0 0) (32 32 64) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model("maps/b_explob.bsp");
}
Large explosive box
If "targetname" is set, cannot be shot and must be triggered.
Keys:
"targetname" - if set, cannot be shot and must be triggered.
"health" - override default health of 20.
"dmg" - override default damage of 160.
*/
void() misc_explobox =
{
explobox_start();
};
/*QUAKED misc_explobox2 (1 .5 0) (0 0 0) (32 32 32) X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{
model("maps/b_exbox2.bsp");
}
Small explosive box
Keys:
"targetname" - if set, cannot be shot and must be triggered.
"health" - override default health of 20.
"dmg" - override default damage of 160.
*/
void() misc_explobox2 =
{
explobox_start();
};
/*QUAKED func_explosive (1 .5 0) ? X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
Brush that explodes when shot or triggered
Keys:
"targetname" - if set, cannot be shot and must be triggered.
"health" - override default health of 20.
"dmg" - override default damage of 160.
*/
void() func_explosive =
{
explobox_start();
};

View File

@@ -0,0 +1,87 @@
static enumflags { LAVABALL_SOUNDS };
/*==========
fireball_touch
==========*/
static void() fireball_touch =
{
if (other.classname == self.classname)
return;
Damage (other, self, self, self.dmg);
remove(self);
};
/*==========
fireball_launch
==========*/
static void() fireball_launch =
{
if (self.spawnflags & LAVABALL_SOUNDS)
sound (self, CHAN_VOICE, "boss1/throw.wav", 1, ATTN_NORM);
for (float i = 0; i < self.count; i++)
{
entity fireball = spawn();
fireball.classname = "fireball";
fireball.solid = SOLID_TRIGGER;
fireball.movetype = MOVETYPE_TOSS;
setmodel (fireball, "progs/lavaball.mdl");
setsize (fireball, '0 0 0', '0 0 0');
setorigin (fireball, self.origin);
fireball.velocity_x = crandom() * 50;
fireball.velocity_y = crandom() * 50;
fireball.velocity_z = self.speed + (random() * 200);
fireball.avelocity = [100, 100, 100];
fireball.touch = fireball_touch;
fireball.think = SUB_Remove;
fireball.nextthink = time + 5;
}
};
/*==========
fireball_fly
==========*/
static void() fireball_fly =
{
fireball_launch();
self.think = fireball_fly;
self.nextthink = time + self.wait + random()*self.wait;
};
/*QUAKED misc_fireball (1 .5 0) (-8 -8 -8) (8 8 8) SOUNDS X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
{ model ("progs/lavaball.mdl"); }
Flying lava balls
Keys:
speed - set the vertical speed of fireballs. default 1000.
wait - delay between fireballs (with some randomness). default 3 seconds.
count - number of fireballs to launch. default 1.
dmg - damage dealt by fireballs. default 20.
targetname - if set, must be triggered to activate.
Spawnflags:
SOUNDS - if set, fireballs will make a whooshing sound when launched.
*/
void() misc_fireball =
{
precache_model ("progs/lavaball.mdl");
if (self.spawnflags & LAVABALL_SOUNDS)
precache_sound ("boss1/throw.wav");
SetPositiveDefault(speed, 1000);
SetPositiveDefault(count, 1);
SetPositiveDefault(wait, 3);
SetPositiveDefault(dmg, 20);
// triggered only
if (self.targetname != "")
self.use = fireball_launch;
else
{
self.think = fireball_fly;
self.nextthink = time + self.wait + random()*self.wait;
}
};

View File

@@ -0,0 +1,93 @@
static enumflags { SHOOTER_SUPERSPIKE, SHOOTER_LASER };
void(vector org, vector vec) LaunchLaser;
/*==========
shooter_use
==========*/
static void() shooter_use =
{
if (self.spawnflags & SHOOTER_LASER)
{
sound (self, CHAN_VOICE, "enforcer/enfire.wav", 1, ATTN_NORM);
LaunchLaser (self.origin, self.movedir);
}
else if (self.spawnflags & SHOOTER_SUPERSPIKE)
{
sound (self, CHAN_VOICE, "weapons/spike2.wav", 1, ATTN_NORM);
launch_spike (self.origin, self.movedir);
newmis.touch = superspike_touch;
}
else
{
sound (self, CHAN_VOICE, "weapons/rocket1i.wav", 1, ATTN_NORM);
launch_spike (self.origin, self.movedir);
}
newmis.velocity = self.movedir * 500;
};
/*==========
shooter_think
==========*/
static void() shooter_think =
{
shooter_use();
self.think = shooter_think;
self.nextthink = time + self.wait;
};
/*==========
shooter_precache
==========*/
static void() shooter_precache =
{
if (self.spawnflags & SHOOTER_LASER)
{
precache_model2 ("progs/laser.mdl");
precache_sound2 ("enforcer/enfire.wav");
precache_sound2 ("enforcer/enfstop.wav");
}
else if (self.spawnflags & SHOOTER_SUPERSPIKE)
precache_sound ("weapons/spike2.wav");
else
precache_sound("weapons/rocket1i.wav");
};
/*QUAKED trap_spikeshooter (1 .5 0) (-8 -8 -8) (8 8 8) SUPERSPIKE LASER
Fires projectiles when triggered.
Keys:
"angle" - direction of movement
Spawnflags:
If no spawnflag is set, shoots regular nails.
SUPERSPIKE - fire supernails
LASER - fire enforcer lasers
*/
void() trap_spikeshooter =
{
shooter_precache();
SetMovedir();
self.use = shooter_use;
};
/*QUAKED trap_shooter (1 .5 0) (-8 -8 -8) (8 8 8) SUPERSPIKE LASER
Continuously fires projectiles.
Keys:
"angle" - direction of movement
"wait" - time between shots
"nextthink" - delay on first shot, so shooters can be staggered.
Spawnflags:
If no spawnflag is set, shoots regular nails.
SUPERSPIKE - fire supernails
LASER - fire enforcer lasers
*/
void() trap_shooter =
{
shooter_precache();
SetPositiveDefault(wait, 1);
self.think = shooter_think;
self.nextthink = self.nextthink + self.wait;
};

View File

@@ -0,0 +1,58 @@
enumflags { CHANGELEVEL_NO_INTERMISSION };
void() GotoNextMap;
void() StartIntermission;
/*==========
changelevel_touch
==========*/
void() changelevel_touch =
{
if (other.classname != "player")
return;
if (other.health <= 0)
return;
if ((cvar("noexit") && (mapname != "start") && deathmatch))
{
if (cvar("noexit") == 2)
Damage (other, self, self, 50000);
return;
}
if (coop || deathmatch)
{
bprint (other.netname);
bprint (" exited the level\n");
}
nextmap = self.map;
activator = other;
UseTargets();
if ((self.spawnflags & CHANGELEVEL_NO_INTERMISSION) && (!deathmatch))
{
GotoNextMap();
return;
}
self.touch = SUB_Null;
self.think = StartIntermission;
self.nextthink = time + 0.1;
};
/*QUAKED trigger_changelevel (0.5 0.5 0.5) ? NO_INTERMISSION X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
When the player touches this trigger, they get sent to the map listed in the "map" key.
Unless the NO_INTERMISSION flag is set, the view will go to the info_intermission spot and display the end of level stats.
*/
void() trigger_changelevel =
{
if (!self.map)
{
objerror("no map");
remove(self);
return;
}
self.touch = changelevel_touch;
InitTrigger();
};

View File

@@ -0,0 +1,74 @@
/*==========
hurt_touch
this was seriously bugged in id1. now correctly damages everything touching it.
==========*/
static void() hurt_touch =
{
force_retouch = 2;
if (other.takedamage)
{
if (other.hurt_time > time)
return;
Damage (other, self, self, self.dmg);
other.hurt_time = time + self.wait;
}
};
/*QUAKED trigger_hurt (.5 .5 .5) ? X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
A trigger that damages anything alive that touches it.
Keys:
dmg - damage to deal. default 5.
wait - time in seconds between causing damage. default 1
*/
void() trigger_hurt =
{
self.touch = hurt_touch;
SetPositiveDefault(dmg, 5);
SetPositiveDefault(wait, 1);
InitTrigger();
};
/*==========
void_touch
==========*/
static void() void_touch =
{
force_retouch = 2;
// just remove items and monsters
if (other.flags & FL_ITEM || other.flags & FL_MONSTER)
{
remove(other);
return;
}
// insta kill players
if (other.flags & FL_CLIENT)
{
// remove all armor
other.items = other.items - (other.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3));
other.armortype = other.armorvalue = 0;
// remove pent
other.items = other.items - other.items & IT_INVULNERABILITY;
other.invincible_finished = other.invincible_time = other.invincible_sound = 0;
// black screen
stuffcmd(other, "v_cshift 0 0 0 255\n");
Damage (other, self, self, other.health);
return;
}
};
/*QUAKED trigger_void (.5 .5 .5) ? X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
A variable sized trigger designed for "void" areas that removes items, projectiles and monsters touching it.
Always kills the player regardless of pentagram or armor.
*/
void() trigger_void =
{
self.touch = void_touch;
InitTrigger();
};

View File

@@ -0,0 +1,34 @@
#define SMALL_FLOAT (float)(__variant)0x00800000i
/*==========
ladder_touch
==========*/
static void() ladder_touch =
{
if (other.classname != "player")
return;
if (other.health <= 0)
return;
// check player is facing the right way
if (self.movedir)
{
makevectors (other.angles);
if (v_forward * self.movedir < 0)
return;
}
other.flags2 = other.flags2 | FL2_ONLADDER;
other.gravity = SMALL_FLOAT; // because setting it to 0 would be normal gravity
};
/*QUAKED trigger_ladder (.5 .5 .5) ? X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
Invisible ladder trigger.
When the player is touching this trigger, they can climb by holding jump.
If "angle" is set, the player must face that direction to climb the ladder.
An angle of 0 is assumed to mean no direction, so use an angle of 360 instead.
*/
void() trigger_ladder =
{
InitTrigger();
self.touch = ladder_touch;
};

View File

@@ -0,0 +1,43 @@
/*==========
monsterjump_touch
==========*/
static void() monsterjump_touch =
{
if (other.flags & (FL_MONSTER | FL_FLY | FL_SWIM) != FL_MONSTER)
return;
if (other.health <= 0)
return;
if (self.netname != "")
{
if (other.classname != self.netname)
return;
}
// set XY even if not on ground, so the jump will clear lips
other.velocity_x = self.movedir_x * self.speed;
other.velocity_y = self.movedir_y * self.speed;
if (!(other.flags & FL_ONGROUND))
return;
other.flags = other.flags - FL_ONGROUND;
other.velocity_z = self.height;
};
/*QUAKED trigger_monsterjump (.5 .5 .5) ? X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
Walking monsters that touch this will jump at a set "speed" and "height" according to "angle"
Keys:
"angle" - angle to fling monsters
"speed" - defaults to 200, the speed thrown forward
"height" - defaults to 200, the speed thrown upwards
"netname" - only monsters with this classname will be affected, e.g. "monster_shambler"
*/
void() trigger_monsterjump =
{
if (!self.angles)
self.angles = '0 360 0';
SetPositiveDefault(speed, 200);
SetPositiveDefault(height, 200);
self.touch = monsterjump_touch;
InitTrigger();
};

View File

@@ -0,0 +1,49 @@
static enumflags { PUSH_ONCE, PUSH_NO_SOUND };
/*==========
push_touch
==========*/
static void() push_touch =
{
if (other.classname == "grenade")
other.velocity = self.speed * self.movedir * 10;
else if (other.health > 0)
{
other.velocity = self.speed * self.movedir * 10;
if (other.classname == "player" && !(self.spawnflags & PUSH_NO_SOUND))
{
if (other.fly_sound < time)
{
other.fly_sound = time + 1.5;
sound (other, CHAN_AUTO, self.noise, 1, ATTN_NORM);
}
}
}
if (self.spawnflags & PUSH_ONCE)
{
self.solid = SOLID_NOT;
self.touch = SUB_Null;
self.think = SUB_Remove;
self.nextthink = time;
}
};
/*QUAKED trigger_push (.5 .5 .5) ? PUSH_ONCE NO_SOUND X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
Pushes the player in the direction of "angle" at "speed" and makes the flying wind sound.
Note that "speed" will be multiplied by a factor of 10, so 30 = 300
Use an "angle" of 360 for 0, -1 for up and -2 for down.
Set "noise" for a custom sound
Set PUSH_ONCE to remove after first use.
Set NO_SOUND to make silent.
*/
void() trigger_push =
{
if (!(self.spawnflags & PUSH_NO_SOUND))
{
SetStringDefault(noise, "ambience/windfly.wav");
precache_sound (self.noise);
}
SetPositiveDefault(speed, 1000);
self.touch = push_touch;
InitTrigger();
};

View File

@@ -0,0 +1,198 @@
static enumflags { TELEPORT_PLAYER_ONLY, TELEPORT_SILENT };
/*==========
play_teleport
==========*/
static void() play_teleport =
{
float r = randomrange(5);
if (r == 0)
sound (self, CHAN_VOICE, "misc/r_tele1.wav", 1, ATTN_NORM);
else if (r == 1)
sound (self, CHAN_VOICE, "misc/r_tele2.wav", 1, ATTN_NORM);
else if (r == 2)
sound (self, CHAN_VOICE, "misc/r_tele3.wav", 1, ATTN_NORM);
else if (r == 3)
sound (self, CHAN_VOICE, "misc/r_tele4.wav", 1, ATTN_NORM);
else
sound (self, CHAN_VOICE, "misc/r_tele5.wav", 1, ATTN_NORM);
remove(self);
};
/*==========
spawn_tfog
==========*/
void(vector org) spawn_tfog =
{
te_teleport(org);
entity e = spawn();
setorigin(e, org);
e.think = play_teleport;
e.nextthink = time + 0.2; // delay sound slightly
};
/*==========
tdeath_touch
==========*/
static void() tdeath_touch =
{
if (!other.takedamage)
return;
if (other == self.owner) // the engine doesn't respect .owner for triggers!
return;
if (other.classname == "player")
{
// monsters can't telefrag players
if (self.owner.flags & FL_MONSTER)
{
Damage (self.owner, self, self, 50000);
return;
}
// check for pentagram on the player on the spot
if (other.items & IT_INVULNERABILITY)
{
// check for pentagram on both players
if (self.owner.items & IT_INVULNERABILITY)
{
// kill the player on the spot
self.classname = "teledeath3";
other.items = other.items - IT_INVULNERABILITY;
other.invincible_time = other.invincible_finished = 0;
Damage (other, self, self, 50000);
}
else
{
// kill the teleporting player
self.classname = "teledeath2";
Damage (self.owner, self, self, 50000);
}
return;
}
}
Damage(other, self, self, 50000);
};
/*==========
spawn_tdeath
==========*/
void(vector org, entity who) spawn_tdeath =
{
force_retouch = 2; // make sure even still objects get hit
entity e = spawn();
e.classname = "teledeath";
e.owner = who;
e.movetype = MOVETYPE_NONE;
e.solid = SOLID_TRIGGER;
setsize (e, who.mins - '1 1 1', who.maxs + '1 1 1');
setorigin (e, org);
e.touch = tdeath_touch;
e.think = SUB_Remove;
e.nextthink = time + 0.2;
};
/*==========
teleport_touch
==========*/
static void() teleport_touch =
{
if (self.spawnflags & TELEPORT_PLAYER_ONLY)
{
if (other.classname != "player")
return;
}
if (other.health <= 0)
return;
if (other.solid != SOLID_SLIDEBOX) // only players/monsters
return;
// look for the destination spot
entity t = find (world, targetname, self.target);
if (!t)
{
objerror ("couldn't find target");
remove(self);
return;
}
// some maps use things other then info_teleport_destination as targets for
// teleporters. just print a warning.
if (developer > 1)
{
if (t.classname != "info_teleport_destination")
{
dprint("warning: teleport destination is ");
dprint(t.classname);
dprint(" at ");
dprint(vtos(t.origin));
dprint("\n");
}
}
// fire targets
activator = other;
UseTargets();
// spawn teleport flash at source and destination
spawn_tfog (other.origin);
makevectors (t.angles);
vector org = t.origin + '0 0 27';
spawn_tfog (org + v_forward * 32);
spawn_tdeath(org, other);
// move the player/monster
setorigin (other, org);
other.angles = t.angles;
other.flags = other.flags - (other.flags & FL_ONGROUND);
if (other.classname == "player")
{
other.fixangle = TRUE; // turn this way immediately
other.teleport_time = time + 0.7; // don't let player move back into teleporter
other.velocity = v_forward * 300; // give a forwards push
}
};
/*==========
teleport_use
using a teleporter makes it active. it then behaves like any other teleporter.
==========*/
static void() teleport_use =
{
force_retouch = 2; // make sure even still objects get hit
self.touch = teleport_touch;
self.use = SUB_Null;
};
/*QUAKED trigger_teleport (.5 .5 .5) ? PLAYER_ONLY SILENT X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
Variable sized trigger that teleports players and monsters to a destination marker.
"target" must be set to an info_teleport_destination with a matching "targetname" field.
If the trigger_teleport has a "targetname", it will only teleport entities once it has been triggered.
This is used in id1 for teleporting monsters - this has been obsoleted by the MONSTER_TELEPORT flag.
Spawnflags:
PLAYER_ONLY - just players, not monsters
SILENT - don't spawn ambient teleporter noise
*/
void() trigger_teleport =
{
if (!self.target)
{
objerror ("no target");
remove(self);
return;
}
if (self.targetname != "")
self.use = teleport_use;
else
self.touch = teleport_touch;
if (!(self.spawnflags & TELEPORT_SILENT))
ambient_teleport();
InitTrigger();
};

View File

@@ -0,0 +1,349 @@
static enumflags { TRIGGER_NOTOUCH, TRIGGER_START_OFF };
/*==========
InitTrigger
==========*/
void() InitTrigger =
{
// if angles are set, the trigger is a one way touch
if (self.angles != '0 0 0')
SetMovedir();
// link into world
self.movetype = MOVETYPE_NONE;
self.solid = SOLID_TRIGGER;
setmodel (self, self.model);
// make invisible
self.modelindex = 0;
self.model = "";
};
/*==========
trigger_reactivate
==========*/
static void() trigger_reactivate =
{
// if shootable, make solid again
if (self.max_health)
{
self.health = self.max_health;
self.takedamage = DAMAGE_YES;
self.solid = SOLID_BBOX;
setorigin(self, self.origin); // link into world
}
};
/*==========
trigger_fire
==========*/
void() trigger_fire =
{
// already triggered
if (self.nextthink > time)
return;
// bump secret counter
if (self.classname == "trigger_secret")
{
if (self.enemy.classname != "player")
return;
found_secrets = found_secrets + 1;
WriteByte (MSG_ALL, SVC_FOUNDSECRET);
}
if (self.noise != "")
sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
// fire targets
activator = self.enemy;
UseTargets();
if (self.wait > 0)
{
self.think = trigger_reactivate;
self.nextthink = time + self.wait;
return;
}
remove(self);
};
/*==========
trigger_killed
==========*/
void(entity inflictor, entity attacker) trigger_killed =
{
self.takedamage = DAMAGE_NO;
self.enemy = attacker;
trigger_fire();
};
/*==========
trigger_use
==========*/
void() trigger_use =
{
self.enemy = activator;
trigger_fire();
};
/*==========
trigger_touch
==========*/
void() trigger_touch =
{
if (other.classname != "player")
return;
if (other.health <= 0)
return;
// check player is facing the right way
if (self.movedir)
{
makevectors (other.angles);
if (v_forward * self.movedir < 0)
return;
}
self.enemy = other;
trigger_fire();
};
/*QUAKED trigger_multiple (.5 .5 .5) ? NOTOUCH X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
Variable sized repeatable trigger.
Keys:
"target" - entities to trigger upon firing
"killtarget" - entities to remove upon firing
"message" - will be printed to player upon activation
"delay" - will wait after activation before firing
"health" - if set, trigger must be killed to activate
"wait" - time between triggers. default 0.2
"sounds" -
0) none
1) secret
2) beep beep
3) large switch
"angle" - player must be facing this direction to activate the trigger.
0 is assumed to mean no restriction, so use 360 for an angle of 0.
Spawnflags:
If NOTOUCH is set, the trigger is only fired by other entities, not by touching.
NOTOUCH has been obsoleted by trigger_relay.
*/
void() trigger_multiple =
{
if (self.sounds == 1)
self.noise = "misc/secret.wav";
else if (self.sounds == 2)
self.noise = "misc/talk.wav";
else if (self.sounds == 3)
self.noise = "misc/trigger1.wav";
if (self.noise != "")
precache_sound(self.noise);
SetFloatDefault(wait, 0.2);
self.use = trigger_use;
InitTrigger();
// shootable trigger
if (self.health > 0)
{
if (self.spawnflags & TRIGGER_NOTOUCH)
{
objerror ("health and NOTOUCH doesn't make sense\n");
remove(self);
return;
}
self.max_health = self.health;
self.th_die = trigger_killed;
self.takedamage = DAMAGE_YES;
self.solid = SOLID_BBOX;
setorigin (self, self.origin); // make sure it links into the world
return;
}
if (!(self.spawnflags & TRIGGER_NOTOUCH))
self.touch = trigger_touch;
};
/*QUAKED trigger_once (.5 .5 .5) ? NOTOUCH X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
Variable sized trigger. Triggers once, then removes itself.
Keys:
"target" - entities to trigger upon firing
"killtarget" - entities to remove upon firing
"message" - will be printed to player upon activation
"delay" - will wait after activation before firing
"health" - if set, trigger must be killed to activate
"wait" - time between triggers. default 0.2
"sounds" -
0) none
1) secret
2) beep beep
3) large switch
"angle" - player must be facing this direction to activate the trigger.
0 is assumed to mean no restriction, so use 360 for an angle of 0.
Spawnflags:
If NOTOUCH is set, the trigger is only fired by other entities, not by touching.
NOTOUCH has been obsoleted by trigger_relay.
*/
void() trigger_once =
{
self.wait = -1;
trigger_multiple();
};
/*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8)
This fixed size trigger cannot be touched, it can only be fired by other events.
It can contain targets, killtargets, delays, and messages.
*/
void() trigger_relay =
{
self.use = UseTargets;
};
/*QUAKED trigger_secret (.5 .5 .5) ? NOTOUCH X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
Variable sized secret counter trigger. Triggers once, then removes itself.
Keys:
"target" - entities to trigger upon firing
"killtarget" - entities to remove upon firing
"message" - will be printed to player upon activation. default "You found a secret area!"
"delay" - will wait after activation before firing
"health" - if set, trigger must be killed to activate
"sounds" -
1) secret (default)
2) beep beep
3) large switch
"angle" - player must be facing this direction to activate the trigger.
0 is assumed to mean no restriction, so use 360 for an angle of 0.
Spawnflags:
If NOTOUCH is set, the trigger is only fired by other entities, not by touching.
NOTOUCH has been obsoleted by trigger_relay.
*/
void() trigger_secret =
{
total_secrets = total_secrets + 1;
self.wait = -1;
SetStringDefault(message, "You found a secret area!");
SetPositiveDefault(sounds, 1);
trigger_multiple();
};
static enumflags { COUNTER_NOMESSAGE };
/*==========
counter_use
==========*/
void() counter_use =
{
self.count = self.count - 1;
// more to go
if (self.count > 0)
{
if (activator.classname == "player")
{
if (!(self.spawnflags & COUNTER_NOMESSAGE))
{
if (self.count > 3)
centerprint (activator, "There are more to go...");
else if (self.count == 3)
centerprint (activator, "Only 3 more to go...");
else if (self.count == 2)
centerprint (activator, "Only 2 more to go...");
else
centerprint (activator, "Only 1 more to go...");
}
}
return;
}
self.use = SUB_Null; // don't allow further triggering
if (activator.classname == "player")
{
if (!(self.spawnflags & COUNTER_NOMESSAGE))
centerprint(activator, "Sequence completed!");
}
// fire targets
self.enemy = activator;
trigger_fire();
};
/*QUAKED trigger_counter (.5 .5 .5) ? NOMESSAGE X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
Acts as an intermediary for an action that takes multiple inputs - cannot be interacted with directly.
It will print "Only X more to go.." when triggered and "Sequence completed!" when finished.
After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself.
Spawnflags:
NOMESSAGE - don't display any messages
*/
void() trigger_counter =
{
SetPositiveDefault(count, 2);
self.use = counter_use;
};
/*==========
skill_touch
==========*/
static void() skill_touch =
{
if (other.classname != "player")
return;
if (other.health <= 0)
return;
cvar_set("skill", self.message);
};
/*QUAKED trigger_setskill (.5 .5 .5) ? X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
Trigger that sets "skill" to the value of "message".
*/
void() trigger_setskill =
{
self.touch = skill_touch;
InitTrigger();
};
/*==========
onlyregistered_touch
==========*/
static void() onlyregistered_touch =
{
if (other.classname != "player")
return;
if (other.health <= 0)
return;
if (self.attack_finished > time)
return;
self.attack_finished = time + 2;
if (cvar("registered"))
{
self.message = "";
activator = other;
UseTargets ();
remove(self);
return;
}
if (self.message != "")
{
centerprint (other, self.message);
sound (other, CHAN_BODY, "misc/talk.wav", 1, ATTN_NORM);
}
};
/*QUAKED trigger_onlyregistered (.5 .5 .5) ? X X X X X X X X NOT_IN_EASY NOT_IN_NORMAL NOT_IN_HARD NOT_IN_DM
Only fires if playing the registered version, otherwise prints the message.
*/
void() trigger_onlyregistered =
{
self.touch = onlyregistered_touch;
InitTrigger();
};

View File

@@ -0,0 +1,189 @@
/*==========
SetStringDefault
==========*/
void(.string field, string val) SetStringDefault =
{
if (!self.field)
self.field = val;
};
/*==========
SetFloatDefault
==========*/
void(.float field, float val) SetFloatDefault =
{
if (self.field == 0)
self.field = val;
};
/*==========
SetPositiveDefault
==========*/
void(.float field, float val) SetPositiveDefault =
{
if (self.field <= 0)
self.field = val;
};
/*==========
realorigin
==========*/
vector(entity e) realorigin =
{
return 0.5 * (e.absmin + e.absmax);
};
/*==========
anglemod
correct an angle so it's between 0 and 359
==========*/
float(float v) anglemod =
{
return v - floor(v/360) * 360;
};
/*==========
angcomp
calculate the difference between two angles
==========*/
float (float y1, float y2) angcomp =
{
y1 = anglemod(y1);
y2 = anglemod(y2);
float answer = y1 - y2;
if (answer > 180)
answer = answer - 360;
else if (answer < -180)
answer = answer + 360;
return answer;
};
/*==========
crandom
returns -1 to +1
==========*/
float() crandom =
{
return 2 * (random() - 0.5);
};
/*==========
randomvec
returns a random vector with all 3 components between -1 and +1
==========*/
vector() randomvec =
{
return [crandom(), crandom(), crandom()];
};
/*==========
randomrange
returns a whole number between 0 and range - 1
==========*/
float(float range) randomrange =
{
if (range < 1)
return 0;
float result = floor(random() * range);
// random can return 1 in some engines
if (result == range)
return range - 1;
else
return result;
};
/*==========
spawn_debug_marker
==========*/
void(vector org) spawn_debug_marker =
{
if (!developer)
return;
entity e = spawn();
e.classname = "DebugMarker";
e.solid = SOLID_NOT;
e.movetype = MOVETYPE_NONE;
setmodel(e, "progs/s_bubble.spr");
setsize(e, '0 0 0', '0 0 0');
setorigin(e, org);
e.think = SUB_Remove;
e.nextthink = time + 5;
};
static vector v_forward2, v_up2, v_right2;
/*==========
save_vectors
==========*/
static inline void() save_vectors =
{
v_forward2 = v_forward;
v_up2 = v_up;
v_right2 = v_right;
};
/*==========
restore_vectors
==========*/
static inline void() restore_vectors =
{
v_forward = v_forward2;
v_up = v_up2;
v_right = v_right2;
};
/*==========
cos
==========*/
float(float n) cos =
{
save_vectors();
vector ang = [0, n, 0];
makevectors(ang);
float result = v_forward_x;
restore_vectors();
return result;
};
/*==========
sin
==========*/
float(float n) sin =
{
save_vectors();
vector ang = [0, n, 0];
makevectors(ang);
float result = v_forward_y;
restore_vectors();
return result;
};
/*==========
tan
==========*/
float(float n) tan =
{
save_vectors();
vector ang = [0, n, 0];
makevectors(ang);
float result = v_forward_y / v_forward_x;
restore_vectors();
return result;
};
/*==========
atan2
==========*/
float(float y, float x) atan2 =
{
vector ang = [x, y, 0];
return vectoyaw(ang);
};

View File

@@ -0,0 +1,108 @@
static entity multi_ent;
static float multi_damage;
/*==========
ClearMultiDamage
==========*/
static void() ClearMultiDamage =
{
multi_ent = world;
multi_damage = 0;
};
/*==========
ApplyMultiDamage
==========*/
static void() ApplyMultiDamage =
{
if (!multi_ent)
return;
Damage (multi_ent, self, self, multi_damage);
};
/*==========
AddMultiDamage
==========*/
static void(entity hit, float damage) AddMultiDamage =
{
if (!hit)
return;
if (hit != multi_ent)
{
ApplyMultiDamage();
multi_damage = damage;
multi_ent = hit;
}
else
multi_damage = multi_damage + damage;
};
/*==========
TraceAttack
==========*/
static void(float damage, vector dir) TraceAttack =
{
vector org = trace_endpos - dir*4;
if (trace_ent.takedamage)
{
vector vel = normalize(dir + v_up*crandom() + v_right*crandom());
vel = vel + 2 * trace_plane_normal;
vel = vel * 4;
if (trace_ent.solid == SOLID_BSP)
particle(org, vel, trace_ent.colour, damage);
else
SpawnBlood (org, vel, damage);
AddMultiDamage (trace_ent, damage);
}
else
te_gunshot(org);
};
/*==========
FireBullets
==========*/
void(float shotcount, vector dir, vector spread) FireBullets =
{
makevectors(self.v_angle);
vector src = self.origin + v_forward*10;
src_z = self.absmin_z + self.size_z * 0.7;
ClearMultiDamage();
while (shotcount > 0)
{
vector direction = dir + crandom()*spread_x*v_right + crandom()*spread_y*v_up;
traceline (src, src + direction*2048, FALSE, self);
if (trace_fraction != 1.0)
TraceAttack (4, direction);
shotcount = shotcount - 1;
}
ApplyMultiDamage();
};
/*==========
W_FireShotgun
==========*/
void() W_FireShotgun =
{
sound (self, CHAN_WEAPON, "weapons/guncock.wav", 1, ATTN_NORM);
self.punchangle_x = -2;
self.currentammo = self.ammo_shells = self.ammo_shells - 1;
vector dir = aim (self, 100000);
FireBullets (6, dir, '0.04 0.04 0');
};
/*==========
W_FireSuperShotgun
==========*/
void() W_FireSuperShotgun =
{
sound (self ,CHAN_WEAPON, "weapons/shotgn2.wav", 1, ATTN_NORM);
self.punchangle_x = -4;
self.currentammo = self.ammo_shells = self.ammo_shells - 2;
vector dir = aim (self, 100000);
FireBullets (14, dir, '0.14 0.08 0');
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,829 @@
/*==========
W_RankForWeapon
used by W_DeathmatchWeapon, returns a rank for a weapon
==========*/
float(entity player, float w) W_RankForWeapon =
{
if (w == IT_LIGHTNING && player.ammo_cells)
return 1;
if (w == IT_ROCKET_LAUNCHER && player.ammo_rockets)
return 2;
if (w == IT_SUPER_NAILGUN && player.ammo_nails > 1)
return 3;
if (w == IT_GRENADE_LAUNCHER && player.ammo_rockets)
return 4;
if (w == IT_SUPER_SHOTGUN && player.ammo_shells > 1)
return 5;
if (w == IT_NAILGUN && player.ammo_nails)
return 6;
if (w == IT_SHOTGUN && player.ammo_shells)
return 7;
return 8;
};
/*==========
W_DeathmatchWeapon
compares two weapons and returns the best one
only used in deathmatch
==========*/
float(entity player, float old, float new) W_DeathmatchWeapon =
{
float or = W_RankForWeapon(player, old);
float nr = W_RankForWeapon(player, new);
if (nr < or)
return new;
else
return old;
};
/*==========
W_BoundAmmo
caps player ammo at the max allowed
==========*/
void(entity player) W_BoundAmmo =
{
if (player.ammo_shells > 100)
player.ammo_shells = 100;
if (player.ammo_nails > 200)
player.ammo_nails = 200;
if (player.ammo_rockets > 100)
player.ammo_rockets = 100;
if (player.ammo_cells > 100)
player.ammo_cells = 100;
};
/*==========
W_BestWeapon
returns the players best weapon
to avoid self damage:
does not auto-switch to GL or RL
does not auto-switch to Thunderbolt if underwater
==========*/
float(entity player) W_BestWeapon =
{
if ((player.waterlevel < 2) && (player.ammo_cells > 0) && (player.items & IT_LIGHTNING))
return IT_LIGHTNING;
if ((player.ammo_nails > 1) && (player.items & IT_SUPER_NAILGUN))
return IT_SUPER_NAILGUN;
if ((player.ammo_shells > 1) && (player.items & IT_SUPER_SHOTGUN))
return IT_SUPER_SHOTGUN;
if ((player.ammo_nails > 1) && (player.items & IT_NAILGUN))
return IT_NAILGUN;
if ((player.ammo_shells > 0) && (player.items & IT_SHOTGUN))
return IT_SHOTGUN;
return IT_AXE;
};
/*==========
W_SetCurrentAmmo
update the hud with the correct ammo icon and count
updates .currentammo and .items
==========*/
void(entity player) W_SetCurrentAmmo =
{
player.currentammo = 0;
player.items = player.items - (player.items & (IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS));
if (player.weapon == IT_SHOTGUN || player.weapon == IT_SUPER_SHOTGUN)
{
player.currentammo = player.ammo_shells;
player.items = player.items | IT_SHELLS;
}
else if (player.weapon == IT_NAILGUN || player.weapon == IT_SUPER_NAILGUN)
{
player.currentammo = player.ammo_nails;
player.items = player.items | IT_NAILS;
}
else if (player.weapon == IT_GRENADE_LAUNCHER || player.weapon == IT_ROCKET_LAUNCHER)
{
player.currentammo = player.ammo_rockets;
player.items = player.items | IT_ROCKETS;
}
else if (player.weapon == IT_LIGHTNING)
{
player.currentammo = player.ammo_cells;
player.items = player.items | IT_CELLS;
}
};
/*==========
W_UpdateWeapon
updates the weapon view model
==========*/
void() player_stand;
void(entity player) W_UpdateWeapon =
{
if (player.weapon == IT_AXE)
player.weaponmodel = "progs/v_axe.mdl";
else if (player.weapon == IT_SHOTGUN)
player.weaponmodel = "progs/v_shot.mdl";
else if (player.weapon == IT_SUPER_SHOTGUN)
player.weaponmodel = "progs/v_shot2.mdl";
else if (player.weapon == IT_NAILGUN)
player.weaponmodel = "progs/v_nail.mdl";
else if (player.weapon == IT_SUPER_NAILGUN)
player.weaponmodel = "progs/v_nail2.mdl";
else if (player.weapon == IT_GRENADE_LAUNCHER)
player.weaponmodel = "progs/v_rock.mdl";
else if (player.weapon == IT_ROCKET_LAUNCHER)
player.weaponmodel = "progs/v_rock2.mdl";
else if (player.weapon == IT_LIGHTNING)
player.weaponmodel = "progs/v_light.mdl";
else
player.weaponmodel = "";
W_SetCurrentAmmo(player);
entity oself = self;
self = player;
player_stand();
self = oself;
};
/*==========
W_CheckNoAmmo
returns TRUE if the player has enough ammo for their current gun
==========*/
float(entity player) W_CheckNoAmmo =
{
if (!player.weapon)
return TRUE;
if (player.weapon == IT_AXE)
return TRUE;
if (player.weapon == IT_SUPER_SHOTGUN || player.weapon == IT_SUPER_NAILGUN)
{
if (player.currentammo > 1)
return TRUE;
else
return FALSE;
}
if (player.currentammo > 0)
return TRUE;
return FALSE;
};
/*==========
W_FireAxe
==========*/
void() W_FireAxe =
{
makevectors (self.v_angle);
vector source = self.origin + '0 0 16';
traceline (source, source + v_forward*64, FALSE, self);
if (trace_fraction == 1.0)
return;
vector org = trace_endpos - v_forward * 4;
if (trace_ent.takedamage)
{
//trace_ent.axhitme = 1;
vector vel = crandom() * v_right + crandom() * v_up;
vel = vel * random() * 4;
if (trace_ent.classname == "func_breakable")
particle(org, vel, trace_ent.colour, 40);
else
SpawnBlood (org, vel, 40);
Damage (trace_ent, self, self, 20);
}
else
{
sound (self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM);
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_GUNSHOT);
WriteCoord (MSG_BROADCAST, org_x);
WriteCoord (MSG_BROADCAST, org_y);
WriteCoord (MSG_BROADCAST, org_z);
}
};
void() T_MissileTouch =
{
if (pointcontents(self.origin) == CONTENT_SKY)
{
remove(self);
return;
}
float damg = 100 + random() * 20;
if (other.takedamage)
{
if (other.classname == "monster_shambler")
damg = damg * 0.5;
Damage (other, self, self.owner, damg);
}
RadiusDamage(self, self.owner, 120, other);
self.origin = self.origin - 8*normalize(self.velocity);
te_explosion(self.origin);
BecomeExplosion();
};
void() W_FireRocket =
{
local entity missile;
self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
sound (self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM);
self.punchangle_x = -2;
missile = spawn ();
missile.owner = self;
missile.movetype = MOVETYPE_FLYMISSILE;
missile.solid = SOLID_BBOX;
missile.classname = "missile";
// set missile speed
makevectors (self.v_angle);
//missile.velocity = aim(self, 1000);
missile.velocity = v_forward * 1000;
missile.angles = vectoangles(missile.velocity);
missile.avelocity = [0, 0, 300];
missile.touch = T_MissileTouch;
// set missile duration
missile.nextthink = time + 5;
missile.think = SUB_Remove;
setmodel (missile, "progs/missile.mdl");
setsize (missile, '0 0 0', '0 0 0');
setorigin (missile, self.origin + v_forward * 12 + self.view_ofs - v_up * 12);
};
void(vector p1, vector p2, entity from, float damage) LightningDamage =
{
traceline (p1, p2, FALSE, self);
if (trace_ent.takedamage)
{
particle (trace_endpos, '0 0 100', 225, damage*4);
Damage (trace_ent, from, from, damage);
}
};
void() W_FireLightning =
{
if (self.ammo_cells < 1)
{
self.weapon = W_BestWeapon(self);
W_UpdateWeapon(self);
return;
}
// explode if under water
if (self.waterlevel > 1)
{
float cells = self.ammo_cells;
self.ammo_cells = 0;
self.weapon = W_BestWeapon(self);
W_UpdateWeapon (self);
RadiusDamage (self, self, 35*cells, world);
return;
}
if (self.t_width < time)
{
sound (self, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM);
self.t_width = time + 0.6;
}
self.punchangle_x = -2;
self.currentammo = self.ammo_cells = self.ammo_cells - 1;
makevectors(self.v_angle);
traceline (self.origin, self.origin + v_forward * 600, TRUE, self);
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
WriteEntity (MSG_BROADCAST, self);
WriteCoord (MSG_BROADCAST, self.origin_x);
WriteCoord (MSG_BROADCAST, self.origin_y);
WriteCoord (MSG_BROADCAST, self.origin_z);
WriteCoord (MSG_BROADCAST, trace_endpos_x);
WriteCoord (MSG_BROADCAST, trace_endpos_y);
WriteCoord (MSG_BROADCAST, trace_endpos_z);
LightningDamage (self.origin, trace_endpos + v_forward * 4, self, 30);
};
void() GrenadeExplode =
{
RadiusDamage (self, self.owner, 120, world);
te_explosion(self.origin);
BecomeExplosion ();
};
void() GrenadeTouch =
{
if (pointcontents(self.origin) == CONTENT_SKY)
{
remove(self);
return;
}
if (other.takedamage == DAMAGE_AIM)
{
GrenadeExplode();
return;
}
sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);
};
void() W_FireGrenade =
{
local entity missile;
self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
self.punchangle_x = -2;
missile = spawn ();
missile.owner = self;
missile.movetype = MOVETYPE_BOUNCE;
missile.solid = SOLID_BBOX;
missile.classname = "grenade";
// set missile speed
makevectors (self.v_angle);
missile.velocity = v_forward * 600 + crandom()*v_right*10 + crandom()*v_up*10 + '0 0 200';
//if (self.v_angle_x)
//missile.velocity = v_forward*600 + v_up*200 + crandom()*v_right*10 + crandom()*v_up*10;
/*else
{
dprint("v_angle_x == 0\n");
missile.velocity = v_forward * 600;
missile.velocity_z = 200;
}*/
missile.avelocity = '300 300 300';
missile.angles = vectoangles(missile.velocity);
missile.touch = GrenadeTouch;
// set missile duration
missile.think = GrenadeExplode;
missile.nextthink = time + 2.5;
setmodel (missile, "progs/grenade.mdl");
setsize (missile, '0 0 0', '0 0 0');
setorigin (missile, self.origin + v_forward*12 + self.view_ofs - v_up*12);
};
void() spike_touch;
void() superspike_touch;
void(vector org, vector dir) launch_spike =
{
newmis = spawn ();
newmis.owner = self;
newmis.movetype = MOVETYPE_FLYMISSILE;
newmis.solid = SOLID_BBOX;
newmis.angles = vectoangles(dir);
newmis.touch = spike_touch;
newmis.classname = "spike";
newmis.think = SUB_Remove;
newmis.nextthink = time + 6;
setmodel (newmis, "progs/spike.mdl");
setsize (newmis, [0,0,0], [0,0,0]);
setorigin (newmis, org);
newmis.velocity = dir * 1000;
};
void() W_FireSuperSpikes =
{
local vector dir;
sound (self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM);
self.attack_finished = time + 0.2;
self.currentammo = self.ammo_nails = self.ammo_nails - 2;
//dir = aim (self, 1000);
//launch_spike (self.origin + '0 0 16', dir);
dir = v_forward;
launch_spike (self.origin + v_forward * 12 + self.view_ofs - v_up * 12, dir);
newmis.touch = superspike_touch;
setmodel (newmis, "progs/s_spike.mdl");
setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
self.punchangle_x = -2;
};
void(float ox) W_FireSpikes =
{
local vector dir;
makevectors (self.v_angle);
if (self.ammo_nails >= 2 && self.weapon == IT_SUPER_NAILGUN)
{
W_FireSuperSpikes ();
return;
}
if (self.ammo_nails < 1)
{
self.weapon = W_BestWeapon (self);
W_UpdateWeapon (self);
return;
}
sound (self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM);
self.attack_finished = time + 0.2;
self.currentammo = self.ammo_nails = self.ammo_nails - 1;
//dir = aim (self, 1000);
//launch_spike (self.origin + '0 0 16' + v_right*ox, dir);
dir = v_forward;
launch_spike (self.origin + v_forward * 8 + self.view_ofs - v_up * 12 + v_right * ox, dir);
self.punchangle_x = -2;
};
void() spike_touch =
{
if (pointcontents(self.origin) == CONTENT_SKY)
{
remove(self);
return;
}
// hit something that bleeds
if (other.takedamage)
{
if (other.solid == SOLID_BSP)
SpawnTouchParticles(9, other.colour);
else
SpawnTouchblood (9);
Damage (other, self, self.owner, 9);
}
else
{
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
if (self.classname == "wizspike")
WriteByte (MSG_BROADCAST, TE_WIZSPIKE);
else if (self.classname == "knightspike")
WriteByte (MSG_BROADCAST, TE_KNIGHTSPIKE);
else
WriteByte (MSG_BROADCAST, TE_SPIKE);
WriteCoord (MSG_BROADCAST, self.origin_x);
WriteCoord (MSG_BROADCAST, self.origin_y);
WriteCoord (MSG_BROADCAST, self.origin_z);
}
remove(self);
};
void() superspike_touch =
{
if (pointcontents(self.origin) == CONTENT_SKY)
{
remove(self);
return;
}
// hit something that bleeds
if (other.takedamage)
{
if (other.solid == SOLID_BSP)
SpawnTouchParticles(18, other.colour);
else
SpawnTouchblood (18);
Damage (other, self, self.owner, 18);
}
else
{
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_SUPERSPIKE);
WriteCoord (MSG_BROADCAST, self.origin_x);
WriteCoord (MSG_BROADCAST, self.origin_y);
WriteCoord (MSG_BROADCAST, self.origin_z);
}
remove(self);
};
/*==========
W_Attack
==========*/
void() player_axe1;
void() player_axeb1;
void() player_axec1;
void() player_axed1;
void() player_shot1;
void() player_nail;
void() player_lightning;
void() player_rocket1;
void() W_Attack =
{
if (time < self.attack_finished)
return;
if (!self.weapon)
return;
if (!W_CheckNoAmmo(self))
{
self.weapon = W_BestWeapon(self);
W_UpdateWeapon(self);
return;
}
makevectors (self.v_angle);
self.show_hostile = time + 1;
if (self.weapon == IT_AXE)
{
sound (self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM);
float r = random();
if (r < 0.25)
player_axe1 ();
else if (r<0.5)
player_axeb1 ();
else if (r<0.75)
player_axec1 ();
else
player_axed1 ();
self.attack_finished = time + 0.5;
}
else if (self.weapon == IT_SHOTGUN)
{
player_shot1 ();
W_FireShotgun ();
self.attack_finished = time + 0.5;
}
else if (self.weapon == IT_SUPER_SHOTGUN)
{
player_shot1 ();
W_FireSuperShotgun ();
self.attack_finished = time + 0.7;
}
else if (self.weapon == IT_NAILGUN)
{
player_nail ();
}
else if (self.weapon == IT_SUPER_NAILGUN)
{
player_nail ();
}
else if (self.weapon == IT_GRENADE_LAUNCHER)
{
player_rocket1();
W_FireGrenade();
self.attack_finished = time + 0.6;
}
else if (self.weapon == IT_ROCKET_LAUNCHER)
{
player_rocket1();
W_FireRocket();
self.attack_finished = time + 0.8;
}
else if (self.weapon == IT_LIGHTNING)
{
sound (self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM);
player_lightning();
}
};
/*==========
W_ChangeWeapon
==========*/
void(float wep) W_ChangeWeapon =
{
float am = 0;
float it = 0;
if (wep == 1)
{
it = IT_AXE;
}
else if (wep == 2)
{
it = IT_SHOTGUN;
if (self.ammo_shells < 1)
am = 1;
}
else if (wep == 3)
{
it = IT_SUPER_SHOTGUN;
if (self.ammo_shells < 2)
am = 1;
}
else if (wep == 4)
{
it = IT_NAILGUN;
if (self.ammo_nails < 1)
am = 1;
}
else if (wep == 5)
{
it = IT_SUPER_NAILGUN;
if (self.ammo_nails < 2)
am = 1;
}
else if (wep == 6)
{
it = IT_GRENADE_LAUNCHER;
if (self.ammo_rockets < 1)
am = 1;
}
else if (wep == 7)
{
it = IT_ROCKET_LAUNCHER;
if (self.ammo_rockets < 1)
am = 1;
}
else if (wep == 8)
{
it = IT_LIGHTNING;
if (self.ammo_cells < 1)
am = 1;
}
if (!(self.items & it))
{
sprint (self, "no weapon.\n");
return;
}
if (am)
{
sprint (self, "not enough ammo.\n");
return;
}
self.weapon = it;
W_UpdateWeapon(self);
};
/*==========
W_Cheat
==========*/
void() W_Cheat =
{
self.ammo_rockets = 100;
self.ammo_nails = 200;
self.ammo_shells = 100;
self.ammo_cells = 200;
self.items = self.items |
IT_AXE |
IT_SHOTGUN |
IT_SUPER_SHOTGUN |
IT_NAILGUN |
IT_SUPER_NAILGUN |
IT_GRENADE_LAUNCHER |
IT_ROCKET_LAUNCHER |
IT_LIGHTNING |
IT_KEY1 | IT_KEY2;
self.weapon = IT_ROCKET_LAUNCHER;
W_UpdateWeapon(self);
};
/*==========
W_RuneCheat
==========*/
void() W_RuneCheat =
{
if (!(serverflags & 1))
serverflags = serverflags + 1;
else if (!(serverflags & 2))
serverflags = serverflags + 2;
else if (!(serverflags & 4))
serverflags = serverflags + 4;
else if (!(serverflags & 8))
serverflags = serverflags + 8;
};
/*==========
QuadCheat
==========*/
void() W_QuadCheat =
{
self.super_time = 1;
self.super_damage_finished = time + 30;
self.items = self.items | IT_QUAD;
sprint(self, "You got the Quad Damage\n");
sound(self, CHAN_VOICE, "items/damage.wav", 1.0, ATTN_NORM);
stuffcmd(self, "bf\n");
};
/*==========
PentCheat
==========*/
void() W_PentCheat =
{
self.invincible_time = 1;
self.invincible_finished = time + 30;
self.items = self.items | IT_INVULNERABILITY;
sprint(self, "You got the Pentagram of Protection!\n");
sound(self, CHAN_VOICE, "items/protect.wav", 1.0, ATTN_NORM);
stuffcmd(self, "bf\n");
};
/*==========
RingCheat
==========*/
void() W_RingCheat =
{
self.invisible_time = 1;
self.invisible_finished = time + 30;
self.items = self.items | IT_INVISIBILITY;
sprint(self, "You got the Ring of Shadows\n");
sound(self, CHAN_VOICE, "items/inv1.wav", 1.0, ATTN_NORM);
stuffcmd(self, "bf\n");
};
/*==========
SuitCheat
==========*/
void() W_SuitCheat =
{
self.rad_time = 1;
self.radsuit_finished = time + 30;
self.items = self.items | IT_SUIT;
sprint(self, "You got the Biosuit\n");
sound(self, CHAN_VOICE, "items/suit.wav", 1.0, ATTN_NORM);
stuffcmd(self, "bf\n");
};
/*==========
W_ImpulseCommands
==========*/
void() W_ImpulseCommands =
{
if (!(deathmatch || coop))
{
if (self.impulse == 9)
W_Cheat();
if (self.impulse == 11)
W_RuneCheat();
if (self.impulse == 255)
W_QuadCheat();
if (self.impulse == 254)
W_PentCheat();
if (self.impulse == 253)
W_RingCheat();
if (self.impulse == 252)
W_SuitCheat();
}
if (time < self.attack_finished)
return;
if (self.impulse >= 1 && self.impulse <= 8)
W_ChangeWeapon(self.impulse);
self.impulse = 0;
};
/*==========
W_QuadDamageSound
==========*/
void() W_QuadDamageSound =
{
if (self.items & IT_QUAD)
{
if (self.super_sound < time)
{
self.super_sound = time + 1;
sound (self, CHAN_BODY, "items/damage3.wav", 1, ATTN_NORM);
}
}
};
/*==========
W_WeaponFrame
==========*/
void() W_WeaponFrame =
{
W_ImpulseCommands();
if (self.button0)
{
W_QuadDamageSound();
W_Attack();
}
};

View File

@@ -0,0 +1,218 @@
/*========================================
world.qc
========================================*/
/*==========
main
==========*/
void() main = {};
/*==========
setup_gravity
==========*/
void() setup_gravity =
{
// custom map gravity
if (mapname == "e1m8")
cvar_set ("sv_gravity", "100");
else if (self.gravity)
cvar_set ("sv_gravity", ftos(self.gravity));
else
cvar_set ("sv_gravity", "800");
sv_gravity = cvar("sv_gravity");
};
/*==========
precache_sounds
==========*/
void() precache_sounds =
{
// sounds used from C code
precache_sound ("demon/dland2.wav"); // landing thud
precache_sound ("misc/h2ohit1.wav"); // landing splash
precache_sound ("misc/talk.wav"); // chat
precache_sound ("weapons/r_exp3.wav"); // explosion
precache_sound ("weapons/ric1.wav"); // spike ricochet
precache_sound ("weapons/ric2.wav"); // spike ricochet
precache_sound ("weapons/ric3.wav"); // spike ricochet
precache_sound ("weapons/tink1.wav"); // spike tink
precache_sound ("wizard/hit.wav"); // scrag projectile impact
precache_sound ("hknight/hit.wav"); // death knight projectile impact
// player movement sounds
precache_sound ("player/plyrjmp8.wav"); // player jump
precache_sound ("player/land.wav"); // player landing
precache_sound ("player/land2.wav"); // player hurt landing
precache_sound ("player/ladder1.wav");
precache_sound ("player/ladder2.wav");
precache_sound ("player/ladder3.wav");
precache_sound ("player/ladder4.wav");
precache_sound ("player/ladder5.wav");
// player pain sounds
precache_sound ("player/pain1.wav");
precache_sound ("player/pain2.wav");
precache_sound ("player/pain3.wav");
precache_sound ("player/pain4.wav");
precache_sound ("player/pain5.wav");
precache_sound ("player/pain6.wav");
// player death sounds
precache_sound ("player/death1.wav");
precache_sound ("player/death2.wav");
precache_sound ("player/death3.wav");
precache_sound ("player/death4.wav");
precache_sound ("player/death5.wav");
// gib sounds
precache_sound ("player/gib.wav");
precache_sound ("player/udeath.wav");
precache_sound ("player/tornoff2.wav");
precache_sound ("player/teledth1.wav");
precache_sound ("zombie/z_miss.wav");
// player liquid sounds
precache_sound ("player/h2ojump.wav"); // jumping into water
precache_sound ("player/inh2o.wav"); // enter water
precache_sound ("player/slimbrn2.wav"); // enter slime
precache_sound ("player/inlava.wav"); // enter lava
precache_sound ("misc/outwater.wav"); // leaving water
precache_sound ("player/lburn1.wav"); // lava burn
precache_sound ("player/lburn2.wav"); // lava burn
precache_sound ("misc/water1.wav"); // swimming
precache_sound ("misc/water2.wav"); // swimming
precache_sound ("player/drown1.wav"); // drowning pain
precache_sound ("player/drown2.wav"); // drowning pain
precache_sound ("player/gasp1.wav"); // gasping for air
precache_sound ("player/gasp2.wav"); // taking breath
precache_sound ("player/h2odeath.wav"); // drowning death
// teleport sounds
precache_sound ("misc/r_tele1.wav");
precache_sound ("misc/r_tele2.wav");
precache_sound ("misc/r_tele3.wav");
precache_sound ("misc/r_tele4.wav");
precache_sound ("misc/r_tele5.wav");
// items
precache_sound ("items/itembk2.wav"); // item respawn
precache_sound ("weapons/lock4.wav"); // ammo pick up
precache_sound ("weapons/pkup.wav"); // weapon pick up
precache_sound ("items/armor1.wav"); // armor pick up
// pentagram of protection
precache_sound ("items/protect.wav");
precache_sound ("items/protect2.wav");
precache_sound ("items/protect3.wav");
// biosuit
precache_sound ("items/suit.wav");
precache_sound ("items/suit2.wav");
// ring of shadows
precache_sound ("items/inv1.wav");
precache_sound ("items/inv2.wav");
precache_sound ("items/inv3.wav");
// quad damage
precache_sound ("items/damage.wav");
precache_sound ("items/damage2.wav");
precache_sound ("items/damage3.wav");
// weapon sounds
precache_sound ("weapons/ax1.wav"); // axe swoosh
precache_sound ("player/axhit1.wav"); // axe hit meat
precache_sound ("player/axhit2.wav"); // axe hit world
precache_sound ("weapons/guncock.wav"); // shotgun
precache_sound ("weapons/shotgn2.wav"); // super shotgun
precache_sound ("weapons/rocket1i.wav"); // nailgun
precache_sound ("weapons/spike2.wav"); // super nailgun
precache_sound ("weapons/grenade.wav"); // grenade launcher
precache_sound ("weapons/bounce.wav"); // grenade bounce
precache_sound ("weapons/sgun1.wav"); // rocket launcher
precache_sound ("weapons/lstart.wav"); // thunderbolt start
precache_sound ("weapons/lhit.wav"); // thunderbolt
};
/*==========
precache_models
==========*/
void() precache_models =
{
// player models
precache_model ("progs/player.mdl");
precache_model ("progs/h_player.mdl");
precache_model ("progs/eyes.mdl");
// gore
precache_model ("progs/zom_gib.mdl");
precache_model ("progs/gib1.mdl");
precache_model ("progs/gib2.mdl");
precache_model ("progs/gib3.mdl");
precache_model ("progs/gib4.mdl");
precache_model ("progs/gib5.mdl");
precache_model ("progs/blood.mdl");
// sprites
precache_model ("progs/s_bubble.spr");
precache_model ("progs/s_explod.spr");
precache_model ("progs/s_null.spr");
// weapon models
precache_model ("progs/v_axe.mdl");
precache_model ("progs/v_shot.mdl");
precache_model ("progs/v_nail.mdl");
precache_model ("progs/v_rock.mdl");
precache_model ("progs/v_shot2.mdl");
precache_model ("progs/v_nail2.mdl");
precache_model ("progs/v_rock2.mdl");
precache_model ("progs/v_light.mdl");
// projectiles, etc
precache_model ("progs/bolt.mdl");
precache_model ("progs/bolt2.mdl");
precache_model ("progs/bolt3.mdl");
precache_model ("progs/beam.mdl");
precache_model ("progs/missile.mdl");
precache_model ("progs/grenade.mdl");
precache_model ("progs/spike.mdl");
precache_model ("progs/s_spike.mdl");
precache_model ("progs/backpack.mdl");
precache_model ("progs/smoke.mdl");
};
/*QUAKED worldspawn (0 0 0) ?
The world entity.
Keys:
"message" "name" - Map name
"sounds" "n" - CD / Music track to play
"worldtype" "n":
0 - medieval, 1 - metal, 2 - base
*/
void() worldspawn =
{
// fix skill at map start
skill = rint(cvar("skill"));
if (skill < 0)
skill = 0;
if (skill > 3)
skill = 3;
precache_sounds();
precache_models();
setup_lightstyles();
setup_gravity();
InitBodyQue();
WaypointInit();
};
/*==========
StartFrame
==========*/
void() StartFrame =
{
framecount = framecount + 1;
teamplay = cvar("teamplay");
developer = cvar("developer");
WaypointFrame();
};