// debug
set _independent_players 0 "DO NOT TOUCH"
+set _notarget 0 "NO, REALLY, DON'T"
// define some engine cvars that we need even on dedicated server
set r_showbboxes 0
if(t != self.enttype || bIsNewEntity)
{
//print(_("A CSQC entity changed its type!\n"));
- print(sprintf(_("A CSQC entity changed its type! (edict: %d, type: %d -> %d)\n"), num_for_edict(self), self.enttype, t));
+ print(sprintf(_("A CSQC entity changed its type! (edict: %d, server: %d, type: %d -> %d)\n"), num_for_edict(self), self.entnum, self.enttype, t));
Ent_Remove();
bIsNewEntity = 1;
}
{
if(!bIsNewEntity)
{
- print(sprintf(_("A CSQC entity appeared out of nowhere! (edict: %d, type: %d)\n"), num_for_edict(self), t));
+ print(sprintf(_("A CSQC entity appeared out of nowhere! (edict: %d, server: %d, type: %d)\n"), num_for_edict(self), self.entnum, t));
bIsNewEntity = 1;
}
}
return pos;
}
+vector HUD_DrawKeyValue(vector pos, string key, string value) {
+ float px = pos_x;
+ pos_x += hud_fontsize_x * 0.25;
+ drawstring(pos, key, hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
+ pos_x = xmax - stringwidth(value, FALSE, hud_fontsize) - hud_fontsize_x * 0.25;
+ drawstring(pos, value, hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
+ pos_x = px;
+ pos_y+= hud_fontsize_y;
+
+ return pos;
+}
+
+vector HUD_DrawMapStats(vector pos, vector rgb, vector bg_size) {
+ float stat_secrets_found, stat_secrets_total;
+ float rows;
+ string val;
+
+ // get secrets stats
+ stat_secrets_found = getstatf(STAT_SECRETS_FOUND);
+ stat_secrets_total = getstatf(STAT_SECRETS_TOTAL);
+
+ // get number of rows
+ rows = (stat_secrets_total ? 1 : 0);
+
+ // if no rows, return
+ if not(rows)
+ return pos;
+
+ // draw table header
+ drawstring(pos, _("Map stats:"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
+ pos_y += 1.25 * hud_fontsize_y + autocvar_scoreboard_border_thickness;
+
+ // draw table
+ vector tmp;
+ tmp_x = sbwidth;
+ tmp_y = hud_fontsize_y * rows;
+
+ if (teamplay)
+ drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb * autocvar_scoreboard_color_bg_team, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
+ else
+ drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
+ drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
+
+ // draw secrets
+ val = sprintf("%d/%d", stat_secrets_found, stat_secrets_total);
+ pos = HUD_DrawKeyValue(pos, _("Secrets found:"), val);
+
+ // update position
+ pos_y += 1.25 * hud_fontsize_y;
+ return pos;
+}
+
+
vector HUD_DrawScoreboardRankings(vector pos, entity pl, vector rgb, vector bg_size)
{
float i;
pos = HUD_DrawScoreboardAccuracyStats(pos, rgb, bg_size);
}
+
+ if(teamplay)
+ pos = HUD_DrawMapStats(pos, GetTeamRGB(myteam), bg_size);
+ else
+ pos = HUD_DrawMapStats(pos, rgb, bg_size);
+
// List spectators
float specs;
specs = 0;
const float STAT_VEHICLESTAT_AMMO2 = 65;
const float STAT_VEHICLESTAT_RELOAD2 = 66;
+const float STAT_SECRETS_TOTAL = 70;
+const float STAT_SECRETS_FOUND = 71;
+
// mod stats (1xx)
const float STAT_REDALIVE = 100;
const float STAT_BLUEALIVE = 101;
void url_multi_ready(entity fh, entity me, float status)
{
float n;
- if(status == URL_READY_ERROR)
+ if(status == URL_READY_ERROR || status < 0)
{
+ if(status == -422) // Unprocessable Entity
+ {
+ print("uri_multi_ready: got HTTP error 422, data is in unusable format - not continuing\n");
+ me.url_ready(fh, me.url_ready_pass, status);
+ strunzone(me.url_url);
+ remove(me);
+ return;
+ }
me.cnt += 1;
n = tokenize_console(me.url_url);
if(n <= me.cnt)
if(status != 0)
{
print(sprintf(_("error: status is %d\n"), status));
+ if(do_cvar)
+ strunzone(do_cvar);
return;
}
if(do_exec)
localcmd(data);
if(do_cvar)
+ {
cvar_set(do_cvar, data);
+ strunzone(do_cvar);
+ }
if(!do_exec && !do_cvar)
print(data);
}
if(argv(i) == "--cvar" && i+2 < argc)
{
++i;
- do_cvar = argv(i);
+ do_cvar = strzone(argv(i));
continue;
}
if(argv(i) == "--exec")
.float antilag_times[ANTILAG_MAX_ORIGINS];
.float antilag_index;
.vector antilag_saved_origin;
+.float antilag_takenback;
.float antilag_debug;
void antilag_takeback(entity e, float t)
{
- if(e.vehicle)
- antilag_takeback(e.vehicle, t);
+ if(e.vehicle)
+ antilag_takeback(e.vehicle, t);
+
+ if(!e.antilag_takenback)
+ e.antilag_saved_origin = e.origin;
- e.antilag_saved_origin = e.origin;
setorigin(e, antilag_takebackorigin(e, t));
+ e.antilag_takenback = TRUE;
}
void antilag_restore(entity e)
{
- if(e.vehicle)
- antilag_restore(e.vehicle);
+ if(e.vehicle)
+ antilag_restore(e.vehicle);
+
+ if(!e.antilag_takenback)
+ return;
setorigin(e, e.antilag_saved_origin);
+ e.antilag_takenback = FALSE;
}
+float autocvar__notarget;
float autocvar__independent_players;
float autocvar__campaign_index;
string autocvar__campaign_name;
FOR_EACH_PLAYER(head)
{
// TODO: Merge this logic with the bot_shouldattack function
- if (self != head)
- if (head.health > 0)
- if ((noteam && (!bot_ignore_bots || clienttype(head) == CLIENTTYPE_REAL)) || head.team != self.team)
+ if(bot_shouldattack(head))
{
distance = vlen(head.origin - org);
if (distance < 100 || distance > sradius)
continue;
- if (head.freezetag_frozen)
- continue;
-
- if(g_minstagib)
- if(head.items & IT_STRENGTH)
- continue;
-
// rate only visible enemies
/*
traceline(self.origin + self.view_ofs, head.origin, MOVE_NOMONSTERS, self);
if(INDEPENDENT_PLAYERS)
MAKE_INDEPENDENT_PLAYER(self);
self.flags = FL_CLIENT;
+ if(autocvar__notarget)
+ self.flags |= FL_NOTARGET;
self.takedamage = DAMAGE_AIM;
if(g_minstagib)
self.effects = EF_FULLBRIGHT;
self.avelocity = randomvec() * autocvar_g_respawn_ghosts_speed * 3 - randomvec() * autocvar_g_respawn_ghosts_speed * 3;
self.effects |= EF_ADDITIVE;
self.oldcolormap = self.colormap;
- self.colormap = 512;
+ self.colormap = 0; // this originally was 512, but raises a warning in the engine, so get rid of it
pointparticles(particleeffectnum("respawn_ghost"), self.origin, '0 0 0', 1);
if(autocvar_g_respawn_ghosts_maxtime)
SUB_SetFade (self, time + autocvar_g_respawn_ghosts_maxtime / 2 + random () * (autocvar_g_respawn_ghosts_maxtime - autocvar_g_respawn_ghosts_maxtime / 2), 1.5);
if(g_nexball)
nexball_setstatus();
-
+
+ // secret status
+ secrets_setstatus();
+
self.dmg_team = max(0, self.dmg_team - autocvar_g_teamdamage_resetspeed * frametime);
//self.angles_y=self.v_angle_y + 90; // temp
self.stored_netname = strzone(uid2name(self.crypto_idfp));
if(self.stored_netname != self.netname)
{
- db_put(ServerProgsDB, strcat("uid2name", self.crypto_idfp), self.netname);
+ db_put(ServerProgsDB, strcat("/uid2name/", self.crypto_idfp), self.netname);
strunzone(self.stored_netname);
self.stored_netname = strzone(self.netname);
}
Drag_MoveDrag(oldself, self);
+ if(self.colormap <= maxclients && self.colormap > 0)
+ self.colormap = 1024 + self.clientcolors;
+
self = oldself;
}
addstat(STAT_MOVEVARS_MAXSPEED, AS_FLOAT, stat_sv_maxspeed);
addstat(STAT_MOVEVARS_AIRACCEL_QW, AS_FLOAT, stat_sv_airaccel_qw);
addstat(STAT_MOVEVARS_AIRSTRAFEACCEL_QW, AS_FLOAT, stat_sv_airstrafeaccel_qw);
-
+
+ // secrets
+ addstat(STAT_SECRETS_TOTAL, AS_FLOAT, stat_secrets_total);
+ addstat(STAT_SECRETS_FOUND, AS_FLOAT, stat_secrets_found);
+
next_pingtime = time + 5;
detect_maptype();
string uid2name(string myuid) {
string s;
- s = db_get(ServerProgsDB, strcat("uid2name", myuid));
+ s = db_get(ServerProgsDB, strcat("/uid2name/", myuid));
+
+ // FIXME remove this later after 0.6 release
+ // convert old style broken records to correct style
+ if(s == "")
+ {
+ s = db_get(ServerProgsDB, strcat("uid2name", myuid));
+ if(s != "")
+ {
+ db_put(ServerProgsDB, strcat("/uid2name/", myuid), s);
+ db_put(ServerProgsDB, strcat("uid2name", myuid), "");
+ }
+ }
if(s == "")
s = "^1Unregistered Player";
playerdemo.qh
+// singleplayer stuff
item_key.qh
+secret.qh
scores_rules.qc
g_triggers.qc
g_models.qc
+// singleplayer stuff
+item_key.qc
+secret.qc
+
cl_weaponsystem.qc
w_common.qc
t_items.qc
cl_weapons.qc
cl_impulse.qc
-item_key.qc
ent_cs.qc
--- /dev/null
+
+
+void secrets_setstatus() {
+ self.stat_secrets_total = secrets_total;
+ self.stat_secrets_found = secrets_found;
+}
+
+/**
+ * A secret has been found (maybe :P)
+ */
+void trigger_secret_touch() {
+ // only a player can trigger this
+ if (other.classname != "player")
+ return;
+
+ // update secrets found counter
+ secrets_found += 1;
+ //print("Secret found: ", ftos(secret_counter.cnt), "/");
+ //print(ftos(secret_counter.count), "\n");
+
+ // centerprint message (multi_touch() doesn't always call centerprint())
+ centerprint(other, self.message);
+ self.message = "";
+
+ // handle normal trigger features
+ multi_touch();
+ remove(self);
+}
+
+/*QUAKED trigger_secret (.5 .5 .5) ?
+Variable sized secret trigger. Can be targeted at one or more entities.
+Basically, it's a trigger_once (with restrictions, see notes) that additionally updates the number of secrets found.
+-------- KEYS --------
+sounds: 1 to play misc/secret.wav, 2 to play misc/talk.wav, 3 to play misc/trigger1.wav (default: 1)
+noise: path to sound file, if you want to play something else
+target: trigger all entities with this targetname when triggered
+message: print this message to the player who activated the trigger instead of the standard 'You found a secret!'
+killtarget: remove all entities with this targetname when triggered
+-------- NOTES --------
+You should create a common/trigger textured brush covering the entrance to a secret room/area.
+Trigger secret can only be trigger by a player's touch and can not be a target itself.
+*/
+void spawnfunc_trigger_secret() {
+ // FIXME: should it be disabled in most modes?
+
+ // update secrets count
+ secrets_total += 1;
+
+ // add default message
+ if (self.message == "")
+ self.message = "You found a secret!";
+
+ // set default sound
+ if (self.noise == "")
+ if not(self.sounds)
+ self.sounds = 1; // misc/secret.wav
+
+ // this entity can't be a target itself!!!!
+ self.targetname = "";
+
+ // you can't just shoot a room to find it, can you?
+ self.health = 0;
+
+ // a secret can not be delayed
+ self.delay = 0;
+
+ // convert this trigger to trigger_once
+ self.classname = "trigger_once";
+ spawnfunc_trigger_once();
+
+ // take over the touch() function, so we can mark secret as found
+ self.touch = trigger_secret_touch;
+ // ignore triggering;
+ self.use = SUB_Null;
+}
+
--- /dev/null
+/**
+ * Total number of secrets on the map.
+ */
+float secrets_total;
+
+/**
+ * Total numbe of secrets found on the map.
+ */
+float secrets_found;
+
+
+.float stat_secrets_total;
+.float stat_secrets_found;
+
+/**
+ * update secrets status.
+ */
+void secrets_setstatus();
+