// ===================================
alias ban "qc_cmd_sv ban ${* ?}" // Ban an IP address or a range of addresses (like 1.2.3)
alias banlist "qc_cmd_sv banlist ${* ?}" // List all existing bans
+alias bans "qc_cmd_sv bans ${* ?}" // COMPATIBILITY COMMAND FOR 0.5 CLIENTS
alias kickban "qc_cmd_sv kickban ${* ?}" // Disconnect a client and ban it at the same time
alias unban "qc_cmd_sv unban ${* ?}" // Remove an existing ban
// when disabled, don't allow game type changes "note: set these two equal to JUST support simple majorities"
set sv_vote_override_mostrecent 0
-alias vhelp "cmd vote help"
-alias vstatus "cmd vote status"
-alias vcall "cmd vote call ${* ?}"
-alias vstop "cmd vote stop"
-alias vmaster "cmd vote master"
-alias vlogin "cmd vote master login ${* ?}"
-alias vdo "cmd vote master do ${* ?}"
-alias vyes "cl_cmd handlevote yes; cl_cmd vyes" // NOTE: COMPATIBILITY FOR 0.5 IS ADDED HERE WITH "VYES", REMOVE LATER
-alias vno "cl_cmd handlevote no; cl_cmd vno" // ^^^ same, see above
-alias vdontcare "cmd vote abstain"
-alias vabstain "cmd vote abstain"
-
+// aliases for client only
+alias vmaster "qc_cmd_cmd vote master"
+alias vlogin "qc_cmd_cmd vote master login ${* ?}"
+alias vdo "qc_cmd_cmd vote master do ${* ?}"
+alias vyes "qc_cmd_cl handlevote yes; cl_cmd vyes" // NOTE: COMPATIBILITY FOR 0.5 IS ADDED HERE WITH "VYES", REMOVE LATER
+alias vno "qc_cmd_cl handlevote no; cl_cmd vno" // ^^^ same, see above
+alias vdontcare "qc_cmd_cmd vote abstain"
+alias vabstain "qc_cmd_cmd vote abstain"
+
+// aliases for both client and server
+alias vcall "qc_cmd_svcmd vote call ${* ?}"
+alias vhelp "qc_cmd_svcmd vote help"
+alias vstatus "qc_cmd_svcmd vote status"
+alias vstop "qc_cmd_svcmd vote stop"
+
+// general
alias vmap "vcall gotomap ${1 ?}"
alias vnextmap "vcall nextmap ${1 ?}"
alias vkick "vcall kick ${1 ?}"
// rcon server commands
// ======================
rcon_secure 1
-set rcon_restricted_commands "restart fraglimit chmap gotomap endmatch reducematchtime extendmatchtime allready kick kickban \"sv_cmd bans\" \"sv_cmd unban *\" status \"sv_cmd teamstatus\" movetoauto movetored movetoblue movetoyellow movetopink"
-
-// =============================
-// other miscellaneous aliases
-// =============================
-alias autoscreenshot "screenshot screenshots/autoscreenshot/${1 !}-${2 !}.jpg; echo \"^5A screenshot has been taken at request of the server.\""
-
+set rcon_restricted_commands "restart fraglimit chmap gotomap endmatch reducematchtime extendmatchtime allready kick kickban \"sv_cmd bans\" \"sv_cmd unban *\" status \"sv_cmd teamstatus\" movetoauto movetored movetoblue movetoyellow movetopink"
\ No newline at end of file
set g_respawn_ghosts 1 "if 1 dead bodies become ghosts and float away when the player respawns"
set g_respawn_ghosts_speed 5 "the speed with which respawn ghosts float and rotate"
set g_respawn_ghosts_maxtime 6 "maximum amount of time a respawn ghost can last, minimum time is half this value. 0 disables and ghosts fade when the body would"
+set cl_deathglow 0.8 "number of seconds during which dead bodies glow out"
set sv_gibhealth 100 "Minus health a dead body must have in order to get gibbed"
// fragmessage: This allows extra information to be displayed with the frag centerprints.
-set sv_fraginfo_ping 1 "Enable ping display information, 0 = Never display; 1 = Always display (If the player is a bot, it will say bot instead of the ping.)"
-set sv_fraginfo_handicap 1 "Enable handicap display information, 0 = Never display; 1 = Only when the player has handicap on; 2 = Always display (Displays Off if off)"
-set sv_fraginfo_stats 1 "Enable statistics (health/armor) display information, 0 = Never display; 1 = Always display (Only available for the person who was killed)"
-set sv_fraginfo_typefrag 1 "Enable typefrag display information, 0 = Never display; 1 = Always display"
+set sv_fraginfo 1 "Enable extra frag message information, 0 = Never display, 1 = Display only in warmup mode; 2 = Always display"
+set sv_fraginfo_ping 1 "Enable ping display information, 0 = Never display, 1 = Always display (If the player is a bot, it will say bot instead of the ping.)"
+set sv_fraginfo_handicap 1 "Enable handicap display information, 0 = Never display, 1 = Only when the player has handicap on, 2 = Always display (Displays Off if disabled)"
+set sv_fraginfo_stats 1 "Enable statistics (health/armor) display information, 0 = Never display, 1 = Always display (Only available for the person who was killed)"
// use default physics
set sv_friction_on_land 0
// waypoint editor enable
set g_waypointeditor 0
+set g_waypointeditor_auto 0 "Automatically create waypoints for bots while playing; BEWARE, this currently creates too many of them"
set bot_ignore_bots 0 "When set, bots don't shoot at other bots"
set bot_join_empty 0 "When set, bots also play if no player has joined the server"
set bot_vs_human 0 "Bots and humans play in different teams when set. positive values to make an all-bot blue team, set to negative values to make an all-bot red team, the absolute value is the ratio bots vs humans (1 for equal count). Changes will be correctly applied only from the next game"
seta cl_clippedspectating 1 "movement collision for spectators so that you can't pass through walls and such. (client setting) NOTE: reconnect or use sendcvar command to update the choice."
-seta cl_autoscreenshot 0 "client option to automatically take a screenshot once the map has ended (see also sv_autoscreenshot)"
+seta cl_autoscreenshot 1 "Take a screenshot upon the end of a match... 0 = Disable completely, 1 = Allow sv_autoscreenshot to take a screenshot when requested, 2 = Always take an autoscreenshot anyway."
// must be at the bottom of this file:
// alias for switching the teamselect menu
float serverflags;
float uid2name_dialog;
+
+.float csqcmodel_isdead; // used by shownames and miscfunctions (float getplayerisdead(float) {}) to know when a player is dead
\ No newline at end of file
hud_configure_prev = -1;
tab_panel = -1;
+
+ draw_currentSkin = strzone(strcat("gfx/menu/", cvar_string("menu_skin")));
}
// CSQC_Shutdown : Called every time the CSQC code is shutdown (changing maps, quitting, etc)
vector vf_size, vf_min;
float a;
+ ++framecount;
+
hud = getstati(STAT_HUD);
if(checkextension("DP_CSQC_MINFPS_QUALITY"))
float autocvar__cl_playerskin;
string autocvar__cl_playermodel;
float autocvar_cl_precacheplayermodels;
+float autocvar_cl_deathglow;
void LocalCommand_macro_help()
{
#define CLIENT_COMMAND(name,function,description) \
- { if(strtolower(description) != string_null) { print(" ^2", name, "^7: ", description, "\n"); } }
+ { if(strtolower(description) != "") { print(" ^2", name, "^7: ", description, "\n"); } }
CLIENT_COMMANDS(0, 0)
#undef CLIENT_COMMAND
void LocalCommand_macro_write_aliases(float fh)
{
#define CLIENT_COMMAND(name,function,description) \
- { CMD_Write_Alias("qc_cmd_cl", name, description); }
+ { if(strtolower(description) != "") { CMD_Write_Alias("qc_cmd_cl", name, description); } }
CLIENT_COMMANDS(0, 0)
#undef CLIENT_COMMAND
+void CSQCModel_Hook_PreDraw();
+
.float isplayermodel;
// FEATURE: LOD
string modelname = self.model;
string s;
- if(!fexists(modelname))
- {
- print(sprintf(_("Trying to use non existing model %s. "), modelname));
- modelname = cvar_defstring("_cl_playermodel");
- print(sprintf(_("Reverted to %s.\n"), modelname));
- }
-
// set modelindex
self.lodmodelindex0 = self.modelindex;
self.lodmodelindex1 = self.modelindex;
// FEATURE: forcemodel (MUST be called BEFORE LOD!)
string forceplayermodels_model;
+float forceplayermodels_modelisgoodmodel;
float forceplayermodels_modelindex;
float forceplayermodels_skin;
string forceplayermodels_mymodel;
+float forceplayermodels_myisgoodmodel;
float forceplayermodels_mymodelindex;
float forceplayermodels_attempted;
+
.string forceplayermodels_savemodel;
.float forceplayermodels_savemodelindex;
.float forceplayermodels_saveskin;
.float forceplayermodels_savecolormap;
+
+.string forceplayermodels_isgoodmodel_mdl;
+.float forceplayermodels_isgoodmodel;
+
+string forceplayermodels_goodmodel;
+float forceplayermodels_goodmodelindex;
+
void CSQCPlayer_ForceModel_PreUpdate(void)
{
self.model = self.forceplayermodels_savemodel;
self.forceplayermodels_savemodelindex = self.modelindex;
self.forceplayermodels_saveskin = self.skin;
self.forceplayermodels_savecolormap = self.colormap;
+
+ if(self.forceplayermodels_savemodel != self.forceplayermodels_isgoodmodel_mdl)
+ {
+ self.forceplayermodels_isgoodmodel = fexists(self.forceplayermodels_savemodel);
+ self.forceplayermodels_isgoodmodel_mdl = self.forceplayermodels_savemodel;
+ if(!self.forceplayermodels_isgoodmodel)
+ print(sprintf("Warning: missing model %s has been used\n", self.forceplayermodels_savemodel));
+ }
}
void CSQCPlayer_ForceModel_Apply(float islocalplayer)
{
- // first, try finding it from the server
+ // which one is ALWAYS good?
+ if not(forceplayermodels_goodmodel)
+ {
+ entity e;
+ e = spawn();
+ setmodel(e, cvar_defstring("_cl_playermodel"));
+ forceplayermodels_goodmodel = e.model;
+ forceplayermodels_goodmodelindex = e.modelindex;
+ remove(e);
+ }
+ // first, try finding it from the server
if(self.forceplayermodels_savemodelindex && self.forceplayermodels_savemodel != "null")
{
if(islocalplayer)
{
// trust server's idea of "own player model"
- forceplayermodels_model = self.model;
- forceplayermodels_modelindex = self.modelindex;
- forceplayermodels_skin = self.skin;
+ forceplayermodels_modelisgoodmodel = self.forceplayermodels_isgoodmodel;
+ forceplayermodels_model = self.forceplayermodels_savemodel;
+ forceplayermodels_modelindex = self.forceplayermodels_savemodelindex;
+ forceplayermodels_skin = self.forceplayermodels_saveskin;
forceplayermodels_attempted = 1;
}
}
entity e;
e = spawn();
setmodel(e, autocvar__cl_playermodel); // this is harmless, see below
+ forceplayermodels_modelisgoodmodel = fexists(e.model);
forceplayermodels_model = e.model;
forceplayermodels_modelindex = e.modelindex;
forceplayermodels_skin = autocvar__cl_playerskin;
entity e;
e = spawn();
setmodel(e, autocvar_cl_forcemyplayermodel); // this is harmless, see below
+ forceplayermodels_myisgoodmodel = fexists(e.model);
forceplayermodels_mymodel = e.model;
forceplayermodels_mymodelindex = e.modelindex;
remove(e);
}
// apply it
- if(autocvar_cl_forcemyplayermodel != "" && forceplayermodels_mymodelindex && self.entnum == player_localnum + 1)
+ if(autocvar_cl_forcemyplayermodel != "" && forceplayermodels_myisgoodmodel && islocalplayer)
{
self.model = forceplayermodels_mymodel;
self.modelindex = forceplayermodels_mymodelindex;
self.skin = autocvar_cl_forcemyplayerskin;
}
- else if(autocvar_cl_forceplayermodels && forceplayermodels_modelindex)
+ else if(autocvar_cl_forceplayermodels && forceplayermodels_modelisgoodmodel)
{
self.model = forceplayermodels_model;
self.modelindex = forceplayermodels_modelindex;
self.skin = forceplayermodels_skin;
}
- else
+ else if(self.forceplayermodels_isgoodmodel)
{
self.model = self.forceplayermodels_savemodel;
self.modelindex = self.forceplayermodels_savemodelindex;
self.skin = self.forceplayermodels_saveskin;
}
+ else
+ {
+ self.model = forceplayermodels_goodmodel;
+ self.modelindex = forceplayermodels_goodmodelindex;
+ self.skin = self.forceplayermodels_saveskin;
+ }
// forceplayercolors too
if(!teamplay)
{
- if(autocvar_cl_forcemyplayercolors && self.entnum == player_localnum + 1)
+ if(autocvar_cl_forcemyplayercolors && islocalplayer)
self.colormap = 1024 + autocvar_cl_forcemyplayercolors;
else if(autocvar_cl_forceplayercolors)
self.colormap = player_localnum + 1;
.float csqcmodel_saveframe3;
.float csqcmodel_saveframe4;
.float csqcmodel_framecount;
+
+#define IS_DEAD_FRAME(f) ((f) == 0 || (f) == 1)
void CSQCPlayer_FallbackFrame_PreUpdate(void)
{
self.frame = self.csqcmodel_saveframe;
if(isnew)
{
#define FIX_FRAMETIME(f,ft) \
- switch(self.f) \
+ if(IS_DEAD_FRAME(self.f)) \
{ \
- case 0: \
- case 1: \
- self.ft = 0; \
- break; \
+ self.ft = self.death_time; \
}
FIX_FRAMETIME(frame, frame1time)
FIX_FRAMETIME(frame2, frame2time)
FIX_FRAMETIME(frame3, frame3time)
FIX_FRAMETIME(frame4, frame4time)
}
+ self.csqcmodel_isdead = IS_DEAD_FRAME(self.frame);
}
float CSQCPlayer_FallbackFrame(float f)
{
self.frame4 = CSQCPlayer_FallbackFrame(self.frame4);
}
-// FEATURE: auto glowmod
-.vector glowmod;
-void CSQCPlayer_GlowMod_Apply(void)
-{
- if(self.colormap > 0)
- self.glowmod = colormapPaletteColor(((self.colormap >= 1024) ? self.colormap : stof(getplayerkeyvalue(self.colormap - 1, "colors"))) & 0x0F, TRUE) * 2;
- else
- self.glowmod = '1 1 1';
-}
-
// FEATURE: auto tag_index
.entity tag_entity;
.float tag_entity_lastmodelindex;
self.tag_entity = findfloat(world, entnum, self.tag_networkentity);
changed = 1;
}
+
+ // recursive predraw call to fix issues with forcemodels and LOD if bone indexes mismatch
+ {
+ entity oldself = self;
+ self = self.tag_entity;
+ CSQCModel_Hook_PreDraw();
+ self = oldself;
+ }
+
if(self.tag_entity.modelindex != self.tag_entity_lastmodelindex)
{
self.tag_entity_lastmodelindex = self.tag_entity.modelindex;
void CSQCModel_Effects_Apply(void)
{
float eff = self.csqcmodel_effects;
- eff &~= CSQCMODEL_EF_INVISIBLE;
+ eff &~= CSQCMODEL_EF_RESPAWNGHOST;
self.renderflags &~= (RF_DEPTHHACK | RF_ADDITIVE | RF_FULLBRIGHT | EF_NOSHADOW | RF_USEAXIS);
self.effects = 0;
adddynamiclight(self.origin, 400, '3 3 3');
if(eff & EF_DIMLIGHT)
adddynamiclight(self.origin, 200, '1.5 1.5 1.5');
- if((eff & EF_NODRAW) || (self.csqcmodel_effects & CSQCMODEL_EF_INVISIBLE) || (self.alpha < 0))
+ if((eff & EF_NODRAW) || (self.alpha < 0))
self.drawmask = 0;
if(eff & EF_ADDITIVE)
self.renderflags |= RF_ADDITIVE;
Projectile_DrawTrail(self.origin);
else
Projectile_ResetTrail(self.origin);
+
+ if(self.csqcmodel_effects & CSQCMODEL_EF_RESPAWNGHOST)
+ self.renderflags |= RF_ADDITIVE;
+ // also special in CSQCPlayer_GlowMod_Apply
+}
+
+// FEATURE: auto glowmod
+.vector glowmod;
+void CSQCPlayer_GlowMod_Apply(void)
+{
+ float cm = self.colormap;
+
+ if(self.csqcmodel_effects & CSQCMODEL_EF_RESPAWNGHOST)
+ cm = 1024;
+
+ if(self.colormap > 0)
+ self.glowmod = colormapPaletteColor(((self.colormap >= 1024) ? self.colormap : stof(getplayerkeyvalue(self.colormap - 1, "colors"))) & 0x0F, TRUE) * 2;
+ else
+ self.glowmod = '1 1 1';
+
+ if(autocvar_cl_deathglow > 0)
+ if(self.csqcmodel_isdead)
+ {
+ self.glowmod = self.glowmod * bound(0, 1 - (time - self.death_time) / autocvar_cl_deathglow, 1);
+ // prevent the zero vector
+ self.glowmod_x = max(self.glowmod_x, 0.0001);
+ self.glowmod_y = max(self.glowmod_y, 0.0001);
+ self.glowmod_z = max(self.glowmod_z, 0.0001);
+ }
}
// general functions
-void CSQCModel_Hook_PreDraw(float isplayer, float islocalplayer)
+.float csqcmodel_predraw_run;
+void CSQCModel_Hook_PreDraw()
{
+ if(self.csqcmodel_predraw_run == framecount)
+ return;
+ self.csqcmodel_predraw_run = framecount;
+
if(!self.modelindex || self.model == "null")
{
self.drawmask = 0;
if(self.isplayermodel) // this checks if it's a player MODEL!
{
+ CSQCPlayer_ForceModel_Apply(self.entnum == player_localnum + 1);
CSQCPlayer_GlowMod_Apply();
- CSQCPlayer_ForceModel_Apply(islocalplayer);
CSQCPlayer_LOD_Apply();
CSQCPlayer_FallbackFrame_Apply();
}
- if(!isplayer) // this checks if it's a player SLOT!
- CSQCModel_AutoTagIndex_Apply();
+ CSQCModel_AutoTagIndex_Apply();
CSQCModel_Effects_Apply();
}
float hud;
float view_quality;
+float framecount;
}
else
{
- drawpic(pos, pic, img_size, '1 1 1', theAlpha, DRAWFLAG_NORMAL);
+ if(drawgetimagesize(pic) == '0 0 0')
+ drawpic(pos, draw_UseSkinFor("nopreview_map"), img_size, '1 1 1', theAlpha, DRAWFLAG_NORMAL);
+ else
+ drawpic(pos, pic, img_size, '1 1 1', theAlpha, DRAWFLAG_NORMAL);
}
if(id == mv_ownvote)
return GETPLAYERORIGIN_ERROR;
}
+
+float getplayerisdead(float pl)
+{
+ entity e;
+
+ e = CSQCModel_server2csqc(pl + 1);
+ if(e)
+ return e.csqcmodel_isdead;
+
+ return FALSE;
+}
\ No newline at end of file
// self.sameteam = player is on same team as local client
// self.fadedelay = time to wait before name tag starts fading in for enemies
// self.pointtime = last time you pointed at this player
-//
+// self.csqcmodel_isdead = value of csqcmodel_isdead to know when the player is dead or not
+
const float SHOWNAMES_FADESPEED = 4;
const float SHOWNAMES_FADEDELAY = 0.4;
void Draw_ShowNames(entity ent)
ent.alpha = max(0, ent.alpha - SHOWNAMES_FADESPEED * frametime);
ent.fadedelay = 0; // reset fade in delay, enemy has left the view
}
- else if(ent.healthvalue < 1) // dead player, fade out slowly
+ else if(ent.csqcmodel_isdead) // dead player, fade out slowly
ent.alpha = max(0, ent.alpha - SHOWNAMES_FADESPEED * 0.25 * frametime);
else if(overlap) // tag overlap detected, fade out
ent.alpha = max(0, ent.alpha - SHOWNAMES_FADESPEED * frametime);
e.origin = getplayerorigin(i);
if(e.origin == GETPLAYERORIGIN_ERROR)
continue;
+
+ e.csqcmodel_isdead = getplayerisdead(i);
Draw_ShowNames(e);
}
.float armorvalue;
.float sameteam;
.float fadedelay;
-.float pointtime;
+.float pointtime;
\ No newline at end of file
CSQCMODEL_PROPERTY(4, float, ReadByte, WriteByte, modelflags) \
CSQCMODEL_PROPERTY_SCALED(8, float, ReadByte, WriteByte, alpha, 254, -1, 254) \
CSQCMODEL_PROPERTY(16, float, ReadByte, WriteByte, skin) \
- CSQCMODEL_IF(isplayer) \
- CSQCMODEL_ENDIF \
+ CSQCMODEL_PROPERTY(32, float, ReadApproxPastTime, WriteApproxPastTime, death_time) \
CSQCMODEL_IF(!isplayer) \
- CSQCMODEL_PROPERTY(32, TAG_ENTITY_TYPE, ReadShort, WriteEntity, TAG_ENTITY_NAME) \
- CSQCMODEL_PROPERTY_SCALED(64, float, ReadByte, WriteByte, glowmod_x, 255, 0, 255) \
- CSQCMODEL_PROPERTY_SCALED(64, float, ReadByte, WriteByte, glowmod_y, 255, 0, 255) \
- CSQCMODEL_PROPERTY_SCALED(64, float, ReadByte, WriteByte, glowmod_z, 255, 0, 255) \
+ CSQCMODEL_PROPERTY(64, TAG_ENTITY_TYPE, ReadShort, WriteEntity, TAG_ENTITY_NAME) \
+ CSQCMODEL_PROPERTY_SCALED(128, float, ReadByte, WriteByte, glowmod_x, 255, 0, 255) \
+ CSQCMODEL_PROPERTY_SCALED(128, float, ReadByte, WriteByte, glowmod_y, 255, 0, 255) \
+ CSQCMODEL_PROPERTY_SCALED(128, float, ReadByte, WriteByte, glowmod_z, 255, 0, 255) \
CSQCMODEL_ENDIF
// TODO get rid of colormod/glowmod here, find good solution for nex charge glowmod hack; also get rid of some useless properties on non-players that only exist for CopyBody
#define CSQCMODEL_HOOK_POSTUPDATE \
CSQCModel_Hook_PostUpdate(isnew, isplayer, islocalplayer);
#define CSQCMODEL_HOOK_PREDRAW \
- CSQCModel_Hook_PreDraw(isplayer, islocalplayer);
+ CSQCModel_Hook_PreDraw();
#define CSQCPLAYER_HOOK_POSTCAMERASETUP
// force updates of player entities that often even if unchanged
# endif
#endif
-#define CSQCMODEL_EF_INVISIBLE EF_SELECTABLE
+#define CSQCMODEL_EF_RESPAWNGHOST EF_SELECTABLE
#endif
#endif
+#ifndef SVQC
+string draw_UseSkinFor(string pic)
+{
+ if(substring(pic, 0, 1) == "/")
+ return substring(pic, 1, strlen(pic)-1);
+ else
+ return strcat(draw_currentSkin, "/", pic);
+}
+#endif
+
string unescape(string in)
{
float i, len;
}
cvar_settemp_restore(); // this must be done LAST, but in any case
}
+
+#define APPROXPASTTIME_ACCURACY_REQUIREMENT 0.05
+#define APPROXPASTTIME_MAX (16384 * APPROXPASTTIME_ACCURACY_REQUIREMENT)
+#define APPROXPASTTIME_RANGE (64 * APPROXPASTTIME_ACCURACY_REQUIREMENT)
+// this will use the value:
+// 128
+// accuracy near zero is APPROXPASTTIME_MAX/(256*255)
+// accuracy at x is 1/derivative, i.e.
+// APPROXPASTTIME_MAX * (1 + 256 * (dt / APPROXPASTTIME_MAX))^2 / 65536
+#ifdef SVQC
+void WriteApproxPastTime(float dst, float t)
+{
+ float dt = time - t;
+
+ // warning: this is approximate; do not resend when you don't have to!
+ // be careful with sendflags here!
+ // we want: 0 -> 0.05, 1 -> 0.1, ..., 255 -> 12.75
+
+ // map to range...
+ dt = 256 * (dt / ((APPROXPASTTIME_MAX / 256) + dt));
+
+ // round...
+ dt = rint(bound(0, dt, 255));
+
+ WriteByte(dst, dt);
+}
+#endif
+#ifdef CSQC
+float ReadApproxPastTime()
+{
+ float dt = ReadByte();
+
+ // map from range...PPROXPASTTIME_MAX / 256
+ dt = (APPROXPASTTIME_MAX / 256) * (dt / (256 - dt));
+
+ return servertime - dt;
+}
+#endif
#endif
void wordwrap_cb(string s, float l, void(string) callback)
+#ifndef SVQC
+string draw_currentSkin;
+string draw_UseSkinFor(string pic);
+#endif
+
// iterative depth-first search, with fields that go "up", "down left" and "right" in a tree
// for each element, funcPre is called first, then funcPre and funcPost for all its children, and funcPost last
void depthfirst(entity start, .entity up, .entity downleft, .entity right, void(entity, entity) funcPre, void(entity, entity) funcPost, entity pass);
// generic shutdown handler
void Shutdown();
+
+#ifdef SVQC
+void WriteApproxPastTime(float dst, float t);
+#endif
+#ifdef CSQC
+float ReadApproxPastTime();
+#endif
csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
+ // FIXME do we really NEED this? dead players have servercommandframe
+ // == 0 and thus won't predict
if (getstatf(STAT_HEALTH) <= 0)
{
csqcplayer_moveframe = clientcommandframe;
getinputstate(csqcplayer_moveframe-1);
+ print("the Weird code path got hit\n");
return;
}
- while(csqcplayer_moveframe < endframe)
+ if(csqcplayer_moveframe >= endframe)
{
- if (!getinputstate(csqcplayer_moveframe))
+ getinputstate(csqcplayer_moveframe - 1);
+ }
+ else
+ {
+ do
{
- break;
+ if (!getinputstate(csqcplayer_moveframe))
+ break;
+ runstandardplayerphysics(self);
+ CSQCPlayer_SetMinsMaxs();
+ csqcplayer_moveframe++;
}
- runstandardplayerphysics(self);
- CSQCPlayer_SetMinsMaxs();
- csqcplayer_moveframe++;
+ while(csqcplayer_moveframe < endframe);
}
//add in anything that was applied after (for low packet rate protocols)
void CSQCPlayer_SetCamera()
{
+ vector v0;
+ v0 = pmove_vel; // TRICK: pmove_vel is set by the engine when we get here. No need to network velocity
+
if(csqcplayer)
{
entity oldself;
// override it back just in case
self.view_ofs = '0 0 1' * getstati(STAT_VIEWHEIGHT);
+
+ // set velocity
+ self.velocity = v0;
}
else
{
{
vector o, v;
o = self.origin;
- v = pmove_vel; // TRICK: pmove_vel is set by the engine when we get here. No need to network velocity
csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
CSQCPlayer_PredictTo(servercommandframe + 1);
CSQCPlayer_SetPredictionError(o - self.origin);
self.origin = o;
- self.velocity = v;
+ self.velocity = v0;
// get crouch state from the server
if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS_z)
if(input_buttons & 4)
refdefflags |= REFDEFFLAG_JUMPING;
+ // note: these two only work in WIP2, but are harmless in WIP1
+ if(getstati(STAT_HEALTH) <= 0)
+ refdefflags |= REFDEFFLAG_DEAD;
+
+ if(intermission)
+ refdefflags |= REFDEFFLAG_INTERMISSION;
+
V_CalcRefdef(view, refdefflags);
}
else
//1 should lead to an unmodified view
//DP_CSQC_V_CALCREFDEF_WIP1
+//DP_CSQC_V_CALCREFDEF_WIP2
//idea: divVerent
//darkplaces implementation: divVerent
//builtin definitions:
float PMF_ONGROUND = 8;
float REFDEFFLAG_TELEPORTED = 1;
float REFDEFFLAG_JUMPING = 2;
+float REFDEFFLAG_DEAD = 4;
+float REFDEFFLAG_INTERMISSION = 8;
//- use this on the player entity after performing prediction
//- pass REFDEFFLAG_TELEPORTED if the player teleported since last frame
//- pass REFDEFFLAG_JUMPING if jump button is pressed
+//- pass REFDEFFLAG_DEAD if dead (DP_CSQC_V_CALCREFDEF_WIP2)
+//- pass REFDEFFLAG_INTERMISSION if in intermission (DP_CSQC_V_CALCREFDEF_WIP2)
//- the player entity needs to have origin, velocity, pmove_flags set according
// to prediction (the above two PMF_ flags are used in the player's pmove_flags)
//- NOTE: to check for this, ALSO OR a check with DP_CSQC_V_CALCREFDEF to also support
vector draw_mousepointer_offset;
vector draw_mousepointer_size;
-string draw_UseSkinFor(string pic)
-{
- if(substring(pic, 0, 1) == "/")
- return substring(pic, 1, strlen(pic)-1);
- else
- return strcat(draw_currentSkin, "/", pic);
-}
-
void draw_setMousePointer(string pic, vector theSize, vector theOffset)
{
draw_mousepointer = strzone(draw_UseSkinFor(pic));
return v;
}
-void draw_PreloadPicture(string pic)
+string draw_PreloadPicture(string pic)
{
pic = draw_UseSkinFor(pic);
- precache_pic(pic);
+ return precache_pic(pic);
}
void draw_Picture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha)
void draw_setMousePointer(string pic, vector theSize, vector theOffset);
void draw_drawMousePointer(vector where);
-void draw_PreloadPicture(string pic);
+string draw_PreloadPicture(string pic);
void draw_ButtonPicture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha);
void draw_VertButtonPicture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha);
void draw_BorderPicture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha, vector theBorderSize);
float draw_NeedResizeNotify;
-string draw_currentSkin;
-
float draw_TextWidth_WithColors(string s, vector size);
float draw_TextWidth_WithoutColors(string s, vector size);
draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
s = ftos(p);
- draw_Picture(me.columnPreviewOrigin * eX, strcat("/maps/", campaign_mapname[i]), me.columnPreviewSize * eX + eY, '1 1 1', theAlpha);
+ if(draw_PictureSize(strcat("/maps/", campaign_mapname[i])) == '0 0 0')
+ draw_Picture(me.columnPreviewOrigin * eX, "nopreview_map", me.columnPreviewSize * eX + eY, '1 1 1', theAlpha);
+ else
+ draw_Picture(me.columnPreviewOrigin * eX, strcat("/maps/", campaign_mapname[i]), me.columnPreviewSize * eX + eY, '1 1 1', theAlpha);
+
if(i < me.campaignIndex)
draw_Picture(me.checkMarkOrigin, "checkmark", me.checkMarkSize, '1 1 1', 1);
if(i <= me.campaignIndex)
me.authorLabel.setText(me.authorLabel, me.currentMapAuthor);
me.descriptionLabel.setText(me.descriptionLabel, me.currentMapDescription);
me.featuresLabel.setText(me.featuresLabel, me.currentMapFeaturesText);
- me.previewImage.src = me.currentMapPreviewImage;
+ if(draw_PictureSize(me.currentMapPreviewImage) == '0 0 0')
+ me.previewImage.src = "nopreview_map";
+ else
+ me.previewImage.src = me.currentMapPreviewImage;
for(i = 0; i < GameType_GetCount(); ++i)
{
draw_Fill('0 0 0', '1 1 0', SKINCOLOR_MAPLIST_INCLUDEDBG, SKINALPHA_MAPLIST_INCLUDEDBG);
s = ftos(p);
- draw_Picture(me.columnPreviewOrigin * eX, strcat("/maps/", MapInfo_Map_bspname), me.columnPreviewSize * eX + eY, '1 1 1', theAlpha);
+ if(draw_PictureSize(strcat("/maps/", MapInfo_Map_bspname)) == '0 0 0')
+ draw_Picture(me.columnPreviewOrigin * eX, "nopreview_map", me.columnPreviewSize * eX + eY, '1 1 1', theAlpha);
+ else
+ draw_Picture(me.columnPreviewOrigin * eX, strcat("/maps/", MapInfo_Map_bspname), me.columnPreviewSize * eX + eY, '1 1 1', theAlpha);
+
if(included)
draw_Picture(me.checkMarkOrigin, "checkmark", me.checkMarkSize, '1 1 1', 1);
s = draw_TextShortenToWidth(MapInfo_Map_titlestring, me.columnNameSize, 0, me.realFontSize);
me.currentModelDescription = strzone(bufstr_get(me.bufModels, BUFMODELS_COUNT*me.idxModels+BUFMODELS_DESC));
// fix the image
- me.src = me.currentModelImage;
+ if(draw_PictureSize(me.currentModelImage) == '0 0 0')
+ me.src = "nopreview_player";
+ else
+ me.src = me.currentModelImage;
me.updateAspect(me);
}
bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_NAME, substring(s, 9, strlen(s) - 24)); // the * part
bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_TITLE, _("<TITLE>"));
bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_AUTHOR, _("<AUTHOR>"));
- bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_PREVIEW, strcat("/gfx/menu/", substring(s, 9, strlen(s) - 24), "/skinpreview"));
+ if(draw_PictureSize(strcat("/gfx/menu/", substring(s, 9, strlen(s) - 24), "/skinpreview")) == '0 0 0')
+ bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_PREVIEW, "nopreview_menuskin");
+ else
+ bufstr_set(buf, i * SKINPARM_COUNT + SKINPARM_PREVIEW, strcat("/gfx/menu/", substring(s, 9, strlen(s) - 24), "/skinpreview"));
fh = fopen(language_filename(s), FILE_READ);
if(fh < 0)
{
float autocvar_g_turrets_unit_walker_turn_swim;
float autocvar_g_use_ammunition;
float autocvar_g_waypointeditor;
+float autocvar_g_waypointeditor_auto;
float autocvar_g_waypoints_for_items;
float autocvar_g_weapon_charge_colormod_blue_full;
float autocvar_g_weapon_charge_colormod_blue_half;
string autocvar_sv_eventlog_files_nameprefix;
string autocvar_sv_eventlog_files_namesuffix;
float autocvar_sv_eventlog_files_timestamps;
+float autocvar_sv_fraginfo;
float autocvar_sv_fraginfo_handicap;
float autocvar_sv_fraginfo_ping;
float autocvar_sv_fraginfo_stats;
-float autocvar_sv_fraginfo_typefrag;
float autocvar_sv_friction;
float autocvar_sv_friction_on_land;
float autocvar_sv_gameplayfix_q2airaccelerate;
localcmd("quit\n");
}
- if (currentbots > 0 || autocvar_g_waypointeditor)
+ if (currentbots > 0 || autocvar_g_waypointeditor || autocvar_g_waypointeditor_auto)
if (botframe_spawnedwaypoints)
{
if(botframe_cachedwaypointlinks)
if (autocvar_g_waypointeditor)
botframe_showwaypointlinks();
+ if (autocvar_g_waypointeditor_auto)
+ botframe_autowaypoints();
+
if(time > bot_cvar_nextthink)
{
if(currentbots>0)
self.goalstack31 = world;
}
+float navigation_waypoint_will_link(vector v, vector org, entity ent, float walkfromwp, float bestdist)
+{
+ float dist;
+ dist = vlen(v - org);
+ if (bestdist > dist)
+ {
+ traceline(v, org, TRUE, ent);
+ if (trace_fraction == 1)
+ {
+ if (walkfromwp)
+ {
+ if (tracewalk(ent, v, PL_MIN, PL_MAX, org, bot_navigation_movemode))
+ return TRUE;
+ }
+ else
+ {
+ if (tracewalk(ent, org, PL_MIN, PL_MAX, v, bot_navigation_movemode))
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
// find the spawnfunc_waypoint near a dynamic goal such as a dropped weapon
-entity navigation_findnearestwaypoint(entity ent, float walkfromwp)
+entity navigation_findnearestwaypoint_withdist(entity ent, float walkfromwp, float bestdist)
{
entity waylist, w, best;
- float dist, bestdist;
+ float dist;
vector v, org, pm1, pm2;
+
pm1 = ent.origin + ent.mins;
pm2 = ent.origin + ent.maxs;
waylist = findchain(classname, "waypoint");
te_plasmaburn(org);
best = world;
- bestdist = 1050;
// box check failed, try walk
w = waylist;
}
else
v = w.origin;
- dist = vlen(v - org);
- if (bestdist > dist)
+ if(navigation_waypoint_will_link(v, org, ent, walkfromwp, bestdist))
{
- traceline(v, org, TRUE, ent);
- if (trace_fraction == 1)
- {
- if (walkfromwp)
- {
- //print("^1can I reach ", vtos(org), " from ", vtos(v), "?\n");
- if (tracewalk(ent, v, PL_MIN, PL_MAX, org, bot_navigation_movemode))
- {
- bestdist = dist;
- best = w;
- }
- }
- else
- {
- if (tracewalk(ent, org, PL_MIN, PL_MAX, v, bot_navigation_movemode))
- {
- bestdist = dist;
- best = w;
- }
- }
- }
+ bestdist = vlen(v - org);
+ best = w;
}
}
w = w.chain;
}
return best;
}
+entity navigation_findnearestwaypoint(entity ent, float walkfromwp)
+{
+ return navigation_findnearestwaypoint_withdist(ent, walkfromwp, 1050);
+}
// finds the waypoints near the bot initiating a navigation query
float navigation_markroutes_nearestwaypoints(entity waylist, float maxdist)
player = find(player, classname, "player");
}
}
+
+float botframe_autowaypoints_fixdown(vector v)
+{
+ tracebox(v, PL_MIN, PL_MAX, v + '0 0 -64', MOVE_NOMONSTERS, world);
+ if(trace_fraction >= 1)
+ return 0;
+ return 1;
+}
+
+float botframe_autowaypoints_createwp(vector v, entity p, .entity fld)
+{
+ entity w;
+
+ w = find(world, classname, "waypoint");
+ while (w)
+ {
+ // if a matching spawnfunc_waypoint already exists, don't add a duplicate
+ if (boxesoverlap(v - '32 32 32', v + '32 32 32', w.absmin, w.absmax))
+ //if (boxesoverlap(v - '4 4 4', v + '4 4 4', w.absmin, w.absmax))
+ return 0;
+ w = find(w, classname, "waypoint");
+ }
+
+ waypoint_schedulerelink(p.fld = waypoint_spawn(v, v, 0));
+ return 1;
+}
+
+// return value:
+// 1 = WP created
+// 0 = no action needed
+// -1 = temp fail, try from world too
+// -2 = permanent fail, do not retry
+float botframe_autowaypoints_fix_from(entity p, float walkfromwp, entity wp, .entity fld)
+{
+ // make it possible to go from p to wp, if we can
+ // if wp is world, nearest is chosen
+
+ entity w;
+ vector porg;
+ float t, tmin, tmax;
+ vector o;
+ vector save;
+
+ if(!botframe_autowaypoints_fixdown(p.origin))
+ return -2;
+ porg = trace_endpos;
+
+ if(wp)
+ {
+ // if any WP w fulfills wp -> w -> porg, then switch from wp to w
+
+ // if wp -> porg, then OK
+ float maxdist;
+ if(navigation_waypoint_will_link(wp.origin, porg, p, walkfromwp, 1050))
+ {
+ // we may find a better one
+ maxdist = vlen(wp.origin - porg);
+ }
+ else
+ {
+ // accept any "good"
+ maxdist = 2100;
+ }
+
+ float bestdist;
+ bestdist = maxdist;
+ w = find(world, classname, "waypoint");
+ while (w)
+ {
+ if(w != wp && !(w.wpflags & WAYPOINTFLAG_NORELINK))
+ {
+ float d;
+ d = vlen(wp.origin - w.origin) + vlen(w.origin - porg);
+ if(d < bestdist)
+ if(navigation_waypoint_will_link(wp.origin, w.origin, p, walkfromwp, 1050))
+ if(navigation_waypoint_will_link(w.origin, porg, p, walkfromwp, 1050))
+ {
+ bestdist = d;
+ p.fld = w;
+ }
+ }
+ w = find(w, classname, "waypoint");
+ }
+ if(bestdist < maxdist)
+ {
+ print("update chain to new nearest WP ", etos(p.fld), "\n");
+ return 0;
+ }
+
+ if(bestdist < 2100)
+ {
+ // we know maxdist < 2100
+ // so wp -> porg is still valid
+ // all is good
+ p.fld = wp;
+ return 0;
+ }
+
+ // otherwise, no existing WP can fix our issues
+ }
+ else
+ {
+ save = p.origin;
+ setorigin(p, porg);
+ w = navigation_findnearestwaypoint(p, walkfromwp);
+ setorigin(p, save);
+ if(w)
+ {
+ p.fld = w;
+ return 0;
+ }
+ }
+
+ tmin = 0;
+ tmax = 1;
+ for(;;)
+ {
+ if(tmax - tmin < 0.001)
+ {
+ // did not get a good candidate
+ return -1;
+ }
+
+ t = (tmin + tmax) * 0.5;
+ o = antilag_takebackorigin(p, time - t);
+ if(!botframe_autowaypoints_fixdown(o))
+ return -1;
+ o = trace_endpos;
+
+ if(wp)
+ {
+ if(!navigation_waypoint_will_link(wp.origin, o, p, walkfromwp, 1050))
+ {
+ // we cannot walk from wp.origin to o
+ // get closer to tmax
+ tmin = t;
+ continue;
+ }
+ }
+ else
+ {
+ save = p.origin;
+ setorigin(p, o);
+ w = navigation_findnearestwaypoint(p, walkfromwp);
+ setorigin(p, save);
+ if(!w)
+ {
+ // we cannot walk from any WP to o
+ // get closer to tmax
+ tmin = t;
+ continue;
+ }
+ }
+
+ // if we get here, o is valid regarding waypoints
+ // check if o is connected right to the player
+ // we break if it succeeds, as that means o is a good waypoint location
+ if(navigation_waypoint_will_link(o, porg, p, walkfromwp, 1050))
+ break;
+
+ // o is no good, we need to get closer to the player
+ tmax = t;
+ }
+
+ print("spawning a waypoint for connecting to ", etos(wp), "\n");
+ botframe_autowaypoints_createwp(o, p, fld);
+ return 1;
+}
+
+// automatically create missing waypoints
+.entity botframe_autowaypoints_lastwp0, botframe_autowaypoints_lastwp1;
+void botframe_autowaypoints_fix(entity p, float walkfromwp, .entity fld)
+{
+ float r;
+ r = botframe_autowaypoints_fix_from(p, walkfromwp, p.fld, fld);
+ if(r != -1)
+ return;
+ r = botframe_autowaypoints_fix_from(p, walkfromwp, world, fld);
+ if(r != -1)
+ return;
+
+ print("emergency: got no good nearby WP to build a link from, starting a new chain\n");
+ if(!botframe_autowaypoints_fixdown(p.origin))
+ return; // shouldn't happen, caught above
+ botframe_autowaypoints_createwp(trace_endpos, p, fld);
+}
+
+void botframe_autowaypoints()
+{
+ entity p;
+ entity wp0, wp1;
+ FOR_EACH_REALPLAYER(p)
+ {
+ if(p.deadflag)
+ continue;
+ // going back is broken, so only fix waypoints to walk TO the player
+ //botframe_autowaypoints_fix(p, FALSE, botframe_autowaypoints_lastwp0);
+ botframe_autowaypoints_fix(p, TRUE, botframe_autowaypoints_lastwp1);
+ //te_explosion(p.botframe_autowaypoints_lastwp0.origin);
+ }
+}
+
entity waypoint_spawnpersonal(vector position);
vector waypoint_fixorigin(vector position);
+
+void botframe_autowaypoints();
self.pauseregen_finished = 0;
self.damageforcescale = 0;
self.death_time = 0;
+ self.respawn_time = 0;
self.alpha = 0;
self.scale = 0;
self.fade_time = 0;
}
self.damageforcescale = 2;
self.death_time = 0;
+ self.respawn_time = 0;
self.scale = 0;
self.fade_time = 0;
self.pain_frame = 0;
else self.colormod = '1 1 1';
}*/
-.float oldcolormap;
void respawn(void)
{
if(self.alpha >= 0 && autocvar_g_respawn_ghosts)
self.movetype = MOVETYPE_FLY;
self.velocity = '0 0 1' * autocvar_g_respawn_ghosts_speed;
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 = 0; // this originally was 512, but raises a warning in the engine, so get rid of it
+ self.effects |= CSQCMODEL_EF_RESPAWNGHOST;
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);
}
CopyBody(1);
+
self.effects |= EF_NODRAW; // prevent another CopyBody
- if(self.oldcolormap)
- {
- self.colormap = self.oldcolormap;
- self.oldcolormap = 0;
- }
PutClientInServer();
}
return;
else
{
- number = ceil(self.death_time - time);
+ number = ceil(self.respawn_time - time);
if(number <= 0)
return;
if(number <= self.respawn_countdown)
{
self.respawn_countdown = number - 1;
- if(ceil(self.death_time - (time + 0.5)) == number) // only say it if it is the same number even in 0.5s; to prevent overlapping sounds
+ if(ceil(self.respawn_time - (time + 0.5)) == number) // only say it if it is the same number even in 0.5s; to prevent overlapping sounds
AnnounceTo(self, strcat(ftos(number), ""));
}
}
float button_pressed, force_respawn;
if(self.personal && g_race_qualifying)
{
- if(time > self.death_time)
+ if(time > self.respawn_time)
{
- self.death_time = time + 1; // only retry once a second
+ self.respawn_time = time + 1; // only retry once a second
respawn();
self.impulse = 141;
}
}
else if (self.deadflag == DEAD_RESPAWNING)
{
- if(time > self.death_time)
+ if(time > self.respawn_time)
{
- self.death_time = time + 1; // only retry once a second
+ self.respawn_time = time + 1; // only retry once a second
respawn();
}
}
self.animstate_endtime = oldself.animstate_endtime;
self.animstate_override = oldself.animstate_override;
self.animstate_looping = oldself.animstate_looping;
+ self.dphitcontentsmask = oldself.dphitcontentsmask;
+ self.death_time = oldself.death_time;
self.frame = oldself.frame;
self.pain_finished = oldself.pain_finished;
self.health = oldself.health;
if(!waves)
waves = autocvar_g_respawn_waves;
if(waves)
- self.death_time = ceil((time + sdelay) / waves) * waves;
+ self.respawn_time = ceil((time + sdelay) / waves) * waves;
else
- self.death_time = time + sdelay;
- if((sdelay + waves >= 5.0) && (self.death_time - time > 1.75))
+ self.respawn_time = time + sdelay;
+ if((sdelay + waves >= 5.0) && (self.respawn_time - time > 1.75))
self.respawn_countdown = 10; // first number to count down from is 10
else
self.respawn_countdown = -1; // do not count down
+ self.death_time = time;
if (random() < 0.5)
setanim(self, self.anim_die1, FALSE, TRUE, TRUE);
else
if(!privatesay)
if(source.classname != "player")
{
- if(teamsay || (autocvar_g_chat_nospectators == 1) || (autocvar_g_chat_nospectators == 2 && !inWarmupStage))
- teamsay = -1; // spectators
+ if not(intermission_running)
+ if(teamsay || (autocvar_g_chat_nospectators == 1) || (autocvar_g_chat_nospectators == 2 && !inWarmupStage))
+ teamsay = -1; // spectators
}
if(flood)
if(sourcemsgstr != "" && ret != 0)
{
- if(ret < 0) // fake
+ if(ret < 0) // faked message, because the player is muted
{
sprint(source, sourcemsgstr);
if(sourcecmsgstr != "" && !privatesay)
centerprint(source, sourcecmsgstr);
}
- else if(privatesay)
+ else if(privatesay) // private message, between 2 people only, not sent to server console
{
sprint(source, sourcemsgstr);
sprint(privatesay, msgstr);
if(cmsgstr != "")
centerprint(privatesay, cmsgstr);
}
- else if(teamsay > 0)
+ else if(teamsay > 0) // team message, only sent to team mates
{
sprint(source, sourcemsgstr);
+ //print(msgstr); // send to server console too
if(sourcecmsgstr != "")
centerprint(source, sourcecmsgstr);
FOR_EACH_REALPLAYER(head) if(head.team == source.team)
centerprint(head, cmsgstr);
}
}
- else if(teamsay < 0)
+ else if(teamsay < 0) // spectator message, only sent to spectators
{
sprint(source, sourcemsgstr);
+ //print(msgstr); // send to server console too
FOR_EACH_REALCLIENT(head) if(head.classname != "player")
if(head != source)
sprint(head, msgstr);
}
- else if(sourcemsgstr != msgstr)
+ else if(sourcemsgstr != msgstr) // trimmed/server fixed message, sent to all players
{
sprint(source, sourcemsgstr);
+ //print(msgstr); // send to server console too
FOR_EACH_REALCLIENT(head)
if(head != source)
sprint(head, msgstr);
}
else
- bprint(msgstr);
+ bprint(msgstr); // entirely normal message, sent to all players -- bprint sends to server console too.
}
return ret;
}
else
setattachment(self, self.owner, "bip01 r hand");
-
- // if that didn't find a tag, hide the exterior weapon model
- if (!self.tag_index)
- self.model = "";
}
self.effects = self.owner.effects;
if(sv_pitch_min == sv_pitch_max)
// ==================================
// Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
+// but for 0.5 compat, we need "bans" here as it was replaced... REMOVE IT AFTER 0.6 RELEASE!!!!
#define BAN_COMMANDS(request,arguments,command) \
BAN_COMMAND("ban", BanCommand_ban(request, arguments, command), "Ban an IP address or a range of addresses (like 1.2.3)") \
BAN_COMMAND("banlist", BanCommand_banlist(request), "List all existing bans") \
+ BAN_COMMAND("bans", BanCommand_banlist(request), "") \
BAN_COMMAND("kickban", BanCommand_kickban(request, arguments, command), "Disconnect a client and ban it at the same time") \
BAN_COMMAND("unban", BanCommand_unban(request, arguments), "Remove an existing ban") \
/* nothing */
void BanCommand_macro_help()
{
#define BAN_COMMAND(name,function,description) \
- { print(" ^2", name, "^7: ", description, "\n"); }
+ { if(strtolower(description) != "") { print(" ^2", name, "^7: ", description, "\n"); } }
BAN_COMMANDS(0, 0, "")
#undef BAN_COMMAND
void BanCommand_macro_write_aliases(float fh)
{
#define BAN_COMMAND(name,function,description) \
- { CMD_Write_Alias("qc_cmd_sv", name, description); }
+ { if(strtolower(description) != "") { CMD_Write_Alias("qc_cmd_sv", name, description); } }
BAN_COMMANDS(0, 0, "")
#undef BAN_COMMAND
}
else { print_to(self, "You can't ^2tell^7 a message to yourself."); return; }
}
- else if(strtolower(argv(1)) == "world")
+ else if(argv(1) == "#0")
{
trigger_magicear_processmessage_forallears(self, -1, world, substring(command, argv_start_index(next_token), argv_end_index(-1) - argv_start_index(next_token)));
return;
//.float cnt2;
.float play_time;
+.float respawn_time;
.float death_time;
.float fade_time;
.float fade_rate;
string handicap_output;
string output;
- // health/armor of attacker (person who killed you)
- if(autocvar_sv_fraginfo_stats && (player.health >= 1))
- if((autocvar_sv_fraginfo_stats == 2) || inWarmupStage)
+ if(autocvar_sv_fraginfo && ((autocvar_sv_fraginfo == 2) || inWarmupStage))
+ {
+ // health/armor of attacker (person who killed you)
+ if(autocvar_sv_fraginfo_stats && (player.health >= 1))
health_output = strcat("^7(Health ^1", ftos(rint(player.health)), "^7 / Armor ^2", ftos(rint(player.armorvalue)), "^7)");
-
- // ping display
- if(autocvar_sv_fraginfo_ping)
- ping_output = ((clienttype(player) == CLIENTTYPE_BOT) ? "^2Bot" : strcat("Ping ", ((player.ping >= 150) ? "^1" : "^2"), ftos(rint(player.ping)), "ms"));
- // handicap display
- if(autocvar_sv_fraginfo_handicap)
- {
- if(autocvar_sv_fraginfo_handicap == 2)
- handicap_output = strcat(output, strcat("Handicap ^2", ((player.cvar_cl_handicap <= 1) ? "Off" : ftos(rint(player.cvar_cl_handicap)))));
- else if(player.cvar_cl_handicap) // with _handicap 1, only show this if there actually is a handicap enabled.
- handicap_output = strcat("Handicap ^2", ftos(rint(player.cvar_cl_handicap)));
+ // ping display
+ if(autocvar_sv_fraginfo_ping)
+ ping_output = ((clienttype(player) == CLIENTTYPE_BOT) ? "^2Bot" : strcat("Ping ", ((player.ping >= 150) ? "^1" : "^2"), ftos(rint(player.ping)), "ms"));
+
+ // handicap display
+ if(autocvar_sv_fraginfo_handicap)
+ {
+ if(autocvar_sv_fraginfo_handicap == 2)
+ handicap_output = strcat(output, strcat("Handicap ^2", ((player.cvar_cl_handicap <= 1) ? "Off" : ftos(rint(player.cvar_cl_handicap)))));
+ else if(player.cvar_cl_handicap) // with _handicap 1, only show this if there actually is a handicap enabled.
+ handicap_output = strcat("Handicap ^2", ftos(rint(player.cvar_cl_handicap)));
+ }
+
+ // format the string
+ output = strcat(health_output, (health_output ? ((ping_output || handicap_output) ? " ^7(" : "") : ((ping_output || handicap_output) ? "^7(" : "")),
+ ping_output, (handicap_output ? "^7 / " : ""),
+ handicap_output, ((ping_output || handicap_output) ? "^7)" : ""));
+
+ // add new line to the beginning if there is a message
+ if(output) { output = strcat("\n", output); }
}
- // format the string
- output = strcat(health_output, (health_output ? ((ping_output || handicap_output) ? " ^7(" : "") : ((ping_output || handicap_output) ? "^7(" : "")),
- ping_output, (handicap_output ? "^7 / " : ""),
- handicap_output, ((ping_output || handicap_output) ? "^7)" : ""));
-
- // add new line to the beginning if there is a message
- if(output) { output = strcat("\n", output); }
-
return output;
}
PlayerStats_Event(targ, PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM, 1);
}
- if((autocvar_sv_fraginfo_typefrag) && (targ.BUTTON_CHAT)) {
+ if(targ.BUTTON_CHAT) {
Send_CSQC_KillCenterprint(attacker, s, Obituary_ExtraFragInfo(targ), KILL_TYPEFRAG, MSG_KILL);
Send_CSQC_KillCenterprint(targ, a, Obituary_ExtraFragInfo(attacker), KILL_TYPEFRAGGED, MSG_KILL);
} else {
BADCVAR("pausable");
BADCVAR("sv_allow_fullbright");
BADCVAR("sv_checkforpacketsduringsleep");
+ BADCVAR("sv_fraginfo");
BADCVAR("sv_timeout");
BADPREFIX("sv_timeout_");
BADCVAR("welcome_message_time");
void IntermissionThink()
{
FixIntermissionClient(self);
-
- if( (autocvar_sv_autoscreenshot || self.cvar_cl_autoscreenshot)
+
+ float server_screenshot = (autocvar_sv_autoscreenshot && self.cvar_cl_autoscreenshot);
+ float client_screenshot = (self.cvar_cl_autoscreenshot == 2);
+
+ if( (server_screenshot || client_screenshot)
&& ((self.autoscreenshot > 0) && (time > self.autoscreenshot)) )
{
self.autoscreenshot = -1;
- if(clienttype(self) == CLIENTTYPE_REAL) { stuffcmd(self, sprintf("\nautoscreenshot \"%s\" \"%s\"\n", GetMapname(), strftime(FALSE, "%s"))); }
+ if(clienttype(self) == CLIENTTYPE_REAL) { stuffcmd(self, sprintf("\nscreenshot screenshots/autoscreenshot/%s-%s.jpg; echo \"^5A screenshot has been taken at request of the server.\"", GetMapname(), strftime(FALSE, "%s"))); }
return;
}
void Send_CSQC_Centerprint_Generic(entity e, float id, string s, float duration, float countdown_num)
{
- if (clienttype(e) == CLIENTTYPE_REAL)
+ if ((clienttype(e) == CLIENTTYPE_REAL) && (e.flags & FL_CLIENT))
{
msg_entity = e;
WRITESPECTATABLE_MSG_ONE({
return;
}
+ if(self.model != "")
+ itemmodel = self.model;
+ if(self.item_pickupsound != "")
+ pickupsound = self.item_pickupsound;
+
self.reset = Item_Reset;
// it's a level item
if(self.spawnflags & 1)
tmax_y = tmin_y + 1;
}
- setsize (trigger, tmin, tmax);
+ if(tmin_x > tmax_x)
+ if(tmin_y > tmax_y)
+ if(tmin_z > tmax_z)
+ {
+ setsize (trigger, tmin, tmax);
+ return;
+ }
+
+ // otherwise, something is fishy...
+ remove(trigger);
+ objerror("plat_spawn_inside_trigger: platform has odd size or lip, can't spawn");
}
void plat_hit_top()
self.pos2 = self.origin;
self.pos2_z = self.origin_z - self.height;
- plat_spawn_inside_trigger (); // the "start moving" trigger
-
self.reset = plat_reset;
plat_reset();
+
+ plat_spawn_inside_trigger (); // the "start moving" trigger
}
#else
#ifdef SVQC
.float minstanex_lasthit;
+.float jump_interval;
void W_MinstaNex_Attack (void)
{
}
else if (self.BUTTON_ATCK2)
{
- if (weapon_prepareattack(1, autocvar_g_balance_minstanex_laser_refire))
+ if (self.jump_interval <= time)
+ if (weapon_prepareattack(1, -1))
{
+ // handle refire manually, so that primary and secondary can be fired without conflictions (important for minstagib)
+ self.jump_interval = time + autocvar_g_balance_minstanex_laser_refire * W_WeaponRateFactor();
+
// decrease ammo for the laser?
if(autocvar_g_balance_minstanex_laser_ammo)
W_DecreaseAmmo(ammo_cells, autocvar_g_balance_minstanex_laser_ammo, autocvar_g_balance_minstanex_reload_ammo);