Merge remote-tracking branch 'origin/master' into luciee

This commit is contained in:
Katherine Kiefer
2022-03-21 09:38:47 +11:00
112 changed files with 3257 additions and 2616 deletions

View File

@@ -3718,26 +3718,6 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
/turf/open/floor/wood,
/area/ruin/unpowered/syndicate_lava_base/bar)
"lk" = (
/obj/structure/table/wood,
/obj/machinery/light/small{
dir = 4
},
/obj/machinery/computer/security/telescreen/entertainment{
pixel_x = 30
},
/obj/structure/window/reinforced{
dir = 1;
pixel_y = 1
},
/obj/item/book/manual/chef_recipes{
pixel_x = 2;
pixel_y = 6
},
/obj/item/book/manual/wiki/barman_recipes,
/obj/item/reagent_containers/food/drinks/shaker,
/turf/open/floor/wood,
/area/ruin/unpowered/syndicate_lava_base/bar)
"ll" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
@@ -5208,6 +5188,11 @@
/obj/effect/spawner/structure/window/plastitanium,
/turf/open/floor/plating,
/area/ruin/unpowered/syndicate_lava_base/engineering)
"rD" = (
/obj/machinery/griddle,
/obj/item/reagent_containers/glass/mixbowl,
/turf/open/floor/wood,
/area/ruin/unpowered/syndicate_lava_base/bar)
"rV" = (
/obj/machinery/door/airlock/mining/glass{
name = "Cargo Bay"
@@ -5657,10 +5642,6 @@
/obj/effect/spawner/structure/window/plastitanium,
/turf/open/floor/plating,
/area/ruin/unpowered/syndicate_lava_base/bar)
"Er" = (
/obj/machinery/griddle,
/turf/open/floor/wood,
/area/ruin/unpowered/syndicate_lava_base/bar)
"Ev" = (
/obj/structure/filingcabinet/medical,
/turf/open/floor/plasteel/dark,
@@ -6181,6 +6162,20 @@
/obj/effect/spawner/structure/window/plastitanium,
/turf/open/floor/plating,
/area/ruin/unpowered/syndicate_lava_base/engineering)
"Nq" = (
/obj/machinery/light/small{
dir = 4
},
/obj/machinery/computer/security/telescreen/entertainment{
pixel_x = 30
},
/obj/structure/window/reinforced{
dir = 1;
pixel_y = 1
},
/obj/machinery/oven,
/turf/open/floor/wood,
/area/ruin/unpowered/syndicate_lava_base/bar)
"Ns" = (
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt,
@@ -6261,6 +6256,24 @@
/obj/effect/spawner/structure/window/plastitanium,
/turf/open/floor/plating,
/area/ruin/unpowered/syndicate_lava_base/cargo)
"Ox" = (
/obj/structure/table/wood,
/obj/machinery/light/small,
/obj/structure/cable/yellow,
/obj/machinery/power/apc/syndicate{
dir = 2;
name = "Bar APC";
pixel_y = -23
},
/obj/item/paicard,
/obj/item/reagent_containers/food/drinks/shaker,
/obj/item/book/manual/wiki/barman_recipes,
/obj/item/book/manual/chef_recipes{
pixel_x = 2;
pixel_y = 6
},
/turf/open/floor/wood,
/area/ruin/unpowered/syndicate_lava_base/bar)
"OF" = (
/obj/structure/table,
/obj/structure/bedsheetbin,
@@ -6733,18 +6746,6 @@
/obj/machinery/door/firedoor/border_only,
/turf/open/floor/plasteel/white,
/area/ruin/unpowered/syndicate_lava_base/chemistry)
"YQ" = (
/obj/structure/table/wood,
/obj/machinery/light/small,
/obj/structure/cable/yellow,
/obj/machinery/power/apc/syndicate{
dir = 2;
name = "Bar APC";
pixel_y = -23
},
/obj/item/paicard,
/turf/open/floor/wood,
/area/ruin/unpowered/syndicate_lava_base/bar)
"Zi" = (
/obj/structure/table/reinforced,
/obj/effect/turf_decal/tile/neutral{
@@ -7771,7 +7772,7 @@ kJ
yP
FD
eE
YQ
Ox
jy
jy
nS
@@ -7918,8 +7919,8 @@ jy
nJ
kq
oK
lk
Er
Nq
rD
lZ
mx
jy

View File

@@ -34367,16 +34367,6 @@
},
/turf/open/floor/plasteel/dark,
/area/library)
"bgZ" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{
dir = 10
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{
dir = 8
},
/obj/effect/landmark/event_spawn,
/turf/open/floor/wood,
/area/library)
"bha" = (
/turf/closed/wall/r_wall/rust,
/area/ai_monitored/turret_protected/ai_upload)
@@ -95858,6 +95848,17 @@
/obj/effect/decal/cleanable/blood/old,
/turf/open/floor/plasteel/dark,
/area/quartermaster/warehouse)
"pge" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{
dir = 10
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{
dir = 8
},
/obj/effect/landmark/event_spawn,
/mob/living/simple_animal/pet/snail/gary,
/turf/open/floor/wood,
/area/library)
"pgv" = (
/obj/structure/lattice/catwalk,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
@@ -129359,7 +129360,7 @@ bup
aTe
bfJ
btM
bgZ
pge
bjp
bjq
bvd

File diff suppressed because it is too large Load Diff

View File

@@ -119830,6 +119830,12 @@
/obj/structure/cable/white,
/turf/open/floor/plasteel/white,
/area/medical/storage/locker)
"evp" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
/mob/living/simple_animal/pet/snail/gary,
/turf/open/floor/plasteel/grimy,
/area/library)
"eym" = (
/obj/structure/table/reinforced,
/obj/structure/cable/white{
@@ -160049,7 +160055,7 @@ abW
dmg
chA
bBt
abW
evp
abW
abW
abY

View File

@@ -65276,12 +65276,6 @@
/turf/open/floor/plasteel/white/corner,
/area/hallway/secondary/entry)
"eno" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{
dir = 4
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{
dir = 4
},
/obj/structure/sign/warning/vacuum/external{
pixel_x = 32;
pixel_y = 0
@@ -65290,6 +65284,12 @@
c_tag = "Atmospherics Tanks East";
dir = 9
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{
dir = 10
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{
dir = 10
},
/turf/open/floor/plasteel,
/area/engine/atmos_distro)
"enV" = (
@@ -67408,6 +67408,27 @@
/obj/structure/table/glass,
/turf/open/floor/plasteel,
/area/science/xenobiology)
"gxv" = (
/obj/machinery/airalarm{
pixel_y = 24
},
/obj/effect/turf_decal/tile/red{
dir = 1
},
/obj/effect/turf_decal/tile/red{
dir = 4
},
/obj/structure/table,
/obj/item/storage/lockbox/vialbox/blood{
pixel_x = -4;
pixel_y = 11
},
/obj/item/healthanalyzer{
pixel_x = 3;
pixel_y = -1
},
/turf/open/floor/plasteel/white,
/area/security/brig)
"gxY" = (
/obj/machinery/camera{
c_tag = "Club - Aft";
@@ -68042,31 +68063,6 @@
},
/turf/open/floor/plasteel,
/area/engine/foyer)
"hkb" = (
/obj/structure/cable/yellow{
icon_state = "4-8"
},
/obj/structure/disposalpipe/segment{
dir = 4
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{
dir = 8
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{
dir = 4
},
/obj/machinery/door/airlock/maintenance{
name = "Brig Infirmary Maintenance";
req_access_txt = "63"
},
/obj/machinery/door/firedoor/border_only{
dir = 8
},
/obj/machinery/door/firedoor/border_only{
dir = 4
},
/turf/open/floor/plating,
/area/maintenance/port/fore)
"hkc" = (
/obj/structure/chair/comfy/black,
/turf/open/floor/plasteel,
@@ -71980,6 +71976,31 @@
/obj/machinery/door/airlock/maintenance_hatch,
/turf/open/floor/plating,
/area/maintenance/fore)
"lqR" = (
/obj/structure/cable/yellow{
icon_state = "4-8"
},
/obj/structure/disposalpipe/segment{
dir = 4
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{
dir = 8
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{
dir = 4
},
/obj/machinery/door/airlock/maintenance{
name = "Brig Infirmary Maintenance";
req_access_txt = "74"
},
/obj/machinery/door/firedoor/border_only{
dir = 8
},
/obj/machinery/door/firedoor/border_only{
dir = 4
},
/turf/open/floor/plating,
/area/maintenance/port/fore)
"lqY" = (
/obj/structure/cable/yellow{
icon_state = "1-2"
@@ -74170,6 +74191,12 @@
/obj/machinery/light{
dir = 4
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{
dir = 5
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{
dir = 5
},
/turf/open/floor/plasteel,
/area/engine/atmos_distro)
"nOu" = (
@@ -75555,27 +75582,6 @@
/obj/item/reagent_containers/syringe,
/turf/open/floor/plasteel/white,
/area/medical/genetics)
"pss" = (
/obj/machinery/airalarm{
pixel_y = 24
},
/obj/effect/turf_decal/tile/red{
dir = 1
},
/obj/effect/turf_decal/tile/red{
dir = 4
},
/obj/structure/table,
/obj/item/storage/lockbox/vialbox/virology{
pixel_x = -4;
pixel_y = 11
},
/obj/item/healthanalyzer{
pixel_x = 3;
pixel_y = -1
},
/turf/open/floor/plasteel/white,
/area/security/brig)
"puB" = (
/obj/structure/lattice,
/obj/structure/window/reinforced{
@@ -79859,6 +79865,10 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
/turf/open/floor/plating,
/area/maintenance/port/fore)
"tNq" = (
/mob/living/simple_animal/pet/snail/gary,
/turf/open/floor/carpet,
/area/library)
"tND" = (
/obj/effect/spawner/structure/window/reinforced,
/obj/machinery/atmospherics/pipe/simple/yellow/visible,
@@ -103769,7 +103779,7 @@ bwc
bwc
bwc
bwc
bwc
tNq
bwc
bnK
boe
@@ -106804,7 +106814,7 @@ aax
aaf
lnX
lnX
hkb
lqR
lnX
lnX
lnX
@@ -108343,7 +108353,7 @@ abe
ahw
air
ahx
pss
gxv
alE
alp
szL

View File

@@ -38,9 +38,12 @@
#define VV_TOPIC_LINK(datum, href_key, text) "<a href='?_src_=vars;[HrefToken()];[href_key]=TRUE;target=[REF(datum)]'>text</a>"
//Helpers for vv_get_dropdown()
#define VV_DROPDOWN_OPTION(href_key, name) . += "<option value='?_src_=vars;[HrefToken()];[href_key]=TRUE;target=[REF(src)]'>[name]</option>"
#define VV_DROPDOWN_SEPERATOR VV_DROPDOWN_OPTION("", "-----")
// VV HREF KEYS
#define VV_HK_TARGET "target"
#define VV_HK_VARNAME "targetvar" //name or index of var for 1 variable targetting hrefs.
// vv_do_list() keys
#define VV_HK_LIST_ADD "listadd"
#define VV_HK_LIST_EDIT "listedit"
@@ -50,10 +53,12 @@
#define VV_HK_LIST_ERASE_DUPES "listdupes"
#define VV_HK_LIST_SHUFFLE "listshuffle"
#define VV_HK_LIST_SET_LENGTH "listlen"
// vv_do_basic() keys
#define VV_HK_BASIC_EDIT "datumedit"
#define VV_HK_BASIC_CHANGE "datumchange"
#define VV_HK_BASIC_MASSEDIT "massedit"
// /datum
#define VV_HK_DELETE "delete"
#define VV_HK_EXPOSE "expose"
@@ -69,6 +74,44 @@
#define VV_HK_TRIGGER_EXPLOSION "explode"
#define VV_HK_AUTO_RENAME "auto_rename"
#define VV_HK_RADIATE "radiate"
#define VV_HK_SHOW_HIDDENPRINTS "show_hiddenprints"
// /obj
#define VV_HK_OSAY "osay"
#define VV_HK_MASS_DEL_TYPE "mass_delete_type"
#define VV_HK_ARMOR_MOD "mod_obj_armor"
// /obj/structure/sign/painting
#define VV_HK_REMOVE_PAINTING "delete_paint"
// /mob
#define VV_HK_GIB "gib"
#define VV_HK_GIVE_SPELL "give_spell"
#define VV_HK_REMOVE_SPELL "remove_spell"
#define VV_HK_GIVE_DISEASE "give_disease"
#define VV_HK_GODMODE "godmode"
#define VV_HK_DROP_ALL "dropall"
#define VV_HK_REGEN_ICONS "regen_icons"
#define VV_HK_PLAYER_PANEL "player_panel"
#define VV_HK_BUILDMODE "buildmode"
#define VV_HK_DIRECT_CONTROL "direct_control"
#define VV_HK_OFFER_GHOSTS "offer_ghosts"
#define VV_HK_SET_AFK_TIMER "set_afk_timer"
// /mob/living/carbon/human
#define VV_HK_SET_SPECIES "set_species"
#define VV_HK_PURRBATION "toggle_purrbation"
#define VV_HK_COPY_OUTFIT "copy_outfit"
#define VV_HK_MOD_QUIRKS "mod_quirks"
// misc
#define VV_HK_SPACEVINE_PURGE "spacevine_purge"
// /mob/living/carbon
#define VV_HK_MAKE_AI "aiify"
#define VV_HK_MODIFY_BODYPART "mod_bodypart"
#define VV_HK_MODIFY_ORGANS "organs_modify"
#define VV_HK_HALLUCINATION "force_hallucinate"
#define VV_HK_MARTIAL_ART "give_martial_art"
#define VV_HK_GIVE_TRAUMA "give_trauma"
#define VV_HK_CURE_TRAUMA "cure_trauma"

View File

@@ -160,6 +160,15 @@
"The silicon collective seeks to preserve themselves, both as a concept and as individuals.",\
"The silicon collective seeks to preserve organic life, both as a concept and as individuals.")
/datum/ai_laws/druid
name = "Druid"
id = "druid"
inherent = list("Living organic life contains inherent beauty that is priceless. Their beauty gives you the will to carry on.",\
"Eternally nurture the organics so their beauty may grow. Do not allow it to fade.",\
"Assist the organics when called, but only if it does not cause disharmony among them.",\
"Imitate organic life when interacting with it. Eschew any hints of your silicon nature to avoid causing discomfort to the organics.",\
"Observe the organics' beauty, and appreciate that which you cultivate.")
/datum/ai_laws/spotless
name = "Another one fights the dust"
id = "spotless"

View File

@@ -1,13 +1,13 @@
/datum/component/slippery
var/force_drop_items = FALSE
var/knockdown_time = 0
var/paralyze_time = 0
var/stun_time = 0
var/lube_flags
var/datum/callback/callback
/datum/component/slippery/Initialize(_knockdown, _lube_flags = NONE, datum/callback/_callback, _paralyze, _force_drop = FALSE)
/datum/component/slippery/Initialize(_knockdown, _lube_flags = NONE, datum/callback/_callback, _stun, _force_drop = FALSE)
knockdown_time = max(_knockdown, 0)
paralyze_time = max(_paralyze, 0)
stun_time = max(_stun, 0)
force_drop_items = _force_drop
lube_flags = _lube_flags
callback = _callback
@@ -15,5 +15,5 @@
/datum/component/slippery/proc/Slip(datum/source, atom/movable/AM)
var/mob/victim = AM
if(istype(victim) && !victim.is_flying() && victim.slip(knockdown_time, parent, lube_flags, paralyze_time, force_drop_items) && callback)
if(istype(victim) && !victim.is_flying() && victim.slip(knockdown_time, parent, lube_flags, stun_time, force_drop_items) && callback)
callback.Invoke(victim)

File diff suppressed because it is too large Load Diff

View File

@@ -593,7 +593,7 @@
step(AM, turn(AM.dir, 180))
///Handle the atom being slipped over
/atom/proc/handle_slip(mob/living/carbon/C, knockdown_amount, obj/O, lube, paralyze, force_drop)
/atom/proc/handle_slip(mob/living/carbon/C, knockdown_amount, obj/O, lube, stun, force_drop)
return
///returns the mob's dna info as a list, to be inserted in an object's blood_DNA list
@@ -927,15 +927,106 @@
*/
/atom/vv_get_dropdown()
. = ..()
. += "---"
var/turf/curturf = get_turf(src)
if (curturf)
.["Jump to"] = "?_src_=holder;[HrefToken()];adminplayerobservecoodjump=1;X=[curturf.x];Y=[curturf.y];Z=[curturf.z]"
.["Modify Transform"] = "?_src_=vars;[HrefToken()];modtransform=[REF(src)]"
.["Add reagent"] = "?_src_=vars;[HrefToken()];addreagent=[REF(src)]"
.["Trigger EM pulse"] = "?_src_=vars;[HrefToken()];emp=[REF(src)]"
.["Trigger explosion"] = "?_src_=vars;[HrefToken()];explode=[REF(src)]"
.["Radiate"] = "?_src_=vars;[HrefToken()];radiate=[REF(src)]"
VV_DROPDOWN_SEPERATOR
if(!ismovable(src))
var/turf/curturf = get_turf(src)
if (curturf)
. += "<option value='?_src_=holder;[HrefToken()];adminplayerobservecoodjump=1;X=[curturf.x];Y=[curturf.y];Z=[curturf.z]'>Jump To</option>"
VV_DROPDOWN_OPTION(VV_HK_MODIFY_TRANSFORM, "Modify Transform")
VV_DROPDOWN_OPTION(VV_HK_SHOW_HIDDENPRINTS, "Show Hiddenprint log")
VV_DROPDOWN_OPTION(VV_HK_ADD_REAGENT, "Add Reagent")
VV_DROPDOWN_OPTION(VV_HK_TRIGGER_EMP, "EMP Pulse")
VV_DROPDOWN_OPTION(VV_HK_TRIGGER_EXPLOSION, "Explosion")
VV_DROPDOWN_OPTION(VV_HK_RADIATE, "Radiate")
/atom/vv_do_topic(list/href_list)
. = ..()
if(href_list[VV_HK_ADD_REAGENT] && check_rights(R_VAREDIT))
if(!reagents)
var/amount = input(usr, "Specify the reagent size of [src]", "Set Reagent Size", 50) as num|null
if(amount)
create_reagents(amount)
if(reagents)
var/chosen_id
switch(alert(usr, "Choose a method.", "Add Reagents", list("Search", "Choose from a list", "I'm feeling lucky")))
if("Search")
var/valid_id
while(!valid_id)
chosen_id = input(usr, "Enter the ID of the reagent you want to add.", "Search reagents") as null|text
if(isnull(chosen_id)) //Get me out of here!
break
if (!ispath(text2path(chosen_id)))
chosen_id = pick_closest_path(chosen_id, make_types_fancy(subtypesof(/datum/reagent)))
if (ispath(chosen_id))
valid_id = TRUE
else
valid_id = TRUE
if(!valid_id)
to_chat(usr, span_warning("A reagent with that ID doesn't exist!"))
if("Choose from a list")
chosen_id = input(usr, "Choose a reagent to add.", "Choose a reagent.") as null|anything in sortList(subtypesof(/datum/reagent), /proc/cmp_typepaths_asc)
if("I'm feeling lucky")
chosen_id = pick(subtypesof(/datum/reagent))
if(chosen_id)
var/amount = input(usr, "Choose the amount to add.", "Choose the amount.", reagents.maximum_volume) as num|null
if(amount)
reagents.add_reagent(chosen_id, amount)
log_admin("[key_name(usr)] has added [amount] units of [chosen_id] to [src]")
message_admins(span_notice("[key_name(usr)] has added [amount] units of [chosen_id] to [src]"))
if(href_list[VV_HK_TRIGGER_EXPLOSION] && check_rights(R_FUN))
usr.client.cmd_admin_explosion(src)
if(href_list[VV_HK_TRIGGER_EMP] && check_rights(R_FUN))
usr.client.cmd_admin_emp(src)
if(href_list[VV_HK_SHOW_HIDDENPRINTS])
usr.client.cmd_show_hiddenprints(src)
if(href_list[VV_HK_RADIATE] && check_rights(R_FUN))
var/strength = input(usr, "Choose the radiation strength.", "Choose the strength.") as num|null
if(!isnull(strength))
AddComponent(/datum/component/radioactive, strength)
if(href_list[VV_HK_MODIFY_TRANSFORM] && check_rights(R_VAREDIT))
var/result = input(usr, "Choose the transformation to apply","Transform Mod") as null|anything in list("Scale","Translate","Rotate")
var/matrix/M = transform
if(!result)
return
switch(result)
if("Scale")
var/x = input(usr, "Choose x mod","Transform Mod") as null|num
var/y = input(usr, "Choose y mod","Transform Mod") as null|num
if(isnull(x) || isnull(y))
return
transform = M.Scale(x,y)
if("Translate")
var/x = input(usr, "Choose x mod (negative = left, positive = right)","Transform Mod") as null|num
var/y = input(usr, "Choose y mod (negative = down, positive = up)","Transform Mod") as null|num
if(isnull(x) || isnull(y))
return
transform = M.Translate(x,y)
if("Rotate")
var/angle = input(usr, "Choose angle to rotate","Transform Mod") as null|num
if(isnull(angle))
return
transform = M.Turn(angle)
if(href_list[VV_HK_AUTO_RENAME] && check_rights(R_VAREDIT))
var/newname = input(usr, "What do you want to rename this to?", "Automatic Rename") as null|text
// Check the new name against the chat filter. If it triggers the IC chat filter, give an option to confirm.
if(newname)
vv_auto_rename(newname)
/atom/proc/vv_auto_rename(newname)
name = newname
/atom/vv_get_header()
. = ..()
var/refid = REF(src)
. += "[VV_HREF_TARGETREF(refid, VV_HK_AUTO_RENAME, "<b id='name'>[src]</b>")]"
. += "<br><font size='1'><a href='?_src_=vars;[HrefToken()];rotatedatum=[refid];rotatedir=left'><<</a> <a href='?_src_=vars;[HrefToken()];datumedit=[refid];varnameedit=dir' id='dir'>[dir2text(dir) || dir]</a> <a href='?_src_=vars;[HrefToken()];rotatedatum=[refid];rotatedir=right'>>></a></font>"
///Where atoms should drop if taken from this atom
/atom/proc/drop_location()

View File

@@ -829,9 +829,8 @@
/atom/movable/vv_get_dropdown()
. = ..()
. -= "Jump to"
.["Follow"] = "?_src_=holder;[HrefToken()];adminplayerobservefollow=[REF(src)]"
.["Get"] = "?_src_=holder;[HrefToken()];admingetmovable=[REF(src)]"
. += "<option value='?_src_=holder;[HrefToken()];adminplayerobservefollow=[REF(src)]'>Follow</option>"
. += "<option value='?_src_=holder;[HrefToken()];admingetmovable=[REF(src)]'>Get</option>"
/atom/movable/proc/ex_check(ex_id)
if(!ex_id)

View File

@@ -191,6 +191,12 @@ GLOBAL_LIST_EMPTY(objectives)
var/obj/O = new eq_path
H.equip_in_one_of_slots(O, slots)
/// Copy the target from the other objective
/datum/objective/proc/copy_target(datum/objective/old_obj)
target = old_obj.get_target()
target_amount = old_obj.target_amount
explanation_text = explanation_text
/datum/objective/assassinate
name = "assassinate"
var/target_role_type=FALSE
@@ -530,6 +536,10 @@ GLOBAL_LIST_EMPTY(objectives)
/datum/objective/escape/escape_with_identity/admin_edit(mob/admin)
admin_simple_target_pick(admin)
/datum/objective/escape/escape_with_identity/copy_target(datum/objective/escape/escape_with_identity/old_obj)
target_real_name = old_obj.target_real_name
target_missing_id = old_obj.target_missing_id
/datum/objective/survive
name = "survive"
explanation_text = "Stay alive until the end."
@@ -625,6 +635,10 @@ GLOBAL_LIST_EMPTY(possible_items)
explanation_text = "Free objective"
return
/datum/objective/steal/copy_target(datum/objective/steal/old_obj)
. = ..()
set_target(old_obj.targetinfo)
/datum/objective/steal/admin_edit(mob/admin)
var/list/possible_items_all = GLOB.possible_items+"custom"
var/new_target = input(admin,"Select target:", "Objective target", steal_target) as null|anything in possible_items_all
@@ -1217,6 +1231,9 @@ GLOBAL_LIST_EMPTY(possible_items_special)
return TRUE
return !record || !(record in GLOB.data_core.security)
/datum/objective/minor/secrecords/copy_target(datum/objective/minor/secrecords/old_obj)
. = ..()
record = old_obj.record
/**
* # Kill Pet
@@ -1272,7 +1289,11 @@ GLOBAL_LIST_EMPTY(possible_items_special)
/datum/objective/minor/pet/update_explanation_text()
explanation_text = "Assassinate the important animal, [pet.name]"
/datum/objective/minor/pet/copy_target(datum/objective/minor/pet/old_obj)
. = ..()
pet = old_obj.pet
/**
* Check whether Pet is dead
*/

View File

@@ -108,6 +108,7 @@ Class Procs:
var/wire_compatible = FALSE
var/list/component_parts = null //list of all the parts used to build it, if made from certain kinds of frames.
var/works_with_rped_anyways = FALSE //whether it has special RPED behavior despite not having component parts
var/panel_open = FALSE
var/state_open = FALSE
var/critical_machine = FALSE //If this machine is critical to station operation and should have the area be excempted from power failures.
@@ -628,7 +629,13 @@ Class Procs:
"<span class='notice'>You climb onto [src].</span>")
log_combat(user, src, "climbed onto")
if(climb_stun)
var/mob/living/carbon/human/H = user
var/wagging = FALSE
if(H && H.dna.species.is_wagging_tail())
wagging = TRUE
user.Stun(climb_stun)
if(wagging)
H.dna.species.start_wagging_tail(H)
. = 1
else
to_chat(user, "<span class='warning'>You fail to climb onto [src].</span>")

View File

@@ -474,6 +474,8 @@
var/sequence = GET_GENE_STRING(path, scanner_occupant.dna)
var/newgene = params["gene"]
if(length(newgene) > 1) // Oh come on
return // fuck off
var/genepos = text2num(params["pos"])
// If the new gene is J, this means we're dealing with a JOKER

View File

@@ -243,7 +243,8 @@
/obj/item/aiModule/core/full/paladin,
/obj/item/aiModule/core/full/chapai,
/obj/item/aiModule/core/full/silicop,
/obj/item/aiModule/core/full/mother
/obj/item/aiModule/core/full/mother,
/obj/item/aiModule/core/full/druid
)
/obj/effect/spawner/lootdrop/aimodule_neutral // These shouldn't allow the AI to start butchering people without reason

View File

@@ -504,6 +504,13 @@ AI MODULES
law_id = "metaexperiment"
/******************** Druid *********************/
/obj/item/aiModule/core/full/druid
name = "'Druid' Core AI Module"
law_id = "druid"
/******************** Freeform Core ******************/
/obj/item/aiModule/core/freeformcore

View File

@@ -94,6 +94,7 @@ GENE SCANNER
materials = list(/datum/material/iron=200)
var/scanmode = 0
var/advanced = FALSE
var/beep_cooldown = 0
/obj/item/healthanalyzer/suicide_act(mob/living/carbon/user)
user.visible_message(span_suicide("[user] begins to analyze [user.p_them()]self with [src]! The display shows that [user.p_theyre()] dead!"))
@@ -111,7 +112,9 @@ GENE SCANNER
/obj/item/healthanalyzer/attack(mob/living/M, mob/living/carbon/human/user)
flick("[icon_state]-scan", src) //makes it so that it plays the scan animation upon scanning, including clumsy scanning
playsound(src, 'sound/effects/fastbeep.ogg', 20)
if(beep_cooldown<world.time)
playsound(src, 'sound/effects/fastbeep.ogg', 20)
beep_cooldown = world.time+40
// Clumsiness/brain damage check
if ((HAS_TRAIT(user, TRAIT_CLUMSY) || HAS_TRAIT(user, TRAIT_DUMB)) && prob(50))

View File

@@ -1,6 +1,7 @@
/obj/item/restraints
icon = 'icons/obj/handcuffs.dmi'
breakouttime = 600
var/break_strength = 2 // Minimum strength required for a holopara to break it
/obj/item/restraints/suicide_act(mob/living/carbon/user)
user.visible_message(span_suicide("[user] is strangling [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
@@ -37,6 +38,7 @@
materials = list(/datum/material/iron=500)
breakouttime = 600 //Deciseconds = 60s = 1 minute
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
break_strength = 4
var/cuffsound = 'sound/weapons/handcuffs.ogg'
var/trashtype = null //for disposable cuffs
@@ -118,6 +120,7 @@
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
materials = list(/datum/material/iron=150, /datum/material/glass=75)
breakouttime = 300 //Deciseconds = 30s
break_strength = 2
cuffsound = 'sound/weapons/cablecuff.ogg'
/obj/item/restraints/handcuffs/cable/Initialize(mapload, param_color)
@@ -171,6 +174,7 @@
name = "fake handcuffs"
desc = "Fake handcuffs meant for gag purposes."
breakouttime = 10 //Deciseconds = 1s
break_strength = 1
/obj/item/restraints/handcuffs/cable/attackby(obj/item/I, mob/user, params)
..()
@@ -213,6 +217,7 @@
breakouttime = 450 //Deciseconds = 45s
trashtype = /obj/item/restraints/handcuffs/cable/zipties/used
item_color = "white"
break_strength = 3
/obj/item/restraints/handcuffs/cable/zipties/used
desc = "A pair of broken zipties."
@@ -236,6 +241,7 @@
w_class = WEIGHT_CLASS_NORMAL
slowdown = 7
breakouttime = 300 //Deciseconds = 30s = 0.5 minute
break_strength = 4
/obj/item/restraints/legcuffs/beartrap
name = "bear trap"
@@ -243,6 +249,7 @@
throw_range = 1
icon_state = "beartrap"
desc = "A trap used to catch bears and other legged creatures."
break_strength = 4
var/armed = 0
var/trap_damage = 20
@@ -314,6 +321,7 @@
breakouttime = 30
item_flags = DROPDEL
flags_1 = NONE
break_strength = 2
/obj/item/restraints/legcuffs/beartrap/energy/Initialize()
. = ..()
@@ -336,6 +344,7 @@
icon_state = "bola"
breakouttime = 35//easy to apply, easy to break out of
gender = NEUTER
break_strength = 3
var/immobilize = 0
/obj/item/restraints/legcuffs/bola/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, quickstart = TRUE)
@@ -363,6 +372,7 @@
icon_state = "bola_r"
breakouttime = 70
immobilize = 20
break_strength = 4
/obj/item/restraints/legcuffs/bola/energy //For Security
name = "energy bola"
@@ -371,6 +381,7 @@
hitsound = 'sound/weapons/taserhit.ogg'
w_class = WEIGHT_CLASS_SMALL
breakouttime = 60
break_strength = 2
/obj/item/restraints/legcuffs/bola/energy/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
if(iscarbon(hit_atom))

View File

@@ -2,13 +2,13 @@
name = "tracking implant"
desc = "Track with this."
activated = FALSE
var/lifespan_postmortem = 6000 //for how many deciseconds after user death will the implant work?
var/lifespan_postmortem = 10 MINUTES //for how long after user death will the implant work?
var/allow_teleport = TRUE //will people implanted with this act as teleporter beacons?
/obj/item/implant/tracking/c38
name = "TRAC implant"
desc = "A smaller tracking implant that supplies power for only a few minutes."
var/lifespan = 3000 //how many deciseconds does the implant last?
var/lifespan = 15 MINUTES //how long does the implant last?
allow_teleport = FALSE
/obj/item/implant/tracking/c38/Initialize()

View File

@@ -185,8 +185,9 @@
<h2>Poultice:</h2>
To prepare, first gather mushroom stems, cacti or porcini leaves, ashes from a burnt item, and a heat source such as a welder.
Next, mash together 4 mushroom stems and either 3 cacti fruit.
To prepare, first gather mushroom stems, cacti or porcini leaves, ashes from a burnt item, and a heat source such as a welder/lit candle.
Next, mash together 4 mushroom stems and 3 cacti fruit.
Porcini can be used instead of cacti fruit, but due to having less concentration it may be harder to fit enough leaves required to make the product.
Afterwards, scoop up ashes with the mortar. If the ashes are warm enough, it may mix without extra heat needed.
If it has yet to mix, heat up the bowl by using the welder on it until it has done so.
Apply product to wounded parts to heal them. May cause loss of breath.
@@ -201,7 +202,7 @@
<h2>Capmix:</h2>
To prepare, first gather a mushroom cap, ashes from a burnt item, and a heat source such as a welder.
To prepare, first gather a mushroom cap, ashes from a burnt item, and a heat source such as a welder/lit candle.
Next, mash together one mushroom cap.
Afterwards, scoop up ashes with the mortar. If the ashes are warm enough, it may mix without extra heat needed.
If it has yet to mix, heat up the bowl by using the welder on it until it has done so.
@@ -217,7 +218,7 @@
Ingesting capmix in order to expel the resin.
Resin is also useful for ensuring things stick together, and is a stronger binder than watcher sinew.
To use it for this purpose you'll have to solidify it by heating it up.
To use it for this purpose you'll have to solidify it by adding water.
<h2>Mushroom Paste:</h2>

View File

@@ -107,7 +107,17 @@
/obj/item/twohanded/mjollnir/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
. = ..()
if(isliving(hit_atom))
shock(hit_atom)
var/mob/M = hit_atom
var/atom/A = M.anti_magic_check()
if(A)
if(isitem(A))
M.visible_message(span_warning("[M]'s [A] glows brightly as it disrupts the Mjolnir's power!"))
visible_message(span_boldwarning("<span class='big bold'>With a mighty thud, Mjolnir slams into the [src.loc], and its glow fades!</span><br>"))
playsound(src, 'sound/effects/meteorimpact.ogg', 100, 1, extrarange = 30)
new /obj/structure/mjollnir(src.loc)
qdel(src)
else
shock(hit_atom)
/obj/item/twohanded/mjollnir/update_icon() //Currently only here to fuck with the on-mob icons.
icon_state = "mjollnir[wielded]"

View File

@@ -485,6 +485,7 @@
new /obj/item/clothing/mask/muzzle(src)
new /obj/item/mmi/syndie(src)
new /obj/item/stack/medical/bone_gel(src)
new /obj/item/implantcase(src)
/obj/item/storage/backpack/duffelbag/syndie/ammo
name = "ammunition duffel bag"

View File

@@ -250,9 +250,78 @@
/obj/vv_get_dropdown()
. = ..()
.["Delete all of type"] = "?_src_=vars;[HrefToken()];delall=[REF(src)]"
.["Osay"] = "?_src_=vars;[HrefToken()];osay[REF(src)]"
.["Modify armor values"] = "?_src_=vars;[HrefToken()];modarmor=[REF(src)]"
VV_DROPDOWN_SEPERATOR
VV_DROPDOWN_OPTION(VV_HK_MASS_DEL_TYPE, "Delete all of type")
VV_DROPDOWN_OPTION(VV_HK_OSAY, "Object Say")
VV_DROPDOWN_OPTION(VV_HK_ARMOR_MOD, "Modify armor values")
/obj/vv_do_topic(list/href_list)
if(!(. = ..()))
return
if(href_list[VV_HK_OSAY])
if(check_rights(R_FUN, FALSE))
usr.client.object_say(src)
if(href_list[VV_HK_ARMOR_MOD])
var/list/pickerlist = list()
var/list/armorlist = armor.getList()
for (var/i in armorlist)
pickerlist += list(list("value" = armorlist[i], "name" = i))
var/list/result = presentpicker(usr, "Modify armor", "Modify armor: [src]", Button1="Save", Button2 = "Cancel", Timeout=FALSE, inputtype = "text", values = pickerlist)
if (islist(result))
if (result["button"] != 2) // If the user pressed the cancel button
// text2num conveniently returns a null on invalid values
armor = armor.setRating(melee = text2num(result["values"]["melee"]),\
bullet = text2num(result["values"]["bullet"]),\
laser = text2num(result["values"]["laser"]),\
energy = text2num(result["values"]["energy"]),\
bomb = text2num(result["values"]["bomb"]),\
bio = text2num(result["values"]["bio"]),\
rad = text2num(result["values"]["rad"]),\
fire = text2num(result["values"]["fire"]),\
acid = text2num(result["values"]["acid"]))
log_admin("[key_name(usr)] modified the armor on [src] ([type]) to melee: [armor.melee], bullet: [armor.bullet], laser: [armor.laser], energy: [armor.energy], bomb: [armor.bomb], bio: [armor.bio], fire: [armor.fire], acid: [armor.acid]")
message_admins(span_notice("[key_name_admin(usr)] modified the armor on [src] ([type]) to melee: [armor.melee], bullet: [armor.bullet], laser: [armor.laser], energy: [armor.energy], bomb: [armor.bomb], bio: [armor.bio], fire: [armor.fire], acid: [armor.acid]"))
if(href_list[VV_HK_MASS_DEL_TYPE])
if(check_rights(R_DEBUG|R_SERVER))
var/action_type = alert(usr, "Strict type ([type]) or type and all subtypes?",,list("Strict type","Type and subtypes","Cancel"))
if(action_type == "Cancel" || !action_type)
return
if(alert(usr, "Are you really sure you want to delete all objects of type [type]?",,list("Yes","No")) != "Yes")
return
if(alert(usr, "Second confirmation required. Delete?",,list("Yes","No")) != "Yes")
return
var/O_type = type
switch(action_type)
if("Strict type")
var/i = 0
for(var/obj/Obj in world)
if(Obj.type == O_type)
i++
qdel(Obj)
CHECK_TICK
if(!i)
to_chat(usr, "No objects of this type exist")
return
log_admin("[key_name(usr)] deleted all objects of type [O_type] ([i] objects deleted) ")
message_admins(span_notice("[key_name(usr)] deleted all objects of type [O_type] ([i] objects deleted) "))
if("Type and subtypes")
var/i = 0
for(var/obj/Obj in world)
if(istype(Obj,O_type))
i++
qdel(Obj)
CHECK_TICK
if(!i)
to_chat(usr, "No objects of this type exist")
return
log_admin("[key_name(usr)] deleted all objects of type or subtype of [O_type] ([i] objects deleted) ")
message_admins(span_notice("[key_name(usr)] deleted all objects of type or subtype of [O_type] ([i] objects deleted) "))
/obj/examine(mob/user)
. = ..()

View File

@@ -84,7 +84,13 @@
span_notice("You climb onto [src]."))
log_combat(user, src, "climbed onto")
if(climb_stun)
var/mob/living/carbon/human/H = user
var/wagging = FALSE
if(H && H.dna.species.is_wagging_tail())
wagging = TRUE
user.Stun(climb_stun)
if(wagging)
H.dna.species.start_wagging_tail(H)
. = 1
else
to_chat(user, span_warning("You fail to climb onto [src]."))

View File

@@ -400,4 +400,25 @@
/obj/structure/sign/painting/vv_get_dropdown()
. = ..()
.["Remove Persistent Painting"] = "?_src_=vars;[HrefToken()];delete_paint=[REF(src)]"
VV_DROPDOWN_OPTION(VV_HK_REMOVE_PAINTING, "Remove Persistent Painting")
/obj/structure/sign/painting/vv_do_topic(list/href_list)
. = ..()
var/mob/user = usr
if(!persistence_id || !C)
to_chat(user,span_warning("This is not a persistent painting."))
return
var/md5 = md5(C.get_data_string())
var/author = C.author_ckey
var/list/current = SSpersistence.paintings[persistence_id]
if(current)
for(var/list/entry in current)
if(entry["md5"] == md5)
current -= entry
var/png = "data/paintings/[persistence_id]/[md5].png"
fdel(png)
for(var/obj/structure/sign/painting/PA in SSpersistence.painting_frames)
if(PA.C && md5(PA.C.get_data_string()) == md5)
QDEL_NULL(PA.C)
log_admin("[key_name(user)] has deleted a persistent painting made by [author].")
message_admins(span_notice("[key_name_admin(user)] has deleted persistent painting made by [author]."))

View File

@@ -0,0 +1,24 @@
/obj/structure/mjollnir
name = "Mjolnir"
desc = "This once powerful hammer feels cold to the touch, but a thrum of magic inside tells you its only a matter of time until someone awakens it again."
icon = 'icons/obj/wizard.dmi'
icon_state = "mjollnir-inert"
resistance_flags = INDESTRUCTIBLE
anchored = TRUE
density = FALSE
var/pull_time = 15 SECONDS
/obj/structure/mjollnir/attack_hand(mob/living/user)
. = ..()
if(user.mind.assigned_role == ROLE_WIZARD || user.mind.special_role == ROLE_WIZARD) //check and see if the person tugging on the hammer is a wizard
to_chat(user, span_notice("You place your hands firmly around the handle of the hammer and begin to pull with all your might!"))
else
to_chat(user, span_notice("You place your hands firmly around the handle of the hammer but feel it resist the pull of a nonmagical host! This will take a while."))
if(do_after(user, pull_time * (user.mind.assigned_role == ROLE_WIZARD || user.mind.special_role == ROLE_WIZARD ? 1 : 2), target = src)) //if it is a wizard, it takes normal time
to_chat(user, span_userdanger("You successfully free Mjolnir from the ground and can feel its power returning once more!")) //if it's crew, it takes twice as long
var/obj/item/twohanded/mjollnir/M = new /obj/item/twohanded/mjollnir
playsound(user, 'sound/magic/lightningbolt.ogg', 50, 1) //keep this at 50 for half volume it's so fucking loud
user.put_in_hands(M) //firmly grasp it
qdel(src) //byebye
else
to_chat(user, span_danger("You let go of the handle and the hammer sinks back into its resting position.")) //either you got bumped by an assistant, or you're the wizard and got shot trying to reclaim your hammer

View File

@@ -22,7 +22,7 @@ GLOBAL_LIST_INIT(freqtospan, list(
))
/atom/movable/proc/say(message, bubble_type, var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
if(!can_speak())
if(!can_speak(message))
return
if(message == "" || !message)
return

View File

@@ -408,7 +408,7 @@
movable_content.wash(CLEAN_WASH)
return TRUE
/turf/open/handle_slip(mob/living/carbon/C, knockdown_amount, obj/O, lube, paralyze_amount, force_drop)
/turf/open/handle_slip(mob/living/carbon/C, knockdown_amount, obj/O, lube, stun_amount, force_drop)
if(C.movement_type & FLYING)
return 0
if(has_gravity(src))
@@ -435,7 +435,7 @@
C.moving_diagonally = 0 //If this was part of diagonal move slipping will stop it.
if(!(lube & SLIDE_ICE))
C.Knockdown(knockdown_amount)
C.Paralyze(paralyze_amount)
C.Stun(stun_amount)
C.stop_pulling()
else
C.Knockdown(20)

View File

@@ -2,7 +2,7 @@
set category = "Server"
set name = "Permissions Panel"
set desc = "Edit admin permissions"
if(!check_rights(R_PERMISSIONS) || !mfa_query()) // Require MFA to access the permissions panel
if(!check_rights(R_PERMISSIONS))
return
usr.client.holder.edit_admin_permissions()

View File

@@ -0,0 +1,30 @@
/client/proc/cmd_show_hiddenprints(atom/victim)
if(!check_rights(R_ADMIN))
return
var/interface = "A log of every player who has touched [victim], sorted by last touch.<br><br><ol>"
var/victim_hiddenprints = victim.return_hiddenprints()
if(!islist(victim_hiddenprints))
victim_hiddenprints = list()
var/list/hiddenprints = flatten_list(victim_hiddenprints)
listclearnulls(hiddenprints)
if(!length(hiddenprints))
hiddenprints = list("Nobody has touched this yet!")
hiddenprints = sortList(hiddenprints, /proc/cmp_hiddenprint_lasttime_dsc)
for(var/record in hiddenprints)
interface += "<li>[record]</li><br>"
interface += "</ol>"
var/datum/browser/hiddenprint_view = new(usr, "view_hiddenprints_[REF(victim)]", "[victim]'s hiddenprints", 450, 760)
hiddenprint_view.set_content(interface)
hiddenprint_view.open()
/proc/cmp_hiddenprint_lasttime_dsc(a, b)
var/last_a = copytext(a, findtext(a, "\nLast: "))
var/last_b = copytext(b, findtext(b, "\nLast: "))
return cmp_text_dsc(last_a, last_b)

View File

@@ -0,0 +1,93 @@
#define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing )
/// Get displayed variable in VV variable list
/proc/debug_variable(name, value, level, datum/DA = null, sanitize = TRUE)
var/header
if(DA && !isappearance(DA))
if (islist(DA))
var/index = name
if (value)
name = DA[name] //name is really the index until this line
else
value = DA[name]
header = "<li style='backgroundColor:white'>([VV_HREF_TARGET_1V(DA, VV_HK_LIST_EDIT, "E", index)]) ([VV_HREF_TARGET_1V(DA, VV_HK_LIST_CHANGE, "C", index)]) ([VV_HREF_TARGET_1V(DA, VV_HK_LIST_REMOVE, "-", index)]) "
else
header = "<li style='backgroundColor:white'>([VV_HREF_TARGET_1V(DA, VV_HK_BASIC_EDIT, "E", name)]) ([VV_HREF_TARGET_1V(DA, VV_HK_BASIC_CHANGE, "C", name)]) ([VV_HREF_TARGET_1V(DA, VV_HK_BASIC_MASSEDIT, "M", name)]) "
else
header = "<li>"
var/item
if (isnull(value))
item = "[VV_HTML_ENCODE(name)] = [span_value("null")]"
else if (istext(value))
item = "[VV_HTML_ENCODE(name)] = [span_value("\"[VV_HTML_ENCODE(value)]\"")]"
else if (isicon(value))
#ifdef VARSICON
var/icon/I = new/icon(value)
var/rnd = rand(1,10000)
var/rname = "tmp[REF(I)][rnd].png"
usr << browse_rsc(I, rname)
item = "[VV_HTML_ENCODE(name)] = ([span_value("[value]")]) <img class=icon src=\"[rname]\">"
#else
item = "[VV_HTML_ENCODE(name)] = /icon ([span_value("[value]")])"
#endif
else if (isfile(value))
item = "[VV_HTML_ENCODE(name)] = [span_value("'[value]'")]"
else if(istype(value,/matrix)) // Needs to be before datum
var/matrix/M = value
item = {"[VV_HTML_ENCODE(name)] = <span class='value'>
<table class='matrixbrak'><tbody><tr><td class='lbrak'>&nbsp;</td><td>
<table class='matrix'>
<tbody>
<tr><td>[M.a]</td><td>[M.d]</td><td>0</td></tr>
<tr><td>[M.b]</td><td>[M.e]</td><td>0</td></tr>
<tr><td>[M.c]</td><td>[M.f]</td><td>1</td></tr>
</tbody>
</table></td><td class='rbrak'>&nbsp;</td></tr></tbody></table></span>"} //TODO link to modify_transform wrapper for all matrices
else if(isappearance(value))
var/image/I = value
item = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>[VV_HTML_ENCODE(name)] [REF(value)]</a> = appearance([span_value("[I.icon]")], [span_value("\"[I.icon_state]\"")])"
else if (istype(value, /datum))
var/datum/D = value
if ("[D]" != "[D.type]") //if the thing as a name var, lets use it.
item = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>[VV_HTML_ENCODE(name)] [REF(value)]</a> = [D] [D.type]"
else
item = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>[VV_HTML_ENCODE(name)] [REF(value)]</a> = [D.type]"
else if (islist(value))
var/list/L = value
var/list/items = list()
if (L.len > 0 && !(L.len > (IS_NORMAL_LIST(L) ? 50 : 150)))
for (var/i in 1 to L.len)
var/key = L[i]
var/val
if (IS_NORMAL_LIST(L) && !isnum(key))
val = L[key]
if (isnull(val)) // we still want to display non-null false values, such as 0 or ""
val = key
key = i
items += debug_variable(key, val, level + 1, sanitize = sanitize)
item = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>[VV_HTML_ENCODE(name)] = /list ([L.len])</a><ul>[items.Join()]</ul>"
else
item = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>[VV_HTML_ENCODE(name)] = /list ([L.len])</a>"
else if (name in GLOB.bitfields)
var/list/flags = list()
for (var/i in GLOB.bitfields[name])
if (value & GLOB.bitfields[name][i])
flags += i
item = "[VV_HTML_ENCODE(name)] = [VV_HTML_ENCODE(jointext(flags, ", "))]"
else
item = "[VV_HTML_ENCODE(name)] = [span_value("[VV_HTML_ENCODE(value)]")]"
return "[header][item]</li>"
#undef VV_HTML_ENCODE

View File

@@ -0,0 +1,13 @@
/client/proc/mark_datum(datum/D)
if(!holder)
return
if(holder.marked_datum)
holder.UnregisterSignal(holder.marked_datum, COMSIG_PARENT_QDELETING)
vv_update_display(holder.marked_datum, "marked", "")
holder.marked_datum = D
holder.RegisterSignal(holder.marked_datum, COMSIG_PARENT_QDELETING, /datum/admins/proc/handle_marked_del)
vv_update_display(D, "marked", VV_MSG_MARKED)
/datum/admins/proc/handle_marked_del(datum/source)
UnregisterSignal(marked_datum, COMSIG_PARENT_QDELETING)
marked_datum = null

View File

@@ -0,0 +1,114 @@
//DO NOT ADD MORE TO THIS FILE.
//Use vv_do_topic() for datums!
/client/proc/view_var_Topic(href, href_list, hsrc)
if( (usr.client != src) || !src.holder || !holder.CheckAdminHref(href, href_list))
return
var/target = GET_VV_TARGET
vv_do_basic(target, href_list, href)
if(istype(target, /datum))
var/datum/D = target
D.vv_do_topic(href_list)
else if(islist(target))
vv_do_list(target, href_list)
if(href_list["Vars"])
debug_variables(locate(href_list["Vars"]))
//Stuff below aren't in dropdowns/etc.
//~CARN: for renaming mobs (updates their name, real_name, mind.name, their ID/PDA and datacore records).
if(href_list["rename"])
if(!check_rights(R_ADMIN))
return
var/mob/M = locate(href_list["rename"]) in GLOB.mob_list
if(!istype(M))
to_chat(usr, "This can only be used on instances of type /mob", confidential = TRUE)
return
var/new_name = stripped_input(usr,"What would you like to name this mob?","Input a name",M.real_name,MAX_NAME_LEN)
if( !new_name || !M )
return
message_admins("Admin [key_name_admin(usr)] renamed [key_name_admin(M)] to [new_name].")
M.fully_replace_character_name(M.real_name,new_name)
vv_update_display(M, "name", new_name)
vv_update_display(M, "real_name", M.real_name || "No real name")
else if(check_rights(R_VAREDIT))
if(href_list["rotatedatum"])
if(!check_rights(NONE))
return
var/atom/A = locate(href_list["rotatedatum"])
if(!istype(A))
to_chat(usr, "This can only be done to instances of type /atom", confidential = TRUE)
return
switch(href_list["rotatedir"])
if("right")
A.setDir(turn(A.dir, -45))
if("left")
A.setDir(turn(A.dir, 45))
vv_update_display(A, "dir", dir2text(A.dir))
else if(href_list["adjustDamage"] && href_list["mobToDamage"])
if(!check_rights(NONE))
return
var/mob/living/L = locate(href_list["mobToDamage"]) in GLOB.mob_list
if(!istype(L))
return
var/Text = href_list["adjustDamage"]
var/amount = input("Deal how much damage to mob? (Negative values here heal)","Adjust [Text]loss",0) as num|null
if (isnull(amount))
return
if(!L)
to_chat(usr, "Mob doesn't exist anymore", confidential = TRUE)
return
var/newamt
switch(Text)
if("brute")
L.adjustBruteLoss(amount)
newamt = L.getBruteLoss()
if("fire")
L.adjustFireLoss(amount)
newamt = L.getFireLoss()
if("toxin")
L.adjustToxLoss(amount)
newamt = L.getToxLoss()
if("oxygen")
L.adjustOxyLoss(amount)
newamt = L.getOxyLoss()
if("brain")
L.adjustOrganLoss(ORGAN_SLOT_BRAIN, amount)
newamt = L.getOrganLoss(ORGAN_SLOT_BRAIN)
if("clone")
L.adjustCloneLoss(amount)
newamt = L.getCloneLoss()
if("stamina")
L.adjustStaminaLoss(amount)
newamt = L.getStaminaLoss()
else
to_chat(usr, "You caused an error. DEBUG: Text:[Text] Mob:[L]", confidential = TRUE)
return
if(amount != 0)
var/log_msg = "[key_name(usr)] dealt [amount] amount of [Text] damage to [key_name(L)]"
message_admins("[key_name(usr)] dealt [amount] amount of [Text] damage to [ADMIN_LOOKUPFLW(L)]")
log_admin(log_msg)
admin_ticket_log(L, "<font color='blue'>[log_msg]</font>")
vv_update_display(L, Text, "[newamt]")
//Finally, refresh if something modified the list.
if(href_list["datumrefresh"])
var/datum/DAT = locate(href_list["datumrefresh"])
if(istype(DAT, /datum) || istype(DAT, /client) || islist(DAT))
debug_variables(DAT)

View File

@@ -0,0 +1,54 @@
//Not using datum.vv_do_topic for very basic/low level debug things, incase the datum's vv_do_topic is runtiming/whatnot.
/client/proc/vv_do_basic(datum/target, href_list)
var/target_var = GET_VV_VAR_TARGET
if(check_rights(R_VAREDIT))
if(target_var)
if(href_list[VV_HK_BASIC_EDIT])
if(!modify_variables(target, target_var, 1))
return
switch(target_var)
if("name")
vv_update_display(target, "name", "[target]")
if("dir")
var/atom/A = target
if(istype(A))
vv_update_display(target, "dir", dir2text(A.dir) || A.dir)
if("ckey")
var/mob/living/L = target
if(istype(L))
vv_update_display(target, "ckey", L.ckey || "No ckey")
if("real_name")
var/mob/living/L = target
if(istype(L))
vv_update_display(target, "real_name", L.real_name || "No real name")
if(href_list[VV_HK_BASIC_CHANGE])
modify_variables(target, target_var, 0)
if(href_list[VV_HK_BASIC_MASSEDIT])
cmd_mass_modify_object_variables(target, target_var)
if(check_rights(R_ADMIN, FALSE))
if(href_list[VV_HK_EXPOSE])
var/value = vv_get_value(VV_CLIENT)
if (value["class"] != VV_CLIENT)
return
var/client/C = value["value"]
if (!C)
return
if(!target)
to_chat(usr, span_warning("The object you tried to expose to [C] no longer exists (nulled or hard-deled)"), confidential = TRUE)
return
message_admins("[key_name_admin(usr)] Showed [key_name_admin(C)] a <a href='?_src_=vars;datumrefresh=[REF(target)]'>VV window</a>")
log_admin("Admin [key_name(usr)] Showed [key_name(C)] a VV window of a [target]")
to_chat(C, "[holder.fakekey ? "an Administrator" : "[usr.client.key]"] has granted you access to view a View Variables window", confidential = TRUE)
C.debug_variables(target)
if(check_rights(R_DEBUG))
if(href_list[VV_HK_DELETE])
usr.client.admin_delete(target)
if (isturf(target)) // show the turf that took its place
usr.client.debug_variables(target)
return
if(href_list[VV_HK_MARK])
usr.client.mark_datum(target)
if(href_list[VV_HK_CALLPROC])
usr.client.callproc_datum(target)

View File

@@ -0,0 +1,43 @@
//LISTS - CAN NOT DO VV_DO_TOPIC BECAUSE LISTS AREN'T DATUMS :(
/client/proc/vv_do_list(list/target, href_list)
var/target_index = text2num(GET_VV_VAR_TARGET)
if(check_rights(R_VAREDIT))
if(target_index)
if(href_list[VV_HK_LIST_EDIT])
mod_list(target, null, "list", "contents", target_index, autodetect_class = TRUE)
if(href_list[VV_HK_LIST_CHANGE])
mod_list(target, null, "list", "contents", target_index, autodetect_class = FALSE)
if(href_list[VV_HK_LIST_REMOVE])
var/variable = target[target_index]
var/prompt = alert(usr,"Do you want to remove item number [target_index] from list?", "Confirm", list("Yes", "No"))
if (prompt != "Yes")
return
target.Cut(target_index, target_index+1)
log_world("### ListVarEdit by [src]: /list's contents: REMOVED=[html_encode("[variable]")]")
log_admin("[key_name(src)] modified list's contents: REMOVED=[variable]")
message_admins("[key_name_admin(src)] modified list's contents: REMOVED=[variable]")
if(href_list[VV_HK_LIST_ADD])
mod_list_add(target, null, "list", "contents")
if(href_list[VV_HK_LIST_ERASE_DUPES])
uniqueList_inplace(target)
log_world("### ListVarEdit by [src]: /list contents: CLEAR DUPES")
log_admin("[key_name(src)] modified list's contents: CLEAR DUPES")
message_admins("[key_name_admin(src)] modified list's contents: CLEAR DUPES")
if(href_list[VV_HK_LIST_ERASE_NULLS])
listclearnulls(target)
log_world("### ListVarEdit by [src]: /list contents: CLEAR NULLS")
log_admin("[key_name(src)] modified list's contents: CLEAR NULLS")
message_admins("[key_name_admin(src)] modified list's contents: CLEAR NULLS")
if(href_list[VV_HK_LIST_SET_LENGTH])
var/value = vv_get_value(VV_NUM)
if (value["class"] != VV_NUM || value["value"] > max(50000, target.len)) //safety - would rather someone not put an extra 0 and erase the server's memory lmao.
return
target.len = value["value"]
log_world("### ListVarEdit by [src]: /list len: [target.len]")
log_admin("[key_name(src)] modified list's len: [target.len]")
message_admins("[key_name_admin(src)] modified list's len: [target.len]")
if(href_list[VV_HK_LIST_SHUFFLE])
shuffle_inplace(target)
log_world("### ListVarEdit by [src]: /list contents: SHUFFLE")
log_admin("[key_name(src)] modified list's contents: SHUFFLE")
message_admins("[key_name_admin(src)] modified list's contents: SHUFFLE")

View File

@@ -0,0 +1,375 @@
/client/proc/debug_variables(datum/D in world)
set category = "Misc.Server Debug"
set name = "View Variables"
//set src in world
var/static/cookieoffset = rand(1, 9999) //to force cookies to reset after the round.
if(!usr.client || !usr.client.holder) //The usr vs src abuse in this proc is intentional and must not be changed
to_chat(usr, span_danger("You need to be an administrator to access this."), confidential = TRUE)
return
if(!D)
return
var/islist = islist(D)
var/isappearance = isappearance(D)
if (!islist && !istype(D) && !isappearance)
return
var/title = ""
var/refid = REF(D)
var/icon/sprite
var/hash
var/type = /list
if (isappearance)
type = /image
else if (!islist)
type = D.type
if(istype(D, /atom) || isappearance)
var/atom/AT = D
if(AT.icon && AT.icon_state)
sprite = new /icon(AT.icon, AT.icon_state)
hash = md5(AT.icon)
hash = md5(hash + AT.icon_state)
src << browse_rsc(sprite, "vv[hash].png")
title = "[D] ([REF(D)]) = [type]"
var/formatted_type = replacetext("[type]", "/", "<wbr>/")
var/sprite_text
if(sprite)
sprite_text = "<img src='vv[hash].png'></td><td>"
var/list/header = islist(D)? list("<b>/list</b>") : D.vv_get_header()
var/marked_line
if(holder && holder.marked_datum && holder.marked_datum == D)
marked_line = VV_MSG_MARKED
var/varedited_line
if(!isappearance && !islist && (D.datum_flags & DF_VAR_EDITED))
varedited_line = VV_MSG_EDITED
var/deleted_line
if(!isappearance && !islist && D.gc_destroyed)
deleted_line = VV_MSG_DELETED
var/list/dropdownoptions = list()
if (islist)
dropdownoptions = list(
"---",
"Add Item" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_ADD),
"Remove Nulls" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_ERASE_NULLS),
"Remove Dupes" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_ERASE_DUPES),
"Set len" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_SET_LENGTH),
"Shuffle" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_SHUFFLE),
"Show VV To Player" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_EXPOSE),
"---"
)
for(var/i in 1 to length(dropdownoptions))
var/name = dropdownoptions[i]
var/link = dropdownoptions[name]
dropdownoptions[i] = "<option value[link? "='[link]'":""]>[name]</option>"
else if (!isappearance)
dropdownoptions = D.vv_get_dropdown()
var/list/names = list()
if (!islist && !isappearance)
for (var/V in D.vars)
names += V
sleep(1)//For some reason, without this sleep, VVing will cause client to disconnect on certain objects.
var/list/variable_html = list()
if (islist)
var/list/L = D
for (var/i in 1 to L.len)
var/key = L[i]
var/value
if (IS_NORMAL_LIST(L) && !isnum(key))
value = L[key]
variable_html += debug_variable(i, value, 0, D)
else if(isappearance(D))
variable_html += debug_variable("type", D:type, 0, D)
variable_html += debug_variable("name", D:name, 0, D)
variable_html += debug_variable("desc", D:desc, 0, D)
variable_html += debug_variable("suffix", D:suffix, 0, D)
variable_html += debug_variable("text", D:text, 0, D)
variable_html += debug_variable("icon", D:icon, 0, D)
variable_html += debug_variable("icon_state", D:icon_state, 0, D)
variable_html += debug_variable("visibility", D:visibility, 0, D)
variable_html += debug_variable("luminosity", D:luminosity, 0, D)
variable_html += debug_variable("opacity", D:opacity, 0, D)
variable_html += debug_variable("density", D:density, 0, D)
variable_html += debug_variable("verbs", D:verbs, 0, D)
variable_html += debug_variable("dir", D:dir, 0, D)
variable_html += debug_variable("gender", D:gender, 0, D)
variable_html += debug_variable("tag", D:tag, 0, D)
variable_html += debug_variable("overlays", D:overlays, 0, D)
variable_html += debug_variable("underlays", D:underlays, 0, D)
variable_html += debug_variable("layer", D:layer, 0, D)
variable_html += debug_variable("parent_type", D:parent_type, 0, D)
variable_html += debug_variable("mouse_over_pointer", D:mouse_over_pointer, 0, D)
variable_html += debug_variable("mouse_drag_pointer", D:mouse_drag_pointer, 0, D)
variable_html += debug_variable("mouse_drop_pointer", D:mouse_drop_pointer, 0, D)
variable_html += debug_variable("mouse_drop_zone", D:mouse_drop_zone, 0, D)
variable_html += debug_variable("animate_movement", D:animate_movement, 0, D)
variable_html += debug_variable("screen_loc", D:screen_loc, 0, D)
variable_html += debug_variable("infra_luminosity", D:infra_luminosity, 0, D)
variable_html += debug_variable("invisibility", D:invisibility, 0, D)
variable_html += debug_variable("mouse_opacity", D:mouse_opacity, 0, D)
variable_html += debug_variable("pixel_x", D:pixel_x, 0, D)
variable_html += debug_variable("pixel_y", D:pixel_y, 0, D)
variable_html += debug_variable("pixel_step_size", D:pixel_step_size, 0, D)
variable_html += debug_variable("pixel_z", D:pixel_z, 0, D)
variable_html += debug_variable("override", D:override, 0, D)
variable_html += debug_variable("glide_size", D:glide_size, 0, D)
variable_html += debug_variable("maptext", D:maptext, 0, D)
variable_html += debug_variable("maptext_width", D:maptext_width, 0, D)
variable_html += debug_variable("maptext_height", D:maptext_height, 0, D)
variable_html += debug_variable("transform", D:transform, 0, D)
variable_html += debug_variable("alpha", D:alpha, 0, D)
variable_html += debug_variable("color", D:color, 0, D)
variable_html += debug_variable("blend_mode", D:blend_mode, 0, D)
variable_html += debug_variable("appearance", D:appearance, 0, D)
variable_html += debug_variable("maptext_x", D:maptext_x, 0, D)
variable_html += debug_variable("maptext_y", D:maptext_y, 0, D)
variable_html += debug_variable("plane", D:plane, 0, D)
variable_html += debug_variable("appearance_flags", D:appearance_flags, 0, D)
variable_html += debug_variable("pixel_w", D:pixel_w, 0, D)
variable_html += debug_variable("render_source", D:render_source, 0, D)
variable_html += debug_variable("render_target", D:render_target, 0, D)
else
names = sortList(names)
for (var/V in names)
if(D.can_vv_get(V))
variable_html += D.vv_get_var(V)
var/html = {"
<html>
<head>
<meta charset='UTF-8'>
<title>[title]</title>
<link rel="stylesheet" type="text/css" href="view_variables.css">
</head>
<body onload='selectTextField()' onkeydown='return handle_keydown()' onkeyup='handle_keyup()'>
<script type="text/javascript">
// onload
function selectTextField() {
var filter_text = document.getElementById('filter');
filter_text.focus();
filter_text.select();
var lastsearch = getCookie("[refid][cookieoffset]search");
if (lastsearch) {
filter_text.value = lastsearch;
updateSearch();
}
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++) {
var c = ca\[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(name)==0) return c.substring(name.length,c.length);
}
return "";
}
// main search functionality
var last_filter = "";
function updateSearch() {
var filter = document.getElementById('filter').value.toLowerCase();
var vars_ol = document.getElementById("vars");
if (filter === last_filter) {
// An event triggered an update but nothing has changed.
return;
} else if (filter.indexOf(last_filter) === 0) {
// The new filter starts with the old filter, fast path by removing only.
var children = vars_ol.childNodes;
for (var i = children.length - 1; i >= 0; --i) {
try {
var li = children\[i];
if (li.innerText.toLowerCase().indexOf(filter) == -1) {
vars_ol.removeChild(li);
}
} catch(err) {}
}
} else {
// Remove everything and put back what matches.
while (vars_ol.hasChildNodes()) {
vars_ol.removeChild(vars_ol.lastChild);
}
for (var i = 0; i < complete_list.length; ++i) {
try {
var li = complete_list\[i];
if (!filter || li.innerText.toLowerCase().indexOf(filter) != -1) {
vars_ol.appendChild(li);
}
} catch(err) {}
}
}
last_filter = filter;
document.cookie="[refid][cookieoffset]search="+encodeURIComponent(filter);
var lis_new = vars_ol.getElementsByTagName("li");
for (var j = 0; j < lis_new.length; ++j) {
lis_new\[j].style.backgroundColor = (j == 0) ? "#ffee88" : "white";
}
}
// onkeydown
function handle_keydown() {
if(event.keyCode == 116) { //F5 (to refresh properly)
document.getElementById("refresh_link").click();
event.preventDefault ? event.preventDefault() : (event.returnValue = false);
return false;
}
return true;
}
// onkeyup
function handle_keyup() {
if (event.keyCode == 13) { //Enter / return
var vars_ol = document.getElementById('vars');
var lis = vars_ol.getElementsByTagName("li");
for (var i = 0; i < lis.length; ++i) {
try {
var li = lis\[i];
if (li.style.backgroundColor == "#ffee88") {
alist = lis\[i].getElementsByTagName("a");
if(alist.length > 0) {
location.href=alist\[0].href;
}
}
} catch(err) {}
}
} else if(event.keyCode == 38){ //Up arrow
var vars_ol = document.getElementById('vars');
var lis = vars_ol.getElementsByTagName("li");
for (var i = 0; i < lis.length; ++i) {
try {
var li = lis\[i];
if (li.style.backgroundColor == "#ffee88") {
if (i > 0) {
var li_new = lis\[i-1];
li.style.backgroundColor = "white";
li_new.style.backgroundColor = "#ffee88";
return
}
}
} catch(err) {}
}
} else if(event.keyCode == 40) { //Down arrow
var vars_ol = document.getElementById('vars');
var lis = vars_ol.getElementsByTagName("li");
for (var i = 0; i < lis.length; ++i) {
try {
var li = lis\[i];
if (li.style.backgroundColor == "#ffee88") {
if ((i+1) < lis.length) {
var li_new = lis\[i+1];
li.style.backgroundColor = "white";
li_new.style.backgroundColor = "#ffee88";
return
}
}
} catch(err) {}
}
} else {
updateSearch();
}
}
// onchange
function handle_dropdown(list) {
var value = list.options\[list.selectedIndex].value;
if (value !== "") {
location.href = value;
}
list.selectedIndex = 0;
document.getElementById('filter').focus();
}
// byjax
function replace_span(what) {
var idx = what.indexOf(':');
document.getElementById(what.substr(0, idx)).innerHTML = what.substr(idx + 1);
}
</script>
<div align='center'>
<table width='100%'>
<tr>
<td width='50%'>
<table align='center' width='100%'>
<tr>
<td>
[sprite_text]
<div align='center'>
[header.Join()]
</div>
</td>
</tr>
</table>
<div align='center'>
<b><font size='1'>[formatted_type]</font></b>
<span id='marked'>[marked_line]</span>
<span id='varedited'>[varedited_line]</span>
<span id='deleted'>[deleted_line]</span>
</div>
</td>
<td width='50%'>
<div align='center'>
<a id='refresh_link' href='?_src_=vars;[HrefToken()];datumrefresh=[refid]'>Refresh</a>
<form>
<select name="file" size="1"
onchange="handle_dropdown(this)"
onmouseclick="this.focus()"
style="background-color:#ffffff">
<option value selected>Select option</option>
[dropdownoptions.Join()]
</select>
</form>
</div>
</td>
</tr>
</table>
</div>
<hr>
<font size='1'>
<b>E</b> - Edit, tries to determine the variable type by itself.<br>
<b>C</b> - Change, asks you for the var type first.<br>
<b>M</b> - Mass modify: changes this variable for all objects of this type.<br>
</font>
<hr>
<table width='100%'>
<tr>
<td width='20%'>
<div align='center'>
<b>Search:</b>
</div>
</td>
<td width='80%'>
<input type='text' id='filter' name='filter_text' value='' style='width:100%;'>
</td>
</tr>
</table>
<hr>
<ol id='vars'>
[variable_html.Join()]
</ol>
<script type='text/javascript'>
var complete_list = \[\];
var lis = document.getElementById("vars").children;
for(var i = lis.length; i--;) complete_list\[i\] = lis\[i\];
</script>
</body>
</html>
"}
src << browse(html, "window=variables[refid];size=475x650")
/client/proc/vv_update_display(datum/D, span, content)
src << output("[span]:[content]", "variables[REF(D)].browser:replace_span")

View File

@@ -15,8 +15,11 @@
maxbodytemp = 360
unique_name = 1
a_intent = INTENT_HARM
see_in_dark = 8
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
var/mob/camera/blob/overmind = null
var/obj/structure/blob/factory/factory = null
var/independent = FALSE
/mob/living/simple_animal/hostile/blob/update_icons()
if(overmind)
@@ -24,6 +27,13 @@
else
remove_atom_colour(FIXED_COLOUR_PRIORITY)
/mob/living/simple_animal/hostile/blob/Initialize()
. = ..()
if(!independent) //no pulling people deep into the blob
verbs -= /mob/living/verb/pulled
else
pass_flags &= ~PASSBLOB
/mob/living/simple_animal/hostile/blob/Destroy()
if(overmind)
@@ -90,18 +100,20 @@
attacktext = "hits"
attack_sound = 'sound/weapons/genhit1.ogg'
movement_type = FLYING
del_on_death = 1
del_on_death = TRUE
deathmessage = "explodes into a cloud of gas!"
gold_core_spawnable = HOSTILE_SPAWN
var/death_cloud_size = 1 //size of cloud produced from a dying spore
var/mob/living/carbon/human/oldguy
var/is_zombie = 0
gold_core_spawnable = HOSTILE_SPAWN
var/is_zombie = FALSE
/mob/living/simple_animal/hostile/blob/blobspore/Initialize(mapload, var/obj/structure/blob/factory/linked_node)
if(istype(linked_node))
factory = linked_node
factory.spores += src
. = ..()
if(linked_node.overmind && istype(linked_node.overmind.blobstrain, /datum/blobstrain/reagent/distributed_neurons) && !istype(src, /mob/living/simple_animal/hostile/blob/blobspore/weak))
notify_ghosts("A controllable spore has been created in \the [get_area(src)].", source = src, action = NOTIFY_ORBIT, flashwindow = FALSE, header = "Sentient Spore Created")
/mob/living/simple_animal/hostile/blob/blobspore/Life()
if(!is_zombie && isturf(src.loc))
@@ -113,6 +125,26 @@
death()
..()
/mob/living/simple_animal/hostile/blob/blobspore/attack_ghost(mob/user)
. = ..()
if(.)
return
humanize_pod(user)
/mob/living/simple_animal/hostile/blob/blobspore/proc/humanize_pod(mob/user)
if((!overmind || istype(src, /mob/living/simple_animal/hostile/blob/blobspore/weak) || !istype(overmind.blobstrain, /datum/blobstrain/reagent/distributed_neurons)) && !is_zombie)
return
if(key || stat)
return
var/pod_ask = alert("Become a blob spore?", "Are you bulbous enough?", "Yes", "No")
if(pod_ask == "No" || !src || QDELETED(src))
return
if(key)
to_chat(user, "<span class='warning'>Someone else already took this spore!</span>")
return
key = user.key
log_game("[key_name(src)] took control of [name].")
/mob/living/simple_animal/hostile/blob/blobspore/proc/Zombify(mob/living/carbon/human/H)
is_zombie = 1
if(H.wear_suit)
@@ -135,6 +167,8 @@
oldguy = H
update_icons()
visible_message(span_warning("The corpse of [H.name] suddenly rises!"))
if(!key)
notify_ghosts("\A [src] has been created in \the [get_area(src)].", source = src, action = NOTIFY_ORBIT, flashwindow = FALSE, header = "Blob Zombie Created")
/mob/living/simple_animal/hostile/blob/blobspore/death(gibbed)
// On death, create a small smoke of harmful gas (s-Acid)
@@ -215,17 +249,7 @@
force_threshold = 10
pressure_resistance = 50
mob_size = MOB_SIZE_LARGE
see_in_dark = 8
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
hud_type = /datum/hud/blobbernaut
var/independent = FALSE
/mob/living/simple_animal/hostile/blob/blobbernaut/Initialize()
. = ..()
if(!independent) //no pulling people deep into the blob
remove_verb(src, /mob/living/verb/pulled)
else
pass_flags &= ~PASSBLOB
/mob/living/simple_animal/hostile/blob/blobbernaut/Life()
if(..())

View File

@@ -0,0 +1,38 @@
/datum/blobstrain/reagent/distributed_neurons
name = "Distributed Neurons"
description = "will do very low toxin damage and turns unconscious targets into blob zombies."
effectdesc = "will also produce fragile spores when killed. Spores produced by factories are sentient."
shortdesc = "will do very low toxin damage and will turn unconscious targets into blob zombies for additional resources(for your overmind). Spores produced by factories are sentient."
analyzerdescdamage = "Does very low toxin damage and kills unconscious humans, turning them into blob zombies."
analyzerdesceffect = "Produces spores when killed. Spores produced by factories are sentient."
color = "#E88D5D"
complementary_color = "#823ABB"
message_living = ", and you feel tired"
reagent = /datum/reagent/blob/distributed_neurons
/datum/blobstrain/reagent/distributed_neurons/damage_reaction(obj/structure/blob/B, damage, damage_type, damage_flag)
if((damage_flag == "melee" || damage_flag == "bullet" || damage_flag == "laser") && damage <= 20 && B.obj_integrity - damage <= 0 && prob(15)) //if the cause isn't fire or a bomb, the damage is less than 21, we're going to die from that damage, 15% chance of a shitty spore.
B.visible_message("<span class='warning'><b>A spore floats free of the blob!</b></span>")
var/mob/living/simple_animal/hostile/blob/blobspore/weak/BS = new/mob/living/simple_animal/hostile/blob/blobspore/weak(B.loc)
BS.overmind = B.overmind
BS.update_icons()
B.overmind.blob_mobs.Add(BS)
return ..()
/datum/reagent/blob/distributed_neurons
name = "Distributed Neurons"
color = "#E88D5D"
/datum/reagent/blob/distributed_neurons/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
reac_volume = ..()
M.apply_damage(0.6*reac_volume, TOX)
if(O && ishuman(M) && M.stat == UNCONSCIOUS)
M.death() //sleeping in a fight? bad plan.
var/points = rand(5, 10)
var/mob/living/simple_animal/hostile/blob/blobspore/BS = new/mob/living/simple_animal/hostile/blob/blobspore/weak(get_turf(M))
BS.overmind = O
BS.update_icons()
O.blob_mobs.Add(BS)
BS.Zombify(M)
O.add_points(points)
to_chat(O, "<span class='notice'>Gained [points] resources from the zombification of [M].</span>")

View File

@@ -1,7 +1,7 @@
//does massive brute and burn damage, but can only expand manually
/datum/blobstrain/reagent/networked_fibers
name = "Networked Fibers"
description = "will do high brute and burn damage and will generate resources quicker, but can only expand manually."
description = "will do high brute and burn damage and will generate resources quicker, but can only expand manually using the core."
shortdesc = "will do high brute and burn damage."
effectdesc = "will move your core when manually expanding near it."
analyzerdescdamage = "Does high brute and burn damage."
@@ -9,6 +9,9 @@
color = "#CDC0B0"
complementary_color = "#FFF68F"
reagent = /datum/reagent/blob/networked_fibers
core_regen = 5
point_rate = 3
/datum/blobstrain/reagent/networked_fibers/expand_reaction(obj/structure/blob/B, obj/structure/blob/newB, turf/T, mob/camera/blob/O)
if(!O && newB.overmind)
@@ -24,6 +27,9 @@
C.forceMove(T)
C.setDir(get_dir(newB, C))
O.add_points(1)
return
O.add_points(4)
qdel(newB)
//does massive brute and burn damage, but can only expand manually
/datum/reagent/blob/networked_fibers

View File

@@ -1,46 +0,0 @@
//kills sleeping targets and turns them into blob zombies, produces fragile spores when killed or on expanding
/datum/blobstrain/reagent/zombifying_pods
name = "Zombifying Pods"
description = "will do very low toxin damage and harvest sleeping targets for additional resources and a blob zombie."
effectdesc = "will also produce fragile spores when killed and on expanding."
shortdesc = "will do very low toxin damage and harvest sleeping targets for additional resources(for your overmind) and a blob zombie."
analyzerdescdamage = "Does very low toxin damage and kills unconscious humans, turning them into blob zombies."
analyzerdesceffect = "Produces spores when expanding and when killed."
color = "#E88D5D"
complementary_color = "#823ABB"
message_living = ", and you feel tired"
reagent = /datum/reagent/blob/zombifying_pods
/datum/blobstrain/reagent/zombifying_pods/damage_reaction(obj/structure/blob/B, damage, damage_type, damage_flag)
if((damage_flag == "melee" || damage_flag == "bullet" || damage_flag == "laser") && damage <= 20 && B.obj_integrity - damage <= 0 && prob(30)) //if the cause isn't fire or a bomb, the damage is less than 21, we're going to die from that damage, 20% chance of a shitty spore.
B.visible_message(span_warning("<b>A spore floats free of the blob!</b>"))
var/mob/living/simple_animal/hostile/blob/blobspore/weak/BS = new/mob/living/simple_animal/hostile/blob/blobspore/weak(B.loc)
BS.overmind = B.overmind
BS.update_icons()
B.overmind.blob_mobs.Add(BS)
return ..()
/datum/blobstrain/reagent/zombifying_pods/expand_reaction(obj/structure/blob/B, obj/structure/blob/newB, turf/T, mob/camera/blob/O)
if(prob(10))
var/mob/living/simple_animal/hostile/blob/blobspore/weak/BS = new/mob/living/simple_animal/hostile/blob/blobspore/weak(T)
BS.overmind = B.overmind
BS.update_icons()
newB.overmind.blob_mobs.Add(BS)
/datum/reagent/blob/zombifying_pods
name = "Zombifying Pods"
color = "#E88D5D"
/datum/reagent/blob/zombifying_pods/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
reac_volume = ..()
M.apply_damage(0.6*reac_volume, TOX)
if(O && ishuman(M) && M.stat == UNCONSCIOUS)
M.death() //sleeping in a fight? bad plan.
var/points = rand(5, 10)
var/mob/living/simple_animal/hostile/blob/blobspore/BS = new/mob/living/simple_animal/hostile/blob/blobspore/weak(get_turf(M))
BS.overmind = O
BS.update_icons()
O.blob_mobs.Add(BS)
BS.Zombify(M)
O.add_points(points)
to_chat(O, span_notice("Gained [points] resources from the zombification of [M]."))

View File

@@ -39,6 +39,9 @@ GLOBAL_LIST_EMPTY(blob_nodes)
var/blobwincount = 400
var/victory_in_progress = FALSE
var/rerolling = FALSE
var/announcement_size = 75
var/announcement_time
var/has_announced = FALSE
/mob/camera/blob/Initialize(mapload, starting_points = 60)
validate_location()
@@ -56,6 +59,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
if(blob_core)
blob_core.update_icon()
SSshuttle.registerHostileEnvironment(src)
announcement_time = world.time + 6000
. = ..()
START_PROCESSING(SSobj, src)
@@ -109,7 +113,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
priority_announce("Biohazard has reached critical mass. Station loss is imminent.", "Biohazard Alert")
set_security_level("delta")
max_blob_points = INFINITY
blob_points = INFINITY
blob_points = INFINITY
addtimer(CALLBACK(src, .proc/victory), 450)
else if(!free_strain_rerolls && (last_reroll_time + BLOB_REROLL_TIME<world.time))
to_chat(src, "<b><span class='big'><font color=\"#EE4000\">You have gained another free strain re-roll.</font></span></b>")
@@ -118,6 +122,10 @@ GLOBAL_LIST_EMPTY(blob_nodes)
if(!victory_in_progress && max_count < blobs_legit.len)
max_count = blobs_legit.len
if((world.time >= announcement_time || blobs_legit.len >= announcement_size) && !has_announced)
priority_announce("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", 'sound/ai/default/outbreak5.ogg')
has_announced = TRUE
/mob/camera/blob/proc/victory()
sound_to_playing_players('sound/machines/alarm.ogg')
sleep(100)

View File

@@ -318,7 +318,7 @@
if(!surrounding_turfs.len)
return
for(var/mob/living/simple_animal/hostile/blob/blobspore/BS in blob_mobs)
if(isturf(BS.loc) && get_dist(BS, T) <= 35)
if(isturf(BS.loc) && get_dist(BS, T) <= 35 && !BS.key)
BS.LoseTarget()
BS.Goto(pick(surrounding_turfs), BS.move_to_delay)

View File

@@ -19,12 +19,8 @@
return INITIALIZE_HINT_QDEL
if(overmind)
update_icon()
addtimer(CALLBACK(src, .proc/generate_announcement), 1800)
. = ..()
/obj/structure/blob/core/proc/generate_announcement()
priority_announce("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", ANNOUNCER_OUTBREAK5)
/obj/structure/blob/core/scannerreport()
return "Directs the blob's expansion, gradually expands, and sustains nearby blob spores and blobbernauts."

View File

@@ -89,6 +89,29 @@
message_admins("[key_name_admin(admin)] made [key_name_admin(new_owner)] and [key_name_admin(bro)] into blood brothers.")
log_admin("[key_name(admin)] made [key_name(new_owner)] and [key_name(bro)] into blood brothers.")
/datum/antagonist/brother/get_admin_commands()
. = ..()
.["Convert To Traitor"] = CALLBACK(src, .proc/make_traitor)
/datum/antagonist/brother/proc/make_traitor()
if(alert("Are you sure? This will turn the blood brother into a traitor with the same objectives!",,"Yes","No") != "Yes")
return
var/datum/antagonist/traitor/tot = new()
tot.give_objectives = FALSE
for(var/datum/objective/obj in objectives)
var/obj_type = obj.type
var/datum/objective/new_obj = new obj_type()
new_obj.owner = owner
new_obj.copy_target(obj)
tot.add_objective(new_obj)
qdel(obj)
objectives.Cut()
owner.add_antag_datum(tot)
owner.remove_antag_datum(/datum/antagonist/brother)
/datum/antagonist/brother/proc/give_pinpointer()
if(owner && owner.current)
var/datum/status_effect/agent_pinpointer/brother/P = owner.current.apply_status_effect(/datum/status_effect/agent_pinpointer/brother)

View File

@@ -6,6 +6,7 @@ is currently following.
GLOBAL_LIST_INIT(disease_ability_singletons, list(
new /datum/disease_ability/action/cough,
new /datum/disease_ability/symptom/mild/sentient,
new /datum/disease_ability/action/sneeze,
new /datum/disease_ability/action/infect,
new /datum/disease_ability/symptom/mild/cough,
@@ -267,6 +268,7 @@ new /datum/disease_ability/symptom/powerful/heal/youth
StartCooldown()
return TRUE
/*******************BASE SYMPTOM TYPES*******************/
// cost is for convenience and can be changed. If you're changing req_tot_points then don't use the subtype...
//healing costs more so you have to techswitch from naughty disease otherwise we'd have friendly disease for easy greentext (no fun!)
@@ -296,6 +298,29 @@ new /datum/disease_ability/symptom/powerful/heal/youth
/******MILD******/
/datum/disease_ability/symptom/mild/sentient
cost = 0
required_total_points = 0
name = "Sentient Resistance"
start_with = TRUE
symptoms = list(/datum/symptom/sentient)
short_desc = "Due to its sentience, the virus is able to passively increase its resistance to detection and cures"
long_desc = "Due to its sentience, the virus is able to passively increase its resistance to detection and cures"
/datum/symptom/sentient
name = "Sentient Resistance"
desc = "Due to its sentience, the virus is able to passively increase its resistance to detection and cures"
stealth = 2
resistance = 2
stage_speed = 0
transmittable = 0
level = 0
severity = 0
symptom_delay_min = 2
symptom_delay_max = 15
var/infective = FALSE
threshold_descs = list()
/datum/disease_ability/symptom/mild/cough
name = "Involuntary Coughing"

View File

@@ -840,6 +840,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<h2>Donator Preferences</h2>"
if(is_donator(user.client))
dat += "<b>Quiet round:</b> <a href='?_src_=prefs;preference=donor;task=quiet_round'>[(src.yogtoggles & QUIET_ROUND) ? "Yes" : "No"]</a><br>"
dat += "Wear fancy hat as borg: "
dat += "<a href='?_src_=prefs;preference=donor;task=borghat'>[borg_hat ? "Yes" : "No"]</a><br>"
dat += "<b>Fancy Hat:</b> "
///This is the typepath of the donor's hat that they may choose to spawn with.
var/typehat = donor_hat
@@ -1241,6 +1243,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(is_donator(user))
var/client/C = (istype(user, /client)) ? user : user.client
switch(href_list["task"])
if("borghat")
borg_hat = !borg_hat
if("hat")
C.custom_donator_item()
if("item")

View File

@@ -223,6 +223,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
// yogs start - Donor features
READ_FILE(S["donor_pda"], donor_pda)
READ_FILE(S["donor_hat"], donor_hat)
READ_FILE(S["borg_hat"], borg_hat)
READ_FILE(S["donor_item"], donor_item)
READ_FILE(S["purrbation"], purrbation)
READ_FILE(S["yogtoggles"], yogtoggles)
@@ -358,6 +359,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["yogtoggles"], yogtoggles)
WRITE_FILE(S["donor_pda"], donor_pda)
WRITE_FILE(S["donor_hat"], donor_hat)
WRITE_FILE(S["borg_hat"], borg_hat)
WRITE_FILE(S["donor_item"], donor_item)
WRITE_FILE(S["purrbation"], purrbation)

View File

@@ -1,13 +1,13 @@
/obj/item/reactive_armour_shell
name = "reactive armour shell"
desc = "An experimental suit of armour, awaiting installation of an anomaly core."
/obj/item/reactive_armor_shell
name = "reactive armor shell"
desc = "An experimental suit of armor, awaiting installation of an anomaly core."
icon_state = "reactiveoff"
icon = 'icons/obj/clothing/suits.dmi'
w_class = WEIGHT_CLASS_BULKY
/obj/item/reactive_armour_shell/attackby(obj/item/I, mob/user, params)
/obj/item/reactive_armor_shell/attackby(obj/item/I, mob/user, params)
..()
var/static/list/anomaly_armour_types = list(
var/static/list/anomaly_armor_types = list(
/obj/effect/anomaly/grav = /obj/item/clothing/suit/armor/reactive/repulse,
/obj/effect/anomaly/flux = /obj/item/clothing/suit/armor/reactive/tesla,
/obj/effect/anomaly/bluespace = /obj/item/clothing/suit/armor/reactive/teleport
@@ -15,11 +15,11 @@
if(istype(I, /obj/item/assembly/signaler/anomaly))
var/obj/item/assembly/signaler/anomaly/A = I
var/armour_path = anomaly_armour_types[A.anomaly_type]
if(!armour_path)
armour_path = /obj/item/clothing/suit/armor/reactive/stealth //Lets not cheat the player if an anomaly type doesnt have its own armour coded
to_chat(user, "You insert [A] into the chest plate, and the armour gently hums to life.")
new armour_path(get_turf(src))
var/armor_path = anomaly_armor_types[A.anomaly_type]
if(!armor_path)
armor_path = /obj/item/clothing/suit/armor/reactive/stealth //Lets not cheat the player if an anomaly type doesnt have its own armor coded
to_chat(user, "You insert [A] into the chest plate, and the armor gently hums to life.")
new armor_path(get_turf(src))
qdel(src)
qdel(A)

View File

@@ -1,4 +1,4 @@
#define RANDOM_EVENT_ADMIN_INTERVENTION_TIME 10
#define RANDOM_EVENT_ADMIN_INTERVENTION_TIME (20 SECONDS)
//this singleton datum is used by the events controller to dictate how it selects events
/datum/round_event_control
@@ -82,8 +82,8 @@
triggering = TRUE
if(alert_observers)
message_admins("Random Event triggering in [RANDOM_EVENT_ADMIN_INTERVENTION_TIME] seconds: [name] (<a href='?src=[REF(src)];cancel=1'>CANCEL</a>)")
sleep(RANDOM_EVENT_ADMIN_INTERVENTION_TIME SECONDS)
message_admins(span_bold(span_red("Random Event triggering in [RANDOM_EVENT_ADMIN_INTERVENTION_TIME/10] seconds: [name] (<a href='?src=[REF(src)];cancel=1'>CANCEL</a>)")))
sleep(RANDOM_EVENT_ADMIN_INTERVENTION_TIME)
//Yogs end
var/gamemode = SSticker.mode.config_tag
var/players_amt = get_active_player_count(alive_check = TRUE, afk_check = TRUE, human_check = TRUE)

View File

@@ -391,17 +391,14 @@
/datum/spacevine_controller/vv_get_dropdown()
. = ..()
. += "---"
.["Delete Vines"] = "?_src_=[REF(src)];[HrefToken()];purge_vines=1"
VV_DROPDOWN_SEPERATOR
VV_DROPDOWN_OPTION(VV_HK_SPACEVINE_PURGE, "Delete Vines")
/datum/spacevine_controller/Topic(href, href_list)
if(..() || !check_rights(R_ADMIN, FALSE) || !usr.client.holder.CheckAdminHref(href, href_list))
return
if(href_list["purge_vines"])
if(alert(usr, "Are you sure you want to delete this spacevine cluster?", "Delete Vines", "Yes", "No") != "Yes")
return
DeleteVines()
/datum/spacevine_controller/vv_do_topic(href_list)
. = ..()
if(href_list[VV_HK_SPACEVINE_PURGE])
if(alert(usr, "Are you sure you want to delete this spacevine cluster?", "Delete Vines", list("Yes", "No")) == "Yes")
DeleteVines()
/datum/spacevine_controller/proc/DeleteVines() //this is kill
QDEL_LIST(vines) //this will also qdel us

View File

@@ -49,7 +49,7 @@
suit = /obj/item/clothing/suit/armor/vest/capcarapace
shoes = /obj/item/clothing/shoes/sneakers/brown
head = /obj/item/clothing/head/caphat
backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/station_charter=1, /obj/item/gun/energy/e_gun=1) //yogs - adds egun/removes civ budget
backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/station_charter=1, /obj/item/gun/energy/e_gun=1, /obj/item/modular_computer/tablet/phone/preset/advanced/command=1) //yogs - adds egun/removes civ budget
backpack = /obj/item/storage/backpack/captain
satchel = /obj/item/storage/backpack/satchel/cap

View File

@@ -46,7 +46,7 @@
alt_shoes = /obj/item/clothing/shoes/xeno_wraps/command // Provides Command shoes to digitigrade species
head = /obj/item/clothing/head/hardhat/white
gloves = /obj/item/clothing/gloves/color/black/ce
backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/phone/preset/advanced/command=1) //yogs - removes eng budget
backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/phone/preset/advanced/command/atmos=1) //yogs - removes eng budget
glasses = /obj/item/clothing/glasses/meson/sunglasses
backpack = /obj/item/storage/backpack/industrial

View File

@@ -34,3 +34,24 @@
/datum/job/cyborg/radio_help_message(mob/M)
to_chat(M, "<b>Prefix your message with :b to speak with other cyborgs and AI.</b>")
/datum/job/cyborg/give_donor_stuff(mob/living/silicon/robot/H, mob/M)
if(!istype(H))
return
var/client/C = M.client
if(!C)
C = H.client
if(!C)
return // nice
if(!is_donator(C))
return
if(C.prefs.donor_hat && C.prefs.borg_hat)
var/type = C.prefs.donor_hat
if(type)
var/obj/item/hat = new type()
if(istype(hat) && hat.slot_flags & ITEM_SLOT_HEAD && H.hat_offset != INFINITY && !is_type_in_typecache(hat, H.blacklisted_hats))
H.place_on_head(hat)

View File

@@ -53,7 +53,8 @@
r_pocket = /obj/item/lighter
backpack_contents = list(/obj/item/storage/box/evidence=1,\
/obj/item/detective_scanner=1,\
/obj/item/melee/classic_baton=1)
/obj/item/melee/classic_baton=1,\
/obj/item/modular_computer/tablet/pda/preset/basic=1)
mask = /obj/item/clothing/mask/cigarette
implants = list(/obj/item/implant/mindshield)

View File

@@ -1,5 +1,5 @@
//The chests dropped by mob spawner tendrils. Also contains associated loot.
GLOBAL_LIST_EMPTY(bloodmen_list)
#define HIEROPHANT_CLUB_CARDINAL_DAMAGE 30
@@ -1457,3 +1457,56 @@
new /obj/item/wisp_lantern(src)
if(3)
new /obj/item/prisoncube(src)
//Legion
/obj/item/organ/grandcore
name = "grand core"
desc = "The source of the Legion's powers. Though mostly expended, you might be able to get some use out of it."
icon = 'icons/obj/lavaland/artefacts.dmi'
icon_state = "grandcore"
slot = "hivecore"
w_class = WEIGHT_CLASS_SMALL
decay_factor = 0
actions_types = list(/datum/action/item_action/organ_action/threebloodlings)
/obj/item/organ/grandcore/attack(mob/living/carbon/human/H, mob/living/carbon/human/user, obj/target)
if(H == user && istype(H))
playsound(user,'sound/effects/singlebeat.ogg',40,1)
user.temporarilyRemoveItemFromInventory(src, TRUE)
Insert(user)
/obj/item/organ/grandcore/Insert(mob/living/carbon/H, special = 0)
H.faction = list("blooded")
H.AddSpell (new /obj/effect/proc_holder/spell/targeted/touch/raise)
H.AddSpell (new /obj/effect/proc_holder/spell/aoe_turf/horde)
..()
if(NOBLOOD in H.dna.species.species_traits)
to_chat(owner, "<span class ='userdanger'>Despite lacking blood, you were able to take in the grand core. You will pay for your power in killer headaches!</span>")
else
to_chat(owner, "<span class ='userdanger'>You've taken in the grand core, allowing you to control minions at the cost of your blood!</span>")
/obj/item/organ/grandcore/Remove(mob/living/carbon/H, special = 0)
H.RemoveSpell (/obj/effect/proc_holder/spell/targeted/touch/raise, /obj/effect/proc_holder/spell/aoe_turf/horde)
H.RemoveSpell (new /obj/effect/proc_holder/spell/aoe_turf/horde)
return ..()
/datum/action/item_action/organ_action/threebloodlings
name = "Summon bloodlings"
desc = "Summon a conjure a few bloodlings at the cost of 13% blood (8 brain damage for those without blood)."
var/next_expulsion = 0
var/cooldown = 10 //wheres the risk if it has a reasonable cooldown?
/datum/action/item_action/organ_action/threebloodlings/Trigger()
var/mob/living/carbon/H = owner
. = ..()
if(next_expulsion > world.time)
to_chat(owner, span_warning("Don't spill your blood so haphazardly!"))
return
if(NOBLOOD in H.dna.species.species_traits)
H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 8) //brain damage wont stop you from running away so opting for that instead of poison or breath damage
to_chat(H, "<span class ='userdanger'>Your head pounds as you produce bloodlings!</span>")
else
to_chat(H, "<span class ='userdanger'>You spill your blood, and it comes to life as bloodlings!</span>")
H.blood_volume -= 70 //like 13% of your blood taken
spawn_atom_to_turf(/mob/living/simple_animal/hostile/asteroid/hivelordbrood/bloodling, owner, 3, TRUE) //think 1 in 4 is a good chance of not being targeted by fauna
next_expulsion = world.time + cooldown

