diff --git a/csqc/main.qc b/csqc/main.qc index 0301c01e..f25a5d9e 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -252,7 +252,7 @@ void Slot_Keyup(float slot) { localcmd("-attack\n"); } -void W_ChangeToSlotAlternate(string opt1, string opt2); +void W_ChangeToSlotAlternate(string opt1, string opt2, string opt3, string opt4); noref float(string cmd) CSQC_ConsoleCommand = { tokenize_console(cmd); @@ -452,7 +452,7 @@ noref float(string cmd) CSQC_ConsoleCommand = { RemoveVoteMap(argv(1), TRUE); break; case "slot_a": // Alternate between passed options - W_ChangeToSlotAlternate(argv(1), argv(2)); + W_ChangeToSlotAlternate(argv(1), argv(2), argv(3), argv(4)); break; } diff --git a/csqc/weapon_predict.qc b/csqc/weapon_predict.qc index ac0eb1c3..a5ca0a9b 100644 --- a/csqc/weapon_predict.qc +++ b/csqc/weapon_predict.qc @@ -712,19 +712,25 @@ void WP_ChangeWeapon(Slot slot) { // Alternate between opt1/opt2, activating opt1 if neither is active. // Useful for demoman to have red/yellows bound to 1 key. -void W_ChangeToSlotAlternate(string opt1, string opt2) { - float v1 = strlen(opt1) > 0 ? stof(opt1) : 0; - float v2 = strlen(opt2) > 0 ? stof(opt2) : v1; +void W_ChangeToSlotAlternate(string opt1, string opt2, string opt3, string opt4) { + float v[4], nv = 0, idx = -1; + string s[4] = {opt1, opt2, opt3, opt4}; - if ((v1 < 1 || v1 > TF_NUM_SLOTS) || (v2 < 1 || v2 > TF_NUM_SLOTS)) - return; + for (int i = 0; i < s.length; i++) { + if (strlen(s[i]) == 0) + break; + + float t = stof(s[i]); + if (t < 1 || t > TF_NUM_SLOTS) + return; + + if (SlotIndex(pstate_pred.current_slot) + 1 == t) + idx = nv; + v[nv++] = t; + } - // The OWI/slot mess rears its head again here. We convert to a slot for - // comparison but use the naked input value which will then be converted per - // OWI if active. - Slot slot = FO_SlotByInput(pstate_pred.playerclass, v1); - float imp = IsSameSlot(pstate_pred.current_slot, slot) ? v2 : v1; - localcmd(sprintf("impulse %d\n", imp)); + idx = (idx + 1) % nv; + localcmd(sprintf("impulse %d\n", TF_SLOT1 + v[idx] - 1)); } Slot WP_BestWeaponSlot() { diff --git a/ssqc/client.qc b/ssqc/client.qc index 38f61bfc..1f8db602 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -241,7 +241,7 @@ static float NB_UseMinPing() { return TRUE; } -void ActivateNewBalance() { +void ActivateOrgGame() { disable_resup_gren = 2; // No gren2 pickups drop_gren1 = 0; // No grenades in backpacks @@ -250,17 +250,17 @@ void ActivateNewBalance() { for (i = 1; i <= 9; i++) // 3 gren spawn SetAllRoles(i, 1, 3); - SetAllRoles(4, 2, 1); // 1 mirv for demoman - SetAllRoles(6, 2, 1); // 1 mirv for hwguy - SetAllRoles(9, 2, 1); // 1 emp for engineer - SetAllRoles(9, 1, 4); // 4 gren1 for engineer - SetAllRoles(3, 1, 4); // 4 gren1 for soldier + SetAllRoles(4, 2, CF_GetSetting("mg2_4", "max_gren2_demoman", ftos(1))); // 1 mirv for demoman + SetAllRoles(6, 2, CF_GetSetting("mg2_6", "max_gren2_hwguy", ftos(1))); // 1 mirv for hwguy + SetAllRoles(9, 2, CF_GetSetting("mg2_9", "max_gren2_engineer", ftos(1))); // 1 emp for engineer + SetAllRoles(9, 1, CF_GetSetting("mg1_9", "max_gren1_engineer", ftos(4))); // 4 gren1 for engineer + SetAllRoles(3, 1, CF_GetSetting("mg1_3", "max_gren1_soldier", ftos(4))); // 4 gren1 for soldier PC_PYRO_AIRBLAST_COOLDOWN = 10; PC_ENGINEER_GRENADE_TYPE_2_RANGE = 200; - float use_new_cap = CF_GetSetting("nbcc", "new_balance_conc_cap", "4"); - if (use_new_cap == 4 && ServerRegion() == kRegionOCE) + float use_new_cap = CF_GetSetting("nbcc", "new_balance_conc_cap", "0"); + if (use_new_cap == 4) use_new_cap = 1; else use_new_cap = 0; @@ -383,6 +383,7 @@ void () DecodeLevelParms = { duelmode = CF_GetSetting("duelmode", "duelmode", "off"); disable_voting = clanbattle || quadmode; + org_game = clanbattle || quadmode; rounds = CF_GetSetting("rounds","rounds","on"); if (!rounds) @@ -711,14 +712,14 @@ void () DecodeLevelParms = { */ Role_None.gren1_limits[0] = 0; Role_None.gren1_limits[1] = CF_GetSetting("mg1_1", "max_gren1_scout", ftos(PC_SCOUT_GRENADE_MAX_1)); - Role_None.gren1_limits[2] = CF_GetSetting("mg1_2", "max_gren1_sniper", ftos(PC_SNIPER_GRENADE_MAX_1)); - Role_None.gren1_limits[3] = CF_GetSetting("mg1_3", "max_gren1_soldier", ftos(PC_SOLDIER_GRENADE_MAX_1)); - Role_None.gren1_limits[4] = CF_GetSetting("mg1_4", "max_gren1_demoman", ftos(PC_DEMOMAN_GRENADE_MAX_1)); - Role_None.gren1_limits[5] = CF_GetSetting("mg1_5", "max_gren1_medic", ftos(PC_MEDIC_GRENADE_MAX_1)); - Role_None.gren1_limits[6] = CF_GetSetting("mg1_6", "max_gren1_hwguy", ftos(PC_HVYWEAP_GRENADE_MAX_1)); - Role_None.gren1_limits[7] = CF_GetSetting("mg1_7", "max_gren1_pyro", ftos(PC_PYRO_GRENADE_MAX_1)); - Role_None.gren1_limits[8] = CF_GetSetting("mg1_8", "max_gren1_spy", ftos(PC_SPY_GRENADE_MAX_1)); - Role_None.gren1_limits[9] = CF_GetSetting("mg2_9", "max_gren1_engineer", ftos(PC_ENGINEER_GRENADE_MAX_1)); + Role_None.gren1_limits[2] = CF_GetSetting("mg1_2", "max_gren1_sniper", ftos(PC_SNIPER_GRENADE_MAX_1)); + Role_None.gren1_limits[3] = CF_GetSetting("mg1_3", "max_gren1_soldier", ftos(PC_SOLDIER_GRENADE_MAX_1)); + Role_None.gren1_limits[4] = CF_GetSetting("mg1_4", "max_gren1_demoman", ftos(PC_DEMOMAN_GRENADE_MAX_1)); + Role_None.gren1_limits[5] = CF_GetSetting("mg1_5", "max_gren1_medic", ftos(PC_MEDIC_GRENADE_MAX_1)); + Role_None.gren1_limits[6] = CF_GetSetting("mg1_6", "max_gren1_hwguy", ftos(PC_HVYWEAP_GRENADE_MAX_1)); + Role_None.gren1_limits[7] = CF_GetSetting("mg1_7", "max_gren1_pyro", ftos(PC_PYRO_GRENADE_MAX_1)); + Role_None.gren1_limits[8] = CF_GetSetting("mg1_8", "max_gren1_spy", ftos(PC_SPY_GRENADE_MAX_1)); + Role_None.gren1_limits[9] = CF_GetSetting("mg1_9", "max_gren1_engineer", ftos(PC_ENGINEER_GRENADE_MAX_1)); // Maximum number of secondary grenades per class Role_None.gren2_limits[1] = CF_GetSetting("mg2_1", "max_gren2_scout", ftos(PC_SCOUT_GRENADE_MAX_2)); @@ -1096,11 +1097,12 @@ void () DecodeLevelParms = { // Overrides other settings. new_balance = CF_GetSetting("new_balance", "new_balance", "1"); - // mirror current state into desired state bit new_balance |= (new_balance << 1); - if (NewBalanceActive()) - ActivateNewBalance(); + + if (org_game) // This used to depend on new balance + ActivateOrgGame(); + }; entity() FindIntermission = diff --git a/ssqc/commands.qc b/ssqc/commands.qc index a0e9451e..5a7bf0f2 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -846,7 +846,10 @@ float (string arg1, string arg2, string arg3) ParseCmds = { break; case "break": processedCmd = TRUE; - if(self.vote_map) { + + if (disable_voting) { + // Do nothing + } else if (self.vote_map) { UnvoteForMap(self); } else { if(votemode) { diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index f1cf18cb..06c3785b 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -1577,6 +1577,33 @@ void () CheckDistance = { self.nextthink = time + 0.3; }; +float IsEngEnt(entity ent) { + return ent.classname == "building_dispenser" || + ent.classname == "building_sentrygun"; + +} + +void RemoveEngEnt(entity bld, float explode) { + entity owner = bld.real_owner; + if (owner.building == bld) { + Menu_Close(owner); + owner.building = world; + } + + if (explode) { + TF_T_Damage(bld, world, world, 500, 0, 0); + } else { + if(bld.classname == "building_dispenser") + owner.has_dispenser = 0; + if(bld.classname == "building_sentrygun") { + owner.has_sentry = 0; + if (bld.trigger_field != world) + dremove (bld.trigger_field); + } + dremove (bld); + } +} + void (entity eng, string bld, float explode) DestroyBuildingWithOptions = { local entity te; local entity oldself; @@ -1593,23 +1620,10 @@ void (entity eng, string bld, float explode) DestroyBuildingWithOptions = { bound_other_ammo(self); self = oldself; } - if (te.real_owner.building == te) { - Menu_Close(te.real_owner); - te.real_owner.building = world; - } - if(explode) { - TF_T_Damage(te, world, world, 500, 0, 0); - } else { - if(bld == "building_dispenser") - te.real_owner.has_dispenser = 0; - if(bld == "building_sentrygun") { - te.real_owner.has_sentry = 0; - if (te.trigger_field != world) - dremove (te.trigger_field); - } - spawn_tfog(te.origin); - dremove (te); - } + + spawn_tfog(te.origin); + RemoveEngEnt(te, explode); + } te = find(te, classname, bld); } diff --git a/ssqc/progs.src b/ssqc/progs.src index e563dbaa..c4d080b9 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -29,6 +29,7 @@ events.qc roles.qc q3defs.qc status.qc +teamplay.qc functions.qc menu.qc csmenu.qc diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 07600659..1453b2e8 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -452,6 +452,7 @@ float clanbattle; float clan_scores_dumped; float cb_prematch; float disable_voting; +float org_game; float v_break; float v_ready; .float allowvote; diff --git a/ssqc/scout.qc b/ssqc/scout.qc index aa2957b5..019979b1 100644 --- a/ssqc/scout.qc +++ b/ssqc/scout.qc @@ -830,8 +830,8 @@ void (entity inflictor, entity attacker, float bounce, local entity te; local vector org; - if (NewBalanceActive() && inflictor.owner.playerclass == PC_MEDIC) - actual_cuss_time = 2; + //if (NewBalanceActive() && inflictor.owner.playerclass == PC_MEDIC) + // actual_cuss_time = 2; head = findradius(inflictor.origin, bounce + 40); while (head) { diff --git a/ssqc/teamplay.qc b/ssqc/teamplay.qc new file mode 100644 index 00000000..c3dbab63 --- /dev/null +++ b/ssqc/teamplay.qc @@ -0,0 +1,104 @@ +static void Apply(entity* targets, int tcount, int(entity) filter_fn, + void(entity) apply_fn) { + for (int i = 0; i < tcount; i++) + if (filter_fn(targets[i])) + apply_fn(targets[i]); +} + +static entity EntityOwner(entity e) { + if (e.real_owner != world) + return e.real_owner; + else + return e.owner; +} + +static void ApplyList(entity* targets, int count, + int(entity) player_filter_fn, void(entity) player_apply_fn, + int(entity) other_filter_fn, void(entity) other_apply_fn) { + for (int i = 0; i < count; i++) { + entity e = targets[i]; + + if (e.classname == "player") { + if (player_filter_fn(e)) + player_apply_fn(e); + } else if (EntityOwner(e).classname == "player") { + if (other_filter_fn(e)) + other_apply_fn(e); + } + } +} + +static void ApplyRadius(vector org, float rad, + int(entity) player_filter_fn, void(entity) player_apply_fn, + int(entity) other_filter_fn, void(entity) other_apply_fn) { + int count; + entity* ents = findradius_list(org, rad, count); + ApplyList(ents, count, + player_filter_fn, player_apply_fn, other_filter_fn, other_apply_fn); +} + +void RemovePrimedGrenades(entity player); + +/* Disabled new-balance remove chaser ammo mechanic +static void EffStrip(entity player) { + player.ammo_cells = 0; + player.ammo_rockets = 0; + player.ammo_shells = 0; + player.ammo_nails = 0; + + player.no_grenades_1 = player.no_grenades_2 = 0; + player.current_slot = player.queue_slot = MakeSlot(4); + + RemovePrimedGrenades(player); + + string msg = "The enemy captured! You are afflicted by the Curse of Isma!"; + stuffcmd(player, "bf\n"); + sprint(player, PRINT_HIGH, msg, "\n"); + centerprint(player, msg); +}*/ + +float IsEngEnt(entity ent); +void RemoveEngEnt(entity bld, float explode); + +static void EffRemove(entity non_player) { + if (non_player.classname == "player") { + printf("ERROR! Tried to remove player [%s]\n", non_player.netname); + return; + } + + pointparticles(particleeffectnum("fo_airblast"), non_player.origin); + if (IsEngEnt(non_player)) + RemoveEngEnt(non_player, FALSE); + else + dremove(non_player); +} + +static int(entity p) FilTeamEQ[] = { + { return p.team_no == 1; }, + { return p.team_no == 2; }, + { return p.team_no == 3; }, + { return p.team_no == 4; }, +}; + +static int(entity p) FilTeamNEQ[] = { + { return p.team_no != 1; }, + { return p.team_no != 2; }, + { return p.team_no != 3; }, + { return p.team_no != 4; }, +}; + +static int(entity p) FilOwnerTeamNEQ[] = { + { return EntityOwner(p).team_no != 1; }, + { return EntityOwner(p).team_no != 2; }, + { return EntityOwner(p).team_no != 3; }, + { return EntityOwner(p).team_no != 4; }, +}; + +void TeamPlay_Cap(vector origin, entity player) { + if (!org_game || !new_balance) + return; + + //ApplyRadius(origin, 1500, + // FilTeamNEQ[player.team_no - 1], EffStrip, + // FilOwnerTeamNEQ[player.team_no - 1], EffRemove); +} diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 176a3da2..2423a696 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -133,15 +133,21 @@ void () RemoveAutoIdTimer = { } }; +void RemovePrimedGrenades(entity player) { + entity* ents; + int count; + + ents = find_list(classname, "primetimer", EV_STRING, count); + for (int i = 0; i < count; i++) + if (ents[i].owner == player) + dremove(ents[i]); + + player.tfstate &= ~(TFSTATE_GREN1_PRIMED | TFSTATE_GREN2_PRIMED); +} + void () RemovePrimeTimers = { - if (!drop_grenades) { - local entity te = find(world, classname, "primetimer"); - while (te != world) { - if (te.owner == self) - dremove(te); - te = find(te, classname, "primetimer"); - } - } + if (!drop_grenades) + RemovePrimedGrenades(self); }; void () RemoveGasTimers = { @@ -2045,11 +2051,12 @@ void (float Suicided) TeamFortress_SetupRespawn = { if (Suicided) { if (self.lives > 0) self.lives = self.lives - 1; - - if(!allowpracspawns) - restime = restime + 7; + + if (!allowpracspawns) + restime = restime + (new_balance ? 5 : 7); } } + if (cb_prematch) { if (self.lives > 0) self.lives = self.lives - 1; diff --git a/ssqc/tfortmap.qc b/ssqc/tfortmap.qc index e244f92b..3a9eed67 100644 --- a/ssqc/tfortmap.qc +++ b/ssqc/tfortmap.qc @@ -950,6 +950,8 @@ void (entity Goal, entity Player, entity AP, float addb) Apply_Results = { if (stock_on_cap) { if (Player == AP) { + TeamPlay_Cap(AP.origin, AP); + if (Player.health > 0) { T_Heal(Player, Player.max_health, 0); Player.armortype = Player.armor_allowed;