From e2c869bc7732ba8e94fa20dcb26b97541d8bc794 Mon Sep 17 00:00:00 2001 From: AnturK Date: Wed, 8 Apr 2015 16:23:25 +0200 Subject: [PATCH] - Adds generic action and action buttons system --- code/_onclick/hud/_defines.dm | 33 --- code/_onclick/hud/action.dm | 238 ++++++++++++++++++ code/_onclick/hud/hud.dm | 8 +- code/_onclick/hud/human.dm | 97 ------- code/_onclick/hud/movable_screen_objects.dm | 3 +- code/_onclick/hud/screen_objects.dm | 26 -- code/datums/mind.dm | 28 +++ code/datums/spell.dm | 46 ++++ code/datums/spells/barnyard.dm | 2 + code/datums/spells/emplosion.dm | 2 + code/datums/spells/ethereal_jaunt.dm | 1 + code/datums/spells/knock.dm | 2 + code/datums/spells/lightning.dm | 2 + code/datums/spells/mime.dm | 5 + code/datums/spells/mind_transfer.dm | 2 + code/datums/spells/summonitem.dm | 2 + code/datums/spells/wizard.dm | 26 +- code/game/gamemodes/antag_spawner.dm | 16 +- code/game/gamemodes/wizard/spellbook.dm | 42 ++-- code/game/jobs/job/civilian.dm | 4 +- code/game/objects/items.dm | 5 +- code/modules/admin/admin_verbs.dm | 4 +- code/modules/events/holiday/xmas.dm | 4 +- code/modules/events/wizard/imposter.dm | 6 +- .../mob/living/carbon/human/inventory.dm | 3 - code/modules/mob/living/carbon/life.dm | 2 - code/modules/mob/living/life.dm | 72 ++++++ code/modules/mob/living/living_defines.dm | 1 + code/modules/mob/mob.dm | 13 + icons/mob/actions.dmi | Bin 0 -> 11704 bytes tgstation.dme | 1 + 31 files changed, 485 insertions(+), 211 deletions(-) create mode 100644 code/_onclick/hud/action.dm create mode 100644 icons/mob/actions.dmi 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 0000000000000000000000000000000000000000..568fbd295d64262f274c6cacf7788901edc5f2c1 GIT binary patch literal 11704 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 HS;PMiClDd7 literal 0 HcmV?d00001 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"