diff --git a/source/server/ai/ai_core.qc b/source/server/ai/ai_core.qc index 5767ee8..207a640 100644 --- a/source/server/ai/ai_core.qc +++ b/source/server/ai/ai_core.qc @@ -403,7 +403,7 @@ void(float dist) Window_Walk = ChangeYaw(); return; } - if(self.goalentity.health > 0) + if(self.goalentity.health > 0 && !self.goalentity.owner) { self.reload_delay = time + 30; self.th_melee(); @@ -412,9 +412,12 @@ void(float dist) Window_Walk = else self.chase_time = time + 0.75; return; + } else if (self.goalentity.owner) { + self.chase_time = time + 0.15; + return; } } - if(self.goalentity.health <= 0) + if(self.goalentity.health <= 0 && !self.goalentity.owner) { self.outside = 2; self.chase_time = 0; @@ -486,8 +489,10 @@ void(float dist) Window_Hop = self.chase_time = time + 0.2; if(self.tries > 10) { // wait enough time before freeing window, to give time for zomb to move. - self.goalentity.think = free_window; - self.goalentity.nextthink = time + 0.5; + if (!self.goalentity.owner) { + self.goalentity.think = free_window; + self.goalentity.nextthink = time + 0.5; + } //self.goalentity.usedent = world;//free up the window if we've been waiting to hop } } @@ -497,8 +502,10 @@ void(float dist) Window_Hop = self.outside = FALSE; //self.goalentity.usedent = world;//free up the window, we're done hopping it //self.used = 0; - self.goalentity.think = free_window; - self.goalentity.nextthink = time + 0.5; + if (!self.goalentity.owner) { + self.goalentity.think = free_window; + self.goalentity.nextthink = time + 0.5; + } self.goalentity = world; self.enemy = find_new_enemy(self); //self.th_die(); diff --git a/source/server/defs/custom.qc b/source/server/defs/custom.qc index c445d5f..b592276 100644 --- a/source/server/defs/custom.qc +++ b/source/server/defs/custom.qc @@ -448,6 +448,7 @@ float total_windows_down; float total_powerup_points; float powerup_score_threshold; float powerup_activate; +float carp_powerup_active; float nuke_powerup_active; float nuke_powerups_activated; float nuke_powerup_spawndelay; diff --git a/source/server/entities/powerups.qc b/source/server/entities/powerups.qc index 94494b5..f933993 100644 --- a/source/server/entities/powerups.qc +++ b/source/server/entities/powerups.qc @@ -376,39 +376,134 @@ void() PU_DoublePoints = other.x2_icon = true; }; +// +// PU_CarpenterFinalize +// Remove the Carpenter Watcher and +// rewards Players with Score. +// +void() PU_CarpenterFinalize = +{ + entity players = find(world, classname, "player"); + + // Reward Players with Points + while(players) { + addmoney(players, 200, 1); + + players = find(players, classname, "player"); + } + + entity windows = find(world, classname, "window"); + + // Reset all windows + while(windows) { + windows.isspec = 0; + windows.box1owner = world; + windows.usedent = world; + windows.owner = world; + windows.ads_release = 0; + + windows = find(windows, classname, "window"); + } + + carp_powerup_active = false; + + // Free ourselves + PU_FreeEnt(self); +}; + +// +// PU_CarpenterFindWindow +// Finds a Barricade elligible for Repair +// +entity() PU_CarpenterFindWindow = +{ + entity windows = find(world, classname, "window"); + + while(windows != world) { + // Window needs repaired and is repairable + if (windows.health < 6 && windows.health != -10 && !windows.isspec + && !windows.ads_release) + return windows; + + windows = find(windows, classname, "window"); + } + + // No Windows are elligible, return world. + return world; +}; + +// +// PU_CarpenterRepair() +// Attempts to Repair a Barricade +// +void() PU_CarpenterRepair = +{ + // Find a new Barricade to Repair + if (self.goaldummy == world || self.goaldummy.isspec == 0) { + + if (self.goaldummy != world) + self.goaldummy.owner = world; + + self.goaldummy = PU_CarpenterFindWindow(); + self.kills = false; + + // Didn't find one, so end the Carpenter sequence. + if (self.goaldummy == world) { + self.think = PU_CarpenterFinalize; + self.nextthink = time + 0.1; + return; + } + + // Mark the window as being Repaired + self.goaldummy.isspec = 1; + self.goaldummy.ads_release = 1; + self.goaldummy.owner = self; + } + // Repair our current Barricade + else if (!self.kills) { + // Trigger the animation + entity tempe = self; + self = self.goaldummy; + switch(self.health) { + case 5: window_carpenter_11(); break; + case 4: window_carpenter_9(); break; + case 3: window_carpenter_7(); break; + case 2: window_carpenter_5(); break; + case 1: window_carpenter_3(); break; + default: window_carpenter_1(); break; + } + self.health = 6; + self = tempe; + + // We're actively building + self.kills = true; + self.ltime = time + 2.1; + } else { + if (self.ltime < time) { + self.goaldummy.frame = 88; + self.goaldummy.isspec = 0; + self.goaldummy.health = 6; + } + } + + self.nextthink = time + 0.05; +}; + // // PU_Carpenter() // Carpenter Power-Up Function // void() PU_Carpenter = { - entity tempe; - entity tempe2; - tempe2 = self; + // create our watcher entity + entity carp_watcher; + carp_watcher = PU_GetFreeEnt(); + carp_watcher.classname = "pu_carpwatcher"; - tempe = find(world, classname, "window"); + carp_watcher.think = PU_CarpenterRepair; + carp_watcher.nextthink = time + 0.05; - // Repair Barricades - while(tempe != world) { - // Target non-full and board-able Barricades - if (tempe.health < 6 && tempe.health != -10) { - self = tempe; - window_carpenter_1(); - self.health = 6; - self = tempe2; - } - - tempe = find(tempe, classname, "window"); - } - - tempe = find(world, classname, "player"); - - // Reward Players with Points - while(tempe) { - addmoney(tempe, 200, 1); - - tempe = find(tempe, classname, "player"); - } + carp_powerup_active = true; }; // diff --git a/source/server/entities/window.qc b/source/server/entities/window.qc index 9a4f1b0..d0747d7 100644 --- a/source/server/entities/window.qc +++ b/source/server/entities/window.qc @@ -235,12 +235,12 @@ void() window_carpenter_8 =[ 8, window_carpenter_9 ] {self.frame = 72;}; void() window_carpenter_9 =[ 7, window_carpenter_10 ] {self.frame = 79;sound(self, 1, self.oldmodel, 1, ATTN_NORM);}; void() window_carpenter_10 =[ 8, window_carpenter_11 ] {self.frame = 80;}; void() window_carpenter_11 =[ 7, window_carpenter_12 ] {self.frame = 87;sound(self, 2, self.oldmodel, 1, ATTN_NORM);}; -void() window_carpenter_12 =[ 8, SUB_Null ] {self.frame = 88;}; +void() window_carpenter_12 =[ 8, SUB_Null ] {self.frame = 88;self.isspec = 0;}; void() Window_Damage = { - if(self.health == 0) + if(self.health == 0 || self.owner) return; sound(self, CHAN_VOICE, self.aistatus, 1, ATTN_NORM); @@ -315,6 +315,9 @@ void() Rebuild_Anims = }; void() window_touch = { + if (self.owner) + return; + if(other.classname == "player" && !other.downed && self.health != -10) { if(self.health < 6) diff --git a/source/server/utilities/command_parser.qc b/source/server/utilities/command_parser.qc index e1952b9..b56ea12 100644 --- a/source/server/utilities/command_parser.qc +++ b/source/server/utilities/command_parser.qc @@ -27,6 +27,8 @@ */ +void(vector where, float type) Spawn_Powerup; + // Whether the command prohibits client-sending. float client_parse_override; @@ -131,6 +133,28 @@ float(string params) Command_noclip = return COMMAND_SUCCESS; } +// +// Command_powerup() +// Spawns a Power-Up of a given ID in front of you. +// +float(string params) Command_powerup = +{ + // Anti-Cheat in Co-Op. + if (coop && cheats_have_been_activated == false) { + bprint(PRINT_HIGH, "Someone tried to issue spawn_pu in a Co-Op match. Nice try!\n"); + return COMMAND_FAILURE; + } + + // Grab parameters. + tokenize(params); + float value = stof(argv(0)); + + makevectors(self.angles); + Spawn_Powerup(self.origin + v_forward * 50, value); + + return COMMAND_SUCCESS; +}; + // // Command_tracedmgmultiplier() // Multiplies damage output with weapons that fire Traces. @@ -176,7 +200,8 @@ var struct { {"qc_soft_restart", Command_softrestart, false, "Executes the Soft_Restart QuakeC function. Useful for debugging its functionality.\n"}, {"god", Command_godmode, false, "Toggles God Mode.\n"}, {"noclip", Command_noclip, false, "Toggles No Clip.\n"}, - {"sv_tracedmgmultiplier", Command_tracedmgmultiplier, true, "Multiplies damage output with weapons that fire Traces.\n"} + {"sv_tracedmgmultiplier", Command_tracedmgmultiplier, true, "Multiplies damage output with weapons that fire Traces.\n"}, + {"spawn_pu", Command_powerup, true, "Spawns a Power-Up of a given ID in front of you. -1 for random.\n"} }; //