Raptor Rework - Ranching and Companionship (#93564)
@@ -81,6 +81,7 @@
|
||||
#define BB_BASIC_MOB_CURRENT_TARGET "BB_basic_current_target"
|
||||
#define BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION "BB_basic_current_target_hiding_location"
|
||||
#define BB_TARGETING_STRATEGY "targeting_strategy"
|
||||
#define BB_HUNT_TARGETING_STRATEGY "hunt_targeting_strategy"
|
||||
///some behaviors that check current_target also set this on deep crit mobs
|
||||
#define BB_BASIC_MOB_EXECUTION_TARGET "BB_basic_execution_target"
|
||||
///Blackboard key for a whitelist typecache of "things we can target while trying to move"
|
||||
|
||||
@@ -39,40 +39,83 @@
|
||||
#define MOOK_ATTACK_ACTIVE 2
|
||||
#define MOOK_ATTACK_STRIKE 3
|
||||
|
||||
///keeps track of how many gutlunches are born
|
||||
/// Keeps track of how many gutlunches are born
|
||||
GLOBAL_VAR_INIT(gutlunch_count, 0)
|
||||
|
||||
///Pet customization settings saved for every client
|
||||
/// Pet customization settings saved for every client
|
||||
GLOBAL_LIST_EMPTY(customized_pets)
|
||||
|
||||
//raptor defines
|
||||
// Raptor defines
|
||||
/// Raptor chick, tiny and very frail
|
||||
#define RAPTOR_BABY "baby"
|
||||
/// Raptor youngling, cannot be ridden and has reduced stats, but can hunt by itself just fine
|
||||
#define RAPTOR_YOUNG "young"
|
||||
/// Fully grown adult raptor
|
||||
#define RAPTOR_ADULT "adult"
|
||||
|
||||
#define RAPTOR_RED "Red"
|
||||
#define RAPTOR_GREEN "Green"
|
||||
#define RAPTOR_PURPLE "Purple"
|
||||
#define RAPTOR_WHITE "White"
|
||||
#define RAPTOR_YELLOW "Yellow"
|
||||
#define RAPTOR_BLACK "Black"
|
||||
#define RAPTOR_BLUE "Blue"
|
||||
/// Innate raptor offsets
|
||||
#define RAPTOR_INNATE_SOURCE "raptor_innate"
|
||||
|
||||
// Growth values
|
||||
/// How much does meal complexity affect our growth?
|
||||
#define RAPTOR_MEAL_COMPLEXITY_GROWTH_FACTOR 5
|
||||
/// Base value for raptor growth from meat
|
||||
#define RAPTOR_GROWTH_BASE_MEAT 10
|
||||
/// Base value for raptor growth from ash flora
|
||||
#define RAPTOR_GROWTH_BASE_PLANT 5
|
||||
/// How much growth progress raptors need to accumulate to fully grow into an adult
|
||||
#define RAPTOR_GROWTH_REQUIRED 100
|
||||
/// Minimum random growth value a baby raptor can gain per second
|
||||
#define RAPTOR_BABY_GROWTH_LOWER 0.5
|
||||
/// Maximum random growth value a baby raptor can gain per second
|
||||
#define RAPTOR_BABY_GROWTH_UPPER 0.8
|
||||
/// How long it takes for a raptor egg to grow up, in seconds
|
||||
#define RAPTOR_EGG_GROWTH_PROGRESS 100
|
||||
/// How much happiness percentage affects our growth speed
|
||||
#define RAPTOR_GROWTH_HAPPINESS_MULTIPLIER 0.005 // Full happiness increases growth rate by 50%
|
||||
|
||||
/// Damage boost per happiness percent
|
||||
#define RAPTOR_HAPPINESS_DAMAGE_BOOST 0.05
|
||||
|
||||
// Raptor inheritance stats
|
||||
/// Maximum amount of traits a raptor can inherit
|
||||
#define RAPTOR_TRAIT_INHERIT_AMOUNT 2
|
||||
/// Minimum modifier to base attack values a raptor can get
|
||||
#define RAPTOR_INHERIT_MIN_ATTACK -5
|
||||
/// Maximum modifier to base attack values a raptor can get
|
||||
#define RAPTOR_INHERIT_MAX_ATTACK 5
|
||||
/// Minimum modifier to the base health value a raptor can get
|
||||
#define RAPTOR_INHERIT_MIN_HEALTH -30
|
||||
/// Maximum modifier to the base health value a raptor can get
|
||||
#define RAPTOR_INHERIT_MAX_HEALTH 30
|
||||
/// Minimum modifier to base speed values a raptor can get
|
||||
#define RAPTOR_INHERIT_MIN_SPEED -0.66
|
||||
/// Maximum modifier to base speed values a raptor can get
|
||||
#define RAPTOR_INHERIT_MAX_SPEED 0.66
|
||||
/// Minimum modifier a raptor can get to their modifiers, such as ability effect and growth speed
|
||||
#define RAPTOR_INHERIT_MIN_MODIFIER -0.25
|
||||
/// Maximum modifier a raptor can get to their modifiers, such as ability effect and growth speed
|
||||
#define RAPTOR_INHERIT_MAX_MODIFIER 0.25
|
||||
/// Genetic drift for raptors, aka min/max value from the cap that stats can receive when breeding
|
||||
#define RAPTOR_GENETIC_DRIFT 0.2
|
||||
|
||||
///this mob suffers depression
|
||||
/// This mob suffers depression
|
||||
#define BB_BASIC_DEPRESSED "basic_depressed"
|
||||
///this mob will care for its young
|
||||
/// This mob will care for its young
|
||||
#define BB_RAPTOR_MOTHERLY "raptor_motherly"
|
||||
///this mob will be playful around their owners
|
||||
/// This mob will be playful around their owners
|
||||
#define BB_RAPTOR_PLAYFUL "raptor_playful"
|
||||
///this mob will flee combat when it feels threatened
|
||||
/// This mob will flee combat when it feels threatened
|
||||
#define BB_RAPTOR_COWARD "raptor_coward"
|
||||
///our raptor baby target we will take care of
|
||||
/// Our raptor baby target we will take care of
|
||||
#define BB_RAPTOR_BABY "raptor_baby"
|
||||
///the raptor we will heal up
|
||||
/// The raptor we will heal up
|
||||
#define BB_INJURED_RAPTOR "injured_raptor"
|
||||
///the cooldown for next time we eat
|
||||
/// The cooldown for next time we eat
|
||||
#define BB_RAPTOR_EAT_COOLDOWN "raptor_eat_cooldown"
|
||||
///our trough target
|
||||
/// Our trough target
|
||||
#define BB_RAPTOR_TROUGH_TARGET "raptor_trough_target"
|
||||
/// HP level at which we'll flee from attackers
|
||||
#define BB_RAPTOR_FLEE_THRESHOLD "raptor_flee_threshold"
|
||||
|
||||
#define MAX_RAPTOR_POP 64
|
||||
|
||||
@@ -74,6 +74,9 @@
|
||||
///Sent to the newly spawned object when it's baked in an oven.
|
||||
#define COMSIG_ITEM_BAKED_RESULT "item_baked_result"
|
||||
|
||||
/// From /datum/element/basic_eating/finish_eating() : (mob/living/eater, mob/living/feeder)
|
||||
#define COMSIG_ITEM_EATEN_BY_BASIC_MOB "item_eaten_by_basic_mob"
|
||||
|
||||
///Called on the result spawned during decomposition: (obj/decomposed)
|
||||
#define COMSIG_OBJ_DECOMPOSITION_RESULT "obj_decomposition_result"
|
||||
|
||||
|
||||
@@ -28,3 +28,8 @@
|
||||
#define COMSIG_BASICMOB_MUTATED "basicmob_mutated"
|
||||
///cancel further mutation modifications to the mob such as shiny mutation.
|
||||
#define MUTATED_NO_FURTHER_MUTATIONS (1 << 0)
|
||||
|
||||
/// from /mob/living/basic/raptor/proc/change_growth_stage() : (new_stage, prev_stage)
|
||||
#define COMSIG_RAPTOR_GROWTH_STAGE_CHANGE "raptor_growth_stage_change"
|
||||
/// Cancel raptor growth
|
||||
#define COMPONENT_CANCEL_RAPTOR_GROWTH (1<<0)
|
||||
|
||||
@@ -182,3 +182,6 @@
|
||||
|
||||
//from base of [/obj/effect/particle_effect/fluid/smoke/proc/smoke_mob]: (seconds_per_tick)
|
||||
#define COMSIG_CARBON_EXPOSED_TO_SMOKE "carbon_exposed_to_smoke"
|
||||
|
||||
/// From /mob/living/carbon/human/proc/update_mob_height() : (old_height)
|
||||
#define COMSIG_HUMAN_HEIGHT_UPDATED "human_height_updated"
|
||||
|
||||
@@ -365,3 +365,6 @@
|
||||
#define COMSIG_LIVING_DROP_LOOT "living_drop_loot"
|
||||
/// Prevent loot from being dropped
|
||||
#define COMPONENT_NO_LOOT_DROP (1<<0)
|
||||
|
||||
/// From /mob/living/proc/mob_pickup() : (mob/living/user, obj/item/mob_holder/holder)
|
||||
#define COMSIG_LIVING_SCOOPED_UP "living_scooped_up"
|
||||
|
||||
@@ -637,3 +637,9 @@
|
||||
|
||||
/// Sent from /obj/machinert/console/camera_advanced/attack_hand() : (mob/eye/camera/remote/new_camera)
|
||||
#define COMSIG_ADVANCED_CAMERA_EYE_CREATED "advanced_camera_eye_created"
|
||||
|
||||
/// Sent from /obj/item/mob_holder/purple_raptor/proc/toggle_wings() : (mob/living/carbon/human/user)
|
||||
#define COMSIG_RAPTOR_WINGS_OPENED "raptor_wings_opened"
|
||||
|
||||
/// Sent from /obj/item/mob_holder/purple_raptor/proc/toggle_wings() : (mob/living/carbon/human/user)
|
||||
#define COMSIG_RAPTOR_WINGS_CLOSED "raptor_wings_closed"
|
||||
|
||||
@@ -370,14 +370,14 @@ rough example of the "cone" made by the 3 dirs checked
|
||||
|
||||
/// Returns an x and y value require to reverse the transformations made to center an oversized icon
|
||||
/atom/proc/get_oversized_icon_offsets()
|
||||
if (pixel_x == 0 && pixel_y == 0)
|
||||
if (!base_pixel_x && !base_pixel_y && !base_pixel_w && !base_pixel_z)
|
||||
return list("x" = 0, "y" = 0)
|
||||
var/list/icon_dimensions = get_icon_dimensions(icon)
|
||||
var/icon_width = icon_dimensions["width"]
|
||||
var/icon_height = icon_dimensions["height"]
|
||||
return list(
|
||||
"x" = icon_width > ICON_SIZE_X && pixel_x != 0 ? (icon_width - ICON_SIZE_X) * 0.5 : 0,
|
||||
"y" = icon_height > ICON_SIZE_Y && pixel_y != 0 ? (icon_height - ICON_SIZE_Y) * 0.5 : 0,
|
||||
"x" = icon_width > ICON_SIZE_X && (base_pixel_x || base_pixel_w) ? (icon_width - ICON_SIZE_X) * 0.5 : 0,
|
||||
"y" = icon_height > ICON_SIZE_Y && (base_pixel_y || base_pixel_z) ? (icon_height - ICON_SIZE_Y) * 0.5 : 0,
|
||||
)
|
||||
|
||||
/// Helper for easily adding blood from INSIDE a mob to an atom (NOT blood ON the mob)
|
||||
|
||||
@@ -205,8 +205,10 @@ GLOBAL_LIST_INIT(skin_tone_names, list(
|
||||
* @param {icon} icon - The icon file of the cog. Default: 'icons/effects/progressbar.dmi'
|
||||
*
|
||||
* @param {iconstate} iconstate - The icon state of the cog. Default: "Cog"
|
||||
*
|
||||
* @param {mob} bar_override - Mob which should see the bar instead of the user
|
||||
*/
|
||||
/proc/do_after(mob/user, delay, atom/target, timed_action_flags = NONE, progress = TRUE, datum/callback/extra_checks, interaction_key, max_interact_count = 1, hidden = FALSE, icon = 'icons/effects/progressbar.dmi', iconstate = "cog")
|
||||
/proc/do_after(mob/user, delay, atom/target, timed_action_flags = NONE, progress = TRUE, datum/callback/extra_checks, interaction_key, max_interact_count = 1, hidden = FALSE, icon = 'icons/effects/progressbar.dmi', iconstate = "cog", mob/bar_override = null)
|
||||
if(!user)
|
||||
return FALSE
|
||||
if(!isnum(delay))
|
||||
@@ -240,11 +242,11 @@ GLOBAL_LIST_INIT(skin_tone_names, list(
|
||||
var/datum/cogbar/cog
|
||||
|
||||
if(progress)
|
||||
if(user.client)
|
||||
progbar = new(user, delay, target || user)
|
||||
if(user.client || bar_override?.client)
|
||||
progbar = new(bar_override || user, delay, target || user)
|
||||
|
||||
if(!hidden && delay >= 1 SECONDS)
|
||||
cog = new(user, icon, iconstate)
|
||||
cog = new(bar_override || user, icon, iconstate)
|
||||
|
||||
SEND_SIGNAL(user, COMSIG_DO_AFTER_BEGAN)
|
||||
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
*/
|
||||
/datum/ai_planning_subtree/make_babies
|
||||
operational_datums = list(/datum/component/breed)
|
||||
///chance to make babies
|
||||
/// Chance to make babies
|
||||
var/chance = 5
|
||||
///make babies behavior we will use
|
||||
/// Make babies behavior we will use
|
||||
var/datum/ai_behavior/reproduce_behavior = /datum/ai_behavior/make_babies
|
||||
/// Find partner behavior we will use
|
||||
var/datum/ai_behavior/partner_behavior = /datum/ai_behavior/find_partner
|
||||
|
||||
/datum/ai_planning_subtree/make_babies/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
. = ..()
|
||||
@@ -25,4 +27,4 @@
|
||||
return
|
||||
|
||||
// Find target
|
||||
controller.queue_behavior(/datum/ai_behavior/find_partner, BB_BABIES_TARGET, BB_BABIES_PARTNER_TYPES, BB_BABIES_CHILD_TYPES)
|
||||
controller.queue_behavior(partner_behavior, BB_BABIES_TARGET, BB_BABIES_PARTNER_TYPES, BB_BABIES_CHILD_TYPES)
|
||||
|
||||
@@ -4,21 +4,32 @@
|
||||
|
||||
/datum/ai_behavior/find_mom/perform(seconds_per_tick, datum/ai_controller/controller, mom_key, ignore_mom_key, found_mom)
|
||||
var/mob/living_pawn = controller.pawn
|
||||
var/list/mom_types = controller.blackboard[mom_key]
|
||||
var/list/all_moms = list()
|
||||
var/list/mom_types = controller.blackboard[mom_key]
|
||||
var/list/ignore_types = controller.blackboard[ignore_mom_key]
|
||||
|
||||
if(!length(mom_types))
|
||||
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED
|
||||
|
||||
for(var/mob/mother in oview(look_range, living_pawn))
|
||||
if(!is_type_in_list(mother, mom_types))
|
||||
continue
|
||||
if(is_type_in_list(mother, ignore_types)) //so the not permanent baby and the permanent baby subtype dont followed each other
|
||||
continue
|
||||
all_moms += mother
|
||||
if (is_possible_mom(mother, mom_types, ignore_types))
|
||||
all_moms += mother
|
||||
|
||||
if(length(all_moms))
|
||||
controller.set_blackboard_key(found_mom, pick(all_moms))
|
||||
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED
|
||||
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED
|
||||
|
||||
/datum/ai_behavior/find_mom/proc/is_possible_mom(mob/mother, list/mom_types, list/ignore_types)
|
||||
if(!is_type_in_list(mother, mom_types))
|
||||
return FALSE
|
||||
if(is_type_in_list(mother, ignore_types)) // so the not permanent baby and the permanent baby subtype dont followed each other
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/ai_behavior/find_mom/raptor/is_possible_mom(mob/mother, list/mom_types, list/ignore_types)
|
||||
. = ..()
|
||||
if (!. || !istype(mother, /mob/living/basic/raptor))
|
||||
return FALSE
|
||||
var/mob/living/basic/raptor/raptor = mother
|
||||
return raptor.growth_stage == RAPTOR_ADULT
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
var/mob/baby = controller.pawn
|
||||
|
||||
if(QDELETED(target))
|
||||
controller.queue_behavior(/datum/ai_behavior/find_mom, BB_FIND_MOM_TYPES, BB_IGNORE_MOM_TYPES, BB_FOUND_MOM)
|
||||
find_mom(controller)
|
||||
return
|
||||
|
||||
if(get_dist(target, baby) > minimum_distance)
|
||||
@@ -23,3 +23,9 @@
|
||||
controller.queue_behavior(/datum/ai_behavior/perform_emote, "dances around their parent!")
|
||||
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
|
||||
/datum/ai_planning_subtree/look_for_adult/proc/find_mom(datum/ai_controller/controller)
|
||||
controller.queue_behavior(/datum/ai_behavior/find_mom, BB_FIND_MOM_TYPES, BB_IGNORE_MOM_TYPES, BB_FOUND_MOM)
|
||||
|
||||
/datum/ai_planning_subtree/look_for_adult/raptor/find_mom(datum/ai_controller/controller)
|
||||
controller.queue_behavior(/datum/ai_behavior/find_mom/raptor, BB_FIND_MOM_TYPES, BB_FOUND_MOM)
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
/datum/ai_planning_subtree/simple_find_target
|
||||
/// Variable to store target in
|
||||
var/target_key = BB_BASIC_MOB_CURRENT_TARGET
|
||||
/// Targeting strategy key to use
|
||||
var/strategy_key = BB_TARGETING_STRATEGY
|
||||
|
||||
/datum/ai_planning_subtree/simple_find_target/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
. = ..()
|
||||
controller.queue_behavior(/datum/ai_behavior/find_potential_targets, target_key, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
|
||||
controller.queue_behavior(/datum/ai_behavior/find_potential_targets, target_key, strategy_key, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
|
||||
|
||||
// Prevents finding a target if a human is nearby
|
||||
/datum/ai_planning_subtree/simple_find_target/not_while_observed
|
||||
@@ -21,4 +23,7 @@
|
||||
/datum/ai_planning_subtree/simple_find_target/increased_range
|
||||
|
||||
/datum/ai_planning_subtree/simple_find_target/increased_range/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
controller.queue_behavior(/datum/ai_behavior/find_potential_targets/bigger_range, target_key, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
|
||||
controller.queue_behavior(/datum/ai_behavior/find_potential_targets/bigger_range, target_key, strategy_key, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
|
||||
|
||||
/datum/ai_planning_subtree/simple_find_target/hunt
|
||||
strategy_key = BB_HUNT_TARGETING_STRATEGY
|
||||
|
||||
@@ -154,3 +154,6 @@
|
||||
if(!istype(target) || target.has_status_effect(/datum/status_effect/gutted))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/targeting_strategy/basic/exact_match
|
||||
check_factions_exactly = TRUE
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
if(!(target.resistance_flags & INDESTRUCTIBLE))
|
||||
return TRUE
|
||||
|
||||
if(target in living_mob.ai_controller.blackboard[BB_FRIENDS_LIST])
|
||||
if(isliving(target) && (target in living_mob.ai_controller.blackboard[BB_FRIENDS_LIST]))
|
||||
return FALSE
|
||||
|
||||
return ..()
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
// With tongs in hand!
|
||||
BB_TARGET_HELD_ITEM = /obj/item/kitchen/tongs,
|
||||
BB_BABIES_PARTNER_TYPES = list(/mob/living/basic/pet/dog),
|
||||
BB_BABIES_CHILD_TYPES = list(/mob/living/basic/pet/dog/corgi),
|
||||
BB_BABIES_CHILD_TYPES = list(/mob/living/basic/pet/dog/corgi/puppy),
|
||||
)
|
||||
|
||||
planning_subtrees = list(
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
* A component to allow us to breed
|
||||
*/
|
||||
/datum/component/breed
|
||||
/// additional mobs we can breed with
|
||||
/// Additional mobs we can breed with
|
||||
var/list/can_breed_with
|
||||
///weighted list of the possible baby types
|
||||
/// Weighted list of the possible baby types
|
||||
var/list/baby_paths
|
||||
///time to wait after breeding
|
||||
/// Time to wait after breeding
|
||||
var/breed_timer
|
||||
///AI key we set when we're ready to breed
|
||||
/// AI key we set when we're ready to breed
|
||||
var/breed_key = BB_BREED_READY
|
||||
///are we ready to breed?
|
||||
/// Are we ready to breed?
|
||||
var/ready_to_breed = TRUE
|
||||
///callback after we give birth to the child
|
||||
/// Callback after we give birth to the child
|
||||
var/datum/callback/post_birth
|
||||
|
||||
/datum/component/breed/Initialize(list/can_breed_with = list(), breed_timer = 40 SECONDS, baby_paths = list(), post_birth)
|
||||
@@ -44,7 +44,6 @@
|
||||
REMOVE_TRAIT(parent, TRAIT_MOB_BREEDER, REF(src))
|
||||
post_birth = null
|
||||
|
||||
|
||||
/datum/component/breed/proc/breed_with_partner(mob/living/source, mob/living/target)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
/datum/component/happiness/proc/on_eat(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
increase_happiness_level(on_eat_change)
|
||||
change_happiness_level(on_eat_change)
|
||||
|
||||
/datum/component/happiness/proc/on_clean(mob/living/source)
|
||||
SIGNAL_HANDLER
|
||||
@@ -74,7 +74,7 @@
|
||||
return NONE
|
||||
|
||||
COOLDOWN_START(src, groom_cooldown, GROOM_COOLDOWN)
|
||||
increase_happiness_level(on_groom_change)
|
||||
change_happiness_level(on_groom_change)
|
||||
return COMPONENT_CLEANED|COMPONENT_CLEANED_GAIN_XP
|
||||
|
||||
/datum/component/happiness/proc/on_petted(datum/source, mob/living/petter, list/modifiers)
|
||||
@@ -91,42 +91,55 @@
|
||||
/datum/component/happiness/proc/pet_animal()
|
||||
if(!COOLDOWN_FINISHED(src, pet_cooldown))
|
||||
return
|
||||
increase_happiness_level(on_petted_change)
|
||||
change_happiness_level(on_petted_change)
|
||||
COOLDOWN_START(src, pet_cooldown, PET_COOLDOWN)
|
||||
|
||||
|
||||
/datum/component/happiness/proc/increase_happiness_level(amount)
|
||||
happiness_level = min(happiness_level + amount, maximum_happiness)
|
||||
if(!HAS_TRAIT(parent, TRAIT_MOB_HIDE_HAPPINESS))
|
||||
var/mob/living/living_parent = parent
|
||||
/datum/component/happiness/proc/change_happiness_level(amount)
|
||||
var/old_happiness = happiness_level
|
||||
happiness_level = clamp(happiness_level + amount, 0, maximum_happiness)
|
||||
var/happiness_percentage = happiness_level / maximum_happiness
|
||||
var/old_percentage = old_happiness / maximum_happiness
|
||||
|
||||
var/old_threshold = 0
|
||||
var/new_threshold = 0
|
||||
for(var/check_percentage in callback_percentages)
|
||||
if (check_percentage <= old_percentage)
|
||||
old_threshold = check_percentage
|
||||
if (check_percentage <= happiness_percentage)
|
||||
new_threshold = check_percentage
|
||||
|
||||
if (old_threshold != new_threshold)
|
||||
SEND_SIGNAL(parent, COMSIG_MOB_HAPPINESS_CHANGE, happiness_percentage)
|
||||
happiness_callback?.Invoke(happiness_percentage)
|
||||
|
||||
var/mob/living/living_parent = parent
|
||||
living_parent.ai_controller?.set_blackboard_key(blackboard_key, happiness_percentage)
|
||||
|
||||
if(!HAS_TRAIT(parent, TRAIT_MOB_HIDE_HAPPINESS) && amount > 0)
|
||||
new /obj/effect/temp_visual/heart(living_parent.loc)
|
||||
living_parent.spin(spintime = 2 SECONDS, speed = 1)
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
|
||||
if (happiness_level > 0)
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
|
||||
/datum/component/happiness/proc/view_happiness(mob/living/source, mob/living/clicker)
|
||||
if(HAS_TRAIT(source, TRAIT_MOB_HIDE_HAPPINESS) || !istype(clicker) || !COOLDOWN_FINISHED(src, happiness_inspect) || !source.IsReachableBy(clicker))
|
||||
return
|
||||
var/y_position = source.get_cached_height() + 1
|
||||
var/obj/effect/overlay/happiness_overlay/hearts = new
|
||||
hearts.pixel_w -= source.base_pixel_x + source.base_pixel_w
|
||||
hearts.pixel_y = y_position
|
||||
hearts.set_hearts(happiness_level/maximum_happiness)
|
||||
hearts.set_hearts(happiness_level / maximum_happiness)
|
||||
source.vis_contents += hearts
|
||||
COOLDOWN_START(src, happiness_inspect, INSPECT_TIMER)
|
||||
|
||||
|
||||
/datum/component/happiness/process()
|
||||
var/mob/living/living_parent = parent
|
||||
var/happiness_percentage = happiness_level/maximum_happiness
|
||||
living_parent.ai_controller?.set_blackboard_key(blackboard_key, happiness_percentage)
|
||||
var/check_percentage_in_list = round(happiness_percentage * 100, 1)
|
||||
if(check_percentage_in_list in callback_percentages)
|
||||
SEND_SIGNAL(parent, COMSIG_MOB_HAPPINESS_CHANGE, happiness_percentage)
|
||||
happiness_callback?.Invoke(happiness_percentage)
|
||||
|
||||
if(happiness_level <= 0)
|
||||
return PROCESS_KILL
|
||||
var/mob/living/living_parent = parent
|
||||
var/modifier = living_parent.ai_controller?.blackboard[BB_BASIC_DEPRESSED] ? 2 : 1
|
||||
happiness_level = max(0, happiness_level - modifier)
|
||||
change_happiness_level(-modifier)
|
||||
|
||||
/obj/effect/overlay/happiness_overlay
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
|
||||
@@ -45,6 +45,8 @@
|
||||
var/required_modifier
|
||||
/// Callback to run after healing a mob
|
||||
var/datum/callback/after_healed
|
||||
/// Callback to run to get a multiplier for our healing value
|
||||
var/datum/callback/healing_multiplier
|
||||
|
||||
/datum/component/healing_touch/Initialize(
|
||||
heal_brute = 20,
|
||||
@@ -65,6 +67,7 @@
|
||||
heal_color = COLOR_HEALING_CYAN,
|
||||
required_modifier = null,
|
||||
datum/callback/after_healed = null,
|
||||
datum/callback/healing_multiplier = null,
|
||||
)
|
||||
if (!isliving(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
@@ -87,6 +90,7 @@
|
||||
src.heal_color = heal_color
|
||||
src.required_modifier = required_modifier
|
||||
src.after_healed = after_healed
|
||||
src.healing_multiplier = healing_multiplier
|
||||
|
||||
RegisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(try_healing)) // Players
|
||||
RegisterSignal(parent, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(try_healing)) // NPCs
|
||||
@@ -190,15 +194,21 @@
|
||||
if (complete_text)
|
||||
healer.visible_message(span_notice("[format_string(complete_text, healer, target)]"))
|
||||
|
||||
var/mult = 1
|
||||
if (healing_multiplier)
|
||||
mult = healing_multiplier.Invoke(healer, target)
|
||||
if (mult == 0)
|
||||
return
|
||||
|
||||
var/healed = target.heal_overall_damage(
|
||||
brute = heal_brute,
|
||||
burn = heal_burn,
|
||||
stamina = heal_stamina,
|
||||
brute = heal_brute * mult,
|
||||
burn = heal_burn * mult,
|
||||
stamina = heal_stamina * mult,
|
||||
required_bodytype = required_bodytype,
|
||||
updating_health = FALSE,
|
||||
)
|
||||
healed += target.adjustOxyLoss(-heal_oxy, updating_health = FALSE, required_biotype = valid_biotypes)
|
||||
healed += target.adjustToxLoss(-heal_tox, updating_health = FALSE, required_biotype = valid_biotypes)
|
||||
healed += target.adjustOxyLoss(-heal_oxy * mult, updating_health = FALSE, required_biotype = valid_biotypes)
|
||||
healed += target.adjustToxLoss(-heal_tox * mult, updating_health = FALSE, required_biotype = valid_biotypes)
|
||||
if (healed <= 0)
|
||||
return
|
||||
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
/// Component given to mobs that can mine when moving
|
||||
/datum/component/proficient_miner
|
||||
/// Toolspeed for mining, 0 will cause it to instamine rock
|
||||
var/mining_speed = 0
|
||||
/// Should we pass the do_after visuals to our rider if we are a mob?
|
||||
var/pass_driver = FALSE
|
||||
/// Last tick when we bumpmined. Prevents diagonal bumpnining being thrice as fast as normal
|
||||
var/last_bumpmine_tick = -1
|
||||
|
||||
/datum/component/proficient_miner/Initialize()
|
||||
/datum/component/proficient_miner/Initialize(mining_speed = 0, pass_driver = FALSE)
|
||||
if (!ismovable(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
src.mining_speed = mining_speed
|
||||
src.pass_driver = pass_driver
|
||||
|
||||
/datum/component/proficient_miner/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_BUMP, PROC_REF(on_bump))
|
||||
@@ -26,12 +32,37 @@
|
||||
return
|
||||
|
||||
var/turf/closed/mineral/mineral_wall = target
|
||||
if(!istype(mineral_wall, /turf/closed/mineral/gibtonite))
|
||||
last_bumpmine_tick = world.time
|
||||
mineral_wall.gets_drilled(source)
|
||||
if(istype(mineral_wall, /turf/closed/mineral/gibtonite))
|
||||
var/turf/closed/mineral/gibtonite/gibtonite_wall = mineral_wall
|
||||
if(gibtonite_wall.stage != GIBTONITE_UNSTRUCK)
|
||||
return
|
||||
|
||||
if(user && mining_speed > 0)
|
||||
INVOKE_ASYNC(src, PROC_REF(slow_mine), user, target)
|
||||
return
|
||||
|
||||
var/turf/closed/mineral/gibtonite/gibtonite_wall = mineral_wall
|
||||
if(gibtonite_wall.stage == GIBTONITE_UNSTRUCK)
|
||||
last_bumpmine_tick = world.time
|
||||
mineral_wall.gets_drilled(source)
|
||||
last_bumpmine_tick = world.time
|
||||
mineral_wall.gets_drilled(source)
|
||||
|
||||
/datum/component/proficient_miner/proc/slow_mine(mob/living/user, turf/closed/mineral/mineral_wall)
|
||||
if(TIMER_COOLDOWN_RUNNING(mineral_wall, REF(user))) //prevents mining turfs in progress
|
||||
return
|
||||
|
||||
var/mining_delay = mineral_wall.tool_mine_speed * mining_speed
|
||||
TIMER_COOLDOWN_START(mineral_wall, REF(user), mining_delay)
|
||||
var/static/list/mine_sounds = list('sound/effects/pickaxe/picaxe1.ogg', 'sound/effects/pickaxe/picaxe2.ogg', 'sound/effects/pickaxe/picaxe3.ogg')
|
||||
playsound(user, pick(mine_sounds), 50)
|
||||
|
||||
var/mob/living/driver = null
|
||||
if (pass_driver && length(user.buckled_mobs))
|
||||
driver = user.buckled_mobs[1]
|
||||
|
||||
if(!do_after(user, mining_delay, mineral_wall, bar_override = driver))
|
||||
TIMER_COOLDOWN_END(mineral_wall, REF(user)) //if we fail we can start again immediately
|
||||
return
|
||||
|
||||
if (mining_delay > MIN_TOOL_SOUND_DELAY)
|
||||
playsound(user, pick(mine_sounds), 50)
|
||||
|
||||
if(istype(mineral_wall))
|
||||
mineral_wall.gets_drilled(driver || user)
|
||||
|
||||
@@ -119,8 +119,7 @@
|
||||
return COMPONENT_DRIVER_BLOCK_MOVE
|
||||
var/mob/living/living_parent = parent
|
||||
step(living_parent, direction)
|
||||
var/datum/movespeed_modifier/slowdown = get_cached_movespeed_modifier(living_parent.get_move_intent_slowdown())
|
||||
var/modified_move_delay = uses_native_speed ? living_parent.cached_multiplicative_slowdown - slowdown?.multiplicative_slowdown : vehicle_move_delay
|
||||
var/modified_move_delay = uses_native_speed ? living_parent.cached_multiplicative_slowdown : vehicle_move_delay
|
||||
if(HAS_TRAIT(user, TRAIT_ROUGHRIDER)) // YEEHAW!
|
||||
switch(HAS_TRAIT(user, TRAIT_PRIMITIVE) ? SANITY_LEVEL_GREAT : user.mob_mood?.sanity_level)
|
||||
if(SANITY_LEVEL_GREAT)
|
||||
@@ -133,6 +132,8 @@
|
||||
modified_move_delay *= 1.1
|
||||
if(SANITY_LEVEL_INSANE)
|
||||
modified_move_delay *= 1.2
|
||||
if(NSCOMPONENT(direction) && EWCOMPONENT(direction))
|
||||
modified_move_delay = FLOOR(modified_move_delay * sqrt(2), world.tick_lag)
|
||||
COOLDOWN_START(src, vehicle_move_cooldown, modified_move_delay)
|
||||
return ..()
|
||||
|
||||
@@ -675,18 +676,11 @@
|
||||
force_dismount(buckled_mob, throw_range = 2, gentle = TRUE)
|
||||
|
||||
/datum/component/riding/creature/raptor/get_rider_offsets_and_layers(pass_index, mob/offsetter)
|
||||
if(!SSmapping.is_planetary())
|
||||
return list(
|
||||
TEXT_NORTH = list(-1, 7),
|
||||
TEXT_SOUTH = list(2, 10),
|
||||
TEXT_EAST = list(0, 7),
|
||||
TEXT_WEST = list(0, 7),
|
||||
)
|
||||
return list(
|
||||
TEXT_NORTH = list(0, 7),
|
||||
TEXT_SOUTH = list(0, 10),
|
||||
TEXT_EAST = list(-3, 9),
|
||||
TEXT_WEST = list(3, 9),
|
||||
TEXT_NORTH = list(-1, 7),
|
||||
TEXT_SOUTH = list(2, 10),
|
||||
TEXT_EAST = list(0, 7),
|
||||
TEXT_WEST = list(0, 7),
|
||||
)
|
||||
|
||||
/datum/component/riding/creature/raptor/get_parent_offsets_and_layers()
|
||||
@@ -705,3 +699,43 @@
|
||||
|
||||
/datum/component/riding/creature/raptor/combat
|
||||
ai_behavior_while_ridden = RIDING_PAUSE_AI_MOVEMENT
|
||||
|
||||
/datum/component/riding/creature/raptor/healer/vehicle_mob_buckle(mob/living/ridden, mob/living/rider, force)
|
||||
RegisterSignal(rider, COMSIG_MOB_STATCHANGE, PROC_REF(on_buckled_stat_change))
|
||||
return ..()
|
||||
|
||||
/datum/component/riding/creature/raptor/healer/vehicle_mob_unbuckle(mob/living/formerly_ridden, mob/living/former_rider, force)
|
||||
UnregisterSignal(former_rider, COMSIG_MOB_STATCHANGE)
|
||||
return ..()
|
||||
|
||||
/datum/component/riding/creature/raptor/healer/proc/on_buckled_stat_change(mob/living/source, new_stat, old_stat)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
var/mob/living/basic/raptor/raptor = source.buckled
|
||||
if (!istype(raptor)) // what
|
||||
UnregisterSignal(source, COMSIG_MOB_STATCHANGE)
|
||||
return
|
||||
|
||||
// Heal the owner and flee whatever might've attacked them
|
||||
if (new_stat == CONSCIOUS || new_stat == DEAD || old_stat != CONSCIOUS || !raptor.ai_controller)
|
||||
ADD_TRAIT(raptor, TRAIT_AI_PAUSED, REF(src))
|
||||
return
|
||||
|
||||
REMOVE_TRAIT(raptor, TRAIT_AI_PAUSED, REF(src))
|
||||
// Rip bozo, but you're not our friend
|
||||
if (source in raptor.ai_controller.blackboard[BB_FRIENDS_LIST])
|
||||
raptor.ai_controller.set_blackboard_key(BB_INJURED_RAPTOR, source)
|
||||
|
||||
for (var/mob/living/possible_hostile in view(5, raptor))
|
||||
if (possible_hostile.stat || possible_hostile.invisibility > raptor.see_invisible || source.faction_check_atom(possible_hostile))
|
||||
continue
|
||||
raptor.ai_controller.set_blackboard_key(BB_BASIC_MOB_FLEE_TARGET, possible_hostile)
|
||||
break
|
||||
|
||||
/datum/component/riding/creature/raptor/small/get_rider_offsets_and_layers(pass_index, mob/offsetter)
|
||||
return list(
|
||||
TEXT_NORTH = list(-1, 5),
|
||||
TEXT_SOUTH = list(2, 8),
|
||||
TEXT_EAST = list(0, 5),
|
||||
TEXT_WEST = list(0, 5),
|
||||
)
|
||||
|
||||
@@ -97,7 +97,10 @@
|
||||
return
|
||||
|
||||
step(movable_parent, direction)
|
||||
COOLDOWN_START(src, vehicle_move_cooldown, vehicle_move_delay)
|
||||
var/move_delay = vehicle_move_delay
|
||||
if(NSCOMPONENT(direction) && EWCOMPONENT(direction))
|
||||
move_delay = FLOOR(move_delay * sqrt(2), world.tick_lag)
|
||||
COOLDOWN_START(src, vehicle_move_cooldown, move_delay)
|
||||
|
||||
if(QDELETED(src))
|
||||
return
|
||||
|
||||
@@ -16,10 +16,12 @@
|
||||
var/drinking
|
||||
/// If true, we put food in our tummy instead of deleting it
|
||||
var/add_to_contents
|
||||
/// Types the animal can eat.
|
||||
/// If true, when add_to_contents would put the item into contents but when used for healing, the item is consumed instead
|
||||
var/consume_healing
|
||||
/// Types the animal can eat. Can be an assoc list with amount to heal/damage the mob by
|
||||
var/list/food_types
|
||||
|
||||
/datum/element/basic_eating/Attach(datum/target, heal_amt = 0, damage_amount = 0, damage_type = null, drinking = FALSE, add_to_contents = FALSE, food_types = list())
|
||||
/datum/element/basic_eating/Attach(datum/target, heal_amt = 0, damage_amount = 0, damage_type = null, drinking = FALSE, add_to_contents = FALSE, consume_healing = TRUE, food_types = list())
|
||||
. = ..()
|
||||
|
||||
if(!isliving(target))
|
||||
@@ -31,6 +33,7 @@
|
||||
src.damage_type = damage_type
|
||||
src.drinking = drinking
|
||||
src.add_to_contents = add_to_contents
|
||||
src.consume_healing = consume_healing
|
||||
src.food_types = food_types
|
||||
|
||||
RegisterSignal(target, COMSIG_ATOM_ITEM_INTERACTION, PROC_REF(try_feed))
|
||||
@@ -66,7 +69,8 @@
|
||||
/datum/element/basic_eating/proc/try_eating(mob/living/eater, atom/target, mob/living/feeder)
|
||||
if(!is_type_in_list(target, food_types))
|
||||
return FALSE
|
||||
if(SEND_SIGNAL(eater, COMSIG_MOB_PRE_EAT, target, feeder) & COMSIG_MOB_CANCEL_EAT)
|
||||
var/list/effect_mult = list()
|
||||
if(SEND_SIGNAL(eater, COMSIG_MOB_PRE_EAT, target, feeder, effect_mult) & COMSIG_MOB_CANCEL_EAT)
|
||||
return FALSE
|
||||
if(add_to_contents && !ismovable(target))
|
||||
return FALSE
|
||||
@@ -76,22 +80,44 @@
|
||||
else
|
||||
eat_verb = pick("bite","chew","nibble","gnaw","gobble","chomp")
|
||||
|
||||
if (heal_amt > 0)
|
||||
var/healed = heal_amt && eater.health < eater.maxHealth
|
||||
eater.heal_overall_damage(heal_amt)
|
||||
var/best_match = null
|
||||
var/best_value = 0
|
||||
for (var/food_path in food_types)
|
||||
// Not an assoc list
|
||||
if (isnull(food_types[food_path]))
|
||||
break
|
||||
if (istype(target, food_path) && (!best_match || ispath(food_path, best_match)))
|
||||
best_match = food_path
|
||||
best_value = food_types[food_path]
|
||||
|
||||
var/to_heal = heal_amt
|
||||
var/to_damage = damage_amount
|
||||
|
||||
if (best_match)
|
||||
to_heal = 0
|
||||
to_damage = 0
|
||||
if (best_value > 0)
|
||||
to_heal = best_value
|
||||
else if (best_value < 0)
|
||||
to_damage = -best_value
|
||||
|
||||
for (var/mult in effect_mult)
|
||||
to_heal *= mult
|
||||
to_damage *= mult
|
||||
|
||||
if (to_heal > 0)
|
||||
var/healed = eater.heal_overall_damage(to_heal)
|
||||
eater.visible_message(span_notice("[eater] [eat_verb]s [target]."), span_notice("You [eat_verb] [target][healed ? ", restoring some health" : ""]."))
|
||||
|
||||
else if (damage_amount > 0 && damage_type)
|
||||
eater.apply_damage(damage_amount, damage_type)
|
||||
eater.visible_message(span_notice("[eater] [eat_verb]s [target], and seems to hurt itself."), span_notice("You [eat_verb] [target], hurting yourself in the process."))
|
||||
|
||||
else if (to_damage > 0 && damage_type)
|
||||
var/damaged = eater.apply_damage(to_damage, damage_type)
|
||||
eater.visible_message(span_notice("[eater] [eat_verb]s [target][damaged ? ", and seems to hurt [eater.p_themselves()]!" : "."]"), span_notice("You [eat_verb] [target][damaged ? ", hurting yourself in the process" : ""]."))
|
||||
else
|
||||
eater.visible_message(span_notice("[eater] [eat_verb]s [target]."), span_notice("You [eat_verb] [target]."))
|
||||
|
||||
finish_eating(eater, target, feeder)
|
||||
finish_eating(eater, target, feeder, to_heal)
|
||||
return TRUE
|
||||
|
||||
/datum/element/basic_eating/proc/finish_eating(mob/living/eater, atom/target, mob/living/feeder)
|
||||
/datum/element/basic_eating/proc/finish_eating(mob/living/eater, atom/target, mob/living/feeder, to_heal)
|
||||
set waitfor = FALSE
|
||||
if(drinking)
|
||||
playsound(eater.loc,'sound/items/drink.ogg', rand(10,50), TRUE)
|
||||
@@ -104,10 +130,12 @@
|
||||
var/obj/item/stack/food_stack = target
|
||||
final_target = food_stack.split_stack(1)
|
||||
|
||||
eater.log_message("has eaten [target], [add_to_contents ? "swallowing it" : "destroying it"]!", LOG_ATTACK)
|
||||
var/devour = add_to_contents && !to_heal
|
||||
eater.log_message("has eaten [target], [devour ? "swallowing it" : "destroying it"]!", LOG_ATTACK)
|
||||
|
||||
if (add_to_contents)
|
||||
if (devour)
|
||||
var/atom/movable/movable_target = final_target
|
||||
movable_target.forceMove(eater)
|
||||
else
|
||||
qdel(final_target)
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/// Element which influences raptor children upon owner's consumption as food
|
||||
/datum/element/raptor_food
|
||||
element_flags = ELEMENT_BESPOKE
|
||||
argument_hash_start_idx = 2
|
||||
/// Flat damage modifier
|
||||
var/attack_modifier = null
|
||||
/// Flat health modifier
|
||||
var/health_modifier = null
|
||||
/// Speed modifier
|
||||
var/speed_modifier = null
|
||||
/// Primary ability stat modifier
|
||||
/// Multiplier equates to 1 + this
|
||||
var/ability_modifier = null
|
||||
/// Growth rate modifier
|
||||
/// Multiplier equates to 1 + this
|
||||
var/growth_modifier = null
|
||||
/// Personality traits the child may get
|
||||
var/list/personality_traits = null
|
||||
/// Offspring color probability modifiers
|
||||
var/list/color_chances = null
|
||||
|
||||
/datum/element/raptor_food/Attach(obj/item/target, attack_modifier, health_modifier, speed_modifier, ability_modifier, growth_modifier, list/personality_traits, list/color_chances)
|
||||
. = ..()
|
||||
if (!isitem(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
src.attack_modifier = attack_modifier
|
||||
src.health_modifier = health_modifier
|
||||
src.speed_modifier = speed_modifier
|
||||
src.ability_modifier = ability_modifier
|
||||
src.growth_modifier = growth_modifier
|
||||
src.personality_traits = personality_traits
|
||||
src.color_chances = color_chances
|
||||
RegisterSignal(target, COMSIG_ITEM_EATEN_BY_BASIC_MOB, PROC_REF(on_eaten))
|
||||
RegisterSignal(target, COMSIG_ATOM_EXAMINE_MORE, PROC_REF(on_examine_more))
|
||||
|
||||
/datum/element/raptor_food/Detach(datum/source, ...)
|
||||
UnregisterSignal(source, list(COMSIG_ITEM_EATEN_BY_BASIC_MOB, COMSIG_ATOM_EXAMINE_MORE))
|
||||
return ..()
|
||||
|
||||
/datum/element/raptor_food/proc/on_examine_more(obj/item/source, mob/examiner, list/examine_list)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if (!istype(examiner.buckled, /mob/living/basic/raptor))
|
||||
return
|
||||
|
||||
// Just to check for priority
|
||||
var/strognest_effect = max(attack_modifier, health_modifier, speed_modifier, ability_modifier, growth_modifier, 0)
|
||||
|
||||
// Only personality or color probability effects, or just pure negatives
|
||||
if (strognest_effect == 0)
|
||||
examine_list += span_notice("You reckon this would have unique effects on your raptor's offspring if you fed it to them...")
|
||||
return
|
||||
|
||||
if (strognest_effect == attack_modifier)
|
||||
examine_list += span_notice("You reckon this would have make your raptor's offspring stronger if you fed it to them...")
|
||||
else if (strognest_effect == health_modifier)
|
||||
examine_list += span_notice("You reckon this would have make your raptor's offspring tougher if you fed it to them...")
|
||||
else if (strognest_effect == speed_modifier)
|
||||
examine_list += span_notice("You reckon this would have make your raptor's offspring faster if you fed it to them...")
|
||||
else if (strognest_effect == ability_modifier)
|
||||
examine_list += span_notice("You reckon this would have make your raptor's offspring more capable if you fed it to them...")
|
||||
else if (strognest_effect == growth_modifier)
|
||||
examine_list += span_notice("You reckon this would have make your raptor's offspring grow faster if you fed it to them...")
|
||||
|
||||
/datum/element/raptor_food/proc/on_eaten(obj/item/source, mob/living/eater, mob/living/feeder)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if (!istype(eater, /mob/living/basic/raptor))
|
||||
return
|
||||
|
||||
var/mob/living/basic/raptor/raptor = eater
|
||||
var/list/our_food = raptor.inherited_stats.foods_eaten[source.type]
|
||||
if (our_food)
|
||||
our_food["amount"] += 1
|
||||
return
|
||||
|
||||
raptor.inherited_stats.foods_eaten[source.type] = list(
|
||||
"amount" = 1,
|
||||
"attack" = attack_modifier,
|
||||
"health" = health_modifier,
|
||||
"speed" = speed_modifier,
|
||||
"ability" = ability_modifier,
|
||||
"growth" = growth_modifier,
|
||||
"traits" = personality_traits?.Copy(),
|
||||
"color_chances" = color_chances?.Copy(),
|
||||
)
|
||||
|
||||
@@ -791,8 +791,9 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
|
||||
return NONE
|
||||
|
||||
if(istype(over_object, /atom/movable/screen/inventory/hand))
|
||||
if(real_location.loc != user || !user.can_perform_action(parent, FORBID_TELEKINESIS_REACH | ALLOW_RESTING))
|
||||
if(parent.loc != user || !user.can_perform_action(parent, FORBID_TELEKINESIS_REACH | ALLOW_RESTING))
|
||||
return NONE
|
||||
|
||||
if(isitem(parent))
|
||||
var/obj/item/item_parent = parent
|
||||
if(!item_parent.can_mob_unequip(user))
|
||||
@@ -803,15 +804,20 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
|
||||
parent.add_fingerprint(user)
|
||||
return COMPONENT_CANCEL_MOUSEDROP_ONTO
|
||||
|
||||
if(ismob(over_object))
|
||||
if(over_object != user || !user.can_perform_action(parent, FORBID_TELEKINESIS_REACH | ALLOW_RESTING))
|
||||
if(over_object == user)
|
||||
if(!user.can_perform_action(parent, FORBID_TELEKINESIS_REACH | ALLOW_RESTING))
|
||||
return NONE
|
||||
|
||||
if(isliving(parent) && user.pulling == parent)
|
||||
var/mob/living/as_living = parent
|
||||
if(as_living.can_be_held)
|
||||
return
|
||||
|
||||
parent.add_fingerprint(user)
|
||||
INVOKE_ASYNC(src, PROC_REF(open_storage), user)
|
||||
return COMPONENT_CANCEL_MOUSEDROP_ONTO
|
||||
|
||||
if(istype(over_object, /atom/movable/screen))
|
||||
if(istype(over_object, /atom/movable/screen) || ismob(over_object))
|
||||
return NONE
|
||||
|
||||
if(!user.can_perform_action(over_object, FORBID_TELEKINESIS_REACH))
|
||||
|
||||
@@ -55,11 +55,41 @@
|
||||
desc = "Chance to spawn a rare shiny version."
|
||||
icon = 'icons/mob/simple/lavaland/raptor_big.dmi'
|
||||
icon_state = "raptor_red"
|
||||
pixel_x = -12
|
||||
loot = list(
|
||||
/mob/living/basic/raptor/red = 20,
|
||||
/mob/living/basic/raptor/white = 20,
|
||||
/mob/living/basic/raptor/purple = 20,
|
||||
/mob/living/basic/raptor/green = 20,
|
||||
/mob/living/basic/raptor/yellow = 20,
|
||||
/mob/living/basic/raptor/red = 25,
|
||||
/mob/living/basic/raptor/white = 25,
|
||||
/mob/living/basic/raptor/purple = 25,
|
||||
/mob/living/basic/raptor/green = 25,
|
||||
/mob/living/basic/raptor/yellow = 25,
|
||||
/mob/living/basic/raptor/blue = 25,
|
||||
/mob/living/basic/raptor/black = 1,
|
||||
)
|
||||
|
||||
/obj/effect/spawner/random/lavaland_mob/raptor/young
|
||||
name = "random raptor youngling"
|
||||
icon_state = "young_red"
|
||||
loot = list(
|
||||
/mob/living/basic/raptor/young/red = 25,
|
||||
/mob/living/basic/raptor/young/white = 25,
|
||||
/mob/living/basic/raptor/young/purple = 25,
|
||||
/mob/living/basic/raptor/young/green = 25,
|
||||
/mob/living/basic/raptor/young/yellow = 25,
|
||||
/mob/living/basic/raptor/young/blue = 25,
|
||||
/mob/living/basic/raptor/young/black = 1,
|
||||
)
|
||||
|
||||
/obj/effect/spawner/random/lavaland_mob/raptor/baby
|
||||
name = "random raptor chick"
|
||||
icon = 'icons/mob/simple/lavaland/raptor_baby.dmi'
|
||||
icon_state = "baby_red"
|
||||
pixel_x = 0
|
||||
loot = list(
|
||||
/mob/living/basic/raptor/baby/red = 25,
|
||||
/mob/living/basic/raptor/baby/white = 25,
|
||||
/mob/living/basic/raptor/baby/purple = 25,
|
||||
/mob/living/basic/raptor/baby/green = 25,
|
||||
/mob/living/basic/raptor/baby/yellow = 25,
|
||||
/mob/living/basic/raptor/baby/blue = 25,
|
||||
/mob/living/basic/raptor/baby/black = 1,
|
||||
)
|
||||
|
||||
@@ -211,6 +211,10 @@
|
||||
foodtypes = RAW | MEAT | BUGS
|
||||
blood_decal_type = /obj/effect/decal/cleanable/insectguts
|
||||
|
||||
/obj/item/food/meat/slab/bugmeat/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/raptor_food, health_modifier = 2, color_chances = string_list(list(/datum/raptor_color/green = 2)))
|
||||
|
||||
/obj/item/food/meat/slab/mouse
|
||||
name = "mouse meat"
|
||||
desc = "A slab of mouse meat. Best not eat it raw."
|
||||
@@ -337,6 +341,10 @@
|
||||
tastes = list("meat" = 1)
|
||||
foodtypes = RAW | MEAT | TOXIC
|
||||
|
||||
/obj/item/food/meat/slab/goliath/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/raptor_food, attack_modifier = 0.5, speed_modifier = -0.05, color_chances = string_list(list(/datum/raptor_color/red = 5)))
|
||||
|
||||
/obj/item/food/meat/slab/goliath/burn()
|
||||
visible_message(span_notice("[src] finishes cooking!"))
|
||||
new /obj/item/food/meat/steak/goliath(loc)
|
||||
@@ -569,6 +577,10 @@
|
||||
trash_type = null
|
||||
tastes = list("meat" = 1, "rock" = 1)
|
||||
|
||||
/obj/item/food/meat/steak/goliath/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/raptor_food, attack_modifier = 1, speed_modifier = -0.075, color_chances = string_list(list(/datum/raptor_color/red = 7)))
|
||||
|
||||
/obj/item/food/meat/steak/gondola
|
||||
name = "gondola steak"
|
||||
tastes = list("meat" = 1, "tranquility" = 1)
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
. = ..()
|
||||
pixel_x = rand(-5, 5)
|
||||
pixel_y = rand(-5, 5)
|
||||
AddElement(/datum/element/raptor_food, ability_modifier = 0.05, attack_modifier = 0.5, color_chances = string_list(list(/datum/raptor_color/black = 1)))
|
||||
|
||||
/obj/item/stack/ore/bluespace_crystal/get_part_rating()
|
||||
return 1
|
||||
|
||||
@@ -205,6 +205,7 @@
|
||||
sound_on_success = 'sound/items/weapons/parry.ogg',\
|
||||
effect_on_success = /obj/effect/temp_visual/guardian/phase,\
|
||||
)
|
||||
AddElement(/datum/element/raptor_food, attack_modifier = 1.5, growth_modifier = -0.075)
|
||||
|
||||
/obj/item/fish/lavaloop/get_fish_taste()
|
||||
return list("chewy fish" = 2)
|
||||
|
||||
@@ -230,6 +230,10 @@
|
||||
wine_power = 50
|
||||
foodtypes = FRUIT
|
||||
|
||||
/obj/item/food/grown/ash_flora/cactus_fruit/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/raptor_food, growth_modifier = 0.1, ability_modifier = -0.05)
|
||||
|
||||
/obj/item/food/grown/ash_flora/seraka
|
||||
name = "seraka cap"
|
||||
desc = "Small, deeply flavourful mushrooms originally native to Tizira."
|
||||
@@ -237,6 +241,10 @@
|
||||
seed = /obj/item/seeds/lavaland/seraka
|
||||
wine_power = 40
|
||||
|
||||
/obj/item/food/grown/ash_flora/seraka/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/raptor_food, ability_modifier = 0.1)
|
||||
|
||||
/obj/item/food/grown/ash_flora/fireblossom
|
||||
name = "fire blossom"
|
||||
desc = "A flower from a fire blossom."
|
||||
@@ -245,7 +253,12 @@
|
||||
seed = /obj/item/seeds/lavaland/fireblossom
|
||||
wine_power = 40
|
||||
|
||||
//SEEDS
|
||||
/obj/item/food/grown/ash_flora/fireblossom/Initialize(mapload)
|
||||
. = ..()
|
||||
// Fire flowers make fireproof raptors
|
||||
AddElement(/datum/element/raptor_food, color_chances = string_list(list(/datum/raptor_color/blue = 5)))
|
||||
|
||||
// SEEDS
|
||||
|
||||
/obj/item/seeds/lavaland
|
||||
name = "lavaland seeds"
|
||||
|
||||
@@ -215,6 +215,10 @@ GLOBAL_LIST_INIT(sand_recipes, list(\
|
||||
scan_state = "rock_diamond"
|
||||
merge_type = /obj/item/stack/ore/diamond
|
||||
|
||||
/obj/item/stack/ore/diamond/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/raptor_food, speed_modifier = 0.05, health_modifier = -1, color_chances = string_list(list(/datum/raptor_color/yellow = 3)))
|
||||
|
||||
/obj/item/stack/ore/diamond/five
|
||||
amount = 5
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
lighting_cutoff_blue = 25
|
||||
can_be_held = TRUE
|
||||
worn_slot_flags = ITEM_SLOT_HEAD
|
||||
inhand_holder_type = /obj/item/mob_holder/drone
|
||||
/// `TRUE` if we have picked our visual appearance, `FALSE` otherwise (default)
|
||||
var/picked = FALSE
|
||||
/// Stored drone color, restored when unhacked
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
if(beegent)
|
||||
reee[beegent.type] = 5
|
||||
holder.AddComponentFrom(SOURCE_EDIBLE_INNATE, /datum/component/edible, reee, null, BEE_FOODGROUPS, 10, 0, list("bee"), null, 10)
|
||||
SEND_SIGNAL(src, COMSIG_LIVING_SCOOPED_UP, picker, holder)
|
||||
picker.visible_message(span_warning("[picker] scoops up [src]!"))
|
||||
picker.put_in_hands(holder)
|
||||
|
||||
|
||||
@@ -1,12 +1,3 @@
|
||||
GLOBAL_LIST_INIT(raptor_growth_paths, list(
|
||||
/mob/living/basic/raptor/baby_raptor/red = list(RAPTOR_PURPLE, RAPTOR_WHITE),
|
||||
/mob/living/basic/raptor/baby_raptor/white = list(RAPTOR_GREEN, RAPTOR_PURPLE),
|
||||
/mob/living/basic/raptor/baby_raptor/purple = list(RAPTOR_GREEN, RAPTOR_WHITE),
|
||||
/mob/living/basic/raptor/baby_raptor/yellow = list(RAPTOR_GREEN, RAPTOR_RED),
|
||||
/mob/living/basic/raptor/baby_raptor/green = list(RAPTOR_RED, RAPTOR_YELLOW),
|
||||
/mob/living/basic/raptor/baby_raptor/blue = list(RAPTOR_RED, RAPTOR_PURPLE)
|
||||
))
|
||||
|
||||
GLOBAL_LIST_INIT(raptor_inherit_traits, list(
|
||||
BB_BASIC_DEPRESSED = "Depressed",
|
||||
BB_RAPTOR_MOTHERLY = "Motherly",
|
||||
@@ -16,23 +7,25 @@ GLOBAL_LIST_INIT(raptor_inherit_traits, list(
|
||||
|
||||
GLOBAL_LIST_EMPTY(raptor_population)
|
||||
|
||||
#define HAPPINESS_BOOST_DAMPENER 0.3
|
||||
|
||||
/// Innate raptor offsets
|
||||
#define RAPTOR_INNATE_SOURCE "raptor_innate"
|
||||
|
||||
/mob/living/basic/raptor
|
||||
name = "raptor"
|
||||
desc = "A trusty, powerful steed. Taming it might prove difficult..."
|
||||
icon = 'icons/mob/simple/lavaland/raptor_big.dmi'
|
||||
speed = 2
|
||||
icon_state = "raptor_red"
|
||||
base_icon_state = "raptor"
|
||||
pixel_w = -12
|
||||
base_pixel_w = -12
|
||||
speed = 0.5
|
||||
mob_biotypes = MOB_ORGANIC|MOB_BEAST
|
||||
maxHealth = 270
|
||||
health = 270
|
||||
maxHealth = 200
|
||||
health = 200
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 15
|
||||
combat_mode = TRUE
|
||||
mob_size = MOB_SIZE_LARGE
|
||||
head_icon = 'icons/mob/clothing/back/pets_back.dmi'
|
||||
worn_slot_flags = ITEM_SLOT_BACK
|
||||
held_w_class = WEIGHT_CLASS_BULKY
|
||||
unsuitable_atmos_damage = 0
|
||||
minimum_survivable_temperature = BODYTEMP_COLD_ICEBOX_SAFE
|
||||
maximum_survivable_temperature = INFINITY
|
||||
@@ -45,14 +38,13 @@ GLOBAL_LIST_EMPTY(raptor_population)
|
||||
/obj/item/food/meat/slab/chicken = 4,
|
||||
/obj/item/stack/sheet/bone = 2,
|
||||
)
|
||||
ai_controller = /datum/ai_controller/basic_controller/raptor
|
||||
///can this mob breed
|
||||
// AI controller is set by our color
|
||||
ai_controller = null
|
||||
/// Can this raptor breed?
|
||||
var/can_breed = TRUE
|
||||
///should we change offsets on direction change?
|
||||
/// Should we change offsets on direction change?
|
||||
var/change_offsets = TRUE
|
||||
///can we ride this mob
|
||||
var/ridable_component = /datum/component/riding/creature/raptor
|
||||
//pet commands when we tame the raptor
|
||||
/// Pet commands when we tame the raptor
|
||||
var/static/list/pet_commands = list(
|
||||
/datum/pet_command/breed,
|
||||
/datum/pet_command/idle,
|
||||
@@ -62,24 +54,47 @@ GLOBAL_LIST_EMPTY(raptor_population)
|
||||
/datum/pet_command/follow,
|
||||
/datum/pet_command/fetch,
|
||||
)
|
||||
///things we inherited from our parent
|
||||
var/datum/raptor_inheritance/inherited_stats
|
||||
///our color
|
||||
var/raptor_color
|
||||
///the description that appears in the dex
|
||||
var/dex_description
|
||||
///path of our child
|
||||
var/child_path
|
||||
/// Can we wear a collar? If so, what is our icon state prefix for it?
|
||||
var/collar_state = "raptor"
|
||||
/// Raptor color datum assigned to this raptor, this is a singleton
|
||||
var/datum/raptor_color/raptor_color = null
|
||||
/// Are we an adult, youngling or baby?
|
||||
var/growth_stage = RAPTOR_ADULT
|
||||
/// Our current growth progress towards the next stage if we're a youngling or a baby
|
||||
var/growth_progress = 0
|
||||
/// Probability of getting progress in the baby phase each second
|
||||
var/growth_probability = 80
|
||||
/// Food types that we can consume
|
||||
var/static/list/food_types = list(
|
||||
/obj/item/stack/ore = 0,
|
||||
/obj/item/food/meat = 15,
|
||||
/obj/item/food/meat/slab = 25,
|
||||
/obj/item/food/meat/slab/spider = -15, // Toxic meats
|
||||
/obj/item/food/meat/slab/xeno = -15,
|
||||
/obj/item/food/meat/steak = 50,
|
||||
/obj/item/food/grown/ash_flora = 10,
|
||||
/obj/item/fish = 15,
|
||||
/obj/item/organ = 25,
|
||||
)
|
||||
/// Inheritance datum we store our genetic data in
|
||||
var/datum/raptor_inheritance/inherited_stats = null
|
||||
/// Current happiness value of the raptor
|
||||
var/happiness_percentage = 0
|
||||
|
||||
|
||||
/mob/living/basic/raptor/Initialize(mapload)
|
||||
/mob/living/basic/raptor/Initialize(mapload, datum/raptor_color/color_type, datum/raptor_inheritance/passed_stats)
|
||||
. = ..()
|
||||
if(SSmapping.is_planetary())
|
||||
change_offsets = FALSE
|
||||
icon = 'icons/mob/simple/lavaland/raptor_icebox.dmi'
|
||||
inherited_stats = passed_stats || new(src)
|
||||
// First thing as to go before tameable in change_growth_stage()
|
||||
AddElement(/datum/element/basic_eating, food_types = food_types)
|
||||
raptor_color = GLOB.raptor_colors[color_type || raptor_color || pick(GLOB.raptor_colors)]
|
||||
raptor_color.setup_raptor(src)
|
||||
|
||||
AddElement(/datum/element/wears_collar)
|
||||
add_traits(list(TRAIT_LAVA_IMMUNE, TRAIT_ASHSTORM_IMMUNE, TRAIT_SNOWSTORM_IMMUNE), INNATE_TRAIT)
|
||||
if (growth_stage == RAPTOR_ADULT)
|
||||
raptor_color.setup_adult(src)
|
||||
else
|
||||
change_growth_stage(growth_stage, RAPTOR_ADULT)
|
||||
|
||||
add_traits(list(TRAIT_ASHSTORM_IMMUNE, TRAIT_SNOWSTORM_IMMUNE, TRAIT_MINING_AOE_IMMUNE), INNATE_TRAIT)
|
||||
AddElement(\
|
||||
/datum/element/crusher_loot,\
|
||||
trophy_type = /obj/item/crusher_trophy/raptor_feather,\
|
||||
@@ -87,15 +102,364 @@ GLOBAL_LIST_EMPTY(raptor_population)
|
||||
drop_immediately = FALSE,\
|
||||
)
|
||||
|
||||
if(!mapload)
|
||||
if (!mapload)
|
||||
GLOB.raptor_population += REF(src)
|
||||
AddComponent(/datum/component/obeys_commands, pet_commands)
|
||||
|
||||
AddComponent(/datum/component/obeys_commands, pet_commands, list(0, -base_pixel_w))
|
||||
AddElement(\
|
||||
/datum/element/change_force_on_death,\
|
||||
move_resist = MOVE_RESIST_DEFAULT,\
|
||||
)
|
||||
RegisterSignal(src, COMSIG_MOB_ATE, PROC_REF(on_eat))
|
||||
RegisterSignal(src, COMSIG_MOB_PRE_EAT, PROC_REF(on_pre_eat))
|
||||
|
||||
AddElement(/datum/element/ai_retaliate)
|
||||
AddElement(/datum/element/ai_flee_while_injured, stop_fleeing_at = 0.5, start_fleeing_below = 0.2)
|
||||
|
||||
if (can_breed)
|
||||
add_breeding_component()
|
||||
|
||||
// Babies handle it in their change_growth_stage
|
||||
if (growth_stage != RAPTOR_BABY)
|
||||
update_blackboard()
|
||||
|
||||
AddElement(/datum/element/footstep, footstep_type = FOOTSTEP_MOB_CLAW)
|
||||
RegisterSignal(src, COMSIG_ATOM_DIR_CHANGE, PROC_REF(on_dir_change))
|
||||
RegisterSignal(src, COMSIG_LIVING_SCOOPED_UP, PROC_REF(on_picked_up))
|
||||
adjust_offsets(dir)
|
||||
add_happiness_component()
|
||||
|
||||
/mob/living/basic/raptor/Destroy()
|
||||
raptor_color = null
|
||||
GLOB.raptor_population -= REF(src)
|
||||
return ..()
|
||||
|
||||
/mob/living/basic/raptor/death(gibbed)
|
||||
. = ..()
|
||||
GLOB.raptor_population -= REF(src)
|
||||
|
||||
/mob/living/basic/raptor/buckle_mob(mob/living/target, force = FALSE, check_loc = TRUE, buckle_mob_flags= NONE)
|
||||
if(!iscarbon(target))
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/basic/raptor/proc/on_dir_change(datum/source, old_dir, new_dir)
|
||||
SIGNAL_HANDLER
|
||||
adjust_offsets(new_dir)
|
||||
|
||||
/mob/living/basic/raptor/proc/adjust_offsets(direction)
|
||||
if (!change_offsets)
|
||||
return
|
||||
|
||||
switch (direction)
|
||||
if (NORTH, SOUTH)
|
||||
add_offsets(RAPTOR_INNATE_SOURCE, w_add = 0, animate = FALSE)
|
||||
if (EAST, SOUTHEAST, NORTHEAST)
|
||||
add_offsets(RAPTOR_INNATE_SOURCE, w_add = -8, animate = FALSE)
|
||||
if (WEST, SOUTHWEST, NORTHWEST)
|
||||
add_offsets(RAPTOR_INNATE_SOURCE, w_add = 8, animate = FALSE)
|
||||
|
||||
/mob/living/basic/raptor/examine(mob/user)
|
||||
. = ..()
|
||||
if (stat == DEAD)
|
||||
return
|
||||
|
||||
switch (health / maxHealth)
|
||||
if (0 to 0.2)
|
||||
. += span_italics(span_bolddanger("[p_They()] [p_are()] gruesomly wounded, barely staying up on [p_their()] feet!"))
|
||||
if (0.2 to 0.4)
|
||||
. += span_danger("[p_They()] [p_have()] heavy injuries and open wounds all around [p_their()] body!")
|
||||
if (0.4 to 0.6)
|
||||
. += span_warning("[p_They()] [p_are()] noticeably hurt, limping from [p_their()] cuts and bruises.")
|
||||
if (0.6 to 0.8)
|
||||
. += span_warning("[p_They()] [p_are()] visibly injured, a few bruises and cuts showing between [p_their()] feathers.")
|
||||
if (0.8 to 0.999)
|
||||
. += span_notice("[p_They()] [p_have()] a few minor bruises and scratches.")
|
||||
|
||||
/mob/living/basic/raptor/Life(seconds_per_tick, times_fired)
|
||||
. = ..()
|
||||
if (growth_stage != RAPTOR_BABY || HAS_TRAIT(src, TRAIT_STASIS) || stat == DEAD)
|
||||
return
|
||||
if (!SPT_PROB(growth_probability * (1 + happiness_percentage * RAPTOR_GROWTH_HAPPINESS_MULTIPLIER), seconds_per_tick))
|
||||
return
|
||||
growth_progress += rand(RAPTOR_BABY_GROWTH_LOWER, RAPTOR_BABY_GROWTH_UPPER)
|
||||
if (growth_progress >= RAPTOR_GROWTH_REQUIRED)
|
||||
change_growth_stage(RAPTOR_YOUNG)
|
||||
growth_progress = 0
|
||||
|
||||
/mob/living/basic/raptor/early_melee_attack(atom/target, list/modifiers, ignore_cooldown)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
if(!istype(target, /obj/structure/ore_container/food_trough/raptor_trough))
|
||||
return TRUE
|
||||
var/obj/ore_food = locate(/obj/item/stack/ore) in target
|
||||
if(isnull(ore_food))
|
||||
balloon_alert(src, "no food!")
|
||||
else
|
||||
UnarmedAttack(ore_food, TRUE, modifiers)
|
||||
return FALSE
|
||||
|
||||
/mob/living/basic/raptor/melee_attack(mob/living/target, list/modifiers, ignore_cooldown)
|
||||
if (!combat_mode && istype(target, /mob/living/basic/raptor))
|
||||
var/mob/living/basic/raptor/possible_baby = target
|
||||
if (possible_baby.growth_stage == RAPTOR_BABY)
|
||||
return target.attack_hand(src, list(LEFT_CLICK = TRUE))
|
||||
return ..()
|
||||
|
||||
/mob/living/basic/raptor/proc/add_breeding_component()
|
||||
var/static/list/partner_types = typecacheof(list(/mob/living/basic/raptor))
|
||||
var/static/list/baby_types = list(/obj/item/food/egg = 1) ///raptor_egg = 1)
|
||||
AddComponent(\
|
||||
/datum/component/breed, \
|
||||
can_breed_with = partner_types, \
|
||||
baby_paths = baby_types, \
|
||||
breed_timer = 3 MINUTES, \
|
||||
post_birth = CALLBACK(src, PROC_REF(egg_inherit)), \
|
||||
)
|
||||
|
||||
/mob/living/basic/raptor/proc/add_happiness_component()
|
||||
var/static/list/percentage_callbacks = list(0, 15, 25, 35, 50, 75, 90, 100)
|
||||
// Higher happiness cap so it decays slower, about 15 minutes from full to zero
|
||||
AddComponent(\
|
||||
/datum/component/happiness, \
|
||||
maximum_happiness = 900, \
|
||||
on_petted_change = 50, \
|
||||
on_groom_change = 200, \
|
||||
on_eat_change = 150, \
|
||||
callback_percentages = percentage_callbacks,\
|
||||
happiness_callback = CALLBACK(src, PROC_REF(happiness_change)),\
|
||||
)
|
||||
|
||||
/mob/living/basic/raptor/proc/happiness_change(percent_value)
|
||||
var/attack_boost = round((percent_value - happiness_percentage) * RAPTOR_HAPPINESS_DAMAGE_BOOST, 1)
|
||||
melee_damage_lower += attack_boost
|
||||
melee_damage_upper += attack_boost
|
||||
happiness_percentage = percent_value
|
||||
|
||||
/mob/living/basic/raptor/projectile_hit(obj/projectile/hitting_projectile, def_zone, piercing_hit, blocked)
|
||||
// Most colors will redirect shots to their rider as to increase their own survivability, and only tank melee attacks
|
||||
if (raptor_color.redirect_shots && length(buckled_mobs))
|
||||
return buckled_mobs[1].projectile_hit(hitting_projectile, def_zone, piercing_hit, blocked)
|
||||
return ..()
|
||||
|
||||
/// Pass our genetic data to the egg
|
||||
/mob/living/basic/raptor/proc/egg_inherit(obj/item/food/egg/raptor_egg/baby_egg, mob/living/basic/raptor/partner)
|
||||
var/datum/raptor_inheritance/child_genes = new()
|
||||
child_genes.set_parents(src, partner)
|
||||
baby_egg.inherited_stats = child_genes
|
||||
baby_egg.child_color = get_child_color(partner)
|
||||
// Halve our food modifiers every time we breed
|
||||
for (var/food_type in inherited_stats.foods_eaten)
|
||||
var/list/stat_mods = inherited_stats.foods_eaten[food_type]
|
||||
stat_mods["amount"] /= 2
|
||||
stat_mods["attack"] /= 2
|
||||
stat_mods["health"] /= 2
|
||||
stat_mods["speed"] /= 2
|
||||
stat_mods["ability"] /= 2
|
||||
stat_mods["growth"] /= 2
|
||||
var/list/trait_list = stat_mods["traits"]
|
||||
for (var/i in 1 to ceil(length(trait_list) / 2))
|
||||
trait_list -= pick(trait_list)
|
||||
|
||||
var/list/color_chances = stat_mods["color_chances"]
|
||||
for (var/datum/raptor_color/color_type as anything in color_chances)
|
||||
color_chances[color_type] = floor(color_chances[color_type] / 2)
|
||||
if (!color_chances[color_type])
|
||||
color_chances -= color_type
|
||||
|
||||
/mob/living/basic/raptor/proc/get_child_color(mob/living/basic/raptor/partner)
|
||||
if (raptor_color == partner.raptor_color)
|
||||
return raptor_color.type
|
||||
|
||||
if (raptor_color.guaranteed_crossbreeds[partner.raptor_color.type])
|
||||
return raptor_color.guaranteed_crossbreeds[partner.raptor_color.type]
|
||||
|
||||
// This should be redundant as they should be mirroring eachother, but just in case
|
||||
if (partner.raptor_color.guaranteed_crossbreeds[raptor_color.type])
|
||||
return partner.raptor_color.guaranteed_crossbreeds[raptor_color.type]
|
||||
|
||||
// We've got all the colors in our family tree and aren't rolling a guarantee, bingo
|
||||
if (length(inherited_stats.parent_colors | partner.inherited_stats.parent_colors | raptor_color.type | partner.raptor_color.type) == length(GLOB.raptor_colors))
|
||||
return /datum/raptor_color/black
|
||||
|
||||
var/list/prob_list = list()
|
||||
for (var/datum/raptor_color/color_type as anything in GLOB.raptor_colors)
|
||||
prob_list[color_type] = color_type::spawn_chance
|
||||
|
||||
var/amount_eaten = 0
|
||||
for (var/food_type in inherited_stats.foods_eaten)
|
||||
var/list/stat_mods = inherited_stats.foods_eaten[food_type]
|
||||
amount_eaten += stat_mods["amount"]
|
||||
|
||||
for (var/food_type in inherited_stats.foods_eaten)
|
||||
var/list/stat_mods = inherited_stats.foods_eaten[food_type]
|
||||
var/list/color_chances = stat_mods["color_chances"]
|
||||
for (var/datum/raptor_color/color_type as anything in color_chances)
|
||||
prob_list[color_type] += floor(color_chances[color_type] * stat_mods["amount"])
|
||||
|
||||
return pick_weight(prob_list)
|
||||
|
||||
/mob/living/basic/raptor/proc/on_picked_up(mob/living/basic/raptor/source, mob/living/user, obj/item/mob_holder/holder)
|
||||
SIGNAL_HANDLER
|
||||
// Our inventory code sucks so we have to do this
|
||||
holder.icon = 'icons/mob/simple/lavaland/raptor_baby.dmi'
|
||||
holder.icon_state = icon_state
|
||||
holder.alternate_worn_layer = HEAD_LAYER
|
||||
holder.pixel_w = 0
|
||||
holder.pixel_z = 0
|
||||
holder.base_pixel_w = 0
|
||||
holder.base_pixel_z = 0
|
||||
|
||||
/mob/living/basic/raptor/proc/on_pre_eat(datum/source, obj/item/potential_food, list/effect_mult)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if (isorgan(potential_food))
|
||||
var/obj/item/organ/guts = potential_food
|
||||
if (!(guts.organ_flags & ORGAN_EDIBLE) || !(guts.organ_flags & ORGAN_ORGANIC))
|
||||
return COMSIG_MOB_CANCEL_EAT
|
||||
|
||||
if (happiness_percentage)
|
||||
effect_mult += happiness_percentage * RAPTOR_GROWTH_HAPPINESS_MULTIPLIER
|
||||
|
||||
/mob/living/basic/raptor/proc/on_eat(datum/source, atom/food, mob/living/feeder)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if (!istype(food, /obj/item/food))
|
||||
return
|
||||
|
||||
var/obj/item/food/meal = food
|
||||
var/is_flora = istype(meal, /obj/item/food/grown/ash_flora)
|
||||
var/is_meat = (meal.foodtypes & (MEAT|GORE))
|
||||
// Babies cannot gain growth from eating meat, only plants, but they get some passively
|
||||
if ((!is_meat || growth_stage == RAPTOR_BABY) && !is_flora)
|
||||
return
|
||||
|
||||
if (growth_stage == RAPTOR_ADULT)
|
||||
return
|
||||
|
||||
// Better meals make your raptor grow faster
|
||||
var/growth_value = meal.crafting_complexity * RAPTOR_MEAL_COMPLEXITY_GROWTH_FACTOR + (is_flora ? RAPTOR_GROWTH_BASE_PLANT : RAPTOR_GROWTH_BASE_MEAT)
|
||||
growth_progress += growth_value * (1 + inherited_stats.growth_modifier) * (1 + happiness_percentage * RAPTOR_GROWTH_HAPPINESS_MULTIPLIER)
|
||||
if (growth_progress >= RAPTOR_GROWTH_REQUIRED)
|
||||
change_growth_stage(growth_stage == RAPTOR_BABY ? RAPTOR_YOUNG : RAPTOR_ADULT)
|
||||
growth_progress = 0
|
||||
|
||||
/// Changes the raptor to a new growth stage. Only should be done forwards, or on raptor init as the first thing before everything else
|
||||
/// Sorry for the monolith, but splitting it up results in even worse looking code with a ton of duplicate calls and assignments
|
||||
/// And making a *second* datum is just insanity
|
||||
/mob/living/basic/raptor/proc/change_growth_stage(new_stage, prev_stage = growth_stage)
|
||||
if (new_stage == prev_stage)
|
||||
return FALSE
|
||||
|
||||
if (SEND_SIGNAL(src, COMSIG_RAPTOR_GROWTH_STAGE_CHANGE, new_stage, prev_stage) & COMPONENT_CANCEL_RAPTOR_GROWTH)
|
||||
return FALSE
|
||||
|
||||
growth_stage = new_stage
|
||||
|
||||
// Visuals
|
||||
switch (new_stage)
|
||||
if (RAPTOR_BABY)
|
||||
name = "baby raptor"
|
||||
desc = "Will this grow into something useful?"
|
||||
icon = 'icons/mob/simple/lavaland/raptor_baby.dmi'
|
||||
base_icon_state = "baby"
|
||||
base_pixel_w = 0
|
||||
mob_size = MOB_SIZE_TINY
|
||||
if (RAPTOR_YOUNG)
|
||||
name = "raptor youngling"
|
||||
desc = "A young raptor that can grow into a robust, trusty steed. Rather naive at such an age, it shouldn't be too hard to tame."
|
||||
icon = 'icons/mob/simple/lavaland/raptor_big.dmi'
|
||||
base_icon_state = "young"
|
||||
base_pixel_w = initial(base_pixel_w)
|
||||
mob_size = MOB_SIZE_HUMAN
|
||||
if (RAPTOR_ADULT)
|
||||
name = "raptor"
|
||||
desc = initial(desc)
|
||||
icon = 'icons/mob/simple/lavaland/raptor_big.dmi'
|
||||
base_icon_state = "raptor"
|
||||
base_pixel_w = initial(base_pixel_w)
|
||||
mob_size = initial(mob_size)
|
||||
|
||||
can_be_held = initial(density)
|
||||
density = initial(density)
|
||||
move_resist = initial(move_resist)
|
||||
can_breed = initial(can_breed)
|
||||
change_offsets = initial(change_offsets)
|
||||
|
||||
if (new_stage == RAPTOR_ADULT)
|
||||
// Adults need to be tamed with skill rather than snacks
|
||||
qdel(GetComponent(/datum/component/tameable))
|
||||
else // Make us teeny-tiny
|
||||
can_be_held = TRUE
|
||||
density = FALSE
|
||||
can_breed = FALSE
|
||||
move_resist = MOVE_RESIST_DEFAULT
|
||||
change_offsets = FALSE
|
||||
|
||||
if (prev_stage == RAPTOR_ADULT)
|
||||
AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 25, bonus_tame_chance = 15, unique = TRUE)
|
||||
|
||||
if (change_offsets)
|
||||
adjust_offsets(dir)
|
||||
else
|
||||
remove_offsets(RAPTOR_INNATE_SOURCE, FALSE)
|
||||
|
||||
if (can_breed)
|
||||
add_breeding_component()
|
||||
else
|
||||
qdel(GetComponent(/datum/component/breed))
|
||||
|
||||
var/obj/item/mob_holder/holder = null
|
||||
if (istype(loc, /obj/item/mob_holder))
|
||||
holder = loc
|
||||
if (!can_be_held)
|
||||
holder.release()
|
||||
holder = null
|
||||
|
||||
if (collar_state)
|
||||
RemoveElement(/datum/element/wears_collar, collar_icon = 'icons/mob/simple/lavaland/raptor_big.dmi', collar_icon_state = "[collar_state]_")
|
||||
|
||||
if (new_stage == RAPTOR_BABY)
|
||||
collar_state = null
|
||||
var/list/friends = ai_controller?.blackboard[BB_FRIENDS_LIST]
|
||||
if (friends)
|
||||
friends = friends.Copy()
|
||||
QDEL_NULL(ai_controller)
|
||||
ai_controller = new /datum/ai_controller/basic_controller/baby_raptor(src)
|
||||
for (var/old_friend in friends)
|
||||
ai_controller.insert_blackboard_key_lazylist(BB_FRIENDS_LIST, old_friend)
|
||||
update_blackboard()
|
||||
held_w_class = WEIGHT_CLASS_SMALL
|
||||
worn_slot_flags = NONE
|
||||
holder?.update_weight_class(held_w_class)
|
||||
else
|
||||
collar_state = base_icon_state
|
||||
AddElement(/datum/element/wears_collar, collar_icon = 'icons/mob/simple/lavaland/raptor_big.dmi', collar_icon_state = "[collar_state]_")
|
||||
if (prev_stage == RAPTOR_BABY)
|
||||
var/list/friends = ai_controller?.blackboard[BB_FRIENDS_LIST]
|
||||
if (friends)
|
||||
friends = friends.Copy()
|
||||
QDEL_NULL(ai_controller)
|
||||
ai_controller = new raptor_color.ai_controller(src)
|
||||
for (var/old_friend in friends)
|
||||
ai_controller.insert_blackboard_key_lazylist(BB_FRIENDS_LIST, old_friend)
|
||||
update_blackboard()
|
||||
held_w_class = WEIGHT_CLASS_BULKY
|
||||
worn_slot_flags = ITEM_SLOT_BACK
|
||||
holder?.update_weight_class(held_w_class)
|
||||
|
||||
// And finish the setup on our color's side
|
||||
switch (new_stage)
|
||||
if (RAPTOR_BABY)
|
||||
raptor_color.setup_baby(src)
|
||||
if (RAPTOR_YOUNG)
|
||||
raptor_color.setup_young(src)
|
||||
if (RAPTOR_ADULT)
|
||||
raptor_color.setup_adult(src)
|
||||
return TRUE
|
||||
|
||||
/mob/living/basic/raptor/proc/update_blackboard()
|
||||
var/static/list/display_emote = list(
|
||||
BB_EMOTE_SAY = list("Chirp chirp chirp!", "Kweh!", "Bwark!"),
|
||||
BB_EMOTE_SEE = list("shakes its feathers!", "stretches!", "flaps its wings!", "pecks at the ground!"),
|
||||
@@ -110,235 +474,110 @@ GLOBAL_LIST_EMPTY(raptor_population)
|
||||
)
|
||||
|
||||
ai_controller.set_blackboard_key(BB_BASIC_MOB_SPEAK_LINES, display_emote)
|
||||
inherited_stats = new
|
||||
inherit_properties()
|
||||
var/list/my_food = string_list(list(/obj/item/stack/ore))
|
||||
AddElement(/datum/element/basic_eating, food_types = my_food)
|
||||
AddElement(/datum/element/ai_retaliate)
|
||||
AddElement(/datum/element/ai_flee_while_injured, stop_fleeing_at = 0.5, start_fleeing_below = 0.2)
|
||||
|
||||
if(ridable_component)
|
||||
AddElement(/datum/element/ridable, ridable_component)
|
||||
var/static/list/preferred_foods = typecacheof(list(
|
||||
/obj/item/food/meat,
|
||||
/obj/item/food/grown/ash_flora,
|
||||
)) - typecacheof(list( // Don't seek out toxic foods
|
||||
/obj/item/food/meat/slab/spider,
|
||||
/obj/item/food/meat/slab/xeno,
|
||||
))
|
||||
|
||||
if(can_breed)
|
||||
add_breeding_component()
|
||||
ai_controller.set_blackboard_key(BB_BASIC_FOODS, preferred_foods)
|
||||
|
||||
AddElement(/datum/element/footstep, footstep_type = FOOTSTEP_MOB_CLAW)
|
||||
RegisterSignal(src, COMSIG_ATOM_DIR_CHANGE, PROC_REF(on_dir_change))
|
||||
adjust_offsets(dir)
|
||||
add_happiness_component()
|
||||
|
||||
/mob/living/basic/raptor/buckle_mob(mob/living/target, force = FALSE, check_loc = TRUE, buckle_mob_flags= NONE)
|
||||
if(!iscarbon(target))
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/basic/raptor/proc/add_happiness_component()
|
||||
var/static/list/percentage_callbacks = list(0, 15, 25, 35, 50, 75, 90, 100)
|
||||
AddComponent(\
|
||||
/datum/component/happiness,\
|
||||
on_petted_change = 100,\
|
||||
on_groom_change = 100,\
|
||||
on_eat_change = 400,\
|
||||
callback_percentages = percentage_callbacks,\
|
||||
happiness_callback = CALLBACK(src, PROC_REF(happiness_change)),\
|
||||
)
|
||||
|
||||
/mob/living/basic/raptor/proc/on_dir_change(datum/source, old_dir, new_dir)
|
||||
SIGNAL_HANDLER
|
||||
adjust_offsets(new_dir)
|
||||
|
||||
/mob/living/basic/raptor/proc/adjust_offsets(direction)
|
||||
if (!change_offsets)
|
||||
return
|
||||
|
||||
switch (direction)
|
||||
if (NORTH)
|
||||
add_offsets(RAPTOR_INNATE_SOURCE, w_add = -8, animate = FALSE)
|
||||
if (SOUTH)
|
||||
add_offsets(RAPTOR_INNATE_SOURCE, w_add = 0, animate = FALSE)
|
||||
if (EAST, SOUTHEAST, NORTHEAST)
|
||||
add_offsets(RAPTOR_INNATE_SOURCE, w_add = -20, animate = FALSE)
|
||||
if (WEST, SOUTHWEST, NORTHWEST)
|
||||
add_offsets(RAPTOR_INNATE_SOURCE, w_add = -5, animate = FALSE)
|
||||
|
||||
/mob/living/basic/raptor/early_melee_attack(atom/target, list/modifiers, ignore_cooldown)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
if(!istype(target, /obj/structure/ore_container/food_trough/raptor_trough))
|
||||
return TRUE
|
||||
|
||||
var/obj/ore_food = locate(/obj/item/stack/ore) in target
|
||||
|
||||
if(isnull(ore_food))
|
||||
balloon_alert(src, "no food!")
|
||||
else
|
||||
UnarmedAttack(ore_food, TRUE, modifiers)
|
||||
return FALSE
|
||||
|
||||
/mob/living/basic/raptor/melee_attack(mob/living/target, list/modifiers, ignore_cooldown)
|
||||
if(!combat_mode && istype(target, /mob/living/basic/raptor/baby_raptor))
|
||||
target.attack_hand(src, list(LEFT_CLICK = TRUE))
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/basic/raptor/death(gibbed)
|
||||
. = ..()
|
||||
GLOB.raptor_population -= REF(src)
|
||||
|
||||
/mob/living/basic/raptor/proc/happiness_change(percent_value)
|
||||
var/attack_boost = round(initial(melee_damage_lower) * percent_value * HAPPINESS_BOOST_DAMPENER, 1)
|
||||
melee_damage_lower = initial(melee_damage_lower) + attack_boost
|
||||
melee_damage_upper = melee_damage_lower + 5
|
||||
|
||||
|
||||
///pass down our inheritance to the egg
|
||||
/mob/living/basic/raptor/proc/egg_inherit(obj/item/food/egg/raptor_egg/baby_egg, mob/living/basic/raptor/partner)
|
||||
var/datum/raptor_inheritance/inherit = new
|
||||
inherit.set_parents(inherited_stats, partner.inherited_stats)
|
||||
baby_egg.inherited_stats = inherit
|
||||
baby_egg.determine_growth_path(src, partner)
|
||||
|
||||
/mob/living/basic/raptor/proc/inherit_properties()
|
||||
if(isnull(inherited_stats))
|
||||
return
|
||||
for(var/trait in GLOB.raptor_inherit_traits) // done this way to allow overriding of traits when assigned new inherit datum
|
||||
var/should_inherit = (trait in inherited_stats.inherit_traits)
|
||||
for(var/trait in GLOB.raptor_inherit_traits)
|
||||
var/should_inherit = (trait in inherited_stats.personality_traits)
|
||||
ai_controller?.set_blackboard_key(trait, should_inherit)
|
||||
melee_damage_lower += inherited_stats.attack_modifier
|
||||
melee_damage_upper += melee_damage_lower + 5
|
||||
maxHealth += inherited_stats.health_modifier
|
||||
heal_overall_damage(maxHealth)
|
||||
|
||||
/mob/living/basic/raptor/proc/add_breeding_component()
|
||||
var/static/list/partner_types = typecacheof(list(/mob/living/basic/raptor))
|
||||
var/static/list/baby_types = list(/obj/item/food/egg/raptor_egg = 1)
|
||||
AddComponent(\
|
||||
/datum/component/breed,\
|
||||
can_breed_with = typecacheof(list(/mob/living/basic/raptor)),\
|
||||
baby_paths = baby_types,\
|
||||
post_birth = CALLBACK(src, PROC_REF(egg_inherit)),\
|
||||
breed_timer = 3 MINUTES,\
|
||||
)
|
||||
|
||||
|
||||
/mob/living/basic/raptor/Destroy()
|
||||
QDEL_NULL(inherited_stats)
|
||||
return ..()
|
||||
// Raptor types for mappers to use
|
||||
|
||||
/mob/living/basic/raptor/red
|
||||
name = "red raptor"
|
||||
icon_state = "raptor_red"
|
||||
icon_living = "raptor_red"
|
||||
icon_dead = "raptor_red_dead"
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 20
|
||||
raptor_color = RAPTOR_RED
|
||||
ridable_component = /datum/component/riding/creature/raptor/combat
|
||||
dex_description = "A resilient breed of raptors, battle-tested and bred for the purpose of humbling its foes in combat, \
|
||||
This breed demonstrates higher combat capabilities than its peers and oozes ruthless aggression."
|
||||
child_path = /mob/living/basic/raptor/baby_raptor/red
|
||||
raptor_color = /datum/raptor_color/red
|
||||
|
||||
/mob/living/basic/raptor/purple
|
||||
name = "purple raptor"
|
||||
icon_state = "raptor_purple"
|
||||
icon_living = "raptor_purple"
|
||||
icon_dead = "raptor_purple_dead"
|
||||
raptor_color = RAPTOR_PURPLE
|
||||
dex_description = "A dependable mount, bred for the purpose of long distance pilgrimages. This breed is also able to store its rider's possessions."
|
||||
child_path = /mob/living/basic/raptor/baby_raptor/purple
|
||||
|
||||
/mob/living/basic/raptor/purple/Initialize(mapload)
|
||||
. = ..()
|
||||
create_storage(
|
||||
max_specific_storage = WEIGHT_CLASS_NORMAL,
|
||||
max_total_storage = 10,
|
||||
storage_type = /datum/storage/raptor_storage,
|
||||
)
|
||||
raptor_color = /datum/raptor_color/purple
|
||||
|
||||
/mob/living/basic/raptor/green
|
||||
name = "green raptor"
|
||||
icon_state = "raptor_green"
|
||||
icon_living = "raptor_green"
|
||||
icon_dead = "raptor_green_dead"
|
||||
maxHealth = 400
|
||||
health = 400
|
||||
raptor_color = RAPTOR_GREEN
|
||||
dex_description = "A tough breed of raptor, made to withstand the harshest of punishment and to laugh in the face of pain, \
|
||||
this breed is able to withstand more punishment than its peers."
|
||||
child_path = /mob/living/basic/raptor/baby_raptor/green
|
||||
|
||||
/mob/living/basic/raptor/green/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/proficient_miner)
|
||||
raptor_color = /datum/raptor_color/green
|
||||
|
||||
/mob/living/basic/raptor/white
|
||||
name = "white raptor"
|
||||
icon_state = "raptor_white"
|
||||
icon_living = "raptor_white"
|
||||
icon_dead = "raptor_white_dead"
|
||||
raptor_color = RAPTOR_WHITE
|
||||
dex_description = "A loving sort, it cares for it peers and rushes to their aid with reckless abandon. It is able to heal any raptors' ailments."
|
||||
child_path = /mob/living/basic/raptor/baby_raptor/white
|
||||
|
||||
/mob/living/basic/raptor/white/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(\
|
||||
/datum/component/healing_touch,\
|
||||
heal_brute = melee_damage_upper,\
|
||||
heal_burn = melee_damage_upper,\
|
||||
heal_time = 0,\
|
||||
valid_targets_typecache = typecacheof(list(/mob/living/basic/raptor)),\
|
||||
)
|
||||
raptor_color = /datum/raptor_color/white
|
||||
|
||||
/mob/living/basic/raptor/black
|
||||
name = "black raptor"
|
||||
icon_state = "raptor_black"
|
||||
icon_living = "raptor_black"
|
||||
icon_dead = "raptor_black_dead"
|
||||
maxHealth = 400
|
||||
health = 400
|
||||
speed = 1.5
|
||||
melee_damage_lower = 20
|
||||
melee_damage_upper = 25
|
||||
raptor_color = RAPTOR_BLACK
|
||||
dex_description = "An ultra rare breed. Due to its sparse nature, not much is known about this sort. However it is said to possess many of its peers' abilities."
|
||||
child_path = /mob/living/basic/raptor/baby_raptor/black
|
||||
raptor_color = /datum/raptor_color/black
|
||||
|
||||
/mob/living/basic/raptor/yellow
|
||||
name = "yellow raptor"
|
||||
icon_state = "raptor_yellow"
|
||||
icon_living = "raptor_yellow"
|
||||
icon_dead = "raptor_yellow_dead"
|
||||
speed = 1.5
|
||||
raptor_color = RAPTOR_YELLOW
|
||||
dex_description = "This breed possesses greasy fast speed, DEMON speed, making light work of long pilgrimages. It's said that a thunderclap could be heard when this breed reaches its maximum speed."
|
||||
child_path = /mob/living/basic/raptor/baby_raptor/yellow
|
||||
raptor_color = /datum/raptor_color/yellow
|
||||
|
||||
/mob/living/basic/raptor/blue
|
||||
name = "blue raptor"
|
||||
icon_state = "raptor_blue"
|
||||
icon_living = "raptor_blue"
|
||||
icon_dead = "raptor_blue_dead"
|
||||
raptor_color = RAPTOR_BLUE
|
||||
dex_description = "Known to produce nutritous and equally delicious milk, which is also said to possess healing properties."
|
||||
child_path = /mob/living/basic/raptor/baby_raptor/blue
|
||||
raptor_color = /datum/raptor_color/blue
|
||||
|
||||
/mob/living/basic/raptor/blue/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(\
|
||||
/datum/component/udder,\
|
||||
udder_type = /obj/item/udder/raptor,\
|
||||
)
|
||||
/mob/living/basic/raptor/young
|
||||
growth_stage = RAPTOR_YOUNG
|
||||
|
||||
/datum/storage/raptor_storage
|
||||
animated = FALSE
|
||||
insert_on_attack = FALSE
|
||||
/mob/living/basic/raptor/young/red
|
||||
icon_state = "young_red"
|
||||
raptor_color = /datum/raptor_color/red
|
||||
|
||||
/datum/storage/raptor_storage/on_mousedropped_onto(datum/source, obj/item/dropping, mob/user)
|
||||
..()
|
||||
return NONE
|
||||
/mob/living/basic/raptor/young/purple
|
||||
icon_state = "young_purple"
|
||||
raptor_color = /datum/raptor_color/purple
|
||||
|
||||
#undef HAPPINESS_BOOST_DAMPENER
|
||||
#undef RAPTOR_INNATE_SOURCE
|
||||
/mob/living/basic/raptor/young/green
|
||||
icon_state = "young_green"
|
||||
raptor_color = /datum/raptor_color/green
|
||||
|
||||
/mob/living/basic/raptor/young/white
|
||||
icon_state = "young_white"
|
||||
raptor_color = /datum/raptor_color/white
|
||||
|
||||
/mob/living/basic/raptor/young/black
|
||||
icon_state = "young_black"
|
||||
raptor_color = /datum/raptor_color/black
|
||||
|
||||
/mob/living/basic/raptor/young/yellow
|
||||
icon_state = "young_yellow"
|
||||
raptor_color = /datum/raptor_color/yellow
|
||||
|
||||
/mob/living/basic/raptor/young/blue
|
||||
icon_state = "young_blue"
|
||||
raptor_color = /datum/raptor_color/blue
|
||||
|
||||
/mob/living/basic/raptor/baby
|
||||
icon = 'icons/mob/simple/lavaland/raptor_baby.dmi'
|
||||
growth_stage = RAPTOR_BABY
|
||||
|
||||
/mob/living/basic/raptor/baby/red
|
||||
icon_state = "baby_red"
|
||||
raptor_color = /datum/raptor_color/red
|
||||
|
||||
/mob/living/basic/raptor/baby/purple
|
||||
icon_state = "baby_purple"
|
||||
raptor_color = /datum/raptor_color/purple
|
||||
|
||||
/mob/living/basic/raptor/baby/green
|
||||
icon_state = "baby_green"
|
||||
raptor_color = /datum/raptor_color/green
|
||||
|
||||
/mob/living/basic/raptor/baby/white
|
||||
icon_state = "baby_white"
|
||||
raptor_color = /datum/raptor_color/white
|
||||
|
||||
/mob/living/basic/raptor/baby/black
|
||||
icon_state = "baby_black"
|
||||
raptor_color = /datum/raptor_color/black
|
||||
|
||||
/mob/living/basic/raptor/baby/yellow
|
||||
icon_state = "baby_yellow"
|
||||
raptor_color = /datum/raptor_color/yellow
|
||||
|
||||
/mob/living/basic/raptor/baby/blue
|
||||
icon_state = "baby_blue"
|
||||
raptor_color = /datum/raptor_color/blue
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
/mob/living/basic/raptor/baby_raptor
|
||||
name = "baby raptor"
|
||||
desc = "Will this grow into something useful?"
|
||||
icon = 'icons/mob/simple/lavaland/raptor_baby.dmi'
|
||||
speed = 5
|
||||
maxHealth = 25
|
||||
health = 25
|
||||
melee_damage_lower = 3
|
||||
melee_damage_upper = 5
|
||||
density = FALSE
|
||||
can_breed = FALSE
|
||||
move_resist = MOVE_RESIST_DEFAULT
|
||||
ai_controller = /datum/ai_controller/basic_controller/baby_raptor
|
||||
ridable_component = null
|
||||
change_offsets = FALSE
|
||||
dex_description = "A cute baby raptor, Having it near a parent or a birds-nest could encourage it to grow faster, \
|
||||
grooming it and feeding it could also ensure that it grows up quicker!"
|
||||
///what do we grow into
|
||||
var/growth_path
|
||||
///probability we are to be rolled
|
||||
var/roll_rate = 100
|
||||
|
||||
/mob/living/basic/raptor/baby_raptor/Initialize(mapload)
|
||||
. = ..()
|
||||
if(isnull(growth_path))
|
||||
return
|
||||
AddComponent(\
|
||||
/datum/component/growth_and_differentiation,\
|
||||
growth_time = null,\
|
||||
growth_path = growth_path,\
|
||||
growth_probability = 80,\
|
||||
lower_growth_value = 0.5,\
|
||||
upper_growth_value = 0.8,\
|
||||
signals_to_kill_on = list(COMSIG_MOB_CLIENT_LOGIN),\
|
||||
optional_checks = CALLBACK(src, PROC_REF(check_grow)),\
|
||||
optional_grow_behavior = CALLBACK(src, PROC_REF(ready_to_grow)),\
|
||||
)
|
||||
|
||||
/mob/living/basic/raptor/baby_raptor/add_happiness_component()
|
||||
AddComponent(/datum/component/happiness, on_petted_change = 100)
|
||||
|
||||
/mob/living/basic/raptor/baby_raptor/proc/check_grow()
|
||||
return (stat != DEAD)
|
||||
|
||||
/mob/living/basic/raptor/baby_raptor/proc/ready_to_grow()
|
||||
var/mob/living/basic/raptor/grown_mob = new growth_path(get_turf(src))
|
||||
QDEL_NULL(grown_mob.inherited_stats)
|
||||
grown_mob.inherited_stats = inherited_stats
|
||||
inherited_stats = null
|
||||
grown_mob.inherit_properties()
|
||||
ADD_TRAIT(grown_mob, TRAIT_MOB_HATCHED, INNATE_TRAIT) //pass on the hatched trait
|
||||
qdel(src)
|
||||
|
||||
/mob/living/basic/raptor/baby_raptor/black
|
||||
name = "baby black raptor"
|
||||
icon_state = "baby_black"
|
||||
icon_living = "baby_black"
|
||||
icon_dead = "baby_black_dead"
|
||||
growth_path = /mob/living/basic/raptor/black
|
||||
roll_rate = 10
|
||||
|
||||
/mob/living/basic/raptor/baby_raptor/red
|
||||
name = "baby red raptor"
|
||||
icon_state = "baby_red"
|
||||
icon_living = "baby_red"
|
||||
icon_dead = "baby_red_dead"
|
||||
growth_path = /mob/living/basic/raptor/red
|
||||
|
||||
/mob/living/basic/raptor/baby_raptor/purple
|
||||
name = "baby purple raptor"
|
||||
icon_state = "baby_purple"
|
||||
icon_living = "baby_purple"
|
||||
icon_dead = "baby_purple_dead"
|
||||
growth_path = /mob/living/basic/raptor/purple
|
||||
|
||||
/mob/living/basic/raptor/baby_raptor/white
|
||||
name = "baby white raptor"
|
||||
icon_state = "baby_white"
|
||||
icon_living = "baby_white"
|
||||
icon_dead = "baby_white_dead"
|
||||
growth_path = /mob/living/basic/raptor/white
|
||||
|
||||
/mob/living/basic/raptor/baby_raptor/yellow
|
||||
name = "baby yellow raptor"
|
||||
icon_state = "baby_yellow"
|
||||
icon_living = "baby_yellow"
|
||||
icon_dead = "baby_yellow_dead"
|
||||
growth_path = /mob/living/basic/raptor/yellow
|
||||
|
||||
/mob/living/basic/raptor/baby_raptor/green
|
||||
name = "baby green raptor"
|
||||
icon_state = "baby_green"
|
||||
icon_living = "baby_green"
|
||||
icon_dead = "baby_green_dead"
|
||||
growth_path = /mob/living/basic/raptor/green
|
||||
|
||||
/mob/living/basic/raptor/baby_raptor/blue
|
||||
name = "baby blue raptor"
|
||||
icon_state = "baby_blue"
|
||||
icon_living = "baby_blue"
|
||||
icon_dead = "baby_blue_dead"
|
||||
growth_path = /mob/living/basic/raptor/blue
|
||||
@@ -8,7 +8,10 @@
|
||||
return (source != target && target.health < target.maxHealth)
|
||||
|
||||
/datum/ai_behavior/find_hunt_target/raptor_baby/valid_dinner(mob/living/source, mob/living/target, radius)
|
||||
return can_see(source, target, radius) && target.stat != DEAD
|
||||
if (!can_see(source, target, radius) || target.stat == DEAD || !istype(target, /mob/living/basic/raptor))
|
||||
return FALSE
|
||||
var/mob/living/basic/raptor/raptor = target
|
||||
return raptor.growth_stage == RAPTOR_BABY
|
||||
|
||||
/datum/ai_behavior/hunt_target/interact_with_target/reset_target_combat_mode_off/care_for_young
|
||||
|
||||
@@ -21,3 +24,15 @@
|
||||
|
||||
/datum/ai_behavior/find_hunt_target/raptor_trough/valid_dinner(mob/living/source, atom/movable/trough, radius)
|
||||
return !!(locate(/obj/item/stack/ore) in trough.contents)
|
||||
|
||||
/datum/ai_behavior/find_injured_rider/perform(seconds_per_tick, datum/ai_controller/controller, hunting_target_key, types_to_hunt, hunt_range)
|
||||
var/mob/living/living_mob = controller.pawn
|
||||
if (!length(living_mob.buckled_mobs) || !isliving(living_mob.buckled_mobs[1]))
|
||||
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED
|
||||
|
||||
var/mob/living/rider = living_mob.buckled_mobs[1]
|
||||
if (rider.stat == CONSCIOUS || rider.stat == DEAD || rider.health >= rider.maxHealth)
|
||||
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED
|
||||
|
||||
controller.set_blackboard_key(hunting_target_key, rider)
|
||||
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
|
||||
BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
|
||||
BB_BABIES_PARTNER_TYPES = list(/mob/living/basic/raptor),
|
||||
BB_BABIES_CHILD_TYPES = list(/mob/living/basic/raptor/baby_raptor),
|
||||
BB_MAX_CHILDREN = 5,
|
||||
BB_RAPTOR_FLEE_THRESHOLD = 0.25,
|
||||
)
|
||||
|
||||
ai_movement = /datum/ai_movement/basic_avoidance
|
||||
@@ -19,6 +19,7 @@
|
||||
/datum/ai_planning_subtree/escape_captivity,
|
||||
/datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/raptor,
|
||||
/datum/ai_planning_subtree/flee_target/from_flee_key,
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/heal_rider,
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/heal_raptors,
|
||||
/datum/ai_planning_subtree/random_speech/blackboard,
|
||||
/datum/ai_planning_subtree/pet_planning,
|
||||
@@ -26,6 +27,42 @@
|
||||
/datum/ai_planning_subtree/simple_find_target,
|
||||
/datum/ai_planning_subtree/basic_melee_attack_subtree,
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/raptor_trough,
|
||||
/datum/ai_planning_subtree/find_food,
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/care_for_young,
|
||||
/datum/ai_planning_subtree/make_babies,
|
||||
/datum/ai_planning_subtree/express_happiness,
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/play_with_owner/raptor,
|
||||
)
|
||||
|
||||
/// Angry raptors with no faction check on retaliation
|
||||
/datum/ai_controller/basic_controller/raptor/aggressive
|
||||
blackboard = list(
|
||||
BB_INTERACTIONS_WITH_OWNER = list(
|
||||
"pecks",
|
||||
"nuzzles",
|
||||
"wags their tail against",
|
||||
"playfully leans against"
|
||||
),
|
||||
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/exact_match,
|
||||
BB_HUNT_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
|
||||
BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
|
||||
BB_BABIES_PARTNER_TYPES = list(/mob/living/basic/raptor),
|
||||
BB_MAX_CHILDREN = 5,
|
||||
BB_RAPTOR_FLEE_THRESHOLD = 0.1,
|
||||
)
|
||||
|
||||
planning_subtrees = list(
|
||||
/datum/ai_planning_subtree/escape_captivity,
|
||||
/datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/raptor,
|
||||
/datum/ai_planning_subtree/flee_target/from_flee_key,
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/heal_raptors,
|
||||
/datum/ai_planning_subtree/random_speech/blackboard,
|
||||
/datum/ai_planning_subtree/pet_planning,
|
||||
/datum/ai_planning_subtree/target_retaliate,
|
||||
/datum/ai_planning_subtree/simple_find_target/hunt,
|
||||
/datum/ai_planning_subtree/basic_melee_attack_subtree,
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/raptor_trough,
|
||||
/datum/ai_planning_subtree/find_food,
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/care_for_young,
|
||||
/datum/ai_planning_subtree/make_babies,
|
||||
/datum/ai_planning_subtree/express_happiness,
|
||||
@@ -55,7 +92,6 @@
|
||||
blackboard = list(
|
||||
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
|
||||
BB_FIND_MOM_TYPES = list(/mob/living/basic/raptor),
|
||||
BB_IGNORE_MOM_TYPES = list(/mob/living/basic/raptor/baby_raptor),
|
||||
)
|
||||
|
||||
ai_movement = /datum/ai_movement/basic_avoidance
|
||||
@@ -67,5 +103,5 @@
|
||||
/datum/ai_planning_subtree/random_speech/blackboard,
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/raptor_trough,
|
||||
/datum/ai_planning_subtree/express_happiness,
|
||||
/datum/ai_planning_subtree/look_for_adult,
|
||||
/datum/ai_planning_subtree/look_for_adult/raptor,
|
||||
)
|
||||
|
||||
@@ -11,19 +11,41 @@
|
||||
return
|
||||
return ..()
|
||||
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/heal_rider
|
||||
target_key = BB_INJURED_RAPTOR
|
||||
hunting_behavior = /datum/ai_behavior/hunt_target/interact_with_target/heal_raptor
|
||||
finding_behavior = /datum/ai_behavior/find_injured_rider
|
||||
hunt_targets = list(/mob/living/carbon/human)
|
||||
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/heal_rider/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
if(!controller.blackboard[BB_BASIC_MOB_HEALER])
|
||||
return
|
||||
return ..()
|
||||
|
||||
/datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/raptor
|
||||
target_key = BB_BASIC_MOB_FLEE_TARGET
|
||||
|
||||
/datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/raptor/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
if(!controller.blackboard[BB_RAPTOR_COWARD])
|
||||
if(controller.blackboard[BB_RAPTOR_COWARD])
|
||||
return ..()
|
||||
|
||||
var/mob/living/basic/raptor/raptor = controller.pawn
|
||||
if (raptor.health <= raptor.maxHealth * controller.blackboard[BB_RAPTOR_FLEE_THRESHOLD])
|
||||
return ..()
|
||||
|
||||
if (!length(raptor.buckled_mobs))
|
||||
return
|
||||
return ..()
|
||||
|
||||
var/mob/living/buckled_to = raptor.buckled_mobs[1]
|
||||
// Flee if our owner is badly injured and out
|
||||
if (buckled_to.stat != CONSCIOUS && buckled_to.stat != DEAD)
|
||||
return ..()
|
||||
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/care_for_young
|
||||
target_key = BB_RAPTOR_BABY
|
||||
hunting_behavior = /datum/ai_behavior/hunt_target/interact_with_target/reset_target_combat_mode_off/care_for_young
|
||||
finding_behavior = /datum/ai_behavior/find_hunt_target/raptor_baby
|
||||
hunt_targets = list(/mob/living/basic/raptor/baby_raptor)
|
||||
hunt_targets = list(/mob/living/basic/raptor)
|
||||
hunt_chance = 75
|
||||
hunt_range = 9
|
||||
|
||||
|
||||
@@ -0,0 +1,439 @@
|
||||
GLOBAL_LIST_INIT(raptor_colors, init_raptor_colors())
|
||||
|
||||
/proc/init_raptor_colors()
|
||||
var/list/colors = list()
|
||||
for (var/datum/raptor_color/color_type as anything in subtypesof(/datum/raptor_color))
|
||||
colors[color_type] = new color_type()
|
||||
return colors
|
||||
|
||||
/datum/raptor_color
|
||||
/// Color name used for raptor name and icon
|
||||
var/color = "error"
|
||||
/// RaptorDex description for the raptor
|
||||
var/description = "Report this!"
|
||||
/// Raptor's health
|
||||
var/health = 220
|
||||
/// Raptor's speed
|
||||
var/speed = 0.5
|
||||
// Minimal and maximal damage for the raptor
|
||||
var/melee_damage_lower = 10
|
||||
var/melee_damage_upper = 15
|
||||
/// Does this raptor redirect projectile hits onto its rider?
|
||||
var/redirect_shots = TRUE
|
||||
/// Rideable component type to assign to the raptor
|
||||
var/rideable_component = /datum/component/riding/creature/raptor
|
||||
/// Guaranteed cross-breeding colors, other parent color -> child color
|
||||
var/guaranteed_crossbreeds = list()
|
||||
/// Type of AI controller the raptor uses
|
||||
var/datum/ai_controller/ai_controller = /datum/ai_controller/basic_controller/raptor
|
||||
/// Chance that a newborn baby raptor will be of this color
|
||||
var/spawn_chance = 33
|
||||
|
||||
/// Shared proc, only called once on raptor init for color-specific traits and properties
|
||||
/datum/raptor_color/proc/setup_raptor(mob/living/basic/raptor/raptor)
|
||||
if (raptor.ai_controller)
|
||||
CRASH("setup_raptor called on a raptor ([raptor]) with a present AI controller! This is most likely a result of a second call to setup_raptor.")
|
||||
raptor.ai_controller = new ai_controller(raptor)
|
||||
|
||||
/datum/raptor_color/proc/setup_adult(mob/living/basic/raptor/raptor)
|
||||
var/datum/raptor_inheritance/stats = raptor.inherited_stats
|
||||
var/real_health = health + stats.health_modifier
|
||||
// If we grow up while damaged, keep the damage percentage the same
|
||||
raptor.health *= real_health / raptor.maxHealth
|
||||
raptor.maxHealth = real_health
|
||||
// -0.33 ~ 0.33 gets rounded to 0 rather than +-0.5
|
||||
var/speed_mod = clamp(round(abs(stats.speed_modifier - 0.08), 0.5) * sign(stats.speed_modifier), -0.5, 0.5)
|
||||
raptor.set_varspeed(speed - speed_mod)
|
||||
raptor.melee_damage_lower = melee_damage_lower + stats.attack_modifier
|
||||
raptor.melee_damage_upper = melee_damage_upper + stats.attack_modifier
|
||||
if (rideable_component)
|
||||
raptor.AddElement(/datum/element/ridable, rideable_component)
|
||||
setup_appearance(raptor)
|
||||
|
||||
/datum/raptor_color/proc/setup_young(mob/living/basic/raptor/raptor)
|
||||
var/datum/raptor_inheritance/stats = raptor.inherited_stats
|
||||
var/real_health = health + stats.health_modifier
|
||||
raptor.health *= real_health / 2 / raptor.maxHealth
|
||||
raptor.maxHealth = real_health / 2
|
||||
var/speed_mod = clamp(round(abs(stats.speed_modifier - 0.08), 0.5) * sign(stats.speed_modifier), -0.5, 0.5)
|
||||
raptor.set_varspeed(speed - speed_mod)
|
||||
raptor.melee_damage_lower = floor((melee_damage_lower + stats.attack_modifier) / 2)
|
||||
raptor.melee_damage_upper = floor((melee_damage_upper + stats.attack_modifier) / 2)
|
||||
setup_appearance(raptor)
|
||||
|
||||
/datum/raptor_color/proc/setup_baby(mob/living/basic/raptor/raptor)
|
||||
var/datum/raptor_inheritance/stats = raptor.inherited_stats
|
||||
var/real_health = health + stats.health_modifier
|
||||
raptor.health *= real_health / 8 / raptor.maxHealth
|
||||
raptor.maxHealth = real_health / 8
|
||||
var/speed_mod = clamp(round(abs(stats.speed_modifier - 0.08), 0.5) * sign(stats.speed_modifier), -0.5, 0.5)
|
||||
raptor.set_varspeed(speed + 4.5 - speed_mod)
|
||||
raptor.melee_damage_lower = floor((melee_damage_lower + stats.attack_modifier) / 3)
|
||||
raptor.melee_damage_upper = floor((melee_damage_upper + stats.attack_modifier) / 3)
|
||||
setup_appearance(raptor)
|
||||
|
||||
/datum/raptor_color/proc/setup_appearance(mob/living/basic/raptor/raptor)
|
||||
raptor.name = "[color] [raptor.name]"
|
||||
raptor.icon_state = "[raptor.base_icon_state]_[color]"
|
||||
raptor.held_state = "[raptor.base_icon_state]_[color]"
|
||||
raptor.icon_living = "[raptor.base_icon_state]_[color]"
|
||||
raptor.icon_dead = "[raptor.base_icon_state]_[color]_dead"
|
||||
raptor.update_appearance()
|
||||
|
||||
/datum/raptor_color/red
|
||||
color = "red"
|
||||
description = "A resilient breed of raptors, battle-tested and bred for the purpose of humbling its foes in combat, \
|
||||
This breed demonstrates higher combat capabilities than its peers and oozes ruthless aggression."
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 20
|
||||
health = 300
|
||||
rideable_component = /datum/component/riding/creature/raptor/combat
|
||||
redirect_shots = FALSE
|
||||
guaranteed_crossbreeds = list(
|
||||
/datum/raptor_color/green = /datum/raptor_color/yellow,
|
||||
/datum/raptor_color/blue = /datum/raptor_color/purple,
|
||||
)
|
||||
// Doesn't care for your excuses for friendly fire
|
||||
ai_controller = /datum/ai_controller/basic_controller/raptor/aggressive
|
||||
|
||||
/datum/raptor_color/purple
|
||||
color = "purple"
|
||||
description = "A small, nimble breed, these raptors have been bred as travel companions rather than mounts, capable of storing the owner's possessions and helping them escape from danger unscathed."
|
||||
health = 140 // smol
|
||||
rideable_component = /datum/component/riding/creature/raptor/small
|
||||
guaranteed_crossbreeds = list(
|
||||
/datum/raptor_color/green = /datum/raptor_color/white,
|
||||
/datum/raptor_color/yellow = /datum/raptor_color/blue,
|
||||
)
|
||||
|
||||
/datum/raptor_color/purple/setup_raptor(mob/living/basic/raptor/raptor)
|
||||
. = ..()
|
||||
RegisterSignal(raptor, COMSIG_MOVABLE_PREBUCKLE, PROC_REF(on_pre_buckle))
|
||||
raptor.inhand_holder_type = /obj/item/mob_holder/purple_raptor
|
||||
|
||||
/datum/raptor_color/purple/proc/on_pre_buckle(mob/living/basic/raptor/source, mob/living/potential_rider, force = FALSE, ride_check_flags = NONE)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if (!ishuman(potential_rider))
|
||||
return COMPONENT_BLOCK_BUCKLE
|
||||
|
||||
var/mob/living/carbon/human/rider = potential_rider
|
||||
if (rider.mob_height > HUMAN_HEIGHT_SHORTEST)
|
||||
to_chat(rider, span_warning("Your tall stature will crush [source] were you attempt to ride [source.p_them()]!"))
|
||||
return COMPONENT_BLOCK_BUCKLE
|
||||
|
||||
// Purple raptors never "fully" grow up, and remain usable as backpacks
|
||||
/datum/raptor_color/purple/setup_adult(mob/living/basic/raptor/raptor)
|
||||
raptor.base_pixel_w = initial(raptor.base_pixel_w)
|
||||
raptor.can_be_held = TRUE
|
||||
raptor.density = FALSE
|
||||
raptor.move_resist = MOVE_RESIST_DEFAULT
|
||||
raptor.change_offsets = FALSE
|
||||
raptor.remove_offsets(RAPTOR_INNATE_SOURCE, FALSE)
|
||||
raptor.held_w_class = WEIGHT_CLASS_BULKY
|
||||
. = ..()
|
||||
// Non-shorties cannot ride these, so we gotta keep em tameable through food
|
||||
raptor.AddComponent(/datum/component/tameable, food_types = raptor.food_types, tame_chance = 25, bonus_tame_chance = 15, unique = TRUE)
|
||||
if (raptor.atom_storage)
|
||||
return
|
||||
// A bit bigger (23 vs 21) than a backpack at max size, a bit less by default
|
||||
var/storage_volume = floor(19 * (1 + raptor.inherited_stats.ability_modifier))
|
||||
raptor.create_storage(
|
||||
max_total_storage = storage_volume,
|
||||
max_slots = storage_volume,
|
||||
storage_type = /datum/storage/raptor_storage,
|
||||
)
|
||||
|
||||
/datum/raptor_color/purple/setup_young(mob/living/basic/raptor/raptor)
|
||||
. = ..()
|
||||
if (raptor.atom_storage)
|
||||
return
|
||||
var/storage_volume = floor(19 * (1 + raptor.inherited_stats.ability_modifier))
|
||||
raptor.create_storage(
|
||||
max_total_storage = storage_volume,
|
||||
max_slots = storage_volume,
|
||||
storage_type = /datum/storage/raptor_storage,
|
||||
)
|
||||
|
||||
/obj/item/mob_holder/purple_raptor
|
||||
/// Wings action granted to whoever is wearing us on their back
|
||||
var/datum/action/innate/raptor_wings/flight_action = null
|
||||
|
||||
/// Are our wings open?
|
||||
var/wings_open = FALSE
|
||||
/// Wings underlay added to the owner, because human rendering code is a mess
|
||||
var/mutable_appearance/wings_underlay = null
|
||||
/// Our drift force
|
||||
var/drift_force = 2 NEWTONS
|
||||
/// Our stabilizing force
|
||||
var/stabilizer_force = 4.5 NEWTONS
|
||||
|
||||
/obj/item/mob_holder/purple_raptor/Initialize(mapload, mob/living/held_mob, worn_state, head_icon, lh_icon, rh_icon, worn_slot_flags)
|
||||
. = ..()
|
||||
|
||||
var/mob/living/basic/raptor/raptor = held_mob
|
||||
if (raptor.growth_stage == RAPTOR_BABY)
|
||||
return
|
||||
|
||||
// Create a mirror storage for our raptor when picked up to handle interactions
|
||||
var/datum/storage/raptor_storage = create_storage(
|
||||
max_total_storage = held_mob.atom_storage.max_total_storage,
|
||||
max_slots = held_mob.atom_storage.max_slots,
|
||||
storage_type = /datum/storage/raptor_storage,
|
||||
)
|
||||
raptor_storage.set_real_location(held_mob)
|
||||
raptor_storage.insert_on_attack = TRUE
|
||||
|
||||
if (raptor.growth_stage != RAPTOR_ADULT)
|
||||
return
|
||||
|
||||
flight_action = new(src)
|
||||
|
||||
AddComponent( \
|
||||
/datum/component/jetpack, \
|
||||
TRUE, \
|
||||
drift_force, \
|
||||
stabilizer_force, \
|
||||
COMSIG_RAPTOR_WINGS_OPENED, \
|
||||
COMSIG_RAPTOR_WINGS_CLOSED, \
|
||||
null, \
|
||||
CALLBACK(src, PROC_REF(can_fly)), \
|
||||
CALLBACK(src, PROC_REF(can_fly)), \
|
||||
)
|
||||
|
||||
/obj/item/mob_holder/purple_raptor/Destroy()
|
||||
if (ishuman(loc) && wings_open)
|
||||
toggle_wings(loc)
|
||||
QDEL_NULL(flight_action)
|
||||
return ..()
|
||||
|
||||
/obj/item/mob_holder/purple_raptor/equipped(mob/user, slot, initial)
|
||||
. = ..()
|
||||
if ((slot & ITEM_SLOT_BACK) && ishuman(user) && flight_action)
|
||||
flight_action.Grant(held_mob)
|
||||
flight_action.GiveAction(user)
|
||||
|
||||
/obj/item/mob_holder/purple_raptor/dropped(mob/user, silent)
|
||||
. = ..()
|
||||
if (wings_open)
|
||||
toggle_wings(user)
|
||||
// Removed in Destroy()
|
||||
if (flight_action)
|
||||
flight_action.Remove(held_mob)
|
||||
flight_action.HideFrom(user)
|
||||
|
||||
/obj/item/mob_holder/purple_raptor/proc/on_weight_updated(mob/living/carbon/human/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if (source.mob_height <= HUMAN_HEIGHT_SHORTEST && !HAS_TRAIT(source, TRAIT_FAT))
|
||||
source.remove_movespeed_modifier(/datum/movespeed_modifier/jetpack/raptor/slow)
|
||||
source.add_movespeed_modifier(/datum/movespeed_modifier/jetpack/raptor)
|
||||
else
|
||||
source.remove_movespeed_modifier(/datum/movespeed_modifier/jetpack/raptor)
|
||||
source.add_movespeed_modifier(/datum/movespeed_modifier/jetpack/raptor/slow)
|
||||
|
||||
/obj/item/mob_holder/purple_raptor/proc/can_fly()
|
||||
var/mob/living/carbon/human/user = loc
|
||||
if (!istype(user) || user.stat || user.body_position == LYING_DOWN || isnull(user.client))
|
||||
return FALSE
|
||||
|
||||
if (user.get_organ_slot(ORGAN_SLOT_EXTERNAL_WINGS))
|
||||
return FALSE
|
||||
|
||||
var/turf/location = get_turf(user)
|
||||
if (!istype(location))
|
||||
return FALSE
|
||||
|
||||
var/datum/gas_mixture/environment = location.return_air()
|
||||
if (environment?.return_pressure() >= HAZARD_LOW_PRESSURE + 10)
|
||||
return TRUE
|
||||
|
||||
to_chat(user, span_warning("The atmosphere is too thin for you to fly!"))
|
||||
return FALSE
|
||||
|
||||
/obj/item/mob_holder/purple_raptor/proc/toggle_wings(mob/living/carbon/human/user)
|
||||
// In case something goes wrong
|
||||
if (!istype(user))
|
||||
wings_open = FALSE
|
||||
worn_icon_state = icon_state
|
||||
SEND_SIGNAL(src, COMSIG_RAPTOR_WINGS_CLOSED, user)
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
return
|
||||
|
||||
if (!wings_open && !can_fly())
|
||||
return
|
||||
|
||||
wings_open = !wings_open
|
||||
worn_icon_state = "[icon_state][wings_open ? "_wings_out" : ""]"
|
||||
user.update_worn_back()
|
||||
|
||||
// Raptors won't have the best of times keeping up tall humans or fatties up in the air
|
||||
var/struggling = HAS_TRAIT(user, TRAIT_FAT) || user.mob_height > HUMAN_HEIGHT_SHORTEST
|
||||
if (wings_open)
|
||||
wings_underlay = user.apply_height_offsets(mutable_appearance(worn_icon, "raptor_purple_wings", -BODY_BEHIND_LAYER, user), UPPER_BODY)
|
||||
user.add_overlay(wings_underlay)
|
||||
user.physiology.stun_mod *= 2
|
||||
user.add_traits(list(TRAIT_MOVE_FLOATING, TRAIT_IGNORING_GRAVITY, TRAIT_NOGRAV_ALWAYS_DRIFT), REF(src))
|
||||
if (struggling)
|
||||
user.add_movespeed_modifier(/datum/movespeed_modifier/jetpack/raptor/slow)
|
||||
else
|
||||
user.add_movespeed_modifier(/datum/movespeed_modifier/jetpack/raptor)
|
||||
user.AddElement(/datum/element/forced_gravity, 0)
|
||||
passtable_on(user, REF(src))
|
||||
to_chat(user, span_notice("You begin gently hovering above ground as [held_mob] on your back starts furiously flapping [held_mob.p_their()] wings[struggling ? ", struggling to keep you up in the air" : ""]!"))
|
||||
user.set_resting(FALSE, TRUE)
|
||||
user.refresh_gravity()
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
RegisterSignals(user, list(COMSIG_HUMAN_HEIGHT_UPDATED, SIGNAL_ADDTRAIT(TRAIT_FAT), SIGNAL_REMOVETRAIT(TRAIT_FAT)), PROC_REF(on_weight_updated))
|
||||
SEND_SIGNAL(src, COMSIG_RAPTOR_WINGS_OPENED, user)
|
||||
return
|
||||
|
||||
user.cut_overlay(wings_underlay)
|
||||
QDEL_NULL(wings_underlay)
|
||||
user.physiology.stun_mod *= 0.5
|
||||
user.remove_traits(list(TRAIT_MOVE_FLOATING, TRAIT_IGNORING_GRAVITY, TRAIT_NOGRAV_ALWAYS_DRIFT), REF(src))
|
||||
user.remove_movespeed_modifier(/datum/movespeed_modifier/jetpack/raptor/slow)
|
||||
user.remove_movespeed_modifier(/datum/movespeed_modifier/jetpack/raptor)
|
||||
user.RemoveElement(/datum/element/forced_gravity, 0)
|
||||
passtable_off(user, REF(src))
|
||||
to_chat(user, span_notice("You settle gently back onto the ground[struggling ? ", [held_mob] on your back breathing out a sigh of releif" : ""]..."))
|
||||
user.refresh_gravity()
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
UnregisterSignal(user, list(COMSIG_HUMAN_HEIGHT_UPDATED, SIGNAL_ADDTRAIT(TRAIT_FAT), SIGNAL_REMOVETRAIT(TRAIT_FAT)))
|
||||
SEND_SIGNAL(src, COMSIG_RAPTOR_WINGS_CLOSED, user)
|
||||
|
||||
/obj/item/mob_holder/purple_raptor/process(seconds_per_tick)
|
||||
if (!can_fly())
|
||||
toggle_wings(loc)
|
||||
return PROCESS_KILL
|
||||
|
||||
/datum/storage/raptor_storage
|
||||
animated = FALSE
|
||||
insert_on_attack = FALSE // should flip when worn on the back
|
||||
|
||||
/datum/storage/raptor_storage/on_mousedropped_onto(datum/source, obj/item/dropping, mob/user)
|
||||
return NONE
|
||||
|
||||
/datum/action/innate/raptor_wings
|
||||
name = "Toggle Flight"
|
||||
check_flags = AB_CHECK_CONSCIOUS | AB_CHECK_IMMOBILE | AB_CHECK_INCAPACITATED
|
||||
button_icon = 'icons/mob/actions/actions_animal.dmi'
|
||||
button_icon_state = "raptor_wings"
|
||||
|
||||
/datum/action/innate/raptor_wings/Activate()
|
||||
var/obj/item/mob_holder/purple_raptor/holder = target
|
||||
var/mob/living/carbon/human/user = holder.loc
|
||||
if (istype(user) && user.get_item_by_slot(ITEM_SLOT_BACK) == holder)
|
||||
holder.toggle_wings(user)
|
||||
|
||||
/datum/raptor_color/green
|
||||
color = "green"
|
||||
description = "A tough breed of raptor, made to withstand the harshest of punishment and to laugh in the face of pain, \
|
||||
this breed is able to withstand more punishment than its peers."
|
||||
health = 400
|
||||
// redirect_shots = FALSE // Need to figure out if I want this or not here
|
||||
guaranteed_crossbreeds = list(
|
||||
/datum/raptor_color/purple = /datum/raptor_color/white,
|
||||
/datum/raptor_color/red = /datum/raptor_color/yellow,
|
||||
)
|
||||
|
||||
/datum/raptor_color/green/setup_adult(mob/living/basic/raptor/raptor)
|
||||
. = ..()
|
||||
var/ability_scale = 1 - INVERSE_LERP(RAPTOR_INHERIT_MIN_MODIFIER, RAPTOR_INHERIT_MAX_MODIFIER, raptor.inherited_stats.ability_modifier)
|
||||
var/mining_mod = round(ability_scale * 0.1, 0.025)
|
||||
if (ability_scale >= 0.75)
|
||||
mining_mod = 0
|
||||
raptor.AddComponent(/datum/component/proficient_miner, mining_mod, TRUE)
|
||||
|
||||
/datum/raptor_color/white
|
||||
color = "white"
|
||||
description = "A loving sort, it cares for it peers and rushes to their aid with reckless abandon. It is able to heal any raptors' ailments, and rescue its owner in case of an emergency."
|
||||
rideable_component = /datum/component/riding/creature/raptor/healer
|
||||
guaranteed_crossbreeds = list(
|
||||
/datum/raptor_color/blue = /datum/raptor_color/green,
|
||||
/datum/raptor_color/yellow = /datum/raptor_color/red,
|
||||
)
|
||||
|
||||
/datum/raptor_color/white/setup_young(mob/living/basic/raptor/raptor)
|
||||
. = ..()
|
||||
raptor.AddComponent( \
|
||||
/datum/component/healing_touch, \
|
||||
heal_brute = melee_damage_upper * 0.75 * (1 + raptor.inherited_stats.ability_modifier), \
|
||||
heal_burn = melee_damage_upper * 0.75 * (1 + raptor.inherited_stats.ability_modifier), \
|
||||
heal_time = 0, \
|
||||
valid_targets_typecache = typecacheof(list(/mob/living/basic/raptor)), \
|
||||
)
|
||||
|
||||
/datum/raptor_color/white/setup_adult(mob/living/basic/raptor/raptor)
|
||||
. = ..()
|
||||
qdel(raptor.GetComponent(/datum/component/healing_touch))
|
||||
raptor.AddComponent( \
|
||||
/datum/component/healing_touch, \
|
||||
heal_brute = melee_damage_upper * (1 + raptor.inherited_stats.ability_modifier), \
|
||||
heal_burn = melee_damage_upper * (1 + raptor.inherited_stats.ability_modifier), \
|
||||
heal_time = 0, \
|
||||
valid_targets_typecache = typecacheof(list(/mob/living/basic/raptor, /mob/living/carbon/human)), \
|
||||
extra_checks = CALLBACK(src, PROC_REF(heal_checks)), \
|
||||
healing_multiplier = CALLBACK(src, PROC_REF(heal_multiplier)), \
|
||||
)
|
||||
|
||||
/datum/raptor_color/white/proc/heal_checks(mob/living/healer, mob/living/target)
|
||||
if (istype(target, /mob/living/basic/raptor))
|
||||
return TRUE
|
||||
// Only heal raptors, or critted rider
|
||||
if (target.stat == CONSCIOUS || target.stat == DEAD)
|
||||
return FALSE
|
||||
return target.buckled == healer
|
||||
|
||||
/datum/raptor_color/white/proc/heal_multiplier(mob/living/healer, mob/living/target)
|
||||
if (istype(target, /mob/living/basic/raptor))
|
||||
return 1
|
||||
// The healing is slow so this is fine
|
||||
return 0.67
|
||||
|
||||
/datum/raptor_color/yellow
|
||||
color = "yellow"
|
||||
description = "This breed possesses greasy fast speed, DEMON speed, making light work of long pilgrimages. \
|
||||
It's said that a thunderclap could be heard when this breed reaches its maximum speed."
|
||||
speed = 0
|
||||
guaranteed_crossbreeds = list(
|
||||
/datum/raptor_color/purple = /datum/raptor_color/blue,
|
||||
/datum/raptor_color/white = /datum/raptor_color/red,
|
||||
)
|
||||
|
||||
/datum/raptor_color/blue
|
||||
color = "blue"
|
||||
description = "Covered in tough, lava-resistant feathers with thick insulated fur underneath, this breed is capable of marching through lava and fire alike."
|
||||
guaranteed_crossbreeds = list(
|
||||
/datum/raptor_color/red = /datum/raptor_color/purple,
|
||||
/datum/raptor_color/white = /datum/raptor_color/green,
|
||||
)
|
||||
|
||||
/datum/raptor_color/blue/setup_raptor(mob/living/basic/raptor/raptor)
|
||||
. = ..()
|
||||
raptor.add_traits(list(TRAIT_LAVA_IMMUNE, TRAIT_NOFIRE_SPREAD), INNATE_TRAIT)
|
||||
|
||||
/datum/raptor_color/black
|
||||
color = "black"
|
||||
description = "An ultra rare breed. Due to its sparse nature, not much is known about this sort. However it is said to possess many of its peers' abilities."
|
||||
health = 400
|
||||
speed = 0
|
||||
melee_damage_lower = 20
|
||||
melee_damage_upper = 25
|
||||
redirect_shots = FALSE
|
||||
rideable_component = /datum/component/riding/creature/raptor/combat
|
||||
ai_controller = /datum/ai_controller/basic_controller/raptor/aggressive
|
||||
spawn_chance = 1 // 1 in 150 chance without modifiers
|
||||
|
||||
/datum/raptor_color/black/setup_raptor(mob/living/basic/raptor/raptor)
|
||||
. = ..()
|
||||
raptor.add_traits(list(TRAIT_LAVA_IMMUNE, TRAIT_NOFIRE_SPREAD), INNATE_TRAIT)
|
||||
|
||||
/datum/raptor_color/black/setup_adult(mob/living/basic/raptor/raptor)
|
||||
. = ..()
|
||||
// Slightly worse than greens at this
|
||||
var/ability_scale = 1 - INVERSE_LERP(RAPTOR_INHERIT_MIN_MODIFIER, RAPTOR_INHERIT_MAX_MODIFIER, raptor.inherited_stats.ability_modifier)
|
||||
var/mining_mod = round(ability_scale * 0.2, 0.025)
|
||||
if (ability_scale >= 0.8)
|
||||
mining_mod = 0
|
||||
raptor.AddComponent(/datum/component/proficient_miner, mining_mod, TRUE)
|
||||
@@ -1,62 +1,64 @@
|
||||
/obj/item/raptor_dex
|
||||
name = "raptor Dex"
|
||||
name = "RaptorDex"
|
||||
desc = "A device used to analyze lavaland raptors!"
|
||||
icon = 'icons/obj/devices/scanner.dmi'
|
||||
icon_state = "raptor_dex"
|
||||
item_flags = NOBLUDGEON
|
||||
///current raptor we are analyzing
|
||||
var/datum/weakref/raptor
|
||||
/// Raptor scan data we have stored
|
||||
var/list/scan_data = list("raptor_scan" = FALSE)
|
||||
|
||||
/obj/item/raptor_dex/ui_interact(mob/user, datum/tgui/ui)
|
||||
if(isnull(raptor?.resolve()))
|
||||
balloon_alert(user, "no specimen data!")
|
||||
return TRUE
|
||||
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "RaptorDex")
|
||||
ui.open()
|
||||
|
||||
/obj/item/raptor_dex/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
var/mob/living/basic/raptor/my_raptor = raptor.resolve()
|
||||
|
||||
data["raptor_image"] = icon2base64(icon(icon = my_raptor.icon, icon_state = my_raptor.icon_state, frame = 1))
|
||||
data["raptor_attack"] = my_raptor.melee_damage_lower
|
||||
data["raptor_health"] = my_raptor.maxHealth
|
||||
data["raptor_speed"] = my_raptor.speed
|
||||
data["raptor_color"] = my_raptor.name
|
||||
data["raptor_gender"] = my_raptor.gender
|
||||
data["raptor_description"] = my_raptor.dex_description
|
||||
|
||||
var/happiness_percentage = my_raptor.ai_controller?.blackboard[BB_BASIC_HAPPINESS]
|
||||
var/obj/effect/overlay/happiness_overlay/display = new
|
||||
display.set_hearts(happiness_percentage)
|
||||
display.pixel_y = ICON_SIZE_Y * 0.5
|
||||
data["raptor_happiness"] = icon2base64(getFlatIcon(display, no_anim = TRUE))
|
||||
qdel(display)
|
||||
|
||||
var/datum/raptor_inheritance/inherit = my_raptor.inherited_stats
|
||||
if(isnull(inherit))
|
||||
return data
|
||||
|
||||
data["inherited_attack"] = inherit.attack_modifier
|
||||
data["inherited_attack_max"] = RAPTOR_INHERIT_MAX_ATTACK
|
||||
data["inherited_health"] = inherit.health_modifier
|
||||
data["inherited_health_max"] = RAPTOR_INHERIT_MAX_HEALTH
|
||||
|
||||
data["inherited_traits"] = list()
|
||||
for(var/index in inherit.inherit_traits)
|
||||
data["inherited_traits"] += GLOB.raptor_inherit_traits[index]
|
||||
return data
|
||||
|
||||
/obj/item/raptor_dex/ui_data(mob/user)
|
||||
return scan_data
|
||||
|
||||
/obj/item/raptor_dex/interact_with_atom(atom/attacked_atom, mob/living/user)
|
||||
if(!istype(attacked_atom, /mob/living/basic/raptor))
|
||||
return NONE
|
||||
|
||||
raptor = WEAKREF(attacked_atom)
|
||||
var/mob/living/basic/raptor/my_raptor = attacked_atom
|
||||
var/datum/movespeed_modifier/intent_mod = my_raptor.get_move_intent_slowdown()
|
||||
|
||||
scan_data = list()
|
||||
scan_data["raptor_scan"] = TRUE
|
||||
scan_data["raptor_image"] = icon2base64(icon(icon = my_raptor.icon, icon_state = my_raptor.icon_state, dir = SOUTH, frame = 1))
|
||||
scan_data["raptor_attack"] = my_raptor.melee_damage_lower
|
||||
scan_data["raptor_health"] = my_raptor.health
|
||||
scan_data["raptor_max_health"] = my_raptor.maxHealth
|
||||
scan_data["raptor_speed"] = my_raptor.speed + intent_mod?.multiplicative_slowdown
|
||||
scan_data["raptor_color"] = my_raptor.name
|
||||
scan_data["raptor_gender"] = my_raptor.gender
|
||||
scan_data["raptor_description"] = my_raptor.raptor_color.description
|
||||
|
||||
var/happiness_percentage = my_raptor.ai_controller?.blackboard[BB_BASIC_HAPPINESS]
|
||||
var/obj/effect/overlay/happiness_overlay/display = new()
|
||||
display.set_hearts(happiness_percentage)
|
||||
display.pixel_y = ICON_SIZE_Y * 0.5
|
||||
scan_data["raptor_happiness"] = icon2base64(getFlatIcon(display, no_anim = TRUE))
|
||||
qdel(display)
|
||||
|
||||
var/datum/raptor_inheritance/inherit = my_raptor.inherited_stats
|
||||
if(!isnull(inherit))
|
||||
scan_data["inherited_attack"] = inherit.attack_modifier
|
||||
scan_data["inherited_attack_max"] = RAPTOR_INHERIT_MAX_ATTACK
|
||||
scan_data["inherited_health"] = inherit.health_modifier
|
||||
scan_data["inherited_health_max"] = RAPTOR_INHERIT_MAX_HEALTH
|
||||
scan_data["inherited_speed"] = inherit.speed_modifier
|
||||
scan_data["inherited_speed_max"] = RAPTOR_INHERIT_MAX_SPEED
|
||||
scan_data["inherited_ability"] = inherit.ability_modifier
|
||||
scan_data["inherited_ability_max"] = RAPTOR_INHERIT_MAX_MODIFIER
|
||||
scan_data["inherited_growth"] = inherit.growth_modifier
|
||||
scan_data["inherited_growth_max"] = RAPTOR_INHERIT_MAX_MODIFIER
|
||||
|
||||
scan_data["inherited_traits"] = list()
|
||||
for(var/index in inherit.personality_traits)
|
||||
scan_data["inherited_traits"] += GLOB.raptor_inherit_traits[index]
|
||||
|
||||
playsound(src, 'sound/mobs/non-humanoids/orbie/orbie_send_out.ogg', 20)
|
||||
balloon_alert(user, "scanned")
|
||||
balloon_alert(my_raptor, "scanned")
|
||||
ui_interact(user)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
@@ -1,58 +1,52 @@
|
||||
/obj/item/food/egg/raptor_egg
|
||||
name = "raptor egg"
|
||||
desc = "An uneven egg with a rough, thick shell."
|
||||
icon = 'icons/mob/simple/lavaland/raptor_baby.dmi'
|
||||
icon_state = "raptor_egg"
|
||||
///inheritance datum to pass on to the child
|
||||
var/datum/raptor_inheritance/inherited_stats
|
||||
resistance_flags = LAVA_PROOF|FIRE_PROOF
|
||||
/// Color typepath of the child we spawn
|
||||
var/datum/raptor_color/child_color = /datum/raptor_color
|
||||
/// Inheritance data to pass onto the child
|
||||
var/datum/raptor_inheritance/inherited_stats = null
|
||||
/// Current growth progress
|
||||
var/growth_progress = 0
|
||||
/// Minimum growth progress per second
|
||||
var/min_growth_rate = 0.5
|
||||
/// Maximum growth progress per second
|
||||
var/max_growth_rate = 1
|
||||
|
||||
/obj/item/food/egg/raptor_egg/Initialize(mapload)
|
||||
. = ..()
|
||||
if(SSmapping.is_planetary())
|
||||
icon = 'icons/mob/simple/lavaland/raptor_icebox.dmi'
|
||||
|
||||
/obj/item/food/egg/raptor_egg/proc/determine_growth_path(mob/living/basic/raptor/dad, mob/living/basic/raptor/mom)
|
||||
if(dad.type == mom.type)
|
||||
add_growth_component(dad.child_path)
|
||||
return
|
||||
var/dad_color = dad.raptor_color
|
||||
var/mom_color = mom.raptor_color
|
||||
var/list/my_colors = list(dad_color, mom_color)
|
||||
sortTim(my_colors, GLOBAL_PROC_REF(cmp_text_asc))
|
||||
for(var/path in GLOB.raptor_growth_paths) //guaranteed spawns
|
||||
var/list/required_colors = GLOB.raptor_growth_paths[path]
|
||||
if(!compare_list(my_colors, required_colors))
|
||||
continue
|
||||
add_growth_component(path)
|
||||
return
|
||||
var/list/valid_subtypesof = list()
|
||||
var/static/list/all_subtypes = subtypesof(/mob/living/basic/raptor/baby_raptor)
|
||||
for(var/path in all_subtypes)
|
||||
var/mob/living/basic/raptor/baby_raptor/raptor_path = path
|
||||
if(!prob(initial(raptor_path.roll_rate)))
|
||||
continue
|
||||
valid_subtypesof += raptor_path
|
||||
add_growth_component(pick(valid_subtypesof))
|
||||
|
||||
/obj/item/food/egg/raptor_egg/proc/add_growth_component(growth_path)
|
||||
if(length(GLOB.raptor_population) >= MAX_RAPTOR_POP)
|
||||
return
|
||||
AddComponent(\
|
||||
/datum/component/fertile_egg,\
|
||||
embryo_type = growth_path,\
|
||||
minimum_growth_rate = 0.5,\
|
||||
maximum_growth_rate = 1,\
|
||||
total_growth_required = 100,\
|
||||
current_growth = 0,\
|
||||
location_allowlist = typecacheof(list(/turf)),\
|
||||
post_hatch = CALLBACK(src, PROC_REF(post_hatch)),\
|
||||
)
|
||||
|
||||
/obj/item/food/egg/raptor_egg/proc/post_hatch(mob/living/basic/raptor/baby)
|
||||
if(!istype(baby))
|
||||
return
|
||||
QDEL_NULL(baby.inherited_stats)
|
||||
baby.inherited_stats = inherited_stats
|
||||
inherited_stats = null
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/food/egg/raptor_egg/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
QDEL_NULL(inherited_stats)
|
||||
return ..()
|
||||
|
||||
/obj/item/food/egg/raptor_egg/examine(mob/user)
|
||||
. = ..()
|
||||
if (growth_progress >= RAPTOR_EGG_GROWTH_PROGRESS)
|
||||
. += span_boldnotice("Its noticeably shaking, ready to hatch!")
|
||||
|
||||
/obj/item/food/egg/raptor_egg/process(seconds_per_tick)
|
||||
if (!isturf(loc) || length(GLOB.raptor_population) >= MAX_RAPTOR_POP)
|
||||
return
|
||||
|
||||
var/growth_value = rand(min_growth_rate, max_growth_rate) * seconds_per_tick * (1 + inherited_stats.growth_modifier)
|
||||
// Slower growth off hot lavaland
|
||||
if (!SSmapping.level_trait(z, ZTRAIT_ASHSTORM))
|
||||
growth_value *= 0.75
|
||||
// Faster growth in hot hot lava
|
||||
if (islava(loc))
|
||||
growth_value *= 1.5
|
||||
|
||||
growth_progress += growth_value
|
||||
// Don't hatch on lava though, or the chick will die instantly
|
||||
if (growth_progress < RAPTOR_EGG_GROWTH_PROGRESS || islava(loc))
|
||||
return
|
||||
|
||||
visible_message(span_notice("[src] hatches with a quiet cracking sound."))
|
||||
new /mob/living/basic/raptor(loc, child_color, inherited_stats)
|
||||
inherited_stats = null
|
||||
qdel(src)
|
||||
|
||||
@@ -1,31 +1,97 @@
|
||||
#define RANDOM_INHERIT_AMOUNT 2
|
||||
/datum/raptor_inheritance
|
||||
///list of traits we inherit
|
||||
var/list/inherit_traits = list()
|
||||
///attack modifier
|
||||
var/attack_modifier
|
||||
///health_modifier
|
||||
var/health_modifier
|
||||
/// Inherited parent personality traits
|
||||
var/list/personality_traits = list()
|
||||
/// Flat damage modifier
|
||||
var/attack_modifier = 0
|
||||
/// Flat health modifier
|
||||
var/health_modifier = 0
|
||||
/// Speed modifier, not randomized by default
|
||||
var/speed_modifier = 0
|
||||
/// Primary ability stat modifier, not randomized by default
|
||||
/// Multiplier equates to 1 + this
|
||||
var/ability_modifier = 0
|
||||
/// Growth rate modifier, not randomized by default
|
||||
/// Multiplier equates to 1 + this
|
||||
var/growth_modifier = 0
|
||||
/// Foods eaten that can affect our child's stats -> stats they modify
|
||||
var/list/foods_eaten = list()
|
||||
/// List of all colors in our family tree
|
||||
var/list/parent_colors = list()
|
||||
|
||||
/datum/raptor_inheritance/New(datum/raptor_inheritance/father, datum/raptor_inheritance/mother)
|
||||
// Owner being set will randomize the stats as it means we're spawned not via an egg
|
||||
// otherwise wait for set_parents call to inherit genetics
|
||||
/datum/raptor_inheritance/New(mob/living/basic/raptor/owner)
|
||||
. = ..()
|
||||
randomize_stats()
|
||||
|
||||
/datum/raptor_inheritance/proc/randomize_stats()
|
||||
attack_modifier = rand(0, RAPTOR_INHERIT_MAX_ATTACK)
|
||||
health_modifier = rand(0, RAPTOR_INHERIT_MAX_HEALTH)
|
||||
var/list/traits_to_pick = GLOB.raptor_inherit_traits.Copy()
|
||||
for(var/i in 1 to RANDOM_INHERIT_AMOUNT)
|
||||
inherit_traits += pick_n_take(traits_to_pick)
|
||||
|
||||
/datum/raptor_inheritance/proc/set_parents(datum/raptor_inheritance/father, datum/raptor_inheritance/mother)
|
||||
if(isnull(father) || isnull(mother))
|
||||
if (!owner)
|
||||
return
|
||||
if(length(father.inherit_traits))
|
||||
inherit_traits += pick(father.inherit_traits)
|
||||
if(length(mother.inherit_traits))
|
||||
inherit_traits += pick(mother.inherit_traits)
|
||||
attack_modifier = rand(min(father.attack_modifier, mother.attack_modifier), max(father.attack_modifier, mother.attack_modifier))
|
||||
health_modifier = rand(min(father.health_modifier, mother.health_modifier), max(father.health_modifier, mother.health_modifier))
|
||||
|
||||
#undef RANDOM_INHERIT_AMOUNT
|
||||
attack_modifier = rand(RAPTOR_INHERIT_MIN_ATTACK * 0.5, RAPTOR_INHERIT_MAX_ATTACK * 0.5)
|
||||
health_modifier = rand(RAPTOR_INHERIT_MIN_HEALTH * 0.5, RAPTOR_INHERIT_MAX_HEALTH * 0.5)
|
||||
var/list/traits_to_pick = GLOB.raptor_inherit_traits.Copy()
|
||||
for(var/i in 1 to rand(1, RAPTOR_TRAIT_INHERIT_AMOUNT))
|
||||
personality_traits += pick_n_take(traits_to_pick)
|
||||
|
||||
/datum/raptor_inheritance/proc/set_parents(mob/living/basic/raptor/mother, mob/living/basic/raptor/father)
|
||||
var/datum/raptor_inheritance/mom_stats = mother.inherited_stats
|
||||
var/datum/raptor_inheritance/dad_stats = father.inherited_stats
|
||||
|
||||
parent_colors = mom_stats.parent_colors | dad_stats.parent_colors | mother.raptor_color.type | father.raptor_color.type
|
||||
|
||||
var/list/traits_to_pick = list()
|
||||
// + so shared traits have double the weight
|
||||
for (var/raptor_trait in mom_stats.personality_traits + dad_stats.personality_traits)
|
||||
if (!traits_to_pick[raptor_trait])
|
||||
traits_to_pick[raptor_trait] = 0
|
||||
traits_to_pick[raptor_trait] += 1
|
||||
|
||||
var/attack_mod = 0
|
||||
var/health_mod = 0
|
||||
var/speed_mod = 0
|
||||
var/ability_mod = 0
|
||||
var/growth_mod = 0
|
||||
var/amount_eaten = 0
|
||||
|
||||
for (var/food_type in foods_eaten)
|
||||
var/list/stat_mods = foods_eaten[food_type]
|
||||
amount_eaten += stat_mods["amount"]
|
||||
|
||||
for (var/food_type in foods_eaten)
|
||||
var/list/stat_mods = foods_eaten[food_type]
|
||||
// First multiply stats themselves, then multiply to get a proportion of this food from amount_eaten
|
||||
var/amount = stat_mods["amount"] ** 2
|
||||
// Eating other foods reduces the effects of a specific one
|
||||
attack_mod += stat_mods["attack"] / amount_eaten * amount
|
||||
health_mod += stat_mods["health"] / amount_eaten * amount
|
||||
speed_mod += stat_mods["speed"] / amount_eaten * amount
|
||||
ability_mod += stat_mods["ability"] / amount_eaten * amount
|
||||
growth_mod += stat_mods["growth"] / amount_eaten * amount
|
||||
var/list/trait_list = stat_mods["traits"]
|
||||
for (var/raptor_trait in trait_list)
|
||||
if (!traits_to_pick[raptor_trait])
|
||||
traits_to_pick[raptor_trait] = 0
|
||||
traits_to_pick[raptor_trait] += trait_list[raptor_trait] * stat_mods["amount"]
|
||||
|
||||
// If we don't clamp these, RNG and drift can get wildly out of control and result in polar values
|
||||
// and this way we at most get twice the minimum/maximum value, so at least half the rand spread is within the clamp values
|
||||
attack_mod = clamp(attack_mod, RAPTOR_INHERIT_MIN_ATTACK, RAPTOR_INHERIT_MAX_ATTACK)
|
||||
health_mod = clamp(health_mod, RAPTOR_INHERIT_MIN_HEALTH, RAPTOR_INHERIT_MAX_HEALTH)
|
||||
speed_mod = clamp(speed_mod, RAPTOR_INHERIT_MIN_SPEED, RAPTOR_INHERIT_MAX_SPEED)
|
||||
ability_mod = clamp(ability_mod, RAPTOR_INHERIT_MIN_MODIFIER, RAPTOR_INHERIT_MAX_MODIFIER)
|
||||
growth_mod = clamp(growth_mod, RAPTOR_INHERIT_MIN_MODIFIER, RAPTOR_INHERIT_MAX_MODIFIER)
|
||||
|
||||
attack_modifier = rand((min(mom_stats.attack_modifier, dad_stats.attack_modifier) + min(0, attack_mod)) + RAPTOR_GENETIC_DRIFT * RAPTOR_INHERIT_MIN_ATTACK, (max(mom_stats.attack_modifier, dad_stats.attack_modifier) + max(0, attack_mod)) + RAPTOR_GENETIC_DRIFT * RAPTOR_INHERIT_MAX_ATTACK)
|
||||
health_modifier = rand((min(mom_stats.health_modifier, dad_stats.health_modifier) + min(0, health_mod)) + RAPTOR_GENETIC_DRIFT * RAPTOR_INHERIT_MIN_HEALTH, (max(mom_stats.health_modifier, dad_stats.health_modifier) + max(0, health_mod)) + RAPTOR_GENETIC_DRIFT * RAPTOR_INHERIT_MAX_HEALTH)
|
||||
speed_modifier = rand((min(mom_stats.speed_modifier, dad_stats.speed_modifier) + min(0, speed_mod)) + RAPTOR_GENETIC_DRIFT * RAPTOR_INHERIT_MIN_SPEED, (max(mom_stats.speed_modifier, dad_stats.speed_modifier) + max(0, speed_mod)) + RAPTOR_GENETIC_DRIFT * RAPTOR_INHERIT_MAX_SPEED)
|
||||
ability_modifier = rand((min(mom_stats.ability_modifier, dad_stats.ability_modifier) + min(0, ability_mod)) + RAPTOR_GENETIC_DRIFT * RAPTOR_INHERIT_MIN_MODIFIER, (max(mom_stats.ability_modifier, dad_stats.ability_modifier) + max(0, ability_mod)) + RAPTOR_GENETIC_DRIFT * RAPTOR_INHERIT_MAX_MODIFIER)
|
||||
growth_modifier = rand((min(mom_stats.growth_modifier, dad_stats.growth_modifier) + min(0, growth_mod)) + RAPTOR_GENETIC_DRIFT * RAPTOR_INHERIT_MIN_MODIFIER, (max(mom_stats.growth_modifier, dad_stats.growth_modifier) + max(0, growth_mod)) + RAPTOR_GENETIC_DRIFT * RAPTOR_INHERIT_MAX_MODIFIER)
|
||||
|
||||
for(var/i in 1 to min(length(traits_to_pick), RAPTOR_TRAIT_INHERIT_AMOUNT))
|
||||
var/chosen_trait = pick_weight(traits_to_pick)
|
||||
traits_to_pick -= chosen_trait
|
||||
personality_traits += chosen_trait
|
||||
|
||||
attack_modifier = clamp(attack_modifier, RAPTOR_INHERIT_MIN_ATTACK, RAPTOR_INHERIT_MAX_ATTACK)
|
||||
health_modifier = clamp(health_modifier, RAPTOR_INHERIT_MIN_HEALTH, RAPTOR_INHERIT_MAX_HEALTH)
|
||||
speed_modifier = clamp(speed_modifier, RAPTOR_INHERIT_MIN_SPEED, RAPTOR_INHERIT_MAX_SPEED)
|
||||
ability_modifier = clamp(ability_modifier, RAPTOR_INHERIT_MIN_MODIFIER, RAPTOR_INHERIT_MAX_MODIFIER)
|
||||
growth_modifier = clamp(growth_modifier, RAPTOR_INHERIT_MIN_MODIFIER, RAPTOR_INHERIT_MAX_MODIFIER)
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
|
||||
/mob/living/basic/snail/mob_pickup(mob/living/user)
|
||||
var/obj/item/mob_holder/snail/holder = new(get_turf(src), src, held_state, head_icon, held_lh, held_rh, worn_slot_flags)
|
||||
SEND_SIGNAL(src, COMSIG_LIVING_SCOOPED_UP, user, holder)
|
||||
var/display_message = "[user] [HAS_TRAIT(src, TRAIT_MOVE_FLOATING) ? "scoops up [src]" : "peels [src] off the ground"]!"
|
||||
user.visible_message(span_warning(display_message))
|
||||
user.put_in_hands(holder)
|
||||
|
||||
@@ -280,6 +280,7 @@
|
||||
mob_height = dna?.species?.update_species_heights(src) || base_mob_height
|
||||
if(old_height != mob_height)
|
||||
regenerate_icons()
|
||||
SEND_SIGNAL(src, COMSIG_HUMAN_HEIGHT_UPDATED, old_height)
|
||||
|
||||
/**
|
||||
* Makes a full copy of src and returns it.
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
slot_flags = NONE
|
||||
/// Mob inside of us
|
||||
var/mob/living/held_mob
|
||||
/// True if we've started being destroyed
|
||||
var/destroying = FALSE
|
||||
lefthand_file = 'icons/mob/inhands/clothing/hats_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/clothing/hats_righthand.dmi'
|
||||
body_parts_covered = HEAD
|
||||
@@ -31,9 +29,9 @@
|
||||
return ..()
|
||||
|
||||
/obj/item/mob_holder/Destroy()
|
||||
destroying = TRUE
|
||||
if(held_mob)
|
||||
if(held_mob?.loc == src)
|
||||
release()
|
||||
held_mob = null
|
||||
return ..()
|
||||
|
||||
/obj/item/mob_holder/proc/insert_mob(mob/living/new_prisoner)
|
||||
@@ -78,11 +76,10 @@
|
||||
|
||||
/obj/item/mob_holder/proc/release(display_messages = TRUE)
|
||||
if(!held_mob)
|
||||
if(!destroying)
|
||||
if(!QDELETED(src))
|
||||
qdel(src)
|
||||
return FALSE
|
||||
var/mob/living/released_mob = held_mob
|
||||
held_mob = null // stops the held mob from being release()'d twice.
|
||||
if(isliving(loc))
|
||||
var/mob/living/captor = loc
|
||||
if(display_messages)
|
||||
@@ -93,7 +90,7 @@
|
||||
released_mob.setDir(SOUTH)
|
||||
if(display_messages)
|
||||
released_mob.visible_message(span_warning("[released_mob] uncurls!"))
|
||||
if(!destroying)
|
||||
if(!QDELETED(src))
|
||||
qdel(src)
|
||||
return TRUE
|
||||
|
||||
@@ -159,3 +156,6 @@
|
||||
if(. || !held_mob) // Another interaction was performed
|
||||
return
|
||||
tool.melee_attack_chain(user, held_mob, modifiers) //Interact with the mob with our tool
|
||||
|
||||
/obj/item/mob_holder/IsContainedAtomAccessible(atom/contained, atom/movable/user)
|
||||
return TRUE
|
||||
|
||||
@@ -1965,7 +1965,8 @@ GLOBAL_LIST_EMPTY(fire_appearances)
|
||||
return ..()
|
||||
|
||||
/mob/living/proc/mob_pickup(mob/living/user)
|
||||
var/obj/item/mob_holder/holder = new(get_turf(src), src, held_state, head_icon, held_lh, held_rh, worn_slot_flags)
|
||||
var/obj/item/mob_holder/holder = new inhand_holder_type(get_turf(src), src, held_state, head_icon, held_lh, held_rh, worn_slot_flags)
|
||||
SEND_SIGNAL(src, COMSIG_LIVING_SCOOPED_UP, user, holder)
|
||||
user.visible_message(span_warning("[user] scoops up [src]!"))
|
||||
user.put_in_hands(holder)
|
||||
|
||||
|
||||
@@ -204,6 +204,8 @@
|
||||
var/icon/head_icon = 'icons/mob/clothing/head/pets_head.dmi'
|
||||
/// icon_state for holding mobs.
|
||||
var/held_state = ""
|
||||
/// Typepath of the holder created when we're picked up
|
||||
var/inhand_holder_type = /obj/item/mob_holder
|
||||
|
||||
///If combat mode is on or not
|
||||
var/combat_mode = FALSE
|
||||
|
||||
@@ -259,6 +259,7 @@
|
||||
greyscale_colors = "#927444#8b4c31#4c202d"
|
||||
starting_programs = list(
|
||||
/datum/computer_file/program/skill_tracker,
|
||||
/datum/computer_file/program/raptordex,
|
||||
)
|
||||
|
||||
/obj/item/modular_computer/pda/bitrunner
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/datum/computer_file/program/raptordex
|
||||
filename = "raptordex"
|
||||
filedesc = "RaptorDex"
|
||||
downloader_category = PROGRAM_CATEGORY_DEVICE
|
||||
program_open_overlay = "bountyboard"
|
||||
extended_desc = "Scan and analyze raptor genes."
|
||||
size = 2
|
||||
tgui_id = "RaptorDex"
|
||||
program_icon = "crow"
|
||||
can_run_on_flags = PROGRAM_PDA
|
||||
/// Raptor scan data we have stored
|
||||
var/list/scan_data = list("raptor_scan" = FALSE)
|
||||
|
||||
/datum/computer_file/program/raptordex/tap(atom/tapped_atom, mob/living/user, list/modifiers)
|
||||
if(!istype(tapped_atom, /mob/living/basic/raptor))
|
||||
return FALSE
|
||||
|
||||
var/mob/living/basic/raptor/my_raptor = tapped_atom
|
||||
var/datum/movespeed_modifier/intent_mod = my_raptor.get_move_intent_slowdown()
|
||||
|
||||
scan_data = list()
|
||||
scan_data["raptor_scan"] = TRUE
|
||||
scan_data["raptor_image"] = icon2base64(icon(icon = my_raptor.icon, icon_state = my_raptor.icon_state, dir = SOUTH, frame = 1))
|
||||
scan_data["raptor_attack"] = my_raptor.melee_damage_lower
|
||||
scan_data["raptor_health"] = my_raptor.health
|
||||
scan_data["raptor_max_health"] = my_raptor.maxHealth
|
||||
scan_data["raptor_speed"] = my_raptor.speed + intent_mod?.multiplicative_slowdown
|
||||
scan_data["raptor_color"] = my_raptor.name
|
||||
scan_data["raptor_gender"] = my_raptor.gender
|
||||
scan_data["raptor_description"] = my_raptor.raptor_color.description
|
||||
|
||||
var/happiness_percentage = my_raptor.ai_controller?.blackboard[BB_BASIC_HAPPINESS]
|
||||
var/obj/effect/overlay/happiness_overlay/display = new()
|
||||
display.set_hearts(happiness_percentage)
|
||||
display.pixel_y = ICON_SIZE_Y * 0.5
|
||||
scan_data["raptor_happiness"] = icon2base64(getFlatIcon(display, no_anim = TRUE))
|
||||
qdel(display)
|
||||
|
||||
var/datum/raptor_inheritance/inherit = my_raptor.inherited_stats
|
||||
if(!isnull(inherit))
|
||||
scan_data["inherited_attack"] = inherit.attack_modifier
|
||||
scan_data["inherited_attack_max"] = RAPTOR_INHERIT_MAX_ATTACK
|
||||
scan_data["inherited_health"] = inherit.health_modifier
|
||||
scan_data["inherited_health_max"] = RAPTOR_INHERIT_MAX_HEALTH
|
||||
scan_data["inherited_speed"] = inherit.speed_modifier
|
||||
scan_data["inherited_speed_max"] = RAPTOR_INHERIT_MAX_SPEED
|
||||
scan_data["inherited_ability"] = inherit.ability_modifier
|
||||
scan_data["inherited_ability_max"] = RAPTOR_INHERIT_MAX_MODIFIER
|
||||
scan_data["inherited_growth"] = inherit.growth_modifier
|
||||
scan_data["inherited_growth_max"] = RAPTOR_INHERIT_MAX_MODIFIER
|
||||
|
||||
scan_data["inherited_traits"] = list()
|
||||
for(var/index in inherit.personality_traits)
|
||||
scan_data["inherited_traits"] += GLOB.raptor_inherit_traits[index]
|
||||
|
||||
playsound(computer, 'sound/mobs/non-humanoids/orbie/orbie_send_out.ogg', 20)
|
||||
my_raptor.balloon_alert(user, "scanned")
|
||||
return TRUE
|
||||
|
||||
/datum/computer_file/program/raptordex/ui_data(mob/user)
|
||||
return scan_data
|
||||
@@ -11,6 +11,12 @@
|
||||
/datum/movespeed_modifier/jetpack/wings
|
||||
multiplicative_slowdown = -0.3
|
||||
|
||||
/datum/movespeed_modifier/jetpack/raptor
|
||||
multiplicative_slowdown = 0.2
|
||||
|
||||
/datum/movespeed_modifier/jetpack/raptor/slow
|
||||
multiplicative_slowdown = 1
|
||||
|
||||
/datum/movespeed_modifier/die_of_fate
|
||||
multiplicative_slowdown = 1
|
||||
|
||||
|
||||
@@ -163,10 +163,10 @@
|
||||
variable = TRUE
|
||||
|
||||
/datum/movespeed_modifier/goliath_mount
|
||||
multiplicative_slowdown = -26
|
||||
multiplicative_slowdown = -27.5
|
||||
|
||||
/datum/movespeed_modifier/goldgrub_mount
|
||||
multiplicative_slowdown = -3
|
||||
multiplicative_slowdown = -4.5
|
||||
|
||||
/datum/movespeed_modifier/settler
|
||||
multiplicative_slowdown = 0.2
|
||||
|
||||
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 33 KiB |
@@ -1625,6 +1625,7 @@
|
||||
#include "code\datums\elements\radiation_protected_clothing.dm"
|
||||
#include "code\datums\elements\radioactive.dm"
|
||||
#include "code\datums\elements\ranged_armour.dm"
|
||||
#include "code\datums\elements\raptor_food.dm"
|
||||
#include "code\datums\elements\reagents_heated_on_fire.dm"
|
||||
#include "code\datums\elements\reagents_item_heatable.dm"
|
||||
#include "code\datums\elements\regal_rat_minion.dm"
|
||||
@@ -5199,10 +5200,10 @@
|
||||
#include "code\modules\mob\living\basic\lavaland\mook\mook_village.dm"
|
||||
#include "code\modules\mob\living\basic\lavaland\node_drone\node_drone.dm"
|
||||
#include "code\modules\mob\living\basic\lavaland\raptor\_raptor.dm"
|
||||
#include "code\modules\mob\living\basic\lavaland\raptor\baby_raptor.dm"
|
||||
#include "code\modules\mob\living\basic\lavaland\raptor\raptor_ai_behavior.dm"
|
||||
#include "code\modules\mob\living\basic\lavaland\raptor\raptor_ai_controller.dm"
|
||||
#include "code\modules\mob\living\basic\lavaland\raptor\raptor_ai_subtrees.dm"
|
||||
#include "code\modules\mob\living\basic\lavaland\raptor\raptor_color.dm"
|
||||
#include "code\modules\mob\living\basic\lavaland\raptor\raptor_dex.dm"
|
||||
#include "code\modules\mob\living\basic\lavaland\raptor\raptor_egg.dm"
|
||||
#include "code\modules\mob\living\basic\lavaland\raptor\raptor_food_trough.dm"
|
||||
@@ -5656,6 +5657,7 @@
|
||||
#include "code\modules\modular_computers\file_system\programs\portrait_printer.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\powermonitor.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\radar.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\raptordex.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\records.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\restock_tracker.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\robocontrol.dm"
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
import {
|
||||
Image,
|
||||
LabeledList,
|
||||
Modal,
|
||||
ProgressBar,
|
||||
Section,
|
||||
Stack,
|
||||
} from 'tgui-core/components';
|
||||
|
||||
import { capitalizeAll, capitalizeFirst } from 'tgui-core/string';
|
||||
import { useBackend } from '../backend';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
type Data = {
|
||||
raptor_scan: boolean;
|
||||
raptor_attack: number;
|
||||
raptor_health: number;
|
||||
raptor_max_health: number;
|
||||
raptor_speed: number;
|
||||
raptor_color: string;
|
||||
raptor_image: string;
|
||||
@@ -22,14 +25,22 @@ type Data = {
|
||||
inherited_attack_max: number;
|
||||
inherited_health: number;
|
||||
inherited_health_max: number;
|
||||
inherited_speed: number;
|
||||
inherited_speed_max: number;
|
||||
inherited_ability: number;
|
||||
inherited_ability_max: number;
|
||||
inherited_growth: number;
|
||||
inherited_growth_max: number;
|
||||
inherited_traits: string[];
|
||||
};
|
||||
|
||||
export const RaptorDex = (props) => {
|
||||
const { act, data } = useBackend<Data>();
|
||||
const {
|
||||
raptor_scan,
|
||||
raptor_attack,
|
||||
raptor_health,
|
||||
raptor_max_health,
|
||||
raptor_speed,
|
||||
raptor_image,
|
||||
raptor_gender,
|
||||
@@ -37,21 +48,39 @@ export const RaptorDex = (props) => {
|
||||
inherited_attack_max,
|
||||
inherited_health,
|
||||
inherited_health_max,
|
||||
inherited_speed,
|
||||
inherited_speed_max,
|
||||
inherited_ability,
|
||||
inherited_ability_max,
|
||||
inherited_growth,
|
||||
inherited_growth_max,
|
||||
raptor_happiness,
|
||||
inherited_traits,
|
||||
raptor_description,
|
||||
raptor_color,
|
||||
} = data;
|
||||
|
||||
if (!raptor_scan) {
|
||||
return (
|
||||
<Window title="Raptor Data" width={625} height={420} theme="hackerman">
|
||||
<Window.Content>
|
||||
<Modal textAlign="center">No scan data present.</Modal>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Window title="Raptor Data" width={625} height={370} theme="hackerman">
|
||||
<Window title="Raptor Data" width={770} height={370} theme="hackerman">
|
||||
<Window.Content>
|
||||
<Stack>
|
||||
{' '}
|
||||
<Stack.Item width="33%">
|
||||
<Section textAlign="center" title={raptor_color}>
|
||||
<Section textAlign="center" title={capitalizeAll(raptor_color)}>
|
||||
<Image
|
||||
src={`data:image/jpeg;base64,${raptor_image}`}
|
||||
height="160px"
|
||||
width="160px"
|
||||
height="128px"
|
||||
width="224px"
|
||||
style={{
|
||||
verticalAlign: 'middle',
|
||||
borderRadius: '1em',
|
||||
@@ -59,21 +88,24 @@ export const RaptorDex = (props) => {
|
||||
}}
|
||||
/>
|
||||
</Section>
|
||||
<Section fill title="Description">
|
||||
{raptor_description}
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
<Stack.Item width="33%" textAlign="center">
|
||||
<Section title="Stats">
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Health">
|
||||
{raptor_health}
|
||||
{raptor_health} / {raptor_max_health}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Attack">
|
||||
{raptor_attack}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Speed">
|
||||
{10 - raptor_speed}
|
||||
{Math.round(10 / Math.max(raptor_speed, 0.5))}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Gender">
|
||||
{raptor_gender}
|
||||
{capitalizeFirst(raptor_gender)}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
@@ -84,12 +116,9 @@ export const RaptorDex = (props) => {
|
||||
value={inherited_health}
|
||||
maxValue={inherited_health_max}
|
||||
ranges={{
|
||||
good: [0.7 * inherited_health_max, inherited_health_max],
|
||||
average: [
|
||||
0.4 * inherited_health_max,
|
||||
inherited_health_max,
|
||||
],
|
||||
bad: [-Infinity, inherited_health_max],
|
||||
good: [0.5 * inherited_health_max, Infinity],
|
||||
average: [0, inherited_health_max * 0.5],
|
||||
bad: [-Infinity, 0],
|
||||
}}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
@@ -98,12 +127,42 @@ export const RaptorDex = (props) => {
|
||||
value={inherited_attack}
|
||||
maxValue={inherited_attack_max}
|
||||
ranges={{
|
||||
good: [0.7 * inherited_attack_max, inherited_attack_max],
|
||||
average: [
|
||||
0.4 * inherited_attack_max,
|
||||
inherited_attack_max,
|
||||
],
|
||||
bad: [-Infinity, inherited_attack_max],
|
||||
good: [0.5 * inherited_attack_max, Infinity],
|
||||
average: [0, inherited_attack_max * 0.5],
|
||||
bad: [-Infinity, 0],
|
||||
}}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Speed">
|
||||
<ProgressBar
|
||||
value={inherited_speed}
|
||||
maxValue={inherited_speed_max}
|
||||
ranges={{
|
||||
good: [0.5 * inherited_speed_max, Infinity],
|
||||
average: [0, inherited_speed_max * 0.5],
|
||||
bad: [-Infinity, 0],
|
||||
}}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Capability">
|
||||
<ProgressBar
|
||||
value={inherited_ability}
|
||||
maxValue={inherited_ability_max}
|
||||
ranges={{
|
||||
good: [0.5 * inherited_ability_max, Infinity],
|
||||
average: [0, inherited_ability_max * 0.5],
|
||||
bad: [-Infinity, 0],
|
||||
}}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Growth Speed">
|
||||
<ProgressBar
|
||||
value={inherited_growth}
|
||||
maxValue={inherited_growth_max}
|
||||
ranges={{
|
||||
good: [0.5 * inherited_growth_max, Infinity],
|
||||
average: [0, inherited_growth_max * 0.5],
|
||||
bad: [-Infinity, 0],
|
||||
}}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
@@ -113,7 +172,7 @@ export const RaptorDex = (props) => {
|
||||
<Stack.Item width="33%">
|
||||
<Section textAlign="center" title="Friendship bond">
|
||||
<Image
|
||||
mt={-7}
|
||||
mt={-9.5}
|
||||
src={`data:image/jpeg;base64,${raptor_happiness}`}
|
||||
height="72px"
|
||||
width="72px"
|
||||
@@ -128,9 +187,6 @@ export const RaptorDex = (props) => {
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
<Section fill title="Desc">
|
||||
{raptor_description}
|
||||
</Section>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
|
||||