diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm
index 1312331ff49..1775761d6a2 100644
--- a/code/_onclick/hud/_defines.dm
+++ b/code/_onclick/hud/_defines.dm
@@ -17,38 +17,6 @@
Therefore, the top right corner (except during admin shenanigans) is at "15,15"
*/
-//Upper left action buttons, displayed when you pick up an item that has this enabled.
-#define ui_action_slot1 "WEST :0, NORTH:0"
-#define ui_action_slot2 "WEST+1 :0, NORTH:0"
-#define ui_action_slot3 "WEST+2 :0, NORTH:0"
-#define ui_action_slot4 "WEST+3 :0, NORTH:0"
-#define ui_action_slot5 "WEST+4 :0, NORTH:0"
-#define ui_action_slot6 "WEST+5 :0, NORTH:0"
-#define ui_action_slot7 "WEST+6 :0, NORTH:0"
-#define ui_action_slot8 "WEST+7 :0, NORTH:0"
-#define ui_action_slot9 "WEST+8 :0, NORTH:0"
-#define ui_action_slot10 "WEST+9 :0, NORTH:0"
-#define ui_action_slot11 "WEST+10 :0, NORTH:0"
-#define ui_action_slot12 "WEST+11 :0, NORTH:0"
-#define ui_action_slot13 "WEST+12 :0, NORTH:0"
-#define ui_action_slot14 "WEST+13 :0, NORTH:0"
-#define ui_action_slot15 "WEST+14 :0, NORTH:0"
-#define ui_action_slot16 "WEST :0, NORTH-1:0"
-#define ui_action_slot17 "WEST+1 :0, NORTH-1:0"
-#define ui_action_slot18 "WEST+2 :0, NORTH-1:0"
-#define ui_action_slot19 "WEST+3 :0, NORTH-1:0"
-#define ui_action_slot20 "WEST+4 :0, NORTH-1:0"
-#define ui_action_slot21 "WEST+5 :0, NORTH-1:0"
-#define ui_action_slot22 "WEST+6 :0, NORTH-1:0"
-#define ui_action_slot23 "WEST+7 :0, NORTH-1:0"
-#define ui_action_slot24 "WEST+8 :0, NORTH-1:0"
-#define ui_action_slot25 "WEST+9 :0, NORTH-1:0"
-#define ui_action_slot26 "WEST+10 :0, NORTH-1:0"
-#define ui_action_slot27 "WEST+11 :0, NORTH-1:0"
-#define ui_action_slot28 "WEST+12 :0, NORTH-1:0"
-#define ui_action_slot29 "WEST+13 :0, NORTH-1:0"
-#define ui_action_slot30 "WEST+14 :0, NORTH-1:0"
-
//Lower left, persistant menu
#define ui_inventory "WEST:6,SOUTH:5"
@@ -155,4 +123,3 @@
#define ui_head "WEST+1:8,SOUTH+3:11"
-
diff --git a/code/_onclick/hud/action.dm b/code/_onclick/hud/action.dm
new file mode 100644
index 00000000000..f91f9e1e266
--- /dev/null
+++ b/code/_onclick/hud/action.dm
@@ -0,0 +1,238 @@
+#define AB_ITEM 1
+#define AB_SPELL 2
+#define AB_INNATE 3
+#define AB_GENERIC 4
+
+#define AB_CHECK_RESTRAINED 1
+#define AB_CHECK_STUNNED 2
+#define AB_CHECK_LYING 4
+#define AB_CHECK_ALIVE 8
+#define AB_CHECK_INSIDE 16
+
+
+/datum/action
+ var/name = "Generic Action"
+ var/action_type = AB_ITEM
+ var/procname = null
+ var/atom/movable/target = null
+ var/check_flags = 0
+ var/processing = 0
+ var/active = 0
+ var/obj/screen/movable/action_button/button = null
+ var/button_icon = 'icons/mob/actions.dmi'
+ var/button_icon_state = "default"
+ var/background_icon_state = "bg_default"
+ var/mob/living/owner
+
+/datum/action/New(var/Target)
+ target = Target
+
+/datum/action/Destroy()
+ if(owner)
+ Remove(owner)
+
+/datum/action/proc/Grant(mob/living/T)
+ if(owner)
+ if(owner == T)
+ return
+ Remove(owner)
+ owner = T
+ owner.actions.Add(src)
+ owner.update_action_buttons()
+ return
+
+/datum/action/proc/Remove(mob/living/T)
+ if(button)
+ if(T.client)
+ T.client.screen -= button
+ del(button)
+ T.actions.Remove(src)
+ T.update_action_buttons()
+ owner = null
+ return
+
+/datum/action/proc/Trigger()
+ if(!Checks())
+ return
+ switch(action_type)
+ if(AB_ITEM)
+ if(target)
+ var/obj/item/item = target
+ item.ui_action_click()
+ if(AB_SPELL)
+ if(target)
+ var/obj/effect/proc_holder/spell = target
+ spell.Click()
+ if(AB_INNATE)
+ if(!active)
+ Activate()
+ else
+ Deactivate()
+ if(AB_GENERIC)
+ if(target && procname)
+ call(target,procname)(usr)
+ return
+
+/datum/action/proc/Activate()
+ return
+
+/datum/action/proc/Deactivate()
+ return
+
+/datum/action/proc/Process()
+ return
+
+/datum/action/proc/CheckRemoval(mob/living/user) // 1 if action is no longer valid for this mob and should be removed
+ return 0
+
+/datum/action/proc/IsAvailable()
+ return Checks()
+
+/datum/action/proc/Checks()// returns 1 if all checks pass
+ if(!owner)
+ return 0
+ if(check_flags & AB_CHECK_RESTRAINED)
+ if(owner.restrained())
+ return 0
+ if(check_flags & AB_CHECK_STUNNED)
+ if(owner.stunned)
+ return 0
+ if(check_flags & AB_CHECK_LYING)
+ if(owner.lying)
+ return 0
+ if(check_flags & AB_CHECK_ALIVE)
+ if(owner.stat)
+ return 0
+ if(check_flags & AB_CHECK_INSIDE)
+ if(!(target in owner))
+ return 0
+ return 1
+
+/datum/action/proc/UpdateName()
+ return name
+
+/obj/screen/movable/action_button
+ var/datum/action/owner
+ screen_loc = "WEST,NORTH"
+
+/obj/screen/movable/action_button/Click(location,control,params)
+ var/list/modifiers = params2list(params)
+ if(modifiers["shift"])
+ moved = 0
+ return 1
+ if(usr.next_move >= world.time) // Is this needed ?
+ return
+ owner.Trigger()
+ return 1
+
+/obj/screen/movable/action_button/proc/UpdateIcon()
+ if(!owner)
+ return
+ icon = owner.button_icon
+ icon_state = owner.background_icon_state
+
+ overlays.Cut()
+ var/image/img
+ if(owner.action_type == AB_ITEM && owner.target)
+ var/obj/item/I = owner.target
+ img = image(I.icon, src , I.icon_state)
+ else if(owner.button_icon && owner.button_icon_state)
+ img = image(owner.button_icon,src,owner.button_icon_state)
+ img.pixel_x = 0
+ img.pixel_y = 0
+ overlays += img
+
+ if(!owner.IsAvailable())
+ color = rgb(128,0,0,128)
+ else
+ color = rgb(255,255,255,255)
+
+//Hide/Show Action Buttons ... Button
+/obj/screen/movable/action_button/hide_toggle
+ name = "Hide Buttons"
+ icon = 'icons/mob/actions.dmi'
+ icon_state = "bg_default"
+ var/hidden = 0
+
+/obj/screen/movable/action_button/hide_toggle/Click()
+ usr.hud_used.action_buttons_hidden = !usr.hud_used.action_buttons_hidden
+
+ hidden = usr.hud_used.action_buttons_hidden
+ if(hidden)
+ name = "Show Buttons"
+ else
+ name = "Hide Buttons"
+ UpdateIcon()
+ usr.update_action_buttons()
+
+/obj/screen/movable/action_button/hide_toggle/UpdateIcon()
+ overlays.Cut()
+ var/image/img = image(icon,src,hidden?"show":"hide")
+ overlays += img
+ return
+
+//This is the proc used to update all the action buttons. Properly defined in /mob/living/
+/mob/proc/update_action_buttons()
+ return
+
+#define AB_WEST_OFFSET 4
+#define AB_NORTH_OFFSET 26
+#define AB_MAX_COLUMNS 10
+
+/datum/hud/proc/ButtonNumberToScreenCoords(var/number) // TODO : Make this zero-indexed for readabilty
+ var/row = round((number-1)/AB_MAX_COLUMNS)
+ var/col = ((number - 1)%(AB_MAX_COLUMNS)) + 1
+ var/coord_col = "+[col-1]"
+ var/coord_col_offset = 4+2*col
+ var/coord_row = "[-1 - row]"
+ var/coord_row_offset = 26
+ return "WEST[coord_col]:[coord_col_offset],NORTH[coord_row]:[coord_row_offset]"
+
+/datum/hud/proc/SetButtonCoords(var/obj/screen/button,var/number)
+ var/row = round((number-1)/AB_MAX_COLUMNS)
+ var/col = ((number - 1)%(AB_MAX_COLUMNS)) + 1
+ var/x_offset = 32*(col-1) + 4 + 2*col
+ var/y_offset = -32*(row+1) + 26
+
+ var/matrix/M = matrix()
+ M.Translate(x_offset,y_offset)
+ button.transform = M
+
+//Presets for item actions
+/datum/action/item_action
+ check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUNNED|AB_CHECK_LYING|AB_CHECK_ALIVE|AB_CHECK_INSIDE
+
+/datum/action/item_action/CheckRemoval(mob/living/user)
+ return !(target in user)
+
+/datum/action/item_action/hands_free
+ check_flags = AB_CHECK_ALIVE|AB_CHECK_INSIDE
+
+
+//Preset for spells
+/datum/action/spell_action
+ action_type = AB_SPELL
+ check_flags = 0
+ background_icon_state = "bg_spell"
+
+/datum/action/spell_action/UpdateName()
+ var/obj/effect/proc_holder/spell/spell = target
+ return spell.name
+
+/datum/action/spell_action/IsAvailable()
+ if(!target)
+ return 0
+ var/obj/effect/proc_holder/spell/spell = target
+
+ if(usr)
+ return spell.can_cast(usr)
+ else
+ if(owner)
+ return spell.can_cast(owner)
+ return 1
+
+/datum/action/spell_action/CheckRemoval()
+ if(owner.mind)
+ if(target in owner.mind.spell_list)
+ return 0
+ return !(target in owner.mob_spell_list)
\ No newline at end of file
diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm
index c84ae5a071c..c896fb76999 100644
--- a/code/_onclick/hud/hud.dm
+++ b/code/_onclick/hud/hud.dm
@@ -110,8 +110,8 @@ var/datum/global_hud/global_hud = new()
var/list/other
var/list/obj/screen/hotkeybuttons
- var/list/obj/screen/item_action/item_action_list = list() //Used for the item action ui buttons.
-
+ var/obj/screen/movable/action_button/hide_toggle/hide_actions_toggle
+ var/action_buttons_hidden = 0
datum/hud/New(mob/owner)
mymob = owner
@@ -243,8 +243,6 @@ datum/hud/New(mob/owner)
mymob.client.screen -= other
if(hotkeybuttons)
mymob.client.screen -= hotkeybuttons
- if(item_action_list)
- mymob.client.screen -= item_action_list
//These ones are not a part of 'adding', 'other' or 'hotkeybuttons' but we want them gone.
mymob.client.screen -= mymob.zone_sel //zone_sel is a mob variable for some reason.
@@ -269,8 +267,6 @@ datum/hud/New(mob/owner)
mymob.client.screen -= other
if(hotkeybuttons)
mymob.client.screen -= hotkeybuttons
- if(item_action_list)
- mymob.client.screen -= item_action_list
//These ones are not a part of 'adding', 'other' or 'hotkeybuttons' but we want them gone.
mymob.client.screen -= mymob.zone_sel //zone_sel is a mob variable for some reason.
diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm
index 774c6f24900..64e8cdc77e9 100644
--- a/code/_onclick/hud/human.dm
+++ b/code/_onclick/hud/human.dm
@@ -323,100 +323,3 @@
else
client.screen -= hud_used.hotkeybuttons
hud_used.hotkey_ui_hidden = 1
-
-
-/mob/living/carbon/human/update_action_buttons()
- var/num = 1
- if(!hud_used) return
- if(!client) return
-
- if(hud_used.hud_shown != 1) //Hud toggled to minimal
- return
-
- client.screen -= hud_used.item_action_list
-
- for(var/obj/item/I in src)
- if(I.action_button_name)
- if(hud_used.item_action_list.len < num)
- var/obj/screen/item_action/N = new(hud_used)
- hud_used.item_action_list += N
-
- var/obj/screen/item_action/A = hud_used.item_action_list[num]
-
- A.icon = ui_style2icon(client.prefs.UI_style)
- A.icon_state = "template"
-
- A.overlays = list()
- var/image/img = image(I.icon, A, I.icon_state)
- img.pixel_x = 0
- img.pixel_y = 0
- A.overlays += img
-
- A.name = I.action_button_name
- A.owner = I
-
- client.screen += hud_used.item_action_list[num]
-
- switch(num)
- if(1)
- A.screen_loc = ui_action_slot1
- if(2)
- A.screen_loc = ui_action_slot2
- if(3)
- A.screen_loc = ui_action_slot3
- if(4)
- A.screen_loc = ui_action_slot4
- if(5)
- A.screen_loc = ui_action_slot5
- if(6)
- A.screen_loc = ui_action_slot6
- if(7)
- A.screen_loc = ui_action_slot7
- if(8)
- A.screen_loc = ui_action_slot8
- if(9)
- A.screen_loc = ui_action_slot9
- if(10)
- A.screen_loc = ui_action_slot10
- if(11)
- A.screen_loc = ui_action_slot11
- if(12)
- A.screen_loc = ui_action_slot12
- if(13)
- A.screen_loc = ui_action_slot13
- if(14)
- A.screen_loc = ui_action_slot14
- if(15)
- A.screen_loc = ui_action_slot15
- if(16)
- A.screen_loc = ui_action_slot16
- if(17)
- A.screen_loc = ui_action_slot17
- if(18)
- A.screen_loc = ui_action_slot18
- if(19)
- A.screen_loc = ui_action_slot19
- if(20)
- A.screen_loc = ui_action_slot20
- if(21)
- A.screen_loc = ui_action_slot21
- if(22)
- A.screen_loc = ui_action_slot22
- if(23)
- A.screen_loc = ui_action_slot23
- if(24)
- A.screen_loc = ui_action_slot24
- if(25)
- A.screen_loc = ui_action_slot25
- if(26)
- A.screen_loc = ui_action_slot26
- if(27)
- A.screen_loc = ui_action_slot27
- if(28)
- A.screen_loc = ui_action_slot28
- if(29)
- A.screen_loc = ui_action_slot29
- if(30)
- A.screen_loc = ui_action_slot30
- break //30 slots available, so no more can be added.
- num++
diff --git a/code/_onclick/hud/movable_screen_objects.dm b/code/_onclick/hud/movable_screen_objects.dm
index 8e0455db14d..a0dc4827ba9 100644
--- a/code/_onclick/hud/movable_screen_objects.dm
+++ b/code/_onclick/hud/movable_screen_objects.dm
@@ -10,7 +10,7 @@
/obj/screen/movable
var/snap2grid = FALSE
-
+ var/moved = FALSE
//Snap Screen Object
//Tied to the grid, snaps to the nearest turf
@@ -43,6 +43,7 @@
var/pix_Y = text2num(screen_loc_Y[2]) - 16
screen_loc = "[screen_loc_X[1]]:[pix_X],[screen_loc_Y[1]]:[pix_Y]"
+ moved = TRUE
//Debug procs
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index 69d9dfe534a..e15c104de11 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -42,32 +42,6 @@
return 1
-/obj/screen/item_action
- var/obj/item/owner
-
-/obj/screen/item_action/Click()
- if(!usr || !owner)
- return 1
- if(usr.next_move >= world.time)
- return
-
- if(!owner.action_button_is_hands_free && (usr.restrained() || usr.stunned || usr.lying))
- return 1
-
- if(usr.stat)
- return 1
-
- if(!(owner in usr))
- return 1
-
- owner.ui_action_click()
- return 1
-
-//This is the proc used to update all the action buttons. It just returns for all mob types except humans.
-/mob/proc/update_action_buttons()
- return
-
-
/obj/screen/drop
name = "drop"
icon = 'icons/mob/screen_midnight.dmi'
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index dbdcb3afadb..0583bb6e072 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -80,6 +80,8 @@
current = new_character //associate ourself with our new body
new_character.mind = src //and associate our new body with ourself
transfer_antag_huds(new_character) //inherit the antag HUDs from this mind (TODO: move this to a possible antag datum)
+ if(spell_list.len > 0)
+ transfer_mindbound_actions(new_character)
if(active)
new_character.key = key //now transfer the key to link the client to our new body
@@ -1310,6 +1312,32 @@
ticker.mode.greet_gang(src)
ticker.mode.equip_gang(current)
+
+
+/datum/mind/proc/AddSpell(var/obj/effect/proc_holder/spell/spell)
+ spell_list += spell
+ if(!spell.action)
+ spell.action = new/datum/action/spell_action
+ spell.action.target = spell
+ spell.action.name = spell.name
+ spell.action.button_icon = spell.action_icon
+ spell.action.button_icon_state = spell.action_icon_state
+ spell.action.background_icon_state = spell.action_background_icon_state
+ spell.action.Grant(current)
+ return
+
+/datum/mind/proc/transfer_mindbound_actions(var/mob/living/new_character)
+ for(var/obj/effect/proc_holder/spell/spell in spell_list)
+ if(!spell.action) // Unlikely but whatever
+ spell.action = new/datum/action/spell_action
+ spell.action.target = spell
+ spell.action.name = spell.name
+ spell.action.button_icon = spell.action_icon
+ spell.action.button_icon_state = spell.action_icon_state
+ spell.action.background_icon_state = spell.action_background_icon_state
+ spell.action.Grant(new_character)
+ return
+
/mob/proc/sync_mind()
mind_initialize() //updates the mind (or creates and initializes one if one doesn't exist)
mind.active = 1 //indicates that the mind is currently synced with a client
diff --git a/code/datums/spell.dm b/code/datums/spell.dm
index 587d5f1c646..b6978142e01 100644
--- a/code/datums/spell.dm
+++ b/code/datums/spell.dm
@@ -53,6 +53,11 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin
var/critfailchance = 0
var/centcom_cancast = 1 //Whether or not the spell should be allowed on z2
+ var/datum/action/spell_action/action = null
+ var/action_icon = 'icons/mob/actions.dmi'
+ var/action_icon_state = "spell_default"
+ var/action_background_icon_state = "bg_spell"
+
/obj/effect/proc_holder/spell/proc/cast_check(skipcharge = 0,mob/user = usr) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell
if(((!user.mind) || !(src in user.mind.spell_list)) && !(src in user.mob_spell_list))
@@ -347,4 +352,45 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin
qdel(dummy)
return 0
qdel(dummy)
+ return 1
+
+/obj/effect/proc_holder/spell/proc/can_cast(mob/user = usr)
+ if(((!user.mind) || !(src in user.mind.spell_list)) && !(src in user.mob_spell_list))
+ return 0
+
+ if(user.z == ZLEVEL_CENTCOM && !centcom_cancast) //Certain spells are not allowed on the centcom zlevel
+ return 0
+ if(user.z == ZLEVEL_CENTCOM && ticker.mode.name == "ragin' mages")
+ return 0
+
+ switch(charge_type)
+ if("recharge")
+ if(charge_counter < charge_max)
+ return 0
+ if("charges")
+ if(!charge_counter)
+ return 0
+
+ if(user.stat && !stat_allowed)
+ return 0
+
+ if(ishuman(user))
+
+ var/mob/living/carbon/human/H = user
+
+ if((invocation_type == "whisper" || invocation_type == "shout") && H.is_muzzled())
+ return 0
+
+ if(clothes_req) //clothes check
+ if(!istype(H.wear_suit, /obj/item/clothing/suit/wizrobe) && !istype(H.wear_suit, /obj/item/clothing/suit/space/hardsuit/wizard))
+ return 0
+ if(!istype(H.shoes, /obj/item/clothing/shoes/sandal))
+ return 0
+ if(!istype(H.head, /obj/item/clothing/head/wizard) && !istype(H.head, /obj/item/clothing/head/helmet/space/hardsuit/wizard))
+ return 0
+ else
+ if(clothes_req || human_req)
+ return 0
+ if(nonabstract_req && (isbrain(user) || ispAI(user)))
+ return 0
return 1
\ No newline at end of file
diff --git a/code/datums/spells/barnyard.dm b/code/datums/spells/barnyard.dm
index 7b62eb90a81..5b81f684b44 100644
--- a/code/datums/spells/barnyard.dm
+++ b/code/datums/spells/barnyard.dm
@@ -14,6 +14,8 @@
selection_type = "range"
var/list/compatible_mobs = list(/mob/living/carbon/human,/mob/living/carbon/monkey)
+ action_icon_state = "barn"
+
/obj/effect/proc_holder/spell/targeted/barnyardcurse/cast(list/targets, mob/user = usr)
if(!targets.len)
user << "No target found in range."
diff --git a/code/datums/spells/emplosion.dm b/code/datums/spells/emplosion.dm
index 33ad284421c..e27814a6fde 100644
--- a/code/datums/spells/emplosion.dm
+++ b/code/datums/spells/emplosion.dm
@@ -5,6 +5,8 @@
var/emp_heavy = 2
var/emp_light = 3
+ action_icon_state = "emp"
+
/obj/effect/proc_holder/spell/targeted/emplosion/cast(list/targets)
for(var/mob/living/target in targets)
diff --git a/code/datums/spells/ethereal_jaunt.dm b/code/datums/spells/ethereal_jaunt.dm
index dc098de63f3..da2b438ebbb 100644
--- a/code/datums/spells/ethereal_jaunt.dm
+++ b/code/datums/spells/ethereal_jaunt.dm
@@ -13,6 +13,7 @@
centcom_cancast = 0 //Prevent people from getting to centcom
nonabstract_req = 1
var/jaunt_duration = 50 //in deciseconds
+ action_icon_state = "jaunt"
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/cast(list/targets) //magnets, so mostly hardcoded
for(var/mob/living/target in targets)
diff --git a/code/datums/spells/knock.dm b/code/datums/spells/knock.dm
index b96c96455a8..85bcaa0c6da 100644
--- a/code/datums/spells/knock.dm
+++ b/code/datums/spells/knock.dm
@@ -10,6 +10,8 @@
range = 3
cooldown_min = 20 //20 deciseconds reduction per rank
+ action_icon_state = "knock"
+
/obj/effect/proc_holder/spell/aoe_turf/knock/cast(list/targets)
for(var/turf/T in targets)
for(var/obj/machinery/door/door in T.contents)
diff --git a/code/datums/spells/lightning.dm b/code/datums/spells/lightning.dm
index b3e813c7e0e..38249722221 100644
--- a/code/datums/spells/lightning.dm
+++ b/code/datums/spells/lightning.dm
@@ -14,6 +14,8 @@
var/ready = 0
var/image/halo = null
+ action_icon_state = "lightning"
+
/obj/effect/proc_holder/spell/targeted/lightning/Click()
if(!ready)
if(cast_check())
diff --git a/code/datums/spells/mime.dm b/code/datums/spells/mime.dm
index 12c4a8e837b..122c89c8c74 100644
--- a/code/datums/spells/mime.dm
+++ b/code/datums/spells/mime.dm
@@ -12,6 +12,8 @@
range = 0
cast_sound = null
+ action_icon_state = "mime"
+ action_background_icon_state = "bg_mime"
/obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall/Click()
if(usr && usr.mind)
@@ -35,6 +37,9 @@
range = -1
include_user = 1
+ action_icon_state = "mime"
+ action_background_icon_state = "bg_mime"
+
/obj/effect/proc_holder/spell/targeted/mime/speak/Click()
if(!usr)
return
diff --git a/code/datums/spells/mind_transfer.dm b/code/datums/spells/mind_transfer.dm
index 0c8032c9b7e..710d98ba015 100644
--- a/code/datums/spells/mind_transfer.dm
+++ b/code/datums/spells/mind_transfer.dm
@@ -13,6 +13,8 @@
var/paralysis_amount_caster = 20 //how much the caster is paralysed for after the spell
var/paralysis_amount_victim = 20 //how much the victim is paralysed for after the spell
+ action_icon_state = "mindswap"
+
/*
Urist: I don't feel like figuring out how you store object spells so I'm leaving this for you to do.
Make sure spells that are removed from spell_list are actually removed and deleted when mind transfering.
diff --git a/code/datums/spells/summonitem.dm b/code/datums/spells/summonitem.dm
index 70becd17a9f..bdd35c2dd01 100644
--- a/code/datums/spells/summonitem.dm
+++ b/code/datums/spells/summonitem.dm
@@ -13,6 +13,8 @@
var/obj/marked_item
+ action_icon_state = "summons"
+
/obj/effect/proc_holder/spell/targeted/summonitem/cast(list/targets)
for(var/mob/living/user in targets)
var/list/hand_items = list(user.get_active_hand(),user.get_inactive_hand())
diff --git a/code/datums/spells/wizard.dm b/code/datums/spells/wizard.dm
index a0b201d9dd7..14ba4bad123 100644
--- a/code/datums/spells/wizard.dm
+++ b/code/datums/spells/wizard.dm
@@ -24,6 +24,8 @@
proj_trail_lifespan = 5
proj_trail_icon_state = "magicmd"
+ action_icon_state = "magicm"
+
/obj/effect/proc_holder/spell/targeted/inflict_handler/magic_missile
amt_weakened = 3
amt_dam_fire = 10
@@ -46,6 +48,8 @@
duration = 300
cooldown_min = 300 //25 deciseconds reduction per rank
+ action_icon_state = "mutate"
+
/obj/effect/proc_holder/spell/targeted/inflict_handler/disintegrate
name = "Disintegrate"
desc = "This spell instantly kills somebody adjacent to you with the vilest of magick."
@@ -63,6 +67,8 @@
sparks_spread = 1
sparks_amt = 4
+ action_icon_state = "gib"
+
/obj/effect/proc_holder/spell/targeted/smoke
name = "Smoke"
desc = "This spell spawns a cloud of choking smoke at your location and does not require wizard garb."
@@ -79,6 +85,8 @@
smoke_spread = 2
smoke_amt = 10
+ action_icon_state = "smoke"
+
/obj/effect/proc_holder/spell/targeted/emplosion/disable_tech
name = "Disable Tech"
desc = "This spell disables all weapons, cameras and most other technology in range."
@@ -115,6 +123,8 @@
centcom_cancast = 0 //prevent people from getting to centcom
+ action_icon_state = "blink"
+
/obj/effect/proc_holder/spell/targeted/area_teleport/teleport
name = "Teleport"
desc = "This spell teleports you to a type of area of your selection."
@@ -146,6 +156,8 @@
summon_type = list("/obj/effect/forcefield")
summon_lifespan = 300
+ action_icon_state = "shield"
+
/obj/effect/proc_holder/spell/aoe_turf/conjure/carp
name = "Summon Carp"
@@ -174,6 +186,8 @@
summon_type = list(/obj/structure/constructshell)
+ action_icon_state = "artificer"
+
/obj/effect/proc_holder/spell/aoe_turf/conjure/creature
name = "Summon Creature Swarm"
@@ -203,6 +217,8 @@
starting_spells = list("/obj/effect/proc_holder/spell/targeted/inflict_handler/blind","/obj/effect/proc_holder/spell/targeted/genetic/blind")
+ action_icon_state = "blind"
+
/obj/effect/proc_holder/spell/targeted/inflict_handler/blind
amt_eye_blind = 10
amt_eye_blurry = 20
@@ -226,6 +242,8 @@
summon_type = "/obj/structure/closet/statue"
+ action_icon_state = "statue"
+
/obj/effect/proc_holder/spell/dumbfire/fireball
name = "Fireball"
desc = "This spell fires a fireball at a target and does not require wizard garb."
@@ -245,6 +263,8 @@
proj_lifespan = 200
proj_step_delay = 1
+ action_icon_state = "fireball"
+
/obj/effect/proc_holder/spell/turf/fireball/cast(var/turf/T)
explosion(T, -1, 0, 2, 3, 0, flame_range = 2)
@@ -271,6 +291,8 @@
selection_type = "view"
var/maxthrow = 5
+ action_icon_state = "repulse"
+
/obj/effect/proc_holder/spell/aoe_turf/repulse/cast(list/targets)
var/mob/user = usr
var/list/thrownatoms = list()
@@ -279,10 +301,10 @@
for(var/turf/T in targets) //Done this way so things don't get thrown all around hilariously.
for(var/atom/movable/AM in T)
thrownatoms += AM
-
+
for(var/atom/movable/AM in thrownatoms)
if(AM == user || AM.anchored) continue
-
+
var/obj/effect/overlay/targeteffect = new /obj/effect/overlay{icon='icons/effects/effects.dmi'; icon_state="shieldsparkles"; mouse_opacity=0; density = 0}()
AM.overlays += targeteffect
throwtarget = get_edge_target_turf(user, get_dir(user, get_step_away(AM, user)))
diff --git a/code/game/gamemodes/antag_spawner.dm b/code/game/gamemodes/antag_spawner.dm
index 7be421ee470..549243bf86c 100644
--- a/code/game/gamemodes/antag_spawner.dm
+++ b/code/game/gamemodes/antag_spawner.dm
@@ -71,21 +71,21 @@
M << "You are the [usr.real_name]'s apprentice! You are bound by magic contract to follow their orders and help them in accomplishing their goals."
switch(type)
if("destruction")
- M.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/projectile/magic_missile(null)
- M.mind.spell_list += new /obj/effect/proc_holder/spell/dumbfire/fireball(null)
+ M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/projectile/magic_missile(null))
+ M.mind.AddSpell(new /obj/effect/proc_holder/spell/dumbfire/fireball(null))
M << "Your service has not gone unrewarded, however. Studying under [usr.real_name], you have learned powerful, destructive spells. You are able to cast magic missile and fireball."
if("bluespace")
- M.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/area_teleport/teleport(null)
- M.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt(null)
+ M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/area_teleport/teleport(null))
+ M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt(null))
M << "Your service has not gone unrewarded, however. Studying under [usr.real_name], you have learned reality bending mobility spells. You are able to cast teleport and ethereal jaunt."
if("healing")
- M.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/charge(null)
- M.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/conjure/forcewall(null)
+ M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/charge(null))
+ M.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/forcewall(null))
M.equip_to_slot_or_del(new /obj/item/weapon/gun/magic/staff/healing(M), slot_r_hand)
M << "Your service has not gone unrewarded, however. Studying under [usr.real_name], you have learned livesaving survival spells. You are able to cast charge and forcewall."
if("robeless")
- M.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/knock(null)
- M.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/mind_transfer(null)
+ M.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/knock(null))
+ M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mind_transfer(null))
M << "Your service has not gone unrewarded, however. Studying under [usr.real_name], you have learned stealthy, robeless spells. You are able to cast knock and mindswap."
equip_antag(M)
diff --git a/code/game/gamemodes/wizard/spellbook.dm b/code/game/gamemodes/wizard/spellbook.dm
index 7df187b1aa6..138a77305c1 100644
--- a/code/game/gamemodes/wizard/spellbook.dm
+++ b/code/game/gamemodes/wizard/spellbook.dm
@@ -100,7 +100,7 @@
dat += "Knock (10)
"
dat += "This spell opens nearby doors and does not require wizard garb.
"
- dat += "Curse of the Barnyward (15)
"
+ dat += "Curse of the Barnyward (15)
"
dat += " This Spell dooms any unlucky soul to the life of a barnyard animal. Well not exactly but you still get to laugh at them when they MOO!. It does not require a wizard garb.
"
dat += "Flesh to Stone (60)
"
@@ -259,71 +259,71 @@
switch(href_list["spell_choice"])
if("magicmissile")
feedback_add_details("wizard_spell_learned","MM") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
- H.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/projectile/magic_missile(null)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/projectile/magic_missile(null))
temp = "You have learned magic missile."
if("fireball")
feedback_add_details("wizard_spell_learned","FB") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
- H.mind.spell_list += new /obj/effect/proc_holder/spell/dumbfire/fireball(null)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/dumbfire/fireball(null))
temp = "You have learned fireball."
if("disintegrate")
feedback_add_details("wizard_spell_learned","DG") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
- H.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/inflict_handler/disintegrate(null)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/inflict_handler/disintegrate(null))
temp = "You have learned disintegrate."
if("disabletech")
feedback_add_details("wizard_spell_learned","DT") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
- H.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/emplosion/disable_tech(null)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/emplosion/disable_tech(null))
temp = "You have learned disable technology."
if("repulse")
feedback_add_details("wizard_spell_learned","RP") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
- H.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/repulse(null)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/repulse(null))
temp = "You have learned repulse."
if("smoke")
feedback_add_details("wizard_spell_learned","SM") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
- H.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/smoke(null)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/smoke(null))
temp = "You have learned smoke."
if("blind")
feedback_add_details("wizard_spell_learned","BD") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
- H.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/trigger/blind(null)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/trigger/blind(null))
temp = "You have learned blind."
if("mindswap")
feedback_add_details("wizard_spell_learned","MT") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
- H.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/mind_transfer(null)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mind_transfer(null))
temp = "You have learned mindswap."
if("forcewall")
feedback_add_details("wizard_spell_learned","FW") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
- H.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/conjure/forcewall(null)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/forcewall(null))
temp = "You have learned forcewall."
if("blink")
feedback_add_details("wizard_spell_learned","BL") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
- H.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/turf_teleport/blink(null)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/turf_teleport/blink(null))
temp = "You have learned blink."
if("teleport")
feedback_add_details("wizard_spell_learned","TP") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
- H.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/area_teleport/teleport(null)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/area_teleport/teleport(null))
temp = "You have learned teleport."
if("mutate")
feedback_add_details("wizard_spell_learned","MU") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
- H.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/genetic/mutate(null)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/genetic/mutate(null))
temp = "You have learned mutate."
if("etherealjaunt")
feedback_add_details("wizard_spell_learned","EJ") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
- H.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt(null)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt(null))
temp = "You have learned ethereal jaunt."
if("knock")
feedback_add_details("wizard_spell_learned","KN") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
- H.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/knock(null)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/knock(null))
temp = "You have learned knock."
if("fleshtostone")
feedback_add_details("wizard_spell_learned","FS") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
- H.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/inflict_handler/flesh_to_stone(null)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/inflict_handler/flesh_to_stone(null))
temp = "You have learned flesh to stone."
if("summonitem")
feedback_add_details("wizard_spell_learned","IS") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
- H.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/summonitem(null)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/summonitem(null))
temp = "You have learned instant summons."
if("lightningbolt")
feedback_add_details("wizard_spell_learned","LB") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
- H.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/lightning(null)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/lightning(null))
temp = "You have learned lightning bolt."
if("summonguns")
feedback_add_details("wizard_spell_learned","SG") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
@@ -352,7 +352,7 @@
if("soulstone")
feedback_add_details("wizard_spell_learned","SS") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
new /obj/item/weapon/storage/belt/soulstone/full(get_turf(H))
- H.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/conjure/construct(null)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/construct(null))
temp = "You have purchased a belt full of soulstones and have learned the artificer spell."
max_uses--
if("necrostone")
@@ -384,7 +384,7 @@
max_uses--
if("barnyard")
feedback_add_details("wizard_spell_learned","BC") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
- H.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/barnyardcurse(null)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/barnyardcurse(null))
temp = "You have learned the curse of the barnyard."
if("wands")
feedback_add_details("wizard_spell_learned","WA") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
@@ -439,7 +439,7 @@
if(used)
recoil(user)
else
- user.mind.spell_list += S
+ user.mind.AddSpell(S)
user <<"you rapidly read through the arcane book. Suddenly you realize you understand [spellname]!"
user.attack_log += text("\[[time_stamp()]\] [user.real_name] ([user.ckey]) learned the spell [spellname] ([S]).")
onlearned(user)
diff --git a/code/game/jobs/job/civilian.dm b/code/game/jobs/job/civilian.dm
index cd2e564b41b..90700b72776 100644
--- a/code/game/jobs/job/civilian.dm
+++ b/code/game/jobs/job/civilian.dm
@@ -78,8 +78,8 @@ Mime
H.equip_to_slot_or_del(new /obj/item/clothing/suit/suspenders(H), slot_wear_suit)
if(H.mind)
- H.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall(null)
- H.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/mime/speak(null)
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall(null))
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mime/speak(null))
H.mind.miming = 1
H.rename_self("mime")
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 20706d966fb..7260637b1ab 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -24,6 +24,7 @@
//If this is set, The item will make an action button on the player's HUD when picked up.
var/action_button_name //It is also the text which gets displayed on the action button. If not set it defaults to 'Use [name]'. If it's not set, there'll be no button.
var/action_button_is_hands_free = 0 //If 1, bypass the restrained, lying, and stunned checks action buttons normally test for
+ var/datum/action/item_action/action = null
//Since any item can now be a piece of clothing, this has to be put here so all items share it.
var/flags_inv //This flag is used to determine when items in someone's inventory cover others. IE helmets making it so you can't see glasses, etc.
@@ -307,9 +308,7 @@
//The default action is attack_self().
//Checks before we get to here are: mob is alive, mob is not restrained, paralyzed, asleep, resting, laying, item is on the mob.
/obj/item/proc/ui_action_click()
- if(src in usr)
- attack_self(usr)
-
+ attack_self(usr)
/obj/item/proc/IsShield()
return 0
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 956e2d99bc7..106becf41c8 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -441,9 +441,9 @@ var/list/admin_verbs_hideable = list(
message_admins("[key_name_admin(usr)] gave [key_name(T)] the spell [S].")
if(T.mind)
- T.mind.spell_list += new S
+ T.mind.AddSpell(new S)
else
- T.mob_spell_list += new S
+ T.AddSpell(new S)
message_admins("Spells given to mindless mobs will not be transferred in mindswap or cloning!")
diff --git a/code/modules/events/holiday/xmas.dm b/code/modules/events/holiday/xmas.dm
index eacc8eacaba..3f40addebdf 100644
--- a/code/modules/events/holiday/xmas.dm
+++ b/code/modules/events/holiday/xmas.dm
@@ -143,9 +143,9 @@
santa_objective.completed = 1 //lets cut our santas some slack.
santa_objective.owner = santa.mind
santa.mind.objectives += santa_objective
- santa.mind.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/conjure/presents
+ santa.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/presents)
var/obj/effect/proc_holder/spell/targeted/area_teleport/teleport/telespell = new(santa)
telespell.clothes_req = 0 //santa robes aren't actually magical.
- santa.mind.spell_list += telespell //does the station have chimneys? WHO KNOWS!
+ santa.mind.AddSpell(telespell) //does the station have chimneys? WHO KNOWS!
santa << "You are Santa! Your objective is to bring joy to the people on this station. You can conjure more presents using a spell, and there are several presents in your bag."
diff --git a/code/modules/events/wizard/imposter.dm b/code/modules/events/wizard/imposter.dm
index e3b4c5d1fb6..5d3567a9d47 100644
--- a/code/modules/events/wizard/imposter.dm
+++ b/code/modules/events/wizard/imposter.dm
@@ -33,9 +33,9 @@
I.key = C.key
//Operation: Fuck off and scare people
- I.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/area_teleport/teleport(null)
- I.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/turf_teleport/blink(null)
- I.mind.spell_list += new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt(null)
+ I.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/area_teleport/teleport(null))
+ I.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/turf_teleport/blink(null))
+ I.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt(null))
ticker.mode.traitors += I.mind
I.mind.special_role = "imposter"
diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm
index c1e89721f8a..2bec9a1583b 100644
--- a/code/modules/mob/living/carbon/human/inventory.dm
+++ b/code/modules/mob/living/carbon/human/inventory.dm
@@ -301,9 +301,6 @@
s_store = null
update_inv_s_store(0)
- update_action_buttons()
-
-
//This is an UNSAFE proc. Use mob_can_equip() before calling this one! Or rather use equip_to_slot_if_possible() or advanced_equip_to_slot_if_possible()
//set redraw_mob to 0 if you don't wish the hud to be updated - if you're doing it manually in your own proc.
/mob/living/carbon/human/equip_to_slot(obj/item/I, slot, redraw_mob = 1)
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index daebf276b12..76df2c205e8 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -375,8 +375,6 @@
/mob/living/carbon/handle_regular_hud_updates()
if(!client) return 0
- update_action_buttons()
-
if(damageoverlay)
if(damageoverlay.overlays)
damageoverlay.overlays = list()
diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm
index e2f440bcfb5..3e996ed1ae0 100644
--- a/code/modules/mob/living/life.dm
+++ b/code/modules/mob/living/life.dm
@@ -47,6 +47,8 @@
handle_disabilities() // eye, ear, brain damages
handle_status_effects() //all special effects, stunned, weakened, jitteryness, hallucination, sleeping, etc
+ handle_actions()
+
update_canmove()
if(client)
@@ -131,6 +133,22 @@
if(ear_damage < 100)
adjustEarDamage(-0.05,-1)
+/mob/living/proc/handle_actions()
+ //Pretty bad, i'd use picked/dropped instead but the parent calls in these are nonexistent
+ for(var/datum/action/A in actions)
+ if(A.CheckRemoval(src))
+ A.Remove(src)
+ for(var/obj/item/I in src)
+ if(I.action_button_name)
+ if(!I.action)
+ if(I.action_button_is_hands_free)
+ I.action = new/datum/action/item_action/hands_free
+ else
+ I.action = new/datum/action/item_action
+ I.action.name = I.action_button_name
+ I.action.target = I
+ I.action.Grant(src)
+ return
//this handles hud updates. Calls update_vision() and handle_hud_icons()
/mob/living/proc/handle_regular_hud_updates()
@@ -138,6 +156,7 @@
handle_vision()
handle_hud_icons()
+ update_action_buttons()
return 1
@@ -185,3 +204,56 @@
/mob/living/proc/handle_hud_icons_health()
return
+
+/mob/living/update_action_buttons()
+ if(!hud_used) return
+ if(!client) return
+
+ if(hud_used.hud_shown != 1) //Hud toggled to minimal
+ return
+
+ client.screen -= hud_used.hide_actions_toggle
+ for(var/datum/action/A in actions)
+ if(A.button)
+ client.screen -= A.button
+
+ if(hud_used.action_buttons_hidden)
+ if(!hud_used.hide_actions_toggle)
+ hud_used.hide_actions_toggle = new(hud_used)
+ hud_used.hide_actions_toggle.UpdateIcon()
+
+ if(!hud_used.hide_actions_toggle.moved)
+ hud_used.hide_actions_toggle.screen_loc = hud_used.ButtonNumberToScreenCoords(1)
+ //hud_used.SetButtonCoords(hud_used.hide_actions_toggle,1)
+
+ client.screen += hud_used.hide_actions_toggle
+ return
+
+ var/button_number = 0
+ for(var/datum/action/A in actions)
+ button_number++
+ if(A.button == null)
+ var/obj/screen/movable/action_button/N = new(hud_used)
+ N.owner = A
+ A.button = N
+
+ var/obj/screen/movable/action_button/B = A.button
+
+ B.UpdateIcon()
+
+ B.name = A.UpdateName()
+
+ client.screen += B
+
+ if(!B.moved)
+ B.screen_loc = hud_used.ButtonNumberToScreenCoords(button_number)
+ //hud_used.SetButtonCoords(B,button_number)
+
+ if(button_number > 0)
+ if(!hud_used.hide_actions_toggle)
+ hud_used.hide_actions_toggle = new(hud_used)
+ hud_used.hide_actions_toggle.UpdateIcon()
+ if(!hud_used.hide_actions_toggle.moved)
+ hud_used.hide_actions_toggle.screen_loc = hud_used.ButtonNumberToScreenCoords(button_number+1)
+ //hud_used.SetButtonCoords(hud_used.hide_actions_toggle,button_number+1)
+ client.screen += hud_used.hide_actions_toggle
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index e90a20e97d0..394626546c8 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -43,3 +43,4 @@
var/list/image/staticOverlays = list()
var/lying_pixel_offset = 0 //offset for pixel_y when the mob is lying down.
var/has_limbs = 0 //does the mob have distinct limbs?(arms,legs, chest,head)
+ var/list/datum/action/actions = list()
\ No newline at end of file
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 3a4af5d847c..a3d17f3c6fe 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -946,4 +946,17 @@ var/list/slot_equipment_priority = list( \
return
/mob/proc/setEarDamage()
+ return
+
+/mob/proc/AddSpell(var/obj/effect/proc_holder/spell/spell)
+ mob_spell_list += spell
+ if(!spell.action)
+ spell.action = new/datum/action/spell_action
+ spell.action.target = spell
+ spell.action.name = spell.name
+ spell.action.button_icon = spell.action_icon
+ spell.action.button_icon_state = spell.action_icon_state
+ spell.action.background_icon_state = spell.action_background_icon_state
+ if(isliving(src))
+ spell.action.Grant(src)
return
\ No newline at end of file
diff --git a/icons/mob/actions.dmi b/icons/mob/actions.dmi
new file mode 100644
index 00000000000..568fbd295d6
Binary files /dev/null and b/icons/mob/actions.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index bd612a48f11..4d9c6ae81c3 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -76,6 +76,7 @@
#include "code\_onclick\overmind.dm"
#include "code\_onclick\telekinesis.dm"
#include "code\_onclick\hud\_defines.dm"
+#include "code\_onclick\hud\action.dm"
#include "code\_onclick\hud\ai.dm"
#include "code\_onclick\hud\alert.dm"
#include "code\_onclick\hud\alien.dm"