mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-25 08:34:23 +00:00
About The Pull Request Chiefly this refactors dogs to use the newer component/datum system for "pet which follows instructions". It also refactors it a little bit because I had better ideas while working on this than I had last week. Specifically, instead of passing around keys we just stick a weakref to our currently active behaviour in the blackboard. Basically the same but skipping an unecessary step. Additionally it adds a component for the previous "befriending a mob by clicking it repeatedly" behaviour which hopefully we won't use too much because it's not very exciting (I am planning on replacing it for dogs some time after Christmas). The biggest effort in here was making the Fetch command more generic, which includes multiple behaviours (which might be used on their own?) and another component (for holding an item without hands). Additionally I noticed that dogs would keep following my instructions after they died. This seems unideal, and would be unideal for virtually any AI controller, so I added it as an AI_flag just in case there's some circumstance where you do want to process AI on a dead mob. Finally this should replicate all behaviour Ian already had plus "follow" (from rats) and a new bonus easter egg reaction, however I noticed that the fetch command is supposed to have Ian eat any food that you try to get him to fetch. This has been broken for some time and I will be away from my desk for a couple weeks pretty soon, so I wrote the behaviour for this but left it unused. I will come back to this in the future, once I figure out a way to implement it which does not require adding the "you can hit this" flag to every edible item. Also I had to refit the recent addition of dogs barking at felinids to fit into this, with a side effect that now dogs won't get mad at a Felinid they are friends with. This... feels like intended behaviour anyway? Why It's Good For The Game It's good for these to work the same way instead of reimplementing the same behaviour in multiple files. Being able to have Ian (or other dogs) follow you around the station is both fun and cute, and also makes him significantly more vulnerable to being murdered. Changelog cl add: Ian has learned some new tricks, tell him what a good boy he is! add: Ian will come on a walk with you, if you are his friend. refactor: Ian's tricks work the same way as some other mobs' tricks and should be extendable to future mobs. fix: Dogs no longer run at the maximum possible speed for a mob at all times. add: When Ian gets old, he also slows down. Poor little guy. add: Dogs will no longer dislike the presence of Felinids who have taken the time to befriend them. /cl
205 lines
7.5 KiB
Plaintext
205 lines
7.5 KiB
Plaintext
///Simple animals 2.0, This time, let's really try to keep it simple. This basetype should purely be used as a base-level for implementing simplified behaviours for things such as damage and attacks. Everything else should be in components or AI behaviours.
|
|
/mob/living/basic
|
|
name = "basic mob"
|
|
icon = 'icons/mob/simple/animal.dmi'
|
|
health = 20
|
|
maxHealth = 20
|
|
gender = PLURAL
|
|
living_flags = MOVES_ON_ITS_OWN
|
|
status_flags = CANPUSH
|
|
|
|
var/basic_mob_flags = NONE
|
|
|
|
///Defines how fast the basic mob can move. This is a multiplier
|
|
var/speed = 1
|
|
///How much stamina the mob recovers per second
|
|
var/stamina_recovery = 5
|
|
|
|
///how much damage this basic mob does to objects, if any.
|
|
var/obj_damage = 0
|
|
///How much armour they ignore, as a flat reduction from the targets armour value.
|
|
var/armour_penetration = 0
|
|
///Damage type of a simple mob's melee attack, should it do damage.
|
|
var/melee_damage_type = BRUTE
|
|
///How much wounding power it has
|
|
var/wound_bonus = CANT_WOUND
|
|
///How much bare wounding power it has
|
|
var/bare_wound_bonus = 0
|
|
///If the attacks from this are sharp
|
|
var/sharpness = NONE
|
|
|
|
/// Sound played when the critter attacks.
|
|
var/attack_sound
|
|
/// Override for the visual attack effect shown on 'do_attack_animation()'.
|
|
var/attack_vis_effect
|
|
///Played when someone punches the creature.
|
|
var/attacked_sound = SFX_PUNCH //This should be an element
|
|
|
|
///What kind of objects this mob can smash.
|
|
var/environment_smash = ENVIRONMENT_SMASH_NONE
|
|
|
|
/// 1 for full damage, 0 for none, -1 for 1:1 heal from that source.
|
|
var/list/damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
|
|
///Minimum force required to deal any damage.
|
|
var/force_threshold = 0
|
|
|
|
///Verbs used for speaking e.g. "Says" or "Chitters". This can be elementized
|
|
var/list/speak_emote = list()
|
|
|
|
///When someone interacts with the simple animal.
|
|
///Help-intent verb in present continuous tense.
|
|
var/response_help_continuous = "pokes"
|
|
///Help-intent verb in present simple tense.
|
|
var/response_help_simple = "poke"
|
|
///Disarm-intent verb in present continuous tense.
|
|
var/response_disarm_continuous = "shoves"
|
|
///Disarm-intent verb in present simple tense.
|
|
var/response_disarm_simple = "shove"
|
|
///Harm-intent verb in present continuous tense.
|
|
var/response_harm_continuous = "hits"
|
|
///Harm-intent verb in present simple tense.
|
|
var/response_harm_simple = "hit"
|
|
|
|
///Basic mob's own attacks verbs,
|
|
///Attacking verb in present continuous tense.
|
|
var/attack_verb_continuous = "attacks"
|
|
///Attacking verb in present simple tense.
|
|
var/attack_verb_simple = "attack"
|
|
///Attacking, but without damage, verb in present continuous tense.
|
|
var/friendly_verb_continuous = "nuzzles"
|
|
///Attacking, but without damage, verb in present simple tense.
|
|
var/friendly_verb_simple = "nuzzle"
|
|
|
|
////////THIS SECTION COULD BE ITS OWN ELEMENT
|
|
///Icon to use
|
|
var/icon_living = ""
|
|
///Icon when the animal is dead. Don't use animated icons for this.
|
|
var/icon_dead = ""
|
|
///We only try to show a gibbing animation if this exists.
|
|
var/icon_gib = null
|
|
|
|
///If the mob can be spawned with a gold slime core. HOSTILE_SPAWN are spawned with plasma, FRIENDLY_SPAWN are spawned with blood.
|
|
var/gold_core_spawnable = NO_SPAWN
|
|
///Sentience type, for slime potions. SHOULD BE AN ELEMENT BUT I DONT CARE ABOUT IT FOR NOW
|
|
var/sentience_type = SENTIENCE_ORGANIC
|
|
|
|
///Leaving something at 0 means it's off - has no maximum.
|
|
var/list/habitable_atmos = list("min_oxy" = 5, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0)
|
|
///This damage is taken when atmos doesn't fit all the requirements above. Set to 0 to avoid adding the atmos_requirements element.
|
|
var/unsuitable_atmos_damage = 1
|
|
|
|
///Minimal body temperature without receiving damage
|
|
var/minimum_survivable_temperature = 250
|
|
///Maximal body temperature without receiving damage
|
|
var/maximum_survivable_temperature = 350
|
|
///This damage is taken when the body temp is too cold. Set both this and unsuitable_heat_damage to 0 to avoid adding the basic_body_temp_sensitive element.
|
|
var/unsuitable_cold_damage = 1
|
|
///This damage is taken when the body temp is too hot. Set both this and unsuitable_cold_damage to 0 to avoid adding the basic_body_temp_sensitive element.
|
|
var/unsuitable_heat_damage = 1
|
|
|
|
/mob/living/basic/Initialize(mapload)
|
|
. = ..()
|
|
|
|
if(gender == PLURAL)
|
|
gender = pick(MALE,FEMALE)
|
|
|
|
if(!real_name)
|
|
real_name = name
|
|
|
|
if(!loc)
|
|
stack_trace("Basic mob being instantiated in nullspace")
|
|
|
|
update_basic_mob_varspeed()
|
|
|
|
if(speak_emote)
|
|
speak_emote = string_list(speak_emote)
|
|
|
|
if(unsuitable_atmos_damage != 0)
|
|
//String assoc list returns a cached list, so this is like a static list to pass into the element below.
|
|
habitable_atmos = string_assoc_list(habitable_atmos)
|
|
AddElement(/datum/element/atmos_requirements, habitable_atmos, unsuitable_atmos_damage)
|
|
|
|
if(unsuitable_cold_damage != 0 && unsuitable_heat_damage != 0)
|
|
AddElement(/datum/element/basic_body_temp_sensitive, minimum_survivable_temperature, maximum_survivable_temperature, unsuitable_cold_damage, unsuitable_heat_damage)
|
|
|
|
/mob/living/basic/Life(delta_time = SSMOBS_DT, times_fired)
|
|
. = ..()
|
|
///Automatic stamina re-gain
|
|
if(staminaloss > 0)
|
|
adjustStaminaLoss(-stamina_recovery * delta_time, FALSE, TRUE)
|
|
|
|
/mob/living/basic/say_mod(input, list/message_mods = list())
|
|
if(length(speak_emote))
|
|
verb_say = pick(speak_emote)
|
|
return ..()
|
|
|
|
/mob/living/basic/death(gibbed)
|
|
. = ..()
|
|
if(basic_mob_flags & DEL_ON_DEATH)
|
|
qdel(src)
|
|
else
|
|
health = 0
|
|
look_dead()
|
|
|
|
/**
|
|
* Apply the appearance and properties this mob has when it dies
|
|
* This is called by the mob pretending to be dead too so don't put loot drops in here or something
|
|
*/
|
|
/mob/living/basic/proc/look_dead()
|
|
icon_state = icon_dead
|
|
if(basic_mob_flags & FLIP_ON_DEATH)
|
|
transform = transform.Turn(180)
|
|
if(basic_mob_flags & UNDENSIFY_ON_DEATH)
|
|
set_density(FALSE)
|
|
|
|
/mob/living/basic/revive(full_heal_flags = NONE, excess_healing = 0, force_grab_ghost = FALSE)
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
look_alive()
|
|
|
|
/// Apply the appearance and properties this mob has when it is alive
|
|
/mob/living/basic/proc/look_alive()
|
|
icon_state = icon_living
|
|
if(basic_mob_flags & FLIP_ON_DEATH)
|
|
transform = transform.Turn(180)
|
|
if(basic_mob_flags & UNDENSIFY_ON_DEATH)
|
|
set_density(initial(density))
|
|
|
|
/mob/living/basic/proc/melee_attack(atom/target, list/modifiers)
|
|
face_atom(target)
|
|
if(SEND_SIGNAL(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, target) & COMPONENT_HOSTILE_NO_ATTACK)
|
|
return FALSE //but more importantly return before attack_animal called
|
|
var/result = target.attack_basic_mob(src, modifiers)
|
|
SEND_SIGNAL(src, COMSIG_HOSTILE_POST_ATTACKINGTARGET, target, result)
|
|
return result
|
|
|
|
/mob/living/basic/resolve_unarmed_attack(atom/attack_target, list/modifiers)
|
|
melee_attack(attack_target, modifiers)
|
|
|
|
/mob/living/basic/vv_edit_var(vname, vval)
|
|
. = ..()
|
|
if(vname == NAMEOF(src, speed))
|
|
datum_flags |= DF_VAR_EDITED
|
|
set_varspeed(vval)
|
|
|
|
/mob/living/basic/proc/set_varspeed(var_value)
|
|
speed = var_value
|
|
update_basic_mob_varspeed()
|
|
|
|
/mob/living/basic/proc/update_basic_mob_varspeed()
|
|
if(speed == 0)
|
|
remove_movespeed_modifier(/datum/movespeed_modifier/simplemob_varspeed)
|
|
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/simplemob_varspeed, multiplicative_slowdown = speed)
|
|
SEND_SIGNAL(src, POST_BASIC_MOB_UPDATE_VARSPEED)
|
|
|
|
/mob/living/basic/relaymove(mob/living/user, direction)
|
|
if(user.incapacitated())
|
|
return
|
|
return relaydrive(user, direction)
|
|
|
|
/mob/living/basic/get_status_tab_items()
|
|
. = ..()
|
|
. += "Health: [round((health / maxHealth) * 100)]%"
|
|
. += "Combat Mode: [combat_mode ? "On" : "Off"]"
|