From d95be2e26121166b60ab1fbf18c7dc73d0b8b738 Mon Sep 17 00:00:00 2001 From: CitadelStationBot Date: Tue, 6 Mar 2018 04:04:12 -0600 Subject: [PATCH] [MIRROR] Allows admins to spawn mob-like objects for shenanigans (#5825) * Allows admins to spawn mob-like objects for shenanigans (#36153) This is basically extracting the functionality of the animation spell into an admin verb. Please excuse the browser.dm code, this is more of a stepping stone towards the more complicated popup needed for custom ERTs. cl Naksu admin: Admins can now easily spawn mobs that look like objects. Googly eyes optional! /cl * Allows admins to spawn mob-like objects for shenanigans --- code/datums/browser.dm | 82 +++++++++++++++++++ code/modules/admin/admin_verbs.dm | 2 +- code/modules/admin/verbs/spawnobjasmob.dm | 70 ++++++++++++++++ .../mob/living/simple_animal/hostile/mimic.dm | 11 ++- tgstation.dme | 1 + 5 files changed, 162 insertions(+), 4 deletions(-) create mode 100644 code/modules/admin/verbs/spawnobjasmob.dm diff --git a/code/datums/browser.dm b/code/datums/browser.dm index d525b52ca5..9561515840 100644 --- a/code/datums/browser.dm +++ b/code/datums/browser.dm @@ -305,6 +305,88 @@ else return +/datum/browser/modal/preflikepicker + var/settings = list() + var/icon/preview_icon = null + +/datum/browser/modal/preflikepicker/New(User,Message,Title,Button1="Ok",Button2,Button3,StealFocus = 1, Timeout = FALSE,list/settings,inputtype="checkbox", width = 400, height, slidecolor) + if (!User) + return + src.settings = settings + + ..(User, ckey("[User]-[Message]-[Title]-[world.time]-[rand(1,10000)]"), Title, width, height, src, StealFocus, Timeout) + set_content(ShowChoices(User)) + +/datum/browser/modal/preflikepicker/proc/ShowChoices(mob/user) + var/dat = "" + + for (var/name in settings["mainsettings"]) + var/setting = settings["mainsettings"][name] + if (setting["type"] == "datum") + dat += "[setting["desc"]]: [setting["value"]]
" + else + dat += "[setting["desc"]]: [setting["value"]]
" + + if (preview_icon) + dat += "" + + dat += "
" + + dat += "" + + dat += "" + + dat += "
Ok " + + dat += "
" + + return dat + +/datum/browser/modal/preflikepicker/Topic(href,href_list) + if (href_list["close"] || !user || !user.client) + opentime = 0 + return + if (href_list["task"] == "input") + var/setting = href_list["setting"] + switch (href_list["type"]) + if ("datum") + settings["mainsettings"][setting]["value"] = pick_closest_path(null, make_types_fancy(typesof(text2path(href_list["path"])))) + if ("string") + settings["mainsettings"][setting]["value"] = stripped_input(user, "Enter new value for [settings["mainsettings"][setting]["desc"]]", "Enter new value for [settings["mainsettings"][setting]["desc"]]") + if ("number") + settings["mainsettings"][setting]["value"] = input(user, "Enter new value for [settings["mainsettings"][setting]["desc"]]", "Enter new value for [settings["mainsettings"][setting]["desc"]]") as num + if ("boolean") + settings["mainsettings"][setting]["value"] = input(user, "[settings["mainsettings"][setting]["desc"]]?") in list("Yes","No") + if ("ckey") + settings["mainsettings"][setting]["value"] = input(user, "[settings["mainsettings"][setting]["desc"]]?") in list("none") + GLOB.directory + if (href_list["button"]) + var/button = text2num(href_list["button"]) + if (button <= 3 && button >= 1) + selectedbutton = button + if (selectedbutton != 1) + set_content(ShowChoices(user)) + open() + return + for (var/item in href_list) + switch(item) + if ("close", "button", "src") + continue + opentime = 0 + close() + +/proc/presentpreflikepicker(var/mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1,Timeout = 6000,list/settings, width, height, slidecolor) + if (!istype(User)) + if (istype(User, /client/)) + var/client/C = User + User = C.mob + else + return + var/datum/browser/modal/preflikepicker/A = new(User, Message, Title, Button1, Button2, Button3, StealFocus,Timeout, settings, width, height, slidecolor) + A.open() + A.wait() + if (A.selectedbutton) + return list("button" = A.selectedbutton, "settings" = A.settings) + // This will allow you to show an icon in the browse window // This is added to mob so that it can be used without a reference to the browser object // There is probably a better place for this... diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index f38bfdd84d..85811f693c 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -100,7 +100,7 @@ GLOBAL_LIST_INIT(admin_verbs_fun, list( /client/proc/smite )) GLOBAL_PROTECT(admin_verbs_spawn) -GLOBAL_LIST_INIT(admin_verbs_spawn, list(/datum/admins/proc/spawn_atom, /datum/admins/proc/spawn_cargo, /client/proc/respawn_character)) +GLOBAL_LIST_INIT(admin_verbs_spawn, list(/datum/admins/proc/spawn_atom, /datum/admins/proc/spawn_cargo, /datum/admins/proc/spawn_objasmob, /client/proc/respawn_character)) GLOBAL_PROTECT(admin_verbs_server) GLOBAL_LIST_INIT(admin_verbs_server, world.AVerbsServer()) /world/proc/AVerbsServer() diff --git a/code/modules/admin/verbs/spawnobjasmob.dm b/code/modules/admin/verbs/spawnobjasmob.dm new file mode 100644 index 0000000000..f51f776d6f --- /dev/null +++ b/code/modules/admin/verbs/spawnobjasmob.dm @@ -0,0 +1,70 @@ +/datum/admins/proc/spawn_objasmob(object as text) + set category = "Debug" + set desc = "(obj path) Spawn object-mob" + set name = "Spawn object-mob" + + if(!check_rights(R_SPAWN)) + return + + var/chosen = pick_closest_path(object, make_types_fancy(subtypesof(/obj))) + + if (!chosen) + return + + var/mob/living/simple_animal/hostile/mimic/copy/basemob = /mob/living/simple_animal/hostile/mimic/copy + + var/obj/chosen_obj = text2path(chosen) + + var/list/settings = list( + "mainsettings" = list( + "name" = list("desc" = "Name", "type" = "string", "value" = "Bob"), + "maxhealth" = list("desc" = "Max. health", "type" = "number", "value" = 100), + "access" = list("desc" = "Access ID", "type" = "datum", "path" = "/obj/item/card/id", "value" = "Default"), + "objtype" = list("desc" = "Base obj type", "type" = "datum", "path" = "/obj", "value" = "[chosen]"), + "googlyeyes" = list("desc" = "Googly eyes", "type" = "boolean", "value" = "No"), + "disableai" = list("desc" = "Disable AI", "type" = "boolean", "value" = "Yes"), + "idledamage" = list("desc" = "Damaged while idle", "type" = "boolean", "value" = "No"), + "dropitem" = list("desc" = "Drop obj on death", "type" = "boolean", "value" = "Yes"), + "mobtype" = list("desc" = "Base mob type", "type" = "datum", "path" = "/mob/living/simple_animal/hostile/mimic/copy", "value" = "/mob/living/simple_animal/hostile/mimic/copy"), + "ckey" = list("desc" = "ckey", "type" = "ckey", "value" = "none"), + ) + ) + + var/list/prefreturn = presentpreflikepicker(usr,"Customize mob", "Customize mob", Button1="Ok", width = 450, StealFocus = 1,Timeout = 0, settings=settings) + if (prefreturn["button"] == 1) + settings = prefreturn["settings"] + var/mainsettings = settings["mainsettings"] + chosen_obj = text2path(mainsettings["objtype"]["value"]) + + basemob = text2path(mainsettings["mobtype"]["value"]) + if (!ispath(basemob, /mob/living/simple_animal/hostile/mimic/copy) || !ispath(chosen_obj, /obj)) + to_chat(usr, "Mob or object path invalid") + + basemob = new basemob(get_turf(usr), new chosen_obj(get_turf(usr)), usr, mainsettings["dropitem"]["value"] == "Yes" ? FALSE : TRUE, (mainsettings["googlyeyes"]["value"] == "Yes" ? FALSE : TRUE)) + + if (mainsettings["disableai"]["value"] == "Yes") + basemob.toggle_ai(AI_OFF) + + if (mainsettings["idledamage"]["value"] == "No") + basemob.idledamage = FALSE + + if (mainsettings["access"]) + var/newaccess = text2path(mainsettings["access"]["value"]) + if (ispath(newaccess)) + basemob.access_card = new newaccess + + if (mainsettings["maxhealth"]["value"]) + if (!isnum(mainsettings["maxhealth"]["value"])) + mainsettings["maxhealth"]["value"] = text2num(mainsettings["maxhealth"]["value"]) + if (mainsettings["maxhealth"]["value"] > 0) + basemob.maxHealth = basemob.maxHealth = mainsettings["maxhealth"]["value"] + + if (mainsettings["name"]["value"]) + basemob.name = basemob.real_name = html_decode(mainsettings["name"]["value"]) + + if (mainsettings["ckey"]["value"] != "none") + basemob.ckey = mainsettings["ckey"]["value"] + + + log_admin("[key_name(usr)] spawned a sentient object-mob [basemob] from [chosen_obj] at ([usr.x],[usr.y],[usr.z])") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Spawn object-mob") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/mob/living/simple_animal/hostile/mimic.dm b/code/modules/mob/living/simple_animal/hostile/mimic.dm index 670d571d4d..7259a730e5 100644 --- a/code/modules/mob/living/simple_animal/hostile/mimic.dm +++ b/code/modules/mob/living/simple_animal/hostile/mimic.dm @@ -101,15 +101,19 @@ GLOBAL_LIST_INIT(protected_objects, list(/obj/structure/table, /obj/structure/ca var/destroy_objects = 0 var/knockdown_people = 0 var/static/mutable_appearance/googly_eyes = mutable_appearance('icons/mob/mob.dmi', "googly_eyes") + var/overlay_googly_eyes = TRUE + var/idledamage = TRUE gold_core_spawnable = NO_SPAWN -/mob/living/simple_animal/hostile/mimic/copy/Initialize(mapload, obj/copy, mob/living/creator, destroy_original = 0) +/mob/living/simple_animal/hostile/mimic/copy/Initialize(mapload, obj/copy, mob/living/creator, destroy_original = 0, no_googlies = FALSE) . = ..() + if (no_googlies) + overlay_googly_eyes = FALSE CopyObject(copy, creator, destroy_original) /mob/living/simple_animal/hostile/mimic/copy/Life() ..() - if(!target && !ckey) //Objects eventually revert to normal if no one is around to terrorize + if(idledamage && !target && !ckey) //Objects eventually revert to normal if no one is around to terrorize adjustBruteLoss(1) for(var/mob/living/M in contents) //a fix for animated statues from the flesh to stone spell death() @@ -143,7 +147,8 @@ GLOBAL_LIST_INIT(protected_objects, list(/obj/structure/table, /obj/structure/ca icon_state = O.icon_state icon_living = icon_state copy_overlays(O) - add_overlay(googly_eyes) + if (overlay_googly_eyes) + add_overlay(googly_eyes) if(isstructure(O) || ismachinery(O)) health = (anchored * 50) + 50 destroy_objects = 1 diff --git a/tgstation.dme b/tgstation.dme index 2bc8d3ec24..0f159bed10 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -1095,6 +1095,7 @@ #include "code\modules\admin\verbs\pray.dm" #include "code\modules\admin\verbs\randomverbs.dm" #include "code\modules\admin\verbs\reestablish_db_connection.dm" +#include "code\modules\admin\verbs\spawnobjasmob.dm" #include "code\modules\admin\verbs\tripAI.dm" #include "code\modules\admin\verbs\SDQL2\SDQL_2.dm" #include "code\modules\admin\verbs\SDQL2\SDQL_2_parser.dm"