Merge branch 'master' into upstream-merge-5335

This commit is contained in:
Aronai Sieyes
2018-06-16 17:43:55 -04:00
committed by GitHub
70 changed files with 1834 additions and 471 deletions
+3 -1
View File
@@ -31,7 +31,8 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
#define INIT_ORDER_DEFAULT 0
#define INIT_ORDER_LIGHTING 0
#define INIT_ORDER_AIR -1
#define INIT_ORDER_HOLOMAPS -5
#define INIT_ORDER_PLANETS -4
#define INIT_ORDER_HOLOMAPS -5 //VOREStation Add
#define INIT_ORDER_OVERLAY -6
#define INIT_ORDER_XENOARCH -20
@@ -44,6 +45,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
#define FIRE_PRIORITY_AIRFLOW 30
#define FIRE_PRIORITY_AIR 35
#define FIRE_PRIORITY_DEFAULT 50
#define FIRE_PRIORITY_PLANETS 75
#define FIRE_PRIORITY_MACHINES 100
#define FIRE_PRIORITY_OVERLAYS 500
+13 -1
View File
@@ -12,4 +12,16 @@
var/area/A = locate(areapath) // Check if it actually exists
if(istype(A) && A.z in using_map.player_levels)
grand_list_of_areas += A
return grand_list_of_areas
return grand_list_of_areas
/** Checks if any living humans are in a given area! */
/proc/is_area_occupied(var/area/myarea)
// Testing suggests looping over human_mob_list is quicker than looping over area contents
for(var/mob/living/carbon/human/H in human_mob_list)
if(H.stat >= DEAD) //Conditions for exclusion here, like if disconnected people start blocking it.
continue
var/area/A = get_area(H)
if(A == myarea) //The loc of a turf is the area it is in.
return 1
return 0
+4
View File
@@ -60,6 +60,7 @@ var/list/gamemode_cache = list()
var/humans_need_surnames = 0
var/allow_random_events = 0 // enables random events mid-round when set to 1
var/allow_ai = 1 // allow ai job
var/allow_ai_drones = 0 // allow ai controlled drones
var/hostedby = null
var/respawn = 1
var/guest_jobban = 1
@@ -400,6 +401,9 @@ var/list/gamemode_cache = list()
if ("allow_ai")
config.allow_ai = 1
if ("allow_ai_drones")
config.allow_ai_drones = 1
// if ("authentication")
// config.enable_authentication = 1
+183
View File
@@ -0,0 +1,183 @@
SUBSYSTEM_DEF(planets)
name = "Planets"
init_order = INIT_ORDER_PLANETS
priority = FIRE_PRIORITY_PLANETS
wait = 2 SECONDS
flags = SS_BACKGROUND
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
var/list/new_outdoor_turfs = list()
var/list/new_outdoor_walls = list()
var/list/planets = list()
var/list/z_to_planet = list()
var/list/currentrun = list()
var/list/needs_sun_update = list()
var/list/needs_temp_update = list()
/datum/controller/subsystem/planets/Initialize(timeofday)
admin_notice("<span class='danger'>Initializing planetary weather.</span>", R_DEBUG)
createPlanets()
allocateTurfs(TRUE)
..()
/datum/controller/subsystem/planets/proc/createPlanets()
var/list/planet_datums = subtypesof(/datum/planet)
for(var/P in planet_datums)
var/datum/planet/NP = new P()
planets.Add(NP)
for(var/Z in NP.expected_z_levels)
if(Z > z_to_planet.len)
z_to_planet.len = Z
if(z_to_planet[Z])
admin_notice("<span class='danger'>Z[Z] is shared by more than one planet!</span>", R_DEBUG)
continue
z_to_planet[Z] = NP
/datum/controller/subsystem/planets/proc/addTurf(var/turf/T,var/is_edge)
if(is_edge)
new_outdoor_walls |= T
else
new_outdoor_turfs |= T
/datum/controller/subsystem/planets/proc/removeTurf(var/turf/T,var/is_edge)
if(is_edge)
new_outdoor_walls -= T
else
new_outdoor_turfs -= T
if(z_to_planet.len >= T.z)
var/datum/planet/P = z_to_planet[T.z]
if(!P)
return
if(is_edge)
P.planet_floors -= T
else
P.planet_walls -= T
/datum/controller/subsystem/planets/proc/allocateTurfs(var/initial = FALSE)
var/list/currentlist = new_outdoor_turfs
while(currentlist.len)
var/turf/simulated/OT = currentlist[currentlist.len]
currentlist.len--
if(istype(OT) && z_to_planet[OT.z])
var/datum/planet/P = z_to_planet[OT.z]
P.planet_floors |= OT
OT.vis_contents |= P.weather_holder.visuals
if(!initial && MC_TICK_CHECK)
return
currentlist = new_outdoor_walls
while(currentlist.len)
var/turf/unsimulated/wall/planetary/PW = currentlist[currentlist.len]
currentlist.len--
if(istype(PW) && z_to_planet[PW.z])
var/datum/planet/P = z_to_planet[PW.z]
P.planet_walls |= PW
if(!initial && MC_TICK_CHECK)
return
/datum/controller/subsystem/planets/proc/unallocateTurf(var/turf/simulated/T)
if(istype(T) && z_to_planet[T.z])
var/datum/planet/P = z_to_planet[T.z]
P.planet_floors -= T
T.vis_contents -= P.weather_holder.visuals
/datum/controller/subsystem/planets/fire(resumed = 0)
if(new_outdoor_turfs.len || new_outdoor_walls.len)
allocateTurfs()
if(!resumed)
src.currentrun = planets.Copy()
var/list/needs_sun_update = src.needs_sun_update
while(needs_sun_update.len)
var/datum/planet/P = needs_sun_update[needs_sun_update.len]
needs_sun_update.len--
updateSunlight(P)
if(MC_TICK_CHECK)
return
var/list/needs_temp_update = src.needs_temp_update
while(needs_temp_update.len)
var/datum/planet/P = needs_temp_update[needs_temp_update.len]
needs_temp_update.len--
updateTemp(P)
if(MC_TICK_CHECK)
return
var/list/currentrun = src.currentrun
while(currentrun.len)
var/datum/planet/P = currentrun[currentrun.len]
currentrun.len--
P.process(last_fire)
//Sun light needs changing
if(P.needs_work & PLANET_PROCESS_SUN)
P.needs_work &= ~PLANET_PROCESS_SUN
needs_sun_update |= P
//Temperature needs updating
if(P.needs_work & PLANET_PROCESS_TEMP)
P.needs_work &= ~PLANET_PROCESS_TEMP
needs_temp_update |= P
if(MC_TICK_CHECK)
return
/datum/controller/subsystem/planets/proc/updateSunlight(var/datum/planet/P)
// Remove old value from corners
var/list/sunlit_corners = P.sunlit_corners
var/old_lum_r = -P.sun["lum_r"]
var/old_lum_g = -P.sun["lum_g"]
var/old_lum_b = -P.sun["lum_b"]
if(old_lum_r || old_lum_g || old_lum_b)
for(var/C in sunlit_corners)
var/datum/lighting_corner/LC = C
LC.update_lumcount(old_lum_r, old_lum_g, old_lum_b)
CHECK_TICK
sunlit_corners.Cut()
// Calculate new values to apply
var/new_brightness = P.sun["brightness"]
var/new_color = P.sun["color"]
var/lum_r = new_brightness * GetRedPart (new_color) / 255
var/lum_g = new_brightness * GetGreenPart(new_color) / 255
var/lum_b = new_brightness * GetBluePart (new_color) / 255
var/static/update_gen = -1 // Used to prevent double-processing corners. Otherwise would happen when looping over adjacent turfs.
for(var/I in P.planet_floors)
var/turf/simulated/T = I
if(!T.lighting_corners_initialised)
T.generate_missing_corners()
for(var/C in T.get_corners())
var/datum/lighting_corner/LC = C
if(LC.update_gen != update_gen && LC.active)
sunlit_corners += LC
LC.update_gen = update_gen
LC.update_lumcount(lum_r, lum_g, lum_b)
CHECK_TICK
update_gen--
P.sun["lum_r"] = lum_r
P.sun["lum_g"] = lum_g
P.sun["lum_b"] = lum_b
/datum/controller/subsystem/planets/proc/updateTemp(var/datum/planet/P)
//Set new temperatures
for(var/W in P.planet_walls)
var/turf/unsimulated/wall/planetary/wall = W
wall.set_temperature(P.weather_holder.temperature)
CHECK_TICK
/datum/controller/subsystem/planets/proc/weatherDisco()
var/count = 100000
while(count > 0)
count--
for(var/planet in planets)
var/datum/planet/P = planet
if(P.weather_holder)
P.weather_holder.change_weather(pick(P.weather_holder.allowed_weather_types))
sleep(3)
-3
View File
@@ -133,9 +133,6 @@
if("Vote")
debug_variables(vote)
feedback_add_details("admin_verb", "DVote")
if("Planets")
debug_variables(planet_controller)
feedback_add_details("admin_verb", "DPlanets")
message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.")
return
+4 -4
View File
@@ -22,16 +22,16 @@
cost = 40
containertype = /obj/structure/closet/crate/secure/gear
containername = "Security equipment crate"
access = access_security
access = access_security*/
/datum/supply_packs/munitions/egunpistol
name = "Weapons - Energy sidearms"
contains = list(/obj/item/weapon/gun/energy/gun = 2)
cost = 40
cost = 50
containertype = /obj/structure/closet/crate/secure/weapon
containername = "Energy sidearms crate"
access = access_security
*/
access = access_armory //VOREStation Edit - Guns are for the armory.
/datum/supply_packs/munitions/flareguns
name = "Weapons - Flare guns"
contains = list(
+1 -1
View File
@@ -83,7 +83,7 @@ The "dust" will damage the hull of the station causin minor hull breaches.
endx = world.maxx-TRANSITIONEDGE
//VOREStation Edit - No space dust outside of space
var/list/z_levels = using_map.station_levels.Copy()
for(var/datum/planet/P in planet_controller.planets)
for(var/datum/planet/P in SSplanets.planets)
z_levels.Remove(P.expected_z_levels)
var/z_level = pick(z_levels)
//VOREStation Edit End
+4 -2
View File
@@ -200,14 +200,16 @@ GLOBAL_LIST_BOILERPLATE(all_deactivated_AI_cores, /obj/structure/AIcore/deactiva
if(!istype(transfer) || locate(/mob/living/silicon/ai) in src)
return
if(transfer.controlling_drone)
transfer.controlling_drone.release_ai_control("Unit control lost. Core transfer completed.")
transfer.aiRestorePowerRoutine = 0
transfer.control_disabled = 0
transfer.aiRadio.disabledAi = 0
transfer.loc = get_turf(src)
transfer.create_eyeobj()
transfer.cancel_camera()
user << "<span class='notice'>Transfer successful:</span> [transfer.name] placed within stationary core."
transfer << "You have been transferred into a stationary core. Remote device connection restored."
to_chat(user, "<span class='notice'>Transfer successful:</span> [transfer.name] placed within stationary core.")
to_chat(transfer, "You have been transferred into a stationary core. Remote device connection restored.")
if(card)
card.clear()
+2
View File
@@ -362,6 +362,8 @@
qdel(R.mmi)
for(var/obj/item/I in R.module) // the tools the borg has; metal, glass, guns etc
for(var/mob/M in I) //VOREStation edit
despawn_occupant(M)
for(var/obj/item/O in I) // the things inside the tools, if anything; mainly for janiborg trash bags
O.forceMove(R)
qdel(I)
+19 -11
View File
@@ -64,20 +64,24 @@
add_attack_logs(user,carded_ai,"Purged from AI Card")
flush = 1
carded_ai.suiciding = 1
carded_ai << "Your power has been disabled!"
to_chat(carded_ai, "Your power has been disabled!")
while (carded_ai && carded_ai.stat != 2)
if(carded_ai.controlling_drone && prob(carded_ai.oxyloss)) //You feel it creeping? Eventually will reach 100, resulting in the second half of the AI's remaining life being lonely.
carded_ai.controlling_drone.release_ai_control("Unit lost. Integrity too low to maintain connection.")
carded_ai.adjustOxyLoss(2)
carded_ai.updatehealth()
sleep(10)
flush = 0
if (href_list["radio"])
carded_ai.aiRadio.disabledAi = text2num(href_list["radio"])
carded_ai << "<span class='warning'>Your Subspace Transceiver has been [carded_ai.aiRadio.disabledAi ? "disabled" : "enabled"]!</span>"
user << "<span class='notice'>You [carded_ai.aiRadio.disabledAi ? "disable" : "enable"] the AI's Subspace Transceiver.</span>"
to_chat(carded_ai, "<span class='warning'>Your Subspace Transceiver has been [carded_ai.aiRadio.disabledAi ? "disabled" : "enabled"]!</span>")
to_chat(user, "<span class='notice'>You [carded_ai.aiRadio.disabledAi ? "disable" : "enable"] the AI's Subspace Transceiver.</span>")
if (href_list["wireless"])
carded_ai.control_disabled = text2num(href_list["wireless"])
carded_ai << "<span class='warning'>Your wireless interface has been [carded_ai.control_disabled ? "disabled" : "enabled"]!</span>"
user << "<span class='notice'>You [carded_ai.control_disabled ? "disable" : "enable"] the AI's wireless interface.</span>"
to_chat(carded_ai, "<span class='warning'>Your wireless interface has been [carded_ai.control_disabled ? "disabled" : "enabled"]!</span>")
to_chat(user, "<span class='notice'>You [carded_ai.control_disabled ? "disable" : "enable"] the AI's wireless interface.</span>")
if(carded_ai.control_disabled && carded_ai.controlling_drone)
carded_ai.controlling_drone.release_ai_control("Unit control terminated at intellicore port.")
update_icon()
return 1
@@ -94,12 +98,12 @@
icon_state = "aicard"
/obj/item/device/aicard/proc/grab_ai(var/mob/living/silicon/ai/ai, var/mob/living/user)
if(!ai.client)
user << "<span class='danger'>ERROR:</span> AI [ai.name] is offline. Unable to transfer."
if(!ai.client && !ai.controlling_drone)
to_chat(user, "<span class='danger'>ERROR:</span> AI [ai.name] is offline. Unable to transfer.")
return 0
if(carded_ai)
user << "<span class='danger'>Transfer failed:</span> Existing AI found on remote device. Remove existing AI to install a new one."
to_chat(user, "<span class='danger'>Transfer failed:</span> Existing AI found on remote device. Remove existing AI to install a new one.")
return 0
if(!user.IsAdvancedToolUser() && isanimal(user))
@@ -108,7 +112,9 @@
return 0
user.visible_message("\The [user] starts transferring \the [ai] into \the [src]...", "You start transferring \the [ai] into \the [src]...")
ai << "<span class='danger'>\The [user] is transferring you into \the [src]!</span>"
to_chat(ai, "<span class='danger'>\The [user] is transferring you into \the [src]!</span>")
if(ai.controlling_drone)
to_chat(ai.controlling_drone, "<span class='danger'>\The [user] is transferring you into \the [src]!</span>")
if(do_after(user, 100))
if(istype(ai.loc, /turf/))
@@ -124,11 +130,13 @@
ai.control_disabled = 1
ai.aiRestorePowerRoutine = 0
carded_ai = ai
if(ai.controlling_drone)
ai.controlling_drone.release_ai_control("Unit control lost.")
if(ai.client)
ai << "You have been transferred into a mobile core. Remote access lost."
to_chat(ai, "You have been transferred into a mobile core. Remote access lost.")
if(user.client)
user << "<span class='notice'><b>Transfer successful:</b></span> [ai.name] extracted from current device and placed within mobile core."
to_chat(ai, "<span class='notice'><b>Transfer successful:</b></span> [ai.name] extracted from current device and placed within mobile core.")
ai.canmove = 1
update_icon()
+252 -253
View File
@@ -1,253 +1,252 @@
// Proc: ui_interact()
// Parameters: 4 (standard NanoUI arguments)
// Description: Uses a bunch of for loops to turn lists into lists of lists, so they can be displayed in nanoUI, then displays various buttons to the user.
/obj/item/device/communicator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/key_state = null)
// this is the data which will be sent to the ui
var/data[0] //General nanoUI information
var/communicators[0] //List of communicators
var/invites[0] //Communicators and ghosts we've invited to our communicator.
var/requests[0] //Communicators and ghosts wanting to go in our communicator.
var/voices[0] //Current /mob/living/voice s inside the device.
var/connected_communicators[0] //Current communicators connected to the device.
var/im_contacts_ui[0] //List of communicators that have been messaged.
var/im_list_ui[0] //List of messages.
var/weather[0]
var/injection = null
var/modules_ui[0] //Home screen info.
//First we add other 'local' communicators.
for(var/obj/item/device/communicator/comm in known_devices)
if(comm.network_visibility && comm.exonet)
communicators[++communicators.len] = list("name" = sanitize(comm.name), "address" = comm.exonet.address)
//Now for ghosts who we pretend have communicators.
for(var/mob/observer/dead/O in known_devices)
if(O.client && O.client.prefs.communicator_visibility == 1 && O.exonet)
communicators[++communicators.len] = list("name" = sanitize("[O.client.prefs.real_name]'s communicator"), "address" = O.exonet.address, "ref" = "\ref[O]")
//Lists all the other communicators that we invited.
for(var/obj/item/device/communicator/comm in voice_invites)
if(comm.exonet)
invites[++invites.len] = list("name" = sanitize(comm.name), "address" = comm.exonet.address, "ref" = "\ref[comm]")
//Ghosts we invited.
for(var/mob/observer/dead/O in voice_invites)
if(O.exonet && O.client)
invites[++invites.len] = list("name" = sanitize("[O.client.prefs.real_name]'s communicator"), "address" = O.exonet.address, "ref" = "\ref[O]")
//Communicators that want to talk to us.
for(var/obj/item/device/communicator/comm in voice_requests)
if(comm.exonet)
requests[++requests.len] = list("name" = sanitize(comm.name), "address" = comm.exonet.address, "ref" = "\ref[comm]")
//Ghosts that want to talk to us.
for(var/mob/observer/dead/O in voice_requests)
if(O.exonet && O.client)
requests[++requests.len] = list("name" = sanitize("[O.client.prefs.real_name]'s communicator"), "address" = O.exonet.address, "ref" = "\ref[O]")
//Now for all the voice mobs inside the communicator.
for(var/mob/living/voice/voice in contents)
voices[++voices.len] = list("name" = sanitize("[voice.name]'s communicator"), "true_name" = sanitize(voice.name))
//Finally, all the communicators linked to this one.
for(var/obj/item/device/communicator/comm in communicating)
connected_communicators[++connected_communicators.len] = list("name" = sanitize(comm.name), "true_name" = sanitize(comm.name), "ref" = "\ref[comm]")
//Devices that have been messaged or recieved messages from.
for(var/obj/item/device/communicator/comm in im_contacts)
if(comm.exonet)
im_contacts_ui[++im_contacts_ui.len] = list("name" = sanitize(comm.name), "address" = comm.exonet.address, "ref" = "\ref[comm]")
for(var/mob/observer/dead/ghost in im_contacts)
if(ghost.exonet)
im_contacts_ui[++im_contacts_ui.len] = list("name" = sanitize(ghost.name), "address" = ghost.exonet.address, "ref" = "\ref[ghost]")
//Actual messages.
for(var/I in im_list)
im_list_ui[++im_list_ui.len] = list("address" = I["address"], "to_address" = I["to_address"], "im" = I["im"])
//Weather reports.
if(planet_controller)
for(var/datum/planet/planet in planet_controller.planets)
if(planet.weather_holder && planet.weather_holder.current_weather)
var/list/W = list(
"Planet" = planet.name,
"Time" = planet.current_time.show_time("hh:mm"),
"Weather" = planet.weather_holder.current_weather.name,
"Temperature" = planet.weather_holder.temperature - T0C,
"High" = planet.weather_holder.current_weather.temp_high - T0C,
"Low" = planet.weather_holder.current_weather.temp_low - T0C)
weather[++weather.len] = W
injection = "<div>Test</div>"
//Modules for homescreen.
for(var/list/R in modules)
modules_ui[++modules_ui.len] = R
data["owner"] = owner ? owner : "Unset"
data["occupation"] = occupation ? occupation : "Swipe ID to set."
data["connectionStatus"] = get_connection_to_tcomms()
data["visible"] = network_visibility
data["address"] = exonet.address ? exonet.address : "Unallocated"
data["targetAddress"] = target_address
data["targetAddressName"] = target_address_name
data["currentTab"] = selected_tab
data["knownDevices"] = communicators
data["invitesSent"] = invites
data["requestsReceived"] = requests
data["voice_mobs"] = voices
data["communicating"] = connected_communicators
data["video_comm"] = video_source ? "\ref[video_source.loc]" : null
data["imContacts"] = im_contacts_ui
data["imList"] = im_list_ui
data["time"] = stationtime2text()
data["ring"] = ringer
data["homeScreen"] = modules_ui
data["note"] = note // current notes
data["weather"] = weather
data["aircontents"] = src.analyze_air()
data["flashlight"] = fon
data["injection"] = injection
// update the ui if it exists, returns null if no ui is passed/found
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if(!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "communicator.tmpl", "Communicator", 475, 700, state = key_state)
// add templates for screens in common with communicator.
ui.add_template("atmosphericScan", "atmospheric_scan.tmpl")
// when the ui is first opened this is the data it will use
ui.set_initial_data(data)
// open the new ui window
ui.open()
// auto update every five Master Controller tick
ui.set_auto_update(5)
// Proc: Topic()
// Parameters: 2 (standard Topic arguments)
// Description: Responds to NanoUI button presses.
/obj/item/device/communicator/Topic(href, href_list)
if(..())
return 1
if(href_list["rename"])
var/new_name = sanitizeSafe(input(usr,"Please enter your name.","Communicator",usr.name) )
if(new_name)
register_device(new_name)
if(href_list["toggle_visibility"])
switch(network_visibility)
if(1) //Visible, becoming invisbile
network_visibility = 0
if(camera)
camera.remove_network(NETWORK_COMMUNICATORS)
if(0) //Invisible, becoming visible
network_visibility = 1
if(camera)
camera.add_network(NETWORK_COMMUNICATORS)
if(href_list["toggle_ringer"])
ringer = !ringer
if(href_list["add_hex"])
var/hex = href_list["add_hex"]
add_to_EPv2(hex)
if(href_list["write_target_address"])
var/new_address = sanitizeSafe(input(usr,"Please enter the desired target EPv2 address. Note that you must write the colons \
yourself.","Communicator",src.target_address) )
if(new_address)
target_address = new_address
if(href_list["clear_target_address"])
target_address = ""
if(href_list["dial"])
if(!get_connection_to_tcomms())
usr << "<span class='danger'>Error: Cannot connect to Exonet node.</span>"
return
var/their_address = href_list["dial"]
exonet.send_message(their_address, "voice")
if(href_list["decline"])
var/ref_to_remove = href_list["decline"]
var/atom/decline = locate(ref_to_remove)
if(decline)
del_request(decline)
if(href_list["message"])
if(!get_connection_to_tcomms())
usr << "<span class='danger'>Error: Cannot connect to Exonet node.</span>"
return
var/their_address = href_list["message"]
var/text = sanitizeSafe(input(usr,"Enter your message.","Text Message"))
if(text)
exonet.send_message(their_address, "text", text)
im_list += list(list("address" = exonet.address, "to_address" = their_address, "im" = text))
log_pda("(COMM: [src]) sent \"[text]\" to [exonet.get_atom_from_address(their_address)]", usr)
for(var/mob/M in player_list)
if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears))
if(istype(M, /mob/new_player) || M.forbid_seeing_deadchat)
continue
if(exonet.get_atom_from_address(their_address) == M)
continue
M.show_message("Comm IM - [src] -> [exonet.get_atom_from_address(their_address)]: [text]")
if(href_list["disconnect"])
var/name_to_disconnect = href_list["disconnect"]
for(var/mob/living/voice/V in contents)
if(name_to_disconnect == V.name)
close_connection(usr, V, "[usr] hung up")
for(var/obj/item/device/communicator/comm in communicating)
if(name_to_disconnect == comm.name)
close_connection(usr, comm, "[usr] hung up")
if(href_list["startvideo"])
var/ref_to_video = href_list["startvideo"]
var/obj/item/device/communicator/comm = locate(ref_to_video)
if(comm)
connect_video(usr, comm)
if(href_list["endvideo"])
if(video_source)
end_video()
if(href_list["watchvideo"])
if(video_source)
watch_video(usr,video_source.loc)
if(href_list["copy"])
target_address = href_list["copy"]
if(href_list["copy_name"])
target_address_name = href_list["copy_name"]
if(href_list["hang_up"])
for(var/mob/living/voice/V in contents)
close_connection(usr, V, "[usr] hung up")
for(var/obj/item/device/communicator/comm in communicating)
close_connection(usr, comm, "[usr] hung up")
if(href_list["switch_tab"])
selected_tab = href_list["switch_tab"]
if(href_list["edit"])
var/n = input(usr, "Please enter message", name, notehtml)
n = sanitizeSafe(n, extra = 0)
if(n)
note = html_decode(n)
notehtml = note
note = replacetext(note, "\n", "<br>")
else
note = ""
notehtml = note
if(href_list["Light"])
fon = !fon
set_light(fon * flum)
nanomanager.update_uis(src)
add_fingerprint(usr)
// Proc: ui_interact()
// Parameters: 4 (standard NanoUI arguments)
// Description: Uses a bunch of for loops to turn lists into lists of lists, so they can be displayed in nanoUI, then displays various buttons to the user.
/obj/item/device/communicator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/key_state = null)
// this is the data which will be sent to the ui
var/data[0] //General nanoUI information
var/communicators[0] //List of communicators
var/invites[0] //Communicators and ghosts we've invited to our communicator.
var/requests[0] //Communicators and ghosts wanting to go in our communicator.
var/voices[0] //Current /mob/living/voice s inside the device.
var/connected_communicators[0] //Current communicators connected to the device.
var/im_contacts_ui[0] //List of communicators that have been messaged.
var/im_list_ui[0] //List of messages.
var/weather[0]
var/injection = null
var/modules_ui[0] //Home screen info.
//First we add other 'local' communicators.
for(var/obj/item/device/communicator/comm in known_devices)
if(comm.network_visibility && comm.exonet)
communicators[++communicators.len] = list("name" = sanitize(comm.name), "address" = comm.exonet.address)
//Now for ghosts who we pretend have communicators.
for(var/mob/observer/dead/O in known_devices)
if(O.client && O.client.prefs.communicator_visibility == 1 && O.exonet)
communicators[++communicators.len] = list("name" = sanitize("[O.client.prefs.real_name]'s communicator"), "address" = O.exonet.address, "ref" = "\ref[O]")
//Lists all the other communicators that we invited.
for(var/obj/item/device/communicator/comm in voice_invites)
if(comm.exonet)
invites[++invites.len] = list("name" = sanitize(comm.name), "address" = comm.exonet.address, "ref" = "\ref[comm]")
//Ghosts we invited.
for(var/mob/observer/dead/O in voice_invites)
if(O.exonet && O.client)
invites[++invites.len] = list("name" = sanitize("[O.client.prefs.real_name]'s communicator"), "address" = O.exonet.address, "ref" = "\ref[O]")
//Communicators that want to talk to us.
for(var/obj/item/device/communicator/comm in voice_requests)
if(comm.exonet)
requests[++requests.len] = list("name" = sanitize(comm.name), "address" = comm.exonet.address, "ref" = "\ref[comm]")
//Ghosts that want to talk to us.
for(var/mob/observer/dead/O in voice_requests)
if(O.exonet && O.client)
requests[++requests.len] = list("name" = sanitize("[O.client.prefs.real_name]'s communicator"), "address" = O.exonet.address, "ref" = "\ref[O]")
//Now for all the voice mobs inside the communicator.
for(var/mob/living/voice/voice in contents)
voices[++voices.len] = list("name" = sanitize("[voice.name]'s communicator"), "true_name" = sanitize(voice.name))
//Finally, all the communicators linked to this one.
for(var/obj/item/device/communicator/comm in communicating)
connected_communicators[++connected_communicators.len] = list("name" = sanitize(comm.name), "true_name" = sanitize(comm.name), "ref" = "\ref[comm]")
//Devices that have been messaged or recieved messages from.
for(var/obj/item/device/communicator/comm in im_contacts)
if(comm.exonet)
im_contacts_ui[++im_contacts_ui.len] = list("name" = sanitize(comm.name), "address" = comm.exonet.address, "ref" = "\ref[comm]")
for(var/mob/observer/dead/ghost in im_contacts)
if(ghost.exonet)
im_contacts_ui[++im_contacts_ui.len] = list("name" = sanitize(ghost.name), "address" = ghost.exonet.address, "ref" = "\ref[ghost]")
//Actual messages.
for(var/I in im_list)
im_list_ui[++im_list_ui.len] = list("address" = I["address"], "to_address" = I["to_address"], "im" = I["im"])
//Weather reports.
for(var/datum/planet/planet in SSplanets.planets)
if(planet.weather_holder && planet.weather_holder.current_weather)
var/list/W = list(
"Planet" = planet.name,
"Time" = planet.current_time.show_time("hh:mm"),
"Weather" = planet.weather_holder.current_weather.name,
"Temperature" = planet.weather_holder.temperature - T0C,
"High" = planet.weather_holder.current_weather.temp_high - T0C,
"Low" = planet.weather_holder.current_weather.temp_low - T0C)
weather[++weather.len] = W
injection = "<div>Test</div>"
//Modules for homescreen.
for(var/list/R in modules)
modules_ui[++modules_ui.len] = R
data["owner"] = owner ? owner : "Unset"
data["occupation"] = occupation ? occupation : "Swipe ID to set."
data["connectionStatus"] = get_connection_to_tcomms()
data["visible"] = network_visibility
data["address"] = exonet.address ? exonet.address : "Unallocated"
data["targetAddress"] = target_address
data["targetAddressName"] = target_address_name
data["currentTab"] = selected_tab
data["knownDevices"] = communicators
data["invitesSent"] = invites
data["requestsReceived"] = requests
data["voice_mobs"] = voices
data["communicating"] = connected_communicators
data["video_comm"] = video_source ? "\ref[video_source.loc]" : null
data["imContacts"] = im_contacts_ui
data["imList"] = im_list_ui
data["time"] = stationtime2text()
data["ring"] = ringer
data["homeScreen"] = modules_ui
data["note"] = note // current notes
data["weather"] = weather
data["aircontents"] = src.analyze_air()
data["flashlight"] = fon
data["injection"] = injection
// update the ui if it exists, returns null if no ui is passed/found
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if(!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "communicator.tmpl", "Communicator", 475, 700, state = key_state)
// add templates for screens in common with communicator.
ui.add_template("atmosphericScan", "atmospheric_scan.tmpl")
// when the ui is first opened this is the data it will use
ui.set_initial_data(data)
// open the new ui window
ui.open()
// auto update every five Master Controller tick
ui.set_auto_update(5)
// Proc: Topic()
// Parameters: 2 (standard Topic arguments)
// Description: Responds to NanoUI button presses.
/obj/item/device/communicator/Topic(href, href_list)
if(..())
return 1
if(href_list["rename"])
var/new_name = sanitizeSafe(input(usr,"Please enter your name.","Communicator",usr.name) )
if(new_name)
register_device(new_name)
if(href_list["toggle_visibility"])
switch(network_visibility)
if(1) //Visible, becoming invisbile
network_visibility = 0
if(camera)
camera.remove_network(NETWORK_COMMUNICATORS)
if(0) //Invisible, becoming visible
network_visibility = 1
if(camera)
camera.add_network(NETWORK_COMMUNICATORS)
if(href_list["toggle_ringer"])
ringer = !ringer
if(href_list["add_hex"])
var/hex = href_list["add_hex"]
add_to_EPv2(hex)
if(href_list["write_target_address"])
var/new_address = sanitizeSafe(input(usr,"Please enter the desired target EPv2 address. Note that you must write the colons \
yourself.","Communicator",src.target_address) )
if(new_address)
target_address = new_address
if(href_list["clear_target_address"])
target_address = ""
if(href_list["dial"])
if(!get_connection_to_tcomms())
usr << "<span class='danger'>Error: Cannot connect to Exonet node.</span>"
return
var/their_address = href_list["dial"]
exonet.send_message(their_address, "voice")
if(href_list["decline"])
var/ref_to_remove = href_list["decline"]
var/atom/decline = locate(ref_to_remove)
if(decline)
del_request(decline)
if(href_list["message"])
if(!get_connection_to_tcomms())
usr << "<span class='danger'>Error: Cannot connect to Exonet node.</span>"
return
var/their_address = href_list["message"]
var/text = sanitizeSafe(input(usr,"Enter your message.","Text Message"))
if(text)
exonet.send_message(their_address, "text", text)
im_list += list(list("address" = exonet.address, "to_address" = their_address, "im" = text))
log_pda("(COMM: [src]) sent \"[text]\" to [exonet.get_atom_from_address(their_address)]", usr)
for(var/mob/M in player_list)
if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears))
if(istype(M, /mob/new_player) || M.forbid_seeing_deadchat)
continue
if(exonet.get_atom_from_address(their_address) == M)
continue
M.show_message("Comm IM - [src] -> [exonet.get_atom_from_address(their_address)]: [text]")
if(href_list["disconnect"])
var/name_to_disconnect = href_list["disconnect"]
for(var/mob/living/voice/V in contents)
if(name_to_disconnect == V.name)
close_connection(usr, V, "[usr] hung up")
for(var/obj/item/device/communicator/comm in communicating)
if(name_to_disconnect == comm.name)
close_connection(usr, comm, "[usr] hung up")
if(href_list["startvideo"])
var/ref_to_video = href_list["startvideo"]
var/obj/item/device/communicator/comm = locate(ref_to_video)
if(comm)
connect_video(usr, comm)
if(href_list["endvideo"])
if(video_source)
end_video()
if(href_list["watchvideo"])
if(video_source)
watch_video(usr,video_source.loc)
if(href_list["copy"])
target_address = href_list["copy"]
if(href_list["copy_name"])
target_address_name = href_list["copy_name"]
if(href_list["hang_up"])
for(var/mob/living/voice/V in contents)
close_connection(usr, V, "[usr] hung up")
for(var/obj/item/device/communicator/comm in communicating)
close_connection(usr, comm, "[usr] hung up")
if(href_list["switch_tab"])
selected_tab = href_list["switch_tab"]
if(href_list["edit"])
var/n = input(usr, "Please enter message", name, notehtml)
n = sanitizeSafe(n, extra = 0)
if(n)
note = html_decode(n)
notehtml = note
note = replacetext(note, "\n", "<br>")
else
note = ""
notehtml = note
if(href_list["Light"])
fon = !fon
set_light(fon * flum)
nanomanager.update_uis(src)
add_fingerprint(usr)
@@ -1,4 +1,4 @@
/obj/item/weapon/tank/emergency/phoron_double
/obj/item/weapon/tank/emergency/phoron/double
name = "double emergency phoron tank"
desc = "Contains dangerous phoron. Do not inhale. Warning: extremely flammable."
icon = 'icons/obj/tank_vr.dmi'
@@ -8,7 +8,7 @@
gauge_cap = 3
volume = 10
/obj/item/weapon/tank/emergency/phoron_double/New()
/obj/item/weapon/tank/emergency/phoron/double/New()
..()
air_contents.adjust_gas("phoron", (10*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C))
@@ -41,6 +41,8 @@
icon = 'icons/obj/tank_vr.dmi'
icon_override = 'icons/mob/back_vr.dmi'
icon_state = "phoron_vox"
gauge_cap = 3
gauge_icon = "indicator_double"
/obj/item/weapon/tank/emergency
icon = 'icons/obj/tank_vr.dmi'
+1 -1
View File
@@ -2,7 +2,7 @@
/obj/structure/catwalk
name = "catwalk"
desc = "Cats really don't like these things."
plane = TURF_PLANE
plane = DECAL_PLANE
layer = ABOVE_UTILITY
icon = 'icons/turf/catwalks.dmi'
icon_state = "catwalk"
@@ -6,15 +6,6 @@
icon = 'icons/obj/abductor.dmi'
density = TRUE
anchored = TRUE
var/interaction_message = null
/obj/structure/prop/alien/attack_hand(mob/living/user) // Used to tell the player that this isn't useful for anything.
if(!istype(user))
return FALSE
if(!interaction_message)
return ..()
else
to_chat(user, interaction_message)
/obj/structure/prop/alien/computer
name = "alien console"
@@ -0,0 +1,215 @@
//A series(?) of prisms for PoIs. The base one only works for beams.
/obj/structure/prop/prism
name = "prismatic turret"
desc = "A raised, externally powered 'turret'. It seems to have a massive crystal ring around its base."
description_info = "This device is capable of redirecting any beam projectile."
icon = 'icons/obj/props/prism.dmi'
icon_state = "prism"
density = TRUE
anchored = TRUE
layer = 3.1 //Layer over projectiles.
plane = -10 //Layer over projectiles.
var/rotation_lock = 0 // Can you rotate the prism at all?
var/free_rotate = 1 // Does the prism rotate in any direction, or only in the eight standard compass directions?
var/external_control_lock = 0 // Does the prism only rotate from the controls of an external switch?
var/degrees_from_north = 0 // How far is it rotated clockwise?
var/compass_directions = list("North" = 0, "South" = 180, "East" = 90, "West" = 270, "Northwest" = 315, "Northeast" = 45, "Southeast" = 135, "Southwest" = 225)
var/interaction_sound = 'sound/mecha/mechmove04.ogg'
var/redirect_type = /obj/item/projectile/beam
var/dialID = null
var/obj/structure/prop/prismcontrol/remote_dial = null
interaction_message = "<span class='notice'>The prismatic turret seems to be able to rotate.</span>"
/obj/structure/prop/prism/initialize()
if(degrees_from_north)
animate(src, transform = turn(NORTH, degrees_from_north), time = 3)
/obj/structure/prop/prism/Destroy()
if(remote_dial)
remote_dial.my_turrets -= src
remote_dial = null
..()
/obj/structure/prop/prism/proc/reset_rotation()
var/degrees_to_rotate = -1 * degrees_from_north
animate(src, transform = turn(src.transform, degrees_to_rotate), time = 2)
/obj/structure/prop/prism/attack_hand(mob/living/user)
..()
if(rotation_lock)
to_chat(user, "<span class='warning'>\The [src] is locked at its current bearing.</span>")
return
if(external_control_lock)
to_chat(user, "<span class='warning'>\The [src]'s motors resist your efforts to rotate it. You may need to find some form of controller.</span>")
return
var/confirm = input("Do you want to try to rotate \the [src]?", "[name]") in list("Yes", "No")
if(confirm == "No")
visible_message(\
"<span class='notice'>[user.name] decides not to try turning \the [src].</span>",\
"<span class='notice'>You decide not to try turning \the [src].</span>")
return
var/new_bearing
if(free_rotate)
new_bearing = input("What bearing do you want to rotate \the [src] to?", "[name]") as num
new_bearing = round(new_bearing)
if(new_bearing <= -1 || new_bearing > 360)
to_chat(user, "<span class='warning'>Rotating \the [src] [new_bearing] degrees would be a waste of time.</span>")
return
else
var/choice = input("What point do you want to set \the [src] to?", "[name]") as null|anything in compass_directions
new_bearing = round(compass_directions[choice])
var/rotate_degrees = new_bearing - degrees_from_north
if(new_bearing == 360) // Weird artifact.
new_bearing = 0
degrees_from_north = new_bearing
var/two_stage = 0
if(rotate_degrees == 180 || rotate_degrees == -180)
two_stage = 1
var/multiplier = pick(-1, 1)
rotate_degrees = multiplier * (rotate_degrees / 2)
playsound(src, interaction_sound, 50, 1)
if(two_stage)
animate(src, transform = turn(src.transform, rotate_degrees), time = 3)
spawn(3)
animate(src, transform = turn(src.transform, rotate_degrees), time = 3)
else
animate(src, transform = turn(src.transform, rotate_degrees), time = 6) //Can't update transform because it will reset the angle.
/obj/structure/prop/prism/proc/rotate_auto(var/new_bearing)
if(rotation_lock)
visible_message("<span class='notice'>\The [src] shudders.</span>")
playsound(src, 'sound/effects/clang.ogg', 50, 1)
return
visible_message("<span class='notice'>\The [src] rotates to a bearing of [new_bearing].</span>")
var/rotate_degrees = new_bearing - degrees_from_north
if(new_bearing == 360)
new_bearing = 0
degrees_from_north = new_bearing
var/two_stage = 0
if(rotate_degrees == 180 || rotate_degrees == -180)
two_stage = 1
var/multiplier = pick(-1, 1)
rotate_degrees = multiplier * (rotate_degrees / 2)
playsound(src, interaction_sound, 50, 1)
if(two_stage)
animate(src, transform = turn(src.transform, rotate_degrees), time = 3)
spawn(3)
animate(src, transform = turn(src.transform, rotate_degrees), time = 3)
else
animate(src, transform = turn(src.transform, rotate_degrees), time = 6)
/obj/structure/prop/prism/bullet_act(var/obj/item/projectile/Proj)
if(istype(Proj, redirect_type))
visible_message("<span class='danger'>\The [src] redirects \the [Proj]!</span>")
flick("[initial(icon_state)]+glow", src)
var/new_x = (1 * round(10 * cos(degrees_from_north - 90))) + x //Vectors vectors vectors.
var/new_y = (-1 * round(10 * sin(degrees_from_north - 90))) + y
var/turf/curloc = get_turf(src)
Proj.penetrating += 1 // Needed for the beam to get out of the turret.
Proj.redirect(new_x, new_y, curloc, null)
/obj/structure/prop/prism/incremental
free_rotate = 0
description_info = "This device is capable of redirecting any beam projectile, but only locks to specific positions in rotation."
/obj/structure/prop/prism/incremental/externalcont
external_control_lock = 1
description_info = "This device is capable of redirecting any beam projectile, but can only be rotated by a control dial to specific positions."
/obj/structure/prop/prism/externalcont
external_control_lock = 1
description_info = "This device is capable of redirecting any beam projectile, but can only be rotated by an external control dial."
/obj/structure/prop/prismcontrol
name = "prismatic dial"
desc = "A large dial with a crystalline ring."
icon = 'icons/obj/props/prism.dmi'
icon_state = "dial"
density = FALSE
anchored = TRUE
interaction_message = "<span class='notice'>The dial pulses as your hand nears it.</span>"
var/list/my_turrets = list()
var/dialID = null
/obj/structure/prop/prismcontrol/attack_hand(mob/living/user)
..()
var/confirm = input("Do you want to try to rotate \the [src]?", "[name]") in list("Yes", "No")
if(confirm == "No")
visible_message(\
"<span class='notice'>[user.name] decides not to try turning \the [src].</span>",\
"<span class='notice'>You decide not to try turning \the [src].</span>")
return
if(!my_turrets || !my_turrets.len)
to_chat(user, "<span class='notice'>\The [src] doesn't seem to do anything.</span>")
return
var/free_rotate = 1
var/list/compass_directions = list()
for(var/obj/structure/prop/prism/P in my_turrets)
if(!P.free_rotate) //Doesn't use bearing, it uses compass points.
free_rotate = 0
compass_directions |= P.compass_directions
var/new_bearing
if(free_rotate)
new_bearing = input("What bearing do you want to rotate \the [src] to?", "[name]") as num
new_bearing = round(new_bearing)
if(new_bearing <= -1 || new_bearing > 360)
to_chat(user, "<span class='warning'>Rotating \the [src] [new_bearing] degrees would be a waste of time.</span>")
return
else
var/choice = input("What point do you want to set \the [src] to?", "[name]") as null|anything in compass_directions
new_bearing = round(compass_directions[choice])
confirm = input("Are you certain you want to rotate \the [src]?", "[name]") in list("Yes", "No")
if(confirm == "No")
visible_message(\
"<span class='notice'>[user.name] decides not to try turning \the [src].</span>",\
"<span class='notice'>You decide not to try turning \the [src].</span>")
return
to_chat(user, "<span class='notice'>\The [src] clicks into place.</span>")
for(var/obj/structure/prop/prism/P in my_turrets)
P.rotate_auto(new_bearing)
/obj/structure/prop/prismcontrol/initialize()
..()
if(my_turrets.len) //Preset controls.
for(var/obj/structure/prop/prism/P in my_turrets)
P.remote_dial = src
return
spawn()
for(var/obj/structure/prop/prism/P in orange(src, world.view)) //Don't search a huge area.
if(P.dialID == dialID && !P.remote_dial && P.external_control_lock)
my_turrets |= P
P.remote_dial = src
/obj/structure/prop/prismcontrol/Destroy()
for(var/obj/structure/prop/prism/P in my_turrets)
P.remote_dial = null
my_turrets = list()
..()
@@ -0,0 +1,53 @@
//A locking mechanism that pulses when hit by a projectile. The base one responds to high-power lasers.
/obj/structure/prop/lock
name = "weird lock"
desc = "An esoteric object that responds to.. something."
icon = 'icons/obj/props/prism.dmi'
icon_state = "lock"
var/enabled = 0
var/lockID = null
var/list/linked_objects = list()
/obj/structure/prop/lock/Destroy()
if(linked_objects.len)
for(var/obj/O in linked_objects)
if(istype(O, /obj/machinery/door/blast/puzzle))
var/obj/machinery/door/blast/puzzle/P = O
P.locks -= src
linked_objects -= P
..()
/obj/structure/prop/lock/proc/toggle_lock()
enabled = !enabled
if(enabled)
icon_state = "[initial(icon_state)]-active"
else
icon_state = "[initial(icon_state)]"
/obj/structure/prop/lock/projectile
name = "beam lock"
desc = "An esoteric object that responds to high intensity light."
var/projectile_key = /obj/item/projectile/beam
var/timed = 0
var/timing = 0
var/time_limit = 1500 // In ticks. Ten is one second.
interaction_message = "<span class='notice'>The object remains inert to your touch.</span>"
/obj/structure/prop/lock/projectile/bullet_act(var/obj/item/projectile/Proj)
if(!istype(Proj, projectile_key) || timing)
return
if(istype(Proj, /obj/item/projectile/beam/heavylaser/cannon) || istype(Proj, /obj/item/projectile/beam/emitter) || (Proj.damage >= 80 && Proj.damtype == BURN))
toggle_lock()
visible_message("<span class='notice'>\The [src] [enabled ? "disengages" : "engages"] its locking mechanism.</span>")
if(timed)
timing = 1
spawn(time_limit)
toggle_lock()
@@ -0,0 +1,18 @@
//The base 'prop' for PoIs or other large junk.
/obj/structure/prop
name = "something"
desc = "My description is broken, bug a developer."
icon = 'icons/obj/structures.dmi'
icon_state = "safe"
density = TRUE
anchored = TRUE
var/interaction_message = null
/obj/structure/prop/attack_hand(mob/living/user) // Used to tell the player that this isn't useful for anything.
if(!istype(user))
return FALSE
if(!interaction_message)
return ..()
else
to_chat(user, interaction_message)
@@ -0,0 +1,92 @@
// An indestructible blast door that can only be opened once its puzzle requirements are completed.
/obj/machinery/door/blast/puzzle
name = "puzzle door"
desc = "A large, virtually indestructible door that will not open unless certain requirements are met."
icon_state_open = "pdoor0"
icon_state_opening = "pdoorc0"
icon_state_closed = "pdoor1"
icon_state_closing = "pdoorc1"
icon_state = "pdoor1"
explosion_resistance = 100
maxhealth = 9999999 //No.
var/list/locks = list()
var/lockID = null
var/checkrange_mult = 1
/obj/machinery/door/blast/puzzle/proc/check_locks()
for(var/obj/structure/prop/lock/L in locks)
if(!L.enabled)
return 0
return 1
/obj/machinery/door/blast/puzzle/bullet_act(var/obj/item/projectile/Proj)
visible_message("<span class='cult'>\The [src] is completely unaffected by \the [Proj].</span>")
qdel(Proj) //No piercing. No.
/obj/machinery/door/blast/puzzle/ex_act(severity)
visible_message("<span class='cult'>\The [src] is completely unaffected by the blast.</span>")
return
/obj/machinery/door/blast/puzzle/initialize()
. = ..()
implicit_material = get_material_by_name("dungeonium")
if(locks.len)
return
var/check_range = world.view * checkrange_mult
for(var/obj/structure/prop/lock/L in orange(src, check_range))
if(L.lockID == lockID)
L.linked_objects |= src
locks |= L
/obj/machinery/door/blast/puzzle/Destroy()
if(locks.len)
for(var/obj/structure/prop/lock/L in locks)
L.linked_objects -= src
locks -= L
..()
/obj/machinery/door/blast/puzzle/attack_hand(mob/user as mob)
if(check_locks())
force_toggle(1, user)
else
to_chat(user, "<span class='notice'>\The [src] does not respond to your touch.</span>")
/obj/machinery/door/blast/puzzle/attackby(obj/item/weapon/C as obj, mob/user as mob)
if(istype(C, /obj/item/weapon))
if(C.pry == 1 && (user.a_intent != I_HURT || (stat & BROKEN)))
if(istype(C,/obj/item/weapon/material/twohanded/fireaxe))
var/obj/item/weapon/material/twohanded/fireaxe/F = C
if(!F.wielded)
to_chat(user, "<span class='warning'>You need to be wielding \the [F] to do that.</span>")
return
if(check_locks())
force_toggle(1, user)
else
to_chat(user, "<span class='notice'>[src]'s arcane workings resist your effort.</span>")
return
else if(src.density && (user.a_intent == I_HURT))
var/obj/item/weapon/W = C
user.setClickCooldown(user.get_attack_speed(W))
if(W.damtype == BRUTE || W.damtype == BURN)
user.do_attack_animation(src)
user.visible_message("<span class='danger'>\The [user] hits \the [src] with \the [W] with no visible effect.</span>")
else if(istype(C, /obj/item/weapon/plastique))
to_chat(user, "<span class='danger'>On contacting \the [src], a flash of light envelops \the [C] as it is turned to ash. Oh.</span>")
qdel(C)
return 0
/obj/machinery/door/blast/puzzle/attack_generic(var/mob/user, var/damage)
if(check_locks())
force_toggle(1, user)
/obj/machinery/door/blast/puzzle/attack_alien(var/mob/user)
if(check_locks())
force_toggle(1, user)
@@ -1,5 +1,4 @@
var/list/turf_edge_cache = list()
var/list/outdoor_turfs = list()
/turf/
// If greater than 0, this turf will apply edge overlays on top of other turfs cardinally adjacent to it, if those adjacent turfs are of a different icon_state,
@@ -24,24 +23,21 @@ var/list/outdoor_turfs = list()
/turf/simulated/floor/New()
if(outdoors)
outdoor_turfs.Add(src)
SSplanets.addTurf(src)
..()
/turf/simulated/floor/Destroy()
if(outdoors)
planet_controller.unallocateTurf(src)
SSplanets.removeTurf(src)
return ..()
/turf/simulated/proc/make_outdoors()
outdoors = TRUE
outdoor_turfs.Add(src)
SSplanets.addTurf(src)
/turf/simulated/proc/make_indoors()
outdoors = FALSE
if(planet_controller)
planet_controller.unallocateTurf(src)
else // This is happening during map gen, if there's no planet_controller (hopefully).
outdoor_turfs -= src
SSplanets.removeTurf(src)
/turf/simulated/post_change()
..()
+1 -1
View File
@@ -14,7 +14,7 @@
/turf/simulated/sky/initialize()
. = ..()
outdoor_turfs.Add(src)
SSplanets.addTurf(src)
set_light(2, 2, "#FFFFFF")
/turf/simulated/sky/north
+2 -4
View File
@@ -1,7 +1,5 @@
// This is a wall you surround the area of your "planet" with, that makes the atmosphere inside stay within bounds, even if canisters
// are opened or other strange things occur.
var/list/planetary_walls = list()
/turf/unsimulated/wall/planetary
name = "railroading"
desc = "Choo choo!"
@@ -21,10 +19,10 @@ var/list/planetary_walls = list()
/turf/unsimulated/wall/planetary/New()
..()
planetary_walls.Add(src)
SSplanets.addTurf(src)
/turf/unsimulated/wall/planetary/Destroy()
planetary_walls.Remove(src)
SSplanets.removeTurf(src)
..()
/turf/unsimulated/wall/planetary/proc/set_temperature(var/new_temperature)
+3 -1
View File
@@ -659,11 +659,13 @@ var/list/admin_verbs_event_manager = list(
set desc = "Cause an explosion of varying strength at your location."
var/turf/epicenter = mob.loc
var/list/choices = list("Small Bomb", "Medium Bomb", "Big Bomb", "Custom Bomb")
var/list/choices = list("Small Bomb", "Medium Bomb", "Big Bomb", "Custom Bomb", "Cancel")
var/choice = input("What size explosion would you like to produce?") in choices
switch(choice)
if(null)
return 0
if("Cancel")
return 0
if("Small Bomb")
explosion(epicenter, 1, 2, 3, 3)
if("Medium Bomb")
+2 -2
View File
@@ -637,7 +637,7 @@
if(!check_rights(R_DEBUG))
return
var/datum/planet/planet = input(usr, "Which planet do you want to modify the weather on?", "Change Weather") in planet_controller.planets
var/datum/planet/planet = input(usr, "Which planet do you want to modify the weather on?", "Change Weather") in SSplanets.planets
var/datum/weather/new_weather = input(usr, "What weather do you want to change to?", "Change Weather") as null|anything in planet.weather_holder.allowed_weather_types
if(new_weather)
planet.weather_holder.change_weather(new_weather)
@@ -653,7 +653,7 @@
if(!check_rights(R_DEBUG))
return
var/datum/planet/planet = input(usr, "Which planet do you want to modify time on?", "Change Time") in planet_controller.planets
var/datum/planet/planet = input(usr, "Which planet do you want to modify time on?", "Change Time") in SSplanets.planets
var/datum/time/current_time_datum = planet.current_time
var/new_hour = input(usr, "What hour do you want to change to?", "Change Time", text2num(current_time_datum.show_time("hh"))) as null|num
@@ -0,0 +1,7 @@
//Minimum limit is 18
/datum/category_item/player_setup_item/get_min_age()
var/min_age = 18
var/datum/species/S = all_species[pref.species ? pref.species : "Human"]
if(!is_FBP() && S.min_age > 18)
min_age = S.min_age
return min_age
-11
View File
@@ -51,17 +51,6 @@
kill()
return
/** Checks if any living humans are in a given area! */
/datum/event/atmos_leak/proc/is_area_occupied(var/area/myarea)
// Testing suggests looping over human_mob_list is quicker than looping over area contents
for(var/mob/living/carbon/human/H in human_mob_list)
if(H.stat >= DEAD) //Conditions for exclusion here, like if disconnected people start blocking it.
continue
var/area/A = get_area(H)
if(A == myarea) //The loc of a turf is the area it is in.
return 1
return 0
/datum/event/atmos_leak/announce()
command_announcement.Announce("Warning, hazardous [gas_data.name[gas_type]] gas leak detected in \the [target_area], evacuate the area and contain the damage!", "Hazard Alert")
+1 -1
View File
@@ -33,7 +33,7 @@
/datum/event/escaped_slimes/start()
var/list/vents = list()
for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in machines)
if(temp_vent.network && temp_vent.loc.z in using_map.station_levels) //borrowed from spiders event, but it works. Distribute the slimes only in rooms with vents
if(temp_vent.network && temp_vent.loc.z in using_map.station_levels && !is_area_occupied(temp_vent.loc.loc)) //borrowed from spiders event, but it works. Distribute the slimes only in rooms with vents
vents += temp_vent
while((spawncount > 0) && vents.len)
+2 -3
View File
@@ -6,9 +6,8 @@
endWhen = rand(15, 60)
// Setup which levels we will disrupt gravit on.
zLevels = using_map.station_levels.Copy()
if (planet_controller)
for(var/datum/planet/P in planet_controller.planets)
zLevels -= P.expected_z_levels
for(var/datum/planet/P in SSplanets.planets)
zLevels -= P.expected_z_levels
/datum/event/gravity/announce()
command_announcement.Announce("Feedback surge detected in mass-distributions systems. Artificial gravity has been disabled whilst the system \
+1 -1
View File
@@ -50,7 +50,7 @@
new /obj/structure/meteorite(current)
var/datum/planet/impacted
for(var/datum/planet/P in planet_controller.planets)
for(var/datum/planet/P in SSplanets.planets)
if(current.z in P.expected_z_levels)
impacted = P
break
@@ -25,3 +25,7 @@
/mob/living/carbon/human/protean/New(var/new_loc)
..(new_loc, "Protean")
/mob/living/carbon/human/alraune/New(var/new_loc)
..(new_loc, "Alraune")
@@ -0,0 +1,336 @@
/datum/species/alraune
name = SPECIES_ALRAUNE
name_plural = "Alraunes"
unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/punch, /datum/unarmed_attack/bite)
num_alternate_languages = 2
language = LANGUAGE_ROOTLOCAL
slowdown = 1 //slow, they're plants. Not as slow as full diona.
total_health = 100 //standard
brute_mod = 1 //nothing special
burn_mod = 1.5 //plants don't like fire
metabolic_rate = 0.75 // slow metabolism
item_slowdown_mod = 0.25 //while they start slow, they don't get much slower
bloodloss_rate = 0.1 //While they do bleed, they bleed out VERY slowly
min_age = 18
max_age = 250
health_hud_intensity = 1.5
body_temperature = T20C
breath_type = "carbon_dioxide"
poison_type = "phoron"
exhale_type = "oxygen"
// Heat and cold resistances are 20 degrees broader on the level 1 range, level 2 is default, level 3 is much weaker, halfway between L2 and normal L3.
// Essentially, they can tolerate a broader range of comfortable temperatures, but suffer more at extremes.
cold_level_1 = 240 //Default 260 - Lower is better
cold_level_2 = 200 //Default 200
cold_level_3 = 160 //Default 120
cold_discomfort_level = 260 //they start feeling uncomfortable around the point where humans take damage
heat_level_1 = 380 //Default 360 - Higher is better
heat_level_2 = 400 //Default 400
heat_level_3 = 700 //Default 1000
heat_discomfort_level = 360
breath_cold_level_1 = 240 //They don't have lungs, they breathe through their skin
breath_cold_level_2 = 180 //sadly for them, their breath tolerance is no better than anyone else's.
breath_cold_level_3 = 140 //mainly 'cause breath tolerance is more generous than body temp tolerance.
breath_heat_level_1 = 400 //slightly better heat tolerance in air though. Slightly.
breath_heat_level_2 = 450
breath_heat_level_3 = 800 //lower incineration threshold though
spawn_flags = SPECIES_CAN_JOIN | SPECIES_IS_WHITELISTED // whitelist only while WIP
flags = NO_SCAN | IS_PLANT | NO_MINOR_CUT
appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR
inherent_verbs = list(
/mob/living/carbon/human/proc/succubus_drain,
/mob/living/carbon/human/proc/succubus_drain_finalize,
/mob/living/carbon/human/proc/succubus_drain_lethal,
/mob/living/carbon/human/proc/bloodsuck) //Give them the voremodes related to wrapping people in vines and sapping their fluids
color_mult = 1
icobase = 'icons/mob/human_races/r_human_vr.dmi'
deform = 'icons/mob/human_races/r_def_human_vr.dmi'
flesh_color = "#9ee02c"
blood_color = "#edf4d0" //sap!
base_color = "#1a5600"
blurb = "Alraunes are a rare sight in space. Their bodies are reminiscent of that of plants, and yet they share many\
traits with other humanoid beings.\
\
Most Alraunes are not interested in traversing space, their heavy preference for natural environments and general\
disinterest in things outside it keeps them as a species at a rather primal stage.\
\
However, after their discovery by the angels of Sanctum, many alraunes succumbed to their curiosity, and took the offer\
to learn of the world and venture out, whether it's to Sanctum, or elsewhere in the galaxy."
has_limbs = list(
BP_TORSO = list("path" = /obj/item/organ/external/chest),
BP_GROIN = list("path" = /obj/item/organ/external/groin),
BP_HEAD = list("path" = /obj/item/organ/external/head),
BP_L_ARM = list("path" = /obj/item/organ/external/arm),
BP_R_ARM = list("path" = /obj/item/organ/external/arm/right),
BP_L_LEG = list("path" = /obj/item/organ/external/leg),
BP_R_LEG = list("path" = /obj/item/organ/external/leg/right),
BP_L_HAND = list("path" = /obj/item/organ/external/hand),
BP_R_HAND = list("path" = /obj/item/organ/external/hand/right),
BP_L_FOOT = list("path" = /obj/item/organ/external/foot),
BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right)
)
// limited organs, 'cause they're simple
has_organ = list(
O_LIVER = /obj/item/organ/internal/liver/alraune,
O_KIDNEYS = /obj/item/organ/internal/kidneys/alraune,
O_BRAIN = /obj/item/organ/internal/brain/alraune,
O_EYES = /obj/item/organ/internal/eyes/alraune,
)
/datum/species/alraune/can_breathe_water()
return TRUE //eh, why not? Aquatic plants are a thing.
/datum/species/alraune/handle_environment_special(var/mob/living/carbon/human/H)
if(H.inStasisNow()) // if they're in stasis, they won't need this stuff.
return
//setting these here 'cause ugh the defines for life are in the wrong place to compile properly
//set them back to HUMAN_MAX_OXYLOSS if we move the life defines to the defines folder at any point
var/ALRAUNE_MAX_OXYLOSS = 1 //Defines how much oxyloss humans can get per tick. A tile with no air at all (such as space) applies this value, otherwise it's a percentage of it.
var/ALRAUNE_CRIT_MAX_OXYLOSS = ( 2.0 / 6) //The amount of damage you'll get when in critical condition. We want this to be a 5 minute deal = 300s. There are 50HP to get through, so (1/6)*last_tick_duration per second. Breaths however only happen every 4 ticks. last_tick_duration = ~2.0 on average
//They don't have lungs so breathe() will just return. Instead, they breathe through their skin.
//This is mostly normal breath code with some tweaks that apply to their particular biology.
var/datum/gas_mixture/breath = null
var/fullysealed = FALSE //if they're wearing a fully sealed suit, their internals take priority.
var/environmentalair = FALSE //if no sealed suit, internals take priority in low pressure environements
if(H.wear_suit && (H.wear_suit.item_flags & STOPPRESSUREDAMAGE) && H.head && (H.head.item_flags & STOPPRESSUREDAMAGE))
fullysealed = TRUE
else // find out if local gas mixture is enough to override use of internals
var/datum/gas_mixture/environment = H.loc.return_air()
var/envpressure = environment.return_pressure()
if(envpressure >= hazard_low_pressure)
environmentalair = TRUE
if(fullysealed || !environmentalair)
breath = H.get_breath_from_internal()
if(!breath) //No breath from internals so let's try to get air from our location
// cut-down version of get_breath_from_environment - notably, gas masks provide no benefit
var/datum/gas_mixture/environment2
if(H.loc)
environment2 = H.loc.return_air_for_internal_lifeform(H)
if(environment2)
breath = environment2.remove_volume(BREATH_VOLUME)
H.handle_chemical_smoke(environment2) //handle chemical smoke while we're at it
// NOW a crude copypasta of handle_breath. Leaving some things out that don't apply to plants.
if(H.does_not_breathe)
H.failed_last_breath = 0
H.adjustOxyLoss(-5)
return // if somehow they don't breathe, abort breathing.
if(!breath || (breath.total_moles == 0))
H.failed_last_breath = 1
if(H.health > config.health_threshold_crit)
H.adjustOxyLoss(ALRAUNE_MAX_OXYLOSS)
else
H.adjustOxyLoss(ALRAUNE_CRIT_MAX_OXYLOSS)
H.oxygen_alert = max(H.oxygen_alert, 1)
return // skip air processing if there's no air
// now into the good stuff
//var/safe_pressure_min = species.minimum_breath_pressure // Minimum safe partial pressure of breathable gas in kPa
//just replace safe_pressure_min with minimum_breath_pressure, no need to declare a new var
var/safe_exhaled_max = 10
var/safe_toxins_max = 0.2
var/SA_para_min = 1
var/SA_sleep_min = 5
var/inhaled_gas_used = 0
var/breath_pressure = (breath.total_moles*R_IDEAL_GAS_EQUATION*breath.temperature)/BREATH_VOLUME
var/inhaling
var/poison
var/exhaling
var/failed_inhale = 0
var/failed_exhale = 0
inhaling = breath.gas[breath_type]
poison = breath.gas[poison_type]
exhaling = breath.gas[exhale_type]
var/inhale_pp = (inhaling/breath.total_moles)*breath_pressure
var/toxins_pp = (poison/breath.total_moles)*breath_pressure
var/exhaled_pp = (exhaling/breath.total_moles)*breath_pressure
// Not enough to breathe
if((inhale_pp + exhaled_pp) < minimum_breath_pressure) //they can breathe either oxygen OR CO2
if(prob(20))
spawn(0) H.emote("gasp")
var/ratio = (inhale_pp + exhaled_pp)/minimum_breath_pressure
// Don't fuck them up too fast (space only does HUMAN_MAX_OXYLOSS (1) after all!)
H.adjustOxyLoss(max(ALRAUNE_MAX_OXYLOSS*(1-ratio), 0))
failed_inhale = 1
H.oxygen_alert = max(H.oxygen_alert, 1)
else
// We're in safe limits
H.oxygen_alert = 0
inhaled_gas_used = inhaling/6
breath.adjust_gas(breath_type, -inhaled_gas_used, update = 0) //update afterwards
breath.adjust_gas_temp(exhale_type, inhaled_gas_used, H.bodytemperature, update = 0) //update afterwards
//Now we handle CO2.
if(inhale_pp > safe_exhaled_max * 0.7) // For a human, this would be too much exhaled gas in the air. But plants don't care.
H.co2_alert = 1 // Give them the alert on the HUD. They'll be aware when the good stuff is present.
else
H.co2_alert = 0
//do the CO2 buff stuff here
var/co2buff = 0
if(inhaling)
co2buff = (Clamp(inhale_pp, 0, minimum_breath_pressure))/minimum_breath_pressure //returns a value between 0 and 1.
var/light_amount = fullysealed ? H.getlightlevel() : H.getlightlevel()/5 // if they're covered, they're not going to get much light on them.
if(co2buff && !H.toxloss && light_amount >= 0.1) //if there's enough light and CO2 and you're not poisoned, heal. Note if you're wearing a sealed suit your heal rate will suck.
H.adjustBruteLoss(-(light_amount * co2buff * 2)) //at a full partial pressure of CO2 and full light, you'll only heal half as fast as diona.
H.adjustFireLoss(-(light_amount * co2buff)) //this won't let you tank environmental damage from fire. MAYBE cold until your body temp drops.
if(H.nutrition < (200 + 400*co2buff)) //if no CO2, a fully lit tile gives them 1/tick up to 200. With CO2, potentially up to 600.
H.nutrition += (light_amount*(1+co2buff*5))
// Too much poison in the air.
if(toxins_pp > safe_toxins_max)
var/ratio = (poison/safe_toxins_max) * 10
if(H.reagents)
H.reagents.add_reagent("toxin", Clamp(ratio, MIN_TOXIN_DAMAGE, MAX_TOXIN_DAMAGE))
breath.adjust_gas(poison_type, -poison/6, update = 0) //update after
H.phoron_alert = max(H.phoron_alert, 1)
else
H.phoron_alert = 0
// If there's some other shit in the air lets deal with it here.
if(breath.gas["sleeping_agent"])
var/SA_pp = (breath.gas["sleeping_agent"] / breath.total_moles) * breath_pressure
// Enough to make us paralysed for a bit
if(SA_pp > SA_para_min)
// 3 gives them one second to wake up and run away a bit!
H.Paralyse(3)
// Enough to make us sleep as well
if(SA_pp > SA_sleep_min)
H.Sleeping(5)
// There is sleeping gas in their lungs, but only a little, so give them a bit of a warning
else if(SA_pp > 0.15)
if(prob(20))
spawn(0) H.emote(pick("giggle", "laugh"))
breath.adjust_gas("sleeping_agent", -breath.gas["sleeping_agent"]/6, update = 0) //update after
// Were we able to breathe?
if (failed_inhale || failed_exhale)
H.failed_last_breath = 1
else
H.failed_last_breath = 0
H.adjustOxyLoss(-5)
// Hot air hurts :(
if((breath.temperature < breath_cold_level_1 || breath.temperature > breath_heat_level_1) && !(COLD_RESISTANCE in H.mutations))
if(breath.temperature <= breath_cold_level_1)
if(prob(20))
to_chat(H, "<span class='danger'>You feel icicles forming on your skin!</span>")
else if(breath.temperature >= breath_heat_level_1)
if(prob(20))
to_chat(H, "<span class='danger'>You feel yourself smouldering in the heat!</span>")
var/bodypart = pick(BP_L_FOOT,BP_R_FOOT,BP_L_LEG,BP_R_LEG,BP_L_ARM,BP_R_ARM,BP_L_HAND,BP_R_HAND,BP_TORSO,BP_GROIN,BP_HEAD)
if(breath.temperature >= breath_heat_level_1)
if(breath.temperature < breath_heat_level_2)
H.apply_damage(HEAT_GAS_DAMAGE_LEVEL_1, BURN, bodypart, used_weapon = "Excessive Heat")
H.fire_alert = max(H.fire_alert, 2)
else if(breath.temperature < breath_heat_level_3)
H.apply_damage(HEAT_GAS_DAMAGE_LEVEL_2, BURN, bodypart, used_weapon = "Excessive Heat")
H.fire_alert = max(H.fire_alert, 2)
else
H.apply_damage(HEAT_GAS_DAMAGE_LEVEL_3, BURN, bodypart, used_weapon = "Excessive Heat")
H.fire_alert = max(H.fire_alert, 2)
else if(breath.temperature <= breath_cold_level_1)
if(breath.temperature > breath_cold_level_2)
H.apply_damage(COLD_GAS_DAMAGE_LEVEL_1, BURN, bodypart, used_weapon = "Excessive Cold")
H.fire_alert = max(H.fire_alert, 1)
else if(breath.temperature > breath_cold_level_3)
H.apply_damage(COLD_GAS_DAMAGE_LEVEL_2, BURN, bodypart, used_weapon = "Excessive Cold")
H.fire_alert = max(H.fire_alert, 1)
else
H.apply_damage(COLD_GAS_DAMAGE_LEVEL_3, BURN, bodypart, used_weapon = "Excessive Cold")
H.fire_alert = max(H.fire_alert, 1)
//breathing in hot/cold air also heats/cools you a bit
var/temp_adj = breath.temperature - H.bodytemperature
if (temp_adj < 0)
temp_adj /= (BODYTEMP_COLD_DIVISOR * 5) //don't raise temperature as much as if we were directly exposed
else
temp_adj /= (BODYTEMP_HEAT_DIVISOR * 5) //don't raise temperature as much as if we were directly exposed
var/relative_density = breath.total_moles / (MOLES_CELLSTANDARD * BREATH_PERCENTAGE)
temp_adj *= relative_density
if (temp_adj > BODYTEMP_HEATING_MAX) temp_adj = BODYTEMP_HEATING_MAX
if (temp_adj < BODYTEMP_COOLING_MAX) temp_adj = BODYTEMP_COOLING_MAX
//world << "Breath: [breath.temperature], [src]: [bodytemperature], Adjusting: [temp_adj]"
H.bodytemperature += temp_adj
else if(breath.temperature >= heat_discomfort_level)
get_environment_discomfort(src,"heat")
else if(breath.temperature <= cold_discomfort_level)
get_environment_discomfort(src,"cold")
breath.update_values()
return 1
/obj/item/organ/internal/brain/alraune
icon = 'icons/mob/species/alraune/organs.dmi'
icon_state = "neurostroma"
name = "neuro-stroma"
desc = "A knot of fibrous plant matter."
parent_organ = BP_TORSO // brains in their core
/obj/item/organ/internal/eyes/alraune
icon = 'icons/mob/species/alraune/organs.dmi'
icon_state = "photoreceptors"
name = "photoreceptors"
desc = "Bulbous and fleshy plant matter."
/obj/item/organ/internal/kidneys/alraune
icon = 'icons/mob/species/alraune/organs.dmi'
icon_state = "rhyzofilter"
name = "rhyzofilter"
desc = "A tangle of root nodules."
/obj/item/organ/internal/liver/alraune
icon = 'icons/mob/species/alraune/organs.dmi'
icon_state = "phytoextractor"
name = "phytoextractor"
desc = "A bulbous gourd-like structure."
+2 -1
View File
@@ -1,10 +1,11 @@
/mob/living/carbon/proc/ingest(var/datum/reagents/from, var/datum/reagents/target, var/amount = 1, var/multiplier = 1, var/copy = 0) //we kind of 'sneak' a proc in here for ingesting stuff so we can play with it.
/* VOREStation Removal - Synths should be able to taste because... reasons
if(ishuman(src))
var/mob/living/carbon/human/H = src
var/braintype = H.get_FBP_type()
if(braintype == FBP_DRONE || braintype == FBP_POSI)
return from.trans_to_holder(target,amount,multiplier,copy) //skip the taste, complete transfer
*/
if(last_taste_time + 50 < world.time)
var/datum/reagents/temp = new(amount) //temporary holder used to analyse what gets transfered.
from.trans_to_holder(temp, amount, multiplier, 1)
+3
View File
@@ -693,6 +693,9 @@ var/list/ai_verbs_default = list(
card.grab_ai(src, user)
else if(istype(W, /obj/item/weapon/wrench))
if(user == controlling_drone)
to_chat(user, "<span class='notice'>The drone's subsystems resist your efforts to tamper with your bolts.</span>")
return
if(anchored)
playsound(src, W.usesound, 50, 1)
user.visible_message("<font color='blue'>\The [user] starts to unbolt \the [src] from the plating...</font>")
@@ -3,6 +3,10 @@
if(stat == DEAD)
return
if(controlling_drone)
controlling_drone.release_ai_control("<b>WARNING: Primary control loop failure.</b> Session terminated.")
. = ..(gibbed)
if(src.eyeobj)
src.eyeobj.setLoc(get_turf(src))
@@ -8,6 +8,8 @@
if (src.stat!=CONSCIOUS)
src.cameraFollow = null
src.reset_view(null)
if(controlling_drone)
controlling_drone.release_ai_control("<b>WARNING: Primary control loop failure.</b> Session terminated.")
src.updatehealth()
@@ -19,7 +19,7 @@ var/list/mob_hat_cache = list()
return mob_hat_cache[key]
/mob/living/silicon/robot/drone
name = "drone"
name = "maintenance drone"
real_name = "drone"
icon = 'icons/mob/robots.dmi'
icon_state = "repairbot"
@@ -57,6 +57,8 @@ var/list/mob_hat_cache = list()
var/obj/item/hat
var/hat_x_offset = 0
var/hat_y_offset = -13
var/serial_number = 0
var/name_override = 0
holder_type = /obj/item/weapon/holder/drone
@@ -71,6 +73,7 @@ var/list/mob_hat_cache = list()
return FALSE
/mob/living/silicon/robot/drone/construction
name = "construction drone"
icon_state = "constructiondrone"
law_type = /datum/ai_laws/construction_drone
module_type = /obj/item/weapon/robot_module/drone/construction
@@ -95,6 +98,7 @@ var/list/mob_hat_cache = list()
remove_language("Robot Talk")
add_language("Robot Talk", 0)
add_language("Drone Talk", 1)
serial_number = rand(0,999)
//They are unable to be upgraded, so let's give them a bit of a better battery.
cell.maxcharge = 10000
@@ -127,14 +131,22 @@ var/list/mob_hat_cache = list()
name = real_name
/mob/living/silicon/robot/drone/updatename()
real_name = "maintenance drone ([rand(100,999)])"
if(name_override)
return
if(controlling_ai)
real_name = "remote drone ([controlling_ai])"
else
real_name = "[initial(name)] ([serial_number])"
name = real_name
/mob/living/silicon/robot/drone/updateicon()
overlays.Cut()
if(stat == 0)
overlays += "eyes-[icon_state]"
if(controlling_ai)
overlays += "eyes-[icon_state]-ai"
else
overlays += "eyes-[icon_state]"
else
overlays -= "eyes"
if(hat) // Let the drones wear hats.
@@ -213,15 +225,18 @@ var/list/mob_hat_cache = list()
return
if(emagged)
to_chat(user, "<span class='danger'>\The [user] attempts to load subversive software into you, but your hacked subroutines ignore the attempt.</span>")
to_chat(src, "<span class='danger'>\The [user] attempts to load subversive software into you, but your hacked subroutines ignore the attempt.</span>")
to_chat(user, "<span class='danger'>You attempt to subvert [src], but the sequencer has no effect.</span>")
return
to_chat(user, "<span class='danger'>You swipe the sequencer across [src]'s interface and watch its eyes flicker.</span>")
to_chat(user, "<span class='danger'>You feel a sudden burst of malware loaded into your execute-as-root buffer. Your tiny brain methodically parses, loads and executes the script.</span>")
message_admins("[key_name_admin(user)] emagged drone [key_name_admin(src)]. Laws overridden.")
log_game("[key_name(user)] emagged drone [key_name(src)]. Laws overridden.")
if(controlling_ai)
to_chat(src, "<span class='danger'>\The [user] loads some kind of subversive software into the remote drone, corrupting its lawset but luckily sparing yours.</span>")
else
to_chat(src, "<span class='danger'>You feel a sudden burst of malware loaded into your execute-as-root buffer. Your tiny brain methodically parses, loads and executes the script.</span>")
log_game("[key_name(user)] emagged drone [key_name(src)][controlling_ai ? " but AI [key_name(controlling_ai)] is in remote control" : " Laws overridden"].")
var/time = time2text(world.realtime,"hh:mm:ss")
lawchanges.Add("[time] <B>:</B> [user.name]([user.key]) emagged [name]([key])")
@@ -234,9 +249,10 @@ var/list/mob_hat_cache = list()
var/datum/gender/TU = gender_datums[user.get_visible_gender()]
set_zeroth_law("Only [user.real_name] and people [TU.he] designate[TU.s] as being such are operatives.")
src << "<b>Obey these laws:</b>"
laws.show_laws(src)
src << "<span class='danger'>ALERT: [user.real_name] [TU.is] your new master. Obey your new laws and [TU.his] commands.</span>"
if(!controlling_ai)
to_chat(src, "<b>Obey these laws:</b>")
laws.show_laws(src)
to_chat(src, "<span class='danger'>ALERT: [user.real_name] is your new master. Obey your new laws and \his commands.</span>")
return 1
//DRONE LIFE/DEATH
@@ -262,26 +278,41 @@ var/list/mob_hat_cache = list()
return
..()
/mob/living/silicon/robot/drone/death(gibbed)
if(controlling_ai)
release_ai_control("<b>WARNING: remote system failure.</b> Connection timed out.")
. = ..(gibbed)
//DRONE MOVEMENT.
/mob/living/silicon/robot/drone/Process_Spaceslipping(var/prob_slip)
return 0
//CONSOLE PROCS
/mob/living/silicon/robot/drone/proc/law_resync()
if(controlling_ai)
to_chat(src, "<span class='warning'>Someone issues a remote law reset order for this unit, but you disregard it.</span>")
return
if(stat != 2)
if(emagged)
src << "<span class='danger'>You feel something attempting to modify your programming, but your hacked subroutines are unaffected.</span>"
to_chat(src, "<span class='danger'>You feel something attempting to modify your programming, but your hacked subroutines are unaffected.</span>")
else
src << "<span class='danger'>A reset-to-factory directive packet filters through your data connection, and you obediently modify your programming to suit it.</span>"
to_chat(src, "<span class='danger'>A reset-to-factory directive packet filters through your data connection, and you obediently modify your programming to suit it.</span>")
full_law_reset()
show_laws()
/mob/living/silicon/robot/drone/proc/shut_down()
if(controlling_ai && mind.special_role)
to_chat(src, "<span class='warning'>Someone issued a remote kill order for this unit, but you disregard it.</span>")
return
if(stat != 2)
if(emagged)
src << "<span class='danger'>You feel a system kill order percolate through your tiny brain, but it doesn't seem like a good idea to you.</span>"
to_chat(src, "<span class='danger'>You feel a system kill order percolate through [controlling_ai ? "the drones" : "your"] tiny brain, but it doesn't seem like a good idea to [controlling_ai ? "it" : "you"].</span>")
else
src << "<span class='danger'>You feel a system kill order percolate through your tiny brain, and you obediently destroy yourself.</span>"
to_chat(src, "<span class='danger'>You feel a system kill order percolate through [controlling_ai ? "the drones" : "your"] tiny brain, and [controlling_ai ? "it" : "you"] obediently destroy[controlling_ai ? "s itself" : " yourself"].</span>")
death()
/mob/living/silicon/robot/drone/proc/full_law_reset()
@@ -290,6 +321,21 @@ var/list/mob_hat_cache = list()
clear_ion_laws(1)
laws = new law_type
/mob/living/silicon/robot/drone/show_laws(var/everyone = 0)
if(!controlling_ai)
return..()
to_chat(src, "<b>Obey these laws:</b>")
controlling_ai.laws_sanity_check()
controlling_ai.laws.show_laws(src)
/mob/living/silicon/robot/drone/robot_checklaws()
set category = "Silicon Commands"
set name = "State Laws"
if(!controlling_ai)
return ..()
controlling_ai.subsystem_law_manager()
//Reboot procs.
/mob/living/silicon/robot/drone/proc/request_player()
@@ -347,14 +393,6 @@ var/list/mob_hat_cache = list()
..()
flavor_text = "It's a bulky construction drone stamped with a Sol Central glyph."
/mob/living/silicon/robot/drone/construction/updatename()
real_name = "construction drone ([rand(100,999)])"
name = real_name
/mob/living/silicon/robot/drone/mining/init()
..()
flavor_text = "It's a bulky mining drone stamped with a Grayson logo."
/mob/living/silicon/robot/drone/mining/updatename()
real_name = "mining drone ([rand(100,999)])"
name = real_name
@@ -75,20 +75,22 @@
if(!produce_drones || !config.allow_drone_spawn || count_drones() >= config.max_maint_drones)
return
if(!player || !istype(player.mob,/mob/observer/dead))
if(player && !istype(player.mob,/mob/observer/dead))
return
announce_ghost_joinleave(player, 0, "They have taken control over a maintenance drone.")
visible_message("\The [src] churns and grinds as it lurches into motion, disgorging a shiny new drone after a few moments.")
flick("h_lathe_leave",src)
drone_progress = 0
time_last_drone = world.time
if(player.mob && player.mob.mind) player.mob.mind.reset()
var/mob/living/silicon/robot/drone/new_drone = new drone_type(get_turf(src))
new_drone.transfer_personality(player)
new_drone.master_fabricator = src
drone_progress = 0
var/mob/living/silicon/robot/drone/new_drone = new drone_type(get_turf(src))
if(player)
announce_ghost_joinleave(player, 0, "They have taken control over a maintenance drone.")
if(player.mob && player.mob.mind) player.mob.mind.reset()
new_drone.transfer_personality(player)
return new_drone
/mob/observer/dead/verb/join_as_drone()
@@ -0,0 +1,104 @@
/mob/living/silicon/ai
var/mob/living/silicon/robot/drone/controlling_drone
/mob/living/silicon/robot/drone
var/mob/living/silicon/ai/controlling_ai
/mob/living/silicon/robot/drone/attack_ai(var/mob/living/silicon/ai/user)
if(!istype(user) || controlling_ai || !config.allow_drone_spawn || !config.allow_ai_drones)
return
if(client || key)
to_chat(user, "<span class='warning'>You cannot take control of an autonomous, active drone.</span>")
return
if(health < -35 || emagged)
to_chat(user, "<span class='notice'><b>WARNING:</b> connection timed out.</span>")
return
user.controlling_drone = src
user.teleop = src
radio.channels = user.aiRadio.keyslot2.channels
controlling_ai = user
verbs += /mob/living/silicon/robot/drone/proc/release_ai_control_verb
local_transmit = FALSE
languages = controlling_ai.languages.Copy()
speech_synthesizer_langs = controlling_ai.speech_synthesizer_langs.Copy()
stat = CONSCIOUS
if(user.mind)
user.mind.transfer_to(src)
else
key = user.key
updatename()
to_chat(src, "<span class='notice'><b>You have shunted your primary control loop into \a [initial(name)].</b> Use the <b>Release Control</b> verb to return to your core.</span>")
/obj/machinery/drone_fabricator/attack_ai(var/mob/living/silicon/ai/user as mob)
if(!istype(user) || user.controlling_drone || !config.allow_drone_spawn || !config.allow_ai_drones)
return
if(stat & NOPOWER)
to_chat(user, "<span class='warning'>\The [src] is unpowered.</span>")
return
if(!produce_drones)
to_chat(user, "<span class='warning'>\The [src] is disabled.</span>")
return
if(drone_progress < 100)
to_chat(user, "<span class='warning'>\The [src] is not ready to produce a new drone.</span>")
return
if(count_drones() >= config.max_maint_drones)
to_chat(user, "<span class='warning'>The drone control subsystems are tasked to capacity; they cannot support any more drones.</span>")
return
var/mob/living/silicon/robot/drone/new_drone = create_drone()
user.controlling_drone = new_drone
user.teleop = new_drone
new_drone.radio.channels = user.aiRadio.keyslot2.channels
new_drone.controlling_ai = user
new_drone.verbs += /mob/living/silicon/robot/drone/proc/release_ai_control_verb
new_drone.local_transmit = FALSE
new_drone.languages = new_drone.controlling_ai.languages.Copy()
new_drone.speech_synthesizer_langs = new_drone.controlling_ai.speech_synthesizer_langs.Copy()
if(user.mind)
user.mind.transfer_to(new_drone)
else
new_drone.key = user.key
new_drone.updatename()
to_chat(new_drone, "<span class='notice'><b>You have shunted your primary control loop into \a [initial(new_drone.name)].</b> Use the <b>Release Control</b> verb to return to your core.</span>")
/mob/living/silicon/robot/drone/proc/release_ai_control_verb()
set name = "Release Control"
set desc = "Release control of a remote drone."
set category = "Silicon Commands"
release_ai_control("Remote session terminated.")
/mob/living/silicon/robot/drone/proc/release_ai_control(var/message = "Connection terminated.")
if(controlling_ai)
if(mind)
mind.transfer_to(controlling_ai)
else
controlling_ai.key = key
to_chat(controlling_ai, "<span class='notice'>[message]</span>")
controlling_ai.controlling_drone = null
controlling_ai.teleop = null
controlling_ai = null
radio.channels = module.channels
verbs -= /mob/living/silicon/robot/drone/proc/release_ai_control_verb
languages = initial(languages)
speech_synthesizer_langs = initial(speech_synthesizer_langs)
remove_language("Robot Talk")
add_language("Robot Talk", 0)
add_language("Drone Talk", 1)
local_transmit = TRUE
full_law_reset()
updatename()
death()
@@ -114,6 +114,8 @@
var/obj/structure/closet/crate/C = new(get_turf(src))
// Put loot in crate
for(var/obj/O in src)
if(isbelly(O)) //VOREStation edit
continue
O.forceMove(C)
..()
@@ -146,6 +148,8 @@ var/global/list/protected_objects = list(/obj/structure/table, /obj/structure/ca
/mob/living/simple_animal/hostile/mimic/copy/death()
for(var/atom/movable/M in src)
if(isbelly(M)) //VOREStation edit
continue
M.forceMove(get_turf(src))
..()
+1 -1
View File
@@ -451,7 +451,7 @@
if(!silent)
if(planetary)
visible_message("<span class='danger'><font size='3'>\A [src] falls out of the sky and crashes into \the [landing]!</font></span>", \
"<span class='danger'><font size='3'> You fall out of the skiy and crash into \the [landing]!</font></span>", \
"<span class='danger'><font size='3'> You fall out of the sky and crash into \the [landing]!</font></span>", \
"You hear something slam into \the [landing].")
var/turf/T = get_turf(landing)
explosion(T, 0, 1, 2)
+1 -1
View File
@@ -50,7 +50,7 @@
// Now sync the organ's eye_colour list.
update_colour()
// Finally, update the eye icon on the mob.
owner.update_eyes()
owner.regenerate_icons()
/obj/item/organ/internal/eyes/replaced(var/mob/living/carbon/human/target)
+2
View File
@@ -1105,6 +1105,8 @@ Note that amputating the affected organ does in fact remove the infection from t
R = basic_robolimb
if(R)
force_icon = R.icon
brute_mod *= R.robo_brute_mod
burn_mod *= R.robo_burn_mod
if(R.lifelike)
robotic = ORGAN_LIFELIKE
name = "[initial(name)]"
+7 -7
View File
@@ -4,13 +4,13 @@ var/global/list/limb_icon_cache = list()
return
/obj/item/organ/external/proc/compile_icon()
overlays.Cut()
cut_overlays()
// This is a kludge, only one icon has more than one generation of children though.
for(var/obj/item/organ/external/organ in contents)
if(organ.children && organ.children.len)
for(var/obj/item/organ/external/child in organ.children)
overlays += child.mob_icon
overlays += organ.mob_icon
add_overlay(organ.mob_icon)
/obj/item/organ/external/proc/sync_colour_to_human(var/mob/living/carbon/human/human)
s_tone = null
@@ -94,7 +94,7 @@ var/global/list/limb_icon_cache = list()
mob_icon.Blend(mark_s, ICON_OVERLAY) //So when it's on your body, it has icons
icon_cache_key += "[M][markings[M]["color"]]"
overlays |= get_hair_icon()
add_overlay(get_hair_icon())
return mob_icon
@@ -107,7 +107,7 @@ var/global/list/limb_icon_cache = list()
var/icon/facial_s = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_s")
if(facial_hair_style.do_colouration)
facial_s.Blend(rgb(owner.r_facial, owner.g_facial, owner.b_facial), ICON_MULTIPLY) // VOREStation edit
add_overlay(facial_s)
res.add_overlay(facial_s)
//Head hair
if(owner.h_style && !(owner.head && (owner.head.flags_inv & BLOCKHEADHAIR)))
@@ -122,7 +122,7 @@ var/global/list/limb_icon_cache = list()
if(hair_style.do_colouration && islist(h_col) && h_col.len >= 3)
hair_s.Blend(rgb(h_col[1], h_col[2], h_col[3]), ICON_MULTIPLY)
hair_s.Blend(hair_s_add, ICON_ADD)
res.overlays |= hair_s
res.add_overlay(hair_s)
return res
@@ -164,7 +164,7 @@ var/global/list/limb_icon_cache = list()
var/datum/sprite_accessory/marking/mark_style = markings[M]["datum"]
var/icon/mark_s = new/icon("icon" = mark_style.icon, "icon_state" = "[mark_style.icon_state]-[organ_tag]")
mark_s.Blend(markings[M]["color"], mark_style.color_blend_mode) // VOREStation edit
overlays |= mark_s //So when it's not on your body, it has icons
add_overlay(mark_s) //So when it's not on your body, it has icons
mob_icon.Blend(mark_s, ICON_OVERLAY) //So when it's on your body, it has icons
icon_cache_key += "[M][markings[M]["color"]]"
@@ -280,7 +280,7 @@ var/list/robot_hud_colours = list("#CFCFCF","#AFAFAF","#8F8F8F","#6F6F6F","#4F4F
var/b = 0.11 * R.health_hud_intensity
temp.color = list(r, r, r, g, g, g, b, b, b)
hud_damage_image = image(null)
hud_damage_image.overlays += temp
hud_damage_image.add_overlay(temp)
// Calculate the required color index.
var/dam_state = min(1,((brute_dam+burn_dam)/max_damage))
+5
View File
@@ -49,6 +49,9 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\
var/suggested_species = "Human" //If it should make the torso a species
var/speech_bubble_appearance = "synthetic" // What icon_state to use for speech bubbles when talking. Check talk.dmi for all the icons.
var/robo_brute_mod = 1 // Multiplier for incoming brute damage.
var/robo_burn_mod = 1 // As above for burn.
/datum/robolimb/unbranded_monitor
company = "Unbranded Monitor"
desc = "A generic unbranded interpretation of a popular prosthetic head model. It looks rudimentary and cheaply constructed."
@@ -214,6 +217,8 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\
skin_tone = 1
blood_color = "#CCCCCC"
speech_bubble_appearance = "normal"
//robo_brute_mod = 1.1 //VOREStation Edit
//robo_burn_mod = 1.1 //VOREStation Edit
/datum/robolimb/wardtakahashi
company = "Ward-Takahashi"
+3 -2
View File
@@ -30,9 +30,10 @@
current_time = current_time.make_random_time()
update_sun()
/datum/planet/proc/process(amount)
/datum/planet/proc/process(last_fire)
if(current_time)
current_time = current_time.add_seconds(amount)
var/difference = world.time - last_fire
current_time = current_time.add_seconds(difference SECONDS)
update_weather() // We update this first, because some weather types decease the brightness of the sun.
if(sun_last_process <= world.time - sun_process_interval)
update_sun()
+29 -9
View File
@@ -184,7 +184,8 @@ datum/weather/sif
)
/datum/weather/sif/snow/process_effects()
for(var/turf/simulated/floor/outdoors/snow/S in outdoor_turfs)
..()
for(var/turf/simulated/floor/outdoors/snow/S in SSplanets.new_outdoor_turfs) //This didn't make any sense before SSplanets, either
if(S.z in holder.our_planet.expected_z_levels)
for(var/dir_checked in cardinal)
var/turf/simulated/floor/T = get_step(S, dir_checked)
@@ -207,7 +208,8 @@ datum/weather/sif
)
/datum/weather/sif/blizzard/process_effects()
for(var/turf/simulated/floor/outdoors/snow/S in outdoor_turfs)
..()
for(var/turf/simulated/floor/outdoors/snow/S in SSplanets.new_outdoor_turfs) //This didn't make any sense before SSplanets, either
if(S.z in holder.our_planet.expected_z_levels)
for(var/dir_checked in cardinal)
var/turf/simulated/floor/T = get_step(S, dir_checked)
@@ -219,6 +221,8 @@ datum/weather/sif
name = "rain"
icon_state = "rain"
light_modifier = 0.5
effect_message = "<span class='warning'>Rain falls on you.</span>"
transition_chances = list(
WEATHER_OVERCAST = 25,
WEATHER_LIGHT_SNOW = 10,
@@ -228,6 +232,7 @@ datum/weather/sif
)
/datum/weather/sif/rain/process_effects()
..()
for(var/mob/living/L in living_mob_list)
if(L.z in holder.our_planet.expected_z_levels)
var/turf/T = get_turf(L)
@@ -238,16 +243,19 @@ datum/weather/sif
if(istype(L.get_active_hand(), /obj/item/weapon/melee/umbrella))
var/obj/item/weapon/melee/umbrella/U = L.get_active_hand()
if(U.open)
to_chat(L, "<span class='notice'>Rain patters softly onto your umbrella</span>")
if(show_message)
to_chat(L, "<span class='notice'>Rain patters softly onto your umbrella</span>")
continue
else if(istype(L.get_inactive_hand(), /obj/item/weapon/melee/umbrella))
var/obj/item/weapon/melee/umbrella/U = L.get_inactive_hand()
if(U.open)
to_chat(L, "<span class='notice'>Rain patters softly onto your umbrella</span>")
if(show_message)
to_chat(L, "<span class='notice'>Rain patters softly onto your umbrella</span>")
continue
L.water_act(1)
to_chat(L, "<span class='warning'>Rain falls on you.</span>")
if(show_message)
to_chat(L, effect_message)
/datum/weather/sif/storm
name = "storm"
@@ -256,6 +264,8 @@ datum/weather/sif
temp_low = 233.15 // -40c
light_modifier = 0.3
flight_failure_modifier = 10
transition_chances = list(
WEATHER_RAIN = 45,
WEATHER_STORM = 40,
@@ -264,6 +274,7 @@ datum/weather/sif
)
/datum/weather/sif/storm/process_effects()
..()
for(var/mob/living/L in living_mob_list)
if(L.z in holder.our_planet.expected_z_levels)
var/turf/T = get_turf(L)
@@ -294,6 +305,10 @@ datum/weather/sif
temp_low = 243.15 // -30c
light_modifier = 0.3
flight_failure_modifier = 15
timer_low_bound = 2
timer_high_bound = 5
effect_message = "<span class='warning'>The hail smacks into you!</span>"
transition_chances = list(
WEATHER_RAIN = 45,
WEATHER_STORM = 40,
@@ -302,6 +317,7 @@ datum/weather/sif
)
/datum/weather/sif/hail/process_effects()
..()
for(var/mob/living/carbon/human/H in living_mob_list)
if(H.z in holder.our_planet.expected_z_levels)
var/turf/T = get_turf(H)
@@ -309,15 +325,18 @@ datum/weather/sif
continue // They're indoors, so no need to pelt them with ice.
// If they have an open umbrella, it'll guard from rain
// Message plays every time the umbrella gets stolen, just so they're especially aware of what's happening
if(istype(H.get_active_hand(), /obj/item/weapon/melee/umbrella))
var/obj/item/weapon/melee/umbrella/U = H.get_active_hand()
if(U.open)
to_chat(H, "<span class='notice'>Hail patters gently onto your umbrella.</span>")
if(show_message)
to_chat(H, "<span class='notice'>Hail patters gently onto your umbrella.</span>")
continue
else if(istype(H.get_inactive_hand(), /obj/item/weapon/melee/umbrella))
var/obj/item/weapon/melee/umbrella/U = H.get_inactive_hand()
if(U.open)
to_chat(H, "<span class='notice'>Hail patters gently onto your umbrella.</span>")
if(show_message)
to_chat(H, "<span class='notice'>Hail patters gently onto your umbrella.</span>")
continue
var/target_zone = pick(BP_ALL)
@@ -330,8 +349,9 @@ datum/weather/sif
if(amount_soaked >= 10)
continue // No need to apply damage.
H.apply_damage(rand(5, 10), BRUTE, target_zone, amount_blocked, amount_soaked, used_weapon = "hail")
to_chat(H, "<span class='warning'>The hail smacks into you!</span>")
H.apply_damage(rand(1, 3), BRUTE, target_zone, amount_blocked, amount_soaked, used_weapon = "hail")
if(show_message)
to_chat(H, effect_message)
/datum/weather/sif/blood_moon
name = "blood moon"
+13 -1
View File
@@ -25,7 +25,7 @@
if(current_weather)
old_light_modifier = current_weather.light_modifier // We store the old one, so we can determine if recalculating the sun is needed.
current_weather = allowed_weather_types[new_weather]
next_weather_shift = world.time + rand(20, 30) MINUTES
next_weather_shift = world.time + rand(current_weather.timer_low_bound, current_weather.timer_high_bound) MINUTES
update_icon_effects()
update_temperature()
@@ -66,8 +66,20 @@
var/flight_failure_modifier = 0 // Some types of weather make flying harder, and therefore make crashes more likely.
var/transition_chances = list() // Assoc list
var/datum/weather_holder/holder = null
var/timer_low_bound = 5 // How long this weather must run before it tries to change, in minutes
var/timer_high_bound = 10 // How long this weather can run before it tries to change, in minutes
var/effect_message = null // Should be a string, this is what is shown to a mob caught in the weather
var/last_message = 0 // Keeps track of when the weather last tells EVERY player it's hitting them
var/message_delay = 10 SECONDS // Delay in between weather hit messages
var/show_message = FALSE // Is set to TRUE and plays the messsage every [message_delay]
/datum/weather/proc/process_effects()
show_message = FALSE // Need to reset the show_message var, just in case
if(effect_message) // Only bother with the code below if we actually need to display something
if(world.time >= last_message + message_delay)
last_message = world.time // Reset the timer
show_message = TRUE // Tell the rest of the process that we need to make a message
return
// All this does is hold the weather icon.
@@ -909,9 +909,9 @@
cup_icon_state = "cup_coffee"
cup_name = "cup of coffee"
cup_desc = "Don't drop it, or you'll send scalding liquid and porcelain shards everywhere."
cup_desc = "Don't drop it, or you'll send scalding liquid and ceramic shards everywhere."
glass_name = "cup of coffee"
glass_name = "coffee"
glass_desc = "Don't drop it, or you'll send scalding liquid and glass shards everywhere."
+1 -2
View File
@@ -5,8 +5,7 @@
desc = "..."
icon = 'icons/obj/objects.dmi'
icon_state = "watertank"
plane = TURF_PLANE
layer = TABLE_LAYER // Above catwalks, hopefully below other things
layer = TABLE_LAYER
density = 1
anchored = 0
pressure_resistance = 2*ONE_ATMOSPHERE
@@ -88,16 +88,58 @@
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
/datum/sprite_accessory/ears/curly_bug
name = "curly antennae, colorable"
desc = ""
icon_state = "curly_bug"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
/datum/sprite_accessory/ears/dual_robot
name = "synth antennae, colorable"
desc = ""
icon_state = "dual_robot_antennae"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
/datum/sprite_accessory/ears/right_robot
name = "right synth, colorable"
desc = ""
icon_state = "right_robot_antennae"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
/datum/sprite_accessory/ears/left_robot
name = "left synth, colorable"
desc = ""
icon_state = "left_robot_antennae"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
/datum/sprite_accessory/ears/oni_h1
name = "oni horns"
desc = ""
icon_state = "oni-h1"
/datum/sprite_accessory/ears/oni_h1_c
name = "oni horns, colorable"
desc = ""
icon_state = "oni-h1_c"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
/datum/sprite_accessory/ears/demon_horns1
name = "demon horns"
desc = ""
icon_state = "demon-horns1"
/datum/sprite_accessory/ears/demon_horns1_c
name = "demon horns, colorable"
desc = ""
icon_state = "demon-horns1_c"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
/datum/sprite_accessory/ears/demon_horns2
name = "demon horns, colorable(outward)"
desc = ""
@@ -105,6 +147,13 @@
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
/datum/sprite_accessory/ears/dragon_horns
name = "dragon horns, colorable"
desc = ""
icon_state = "dragon-horns"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
/datum/sprite_accessory/ears/foxears
name = "highlander zorren ears"
desc = ""
@@ -413,6 +462,7 @@
desc = ""
icon_state = "spider-legs"
color_blend_mode = ICON_MULTIPLY
/datum/sprite_accessory/wing/moth
name = "moth wings"
desc = ""
@@ -682,12 +732,14 @@
icon_state = "fantail"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
/datum/sprite_accessory/tail/wagtail
name = "avian wagtail, colorable"
desc = ""
icon_state = "wagtail"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
/datum/sprite_accessory/tail/crossfox
name = "cross fox"
desc = ""
+5
View File
@@ -578,6 +578,11 @@
if(!(content in src) || !istype(target))
return
content.forceMove(target)
if(isitem(content))
var/obj/item/I = content
if(I.gurgled && (target.mode_flags & DM_FLAG_ITEMWEAK))
I.decontaminate()
I.gurgle_contaminate(target.contents, target.cont_flavor)
items_preserved -= content
if(!silent && target.vore_sound && !recent_sound)
var/soundfile = vore_sounds[target.vore_sound]
@@ -217,6 +217,13 @@
/obj/item/clothing/gloves/fluff/morsleeves,
/obj/item/clothing/under/fluff/morunder)
// Mewchild: Phi Vietsi
/obj/item/weapon/storage/box/fluff/vietsi
name = "Phi's Personal Items"
desc = "A small box containing Phi's small things"
has_items = list(
/obj/item/clothing/accessory/medal/bronze_heart,
/obj/item/clothing/gloves/ring/seal/signet/fluff/vietsi)
/*
Swimsuits, for general use, to avoid arriving to work with your swimsuit.
@@ -1680,9 +1680,10 @@ Departamental Swimsuits, for general use
//Mewchild: Phi Vietsi
/obj/item/clothing/gloves/ring/seal/signet/fluff/vietsi
name = "signet ring"
desc = "A signet ring carved from the bones of something long extinct, as a ward against bad luck."
name = "Phi Vietsi's Bone Signet Ring"
desc = "A signet ring belonging to Phi Vietsi, carved from the bones of something long extinct, as a ward against bad luck."
var/signet_name = "Phi Vietsi"
icon = 'icons/vore/custom_clothes_vr.dmi'
icon_state = "vietsi_ring"
+1 -1
View File
@@ -534,7 +534,7 @@ item_path: /obj/item/weapon/implanter/reagent_generator/savannah
{
ckey: mewchild
character_name: Phi Vietsi
item_path: /obj/item/clothing/gloves/ring/seal/signet/fluff/vietsi
item_path: /obj/item/weapon/storage/box/fluff/vietsi
}
{
+1
View File
@@ -6,3 +6,4 @@ suicidalpickles - mime
whiskyrose - clown
tinybear16 - clown
chargae - mime
verkister - clown
@@ -0,0 +1,37 @@
################################
# Example Changelog File
#
# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
#
# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
# When it is, any changes listed below will disappear.
#
# Valid Prefixes:
# bugfix
# wip (For works in progress)
# tweak
# soundadd
# sounddel
# rscadd (general adding of nice things)
# rscdel (general deleting of nice things)
# imageadd
# imagedel
# maptweak
# spellcheck (typo fixes)
# experiment
#################################
# Your name.
author: Anewbe
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
delete-after: True
# Any changes you've made. See valid prefix list above.
# INDENT WITH TWO SPACES. NOT TABS. SPACES.
# SCREW THIS UP AND IT WON'T WORK.
# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
changes:
- rscadd: "Adds the ability to make robolimb brands more or less vulnerable to brute or burn."
- rscdel: "Makes VeyMed limbs more vulnerable to brute and burn."
+7
View File
@@ -0,0 +1,7 @@
author: Mechoid
delete-after: True
changes:
- rscadd: "Allow AIs to create and take control of mindless drones from fabricators."
Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 657 B

After

Width:  |  Height:  |  Size: 684 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 388 KiB

After

Width:  |  Height:  |  Size: 388 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 877 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

+71 -4
View File
@@ -1001,6 +1001,9 @@
dir = 1
},
/obj/machinery/camera/network/cargo,
/obj/structure/sign/nosmoking_2{
pixel_y = 30
},
/turf/simulated/floor/tiled,
/area/tether/surfacebase/mining_main/storage)
"ace" = (
@@ -1078,6 +1081,9 @@
},
/obj/machinery/atmospherics/pipe/simple/hidden/cyan,
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
/obj/structure/sign/nosmoking_2{
pixel_x = -32
},
/turf/simulated/floor/tiled,
/area/tether/surfacebase/mining_main/storage)
"ack" = (
@@ -2911,6 +2917,9 @@
/obj/effect/floor_decal/steeldecal/steel_decals7{
dir = 6
},
/obj/structure/sign/nosmoking_2{
pixel_x = -32
},
/turf/simulated/floor/tiled,
/area/tether/surfacebase/mining_main/lobby)
"agP" = (
@@ -4474,6 +4483,9 @@
/obj/machinery/washing_machine,
/obj/machinery/atmospherics/unary/vent_scrubber/on,
/obj/machinery/camera/network/civilian,
/obj/structure/sign/nosmoking_2{
pixel_y = 30
},
/turf/simulated/floor/tiled,
/area/storage/surface_eva)
"akg" = (
@@ -5142,6 +5154,9 @@
dir = 4
},
/obj/structure/curtain/open/shower,
/obj/structure/sign/fire{
pixel_y = -32
},
/turf/simulated/floor/tiled/monotile,
/area/storage/surface_eva)
"amd" = (
@@ -10226,6 +10241,9 @@
frequency = 1379;
scrub_id = "civ_airlock_scrubber"
},
/obj/structure/sign/nosmoking_2{
pixel_y = 30
},
/turf/simulated/floor/tiled/techmaint,
/area/storage/surface_eva/external)
"ayO" = (
@@ -11343,6 +11361,9 @@
/obj/item/clothing/mask/gas,
/obj/item/clothing/suit/storage/hooded/wintercoat,
/obj/item/weapon/tank/emergency/oxygen/engi,
/obj/structure/sign/nosmoking_2{
pixel_y = 30
},
/turf/simulated/floor/tiled/dark,
/area/storage/surface_eva)
"aAO" = (
@@ -12776,6 +12797,9 @@
frequency = 1379;
scrub_id = "civ_airlock_scrubber"
},
/obj/structure/sign/fire{
pixel_y = -32
},
/turf/simulated/floor/tiled/techmaint,
/area/storage/surface_eva/external)
"aEo" = (
@@ -12875,6 +12899,9 @@
/obj/item/clothing/mask/gas,
/obj/item/clothing/suit/storage/hooded/wintercoat,
/obj/item/weapon/tank/emergency/oxygen/engi,
/obj/structure/sign/fire{
pixel_y = -32
},
/turf/simulated/floor/tiled/dark,
/area/storage/surface_eva)
"aEu" = (
@@ -27598,6 +27625,16 @@
"gPz" = (
/turf/simulated/floor/tiled,
/area/tether/surfacebase/public_garden_one)
"gRx" = (
/obj/machinery/portable_atmospherics/powered/scrubber/huge/stationary{
frequency = 1379;
scrub_id = "mining_airlock_scrubber"
},
/obj/structure/sign/nosmoking_2{
pixel_x = -32
},
/turf/simulated/floor/tiled/techmaint,
/area/tether/surfacebase/mining_main/airlock)
"gUy" = (
/obj/structure/railing{
dir = 4
@@ -27697,6 +27734,16 @@
},
/turf/simulated/floor/tiled,
/area/tether/surfacebase/public_garden_one)
"iAg" = (
/obj/machinery/portable_atmospherics/powered/scrubber/huge/stationary{
frequency = 1379;
scrub_id = "mining_airlock_scrubber"
},
/obj/structure/sign/fire{
pixel_x = -32
},
/turf/simulated/floor/tiled/techmaint,
/area/tether/surfacebase/mining_main/airlock)
"iPi" = (
/obj/effect/floor_decal/techfloor/corner{
dir = 1
@@ -28266,6 +28313,16 @@
/obj/structure/closet/crate,
/turf/simulated/floor/tiled/techfloor,
/area/tether/surfacebase/public_garden_one)
"tNF" = (
/obj/structure/grille,
/obj/structure/railing{
dir = 8
},
/obj/structure/sign/nosmoking_2{
pixel_y = 30
},
/turf/simulated/floor/tiled/techmaint,
/area/rnd/external)
"tPq" = (
/obj/structure/bed/chair/wood{
dir = 1
@@ -28392,6 +28449,16 @@
},
/turf/simulated/floor/tiled,
/area/tether/surfacebase/public_garden)
"vNR" = (
/obj/structure/grille,
/obj/structure/railing{
dir = 4
},
/obj/structure/sign/fire{
pixel_y = 32
},
/turf/simulated/floor/tiled/techmaint,
/area/rnd/external)
"vOI" = (
/obj/structure/table/bench/steel,
/obj/effect/floor_decal/borderfloor{
@@ -33973,7 +34040,7 @@ aGi
aGw
aHA
aHe
aHC
vNR
aHC
aHe
azr
@@ -34683,7 +34750,7 @@ aGA
bIj
aGR
aHh
aHH
tNF
aHH
aHh
aah
@@ -39024,8 +39091,8 @@ aaf
aaf
aao
aau
aau
aau
gRx
iAg
aau
aao
abn
+39 -31
View File
@@ -17600,6 +17600,9 @@
},
/turf/simulated/floor/tiled,
/area/security/prison)
"Ey" = (
/turf/simulated/floor/reinforced/airless,
/area/space)
"ED" = (
/obj/structure/table/rack{
dir = 8;
@@ -18101,6 +18104,11 @@
/obj/random/maintenance/medical,
/turf/simulated/floor,
/area/maintenance/station/sec_lower)
"NS" = (
/obj/structure/lattice,
/obj/structure/grille,
/turf/space,
/area/space)
"NY" = (
/obj/machinery/light/small{
dir = 8
@@ -22628,16 +22636,16 @@ aa
aa
aa
aa
aa
aa
aa
aa
aa
aa
aa
aa
aa
aa
NS
NS
NS
NS
NS
NS
NS
eM
NS
NS
aa
aa
aa
@@ -22770,6 +22778,7 @@ aa
aa
aa
aa
NS
aa
aa
aa
@@ -22778,8 +22787,7 @@ aa
aa
aa
aa
aa
aa
NS
aa
aa
aa
@@ -22912,7 +22920,7 @@ aa
aa
aa
aa
aa
NS
aa
aa
aa
@@ -23054,7 +23062,7 @@ aa
aa
aa
aa
aa
NS
aa
aa
aa
@@ -23196,7 +23204,7 @@ aa
aa
aa
aa
aa
NS
aa
aa
aa
@@ -23338,14 +23346,14 @@ aa
aa
aa
aa
aa
NS
aa
aa
aa
ab
ac
ac
at
Ey
Ey
Ey
Qs
Qs
at
@@ -23480,14 +23488,14 @@ aa
aa
aa
aa
NS
aa
aa
aa
aa
ac
ac
ac
Qs
ab
Ey
Ey
Ey
Qs
Qs
at
@@ -23622,14 +23630,14 @@ aa
aa
aa
aa
aa
eM
aa
aa
aa
ac
ac
at
Qs
Ey
Ey
kk
Qs
Ug
at
@@ -23764,7 +23772,7 @@ aa
aa
aa
aa
aa
NS
aa
ab
ab
@@ -23906,8 +23914,8 @@ aa
aa
aa
aa
aa
aa
NS
NS
ac
ac
ac
+25 -21
View File
@@ -23475,6 +23475,10 @@
/obj/random/maintenance/engineering,
/turf/simulated/floor,
/area/maintenance/station/ai)
"Wf" = (
/obj/structure/grille,
/turf/space,
/area/space)
"WD" = (
/obj/effect/floor_decal/borderfloor,
/obj/effect/floor_decal/corner/red/border,
@@ -27344,16 +27348,16 @@ aa
aa
aa
aa
aa
aa
aa
aa
aa
aa
aa
aa
aa
aa
nA
nA
nA
nA
Wf
nA
nA
nB
nA
nA
aa
aa
aa
@@ -27486,6 +27490,7 @@ aa
aa
aa
aa
nA
aa
aa
aa
@@ -27494,8 +27499,7 @@ aa
aa
aa
aa
aa
aa
nA
aa
aa
aa
@@ -27628,7 +27632,7 @@ aa
aa
aa
aa
aa
nA
aa
aa
aa
@@ -27770,7 +27774,7 @@ aa
aa
aa
aa
aa
nA
aa
aa
aa
@@ -27912,7 +27916,7 @@ aa
aa
aa
aa
aa
nA
aa
aa
aa
@@ -28054,7 +28058,7 @@ aa
aa
aa
aa
aa
nA
aa
aa
aa
@@ -28196,7 +28200,7 @@ aa
aa
aa
aa
aa
nA
aa
aa
aa
@@ -28338,7 +28342,7 @@ aa
aa
aa
aa
aa
nB
aa
aa
aa
@@ -28480,7 +28484,7 @@ aa
aa
aa
aa
aa
nA
aa
aa
aa
@@ -28622,8 +28626,8 @@ aa
aa
aa
aa
aa
aa
nA
nA
ab
ab
ab
+2 -2
View File
@@ -5,7 +5,7 @@ VIRGO3B_TURF_CREATE(/turf/simulated/open)
/turf/simulated/open/virgo3b/New()
..()
if(outdoors)
outdoor_turfs.Add(src)
SSplanets.addTurf(src)
VIRGO3B_TURF_CREATE(/turf/simulated/floor)
@@ -183,7 +183,7 @@ VIRGO3B_TURF_CREATE(/turf/simulated/mineral/floor)
color = "#FFBBBB"
/turf/simulated/sky/virgo3b/initialize()
outdoor_turfs.Add(src)
SSplanets.addTurf(src)
set_light(2, 2, "#FFBBBB")
/turf/simulated/sky/virgo3b/north
+91 -32
View File
@@ -127,7 +127,7 @@ var/datum/planet/virgo3b/planet_virgo3b = null
WEATHER_HAIL = 2.5
)
datum/weather/virgo3b
/datum/weather/virgo3b
name = "virgo3b base"
temp_high = 243.15 // -20c
temp_low = 233.15 // -30c
@@ -154,8 +154,8 @@ datum/weather/virgo3b
/datum/weather/virgo3b/light_snow
name = "light snow"
icon_state = "snowfall_light"
temp_high = 238.15 // -25c
temp_low = 228.15 // -35c
temp_high = 235
temp_low = 225
light_modifier = 0.7
transition_chances = list(
WEATHER_OVERCAST = 20,
@@ -167,9 +167,10 @@ datum/weather/virgo3b
/datum/weather/virgo3b/snow
name = "moderate snow"
icon_state = "snowfall_med"
temp_high = 233.15 // -30c
temp_low = 223.15 // -40c
temp_high = 230
temp_low = 220
light_modifier = 0.5
flight_failure_modifier = 5
transition_chances = list(
WEATHER_LIGHT_SNOW = 20,
WEATHER_SNOW = 50,
@@ -179,7 +180,8 @@ datum/weather/virgo3b
)
/datum/weather/virgo3b/snow/process_effects()
for(var/turf/simulated/floor/outdoors/snow/S in outdoor_turfs)
..()
for(var/turf/simulated/floor/outdoors/snow/S in SSplanets.new_outdoor_turfs) //This didn't make any sense before SSplanets, either
if(S.z in holder.our_planet.expected_z_levels)
for(var/dir_checked in cardinal)
var/turf/simulated/floor/T = get_step(S, dir_checked)
@@ -190,9 +192,10 @@ datum/weather/virgo3b
/datum/weather/virgo3b/blizzard
name = "blizzard"
icon_state = "snowfall_heavy"
temp_high = 223.15 // -40c
temp_low = 203.15 // -60c
temp_high = 215
temp_low = 200
light_modifier = 0.3
flight_failure_modifier = 10
transition_chances = list(
WEATHER_SNOW = 45,
WEATHER_BLIZZARD = 40,
@@ -201,7 +204,8 @@ datum/weather/virgo3b
)
/datum/weather/virgo3b/blizzard/process_effects()
for(var/turf/simulated/floor/outdoors/snow/S in outdoor_turfs)
..()
for(var/turf/simulated/floor/outdoors/snow/S in SSplanets.new_outdoor_turfs) //This didn't make any sense before SSplanets, either
if(S.z in holder.our_planet.expected_z_levels)
for(var/dir_checked in cardinal)
var/turf/simulated/floor/T = get_step(S, dir_checked)
@@ -213,6 +217,8 @@ datum/weather/virgo3b
name = "rain"
icon_state = "rain"
light_modifier = 0.5
effect_message = "<span class='warning'>Rain falls on you.</span>"
transition_chances = list(
WEATHER_OVERCAST = 25,
WEATHER_LIGHT_SNOW = 10,
@@ -222,21 +228,38 @@ datum/weather/virgo3b
)
/datum/weather/virgo3b/rain/process_effects()
..()
for(var/mob/living/L in living_mob_list)
if(L.z in holder.our_planet.expected_z_levels)
var/turf/T = get_turf(L)
if(!T.outdoors)
return // They're indoors, so no need to rain on them.
continue // They're indoors, so no need to rain on them.
L.adjust_fire_stacks(-5)
to_chat(L, "<span class='warning'>Rain falls on you.</span>")
// If they have an open umbrella, it'll guard from rain
if(istype(L.get_active_hand(), /obj/item/weapon/melee/umbrella))
var/obj/item/weapon/melee/umbrella/U = L.get_active_hand()
if(U.open)
if(show_message)
to_chat(L, "<span class='notice'>Rain patters softly onto your umbrella</span>")
continue
else if(istype(L.get_inactive_hand(), /obj/item/weapon/melee/umbrella))
var/obj/item/weapon/melee/umbrella/U = L.get_inactive_hand()
if(U.open)
if(show_message)
to_chat(L, "<span class='notice'>Rain patters softly onto your umbrella</span>")
continue
L.water_act(1)
if(show_message)
to_chat(L, effect_message)
/datum/weather/virgo3b/storm
name = "storm"
icon_state = "storm"
temp_high = 233.15 // -30c
temp_low = 213.15 // -50c
light_modifier = 0.3
flight_failure_modifier = 10
transition_chances = list(
WEATHER_RAIN = 45,
WEATHER_STORM = 40,
@@ -244,53 +267,89 @@ datum/weather/virgo3b
WEATHER_OVERCAST = 5
)
/datum/weather/virgo3b/rain/process_effects()
/datum/weather/virgo3b/storm/process_effects()
..()
for(var/mob/living/L in living_mob_list)
if(L.z in holder.our_planet.expected_z_levels)
var/turf/T = get_turf(L)
if(!T.outdoors)
return // They're indoors, so no need to rain on them.
continue // They're indoors, so no need to rain on them.
L.adjust_fire_stacks(-10)
// If they have an open umbrella, it'll get stolen by the wind
if(istype(L.get_active_hand(), /obj/item/weapon/melee/umbrella))
var/obj/item/weapon/melee/umbrella/U = L.get_active_hand()
if(U.open)
to_chat(L, "<span class='warning'>A gust of wind yanks the umbrella from your hand!</span>")
L.drop_from_inventory(U)
U.throw_at(get_edge_target_turf(U, pick(alldirs)), 8, 1, L)
else if(istype(L.get_inactive_hand(), /obj/item/weapon/melee/umbrella))
var/obj/item/weapon/melee/umbrella/U = L.get_inactive_hand()
if(U.open)
to_chat(L, "<span class='warning'>A gust of wind yanks the umbrella from your hand!</span>")
L.drop_from_inventory(U)
U.throw_at(get_edge_target_turf(U, pick(alldirs)), 8, 1, L)
L.water_act(2)
to_chat(L, "<span class='warning'>Rain falls on you, drenching you in water.</span>")
/datum/weather/virgo3b/hail
name = "hail"
icon_state = "hail"
temp_high = 233.15 // -30c
temp_low = 213.15 // -50c
light_modifier = 0.3
flight_failure_modifier = 15
timer_low_bound = 2
timer_high_bound = 5
effect_message = "<span class='warning'>The hail smacks into you!</span>"
transition_chances = list(
WEATHER_RAIN = 45,
WEATHER_STORM = 10,
WEATHER_HAIL = 40,
WEATHER_STORM = 40,
WEATHER_HAIL = 10,
WEATHER_OVERCAST = 5
)
/datum/weather/virgo3b/hail/process_effects()
for(var/mob/living/L in living_mob_list)
if(L.z in holder.our_planet.expected_z_levels)
var/turf/T = get_turf(L)
..()
for(var/mob/living/carbon/human/H in living_mob_list)
if(H.z in holder.our_planet.expected_z_levels)
var/turf/T = get_turf(H)
if(!T.outdoors)
return // They're indoors, so no need to pelt them with ice.
continue // They're indoors, so no need to pelt them with ice.
// If they have an open umbrella, it'll guard from rain
// Message plays every time the umbrella gets stolen, just so they're especially aware of what's happening
if(istype(H.get_active_hand(), /obj/item/weapon/melee/umbrella))
var/obj/item/weapon/melee/umbrella/U = H.get_active_hand()
if(U.open)
if(show_message)
to_chat(H, "<span class='notice'>Hail patters gently onto your umbrella.</span>")
continue
else if(istype(H.get_inactive_hand(), /obj/item/weapon/melee/umbrella))
var/obj/item/weapon/melee/umbrella/U = H.get_inactive_hand()
if(U.open)
if(show_message)
to_chat(H, "<span class='notice'>Hail patters gently onto your umbrella.</span>")
continue
var/target_zone = pick(BP_ALL)
var/amount_blocked = L.run_armor_check(target_zone, "melee")
var/amount_soaked = L.get_armor_soak(target_zone, "melee")
var/amount_blocked = H.run_armor_check(target_zone, "melee")
var/amount_soaked = H.get_armor_soak(target_zone, "melee")
if(amount_blocked >= 100)
return // No need to apply damage.
continue // No need to apply damage.
if(amount_soaked >= 10)
return // No need to apply damage.
continue // No need to apply damage.
L.apply_damage(rand(5, 10), BRUTE, target_zone, amount_blocked, amount_soaked, used_weapon = "hail")
to_chat(L, "<span class='warning'>The hail raining down on you [L.can_feel_pain() ? "hurts" : "damages you"]!</span>")
H.apply_damage(rand(1, 3), BRUTE, target_zone, amount_blocked, amount_soaked, used_weapon = "hail")
if(show_message)
to_chat(H, effect_message)
/datum/weather/virgo3b/blood_moon
name = "blood moon"
light_modifier = 0.5
light_color = "#FF0000"
flight_failure_modifier = 25
transition_chances = list(
WEATHER_BLOODMOON = 100
)
)
+9 -2
View File
@@ -195,7 +195,6 @@
#include "code\controllers\Processes\inactivity.dm"
#include "code\controllers\Processes\nanoui.dm"
#include "code\controllers\Processes\obj.dm"
#include "code\controllers\Processes\planet.dm"
#include "code\controllers\Processes\radiation.dm"
#include "code\controllers\Processes\scheduler.dm"
#include "code\controllers\Processes\sun.dm"
@@ -218,6 +217,7 @@
#include "code\controllers\subsystems\orbits.dm"
#include "code\controllers\subsystems\overlays.dm"
#include "code\controllers\subsystems\persist_vr.dm"
#include "code\controllers\subsystems\planets.dm"
#include "code\controllers\subsystems\shuttles.dm"
#include "code\controllers\subsystems\transcore_vr.dm"
#include "code\controllers\subsystems\xenoarch.dm"
@@ -1156,7 +1156,6 @@
#include "code\game\objects\random\mob.dm"
#include "code\game\objects\random\random_vr.dm"
#include "code\game\objects\random\spacesuits.dm"
#include "code\game\objects\structures\alien_props.dm"
#include "code\game\objects\structures\barsign.dm"
#include "code\game\objects\structures\bedsheet_bin.dm"
#include "code\game\objects\structures\bonfire.dm"
@@ -1238,6 +1237,11 @@
#include "code\game\objects\structures\flora\trees.dm"
#include "code\game\objects\structures\ghost_pods\ghost_pods.dm"
#include "code\game\objects\structures\ghost_pods\silicon.dm"
#include "code\game\objects\structures\props\alien_props.dm"
#include "code\game\objects\structures\props\beam_prism.dm"
#include "code\game\objects\structures\props\projectile_lock.dm"
#include "code\game\objects\structures\props\prop.dm"
#include "code\game\objects\structures\props\puzzledoor.dm"
#include "code\game\objects\structures\stool_bed_chair_nest\alien_nests.dm"
#include "code\game\objects\structures\stool_bed_chair_nest\bed.dm"
#include "code\game\objects\structures\stool_bed_chair_nest\chairs.dm"
@@ -1452,6 +1456,7 @@
#include "code\modules\client\ui_style.dm"
#include "code\modules\client\preference_setup\_defines.dm"
#include "code\modules\client\preference_setup\preference_setup.dm"
#include "code\modules\client\preference_setup\preference_setup_vr.dm"
#include "code\modules\client\preference_setup\antagonism\01_basic.dm"
#include "code\modules\client\preference_setup\antagonism\02_candidacy.dm"
#include "code\modules\client\preference_setup\general\01_basic.dm"
@@ -2048,6 +2053,7 @@
#include "code\modules\mob\living\carbon\human\species\outsider\shadow.dm"
#include "code\modules\mob\living\carbon\human\species\outsider\skeleton.dm"
#include "code\modules\mob\living\carbon\human\species\outsider\vox.dm"
#include "code\modules\mob\living\carbon\human\species\station\alraune.dm"
#include "code\modules\mob\living\carbon\human\species\station\blank_vr.dm"
#include "code\modules\mob\living\carbon\human\species\station\golem.dm"
#include "code\modules\mob\living\carbon\human\species\station\human_subspecies.dm"
@@ -2142,6 +2148,7 @@
#include "code\modules\mob\living\silicon\robot\drone\drone_damage.dm"
#include "code\modules\mob\living\silicon\robot\drone\drone_items.dm"
#include "code\modules\mob\living\silicon\robot\drone\drone_manufacturer.dm"
#include "code\modules\mob\living\silicon\robot\drone\drone_remote_control.dm"
#include "code\modules\mob\living\silicon\robot\drone\drone_say.dm"
#include "code\modules\mob\living\silicon\robot\robot_modules\event.dm"
#include "code\modules\mob\living\silicon\robot\robot_modules\station.dm"