mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-11 23:23:28 +01:00
Merge branch 'master' of https://github.com/ParadiseSS13/Paradise into ImportentpAIUpdate
This commit is contained in:
@@ -142,8 +142,10 @@ var/list/admin_verbs_debug = list(
|
||||
/client/proc/callproc,
|
||||
/client/proc/callproc_datum,
|
||||
/client/proc/toggledebuglogs,
|
||||
/client/proc/qdel_toggle, // /vg/
|
||||
/client/proc/qdel_toggle,
|
||||
/client/proc/gc_dump_hdl,
|
||||
/client/proc/gc_toggle_profiling,
|
||||
/client/proc/gc_show_del_report,
|
||||
/client/proc/debugNatureMapGenerator,
|
||||
/client/proc/check_bomb_impacts,
|
||||
/client/proc/test_movable_UI,
|
||||
|
||||
@@ -101,7 +101,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
|
||||
if(!lst)
|
||||
return
|
||||
|
||||
if(!A || A.gc_destroyed)
|
||||
if(!A || !isnull(A.gcDestroyed))
|
||||
usr << "<span class='warning'>Error: callproc_datum(): owner of proc no longer exists.</span>"
|
||||
return
|
||||
if(!hascall(A,procname))
|
||||
|
||||
@@ -8,9 +8,42 @@
|
||||
//var/darkness_view = 0//Base human is 2
|
||||
//var/invisa_view = 0
|
||||
var/prescription = 0
|
||||
var/prescription_upgradable = 0
|
||||
var/see_darkness = 1
|
||||
var/HUDType = 0
|
||||
|
||||
/obj/item/clothing/glasses/New()
|
||||
. = ..()
|
||||
if(prescription_upgradable && prescription)
|
||||
// Pre-upgraded upgradable glasses
|
||||
name = "prescription [name]"
|
||||
|
||||
/obj/item/clothing/glasses/attackby(var/obj/item/O as obj, var/mob/user as mob)
|
||||
if (user.stat || user.restrained() || !ishuman(user))
|
||||
return ..()
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(prescription_upgradable)
|
||||
if(istype(O, /obj/item/clothing/glasses/regular))
|
||||
if(prescription)
|
||||
H << "You can't possibly imagine how adding more lenses would improve \the [name]."
|
||||
return
|
||||
H.unEquip(O)
|
||||
O.loc = src // Store the glasses for later removal
|
||||
H << "You fit \the [name] with lenses from \the [O]."
|
||||
prescription = 1
|
||||
name = "prescription [name]"
|
||||
return
|
||||
if(prescription && istype(O, /obj/item/weapon/screwdriver))
|
||||
var/obj/item/clothing/glasses/regular/G = locate() in src
|
||||
if(!G)
|
||||
G = new(get_turf(H))
|
||||
H << "You salvage the prescription lenses from \the [name]."
|
||||
prescription = 0
|
||||
name = initial(name)
|
||||
H.put_in_hands(G)
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/glasses/meson
|
||||
name = "Optical Meson Scanner"
|
||||
desc = "Used for seeing walls, floors, and stuff through anything."
|
||||
@@ -18,26 +51,12 @@
|
||||
item_state = "glasses"
|
||||
origin_tech = "magnets=2;engineering=2"
|
||||
vision_flags = SEE_TURFS
|
||||
prescription_upgradable = 1
|
||||
species_fit = list("Vox")
|
||||
sprite_sheets = list(
|
||||
"Vox" = 'icons/mob/species/vox/eyes.dmi'
|
||||
)
|
||||
|
||||
/obj/item/clothing/glasses/meson/attackby(var/obj/item/O as obj, var/mob/user as mob)
|
||||
if (user.stat || user.restrained() || !ishuman(user))
|
||||
return
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(istype(O, /obj/item/clothing/glasses/regular))
|
||||
H.unEquip(src)
|
||||
H.unEquip(O)
|
||||
var/obj/item/clothing/glasses/meson/prescription/P = new /obj/item/clothing/glasses/meson/prescription(get_turf(H))
|
||||
H << "You fit \the [src.name] with lenses from \the [O.name]."
|
||||
H.put_in_hands(P)
|
||||
qdel(O)
|
||||
qdel(src)
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/clothing/glasses/meson/night
|
||||
name = "Night Vision Optical Meson Scanner"
|
||||
desc = "An Optical Meson Scanner fitted with an amplified visible light spectrum overlay, providing greater visual clarity in darkness."
|
||||
@@ -45,39 +64,10 @@
|
||||
item_state = "glasses"
|
||||
darkness_view = 8
|
||||
see_darkness = 0
|
||||
|
||||
/obj/item/clothing/glasses/meson/night/attackby(var/obj/item/O as obj, var/mob/user as mob)
|
||||
if(istype(O, /obj/item/clothing/glasses/regular))
|
||||
user << "\The [src.name] is too complex for you to fit with prescription lenses."
|
||||
return
|
||||
..()
|
||||
prescription_upgradable = 0
|
||||
|
||||
/obj/item/clothing/glasses/meson/prescription
|
||||
name = "prescription mesons"
|
||||
desc = "Optical Meson Scanner with prescription lenses."
|
||||
prescription = 1
|
||||
species_fit = list("Vox")
|
||||
sprite_sheets = list(
|
||||
"Vox" = 'icons/mob/species/vox/eyes.dmi'
|
||||
)
|
||||
|
||||
/obj/item/clothing/glasses/meson/prescription/attackby(var/obj/item/O as obj, var/mob/user as mob)
|
||||
if (user.stat || user.restrained() || !ishuman(user))
|
||||
return
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(istype(O, /obj/item/clothing/glasses/regular))
|
||||
H <<"You can't possibly imagine how adding more lenses would improve \the [src.name]."
|
||||
return
|
||||
if(istype(O, /obj/item/weapon/screwdriver))
|
||||
H.unEquip(src)
|
||||
var/obj/item/clothing/glasses/meson/M = new /obj/item/clothing/glasses/meson(get_turf(H))
|
||||
var/obj/item/clothing/glasses/regular/R = new /obj/item/clothing/glasses/regular(get_turf(H))
|
||||
H << "You salvage the prescription lenses from \the [src.name]."
|
||||
H.put_in_hands(M)
|
||||
H.put_in_hands(R)
|
||||
qdel(src)
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/clothing/glasses/meson/cyber
|
||||
name = "Eye Replacement Implant"
|
||||
@@ -85,6 +75,7 @@
|
||||
icon_state = "cybereye-green"
|
||||
item_state = "eyepatch"
|
||||
flags = NODROP
|
||||
prescription_upgradable = 0
|
||||
|
||||
/obj/item/clothing/glasses/science
|
||||
name = "Science Goggles"
|
||||
@@ -147,14 +138,14 @@
|
||||
flags = NODROP
|
||||
|
||||
/obj/item/clothing/glasses/regular
|
||||
name = "Prescription Glasses"
|
||||
name = "prescription glasses"
|
||||
desc = "Made by Nerd. Co."
|
||||
icon_state = "glasses"
|
||||
item_state = "glasses"
|
||||
prescription = 1
|
||||
|
||||
/obj/item/clothing/glasses/regular/hipster
|
||||
name = "Prescription Glasses"
|
||||
name = "prescription glasses"
|
||||
desc = "Made by Uncool. Co."
|
||||
icon_state = "hipster_glasses"
|
||||
item_state = "hipster_glasses"
|
||||
@@ -179,26 +170,12 @@
|
||||
darkness_view = 1
|
||||
flash_protect = 1
|
||||
tint = 1
|
||||
prescription_upgradable = 1
|
||||
species_fit = list("Vox")
|
||||
sprite_sheets = list(
|
||||
"Vox" = 'icons/mob/species/vox/eyes.dmi'
|
||||
)
|
||||
|
||||
/obj/item/clothing/glasses/sunglasses/attackby(var/obj/item/O as obj, var/mob/user as mob)
|
||||
if (user.stat || user.restrained() || !ishuman(user))
|
||||
return
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(istype(O, /obj/item/clothing/glasses/regular))
|
||||
H.unEquip(src)
|
||||
H.unEquip(O)
|
||||
var/obj/item/clothing/glasses/sunglasses/prescription/P = new /obj/item/clothing/glasses/sunglasses/prescription(get_turf(H))
|
||||
H << "You fit \the [src.name] with lenses from \the [O.name]."
|
||||
H.put_in_hands(P)
|
||||
qdel(O)
|
||||
qdel(src)
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/clothing/glasses/virussunglasses
|
||||
desc = "Strangely ancient technology used to help provide rudimentary eye cover. Enhanced shielding blocks many flashes."
|
||||
name = "sunglasses"
|
||||
@@ -282,42 +259,14 @@
|
||||
//vision_flags = BLIND
|
||||
flash_protect = 2
|
||||
tint = 3 //to make them blind
|
||||
prescription_upgradable = 0
|
||||
species_fit = list("Vox")
|
||||
sprite_sheets = list(
|
||||
"Vox" = 'icons/mob/species/vox/eyes.dmi'
|
||||
)
|
||||
|
||||
/obj/item/clothing/glasses/sunglasses/blindfold/attackby(var/obj/item/O as obj, var/mob/user as mob)
|
||||
if(istype(O, /obj/item/clothing/glasses/regular))
|
||||
user << "You doubt you can make a blindfold actually IMPROVE vision."
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/clothing/glasses/sunglasses/prescription
|
||||
name = "prescription sunglasses"
|
||||
prescription = 1
|
||||
species_fit = list("Vox")
|
||||
sprite_sheets = list(
|
||||
"Vox" = 'icons/mob/species/vox/eyes.dmi'
|
||||
)
|
||||
|
||||
/obj/item/clothing/glasses/sunglasses/prescription/attackby(var/obj/item/O as obj, var/mob/user as mob)
|
||||
if (user.stat || user.restrained() || !ishuman(user))
|
||||
return
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(istype(O, /obj/item/clothing/glasses/regular))
|
||||
H <<"You can't possibly imagine how adding more lenses would improve \the [src.name]."
|
||||
return
|
||||
if(istype(O, /obj/item/weapon/screwdriver))
|
||||
H.unEquip(src)
|
||||
var/obj/item/clothing/glasses/sunglasses/S = new /obj/item/clothing/glasses/sunglasses(get_turf(H))
|
||||
var/obj/item/clothing/glasses/regular/R = new /obj/item/clothing/glasses/regular(get_turf(H))
|
||||
H << "You salvage the prescription lenses from \the [src.name]."
|
||||
H.put_in_hands(S)
|
||||
H.put_in_hands(R)
|
||||
qdel(src)
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/clothing/glasses/sunglasses/big
|
||||
desc = "Strangely ancient technology used to help provide rudimentary eye cover. Larger than average enhanced shielding blocks many flashes."
|
||||
@@ -338,51 +287,14 @@
|
||||
flash_protect = 1
|
||||
tint = 1
|
||||
HUDType = SECHUD
|
||||
prescription_upgradable = 1
|
||||
species_fit = list("Vox")
|
||||
sprite_sheets = list(
|
||||
"Vox" = 'icons/mob/species/vox/eyes.dmi'
|
||||
)
|
||||
|
||||
/obj/item/clothing/glasses/sunglasses/sechud/attackby(var/obj/item/O as obj, var/mob/user as mob)
|
||||
if (user.stat || user.restrained() || !ishuman(user))
|
||||
return
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(istype(O, /obj/item/clothing/glasses/regular))
|
||||
H.unEquip(src)
|
||||
H.unEquip(O)
|
||||
var/obj/item/clothing/glasses/sunglasses/sechud/prescription/P = new /obj/item/clothing/glasses/sunglasses/sechud/prescription(get_turf(H))
|
||||
H << "You fit \the [src.name] with lenses from \the [O.name]."
|
||||
H.put_in_hands(P)
|
||||
qdel(O)
|
||||
qdel(src)
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/clothing/glasses/sunglasses/sechud/prescription
|
||||
name = "prescription HUDSunglasses"
|
||||
prescription = 1
|
||||
species_fit = list("Vox")
|
||||
sprite_sheets = list(
|
||||
"Vox" = 'icons/mob/species/vox/eyes.dmi'
|
||||
)
|
||||
|
||||
/obj/item/clothing/glasses/sunglasses/sechud/prescription/attackby(var/obj/item/O as obj, var/mob/user as mob)
|
||||
if (user.stat || user.restrained() || !ishuman(user))
|
||||
return
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(istype(O, /obj/item/clothing/glasses/regular))
|
||||
H <<"You can't possibly imagine how adding more lenses would improve \the [src.name]."
|
||||
return
|
||||
if(istype(O, /obj/item/weapon/screwdriver))
|
||||
H.unEquip(src)
|
||||
var/obj/item/clothing/glasses/sunglasses/sechud/S = new /obj/item/clothing/glasses/sunglasses/sechud(get_turf(H))
|
||||
var/obj/item/clothing/glasses/regular/R = new /obj/item/clothing/glasses/regular(get_turf(H))
|
||||
H << "You salvage the prescription lenses from \the [src.name]."
|
||||
H.put_in_hands(S)
|
||||
H.put_in_hands(R)
|
||||
qdel(src)
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/clothing/glasses/thermal
|
||||
name = "Optical Thermal Scanner"
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
flags = null //doesn't protect eyes because it's a monocle, duh
|
||||
origin_tech = "magnets=3;biotech=2"
|
||||
HUDType = SECHUD
|
||||
prescription_upgradable = 1
|
||||
var/list/icon/current = list() //the current hud icons
|
||||
|
||||
|
||||
@@ -27,6 +28,7 @@
|
||||
item_state = "glasses"
|
||||
darkness_view = 8
|
||||
see_darkness = 0
|
||||
prescription_upgradable = 0
|
||||
|
||||
|
||||
/obj/item/clothing/glasses/hud/security
|
||||
@@ -50,3 +52,4 @@
|
||||
icon_state = "securityhudnight"
|
||||
darkness_view = 8
|
||||
see_darkness = 0
|
||||
prescription_upgradable = 0
|
||||
|
||||
@@ -346,7 +346,7 @@
|
||||
return
|
||||
on = !on
|
||||
if(on)
|
||||
user << "<span class='notice'>You switch your helmet to travel mode.</span>"
|
||||
user << "<span class='notice'>You switch your helmet to travel mode. It will allow you to stand in zero pressure environments, at the cost of speed and armor.</span>"
|
||||
name = "blood-red hardsuit helmet"
|
||||
desc = "A dual-mode advanced helmet designed for work in special operations. It is in travel mode. Property of Gorlex Marauders."
|
||||
flags = HEADCOVERSEYES | BLOCKHAIR | HEADCOVERSMOUTH | STOPSPRESSUREDMAGE | THICKMATERIAL
|
||||
@@ -354,7 +354,7 @@
|
||||
cold_protection = HEAD
|
||||
set_light(brightness_on)
|
||||
else
|
||||
user << "<span class='notice'>You switch your helmet to combat mode.</span>"
|
||||
user << "<span class='notice'>You switch your helmet to combat mode. You will take damage in zero pressure environments, but you are more suited for a fight.</span>"
|
||||
name = "blood-red hardsuit helmet (combat)"
|
||||
desc = "A dual-mode advanced helmet designed for work in special operations. It is in combat mode. Property of Gorlex Marauders."
|
||||
flags = BLOCKHAIR
|
||||
@@ -387,7 +387,7 @@
|
||||
/obj/item/clothing/suit/space/rig/syndi/attack_self(mob/user)
|
||||
on = !on
|
||||
if(on)
|
||||
user << "<span class='notice'>You switch your hardsuit to travel mode.</span>"
|
||||
user << "<span class='notice'>You switch your hardsuit to travel mode. It will allow you to stand in zero pressure environments, at the cost of speed and armor.</span>"
|
||||
name = "blood-red hardsuit helmet"
|
||||
desc = "A dual-mode advanced hardsuit designed for work in special operations. It is in travel mode. Property of Gorlex Marauders."
|
||||
slowdown = 1
|
||||
@@ -395,7 +395,7 @@
|
||||
flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
|
||||
cold_protection = UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS | HANDS
|
||||
else
|
||||
user << "<span class='notice'>You switch your hardsuit to combat mode.</span>"
|
||||
user << "<span class='notice'>You switch your hardsuit to combat mode. You will take damage in zero pressure environments, but you are more suited for a fight.</span>"
|
||||
name = "blood-red hardsuit helmet (combat)"
|
||||
desc = "A dual-mode advanced hardsuit designed for work in special operations. It is in combat mode. Property of Gorlex Marauders."
|
||||
slowdown = 0
|
||||
|
||||
@@ -107,6 +107,13 @@
|
||||
icon = 'icons/obj/custom_items.dmi'
|
||||
icon_state = "norah_briggs_1"
|
||||
|
||||
/obj/item/clothing/head/bearpelt/fluff/polar //Gibson1027: Sploosh
|
||||
name = "polar bear pelt hat"
|
||||
desc = "Fuzzy, and also stained with blood."
|
||||
icon = 'icons/obj/custom_items.dmi'
|
||||
icon_state = "polarbearpelt"
|
||||
item_state = "polarbearpelt"
|
||||
|
||||
//////////// Suits ////////////
|
||||
|
||||
/obj/item/clothing/suit/storage/labcoat/fluff/aeneas_rinil //Robotics Labcoat - Aeneas Rinil [APPR]
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
|
||||
|
||||
/datum/event/blob/announce()
|
||||
command_announcement.Announce("Confirmed outbreak of level 7 biohazard aboard [station_name()]. Nanotrasen has issued a directive 7-10. The station is to be considered quarantined.", "Biohazard Alert", new_sound = 'sound/AI/blob_confirmed.ogg')
|
||||
|
||||
command_announcement.Announce("Confirmed outbreak of level 7 biohazard aboard [station_name()]. Nanotrasen has issued a directive 7-10. The station is to be considered quarantined.", "Biohazard Alert", new_sound = 'sound/AI/outbreak7.ogg')
|
||||
|
||||
for (var/mob/living/silicon/ai/aiPlayer in player_list)
|
||||
if (aiPlayer.client)
|
||||
var/law = "The station is under quarantine, prevent biological entities from leaving the station at all costs while minimizing collateral damage."
|
||||
@@ -34,16 +34,16 @@
|
||||
if(!Blob && !blob_cores.len)
|
||||
kill()
|
||||
return
|
||||
|
||||
|
||||
/datum/event/blob/proc/announce_nuke()
|
||||
var/nukecode = "ERROR"
|
||||
for(var/obj/machinery/nuclearbomb/bomb in world)
|
||||
if(bomb && bomb.r_code && (bomb.z in config.station_levels))
|
||||
nukecode = bomb.r_code
|
||||
|
||||
|
||||
command_announcement.Announce("The biohazard has grown out of control and will soon reach critical mass. Activate the nuclear failsafe to maintain quarantine. The Nuclear Authentication Code is [nukecode] ", "Biohazard Alert")
|
||||
set_security_level("gamma")
|
||||
|
||||
|
||||
var/obj/machinery/door/airlock/vault/V = locate(/obj/machinery/door/airlock/vault) in world
|
||||
if(V && (V.z in config.station_levels))
|
||||
V.locked = 0
|
||||
@@ -55,16 +55,16 @@
|
||||
aiPlayer.set_zeroth_law(law)
|
||||
aiPlayer << "\red <b>You have detected a change in your laws information:</b>"
|
||||
aiPlayer << "Laws Updated: [law]"
|
||||
|
||||
spawn(10)
|
||||
|
||||
spawn(10)
|
||||
world << sound('sound/effects/siren.ogg')
|
||||
|
||||
|
||||
/datum/event/blob/kill()
|
||||
spawn(10)
|
||||
if(Blob || blob_cores.len)
|
||||
return
|
||||
command_announcement.Announce("The level 7 biohazard aboard [station_name()] has been eliminated. Directive 7-10 has been lifted, and the station is no longer quarantined.", "Biohazard Update")
|
||||
|
||||
|
||||
for (var/mob/living/silicon/ai/aiPlayer in player_list)
|
||||
if (aiPlayer.client)
|
||||
aiPlayer.clear_zeroth_law()
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
|
||||
/datum/event/brand_intelligence/tick()
|
||||
if(!originMachine || originMachine.gc_destroyed || originMachine.shut_up || originMachine.wires.IsAllCut()) //if the original vending machine is missing or has it's voice switch flipped
|
||||
if(!originMachine || !isnull(originMachine.gcDestroyed) || originMachine.shut_up || originMachine.wires.IsAllCut()) //if the original vending machine is missing or has it's voice switch flipped
|
||||
for(var/obj/machinery/vending/saved in infectedMachines)
|
||||
saved.shoot_inventory = 0
|
||||
if(originMachine)
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
if(!vendingMachines.len) //if every machine is infected
|
||||
for(var/obj/machinery/vending/upriser in infectedMachines)
|
||||
if(prob(70) && !upriser.gc_destroyed)
|
||||
if(prob(70) && isnull(upriser.gcDestroyed))
|
||||
var/mob/living/simple_animal/hostile/mimic/copy/M = new(upriser.loc, upriser, null, 1) // it will delete upriser on creation and override any machine checks
|
||||
M.faction = list("profit")
|
||||
M.speak = rampant_speeches.Copy()
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
var/list/gunk = list("water","carbon","flour","radium","toxin","cleaner","nutriment","condensedcapsaicin","psilocybin","lube",
|
||||
"atrazine","banana","charcoal","space_drugs","methamphetamine","holywater","ethanol","hot_coco","facid",
|
||||
"blood","morphine","fluorine","mutadone","mutagen","hydrocodone","fuel",
|
||||
"blood","morphine","ether","fluorine","mutadone","mutagen","hydrocodone","fuel",
|
||||
"haloperidol","lsd","nanites","lipolicide","frostoil","salglu_solution","beepskysmash",
|
||||
"omnizine", "amanitin", "adminordrazine", "neurotoxin", "synaptizine")
|
||||
var/datum/reagents/R = new/datum/reagents(50)
|
||||
|
||||
@@ -11,7 +11,7 @@ Gunshots/explosions/opening doors/less rare audio (done)
|
||||
|
||||
*/
|
||||
|
||||
mob/living/carbon/
|
||||
/mob/living/carbon/
|
||||
var/image/halimage
|
||||
var/image/halbody
|
||||
var/obj/halitem
|
||||
@@ -19,187 +19,354 @@ mob/living/carbon/
|
||||
var/handling_hal = 0
|
||||
var/hal_crit = 0
|
||||
|
||||
mob/living/carbon/proc/handle_hallucinations()
|
||||
/mob/living/carbon/proc/handle_hallucinations()
|
||||
if(handling_hal)
|
||||
return
|
||||
|
||||
//Least obvious
|
||||
var/list/minor = list("sounds"=20,"bolts_minor"=10,"whispers"=15,"message"=5)
|
||||
//Something's wrong here
|
||||
var/list/medium = list("hudscrew"=15,"items"=15,"dangerflash"=15,"bolts"=10,"flood"=10,"husks"=10,"battle"=10)
|
||||
//AAAAH
|
||||
var/list/major = list("fake"=10,"death"=5,"xeno"=10,"singulo"=10,"delusion"=10)
|
||||
|
||||
var/grade = 0
|
||||
var/current = list()
|
||||
var/trip_length = 0
|
||||
|
||||
handling_hal = 1
|
||||
while(hallucination > 20)
|
||||
sleep(rand(200,500)/(hallucination/25))
|
||||
var/halpick = rand(1,100)
|
||||
switch(halpick)
|
||||
if(0 to 15)
|
||||
//Screwy HUD
|
||||
//src << "Screwy HUD"
|
||||
hal_screwyhud = pick(1,2,3,3,4,4)
|
||||
spawn(rand(100,250))
|
||||
hal_screwyhud = 0
|
||||
if(16 to 25)
|
||||
//Strange items
|
||||
//src << "Traitor Items"
|
||||
if(!halitem)
|
||||
halitem = new
|
||||
var/list/slots_free = list(ui_lhand,ui_rhand)
|
||||
if(l_hand) slots_free -= ui_lhand
|
||||
if(r_hand) slots_free -= ui_rhand
|
||||
if(istype(src,/mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = src
|
||||
if(!H.belt) slots_free += ui_belt
|
||||
if(!H.l_store) slots_free += ui_storage1
|
||||
if(!H.r_store) slots_free += ui_storage2
|
||||
if(slots_free.len)
|
||||
halitem.screen_loc = pick(slots_free)
|
||||
halitem.layer = 50
|
||||
switch(rand(1,6))
|
||||
if(1) //revolver
|
||||
halitem.icon = 'icons/obj/gun.dmi'
|
||||
halitem.icon_state = "revolver"
|
||||
halitem.name = "Revolver"
|
||||
if(2) //c4
|
||||
halitem.icon = 'icons/obj/assemblies.dmi'
|
||||
halitem.icon_state = "plastic-explosive0"
|
||||
halitem.name = "Mysterious Package"
|
||||
if(prob(25))
|
||||
halitem.icon_state = "c4small_1"
|
||||
if(3) //sword
|
||||
halitem.icon = 'icons/obj/weapons.dmi'
|
||||
halitem.icon_state = "sword1"
|
||||
halitem.name = "Sword"
|
||||
if(4) //stun baton
|
||||
halitem.icon = 'icons/obj/weapons.dmi'
|
||||
halitem.icon_state = "stunbaton"
|
||||
halitem.name = "Stun Baton"
|
||||
if(5) //emag
|
||||
halitem.icon = 'icons/obj/card.dmi'
|
||||
halitem.icon_state = "emag"
|
||||
halitem.name = "Cryptographic Sequencer"
|
||||
if(6) //flashbang
|
||||
halitem.icon = 'icons/obj/grenade.dmi'
|
||||
halitem.icon_state = "flashbang1"
|
||||
halitem.name = "Flashbang"
|
||||
if(client) client.screen += halitem
|
||||
spawn(rand(100,250))
|
||||
qdel(halitem)
|
||||
if(26 to 40)
|
||||
//Flashes of danger
|
||||
//src << "Danger Flash"
|
||||
if(!halimage)
|
||||
var/list/possible_points = list()
|
||||
for(var/turf/simulated/floor/F in view(src,world.view))
|
||||
possible_points += F
|
||||
if(possible_points.len)
|
||||
var/turf/simulated/floor/target = pick(possible_points)
|
||||
trip_length += 1
|
||||
if(prob(min(20,trip_length*2)))
|
||||
grade = min(3,grade+1)
|
||||
if(prob(20))
|
||||
continue
|
||||
current = list()
|
||||
for(var/a in minor)
|
||||
current[a] = minor[a] * (grade==0?2:1)
|
||||
for(var/b in medium)
|
||||
current[b] = medium[b] * (grade==1?2:1)
|
||||
for(var/c in major)
|
||||
current[c] = major[c] * (grade==2?2:1)
|
||||
|
||||
switch(rand(1,3))
|
||||
if(1)
|
||||
//src << "Space"
|
||||
halimage = image('icons/turf/space.dmi',target,"[rand(1,25)]",TURF_LAYER)
|
||||
if(2)
|
||||
//src << "Fire"
|
||||
halimage = image('icons/effects/fire.dmi',target,"1",TURF_LAYER)
|
||||
if(3)
|
||||
//src << "C4"
|
||||
halimage = image('icons/obj/assemblies.dmi',target,"plastic-explosive2",OBJ_LAYER+0.01)
|
||||
var/halpick = pickweight(current)
|
||||
|
||||
|
||||
if(client) client.images += halimage
|
||||
spawn(rand(10,50)) //Only seen for a brief moment.
|
||||
if(client) client.images -= halimage
|
||||
halimage = null
|
||||
|
||||
|
||||
if(41 to 65)
|
||||
//Strange audio
|
||||
//src << "Strange Audio"
|
||||
switch(rand(1,14))
|
||||
if(1) src << 'sound/machines/airlock.ogg'
|
||||
if(2)
|
||||
if(prob(50))src << 'sound/effects/Explosion1.ogg'
|
||||
else src << 'sound/effects/Explosion2.ogg'
|
||||
if(3) src << 'sound/effects/explosionfar.ogg'
|
||||
if(4) src << 'sound/effects/Glassbr1.ogg'
|
||||
if(5) src << 'sound/effects/Glassbr2.ogg'
|
||||
if(6) src << 'sound/effects/Glassbr3.ogg'
|
||||
if(7) src << 'sound/machines/twobeep.ogg'
|
||||
if(8) src << 'sound/machines/windowdoor.ogg'
|
||||
if(9)
|
||||
//To make it more realistic, I added two gunshots (enough to kill)
|
||||
src << 'sound/weapons/Gunshot.ogg'
|
||||
spawn(rand(10,30))
|
||||
src << 'sound/weapons/Gunshot.ogg'
|
||||
if(10) src << 'sound/weapons/smash.ogg'
|
||||
if(11)
|
||||
//Same as above, but with tasers.
|
||||
src << 'sound/weapons/Taser.ogg'
|
||||
spawn(rand(10,30))
|
||||
src << 'sound/weapons/Taser.ogg'
|
||||
//Rare audio
|
||||
if(12)
|
||||
//These sounds are (mostly) taken from Hidden: Source
|
||||
var/list/creepyasssounds = list('sound/effects/ghost.ogg', 'sound/effects/ghost2.ogg', 'sound/effects/Heart Beat.ogg', 'sound/effects/screech.ogg',\
|
||||
'sound/hallucinations/behind_you1.ogg', 'sound/hallucinations/behind_you2.ogg', 'sound/hallucinations/far_noise.ogg', 'sound/hallucinations/growl1.ogg', 'sound/hallucinations/growl2.ogg',\
|
||||
'sound/hallucinations/growl3.ogg', 'sound/hallucinations/im_here1.ogg', 'sound/hallucinations/im_here2.ogg', 'sound/hallucinations/i_see_you1.ogg', 'sound/hallucinations/i_see_you2.ogg',\
|
||||
'sound/hallucinations/look_up1.ogg', 'sound/hallucinations/look_up2.ogg', 'sound/hallucinations/over_here1.ogg', 'sound/hallucinations/over_here2.ogg', 'sound/hallucinations/over_here3.ogg',\
|
||||
'sound/hallucinations/turn_around1.ogg', 'sound/hallucinations/turn_around2.ogg', 'sound/hallucinations/veryfar_noise.ogg', 'sound/hallucinations/wail.ogg')
|
||||
src << pick(creepyasssounds)
|
||||
if(13)
|
||||
src << "<span class='warning'>You feel a tiny prick!</span>"
|
||||
if(14)
|
||||
src << "<h1 class='alert'>Priority Announcement</h1>"
|
||||
src << "<br><br><span class='alert'>The Emergency Shuttle has docked with the station. You have 3 minutes to board the Emergency Shuttle.</span><br><br>"
|
||||
src << sound('sound/AI/shuttledock.ogg')
|
||||
if(66 to 70)
|
||||
//Flashes of danger
|
||||
if(!halbody)
|
||||
var/list/possible_points = list()
|
||||
for(var/turf/simulated/floor/F in view(src,world.view))
|
||||
possible_points += F
|
||||
if(possible_points.len)
|
||||
var/turf/simulated/floor/target = pick(possible_points)
|
||||
switch(rand(1,4))
|
||||
if(1)
|
||||
halbody = image('icons/mob/human.dmi',target,"husk_l",TURF_LAYER)
|
||||
if(2,3)
|
||||
halbody = image('icons/mob/human.dmi',target,"husk_s",TURF_LAYER)
|
||||
if(4)
|
||||
halbody = image('icons/mob/alien.dmi',target,"alienother",TURF_LAYER)
|
||||
|
||||
if(client) client.images += halbody
|
||||
spawn(rand(50,80)) //Only seen for a brief moment.
|
||||
if(client) client.images -= halbody
|
||||
halbody = null
|
||||
if(71 to 72)
|
||||
//Fake death
|
||||
src.sleeping = 20
|
||||
hal_crit = 1
|
||||
hal_screwyhud = 1
|
||||
spawn(rand(50,100))
|
||||
src.sleeping = 0
|
||||
hal_crit = 0
|
||||
hal_screwyhud = 0
|
||||
if(73 to 75)
|
||||
fake_attack()
|
||||
hallucinate(halpick)
|
||||
handling_hal = 0
|
||||
|
||||
/obj/effect/hallucination
|
||||
invisibility = INVISIBILITY_OBSERVER
|
||||
var/mob/living/carbon/target = null
|
||||
|
||||
/mob/living/carbon/proc/fake_attack()
|
||||
// var/list/possible_clones = new/list()
|
||||
/obj/effect/hallucination/simple
|
||||
var/image_icon = 'icons/mob/alien.dmi'
|
||||
var/image_state = "alienh_pounce"
|
||||
var/px = 0
|
||||
var/py = 0
|
||||
var/col_mod = null
|
||||
var/image/current_image = null
|
||||
var/image_layer = MOB_LAYER
|
||||
var/active = 1 //qdelery
|
||||
|
||||
/obj/effect/hallucination/simple/New(loc,var/mob/living/carbon/T)
|
||||
target = T
|
||||
current_image = GetImage()
|
||||
if(target.client) target.client.images |= current_image
|
||||
return
|
||||
|
||||
/obj/effect/hallucination/simple/proc/GetImage()
|
||||
var/image/I = image(image_icon,loc,image_state,image_layer,dir=src.dir)
|
||||
I.pixel_x = px
|
||||
I.pixel_y = py
|
||||
if(col_mod)
|
||||
I.color = col_mod
|
||||
return I
|
||||
|
||||
/obj/effect/hallucination/simple/proc/Show(var/update=1)
|
||||
if(active)
|
||||
if(target.client) target.client.images.Remove(current_image)
|
||||
if(update)
|
||||
current_image = GetImage()
|
||||
if(target.client) target.client.images |= current_image
|
||||
|
||||
/obj/effect/hallucination/simple/update_icon(var/new_state,var/new_icon,var/new_px=0,var/new_py=0)
|
||||
image_state = new_state
|
||||
if(new_icon)
|
||||
image_icon = new_icon
|
||||
else
|
||||
image_icon = initial(image_icon)
|
||||
px = new_px
|
||||
py = new_py
|
||||
Show()
|
||||
|
||||
/obj/effect/hallucination/simple/Move()
|
||||
..()
|
||||
Show()
|
||||
|
||||
/obj/effect/hallucination/simple/Destroy()
|
||||
if(target.client) target.client.images.Remove(current_image)
|
||||
active = 0
|
||||
|
||||
#define FAKE_FLOOD_EXPAND_TIME 30
|
||||
#define FAKE_FLOOD_MAX_RADIUS 7
|
||||
|
||||
/obj/effect/hallucination/fake_flood
|
||||
//Plasma/N2O starts flooding from the nearby vent
|
||||
var/list/flood_images = list()
|
||||
var/list/turf/flood_turfs = list()
|
||||
var/image_icon = 'icons/effects/tile_effects.dmi'
|
||||
var/image_state = "plasma"
|
||||
var/radius = 0
|
||||
var/next_expand = 0
|
||||
|
||||
/obj/effect/hallucination/fake_flood/New(loc,var/mob/living/carbon/T)
|
||||
..()
|
||||
target = T
|
||||
for(var/obj/machinery/atmospherics/unary/vent_pump/U in orange(7,target))
|
||||
if(!U.welded)
|
||||
src.loc = U.loc
|
||||
break
|
||||
image_state = pick("plasma","sleeping_agent")
|
||||
flood_images += image(image_icon,src,image_state,MOB_LAYER)
|
||||
flood_turfs += get_turf(src.loc)
|
||||
if(target.client) target.client.images |= flood_images
|
||||
next_expand = world.time + FAKE_FLOOD_EXPAND_TIME
|
||||
processing_objects += src
|
||||
|
||||
/obj/effect/hallucination/fake_flood/process()
|
||||
if(next_expand <= world.time)
|
||||
radius++
|
||||
if(radius > FAKE_FLOOD_MAX_RADIUS)
|
||||
qdel(src)
|
||||
Expand()
|
||||
next_expand = world.time + FAKE_FLOOD_EXPAND_TIME
|
||||
return
|
||||
|
||||
/obj/effect/hallucination/fake_flood/proc/Expand()
|
||||
if(!flood_turfs) //for qdel
|
||||
return
|
||||
for(var/turf/T in circlerangeturfs(loc,radius))
|
||||
if((T in flood_turfs)|| T.blocks_air)
|
||||
continue
|
||||
flood_images += image(image_icon,T,image_state,MOB_LAYER)
|
||||
flood_turfs += T
|
||||
if(target.client) target.client.images |= flood_images
|
||||
return
|
||||
|
||||
/obj/effect/hallucination/fake_flood/Destroy()
|
||||
processing_objects -= src
|
||||
del(flood_turfs)
|
||||
if(target.client) target.client.images.Remove(flood_images)
|
||||
target = null
|
||||
del(flood_images)
|
||||
return
|
||||
|
||||
/obj/effect/hallucination/simple/xeno
|
||||
image_icon = 'icons/mob/alien.dmi'
|
||||
image_state = "alienh_pounce"
|
||||
|
||||
/obj/effect/hallucination/simple/xeno/New(loc,var/mob/living/carbon/T)
|
||||
..()
|
||||
name = "alien hunter ([rand(1, 1000)])"
|
||||
return
|
||||
|
||||
/obj/effect/hallucination/simple/xeno/throw_at(atom/target, range, speed) // TODO : Make diagonal trhow into proc/property
|
||||
if(!target || !src || (flags & NODROP)) return 0
|
||||
|
||||
src.throwing = 1
|
||||
|
||||
var/dist_x = abs(target.x - src.x)
|
||||
var/dist_y = abs(target.y - src.y)
|
||||
var/dist_travelled = 0
|
||||
var/dist_since_sleep = 0
|
||||
|
||||
var/tdist_x = dist_x;
|
||||
var/tdist_y = dist_y;
|
||||
|
||||
if(dist_x <= dist_y)
|
||||
tdist_x = dist_y;
|
||||
tdist_y = dist_x;
|
||||
|
||||
var/error = tdist_x/2 - tdist_y
|
||||
while(target && (((((dist_x > dist_y) && ((src.x < target.x) || (src.x > target.x))) || ((dist_x <= dist_y) && ((src.y < target.y) || (src.y > target.y))) || (src.x > target.x)) && dist_travelled < range) || !has_gravity(src)))
|
||||
|
||||
if(!src.throwing) break
|
||||
if(!istype(src.loc, /turf)) break
|
||||
|
||||
var/atom/step = get_step(src, get_dir(src,target))
|
||||
if(!step)
|
||||
break
|
||||
src.Move(step, get_dir(src, step))
|
||||
hit_check()
|
||||
error += (error < 0) ? tdist_x : -tdist_y;
|
||||
dist_travelled++
|
||||
dist_since_sleep++
|
||||
if(dist_since_sleep >= speed)
|
||||
dist_since_sleep = 0
|
||||
sleep(1)
|
||||
|
||||
|
||||
src.throwing = 0
|
||||
src.throw_impact(get_turf(src))
|
||||
|
||||
return 1
|
||||
|
||||
/obj/effect/hallucination/simple/xeno/throw_impact(A)
|
||||
update_icon("alienh_pounce")
|
||||
if(A == target)
|
||||
target.Weaken(5)
|
||||
target.visible_message("<span class='danger'>[target] flails around wildly.</span>","<span class ='userdanger'>[name] pounces on you!</span>")
|
||||
|
||||
/obj/effect/hallucination/xeno_attack
|
||||
//Xeno crawls from nearby vent,jumps at you, and goes back in
|
||||
var/obj/machinery/atmospherics/unary/vent_pump/pump = null
|
||||
var/obj/effect/hallucination/simple/xeno/xeno = null
|
||||
|
||||
/obj/effect/hallucination/xeno_attack/New(loc,var/mob/living/carbon/T)
|
||||
target = T
|
||||
for(var/obj/machinery/atmospherics/unary/vent_pump/U in orange(7,target))
|
||||
if(!U.welded)
|
||||
pump = U
|
||||
break
|
||||
if(!pump) return 0
|
||||
xeno = new(pump.loc,target)
|
||||
sleep(10)
|
||||
if(!xeno) return
|
||||
xeno.update_icon("alienh_leap",'icons/mob/alienleap.dmi',-32,-32)
|
||||
xeno.throw_at(target,7,1)
|
||||
sleep(10)
|
||||
if(!xeno) return
|
||||
xeno.update_icon("alienh_leap",'icons/mob/alienleap.dmi',-32,-32)
|
||||
xeno.throw_at(pump,7,1)
|
||||
sleep(10)
|
||||
if(!xeno) return
|
||||
var/xeno_name = xeno.name
|
||||
target << "<span class='notice'>[xeno_name] begins climbing into the ventilation system...</span>"
|
||||
sleep(10)
|
||||
if(!xeno) return
|
||||
qdel(xeno)
|
||||
target << "<span class='notice'>[xeno_name] scrambles into the ventilation ducts!</span>"
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/hallucination/singularity_scare
|
||||
//Singularity moving towards you.
|
||||
//todo Hide where it moved with fake space images
|
||||
var/obj/effect/hallucination/simple/singularity/s = null
|
||||
|
||||
/obj/effect/hallucination/singularity_scare/New(loc,var/mob/living/carbon/T)
|
||||
target = T
|
||||
var/turf/start = T.loc
|
||||
var/screen_border = pick(SOUTH,EAST,WEST,NORTH)
|
||||
for(var/i = 0,i<11,i++)
|
||||
start = get_step(start,screen_border)
|
||||
s = new(start,target)
|
||||
for(var/i = 0,i<11,i++)
|
||||
sleep(5)
|
||||
s.loc = get_step(get_turf(s),get_dir(s,target))
|
||||
s.Show()
|
||||
s.Eat()
|
||||
qdel(s)
|
||||
|
||||
/obj/effect/hallucination/simple/singularity
|
||||
image_icon = 'icons/effects/224x224.dmi'
|
||||
image_state = "singularity_s7"
|
||||
image_layer = 6
|
||||
px = -96
|
||||
py = -96
|
||||
|
||||
/obj/effect/hallucination/simple/singularity/proc/Eat(atom/OldLoc, Dir)
|
||||
var/target_dist = get_dist(src,target)
|
||||
if(target_dist<=3) //"Eaten"
|
||||
target.sleeping = 20
|
||||
target.hal_crit = 1
|
||||
target.hal_screwyhud = 1
|
||||
spawn(rand(50,100))
|
||||
target.sleeping = 0
|
||||
target.hal_crit = 0
|
||||
target.hal_screwyhud = 0
|
||||
|
||||
/obj/effect/hallucination/battle
|
||||
|
||||
/obj/effect/hallucination/battle/New(loc,var/mob/living/carbon/T)
|
||||
target = T
|
||||
var/hits = rand(3,6)
|
||||
switch(rand(1,5))
|
||||
if(1) //Laser fight
|
||||
for(var/i=0,i<hits,i++)
|
||||
target << sound('sound/weapons/Laser.ogg',0,1,0,25)
|
||||
sleep(rand(1,5))
|
||||
target << sound(get_sfx("bodyfall"),0,1,0,25)
|
||||
if(2) //Esword fight
|
||||
target << sound('sound/weapons/saberon.ogg',0,1,0,15)
|
||||
for(var/i=0,i<hits,i++)
|
||||
target << sound('sound/weapons/blade1.ogg',,0,1,0,25)
|
||||
sleep(rand(1,5))
|
||||
target << sound(get_sfx("bodyfall"),0,1,0,25)
|
||||
target << sound('sound/weapons/saberoff.ogg',0,1,0,15)
|
||||
if(3) //Gun fight
|
||||
for(var/i=0,i<hits,i++)
|
||||
target << sound(get_sfx("gunshot"),0,1,0,25)
|
||||
sleep(rand(1,5))
|
||||
target << sound(get_sfx("bodyfall"),0,1,0,25)
|
||||
if(4) //Stunprod + cablecuff
|
||||
target << sound('sound/weapons/Egloves.ogg',0,1,40)
|
||||
target << sound(get_sfx("bodyfall"),0,1,0,25)
|
||||
sleep(30)
|
||||
target << sound('sound/weapons/cablecuff.ogg',0,1,0,15)
|
||||
if(5) // Tick Tock
|
||||
for(var/i=0,i<hits,i++)
|
||||
target << sound('sound/items/timer.ogg',0,1,0,25)
|
||||
sleep(15)
|
||||
qdel(src)
|
||||
|
||||
|
||||
/obj/effect/hallucination/delusion
|
||||
var/list/image/delusions = list()
|
||||
|
||||
/obj/effect/hallucination/delusion/New(loc,var/mob/living/carbon/T)
|
||||
target = T
|
||||
var/image/A = null
|
||||
var/kind = rand(1,3)
|
||||
for(var/mob/living/carbon/human/H in living_mob_list)
|
||||
if(H == target)
|
||||
continue
|
||||
if(H in view(target))
|
||||
continue
|
||||
switch(kind)
|
||||
if(1)//Clown
|
||||
A = image('icons/mob/animal.dmi',H,"clown")
|
||||
if(2)//Carp
|
||||
A = image('icons/mob/animal.dmi',H,"carp")
|
||||
if(3)//Corgi
|
||||
A = image('icons/mob/pets.dmi',H,"corgi")
|
||||
if(4)//Skeletons
|
||||
A = image('icons/mob/human.dmi',H,"skeleton_s")
|
||||
A.override = 1
|
||||
if(target.client)
|
||||
delusions |= A
|
||||
target.client.images |= A
|
||||
sleep(300)
|
||||
for(var/image/I in delusions)
|
||||
if(target.client)
|
||||
target.client.images.Remove(I)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/hallucination/fakeattacker/New(loc,var/mob/living/carbon/T)
|
||||
target = T
|
||||
var/mob/living/carbon/human/clone = null
|
||||
var/clone_weapon = null
|
||||
|
||||
for(var/mob/living/carbon/human/H in living_mob_list)
|
||||
if(H.stat || H.lying)
|
||||
continue
|
||||
// possible_clones += H
|
||||
clone = H
|
||||
break //changed the code a bit. Less randomised, but less work to do. Should be ok, world.contents aren't stored in any particular order.
|
||||
break
|
||||
|
||||
// if(!possible_clones.len) return
|
||||
// clone = pick(possible_clones)
|
||||
if(!clone)
|
||||
return
|
||||
|
||||
//var/obj/effect/fake_attacker/F = new/obj/effect/fake_attacker(outside_range(target))
|
||||
var/obj/effect/fake_attacker/F = new/obj/effect/fake_attacker(src.loc)
|
||||
var/obj/effect/fake_attacker/F = new/obj/effect/fake_attacker(get_turf(target),target)
|
||||
if(clone.l_hand)
|
||||
if(!(locate(clone.l_hand) in non_fakeattack_weapons))
|
||||
clone_weapon = clone.l_hand.name
|
||||
@@ -210,9 +377,8 @@ mob/living/carbon/proc/handle_hallucinations()
|
||||
F.weap = clone.r_hand
|
||||
|
||||
F.name = clone.name
|
||||
F.my_target = src
|
||||
F.my_target = target
|
||||
F.weapon_name = clone_weapon
|
||||
src.hallucinations += F
|
||||
|
||||
F.left = image(clone,dir = WEST)
|
||||
F.right = image(clone,dir = EAST)
|
||||
@@ -220,7 +386,7 @@ mob/living/carbon/proc/handle_hallucinations()
|
||||
F.down = image(clone,dir = SOUTH)
|
||||
|
||||
F.updateimage()
|
||||
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/fake_attacker
|
||||
icon = null
|
||||
@@ -255,8 +421,6 @@ mob/living/carbon/proc/handle_hallucinations()
|
||||
"<span class='danger'>[my_target] has attacked [src]!</span>")
|
||||
|
||||
src.health -= P.force
|
||||
|
||||
|
||||
return
|
||||
|
||||
/obj/effect/fake_attacker/Crossed(var/mob/M, somenumber)
|
||||
@@ -266,20 +430,18 @@ mob/living/carbon/proc/handle_hallucinations()
|
||||
for(var/mob/O in oviewers(world.view , my_target))
|
||||
O << "<span class='danger'>[my_target] stumbles around.</span>"
|
||||
|
||||
/obj/effect/fake_attacker/New()
|
||||
/obj/effect/fake_attacker/New(loc,var/mob/living/carbon/T)
|
||||
..()
|
||||
my_target = T
|
||||
spawn(300)
|
||||
if(my_target)
|
||||
my_target.hallucinations -= src
|
||||
qdel(src)
|
||||
step_away(src,my_target,2)
|
||||
spawn attack_loop()
|
||||
spawn(0)
|
||||
attack_loop()
|
||||
|
||||
|
||||
/obj/effect/fake_attacker/proc/updateimage()
|
||||
// del src.currentimage
|
||||
|
||||
|
||||
if(src.dir == NORTH)
|
||||
del src.currentimage
|
||||
src.currentimage = new /image(up,src)
|
||||
@@ -342,7 +504,7 @@ mob/living/carbon/proc/handle_hallucinations()
|
||||
return
|
||||
|
||||
var/list/non_fakeattack_weapons = list(/obj/item/weapon/gun/projectile, /obj/item/ammo_box/a357,\
|
||||
/obj/item/weapon/gun/energy/crossbow, /obj/item/weapon/melee/energy/sword,\
|
||||
/obj/item/weapon/gun/energy/kinetic_accelerator/crossbow,\
|
||||
/obj/item/weapon/storage/box/syndicate, /obj/item/weapon/storage/box/emps,\
|
||||
/obj/item/weapon/cartridge/syndicate, /obj/item/clothing/under/chameleon,\
|
||||
/obj/item/clothing/shoes/syndigaloshes, /obj/item/weapon/card/id/syndicate,\
|
||||
@@ -356,3 +518,251 @@ var/list/non_fakeattack_weapons = list(/obj/item/weapon/gun/projectile, /obj/ite
|
||||
/obj/item/clothing/under/rank/captain, /obj/item/device/aicard,\
|
||||
/obj/item/clothing/shoes/magboots, /obj/item/areaeditor/blueprints, /obj/item/weapon/disk/nuclear,\
|
||||
/obj/item/clothing/suit/space/nasavoid, /obj/item/weapon/tank)
|
||||
|
||||
/obj/effect/hallucination/bolts
|
||||
var/list/doors = list()
|
||||
|
||||
/obj/effect/hallucination/bolts/New(loc,var/mob/living/carbon/T,var/door_number=-1) //-1 for sever 1-2 for subtle
|
||||
target = T
|
||||
var/image/I = null
|
||||
var/count = 0
|
||||
for(var/obj/machinery/door/airlock/A in range(target,7))
|
||||
if(count>door_number && door_number>0)
|
||||
break
|
||||
count++
|
||||
I = image(A.icon,A,"door_locked",layer=A.layer+0.1)
|
||||
doors += I
|
||||
if(target.client)
|
||||
target.client.images |= I
|
||||
sleep(2)
|
||||
sleep(100)
|
||||
for(var/image/B in doors)
|
||||
if(target.client)
|
||||
target.client.images.Remove(B)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/hallucination/whispers
|
||||
|
||||
/obj/effect/hallucination/whispers/New(loc,var/mob/living/carbon/T)
|
||||
target = T
|
||||
var/speak_messages = list("I'm watching you...","[target.name]!","Go away!","Kchck-Chkck? Kchchck!","Did you hear that?","What did you do ?","Why?","Give me that!","Honk!","HELP!!")
|
||||
var/radio_messages = list("Xenos!","Singularity loose!","They are arming the nuke!","They butchered Ian!","H-help!","[pick(teleportlocs)]!!","Where's [target.name]?","Call the shuttle!")
|
||||
|
||||
var/list/mob/living/carbon/people = list()
|
||||
var/list/mob/living/carbon/person = null
|
||||
for(var/mob/living/carbon/H in view(target))
|
||||
if(H == target)
|
||||
continue
|
||||
if(!person)
|
||||
person = H
|
||||
else
|
||||
if(get_dist(target,H)<get_dist(target,person))
|
||||
person = H
|
||||
people += H
|
||||
if(person) //Basic talk
|
||||
target << target.hear_say(pick(speak_messages),language = pick(person.languages),speaker = person)
|
||||
else // Radio talk
|
||||
var/list/humans = list()
|
||||
for(var/mob/living/carbon/human/H in living_mob_list)
|
||||
humans += H
|
||||
person = pick(humans)
|
||||
target << target.hear_radio(pick(radio_messages),language = pick(person.languages),speaker = person, part_a = "<span class='[frequency_span_class(PUB_FREQ)]'><b>\[[get_frequency_name(PUB_FREQ)]\]</b> <span class='name'>", part_b = "</span> <span class='message'>")
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/hallucination/message
|
||||
|
||||
/obj/effect/hallucination/message/New(loc,var/mob/living/carbon/T)
|
||||
target = T
|
||||
var/chosen = pick("<span class='userdanger'>The light burns you!</span>", \
|
||||
"<span class='danger'>You don't feel like yourself.</span>", \
|
||||
"<span class='userdanger'>Unknown has punched [target]!</span>", \
|
||||
"<span class='notice'>You hear something squeezing through the ducts...</span>", \
|
||||
"<span class='notice'>You hear a distant scream.</span>", \
|
||||
"<span class='notice'>You feel invincible, nothing can hurt you!</span>", \
|
||||
"<B>[target]</B> sneezes.", \
|
||||
"<span class='warning'>You feel faint.</span>", \
|
||||
"<span class='noticealien'>You hear a strange, alien voice in your head...</span>[pick("Hiss","Ssss")]", \
|
||||
"<span class='notice'>You can see...everything!</span>")
|
||||
target << chosen
|
||||
qdel(src)
|
||||
|
||||
/mob/living/carbon/proc/hallucinate(var/hal_type) // Todo -> proc / defines
|
||||
switch(hal_type)
|
||||
if("xeno")
|
||||
new /obj/effect/hallucination/xeno_attack(src.loc,src)
|
||||
if("singulo")
|
||||
new /obj/effect/hallucination/singularity_scare(src.loc,src)
|
||||
if("battle")
|
||||
new /obj/effect/hallucination/battle(src.loc,src)
|
||||
if("flood")
|
||||
new /obj/effect/hallucination/fake_flood(src.loc,src)
|
||||
if("delusion")
|
||||
new /obj/effect/hallucination/delusion(src.loc,src)
|
||||
if("fake")
|
||||
new /obj/effect/hallucination/fakeattacker(src.loc,src)
|
||||
if("bolts")
|
||||
new /obj/effect/hallucination/bolts(src.loc,src)
|
||||
if("bolts_minor")
|
||||
new /obj/effect/hallucination/bolts(src.loc,src,rand(1,2))
|
||||
if("whispers")
|
||||
new /obj/effect/hallucination/whispers(src.loc,src)
|
||||
if("message")
|
||||
new /obj/effect/hallucination/message(src.loc,src)
|
||||
if("sounds")
|
||||
//Strange audio
|
||||
//src << "Strange Audio"
|
||||
switch(rand(1,18))
|
||||
if(1) src << 'sound/machines/airlock.ogg'
|
||||
if(2)
|
||||
if(prob(50))src << 'sound/effects/Explosion1.ogg'
|
||||
else src << 'sound/effects/Explosion2.ogg'
|
||||
if(3) src << 'sound/effects/explosionfar.ogg'
|
||||
if(4) src << 'sound/effects/Glassbr1.ogg'
|
||||
if(5) src << 'sound/effects/Glassbr2.ogg'
|
||||
if(6) src << 'sound/effects/Glassbr3.ogg'
|
||||
if(7) src << 'sound/machines/twobeep.ogg'
|
||||
if(8) src << 'sound/machines/windowdoor.ogg'
|
||||
if(9)
|
||||
//To make it more realistic, I added two gunshots (enough to kill)
|
||||
src << 'sound/weapons/Gunshot.ogg'
|
||||
spawn(rand(10,30))
|
||||
src << 'sound/weapons/Gunshot.ogg'
|
||||
if(10) src << 'sound/weapons/smash.ogg'
|
||||
if(11)
|
||||
//Same as above, but with tasers.
|
||||
src << 'sound/weapons/Taser.ogg'
|
||||
spawn(rand(10,30))
|
||||
src << 'sound/weapons/Taser.ogg'
|
||||
//Rare audio
|
||||
if(12)
|
||||
//These sounds are (mostly) taken from Hidden: Source
|
||||
var/list/creepyasssounds = list('sound/effects/ghost.ogg', 'sound/effects/ghost2.ogg', 'sound/effects/Heart Beat.ogg', 'sound/effects/screech.ogg',\
|
||||
'sound/hallucinations/behind_you1.ogg', 'sound/hallucinations/behind_you2.ogg', 'sound/hallucinations/far_noise.ogg', 'sound/hallucinations/growl1.ogg', 'sound/hallucinations/growl2.ogg',\
|
||||
'sound/hallucinations/growl3.ogg', 'sound/hallucinations/im_here1.ogg', 'sound/hallucinations/im_here2.ogg', 'sound/hallucinations/i_see_you1.ogg', 'sound/hallucinations/i_see_you2.ogg',\
|
||||
'sound/hallucinations/look_up1.ogg', 'sound/hallucinations/look_up2.ogg', 'sound/hallucinations/over_here1.ogg', 'sound/hallucinations/over_here2.ogg', 'sound/hallucinations/over_here3.ogg',\
|
||||
'sound/hallucinations/turn_around1.ogg', 'sound/hallucinations/turn_around2.ogg', 'sound/hallucinations/veryfar_noise.ogg', 'sound/hallucinations/wail.ogg')
|
||||
src << pick(creepyasssounds)
|
||||
if(13)
|
||||
src << "<span class='warning'>You feel a tiny prick!</span>"
|
||||
if(14)
|
||||
src << "<h1 class='alert'>Priority Announcement</h1>"
|
||||
src << "<br><br><span class='alert'>The Emergency Shuttle has docked with the station. You have 3 minutes to board the Emergency Shuttle.</span><br><br>"
|
||||
src << sound('sound/AI/shuttledock.ogg')
|
||||
if(15)
|
||||
src << 'sound/items/Welder.ogg'
|
||||
if(16)
|
||||
src << 'sound/items/Screwdriver.ogg'
|
||||
if(17)
|
||||
src << 'sound/weapons/saberon.ogg'
|
||||
if(18)
|
||||
src << 'sound/weapons/saberoff.ogg'
|
||||
if("hudscrew")
|
||||
//Screwy HUD
|
||||
//src << "Screwy HUD"
|
||||
hal_screwyhud = pick(1,2,3,3,4,4)
|
||||
spawn(rand(100,250))
|
||||
hal_screwyhud = 0
|
||||
if("items")
|
||||
//Strange items
|
||||
//src << "Traitor Items"
|
||||
if(!halitem)
|
||||
halitem = new
|
||||
var/list/slots_free = list(ui_lhand,ui_rhand)
|
||||
if(l_hand) slots_free -= ui_lhand
|
||||
if(r_hand) slots_free -= ui_rhand
|
||||
if(istype(src,/mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = src
|
||||
if(!H.belt) slots_free += ui_belt
|
||||
if(!H.l_store) slots_free += ui_storage1
|
||||
if(!H.r_store) slots_free += ui_storage2
|
||||
if(slots_free.len)
|
||||
halitem.screen_loc = pick(slots_free)
|
||||
halitem.layer = 50
|
||||
switch(rand(1,6))
|
||||
if(1) //revolver
|
||||
halitem.icon = 'icons/obj/gun.dmi'
|
||||
halitem.icon_state = "revolver"
|
||||
halitem.name = "Revolver"
|
||||
if(2) //c4
|
||||
halitem.icon = 'icons/obj/assemblies.dmi'
|
||||
halitem.icon_state = "plastic-explosive0"
|
||||
halitem.name = "Mysterious Package"
|
||||
if(prob(25))
|
||||
halitem.icon_state = "c4small_1"
|
||||
if(3) //sword
|
||||
halitem.icon = 'icons/obj/weapons.dmi'
|
||||
halitem.icon_state = "sword1"
|
||||
halitem.name = "Sword"
|
||||
if(4) //stun baton
|
||||
halitem.icon = 'icons/obj/weapons.dmi'
|
||||
halitem.icon_state = "stunbaton"
|
||||
halitem.name = "Stun Baton"
|
||||
if(5) //emag
|
||||
halitem.icon = 'icons/obj/card.dmi'
|
||||
halitem.icon_state = "emag"
|
||||
halitem.name = "Cryptographic Sequencer"
|
||||
if(6) //flashbang
|
||||
halitem.icon = 'icons/obj/grenade.dmi'
|
||||
halitem.icon_state = "flashbang1"
|
||||
halitem.name = "Flashbang"
|
||||
if(client) client.screen += halitem
|
||||
spawn(rand(100,250))
|
||||
qdel(halitem)
|
||||
if("dangerflash")
|
||||
//Flashes of danger
|
||||
//src << "Danger Flash"
|
||||
if(!halimage)
|
||||
var/list/possible_points = list()
|
||||
for(var/turf/simulated/floor/F in view(src,world.view))
|
||||
possible_points += F
|
||||
if(possible_points.len)
|
||||
var/turf/simulated/floor/target = pick(possible_points)
|
||||
|
||||
switch(rand(1,3))
|
||||
if(1)
|
||||
//src << "Space"
|
||||
halimage = image('icons/turf/space.dmi',target,"[rand(1,25)]",TURF_LAYER)
|
||||
if(2)
|
||||
//src << "Fire"
|
||||
halimage = image('icons/effects/fire.dmi',target,"1",TURF_LAYER)
|
||||
if(3)
|
||||
//src << "C4"
|
||||
halimage = image('icons/obj/assemblies.dmi',target,"plastic-explosive2",OBJ_LAYER+0.01)
|
||||
|
||||
|
||||
if(client) client.images += halimage
|
||||
spawn(rand(10,50)) //Only seen for a brief moment.
|
||||
if(client) client.images -= halimage
|
||||
halimage = null
|
||||
if("death")
|
||||
//Fake death
|
||||
src.sleeping = 20
|
||||
hal_crit = 1
|
||||
hal_screwyhud = 1
|
||||
spawn(rand(50,100))
|
||||
src.sleeping = 0
|
||||
hal_crit = 0
|
||||
hal_screwyhud = 0
|
||||
if("husks")
|
||||
if(!halbody)
|
||||
var/list/possible_points = list()
|
||||
for(var/turf/simulated/floor/F in view(src,world.view))
|
||||
possible_points += F
|
||||
if(possible_points.len)
|
||||
var/turf/simulated/floor/target = pick(possible_points)
|
||||
switch(rand(1,4))
|
||||
if(1)
|
||||
var/image/body = image('icons/mob/human.dmi',target,"husk_s",TURF_LAYER)
|
||||
var/matrix/M = matrix()
|
||||
M.Turn(90)
|
||||
body.transform = M
|
||||
halbody = body
|
||||
if(2,3)
|
||||
halbody = image('icons/mob/human.dmi',target,"husk_s",TURF_LAYER)
|
||||
if(4)
|
||||
halbody = image('icons/mob/alien.dmi',target,"alienother",TURF_LAYER)
|
||||
|
||||
if(client) client.images += halbody
|
||||
spawn(rand(50,80)) //Only seen for a brief moment.
|
||||
if(client) client.images -= halbody
|
||||
halbody = null
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
|
||||
===============================================================================
|
||||
How Garbage Collection Works
|
||||
===============================================================================
|
||||
|
||||
In BYOND, there are exactly two ways anything gets deleted:
|
||||
|
||||
- A "soft delete", which occurs when an object's reference count hits 0, meaning it is not being referenced by anything
|
||||
in the world (more on references further down). When an object is unreferenced, nothing can access it, so it has no
|
||||
reason to exist, and BYOND's garbage collector simply deletes the object. This is fast.
|
||||
|
||||
- A "hard delete", which occurs when the del keyword is used to directly delete an object. This forces BYOND to find
|
||||
every reference to the object being deleted, and null them all out. This is slow.
|
||||
|
||||
A reference is anything that refers to an object, and can thus be used to access it. A variable on another object, a
|
||||
variable in a proc, an argument to a proc, the src of a running proc, the locs of contained objects, another object's
|
||||
contents list (but not the world's automatic contents list), anything. BYOND keeps track of how many references there
|
||||
are to an object - the reference count goes up when you make a new reference to an object, and back down when that
|
||||
reference gets set to null, goes out of scope, or is deleted. When the reference count hits 0, there are no remaining
|
||||
references to the object, and it is deleted by BYOND's garbage collector.
|
||||
|
||||
When you have something that exists in the world, and you want it to stop existing (maybe it got blown up, or eaten by
|
||||
the singularity, or whatever), it needs to be deleted. You can use the del keyword to make sure it's deleted instantly,
|
||||
but del is slow, and you want things to be deleted as quickly as possible, especially if you're deleting a whole lot of
|
||||
them. You want soft deletes.
|
||||
|
||||
That's where the garbage collection system comes in - it prepares things to be soft deleted, and hard deletes anything
|
||||
that can't be. There are two main procs involved in this process:
|
||||
|
||||
/proc/qdel(datumToDelete)
|
||||
This is, effectively, a replacement for del that tells an object to prepare itself to be soft deleted by calling its
|
||||
Destroy() proc. Depending on the qdel hint returned by Destroy(), qdel will queue the object in the garbage collector
|
||||
(to be hard deleted if it isn't soft deleted), directly delete the object, pool the object, or ignore the object and
|
||||
assume it will handle deleting itself. An object passed into qdel will have its gcDestroyed var set, so
|
||||
isnull(gcDestroyed) will be true if an object is not being destroyed, and false if it is (which means you should get
|
||||
rid of the reference you have to it).
|
||||
|
||||
Note that qdel can only work with datum-based objects, which excludes the world (deleting this shuts down the world),
|
||||
clients (deleting these disconnect the client), lists, and savefiles. If any of these are passed to qdel, they will
|
||||
be directly deleted, just as if they had been passed straight to del, so it should never be unsafe to qdel anything
|
||||
you could del.
|
||||
|
||||
/datum/proc/Destroy()
|
||||
This is, effectively, a replacement for Del() (with some exceptions) which is also responsible for nulling out
|
||||
references to or on the object it is called on. Like Del, the Destroy proc will always be called, even if the object
|
||||
is getting destroyed by a direct del instead of qdel; in that case, isnull(gcDestroyed) will be true, and some
|
||||
references can safely be ignored.
|
||||
|
||||
The exceptions where Destroy cannot replace Del are for the same non-datum types mentioned under qdel, above. Those
|
||||
should use a Del proc for any necessary cleanup, as a Destroy proc on them will not automatically get called.
|
||||
|
||||
When called by qdel, Destroy is expected to return a qdel hint, which determines whether the object should be directly
|
||||
deleted, queued for deletion, pooled, or ignored entirely; which of these are appropriate will vary, though objects
|
||||
should be pooled or queued whenever possible. The full list of qdel hints are in the code for the qdel proc.
|
||||
|
||||
As mentioned above, gcDestroyed can be used to tell whether an object is being destroyed. This is important, because if
|
||||
an object is being destroyed, it WILL still exist, and any code that references it should stop referencing it as soon as
|
||||
possible. In the same places that you check whether a reference still exists, you should also check for something like
|
||||
isnull(myRefVar.gcDestroyed), which will be false if your object is being destroyed, meaning you should throw out the
|
||||
reference immediately.
|
||||
|
||||
The inner workings of the GC itself and the stuff related to testing it probably don't need a detailed description - if
|
||||
you intend to work with them, it would be best to read the code to understand what they do.
|
||||
|
||||
Pooling is related to GC, in that it's meant to reduce deletion overhead, but it does so by re-using objects instead of
|
||||
deleting them at all. Explaining pooling is outside the scope of this file.
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,166 @@
|
||||
// Main garbage collection code
|
||||
|
||||
// For general information about how the GC works and how to use it, see __gc_info.dm
|
||||
|
||||
#define GC_COLLECTIONS_PER_TICK 300 // Was 100.
|
||||
#define GC_COLLECTION_TIMEOUT (30 SECONDS)
|
||||
#define GC_FORCE_DEL_PER_TICK 60
|
||||
//#define GC_DEBUG
|
||||
|
||||
// A list of types that were queued in the GC, and had to be soft deleted; used in testing
|
||||
var/list/gc_hard_del_types = list()
|
||||
var/datum/garbage_collector/garbageCollector
|
||||
|
||||
// The time a datum was destroyed by the GC, or null if it hasn't been
|
||||
/datum/var/gcDestroyed
|
||||
// Whether a datum was hard-deleted by the GC; 0 if not, 1 if it was queued, -1 if directly deleted
|
||||
/datum/var/hard_deleted = 0
|
||||
|
||||
/datum/garbage_collector
|
||||
var/list/queue = new
|
||||
var/del_everything = 0
|
||||
|
||||
// To let them know how hardworking am I :^).
|
||||
var/dels_count = 0
|
||||
var/hard_dels = 0
|
||||
var/soft_dels = 0
|
||||
|
||||
/datum/garbage_collector/proc/addTrash(var/datum/D)
|
||||
if(!istype(D) || del_everything)
|
||||
del(D)
|
||||
hard_dels++
|
||||
dels_count++
|
||||
return
|
||||
|
||||
queue -= "\ref[D]" // If this is a re-used ref, remove the old ref from the queue
|
||||
queue["\ref[D]"] = world.time
|
||||
|
||||
/datum/garbage_collector/proc/process()
|
||||
var/remainingCollectionPerTick = GC_COLLECTIONS_PER_TICK
|
||||
var/remainingForceDelPerTick = GC_FORCE_DEL_PER_TICK
|
||||
var/collectionTimeScope = world.time - GC_COLLECTION_TIMEOUT
|
||||
while(queue.len && --remainingCollectionPerTick >= 0)
|
||||
var/refID = queue[1]
|
||||
var/destroyedAtTime = queue[refID]
|
||||
|
||||
if(destroyedAtTime > collectionTimeScope)
|
||||
break
|
||||
|
||||
var/datum/D = locate(refID)
|
||||
// If the object still exists, and it's the same object, hard del it
|
||||
if(D && D.gcDestroyed == destroyedAtTime)
|
||||
if(remainingForceDelPerTick <= 0)
|
||||
break
|
||||
|
||||
#ifdef GC_DEBUG
|
||||
gcwarning("GC process force delete [D.type]")
|
||||
#endif
|
||||
|
||||
hardDel(D)
|
||||
queue.Cut(1, 2)
|
||||
|
||||
remainingForceDelPerTick--
|
||||
else // Otherwise, it was GC'd - remove it from the queue
|
||||
queue.Cut(1, 2)
|
||||
soft_dels++
|
||||
dels_count++
|
||||
|
||||
#ifdef GC_DEBUG
|
||||
#undef GC_DEBUG
|
||||
#endif
|
||||
|
||||
#undef GC_FORCE_DEL_PER_TICK
|
||||
#undef GC_COLLECTION_TIMEOUT
|
||||
#undef GC_COLLECTIONS_PER_TICK
|
||||
|
||||
/datum/garbage_collector/proc/hardDel(var/datum/D)
|
||||
gc_hard_del_types |= D.type
|
||||
D.hard_deleted = 1
|
||||
if(!D.gcDestroyed)
|
||||
spawn(-1)
|
||||
D.Destroy()
|
||||
D.gcDestroyed = world.time
|
||||
del(D)
|
||||
hard_dels++
|
||||
dels_count++
|
||||
|
||||
// Effectively replaces del for any datum-based type
|
||||
/proc/qdel(var/datum/D)
|
||||
if(isnull(D))
|
||||
return
|
||||
|
||||
if(isnull(garbageCollector))
|
||||
del(D)
|
||||
return
|
||||
|
||||
if(!istype(D)) // A non-datum was passed into qdel - just delete it outright.
|
||||
// warning("qdel() passed object of type [D.type]. qdel() can only handle /datum/ types.")
|
||||
del(D)
|
||||
return
|
||||
|
||||
if(isnull(D.gcDestroyed))
|
||||
// Let our friend know they're about to get fucked up.
|
||||
var/hint
|
||||
D.gcDestroyed = world.time
|
||||
try
|
||||
hint = D.Destroy()
|
||||
catch(var/exception/e)
|
||||
if(istype(e))
|
||||
gcwarning("qdel() caught runtime destroying [D.type]: [e] in [e.file], line [e.line]")
|
||||
else
|
||||
gcwarning("qdel() caught runtime destroying [D.type]: [e]")
|
||||
// Destroy runtimed? Panic! Hard delete!
|
||||
D.hard_deleted = -1
|
||||
del(D)
|
||||
if(garbageCollector)
|
||||
garbageCollector.dels_count++
|
||||
return
|
||||
if(!isnull(D.gcDestroyed) && D.gcDestroyed != world.time)
|
||||
gcwarning("Sleep detected in Destroy() call of [D.type]")
|
||||
D.gcDestroyed = world.time
|
||||
|
||||
switch(hint)
|
||||
if(QDEL_HINT_QUEUE) //qdel should queue the object for deletion
|
||||
garbageCollector.addTrash(D)
|
||||
if(QDEL_HINT_LETMELIVE) //qdel should let the object live after calling destroy.
|
||||
return
|
||||
if(QDEL_HINT_IWILLGC) //functionally the same as the above. qdel should assume the object will gc on its own, and not check it.
|
||||
return
|
||||
if (QDEL_HINT_HARDDEL_NOW) //qdel should assume this object won't gc, and hard del it post haste.
|
||||
D.hard_deleted = -1 // -1 means "this hard del skipped the queue", used for profiling
|
||||
del(D)
|
||||
if(garbageCollector)
|
||||
garbageCollector.dels_count++
|
||||
if (QDEL_HINT_PUTINPOOL) //qdel will put this object in the pool.
|
||||
PlaceInPool(D,0)
|
||||
else
|
||||
// world << "WARNING GC DID NOT GET A RETURN VALUE FOR [D], [D.type]!"
|
||||
garbageCollector.addTrash(D)
|
||||
|
||||
/*
|
||||
* Like Del(), but for qdel.
|
||||
* Called BEFORE qdel moves shit.
|
||||
*/
|
||||
/datum/proc/Destroy()
|
||||
tag = null
|
||||
return QDEL_HINT_HARDDEL_NOW // By default, assume that queueing any given datum is unsafe
|
||||
|
||||
// If something gets deleted directly, make sure its Destroy proc is still called
|
||||
/datum/Del()
|
||||
if(isnull(gcDestroyed)) // Not GC'd
|
||||
try
|
||||
Destroy()
|
||||
catch(var/exception/e)
|
||||
if(istype(e))
|
||||
gcwarning("Del() caught runtime destroying [type]: [e] in [e.file], line [e.line]")
|
||||
else
|
||||
gcwarning("Del() caught runtime destroying [type]: [e]")
|
||||
if(del_profiling)
|
||||
delete_profile(src)
|
||||
else
|
||||
if(del_profiling)
|
||||
delete_profile(src)
|
||||
return ..()
|
||||
|
||||
/proc/gcwarning(msg)
|
||||
world.log << "## GC WARNING: [msg]"
|
||||
@@ -0,0 +1,171 @@
|
||||
// Garbage collection testing/debugging/profiling code
|
||||
|
||||
/client/proc/qdel_toggle()
|
||||
set name = "(GC) Toggle Queueing"
|
||||
set desc = "Toggle qdel usage between normal and force del()."
|
||||
set category = "Debug"
|
||||
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
|
||||
garbageCollector.del_everything = !garbageCollector.del_everything
|
||||
// world << "<b>GC: qdel turned [garbageCollector.del_everything ? "off" : "on"].</b>"
|
||||
log_admin("[key_name(usr)] turned qdel [garbageCollector.del_everything ? "off" : "on"].")
|
||||
message_admins("\blue [key_name(usr)] turned qdel [garbageCollector.del_everything ? "off" : "on"].", 1)
|
||||
|
||||
/client/proc/gc_toggle_profiling()
|
||||
set name = "(GC) Toggle Profiling"
|
||||
set desc = "Toggle profiling of deletion methods"
|
||||
set category = "Debug"
|
||||
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
|
||||
del_profiling = !del_profiling
|
||||
log_admin("[key_name(usr)] turned deletion profiling [del_profiling ? "on" : "off"].")
|
||||
message_admins("\blue [key_name(usr)] turned deletion profiling [del_profiling ? "on" : "off"].", 1)
|
||||
|
||||
/client/proc/gc_show_del_report()
|
||||
set name = "(GC) Show Del Report"
|
||||
set desc = "Show report of deletions seen while profiling"
|
||||
set category = "Debug"
|
||||
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
|
||||
delete_profiler_report()
|
||||
|
||||
/client/proc/gc_dump_hdl()
|
||||
set name = "(GC) Hard Del List"
|
||||
set desc = "List types that are hard del()'d by the GC."
|
||||
set category = "Debug"
|
||||
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
|
||||
if(!gc_hard_del_types || !gc_hard_del_types.len)
|
||||
usr << "<span class='notice'>No hard del()'d types found.</span>"
|
||||
return
|
||||
|
||||
usr << "Types hard del()'d by the GC:"
|
||||
for(var/A in gc_hard_del_types)
|
||||
usr << "[A]"
|
||||
|
||||
// Profiling stuff
|
||||
var/global/del_profiling = 0
|
||||
var/global/list/dels_profiled = list()
|
||||
var/global/list/gdels_profiled = list()
|
||||
var/global/list/ghdels_profiled = list()
|
||||
|
||||
/proc/delete_profile(var/datum/D)
|
||||
if(!ticker || (ticker.current_state < 3)) return
|
||||
var/code = 0
|
||||
var/type = D.type
|
||||
if(isnull(D.gcDestroyed))
|
||||
code = 0
|
||||
else if(D.hard_deleted == -1)
|
||||
code = 0 // A non-queued hard deletion is counted as a straight deletion
|
||||
else if(D.hard_deleted)
|
||||
code = 1
|
||||
else
|
||||
code = 2
|
||||
switch(code)
|
||||
if(0) // Directly deleted (skipped the GC queue entirely)
|
||||
if (!("[type]" in dels_profiled))
|
||||
dels_profiled["[type]"] = 0
|
||||
|
||||
dels_profiled["[type]"] += 1
|
||||
if(1) // Hard-deleted by the GC
|
||||
if (!("[type]" in ghdels_profiled))
|
||||
ghdels_profiled["[type]"] = 0
|
||||
|
||||
ghdels_profiled["[type]"] += 1
|
||||
if(2) // qdel'd and garbage collected by BYOND
|
||||
if (!("[type]" in gdels_profiled))
|
||||
gdels_profiled["[type]"] = 0
|
||||
|
||||
gdels_profiled["[type]"] += 1
|
||||
|
||||
/proc/delete_profiler_report()
|
||||
var/dat = "<html><head><title>Deletion Profiler Report</title></head>"
|
||||
if(dels_profiled.len + gdels_profiled.len + ghdels_profiled.len)
|
||||
dat += "<a href='#DD'>Direct Deletions</a><br />"
|
||||
dat += "<a href='#SD'>GC Soft Deletions</a><br />"
|
||||
dat += "<a href='#HD'>GC Hard Deletions</a><br />"
|
||||
dat += delete_profiler_sortedlist(dels_profiled, "Direct Deletions", "DD")
|
||||
dat += delete_profiler_sortedlist(gdels_profiled, "GC Soft Deletions", "SD")
|
||||
dat += delete_profiler_sortedlist(ghdels_profiled, "GC Hard Deletions", "HD")
|
||||
else
|
||||
dat += "(No deletions profiled; listing types that have been hard-deleted by GC)<br />"
|
||||
dat += "<table border='1'><tr><th>GC Hard Deletion Types</th></tr>"
|
||||
for(var/A in gc_hard_del_types)
|
||||
dat += "<tr><td>[A]</td></tr>"
|
||||
dat += "</table>"
|
||||
usr << browse(dat, "window=delete_profiler_report;size=600x480")
|
||||
|
||||
/proc/delete_profiler_sortedlist(var/list/L, var/header, var/anchorid)
|
||||
L = L.Copy()
|
||||
// Yes, this is a terrible sort, but I'm too lazy to find a good one
|
||||
var/v,i,j,s
|
||||
for(i = 1 to L.len-1)
|
||||
s=i
|
||||
v = L[L[i]]
|
||||
for(j = i + 1 to L.len)
|
||||
if(L[L[j]] > v)
|
||||
s = j
|
||||
v = L[L[j]]
|
||||
L.Swap(i,s)
|
||||
|
||||
var/dat = "<table border='1' id='[anchorid]'><tr><th colspan='2'>[header]</th></tr>"
|
||||
for (var/t in L)
|
||||
dat +="<tr><td>[L[t]]</td><td>[t]</td></tr>"
|
||||
dat += "</table>"
|
||||
return dat
|
||||
|
||||
/*/client/var/running_find_references
|
||||
|
||||
/atom/verb/find_references()
|
||||
set category = "Debug"
|
||||
set name = "Find References"
|
||||
set background = 1
|
||||
set src in world
|
||||
|
||||
if(!usr || !usr.client)
|
||||
return
|
||||
|
||||
if(usr.client.running_find_references)
|
||||
testing("CANCELLED search for references to a [usr.client.running_find_references].")
|
||||
usr.client.running_find_references = null
|
||||
return
|
||||
|
||||
if(alert("Running this will create a lot of lag until it finishes. You can cancel it by running it again. Would you like to begin the search?", "Find References", "Yes", "No") == "No")
|
||||
return
|
||||
qdel(src)
|
||||
// Remove this object from the list of things to be auto-deleted.
|
||||
if(garbageCollector)
|
||||
garbageCollector.queue -= "\ref[src]"
|
||||
|
||||
usr.client.running_find_references = type
|
||||
testing("Beginning search for references to a [type].")
|
||||
var/list/things = list()
|
||||
for(var/client/thing)
|
||||
things += thing
|
||||
for(var/datum/thing)
|
||||
things += thing
|
||||
for(var/atom/thing)
|
||||
things += thing
|
||||
for(var/event/thing)
|
||||
things += thing
|
||||
testing("Collected list of things in search for references to a [type]. ([things.len] Thing\s)")
|
||||
for(var/datum/thing in things)
|
||||
if(!usr.client.running_find_references) return
|
||||
for(var/varname in thing.vars)
|
||||
var/variable = thing.vars[varname]
|
||||
if(variable == src)
|
||||
testing("Found [src.type] \ref[src] in [thing.type]'s [varname] var.")
|
||||
else if(islist(variable))
|
||||
if(src in variable)
|
||||
testing("Found [src.type] \ref[src] in [thing.type]'s [varname] list var.")
|
||||
testing("Completed search for references to a [type].")
|
||||
usr.client.running_find_references = null
|
||||
*/
|
||||
@@ -450,7 +450,8 @@
|
||||
"slimejelly",
|
||||
"cyanide",
|
||||
"lsd",
|
||||
"morphine"
|
||||
"morphine",
|
||||
"ether"
|
||||
)
|
||||
|
||||
for(var/x=1;x<=additional_chems;x++)
|
||||
|
||||
@@ -1190,7 +1190,7 @@
|
||||
name = "gelthi"
|
||||
seed_name = "gelthi"
|
||||
display_name = "gelthi plant"
|
||||
chems = list("morphine" = list(1,5),"capsaicin" = list(1,5),"plantmatter" = list(1,5))
|
||||
chems = list("ether" = list(1,5),"capsaicin" = list(1,5),"plantmatter" = list(1,5))
|
||||
|
||||
/datum/seed/gelthi/New()
|
||||
..()
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
//*******************************//
|
||||
|
||||
var/list/fruit_icon_states = list("badrecipe","kudzupod","reishi","lime","grapes","boiledrorocore","chocolateegg")
|
||||
var/list/reagent_effects = list("toxin","charcoal","morphine","space_drugs","lsd","haloperidol")
|
||||
var/list/reagent_effects = list("toxin","charcoal","ether","space_drugs","lsd","haloperidol")
|
||||
var/jungle_plants_init = 0
|
||||
|
||||
/proc/init_jungle_plants()
|
||||
|
||||
@@ -924,16 +924,13 @@ var/global/list/brutefireloss_overlays = list("1" = image("icon" = 'icons/mob/sc
|
||||
else
|
||||
hallucination -= 2
|
||||
|
||||
else
|
||||
for(var/atom/a in hallucinations)
|
||||
del a
|
||||
|
||||
if(halloss > 100)
|
||||
src << "<span class='notice'>You're in too much pain to keep going...</span>"
|
||||
for(var/mob/O in oviewers(src, null))
|
||||
O.show_message("<B>[src]</B> slumps to the ground, too weak to continue fighting.", 1)
|
||||
Paralyse(10)
|
||||
setHalLoss(99)
|
||||
if(halloss > 100)
|
||||
src << "<span class='notice'>You're in too much pain to keep going...</span>"
|
||||
for(var/mob/O in oviewers(src, null))
|
||||
O.show_message("<B>[src]</B> slumps to the ground, too weak to continue fighting.", 1)
|
||||
Paralyse(10)
|
||||
setHalLoss(99)
|
||||
|
||||
if(paralysis)
|
||||
AdjustParalysis(-1)
|
||||
@@ -947,7 +944,7 @@ var/global/list/brutefireloss_overlays = list("1" = image("icon" = 'icons/mob/sc
|
||||
adjustStaminaLoss(-10)
|
||||
adjustHalLoss(-3)
|
||||
if (mind)
|
||||
//Are they SSD? If so we'll keep them asleep but work off some of that sleep var in case of morphine or similar.
|
||||
//Are they SSD? If so we'll keep them asleep but work off some of that sleep var in case of ether or similar.
|
||||
if(player_logged)
|
||||
sleeping = max(sleeping-1, 2)
|
||||
else
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
var/staminaloss = 0 //Stamina damage, or exhaustion. You recover it slowly naturally, and are stunned if it gets too high. Holodeck and hallucinations deal this.
|
||||
|
||||
var/hallucination = 0 //Directly affects how long a mob will hallucinate for
|
||||
var/list/atom/hallucinations = list() //A list of hallucinated people that try to attack the mob. See /obj/effect/fake_attacker in hallucinations.dm
|
||||
|
||||
|
||||
var/last_special = 0 //Used by the resist verb, likely used to prevent players from bypassing next_move by logging in/out.
|
||||
|
||||
@@ -373,7 +373,7 @@
|
||||
src.modules += new /obj/item/device/flash/cyborg/alien(src)
|
||||
src.modules += new /obj/item/borg/sight/thermal/alien(src)
|
||||
var/obj/item/weapon/reagent_containers/spray/alien/stun/S = new /obj/item/weapon/reagent_containers/spray/alien/stun(src)
|
||||
S.reagents.add_reagent("morphine",250) //nerfed to sleeptoxin to make it less instant drop.
|
||||
S.reagents.add_reagent("ether",250) //nerfed to sleeptoxin to make it less instant drop.
|
||||
src.modules += S
|
||||
var/obj/item/weapon/reagent_containers/spray/alien/smoke/A = new /obj/item/weapon/reagent_containers/spray/alien/smoke(src)
|
||||
S.reagents.add_reagent("water",50) //Water is used as a dummy reagent for the smoke bombs. More of an ammo counter.
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
melee_damage_upper = 10
|
||||
poison_per_bite = 10
|
||||
var/atom/cocoon_target
|
||||
poison_type = "morphine"
|
||||
poison_type = "ether"
|
||||
var/fed = 0
|
||||
|
||||
//hunters have the most poison and move the fastest, so they can find prey
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
var/lastout = 0
|
||||
var/loaddemand = 0
|
||||
var/capacity = 5e6
|
||||
var/charge = 1e6
|
||||
var/charge = 0
|
||||
var/charging = 0
|
||||
var/chargemode = 0
|
||||
var/chargecount = 0
|
||||
@@ -470,6 +470,9 @@
|
||||
|
||||
|
||||
|
||||
/obj/machinery/power/smes/engineering
|
||||
charge = 1e6 // Engineering starts with some charge for singulo
|
||||
|
||||
/obj/machinery/power/smes/magical
|
||||
name = "magical power storage unit"
|
||||
desc = "A high-capacity superconducting magnetic energy storage (SMES) unit. Magically produces power."
|
||||
|
||||
@@ -150,7 +150,7 @@ var/list/solars_list = list()
|
||||
|
||||
/obj/machinery/power/solar/ex_act(severity, target)
|
||||
..()
|
||||
if(!gc_destroyed)
|
||||
if(isnull(gcDestroyed))
|
||||
switch(severity)
|
||||
if(2)
|
||||
if(prob(50) && broken())
|
||||
@@ -501,7 +501,7 @@ var/list/solars_list = list()
|
||||
|
||||
/obj/machinery/power/solar_control/ex_act(severity, target)
|
||||
..()
|
||||
if(!gc_destroyed)
|
||||
if(isnull(gcDestroyed))
|
||||
switch(severity)
|
||||
if(2)
|
||||
if(prob(50))
|
||||
|
||||
@@ -127,32 +127,6 @@ datum
|
||||
if (!target.reagents || src.total_volume<=0)
|
||||
return
|
||||
|
||||
/*var/datum/reagents/R = target.reagents
|
||||
|
||||
var/obj/item/weapon/reagent_containers/glass/beaker/noreact/B = new /obj/item/weapon/reagent_containers/glass/beaker/noreact //temporary holder
|
||||
|
||||
amount = min(min(amount, src.total_volume), R.maximum_volume-R.total_volume)
|
||||
var/part = amount / src.total_volume
|
||||
var/trans_data = null
|
||||
for (var/datum/reagent/current_reagent in src.reagent_list)
|
||||
if (!current_reagent)
|
||||
continue
|
||||
//if (current_reagent.id == "blood" && ishuman(target))
|
||||
// var/mob/living/carbon/human/H = target
|
||||
// H.inject_blood(my_atom, amount)
|
||||
// continue
|
||||
var/current_reagent_transfer = current_reagent.volume * part
|
||||
if(preserve_data)
|
||||
trans_data = current_reagent.data
|
||||
|
||||
B.add_reagent(current_reagent.id, (current_reagent_transfer * multiplier), trans_data, safety = 1) //safety checks on these so all chemicals are transferred
|
||||
src.remove_reagent(current_reagent.id, current_reagent_transfer, safety = 1) // to the target container before handling reactions
|
||||
|
||||
src.update_total()
|
||||
B.update_total()
|
||||
B.handle_reactions()
|
||||
src.handle_reactions()*/
|
||||
|
||||
var/obj/item/weapon/reagent_containers/glass/beaker/noreact/B = new /obj/item/weapon/reagent_containers/glass/beaker/noreact //temporary holder
|
||||
B.volume = 1000
|
||||
|
||||
@@ -163,9 +137,13 @@ datum
|
||||
|
||||
src.trans_to(B, amount)
|
||||
|
||||
spawn(100)
|
||||
spawn(-1)
|
||||
src = null // Survive through deletion of the reagent holder
|
||||
sleep(100)
|
||||
if(!target)
|
||||
return
|
||||
BR.trans_to(target, BR.total_volume)
|
||||
del(B)
|
||||
qdel(B)
|
||||
|
||||
return amount
|
||||
|
||||
|
||||
@@ -234,6 +234,7 @@ datum
|
||||
reagent_state = LIQUID
|
||||
color = "#0064C8" // rgb: 0, 100, 200
|
||||
var/cooling_temperature = 2
|
||||
process_flags = ORGANIC | SYNTHETIC
|
||||
|
||||
reaction_mob(var/mob/living/M, var/method=TOUCH, var/volume)
|
||||
if(!istype(M, /mob/living))
|
||||
@@ -3238,4 +3239,4 @@ datum
|
||||
holder.reagent_list -= src
|
||||
holder = null
|
||||
|
||||
return ..()
|
||||
return ..()
|
||||
|
||||
@@ -1463,7 +1463,7 @@ datum
|
||||
name = "Neurotoxin"
|
||||
id = "neurotoxin"
|
||||
result = "neurotoxin"
|
||||
required_reagents = list("gargleblaster" = 1, "morphine" = 1)
|
||||
required_reagents = list("gargleblaster" = 1, "ether" = 1)
|
||||
result_amount = 2
|
||||
|
||||
snowwhite
|
||||
|
||||
@@ -297,7 +297,7 @@
|
||||
starting_chems = list("silver_sulfadiazine","styptic_powder","charcoal")
|
||||
|
||||
/obj/item/weapon/gun/dartgun/vox/raider
|
||||
starting_chems = list("space_drugs","morphine","haloperidol")
|
||||
starting_chems = list("space_drugs","ether","haloperidol")
|
||||
|
||||
/obj/effect/syringe_gun_dummy //moved this shitty thing here
|
||||
name = ""
|
||||
|
||||
@@ -913,6 +913,36 @@ datum/reagent/haloperidol/on_mob_life(var/mob/living/M as mob)
|
||||
result_amount = 4
|
||||
mix_message = "The chemicals mix into an odd pink slush."
|
||||
|
||||
|
||||
/datum/reagent/ether
|
||||
name = "Ether"
|
||||
id = "ether"
|
||||
description = "A strong anesthetic and sedative."
|
||||
reagent_state = LIQUID
|
||||
color = "#96DEDE"
|
||||
|
||||
/datum/reagent/ether/on_mob_life(var/mob/living/M as mob)
|
||||
if(!M) M = holder.my_atom
|
||||
switch(current_cycle)
|
||||
if(0 to 15)
|
||||
if(prob(5))
|
||||
M.emote("yawn")
|
||||
if(16 to 35)
|
||||
M.drowsyness = max(M.drowsyness, 10)
|
||||
if(36 to INFINITY)
|
||||
M.Paralyse(10)
|
||||
M.drowsyness = max(M.drowsyness, 15)
|
||||
..()
|
||||
return
|
||||
|
||||
/datum/chemical_reaction/ether
|
||||
name = "Ether"
|
||||
id = "ether"
|
||||
result = "ether"
|
||||
required_reagents = list("sacid" = 1, "ethanol" = 1, "oxygen" = 1)
|
||||
result_amount = 1
|
||||
mix_message = "The mixture yields a pungent odor, which makes you tired."
|
||||
|
||||
//////////////////////////////
|
||||
// Synth-Meds //
|
||||
//////////////////////////////
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
M << "\blue You swallow some of contents of the [src]."
|
||||
if(reagents.total_volume)
|
||||
reagents.reaction(M, INGEST)
|
||||
spawn(5)
|
||||
spawn(0)
|
||||
reagents.trans_to_ingest(M, 10)
|
||||
|
||||
playsound(M.loc,'sound/items/drink.ogg', rand(10,50), 1)
|
||||
@@ -59,7 +59,7 @@
|
||||
|
||||
if(reagents.total_volume)
|
||||
reagents.reaction(M, INGEST)
|
||||
spawn(5)
|
||||
spawn(0)
|
||||
reagents.trans_to(M, 10)
|
||||
|
||||
playsound(M.loc,'sound/items/drink.ogg', rand(10,50), 1)
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
M << "\blue You swallow a gulp of [src]."
|
||||
if(reagents.total_volume)
|
||||
reagents.reaction(M, INGEST)
|
||||
spawn(5)
|
||||
spawn(0)
|
||||
reagents.trans_to_ingest(M, gulp_size)
|
||||
|
||||
playsound(M.loc,'sound/items/drink.ogg', rand(10,50), 1)
|
||||
@@ -65,7 +65,7 @@
|
||||
|
||||
if(reagents.total_volume)
|
||||
reagents.reaction(M, INGEST)
|
||||
spawn(5)
|
||||
spawn(0)
|
||||
reagents.trans_to_ingest(M, gulp_size)
|
||||
|
||||
if(isrobot(user)) //Cyborg modules that include drinks automatically refill themselves, but drain the borg's cell
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
playsound(M.loc,'sound/items/eatfood.ogg', rand(10,50), 1)
|
||||
if(reagents.total_volume)
|
||||
reagents.reaction(M, INGEST)
|
||||
spawn(5)
|
||||
spawn(0)
|
||||
if(reagents.total_volume > bitesize)
|
||||
/*
|
||||
* I totally cannot understand what this code supposed to do.
|
||||
@@ -675,7 +675,7 @@
|
||||
New()
|
||||
..()
|
||||
reagents.add_reagent("nutriment", 12)
|
||||
reagents.add_reagent("morphine", 3)
|
||||
reagents.add_reagent("ether", 3)
|
||||
bitesize = 3
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/stuffing
|
||||
@@ -3116,7 +3116,7 @@
|
||||
New()
|
||||
..()
|
||||
reagents.add_reagent("nutriment", 12)
|
||||
reagents.add_reagent("morphine", 3)
|
||||
reagents.add_reagent("ether", 3)
|
||||
bitesize = 3
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/stuffing
|
||||
|
||||
@@ -150,6 +150,15 @@
|
||||
..()
|
||||
reagents.add_reagent("morphine", 30)
|
||||
|
||||
/obj/item/weapon/reagent_containers/glass/bottle/ether
|
||||
name = "Ether Bottle"
|
||||
desc = "A small bottle. Contains ether."
|
||||
icon = 'icons/obj/chemical.dmi'
|
||||
icon_state = "bottle17"
|
||||
New()
|
||||
..()
|
||||
reagents.add_reagent("ether", 30)
|
||||
|
||||
/obj/item/weapon/reagent_containers/glass/bottle/charcoal
|
||||
name = "Charcoal Bottle"
|
||||
desc = "A small bottle. Contains charcoal."
|
||||
|
||||
@@ -21,12 +21,18 @@
|
||||
return
|
||||
attack(mob/M as mob, mob/user as mob, def_zone)
|
||||
if(M == user)
|
||||
M << "\blue You [apply_method] [src]."
|
||||
if(istype(M,/mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(H.species.flags & IS_SYNTHETIC)
|
||||
H << "<span class='warning'>You have a monitor for a head, where do you think you're going to put that?</span>"
|
||||
return
|
||||
|
||||
M << "<span class='notify'>You [apply_method] [src].</span>"
|
||||
M.unEquip(src) //icon update
|
||||
if(reagents.total_volume)
|
||||
reagents.reaction(M, apply_type)
|
||||
spawn(5)
|
||||
reagents.trans_to(M, reagents.total_volume)
|
||||
spawn(0)
|
||||
reagents.trans_to_ingest(M, reagents.total_volume)
|
||||
qdel(src)
|
||||
else
|
||||
qdel(src)
|
||||
@@ -34,14 +40,19 @@
|
||||
|
||||
else if(istype(M, /mob/living/carbon/human) )
|
||||
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(H.species.flags & IS_SYNTHETIC)
|
||||
user << "<span class='warning'>They have a monitor for a head, where do you think you're going to put that?</span>"
|
||||
return
|
||||
|
||||
for(var/mob/O in viewers(world.view, user))
|
||||
O.show_message("\red [user] attempts to force [M] to [apply_method] [src].", 1)
|
||||
O.show_message("<span class='warning'>[user] attempts to force [M] to [apply_method] [src].</span>", 1)
|
||||
|
||||
if(!do_mob(user, M)) return
|
||||
|
||||
user.unEquip(src) //icon update
|
||||
for(var/mob/O in viewers(world.view, user))
|
||||
O.show_message("\red [user] forces [M] to [apply_method] [src].", 1)
|
||||
O.show_message("<span class='warning'>[user] forces [M] to [apply_method] [src].</span>", 1)
|
||||
|
||||
M.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has been fed [src.name] by [user.name] ([user.ckey]) Reagents: [reagentlist(src)]</font>")
|
||||
user.attack_log += text("\[[time_stamp()]\] <font color='red'>Fed [M.name] by [M.name] ([M.ckey]) Reagents: [reagentlist(src)]</font>")
|
||||
@@ -54,7 +65,7 @@
|
||||
|
||||
if(reagents.total_volume)
|
||||
reagents.reaction(M, apply_type)
|
||||
spawn(5)
|
||||
spawn(0)
|
||||
reagents.trans_to_ingest(M, reagents.total_volume)
|
||||
qdel(src)
|
||||
else
|
||||
@@ -69,7 +80,7 @@
|
||||
|
||||
if(target.is_open_container() != 0 && target.reagents)
|
||||
if(!target.reagents.total_volume)
|
||||
user << "\red [target] is empty. Cant dissolve [src]."
|
||||
user << "<span class='warning'>[target] is empty. Cant dissolve [src].</span>"
|
||||
return
|
||||
|
||||
// /vg/: Logging transfers of bad things
|
||||
@@ -83,10 +94,10 @@
|
||||
message_admins("[user.name] ([user.ckey]) added [reagents.get_reagent_ids(1)] to \a [target] with [src].[hl] (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[user.x];Y=[user.y];Z=[user.z]'>JMP</a>)")
|
||||
log_game("[user.name] ([user.ckey]) added [reagents.get_reagent_ids(1)] to \a [target] with [src].")
|
||||
|
||||
user << "\blue You dissolve [src] in [target]"
|
||||
user << "<span class='notify'>You dissolve [src] in [target].</span>"
|
||||
reagents.trans_to(target, reagents.total_volume)
|
||||
for(var/mob/O in viewers(2, user))
|
||||
O.show_message("\red [user] puts something in [target].", 1)
|
||||
O.show_message("<span class='warning'>[user] puts something in [target].</span>", 1)
|
||||
spawn(5)
|
||||
qdel(src)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user