self.cnt = self.switchweapon;
self.weapon = 0;
- self.wish_reload = 0;
-
if(!self.alivetime)
self.alivetime = time;
} else if(self.classname == "observer" || (g_ca && !allowed_to_spawn)) {
WriteByte(MSG_ENTITY, autocvar_g_balance_nex_secondary); // client has to know if it should zoom or not
WriteByte(MSG_ENTITY, autocvar_g_balance_sniperrifle_secondary); // client has to know if it should zoom or not
WriteByte(MSG_ENTITY, serverflags); // client has to know if it should zoom or not
- WriteByte(MSG_ENTITY, autocvar_g_balance_sniperrifle_magazinecapacity); // rifle max bullets
WriteCoord(MSG_ENTITY, autocvar_g_trueaim_minrange);
return TRUE;
}
self.ammo_nails = spectatee.ammo_nails;
self.ammo_rockets = spectatee.ammo_rockets;
self.ammo_fuel = spectatee.ammo_fuel;
+ self.clip_load = spectatee.clip_load;
+ self.clip_size = spectatee.clip_size;
self.effects = spectatee.effects & EFMASK_CHEAP; // eat performance
self.health = spectatee.health;
self.impulse = 0;
void LeaveSpectatorMode()
{
- if(isJoinAllowed()) {
+ if(nJoinAllowed(1)) {
if(!teams_matter || autocvar_g_campaign || autocvar_g_balance_teams || (self.wasplayer && autocvar_g_changeteam_banned) || self.team_forced > 0) {
self.classname = "player";
* Determines whether the player is allowed to join. This depends on cvar
* g_maxplayers, if it isn't used this function always return TRUE, otherwise
* it checks whether the number of currently playing players exceeds g_maxplayers.
- * @return bool TRUE if the player is allowed to join, false otherwise
+ * @return int number of free slots for players, 0 if none
*/
- float isJoinAllowed() {
+ float nJoinAllowed(float includeMe) {
if(self.team_forced < 0)
return FALSE; // forced spectators can never join
+ // TODO simplify this
+ local entity e;
+
+ local float totalClients;
+ FOR_EACH_CLIENT(e)
+ totalClients += 1;
+
if (!autocvar_g_maxplayers)
- return TRUE;
+ return maxclients - totalClients + includeMe;
- local entity e;
local float currentlyPlaying;
- FOR_EACH_REALPLAYER(e) {
- if(e.classname == "player")
- currentlyPlaying += 1;
- }
+ FOR_EACH_REALPLAYER(e)
+ currentlyPlaying += 1;
+
if(currentlyPlaying < autocvar_g_maxplayers)
- return TRUE;
+ return min(maxclients - totalClients + includeMe, autocvar_g_maxplayers - currentlyPlaying);
- return FALSE;
+ return 0;
}
/**
}
target_voicescript_next(self);
+
+ // if a player goes unarmed after holding a loaded weapon, empty his clip size and remove the crosshair ammo ring
+ if(!self.weapon)
+ self.clip_load = self.clip_size = 0;
}
float isInvisibleString(string s)
#define BADPREFIX(p) if(substring(k, 0, strlen(p)) == p) continue
#define BADPRESUFFIX(p,s) if(substring(k, 0, strlen(p)) == p && substring(k, -strlen(s), -1) == s) continue
#define BADCVAR(p) if(k == p) continue
+
+ // general excludes and namespaces for server admin used cvars
+ BADPREFIX("help_"); // PN's server has this listed as changed, let's not rat him out for THAT
+
// internal
BADPREFIX("csqc_");
BADPREFIX("cvar_check_");
BADCVAR("hostname");
BADCVAR("log_file");
BADCVAR("maxplayers");
+ BADCVAR("g_maxplayers");
BADCVAR("minplayers");
BADCVAR("net_address");
BADCVAR("port");
addstat(STAT_FUEL, AS_INT, ammo_fuel);
addstat(STAT_SHOTORG, AS_INT, stat_shotorg);
addstat(STAT_LEADLIMIT, AS_FLOAT, stat_leadlimit);
- addstat(STAT_BULLETS_LOADED, AS_INT, sniperrifle_bulletcounter);
+ addstat(STAT_WEAPON_CLIPLOAD, AS_INT, clip_load);
+ addstat(STAT_WEAPON_CLIPSIZE, AS_INT, clip_size);
addstat(STAT_LAST_PICKUP, AS_FLOAT, last_pickup);
addstat(STAT_NEX_CHARGE, AS_FLOAT, nex_charge);
.entity queuenext;
.entity queueprev;
+// weapon load persistence, for weapons that support reloading
+.float crylink_load;
+
+void W_Crylink_SetAmmoCounter()
+{
+ // set clip_load to the weapon we have switched to, if the gun uses reloading
+ if(!autocvar_g_balance_crylink_reload_ammo)
+ self.clip_load = 0; // also keeps crosshair ammo from displaying
+ else
+ {
+ self.clip_load = self.crylink_load;
+ self.clip_size = autocvar_g_balance_crylink_reload_ammo; // for the crosshair ammo display
+ }
+}
+
+void W_Crylink_ReloadedAndReady()
+{
+ float t;
+
+ // now do the ammo transfer
+ self.clip_load = self.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading
+ while(self.clip_load < autocvar_g_balance_crylink_reload_ammo && self.ammo_cells) // make sure we don't add more ammo than we have
+ {
+ self.clip_load += 1;
+ self.ammo_cells -= 1;
+ }
+ self.crylink_load = self.clip_load;
+
+ t = ATTACK_FINISHED(self) - autocvar_g_balance_crylink_reload_time - 1;
+ ATTACK_FINISHED(self) = t;
+ w_ready();
+}
+
+void W_Crylink_Reload()
+{
+ // return if reloading is disabled for this weapon
+ if(!autocvar_g_balance_crylink_reload_ammo)
+ return;
+
+ if(!W_ReloadCheck(self.ammo_cells, min(autocvar_g_balance_crylink_primary_ammo, autocvar_g_balance_crylink_secondary_ammo)))
+ return;
+
+ float t;
+
+ sound (self, CHAN_WEAPON2, "weapons/reload.wav", VOL_BASE, ATTN_NORM);
+
+ t = max(time, ATTACK_FINISHED(self)) + autocvar_g_balance_crylink_reload_time + 1;
+ ATTACK_FINISHED(self) = t;
+
+ weapon_thinkf(WFRAME_RELOAD, autocvar_g_balance_crylink_reload_time, W_Crylink_ReloadedAndReady);
+
+ self.old_clip_load = self.clip_load;
+ self.clip_load = -1;
+}
+
void W_Crylink_CheckLinks(entity e)
{
float i;
if(e == world)
error("W_Crylink_CheckLinks: entity is world");
+ if(e.classname != "spike")
+ error("W_Crylink_CheckLinks: entity is not a spike");
p = e;
for(i = 0; i < 1000; ++i)
void W_Crylink_Dequeue_Raw(entity own, entity prev, entity me, entity next)
{
+ W_Crylink_CheckLinks(next);
if(me == own.crylink_lastgroup)
own.crylink_lastgroup = ((me == next) ? world : next);
prev.queuenext = next;
next.queueprev = prev;
+ if(me != next)
+ W_Crylink_CheckLinks(next);
}
void W_Crylink_Dequeue(entity e)
// p->velocity -> HUEG away from center
}
+ W_Crylink_CheckLinks(e);
+
return targ_origin;
}
vector forward, right, up;
float maxdmg;
+ // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
- self.ammo_cells = self.ammo_cells - autocvar_g_balance_crylink_primary_ammo;
+ {
+ if(autocvar_g_balance_crylink_reload_ammo)
+ {
+ self.clip_load -= autocvar_g_balance_crylink_primary_ammo;
+ self.crylink_load = self.clip_load;
+ }
+ else
+ self.ammo_cells -= autocvar_g_balance_crylink_primary_ammo;
+ }
maxdmg = autocvar_g_balance_crylink_primary_damage*autocvar_g_balance_crylink_primary_shots;
maxdmg *= 1 + autocvar_g_balance_crylink_primary_bouncedamagefactor * autocvar_g_balance_crylink_primary_bounces;
counter = counter + 1;
}
self.crylink_lastgroup = proj;
+ W_Crylink_CheckLinks(proj);
}
void W_Crylink_Attack2 (void)
local entity proj, prevproj, firstproj;
float maxdmg;
+ // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
- self.ammo_cells = self.ammo_cells - autocvar_g_balance_crylink_secondary_ammo;
+ {
+ if(autocvar_g_balance_crylink_reload_ammo)
+ {
+ self.clip_load -= autocvar_g_balance_crylink_secondary_ammo;
+ self.crylink_load = self.clip_load;
+ }
+ else
+ self.ammo_cells -= autocvar_g_balance_crylink_secondary_ammo;
+ }
maxdmg = autocvar_g_balance_crylink_secondary_damage*autocvar_g_balance_crylink_secondary_shots;
maxdmg *= 1 + autocvar_g_balance_crylink_secondary_bouncedamagefactor * autocvar_g_balance_crylink_secondary_bounces;
float w_crylink(float req)
{
+ float ammo_amount;
if (req == WR_AIM)
{
if (random() < 0.10)
}
else if (req == WR_THINK)
{
- if (self.BUTTON_ATCK)
+ if(autocvar_g_balance_crylink_reload_ammo && self.clip_load < min(autocvar_g_balance_crylink_primary_ammo, autocvar_g_balance_crylink_secondary_ammo)) // forced reload
+ W_Crylink_Reload();
+ else if (self.BUTTON_ATCK)
{
if (!self.crylink_waitrelease)
if (weapon_prepareattack(0, autocvar_g_balance_crylink_primary_refire))
precache_sound ("weapons/crylink_fire.wav");
precache_sound ("weapons/crylink_fire2.wav");
precache_sound ("weapons/crylink_linkjoin.wav");
+ precache_sound ("weapons/reload.wav");
}
else if (req == WR_SETUP)
+ {
weapon_setup(WEP_CRYLINK);
+ W_Crylink_SetAmmoCounter();
+ }
else if (req == WR_CHECKAMMO1)
{
// don't "run out of ammo" and switch weapons while waiting for release
if(self.crylink_lastgroup && self.crylink_waitrelease)
return TRUE;
- return self.ammo_cells >= autocvar_g_balance_crylink_primary_ammo;
+
+ ammo_amount = self.ammo_cells >= autocvar_g_balance_crylink_primary_ammo;
+ ammo_amount += self.crylink_load >= autocvar_g_balance_crylink_primary_ammo;
+ return ammo_amount;
}
else if (req == WR_CHECKAMMO2)
{
// don't "run out of ammo" and switch weapons while waiting for release
if(self.crylink_lastgroup && self.crylink_waitrelease)
return TRUE;
- return self.ammo_cells >= autocvar_g_balance_crylink_secondary_ammo;
+
+ ammo_amount = self.ammo_cells >= autocvar_g_balance_crylink_secondary_ammo;
+ ammo_amount += self.crylink_load >= autocvar_g_balance_crylink_secondary_ammo;
+ return ammo_amount;
+ }
+ else if (req == WR_RESETPLAYER)
+ {
+ // all weapons must be fully loaded when we spawn
+ self.crylink_load = autocvar_g_balance_crylink_reload_ammo;
+ }
+ else if (req == WR_RELOAD)
+ {
+ W_Crylink_Reload();
}
return TRUE;
};