diff --git a/code/datums/action.dm b/code/datums/action.dm
index ca71a7cbec..a65294fa40 100644
--- a/code/datums/action.dm
+++ b/code/datums/action.dm
@@ -485,7 +485,7 @@
/datum/action/spell_action/New(Target)
..()
- var/obj/effect/proc_holder/spell/S = target
+ var/obj/effect/proc_holder/S = target
S.action = src
name = S.name
desc = S.desc
@@ -495,36 +495,40 @@
button.name = name
/datum/action/spell_action/Destroy()
- var/obj/effect/proc_holder/spell/S = target
+ var/obj/effect/proc_holder/S = target
S.action = null
return ..()
/datum/action/spell_action/Trigger()
if(!..())
- return 0
+ return FALSE
if(target)
- var/obj/effect/proc_holder/spell = target
- spell.Click()
- return 1
+ var/obj/effect/proc_holder/S = target
+ S.Click()
+ return TRUE
/datum/action/spell_action/IsAvailable()
if(!target)
- return 0
- var/obj/effect/proc_holder/spell/spell = target
- if(owner)
- return spell.can_cast(owner)
- return 0
+ return FALSE
+ return TRUE
+/datum/action/spell_action/spell/IsAvailable()
+ if(!target)
+ return FALSE
+ var/obj/effect/proc_holder/spell/S = target
+ if(owner)
+ return S.can_cast(owner)
+ return FALSE
/datum/action/spell_action/alien
/datum/action/spell_action/alien/IsAvailable()
if(!target)
- return 0
+ return FALSE
var/obj/effect/proc_holder/alien/ab = target
if(owner)
return ab.cost_check(ab.check_turf,owner,1)
- return 0
+ return FALSE
diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm
index 7a0faed690..6722ffd89b 100644
--- a/code/game/objects/effects/spiders.dm
+++ b/code/game/objects/effects/spiders.dm
@@ -52,6 +52,7 @@
icon_state = "eggs"
var/amount_grown = 0
var/player_spiders = 0
+ var/directive = "" //Message from the mother
var/poison_type = "toxin"
var/poison_per_bite = 5
var/list/faction = list("spiders")
@@ -71,6 +72,7 @@
S.poison_type = poison_type
S.poison_per_bite = poison_per_bite
S.faction = faction.Copy()
+ S.directive = directive
if(player_spiders)
S.player_spiders = 1
qdel(src)
@@ -87,6 +89,7 @@
var/obj/machinery/atmospherics/components/unary/vent_pump/entry_vent
var/travelling_in_vent = 0
var/player_spiders = 0
+ var/directive = "" //Message from the mother
var/poison_type = "toxin"
var/poison_per_bite = 5
var/list/faction = list("spiders")
@@ -192,6 +195,7 @@
S.poison_per_bite = poison_per_bite
S.poison_type = poison_type
S.faction = faction.Copy()
+ S.directive = directive
if(player_spiders)
S.playable_spider = TRUE
notify_ghosts("Spider [S.name] can be controlled", null, enter_link="(Click to play)", source=S, action=NOTIFY_ATTACK)
diff --git a/code/modules/goonchat/browserassets/css/browserOutput.css b/code/modules/goonchat/browserassets/css/browserOutput.css
index fa2c5d056c..f6810d0b05 100644
--- a/code/modules/goonchat/browserassets/css/browserOutput.css
+++ b/code/modules/goonchat/browserassets/css/browserOutput.css
@@ -353,6 +353,8 @@ h1.alert, h2.alert {color: #000000;}
.borer {color: #543354; font-style: italic;}
.changeling {color: #800080; font-style: italic;}
+.spider {color: #4d004d;}
+
.interface {color: #330033;}
.sans {font-family: "Comic Sans MS", cursive, sans-serif;}
diff --git a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
index e6a5f58d69..1390028282 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
@@ -10,15 +10,15 @@ Doesn't work on other aliens/AI.*/
name = "Alien Power"
panel = "Alien"
var/plasma_cost = 0
- var/check_turf = 0
- var/has_action = 1
- var/datum/action/spell_action/alien/action = null
- var/action_icon = 'icons/mob/actions/actions_xeno.dmi'
- var/action_icon_state = "spell_default"
- var/action_background_icon_state = "bg_alien"
+ var/check_turf = FALSE
+ has_action = TRUE
+ datum/action/spell_action/alien/action
+ action_icon = 'icons/mob/actions/actions_xeno.dmi'
+ action_icon_state = "spell_default"
+ action_background_icon_state = "bg_alien"
-/obj/effect/proc_holder/alien/New()
- ..()
+/obj/effect/proc_holder/alien/Initialize()
+ . = ..()
action = new(src)
/obj/effect/proc_holder/alien/Click()
@@ -30,15 +30,20 @@ Doesn't work on other aliens/AI.*/
user.adjustPlasma(-plasma_cost)
return 1
-/obj/effect/proc_holder/alien/proc/on_gain(mob/living/carbon/user)
+/obj/effect/proc_holder/alien/on_gain(mob/living/carbon/user)
return
-/obj/effect/proc_holder/alien/proc/on_lose(mob/living/carbon/user)
+/obj/effect/proc_holder/alien/on_lose(mob/living/carbon/user)
return
-/obj/effect/proc_holder/alien/proc/fire(mob/living/carbon/user)
+/obj/effect/proc_holder/alien/fire(mob/living/carbon/user)
return 1
+/obj/effect/proc_holder/alien/get_panel_text()
+ . = ..()
+ if(plasma_cost > 0)
+ return "[plasma_cost]"
+
/obj/effect/proc_holder/alien/proc/cost_check(check_turf=0,mob/living/carbon/user,silent = 0)
if(user.stat)
if(!silent)
@@ -168,7 +173,6 @@ Doesn't work on other aliens/AI.*/
if(user.getPlasma() > A.plasma_cost && A.corrode(O))
user.adjustPlasma(-A.plasma_cost)
-
/obj/effect/proc_holder/alien/neurotoxin
name = "Spit Neurotoxin"
desc = "Spits neurotoxin at someone, paralyzing them for a short time."
@@ -179,7 +183,7 @@ Doesn't work on other aliens/AI.*/
var/message
if(active)
message = "You empty your neurotoxin gland."
- remove_ranged_ability(user,message)
+ remove_ranged_ability(message)
else
message = "You prepare your neurotoxin gland. Left-click to fire at a target!"
add_ranged_ability(user, message, TRUE)
@@ -193,7 +197,7 @@ Doesn't work on other aliens/AI.*/
return
var/p_cost = 50
if(!iscarbon(ranged_ability_user) || ranged_ability_user.lying || ranged_ability_user.stat)
- remove_ranged_ability(ranged_ability_user)
+ remove_ranged_ability()
return
var/mob/living/carbon/user = ranged_ability_user
@@ -219,8 +223,7 @@ Doesn't work on other aliens/AI.*/
return TRUE
/obj/effect/proc_holder/alien/neurotoxin/on_lose(mob/living/carbon/user)
- if(user.ranged_ability == src)
- user.ranged_ability = null
+ remove_ranged_ability()
/obj/effect/proc_holder/alien/neurotoxin/add_ranged_ability(mob/living/user, msg)
..()
@@ -328,7 +331,3 @@ Doesn't work on other aliens/AI.*/
return 1
return 0
-
-
-/proc/cmp_abilities_cost(obj/effect/proc_holder/alien/a, obj/effect/proc_holder/alien/b)
- return b.plasma_cost - a.plasma_cost
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index aa72ebfa9f..80c6d836a0 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -425,23 +425,6 @@
var/turf/target = get_turf(loc)
I.throw_at(target,I.throw_range,I.throw_speed,src)
-/mob/living/carbon/proc/AddAbility(obj/effect/proc_holder/alien/A)
- abilities.Add(A)
- A.on_gain(src)
- if(A.has_action)
- A.action.Grant(src)
- sortInsert(abilities, /proc/cmp_abilities_cost, 0)
-
-/mob/living/carbon/proc/RemoveAbility(obj/effect/proc_holder/alien/A)
- abilities.Remove(A)
- A.on_lose(src)
- if(A.action)
- A.action.Remove(src)
-
-/mob/living/carbon/proc/add_abilities_to_panel()
- for(var/obj/effect/proc_holder/alien/A in abilities)
- statpanel("[A.panel]",A.plasma_cost > 0?"([A.plasma_cost])":"",A)
-
/mob/living/carbon/Stat()
..()
if(statpanel("Status"))
diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm
index 8e9f66de31..45c10c6ae9 100644
--- a/code/modules/mob/living/carbon/carbon_defines.dm
+++ b/code/modules/mob/living/carbon/carbon_defines.dm
@@ -35,7 +35,6 @@
has_limbs = 1
var/obj/item/reagent_containers/food/snacks/meat/slab/type_of_meat = /obj/item/reagent_containers/food/snacks/meat/slab
- var/list/obj/effect/proc_holder/alien/abilities = list()
var/gib_type = /obj/effect/decal/cleanable/blood/gibs
var/rotate_on_lying = 1
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index b2e88e278a..47458b01d2 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -412,8 +412,9 @@
liver_failure()
else
liver.failing = FALSE
-
- if(((!(NOLIVER in dna.species.species_traits)) && (!liver)))
+ else
+ if((dna && dna.species && (NOLIVER in dna.species.species_traits)))
+ return
liver_failure()
/mob/living/carbon/proc/undergoing_liver_failure()
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 649e19ba29..1cf99e8d9e 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -982,3 +982,19 @@
client.move_delay = world.time + movement_delay()
lying_prev = lying
return canmove
+
+/mob/living/proc/AddAbility(obj/effect/proc_holder/A)
+ abilities.Add(A)
+ A.on_gain(src)
+ if(A.has_action)
+ A.action.Grant(src)
+
+/mob/living/proc/RemoveAbility(obj/effect/proc_holder/A)
+ abilities.Remove(A)
+ A.on_lose(src)
+ if(A.action)
+ A.action.Remove(src)
+
+/mob/living/proc/add_abilities_to_panel()
+ for(var/obj/effect/proc_holder/A in abilities)
+ statpanel("[A.panel]",A.get_panel_text(),A)
\ No newline at end of file
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index f32ca97b09..36b8c62cca 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -77,3 +77,5 @@
var/datum/language/selected_default_language
var/last_words //used for database logging
+
+ var/list/obj/effect/proc_holder/abilities = list()
diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
index 6ae5fe0622..75cc53e0c9 100644
--- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
+++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
@@ -49,6 +49,17 @@
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
var/playable_spider = FALSE
devourable = TRUE
+ var/datum/action/innate/spider/lay_web/lay_web
+ var/directive = "" //Message passed down to children, to relay the creator's orders
+
+/mob/living/simple_animal/hostile/poison/giant_spider/Initialize()
+ . = ..()
+ lay_web = new
+ lay_web.Grant(src)
+
+/mob/living/simple_animal/hostile/poison/giant_spider/Destroy()
+ QDEL_NULL(lay_web)
+ return ..()
/mob/living/simple_animal/hostile/poison/giant_spider/Topic(href, href_list)
if(href_list["activate"])
@@ -56,6 +67,12 @@
if(istype(ghost) && playable_spider)
humanize_spider(ghost)
+/mob/living/simple_animal/hostile/poison/giant_spider/Login()
+ ..()
+ if(directive)
+ to_chat(src, "Your mother left you a directive! Follow it at all costs.")
+ to_chat(src, "[directive]")
+
/mob/living/simple_animal/hostile/poison/giant_spider/attack_ghost(mob/user)
if(!humanize_spider(user))
return ..()
@@ -87,8 +104,26 @@
poison_per_bite = 3
var/atom/movable/cocoon_target
var/fed = 0
+ var/obj/effect/proc_holder/wrap/wrap
+ var/datum/action/innate/spider/lay_eggs/lay_eggs
+ var/datum/action/innate/spider/set_directive/set_directive
var/static/list/consumed_mobs = list() //the tags of mobs that have been consumed by nurse spiders to lay eggs
+/mob/living/simple_animal/hostile/poison/giant_spider/nurse/Initialize()
+ . = ..()
+ wrap = new
+ AddAbility(wrap)
+ lay_eggs = new
+ lay_eggs.Grant(src)
+ set_directive = new
+ set_directive.Grant(src)
+
+/mob/living/simple_animal/hostile/poison/giant_spider/nurse/Destroy()
+ RemoveAbility(wrap)
+ QDEL_NULL(lay_eggs)
+ QDEL_NULL(set_directive)
+ return ..()
+
//hunters have the most poison and move the fastest, so they can find prey
/mob/living/simple_animal/hostile/poison/giant_spider/hunter
desc = "Furry and black, it makes you shudder to look at it. This one has sparkling purple eyes."
@@ -162,6 +197,9 @@
letmetalkpls = new
letmetalkpls.Grant(src)
+/mob/living/simple_animal/hostile/poison/giant_spider/nurse/midwife/Destroy()
+ QDEL_NULL(letmetalkpls)
+ return ..()
/mob/living/simple_animal/hostile/poison/giant_spider/ice //spiders dont usually like tempatures of 140 kelvin who knew
name = "giant ice spider"
@@ -225,11 +263,11 @@
//second, spin a sticky spiderweb on this tile
var/obj/structure/spider/stickyweb/W = locate() in get_turf(src)
if(!W)
- Web()
+ lay_web.Activate()
else
//third, lay an egg cluster there
if(fed)
- LayEggs()
+ lay_eggs.Activate()
else
//fourthly, cocoon any nearby items so those pesky pinkskins can't use them
for(var/obj/O in can_see)
@@ -247,62 +285,28 @@
else if(busy == MOVING_TO_TARGET && cocoon_target)
if(get_dist(src, cocoon_target) <= 1)
- Wrap()
+ cocoon()
else
busy = SPIDER_IDLE
stop_automated_movement = FALSE
-/mob/living/simple_animal/hostile/poison/giant_spider/verb/Web()
- set name = "Lay Web"
- set category = "Spider"
- set desc = "Spread a sticky web to slow down prey."
-
- var/T = src.loc
-
- if(stat == DEAD)
- return
- if(busy != SPINNING_WEB)
- busy = SPINNING_WEB
- src.visible_message("\the [src] begins to secrete a sticky substance.")
- stop_automated_movement = 1
- if(do_after(src, 40, target = T))
- if(busy == SPINNING_WEB && src.loc == T)
- new /obj/structure/spider/stickyweb(T)
- busy = SPIDER_IDLE
- stop_automated_movement = FALSE
-
-
-/mob/living/simple_animal/hostile/poison/giant_spider/nurse/verb/Wrap()
- set name = "Wrap"
- set category = "Spider"
- set desc = "Wrap up prey to feast upon and objects for safe keeping."
-
- if(stat == DEAD)
- return
- if(!cocoon_target)
- var/list/choices = list()
- for(var/mob/living/L in view(1,src))
- if(L == src || L.anchored)
- continue
- if(istype(L, /mob/living/simple_animal/hostile/poison/giant_spider))
- continue
- if(Adjacent(L))
- choices += L
- for(var/obj/O in src.loc)
- if(O.anchored)
- continue
- if(Adjacent(O))
- choices += O
- var/temp_input = input(src,"What do you wish to cocoon?") in null|choices
- if(temp_input && !cocoon_target)
- cocoon_target = temp_input
-
- if(stat != DEAD && cocoon_target && Adjacent(cocoon_target) && !cocoon_target.anchored)
+/mob/living/simple_animal/hostile/poison/giant_spider/nurse/proc/cocoon()
+ if(stat != DEAD && cocoon_target && !cocoon_target.anchored)
+ if(cocoon_target == src)
+ to_chat(src, "You can't wrap yourself!")
+ return
+ if(istype(cocoon_target, /mob/living/simple_animal/hostile/poison/giant_spider))
+ to_chat(src, "You can't wrap other spiders!")
+ return
+ if(!Adjacent(cocoon_target))
+ to_chat(src, "You can't reach [cocoon_target]!")
+ return
if(busy == SPINNING_COCOON)
+ to_chat(src, "You're already spinning a cocoon!")
return //we're already doing this, don't cancel out or anything
busy = SPINNING_COCOON
- visible_message("\the [src] begins to secrete a sticky substance around \the [cocoon_target].")
+ visible_message("[src] begins to secrete a sticky substance around [cocoon_target].","You begin wrapping [cocoon_target] into a cocoon.")
stop_automated_movement = TRUE
walk(src,0)
if(do_after(src, 50, target = cocoon_target))
@@ -313,7 +317,8 @@
if(L.blood_volume && (L.stat != DEAD || !consumed_mobs[L.tag])) //if they're not dead, you can consume them anyway
consumed_mobs[L.tag] = TRUE
fed++
- visible_message("\the [src] sticks a proboscis into \the [L] and sucks a viscous substance out.")
+ lay_eggs.UpdateButtonIcon(TRUE)
+ visible_message("[src] sticks a proboscis into [L] and sucks a viscous substance out.","You suck the nutriment out of [L], feeding you enough to lay a cluster of eggs.")
L.death() //you just ate them, they're dead.
else
to_chat(src, "[L] cannot sate your hunger!")
@@ -325,35 +330,155 @@
busy = SPIDER_IDLE
stop_automated_movement = FALSE
-/mob/living/simple_animal/hostile/poison/giant_spider/nurse/verb/LayEggs()
- set name = "Lay Eggs"
- set category = "Spider"
- set desc = "Lay a clutch of eggs, but you must wrap a creature for feeding first."
+/datum/action/innate/spider
+ icon_icon = 'icons/mob/actions/actions_animal.dmi'
+ background_icon_state = "bg_alien"
- var/obj/structure/spider/eggcluster/E = locate() in get_turf(src)
- if(stat == DEAD)
+/datum/action/innate/spider/lay_web
+ name = "Spin Web"
+ desc = "Spin a web to slow down potential prey."
+ check_flags = AB_CHECK_CONSCIOUS
+ button_icon_state = "lay_web"
+
+/datum/action/innate/spider/lay_web/Activate()
+ if(!istype(owner, /mob/living/simple_animal/hostile/poison/giant_spider/nurse))
return
+ var/mob/living/simple_animal/hostile/poison/giant_spider/nurse/S = owner
+
+ if(!isturf(S.loc))
+ return
+ var/turf/T = get_turf(S)
+
+ var/obj/structure/spider/stickyweb/W = locate() in T
+ if(W)
+ to_chat(S, "There's already a web here!")
+ return
+
+ if(S.busy != SPINNING_WEB)
+ S.busy = SPINNING_WEB
+ S.visible_message("[S] begins to secrete a sticky substance.","You begin to lay a web.")
+ S.stop_automated_movement = TRUE
+ if(do_after(S, 40, target = T))
+ if(S.busy == SPINNING_WEB && S.loc == T)
+ new /obj/structure/spider/stickyweb(T)
+ S.busy = SPIDER_IDLE
+ S.stop_automated_movement = FALSE
+ else
+ to_chat(S, "You're already spinning a web!")
+
+/obj/effect/proc_holder/wrap
+ name = "Wrap"
+ panel = "Spider"
+ active = FALSE
+ datum/action/spell_action/action = null
+ desc = "Wrap something or someone in a cocoon. If it's a living being, you'll also consume them, allowing you to lay eggs."
+ ranged_mousepointer = 'icons/effects/wrap_target.dmi'
+ action_icon = 'icons/mob/actions/actions_animal.dmi'
+ action_icon_state = "wrap_0"
+ action_background_icon_state = "bg_alien"
+
+/obj/effect/proc_holder/wrap/Initialize()
+ . = ..()
+ action = new(src)
+
+/obj/effect/proc_holder/wrap/update_icon()
+ action.button_icon_state = "wrap_[active]"
+ action.UpdateButtonIcon()
+
+/obj/effect/proc_holder/wrap/Click()
+ if(!istype(usr, /mob/living/simple_animal/hostile/poison/giant_spider/nurse))
+ return TRUE
+ var/mob/living/simple_animal/hostile/poison/giant_spider/nurse/user = usr
+ activate(user)
+ return TRUE
+
+/obj/effect/proc_holder/wrap/proc/activate(mob/living/user)
+ var/message
+ if(active)
+ message = "You no longer prepare to wrap something in a cocoon."
+ remove_ranged_ability(message)
+ else
+ message = "You prepare to wrap something in a cocoon. Left-click your target to start wrapping!"
+ add_ranged_ability(user, message, TRUE)
+ return 1
+
+/obj/effect/proc_holder/wrap/InterceptClickOn(mob/living/caller, params, atom/target)
+ if(..())
+ return
+ if(ranged_ability_user.incapacitated() || !istype(ranged_ability_user, /mob/living/simple_animal/hostile/poison/giant_spider/nurse))
+ remove_ranged_ability()
+ return
+
+ var/mob/living/simple_animal/hostile/poison/giant_spider/nurse/user = ranged_ability_user
+
+ if(user.Adjacent(target) && (ismob(target) || isobj(target)))
+ var/atom/movable/target_atom = target
+ if(target_atom.anchored)
+ return
+ user.cocoon_target = target_atom
+ INVOKE_ASYNC(user, /mob/living/simple_animal/hostile/poison/giant_spider/nurse/.proc/cocoon)
+ remove_ranged_ability()
+ return TRUE
+
+/obj/effect/proc_holder/wrap/on_lose(mob/living/carbon/user)
+ remove_ranged_ability()
+
+/datum/action/innate/spider/lay_eggs
+ name = "Lay Eggs"
+ desc = "Lay a cluster of eggs, which will soon grow into more spiders. You must wrap a living being to do this."
+ check_flags = AB_CHECK_CONSCIOUS
+ button_icon_state = "lay_eggs"
+
+/datum/action/innate/spider/lay_eggs/IsAvailable()
+ if(..())
+ if(!istype(owner, /mob/living/simple_animal/hostile/poison/giant_spider/nurse))
+ return 0
+ var/mob/living/simple_animal/hostile/poison/giant_spider/nurse/S = owner
+ if(S.fed)
+ return 1
+ return 0
+
+/datum/action/innate/spider/lay_eggs/Activate()
+ if(!istype(owner, /mob/living/simple_animal/hostile/poison/giant_spider/nurse))
+ return
+ var/mob/living/simple_animal/hostile/poison/giant_spider/nurse/S = owner
+
+ var/obj/structure/spider/eggcluster/E = locate() in get_turf(S)
if(E)
- to_chat(src, "There is already a cluster of eggs here!")
- else if(!fed)
- to_chat(src, "You are too hungry to do this!")
- else if(busy != LAYING_EGGS)
- busy = LAYING_EGGS
- src.visible_message("\the [src] begins to lay a cluster of eggs.")
- stop_automated_movement = 1
- if(do_after(src, 50, target = src.loc))
- if(busy == LAYING_EGGS)
- E = locate() in get_turf(src)
- if(!E)
- var/obj/structure/spider/eggcluster/C = new /obj/structure/spider/eggcluster(src.loc)
- if(ckey)
- C.player_spiders = 1
- C.poison_type = poison_type
- C.poison_per_bite = poison_per_bite
- C.faction = faction.Copy()
- fed--
- busy = SPIDER_IDLE
- stop_automated_movement = FALSE
+ to_chat(S, "There is already a cluster of eggs here!")
+ else if(!S.fed)
+ to_chat(S, "You are too hungry to do this!")
+ else if(S.busy != LAYING_EGGS)
+ S.busy = LAYING_EGGS
+ S.visible_message("[S] begins to lay a cluster of eggs.","You begin to lay a cluster of eggs.")
+ S.stop_automated_movement = TRUE
+ if(do_after(S, 50, target = get_turf(S)))
+ if(S.busy == LAYING_EGGS)
+ E = locate() in get_turf(S)
+ if(!E || !isturf(S.loc))
+ var/obj/structure/spider/eggcluster/C = new /obj/structure/spider/eggcluster(get_turf(S))
+ if(S.ckey)
+ C.player_spiders = TRUE
+ C.directive = S.directive
+ C.poison_type = S.poison_type
+ C.poison_per_bite = S.poison_per_bite
+ C.faction = S.faction.Copy()
+ S.fed--
+ UpdateButtonIcon(TRUE)
+ S.busy = SPIDER_IDLE
+ S.stop_automated_movement = FALSE
+
+/datum/action/innate/spider/set_directive
+ name = "Set Directive"
+ desc = "Set a directive for your children to follow."
+ check_flags = AB_CHECK_CONSCIOUS
+ button_icon_state = "directive"
+
+/datum/action/innate/spider/set_directive/Activate()
+ if(!istype(owner, /mob/living/simple_animal/hostile/poison/giant_spider/nurse))
+ return
+ var/mob/living/simple_animal/hostile/poison/giant_spider/nurse/S = owner
+ S.directive = stripped_input(S, "Enter the new directive", "Create directive", "[S.directive]", MAX_MESSAGE_LEN)
/mob/living/simple_animal/hostile/poison/giant_spider/Login()
. = ..()
@@ -365,7 +490,8 @@
/datum/action/innate/spider/comm
name = "Command"
- button_icon_state = "cult_comms"
+ desc = "Send a command to all living spiders."
+ button_icon_state = "command"
/datum/action/innate/spider/comm/IsAvailable()
if(!istype(owner, /mob/living/simple_animal/hostile/poison/giant_spider/nurse/midwife))
@@ -373,19 +499,22 @@
return TRUE
/datum/action/innate/spider/comm/Trigger()
- var/input = stripped_input(usr, "Input a message for your legions to follow.", "Command", "")
+ var/input = stripped_input(owner, "Input a command for your legions to follow.", "Command", "")
if(QDELETED(src) || !input || !IsAvailable())
return FALSE
- spider_command(usr, input)
+ spider_command(owner, input)
return TRUE
/datum/action/innate/spider/comm/proc/spider_command(mob/living/user, message)
if(!message)
return
var/my_message
- my_message = "COMMAND FROM SPIDER QUEEN: [message]"
+ my_message = "Command from [user]: [message]"
for(var/mob/living/simple_animal/hostile/poison/giant_spider/M in GLOB.spidermobs)
to_chat(M, my_message)
+ for(var/M in GLOB.dead_mob_list)
+ var/link = FOLLOW_LINK(M, user)
+ to_chat(M, "[link] [my_message]")
log_talk(user, "SPIDERCOMMAND: [key_name(user)] : [message]",LOGSAY)
/mob/living/simple_animal/hostile/poison/giant_spider/handle_temperature_damage()
diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm
index 3cb56becf8..d3008625cf 100644
--- a/code/modules/spells/spell.dm
+++ b/code/modules/spells/spell.dm
@@ -8,6 +8,28 @@
var/ranged_mousepointer
var/mob/living/ranged_ability_user
var/ranged_clickcd_override = -1
+ var/has_action = TRUE
+ var/datum/action/spell_action/action = null
+ var/action_icon = 'icons/mob/actions/actions_spells.dmi'
+ var/action_icon_state = "spell_default"
+ var/action_background_icon_state = "bg_spell"
+
+/obj/effect/proc_holder/Initialize()
+ . = ..()
+ if(has_action)
+ action = new(src)
+
+/obj/effect/proc_holder/proc/on_gain(mob/living/user)
+ return
+
+/obj/effect/proc_holder/proc/on_lose(mob/living/user)
+ return
+
+/obj/effect/proc_holder/proc/fire(mob/living/user)
+ return TRUE
+
+/obj/effect/proc_holder/proc/get_panel_text()
+ return ""
GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for the badmin verb for now
@@ -118,10 +140,10 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
var/critfailchance = 0
var/centcom_cancast = 1 //Whether or not the spell should be allowed on z2
- var/action_icon = 'icons/mob/actions/actions_spells.dmi'
- var/action_icon_state = "spell_default"
- var/action_background_icon_state = "bg_spell"
- var/datum/action/spell_action/action
+ action_icon = 'icons/mob/actions/actions_spells.dmi'
+ action_icon_state = "spell_default"
+ action_background_icon_state = "bg_spell"
+ datum/action/spell_action/spell/action
/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
diff --git a/icons/effects/wrap_target.dmi b/icons/effects/wrap_target.dmi
new file mode 100644
index 0000000000..2e9a338c9e
Binary files /dev/null and b/icons/effects/wrap_target.dmi differ
diff --git a/icons/mob/actions/actions_animal.dmi b/icons/mob/actions/actions_animal.dmi
new file mode 100644
index 0000000000..1dcf7590cd
Binary files /dev/null and b/icons/mob/actions/actions_animal.dmi differ