diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm
index 81a0cf3d028..03959a3265b 100644
--- a/_maps/map_files/BoxStation/BoxStation.dmm
+++ b/_maps/map_files/BoxStation/BoxStation.dmm
@@ -5717,6 +5717,10 @@
},
/turf/open/floor/plasteel/dark,
/area/security/courtroom)
+"amu" = (
+/mob/living/simple_animal/hostile/retaliate/goose/vomit,
+/turf/open/floor/wood,
+/area/maintenance/port/aft)
"amv" = (
/obj/effect/mapping_helpers/airlock/cyclelink_helper,
/obj/machinery/door/airlock/external{
@@ -72265,7 +72269,7 @@ bCq
bPS
aad
bPS
-bPS
+amu
bCq
cbk
bLv
diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm
index 27531838ff7..5bb87dbc52a 100644
--- a/_maps/map_files/Deltastation/DeltaStation2.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2.dmm
@@ -96331,6 +96331,7 @@
/turf/open/floor/plasteel/dark,
/area/crew_quarters/abandoned_gambling_den)
"dvV" = (
+/mob/living/simple_animal/hostile/retaliate/goose/vomit,
/turf/open/floor/wood{
icon_state = "wood-broken7"
},
diff --git a/_maps/map_files/Donutstation/Donutstation.dmm b/_maps/map_files/Donutstation/Donutstation.dmm
index 19fb34449b1..71cb4986016 100644
--- a/_maps/map_files/Donutstation/Donutstation.dmm
+++ b/_maps/map_files/Donutstation/Donutstation.dmm
@@ -5,6 +5,13 @@
"aab" = (
/turf/closed/wall,
/area/space/nearstation)
+"aac" = (
+/obj/effect/decal/cleanable/dirt,
+/mob/living/simple_animal/hostile/retaliate/goose/vomit,
+/turf/open/floor/plating{
+ icon_state = "panelscorched"
+ },
+/area/maintenance/department/crew_quarters/bar)
"aad" = (
/turf/closed/wall/r_wall,
/area/engine/engineering)
@@ -75563,7 +75570,7 @@ kIi
bXA
bVM
bVU
-bSy
+aac
bSy
bWC
aRr
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index a2f581c4218..9d9ffd16b82 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -9939,6 +9939,10 @@
/obj/structure/cable,
/turf/open/floor/plating,
/area/maintenance/starboard)
+"auR" = (
+/mob/living/simple_animal/hostile/retaliate/goose/vomit,
+/turf/open/floor/wood,
+/area/maintenance/port/aft)
"auU" = (
/obj/structure/disposalpipe/segment{
dir = 6
@@ -92469,7 +92473,7 @@ ckP
ckS
ckP
ckP
-ckP
+auR
cjt
crh
ckN
diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm
index 7803dbac70b..ed803e219ea 100644
--- a/_maps/map_files/PubbyStation/PubbyStation.dmm
+++ b/_maps/map_files/PubbyStation/PubbyStation.dmm
@@ -56011,6 +56011,10 @@
icon_state = "panelscorched"
},
/area/maintenance/department/science)
+"tSN" = (
+/mob/living/simple_animal/hostile/retaliate/goose/vomit,
+/turf/open/floor/wood,
+/area/maintenance/department/crew_quarters/dorms)
"tSU" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/visible/layer1,
/obj/effect/turf_decal/stripes/line{
@@ -94879,7 +94883,7 @@ cBk
jhD
cBo
alQ
-alb
+tSN
cBw
alb
aiS
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index 22c1ab84e3e..f83d44977d6 100755
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -536,9 +536,11 @@
/turf/AllowDrop()
return TRUE
-/turf/proc/add_vomit_floor(mob/living/carbon/M, toxvomit = NONE)
+/turf/proc/add_vomit_floor(mob/living/M, toxvomit = NONE)
+
var/obj/effect/decal/cleanable/vomit/V = new /obj/effect/decal/cleanable/vomit(src, M.get_static_viruses())
- // If the vomit combined, apply toxicity and reagents to the old vomit
+
+ //if the vomit combined, apply toxicity and reagents to the old vomit
if (QDELETED(V))
V = locate() in src
if(!V)
@@ -546,10 +548,12 @@
// Make toxins and blazaam vomit look different
if(toxvomit == VOMIT_PURPLE)
V.icon_state = "vomitpurp_[pick(1,4)]"
- else if(toxvomit == VOMIT_TOXIC)
+ else if (toxvomit == VOMIT_TOXIC)
V.icon_state = "vomittox_[pick(1,4)]"
- if(M.reagents)
- clear_reagents_to_vomit_pool(M,V)
+ if (iscarbon(M))
+ var/mob/living/carbon/C = M
+ if(C.reagents)
+ clear_reagents_to_vomit_pool(C,V)
/proc/clear_reagents_to_vomit_pool(mob/living/carbon/M, obj/effect/decal/cleanable/vomit/V)
M.reagents.trans_to(V, M.reagents.total_volume / 10, transfered_by = M)
diff --git a/code/modules/mob/living/simple_animal/hostile/goose.dm b/code/modules/mob/living/simple_animal/hostile/goose.dm
index a0a2073a790..19e9c7c8b30 100644
--- a/code/modules/mob/living/simple_animal/hostile/goose.dm
+++ b/code/modules/mob/living/simple_animal/hostile/goose.dm
@@ -1,7 +1,9 @@
+#define GOOSE_SATIATED 50
+
/mob/living/simple_animal/hostile/retaliate/goose
name = "goose"
desc = "It's loose"
- icon_state = "goose"
+ icon_state = "goose" // sprites by cogwerks from goonstation, used with permission
icon_living = "goose"
icon_dead = "goose_dead"
mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
@@ -10,7 +12,7 @@
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat = 2)
response_help = "pets"
response_disarm = "gently pushes aside"
- response_harm = "hits"
+ response_harm = "kicks"
emote_taunt = list("hisses")
taunt_chance = 30
speed = 0
@@ -25,33 +27,143 @@
faction = list("neutral")
attack_same = TRUE
gold_core_spawnable = HOSTILE_SPAWN
- var/icon_resting = "goose_sit"
-
-
-/mob/living/simple_animal/hostile/retaliate/goose/toggle_ai(togglestatus)
- . = ..()
- if(!key)
- if(AIStatus != AI_ON)
- set_resting(TRUE)
- else
- set_resting(FALSE)
-
-/mob/living/simple_animal/hostile/retaliate/goose/update_resting()
- . = ..()
- if(resting)
- wander = FALSE
- else
- wander = TRUE
- update_icon()
+ var/random_retaliate = TRUE
+ var/icon_vomit_start = "vomit_start"
+ var/icon_vomit = "vomit"
+ var/icon_vomit_end = "vomit_end"
/mob/living/simple_animal/hostile/retaliate/goose/handle_automated_movement()
. = ..()
- if(prob(5))
+ if(prob(5) && random_retaliate == TRUE)
Retaliate()
-/mob/living/simple_animal/hostile/retaliate/goose/proc/update_icon()
- if(stat != DEAD)
- icon_state = resting ? icon_resting : icon_living
- else
- icon_state = icon_dead
+/mob/living/simple_animal/hostile/retaliate/goose/vomit
+ name = "Birdboat"
+ real_name = "Birdboat"
+ desc = "It's a sick-looking goose, probably ate too much maintenance trash. Best not to move it around too much."
+ gender = MALE
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "kicks"
+ gold_core_spawnable = NO_SPAWN
+ random_retaliate = FALSE
+ var/vomiting = FALSE
+ var/vomitCoefficient = 1
+ var/vomitTimeBonus = 0
+ var/datum/action/cooldown/vomit/goosevomit
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/Initialize()
+ . = ..()
+ goosevomit = new
+ goosevomit.Grant(src)
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/Destroy()
+ QDEL_NULL(goosevomit)
+ return ..()
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/examine(user)
+ . = ..()
+ . += "Somehow, it still looks hungry."
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/attacked_by(obj/item/O, mob/user)
+ . = ..()
+ feed(O)
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/feed(obj/item/O)
+ var/obj/item/reagent_containers/food/tasty = O
+ if(!istype(O))
+ return
+ if (contents.len > GOOSE_SATIATED)
+ visible_message("[src] looks too full to eat \the [tasty]!")
+ return
+ if (tasty.foodtype & GROSS)
+ visible_message("[src] hungrily gobbles up \the [tasty]!")
+ tasty.forceMove(src)
+ playsound(src,'sound/items/eatfood.ogg', 70, 1)
+ vomitCoefficient += 3
+ vomitTimeBonus += 2
+ else
+ visible_message("[src] refuses to eat \the [tasty].")
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/vomit()
+ var/turf/T = get_turf(src)
+ var/obj/item/reagent_containers/food/consumed = locate() in contents //Barf out a single food item from our guts
+ if (prob(50) && consumed)
+ barf_food(consumed)
+ else
+ playsound(T, 'sound/effects/splat.ogg', 50, 1)
+ T.add_vomit_floor(src)
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/barf_food(var/atom/A, var/hard = FALSE)
+ if(!istype(A, /obj/item/reagent_containers/food))
+ return
+ var/turf/currentTurf = get_turf(src)
+ var/obj/item/reagent_containers/food/consumed = A
+ consumed.forceMove(currentTurf)
+ var/destination = get_edge_target_turf(currentTurf, pick(GLOB.alldirs)) //Pick a random direction to toss them in
+ var/throwRange = hard ? rand(2,8) : 1
+ consumed.safe_throw_at(destination, throwRange, 2) //Thow the food at a random tile 1 spot away
+ sleep(2)
+ if (QDELETED(src) || QDELETED(consumed))
+ return
+ currentTurf = get_turf(consumed)
+ currentTurf.add_vomit_floor(src)
+ playsound(currentTurf, 'sound/effects/splat.ogg', 50, 1)
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/vomit_prestart(duration)
+ flick("vomit_start",src)
+ addtimer(CALLBACK(src, .proc/vomit_start, duration), 13) //13 is the length of the vomit_start animation in gooseloose.dmi
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/vomit_start(duration)
+ vomiting = TRUE
+ icon_state = "vomit"
+ vomit()
+ addtimer(CALLBACK(src, .proc/vomit_preend), duration)
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/vomit_preend()
+ for (var/obj/item/consumed in contents) //Get rid of any food left in the poor thing
+ barf_food(consumed, TRUE)
+ sleep(1)
+ if (QDELETED(src))
+ return
+ vomit_end()
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/vomit_end()
+ flick("vomit_end",src)
+ vomiting = FALSE
+ icon_state = initial(icon_state)
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/Moved(oldLoc, dir)
+ . = ..()
+ if(vomiting)
+ vomit() // its supposed to keep vomiting if you move
+ return
+ var/turf/currentTurf = get_turf(src)
+ while (currentTurf == get_turf(src))
+ var/obj/item/reagent_containers/food/tasty = locate() in currentTurf
+ if (tasty)
+ feed(tasty)
+ stoplag(2)
+ if(prob(vomitCoefficient * 0.2))
+ vomit_prestart(vomitTimeBonus + 25)
+ vomitCoefficient = 1
+ vomitTimeBonus = 0
+
+/datum/action/cooldown/vomit
+ name = "Vomit"
+ check_flags = AB_CHECK_CONSCIOUS
+ button_icon_state = "vomit"
+ icon_icon = 'icons/mob/animal.dmi'
+ cooldown_time = 250
+
+/datum/action/cooldown/vomit/Trigger()
+ if(!..())
+ return FALSE
+ if(!istype(owner, /mob/living/simple_animal/hostile/retaliate/goose/vomit))
+ return FALSE
+ var/mob/living/simple_animal/hostile/retaliate/goose/vomit/vomit = owner
+ if(!vomit.vomiting)
+ vomit.vomit_prestart(vomit.vomitTimeBonus + 25)
+ vomit.vomitCoefficient = 1
+ vomit.vomitTimeBonus = 0
+ return TRUE
diff --git a/icons/mob/animal.dmi b/icons/mob/animal.dmi
index 0fa693a7c52..e551678e5a2 100644
Binary files a/icons/mob/animal.dmi and b/icons/mob/animal.dmi differ