From ab70641e4b4aa33aa437e59dcddffb2f77ce53fe Mon Sep 17 00:00:00 2001 From: cypress Date: Sat, 28 Sep 2024 13:32:55 -0700 Subject: [PATCH 1/9] SERVER/CLIENT: Adjust ADS offset for Colt M1911 --- source/shared/weapon_stats.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/shared/weapon_stats.qc b/source/shared/weapon_stats.qc index 3c0f809..3a9d116 100644 --- a/source/shared/weapon_stats.qc +++ b/source/shared/weapon_stats.qc @@ -1550,7 +1550,7 @@ vector GetWeaponADSOfs(float wep) = { case W_COLT: case W_BIATCH: - return [-5479.2, 1850, -4000]; + return [-3479.2, 1050, -4000]; case W_KAR: case W_ARMAGEDDON: return [-5495.9, 3006.9, -6000]; From 0a86a64995d96c0057faf2398c6f6c3537986b30 Mon Sep 17 00:00:00 2001 From: cypress Date: Sat, 5 Oct 2024 20:23:06 -0700 Subject: [PATCH 2/9] SERVER: Allow worldspawn gravity property to manipulate sv_gravity --- source/server/main.qc | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/source/server/main.qc b/source/server/main.qc index 439e73d..d3e5b71 100644 --- a/source/server/main.qc +++ b/source/server/main.qc @@ -395,6 +395,23 @@ void() worldspawn = G_WORLDTEXT = 1; G_PERKS = 0; G_PERKPOWER = 0; + + // + // World Gravity Multiplier + // + + // FIXME: This should technically poll sv_gravity but + // we do not currently enforce a default that resets + // on a new server. + float sv_gravity = 800; + + // worldspawn "gravity" field is a multiplier to be applied + // to sv_gravity. + if (!world.gravity) world.gravity = 1; + world.gravity = clamp(world.gravity, 0.1, 2); + + // Update the cvar for the server. + cvar_set("sv_gravity", ftos(sv_gravity * world.gravity)); } void() SpectatorConnect = From c0b6e943be154c10464f379748fc88ed0e8aebc7 Mon Sep 17 00:00:00 2001 From: cypress Date: Sat, 12 Oct 2024 09:08:41 -0700 Subject: [PATCH 3/9] FTE/SERVER: Improve Waypoint Link Validation --- source/server/ai/fte/waypoints_core.qc | 34 ++++++++++++++++++-------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/source/server/ai/fte/waypoints_core.qc b/source/server/ai/fte/waypoints_core.qc index 5e15eea..7f50908 100644 --- a/source/server/ai/fte/waypoints_core.qc +++ b/source/server/ai/fte/waypoints_core.qc @@ -218,9 +218,9 @@ float Link (entity from, entity to) { float i; entity tempe; for (i = 0; i < MAX_WAY_TARGETS; i++) { - tempe = find (world, waynum, from.targets[i]); + tempe = find(world, waynum, from.targets[i]); - if (tempe == world || tempe == to) { + if (tempe == world || !from.targets[i]) { from.targets[i] = to.waynum; bprint(PRINT_HIGH, "Linked waypoint "); bprint(PRINT_HIGH, to.waynum); @@ -253,24 +253,38 @@ void () Link_Waypoints = return; if (Waypoint_Linked_To(current_way, active_way)) { - bprint(PRINT_HIGH, "These waypoints are already linked!\n"); + bprint(PRINT_HIGH, "[INFO]: These waypoints are already linked!\n"); return; } float i; entity tempe; for (i = 0; i < MAX_WAY_TARGETS; i++) { - tempe = findfloat (world, waynum, active_way.targets[i]); - - if (tempe == world) { - if (Link(active_way, current_way)) { + // First pass - if the target field is blank no extra + // validation is needed, just link. + if (!active_way.targets[i]) { + if (Link(active_way, current_way)) return; - } + + bprint(PRINT_HIGH, "[INFO]: Got Linkable Waypoints but Linking failed!\n"); + return; + } + + // Second pass - if the targets field is occupied + // check if the waypoint still exists, link if it + // does not. + if (find(world, waynum, active_way.targets[i]) == world) { + bprint(PRINT_HIGH, sprintf("[INFO]: Found Waypoint ID %s but not entity, overwriting link..\n", active_way.targets[i])); + + if (Link(active_way, current_way)) + return; + + bprint(PRINT_HIGH, " ..Failed!\n"); + return; } } - - bprint(PRINT_HIGH, "no targets remaining!\n"); + bprint(PRINT_HIGH, "[INFO]: All Waypoint links occupied for this Waypoint!\n"); } From 01e95c4dab91ce0e8b7387d2726d9ee307792ae7 Mon Sep 17 00:00:00 2001 From: cypress Date: Sat, 12 Oct 2024 12:03:59 -0700 Subject: [PATCH 4/9] SERVER: Fix Double-Barrel Take Out Start Frame --- source/shared/weapon_stats.qc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/shared/weapon_stats.qc b/source/shared/weapon_stats.qc index 3a9d116..dfd51ac 100644 --- a/source/shared/weapon_stats.qc +++ b/source/shared/weapon_stats.qc @@ -1928,7 +1928,7 @@ float(float wep, float frametype, optional float z) GetFrame = case SPRINT_OUT_END: return 31; case TAKE_OUT_START: - return 38; + return 37; case TAKE_OUT_END: return 41; case PUT_OUT_START: From 35d887fb551d06db9a8b180c0348019f4f8a4aa6 Mon Sep 17 00:00:00 2001 From: cypress Date: Sun, 3 Nov 2024 09:54:14 -0800 Subject: [PATCH 5/9] SERVER: Explicitly use SUB_UseTargets() for buy_weapon --- source/server/entities/wall_weapon.qc | 30 ++++++--------------------- 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/source/server/entities/wall_weapon.qc b/source/server/entities/wall_weapon.qc index 51d5b7c..d170481 100644 --- a/source/server/entities/wall_weapon.qc +++ b/source/server/entities/wall_weapon.qc @@ -202,10 +202,7 @@ void () WallWeapon_TouchTrigger = Player_RemoveScore(other, wcost); if (self.enemy) { - oldent = self; - self = self.enemy; - self.use(); - self = oldent; + SUB_UseTargets(); } } } else @@ -247,10 +244,7 @@ void () WallWeapon_TouchTrigger = Player_RemoveScore(other, wcost); if (self.enemy) { - oldent = self; - self = self.enemy; - self.use(); - self = oldent; + SUB_UseTargets(); } } } @@ -282,10 +276,7 @@ void () WallWeapon_TouchTrigger = nzp_bettyprompt(other); if (self.enemy) { - oldent = self; - self = self.enemy; - self.use(); - self = oldent; + SUB_UseTargets(); } } other.semi_actions |= SEMIACTION_USE; @@ -315,10 +306,7 @@ void () WallWeapon_TouchTrigger = other.primary_grenades = 4; if (self.enemy) { - oldent = self; - self = self.enemy; - self.use(); - self = oldent; + SUB_UseTargets(); } } other.semi_actions |= SEMIACTION_USE; @@ -341,10 +329,7 @@ void () WallWeapon_TouchTrigger = other.ach_tracker_coll++; if (self.enemy) { - oldent = self; - self = self.enemy; - self.use(); - self = oldent; + SUB_UseTargets(); } entity tempz; tempz = self; @@ -378,10 +363,7 @@ void () WallWeapon_TouchTrigger = other.reload_delay = 0; Player_RemoveScore(other, self.cost); if (self.enemy) { - oldent = self; - self = self.enemy; - self.use(); - self = oldent; + SUB_UseTargets(); } tempe = self; self = other; From c367fdc8445a33ca3f112c6bfb17f24f20f07a50 Mon Sep 17 00:00:00 2001 From: MotoLegacy Date: Sun, 24 Nov 2024 17:34:06 -0800 Subject: [PATCH 6/9] CLIENT: Add automatic Q3 shader generation for alpha transparency --- source/client/defs/fte.qc | 2 +- source/client/main.qc | 100 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/source/client/defs/fte.qc b/source/client/defs/fte.qc index 470322d..aa3aaa5 100644 --- a/source/client/defs/fte.qc +++ b/source/client/defs/fte.qc @@ -2093,7 +2093,7 @@ vector(entity e, float s, vector p) getsurfaceclippedpoint = #439; /* Part of DP float(string s) tokenize = #441; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ string(float n) argv = #442; /* Part of KRIMZON_SV_PARSECLIENTCOMMAND*/ void(entity e, entity tagentity, string tagname) setattachment = #443; /* Part of DP_GFX_QUAKE3MODELTAGS*/ -searchhandle(string pattern, enumflags:float{SB_CASEINSENSITIVE=1<<0,SB_FULLPACKAGEPATH=1<<1,SB_ALLOWDUPES=1<<2,SB_FORCESEARCH=1<<3} flags, float quiet, optional string filterpackage) search_begin = #444; /* Part of DP_QC_FS_SEARCH, DP_QC_FS_SEARCH_PACKFILE +searchhandle(string pattern, enumflags:float{SB_CASEINSENSITIVE=1<<0,SB_FULLPACKAGEPATH=1<<1,SB_ALLOWDUPES=1<<2,SB_FORCESEARCH=1<<3,SB_MULTISEARCH=1<<4} flags, float quiet, optional string filterpackage) search_begin = #444; /* Part of DP_QC_FS_SEARCH, DP_QC_FS_SEARCH_PACKFILE initiate a filesystem scan based upon filenames. Be sure to call search_end on the returned handle. SB_FULLPACKAGEPATH interprets the filterpackage arg as a full package path to avoid gamedir ambiguity, equivelent to whichpack's WP_FULLPACKAGEPATH flag. SB_ALLOWDUPES allows returning multiple entries with the same name (but different package, useful with search_fopen). SB_FORCESEARCH requires use of the filterpackage and SB_FULLPACKAGEPATH flag, initiating searches from gamedirs/packages which are not currently active. */ void(searchhandle handle) search_end = #445; /* Part of DP_QC_FS_SEARCH, DP_QC_FS_SEARCH_PACKFILE*/ diff --git a/source/client/main.qc b/source/client/main.qc index facd443..f873bc5 100644 --- a/source/client/main.qc +++ b/source/client/main.qc @@ -25,6 +25,8 @@ */ +float need_vid_reload; + void() ToggleMenu = { if(serverkey("constate") != "disconnected") @@ -75,6 +77,95 @@ float(float isnew) SetZombieSkinning = return PREDRAW_NEXT; }; +// +// GenerateAlphaTransparencyQ3Shaders() +// What a mouth-full! Anyway, NZ:P supports +// alpha transparency via a pseudo-hack where +// if the last character of a model is "$" +// we render with special blend modes. To +// do the same on FTE, we need to generate +// Quake III "shader" files. Returns TRUE +// if we had shader modifications. +// +float() GenerateAlphaTransparencyQ3Shaders = +{ + searchhandle alias_models; + float amod_count; + float need_reload = false; + + alias_models = search_begin("*.mdl:*/*.mdl:*/*/*.mdl:*/*/*/*.mdl:*/*/*/*/*.mdl:*/*/*/*/*/*.mdl", SB_CASEINSENSITIVE | SB_MULTISEARCH, true); // gross. + amod_count = search_getsize(alias_models); + + for (float i = 0; i < amod_count; i++) { + string full_path = search_getfilename(alias_models, i); + + // Single out character before ".mdl" extension. + string special_character = substring(full_path, strlen(full_path) - 5, 1); + + // Early out, not a special guy. + if (special_character != "$") + continue; + + // Isolate its basename.. manually :( + string basename = ""; + for (float j = strlen(full_path); j > 0; j--) { + if (str2chr(full_path, j) == str2chr("/", 0)) { + // Strip path + basename = substring(full_path, j + 1, strlen(full_path) - (j + 1)); + + // Strip extension + basename = substring(basename, 0, strlen(basename) - 4); + break; + } + } + + if (basename == "") { + print(sprintf("[ERROR]: Unable to calculate basename for [%s]!\n", full_path)); + continue; + } + + float shader_file; + string shader_path = sprintf("scripts/%s.shader", basename); + + // Check if the shader already exists. + shader_file = fopen(shader_path, FILE_READ); + if (shader_file != -1) { + fclose(shader_file); + continue; + } + + // Begin to write. + shader_file = fopen(shader_path, FILE_WRITE); + if (shader_file == -1) { + print(sprintf("[ERROR]: Unable to generate Q3 shader for [%s]!\n", full_path)); + continue; + } + + // Body of our shader file we're writing. + string shader_content = sprintf( + "//\n" + "// Quake III Shader generated automatically by Nazi Zombies: Portable. Do not modify.\n" + "//\n" + "\n" + "%s_0.lmp\n" // full_path + "{\n" + " program defaultskin\n" + " progblendfunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA\n" + " diffusemap %s_0.tga\n" // full_path + " alphafunc ge128\n" + "}\n" + , full_path, full_path); + + fputs(shader_file, shader_content); + fclose(shader_file); + + need_reload = true; + } + + search_end(alias_models); + return need_reload; +}; + noref void(float apiver, string enginename, float enginever) CSQC_Init = { setwindowcaption("Nazi Zombies: Portable"); @@ -192,10 +283,19 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = } InitKerningMap(); + + // If we've made shader changes, we should perform + // a vid_reload at a reasonable time. + need_vid_reload = GenerateAlphaTransparencyQ3Shaders(); }; noref void() CSQC_WorldLoaded = { + if (need_vid_reload == true) { + need_vid_reload = false; + localcmd("vid_reload\n"); + } + Achievement_Init(); Particles_Init(); nameprint_time = time + 8; From 217e34b05eff58af1261bcb857ab5f378e721ac7 Mon Sep 17 00:00:00 2001 From: MotoLegacy Date: Sun, 24 Nov 2024 18:21:55 -0800 Subject: [PATCH 7/9] SERVER: Give up after X attempts to pick random Perk-A-Cola --- source/server/entities/perk_a_cola.qc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/server/entities/perk_a_cola.qc b/source/server/entities/perk_a_cola.qc index ada2836..c0f07ab 100644 --- a/source/server/entities/perk_a_cola.qc +++ b/source/server/entities/perk_a_cola.qc @@ -643,7 +643,8 @@ void() Perk_RandomDecide = } // Choose which of the eight machines we want to become, if permitted. - while (true) { + float num_attempts; + for(num_attempts = 64; num_attempts > 0; num_attempts--) { i = random(); // Quick Revive if (i < (1/8) && (self.spawnflags & SPAWNFLAG_PERKRANDOM_QUICKREVIVE)) { @@ -694,6 +695,9 @@ void() Perk_RandomDecide = break; } } + + if (!num_attempts) + objerror("perk_random: Failed 64 times to pick a Perk-A-Cola. Bailing!\n"); }; void() Perk_RandomPrecaches = From 75152b9ad6f77b35deaf36d1b2b831a799776278 Mon Sep 17 00:00:00 2001 From: MotoLegacy Date: Sun, 24 Nov 2024 18:33:55 -0800 Subject: [PATCH 8/9] SERVER: Remove Bowie Knife on Re-Spawn --- source/server/defs/custom.qc | 2 +- source/server/entities/wall_weapon.qc | 4 ++-- source/server/player/player_core.qc | 3 ++- source/server/weapons/weapon_core.qc | 10 +++++----- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/source/server/defs/custom.qc b/source/server/defs/custom.qc index 8203253..4fb17d6 100644 --- a/source/server/defs/custom.qc +++ b/source/server/defs/custom.qc @@ -225,7 +225,7 @@ var struct guninventory_struct //Knife .float knife_delay; -.float bowie; +.float has_bowie_knife; //Grenades .float grenades; diff --git a/source/server/entities/wall_weapon.qc b/source/server/entities/wall_weapon.qc index d170481..aa6759c 100644 --- a/source/server/entities/wall_weapon.qc +++ b/source/server/entities/wall_weapon.qc @@ -314,7 +314,7 @@ void () WallWeapon_TouchTrigger = } else if (self.weapon == W_BOWIE) { - if (!other.bowie) { + if (!other.has_bowie_knife) { useprint(other, 4, self.cost2, self.weapon); if (other.button7) { @@ -335,7 +335,7 @@ void () WallWeapon_TouchTrigger = tempz = self; self = other; Set_W_Frame(15, 30, 2.75, 0, 0, W_PlayTakeOut, "models/weapons/knife/v_bowie.mdl", false, S_BOTH, true); - self.bowie = 1; + self.has_bowie_knife = true; } } } diff --git a/source/server/player/player_core.qc b/source/server/player/player_core.qc index 622895b..e101d8e 100644 --- a/source/server/player/player_core.qc +++ b/source/server/player/player_core.qc @@ -926,7 +926,8 @@ void() PlayerSpawn = setsize(self, PLAYER_MINS_STANDING, PLAYER_MAXS_STANDING); } - self.stance = 2; + self.has_bowie_knife = false; + self.stance = PLAYER_STANCE_STAND; self.new_ofs_z = self.view_ofs_z; self.oldz = self.origin_z; self.grenades = self.grenades | 1; // add frag grenades to player inventory diff --git a/source/server/weapons/weapon_core.qc b/source/server/weapons/weapon_core.qc index 61b4124..7937b2d 100644 --- a/source/server/weapons/weapon_core.qc +++ b/source/server/weapons/weapon_core.qc @@ -1268,17 +1268,17 @@ void() WeaponCore_Melee = // Apply damage to the entity. if (trace_ent.takedamage) { - float melee_damage = WepDef_CalculateMeleeDamage(self.weapon, self.bowie); + float melee_damage = WepDef_CalculateMeleeDamage(self.weapon, self.has_bowie_knife); DamageHandler (trace_ent, self, melee_damage, DMG_TYPE_MELEE); } } } // Grab animation stats for our melee weapon. - float start_frame = WepDef_GetMeleeFirstFrame(self.weapon, did_lunge, self.bowie); - float end_frame = WepDef_GetMeleeLastFrame(self.weapon, did_lunge, self.bowie); - float anim_duration = WepDef_GetMeleeAnimDuration(self.weapon, did_lunge, self.bowie); - string model_path = WepDef_GetMeleeModel(self.weapon, self.bowie); + float start_frame = WepDef_GetMeleeFirstFrame(self.weapon, did_lunge, self.has_bowie_knife); + float end_frame = WepDef_GetMeleeLastFrame(self.weapon, did_lunge, self.has_bowie_knife); + float anim_duration = WepDef_GetMeleeAnimDuration(self.weapon, did_lunge, self.has_bowie_knife); + string model_path = WepDef_GetMeleeModel(self.weapon, self.has_bowie_knife); // Ensure we play the Take Out animation if the melee model is not our active weapon void() end_func; From 937b8b588f739ee3576718f5af087e93f4c3e8e0 Mon Sep 17 00:00:00 2001 From: MotoLegacy Date: Sun, 24 Nov 2024 18:49:39 -0800 Subject: [PATCH 9/9] CLIENT: Fix underflow of Round stopwatch --- source/client/hud.qc | 1 + 1 file changed, 1 insertion(+) diff --git a/source/client/hud.qc b/source/client/hud.qc index fd4ac46..a7ef9be 100644 --- a/source/client/hud.qc +++ b/source/client/hud.qc @@ -779,6 +779,7 @@ void(float width, float height) HUD_Rounds = else if (rounds_change == 7)//blink white while fading back { stopwatch_round_isactive = true; + stopwatch_round_hr = stopwatch_round_min = stopwatch_round_sec = 0; if (!color_shift_init) { color_shift_end[0] = 107;