This commit is contained in:
Ghommie
2020-01-04 13:35:05 +01:00
489 changed files with 24949 additions and 14497 deletions
+1 -1
View File
@@ -693,7 +693,7 @@
var/prev_dynamic_voting = CONFIG_GET(flag/dynamic_voting)
CONFIG_SET(flag/dynamic_voting,!prev_dynamic_voting)
if (!prev_dynamic_voting)
to_chat(world, "<B>Vote is now between extended and dynamic chaos.</B>")
to_chat(world, "<B>Vote is now a ranked choice of dynamic storytellers.</B>")
else
to_chat(world, "<B>Vote is now between extended and secret.</B>")
log_admin("[key_name(usr)] [prev_dynamic_voting ? "disabled" : "enabled"] dynamic voting.")
+1 -1
View File
@@ -492,7 +492,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
message_admins("<span class='adminnotice'>[key_name_admin(usr)] assumed direct control of [M].</span>")
log_admin("[key_name(usr)] assumed direct control of [M].")
var/mob/adminmob = src.mob
M.ckey = src.ckey
adminmob.transfer_ckey(M, send_signal = FALSE)
if( isobserver(adminmob) )
qdel(adminmob)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Assume Direct Control") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+19
View File
@@ -35,6 +35,9 @@ GLOBAL_LIST_INIT(admin_verbs_debug_mapping, list(
/client/proc/cmd_admin_grantfullaccess,
/client/proc/cmd_admin_areatest_all,
/client/proc/cmd_admin_areatest_station,
#ifdef TESTING
/client/proc/see_dirty_varedits,
#endif
/client/proc/cmd_admin_test_atmos_controllers,
/client/proc/cmd_admin_rejuvenate,
/datum/admins/proc/show_traitor_panel,
@@ -84,8 +87,24 @@ GLOBAL_PROTECT(admin_verbs_debug_mapping)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Show Camera Range") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
SSblackbox.record_feedback("tally", "admin_verb", 1, "Show Camera Range")
#ifdef TESTING
GLOBAL_LIST_EMPTY(dirty_vars)
/client/proc/see_dirty_varedits()
set category = "Mapping"
set name = "Dirty Varedits"
var/list/dat = list()
dat += "<h3>Abandon all hope ye who enter here</h3><br><br>"
for(var/thing in GLOB.dirty_vars)
dat += "[thing]<br>"
CHECK_TICK
var/datum/browser/popup = new(usr, "dirty_vars", "Dirty Varedits", 900, 750)
popup.set_content(dat.Join())
popup.open()
#endif
/client/proc/sec_camera_report()
set category = "Mapping"
set name = "Camera Report"
@@ -484,11 +484,9 @@
user.do_attack_animation(L)
if(ishuman(L))
var/mob/living/carbon/human/H = L
if(H.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK))
playsound(H, 'sound/weapons/genhit.ogg', 50, TRUE)
return FALSE
if(L.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK))
playsound(L, 'sound/weapons/genhit.ogg', 50, TRUE)
return FALSE
switch (mode)
if(BATON_STUN)
@@ -3,6 +3,7 @@
icon = 'icons/mob/blob.dmi'
icon_state = "blob_shield"
desc = "A solid wall of slightly twitching tendrils."
var/damaged_desc = "A wall of twitching tendrils."
max_integrity = 150
brute_resist = 0.25
explosion_block = 3
@@ -21,10 +22,10 @@
/obj/structure/blob/shield/update_icon()
..()
if(obj_integrity <= 70)
icon_state = "blob_shield_damaged"
name = "weakened strong blob"
desc = "A wall of twitching tendrils."
if(obj_integrity < max_integrity * 0.5)
icon_state = "[initial(icon_state)]_damaged"
name = "weakened [initial(name)]"
desc = "[damaged_desc]"
atmosblock = FALSE
if(!weakened)
armor = armor.setRating("melee" = 15, "bullet" = 15, "laser" = 5, "energy" = 0, "bomb" = 10, "bio" = 0, "rad" = 0, "fire" = 90, "acid" = 90)
@@ -37,4 +38,27 @@
if(weakened)
armor = armor.setRating("melee" = 25, "bullet" = 25, "laser" = 15, "energy" = 10, "bomb" = 20, "bio" = 0, "rad" = 0, "fire" = 90, "acid" = 90)
weakened = FALSE
air_update_turf(1)
air_update_turf(1)
/obj/structure/blob/shield/reflective
name = "reflective blob"
desc = "A solid wall of slightly twitching tendrils with a reflective glow."
damaged_desc = "A wall of twitching tendrils with a reflective glow."
icon_state = "blob_glow"
flags_1 = CHECK_RICOCHET_1
point_return = 8
max_integrity = 50
brute_resist = 1
explosion_block = 2
/obj/structure/blob/shield/reflective/handle_ricochet(obj/item/projectile/P)
var/turf/p_turf = get_turf(P)
var/face_direction = get_dir(src, p_turf)
var/face_angle = dir2angle(face_direction)
var/incidence_s = GET_ANGLE_OF_INCIDENCE(face_angle, (P.Angle + 180))
if(abs(incidence_s) > 90 && abs(incidence_s) < 270)
return FALSE
var/new_angle_s = SIMPLIFY_DEGREES(face_angle + incidence_s)
P.setAngle(new_angle_s)
visible_message("<span class='warning'>[P] reflects off [src]!</span>")
return TRUE
+14 -4
View File
@@ -113,12 +113,22 @@
/mob/camera/blob/verb/create_shield_power()
set category = "Blob"
set name = "Create Shield Blob (15)"
set desc = "Create a shield blob, which will block fire and is hard to kill."
set name = "Create/Upgrade Shield Blob (15)"
set desc = "Create a shield blob, which will block fire and is hard to kill. Using this on an existing shield blob turns it into a reflective blob, capable of reflecting most projectiles but making it much weaker than usual to brute attacks."
create_shield()
/mob/camera/blob/proc/create_shield(turf/T)
createSpecial(15, /obj/structure/blob/shield, 0, 0, T)
var/obj/structure/blob/shield/S = locate(/obj/structure/blob/shield) in T
if(S)
if(!can_buy(15))
return
if(S.obj_integrity < S.max_integrity * 0.5)
to_chat(src, "<span class='warning'>This shield blob is too damaged to be modified properly!</span>")
return
to_chat(src, "<span class='warning'>You secrete a reflective ooze over the shield blob, allowing it to reflect projectiles at the cost of reduced intregrity.</span>")
S.change_to(/obj/structure/blob/shield/reflective, src)
else
createSpecial(15, /obj/structure/blob/shield, 0, 0, T)
/mob/camera/blob/verb/create_resource()
set category = "Blob"
@@ -359,7 +369,7 @@
to_chat(src, "<b>You can expand, which will attack people, damage objects, or place a Normal Blob if the tile is clear.</b>")
to_chat(src, "<i>Normal Blobs</i> will expand your reach and can be upgraded into special blobs that perform certain functions.")
to_chat(src, "<b>You can upgrade normal blobs into the following types of blob:</b>")
to_chat(src, "<i>Shield Blobs</i> are strong and expensive blobs which take more damage. In additon, they are fireproof and can block air, use these to protect yourself from station fires.")
to_chat(src, "<i>Shield Blobs</i> are strong and expensive blobs which take more damage. In additon, they are fireproof and can block air, use these to protect yourself from station fires. Upgrading them again will result in a reflective blob, capable of reflecting most projectiles at the cost of the strong blob's extra health.")
to_chat(src, "<i>Resource Blobs</i> are blobs which produce more resources for you, build as many of these as possible to consume the station. This type of blob must be placed near node blobs or your core to work.")
to_chat(src, "<i>Factory Blobs</i> are blobs that spawn blob spores which will attack nearby enemies. This type of blob must be placed near node blobs or your core to work.")
to_chat(src, "<i>Blobbernauts</i> can be produced from factories for a cost, and are hard to kill, powerful, and moderately smart. The factory used to create one will become fragile and briefly unable to produce spores.")
@@ -128,7 +128,7 @@
/mob/living/carbon/human/ShowAsPaleExamine()
// Check for albino, as per human/examine.dm's check.
if(skin_tone == "albino")
if(dna.species.use_skintones && skin_tone == "albino")
return TRUE
return ..() // Return vamp check
@@ -183,7 +183,7 @@
BuyPower(new /datum/action/bloodsucker/masquerade)
BuyPower(new /datum/action/bloodsucker/veil)
// Traits
for (var/T in defaultTraits)
for(var/T in defaultTraits)
ADD_TRAIT(owner.current, T, "bloodsucker")
if(HAS_TRAIT(owner.current, TRAIT_TOXINLOVER)) //No slime bonuses here, no thank you
had_toxlover = TRUE
@@ -200,10 +200,10 @@
var/mob/living/carbon/human/H = owner.current
var/datum/species/S = H.dna.species
// Make Changes
S.brutemod *= 0.5 // <-------------------- Start small, but burn mod increases based on rank!
S.coldmod = 0
S.stunmod *= 0.25
S.siemens_coeff *= 0.75 //base electrocution coefficient 1
H.physiology.brute_mod *= 0.8 // <-------------------- Start small, but burn mod increases based on rank!
H.physiology.cold_mod = 0
H.physiology.stun_mod *= 0.35
H.physiology.siemens_coeff *= 0.75 //base electrocution coefficient 1
//S.heatmod += 0.5 // Heat shouldn't affect. Only Fire.
//S.punchstunthreshold = 8 //damage at which punches from this race will stun 9
S.punchdamagelow += 1 //lowest possible punch damage 0
@@ -319,12 +319,10 @@ datum/antagonist/bloodsucker/proc/SpendRank()
if(ishuman(owner.current))
var/mob/living/carbon/human/H = owner.current
var/datum/species/S = H.dna.species
S.burnmod *= 0.025 // Slightly more burn damage
S.stunmod *= 0.95 // Slightly less stun time.
S.punchdamagelow += 0.5
S.punchdamagehigh += 0.5 // NOTE: This affects the hitting power of Brawn.
// More Health
owner.current.setMaxHealth(owner.current.maxHealth + 5)
owner.current.setMaxHealth(owner.current.maxHealth + 10)
// Vamp Stats
regenRate += 0.05 // Points of brute healed (starts at 0.3)
feedAmount += 2 // Increase how quickly I munch down vics (15)
@@ -275,7 +275,7 @@
// All done!
if(convert_progress <= 0)
// FAIL: Can't be Vassal
if(!SSticker.mode.can_make_vassal(target, user, display_warning=FALSE) && HAS_TRAIT(target, TRAIT_MINDSHIELD)) // If I'm an unconvertable Antag ONLY
if(!SSticker.mode.can_make_vassal(target, user, display_warning=FALSE) || HAS_TRAIT(target, TRAIT_MINDSHIELD)) // If I'm an unconvertable Antag ONLY
to_chat(user, "<span class='danger'>[target] doesn't respond to your persuasion. It doesn't appear they can be converted to follow you, they either have a mindshield or their external loyalties are too difficult for you to break.<i>\[ALT+click to release\]</span>")
convert_progress ++ // Pop it back up some. Avoids wasting Blood on a lost cause.
// SUCCESS: All done!
@@ -345,3 +345,8 @@
if(!power_amount)
power_amount = -(CLOCKCULT_POWER_UNIT*0.02)
return ..()
// Winter coat
/obj/item/clothing/suit/hooded/wintercoat/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) //four sheets of metal
return list("operation_time" = 30, "new_obj_type" = /obj/item/clothing/suit/hooded/wintercoat/ratvar, "power_cost" = POWER_METAL * 4, "spawn_dir" = SOUTH)
@@ -139,7 +139,7 @@
var/new_thing_type = fabrication_values["new_obj_type"]
if(isturf(target)) //if our target is a turf, we're just going to ChangeTurf it and assume it'll work out.
var/turf/T = target
T.ChangeTurf(new_thing_type)
T.ChangeTurf(new_thing_type, flags = CHANGETURF_INHERIT_AIR)
else
if(new_thing_type)
if(fabrication_values["dir_in_new"])
@@ -59,7 +59,7 @@
if(anchored)
T.PlaceOnTop(/turf/closed/wall/clockwork)
else
T.PlaceOnTop(/turf/open/floor/clockwork)
T.PlaceOnTop(/turf/open/floor/clockwork, flags = CHANGETURF_INHERIT_AIR)
new /obj/structure/falsewall/brass(T)
qdel(src)
else
@@ -585,6 +585,12 @@
new /obj/item/stack/sheet/runed_metal(T,quantity)
to_chat(user, "<span class='warning'>A dark cloud emanates from you hand and swirls around the plasteel, transforming it into runed metal!</span>")
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
if(istype(target, /obj/item/clothing/suit/hooded/wintercoat) && target.type != /obj/item/clothing/suit/hooded/wintercoat/narsie)
if (do_after(user,30,target=target))
new /obj/item/clothing/suit/hooded/wintercoat/narsie(T)
qdel(target)
to_chat(user, "<span class='warning'>A dark cloud emanates from you hand and swirls around [target], transforming it into a narsian winter coat!</span>")
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
else if(istype(target,/mob/living/silicon/robot))
var/mob/living/silicon/robot/candidate = target
if(candidate.mmi)
@@ -239,9 +239,9 @@
var/turf/T = safepick(validturfs)
if(T)
if(istype(T, /turf/open/floor/plating))
T.PlaceOnTop(/turf/open/floor/engine/cult)
T.PlaceOnTop(/turf/open/floor/engine/cult, flags = CHANGETURF_INHERIT_AIR)
else
T.ChangeTurf(/turf/open/floor/engine/cult)
T.ChangeTurf(/turf/open/floor/engine/cult, flags = CHANGETURF_INHERIT_AIR)
else
var/turf/open/floor/engine/cult/F = safepick(cultturfs)
if(F)
@@ -5,6 +5,14 @@
antagpanel_category = "ClownOp"
nukeop_outfit = /datum/outfit/syndicate/clownop
/datum/antagonist/nukeop/clownop/on_gain()
. = ..()
ADD_TRAIT(owner, TRAIT_CLOWN_MENTALITY, NUKEOP_ANTAGONIST)
/datum/antagonist/nukeop/clownop/on_removal()
REMOVE_TRAIT(owner, TRAIT_CLOWN_MENTALITY, NUKEOP_ANTAGONIST)
return ..()
/datum/antagonist/nukeop/leader/clownop
name = "Clown Operative Leader"
roundend_category = "clown operatives"
@@ -76,9 +76,10 @@ GLOBAL_VAR_INIT(war_declared, FALSE)
CONFIG_SET(number/shuttle_refuel_delay, max(CONFIG_GET(number/shuttle_refuel_delay), CHALLENGE_SHUTTLE_DELAY))
if(istype(SSticker.mode, /datum/game_mode/dynamic))
var/datum/game_mode/dynamic/mode = SSticker.mode
var/threat_spent = CONFIG_GET(number/dynamic_warops_cost)
mode.spend_threat(threat_spent)
mode.log_threat("Nuke ops spent [threat_spent] on war ops.")
if(!(mode.storyteller.flags & WAROPS_ALWAYS_ALLOWED))
var/threat_spent = CONFIG_GET(number/dynamic_warops_cost)
mode.spend_threat(threat_spent)
mode.log_threat("Nuke ops spent [threat_spent] on war ops.")
SSblackbox.record_feedback("amount", "nuclear_challenge_mode", 1)
qdel(src)
@@ -101,12 +102,13 @@ GLOBAL_VAR_INIT(war_declared, FALSE)
return FALSE
if(istype(SSticker.mode, /datum/game_mode/dynamic))
var/datum/game_mode/dynamic/mode = SSticker.mode
if(mode.threat_level < CONFIG_GET(number/dynamic_warops_requirement))
to_chat(user, "Due to the dynamic space in which the station resides, you are too deep into Nanotrasen territory to reasonably go loud.")
return FALSE
else if(mode.threat < CONFIG_GET(number/dynamic_warops_cost))
to_chat(user, "Due to recent threats on the station, Nanotrasen is looking too closely for a war declaration to be wise.")
return FALSE
if(!(mode.storyteller.flags & WAROPS_ALWAYS_ALLOWED))
if(mode.threat_level < CONFIG_GET(number/dynamic_warops_requirement))
to_chat(user, "Due to the dynamic space in which the station resides, you are too deep into Nanotrasen territory to reasonably go loud.")
return FALSE
else if(mode.threat < CONFIG_GET(number/dynamic_warops_cost))
to_chat(user, "Due to recent threats on the station, Nanotrasen is looking too closely for a war declaration to be wise.")
return FALSE
return TRUE
/obj/item/nuclear_challenge/clownops
@@ -80,6 +80,8 @@
if(istype(SSticker.mode,/datum/game_mode/dynamic))
mode = SSticker.mode
is_dynamic = TRUE
if(mode.storyteller.flags & NO_ASSASSIN)
is_hijacker = FALSE
if(GLOB.joined_player_list.len>=GLOB.dynamic_high_pop_limit)
is_hijacker = (prob(10) && mode.threat_level > CONFIG_GET(number/dynamic_hijack_high_population_requirement))
else
@@ -180,7 +182,7 @@
destroy_objective.owner = owner
destroy_objective.find_target()
add_objective(destroy_objective)
else if(prob(30))
else if(prob(30) || (mode.storyteller.flags & NO_ASSASSIN))
var/datum/objective/maroon/maroon_objective = new
maroon_objective.owner = owner
maroon_objective.find_target()
+2 -2
View File
@@ -39,7 +39,7 @@
if(flash)
add_overlay(flashing_overlay)
attached_overlays += flashing_overlay
addtimer(CALLBACK(src, .proc/update_icon), 5)
addtimer(CALLBACK(src, /atom/.proc/update_icon), 5)
if(holder)
holder.update_icon()
@@ -308,7 +308,7 @@
else if(flash)
icon_state = "flashshield_flash"
item_state = "flashshield_flash"
addtimer(CALLBACK(src, .proc/update_icon), 5)
addtimer(CALLBACK(src, /atom/.proc/update_icon), 5)
if(holder)
holder.update_icon()
@@ -57,10 +57,10 @@
if(item.parent)
var/static/pipenetwarnings = 10
if(pipenetwarnings > 0)
warning("build_pipeline(): [item.type] added to a pipenet while still having one. (pipes leading to the same spot stacking in one turf) Nearby: ([item.x], [item.y], [item.z])")
log_mapping("build_pipeline(): [item.type] added to a pipenet while still having one. (pipes leading to the same spot stacking in one turf) Nearby: ([item.x], [item.y], [item.z]).")
pipenetwarnings -= 1
if(pipenetwarnings == 0)
warning("build_pipeline(): further messages about pipenets will be suppressed")
log_mapping("build_pipeline(): further messages about pipenets will be suppressed")
members += item
possible_expansions += item
@@ -154,11 +154,6 @@
var/partial_heat_capacity = total_heat_capacity*(share_volume/air.volume)
var/target_temperature
var/target_heat_capacity
// first calculate heat from radiation. there's an implied "* 1 tick" here.
// 0.05 magic multiplicand is, first, 0.1 deciseconds; second, half of the radiation's going right back into the gas.
var/share_constant = STEFANBOLTZMANN*(share_volume**(2/3))*0.05
// Minimizing temp to 4 billion is mostly to prevent -infinity temperatures.
var/heat = share_constant*(min(air.temperature,4000000000)**4)
if(isopenturf(target))
@@ -170,8 +165,8 @@
if((modeled_location.heat_capacity>0) && (partial_heat_capacity>0))
var/delta_temperature = air.temperature - target_temperature
heat -= share_constant*(min(target_temperature,4000000000)**4)
heat += thermal_conductivity*delta_temperature* \
var/heat = thermal_conductivity*delta_temperature* \
(partial_heat_capacity*target_heat_capacity/(partial_heat_capacity+target_heat_capacity))
air.temperature -= heat/total_heat_capacity
@@ -188,8 +183,7 @@
var/sharer_temperature_delta = 0
if((sharer_heat_capacity>0) && (partial_heat_capacity>0))
heat -= share_constant*(min(target_temperature,4000000000)**4)
heat += thermal_conductivity*delta_temperature* \
var/heat = thermal_conductivity*delta_temperature* \
(partial_heat_capacity*sharer_heat_capacity/(partial_heat_capacity+sharer_heat_capacity))
self_temperature_delta = -heat/total_heat_capacity
@@ -205,12 +199,10 @@
if((target.heat_capacity>0) && (partial_heat_capacity>0))
var/delta_temperature = air.temperature - target.temperature
heat -= share_constant*(min(target.temperature,4000000000)**4)
heat += thermal_conductivity*delta_temperature* \
var/heat = thermal_conductivity*delta_temperature* \
(partial_heat_capacity*target.heat_capacity/(partial_heat_capacity+target.heat_capacity))
air.temperature -= heat/total_heat_capacity
air.temperature = CLAMP(air.temperature,TCMB,INFINITY) // i have no idea why TCMB needs to be the min but i ain't changing it
update = TRUE
/datum/pipeline/proc/return_air()
@@ -56,7 +56,7 @@
pixel_y = (new_layer - PIPING_LAYER_DEFAULT) * PIPING_LAYER_P_Y
/obj/machinery/meter/process_atmos()
if(!target)
if(!(target?.flags_1 & INITIALIZED_1))
icon_state = "meterX"
return 0
@@ -26,7 +26,9 @@
var/turf/T = loc
if(istype(T))
if(T.blocks_air)
if(islava(T))
environment_temperature = 5000
else if(T.blocks_air)
environment_temperature = T.temperature
else
var/turf/open/OT = T
+2 -1
View File
@@ -29,6 +29,7 @@
var/show_flavour = TRUE
var/banType = "lavaland"
var/ghost_usable = TRUE
var/skip_reentry_check = FALSE //Skips the ghost role blacklist time for people who ghost/suicide/cryo
//ATTACK GHOST IGNORING PARENT RETURN VALUE
/obj/effect/mob_spawn/attack_ghost(mob/user, latejoinercalling)
@@ -44,7 +45,7 @@
return
if(isobserver(user))
var/mob/dead/observer/O = user
if(!O.can_reenter_round())
if(!O.can_reenter_round() && !skip_reentry_check)
return FALSE
var/ghost_role = alert(latejoinercalling ? "Latejoin as [mob_name]? (This is a ghost role, and as such, it's very likely to be off-station.)" : "Become [mob_name]? (Warning, You can no longer be cloned!)",,"Yes","No")
if(ghost_role == "No" || !loc)
+3 -3
View File
@@ -22,9 +22,9 @@
if(istype(object,/turf) && left_click && !alt_click && !ctrl_click)
var/turf/T = object
if(isspaceturf(object))
T.PlaceOnTop(/turf/open/floor/plating)
T.PlaceOnTop(/turf/open/floor/plating, flags = CHANGETURF_INHERIT_AIR)
else if(isplatingturf(object))
T.PlaceOnTop(/turf/open/floor/plasteel)
T.PlaceOnTop(/turf/open/floor/plasteel, flags = CHANGETURF_INHERIT_AIR)
else if(isfloorturf(object))
T.PlaceOnTop(/turf/closed/wall)
else if(iswallturf(object))
@@ -35,7 +35,7 @@
log_admin("Build Mode: [key_name(c)] deleted [object] at [AREACOORD(object)]")
if(isturf(object))
var/turf/T = object
T.ScrapeAway()
T.ScrapeAway(flags = CHANGETURF_INHERIT_AIR)
else if(isobj(object))
qdel(object)
return
+1 -1
View File
@@ -29,7 +29,7 @@
name = linked_pod.name
. = ..()
/mob/living/simple_animal/pet/gondola/gondolapod/proc/update_icon()
/mob/living/simple_animal/pet/gondola/gondolapod/update_icon_state()
if(opened)
icon_state = "gondolapod_open"
else
+4 -5
View File
@@ -13,17 +13,16 @@
//////////////////// Paperwork and Writing Supplies //////////////////////////
//////////////////////////////////////////////////////////////////////////////
/* I did it Kevin
/datum/supply_pack/misc/abandonedcrate
name = "Abandoned Crate"
desc = "Someone keeps finding these locked crates out in the boonies. How about you take a crack at it, we've had our fill. WARNING: EXPLOSIVE"
name = "Loot Box"
desc = "Try your luck with these highly secure loot boxes! Solve the lock, win great prizes! WARNING: EXPLOSIVE FAILURE."
contraband = TRUE
cost = 12800
cost = 15000
contains = list(/obj/structure/closet/crate/secure/loot)
crate_name = "abandoned crate"
crate_type = /obj/structure/closet/crate/large
dangerous = TRUE
*/
/datum/supply_pack/misc/artsupply
name = "Art Supplies"
desc = "Make some happy little accidents with six canvasses, two easels, two boxes of crayons, and a rainbow crayon!"
+5 -1
View File
@@ -79,4 +79,8 @@
var/client_keysend_amount = 0
var/next_keysend_reset = 0
var/next_keysend_trip_reset = 0
var/keysend_tripped = FALSE
var/keysend_tripped = FALSE
// stops players from coming back through ghost/midround roles after suicide/cryo
// for a duration set by CONFIG_GET(number/suicide_reenter_round_timer) and CONFIG_GET(number/roundstart_suicide_time_limit)
var/reenter_round_timeout = 0
+83 -10
View File
@@ -103,6 +103,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
"legs" = "Plantigrade",
"insect_wings" = "Plain",
"insect_fluff" = "None",
"insect_markings" = "None",
"mcolor2" = "FFF",
"mcolor3" = "FFF",
"mam_body_markings" = "Plain",
@@ -194,6 +195,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/auto_fit_viewport = TRUE
var/uplink_spawn_loc = UPLINK_PDA
var/sprint_spacebar = FALSE
var/sprint_toggle = FALSE
var/list/exp = list()
var/list/menuoptions
@@ -244,6 +248,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<a href='?_src_=prefs;preference=tab;tab=2' [current_tab == 2 ? "class='linkOn'" : ""]>Character Appearance</a>"
dat += "<a href='?_src_=prefs;preference=tab;tab=3' [current_tab == 3 ? "class='linkOn'" : ""]>Loadout</a>"
dat += "<a href='?_src_=prefs;preference=tab;tab=1' [current_tab == 1 ? "class='linkOn'" : ""]>Game Preferences</a>"
dat += "<a href='?_src_=prefs;preference=tab;tab=4' [current_tab == 4 ? "class='linkOn'" : ""]>Content Preferences</a>"
if(!path)
dat += "<div class='notice'>Please create an account to save your preferences</div>"
@@ -620,6 +625,19 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<a style='display:block;width:100px' href='?_src_=prefs;preference=taur;task=input'>[features["taur"]]</a>"
if("insect_markings" in pref_species.default_features)
if(!mutant_category)
dat += APPEARANCE_CATEGORY_COLUMN
dat += "<h3>Insect markings</h3>"
dat += "<a href='?_src_=prefs;preference=insect_markings;task=input'>[features["insect_markings"]]</a><BR>"
mutant_category++
if(mutant_category >= MAX_MUTANT_ROWS)
dat += "</td>"
mutant_category = 0
mutant_category++
if(mutant_category >= MAX_MUTANT_ROWS)
dat += "</td>"
@@ -707,13 +725,13 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<table><tr><td width='340px' height='300px' valign='top'>"
dat += "<h2>Clothing & Equipment</h2>"
dat += "<b>Underwear:</b><a style='display:block;width:100px' href ='?_src_=prefs;preference=underwear;task=input'>[underwear]</a>"
if(UNDIE_COLORABLE(GLOB.underwear_list[underwear]))
if(GLOB.underwear_list[underwear]?.has_color)
dat += "<b>Underwear Color:</b> <span style='border:1px solid #161616; background-color: #[undie_color];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=undie_color;task=input'>Change</a><BR>"
dat += "<b>Undershirt:</b><a style='display:block;width:100px' href ='?_src_=prefs;preference=undershirt;task=input'>[undershirt]</a>"
if(UNDIE_COLORABLE(GLOB.undershirt_list[undershirt]))
if(GLOB.undershirt_list[undershirt]?.has_color)
dat += "<b>Undershirt Color:</b> <span style='border:1px solid #161616; background-color: #[shirt_color];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=shirt_color;task=input'>Change</a><BR>"
dat += "<b>Socks:</b><a style='display:block;width:100px' href ='?_src_=prefs;preference=socks;task=input'>[socks]</a>"
if(UNDIE_COLORABLE(GLOB.socks_list[socks]))
if(GLOB.socks_list[socks]?.has_color)
dat += "<b>Socks Color:</b> <span style='border:1px solid #161616; background-color: #[socks_color];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=socks_color;task=input'>Change</a><BR>"
dat += "<b>Backpack:</b><a style='display:block;width:100px' href ='?_src_=prefs;preference=bag;task=input'>[backbag]</a>"
dat += "<b>Jumpsuit:</b><BR><a href ='?_src_=prefs;preference=suit;task=input'>[jumpsuit_style]</a><BR>"
@@ -820,13 +838,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat +="<td width='300px' height='300px' valign='top'>"
dat += "<h2>Citadel Preferences</h2>" //Because fuck me if preferences can't be fucking modularized and expected to update in a reasonable timeframe.
dat += "<b>Arousal:</b><a href='?_src_=prefs;preference=arousable'>[arousable == TRUE ? "Enabled" : "Disabled"]</a><BR>"
dat += "<b>Voracious MediHound sleepers:</b> <a href='?_src_=prefs;preference=hound_sleeper'>[(cit_toggles & MEDIHOUND_SLEEPER) ? "Yes" : "No"]</a><br>"
dat += "<b>Hear Vore Sounds:</b> <a href='?_src_=prefs;preference=toggleeatingnoise'>[(cit_toggles & EATING_NOISES) ? "Yes" : "No"]</a><br>"
dat += "<b>Hear Vore Digestion Sounds:</b> <a href='?_src_=prefs;preference=toggledigestionnoise'>[(cit_toggles & DIGESTION_NOISES) ? "Yes" : "No"]</a><br>"
dat += "<b>Lewdchem:</b><a href='?_src_=prefs;preference=lewdchem'>[lewdchem == TRUE ? "Enabled" : "Disabled"]</a><BR>"
dat += "<b>Widescreen:</b> <a href='?_src_=prefs;preference=widescreenpref'>[widescreenpref ? "Enabled ([CONFIG_GET(string/default_view)])" : "Disabled (15x15)"]</a><br>"
dat += "<b>Auto stand:</b> <a href='?_src_=prefs;preference=autostand'>[autostand ? "Enabled" : "Disabled"]</a><br>"
dat += "<b>Auto OOC:</b> <a href='?_src_=prefs;preference=auto_ooc'>[auto_ooc ? "Enabled" : "Disabled"]</a><br>"
dat += "<b>Screen Shake:</b> <a href='?_src_=prefs;preference=screenshake'>[(screenshake==100) ? "Full" : ((screenshake==0) ? "None" : "[screenshake]")]</a><br>"
if (user && user.client && !user.client.prefs.screenshake==0)
dat += "<b>Damage Screen Shake:</b> <a href='?_src_=prefs;preference=damagescreenshake'>[(damagescreenshake==1) ? "On" : ((damagescreenshake==0) ? "Off" : "Only when down")]</a><br>"
@@ -878,6 +892,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "</a><br>"
dat += "<b>Ambient Occlusion:</b> <a href='?_src_=prefs;preference=ambientocclusion'>[ambientocclusion ? "Enabled" : "Disabled"]</a><br>"
dat += "<b>Fit Viewport:</b> <a href='?_src_=prefs;preference=auto_fit_viewport'>[auto_fit_viewport ? "Auto" : "Manual"]</a><br>"
dat += "<b>Sprint Key:</b> <a href='?_src_=prefs;preference=sprint_key'>[sprint_spacebar ? "Space" : "Shift"]</a><br>"
dat += "<b>Toggle Sprint:</b> <a href='?_src_=prefs;preference=sprint_toggle'>[sprint_toggle ? "Enabled" : "Disabled"]</a><br>"
if (CONFIG_GET(flag/maprotation) && CONFIG_GET(flag/tgstyle_maprotation))
var/p_map = preferred_map
@@ -977,6 +993,26 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "</font>"
dat += "</td><td><font size=2><i>[gear.description]</i></font></td></tr>"
dat += "</table>"
if(4) // Content preferences
dat += "<table><tr><td width='340px' height='300px' valign='top'>"
dat += "<h2>Fetish content prefs</h2>"
dat += "<b>Arousal:</b><a href='?_src_=prefs;preference=arousable'>[arousable == TRUE ? "Enabled" : "Disabled"]</a><BR>"
dat += "<b>Voracious MediHound sleepers:</b> <a href='?_src_=prefs;preference=hound_sleeper'>[(cit_toggles & MEDIHOUND_SLEEPER) ? "Yes" : "No"]</a><br>"
dat += "<b>Hear Vore Sounds:</b> <a href='?_src_=prefs;preference=toggleeatingnoise'>[(cit_toggles & EATING_NOISES) ? "Yes" : "No"]</a><br>"
dat += "<b>Hear Vore Digestion Sounds:</b> <a href='?_src_=prefs;preference=toggledigestionnoise'>[(cit_toggles & DIGESTION_NOISES) ? "Yes" : "No"]</a><br>"
dat += "<b>Forced Feminization:</b> <a href='?_src_=prefs;preference=feminization'>[(cit_toggles & FORCED_FEM) ? "Allowed" : "Disallowed"]</a><br>"
dat += "<b>Forced Masculinization:</b> <a href='?_src_=prefs;preference=masculinization'>[(cit_toggles & FORCED_MASC) ? "Allowed" : "Disallowed"]</a><br>"
dat += "<b>Lewd Hypno:</b> <a href='?_src_=prefs;preference=hypno'>[(cit_toggles & HYPNO) ? "Allowed" : "Disallowed"]</a><br>"
dat += "</td>"
dat +="<td width='300px' height='300px' valign='top'>"
dat += "<h2>Other content prefs</h2>"
dat += "<b>Breast Enlargement:</b> <a href='?_src_=prefs;preference=breast_enlargement'>[(cit_toggles & BREAST_ENLARGEMENT) ? "Allowed" : "Disallowed"]</a><br>"
dat += "<b>Penis Enlargement:</b> <a href='?_src_=prefs;preference=penis_enlargement'>[(cit_toggles & PENIS_ENLARGEMENT) ? "Allowed" : "Disallowed"]</a><br>"
dat += "<b>Hypno:</b> <a href='?_src_=prefs;preference=never_hypno'>[(cit_toggles & NEVER_HYPNO) ? "Disallowed" : "Allowed"]</a><br>"
dat += "<b>Aphrodisiacs:</b> <a href='?_src_=prefs;preference=aphro'>[(cit_toggles & NO_APHRO) ? "Disallowed" : "Allowed"]</a><br>"
dat += "<b>Ass Slapping:</b> <a href='?_src_=prefs;preference=ass_slap'>[(cit_toggles & NO_ASS_SLAP) ? "Disallowed" : "Allowed"]</a><br>"
dat += "<br>"
dat += "<hr><center>"
@@ -1743,6 +1779,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(new_insect_fluff)
features["insect_fluff"] = new_insect_fluff
if("insect_markings")
var/new_insect_markings
new_insect_markings = input(user, "Choose your character's markings:", "Character Preference") as null|anything in GLOB.insect_markings_list
if(new_insect_markings)
features["insect_markings"] = new_insect_markings
if("s_tone")
var/new_s_tone = input(user, "Choose your character's skin-tone:", "Character Preference") as null|anything in GLOB.skin_tones
if(new_s_tone)
@@ -2016,8 +2058,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
features["genitals_use_skintone"] = !features["genitals_use_skintone"]
if("arousable")
arousable = !arousable
if("lewdchem")
lewdchem = !lewdchem
if("has_cock")
features["has_cock"] = !features["has_cock"]
if(features["has_cock"] == FALSE)
@@ -2049,6 +2089,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
user.client.change_view(CONFIG_GET(string/default_view))
if("autostand")
autostand = !autostand
if("auto_ooc")
auto_ooc = !auto_ooc
if ("screenshake")
var/desiredshake = input(user, "Set the amount of screenshake you want. \n(0 = disabled, 100 = full, 200 = maximum.)", "Character Preference", screenshake) as null|num
if (!isnull(desiredshake))
@@ -2164,6 +2206,31 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("toggledigestionnoise")
cit_toggles ^= DIGESTION_NOISES
if("breast_enlargement")
cit_toggles ^= BREAST_ENLARGEMENT
if("penis_enlargement")
cit_toggles ^= PENIS_ENLARGEMENT
if("feminization")
cit_toggles ^= FORCED_FEM
if("masculinization")
cit_toggles ^= FORCED_MASC
if("hypno")
cit_toggles ^= HYPNO
if("never_hypno")
cit_toggles ^= NEVER_HYPNO
if("aphro")
cit_toggles ^= NO_APHRO
if("ass_slap")
cit_toggles ^= NO_ASS_SLAP
//END CITADEL EDIT
if("ambientocclusion")
@@ -2177,6 +2244,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(auto_fit_viewport && parent)
parent.fit_viewport()
if("sprint_key")
sprint_spacebar = !sprint_spacebar
if("sprint_toggle")
sprint_toggle = !sprint_toggle
if("save")
save_preferences()
save_character()
+31 -6
View File
@@ -167,6 +167,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["parallax"] >> parallax
S["ambientocclusion"] >> ambientocclusion
S["auto_fit_viewport"] >> auto_fit_viewport
S["sprint_spacebar"] >> sprint_spacebar
S["sprint_toggle"] >> sprint_toggle
S["menuoptions"] >> menuoptions
S["enable_tips"] >> enable_tips
S["tip_delay"] >> tip_delay
@@ -181,8 +183,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["widescreenpref"] >> widescreenpref
S["autostand"] >> autostand
S["cit_toggles"] >> cit_toggles
S["lewdchem"] >> lewdchem
S["preferred_chaos"] >> preferred_chaos
S["auto_ooc"] >> auto_ooc
//try to fix any outdated data if necessary
@@ -204,6 +206,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
parallax = sanitize_integer(parallax, PARALLAX_INSANE, PARALLAX_DISABLE, null)
ambientocclusion = sanitize_integer(ambientocclusion, 0, 1, initial(ambientocclusion))
auto_fit_viewport = sanitize_integer(auto_fit_viewport, 0, 1, initial(auto_fit_viewport))
sprint_spacebar = sanitize_integer(sprint_spacebar, 0, 1, initial(sprint_spacebar))
sprint_toggle = sanitize_integer(sprint_toggle, 0, 1, initial(sprint_toggle))
ghost_form = sanitize_inlist(ghost_form, GLOB.ghost_forms, initial(ghost_form))
ghost_orbit = sanitize_inlist(ghost_orbit, GLOB.ghost_orbits, initial(ghost_orbit))
ghost_accs = sanitize_inlist(ghost_accs, GLOB.ghost_accs_options, GHOST_ACCS_DEFAULT_OPTION)
@@ -219,7 +223,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
widescreenpref = sanitize_integer(widescreenpref, 0, 1, initial(widescreenpref))
autostand = sanitize_integer(autostand, 0, 1, initial(autostand))
cit_toggles = sanitize_integer(cit_toggles, 0, 65535, initial(cit_toggles))
auto_ooc = sanitize_integer(auto_ooc, 0, 1, initial(auto_ooc))
return 1
@@ -264,6 +268,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["parallax"], parallax)
WRITE_FILE(S["ambientocclusion"], ambientocclusion)
WRITE_FILE(S["auto_fit_viewport"], auto_fit_viewport)
WRITE_FILE(S["sprint_spacebar"], sprint_spacebar)
WRITE_FILE(S["sprint_toggle"], sprint_toggle)
WRITE_FILE(S["menuoptions"], menuoptions)
WRITE_FILE(S["enable_tips"], enable_tips)
WRITE_FILE(S["tip_delay"], tip_delay)
@@ -278,8 +284,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["widescreenpref"], widescreenpref)
WRITE_FILE(S["autostand"], autostand)
WRITE_FILE(S["cit_toggles"], cit_toggles)
WRITE_FILE(S["lewdchem"], lewdchem)
WRITE_FILE(S["preferred_chaos"], preferred_chaos)
WRITE_FILE(S["auto_ooc"], auto_ooc)
return 1
@@ -366,9 +372,10 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["feature_lizard_legs"] >> features["legs"]
S["feature_human_tail"] >> features["tail_human"]
S["feature_human_ears"] >> features["ears"]
S["feature_deco_wings"] >> features["deco_wings"]
S["feature_insect_wings"] >> features["insect_wings"]
S["feature_deco_wings"] >> features["deco_wings"]
S["feature_insect_fluff"] >> features["insect_fluff"]
S["feature_insect_markings"] >> features["insect_markings"]
//Custom names
for(var/custom_name_id in GLOB.preferences_custom_names)
@@ -503,9 +510,10 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
features["spines"] = sanitize_inlist(features["spines"], GLOB.spines_list)
features["body_markings"] = sanitize_inlist(features["body_markings"], GLOB.body_markings_list)
features["feature_lizard_legs"] = sanitize_inlist(features["legs"], GLOB.legs_list)
features["insect_wings"] = sanitize_inlist(features["insect_wings"], GLOB.insect_wings_list)
features["deco_wings"] = sanitize_inlist(features["deco_wings"], GLOB.deco_wings_list, "None")
features["insect_fluff"] = sanitize_inlist(features["insect_fluff"], GLOB.insect_fluffs_list)
features["insect_markings"] = sanitize_inlist(features["insect_markings"], GLOB.insect_markings_list, "None")
features["insect_wings"] = sanitize_inlist(features["insect_wings"], GLOB.insect_wings_list)
joblessrole = sanitize_integer(joblessrole, 1, 3, initial(joblessrole))
//Validate job prefs
@@ -515,6 +523,21 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
all_quirks = SANITIZE_LIST(all_quirks)
for(var/V in all_quirks) // quirk migration
switch(V)
if("Acute hepatic pharmacokinesis")
DISABLE_BITFIELD(cit_toggles, PENIS_ENLARGEMENT)
DISABLE_BITFIELD(cit_toggles, BREAST_ENLARGEMENT)
ENABLE_BITFIELD(cit_toggles,FORCED_FEM)
ENABLE_BITFIELD(cit_toggles,FORCED_MASC)
all_quirks -= V
if("Crocin Immunity")
ENABLE_BITFIELD(cit_toggles,NO_APHRO)
all_quirks -= V
if("Buns of Steel")
ENABLE_BITFIELD(cit_toggles,NO_ASS_SLAP)
all_quirks -= V
cit_character_pref_load(S)
return 1
@@ -570,11 +593,13 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["feature_lizard_spines"] , features["spines"])
WRITE_FILE(S["feature_lizard_body_markings"] , features["body_markings"])
WRITE_FILE(S["feature_lizard_legs"] , features["legs"])
WRITE_FILE(S["feature_insect_wings"] , features["insect_wings"])
WRITE_FILE(S["feature_deco_wings"] , features["deco_wings"])
WRITE_FILE(S["feature_insect_wings"] , features["insect_wings"])
WRITE_FILE(S["feature_insect_fluff"] , features["insect_fluff"])
WRITE_FILE(S["feature_insect_markings"] , features["insect_markings"])
WRITE_FILE(S["feature_meat"] , features["meat_type"])
//Custom names
for(var/custom_name_id in GLOB.preferences_custom_names)
var/savefile_slot_name = custom_name_id + "_name" //TODO remove this
+80 -1
View File
@@ -22,7 +22,6 @@
var/cooldown = 0
var/obj/item/flashlight/F = null
var/can_flashlight = 0
var/scan_reagents = 0 //Can the wearer see reagents while it's equipped?
var/blocks_shove_knockdown = FALSE //Whether wearing the clothing item blocks the ability for shove to knock down.
@@ -47,6 +46,17 @@
//Add a "exclude" string to do the opposite, making it only only species listed that can't wear it.
//You append this to clothing objects.
//Polychrome stuff:
var/hasprimary = FALSE //These vars allow you to choose which overlays a clothing has
var/hassecondary = FALSE
var/hastertiary = FALSE
var/primary_color = "#FFFFFF" //RGB in hexcode
var/secondary_color = "#FFFFFF"
var/tertiary_color = "#808080"
//No idea what this is but eh -tori
var/force_alternate_icon = FALSE
/obj/item/clothing/Initialize()
. = ..()
@@ -54,6 +64,8 @@
actions_types += /datum/action/item_action/toggle_voice_box
if(ispath(pocket_storage_component_path))
LoadComponent(pocket_storage_component_path)
if(hasprimary | hassecondary | hastertiary) //Checks if polychrome is enabled
update_icon() //Applies the overlays and default colors onto the clothes on spawn.
/obj/item/clothing/MouseDrop(atom/over_object)
. = ..()
@@ -138,6 +150,8 @@
how_cool_are_your_threads += "Adding or removing items from [src] makes no noise.\n"
how_cool_are_your_threads += "</span>"
. += how_cool_are_your_threads.Join()
if(hasprimary | hassecondary | hastertiary) //Checks if polychrome is enabled
. += "<span class='notice'>Alt-click to recolor it.</span>"
/obj/item/clothing/obj_break(damage_flag)
if(!damaged_clothes)
@@ -260,6 +274,56 @@ BLIND // can't see anything
remove_accessory(user)
else
rolldown()
// Polychrome stuff:
if(hasprimary | hassecondary | hastertiary)
var/choice = input(user,"polychromic thread options", "Clothing Recolor") as null|anything in list("[hasprimary ? "Primary Color" : ""]", "[hassecondary ? "Secondary Color" : ""]", "[hastertiary ? "Tertiary Color" : ""]") //generates a list depending on the enabled overlays
switch(choice) //Lets the list's options actually lead to something
if("Primary Color")
var/primary_color_input = input(usr,"","Choose Primary Color",primary_color) as color|null //color input menu, the "|null" adds a cancel button to it.
if(primary_color_input) //Checks if the color selected is NULL, rejects it if it is NULL.
primary_color = sanitize_hexcolor(primary_color_input, desired_format=6, include_crunch=1) //formats the selected color properly
update_icon() //updates the item icon
user.regenerate_icons() //updates the worn icon. Probably a bad idea, but it works.
if("Secondary Color")
var/secondary_color_input = input(usr,"","Choose Secondary Color",secondary_color) as color|null
if(secondary_color_input)
secondary_color = sanitize_hexcolor(secondary_color_input, desired_format=6, include_crunch=1)
update_icon()
user.regenerate_icons()
if("Tertiary Color")
var/tertiary_color_input = input(usr,"","Choose Tertiary Color",tertiary_color) as color|null
if(tertiary_color_input)
tertiary_color = sanitize_hexcolor(tertiary_color_input, desired_format=6, include_crunch=1)
update_icon()
user.regenerate_icons()
return TRUE
/obj/item/clothing/neck/AltClick(mob/user)
. = ..()
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
return
// Polychrome stuff:
if(hasprimary | hassecondary | hastertiary)
var/choice = input(user,"polychromic thread options", "Clothing Recolor") as null|anything in list("[hasprimary ? "Primary Color" : ""]", "[hassecondary ? "Secondary Color" : ""]", "[hastertiary ? "Tertiary Color" : ""]") //generates a list depending on the enabled overlays
switch(choice) //Lets the list's options actually lead to something
if("Primary Color")
var/primary_color_input = input(usr,"","Choose Primary Color",primary_color) as color|null //color input menu, the "|null" adds a cancel button to it.
if(primary_color_input) //Checks if the color selected is NULL, rejects it if it is NULL.
primary_color = sanitize_hexcolor(primary_color_input, desired_format=6, include_crunch=1) //formats the selected color properly
update_icon() //updates the item icon
user.regenerate_icons() //updates the worn icon. Probably a bad idea, but it works.
if("Secondary Color")
var/secondary_color_input = input(usr,"","Choose Secondary Color",secondary_color) as color|null
if(secondary_color_input)
secondary_color = sanitize_hexcolor(secondary_color_input, desired_format=6, include_crunch=1)
update_icon()
user.regenerate_icons()
if("Tertiary Color")
var/tertiary_color_input = input(usr,"","Choose Tertiary Color",tertiary_color) as color|null
if(tertiary_color_input)
tertiary_color = sanitize_hexcolor(tertiary_color_input, desired_format=6, include_crunch=1)
update_icon()
user.regenerate_icons()
return TRUE
/obj/item/clothing/under/verb/jumpsuit_adjust()
@@ -377,3 +441,18 @@ BLIND // can't see anything
return FALSE
return TRUE
/obj/item/clothing/update_icon() // Polychrome stuff
..()
if(hasprimary) //Checks if the overlay is enabled
var/mutable_appearance/primary_overlay = mutable_appearance(icon, "[item_color]-primary") //Automagically picks overlays
primary_overlay.color = primary_color //Colors the greyscaled overlay
add_overlay(primary_overlay) //Applies the coloured overlay onto the item sprite. but NOT the mob sprite.
if(hassecondary)
var/mutable_appearance/secondary_overlay = mutable_appearance(icon, "[item_color]-secondary")
secondary_overlay.color = secondary_color
add_overlay(secondary_overlay)
if(hastertiary)
var/mutable_appearance/tertiary_overlay = mutable_appearance(icon, "[item_color]-tertiary")
tertiary_overlay.color = tertiary_color
add_overlay(tertiary_overlay)
+6 -3
View File
@@ -54,6 +54,9 @@
H.blur_eyes(5)
eyes.applyOrganDamage(5)
/obj/item/clothing/glasses/proc/ranged_attack(mob/living/carbon/human/user,atom/A, params)
return FALSE
/obj/item/clothing/glasses/meson
name = "optical meson scanner"
desc = "Used by engineering and mining staff to see basic structural and terrain layouts through walls, regardless of lighting conditions."
@@ -99,7 +102,7 @@
desc = "A pair of snazzy goggles used to protect against chemical spills. Fitted with an analyzer for scanning items and reagents."
icon_state = "purple"
item_state = "glasses"
scan_reagents = TRUE //You can see reagents while wearing science goggles
clothing_flags = SCAN_REAGENTS //You can see reagents while wearing science goggles
actions_types = list(/datum/action/item_action/toggle_research_scanner)
glass_colour_type = /datum/client_colour/glass_colour/purple
resistance_flags = ACID_PROOF
@@ -203,7 +206,7 @@
/obj/item/clothing/glasses/sunglasses/reagent
name = "beer goggles"
desc = "A pair of sunglasses outfitted with apparatus to scan reagents."
scan_reagents = TRUE
clothing_flags = SCAN_REAGENTS
/obj/item/clothing/glasses/sunglasses/garb
name = "black gar glasses"
@@ -405,7 +408,7 @@
item_state = "godeye"
vision_flags = SEE_TURFS|SEE_MOBS|SEE_OBJS
darkness_view = 8
scan_reagents = TRUE
clothing_flags = SCAN_REAGENTS
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
resistance_flags = LAVA_PROOF | FIRE_PROOF
@@ -0,0 +1,15 @@
/obj/item/clothing/glasses/hud/security/sunglasses/disablers
name = "true stunglasses"
desc = "Made for only the best of shitsec. Wear 'em like you're gonna robust all of those fuckers."
var/beamtype = /obj/item/projectile/beam/disabler //change for adminbus
/obj/item/clothing/glasses/hud/security/sunglasses/disablers/ranged_attack(mob/living/carbon/human/user,atom/A, params)
user.changeNext_move(CLICK_CD_RANGE)
var/obj/item/projectile/beam/disabler/LE = new beamtype( loc )
playsound(usr.loc, 'sound/weapons/taser2.ogg', 75, 1)
LE.firer = src
LE.def_zone = user.get_organ_target()
LE.preparePixelProjectile(A, src, params)
LE.fire()
return TRUE
//shamelessly copied
@@ -90,7 +90,7 @@
for(var/i in rad_places)
var/turf/place = i
if(get_dist(user, place) >= range*2) //Rads are easier to see than wires under the floor
if(get_dist(user, place) >= range*8) //Rads are easier to see than wires under the floor
continue
var/strength = round(rad_places[i] / 1000, 0.1)
var/image/pic = new(loc = place)
@@ -139,7 +139,6 @@
item_state = "trayson-t-ray"
desc = "Used by engineering staff to see underfloor objects such as cables and pipes."
range = 2
modes = list(MODE_NONE = MODE_TRAY, MODE_TRAY = MODE_NONE)
/obj/item/clothing/glasses/meson/engine/tray/prescription
@@ -152,7 +151,6 @@
icon_state = "trayson-shuttle"
item_state = "trayson-shuttle"
desc = "Used to see the boundaries of shuttle regions."
modes = list(MODE_NONE = MODE_SHUTTLE, MODE_SHUTTLE = MODE_NONE)
#undef MODE_NONE
+2 -2
View File
@@ -89,12 +89,12 @@
/obj/item/clothing/shoes/clown_shoes/equipped(mob/user, slot)
. = ..()
if(user.mind && user.mind.assigned_role == "Clown")
if(user.mind && HAS_TRAIT(user.mind, TRAIT_CLOWN_MENTALITY))
SEND_SIGNAL(user, COMSIG_CLEAR_MOOD_EVENT, "noshoes")
/obj/item/clothing/shoes/clown_shoes/dropped(mob/user)
. = ..()
if(user.mind && user.mind.assigned_role == "Clown")
if(user.mind && HAS_TRAIT(user.mind, TRAIT_CLOWN_MENTALITY))
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "noshoes", /datum/mood_event/noshoes)
/obj/item/clothing/shoes/clown_shoes/jester
+1 -1
View File
@@ -13,7 +13,7 @@
if(!ishuman(user))
return
var/mob/living/carbon/human/H = user
if(!(HAS_TRAIT(H, TRAIT_CLUMSY)) && !(H.mind && H.mind.assigned_role == "Clown"))
if(!(HAS_TRAIT(H, TRAIT_CLUMSY)) && !(H.mind && HAS_TRAIT(H.mind, TRAIT_CLOWN_MENTALITY)))
return
if(slot == SLOT_SHOES)
spells = new
+4 -5
View File
@@ -445,7 +445,7 @@
flash_protect = 0
armor = list("melee" = 30, "bullet" = 5, "laser" = 10, "energy" = 5, "bomb" = 10, "bio" = 100, "rad" = 60, "fire" = 60, "acid" = 75)
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR
scan_reagents = TRUE
clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | BLOCK_GAS_SMOKE_EFFECT | ALLOWINTERNALS | SCAN_REAGENTS
/obj/item/clothing/suit/space/hardsuit/medical
icon_state = "hardsuit-medical"
@@ -467,7 +467,7 @@
max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT
armor = list("melee" = 30, "bullet" = 5, "laser" = 10, "energy" = 5, "bomb" = 100, "bio" = 100, "rad" = 60, "fire" = 60, "acid" = 80)
var/obj/machinery/doppler_array/integrated/bomb_radar
scan_reagents = TRUE
clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | BLOCK_GAS_SMOKE_EFFECT | ALLOWINTERNALS | SCAN_REAGENTS
actions_types = list(/datum/action/item_action/toggle_helmet_light, /datum/action/item_action/toggle_research_scanner)
/obj/item/clothing/head/helmet/space/hardsuit/rd/Initialize()
@@ -590,8 +590,7 @@
/obj/item/clothing/suit/space/hardsuit/clown/mob_can_equip(mob/M, slot)
if(!..() || !ishuman(M))
return FALSE
var/mob/living/carbon/human/H = M
if(H.mind.assigned_role == "Clown")
if(M.mind && HAS_TRAIT(M.mind, TRAIT_CLOWN_MENTALITY))
return TRUE
else
return FALSE
@@ -638,7 +637,7 @@
armor = list("melee" = 20, "bullet" = 15, "laser" = 15, "energy" = 45, "bomb" = 100, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100)
item_color = "ancient"
brightness_on = 16
scan_reagents = TRUE
clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | BLOCK_GAS_SMOKE_EFFECT | ALLOWINTERNALS | SCAN_REAGENTS
flash_protect = 5 //We will not be flash by bombs
tint = 1
var/obj/machinery/doppler_array/integrated/bomb_radar
@@ -742,6 +742,7 @@
name = "assistant's formal winter coat"
icon_state = "coataformal"
item_state = "coataformal"
allowed = list(/obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter,/obj/item/clothing/gloves/color/yellow)
hoodtype = /obj/item/clothing/head/hooded/winterhood/aformal
/obj/item/clothing/head/hooded/winterhood/aformal
@@ -762,7 +763,10 @@
name = "ratvarian winter coat"
icon_state = "coatratvar"
item_state = "coatratvar"
armor = list("melee" = 30, "bullet" = 45, "laser" = -10, "energy" = 0, "bomb" = 30, "bio" = 0, "rad" = 0, "fire" = 60, "acid" = 60)
allowed = list(/obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/clockwork/replica_fabricator, /obj/item/clockwork/integration_cog, /obj/item/clockwork/slab, /obj/item/clockwork/weapon/ratvarian_spear)
hoodtype = /obj/item/clothing/head/hooded/winterhood/ratvar
var/real = TRUE
/obj/item/clothing/head/hooded/winterhood/ratvar
icon_state = "winterhood_ratvar"
@@ -770,15 +774,59 @@
light_power = 1
light_color = "#B18B25" //clockwork slab background top color
/obj/item/clothing/suit/hooded/wintercoat/ratvar/equipped(mob/living/user,slot)
..()
if (slot != SLOT_WEAR_SUIT || !real)
return
if (is_servant_of_ratvar(user))
return
else
user.dropItemToGround(src)
to_chat(user,"<span class='large_brass'>\"Amusing that you think you are fit to wear this.\"</span>")
to_chat(user,"<span class='userdanger'>Your skin burns where the coat touched your skin!</span>")
user.adjustFireLoss(rand(10,16))
/obj/item/clothing/suit/hooded/wintercoat/narsie
name = "narsian winter coat"
icon_state = "coatnarsie"
item_state = "coatnarsie"
armor = list("melee" = 30, "bullet" = 20, "laser" = 30,"energy" = 10, "bomb" = 30, "bio" = 10, "rad" = 10, "fire" = 30, "acid" = 30)
allowed = list(/obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/restraints/legcuffs/bola/cult,/obj/item/melee/cultblade,/obj/item/melee/cultblade/dagger,/obj/item/reagent_containers/glass/beaker/unholywater,/obj/item/cult_shift,/obj/item/flashlight/flare/culttorch,/obj/item/twohanded/cult_spear)
hoodtype = /obj/item/clothing/head/hooded/winterhood/narsie
var/real = TRUE
/obj/item/clothing/suit/hooded/wintercoat/narsie/equipped(mob/living/user,slot)
..()
if (slot != SLOT_WEAR_SUIT || !real)
return
if (iscultist(user))
return
else
user.dropItemToGround(src)
to_chat(user,"<span class='cultlarge'>\"You are not fit to wear my follower's coat!\"</span>")
to_chat(user,"<span class='userdanger'>Sharp spines jab you from within the coat!</span>")
user.adjustBruteLoss(rand(10,16))
/obj/item/clothing/head/hooded/winterhood/narsie
icon_state = "winterhood_narsie"
/obj/item/clothing/suit/hooded/wintercoat/ratvar/fake
name = "brass winter coat"
icon_state = "coatratvar"
item_state = "coatratvar"
allowed = list(/obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter)
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
real = FALSE
/obj/item/clothing/suit/hooded/wintercoat/narsie/fake
name = "runed winter coat"
icon_state = "coatnarsie"
item_state = "coatnarsie"
allowed = list(/obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter)
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
real = FALSE
/obj/item/clothing/suit/spookyghost
name = "spooky ghost"
desc = "This is obviously just a bedsheet, but maybe try it on?"
@@ -467,6 +467,33 @@
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
/obj/item/clothing/under/sundresswhite
name = "white sundress"
desc = "Makes you want to frolic in a field of lillies."
icon_state = "sundress_white"
item_color = "sundress_white"
body_parts_covered = CHEST|GROIN
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
/obj/item/clothing/under/greendress
name = "green dress"
desc = "A tight green dress"
icon_state = "dress_green"
item_color = "dress_green"
body_parts_covered = CHEST|GROIN
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
/obj/item/clothing/under/pinkdress
name = "pink dress"
desc = "A tight pink dress"
icon_state = "dress_pink"
item_color = "dress_pink"
body_parts_covered = CHEST|GROIN
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
/obj/item/clothing/under/captainparade
name = "captain's parade uniform"
desc = "A captain's luxury-wear, for special occasions."
@@ -509,6 +536,24 @@
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
/obj/item/clothing/under/westernbustle
name = "western bustle dress"
desc = "Filled with Western fire."
icon_state = "western_bustle"
item_state = "wcoat"
item_color = "western_bustle"
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
/obj/item/clothing/under/flamenco
name = "flamenco dress"
desc = "Filled with Latin fire."
icon_state = "flamenco"
item_state = "wcoat"
item_color = "flamenco"
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
/obj/item/clothing/under/stripeddress
name = "striped dress"
desc = "Fashion in space."
@@ -529,6 +574,44 @@
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
/obj/item/clothing/under/flowerdress
name = "flower dress"
desc = "Lovely dress"
icon_state = "flower_dress"
item_state = "sailordress"
item_color = "flower_dress"
body_parts_covered = CHEST|GROIN
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
/obj/item/clothing/under/sweptskirt
name = "swept skirt"
desc = "Formal skirt"
icon_state = "skirt_swept"
item_color = "skirt_swept"
body_parts_covered = GROIN
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
/obj/item/clothing/under/corset
name = "black corset"
desc = "Nanotrasen is not resposible for any organ damage"
icon_state = "corset"
item_color = "corset"
body_parts_covered = CHEST|GROIN
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
/obj/item/clothing/under/croptop
name = "crop top"
desc = "We've saved money by giving you half a shirt!"
icon_state = "sailor_dress"
item_state = "sailordress"
item_color = "sailor_dress"
body_parts_covered = CHEST|GROIN|ARMS
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
/obj/item/clothing/under/redeveninggown
name = "red evening gown"
desc = "Fancy dress for space bar singers."
+31
View File
@@ -75,3 +75,34 @@
desc = "A pair of woodland camouflage pants. Probably not the best choice for a space station."
icon_state = "camopants"
item_color = "camopants"
/obj/item/clothing/under/pants/jeanripped
name = "ripped jeans"
desc = "If you're wearing this you're poor or a rebel"
icon_state = "jean_ripped"
item_color = "jean_ripped"
/obj/item/clothing/under/pants/jeanshort
name = "jean shorts"
desc = "These are really just jeans cut in half"
icon_state = "jean_shorts"
item_color = "jean_shorts"
/obj/item/clothing/under/pants/denimskirt
name = "denim skirt"
desc = "These are really just a jean leg hole cut from a pair"
icon_state = "denim_skirt"
item_color = "denim_skirt"
/obj/item/clothing/under/pants/chaps
name = "black chaps"
body_parts_covered = LEGS
desc = "Yeehaw"
icon_state = "chaps"
item_color = "chaps"
/obj/item/clothing/under/pants/yoga
name = "yoga pants"
desc = "Comfy!"
icon_state = "yoga_pants"
item_color = "yoga_pants"
@@ -0,0 +1,166 @@
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Polychromic Uniforms: //
// //
// Polychromic clothes simply consist of 4 sprites: A base, unrecoloured sprite, and up to 3 greyscaled sprites. //
// In order to add more polychromic clothes, simply create a base sprite, and up to 3 recolourable overlays for it, //
// and then name them as follows: [name], [name]-primary, [name]-secondary, [name]-tertiary. The sprites should //
// ideally be in 'icons/obj/clothing/uniform.dmi' and 'icons/mob/uniform.dmi' for the //
// worn sprites. After that, copy paste the code from any of the example clothes and //
// change the names around. [name] should go in BOTH icon_state and item_color. You can preset colors and disable //
// any overlays using the self-explainatory vars. //
// //
// -Tori //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/obj/item/clothing/under/polychromic //enables all three overlays to reduce copypasta and defines basic stuff
name = "polychromic suit"
desc = "For when you want to show off your horrible colour coordination skills."
icon_state = "polysuit"
item_color = "polysuit"
item_state = "sl_suit"
hasprimary = TRUE
hassecondary = TRUE
hastertiary = TRUE
primary_color = "#FFFFFF" //RGB in hexcode
secondary_color = "#FFFFFF"
tertiary_color = "#808080"
can_adjust = FALSE
mutantrace_variation = NO_MUTANTRACE_VARIATION //Not all clothes are currently digi-compatible (only the shorts are as of time of writing)
/obj/item/clothing/under/polychromic/worn_overlays(isinhands, icon_file) //this is where the main magic happens.
. = ..()
if(hasprimary | hassecondary | hastertiary)
if(!isinhands) //prevents the worn sprites from showing up if you're just holding them
if(hasprimary) //checks if overlays are enabled
var/mutable_appearance/primary_worn = mutable_appearance(icon_file, "[item_color]-primary") //automagical sprite selection
primary_worn.color = primary_color //colors the overlay
. += primary_worn //adds the overlay onto the buffer list to draw on the mob sprite.
if(hassecondary)
var/mutable_appearance/secondary_worn = mutable_appearance(icon_file, "[item_color]-secondary")
secondary_worn.color = secondary_color
. += secondary_worn
if(hastertiary)
var/mutable_appearance/tertiary_worn = mutable_appearance(icon_file, "[item_color]-tertiary")
tertiary_worn.color = tertiary_color
. += tertiary_worn
/obj/item/clothing/under/polychromic/shirt //COPY PASTE THIS TO MAKE A NEW THING
name = "polychromic button-up shirt"
desc = "A fancy button-up shirt made with polychromic threads."
icon_state = "polysuit"
item_color = "polysuit"
item_state = "sl_suit"
primary_color = "#FFFFFF" //RGB in hexcode
secondary_color = "#353535"
tertiary_color = "#353535"
/obj/item/clothing/under/polychromic/kilt
name = "polychromic kilt"
desc = "It's not a skirt!"
icon_state = "polykilt"
item_color = "polykilt"
item_state = "kilt"
primary_color = "#FFFFFF" //RGB in hexcode
secondary_color = "#F08080"
hastertiary = FALSE // so it doesn't futz with digilegs
body_parts_covered = CHEST|GROIN|ARMS
/obj/item/clothing/under/polychromic/skirt
name = "polychromic skirt"
desc = "A fancy skirt made with polychromic threads."
icon_state = "polyskirt"
item_color = "polyskirt"
item_state = "rainbow"
primary_color = "#FFFFFF" //RGB in hexcode
secondary_color = "#F08080"
tertiary_color = "#808080"
body_parts_covered = CHEST|GROIN|ARMS
/obj/item/clothing/under/polychromic/shorts
name = "polychromic shorts"
desc = "For ease of movement and style."
icon_state = "polyshorts"
item_color = "polyshorts"
item_state = "rainbow"
primary_color = "#353535" //RGB in hexcode
secondary_color = "#808080"
tertiary_color = "#808080"
body_parts_covered = CHEST|GROIN|ARMS
mutantrace_variation = MUTANTRACE_VARIATION //to enable digitigrade wearing
/obj/item/clothing/under/polychromic/jumpsuit
name = "polychromic tri-tone jumpsuit"
desc = "A fancy jumpsuit made with polychromic threads."
icon_state = "polyjump"
item_color = "polyjump"
item_state = "rainbow"
primary_color = "#FFFFFF" //RGB in hexcode
secondary_color = "#808080"
tertiary_color = "#FF3535"
/obj/item/clothing/under/polychromic/shortpants
name = "polychromic athletic shorts"
desc = "95% Polychrome, 5% Spandex!"
icon_state = "polyshortpants"
item_color = "polyshortpants"
item_state = "rainbow"
hastertiary = FALSE
primary_color = "#FFFFFF" //RGB in hexcode
secondary_color = "#F08080"
gender = PLURAL //Because shortS
body_parts_covered = GROIN //Because there's no shirt included
/obj/item/clothing/under/polychromic/pleat
name = "polychromic pleated skirt"
desc = "A magnificent pleated skirt complements the woolen polychromatic sweater."
icon_state = "polypleat"
item_color = "polypleat"
item_state = "rainbow"
primary_color = "#8CC6FF" //RGB in hexcode
secondary_color = "#808080"
tertiary_color = "#FF3535"
body_parts_covered = CHEST|GROIN|ARMS
/obj/item/clothing/under/polychromic/femtank
name = "polychromic feminine tank top"
desc = "Great for showing off your chest in style. Not recommended for males."
icon_state = "polyfemtankpantsu"
item_color = "polyfemtankpantsu"
item_state = "rainbow"
hastertiary = FALSE
primary_color = "#808080" //RGB in hexcode
secondary_color = "#FF3535"
body_parts_covered = CHEST|GROIN|ARMS
/obj/item/clothing/under/polychromic/shortpants/pantsu
name = "polychromic panties"
desc = "Topless striped panties. Now with 120% more polychrome!"
icon_state = "polypantsu"
item_color = "polypantsu"
item_state = "rainbow"
hastertiary = FALSE
primary_color = "#FFFFFF" //RGB in hexcode
secondary_color = "#8CC6FF"
body_parts_covered = GROIN
/obj/item/clothing/under/polychromic/bottomless
name = "polychromic bottomless shirt"
desc = "Great for showing off your junk in dubious style."
icon_state = "polybottomless"
item_color = "polybottomless"
item_state = "rainbow"
hastertiary = FALSE
primary_color = "#808080" //RGB in hexcode
secondary_color = "#FF3535"
body_parts_covered = CHEST|ARMS //Because there's no bottom included
/obj/item/clothing/under/polychromic/shimatank
name = "polychromic tank top"
desc = "For those lazy summer days."
icon_state = "polyshimatank"
item_color = "polyshimatank"
item_state = "rainbow"
primary_color = "#808080" //RGB in hexcode
secondary_color = "#FFFFFF"
tertiary_color = "#8CC6FF"
body_parts_covered = CHEST|GROIN
@@ -358,3 +358,11 @@
time = 100
category = CAT_MISC
always_availible = FALSE // Disabled til learned
/datum/crafting_recipe/coconut_bong
name = "Coconut Bong"
result = /obj/item/bong/coconut
reqs = list(/obj/item/stack/sheet/mineral/bamboo = 2,
/obj/item/reagent_containers/food/snacks/grown/coconut = 1)
time = 70
category = CAT_MISC
+2
View File
@@ -37,6 +37,8 @@
continue
if(!H.client)
continue
if(HAS_TRAIT(H,TRAIT_EXEMPT_HEALTH_EVENTS))
continue
if(H.stat == DEAD)
continue
if(HAS_TRAIT(H, TRAIT_VIRUSIMMUNE)) //Don't pick someone who's virus immune, only for it to not do anything.
+1 -1
View File
@@ -9,7 +9,7 @@
/datum/round_event/heart_attack/start()
var/list/heart_attack_contestants = list()
for(var/mob/living/carbon/human/H in shuffle(GLOB.player_list))
if(!H.client || H.stat == DEAD || H.InCritical() || !H.can_heartattack() || H.has_status_effect(STATUS_EFFECT_EXERCISED) || (/datum/disease/heart_failure in H.diseases) || H.undergoing_cardiac_arrest())
if(!H.client || H.stat == DEAD || H.InCritical() || !H.can_heartattack() || H.has_status_effect(STATUS_EFFECT_EXERCISED) || (/datum/disease/heart_failure in H.diseases) || H.undergoing_cardiac_arrest() || HAS_TRAIT(H,TRAIT_EXEMPT_HEALTH_EVENTS))
continue
if(H.satiety <= -60) //Multiple junk food items recently
heart_attack_contestants[H] = 3
@@ -35,4 +35,6 @@
/datum/hallucination/delusion,
/datum/hallucination/oh_yeah)
for(var/mob/living/carbon/C in GLOB.alive_mob_list)
if (HAS_TRAIT(C,TRAIT_EXEMPT_HEALTH_EVENTS))
continue
new picked_hallucination(C, TRUE)
@@ -15,6 +15,8 @@
continue
if(H.stat == DEAD)
continue
if (HAS_TRAIT(H,TRAIT_EXEMPT_HEALTH_EVENTS))
continue
if(!H.getorgan(/obj/item/organ/appendix)) //Don't give the disease to some who lacks it, only for it to be auto-cured
continue
if(!(MOB_ORGANIC in H.mob_biotypes)) //biotype sleeper bugs strike again, once again making appendicitis pick a target that can't take it
@@ -55,7 +55,7 @@
mix_filling_color(S)
S.reagents.trans_to(src,min(S.reagents.total_volume, 15)) //limit of 15, we don't want our custom food to be completely filled by just one ingredient with large reagent volume.
foodtype |= S.foodtype
update_overlays(S)
update_snack_overlays(S)
to_chat(user, "<span class='notice'>You add the [I.name] to the [name].</span>")
update_name(S)
else
@@ -103,7 +103,7 @@
rgbcolor[4] = (customcolor[4]+ingcolor[4])/2
filling_color = rgb(rgbcolor[1], rgbcolor[2], rgbcolor[3], rgbcolor[4])
/obj/item/reagent_containers/food/snacks/customizable/update_overlays(obj/item/reagent_containers/food/snacks/S)
/obj/item/reagent_containers/food/snacks/customizable/update_snack_overlays(obj/item/reagent_containers/food/snacks/S)
var/mutable_appearance/filling = mutable_appearance(icon, "[initial(icon_state)]_filling")
if(S.filling_color == "#FFFFFF")
filling.color = pick("#FF0000","#0000FF","#008000","#FFFF00")
@@ -139,7 +139,7 @@
/obj/item/reagent_containers/food/snacks/customizable/initialize_slice(obj/item/reagent_containers/food/snacks/slice, reagents_per_slice)
..()
slice.filling_color = filling_color
slice.update_overlays(src)
slice.update_snack_overlays(src)
/obj/item/reagent_containers/food/snacks/customizable/Destroy()
+1 -1
View File
@@ -269,7 +269,7 @@ All foods are distributed among various categories. Use common sense.
trash = null
return
/obj/item/reagent_containers/food/snacks/proc/update_overlays(obj/item/reagent_containers/food/snacks/S)
/obj/item/reagent_containers/food/snacks/proc/update_snack_overlays(obj/item/reagent_containers/food/snacks/S)
cut_overlays()
var/mutable_appearance/filling = mutable_appearance(icon, "[initial(icon_state)]_filling")
if(S.filling_color == "#FFFFFF")
@@ -219,7 +219,7 @@
name = "space cola snowcone"
desc = "Space Cola drizzled over a snowball in a paper cup."
icon_state = "soda_sc"
list_reagents = list("nutriment" = 1, "space_cola" = 5)
list_reagents = list("nutriment" = 1, "cola" = 5)
tastes = list("ice" = 1, "water" = 1, "cola" = 5)
/obj/item/reagent_containers/food/snacks/snowcones/spacemountainwind
@@ -248,4 +248,4 @@
desc = "A very colorful snowball in a paper cup."
icon_state = "rainbow_sc"
list_reagents = list("nutriment" = 5, "laughter" = 25)
tastes = list("ice" = 1, "water" = 1, "sunlight" = 5, "light" = 5, "slime" = 5, "paint" = 3, "clouds" = 3)
tastes = list("ice" = 1, "water" = 1, "sunlight" = 5, "light" = 5, "slime" = 5, "paint" = 3, "clouds" = 3)
@@ -609,4 +609,68 @@
filling_color = "#ECA735"
tastes = list("fried corn" = 1)
foodtype = JUNKFOOD | FRIED
dunkable = TRUE
dunkable = TRUE
/obj/item/reagent_containers/food/snacks/marshmallow
name = "marshmallow"
desc = "A marshmallow filled with fluffy marshmallow fluff."
icon_state = "marshmallow"
list_reagents = list("sugar" = 5, "nutriment" = 2)
filling_color = "#fafafa"
w_class = WEIGHT_CLASS_TINY
tastes = list("marshmallow" = 2)
foodtype = SUGAR | JUNKFOOD
var/burned = 0
/obj/item/reagent_containers/food/snacks/marshmallow/attackby(obj/item/I, mob/user)
switch (I.get_temperature())
if (355 to 1500)
if (prob(30))
burnmallow()
if (1500 to 2000)
if (prob(50))
burnmallow()
else
burnmallow(TRUE)
if (2000 to 3000)
if (prob(10))
burnmallow()
else
burnmallow(TRUE)
if (3000 to INFINITY)
burnmallow(TRUE)
return ..()
/obj/item/reagent_containers/food/snacks/marshmallow/proc/burnmallow(reallyburned = FALSE)
if (reallyburned && burned == 1)
icon_state = "marshmallowrburned"
else if (burned == 0)
icon_state = "marshmallowburned"
/obj/item/reagent_containers/food/snacks/marshmallow/examine(mob/user)
. = ..()
if (burned == 2)
. += "It looks very burned."
if (burned == 1)
. += "It looks just right for eating!"
/obj/item/reagent_containers/food/snacks/marshmallow/fire_act(temp,volume)
switch (temp)
if (355 to 1500)
if (prob(30))
burnmallow()
if (1500 to 2000)
if (prob(50))
burnmallow()
else
burnmallow(TRUE)
if (2000 to 3000)
if (prob(10))
burnmallow()
else
burnmallow(TRUE)
if (3000 to 7000)
burnmallow(TRUE)
if (7000 to INFINITY)
burn()
..()
@@ -692,13 +692,13 @@
to_chat(user, "<span class='notice'>You add the [I] to the [name].</span>")
P.name = initial(P.name)
contents += P
update_overlays(P)
update_snack_overlays(P)
if (P.contents.len)
for(var/V in P.contents)
P = V
P.name = initial(P.name)
contents += P
update_overlays(P)
update_snack_overlays(P)
P = I
clearlist(P.contents)
return
@@ -707,7 +707,7 @@
return O.attackby(I, user, params)
..()
/obj/item/reagent_containers/food/snacks/pancakes/update_overlays(obj/item/reagent_containers/food/snacks/P)
/obj/item/reagent_containers/food/snacks/pancakes/update_snack_overlays(obj/item/reagent_containers/food/snacks/P)
var/mutable_appearance/pancake = mutable_appearance(icon, "[P.item_state]_[rand(1,3)]")
pancake.pixel_x = rand(-1,1)
pancake.pixel_y = 3 * contents.len - 1
+24 -1
View File
@@ -8,6 +8,8 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico
//On client, created on login
/datum/chatOutput
var/client/owner //client ref
var/total_checks = 0
var/last_check = 0
var/loaded = FALSE // Has the client loaded the browser output area?
var/list/messageQueue //If they haven't loaded chat, this is where messages will go until they do
var/cookieSent = FALSE // Has the client sent a cookie for analysis
@@ -150,6 +152,18 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico
//Called by client, sent data to investigate (cookie history so far)
/datum/chatOutput/proc/analyzeClientData(cookie = "")
//Spam check
if(world.time > last_check + (3 SECONDS))
last_check = world.time
total_checks = 0
total_checks += 1
if(total_checks > SPAM_TRIGGER_AUTOMUTE)
message_admins("[key_name(owner)] kicked for goonchat topic spam")
qdel(owner)
return
if(!cookie)
return
@@ -158,13 +172,22 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico
if (connData && islist(connData) && connData.len > 0 && connData["connData"])
connectionHistory = connData["connData"] //lol fuck
var/list/found = new()
for(var/i in connectionHistory.len to 1 step -1)
if(connectionHistory.len > 5)
message_admins("[key_name(src.owner)] was kicked for an invalid ban cookie)")
qdel(owner)
return
for(var/i in min(connectionHistory.len, 5) to 1 step -1)
if(QDELETED(owner))
//he got cleaned up before we were done
return
var/list/row = src.connectionHistory[i]
if (!row || row.len < 3 || (!row["ckey"] || !row["compid"] || !row["ip"])) //Passed malformed history object
return
if (world.IsBanned(row["ckey"], row["ip"], row["compid"], real_bans_only=TRUE))
found = row
break
CHECK_TICK
//Uh oh this fucker has a history of playing on a banned account!!
if (found.len > 0)
@@ -421,8 +421,8 @@ function handleClientData(ckey, ip, compid) {
return; //Record already exists
}
}
if (opts.clientData.length >= opts.clientDataLimit) {
//Lets make sure we obey our limit (can connect from server with higher limit)
while (opts.clientData.length >= opts.clientDataLimit) {
opts.clientData.shift();
}
} else {
+1 -3
View File
@@ -59,9 +59,7 @@
return
var/area/AS = get_area(src)
if(istype(AS, /area/holodeck))
log_world("### MAPPING ERROR")
log_world("Holodeck computer cannot be in a holodeck.")
log_world("This would cause circular power dependency.")
log_mapping("Holodeck computer cannot be in a holodeck, This would cause circular power dependency.")
qdel(src)
return
else
+2 -3
View File
@@ -111,11 +111,10 @@
/turf/open/floor/holofloor/carpet/Initialize()
. = ..()
addtimer(CALLBACK(src, .proc/update_icon), 1)
addtimer(CALLBACK(src, /atom/.proc/update_icon), 1)
/turf/open/floor/holofloor/carpet/update_icon()
if(!..())
return 0
. = ..()
if(intact)
queue_smooth(src)
+1 -1
View File
@@ -240,7 +240,7 @@
dat += "</table>"
else
dat += "No trait-related genes detected in sample.<br>"
if(can_insert && istype(disk.gene, /datum/plant_gene/trait))
if(can_insert && istype(disk.gene, /datum/plant_gene/trait) && !seed.is_gene_forbidden(disk.gene.type))
dat += "<a href='?src=[REF(src)];op=insert'>Insert: [disk.gene.get_name()]</a>"
dat += "</div>"
else
+2 -2
View File
@@ -148,7 +148,7 @@
icon_grow = "sunflower-grow"
icon_dead = "sunflower-dead"
mutatelist = list(/obj/item/seeds/sunflower/moonflower, /obj/item/seeds/sunflower/novaflower)
reagents_add = list("cornoil" = 0.08, "nutriment" = 0.04)
reagents_add = list("cooking_oil" = 0.08, "nutriment" = 0.04)
/obj/item/grown/sunflower // FLOWER POWER!
seed = /obj/item/seeds/sunflower
@@ -316,4 +316,4 @@
filling_color = "#FF6347"
bitesize_mod = 8
tastes = list("wax" = 1)
foodtype = SUGAR
foodtype = SUGAR
@@ -27,7 +27,7 @@
bitesize_mod = 2
var/stacktype = /obj/item/stack/tile/grass
var/tile_coefficient = 0.02 // 1/50
wine_power = 15
distill_reagent = /datum/reagent/consumable/ethanol/beer/light
/obj/item/reagent_containers/food/snacks/grown/grass/attack_self(mob/user)
to_chat(user, "<span class='notice'>You prepare the astroturf.</span>")
+277 -1
View File
@@ -232,7 +232,7 @@
/obj/item/reagent_containers/food/snacks/grown/cherry_bomb/proc/detonate()
reagents.chem_temp = 1000 //Sets off the black powder
reagents.handle_reactions()
// Lavaland cactus
/obj/item/seeds/lavaland/cactus
@@ -244,3 +244,279 @@
product = /obj/item/reagent_containers/food/snacks/grown/ash_flora/cactus_fruit
growing_icon = 'icons/obj/hydroponics/growing_fruits.dmi'
growthstages = 2
// Coconut
/obj/item/seeds/coconut
name = "pack of coconut seeds"
desc = "They're seeds that grow into coconut palm trees."
icon_state = "seed-coconut"
species = "coconut"
plantname = "Coconut Palm Tree"
product = /obj/item/reagent_containers/food/snacks/grown/coconut
lifespan = 50
endurance = 30
potency = 35
growing_icon = 'icons/obj/hydroponics/growing.dmi'
icon_dead = "coconut-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest)
forbiddengenes = list(/datum/plant_gene/trait/squash, /datum/plant_gene/trait/stinging)
reagents_add = list("coconutmilk" = 0.3)
/obj/item/reagent_containers/food/snacks/grown/coconut
seed = /obj/item/seeds/coconut
name = "coconut"
desc = "Hard shell of a nut containing delicious milk inside. Perhaps try using something sharp?"
icon_state = "coconut"
item_state = "coconut"
possible_transfer_amounts = list(5, 10, 15, 20, 25, 30, 50)
spillable = FALSE
resistance_flags = ACID_PROOF
volume = 150 //so it won't cut reagents despite having the capacity for them
w_class = WEIGHT_CLASS_SMALL
force = 5
throwforce = 5
hitsound = 'sound/weapons/klonk.ogg'
attack_verb = list("klonked", "donked", "bonked")
var/opened = FALSE
var/carved = FALSE
var/chopped = FALSE
var/straw = FALSE
var/fused = FALSE
var/fusedactive = FALSE
var/defused = FALSE
/obj/item/reagent_containers/food/snacks/grown/coconut/Initialize(mapload, obj/item/seeds/new_seed)
. = ..()
var/newvolume = 50 + round(seed.potency,10)
if (seed.get_gene(/datum/plant_gene/trait/maxchem))
newvolume = newvolume + 50
volume = newvolume
reagents.maximum_volume = newvolume
reagents.update_total()
transform *= TRANSFORM_USING_VARIABLE(40, 100) + 0.5 //temporary fix for size?
/obj/item/reagent_containers/food/snacks/grown/coconut/attack_self(mob/user)
if (!opened)
return
if(!possible_transfer_amounts.len)
return
var/i=0
for(var/A in possible_transfer_amounts)
i++
if(A != amount_per_transfer_from_this)
continue
if(i<possible_transfer_amounts.len)
amount_per_transfer_from_this = possible_transfer_amounts[i+1]
else
amount_per_transfer_from_this = possible_transfer_amounts[1]
to_chat(user, "<span class='notice'>[src]'s transfer amount is now [amount_per_transfer_from_this] units.</span>")
return
/obj/item/reagent_containers/food/snacks/grown/coconut/attackby(obj/item/W, mob/user, params)
//DEFUSING NADE LOGIC
if (W.tool_behaviour == TOOL_WIRECUTTER && fused)
user.show_message("<span class='notice'>You cut the fuse!</span>", MSG_VISUAL)
playsound(user, W.hitsound, 50, 1, -1)
icon_state = "coconut_carved"
desc = "A coconut. This one's got a hole in it."
name = "coconut"
defused = TRUE
fused = FALSE
fusedactive = FALSE
if(!seed.get_gene(/datum/plant_gene/trait/glow))
set_light(0, 0.0)
return
//IGNITING NADE LOGIC
if(!fusedactive && fused)
var/lighting_text = W.ignition_effect(src, user)
if(lighting_text)
user.visible_message("<span class='warning'>[user] ignites [src]'s fuse!</span>", "<span class='userdanger'>You ignite the [src]'s fuse!</span>")
fusedactive = TRUE
defused = FALSE
playsound(src, 'sound/effects/fuse.ogg', 100, 0)
message_admins("[ADMIN_LOOKUPFLW(user)] ignited a coconut bomb for detonation at [ADMIN_VERBOSEJMP(user)] [pretty_string_from_reagent_list(reagents.reagent_list)]")
log_game("[key_name(user)] primed a coconut grenade for detonation at [AREACOORD(user)].")
addtimer(CALLBACK(src, .proc/prime), 5 SECONDS)
icon_state = "coconut_grenade_active"
desc = "RUN!"
if(!seed.get_gene(/datum/plant_gene/trait/glow))
light_color = "#FFCC66" //for the fuse
set_light(3, 0.8)
return
//ADDING A FUSE, NADE LOGIC
if (istype(W,/obj/item/stack/sheet/cloth) || istype(W,/obj/item/stack/sheet/durathread))
if (carved && !straw && !fused)
user.show_message("<span class='notice'>You add a fuse to the coconut!</span>", 1)
W.use(1)
fused = TRUE
icon_state = "coconut_grenade"
desc = "A makeshift bomb made out of a coconut. You estimate the fuse is long enough for 5 seconds."
name = "coconut bomb"
return
//ADDING STRAW LOGIC
if (istype(W,/obj/item/stack/sheet/mineral/bamboo) && opened && !straw && fused)
user.show_message("<span class='notice'>You add a bamboo straw to the coconut!</span>", 1)
straw = TRUE
W.use(1)
icon_state += "_straw"
desc = "You can already feel like you're on a tropical vacation."
return
//OPENING THE NUT LOGIC
if (!carved && !chopped)
var/screwdrivered = W.tool_behaviour == TOOL_SCREWDRIVER
if(screwdrivered || W.sharpness)
user.show_message("<span class='notice'>You [screwdrivered ? "make a hole in the coconut" : "slice the coconut open"]!</span>", 1)
carved = TRUE
opened = TRUE
spillable = !screwdrivered
reagent_flags = OPENCONTAINER
ENABLE_BITFIELD(reagents.reagents_holder_flags, OPENCONTAINER)
icon_state = screwdrivered ? "coconut_carved" : "coconut_chopped"
desc = "A coconut. [screwdrivered ? "This one's got a hole in it" : "This one's sliced open, with all its delicious contents for your eyes to savour"]."
playsound(user, W.hitsound, 50, 1, -1)
return
return ..()
/obj/item/reagent_containers/food/snacks/grown/coconut/attack(mob/living/M, mob/user, obj/target)
if(M && user.a_intent == INTENT_HARM && !spillable)
var/obj/item/bodypart/affecting = user.zone_selected //Find what the player is aiming at
if (affecting == BODY_ZONE_HEAD && prob(15))
//smash the nut open
var/armor_block = min(90, M.run_armor_check(affecting, "melee", null, null,armour_penetration)) // For normal attack damage
M.apply_damage(force, BRUTE, affecting, armor_block)
//Sound
playsound(user, hitsound, 100, 1, -1)
//Attack logs
log_combat(user, M, "attacked", src)
//Display an attack message.
if(M != user)
M.visible_message("<span class='danger'>[user] has cracked open a [name] on [M]'s head!</span>", \
"<span class='userdanger'>[user] has cracked open a [name] on [M]'s head!</span>")
else
user.visible_message("<span class='danger'>[M] cracks open a [name] on their [M.p_them()] head!</span>", \
"<span class='userdanger'>[M] cracks open a [name] on [M.p_their()] head!</span>")
//The coconut breaks open so splash its reagents
spillable = TRUE
SplashReagents(M)
//Lastly we remove the nut
qdel(src)
else
. = ..()
return
if(fusedactive)
return
if(!opened)
return
if(!canconsume(M, user))
return
if(!reagents || !reagents.total_volume)
to_chat(user, "<span class='warning'>[src] is empty!</span>")
return
if(user.a_intent == INTENT_HARM && spillable)
var/R
M.visible_message("<span class='danger'>[user] splashes the contents of [src] onto [M]!</span>", \
"<span class='userdanger'>[user] splashes the contents of [src] onto [M]!</span>")
if(reagents)
for(var/datum/reagent/A in reagents.reagent_list)
R += A.id + " ("
R += num2text(A.volume) + "),"
if(isturf(target) && reagents.reagent_list.len && thrownby)
log_combat(thrownby, target, "splashed (thrown) [english_list(reagents.reagent_list)]")
message_admins("[ADMIN_LOOKUPFLW(thrownby)] splashed (thrown) [english_list(reagents.reagent_list)] on [target] at [ADMIN_VERBOSEJMP(target)].")
reagents.reaction(M, TOUCH)
log_combat(user, M, "splashed", R)
reagents.clear_reagents()
else
if(M != user)
M.visible_message("<span class='danger'>[user] attempts to feed something to [M].</span>", \
"<span class='userdanger'>[user] attempts to feed something to you.</span>")
if(!do_mob(user, M))
return
if(!reagents || !reagents.total_volume)
return // The drink might be empty after the delay, such as by spam-feeding
M.visible_message("<span class='danger'>[user] feeds something to [M].</span>", "<span class='userdanger'>[user] feeds something to you.</span>")
log_combat(user, M, "fed", reagents.log_list())
else
to_chat(user, "<span class='notice'>You swallow a gulp of [src].</span>")
var/fraction = min(5/reagents.total_volume, 1)
reagents.reaction(M, INGEST, fraction)
addtimer(CALLBACK(reagents, /datum/reagents.proc/trans_to, M, 5), 5)
playsound(M.loc,'sound/items/drink.ogg', rand(10,50), 1)
/obj/item/reagent_containers/food/snacks/grown/coconut/afterattack(obj/target, mob/user, proximity)
. = ..()
if(fusedactive)
return
if((!proximity) || !check_allowed_items(target,target_self=1))
return
if(target.is_refillable()) //Something like a glass. Player probably wants to transfer TO it.
if(!reagents.total_volume)
to_chat(user, "<span class='warning'>[src] is empty!</span>")
return
if(target.reagents.holder_full())
to_chat(user, "<span class='warning'>[target] is full.</span>")
return
var/trans = reagents.trans_to(target, amount_per_transfer_from_this)
to_chat(user, "<span class='notice'>You transfer [trans] unit\s of the solution to [target].</span>")
else if(target.is_drainable()) //A dispenser. Transfer FROM it TO us.
if(!target.reagents.total_volume)
to_chat(user, "<span class='warning'>[target] is empty and can't be refilled!</span>")
return
if(reagents.holder_full())
to_chat(user, "<span class='warning'>[src] is full.</span>")
return
var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this)
to_chat(user, "<span class='notice'>You fill [src] with [trans] unit\s of the contents of [target].</span>")
else if(reagents.total_volume)
if(user.a_intent == INTENT_HARM && spillable == TRUE)
user.visible_message("<span class='danger'>[user] splashes the contents of [src] onto [target]!</span>", \
"<span class='notice'>You splash the contents of [src] onto [target].</span>")
reagents.reaction(target, TOUCH)
reagents.clear_reagents()
/obj/item/reagent_containers/food/snacks/grown/coconut/dropped(mob/user)
. = ..()
transform *= TRANSFORM_USING_VARIABLE(40, 100) + 0.5 //temporary fix for size?
/obj/item/reagent_containers/food/snacks/grown/coconut/proc/prime()
if (defused)
return
var/turf/T = get_turf(src)
reagents.chem_temp = 1000
//Disable seperated contents when the grenade primes
if (seed.get_gene(/datum/plant_gene/trait/noreact))
DISABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT)
reagents.handle_reactions()
log_game("Coconut bomb detonation at [AREACOORD(T)], location [loc]")
qdel(src)
/obj/item/reagent_containers/food/snacks/grown/coconut/ex_act(severity)
qdel(src)
/obj/item/reagent_containers/food/snacks/grown/coconut/deconstruct(disassembled = TRUE)
if(!disassembled && fused)
prime()
if(!QDELETED(src))
qdel(src)
+6 -1
View File
@@ -27,6 +27,7 @@
var/rarity = 0 // How rare the plant is. Used for giving points to cargo when shipping off to CentCom.
var/list/mutatelist = list() // The type of plants that this plant can mutate into.
var/list/genes = list() // Plant genes are stored here, see plant_genes.dm for more info.
var/list/forbiddengenes = list()
var/list/reagents_add = list()
// A list of reagents to add to product.
// Format: "reagent_id" = potency multiplier
@@ -96,6 +97,10 @@
S.reagents_add = reagents_add.Copy() // Faster than grabbing the list from genes.
return S
obj/item/seeds/proc/is_gene_forbidden(typepath)
return (typepath in forbiddengenes)
/obj/item/seeds/proc/get_gene(typepath)
return (locate(typepath) in genes)
@@ -448,7 +453,7 @@
for(var/i in 1 to amount_random_traits)
var/random_trait = pick((subtypesof(/datum/plant_gene/trait)-typesof(/datum/plant_gene/trait/plant_type)))
var/datum/plant_gene/trait/T = new random_trait
if(T.can_add(src))
if(T.can_add(src) && !is_gene_forbidden(random_trait))
genes += T
else
qdel(T)
+2
View File
@@ -14,6 +14,8 @@
access = list(ACCESS_THEATRE)
minimal_access = list(ACCESS_THEATRE)
mind_traits = list(TRAIT_CLOWN_MENTALITY)
display_order = JOB_DISPLAY_ORDER_CLOWN
/datum/outfit/job/clown
+1 -1
View File
@@ -71,7 +71,7 @@ GLOBAL_LIST_INIT(exp_jobsmap, list(
GLOBAL_LIST_INIT(exp_specialmap, list(
EXP_TYPE_LIVING = list(), // all living mobs
EXP_TYPE_ANTAG = list(),
EXP_TYPE_SPECIAL = list("Lifebringer","Ash Walker","Exile","Servant Golem","Free Golem","Hermit","Translocated Vet","Escaped Prisoner","Hotel Staff","SuperFriend","Space Syndicate","Ancient Crew","Space Doctor","Space Bartender","Beach Bum","Skeleton","Zombie","Space Bar Patron","Lavaland Syndicate","Ghost Role"), // Ghost roles
EXP_TYPE_SPECIAL = list("Lifebringer","Ash Walker","Exile","Servant Golem","Free Golem","Hermit","Translocated Vet","Escaped Prisoner","Hotel Staff","SuperFriend","Space Syndicate","Ancient Crew","Space Doctor","Space Bartender","Beach Bum","Skeleton","Zombie","Space Bar Patron","Lavaland Syndicate","Ghost Role", "Ghost Cafe Visitor"), // Ghost roles
EXP_TYPE_GHOST = list() // dead people, observers
))
GLOBAL_PROTECT(exp_jobsmap)
+12 -2
View File
@@ -58,13 +58,23 @@
return
switch(_key)
if("Shift")
sprint_hotkey(TRUE)
if(!user.prefs.sprint_spacebar)
user.prefs.sprint_toggle ? togglesprint() : sprint_hotkey(TRUE) //Yes, this looks hacky. Yes, this works.
return
if("Space")
if(user.prefs.sprint_spacebar)
user.prefs.sprint_toggle ? togglesprint() : sprint_hotkey(TRUE)
return
return ..()
/mob/living/carbon/human/key_up(_key, client/user)
switch(_key)
if("Shift")
sprint_hotkey(FALSE)
if(!user.prefs.sprint_spacebar && !user.prefs.sprint_toggle)
sprint_hotkey(FALSE)
return
if("Space")
if(user.prefs.sprint_spacebar && !user.prefs.sprint_toggle)
sprint_hotkey(FALSE)
return
return ..()
+1 -1
View File
@@ -134,7 +134,7 @@
/datum/language_holder/synthetic
languages = list(/datum/language/common)
shadow_languages = list(/datum/language/common, /datum/language/machine, /datum/language/draconic)
shadow_languages = list(/datum/language/common, /datum/language/machine, /datum/language/draconic, /datum/language/slime)
/datum/language_holder/empty
languages = list()
+9 -2
View File
@@ -70,7 +70,7 @@
//initialize things that are normally initialized after map load
parsed.initTemplateBounds()
smooth_zlevel(world.maxz)
log_game("Z-level [name] loaded at at [x],[y],[world.maxz]")
log_game("Z-level [name] loaded at [x],[y],[world.maxz]")
return level
@@ -84,6 +84,13 @@
if(T.y+height > world.maxy)
return
var/list/border = block(locate(max(T.x-1, 1), max(T.y-1, 1), T.z),
locate(min(T.x+width+1, world.maxx), min(T.y+height+1, world.maxy), T.z))
for(var/L in border)
var/turf/turf_to_disable = L
SSair.remove_from_active(turf_to_disable) //stop processing turfs along the border to prevent runtimes, we return it in initTemplateBounds()
turf_to_disable.atmos_adjacent_turfs?.Cut()
// Accept cached maps, but don't save them automatically - we don't want
// ruins clogging up memory for the whole round.
var/datum/parsed_map/parsed = cached_map || new(file(mappath))
@@ -100,7 +107,7 @@
//initialize things that are normally initialized after map load
parsed.initTemplateBounds()
log_game("[name] loaded at at [T.x],[T.y],[T.z]")
log_game("[name] loaded at [T.x],[T.y],[T.z]")
return bounds
/datum/map_template/proc/get_affected_turfs(turf/T, centered = FALSE)
+9 -21
View File
@@ -18,7 +18,7 @@
/obj/effect/baseturf_helper/LateInitialize()
if(!baseturf_to_replace)
baseturf_to_replace = typecacheof(/turf/open/space)
baseturf_to_replace = typecacheof(list(/turf/open/space,/turf/baseturf_bottom))
else if(!length(baseturf_to_replace))
baseturf_to_replace = list(baseturf_to_replace = TRUE)
else if(baseturf_to_replace[baseturf_to_replace[1]] != TRUE) // It's not associative
@@ -45,7 +45,6 @@
thing.PlaceOnBottom(null, baseturf)
else if(baseturf_to_replace[thing.baseturfs])
thing.assemble_baseturfs(baseturf)
return
else
thing.PlaceOnBottom(null, baseturf)
@@ -107,16 +106,16 @@
/obj/effect/mapping_helpers/airlock/cyclelink_helper/Initialize(mapload)
. = ..()
if(!mapload)
log_world("### MAP WARNING, [src] spawned outside of mapload!")
log_mapping("[src] spawned outside of mapload!")
return
var/obj/machinery/door/airlock/airlock = locate(/obj/machinery/door/airlock) in loc
if(airlock)
if(airlock.cyclelinkeddir)
log_world("### MAP WARNING, [src] at [AREACOORD(src)] tried to set [airlock] cyclelinkeddir, but it's already set!")
log_mapping("[src] at [AREACOORD(src)] tried to set [airlock] cyclelinkeddir, but it's already set!")
else
airlock.cyclelinkeddir = dir
else
log_world("### MAP WARNING, [src] failed to find an airlock at [AREACOORD(src)]")
log_mapping("[src] failed to find an airlock at [AREACOORD(src)]")
/obj/effect/mapping_helpers/airlock/locked
@@ -126,16 +125,16 @@
/obj/effect/mapping_helpers/airlock/locked/Initialize(mapload)
. = ..()
if(!mapload)
log_world("### MAP WARNING, [src] spawned outside of mapload!")
log_mapping("[src] spawned outside of mapload!")
return
var/obj/machinery/door/airlock/airlock = locate(/obj/machinery/door/airlock) in loc
if(airlock)
if(airlock.locked)
log_world("### MAP WARNING, [src] at [AREACOORD(src)] tried to bolt [airlock] but it's already locked!")
log_mapping("[src] at [AREACOORD(src)] tried to bolt [airlock] but it's already locked!")
else
airlock.locked = TRUE
else
log_world("### MAP WARNING, [src] failed to find an airlock at [AREACOORD(src)]")
log_mapping("[src] failed to find an airlock at [AREACOORD(src)]")
/obj/effect/mapping_helpers/airlock/unres
name = "airlock unresctricted side helper"
@@ -144,13 +143,13 @@
/obj/effect/mapping_helpers/airlock/unres/Initialize(mapload)
. = ..()
if(!mapload)
log_world("### MAP WARNING, [src] spawned outside of mapload!")
log_mapping("[src] spawned outside of mapload!")
return
var/obj/machinery/door/airlock/airlock = locate(/obj/machinery/door/airlock) in loc
if(airlock)
airlock.unres_sides ^= dir
else
log_world("### MAP WARNING, [src] failed to find an airlock at [AREACOORD(src)]")
log_mapping("[src] failed to find an airlock at [AREACOORD(src)]")
//needs to do its thing before spawn_rivers() is called
@@ -164,17 +163,6 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava)
var/turf/T = get_turf(src)
T.flags_1 |= NO_LAVA_GEN_1
/// Adds the map it is on to the z_is_planet list
/obj/effect/mapping_helpers/planet_z
name = "planet z helper"
layer = POINT_LAYER
/obj/effect/mapping_helpers/planet_z/Initialize()
. = ..()
var/datum/space_level/S = SSmapping.get_level(z)
S.traits[ZTRAIT_PLANET] = TRUE
//This helper applies components to things on the map directly.
/obj/effect/mapping_helpers/component_injector
name = "Component Injector"
+14 -6
View File
@@ -8,18 +8,26 @@ GLOBAL_DATUM_INIT(_preloader, /datum/map_preloader, new)
var/list/attributes
var/target_path
/datum/map_preloader/proc/setup(list/the_attributes, path)
/world/proc/preloader_setup(list/the_attributes, path)
if(the_attributes.len)
GLOB.use_preloader = TRUE
attributes = the_attributes
target_path = path
var/datum/map_preloader/preloader_local = GLOB._preloader
preloader_local.attributes = the_attributes
preloader_local.target_path = path
/datum/map_preloader/proc/load(atom/what)
/world/proc/preloader_load(atom/what)
GLOB.use_preloader = FALSE
for(var/attribute in attributes)
var/value = attributes[attribute]
var/datum/map_preloader/preloader_local = GLOB._preloader
for(var/attribute in preloader_local.attributes)
var/value = preloader_local.attributes[attribute]
if(islist(value))
value = deepCopyList(value)
#ifdef TESTING
if(what.vars[attribute] == value)
var/message = "<font color=green>[what.type]</font> at [AREACOORD(what)] - <b>VAR:</b> <font color=red>[attribute] = [isnull(value) ? "null" : (isnum(value) ? value : "\"[value]\"")]</font>"
log_mapping("DIRTY VAR: [message]")
GLOB.dirty_vars += message
#endif
what.vars[attribute] = value
/area/template_noop
+4 -4
View File
@@ -306,8 +306,8 @@
//first instance the /area and remove it from the members list
index = members.len
if(members[index] != /area/template_noop)
GLOB._preloader.setup(members_attributes[index])//preloader for assigning set variables on atom creation
var/atype = members[index]
world.preloader_setup(members_attributes[index], atype)//preloader for assigning set variables on atom creation
var/atom/instance = areaCache[atype]
if (!instance)
instance = GLOB.areas_by_type[atype]
@@ -318,7 +318,7 @@
instance.contents.Add(crds)
if(GLOB.use_preloader && instance)
GLOB._preloader.load(instance)
world.preloader_load(instance)
//then instance the /turf and, if multiple tiles are presents, simulates the DMM underlays piling effect
@@ -354,7 +354,7 @@
//Instance an atom at (x,y,z) and gives it the variables in attributes
/datum/parsed_map/proc/instance_atom(path,list/attributes, turf/crds, no_changeturf, placeOnTop)
GLOB._preloader.setup(attributes, path)
world.preloader_setup(attributes, path)
if(crds)
if(ispath(path, /turf))
@@ -368,7 +368,7 @@
. = create_atom(path, crds)//first preloader pass
if(GLOB.use_preloader && .)//second preloader pass, for those atoms that don't ..() in New()
GLOB._preloader.load(.)
world.preloader_load(.)
//custom CHECK_TICK here because we don't want things created while we're sleeping to not initialize
if(TICK_CHECK)
@@ -67,11 +67,18 @@
new /obj/effect/particle_effect/smoke(get_turf(src))
qdel(src)
//Non-default pods
/obj/item/survivalcapsule/luxury
name = "luxury bluespace shelter capsule"
desc = "An exorbitantly expensive luxury suite stored within a pocket of bluespace."
template_id = "shelter_beta"
/obj/item/survivalcapsule/luxuryelite
name = "luxury elite bar capsule"
desc = "A luxury bar in a capsule. Bartender required and not included."
template_id = "shelter_charlie"
//Pod objects
//Window
@@ -926,7 +926,7 @@
timer = world.time + create_delay + 1
if(do_after(user, create_delay, target = T))
var/old_name = T.name
if(T.TerraformTurf(turf_type))
if(T.TerraformTurf(turf_type, flags = CHANGETURF_INHERIT_AIR))
user.visible_message("<span class='danger'>[user] turns \the [old_name] into [transform_string]!</span>")
message_admins("[ADMIN_LOOKUPFLW(user)] fired the lava staff at [ADMIN_VERBOSEJMP(T)]")
log_game("[key_name(user)] fired the lava staff at [AREACOORD(T)].")
@@ -937,7 +937,7 @@
qdel(L)
else
var/old_name = T.name
if(T.TerraformTurf(reset_turf_type))
if(T.TerraformTurf(reset_turf_type, flags = CHANGETURF_INHERIT_AIR))
user.visible_message("<span class='danger'>[user] turns \the [old_name] into [reset_string]!</span>")
timer = world.time + reset_cooldown
playsound(T,'sound/magic/fireball.ogg', 200, 1)
+2 -2
View File
@@ -50,7 +50,7 @@
/obj/machinery/mineral/ore_redemption/examine(mob/user)
. = ..()
if(in_range(user, src) || isobserver(user))
. += "<span class='notice'>The status display reads: Smelting <b>[sheet_per_ore]</b> sheet(s) per piece of ore.<br>Ore pickup speed at <b>[ore_pickup_rate]</b>.</span>"
. += "<span class='notice'>The status display reads: Smelting <b>[sheet_per_ore]</b> sheet(s) per piece of ore.<br>Reward point generation at <b>[point_upgrade*100]%</b>.<br>Ore pickup speed at <b>[ore_pickup_rate]</b>.</span>"
/obj/machinery/mineral/ore_redemption/proc/smelt_ore(obj/item/stack/ore/O)
var/datum/component/material_container/mat_container = materials.mat_container
@@ -63,7 +63,7 @@
ore_buffer -= O
if(O && O.refined_type)
points += O.points * O.amount
points += O.points * point_upgrade * O.amount
var/material_amount = mat_container.get_item_material_amount(O)
+1
View File
@@ -54,6 +54,7 @@
new /datum/data/mining_equipment("Super Resonator", /obj/item/resonator/upgraded, 2500),
new /datum/data/mining_equipment("Jump Boots", /obj/item/clothing/shoes/bhop, 2500),
new /datum/data/mining_equipment("Luxury Shelter Capsule", /obj/item/survivalcapsule/luxury, 3000),
new /datum/data/mining_equipment("Luxury Bar Capsule", /obj/item/survivalcapsule/luxuryelite, 10000),
new /datum/data/mining_equipment("Nanotrasen Minebot", /mob/living/simple_animal/hostile/mining_drone, 800),
new /datum/data/mining_equipment("Minebot Melee Upgrade", /obj/item/mine_bot_upgrade, 400),
new /datum/data/mining_equipment("Minebot Armor Upgrade", /obj/item/mine_bot_upgrade/health, 400),
+15
View File
@@ -58,3 +58,18 @@
. = ..()
whitelisted_turfs = typecacheof(/turf/closed/mineral)
banned_objects = typecacheof(/obj/structure/stone_tile)
/datum/map_template/shelter/charlie
name = "Shelter Charlie"
shelter_id = "shelter_charlie"
description = "A luxury elite bar which holds an entire bar \
along with two vending machines, tables, and a restroom that \
also has a sink. This isn't a survival capsule and so you can \
expect that this won't save you if you're bleeding out to \
death."
mappath = "_maps/templates/shelter_3.dmm"
/datum/map_template/shelter/charlie/New()
. = ..()
whitelisted_turfs = typecacheof(/turf/closed/mineral)
banned_objects = typecacheof(/obj/structure/stone_tile)
@@ -74,4 +74,5 @@
/datum/sprite_accessory/underwear
icon = 'icons/mob/underwear.dmi'
var/has_color = FALSE
var/has_color = FALSE
var/has_digitigrade = FALSE
@@ -275,6 +275,18 @@
name = "Snow"
icon_state = "snow"
/datum/sprite_accessory/insect_fluff/oakworm
name = "Oak Worm"
icon_state = "oakworm"
/datum/sprite_accessory/insect_fluff/jungle
name = "Jungle"
icon_state = "jungle"
/datum/sprite_accessory/insect_fluff/witchwing
name = "Witch Wing"
icon_state = "witchwing"
/datum/sprite_accessory/insect_fluff/colored
name = "Colored (Hair)"
icon_state = "snow"
@@ -2,6 +2,9 @@
// Socks Definitions //
///////////////////////
/datum/sprite_accessory/underwear/socks
has_digitigrade = TRUE
/datum/sprite_accessory/underwear/socks/nude
name = "Nude"
icon_state = null
@@ -28,41 +28,49 @@
name = "Boxers"
icon_state = "boxers"
has_color = TRUE
has_digitigrade = TRUE
gender = MALE
/datum/sprite_accessory/underwear/bottom/male_bee
name = "Boxers - Bee"
icon_state = "bee_shorts"
has_digitigrade = TRUE
gender = MALE
/datum/sprite_accessory/underwear/bottom/male_hearts
name = "Boxers - Heart"
icon_state = "boxers_heart"
has_digitigrade = TRUE
gender = MALE
/datum/sprite_accessory/underwear/bottom/male_stripe
name = "Boxers - Striped"
icon_state = "boxers_striped"
has_digitigrade = TRUE
gender = MALE
/datum/sprite_accessory/underwear/bottom/male_commie
name = "Boxers - Striped Communist"
icon_state = "boxers_commie"
has_digitigrade = TRUE
gender = MALE
/datum/sprite_accessory/underwear/bottom/male_usastripe
name = "Boxers - Striped Freedom"
icon_state = "boxers_assblastusa"
has_digitigrade = TRUE
gender = MALE
/datum/sprite_accessory/underwear/bottom/male_uk
name = "Boxers - Striped UK"
icon_state = "boxers_uk"
has_digitigrade = TRUE
gender = MALE
/datum/sprite_accessory/underwear/bottom/boxer_briefs
name = "Boxer Briefs"
icon_state = "boxer_briefs"
has_digitigrade = TRUE
has_color = TRUE
/datum/sprite_accessory/underwear/bottom/panties
@@ -140,6 +148,7 @@
/datum/sprite_accessory/underwear/bottom/longjon
name = "Long John Bottoms"
icon_state = "ljonb"
has_digitigrade = TRUE
has_color = TRUE
/datum/sprite_accessory/underwear/bottom/swimsuit_red
@@ -213,4 +213,81 @@
/datum/sprite_accessory/insect_wings/whitefly
name = "White Fly"
icon_state = "whitefly"
icon_state = "whitefly"
/datum/sprite_accessory/insect_wings/oakworm
name = "Oak Worm"
icon_state = "oakworm"
/datum/sprite_accessory/insect_wings/jungle
name = "Jungle"
icon_state = "jungle"
/datum/sprite_accessory/insect_wings/witchwing
name = "Witch Wing"
icon_state = "witchwing"
//insect markings
/datum/sprite_accessory/insect_markings // Extra markings for insects ported from tg.
icon = 'icons/mob/insect_markings.dmi'
color_src = null
/datum/sprite_accessory/insect_markings/none
name = "None"
icon_state = "none"
/datum/sprite_accessory/insect_markings/reddish
name = "Reddish"
icon_state = "reddish"
/datum/sprite_accessory/insect_markings/royal
name = "Royal"
icon_state = "royal"
/datum/sprite_accessory/insect_markings/gothic
name = "Gothic"
icon_state = "gothic"
/datum/sprite_accessory/insect_markings/whitefly
name = "White Fly"
icon_state = "whitefly"
/datum/sprite_accessory/insect_markings/lovers
name = "Lovers"
icon_state = "lovers"
/datum/sprite_accessory/insect_markings/punished
name = "Punished"
icon_state = "punished"
/datum/sprite_accessory/insect_markings/firewatch
name = "Firewatch"
icon_state = "firewatch"
/datum/sprite_accessory/insect_markings/deathhead
name = "Deathshead"
icon_state = "deathhead"
/datum/sprite_accessory/insect_markings/poison
name = "Poison"
icon_state = "poison"
/datum/sprite_accessory/insect_markings/ragged
name = "Ragged"
icon_state = "ragged"
/datum/sprite_accessory/insect_markings/moonfly
name = "Moon Fly"
icon_state = "moonfly"
/datum/sprite_accessory/insect_markings/oakworm
name = "Oak Worm"
icon_state = "oakworm"
/datum/sprite_accessory/insect_markings/jungle
name = "Jungle"
icon_state = "jungle"
/datum/sprite_accessory/insect_markings/witchwing
name = "Witch Wing"
icon_state = "witchwing"
+3
View File
@@ -18,3 +18,6 @@
update_icon(preferred_form)
updateghostimages()
client.reenter_round_timeout = max(client.reenter_round_timeout, clientless_round_timeout)
clientless_round_timeout = client.reenter_round_timeout
+19 -12
View File
@@ -3,8 +3,6 @@ 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!
@@ -20,7 +18,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
hud_type = /datum/hud/ghost
movement_type = GROUND | FLYING
var/can_reenter_corpse
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/clientless_round_timeout = 0 //mobs will lack a client as long as their player is disconnected. See client_defines.dm "reenter_round_timeout"
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.
@@ -177,7 +175,8 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
* Hair will always update its dir, so if your sprite has no dirs the haircut will go all over the place.
* |- Ricotez
*/
/mob/dead/observer/proc/update_icon(new_form)
/mob/dead/observer/update_icon(new_form)
. = ..()
if(client) //We update our preferences in case they changed right before update_icon was called.
ghost_accs = client.prefs.ghost_accs
ghost_others = client.prefs.ghost_others
@@ -276,9 +275,16 @@ Works together with spawning an observer, noted above.
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
penalty += world.realtime
if(penalty - SSshuttle.realtimeofstart > SSshuttle.auto_call + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
penalty = CANT_REENTER_ROUND
if(client)
client.reenter_round_timeout = penalty
else //A disconnected player (quite likely for cryopods)
ghost.clientless_round_timeout = penalty
if (client && client.prefs && client.prefs.auto_ooc)
if (!(client.prefs.chat_toggles & CHAT_OOC))
client.prefs.chat_toggles ^= CHAT_OOC
transfer_ckey(ghost, FALSE)
return ghost
@@ -337,10 +343,13 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
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)
var/timeout = clientless_round_timeout
if(client)
timeout = client.reenter_round_timeout
if(timeout != CANT_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>")
if(!silent && client)
to_chat(src, "<span class='warning'>You are unable to reenter the round[timeout != CANT_REENTER_ROUND ? " yet. Your ghost role blacklist will expire in [DisplayTimeText(timeout - world.realtime)]" : ""].</span>")
return FALSE
/mob/dead/observer/Move(NewLoc, direct)
@@ -892,5 +901,3 @@ 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
@@ -6,21 +6,21 @@
return 2 //no ears
/mob/living/carbon/alien/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
..(AM, skipcatch = TRUE, hitpush = FALSE)
return ..(AM, skipcatch = TRUE, hitpush = FALSE)
/mob/living/carbon/alien/can_embed(obj/item/I)
return FALSE
/*Code for aliens attacking aliens. Because aliens act on a hivemind, I don't see them as very aggressive with each other.
As such, they can either help or harm other aliens. Help works like the human help command while harm is a simple nibble.
In all, this is a lot like the monkey code. /N
*/
/mob/living/carbon/alien/attack_alien(mob/living/carbon/alien/M)
if(isturf(loc) && istype(loc.loc, /area/start))
to_chat(M, "No attacking people at spawn, you jackass.")
. = ..()
if(!.) // the attack was blocked or was help/grab intent
return
switch(M.a_intent)
if ("help")
if (INTENT_HELP)
if(!recoveringstam)
resting = 0
AdjustStun(-60)
@@ -28,11 +28,7 @@ In all, this is a lot like the monkey code. /N
AdjustUnconscious(-60)
AdjustSleeping(-100)
visible_message("<span class='notice'>[M.name] nuzzles [src] trying to wake [p_them()] up!</span>")
if ("grab")
grabbedby(M)
else
if(INTENT_DISARM, INTENT_HARM)
if(health > 0)
M.do_attack_animation(src, ATTACK_EFFECT_BITE)
playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1)
@@ -50,28 +46,31 @@ In all, this is a lot like the monkey code. /N
/mob/living/carbon/alien/attack_hand(mob/living/carbon/human/M)
if(..()) //to allow surgery to return properly.
return 0
. = ..()
if(.) //To allow surgery to return properly.
return
switch(M.a_intent)
if("help")
if(INTENT_HELP)
help_shake_act(M)
if("grab")
if(INTENT_GRAB)
grabbedby(M)
if ("harm")
if (INTENT_HARM)
if(HAS_TRAIT(M, TRAIT_PACIFISM))
to_chat(M, "<span class='notice'>You don't want to hurt [src]!</span>")
return TRUE
M.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
return 1
if("disarm")
if(INTENT_DISARM)
if(HAS_TRAIT(M, TRAIT_PACIFISM))
to_chat(M, "<span class='notice'>You don't want to hurt [src]!</span>")
return TRUE
M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
return 1
return 0
/mob/living/carbon/alien/attack_paw(mob/living/carbon/monkey/M)
if(..())
if (stat != DEAD)
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
apply_damage(rand(1, 3), BRUTE, affecting)
. = ..()
if(.) //successful monkey bite.
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
apply_damage(rand(1, 3), BRUTE, affecting)
/mob/living/carbon/alien/attack_animal(mob/living/simple_animal/M)
@@ -93,13 +92,15 @@ In all, this is a lot like the monkey code. /N
adjustStaminaLoss(damage)
/mob/living/carbon/alien/attack_slime(mob/living/simple_animal/slime/M)
if(..()) //successful slime attack
var/damage = rand(5, 35)
if(M.is_adult)
damage = rand(10, 40)
adjustBruteLoss(damage)
log_combat(M, src, "attacked")
updatehealth()
. = ..()
if(!.) //unsuccessful slime attack
return
var/damage = rand(5, 35)
if(M.is_adult)
damage = rand(10, 40)
adjustBruteLoss(damage)
log_combat(M, src, "attacked")
updatehealth()
/mob/living/carbon/alien/ex_act(severity, target, origin)
if(origin && istype(origin, /datum/spacevine_mutation) && isvineimmune(src))
@@ -63,12 +63,7 @@
if(hit_atom)
if(isliving(hit_atom))
var/mob/living/L = hit_atom
var/blocked = FALSE
if(ishuman(hit_atom))
var/mob/living/carbon/human/H = hit_atom
if(H.check_shields(src, 0, "the [name]", attack_type = LEAP_ATTACK))
blocked = TRUE
if(!blocked)
if(!L.check_shields(src, 0, "the [name]", attack_type = LEAP_ATTACK))
L.visible_message("<span class ='danger'>[src] pounces on [L]!</span>", "<span class ='userdanger'>[src] pounces on you!</span>")
L.Knockdown(100)
sleep(2)//Runtime prevention (infinite bump() calls on hulks)
@@ -5,9 +5,11 @@
else
..()
/mob/living/carbon/alien/humanoid/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0)
/mob/living/carbon/alien/humanoid/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
if(user.a_intent == INTENT_HARM)
..(user, 1)
. = ..(user, TRUE)
if(.)
return
adjustBruteLoss(15)
var/hitverb = "punched"
if(mob_size < MOB_SIZE_LARGE)
@@ -21,46 +23,46 @@
return 1
/mob/living/carbon/alien/humanoid/attack_hand(mob/living/carbon/human/M)
if(..())
switch(M.a_intent)
if ("harm")
var/damage = rand(1, 9)
if (prob(90))
playsound(loc, "punch", 25, 1, -1)
visible_message("<span class='danger'>[M] has punched [src]!</span>", \
"<span class='userdanger'>[M] has punched [src]!</span>", null, COMBAT_MESSAGE_RANGE)
if ((stat != DEAD) && (damage > 9 || prob(5)))//Regular humans have a very small chance of knocking an alien down.
Unconscious(40)
visible_message("<span class='danger'>[M] has knocked [src] down!</span>", \
"<span class='userdanger'>[M] has knocked [src] down!</span>")
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
apply_damage(damage, BRUTE, affecting)
log_combat(M, src, "attacked")
. = ..()
if(.) //To allow surgery to return properly.
return
switch(M.a_intent)
if (INTENT_HARM)
var/damage = rand(1, 9)
if (prob(90))
playsound(loc, "punch", 25, 1, -1)
visible_message("<span class='danger'>[M] has punched [src]!</span>", \
"<span class='userdanger'>[M] has punched [src]!</span>", null, COMBAT_MESSAGE_RANGE)
if ((stat != DEAD) && (damage > 9 || prob(5)))//Regular humans have a very small chance of knocking an alien down.
Unconscious(40)
visible_message("<span class='danger'>[M] has knocked [src] down!</span>", \
"<span class='userdanger'>[M] has knocked [src] down!</span>")
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
apply_damage(damage, BRUTE, affecting)
log_combat(M, src, "attacked")
else
playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
visible_message("<span class='danger'>[M] has attempted to punch [src]!</span>", \
"<span class='userdanger'>[M] has attempted to punch [src]!</span>", null, COMBAT_MESSAGE_RANGE)
if (INTENT_DISARM)
if (!lying)
if (prob(5))
Unconscious(40)
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
log_combat(M, src, "pushed")
visible_message("<span class='danger'>[M] has pushed down [src]!</span>", \
"<span class='userdanger'>[M] has pushed down [src]!</span>")
else
playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
visible_message("<span class='userdanger'>[M] has attempted to punch [src]!</span>", \
"<span class='userdanger'>[M] has attempted to punch [src]!</span>", null, COMBAT_MESSAGE_RANGE)
if ("disarm")
if (!lying)
if (prob(5))
Unconscious(40)
if (prob(50))
dropItemToGround(get_active_held_item())
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
log_combat(M, src, "pushed")
visible_message("<span class='danger'>[M] has pushed down [src]!</span>", \
"<span class='userdanger'>[M] has pushed down [src]!</span>")
visible_message("<span class='danger'>[M] has disarmed [src]!</span>", \
"<span class='userdanger'>[M] has disarmed [src]!</span>", null, COMBAT_MESSAGE_RANGE)
else
if (prob(50))
dropItemToGround(get_active_held_item())
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
visible_message("<span class='danger'>[M] has disarmed [src]!</span>", \
"<span class='userdanger'>[M] has disarmed [src]!</span>", null, COMBAT_MESSAGE_RANGE)
else
playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
visible_message("<span class='userdanger'>[M] has attempted to disarm [src]!</span>",\
"<span class='userdanger'>[M] has attempted to disarm [src]!</span>", null, COMBAT_MESSAGE_RANGE)
playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
visible_message("<span class='danger'>[M] has attempted to disarm [src]!</span>",\
"<span class='userdanger'>[M] has attempted to disarm [src]!</span>", null, COMBAT_MESSAGE_RANGE)
/mob/living/carbon/alien/humanoid/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
if(!no_effect && !visual_effect_icon)
@@ -1,26 +1,33 @@
/mob/living/carbon/alien/larva/attack_hand(mob/living/carbon/human/M)
if(..())
var/damage = rand(1, 9)
if (prob(90))
playsound(loc, "punch", 25, 1, -1)
log_combat(M, src, "attacked")
visible_message("<span class='danger'>[M] has kicked [src]!</span>", \
"<span class='userdanger'>[M] has kicked [src]!</span>", null, COMBAT_MESSAGE_RANGE)
if ((stat != DEAD) && (damage > 4.9))
Unconscious(rand(100,200))
. = ..()
if(. || M.a_intent == INTENT_HELP || M.a_intent == INTENT_GRAB)
return
var/damage = rand(1, 9)
if (prob(90))
playsound(loc, "punch", 25, 1, -1)
log_combat(M, src, "attacked")
visible_message("<span class='danger'>[M] has kicked [src]!</span>", \
"<span class='userdanger'>[M] has kicked [src]!</span>", null, COMBAT_MESSAGE_RANGE)
if ((stat != DEAD) && (damage > 4.9))
Unconscious(rand(100,200))
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
apply_damage(damage, BRUTE, affecting)
else
playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
visible_message("<span class='danger'>[M] has attempted to kick [src]!</span>", \
"<span class='userdanger'>[M] has attempted to kick [src]!</span>", null, COMBAT_MESSAGE_RANGE)
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
apply_damage(damage, BRUTE, affecting)
else
playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
visible_message("<span class='danger'>[M] has attempted to kick [src]!</span>", \
"<span class='userdanger'>[M] has attempted to kick [src]!</span>", null, COMBAT_MESSAGE_RANGE)
/mob/living/carbon/alien/larva/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0)
/mob/living/carbon/alien/larva/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
if(user.a_intent == INTENT_HARM)
..(user, 1)
. = ..(user, TRUE)
if(.)
return
playsound(loc, "punch", 25, 1, -1)
visible_message("<span class='danger'>[user] has pummeled [src]!</span>", \
"<span class='userdanger'>[user] has pummeled [src]!</span>", null, COMBAT_MESSAGE_RANGE)
adjustBruteLoss(5 + rand(1,9))
new /datum/forced_movement(src, get_step_away(user,src, 30), 1)
return 1
@@ -103,15 +103,17 @@
new_xeno.notransform = 0
new_xeno.invisibility = 0
var/mob/living/carbon/old_owner = owner
if(kill_on_sucess) //ITS TOO LATE
new_xeno.visible_message("<span class='danger'>[new_xeno] bursts out of [owner]!</span>", "<span class='userdanger'>You exit [owner], your previous host.</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
owner.apply_damage(rand(100,300),BRUTE,zone,FALSE) //Random high damage to torso so health sensors don't metagame.
owner.spill_organs(TRUE,FALSE,TRUE) //Lets still make the death gruesome and impossible to just simply defib someone.
var/obj/item/bodypart/B = owner.get_bodypart(zone)
B.drop_organs(owner) //Lets still make the death gruesome and impossible to just simply defib someone.
owner.death(FALSE) //Just in case some freak occurance occurs where you somehow survive all your organs being removed from you and the 100-300 brute damage.
else //When it is removed via surgery at a late stage, rather than forced.
new_xeno.visible_message("<span class='danger'>[new_xeno] wriggles out of [owner]!</span>", "<span class='userdanger'>You exit [owner], your previous host.</span>")
owner.adjustBruteLoss(40)
owner.cut_overlay(overlay)
old_owner.cut_overlay(overlay)
qdel(src)
+13 -1
View File
@@ -155,6 +155,7 @@
if(getStaminaLoss() >= STAMINA_SOFTCRIT)
to_chat(src, "<span class='warning'>You're too exhausted.</span>")
return
var/random_turn = a_intent == INTENT_HARM
//END OF CIT CHANGES
var/obj/item/I = get_active_held_item()
@@ -202,7 +203,7 @@
do_attack_animation(target, no_effect = 1)
playsound(loc, 'sound/weapons/punchmiss.ogg', 50, 1, -1)
newtonian_move(get_dir(target, src))
thrown_thing.safe_throw_at(target, thrown_thing.throw_range, thrown_thing.throw_speed, src, null, null, null, move_force)
thrown_thing.safe_throw_at(target, thrown_thing.throw_range, thrown_thing.throw_speed, src, null, null, null, move_force, random_turn)
@@ -975,3 +976,14 @@
if(combatmode)
toggle_combat_mode(TRUE, TRUE)
return ..()
/mob/living/carbon/can_see_reagents()
. = ..()
if(.) //No need to run through all of this if it's already true.
return
if(isclothing(head))
var/obj/item/clothing/H = head
if(H.clothing_flags & SCAN_REAGENTS)
return TRUE
if(isclothing(wear_mask) && (wear_mask.clothing_flags & SCAN_REAGENTS))
return TRUE
@@ -48,31 +48,42 @@
if(affecting && affecting.dismemberable && affecting.get_damage() >= (affecting.max_damage - P.dismemberment))
affecting.dismember(P.damtype)
/mob/living/carbon/proc/can_catch_item(skip_throw_mode_check)
. = FALSE
if(!skip_throw_mode_check && !in_throw_mode)
/mob/living/carbon/catch_item(obj/item/I, skip_throw_mode_check = FALSE)
. = ..()
if(!HAS_TRAIT(src, TRAIT_AUTO_CATCH_ITEM) && !skip_throw_mode_check && !in_throw_mode)
return
if(get_active_held_item())
if(get_active_held_item() || restrained())
return
if(restrained())
return
return TRUE
/mob/living/carbon/hitby(atom/movable/AM, skipcatch, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
if(!skipcatch) //ugly, but easy
if(can_catch_item())
if(istype(AM, /obj/item))
var/obj/item/I = AM
if(isturf(I.loc))
I.attack_hand(src)
if(get_active_held_item() == I) //if our attack_hand() picks up the item...
visible_message("<span class='warning'>[src] catches [I]!</span>") //catch that sucker!
throw_mode_off()
return 1
..()
I.attack_hand(src)
if(get_active_held_item() == I) //if our attack_hand() picks up the item...
visible_message("<span class='warning'>[src] catches [I]!</span>") //catch that sucker!
throw_mode_off()
return TRUE
/mob/living/carbon/embed_item(obj/item/I)
throw_alert("embeddedobject", /obj/screen/alert/embeddedobject)
var/obj/item/bodypart/L = pick(bodyparts)
L.embedded_objects |= I
I.add_mob_blood(src)//it embedded itself in you, of course it's bloody!
I.forceMove(src)
L.receive_damage(I.w_class*I.embedding.embedded_impact_pain_multiplier)
visible_message("<span class='danger'>[I] embeds itself in [src]'s [L.name]!</span>","<span class='userdanger'>[I] embeds itself in your [L.name]!</span>")
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded)
/mob/living/carbon/attacked_by(obj/item/I, mob/living/user)
//CIT CHANGES START HERE - combatmode and resting checks
var/totitemdamage = I.force
if(iscarbon(user))
var/mob/living/carbon/tempcarb = user
if(!tempcarb.combatmode)
totitemdamage *= 0.5
if(user.resting)
totitemdamage *= 0.5
if(!combatmode)
totitemdamage *= 1.5
//CIT CHANGES END HERE
if(user != src && check_shields(I, totitemdamage, "the [I.name]", MELEE_ATTACK, I.armour_penetration))
return FALSE
var/obj/item/bodypart/affecting
if(user == src)
affecting = get_bodypart(check_zone(user.zone_selected)) //we're self-mutilating! yay!
@@ -83,17 +94,6 @@
SEND_SIGNAL(I, COMSIG_ITEM_ATTACK_ZONE, src, user, affecting)
send_item_attack_message(I, user, affecting.name)
if(I.force)
//CIT CHANGES START HERE - combatmode and resting checks
var/totitemdamage = I.force
if(iscarbon(user))
var/mob/living/carbon/tempcarb = user
if(!tempcarb.combatmode)
totitemdamage *= 0.5
if(user.resting)
totitemdamage *= 0.5
if(!combatmode)
totitemdamage *= 1.5
//CIT CHANGES END HERE
apply_damage(totitemdamage, I.damtype, affecting) //CIT CHANGE - replaces I.force with totitemdamage
if(I.damtype == BRUTE && affecting.status == BODYPART_ORGANIC)
var/basebloodychance = affecting.brute_dam + totitemdamage
@@ -127,7 +127,9 @@
//ATTACK HAND IGNORING PARENT RETURN VALUE
/mob/living/carbon/attack_hand(mob/living/carbon/human/user)
. = ..()
if(.) //was the attack blocked?
return
for(var/thing in diseases)
var/datum/disease/D = thing
if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN)
@@ -142,8 +144,7 @@
if(user.a_intent == INTENT_HELP || user.a_intent == INTENT_DISARM)
for(var/datum/surgery/S in surgeries)
if(S.next_step(user, user.a_intent))
return 1
return 0
return TRUE
/mob/living/carbon/attack_paw(mob/living/carbon/monkey/M)
@@ -163,7 +164,8 @@
help_shake_act(M)
return 0
if(..()) //successful monkey bite.
. = ..()
if(.) //successful monkey bite.
for(var/thing in M.diseases)
var/datum/disease/D = thing
ForceContractDisease(D)
@@ -171,26 +173,27 @@
/mob/living/carbon/attack_slime(mob/living/simple_animal/slime/M)
if(..()) //successful slime attack
if(M.powerlevel > 0)
var/stunprob = M.powerlevel * 7 + 10 // 17 at level 1, 80 at level 10
if(prob(stunprob))
M.powerlevel -= 3
if(M.powerlevel < 0)
M.powerlevel = 0
. = ..()
if(!.)
return
if(M.powerlevel > 0)
var/stunprob = M.powerlevel * 7 + 10 // 17 at level 1, 80 at level 10
if(prob(stunprob))
M.powerlevel -= 3
if(M.powerlevel < 0)
M.powerlevel = 0
visible_message("<span class='danger'>The [M.name] has shocked [src]!</span>", \
"<span class='userdanger'>The [M.name] has shocked [src]!</span>")
visible_message("<span class='danger'>The [M.name] has shocked [src]!</span>", \
"<span class='userdanger'>The [M.name] has shocked [src]!</span>")
do_sparks(5, TRUE, src)
var/power = M.powerlevel + rand(0,3)
Knockdown(power*20)
if(stuttering < power)
stuttering = power
if (prob(stunprob) && M.powerlevel >= 8)
adjustFireLoss(M.powerlevel * rand(6,10))
updatehealth()
return 1
do_sparks(5, TRUE, src)
var/power = M.powerlevel + rand(0,3)
Knockdown(power*20)
if(stuttering < power)
stuttering = power
if (prob(stunprob) && M.powerlevel >= 8)
adjustFireLoss(M.powerlevel * rand(6,10))
updatehealth()
/mob/living/carbon/proc/dismembering_strike(mob/living/attacker, dam_zone)
if(!attacker.limb_destroyer)
@@ -322,12 +325,12 @@
else
return
else if(check_zone(M.zone_selected) == "r_arm" || check_zone(M.zone_selected) == "l_arm")
M.visible_message( \
"<span class='notice'>[M] shakes [src]'s hand.</span>", \
"<span class='notice'>You shake [src]'s hand.</span>", )
else
M.visible_message("<span class='notice'>[M] hugs [src] to make [p_them()] feel better!</span>", \
"<span class='notice'>You hug [src] to make [p_them()] feel better!</span>")
@@ -308,7 +308,7 @@
var/obj/item/organ/vocal_cords/Vc = user.getorganslot(ORGAN_SLOT_VOICE)
if(Vc)
if(istype(Vc, /obj/item/organ/vocal_cords/velvet))
if(client?.prefs.lewdchem)
if(client.prefs.cit_toggles & HYPNO)
msg += "<span class='velvet'><i>You feel your chords resonate looking at them.</i></span>\n"
@@ -803,10 +803,8 @@
else
hud_used.healthdoll.icon_state = "healthdoll_DEAD"
if(hud_used.staminas)
hud_used.staminas.icon_state = staminahudamount()
if(hud_used.staminabuffer)
hud_used.staminabuffer.icon_state = staminabufferhudamount()
hud_used.staminas?.update_icon_state()
hud_used.staminabuffer?.update_icon_state()
/mob/living/carbon/human/fully_heal(admin_revive = 0)
if(admin_revive)
@@ -46,6 +46,12 @@
return spec_return
if(mind)
if (mind.martial_art && mind.martial_art.dodge_chance)
if(!lying && dna && !dna.check_mutation(HULK))
if(prob(mind.martial_art.dodge_chance))
var/dodgemessage = pick("dodges under the projectile!","dodges to the right of the projectile!","jumps over the projectile!")
visible_message("<span class='danger'>[src] [dodgemessage]</span>", "<span class='userdanger'>You dodge the projectile!</span>")
return -1
if(mind.martial_art && !incapacitated(FALSE, TRUE) && mind.martial_art.can_use(src) && mind.martial_art.deflection_chance) //Some martial arts users can deflect projectiles!
if(prob(mind.martial_art.deflection_chance))
if(!lying && dna && !dna.check_mutation(HULK)) //But only if they're not lying down, and hulks can't do it
@@ -61,66 +67,36 @@
P.setAngle(rand(0, 360))//SHING
return FALSE
if(!(P.original == src && P.firer == src)) //can't block or reflect when shooting yourself
if(P.is_reflectable)
if(check_reflect(def_zone)) // Checks if you've passed a reflection% check
visible_message("<span class='danger'>The [P.name] gets reflected by [src]!</span>", \
"<span class='userdanger'>The [P.name] gets reflected by [src]!</span>")
// Find a turf near or on the original location to bounce to
if(P.starting)
var/new_x = P.starting.x + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
var/new_y = P.starting.y + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
var/turf/curloc = get_turf(src)
return ..()
// redirect the projectile
P.original = locate(new_x, new_y, P.z)
P.starting = curloc
P.firer = src
P.yo = new_y - curloc.y
P.xo = new_x - curloc.x
var/new_angle_s = P.Angle + rand(120,240)
while(new_angle_s > 180) // Translate to regular projectile degrees
new_angle_s -= 360
P.setAngle(new_angle_s)
/mob/living/carbon/human/check_reflect(def_zone)
if(wear_suit?.IsReflect(def_zone))
return TRUE
return ..()
return -1 // complete projectile permutation
if(check_shields(P, P.damage, "the [P.name]", PROJECTILE_ATTACK, P.armour_penetration))
P.on_hit(src, 100, def_zone)
return 2
return (..(P , def_zone))
/mob/living/carbon/human/proc/check_reflect(def_zone) //Reflection checks for anything in your l_hand, r_hand, or wear_suit based on the reflection chance of the object
if(wear_suit)
if(wear_suit.IsReflect(def_zone) == 1)
return 1
for(var/obj/item/I in held_items)
if(I.IsReflect(def_zone) == 1)
return 1
return 0
/mob/living/carbon/human/proc/check_shields(atom/AM, var/damage, attack_text = "the attack", attack_type = MELEE_ATTACK, armour_penetration = 0)
/mob/living/carbon/human/check_shields(atom/AM, damage, attack_text = "the attack", attack_type = MELEE_ATTACK, armour_penetration = 0)
. = ..()
if(.)
return
var/block_chance_modifier = round(damage / -3)
for(var/obj/item/I in held_items)
if(!istype(I, /obj/item/clothing))
var/final_block_chance = I.block_chance - (CLAMP((armour_penetration-I.armour_penetration)/2,0,100)) + block_chance_modifier //So armour piercing blades can still be parried by other blades, for example
if(I.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
return 1
if(wear_suit)
var/final_block_chance = wear_suit.block_chance - (CLAMP((armour_penetration-wear_suit.armour_penetration)/2,0,100)) + block_chance_modifier
if(wear_suit.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
return 1
return TRUE
if(w_uniform)
var/final_block_chance = w_uniform.block_chance - (CLAMP((armour_penetration-w_uniform.armour_penetration)/2,0,100)) + block_chance_modifier
if(w_uniform.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
return 1
return TRUE
if(wear_neck)
var/final_block_chance = wear_neck.block_chance - (CLAMP((armour_penetration-wear_neck.armour_penetration)/2,0,100)) + block_chance_modifier
if(wear_neck.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
return 1
return 0
return TRUE
return FALSE
/mob/living/carbon/human/can_embed(obj/item/I)
if(I.get_sharpness() || is_pointed(I) || is_type_in_typecache(I, GLOB.can_embed_types))
return TRUE
return FALSE
/mob/living/carbon/human/proc/check_block()
if(mind)
@@ -129,37 +105,7 @@
return FALSE
/mob/living/carbon/human/hitby(atom/movable/AM, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
if(dna && dna.species)
var/spec_return = dna.species.spec_hitby(AM, src)
if(spec_return)
return spec_return
var/obj/item/I
var/throwpower = 30
if(istype(AM, /obj/item))
I = AM
throwpower = I.throwforce
if(I.thrownby == src) //No throwing stuff at yourself to trigger hit reactions
return ..()
if(check_shields(AM, throwpower, "\the [AM.name]", THROWN_PROJECTILE_ATTACK))
hitpush = FALSE
skipcatch = TRUE
blocked = TRUE
else if(I)
if(I.throw_speed >= EMBED_THROWSPEED_THRESHOLD)
if(can_embed(I))
if(prob(I.embedding.embed_chance) && !HAS_TRAIT(src, TRAIT_PIERCEIMMUNE))
throw_alert("embeddedobject", /obj/screen/alert/embeddedobject)
var/obj/item/bodypart/L = pick(bodyparts)
L.embedded_objects |= I
I.add_mob_blood(src)//it embedded itself in you, of course it's bloody!
I.forceMove(src)
L.receive_damage(I.w_class*I.embedding.embedded_impact_pain_multiplier)
visible_message("<span class='danger'>[I] embeds itself in [src]'s [L.name]!</span>","<span class='userdanger'>[I] embeds itself in your [L.name]!</span>")
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded)
hitpush = FALSE
skipcatch = TRUE //can't catch the now embedded item
return ..()
return dna?.species?.spec_hitby(AM, src) || ..()
/mob/living/carbon/human/grabbedby(mob/living/carbon/user, supress_message = 0)
if(user == src && pulling && !pulling.anchored && grab_state >= GRAB_AGGRESSIVE && (HAS_TRAIT(src, TRAIT_FAT)) && ismonkey(pulling))
@@ -193,12 +139,12 @@
return dna.species.spec_attacked_by(I, user, affecting, a_intent, src)
/mob/living/carbon/human/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0)
/mob/living/carbon/human/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
if(user.a_intent == INTENT_HARM)
var/hulk_verb = pick("smash","pummel")
if(check_shields(user, 15, "the [hulk_verb]ing"))
. = ..(user, TRUE)
if(.)
return
..(user, 1)
var/hulk_verb = pick("smash","pummel")
playsound(loc, user.dna.species.attack_sound, 25, 1, -1)
var/message = "[user] has [hulk_verb]ed [src]!"
visible_message("<span class='danger'>[message]</span>", \
@@ -207,7 +153,8 @@
return 1
/mob/living/carbon/human/attack_hand(mob/user)
if(..()) //to allow surgery to return properly.
. = ..()
if(.) //To allow surgery to return properly.
return
if(ishuman(user))
var/mob/living/carbon/human/H = user
@@ -219,8 +166,7 @@
if(!affecting)
affecting = get_bodypart(BODY_ZONE_CHEST)
if(M.a_intent == INTENT_HELP)
..() //shaking
return 0
return ..() //shaking
if(M.a_intent == INTENT_DISARM) //Always drop item in hand, if no item, get stunned instead.
var/obj/item/I = get_active_held_item()
@@ -241,78 +187,69 @@
if(can_inject(M, 1, affecting))//Thick suits can stop monkey bites.
if(..()) //successful monkey bite, this handles disease contraction.
var/damage = rand(1, 3)
if(check_shields(M, damage, "the [M.name]"))
return 0
if(stat != DEAD)
apply_damage(damage, BRUTE, affecting, run_armor_check(affecting, "melee"))
apply_damage(damage, BRUTE, affecting, run_armor_check(affecting, "melee"))
return 1
/mob/living/carbon/human/attack_alien(mob/living/carbon/alien/humanoid/M)
if(check_shields(M, 0, "the M.name"))
visible_message("<span class='danger'>[M] attempted to touch [src]!</span>")
return 0
. = ..()
if(!.)
return
if(M.a_intent == INTENT_HARM)
if (w_uniform)
w_uniform.add_fingerprint(M)
var/damage = prob(90) ? 20 : 0
if(!damage)
playsound(loc, 'sound/weapons/slashmiss.ogg', 50, 1, -1)
visible_message("<span class='danger'>[M] has lunged at [src]!</span>", \
"<span class='userdanger'>[M] has lunged at [src]!</span>")
return 0
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
if(!affecting)
affecting = get_bodypart(BODY_ZONE_CHEST)
var/armor_block = run_armor_check(affecting, "melee", null, null,10)
if(..())
if(M.a_intent == INTENT_HARM)
if (w_uniform)
w_uniform.add_fingerprint(M)
var/damage = prob(90) ? 20 : 0
if(!damage)
playsound(loc, 'sound/weapons/slashmiss.ogg', 50, 1, -1)
visible_message("<span class='danger'>[M] has lunged at [src]!</span>", \
"<span class='userdanger'>[M] has lunged at [src]!</span>")
return 0
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
if(!affecting)
affecting = get_bodypart(BODY_ZONE_CHEST)
var/armor_block = run_armor_check(affecting, "melee", null, null,10)
playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
visible_message("<span class='danger'>[M] has slashed at [src]!</span>", \
"<span class='userdanger'>[M] has slashed at [src]!</span>")
log_combat(M, src, "attacked")
if(!dismembering_strike(M, M.zone_selected)) //Dismemberment successful
return 1
apply_damage(damage, BRUTE, affecting, armor_block)
playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
visible_message("<span class='danger'>[M] has slashed at [src]!</span>", \
"<span class='userdanger'>[M] has slashed at [src]!</span>")
log_combat(M, src, "attacked")
if(!dismembering_strike(M, M.zone_selected)) //Dismemberment successful
return 1
apply_damage(damage, BRUTE, affecting, armor_block)
if(M.a_intent == INTENT_DISARM) //Always drop item in hand, if no item, get stun instead.
var/obj/item/I = get_active_held_item()
if(I && dropItemToGround(I))
playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1)
visible_message("<span class='danger'>[M] disarmed [src]!</span>", \
"<span class='userdanger'>[M] disarmed [src]!</span>")
if(M.a_intent == INTENT_DISARM) //Always drop item in hand, if no item, get stun instead.
var/obj/item/I = get_active_held_item()
if(I && dropItemToGround(I))
playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1)
visible_message("<span class='danger'>[M] disarmed [src]!</span>", \
"<span class='userdanger'>[M] disarmed [src]!</span>")
else
playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
if(!lying) //CITADEL EDIT
Knockdown(100, TRUE, FALSE, 30, 25)
else
playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
if(!lying) //CITADEL EDIT
Knockdown(100, TRUE, FALSE, 30, 25)
else
Knockdown(100)
log_combat(M, src, "tackled")
visible_message("<span class='danger'>[M] has tackled down [src]!</span>", \
"<span class='userdanger'>[M] has tackled down [src]!</span>")
Knockdown(100)
log_combat(M, src, "tackled")
visible_message("<span class='danger'>[M] has tackled down [src]!</span>", \
"<span class='userdanger'>[M] has tackled down [src]!</span>")
/mob/living/carbon/human/attack_larva(mob/living/carbon/alien/larva/L)
if(..()) //successful larva bite.
var/damage = rand(1, 3)
if(check_shields(L, damage, "the [L.name]"))
return 0
if(stat != DEAD)
L.amount_grown = min(L.amount_grown + damage, L.max_grown)
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(L.zone_selected))
if(!affecting)
affecting = get_bodypart(BODY_ZONE_CHEST)
var/armor_block = run_armor_check(affecting, "melee")
apply_damage(damage, BRUTE, affecting, armor_block)
. = ..()
if(!.) //unsuccessful larva bite.
return
var/damage = rand(1, 3)
if(stat != DEAD)
L.amount_grown = min(L.amount_grown + damage, L.max_grown)
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(L.zone_selected))
if(!affecting)
affecting = get_bodypart(BODY_ZONE_CHEST)
var/armor_block = run_armor_check(affecting, "melee")
apply_damage(damage, BRUTE, affecting, armor_block)
/mob/living/carbon/human/attack_animal(mob/living/simple_animal/M)
. = ..()
if(.)
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
if(check_shields(M, damage, "the [M.name]", MELEE_ATTACK, M.armour_penetration))
return FALSE
var/dam_zone = dismembering_strike(M, pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
if(!dam_zone) //Dismemberment successful
return TRUE
@@ -324,23 +261,22 @@
/mob/living/carbon/human/attack_slime(mob/living/simple_animal/slime/M)
if(..()) //successful slime attack
var/damage = rand(5, 25)
if(M.is_adult)
damage = rand(10, 35)
. = ..()
if(!.) //unsuccessful slime attack
return
var/damage = rand(5, 25)
if(M.is_adult)
damage = rand(10, 35)
if(check_shields(M, damage, "the [M.name]"))
return 0
var/dam_zone = dismembering_strike(M, pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
if(!dam_zone) //Dismemberment successful
return 1
var/dam_zone = dismembering_strike(M, pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
if(!dam_zone) //Dismemberment successful
return 1
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
if(!affecting)
affecting = get_bodypart(BODY_ZONE_CHEST)
var/armor_block = run_armor_check(affecting, "melee")
apply_damage(damage, BRUTE, affecting, armor_block)
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
if(!affecting)
affecting = get_bodypart(BODY_ZONE_CHEST)
var/armor_block = run_armor_check(affecting, "melee")
apply_damage(damage, BRUTE, affecting, armor_block)
/mob/living/carbon/human/mech_melee_attack(obj/mecha/M)
if(M.occupant.a_intent == INTENT_HARM)
@@ -644,7 +580,7 @@
if(mind)
if((mind.assigned_role == "Station Engineer") || (mind.assigned_role == "Chief Engineer") )
gain = 100
if(mind.assigned_role == "Clown")
if(HAS_TRAIT(mind, TRAIT_CLOWN_MENTALITY))
gain = rand(-300, 300)
investigate_log("([key_name(src)]) has been consumed by the singularity.", INVESTIGATE_SINGULO) //Oh that's where the clown ended up!
gib()
@@ -117,7 +117,8 @@
/mob/living/carbon/human/can_use_guns(obj/item/G)
. = ..()
if(!.)
return
if(G.trigger_guard == TRIGGER_GUARD_NORMAL)
if(HAS_TRAIT(src, TRAIT_CHUNKYFINGERS))
to_chat(src, "<span class='warning'>Your meaty finger is much too large for the trigger guard!</span>")
@@ -126,7 +127,13 @@
to_chat(src, "<span class='warning'>Your fingers don't fit in the trigger guard!</span>")
return FALSE
return .
/mob/living/carbon/human/can_see_reagents()
. = ..()
if(.) //No need to run through all of this if it's already true.
return
if(isclothing(glasses) && (glasses.clothing_flags & SCAN_REAGENTS))
return TRUE
/*
/mob/living/carbon/human/transfer_blood_dna(list/blood_dna)
..()
+26 -35
View File
@@ -545,6 +545,20 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
//Underwear, Undershirts & Socks
if(!(NO_UNDERWEAR in species_traits))
if(H.socks && H.get_num_legs(FALSE) >= 2)
if(H.hidden_socks)
H.socks = "Nude"
else
H.socks = H.saved_socks
var/datum/sprite_accessory/underwear/socks/S = GLOB.socks_list[H.socks]
if(S)
var/digilegs = ((DIGITIGRADE in species_traits) && S.has_digitigrade) ? "_d" : ""
var/mutable_appearance/MA = mutable_appearance(S.icon, "[S.icon_state][digilegs]", -BODY_LAYER)
if(S.has_color)
MA.color = "#[H.socks_color]"
standing += MA
if(H.underwear)
if(H.hidden_underwear)
H.underwear = "Nude"
@@ -552,8 +566,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
H.underwear = H.saved_underwear
var/datum/sprite_accessory/underwear/bottom/B = GLOB.underwear_list[H.underwear]
if(B)
var/mutable_appearance/MA = mutable_appearance(B.icon, B.icon_state, -BODY_LAYER)
if(UNDIE_COLORABLE(B))
var/digilegs = ((DIGITIGRADE in species_traits) && B.has_digitigrade) ? "_d" : ""
var/mutable_appearance/MA = mutable_appearance(B.icon, "[B.icon_state][digilegs]", -BODY_LAYER)
if(B.has_color)
MA.color = "#[H.undie_color]"
standing += MA
@@ -564,28 +579,16 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
H.undershirt = H.saved_undershirt
var/datum/sprite_accessory/underwear/top/T = GLOB.undershirt_list[H.undershirt]
if(T)
var/state = "[T.icon_state][((DIGITIGRADE in species_traits) && T.has_digitigrade) ? "_d" : ""]"
var/mutable_appearance/MA
if(H.dna.species.sexes && H.gender == FEMALE)
MA = wear_female_version(T.icon_state, T.icon, BODY_LAYER)
MA = wear_female_version(state, T.icon, BODY_LAYER)
else
MA = mutable_appearance(T.icon, T.icon_state, -BODY_LAYER)
if(UNDIE_COLORABLE(T))
MA = mutable_appearance(T.icon, state, -BODY_LAYER)
if(T.has_color)
MA.color = "#[H.shirt_color]"
standing += MA
if(H.socks && H.get_num_legs(FALSE) >= 2)
if(H.hidden_socks)
H.socks = "Nude"
else
H.socks = H.saved_socks
var/datum/sprite_accessory/underwear/socks/S = GLOB.socks_list[H.socks]
if(S)
var/digilegs = (DIGITIGRADE in species_traits) ? "_d" : ""
var/mutable_appearance/MA = mutable_appearance(S.icon, "[S.icon_state][digilegs]", -BODY_LAYER)
if(UNDIE_COLORABLE(S))
MA.color = "#[H.socks_color]"
standing += MA
if(standing.len)
H.overlays_standing[BODY_LAYER] = standing
@@ -781,6 +784,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
S = GLOB.insect_wings_list[H.dna.features["insect_wings"]]
if("insect_fluff")
S = GLOB.insect_fluffs_list[H.dna.features["insect_fluff"]]
if("insect_markings")
S = GLOB.insect_markings_list[H.dna.features["insect_markings"]]
if("caps")
S = GLOB.caps_list[H.dna.features["caps"]]
if("ipc_screen")
@@ -1587,20 +1592,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
user.adjustStaminaLossBuffered(3)
return FALSE
else if(aim_for_groin && (target == user || target.lying || same_dir) && (target_on_help || target_restrained || target_aiming_for_groin))
if(target.client?.prefs.cit_toggles & NO_ASS_SLAP)
to_chat(user,"A force stays your hand, preventing you from slapping \the [target]'s ass!")
return FALSE
user.do_attack_animation(target, ATTACK_EFFECT_ASS_SLAP)
user.adjustStaminaLossBuffered(3)
if(HAS_TRAIT(target, TRAIT_ASSBLASTUSA))
var/hit_zone = (user.held_index_to_dir(user.active_hand_index) == "l" ? "l_":"r_") + "arm"
user.adjustStaminaLoss(20, affected_zone = hit_zone)
user.visible_message(\
"<span class='danger'>\The [user] slaps \the [target]'s ass, but their hand bounces off like they hit metal!</span>",\
"<span class='danger'>You slap [user == target ? "your" : "\the [target]'s"] ass, but feel an intense amount of pain as you realise their buns are harder than steel!</span>",\
"You hear a slap."
)
playsound(target.loc, 'sound/weapons/tap.ogg', 50, 1, -1)
user.emote("scream")
return FALSE
playsound(target.loc, 'sound/weapons/slap.ogg', 50, 1, -1)
user.visible_message(\
"<span class='danger'>\The [user] slaps \the [target]'s ass!</span>",\
@@ -1689,11 +1685,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
attacker_style = M.mind.martial_art
if(attacker_style?.pacifism_check && HAS_TRAIT(M, TRAIT_PACIFISM)) // most martial arts are quite harmful, alas.
attacker_style = null
if((M != H) && M.a_intent != INTENT_HELP && H.check_shields(M, 0, M.name, attack_type = UNARMED_ATTACK))
log_combat(M, H, "attempted to touch")
H.visible_message("<span class='warning'>[M] attempted to touch [H]!</span>")
return 0
SEND_SIGNAL(M, COMSIG_MOB_ATTACK_HAND, M, H, attacker_style)
switch(M.a_intent)
if("help")
help(M, H, attacker_style)
@@ -4,9 +4,9 @@
default_color = "00FF00"
species_traits = list(LIPS,EYECOLOR,HAIR,FACEHAIR,MUTCOLORS,HORNCOLOR,WINGCOLOR)
inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID, MOB_BUG)
mutant_bodyparts = list("mam_ears", "mam_snout", "mam_tail", "taur", "insect_wings", "mam_snouts", "insect_fluff","horns")
mutant_bodyparts = list("mam_ears","mam_tail", "taur", "insect_wings","mam_snout", "mam_snouts", "insect_fluff","insect_markings")
default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "None", "mam_ears" = "None",
"insect_wings" = "None", "insect_fluff" = "None", "mam_snouts" = "None", "taur" = "None","horns" = "None")
"insect_wings" = "None", "insect_fluff" = "None", "mam_snouts" = "None", "taur" = "None", "insect_markings" = "None")
attack_verb = "slash"
attack_sound = 'sound/weapons/slash.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
@@ -51,11 +51,7 @@
. = ..()
to_chat(C, "[info_text]")
C.real_name = "[pick(GLOB.nightmare_names)]"
C.name = C.real_name
if(C.mind)
C.mind.name = C.real_name
C.dna.real_name = C.real_name
C.fully_replace_character_name("[pick(GLOB.nightmare_names)]")
/datum/species/shadow/nightmare/bullet_act(obj/item/projectile/P, mob/living/carbon/human/H)
var/turf/T = H.loc
@@ -127,8 +123,8 @@
/obj/item/organ/heart/nightmare/Remove(mob/living/carbon/M, special = 0)
respawn_progress = 0
if(blade && special != HEART_SPECIAL_SHADOWIFY)
QDEL_NULL(blade)
M.visible_message("<span class='warning'>\The [blade] disintegrates!</span>")
QDEL_NULL(blade)
..()
/obj/item/organ/heart/nightmare/Stop()
@@ -183,15 +179,21 @@
. = ..()
if(!proximity)
return
if(isopenturf(AM)) //So you can actually melee with it
return
if(isliving(AM))
if(isopenturf(AM))
var/turf/open/T = AM
if(T.light_range && !isspaceturf(T)) //no fairy grass or light tile can escape the fury of the darkness.
to_chat(user, "<span class='notice'>You scrape away [T] with your [name] and snuff out its lights.</span>")
T.ScrapeAway(flags = CHANGETURF_INHERIT_AIR)
else if(isliving(AM))
var/mob/living/L = AM
if(iscyborg(AM))
var/mob/living/silicon/robot/borg = AM
if(!borg.lamp_cooldown)
if(borg.lamp_intensity)
borg.update_headlamp(TRUE, INFINITY)
to_chat(borg, "<span class='danger'>Your headlamp is fried! You'll need a human to help replace it.</span>")
for(var/obj/item/assembly/flash/cyborg/F in borg.held_items)
if(!F.crit_fail)
F.burn_out()
else
for(var/obj/item/O in AM)
if(O.light_range && O.light_power)
@@ -369,6 +369,23 @@
retaliate(L)
return ..()
/mob/living/carbon/monkey/attack_alien(mob/living/carbon/alien/humanoid/M)
if(M.a_intent == INTENT_HARM && prob(MONKEY_RETALIATE_HARM_PROB))
retaliate(M)
else if(M.a_intent == INTENT_DISARM && prob(MONKEY_RETALIATE_DISARM_PROB))
retaliate(M)
return ..()
/mob/living/carbon/monkey/attack_larva(mob/living/carbon/alien/larva/L)
if(L.a_intent == INTENT_HARM && prob(MONKEY_RETALIATE_HARM_PROB))
retaliate(L)
return ..()
/mob/living/carbon/monkey/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
if(user.a_intent == INTENT_HARM && prob(MONKEY_RETALIATE_HARM_PROB))
retaliate(user)
return ..()
/mob/living/carbon/monkey/attack_paw(mob/living/L)
if(L.a_intent == INTENT_HARM && prob(MONKEY_RETALIATE_HARM_PROB))
retaliate(L)
@@ -6,37 +6,55 @@
..()
/mob/living/carbon/monkey/attack_paw(mob/living/M)
if(..()) //successful monkey bite.
var/dam_zone = pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
if(!affecting)
affecting = get_bodypart(BODY_ZONE_CHEST)
if(M.limb_destroyer)
dismembering_strike(M, affecting.body_zone)
if(stat != DEAD)
var/dmg = rand(1, 5)
apply_damage(dmg, BRUTE, affecting)
. = ..()
if(!.) //unsuccessful monkey bite.
return
var/dam_zone = pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
if(!affecting)
affecting = get_bodypart(BODY_ZONE_CHEST)
if(M.limb_destroyer)
dismembering_strike(M, affecting.body_zone)
var/dmg = rand(1, 5)
apply_damage(dmg, BRUTE, affecting)
/mob/living/carbon/monkey/attack_larva(mob/living/carbon/alien/larva/L)
if(..()) //successful larva bite.
var/damage = rand(1, 3)
if(stat != DEAD)
L.amount_grown = min(L.amount_grown + damage, L.max_grown)
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(L.zone_selected))
if(!affecting)
affecting = get_bodypart(BODY_ZONE_CHEST)
apply_damage(damage, BRUTE, affecting)
. = ..()
if(!.) //unsuccessful larva bite
return
var/damage = rand(1, 3)
if(stat != DEAD)
L.amount_grown = min(L.amount_grown + damage, L.max_grown)
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(L.zone_selected))
if(!affecting)
affecting = get_bodypart(BODY_ZONE_CHEST)
apply_damage(damage, BRUTE, affecting)
/mob/living/carbon/monkey/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
. = ..(user, TRUE)
if(.)
return
var/hulk_verb = pick("smash","pummel")
playsound(loc, user.dna.species.attack_sound, 25, 1, -1)
var/message = "[user] has [hulk_verb]ed [src]!"
visible_message("<span class='danger'>[message]</span>", \
"<span class='userdanger'>[message]</span>")
adjustBruteLoss(15)
return TRUE
/mob/living/carbon/monkey/attack_hand(mob/living/carbon/human/M)
if(..()) //To allow surgery to return properly.
. = ..()
if(.) //To allow surgery to return properly.
return
switch(M.a_intent)
if("help")
if(INTENT_HELP)
help_shake_act(M)
if("grab")
if(INTENT_GRAB)
grabbedby(M)
if("harm")
if(INTENT_HARM)
if(HAS_TRAIT(M, TRAIT_PACIFISM))
to_chat(M, "<span class='notice'>You don't want to hurt [src]!</span>")
return
M.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
if (prob(75))
visible_message("<span class='danger'>[M] has punched [name]!</span>", \
@@ -60,7 +78,7 @@
playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
visible_message("<span class='danger'>[M] has attempted to punch [name]!</span>", \
"<span class='userdanger'>[M] has attempted to punch [name]!</span>", null, COMBAT_MESSAGE_RANGE)
if("disarm")
if(INTENT_DISARM)
if(!IsUnconscious())
M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
if (prob(25))
@@ -74,50 +92,51 @@
visible_message("<span class='danger'>[M] has disarmed [src]!</span>", "<span class='userdanger'>[M] has disarmed [src]!</span>", null, COMBAT_MESSAGE_RANGE)
/mob/living/carbon/monkey/attack_alien(mob/living/carbon/alien/humanoid/M)
if(..()) //if harm or disarm intent.
if (M.a_intent == INTENT_HARM)
if ((prob(95) && health > 0))
playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
var/damage = rand(15, 30)
if (damage >= 25)
damage = rand(20, 40)
if(AmountUnconscious() < 300)
Unconscious(rand(200, 300))
visible_message("<span class='danger'>[M] has wounded [name]!</span>", \
"<span class='userdanger'>[M] has wounded [name]!</span>", null, COMBAT_MESSAGE_RANGE)
else
visible_message("<span class='danger'>[M] has slashed [name]!</span>", \
"<span class='userdanger'>[M] has slashed [name]!</span>", null, COMBAT_MESSAGE_RANGE)
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
log_combat(M, src, "attacked")
if(!affecting)
affecting = get_bodypart(BODY_ZONE_CHEST)
if(!dismembering_strike(M, affecting.body_zone)) //Dismemberment successful
return 1
apply_damage(damage, BRUTE, affecting)
. = ..()
if(!.) // the attack was blocked or was help/grab intent
return
if (M.a_intent == INTENT_HARM)
if ((prob(95) && health > 0))
playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
var/damage = rand(15, 30)
if (damage >= 25)
damage = rand(20, 40)
if(AmountUnconscious() < 300)
Unconscious(rand(200, 300))
visible_message("<span class='danger'>[M] has wounded [name]!</span>", \
"<span class='userdanger'>[M] has wounded [name]!</span>", null, COMBAT_MESSAGE_RANGE)
else
playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1)
visible_message("<span class='danger'>[M] has attempted to lunge at [name]!</span>", \
"<span class='userdanger'>[M] has attempted to lunge at [name]!</span>", null, COMBAT_MESSAGE_RANGE)
visible_message("<span class='danger'>[M] has slashed [name]!</span>", \
"<span class='userdanger'>[M] has slashed [name]!</span>", null, COMBAT_MESSAGE_RANGE)
if (M.a_intent == INTENT_DISARM)
var/obj/item/I = null
playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
if(prob(95))
Knockdown(20)
visible_message("<span class='danger'>[M] has tackled down [name]!</span>", \
"<span class='userdanger'>[M] has tackled down [name]!</span>", null, COMBAT_MESSAGE_RANGE)
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
log_combat(M, src, "attacked")
if(!affecting)
affecting = get_bodypart(BODY_ZONE_CHEST)
if(!dismembering_strike(M, affecting.body_zone)) //Dismemberment successful
return 1
apply_damage(damage, BRUTE, affecting)
else
playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1)
visible_message("<span class='danger'>[M] has attempted to lunge at [name]!</span>", \
"<span class='userdanger'>[M] has attempted to lunge at [name]!</span>", null, COMBAT_MESSAGE_RANGE)
else
var/obj/item/I = null
playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
if(prob(95))
Knockdown(20)
visible_message("<span class='danger'>[M] has tackled down [name]!</span>", \
"<span class='userdanger'>[M] has tackled down [name]!</span>", null, COMBAT_MESSAGE_RANGE)
else
I = get_active_held_item()
if(dropItemToGround(I))
visible_message("<span class='danger'>[M] has disarmed [name]!</span>", "<span class='userdanger'>[M] has disarmed [name]!</span>", null, COMBAT_MESSAGE_RANGE)
else
I = get_active_held_item()
if(dropItemToGround(I))
visible_message("<span class='danger'>[M] has disarmed [name]!</span>", "<span class='userdanger'>[M] has disarmed [name]!</span>", null, COMBAT_MESSAGE_RANGE)
else
I = null
log_combat(M, src, "disarmed", "[I ? " removing \the [I]" : ""]")
updatehealth()
I = null
log_combat(M, src, "disarmed", "[I ? " removing \the [I]" : ""]")
updatehealth()
/mob/living/carbon/monkey/attack_animal(mob/living/simple_animal/M)
. = ..()
@@ -132,17 +151,19 @@
apply_damage(damage, M.melee_damage_type, affecting)
/mob/living/carbon/monkey/attack_slime(mob/living/simple_animal/slime/M)
if(..()) //successful slime attack
var/damage = rand(5, 35)
if(M.is_adult)
damage = rand(20, 40)
var/dam_zone = dismembering_strike(M, pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
if(!dam_zone) //Dismemberment successful
return 1
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
if(!affecting)
affecting = get_bodypart(BODY_ZONE_CHEST)
apply_damage(damage, BRUTE, affecting)
. = ..()
if(!.) //unsuccessful slime attack
return
var/damage = rand(5, 35)
if(M.is_adult)
damage = rand(20, 40)
var/dam_zone = dismembering_strike(M, pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
if(!dam_zone) //Dismemberment successful
return 1
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
if(!affecting)
affecting = get_bodypart(BODY_ZONE_CHEST)
apply_damage(damage, BRUTE, affecting)
/mob/living/carbon/monkey/acid_act(acidpwr, acid_volume, bodyzone_hit)
. = 1
+3 -1
View File
@@ -91,7 +91,9 @@
if(mind && mind.name && mind.active && !istype(T.loc, /area/ctf) && !(signal & COMPONENT_BLOCK_DEATH_BROADCAST))
var/rendered = "<span class='deadsay'><b>[mind.name]</b> has died at <b>[get_area_name(T)]</b>.</span>"
deadchat_broadcast(rendered, follow_target = src, turf_target = T, message_type=DEADCHAT_DEATHRATTLE)
if (client && client.prefs && client.prefs.auto_ooc)
if (!(client.prefs.chat_toggles & CHAT_OOC))
client.prefs.chat_toggles ^= CHAT_OOC
if (client)
client.move_delay = initial(client.move_delay)
+113 -18
View File
@@ -36,7 +36,50 @@
/mob/living/proc/on_hit(obj/item/projectile/P)
return
/mob/living/proc/check_shields(atom/AM, damage, attack_text = "the attack", attack_type = MELEE_ATTACK, armour_penetration = 0)
var/block_chance_modifier = round(damage / -3)
for(var/obj/item/I in held_items)
if(!istype(I, /obj/item/clothing))
var/final_block_chance = I.block_chance - (CLAMP((armour_penetration-I.armour_penetration)/2,0,100)) + block_chance_modifier //So armour piercing blades can still be parried by other blades, for example
if(I.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
return TRUE
return FALSE
/mob/living/proc/check_reflect(def_zone) //Reflection checks for anything in your hands, based on the reflection chance of the object(s)
for(var/obj/item/I in held_items)
if(I.IsReflect(def_zone))
return TRUE
return FALSE
/mob/living/proc/reflect_bullet_check(obj/item/projectile/P, def_zone)
if(P.is_reflectable && check_reflect(def_zone)) // Checks if you've passed a reflection% check
visible_message("<span class='danger'>The [P.name] gets reflected by [src]!</span>", \
"<span class='userdanger'>The [P.name] gets reflected by [src]!</span>")
// Find a turf near or on the original location to bounce to
if(P.starting)
var/new_x = P.starting.x + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
var/new_y = P.starting.y + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
var/turf/curloc = get_turf(src)
// redirect the projectile
P.original = locate(new_x, new_y, P.z)
P.starting = curloc
P.firer = src
P.yo = new_y - curloc.y
P.xo = new_x - curloc.x
var/new_angle_s = P.Angle + rand(120,240)
while(new_angle_s > 180) // Translate to regular projectile degrees
new_angle_s -= 360
P.setAngle(new_angle_s)
return TRUE
return FALSE
/mob/living/bullet_act(obj/item/projectile/P, def_zone)
if(P.original != src || P.firer != src) //try to block or reflect the bullet, can't do so when shooting oneself
if(reflect_bullet_check(P, def_zone))
return -1 // complete projectile permutation
if(check_shields(P, P.damage, "the [P.name]", PROJECTILE_ATTACK, P.armour_penetration))
P.on_hit(src, 100, def_zone)
return 2
var/armor = run_armor_check(def_zone, P.flag, null, null, P.armour_penetration, null)
if(!P.nodamage)
apply_damage(P.damage, P.damage_type, def_zone, armor)
@@ -55,9 +98,32 @@
else
return 0
/mob/living/proc/catch_item(obj/item/I, skip_throw_mode_check = FALSE)
return FALSE
/mob/living/proc/embed_item(obj/item/I)
return
/mob/living/proc/can_embed(obj/item/I)
return FALSE
/mob/living/hitby(atom/movable/AM, skipcatch, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
if(istype(AM, /obj/item))
var/obj/item/I = AM
var/obj/item/I
var/throwpower = 30
if(isitem(AM))
I = AM
throwpower = I.throwforce
if(check_shields(AM, throwpower, "\the [AM.name]", THROWN_PROJECTILE_ATTACK))
hitpush = FALSE
skipcatch = TRUE
blocked = TRUE
else if(I && I.throw_speed >= EMBED_THROWSPEED_THRESHOLD && can_embed(I, src) && prob(I.embedding.embed_chance) && !HAS_TRAIT(src, TRAIT_PIERCEIMMUNE) && (!HAS_TRAIT(src, TRAIT_AUTO_CATCH_ITEM) || incapacitated() || get_active_held_item()))
embed_item(I)
hitpush = FALSE
skipcatch = TRUE //can't catch the now embedded item
if(I)
if(!skipcatch && isturf(I.loc) && catch_item(I))
return TRUE
var/zone = ran_zone(BODY_ZONE_CHEST, 65)//Hits a random part of the body, geared towards the chest
var/dtype = BRUTE
var/volume = I.get_volume_by_throwforce_and_or_w_class()
@@ -214,6 +280,24 @@
Move(user.loc)
return 1
/mob/living/attack_hand(mob/user)
..() //Ignoring parent return value here.
SEND_SIGNAL(src, COMSIG_MOB_ATTACK_HAND, user)
if((user != src) && user.a_intent != INTENT_HELP && check_shields(user, 0, user.name, attack_type = UNARMED_ATTACK))
log_combat(user, src, "attempted to touch")
visible_message("<span class='warning'>[user] attempted to touch [src]!</span>")
return TRUE
/mob/living/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
if(user.a_intent == INTENT_HARM)
if(HAS_TRAIT(user, TRAIT_PACIFISM))
to_chat(user, "<span class='notice'>You don't want to hurt [src]!</span>")
return TRUE
var/hulk_verb = pick("smash","pummel")
if(user != src && check_shields(user, 15, "the [hulk_verb]ing"))
return TRUE
..()
return FALSE
/mob/living/attack_slime(mob/living/simple_animal/slime/M)
if(!SSticker.HasRoundStarted())
@@ -229,6 +313,12 @@
to_chat(M, "<span class='notice'>You don't want to hurt anyone!</span>")
return FALSE
var/damage = rand(5, 35)
if(M.is_adult)
damage = rand(20, 40)
if(check_shields(M, damage, "the [M.name]"))
return FALSE
if (stat != DEAD)
log_combat(M, src, "attacked")
M.do_attack_animation(src)
@@ -245,7 +335,8 @@
if(HAS_TRAIT(M, TRAIT_PACIFISM))
to_chat(M, "<span class='notice'>You don't want to hurt anyone!</span>")
return FALSE
if(check_shields(M, rand(M.melee_damage_lower, M.melee_damage_upper), "the [M.name]", MELEE_ATTACK, M.armour_penetration))
return FALSE
if(M.attack_sound)
playsound(loc, M.attack_sound, 50, 1, 1)
M.do_attack_animation(src)
@@ -256,10 +347,6 @@
/mob/living/attack_paw(mob/living/carbon/monkey/M)
if(isturf(loc) && istype(loc.loc, /area/start))
to_chat(M, "No attacking people at spawn, you jackass.")
return FALSE
if (M.a_intent == INTENT_HARM)
if(HAS_TRAIT(M, TRAIT_PACIFISM))
to_chat(M, "<span class='notice'>You don't want to hurt anyone!</span>")
@@ -268,6 +355,8 @@
if(M.is_muzzled() || (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSMOUTH))
to_chat(M, "<span class='warning'>You can't bite with your mouth covered!</span>")
return FALSE
if(check_shields(M, 0, "the [M.name]"))
return FALSE
M.do_attack_animation(src, ATTACK_EFFECT_BITE)
if (prob(75))
log_combat(M, src, "attacked")
@@ -282,15 +371,16 @@
/mob/living/attack_larva(mob/living/carbon/alien/larva/L)
switch(L.a_intent)
if("help")
if(INTENT_HELP)
visible_message("<span class='notice'>[L.name] rubs its head against [src].</span>")
return FALSE
else
if(HAS_TRAIT(L, TRAIT_PACIFISM))
to_chat(L, "<span class='notice'>You don't want to hurt anyone!</span>")
return
return FALSE
if(L != src && check_shields(L, rand(1, 3), "the [L.name]"))
return FALSE
L.do_attack_animation(src)
if(prob(90))
log_combat(L, src, "attacked")
@@ -301,24 +391,29 @@
else
visible_message("<span class='danger'>[L.name] has attempted to bite [src]!</span>", \
"<span class='userdanger'>[L.name] has attempted to bite [src]!</span>", null, COMBAT_MESSAGE_RANGE)
return FALSE
/mob/living/attack_alien(mob/living/carbon/alien/humanoid/M)
if((M != src) && M.a_intent != INTENT_HELP && check_shields(M, 0, "the [M.name]"))
visible_message("<span class='danger'>[M] attempted to touch [src]!</span>")
return FALSE
switch(M.a_intent)
if ("help")
visible_message("<span class='notice'>[M] caresses [src] with its scythe like arm.</span>")
if (INTENT_HELP)
if(!isalien(src)) //I know it's ugly, but the alien vs alien attack_alien behaviour is a bit different.
visible_message("<span class='notice'>[M] caresses [src] with its scythe like arm.</span>")
return FALSE
if ("grab")
if (INTENT_GRAB)
grabbedby(M)
return FALSE
if("harm")
if(INTENT_HARM)
if(HAS_TRAIT(M, TRAIT_PACIFISM))
to_chat(M, "<span class='notice'>You don't want to hurt anyone!</span>")
return FALSE
M.do_attack_animation(src)
if(!isalien(src))
M.do_attack_animation(src)
return TRUE
if("disarm")
M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
if(INTENT_DISARM)
if(!isalien(src))
M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
return TRUE
/mob/living/ex_act(severity, target, origin)
-9
View File
@@ -260,15 +260,6 @@
viewalerts = 1
src << browse(dat, "window=aialerts&can_close=0")
/mob/living/silicon/ai/proc/ai_roster()
var/dat = "<html><head><title>Crew Roster</title></head><body><b>Crew Roster:</b><br><br>"
dat += GLOB.data_core.get_manifest()
dat += "</body></html>"
src << browse(dat, "window=airoster")
onclose(src, "airoster")
/mob/living/silicon/ai/proc/ai_call_shuttle()
if(control_disabled)
to_chat(usr, "<span class='warning'>Wireless control is disabled!</span>")
@@ -1,15 +1,9 @@
/mob/living/silicon/ai/attacked_by(obj/item/I, mob/living/user, def_zone)
. = ..()
if(!.)
return FALSE
if(I.force && I.damtype != STAMINA && stat != DEAD) //only sparks if real damage is dealt.
spark_system.start()
return ..()
/mob/living/silicon/ai/attack_alien(mob/living/carbon/alien/humanoid/M)
if(!SSticker.HasRoundStarted())
to_chat(M, "You cannot attack people before the game has started.")
return
..()
/mob/living/silicon/ai/attack_slime(mob/living/simple_animal/slime/user)
return //immune to slimes
@@ -26,13 +26,14 @@
fold_in(force = 1)
Knockdown(200)
//ATTACK HAND IGNORING PARENT RETURN VALUE
/mob/living/silicon/pai/attack_hand(mob/living/carbon/human/user)
switch(user.a_intent)
if("help")
if(INTENT_HELP)
visible_message("<span class='notice'>[user] gently pats [src] on the head, eliciting an off-putting buzzing from its holographic field.</span>")
if("disarm")
if(INTENT_DISARM)
visible_message("<span class='notice'>[user] boops [src] on the head!</span>")
if("harm")
if(INTENT_HARM)
user.do_attack_animation(src)
if (user.name == master)
visible_message("<span class='notice'>Responding to its master's touch, [src] disengages its holochassis emitter, rapidly losing coherence.</span>")
@@ -41,14 +42,19 @@
if(user.put_in_hands(card))
user.visible_message("<span class='notice'>[user] promptly scoops up [user.p_their()] pAI's card.</span>")
else
if(HAS_TRAIT(user, TRAIT_PACIFISM))
to_chat(user, "<span class='notice'>You don't want to hurt [src]!</span>")
return
visible_message("<span class='danger'>[user] stomps on [src]!.</span>")
take_holo_damage(2)
else
grabbedby(user)
/mob/living/silicon/pai/bullet_act(obj/item/projectile/Proj)
if(Proj.stun)
/mob/living/silicon/pai/bullet_act(obj/item/projectile/P, def_zone)
if(P.stun)
fold_in(force = TRUE)
src.visible_message("<span class='warning'>The electrically-charged projectile disrupts [src]'s holomatrix, forcing [src] to fold in!</span>")
. = ..(Proj)
visible_message("<span class='warning'>The electrically-charged projectile disrupts [src]'s holomatrix, forcing [src] to fold in!</span>")
. = ..()
/mob/living/silicon/pai/stripPanelUnequip(obj/item/what, mob/who, where) //prevents stripping
to_chat(src, "<span class='warning'>Your holochassis stutters and warps intensely as you attempt to interact with the object, forcing you to cease lest the field fail.</span>")
@@ -63,7 +69,8 @@
emitterhealth = CLAMP((emitterhealth - amount), -50, emittermaxhealth)
if(emitterhealth < 0)
fold_in(force = TRUE)
to_chat(src, "<span class='userdanger'>The impact degrades your holochassis!</span>")
if(amount > 0)
to_chat(src, "<span class='userdanger'>The impact degrades your holochassis!</span>")
return amount
/mob/living/silicon/pai/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE)
@@ -1298,4 +1298,12 @@
/mob/living/silicon/robot/adjustStaminaLossBuffered(amount, updating_health = 1)
if(istype(cell))
cell.charge -= amount*5
cell.charge -= amount*5
/mob/living/silicon/robot/verb/viewmanifest()
set category = "Robot Commands"
set name = "View Crew Manifest"
if(usr.stat == DEAD)
return //won't work if dead
ai_roster()

Some files were not shown because too many files have changed in this diff Show More