diff --git a/code/_globalvars/lists/objects.dm b/code/_globalvars/lists/objects.dm
index 617a0af3d7d..ec3be384bad 100644
--- a/code/_globalvars/lists/objects.dm
+++ b/code/_globalvars/lists/objects.dm
@@ -30,3 +30,4 @@ var/global/list/beacons = list()
var/global/list/shuttle_caller_list = list() //list of all communication consoles and AIs, for automatic shuttle calls when there are none.
var/global/list/tracked_implants = list() //list of all current implants that are tracked to work out what sort of trek everyone is on. Sadly not on lavaworld not implemented...
var/global/list/abductor_equipment = list() //list of all abductor equipment
+var/global/list/global_intercoms = list() //list of all intercomms, across all z-levels
\ No newline at end of file
diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm
index cc3c176ec17..38f711500ff 100644
--- a/code/datums/uplink_item.dm
+++ b/code/datums/uplink_item.dm
@@ -235,6 +235,16 @@ var/list/uplink_items = list()
cost = 5
job = list("Barber")
+//Botanist
+
+/datum/uplink_item/jobspecific/bee_briefcase
+ name = "Briefcase Full of Bees"
+ desc = "A seemingly innocent briefcase full of not-so-innocent Syndicate-bred bees. Inject the case with blood to train the bees to ignore the donor(s). It also wirelessly taps into station intercomms to broadcast a message of TERROR."
+ reference = "BEE"
+ item = /obj/item/weapon/bee_briefcase
+ cost = 10
+ job = list("Botanist")
+
//Engineer
/datum/uplink_item/jobspecific/powergloves
diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm
index fba22decc42..f1eb48e06d7 100644
--- a/code/game/objects/items/devices/radio/intercom.dm
+++ b/code/game/objects/items/devices/radio/intercom.dm
@@ -56,6 +56,7 @@
dir=ndir
b_stat=1
on = 0
+ global_intercoms.Add(src)
update_icon()
/obj/item/device/radio/intercom/department/medbay/New()
@@ -104,6 +105,7 @@
/obj/item/device/radio/intercom/Destroy()
processing_objects.Remove(src)
+ global_intercoms.Remove(src)
return ..()
/obj/item/device/radio/intercom/attack_ai(mob/user as mob)
diff --git a/code/game/objects/items/weapons/bee_briefcase.dm b/code/game/objects/items/weapons/bee_briefcase.dm
new file mode 100644
index 00000000000..5c3e9afff5d
--- /dev/null
+++ b/code/game/objects/items/weapons/bee_briefcase.dm
@@ -0,0 +1,79 @@
+
+/obj/item/weapon/bee_briefcase
+ name = "briefcase"
+ desc = "This briefcase has easy-release clasps and smells vaguely of honey and blood..."
+ icon = 'icons/obj/storage.dmi'
+ icon_state = "briefcase"
+ item_state = "briefcase"
+ flags = CONDUCT
+ hitsound = "swing_hit"
+ force = 10
+ throw_speed = 2
+ throw_range = 4
+ w_class = 4
+ attack_verb = list("bashed", "battered", "bludgeoned", "thrashed", "whacked")
+ var/bees_left = 10
+ var/list/blood_list = list()
+ var/sound_file = 'sound/misc/briefcase_bees.ogg'
+ var/next_sound = 0
+
+/obj/item/weapon/bee_briefcase/examine(mob/user)
+ ..()
+ if(loc == user)
+ if(bees_left)
+ to_chat(user, "There are [bees_left] bees still inside in briefcase!")
+ else
+ to_chat(user, "The bees are gone... Colony collapse disorder?")
+
+/obj/item/weapon/bee_briefcase/attackby(obj/item/I, mob/user, params)
+ if(istype(I, /obj/item/weapon/reagent_containers/syringe))
+
+ var/obj/item/weapon/reagent_containers/syringe/S = I
+ if(!bees_left)
+ to_chat(user, "The briefcase is empty, so there is no point in injecting something into it.")
+ return
+ if(S.reagents && S.reagents.total_volume)
+ to_chat(user, "You inject [src] with [S].")
+ for(var/datum/reagent/A in S.reagents.reagent_list)
+ if(A.id == "blood")
+ if(!(A.data["donor"] in blood_list))
+ blood_list += A.data["donor"]
+ if(A.id == "strange_reagent") //RELOAD THE BEES (1 bee per 1 unit, max 15 bees)
+ if(bees_left < 15)
+ bees_left = min(15, round((bees_left + A.volume), 1)) //No partial bees, max 15 bees in case at any given time
+ to_chat(user, "The buzzing inside the briefcase intensifies as new bees form inside.")
+ else
+ to_chat(user, "The buzzing inside the briefcase swells momentarily, then returns to normal. Guess it was too cramped...")
+ S.reagents.clear_reagents()
+ S.update_icon()
+
+ else if(istype(I, /obj/item/weapon/plantspray))
+ var/obj/item/weapon/plantspray/PS = I
+ user.drop_item(PS)
+ bees_left = max(0, (bees_left - PS.pest_kill_str))
+ to_chat(user, "You spray [PS] into \the [src].")
+ playsound(loc, 'sound/effects/spray3.ogg', 50, 1, -6)
+ qdel(PS)
+
+/obj/item/weapon/bee_briefcase/attack_self(mob/user as mob)
+ if(!bees_left)
+ to_chat(user, "The lack of all and any bees at this event has been somewhat of a let-down...")
+ return
+ else
+ if(world.time >= next_sound) //This cooldown doesn't prevent us from releasing bees, just stops the sound
+ next_sound = world.time + 90
+ //Play sound through the station intercomms, so everyone knows the doom you have wrought.
+ for(var/O in global_intercoms)
+ var/obj/item/device/radio/intercom/I = O
+ if(I.z != ZLEVEL_STATION) //Only broadcast to the station intercoms
+ continue
+ if(!I.on) //Only broadcast to active intercoms (powered, switched on)
+ continue
+ playsound(I, sound_file, 35)
+
+ //Release up to 5 bees per use. Without using strange reagent, that means two uses. WITH strange reagent, you can get more if you don't release the last bee
+ for(var/bee = min(5, bees_left), bee > 0, bee--)
+ var/mob/living/simple_animal/hostile/poison/bees/syndi/B = new /mob/living/simple_animal/hostile/poison/bees/syndi(null)
+ B.master_and_friends = blood_list //Doesn't automatically add the person who opens the case, so the bees will attack the user unless they gave their blood
+ B.forceMove(get_turf(user)) //RELEASE THE BEES!
+ bees_left -= 5
\ No newline at end of file
diff --git a/code/modules/admin/verbs/playsound.dm b/code/modules/admin/verbs/playsound.dm
index 25b0ed54140..47c7da15724 100644
--- a/code/modules/admin/verbs/playsound.dm
+++ b/code/modules/admin/verbs/playsound.dm
@@ -52,7 +52,7 @@ var/list/sounds_cache = list()
set desc = "Plays a sound at every intercomm on the station z level. Works best with small sounds."
if(!check_rights(R_SOUNDS)) return
- var/A = alert("This will play a sound at every intercomm on the station Z, are you sure you want to continue? This works best with short sounds, beware.","Warning","Yep","Nope")
+ var/A = alert("This will play a sound at every intercomm, are you sure you want to continue? This works best with short sounds, beware.","Warning","Yep","Nope")
if(A != "Yep") return
var/list/sounds = file2list("sound/serversound_list.txt");
@@ -67,15 +67,25 @@ var/list/sounds_cache = list()
if(inputvol && inputvol >= 1 && inputvol <= 70)
cvol = inputvol
- var/list/intercomms = list()
+ //Allows for override to utilize intercomms on all z-levels
+ var/B = alert("Do you want to play through intercomms on ALL Z-levels, or just the station?", "Override", "All", "Station")
+ var/ignore_z = 0
+ if(B == "All")
+ ignore_z = 1
- for(var/obj/item/device/radio/intercom/I in world)
- if(I.z != ZLEVEL_STATION) continue
- intercomms += I
+ //Allows for override to utilize incomplete and unpowered intercomms
+ var/C = alert("Do you want to play through unpowered / incomplete intercomms, so the crew can't silence it?", "Override", "Yep", "Nope")
+ var/ignore_power = 0
+ if(C == "Yep")
+ ignore_power = 1
- if(intercomms.len)
- for(var/obj/item/device/radio/intercom/I in intercomms)
- playsound(I, melody, cvol)
+ for(var/O in global_intercoms)
+ var/obj/item/device/radio/intercom/I = O
+ if(I.z != ZLEVEL_STATION && !ignore_z)
+ continue
+ if(!I.on && !ignore_power)
+ continue
+ playsound(I, melody, cvol)
/*
/client/proc/cuban_pete()
diff --git a/code/modules/hydroponics/beekeeping/beebox.dm b/code/modules/hydroponics/beekeeping/beebox.dm
index d3d9cb0f3dc..150528d4c66 100644
--- a/code/modules/hydroponics/beekeeping/beebox.dm
+++ b/code/modules/hydroponics/beekeeping/beebox.dm
@@ -109,7 +109,7 @@
if((bee_resources >= BEE_RESOURCE_NEW_BEE_COST && prob(BEE_PROB_NEW_BEE)) || freebee)
if(!freebee)
bee_resources = max(bee_resources - BEE_RESOURCE_NEW_BEE_COST, 0)
- var/mob/living/simple_animal/hostile/poison/bees/B = new(src)
+ var/mob/living/simple_animal/hostile/poison/bees/worker/B = new(src)
B.beehome = src
B.assign_reagent(queen_bee.beegent)
bees += B
@@ -180,7 +180,7 @@
visible_message("[user] sets [qb] down inside the apiary, making it their new home.")
var/relocated = 0
for(var/b in bees)
- var/mob/living/simple_animal/hostile/poison/bees/B = b
+ var/mob/living/simple_animal/hostile/poison/bees/worker/B = b
if(B.reagent_incompatible(queen_bee))
bees -= B
B.beehome = null
diff --git a/code/modules/mob/living/simple_animal/hostile/bees.dm b/code/modules/mob/living/simple_animal/hostile/bees.dm
index 5a2ef732eb5..54b0d10608a 100644
--- a/code/modules/mob/living/simple_animal/hostile/bees.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bees.dm
@@ -42,33 +42,23 @@
var/datum/reagent/beegent = null //hehe, beegent
var/obj/structure/beebox/beehome = null
- var/idle = 0
var/isqueen = FALSE
+ var/idle = 0
var/icon_base = "bee"
var/static/list/bee_icons = list()
-
/mob/living/simple_animal/hostile/poison/bees/Process_Spacemove(movement_dir = 0)
return 1
-
/mob/living/simple_animal/hostile/poison/bees/New()
..()
generate_bee_visuals()
-
/mob/living/simple_animal/hostile/poison/bees/Destroy()
- if(beehome)
- beehome.bees.Remove(src)
- beehome = null
beegent = null
return ..()
-
/mob/living/simple_animal/hostile/poison/bees/death(gibbed)
- if(beehome)
- beehome.bees.Remove(src)
- beehome = null
beegent = null
..()
ghostize()
@@ -77,10 +67,6 @@
/mob/living/simple_animal/hostile/poison/bees/examine(mob/user)
..()
- if(!beehome)
- to_chat(user, "This bee is homeless!")
-
-
/mob/living/simple_animal/hostile/poison/bees/proc/generate_bee_visuals()
overlays.Cut()
@@ -107,31 +93,87 @@
wings = bee_icons["[icon_base]_wings"]
overlays += wings
-
//We don't attack beekeepers/people dressed as bees//Todo: bee costume
/mob/living/simple_animal/hostile/poison/bees/CanAttack(atom/the_target)
. = ..()
- if(!.)
- return 0
- if(ishuman(the_target))
- var/mob/living/carbon/human/H = the_target
- return !H.bee_friendly()
-
+ return .
/mob/living/simple_animal/hostile/poison/bees/Found(atom/A)
+ if(isliving(A))
+ var/mob/living/L = A
+ return !L.bee_friendly()
+ return 0
+
+/mob/living/simple_animal/hostile/poison/bees/AttackingTarget()
+ if(beegent && isliving(target))
+ var/mob/living/L = target
+ if(!isnull(target.reagents))
+ beegent.reaction_mob(L, INGEST)
+ L.reagents.add_reagent(beegent.id, rand(1,5))
+ target.attack_animal(src)
+
+/mob/living/simple_animal/hostile/poison/bees/proc/assign_reagent(datum/reagent/R)
+ if(istype(R))
+ beegent = R
+ name = "[initial(name)] ([R.name])"
+ generate_bee_visuals()
+
+/mob/living/simple_animal/hostile/poison/bees/handle_automated_action()
+ . = ..()
+ if(!.)
+ return
+
+/mob/living/simple_animal/hostile/poison/bees/proc/reagent_incompatible(mob/living/simple_animal/hostile/poison/bees/B)
+ if(!B)
+ return 0
+ if(B.beegent && beegent && B.beegent.id != beegent.id || B.beegent && !beegent || !B.beegent && beegent)
+ return 1
+ return 0
+
+
+
+
+//Botany Worker Bees
+/mob/living/simple_animal/hostile/poison/bees/worker
+ //Blank type define in case we need to give them special stuff later, plus organization (currently they are same as base type bee)
+
+
+/mob/living/simple_animal/hostile/poison/bees/worker/Destroy()
+ if(beehome)
+ beehome.bees.Remove(src)
+ beehome = null
+ ..()
+
+/mob/living/simple_animal/hostile/poison/bees/worker/death(gibbed)
+ if(beehome)
+ beehome.bees.Remove(src)
+ beehome = null
+ ..()
+
+/mob/living/simple_animal/hostile/poison/bees/worker/examine(mob/user)
+ ..()
+
+ if(!beehome)
+ to_chat(user, "This bee is homeless!")
+
+/mob/living/simple_animal/hostile/poison/bees/worker/Found(atom/A)
if(istype(A, /obj/machinery/portable_atmospherics/hydroponics))
var/obj/machinery/portable_atmospherics/hydroponics/Hydro = A
if(Hydro.seed && !Hydro.dead && !Hydro.recent_bee_visit)
wanted_objects |= /obj/machinery/portable_atmospherics/hydroponics //so we only hunt them while they're alive/seeded/not visisted
return 1
- if(ishuman(A))
- var/mob/living/carbon/human/H = A
- return !H.bee_friendly()
- return 0
+ ..()
+/mob/living/simple_animal/hostile/poison/bees/worker/CanAttack(atom/the_target)
+ . = ..()
+ if(!.)
+ return 0
+ if(isliving(the_target)) //Should ignore ghosts and camera mobs already, but just in case
+ var/mob/living/L = the_target
+ return !L.bee_friendly()
-/mob/living/simple_animal/hostile/poison/bees/AttackingTarget()
- //Pollinate
+/mob/living/simple_animal/hostile/poison/bees/worker/AttackingTarget()
+ //Pollinate
if(istype(target, /obj/machinery/portable_atmospherics/hydroponics))
var/obj/machinery/portable_atmospherics/hydroponics/Hydro = target
pollinate(Hydro)
@@ -141,22 +183,9 @@
target = null
wanted_objects.Remove(/obj/structure/beebox) //so we don't attack beeboxes when not going home
else
- if(beegent && isliving(target))
- var/mob/living/L = target
- if(!isnull(target.reagents))
- beegent.reaction_mob(L, INGEST)
- L.reagents.add_reagent(beegent.id, rand(1,5))
- target.attack_animal(src)
+ ..()
-
-/mob/living/simple_animal/hostile/poison/bees/proc/assign_reagent(datum/reagent/R)
- if(istype(R))
- beegent = R
- name = "[initial(name)] ([R.name])"
- generate_bee_visuals()
-
-
-/mob/living/simple_animal/hostile/poison/bees/proc/pollinate(obj/machinery/portable_atmospherics/hydroponics/Hydro)
+/mob/living/simple_animal/hostile/poison/bees/worker/proc/pollinate(obj/machinery/portable_atmospherics/hydroponics/Hydro)
if(!istype(Hydro) || !Hydro.seed || Hydro.dead || Hydro.recent_bee_visit)
target = null
return
@@ -187,12 +216,10 @@
if(beehome)
beehome.bee_resources = min(beehome.bee_resources + growth, 100)
-
-/mob/living/simple_animal/hostile/poison/bees/handle_automated_action()
+/mob/living/simple_animal/hostile/poison/bees/worker/handle_automated_action()
. = ..()
if(!.)
return
-
if(!isqueen)
if(loc == beehome)
idle = min(100, ++idle)
@@ -212,7 +239,9 @@
beehome = BB
- /mob/living/simple_animal/hostile/poison/bees/queen
+
+//Botany Queen Bee
+/mob/living/simple_animal/hostile/poison/bees/queen
name = "queen bee"
desc = "she's the queen of bees, BZZ BZZ"
icon_base = "queen"
@@ -223,28 +252,13 @@
/mob/living/simple_animal/hostile/poison/bees/queen/Found(atom/A)
return 0
-
-//leave pollination for the peasent bees
-/mob/living/simple_animal/hostile/poison/bees/queen/AttackingTarget()
- if(beegent && isliving(target))
- var/mob/living/L = target
- beegent.reaction_mob(L, TOUCH)
- L.reagents.add_reagent(beegent.id, rand(1,5))
- target.attack_animal(src)
-
-
-//PEASENT BEES
-/mob/living/simple_animal/hostile/poison/bees/queen/pollinate()
- return
-
-
-/mob/living/simple_animal/hostile/poison/bees/proc/reagent_incompatible(mob/living/simple_animal/hostile/poison/bees/B)
- if(!B)
+/mob/living/simple_animal/hostile/poison/bees/queen/CanAttack(atom/the_target)
+ . = ..()
+ if(!.)
return 0
- if(B.beegent && beegent && B.beegent.id != beegent.id || B.beegent && !beegent || !B.beegent && beegent)
- return 1
- return 0
-
+ if(isliving(the_target)) //Should ignore ghosts and camera mobs already, but just in case
+ var/mob/living/L = the_target
+ return !L.bee_friendly()
/obj/item/queen_bee
name = "queen bee"
@@ -254,7 +268,6 @@
icon = 'icons/mob/bees.dmi'
var/mob/living/simple_animal/hostile/poison/bees/queen/queen
-
/obj/item/queen_bee/attackby(obj/item/I, mob/user, params)
if(istype(I,/obj/item/weapon/reagent_containers/syringe))
var/obj/item/weapon/reagent_containers/syringe/S = I
@@ -280,7 +293,6 @@
to_chat(user, "You don't have enough units of that chemical to modify the bee's DNA!")
..()
-
/obj/item/queen_bee/bought/New()
..()
queen = new(src)
@@ -288,3 +300,43 @@
/obj/item/queen_bee/Destroy()
qdel(queen)
return ..()
+
+
+
+//Syndicate Bees
+/mob/living/simple_animal/hostile/poison/bees/syndi
+ name = "syndi-bee"
+ desc = "The result of a large influx of BEES!"
+ melee_damage_lower = 5
+ melee_damage_upper = 5
+ maxHealth = 25
+ health = 25
+ faction = list("hostile", "syndicate")
+ search_objects = 0 //these bees don't care about trivial things like plants, especially when there is havoc to sow
+ beegent = new /datum/reagent/facid() //prepare to die
+ var/list/master_and_friends = list()
+
+/mob/living/simple_animal/hostile/poison/bees/syndi/assign_reagent(datum/reagent/R)
+ return
+
+/mob/living/simple_animal/hostile/poison/bees/syndi/Found(atom/A)
+ return CanAttack(A)
+
+/mob/living/simple_animal/hostile/poison/bees/syndi/CanAttack(atom/the_target)
+ . = ..()
+ if(!.)
+ return 0
+ if(isliving(the_target))
+ var/mob/living/L = the_target
+ if(ishuman(L))
+ var/mob/living/carbon/human/H = L
+ if(H in master_and_friends)
+ return 0
+ return 1
+
+/mob/living/simple_animal/hostile/poison/bees/syndi/AttackingTarget()
+ ..()
+ if(target && isliving(target))
+ var/mob/living/L = target
+ if(L.stat)
+ LoseTarget()
diff --git a/paradise.dme b/paradise.dme
index c50ca178c7f..6e79b17f2d0 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -774,6 +774,7 @@
#include "code\game\objects\items\stacks\tiles\tile_types.dm"
#include "code\game\objects\items\weapons\AI_modules.dm"
#include "code\game\objects\items\weapons\alien_specific.dm"
+#include "code\game\objects\items\weapons\bee_briefcase.dm"
#include "code\game\objects\items\weapons\cards_ids.dm"
#include "code\game\objects\items\weapons\cash.dm"
#include "code\game\objects\items\weapons\caution.dm"
diff --git a/sound/misc/briefcase_bees.ogg b/sound/misc/briefcase_bees.ogg
new file mode 100644
index 00000000000..5483d9d5f91
Binary files /dev/null and b/sound/misc/briefcase_bees.ogg differ