Merge pull request #10649 from kevinz000/hijack
Completely reworks the hijack objective, and shuttle hijacking in general
This commit is contained in:
@@ -782,3 +782,19 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
|
||||
|
||||
#define is_alpha(X) ((text2ascii(X) <= 122) && (text2ascii(X) >= 97))
|
||||
#define is_digit(X) ((length(X) == 1) && (length(text2num(X)) == 1))
|
||||
|
||||
/// Slightly expensive proc to scramble a message using equal probabilities of character replacement from a list. DOES NOT SUPPORT HTML!
|
||||
/proc/scramble_message_replace_chars(original, replaceprob = 25, list/replacementchars = list("$", "@", "!", "#", "%", "^", "&", "*"), replace_letters_only = FALSE, replace_whitespace = FALSE)
|
||||
var/list/out = list()
|
||||
var/static/list/whitespace = list(" ", "\n", "\t")
|
||||
for(var/i in 1 to length(original))
|
||||
var/char = original[i]
|
||||
if(!replace_whitespace && (char in whitespace))
|
||||
out += char
|
||||
continue
|
||||
if(replace_letters_only && (!ISINRANGE(char, 65, 90) && !ISINRANGE(char, 97, 122)))
|
||||
out += char
|
||||
continue
|
||||
out += prob(replaceprob)? pick(replacementchars) : char
|
||||
return out.Join("")
|
||||
|
||||
|
||||
+5
-1
@@ -61,7 +61,6 @@
|
||||
var/late_joiner = FALSE
|
||||
|
||||
var/force_escaped = FALSE // Set by Into The Sunset command of the shuttle manipulator
|
||||
|
||||
var/list/learned_recipes //List of learned recipe TYPES.
|
||||
|
||||
/datum/mind/New(var/key)
|
||||
@@ -715,6 +714,11 @@
|
||||
if(G)
|
||||
G.reenter_corpse()
|
||||
|
||||
/// Sets our can_hijack to the fastest speed our antag datums allow.
|
||||
/datum/mind/proc/get_hijack_speed()
|
||||
. = 0
|
||||
for(var/datum/antagonist/A in antag_datums)
|
||||
. = max(., A.hijack_speed())
|
||||
|
||||
/datum/mind/proc/has_objective(objective_type)
|
||||
for(var/datum/antagonist/A in antag_datums)
|
||||
|
||||
@@ -314,9 +314,11 @@ GLOBAL_LIST_EMPTY(objectives)
|
||||
|
||||
/datum/objective/hijack
|
||||
name = "hijack"
|
||||
explanation_text = "Hijack the shuttle to ensure no loyalist Nanotrasen crew escape alive and out of custody."
|
||||
team_explanation_text = "Hijack the shuttle to ensure no loyalist Nanotrasen crew escape alive and out of custody. Leave no team member behind."
|
||||
explanation_text = "Hijack the emergency shuttle by hacking its navigational protocols through the control console (alt click emergency shuttle console)."
|
||||
team_explanation_text = "Hijack the emergency shuttle by hacking its navigational protocols through the control console (alt click emergency shuttle console). Leave no team member behind."
|
||||
martyr_compatible = 0 //Technically you won't get both anyway.
|
||||
/// Overrides the hijack speed of any antagonist datum it is on ONLY, no other datums are impacted.
|
||||
var/hijack_speed_override = 1
|
||||
|
||||
/datum/objective/hijack/check_completion() // Requires all owners to escape.
|
||||
if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME)
|
||||
|
||||
@@ -14,7 +14,8 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
var/list/objectives = list()
|
||||
var/antag_memory = ""//These will be removed with antag datum
|
||||
var/antag_moodlet //typepath of moodlet that the mob will gain with their status
|
||||
var/can_hijack = HIJACK_NEUTRAL //If these antags are alone on shuttle hijack happens.
|
||||
/// If above 0, this is the multiplier for the speed at which we hijack the shuttle. Do not directly read, use hijack_speed().
|
||||
var/hijack_speed = 0
|
||||
|
||||
//Antag panel properties
|
||||
var/show_in_antagpanel = TRUE //This will hide adding this antag type in antag panel, use only for internal subtypes that shouldn't be added directly but still show if possessed by mind
|
||||
@@ -229,6 +230,13 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
return
|
||||
antag_memory = new_memo
|
||||
|
||||
/// Gets how fast we can hijack the shuttle, return 0 for can not hijack. Defaults to hijack_speed var, override for custom stuff like buffing hijack speed for hijack objectives or something.
|
||||
/datum/antagonist/proc/hijack_speed()
|
||||
var/datum/objective/hijack/H = locate() in objectives
|
||||
if(!isnull(H?.hijack_speed_override))
|
||||
return H.hijack_speed_override
|
||||
return hijack_speed
|
||||
|
||||
//This one is created by admin tools for custom objectives
|
||||
/datum/antagonist/custom
|
||||
antagpanel_category = "Custom"
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
var/special_role = ROLE_BROTHER
|
||||
var/datum/team/brother_team/team
|
||||
antag_moodlet = /datum/mood_event/focused
|
||||
can_hijack = HIJACK_HIJACKER
|
||||
|
||||
/datum/antagonist/brother/create_team(datum/team/brother_team/new_team)
|
||||
if(!new_team)
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
var/list/name_source
|
||||
show_in_antagpanel = FALSE
|
||||
antag_moodlet = /datum/mood_event/focused
|
||||
can_hijack = HIJACK_PREVENT
|
||||
|
||||
/datum/antagonist/ert/on_gain()
|
||||
update_name()
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
var/obj/item/claymore/highlander/sword
|
||||
show_in_antagpanel = FALSE
|
||||
show_name_in_check_antagonists = TRUE
|
||||
can_hijack = HIJACK_HIJACKER
|
||||
hijack_speed = 2 //if you kill everyone and actually haev a hand to hijack with, you win??
|
||||
|
||||
/datum/antagonist/highlander/apply_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/L = owner.current || mob_override
|
||||
|
||||
@@ -8,11 +8,6 @@
|
||||
var/give_objectives = TRUE
|
||||
var/give_equipment = TRUE
|
||||
|
||||
/datum/antagonist/ninja/New()
|
||||
if(helping_station)
|
||||
can_hijack = HIJACK_PREVENT
|
||||
. = ..()
|
||||
|
||||
/datum/antagonist/ninja/apply_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/M = mob_override || owner.current
|
||||
update_ninja_icons_added(M)
|
||||
@@ -135,8 +130,6 @@
|
||||
adj = "objectiveless"
|
||||
else
|
||||
return
|
||||
if(helping_station)
|
||||
can_hijack = HIJACK_PREVENT
|
||||
new_owner.assigned_role = ROLE_NINJA
|
||||
new_owner.special_role = ROLE_NINJA
|
||||
new_owner.add_antag_datum(src)
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
var/always_new_team = FALSE //If not assigned a team by default ops will try to join existing ones, set this to TRUE to always create new team.
|
||||
var/send_to_spawnpoint = TRUE //Should the user be moved to default spawnpoint.
|
||||
var/nukeop_outfit = /datum/outfit/syndicate
|
||||
can_hijack = HIJACK_HIJACKER //Alternative way to wipe out the station.
|
||||
|
||||
/datum/antagonist/nukeop/proc/update_synd_icons_added(mob/living/M)
|
||||
var/datum/atom_hud/antag/opshud = GLOB.huds[ANTAG_HUD_OPS]
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
show_in_antagpanel = FALSE
|
||||
var/datum/objective/mission
|
||||
var/datum/team/ert/ert_team
|
||||
can_hijack = HIJACK_PREVENT
|
||||
|
||||
/datum/antagonist/official/greet()
|
||||
to_chat(owner, "<B><font size=3 color=red>You are a CentCom Official.</font></B>")
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
var/should_give_codewords = TRUE
|
||||
var/should_equip = TRUE
|
||||
var/traitor_kind = TRAITOR_HUMAN //Set on initial assignment
|
||||
can_hijack = HIJACK_HIJACKER
|
||||
hijack_speed = 0.5 //10 seconds per hijack stage by default
|
||||
|
||||
/datum/antagonist/traitor/on_gain()
|
||||
if(owner.current && isAI(owner.current))
|
||||
@@ -60,6 +60,7 @@
|
||||
message = GLOB.syndicate_code_response_regex.Replace(message, "<span class='red'>$1</span>")
|
||||
hearing_args[HEARING_RAW_MESSAGE] = message
|
||||
|
||||
// needs to be refactored to base /datum/antagonist sometime..
|
||||
/datum/antagonist/traitor/proc/add_objective(datum/objective/O)
|
||||
objectives += O
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
name = "Wishgranter Avatar"
|
||||
show_in_antagpanel = FALSE
|
||||
show_name_in_check_antagonists = TRUE
|
||||
can_hijack = HIJACK_HIJACKER
|
||||
|
||||
/datum/antagonist/wishgranter/proc/forge_objectives()
|
||||
var/datum/objective/hijack/hijack = new
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
var/move_to_lair = TRUE
|
||||
var/outfit_type = /datum/outfit/wizard
|
||||
var/wiz_age = WIZARD_AGE_MIN /* Wizards by nature cannot be too young. */
|
||||
can_hijack = HIJACK_HIJACKER
|
||||
|
||||
/datum/antagonist/wizard/on_gain()
|
||||
register()
|
||||
|
||||
@@ -3,13 +3,38 @@
|
||||
#define ENGINES_STARTED (SSshuttle.emergency.mode == SHUTTLE_IGNITING)
|
||||
#define IS_DOCKED (SSshuttle.emergency.mode == SHUTTLE_DOCKED || (ENGINES_STARTED))
|
||||
|
||||
#define NOT_BEGUN 0
|
||||
#define STAGE_1 1
|
||||
#define STAGE_2 2
|
||||
#define STAGE_3 3
|
||||
#define STAGE_4 4
|
||||
#define HIJACKED 5
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle
|
||||
name = "emergency shuttle console"
|
||||
desc = "For shuttle control."
|
||||
icon_screen = "shuttle"
|
||||
icon_keyboard = "tech_key"
|
||||
resistance_flags = INDESTRUCTIBLE
|
||||
var/auth_need = 3
|
||||
var/list/authorized = list()
|
||||
var/hijack_last_stage_increase = 0
|
||||
var/hijack_stage_time = 50
|
||||
var/hijack_stage_cooldown = 50
|
||||
var/hijack_flight_time_increase = 300
|
||||
var/hijack_completion_flight_time_set = 100 //How long in deciseconds to set shuttle's timer after hijack is done.
|
||||
var/hijack_hacking = FALSE
|
||||
var/hijack_announce = TRUE
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle/examine(mob/user)
|
||||
. = ..()
|
||||
if(hijack_announce)
|
||||
. += "<span class='danger'>Security systems present on console. Any unauthorized tampering will result in an emergency announcement.</span>"
|
||||
if(user?.mind?.get_hijack_speed())
|
||||
. += "<span class='danger'>Alt click on this to attempt to hijack the shuttle. This will take multiple tries (current: stage [SSshuttle.emergency.hijack_status]/[HIJACKED]).</span>"
|
||||
. += "<span class='notice'>It will take you [(hijack_stage_time * user.mind.get_hijack_speed()) / 10] seconds to reprogram a stage of the shuttle's navigational firmware, and the console will undergo automated timed lockout for [hijack_stage_cooldown/10] seconds after each stage.</span>"
|
||||
if(hijack_announce)
|
||||
. += "<span class='warning'>It is probably best to fortify your position as to be uninterrupted during the attempt, given the automatic announcements..</span>"
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle/attackby(obj/item/I, mob/user,params)
|
||||
if(istype(I, /obj/item/card/id))
|
||||
@@ -133,6 +158,71 @@
|
||||
[TIME_LEFT] seconds", system_error, alert=TRUE)
|
||||
. = TRUE
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle/proc/increase_hijack_stage()
|
||||
var/obj/docking_port/mobile/emergency/shuttle = SSshuttle.emergency
|
||||
shuttle.hijack_status++
|
||||
if(hijack_announce)
|
||||
announce_hijack_stage()
|
||||
hijack_last_stage_increase = world.time
|
||||
say("Navigational protocol error! Rebooting systems.")
|
||||
if(shuttle.mode == SHUTTLE_ESCAPE)
|
||||
if(shuttle.hijack_status == HIJACKED)
|
||||
shuttle.setTimer(hijack_completion_flight_time_set)
|
||||
else
|
||||
shuttle.setTimer(shuttle.timeLeft(1) + hijack_flight_time_increase) //give the guy more time to hijack if it's already in flight.
|
||||
return shuttle.hijack_status
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle/AltClick(user)
|
||||
attempt_hijack_stage(user)
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle/proc/attempt_hijack_stage(mob/living/user)
|
||||
if(!user.CanReach(src))
|
||||
return
|
||||
if(!user?.mind?.get_hijack_speed())
|
||||
to_chat(user, "<span class='warning'>You manage to open a user-mode shell on [src], and hundreds of lines of debugging output fly through your vision. It is probably best to leave this alone.</span.")
|
||||
return
|
||||
if(hijack_hacking == TRUE)
|
||||
return
|
||||
if(SSshuttle.emergency.hijack_status >= HIJACKED)
|
||||
to_chat(user, "<span class='warning'>The emergency shuttle is already loaded with a corrupt navigational payload. What more do you want from it?</span>")
|
||||
return
|
||||
if(hijack_last_stage_increase >= world.time + hijack_stage_cooldown)
|
||||
say("Error - Catastrophic software error detected. Input is currently on timeout.")
|
||||
return
|
||||
hijack_hacking = TRUE
|
||||
to_chat(user, "<span class='boldwarning'>You [SSshuttle.emergency.hijack_status == NOT_BEGUN? "begin" : "continue"] to override [src]'s navigational protocols.</span>")
|
||||
say("Software override initiated.")
|
||||
. = FALSE
|
||||
if(do_after(user, hijack_stage_time * (1 / user.mind.get_hijack_speed()), target = src))
|
||||
increase_hijack_stage()
|
||||
. = TRUE
|
||||
to_chat(user, "<span class='notice'>You reprogram some of [src]'s programming, putting it on timeout for [hijack_stage_cooldown/10] seconds.</span>")
|
||||
hijack_hacking = FALSE
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle/proc/announce_hijack_stage()
|
||||
var/msg
|
||||
switch(SSshuttle.emergency.hijack_status)
|
||||
if(NOT_BEGUN)
|
||||
return
|
||||
if(STAGE_1)
|
||||
var/datum/species/S = new
|
||||
msg = "AUTHENTICATING - FAIL. AUTHENTICATING - FAIL. AUTHENTICATING - FAI###### Welcome, technician JOHN DOE."
|
||||
qdel(S)
|
||||
if(STAGE_2)
|
||||
msg = "Warning: Navigational route fails \"IS_AUTHORIZED\". Please try againNN[scramble_message_replace_chars("againagainagainagainagain", 70)]."
|
||||
if(STAGE_3)
|
||||
var/hex = ""
|
||||
for(var/i in 1 to 8)
|
||||
hex += num2hex(rand(1,16))
|
||||
msg = "CRC mismatch at 0x[hex] in calculated route buffer. Full reset initiated of FTL_NAVIGATION_SERVICES. Memory decrypted for automatic repair."
|
||||
if(STAGE_4)
|
||||
msg = "~ACS_directive module_load(cyberdyne.exploit.nanotrasen.shuttlenav)... NT key mismatch. Confirm load? Y...###Reboot complete. $SET transponder_state = 0; System link initiated with connected engines..."
|
||||
if(HIJACKED)
|
||||
msg = "<font color='red'>SYSTEM OVERRIDE - Resetting course to \[[scramble_message_replace_chars("###########", 100)]\] \
|
||||
([scramble_message_replace_chars("#######", 100)]/[scramble_message_replace_chars("#######", 100)]/[scramble_message_replace_chars("#######", 100)]) \
|
||||
{AUTH - ROOT (uid: 0)}.</font>[SSshuttle.emergency.mode == SHUTTLE_ESCAPE? "Diverting from existing route - Bluespace exit in [hijack_completion_flight_time_set/10] seconds." : ""]"
|
||||
minor_announce(scramble_message_replace_chars(msg, replaceprob = 10), "Emergency Shuttle", TRUE)
|
||||
|
||||
/obj/machinery/computer/emergency_shuttle/emag_act(mob/user)
|
||||
. = ..()
|
||||
|
||||
@@ -185,6 +275,7 @@
|
||||
dir = EAST
|
||||
port_direction = WEST
|
||||
var/sound_played = 0 //If the launch sound has been sent to all players on the shuttle itself
|
||||
var/hijack_status = NOT_BEGUN
|
||||
|
||||
/obj/docking_port/mobile/emergency/canDock(obj/docking_port/stationary/S)
|
||||
return SHUTTLE_CAN_DOCK //If the emergency shuttle can't move, the whole game breaks, so it will force itself to land even if it has to crush a few departments in the process
|
||||
@@ -250,37 +341,7 @@
|
||||
priority_announce("The emergency shuttle has been recalled.[SSshuttle.emergencyLastCallLoc ? " Recall signal traced. Results can be viewed on any communications console." : "" ]", null, "shuttlerecalled", "Priority")
|
||||
|
||||
/obj/docking_port/mobile/emergency/proc/is_hijacked()
|
||||
var/has_people = FALSE
|
||||
var/hijacker_present = FALSE
|
||||
for(var/mob/living/player in GLOB.player_list)
|
||||
if(player.mind)
|
||||
if(player.stat != DEAD)
|
||||
if(issilicon(player)) //Borgs are technically dead anyways
|
||||
continue
|
||||
if(isanimal(player)) //animals don't count
|
||||
continue
|
||||
if(isbrain(player)) //also technically dead
|
||||
continue
|
||||
if(shuttle_areas[get_area(player)])
|
||||
has_people = TRUE
|
||||
var/location = get_turf(player.mind.current)
|
||||
//Non-antag present. Can't hijack.
|
||||
if(!(player.mind.has_antag_datum(/datum/antagonist)) && !istype(location, /turf/open/floor/plasteel/shuttle/red) && !istype(location, /turf/open/floor/mineral/plastitanium/red/brig))
|
||||
return FALSE
|
||||
//Antag present, doesn't stop but let's see if we actually want to hijack
|
||||
var/prevent = FALSE
|
||||
for(var/datum/antagonist/A in player.mind.antag_datums)
|
||||
if(A.can_hijack == HIJACK_HIJACKER)
|
||||
hijacker_present = TRUE
|
||||
prevent = FALSE
|
||||
break //If we have both prevent and hijacker antags assume we want to hijack.
|
||||
else if(A.can_hijack == HIJACK_PREVENT)
|
||||
prevent = TRUE
|
||||
if(prevent)
|
||||
return FALSE
|
||||
|
||||
|
||||
return has_people && hijacker_present
|
||||
return hijack_status == HIJACKED
|
||||
|
||||
/obj/docking_port/mobile/emergency/proc/ShuttleDBStuff()
|
||||
set waitfor = FALSE
|
||||
@@ -422,7 +483,7 @@
|
||||
mode = SHUTTLE_ESCAPE
|
||||
launch_status = ENDGAME_LAUNCHED
|
||||
setTimer(SSshuttle.emergencyEscapeTime)
|
||||
priority_announce("The Emergency Shuttle preparing for direct jump. Estimate [timeLeft(600)] minutes until the shuttle docks at Central Command.", null, null, "Priority")
|
||||
priority_announce("The Emergency Shuttle is preparing for direct jump. Estimate [timeLeft(600)] minutes until the shuttle docks at Central Command.", null, null, "Priority")
|
||||
|
||||
|
||||
/obj/docking_port/mobile/pod
|
||||
@@ -567,3 +628,10 @@
|
||||
#undef ENGINES_START_TIME
|
||||
#undef ENGINES_STARTED
|
||||
#undef IS_DOCKED
|
||||
|
||||
#undef NOT_BEGUN
|
||||
#undef STAGE_1
|
||||
#undef STAGE_2
|
||||
#undef STAGE_3
|
||||
#undef STAGE_4
|
||||
#undef HIJACKED
|
||||
|
||||
Reference in New Issue
Block a user