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"