ZIPEXCLUDE ?= -x\!*.pk3 -xr\!\.svn -x\!qcsrc
DIFF ?= diff
-FTEQCCFLAGS_WATERMARK ?= -DWATERMARK='"^1$(shell git describe) TEST BUILD"'
+FTEQCCFLAGS_WATERMARK ?= -DWATERMARK='"^1$(shell git describe) TEST BUILD"' -DCVAR_POPCON
FTEQCCFLAGS ?= -Werror -Wno-Q302 -O3 -Ono-c -Ono-cs $(FTEQCCFLAGS_EXTRA) $(FTEQCCFLAGS_WATERMARK)
FTEQCCFLAGS_PROGS ?=
FTEQCCFLAGS_MENU ?=
set g_balance_hlac_primary_edgedamage 2
set g_balance_hlac_primary_force -100
set g_balance_hlac_primary_radius 100
-set g_balance_hlac_primary_speed 5000
+set g_balance_hlac_primary_speed 15000
set g_balance_hlac_primary_lifetime 3
set g_balance_hlac_primary_refire 0.1
set g_balance_hlac_secondary_edgedamage 3
set g_balance_hlac_secondary_force 100
set g_balance_hlac_secondary_radius 50
-set g_balance_hlac_secondary_speed 9000
+set g_balance_hlac_secondary_speed 15000
set g_balance_hlac_secondary_lifetime 3
set g_balance_hlac_secondary_refire 1
set g_balance_hlac_secondary_animtime 0.7
set g_balance_seeker_flac_speed_z 0
set g_balance_seeker_flac_spread 0.25
-set g_balance_seeker_missile_accel 3000
+set g_balance_seeker_missile_accel 1400
set g_balance_seeker_missile_ammo 2
set g_balance_seeker_missile_animtime 0.3
set g_balance_seeker_missile_count 4
set g_balance_seeker_missile_damage 50
set g_balance_seeker_missile_damageforcescale 2
-set g_balance_seeker_missile_decel 6000
+set g_balance_seeker_missile_decel 1400
set g_balance_seeker_missile_delay 0.25
set g_balance_seeker_missile_edgedamage 10
set g_balance_seeker_missile_force 250
set g_balance_seeker_missile_speed 700
set g_balance_seeker_missile_speed_up 300
set g_balance_seeker_missile_speed_z 0
-set g_balance_seeker_missile_speed_max 1250
+set g_balance_seeker_missile_speed_max 1400
set g_balance_seeker_missile_spread 0
set g_balance_seeker_missile_turnrate 0.65
// server about changes)
alias setreport "set \"$1\" \"$2\" ; sendcvar \"$1\""
+seta cl_firststart "" "how many times the client has been run"
+seta cl_startcount 0 "how many times the client has been run"
+
// detect dedicated server or client
alias "_detect_dedicated_$qport" "${* asis}"
alias "_detect_dedicated_0" ""
seta crosshair_pickup 0.25
seta crosshair_pickup_speed 4
seta crosshair_per_weapon 0 "when 1, each gun will display a different crosshair"
-seta crosshair_color_override 0 "when 1, crosshair_color_* overrides the per-weapon color"
-seta crosshair_color_per_weapon 1 "when 1, each gun will display a different colored crosshair"
+seta crosshair_color_per_weapon 1 "when 1, each gun will display the crosshair with a different color"
seta crosshair_effect_speed -1 "how fast (in seconds) some crosshair effects should take place, 0 = instant, -1 = 2x weapon switch time"
seta crosshair_effect_scalefade 1 "use scaling and fading for crosshair effects"
seta crosshair_hittest 1 "do a crosshair hit evaluation; also, the crosshair is scaled by the given number when aiming at an enemy, and blurred when aiming at a team mate"
set cl_lerpanim_maxdelta_framegroups 0.05 // must be faster than fastest weapon refire
set cl_lerpanim_maxdelta_server 0.1 // must be slower than slowest server controlled anim (e.g. animinfo stuff)
-// player ID
-seta _cl_userid "" "player ID (e.g. for tournaments)"
-
// FIXME workaround for engine bug
sv_gameplayfix_nudgeoutofsolid 0
// to div0: remove this once 5b7ac1706712977bbc0297d2d53294e73574c7cd (svn r9537) is in the stable branch of the engine again
return vercmp_recursive(v1, v2);
}
+
+float u8_strsize(string s)
+{
+ float l, i, c;
+ l = 0;
+ for(i = 0; ; ++i)
+ {
+ c = str2chr(s, i);
+ if(c <= 0)
+ break;
+ ++l;
+ if(c >= 0x80)
+ ++l;
+ if(c >= 0x800)
+ ++l;
+ if(c >= 0x10000)
+ ++l;
+ }
+ return l;
+}
#endif
float vercmp(string v1, string v2);
+
+float u8_strsize(string s);
ATTRIB(InputBox, forbiddenCharacters, string, "")
ATTRIB(InputBox, color, vector, '1 1 1')
ATTRIB(InputBox, colorF, vector, '1 1 1')
- ATTRIB(InputBox, maxLength, float, 255)
+ ATTRIB(InputBox, maxLength, float, 255) // if negative, it counts bytes, not chars
ENDCLASS(InputBox)
void InputBox_Clear_Click(entity btn, entity me);
#endif
for(i = 0; i < strlen(ch); ++i)
if(strstrofs(me.forbiddenCharacters, substring(ch, i, 1), 0) > -1)
return;
- if(strlen(ch) + strlen(me.text) > me.maxLength)
- return;
+ if(me.maxLength > 0)
+ {
+ if(strlen(ch) + strlen(me.text) > me.maxLength)
+ return;
+ }
+ else if(me.maxLength < 0)
+ {
+ if(u8_strsize(ch) + u8_strsize(me.text) > -me.maxLength)
+ return;
+ }
me.setText(me, strcat(substring(me.text, 0, me.cursorPos), ch, substring(me.text, me.cursorPos, strlen(me.text) - me.cursorPos)));
me.cursorPos += strlen(ch);
}
me.TR(me);
me.TD(me, 1, 3.0, box = makeXonoticInputBox(1, "_cl_name"));
box.forbiddenCharacters = "\r\n\\\"$"; // don't care, isn't getting saved
- box.maxLength = 63;
+ box.maxLength = -63; // negativ means encoded length in bytes
label.textEntity = box;
me.TR(me);
me.TD(me, 5, 1, e = makeXonoticColorpicker(box));
if(!_Nex_ExtResponseSystem_Queried)
{
_Nex_ExtResponseSystem_Queried = 1;
- uri_get(sprintf("http://www.xonotic.org/dl/checkupdate.txt?version=%s", uri_escape(cvar_string("g_xonoticversion"))), URI_GET_UPDATENOTIFICATION);
- //crypto_uri_postbuf(sprintf("http://www.xonotic.org/dl/t/checkupdate2.cgi?version=%s", uri_escape(cvar_string("g_xonoticversion"))), URI_GET_UPDATENOTIFICATION, "application/x-www-urlencoded", "hello=world&foo=bar", -1, 0);
+ float startcnt;
+ string uri;
+
+ cvar_set("cl_startcount", ftos(startcnt = cvar("cl_startcount") + 1));
+
+ // for privacy, munge the start count a little
+ startcnt = floor((floor(startcnt / 10) + random()) * 10);
+ uri = sprintf("http://www.xonotic.org/dl/checkupdate.txt?version=%s&cnt=%d", uri_escape(cvar_string("g_xonoticversion")), startcnt);
+
+#ifdef CVAR_POPCON
+ float cvar_handle, popcon_handle;
+ float n, i, j;
+ string k, s;
+ cvar_handle = buf_create();
+ buf_cvarlist(cvar_handle, "", "");
+ n = buf_getsize(cvar_handle);
+ popcon_handle = buf_create();
+ for(i= 0, j = 0; i < n; ++i)
+ {
+ k = bufstr_get(cvar_handle, i);
+ if(!(cvar_type(k) & CVAR_TYPEFLAG_SAVED))
+ continue;
+ s = sprintf("%s=%d", uri_escape(k), cvar_string(k) != cvar_defstring(k));
+ bufstr_set(popcon_handle, j, s);
+ ++j;
+ }
+ buf_del(cvar_handle);
+ uri_postbuf(
+ uri, URI_GET_UPDATENOTIFICATION,
+ "application/x-www-form-urlencoded",
+ "&",
+ popcon_handle
+ );
+ buf_del(popcon_handle);
+#else
+ uri_get(uri, URI_GET_UPDATENOTIFICATION);
+#endif
}
}
float autocvar_g_ctf_shield_force;
float autocvar_g_ctf_shield_max_ratio;
float autocvar_g_ctf_shield_min_negscore;
-float autocvar_g_ctf_win_mode;
float autocvar_g_cts_finish_kill_delay;
float autocvar_g_cts_selfdamage;
float autocvar_g_deathglow;
// dom_player_join_team(self);
// identify the right forced team
- if(PlayerInIDList(self, autocvar_g_forced_team_red))
+ if(autocvar_g_campaign)
+ {
+ if(clienttype(self) == CLIENTTYPE_REAL) // only players, not bots
+ {
+ switch(autocvar_g_campaign_forceteam)
+ {
+ case 1: self.team_forced = COLOR_TEAM1; break;
+ case 2: self.team_forced = COLOR_TEAM2; break;
+ case 3: self.team_forced = COLOR_TEAM3; break;
+ case 4: self.team_forced = COLOR_TEAM4; break;
+ default: self.team_forced = 0;
+ }
+ }
+ }
+ else if(PlayerInIDList(self, autocvar_g_forced_team_red))
self.team_forced = COLOR_TEAM1;
else if(PlayerInIDList(self, autocvar_g_forced_team_blue))
self.team_forced = COLOR_TEAM2;
}
string allvoicesamples;
-float GetPlayerSoundSampleField_notFound;
-float GetPlayerSoundSampleField_fixed;
.string GetVoiceMessageSampleField(string type)
{
GetPlayerSoundSampleField_notFound = 0;
- GetPlayerSoundSampleField_fixed = 0;
switch(type)
{
#define _VOICEMSG(m) case #m: return playersound_##m;
.string GetPlayerSoundSampleField(string type)
{
GetPlayerSoundSampleField_notFound = 0;
- GetPlayerSoundSampleField_fixed = 0;
switch(type)
{
#define _VOICEMSG(m) case #m: return playersound_##m;
field = GetVoiceMessageSampleField(argv(0));
if(GetPlayerSoundSampleField_notFound)
continue;
- if(GetPlayerSoundSampleField_fixed)
- if not(first)
- continue;
if(self.field)
strunzone(self.field);
self.field = strzone(strcat(argv(1), " ", argv(2)));
captureshield_min_negscore = autocvar_g_ctf_shield_min_negscore;
captureshield_max_ratio = autocvar_g_ctf_shield_max_ratio;
captureshield_force = autocvar_g_ctf_shield_force;
+
+
+//#NO AUTOCVARS START
+ g_ctf_win_mode = cvar("g_ctf_win_mode");
+//#NO AUTOCVARS END
};
void ctf_setstatus2(entity flag, float shift)
void GlobalSound(string samplestring, float channel, float voicetype);
void FakeGlobalSound(string samplestring, float channel, float voicetype);
void VoiceMessage(string type, string message);
+float GetPlayerSoundSampleField_notFound;
+.string GetVoiceMessageSampleField(string type)
// autotaunt system
.float cvar_cl_autotaunt;
{
// trigger angles are used for one-way touches. An angle of 0 is assumed
// to mean no restrictions, so use a yaw of 360 instead.
- if (self.movedir == '0 0 0')
- if (self.angles != '0 0 0')
- SetMovedir ();
+ SetMovedir ();
self.solid = SOLID_TRIGGER;
SetBrushEntityModel();
self.movetype = MOVETYPE_NONE;
{
// trigger angles are used for one-way touches. An angle of 0 is assumed
// to mean no restrictions, so use a yaw of 360 instead.
- if (self.movedir == '0 0 0')
- if (self.angles != '0 0 0')
- SetMovedir ();
+ SetMovedir ();
self.solid = SOLID_BSP;
SetBrushEntityModel();
self.movetype = MOVETYPE_NONE; // why was this PUSH? -div0
t.message = self.message;
t.killtarget = self.killtarget;
t.target = self.target;
+ t.target2 = self.target2;
+ t.target3 = self.target3;
+ t.target4 = self.target4;
return;
}
void multi_touch()
{
if not(self.spawnflags & 2)
- {
if not(other.iscreature)
return;
- if(self.team)
- if(self.team == other.team)
+ if(self.team)
+ if((self.spawnflags & 4 == 0) == (self.team != other.team))
return;
- }
// if the trigger has an angles field, check player's facing direction
if (self.movedir != '0 0 0')
// TODO add a way to do looped sounds with sound(); then complete this entity
.float volume, atten;
-void target_speaker_use() {sound(self, CHAN_TRIGGER, self.noise, VOL_BASE * self.volume, self.atten);}
+void target_speaker_use_off();
+void target_speaker_use_activator()
+{
+ if(clienttype(activator) != CLIENTTYPE_REAL)
+ return;
+ string snd;
+ if(substring(self.noise, 0, 1) == "*")
+ {
+ var .string sample;
+ sample = GetVoiceMessageSampleField(substring(self.noise, 1, -1));
+ if(GetPlayerSoundSampleField_notFound)
+ snd = "misc/null.wav";
+ else if(activator.sample == "")
+ snd = "misc/null.wav";
+ else
+ {
+ tokenize_console(activator.sample);
+ float n;
+ n = stof(argv(1));
+ if(n > 0)
+ snd = strcat(argv(0), ftos(floor(random() * n + 1)), ".wav"); // randomization
+ else
+ snd = strcat(argv(0), ".wav"); // randomization
+ }
+ }
+ else
+ snd = self.noise;
+ msg_entity = activator;
+ soundto(MSG_ONE, self, CHAN_TRIGGER, snd, VOL_BASE * self.volume, self.atten);
+}
+void target_speaker_use_on()
+{
+ string snd;
+ if(substring(self.noise, 0, 1) == "*")
+ {
+ var .string sample;
+ sample = GetVoiceMessageSampleField(substring(self.noise, 1, -1));
+ if(GetPlayerSoundSampleField_notFound)
+ snd = "misc/null.wav";
+ else if(activator.sample == "")
+ snd = "misc/null.wav";
+ else
+ {
+ tokenize_console(activator.sample);
+ float n;
+ n = stof(argv(1));
+ if(n > 0)
+ snd = strcat(argv(0), ftos(floor(random() * n + 1)), ".wav"); // randomization
+ else
+ snd = strcat(argv(0), ".wav"); // randomization
+ }
+ }
+ else
+ snd = self.noise;
+ sound(self, CHAN_TRIGGER, snd, VOL_BASE * self.volume, self.atten);
+ if(self.spawnflags & 3)
+ self.use = target_speaker_use_off;
+}
+void target_speaker_use_off()
+{
+ sound(self, CHAN_TRIGGER, "misc/null.wav", VOL_BASE * self.volume, self.atten);
+ self.use = target_speaker_use_on;
+}
+void target_speaker_reset()
+{
+ if(self.spawnflags & 1) // LOOPED_ON
+ {
+ if(self.use == target_speaker_use_on)
+ target_speaker_use_on();
+ }
+ else if(self.spawnflags & 2)
+ {
+ if(self.use == target_speaker_use_off)
+ target_speaker_use_off();
+ }
+}
void spawnfunc_target_speaker()
{
+ // TODO: "*" prefix to sound file name
+ // TODO: wait and random (just, HOW? random is not a field)
if(self.noise)
precache_sound (self.noise);
- IFTARGETED
+
+ if(!self.atten && !(self.spawnflags & 4))
{
- if(!self.atten)
+ IFTARGETED
self.atten = ATTN_NORM;
- else if(self.atten < 0)
- self.atten = 0;
- if(!self.volume)
- self.volume = 1;
- self.use = target_speaker_use;
+ else
+ self.atten = ATTN_STATIC;
+ }
+ else if(self.atten < 0)
+ self.atten = 0;
+
+ if(!self.volume)
+ self.volume = 1;
+
+ IFTARGETED
+ {
+ if(self.spawnflags & 8) // ACTIVATOR
+ self.use = target_speaker_use_activator;
+ else if(self.spawnflags & 1) // LOOPED_ON
+ {
+ target_speaker_use_on();
+ self.reset = target_speaker_reset;
+ }
+ else if(self.spawnflags & 2) // LOOPED_OFF
+ {
+ self.use = target_speaker_use_on;
+ self.reset = target_speaker_reset;
+ }
+ else
+ self.use = target_speaker_use_on;
+ }
+ else if(self.spawnflags & 1) // LOOPED_ON
+ {
+ ambientsound (self.origin, self.noise, VOL_BASE * self.volume, self.atten);
+ remove(self);
+ }
+ else if(self.spawnflags & 2) // LOOPED_OFF
+ {
+ objerror("This sound entity can never be activated");
}
else
{
- if(!self.atten)
- self.atten = ATTN_STATIC;
- else if(self.atten < 0)
- self.atten = 0;
- if(!self.volume)
- self.volume = 1;
+ // Quake/Nexuiz fallback
ambientsound (self.origin, self.noise, VOL_BASE * self.volume, self.atten);
+ remove(self);
}
};
*/
void spawnfunc_trigger_push()
{
- if (self.angles != '0 0 0')
- SetMovedir ();
+ SetMovedir ();
EXACTTRIGGER_INIT;
}
teams_matter = 0;
+ serverflags &~= SERVERFLAG_TEAMPLAY;
}
void default_delayedinit()
VoteReset();
- teams_matter = 0;
-
// make sure only ONE type is selected
ReadGameCvars();
WriteGameCvars();
game = GAME_CTF;
gamemode_name = "Capture the Flag";
ActivateTeamplay();
- if(autocvar_g_campaign)
- g_ctf_win_mode = 2;
- else
- g_ctf_win_mode = autocvar_g_ctf_win_mode;
g_ctf_ignore_frags = autocvar_g_ctf_ignore_frags;
if(g_ctf_win_mode == 2)
{
c1 = c2 = c3 = c4 = -1;
cb1 = cb2 = cb3 = cb4 = 0;
- if(autocvar_g_campaign && for_whom && clienttype(for_whom) == CLIENTTYPE_REAL)
- {
- c1 = 0; // only allow RED team for player joining
- }
- else if(g_onslaught)
+ if(g_onslaught)
{
// onslaught is special
head = findchain(classname, "onslaught_generator");
// FIXME: also find and memorize the lowest-scoring bot on each team (in case players must be shuffled around)
// also remember the lowest-scoring player
- FOR_EACH_PLAYER(head)
+ FOR_EACH_CLIENT(head)
{
+ float t;
+ if(head.classname == "player")
+ t = head.team;
+ else if(head.team_forced > 0)
+ t = head.team_forced; // reserve the spot
+ else
+ continue;
if(head != ignore)// && head.netname != "")
{
value = PlayerValue(head);
bvalue = value;
else
bvalue = 0;
- if(head.team == COLOR_TEAM1)
+ if(t == COLOR_TEAM1)
{
if(c1 >= 0)
{
cb1 = cb1 + bvalue;
}
}
- if(head.team == COLOR_TEAM2)
+ if(t == COLOR_TEAM2)
{
if(c2 >= 0)
{
cb2 = cb2 + bvalue;
}
}
- if(head.team == COLOR_TEAM3)
+ if(t == COLOR_TEAM3)
{
if(c3 >= 0)
{
cb3 = cb3 + bvalue;
}
}
- if(head.team == COLOR_TEAM4)
+ if(t == COLOR_TEAM4)
{
if(c4 >= 0)
{
}
}
}
+
+ // if the player who has a forced team has not joined yet, reserve the spot
+ if(autocvar_g_campaign)
+ {
+ switch(autocvar_g_campaign_forceteam)
+ {
+ case 1: if(c1 == cb1) ++c1; break;
+ case 2: if(c2 == cb2) ++c2; break;
+ case 3: if(c3 == cb3) ++c3; break;
+ case 4: if(c4 == cb4) ++c4; break;
+ }
+ }
}
// returns # of smallest team (1, 2, 3, 4)
// find out what teams are available
CheckAllowedTeams(pl);
- // if we want the player in a certain team for campaign, force him there
- if(autocvar_g_campaign)
- if(clienttype(pl) == CLIENTTYPE_REAL) // only players, not bots
- {
- switch(autocvar_g_campaign_forceteam)
- {
- case 1:
- SetPlayerColors(pl, COLOR_TEAM1 - 1);
- LogTeamchange(pl.playerid, pl.team, 2);
- return COLOR_TEAM1;
- case 2:
- SetPlayerColors(pl, COLOR_TEAM2 - 1);
- LogTeamchange(pl.playerid, pl.team, 2);
- return COLOR_TEAM2;
- case 3:
- SetPlayerColors(pl, COLOR_TEAM3 - 1);
- LogTeamchange(pl.playerid, pl.team, 2);
- return COLOR_TEAM3;
- case 4:
- SetPlayerColors(pl, COLOR_TEAM4 - 1);
- LogTeamchange(pl.playerid, pl.team, 2);
- return COLOR_TEAM4;
- default:
- break;
- }
- }
-
// if we don't care what team he ends up on, put him on whatever team he entered as.
// if he's not on a valid team, then let other code put him on the smallest team
if(!forcebestteam)
W_BallisticBullet_Hit();
}
+ // if we hit "weapclip", bail out
+ //
+ // rationale of this check:
+ //
+ // any shader that is solid, nodraw AND trans is meant to clip weapon
+ // shots and players, but has no other effect!
+ //
+ // if it is not trans, it is caulk and should not have this side effect
+ //
+ // matching shaders:
+ // common/weapclip (intended)
+ // common/noimpact (is supposed to eat projectiles, but is erased farther above)
+ if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NODRAW)
+ if not(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NONSOLID)
+ if not(trace_dphitcontents & DPCONTENTS_OPAQUE)
+ break;
+
density = other.ballistics_density;
if(density == 0)
density = 1;
*3D Art
morphed
+*Concept Art
+LJFHutch
+theShadow
+
*Level Design
FruitieX
MirceaKitsune