float BOT_PICKUP_RATING_MID = 5000;
float BOT_PICKUP_RATING_HIGH = 10000;
- float WEP_TYPE_OTHER = 0x00; // e.g: Hook, Port-o-launch, etc
- float WEP_TYPE_SPLASH = 0x01;
- float WEP_TYPE_HITSCAN = 0x02;
- float WEP_TYPEMASK = 0x0F;
- float WEP_FLAG_CANCLIMB = 0x10;
- float WEP_FLAG_NORMAL = 0x20;
- float WEP_FLAG_HIDDEN = 0x40;
- float WEP_FLAG_RELOADABLE = 0x80;
+ float WEP_TYPE_OTHER = 0x00; // e.g: Hook, Port-o-launch, etc
+ float WEP_TYPE_SPLASH = 0x01;
+ float WEP_TYPE_HITSCAN = 0x02;
+ float WEP_TYPEMASK = 0x0F;
+ float WEP_FLAG_CANCLIMB = 0x10;
+ float WEP_FLAG_NORMAL = 0x20;
+ float WEP_FLAG_HIDDEN = 0x40;
+ float WEP_FLAG_RELOADABLE = 0x80;
+ float WEP_FLAG_SUPERWEAPON = 0x100;
- float IT_UNLIMITED_WEAPON_AMMO = 1;
+ float IT_UNLIMITED_WEAPON_AMMO = 1;
// when this bit is set, using a weapon does not reduce ammo. Checkpoints can give this powerup.
- float IT_UNLIMITED_SUPERWEAPONS = 2;
- // when this bit is set, using a superweapon does not throw it away. Checkpoints can give this powerup.
- float IT_CTF_SHIELDED = 4; // set for the flag shield
- // using jetpack
- float IT_USING_JETPACK = 8; // confirmation that button is pressed
- float IT_JETPACK = 16; // actual item
- float IT_FUEL_REGEN = 32; // fuel regeneration trigger
- float IT_SHELLS = 256;
- float IT_NAILS = 512;
- float IT_ROCKETS = 1024;
- float IT_CELLS = 2048;
- float IT_SUPERWEAPON = 4096;
- float IT_FUEL = 128;
- float IT_STRENGTH = 8192;
- float IT_INVINCIBLE = 16384;
- float IT_HEALTH = 32768;
+ float IT_UNLIMITED_SUPERWEAPONS = 2;
+ // when this bit is set, superweapons don't expire. Checkpoints can give this powerup.
+ float IT_CTF_SHIELDED = 4; // set for the flag shield
+ float IT_USING_JETPACK = 8; // confirmation that button is pressed
+ float IT_JETPACK = 16; // actual item
+ float IT_FUEL_REGEN = 32; // fuel regeneration trigger
+ float IT_SHELLS = 256;
+ float IT_NAILS = 512;
+ float IT_ROCKETS = 1024;
+ float IT_CELLS = 2048;
+ float IT_SUPERWEAPON = 4096;
+ float IT_FUEL = 128;
+ float IT_STRENGTH = 8192;
+ float IT_INVINCIBLE = 16384;
+ float IT_HEALTH = 32768;
// union:
- // for items:
- float IT_KEY1 = 131072;
- float IT_KEY2 = 262144;
- // for players:
- float IT_RED_FLAG_TAKEN = 32768;
- float IT_RED_FLAG_LOST = 65536;
- float IT_RED_FLAG_CARRING = 98304;
- float IT_BLUE_FLAG_TAKEN = 131072;
- float IT_BLUE_FLAG_LOST = 262144;
- float IT_BLUE_FLAG_CARRING = 393216;
+ // for items:
+ float IT_KEY1 = 131072;
+ float IT_KEY2 = 262144;
+ // for players:
+ float IT_RED_FLAG_TAKEN = 32768;
+ float IT_RED_FLAG_LOST = 65536;
+ float IT_RED_FLAG_CARRYING = 98304;
+ float IT_BLUE_FLAG_TAKEN = 131072;
+ float IT_BLUE_FLAG_LOST = 262144;
+ float IT_BLUE_FLAG_CARRYING = 393216;
// end
- float IT_5HP = 524288;
- float IT_25HP = 1048576;
- float IT_ARMOR_SHARD = 2097152;
- float IT_ARMOR = 4194304;
+ float IT_5HP = 524288;
+ float IT_25HP = 1048576;
+ float IT_ARMOR_SHARD = 2097152;
+ float IT_ARMOR = 4194304;
- float IT_AMMO = 8064; // IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS | IT_SUPERWEAPON | IT_FUEL;
- float IT_PICKUPMASK = 51; // IT_FUEL_REGEN | IT_JETPACK | IT_UNLIMITED_AMMO; // strength and invincible are handled separately
- float IT_UNLIMITED_AMMO = 3; // IT_UNLIMITED_SUPERWEAPONS | IT_UNLIMITED_WEAPON_AMMO;
+ float IT_AMMO = 3968; // IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS | IT_FUEL;
+ float IT_PICKUPMASK = 51; // IT_FUEL_REGEN | IT_JETPACK | IT_UNLIMITED_AMMO; // strength and invincible are handled separately
+ float IT_UNLIMITED_AMMO = 3; // IT_UNLIMITED_SUPERWEAPONS | IT_UNLIMITED_WEAPON_AMMO;
float AMMO_COUNT = 4; // amount of ammo types to show in the inventory panel
float WEP_LAST;
#define WEP_MAXCOUNT 24
float WEPBIT_ALL;
+ float WEPBIT_SUPERWEAPONS;
#define REGISTER_WEAPON_2(id,bit,func,ammotype,i,weapontype,pickupbasevalue,modelname,shortname,wname) \
float id; \
float bit; \
{ \
WEP_LAST = (id = WEP_FIRST + WEP_COUNT); \
WEPBIT_ALL |= (bit = power2of(WEP_COUNT)); \
+ WEPBIT_SUPERWEAPONS |= (bit = power2of(WEP_COUNT)) * !!(weapontype & WEP_FLAG_SUPERWEAPON); \
++WEP_COUNT; \
register_weapon(id,func,ammotype,i,weapontype,pickupbasevalue,modelname,shortname,wname); \
} \
entity spawnqueue_first;
entity spawnqueue_last;
entity champion;
- string champion_name;
float warmup;
- float ca_players;
- float required_ca_players;
+ float ca_teams_ok;
.float caplayer;
void PutObserverInServer();
void PutClientInServer();
-void(entity e) ReturnFlag;
+void ctf_RespawnFlag(entity); // FIXCTF
void dom_controlpoint_setup();
void onslaught_generator_reset();
void onslaught_controlpoint_reset();
float redalive, bluealive, yellowalive, pinkalive;
float totalalive;
.float redalive_stat, bluealive_stat, yellowalive_stat, pinkalive_stat;
- float redspawned, bluespawned, yellowspawned, pinkspawned;
- float totalspawned;
+ float red_players, blue_players, yellow_players, pink_players;
+ float total_players;
/**
* Resets the state of all clients, items, flags, runes, keys, weapons, waypoints, ... of the map.
}
if(g_keyhunt)
- kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_round+(game_starttime - time), "", kh_StartRound);
+ kh_Controller_SetThink_NoMsg(autocvar_g_balance_keyhunt_delay_round+(game_starttime - time), kh_StartRound);
if(g_arena)
if(champion && champion.classname == "player" && player_count > 1)
void Arena_Warmup()
{
float f;
- string msg;
entity e;
if((!g_arena && !g_ca && !g_freezetag) || (g_arena && !arena_roundbased) || (time < game_starttime))
return;
f = ceil(warmup - time);
- if(f > 0)
- champion = world; // this is done because a if(champion) will not execute if champion = world
allowed_to_spawn = 0;
if(inWarmupStage)
allowed_to_spawn = 1;
- if(ca_players < required_ca_players)
+ if(g_ca && !ca_teams_ok)
allowed_to_spawn = 1;
- msg = NEWLINES;
if(time < warmup && !inWarmupStage)
{
if (g_ca)
allowed_to_spawn = 1;
if(champion && g_arena)
- msg = strcat("The Champion is ", champion_name, "^7\n");
- //centerprint(self, strcat(msg, "The Champion is ", champion.netname, "^7\n"));
+ {
+ FOR_EACH_PLAYER(e)
+ centerprint(e, strcat("The Champion is ", champion.netname));
+ }
if(f != roundStartTime_prev) {
- msg = strcat(msg, "Round will start in ", ftos(f),"\n");
- //centerprint(self, strcat("Round will start in ", ftos(f),"\n"));
roundStartTime_prev = f;
if(f == 5)
Announce("prepareforbattle");
else if(f == 1)
Announce("1");
- FOR_EACH_PLAYER(e)
- centerprint(e, msg);
+ FOR_EACH_PLAYER(e)
+ Send_CSQC_Centerprint_Generic(e, CPID_ROUND_STARTING, "Round will start in %d", 1, f);
}
if (g_arena) {
self.movement = '0 0 0';
}
}
-
else if(f > -1 && f != roundStartTime_prev)
{
roundStartTime_prev = f;
Announce("begin");
- centerprint(self, "^1Begin!\n");
+ FOR_EACH_PLAYER(e)
+ Send_CSQC_Centerprint_Generic(e, CPID_ROUND_STARTING, "^1Begin!", 1, 0);
if(g_ca) {
- ca_players = 0;
+ float start_red_ca_players, start_blue_ca_players;
- FOR_EACH_PLAYER(e)
- ca_players += 1;
+ FOR_EACH_PLAYER(e) {
+ if (e.team == COLOR_TEAM1)
+ start_red_ca_players += 1;
+ else if (e.team == COLOR_TEAM2)
+ start_blue_ca_players += 1;
+ }
+ // teams are ok if there's at least 1 player in each team
+ ca_teams_ok = (start_red_ca_players && start_blue_ca_players);
}
if(self.classname == "player" && self.health > 0 && self.movetype == MOVETYPE_NONE)
self.movetype = MOVETYPE_WALK;
+
}
+
+ // clear champion to avoid centerprinting again the champion msg
+ if (champion)
+ champion = world;
}
- void count_spawned_players()
+ void count_players()
{
- // TODO fix "*spawned" name, it should rather be "*players" or so
- // not doing this now to prevent merge hell with Tag
- // fix after merging with Tag
-
// count amount of players in each team
- totalspawned = redspawned = bluespawned = yellowspawned = pinkspawned = 0;
+ total_players = red_players = blue_players = yellow_players = pink_players = 0;
FOR_EACH_PLAYER(self) {
if (self.team == COLOR_TEAM1)
{
- redspawned += 1;
- totalspawned += 1;
+ red_players += 1;
+ total_players += 1;
}
else if (self.team == COLOR_TEAM2)
{
- bluespawned += 1;
- totalspawned += 1;
+ blue_players += 1;
+ total_players += 1;
}
else if (self.team == COLOR_TEAM3)
{
- yellowspawned += 1;
- totalspawned += 1;
+ yellow_players += 1;
+ total_players += 1;
}
else if (self.team == COLOR_TEAM4)
{
- pinkspawned += 1;
- totalspawned += 1;
+ pink_players += 1;
+ total_players += 1;
}
}
}
*
* Gets called in StartFrame()
*/
+ float warntime;
void Spawnqueue_Check()
{
- count_spawned_players();
+ count_players();
if(g_ca || g_freezetag) // we want to perform this before the return block below (CA)...
{
count_alive_players();
return;
if(g_ca) {
- required_ca_players = max(2, fabs(autocvar_bot_vs_human + 1));
-
- if(ca_players < required_ca_players && (redspawned && bluespawned)) {
+ if(!ca_teams_ok && (red_players && blue_players)) {
reset_map(TRUE);
}
- else if(ca_players < required_ca_players) {
- FOR_EACH_PLAYER(self)
- centerprint(self, strcat("^1Need at least 1 player in each team to play CA", "^7\n"));
+ else if(!ca_teams_ok) {
+ if (time > warntime)
+ {
+ FOR_EACH_PLAYER(self)
+ Send_CSQC_Centerprint_Generic(self, CPID_ROUND_STARTING, "^1Need at least 1 player in each team to play CA", 2, 0);
+ warntime = time + 1;
+ }
return;
}
else if(!next_round) {
- if((redspawned && !bluespawned) || (bluespawned && !redspawned)) {
+ if((red_players && !blue_players) || (blue_players && !red_players)) {
next_round = time + 5;
- champion = find(world, classname, "player");
- if(champion_name)
- strunzone(champion_name);
- champion_name = strzone(champion.netname);
}
- else if((!redspawned && !bluespawned) || time - warmup > autocvar_g_ca_round_timelimit) {
- FOR_EACH_CLIENT(self) centerprint(self, strcat("^7Round tied.", "^7\n"));
+ else if((!red_players && !blue_players) || time - warmup > autocvar_g_ca_round_timelimit) {
+ FOR_EACH_CLIENT(self) centerprint(self, "^7Round tied");
next_round = time + 5;
}
if(redalive && !bluealive)
{
play2all("ctf/red_capture.wav");
- FOR_EACH_CLIENT(self) centerprint(self, "^1 RED ^7team wins the round.\n");
+ FOR_EACH_CLIENT(self) centerprint(self, "^1RED ^7team wins the round");
TeamScore_AddToTeam(COLOR_TEAM1, ST_SCORE, +1);
stopalivecheck = TRUE;
}
else if(bluealive && !redalive)
{
play2all("ctf/blue_capture.wav");
- FOR_EACH_CLIENT(self) centerprint(self, "^4 BLUE ^7team wins the round.\n");
+ FOR_EACH_CLIENT(self) centerprint(self, "^4BLUE ^7team wins the round");
TeamScore_AddToTeam(COLOR_TEAM2, ST_SCORE, +1);
stopalivecheck = TRUE;
}
+ float autocvar__notarget;
+ float autocvar__independent_players;
float autocvar__campaign_index;
string autocvar__campaign_name;
float autocvar__sv_init;
float autocvar_bot_wander_enable;
float autocvar_captureleadlimit_override;
#define autocvar_capturelimit_override cvar("capturelimit_override")
- float autocvar_deathmatch_force_teamplay;
#define autocvar_developer cvar("developer")
float autocvar_developer_fteqccbugs;
float autocvar_ekg;
float autocvar_g_arena_maxspawned;
float autocvar_g_arena_point_leadlimit;
float autocvar_g_arena_point_limit;
- float autocvar_g_arena_powerups;
float autocvar_g_arena_roundbased;
float autocvar_g_arena_warmup;
float autocvar_g_assault;
float autocvar_g_balance_rifle_reload_ammo;
float autocvar_g_balance_rifle_reload_time;
float autocvar_g_balance_cloaked_alpha;
+ float autocvar_g_balance_contents_damagerate;
+ float autocvar_g_balance_contents_drowndelay;
+ float autocvar_g_balance_contents_playerdamage_drowning;
+ float autocvar_g_balance_contents_playerdamage_lava;
+ float autocvar_g_balance_contents_playerdamage_slime;
+ float autocvar_g_balance_contents_projectiledamage;
float autocvar_g_balance_crylink_primary_ammo;
float autocvar_g_balance_crylink_primary_animtime;
float autocvar_g_balance_crylink_primary_bouncedamagefactor;
float autocvar_g_balance_electro_combo_force;
float autocvar_g_balance_electro_combo_radius;
float autocvar_g_balance_electro_combo_speed;
+ float autocvar_g_balance_electro_combo_safeammocheck;
float autocvar_g_balance_electro_lightning;
float autocvar_g_balance_electro_primary_ammo;
float autocvar_g_balance_electro_primary_animtime;
float autocvar_g_balance_electro_secondary_count;
float autocvar_g_balance_electro_secondary_damage;
float autocvar_g_balance_electro_secondary_damageforcescale;
+ float autocvar_g_balance_electro_secondary_damagedbycontents;
float autocvar_g_balance_electro_secondary_edgedamage;
float autocvar_g_balance_electro_secondary_force;
float autocvar_g_balance_electro_secondary_health;
float autocvar_g_balance_falldamage_factor;
float autocvar_g_balance_falldamage_maxdamage;
float autocvar_g_balance_falldamage_minspeed;
- float autocvar_g_balance_fireball_primary_ammo;
float autocvar_g_balance_fireball_primary_animtime;
float autocvar_g_balance_fireball_primary_bfgdamage;
float autocvar_g_balance_fireball_primary_bfgforce;
float autocvar_g_balance_fireball_primary_refire;
float autocvar_g_balance_fireball_primary_refire2;
float autocvar_g_balance_fireball_primary_speed;
- float autocvar_g_balance_fireball_secondary_ammo;
float autocvar_g_balance_fireball_secondary_animtime;
float autocvar_g_balance_fireball_secondary_damage;
float autocvar_g_balance_fireball_secondary_damageforcescale;
float autocvar_g_balance_fireball_secondary_refire;
float autocvar_g_balance_fireball_secondary_speed;
float autocvar_g_balance_fireball_secondary_speed_up;
- float autocvar_g_balance_fireball_reload_ammo;
- float autocvar_g_balance_fireball_reload_time;
float autocvar_g_balance_firetransfer_damage;
float autocvar_g_balance_firetransfer_time;
float autocvar_g_balance_fuel_limit;
float autocvar_g_balance_grapplehook_speed_fly;
float autocvar_g_balance_grapplehook_speed_pull;
float autocvar_g_balance_grapplehook_stretch;
+ float autocvar_g_balance_grapplehook_damagedbycontents;
float autocvar_g_balance_grenadelauncher_bouncefactor;
float autocvar_g_balance_grenadelauncher_bouncestop;
float autocvar_g_balance_grenadelauncher_primary_ammo;
float autocvar_g_balance_hagar_primary_damage;
float autocvar_g_balance_hagar_primary_edgedamage;
float autocvar_g_balance_hagar_primary_force;
+ float autocvar_g_balance_hagar_primary_health;
+ float autocvar_g_balance_hagar_primary_damageforcescale;
float autocvar_g_balance_hagar_primary_lifetime;
float autocvar_g_balance_hagar_primary_radius;
float autocvar_g_balance_hagar_primary_refire;
float autocvar_g_balance_hagar_secondary;
float autocvar_g_balance_hagar_secondary_load;
float autocvar_g_balance_hagar_secondary_load_speed;
+ float autocvar_g_balance_hagar_secondary_load_spread;
+ float autocvar_g_balance_hagar_secondary_load_spread_bias;
float autocvar_g_balance_hagar_secondary_load_max;
float autocvar_g_balance_hagar_secondary_load_hold;
float autocvar_g_balance_hagar_secondary_load_releasedeath;
float autocvar_g_balance_hagar_secondary_load_abort;
+ float autocvar_g_balance_hagar_secondary_load_linkexplode;
+ float autocvar_g_balance_hagar_secondary_load_animtime;
float autocvar_g_balance_hagar_secondary_ammo;
float autocvar_g_balance_hagar_secondary_damage;
float autocvar_g_balance_hagar_secondary_edgedamage;
float autocvar_g_balance_hagar_secondary_force;
+ float autocvar_g_balance_hagar_secondary_health;
+ float autocvar_g_balance_hagar_secondary_damageforcescale;
float autocvar_g_balance_hagar_secondary_lifetime_min;
float autocvar_g_balance_hagar_secondary_lifetime_rand;
float autocvar_g_balance_hagar_secondary_radius;
float autocvar_g_balance_hagar_secondary_refire;
+ float autocvar_g_balance_hagar_secondary_speed;
+ float autocvar_g_balance_hagar_secondary_spread;
float autocvar_g_balance_hagar_reload_ammo;
float autocvar_g_balance_hagar_reload_time;
float autocvar_g_balance_health_limit;
float autocvar_g_balance_hook_secondary_radius;
float autocvar_g_balance_hook_secondary_refire;
float autocvar_g_balance_hook_secondary_speed;
+ float autocvar_g_balance_hook_secondary_health;
+ float autocvar_g_balance_hook_secondary_damageforcescale;
float autocvar_g_balance_keyhunt_damageforcescale;
float autocvar_g_balance_keyhunt_delay_collect;
float autocvar_g_balance_keyhunt_delay_return;
float autocvar_g_balance_minelayer_reload_time;
float autocvar_g_balance_minstanex_ammo;
float autocvar_g_balance_minstanex_laser_ammo;
+ float autocvar_g_balance_minstanex_laser_animtime;
+ float autocvar_g_balance_minstanex_laser_refire;
float autocvar_g_balance_minstanex_animtime;
float autocvar_g_balance_minstanex_refire;
float autocvar_g_balance_minstanex_reload_ammo;
float autocvar_g_balance_porto_primary_lifetime;
float autocvar_g_balance_porto_primary_refire;
float autocvar_g_balance_porto_primary_speed;
+ float autocvar_g_balance_porto_secondary;
+ float autocvar_g_balance_porto_secondary_animtime;
+ float autocvar_g_balance_porto_secondary_lifetime;
+ float autocvar_g_balance_porto_secondary_refire;
+ float autocvar_g_balance_porto_secondary_speed;
float autocvar_g_balance_powerup_invincible_takedamage;
float autocvar_g_balance_powerup_invincible_time;
float autocvar_g_balance_powerup_strength_damage;
float autocvar_g_balance_powerup_strength_selfdamage;
float autocvar_g_balance_powerup_strength_selfforce;
float autocvar_g_balance_powerup_strength_time;
- float autocvar_g_balance_powerup_timer;
+ float autocvar_g_balance_superweapons_time;
float autocvar_g_balance_rocketlauncher_ammo;
float autocvar_g_balance_rocketlauncher_animtime;
float autocvar_g_balance_rocketlauncher_damage;
float autocvar_g_balance_shotgun_secondary_force;
float autocvar_g_balance_shotgun_secondary_melee_delay;
float autocvar_g_balance_shotgun_secondary_melee_range;
- float autocvar_g_balance_shotgun_secondary_melee_swing;
+ float autocvar_g_balance_shotgun_secondary_melee_swing_side;
+ float autocvar_g_balance_shotgun_secondary_melee_swing_up;
float autocvar_g_balance_shotgun_secondary_melee_time;
+ float autocvar_g_balance_shotgun_secondary_melee_traces;
float autocvar_g_balance_shotgun_secondary_melee_no_doubleslap;
+ float autocvar_g_balance_shotgun_secondary_melee_nonplayerdamage;
+ float autocvar_g_balance_shotgun_secondary_melee_multihit;
float autocvar_g_balance_shotgun_secondary_refire;
float autocvar_g_balance_shotgun_reload_ammo;
float autocvar_g_balance_shotgun_reload_time;
float autocvar_g_balance_uzi_first;
float autocvar_g_balance_uzi_first_ammo;
float autocvar_g_balance_uzi_first_damage;
+ float autocvar_g_balance_uzi_first_headshotaddeddamage;
float autocvar_g_balance_uzi_first_force;
float autocvar_g_balance_uzi_first_refire;
float autocvar_g_balance_uzi_first_spread;
float autocvar_g_balance_uzi_spread_min;
float autocvar_g_balance_uzi_sustained_ammo;
float autocvar_g_balance_uzi_sustained_damage;
+ float autocvar_g_balance_uzi_sustained_headshotaddeddamage;
float autocvar_g_balance_uzi_sustained_force;
float autocvar_g_balance_uzi_sustained_refire;
float autocvar_g_balance_uzi_sustained_spread;
float autocvar_g_ca_point_leadlimit;
float autocvar_g_ca_point_limit;
float autocvar_g_ca_round_timelimit;
+ float autocvar_g_ca_spectate_enemies;
float autocvar_g_ca_warmup;
float autocvar_g_campaign;
- float autocvar_g_campaign_forceteam;
+ #define autocvar_g_campaign_forceteam cvar("g_campaign_forceteam")
float autocvar_g_campaign_skill;
float autocvar_g_casings;
float autocvar_g_changeteam_banned;
float autocvar_g_chat_flood_spl_tell;
float autocvar_g_chat_nospectators;
float autocvar_g_chat_teamcolors;
+float autocvar_g_ctf_allow_drop;
float autocvar_g_ctf_captimerecord_always;
- float autocvar_g_ctf_capture_leadlimit;
- float autocvar_g_ctf_capture_limit;
float autocvar_g_ctf_dynamiclights;
string autocvar_g_ctf_flag_blue_model;
float autocvar_g_ctf_flag_blue_skin;
float autocvar_g_ctf_flag_capture_effects;
float autocvar_g_ctf_flag_glowtrails;
float autocvar_g_ctf_flag_pickup_effects;
+float autocvar_g_ctf_flag_pickup_verbosename;
string autocvar_g_ctf_flag_red_model;
float autocvar_g_ctf_flag_red_skin;
float autocvar_g_ctf_flag_returntime;
float autocvar_g_ctf_shield_min_negscore;
float autocvar_g_cts_finish_kill_delay;
float autocvar_g_cts_selfdamage;
- float autocvar_g_deathglow;
float autocvar_g_debug_bot_commands;
float autocvar_g_domination_default_teams;
float autocvar_g_domination_disable_frags;
float autocvar_g_minstagib_speed_highspeed;
#define autocvar_g_mirrordamage cvar("g_mirrordamage")
#define autocvar_g_mirrordamage_virtual cvar("g_mirrordamage_virtual")
- float autocvar_g_monster_zombie_attack_run_damage;
- float autocvar_g_monster_zombie_attack_run_delay;
- float autocvar_g_monster_zombie_attack_run_force;
- float autocvar_g_monster_zombie_attack_run_hitrange;
- float autocvar_g_monster_zombie_attack_run_range;
- float autocvar_g_monster_zombie_attack_stand_damage;
- float autocvar_g_monster_zombie_attack_stand_delay;
- float autocvar_g_monster_zombie_attack_stand_force;
- float autocvar_g_monster_zombie_attack_stand_range;
- float autocvar_g_monster_zombie_health;
- float autocvar_g_monster_zombie_idle_timer_max;
- float autocvar_g_monster_zombie_idle_timer_min;
- float autocvar_g_monster_zombie_movespeed;
- float autocvar_g_monster_zombie_respawntime;
- float autocvar_g_monster_zombie_stopspeed;
- float autocvar_g_monster_zombie_targetrange;
- float autocvar_g_monster_zombie_turnspeed;
- float autocvar_g_monsters;
+
var float autocvar_g_movement_highspeed = 1;
float autocvar_g_multijump;
float autocvar_g_multijump_add;
float autocvar_g_player_brightness;
float autocvar_g_playerclip_collisions;
string autocvar_g_playerstats_uri;
- float autocvar_g_playerstats_debug;
- float autocvar_g_powerup_shield;
- float autocvar_g_powerup_strength;
- float autocvar_g_powerup_superhealth;
+ float autocvar_g_powerups;
+ float autocvar_g_projectiles_damage;
float autocvar_g_projectiles_newton_style;
float autocvar_g_projectiles_newton_style_2_maxfactor;
float autocvar_g_projectiles_newton_style_2_minfactor;
string autocvar_g_shootfromfixedorigin;
float autocvar_g_showweaponspawns;
float autocvar_g_spawn_furthest;
+ float autocvar_g_spawn_useallspawns;
float autocvar_g_spawnpoints_auto_move_out_of_solid;
#define autocvar_g_spawnshieldtime cvar("g_spawnshieldtime")
float autocvar_g_spawnsound;
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_waypointsprite_deadlifetime;
- float autocvar_g_waypointsprite_deployed_lifetime;
- float autocvar_g_waypointsprite_limitedrange;
float autocvar_g_weapon_charge_colormod_blue_full;
float autocvar_g_weapon_charge_colormod_blue_half;
float autocvar_g_weapon_charge_colormod_green_full;
float autocvar_g_weapon_throwable;
#define autocvar_g_weaponarena cvar_string("g_weaponarena")
string autocvar_g_xonoticversion;
- float autocvar_gamecfg;
float autocvar_gameversion;
float autocvar_gameversion_min;
float autocvar_gameversion_max;
float autocvar_r_showbboxes;
float autocvar_rescan_pending;
float autocvar_samelevel;
+ string autocvar_sessionid;
#define autocvar_skill cvar("skill")
float autocvar_skill_auto;
#define autocvar_slowmo cvar("slowmo")
float autocvar_snd_soundradius;
float autocvar_spawn_debug;
- float autocvar_spawn_debugview;
float autocvar_speedmeter;
float autocvar_sv_accelerate;
var float autocvar_sv_accuracy_data_share = 1;
float autocvar_sv_airstrafeaccelerate;
float autocvar_sv_autoscreenshot;
float autocvar_sv_cheats;
+ float autocvar_sv_clientcommand_antispam_time;
+ float autocvar_sv_clientcommand_antispam_count;
float autocvar_sv_curl_serverpackages_auto;
float autocvar_sv_db_saveasdump;
float autocvar_sv_defaultcharacter;
string autocvar_sv_eventlog_files_nameprefix;
string autocvar_sv_eventlog_files_namesuffix;
float autocvar_sv_eventlog_files_timestamps;
- float autocvar_sv_fragmessage_information_handicap;
- float autocvar_sv_fragmessage_information_ping;
- float autocvar_sv_fragmessage_information_stats;
- float autocvar_sv_fragmessage_information_typefrag;
+ float autocvar_sv_fraginfo;
+ float autocvar_sv_fraginfo_handicap;
+ float autocvar_sv_fraginfo_ping;
+ float autocvar_sv_fraginfo_stats;
float autocvar_sv_friction;
float autocvar_sv_friction_on_land;
float autocvar_sv_gameplayfix_q2airaccelerate;
float autocvar_sv_maxairstrafespeed;
float autocvar_sv_maxspeed;
string autocvar_sv_motd;
- string autocvar_sv_player_crouch_maxs;
- string autocvar_sv_player_crouch_mins;
- string autocvar_sv_player_crouch_viewoffset;
- string autocvar_sv_player_headsize;
- string autocvar_sv_player_maxs;
- string autocvar_sv_player_mins;
- string autocvar_sv_player_viewoffset;
+ float autocvar_sv_player_jumpanim_minfall;
float autocvar_sv_precacheplayermodels;
float autocvar_sv_precacheweapons;
float autocvar_sv_q3acompat_machineshotgunswap;
- float autocvar_sv_qcweaponanimation;
float autocvar_sv_ready_restart;
float autocvar_sv_ready_restart_after_countdown;
float autocvar_sv_ready_restart_repeatable;
float autocvar_sv_servermodelsonly;
float autocvar_sv_spectate;
float autocvar_sv_spectator_speed_multiplier;
+ float autocvar_sv_status_privacy;
float autocvar_sv_stepheight;
float autocvar_sv_stopspeed;
float autocvar_sv_strengthsound_antispam_refire_threshold;
float autocvar_sv_vote_change;
string autocvar_sv_vote_commands;
float autocvar_sv_vote_majority_factor;
+ float autocvar_sv_vote_majority_factor_of_voted;
float autocvar_sv_vote_master;
+ float autocvar_sv_vote_master_callable;
string autocvar_sv_vote_master_commands;
string autocvar_sv_vote_master_password;
+ float autocvar_sv_vote_master_playerlimit;
+ float autocvar_sv_vote_no_stops_vote;
float autocvar_sv_vote_nospectators;
string autocvar_sv_vote_only_commands;
float autocvar_sv_vote_override_mostrecent;
- float autocvar_sv_vote_simple_majority_factor;
float autocvar_sv_vote_singlecount;
float autocvar_sv_vote_stop;
float autocvar_sv_vote_timeout;
float autocvar_sv_warsowbunny_backtosideratio;
float autocvar_sv_warsowbunny_topspeed;
float autocvar_sv_warsowbunny_turnaccel;
+ float autocvar_sv_waypointsprite_deadlifetime;
+ float autocvar_sv_waypointsprite_deployed_lifetime;
+ float autocvar_sv_waypointsprite_limitedrange;
string autocvar_sv_weaponstats_file;
float autocvar_sv_gibhealth;
float autocvar_sys_ticrate;
float autocvar_sv_gameplayfix_gravityunaffectedbyticrate;
float autocvar_g_trueaim_minrange;
float autocvar_g_debug_defaultsounds;
+ float autocvar_g_loituma;
+ float autocvar_g_grab_range;
+ float autocvar_g_sandbox_info;
+ float autocvar_g_sandbox_readonly;
+ string autocvar_g_sandbox_storage_name;
+ float autocvar_g_sandbox_storage_autosave;
+ float autocvar_g_sandbox_storage_autoload;
+ float autocvar_g_sandbox_editor_flood;
+ float autocvar_g_sandbox_editor_maxobjects;
+ float autocvar_g_sandbox_editor_free;
+ float autocvar_g_sandbox_editor_distance_spawn;
+ float autocvar_g_sandbox_editor_distance_edit;
+ float autocvar_g_sandbox_object_scale_min;
+ float autocvar_g_sandbox_object_scale_max;
+ float autocvar_g_sandbox_object_material_velocity_min;
+ float autocvar_g_sandbox_object_material_velocity_factor;
+ float autocvar_g_max_info_autoscreenshot;
.float havocbot_cantfindflag;
.float havocbot_role_timeout;
.entity ctf_worldflagnext;
-.entity basewaypoint;
+.entity bot_basewaypoint;
entity ctf_worldflaglist;
vector havocbot_ctf_middlepoint;
f = f.ctf_worldflagnext;
}
return world;
- };
+ }
entity havocbot_ctf_find_enemy_flag(entity bot)
{
f = f.ctf_worldflagnext;
}
return world;
- };
+ }
float havocbot_ctf_teamcount(entity bot, vector org, float radius)
{
}
return c;
- };
+ }
void havocbot_goalrating_ctf_ourflag(float ratingscale)
{
- local entity head;
+ entity head;
head = ctf_worldflaglist;
while (head)
{
}
if (head)
navigation_routerating(head, ratingscale, 10000);
- };
+ }
void havocbot_goalrating_ctf_ourbase(float ratingscale)
{
- local entity head;
+ entity head;
head = ctf_worldflaglist;
while (head)
{
if not(head)
return;
- navigation_routerating(head.basewaypoint, ratingscale, 10000);
+ navigation_routerating(head.bot_basewaypoint, ratingscale, 10000);
- };
+ }
void havocbot_goalrating_ctf_enemyflag(float ratingscale)
{
- local entity head;
+ entity head;
head = ctf_worldflaglist;
while (head)
{
}
if (head)
navigation_routerating(head, ratingscale, 10000);
- };
+ }
void havocbot_goalrating_ctf_enemybase(float ratingscale)
{
return;
}
- local entity head;
+ entity head;
head = havocbot_ctf_find_enemy_flag(self);
if not(head)
return;
- navigation_routerating(head.basewaypoint, ratingscale, 10000);
+ navigation_routerating(head.bot_basewaypoint, ratingscale, 10000);
- };
+ }
void havocbot_goalrating_ctf_ourstolenflag(float ratingscale)
{
- local entity mf;
+ entity mf;
mf = havocbot_ctf_find_flag(self);
if(mf.cnt == FLAG_BASE)
return;
- navigation_routerating(mf, ratingscale, 10000);
- };
+ if(mf.tag_entity)
+ navigation_routerating(mf.tag_entity, ratingscale, 10000);
+ }
void havocbot_goalrating_ctf_droppedflags(float ratingscale, vector org, float radius)
{
- local entity head;
+ entity head;
head = ctf_worldflaglist;
while (head)
{
head = head.ctf_worldflagnext;
}
- };
+ }
void havocbot_goalrating_ctf_carrieritems(float ratingscale, vector org, float sradius)
{
- local entity head;
- local float t;
+ entity head;
+ float t;
head = findchainfloat(bot_pickup, TRUE);
while (head)
{
}
head = head.chain;
}
- };
+ }
void havocbot_role_ctf_setrole(entity bot, float role)
{
bot.havocbot_role = havocbot_role_ctf_carrier;
bot.havocbot_role_timeout = 0;
bot.havocbot_cantfindflag = time + 10;
+ bot.bot_strategytime = 0;
break;
case HAVOCBOT_CTF_ROLE_DEFENSE:
dprint("defense");
bot.havocbot_previous_role = bot.havocbot_role;
bot.havocbot_role = havocbot_role_ctf_retriever;
bot.havocbot_role_timeout = time + 10;
+ bot.bot_strategytime = 0;
break;
case HAVOCBOT_CTF_ROLE_ESCORT:
dprint("escort");
bot.havocbot_previous_role = bot.havocbot_role;
bot.havocbot_role = havocbot_role_ctf_escort;
bot.havocbot_role_timeout = time + 30;
+ bot.bot_strategytime = 0;
break;
}
dprint("\n");
- };
+ }
void havocbot_role_ctf_carrier()
{
return;
}
}
- };
+ }
void havocbot_role_ctf_escort()
{
- local entity mf, ef;
+ entity mf, ef;
if(self.deadflag != DEAD_NO)
{
havocbot_goalrating_items(10000, self.origin, 10000);
navigation_goalrating_end();
}
- };
+ }
void havocbot_role_ctf_offense()
{
- local entity mf, ef;
- local vector pos;
+ entity mf, ef;
+ vector pos;
if(self.deadflag != DEAD_NO)
{
havocbot_goalrating_items(1000, self.origin, 10000);
navigation_goalrating_end();
}
- };
+ }
// Retriever (temporary role):
void havocbot_role_ctf_retriever()
{
- local entity mf;
+ entity mf;
if(self.deadflag != DEAD_NO)
{
if (self.bot_strategytime < time)
{
- local float radius;
+ float radius;
radius = 10000;
self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
havocbot_goalrating_items(500, self.origin, radius);
navigation_goalrating_end();
}
- };
+ }
void havocbot_role_ctf_middle()
{
- local entity mf;
+ entity mf;
if(self.deadflag != DEAD_NO)
{
if (self.bot_strategytime < time)
{
- local vector org;
+ vector org;
org = havocbot_ctf_middlepoint;
org_z = self.origin_z;
havocbot_goalrating_ctf_enemybase(2500);
navigation_goalrating_end();
}
- };
+ }
void havocbot_role_ctf_defense()
{
- local entity mf;
+ entity mf;
if(self.deadflag != DEAD_NO)
{
}
if (self.bot_strategytime < time)
{
- local float radius;
- local vector org;
+ float radius;
+ vector org;
org = mf.dropped_origin;
radius = havocbot_ctf_middlepoint_radius;
navigation_goalrating_start();
// if enemies are closer to our base, go there
- local entity head, closestplayer;
- local float distance, bestdistance;
+ entity head, closestplayer;
+ float distance, bestdistance;
distance = 10000;
FOR_EACH_PLAYER(head)
{
havocbot_goalrating_items(5000, self.origin, 10000);
navigation_goalrating_end();
}
- };
+ }
void havocbot_calculate_middlepoint()
{
}
havocbot_ctf_middlepoint = p1 + ((p2-p1) * 0.5);
havocbot_ctf_middlepoint_radius = vlen(p2-p1) * 0.5;
- };
+ }
void havocbot_ctf_reset_role(entity bot)
{
- local float cdefense, cmiddle, coffense;
- local entity mf, ef, head;
- local float c;
+ float cdefense, cmiddle, coffense;
+ entity mf, ef, head;
+ float c;
if(bot.deadflag != DEAD_NO)
return;
havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_OFFENSE);
else
havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_MIDDLE);
- };
+ }
void havocbot_chooserole_ctf()
{
havocbot_ctf_reset_role(self);
- };
+ }
ADD_CHEATS(self,cheating); \
return attempting
#define IS_CHEAT(i,argc,fr) \
- ++attempting; \
- if(!CheatsAllowed(i,argc,fr)) \
+ if((++attempting, !CheatsAllowed(i,argc,fr))) \
break
+ float num_autoscreenshot;
+ void info_autoscreenshot_findtarget()
+ {
+ entity e;
+ e = find(world, targetname, self.target);
+ if(!e)
+ {
+ objerror("Missing target. FAIL!");
+ return;
+ }
+ vector a = vectoangles(e.origin - self.origin);
+ a_x = -a_x; // don't ask
+ self.angles_x = a_x;
+ self.angles_y = a_y;
+ // we leave Rick Roll alone
+ }
+ void spawnfunc_info_autoscreenshot()
+ {
+ if(++num_autoscreenshot > autocvar_g_max_info_autoscreenshot)
+ {
+ objerror("Too many info_autoscreenshot entitites. FAIL!");
+ return;
+ }
+ if(self.target != "")
+ InitializeEntity(self, info_autoscreenshot_findtarget, INITPRIO_FINDTARGET);
+ // this one just has to exist
+ }
+
float CheatImpulse(float i)
{
BEGIN_CHEAT_FUNCTION();
if(self.flagcarried)
{
bprint("The ", self.flagcarried.netname, " was returned to base by its carrier\n");
- ReturnFlag(self.flagcarried);
+ ctf_RespawnFlag(self); // FIXCTF
}
}
if(g_ctf)
break;
case CHIMPULSE_TELEPORT:
IS_CHEAT(i, 0, 0);
+ if(self.movetype == MOVETYPE_NOCLIP)
+ {
+ e = find(world, classname, "info_autoscreenshot");
+ if(e)
+ {
+ sprint(self, "Emergency teleport used info_autoscreenshot location\n");
+ setorigin(self, e.origin);
+ self.angles = e.angles;
+ remove(e);
+ // should we? self.angles_x = -self.angles_x;
+ self.fixangle = TRUE;
+ self.velocity = '0 0 0';
+ DID_CHEAT();
+ break;
+ }
+ }
if(MoveToRandomMapLocation(self, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, ((gamestart_sv_cheats >= 2) ? 100000 : 100), 1024, 256))
{
+ sprint(self, "Emergency teleport used random location\n");
self.angles_x = -self.angles_x;
self.fixangle = TRUE;
self.velocity = '0 0 0';
IS_CHEAT(i, 0, 0);
FOR_EACH_PLAYER(e)
{
- get_model_parameters(e.playermodel, e.skinindex);
+ get_model_parameters(e.playermodel, e.skin);
if(get_model_parameters_sex == "Female")
{
makevectors(e.angles);
remove(e);
DID_CHEAT();
break;
- case "warp":
- IS_CHEAT(0, argc, 0);
- if(argc == 2) if(autocvar_g_campaign)
- {
- CampaignLevelWarp(stof(argv(1)));
- DID_CHEAT();
- }
- break;
case "god":
IS_CHEAT(0, argc, 0);
BITXOR_ASSIGN(self.flags, FL_GODMODE);
END_CHEAT_FUNCTION();
}
- void crosshair_trace_plusvisibletriggers(entity pl);
+ float Drag(entity e, float grab, float ischeat);
void Drag_Begin(entity dragger, entity draggee, vector touchpoint);
void Drag_Finish(entity dragger);
float Drag_IsDraggable(entity draggee);
{
BEGIN_CHEAT_FUNCTION();
- if(Drag_IsDragging(self))
+ // Dragging can be used as either a cheat, or a function for some objects. If sv_cheats is active,
+ // the cheat dragging is used (unlimited pickup range and any entity can be carried). If sv_cheats
+ // is disabled, normal dragging is used (limited pickup range and only dragable objects can be carried),
+ // grabbing itself no longer being accounted as cheating.
+
+ switch(0)
{
- if(self.BUTTON_DRAG)
- {
- if(self.impulse == 10 || self.impulse == 15 || self.impulse == 18)
- {
- Drag_MoveForward(self);
- self.impulse = 0;
- }
- else if(self.impulse == 12 || self.impulse == 16 || self.impulse == 19)
- {
- Drag_MoveBackward(self);
- self.impulse = 0;
- }
- else if(self.impulse >= 1 && self.impulse <= 9)
+ default:
+ if(self.maycheat || (gamestart_sv_cheats && autocvar_sv_cheats))
{
- Drag_SetSpeed(self, self.impulse - 1);
+ // use cheat dragging if cheats are enabled
+ crosshair_trace_plusvisibletriggers(self);
+ Drag(trace_ent, TRUE, TRUE);
}
- else if(self.impulse == 14)
+ else
{
- Drag_SetSpeed(self, 9);
- }
+ // drag is TRUE if the object can be picked up. While an object is being carried, the Drag() function
+ // must execute for it either way, otherwise it would cause bugs if it went out of the player's trace.
+ // This also makes sure that an object can only pe picked up if in range, but does not get dropped if
+ // it goes out of range while slinging it around.
- if(frametime)
- Drag_Update(self);
- }
- else
- {
- Drag_Finish(self);
- }
- }
- else
- {
- if(Drag_CanDrag(self))
- if(self.BUTTON_DRAG)
- {
+ float drag;
crosshair_trace_plusvisibletriggers(self);
- if(trace_ent)
- if(Drag_IsDraggable(trace_ent))
- switch(0)
- {
- default:
- IS_CHEAT(0, 0, CHRAME_DRAG);
- if(trace_ent.draggedby)
- Drag_Finish(trace_ent.draggedby);
- if(trace_ent.tag_entity)
- detach_sameorigin(trace_ent);
- Drag_Begin(self, trace_ent, trace_endpos);
- DID_CHEAT();
- break;
- }
+ if(vlen(self.origin - trace_ent.origin) <= autocvar_g_grab_range)
+ {
+ switch(trace_ent.grab)
+ {
+ case 0: // can't grab
+ break;
+ case 1: // owner can grab
+ if(trace_ent.owner == self || trace_ent.realowner == self)
+ drag = TRUE;
+ break;
+ case 2: // owner and team mates can grab
+ if(!IsDifferentTeam(trace_ent.owner, self) || !IsDifferentTeam(trace_ent.realowner, self) || trace_ent.team == self.team)
+ drag = TRUE;
+ break;
+ case 3: // anyone can grab
+ drag = TRUE;
+ break;
+ default:
+ break;
+ }
+ }
+ Drag(trace_ent, drag, FALSE); // execute dragging
}
+ break;
}
END_CHEAT_FUNCTION();
// ENTITY DRAGGING
- void crosshair_trace_plusvisibletriggers(entity pl)
+ float Drag(entity e, float pick, float ischeat)
{
- entity first;
- entity e;
- first = findchainfloat(solid, SOLID_TRIGGER);
+ BEGIN_CHEAT_FUNCTION();
- for (e = first; e; e = e.chain)
- if (e.model != "")
- e.solid = SOLID_BSP;
+ // returns TRUE when an entity has been picked up
+ // If pick is TRUE, the object can also be picked up if it's not being held already
+ // If pick is FALSE, only keep dragging the object if it's already being held
- crosshair_trace(pl);
+ switch(0)
+ {
+ default:
+ if(Drag_IsDragging(self))
+ {
+ if(self.BUTTON_DRAG)
+ {
+ if(self.impulse == 10 || self.impulse == 15 || self.impulse == 18)
+ {
+ Drag_MoveForward(self);
+ self.impulse = 0;
+ }
+ else if(self.impulse == 12 || self.impulse == 16 || self.impulse == 19)
+ {
+ Drag_MoveBackward(self);
+ self.impulse = 0;
+ }
+ else if(self.impulse >= 1 && self.impulse <= 9)
+ {
+ Drag_SetSpeed(self, self.impulse - 1);
+ }
+ else if(self.impulse == 14)
+ {
+ Drag_SetSpeed(self, 9);
+ }
- for (e = first; e; e = e.chain)
- e.solid = SOLID_TRIGGER;
+ if(frametime)
+ Drag_Update(self);
+ }
+ else
+ {
+ Drag_Finish(self);
+ }
+ }
+ else
+ {
+ if(Drag_CanDrag(self))
+ if(self.BUTTON_DRAG && pick)
+ {
+ if(e)
+ if(Drag_IsDraggable(e))
+ {
+ if(ischeat)
+ IS_CHEAT(0, 0, CHRAME_DRAG);
+ if(e.draggedby)
+ Drag_Finish(e.draggedby);
+ if(e.tag_entity)
+ detach_sameorigin(e);
+ Drag_Begin(self, e, trace_endpos);
+ if(ischeat)
+ DID_CHEAT();
+ return TRUE;
+ }
+ }
+ }
+ break;
+ }
+ return FALSE;
}
// on dragger:
float Drag_IsDraggable(entity draggee)
{
// TODO add more checks for bad stuff here
+ if(draggee == world)
+ return FALSE;
if(draggee.classname == "func_bobbing")
return FALSE;
if(draggee.classname == "door") // FIXME find out why these must be excluded, or work around the problem (trying to drag these causes like 4 fps)
}
}
-
-
-
-
-
void DragBox_Think()
{
if(self.aiment && self.enemy)
self.team = activator.team;
some_spawn_has_been_used = 1;
}
- };
+ }
// Returns:
// _x: prio (-1 if unusable)
// _y: weight
- vector Spawn_Score(entity spot, entity playerlist, float teamcheck, float anypoint)
+ vector Spawn_Score(entity spot, float mindist, float teamcheck)
{
float shortest, thisdist;
float prio;
return '-1 0 0';
}
+ shortest = vlen(world.maxs - world.mins);
+ FOR_EACH_PLAYER(player) if (player != self)
+ {
+ thisdist = vlen(player.origin - spot.origin);
+ if (thisdist < shortest)
+ shortest = thisdist;
+ }
+ if(shortest > mindist)
+ prio += SPAWN_PRIO_GOOD_DISTANCE;
+
+ spawn_score = prio * '1 0 0' + shortest * '0 1 0';
+ spawn_spot = spot;
+
// filter out spots for assault
if(spot.target != "") {
- local entity ent;
- float good, found;
- ent = find(world, targetname, spot.target);
+ entity ent;
+ float found;
- while(ent) {
- if(ent.classname == "target_objective")
- {
- found = 1;
- if(ent.health < 0 || ent.health >= ASSAULT_VALUE_INACTIVE)
- return '-1 0 0';
- good = 1;
- }
- else if(ent.classname == "trigger_race_checkpoint")
+ found = 0;
+ for(ent = world; (ent = find(ent, targetname, spot.target)); )
+ {
+ ++found;
+ if(ent.spawn_evalfunc)
{
- found = 1;
- if(!anypoint) // spectators may spawn everywhere
-
- {
- if(g_race_qualifying)
- {
- // spawn at first
- if(ent.race_checkpoint != 0)
- return '-1 0 0';
- if(spot.race_place != race_lowest_place_spawn)
- return '-1 0 0';
- }
- else
- {
- if(ent.race_checkpoint != self.race_respawn_checkpoint)
- return '-1 0 0';
- // try reusing the previous spawn
- if(ent == self.race_respawn_spotref || spot == self.race_respawn_spotref)
- prio += 1;
- if(ent.race_checkpoint == 0)
- {
- float pl;
- pl = self.race_place;
- if(pl > race_highest_place_spawn)
- pl = 0;
- if(pl == 0 && !self.race_started)
- pl = race_highest_place_spawn; // use last place if he has not even touched finish yet
- if(spot.race_place != pl)
- return '-1 0 0';
- }
- }
- }
- good = 1;
+ entity oldself = self;
+ self = ent;
+ spawn_score = ent.spawn_evalfunc(oldself, spot, spawn_score);
+ self = oldself;
+ if(spawn_score_x < 0)
+ return spawn_score;
}
- ent = find(ent, targetname, spot.target);
}
- if(found && !good)
+ if(!found)
+ {
+ dprint("WARNING: spawnpoint at ", vtos(spot.origin), " could not find its target ", spot.target, "\n");
return '-1 0 0';
+ }
}
- player = playerlist;
- shortest = vlen(world.maxs - world.mins);
- for(player = playerlist; player; player = player.chain)
- if (player != self)
- {
- thisdist = vlen(player.origin - spot.origin);
- if (thisdist < shortest)
- shortest = thisdist;
- }
- return prio * '1 0 0' + shortest * '0 1 0';
+ MUTATOR_CALLHOOK(Spawn_Score);
+ return spawn_score;
}
- float spawn_allbad;
- float spawn_allgood;
- entity Spawn_FilterOutBadSpots(entity firstspot, entity playerlist, float mindist, float teamcheck, float anypoint)
+ void Spawn_ScoreAll(entity firstspot, float mindist, float teamcheck)
{
- local entity spot, spotlist, spotlistend;
- spawn_allgood = TRUE;
- spawn_allbad = TRUE;
+ entity spot;
+ for(spot = firstspot; spot; spot = spot.chain)
+ spot.spawnpoint_score = Spawn_Score(spot, mindist, teamcheck);
+ }
+
+ entity Spawn_FilterOutBadSpots(entity firstspot, float mindist, float teamcheck)
+ {
+ entity spot, spotlist, spotlistend;
spotlist = world;
spotlistend = world;
+ Spawn_ScoreAll(firstspot, mindist, teamcheck);
+
for(spot = firstspot; spot; spot = spot.chain)
{
- spot.spawnpoint_score = Spawn_Score(spot, playerlist, teamcheck, anypoint);
-
- if(autocvar_spawn_debugview)
- {
- setmodel(spot, "models/runematch/rune.mdl");
- if(spot.spawnpoint_score_y < mindist)
- {
- spot.colormod = '1 0 0';
- spot.scale = 1;
- }
- else
- {
- spot.colormod = '0 1 0';
- spot.scale = spot.spawnpoint_score_y / mindist;
- }
- }
-
if(spot.spawnpoint_score_x >= 0) // spawning allowed here
{
- if(spot.spawnpoint_score_y < mindist)
- {
- // too short distance
- spawn_allgood = FALSE;
- }
- else
- {
- // perfect
- spawn_allbad = FALSE;
-
- if(spotlistend)
- spotlistend.chain = spot;
- spotlistend = spot;
- if(!spotlist)
- spotlist = spot;
-
- /*
- if(teamcheck >= 0)
- if(spot.team != teamcheck)
- error("invalid spawn added");
-
- print("added ", etos(spot), "\n");
- */
- }
+ if(spotlistend)
+ spotlistend.chain = spot;
+ spotlistend = spot;
+ if(!spotlist)
+ spotlist = spot;
}
}
if(spotlistend)
spotlistend.chain = world;
- /*
- entity e;
- if(teamcheck >= 0)
- for(e = spotlist; e; e = e.chain)
- {
- print("seen ", etos(e), "\n");
- if(e.team != teamcheck)
- error("invalid spawn found");
- }
- */
-
return spotlist;
}
{
// weight of a point: bound(lower, mindisttoplayer, upper)^exponent
// multiplied by spot.cnt (useful if you distribute many spawnpoints in a small area)
- local entity spot;
+ entity spot;
RandomSelection_Init();
for(spot = firstspot; spot; spot = spot.chain)
*/
entity SelectSpawnPoint (float anypoint)
{
- local float teamcheck;
- local entity firstspot_new;
- local entity spot, firstspot, playerlist;
+ float teamcheck;
+ entity spot, firstspot;
spot = find (world, classname, "testplayerstart");
if (spot)
return spot;
- if(anypoint)
+ if(anypoint || autocvar_g_spawn_useallspawns)
teamcheck = -1;
else if(have_team_spawns > 0)
{
// if we get here, we either require team spawns but have none, or we require non-team spawns and have none; use any spawn then
- // get the list of players
- playerlist = findchain(classname, "player");
// get the entire list of spots
firstspot = findchain(classname, "info_player_deathmatch");
// filter out the bad ones
}
else
{
- firstspot_new = Spawn_FilterOutBadSpots(firstspot, playerlist, 100, teamcheck, anypoint);
- if(!firstspot_new)
- firstspot_new = Spawn_FilterOutBadSpots(firstspot, playerlist, -1, teamcheck, anypoint);
- firstspot = firstspot_new;
+ float mindist;
+ if (arena_roundbased && !g_ca)
+ mindist = 800;
+ else
+ mindist = 100;
+ firstspot = Spawn_FilterOutBadSpots(firstspot, mindist, teamcheck);
// there is 50/50 chance of choosing a random spot or the furthest spot
// (this means that roughly every other spawn will be furthest, so you
// usually won't get fragged at spawn twice in a row)
- if (arena_roundbased && !g_ca)
- {
- firstspot_new = Spawn_FilterOutBadSpots(firstspot, playerlist, 800, teamcheck, anypoint);
- if(firstspot_new)
- firstspot = firstspot_new;
- spot = Spawn_WeightedPoint(firstspot, 1, 1, 1);
- }
- else if (random() > autocvar_g_spawn_furthest)
+ if (random() > autocvar_g_spawn_furthest)
spot = Spawn_WeightedPoint(firstspot, 1, 1, 1);
else
spot = Spawn_WeightedPoint(firstspot, 1, 5000, 5); // chooses a far far away spawnpoint
}
- if(autocvar_spawn_debugview)
- {
- print("spot mindistance: ", vtos(spot.spawnpoint_score), "\n");
-
- entity e;
- if(teamcheck >= 0)
- for(e = firstspot; e; e = e.chain)
- if(e.team != teamcheck)
- error("invalid spawn found");
- }
-
if (!spot)
{
if(autocvar_spawn_debug)
- GotoNextMap();
+ GotoNextMap(0);
else
{
if(some_spawn_has_been_used)
// to change a cvar default, we'll have a small leak here.
FallbackPlayerModel = strzone(cvar_defstring("_cl_playermodel"));
}
- if(strlen(plyermodel) < 4)
- return FallbackPlayerModel;
+ // only in right path
if( substring(plyermodel,0,14) != "models/player/")
return FallbackPlayerModel;
- else if(autocvar_sv_servermodelsonly)
+ // only good file extensions
+ if(substring(plyermodel,-4,4) != ".zym")
+ if(substring(plyermodel,-4,4) != ".dpm")
+ if(substring(plyermodel,-4,4) != ".iqm")
+ if(substring(plyermodel,-4,4) != ".md3")
+ if(substring(plyermodel,-4,4) != ".psk")
+ return FallbackPlayerModel;
+ // forbid the LOD models
+ if(substring(plyermodel, -9,5) == "_lod1")
+ return FallbackPlayerModel;
+ if(substring(plyermodel, -9,5) == "_lod2")
+ return FallbackPlayerModel;
+ if(plyermodel != strtolower(plyermodel))
+ return FallbackPlayerModel;
+ // also, restrict to server models
+ if(autocvar_sv_servermodelsonly)
{
- if(substring(plyermodel,-4,4) != ".zym")
- if(substring(plyermodel,-4,4) != ".dpm")
- if(substring(plyermodel,-4,4) != ".iqm")
- if(substring(plyermodel,-4,4) != ".md3")
- if(substring(plyermodel,-4,4) != ".psk")
- return FallbackPlayerModel;
- // forbid the LOD models
- if(substring(plyermodel, -9,5) == "_lod1")
- return FallbackPlayerModel;
- if(substring(plyermodel, -9,5) == "_lod2")
- return FallbackPlayerModel;
- if(plyermodel != strtolower(plyermodel))
- return FallbackPlayerModel;
if(!fexists(plyermodel))
return FallbackPlayerModel;
}
return plyermodel;
}
- /*
- =============
- Client_customizeentityforclient
-
- LOD reduction
- =============
- */
- void Client_uncustomizeentityforclient()
+ void setplayermodel(entity e, string modelname)
{
- if(self.modelindex == 0) // no need to uncustomize then
- return;
- self.modelindex = self.modelindex_lod0;
- self.skin = self.skinindex;
- }
-
- float Client_customizeentityforclient()
- {
- entity modelsource;
-
- if(self.modelindex == 0)
- return TRUE;
-
- // forcemodel stuff
-
- #ifdef PROFILING
- float t0;
- t0 = gettime(GETTIME_HIRES); // reference
- #endif
-
- modelsource = self;
-
- #ifdef ALLOW_FORCEMODELS
- if(other.cvar_cl_forceplayermodelsfromxonotic)
- if not(self.modelindex_lod0_from_xonotic)
- modelsource = other;
- if(other.cvar_cl_forceplayermodels && sv_clforceplayermodels)
- modelsource = other;
- #endif
-
- self.skin = modelsource.skinindex;
-
- #if 0
- if(modelsource == self)
- self.skin = modelsource.skinindex;
- else
- self.skin = mod(modelsource.skinindex, 3); // forbid the fbskins as forced skins
- #endif
-
- // self: me
- // other: the player viewing me
- float distance;
- float f;
-
- if(other.cvar_cl_playerdetailreduction <= 0)
- {
- if(other.cvar_cl_playerdetailreduction <= -2)
- self.modelindex = modelsource.modelindex_lod2;
- else if(other.cvar_cl_playerdetailreduction <= -1)
- self.modelindex = modelsource.modelindex_lod1;
- else
- self.modelindex = modelsource.modelindex_lod0;
- }
- else
- {
- distance = vlen(self.origin - other.origin);
- f = (distance + 100.0) * other.cvar_cl_playerdetailreduction;
- if(f > sv_loddistance2)
- self.modelindex = modelsource.modelindex_lod2;
- else if(f > sv_loddistance1)
- self.modelindex = modelsource.modelindex_lod1;
- else
- self.modelindex = modelsource.modelindex_lod0;
- }
-
- #ifdef PROFILING
- float t1;
- t1 = gettime(GETTIME_HIRES); // reference
- client_cefc_accumulator += (t1 - t0);
- #endif
-
- return TRUE;
- }
-
- void setmodel_lod(entity e, string modelname)
- {
- string s;
-
- if(sv_loddistance1)
- {
- // FIXME: this only supports 3-letter extensions
- s = strcat(substring(modelname, 0, strlen(modelname)-4), "_lod1", substring(modelname, -4, 4));
- if(fexists(s))
- {
- setmodel(e, s); // players have high precision
- self.modelindex_lod1 = self.modelindex;
- }
- else
- self.modelindex_lod1 = -1;
-
- s = strcat(substring(modelname, 0, strlen(modelname)-4), "_lod2", substring(modelname, -4, 4));
- if(fexists(s))
- {
- setmodel(e, s); // players have high precision
- self.modelindex_lod2 = self.modelindex;
- }
- else
- self.modelindex_lod2 = -1;
-
- precache_model(modelname);
- setmodel(e, modelname); // players have high precision
- self.modelindex_lod0 = self.modelindex;
-
- if(self.modelindex_lod1 < 0)
- self.modelindex_lod1 = self.modelindex;
-
- if(self.modelindex_lod2 < 0)
- self.modelindex_lod2 = self.modelindex;
- }
- else
- {
- precache_model(modelname);
- setmodel(e, modelname); // players have high precision
- self.modelindex_lod0 = self.modelindex;
- // save it for possible player model forcing
- }
-
- s = whichpack(self.model);
- self.modelindex_lod0_from_xonotic = ((s == "") || (substring(s, 0, 4) == "data"));
-
+ precache_model(modelname);
+ setmodel(e, modelname);
player_setupanimsformodel();
UpdatePlayerSounds();
}
DropAllRunes(self);
MUTATOR_CALLHOOK(MakePlayerObserver);
+ if (g_minstagib)
+ minstagib_stop_countdown();
+
Portal_ClearAll(self);
if(self.alivetime)
vehicles_exit(VHEF_RELESE);
if(self.flagcarried)
- DropFlag(self.flagcarried, world, world);
+ ctf_Handle_Drop(self); // FIXCTF
if(self.ballcarried && g_nexball)
DropBall(self.ballcarried, self.origin + self.ballcarried.origin, self.velocity);
accuracy_resend(self);
self.spectatortime = time;
-
+
self.classname = "observer";
self.iscreature = FALSE;
+ self.damagedbycontents = FALSE;
self.health = -666;
self.takedamage = DAMAGE_NO;
self.solid = SOLID_NOT;
- self.movetype = MOVETYPE_NOCLIP;
+ self.movetype = MOVETYPE_FLY_WORLDONLY; // user preference is controlled by playerprethink
self.flags = FL_CLIENT | FL_NOTARGET;
self.armorvalue = 666;
self.effects = 0;
self.pauseregen_finished = 0;
self.damageforcescale = 0;
self.death_time = 0;
- self.dead_frame = 0;
+ self.respawn_time = 0;
self.alpha = 0;
self.scale = 0;
self.fade_time = 0;
self.pain_finished = 0;
self.strength_finished = 0;
self.invincible_finished = 0;
+ self.superweapons_finished = 0;
self.pushltime = 0;
self.think = SUB_Null;
self.nextthink = 0;
self.fixangle = TRUE;
self.crouch = FALSE;
- self.view_ofs = PL_VIEW_OFS;
- setorigin (self, spot.origin);
- setsize (self, '0 0 0', '0 0 0');
+ setorigin (self, (spot.origin + PL_VIEW_OFS)); // offset it so that the spectator spawns higher off the ground, looks better this way
self.prevorigin = self.origin;
self.items = 0;
self.weapons = 0;
self.model = "";
FixPlayermodel();
- self.model = "";
- self.modelindex = 0;
+ setmodel(self, "null");
+ self.drawonlytoclient = self;
+
+ setsize (self, PL_CROUCH_MIN, PL_CROUCH_MAX); // give the spectator some space between walls for MOVETYPE_FLY_WORLDONLY
+ self.view_ofs = '0 0 0'; // so that your view doesn't go into the ceiling with MOVETYPE_FLY_WORLDONLY, previously "PL_VIEW_OFS"
+
self.weapon = 0;
+ self.weaponname = "";
+ self.switchingweapon = 0;
self.weaponmodel = "";
self.weaponentity = world;
self.exteriorweaponentity = world;
self.oldvelocity = self.velocity;
self.fire_endtime = -1;
- if(sv_loddistance1)
- SetCustomizer(self, Client_customizeentityforclient, Client_uncustomizeentityforclient);
-
if(g_arena)
{
if(self.version_mismatch)
else
self.frags = FRAGS_LMS_LOSER;
}
+ else if(g_ca)
+ {
+ if(self.caplayer)
+ self.frags = FRAGS_LMS_LOSER;
+ else
+ self.frags = FRAGS_SPECTATOR;
+ }
else
self.frags = FRAGS_SPECTATOR;
}
+ .float model_randomizer;
void FixPlayermodel()
{
- local string defaultmodel;
- local float defaultskin, chmdl, oldskin;
- local vector m1, m2;
+ string defaultmodel;
+ float defaultskin, chmdl, oldskin, n, i;
+ vector m1, m2;
defaultmodel = "";
- if(autocvar_sv_defaultcharacter == 1) {
+ if(autocvar_sv_defaultcharacter == 1)
+ {
defaultskin = 0;
if(teamplay)
defaultmodel = autocvar_sv_defaultplayermodel;
defaultskin = autocvar_sv_defaultplayerskin;
}
- }
- if(self.modelindex == 0 && self.deadflag == DEAD_NO)
- {
- if(self.model != "")
- bprint("\{1}^1Player ", self.netname, "^1 has a zero modelindex, trying to fix...\n");
- self.model = ""; // force the != checks to return true
+ n = tokenize_console(defaultmodel);
+ if(n > 0)
+ defaultmodel = argv(floor(n * self.model_randomizer));
+
+ i = strstrofs(defaultmodel, ":", 0);
+ if(i >= 0)
+ {
+ defaultskin = stof(substring(defaultmodel, i+1, -1));
+ defaultmodel = substring(defaultmodel, 0, i);
+ }
}
if(defaultmodel != "")
{
m1 = self.mins;
m2 = self.maxs;
- setmodel_lod (self, defaultmodel);
+ setplayermodel (self, defaultmodel);
setsize (self, m1, m2);
chmdl = TRUE;
}
- oldskin = self.skinindex;
- self.skinindex = defaultskin;
+ oldskin = self.skin;
+ self.skin = defaultskin;
} else {
if (self.playermodel != self.model || self.playermodel == "")
{
self.playermodel = CheckPlayerModel(self.playermodel); // this is never "", so no endless loop
m1 = self.mins;
m2 = self.maxs;
- setmodel_lod (self, self.playermodel);
+ setplayermodel (self, self.playermodel);
setsize (self, m1, m2);
chmdl = TRUE;
}
- oldskin = self.skinindex;
- self.skinindex = stof(self.playerskin);
+ oldskin = self.skin;
+ self.skin = stof(self.playerskin);
}
- if(chmdl || oldskin != self.skinindex)
+ if(chmdl || oldskin != self.skin)
self.species = player_getspecies(); // model or skin has changed
if(!teamplay)
WriteByte(MSG_ONE, SVC_SETVIEW);
WriteEntity(MSG_ONE, self);
}
+
+ // reset player keys
+ self.itemkeys = 0;
// player is dead and becomes observer
// FIXME fix LMS scoring for new system
self.classname = "player";
self.wasplayer = TRUE;
self.iscreature = TRUE;
+ self.damagedbycontents = TRUE;
self.movetype = MOVETYPE_WALK;
self.solid = SOLID_SLIDEBOX;
self.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_SOLID;
if(clienttype(self) == CLIENTTYPE_BOT && autocvar_g_botclip_collisions)
self.dphitcontentsmask |= DPCONTENTS_BOTCLIP;
self.frags = FRAGS_PLAYER;
- if(independent_players)
+ 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;
else
self.effects = 0;
+ self.effects |= EF_TELEPORT_BIT | EF_RESTARTANIM_BIT;
self.air_finished = time + 12;
self.dmg = 2;
if(autocvar_g_balance_nex_charge)
self.weapons = start_weapons;
}
+ if(self.weapons & WEPBIT_SUPERWEAPONS) // exception for minstagib, as minstanex is a superweapon
+ self.superweapons_finished = time + autocvar_g_balance_superweapons_time;
+ else
+ self.superweapons_finished = 0;
+
if(g_weaponarena_random)
{
if(g_weaponarena_random_with_laser)
}
self.items = start_items;
- self.jump_interval = time;
self.spawnshieldtime = time + autocvar_g_spawnshieldtime;
self.pauserotarmor_finished = time + autocvar_g_balance_pause_armor_rot_spawn;
}
self.damageforcescale = 2;
self.death_time = 0;
- self.dead_frame = 0;
- self.alpha = 0;
+ self.respawn_time = 0;
self.scale = 0;
self.fade_time = 0;
self.pain_frame = 0;
WriteByte(MSG_ONE, TE_CSQC_SPAWN);
});
- if(sv_loddistance1)
- SetCustomizer(self, Client_customizeentityforclient, Client_uncustomizeentityforclient);
-
self.model = "";
FixPlayermodel();
+ self.drawonlytoclient = world;
self.crouch = FALSE;
self.view_ofs = PL_VIEW_OFS;
self.prevorigin = self.origin;
self.lastrocket = world; // stop rocket guiding, no revenge from the grave!
self.lastteleporttime = time; // prevent insane speeds due to changing origin
-
+ self.hud = HUD_NORMAL;
+
if(g_arena)
{
Spawnqueue_Remove(self);
self.killcount = 0;
}
- self.cnt = WEP_LASER;
-
CL_SpawnWeaponentity();
self.alpha = default_player_alpha;
self.colormod = '1 1 1' * autocvar_g_player_brightness;
race_PostSpawn(spot);
- if(autocvar_spawn_debug)
- {
- sprint(self, strcat("spawnpoint origin: ", vtos(spot.origin), "\n"));
- remove(spot); // usefull for checking if there are spawnpoints, that let drop through the floor
- }
-
//stuffcmd(self, "chase_active 0");
//stuffcmd(self, "set viewsize $tmpviewsize \n");
entity e;
e = get_weaponinfo(j);
if(e.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars
- self.weapon_load[j] = cvar(strcat("g_balance_", e.netname, "_reload_ammo"));
+ self.(weapon_load[j]) = cvar(strcat("g_balance_", e.netname, "_reload_ammo"));
}
- self.weapon_forbidchange = FALSE;
oldself = self;
self = spot;
activator = world;
self = oldself;
+ spawn_spot = spot;
MUTATOR_CALLHOOK(PlayerSpawn);
+ if(autocvar_spawn_debug)
+ {
+ sprint(self, strcat("spawnpoint origin: ", vtos(spot.origin), "\n"));
+ remove(spot); // usefull for checking if there are spawnpoints, that let drop through the floor
+ }
+
self.switchweapon = w_getbestweapon(self);
- self.cnt = self.switchweapon;
+ self.cnt = -1; // W_LastWeapon will not complain
self.weapon = 0;
+ self.weaponname = "";
+ self.switchingweapon = 0;
if(!self.alivetime)
self.alivetime = time;
+
+ antilag_clear(self);
} else if(self.classname == "observer" || (g_ca && !allowed_to_spawn)) {
PutObserverInServer ();
}
WriteByte(MSG_ENTITY, autocvar_g_balance_minelayer_limit); // minelayer max mines
WriteByte(MSG_ENTITY, autocvar_g_balance_hagar_secondary_load_max); // hagar max loadable rockets
WriteCoord(MSG_ENTITY, autocvar_g_trueaim_minrange);
+ WriteByte(MSG_ENTITY, autocvar_g_balance_porto_secondary);
return TRUE;
}
return;
}
- if (!self.owner.modelindex)
+ if (self.owner.alpha < 0)
{
self.owner.killindicator = world;
remove(self);
{
if(self.cnt <= 10)
AnnounceTo(self.owner, strcat(ftos(self.cnt), ""));
- if(self.owner.killindicator_teamchange)
- {
- if(self.owner.killindicator_teamchange == -1)
- centerprint(self.owner, strcat("Changing team in ", ftos(self.cnt), " seconds"));
- else if(self.owner.killindicator_teamchange == -2)
- centerprint(self.owner, strcat("Spectating in ", ftos(self.cnt), " seconds"));
- else
- centerprint(self.owner, strcat("Changing to ", ColoredTeamName(self.owner.killindicator_teamchange), " in ", ftos(self.cnt), " seconds"));
- }
- else
- centerprint(self.owner, strcat("^1Suicide in ", ftos(self.cnt), " seconds"));
}
self.nextthink = time + 1;
self.cnt -= 1;
}
}
+ float clientkilltime;
void ClientKill_TeamChange (float targetteam) // 0 = don't change, -1 = auto, -2 = spec
{
float killtime;
+ float starttime;
entity e;
if (gameover)
if(!self.killindicator)
{
- if(self.modelindex && self.deadflag == DEAD_NO)
+ if(self.deadflag == DEAD_NO)
{
killtime = max(killtime, self.clientkill_nexttime - time);
self.clientkill_nexttime = time + killtime + autocvar_g_balance_kill_antispam;
}
- if(killtime <= 0 || !self.modelindex || self.deadflag != DEAD_NO)
+ if(killtime <= 0 || self.classname != "player" || self.deadflag != DEAD_NO)
{
ClientKill_Now();
}
else
{
+ starttime = max(time, clientkilltime);
+
self.killindicator = spawn();
self.killindicator.owner = self;
self.killindicator.scale = 0.5;
setattachment(self.killindicator, self, "");
setorigin(self.killindicator, '0 0 52');
self.killindicator.think = KillIndicator_Think;
- self.killindicator.nextthink = time + (self.lip) * 0.05;
+ self.killindicator.nextthink = starttime + (self.lip) * 0.05;
+ clientkilltime = max(clientkilltime, self.killindicator.nextthink + 0.05);
self.killindicator.cnt = ceil(killtime);
self.killindicator.count = bound(0, ceil(killtime), 10);
//sprint(self, strcat("^1You'll be dead in ", ftos(self.killindicator.cnt), " seconds\n"));
setattachment(e.killindicator, e, "");
setorigin(e.killindicator, '0 0 52');
e.killindicator.think = KillIndicator_Think;
- e.killindicator.nextthink = time + (e.lip) * 0.05;
+ e.killindicator.nextthink = starttime + (e.lip) * 0.05;
+ clientkilltime = max(clientkilltime, e.killindicator.nextthink + 0.05);
e.killindicator.cnt = ceil(killtime);
}
self.lip = 0;
if(self.killindicator)
{
if(targetteam == 0) // just die
+ {
self.killindicator.colormod = '0 0 0';
+ if(clienttype(self) == CLIENTTYPE_REAL)
+ if(self.killindicator.cnt > 0)
+ Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, "^1Suicide in %d seconds", 1, self.killindicator.cnt);
+ }
else if(targetteam == -1) // auto
+ {
self.killindicator.colormod = '0 1 0';
+ if(clienttype(self) == CLIENTTYPE_REAL)
+ if(self.killindicator.cnt > 0)
+ Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, "Changing team in %d seconds", 1, self.killindicator.cnt);
+ }
else if(targetteam == -2) // spectate
+ {
self.killindicator.colormod = '0.5 0.5 0.5';
+ if(clienttype(self) == CLIENTTYPE_REAL)
+ if(self.killindicator.cnt > 0)
+ Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, "Spectating in %d seconds", 1, self.killindicator.cnt);
+ }
else
+ {
self.killindicator.colormod = TeamColor(targetteam);
+ if(clienttype(self) == CLIENTTYPE_REAL)
+ if(self.killindicator.cnt > 0)
+ Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, strcat("Changing to ", ColoredTeamName(targetteam), " in %d seconds"), 1, self.killindicator.cnt);
+ }
}
+
}
void ClientKill (void)
self.playerid = (playerid_last = playerid_last + 1);
+ PlayerStats_AddEvent(sprintf("kills-%d", self.playerid));
+
if(clienttype(self) == CLIENTTYPE_BOT)
PlayerStats_AddPlayer(self);
bprint("\n");
- self.welcomemessage_time = 0;
-
stuffcmd(self, strcat(clientstuff, "\n"));
- stuffcmd(self, strcat("exec maps/", mapname, ".cfg\n"));
- stuffcmd(self, "cl_particles_reloadeffects\n");
+ stuffcmd(self, "cl_particles_reloadeffects\n"); // TODO do we still need this?
FixClientCvars(self);
// Wazat's grappling hook
SetGrappleHookBindings();
- // get autoswitch state from player when he toggles it
- stuffcmd(self, "alias autoswitch \"set cl_autoswitch $1 ; cmd autoswitch $1\"\n"); // default.cfg-ed in 2.4.1
-
// get version info from player
stuffcmd(self, "cmd clientversion $gameversion\n");
else
stuffcmd(self, "set _teams_available 0\n");
- stuffcmd(self, strcat("set gametype ", ftos(game), "\n"));
-
if(g_arena || g_ca)
{
self.classname = "observer";
}
self.jointime = time;
- self.allowedTimeouts = autocvar_sv_timeout_number;
+ self.allowed_timeouts = autocvar_sv_timeout_number;
if(clienttype(self) == CLIENTTYPE_REAL)
{
set_dom_state(self);
CheatInitClient();
+
+ if(!autocvar_g_campaign)
+ Send_CSQC_Centerprint_Generic(self, CPID_MOTD, getwelcomemessage(), autocvar_welcome_message_time, 0);
+
+ CSQCMODEL_AUTOINIT();
+
+ self.model_randomizer = random();
}
/*
Portal_ClearAll(self);
+ RemoveGrapplingHook(self);
if(self.flagcarried)
- DropFlag(self.flagcarried, world, world);
+ ctf_Handle_Drop(self); // FIXCTF
if(self.ballcarried && g_nexball)
DropBall(self.ballcarried, self.origin + self.ballcarried.origin, self.velocity);
void ChatBubbleThink()
{
self.nextthink = time;
- if (!self.owner.modelindex || self.owner.chatbubbleentity != self)
+ if ((self.owner.alpha < 0) || self.owner.chatbubbleentity != self)
{
if(self.owner) // but why can that ever be world?
self.owner.chatbubbleentity = world;
self.model = self.mdl;
else
self.model = "";
- };
+ }
void UpdateChatBubble()
{
- if (!self.modelindex)
+ if (self.alpha < 0)
return;
// spawn a chatbubble entity if needed
if (!self.chatbubbleentity)
// added to the model skins
/*void UpdateColorModHack()
{
- local float c;
+ float c;
c = self.clientcolors & 15;
// LordHavoc: only bothering to support white, green, red, yellow, blue
if (!teamplay) self.colormod = '0 0 0';
else if (c == 12) self.colormod = '1.22 1.22 0.10';
else if (c == 13) self.colormod = '0.10 0.10 1.73';
else self.colormod = '1 1 1';
- };*/
+ }*/
- .float oldcolormap;
void respawn(void)
{
- if(self.modelindex != 0 && autocvar_g_respawn_ghosts)
+ if(self.alpha >= 0 && autocvar_g_respawn_ghosts)
{
self.solid = SOLID_NOT;
self.takedamage = DAMAGE_NO;
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 = 512;
+ 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();
}
sound (self, CH_INFO, samp, VOL_BASE, ATTN_NORM);
}
- /**
- * When sv_timeout is used this function returs strings like
- * "Timeout begins in 2 seconds!\n" or "Timeout ends in 23 seconds!\n".
- * Called by centerprint functions
- * @param addOneSecond boolean, set to 1 if the welcome-message centerprint asks for the text
- */
- string getTimeoutText(float addOneSecond) {
- if (!autocvar_sv_timeout || !timeoutStatus)
- return "";
-
- local string retStr;
- if (timeoutStatus == 1) {
- if (addOneSecond == 1) {
- retStr = strcat("Timeout begins in ", ftos(remainingLeadTime + 1), " seconds!\n");
- }
- else {
- retStr = strcat("Timeout begins in ", ftos(remainingLeadTime), " seconds!\n");
- }
- return retStr;
- }
- else if (timeoutStatus == 2) {
- if (addOneSecond) {
- retStr = strcat("Timeout ends in ", ftos(remainingTimeoutTime + 1), " seconds!\n");
- //don't show messages like "Timeout ends in 0 seconds"...
- if ((remainingTimeoutTime + 1) > 0)
- return retStr;
- else
- return "";
- }
- else {
- retStr = strcat("Timeout ends in ", ftos(remainingTimeoutTime), " seconds!\n");
- //don't show messages like "Timeout ends in 0 seconds"...
- if (remainingTimeoutTime > 0)
- return retStr;
- else
- return "";
- }
- }
- else return "";
- }
-
void player_powerups (void)
{
// add a way to see what the items were BEFORE all of these checks for the mutator hook
self.modelflags &~= MF_ROCKET;
}
- self.effects &~= (EF_DIMLIGHT | EF_RED | EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT | EF_FLAME | EF_NODEPTHTEST);
+ self.effects &~= (EF_RED | EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT | EF_FLAME | EF_NODEPTHTEST);
- if(!self.modelindex || self.deadflag) // don't apply the flags if the player is gibbed
+ if(self.alpha < 0 || self.deadflag) // don't apply the flags if the player is gibbed
return;
Fire_ApplyDamage(self);
if (self.items & IT_INVINCIBLE)
{
play_countdown(self.invincible_finished, "misc/poweroff.wav");
- if (time > self.invincible_finished && autocvar_g_balance_powerup_timer)
+ if (time > self.invincible_finished)
{
self.items = self.items - (self.items & IT_INVINCIBLE);
sprint(self, "^3Speed has worn off\n");
{
play_countdown(self.strength_finished, "misc/poweroff.wav");
self.effects = self.effects | (EF_BLUE | EF_ADDITIVE | EF_FULLBRIGHT);
- if (time > self.strength_finished && autocvar_g_balance_powerup_timer)
+ if (time > self.strength_finished)
{
self.items = self.items - (self.items & IT_STRENGTH);
sprint(self, "^3Strength has worn off\n");
{
play_countdown(self.invincible_finished, "misc/poweroff.wav");
self.effects = self.effects | (EF_RED | EF_ADDITIVE | EF_FULLBRIGHT);
- if (time > self.invincible_finished && autocvar_g_balance_powerup_timer)
+ if (time > self.invincible_finished)
{
self.items = self.items - (self.items & IT_INVINCIBLE);
sprint(self, "^3Shield has worn off\n");
sprint(self, "^3Shield surrounds you\n");
}
}
+ if (self.items & IT_SUPERWEAPON)
+ {
+ //if(W_WeaponBit(self.weapon) & WEPBIT_SUPERWEAPONS)
+ // self.effects = self.effects | EF_RED;
+ if (!(self.weapons & WEPBIT_SUPERWEAPONS))
+ {
+ self.superweapons_finished = 0;
+ self.items = self.items - (self.items & IT_SUPERWEAPON);
+ sprint(self, "^3Superweapons have been lost\n");
+ }
+ else if (self.items & IT_UNLIMITED_SUPERWEAPONS)
+ {
+ // don't let them run out
+ }
+ else
+ {
+ play_countdown(self.superweapons_finished, "misc/poweroff.wav");
+ if (time > self.superweapons_finished)
+ {
+ self.items = self.items - (self.items & IT_SUPERWEAPON);
+ self.weapons &~= WEPBIT_SUPERWEAPONS;
+ sprint(self, "^3Superweapons have broken down\n");
+ }
+ }
+ }
+ else if(self.weapons & WEPBIT_SUPERWEAPONS)
+ {
+ if (time < self.superweapons_finished || (self.items & IT_UNLIMITED_SUPERWEAPONS))
+ {
+ self.items = self.items | IT_SUPERWEAPON;
+ sprint(self, "^3You now have a superweapon\n");
+ }
+ else
+ {
+ self.superweapons_finished = 0;
+ self.weapons &~= WEPBIT_SUPERWEAPONS; // just in case
+ }
+ }
+ else
+ {
+ self.superweapons_finished = 0;
+ }
+ }
+
+ if(autocvar_g_nodepthtestplayers)
+ self.effects = self.effects | EF_NODEPTHTEST;
- if(autocvar_g_nodepthtestplayers)
- self.effects = self.effects | EF_NODEPTHTEST;
-
- if(autocvar_g_fullbrightplayers)
- self.effects = self.effects | EF_FULLBRIGHT;
+ if(autocvar_g_fullbrightplayers)
+ self.effects = self.effects | EF_FULLBRIGHT;
- // midair gamemode: damage only while in the air
- // if in midair mode, being on ground grants temporary invulnerability
- // (this is so that multishot weapon don't clear the ground flag on the
- // first damage in the frame, leaving the player vulnerable to the
- // remaining hits in the same frame)
- if (self.flags & FL_ONGROUND)
- if (g_midair)
- self.spawnshieldtime = max(self.spawnshieldtime, time + autocvar_g_midair_shieldtime);
+ // midair gamemode: damage only while in the air
+ // if in midair mode, being on ground grants temporary invulnerability
+ // (this is so that multishot weapon don't clear the ground flag on the
+ // first damage in the frame, leaving the player vulnerable to the
+ // remaining hits in the same frame)
+ if (self.flags & FL_ONGROUND)
+ if (g_midair)
+ self.spawnshieldtime = max(self.spawnshieldtime, time + autocvar_g_midair_shieldtime);
- if (time >= game_starttime)
- if (time < self.spawnshieldtime)
- self.effects = self.effects | (EF_ADDITIVE | EF_FULLBRIGHT);
- }
+ if (time >= game_starttime)
+ if (time < self.spawnshieldtime)
+ self.effects = self.effects | (EF_ADDITIVE | EF_FULLBRIGHT);
MUTATOR_CALLHOOK(PlayerPowerups);
}
self.pressedkeys = spectatee.pressedkeys;
self.weapons = spectatee.weapons;
self.switchweapon = spectatee.switchweapon;
+ self.switchingweapon = spectatee.switchingweapon;
self.weapon = spectatee.weapon;
self.nex_charge = spectatee.nex_charge;
self.nex_chargepool_ammo = spectatee.nex_chargepool_ammo;
self.dmg_save = spectatee.dmg_save;
self.dmg_inflictor = spectatee.dmg_inflictor;
self.angles = spectatee.v_angle;
- self.fixangle = TRUE;
+ if(!self.BUTTON_USE)
+ self.fixangle = TRUE;
setorigin(self, spectatee.origin);
setsize(self, spectatee.mins, spectatee.maxs);
SetZoomState(spectatee.zoomstate);
return 1;
}
- float SpectateNext() {
- other = find(self.enemy, classname, "player");
- if (!other)
+ // Returns next available player to spectate if g_ca_spectate_enemies == 0
+ entity CA_SpectateNext(entity start) {
+ if (start.team == self.team) {
+ return start;
+ }
+
+ other = start;
+ // continue from current player
+ while(other && other.team != self.team) {
other = find(other, classname, "player");
+ }
+
+ if (!other) {
+ // restart from begining
+ other = find(other, classname, "player");
+ while(other && other.team != self.team) {
+ other = find(other, classname, "player");
+ }
+ }
+
+ return other;
+ }
+ float SpectateNext() {
+ other = find(self.enemy, classname, "player");
+ if (g_ca && !autocvar_g_ca_spectate_enemies && self.caplayer) {
+ // CA and ca players when spectating enemies is forbidden
+ other = CA_SpectateNext(other);
+ } else {
+ // other modes and ca spectators or spectating enemies is allowed
+ if (!other)
+ other = find(other, classname, "player");
+ }
+
if (other)
self.enemy = other;
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 prevent_join_msgtime;
void LeaveSpectatorMode()
{
if(nJoinAllowed(1)) {
bprint ("^4", self.netname, "^4 is playing now\n");
if(!autocvar_g_campaign)
- centerprint(self,""); // clear MOTD
+ if (time < self.jointime + autocvar_welcome_message_time)
+ Send_CSQC_Centerprint_Generic_Expire(self, CPID_MOTD); // clear MOTD
+
+ if (self.prevent_join_msgtime)
+ {
+ Send_CSQC_Centerprint_Generic_Expire(self, CPID_PREVENT_JOIN);
+ self.prevent_join_msgtime = 0;
+ }
return;
} else {
}
else {
//player may not join because of g_maxplayers is set
- centerprint_atprio(self, CENTERPRIO_MAPVOTE, PREVENT_JOIN_TEXT);
+ if (time - self.prevent_join_msgtime > 2)
+ {
+ Send_CSQC_Centerprint_Generic(self, CPID_PREVENT_JOIN, PREVENT_JOIN_TEXT, 0, 0);
+ self.prevent_join_msgtime = time;
+ }
}
}
return FALSE; // forced spectators can never join
// TODO simplify this
- local entity e;
+ entity e;
- local float totalClients;
+ float totalClients;
FOR_EACH_CLIENT(e)
totalClients += 1;
if (!autocvar_g_maxplayers)
return maxclients - totalClients + includeMe;
- local float currentlyPlaying;
+ float currentlyPlaying;
FOR_EACH_REALPLAYER(e)
currentlyPlaying += 1;
}
}
+ .float motd_actived_time; // used for both motd and campaign_message
+ void PrintWelcomeMessage()
+ {
+ if (self.motd_actived_time == 0) { // is there already a message showing?
+ if (autocvar_g_campaign) {
+ if ((self.classname == "player" && self.BUTTON_INFO) || (self.classname != "player")) {
+ self.motd_actived_time = time;
+ Send_CSQC_Centerprint_Generic(self, CPID_MOTD, campaign_message, -1, 0);
+ }
+ } else {
+ if ((time - self.jointime > autocvar_welcome_message_time) && self.BUTTON_INFO) {
+ self.motd_actived_time = time;
+ Send_CSQC_Centerprint_Generic(self, CPID_MOTD, getwelcomemessage(), -1, 0);
+ }
+ }
+ } else { // showing MOTD or campaign message
+ if (autocvar_g_campaign) {
+ if (self.BUTTON_INFO)
+ self.motd_actived_time = time;
+ else if ((time - self.motd_actived_time > 2) && self.classname == "player") { // hide it some seconds after BUTTON_INFO has been released
+ self.motd_actived_time = 0;
+ Send_CSQC_Centerprint_Generic_Expire(self, CPID_MOTD);
+ }
+ } else {
+ if ((time - self.jointime) > autocvar_welcome_message_time) {
+ if (self.BUTTON_INFO)
+ self.motd_actived_time = time;
+ else if (time - self.motd_actived_time > 2) { // hide it some seconds after BUTTON_INFO has been released
+ self.motd_actived_time = 0;
+ Send_CSQC_Centerprint_Generic_Expire(self, CPID_MOTD);
+ }
+ }
+ }
+ }
+ }
+
void ObserverThink()
{
+ float prefered_movetype;
if (self.flags & FL_JUMPRELEASED) {
if (self.BUTTON_JUMP && !self.version_mismatch) {
- self.welcomemessage_time = 0;
self.flags &~= FL_JUMPRELEASED;
self.flags |= FL_SPAWNING;
} else if(self.BUTTON_ATCK && !self.version_mismatch) {
- self.welcomemessage_time = 0;
self.flags &~= FL_JUMPRELEASED;
if(SpectateNext() == 1) {
self.classname = "spectator";
}
+ } else {
+ prefered_movetype = ((!self.BUTTON_USE ? self.cvar_cl_clippedspectating : !self.cvar_cl_clippedspectating) ? MOVETYPE_FLY_WORLDONLY : MOVETYPE_NOCLIP);
+ if (self.movetype != prefered_movetype)
+ self.movetype = prefered_movetype;
}
} else {
if (!(self.BUTTON_ATCK || self.BUTTON_JUMP)) {
}
}
}
- PrintWelcomeMessage(self);
+
+ PrintWelcomeMessage();
}
void SpectatorThink()
{
if (self.flags & FL_JUMPRELEASED) {
if (self.BUTTON_JUMP && !self.version_mismatch) {
- self.welcomemessage_time = 0;
self.flags &~= FL_JUMPRELEASED;
self.flags |= FL_SPAWNING;
} else if(self.BUTTON_ATCK) {
- self.welcomemessage_time = 0;
self.flags &~= FL_JUMPRELEASED;
if(SpectateNext() == 1) {
self.classname = "spectator";
PutClientInServer();
}
} else if (self.BUTTON_ATCK2) {
- self.welcomemessage_time = 0;
self.flags &~= FL_JUMPRELEASED;
self.classname = "observer";
PutClientInServer();
PutObserverInServer();
}
- PrintWelcomeMessage(self);
+ PrintWelcomeMessage();
self.flags |= FL_CLIENT | FL_NOTARGET;
}
-float ctf_usekey();
void PlayerUseKey()
{
if(self.classname != "player")
}
// a use key was pressed; call handlers
- if(ctf_usekey())
- return;
-
MUTATOR_CALLHOOK(PlayerUseKey);
}
=============
*/
.float usekeypressed;
-void() ctf_setstatus;
+//void() ctf_setstatus;
void() nexball_setstatus;
.float items_added;
void PlayerPreThink (void)
if(self.cvar_g_xonoticversion)
if(time > self.version_nagtime)
{
- if(strstr(self.cvar_g_xonoticversion, "git", 0) < 0)
+ // don't notify git users
+ if(strstr(self.cvar_g_xonoticversion, "git", 0) < 0 && strstr(self.cvar_g_xonoticversion, "autobuild", 0) < 0)
{
- if(strstr(autocvar_g_xonoticversion, "git", 0) >= 0)
+ if(strstr(autocvar_g_xonoticversion, "git", 0) >= 0 || strstr(autocvar_g_xonoticversion, "autobuild", 0) >= 0)
{
+ // notify release users if connecting to git
dprint("^1NOTE^7 to ", self.netname, "^7 - the server is running ^3Xonotic ", autocvar_g_xonoticversion, " (beta)^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n");
sprint(self, strcat("\{1}^1NOTE: ^7the server is running ^3Xonotic ", autocvar_g_xonoticversion, " (beta)^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n"));
}
r = vercmp(self.cvar_g_xonoticversion, autocvar_g_xonoticversion);
if(r < 0)
{
- dprint("^1NOTE^7 to ", self.netname, "^7 - ^3Xonotic ", autocvar_g_xonoticversion, "^7 is out, and you still have ^3Xonotic ", self.cvar_g_xonoticversion, "^1 - get the update from ^4http://www.xonotic.com/^1!\n");
- sprint(self, strcat("\{1}^1NOTE: ^3Xonotic ", autocvar_g_xonoticversion, "^7 is out, and you still have ^3Xonotic ", self.cvar_g_xonoticversion, "^1 - get the update from ^4http://www.xonotic.com/^1!\n"));
+ // give users new version
+ dprint("^1NOTE^7 to ", self.netname, "^7 - ^3Xonotic ", autocvar_g_xonoticversion, "^7 is out, and you still have ^3Xonotic ", self.cvar_g_xonoticversion, "^1 - get the update from ^4http://www.xonotic.org/^1!\n");
+ sprint(self, strcat("\{1}^1NOTE: ^3Xonotic ", autocvar_g_xonoticversion, "^7 is out, and you still have ^3Xonotic ", self.cvar_g_xonoticversion, "^1 - get the update from ^4http://www.xonotic.org/^1!\n"));
}
else if(r > 0)
{
- dprint("^1NOTE^7 to ", self.netname, "^7 - the server is running ^3Xonotic ", autocvar_g_xonoticversion, "^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n");
+ // notify users about old server version
+ print("^1NOTE^7 to ", self.netname, "^7 - the server is running ^3Xonotic ", autocvar_g_xonoticversion, "^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n");
sprint(self, strcat("\{1}^1NOTE: ^7the server is running ^3Xonotic ", autocvar_g_xonoticversion, "^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n"));
}
}
MUTATOR_CALLHOOK(PlayerPreThink);
- if(self.BUTTON_USE && !self.usekeypressed)
- PlayerUseKey();
- self.usekeypressed = self.BUTTON_USE;
+ if(!self.cvar_cl_newusekeysupported) // FIXME remove this - it was a stupid idea to begin with, we can JUST use the button
+ {
+ if(self.BUTTON_USE && !self.usekeypressed)
+ PlayerUseKey();
+ self.usekeypressed = self.BUTTON_USE;
+ }
+
+ PrintWelcomeMessage();
if(self.classname == "player") {
// if(self.netname == "Wazat")
CheckRules_Player();
- PrintWelcomeMessage(self);
-
if (intermission_running)
{
IntermissionThink (); // otherwise a button could be missed between
}
//don't allow the player to turn around while game is paused!
- if(timeoutStatus == 2) {
+ if(timeout_status == TIMEOUT_ACTIVE) {
// FIXME turn this into CSQC stuff
self.v_angle = self.lastV_angle;
self.angles = self.lastV_angle;
if(frametime)
{
- if(self.health <= 0 && autocvar_g_deathglow)
- {
- if(self.glowmod_x > 0)
- self.glowmod_x -= autocvar_g_deathglow * frametime;
- else
- self.glowmod_x = -1;
- if(self.glowmod_y > 0)
- self.glowmod_y -= autocvar_g_deathglow * frametime;
- else
- self.glowmod_y = -1;
- if(self.glowmod_z > 0)
- self.glowmod_z -= autocvar_g_deathglow * frametime;
- else
- self.glowmod_z = -1;
- }
- else
+ #ifndef NO_LEGACY_NETWORKING
+ self.glowmod = colormapPaletteColor(self.clientcolors & 0x0F, TRUE) * 2;
+ #endif
+
+ if(self.weapon == WEP_NEX && autocvar_g_balance_nex_charge)
{
- // set weapon and player glowmod
- self.glowmod = colormapPaletteColor(self.clientcolors & 0x0F, TRUE) * 2;
+ self.weaponentity_glowmod_x = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_red_half * min(1, self.nex_charge / autocvar_g_balance_nex_charge_animlimit);
+ self.weaponentity_glowmod_y = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_green_half * min(1, self.nex_charge / autocvar_g_balance_nex_charge_animlimit);
+ self.weaponentity_glowmod_z = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_blue_half * min(1, self.nex_charge / autocvar_g_balance_nex_charge_animlimit);
- if(self.weapon == WEP_NEX && autocvar_g_balance_nex_charge)
+ if(self.nex_charge > autocvar_g_balance_nex_charge_animlimit)
{
- self.weaponentity_glowmod_x = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_red_half * min(1, self.nex_charge / autocvar_g_balance_nex_charge_animlimit);
- self.weaponentity_glowmod_y = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_green_half * min(1, self.nex_charge / autocvar_g_balance_nex_charge_animlimit);
- self.weaponentity_glowmod_z = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_blue_half * min(1, self.nex_charge / autocvar_g_balance_nex_charge_animlimit);
-
- if(self.nex_charge > autocvar_g_balance_nex_charge_animlimit)
- {
- self.weaponentity_glowmod_x = self.weaponentity_glowmod_x + autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_red_full * (self.nex_charge - autocvar_g_balance_nex_charge_animlimit) / (1 - autocvar_g_balance_nex_charge_animlimit);
- self.weaponentity_glowmod_y = self.weaponentity_glowmod_y + autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_green_full * (self.nex_charge - autocvar_g_balance_nex_charge_animlimit) / (1 - autocvar_g_balance_nex_charge_animlimit);
- self.weaponentity_glowmod_z = self.weaponentity_glowmod_z + autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_blue_full * (self.nex_charge - autocvar_g_balance_nex_charge_animlimit) / (1 - autocvar_g_balance_nex_charge_animlimit);
- }
+ self.weaponentity_glowmod_x = self.weaponentity_glowmod_x + autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_red_full * (self.nex_charge - autocvar_g_balance_nex_charge_animlimit) / (1 - autocvar_g_balance_nex_charge_animlimit);
+ self.weaponentity_glowmod_y = self.weaponentity_glowmod_y + autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_green_full * (self.nex_charge - autocvar_g_balance_nex_charge_animlimit) / (1 - autocvar_g_balance_nex_charge_animlimit);
+ self.weaponentity_glowmod_z = self.weaponentity_glowmod_z + autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_blue_full * (self.nex_charge - autocvar_g_balance_nex_charge_animlimit) / (1 - autocvar_g_balance_nex_charge_animlimit);
}
- else
- self.weaponentity_glowmod = self.glowmod;
}
+ else
+ self.weaponentity_glowmod = colormapPaletteColor(self.clientcolors & 0x0F, TRUE) * 2;
+
player_powerups();
}
+ if (g_minstagib)
+ minstagib_ammocheck();
+
if (self.deadflag != DEAD_NO)
{
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();
}
}
}
return;
}
+ // FIXME from now on self.deadflag is always 0 (and self.health is never < 1)
+ // so (self.deadflag == DEAD_NO) is always true in the code below
if(g_touchexplode)
if(time > self.touchexplode_time)
self.prevorigin = self.origin;
- if ((self.BUTTON_CROUCH && !self.hook.state) || self.health <= g_bloodloss)
+ if (((self.BUTTON_CROUCH && !self.hook.state) || self.health <= g_bloodloss) && self.animstate_startframe != self.anim_melee_x) // prevent crouching if using melee attack
{
if (!self.crouch)
{
self.crouch = TRUE;
self.view_ofs = PL_CROUCH_VIEW_OFS;
setsize (self, PL_CROUCH_MIN, PL_CROUCH_MAX);
- setanim(self, self.anim_duck, FALSE, TRUE, TRUE);
+ // setanim(self, self.anim_duck, FALSE, TRUE, TRUE); // this anim is BROKEN anyway
}
}
else
if(frametime)
player_anim();
- if (g_minstagib)
- minstagib_ammocheck();
-
- if(g_ctf)
- ctf_setstatus();
+ //if(g_ctf)
+ // ctf_setstatus();
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
stuffcmd(self, strcat("name ", self.netname, substring(ftos(random()), 2, -1), "\n"));
}
- if(sv_maxidle && frametime)
+ if(sv_maxidle && frametime) // WORKAROUND: only use dropclient in server frames (frametime set). Never use it in cl_movement frames (frametime zero).
{
- // WORKAROUND: only use dropclient in server frames (frametime set). Never use it in cl_movement frames (frametime zero).
- float timeleft;
- timeleft = ceil(sv_maxidle - (time - self.parm_idlesince));
- if(timeleft <= 0)
+ if (time - self.parm_idlesince < 1) // instead of (time == self.parm_idlesince) to support sv_maxidle <= 10
{
- bprint("^3", self.netname, "^3 was kicked for idling.\n");
- AnnounceTo(self, "terminated");
- dropclient(self);
- return;
- }
- else if(timeleft <= 10)
- {
- if(timeleft != self.idlekick_lasttimeleft)
+ if(self.idlekick_lasttimeleft)
{
- centerprint_atprio(self, CENTERPRIO_IDLEKICK, strcat("^3Stop idling!\n^3Disconnecting in ", ftos(timeleft), "..."));
- AnnounceTo(self, strcat(ftos(timeleft), ""));
+ Send_CSQC_Centerprint_Generic_Expire(self, CPID_DISCONNECT_IDLING);
+ self.idlekick_lasttimeleft = 0;
}
}
else
{
- centerprint_expire(self, CENTERPRIO_IDLEKICK);
+ float timeleft;
+ timeleft = ceil(sv_maxidle - (time - self.parm_idlesince));
+ if(timeleft == min(10, sv_maxidle - 1)) // - 1 to support sv_maxidle <= 10
+ {
+ if(!self.idlekick_lasttimeleft)
+ Send_CSQC_Centerprint_Generic(self, CPID_DISCONNECT_IDLING, "^3Stop idling!\n^3Disconnecting in %d seconds...", 1, timeleft);
+ }
+ if(timeleft <= 0)
+ {
+ bprint("^3", self.netname, "^3 was kicked for idling.\n");
+ AnnounceTo(self, "terminated");
+ dropclient(self);
+ return;
+ }
+ else if(timeleft <= 10)
+ {
+ if(timeleft != self.idlekick_lasttimeleft)
+ AnnounceTo(self, ftos(timeleft));
+ self.idlekick_lasttimeleft = timeleft;
+ }
}
- self.idlekick_lasttimeleft = timeleft;
}
#ifdef TETRIS
if(self.impulse == 100)
ImpulseCommands();
- if (TetrisPostFrame())
- return;
+ if (!TetrisPostFrame())
+ {
#endif
CheatFrame();
+ //CheckPlayerJump();
+
if(self.classname == "player") {
CheckRules_Player();
UpdateChatBubble();
//do nothing
}
+ #ifdef TETRIS
+ }
+ #endif
+
/*
float i;
for(i = 0; i < 1000; ++i)
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);
}
if(g_race)
dprint(sprintf("%f %.6f\n", time, race_GetFractionalLapCount(self)));
*/
+
+ CSQCMODEL_AUTOUPDATE();
}
#define WEAPONSTATS_GETINDEX(awep,abot,vwep,vbot) (((vwep) + (awep) * (WEP_LAST - WEP_FIRST + 1) - (WEP_FIRST + WEP_FIRST * (WEP_LAST - WEP_FIRST + 1))) * 4 + (abot) * 2 + (vbot))
- void WeaponStats_Shutdown()
+ void WeaponStats_ready(entity fh, entity pass, float status)
{
- float i, j, ibot, jbot, idx;
- float fh;
+ float i, j, n, ibot, jbot, idx;
vector v;
- string prefix;
- if(weaponstats_buffer < 0)
- return;
- prefix = strcat(autocvar_hostname, "\t", GetGametype(), "_", GetMapname(), "\t");
- if(autocvar_sv_weaponstats_file != "")
+ string prefix, s;
+ switch(status)
{
- fh = fopen(autocvar_sv_weaponstats_file, FILE_APPEND);
- if(fh >= 0)
- {
- fputs(fh, "#begin statsfile\n");
- fputs(fh, strcat("#date ", strftime(TRUE, "%a %b %e %H:%M:%S %Z %Y"), "\n"));
- fputs(fh, strcat("#config ", ftos(crc16(FALSE, cvar_changes)), "\n"));
+ case URL_READY_CANWRITE:
+ // we can write
+ prefix = strcat(autocvar_hostname, "\t", GetGametype(), "_", GetMapname(), "\t");
+ url_fputs(fh, "#begin statsfile\n");
+ url_fputs(fh, strcat("#date ", strftime(TRUE, "%a %b %e %H:%M:%S %Z %Y"), "\n"));
+ #ifdef WATERMARK
+ url_fputs(fh, strcat("#version ", WATERMARK(), "\n"));
+ #endif
+ url_fputs(fh, strcat("#config ", ftos(crc16(FALSE, cvar_purechanges)), "\n"));
+ url_fputs(fh, strcat("#cvar_purechanges ", ftos(cvar_purechanges_count), "\n"));
+ n = tokenizebyseparator(cvar_purechanges, "\n");
+ for(i = 0; i < n; ++i)
+ url_fputs(fh, strcat("#cvar_purechange ", argv(i), "\n"));
for(i = WEP_FIRST; i <= WEP_LAST; ++i) for(ibot = 0; ibot <= 1; ++ibot)
for(j = WEP_FIRST; j <= WEP_LAST; ++j) for(jbot = 0; jbot <= 1; ++jbot)
{
if(v != '0 0 0')
{
//vector is: kills hits damage
- fputs(fh, sprintf("%s%d %d\t%d %d\t", prefix, i, ibot, j, jbot));
- fputs(fh, sprintf("%d %d %g\n", v_x, v_y, v_z));
+ url_fputs(fh, sprintf("%s%d %d\t%d %d\t", prefix, i, ibot, j, jbot));
+ url_fputs(fh, sprintf("%d %d %g\n", v_x, v_y, v_z));
}
}
- fputs(fh, "#end\n\n");
- fclose(fh);
+ url_fputs(fh, "#end\n\n");
+ url_fclose(fh);
+ break;
+ case URL_READY_CANREAD:
+ // url_fclose is processing, we got a response for writing the data
+ // this must come from HTTP
+ print("Got response from weapon stats server:\n");
+ while((s = url_fgets(fh)))
+ print(" ", s, "\n");
+ print("End of response.\n");
+ url_fclose(fh);
+ break;
+ case URL_READY_CLOSED:
+ // url_fclose has finished
print("Weapon stats written\n");
- }
+ buf_del(weaponstats_buffer);
+ weaponstats_buffer = -1;
+ break;
+ case URL_READY_ERROR:
+ default:
+ print("Weapon stats writing failed: ", ftos(status), "\n");
+ buf_del(weaponstats_buffer);
+ weaponstats_buffer = -1;
+ break;
+ }
+ }
+
+ void WeaponStats_Shutdown()
+ {
+ if(weaponstats_buffer < 0)
+ return;
+ if(autocvar_sv_weaponstats_file != "")
+ {
+ url_multi_fopen(autocvar_sv_weaponstats_file, FILE_APPEND, WeaponStats_ready, world);
+ }
+ else
+ {
+ buf_del(weaponstats_buffer);
+ weaponstats_buffer = -1;
}
- buf_del(weaponstats_buffer);
- weaponstats_buffer = -1;
}
void WeaponStats_LogItem(float awep, float abot, float vwep, float vbot, vector item)
.entity pusher;
.float pushltime;
+ .float CopyBody_nextthink;
+ .void(void) CopyBody_think;
+ void CopyBody_Think(void)
+ {
+ if(self.CopyBody_nextthink && time > self.CopyBody_nextthink)
+ {
+ self.CopyBody_think();
+ if(wasfreed(self))
+ return;
+ self.CopyBody_nextthink = self.nextthink;
+ self.CopyBody_think = self.think;
+ self.think = CopyBody_Think;
+ }
+ CSQCMODEL_AUTOUPDATE();
+ self.nextthink = time;
+ }
void CopyBody(float keepvelocity)
{
- local entity oldself;
+ entity oldself;
if (self.effects & EF_NODRAW)
return;
oldself = self;
self.enemy = oldself;
self.lip = oldself.lip;
self.colormap = oldself.colormap;
- self.glowmod = oldself.glowmod;
self.iscreature = oldself.iscreature;
+ self.damagedbycontents = oldself.damagedbycontents;
self.angles = oldself.angles;
self.avelocity = oldself.avelocity;
self.classname = "body";
self.damageforcescale = oldself.damageforcescale;
self.effects = oldself.effects;
+ self.glowmod = oldself.glowmod;
self.event_damage = oldself.event_damage;
self.animstate_startframe = oldself.animstate_startframe;
self.animstate_numframes = oldself.animstate_numframes;
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.dead_frame = oldself.dead_frame;
self.pain_finished = oldself.pain_finished;
self.health = oldself.health;
self.armorvalue = oldself.armorvalue;
self.armortype = oldself.armortype;
self.model = oldself.model;
self.modelindex = oldself.modelindex;
- self.modelindex_lod0 = oldself.modelindex_lod0;
- self.modelindex_lod0_from_xonotic = oldself.modelindex_lod0_from_xonotic;
- self.modelindex_lod1 = oldself.modelindex_lod1;
- self.modelindex_lod2 = oldself.modelindex_lod2;
- self.skinindex = oldself.skinindex;
+ self.skin = oldself.skin;
self.species = oldself.species;
self.movetype = oldself.movetype;
- self.nextthink = oldself.nextthink;
self.solid = oldself.solid;
self.ballistics_density = oldself.ballistics_density;
self.takedamage = oldself.takedamage;
- self.think = oldself.think;
self.customizeentityforclient = oldself.customizeentityforclient;
self.uncustomizeentityforclient = oldself.uncustomizeentityforclient;
self.uncustomizeentityforclient_set = oldself.uncustomizeentityforclient_set;
if (keepvelocity == 1)
self.velocity = oldself.velocity;
self.oldvelocity = self.velocity;
+ self.alpha = oldself.alpha;
self.fade_time = oldself.fade_time;
self.fade_rate = oldself.fade_rate;
//self.weapon = oldself.weapon;
Drag_MoveDrag(oldself, self);
+ self.owner = oldself;
+
+ if(self.colormap <= maxclients && self.colormap > 0)
+ self.colormap = 1024 + oldself.clientcolors;
+
+ CSQCMODEL_AUTOINIT();
+ self.CopyBody_nextthink = oldself.nextthink;
+ self.CopyBody_think = oldself.think;
+ self.nextthink = time;
+ self.think = CopyBody_Think;
+
self = oldself;
}
float player_getspecies()
{
float s;
- get_model_parameters(self.model, self.skinindex);
+ get_model_parameters(self.model, self.skin);
s = get_model_parameters_species;
get_model_parameters(string_null, 0);
if(s < 0)
void player_setupanimsformodel()
{
- local string animfilename;
- local float animfile;
// defaults for legacy .zym models without animinfo files
- self.anim_die1 = '0 1 0.5'; // 2 seconds
- self.anim_die2 = '1 1 0.5'; // 2 seconds
- self.anim_draw = '2 1 3'; // TODO: analyze models and set framerate
- self.anim_duck = '3 1 100'; // this anim seems bogus in most models, so make it play VERY briefly!
- self.anim_duckwalk = '4 1 1';
- self.anim_duckjump = '5 1 100'; // zym anims keep playing until changed, so this only has to start the anim, landing will end it
- self.anim_duckidle = '6 1 1';
- self.anim_idle = '7 1 1';
- self.anim_jump = '8 1 100'; // zym anims keep playing until changed, so this only has to start the anim, landing will end it
- self.anim_pain1 = '9 1 2'; // 0.5 seconds
- self.anim_pain2 = '10 1 2'; // 0.5 seconds
- self.anim_shoot = '11 1 5'; // TODO: analyze models and set framerate
- self.anim_taunt = '12 1 0.33'; // FIXME? there is no code using this anim
- self.anim_run = '13 1 1';
- self.anim_runbackwards = '14 1 1';
- self.anim_strafeleft = '15 1 1';
- self.anim_straferight = '16 1 1';
- self.anim_dead1 = '17 1 1';
- self.anim_dead2 = '18 1 1';
- self.anim_forwardright = '19 1 1';
- self.anim_forwardleft = '20 1 1';
- self.anim_backright = '21 1 1';
- self.anim_backleft = '22 1 1';
- self.anim_melee = '23 1 1';
- animparseerror = FALSE;
- animfilename = strcat(self.model, ".animinfo");
- animfile = fopen(animfilename, FILE_READ);
- if (animfile >= 0)
- {
- self.anim_die1 = animparseline(animfile);
- self.anim_die2 = animparseline(animfile);
- self.anim_draw = animparseline(animfile);
- self.anim_duck = animparseline(animfile);
- self.anim_duckwalk = animparseline(animfile);
- self.anim_duckjump = animparseline(animfile);
- self.anim_duckidle = animparseline(animfile);
- self.anim_idle = animparseline(animfile);
- self.anim_jump = animparseline(animfile);
- self.anim_pain1 = animparseline(animfile);
- self.anim_pain2 = animparseline(animfile);
- self.anim_shoot = animparseline(animfile);
- self.anim_taunt = animparseline(animfile);
- self.anim_run = animparseline(animfile);
- self.anim_runbackwards = animparseline(animfile);
- self.anim_strafeleft = animparseline(animfile);
- self.anim_straferight = animparseline(animfile);
- self.anim_forwardright = animparseline(animfile);
- self.anim_forwardleft = animparseline(animfile);
- self.anim_backright = animparseline(animfile);
- self.anim_backleft = animparseline(animfile);
- self.anim_melee = animparseline(animfile);
- fclose(animfile);
-
- // derived anims
- self.anim_dead1 = '0 1 1' + '1 0 0' * (self.anim_die1_x + self.anim_die1_y - 1);
- self.anim_dead2 = '0 1 1' + '1 0 0' * (self.anim_die2_x + self.anim_die2_y - 1);
-
- if (animparseerror)
- print("Parse error in ", animfilename, ", some player animations are broken\n");
- }
- else
- dprint("File ", animfilename, " not found, assuming legacy .zym model animation timings\n");
+ self.anim_die1 = animfixfps(self, '0 1 0.5'); // 2 seconds
+ self.anim_die2 = animfixfps(self, '1 1 0.5'); // 2 seconds
+ self.anim_draw = animfixfps(self, '2 1 3');
+ // self.anim_duck = '3 1 100'; // This anim is broken, use slot 3 as a new free slot in the future ;)
+ self.anim_duckwalk = animfixfps(self, '4 1 1');
+ self.anim_duckjump = '5 1 100'; // NOTE: zym anims keep playing until changed, so this only has to start the anim, landing will end it
+ self.anim_duckidle = animfixfps(self, '6 1 1');
+ self.anim_idle = animfixfps(self, '7 1 1');
+ self.anim_jump = '8 1 100'; // NOTE: zym anims keep playing until changed, so this only has to start the anim, landing will end it
+ self.anim_pain1 = animfixfps(self, '9 1 2'); // 0.5 seconds
+ self.anim_pain2 = animfixfps(self, '10 1 2'); // 0.5 seconds
+ self.anim_shoot = animfixfps(self, '11 1 5'); // analyze models and set framerate
+ self.anim_taunt = animfixfps(self, '12 1 0.33');
+ self.anim_run = animfixfps(self, '13 1 1');
+ self.anim_runbackwards = animfixfps(self, '14 1 1');
+ self.anim_strafeleft = animfixfps(self, '15 1 1');
+ self.anim_straferight = animfixfps(self, '16 1 1');
+ //self.anim_dead1 = animfixfps(self, '17 1 1');
+ //self.anim_dead2 = animfixfps(self, '18 1 1');
+ self.anim_forwardright = animfixfps(self, '19 1 1');
+ self.anim_forwardleft = animfixfps(self, '20 1 1');
+ self.anim_backright = animfixfps(self, '21 1 1');
+ self.anim_backleft = animfixfps(self, '22 1 1');
+ self.anim_melee = animfixfps(self, '23 1 1');
+ self.anim_duckwalkbackwards = animfixfps(self, '24 1 1');
+ self.anim_duckwalkstrafeleft = animfixfps(self, '25 1 1');
+ self.anim_duckwalkstraferight = animfixfps(self, '26 1 1');
+ self.anim_duckwalkforwardright = animfixfps(self, '27 1 1');
+ self.anim_duckwalkforwardleft = animfixfps(self, '28 1 1');
+ self.anim_duckwalkbackright = animfixfps(self, '29 1 1');
+ self.anim_duckwalkbackleft = animfixfps(self, '30 1 1');
+ // TODO introspect models for finding right "fps" value (1/duration)
// reset animstate now
setanim(self, self.anim_idle, TRUE, FALSE, TRUE);
- };
+ }
void player_anim (void)
{
updateanim(self.weaponentity);
if (self.deadflag != DEAD_NO)
- {
- if (time > self.animstate_endtime)
- {
- if (self.maxs_z > 5)
- {
- self.maxs_z = 5;
- setsize(self, self.mins, self.maxs);
- }
- self.frame = self.dead_frame;
- }
return;
- }
if (!self.animstate_override)
{
- if (!(self.flags & FL_ONGROUND))
+ if (!(self.flags & FL_ONGROUND) || self.BUTTON_JUMP)
{
if (self.crouch)
- setanim(self, self.anim_duckjump, FALSE, TRUE, self.restart_jump);
+ {
+ if (self.animstate_startframe != self.anim_duckjump_x) // don't perform another trace if already playing the crouch jump anim
+ {
+ traceline(self.origin + '0 0 1' * PL_CROUCH_MIN_z, self.origin + '0 0 1' * (PL_CROUCH_MIN_z - autocvar_sv_player_jumpanim_minfall), TRUE, self);
+ if(!trace_startsolid && trace_fraction == 1 || !(self.animstate_startframe == self.anim_duckwalk_x || self.animstate_startframe == self.anim_duckidle_x)) // don't get stuck on non-crouch anims
+ {
+ setanim(self, self.anim_duckjump, FALSE, TRUE, self.restart_jump);
+ self.restart_jump = FALSE;
+ }
+ }
+ }
else
- setanim(self, self.anim_jump, FALSE, TRUE, self.restart_jump);
- self.restart_jump = FALSE;
+ {
+ if (self.animstate_startframe != self.anim_jump_x) // don't perform another trace if already playing the jump anim
+ {
+ traceline(self.origin + '0 0 1' * PL_MIN_z, self.origin + '0 0 1' * (PL_MIN_z - autocvar_sv_player_jumpanim_minfall), TRUE, self);
+ if(!trace_startsolid && trace_fraction == 1 || self.animstate_startframe == self.anim_idle_x || (self.animstate_startframe == self.anim_melee_x && time - self.animstate_starttime >= 21/20)) // don't get stuck on idle animation in midair, nor melee after it finished
+ {
+ setanim(self, self.anim_jump, FALSE, TRUE, self.restart_jump);
+ self.restart_jump = FALSE;
+ }
+ }
+ }
}
else if (self.crouch)
{
- if (self.movement_x * self.movement_x + self.movement_y * self.movement_y > 20)
+ if (self.movement_x > 0 && self.movement_y == 0)
setanim(self, self.anim_duckwalk, TRUE, FALSE, FALSE);
+ else if (self.movement_x < 0 && self.movement_y == 0)
+ setanim(self, self.anim_duckwalkbackwards, TRUE, FALSE, FALSE);
+ else if (self.movement_x == 0 && self.movement_y > 0)
+ setanim(self, self.anim_duckwalkstraferight, TRUE, FALSE, FALSE);
+ else if (self.movement_x == 0 && self.movement_y < 0)
+ setanim(self, self.anim_duckwalkstrafeleft, TRUE, FALSE, FALSE);
+ else if (self.movement_x > 0 && self.movement_y > 0)
+ setanim(self, self.anim_duckwalkforwardright, TRUE, FALSE, FALSE);
+ else if (self.movement_x > 0 && self.movement_y < 0)
+ setanim(self, self.anim_duckwalkforwardleft, TRUE, FALSE, FALSE);
+ else if (self.movement_x < 0 && self.movement_y > 0)
+ setanim(self, self.anim_duckwalkbackright, TRUE, FALSE, FALSE);
+ else if (self.movement_x < 0 && self.movement_y < 0)
+ setanim(self, self.anim_duckwalkbackleft, TRUE, FALSE, FALSE);
else
setanim(self, self.anim_duckidle, TRUE, FALSE, FALSE);
}
void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
{
- local float take, save;
+ float take, save;
vector v;
Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, self, attacker);
self.dmg_take = self.dmg_take + take;//max(take - 10, 0);
self.dmg_inflictor = inflictor;
- if (self.health <= -autocvar_sv_gibhealth && self.modelindex != 0)
+ if (self.health <= -autocvar_sv_gibhealth && self.alpha >= 0)
{
// don't use any animations as a gib
self.frame = 0;
- self.dead_frame = 0;
// view just above the floor
self.view_ofs = '0 0 4';
Violence_GibSplash(self, 1, 1, attacker);
- self.modelindex = 0; // restore later
+ self.alpha = -1;
self.solid = SOLID_NOT; // restore later
+ self.takedamage = DAMAGE_NO; // restore later
}
}
void PlayerDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
{
- local float take, save, waves, sdelay, dh, da, j;
+ float take, save, waves, sdelay, dh, da, j;
vector v;
float valid_damage_for_weaponstats;
float excess;
- if((g_arena && numspawned < 2) || (g_ca && ca_players < required_ca_players) && !inWarmupStage)
+ if((g_arena && numspawned < 2) || (g_ca && !ca_teams_ok) && !inWarmupStage)
return;
dh = max(self.health, 0);
self.armorvalue = self.armorvalue - save;
self.health = self.health - take;
// pause regeneration for 5 seconds
- self.pauseregen_finished = max(self.pauseregen_finished, time + autocvar_g_balance_pause_health_regen);
+ if(take)
+ self.pauseregen_finished = max(self.pauseregen_finished, time + autocvar_g_balance_pause_health_regen);
if (time > self.pain_finished) //Don't switch pain sequences like crazy
{
if(sv_gentle < 1) {
if(self.classname != "body") // pain anim is BORKED on our ZYMs, FIXME remove this once we have good models
{
- if (random() > 0.5)
- setanim(self, self.anim_pain1, FALSE, TRUE, TRUE);
- else
- setanim(self, self.anim_pain2, FALSE, TRUE, TRUE);
+ if (!self.animstate_override)
+ {
+ if (random() > 0.5)
+ setanim(self, self.anim_pain1, FALSE, TRUE, TRUE);
+ else
+ setanim(self, self.anim_pain2, FALSE, TRUE, TRUE);
+ }
}
if(sound_allowed(MSG_BROADCAST, attacker))
}
// throw off bot aim temporarily
- local float shake;
+ float shake;
shake = damage * 5 / (bound(0,skill,100) + 1);
self.v_angle_x = self.v_angle_x + (random() * 2 - 1) * shake;
self.v_angle_y = self.v_angle_y + (random() * 2 - 1) * shake;
if(!g_freezetag)
{
// become fully visible
- self.alpha = 1;
+ self.alpha = default_player_alpha;
// throw a weapon
SpawnThrownWeapon (self.origin + (self.mins + self.maxs) * 0.5, self.switchweapon);
}
float w;
w = DEATH_WEAPONOF(deathtype);
if(WEP_VALID(w))
- if(self.classname == "player")
- if(self != attacker)
+ if(accuracy_isgooddamage(attacker, self))
attacker.accuracy.(accuracy_frags[w-1]) += 1;
if(deathtype == DEATH_HURTTRIGGER && g_freezetag)
MUTATOR_CALLHOOK(PlayerDies);
weapon_action(self.weapon, WR_PLAYERDEATH);
+ RemoveGrapplingHook(self);
+
if(self.flagcarried)
{
+ // FIXCTF
if(attacker.classname != "player")
- DropFlag(self.flagcarried, self, attacker); // penalty for flag loss by suicide
+ ctf_Handle_Drop(self); // penalty for flag loss by suicide
else if(attacker.team == self.team)
- DropFlag(self.flagcarried, attacker, attacker); // penalty for flag loss by suicide/teamkill
+ ctf_Handle_Drop(self); // penalty for flag loss by suicide/teamkill
else
- DropFlag(self.flagcarried, world, attacker);
+ ctf_Handle_Drop(self);
}
if(self.ballcarried && g_nexball)
DropBall(self.ballcarried, self.origin, self.velocity);
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);
- self.dead_frame = self.anim_dead1_x;
- }
else
- {
setanim(self, self.anim_die2, FALSE, TRUE, TRUE);
- self.dead_frame = self.anim_dead2_x;
+ if (self.maxs_z > 5)
+ {
+ self.maxs_z = 5;
+ setsize(self, self.mins, self.maxs);
}
// set damage function to corpse damage
self.event_damage = PlayerCorpseDamage;
flood = 1;
}
- if (timeoutStatus == 2) //when game is paused, no flood protection
+ if (timeout_status == TIMEOUT_ACTIVE) // when game is paused, no flood protection
source.flood_field = flood = 0;
}
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;
}
.float modelindex_for_playersound;
- .float skinindex_for_playersound;
+ .float skin_for_playersound;
void UpdatePlayerSounds()
{
if(self.modelindex == self.modelindex_for_playersound)
- if(self.skinindex == self.skinindex_for_playersound)
+ if(self.skin == self.skin_for_playersound)
return;
self.modelindex_for_playersound = self.modelindex;
- self.skinindex_for_playersound = self.skinindex;
+ self.skin_for_playersound = self.skin;
ClearPlayerSounds();
LoadPlayerSounds("sound/player/default.sounds", 1);
if(!autocvar_g_debug_defaultsounds)
- if(!LoadPlayerSounds(get_model_datafilename(self.model, self.skinindex, "sounds"), 0))
+ if(!LoadPlayerSounds(get_model_datafilename(self.model, self.skin, "sounds"), 0))
LoadPlayerSounds(get_model_datafilename(self.model, 0, "sounds"), 0);
}
#define INDEPENDENT_ATTACK_FINISHED
- float require_spawnfunc_prefix; // if this float exists, only functions with spawnfunc_ name prefix qualify as spawn functions
+ noref float require_spawnfunc_prefix; // if this float exists, only functions with spawnfunc_ name prefix qualify as spawn functions
#define BUTTON_ATCK button0
#define BUTTON_JUMP button2
// Globals
-float ctf_score_value(string parameter);
+float ctf_ReadScore(string parameter); // SOON WON'T BE NEEDED. // FIXCTF
- float g_dm, g_domination, g_ctf, g_tdm, g_keyhunt, g_onslaught, g_assault, g_arena, g_ca, g_lms, g_runematch, g_race, g_nexball, g_cts, g_freezetag, g_keepaway;
float g_cloaked, g_footsteps, g_jump_grunt, g_grappling_hook, g_midair, g_minstagib, g_pinata, g_norecoil, g_minstagib_invis_alpha, g_bloodloss;
float g_warmup_limit;
float g_warmup_allguns;
float g_warmup_allow_timeout;
- float g_ctf_win_mode;
float g_ctf_ignore_frags;
float g_ctf_reverse;
float g_race_qualifying;
float inWarmupStage;
float g_pickup_respawntime_weapon;
+ float g_pickup_respawntime_superweapon;
float g_pickup_respawntime_ammo;
float g_pickup_respawntime_short;
float g_pickup_respawntime_medium;
float g_pickup_respawntime_long;
float g_pickup_respawntime_powerup;
float g_pickup_respawntimejitter_weapon;
+ float g_pickup_respawntimejitter_superweapon;
float g_pickup_respawntimejitter_ammo;
float g_pickup_respawntimejitter_short;
float g_pickup_respawntimejitter_medium;
.float crouch; // Crouching or not?
.float strength_finished;
- //.float speed_finished;
.float invincible_finished;
- //.float slowmo_finished;
+ .float superweapons_finished;
.vector finaldest, finalangle; //plat.qc stuff
.void() think1;
//.float cnt2;
.float play_time;
+ .float respawn_time;
.float death_time;
- .float dead_frame;
.float fade_time;
.float fade_rate;
.vector anim_die1; // player dies
.vector anim_die2; // player dies differently
.vector anim_draw; // player pulls out a weapon
- .vector anim_duck; // player crouches (from idle to duckidle)
+ // .vector anim_duck; // player crouches (from idle to duckidle)
.vector anim_duckwalk; // player walking while crouching
.vector anim_duckjump; // player jumping from a crouch
.vector anim_duckidle; // player idling while crouching
.vector anim_runbackwards; // player running backward
.vector anim_strafeleft; // player shuffling left quickly
.vector anim_straferight; // player shuffling right quickly
- .vector anim_dead1; // player dead (must be identical to last frame of die1)
- .vector anim_dead2; // player dead (must be identical to last frame of die2)
+ //.vector anim_dead1; // player dead (must be identical to last frame of die1)
+ //.vector anim_dead2; // player dead (must be identical to last frame of die2)
.vector anim_forwardright; // player running forward and right
.vector anim_forwardleft; // player running forward and left
.vector anim_backright; // player running backward and right
.vector anim_backleft; // player running back and left
.vector anim_melee; // player doing the melee action
+ .vector anim_duck; // player doing the melee action
+ .vector anim_duckwalkbackwards;
+ .vector anim_duckwalkstrafeleft;
+ .vector anim_duckwalkstraferight;
+ .vector anim_duckwalkforwardright;
+ .vector anim_duckwalkforwardleft;
+ .vector anim_duckwalkbackright;
+ .vector anim_duckwalkbackleft;
// weapon animation vectors:
.vector anim_fire1;
//.float chasecam;
.float damageforcescale;
+ #define MIN_DAMAGEEXTRARADIUS 2
+ #define MAX_DAMAGEEXTRARADIUS 16
+ .float damageextraradius;
//.float gravity;
.float watersound_finished;
.float iscreature;
+ .float damagedbycontents;
.vector oldvelocity;
.float pauseregen_finished;
.entity weaponentity;
.entity exteriorweaponentity;
.vector weaponentity_glowmod;
- .float switchweapon;
+
+ //.float weapon; // current weapon
+ .float switchweapon; // weapon requested to switch to
+ .float switchingweapon; // weapon currently being switched to (is copied from switchweapon once switch is possible)
+ .string weaponname; // name of .weapon
+
.float autoswitch;
float weapon_action(float wpn, float wrequest);
float client_hasweapon(entity cl, float wpn, float andammo, float complain);
void w_ready();
// VorteX: standalone think for weapons, so normal think on weaponentity can be reserved by weaponflashes (which needs update even player dies)
.float weapon_nextthink;
- .float weapon_forbidchange;
.void() weapon_think;
//float PLAYER_WEAPONSELECTION_DELAY = );
string w_deathtypestring;
- void(entity client, string s) centerprint_builtin = #73;
.vector dest1, dest2;
float gameover;
.float runes;
+ // Keys player is holding
+ .float itemkeys;
+ // message delay for func_door locked by keys and key locks
+ // this field is used on player entities
+ .float key_door_messagetime;
- .float welcomemessage_time;
- .float version;
- // minstagib vars
- .float jump_interval; // laser refire
+ .float version;
//swamp
.float in_swamp; // bool
// footstep interval
.float nextstep;
- .float ready;
- #define RESTART_COUNTDOWN 10
- float restart_mapalreadyrestarted; //bool, indicates whether reset_map() was already executed
- entity restartTimer;
- void restartTimer_Think();
float blockSpectators; //if set, new or existing spectators or observers will be removed unless they become a player within g_maxplayers_spectator_blocktime seconds
.float spectatortime; //point in time since the client is spectating or observing
void checkSpectatorBlock();
float nJoinAllowed(float includeMe);
#define PREVENT_JOIN_TEXT "^1You may not join the game at this time.\n\nThe player limit reached maximum capacity."
- //sv_timeout: pauses the game by setting the gamespeed to a really low value (see TIMEOUT_SLOWMO_VALUE)
- #define TIMEOUT_SLOWMO_VALUE 0.0001
- float sys_frametime; // gets initialised in worlspawn, saves the value from autocvar_sys_ticrate
- float remainingTimeoutTime; // contains the time in seconds that the active timeout has left
- float remainingLeadTime; // contains the number of seconds left of the leadtime (before the timeout starts)
- float timeoutStatus; // (values: 0, 1, 2) contains whether a timeout is not active (0), was called but still at leadtime (1) or is active (2)
- .float allowedTimeouts; // contains the number of allowed timeouts for each player
- entity timeoutInitiator; // contains the entity of the player who started the last timeout
- float orig_slowmo; // contains the value of autocvar_slowmo so that, after timeout finished, it isn't set to slowmo 1 necessarily
- .vector lastV_angle; //used when pausing the game in order to force the player to keep his old view angle fixed
- entity timeoutHandler; //responsible for centerprinting the timeout countdowns and playing sounds
- void timeoutHandler_Think();
- void evaluateTimeout();
- void evaluateTimein();
- string getTimeoutText(float addOneSecond);
-
.float spawnshieldtime;
.float lms_nextcheck;
.float() customizeentityforclient;
.float cvar_cl_handicap;
- .float cvar_cl_playerdetailreduction;
- .float cvar_scr_centertime;
+ .float cvar_cl_clippedspectating;
+ .float cvar_cl_autoscreenshot;
+ .float cvar_cl_movement_track_canjump;
+ .float cvar_cl_newusekeysupported;
+
.string cvar_g_xonoticversion;
.string cvar_cl_weaponpriority;
.string cvar_cl_weaponpriorities[10];
.float cvar_cl_forceplayermodelsfromxonotic;
float sv_clforceplayermodels;
#endif
- float sv_loddistance1;
- float sv_loddistance2;
.float cvar_cl_gunalign;
.float cvar_cl_noantilag;
.float version_nagtime;
- .float modelindex_lod0;
- .float modelindex_lod0_from_xonotic;
- .float skinindex;
- .float modelindex_lod1;
- .float modelindex_lod2;
-
#define NUM_JUMPPADSUSED 3
.float jumppadcount;
.entity jumppadsused[NUM_JUMPPADSUSED];
float startitem_failed;
-void DropFlag(entity flag, entity penalty_receiver, entity attacker);
+void ctf_Handle_Drop(entity player); // FIXCTF
void DropBall(entity ball, vector org, vector vel);
void DropAllRunes(entity pl);
float weaponsInMap;
- void centerprint_atprio(entity e, float prio, string s);
- void centerprint_expire(entity e, float prio);
- void centerprint(entity e, string s);
-
.float respawn_countdown; // next number to count
float bot_waypoints_for_items;
// speedrun: when 1, player auto teleports back when capture timeout happens
.float speedrunning;
- // Q3 support
- float q3acompat_machineshotgunswap;
-
// database
float ServerProgsDB;
float TemporaryDB;
float sv_maxidle;
float sv_maxidle_spectatorsareidle;
- float sv_pogostick;
float tracebox_hits_trigger_hurt(vector start, vector mi, vector ma, vector end);
float next_pingtime;
.float version_mismatch;
float independent_players;
+ #define INDEPENDENT_PLAYERS (autocvar__independent_players ? (autocvar__independent_players > 0) : independent_players)
#define IS_INDEPENDENT_PLAYER(e) ((e).solid == SOLID_TRIGGER)
#define MAKE_INDEPENDENT_PLAYER(e) (((e).solid = SOLID_TRIGGER) + ((e).frags = FRAGS_PLAYER_NONSOLID))
// we're using + here instead of , because fteqcc sucks
.float clip_size;
.float minelayer_mines;
+ .float grab; // 0 = can't grab, 1 = owner can grab, 2 = owner and team mates can grab, 3 = anyone can grab
+
#define PROJECTILE_MAKETRIGGER(e) (e).solid = SOLID_CORPSE; (e).dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE
// when doing this, hagar can go through clones
// #define PROJECTILE_MAKETRIGGER(e) (e).solid = SOLID_BBOX
.float misc_bulletcounter; // replaces uzi & hlac bullet counter.
void PlayerUseKey();
+
+ typedef vector(entity player, entity spot, vector current) spawn_evalfunc_t;
+ .spawn_evalfunc_t spawn_evalfunc;
+
+ .entity conveyor;
WriteByte(MSG_ENTITY, bound(0, self.dmg_radius, 255));
WriteByte(MSG_ENTITY, bound(1, self.dmg_edge, 255));
WriteShort(MSG_ENTITY, self.oldorigin_x);
+ WriteByte(MSG_ENTITY, self.species);
return TRUE;
}
- void Damage_DamageInfo(vector org, float coredamage, float edgedamage, float rad, vector force, float deathtype, entity dmgowner)
+ void Damage_DamageInfo(vector org, float coredamage, float edgedamage, float rad, vector force, float deathtype, float bloodtype, entity dmgowner)
{
// TODO maybe call this from non-edgedamage too?
// TODO maybe make the client do the particle effects for the weapons and the impact sounds using this info?
e.dmg_radius = rad;
e.dmg_force = vlen(force);
e.velocity = force;
-
e.oldorigin_x = compressShortVector(e.velocity);
+ e.species = bloodtype;
Net_LinkEntity(e, FALSE, 0.2, Damage_DamageInfo_SendEntity);
}
- #define DAMAGE_CENTERPRINT_SPACER NEWLINES
-
float checkrules_firstblood;
float yoda;
{
// regular frag
PlayerScore_Add(attacker, SP_KILLS, 1);
+ if(targ.playerid)
+ PlayerStats_Event(attacker, sprintf("kills-%d", targ.playerid), 1);
}
PlayerScore_Add(targ, SP_DEATHS, 1);
}
f = 0;
}
- else if(g_ctf)
+ else if(g_ctf) // FIXCTF
{
if(g_ctf_ignore_frags)
f = 0;
UpdateFrags(attacker, f);
}
+ string Obituary_ExtraFragInfo(entity player) // Extra fragmessage information
+ {
+ string health_output;
+ string ping_output;
+ string handicap_output;
+ string output;
+
+ 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)));
+ }
+
+ // 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;
+ }
+
string AppendItemcodes(string s, entity player)
{
float w;
void Send_KillNotification (string s1, string s2, string s3, float msg, float type)
{
WriteByte(MSG_ALL, SVC_TEMPENTITY);
- WriteByte(MSG_ALL, TE_CSQC_NOTIFY);
- WriteByte(MSG_ALL, CSQC_KILLNOTIFY);
+ WriteByte(MSG_ALL, TE_CSQC_KILLNOTIFY);
WriteString(MSG_ALL, s1);
WriteString(MSG_ALL, s2);
WriteString(MSG_ALL, s3);
}
// Function is used to send a generic centerprint whose content CSQC gets to decide (gentle version or not in the below cases)
- void Send_CSQC_Centerprint(entity e, string s1, string s2, float msg, float type)
+ void Send_CSQC_KillCenterprint(entity e, string s1, string s2, float msg, float type)
{
if (clienttype(e) == CLIENTTYPE_REAL)
{
msg_entity = e;
WRITESPECTATABLE_MSG_ONE({
WriteByte(MSG_ONE, SVC_TEMPENTITY);
- WriteByte(MSG_ONE, TE_CSQC_NOTIFY);
- WriteByte(MSG_ONE, CSQC_CENTERPRINT);
+ WriteByte(MSG_ONE, TE_CSQC_KILLCENTERPRINT);
WriteString(MSG_ONE, s1);
WriteString(MSG_ONE, s2);
WriteShort(MSG_ONE, msg);
if (deathtype == DEATH_TEAMCHANGE || deathtype == DEATH_AUTOTEAMCHANGE)
msg = ColoredTeamName(targ.team); // TODO: check if needed?
if(!g_cts) // no "killed your own dumb self" message in CTS
- Send_CSQC_Centerprint(targ, msg, "", deathtype, MSG_SUICIDE);
+ Send_CSQC_KillCenterprint(targ, msg, "", deathtype, MSG_SUICIDE);
if(deathtype != DEATH_TEAMCHANGE && deathtype != DEATH_QUIET)
{
}
else if (attacker.classname == "player")
{
- if(teamplay && attacker.team == targ.team)
+ if(!IsDifferentTeam(attacker, targ))
{
if(attacker.team == COLOR_TEAM1)
type = KILL_TEAM_RED;
GiveFrags(attacker, targ, -1, deathtype);
- Send_CSQC_Centerprint(attacker, s, "", type, MSG_KILL);
+ Send_CSQC_KillCenterprint(attacker, s, "", type, MSG_KILL);
if (targ.killcount > 2) {
msg = ftos(targ.killcount);
checkrules_firstblood = TRUE;
Send_KillNotification(a, "", "", KILL_FIRST_BLOOD, MSG_KILL);
// TODO: make these print a newline if they dont
- Send_CSQC_Centerprint(attacker, "", "", KILL_FIRST_BLOOD, MSG_KILL);
- Send_CSQC_Centerprint(targ, "", "", KILL_FIRST_VICTIM, MSG_KILL);
+ Send_CSQC_KillCenterprint(attacker, "", "", KILL_FIRST_BLOOD, MSG_KILL);
+ Send_CSQC_KillCenterprint(targ, "", "", KILL_FIRST_VICTIM, MSG_KILL);
PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD, 1);
PlayerStats_Event(targ, PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM, 1);
}
- if((autocvar_sv_fragmessage_information_typefrag) && (targ.BUTTON_CHAT)) {
- Send_CSQC_Centerprint(attacker, s, GetAdvancedDeathReports(targ), KILL_TYPEFRAG, MSG_KILL);
- Send_CSQC_Centerprint(targ, a, GetAdvancedDeathReports(attacker), KILL_TYPEFRAGGED, MSG_KILL);
+ 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 {
- Send_CSQC_Centerprint(attacker, s, GetAdvancedDeathReports(targ), KILL_FRAG, MSG_KILL);
- Send_CSQC_Centerprint(targ, a, GetAdvancedDeathReports(attacker), KILL_FRAGGED, MSG_KILL);
+ Send_CSQC_KillCenterprint(attacker, s, Obituary_ExtraFragInfo(targ), KILL_FRAG, MSG_KILL);
+ Send_CSQC_KillCenterprint(targ, a, Obituary_ExtraFragInfo(attacker), KILL_FRAGGED, MSG_KILL);
}
attacker.taunt_soundtime = time + 1;
if(g_ctf && targ.flagcarried)
{
- UpdateFrags(attacker, ctf_score_value("score_kill"));
+ UpdateFrags(attacker, ctf_ReadScore("score_kill")); // FIXCTF
PlayerScore_Add(attacker, SP_CTF_FCKILLS, 1);
GiveFrags(attacker, targ, 0, deathtype); // for logging
}
}
else
{
- Send_CSQC_Centerprint(targ, "", "", deathtype, MSG_KILL_ACTION);
+ Send_CSQC_KillCenterprint(targ, "", "", deathtype, MSG_KILL_ACTION);
if (deathtype == DEATH_HURTTRIGGER && inflictor.message != "")
msg = inflictor.message;
else if (deathtype == DEATH_CUSTOM)
if (gameover || targ.killcount == -666)
return;
- local entity oldself;
+ entity oldself;
oldself = self;
self = targ;
damage_targ = targ;
}
else
{
+ /*
+ skill based bot damage? gtfo. (tZork)
if (targ.classname == "player")
if (attacker.classname == "player")
if (!targ.isbot)
if (attacker.isbot)
damage = damage * bound(0.1, (skill + 5) * 0.1, 1);
-
+ */
+
// nullify damage if teamplay is on
if(deathtype != DEATH_TELEFRAG)
if(attacker.classname == "player")
damage = 0;
force = '0 0 0';
}
- else if(teamplay && attacker.team == targ.team)
+ else if(!IsDifferentTeam(attacker, targ))
{
if(autocvar_teamplay_mode == 1)
damage = 0;
{
vector v;
v = healtharmor_applydamage(attacker.armorvalue, autocvar_g_balance_armor_blockpercent, mirrordamage);
+ v_z = 0; // fteqcc sucks
attacker.dmg_take += v_x;
attacker.dmg_save += v_y;
attacker.dmg_inflictor = inflictor;
{
vector v;
v = healtharmor_applydamage(targ.armorvalue, autocvar_g_balance_armor_blockpercent, damage);
+ v_z = 0; // fteqcc sucks
targ.dmg_take += v_x;
targ.dmg_save += v_y;
targ.dmg_inflictor = inflictor;
damage = 0;
- if(!autocvar_g_friendlyfire_virtual_force)
- force = '0 0 0';
+ if(!autocvar_g_friendlyfire_virtual_force)
+ force = '0 0 0';
}
}
else
if (targ.armorvalue && (deathtype == WEP_MINSTANEX) && damage)
{
targ.armorvalue -= 1;
- centerprint(targ, strcat(DAMAGE_CENTERPRINT_SPACER, "^3Remaining extra lives: ",ftos(targ.armorvalue)));
+ centerprint(targ, strcat("^3Remaining extra lives: ",ftos(targ.armorvalue)));
damage = 0;
targ.hitsound += 1;
attacker.hitsound += 1; // TODO change this to a future specific hitsound for armor hit
if (targ != attacker)
{
if ((targ.health >= 1) && (targ.classname == "player"))
- centerprint(attacker, strcat(DAMAGE_CENTERPRINT_SPACER, "Secondary fire inflicts no damage!"));
+ centerprint(attacker, "Secondary fire inflicts no damage!");
force = '0 0 0';
// keep mirrorforce
attacker = targ;
damage = damage * autocvar_g_balance_selfdamagepercent; // Partial damage if the attacker hits himself
}
- // CTF: reduce damage/force
- if(g_ctf)
- if(targ == attacker)
- if(targ.flagcarried)
- {
- damage = damage * autocvar_g_ctf_flagcarrier_selfdamage;
- force = force * autocvar_g_ctf_flagcarrier_selfforce;
- }
-
if(g_runematch)
{
// apply strength rune
if(targ.takedamage == DAMAGE_AIM)
if(targ != attacker)
{
- if(targ.classname == "player")
+ if(damage_headshotbonus > 0)
{
- // HEAD SHOT:
- // find height of hit on player axis
- // if above view_ofs and below maxs, and also in the middle half of the bbox, it is head shot
- vector headmins, headmaxs, org;
- org = antilag_takebackorigin(targ, time - ANTILAG_LATENCY(attacker));
- headmins = org + GetHeadshotMins(targ);
- headmaxs = org + GetHeadshotMaxs(targ);
- if(trace_hits_box(railgun_start, railgun_end, headmins, headmaxs))
+ if(targ.classname == "player")
+ {
+ // HEAD SHOT:
+ // find height of hit on player axis
+ // if above view_ofs and below maxs, and also in the middle half of the bbox, it is head shot
+ vector headmins, headmaxs, org;
+ org = antilag_takebackorigin(targ, time - ANTILAG_LATENCY(attacker));
+ headmins = org + GetHeadshotMins(targ);
+ headmaxs = org + GetHeadshotMaxs(targ);
+ if(trace_hits_box(railgun_start, railgun_end, headmins, headmaxs))
+ {
+ deathtype |= HITTYPE_HEADSHOT;
+ }
+ }
+ else if(targ.classname == "turret_head")
{
deathtype |= HITTYPE_HEADSHOT;
}
+ if(deathtype & HITTYPE_HEADSHOT)
+ damage *= 1 + damage_headshotbonus;
}
- else if(targ.classname == "turret_head")
- {
- deathtype |= HITTYPE_HEADSHOT;
- }
- if(deathtype & HITTYPE_HEADSHOT)
- damage *= 1 + damage_headshotbonus;
entity victim;
if((targ.vehicle_flags & VHF_ISVEHICLE) && targ.owner)
if(attacker.armorvalue > 0)
{
attacker.armorvalue = attacker.armorvalue - 1;
- centerprint(attacker, strcat(DAMAGE_CENTERPRINT_SPACER, "^3Remaining extra lives: ",ftos(attacker.armorvalue)));
+ centerprint(attacker, strcat("^3Remaining extra lives: ",ftos(attacker.armorvalue)));
attacker.hitsound += 1;
}
mirrordamage = 0;
else
force = normalize(force);
if(forceintensity >= 0)
- Damage_DamageInfo(blastorigin, coredamage, edgedamage, rad, forceintensity * force, deathtype, attacker);
+ Damage_DamageInfo(blastorigin, coredamage, edgedamage, rad, forceintensity * force, deathtype, 0, attacker);
else
- Damage_DamageInfo(blastorigin, coredamage, edgedamage, -rad, (-forceintensity) * force, deathtype, attacker);
+ Damage_DamageInfo(blastorigin, coredamage, edgedamage, -rad, (-forceintensity) * force, deathtype, 0, attacker);
}
stat_damagedone = 0;
- targ = WarpZone_FindRadius (blastorigin, rad, FALSE);
+ targ = WarpZone_FindRadius (blastorigin, rad + MAX_DAMAGEEXTRARADIUS, FALSE);
while (targ)
{
next = targ.chain;
diff = targ.WarpZone_findradius_dist;
// round up a little on the damage to ensure full damage on impacts
// and turn the distance into a fraction of the radius
- power = 1 - ((vlen (diff) - 2) / rad);
+ power = 1 - ((vlen (diff) - bound(MIN_DAMAGEEXTRARADIUS, targ.damageextraradius, MAX_DAMAGEEXTRARADIUS)) / rad);
//bprint(" ");
//bprint(ftos(power));
//if (targ == attacker)
finaldmg = coredamage * power + edgedamage * (1 - power);
if (finaldmg > 0)
{
- local float a;
- local float c;
- local float hits;
- local float total;
- local float hitratio;
- local vector hitloc;
- local vector myblastorigin;
+ float a;
+ float c;
+ float hits;
+ float total;
+ float hitratio;
+ vector hitloc;
+ vector myblastorigin;
myblastorigin = WarpZone_TransformOrigin(targ, blastorigin);
center = targ.origin + (targ.mins + targ.maxs) * 0.5;
// if it's a player, use the view origin as reference
--- /dev/null
- if(g_ctf_win_mode != 2)
+// ================================================================
+// Official capture the flag game mode coding, reworked by Samual
+// Last updated: March 28th, 2011
+// ================================================================
+
+// Flag constants
+#define FLAG_MIN (PL_MIN + '0 0 -13')
+#define FLAG_MAX (PL_MAX + '0 0 -13')
+#define FLAG_CARRY_POS '-15 0 7'
+
+.entity bot_basewaypoint; // flag waypointsprite
+.entity wps_flagbase;
+.entity wps_flagcarrier;
+.entity wps_flagdropped;
+
+entity ctf_worldflaglist; // CTF flags in the map
+.entity ctf_worldflagnext;
+
+.vector ctf_spawnorigin; // stored vector for where the flag is placed on the map itself.
+
+float ctf_captimerecord; // record time for capturing the flag
+.float ctf_pickuptime;
+.float ctf_pickupid;
+.float ctf_dropperid; // don't allow spam of dropping the flag
+.float ctf_droptime;
+.float ctf_status; // status of the flag (FLAG_BASE, FLAG_DROPPED, FLAG_CARRY declared globally)
+
+
+.float next_take_time; // Delay between when the person can pick up a flag // is this obsolete from the stuff above?
+
+// CaptureShield: If the player is too bad to be allowed to capture, shield them from taking the flag.
+.float ctf_captureshielded; // set to 1 if the player is too bad to be allowed to capture
+float ctf_captureshield_min_negscore; // punish at -20 points
+float ctf_captureshield_max_ratio; // punish at most 30% of each team
+float ctf_captureshield_force; // push force of the shield
+
+// after game mode is finished, these will be changed to use #define with other entities so as to not create many more.
+
+// ==================
+// Misc CTF functions
+// ==================
+
+float ctf_ReadScore(string parameter) // make this obsolete
+{
- else
- return cvar(strcat("g_ctf_flag", parameter));
++ //if(g_ctf_win_mode != 2)
+ return cvar(strcat("g_ctf_personal", parameter));
- centerprint_atprio(player, CENTERPRIO_SHIELDING, "^3You are now ^4shielded^3 from the flag\n^3for ^1too many unsuccessful attempts^3 to capture.\n\n^3Make some defensive scores before trying again.");
++ //else
++ // return cvar(strcat("g_ctf_flag", parameter));
+}
+
+void ctf_FakeTimeLimit(entity e, float t)
+{
+ msg_entity = e;
+ WriteByte(MSG_ONE, 3); // svc_updatestat
+ WriteByte(MSG_ONE, 236); // STAT_TIMELIMIT
+ if(t < 0)
+ WriteCoord(MSG_ONE, autocvar_timelimit);
+ else
+ WriteCoord(MSG_ONE, (t + 1) / 60);
+}
+
+void ctf_EventLog(string mode, float flagteam, entity actor) // use an alias for easy changing and quick editing later
+{
+ if(autocvar_sv_eventlog)
+ GameLogEcho(strcat(":ctf:", mode, ":", ftos(flagteam), ((actor != world) ? (strcat(":", ftos(actor.playerid))) : "")));
+}
+
+
+// =======================
+// CaptureShield Functions
+// =======================
+
+float ctf_CaptureShield_CheckStatus(entity p)
+{
+ float s, se;
+ entity e;
+ float players_worseeq, players_total;
+
+ if(ctf_captureshield_max_ratio <= 0)
+ return FALSE;
+
+ s = PlayerScore_Add(p, SP_SCORE, 0);
+ if(s >= -ctf_captureshield_min_negscore)
+ return FALSE;
+
+ players_total = players_worseeq = 0;
+ FOR_EACH_PLAYER(e)
+ {
+ if(e.team != p.team)
+ continue;
+ se = PlayerScore_Add(e, SP_SCORE, 0);
+ if(se <= s)
+ ++players_worseeq;
+ ++players_total;
+ }
+
+ // player is in the worse half, if >= half the players are better than him, or consequently, if < half of the players are worse
+ // use this rule here
+
+ if(players_worseeq >= players_total * ctf_captureshield_max_ratio)
+ return FALSE;
+
+ return TRUE;
+}
+
+void ctf_CaptureShield_Update(entity player, float wanted_status)
+{
+ float updated_status = ctf_CaptureShield_CheckStatus(player);
+ if((wanted_status == player.ctf_captureshielded) && (updated_status != wanted_status)) // 0: shield only, 1: unshield only
+ {
+ if(updated_status) // TODO csqc notifier for this // Samual: How?
- centerprint_atprio(player, CENTERPRIO_SHIELDING, "^3You are now free.\n\n^3Feel free to ^1try to capture^3 the flag again\n^3if you think you will succeed.");
++ Send_CSQC_Centerprint_Generic(player, CPID_CTF_CAPTURESHIELD, "^3You are now ^4shielded^3 from the flag\n^3for ^1too many unsuccessful attempts^3 to capture.\n\n^3Make some defensive scores before trying again.", 5, 0);
+ else
- centerprint_atprio(other, CENTERPRIO_SHIELDING, "^3You are ^4shielded^3 from the flag\n^3for ^1too many unsuccessful attempts^3 to capture.\n\n^3Get some defensive scores before trying again.");
++ Send_CSQC_Centerprint_Generic(player, CPID_CTF_CAPTURESHIELD, "^3You are now free.\n\n^3Feel free to ^1try to capture^3 the flag again\n^3if you think you will succeed.", 5, 0);
+
+ player.ctf_captureshielded = updated_status;
+ }
+}
+
+float ctf_CaptureShield_Customize()
+{
+ if not(other.ctf_captureshielded)
+ return FALSE;
+ if(self.team == other.team)
+ return FALSE;
+ return TRUE;
+}
+
+void ctf_CaptureShield_Touch()
+{
+ if not(other.ctf_captureshielded)
+ return;
+ if(self.team == other.team)
+ return;
+ vector mymid;
+ vector othermid;
+ mymid = (self.absmin + self.absmax) * 0.5;
+ othermid = (other.absmin + other.absmax) * 0.5;
+ Damage(other, self, self, 0, DEATH_HURTTRIGGER, mymid, normalize(othermid - mymid) * ctf_captureshield_force);
- g_ctf_win_mode = cvar("g_ctf_win_mode");
++ Send_CSQC_Centerprint_Generic(other, CPID_CTF_CAPTURESHIELD, "^3You are ^4shielded^3 from the flag\n^3for ^1too many unsuccessful attempts^3 to capture.\n\n^3Get some defensive scores before trying again.", 5, 0);
+}
+
+void ctf_CaptureShield_Spawn(entity flag)
+{
+ entity e;
+ e = spawn();
+ e.enemy = self;
+ e.team = self.team;
+ e.touch = ctf_CaptureShield_Touch;
+ e.customizeentityforclient = ctf_CaptureShield_Customize;
+ e.classname = "ctf_captureshield";
+ e.effects = EF_ADDITIVE;
+ e.movetype = MOVETYPE_NOCLIP;
+ e.solid = SOLID_TRIGGER;
+ e.avelocity = '7 0 11';
+ setorigin(e, self.origin);
+ setmodel(e, "models/ctf/shield.md3");
+ e.scale = 0.5;
+ setsize(e, e.scale * e.mins, e.scale * e.maxs);
+}
+
+
+// ==============
+// Event Handlers
+// ==============
+
+void ctf_Handle_Drop(entity player)
+{
+ entity flag = player.flagcarried;
+
+ if(!flag) { return; }
+ if(flag.speedrunning) { ctf_RespawnFlag(flag); return; }
+
+ // reset the flag
+ setattachment(flag, world, "");
+ setorigin(flag, player.origin - '0 0 24' + '0 0 37');
+ flag.owner.flagcarried = world;
+ flag.owner = world;
+ flag.movetype = MOVETYPE_TOSS;
+ flag.solid = SOLID_TRIGGER;
+ flag.takedamage = DAMAGE_YES;
+ flag.velocity = ('0 0 200' + ('0 100 0' * crandom()) + ('100 0 0' * crandom()));
+ flag.pain_finished = time + autocvar_g_ctf_flag_returntime; // replace this later
+
+ flag.ctf_droptime = time;
+ flag.ctf_dropperid = player.playerid;
+ flag.ctf_status = FLAG_DROPPED;
+
+ // messages and sounds
+ Send_KillNotification(player.netname, flag.netname, "", INFO_LOSTFLAG, MSG_INFO);
+ sound(flag, CH_TRIGGER, flag.noise4, VOL_BASE, ATTN_NONE);
+ ctf_EventLog("dropped", player.team, player);
+
+ // scoring
+ PlayerTeamScore_AddScore(player, -ctf_ReadScore("penalty_drop"));
+ PlayerScore_Add(player, SP_CTF_DROPS, 1);
+
+ // waypoints
+ WaypointSprite_Spawn("flagdropped", 0, 0, flag, '0 0 64', world, player.team, flag, wps_flagdropped, FALSE, RADARICON_FLAG, '0 1 1'); // (COLOR_TEAM1 + COLOR_TEAM2 - flag.team)
+ WaypointSprite_Ping(player.wps_flagcarrier);
+ WaypointSprite_Kill(player.wps_flagcarrier);
+
+ // captureshield
+ ctf_CaptureShield_Update(player, 0); // shield only
+
+ // check if the flag will fall off the map
+ trace_startsolid = FALSE;
+ tracebox(flag.origin, flag.mins, flag.maxs, flag.origin, TRUE, flag);
+ if(trace_startsolid)
+ dprint("FLAG FALLTHROUGH will happen SOON\n");
+}
+
+void ctf_Handle_Capture(entity flag, entity player)
+{
+ // declarations
+ float cap_time, cap_record, success;
+ string cap_message, refername;
+
+ // records
+ if((autocvar_g_ctf_captimerecord_always) || (player_count - currentbots)) {
+ cap_record = ctf_captimerecord;
+ cap_time = (time - player.flagcarried.ctf_pickuptime);
+
+ refername = db_get(ServerProgsDB, strcat(GetMapname(), "/captimerecord/netname"));
+ refername = ((refername == player.netname) ? "their" : strcat(refername, "^7's"));
+
+ if(!ctf_captimerecord)
+ { cap_message = strcat(" in ", ftos_decimals(cap_time, 2), " seconds"); success = TRUE; }
+ else if(cap_time < cap_record)
+ { cap_message = strcat(" in ", ftos_decimals(cap_time, 2), " seconds, breaking ", refername, " previous record of ", ftos_decimals(cap_record, 2), " seconds"); success = TRUE; }
+ else
+ { cap_message = strcat(" in ", ftos_decimals(cap_time, 2), " seconds, failing to break ", refername, " record of ", ftos_decimals(cap_record, 2), " seconds"); success = FALSE; }
+
+ if(success) {
+ ctf_captimerecord = cap_time;
+ db_put(ServerProgsDB, strcat(GetMapname(), "/captimerecord/time"), ftos(cap_time));
+ db_put(ServerProgsDB, strcat(GetMapname(), "/captimerecord/netname"), player.netname);
+ write_recordmarker(player, (time - cap_time), cap_time); } }
+
+ // messages and sounds
+ Send_KillNotification(player.netname, player.flagcarried.netname, cap_message, INFO_CAPTUREFLAG, MSG_INFO);
+ sound(player, CH_TRIGGER, flag.noise2, VOL_BASE, ATTN_NONE); // "ctf/*_capture.wav"
+ ctf_EventLog("capture", player.flagcarried.team, player);
+
+ // scoring
+ PlayerTeamScore_AddScore(player, ctf_ReadScore("score_capture"));
+ PlayerTeamScore_Add(player, SP_CTF_CAPS, ST_CTF_CAPS, 1);
+
+ // effects
+ if (autocvar_g_ctf_flag_capture_effects)
+ {
+ pointparticles(particleeffectnum((player.team == COLOR_TEAM1) ? "red_ground_quake" : "blue_ground_quake"), flag.origin, '0 0 0', 1);
+ //shockwave_spawn("models/ctf/shockwavetransring.md3", flag.origin - '0 0 15', -0.8, 0, 1);
+ }
+
+ // waypointsprites
+ WaypointSprite_Kill(player.wps_flagcarrier);
+
+ // reset the flag
+ if(flag.speedrunning) { ctf_FakeTimeLimit(player, -1); }
+
+ ctf_RespawnFlag(player.flagcarried);
+}
+
+void ctf_Handle_Return(entity flag, entity player)
+{
+ // messages and sounds
+ Send_KillNotification (player.netname, flag.netname, "", INFO_RETURNFLAG, MSG_INFO);
+ sound(player, CH_TRIGGER, flag.noise1, VOL_BASE, ATTN_NONE);
+ ctf_EventLog("return", flag.team, player);
+
+ // scoring
+ PlayerTeamScore_AddScore(player, ctf_ReadScore(strcat("score_return", ((player.playerid == flag.playerid) ? "_by_killer" : "")))); // reward for return
+ PlayerScore_Add(player, SP_CTF_RETURNS, 1); // add to count of returns
+
+ TeamScore_AddToTeam(((flag.team == COLOR_TEAM1) ? COLOR_TEAM2 : COLOR_TEAM1), ST_SCORE, -ctf_ReadScore("penalty_returned")); // punish the team who was last carrying it
+ FOR_EACH_PLAYER(player) if(player.playerid == flag.ctf_dropperid) // punish the player who dropped the flag
+ {
+ PlayerScore_Add(player, SP_SCORE, -ctf_ReadScore("penalty_returned"));
+ ctf_CaptureShield_Update(player, 0); // shield only
+ }
+
+ // waypointsprites
+ WaypointSprite_Kill(flag.wps_flagdropped);
+
+ // reset the flag
+ ctf_RespawnFlag(flag);
+}
+
+void ctf_Handle_Pickup_Base(entity flag, entity player)
+{
+ entity tmp_player; // temporary entity which the FOR_EACH_PLAYER loop uses to scan players
+ string verbosename; // holds the name of the player OR no name at all for printing in the centerprints
+
+ // attach the flag to the player
+ flag.owner = player;
+ player.flagcarried = flag;
+ setattachment(flag, player, "");
+ setorigin(flag, FLAG_CARRY_POS);
+
+ // set up the flag
+ flag.movetype = MOVETYPE_NONE;
+ flag.takedamage = DAMAGE_NO;
+ flag.solid = SOLID_NOT;
+ flag.angles = '0 0 0';
+ flag.ctf_pickuptime = time; // used for timing runs
+ flag.ctf_pickupid = player.playerid;
+ flag.ctf_status = FLAG_CARRY;
+
+ // messages and sounds
+ Send_KillNotification (player.netname, flag.netname, "", INFO_GOTFLAG, MSG_INFO);
+ sound(player, CH_TRIGGER, flag.noise, VOL_BASE, ATTN_NONE);
+ ctf_EventLog("steal", flag.team, player);
+ verbosename = ((autocvar_g_ctf_flag_pickup_verbosename) ? strcat("(", player.netname, ")") : ""); // replace TRUE with an autocvar for it.
+ FOR_EACH_PLAYER(tmp_player)
+ if(tmp_player.team == flag.team)
+ centerprint(tmp_player, strcat("The enemy ", verbosename, "got your flag! Retrieve it!"));
+ else if((tmp_player.team == player.team) && (tmp_player != player))
+ centerprint(tmp_player, strcat("Your team mate ", verbosename, "got the flag! Protect them!"));
+
+ // scoring
+ PlayerTeamScore_AddScore(player, ctf_ReadScore("score_pickup_base"));
+ PlayerScore_Add(player, SP_CTF_PICKUPS, 1);
+
+ // speedrunning
+ flag.speedrunning = player.speedrunning; // if speedrunning, flag will flag-return and teleport the owner back after the record
+ if((player.speedrunning) && (ctf_captimerecord))
+ ctf_FakeTimeLimit(player, time + ctf_captimerecord);
+
+ // effects
+ if (autocvar_g_ctf_flag_pickup_effects)
+ {
+ pointparticles(particleeffectnum("smoke_ring"), 0.5 * (flag.absmin + flag.absmax), '0 0 0', 1);
+ }
+
+ // waypoints
+ WaypointSprite_Spawn("flagcarrier", 0, 0, player, '0 0 64', world, player.team, player, wps_flagcarrier, FALSE, RADARICON_FLAG, '1 1 0'); // (COLOR_TEAM1 + COLOR_TEAM2 - flag.team)
+ WaypointSprite_UpdateMaxHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(start_health, start_armorvalue, autocvar_g_balance_armor_blockpercent) * 2);
+ WaypointSprite_UpdateHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(player.health, player.armorvalue, autocvar_g_balance_armor_blockpercent));
+ WaypointSprite_UpdateTeamRadar(player.wps_flagcarrier, RADARICON_FLAGCARRIER, '1 1 0');
+ WaypointSprite_Ping(player.wps_flagcarrier);
+}
+
+void ctf_Handle_Pickup_Dropped(entity flag, entity player) // make sure this works
+{
+ // declarations
+ float returnscore = bound(0, (flag.pain_finished - time) / autocvar_g_ctf_flag_returntime, 1); // can this be division by zero?
+ entity tmp_player; // temporary entity which the FOR_EACH_PLAYER loop uses to scan players
+ string verbosename; // holds the name of the player OR no name at all for printing in the centerprints
+
+ // attach the flag to the player
+ flag.owner = player;
+ player.flagcarried = flag;
+ setattachment(flag, player, "");
+ setorigin(flag, FLAG_CARRY_POS);
+
+ // set up the flag
+ flag.movetype = MOVETYPE_NONE;
+ flag.takedamage = DAMAGE_NO;
+ flag.solid = SOLID_NOT;
+ flag.angles = '0 0 0';
+ //flag.ctf_pickuptime = time; // don't update pickuptime since this isn't a real steal.
+ flag.ctf_pickupid = player.playerid;
+ flag.ctf_status = FLAG_CARRY;
+
+ // messages and sounds
+ Send_KillNotification (player.netname, flag.netname, "", INFO_PICKUPFLAG, MSG_INFO);
+ sound (player, CH_TRIGGER, flag.noise, VOL_BASE, ATTN_NONE);
+ ctf_EventLog("pickup", flag.team, player);
+ verbosename = ((autocvar_g_ctf_flag_pickup_verbosename) ? strcat("(", player.netname, ")") : "");
+ FOR_EACH_PLAYER(tmp_player)
+ if(tmp_player.team == flag.team)
+ centerprint(tmp_player, strcat("The enemy ", verbosename, "got your flag! Retrieve it!"));
+ else if((tmp_player.team == player.team) && (tmp_player != player))
+ centerprint(tmp_player, strcat("Your team mate ", verbosename, "got the flag! Protect them!"));
+
+ // scoring
+ returnscore = floor((ctf_ReadScore("score_pickup_dropped_late") * (1-returnscore) + ctf_ReadScore("score_pickup_dropped_early") * returnscore) + 0.5);
+ print("score is ", ftos(returnscore), "\n");
+ PlayerTeamScore_AddScore(player, returnscore);
+ PlayerScore_Add(player, SP_CTF_PICKUPS, 1);
+
+ // effects
+ if (autocvar_g_ctf_flag_pickup_effects) // field pickup effect
+ {
+ pointparticles(particleeffectnum("smoke_ring"), 0.5 * (flag.absmin + flag.absmax), '0 0 0', 1);
+ }
+
+ // waypoints
+ WaypointSprite_Kill(flag.wps_flagdropped);
+ WaypointSprite_Spawn("flagcarrier", 0, 0, player, '0 0 64', world, player.team, player, wps_flagcarrier, FALSE, RADARICON_FLAG, '1 1 0'); // (COLOR_TEAM1 + COLOR_TEAM2 - flag.team)
+ WaypointSprite_UpdateMaxHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(start_health, start_armorvalue, autocvar_g_balance_armor_blockpercent) * 2);
+ WaypointSprite_UpdateHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(player.health, player.armorvalue, autocvar_g_balance_armor_blockpercent));
+ WaypointSprite_UpdateTeamRadar(player.wps_flagcarrier, RADARICON_FLAGCARRIER, '1 1 0');
+ WaypointSprite_Ping(player.wps_flagcarrier);
+}
+
+
+// ===================
+// Main Flag Functions
+// ===================
+
+void ctf_FlagThink()
+{
+ // declarations
+ entity tmp_entity;
+
+ self.nextthink = time + 0.1; // only 10 fps, more is unnecessary.
+
+ // captureshield
+ if(self == ctf_worldflaglist) // only for the first flag
+ FOR_EACH_CLIENT(tmp_entity)
+ ctf_CaptureShield_Update(tmp_entity, 1); // release shield only
+
+ // sanity checks
+ if(self.mins != FLAG_MIN || self.maxs != FLAG_MAX) { // reset the flag boundaries in case it got squished
+ dprint("wtf the flag got squished?\n");
+ tracebox(self.origin, FLAG_MIN, FLAG_MAX, self.origin, MOVE_NOMONSTERS, self);
+ if(!trace_startsolid) // can we resize it without getting stuck?
+ setsize(self, FLAG_MIN, FLAG_MAX); }
+
+ if(self.owner.classname != "player" || (self.owner.deadflag) || (self.owner.flagcarried != self)) {
+ dprint("CANNOT HAPPEN - player dead and STILL had a flag!\n");
+ ctf_Handle_Drop(self.owner);
+ return; }
+
+ // main think method
+ switch(self.ctf_status)
+ {
+ case FLAG_BASE: // nothing to do here
+ return;
+
+ case FLAG_DROPPED:
+ // flag fallthrough? FIXME remove this if bug is really fixed now
+ if(self.origin_z < -131072)
+ {
+ dprint("FLAG FALLTHROUGH just happened\n");
+ self.pain_finished = 0;
+ }
+ setattachment(self, world, "");
+ if(time > self.pain_finished)
+ {
+ bprint("The ", self.netname, " has returned to base\n");
+ sound (self, CH_TRIGGER, self.noise3, VOL_BASE, ATTN_NONE);
+ ctf_EventLog("returned", self.team, world);
+ ctf_RespawnFlag(self);
+ }
+ return;
+
+ case FLAG_CARRY:
+ if((self.owner) && (self.speedrunning) && (ctf_captimerecord) && (time >= self.ctf_pickuptime + ctf_captimerecord))
+ {
+ bprint("The ", self.netname, " became impatient after ", ftos_decimals(ctf_captimerecord, 2), " seconds and returned itself\n");
+ sound (self, CH_TRIGGER, self.noise3, VOL_BASE, ATTN_NONE);
+
+ self.owner.impulse = 141; // returning!
+
+ tmp_entity = self;
+ self = self.owner;
+ ctf_RespawnFlag(tmp_entity);
+ ImpulseCommands();
+ self = tmp_entity;
+ }
+ return;
+
+ default: // this should never happen
+ dprint("Think: Flag exists with no status?\n");
+ return;
+ }
+}
+
+void ctf_FlagTouch()
+{
+ if(gameover) { return; }
+ if(!self) { return; }
+ if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
+ { // The flag fell off the map, respawn it since players can't get to it
+ //ctf_RespawnFlag(self);
+ return;
+ }
+ if(other.deadflag != DEAD_NO) { return; }
+ if(other.classname != "player")
+ { // The flag just touched an object, most likely the world
+ pointparticles(particleeffectnum("kaball_sparks"), self.origin, '0 0 0', 1);
+ sound(self, CH_TRIGGER, "keepaway/touch.wav", VOL_BASE, ATTN_NORM);
+ return;
+ }
+ else if(self.wait > time) { return; }
+
+ switch(self.ctf_status)
+ {
+ case FLAG_BASE:
+ if((other.team == self.team) && (other.flagcarried) && (other.flagcarried.team != self.team))
+ ctf_Handle_Capture(self, other); // other just captured the enemies flag to his base
+ else if((other.team != self.team) && (!other.flagcarried) && (!other.ctf_captureshielded))
+ ctf_Handle_Pickup_Base(self, other); // other just stole the enemies flag
+ break;
+
+ case FLAG_DROPPED:
+ if(other.team == self.team)
+ ctf_Handle_Return(self, other); // other just returned his own flag
+ else if((!other.flagcarried) && ((other.playerid != self.ctf_dropperid) || (time > self.ctf_droptime + autocvar_g_balance_ctf_delay_collect)))
+ ctf_Handle_Pickup_Dropped(self, other); // other just picked up a dropped enemy flag
+ break;
+
+ case FLAG_CARRY:
+ dprint("Someone touched a flag even though it was being carried?\n");
+ break;
+
+ default: // this should never happen
+ dprint("Touch: Flag exists with no status?\n");
+ break;
+ }
+}
+
+void ctf_RespawnFlag(entity flag)
+{
+ // reset the player (if there is one)
+ if((flag.owner) && (flag.owner.flagcarried == flag))
+ {
+ WaypointSprite_Kill(flag.wps_flagcarrier);
+ flag.owner.flagcarried = world;
+
+ if(flag.speedrunning)
+ ctf_FakeTimeLimit(flag.owner, -1);
+ }
+
+ // reset the flag
+ setattachment(flag, world, "");
+ setorigin(flag, flag.ctf_spawnorigin); // replace with flag.ctf_spawnorigin
+ flag.movetype = ((flag.noalign) ? MOVETYPE_NONE : MOVETYPE_TOSS);
+ flag.takedamage = DAMAGE_NO;
+ flag.solid = SOLID_TRIGGER;
+ flag.velocity = '0 0 0';
+ flag.angles = flag.mangle;
+ flag.ctf_status = FLAG_BASE;
+ flag.flags = FL_ITEM | FL_NOTARGET;
+ flag.owner = world;
+}
+
+void ctf_Reset()
+{
+ if(self.owner)
+ if(self.owner.classname == "player")
+ ctf_Handle_Drop(self.owner);
+
+ ctf_RespawnFlag(self);
+}
+
+void ctf_SetupFlag(float teamnumber, entity flag) // called when spawning a flag entity on the map as a spawnfunc
+{
+ // declarations
+ teamnumber = fabs(teamnumber - bound(0, g_ctf_reverse, 1)); // if we were originally 1, this will become 0. If we were originally 0, this will become 1.
+
+ // main setup
+ flag.ctf_worldflagnext = ctf_worldflaglist; // link flag into ctf_worldflaglist // todo: find out if this can be simplified
+ ctf_worldflaglist = flag;
+
+ setattachment(flag, world, "");
+
+ flag.netname = ((teamnumber) ? "^1RED^7 flag" : "^4BLUE^7 flag");
+ flag.team = ((teamnumber) ? COLOR_TEAM1 : COLOR_TEAM2); // COLOR_TEAM1: color 4 team (red) - COLOR_TEAM2: color 13 team (blue)
+ flag.items = ((teamnumber) ? IT_KEY2 : IT_KEY1); // IT_KEY2: gold key (redish enough) - IT_KEY1: silver key (bluish enough)
+ flag.classname = "item_flag_team";
+ flag.target = "###item###"; // wut?
+ flag.flags = FL_ITEM | FL_NOTARGET;
+ flag.solid = SOLID_TRIGGER;
+ flag.velocity = '0 0 0';
+ flag.ctf_status = FLAG_BASE;
+ flag.ctf_spawnorigin = flag.origin;
+ flag.mangle = flag.angles;
+ flag.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
+
+ if(flag.spawnflags & 1) // I don't understand what all this is about.
+ {
+ flag.noalign = TRUE;
+ flag.movetype = MOVETYPE_NONE;
+ print("This map was loaded with flags using MOVETYPE_NONE\n");
+ }
+ else
+ {
+ flag.noalign = FALSE;
+ flag.movetype = MOVETYPE_TOSS;
+ print("This map was loaded with flags using MOVETYPE_TOSS\n");
+ }
+
+ flag.reset = ctf_Reset;
+ flag.touch = ctf_FlagTouch;
+
+ // appearence
+ if(!flag.model) { flag.model = ((teamnumber) ? autocvar_g_ctf_flag_red_model : autocvar_g_ctf_flag_blue_model); }
+ setmodel (flag, flag.model); // precision set below
+ setsize(flag, FLAG_MIN, FLAG_MAX);
+ setorigin(flag, flag.origin);
+ if(!flag.scale) { flag.scale = 0.6; }
+
+ flag.skin = ((teamnumber) ? autocvar_g_ctf_flag_red_skin : autocvar_g_ctf_flag_blue_skin);
+
+ if(autocvar_g_ctf_flag_glowtrails)
+ {
+ flag.glow_color = ((teamnumber) ? 251 : 210); // 251: red - 210: blue
+ flag.glow_size = 25;
+ flag.glow_trail = 1;
+ }
+
+ flag.effects |= EF_LOWPRECISION;
+ if(autocvar_g_ctf_fullbrightflags) { flag.effects |= EF_FULLBRIGHT; }
+ if(autocvar_g_ctf_dynamiclights) { flag.effects |= ((teamnumber) ? EF_RED : EF_BLUE); }
+
+ // sound
+ if(!flag.noise) { flag.noise = ((teamnumber) ? "ctf/red_taken.wav" : "ctf/blue_taken.wav"); }
+ if(!flag.noise1) { flag.noise1 = ((teamnumber) ? "ctf/red_returned.wav" : "ctf/blue_returned.wav"); }
+ if(!flag.noise2) { flag.noise2 = ((teamnumber) ? "ctf/red_capture.wav" : "ctf/blue_capture.wav"); } // blue team scores by capturing the red flag
+ if(!flag.noise3) { flag.noise3 = "ctf/flag_respawn.wav"; } // if there is ever a team-based sound for this, update the code to match.
+ if(!flag.noise4) { flag.noise4 = ((teamnumber) ? "ctf/red_dropped.wav" : "ctf/blue_dropped.wav"); }
+
+ // precache
+ precache_sound(flag.noise);
+ precache_sound(flag.noise1);
+ precache_sound(flag.noise2);
+ precache_sound(flag.noise3);
+ precache_sound(flag.noise4);
+ precache_model(flag.model);
+ precache_model("models/ctf/shield.md3");
+ precache_model("models/ctf/shockwavetransring.md3");
+
+ // bot waypoints
+ waypoint_spawnforitem_force(flag, flag.origin);
+ flag.nearestwaypointtimeout = 0; // activate waypointing again
+ flag.bot_basewaypoint = flag.nearestwaypoint;
+
+ // waypointsprites
+ WaypointSprite_SpawnFixed(((teamnumber) ? "redbase" : "bluebase"), flag.origin + '0 0 64', flag, wps_flagbase, RADARICON_FLAG, colormapPaletteColor(((teamnumber) ? COLOR_TEAM1 : COLOR_TEAM2) - 1, FALSE));
+ WaypointSprite_UpdateTeamRadar(flag.wps_flagbase, RADARICON_FLAG, colormapPaletteColor(((teamnumber) ? COLOR_TEAM1 : COLOR_TEAM2) - 1, FALSE));
+
+ // captureshield setup
+ ctf_CaptureShield_Spawn(flag);
+}
+
+
+// ==============
+// Hook Functions
+// ==============
+
+// g_ctf_ignore_frags
+
+MUTATOR_HOOKFUNCTION(ctf_RemovePlayer)
+{
+ if(self.flagcarried) { ctf_Handle_Drop(self); }
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(ctf_PlayerPreThink)
+{
+ entity flag;
+
+ // initially clear items so they can be set as necessary later.
+ self.items &~= (IT_RED_FLAG_CARRYING | IT_RED_FLAG_TAKEN | IT_RED_FLAG_LOST
+ | IT_BLUE_FLAG_CARRYING | IT_BLUE_FLAG_TAKEN | IT_BLUE_FLAG_LOST | IT_CTF_SHIELDED);
+
+ // item for stopping players from capturing the flag too often
+ if(self.ctf_captureshielded)
+ self.items |= IT_CTF_SHIELDED;
+
+ // scan through all the flags and notify the client about them
+ for (flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext)
+ {
+ if(flag.ctf_status == FLAG_CARRY)
+ if(flag.owner == self)
+ self.items |= ((flag.items & IT_KEY2) ? IT_RED_FLAG_CARRYING : IT_BLUE_FLAG_CARRYING); // carrying: self is currently carrying the flag
+ else
+ self.items |= ((flag.items & IT_KEY2) ? IT_RED_FLAG_TAKEN : IT_BLUE_FLAG_TAKEN); // taken: someone on self's team is carrying the flag
+ else if(flag.ctf_status == FLAG_DROPPED)
+ self.items |= ((flag.items & IT_KEY2) ? IT_RED_FLAG_LOST : IT_BLUE_FLAG_LOST); // lost: the flag is dropped somewhere on the map
+ }
+
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(ctf_PlayerDamage) // for changing damage and force values that are applied to players in g_damage.qc
+{ /*
+ if(frag_attacker.flagcarried) // if the attacker is a flagcarrier
+ {
+ if(frag_target == frag_attacker) // damage done to yourself
+ {
+ frag_damage *= autocvar_g_ctf_flagcarrier_selfdamagefactor;
+ frag_force *= autocvar_g_ctf_flagcarrier_selfforcefactor;
+ }
+ else // damage done to noncarriers
+ {
+ frag_damage *= autocvar_g_ctf_flagcarrier_damagefactor;
+ frag_force *= autocvar_g_ctf_flagcarrier_forcefactor;
+ }
+ }*/
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(ctf_GiveFragsForKill)
+{
+ frag_score = 0; // no frags counted in keepaway
+ return (g_ctf_ignore_frags); // you deceptive little bugger ;3 This needs to be true in order for this function to even count.
+}
+
+MUTATOR_HOOKFUNCTION(ctf_PlayerUseKey)
+{
+ if(autocvar_g_ctf_allow_drop)
+ ctf_Handle_Drop(self);
+
+ return 0;
+}
+
+// ==========
+// Spawnfuncs
+// ==========
+
+/*QUAKED spawnfunc_info_player_team1 (1 0 0) (-16 -16 -24) (16 16 24)
+CTF Starting point for a player in team one (Red).
+Keys: "angle" viewing angle when spawning. */
+void spawnfunc_info_player_team1()
+{
+ if(g_assault) { remove(self); return; }
+
+ self.team = COLOR_TEAM1; // red
+ spawnfunc_info_player_deathmatch();
+}
+
+
+/*QUAKED spawnfunc_info_player_team2 (1 0 0) (-16 -16 -24) (16 16 24)
+CTF Starting point for a player in team two (Blue).
+Keys: "angle" viewing angle when spawning. */
+void spawnfunc_info_player_team2()
+{
+ if(g_assault) { remove(self); return; }
+
+ self.team = COLOR_TEAM2; // blue
+ spawnfunc_info_player_deathmatch();
+}
+
+/*QUAKED spawnfunc_info_player_team3 (1 0 0) (-16 -16 -24) (16 16 24)
+CTF Starting point for a player in team three (Yellow).
+Keys: "angle" viewing angle when spawning. */
+void spawnfunc_info_player_team3()
+{
+ if(g_assault) { remove(self); return; }
+
+ self.team = COLOR_TEAM3; // yellow
+ spawnfunc_info_player_deathmatch();
+}
+
+
+/*QUAKED spawnfunc_info_player_team4 (1 0 0) (-16 -16 -24) (16 16 24)
+CTF Starting point for a player in team four (Purple).
+Keys: "angle" viewing angle when spawning. */
+void spawnfunc_info_player_team4()
+{
+ if(g_assault) { remove(self); return; }
+
+ self.team = COLOR_TEAM4; // purple
+ spawnfunc_info_player_deathmatch();
+}
+
+/*QUAKED spawnfunc_item_flag_team1 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
+CTF flag for team one (Red). Multiple flags are allowed.
+Keys:
+"angle" Angle the flag will point (minus 90 degrees)...
+"model" model to use, note this needs red and blue as skins 0 and 1 (default models/ctf/flag.md3)...
+"noise" sound played when flag is picked up (default ctf/take.wav)...
+"noise1" sound played when flag is returned by a teammate (default ctf/return.wav)...
+"noise2" sound played when flag is captured (default ctf/redcapture.wav)...
+"noise3" sound played when flag is lost in the field and respawns itself (default ctf/respawn.wav)... */
+void spawnfunc_item_flag_team1()
+{
+ if(!g_ctf) { remove(self); return; }
+
+ ctf_SetupFlag(1, self); // 1 = red
+}
+
+/*QUAKED spawnfunc_item_flag_team2 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
+CTF flag for team two (Blue). Multiple flags are allowed.
+Keys:
+"angle" Angle the flag will point (minus 90 degrees)...
+"model" model to use, note this needs red and blue as skins 0 and 1 (default models/ctf/flag.md3)...
+"noise" sound played when flag is picked up (default ctf/take.wav)...
+"noise1" sound played when flag is returned by a teammate (default ctf/return.wav)...
+"noise2" sound played when flag is captured (default ctf/redcapture.wav)...
+"noise3" sound played when flag is lost in the field and respawns itself (default ctf/respawn.wav)... */
+void spawnfunc_item_flag_team2()
+{
+ if(!g_ctf) { remove(self); return; }
+
+ ctf_SetupFlag(0, self); // the 0 is misleading, but -- 0 = blue.
+}
+
+/*QUAKED spawnfunc_ctf_team (0 .5 .8) (-16 -16 -24) (16 16 32)
+Team declaration for CTF gameplay, this allows you to decide what team names and control point models are used in your map.
+Note: If you use spawnfunc_ctf_team entities you must define at least 2! However, unlike domination, you don't need to make a blank one too.
+Keys:
+"netname" Name of the team (for example Red, Blue, Green, Yellow, Life, Death, Offense, Defense, etc)...
+"cnt" Scoreboard color of the team (for example 4 is red and 13 is blue)... */
+void spawnfunc_ctf_team()
+{
+ if(!g_ctf) { remove(self); return; }
+
+ self.classname = "ctf_team";
+ self.team = self.cnt + 1;
+}
+
+
+// ==============
+// Initialization
+// ==============
+
+// code from here on is just to support maps that don't have flag and team entities
+void ctf_SpawnTeam (string teamname, float teamcolor)
+{
+ entity oldself;
+ oldself = self;
+ self = spawn();
+ self.classname = "ctf_team";
+ self.netname = teamname;
+ self.cnt = teamcolor;
+
+ spawnfunc_ctf_team();
+
+ self = oldself;
+}
+
+void ctf_DelayedInit() // Do this check with a delay so we can wait for teams to be set up.
+{
+ // if no teams are found, spawn defaults
+ if(find(world, classname, "ctf_team") == world)
+ {
+ print("NO TEAMS FOUND FOR CTF! creating them anyway.\n");
+ ctf_SpawnTeam("Red", COLOR_TEAM1 - 1);
+ ctf_SpawnTeam("Blue", COLOR_TEAM2 - 1);
+ }
+
+ ScoreRules_ctf();
+}
+
+void ctf_Initialize()
+{
+ ctf_captimerecord = stof(db_get(ServerProgsDB, strcat(GetMapname(), "/captimerecord/time")));
+
+ ctf_captureshield_min_negscore = autocvar_g_ctf_shield_min_negscore;
+ ctf_captureshield_max_ratio = autocvar_g_ctf_shield_max_ratio;
+ ctf_captureshield_force = autocvar_g_ctf_shield_force;
+
++ //g_ctf_win_mode = cvar("g_ctf_win_mode");
+
+ InitializeEntity(world, ctf_DelayedInit, INITPRIO_GAMETYPE);
+}
+
+
+MUTATOR_DEFINITION(gamemode_ctf)
+{
+ MUTATOR_HOOK(MakePlayerObserver, ctf_RemovePlayer, CBC_ORDER_ANY);
+ MUTATOR_HOOK(ClientDisconnect, ctf_RemovePlayer, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerDies, ctf_RemovePlayer, CBC_ORDER_ANY);
+ MUTATOR_HOOK(GiveFragsForKill, ctf_GiveFragsForKill, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerPreThink, ctf_PlayerPreThink, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerDamage_Calculate, ctf_PlayerDamage, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerUseKey, ctf_PlayerUseKey, CBC_ORDER_ANY);
+ //MUTATOR_HOOK(PlayerPowerups, ctf_PlayerPowerups, CBC_ORDER_ANY);
+
+ MUTATOR_ONADD
+ {
+ if(time > 1) // game loads at time 1
+ error("This is a game type and it cannot be added at runtime.");
+ g_ctf = 1;
+ ctf_Initialize();
+ }
+
+ MUTATOR_ONREMOVE
+ {
+ g_ctf = 0;
+ error("This is a game type and it cannot be removed at runtime.");
+ }
+
+ return 0;
+}
MUTATOR_DECLARATION(gamemode_keyhunt);
MUTATOR_DECLARATION(gamemode_freezetag);
MUTATOR_DECLARATION(gamemode_keepaway);
+MUTATOR_DECLARATION(gamemode_ctf);
+ MUTATOR_DECLARATION(mutator_invincibleprojectiles);
MUTATOR_DECLARATION(mutator_nix);
MUTATOR_DECLARATION(mutator_dodging);
MUTATOR_DECLARATION(mutator_rocketflying);
MUTATOR_DECLARATION(mutator_vampire);
+ MUTATOR_DECLARATION(mutator_spawn_near_teammate);
+ MUTATOR_DECLARATION(mutator_spawn_near_teammate);
+
+ MUTATOR_DECLARATION(sandbox);
.float teamtime;
+.float nb_dropperid;
+.float nb_droptime;
+
void nb_delayedinit();
void nb_init() // Called early (worldspawn stage)
{
void nexball_setstatus (void)
{
- local entity oldself;
+ entity oldself;
self.items &~= IT_KEY1;
if (self.ballcarried)
{
void DropOwner (void)
{
- local entity ownr;
+ entity ownr;
ownr = self.owner;
DropBall(self, ownr.origin, ownr.velocity);
makevectors(ownr.v_angle_y * '0 1 0');
void GiveBall (entity plyr, entity ball)
{
- local entity ownr;
+ entity ownr;
if ((ownr = ball.owner))
{
ball.owner = ball.pusher = plyr; //"owner" is set to the player carrying, "pusher" to the last player who touched it
ball.team = plyr.team;
plyr.ballcarried = ball;
- ball.dropperid = plyr.playerid;
+ ball.nb_dropperid = plyr.playerid;
plyr.effects |= g_nexball_basketball_effects_default;
ball.effects &~= g_nexball_basketball_effects_default;
ball.flags &~= FL_ONGROUND;
ball.scale = ball_scale;
ball.velocity = vel;
- ball.ctf_droptime = time;
+ ball.nb_droptime = time;
ball.touch = basketball_touch;
ball.think = ResetBall;
ball.nextthink = min(time + g_nexball_delay_idle, ball.teamtime);
football_touch();
return;
}
- if (!self.cnt && other.classname == "player" && (other.playerid != self.dropperid || time > self.ctf_droptime + autocvar_g_nexball_delay_collect)) {
+ if (!self.cnt && other.classname == "player" && (other.playerid != self.nb_dropperid || time > self.nb_droptime + autocvar_g_nexball_delay_collect)) {
if (other.health <= 0)
return;
LogNB("caught", other);
void nb_spawnteam (string teamname, float teamcolor)
{
dprint("^2spawned team ", teamname, "\n");
- local entity e;
+ entity e;
e = spawn();
e.classname = "nexball_team";
e.netname = teamname;
e.cnt = teamcolor;
e.team = e.cnt + 1;
nb_teams += 1;
- };
+ }
void nb_spawnteams (void)
{
void W_Nexball_Touch (void)
{
- local entity ball, attacker;
+ entity ball, attacker;
attacker = self.owner;
PROJECTILE_TOUCH;
void W_Nexball_Attack (float t)
{
- local entity ball;
- local float mul, mi, ma;
+ entity ball;
+ float mul, mi, ma;
if (!(ball = self.ballcarried))
return;
void W_Nexball_Attack2 (void)
{
- local entity missile;
+ entity missile;
if (!(balls & BALL_BASKET))
return;
W_SetupShot (self, FALSE, 2, "nexball/shoot2.wav", CH_WEAPON_A, 0);
{
precache_model ("models/weapons/g_porto.md3");
precache_model ("models/weapons/v_porto.md3");
- precache_model ("models/weapons/h_porto.dpm");
+ precache_model ("models/weapons/h_porto.iqm");
precache_model ("models/elaser.mdl");
precache_sound ("nexball/shoot1.wav");
precache_sound ("nexball/shoot2.wav");
.vector portal_safe_origin;
.float portal_wants_to_vanish;
.float portal_activatetime;
+ .float savemodelindex;
float PlayerEdgeDistance(entity p, vector v)
{
player.right_vector = -1 * AnglesTransform_Apply(transform, player.right_vector);
if(player.flagcarried)
- DropFlag(player.flagcarried, player, world);
+ ctf_Handle_Drop(player); // FIXCTF
if not(teleporter.enemy)
{
other = other.enemy;
if(other == self.aiment)
{
- self.modelindex = self.modelindex_lod0;
+ self.modelindex = self.savemodelindex;
}
else if(IS_INDEPENDENT_PLAYER(other) || IS_INDEPENDENT_PLAYER(self.aiment))
{
}
else
{
- self.modelindex = self.modelindex_lod0;
+ self.modelindex = self.savemodelindex;
}
return TRUE;
}
portal.fade_time = time + autocvar_g_balance_portal_lifetime;
portal.health = autocvar_g_balance_portal_health;
setmodel(portal, "models/portal.md3");
- portal.modelindex_lod0 = portal.modelindex;
+ portal.savemodelindex = portal.modelindex;
portal.customizeentityforclient = Portal_Customize;
if(!Portal_FindSafeOrigin(portal))
portal = Portal_Spawn(own, org, ang);
if(!portal)
- {
- // if(!own.portal_out || own.portal_out.portal_id == portal_id_val)
- Portal_ClearAll_PortalsOnly(own);
return 0;
- }
portal.portal_id = portal_id_val;
Portal_SetInPortal(own, portal);
portal = Portal_Spawn(own, org, ang);
if(!portal)
- {
- // if(!own.portal_in || own.portal_in.portal_id == portal_id_val)
- Portal_ClearAll_PortalsOnly(own);
return 0;
- }
portal.portal_id = portal_id_val;
Portal_SetOutPortal(own, portal);
../../progs.dat // output filename
../common/util-pre.qh
-
- sys.qh
- pre-builtins.qh
- builtins.qh
- extensions.qh
- post-builtins.qh
+ sys-pre.qh
+ ../dpdefs/progsdefs.qc
+ ../dpdefs/dpextensions.qc
+ sys-post.qh
../warpzonelib/anglestransform.qh
../warpzonelib/mathlib.qh
../common/util.qh
../common/items.qh
../common/explosion_equation.qh
+ ../common/urllib.qh
+ ../common/command/markup.qh
+ ../common/command/rpn.qh
+ ../common/command/generic.qh
+ ../common/command/shared_defs.qh
autocvars.qh
constants.qh
mutators/base.qh
mutators/mutators.qh
+mutators/gamemode_ctf.qh // for spawnfuncs
mutators/gamemode_keyhunt.qh // TODO fix this
mutators/mutator_dodging.qh
campaign.qh
../common/campaign_common.qh
../common/mapinfo.qh
- ../common/util.qc
+
+ command/common.qh
+ command/banning.qh
+ command/radarmap.qh
+ command/vote.qh
+ command/getreplies.qh
+ command/cmd.qh
+ command/sv_cmd.qh
accuracy.qh
csqcprojectile.qh
+ ../common/csqcmodel_settings.qh
+ ../csqcmodellib/common.qh
+ ../csqcmodellib/sv_model.qh
csqceffects.qc
anticheat.qh
antilag.qh
- vote.qh
-
playerdemo.qh
+ // singleplayer stuff
+ item_key.qh
+ secret.qh
+
scores_rules.qc
miscfunctions.qc
g_triggers.qc
g_models.qc
+ // singleplayer stuff
+ item_key.qc
+ secret.qc
+
cl_weaponsystem.qc
w_common.qc
t_plats.qc
antilag.qc
-ctf.qc
+//ctf.qc
domination.qc
mode_onslaught.qc
nexball.qc
t_swamp.qc
- clientcommands.qc
-
- vote.qc
-
campaign.qc
../common/campaign_file.qc
../common/campaign_setup.qc
-
- ../common/gamecommand.qc
- gamecommand.qc
+ ../common/urllib.qc
+
+ ../common/command/markup.qc
+ ../common/command/rpn.qc
+ ../common/command/generic.qc
+ command/common.qc
+ command/banning.qc
+ command/radarmap.qc
+ command/vote.qc
+ command/getreplies.qc
+ command/cmd.qc
+ command/sv_cmd.qc
assault.qc
../common/mapinfo.qc
-
-
-
t_quake3.qc
t_halflife.qc
t_quake.qc
../common/items.qc
- monsters/defs.qc
- monsters/fight.qc
- monsters/ai.qc
- monsters/m_monsters.qc
- monsters/monster_zombie.qc
+
accuracy.qc
+ ../csqcmodellib/sv_model.qc
csqcprojectile.qc
playerdemo.qc
../common/explosion_equation.qc
mutators/base.qc
+mutators/gamemode_ctf.qc
mutators/gamemode_keyhunt.qc
mutators/gamemode_freezetag.qc
mutators/gamemode_keepaway.qc
+ mutators/mutator_invincibleproj.qc
mutators/mutator_nix.qc
mutators/mutator_dodging.qc
mutators/mutator_rocketflying.qc
mutators/mutator_vampire.qc
+ mutators/mutator_spawn_near_teammate.qc
+ mutators/sandbox.qc
../warpzonelib/anglestransform.qc
../warpzonelib/mathlib.qc
../warpzonelib/util_server.qc
../warpzonelib/server.qc
+ ../common/util.qc
+
../common/if-this-file-errors-scroll-up-and-fix-the-warnings.fteqccfail
}
void dom_init();
-void ctf_init();
+//void ctf_init();
void runematch_init();
void tdm_init();
void nb_init();
GameLogEcho(strcat(":team:", ftos(player_id), ":", ftos(team_number), ":", ftos(type)));
}
- void WriteGameCvars()
- {
- cvar_set("g_dm", ftos(g_dm));
- cvar_set("g_tdm", ftos(g_tdm));
- cvar_set("g_domination", ftos(g_domination));
- cvar_set("g_ctf", ftos(g_ctf));
- cvar_set("g_runematch", ftos(g_runematch));
- cvar_set("g_lms", ftos(g_lms));
- cvar_set("g_arena", ftos(g_arena));
- cvar_set("g_ca", ftos(g_ca));
- cvar_set("g_keyhunt", ftos(g_keyhunt));
- cvar_set("g_assault", ftos(g_assault));
- cvar_set("g_onslaught", ftos(g_onslaught));
- cvar_set("g_race", ftos(g_race));
- cvar_set("g_nexball", ftos(g_nexball));
- cvar_set("g_cts", ftos(g_cts));
- cvar_set("g_freezetag", ftos(g_freezetag));
- cvar_set("g_keepaway", ftos(g_keepaway));
- }
-
- void ReadGameCvars()
- {
- float found;
- float prev;
- float i;
-
- found = 0;
- prev = autocvar_gamecfg;
- for(i = 0; i < 2; ++i)
- {
- //#NO AUTOCVARS START
- found += (g_dm = (!found && (prev != GAME_DEATHMATCH) && cvar("g_dm")));
- found += (g_tdm = (!found && (prev != GAME_TEAM_DEATHMATCH) && cvar("g_tdm")));
- found += (g_domination = (!found && (prev != GAME_DOMINATION) && cvar("g_domination")));
- found += (g_ctf = (!found && (prev != GAME_CTF) && cvar("g_ctf")));
- found += (g_runematch = (!found && (prev != GAME_RUNEMATCH) && cvar("g_runematch")));
- found += (g_lms = (!found && (prev != GAME_LMS) && cvar("g_lms")));
- found += (g_arena = (!found && (prev != GAME_ARENA) && cvar("g_arena")));
- found += (g_ca = (!found && (prev != GAME_CA) && cvar("g_ca")));
- found += (g_keyhunt = (!found && (prev != GAME_KEYHUNT) && cvar("g_keyhunt")));
- found += (g_assault = (!found && (prev != GAME_ASSAULT) && cvar("g_assault")));
- found += (g_onslaught = (!found && (prev != GAME_ONSLAUGHT) && cvar("g_onslaught")));
- found += (g_race = (!found && (prev != GAME_RACE) && cvar("g_race")));
- found += (g_nexball = (!found && (prev != GAME_NEXBALL) && cvar("g_nexball")));
- found += (g_cts = (!found && (prev != GAME_CTS) && cvar("g_cts")));
- found += (g_freezetag = (!found && (prev != GAME_FREEZETAG) && cvar("g_freezetag")));
- found += (g_keepaway = (!found && (prev != GAME_KEEPAWAY) && cvar("g_keepaway")));
- //#NO AUTOCVARS END
-
- if(found)
- break;
-
- prev = -1; // second attempt takes place WITHOUT prev set
- }
-
- if(!found)
- g_dm = 1;
-
- if(g_dm && autocvar_deathmatch_force_teamplay)
- {
- g_dm = 0;
- g_tdm = 1;
- }
-
- teamplay = 0;
- serverflags &~= SERVERFLAG_TEAMPLAY;
- }
-
void default_delayedinit()
{
if(!scores_initialized)
VoteReset();
- // make sure only ONE type is selected
- ReadGameCvars();
- WriteGameCvars();
-
// find out good world mins/maxs bounds, either the static bounds found by looking for solid, or the mapinfo specified bounds
get_mi_min_max(1);
world.mins = mi_min;
world.maxs = mi_max;
MapInfo_LoadMapSettings(mapname);
+ teamplay = 0;
+ serverflags &~= SERVERFLAG_TEAMPLAY;
if not(cvar_value_issafe(world.fog))
{
MapInfo_ClearTemps();
- // in case mapinfo switched the type
- ReadGameCvars();
-
// set both here, gamemode can override it later
timelimit_override = autocvar_timelimit_override;
fraglimit_override = autocvar_fraglimit_override;
leadlimit_override = autocvar_leadlimit_override;
+ gamemode_name = MapInfo_Type_ToText(MapInfo_LoadedGametype);
if(g_dm)
{
- game = GAME_DEATHMATCH;
- gamemode_name = "Deathmatch";
}
if(g_tdm)
{
- game = GAME_TEAM_DEATHMATCH;
- gamemode_name = "Team Deathmatch";
ActivateTeamplay();
tdm_init();
if(autocvar_g_tdm_team_spawns)
if(g_domination)
{
- game = GAME_DOMINATION;
- gamemode_name = "Domination";
ActivateTeamplay();
fraglimit_override = autocvar_g_domination_point_limit;
leadlimit_override = autocvar_g_domination_point_leadlimit;
if(g_ctf)
{
- game = GAME_CTF;
- gamemode_name = "Capture the Flag";
ActivateTeamplay();
g_ctf_ignore_frags = autocvar_g_ctf_ignore_frags;
- if(g_ctf_win_mode == 2)
- {
- fraglimit_override = autocvar_g_ctf_capture_limit;
- leadlimit_override = autocvar_g_ctf_capture_leadlimit;
- }
- else
- {
- fraglimit_override = autocvar_capturelimit_override;
- leadlimit_override = autocvar_captureleadlimit_override;
- }
+ fraglimit_override = autocvar_capturelimit_override;
+ leadlimit_override = autocvar_captureleadlimit_override;
- ctf_init();
+ MUTATOR_ADD(gamemode_ctf);
have_team_spawns = -1; // request team spawns
}
if(g_runematch)
{
- game = GAME_RUNEMATCH;
- gamemode_name = "Rune Match";
- if(autocvar_deathmatch_force_teamplay)
- ActivateTeamplay();
+ // ActivateTeamplay();
fraglimit_override = autocvar_g_runematch_point_limit;
leadlimit_override = autocvar_g_runematch_point_leadlimit;
runematch_init();
if(g_lms)
{
- game = GAME_LMS;
- gamemode_name = "Last Man Standing";
fraglimit_override = autocvar_g_lms_lives_override;
leadlimit_override = 0; // not supported by LMS
if(fraglimit_override == 0)
if(g_arena)
{
- game = GAME_ARENA;
- gamemode_name = "Arena";
fraglimit_override = autocvar_g_arena_point_limit;
leadlimit_override = autocvar_g_arena_point_leadlimit;
maxspawned = autocvar_g_arena_maxspawned;
if(g_ca)
{
- game = GAME_CA;
- gamemode_name = "Clan Arena";
ActivateTeamplay();
fraglimit_override = autocvar_g_ca_point_limit;
leadlimit_override = autocvar_g_ca_point_leadlimit;
}
if(g_keyhunt)
{
- game = GAME_KEYHUNT;
- gamemode_name = "Key Hunt";
ActivateTeamplay();
fraglimit_override = autocvar_g_keyhunt_point_limit;
leadlimit_override = autocvar_g_keyhunt_point_leadlimit;
if(g_freezetag)
{
- game = GAME_FREEZETAG;
- gamemode_name = "Freeze Tag";
ActivateTeamplay();
fraglimit_override = autocvar_g_freezetag_point_limit;
leadlimit_override = autocvar_g_freezetag_point_leadlimit;
if(g_assault)
{
- game = GAME_ASSAULT;
- gamemode_name = "Assault";
ActivateTeamplay();
ScoreRules_assault();
have_team_spawns = -1; // request team spawns
if(g_onslaught)
{
- game = GAME_ONSLAUGHT;
- gamemode_name = "Onslaught";
ActivateTeamplay();
have_team_spawns = -1; // request team spawns
}
if(g_race)
{
- game = GAME_RACE;
- gamemode_name = "Race";
if(autocvar_g_race_teams)
{
if(g_cts)
{
- game = GAME_CTS;
- gamemode_name = "CTS";
g_race_qualifying = 1;
fraglimit_override = 0;
leadlimit_override = 0;
if(g_nexball)
{
- game = GAME_NEXBALL;
- gamemode_name = "Nexball";
fraglimit_override = autocvar_g_nexball_goallimit;
leadlimit_override = autocvar_g_nexball_goalleadlimit;
ActivateTeamplay();
if(g_keepaway)
{
- game = GAME_KEEPAWAY;
- gamemode_name = "Keepaway";
MUTATOR_ADD(gamemode_keepaway);
}
if(teamplay)
entcs_init();
- // save it (for the next startup)
- cvar_set("gamecfg", ftos(game));
-
cache_mutatormsg = strzone("");
cache_lastmutatormsg = strzone("");
}
string GetClientVersionMessage() {
- local string versionmsg;
+ string versionmsg;
if (self.version_mismatch) {
if(self.version < autocvar_gameversion) {
versionmsg = "^3Your client version is outdated.\n\n\n### YOU WON'T BE ABLE TO PLAY ON THIS SERVER ###\n\n\nPlease update!!!^8";
return versionmsg;
}
-
- void PrintWelcomeMessage(entity pl)
+ string getwelcomemessage(void)
{
string s, modifications, motd;
- if(self.cvar_scr_centertime == 0) return;
-
- if(autocvar_g_campaign)
- {
- if(self.classname == "player" && !self.BUTTON_INFO)
- return;
- }
- else
- {
- if((time - self.jointime) > autocvar_welcome_message_time && !self.BUTTON_INFO)
- return;
- }
-
- if( !(timeoutStatus >= 1) ) { //really print the WelcomeMessage to the player every frame when timeout-seconds are shown or the game is restarted, to make sure that the shown number is accurate
- if(self.welcomemessage_time > time) return;
- self.welcomemessage_time = time + max(0.5, self.cvar_scr_centertime * 0.6);
- }
-
- if(autocvar_g_campaign)
- {
- centerprint(pl, campaign_message);
- return;
- }
-
- //TODO GreEn`mArine: make the timeout-messages clientside as well (just like the ready restart countdown)!
- if(!self.BUTTON_INFO)
- {
- // TODO get rid of this too
- local string specString;
- specString = NEWLINES;
- //if(time < game_starttime) //also show the countdown when being a spectator
- // specString = strcat(specString, "\n\n^1Game starts in ", ftos(ceil(game_starttime - time)), " seconds^7");
- //else
- if (timeoutStatus != 0)
- specString = strcat(specString, "\n\n", getTimeoutText(1));
- else
- {
- if(self.classname == "player")
- return;
- goto normal;
- }
- return centerprint_atprio(self, CENTERPRIO_SPAM, specString);
- }
-
- :normal
ret_string = "";
MUTATOR_CALLHOOK(BuildMutatorsPrettyString);
modifications = ret_string;
modifications = strcat(modifications, ", Blood loss");
if(g_jetpack)
modifications = strcat(modifications, ", Jet pack");
+ if(autocvar_g_powerups == 0)
+ modifications = strcat(modifications, ", No powerups");
+ if(autocvar_g_powerups > 0)
+ modifications = strcat(modifications, ", Powerups");
modifications = substring(modifications, 2, strlen(modifications) - 2);
- local string versionmessage;
+ string versionmessage;
versionmessage = GetClientVersionMessage();
- s = strcat(s, NEWLINES, "This is Xonotic ", autocvar_g_xonoticversion, "\n", versionmessage);
+ s = strcat("This is Xonotic ", autocvar_g_xonoticversion, "\n", versionmessage);
s = strcat(s, "^8\n\nmatch type is ^1", gamemode_name, "^8\n");
if(modifications != "")
s = strcat(s, "^8\nactive modifications: ^3", modifications, "^8\n");
- if(timeoutStatus != 0)
- s = strcat(s, "\n\n", getTimeoutText(1));
-
if (g_grappling_hook)
s = strcat(s, "\n\n^3grappling hook^8 is enabled, press 'e' to use it\n");
if (motd != "") {
s = strcat(s, "\n\n^8MOTD: ^7", strreplace("\\n", "\n", motd));
}
- s = strcat(s, "\n");
-
- centerprint(pl, s);
+ return s;
}
-
void SetPlayerColors(entity pl, float _color)
{
/*string s;
// code from here on is just to support maps that don't have team entities
void tdm_spawnteam (string teamname, float teamcolor)
{
- local entity e;
+ entity e;
e = spawn();
e.classname = "tdm_team";
e.netname = teamname;
e.cnt = teamcolor;
e.team = e.cnt + 1;
- };
+ }
// spawn some default teams if the map is not set up for tdm
void tdm_spawnteams()
tdm_spawnteam("Yellow", COLOR_TEAM3-1);
if(numteams >= 4)
tdm_spawnteam("Pink", COLOR_TEAM4-1);
- };
+ }
void tdm_delayedinit()
{
// if no teams are found, spawn defaults
if (find(world, classname, "tdm_team") == world)
tdm_spawnteams();
- };
+ }
void tdm_init()
{
InitializeEntity(world, tdm_delayedinit, INITPRIO_GAMETYPE);
- };
+ }
entity axh;
axh_id = bound(0, axh_id, MAX_AXH);
- axh = own.AuxiliaryXhair[axh_id];
+ axh = own.(AuxiliaryXhair[axh_id]);
if(axh == world || wasfreed(axh)) // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist?)
{
setorigin(axh, loc);
axh.colormod = clr;
axh.SendFlags = 0x01;
- own.AuxiliaryXhair[axh_id] = axh;
+ own.(AuxiliaryXhair[axh_id]) = axh;
}
/*
self.touch = vehicles_touch;
self.event_damage = vehicles_damage;
self.iscreature = TRUE;
+ self.damagedbycontents = TRUE;
self.movetype = MOVETYPE_WALK;
self.solid = SOLID_SLIDEBOX;
self.takedamage = DAMAGE_AIM;
// Return to spawn
self.angles = self.pos2;
- setorigin(self, self.pos1 + '0 0 128');
+ setorigin(self, self.pos1 + '0 0 0');
// Show it
pointparticles(particleeffectnum("teleport"), self.origin + '0 0 64', '0 0 0', 1);
return FALSE;
}
+ void vehilces_impact(float _minspeed, float _speedfac, float _maxpain)
+ {
+ if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
+ return;
+
+ if(self.play_time < time)
+ {
+ float wc = vlen(self.velocity - self.oldvelocity);
+ //dprint("oldvel: ", vtos(self.oldvelocity), "\n");
+ //dprint("vel: ", vtos(self.velocity), "\n");
+ if(_minspeed < wc)
+ {
+ float take = take = min(_speedfac * wc, _maxpain);
+ Damage (self, world, world, take, DEATH_FALL, self.origin, '0 0 0');
+ self.play_time = time + 0.25;
+
+ //dprint("wc: ", ftos(wc), "\n");
+ //dprint("take: ", ftos(take), "\n");
+ }
+ }
+ }
+
+ .void() vehicle_impact;
void vehicles_touch()
{
// Vehicle currently in use
if(self.owner)
{
- // Colided with world?
- if(other == world)
- {
- }
- else
+ if(other != world)
+ if(vehicles_crushable(other))
{
- if(other.vehicle_flags & VHF_ISVEHICLE)
- {
- //other.velocity += self.velocity * (self.mass / other.mass);
- }
- else if(vehicles_crushable(other))
- {
- if(vlen(self.velocity) != 0)
- Damage(other, self, self.owner, autocvar_g_vehicles_crush_dmg, DEATH_VHCRUSH, '0 0 0', normalize(other.origin - self.origin) * autocvar_g_vehicles_crush_force);
- }
+ if(vlen(self.velocity) != 0)
+ Damage(other, self, self.owner, autocvar_g_vehicles_crush_dmg, DEATH_VHCRUSH, '0 0 0', normalize(other.origin - self.origin) * autocvar_g_vehicles_crush_force);
+
+ return; // Dont do selfdamage when hitting "soft targets".
}
+
+ if(self.play_time < time)
+ if(self.vehicle_impact)
+ self.vehicle_impact();
+
return;
}
if(self.team)
if(self.team != other.team)
return;
+
+ RemoveGrapplingHook(other);
self.vehicle_ammo1 = 0;
self.vehicle_ammo2 = 0;
CSQCVehicleSetup(self.owner, self.hud);
+ /* FIXCTF // THIS IS A BIG NO-NO, NO GAME MODE SPECIFIC CODE IN VEHICLES.
if(other.flagcarried)
{
if(!autocvar_g_vehicles_allow_flagcarry)
setorigin(other, '0 0 96');
}
}
+ */
self.vehicle_enter();
+ antilag_clear(other);
}
/** vehicles_findgoodexit
self.owner.hud = HUD_NORMAL;
self.owner.switchweapon = self.switchweapon;
//self.owner.BUTTON_USE = 0;
+
+ CSQCVehicleSetup(self.owner, HUD_NORMAL);
}
if(self.deadflag == DEAD_NO)
else
self.team = self.tur_head.team;
+ /* FIXCTF // THIS IS A BIG NO-NO, NO GAME MODE SPECIFIC CODE IN VEHICLES.
if(self.owner.flagcarried)
{
self.owner.flagcarried.scale = 0.6;
setattachment(self.owner.flagcarried, self.owner, "");
setorigin(self.owner.flagcarried, FLAG_CARRY_POS);
}
+ */
sound (self, CH_TRIGGER_SINGLE, "misc/null.wav", 1, ATTN_NORM);
self.vehicle_exit(eject);
}
void vehicles_painframe()
- {
- //.float pain_finished; //Added by Supajoe
-
+ {
if(self.owner.vehicle_health <= 50)
if(self.pain_frame < time)
{
self.takedamage = DAMAGE_AIM;
self.bot_attack = TRUE;
self.iscreature = TRUE;
+ self.damagedbycontents = TRUE;
self.hud = vhud;
self.vehicle_die = dieproc;