mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-16 12:07:48 +00:00
## About The Pull Request Recently we allowed items held in your hands to catch fire if you catch fire. This makes sense but the code had a few oversights, then we reverted it. This PR reintroduces the feature, but with a few refinements. The basic feature is simple: If you are on fire then items you are holding will also catch fire, in the same vein as items you are wearing on your head or hands. There are also a few caveats we forgot about the first time we added this: - If your gloves cannot catch fire, your held items will not catch fire (because your hands aren't on fire). - If you are extinguished, your held items will also be extinguished. - Stopping, Dropping, and Rolling on top of any items will also extinguish those items. As part of this change, after an argument about whether or not this is an oversight in coding-general, I've made the proc `get_equipped_items` take a bitflag instead of a series of booleans as an argument and added a new one for "include held items", so that we need no longer argue about whether holding something counts as "equipping" it (in all other parts of the game than this proc, it does). This is what gives the PR most of its code footprint, don't be scared. ## Why It's Good For The Game Items you are holding in your hands _should_ catch fire if everything else on your person is on fire, and taking an item off of your body to put it in your hands shouldn't protect it from fire, because those things don't make intuitive sense. If we want an item to be able to catch fire when worn, then it should do so. This might expose some issues where we were improperly setting the flammability flags on items, but any weapon which will burn in your hands now would also have burned if you were wearing it on your belt or back, so making those issues more visible should be a bonus (we'll also stop them from burning on your back or belt). If you see someone holding a piece of paper that you really don't want them to read you can now set them on fire to stop them from reading it, whereas previously they would deftly hold the very flammable object out of reach of their flaming body. ## Changelog 🆑 balance: Items held in your hands can catch fire. balance: Items you are holding won't catch fire if your hands cannot catch fire. balance: When you stop being on fire so will items you are holding. balance: If you roll around on your burning items they will stop being on fire. /🆑
428 lines
13 KiB
Plaintext
428 lines
13 KiB
Plaintext
#define TRANSFORMATION_DURATION 22
|
|
/// Will be removed once the transformation is complete.
|
|
#define TEMPORARY_TRANSFORMATION_TRAIT "temporary_transformation"
|
|
/// Considered "permanent" since we'll be deleting the old mob and the client will be inserted into a new one (without this trait)
|
|
#define PERMANENT_TRANSFORMATION_TRAIT "permanent_transformation"
|
|
|
|
/mob/living/carbon/proc/monkeyize(instant = FALSE)
|
|
if (transformation_timer || HAS_TRAIT(src, TRAIT_NO_TRANSFORM))
|
|
return
|
|
|
|
if(ismonkey(src))
|
|
return
|
|
|
|
if(instant)
|
|
finish_monkeyize()
|
|
return
|
|
|
|
//Make mob invisible and spawn animation
|
|
ADD_TRAIT(src, TRAIT_NO_TRANSFORM, TEMPORARY_TRANSFORMATION_TRAIT)
|
|
Paralyze(TRANSFORMATION_DURATION, ignore_canstun = TRUE)
|
|
icon = null
|
|
cut_overlays()
|
|
|
|
var/obj/effect = new /obj/effect/temp_visual/monkeyify(loc)
|
|
effect.SetInvisibility(invisibility)
|
|
SetInvisibility(INVISIBILITY_MAXIMUM, id=type)
|
|
|
|
transformation_timer = addtimer(CALLBACK(src, PROC_REF(finish_monkeyize)), TRANSFORMATION_DURATION, TIMER_UNIQUE)
|
|
|
|
/mob/living/carbon/proc/finish_monkeyize()
|
|
transformation_timer = null
|
|
to_chat(src, span_boldnotice("You are now a monkey."))
|
|
REMOVE_TRAIT(src, TRAIT_NO_TRANSFORM, TEMPORARY_TRANSFORMATION_TRAIT)
|
|
icon = initial(icon)
|
|
RemoveInvisibility(type)
|
|
set_species(/datum/species/monkey)
|
|
name = "monkey"
|
|
regenerate_icons()
|
|
set_name()
|
|
SEND_SIGNAL(src, COMSIG_HUMAN_MONKEYIZE)
|
|
uncuff()
|
|
return src
|
|
|
|
////////////////////////// Humanize //////////////////////////////
|
|
//Could probably be merged with monkeyize but other transformations got their own procs, too
|
|
|
|
/mob/living/carbon/proc/humanize(species = /datum/species/human, instant = FALSE)
|
|
if (transformation_timer || HAS_TRAIT(src, TRAIT_NO_TRANSFORM))
|
|
return
|
|
|
|
if(!ismonkey(src))
|
|
return
|
|
|
|
if(instant)
|
|
finish_humanize(species)
|
|
return
|
|
|
|
//Make mob invisible and spawn animation
|
|
ADD_TRAIT(src, TRAIT_NO_TRANSFORM, TEMPORARY_TRANSFORMATION_TRAIT)
|
|
Paralyze(TRANSFORMATION_DURATION, ignore_canstun = TRUE)
|
|
icon = null
|
|
cut_overlays()
|
|
|
|
var/obj/effect = new /obj/effect/temp_visual/monkeyify/humanify(loc)
|
|
effect.SetInvisibility(invisibility)
|
|
SetInvisibility(INVISIBILITY_MAXIMUM, id=type)
|
|
|
|
transformation_timer = addtimer(CALLBACK(src, PROC_REF(finish_humanize), species), TRANSFORMATION_DURATION, TIMER_UNIQUE)
|
|
|
|
/mob/living/carbon/proc/finish_humanize(species = /datum/species/human)
|
|
transformation_timer = null
|
|
to_chat(src, span_boldnotice("You are now a human."))
|
|
REMOVE_TRAIT(src, TRAIT_NO_TRANSFORM, TEMPORARY_TRANSFORMATION_TRAIT)
|
|
icon = initial(icon)
|
|
RemoveInvisibility(type)
|
|
set_species(species)
|
|
SEND_SIGNAL(src, COMSIG_MONKEY_HUMANIZE)
|
|
return src
|
|
|
|
/mob/proc/AIize(client/preference_source, move = TRUE)
|
|
var/list/turf/landmark_loc = list()
|
|
|
|
if(!move)
|
|
landmark_loc += loc
|
|
else
|
|
for(var/obj/effect/landmark/start/ai/sloc in GLOB.landmarks_list)
|
|
if(locate(/mob/living/silicon/ai) in sloc.loc)
|
|
continue
|
|
if(sloc.primary_ai)
|
|
LAZYCLEARLIST(landmark_loc)
|
|
landmark_loc += sloc.loc
|
|
break
|
|
landmark_loc += sloc.loc
|
|
if(!length(landmark_loc))
|
|
to_chat(src, "Oh god sorry we can't find an unoccupied AI spawn location, so we're spawning you on top of someone.")
|
|
for(var/obj/effect/landmark/start/ai/sloc in GLOB.landmarks_list)
|
|
landmark_loc += sloc.loc
|
|
|
|
if(!length(landmark_loc))
|
|
message_admins("Could not find ai landmark for [src]. Yell at a mapper! We are spawning them at their current location.")
|
|
landmark_loc += loc
|
|
|
|
if(client)
|
|
stop_sound_channel(CHANNEL_LOBBYMUSIC)
|
|
|
|
var/mob/living/silicon/ai/our_AI = new /mob/living/silicon/ai(pick(landmark_loc), null, src)
|
|
. = our_AI
|
|
|
|
if(preference_source)
|
|
apply_pref_name(/datum/preference/name/ai, preference_source)
|
|
our_AI.apply_pref_hologram_display(preference_source)
|
|
our_AI.set_core_display_icon(null, preference_source)
|
|
|
|
qdel(src)
|
|
|
|
/mob/living/carbon/AIize(client/preference_source, transfer_after = TRUE)
|
|
if(HAS_TRAIT(src, TRAIT_NO_TRANSFORM))
|
|
return
|
|
ADD_TRAIT(src, TRAIT_NO_TRANSFORM, PERMANENT_TRANSFORMATION_TRAIT)
|
|
Paralyze(1, ignore_canstun = TRUE)
|
|
for(var/obj/item/W in src)
|
|
dropItemToGround(W)
|
|
regenerate_icons()
|
|
icon = null
|
|
SetInvisibility(INVISIBILITY_MAXIMUM)
|
|
return ..()
|
|
|
|
/mob/living/carbon/human/AIize(client/preference_source, transfer_after = TRUE)
|
|
if(HAS_TRAIT(src, TRAIT_NO_TRANSFORM))
|
|
return
|
|
|
|
return ..()
|
|
|
|
/mob/proc/Robotize(delete_items = 0, transfer_after = TRUE)
|
|
if(HAS_TRAIT(src, TRAIT_NO_TRANSFORM))
|
|
return
|
|
ADD_TRAIT(src, TRAIT_NO_TRANSFORM, PERMANENT_TRANSFORMATION_TRAIT)
|
|
var/mob/living/silicon/robot/new_borg = new /mob/living/silicon/robot(loc)
|
|
|
|
new_borg.gender = gender
|
|
new_borg.SetInvisibility(INVISIBILITY_NONE)
|
|
|
|
if(client)
|
|
new_borg.updatename(client)
|
|
|
|
if(mind) //TODO //TODO WHAT
|
|
if(!transfer_after)
|
|
mind.active = FALSE
|
|
mind.transfer_to(new_borg)
|
|
else if(transfer_after)
|
|
new_borg.key = key
|
|
|
|
if(new_borg.mmi)
|
|
new_borg.mmi.name = "[initial(new_borg.mmi.name)]: [real_name]"
|
|
if(new_borg.mmi.brain)
|
|
new_borg.mmi.brain.name = "[real_name]'s brain"
|
|
if(new_borg.mmi.brainmob)
|
|
new_borg.mmi.brainmob.real_name = real_name //the name of the brain inside the cyborg is the robotized human's name.
|
|
new_borg.mmi.brainmob.name = real_name
|
|
|
|
new_borg.job = JOB_CYBORG
|
|
new_borg.notify_ai(AI_NOTIFICATION_NEW_BORG)
|
|
|
|
. = new_borg
|
|
if(new_borg.ckey && is_banned_from(new_borg.ckey, JOB_CYBORG))
|
|
INVOKE_ASYNC(new_borg, TYPE_PROC_REF(/mob/living/silicon/robot, replace_banned_cyborg))
|
|
qdel(src)
|
|
|
|
/mob/living/Robotize(delete_items = 0, transfer_after = TRUE)
|
|
if(HAS_TRAIT(src, TRAIT_NO_TRANSFORM))
|
|
return
|
|
ADD_TRAIT(src, TRAIT_NO_TRANSFORM, TEMPORARY_TRANSFORMATION_TRAIT)
|
|
Paralyze(1, ignore_canstun = TRUE)
|
|
|
|
drop_everything(delete_items)
|
|
|
|
regenerate_icons()
|
|
icon = null
|
|
SetInvisibility(INVISIBILITY_MAXIMUM)
|
|
|
|
REMOVE_TRAIT(src, TRAIT_NO_TRANSFORM, TEMPORARY_TRANSFORMATION_TRAIT)
|
|
return ..()
|
|
|
|
/mob/living/silicon/robot/proc/replace_banned_cyborg()
|
|
to_chat(src, "<b>You are job banned from cyborg! Appeal your job ban if you want to avoid this in the future!</b>")
|
|
ghostize(FALSE)
|
|
|
|
var/mob/chosen_one = SSpolling.poll_ghosts_for_target("Do you want to play as [span_notice(name)]?", check_jobban = JOB_CYBORG, poll_time = 5 SECONDS, checked_target = src, alert_pic = src, role_name_text = "cyborg")
|
|
if(chosen_one)
|
|
message_admins("[key_name_admin(chosen_one)] has taken control of ([key_name_admin(src)]) to replace a jobbanned player.")
|
|
key = chosen_one.key
|
|
|
|
//human -> alien
|
|
/mob/living/carbon/human/proc/Alienize()
|
|
if(HAS_TRAIT(src, TRAIT_NO_TRANSFORM))
|
|
return
|
|
ADD_TRAIT(src, TRAIT_NO_TRANSFORM, PERMANENT_TRANSFORMATION_TRAIT)
|
|
add_traits(list(TRAIT_IMMOBILIZED, TRAIT_HANDS_BLOCKED), TRAIT_GENERIC)
|
|
for(var/obj/item/W in src)
|
|
dropItemToGround(W)
|
|
regenerate_icons()
|
|
icon = null
|
|
SetInvisibility(INVISIBILITY_MAXIMUM)
|
|
for(var/t in bodyparts)
|
|
qdel(t)
|
|
|
|
var/alien_caste = pick("Hunter","Sentinel","Drone")
|
|
var/mob/living/carbon/alien/adult/new_xeno
|
|
switch(alien_caste)
|
|
if("Hunter")
|
|
new_xeno = new /mob/living/carbon/alien/adult/hunter(loc)
|
|
if("Sentinel")
|
|
new_xeno = new /mob/living/carbon/alien/adult/sentinel(loc)
|
|
if("Drone")
|
|
new_xeno = new /mob/living/carbon/alien/adult/drone(loc)
|
|
|
|
new_xeno.set_combat_mode(TRUE)
|
|
new_xeno.key = key
|
|
|
|
to_chat(new_xeno, span_boldnotice("You are now an alien."))
|
|
qdel(src)
|
|
return new_xeno
|
|
|
|
/mob/living/carbon/human/proc/slimeize(reproduce as num)
|
|
if(HAS_TRAIT(src, TRAIT_NO_TRANSFORM))
|
|
return
|
|
ADD_TRAIT(src, TRAIT_NO_TRANSFORM, PERMANENT_TRANSFORMATION_TRAIT)
|
|
add_traits(list(TRAIT_IMMOBILIZED, TRAIT_HANDS_BLOCKED), TRAIT_GENERIC)
|
|
for(var/obj/item/W in src)
|
|
dropItemToGround(W)
|
|
regenerate_icons()
|
|
icon = null
|
|
SetInvisibility(INVISIBILITY_MAXIMUM)
|
|
for(var/t in bodyparts)
|
|
qdel(t)
|
|
|
|
var/mob/living/basic/slime/new_slime
|
|
if(reproduce)
|
|
var/number = pick(14;2,3,4) //reproduce (has a small chance of producing 3 or 4 offspring)
|
|
var/list/babies = list()
|
|
for(var/i in 1 to number)
|
|
var/mob/living/basic/slime/M = new/mob/living/basic/slime(loc)
|
|
M.set_nutrition(round(nutrition/number))
|
|
step_away(M,src)
|
|
babies += M
|
|
new_slime = pick(babies)
|
|
else
|
|
new_slime = new /mob/living/basic/slime(loc)
|
|
new_slime.set_combat_mode(TRUE)
|
|
new_slime.key = key
|
|
|
|
to_chat(new_slime, span_boldnotice("You are now a slime. Skreee!"))
|
|
qdel(src)
|
|
return new_slime
|
|
|
|
/mob/proc/become_overmind(starting_points = OVERMIND_STARTING_POINTS)
|
|
var/mob/camera/blob/B = new /mob/camera/blob(get_turf(src), starting_points)
|
|
B.key = key
|
|
. = B
|
|
qdel(src)
|
|
|
|
|
|
/mob/living/carbon/human/proc/corgize()
|
|
if(HAS_TRAIT(src, TRAIT_NO_TRANSFORM))
|
|
return
|
|
ADD_TRAIT(src, TRAIT_NO_TRANSFORM, PERMANENT_TRANSFORMATION_TRAIT)
|
|
Paralyze(1, ignore_canstun = TRUE)
|
|
for(var/obj/item/W in src)
|
|
dropItemToGround(W)
|
|
regenerate_icons()
|
|
icon = null
|
|
SetInvisibility(INVISIBILITY_MAXIMUM)
|
|
for(var/t in bodyparts) //this really should not be necessary
|
|
qdel(t)
|
|
|
|
var/mob/living/basic/pet/dog/corgi/new_corgi = new /mob/living/basic/pet/dog/corgi (loc)
|
|
new_corgi.set_combat_mode(TRUE)
|
|
new_corgi.key = key
|
|
|
|
to_chat(new_corgi, span_boldnotice("You are now a Corgi. Yap Yap!"))
|
|
qdel(src)
|
|
return new_corgi
|
|
|
|
/**
|
|
* Turns the source atom into a crab crab, the peak of evolutionary design.
|
|
*/
|
|
/mob/living/carbon/human/proc/crabize()
|
|
if(HAS_TRAIT(src, TRAIT_NO_TRANSFORM))
|
|
return
|
|
ADD_TRAIT(src, TRAIT_NO_TRANSFORM, PERMANENT_TRANSFORMATION_TRAIT)
|
|
Paralyze(1, ignore_canstun = TRUE)
|
|
for(var/obj/item/objeto in src)
|
|
dropItemToGround(objeto)
|
|
regenerate_icons()
|
|
icon = null
|
|
SetInvisibility(INVISIBILITY_MAXIMUM)
|
|
|
|
var/mob/living/basic/crab/new_crab = new (loc)
|
|
new_crab.set_combat_mode(TRUE) // snip snip
|
|
if(mind)
|
|
mind.transfer_to(new_crab)
|
|
|
|
to_chat(new_crab, span_boldnotice("You have evolved into a crab!"))
|
|
qdel(src)
|
|
return new_crab
|
|
|
|
/mob/living/carbon/proc/gorillize()
|
|
if(HAS_TRAIT(src, TRAIT_NO_TRANSFORM))
|
|
return
|
|
ADD_TRAIT(src, TRAIT_NO_TRANSFORM, PERMANENT_TRANSFORMATION_TRAIT)
|
|
Paralyze(1, ignore_canstun = TRUE)
|
|
|
|
SSblackbox.record_feedback("amount", "gorillas_created", 1)
|
|
|
|
var/Itemlist = get_equipped_items(INCLUDE_POCKETS)
|
|
Itemlist += held_items
|
|
for(var/obj/item/W in Itemlist)
|
|
dropItemToGround(W, TRUE)
|
|
|
|
regenerate_icons()
|
|
icon = null
|
|
SetInvisibility(INVISIBILITY_MAXIMUM)
|
|
var/mob/living/basic/gorilla/new_gorilla = new (get_turf(src))
|
|
new_gorilla.set_combat_mode(TRUE)
|
|
if(mind)
|
|
mind.transfer_to(new_gorilla)
|
|
else
|
|
new_gorilla.key = key
|
|
to_chat(new_gorilla, span_boldnotice("You are now a gorilla. Ooga ooga!"))
|
|
qdel(src)
|
|
return new_gorilla
|
|
|
|
/mob/living/carbon/human/Animalize()
|
|
|
|
var/list/mobtypes = typesof(/mob/living/simple_animal) + typesof(/mob/living/basic)
|
|
var/mobpath = tgui_input_list(usr, "Which type of mob should [src] turn into?", "Choose a type", sort_list(mobtypes, GLOBAL_PROC_REF(cmp_typepaths_asc)))
|
|
if(isnull(mobpath))
|
|
return
|
|
if(!safe_animal(mobpath))
|
|
to_chat(usr, span_danger("Sorry but this mob type is currently unavailable."))
|
|
return
|
|
|
|
if(HAS_TRAIT(src, TRAIT_NO_TRANSFORM))
|
|
return
|
|
ADD_TRAIT(src, TRAIT_NO_TRANSFORM, PERMANENT_TRANSFORMATION_TRAIT)
|
|
Paralyze(1, ignore_canstun = TRUE)
|
|
|
|
for(var/obj/item/W in src)
|
|
dropItemToGround(W)
|
|
|
|
regenerate_icons()
|
|
icon = null
|
|
SetInvisibility(INVISIBILITY_MAXIMUM)
|
|
|
|
for(var/t in bodyparts)
|
|
qdel(t)
|
|
|
|
var/mob/living/new_mob = new mobpath(src.loc)
|
|
|
|
new_mob.key = key
|
|
new_mob.set_combat_mode(TRUE)
|
|
|
|
to_chat(new_mob, span_boldnotice("You suddenly feel more... animalistic."))
|
|
qdel(src)
|
|
return new_mob
|
|
|
|
/mob/proc/Animalize()
|
|
|
|
var/list/mobtypes = typesof(/mob/living/simple_animal) + typesof(/mob/living/basic)
|
|
var/mobpath = tgui_input_list(usr, "Which type of mob should [src] turn into?", "Choose a type", sort_list(mobtypes, GLOBAL_PROC_REF(cmp_typepaths_asc)))
|
|
if(isnull(mobpath))
|
|
return
|
|
if(!safe_animal(mobpath))
|
|
to_chat(usr, span_danger("Sorry but this mob type is currently unavailable."))
|
|
return
|
|
|
|
var/mob/living/new_mob = new mobpath(src.loc)
|
|
|
|
new_mob.key = key
|
|
new_mob.set_combat_mode(TRUE)
|
|
to_chat(new_mob, span_boldnotice("You feel more... animalistic."))
|
|
|
|
. = new_mob
|
|
qdel(src)
|
|
|
|
/* Certain mob types have problems and should not be allowed to be controlled by players.
|
|
*
|
|
* This proc is here to force coders to manually place their mob in this list, hopefully tested.
|
|
* This also gives a place to explain -why- players shouldn't be turn into certain mobs and hopefully someone can fix them.
|
|
*/
|
|
/mob/proc/safe_animal(MP)
|
|
|
|
//Bad mobs! - Remember to add a comment explaining what's wrong with the mob
|
|
if(!MP)
|
|
return FALSE //Sanity, this should never happen.
|
|
|
|
if(ispath(MP, /mob/living/basic/construct))
|
|
return FALSE //Verbs do not appear for players.
|
|
|
|
//Good mobs!
|
|
if(ispath(MP, /mob/living/basic/pet/cat))
|
|
return TRUE
|
|
if(ispath(MP, /mob/living/basic/pet/dog/corgi))
|
|
return TRUE
|
|
if(ispath(MP, /mob/living/basic/crab))
|
|
return TRUE
|
|
if(ispath(MP, /mob/living/basic/carp))
|
|
return TRUE
|
|
if(ispath(MP, /mob/living/basic/mushroom))
|
|
return TRUE
|
|
if(ispath(MP, /mob/living/basic/shade))
|
|
return TRUE
|
|
if(ispath(MP, /mob/living/basic/killer_tomato))
|
|
return TRUE
|
|
if(ispath(MP, /mob/living/basic/mouse))
|
|
return TRUE
|
|
if(ispath(MP, /mob/living/basic/bear))
|
|
return TRUE
|
|
if(ispath(MP, /mob/living/basic/parrot))
|
|
return TRUE //Parrots are no longer unfinished! -Nodrak
|
|
|
|
//Not in here? Must be untested!
|
|
return FALSE
|
|
|
|
#undef PERMANENT_TRANSFORMATION_TRAIT
|
|
#undef TEMPORARY_TRANSFORMATION_TRAIT
|
|
#undef TRANSFORMATION_DURATION
|