Merge pull request #31947 from AnturK/yarr

How does this work:
Station receives a communication extorting current cargo point, if they answer yes the points are just gone and nothing of interest happens.

If station refuses to pay or is silent for 3 minutes, pirate shuttle spawns somewhere in space.

    There's an internal GPS onboard so crew will always be able to follow the shuttle.
    Crew of 3, moderately armed. (Balance pending)
    Shuttle engines have 3 minute cooldown between jumps.
    Special shuttle equipment will block cargo and emergency shuttles from leaving and slowly steal the points.
This commit is contained in:
oranges
2017-11-13 22:18:37 +13:00
committed by CitadelStationBot
parent 3ea8808201
commit 43113cd9b5
24 changed files with 3029 additions and 37 deletions
+14
View File
@@ -607,6 +607,20 @@
dat += "<td><A href='?priv_msg=[blob.key]'>PM</A></td></tr>"
dat += "</table>"
var/list/pirates = get_antagonists(/datum/antagonist/pirate)
if(pirates.len > 0)
dat += "<br><table cellspacing=5><tr><td><B>Pirates</B></td><td></td></tr>"
for(var/datum/mind/N in pirates)
var/mob/M = N.current
if(!M)
dat += "<tr><td><a href='?_src_=vars;[HrefToken()];Vars=\ref[N]'>[N.name]([N.key])</a><i>No body.</i></td>"
dat += "<td><A href='?priv_msg=[N.key]'>PM</A></td></tr>"
else
dat += "<tr><td><a href='?_src_=holder;[HrefToken()];adminplayeropts=\ref[M]'>[M.real_name]</a>[M.client ? "" : " <i>(No Client)</i>"][M.stat == DEAD ? " <b><font color=red>(DEAD)</font></b>" : ""]</td>"
dat += "<td><A href='?priv_msg=[M.ckey]'>PM</A></td>"
dat += "<td><A href='?_src_=holder;[HrefToken()];adminplayerobservefollow=\ref[M]'>FLW</a></td></tr>"
dat += "</table>"
if(istype(SSticker.mode, /datum/game_mode/monkey))
var/datum/game_mode/monkey/mode = SSticker.mode
+5 -4
View File
@@ -4,6 +4,8 @@
/obj/effect/mob_spawn
name = "Unknown"
density = TRUE
anchored = TRUE
var/mob_type = null
var/mob_name = ""
var/mob_gender = null
@@ -21,8 +23,7 @@
var/burn_damage = 0
var/mob_color //Change the mob's color
var/assignedrole
density = TRUE
anchored = TRUE
var/show_flavour = TRUE
var/banType = "lavaland"
/obj/effect/mob_spawn/attack_ghost(mob/user)
@@ -60,7 +61,7 @@
/obj/effect/mob_spawn/proc/equip(mob/M)
return
/obj/effect/mob_spawn/proc/create(ckey, flavour = TRUE, name)
/obj/effect/mob_spawn/proc/create(ckey, name)
var/mob/living/M = new mob_type(get_turf(src)) //living mobs only
if(!random)
M.real_name = mob_name ? mob_name : M.name
@@ -80,7 +81,7 @@
if(ckey)
M.ckey = ckey
if(flavour)
if(show_flavour)
to_chat(M, "[flavour_text]")
var/datum/mind/MM = M.mind
if(objectives)
+13 -2
View File
@@ -8,6 +8,7 @@
var/safety_warning = "For safety reasons the automated supply shuttle \
cannot transport live organisms, classified nuclear weaponry or \
homing beacons."
var/blockade_warning = "Bluespace instability detected. Shuttle movement impossible."
light_color = "#E2853D"//orange
@@ -54,8 +55,12 @@
data["docked"] = SSshuttle.supply.mode == SHUTTLE_IDLE
data["loan"] = !!SSshuttle.shuttle_loan
data["loan_dispatched"] = SSshuttle.shuttle_loan && SSshuttle.shuttle_loan.dispatched
data["message"] = SSshuttle.centcom_message || "Remember to stamp and send back the supply manifests."
var/message = "Remember to stamp and send back the supply manifests."
if(SSshuttle.centcom_message)
message = SSshuttle.centcom_message
if(SSshuttle.supplyBlocked)
message = blockade_warning
data["message"] = message
data["supplies"] = list()
for(var/pack in SSshuttle.supply_packs)
var/datum/supply_pack/P = SSshuttle.supply_packs[pack]
@@ -102,6 +107,9 @@
if(!SSshuttle.supply.canMove())
say(safety_warning)
return
if(SSshuttle.supplyBlocked)
say(blockade_warning)
return
if(SSshuttle.supply.getDockedId() == "supply_home")
SSshuttle.supply.emagged = emagged
SSshuttle.supply.contraband = contraband
@@ -116,6 +124,9 @@
if("loan")
if(!SSshuttle.shuttle_loan)
return
if(SSshuttle.supplyBlocked)
say(blockade_warning)
return
else if(SSshuttle.supply.mode != SHUTTLE_IDLE)
return
else if(SSshuttle.supply.getDockedId() != "supply_away")
+22 -4
View File
@@ -78,20 +78,38 @@
suit_store = /obj/item/gun/energy/laser/bluetag
/datum/outfit/pirate
name = "Pirate"
name = "Space Pirate"
uniform = /obj/item/clothing/under/pirate
shoes = /obj/item/clothing/shoes/sneakers/brown
suit = /obj/item/clothing/suit/pirate
head = /obj/item/clothing/head/bandana
glasses = /obj/item/clothing/glasses/eyepatch
r_hand = /obj/item/melee/transforming/energy/sword/pirate
/datum/outfit/pirate/space
name = "Space Pirate"
suit = /obj/item/clothing/suit/space/pirate
head = /obj/item/clothing/head/helmet/space/pirate/bandana
mask = /obj/item/clothing/mask/breath
suit_store = /obj/item/tank/internals/oxygen
ears = /obj/item/device/radio/headset/syndicate
id = /obj/item/card/id
/datum/outfit/pirate/space/captain
head = /obj/item/clothing/head/helmet/space/pirate
/datum/outfit/pirate/post_equip(mob/living/carbon/human/H)
H.faction |= "pirate"
var/obj/item/device/radio/R = H.ears
if(R)
R.set_frequency(GLOB.SYND_FREQ)
R.freqlock = 1
var/obj/item/card/id/W = H.wear_id
if(W)
W.registered_name = H.real_name
W.update_label(H.real_name)
/datum/outfit/tunnel_clown
name = "Tunnel Clown"
@@ -137,10 +137,16 @@ Contains:
item_state = "pirate"
armor = list(melee = 30, bullet = 50, laser = 30,energy = 15, bomb = 30, bio = 30, rad = 30, fire = 60, acid = 75)
flags_1 = STOPSPRESSUREDMAGE_1
flags_inv = HIDEHAIR
strip_delay = 40
equip_delay_other = 20
flags_cover = HEADCOVERSEYES
/obj/item/clothing/head/helmet/space/pirate/bandana
name = "pirate bandana"
icon_state = "bandana"
item_state = "bandana"
/obj/item/clothing/suit/space/pirate
name = "pirate coat"
desc = "Yarr."
+1 -1
View File
@@ -22,7 +22,7 @@
priority_announce("Due to [cause], [plural] [name] have [movement] \
into the [location].", "Migration Alert",
'sound/effects/mousesqueek.ogg', 100, 1)
'sound/effects/mousesqueek.ogg')
/datum/round_event/mice_migration/start()
SSsqueak.trigger_migration(rand(minimum_mice, maximum_mice))
+280
View File
@@ -0,0 +1,280 @@
#define LOOT_LOCATOR_COOLDOWN 150
/datum/round_event_control/pirates
name = "Space Pirates"
typepath = /datum/round_event/pirates
weight = 8
max_occurrences = 1
min_players = 10
earliest_start = 30 MINUTES
gamemode_blacklist = list("nuclear")
/datum/round_event/pirates
startWhen = 60 //2 minutes to answer
var/datum/comm_message/threat
var/payoff = 0
var/paid_off = FALSE
var/ship_name = "Space Privateers Association"
var/shuttle_spawned = FALSE
/datum/round_event/pirates/setup()
ship_name = pick(strings(PIRATE_NAMES_FILE, "ship_names"))
/datum/round_event/pirates/announce()
priority_announce("Incoming subspace communication. Secure channel opened at all communication consoles.", "Incoming Message", 'sound/ai/commandreport.ogg')
if(!control) //Means this is false alarm, todo : explicit checks instead of using announceWhen
return
threat = new
payoff = round(SSshuttle.points * 0.80)
threat.title = "Business proposition"
threat.content = "This is [ship_name]. Pay up [payoff] credits or you'll walk the plank."
threat.possible_answers = list("We'll pay.","No way.")
threat.answer_callback = CALLBACK(src,.proc/answered)
SScommunications.send_message(threat,unique = TRUE)
/datum/round_event/pirates/proc/answered()
if(threat && threat.answered == 1)
if(SSshuttle.points >= payoff)
SSshuttle.points -= payoff
priority_announce("Thanks for the credits, landlubbers.",sender_override = ship_name)
paid_off = TRUE
return
else
priority_announce("Trying to cheat us ? You'll regret this!",sender_override = ship_name)
if(!shuttle_spawned)
spawn_shuttle()
/datum/round_event/pirates/start()
if(!paid_off && !shuttle_spawned)
spawn_shuttle()
/datum/round_event/pirates/proc/spawn_shuttle()
shuttle_spawned = TRUE
var/list/candidates = pollGhostCandidates("Do you wish to be considered for pirate crew ?", ROLE_TRAITOR)
shuffle_inplace(candidates)
var/datum/map_template/pirate_event_ship/ship = new
var/x = rand(TRANSITIONEDGE,world.maxx - TRANSITIONEDGE - ship.width)
var/y = rand(TRANSITIONEDGE,world.maxy - TRANSITIONEDGE - ship.height)
var/z = ZLEVEL_EMPTY_SPACE
var/turf/T = locate(x,y,z)
if(!T)
CRASH("Pirate event found no turf to load in")
if(!ship.load(T))
CRASH("Loading pirate ship failed!")
for(var/turf/A in ship.get_affected_turfs(T))
for(var/obj/effect/mob_spawn/human/pirate/spawner in A)
if(candidates.len > 0)
var/mob/M = candidates[1]
spawner.create(M.ckey)
candidates -= M
else
notify_ghosts("Space pirates are waking up!", source = spawner, action=NOTIFY_ATTACK, flashwindow = FALSE)
priority_announce("Unidentified armed ship detected near the station.")
//Shuttle equipment
/obj/machinery/shuttle_scrambler
name = "Data Siphon"
desc = "This heap of machinery steals credits and data from unprotected systems and locks down cargo shuttles."
icon = 'icons/obj/machines/dominator.dmi'
icon_state = "dominator"
density = TRUE
anchored = TRUE
var/active = FALSE
var/obj/item/device/gps/gps
var/credits_stored = 0
var/siphon_per_tick = 5
/obj/machinery/shuttle_scrambler/Initialize(mapload)
. = ..()
gps = new/obj/item/device/gps/internal/pirate(src)
gps.tracking = FALSE
update_icon()
/obj/machinery/shuttle_scrambler/process()
if(active)
if(z in GLOB.station_z_levels)
var/siphoned = min(SSshuttle.points,siphon_per_tick)
SSshuttle.points -= siphoned
credits_stored += siphoned
steal_tech()
else
return
else
STOP_PROCESSING(SSobj,src)
/obj/machinery/shuttle_scrambler/proc/toggle_on(mob/user)
SSshuttle.registerTradeBlockade(src)
gps.tracking = TRUE
active = TRUE
to_chat(user,"<span class='notice'>You toggle [src] [active ? "on":"off"].</span>")
to_chat(user,"<span class='warning'>The scrambling signal can be now tracked by gps.</span>")
START_PROCESSING(SSobj,src)
/obj/machinery/shuttle_scrambler/interact(mob/user)
if(!active)
if(alert(user, "Turning the scrambler on will make the shuttle trackable by GPS. Are you sure you want to do it ?", "Scrambler", "Yes", "Cancel") == "Cancel")
return
if(active || !user.canUseTopic(src))
return
toggle_on(user)
update_icon()
send_notification()
else
dump_loot(user)
//20% to sap tech levels on unlocked consoles
/obj/machinery/shuttle_scrambler/proc/steal_tech()
if(!prob(20))
return
var/datum/tech/target_tech = pick(subtypesof(/datum/tech))
var/target_id = initial(target_tech.id)
for(var/obj/machinery/computer/rdconsole/C in GLOB.machines)
if(C.screen == RD_CONSOLE_LOCKED_SCREEN || C.stat & (NOPOWER|BROKEN))
continue
var/datum/research/files = C.files
files.LowerTech(target_id,1)
new /obj/effect/temp_visual/emp(get_turf(C))
for(var/obj/machinery/r_n_d/server/S in GLOB.machines)
if(S.stat & (NOPOWER|BROKEN))
continue
var/datum/research/files = S.files
files.LowerTech(target_id,1)
new /obj/effect/temp_visual/emp(get_turf(S))
/obj/machinery/shuttle_scrambler/proc/dump_loot(mob/user)
if(credits_stored < 200)
to_chat(user,"<span class='notice'>Not enough credits to retrieve.</span>")
return
while(credits_stored >= 200)
new /obj/item/stack/spacecash/c200(drop_location())
credits_stored -= 200
to_chat(user,"<span class='notice'>You retrieve the siphoned credits!</span>")
/obj/machinery/shuttle_scrambler/proc/send_notification()
priority_announce("Data theft signal detected, source registered on local gps units.")
/obj/machinery/shuttle_scrambler/proc/toggle_off(mob/user)
SSshuttle.clearTradeBlockade(src)
gps.tracking = FALSE
active = FALSE
STOP_PROCESSING(SSobj,src)
/obj/machinery/shuttle_scrambler/update_icon()
if(active)
icon_state = "dominator-blue"
else
icon_state = "dominator"
/obj/machinery/shuttle_scrambler/Destroy()
toggle_off()
QDEL_NULL(gps)
return ..()
/datum/map_template/pirate_event_ship
name = "Pirate Ship"
mappath = "_maps/templates/pirate_ship.dmm"
/obj/item/device/gps/internal/pirate
gpstag = "Nautical Signal"
desc = "You can hear shanties over the static."
/obj/machinery/computer/shuttle/pirate
name = "pirate shuttle console"
shuttleId = "pirateship"
icon_screen = "syndishuttle"
icon_keyboard = "syndie_key"
light_color = LIGHT_COLOR_RED
possible_destinations = "pirateship_away;pirateship_home;pirateship_custom"
/obj/machinery/computer/camera_advanced/shuttle_docker/syndicate/pirate
name = "pirate shuttle navigation computer"
desc = "Used to designate a precise transit location for the pirate shuttle."
shuttleId = "pirateship"
station_lock_override = TRUE
shuttlePortId = "pirateship_custom"
shuttlePortName = "custom location"
x_offset = 9
y_offset = 0
/obj/docking_port/mobile/pirate
name = "pirate shuttle"
id = "pirateship"
var/engines_cooling = FALSE
var/engine_cooldown = 3 MINUTES
/obj/docking_port/mobile/pirate/getStatusText()
. = ..()
if(engines_cooling)
return "[.] - Engines cooling."
/obj/docking_port/mobile/pirate/dock(obj/docking_port/stationary/new_dock, movement_direction, force=FALSE)
. = ..()
if(. == DOCKING_SUCCESS && new_dock.z != ZLEVEL_TRANSIT)
engines_cooling = TRUE
addtimer(CALLBACK(src,.proc/reset_cooldown),engine_cooldown,TIMER_UNIQUE)
/obj/docking_port/mobile/pirate/proc/reset_cooldown()
engines_cooling = FALSE
/obj/docking_port/mobile/pirate/canMove()
if(engines_cooling)
return FALSE
return ..()
/obj/machinery/suit_storage_unit/pirate
suit_type = /obj/item/clothing/suit/space
helmet_type = /obj/item/clothing/head/helmet/space
mask_type = /obj/item/clothing/mask/breath
storage_type = /obj/item/tank/internals/oxygen
/obj/machinery/loot_locator
name = "Booty Locator"
desc = "This sophisticated machine scans the nearby space for items of value."
icon = 'icons/obj/machines/research.dmi'
icon_state = "tdoppler"
density = TRUE
anchored = TRUE
var/cooldown = 0
var/result_count = 3 //Show X results.
/obj/machinery/proc/display_current_value()
var/area/current = get_area(src)
var/value = 0
for(var/turf/T in current.contents)
value += export_item_and_contents(T,TRUE, TRUE, dry_run = TRUE)
say("Current vault value : [value] credits.")
/obj/machinery/loot_locator/interact(mob/user)
if(world.time <= cooldown)
to_chat(user,"<span class='warning'>[src] is recharging.</span>")
return
cooldown = world.time + LOOT_LOCATOR_COOLDOWN
display_current_value()
var/list/results = list()
for(var/atom/movable/AM in world)
if(is_type_in_typecache(AM,GLOB.pirate_loot_cache))
if(AM.z in GLOB.station_z_levels)
if(get_area(AM) == get_area(src)) //Should this be variable ?
continue
results += AM
CHECK_TICK
if(!results.len)
say("No valuables located. Try again later.")
else
for(var/i in 1 to result_count)
if(!results.len)
return
var/atom/movable/AM = pick_n_take(results)
var/area/loot_area = get_area(AM)
say("Located: [AM.name] at [loot_area.name]")
#undef LOOT_LOCATOR_COOLDOWN
+2 -2
View File
@@ -387,8 +387,8 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
/mob/proc/reagent_check(datum/reagent/R) // utilized in the species code
return 1
/proc/notify_ghosts(var/message, var/ghost_sound = null, var/enter_link = null, var/atom/source = null, var/mutable_appearance/alert_overlay = null, var/action = NOTIFY_JUMP, flashwindow = TRUE) //Easy notification of ghosts.
if(SSatoms.initialized != INITIALIZATION_INNEW_REGULAR) //don't notify for objects created during a map load
/proc/notify_ghosts(var/message, var/ghost_sound = null, var/enter_link = null, var/atom/source = null, var/mutable_appearance/alert_overlay = null, var/action = NOTIFY_JUMP, flashwindow = TRUE, ignore_mapload = TRUE) //Easy notification of ghosts.
if(ignore_mapload && SSatoms.initialized != INITIALIZATION_INNEW_REGULAR) //don't notify for objects created during a map load
return
for(var/mob/dead/observer/O in GLOB.player_list)
if(O.client)
+10 -1
View File
@@ -315,10 +315,19 @@
/obj/machinery/computer/turbine_computer/Initialize()
. = ..()
return INITIALIZE_HINT_LATELOAD
/obj/machinery/computer/turbine_computer/LateInitialize()
locate_machinery()
/obj/machinery/computer/turbine_computer/locate_machinery()
compressor = locate(/obj/machinery/power/compressor) in range(5, src)
if(id)
for(var/obj/machinery/power/compressor/C in GLOB.machines)
if(C.comp_id == id)
compressor = C
return
else
compressor = locate(/obj/machinery/power/compressor) in range(5, src)
/obj/machinery/computer/turbine_computer/attack_hand(var/mob/user as mob)
if(..())
+1 -2
View File
@@ -28,7 +28,6 @@ won't update every console in existence) but it's more of a hassle to do. Also,
*/
/obj/machinery/computer/rdconsole
name = "R&D Console"
icon_screen = "rdcomp"
@@ -660,7 +659,7 @@ won't update every console in existence) but it's more of a hassle to do. Also,
if(0.1)
dat += "<div class='statusDisplay'>Processing and Updating Database...</div>"
if(0.2)
if(RD_CONSOLE_LOCKED_SCREEN)
dat += "<div class='statusDisplay'>SYSTEM LOCKED</div>"
dat += "<A href='?src=[REF(src)];lock=1.6'>Unlock</A>"
+6
View File
@@ -134,6 +134,12 @@ research holder datum.
/datum/research/proc/FindDesignByID(id)
return known_designs[id]
/datum/research/proc/LowerTech(tech_id,value)
var/datum/tech/T = known_tech[tech_id]
T.level = max(initial(T.level),T.level - value)
known_designs.Cut()
RefreshResearch()
//Autolathe files
/datum/research/autolathe/New()
+1 -2
View File
@@ -13,8 +13,7 @@
/obj/machinery/computer/shuttle/attack_hand(mob/user)
if(..(user))
return
src.add_fingerprint(usr)
add_fingerprint(usr)
var/list/options = params2list(possible_destinations)
var/obj/docking_port/mobile/M = SSshuttle.getShuttle(shuttleId)
var/dat = "Status: [M ? M.getStatusText() : "*Missing*"]<br><br>"