From: Mircea Kitsune Date: Thu, 17 Feb 2011 14:32:47 +0000 (+0200) Subject: Merge branch 'master' into mirceakitsune/universal_reload_system X-Git-Tag: xonotic-v0.5.0~309^2~7^2~15 X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=commitdiff_plain;h=bc91f7dc48927953480bdc9622973c7de075fb5f;hp=a264c5e229926ed99be77f49ed5c6b4a9e256ce0 Merge branch 'master' into mirceakitsune/universal_reload_system Conflicts: qcsrc/common/constants.qh --- diff --git a/balanceXonotic.cfg b/balanceXonotic.cfg index 1842dabd4f..c2862e2985 100644 --- a/balanceXonotic.cfg +++ b/balanceXonotic.cfg @@ -243,6 +243,8 @@ set g_balance_laser_secondary_gauntlet 1 set g_balance_laser_secondary_force_zscale 1.25 set g_balance_laser_secondary_force_velocitybias 0 set g_balance_laser_secondary_force_other_scale 0 +set g_balance_laser_reload_ammo 0 //default: 6 +set g_balance_laser_reload_time 2 // }}} // {{{ shotgun set g_balance_shotgun_primary_bullets 18 @@ -263,6 +265,8 @@ set g_balance_shotgun_secondary_damage 110 set g_balance_shotgun_secondary_force 150 set g_balance_shotgun_secondary_refire 1.1 set g_balance_shotgun_secondary_animtime 1 +set g_balance_shotgun_reload_ammo 0 //default: 5 +set g_balance_shotgun_reload_time 2 // }}} // {{{ uzi set g_balance_uzi_mode 1 // Activates varible spread for sustained & burst mode secondary @@ -294,6 +298,9 @@ set g_balance_uzi_sustained_ammo 1 set g_balance_uzi_speed 18000 set g_balance_uzi_bulletconstant 115 // 13.1qu + +set g_balance_uzi_reload_ammo 0 //default: 30 +set g_balance_uzi_reload_time 2 // }}} // {{{ mortar set g_balance_grenadelauncher_primary_type 0 @@ -334,6 +341,9 @@ set g_balance_grenadelauncher_secondary_remote_detonateprimary 0 set g_balance_grenadelauncher_bouncefactor 0.5 set g_balance_grenadelauncher_bouncestop 0.12 + +set g_balance_grenadelauncher_reload_ammo 0 //default: 12 +set g_balance_grenadelauncher_reload_time 2 // }}} // {{{ minelayer set g_balance_minelayer_damage 42 @@ -357,6 +367,8 @@ set g_balance_minelayer_remote_damage 45 set g_balance_minelayer_remote_edgedamage 40 set g_balance_minelayer_remote_radius 200 set g_balance_minelayer_remote_force 300 +set g_balance_minelayer_reload_ammo 0 //default: 15 +set g_balance_minelayer_reload_time 2 // }}} // {{{ electro set g_balance_electro_lightning 1 @@ -400,6 +412,8 @@ set g_balance_electro_combo_force 80 set g_balance_electro_combo_radius 250 set g_balance_electro_combo_comboradius 0 set g_balance_electro_combo_speed 400 +set g_balance_electro_reload_ammo 0 //default: 20 +set g_balance_electro_reload_time 2 // }}} // {{{ crylink set g_balance_crylink_primary_damage 7 // LOG: 10 -> 7 @@ -456,6 +470,9 @@ set g_balance_crylink_secondary_middle_lifetime 5 // range: 10000 full, fades to set g_balance_crylink_secondary_middle_fadetime 5 set g_balance_crylink_secondary_line_lifetime 2 // range: 4000 full, fades to 8000 set g_balance_crylink_secondary_line_fadetime 0.25 + +set g_balance_crylink_reload_ammo 0 //default: 10 +set g_balance_crylink_reload_time 2 // }}} // {{{ nex set g_balance_nex_primary_damage 90 @@ -497,11 +514,17 @@ set g_balance_nex_charge_shot_multiplier 0 set g_balance_nex_charge_velocity_rate 0 set g_balance_nex_charge_minspeed 600 set g_balance_nex_charge_maxspeed 1000 + +set g_balance_nex_reload_ammo 0 //default: 25 +set g_balance_nex_reload_time 2 // }}} // {{{ minstanex set g_balance_minstanex_refire 1 set g_balance_minstanex_animtime 0.50 set g_balance_minstanex_ammo 10 +set g_balance_minstanex_laser_ammo 0 +set g_balance_minstanex_reload_ammo 0 //default: 50 +set g_balance_minstanex_reload_time 2 // }}} // {{{ hagar set g_balance_hagar_primary_damage 14 @@ -524,6 +547,8 @@ set g_balance_hagar_secondary_lifetime_min 5 set g_balance_hagar_secondary_lifetime_rand 0 set g_balance_hagar_secondary_refire 0.12 set g_balance_hagar_secondary_ammo 1 +set g_balance_hagar_reload_ammo 0 //default: 25 +set g_balance_hagar_reload_time 2 // }}} // {{{ rocketlauncher set g_balance_rocketlauncher_damage 82 @@ -549,6 +574,8 @@ set g_balance_rocketlauncher_remote_damage 60 set g_balance_rocketlauncher_remote_edgedamage 20 set g_balance_rocketlauncher_remote_radius 120 set g_balance_rocketlauncher_remote_force 350 +set g_balance_rocketlauncher_reload_ammo 0 //default: 25 +set g_balance_rocketlauncher_reload_time 2 // }}} // {{{ porto set g_balance_porto_primary_refire 1.5 @@ -610,11 +637,11 @@ set g_balance_hlac_secondary_refire 0.8 set g_balance_hlac_secondary_animtime 0.4 set g_balance_hlac_secondary_ammo 4 set g_balance_hlac_secondary_shots 6 + +set g_balance_hlac_reload_ammo 0 //default: 20 +set g_balance_hlac_reload_time 2 // }}} // {{{ sniperrifle -set g_balance_sniperrifle_magazinecapacity 8 // make it pretty much useless in close combat -set g_balance_sniperrifle_reloadtime 2 // matches reload anim -set g_balance_sniperrifle_auto_reload_on_switch 0 set g_balance_sniperrifle_bursttime 0 set g_balance_sniperrifle_primary_tracer 1 set g_balance_sniperrifle_primary_damage 60 @@ -644,6 +671,8 @@ set g_balance_sniperrifle_secondary_ammo 10 set g_balance_sniperrifle_secondary_bulletconstant 110 // 15.5qu set g_balance_sniperrifle_secondary_burstcost 0 set g_balance_sniperrifle_secondary_bullethail 0 // empty magazine on shot +set g_balance_sniperrifle_reload_ammo 60 //default: 60 +set g_balance_sniperrifle_reload_time 2 // }}} // {{{ tuba set g_balance_tuba_refire 0.05 @@ -693,6 +722,8 @@ set g_balance_fireball_secondary_speed 900 set g_balance_fireball_secondary_speed_up 100 set g_balance_fireball_secondary_speed_z 0 set g_balance_fireball_secondary_spread 0 +set g_balance_fireball_reload_ammo 0 //default: 60 +set g_balance_fireball_reload_time 2 // }}} // {{{ seeker set g_balance_seeker_flac_ammo 0.5 @@ -743,4 +774,6 @@ set g_balance_seeker_tag_lifetime 15 set g_balance_seeker_tag_refire 0.75 // LOG: 0.7 -> 0.75 set g_balance_seeker_tag_speed 5000 set g_balance_seeker_tag_spread 0 +set g_balance_seeker_reload_ammo 0 //default: 15 +set g_balance_seeker_reload_time 2 // End new seeker diff --git a/qcsrc/client/Defs.qc b/qcsrc/client/Defs.qc index 3d15295942..eef29cdd55 100644 --- a/qcsrc/client/Defs.qc +++ b/qcsrc/client/Defs.qc @@ -261,8 +261,6 @@ vector w_org, w_backoff; float sniperrifle_scope; float nex_scope; -float cr_maxbullets; - float bgmtime; string weaponorder_byimpulse; diff --git a/qcsrc/client/Main.qc b/qcsrc/client/Main.qc index 8614863318..125c6db312 100644 --- a/qcsrc/client/Main.qc +++ b/qcsrc/client/Main.qc @@ -1094,8 +1094,6 @@ void Ent_Init() serverflags = ReadByte(); - cr_maxbullets = ReadByte(); - g_trueaim_minrange = ReadCoord(); if(!postinit) diff --git a/qcsrc/client/View.qc b/qcsrc/client/View.qc index 7270a9cf19..7fde6824d3 100644 --- a/qcsrc/client/View.qc +++ b/qcsrc/client/View.qc @@ -866,7 +866,7 @@ void CSQC_UpdateView(float w, float h) // TrueAim check float shottype; - float bullets, ring_scale; + float weapon_clipload, weapon_clipsize, ring_scale; // wcross_origin = '0.5 0 0' * vid_conwidth + '0 0.5 0' * vid_conheight; wcross_origin = project_3d_to_2d(view_origin + MAX_SHOT_DISTANCE * view_forward); wcross_origin_z = 0; @@ -1076,16 +1076,17 @@ void CSQC_UpdateView(float w, float h) if(nex_charge_movingavg == 0) // this should only happen if we have just loaded up the game nex_charge_movingavg = nex_charge; - // ring around crosshair representing bullets left in camping rifle clip - if (activeweapon == WEP_SNIPERRIFLE && cr_maxbullets) + // ring around crosshair representing bullets left in weapon clip + weapon_clipload = getstati(STAT_WEAPON_CLIPLOAD); + if (weapon_clipload) { - bullets = getstati(STAT_BULLETS_LOADED); - f = bound(0, bullets / cr_maxbullets, 1); + weapon_clipsize = getstati(STAT_WEAPON_CLIPSIZE); + f = bound(0, weapon_clipload / weapon_clipsize, 1); a = autocvar_crosshair_ring_sniperrifle_alpha; DrawCircleClippedPic(wcross_origin, wcross_size_x * ring_scale, "gfx/crosshair_ring.tga", f, wcross_color, wcross_alpha * a, DRAWFLAG_ADDITIVE); } - else if (activeweapon == WEP_NEX && nex_charge) // ring around crosshair representing velocity-dependent damage for the nex + if (activeweapon == WEP_NEX && nex_charge) // ring around crosshair representing velocity-dependent damage for the nex { if(nex_chargepool || use_nex_chargepool) { diff --git a/qcsrc/common/constants.qh b/qcsrc/common/constants.qh index 60633f5747..b8c4f44699 100644 --- a/qcsrc/common/constants.qh +++ b/qcsrc/common/constants.qh @@ -62,7 +62,6 @@ const float TE_CSQC_TARGET_MUSIC = 111; const float TE_CSQC_NOTIFY = 112; const float TE_CSQC_WEAPONCOMPLAIN = 113; const float TE_CSQC_NEX_SCOPE = 116; -const float TE_CSQC_CR_MAXBULLETS = 117; const float RACE_NET_CHECKPOINT_HIT_QUALIFYING = 0; // byte checkpoint, short time, short recordtime, string recordholder const float RACE_NET_CHECKPOINT_CLEAR = 1; @@ -308,13 +307,14 @@ const float STAT_FUEL = 44; const float STAT_NB_METERSTART = 45; const float STAT_SHOTORG = 46; // compressShotOrigin const float STAT_LEADLIMIT = 47; -const float STAT_BULLETS_LOADED = 48; -const float STAT_NEX_CHARGE = 49; -const float STAT_LAST_PICKUP = 50; -const float STAT_HUD = 51; -const float STAT_NEX_CHARGEPOOL = 52; -const float STAT_HIT_TIME = 53; -const float STAT_TYPEHIT_TIME = 54; +const float STAT_WEAPON_CLIPLOAD = 48; +const float STAT_WEAPON_CLIPSIZE = 49; +const float STAT_NEX_CHARGE = 50; +const float STAT_LAST_PICKUP = 51; +const float STAT_HUD = 52; +const float STAT_NEX_CHARGEPOOL = 53; +const float STAT_HIT_TIME = 54; +const float STAT_TYPEHIT_TIME = 55; // see DP source, quakedef.h const float STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW = 222; @@ -623,6 +623,7 @@ float WR_KILLMESSAGE = 8; // (CSQC) sets w_deathtypestring or leaves it alone float WR_RELOAD = 9; // (SVQC) does not need to do anything float WR_RESETPLAYER = 10; // (SVQC) does not need to do anything float WR_IMPACTEFFECT = 11; // (CSQC) impact effect +float WR_SWITCHABLE = 12; // (CSQC) impact effect float HUD_PANEL_WEAPONS = 0; diff --git a/qcsrc/common/items.qh b/qcsrc/common/items.qh index ebee8aaaa4..c98ff786b9 100644 --- a/qcsrc/common/items.qh +++ b/qcsrc/common/items.qh @@ -2,13 +2,14 @@ float BOT_PICKUP_RATING_LOW = 2500; 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_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 IT_UNLIMITED_WEAPON_AMMO = 1; // when this bit is set, using a weapon does not reduce ammo. Checkpoints can give this powerup. diff --git a/qcsrc/server/autocvars.qh b/qcsrc/server/autocvars.qh index 7c3bcf8977..c78460c173 100644 --- a/qcsrc/server/autocvars.qh +++ b/qcsrc/server/autocvars.qh @@ -82,9 +82,7 @@ float autocvar_g_balance_armor_rot; float autocvar_g_balance_armor_rotlinear; float autocvar_g_balance_armor_rotstable; float autocvar_g_balance_armor_start; -float autocvar_g_balance_sniperrifle_auto_reload_on_switch; float autocvar_g_balance_sniperrifle_bursttime; -float autocvar_g_balance_sniperrifle_magazinecapacity; float autocvar_g_balance_sniperrifle_primary_ammo; float autocvar_g_balance_sniperrifle_primary_animtime; float autocvar_g_balance_sniperrifle_primary_bulletconstant; @@ -98,7 +96,6 @@ float autocvar_g_balance_sniperrifle_primary_refire; float autocvar_g_balance_sniperrifle_primary_speed; float autocvar_g_balance_sniperrifle_primary_spread; float autocvar_g_balance_sniperrifle_primary_tracer; -float autocvar_g_balance_sniperrifle_reloadtime; float autocvar_g_balance_sniperrifle_secondary; float autocvar_g_balance_sniperrifle_secondary_ammo; float autocvar_g_balance_sniperrifle_secondary_animtime; @@ -114,6 +111,8 @@ float autocvar_g_balance_sniperrifle_secondary_refire; float autocvar_g_balance_sniperrifle_secondary_speed; float autocvar_g_balance_sniperrifle_secondary_spread; float autocvar_g_balance_sniperrifle_secondary_tracer; +float autocvar_g_balance_sniperrifle_reload_ammo; +float autocvar_g_balance_sniperrifle_reload_time; float autocvar_g_balance_cloaked_alpha; float autocvar_g_balance_crylink_primary_ammo; float autocvar_g_balance_crylink_primary_animtime; @@ -166,6 +165,8 @@ float autocvar_g_balance_crylink_secondary_refire; float autocvar_g_balance_crylink_secondary_shots; float autocvar_g_balance_crylink_secondary_speed; float autocvar_g_balance_crylink_secondary_spread; +float autocvar_g_balance_crylink_reload_ammo; +float autocvar_g_balance_crylink_reload_time; float autocvar_g_balance_ctf_damageforcescale; float autocvar_g_balance_ctf_delay_collect; float autocvar_g_balance_curse_empathy_minhealth; @@ -215,6 +216,8 @@ float autocvar_g_balance_electro_secondary_radius; float autocvar_g_balance_electro_secondary_refire; float autocvar_g_balance_electro_secondary_refire2; float autocvar_g_balance_electro_secondary_speed; +float autocvar_g_balance_electro_reload_ammo; +float autocvar_g_balance_electro_reload_time; float autocvar_g_balance_falldamage_deadminspeed; float autocvar_g_balance_falldamage_factor; float autocvar_g_balance_falldamage_maxdamage; @@ -251,6 +254,8 @@ float autocvar_g_balance_fireball_secondary_lifetime; 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; @@ -299,6 +304,8 @@ float autocvar_g_balance_grenadelauncher_secondary_refire; float autocvar_g_balance_grenadelauncher_secondary_speed; float autocvar_g_balance_grenadelauncher_secondary_speed_up; float autocvar_g_balance_grenadelauncher_secondary_type; +float autocvar_g_balance_grenadelauncher_reload_ammo; +float autocvar_g_balance_grenadelauncher_reload_time; float autocvar_g_balance_hagar_primary_ammo; float autocvar_g_balance_hagar_primary_damage; float autocvar_g_balance_hagar_primary_edgedamage; @@ -316,6 +323,8 @@ 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_reload_ammo; +float autocvar_g_balance_hagar_reload_time; float autocvar_g_balance_health_limit; float autocvar_g_balance_health_regen; float autocvar_g_balance_health_regenlinear; @@ -350,6 +359,8 @@ float autocvar_g_balance_hlac_secondary_shots; float autocvar_g_balance_hlac_secondary_speed; float autocvar_g_balance_hlac_secondary_spread; float autocvar_g_balance_hlac_secondary_spread_crouchmod; +float autocvar_g_balance_hlac_reload_ammo; +float autocvar_g_balance_hlac_reload_time; float autocvar_g_balance_hook_primary_animtime; float autocvar_g_balance_hook_primary_fuel; float autocvar_g_balance_hook_primary_hooked_fuel; @@ -410,6 +421,8 @@ float autocvar_g_balance_laser_secondary_force_zscale; float autocvar_g_balance_laser_secondary_lifetime; float autocvar_g_balance_laser_secondary_radius; float autocvar_g_balance_laser_secondary_speed; +float autocvar_g_balance_laser_reload_ammo; +float autocvar_g_balance_laser_reload_time; float autocvar_g_balance_minelayer_ammo; float autocvar_g_balance_minelayer_animtime; float autocvar_g_balance_minelayer_damage; @@ -431,9 +444,14 @@ float autocvar_g_balance_minelayer_remote_force; float autocvar_g_balance_minelayer_remote_radius; float autocvar_g_balance_minelayer_speed; float autocvar_g_balance_minelayer_time; +float autocvar_g_balance_minelayer_reload_ammo; +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_animtime; float autocvar_g_balance_minstanex_refire; +float autocvar_g_balance_minstanex_reload_ammo; +float autocvar_g_balance_minstanex_reload_time; float autocvar_g_balance_nex_charge; float autocvar_g_balance_nex_charge_animlimit; float autocvar_g_balance_nex_charge_limit; @@ -471,6 +489,8 @@ float autocvar_g_balance_nex_secondary_damagefalloff_maxdist; float autocvar_g_balance_nex_secondary_damagefalloff_mindist; float autocvar_g_balance_nex_secondary_force; float autocvar_g_balance_nex_secondary_refire; +float autocvar_g_balance_nex_reload_ammo; +float autocvar_g_balance_nex_reload_time; float autocvar_g_balance_nexball_primary_animtime; float autocvar_g_balance_nexball_primary_refire; float autocvar_g_balance_nexball_primary_speed; @@ -537,6 +557,8 @@ float autocvar_g_balance_rocketlauncher_remote_radius; float autocvar_g_balance_rocketlauncher_speed; float autocvar_g_balance_rocketlauncher_speedaccel; float autocvar_g_balance_rocketlauncher_speedstart; +float autocvar_g_balance_rocketlauncher_reload_ammo; +float autocvar_g_balance_rocketlauncher_reload_time; float autocvar_g_balance_rune_defense_combo_takedamage; float autocvar_g_balance_rune_defense_takedamage; float autocvar_g_balance_rune_regen_combo_hpmod; @@ -594,6 +616,8 @@ float autocvar_g_balance_seeker_tag_health; float autocvar_g_balance_seeker_tag_lifetime; float autocvar_g_balance_seeker_tag_refire; float autocvar_g_balance_seeker_tag_speed; +float autocvar_g_balance_seeker_reload_ammo; +float autocvar_g_balance_seeker_reload_time; float autocvar_g_balance_selfdamagepercent; float autocvar_g_balance_shotgun_primary_ammo; float autocvar_g_balance_shotgun_primary_animtime; @@ -613,6 +637,8 @@ float autocvar_g_balance_shotgun_secondary_melee_range; float autocvar_g_balance_shotgun_secondary_melee_swing; float autocvar_g_balance_shotgun_secondary_melee_time; 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_teams; float autocvar_g_balance_teams_force; float autocvar_g_balance_teams_prevent_imbalance; @@ -646,6 +672,8 @@ float autocvar_g_balance_uzi_sustained_damage; float autocvar_g_balance_uzi_sustained_force; float autocvar_g_balance_uzi_sustained_refire; float autocvar_g_balance_uzi_sustained_spread; +float autocvar_g_balance_uzi_reload_ammo; +float autocvar_g_balance_uzi_reload_time; float autocvar_g_balance_weaponswitchdelay; float autocvar_g_ballistics_density_corpse; float autocvar_g_ballistics_density_player; diff --git a/qcsrc/server/bot/havocbot/havocbot.qc b/qcsrc/server/bot/havocbot/havocbot.qc index fde9a26db2..34db488b13 100644 --- a/qcsrc/server/bot/havocbot/havocbot.qc +++ b/qcsrc/server/bot/havocbot/havocbot.qc @@ -145,6 +145,31 @@ void havocbot_ai() bot_aimdir(v, -1); } havocbot_movetogoal(); + + // if the bot is not attacking, consider reloading weapons + if not(self.aistatus & AI_STATUS_ATTACKING) + { + float i; + entity e; + + // we are currently holding a weapon that's not fully loaded, reload it + if(skill >= 2) // bots can only reload the held weapon on purpose past this skill + if(self.clip_load < self.clip_size) + self.impulse = 20; // "press" the reload button, not sure if this is done right + + // if we're not reloading a weapon, switch to any weapon in our invnetory that's not fully loaded to reload it next + // the code above executes next frame, starting the reloading then + if(skill >= 5) // bots can only look for unloaded weapons past this skill + if(self.clip_load >= 0) // only if we're not reloading a weapon already + { + for(i = WEP_FIRST; i <= WEP_LAST; ++i) + { + e = get_weaponinfo(i); + if(self.weapon_load[i] < cvar(strcat("g_balance_", e.netname, "_reload_ammo"))) + self.switchweapon = i; + } + } + } }; void havocbot_keyboard_movement(vector destorg) @@ -914,6 +939,31 @@ void havocbot_chooseenemy() self.havocbot_stickenemy = TRUE; }; +float havocbot_chooseweapon_checkreload(float new_weapon) +{ + // bots under this skill cannot find unloaded weapons to reload idly when not in combat, + // so skip this for them, or they'll never get to reload their weapons at all. + // this also allows bots under this skill to be more stupid, and reload more often during combat :) + if(skill < 5) + return FALSE; + + // if this weapon is scheduled for reloading, don't switch to it during combat + if (self.weapon_load[new_weapon] < 0) + { + local float i, other_weapon_available; + for(i = WEP_FIRST; i <= WEP_LAST; ++i) + { + // if we are out of ammo for all other weapons, it's an emergency to switch to anything else + if (weapon_action(i, WR_CHECKAMMO1) + weapon_action(i, WR_CHECKAMMO2)) + other_weapon_available = TRUE; + } + if(other_weapon_available) + return TRUE; + } + + return FALSE; +} + void havocbot_chooseweapon() { local float i; @@ -946,11 +996,6 @@ void havocbot_chooseweapon() if(i < 1) return; - // Workaround for rifle reloading (..) - if(self.weapon == WEP_SNIPERRIFLE) - if(i < autocvar_g_balance_sniperrifle_reloadtime + 1) - return; - local float w; local float distance; distance=bound(10,vlen(self.origin-self.enemy.origin)-200,10000); @@ -983,8 +1028,9 @@ void havocbot_chooseweapon() if ( distance > bot_distance_far ) { for(i=0; i < WEP_COUNT && bot_weapons_far[i] != -1 ; ++i){ w = bot_weapons_far[i]; - if ( client_hasweapon(self, w, TRUE, FALSE) ){ - if ( self.weapon == w && combo) + if ( client_hasweapon(self, w, TRUE, FALSE) ) + { + if ((self.weapon == w && combo) || havocbot_chooseweapon_checkreload(w)) continue; self.switchweapon = w; return; @@ -996,8 +1042,9 @@ void havocbot_chooseweapon() if ( distance > bot_distance_close) { for(i=0; i < WEP_COUNT && bot_weapons_mid[i] != -1 ; ++i){ w = bot_weapons_mid[i]; - if ( client_hasweapon(self, w, TRUE, FALSE) ){ - if ( self.weapon == w && combo) + if ( client_hasweapon(self, w, TRUE, FALSE) ) + { + if ((self.weapon == w && combo) || havocbot_chooseweapon_checkreload(w)) continue; self.switchweapon = w; return; @@ -1008,8 +1055,9 @@ void havocbot_chooseweapon() // Choose weapons for close distance for(i=0; i < WEP_COUNT && bot_weapons_close[i] != -1 ; ++i){ w = bot_weapons_close[i]; - if ( client_hasweapon(self, w, TRUE, FALSE) ){ - if ( self.weapon == w && combo) + if ( client_hasweapon(self, w, TRUE, FALSE) ) + { + if ((self.weapon == w && combo) || havocbot_chooseweapon_checkreload(w)) continue; self.switchweapon = w; return; diff --git a/qcsrc/server/cl_client.qc b/qcsrc/server/cl_client.qc index 71584d3503..c5312469a8 100644 --- a/qcsrc/server/cl_client.qc +++ b/qcsrc/server/cl_client.qc @@ -1050,8 +1050,16 @@ void PutClientInServer (void) // reset fields the weapons may use for (j = WEP_FIRST; j <= WEP_LAST; ++j) + { weapon_action(j, WR_RESETPLAYER); + // all weapons must be fully loaded when we spawn + 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")); + } + oldself = self; self = spot; activator = oldself; @@ -1065,8 +1073,6 @@ void PutClientInServer (void) self.cnt = self.switchweapon; self.weapon = 0; - self.wish_reload = 0; - if(!self.alivetime) self.alivetime = time; } else if(self.classname == "observer" || (g_ca && !allowed_to_spawn)) { @@ -1109,7 +1115,6 @@ float ClientInit_SendEntity(entity to, float sf) WriteByte(MSG_ENTITY, autocvar_g_balance_nex_secondary); // client has to know if it should zoom or not WriteByte(MSG_ENTITY, autocvar_g_balance_sniperrifle_secondary); // client has to know if it should zoom or not WriteByte(MSG_ENTITY, serverflags); // client has to know if it should zoom or not - WriteByte(MSG_ENTITY, autocvar_g_balance_sniperrifle_magazinecapacity); // rifle max bullets WriteCoord(MSG_ENTITY, autocvar_g_trueaim_minrange); return TRUE; } @@ -2341,6 +2346,8 @@ void SpectateCopy(entity spectatee) { self.ammo_nails = spectatee.ammo_nails; self.ammo_rockets = spectatee.ammo_rockets; self.ammo_fuel = spectatee.ammo_fuel; + self.clip_load = spectatee.clip_load; + self.clip_size = spectatee.clip_size; self.effects = spectatee.effects & EFMASK_CHEAP; // eat performance self.health = spectatee.health; self.impulse = 0; @@ -2943,6 +2950,10 @@ void PlayerPreThink (void) } target_voicescript_next(self); + + // if a player goes unarmed after holding a loaded weapon, empty his clip size and remove the crosshair ammo ring + if(!self.weapon) + self.clip_load = self.clip_size = 0; } float isInvisibleString(string s) diff --git a/qcsrc/server/cl_impulse.qc b/qcsrc/server/cl_impulse.qc index ff3903cbad..7bde8b32f7 100644 --- a/qcsrc/server/cl_impulse.qc +++ b/qcsrc/server/cl_impulse.qc @@ -98,7 +98,7 @@ void ImpulseCommands (void) W_PreviousWeapon (1); break; case 20: - W_Reload (); + W_TriggerReload (); break; } } diff --git a/qcsrc/server/cl_weapons.qc b/qcsrc/server/cl_weapons.qc index 864dd77fce..7b0bbce3c8 100644 --- a/qcsrc/server/cl_weapons.qc +++ b/qcsrc/server/cl_weapons.qc @@ -1,6 +1,6 @@ -void W_Reload() +void W_TriggerReload() { - self.wish_reload = 1; + weapon_action(self.weapon, WR_RELOAD); } // switch between weapons @@ -15,7 +15,7 @@ void W_SwitchWeapon(float imp) } else { - W_Reload(); + W_TriggerReload(); } }; @@ -221,6 +221,13 @@ string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vecto wep.ammofield = thisammo; own.ammofield -= thisammo; s = strcat(s, " and ", ftos(thisammo), " ", Item_CounterFieldName(j)); + + // if our weapon is loaded, give its load back to the player + if(self.weapon_load[self.weapon] > 0) + { + own.ammofield += self.weapon_load[self.weapon]; + self.weapon_load[self.weapon] = -1; // schedule the weapon for reloading + } } } s = substring(s, 5, -1); @@ -340,6 +347,18 @@ void W_WeaponFrame() setanim(self, self.anim_draw, FALSE, TRUE, TRUE); self.weaponentity.state = WS_RAISE; weapon_action(self.switchweapon, WR_SETUP); + + // set our clip load to the load of the weapon we switched to, if it's reloadable + entity e; + e = get_weaponinfo(self.switchweapon); + if(e.spawnflags & WEP_FLAG_RELOADABLE && cvar(strcat("g_balance_", e.netname, "_reload_ammo"))) // prevent accessing undefined cvars + { + self.clip_load = self.weapon_load[self.switchweapon]; + self.clip_size = cvar(strcat("g_balance_", e.netname, "_reload_ammo")); + } + else + self.clip_load = self.clip_size = 0; + // VorteX: add player model weapon select frame here // setcustomframe(PlayerWeaponRaise); weapon_thinkf(WFRAME_IDLE, autocvar_g_balance_weaponswitchdelay, w_ready); diff --git a/qcsrc/server/cl_weaponsystem.qc b/qcsrc/server/cl_weaponsystem.qc index 057c5cb1dc..616aee69dc 100644 --- a/qcsrc/server/cl_weaponsystem.qc +++ b/qcsrc/server/cl_weaponsystem.qc @@ -1611,3 +1611,132 @@ void W_SetupProjectileVelocity(entity missile, float pSpeed, float spread) #define W_SETUPPROJECTILEVELOCITY_UP(m,s) W_SetupProjectileVelocityEx(m, w_shotdir, v_up, cvar(#s "_speed"), cvar(#s "_speed_up"), cvar(#s "_speed_z"), cvar(#s "_spread"), FALSE) #define W_SETUPPROJECTILEVELOCITY(m,s) W_SetupProjectileVelocityEx(m, w_shotdir, v_up, cvar(#s "_speed"), 0, 0, cvar(#s "_spread"), FALSE) + +void W_DecreaseAmmo(.float ammo_type, float ammo_use, float ammo_reload) +{ + if(self.items & IT_UNLIMITED_WEAPON_AMMO) + return; + + // if this weapon is reloadable, decrease its load. Else decrease the player's ammo + if(ammo_reload) + { + self.clip_load -= ammo_use; + self.weapon_load[self.weapon] = self.clip_load; + } + else + self.(self.current_ammo) -= ammo_use; +} + +// weapon reloading code + +.float reload_ammo_amount, reload_ammo_min, reload_time; +.float reload_complain; +.string reload_sound; + +float W_ReloadCheck() +{ + // check if we meet the necessary conditions to reload + + entity e; + e = get_weaponinfo(self.weapon); + + // don't reload weapons that don't have the RELOADABLE flag + if not(e.spawnflags & WEP_FLAG_RELOADABLE) + { + dprint("Warning: Attempted to reload a weapon that does not have the WEP_FLAG_RELOADABLE flag. Fix your code!\n"); + return FALSE; + } + + // return if reloading is disabled for this weapon + if(!self.reload_ammo_amount) + return FALSE; + + // our weapon is fully loaded, no need to reload + if (self.clip_load >= self.reload_ammo_amount) + return FALSE; + + // no ammo, so nothing to load + if(!self.(self.current_ammo) && self.reload_ammo_min) + { + if(clienttype(self) == CLIENTTYPE_REAL && self.reload_complain < time) + { + play2(self, "weapons/unavailable.wav"); + sprint(self, strcat("You don't have enough ammo to reload the ^2", W_Name(self.weapon), "\n")); + self.reload_complain = time + 1; + } + // switch away if the amount of ammo is not enough to keep using this weapon + if not(weapon_action(self.weapon, WR_CHECKAMMO1) + weapon_action(self.weapon, WR_CHECKAMMO2)) + { + self.clip_load = -1; // reload later + W_SwitchToOtherWeapon(self); + } + return FALSE; + } + + if (self.weaponentity) + { + if (self.weaponentity.wframe == WFRAME_RELOAD) + return FALSE; + + // allow switching away while reloading, but this will cause a new reload! + self.weaponentity.state = WS_READY; + } + + return TRUE; +} + +void W_ReloadedAndReady() +{ + // finish the reloading process, and do the ammo transfer + + self.clip_load = self.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading + + // if the gun uses no ammo, max out weapon load, else decrease ammo as we increase weapon load + if(!self.reload_ammo_min) + self.clip_load = self.reload_ammo_amount; + else + { + while(self.clip_load < self.reload_ammo_amount && self.(self.current_ammo)) // make sure we don't add more ammo than we have + { + self.clip_load += 1; + self.(self.current_ammo) -= 1; + } + } + self.weapon_load[self.weapon] = self.clip_load; + + // do not set ATTACK_FINISHED in reload code any more. This causes annoying delays if eg: You start reloading a weapon, + // then quickly switch to another weapon and back. Reloading is canceled, but the reload delay is still there, + // so your weapon is disabled for a few seconds without reason + + //ATTACK_FINISHED(self) -= self.reload_time - 1; + + w_ready(); +} + +void W_Reload(float sent_ammo_min, float sent_ammo_amount, float sent_time, string sent_sound) +{ + // set global values to work with + self.reload_ammo_min = sent_ammo_min; + self.reload_ammo_amount = sent_ammo_amount; + self.reload_time = sent_time; + self.reload_sound = sent_sound; + + if(!W_ReloadCheck()) + return; + + // now begin the reloading process + + sound (self, CHAN_WEAPON2, self.reload_sound, VOL_BASE, ATTN_NORM); + + // do not set ATTACK_FINISHED in reload code any more. This causes annoying delays if eg: You start reloading a weapon, + // then quickly switch to another weapon and back. Reloading is canceled, but the reload delay is still there, + // so your weapon is disabled for a few seconds without reason + + //ATTACK_FINISHED(self) = max(time, ATTACK_FINISHED(self)) + self.reload_time + 1; + + weapon_thinkf(WFRAME_RELOAD, self.reload_time, W_ReloadedAndReady); + + if(self.clip_load >= 0) + self.old_clip_load = self.clip_load; + self.clip_load = self.weapon_load[self.weapon] = -1; +} \ No newline at end of file diff --git a/qcsrc/server/defs.qh b/qcsrc/server/defs.qh index 936cb9c6b6..df80e703b7 100644 --- a/qcsrc/server/defs.qh +++ b/qcsrc/server/defs.qh @@ -617,8 +617,13 @@ float client_cefc_accumulator; float client_cefc_accumulatortime; #endif -.float sniperrifle_bulletcounter; -.float wish_reload; +..float current_ammo; + +.float weapon_load[WEP_MAXCOUNT]; FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(weapon_load); +.float ammo_none; // used by the reloading system, must always be 0 +.float clip_load; +.float old_clip_load; +.float clip_size; #define PROJECTILE_MAKETRIGGER(e) (e).solid = SOLID_CORPSE; (e).dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE // when doing this, hagar can go through clones diff --git a/qcsrc/server/g_world.qc b/qcsrc/server/g_world.qc index 268743b415..57d0071d2f 100644 --- a/qcsrc/server/g_world.qc +++ b/qcsrc/server/g_world.qc @@ -823,7 +823,8 @@ void spawnfunc_worldspawn (void) addstat(STAT_FUEL, AS_INT, ammo_fuel); addstat(STAT_SHOTORG, AS_INT, stat_shotorg); addstat(STAT_LEADLIMIT, AS_FLOAT, stat_leadlimit); - addstat(STAT_BULLETS_LOADED, AS_INT, sniperrifle_bulletcounter); + addstat(STAT_WEAPON_CLIPLOAD, AS_INT, clip_load); + addstat(STAT_WEAPON_CLIPSIZE, AS_INT, clip_size); addstat(STAT_LAST_PICKUP, AS_FLOAT, last_pickup); addstat(STAT_HIT_TIME, AS_FLOAT, hit_time); addstat(STAT_TYPEHIT_TIME, AS_FLOAT, typehit_time); diff --git a/qcsrc/server/w_crylink.qc b/qcsrc/server/w_crylink.qc index 93a110dad8..d393a32f3e 100644 --- a/qcsrc/server/w_crylink.qc +++ b/qcsrc/server/w_crylink.qc @@ -1,5 +1,5 @@ #ifdef REGISTER_WEAPON -REGISTER_WEAPON(CRYLINK, w_crylink, IT_CELLS, 6, WEP_FLAG_NORMAL | WEP_TYPE_SPLASH, BOT_PICKUP_RATING_MID, "crylink", "crylink", _("Crylink")); +REGISTER_WEAPON(CRYLINK, w_crylink, IT_CELLS, 6, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH, BOT_PICKUP_RATING_MID, "crylink", "crylink", _("Crylink")); #else #ifdef SVQC .float gravity; @@ -329,8 +329,7 @@ void W_Crylink_Attack (void) vector forward, right, up; float maxdmg; - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - self.ammo_cells = self.ammo_cells - autocvar_g_balance_crylink_primary_ammo; + W_DecreaseAmmo(ammo_cells, autocvar_g_balance_crylink_primary_ammo, autocvar_g_balance_crylink_reload_ammo); maxdmg = autocvar_g_balance_crylink_primary_damage*autocvar_g_balance_crylink_primary_shots; maxdmg *= 1 + autocvar_g_balance_crylink_primary_bouncedamagefactor * autocvar_g_balance_crylink_primary_bounces; @@ -433,8 +432,7 @@ void W_Crylink_Attack2 (void) local entity proj, prevproj, firstproj; float maxdmg; - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - self.ammo_cells = self.ammo_cells - autocvar_g_balance_crylink_secondary_ammo; + W_DecreaseAmmo(ammo_cells, autocvar_g_balance_crylink_secondary_ammo, autocvar_g_balance_crylink_reload_ammo); maxdmg = autocvar_g_balance_crylink_secondary_damage*autocvar_g_balance_crylink_secondary_shots; maxdmg *= 1 + autocvar_g_balance_crylink_secondary_bouncedamagefactor * autocvar_g_balance_crylink_secondary_bounces; @@ -522,6 +520,7 @@ void spawnfunc_weapon_crylink (void) float w_crylink(float req) { + float ammo_amount; if (req == WR_AIM) { if (random() < 0.10) @@ -531,7 +530,9 @@ float w_crylink(float req) } else if (req == WR_THINK) { - if (self.BUTTON_ATCK) + if(autocvar_g_balance_crylink_reload_ammo && self.clip_load < min(autocvar_g_balance_crylink_primary_ammo, autocvar_g_balance_crylink_secondary_ammo)) // forced reload + weapon_action(self.weapon, WR_RELOAD); + else if (self.BUTTON_ATCK) { if (!self.crylink_waitrelease) if (weapon_prepareattack(0, autocvar_g_balance_crylink_primary_refire)) @@ -598,22 +599,36 @@ float w_crylink(float req) precache_sound ("weapons/crylink_fire.wav"); precache_sound ("weapons/crylink_fire2.wav"); precache_sound ("weapons/crylink_linkjoin.wav"); + precache_sound ("weapons/reload.wav"); } else if (req == WR_SETUP) + { weapon_setup(WEP_CRYLINK); + self.current_ammo = ammo_cells; + } else if (req == WR_CHECKAMMO1) { // don't "run out of ammo" and switch weapons while waiting for release if(self.crylink_lastgroup && self.crylink_waitrelease) return TRUE; - return self.ammo_cells >= autocvar_g_balance_crylink_primary_ammo; + + ammo_amount = self.ammo_cells >= autocvar_g_balance_crylink_primary_ammo; + ammo_amount += self.weapon_load[WEP_CRYLINK] >= autocvar_g_balance_crylink_primary_ammo; + return ammo_amount; } else if (req == WR_CHECKAMMO2) { // don't "run out of ammo" and switch weapons while waiting for release if(self.crylink_lastgroup && self.crylink_waitrelease) return TRUE; - return self.ammo_cells >= autocvar_g_balance_crylink_secondary_ammo; + + ammo_amount = self.ammo_cells >= autocvar_g_balance_crylink_secondary_ammo; + ammo_amount += self.weapon_load[WEP_CRYLINK] >= autocvar_g_balance_crylink_secondary_ammo; + return ammo_amount; + } + else if (req == WR_RELOAD) + { + W_Reload(min(autocvar_g_balance_crylink_primary_ammo, autocvar_g_balance_crylink_secondary_ammo), autocvar_g_balance_crylink_reload_ammo, autocvar_g_balance_crylink_reload_time, "weapons/reload.wav"); } return TRUE; }; diff --git a/qcsrc/server/w_electro.qc b/qcsrc/server/w_electro.qc index f5491f39aa..a9f927db10 100644 --- a/qcsrc/server/w_electro.qc +++ b/qcsrc/server/w_electro.qc @@ -1,5 +1,5 @@ #ifdef REGISTER_WEAPON -REGISTER_WEAPON(ELECTRO, w_electro, IT_CELLS, 5, WEP_FLAG_NORMAL | WEP_TYPE_SPLASH, BOT_PICKUP_RATING_MID, "electro", "electro", _("Electro")); +REGISTER_WEAPON(ELECTRO, w_electro, IT_CELLS, 5, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH, BOT_PICKUP_RATING_MID, "electro", "electro", _("Electro")); #else #ifdef SVQC .float electro_count; @@ -110,6 +110,8 @@ void W_Electro_Attack() { local entity proj; + W_DecreaseAmmo(ammo_cells, autocvar_g_balance_electro_primary_ammo, autocvar_g_balance_electro_reload_ammo); + W_SetupShot_ProjectileSize (self, '0 0 -3', '0 0 -3', FALSE, 2, "weapons/electro_fire.wav", CHAN_WEAPON, autocvar_g_balance_electro_primary_damage); pointparticles(particleeffectnum("electro_muzzleflash"), w_shotorg, w_shotdir * 1000, 1); @@ -126,8 +128,6 @@ void W_Electro_Attack() proj.projectiledeathtype = WEP_ELECTRO; setorigin(proj, w_shotorg); - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - self.ammo_cells = self.ammo_cells - autocvar_g_balance_electro_primary_ammo; proj.movetype = MOVETYPE_FLY; W_SETUPPROJECTILEVELOCITY(proj, g_balance_electro_primary); proj.angles = vectoangles(proj.velocity); @@ -147,6 +147,8 @@ void W_Electro_Attack2() { local entity proj; + W_DecreaseAmmo(ammo_cells, autocvar_g_balance_electro_secondary_ammo, autocvar_g_balance_electro_reload_ammo); + W_SetupShot_ProjectileSize (self, '0 0 -4', '0 0 -4', FALSE, 2, "weapons/electro_fire2.wav", CHAN_WEAPON, autocvar_g_balance_electro_secondary_damage); w_shotdir = v_forward; // no TrueAim for grenades please @@ -165,8 +167,6 @@ void W_Electro_Attack2() proj.projectiledeathtype = WEP_ELECTRO | HITTYPE_SECONDARY; setorigin(proj, w_shotorg); - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - self.ammo_cells = self.ammo_cells - autocvar_g_balance_electro_secondary_ammo; //proj.glow_size = 50; //proj.glow_color = 45; proj.movetype = MOVETYPE_BOUNCE; @@ -193,7 +193,7 @@ void W_Electro_Attack2() CSQCProjectile(proj, TRUE, PROJECTILE_ELECTRO, FALSE); // no culling, it has sound other = proj; MUTATOR_CALLHOOK(EditProjectile); - } +} .vector hook_start, hook_end; float lgbeam_send(entity to, float sf) @@ -224,39 +224,64 @@ float lgbeam_send(entity to, float sf) } .entity lgbeam; .float prevlgfire; +float lgbeam_checkammo() +{ + if(self.owner.items & IT_UNLIMITED_WEAPON_AMMO) + return TRUE; + else if(autocvar_g_balance_electro_reload_ammo) + return self.owner.clip_load > 0; + else + return self.owner.ammo_cells > 0; +} + void lgbeam_think() { - self.owner.prevlgfire = time; - if (self != self.owner.lgbeam) + entity owner_player; + owner_player = self.owner; + + owner_player.prevlgfire = time; + if (self != owner_player.lgbeam) { remove(self); return; } - if (self.owner.weaponentity.state != WS_INUSE || (self.owner.ammo_cells <= 0 && !(self.owner.items & IT_UNLIMITED_WEAPON_AMMO)) || self.owner.deadflag != DEAD_NO || !self.owner.BUTTON_ATCK || self.owner.freezetag_frozen) + + if (owner_player.weaponentity.state != WS_INUSE || !lgbeam_checkammo() || owner_player.deadflag != DEAD_NO || !owner_player.BUTTON_ATCK || owner_player.freezetag_frozen) { - if(self == self.owner.lgbeam) - self.owner.lgbeam = world; + if(self == owner_player.lgbeam) + owner_player.lgbeam = world; remove(self); return; } self.nextthink = time; - makevectors(self.owner.v_angle); + makevectors(owner_player.v_angle); float dt, f; dt = frametime; - if not(self.owner.items & IT_UNLIMITED_WEAPON_AMMO) + + // if this weapon is reloadable, decrease its load. Else decrease the player's ammo + if not(owner_player.items & IT_UNLIMITED_WEAPON_AMMO) { if(autocvar_g_balance_electro_primary_ammo) { - dt = min(dt, self.owner.ammo_cells / autocvar_g_balance_electro_primary_ammo); - self.owner.ammo_cells = max(0, self.owner.ammo_cells - autocvar_g_balance_electro_primary_ammo * frametime); + if(autocvar_g_balance_electro_reload_ammo) + { + dt = min(dt, owner_player.clip_load / autocvar_g_balance_electro_primary_ammo); + owner_player.clip_load = max(0, owner_player.clip_load - autocvar_g_balance_electro_primary_ammo * frametime); + owner_player.weapon_load[WEP_ELECTRO] = owner_player.clip_load; + } + else + { + dt = min(dt, owner_player.ammo_cells / autocvar_g_balance_electro_primary_ammo); + owner_player.ammo_cells = max(0, owner_player.ammo_cells - autocvar_g_balance_electro_primary_ammo * frametime); + } } } - W_SetupShot_Range(self.owner, TRUE, 0, "", 0, autocvar_g_balance_electro_primary_damage * dt, autocvar_g_balance_electro_primary_range); - WarpZone_traceline_antilag(self.owner, w_shotorg, w_shotend, MOVE_NORMAL, self.owner, ANTILAG_LATENCY(self.owner)); + W_SetupShot_Range(owner_player, TRUE, 0, "", 0, autocvar_g_balance_electro_primary_damage * dt, autocvar_g_balance_electro_primary_range); + WarpZone_traceline_antilag(owner_player, w_shotorg, w_shotend, MOVE_NORMAL, owner_player, ANTILAG_LATENCY(owner_player)); // apply the damage if(trace_ent) @@ -266,11 +291,11 @@ void lgbeam_think() f = ExponentialFalloff(autocvar_g_balance_electro_primary_falloff_mindist, autocvar_g_balance_electro_primary_falloff_maxdist, autocvar_g_balance_electro_primary_falloff_halflifedist, vlen(WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos) - w_shotorg)); - if(accuracy_isgooddamage(self.owner, trace_ent)) - accuracy_add(self.owner, WEP_ELECTRO, 0, autocvar_g_balance_electro_primary_damage * dt * f); - Damage (trace_ent, self.owner, self.owner, autocvar_g_balance_electro_primary_damage * dt * f, WEP_ELECTRO, trace_endpos, force * dt); + if(accuracy_isgooddamage(owner_player, trace_ent)) + accuracy_add(owner_player, WEP_ELECTRO, 0, autocvar_g_balance_electro_primary_damage * dt * f); + Damage (trace_ent, owner_player, owner_player, autocvar_g_balance_electro_primary_damage * dt * f, WEP_ELECTRO, trace_endpos, force * dt); } - W_Plasma_TriggerCombo(trace_endpos, autocvar_g_balance_electro_primary_comboradius, self.owner); + W_Plasma_TriggerCombo(trace_endpos, autocvar_g_balance_electro_primary_comboradius, owner_player); // draw effect if(w_shotorg != self.hook_start) @@ -344,6 +369,7 @@ void w_electro_checkattack() .float BUTTON_ATCK_prev; float w_electro(float req) { + float ammo_amount; if (req == WR_AIM) { self.BUTTON_ATCK=FALSE; @@ -376,6 +402,24 @@ float w_electro(float req) } else if (req == WR_THINK) { + if(autocvar_g_balance_electro_reload_ammo) // forced reload + { + if(autocvar_g_balance_electro_lightning) + { + if(self.clip_load > 0) + ammo_amount = 1; + } + else if(self.clip_load >= autocvar_g_balance_electro_primary_ammo) + ammo_amount = 1; + if(self.clip_load >= autocvar_g_balance_electro_secondary_ammo) + ammo_amount += 1; + + if(!ammo_amount) + { + weapon_action(self.weapon, WR_RELOAD); + return FALSE; + } + } if (self.BUTTON_ATCK) { if(autocvar_g_balance_electro_lightning) @@ -417,16 +461,18 @@ float w_electro(float req) } self.BUTTON_ATCK_prev = 0; } - } - if (self.BUTTON_ATCK2) - if (time >= self.electro_secondarytime) - if (weapon_prepareattack(1, autocvar_g_balance_electro_secondary_refire)) - { - W_Electro_Attack2(); - self.electro_count = autocvar_g_balance_electro_secondary_count; - weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_electro_secondary_animtime, w_electro_checkattack); - self.electro_secondarytime = time + autocvar_g_balance_electro_secondary_refire2 * W_WeaponRateFactor(); + if (self.BUTTON_ATCK2) + { + if (time >= self.electro_secondarytime) + if (weapon_prepareattack(1, autocvar_g_balance_electro_secondary_refire)) + { + W_Electro_Attack2(); + self.electro_count = autocvar_g_balance_electro_secondary_count; + weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_electro_secondary_animtime, w_electro_checkattack); + self.electro_secondarytime = time + autocvar_g_balance_electro_secondary_refire2 * W_WeaponRateFactor(); + } + } } } else if (req == WR_PRECACHE) @@ -439,26 +485,48 @@ float w_electro(float req) precache_sound ("weapons/electro_fire2.wav"); precache_sound ("weapons/electro_impact.wav"); precache_sound ("weapons/electro_impact_combo.wav"); + precache_sound ("weapons/reload.wav"); if(autocvar_g_balance_electro_lightning) { precache_sound ("weapons/lgbeam_fire.wav"); } } else if (req == WR_SETUP) + { weapon_setup(WEP_ELECTRO); + self.current_ammo = ammo_cells; + } else if (req == WR_CHECKAMMO1) { if(autocvar_g_balance_electro_lightning) - return !autocvar_g_balance_electro_primary_ammo || (self.ammo_cells > 0); + { + if(!autocvar_g_balance_electro_primary_ammo) + ammo_amount = 1; + else + ammo_amount = self.ammo_cells > 0; + ammo_amount += self.weapon_load[WEP_ELECTRO] > 0; + } else - return self.ammo_cells >= autocvar_g_balance_electro_primary_ammo; + { + ammo_amount = self.ammo_cells >= autocvar_g_balance_electro_primary_ammo; + ammo_amount += self.weapon_load[WEP_ELECTRO] >= autocvar_g_balance_electro_primary_ammo; + } + return ammo_amount; } else if (req == WR_CHECKAMMO2) - return self.ammo_cells >= autocvar_g_balance_electro_secondary_ammo; + { + ammo_amount = self.ammo_cells >= autocvar_g_balance_electro_secondary_ammo; + ammo_amount += self.weapon_load[WEP_ELECTRO] >= autocvar_g_balance_electro_secondary_ammo; + return ammo_amount; + } else if (req == WR_RESETPLAYER) { self.electro_secondarytime = time; } + else if (req == WR_RELOAD) + { + W_Reload(min(autocvar_g_balance_electro_primary_ammo, autocvar_g_balance_electro_secondary_ammo), autocvar_g_balance_electro_reload_ammo, autocvar_g_balance_electro_reload_time, "weapons/reload.wav"); + } return TRUE; }; #endif diff --git a/qcsrc/server/w_fireball.qc b/qcsrc/server/w_fireball.qc index 73ff1595a7..e7dec23932 100644 --- a/qcsrc/server/w_fireball.qc +++ b/qcsrc/server/w_fireball.qc @@ -1,5 +1,5 @@ #ifdef REGISTER_WEAPON -REGISTER_WEAPON(FIREBALL, w_fireball, IT_FUEL, 9, WEP_TYPE_SPLASH, BOT_PICKUP_RATING_MID, "fireball", "fireball", _("Fireball")); +REGISTER_WEAPON(FIREBALL, w_fireball, IT_FUEL, 9, WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH, BOT_PICKUP_RATING_MID, "fireball", "fireball", _("Fireball")); #else #ifdef SVQC .float bot_primary_fireballmooth; // whatever a mooth is @@ -194,8 +194,7 @@ void W_Fireball_Attack1_Frame1() void W_Fireball_Attack1_Frame0() { - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - self.ammo_fuel = self.ammo_fuel - autocvar_g_balance_fireball_primary_ammo; + W_DecreaseAmmo(ammo_fuel, autocvar_g_balance_fireball_primary_ammo, autocvar_g_balance_fireball_reload_ammo); W_Fireball_AttackEffect(0, '-1.25 -3.75 0'); sound (self, CHAN_WEAPON, "weapons/fireball_prefire2.wav", VOL_BASE, ATTN_NORM); @@ -246,8 +245,7 @@ void W_Fireball_Attack2() vector f_diff; float c; - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - self.ammo_fuel = self.ammo_fuel - autocvar_g_balance_fireball_secondary_ammo; + W_DecreaseAmmo(ammo_fuel, autocvar_g_balance_fireball_secondary_ammo, autocvar_g_balance_fireball_reload_ammo); c = mod(self.bulletcounter, 4); switch(c) @@ -304,6 +302,7 @@ void spawnfunc_weapon_fireball (void) float w_fireball(float req) { + float ammo_amount; if (req == WR_AIM) { self.BUTTON_ATCK = FALSE; @@ -327,18 +326,24 @@ float w_fireball(float req) } else if (req == WR_THINK) { - if (self.BUTTON_ATCK) - if (time >= self.fireball_primarytime) - if (weapon_prepareattack(0, autocvar_g_balance_fireball_primary_refire)) + if(autocvar_g_balance_fireball_reload_ammo && self.clip_load < min(autocvar_g_balance_fireball_primary_ammo, autocvar_g_balance_fireball_secondary_ammo)) // forced reload + weapon_action(self.weapon, WR_RELOAD); + else if (self.BUTTON_ATCK) { - W_Fireball_Attack1_Frame0(); - self.fireball_primarytime = time + autocvar_g_balance_fireball_primary_refire2; + if (time >= self.fireball_primarytime) + if (weapon_prepareattack(0, autocvar_g_balance_fireball_primary_refire)) + { + W_Fireball_Attack1_Frame0(); + self.fireball_primarytime = time + autocvar_g_balance_fireball_primary_refire2; + } } - if (self.BUTTON_ATCK2) - if (weapon_prepareattack(1, autocvar_g_balance_fireball_secondary_refire)) + else if (self.BUTTON_ATCK2) { - W_Fireball_Attack2(); - weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_fireball_secondary_animtime, w_ready); + if (weapon_prepareattack(1, autocvar_g_balance_fireball_secondary_refire)) + { + W_Fireball_Attack2(); + weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_fireball_secondary_animtime, w_ready); + } } } else if (req == WR_PRECACHE) @@ -350,17 +355,37 @@ float w_fireball(float req) precache_sound ("weapons/fireball_fire.wav"); precache_sound ("weapons/fireball_fire2.wav"); precache_sound ("weapons/fireball_prefire2.wav"); + precache_sound ("weapons/reload.wav"); } else if (req == WR_SETUP) + { weapon_setup(WEP_FIREBALL); + self.current_ammo = ammo_fuel; + } else if (req == WR_CHECKAMMO1) - return self.ammo_fuel >= autocvar_g_balance_fireball_primary_ammo; + { + ammo_amount = self.ammo_fuel >= autocvar_g_balance_fireball_primary_ammo; + ammo_amount += self.weapon_load[WEP_FIREBALL] >= autocvar_g_balance_fireball_primary_ammo; + return ammo_amount; + } else if (req == WR_CHECKAMMO2) - return self.ammo_fuel >= autocvar_g_balance_fireball_secondary_ammo; + { + ammo_amount = self.ammo_fuel >= autocvar_g_balance_fireball_secondary_ammo; + ammo_amount += self.weapon_load[WEP_FIREBALL] >= autocvar_g_balance_fireball_secondary_ammo; + return ammo_amount; + } else if (req == WR_RESETPLAYER) { self.fireball_primarytime = time; } + else if (req == WR_RELOAD) + { + // fuel can be a non-whole number, which brakes stuff here when between 0 and 1 + if(self.ammo_fuel < 1) + self.ammo_fuel = 0; + + W_Reload(min(autocvar_g_balance_fireball_primary_ammo, autocvar_g_balance_fireball_secondary_ammo), autocvar_g_balance_fireball_reload_ammo, autocvar_g_balance_fireball_reload_time, "weapons/reload.wav"); + } return TRUE; }; #endif diff --git a/qcsrc/server/w_grenadelauncher.qc b/qcsrc/server/w_grenadelauncher.qc index d5f6c5d682..82cca44909 100644 --- a/qcsrc/server/w_grenadelauncher.qc +++ b/qcsrc/server/w_grenadelauncher.qc @@ -1,5 +1,5 @@ #ifdef REGISTER_WEAPON -REGISTER_WEAPON(GRENADE_LAUNCHER, w_glauncher, IT_ROCKETS, 4, WEP_FLAG_NORMAL | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH, BOT_PICKUP_RATING_MID, "gl", "grenadelauncher", _("Mortar")) +REGISTER_WEAPON(GRENADE_LAUNCHER, w_glauncher, IT_ROCKETS, 4, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH, BOT_PICKUP_RATING_MID, "gl", "grenadelauncher", _("Mortar")) #else #ifdef SVQC .float gl_detonate_later; @@ -161,8 +161,8 @@ void W_Grenade_Attack (void) { local entity gren; - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - self.ammo_rockets = self.ammo_rockets - autocvar_g_balance_grenadelauncher_primary_ammo; + W_DecreaseAmmo(ammo_rockets, autocvar_g_balance_grenadelauncher_primary_ammo, autocvar_g_balance_grenadelauncher_reload_ammo); + W_SetupShot_ProjectileSize (self, '-3 -3 -3', '3 3 3', FALSE, 4, "weapons/grenade_fire.wav", CHAN_WEAPON, autocvar_g_balance_grenadelauncher_primary_damage); w_shotdir = v_forward; // no TrueAim for grenades please @@ -208,8 +208,8 @@ void W_Grenade_Attack2 (void) { local entity gren; - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - self.ammo_rockets = self.ammo_rockets - autocvar_g_balance_grenadelauncher_secondary_ammo; + W_DecreaseAmmo(ammo_rockets, autocvar_g_balance_grenadelauncher_secondary_ammo, autocvar_g_balance_grenadelauncher_reload_ammo); + W_SetupShot_ProjectileSize (self, '-3 -3 -3', '3 3 3', FALSE, 4, "weapons/grenade_fire.wav", CHAN_WEAPON, autocvar_g_balance_grenadelauncher_secondary_damage); w_shotdir = v_forward; // no TrueAim for grenades please @@ -260,6 +260,7 @@ float w_glauncher(float req) { entity nade; float nadefound; + float ammo_amount; if (req == WR_AIM) { @@ -284,13 +285,17 @@ float w_glauncher(float req) } else if (req == WR_THINK) { - if (self.BUTTON_ATCK) - if (weapon_prepareattack(0, autocvar_g_balance_grenadelauncher_primary_refire)) + if(autocvar_g_balance_grenadelauncher_reload_ammo && self.clip_load < min(autocvar_g_balance_grenadelauncher_primary_ammo, autocvar_g_balance_grenadelauncher_secondary_ammo)) // forced reload + weapon_action(self.weapon, WR_RELOAD); + else if (self.BUTTON_ATCK) { - W_Grenade_Attack(); - weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_grenadelauncher_primary_animtime, w_ready); + if (weapon_prepareattack(0, autocvar_g_balance_grenadelauncher_primary_refire)) + { + W_Grenade_Attack(); + weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_grenadelauncher_primary_animtime, w_ready); + } } - if (self.BUTTON_ATCK2) + else if (self.BUTTON_ATCK2) { if (cvar("g_balance_grenadelauncher_secondary_remote_detonateprimary")) { @@ -326,13 +331,29 @@ float w_glauncher(float req) precache_sound ("weapons/grenade_bounce6.wav"); precache_sound ("weapons/grenade_stick.wav"); precache_sound ("weapons/grenade_fire.wav"); + precache_sound ("weapons/reload.wav"); } else if (req == WR_SETUP) + { weapon_setup(WEP_GRENADE_LAUNCHER); + self.current_ammo = ammo_rockets; + } else if (req == WR_CHECKAMMO1) - return self.ammo_rockets >= autocvar_g_balance_grenadelauncher_primary_ammo; + { + ammo_amount = self.ammo_rockets >= autocvar_g_balance_grenadelauncher_primary_ammo; + ammo_amount += self.weapon_load[WEP_GRENADE_LAUNCHER] >= autocvar_g_balance_grenadelauncher_primary_ammo; + return ammo_amount; + } else if (req == WR_CHECKAMMO2) - return self.ammo_rockets >= autocvar_g_balance_grenadelauncher_secondary_ammo; + { + ammo_amount = self.ammo_rockets >= autocvar_g_balance_grenadelauncher_secondary_ammo; + ammo_amount += self.weapon_load[WEP_GRENADE_LAUNCHER] >= autocvar_g_balance_grenadelauncher_secondary_ammo; + return ammo_amount; + } + else if (req == WR_RELOAD) + { + W_Reload(min(autocvar_g_balance_grenadelauncher_primary_ammo, autocvar_g_balance_grenadelauncher_secondary_ammo), autocvar_g_balance_grenadelauncher_reload_ammo, autocvar_g_balance_grenadelauncher_reload_time, "weapons/reload.wav"); + } return TRUE; }; #endif diff --git a/qcsrc/server/w_hagar.qc b/qcsrc/server/w_hagar.qc index 5fb25642e2..92ca4ba005 100644 --- a/qcsrc/server/w_hagar.qc +++ b/qcsrc/server/w_hagar.qc @@ -1,8 +1,9 @@ #ifdef REGISTER_WEAPON -REGISTER_WEAPON(HAGAR, w_hagar, IT_ROCKETS, 8, WEP_FLAG_NORMAL | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH, BOT_PICKUP_RATING_MID, "hagar", "hagar", _("Hagar")) +REGISTER_WEAPON(HAGAR, w_hagar, IT_ROCKETS, 8, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH, BOT_PICKUP_RATING_MID, "hagar", "hagar", _("Hagar")) #else #ifdef SVQC // NO bounce protection, as bounces are limited! + void W_Hagar_Explode (void) { self.event_damage = SUB_Null; @@ -44,8 +45,8 @@ void W_Hagar_Attack (void) { local entity missile; - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - self.ammo_rockets = self.ammo_rockets - autocvar_g_balance_hagar_primary_ammo; + W_DecreaseAmmo(ammo_rockets, autocvar_g_balance_hagar_primary_ammo, autocvar_g_balance_hagar_reload_ammo); + W_SetupShot (self, FALSE, 2, "weapons/hagar_fire.wav", CHAN_WEAPON, autocvar_g_balance_hagar_primary_damage); pointparticles(particleeffectnum("hagar_muzzleflash"), w_shotorg, w_shotdir * 1000, 1); @@ -79,8 +80,8 @@ void W_Hagar_Attack2 (void) { local entity missile; - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - self.ammo_rockets = self.ammo_rockets - autocvar_g_balance_hagar_secondary_ammo; + W_DecreaseAmmo(ammo_rockets, autocvar_g_balance_hagar_secondary_ammo, autocvar_g_balance_hagar_reload_ammo); + W_SetupShot (self, FALSE, 2, "weapons/hagar_fire.wav", CHAN_WEAPON, autocvar_g_balance_hagar_secondary_damage); pointparticles(particleeffectnum("hagar_muzzleflash"), w_shotorg, w_shotdir * 1000, 1); @@ -118,6 +119,7 @@ void spawnfunc_weapon_hagar (void) float w_hagar(float req) { + float ammo_amount; if (req == WR_AIM) if (random()>0.15) self.BUTTON_ATCK = bot_aim(autocvar_g_balance_hagar_primary_speed, 0, autocvar_g_balance_hagar_primary_lifetime, FALSE); @@ -128,17 +130,23 @@ float w_hagar(float req) } else if (req == WR_THINK) { - if (self.BUTTON_ATCK) - if (weapon_prepareattack(0, autocvar_g_balance_hagar_primary_refire)) + if(autocvar_g_balance_hagar_reload_ammo && self.clip_load < min(autocvar_g_balance_hagar_primary_ammo, autocvar_g_balance_hagar_secondary_ammo)) // forced reload + weapon_action(self.weapon, WR_RELOAD); + else if (self.BUTTON_ATCK) { - W_Hagar_Attack(); - weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_hagar_primary_refire, w_ready); + if (weapon_prepareattack(0, autocvar_g_balance_hagar_primary_refire)) + { + W_Hagar_Attack(); + weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_hagar_primary_refire, w_ready); + } } - if (self.BUTTON_ATCK2 && autocvar_g_balance_hagar_secondary) - if (weapon_prepareattack(1, autocvar_g_balance_hagar_secondary_refire)) + else if (self.BUTTON_ATCK2 && autocvar_g_balance_hagar_secondary) { - W_Hagar_Attack2(); - weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_hagar_secondary_refire, w_ready); + if (weapon_prepareattack(1, autocvar_g_balance_hagar_secondary_refire)) + { + W_Hagar_Attack2(); + weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_hagar_secondary_refire, w_ready); + } } } else if (req == WR_PRECACHE) @@ -147,13 +155,29 @@ float w_hagar(float req) precache_model ("models/weapons/v_hagar.md3"); precache_model ("models/weapons/h_hagar.iqm"); precache_sound ("weapons/hagar_fire.wav"); + precache_sound ("weapons/reload.wav"); } else if (req == WR_SETUP) + { weapon_setup(WEP_HAGAR); + self.current_ammo = ammo_rockets; + } else if (req == WR_CHECKAMMO1) - return self.ammo_rockets >= autocvar_g_balance_hagar_primary_ammo; + { + ammo_amount = self.ammo_rockets >= autocvar_g_balance_hagar_primary_ammo; + ammo_amount += self.weapon_load[WEP_HAGAR] >= autocvar_g_balance_hagar_primary_ammo; + return ammo_amount; + } else if (req == WR_CHECKAMMO2) - return self.ammo_rockets >= autocvar_g_balance_hagar_secondary_ammo; + { + ammo_amount = self.ammo_rockets >= autocvar_g_balance_hagar_secondary_ammo; + ammo_amount += self.weapon_load[WEP_HAGAR] >= autocvar_g_balance_hagar_secondary_ammo; + return ammo_amount; + } + else if (req == WR_RELOAD) + { + W_Reload(min(autocvar_g_balance_hagar_primary_ammo, autocvar_g_balance_hagar_secondary_ammo), autocvar_g_balance_hagar_reload_ammo, autocvar_g_balance_hagar_reload_time, "weapons/reload.wav"); + } return TRUE; }; #endif diff --git a/qcsrc/server/w_hlac.qc b/qcsrc/server/w_hlac.qc index 4bba3b8051..6d579cf482 100644 --- a/qcsrc/server/w_hlac.qc +++ b/qcsrc/server/w_hlac.qc @@ -1,5 +1,5 @@ #ifdef REGISTER_WEAPON -REGISTER_WEAPON(HLAC, w_hlac, IT_CELLS, 6, WEP_FLAG_NORMAL | WEP_TYPE_SPLASH, BOT_PICKUP_RATING_MID, "hlac", "hlac", _("Heavy Laser Assault Cannon")) +REGISTER_WEAPON(HLAC, w_hlac, IT_CELLS, 6, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH, BOT_PICKUP_RATING_MID, "hlac", "hlac", _("Heavy Laser Assault Cannon")) #else #ifdef SVQC @@ -22,10 +22,7 @@ void W_HLAC_Attack (void) local entity missile; float spread; - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - { - self.ammo_cells = self.ammo_cells - autocvar_g_balance_hlac_primary_ammo; - } + W_DecreaseAmmo(ammo_cells, autocvar_g_balance_hlac_primary_ammo, autocvar_g_balance_hlac_reload_ammo); spread = autocvar_g_balance_hlac_primary_spread_min + (autocvar_g_balance_hlac_primary_spread_add * self.misc_bulletcounter); spread = min(spread,autocvar_g_balance_hlac_primary_spread_max); @@ -116,10 +113,7 @@ void W_HLAC_Attack2 (void) { float i; - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - { - self.ammo_cells = self.ammo_cells - autocvar_g_balance_hlac_secondary_ammo; - } + W_DecreaseAmmo(ammo_cells, autocvar_g_balance_hlac_secondary_ammo, autocvar_g_balance_hlac_reload_ammo); for(i=autocvar_g_balance_hlac_secondary_shots;i>0;--i) W_HLAC_Attack2f(); @@ -167,25 +161,31 @@ void spawnfunc_weapon_hlac (void) float w_hlac(float req) { + float ammo_amount; if (req == WR_AIM) self.BUTTON_ATCK = bot_aim(autocvar_g_balance_hlac_primary_speed, 0, autocvar_g_balance_hlac_primary_lifetime, FALSE); else if (req == WR_THINK) { - if (self.BUTTON_ATCK) - if (weapon_prepareattack(0, autocvar_g_balance_hlac_primary_refire)) + if(autocvar_g_balance_hlac_reload_ammo && self.clip_load < min(autocvar_g_balance_hlac_primary_ammo, autocvar_g_balance_hlac_secondary_ammo)) // forced reload + weapon_action(self.weapon, WR_RELOAD); + else if (self.BUTTON_ATCK) { - self.misc_bulletcounter = 0; - W_HLAC_Attack(); - weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_hlac_primary_refire, HLAC_fire1_02); + if (weapon_prepareattack(0, autocvar_g_balance_hlac_primary_refire)) + { + self.misc_bulletcounter = 0; + W_HLAC_Attack(); + weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_hlac_primary_refire, HLAC_fire1_02); + } } - if (self.BUTTON_ATCK2 && autocvar_g_balance_hlac_secondary) - if (weapon_prepareattack(1, autocvar_g_balance_hlac_secondary_refire)) + else if (self.BUTTON_ATCK2 && autocvar_g_balance_hlac_secondary) { - W_HLAC_Attack2(); - weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_hlac_secondary_animtime, w_ready); + if (weapon_prepareattack(1, autocvar_g_balance_hlac_secondary_refire)) + { + W_HLAC_Attack2(); + weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_hlac_secondary_animtime, w_ready); + } } - } else if (req == WR_PRECACHE) { @@ -193,14 +193,30 @@ float w_hlac(float req) precache_model ("models/weapons/v_hlac.md3"); precache_model ("models/weapons/h_hlac.iqm"); precache_sound ("weapons/lasergun_fire.wav"); + precache_sound ("weapons/reload.wav"); } else if (req == WR_SETUP) + { weapon_setup(WEP_HLAC); + self.current_ammo = ammo_cells; + } else if (req == WR_CHECKAMMO1) - return self.ammo_cells >= autocvar_g_balance_hlac_primary_ammo; + { + ammo_amount = self.ammo_cells >= autocvar_g_balance_hlac_primary_ammo; + ammo_amount += self.weapon_load[WEP_HLAC] >= autocvar_g_balance_hlac_primary_ammo; + return ammo_amount; + } else if (req == WR_CHECKAMMO2) - return self.ammo_cells >= autocvar_g_balance_hlac_secondary_ammo; + { + ammo_amount = self.ammo_cells >= autocvar_g_balance_hlac_secondary_ammo; + ammo_amount += self.weapon_load[WEP_HLAC] >= autocvar_g_balance_hlac_secondary_ammo; + return ammo_amount; + } + else if (req == WR_RELOAD) + { + W_Reload(min(autocvar_g_balance_hlac_primary_ammo, autocvar_g_balance_hlac_secondary_ammo), autocvar_g_balance_hlac_reload_ammo, autocvar_g_balance_hlac_reload_time, "weapons/reload.wav"); + } return TRUE; }; #endif diff --git a/qcsrc/server/w_hook.qc b/qcsrc/server/w_hook.qc index da5e3f9423..c3a1768beb 100644 --- a/qcsrc/server/w_hook.qc +++ b/qcsrc/server/w_hook.qc @@ -63,7 +63,7 @@ void W_Hook_Attack2() local entity gren; if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - self.ammo_cells = self.ammo_cells - autocvar_g_balance_hook_secondary_ammo; + W_DecreaseAmmo(ammo_cells, autocvar_g_balance_hook_secondary_ammo, FALSE); W_SetupShot (self, FALSE, 4, "weapons/hookbomb_fire.wav", CHAN_WEAPON, autocvar_g_balance_hook_secondary_damage); gren = spawn (); @@ -127,7 +127,7 @@ float w_hook(float req) if (weapon_prepareattack(0, -1)) { if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - self.ammo_fuel = self.ammo_fuel - autocvar_g_balance_hook_primary_fuel; + W_DecreaseAmmo(ammo_fuel, autocvar_g_balance_hook_primary_fuel, FALSE); self.hook_state |= HOOK_FIRING; weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_hook_primary_animtime, w_ready); } @@ -170,7 +170,7 @@ float w_hook(float req) { if ( self.ammo_fuel >= (time - self.hook_time_fueldecrease) * hooked_fuel ) { - self.ammo_fuel -= (time - self.hook_time_fueldecrease) * hooked_fuel; + W_DecreaseAmmo(ammo_fuel, (time - self.hook_time_fueldecrease) * hooked_fuel, FALSE); self.hook_time_fueldecrease = time; // decrease next frame again } @@ -228,6 +228,7 @@ float w_hook(float req) else if (req == WR_SETUP) { weapon_setup(WEP_HOOK); + self.current_ammo = ammo_fuel; self.hook_state &~= HOOK_WAITING_FOR_RELEASE; } else if (req == WR_CHECKAMMO1) diff --git a/qcsrc/server/w_laser.qc b/qcsrc/server/w_laser.qc index 4ce1331931..a28faea754 100644 --- a/qcsrc/server/w_laser.qc +++ b/qcsrc/server/w_laser.qc @@ -1,5 +1,5 @@ #ifdef REGISTER_WEAPON -REGISTER_WEAPON(LASER, w_laser, 0, 1, WEP_FLAG_NORMAL | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH, 0, "laser", "laser", _("Laser")) +REGISTER_WEAPON(LASER, w_laser, 0, 1, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH, 0, "laser", "laser", _("Laser")) #else #ifdef SVQC void(float imp) W_SwitchWeapon; @@ -226,16 +226,24 @@ float w_laser(float req) } else if (req == WR_THINK) { - if (self.BUTTON_ATCK) - if (weapon_prepareattack(0, autocvar_g_balance_laser_primary_refire)) + if(autocvar_g_balance_laser_reload_ammo && self.clip_load < 1) // forced reload + weapon_action(self.weapon, WR_RELOAD); + else if (self.BUTTON_ATCK) { - W_Laser_Attack(0); - weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_laser_primary_animtime, w_ready); + if (weapon_prepareattack(0, autocvar_g_balance_laser_primary_refire)) + { + W_DecreaseAmmo(ammo_none, 1, TRUE); + + W_Laser_Attack(0); + weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_laser_primary_animtime, w_ready); + } } - if (self.BUTTON_ATCK2) + else if (self.BUTTON_ATCK2) { if(autocvar_g_balance_laser_secondary) { + W_DecreaseAmmo(ammo_none, 1, TRUE); + if (weapon_prepareattack(0, 0)) { W_Laser_Attack2(); @@ -256,13 +264,25 @@ float w_laser(float req) precache_model ("models/weapons/h_laser.iqm"); precache_sound ("weapons/lasergun_fire.wav"); precache_sound ("weapons/gauntlet_fire.wav"); + precache_sound ("weapons/reload.wav"); } else if (req == WR_SETUP) + { weapon_setup(WEP_LASER); + self.current_ammo = ammo_none; + } else if (req == WR_CHECKAMMO1) + { return TRUE; + } else if (req == WR_CHECKAMMO2) + { return TRUE; + } + else if (req == WR_RELOAD) + { + W_Reload(0, autocvar_g_balance_laser_reload_ammo, autocvar_g_balance_laser_reload_time, "weapons/reload.wav"); + } return TRUE; }; #endif diff --git a/qcsrc/server/w_minelayer.qc b/qcsrc/server/w_minelayer.qc index 7e4749cd54..b475989d68 100644 --- a/qcsrc/server/w_minelayer.qc +++ b/qcsrc/server/w_minelayer.qc @@ -1,5 +1,5 @@ #ifdef REGISTER_WEAPON -REGISTER_WEAPON(MINE_LAYER, w_minelayer, IT_ROCKETS, 4, WEP_FLAG_NORMAL | WEP_TYPE_SPLASH, BOT_PICKUP_RATING_HIGH, "minelayer", "minelayer", _("Mine Layer")) +REGISTER_WEAPON(MINE_LAYER, w_minelayer, IT_ROCKETS, 4, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH, BOT_PICKUP_RATING_HIGH, "minelayer", "minelayer", _("Mine Layer")) #else #ifdef SVQC void W_Mine_Think (void); @@ -220,8 +220,7 @@ void W_Mine_Attack (void) } } - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - self.ammo_rockets = self.ammo_rockets - autocvar_g_balance_minelayer_ammo; + W_DecreaseAmmo(ammo_rockets, autocvar_g_balance_minelayer_ammo, autocvar_g_balance_minelayer_reload_ammo); W_SetupShot_ProjectileSize (self, '-4 -4 -4', '4 4 4', FALSE, 5, "weapons/mine_fire.wav", CHAN_WEAPON, autocvar_g_balance_minelayer_damage); pointparticles(particleeffectnum("rocketlauncher_muzzleflash"), w_shotorg, w_shotdir * 1000, 1); @@ -276,6 +275,8 @@ float w_minelayer(float req) { entity mine; float minfound; + float ammo_amount; + if (req == WR_AIM) { // aim and decide to fire if appropriate @@ -373,7 +374,9 @@ float w_minelayer(float req) } else if (req == WR_THINK) { - if (self.BUTTON_ATCK) + if(autocvar_g_balance_minelayer_reload_ammo && self.clip_load < autocvar_g_balance_minelayer_ammo) // forced reload + weapon_action(self.weapon, WR_RELOAD); + else if (self.BUTTON_ATCK) { if(weapon_prepareattack(0, autocvar_g_balance_minelayer_refire)) { @@ -382,7 +385,7 @@ float w_minelayer(float req) } } - if (self.BUTTON_ATCK2) + else if (self.BUTTON_ATCK2) { minfound = 0; for(mine = world; (mine = find(mine, classname, "mine")); ) if(mine.owner == self) @@ -408,20 +411,36 @@ float w_minelayer(float req) precache_sound ("weapons/mine_fire.wav"); precache_sound ("weapons/mine_stick.wav"); precache_sound ("weapons/mine_trigger.wav"); + precache_sound ("weapons/reload.wav"); } else if (req == WR_SETUP) { weapon_setup(WEP_MINE_LAYER); + self.current_ammo = ammo_rockets; } else if (req == WR_CHECKAMMO1) { // don't switch while placing a mine - if ((ATTACK_FINISHED(self) <= time || self.weapon != WEP_MINE_LAYER) - && self.ammo_rockets < autocvar_g_balance_minelayer_ammo) - return FALSE; + if (ATTACK_FINISHED(self) <= time || self.weapon != WEP_MINE_LAYER) + { + if(autocvar_g_balance_minelayer_reload_ammo) + { + if(self.ammo_rockets < autocvar_g_balance_minelayer_ammo && self.weapon_load[WEP_MINE_LAYER] < autocvar_g_balance_minelayer_ammo) + ammo_amount = TRUE; + } + else if(self.ammo_rockets < autocvar_g_balance_minelayer_ammo) + ammo_amount = TRUE; + return !ammo_amount; + } } else if (req == WR_CHECKAMMO2) + { return FALSE; + } + else if (req == WR_RELOAD) + { + W_Reload(autocvar_g_balance_minelayer_ammo, autocvar_g_balance_minelayer_reload_ammo, autocvar_g_balance_minelayer_reload_time, "weapons/reload.wav"); + } return TRUE; }; #endif diff --git a/qcsrc/server/w_minstanex.qc b/qcsrc/server/w_minstanex.qc index 89f209937a..b826b98543 100644 --- a/qcsrc/server/w_minstanex.qc +++ b/qcsrc/server/w_minstanex.qc @@ -1,5 +1,5 @@ #ifdef REGISTER_WEAPON -REGISTER_WEAPON(MINSTANEX, w_minstanex, IT_CELLS, 7, WEP_FLAG_HIDDEN | WEP_FLAG_CANCLIMB | WEP_TYPE_HITSCAN, BOT_PICKUP_RATING_HIGH, "minstanex", "minstanex", _("MinstaNex")) +REGISTER_WEAPON(MINSTANEX, w_minstanex, IT_CELLS, 7, WEP_FLAG_HIDDEN | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_HITSCAN, BOT_PICKUP_RATING_HIGH, "minstanex", "minstanex", _("MinstaNex")) #else #ifdef SVQC .float minstanex_lasthit; @@ -80,13 +80,10 @@ void W_MinstaNex_Attack (void) if (trace_ent.solid == SOLID_BSP && !(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)) Damage_DamageInfo(trace_endpos, 10000, 0, 0, 800 * w_shotdir, WEP_MINSTANEX, self); - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - { - if (g_minstagib) - self.ammo_cells = self.ammo_cells - 1; - else - self.ammo_cells = self.ammo_cells - autocvar_g_balance_minstanex_ammo; - } + if (g_minstagib) + W_DecreaseAmmo(ammo_cells, 1, autocvar_g_balance_minstanex_reload_ammo); + else + W_DecreaseAmmo(ammo_cells, autocvar_g_balance_minstanex_ammo, autocvar_g_balance_minstanex_reload_ammo); } @@ -171,18 +168,30 @@ void minstagib_ammocheck (void) void spawnfunc_weapon_minstanex (void); // defined in t_items.qc +float minstanex_ammo; float w_minstanex(float req) { + float ammo_amount; if (req == WR_AIM) { - if(self.ammo_cells>0) + if(self.ammo_cells > 0) self.BUTTON_ATCK = bot_aim(1000000, 0, 1, FALSE); else self.BUTTON_ATCK2 = bot_aim(autocvar_g_balance_laser_primary_speed, 0, autocvar_g_balance_laser_primary_lifetime, FALSE); } else if (req == WR_THINK) { - if (self.BUTTON_ATCK) + if(g_minstagib) + minstanex_ammo = 1; + else + minstanex_ammo = autocvar_g_balance_minstanex_ammo; + + // if the laser uses load, we also consider its ammo for reloading + if(autocvar_g_balance_minstanex_reload_ammo && autocvar_g_balance_minstanex_laser_ammo && self.clip_load < min(minstanex_ammo, autocvar_g_balance_minstanex_laser_ammo)) // forced reload + weapon_action(self.weapon, WR_RELOAD); + else if(autocvar_g_balance_minstanex_reload_ammo && self.clip_load < minstanex_ammo) // forced reload + weapon_action(self.weapon, WR_RELOAD); + else if (self.BUTTON_ATCK) { if (weapon_prepareattack(0, autocvar_g_balance_minstanex_refire)) { @@ -196,6 +205,10 @@ float w_minstanex(float req) { self.jump_interval = time + autocvar_g_balance_laser_primary_refire * W_WeaponRateFactor(); + // decrease ammo for the laser? + if(autocvar_g_balance_minstanex_laser_ammo) + W_DecreaseAmmo(ammo_cells, autocvar_g_balance_minstanex_laser_ammo, autocvar_g_balance_minstanex_reload_ammo); + // ugly minstagib hack to reuse the fire mode of the laser float w; w = self.weapon; @@ -215,26 +228,43 @@ float w_minstanex(float req) precache_sound ("weapons/nexwhoosh1.wav"); precache_sound ("weapons/nexwhoosh2.wav"); precache_sound ("weapons/nexwhoosh3.wav"); + precache_sound ("weapons/reload.wav"); w_laser(WR_PRECACHE); } else if (req == WR_SETUP) { weapon_setup(WEP_MINSTANEX); + self.current_ammo = ammo_cells; self.minstanex_lasthit = 0; } else if (req == WR_CHECKAMMO1) { - if (g_minstagib) - return self.ammo_cells >= 1; - else - return self.ammo_cells >= autocvar_g_balance_minstanex_ammo; + ammo_amount = self.ammo_cells >= autocvar_g_balance_minstanex_ammo; + ammo_amount += self.weapon_load[WEP_MINSTANEX] >= autocvar_g_balance_minstanex_ammo; + return ammo_amount; } else if (req == WR_CHECKAMMO2) - return TRUE; + { + if(!autocvar_g_balance_minstanex_laser_ammo) + return TRUE; + ammo_amount = self.ammo_cells >= autocvar_g_balance_minstanex_laser_ammo; + ammo_amount += self.weapon_load[WEP_MINSTANEX] >= autocvar_g_balance_minstanex_laser_ammo; + return ammo_amount; + } else if (req == WR_RESETPLAYER) { self.minstanex_lasthit = 0; } + else if (req == WR_RELOAD) + { + float used_ammo; + if(autocvar_g_balance_minstanex_laser_ammo) + used_ammo = min(autocvar_g_balance_minstanex_ammo, autocvar_g_balance_minstanex_laser_ammo); + else + used_ammo = autocvar_g_balance_minstanex_ammo; + + W_Reload(used_ammo, autocvar_g_balance_minstanex_reload_ammo, autocvar_g_balance_minstanex_reload_time, "weapons/reload.wav"); + } return TRUE; }; #endif diff --git a/qcsrc/server/w_nex.qc b/qcsrc/server/w_nex.qc index e05698851f..482e216dfc 100644 --- a/qcsrc/server/w_nex.qc +++ b/qcsrc/server/w_nex.qc @@ -1,7 +1,8 @@ #ifdef REGISTER_WEAPON -REGISTER_WEAPON(NEX, w_nex, IT_CELLS, 7, WEP_FLAG_NORMAL | WEP_TYPE_HITSCAN, BOT_PICKUP_RATING_HIGH, "nex", "nex", _("Nex")) +REGISTER_WEAPON(NEX, w_nex, IT_CELLS, 7, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN, BOT_PICKUP_RATING_HIGH, "nex", "nex", _("Nex")) #else #ifdef SVQC + void SendCSQCNexBeamParticle(float charge) { vector v; v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos); @@ -74,8 +75,7 @@ void W_Nex_Attack (float issecondary) if (trace_ent.solid == SOLID_BSP && !(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)) Damage_DamageInfo(trace_endpos, mydmg, 0, 0, myforce * w_shotdir, WEP_NEX, self); - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - self.ammo_cells = self.ammo_cells - myammo; + W_DecreaseAmmo(ammo_cells, myammo, autocvar_g_balance_nex_reload_ammo); } void spawnfunc_weapon_nex (void); // defined in t_items.qc @@ -84,6 +84,7 @@ void spawnfunc_weapon_nex (void); // defined in t_items.qc float w_nex(float req) { float dt; + float ammo_amount; if (req == WR_AIM) { self.BUTTON_ATCK = bot_aim(1000000, 0, 1, FALSE); @@ -102,70 +103,89 @@ float w_nex(float req) self.pauseregen_finished = max(self.pauseregen_finished, time + autocvar_g_balance_nex_secondary_chargepool_pause_health_regen); } - if (self.BUTTON_ATCK) + if(autocvar_g_balance_nex_reload_ammo && self.clip_load < min(autocvar_g_balance_nex_primary_ammo, autocvar_g_balance_nex_secondary_ammo)) // forced reload + weapon_action(self.weapon, WR_RELOAD); + else { - if (weapon_prepareattack(0, autocvar_g_balance_nex_primary_refire)) + if (self.BUTTON_ATCK) { - W_Nex_Attack(0); - weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_nex_primary_animtime, w_ready); + if (weapon_prepareattack(0, autocvar_g_balance_nex_primary_refire)) + { + W_Nex_Attack(0); + weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_nex_primary_animtime, w_ready); + } } - } - if ((autocvar_g_balance_nex_secondary_charge && !autocvar_g_balance_nex_secondary) ? self.BUTTON_ZOOM : self.BUTTON_ATCK2) - { - if(autocvar_g_balance_nex_secondary_charge) + if ((autocvar_g_balance_nex_secondary_charge && !autocvar_g_balance_nex_secondary) ? self.BUTTON_ZOOM : self.BUTTON_ATCK2) { - self.nex_charge_rottime = time + autocvar_g_balance_nex_charge_rot_pause; - dt = frametime / W_TICSPERFRAME; - - if(self.nex_charge < 1) + if(autocvar_g_balance_nex_secondary_charge) { - if(autocvar_g_balance_nex_secondary_chargepool) + self.nex_charge_rottime = time + autocvar_g_balance_nex_charge_rot_pause; + dt = frametime / W_TICSPERFRAME; + + if(self.nex_charge < 1) { - if(autocvar_g_balance_nex_secondary_ammo) + if(autocvar_g_balance_nex_secondary_chargepool) { - // always deplete if secondary is held - self.nex_chargepool_ammo = max(0, self.nex_chargepool_ammo - autocvar_g_balance_nex_secondary_ammo * dt); + if(autocvar_g_balance_nex_secondary_ammo) + { + // always deplete if secondary is held + self.nex_chargepool_ammo = max(0, self.nex_chargepool_ammo - autocvar_g_balance_nex_secondary_ammo * dt); - dt = min(dt, (1 - self.nex_charge) / autocvar_g_balance_nex_secondary_charge_rate); - self.nex_chargepool_pauseregen_finished = time + autocvar_g_balance_nex_secondary_chargepool_pause_regen; - dt = min(dt, self.nex_chargepool_ammo); - dt = max(0, dt); + dt = min(dt, (1 - self.nex_charge) / autocvar_g_balance_nex_secondary_charge_rate); + self.nex_chargepool_pauseregen_finished = time + autocvar_g_balance_nex_secondary_chargepool_pause_regen; + dt = min(dt, self.nex_chargepool_ammo); + dt = max(0, dt); - self.nex_charge += dt * autocvar_g_balance_nex_secondary_charge_rate; + self.nex_charge += dt * autocvar_g_balance_nex_secondary_charge_rate; + } } - } - else if(autocvar_g_balance_nex_secondary_ammo) - { - if(self.BUTTON_ATCK2) // only eat ammo when the button is pressed + else if(autocvar_g_balance_nex_secondary_ammo) { - dt = min(dt, (1 - self.nex_charge) / autocvar_g_balance_nex_secondary_charge_rate); - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) + if(self.BUTTON_ATCK2) // only eat ammo when the button is pressed { - dt = min(dt, (self.ammo_cells - autocvar_g_balance_nex_primary_ammo) / autocvar_g_balance_nex_secondary_ammo); - dt = max(0, dt); - if(dt > 0) + dt = min(dt, (1 - self.nex_charge) / autocvar_g_balance_nex_secondary_charge_rate); + if not(self.items & IT_UNLIMITED_WEAPON_AMMO) { - self.ammo_cells = max(autocvar_g_balance_nex_secondary_ammo, self.ammo_cells - autocvar_g_balance_nex_secondary_ammo * dt); + // if this weapon is reloadable, decrease its load. Else decrease the player's ammo + if(autocvar_g_balance_nex_reload_ammo) + { + dt = min(dt, (self.clip_load - autocvar_g_balance_nex_primary_ammo) / autocvar_g_balance_nex_secondary_ammo); + dt = max(0, dt); + if(dt > 0) + { + self.clip_load = max(autocvar_g_balance_nex_secondary_ammo, self.clip_load - autocvar_g_balance_nex_secondary_ammo * dt); + } + self.weapon_load[WEP_NEX] = self.clip_load; + } + else + { + dt = min(dt, (self.ammo_cells - autocvar_g_balance_nex_primary_ammo) / autocvar_g_balance_nex_secondary_ammo); + dt = max(0, dt); + if(dt > 0) + { + self.ammo_cells = max(autocvar_g_balance_nex_secondary_ammo, self.ammo_cells - autocvar_g_balance_nex_secondary_ammo * dt); + } + } } + self.nex_charge += dt * autocvar_g_balance_nex_secondary_charge_rate; } - self.nex_charge += dt * autocvar_g_balance_nex_secondary_charge_rate; } - } - else - { - dt = min(dt, (1 - self.nex_charge) / autocvar_g_balance_nex_secondary_charge_rate); - self.nex_charge += dt * autocvar_g_balance_nex_secondary_charge_rate; + else + { + dt = min(dt, (1 - self.nex_charge) / autocvar_g_balance_nex_secondary_charge_rate); + self.nex_charge += dt * autocvar_g_balance_nex_secondary_charge_rate; + } } } - } - else if(autocvar_g_balance_nex_secondary) - { - if (weapon_prepareattack(0, autocvar_g_balance_nex_secondary_refire)) + else if(autocvar_g_balance_nex_secondary) { - W_Nex_Attack(1); - weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_nex_secondary_animtime, w_ready); + if (weapon_prepareattack(0, autocvar_g_balance_nex_secondary_refire)) + { + W_Nex_Attack(1); + weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_nex_secondary_animtime, w_ready); + } } } } @@ -195,13 +215,31 @@ float w_nex(float req) precache_sound ("weapons/nexwhoosh1.wav"); precache_sound ("weapons/nexwhoosh2.wav"); precache_sound ("weapons/nexwhoosh3.wav"); + precache_sound ("weapons/reload.wav"); } else if (req == WR_SETUP) + { weapon_setup(WEP_NEX); + self.current_ammo = ammo_cells; + } else if (req == WR_CHECKAMMO1) - return self.ammo_cells >= autocvar_g_balance_nex_primary_ammo; + { + ammo_amount = self.ammo_cells >= autocvar_g_balance_nex_primary_ammo; + ammo_amount += (autocvar_g_balance_nex_reload_ammo && self.weapon_load[WEP_NEX] >= autocvar_g_balance_nex_primary_ammo); + return ammo_amount; + } else if (req == WR_CHECKAMMO2) - return self.ammo_cells >= autocvar_g_balance_nex_primary_ammo; // don't allow charging if we don't have enough ammo + { + // don't allow charging if we don't have enough ammo + ammo_amount = self.ammo_cells >= autocvar_g_balance_nex_secondary_ammo; + ammo_amount += self.weapon_load[WEP_NEX] >= autocvar_g_balance_nex_secondary_ammo; + return ammo_amount; + } + else if (req == WR_RELOAD) + { + W_Reload(min(autocvar_g_balance_nex_primary_ammo, autocvar_g_balance_nex_secondary_ammo), autocvar_g_balance_nex_reload_ammo, autocvar_g_balance_nex_reload_time, "weapons/reload.wav"); + } + return TRUE; }; #endif diff --git a/qcsrc/server/w_porto.qc b/qcsrc/server/w_porto.qc index 4e9a2cd706..d6e92a5372 100644 --- a/qcsrc/server/w_porto.qc +++ b/qcsrc/server/w_porto.qc @@ -270,7 +270,10 @@ float w_porto(float req) precache_sound ("porto/unsupported.wav"); } else if (req == WR_SETUP) + { weapon_setup(WEP_PORTO); + self.current_ammo = ammo_none; + } else if (req == WR_RESETPLAYER) { self.porto_current = world; diff --git a/qcsrc/server/w_rocketlauncher.qc b/qcsrc/server/w_rocketlauncher.qc index 21874b7905..36dbd8af8d 100644 --- a/qcsrc/server/w_rocketlauncher.qc +++ b/qcsrc/server/w_rocketlauncher.qc @@ -1,5 +1,5 @@ #ifdef REGISTER_WEAPON -REGISTER_WEAPON(ROCKET_LAUNCHER, w_rlauncher, IT_ROCKETS, 9, WEP_FLAG_NORMAL | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH, BOT_PICKUP_RATING_HIGH, "rl", "rocketlauncher", _("Rocket Launcher")) +REGISTER_WEAPON(ROCKET_LAUNCHER, w_rlauncher, IT_ROCKETS, 9, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH, BOT_PICKUP_RATING_HIGH, "rl", "rocketlauncher", _("Rocket Launcher")) #else #ifdef SVQC .float rl_release; @@ -248,8 +248,7 @@ void W_Rocket_Attack (void) local entity missile; local entity flash; - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - self.ammo_rockets = self.ammo_rockets - autocvar_g_balance_rocketlauncher_ammo; + W_DecreaseAmmo(ammo_rockets, autocvar_g_balance_rocketlauncher_ammo, autocvar_g_balance_rocketlauncher_reload_ammo); W_SetupShot_ProjectileSize (self, '-3 -3 -3', '3 3 3', FALSE, 5, "weapons/rocket_fire.wav", CHAN_WEAPON, autocvar_g_balance_rocketlauncher_damage); pointparticles(particleeffectnum("rocketlauncher_muzzleflash"), w_shotorg, w_shotdir * 1000, 1); @@ -305,6 +304,8 @@ float w_rlauncher(float req) { entity rock; float rockfound; + float ammo_amount; + if (req == WR_AIM) { // aim and decide to fire if appropriate @@ -402,32 +403,37 @@ float w_rlauncher(float req) } else if (req == WR_THINK) { - if (self.BUTTON_ATCK) + if(autocvar_g_balance_rocketlauncher_reload_ammo && self.clip_load < autocvar_g_balance_rocketlauncher_ammo) // forced reload + weapon_action(self.weapon, WR_RELOAD); + else { - if(self.rl_release || autocvar_g_balance_rocketlauncher_guidestop) - if(weapon_prepareattack(0, autocvar_g_balance_rocketlauncher_refire)) + if (self.BUTTON_ATCK) { - W_Rocket_Attack(); - weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_rocketlauncher_animtime, w_ready); - self.rl_release = 0; + if(self.rl_release || autocvar_g_balance_rocketlauncher_guidestop) + if(weapon_prepareattack(0, autocvar_g_balance_rocketlauncher_refire)) + { + W_Rocket_Attack(); + weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_rocketlauncher_animtime, w_ready); + self.rl_release = 0; + } } - } - else - self.rl_release = 1; + else + self.rl_release = 1; - if (self.BUTTON_ATCK2) - { - rockfound = 0; - for(rock = world; (rock = find(rock, classname, "rocket")); ) if(rock.owner == self) + if (self.BUTTON_ATCK2) { - if(!rock.rl_detonate_later) + rockfound = 0; + for(rock = world; (rock = find(rock, classname, "rocket")); ) if(rock.owner == self) { - rock.rl_detonate_later = TRUE; - rockfound = 1; + if(!rock.rl_detonate_later) + { + rock.rl_detonate_later = TRUE; + rockfound = 1; + } } + if(rockfound) + sound (self, CHAN_WEAPON2, "weapons/rocket_det.wav", VOL_BASE, ATTN_NORM); } - if(rockfound) - sound (self, CHAN_WEAPON2, "weapons/rocket_det.wav", VOL_BASE, ATTN_NORM); } } else if (req == WR_PRECACHE) @@ -439,18 +445,28 @@ float w_rlauncher(float req) precache_sound ("weapons/rocket_det.wav"); precache_sound ("weapons/rocket_fire.wav"); precache_sound ("weapons/rocket_mode.wav"); + precache_sound ("weapons/reload.wav"); } else if (req == WR_SETUP) { weapon_setup(WEP_ROCKET_LAUNCHER); + self.current_ammo = ammo_rockets; self.rl_release = 1; } else if (req == WR_CHECKAMMO1) { // don't switch while guiding a missile - if ((ATTACK_FINISHED(self) <= time || self.weapon != WEP_ROCKET_LAUNCHER) - && self.ammo_rockets < autocvar_g_balance_rocketlauncher_ammo) - return FALSE; + if (ATTACK_FINISHED(self) <= time || self.weapon != WEP_ROCKET_LAUNCHER) + { + if(autocvar_g_balance_rocketlauncher_reload_ammo) + { + if(self.ammo_rockets < autocvar_g_balance_rocketlauncher_ammo && self.weapon_load[WEP_ROCKET_LAUNCHER] < autocvar_g_balance_rocketlauncher_ammo) + ammo_amount = TRUE; + } + else if(self.ammo_rockets < autocvar_g_balance_rocketlauncher_ammo) + ammo_amount = TRUE; + return !ammo_amount; + } } else if (req == WR_CHECKAMMO2) return FALSE; @@ -458,6 +474,10 @@ float w_rlauncher(float req) { self.rl_release = 0; } + else if (req == WR_RELOAD) + { + W_Reload(autocvar_g_balance_rocketlauncher_ammo, autocvar_g_balance_rocketlauncher_reload_ammo, autocvar_g_balance_rocketlauncher_reload_time, "weapons/reload.wav"); + } return TRUE; }; #endif diff --git a/qcsrc/server/w_seeker.qc b/qcsrc/server/w_seeker.qc index 81d55a2265..a084966600 100644 --- a/qcsrc/server/w_seeker.qc +++ b/qcsrc/server/w_seeker.qc @@ -1,5 +1,5 @@ #ifdef REGISTER_WEAPON -REGISTER_WEAPON(SEEKER, w_seeker, IT_ROCKETS, 8, WEP_FLAG_NORMAL | WEP_TYPE_SPLASH, BOT_PICKUP_RATING_MID, "seeker", "seeker", _("T.A.G. Seeker")) +REGISTER_WEAPON(SEEKER, w_seeker, IT_ROCKETS, 8, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH, BOT_PICKUP_RATING_MID, "seeker", "seeker", _("T.A.G. Seeker")) #else #ifdef SVQC //.float proxytime; = autoswitch @@ -158,8 +158,7 @@ void Seeker_Fire_Missile(vector f_diff) { local entity missile; - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - self.ammo_rockets = self.ammo_rockets - autocvar_g_balance_seeker_missile_ammo; + W_DecreaseAmmo(ammo_rockets, autocvar_g_balance_seeker_missile_ammo, autocvar_g_balance_seeker_reload_ammo); makevectors(self.v_angle); W_SetupShot_ProjectileSize (self, '-2 -2 -2', '2 2 2', FALSE, 2, "weapons/seeker_fire.wav", CHAN_WEAPON, 0); @@ -294,8 +293,7 @@ void Seeker_Tag_Touch() void Seeker_Fire_Tag() { local entity missile; - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - self.ammo_rockets = self.ammo_rockets - autocvar_g_balance_seeker_tag_ammo; + W_DecreaseAmmo(ammo_rockets, autocvar_g_balance_seeker_tag_ammo, autocvar_g_balance_seeker_reload_ammo); W_SetupShot_ProjectileSize (self, '-2 -2 -2', '2 2 2', FALSE, 2, "weapons/tag_fire.wav", CHAN_WEAPON, autocvar_g_balance_seeker_missile_damage * autocvar_g_balance_seeker_missile_count); @@ -353,8 +351,7 @@ void Seeker_Fire_Flac() vector f_diff; float c; - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - self.ammo_rockets = self.ammo_rockets - autocvar_g_balance_seeker_flac_ammo; + W_DecreaseAmmo(ammo_rockets, autocvar_g_balance_seeker_flac_ammo, autocvar_g_balance_seeker_reload_ammo); c = mod(self.bulletcounter, 4); switch(c) @@ -413,25 +410,33 @@ void spawnfunc_weapon_seeker (void) float w_seeker(float req) { + float ammo_amount; + if (req == WR_AIM) self.BUTTON_ATCK = bot_aim(autocvar_g_balance_seeker_tag_speed, 0, 20, FALSE); else if (req == WR_THINK) { - if (self.BUTTON_ATCK) + if(autocvar_g_balance_seeker_reload_ammo && self.clip_load < min(autocvar_g_balance_seeker_missile_ammo, autocvar_g_balance_seeker_tag_ammo)) // forced reload + weapon_action(self.weapon, WR_RELOAD); + + else if (self.BUTTON_ATCK) + { if (weapon_prepareattack(0, autocvar_g_balance_seeker_tag_refire)) { Seeker_Fire_Tag(); weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_seeker_tag_animtime, w_ready); } + } - if (self.BUTTON_ATCK2) + else if (self.BUTTON_ATCK2) + { if (weapon_prepareattack(1, autocvar_g_balance_seeker_flac_refire)) { Seeker_Fire_Flac(); weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_seeker_flac_animtime, w_ready); } - + } } else if (req == WR_PRECACHE) { @@ -441,13 +446,29 @@ float w_seeker(float req) precache_sound ("weapons/tag_fire.wav"); precache_sound ("weapons/flac_fire.wav"); precache_sound ("weapons/seeker_fire.wav"); + precache_sound ("weapons/reload.wav"); } else if (req == WR_SETUP) + { weapon_setup(WEP_SEEKER); + self.current_ammo = ammo_rockets; + } else if (req == WR_CHECKAMMO1) - return self.ammo_rockets >= autocvar_g_balance_seeker_tag_ammo + autocvar_g_balance_seeker_missile_ammo; + { + ammo_amount = self.ammo_cells >= autocvar_g_balance_seeker_missile_ammo; + ammo_amount += self.weapon_load[WEP_SEEKER] >= autocvar_g_balance_seeker_missile_ammo; + return ammo_amount; + } else if (req == WR_CHECKAMMO2) - return self.ammo_rockets >= autocvar_g_balance_seeker_flac_ammo; + { + ammo_amount = self.ammo_cells >= autocvar_g_balance_seeker_flac_ammo; + ammo_amount += self.weapon_load[WEP_SEEKER] >= autocvar_g_balance_seeker_flac_ammo; + return ammo_amount; + } + else if (req == WR_RELOAD) + { + W_Reload(min(autocvar_g_balance_seeker_missile_ammo, autocvar_g_balance_seeker_tag_ammo), autocvar_g_balance_seeker_reload_ammo, autocvar_g_balance_seeker_reload_time, "weapons/reload.wav"); + } return TRUE; }; #endif diff --git a/qcsrc/server/w_shotgun.qc b/qcsrc/server/w_shotgun.qc index 6d0d094eb4..788a578b2b 100644 --- a/qcsrc/server/w_shotgun.qc +++ b/qcsrc/server/w_shotgun.qc @@ -1,7 +1,8 @@ #ifdef REGISTER_WEAPON -REGISTER_WEAPON(SHOTGUN, w_shotgun, IT_SHELLS, 2, WEP_FLAG_NORMAL | WEP_TYPE_HITSCAN, BOT_PICKUP_RATING_LOW, "shotgun", "shotgun", _("Shotgun")) +REGISTER_WEAPON(SHOTGUN, w_shotgun, IT_SHELLS, 2, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN, BOT_PICKUP_RATING_LOW, "shotgun", "shotgun", _("Shotgun")) #else #ifdef SVQC + void W_Shotgun_Attack (void) { float sc; @@ -22,12 +23,12 @@ void W_Shotgun_Attack (void) bulletspeed = autocvar_g_balance_shotgun_primary_speed; bulletconstant = autocvar_g_balance_shotgun_primary_bulletconstant; + W_DecreaseAmmo(ammo_shells, ammoamount, autocvar_g_balance_shotgun_reload_ammo); + W_SetupShot (self, autocvar_g_antilag_bullets && bulletspeed >= autocvar_g_antilag_bullets, 5, "weapons/shotgun_fire.wav", CHAN_WEAPON, d * bullets); for (sc = 0;sc < bullets;sc = sc + 1) fireBallisticBullet(w_shotorg, w_shotdir, spread, bulletspeed, 5, d, 0, f, WEP_SHOTGUN, 0, 1, bulletconstant); endFireBallisticBullet(); - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - self.ammo_shells = self.ammo_shells - ammoamount; pointparticles(particleeffectnum("shotgun_muzzleflash"), w_shotorg, w_shotdir * 1000, autocvar_g_balance_shotgun_primary_ammo); @@ -43,7 +44,6 @@ void W_Shotgun_Attack (void) flash.nextthink = time + 0.06; flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION; W_AttachToShotorg(flash, '5 0 0'); - } void shotgun_meleethink (void) @@ -102,6 +102,7 @@ void spawnfunc_weapon_shotgun(); // defined in t_items.qc float w_shotgun(float req) { + float ammo_amount; if (req == WR_AIM) if(vlen(self.origin-self.enemy.origin) <= autocvar_g_balance_shotgun_secondary_melee_range) self.BUTTON_ATCK2 = bot_aim(1000000, 0, 0.001, FALSE); @@ -109,18 +110,28 @@ float w_shotgun(float req) self.BUTTON_ATCK = bot_aim(1000000, 0, 0.001, FALSE); else if (req == WR_THINK) { - if (self.BUTTON_ATCK) + if(autocvar_g_balance_shotgun_reload_ammo && self.clip_load < autocvar_g_balance_shotgun_primary_ammo) // forced reload + { + // don't force reload an empty shotgun if its melee attack is active + if not(autocvar_g_balance_shotgun_secondary && self.ammo_shells < autocvar_g_balance_shotgun_primary_ammo) + weapon_action(self.weapon, WR_RELOAD); + } + else { - if (time >= self.shotgun_primarytime) // handle refire separately so the secondary can be fired straight after a primary + if (self.BUTTON_ATCK) { - if(weapon_prepareattack(0, autocvar_g_balance_shotgun_primary_animtime)) + if (time >= self.shotgun_primarytime) // handle refire separately so the secondary can be fired straight after a primary { - W_Shotgun_Attack(); - self.shotgun_primarytime = time + autocvar_g_balance_shotgun_primary_refire; - weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_shotgun_primary_animtime, w_ready); + if(weapon_prepareattack(0, autocvar_g_balance_shotgun_primary_animtime)) + { + W_Shotgun_Attack(); + self.shotgun_primarytime = time + autocvar_g_balance_shotgun_primary_refire; + weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_shotgun_primary_animtime, w_ready); + } } } } + if (self.clip_load >= 0) // we are not currently reloading if (self.BUTTON_ATCK2 && autocvar_g_balance_shotgun_secondary) if (weapon_prepareattack(1, autocvar_g_balance_shotgun_secondary_refire)) { @@ -137,15 +148,28 @@ float w_shotgun(float req) precache_sound ("misc/itempickup.wav"); precache_sound ("weapons/shotgun_fire.wav"); precache_sound ("weapons/shotgun_melee.wav"); + precache_sound ("weapons/reload.wav"); } else if (req == WR_SETUP) + { weapon_setup(WEP_SHOTGUN); + self.current_ammo = ammo_shells; + } else if (req == WR_CHECKAMMO1) - return self.ammo_shells >= autocvar_g_balance_shotgun_primary_ammo; + { + ammo_amount = self.ammo_shells >= autocvar_g_balance_shotgun_primary_ammo; + ammo_amount += self.weapon_load[WEP_SHOTGUN] >= autocvar_g_balance_shotgun_primary_ammo; + return ammo_amount; + } else if (req == WR_CHECKAMMO2) { + // melee attack is always available return TRUE; } + else if (req == WR_RELOAD) + { + W_Reload(autocvar_g_balance_shotgun_primary_ammo, autocvar_g_balance_shotgun_reload_ammo, autocvar_g_balance_shotgun_reload_time, "weapons/reload.wav"); + } return TRUE; }; #endif diff --git a/qcsrc/server/w_sniperrifle.qc b/qcsrc/server/w_sniperrifle.qc index a03a9b6108..0b5ae414dc 100644 --- a/qcsrc/server/w_sniperrifle.qc +++ b/qcsrc/server/w_sniperrifle.qc @@ -1,5 +1,5 @@ #ifdef REGISTER_WEAPON -REGISTER_WEAPON(SNIPERRIFLE, w_sniperrifle, IT_NAILS, 7, WEP_FLAG_NORMAL | WEP_TYPE_HITSCAN, BOT_PICKUP_RATING_MID, "campingrifle", "sniperrifle", _("Sniper Rifle")) +REGISTER_WEAPON(SNIPERRIFLE, w_sniperrifle, IT_NAILS, 7, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN, BOT_PICKUP_RATING_MID, "campingrifle", "sniperrifle", _("Sniper Rifle")) #else #ifdef SVQC //Sniper rifle Primary mode: manually operated bolt*, Secondary: full automatic** @@ -8,87 +8,16 @@ REGISTER_WEAPON(SNIPERRIFLE, w_sniperrifle, IT_NAILS, 7, WEP_FLAG_NORMAL | WEP_T .float sniperrifle_accumulator; -float W_SniperRifle_CheckMaxBullets(float checkammo) -{ - float maxbulls; - maxbulls = autocvar_g_balance_sniperrifle_magazinecapacity; - if(!maxbulls) - maxbulls = 8; // match HUD - if(checkammo) - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - maxbulls = min(maxbulls, floor(self.ammo_nails / min(autocvar_g_balance_sniperrifle_primary_ammo, autocvar_g_balance_sniperrifle_secondary_ammo))); - if(self.sniperrifle_bulletcounter > maxbulls || !autocvar_g_balance_sniperrifle_magazinecapacity) - self.sniperrifle_bulletcounter = maxbulls; - return (self.sniperrifle_bulletcounter == maxbulls); -} - -void W_SniperRifle_ReloadedAndReady() -{ - float t; - self.sniperrifle_bulletcounter = autocvar_g_balance_sniperrifle_magazinecapacity; - W_SniperRifle_CheckMaxBullets(TRUE); - t = ATTACK_FINISHED(self) - autocvar_g_balance_sniperrifle_reloadtime - 1; - ATTACK_FINISHED(self) = t; - w_ready(); -} - -float W_SniperRifle_Reload() -{ - float t; - - W_SniperRifle_CheckMaxBullets(TRUE); - - if(self.ammo_nails < min(autocvar_g_balance_sniperrifle_primary_ammo, autocvar_g_balance_sniperrifle_secondary_ammo)) // when we get here, bulletcounter must be 0 or -1 - { - print("cannot reload... not enough bullets\n"); - self.sniperrifle_bulletcounter = -1; // reload later - W_SwitchToOtherWeapon(self); - return 0; - } - - if (self.sniperrifle_bulletcounter >= autocvar_g_balance_sniperrifle_magazinecapacity) - return 0; - - if (self.weaponentity) - { - if (self.weaponentity.wframe == WFRAME_RELOAD) - return 0; - - // allow to switch away while reloading, but this will cause a new reload! - self.weaponentity.state = WS_READY; - } - - sound (self, CHAN_WEAPON2, "weapons/campingrifle_reload.wav", VOL_BASE, ATTN_NORM); - - t = max(time, ATTACK_FINISHED(self)) + autocvar_g_balance_sniperrifle_reloadtime + 1; - ATTACK_FINISHED(self) = t; - - weapon_thinkf(WFRAME_RELOAD, autocvar_g_balance_sniperrifle_reloadtime, W_SniperRifle_ReloadedAndReady); - - self.sniperrifle_bulletcounter = -1; - - return 1; -} - -void W_SniperRifle_CheckReloadAndReady() -{ - w_ready(); - if(self.sniperrifle_bulletcounter <= 0) - if(W_SniperRifle_Reload()) - return; -} - void W_SniperRifle_FireBullet(float pSpread, float pDamage, float pHeadshotAddedDamage, float pForce, float pSpeed, float pLifetime, float pAmmo, float deathtype, float pBulletConstant) { - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - self.ammo_nails -= pAmmo; + W_DecreaseAmmo(ammo_nails, pAmmo, autocvar_g_balance_sniperrifle_reload_ammo); if(deathtype & HITTYPE_SECONDARY) W_SetupShot (self, autocvar_g_antilag_bullets && pSpeed >= autocvar_g_antilag_bullets, 2, "weapons/campingrifle_fire2.wav", CHAN_WEAPON, autocvar_g_balance_sniperrifle_secondary_damage + autocvar_g_balance_sniperrifle_secondary_headshotaddeddamage); else W_SetupShot (self, autocvar_g_antilag_bullets && pSpeed >= autocvar_g_antilag_bullets, 2, "weapons/campingrifle_fire.wav", CHAN_WEAPON, autocvar_g_balance_sniperrifle_primary_damage + autocvar_g_balance_sniperrifle_primary_headshotaddeddamage); - pointparticles(particleeffectnum("shotgun_muzzleflash"), w_shotorg, w_shotdir * 2000, 1); + pointparticles(particleeffectnum("sniperrifle_muzzleflash"), w_shotorg, w_shotdir * 2000, 1); if(self.BUTTON_ZOOM) // if zoomed, shoot from the eye { @@ -104,9 +33,6 @@ void W_SniperRifle_FireBullet(float pSpread, float pDamage, float pHeadshotAdded if (autocvar_g_casings >= 2) SpawnCasing (((random () * 50 + 50) * v_right) - (v_forward * (random () * 25 + 25)) - ((random () * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, self); - - self.sniperrifle_bulletcounter = self.sniperrifle_bulletcounter - 1; - W_SniperRifle_CheckMaxBullets(TRUE); } void W_SniperRifle_Attack() @@ -137,9 +63,7 @@ void spawnfunc_weapon_campingrifle (void) void W_SniperRifle_BulletHail_Continue() { float r, sw, af; - W_SniperRifle_CheckReloadAndReady(); - if(self.sniperrifle_bulletcounter < 0) - return; // reloading, so we are done + sw = self.switchweapon; // make it not detect weapon changes as reason to abort firing af = ATTACK_FINISHED(self); self.switchweapon = self.weapon; @@ -177,14 +101,15 @@ void W_SniperRifle_BulletHail(float mode, void(void) AttackFunc, float fr, float else { // just one shot - weapon_thinkf(fr, animtime, W_SniperRifle_CheckReloadAndReady); + weapon_thinkf(fr, animtime, w_ready); } } .float bot_secondary_sniperriflemooth; float w_sniperrifle(float req) { - float full; + float ammo_amount; + if (req == WR_AIM) { self.BUTTON_ATCK=FALSE; @@ -210,10 +135,8 @@ float w_sniperrifle(float req) } else if (req == WR_THINK) { - if(self.sniperrifle_bulletcounter < 0) // forced reload (e.g. because interrupted) - { - self.wish_reload = 1; - } + if(autocvar_g_balance_sniperrifle_reload_ammo && self.clip_load < min(autocvar_g_balance_sniperrifle_primary_ammo, autocvar_g_balance_sniperrifle_secondary_ammo)) // forced reload + weapon_action(self.weapon, WR_RELOAD); else { self.sniperrifle_accumulator = bound(time - autocvar_g_balance_sniperrifle_bursttime, self.sniperrifle_accumulator, time); @@ -230,7 +153,7 @@ float w_sniperrifle(float req) if (autocvar_g_balance_sniperrifle_secondary) { if(autocvar_g_balance_sniperrifle_secondary_reload) - self.wish_reload = 1; + weapon_action(self.weapon, WR_RELOAD); else { if (weapon_prepareattack_check(1, autocvar_g_balance_sniperrifle_secondary_refire)) @@ -244,49 +167,40 @@ float w_sniperrifle(float req) } } } - if(self.wish_reload) - { - if(self.switchweapon == self.weapon) - { - if(self.weaponentity.state == WS_READY) - { - self.wish_reload = 0; - W_SniperRifle_Reload(); - } - } - } } else if (req == WR_PRECACHE) { precache_model ("models/weapons/g_campingrifle.md3"); precache_model ("models/weapons/v_campingrifle.md3"); precache_model ("models/weapons/h_campingrifle.iqm"); - precache_sound ("weapons/campingrifle_reload.wav"); precache_sound ("weapons/campingrifle_fire.wav"); precache_sound ("weapons/campingrifle_fire2.wav"); + precache_sound ("weapons/reload.wav"); } else if (req == WR_SETUP) { weapon_setup(WEP_SNIPERRIFLE); - - full = W_SniperRifle_CheckMaxBullets(TRUE); - if(autocvar_g_balance_sniperrifle_auto_reload_on_switch) - if(!full) - self.sniperrifle_bulletcounter = -1; + self.current_ammo = ammo_nails; } else if (req == WR_CHECKAMMO1) - return self.ammo_nails >= autocvar_g_balance_sniperrifle_primary_ammo; + { + ammo_amount = self.ammo_nails >= autocvar_g_balance_sniperrifle_primary_ammo; + ammo_amount += self.weapon_load[WEP_SNIPERRIFLE] >= autocvar_g_balance_sniperrifle_primary_ammo; + return ammo_amount; + } else if (req == WR_CHECKAMMO2) - return self.ammo_nails >= autocvar_g_balance_sniperrifle_secondary_ammo; - else if (req == WR_RELOAD) { - self.wish_reload = 1; + ammo_amount = self.ammo_nails >= autocvar_g_balance_sniperrifle_secondary_ammo; + ammo_amount += self.weapon_load[WEP_SNIPERRIFLE] >= autocvar_g_balance_sniperrifle_secondary_ammo; + return ammo_amount; } else if (req == WR_RESETPLAYER) { self.sniperrifle_accumulator = time - autocvar_g_balance_sniperrifle_bursttime; - self.sniperrifle_bulletcounter = autocvar_g_balance_sniperrifle_magazinecapacity; - W_SniperRifle_CheckMaxBullets(FALSE); + } + else if (req == WR_RELOAD) + { + W_Reload(min(autocvar_g_balance_sniperrifle_primary_ammo, autocvar_g_balance_sniperrifle_secondary_ammo), autocvar_g_balance_sniperrifle_reload_ammo, autocvar_g_balance_sniperrifle_reload_time, "weapons/reload.wav"); } return TRUE; }; diff --git a/qcsrc/server/w_tuba.qc b/qcsrc/server/w_tuba.qc index 98767516ae..4a79788083 100644 --- a/qcsrc/server/w_tuba.qc +++ b/qcsrc/server/w_tuba.qc @@ -236,7 +236,10 @@ float w_tuba(float req) // precache_sound(TUBA_NOTE(i)); } else if (req == WR_SETUP) + { weapon_setup(WEP_TUBA); + self.current_ammo = ammo_none; + } else if (req == WR_CHECKAMMO1) return TRUE; // TODO use fuel? else if (req == WR_CHECKAMMO2) diff --git a/qcsrc/server/w_uzi.qc b/qcsrc/server/w_uzi.qc index 0e563405a1..eb9e08b205 100644 --- a/qcsrc/server/w_uzi.qc +++ b/qcsrc/server/w_uzi.qc @@ -1,10 +1,10 @@ #ifdef REGISTER_WEAPON -REGISTER_WEAPON(UZI, w_uzi, IT_NAILS, 3, WEP_FLAG_NORMAL | WEP_TYPE_HITSCAN, BOT_PICKUP_RATING_MID, "uzi", "uzi", _("Machine Gun")) +REGISTER_WEAPON(UZI, w_uzi, IT_NAILS, 3, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN, BOT_PICKUP_RATING_MID, "uzi", "uzi", _("Machine Gun")) #else #ifdef SVQC // leilei's fancy muzzleflash stuff -void Uzi_Flash_Go() +void UZI_Flash_Go() { self.frame = self.frame + 2; self.scale = self.scale * 0.5; @@ -30,7 +30,7 @@ void UziFlash() setmodel(self.muzzle_flash, "models/uziflash.md3"); // precision set below self.muzzle_flash.scale = 0.75; - self.muzzle_flash.think = Uzi_Flash_Go; + self.muzzle_flash.think = UZI_Flash_Go; self.muzzle_flash.nextthink = time + 0.02; self.muzzle_flash.frame = 2; self.muzzle_flash.alpha = 0.75; @@ -39,15 +39,8 @@ void UziFlash() self.muzzle_flash.owner = self; } -void W_Uzi_Attack (float deathtype) +void W_UZI_Attack (float deathtype) { - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - { - if (self.misc_bulletcounter == 1) - self.ammo_nails = self.ammo_nails - autocvar_g_balance_uzi_first_ammo; - else - self.ammo_nails = self.ammo_nails - autocvar_g_balance_uzi_sustained_ammo; - } W_SetupShot (self, autocvar_g_antilag_bullets && autocvar_g_balance_uzi_speed >= autocvar_g_antilag_bullets, 0, "weapons/uzi_fire.wav", CHAN_WEAPON, ((self.misc_bulletcounter == 1) ? autocvar_g_balance_uzi_first_damage : autocvar_g_balance_uzi_sustained_damage)); if (!g_norecoil) { @@ -72,6 +65,11 @@ void W_Uzi_Attack (float deathtype) // casing code if (autocvar_g_casings >= 2) SpawnCasing (((random () * 50 + 50) * v_right) - (v_forward * (random () * 25 + 25)) - ((random () * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, self); + + if (self.misc_bulletcounter == 1) + W_DecreaseAmmo(ammo_nails, autocvar_g_balance_uzi_first_ammo, autocvar_g_balance_uzi_reload_ammo); + else + W_DecreaseAmmo(ammo_nails, autocvar_g_balance_uzi_sustained_ammo, autocvar_g_balance_uzi_reload_ammo); } // weapon frames @@ -91,7 +89,7 @@ void uzi_fire1_02() return; } self.misc_bulletcounter = self.misc_bulletcounter + 1; - W_Uzi_Attack(WEP_UZI); + W_UZI_Attack(WEP_UZI); weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_uzi_sustained_refire, uzi_fire1_02); } else @@ -102,6 +100,8 @@ void uzi_fire1_02() void uzi_mode1_fire_auto() { float uzi_spread; + + W_DecreaseAmmo(ammo_nails, autocvar_g_balance_uzi_sustained_ammo, autocvar_g_balance_uzi_reload_ammo); if (self.BUTTON_ATCK) weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_uzi_sustained_refire, uzi_mode1_fire_auto); @@ -139,10 +139,6 @@ void uzi_mode1_fire_auto() if (autocvar_g_casings >= 2) // casing code SpawnCasing (((random () * 50 + 50) * v_right) - (v_forward * (random () * 25 + 25)) - ((random () * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, self); - - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - self.ammo_nails = self.ammo_nails - autocvar_g_balance_uzi_sustained_ammo; - } void uzi_mode1_fire_burst() @@ -183,6 +179,7 @@ void spawnfunc_weapon_machinegun(); // defined in t_items.qc float w_uzi(float req) { + float ammo_amount; if (req == WR_AIM) if(vlen(self.origin-self.enemy.origin) < 3000 - bound(0, skill, 10) * 200) self.BUTTON_ATCK = bot_aim(1000000, 0, 0.001, FALSE); @@ -192,7 +189,9 @@ float w_uzi(float req) } else if (req == WR_THINK) { - if(autocvar_g_balance_uzi_mode == 1) + if(autocvar_g_balance_uzi_reload_ammo && self.clip_load < min(max(autocvar_g_balance_uzi_sustained_ammo, autocvar_g_balance_uzi_first_ammo), autocvar_g_balance_uzi_burst_ammo)) // forced reload + weapon_action(self.weapon, WR_RELOAD); + else if(autocvar_g_balance_uzi_mode == 1) { if (self.BUTTON_ATCK) if (weapon_prepareattack(0, 0)) @@ -210,9 +209,8 @@ float w_uzi(float req) w_ready(); return FALSE; } - - if not(self.items & IT_UNLIMITED_WEAPON_AMMO) - self.ammo_nails = self.ammo_nails - autocvar_g_balance_uzi_burst_ammo; + + W_DecreaseAmmo(ammo_nails, autocvar_g_balance_uzi_burst_ammo, autocvar_g_balance_uzi_reload_ammo); self.misc_bulletcounter = autocvar_g_balance_uzi_burst * -1; uzi_mode1_fire_burst(); @@ -225,7 +223,7 @@ float w_uzi(float req) if (weapon_prepareattack(0, 0)) { self.misc_bulletcounter = 1; - W_Uzi_Attack(WEP_UZI); // sets attack_finished + W_UZI_Attack(WEP_UZI); // sets attack_finished weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_uzi_sustained_refire, uzi_fire1_02); } @@ -233,7 +231,7 @@ float w_uzi(float req) if (weapon_prepareattack(1, 0)) { self.misc_bulletcounter = 1; - W_Uzi_Attack(WEP_UZI | HITTYPE_SECONDARY); // sets attack_finished + W_UZI_Attack(WEP_UZI | HITTYPE_SECONDARY); // sets attack_finished weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_uzi_first_refire, w_ready); } } @@ -245,19 +243,49 @@ float w_uzi(float req) precache_model ("models/weapons/v_uzi.md3"); precache_model ("models/weapons/h_uzi.iqm"); precache_sound ("weapons/uzi_fire.wav"); + precache_sound ("weapons/reload.wav"); } else if (req == WR_SETUP) + { weapon_setup(WEP_UZI); + self.current_ammo = ammo_nails; + } else if (req == WR_CHECKAMMO1) + { if(autocvar_g_balance_uzi_mode == 1) - return self.ammo_nails >= autocvar_g_balance_uzi_sustained_ammo; + ammo_amount = self.ammo_nails >= autocvar_g_balance_uzi_sustained_ammo; else - return self.ammo_nails >= autocvar_g_balance_uzi_first_ammo; + ammo_amount = self.ammo_nails >= autocvar_g_balance_uzi_first_ammo; + + if(autocvar_g_balance_uzi_reload_ammo) + { + if(autocvar_g_balance_uzi_mode == 1) + ammo_amount += self.weapon_load[WEP_UZI] >= autocvar_g_balance_uzi_sustained_ammo; + else + ammo_amount += self.weapon_load[WEP_UZI] >= autocvar_g_balance_uzi_first_ammo; + } + return ammo_amount; + } else if (req == WR_CHECKAMMO2) + { if(autocvar_g_balance_uzi_mode == 1) - return self.ammo_nails >= autocvar_g_balance_uzi_burst_ammo; + ammo_amount = self.ammo_nails >= autocvar_g_balance_uzi_burst_ammo; else - return self.ammo_nails >= autocvar_g_balance_uzi_first_ammo; + ammo_amount = self.ammo_nails >= autocvar_g_balance_uzi_first_ammo; + + if(autocvar_g_balance_uzi_reload_ammo) + { + if(autocvar_g_balance_uzi_mode == 1) + ammo_amount += self.weapon_load[WEP_UZI] >= autocvar_g_balance_uzi_burst_ammo; + else + ammo_amount += self.weapon_load[WEP_UZI] >= autocvar_g_balance_uzi_first_ammo; + } + return ammo_amount; + } + else if (req == WR_RELOAD) + { + W_Reload(min(max(autocvar_g_balance_uzi_sustained_ammo, autocvar_g_balance_uzi_first_ammo), autocvar_g_balance_uzi_burst_ammo), autocvar_g_balance_uzi_reload_ammo, autocvar_g_balance_uzi_reload_time, "weapons/reload.wav"); + } return TRUE; }; #endif diff --git a/sound/weapons/campingrifle_reload.ogg b/sound/weapons/campingrifle_reload.ogg deleted file mode 100644 index 2edb3739cc..0000000000 Binary files a/sound/weapons/campingrifle_reload.ogg and /dev/null differ diff --git a/sound/weapons/reload.ogg b/sound/weapons/reload.ogg new file mode 100644 index 0000000000..2edb3739cc Binary files /dev/null and b/sound/weapons/reload.ogg differ