mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-19 12:05:59 +01:00
Raptor Rework - Ranching and Companionship (#93564)
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user