From d46cde8eae50edfe9ee39cbc67f84e1af5684a08 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Thu, 28 Jan 2021 03:06:55 +0100 Subject: [PATCH] [MIRROR] Adds the Hauntium material, which turns any item into a ghost (with AI) (#2918) * Adds the Hauntium material, which turns any item into a ghost (with AI) (#55728) * Adds the Hauntium material, which turns any item into a ghost (with AI) Co-authored-by: Qustinnus --- code/__DEFINES/ai.dm | 22 +++++- code/__DEFINES/materials.dm | 3 + code/datums/ai/_ai_behavior.dm | 3 + code/datums/ai/_ai_controller.dm | 8 ++- code/datums/ai/_item_behaviors.dm | 57 ++++++++++++++++ code/datums/ai/generic_actions.dm | 1 + code/datums/ai/hauntium/haunted_controller.dm | 63 ++++++++++++++++++ code/datums/ai/monkey/monkey_behaviors.dm | 3 +- code/datums/elements/haunted.dm | 25 +++++++ code/datums/materials/alloys.dm | 12 ++-- code/datums/materials/basemats.dm | 42 ++++++------ code/datums/materials/hauntium.dm | 22 ++++++ code/datums/materials/meat.dm | 2 +- code/datums/materials/pizza.dm | 2 +- code/game/atoms.dm | 2 +- .../items/stacks/sheets/sheet_types.dm | 19 ++++++ code/game/objects/items/storage/toolbox.dm | 8 +++ code/modules/photography/_pictures.dm | 6 +- code/modules/photography/camera/camera.dm | 2 +- code/modules/photography/photos/photo.dm | 9 +++ .../research/designs/autolathe_designs.dm | 2 +- code/modules/research/designs/misc_designs.dm | 4 +- .../research/designs/weapon_designs.dm | 2 +- sound/items/haunted/ghostitemattack.ogg | Bin 0 -> 23349 bytes tgstation.dme | 4 ++ 25 files changed, 283 insertions(+), 40 deletions(-) create mode 100644 code/datums/ai/_item_behaviors.dm create mode 100644 code/datums/ai/hauntium/haunted_controller.dm create mode 100644 code/datums/elements/haunted.dm create mode 100644 code/datums/materials/hauntium.dm create mode 100644 sound/items/haunted/ghostitemattack.ogg diff --git a/code/__DEFINES/ai.dm b/code/__DEFINES/ai.dm index 8533b848009..471a7925324 100644 --- a/code/__DEFINES/ai.dm +++ b/code/__DEFINES/ai.dm @@ -10,7 +10,7 @@ #define IS_DEAD_OR_INCAP(source) (HAS_TRAIT(source, TRAIT_INCAPACITATED) || HAS_TRAIT(source, TRAIT_HANDS_BLOCKED) || IS_IN_STASIS(source) || source.stat) ///Max pathing attempts before auto-fail -#define MAX_PATHING_ATTEMPTS 30 +#define MAX_PATHING_ATTEMPTS 16 ///Flags for ai_behavior new() #define AI_CONTROLLER_INCOMPATIBLE (1<<0) @@ -35,8 +35,26 @@ #define BB_MONKEY_RECRUIT_COOLDOWN "BB_monkey_recruit_cooldown" -///Vending machine AI controller blackboard keys +///Haunted item controller defines + +///Chance for haunted item to haunt someone +#define HAUNTED_ITEM_ATTACK_HAUNT_CHANCE 10 +///Chance for haunted item to try to get itself let go. +#define HAUNTED_ITEM_ESCAPE_GRASP_CHANCE 20 +///Chance for haunted item to warp somewhere new +#define HAUNTED_ITEM_TELEPORT_CHANCE 4 +///Amount of aggro you get when picking up a haunted item +#define HAUNTED_ITEM_AGGRO_ADDITION 2 + +///Blackboard keys for haunted items +#define BB_TO_HAUNT_LIST "BB_to_haunt_list" +///Actual mob the item is haunting at the moment +#define BB_HAUNT_TARGET "BB_haunt_target" +///Amount of successful hits in a row this item has had +#define BB_HAUNTED_THROW_ATTEMPT_COUNT "BB_haunted_throw_attempt_count" + +///Vending machine AI controller blackboard keys #define BB_VENDING_CURRENT_TARGET "BB_vending_current_target" #define BB_VENDING_TILT_COOLDOWN "BB_vending_tilt_cooldown" #define BB_VENDING_UNTILT_COOLDOWN "BB_vending_untilt_cooldown" diff --git a/code/__DEFINES/materials.dm b/code/__DEFINES/materials.dm index 107e8c841ff..a2a37069e46 100644 --- a/code/__DEFINES/materials.dm +++ b/code/__DEFINES/materials.dm @@ -4,6 +4,9 @@ /// Hard materials, such as iron or metal #define MAT_CATEGORY_RIGID "rigid material" +/// Materials that can be used to craft items +#define MAT_CATEGORY_ITEM_MATERIAL "item material" + ///Use this flag on TRUE if you want the basic recipes #define MAT_CATEGORY_BASE_RECIPES "basic recipes" diff --git a/code/datums/ai/_ai_behavior.dm b/code/datums/ai/_ai_behavior.dm index 3c5154f42a0..2961ed010ad 100644 --- a/code/datums/ai/_ai_behavior.dm +++ b/code/datums/ai/_ai_behavior.dm @@ -4,9 +4,12 @@ var/required_distance = 1 ///Flags for extra behavior var/behavior_flags = NONE + ///Cooldown between actions performances + var/action_cooldown = 0 ///Called by the AI controller when this action is performed /datum/ai_behavior/proc/perform(delta_time, datum/ai_controller/controller) + controller.behavior_cooldowns[src] = world.time + action_cooldown return ///Called when the action is finished. diff --git a/code/datums/ai/_ai_controller.dm b/code/datums/ai/_ai_controller.dm index fd794437a90..c44a00230b7 100644 --- a/code/datums/ai/_ai_controller.dm +++ b/code/datums/ai/_ai_controller.dm @@ -10,7 +10,9 @@ have ways of interacting with a specific atom and control it. They posses a blac var/ai_traits ///Current actions being performed by the AI. var/list/current_behaviors = list() - ///Current status of AI (OFF/ON ) + ///Current actions and their respective last time ran as an assoc list. + var/list/behavior_cooldowns = list() + ///Current status of AI (OFF/ON) var/ai_status ///Current movement target of the AI, generally set by decision making. var/atom/current_movement_target @@ -91,6 +93,10 @@ have ways of interacting with a specific atom and control it. They posses a blac var/want_to_move = FALSE for(var/i in current_behaviors) var/datum/ai_behavior/current_behavior = i + + if(behavior_cooldowns[current_behavior] > world.time) //Still on cooldown + continue + if(current_behavior.behavior_flags & AI_BEHAVIOR_REQUIRE_MOVEMENT && current_movement_target && current_behavior.required_distance < get_dist(pawn, current_movement_target)) //Move closer want_to_move = TRUE if(current_behavior.behavior_flags & AI_BEHAVIOR_MOVE_AND_PERFORM) //Move and perform the action diff --git a/code/datums/ai/_item_behaviors.dm b/code/datums/ai/_item_behaviors.dm new file mode 100644 index 00000000000..e51c7f392c5 --- /dev/null +++ b/code/datums/ai/_item_behaviors.dm @@ -0,0 +1,57 @@ +///This behavior is for obj/items, it is used to free themselves out of the hands of whoever is holding them +/datum/ai_behavior/item_escape_grasp + +/datum/ai_behavior/item_escape_grasp/perform(delta_time, datum/ai_controller/controller) + . = ..() + var/obj/item/item_pawn = controller.pawn + var/mob/item_holder = item_pawn.loc + if(!istype(item_holder)) + finish_action(controller, FALSE) //We're no longer beind held. abort abort!! + item_pawn.visible_message("[item_pawn] slips out of the hands of [item_holder]!") + item_holder.dropItemToGround(item_pawn, TRUE) + finish_action(controller, TRUE) + + +///This behavior is for obj/items, it is used to move closer to a target and throw themselves towards them. +/datum/ai_behavior/item_move_close_and_attack + required_distance = 3 + behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT + action_cooldown = 20 + ///Blackboard key for the max attempt of throws + var/throw_count_key + ///Blackboard key for the target to hit + var/target_key + ///Sound to use + var/attack_sound + ///Max attemps to make + var/max_attempts = 3 + + +/datum/ai_behavior/item_move_close_and_attack/perform(delta_time, datum/ai_controller/controller) + . = ..() + var/obj/item/item_pawn = controller.pawn + var/atom/throw_target = controller.blackboard[target_key] + + item_pawn.visible_message("[item_pawn] hurls towards [throw_target]!") + item_pawn.throw_at(throw_target, rand(4,5), 9) + playsound(item_pawn.loc, attack_sound, 100, TRUE) + controller.blackboard[throw_count_key]++ + if(controller.blackboard[throw_count_key] >= max_attempts) + finish_action(controller, TRUE) + +/datum/ai_behavior/item_move_close_and_attack/finish_action(datum/ai_controller/controller, succeeded) + . = ..() + controller.blackboard[throw_count_key] = 0 + controller.blackboard[target_key] = null + +/datum/ai_behavior/item_move_close_and_attack/haunted + throw_count_key = BB_HAUNTED_THROW_ATTEMPT_COUNT + target_key = BB_HAUNT_TARGET + attack_sound = 'sound/items/haunted/ghostitemattack.ogg' + max_attempts = 4 + +/datum/ai_behavior/item_move_close_and_attack/haunted/finish_action(datum/ai_controller/controller, succeeded) + var/atom/throw_target = controller.blackboard[target_key] + var/list/hauntee_list = controller.blackboard[BB_TO_HAUNT_LIST] + hauntee_list[throw_target]-- + return ..() diff --git a/code/datums/ai/generic_actions.dm b/code/datums/ai/generic_actions.dm index 884f17f75f7..a3af839a568 100644 --- a/code/datums/ai/generic_actions.dm +++ b/code/datums/ai/generic_actions.dm @@ -10,6 +10,7 @@ var/list/screeches /datum/ai_behavior/battle_screech/perform(delta_time, datum/ai_controller/controller) + . = ..() var/mob/living/living_pawn = controller.pawn INVOKE_ASYNC(living_pawn, /mob.proc/emote, pick(screeches)) finish_action(controller, TRUE) diff --git a/code/datums/ai/hauntium/haunted_controller.dm b/code/datums/ai/hauntium/haunted_controller.dm new file mode 100644 index 00000000000..9c3a1438dd6 --- /dev/null +++ b/code/datums/ai/hauntium/haunted_controller.dm @@ -0,0 +1,63 @@ + +/datum/ai_controller/haunted + blackboard = list(BB_TO_HAUNT_LIST = list(), + BB_HAUNT_TARGET, + BB_HAUNTED_THROW_ATTEMPT_COUNT) + +/datum/ai_controller/haunted/TryPossessPawn(atom/new_pawn) + if(!isitem(new_pawn)) + return AI_CONTROLLER_INCOMPATIBLE + RegisterSignal(new_pawn, COMSIG_ITEM_EQUIPPED, .proc/on_equip) + return ..() //Run parent at end + +/datum/ai_controller/haunted/UnpossessPawn() + UnregisterSignal(pawn, COMSIG_ITEM_EQUIPPED) + return ..() //Run parent at end + +/datum/ai_controller/haunted/able_to_run() + return TRUE + +/datum/ai_controller/haunted/SelectBehaviors(delta_time) + current_behaviors = list() + var/obj/item/item_pawn = pawn + + if(ismob(item_pawn.loc)) //We're being held, maybe escape? + if(DT_PROB(HAUNTED_ITEM_ESCAPE_GRASP_CHANCE, delta_time)) + current_behaviors += GET_AI_BEHAVIOR(/datum/ai_behavior/item_escape_grasp) + return + + if(!DT_PROB(HAUNTED_ITEM_ATTACK_HAUNT_CHANCE, delta_time)) + return + + var/list/to_haunt_list = blackboard[BB_TO_HAUNT_LIST] + + for(var/i in to_haunt_list) + if(to_haunt_list[i] <= 0) + continue + var/mob/living/potential_target = i + if(get_dist(potential_target, item_pawn) <= 7) + blackboard[BB_HAUNT_TARGET] = potential_target + current_movement_target = potential_target + current_behaviors += GET_AI_BEHAVIOR(/datum/ai_behavior/item_move_close_and_attack/haunted) + return + +/datum/ai_controller/haunted/PerformIdleBehavior(delta_time) + var/obj/item/item_pawn = pawn + if(ismob(item_pawn.loc)) //Being held. dont teleport + return + if(DT_PROB(HAUNTED_ITEM_TELEPORT_CHANCE, delta_time)) + playsound(item_pawn.loc, 'sound/items/haunted/ghostitemattack.ogg', 100, TRUE) + do_teleport(pawn, get_turf(pawn), 4, channel = TELEPORT_CHANNEL_MAGIC) + +///Signal response for when the item is picked up; stops listening for follow up equips, just waits for a drop. +/datum/ai_controller/haunted/proc/on_equip(datum/source, mob/equipper, slot) + UnregisterSignal(pawn, COMSIG_ITEM_EQUIPPED) + var/list/hauntee_list = blackboard[BB_TO_HAUNT_LIST] + hauntee_list[equipper] = hauntee_list[equipper] + HAUNTED_ITEM_AGGRO_ADDITION //You have now become one of the victims of the HAAAAUNTTIIIINNGGG OOOOOO~~~ + RegisterSignal(pawn, COMSIG_ITEM_DROPPED, .proc/on_dropped) + SIGNAL_HANDLER + +///Flip it so we listen for equip again but not for drop. +/datum/ai_controller/haunted/proc/on_dropped(datum/source, mob/user) + RegisterSignal(pawn, COMSIG_ITEM_EQUIPPED, .proc/on_equip) + UnregisterSignal(pawn, COMSIG_ITEM_DROPPED) diff --git a/code/datums/ai/monkey/monkey_behaviors.dm b/code/datums/ai/monkey/monkey_behaviors.dm index d052aa0f7de..16018f95940 100644 --- a/code/datums/ai/monkey/monkey_behaviors.dm +++ b/code/datums/ai/monkey/monkey_behaviors.dm @@ -59,12 +59,13 @@ required_distance = 0 /datum/ai_behavior/monkey_equip/ground/perform(delta_time, datum/ai_controller/controller) + . = ..() equip_item(controller) /datum/ai_behavior/monkey_equip/pickpocket /datum/ai_behavior/monkey_equip/pickpocket/perform(delta_time, datum/ai_controller/controller) - + . = ..() if(controller.blackboard[BB_MONKEY_PICKPOCKETING]) //We are pickpocketing, don't do ANYTHING!!!! return INVOKE_ASYNC(src, .proc/attempt_pickpocket, controller) diff --git a/code/datums/elements/haunted.dm b/code/datums/elements/haunted.dm new file mode 100644 index 00000000000..5b6ef377e2c --- /dev/null +++ b/code/datums/elements/haunted.dm @@ -0,0 +1,25 @@ +///Attaching this element to something will make it float, get a special ai controller, and gives it a spooky outline. +/datum/element/haunted + element_flags = ELEMENT_DETACH + +/datum/element/haunted/Attach(datum/target) + . = ..() + if(!isitem(target)) + return COMPONENT_INCOMPATIBLE + //Make em look spooky + var/obj/item/master = target + master.add_filter("haunt_glow", 2, list("type" = "outline", "color" = "#f8f8ff", "size" = 1)) + master.ai_controller = new /datum/ai_controller/haunted(master) + master.AddElement(/datum/element/movetype_handler) + ADD_TRAIT(master, TRAIT_MOVE_FLYING, ELEMENT_TRAIT) + +/datum/element/haunted/Detach(datum/source, force) + . = ..() + var/atom/movable/master = source + master.remove_filter("haunt_glow") + QDEL_NULL(master.ai_controller) + REMOVE_TRAIT(master, TRAIT_MOVE_FLYING, ELEMENT_TRAIT) + master.RemoveElement(/datum/element/movetype_handler) + return ..() + + diff --git a/code/datums/materials/alloys.dm b/code/datums/materials/alloys.dm index eec3809e110..2bdfb857e23 100644 --- a/code/datums/materials/alloys.dm +++ b/code/datums/materials/alloys.dm @@ -37,7 +37,7 @@ integrity_modifier = 1.5 // Heavy duty. armor_modifiers = list(MELEE = 1.4, BULLET = 1.4, LASER = 1.1, ENERGY = 1.1, BOMB = 1.5, BIO = 1, RAD = 1.5, FIRE = 1.1, ACID = 1) sheet_type = /obj/item/stack/sheet/plasteel - categories = list(MAT_CATEGORY_RIGID=TRUE, MAT_CATEGORY_BASE_RECIPES=TRUE) + categories = list(MAT_CATEGORY_RIGID=TRUE, MAT_CATEGORY_BASE_RECIPES=TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) composition = list(/datum/material/iron=1, /datum/material/plasma=1) /datum/material/alloy/plasteel/on_applied_obj(obj/item/target_item, amount, material_flags) @@ -69,7 +69,7 @@ integrity_modifier = 1.3 armor_modifiers = list(MELEE = 1.1, BULLET = 1.1, LASER = 1.4, ENERGY = 1.4, BOMB = 1.1, BIO = 1.2, RAD = 1.1, FIRE = 1.5, ACID = 1) sheet_type = /obj/item/stack/sheet/mineral/plastitanium - categories = list(MAT_CATEGORY_RIGID=TRUE, MAT_CATEGORY_BASE_RECIPES=TRUE) + categories = list(MAT_CATEGORY_RIGID=TRUE, MAT_CATEGORY_BASE_RECIPES=TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) composition = list(/datum/material/titanium=1, /datum/material/plasma=1) /** Plasmaglass @@ -87,7 +87,7 @@ sheet_type = /obj/item/stack/sheet/plasmaglass shard_type = /obj/item/shard/plasma value_per_unit = 0.075 - categories = list(MAT_CATEGORY_RIGID=TRUE, MAT_CATEGORY_BASE_RECIPES=TRUE) + categories = list(MAT_CATEGORY_RIGID=TRUE, MAT_CATEGORY_BASE_RECIPES=TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) composition = list(/datum/material/glass=1, /datum/material/plasma=0.5) /** Titaniumglass @@ -104,7 +104,7 @@ sheet_type = /obj/item/stack/sheet/titaniumglass shard_type = /obj/item/shard value_per_unit = 0.04 - categories = list(MAT_CATEGORY_RIGID=TRUE, MAT_CATEGORY_BASE_RECIPES=TRUE) + categories = list(MAT_CATEGORY_RIGID=TRUE, MAT_CATEGORY_BASE_RECIPES=TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) composition = list(/datum/material/glass=1, /datum/material/titanium=0.5) /** Plastitanium Glass @@ -122,7 +122,7 @@ sheet_type = /obj/item/stack/sheet/plastitaniumglass shard_type = /obj/item/shard/plasma value_per_unit = 0.125 - categories = list(MAT_CATEGORY_RIGID=TRUE, MAT_CATEGORY_BASE_RECIPES=TRUE) + categories = list(MAT_CATEGORY_RIGID=TRUE, MAT_CATEGORY_BASE_RECIPES=TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) composition = list(/datum/material/glass=1, /datum/material/alloy/plastitanium=0.5) /** Alien Alloy @@ -141,7 +141,7 @@ armor_modifiers = list(MELEE = 1.4, BULLET = 1.4, LASER = 1.2, ENERGY = 1.2, BOMB = 1.5, BIO = 1.2, RAD = 1.5, FIRE = 1.2, ACID = 1.2) sheet_type = /obj/item/stack/sheet/mineral/abductor value_per_unit = 0.4 - categories = list(MAT_CATEGORY_RIGID=TRUE, MAT_CATEGORY_BASE_RECIPES=TRUE) + categories = list(MAT_CATEGORY_RIGID=TRUE, MAT_CATEGORY_BASE_RECIPES=TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) composition = list(/datum/material/iron=2, /datum/material/plasma=2) /datum/material/alloy/alien/on_applied_obj(obj/item/target_item, amount, material_flags) diff --git a/code/datums/materials/basemats.dm b/code/datums/materials/basemats.dm index 7e0e6cc8baa..91e76c4f88e 100644 --- a/code/datums/materials/basemats.dm +++ b/code/datums/materials/basemats.dm @@ -3,7 +3,7 @@ name = "iron" desc = "Common iron ore often found in sedimentary and igneous layers of the crust." color = "#878687" - categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE) + categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/metal value_per_unit = 0.0025 @@ -17,7 +17,7 @@ desc = "Glass forged by melting sand." color = "#88cdf1" alpha = 150 - categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE) + categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) integrity_modifier = 0.1 sheet_type = /obj/item/stack/sheet/glass shard_type = /obj/item/shard @@ -39,7 +39,7 @@ Unless you know what you're doing, only use the first three numbers. They're in name = "silver" desc = "Silver" color = list(255/255, 284/255, 302/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) - categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE) + categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/mineral/silver value_per_unit = 0.025 beauty_modifier = 0.075 @@ -54,7 +54,7 @@ Unless you know what you're doing, only use the first three numbers. They're in desc = "Gold" color = list(340/255, 240/255, 50/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) //gold is shiny, but not as bright as bananium strength_modifier = 1.2 - categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE) + categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/mineral/gold value_per_unit = 0.0625 beauty_modifier = 0.15 @@ -69,7 +69,7 @@ Unless you know what you're doing, only use the first three numbers. They're in name = "diamond" desc = "Highly pressurized carbon" color = list(48/255, 272/255, 301/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) - categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE) + categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/mineral/diamond alpha = 132 value_per_unit = 0.25 @@ -85,7 +85,7 @@ Unless you know what you're doing, only use the first three numbers. They're in name = "uranium" desc = "Uranium" color = rgb(48, 237, 26) - categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE) + categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/mineral/uranium value_per_unit = 0.05 beauty_modifier = 0.3 //It shines so beautiful @@ -109,7 +109,7 @@ Unless you know what you're doing, only use the first three numbers. They're in name = "plasma" desc = "Isn't plasma a state of matter? Oh whatever." color = list(298/255, 46/255, 352/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) - categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE) + categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/mineral/plasma shard_type = /obj/item/shard/plasma value_per_unit = 0.1 @@ -153,7 +153,7 @@ Unless you know what you're doing, only use the first three numbers. They're in name = "bananium" desc = "Material with hilarious properties" color = list(460/255, 464/255, 0, 0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) //obnoxiously bright yellow - categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE) + categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/mineral/bananium value_per_unit = 0.5 beauty_modifier = 0.5 @@ -195,7 +195,7 @@ Unless you know what you're doing, only use the first three numbers. They're in desc = "Runite" color = "#3F9995" strength_modifier = 1.3 - categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE) + categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/mineral/runite value_per_unit = 0.3 beauty_modifier = 0.5 @@ -309,7 +309,7 @@ Unless you know what you're doing, only use the first three numbers. They're in desc = "A weird kind of ice, feels warm to the touch" color = "#88cdf1" alpha = 150 - categories = list(MAT_CATEGORY_RIGID = TRUE) + categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/hot_ice value_per_unit = 0.2 beauty_modifier = 0.2 @@ -332,7 +332,7 @@ Unless you know what you're doing, only use the first three numbers. They're in desc = "Solid metallic hydrogen. Some say it should be impossible" color = "#f2d5d7" alpha = 150 - categories = list(MAT_CATEGORY_RIGID = TRUE) + categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/mineral/metal_hydrogen value_per_unit = 0.35 beauty_modifier = 0.35 @@ -348,7 +348,7 @@ Unless you know what you're doing, only use the first three numbers. They're in desc = "An unkown crystal from an unkown dimension" color = COLOR_YELLOW strength_modifier = 0.95 - categories = list(MAT_CATEGORY_RIGID = TRUE) + categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/otherworld_crystal value_per_unit = 0.25 beauty_modifier = 0.4 @@ -359,7 +359,7 @@ Unless you know what you're doing, only use the first three numbers. They're in name = "sand" desc = "You know, it's amazing just how structurally sound sand can be." color = "#EDC9AF" - categories = list(MAT_CATEGORY_RIGID = TRUE) + categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/sandblock value_per_unit = 0.001 strength_modifier = 0.5 @@ -378,7 +378,7 @@ Unless you know what you're doing, only use the first three numbers. They're in name = "sandstone" desc = "Bialtaakid 'ant taerif ma hdha." color = "#B77D31" - categories = list(MAT_CATEGORY_RIGID = TRUE) + categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/mineral/sandstone value_per_unit = 0.0025 armor_modifiers = list(MELEE = 0.5, BULLET = 0.5, LASER = 1.25, ENERGY = 0.5, BOMB = 0.5, BIO = 0.25, RAD = 1.5, FIRE = 1.5, ACID = 1.5) @@ -390,7 +390,7 @@ Unless you know what you're doing, only use the first three numbers. They're in name = "snow" desc = "There's no business like snow business." color = "#FFFFFF" - categories = list(MAT_CATEGORY_RIGID = TRUE) + categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/mineral/snow value_per_unit = 0.0025 armor_modifiers = list(MELEE = 0.25, BULLET = 0.25, LASER = 0.25, ENERGY = 0.25, BOMB = 0.25, BIO = 0.25, RAD = 1.5, FIRE = 0.25, ACID = 1.5) @@ -406,7 +406,7 @@ Unless you know what you're doing, only use the first three numbers. They're in name = "runed metal" desc = "Mir'ntrath barhah Nar'sie." color = "#3C3434" - categories = list(MAT_CATEGORY_RIGID = TRUE) + categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/runed_metal value_per_unit = 0.75 armor_modifiers = list(MELEE = 1.2, BULLET = 1.2, LASER = 1, ENERGY = 1, BOMB = 1.2, BIO = 1.2, RAD = 1.5, FIRE = 1.5, ACID = 1.5) @@ -422,7 +422,7 @@ Unless you know what you're doing, only use the first three numbers. They're in name = "bronze" desc = "Clock Cult? Never heard of it." color = "#92661A" - categories = list(MAT_CATEGORY_RIGID = TRUE) + categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/tile/bronze value_per_unit = 0.025 armor_modifiers = list(MELEE = 1, BULLET = 1, LASER = 1, ENERGY = 1, BOMB = 1, BIO = 1, RAD = 1.5, FIRE = 1.5, ACID = 1.5) @@ -432,7 +432,7 @@ Unless you know what you're doing, only use the first three numbers. They're in name = "paper" desc = "Ten thousand folds of pure starchy power." color = "#E5DCD5" - categories = list(MAT_CATEGORY_RIGID = TRUE) + categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/paperframes value_per_unit = 0.0025 armor_modifiers = list(MELEE = 0.1, BULLET = 0.1, LASER = 0.1, ENERGY = 0.1, BOMB = 0.1, BIO = 0.1, RAD = 1.5, FIRE = 0, ACID = 1.5) @@ -457,7 +457,7 @@ Unless you know what you're doing, only use the first three numbers. They're in name = "cardboard" desc = "They say cardboard is used by hobos to make incredible things." color = "#5F625C" - categories = list(MAT_CATEGORY_RIGID = TRUE) + categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/cardboard value_per_unit = 0.003 armor_modifiers = list(MELEE = 0.25, BULLET = 0.25, LASER = 0.25, ENERGY = 0.25, BOMB = 0.25, BIO = 0.25, RAD = 1.5, FIRE = 0, ACID = 1.5) @@ -480,7 +480,7 @@ Unless you know what you're doing, only use the first three numbers. They're in name = "bone" desc = "Man, building with this will make you the coolest caveman on the block." color = "#e3dac9" - categories = list(MAT_CATEGORY_RIGID = TRUE) + categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/bone value_per_unit = 0.05 armor_modifiers = list(MELEE = 1.2, BULLET = 0.75, LASER = 0.75, ENERGY = 1.2, BOMB = 1, BIO = 1, RAD = 1.5, FIRE = 1.5, ACID = 1.5) @@ -490,7 +490,7 @@ Unless you know what you're doing, only use the first three numbers. They're in name = "bamboo" desc = "If it's good enough for pandas, it's good enough for you." color = "#339933" - categories = list(MAT_CATEGORY_RIGID = TRUE) + categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/mineral/bamboo value_per_unit = 0.0025 armor_modifiers = list(MELEE = 0.5, BULLET = 0.5, LASER = 0.5, ENERGY = 0.5, BOMB = 0.5, BIO = 0.51, RAD = 1.5, FIRE = 0.5, ACID = 1.5) diff --git a/code/datums/materials/hauntium.dm b/code/datums/materials/hauntium.dm new file mode 100644 index 00000000000..abee58f7216 --- /dev/null +++ b/code/datums/materials/hauntium.dm @@ -0,0 +1,22 @@ +/datum/material/hauntium + name = "hauntium" + desc = "very scary!" + color = list(460/255, 464/255, 460/255, 0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) + alpha = 100 + categories = list(MAT_CATEGORY_ITEM_MATERIAL=TRUE) + sheet_type = /obj/item/stack/sheet/hauntium + value_per_unit = 0.05 + beauty_modifier = 0.25 + strength_modifier = 1 + armor_modifiers = list(MELEE = 1, BULLET = 1, LASER = 1, ENERGY = 1, BOMB = 1, BIO = 1, RAD = 1, FIRE = 1, ACID = 1) + + +/datum/material/hauntium/on_applied_obj(obj/o, amount, material_flags) + . = ..() + if(isitem(o)) + o.AddElement(/datum/element/haunted) + +/datum/material/hauntium/on_removed_obj(obj/o, amount, material_flags) + . = ..() + if(isitem(o)) + o.RemoveElement(/datum/element/haunted) diff --git a/code/datums/materials/meat.dm b/code/datums/materials/meat.dm index 838c57099f9..7fb29fb8493 100644 --- a/code/datums/materials/meat.dm +++ b/code/datums/materials/meat.dm @@ -6,7 +6,7 @@ desc = "Meat" id = /datum/material/meat // So the bespoke versions are categorized under this color = rgb(214, 67, 67) - categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE) + categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/meat value_per_unit = 0.05 beauty_modifier = -0.3 diff --git a/code/datums/materials/pizza.dm b/code/datums/materials/pizza.dm index 71967c0ec93..3a1e0cd7f78 100644 --- a/code/datums/materials/pizza.dm +++ b/code/datums/materials/pizza.dm @@ -4,7 +4,7 @@ name = "pizza" desc = "~Jamme, jamme, n'coppa, jamme ja! Jamme, jamme, n'coppa jamme ja, funi-culi funi-cala funi-culi funi-cala!! Jamme jamme ja funiculi funicula!~" color = "#FF9F23" - categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE) + categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE) sheet_type = /obj/item/stack/sheet/pizza value_per_unit = 0.05 beauty_modifier = 0.1 diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 50ef400119e..7469ca1bf19 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -1852,7 +1852,7 @@ +*/ /atom/proc/InitializeAIController() - if(ai_controller) + if(ispath(ai_controller)) ai_controller = new ai_controller(src) /** diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 12fe46b9eba..63a445afae1 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -770,3 +770,22 @@ new /datum/stack_recipe("paper frame door", /obj/structure/mineral_door/paperfra amount = 20 /obj/item/stack/sheet/sandblock/five amount = 5 + + +/obj/item/stack/sheet/hauntium + name = "haunted sheets" + desc = "These sheets seem cursed." + singular_name = "haunted sheet" + icon_state = "sheet-meat" + material_flags = MATERIAL_COLOR + mats_per_unit = list(/datum/material/hauntium = MINERAL_MATERIAL_AMOUNT) + merge_type = /obj/item/stack/sheet/hauntium + material_type = /datum/material/hauntium + material_modifier = 1 //None of that wussy stuff + +/obj/item/stack/sheet/hauntium/fifty + amount = 50 +/obj/item/stack/sheet/hauntium/twenty + amount = 20 +/obj/item/stack/sheet/hauntium/five + amount = 5 diff --git a/code/game/objects/items/storage/toolbox.dm b/code/game/objects/items/storage/toolbox.dm index 9e04015935b..8ff5412eb2f 100644 --- a/code/game/objects/items/storage/toolbox.dm +++ b/code/game/objects/items/storage/toolbox.dm @@ -315,3 +315,11 @@ else to_chat(user, "You need 10 floor tiles to start building a floorbot!") return + + +/obj/item/storage/toolbox/haunted + name = "old toolbox" + custom_materials = list(/datum/material/hauntium = 500) + + + diff --git a/code/modules/photography/_pictures.dm b/code/modules/photography/_pictures.dm index 511d75ac6c3..daa0fc53c1e 100644 --- a/code/modules/photography/_pictures.dm +++ b/code/modules/photography/_pictures.dm @@ -11,8 +11,10 @@ var/has_blueprints = FALSE var/logpath //If the picture has been logged this is the path. var/id //this var is NOT protected because the worst you can do with this that you couldn't do otherwise is overwrite photos, and photos aren't going to be used as attack logs/investigations anytime soon. + ///Was this image capable of seeing ghosts? + var/see_ghosts = CAMERA_NO_GHOSTS -/datum/picture/New(name, desc, mobs_spotted, dead_spotted, image, icon, size_x, size_y, bp, caption_, autogenerate_icon) +/datum/picture/New(name, desc, mobs_spotted, dead_spotted, image, icon, size_x, size_y, bp, caption_, autogenerate_icon, can_see_ghosts) if(!isnull(name)) picture_name = name if(!isnull(desc)) @@ -35,6 +37,8 @@ caption = caption_ if(autogenerate_icon && !picture_icon && picture_image) regenerate_small_icon() + if(can_see_ghosts) + see_ghosts = can_see_ghosts /datum/picture/proc/get_small_icon(iconstate) if(!picture_icon) diff --git a/code/modules/photography/camera/camera.dm b/code/modules/photography/camera/camera.dm index 153fb049a49..6acfbcc4755 100644 --- a/code/modules/photography/camera/camera.dm +++ b/code/modules/photography/camera/camera.dm @@ -207,7 +207,7 @@ qdel(clone_area) get_icon.Blend("#000", ICON_UNDERLAY) - var/datum/picture/P = new("picture", desc.Join(" "), mobs_spotted, dead_spotted, get_icon, null, psize_x, psize_y, blueprints) + var/datum/picture/P = new("picture", desc.Join(" "), mobs_spotted, dead_spotted, get_icon, null, psize_x, psize_y, blueprints, see_ghosts) after_picture(user, P, flag) blending = FALSE diff --git a/code/modules/photography/photos/photo.dm b/code/modules/photography/photos/photo.dm index 0bc800478f0..28120362ca5 100644 --- a/code/modules/photography/photos/photo.dm +++ b/code/modules/photography/photos/photo.dm @@ -10,6 +10,7 @@ resistance_flags = FLAMMABLE max_integrity = 50 grind_results = list(/datum/reagent/iodine = 4) + material_flags = MATERIAL_NO_EFFECTS var/datum/picture/picture var/scribble //Scribble on the back. @@ -32,6 +33,14 @@ if(setdesc && P.picture_desc) desc = P.picture_desc + + if(!P.see_ghosts) ///Dont bother with this last bit if we can't see ghosts + return + for(var/i in P.mobs_seen) //Any ghosts in the pic? its a haunted photo ooooo~ + if(isobserver(i)) + set_custom_materials(list(/datum/material/hauntium = 1000)) + break + /obj/item/photo/update_icon_state() if(!istype(picture) || !picture.picture_image) return diff --git a/code/modules/research/designs/autolathe_designs.dm b/code/modules/research/designs/autolathe_designs.dm index 00c82840431..4ebd85523c5 100644 --- a/code/modules/research/designs/autolathe_designs.dm +++ b/code/modules/research/designs/autolathe_designs.dm @@ -164,7 +164,7 @@ name = "Toolbox" id = "tool_box" build_type = AUTOLATHE - materials = list(MAT_CATEGORY_RIGID = 500) + materials = list(MAT_CATEGORY_ITEM_MATERIAL = 500) build_path = /obj/item/storage/toolbox category = list("initial","Tools") diff --git a/code/modules/research/designs/misc_designs.dm b/code/modules/research/designs/misc_designs.dm index ad0efcad751..e8bb1943017 100644 --- a/code/modules/research/designs/misc_designs.dm +++ b/code/modules/research/designs/misc_designs.dm @@ -503,7 +503,7 @@ desc = "A royal knight's favorite garments. Can be trimmed by any friendly person." id = "knight_armour" build_type = AUTOLATHE - materials = list(MAT_CATEGORY_RIGID = 10000) + materials = list(MAT_CATEGORY_ITEM_MATERIAL = 10000) build_path = /obj/item/clothing/suit/armor/riot/knight/greyscale category = list("Imported") @@ -512,7 +512,7 @@ desc = "A royal knight's favorite hat. If you hold it upside down it's actually a bucket." id = "knight_helmet" build_type = AUTOLATHE - materials = list(MAT_CATEGORY_RIGID = 5000) + materials = list(MAT_CATEGORY_ITEM_MATERIAL = 5000) build_path = /obj/item/clothing/head/helmet/knight/greyscale category = list("Imported") diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm index 6fe3094f7b7..4ba29a42b09 100644 --- a/code/modules/research/designs/weapon_designs.dm +++ b/code/modules/research/designs/weapon_designs.dm @@ -325,7 +325,7 @@ desc = "A mace fit for a cleric. Useful for bypassing plate armor, but too bulky for much else." id = "cleric_mace" build_type = AUTOLATHE - materials = list(MAT_CATEGORY_RIGID = 12000) + materials = list(MAT_CATEGORY_ITEM_MATERIAL = 12000) build_path = /obj/item/melee/cleric_mace category = list("Imported") diff --git a/sound/items/haunted/ghostitemattack.ogg b/sound/items/haunted/ghostitemattack.ogg new file mode 100644 index 0000000000000000000000000000000000000000..52af7d77db065bb6fbd6561c3338310670b6a03c GIT binary patch literal 23349 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 HfQv!`LBh&V literal 0 HcmV?d00001 diff --git a/tgstation.dme b/tgstation.dme index e1f5b31fcc5..65ec630e4aa 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -418,7 +418,9 @@ #include "code\datums\actions\beam_rifle.dm" #include "code\datums\ai\_ai_behavior.dm" #include "code\datums\ai\_ai_controller.dm" +#include "code\datums\ai\_item_behaviors.dm" #include "code\datums\ai\generic_actions.dm" +#include "code\datums\ai\hauntium\haunted_controller.dm" #include "code\datums\ai\telegraph_effects.dm" #include "code\datums\ai\monkey\monkey_behaviors.dm" #include "code\datums\ai\monkey\monkey_controller.dm" @@ -623,6 +625,7 @@ #include "code\datums\elements\empprotection.dm" #include "code\datums\elements\firestacker.dm" #include "code\datums\elements\forced_gravity.dm" +#include "code\datums\elements\haunted.dm" #include "code\datums\elements\item_scaling.dm" #include "code\datums\elements\light_blocking.dm" #include "code\datums\elements\movetype_handler.dm" @@ -688,6 +691,7 @@ #include "code\datums\materials\_material.dm" #include "code\datums\materials\alloys.dm" #include "code\datums\materials\basemats.dm" +#include "code\datums\materials\hauntium.dm" #include "code\datums\materials\meat.dm" #include "code\datums\materials\pizza.dm" #include "code\datums\mood_events\_mood_event.dm"