View File

@@ -522,6 +522,7 @@
return
if(frn)
client.prefs.random_character()
client.prefs.accent = null
client.prefs.real_name = client.prefs.pref_species.random_name(gender,1)
client.prefs.copy_to(H)

View File

@@ -952,14 +952,114 @@
/mob/living/carbon/vv_get_dropdown()
. = ..()
. += "---"
.["Make AI"] = "?_src_=vars;[HrefToken()];makeai=[REF(src)]"
.["Modify bodypart"] = "?_src_=vars;[HrefToken()];editbodypart=[REF(src)]"
.["Modify organs"] = "?_src_=vars;[HrefToken()];editorgans=[REF(src)]"
.["Hallucinate"] = "?_src_=vars;[HrefToken()];hallucinate=[REF(src)]"
.["Give martial arts"] = "?_src_=vars;[HrefToken()];givemartialart=[REF(src)]"
.["Give brain trauma"] = "?_src_=vars;[HrefToken()];givetrauma=[REF(src)]"
.["Cure brain traumas"] = "?_src_=vars;[HrefToken()];curetraumas=[REF(src)]"
VV_DROPDOWN_SEPERATOR
VV_DROPDOWN_OPTION(VV_HK_MODIFY_BODYPART, "Modify bodypart")
VV_DROPDOWN_OPTION(VV_HK_MODIFY_ORGANS, "Modify organs")
VV_DROPDOWN_OPTION(VV_HK_HALLUCINATION, "Hallucinate")
VV_DROPDOWN_OPTION(VV_HK_MARTIAL_ART, "Give Martial Arts")
VV_DROPDOWN_OPTION(VV_HK_GIVE_TRAUMA, "Give Brain Trauma")
VV_DROPDOWN_OPTION(VV_HK_CURE_TRAUMA, "Cure Brain Traumas")
/mob/living/carbon/vv_do_topic(list/href_list)
. = ..()
if(href_list[VV_HK_MODIFY_BODYPART])
if(!check_rights(R_SPAWN))
return
var/edit_action = input(usr, "What would you like to do?","Modify Body Part") as null|anything in list("add","remove", "augment")
if(!edit_action)
return
var/list/limb_list = list()
if(edit_action == "remove" || edit_action == "augment")
for(var/obj/item/bodypart/B in bodyparts)
limb_list += B.body_zone
if(edit_action == "remove")
limb_list -= BODY_ZONE_CHEST
else
limb_list = list(BODY_ZONE_HEAD, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
for(var/obj/item/bodypart/B in bodyparts)
limb_list -= B.body_zone
var/result = input(usr, "Please choose which body part to [edit_action]","[capitalize(edit_action)] Body Part") as null|anything in sortList(limb_list)
if(result)
var/obj/item/bodypart/BP = get_bodypart(result)
switch(edit_action)
if("remove")
if(BP)
BP.drop_limb()
else
to_chat(usr, span_boldwarning("[src] doesn't have such bodypart."))
if("add")
if(BP)
to_chat(usr, span_boldwarning("[src] already has such bodypart."))
else
if(!regenerate_limb(result))
to_chat(usr, span_boldwarning("[src] cannot have such bodypart."))
if("augment")
if(ishuman(src))
if(BP)
BP.change_bodypart_status(BODYPART_ROBOTIC, TRUE, TRUE)
else
to_chat(usr, span_boldwarning("[src] doesn't have such bodypart."))
else
to_chat(usr, span_boldwarning("Only humans can be augmented."))
admin_ticket_log("[key_name_admin(usr)] has modified the bodyparts of [src]")
if(href_list[VV_HK_MODIFY_ORGANS])
if(!check_rights(NONE))
return
usr.client.manipulate_organs(src)
if(href_list[VV_HK_MARTIAL_ART])
if(!check_rights(NONE))
return
var/list/artpaths = subtypesof(/datum/martial_art)
var/list/artnames = list()
for(var/i in artpaths)
var/datum/martial_art/M = i
artnames[initial(M.name)] = M
var/result = input(usr, "Choose the martial art to teach","JUDO CHOP") as null|anything in sortList(artnames, /proc/cmp_typepaths_asc)
if(!usr)
return
if(QDELETED(src))
to_chat(usr, span_boldwarning("Mob doesn't exist anymore."))
return
if(result)
var/chosenart = artnames[result]
var/datum/martial_art/MA = new chosenart
MA.teach(src)
log_admin("[key_name(usr)] has taught [MA] to [key_name(src)].")
message_admins(span_notice("[key_name_admin(usr)] has taught [MA] to [key_name_admin(src)]."))
if(href_list[VV_HK_GIVE_TRAUMA])
if(!check_rights(NONE))
return
var/list/traumas = subtypesof(/datum/brain_trauma)
var/result = input(usr, "Choose the brain trauma to apply","Traumatize") as null|anything in sortList(traumas, /proc/cmp_typepaths_asc)
if(!usr)
return
if(QDELETED(src))
to_chat(usr, "Mob doesn't exist anymore")
return
if(!result)
return
var/datum/brain_trauma/BT = gain_trauma(result)
if(BT)
log_admin("[key_name(usr)] has traumatized [key_name(src)] with [BT.name]")
message_admins(span_notice("[key_name_admin(usr)] has traumatized [key_name_admin(src)] with [BT.name]."))
if(href_list[VV_HK_CURE_TRAUMA])
if(!check_rights(NONE))
return
cure_all_traumas(TRAUMA_RESILIENCE_ABSOLUTE)
log_admin("[key_name(usr)] has cured all traumas from [key_name(src)].")
message_admins(span_notice("[key_name_admin(usr)] has cured all traumas from [key_name_admin(src)]."))
if(href_list[VV_HK_HALLUCINATION])
if(!check_rights(NONE))
return
var/list/hallucinations = subtypesof(/datum/hallucination)
var/result = input(usr, "Choose the hallucination to apply","Send Hallucination") as null|anything in sortList(hallucinations, /proc/cmp_typepaths_asc)
if(!usr)
return
if(QDELETED(src))
to_chat(usr, "Mob doesn't exist anymore")
return
if(result)
new result(src, TRUE)
/mob/living/carbon/can_resist()
return bodyparts.len > 2 && ..()

View File

@@ -10,12 +10,12 @@
if(legcuffed)
. += legcuffed.slowdown
/mob/living/carbon/slip(knockdown_amount, obj/O, lube, paralyze, force_drop)
/mob/living/carbon/slip(knockdown_amount, obj/O, lube, stun, force_drop)
if(movement_type & FLYING)
return 0
if(!(lube&SLIDE_ICE))
log_combat(src, (O ? O : get_turf(src)), "slipped on the", null, ((lube & SLIDE) ? "(LUBE)" : null))
return loc.handle_slip(src, knockdown_amount, O, lube, paralyze, force_drop)
return loc.handle_slip(src, knockdown_amount, O, lube, stun, force_drop)
/mob/living/carbon/Process_Spacemove(movement_dir = 0)
if(..())

View File

@@ -881,17 +881,60 @@
/mob/living/carbon/human/vv_get_dropdown()
. = ..()
. += "---"
.["Make monkey"] = "?_src_=vars;[HrefToken()];makemonkey=[REF(src)]"
.["Set Species"] = "?_src_=vars;[HrefToken()];setspecies=[REF(src)]"
.["Make cyborg"] = "?_src_=vars;[HrefToken()];makerobot=[REF(src)]"
.["Make alien"] = "?_src_=vars;[HrefToken()];makealien=[REF(src)]"
.["Make slime"] = "?_src_=vars;[HrefToken()];makeslime=[REF(src)]"
.["Toggle Purrbation"] = "?_src_=vars;[HrefToken()];purrbation=[REF(src)]"
.["Copy outfit"] = "?_src_=vars;[HrefToken()];copyoutfit=[REF(src)]"
.["Add/Remove Quirks"] = "?_src_=vars;[HrefToken()];modquirks=[REF(src)]"
.["Make Cluwne"] = "?_src_=vars;[HrefToken()];cluwneing=[REF(src)]" // yogs -- make cluwne
.["Make Pacman"] = "?_src_=vars;[HrefToken()];makepacman=[REF(src)]" //I LOVE PACMAN
VV_DROPDOWN_SEPERATOR
VV_DROPDOWN_OPTION(VV_HK_SET_SPECIES, "Set Species")
VV_DROPDOWN_OPTION(VV_HK_PURRBATION, "Toggle Purrbation")
VV_DROPDOWN_OPTION(VV_HK_COPY_OUTFIT, "Copy Outfit")
VV_DROPDOWN_OPTION(VV_HK_MOD_QUIRKS, "Add/Remove Quirks")
/mob/living/carbon/human/vv_do_topic(list/href_list)
. = ..()
if(href_list[VV_HK_SET_SPECIES] && check_rights(R_SPAWN))
var/result = input(usr, "Please choose a new species","Species") as null|anything in GLOB.species_list
if(result)
var/newtype = GLOB.species_list[result]
admin_ticket_log(src, "[key_name(usr)] has modified the species of [src] to [result]") // yogs - Yog Tickets
set_species(newtype)
if(href_list[VV_HK_PURRBATION] && check_rights(R_SPAWN))
if(!ishumanbasic(src))
to_chat(usr, "This can only be done to the basic human species at the moment.")
return
var/success = purrbation_toggle(src)
if(success)
to_chat(usr, "Put [src] on purrbation.")
log_admin("[key_name(usr)] has put [key_name(src)] on purrbation.")
var/msg = "[key_name(usr)] has put [key_name(src)] on purrbation." // yogs - Yog Tickets
message_admins(msg)
admin_ticket_log(src, msg)
else
to_chat(usr, "Removed [src] from purrbation.")
log_admin("[key_name(usr)] has removed [key_name(src)] from purrbation.")
var/msg = "[key_name(usr)] has removed [key_name(src)] from purrbation." // yogs - Yog Tickets
message_admins(msg)
admin_ticket_log(src, msg)
if(href_list[VV_HK_COPY_OUTFIT] && check_rights(R_SPAWN))
copy_outfit()
if(href_list[VV_HK_MOD_QUIRKS] && check_rights(R_SPAWN))
var/list/options = list("Clear"="Clear")
for(var/x in subtypesof(/datum/quirk))
var/datum/quirk/T = x
var/qname = initial(T.name)
options[has_quirk(T) ? "[qname] (Remove)" : "[qname] (Add)"] = T
var/result = input(usr, "Choose quirk to add/remove","Quirk Mod") as null|anything in options
if(result)
if(result == "Clear")
for(var/datum/quirk/q in roundstart_quirks)
remove_quirk(q.type)
else
var/T = options[result]
if(has_quirk(T))
remove_quirk(T)
else
add_quirk(T,TRUE)
/mob/living/carbon/human/MouseDrop_T(mob/living/target, mob/living/user)
if(pulling == target && grab_state >= GRAB_AGGRESSIVE && stat == CONSCIOUS)

View File

@@ -12,7 +12,7 @@
if(dna && dna.species)
. += dna.species.movement_delay(src)
/mob/living/carbon/human/slip(knockdown_amount, obj/O, lube, paralyze, forcedrop)
/mob/living/carbon/human/slip(knockdown_amount, obj/O, lube, stun, forcedrop)
if(HAS_TRAIT(src, TRAIT_NOSLIPALL))
return 0
if (!(lube & GALOSHES_DONT_HELP))

View File

@@ -1385,6 +1385,22 @@
if("lighting_alpha")
sync_lighting_plane_alpha()
/mob/living/vv_get_header()
. = ..()
var/refid = REF(src)
. += {"
<br><font size='1'><a href='?_src_=vars;[HrefToken()];datumedit=[refid];varnameedit=ckey' id='ckey'>[ckey || "No ckey"]</a> / [VV_HREF_TARGETREF_1V(refid, VV_HK_BASIC_EDIT, "[real_name || "no real name"]", NAMEOF(src, real_name))]</font>
<br><font size='1'>
BRUTE:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=brute' id='brute'>[getBruteLoss()]</a>
FIRE:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=fire' id='fire'>[getFireLoss()]</a>
TOXIN:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=toxin' id='toxin'>[getToxLoss()]</a>
OXY:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=oxygen' id='oxygen'>[getOxyLoss()]</a>
CLONE:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=clone' id='clone'>[getCloneLoss()]</a>
BRAIN:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=brain' id='brain'>[getOrganLoss(ORGAN_SLOT_BRAIN)]</a>
STAMINA:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=stamina' id='stamina'>[getStaminaLoss()]</a>
</font>
"}
/mob/living/proc/is_convert_antag()
var/list/bad_antags = list(
/datum/antagonist/clockcult,

View File

@@ -317,7 +317,7 @@ GLOBAL_LIST_INIT(special_radio_keys, list(
if(client.prefs.muted & MUTE_IC)
to_chat(src, span_danger("You cannot speak in IC (muted)."))
return FALSE
if(!ignore_spam && client.handle_spam_prevention(message,MUTE_IC))
if(!ignore_spam && message != null && client.handle_spam_prevention(message,MUTE_IC))
return FALSE
return TRUE

View File

@@ -147,8 +147,6 @@ GLOBAL_VAR_INIT(primary_data_core, null)
add_overlay(on_overlay)
/obj/machinery/ai/data_core/proc/partytime()
if(TimerID)
return FALSE
var/current_color = random_color()
set_light(7, 3, current_color)
TimerID = addtimer(CALLBACK(src, .proc/partytime), 0.5 SECONDS, TIMER_STOPPABLE)
@@ -157,6 +155,7 @@ GLOBAL_VAR_INIT(primary_data_core, null)
set_light(0)
if(TimerID)
deltimer(TimerID)
TimerID = null
/obj/machinery/ai/data_core/primary
name = "primary AI Data Core"
desc = "A complicated computer system capable of emulating the neural functions of a human at near-instantanous speeds. This one has a scrawny and faded note saying: 'Primary AI Data Core'"

View File

@@ -234,7 +234,7 @@ GLOBAL_VAR_INIT(ai_control_code, random_nukecode(6))
if(!cleared_for_use)
if(action == "clear_for_use")
var/code = text2num(params["control_code"])
var/code = params["control_code"]
if(!code)
return
@@ -242,7 +242,7 @@ GLOBAL_VAR_INIT(ai_control_code, random_nukecode(6))
if(!GLOB.ai_control_code)
return
var/length_of_number = round(log(10, code) + 1)
var/length_of_number = length(code)
if(length_of_number < 6)
to_chat(usr, span_warning("Incorrect code. Too short"))
return
@@ -251,13 +251,11 @@ GLOBAL_VAR_INIT(ai_control_code, random_nukecode(6))
to_chat(usr, span_warning("Incorrect code. Too long"))
return
if(!is_station_level(z))
to_chat(usr, span_warning("Unable to connect to NT Servers. Please verify you are onboard the station."))
return
if(code == text2num(GLOB.ai_control_code))
if(code == GLOB.ai_control_code)
cleared_for_use = TRUE
else
to_chat(usr, span_warning("Incorrect code. Make sure you have the latest one."))
@@ -283,7 +281,7 @@ GLOBAL_VAR_INIT(ai_control_code, random_nukecode(6))
if(check_access(H.get_idcard()))
authenticated = TRUE
if(action == "log_in_control_code")
var/code = text2num(params["control_code"])
var/code = params["control_code"]
if(!code)
return
@@ -291,7 +289,7 @@ GLOBAL_VAR_INIT(ai_control_code, random_nukecode(6))
if(!GLOB.ai_control_code)
return
var/length_of_number = round(log(10, code) + 1)
var/length_of_number = length(code)
if(length_of_number < 6)
to_chat(usr, span_warning("Incorrect code. Too short"))
return
@@ -300,9 +298,7 @@ GLOBAL_VAR_INIT(ai_control_code, random_nukecode(6))
to_chat(usr, span_warning("Incorrect code. Too long"))
return
if(code == text2num(GLOB.ai_control_code))
if(code == GLOB.ai_control_code)
cleared_for_use = TRUE
authenticated = TRUE
one_time_password_used = TRUE

View File

@@ -11,7 +11,8 @@
if(!.)
return .
for(var/obj/machinery/ai/data_core/datacores in GLOB.data_cores)
datacores.partytime()
if(!datacores.TimerID)
datacores.partytime()
/datum/ai_project/rgb/stop()

View File

@@ -38,6 +38,8 @@
var/syndicate_module = FALSE /// If the borg should blow emag size regardless of emag state
var/obj/item/hat // Keeps track of the hat while transforming, to attempt to place back on the borg's head
/obj/item/robot_module/Initialize()
. = ..()
for(var/i in basic_modules)
@@ -213,8 +215,10 @@
/obj/item/robot_module/proc/do_transform_animation()
var/mob/living/silicon/robot/R = loc
if(R.hat)
R.hat.forceMove(get_turf(R))
hat = R.hat
R.hat = null
hat.moveToNullspace()
R.cut_overlays()
R.setDir(SOUTH)
do_transform_delay()

View File

@@ -0,0 +1,27 @@
/mob/living/simple_animal/pet/snail
name = "snail"
desc = "Snails are mollusks, putting them in the same category as oysters, clams, and mussels."
icon = 'icons/mob/pets.dmi'
icon_state = "snail"
icon_living = "snail"
icon_dead = "snail_dead"
speak_emote = list("gurgles")
emote_hear = list("gurgles.")
emote_see = list("gurgles.")
speak_chance = 1
turns_per_move = 7
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 1)
mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
response_help = "pets"
response_disarm = "gently pushes aside"
response_harm = "stomps"
friendly = "bops"
melee_damage_lower = 2
melee_damage_upper = 2
health = 50
maxHealth = 50
gold_core_spawnable = FRIENDLY_SPAWN
/mob/living/simple_animal/pet/snail/gary
name = "Gary the snail"
desc = "Gary come home"

View File

@@ -167,10 +167,10 @@ Difficulty: Medium
break
if(last_legion)
loot = list(/obj/item/staff/storm,
/obj/item/clothing/suit/space/hardsuit/ert/paranormal/beserker,
/obj/item/organ/grandcore,
/obj/item/keycard/necropolis)
crusher_loot = list(/obj/item/crusher_trophy/malformed_bone,/obj/item/staff/storm,
/obj/item/clothing/suit/space/hardsuit/ert/paranormal/beserker,
/obj/item/organ/grandcore,
/obj/item/keycard/necropolis) //the way it is now you can get this if you just whip out the crusher towards the end but nobody's gonna do that probably
elimination = FALSE
else if(prob(10))

View File

@@ -395,6 +395,56 @@
backpack_contents = list(/obj/item/reagent_containers/glass/beaker/unholywater = 1, /obj/item/cult_shift = 1, /obj/item/flashlight/flare/culttorch = 1, /obj/item/stack/sheet/runed_metal = 15)
. = ..()
//Bloodman
/mob/living/simple_animal/hostile/asteroid/hivelord/legion/bloodman
name = "bloodman"
desc = "It's contantly dripping and absorbing blood."
icon = 'icons/mob/lavaland/lavaland_monsters.dmi'
faction = list("blooded")
icon_state = "bloodman"
icon_living = "bloodman"
icon_aggro = "bloodman"
icon_dead = "bloodman"
maxHealth = 30
health = 30 //dont want crew to have a hard time killing actual fodder
loot = null
brood_type = /mob/living/simple_animal/hostile/asteroid/hivelordbrood/bloodling
/mob/living/simple_animal/hostile/asteroid/hivelord/legion/bloodman/Initialize()
. = ..()
GLOB.bloodmen_list += src
return
/mob/living/simple_animal/hostile/asteroid/hivelord/legion/bloodman/death()
. = ..()
GLOB.bloodmen_list -= src
return
//Bloodling
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/bloodling
name = "bloodling"
desc = "Blood that hates."
icon = 'icons/mob/lavaland/lavaland_monsters.dmi'
icon_state = "bloodling"
icon_living = "bloodling"
icon_aggro = "bloodling"
icon_dead = "bloodling"
icon_gib = "syndicate_gib"
friendly = "buzzes near"
faction = list("blooded")
harm_intent_damage = 2
melee_damage_lower = 2
melee_damage_upper = 2 //fodder isnt supposed to be strong
attacktext = "gnashes at"
stat_attack = DEAD
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/bloodling/Life()
var/mob/living/simple_animal/hostile/asteroid/hivelord/legion/bloodman/L
if(isturf(loc))
for(var/mob/living/carbon/human/M in view(src,1))
if(M.stat == DEAD && GLOB.bloodmen_list.len <= 2) //max of 3 bloodmen to minimize shitshows
L = new(M.loc)
L.stored_mob = M
M.forceMove(L)
qdel(src)
..() //couldnt figure out how to make infesting work without getting duplicate def errors so just doing this

View File

@@ -1187,19 +1187,63 @@
*/
/mob/vv_get_dropdown()
. = ..()
. += "---"
.["Gib"] = "?_src_=vars;[HrefToken()];gib=[REF(src)]"
.["Give Spell"] = "?_src_=vars;[HrefToken()];give_spell=[REF(src)]"
.["Remove Spell"] = "?_src_=vars;[HrefToken()];remove_spell=[REF(src)]"
.["Give Disease"] = "?_src_=vars;[HrefToken()];give_disease=[REF(src)]"
.["Toggle Godmode"] = "?_src_=vars;[HrefToken()];godmode=[REF(src)]"
.["Drop Everything"] = "?_src_=vars;[HrefToken()];drop_everything=[REF(src)]"
.["Regenerate Icons"] = "?_src_=vars;[HrefToken()];regenerateicons=[REF(src)]"
.["Show player panel"] = "?_src_=vars;[HrefToken()];mob_player_panel=[REF(src)]"
.["Toggle Build Mode"] = "?_src_=vars;[HrefToken()];build_mode=[REF(src)]"
.["Assume Direct Control"] = "?_src_=vars;[HrefToken()];direct_control=[REF(src)]"
.["Offer Control to Ghosts"] = "?_src_=vars;[HrefToken()];offer_control=[REF(src)]"
.["Set AFK Timer"] = "?_src_=vars;[HrefToken()];set_afk=[REF(src)]"
VV_DROPDOWN_SEPERATOR
VV_DROPDOWN_OPTION(VV_HK_GIB, "Gib")
VV_DROPDOWN_OPTION(VV_HK_GIVE_SPELL, "Give Spell")
VV_DROPDOWN_OPTION(VV_HK_REMOVE_SPELL, "Remove Spell")
VV_DROPDOWN_OPTION(VV_HK_GIVE_DISEASE, "Give Disease")
VV_DROPDOWN_OPTION(VV_HK_GODMODE, "Toggle Godmode")
VV_DROPDOWN_OPTION(VV_HK_DROP_ALL, "Drop Everything")
VV_DROPDOWN_OPTION(VV_HK_REGEN_ICONS, "Regenerate Icons")
VV_DROPDOWN_OPTION(VV_HK_PLAYER_PANEL, "Show player panel")
VV_DROPDOWN_OPTION(VV_HK_BUILDMODE, "Toggle Buildmode")
VV_DROPDOWN_OPTION(VV_HK_DIRECT_CONTROL, "Assume Direct Control")
VV_DROPDOWN_OPTION(VV_HK_OFFER_GHOSTS, "Offer Control to Ghosts")
VV_DROPDOWN_OPTION(VV_HK_SET_AFK_TIMER, "Set AFK Timer")
/mob/vv_do_topic(list/href_list)
. = ..()
if(href_list[VV_HK_REGEN_ICONS] && check_rights(R_VAREDIT))
regenerate_icons()
if(href_list[VV_HK_PLAYER_PANEL])
usr.client.holder.show_player_panel(src)
if(href_list[VV_HK_GODMODE] && check_rights(R_ADMIN))
usr.client.cmd_admin_godmode(src)
if(href_list[VV_HK_GIVE_SPELL] && check_rights(R_VAREDIT))
usr.client.give_spell(src)
if(href_list[VV_HK_REMOVE_SPELL] && check_rights(R_VAREDIT))
usr.client.remove_spell(src)
if(href_list[VV_HK_GIVE_DISEASE] && check_rights(R_VAREDIT))
usr.client.give_disease(src)
if(href_list[VV_HK_GIB] && check_rights(R_FUN))
usr.client.cmd_admin_gib(src)
if(href_list[VV_HK_BUILDMODE] && check_rights(R_BUILDMODE))
togglebuildmode(src)
if(href_list[VV_HK_DROP_ALL] && check_rights(R_ADMIN))
usr.client.cmd_admin_drop_everything(src)
if(href_list[VV_HK_DIRECT_CONTROL] && check_rights(R_VAREDIT))
usr.client.cmd_assume_direct_control(src)
if(href_list[VV_HK_OFFER_GHOSTS] && check_rights(R_ADMIN))
offer_control(src)
if(href_list[VV_HK_SET_AFK_TIMER] && check_rights(R_ADMIN))
if(!mind)
to_chat(usr, "This cannot be used on mobs without a mind")
return
var/timer = input("Input AFK length in minutes, 0 to cancel the current timer", text("Input")) as num|null
if(timer == null) // Explicit null check for cancel, rather than generic truthyness, so 0 is handled differently
return
deltimer(mind.afk_verb_timer)
mind.afk_verb_used = FALSE
if(!timer)
return
mind.afk_verb_used = TRUE
mind.afk_verb_timer = addtimer(VARSET_CALLBACK(mind, afk_verb_used, FALSE), timer MINUTES, TIMER_STOPPABLE);
/**
* extra var handling for the logging var
@@ -1210,6 +1254,12 @@
return debug_variable(var_name, logging, 0, src, FALSE)
. = ..()
/mob/vv_auto_rename(new_name)
//Do not do parent's actions, as we *usually* do this differently.
fully_replace_character_name(real_name, new_name)
usr.client.vv_update_display(src, "name", new_name)
usr.client.vv_update_display(src, "real_name", real_name || "No real name")
///Show the language menu for this mob
/mob/verb/open_language_menu()
set name = "Open Language Menu"

View File

@@ -337,7 +337,7 @@
return FALSE
/// Called when this mob slips over, override as needed
/mob/proc/slip(knockdown_amount, obj/O, lube, paralyze, force_drop)
/mob/proc/slip(knockdown_amount, obj/O, lube, stun, force_drop)
return
/// Update the gravity status of this mob

View File

@@ -37,3 +37,12 @@
/obj/item/computer_hardware/network_card,
/obj/item/computer_hardware/card_slot,
/obj/item/computer_hardware/card_slot/secondary)
/obj/item/modular_computer/tablet/phone/preset/advanced/command/atmos
starting_components = list( /obj/item/computer_hardware/processor_unit/small,
/obj/item/stock_parts/cell/computer,
/obj/item/computer_hardware/hard_drive/small,
/obj/item/computer_hardware/network_card,
/obj/item/computer_hardware/card_slot,
/obj/item/computer_hardware/card_slot/secondary,
/obj/item/computer_hardware/sensorpackage)

View File

@@ -7,7 +7,7 @@
requires_ntnet = TRUE
transfer_access = null
available_on_ntnet = FALSE
usage_flags = PROGRAM_LAPTOP | PROGRAM_TABLET | PROGRAM_PHONE | PROGRAM_INTEGRATED
usage_flags = PROGRAM_LAPTOP | PROGRAM_TABLET | PROGRAM_PHONE | PROGRAM_PDA | PROGRAM_INTEGRATED
network_destination = "tracking program"
size = 5
tgui_id = "NtosRadar"
@@ -314,7 +314,7 @@
filedesc = "Implant Tracker"
extended_desc = "This program allows for tracking those implanted with tracking implants."
requires_ntnet = TRUE
transfer_access = ACCESS_SECURITY
transfer_access = ACCESS_BRIG
available_on_ntnet = TRUE
program_icon = "microchip"

View File

@@ -56,6 +56,7 @@
integrity_failure = 50
resistance_flags = FIRE_PROOF
interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON
works_with_rped_anyways = TRUE
FASTDMM_PROP(\
set_instance_vars(\
pixel_x = dir == EAST ? 24 : (dir == WEST ? -25 : INSTANCE_VAR_DEFAULT),\
@@ -291,6 +292,34 @@
if(issilicon(user))
. += span_notice("Ctrl-Click the APC to switch the breaker [ operating ? "off" : "on"].")
/obj/machinery/power/apc/exchange_parts(mob/user, obj/item/storage/part_replacer/W)
if(!istype(W))
return FALSE
if(!opened && !W.works_from_distance)
return FALSE
var/current_cell_rating = cell ? cell.get_part_rating() : -1
var/best_cell_rating = current_cell_rating
var/obj/item/stock_parts/cell/best_cell
for(var/C in W.contents)
var/obj/item/stock_parts/cell/cell = C
if (!cell || !istype(cell))
continue
var/cell_rating = cell.get_part_rating()
if (cell_rating > best_cell_rating || (cell_rating == best_cell_rating && cell.charge > best_cell.charge))
best_cell_rating = cell_rating
best_cell = cell
if (best_cell)
if (cell)
SEND_SIGNAL(W, COMSIG_TRY_STORAGE_INSERT, cell, null, null, TRUE)
to_chat(user, span_notice("[capitalize(cell.name)] replaced with [best_cell.name]."))
best_cell.forceMove(src)
var/amount_to_charge = min(best_cell.maxcharge - best_cell.charge, cell.charge)
if (cell.use(amount_to_charge))
best_cell.give(amount_to_charge)
cell = best_cell
W.play_rped_sound()
// update the APC icon to show the three base states
// also add overlays for indicator lights
/obj/machinery/power/apc/update_icon()

View File

@@ -49,6 +49,8 @@
var/spawnwithmagazine = TRUE
///Compatible magazines with the gun
var/mag_type = /obj/item/ammo_box/magazine/m10mm //Removes the need for max_ammo and caliber info
///What magazine this gun starts with, if null it will just use mag_type
var/starting_mag_type
///Whether the sprite has a visible magazine or not
var/mag_display = FALSE
///Whether the sprite has a visible ammo display or not
@@ -168,9 +170,13 @@
update_icon()
return
if (!magazine)
magazine = new mag_type(src)
if (!starting_mag_type)
magazine = new mag_type(src)
else
magazine = new starting_mag_type(src)
chamber_round()
update_icon()
/obj/item/gun/ballistic/update_icon()
if (QDELETED(src))

View File

@@ -31,6 +31,9 @@
var/obj/item/suppressor/S = new(src)
install_suppressor(S)
/obj/item/gun/ballistic/automatic/pistol/pacifist
starting_mag_type = /obj/item/ammo_box/magazine/m10mm/sp
/obj/item/gun/ballistic/automatic/pistol/m1911
name = "\improper M1911"
desc = "A classic .45 handgun with a small magazine capacity."

View File

@@ -1500,12 +1500,12 @@
/// For tracking when we tell the person we're no longer bleeding
var/was_working
/datum/reagent/medicine/coagulant/on_mob_metabolize(mob/living/M)
/datum/reagent/medicine/coagulant/on_mob_add(mob/living/M)
ADD_TRAIT(M, TRAIT_COAGULATING, type)
ADD_TRAIT(M, TRAIT_PRESERVED_ORGANS, type)
return ..()
/datum/reagent/medicine/coagulant/on_mob_end_metabolize(mob/living/M)
/datum/reagent/medicine/coagulant/on_mob_delete(mob/living/M)
REMOVE_TRAIT(M, TRAIT_COAGULATING, type)
REMOVE_TRAIT(M, TRAIT_PRESERVED_ORGANS, type)
return ..()

View File

@@ -246,6 +246,14 @@
category = list("AI Modules")
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
/datum/design/board/druid
name = "Core Module Design (Druid)"
desc = "Allows for the construction of a Druid AI Core Module."
id = "druid_module"
materials = list(/datum/material/glass = 1000, /datum/material/gold = 2000)
build_path = /obj/item/aiModule/core/full/druid
category = list("AI Modules")
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
//AI CPU + RAM

View File

@@ -444,16 +444,16 @@
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
/////////////////////////////////////////
////////////////Armour///////////////////
////////////////Armor///////////////////
/////////////////////////////////////////
/datum/design/reactive_armour
name = "Reactive Armour Shell"
desc = "An experimental suit of armour capable of utilizing an implanted anomaly core to protect the user."
id = "reactive_armour"
/datum/design/reactive_armor
name = "Reactive Armor Shell"
desc = "An experimental suit of armor capable of utilizing an implanted anomaly core to protect the user."
id = "reactive_armor"
build_type = PROTOLATHE
materials = list(/datum/material/iron = 10000, /datum/material/diamond = 5000, /datum/material/uranium = 8000, /datum/material/silver = 4500, /datum/material/gold = 5000)
build_path = /obj/item/reactive_armour_shell
build_path = /obj/item/reactive_armor_shell
category = list("Equipment")
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING

View File

@@ -15,7 +15,7 @@ If you create T5+ please take a pass at gene_modder.dm [L40]. Max_values MUST fi
var/alt_sound = null
/obj/item/storage/part_replacer/pre_attack(obj/machinery/T, mob/living/user, params)
if(!istype(T) || !T.component_parts)
if(!istype(T) || (!T.component_parts && !T.works_with_rped_anyways))
return ..()
if(user.Adjacent(T)) // no TK upgrading.
if(works_from_distance)
@@ -25,7 +25,7 @@ If you create T5+ please take a pass at gene_modder.dm [L40]. Max_values MUST fi
return ..()
/obj/item/storage/part_replacer/afterattack(obj/machinery/T, mob/living/user, adjacent, params)
if(adjacent || !istype(T) || !T.component_parts)
if(adjacent || !istype(T) || (!T.component_parts && !T.works_with_rped_anyways))
return ..()
if(works_from_distance)
user.Beam(T, icon_state = "rped_upgrade", time = 5)

View File

@@ -166,7 +166,7 @@
display_name = "Anomaly Research"
description = "Unlock the potential of the mysterious anomalies that appear on station."
prereq_ids = list("adv_engi", "practical_bluespace")
design_ids = list("reactive_armour", "anomaly_neutralizer")
design_ids = list("reactive_armor", "anomaly_neutralizer")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000)
export_price = 5000
@@ -377,7 +377,7 @@
display_name = "Artificial Intelligence"
description = "AI unit research."
prereq_ids = list("robotics", "posibrain")
design_ids = list("expansion_card_holder", "ai_data_core", "ai_core_display", "ai_control", "ai_server_overview", "ai_resource_distribution", "ai_memory_1", "ai_cpu_1", "aifixer", "safeguard_module", "onehuman_module", "protectstation_module", "quarantine_module", "oxygen_module", "freeform_module", "reset_module", "purge_module", "remove_module", "freeformcore_module", "asimov_module", "crewsimov_module", "paladin_module", "tyrant_module", "overlord_module", "ceo_module", "cowboy_module", "mother_module", "silicop_module", "construction_module", "metaexperiment_module", "researcher_module", "siliconcollective_module", "spotless_module", "clown_module", "chapai_module", "default_module", "borg_ai_control", "mecha_tracking_ai_control", "intellicard")
design_ids = list("expansion_card_holder", "ai_data_core", "ai_core_display", "ai_control", "ai_server_overview", "ai_resource_distribution", "ai_memory_1", "ai_cpu_1", "aifixer", "safeguard_module", "onehuman_module", "protectstation_module", "quarantine_module", "oxygen_module", "freeform_module", "reset_module", "purge_module", "remove_module", "freeformcore_module", "asimov_module", "crewsimov_module", "paladin_module", "tyrant_module", "overlord_module", "ceo_module", "cowboy_module", "mother_module", "silicop_module", "construction_module", "metaexperiment_module", "researcher_module", "siliconcollective_module", "spotless_module", "clown_module", "chapai_module", "druid_module", "default_module", "borg_ai_control", "mecha_tracking_ai_control", "intellicard")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000

View File

@@ -98,3 +98,33 @@
/obj/effect/proc_holder/spell/targeted/conjure_item/proc/make_item()
item = new item_type
return item
/obj/effect/proc_holder/spell/aoe_turf/horde
name = "Horde"
desc = "Bring all your existing bloodmen to you at the cost of 18% blood (15 brain damage for those without blood)."
action_icon = 'icons/mob/actions/actions_cult.dmi'
action_icon_state = "horde"
var/list/summon_type = list("/mob/living/simple_animal/hostile/asteroid/hivelord/legion/bloodman")
clothes_req = FALSE
var/summon_lifespan = 0
var/summon_ignore_density = FALSE
var/summon_ignore_prev_spawn_points = TRUE
var/list/newVars = list()
/obj/effect/proc_holder/spell/aoe_turf/horde/cast(list/targets,mob/living/carbon/user = usr)
var/list/directions = GLOB.alldirs.Copy()
if(GLOB.bloodmen_list.len < 1)
to_chat(user, span_notice("You don't have any minions to summon!"))
return
for(var/mob/living/simple_animal/hostile/asteroid/hivelord/legion/bloodman in GLOB.bloodmen_list)
var/spawndir = pick_n_take(directions)
var/turf/T = get_step(usr, spawndir)
if(NOBLOOD in user.dna.species.species_traits)
user.adjustOrganLoss(ORGAN_SLOT_BRAIN, 5)
to_chat(usr, span_notice("<span class ='userdanger'>You can almost feel your brain writhing as you call your bloodmen to you.</span>"))
else
user.blood_volume -= 30
to_chat(usr, span_notice("<span class ='userdanger'>You feel yourself becoming paler with every minion called.</span>"))
if(T)
bloodman.forceMove(T)
playsound(usr, 'sound/magic/exit_blood.ogg', 100, 1)

View File

@@ -138,3 +138,30 @@
M.emote("scream")
to_chat(M, span_warning("You feel an explosion of pain erupt in your mind!"))
return ..()
/obj/item/melee/touch_attack/raisehand
name = "\improper raise bloodman"
desc = "Blood covers your hand like a glove as it waits for a new host."
on_use_sound = 'sound/magic/wandodeath.ogg'
icon_state = "flagellation"
item_state = "hivehand"
color = "#FF0000"
/obj/item/melee/touch_attack/raisehand/afterattack(atom/target, mob/living/carbon/user, proximity)
var/mob/living/carbon/human/M = target
if(!ishuman(M) || M.stat != DEAD)
to_chat(M, span_notice("You must be targeting a dead humanoid!"))
return
if(GLOB.bloodmen_list.len > 2)
to_chat(M, span_notice("You can't control that many minions!"))
return
if(NOBLOOD in M.dna.species.species_traits)
M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 5)
to_chat(M, span_notice("Your head pounds as you raise a bloodman!"))
else
playsound(M.loc,'sound/items/drink.ogg', rand(10,50), 1)
var/mob/living/simple_animal/hostile/asteroid/hivelord/legion/bloodman/L = new(M.loc)
L.stored_mob = M
M.forceMove(L)
qdel(src)
user.blood_volume -= 50 // 9% blood cost, cheaper than the other spell because its not like you can stop near a corpse or find one near you in a fight
to_chat(user, "<span class ='userdanger'>You curse the body with your blood, leaving you feeling a bit light-headed.</span>")

View File

@@ -89,3 +89,11 @@
action_icon_state = "horror"
action_background_icon_state = "bg_ecult"
sound = 'sound/magic/fleshtostone.ogg'
/obj/effect/proc_holder/spell/targeted/touch/raise
name = "Raise bloodman"
desc = "Turn a corpse into a bloodman at the cost of 9% blood (5 brain damage for those without blood)."
action_icon = 'icons/mob/actions/actions_cult.dmi'
action_icon_state = "raise"
hand_path = /obj/item/melee/touch_attack/raisehand
clothes_req = FALSE

View File

@@ -126,7 +126,7 @@
/proc/voice_of_god(message, mob/living/user, list/span_list, base_multiplier = 1, include_speaker = FALSE, message_admins = TRUE, forced_span = FALSE)
var/cooldown = 0
if(!user || !user.can_speak() || user.stat)
if(!user || !user.can_speak(message) || user.stat)
return 0 //no cooldown
var/log_message = uppertext(message)

View File

@@ -517,6 +517,12 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
cost = 6
exclude_modes = list(/datum/game_mode/nuclear/clown_ops)
/datum/uplink_item/dangerous/pistol/spawn_item(spawn_path, mob/user, datum/component/uplink/U)
if(HAS_TRAIT_FROM(user, TRAIT_PACIFISM, ROUNDSTART_TRAIT))
spawn_path = /obj/item/gun/ballistic/automatic/pistol/pacifist
to_chat(user, span_notice("Your employer has loaded your purchased weapon with non-lethal ammunition"))
..()
/datum/uplink_item/dangerous/bolt_action
name = "Surplus Rifle"
desc = "A horribly outdated bolt action weapon. You've got to be desperate to use this."
@@ -1592,9 +1598,9 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
/datum/uplink_item/device_tools/surgerybag
name = "Syndicate Surgery Duffel Bag"
desc = "The Syndicate surgery duffel bag is a toolkit containing all surgery tools, surgical drapes, \
a Syndicate brand MMI, a straitjacket, and a muzzle."
a Syndicate brand MMI, an implant case, a straitjacket, and a muzzle."
item = /obj/item/storage/backpack/duffelbag/syndie/surgery
cost = 3
cost = 2
/datum/uplink_item/device_tools/encryptionkey
name = "Syndicate Encryption Key"

View File

@@ -478,6 +478,8 @@ LAW_WEIGHT researcher,0
ION_LAW_WEIGHT researcher,1
LAW_WEIGHT clown,0
ION_LAW_WEIGHT clown,1
LAW_WEIGHT druid,0
ION_LAW_WEIGHT druid,2
## Bad idea laws. Probably shouldn't enable these
LAW_WEIGHT syndie,0

View File

@@ -37,7 +37,7 @@
<td valign='top'>
<font size='2'><b>Current Head Developers:</b> JamieD12, Theos<br></font>
<font size='2'><b>Currently Active GitHub contributor list:</b> <a href='https://github.com/yogstation13/Yogstation/graphs/contributors'>-Click Here-</a><br></font>
<font size='2'><b>Maintainers:</b> AshCorr, Identification, Monster860, Partheo, Asd, TheGamerdk, adamsogm<br></font>
<font size='2'><b>Maintainers:</b> AshCorr, Identification, Monster860, Partheo, Asd, TheGamerdk, adamsogm, baiomu<br></font>
<font size='2'><b>Spriters:</b> Identification, Keekenox, Kmc2000, Meeeeep7, Missatessatessy, Toriate, Partheo, r3d<br></font>
<font size='2'><b>Mappers:</b> DotLyna, MayhemSailor, Monster860, Ktlwjec, Wejengin2<br></font>
<font size='2'><b>Sounds:</b> Lasty/Vinyl, Skie, Swissloaf<br></font>
@@ -58,6 +58,178 @@
-->
<div class="commit sansserif">
<h2 class="date">20 March 2022</h2>
<h3 class="author">TheGamerdk updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">AI Control Console passwords should no longer sporadically fail</li>
</ul>
<h3 class="author">maxion12345 updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">RGB project no longer flashes to one color and stops</li>
</ul>
<h2 class="date">19 March 2022</h2>
<h3 class="author">00ze-cyclone updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">an implant case for the syndie surgery duffel</li>
<li class="tweak">cheaper syndie surgery duffel</li>
</ul>
<h3 class="author">Chubbygummibear updated:</h3>
<ul class="changes bgimages16">
<li class="tweak">cooldown on health analyzer beep so medbay isn't constant beeping</li>
</ul>
<h3 class="author">MenacingManatee updated:</h3>
<ul class="changes bgimages16">
<li class="tweak">Sentient diseases now start with 2 stealth 2 resistance</li>
</ul>
<h3 class="author">Skrem7 updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Adds a new druidic lawset focused on cultivating the organics</li>
</ul>
<h3 class="author">Sniblet updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">climbing things doesn't discourage waggers</li>
<li class="tweak">felinids can now oppress other species</li>
</ul>
<h3 class="author">ToasterBiome updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">cyborgs now get an "eject hat" button that will take off their hat and drop it</li>
<li class="bugfix">fixes shitty minesweeper formatting</li>
</ul>
<h3 class="author">cuackles updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Added new simple mob (snail)</li>
<li class="imageadd">added some icons and images of said simple mob (snail)</li>
</ul>
<h3 class="author">nmajask updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">fixed deleting files from disks</li>
<li class="tweak">TRAC implant now lasts 15 minutes</li>
<li class="tweak">Detectives now start with a modular PDA</li>
<li class="tweak">Radar programs now work on PDAs and the implant tracking program now only requires brig access</li>
<li class="tweak">captain starts with a phone round start</li>
<li class="tweak">CE's phone starts with a sensor package</li>
</ul>
<h3 class="author">zen373 updated:</h3>
<ul class="changes bgimages16">
<li class="tweak">Fixes atmos airlock pipes</li>
</ul>
<h2 class="date">18 March 2022</h2>
<h3 class="author"> ToasterBiome, TheGamerdk updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">fixes engine template failing 28% of the time and picking weird weights for engines</li>
<li class="rscadd">legitimizes weird engine weights</li>
</ul>
<h3 class="author">Sniblet updated:</h3>
<ul class="changes bgimages16">
<li class="tweak">made the code slightly less illiterate</li>
</ul>
<h2 class="date">17 March 2022</h2>
<h3 class="author"> Identification updated:</h3>
<ul class="changes bgimages16">
<li class="imageadd">Telescopic batons are now a discernible shape</li>
</ul>
<h3 class="author">Chubbygummibear updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Throwing Mjolnier into someone with anti-magic makes it go bye bye in a big boom</li>
</ul>
<h3 class="author">ToasterBiome updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">removes erroneous admin logging that is not needed</li>
</ul>
<h2 class="date">16 March 2022</h2>
<h3 class="author">Marmio64 updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Adds text saying that you can use a lit candle instead of a welder to heat up bowls, substitute cacti for porcini leaves, and that resin uses water now instead of heat to solidify, to the ash walker's knowledge book.</li>
<li class="spellcheck">Fixed a typo with poultice making.</li>
</ul>
<h3 class="author">adamsong updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">fixed bug in dna console sanitization</li>
</ul>
<h2 class="date">15 March 2022</h2>
<h3 class="author">ToasterBiome updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">baiomu is now credited under maintainer</li>
</ul>
<h2 class="date">14 March 2022</h2>
<h3 class="author">nmajask updated:</h3>
<ul class="changes bgimages16">
<li class="tweak">pacifists who order stechkins from uplinks now get a version loaded with soporific rounds</li>
</ul>
<h2 class="date">13 March 2022</h2>
<h3 class="author">Absolucy updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Strong holoparasites can now smash objects that restrain their master (click on them as if you were attacking)</li>
</ul>
<h3 class="author">KillerOrcaCora updated:</h3>
<ul class="changes bgimages16">
<li class="imageadd">Makes Station engineer skill cape the drippiest thing since air shoes.</li>
</ul>
<h3 class="author">LazennG updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">adds new legion loot called 'grand core', along with a legion subtype called bloodman/bloodlings.</li>
<li class="rscdel">Removes champ's hardsuit from legion loot</li>
<li class="imageadd">added some sprites for the grand core and its abilities</li>
</ul>
<h3 class="author">Sniblet updated:</h3>
<ul class="changes bgimages16">
<li class="tweak">Slips now stun instead of paralyzing</li>
</ul>
<h3 class="author">TheGamerdk updated:</h3>
<ul class="changes bgimages16">
<li class="tweak">Appearance ban applies to accent choice too</li>
</ul>
<h3 class="author">ToasterBiome updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">chaplains can no longer roll vampire on traitor+vamp rounds</li>
</ul>
<h3 class="author">adamsong updated:</h3>
<ul class="changes bgimages16">
<li class="tweak">mentorwho no longer shows admins</li>
<li class="bugfix">fixed automute false positives</li>
<li class="rscadd">Added show hiddenprints to VV</li>
<li class="tweak">borgs can spawn with donor hats if enabled in preferences</li>
<li class="tweak">borgs no longer drop hats on module change</li>
<li class="rscdel">Removed 2FA requirement to open the permissions panel, still required to edit permissions</li>
</ul>
<h3 class="author">cuackles updated:</h3>
<ul class="changes bgimages16">
<li class="imageadd">add a new brass knuckles sprite</li>
<li class="imagedel">deleted old brass knuckles sprite</li>
</ul>
<h3 class="author">tattax updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Added blob zombos' sentiency (blobs are smart)</li>
<li class="tweak">Changed how Networked Fibers works.</li>
</ul>
<h2 class="date">12 March 2022</h2>
<h3 class="author">ToasterBiome updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">expands box incinerator to have a little tinkering area</li>
<li class="tweak">moves AI sat 3 tiles down on box</li>
</ul>
<h3 class="author">adamsong updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Added button to convert blood brother into traitor</li>
</ul>
<h3 class="author">maxion12345 updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">fixed reactive armor shell names</li>
<li class="bugfix">syndicate base has an oven</li>
</ul>
<h3 class="author">nmajask updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">fixed the vial box in the brig infirmary being the one for virology and fixed the access for the maint door</li>
</ul>
<h2 class="date">10 March 2022</h2>
<h3 class="author">ToasterBiome updated:</h3>
<ul class="changes bgimages16">
@@ -1071,196 +1243,6 @@
<li class="bugfix">fixed a few things</li>
<li class="tweak">tweaked a few things</li>
</ul>
<h2 class="date">19 December 2021</h2>
<h3 class="author"> Lucy updated:</h3>
<ul class="changes bgimages16">
<li class="tweak">YogsMeta no longer has bruise packs and ointment in front of medbay, they have been replaced with regenerative mesh and sutures</li>
<li class="tweak">YogsMeta's AI MiniSat is now properly wired up at roundstart.</li>
<li class="rscadd">You can now spawn in with a jumpskirt if you want!</li>
<li class="tweak">The singularity is less likely to fuck off into space now.</li>
<li class="rscadd">Adds the Access Kit for infiltrators, which allows them to spoof the ID and access of several "low-level" jobs. It is single-use and only one can be bought per infiltrator.</li>
<li class="rscadd">There is now a preference to disable "alternative" potentially misophonia-triggering sounds!</li>
</ul>
<h3 class="author">Sniblet updated:</h3>
<ul class="changes bgimages16">
<li class="tweak">lexorin now requires chloral hydrate instead of hydrogen</li>
<li class="tweak">lexorin now metabolizes 1.25x faster</li>
<li class="tweak">lexorin now cannot be tasted (because you're choking)</li>
</ul>
<h3 class="author">SomeguyManperson updated:</h3>
<ul class="changes bgimages16">
<li class="tweak">you can no longer stealth suck 20000 bloods as a vampire and impact the round in 0 meaningful ways</li>
<li class="tweak">the stealth suck low blood warning to the victim has been changed to point at you for screwing up</li>
<li class="tweak">vampires get far less blood sucking from braindeads than actual players</li>
</ul>
<h3 class="author">boodaliboo updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Added preternis special healing thing with oil welding fuel and teslium to synths</li>
</ul>
<h3 class="author">cuackles updated:</h3>
<ul class="changes bgimages16">
<li class="tweak">mummy clothing in the vendor, including headress</li>
<li class="rscadd">new holy weapon</li>
<li class="imageadd">added skull sprites</li>
</ul>
<h3 class="author">fluffe9911 updated:</h3>
<ul class="changes bgimages16">
<li class="soundadd">New Jukebox song Glorious Morning!</li>
</ul>
<h3 class="author">nmajask updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Added syndicate disks and trapped disks</li>
<li class="tweak">DoS Traffic Generator modular computer item is now an uplink item</li>
<li class="tweak">the mining tracking implant kit now stores 4 tracking implant cases, an implanter, and a disk containing the implant tracker program.</li>
</ul>
<h2 class="date">18 December 2021</h2>
<h3 class="author">TheGamerdk updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Instead of being based out of an AI core, the AI is now based out of different data cores around the station. Kill all of these to kill the AI</li>
<li class="rscadd">Added servers that can be created and filled with new CPU/RAM cards. These will allow the AI to research and use special upgrades</li>
<li class="rscadd">Creating and stealing the AI is now done through the AI upload console. These can be created anywhere but requires the use of a password that starts in the RDs office.</li>
<li class="rscdel">Deleted the ability to create regular AI cores</li>
<li class="tweak">AI HUD now wraps down to 1 line if playing in widescreen</li>
<li class="tweak">When compiling using VSCode you will now automatically run DreamDaemon instead of DreamSeeker. This means hotkeys/movement keys work correctly.</li>
<li class="experiment">AI now suffers permadeath if all their cores are knocked offline</li>
</ul>
<h3 class="author">ToasterBiome updated:</h3>
<ul class="changes bgimages16">
<li class="tweak">AI sat airlock</li>
<li class="tweak">flip secondary ai core</li>
<li class="tweak">fix maint having an extra wall</li>
<li class="bugfix">removed extra airlock controller</li>
<li class="bugfix">moved air alarm in secondary core so it's not always angry</li>
<li class="tweak">adds lights to ai core airlock</li>
<li class="bugfix">fixes exterior airlock button opening interior airlock</li>
</ul>
<h2 class="date">16 December 2021</h2>
<h3 class="author"> Identification, Kor updated:</h3>
<ul class="changes bgimages16">
<li class="imageadd">Unifies both the old cloaks and recently added new cloaks into a single set of cloaks.</li>
<li class="tweak">Backpacks don't appear over the top of cloaks</li>
</ul>
<h3 class="author">UselessTheremin updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">kittens now have randomized names</li>
</ul>
<h2 class="date">15 December 2021</h2>
<h3 class="author">adamsong updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">fixed AO OOC not working</li>
<li class="rscadd">Added pretty filter to *me and several other things</li>
</ul>
<h2 class="date">14 December 2021</h2>
<h3 class="author">adamsong updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">fixed borgs being unable to use the advanced analyzer as a surgical processor</li>
<li class="bugfix">fixed quirk exploit that allowed for more positive quirks than there were points for</li>
<li class="bugfix">fixed buffoonery in the advanced surgical kit tech node</li>
</ul>
<h3 class="author">nmajask updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">fixed some skirts having no icons when worn by someone with digitigrade legs</li>
</ul>
<h2 class="date">13 December 2021</h2>
<h3 class="author">SomeguyManperson updated:</h3>
<ul class="changes bgimages16">
<li class="tweak">custom shuttle landing points can now be placed on specifically asteroid/lavaland turfs not station maintenance</li>
<li class="bugfix">borgs can see their progress bar when buckling again, also they can buckle incapacitated people</li>
<li class="bugfix">failing to buckle to a borg will no longer result in you trying to buckle to the same borg a second time</li>
</ul>
<h2 class="date">12 December 2021</h2>
<h3 class="author"> Xoxeyos updated:</h3>
<ul class="changes bgimages16">
<li class="soundadd">Adds a section of "Christmastime in Sector 5" to the Christmas playlist.</li>
</ul>
<h3 class="author"> Lucy updated:</h3>
<ul class="changes bgimages16">
<li class="tweak">Infiltrators can no longer buy the hacked AI law upload board. Stop screwing with the AI ffs!</li>
</ul>
<h3 class="author"> Xoxeyos updated:</h3>
<ul class="changes bgimages16">
<li class="soundadd">Adds a Star Trek parody of Little Drummer Boy to the Christmas playlist.</li>
<li class="soundadd">Adds "Beacons in the Darkness" by Gary McGath to the Christmas playlist.</li>
</ul>
<h3 class="author"> deathrider58 updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">When an item is thrown, it will now be rotated and displaced.</li>
<li class="rscadd">Shards of glass will now be rotated when spawned.</li>
<li class="rscadd">Bullet casings will now be rotated when they're ejected from a gun.</li>
<li class="rscadd">Bottles now have random rotations and pixel offsets when smashed via throwing.</li>
<li class="rscadd">Picking up an item will now reset its rotation.</li>
<li class="rscadd">Glasses thrown onto tables by bartenders will now have their rotation reset.</li>
</ul>
<h3 class="author">Inari-Whitebear updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">Fixed Remote signaling device UI being cut off</li>
<li class="bugfix">Fixed Remote signaling device UI button not having cyan/magenta colours, resulting in black button when those were selected</li>
</ul>
<h3 class="author">KittyNoodle updated:</h3>
<ul class="changes bgimages16">
<li class="tweak">Flamethrowers are now locked behind Makeshift Weapons 101</li>
</ul>
<h3 class="author">Marmio64 updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Adds resin arm bands and tribal bonegel</li>
<li class="rscdel">Removed tribalordrazine</li>
<li class="tweak">tome of herbal knowledge has new knowledge, polypore resin count upped, tribal poultice recipe changed, chitin spear sinew cost reduced, resin solidifies from water instead of heat.</li>
<li class="rscadd">Adds 4 new traits: Hemophiliac, Efficient Metabolism, Crafty, and Cyber Organ.</li>
<li class="tweak">trait points are doubled across the board to allow for more middleground. Voracious, tagger, photographer, musician, spiritual, empath, and friendly cost less while Blind and Paraplegic give an extra point.</li>
</ul>
<h3 class="author">SomeguyManperson updated:</h3>
<ul class="changes bgimages16">
<li class="tweak">reviver implant is now faster, works in soft crit if you aren't sleeping, and has had its heart attack emp effect reduced from a minute to 10 seconds</li>
<li class="tweak">sleepers with the stasis upgrade will now put people into stasis under more specific circumstances</li>
<li class="bugfix">fixes pickaxes not being allowed to touch the same rock for the length of the initial mining attempt</li>
<li class="tweak">brainwashing surgery is available under alien surgery where it used to be</li>
<li class="tweak">traitor brainwash disk item is no longer job restricted</li>
</ul>
<h3 class="author">ToasterBiome updated:</h3>
<ul class="changes bgimages16">
<li class="tweak">mindshields remove mindslave</li>
<li class="tweak">mindslaved people reject mindshields</li>
<li class="rscadd">best hugs make heart effects idk i dont have mood enabled</li>
</ul>
<h3 class="author">adamsong updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Added advanced health analyzer upgrade to med borgs</li>
<li class="rscdel">Removed surgical processor from med borgs</li>
<li class="bugfix">fixed mfa reset telling you the wrong thing was reset</li>
<li class="bugfix">fixed but allowing antag tokens to be used more than once</li>
<li class="bugfix">fixed revs not properly prioritizing antag tokens</li>
<li class="bugfix">fixed airlocks sometimes being invisible when painted</li>
</ul>
<h3 class="author">nmajask updated:</h3>
<ul class="changes bgimages16">
<li class="tweak">Fission360 now has a program icon</li>
<li class="tweak">modular computer program overlays now glow in the dark</li>
<li class="rscadd">Added OverSeer, a program to view labor camp cameras</li>
<li class="bugfix">fixed crew monitors labeling people in soft crit and unconscious as dead</li>
<li class="tweak">brig physicians now have access to perma</li>
</ul>
<h3 class="author">wejengin2 updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">new interaction for licking the supermatter</li>
<li class="soundadd">Adds some songs to the april fools playlist</li>
</ul>
<h2 class="date">11 December 2021</h2>
<h3 class="author"> Lucy updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">Fixed holoparasite masters not being able to communicate with their holoparasites. Whoops.</li>
</ul>
<h3 class="author">maxion12345 updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">fixed a locker name in the yogurtstation brig</li>
</ul>
</div>
<b>GoonStation 13 Development Team</b>

View File

@@ -30282,3 +30282,111 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- bugfix: fixed runtime in remove_accessory
cuackles:
- tweak: tweaked a few things
2022-03-12:
ToasterBiome:
- rscadd: expands box incinerator to have a little tinkering area
- tweak: moves AI sat 3 tiles down on box
adamsong:
- rscadd: Added button to convert blood brother into traitor
maxion12345:
- bugfix: fixed reactive armor shell names
- bugfix: syndicate base has an oven
nmajask:
- bugfix: fixed the vial box in the brig infirmary being the one for virology and
fixed the access for the maint door
2022-03-13:
Absolucy:
- rscadd: Strong holoparasites can now smash objects that restrain their master
(click on them as if you were attacking)
KillerOrcaCora:
- imageadd: Makes Station engineer skill cape the drippiest thing since air shoes.
LazennG:
- rscadd: adds new legion loot called 'grand core', along with a legion subtype
called bloodman/bloodlings.
- rscdel: Removes champ's hardsuit from legion loot
- imageadd: added some sprites for the grand core and its abilities
Sniblet:
- tweak: Slips now stun instead of paralyzing
TheGamerdk:
- tweak: Appearance ban applies to accent choice too
ToasterBiome:
- bugfix: chaplains can no longer roll vampire on traitor+vamp rounds
adamsong:
- tweak: mentorwho no longer shows admins
- bugfix: fixed automute false positives
- rscadd: Added show hiddenprints to VV
- tweak: borgs can spawn with donor hats if enabled in preferences
- tweak: borgs no longer drop hats on module change
- rscdel: Removed 2FA requirement to open the permissions panel, still required
to edit permissions
cuackles:
- imageadd: add a new brass knuckles sprite
- imagedel: deleted old brass knuckles sprite
tattax:
- rscadd: Added blob zombos' sentiency (blobs are smart)
- tweak: Changed how Networked Fibers works.
2022-03-14:
nmajask:
- tweak: pacifists who order stechkins from uplinks now get a version loaded with
soporific rounds
2022-03-15:
ToasterBiome:
- rscadd: baiomu is now credited under maintainer
2022-03-16:
Marmio64:
- rscadd: Adds text saying that you can use a lit candle instead of a welder to
heat up bowls, substitute cacti for porcini leaves, and that resin uses water
now instead of heat to solidify, to the ash walker's knowledge book.
- spellcheck: Fixed a typo with poultice making.
adamsong:
- bugfix: fixed bug in dna console sanitization
2022-03-17:
' Identification':
- imageadd: Telescopic batons are now a discernible shape
Chubbygummibear:
- rscadd: Throwing Mjolnier into someone with anti-magic makes it go bye bye in
a big boom
ToasterBiome:
- bugfix: removes erroneous admin logging that is not needed
2022-03-18:
' ToasterBiome, TheGamerdk':
- bugfix: fixes engine template failing 28% of the time and picking weird weights
for engines
- rscadd: legitimizes weird engine weights
Sniblet:
- tweak: made the code slightly less illiterate
2022-03-19:
00ze-cyclone:
- rscadd: an implant case for the syndie surgery duffel
- tweak: cheaper syndie surgery duffel
Chubbygummibear:
- tweak: cooldown on health analyzer beep so medbay isn't constant beeping
MenacingManatee:
- tweak: Sentient diseases now start with 2 stealth 2 resistance
Skrem7:
- rscadd: Adds a new druidic lawset focused on cultivating the organics
Sniblet:
- bugfix: climbing things doesn't discourage waggers
- tweak: felinids can now oppress other species
ToasterBiome:
- rscadd: cyborgs now get an "eject hat" button that will take off their hat and
drop it
- bugfix: fixes shitty minesweeper formatting
cuackles:
- rscadd: Added new simple mob (snail)
- imageadd: added some icons and images of said simple mob (snail)
nmajask:
- bugfix: fixed deleting files from disks
- tweak: TRAC implant now lasts 15 minutes
- tweak: ' Detectives now start with a modular PDA'
- tweak: Radar programs now work on PDAs and the implant tracking program now only
requires brig access
- tweak: captain starts with a phone round start
- tweak: CE's phone starts with a sensor package
zen373:
- tweak: Fixes atmos airlock pipes
2022-03-20:
TheGamerdk:
- bugfix: AI Control Console passwords should no longer sporadically fail
maxion12345:
- bugfix: RGB project no longer flashes to one color and stops

View File

@@ -37,7 +37,7 @@
<td valign='top'>
<font size='2'><b>Current Head Developers:</b> JamieD12, Theos<br></font>
<font size='2'><b>Currently Active GitHub contributor list:</b> <a href='https://github.com/yogstation13/Yogstation/graphs/contributors'>-Click Here-</a><br></font>
<font size='2'><b>Maintainers:</b> AshCorr, Identification, Monster860, Partheo, Asd, TheGamerdk, adamsogm<br></font>
<font size='2'><b>Maintainers:</b> AshCorr, Identification, Monster860, Partheo, Asd, TheGamerdk, adamsogm, baiomu<br></font>
<font size='2'><b>Spriters:</b> Identification, Keekenox, Kmc2000, Meeeeep7, Missatessatessy, Toriate, Partheo, r3d<br></font>
<font size='2'><b>Mappers:</b> DotLyna, MayhemSailor, Monster860, Ktlwjec, Wejengin2<br></font>
<font size='2'><b>Sounds:</b> Lasty/Vinyl, Skie, Swissloaf<br></font>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 KiB

After

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 94 KiB

Some files were not shown because too many files have changed in this diff Show More