add lives and spectating

master
an 2019-09-19 16:57:27 -04:00
parent 6015681eaa
commit df8107d247
7 changed files with 120 additions and 42 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) && !(temp1flag & SF_CHEATS)) { if((deathmatch || coop) && !sf_cheats) {
return; return;
} }
@ -1051,7 +1100,7 @@ void() cheat = {
}; };
void() cheat_quad = { void() cheat_quad = {
if((deathmatch || coop) && !(temp1flag & SF_CHEATS)) { 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

@ -555,9 +555,9 @@ enum {
enum { enum {
SF_CHEATS = 1 << 0, SF_CHEATS = 1 << 0,
SF_LIVES_BEG = 1 << 1, SF_LIVES_BEG = 1,
SF_LIVES_END = 1 << 3, SF_LIVES_END = 3,
SF_LIVES_FLG = 0x0E, SF_LIVES_MSK = 0x0E,
SF_DIST_AMMO = 1 << 4, SF_DIST_AMMO = 1 << 4,
}; };
#pragma noref 0 #pragma noref 0
@ -605,7 +605,12 @@ string nextmap;
entity sight_entity; entity sight_entity;
float sight_entity_time; float sight_entity_time;
float temp1flag; // super co-op additions
float sf_cheats;
float sf_lives;
float sf_dist_ammo;
float player_respawned;
// fields --------------------------------------------------------------------| // fields --------------------------------------------------------------------|
@ -723,6 +728,7 @@ float temp1flag;
// super co-op additions // super co-op additions
.float pronoun; .float pronoun;
.float lives;
// functions -----------------------------------------------------------------| // functions -----------------------------------------------------------------|

View File

@ -179,10 +179,16 @@ void() worldspawn = {
}; };
void() StartFrame = { void() StartFrame = {
float temp1flag;
teamplay = cvar("teamplay"); teamplay = cvar("teamplay");
skill = cvar("skill"); skill = cvar("skill");
temp1flag = cvar("temp1"); 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