Sync with master (#3)

Alot of stuff, honk
This commit is contained in:
DeltaFire15
2019-11-16 16:03:25 +01:00
committed by GitHub
parent 3d8c41e143
commit 350dd6ed3a
1635 changed files with 40068 additions and 142864 deletions
+1 -1
View File
@@ -310,7 +310,7 @@
});
$( "#sortable" ).disableSelection();
$('form').submit(function(){
$('#IRVdata').val($( "#sortable" ).sortable("toArray", { attribute: "voteid" }));
$('#IRVdata').val($( "#sortable" ).sortable("toArray", { attribute: "voteid" }));
});
});
@@ -130,10 +130,10 @@
color_src = MATRIXED
/datum/sprite_accessory/ears/human/rabbit
name = "Rabbit"
icon_state = "rabbit"
color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
name = "Rabbit"
icon_state = "rabbit"
color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
/datum/sprite_accessory/ears/human/sergal
name = "Sergal"
@@ -287,8 +287,8 @@
icon_state = "pede"
/datum/sprite_accessory/mam_ears/rabbit
name = "Rabbit"
icon_state = "rabbit"
name = "Rabbit"
icon_state = "rabbit"
/datum/sprite_accessory/mam_ears/sergal
name = "Sergal"
+51 -23
View File
@@ -3,6 +3,8 @@ GLOBAL_LIST_EMPTY(ghost_images_simple) //this is a list of all ghost images as t
GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
#define CANT_REENTER_ROUND -1
/mob/dead/observer
name = "ghost"
desc = "It's a g-g-g-g-ghooooost!" //jinkies!
@@ -17,8 +19,9 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
see_in_dark = 100
invisibility = INVISIBILITY_OBSERVER
hud_type = /datum/hud/ghost
movement_type = GROUND | FLYING
var/can_reenter_corpse
var/can_reenter_round = TRUE
var/reenter_round_timeout = 0 // used to prevent people from coming back through ghost roles/midround antags as they suicide/cryo for a duration set by CONFIG_GET(number/suicide_reenter_round_timer) and CONFIG_GET(number/roundstart_suicide_time_limit)
var/datum/hud/living/carbon/hud = null // hud
var/bootime = 0
var/started_as_observer //This variable is set to 1 when you enter the game as an observer.
@@ -231,7 +234,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
var/r_val
var/b_val
var/g_val
var/color_format = lentext(input_color)
var/color_format = length(input_color)
if(color_format == 3)
r_val = hex2num(copytext(input_color, 1, 2))*16
g_val = hex2num(copytext(input_color, 2, 3))*16
@@ -260,14 +263,22 @@ Transfer_mind is there to check if mob is being deleted/not going to have a body
Works together with spawning an observer, noted above.
*/
/mob/proc/ghostize(can_reenter_corpse = TRUE, special = FALSE)
if(!key || cmptext(copytext(key,1,2),"@") || (!special && SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, can_reenter_corpse, special) & COMPONENT_BLOCK_GHOSTING))
/mob/proc/ghostize(can_reenter_corpse = TRUE, special = FALSE, penalize = FALSE)
if(!key || cmptext(copytext(key,1,2),"@") || (!special && SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, can_reenter_corpse) & COMPONENT_BLOCK_GHOSTING))
return //mob has no key, is an aghost or some component hijacked.
stop_sound_channel(CHANNEL_HEARTBEAT) //Stop heartbeat sounds because You Are A Ghost Now
var/mob/dead/observer/ghost = new(src) // Transfer safety to observer spawning proc.
SStgui.on_transfer(src, ghost) // Transfer NanoUIs.
ghost.can_reenter_corpse = can_reenter_corpse
ghost.can_reenter_round = (can_reenter_corpse && !suiciding)
if(penalize) //penalizing them from making a ghost role / midround antag comeback right away.
var/penalty = CONFIG_GET(number/suicide_reenter_round_timer) MINUTES
var/roundstart_quit_limit = CONFIG_GET(number/roundstart_suicide_time_limit) MINUTES
if(world.time < roundstart_quit_limit) //add up the time difference to their antag rolling penalty if they quit before half a (ingame) hour even passed.
penalty += roundstart_quit_limit - world.time
if(penalty)
ghost.reenter_round_timeout = world.realtime + penalty
if(ghost.reenter_round_timeout - SSshuttle.realtimeofstart > SSshuttle.auto_call + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
ghost.reenter_round_timeout = CANT_REENTER_ROUND
transfer_ckey(ghost, FALSE)
return ghost
@@ -283,26 +294,27 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, (stat == DEAD) ? TRUE : FALSE, FALSE) & COMPONENT_BLOCK_GHOSTING)
return
// CITADEL EDIT
if(istype(loc, /obj/machinery/cryopod))
var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst still alive you won't be able to re-enter this round! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
if(response != "Ghost")//darn copypaste
return
var/obj/machinery/cryopod/C = loc
C.despawn_occupant()
return
// END EDIT
var/penalty = CONFIG_GET(number/suicide_reenter_round_timer) MINUTES
var/roundstart_quit_limit = CONFIG_GET(number/roundstart_suicide_time_limit) MINUTES
if(world.time < roundstart_quit_limit)
penalty += roundstart_quit_limit - world.time
if(penalty + world.realtime - SSshuttle.realtimeofstart > SSshuttle.auto_call + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
penalty = CANT_REENTER_ROUND
if(stat != DEAD)
succumb()
if(stat == DEAD)
ghostize(1)
else
var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst still alive you won't be able to re-enter this round! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst alive you won't be able to re-enter this round [penalty ? "or play ghost roles [penalty != CANT_REENTER_ROUND ? "until the round is over" : "for the next [DisplayTimeText(penalty)]"]" : ""]! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
if(response != "Ghost")
return //didn't want to ghost after-all
ghostize(0) //0 parameter is so we can never re-enter our body, "Charlie, you can never come baaaack~" :3
suicide_log(TRUE)
if(istype(loc, /obj/machinery/cryopod))
var/obj/machinery/cryopod/C = loc
C.despawn_occupant()
else
ghostize(0, penalize = TRUE) //0 parameter is so we can never re-enter our body, "Charlie, you can never come baaaack~" :3
suicide_log(TRUE)
/mob/camera/verb/ghost()
set category = "OOC"
@@ -312,10 +324,24 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, FALSE, FALSE) & COMPONENT_BLOCK_GHOSTING)
return
var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst still alive you won't be able to re-enter this round! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
var/penalty = CONFIG_GET(number/suicide_reenter_round_timer) MINUTES
var/roundstart_quit_limit = CONFIG_GET(number/roundstart_suicide_time_limit) MINUTES
if(world.time < roundstart_quit_limit)
penalty += roundstart_quit_limit - world.time
if(penalty + world.realtime - SSshuttle.realtimeofstart > SSshuttle.auto_call + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
penalty = CANT_REENTER_ROUND
var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst alive you won't be able to re-enter this round [penalty ? "or play ghost roles [penalty != CANT_REENTER_ROUND ? "until the round is over" : "for the next [DisplayTimeText(penalty)]"]" : ""]! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
if(response != "Ghost")
return
ghostize(0)
ghostize(0, penalize = TRUE)
/mob/dead/observer/proc/can_reenter_round(silent = FALSE)
if(reenter_round_timeout != CANT_REENTER_ROUND && reenter_round_timeout <= world.realtime)
return TRUE
if(!silent)
to_chat(src, "<span class='warning'>You are unable to reenter the round[reenter_round_timeout != CANT_REENTER_ROUND ? " yet. Your ghost role blacklist will expire in [DisplayTimeText(reenter_round_timeout - world.realtime)]" : ""].</span>")
return FALSE
/mob/dead/observer/Move(NewLoc, direct)
if(updatedir)
@@ -603,6 +629,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set name = "Possess!"
set desc= "Take over the body of a mindless creature!"
if(reenter_round_timeout > world.realtime)
to_chat(src, "<span class='warning'>You are unable to re-enter the round yet. Your ghost role blacklist will expire in [DisplayTimeText(reenter_round_timeout - world.realtime)].</span>")
return FALSE
var/list/possessible = list()
for(var/mob/living/L in GLOB.alive_mob_list)
if(istype(L,/mob/living/carbon/human/dummy) || !get_turf(L)) //Haha no.
@@ -623,10 +653,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
to_chat(src, "<span class='warning'>This isn't really a creature, now is it!</span>")
return 0
if(!can_reenter_round)
to_chat(src, "<span class='warning'>You are unable to re-enter the round.</span>")
return FALSE
if(can_reenter_corpse && mind && mind.current)
if(alert(src, "Your soul is still tied to your former life as [mind.current.name], if you go forward there is no going back to that life. Are you sure you wish to continue?", "Move On", "Yes", "No") == "No")
return 0
@@ -871,3 +897,5 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
spawners_menu = new(src)
spawners_menu.ui_interact(src)
#undef CANT_REENTER_ROUND
@@ -0,0 +1,2 @@
/mob/dead/observer/canZMove(direction, turf/target)
return TRUE
+1 -1
View File
@@ -24,7 +24,7 @@
var/list/datum/brain_trauma/traumas = list()
/obj/item/organ/brain/Insert(mob/living/carbon/C, special = 0,no_id_transfer = FALSE)
/obj/item/organ/brain/Insert(mob/living/carbon/C, special = 0,no_id_transfer = FALSE, drop_if_replaced = TRUE)
..()
name = "brain"
+7 -4
View File
@@ -36,7 +36,7 @@ GLOBAL_VAR(posibrain_notify_cooldown)
/obj/item/mmi/posibrain/proc/ping_ghosts(msg, newlymade)
if(newlymade || GLOB.posibrain_notify_cooldown <= world.time)
notify_ghosts("[name] [msg] in [get_area(src)]!", ghost_sound = !newlymade ? 'sound/misc/server-ready.ogg':null, enter_link = "<a href=?src=[REF(src)];activate=1>(Click to enter)</a>", source = src, action = NOTIFY_ATTACK, flashwindow = FALSE, ignore_key = POLL_IGNORE_POSIBRAIN)
notify_ghosts("[name] [msg] in [get_area(src)]!", ghost_sound = !newlymade ? 'sound/misc/server-ready.ogg':null, enter_link = "<a href=?src=[REF(src)];activate=1>(Click to enter)</a>", source = src, action = NOTIFY_ATTACK, flashwindow = FALSE, ignore_key = POLL_IGNORE_POSIBRAIN, ignore_dnr_observers = TRUE)
if(!newlymade)
GLOB.posibrain_notify_cooldown = world.time + askDelay
@@ -83,11 +83,14 @@ GLOBAL_VAR(posibrain_notify_cooldown)
//Two ways to activate a positronic brain. A clickable link in the ghost notif, or simply clicking the object itself.
/obj/item/mmi/posibrain/proc/activate(mob/user)
if(QDELETED(brainmob))
return
if(is_occupied() || jobban_isbanned(user,"posibrain") || QDELETED(brainmob) || QDELETED(src) || QDELETED(user))
if(QDELETED(brainmob) || is_occupied() || jobban_isbanned(user,"posibrain") || QDELETED(src) || QDELETED(user))
return
if(isobserver(user))
var/mob/dead/observer/O = user
if(!O.can_reenter_round())
return FALSE
var/posi_ask = alert("Become a [name]? (Warning, You can no longer be cloned, and all past lives will be forgotten!)","Are you positive?","Yes","No")
if(posi_ask == "No" || QDELETED(src))
return
@@ -1,8 +1,9 @@
/mob/living/carbon/alien/spawn_gibs(with_bodyparts)
/mob/living/carbon/alien/spawn_gibs(with_bodyparts, atom/loc_override)
var/location = loc_override ? loc_override.drop_location() : drop_location()
if(with_bodyparts)
new /obj/effect/gibspawner/xeno(drop_location())
new /obj/effect/gibspawner/xeno(location, src)
else
new /obj/effect/gibspawner/xeno/bodypartless(drop_location())
new /obj/effect/gibspawner/xeno/bodypartless(location, src)
/mob/living/carbon/alien/gib_animation()
new /obj/effect/temp_visual/gib_animation(loc, "gibbed-a")
@@ -6,11 +6,12 @@
update_icons()
/mob/living/carbon/alien/larva/spawn_gibs(with_bodyparts)
/mob/living/carbon/alien/larva/spawn_gibs(with_bodyparts, atom/loc_override)
var/location = loc_override ? loc_override.drop_location() : drop_location()
if(with_bodyparts)
new /obj/effect/gibspawner/larva(drop_location())
new /obj/effect/gibspawner/larva(location, src)
else
new /obj/effect/gibspawner/larva/bodypartless(drop_location())
new /obj/effect/gibspawner/larva/bodypartless(location, src)
/mob/living/carbon/alien/larva/gib_animation()
new /obj/effect/temp_visual/gib_animation(loc, "gibbed-l")
@@ -14,7 +14,7 @@
QDEL_LIST(alien_powers)
return ..()
/obj/item/organ/alien/Insert(mob/living/carbon/M, special = 0)
/obj/item/organ/alien/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
..()
for(var/obj/effect/proc_holder/alien/P in alien_powers)
M.AddAbility(P)
@@ -94,7 +94,7 @@
else
owner.adjustPlasma(plasma_rate * 0.1)
/obj/item/organ/alien/plasmavessel/Insert(mob/living/carbon/M, special = 0)
/obj/item/organ/alien/plasmavessel/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
..()
if(isalien(M))
var/mob/living/carbon/alien/A = M
@@ -117,7 +117,7 @@
var/recent_queen_death = 0 //Indicates if the queen died recently, aliens are heavily weakened while this is active.
alien_powers = list(/obj/effect/proc_holder/alien/whisper)
/obj/item/organ/alien/hivenode/Insert(mob/living/carbon/M, special = 0)
/obj/item/organ/alien/hivenode/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
..()
M.faction |= ROLE_ALIEN
+2 -2
View File
@@ -256,7 +256,7 @@
/mob/living/carbon/fall(forced)
loc.handle_fall(src, forced)//it's loc so it doesn't call the mob's handle_fall which does nothing
loc.handle_fall(src, forced)//it's loc so it doesn't call the mob's handle_fall which does nothing
/mob/living/carbon/is_muzzled()
return(istype(src.wear_mask, /obj/item/clothing/mask/muzzle))
@@ -585,7 +585,7 @@
if(!isnull(E.lighting_alpha))
lighting_alpha = E.lighting_alpha
if(client.eye != src)
if(client.eye && client.eye != src)
var/atom/A = client.eye
if(A.update_remote_sight(src)) //returns 1 if we override all other sight updates.
return
+3 -3
View File
@@ -31,9 +31,9 @@
if (!user.get_bodypart(BODY_ZONE_L_ARM) || !user.get_bodypart(BODY_ZONE_R_ARM))
return
var/clap = pick('sound/misc/clap1.ogg',
'sound/misc/clap2.ogg',
'sound/misc/clap3.ogg',
'sound/misc/clap4.ogg')
'sound/misc/clap2.ogg',
'sound/misc/clap3.ogg',
'sound/misc/clap4.ogg')
playsound(user, clap, 50, 1, -1)
/datum/emote/living/carbon/gnarl
+18 -28
View File
@@ -4,36 +4,21 @@
/mob/living/carbon/human/dust_animation()
new /obj/effect/temp_visual/dust_animation(loc, "dust-h")
/mob/living/carbon/human/spawn_gibs(with_bodyparts)
if(isjellyperson(src))
if(with_bodyparts)
new /obj/effect/gibspawner/slime(drop_location(), dna, get_static_viruses())
/mob/living/carbon/human/spawn_gibs(with_bodyparts, atom/loc_override)
var/location = loc_override ? loc_override.drop_location() : drop_location()
if(dna?.species?.gib_types)
var/datum/species/S = dna.species
var/length = length(S.gib_types)
if(length)
var/path = (with_bodyparts && length > 1) ? S.gib_types[2] : S.gib_types[1]
new path(location, src, get_static_viruses())
else
new /obj/effect/gibspawner/slime/bodypartless(drop_location(), dna, get_static_viruses())
if(isipcperson(src))
if(with_bodyparts)
new /obj/effect/gibspawner/ipc(drop_location(), dna, get_static_viruses())
else
new /obj/effect/gibspawner/ipc/bodypartless(drop_location(), dna, get_static_viruses())
if(isxenoperson(src))
if(with_bodyparts)
new /obj/effect/gibspawner/xeno/xenoperson(drop_location(), dna, get_static_viruses())
else
new /obj/effect/gibspawner/xeno/xenoperson/bodypartless(drop_location(), dna, get_static_viruses())
if(islizard(src))
if(with_bodyparts)
new /obj/effect/gibspawner/lizard(drop_location(), dna, get_static_viruses())
else
new /obj/effect/gibspawner/lizard/bodypartless(drop_location(), dna, get_static_viruses())
new S.gib_types(location, src, get_static_viruses())
else
if(with_bodyparts)
new /obj/effect/gibspawner/human(drop_location(), dna, get_static_viruses())
new /obj/effect/gibspawner/human(location, src, get_static_viruses())
else
new /obj/effect/gibspawner/human/bodypartless(drop_location(), dna, get_static_viruses())
new /obj/effect/gibspawner/human/bodypartless(location, src, get_static_viruses())
/mob/living/carbon/human/spawn_dust(just_ash = FALSE)
if(just_ash)
@@ -69,11 +54,16 @@
/mob/living/carbon/human/proc/makeSkeleton()
ADD_TRAIT(src, TRAIT_DISFIGURED, TRAIT_GENERIC)
set_species(/datum/species/skeleton)
return 1
return TRUE
/mob/living/carbon/proc/Drain()
become_husk(CHANGELING_DRAIN)
ADD_TRAIT(src, TRAIT_NOCLONE, CHANGELING_DRAIN)
blood_volume = 0
return 1
return TRUE
/mob/living/carbon/proc/makeUncloneable()
ADD_TRAIT(src, TRAIT_NOCLONE, MADE_UNCLONEABLE)
blood_volume = 0
return TRUE
@@ -574,7 +574,7 @@
return threatcount
//Check for ID
var/obj/item/card/id/idcard = get_idcard()
var/obj/item/card/id/idcard = get_idcard(FALSE)
if( (judgement_criteria & JUDGE_IDCHECK) && !idcard && name=="Unknown")
threatcount += 4
@@ -778,7 +778,7 @@
broken_plural = TRUE
else
var/holder = broken[1] //our one and only element
if(holder[lentext(holder)] == "s")
if(holder[length(holder)] == "s")
broken_plural = TRUE
//Put the items in that list into a string of text
for(var/B in broken)
@@ -790,7 +790,7 @@
damaged_plural = TRUE
else
var/holder = damaged[1]
if(holder[lentext(holder)] == "s")
if(holder[length(holder)] == "s")
damaged_plural = TRUE
for(var/D in damaged)
damaged_message += D
@@ -11,8 +11,8 @@
//gets assignment from ID or ID inside PDA or PDA itself
//Useful when player do something with computers
/mob/living/carbon/human/proc/get_assignment(if_no_id = "No id", if_no_job = "No job")
var/obj/item/card/id/id = get_idcard()
/mob/living/carbon/human/proc/get_assignment(if_no_id = "No id", if_no_job = "No job", hand_first = TRUE)
var/obj/item/card/id/id = get_idcard(hand_first)
if(id)
. = id.assignment
else
@@ -27,7 +27,7 @@
//gets name from ID or ID inside PDA or PDA itself
//Useful when player do something with computers
/mob/living/carbon/human/proc/get_authentification_name(if_no_id = "Unknown")
var/obj/item/card/id/id = get_idcard()
var/obj/item/card/id/id = get_idcard(FALSE)
if(id)
return id.registered_name
var/obj/item/pda/pda = wear_id
@@ -86,10 +86,15 @@
return
//gets ID card object from special clothes slot or null.
/mob/living/carbon/human/get_idcard()
if(wear_id)
return wear_id.GetID()
/mob/living/carbon/human/get_idcard(hand_first = TRUE)
. = ..()
if(. && hand_first)
return
//Check inventory slots
var/obj/item/card/id/id_card = wear_id?.GetID()
if(!id_card)
id_card = belt?.GetID()
return id_card || .
/mob/living/carbon/human/IsAdvancedToolUser()
if(HAS_TRAIT(src, TRAIT_MONKEYLIKE))
@@ -100,7 +105,6 @@
return dna.species.handle_chemicals(R,src)
// if it returns 0, it will run the usual on_mob_life for that reagent. otherwise, it will stop after running handle_chemicals for the species.
/mob/living/carbon/human/can_track(mob/living/user)
if(wear_id && istype(wear_id.GetID(), /obj/item/card/id/syndicate))
return 0
+43 -49
View File
@@ -3,7 +3,7 @@
//NOTE: Breathing happens once per FOUR TICKS, unless the last breath fails. In which case it happens once per ONE TICK! So oxyloss healing is done once per 4 ticks while oxyloss damage is applied once per tick!
// bitflags for the percentual amount of protection a piece of clothing which covers the body part offers.
// Used with human/proc/get_heat_protection() and human/proc/get_cold_protection()
// Used with human/proc/get_thermal_protection()
// The values here should add up to 1.
// Hands and feet have 2.5%, arms and legs 7.5%, each of the torso parts has 15% and the head has 30%
#define THERMAL_PROTECTION_HEAD 0.3
@@ -53,16 +53,17 @@
/mob/living/carbon/human/calculate_affecting_pressure(pressure)
if (wear_suit && head && istype(wear_suit, /obj/item/clothing) && istype(head, /obj/item/clothing))
var/headless = !get_bodypart(BODY_ZONE_HEAD) //should the mob be perennially headless (see dullahans), we only take the suit into account, so they can into space.
if (wear_suit && istype(wear_suit, /obj/item/clothing) && (headless || (head && istype(head, /obj/item/clothing))))
var/obj/item/clothing/CS = wear_suit
var/obj/item/clothing/CH = head
if (CS.clothing_flags & CH.clothing_flags & STOPSPRESSUREDAMAGE)
if (CS.clothing_flags & STOPSPRESSUREDAMAGE && (headless || (CH.clothing_flags & STOPSPRESSUREDAMAGE)))
return ONE_ATMOSPHERE
if(isbelly(loc)) //START OF CIT CHANGES - Makes it so you don't suffocate while inside vore organs. Remind me to modularize this some time - Bhijn
return ONE_ATMOSPHERE
if(istype(loc, /obj/item/dogborg/sleeper))
return ONE_ATMOSPHERE //END OF CIT CHANGES
return pressure
return ..()
/mob/living/carbon/human/handle_traits()
@@ -136,7 +137,7 @@
if(dna)
dna.species.handle_fire(src)
/mob/living/carbon/human/proc/get_thermal_protection()
/mob/living/carbon/human/proc/easy_thermal_protection()
var/thermal_protection = 0 //Simple check to estimate how protected we are against multiple temperatures
//CITADEL EDIT Vore code required overrides
if(istype(loc, /obj/item/dogborg/sleeper))
@@ -168,7 +169,6 @@
..()
//END FIRE CODE
//This proc returns a number made up of the flags for body parts which you are protected on. (such as HEAD, CHEST, GROIN, etc. See setup.dm for the full list)
/mob/living/carbon/human/proc/get_heat_protection_flags(temperature) //Temperature is the temperature you're being exposed to.
var/thermal_protection_flags = 0
@@ -194,37 +194,6 @@
return thermal_protection_flags
/mob/living/carbon/human/proc/get_heat_protection(temperature) //Temperature is the temperature you're being exposed to.
var/thermal_protection_flags = get_heat_protection_flags(temperature)
var/thermal_protection = 0
if(thermal_protection_flags)
if(thermal_protection_flags & HEAD)
thermal_protection += THERMAL_PROTECTION_HEAD
if(thermal_protection_flags & CHEST)
thermal_protection += THERMAL_PROTECTION_CHEST
if(thermal_protection_flags & GROIN)
thermal_protection += THERMAL_PROTECTION_GROIN
if(thermal_protection_flags & LEG_LEFT)
thermal_protection += THERMAL_PROTECTION_LEG_LEFT
if(thermal_protection_flags & LEG_RIGHT)
thermal_protection += THERMAL_PROTECTION_LEG_RIGHT
if(thermal_protection_flags & FOOT_LEFT)
thermal_protection += THERMAL_PROTECTION_FOOT_LEFT
if(thermal_protection_flags & FOOT_RIGHT)
thermal_protection += THERMAL_PROTECTION_FOOT_RIGHT
if(thermal_protection_flags & ARM_LEFT)
thermal_protection += THERMAL_PROTECTION_ARM_LEFT
if(thermal_protection_flags & ARM_RIGHT)
thermal_protection += THERMAL_PROTECTION_ARM_RIGHT
if(thermal_protection_flags & HAND_LEFT)
thermal_protection += THERMAL_PROTECTION_HAND_LEFT
if(thermal_protection_flags & HAND_RIGHT)
thermal_protection += THERMAL_PROTECTION_HAND_RIGHT
return min(1,thermal_protection)
//See proc/get_heat_protection_flags(temperature) for the description of this proc.
/mob/living/carbon/human/proc/get_cold_protection_flags(temperature)
var/thermal_protection_flags = 0
@@ -251,17 +220,42 @@
return thermal_protection_flags
/mob/living/carbon/human/proc/get_cold_protection(temperature)
//CITADEL EDIT Mandatory for vore code.
if(istype(loc, /obj/item/dogborg/sleeper))
return TRUE //freezing to death in sleepers ruins fun.
if(isbelly(loc))
return TRUE
if(ismob(loc))
return TRUE //because lazy and being inside somemone insulates you from space
//END EDIT
temperature = max(temperature, 2.7) //There is an occasional bug where the temperature is miscalculated in ares with a small amount of gas on them, so this is necessary to ensure that that bug does not affect this calculation. Space's temperature is 2.7K and most suits that are intended to protect against any cold, protect down to 2.0K.
var/thermal_protection_flags = get_cold_protection_flags(temperature)
/mob/living/carbon/human/proc/get_thermal_protection(temperature, cold = FALSE)
if(cold)
//CITADEL EDIT Mandatory for vore code.
if(istype(loc, /obj/item/dogborg/sleeper) || isbelly(loc) || ismob(loc))
return 1 //freezing to death in sleepers ruins fun.
//END EDIT
temperature = max(temperature, 2.7) //There is an occasional bug where the temperature is miscalculated in ares with a small amount of gas on them, so this is necessary to ensure that that bug does not affect this calculation. Space's temperature is 2.7K and most suits that are intended to protect against any cold, protect down to 2.0K.
var/thermal_protection_flags = cold ? get_cold_protection_flags(temperature) : get_heat_protection_flags(temperature)
var/missing_body_parts_flags = ~get_body_parts_flags()
var/max_protection = 1
if(missing_body_parts_flags) //I don't like copypasta as much as proc overhead. Do you want me to make these into a macro?
DISABLE_BITFIELD(thermal_protection_flags, missing_body_parts_flags)
if(missing_body_parts_flags & HEAD)
max_protection -= THERMAL_PROTECTION_HEAD
if(missing_body_parts_flags & CHEST)
max_protection -= THERMAL_PROTECTION_CHEST
if(missing_body_parts_flags & GROIN)
max_protection -= THERMAL_PROTECTION_GROIN
if(missing_body_parts_flags & LEG_LEFT)
max_protection -= THERMAL_PROTECTION_LEG_LEFT
if(missing_body_parts_flags & LEG_RIGHT)
max_protection -= THERMAL_PROTECTION_LEG_RIGHT
if(missing_body_parts_flags & FOOT_LEFT)
max_protection -= THERMAL_PROTECTION_FOOT_LEFT
if(missing_body_parts_flags & FOOT_RIGHT)
max_protection -= THERMAL_PROTECTION_FOOT_RIGHT
if(missing_body_parts_flags & ARM_LEFT)
max_protection -= THERMAL_PROTECTION_ARM_LEFT
if(missing_body_parts_flags & ARM_RIGHT)
max_protection -= THERMAL_PROTECTION_ARM_RIGHT
if(missing_body_parts_flags & HAND_LEFT)
max_protection -= THERMAL_PROTECTION_HAND_LEFT
if(missing_body_parts_flags & HAND_RIGHT)
max_protection -= THERMAL_PROTECTION_HAND_RIGHT
if(max_protection == 0) //Is it even a man if it doesn't have a body at all? Early return to avoid division by zero.
return 1
var/thermal_protection = 0
if(thermal_protection_flags)
@@ -288,7 +282,7 @@
if(thermal_protection_flags & HAND_RIGHT)
thermal_protection += THERMAL_PROTECTION_HAND_RIGHT
return min(1,thermal_protection)
return round(thermal_protection/max_protection, 0.001)
/mob/living/carbon/human/handle_random_events()
//Puke if toxloss is too high
@@ -43,6 +43,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/exotic_blood = "" // If your race wants to bleed something other than bog standard blood, change this to reagent id.
var/exotic_bloodtype = "" //If your race uses a non standard bloodtype (A+, O-, AB-, etc)
var/meat = /obj/item/reagent_containers/food/snacks/meat/slab/human //What the species drops on gibbing
var/list/gib_types = list(/obj/effect/gibspawner/human, /obj/effect/gibspawner/human/bodypartless)
var/skinned_type
var/liked_food = NONE
var/disliked_food = GROSS
@@ -81,7 +82,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/sound/attack_sound = 'sound/weapons/punch1.ogg'
var/sound/miss_sound = 'sound/weapons/punchmiss.ogg'
var/mob/living/list/ignored_by = list() // list of mobs that will ignore this species
var/list/mob/living/ignored_by = list() // list of mobs that will ignore this species
//Breathing!
var/obj/item/organ/lungs/mutantlungs = null
var/breathid = "o2"
@@ -1755,7 +1756,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
switch(hit_area)
if(BODY_ZONE_HEAD)
if(!I.is_sharp() && armor_block < 50)
if(!I.get_sharpness() && armor_block < 50)
if(prob(I.force))
H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 20)
if(H.stat == CONSCIOUS)
@@ -1788,7 +1789,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
H.update_inv_glasses()
if(BODY_ZONE_CHEST)
if(H.stat == CONSCIOUS && !I.is_sharp() && armor_block < 50)
if(H.stat == CONSCIOUS && !I.get_sharpness() && armor_block < 50)
if(prob(I.force))
H.visible_message("<span class='danger'>[H] has been knocked down!</span>", \
"<span class='userdanger'>[H] has been knocked down!</span>")
@@ -2034,13 +2035,13 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
natural = H.natural_bodytemperature_stabilization()
var/thermal_protection = 1
if(loc_temp < H.bodytemperature) //Place is colder than we are
thermal_protection -= H.get_cold_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to.
thermal_protection -= H.get_thermal_protection(loc_temp, TRUE) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to.
if(H.bodytemperature < BODYTEMP_NORMAL) //we're cold, insulation helps us retain body heat and will reduce the heat we lose to the environment
H.adjust_bodytemperature((thermal_protection+1)*natural + max(thermal_protection * (loc_temp - H.bodytemperature) / BODYTEMP_COLD_DIVISOR, BODYTEMP_COOLING_MAX))
else //we're sweating, insulation hinders our ability to reduce heat - and it will reduce the amount of cooling you get from the environment
H.adjust_bodytemperature(natural*(1/(thermal_protection+1)) + max((thermal_protection * (loc_temp - H.bodytemperature) + BODYTEMP_NORMAL - H.bodytemperature) / BODYTEMP_COLD_DIVISOR , BODYTEMP_COOLING_MAX)) //Extra calculation for hardsuits to bleed off heat
else //Place is hotter than we are
thermal_protection -= H.get_heat_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to.
thermal_protection -= H.get_thermal_protection(loc_temp) //This returns a 0 - 1 value, which corresponds to the percentage of protection based on what you're wearing and what you're exposed to.
if(H.bodytemperature < BODYTEMP_NORMAL) //and we're cold, insulation enhances our ability to retain body heat but reduces the heat we get from the environment
H.adjust_bodytemperature((thermal_protection+1)*natural + min(thermal_protection * (loc_temp - H.bodytemperature) / BODYTEMP_HEAT_DIVISOR, BODYTEMP_HEATING_MAX))
else //we're sweating, insulation hinders out ability to reduce heat - but will reduce the amount of heat we get from the environment
@@ -2179,7 +2180,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(!(I.resistance_flags & FIRE_PROOF))
I.take_damage(H.fire_stacks, BURN, "fire", 0)
var/thermal_protection = H.get_thermal_protection()
var/thermal_protection = H.easy_thermal_protection()
if(thermal_protection >= FIRE_IMMUNITY_MAX_TEMP_PROTECT && !no_protection)
return
@@ -6,6 +6,7 @@
inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_NOFIRE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_LIMBATTACHMENT)
inherent_biotypes = list(MOB_ROBOTIC, MOB_HUMANOID)
meat = null
gib_types = /obj/effect/gibspawner/robot
damage_overlay_type = "synth"
mutanttongue = /obj/item/organ/tongue/robot
limbs_id = "synth"
@@ -17,4 +17,5 @@
use_skintones = 0
species_traits = list(NOBLOOD,EYECOLOR,NOGENITALS)
inherent_traits = list(TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOLIMBDISABLE,TRAIT_NOHUNGER)
sexes = 0
sexes = 0
gib_types = /obj/effect/gibspawner/robot
@@ -18,6 +18,8 @@
var/obj/item/dullahan_relay/myhead
/datum/species/dullahan/pumpkin
name = "Pumpkin Head Dullahan"
id = "pumpkindullahan"
pumpkin = TRUE
/datum/species/dullahan/check_roundstart_eligible()
@@ -27,7 +29,7 @@
/datum/species/dullahan/on_species_gain(mob/living/carbon/human/H, datum/species/old_species)
. = ..()
H.flags_1 &= ~HEAR_1
DISABLE_BITFIELD(H.flags_1, HEAR_1)
var/obj/item/bodypart/head/head = H.get_bodypart(BODY_ZONE_HEAD)
if(head)
if(pumpkin)//Pumpkinhead!
@@ -36,16 +38,16 @@
head.icon_state = "hardhat1_pumpkin_j"
head.custom_head = TRUE
head.drop_limb()
head.flags_1 = HEAR_1
head.throwforce = 25
myhead = new /obj/item/dullahan_relay (head, H)
H.put_in_hands(head)
var/obj/item/organ/eyes/E = H.getorganslot(ORGAN_SLOT_EYES)
for(var/datum/action/item_action/organ_action/OA in E.actions)
OA.Trigger()
if(!QDELETED(head)) //drop_limb() deletes the limb if it's no drop location and dummy humans used for rendering icons are located in nullspace. Do the math.
head.throwforce = 25
myhead = new /obj/item/dullahan_relay (head, H)
H.put_in_hands(head)
var/obj/item/organ/eyes/E = H.getorganslot(ORGAN_SLOT_EYES)
for(var/datum/action/item_action/organ_action/OA in E.actions)
OA.Trigger()
/datum/species/dullahan/on_species_loss(mob/living/carbon/human/H)
H.flags_1 |= ~HEAR_1
ENABLE_BITFIELD(H.flags_1, HEAR_1)
H.reset_perspective(H)
if(myhead)
var/obj/item/dullahan_relay/DR = myhead
@@ -84,7 +86,7 @@
/obj/item/organ/tongue/dullahan/handle_speech(datum/source, list/speech_args)
if(ishuman(owner))
var/mob/living/carbon/human/H = owner
if(H.dna.species.id == "dullahan")
if(isdullahan(H))
var/datum/species/dullahan/D = H.dna.species
if(isobj(D.myhead.loc))
var/obj/O = D.myhead.loc
@@ -99,6 +101,7 @@
desc = "An abstraction."
actions_types = list(/datum/action/item_action/organ_action/dullahan)
zone = "abstract"
tint = INFINITY // used to switch the vision perspective to the head on species_gain().
/datum/action/item_action/organ_action/dullahan
name = "Toggle Perspective"
@@ -114,37 +117,53 @@
if(ishuman(owner))
var/mob/living/carbon/human/H = owner
if(H.dna.species.id == "dullahan")
if(isdullahan(H))
var/datum/species/dullahan/D = H.dna.species
D.update_vision_perspective(H)
/obj/item/dullahan_relay
name = "dullahan relay"
var/mob/living/owner
flags_1 = HEAR_1
/obj/item/dullahan_relay/Initialize(mapload,new_owner)
/obj/item/dullahan_relay/Initialize(mapload, mob/living/carbon/human/new_owner)
. = ..()
if(!new_owner)
return INITIALIZE_HINT_QDEL
owner = new_owner
START_PROCESSING(SSobj, src)
RegisterSignal(owner, COMSIG_MOB_EXAMINATE, .proc/examinate_check)
RegisterSignal(src, COMSIG_ATOM_HEARER_IN_VIEW, .proc/include_owner)
RegisterSignal(owner, COMSIG_LIVING_REGENERATE_LIMBS, .proc/unlist_head)
RegisterSignal(owner, COMSIG_LIVING_FULLY_HEAL, .proc/retrieve_head)
/obj/item/dullahan_relay/proc/examinate_check(mob/source, atom/A)
if(source.client.eye == src && ((A in view(source.client.view, src)) || (isturf(A) && source.sight & SEE_TURFS) || (ismob(A) && source.sight & SEE_MOBS) || (isobj(A) && source.sight & SEE_OBJS)))
return COMPONENT_ALLOW_EXAMINE
/obj/item/dullahan_relay/proc/include_owner(datum/source, list/processing_list, list/hearers)
if(!QDELETED(owner))
hearers += owner
/obj/item/dullahan_relay/proc/unlist_head(datum/source, noheal = FALSE, list/excluded_limbs)
excluded_limbs |= BODY_ZONE_HEAD // So we don't gib when regenerating limbs.
/obj/item/dullahan_relay/proc/retrieve_head(datum/source, admin_revive = FALSE)
if(admin_revive) //retrieving the owner's head for ahealing purposes.
var/obj/item/bodypart/head/H = loc
var/turf/T = get_turf(owner)
if(H && istype(H) && T && !(H in owner.GetAllContents()))
H.forceMove(T)
/obj/item/dullahan_relay/process()
if(!istype(loc, /obj/item/bodypart/head) || QDELETED(owner))
. = PROCESS_KILL
qdel(src)
/obj/item/dullahan_relay/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
. = ..()
if(!QDELETED(owner))
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode)
to_chat(owner,message)
else
qdel(src)
/obj/item/dullahan_relay/Destroy()
if(!QDELETED(owner))
var/mob/living/carbon/human/H = owner
if(H.dna.species.id == "dullahan")
if(isdullahan(H))
var/datum/species/dullahan/D = H.dna.species
D.myhead = null
owner.gib()
@@ -64,6 +64,7 @@
attack_sound = 'sound/weapons/slash.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
meat = /obj/item/reagent_containers/food/snacks/meat/slab/xeno
gib_types = list(/obj/effect/gibspawner/xeno/xenoperson, /obj/effect/gibspawner/xeno/xenoperson/bodypartless)
skinned_type = /obj/item/stack/sheet/animalhide/xeno
exotic_bloodtype = "X*"
damage_overlay_type = "xeno"
@@ -796,7 +796,7 @@
if(resistance_flags & ON_FIRE)
return
if(P.is_hot())
if(P.get_temperature())
visible_message("<span class='danger'>[src] bursts into flames!</span>")
fire_act()
@@ -11,6 +11,7 @@
mutant_bodyparts = list("ipc_screen", "ipc_antenna")
default_features = list("ipc_screen" = "Blank", "ipc_antenna" = "None")
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/ipc
gib_types = list(/obj/effect/gibspawner/ipc, /obj/effect/gibspawner/ipc/bodypartless)
mutanttongue = /obj/item/organ/tongue/robot/ipc
mutant_heart = /obj/item/organ/heart/ipc
exotic_bloodtype = "HF"
@@ -11,6 +11,7 @@
default_features = list("mcolor" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "mam_snouts" = "None", "taur" = "None", "deco_wings" = "None") //CIT CHANGE
inherent_traits = list(TRAIT_TOXINLOVER)
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/slime
gib_types = list(/obj/effect/gibspawner/slime, /obj/effect/gibspawner/slime/bodypartless)
exotic_blood = "jellyblood"
exotic_bloodtype = "GEL"
damage_overlay_type = ""
@@ -18,6 +18,7 @@
attack_sound = 'sound/weapons/slash.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/lizard
gib_types = list(/obj/effect/gibspawner/lizard, /obj/effect/gibspawner/lizard/bodypartless)
skinned_type = /obj/item/stack/sheet/animalhide/lizard
exotic_bloodtype = "L"
disliked_food = GRAIN | DAIRY
@@ -78,7 +78,7 @@
icon_state = "brain-x-d"
var/obj/effect/proc_holder/spell/targeted/shadowwalk/shadowwalk
/obj/item/organ/brain/nightmare/Insert(mob/living/carbon/M, special = 0)
/obj/item/organ/brain/nightmare/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
..()
if(M.dna.species.id != "nightmare")
M.set_species(/datum/species/shadow/nightmare)
@@ -118,7 +118,7 @@
user.temporarilyRemoveItemFromInventory(src, TRUE)
Insert(user)
/obj/item/organ/heart/nightmare/Insert(mob/living/carbon/M, special = 0)
/obj/item/organ/heart/nightmare/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
..()
if(special != HEART_SPECIAL_SHADOWIFY)
blade = new/obj/item/light_eater
@@ -9,6 +9,7 @@
dangerous_existence = 1
blacklisted = 1
meat = null
gib_types = /obj/effect/gibspawner/robot
damage_overlay_type = "synth"
limbs_id = "synth"
var/list/initial_species_traits = list(NOTRANSSTING) //for getting these values back for assume_disguise()
@@ -400,17 +400,17 @@ There are several things that need to be remembered:
if(wear_suit)
var/obj/item/clothing/suit/S = wear_suit
var/no_taur_thanks = FALSE
var/item_level_support = FALSE // LISTEN! If you must degrade the code with further snowflake checks, at least keep it compatible with worn non-clothing items!
if(!istype(S))
no_taur_thanks = TRUE
item_level_support = TRUE
wear_suit.screen_loc = ui_oclothing
if(client && hud_used && hud_used.hud_shown)
if(hud_used.inventory_shown)
client.screen += wear_suit
update_observer_view(wear_suit,1)
if(!S.force_alternate_icon)
if(!no_taur_thanks && S.mutantrace_variation) //Just make sure we've got this checked too
if(!item_level_support && !S.force_alternate_icon)
if(S.mutantrace_variation) //Just make sure we've got this checked too
if(S.taurmode == NOT_TAURIC && S.adjusted == ALT_STYLE) //are we not a taur, but we have Digitigrade legs? Run this check first, then.
S.alternate_worn_icon = 'modular_citadel/icons/mob/suit_digi.dmi'
else
@@ -431,7 +431,7 @@ There are several things that need to be remembered:
if(OFFSET_SUIT in dna.species.offset_features)
suit_overlay.pixel_x += dna.species.offset_features[OFFSET_SUIT][1]
suit_overlay.pixel_y += dna.species.offset_features[OFFSET_SUIT][2]
if(!no_taur_thanks && S.center)
if(!item_level_support && S.center)
suit_overlay = center_image(suit_overlay, S.dimension_x, S.dimension_y)
overlays_standing[SUIT_LAYER] = suit_overlay
update_hair()
+6 -2
View File
@@ -23,8 +23,12 @@
/mob/living/proc/gib_animation()
return
/mob/living/proc/spawn_gibs()
new /obj/effect/gibspawner/generic(drop_location(), null, get_static_viruses())
/mob/living/proc/spawn_gibs(with_bodyparts, atom/loc_override)
var/location = loc_override ? loc_override.drop_location() : drop_location()
if(MOB_ROBOTIC in mob_biotypes)
new /obj/effect/gibspawner/robot(location, src, get_static_viruses())
else
new /obj/effect/gibspawner/generic(location, src, get_static_viruses())
/mob/living/proc/spill_organs()
return
+11
View File
@@ -40,6 +40,16 @@
QDEL_LIST(diseases)
return ..()
/mob/living/onZImpact(turf/T, levels)
if(!isgroundlessturf(T))
ZImpactDamage(T, levels)
return ..()
/mob/living/proc/ZImpactDamage(turf/T, levels)
visible_message("<span class='danger'>[src] crashes into [T] with a sickening noise!</span>")
adjustBruteLoss((levels * 5) ** 1.5)
Knockdown(levels * 50)
/mob/living/proc/OpenCraftingMenu()
return
@@ -514,6 +524,7 @@
for(var/organ in C.internal_organs)
var/obj/item/organ/O = organ
O.setOrganDamage(0)
SEND_SIGNAL(src, COMSIG_LIVING_FULLY_HEAL, admin_revive)
//proc called by revive(), to check if we can actually ressuscitate the mob (we don't want to revive him and have him instantly die again)
+4 -1
View File
@@ -32,4 +32,7 @@
if(drag_slowdown && L.lying && !L.buckled && grab_state < GRAB_AGGRESSIVE)
add_movespeed_modifier(MOVESPEED_ID_PRONE_DRAGGING, multiplicative_slowdown = PULL_PRONE_SLOWDOWN)
return
remove_movespeed_modifier(MOVESPEED_ID_PRONE_DRAGGING)
remove_movespeed_modifier(MOVESPEED_ID_PRONE_DRAGGING)
/mob/living/canZMove(dir, turf/target)
return can_zTravel(target, dir) && (movement_type & FLYING)
+2 -1
View File
@@ -783,7 +783,7 @@
/mob/living/silicon/ai/can_buckle()
return 0
/mob/living/silicon/ai/incapacitated()
/mob/living/silicon/ai/incapacitated(ignore_restraints, ignore_grab)
if(aiRestorePowerRoutine)
return TRUE
return ..()
@@ -882,6 +882,7 @@
/mob/living/silicon/ai/revive(full_heal = 0, admin_revive = 0)
. = ..()
if(.) //successfully ressuscitated from death
set_eyeobj_visible(TRUE)
set_core_display_icon(display_icon_override)
/mob/living/silicon/ai/proc/malfhacked(obj/machinery/power/apc/apc)
@@ -18,6 +18,7 @@
update_canmove()
if(eyeobj)
eyeobj.setLoc(get_turf(src))
set_eyeobj_visible(FALSE)
GLOB.shuttle_caller_list -= src
SSshuttle.autoEvac()
@@ -36,6 +37,8 @@
if(istype(loc, /obj/item/aicard/aitater))
loc.icon_state = "aitater-404"
else if(istype(loc, /obj/item/aicard/aispook))
loc.icon_state = "aispook-404"
else if(istype(loc, /obj/item/aicard))
loc.icon_state = "aicard-404"
@@ -6,6 +6,8 @@
/mob/camera/aiEye
name = "Inactive AI Eye"
icon_state = "ai_camera"
icon = 'icons/mob/cameramob.dmi'
invisibility = INVISIBILITY_MAXIMUM
hud_possible = list(ANTAG_HUD, AI_DETECT_HUD = HUD_LIST_LIST)
var/list/visibleCameraChunks = list()
@@ -158,11 +160,11 @@
cameraFollow = null
unset_machine()
if(!eyeobj || !eyeobj.loc || QDELETED(eyeobj))
if(isturf(loc) && (QDELETED(eyeobj) || !eyeobj.loc))
to_chat(src, "ERROR: Eyeobj not found. Creating new eye...")
create_eye()
eyeobj.setLoc(loc)
eyeobj?.setLoc(loc)
/mob/living/silicon/ai/proc/create_eye()
if(eyeobj)
@@ -172,6 +174,13 @@
eyeobj.ai = src
eyeobj.setLoc(loc)
eyeobj.name = "[name] (AI Eye)"
set_eyeobj_visible(TRUE)
/mob/living/silicon/ai/proc/set_eyeobj_visible(state = TRUE)
if(!eyeobj)
return
eyeobj.mouse_opacity = state ? MOUSE_OPACITY_ICON : initial(eyeobj.mouse_opacity)
eyeobj.invisibility = state ? INVISIBILITY_OBSERVER : initial(eyeobj.invisibility)
/mob/living/silicon/ai/verb/toggle_acceleration()
set category = "AI Commands"
+1 -1
View File
@@ -19,7 +19,7 @@
// messenging the client
malfhacked(malfhack)
if(!eyeobj || QDELETED(eyeobj) || !eyeobj.loc)
if(isturf(loc) && (QDELETED(eyeobj) || !eyeobj.loc))
view_core()
if(machine)
@@ -6,6 +6,7 @@
O.mode = 1
O.emotion = "Neutral"
O.update()
set_eyeobj_visible(TRUE)
if(multicam_on)
end_multicam()
view_core()
@@ -4,4 +4,5 @@
var/obj/machinery/status_display/ai/O = each
O.mode = 0
O.update()
set_eyeobj_visible(FALSE)
view_core()
@@ -120,6 +120,9 @@ GLOBAL_DATUM(ai_camera_room_landmark, /obj/effect/landmark/ai_multicam_room)
/mob/camera/aiEye/pic_in_pic
name = "Secondary AI Eye"
invisibility = INVISIBILITY_OBSERVER
mouse_opacity = MOUSE_OPACITY_ICON
icon_state = "ai_pip_camera"
var/obj/screen/movable/pic_in_pic/ai/screen
var/list/cameras_telegraphed = list()
var/telegraph_cameras = TRUE
+1 -1
View File
@@ -49,7 +49,7 @@
else
padloc = "(UNKNOWN)"
src.log_talk(message, LOG_SAY, tag="HOLOPAD in [padloc]")
send_speech(message, 7, T, "robot", message_language = language)
send_speech(message, 7, T, "robot", language)
to_chat(src, "<i><span class='game say'>Holopad transmitted, <span class='name'>[real_name]</span> <span class='message robot'>\"[message]\"</span></span></i>")
else
to_chat(src, "No holopad connected.")
+2 -2
View File
@@ -1,5 +1,5 @@
/mob/living/silicon/spawn_gibs()
new /obj/effect/gibspawner/robot(drop_location())
/mob/living/silicon/spawn_gibs(with_bodyparts, atom/loc_override)
new /obj/effect/gibspawner/robot(loc_override ? loc_override.drop_location() : drop_location(), src)
/mob/living/silicon/spawn_dust()
new /obj/effect/decal/remains/robot(loc)
@@ -140,7 +140,7 @@
radio.attack_self(src)
if("image")
var/newImage = input("Select your new display image.", "Display Image", "Happy") in list("Happy", "Cat", "Extremely Happy", "Face", "Laugh", "Off", "Sad", "Angry", "What" , "Exclamation" ,"Question") // CITADEL EDIT
var/newImage = input("Select your new display image.", "Display Image", "Happy") in list("Happy", "Cat", "Extremely Happy", "Face", "Laugh", "Off", "Sad", "Angry", "What" , "Exclamation" ,"Question", "Sunglasses")
var/pID = 1
switch(newImage)
@@ -164,10 +164,12 @@
pID = 9
if("Null")
pID = 10
if("Exclamation") // CITADEL EDIT
if("Exclamation")
pID = 11
if("Question") // CITADEL EDIT
if("Question")
pID = 12
if("Sunglasses")
pID = 13
card.setEmotion(pID)
if("signaller")
@@ -101,7 +101,7 @@
if(ASSEMBLY_FOURTH_STEP)
if(istype(W, /obj/item/weldingtool))
if(W.use_tool(src, user, 0, volume=40))
if(W.use_tool(src, user, 0, volume=40) && build_step == 4)
name = "shielded frame assembly"
to_chat(user, "<span class='notice'>You weld the vest to [src].</span>")
build_step++
@@ -183,7 +183,7 @@
if(8)
if(istype(W, /obj/item/screwdriver))
to_chat(user, "<span class='notice'>You start attaching the gun to the frame...</span>")
if(W.use_tool(src, user, 40, volume=100))
if(W.use_tool(src, user, 40, volume=100) && build_step == 8)
name = "armed [name]"
to_chat(user, "<span class='notice'>Taser gun attached.</span>")
build_step++
@@ -218,7 +218,7 @@
bot_control(action, usr) // Kill this later.
. = TRUE
/mob/living/simple_animal/bot/mulebot/bot_control(command, mob/user, pda = 0)
/mob/living/simple_animal/bot/mulebot/bot_control(command, mob/user, pda = 0, turf/user_turf, list/user_access = list())
if(pda && wires.is_cut(WIRE_RX)) // MULE wireless is controlled by wires.
return
@@ -159,16 +159,16 @@ Auto Patrol: []"},
mode = BOT_HUNT
/mob/living/simple_animal/bot/secbot/proc/judgement_criteria()
var/final = FALSE
if(idcheck)
final = final|JUDGE_IDCHECK
if(check_records)
final = final|JUDGE_RECORDCHECK
if(weaponscheck)
final = final|JUDGE_WEAPONCHECK
if(emagged == 2)
final = final|JUDGE_EMAGGED
return final
var/final = FALSE
if(idcheck)
final = final|JUDGE_IDCHECK
if(check_records)
final = final|JUDGE_RECORDCHECK
if(weaponscheck)
final = final|JUDGE_WEAPONCHECK
if(emagged == 2)
final = final|JUDGE_EMAGGED
return final
/mob/living/simple_animal/bot/secbot/proc/special_retaliate_after_attack(mob/user) //allows special actions to take place after being attacked.
return
@@ -21,7 +21,7 @@
. = ..()
var/area/A = get_area(src)
if(A)
notify_ghosts("A drone shell has been created in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE, ignore_key = POLL_IGNORE_DRONE)
notify_ghosts("A drone shell has been created in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE, ignore_key = POLL_IGNORE_DRONE, ignore_dnr_observers = TRUE)
GLOB.poi_list |= src
if(isnull(possible_seasonal_hats))
build_seasonal_hats()
@@ -40,7 +40,7 @@
. = ..()
//ATTACK GHOST IGNORING PARENT RETURN VALUE
/obj/item/drone_shell/attack_ghost(mob/user)
/obj/item/drone_shell/attack_ghost(mob/dead/observer/user)
if(jobban_isbanned(user,"drone") || QDELETED(src) || QDELETED(user))
return
if(CONFIG_GET(flag/use_age_restriction_for_jobs))
@@ -49,6 +49,8 @@
if(user.client.player_age < DRONE_MINIMUM_AGE)
to_chat(user, "<span class='danger'>You're too new to play as a drone! Please try again in [DRONE_MINIMUM_AGE - user.client.player_age] days.</span>")
return
if(!user.can_reenter_round())
return FALSE
if(!SSticker.mode)
to_chat(user, "Can't become a drone before the game has started.")
return
@@ -1,39 +1,39 @@
/mob/living/simple_animal/hostile/retaliate/poison
var/poison_per_bite = 0
var/poison_type = "toxin"
var/poison_per_bite = 0
var/poison_type = "toxin"
/mob/living/simple_animal/hostile/retaliate/poison/AttackingTarget()
. = ..()
if(. && isliving(target))
var/mob/living/L = target
if(L.reagents && !poison_per_bite == 0)
L.reagents.add_reagent(poison_type, poison_per_bite)
return .
. = ..()
if(. && isliving(target))
var/mob/living/L = target
if(L.reagents && !poison_per_bite == 0)
L.reagents.add_reagent(poison_type, poison_per_bite)
return
/mob/living/simple_animal/hostile/retaliate/poison/snake
name = "snake"
desc = "A slithery snake. These legless reptiles are the bane of mice and adventurers alike."
icon_state = "snake"
icon_living = "snake"
icon_dead = "snake_dead"
speak_emote = list("hisses")
health = 20
maxHealth = 20
attacktext = "bites"
melee_damage_lower = 5
melee_damage_upper = 6
response_help = "pets"
response_disarm = "shoos"
response_harm = "steps on"
faction = list("hostile")
ventcrawler = VENTCRAWLER_ALWAYS
density = FALSE
pass_flags = PASSTABLE | PASSMOB
mob_size = MOB_SIZE_SMALL
mob_biotypes = list(MOB_ORGANIC, MOB_BEAST, MOB_REPTILE)
gold_core_spawnable = FRIENDLY_SPAWN
obj_damage = 0
environment_smash = ENVIRONMENT_SMASH_NONE
name = "snake"
desc = "A slithery snake. These legless reptiles are the bane of mice and adventurers alike."
icon_state = "snake"
icon_living = "snake"
icon_dead = "snake_dead"
speak_emote = list("hisses")
health = 20
maxHealth = 20
attacktext = "bites"
melee_damage_lower = 5
melee_damage_upper = 6
response_help = "pets"
response_disarm = "shoos"
response_harm = "steps on"
faction = list("hostile")
ventcrawler = VENTCRAWLER_ALWAYS
density = FALSE
pass_flags = PASSTABLE | PASSMOB
mob_size = MOB_SIZE_SMALL
mob_biotypes = list(MOB_ORGANIC, MOB_BEAST, MOB_REPTILE)
gold_core_spawnable = FRIENDLY_SPAWN
obj_damage = 0
environment_smash = ENVIRONMENT_SMASH_NONE
/mob/living/simple_animal/hostile/retaliate/poison/snake/ListTargets(atom/the_target)
@@ -54,9 +54,9 @@
return mice
/mob/living/simple_animal/hostile/retaliate/poison/snake/AttackingTarget()
if(istype(target, /mob/living/simple_animal/mouse))
visible_message("<span class='notice'>[name] consumes [target] in a single gulp!</span>", "<span class='notice'>You consume [target] in a single gulp!</span>")
QDEL_NULL(target)
adjustBruteLoss(-2)
else
return ..()
if(istype(target, /mob/living/simple_animal/mouse))
visible_message("<span class='notice'>[name] consumes [target] in a single gulp!</span>", "<span class='notice'>You consume [target] in a single gulp!</span>")
QDEL_NULL(target)
adjustBruteLoss(-2)
else
return ..()
@@ -33,7 +33,7 @@
. = ..()
var/area/A = get_area(src)
if(A)
notify_ghosts("A banana spider has been created in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE)
notify_ghosts("A banana spider has been created in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE, ignore_dnr_observers = TRUE)
/mob/living/simple_animal/banana_spider/attack_ghost(mob/user)
if(key) //please stop using src. without a good reason.
@@ -41,12 +41,19 @@
if(CONFIG_GET(flag/use_age_restriction_for_jobs))
if(!isnum(user.client.player_age))
return
if(isobserver(user))
var/mob/dead/observer/O = user
if(!O.can_reenter_round())
return
if(!SSticker.mode)
to_chat(user, "Can't become a banana spider before the game has started.")
return
var/be_spider = alert("Become a banana spider? (Warning, You can no longer be cloned!)",,"Yes","No")
if(be_spider == "No" || QDELETED(src) || !isobserver(user))
return
if(key)
to_chat(user, "<span class='notice'>Someone else already took this banana spider.</span>")
return
sentience_act()
user.transfer_ckey(src, FALSE)
density = TRUE
@@ -83,15 +83,19 @@
/mob/living/simple_animal/hostile/poison/giant_spider/proc/humanize_spider(mob/user)
if(key || !playable_spider || stat)//Someone is in it, it's dead, or the fun police are shutting it down
return 0
return FALSE
if(isobserver(user))
var/mob/dead/observer/O = user
if(!O.can_reenter_round())
return FALSE
var/spider_ask = alert("Become a spider?", "Are you australian?", "Yes", "No")
if(spider_ask == "No" || !src || QDELETED(src))
return 1
return TRUE
if(key)
to_chat(user, "<span class='notice'>Someone else already took this spider.</span>")
return 1
return TRUE
user.transfer_ckey(src, FALSE)
return 1
return TRUE
//nursemaids - these create webs and eggs
/mob/living/simple_animal/hostile/poison/giant_spider/nurse
@@ -388,7 +388,7 @@ Difficulty: Very Hard
ActivationReaction(user, ACTIVATE_TOUCH)
/obj/machinery/anomalous_crystal/attackby(obj/item/I, mob/user, params)
if(I.is_hot())
if(I.get_temperature())
ActivationReaction(user, ACTIVATE_HEAT)
else
ActivationReaction(user, ACTIVATE_WEAPON)
@@ -575,13 +575,15 @@ Difficulty: Very Hard
if(..() && !ready_to_deploy)
GLOB.poi_list |= src
ready_to_deploy = TRUE
notify_ghosts("An anomalous crystal has been activated in [get_area(src)]! This crystal can always be used by ghosts hereafter.", enter_link = "<a href=?src=[REF(src)];ghostjoin=1>(Click to enter)</a>", ghost_sound = 'sound/effects/ghost2.ogg', source = src, action = NOTIFY_ATTACK)
notify_ghosts("An anomalous crystal has been activated in [get_area(src)]! This crystal can always be used by ghosts hereafter.", enter_link = "<a href=?src=[REF(src)];ghostjoin=1>(Click to enter)</a>", ghost_sound = 'sound/effects/ghost2.ogg', source = src, action = NOTIFY_ATTACK, ignore_dnr_observers = TRUE)
/obj/machinery/anomalous_crystal/helpers/attack_ghost(mob/dead/observer/user)
. = ..()
if(.)
return
if(ready_to_deploy)
if(!user.can_reenter_round())
return FALSE
var/be_helper = alert("Become a Lightgeist? (Warning, You can no longer be cloned!)",,"Yes","No")
if(be_helper == "Yes" && !QDELETED(src) && isobserver(user))
var/mob/living/simple_animal/hostile/lightgeist/W = new /mob/living/simple_animal/hostile/lightgeist(get_turf(loc))
@@ -649,7 +651,7 @@ Difficulty: Very Hard
L.heal_overall_damage(heal_power, heal_power)
new /obj/effect/temp_visual/heal(get_turf(target), "#80F5FF")
/mob/living/simple_animal/hostile/lightgeist/ghostize(can_reenter_corpse = TRUE, send_the_signal = TRUE)
/mob/living/simple_animal/hostile/lightgeist/ghostize(can_reenter_corpse = TRUE, special = FALSE)
. = ..()
if(.)
death()
@@ -728,7 +730,7 @@ Difficulty: Very Hard
holder_animal.mind.AddSpell(P)
holder_animal.verbs -= /mob/living/verb/pulled
/obj/structure/closet/stasis/dump_contents(var/kill = 1)
/obj/structure/closet/stasis/dump_contents(override = TRUE, kill = 1)
STOP_PROCESSING(SSobj, src)
for(var/mob/living/L in src)
REMOVE_TRAIT(L, TRAIT_MUTE, STASIS_MUTE)
@@ -774,7 +776,7 @@ Difficulty: Very Hard
for(var/i in user)
if(istype(i, /obj/structure/closet/stasis))
var/obj/structure/closet/stasis/S = i
S.dump_contents(0)
S.dump_contents(kill=0)
qdel(S)
break
user.gib()
@@ -95,7 +95,7 @@
if(M)
playsound(src, 'sound/magic/demon_consume.ogg', 50, 1)
M.adjustBruteLoss(60)
new /obj/effect/gibspawner/generic(get_turf(M))
M.spawn_gibs()
if(M.stat == DEAD)
var/mob/living/simple_animal/hostile/netherworld/blankbody/blank
blank = new(loc)
@@ -462,8 +462,8 @@
return
sync_lighting_plane_alpha()
/mob/living/simple_animal/get_idcard()
return access_card
/mob/living/simple_animal/get_idcard(hand_first = TRUE)
return ..() || access_card
/mob/living/simple_animal/OpenCraftingMenu()
if(dextrous)
+6 -7
View File
@@ -307,8 +307,11 @@
set name = "Examine"
set category = "IC"
if(isturf(A) && !(sight & SEE_TURFS) && !(A in view(client ? client.view : world.view, src)))
// shift-click catcher may issue examinate() calls for out-of-sight turfs
if(!client)
return
if(!(SEND_SIGNAL(src, COMSIG_MOB_EXAMINATE, A) & COMPONENT_ALLOW_EXAMINE) && ((client.eye != src && client.eye != loc) || (isturf(A) && !(sight & SEE_TURFS) && !(A in view(client ? client.view : world.view, src)))))
//cameras & co don't allow users to examine far away things, also shift-click catcher may issue examinate() calls for out-of-sight turfs
return
if(is_blind(src))
@@ -864,7 +867,7 @@ GLOBAL_VAR_INIT(exploit_warn_spam_prevention, 0)
replace_identification_name(oldname,newname)
for(var/datum/mind/T in SSticker.minds)
for(var/datum/objective/obj in T.objectives)
for(var/datum/objective/obj in T.get_all_objectives())
// Only update if this player is a target
if(obj.target && obj.target.current && obj.target.current.real_name == name)
obj.update_explanation_text()
@@ -930,10 +933,6 @@ GLOBAL_VAR_INIT(exploit_warn_spam_prevention, 0)
/mob/proc/can_hold_items()
return FALSE
/mob/proc/get_idcard()
return
/mob/vv_get_dropdown()
. = ..()
. += "---"
+20 -6
View File
@@ -67,8 +67,8 @@
/proc/slur(n,var/strength=50)
strength = min(strength,50)
var/phrase = html_decode(n)
var/leng = lentext(phrase)
var/counter=lentext(phrase)
var/leng = length(phrase)
var/counter=length(phrase)
var/newphrase=""
var/newletter=""
while(counter>=1)
@@ -102,8 +102,8 @@
/proc/cultslur(n) // Inflicted on victims of a stun talisman
var/phrase = html_decode(n)
var/leng = lentext(phrase)
var/counter=lentext(phrase)
var/leng = length(phrase)
var/counter=length(phrase)
var/newphrase=""
var/newletter=""
while(counter>=1)
@@ -352,12 +352,12 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
/mob/proc/reagent_check(datum/reagent/R) // utilized in the species code
return 1
/proc/notify_ghosts(var/message, var/ghost_sound = null, var/enter_link = null, var/atom/source = null, var/mutable_appearance/alert_overlay = null, var/action = NOTIFY_JUMP, flashwindow = TRUE, ignore_mapload = TRUE, ignore_key) //Easy notification of ghosts.
/proc/notify_ghosts(message, ghost_sound, enter_link, atom/source, mutable_appearance/alert_overlay, action = NOTIFY_JUMP, flashwindow = TRUE, ignore_mapload = TRUE, ignore_key, ignore_dnr_observers = FALSE) //Easy notification of ghosts.
if(ignore_mapload && SSatoms.initialized != INITIALIZATION_INNEW_REGULAR) //don't notify for objects created during a map load
return
for(var/mob/dead/observer/O in GLOB.player_list)
if(O.client)
if (ignore_key && O.ckey in GLOB.poll_ignore[ignore_key])
if ((ignore_key && (O.ckey in GLOB.poll_ignore[ignore_key])) || (ignore_dnr_observers && !O.can_reenter_round(TRUE)))
continue
to_chat(O, "<span class='ghostalert'>[message][(enter_link) ? " [enter_link]" : ""]</span>")
if(ghost_sound)
@@ -518,3 +518,17 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
else if(HAS_TRAIT_FROM(src, TRAIT_DISSECTED,"Thorough Dissection"))
dissectionmsg = " via Thorough Dissection"
. += "<span class='notice'>This body has been dissected and analyzed[dissectionmsg].</span><br>"
//gets ID card object from special clothes slot or null.
/mob/proc/get_idcard(hand_first = TRUE)
var/obj/item/held_item = get_active_held_item()
. = held_item?.GetID()
if(!.) //If so, then check the inactive hand
held_item = get_inactive_held_item()
. = held_item?.GetID()
/mob/proc/get_id_in_hand()
var/obj/item/held_item = get_active_held_item()
if(!held_item)
return
return held_item.GetID()
+32
View File
@@ -370,3 +370,35 @@
if(hud_used && hud_used.static_inventory)
for(var/obj/screen/mov_intent/selector in hud_used.static_inventory)
selector.update_icon(src)
/mob/verb/up()
set name = "Move Upwards"
set category = "IC"
if(zMove(UP, TRUE))
to_chat(src, "<span class='notice'>You move upwards.</span>")
/mob/verb/down()
set name = "Move Down"
set category = "IC"
if(zMove(DOWN, TRUE))
to_chat(src, "<span class='notice'>You move down.</span>")
/mob/proc/zMove(dir, feedback = FALSE)
if(dir != UP && dir != DOWN)
return FALSE
var/turf/target = get_step_multiz(src, dir)
if(!target)
if(feedback)
to_chat(src, "<span class='warning'>There's nothing in that direction!</span>")
return FALSE
if(!canZMove(dir, target))
if(feedback)
to_chat(src, "<span class='warning'>You couldn't move there!</span>")
return FALSE
forceMove(target)
return TRUE
/mob/proc/canZMove(direction, turf/target)
return FALSE
@@ -47,7 +47,7 @@
D.updateappearance(mutcolor_update=1, mutations_overlay_update=1)
else if(ishuman(M))
var/mob/living/carbon/human/H = M
client.prefs.copy_to(H)
client?.prefs.copy_to(H)
H.dna.update_dna_identity()
if(mind && isliving(M))
+1 -1
View File
@@ -25,7 +25,7 @@
if(flavor_text && flavor_text != "")
// We are decoding and then encoding to not only get correct amount of characters, but also to prevent partial escaping characters being shown.
var/msg = html_decode(replacetext(flavor_text, "\n", " "))
if(lentext(msg) <= 40)
if(length(msg) <= 40)
return "<span class='notice'>[html_encode(msg)]</span>"
else
return "<span class='notice'>[html_encode(copytext(msg, 1, 37))]... <a href='?src=[REF(src)];flavor_more=1'>More...</span></a>"