diff --git a/csqc/csextradefs.qc b/csqc/csextradefs.qc index 1e4db845..6e56721b 100644 --- a/csqc/csextradefs.qc +++ b/csqc/csextradefs.qc @@ -114,6 +114,7 @@ float vote_selected_index; float vote_list_offset; entity current_vote; string vote_list_filter; +float oldbuttons; float zoomed_in; float pick_up_time; float flag_team; @@ -866,6 +867,7 @@ struct { DEFCVAR_FLOAT(fo_fte_hud, 0); DEFCVAR_FLOAT(fo_legacy_sbar, 0); DEFCVAR_FLOAT(fo_csjumpsounds, 1); +DEFCVAR_FLOAT(fo_forward_facing_sentry, 0); struct GameState { float localentnum; diff --git a/csqc/csprogs.src b/csqc/csprogs.src index fcf7f83b..6870ce29 100644 --- a/csqc/csprogs.src +++ b/csqc/csprogs.src @@ -21,6 +21,7 @@ profile.qc ../share/classes.qc ../share/animate.qc ../share/mcp_precache.qc +../share/engineer.qc weapon_predict.qc pmove.qc tfx.qc diff --git a/csqc/events.qc b/csqc/events.qc index 8f4f6763..2c37aa9a 100644 --- a/csqc/events.qc +++ b/csqc/events.qc @@ -359,6 +359,9 @@ void() CSQC_Parse_Event = { flag_team = readfloat(); pick_up_time = time; break; + case MSG_BUILDING: + SentryPreviewStop(); + break; case MSG_FLAG_DROP: pick_up_time = FALSE; break; diff --git a/csqc/input.qc b/csqc/input.qc index 92161688..19282cbe 100644 --- a/csqc/input.qc +++ b/csqc/input.qc @@ -96,7 +96,7 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { } return TRUE; } - } + } case IE_KEYUP: switch (scanx) { case K_ESCAPE: @@ -117,7 +117,6 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent = { return TRUE; } break; - default: } } diff --git a/csqc/main.qc b/csqc/main.qc index 23cd0252..f6892653 100644 --- a/csqc/main.qc +++ b/csqc/main.qc @@ -16,6 +16,12 @@ void FO_Hud_Init(); float InFluid(vector point); float CalculateWaterLevel(); void RenderHitTexts(); +entity sentry_preview; +entity sentry_preview_range_sphere; +float sentry_preview_offset; +float previewing_sentry; +float prevent_firing; +float sentry_fits; void GetSelf() = { self = findfloat(world, entnum, player_localentnum); @@ -58,7 +64,6 @@ float RemoveFromSlotHistory(float slot) { } } - static void BindAlias(TFAlias* tfa) { if (tfa->impulse == 0 && tfa->cmd == "") // Some aliases are !csqc-only return; @@ -90,7 +95,6 @@ void ClientSettings_Check(); noref void(float apiver, string enginename, float enginever) CSQC_Init = { print("CSQC Started\n"); - // precache_model("progs/weapons/v_rock.mdl"); // for (float i = 0; i < HudIcons.length; i++) { // precache_pic(HudIcons[i].icon); @@ -106,6 +110,9 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { FO_Predict_Init(); CsGrenTimer::Init(); + registercommand("specialup"); + registercommand("specialdown"); + registercommand("+slot"); registercommand("-slot"); @@ -180,6 +187,19 @@ noref void(float apiver, string enginename, float enginever) CSQC_Init = { FO_Menu_Game(TRUE); pengine.view_mask = MASK_VIEWMODEL; // Start with engine models. + + precache_model("progs/turrpreview.mdl"); + sentry_preview = spawn(); + setmodel(sentry_preview, "progs/turrpreview.mdl"); + setsize(sentry_preview, '-16 -16 0', '16 16 48'); + sentry_preview.alpha = 0.25; + + precache_model("progs/sphere.mdl"); + sentry_preview_range_sphere = spawn(); + setmodel(sentry_preview_range_sphere, "progs/sphere.mdl"); + sentry_preview_range_sphere.scale = 1000; + sentry_preview_range_sphere.alpha = 0.02; + print("CSQC initialization finished\n"); }; @@ -199,11 +219,50 @@ void PMD_DrawGraphs(float width); DEFCVAR_FLOAT(fov, 90); +void SentryPreviewStart() { + if (CVARF(fo_forward_facing_sentry)) { + sentry_preview_offset = 0; + } else { + sentry_preview_offset = 180; + } + + sentry_preview.angles_y = input_angles_y; + sentry_preview.drawmask = MASK_ENGINE; + + local vector sphere_colormod = '1 1 1'; + switch (team_no) { + case 1: + sphere_colormod = '0 0.4 1'; + break; + case 2: + sphere_colormod = '1 0 0'; + break; + case 3: + sphere_colormod = '1 1 0'; + break; + case 4: + sphere_colormod = '0 1 0'; + break; + } + + sentry_preview_range_sphere.colormod = sphere_colormod * 4; + sentry_preview_range_sphere.drawmask = MASK_ENGINE; + + previewing_sentry = TRUE; + prevent_firing = TRUE; +} + +void SentryPreviewStop() { + previewing_sentry = FALSE; + sentry_preview.drawmask = 0; + sentry_preview_range_sphere.drawmask = 0; +} + noref void(float width, float height, float menushown) CSQC_UpdateView = { float fts = perf_start_sample(&frame_timing); clearscene(); setproperty(VF_DRAWWORLD, 1); // we want to draw our world! - setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! + FO_CussView(); if (zoomed_in) @@ -221,6 +280,34 @@ noref void(float width, float height, float menushown) CSQC_UpdateView = { if (PM_Enabled()) PM_UpdateView(); + if (previewing_sentry) { + if (game_state.is_alive) { + } else { + } + } + + if (previewing_sentry) { + if (!game_state.is_alive) { + SentryPreviewStop(); + } else { + } + makevectors(view_angles); + local vector v_forward_sentry; + v_forward_sentry.z = (normalize(v_forward) * 64).z; + v_forward_z = 0; + local vector xy_pos = normalize(v_forward) * 64; + v_forward_sentry.x = xy_pos.x; + v_forward_sentry.y = xy_pos.y; + + sentry_preview.origin = PM_Org() + v_forward_sentry; + sentry_fits = PlaceSentry(sentry_preview, PM_Org()); + sentry_preview.colormod = sentry_fits ? '1 1 1' : '0.5 0.2 0.2'; + sentry_preview_range_sphere.origin = sentry_preview.origin; + sentry_preview.angles_y = anglemod(view_angles_y + sentry_preview_offset); + } else { + setproperty(VF_DRAWCROSSHAIR, 1); // we want to draw our crosshair! + } + renderscene(); FO_CussCrosshair(width, height); @@ -261,6 +348,32 @@ noref float(string cmd) CSQC_ConsoleCommand = { local float grentype; switch(argv(0)) { + case "specialup": + switch (WP_PlayerClass()) { + case PC_ENGINEER: + if (previewing_sentry) { + sentry_preview_offset = anglemod(sentry_preview_offset - 15); + } else if (vlen(PM_Org() - sentry_pos) < ENG_BUILDING_DISMANTLE_DISTANCE) { + update_sentry_angles = time + 0.55; + sentry_angles_y = anglemod(sentry_angles_y - 15); + localcmd(sprintf("cmd sentry angle %f\n", sentry_angles_y)); + } + break; + } + break; + case "specialdown": + switch (WP_PlayerClass()) { + case PC_ENGINEER: + if (previewing_sentry) { + sentry_preview_offset = anglemod(sentry_preview_offset + 15); + } else if (vlen(PM_Org() - sentry_pos) < ENG_BUILDING_DISMANTLE_DISTANCE) { + update_sentry_angles = time + 0.55; + sentry_angles_y = anglemod(sentry_angles_y + 15); + localcmd(sprintf("cmd sentry angle %f\n", sentry_angles_y)); + } + break; + } + break; case "+slot": Slot_Keydown(stof(argv(1))); break; @@ -531,11 +644,11 @@ static vector FO_Conc_Offset() { float i, rot = 0; if (!IsClownMode(CLOWN_CONC)) { - table = conc_curve; - len = conc_curve.length; + table = conc_curve; + len = conc_curve.length; } else { - table = clown_curve; - len = clown_curve.length; + table = clown_curve; + len = clown_curve.length; } for (i = 0; i < len - 1; i++) { @@ -633,7 +746,7 @@ void FO_ApplyCussInput() { float modify_forward = TRUE; if ((!pmove_onground && (fo_config.fo_concuss & FOC_EASY_AIR)) || - (pmove_onground && (fo_config.fo_concuss & FOC_EASY_GROUND))) + (pmove_onground && (fo_config.fo_concuss & FOC_EASY_GROUND))) modify_forward = input_buttons & BUTTON0; if (modify_forward) { @@ -646,13 +759,60 @@ void FO_ApplyCussInput() { void PM_InputFrame(); noref void CSQC_Input_Frame() { + local float changed_buttons = input_buttons ^ oldbuttons; + oldbuttons = input_buttons; + + local float keydowns = changed_buttons & input_buttons; + local float keyups = changed_buttons & ~input_buttons; + Sync_GameState(); - // Intercept rocket jump; + // Intercept rocket jump if ((WP_PlayerClass() == PC_SOLDIER || WP_PlayerClass() == PC_PYRO) && - (input_buttons & BUTTON4)) + (input_buttons & BUTTON4)) input_buttons |= BUTTON0 | BUTTON2; + if (WP_PlayerClass() == PC_ENGINEER) { + // Intercept sentry build + if (!getstatf(STAT_HAS_SENTRY) && getstatf(STAT_CELLS) >= 130 && game_state.is_alive && !prematch) { + if (input_buttons & BUTTON4) { + if (keydowns & BUTTON4) { + if (!previewing_sentry) { + SentryPreviewStart(); + } else { + SentryPreviewStop(); + } + } + + input_buttons = input_buttons - BUTTON4; + } + + if (previewing_sentry) { + if (keydowns & BUTTON0) { + if (sentry_fits) { + localcmd(sprintf("cmd build sentry %f\n", anglemod(180 + sentry_preview_offset))); + SentryPreviewStop(); + } else { + print("Can't build here\n"); + } + } + + if (input_buttons & BUTTON0) { + input_buttons = input_buttons - BUTTON0; + } + } + + } + + if (prevent_firing && !previewing_sentry && (keyups & BUTTON0)) { + prevent_firing = FALSE; + } + + if (prevent_firing) { + input_buttons &= ~BUTTON0; + } + } + // Handle zoom float prev_zoomed_in = zoomed_in; if (WP_PlayerClass() == PC_SNIPER) @@ -753,7 +913,7 @@ float FoLogin(string token, float print_error) { } if (token == "") { - if (print_error) + if (print_error) print("Token required: Please sign-up at fortressone.org and follow the instructions to generate your login token.\n"); return FALSE; } diff --git a/csqc/menu.qc b/csqc/menu.qc index 17b341d2..d901afae 100644 --- a/csqc/menu.qc +++ b/csqc/menu.qc @@ -324,10 +324,11 @@ var fo_menu FO_MENU_BUILD = { }; var fo_menu FO_MENU_SENTRY_MAINTAIN = { [0,0], [300,200], "Sentry Gun", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { - {"1","Anticlockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate 45\n");Menu_Cancel();},MENU_BUTTON}, + {"1","Anticlockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate -45\n");Menu_Cancel();},MENU_BUTTON}, {"2","180 Degrees","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate 180\n");Menu_Cancel();},MENU_BUTTON}, - {"3","Clockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate -45\n");Menu_Cancel();},MENU_BUTTON}, + {"3","Clockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate 45\n");Menu_Cancel();},MENU_BUTTON}, MenuSpacer, + /* {"4","With Mouse","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate mouse\n");Menu_Cancel();},MENU_BUTTON}, */ {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, }, 5, TRUE, { if(vlen(PM_Org() - sentry_pos) > ENG_BUILDING_MAINT_DISTANCE) { @@ -339,10 +340,11 @@ var fo_menu FO_MENU_SENTRY_MAINTAIN = { var fo_menu FO_MENU_SENTRY_ROTATE = { [0,0], [300,200], "Rotate Sentry Gun", FO_MENU_FLAG_CENTER | FO_MENU_FLAG_SHOW_SHORTCUTS, { - {"1","Anticlockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate 45\n");Menu_Cancel();},MENU_BUTTON}, + {"1","Anticlockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate -45\n");Menu_Cancel();},MENU_BUTTON}, {"2","180 Degrees","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate 180\n");Menu_Cancel();},MENU_BUTTON}, - {"3","Clockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate -45\n");Menu_Cancel();},MENU_BUTTON}, + {"3","Clockwise","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate 45\n");Menu_Cancel();},MENU_BUTTON}, MenuSpacer, + /* {"4","With Mouse","","",FO_MENU_STATE_NORMAL,{localcmd("cmd sentry rotate mouse\n");Menu_Cancel();},MENU_BUTTON}, */ {"5","Nothing","","",FO_MENU_STATE_NORMAL,{Menu_Cancel();},MENU_BUTTON}, }, 5, TRUE, { if(vlen(PM_Org() - sentry_pos) > ENG_BUILDING_MAINT_DISTANCE) { diff --git a/csqc/tfx.qc b/csqc/tfx.qc index 1de72c02..c69366ee 100644 --- a/csqc/tfx.qc +++ b/csqc/tfx.qc @@ -3,6 +3,8 @@ .float teamno; static entity local_player; static float shader_team[2], shader_flag, shader_over_outline; +float update_sentry_angles; +float sentry_angles_y; enum { TeamNone = 0, @@ -263,6 +265,36 @@ float UpdateFlag(float isnew) { return TRUE; } +float UpdateSentry(float isnew) { + if (isnew) { + sentry_angles_y = self.angles_y; + } else { + if (update_sentry_angles > time) { + self.angles_y = sentry_angles_y; + } else { + sentry_angles_y = self.angles_y; + } + } + + return TRUE; +} + +float UpdateSentryBase(float isnew) { + if (isnew) { + sentry_angles_y = self.angles_y; + } else { + if (!SBAR.SentryLevel && SBAR.IsBuilding) { + if (update_sentry_angles > time) { + self.angles_y = sentry_angles_y; + } else { + sentry_angles_y = self.angles_y; + } + } + } + + return TRUE; +} + void TFxGrenTimerUpdate(float ent_num, float expiry) { EntHash* he = EntGet(ent_num); he->grentimer_expires = expiry; @@ -309,4 +341,6 @@ void TF_Init() { shader_over_outline = shaderforname(rnds("over_outline"), "{ sort 7 }"); #endif + deltalisten("progs/turrgun.mdl", UpdateSentry, 0); + deltalisten("progs/turrbase.mdl", UpdateSentryBase, 0); } diff --git a/share/commondefs.qc b/share/commondefs.qc index f6b24f95..1a7162aa 100644 --- a/share/commondefs.qc +++ b/share/commondefs.qc @@ -215,6 +215,7 @@ const float SERVER_FRAME_MS = SERVER_FRAME_DT * 1000.0; #define MSG_RELOADSOUND 28 #define MSG_FLAG_PICKUP 29 #define MSG_FLAG_DROP 30 +#define MSG_BUILDING 31 #define FLAGINFO_HOME 1 #define FLAGINFO_CARRIED 2 diff --git a/share/defs.h b/share/defs.h index a96d8bcd..979dbe52 100644 --- a/share/defs.h +++ b/share/defs.h @@ -1460,16 +1460,19 @@ enum { #define STAT_ALL_TIME 38 #define STAT_SPAWN_GEN 39 #define STAT_ROUND_END 40 +#define STAT_HAS_SENTRY 41 // Dimensions #define DMN_FLASH 1 // when flashed, we set dimension see to this // all bits between 1 and 255 are reserved for flash #define DMN_NOFLASH 256 // see all the things #define DMN_TEAMBLUE 512 -#define DMN_TEAMRED 1024 +#define DMN_TEAMRED 1024 #define DMN_TEAMYELL 2048 #define DMN_TEAMGREN 4096 #define DMN_INVISIBLE 8192 // special dimension to hide stuff in +#define DMN_HIDDEN 16384 // put an entity here instead of noflash, then remove DMN_HIDDEN from a player's dimension_see to hide it from that player +#define DMN_GHOST 32768 // put ghosts in here // trigger_push #define PUSH_ONCE 1 diff --git a/share/engineer.qc b/share/engineer.qc new file mode 100644 index 00000000..01bb7083 --- /dev/null +++ b/share/engineer.qc @@ -0,0 +1,22 @@ +float PlaceSentry(entity sentry, vector builder_org) { + tracebox(sentry.origin, sentry.mins, sentry.maxs, sentry.origin, MOVE_NORMAL, sentry); + + if (trace_inopen) + return (1); + + local vector start = sentry.origin; + start_z = builder_org_z + 64; + + tracebox(start, sentry.mins, sentry.maxs, sentry.origin, MOVE_NORMAL, sentry); + + if (trace_fraction < 1.0) { + tracebox(trace_endpos, sentry.mins, sentry.maxs, trace_endpos, MOVE_NORMAL, sentry); + + if (trace_inopen) { + sentry.origin = trace_endpos; + return (1); + } + } + + return (0); +} diff --git a/ssqc/client.qc b/ssqc/client.qc index 7646ba4d..91fbf736 100644 --- a/ssqc/client.qc +++ b/ssqc/client.qc @@ -2101,19 +2101,19 @@ void (float all_dimensions) SetDimensions = { switch (self.team_no) { case TEAM_BLUE: - self.dimension_see = DMN_NOFLASH | DMN_TEAMBLUE; + self.dimension_see = DMN_NOFLASH | DMN_HIDDEN | DMN_TEAMBLUE; break; case TEAM_RED: - self.dimension_see = DMN_NOFLASH | DMN_TEAMRED; + self.dimension_see = DMN_NOFLASH | DMN_HIDDEN | DMN_TEAMRED; break; case TEAM_YELL: - self.dimension_see = DMN_NOFLASH | DMN_TEAMYELL; + self.dimension_see = DMN_NOFLASH | DMN_HIDDEN | DMN_TEAMYELL; break; case TEAM_GREN: - self.dimension_see = DMN_NOFLASH | DMN_TEAMGREN; + self.dimension_see = DMN_NOFLASH | DMN_HIDDEN | DMN_TEAMGREN; break; default: - self.dimension_see = DMN_NOFLASH; + self.dimension_see = DMN_NOFLASH | DMN_HIDDEN; break; } } diff --git a/ssqc/combat.qc b/ssqc/combat.qc index 6915b9d3..e2e6fd3c 100644 --- a/ssqc/combat.qc +++ b/ssqc/combat.qc @@ -121,9 +121,10 @@ void (entity targ, entity attacker) Killed = { ClientObituary(self, attacker); self.takedamage = DAMAGE_NO; self.touch = SUB_Null; - monster_death_use(); + self.th_die(); + self = oself; if(duelmode && targ.classname == "player" && !cb_prematch) { //Already in no fire mode - implies you're not the first to die @@ -716,7 +717,6 @@ void TF_T_Damage(entity targ, entity inflictor, entity attacker, BroadcastHitFlag(targ, inflictor, attacker, original_damage, damh); if (targ.health <= 0) { - if ((inflictor.classname == "detpack") && (inflictor.is_disarming) && (inflictor.enemy == targ)) deathmsg = DMSG_DETPACK_DIS; diff --git a/ssqc/commands.qc b/ssqc/commands.qc index 908a2613..b705dc0c 100644 --- a/ssqc/commands.qc +++ b/ssqc/commands.qc @@ -313,10 +313,10 @@ void (entity pl) PrintWho = { strunzone(msg); } -float (string arg1, string arg2, string arg3) ParseCmds = { +float (string arg1, string arg2, string arg3, string arg4) ParseCmds = { local float arg_num = 0, processedCmd, inp; local string tmp; - local float farg2, farg3; + local float farg2, farg3, farg4; local entity ent, pl; processedCmd = FALSE; @@ -692,13 +692,14 @@ float (string arg1, string arg2, string arg3) ParseCmds = { if(arg2 == "cancel") { TeamFortress_EngineerBuildStop(); break; - } + } if(arg2 == "sentry") { if(self.is_building && !engineer_move) { TeamFortress_EngineerBuildStop(); break; } - Menu_Engineer_Input(1); + + TeamFortress_BuildSentry(stof(arg3)); break; } if(arg2 == "dispenser") { @@ -730,11 +731,12 @@ float (string arg1, string arg2, string arg3) ParseCmds = { sprint(self, PRINT_HIGH, "Only engineers can do that!\n"); break; } + if(self.health <= 0) { sprint(self, PRINT_HIGH, "Can't maintain while dead.\n"); break; } - + //find sentry first ent = findradius(self.origin, ENG_BUILDING_MAINT_DISTANCE); while (ent) { @@ -744,10 +746,12 @@ float (string arg1, string arg2, string arg3) ParseCmds = { } ent = ent.chain; } + if (!ent) { sprint(self, PRINT_HIGH, "No sentry in range\n"); break; } + if (arg2 && arg3) { if(arg2 == "rotate") { farg3 = stof(arg3); @@ -756,13 +760,34 @@ float (string arg1, string arg2, string arg3) ParseCmds = { sprint(self, PRINT_HIGH, "Sentry detection issue!\n"); break; } - if(farg3 < 0) { - sprint(self, PRINT_HIGH, "Rotating ",ftos(farg3 * -1)," degrees clockwise...\n"); - } else { - sprint(self, PRINT_HIGH, "Rotating ",ftos(farg3)," degrees anticlockwise...\n"); + ent.angles_y -= farg3; + ent.waitmin = rint(ent.angles_y - 50); + ent.waitmin = anglemod(ent.waitmin); + ent.waitmax = rint(ent.angles_y + 50); + ent.waitmax = anglemod(ent.waitmax); + if (ent.waitmin > ent.waitmax) { + ent.waitmin = ent.waitmax; + ent.waitmax = anglemod(ent.angles_y - 50); } - ent.waitmin = anglemod(ent.waitmin + farg3); - ent.waitmax = anglemod(ent.waitmax + farg3); + ent.nextthink = time + 0.5; + break; + } else if (arg2 == "angle") { + farg3 = stof(arg3); + if (!ent.real_owner.has_sentry || ent.real_owner != self + || self.classname != "player" || ent == world) { + sprint(self, PRINT_HIGH, "Sentry detection issue!\n"); + break; + } + ent.angles_y = farg3; + ent.waitmin = rint(ent.angles_y - 50); + ent.waitmin = anglemod(ent.waitmin); + ent.waitmax = rint(ent.angles_y + 50); + ent.waitmax = anglemod(ent.waitmax); + if (ent.waitmin > ent.waitmax) { + ent.waitmin = ent.waitmax; + ent.waitmax = anglemod(ent.angles_y - 50); + } + ent.nextthink = time + 0.5; break; } sprint(self, PRINT_HIGH, "Invalid choice.\n"); @@ -1301,7 +1326,7 @@ float (string arg1, string arg2, string arg3) ParseCmds = { break; case "play_to_completion": if(arg2 != "0" && arg2 != "1") - return; + break; processedCmd = TRUE; localcmd ("localinfo play_to_completion ",arg2,"\n"); @@ -1376,7 +1401,7 @@ void (string cmd) SV_ParseClientCommand = { float isProcessed; tokenize(cmd); - isProcessed = ParseCmds(argv(0), argv(1), argv(2)); + isProcessed = ParseCmds(argv(0), argv(1), argv(2), argv(3)); if (!isProcessed) { diff --git a/ssqc/engineer.qc b/ssqc/engineer.qc index 06c3785b..7cea347b 100644 --- a/ssqc/engineer.qc +++ b/ssqc/engineer.qc @@ -18,7 +18,6 @@ void (entity disp) Engineer_SentryGun_Upgrade; void (entity disp) Engineer_SentryGun_Repair; void () Menu_Engineer_Cancel; void () CF_CheckBuilding; -float (entity obj, entity builder) CheckArea; void () LaserBolt_Think = { self.solid = SOLID_TRIGGER; @@ -484,14 +483,14 @@ void () FO_Engineer_ToggleSentry = { } void () TeamFortress_EngineerBuild = { - if (self.is_building == 0) { + if (!self.is_building) { if (((self.ammo_cells < 100) && !self.has_dispenser) && !self.has_sentry) { Status_Print(self, "\n\n\n\n\n\n\n", "Not enough metal to build anything"); return; } Menu_Engineer(self); - } else if (self.is_building == 1) { + } else if (self.is_building) { TeamFortress_EngineerBuildStop(); } }; @@ -526,7 +525,7 @@ void () TeamFortress_EngineerBuildStop = { } Menu_Close(self); - self.is_building = 0; + self.is_building = FALSE; self.building_percentage = 0; if (!engineer_move) { self.tfstate &= ~(TFSTATE_CANT_MOVE | TFSTATE_NO_WEAPON); @@ -534,69 +533,12 @@ void () TeamFortress_EngineerBuildStop = { } } -float (entity obj, entity builder) CheckArea = { - local vector src; - local vector end; - local float pos; - local entity te; - - pos = pointcontents(obj.origin); - if ((pos == -2) || (pos == -6)) { - return (0); - } - src_x = (obj.origin_x + obj.maxs_x) + 24; - src_y = (obj.origin_y + obj.maxs_y) + 24; - src_z = (obj.origin_z + obj.maxs_z) + 16; - pos = pointcontents(src); - if ((pos == -2) || (pos == -6)) { - return (0); - } - end_x = (obj.origin_x + obj.mins_x) - 16; - end_y = (obj.origin_y + obj.mins_y) - 16; - end_z = (obj.origin_z + obj.mins_z) - 16; - traceline(src, end, 1, obj); - if (trace_fraction != 1) { - return (0); - } - pos = pointcontents(end); - if ((pos == -2) || (pos == -6)) { - return (0); - } - src_x = (obj.origin_x + obj.mins_x) - 16; - src_y = (obj.origin_y + obj.maxs_y) + 16; - src_z = (obj.origin_z + obj.maxs_z) + 16; - pos = pointcontents(src); - if ((pos == -2) || (pos == -6)) { - return (0); - } - end_x = (obj.origin_x + obj.maxs_x) + 16; - end_y = (obj.origin_y + obj.mins_y) - 16; - end_z = (obj.origin_z + obj.mins_z) - 16; - traceline(src, end, 1, obj); - if (trace_fraction != 1) { - return (0); - } - pos = pointcontents(end); - if ((pos == -2) || (pos == -6)) { - return (0); - } - traceline(builder.origin, obj.origin, 1, builder); - if (trace_fraction != 1) { - return (0); - } - te = findradius(obj.origin, 64); - if (te != world) { - return (0); - } - return (1); -}; - -void (float objtobuild) TeamFortress_Build = { +void (float objtobuild, float offset) TeamFortress_Build = { if (cb_prematch) { sprint(self, PRINT_MEDIUM, "You cannot build during prematch\n"); return; } - + if(no_fire_mode) { sprint(self, PRINT_MEDIUM, "You cannot build right now\n"); return; @@ -611,16 +553,26 @@ void (float objtobuild) TeamFortress_Build = { tmp2 = '0 0 0'; newmis = spawn(); + makevectors(self.v_angle); + /* v_forward_z = 0; */ + /* v_forward = normalize(v_forward) * 64; */ + /* newmis.origin = self.origin + v_forward; */ + + local vector v_forward_sentry; + v_forward_sentry.z = (normalize(v_forward) * 64).z; v_forward_z = 0; - v_forward = normalize(v_forward) * 64; - newmis.origin = self.origin + v_forward; + local vector xy_pos = normalize(v_forward) * 64; + v_forward_sentry.x = xy_pos.x; + v_forward_sentry.y = xy_pos.y; + + newmis.origin = self.origin + v_forward_sentry; tmp1 = newmis.origin; tmp2 = newmis.origin - normalize(v_up) * 128; traceline(tmp1, tmp2, 1, world); if (trace_ent != world) { - sprint(self, PRINT_HIGH, "You cannot build here\n"); + sprint(self, PRINT_HIGH, "You can't build here\n"); dremove(newmis); return; } @@ -634,7 +586,7 @@ void (float objtobuild) TeamFortress_Build = { return; } - if (objtobuild == 1) { + if (objtobuild == BUILD_DISPENSER) { if (self.has_dispenser) { sprint(self, PRINT_HIGH, "You can only have one dispenser\n"); dremove(newmis); @@ -646,7 +598,7 @@ void (float objtobuild) TeamFortress_Build = { newmis.netname = "dispenser"; btime = time + 2; self.dispenser_ticks = 0; - } else if (objtobuild == 2) { + } else if (objtobuild == BUILD_SENTRYGUN) { if (self.has_sentry) { sprint(self, PRINT_HIGH, "You can only have one sentry gun\n"); dremove(newmis); @@ -659,8 +611,11 @@ void (float objtobuild) TeamFortress_Build = { btime = time + 5; self.sentry_ticks = 0; } - if (CheckArea(newmis, self) == 0) { - sprint(self, PRINT_HIGH, "Not enough room to build here\n"); + + setsize(newmis, tmp1, tmp2); + + if (!PlaceSentry(newmis, self.origin)) { + sprint(self, PRINT_HIGH, "You can't build here\n"); dremove(newmis); return; } @@ -669,13 +624,16 @@ void (float objtobuild) TeamFortress_Build = { sprint(self, PRINT_HIGH, "You cannot build in the water\n"); dremove(newmis); return; - } else if (!self.waterlevel) { - sprint(self, PRINT_HIGH, "You cannot build in the air\n"); - dremove(newmis); - return; } } - self.is_building = 1; + + UpdateClientBuilding(self); + + if (objtobuild == BUILD_SENTRYGUN) { + UpdateClient_Sentry(self, newmis); + } + + self.is_building = objtobuild; if (!engineer_move) { self.immune_to_check = time + 5; self.tfstate |= TFSTATE_CANT_MOVE | TFSTATE_NO_WEAPON; @@ -691,12 +649,11 @@ void (float objtobuild) TeamFortress_Build = { newmis.think = TeamFortress_FinishedBuilding; newmis.colormap = self.colormap; newmis.weapon = objtobuild; - newmis.angles_y = anglemod(self.angles_y + 180); + newmis.angles_y = anglemod(self.angles_y + 180 + offset); newmis.velocity = '0 0 8'; newmis.movetype = 6; newmis.solid = 2; FO_SetModel(newmis, newmis.mdl); - setsize(newmis, tmp1, tmp2); setorigin(newmis, newmis.origin); newmis.flags = newmis.flags - (newmis.flags & 512); @@ -707,15 +664,15 @@ void (float objtobuild) TeamFortress_Build = { newmis.team_no = self.team_no; newmis.max_health = newmis.health; newmis.takedamage = DAMAGE_AIM; - if (objtobuild == 1) { - self.has_dispenser = TRUE; + if (objtobuild == BUILD_DISPENSER) { + self.has_dispenser = TRUE; newmis.th_die = Dispenser_Die; self.ammo_cells = self.ammo_cells - ENG_DISPENSER_COST; newmis.classname = "building_dispenser"; } - if (objtobuild == 2) { + if (objtobuild == BUILD_SENTRYGUN) { self.sentry_ent = newmis; - self.has_sentry = TRUE; + self.has_sentry = TRUE; newmis.th_die = Sentry_Die; newmis.th_pain = Sentry_Pain; newmis.takedamage = DAMAGE_AIM; @@ -743,7 +700,7 @@ void () CF_CheckBuilding = { local entity building = self.enemy; self = self.owner; - if (self.is_building == 0) { + if (!self.is_building) { dremove(timer); return; } @@ -978,18 +935,6 @@ void () DispenserThink = { self.nextthink = time + 0.3; }; -void UpdateClient_Sentry(entity pl, entity sent) = { - if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) - return; - msg_entity = pl; - WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); - WriteByte(MSG_MULTICAST, MSG_SENTRY_POS); - WriteFloat(MSG_MULTICAST, sent.origin.x); - WriteFloat(MSG_MULTICAST, sent.origin.y); - WriteFloat(MSG_MULTICAST, sent.origin.z); - multicast('0 0 0', MULTICAST_ONE_NOSPECS); -} - void UpdateClient_Dispenser(entity pl, entity disp) = { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; @@ -1002,16 +947,15 @@ void UpdateClient_Dispenser(entity pl, entity disp) = { multicast('0 0 0', MULTICAST_ONE_NOSPECS); } - void () TeamFortress_FinishedBuilding = { local entity oldself; if (engineer_move) { - if (self.real_owner.is_building != 1) { + if (!self.real_owner.is_building) { return; } } else { - if (self.owner.is_building != 1) { + if (!self.owner.is_building) { return; } } @@ -1098,6 +1042,8 @@ void () TeamFortress_FinishedBuilding = { newmis.th_die = Sentry_Die; newmis.th_pain = Sentry_Pain; newmis.mdl = "progs/turrgun.mdl"; + newmis.dimension_ghost = DMN_GHOST; + newmis.dimension_ghost_alpha = 0.25; self.sentry_ent = newmis; FO_Sound(oldself, CHAN_ITEM, "weapons/turrset.wav", 1, 1); newmis.solid = SOLID_BBOX; @@ -1200,7 +1146,7 @@ void () Dispenser_Die = { self.real_owner.has_dispenser = 0; self.think = Dispenser_Explode; self.nextthink = time + 0.1; - if (self.real_owner.is_building) { + if (self.real_owner.is_building == BUILD_DISPENSER) { self = self.real_owner; TeamFortress_EngineerBuildStop(); } diff --git a/ssqc/menu.qc b/ssqc/menu.qc index 9b0429fd..44e69bcc 100644 --- a/ssqc/menu.qc +++ b/ssqc/menu.qc @@ -18,7 +18,7 @@ void (entity spy) Spy_RemoveDisguise; void (entity eng, string bld) DestroyBuilding; -void (float objtobuild) TeamFortress_Build; +void (float objtobuild, float offset) TeamFortress_Build; void () lvl1_sentry_stand; void () lvl2_sentry_stand; @@ -806,77 +806,87 @@ void () Menu_Demoman_Cancel = { Status_Menu(self, Menu_Demoman_Cancel_Input, s_detpack, s_cancel); } -void (float inp) Menu_Engineer_Input = { - local float dismantle_sentrygun; - local float dismantle_dispenser; - local entity te; +void (float offset) TeamFortress_BuildSentry = { + if (self.has_sentry) return; - if (inp == 5) - return; + if (self.ammo_cells >= ENG_SENTRY_COST) + TeamFortress_Build(BUILD_SENTRYGUN, offset); + else + Status_Print(self, "\n\n\n\n\n\n\n", strcat("You need ", ftos(ENG_SENTRY_COST - self.ammo_cells), " more cells to build a sentry gun")); +} - if (self.is_building) { - if (engineer_move) { - Status_Print(self, "\n\n\n\n\n\n\n", strcat("You are already building something")); - return; - } - Menu_Engineer(self); - return; - } +void (float inp) Menu_Engineer_Input = { + switch (inp) { + case 5: + break; - dismantle_sentrygun = 0; - dismantle_dispenser = 0; + // build sentry + case 1: + TeamFortress_BuildSentry(0); + break; - if (inp == 1 && !self.has_sentry) { - if (self.ammo_cells >= ENG_SENTRY_COST) - TeamFortress_Build(2); - else - Status_Print(self, "\n\n\n\n\n\n\n", strcat("You need ", ftos(ENG_SENTRY_COST), " cells to build a sentry gun")); - } - - if (inp == 2 && !self.has_dispenser) { - if (self.ammo_cells >= ENG_DISPENSER_COST) - TeamFortress_Build(1); - else - Status_Print(self, "\n\n\n\n\n\n\n", strcat("You need ", ftos(ENG_DISPENSER_COST), " cells to build a dispenser")); - } + // build dispenser + case 2: + if (!self.has_dispenser) { + if (self.ammo_cells >= ENG_DISPENSER_COST) + TeamFortress_Build(BUILD_DISPENSER, 0); + else + Status_Print(self, "\n\n\n\n\n\n\n", strcat("You need ", ftos(ENG_DISPENSER_COST), " cells to build a dispenser")); + } + break; - if (inp == 3 && self.has_sentry) { - te = findradius(self.origin, ENG_BUILDING_DISMANTLE_DISTANCE); - while (te) { - if (te.classname == "building_sentrygun") { - if (te.real_owner == self){ - sprint (self, PRINT_HIGH, "You dismantled the sentry gun and got 65 cells\n"); - self.ammo_cells = self.ammo_cells + 65; - dremove (te.trigger_field); - dremove (te); - self.has_sentry = 0; - dismantle_sentrygun = 1; + // dismantle or destroy sentry + case 3: + if (self.has_sentry) { + local float dismantle_sentrygun = 0; + local entity te = findradius(self.origin, ENG_BUILDING_DISMANTLE_DISTANCE); + while (te) { + if (te.classname == "building_sentrygun" && te.real_owner == self) { + if (te.weapon == 0) { + sprint(self, PRINT_HIGH, strcat("You stopped building a sentry gun and got ", ftos(ENG_SENTRY_COST), " cells back\n")); + self.ammo_cells += ENG_SENTRY_COST; + if (self.ammo_cells > self.maxammo_cells) + self.ammo_cells = self.maxammo_cells; + if (te.trigger_field != world) + dremove(te.trigger_field); + self = te.real_owner; + TeamFortress_EngineerBuildStop(); + } else { + sprint(self, PRINT_HIGH, "You dismantled the sentry gun and got 65 cells\n"); + self.ammo_cells += 65; + dremove(te.trigger_field); + dremove(te); + self.has_sentry = 0; + dismantle_sentrygun = 1; + } + } + te = te.chain; } + if (dismantle_sentrygun == 0) + DestroyBuilding(self, "building_sentrygun"); } - te = te.chain; - } - if (dismantle_sentrygun == 0) - DestroyBuilding(self, "building_sentrygun"); - } + break; - if (inp == 4 && self.has_dispenser) { - te = findradius(self.origin, ENG_BUILDING_DISMANTLE_DISTANCE); - while (te) { - if (te.classname == "building_dispenser") { - if (te.real_owner == self) { - sprint (self, PRINT_HIGH, "You dismantled the dispenser and got 50 cells\n"); - self.ammo_cells = self.ammo_cells + 50; - dremove (te); - self.has_dispenser = 0; - dismantle_dispenser = 1; + // dismantle or destroy dispenser + case 4: + if (self.has_dispenser) { + local float dismantle_dispenser = 0; + local entity te = findradius(self.origin, ENG_BUILDING_DISMANTLE_DISTANCE); + while (te) { + if (te.classname == "building_dispenser" && te.real_owner == self) { + sprint(self, PRINT_HIGH, "You dismantled the dispenser and got 50 cells\n"); + self.ammo_cells += 50; + dremove(te); + self.has_dispenser = 0; + dismantle_dispenser = 1; + } + te = te.chain; } + if (dismantle_dispenser == 0) + DestroyBuilding(self, "building_dispenser"); } - te = te.chain; - } - if (dismantle_dispenser == 0) - DestroyBuilding(self, "building_dispenser"); + break; } - }; void (entity player) Menu_Engineer = { @@ -922,7 +932,7 @@ void (entity player) Menu_Engineer = { te = te.chain; } } else if (player.ammo_cells >= 100) { - s_disp = Q"\s[2]\s Build dispenser \n"; + s_disp = Q"\s[2]\s Build dispenser \n"; } if ((player.has_dispenser || player.has_sentry) && !player.has_menutimer) { @@ -1021,10 +1031,10 @@ void () Menu_EngineerFix_SentryGun_Rotate = { if (!self.building.real_owner.has_sentry || self.building.real_owner != self - || self.classname != "player" || self.building == world) { + || self.classname != "player" || self.building == world) { return; } - + if(infokeyf(self, INFOKEY_P_CSQCACTIVE)) { //fte+csqc has its own team menu //ask the client to activate it @@ -1032,13 +1042,13 @@ void () Menu_EngineerFix_SentryGun_Rotate = { UpdateClientMenu_FixSentry(self); return; } - + Status_Menu(self, Menu_EngineerFix_SentryGun_Rotate_Input, action, rotl, rot180, rotr, nothing); }; void (float inp) Menu_EngineerFix_SentryGun_Input = { if (!self.building.real_owner.has_sentry || self.building.real_owner != self - || self.classname != "player" || self.building == world) + || self.classname != "player" || self.building == world) return; if (inp == 1) { @@ -1095,9 +1105,9 @@ void (float inp) Menu_Dispenser_Input = { empty = FALSE; if (inp == 1) { if ((self.building.ammo_shells == 0) - && (self.building.ammo_nails == 0) - && (self.building.ammo_rockets == 0) - && (self.building.ammo_cells == 0)) { + && (self.building.ammo_nails == 0) + && (self.building.ammo_rockets == 0) + && (self.building.ammo_cells == 0)) { empty = TRUE; } else { am = self.maxammo_shells - self.ammo_shells; @@ -1324,7 +1334,7 @@ void () Menu_Admin = s_menu1 = "Round Time Input Menu: \n\n"; //s_menu1 = strcat(s_menu1, "Enter a number between 1 and 10 \n"); //s_menu1 = strcat(s_menu1, "\n\n"); - + s_menu1 = strcat(s_menu1, Q"\s[1]\s 1 minute \n"); s_menu1 = strcat(s_menu1, Q"\s[2]\s 5 minutes \n"); s_menu1 = strcat(s_menu1, Q"\s[3]\s 10 minutes \n"); @@ -1388,12 +1398,12 @@ void () Menu_Admin = Status_Menu(self, Menu_Admin_Input, s_menu1); break; } - + // jesus christ what is this, this should be separated out for the good of the people // or maybe made understandable if (self.current_menu_type == ADMIN_MENU_TYPE_KICK || self.current_menu_type == ADMIN_MENU_TYPE_BAN - || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMONE || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO - || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT || self.current_menu_type == ADMIN_MENU_TYPE_FORCESPEC) + || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMONE || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO + || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT || self.current_menu_type == ADMIN_MENU_TYPE_FORCESPEC) { f_tmp = 0; f_tmp2 = 0; @@ -1450,20 +1460,20 @@ void () Menu_Admin = } if (f_tmp == 0 && ( self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO ) ) { - bprint(2, "\x10\sCaptain Mode\s\x11\s:\s \sTeams are set, let's start the game!\s\n"); - temp = self; - te = find (world, classname, "player"); - while (te != world) { - te.captain = 0; - self = te; - Menu_Close(self); - self.current_menu_type = ADMIN_MENU_TYPE_MAIN; - self.current_menu_page = 1; - te = find (te, classname, "player"); - } - self = temp; - captainmode = 0; - return; + bprint(2, "\x10\sCaptain Mode\s\x11\s:\s \sTeams are set, let's start the game!\s\n"); + temp = self; + te = find (world, classname, "player"); + while (te != world) { + te.captain = 0; + self = te; + Menu_Close(self); + self.current_menu_type = ADMIN_MENU_TYPE_MAIN; + self.current_menu_page = 1; + te = find (te, classname, "player"); + } + self = temp; + captainmode = 0; + return; } s_menu2 = strcat( s_menu2, "\n"); s_menu7 = "\b[\b8\b]\b \bPrevious Page\b "; @@ -1471,13 +1481,13 @@ void () Menu_Admin = s_menu8 = "\b[\b9\b]\b \bNext Page\b "; s_menu8 = Menu_Indent_line(s_menu8, 30); if (self.is_admin || self.captain == 1) { - s_menu9 = "\b[\b0\b]\b \bBack to Main Menu\b "; - s_menu9 = Menu_Indent_line(s_menu9, 30); + s_menu9 = "\b[\b0\b]\b \bBack to Main Menu\b "; + s_menu9 = Menu_Indent_line(s_menu9, 30); } else { - s_menu9 = "\n"; + s_menu9 = "\n"; } if ((self.is_admin || self.captain == 1) && captainmode) { - s_menu9 = strcat(s_menu9, "Option 0 results in canceling captain mode.\n"); + s_menu9 = strcat(s_menu9, "Option 0 results in canceling captain mode.\n"); } s_menu1 = strcat(s_menu1, s_menu2); @@ -1638,7 +1648,7 @@ void (float inp) Menu_Admin_Input = } } else if ((self.current_menu_type == ADMIN_MENU_TYPE_KICK || self.current_menu_type == ADMIN_MENU_TYPE_BAN || self.current_menu_type == ADMIN_MENU_TYPE_FORCESPEC) - && inp >= 1 && inp <= 7) + && inp >= 1 && inp <= 7) { // Kick / Ban Actions //bprint(PRINT_HIGH, "Getting player ", ftos(inp), "\n"); f_tmp = 1; @@ -1681,8 +1691,8 @@ void (float inp) Menu_Admin_Input = } } else if ((self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMONE - || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO - || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT) && inp >= 1 && inp <= 7) + || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINTEAMTWO + || self.current_menu_type == ADMIN_MENU_TYPE_CAPTAINSELECT) && inp >= 1 && inp <= 7) { // Captain Actions f_tmp = 1; self.admin_use = find (world, classname, "player"); diff --git a/ssqc/mvdsv.qc b/ssqc/mvdsv.qc index d77e8df5..11147cd9 100644 --- a/ssqc/mvdsv.qc +++ b/ssqc/mvdsv.qc @@ -1,12 +1,13 @@ float () UserCmd = { float isProcessed; - string arg1, arg2, arg3; + string arg1, arg2, arg3, arg4; arg1 = argv_mvdsv(0); arg2 = argv_mvdsv(1); arg3 = argv_mvdsv(2); + arg4 = argv_mvdsv(3); - isProcessed = ParseCmds(arg1, arg2, arg3); + isProcessed = ParseCmds(arg1, arg2, arg3, arg4); return (isProcessed); }; diff --git a/ssqc/progs.src b/ssqc/progs.src index c4d080b9..f588d2f7 100644 --- a/ssqc/progs.src +++ b/ssqc/progs.src @@ -24,6 +24,7 @@ time.qc ../share/classes.qc ../share/animate.qc ../share/mcp_precache.qc +../share/engineer.qc helpers.qc events.qc roles.qc diff --git a/ssqc/qw.qc b/ssqc/qw.qc index 96e73c72..566baae1 100644 --- a/ssqc/qw.qc +++ b/ssqc/qw.qc @@ -48,7 +48,7 @@ float remote_client_time(); .float cheat_check; // Time when we'll next check for team cheats .float is_removed; // TRUE if the entity has been removed .float is_undercover; // TRUE for a SPY if they're undercover -.float is_building; // TRUE for an ENGINEER if they're building something +.float is_building; // BUILD_DISPENSER, BUILD_SENTRYGUN or FALSE for an ENGINEER .float is_detpacking; // TRUE for a DEMOMAN if they're setting a detpack .float is_button_feigning; // TRUE for a SPY if they're feigning death with +feign or +special .float feign_next_damage; // TRUE for a SPY if they're going to feign death on next damage @@ -202,7 +202,7 @@ float coop; .entity real_owner; .float has_dispenser; // TRUE for an ENGINEER if he has a dispenser .float has_sentry; // TRUE for an ENGINEER if he has a sentry -.entity sentry_ent; // Contains sentry gun entity +.entity sentry_ent; // Contains sentry gun entity .float real_frags; // Used to store the players frags when TeamFrags is On diff --git a/ssqc/sentry.qc b/ssqc/sentry.qc index 78305792..c1498741 100644 --- a/ssqc/sentry.qc +++ b/ssqc/sentry.qc @@ -374,13 +374,14 @@ void () Sentry_Explode = { void () Sentry_Die = { sprint(self.real_owner, PRINT_HIGH, "Your sentry gun was destroyed\n"); stuffcmd(self.real_owner, "play misc/chink.wav\n"); - self.real_owner.has_sentry = 0; - + local entity ro = self.real_owner; + ro.has_sentry = 0; + self.tfstate = self.tfstate | TFSTATE_RESPAWN_READY; self.think = Sentry_Explode; self.nextthink = time + 0.1; - if (self.real_owner.is_building) { - self = self.real_owner; + if (ro.is_building) { + self = ro; TeamFortress_EngineerBuildStop(); } }; diff --git a/ssqc/status.qc b/ssqc/status.qc index 995cf016..26ba4705 100644 --- a/ssqc/status.qc +++ b/ssqc/status.qc @@ -757,6 +757,28 @@ string GetSBClassInfo(entity pl, float csqcactive) return st1; } +void UpdateClientBuilding(entity pl) { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; + + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_BUILDING); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + +void UpdateClient_Sentry(entity pl, entity sent) = { + if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) + return; + msg_entity = pl; + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, MSG_SENTRY_POS); + WriteFloat(MSG_MULTICAST, sent.origin.x); + WriteFloat(MSG_MULTICAST, sent.origin.y); + WriteFloat(MSG_MULTICAST, sent.origin.z); + multicast('0 0 0', MULTICAST_ONE_NOSPECS); +} + void UpdateClientReloadSound(entity pl, float weapon) { if(!infokeyf(pl, INFOKEY_P_CSQCACTIVE)) return; diff --git a/ssqc/tfort.qc b/ssqc/tfort.qc index 359b828d..121fd664 100644 --- a/ssqc/tfort.qc +++ b/ssqc/tfort.qc @@ -1250,7 +1250,7 @@ void () TeamFortress_SetEquipment = { stuffcmd(self, st); stuffcmd(self, "\n"); } - self.is_building = 0; + self.is_building = FALSE; self.is_detpacking = 0; self.airblast_cooldown = 0; self.is_undercover = 0; @@ -1963,7 +1963,7 @@ void () TeamFortress_RemoveTimers = { TeamFortress_EngineerBuildStop(); } - self.is_building = 0; + self.is_building = FALSE; self.building = world; if (self.tfstate & TFSTATE_AIMING) { self.tfstate &= ~TFSTATE_AIMING; diff --git a/ssqc/world.qc b/ssqc/world.qc index e194f42a..abe751a8 100644 --- a/ssqc/world.qc +++ b/ssqc/world.qc @@ -333,6 +333,7 @@ void () worldspawn = { clientstat(STAT_ALL_TIME, EV_FLOAT, all_time); clientstat(STAT_FLAGS, EV_FLOAT, stat_flags); clientstat(STAT_SPAWN_GEN, EV_FLOAT, spawn_gen); + clientstat(STAT_HAS_SENTRY, EV_FLOAT, has_sentry); globalstat(STAT_ROUND_END, EV_FLOAT, "round_end_time"); globalstat(STAT_PAUSED, EV_FLOAT, "cs_paused");