mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-30 03:22:41 +00:00
About The Pull Request
Made a basic version of the pet base called /mob/living/basic/pet. It's significantly more stripped down from the old simple_animal one, because its half collar stuff and...
Made the collar slot a component that you could theoretically remove from a pet to disable the behavior, or add to any other living mob as long as you set up the icon states for the collar (or not, the visuals are optional).
The corgi's collar strippable slot is now generally the pet collar slot, and in theory could be used for other pet stripping screens.
I also gutted the extra access card code from /mob/living/basic/pet as it's only being used by corgis. Having a physical ID is now just inherent to corgis, as they're the only ones that could equip it anyway.
Ported the make_babies() function from simple_animals to a new subtree and associated behavior, called /datum/ai_planning_subtree/make_babies that uses blackboards to know the animal-specific info.
Note that it's marginally improved, as the female walks to the male first instead of bluespace reproduction.
Tweaked and improved the dog AI to work as a basic mob, including making /datum/idle_behavior/idle_dog fully functional.
Made a /datum/ai_planning_subtree/random_speech/dog that pulls the dynamic speech and emotes to support dog fashion.
I've tested base collars across multiple pet types.
For dogs, I've tested general behavior, fetching, reproduction, dog fashion, and deadchat_plays, covering all the oddities I'm aware of.
image
Why It's Good For The Game
Very big mob converted to a basic mob.
Changelog
cl
fix: Lisa no longer uses bluespace when interacting with Ian.
refactor: A large portion of dog code was re-written; please report any strange bugs.
/cl
208 lines
8.2 KiB
Plaintext
208 lines
8.2 KiB
Plaintext
///little tidbits of past events generated by the player doing things. can be used in engravings, dreams, and changeling succs.
|
|
///all of those things are supposed to be taken vaguely (engravings crossround and should not include names, dreams and succs are memory goop)
|
|
///and as such the generated text of the memory is vague. also, no references held so hard delling isn't an issue, thank god
|
|
/datum/memory
|
|
///name of the memory the user sees
|
|
var/name
|
|
///job of the person memorizing the event
|
|
var/memorizer
|
|
///job of the person memorizing the event
|
|
var/datum/mind/memorizer_mind
|
|
///the action done to the target, see memory.dm in _DEFINES
|
|
var/action
|
|
///extra information used in the memories to more accurately describe what happened. Assoc list of key -> string identifying what kind of info it is, value is a string identifying the detail.
|
|
var/list/extra_info
|
|
///mood of the person memorizing the event when it happend. can change the style.
|
|
var/memorizer_mood
|
|
///the value of the mood in it's worth as a story, defines how beautiful art from it can be and whether or not it stays in persistence.
|
|
var/story_value = STORY_VALUE_NONE
|
|
///Flags of any special behavior for the memory
|
|
var/memory_flags = NONE
|
|
|
|
/datum/memory/New(memorizer_mind, memorizer, action, extra_info, memorizer_mood, story_value, memory_flags)
|
|
. = ..()
|
|
src.memorizer_mind = memorizer_mind
|
|
src.memorizer = memorizer
|
|
src.action = action
|
|
//You can feed atoms in, but they're gonna be reduced to text
|
|
for(var/key in extra_info)
|
|
var/thing = extra_info[key]
|
|
if(!isdatum(thing))
|
|
continue
|
|
var/datum/reduce_to_string = thing
|
|
extra_info[key] = "[reduce_to_string]"
|
|
|
|
src.extra_info = extra_info
|
|
src.memorizer_mood = memorizer_mood
|
|
src.story_value = story_value
|
|
src.memory_flags = memory_flags
|
|
|
|
generate_memory_name()
|
|
|
|
/datum/memory/proc/generate_story(story_type, story_flags)
|
|
var/list/story_pieces = list()
|
|
|
|
//entirely independent vars (not related to the action or story type)
|
|
|
|
var/static/list/something_pool = list(
|
|
/mob/living/simple_animal/hostile/carp,
|
|
/mob/living/simple_animal/hostile/bear,
|
|
/mob/living/simple_animal/hostile/mushroom,
|
|
/mob/living/simple_animal/hostile/netherworld/statue,
|
|
/mob/living/simple_animal/hostile/retaliate/bat,
|
|
/mob/living/simple_animal/hostile/retaliate/goat,
|
|
/mob/living/simple_animal/hostile/killertomato,
|
|
/mob/living/simple_animal/hostile/giant_spider,
|
|
/mob/living/simple_animal/hostile/giant_spider/hunter,
|
|
/mob/living/simple_animal/hostile/blob/blobbernaut/independent,
|
|
/mob/living/simple_animal/hostile/carp/ranged,
|
|
/mob/living/simple_animal/hostile/carp/ranged/chaos,
|
|
/mob/living/simple_animal/hostile/asteroid/basilisk/watcher,
|
|
/mob/living/simple_animal/hostile/asteroid/goliath/beast,
|
|
/mob/living/simple_animal/hostile/headcrab,
|
|
/mob/living/simple_animal/hostile/morph,
|
|
/mob/living/basic/stickman,
|
|
/mob/living/basic/stickman/dog,
|
|
/mob/living/simple_animal/hostile/megafauna/dragon/lesser,
|
|
/mob/living/simple_animal/hostile/gorilla,
|
|
/mob/living/simple_animal/parrot,
|
|
/mob/living/basic/pet/dog/corgi,
|
|
/mob/living/simple_animal/crab,
|
|
/mob/living/basic/pet/dog/pug,
|
|
/mob/living/simple_animal/pet/cat,
|
|
/mob/living/basic/mouse,
|
|
/mob/living/simple_animal/chicken,
|
|
/mob/living/basic/cow,
|
|
/mob/living/simple_animal/hostile/lizard,
|
|
/mob/living/simple_animal/pet/fox,
|
|
/mob/living/simple_animal/butterfly,
|
|
/mob/living/simple_animal/pet/cat/cak,
|
|
/mob/living/basic/pet/dog/breaddog,
|
|
/mob/living/simple_animal/chick,
|
|
/mob/living/basic/cow/wisdom,
|
|
/obj/item/skub,
|
|
/obj/item/food/sausage/american
|
|
)
|
|
|
|
var/list/forewords = strings(MEMORY_FILE, story_type + "_forewords")
|
|
var/list/somethings =strings(MEMORY_FILE, story_type + "_somethings")
|
|
//changeling absorbing does not have styles
|
|
var/list/styles
|
|
if(!story_type == STORY_CHANGELING_ABSORB)
|
|
styles = strings(MEMORY_FILE, "styles")
|
|
if("[story_type]_styles" in GLOB.string_cache[MEMORY_FILE])
|
|
styles += strings(MEMORY_FILE, story_type + "_styles")
|
|
var/list/wheres = strings(MEMORY_FILE, "where")
|
|
|
|
|
|
//story action vars
|
|
var/list/story_starts = strings(MEMORY_FILE, action + "_starts")
|
|
///The action-specific reactions with mood intercepted into it e.g. "the clown looks (story_mood_here) at the situation"
|
|
var/list/story_mood_sentences = strings(MEMORY_FILE, action + "_moods")
|
|
///Moods the mob can express e.g. "chuckles" "looks disinterested"
|
|
var/list/story_moods
|
|
|
|
|
|
|
|
var/victim_mood = extra_info[DETAIL_PROTAGONIST_MOOD]
|
|
|
|
if(victim_mood != MOODLESS_MEMORY) //How the victim felt when it all happend.
|
|
switch(victim_mood)
|
|
if(MOOD_SAD4 to MOOD_SAD2)
|
|
story_moods = strings(MEMORY_FILE, "sad")
|
|
if("[action]_sad" in GLOB.string_cache[MEMORY_FILE])
|
|
story_moods += strings(MEMORY_FILE, "[action]_sad")
|
|
if(MOOD_SAD2 to MOOD_HAPPY2)
|
|
story_moods = strings(MEMORY_FILE, "neutral")
|
|
if("[action]_neutral" in GLOB.string_cache[MEMORY_FILE])
|
|
story_moods += strings(MEMORY_FILE, "[action]_neutral")
|
|
if(MOOD_HAPPY2 to MOOD_HAPPY4)
|
|
story_moods = strings(MEMORY_FILE, "happy")
|
|
if("[action]_happy" in GLOB.string_cache[MEMORY_FILE])
|
|
story_moods += strings(MEMORY_FILE, "[action]_happy")
|
|
|
|
|
|
|
|
//storybuilding
|
|
|
|
//The forewords for this specific type of story (E.g. This engraving depicts)
|
|
story_pieces.Add(pick(forewords))
|
|
//The story start for this specific action. (E.g. The Chef carving into The Clown)
|
|
story_pieces.Add(pick(story_starts))
|
|
//The location it happend, which isn't always included, but commonly is. (E.g. in Space, while in the Bar)
|
|
if(extra_info[DETAIL_WHERE])
|
|
story_pieces.Add(pick(wheres))
|
|
//Shows how the protagonist felt about it all (E.g. The Chef is looking sad as they tear into The Clown.)
|
|
if(LAZYLEN(story_moods))
|
|
story_pieces.Add(pick(story_mood_sentences))
|
|
//A nonsensical addition, using the memorizer, protagonist or even random crew / things (E.g. in the meantime, the Clown is being arrested, clutching a skub.")
|
|
if(prob(75))
|
|
story_pieces.Add(pick(somethings))
|
|
//Explains any unique styling the art has. e.g. (The engraving has a cubist style.)
|
|
if(styles && prob(75))
|
|
story_pieces.Add(pick(styles))
|
|
|
|
var/parsed_story = ""
|
|
|
|
var/mob/living/crew_member
|
|
|
|
var/atom/something = pick(something_pool) //Pick a something for the potential something line
|
|
|
|
var/datum/antagonist/obsessed/creeper = memorizer_mind.has_antag_datum(/datum/antagonist/obsessed)
|
|
if(creeper && creeper.trauma.obsession)
|
|
crew_member = creeper.trauma.obsession //ALWAYS ENGRAVE MY OBSESSION!
|
|
|
|
var/list/crew_members = list()
|
|
for(var/mob/living/carbon/human/potential_crew_member as anything in GLOB.player_list)
|
|
if(potential_crew_member?.mind?.assigned_role.job_flags & JOB_CREW_MEMBER)
|
|
crew_members += potential_crew_member
|
|
|
|
if(crew_members.len)
|
|
crew_member = pick(crew_members)
|
|
else
|
|
crew_member = "an unknown crewmember"
|
|
|
|
var/capitalize_next_line = FALSE
|
|
|
|
for(var/line in story_pieces)
|
|
for(var/key in extra_info)
|
|
var/detail = extra_info[key]
|
|
line = replacetext(line, "%[key]", "[detail]")
|
|
|
|
line = replacetext(line, "%PROPER", "\proper")
|
|
line = replacetext(line, "%MEMORIZER", "[memorizer]")
|
|
if(LAZYLEN(story_moods))
|
|
line = replacetext(line, "%MOOD", pick(story_moods))
|
|
line = replacetext(line, "%SOMETHING", initial(something.name))
|
|
line = replacetext(line, "%CREWMEMBER", memorizer_mind.build_story_mob(crew_member))
|
|
line = replacetext(line, "%STORY_TYPE", story_type)
|
|
|
|
if(capitalize_next_line)
|
|
line = capitalize(line)
|
|
capitalize_next_line = FALSE
|
|
|
|
if(line[length(line)] == ".")//End of sentence, next sentence needs to start with a capital.'
|
|
capitalize_next_line = TRUE
|
|
|
|
if(line != story_pieces[story_pieces.len]) //not the last line
|
|
parsed_story += "[line] "
|
|
|
|
//after replacement section for performance
|
|
if(story_flags & STORY_FLAG_DATED)
|
|
if(memory_flags & MEMORY_FLAG_NOSTATIONNAME)
|
|
parsed_story += "This took place in [time2text(world.realtime, "Month")] of [CURRENT_STATION_YEAR]."
|
|
else
|
|
parsed_story += "This took place in [time2text(world.realtime, "Month")] of [CURRENT_STATION_YEAR] on [station_name()]."
|
|
|
|
parsed_story = trim_right(parsed_story)
|
|
|
|
return parsed_story
|
|
|
|
/datum/memory/proc/generate_memory_name()
|
|
var/names = strings(MEMORY_FILE, action + "_names")
|
|
var/line = pick(names)
|
|
for(var/key in extra_info)
|
|
var/detail = extra_info[key]
|
|
line = replacetext(line, "%[key]", "[detail]")
|
|
name = line
|