Compare commits

...

3 Commits

Author SHA1 Message Date
an df8107d247 add lives and spectating 2019-09-19 16:57:27 -04:00
an 6015681eaa add sf_cheats support 2019-09-19 12:56:39 -04:00
an 2aa46c72ec add temp1flag 2019-09-19 12:56:17 -04:00
8 changed files with 128 additions and 47 deletions

View File

@ -1,5 +1,9 @@
// ai.qc: monster AI functions // ai.qc: monster AI functions
float(entity enemy) enemy_is_gone = {
return enemy.health <= 0 || enemy.flags & FL_NOTARGET;
};
// //
// when a monster becomes angry at a player, that monster will be used // when a monster becomes angry at a player, that monster will be used
// as the sight target the next frame so that monsters near that one // as the sight target the next frame so that monsters near that one
@ -180,14 +184,9 @@ float() FindTarget = {
} }
} }
if(client == self.enemy) { if(client == self.enemy ||
return FALSE; client.flags & FL_NOTARGET ||
} client.items & IT_INVISIBILITY) {
if(client.flags & FL_NOTARGET) {
return FALSE;
}
if(client.items & IT_INVISIBILITY) {
return FALSE; return FALSE;
} }
@ -205,7 +204,7 @@ float() FindTarget = {
return FALSE; return FALSE;
} }
} else if(r == RANGE_MID) { } else if(r == RANGE_MID) {
if(/* client.show_hostile < time || */ !infront(client)) { if(!infront(client)) {
return FALSE; return FALSE;
} }
} }
@ -468,10 +467,9 @@ void(float dist) ai_run = {
movedist = dist; movedist = dist;
// see if the enemy is dead // see if the enemy is dead
if(self.enemy.health <= 0) { if(enemy_is_gone(self.enemy)) {
self.enemy = world; self.enemy = world;
// FIXME: look all around for other targets if(!enemy_is_gone(self.oldenemy)) {
if(self.oldenemy.health > 0) {
self.enemy = self.oldenemy; self.enemy = self.oldenemy;
HuntTarget(); HuntTarget();
} else { } else {

View File

@ -30,9 +30,8 @@ $frame shockc1 shockc2 shockc3 shockc4 shockc5 shockc6 shockc7 shockc8
$frame shockc9 shockc10 $frame shockc9 shockc10
void() boss_face = { void() boss_face = {
// go for another player if multi player // go for another player if multi player
if(self.enemy.health <= 0 || random() < 0.02) { if(enemy_is_gone(self.enemy) || random() < 0.02) {
self.enemy = find(self.enemy, classname, "player"); self.enemy = find(self.enemy, classname, "player");
if(!self.enemy) { if(!self.enemy) {
self.enemy = find(self.enemy, classname, "player"); self.enemy = find(self.enemy, classname, "player");
@ -211,7 +210,7 @@ void(vector p) boss_missile = {
sound(self, CHAN_WEAPON, "boss1/throw.wav", 1, ATTN_NORM); sound(self, CHAN_WEAPON, "boss1/throw.wav", 1, ATTN_NORM);
// check for dead enemy // check for dead enemy
if(self.enemy.health <= 0) { if(enemy_is_gone(self.enemy)) {
boss_idle1(); boss_idle1();
} }
}; };

View File

@ -16,7 +16,7 @@ void() info_intermission = {
}; };
void() SetChangeParms = { void() SetChangeParms = {
if(self.health <= 0) { if(self.health <= 0 || self.lives == 0) {
SetNewParms(); SetNewParms();
return; return;
} }
@ -253,7 +253,7 @@ void() changelevel_touch = {
return; return;
} }
if((cvar("noexit") == 1) || ((cvar("noexit") == 2) && (mapname != "start"))) { if(cvar("noexit") == 1 || (cvar("noexit") == 2 && mapname != "start")) {
T_Damage(other, self, self, 50000); T_Damage(other, self, self, 50000);
return; return;
} }
@ -266,7 +266,7 @@ void() changelevel_touch = {
SUB_UseTargets(); SUB_UseTargets();
if((self.spawnflags & 1) && (deathmatch == 0)) { if(self.spawnflags & 1 && deathmatch == 0) {
// NO_INTERMISSION // NO_INTERMISSION
GotoNextMap(); GotoNextMap();
return; return;
@ -285,7 +285,7 @@ When the player touches this, they get sent to the map listed in the "map" varia
*/ */
void() trigger_changelevel = { void() trigger_changelevel = {
if(!self.map) { if(!self.map) {
objerror("chagnelevel trigger doesn't have map"); objerror("changelevel trigger doesn't have map");
} }
InitTrigger(); InitTrigger();
@ -300,7 +300,26 @@ void() trigger_changelevel = {
============================================================================= =============================================================================
*/ */
// called by ClientKill and DeadThink void() become_spectator = {
self.health = self.max_health;
self.armortype = 0;
self.armorvalue = 0;
self.items = 0;
self.weapon = 0;
self.ammo_shells = 0;
self.ammo_nails = 0;
self.ammo_rockets = 0;
self.ammo_cells = 0;
self.takedamage = DAMAGE_NO;
self.solid = SOLID_NOT;
self.movetype = MOVETYPE_NOCLIP;
self.flags |= FL_NOTARGET;
self.deadflag = DEAD_DEAD;
self.view_ofs = VEC_ORIGIN;
self.modelindex = modelindex_eyes;
W_SetCurrentAmmo();
};
void() respawn = { void() respawn = {
if(coop) { if(coop) {
// make a copy of the dead body for appearances sake // make a copy of the dead body for appearances sake
@ -308,6 +327,7 @@ void() respawn = {
// get the spawn parms as they were at level start // get the spawn parms as they were at level start
setspawnparms(self); setspawnparms(self);
// respawn // respawn
player_respawned = TRUE;
PutClientInServer(); PutClientInServer();
} else if(deathmatch) { } else if(deathmatch) {
// make a copy of the dead body for appearances sake // make a copy of the dead body for appearances sake
@ -315,6 +335,7 @@ void() respawn = {
// set default spawn parms // set default spawn parms
SetNewParms(); SetNewParms();
// respawn // respawn
player_respawned = TRUE;
PutClientInServer(); PutClientInServer();
} else { } else {
// restart the entire server // restart the entire server
@ -402,6 +423,31 @@ called each time a player is spawned
*/ */
void() PutClientInServer = { void() PutClientInServer = {
entity spot; entity spot;
float respawned;
respawned = player_respawned;
player_respawned = FALSE;
if(sf_lives) {
if(respawned) {
self.lives--;
bprint(self.netname, " has ");
if(self.lives == 0) {
bprint("run out of lives...\n");
become_spectator();
return;
} else if(self.lives == 1) {
bprint("one life left!\n");
} else {
bprint(ftos(self.lives), " lives left\n");
}
} else {
self.lives = sf_lives;
dprint("lives reset to ", ftos(sf_lives), "\n");
}
} else {
self.lives = 1;
}
spot = SelectSpawnPoint(); spot = SelectSpawnPoint();
@ -583,11 +629,10 @@ void() CheckRules = {
//============================================================================ //============================================================================
void() PlayerDeathThink = { void() reset_death_vel = {
entity old_self;
float forward; float forward;
if((self.flags & FL_ONGROUND)) { if(self.flags & FL_ONGROUND) {
forward = vlen(self.velocity); forward = vlen(self.velocity);
forward = forward - 20; forward = forward - 20;
if(forward <= 0) { if(forward <= 0) {
@ -596,6 +641,10 @@ void() PlayerDeathThink = {
self.velocity = forward * normalize(self.velocity); self.velocity = forward * normalize(self.velocity);
} }
} }
};
void() PlayerDeathThink = {
reset_death_vel();
// wait for all buttons released // wait for all buttons released
if(self.deadflag == DEAD_DEAD) { if(self.deadflag == DEAD_DEAD) {
@ -786,7 +835,7 @@ void() PlayerPreThink = {
} }
if(self.view_ofs == VEC_ORIGIN) { if(self.view_ofs == VEC_ORIGIN) {
return; // intermission or finale return; // intermission, finale or spectating
} }
makevectors(self.v_angle); // is this still used makevectors(self.v_angle); // is this still used
@ -841,7 +890,7 @@ void() CheckPowerups = {
// sound and screen flash when items starts to run out // sound and screen flash when items starts to run out
if(self.invisible_sound < time) { if(self.invisible_sound < time) {
sound(self, CHAN_AUTO, "items/inv3.wav", 0.5, ATTN_IDLE); sound(self, CHAN_AUTO, "items/inv3.wav", 0.5, ATTN_IDLE);
self.invisible_sound = time + ((random() * 3) + 1); self.invisible_sound = time + random() * 3 + 1;
} }
if(self.invisible_finished < time + 3) { if(self.invisible_finished < time + 3) {
if(self.invisible_time == 1) { if(self.invisible_time == 1) {
@ -969,7 +1018,7 @@ void() PlayerPostThink = {
W_WeaponFrame(); W_WeaponFrame();
// check to see if player landed and play landing sound // check to see if player landed and play landing sound
if((self.jump_flag < -300) && (self.flags & FL_ONGROUND) && (self.health > 0)) { if(self.jump_flag < -300 && self.flags & FL_ONGROUND && self.health > 0) {
if(self.watertype == CONTENT_WATER) { if(self.watertype == CONTENT_WATER) {
sound(self, CHAN_BODY, "player/h2ojump.wav", 1, ATTN_NORM); sound(self, CHAN_BODY, "player/h2ojump.wav", 1, ATTN_NORM);
} else if(self.jump_flag < -650) { } else if(self.jump_flag < -650) {
@ -1026,7 +1075,7 @@ void() ClientDisconnect = {
}; };
void() cheat = { void() cheat = {
if(deathmatch || coop) { if((deathmatch || coop) && !sf_cheats) {
return; return;
} }
@ -1051,7 +1100,7 @@ void() cheat = {
}; };
void() cheat_quad = { void() cheat_quad = {
if(deathmatch || coop) { if((deathmatch || coop) && !sf_cheats) {
return; return;
} }
@ -1123,13 +1172,13 @@ float(entity targ, entity attacker) obit_teledeath = {
}; };
float(entity targ, entity attacker) obit_teledeath2 = { float(entity targ, entity attacker) obit_teledeath2 = {
targ.frags = targ.frags - 1; targ.frags--;
bprint("'s telefrag was deflected by satanic power\n"); bprint("'s telefrag was deflected by satanic power\n");
return TRUE; return TRUE;
}; };
float(entity targ, entity attacker) obit_suicide = { float(entity targ, entity attacker) obit_suicide = {
targ.frags = targ.frags - 1; targ.frags--;
if(targ.weapon == IT_LIGHTNING && targ.waterlevel > 1) { if(targ.weapon == IT_LIGHTNING && targ.waterlevel > 1) {
bprint(" discharges into the water\n"); bprint(" discharges into the water\n");
@ -1150,7 +1199,7 @@ float(entity targ, entity attacker) obit_teamkill = {
float rnum; float rnum;
rnum = random(); rnum = random();
attacker.frags = attacker.frags - 1; attacker.frags--;
if(rnum < 0.25) { if(rnum < 0.25) {
bprint(" mows down a teammate\n"); bprint(" mows down a teammate\n");
@ -1417,7 +1466,7 @@ float(entity targ, entity attacker) obit_trap = {
}; };
float(entity targ, entity attacker) obit_worldkill = { float(entity targ, entity attacker) obit_worldkill = {
targ.frags = targ.frags - 1; targ.frags--;
if(attacker.flags & FL_MONSTER) { if(attacker.flags & FL_MONSTER) {
return obit_monster(targ, attacker); return obit_monster(targ, attacker);
@ -1482,9 +1531,12 @@ Player entered the suicide command
============ ============
*/ */
void() ClientKill = { void() ClientKill = {
self.frags = self.frags - 1; // extra penalty if(self.view_ofs != VEC_ORIGIN) {
ClientObituary(self, self); reset_death_vel();
set_suicide_frame(); self.frags--; // extra penalty
self.modelindex = modelindex_player; ClientObituary(self, self);
respawn(); set_suicide_frame();
self.modelindex = modelindex_player;
respawn();
}
}; };

View File

@ -1,5 +1,18 @@
// common.qc: common functions // common.qc: common functions
const float PO2_LUT[25] = {
1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768,
65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216
};
float(float x, float y) bit_shift_right = {
return rint(x / PO2_LUT[y]);
};
float(float x, float y) bit_shift_left = {
return rint(x * PO2_LUT[y]);
};
float() crandom = { float() crandom = {
return 2 * (random() - 0.5); return 2 * (random() - 0.5);
}; };

View File

@ -554,10 +554,11 @@ enum {
}; };
enum { enum {
WEAPON_SHOTGUN = 1, SF_CHEATS = 1 << 0,
WEAPON_ROCKET = 2, SF_LIVES_BEG = 1,
WEAPON_SPIKES = 4, SF_LIVES_END = 3,
WEAPON_BIG = 8, SF_LIVES_MSK = 0x0E,
SF_DIST_AMMO = 1 << 4,
}; };
#pragma noref 0 #pragma noref 0
@ -604,6 +605,13 @@ string nextmap;
entity sight_entity; entity sight_entity;
float sight_entity_time; float sight_entity_time;
// super co-op additions
float sf_cheats;
float sf_lives;
float sf_dist_ammo;
float player_respawned;
// fields --------------------------------------------------------------------| // fields --------------------------------------------------------------------|
// world fields // world fields
@ -720,6 +728,7 @@ float sight_entity_time;
// super co-op additions // super co-op additions
.float pronoun; .float pronoun;
.float lives;
// functions -----------------------------------------------------------------| // functions -----------------------------------------------------------------|

View File

@ -118,9 +118,8 @@ float(entity e, float healamount, float ignore) T_Heal = {
/*QUAKED item_health(.3 .3 1) (0 0 0) (32 32 32) rotten megahealth /*QUAKED item_health(.3 .3 1) (0 0 0) (32 32 32) rotten megahealth
Health box. Normally gives 25 points. Health box. Normally gives 25 points.
Rotten box heals 5-10 points, Rotten box heals 15 points,
megahealth will add 100 health, then Megahealth will add 100 health, then rot you down to your maximum health limit,
rot you down to your maximum health limit,
one point per second. one point per second.
*/ */

View File

@ -179,9 +179,16 @@ void() worldspawn = {
}; };
void() StartFrame = { void() StartFrame = {
teamplay = cvar("teamplay"); float temp1flag;
skill = cvar("skill");
teamplay = cvar("teamplay");
skill = cvar("skill");
temp1flag = cvar("temp1");
framecount = framecount + 1; framecount = framecount + 1;
sf_cheats = temp1flag & SF_CHEATS;
sf_lives = bit_shift_right(temp1flag & SF_LIVES_MSK, SF_LIVES_BEG);
sf_dist_ammo = temp1flag & SF_DIST_AMMO;
}; };
/* /*

6
todo
View File

@ -1,3 +1,7 @@
bugs:
enforcers are broken
refactoring: refactoring:
add expansion pack entities add expansion pack entities
@ -6,7 +10,6 @@ rename all functions to be lower_underscore
core features: core features:
distributed ammo distributed ammo
lives counting
useful features: useful features:
@ -27,4 +30,5 @@ done:
corpse pickups have keys corpse pickups have keys
custom pronouns custom pronouns
lives counting
no friendly fire no friendly fire