From 0c88896adf8512af5b3df80d4c52f7f20d5efd19 Mon Sep 17 00:00:00 2001 From: Zuhayr Date: Sun, 28 Jul 2013 05:18:04 -0700 Subject: [PATCH] Adds a vox heist game mode. Fairly complex. --- baystation12.dme | 2 +- code/game/gamemodes/game_mode.dm | 1 + code/game/gamemodes/heist/heist.dm | 250 ++++++++++++++++++ code/game/gamemodes/objective.dm | 169 ++++++++++++ code/game/machinery/computer/vox_shuttle.dm | 17 +- code/global.dm | 1 - code/modules/mob/living/carbon/human/death.dm | 8 + code/setup.dm | 6 +- 8 files changed, 446 insertions(+), 8 deletions(-) create mode 100644 code/game/gamemodes/heist/heist.dm diff --git a/baystation12.dme b/baystation12.dme index c835b5add34..6db691a79e0 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -22,7 +22,6 @@ #define FILE_DIR "icons/misc" #define FILE_DIR "icons/mob" #define FILE_DIR "icons/mob/human_races" -#define FILE_DIR "icons/NTOS" #define FILE_DIR "icons/obj" #define FILE_DIR "icons/obj/assemblies" #define FILE_DIR "icons/obj/atmospherics" @@ -249,6 +248,7 @@ #include "code\game\gamemodes\events\holidays\Holidays.dm" #include "code\game\gamemodes\events\holidays\Other.dm" #include "code\game\gamemodes\extended\extended.dm" +#include "code\game\gamemodes\heist\heist.dm" #include "code\game\gamemodes\malfunction\Malf_Modules.dm" #include "code\game\gamemodes\malfunction\malfunction.dm" #include "code\game\gamemodes\meteor\meteor.dm" diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 85fdca943e9..bb627fd3bcf 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -278,6 +278,7 @@ Implants; if(BE_REV) roletext="revolutionary" if(BE_CULTIST) roletext="cultist" if(BE_NINJA) roletext="ninja" + if(BE_RAIDER) roletext="raider" // Assemble a list of active players without jobbans. for(var/mob/new_player/player in player_list) diff --git a/code/game/gamemodes/heist/heist.dm b/code/game/gamemodes/heist/heist.dm new file mode 100644 index 00000000000..d3a2ce69d3d --- /dev/null +++ b/code/game/gamemodes/heist/heist.dm @@ -0,0 +1,250 @@ +/* +VOX HEIST ROUNDTYPE +*/ + +#define MAX_VOX_KILLS 10 //Number of kills during the round before the Inviolate is broken. + //Would be nice to use vox-specific kills but is currently not feasible. + +var/global/vox_kills = 0 //Used to check the Inviolate. + +/datum/game_mode + var/list/datum/mind/raiders = list() + +/datum/game_mode/heist + name = "heist" + config_tag = "heist" + required_players = 1 + required_players_secret = 1 + required_enemies = 1 + recommended_enemies = 1 + + var/const/waittime_l = 600 //lower bound on time before intercept arrives (in tenths of seconds) + var/const/waittime_h = 1800 //upper bound on time before intercept arrives (in tenths of seconds) + + var/list/raid_objectives = list() //Raid objectives. + +/datum/game_mode/heist/announce() + world << "The current game mode is - Heist!" + world << "An unidentified bluespace signature has slipped past the Icarus and is approaching [station_name()]!" + world << "Whoever they are, they're likely up to no good. Protect the crew and station resources against this dastardly threat!" + world << "Raiders: Loot [station_name()] for anything and everything you need." + world << "Personnel: Repel the raiders and their low, low prices and/or crossbows." + +/datum/game_mode/heist/can_start() + + if(!..()) + return 0 + + var/list/candidates = get_players_for_role(BE_OPERATIVE) + var/raider_num = 0 + + //Check that we have enough vox. + if(candidates.len < required_enemies) + return 0 + else if(candidates.len < recommended_enemies) + raider_num = candidates.len + else + raider_num = recommended_enemies + + //Grab candidates randomly until we have enough. + while(raider_num > 0) + var/datum/mind/new_raider = pick(candidates) + raiders += new_raider + candidates -= new_raider + raider_num-- + + for(var/datum/mind/raider in raiders) + raider.assigned_role = "MODE" + raider.special_role = "Vox Raider" + return 1 + +/datum/game_mode/heist/pre_setup() + return 1 + +/datum/game_mode/heist/post_setup() + + //Build a list of spawn points. + var/list/turf/raider_spawn = list() + + for(var/obj/effect/landmark/L in landmarks_list) + if(L.name == "voxstart") + raider_spawn += get_turf(L) + del(L) + continue + + //Generate objectives for the group. + raid_objectives = forge_vox_objectives() + + var/index = 1 + + //Spawn the vox! + for(var/datum/mind/raider in raiders) + + if(index > raider_spawn.len) + index = 1 + + raider.current.loc = raider_spawn[index] + index++ + + var/sounds = rand(2,8) + var/i = 0 + var/newname = "" + + while(i<=sounds) + i++ + newname += pick(list("ti","hi","ki","ya","ta","ha","ka","ya","chi","cha","kah")) + + var/mob/living/carbon/human/vox = raider.current + + vox.vox_talk_understand = 1 + vox.real_name = capitalize(newname) + vox.name = vox.real_name + vox.age = rand(12,20) + vox.dna.mutantrace = "vox" + vox.h_style = "Short Vox Quills" + vox.equip_vox_raider() + vox.regenerate_icons() + + raider.objectives = raid_objectives + greet_vox(raider) + + spawn (rand(waittime_l, waittime_h)) + send_intercept() + +/datum/game_mode/heist/declare_completion() + +/datum/game_mode/heist/proc/is_raider_crew_safe() + + for(var/datum/mind/raider in raiders) + if(raider.current) + if (get_area(raider.current) != locate(/area/shuttle/vox/station)) + return 0 + return 1 + +/datum/game_mode/heist/proc/is_raider_crew_alive() + + for(var/datum/mind/raider in raiders) + if(raider.current) + if(istype(raider.current,/mob/living/carbon/human) && raider.current.stat != 2) + return 1 + return 0 + +/datum/game_mode/heist/proc/forge_vox_objectives() + + + //Commented out for testing. + /* var/i = 1 + var/max_objectives = pick(2,2,2,3,3) + var/list/objs = list() + while(i<= max_objectives) + var/list/goals = list("kidnap","loot","salvage") + var/goal = pick(goals) + var/datum/objective/heist/O + + if(goal == "kidnap") + goals -= "kidnap" + O = new /datum/objective/heist/kidnap() + else if(goal == "loot") + O = new /datum/objective/heist/loot() + else + O = new /datum/objective/heist/salvage() + O.choose_target() + objs += O + + i++ + + //-All- vox raids have these two objectives. Failing them loses the game. + objs += new /datum/objective/heist/inviolate_crew + objs += new /datum/objective/heist/inviolate_death */ + + raid_objectives += new /datum/objective/heist/kidnap + raid_objectives += new /datum/objective/heist/loot + raid_objectives += new /datum/objective/heist/salvage + raid_objectives += new /datum/objective/heist/inviolate_crew + raid_objectives += new /datum/objective/heist/inviolate_death + + for(var/datum/objective/heist/O in raid_objectives) + O.choose_target() + + return raid_objectives + +/datum/game_mode/heist/proc/greet_vox(var/datum/mind/raider) + raider.current << "\blue You are a Vox Raider, fresh from the Shoal!" + raider.current << "\blue Don't forget to turn on your nitrogen internals." + var/obj_count = 1 + for(var/datum/objective/objective in raider.objectives) + raider.current << "Objective #[obj_count]: [objective.explanation_text]" + obj_count++ + + +/datum/game_mode/heist/declare_completion() + + //No objectives, go straight to the feedback. + if(!(raid_objectives.len)) return ..() + + var/win_type = "Major" + var/win_group = "Crew" + var/win_msg = "" + + var/success = raid_objectives.len + + //Decrease success for failed objectives. + for(var/datum/objective/O in raid_objectives) + if(!(O.check_completion())) success-- + + //Set result by objectives. + if(success == raid_objectives.len) + win_type = "Major" + win_group = "Vox" + else if(success > 2) + win_type = "Minor" + win_group = "Vox" + else + win_type = "Minor" + win_group = "Crew" + + //Now we modify that result by the state of the vox crew. + if(!is_raider_crew_alive()) + + win_type = "Major" + win_group = "Crew" + win_msg += "The Vox Raiders have been wiped out!" + + else if(!is_raider_crew_safe()) + + if(win_group == "Crew" && win_type == "Minor") + win_type = "Major" + + win_group = "Crew" + win_msg += "The Vox Raiders have left someone behind!" + + else + + if(win_group == "Vox") + if(win_type == "Minor") + + win_type = "Major" + win_msg += "The Vox Raiders escaped the station!" + else + win_msg += "The Vox Raiders were repelled!" + + world << "\red [win_type] [win_group] victory!" + world << "[win_msg]" + feedback_set_details("round_end_result","heist - [win_type] [win_group]") + + var/count = 1 + for(var/datum/objective/objective in raid_objectives) + if(objective.check_completion()) + world << "
Objective #[count]: [objective.explanation_text] Success!" + feedback_add_details("traitor_objective","[objective.type]|SUCCESS") + else + world << "
Objective #[count]: [objective.explanation_text] Fail." + feedback_add_details("traitor_objective","[objective.type]|FAIL") + count++ + + ..() + +/datum/game_mode/heist/check_finished() + if (!(is_raider_crew_alive()) || (vox_shuttle_location && (vox_shuttle_location == "start"))) + return 1 + return ..() \ No newline at end of file diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 1b3552408c5..a8c0e29947a 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -742,3 +742,172 @@ datum/objective/absorb /*-------ENDOF CULTIST------*/ */ + +//Vox heist objectives. + +datum/objective/heist + proc/choose_target() + return + +datum/objective/heist/kidnap + choose_target() + var/list/roles = list("Chief Engineer","Research Director","Roboticist","Chemist","Station Engineer") + var/list/possible_targets = list() + var/list/priority_targets = list() + + for(var/datum/mind/possible_target in ticker.minds) + if(possible_target != owner && ishuman(possible_target.current) && (possible_target.current.stat != 2) && (possible_target.assigned_role != "MODE")) + possible_targets += possible_target + for(var/role in roles) + if(possible_target.assigned_role == role) + priority_targets += possible_target + continue + + if(priority_targets.len > 0) + target = pick(priority_targets) + else if(possible_targets.len > 0) + target = pick(possible_targets) + + if(target && target.current) + explanation_text = "The Shoal has a need for [target.current.real_name], the [target.assigned_role]. Take them alive." + else + explanation_text = "Free Objective" + return target + + check_completion() + if(target && target.current) + if (target.current.stat == 2) + return 0 // They're dead. Fail. + //if (!target.current.restrained()) + // return 0 // They're loose. Close but no cigar. + + var/area/shuttle/vox/station/A = locate() + for(var/mob/living/carbon/human/M in A) + if(target.current == M) + return 1 //They're restrained on the shuttle. Success. + else + return 0 + +datum/objective/heist/loot + choose_target() + + if(pick("hardware","weapons") == "hardware") + target = pick("a complete particle accelerator","a gravitational generator","four emitters","a nuclear bomb") + else + target = pick("six guns","four energy guns","two laser guns","an ion gun") + + explanation_text = "We are lacking in hardware. Steal [target]." + + switch(target) + if("a complete particle accelerator") + target = /obj/structure/particle_accelerator + target_amount = 6 + if("a gravitational generator") + target = /obj/machinery/the_singularitygen + target_amount = 1 + if("four emitters") + target = /obj/machinery/power/emitter + target_amount = 4 + if("a nuclear bomb") + target = /obj/machinery/nuclearbomb + target_amount = 1 + if("six guns") + target = /obj/item/weapon/gun + target_amount = 6 + if("four energy guns") + target = /obj/item/weapon/gun/energy + target_amount = 4 + if("two laser guns") + target = /obj/item/weapon/gun/energy/laser + target_amount = 2 + if("an ion gun") + target = /obj/item/weapon/gun/energy/ionrifle + target_amount = 1 + + check_completion() + + var/total_amount = 0 + + for(var/obj/O in locate(/area/shuttle/vox/station)) + if(istype(O,target)) total_amount++ + if(total_amount >= target_amount) return 1 + + var/datum/game_mode/heist/H = ticker.mode + for(var/datum/mind/raider in H.raiders) + if(raider.current) + for(var/obj/O in raider.current.get_contents()) + if(istype(O,target)) total_amount++ + if(total_amount >= target_amount) return 1 + + return 0 + +datum/objective/heist/salvage + + choose_target() + var/list/possible_items = list("300 metal sheets","200 glass sheets","100 plasteel sheets","100 units of solid plasma","50 silver bars","20 gold bars","20 uranium bars","20 diamonds") + target = pick(possible_items) + explanation_text = "Ransack the station and escape with [target]." + + switch(target) + if("300 metal sheets") + target = "metal" + target_amount = 300 + if("200 glass sheets") + target = "glass" + target_amount = 200 + if("100 plasteel sheets") + target = "plasteel" + target_amount = 100 + if("100 units of solid plasma") + target = "plasma" + target_amount = 100 + if("50 silver bars") + target = "silver" + target_amount = 50 + if("20 gold bars") + target = "gold" + target_amount = 20 + if("20 uranium bars") + target = "uranium" + target_amount = 20 + if("20 diamonds") + target = "diamond" + target_amount = 20 + + + check_completion() + + var/total_amount = 0 + + for(var/obj/item/O in locate(/area/shuttle/vox/station)) + if(istype(O,/obj/item/stack/sheet)) + if(O.name == target) + var/obj/item/stack/sheet/S = O + total_amount += S.amount + + var/datum/game_mode/heist/H = ticker.mode + for(var/datum/mind/raider in H.raiders) + if(raider.current) + for(var/obj/item/O in raider.current.get_contents()) + if(istype(O,/obj/item/stack/sheet)) + if(O.name == target) + var/obj/item/stack/sheet/S = O + total_amount += S.amount + + if(total_amount >= target_amount) return 1 + return 0 + + +datum/objective/heist/inviolate_crew + explanation_text = "Do not leave any Vox behind, alive or dead." + + check_completion() + var/datum/game_mode/heist/H = ticker.mode + if(H.is_raider_crew_safe()) return 1 + return 0 + +datum/objective/heist/inviolate_death + explanation_text = "Follow the Inviolate. Minimise death and loss of resources." + check_completion() + if(vox_kills>5) return 0 + return 1 \ No newline at end of file diff --git a/code/game/machinery/computer/vox_shuttle.dm b/code/game/machinery/computer/vox_shuttle.dm index 59513acd0b4..fa9d05d7b90 100644 --- a/code/game/machinery/computer/vox_shuttle.dm +++ b/code/game/machinery/computer/vox_shuttle.dm @@ -1,7 +1,8 @@ -#define VOX_SHUTTLE_MOVE_TIME 60 -#define VOX_SHUTTLE_COOLDOWN 200 +#define VOX_SHUTTLE_MOVE_TIME 260 +#define VOX_SHUTTLE_COOLDOWN 460 //Copied from Syndicate shuttle. +var/global/vox_shuttle_location /obj/machinery/computer/vox_station name = "vox skipjack terminal" @@ -11,7 +12,7 @@ var/area/curr_location var/moving = 0 var/lastMove = 0 - + var/warning //Warning about the end of the round. /obj/machinery/computer/vox_station/New() curr_location= locate(/area/shuttle/vox/station) @@ -35,6 +36,7 @@ curr_location.move_contents_to(dest_location) curr_location = dest_location moving = 0 + return 1 @@ -56,7 +58,7 @@ var/dat = {"Location: [curr_location]
Ready to move[max(lastMove + VOX_SHUTTLE_COOLDOWN - world.time, 0) ? " in [max(round((lastMove + VOX_SHUTTLE_COOLDOWN - world.time) * 0.1), 0)] seconds" : ": now"]
- Dark space
+ Return to dark space
Fore port solar | Aft port solar | Fore starboard solar
@@ -76,8 +78,15 @@ if(in_range(src, user) || istype(user, /mob/living/silicon)) user.set_machine(src) + vox_shuttle_location = "station" if(href_list["start"]) + if(ticker && (istype(ticker.mode,/datum/game_mode/heist))) + if(!warning) + user << "\red Returning to dark space will end your raid and report your success or failure. If you are sure, press the button again." + warning = 1 + return vox_move_to(/area/shuttle/vox/station) + vox_shuttle_location = "start" else if(href_list["solars_fore_starboard"]) vox_move_to(/area/vox_station/northeast_solars) else if(href_list["solars_fore_port"]) diff --git a/code/global.dm b/code/global.dm index ce0fa371e32..348cc8702fa 100644 --- a/code/global.dm +++ b/code/global.dm @@ -134,7 +134,6 @@ var/list/prisonsecuritywarp = list() //prison security goes to these var/list/prisonwarped = list() //list of players already warped var/list/blobstart = list() var/list/ninjastart = list() -var/list/voxstart = list() // list/traitors = list() //traitor list var/list/cardinal = list( NORTH, SOUTH, EAST, WEST ) var/list/alldirs = list(NORTH, SOUTH, EAST, WEST, NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST) diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index 4c61f2e60b0..90617f3019f 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -54,6 +54,14 @@ dizziness = 0 jitteriness = 0 + //Check for heist mode kill count. + if(ticker.mode && ( istype( ticker.mode,/datum/game_mode/heist) ) ) + //Check for last assailant's mutantrace. + /*if( LAssailant && ( istype( LAssailant,/mob/living/carbon/human ) ) ) + var/mob/living/carbon/human/V = LAssailant + if (V.dna && (V.dna.mutantrace == "vox"))*/ //Not currently feasible due to terrible LAssailant tracking. + vox_kills++ //Bad vox. Shouldn't be killing humans. + if(!gibbed) emote("deathgasp") //let the world KNOW WE ARE DEAD diff --git a/code/setup.dm b/code/setup.dm index 8afcbe689a5..6759a91e0eb 100644 --- a/code/setup.dm +++ b/code/setup.dm @@ -640,6 +640,7 @@ var/list/TAGGERLOCATIONS = list("Disposals", #define BE_CULTIST 256 #define BE_MONKEY 512 #define BE_NINJA 1024 +#define BE_RAIDER 2048 var/list/be_special_flags = list( "Traitor" = BE_TRAITOR, @@ -652,7 +653,8 @@ var/list/be_special_flags = list( "pAI" = BE_PAI, "Cultist" = BE_CULTIST, "Monkey" = BE_MONKEY, - "Ninja" = BE_NINJA + "Ninja" = BE_NINJA, + "Raider" = BE_RAIDER ) #define AGE_MIN 17 //youngest a character can be @@ -693,4 +695,4 @@ var/list/bradycardics = list("neurotoxin", "cryoxadone", "clonexadone", "space_d //proc/get_pulse methods #define GETPULSE_HAND 0 //less accurate (hand) -#define GETPULSE_TOOL 1 //more accurate (med scanner, sleeper, etc) +#define GETPULSE_TOOL 1 //more accurate (med scanner, sleeper, etc)