diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm index 328482f9892..ec43330a8eb 100644 --- a/code/datums/supplypacks.dm +++ b/code/datums/supplypacks.dm @@ -1199,7 +1199,7 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine /datum/supply_packs/organic/hydroponics/beekeeping_fullkit name = "Beekeeping Starter Kit" - contains = list(/obj/structure/beebox, + contains = list(/obj/structure/beebox/unwrenched, /obj/item/honey_frame, /obj/item/honey_frame, /obj/item/honey_frame, diff --git a/code/modules/hydroponics/beekeeping/beebox.dm b/code/modules/hydroponics/beekeeping/beebox.dm index 7acd3efc961..371822643a1 100644 --- a/code/modules/hydroponics/beekeeping/beebox.dm +++ b/code/modules/hydroponics/beekeeping/beebox.dm @@ -8,35 +8,36 @@ /mob/proc/bee_friendly() - return 0 + return FALSE /mob/living/simple_animal/hostile/poison/bees/bee_friendly() - return 1 + return TRUE /mob/living/simple_animal/bot/bee_friendly() if(paicard) - return 0 - return 1 + return FALSE + return TRUE /mob/living/simple_animal/diona/bee_friendly() - return 1 + return TRUE /mob/living/carbon/human/bee_friendly() if(isdiona(src)) //bees pollinate plants, duh. - return 1 + return TRUE if((wear_suit && (wear_suit.flags & THICKMATERIAL)) && (head && (head.flags & THICKMATERIAL))) - return 1 - return 0 + return TRUE + return FALSE /obj/structure/beebox name = "apiary" - desc = "Dr Miles Manners is just your average Wasp themed super hero by day, but by night he becomes DR BEES!" + desc = "Dr. Miles Manners is just your average wasp-themed super hero by day, but by night he becomes DR. BEES!" icon = 'icons/obj/hydroponics/equipment.dmi' icon_state = "beebox" - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE + max_integrity = 300 var/mob/living/simple_animal/hostile/poison/bees/queen/queen_bee = null var/list/bees = list() //bees owned by the box, not those inside it var/list/honeycombs = list() @@ -44,8 +45,8 @@ var/bee_resources = 0 -/obj/structure/beebox/New() - ..() +/obj/structure/beebox/Initialize(mapload) + . = ..() processing_objects.Add(src) @@ -66,12 +67,11 @@ var/random_reagent = FALSE -/obj/structure/beebox/premade/New() - ..() - +/obj/structure/beebox/premade/Initialize(mapload) + . = ..() var/datum/reagent/R = null if(random_reagent) - R = get_random_reagent_id() + R = GLOB.chemical_reagents_list[get_random_reagent_id()] queen_bee = new(src) queen_bee.beehome = src @@ -83,7 +83,7 @@ honey_frames += HF for(var/i in 1 to get_max_bees()) - var/mob/living/simple_animal/hostile/poison/bees/worker/B = new(src) + var/mob/living/simple_animal/hostile/poison/bees/B = new(src) bees += B B.beehome = src B.assign_reagent(R) @@ -93,7 +93,7 @@ /obj/structure/beebox/process() - if(queen_bee && (!queen_bee.beegent || !queen_bee.beegent.can_synth)) + if(queen_bee) if(bee_resources >= BEE_RESOURCE_HONEYCOMB_COST) if(honeycombs.len < get_max_honeycomb()) bee_resources = max(bee_resources-BEE_RESOURCE_HONEYCOMB_COST, 0) @@ -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/worker/B = new(src) + var/mob/living/simple_animal/hostile/poison/bees/B = new(get_turf(src)) B.beehome = src B.assign_reagent(queen_bee.beegent) bees += B @@ -152,14 +152,16 @@ if(istype(I, /obj/item/honey_frame)) var/obj/item/honey_frame/HF = I if(honey_frames.len < BEEBOX_MAX_FRAMES) + if(!user.unEquip(HF)) + return visible_message("[user] adds a frame to the apiary.") - user.unEquip(HF) HF.forceMove(src) honey_frames += HF else to_chat(user, "There's no room for anymore frames in the apiary!") + return - if(istype(I, /obj/item/wrench)) + if(iswrench(I)) if(default_unfasten_wrench(user, I, time = 20)) return @@ -169,25 +171,27 @@ return var/obj/item/queen_bee/qb = I - user.unEquip(qb) if(!qb.queen.beegent || (qb.queen.beegent && qb.queen.beegent.can_synth)) + if(!user.unEquip(qb)) + return qb.queen.forceMove(src) bees += qb.queen queen_bee = qb.queen qb.queen = null else visible_message("The [qb] refuses to settle down. Maybe it's something to do with its reagent?") + return if(queen_bee) visible_message("[user] sets [qb] down inside the apiary, making it [user.p_their()] new home.") var/relocated = 0 for(var/b in bees) - var/mob/living/simple_animal/hostile/poison/bees/worker/B = b + var/mob/living/simple_animal/hostile/poison/bees/B = b if(B.reagent_incompatible(queen_bee)) bees -= B B.beehome = null if(B.loc == src) - B.forceMove(get_turf(src)) + B.forceMove(drop_location()) relocated++ if(relocated) to_chat(user, "This queen has a different reagent to some of the bees who live here, those bees will not return to this apiary!") @@ -196,6 +200,8 @@ to_chat(user, "The queen bee disappeared! bees disappearing has been in the news lately...") qdel(qb) + return + return ..() /obj/structure/beebox/attack_hand(mob/user) @@ -208,7 +214,7 @@ if(B.isqueen) continue if(B.loc == src) - B.forceMove(get_turf(src)) + B.forceMove(drop_location()) B.target = user bees = TRUE if(bees) @@ -254,3 +260,16 @@ QB.forceMove(get_turf(src)) visible_message("[user] removes the queen from the apiary.") queen_bee = null + +/obj/structure/beebox/deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/wood(loc, 20) + for(var/mob/living/simple_animal/hostile/poison/bees/B in bees) + if(B.loc == src) + B.forceMove(drop_location()) + for(var/obj/item/honey_frame/HF in honey_frames) + HF.forceMove(drop_location()) + honey_frames -= HF + qdel(src) + +/obj/structure/beebox/unwrenched + anchored = FALSE \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/bees.dm b/code/modules/mob/living/simple_animal/hostile/bees.dm index 4516a44a935..5ebefeba405 100644 --- a/code/modules/mob/living/simple_animal/hostile/bees.dm +++ b/code/modules/mob/living/simple_animal/hostile/bees.dm @@ -11,7 +11,7 @@ /mob/living/simple_animal/hostile/poison/bees name = "bee" - desc = "buzzy buzzy bee, stingy sti- Ouch!" + desc = "Buzzy buzzy bee, stingy sti- Ouch!" icon_state = "" icon_living = "" icon = 'icons/mob/bees.dmi' @@ -33,25 +33,28 @@ environment_smash = 0 mouse_opacity = MOUSE_OPACITY_OPAQUE pass_flags = PASSTABLE | PASSGRILLE | PASSMOB - flying = 1 - search_objects = 1 //have to find those plant trays! - density = 0 + density = FALSE mob_size = MOB_SIZE_TINY + flying = TRUE + search_objects = TRUE //have to find those plant trays! //Spaceborn beings don't get hurt by space atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) minbodytemp = 0 - del_on_death = 1 + del_on_death = TRUE var/datum/reagent/beegent = null //hehe, beegent var/obj/structure/beebox/beehome = null - var/isqueen = FALSE var/idle = 0 + var/isqueen = FALSE + var/bee_syndicate = FALSE var/icon_base = "bee" var/static/list/bee_icons = list() + var/static/beehometypecache = typecacheof(/obj/structure/beebox) + var/static/hydroponicstypecache = typecacheof(/obj/machinery/hydroponics) /mob/living/simple_animal/hostile/poison/bees/Process_Spacemove(movement_dir = 0) - return 1 + return TRUE /mob/living/simple_animal/hostile/poison/bees/New() ..() @@ -65,6 +68,20 @@ beehome = null return ..() +/mob/living/simple_animal/hostile/poison/bees/death(gibbed) + . = ..() + if(!.) + return + if(beehome) + if(beehome.bees) + beehome.bees.Remove(src) + beehome = null + +/mob/living/simple_animal/hostile/poison/bees/examine(mob/user) + ..() + if(!bee_syndicate && !beehome) + to_chat(user, "This bee is homeless!") + /mob/living/simple_animal/hostile/poison/bees/proc/generate_bee_visuals() overlays.Cut() @@ -94,21 +111,45 @@ //We don't attack beekeepers/people dressed as bees//Todo: bee costume /mob/living/simple_animal/hostile/poison/bees/CanAttack(atom/the_target) . = ..() - return . + if(!.) + return FALSE + if(!bee_syndicate && isliving(the_target)) + var/mob/living/H = the_target + return !H.bee_friendly() /mob/living/simple_animal/hostile/poison/bees/Found(atom/A) if(isliving(A)) - var/mob/living/L = A - return !L.bee_friendly() - return 0 + var/mob/living/H = A + return !H.bee_friendly() + if(istype(A, /obj/machinery/hydroponics)) + var/obj/machinery/hydroponics/Hydro = A + if(Hydro.myseed && !Hydro.dead && !Hydro.recent_bee_visit) + wanted_objects |= hydroponicstypecache //so we only hunt them while they're alive/seeded/not visisted + return TRUE + return FALSE /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) + //Pollinate + if(istype(target, /obj/machinery/hydroponics)) + var/obj/machinery/hydroponics/Hydro = target + pollinate(Hydro) + else if(istype(target, /obj/structure/beebox)) + if(target == beehome) + var/obj/structure/beebox/BB = target + forceMove(BB) + target = null + wanted_objects -= beehometypecache //so we don't attack beeboxes when not going home + return //no don't attack the goddamm box + else + ..() + if(isliving(target)) + var/mob/living/L = target + if(L.reagents) + if(beegent) + beegent.reaction_mob(L, INGEST) + L.reagents.add_reagent(beegent.id, rand(1, 5)) + else + L.reagents.add_reagent("spidertoxin", 5) /mob/living/simple_animal/hostile/poison/bees/proc/assign_reagent(datum/reagent/R) if(istype(R)) @@ -116,81 +157,13 @@ 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) - if(beehome.bees) - beehome.bees.Remove(src) - beehome = null - return ..() - -/mob/living/simple_animal/hostile/poison/bees/worker/death(gibbed) - . = ..() - if(!.) - return - if(beehome) - if(beehome.bees) - 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/hydroponics)) - var/obj/machinery/hydroponics/Hydro = A - if(Hydro.myseed && !Hydro.dead && !Hydro.recent_bee_visit && !Hydro.lid_state) - wanted_objects |= /obj/machinery/hydroponics //so we only hunt them while they're alive/seeded/not visisted and uncovered - return 1 - ..() - -/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/worker/AttackingTarget() - //Pollinate - if(istype(target, /obj/machinery/hydroponics)) - var/obj/machinery/hydroponics/Hydro = target - pollinate(Hydro) - else if(target == beehome) - var/obj/structure/beebox/BB = target - forceMove(BB) - target = null - wanted_objects -= /obj/structure/beebox //so we don't attack beeboxes when not going home - else - ..() - -/mob/living/simple_animal/hostile/poison/bees/worker/proc/pollinate(obj/machinery/hydroponics/Hydro) +/mob/living/simple_animal/hostile/poison/bees/proc/pollinate(obj/machinery/hydroponics/Hydro) if(!istype(Hydro) || !Hydro.myseed || Hydro.dead || Hydro.recent_bee_visit || Hydro.lid_state) target = null return target = null //so we pick a new hydro tray next FindTarget(), instead of loving the same plant for eternity - wanted_objects -= /obj/machinery/hydroponics //so we only hunt them while they're alive/seeded/not visisted and uncovered + wanted_objects -= hydroponicstypecache //so we only hunt them while they're alive/seeded/not visisted Hydro.recent_bee_visit = TRUE spawn(BEE_TRAY_RECENT_VISIT) if(Hydro) @@ -210,68 +183,79 @@ if(beehome) beehome.bee_resources = min(beehome.bee_resources + growth, 100) -/mob/living/simple_animal/hostile/poison/bees/worker/handle_automated_action() +/mob/living/simple_animal/hostile/poison/bees/handle_automated_action() . = ..() if(!.) return - if(!isqueen) - if(loc == beehome) - idle = min(100, ++idle) - if(idle >= BEE_IDLE_ROAMING && prob(BEE_PROB_GOROAM)) - forceMove(get_turf(beehome)) - else - idle = max(0, --idle) - if(idle <= BEE_IDLE_GOHOME && prob(BEE_PROB_GOHOME)) - if(!FindTarget()) - wanted_objects += /obj/structure/beebox //so we don't attack beeboxes when not going home - target = beehome - if(!beehome) //add outselves to a beebox (of the same reagent) if we have no home - for(var/obj/structure/beebox/BB in view(vision_range, src)) - if(reagent_incompatible(BB.queen_bee) || BB.bees.len >= BB.get_max_bees()) - continue - BB.bees |= src - beehome = BB - + if(!bee_syndicate) + if(!isqueen) + if(loc == beehome) + idle = min(100, ++idle) + if(idle >= BEE_IDLE_ROAMING && prob(BEE_PROB_GOROAM)) + forceMove(beehome.drop_location()) + else + idle = max(0, --idle) + if(idle <= BEE_IDLE_GOHOME && prob(BEE_PROB_GOHOME)) + if(!FindTarget()) + wanted_objects |= beehometypecache //so we don't attack beeboxes when not going home + target = beehome + if(!beehome) //add ourselves to a beebox (of the same reagent) if we have no home + for(var/obj/structure/beebox/BB in view(vision_range, src)) + if(reagent_incompatible(BB.queen_bee) || BB.bees.len >= BB.get_max_bees()) + continue + BB.bees |= src + beehome = BB + break // End loop after the first compatible find. //Botany Queen Bee /mob/living/simple_animal/hostile/poison/bees/queen name = "queen bee" - desc = "she's the queen of bees, BZZ BZZ" + desc = "She's the queen of bees, BZZ BZZ" icon_base = "queen" isqueen = TRUE - //the Queen doesn't leave the box on her own, and she CERTAINLY doesn't pollinate by herself +//the Queen doesn't leave the box on her own, and she CERTAINLY doesn't pollinate by herself /mob/living/simple_animal/hostile/poison/bees/queen/Found(atom/A) - return 0 + return FALSE + +//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)) + +//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) + return FALSE + if(B.beegent && beegent && B.beegent.id != beegent.id || B.beegent && !beegent || !B.beegent && beegent) + return TRUE + return FALSE -/mob/living/simple_animal/hostile/poison/bees/queen/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() /obj/item/queen_bee name = "queen bee" - desc = "she's the queen of bees, BZZ BZZ" + desc = "She's the queen of bees, BZZ BZZ" icon_state = "queen_item" item_state = "" 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/reagent_containers/syringe)) + if(istype(I, /obj/item/reagent_containers/syringe)) var/obj/item/reagent_containers/syringe/S = I if(S.reagents.has_reagent("royal_bee_jelly")) //checked twice, because I really don't want royal bee jelly to be duped - if(S.reagents.has_reagent("royal_bee_jelly",5)) + if(S.reagents.has_reagent("royal_bee_jelly", 5)) S.reagents.remove_reagent("royal_bee_jelly", 5) - if(!queen.beegent.can_synth) - to_chat(user, "You inject [src] with the royal bee jelly. It's ineffective! Maybe it's something to do with the [src] reagent.") - return - var/obj/item/queen_bee/qb = new(get_turf(user)) + var/obj/item/queen_bee/qb = new(user.drop_location()) qb.queen = new(qb) if(queen && queen.beegent) qb.queen.assign_reagent(queen.beegent) //Bees use the global singleton instances of reagents, so we don't need to worry about one bee being deleted and her copies losing their reagents. @@ -282,16 +266,17 @@ else var/datum/reagent/R = GLOB.chemical_reagents_list[S.reagents.get_master_reagent_id()] if(R && S.reagents.has_reagent(R.id, 5)) - S.reagents.remove_reagent(R.id,5) + S.reagents.remove_reagent(R.id, 5) queen.assign_reagent(R) - user.visible_message("[user] injects [src]'s genome with [R.name], mutating it's DNA!","You inject [src]'s genome with [R.name], mutating it's DNA!") + user.visible_message("[user] injects [src]'s genome with [R.name], mutating its DNA!", "You inject [src]'s genome with [R.name], mutating its DNA!") name = queen.name else to_chat(user, "You don't have enough units of that chemical to modify the bee's DNA!") - ..() + else + return ..() -/obj/item/queen_bee/bought/New() - ..() +/obj/item/queen_bee/bought/Initialize(mapload) + . = ..() queen = new(src) /obj/item/queen_bee/Destroy() @@ -299,7 +284,6 @@ return ..() - //Syndicate Bees /mob/living/simple_animal/hostile/poison/bees/syndi name = "syndi-bee" @@ -309,10 +293,14 @@ 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 + search_objects = FALSE //these bees don't care about trivial things like plants, especially when there is havoc to sow + bee_syndicate = TRUE var/list/master_and_friends = list() +/mob/living/simple_animal/hostile/poison/bees/syndi/New() + beegent = GLOB.chemical_reagents_list["facid"] //Prepare to die + ..() + /mob/living/simple_animal/hostile/poison/bees/syndi/Destroy() master_and_friends.Cut() return ..() @@ -320,24 +308,27 @@ /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/pollinate() // No Pollination + return + +/mob/living/simple_animal/hostile/poison/bees/syndi/Found(atom/A) //Typical usual hostile mob targeting list + return /mob/living/simple_animal/hostile/poison/bees/syndi/CanAttack(atom/the_target) . = ..() if(!.) - return 0 + return FALSE 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 + return FALSE + return TRUE /mob/living/simple_animal/hostile/poison/bees/syndi/AttackingTarget() ..() if(target && isliving(target)) var/mob/living/L = target if(L.stat) - LoseTarget() + LoseTarget() \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index ccbd37f2f4c..50568fb37d0 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -53,6 +53,7 @@ if(!targets_from) targets_from = src environment_target_typecache = typecacheof(environment_target_typecache) + wanted_objects = typecacheof(wanted_objects) /mob/living/simple_animal/hostile/Destroy() targets_from = null @@ -205,7 +206,7 @@ return 0 return 1 if(isobj(the_target)) - if(is_type_in_list(the_target, wanted_objects)) + if(is_type_in_typecache(the_target, wanted_objects)) return 1 return 0