Alternate Appearance system (from tgstation/-tg-station#16586)

This adds an "alternate appearance system" using image overrides and a new
handler system.

Usage:
 - Create a new `image()` casted as `var/image`
 - Set image.override = 1
 - Call mob.add_alt_appearance("appearance_ID", image, listOfMobsToDisplayTo).
 - To remove an image, you use mob.remove_alt_appearance("appearance_ID")

Comes with one usage, cardborg costumes. They will now disguise you as a
standard borg to any silicon mobs and yourself.
As this is a per-client system, that means that only silicon mobs and you will
see yourself as a standard borg. All other mobs will see you as a silly
human in a cardborg costume.
This commit is contained in:
Tigercat2000
2016-04-06 12:36:26 -07:00
parent 1a1701d27a
commit 801cbe7f8d
8 changed files with 212 additions and 12 deletions
+2 -2
View File
@@ -17,11 +17,11 @@ var/list/stealthminID = list() //reference list with IDs that store ckeys,
var/global/list/player_list = list() //List of all mobs **with clients attached**. Excludes /mob/new_player
var/global/list/mob_list = list() //List of all mobs, including clientless
var/global/list/silicon_mob_list = list() //List of all silicon mobs, including clientless
var/global/list/silicon_mob_list = list() //List of all silicon mobs, including clientless
var/global/list/spirits = list() //List of all the spirits, including Masks
var/global/list/living_mob_list = list() //List of all alive mobs, including clientless. Excludes /mob/new_player
var/global/list/dead_mob_list = list() //List of all dead mobs, including clientless. Excludes /mob/new_player
var/global/list/respawnable_list = list() //List of all mobs, dead or in mindless creatures that still be respawned.
var/global/list/respawnable_list = list() //List of all mobs, dead or in mindless creatures that still be respawned.
var/global/list/simple_animal_list = list() //List of all simple animals, including clientless
var/global/list/med_hud_users = list()
+155
View File
@@ -0,0 +1,155 @@
/*
Alternate Appearances! By RemieRichards
A framework for replacing an atom (and it's overlays) with an override = 1 image, that's less shit!
Example uses:
* hallucinating all mobs looking like skeletons
* people wearing cardborg suits appearing as Standard Cyborgs to the other Silicons
* !!use your imagination!!
*/
//This datum is built on-the-fly by some of the procs below
//no need to instantiate it
/datum/alternate_appearance
var/key = ""
var/image/img
var/list/viewers = list()
var/atom/owner = null
/*
Displays the alternate_appearance
displayTo - a list of MOBS to show this appearance to
*/
/datum/alternate_appearance/proc/display_to(list/displayTo)
if(!displayTo || !displayTo.len)
return
for(var/m in displayTo)
var/mob/M = m
if(!M.viewing_alternate_appearances)
M.viewing_alternate_appearances = list()
viewers |= M
M.viewing_alternate_appearances[key] = src
if(M.client)
M.client.images |= img
/*
Hides the alternate_appearance
hideFrom - optional list of MOBS to hide it from the list's mobs specifically
*/
/datum/alternate_appearance/proc/hide(list/hideFrom)
var/list/hiding = viewers
if(hideFrom)
hiding = hideFrom
for(var/m in hiding)
var/mob/M = m
if(M.client)
M.client.images -= img
if(M.viewing_alternate_appearances && M.viewing_alternate_appearances.len)
M.viewing_alternate_appearances -= key
if(!M.viewing_alternate_appearances.len)
M.viewing_alternate_appearances = null
viewers -= M
/*
Removes the alternate_appearance from its owner's alternate_appearances list, hiding it also
*/
/datum/alternate_appearance/proc/remove()
hide()
if(owner && owner.alternate_appearances)
owner.alternate_appearances -= key
if(!owner.alternate_appearances.len)
owner.alternate_appearances = null
/datum/alternate_appearance/Destroy()
remove()
return ..()
/atom
var/list/alternate_appearances //the alternate appearances we own
var/list/viewing_alternate_appearances //the alternate appearances we're viewing, stored here to reestablish them after Logout()s
//these lists are built/destroyed as necessary, so atoms aren't all lugging around lists full of datums
/*
Builds an alternate_appearance datum for the supplied args, optionally displaying it straight away
key - the key to the assoc list of key = /datum/alternate_appearances
img - the image file to be the "alternate appearance"
WORKS BEST IF:
* it has override = 1 set
* the image's loc is the atom that will use the appearance (otherwise... it's not exactly an alt appearance of this atom is it?)
displayTo - optional list of MOBS to display to immediately
Example:
var/image/I = image(icon = 'disguise.dmi', icon_state = "disguise", loc = src)
I.override = 1
add_alt_appearance("super_secret_disguise", I, players)
*/
/atom/proc/add_alt_appearance(key, img, list/displayTo = list())
if(!key || !img)
return
if(!alternate_appearances)
alternate_appearances = list()
var/datum/alternate_appearance/AA = new()
AA.img = img
AA.key = key
AA.owner = src
alternate_appearances[key] = AA
if(displayTo && displayTo.len)
display_alt_appearance(key, displayTo)
//////////////
// WRAPPERS //
//////////////
/*
Removes an alternate_appearance from src's alternate_appearances list
Wrapper for: alternate_appearance/remove()
key - the key to the assoc list of key = /datum/alternate_appearance
*/
/atom/proc/remove_alt_appearance(key)
if(alternate_appearances)
if(alternate_appearances[key])
var/datum/alternate_appearance/AA = alternate_appearances[key]
qdel(AA)
/*
Displays an alternate appearance from src's alternate_appearances list
Wrapper for: alternate_appearance/display_to()
key - the key to the assoc list of key = /datum/alternate_appearance
displayTo - a list of MOBS to show this appearance to
*/
/atom/proc/display_alt_appearance(key, list/displayTo)
if(!alternate_appearances || !key)
return
var/datum/alternate_appearance/AA = alternate_appearances[key]
if(!AA || !AA.img)
return
AA.display_to(displayTo)
/*
Hides an alternate appearance from src's alternate_appearances list
Wrapper for: alternate_appearance/hide()
key - the key to the assoc list of key = /datum/alternate_appearance
hideFrom - optional list of MOBS to hide it from the list's mobs specifically
*/
/atom/proc/hide_alt_appearance(key, list/hideFrom)
if(!alternate_appearances || !key)
return
var/datum/alternate_appearance/AA = alternate_appearances[key]
if(!AA)
return
AA.hide(hideFrom)
+6
View File
@@ -67,6 +67,12 @@
return 0
/atom/Destroy()
if(alternate_appearances)
for(var/aakey in alternate_appearances)
var/datum/alternate_appearance/AA = alternate_appearances[aakey]
qdel(AA)
alternate_appearances = null
if(reagents)
qdel(reagents)
reagents = null
-8
View File
@@ -89,14 +89,6 @@
item_state = "greenbandana"
flags_inv = 0
/obj/item/clothing/head/cardborg
name = "cardborg helmet"
desc = "A helmet made out of a box."
icon_state = "cardborg_h"
item_state = "cardborg_h"
flags = HEADCOVERSEYES | HEADCOVERSMOUTH
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE
/obj/item/clothing/head/justice
name = "justice hat"
desc = "Fight for what's righteous!"
+22 -2
View File
@@ -5,7 +5,7 @@
* Ushanka
* Pumpkin head
* Kitty ears
*
* Cardborg Disguise
*/
/*
@@ -207,4 +207,24 @@
var/icon/earbit = new/icon("icon" = 'icons/mob/head.dmi', "icon_state" = "mouseyinner")
mob.Blend(earbit, ICON_OVERLAY)
icon_override = mob
icon_override = mob
/obj/item/clothing/head/cardborg
name = "cardborg helmet"
desc = "A helmet made out of a box."
icon_state = "cardborg_h"
item_state = "cardborg_h"
flags = HEADCOVERSEYES | HEADCOVERSMOUTH
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE
/obj/item/clothing/head/cardborg/equipped(mob/living/user, slot)
..()
if(ishuman(user) && slot == slot_head)
var/mob/living/carbon/human/H = user
if(istype(H.wear_suit, /obj/item/clothing/suit/cardborg))
var/obj/item/clothing/suit/cardborg/CB = H.wear_suit
CB.disguise(user, src)
/obj/item/clothing/head/cardborg/dropped(mob/living/user)
..()
user.remove_alt_appearance("standard_borg_disguise")
@@ -199,6 +199,26 @@
body_parts_covered = UPPER_TORSO|LOWER_TORSO
flags_inv = HIDEJUMPSUIT
/obj/item/clothing/suit/cardborg/equipped(mob/living/user, slot)
..()
if(slot == slot_wear_suit)
disguise(user)
/obj/item/clothing/suit/cardborg/dropped(mob/living/user)
..()
user.remove_alt_appearance("standard_borg_disguise")
/obj/item/clothing/suit/cardborg/proc/disguise(mob/living/carbon/human/H, obj/item/clothing/head/cardborg/borghead)
if(istype(H))
if(!borghead)
borghead = H.head
if(istype(borghead, /obj/item/clothing/head/cardborg)) //why is this done this way? because equipped() is called BEFORE THE ITEM IS IN THE SLOT WHYYYY
var/image/I = image(icon = 'icons/mob/robots.dmi' , icon_state = "robot", loc = H)
I.override = 1
I.overlays += image(icon = 'icons/mob/robots.dmi' , icon_state = "eyes-robot") //gotta look realistic
H.add_alt_appearance("standard_borg_disguise", I, silicon_mob_list+H) //you look like a robot to robots! (including yourself because you're totally a robot)
/obj/item/clothing/suit/poncho
name = "poncho"
desc = "Your classic, non-racist poncho."
+6
View File
@@ -70,6 +70,12 @@
//readd this mob's HUDs (antag, med, etc)
reload_huds()
if(viewing_alternate_appearances && viewing_alternate_appearances.len)
for(var/aakey in viewing_alternate_appearances)
var/datum/alternate_appearance/AA = viewing_alternate_appearances[aakey]
if(AA)
AA.display_to(list(src))
CallHook("Login", list("client" = src.client, "mob" = src))
// Calling update_interface() in /mob/Login() causes the Cyborg to immediately be ghosted; because of winget().
+1
View File
@@ -306,6 +306,7 @@
#include "code\defines\procs\radio.dm"
#include "code\defines\procs\records.dm"
#include "code\defines\procs\statistics.dm"
#include "code\game\alternate_appearance.dm"
#include "code\game\asteroid.dm"
#include "code\game\atoms.dm"
#include "code\game\atoms_movable.dm"