Merge branch 'master' into hook-kill-v10-final-ultimate-final

This commit is contained in:
AffectedArc07
2020-07-02 11:17:30 +01:00
committed by GitHub
414 changed files with 23025 additions and 3199 deletions
+2 -2
View File
@@ -187,12 +187,12 @@
log_game("SQL ERROR obtaining ckey from notes table. Error : \[[err]\]\n")
return
to_chat(usr, "<span class='notice'>Started regex note search for [search]. Please wait for results...</span>")
message_admins("[usr] has started a note search with regex [search]. CPU usage may be higher.")
message_admins("[usr.ckey] has started a note search with the following regex: [search] | CPU usage may be higher.")
while(query_list_notes.NextRow())
index_ckey = query_list_notes.item[1]
output += "<a href='?_src_=holder;shownoteckey=[index_ckey]'>[index_ckey]</a><br>"
CHECK_TICK
message_admins("The note search started by [usr] has complete. CPU should return to normal.")
message_admins("The note search started by [usr.ckey] has complete. CPU should return to normal.")
else
output += "<center><a href='?_src_=holder;addnoteempty=1'>\[Add Note\]</a></center>"
output += ruler
+5 -4
View File
@@ -73,9 +73,11 @@
..()
if((ishuman(hit_atom)))
var/mob/living/carbon/human/H = hit_atom
if(H.r_hand == src) return
if(H.l_hand == src) return
var/mob/A = H.LAssailant
if(H.r_hand == src)
return
if(H.l_hand == src)
return
var/mob/A = thrownby
if((H in GLOB.team_alpha) && (A in GLOB.team_alpha))
to_chat(A, "<span class='warning'>He's on your team!</span>")
return
@@ -89,4 +91,3 @@
playsound(src, 'sound/items/dodgeball.ogg', 50, 1)
visible_message("<span class='danger'>[H] HAS BEEN ELIMINATED!</span>")
H.melt()
return
@@ -80,7 +80,7 @@
/obj/machinery/computer/mob_battle_terminal/proc/eject_card(override = 0)
if(!override)
if(ready && SSmob_hunt.battle_turn != team)
audible_message("You can't recall on your rival's turn!", null, 2)
atom_say("You can't recall on your rival's turn!")
return
card.mob_data = mob_info
mob_info = null
@@ -202,7 +202,7 @@
start_battle()
else if(option == 2)
ready = 0
audible_message("[team] Player cancels their battle challenge.", null, 5)
atom_say("[team] Player cancels their battle challenge.")
updateUsrDialog()
@@ -246,7 +246,7 @@
var/message = "[mob_info.mob_name] attacks!"
if(mob_info.nickname)
message = "[mob_info.nickname] attacks!"
audible_message(message, null, 5)
atom_say(message)
SSmob_hunt.launch_attack(team, mob_info.get_raw_damage(), mob_info.get_attack_type())
/obj/machinery/computer/mob_battle_terminal/proc/start_battle()
@@ -255,7 +255,7 @@
if(!card) //don't do anything if there isn't a card inserted
return
ready = 1
audible_message("[team] Player is ready for battle! Waiting for rival...", null, 5)
atom_say("[team] Player is ready for battle! Waiting for rival...")
SSmob_hunt.start_check()
/obj/machinery/computer/mob_battle_terminal/proc/receive_attack(raw_damage, datum/mob_type/attack_type)
@@ -268,7 +268,7 @@
SSmob_hunt.end_turn()
/obj/machinery/computer/mob_battle_terminal/proc/surrender()
audible_message("[team] Player surrenders the battle!", null, 5)
atom_say("[team] Player surrenders the battle!")
SSmob_hunt.end_battle(team, 1)
//////////////////////////////
+3 -3
View File
@@ -55,7 +55,7 @@
var/datum/data/pda/app/mob_hunter_game/client = P.current_app
var/total_catch_mod = client.catch_mod + catch_mod //negative values decrease the chance of the mob running, positive values makes it more likely to flee
if(!client.connected) //must be connected to attempt captures
P.audible_message("[bicon(P)] No server connection. Capture aborted.", null, 4)
P.atom_say("No server connection. Capture aborted.")
return
if(mob_info.is_trap) //traps work even if you ran into them before, which is why this is before the clients_encountered check
@@ -79,7 +79,7 @@
return
else //deal with the new hunter by either running away or getting caught
clients_encountered += client
var/message = "[bicon(P)] "
var/message = null
var/effective_run_chance = mob_info.run_chance + total_catch_mod
if((effective_run_chance > 0) && prob(effective_run_chance))
message += "Capture failed! [name] escaped [P.owner ? "from [P.owner]" : "from this hunter"]!"
@@ -91,7 +91,7 @@
else
message += "Capture error! Try again."
clients_encountered -= client //if the capture registration failed somehow, let them have another chance with this mob
P.audible_message(message, null, 4)
P.atom_say(message)
/obj/effect/nanomob/proc/despawn()
if(SSmob_hunt)
+1 -1
View File
@@ -55,7 +55,7 @@
health_scan = M.health
if(health_scan <= alarm_health)
pulse()
audible_message("[bicon(src)] *beep* *beep*", "*beep* *beep*")
audible_message("[bicon(src)] *beep* *beep*")
toggle_scan()
return
return
+1 -1
View File
@@ -129,7 +129,7 @@
return FALSE
cooldown = 2
pulse(FALSE)
audible_message("[bicon(src)] *beep* *beep*", null, 3)
audible_message("[bicon(src)] *beep* *beep*", hearing_distance = 3)
if(first)
qdel(first)
addtimer(CALLBACK(src, .proc/process_cooldown), 10)
@@ -7,32 +7,32 @@
/area/awaymission/centcomAway/general
name = "XCC-P5831"
music = "music/ambigen3.ogg"
ambientsounds = list('sound/ambience/ambigen3.ogg')
/area/awaymission/centcomAway/maint
name = "XCC-P5831 Maintenance"
icon_state = "away1"
music = "music/ambisin1.ogg"
ambientsounds = list('sound/ambience/ambisin1.ogg')
/area/awaymission/centcomAway/thunderdome
name = "XCC-P5831 Thunderdome"
icon_state = "away2"
music = "music/ambisin2.ogg"
ambientsounds = list('sound/ambience/ambisin2.ogg')
/area/awaymission/centcomAway/cafe
name = "XCC-P5831 Kitchen Arena"
icon_state = "away3"
music = "music/ambisin3.ogg"
ambientsounds = list('sound/ambience/ambisin3.ogg')
/area/awaymission/centcomAway/courtroom
name = "XCC-P5831 Courtroom"
icon_state = "away4"
music = "music/ambisin4.ogg"
ambientsounds = list('sound/ambience/ambisin4.ogg')
/area/awaymission/centcomAway/hangar
name = "XCC-P5831 Hangars"
icon_state = "away4"
music = "music/ambigen5.ogg"
ambientsounds = list('sound/ambience/ambigen5.ogg')
//centcomAway items
@@ -321,6 +321,7 @@
name = "Beta Station Atmospherics"
icon_state = "red"
has_gravity = FALSE
ambientsounds = ENGINEERING_SOUNDS
/area/ruin/space/ancientstation/betanorth
name = "Beta Station North Corridor"
@@ -333,6 +334,7 @@
/area/ruin/space/ancientstation/engi
name = "Charlie Station Engineering"
icon_state = "engine"
ambientsounds = ENGINEERING_SOUNDS
/area/ruin/space/ancientstation/comm
name = "Charlie Station Command"
+18
View File
@@ -177,6 +177,12 @@ GLOBAL_LIST_EMPTY(asset_datums)
//DEFINITIONS FOR ASSET DATUMS START HERE.
/datum/asset/simple/tgui
assets = list(
"tgui.bundle.js" = 'tgui/packages/tgui/public/tgui.bundle.js',
"tgui.bundle.css" = 'tgui/packages/tgui/public/tgui.bundle.css'
)
/datum/asset/simple/paper
assets = list(
"large_stamp-clown.png" = 'icons/paper_icons/large_stamp-clown.png',
@@ -344,3 +350,15 @@ GLOBAL_LIST_EMPTY(asset_datums)
/datum/asset/mob_hunt/send(client)
send_asset_list(client, assets, verify)
// Fontawesome
/datum/asset/simple/fontawesome
verify = FALSE
assets = list(
"fa-regular-400.eot" = 'html/font-awesome/webfonts/fa-regular-400.eot',
"fa-regular-400.woff" = 'html/font-awesome/webfonts/fa-regular-400.woff',
"fa-solid-900.eot" = 'html/font-awesome/webfonts/fa-solid-900.eot',
"fa-solid-900.woff" = 'html/font-awesome/webfonts/fa-solid-900.woff',
"font-awesome.css" = 'html/font-awesome/css/all.min.css',
"v4shim.css" = 'html/font-awesome/css/v4-shims.min.css'
)
@@ -318,6 +318,36 @@
if(isliving(user))
user.visible_message("<span class='warning'>[user] invades [M]'s personal space, thrusting [src] into [M.p_their()] face insistently.</span>","<span class='warning'>You invade [M]'s personal space, thrusting [src] into [M.p_their()] face insistently. You are the law.</span>")
//////////////
//OBJECTION!//
//////////////
/obj/item/clothing/accessory/lawyers_badge
name = "attorney's badge"
desc = "Fills you with the conviction of JUSTICE. Lawyers tend to want to show it to everyone they meet."
icon_state = "lawyerbadge"
item_state = "lawyerbadge"
item_color = "lawyerbadge"
var/cached_bubble_icon = null
/obj/item/clothing/accessory/attack_self(mob/user)
if(prob(1))
user.say("The testimony contradicts the evidence!")
user.visible_message("<span class='notice'>[user] shows [user.p_their()] attorney's badge.</span>", "<span class='notice'>You show your attorney's badge.</span>")
/obj/item/clothing/accessory/lawyers_badge/on_attached(obj/item/clothing/under/S, mob/user)
..()
if(has_suit && ismob(has_suit.loc))
var/mob/M = has_suit.loc
cached_bubble_icon = M.bubble_icon
M.bubble_icon = "lawyer"
/obj/item/clothing/accessory/lawyers_badge/on_removed(mob/user)
if(has_suit && ismob(has_suit.loc))
var/mob/M = has_suit.loc
M.bubble_icon = cached_bubble_icon
..()
///////////
//SCARVES//
///////////
+1 -1
View File
@@ -48,7 +48,7 @@
var/mob/living/carbon/human/target = M
if(ismachine(target))
if(ismachineperson(target))
to_chat(user, "<span class= 'notice'>[target] has no skin, how do you expect to tattoo [target.p_them()]?</span>")
return
@@ -278,11 +278,6 @@
if(!UserOverride)
add_attack_logs(user, occupant, "Gibbed in [src]", !!occupant.ckey ? ATKLOG_FEW : ATKLOG_ALL)
if(!iscarbon(user))
occupant.LAssailant = null
else
occupant.LAssailant = user
else //this looks ugly but it's better than a copy-pasted startgibbing proc override
occupant.create_attack_log("Was gibbed by <b>an autogibber (\the [src])</b>")
add_attack_logs(src, occupant, "gibbed")
+1
View File
@@ -184,3 +184,4 @@
D.consume(src)
else
return ..()
+2 -2
View File
@@ -207,7 +207,7 @@
var/obj/item/barcodescanner/scanner = W
scanner.computer = src
to_chat(user, "[scanner]'s associated machine has been set to [src].")
audible_message("[src] lets out a low, short blip.", 2)
audible_message("[src] lets out a low, short blip.", hearing_distance = 2)
return 1
else
return ..()
@@ -413,7 +413,7 @@
return
if(bibledelay)
audible_message("<b>[src]</b>'s monitor flashes, \"Printer unavailable. Please allow a short time before attempting to print.\"")
visible_message("<b>[src]</b>'s monitor flashes, \"Printer unavailable. Please allow a short time before attempting to print.\"")
else
bibledelay = 1
spawn(60)
+7 -6
View File
@@ -220,13 +220,14 @@
var/oldlum = source_turf.luminosity
source_turf.luminosity = CEILING(light_range, 1)
for(T in view(CEILING(light_range, 1), source_turf))
if((!IS_DYNAMIC_LIGHTING(T) && !T.light_sources) || T.has_opaque_atom)
if((!IS_DYNAMIC_LIGHTING(T) && !T.light_sources))
continue
if(!T.lighting_corners_initialised)
T.generate_missing_corners()
for(thing in T.corners)
C = thing
corners[C] = 0
if(!T.has_opaque_atom)
if(!T.lighting_corners_initialised)
T.generate_missing_corners()
for(thing in T.corners)
C = thing
corners[C] = 0
turfs += T
source_turf.luminosity = oldlum
@@ -2,6 +2,7 @@
name = "alien"
voice_name = "alien"
speak_emote = list("hisses")
bubble_icon = "alien"
icon = 'icons/mob/alien.dmi'
gender = NEUTER
dna = null
@@ -136,14 +136,11 @@ Doesn't work on other aliens/AI.*/
set category = "Alien"
if(powerc())
if(stomach_contents.len)
if(LAZYLEN(stomach_contents))
for(var/mob/M in src)
if(M in stomach_contents)
stomach_contents.Remove(M)
M.forceMove(loc)
//Paralyse(10)
src.visible_message("<span class='alertalien'><B>[src] hurls out the contents of [p_their()] stomach!</span>")
return
LAZYREMOVE(stomach_contents, M)
M.forceMove(drop_location())
visible_message("<span class='alertalien'><B>[src] hurls out the contents of [p_their()] stomach!</span>")
/mob/living/carbon/proc/getPlasma()
var/obj/item/organ/internal/xenos/plasmavessel/vessel = get_int_organ(/obj/item/organ/internal/xenos/plasmavessel)
@@ -6,6 +6,7 @@
icon_state = "alienq_s"
status_flags = CANPARALYSE
mob_size = MOB_SIZE_LARGE
bubble_icon = "alienroyal"
large = 1
ventcrawler = 0
+49 -41
View File
@@ -22,8 +22,7 @@
return ..()
/mob/living/carbon/handle_atom_del(atom/A)
if(A in processing_patches)
processing_patches -= A
LAZYREMOVE(processing_patches, A)
return ..()
/mob/living/carbon/blob_act(obj/structure/blob/B)
@@ -51,41 +50,40 @@
/mob/living/carbon/var/last_stomach_attack //defining this here because no one would look in carbon_defines for it
/mob/living/carbon/relaymove(var/mob/user, direction)
if(user in src.stomach_contents)
if(last_stomach_attack + STOMACH_ATTACK_DELAY > world.time) return
/mob/living/carbon/relaymove(mob/user, direction)
if(LAZYLEN(stomach_contents))
if(user in stomach_contents)
if(last_stomach_attack + STOMACH_ATTACK_DELAY > world.time)
return
last_stomach_attack = world.time
for(var/mob/M in hearers(4, src))
if(M.client)
M.show_message(text("<span class='warning'>You hear something rumbling inside [src]'s stomach...</span>"), 2)
var/obj/item/I = user.get_active_hand()
if(I && I.force)
var/d = rand(round(I.force / 4), I.force)
if(istype(src, /mob/living/carbon/human))
var/mob/living/carbon/human/H = src
var/obj/item/organ/external/organ = H.get_organ("chest")
if(istype(organ))
if(organ.receive_damage(d, 0))
H.UpdateDamageIcon()
H.updatehealth("stomach attack")
else
src.take_organ_damage(d)
for(var/mob/M in viewers(user, null))
last_stomach_attack = world.time
for(var/mob/M in hearers(4, src))
if(M.client)
M.show_message(text("<span class='warning'><B>[user] attacks [src]'s stomach wall with the [I.name]!</span>"), 2)
playsound(user.loc, 'sound/effects/attackblob.ogg', 50, 1)
M.show_message(text("<span class='warning'>You hear something rumbling inside [src]'s stomach...</span>"), 2)
if(prob(src.getBruteLoss() - 50))
for(var/atom/movable/A in stomach_contents)
A.forceMove(drop_location())
stomach_contents.Remove(A)
src.gib()
var/obj/item/I = user.get_active_hand()
if(I && I.force)
var/d = rand(round(I.force / 4), I.force)
if(istype(src, /mob/living/carbon/human))
var/mob/living/carbon/human/H = src
var/obj/item/organ/external/organ = H.get_organ("chest")
if(istype(organ))
if(organ.receive_damage(d, 0))
H.UpdateDamageIcon()
H.updatehealth("stomach attack")
else
take_organ_damage(d)
for(var/mob/M in viewers(user, null))
if(M.client)
M.show_message(text("<span class='warning'><B>[user] attacks [src]'s stomach wall with the [I.name]!</span>"), 2)
playsound(user.loc, 'sound/effects/attackblob.ogg', 50, 1)
if(prob(getBruteLoss() - 50))
gib()
#undef STOMACH_ATTACK_DELAY
@@ -140,9 +138,8 @@
I.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),5)
for(var/mob/M in src)
if(M in src.stomach_contents)
src.stomach_contents.Remove(M)
M.forceMove(get_turf(src))
LAZYREMOVE(stomach_contents, M)
M.forceMove(drop_location())
visible_message("<span class='danger'>[M] bursts out of [src]!</span>")
/mob/living/carbon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = FALSE, override = FALSE, tesla_shock = FALSE, illusion = FALSE, stun = TRUE)
@@ -1069,10 +1066,6 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, list(/obj/machinery/atmospherics/unary/ven
/mob/living/carbon/proc/forceFedAttackLog(var/obj/item/reagent_containers/food/toEat, mob/user)
add_attack_logs(user, src, "Fed [toEat]. Reagents: [toEat.reagents.log_list(toEat)]", toEat.reagents.harmless_helper() ? ATKLOG_ALMOSTALL : null)
if(!iscarbon(user))
LAssailant = null
else
LAssailant = user
/*TO DO - If/when stomach organs are introduced, override this at the human level sending the item to the stomach
@@ -1205,3 +1198,18 @@ so that different stomachs can handle things in different ways VB*/
I.acid_level = 0 //washes off the acid on our clothes
I.extinguish() //extinguishes our clothes
..()
/mob/living/carbon/clean_blood(clean_hands = TRUE, clean_mask = TRUE, clean_feet = TRUE)
if(head)
if(head.clean_blood())
update_inv_head()
if(head.flags_inv & HIDEMASK)
clean_mask = FALSE
if(wear_suit)
if(wear_suit.clean_blood())
update_inv_wear_suit()
if(wear_suit.flags_inv & HIDESHOES)
clean_feet = FALSE
if(wear_suit.flags_inv & HIDEGLOVES)
clean_hands = FALSE
..(clean_hands, clean_mask, clean_feet)
@@ -1,11 +1,10 @@
/mob/living/carbon
gender = MALE
pressure_resistance = 15
var/list/stomach_contents = list()
var/list/processing_patches = list()
var/list/stomach_contents
var/list/processing_patches
var/list/internal_organs = list()
var/list/internal_organs_slot = list() //Same as above, but stores "slot ID" - "organ" pairs for easy access.
var/antibodies = 0
var/life_tick = 0 // The amount of life ticks that have processed on this mob.
+4 -10
View File
@@ -6,7 +6,7 @@
canmove = 0
icon = null
invisibility = 101
if(!isSynthetic())
if(!ismachineperson(src))
animation = new(loc)
animation.icon_state = "blank"
animation.icon = 'icons/mob/mob.dmi'
@@ -32,12 +32,11 @@
E.droplimb(DROPLIMB_SHARP)
for(var/mob/M in src)
if(M in stomach_contents)
stomach_contents.Remove(M)
M.forceMove(get_turf(src))
LAZYREMOVE(stomach_contents, M)
M.forceMove(drop_location())
visible_message("<span class='danger'>[M] bursts out of [src]!</span>")
if(!isSynthetic())
if(!ismachineperson(src))
flick("gibbed-h", animation)
hgibs(loc, dna)
else
@@ -106,11 +105,6 @@
//Handle species-specific deaths.
dna.species.handle_death(gibbed, src)
if(ishuman(LAssailant))
var/mob/living/carbon/human/H=LAssailant
if(H.mind)
H.mind.kills += "[key_name(src)]"
if(SSticker && SSticker.mode)
// log_world("k")
sql_report_death(src)
@@ -34,7 +34,7 @@
//Cooldown-inducing emotes
if("ping", "pings", "buzz", "buzzes", "beep", "beeps", "yes", "no", "buzz2")
var/found_machine_head = FALSE
if(ismachine(src)) //Only Machines can beep, ping, and buzz, yes, no, and make a silly sad trombone noise.
if(ismachineperson(src)) //Only Machines can beep, ping, and buzz, yes, no, and make a silly sad trombone noise.
on_CD = handle_emote_CD() //proc located in code\modules\mob\emote.dm
found_machine_head = TRUE
else
@@ -947,7 +947,7 @@
if("Skrell")
emotelist += "\nSkrell specific emotes :- warble(s)"
if(ismachine(src))
if(ismachineperson(src))
emotelist += "\nMachine specific emotes :- beep(s)-(none)/mob, buzz(es)-none/mob, no-(none)/mob, ping(s)-(none)/mob, yes-(none)/mob, buzz2-(none)/mob"
else
var/obj/item/organ/external/head/H = get_organ("head") // If you have a robotic head, you can make beep-boop noises
@@ -208,7 +208,7 @@
if(!E)
wound_flavor_text["[organ_tag]"] = "<B>[p_they(TRUE)] [p_are()] missing [p_their()] [organ_descriptor].</B>\n"
else
if(!isSynthetic())
if(!ismachineperson(src))
if(E.is_robotic())
wound_flavor_text["[E.limb_name]"] = "[p_they(TRUE)] [p_have()] a robotic [E.name]!\n"
@@ -252,7 +252,7 @@
var/temp = getBruteLoss() //no need to calculate each of these twice
if(temp)
var/brute_message = !isSynthetic() ? "bruising" : "denting"
var/brute_message = !ismachineperson(src) ? "bruising" : "denting"
if(temp < 30)
msg += "[p_they(TRUE)] [p_have()] minor [brute_message ].\n"
else
@@ -301,13 +301,13 @@
else if(nutrition >= NUTRITION_LEVEL_FAT)
msg += "[p_they(TRUE)] [p_are()] quite chubby.\n"
if(!isSynthetic() && blood_volume < BLOOD_VOLUME_SAFE)
if(!ismachineperson(src) && blood_volume < BLOOD_VOLUME_SAFE)
msg += "[p_they(TRUE)] [p_have()] pale skin.\n"
if(bleedsuppress)
msg += "[p_they(TRUE)] [p_are()] bandaged with something.\n"
else if(bleed_rate)
var/bleed_message = !isSynthetic() ? "bleeding" : "leaking"
var/bleed_message = !ismachineperson(src) ? "bleeding" : "leaking"
msg += "<B>[p_they(TRUE)] [p_are()] [bleed_message]!</B>\n"
if(reagents.has_reagent("teslium"))
+2 -14
View File
@@ -1162,18 +1162,6 @@
custom_pain("You feel a stabbing pain in your chest!")
L.damage = L.min_bruised_damage
//returns 1 if made bloody, returns 0 otherwise
/mob/living/carbon/human/clean_blood(var/clean_feet)
.=..()
if(clean_feet && !shoes && istype(feet_blood_DNA, /list) && feet_blood_DNA.len)
feet_blood_color = null
qdel(feet_blood_DNA)
bloody_feet = list(BLOOD_STATE_HUMAN = 0, BLOOD_STATE_XENO = 0, BLOOD_STATE_NOT_BLOODY = 0)
blood_state = BLOOD_STATE_NOT_BLOODY
update_inv_shoes()
return 1
/mob/living/carbon/human/cuff_resist(obj/item/I)
if(HULK in mutations)
say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ))
@@ -1701,14 +1689,14 @@ Eyes need to have significantly high darksight to shine unless the mob has the X
/mob/living/carbon/human/forceFed(var/obj/item/reagent_containers/food/toEat, mob/user, fullness)
if(!check_has_mouth())
if(!((istype(toEat, /obj/item/reagent_containers/food/drinks) && (ismachine(src)))))
if(!((istype(toEat, /obj/item/reagent_containers/food/drinks) && (ismachineperson(src)))))
to_chat(user, "Where do you intend to put \the [toEat]? \The [src] doesn't have a mouth!")
return 0
return ..()
/mob/living/carbon/human/selfDrink(var/obj/item/reagent_containers/food/drinks/toDrink)
if(!check_has_mouth())
if(!ismachine(src))
if(!ismachineperson(src))
to_chat(src, "Where do you intend to put \the [src]? You don't have a mouth!")
return 0
else
@@ -84,7 +84,7 @@ emp_act
E.heal_damage(rembrute,0,0,1)
rembrute = nrembrute
user.visible_message("<span class='alert'>[user] patches some dents on [src]'s [E.name] with [I].</span>")
if(bleed_rate && isSynthetic())
if(bleed_rate && ismachineperson(src))
bleed_rate = 0
user.visible_message("<span class='alert'>[user] patches some leaks on [src] with [I].</span>")
if(IgniteMob())
@@ -387,11 +387,6 @@ emp_act
to_chat(user, "<span class='warning'>You hack off a chunk of meat from [name]</span>")
if(!meatleft)
add_attack_logs(user, src, "Chopped up into meat")
if(!iscarbon(user))
LAssailant = null
else
LAssailant = user
qdel(src)
var/obj/item/organ/external/affecting = get_organ(ran_zone(user.zone_selected))
@@ -37,7 +37,6 @@ GLOBAL_DATUM_INIT(default_martial_art, /datum/martial_art, new())
var/obj/item/s_store = null
var/icon/stand_icon = null
var/icon/lying_icon = null
var/voice = "" //Instead of new say code calling GetVoice() over and over and over, we're just going to ask this variable, which gets updated in Life()
+3 -3
View File
@@ -635,7 +635,7 @@
else
overeatduration -= 2
if(!ismachine(src) && nutrition < NUTRITION_LEVEL_HYPOGLYCEMIA) //Gosh damn snowflakey IPCs
if(!ismachineperson(src) && nutrition < NUTRITION_LEVEL_HYPOGLYCEMIA) //Gosh damn snowflakey IPCs
var/datum/disease/D = new /datum/disease/critical/hypoglycemia
ForceContractDisease(D)
@@ -697,7 +697,7 @@
alcohol_strength /= sober_str
var/obj/item/organ/internal/liver/L
if(!isSynthetic())
if(!ismachineperson(src))
L = get_int_organ(/obj/item/organ/internal/liver)
if(L)
alcohol_strength *= L.alcohol_intensity
@@ -719,7 +719,7 @@
AdjustConfused(3 / sober_str)
if(alcohol_strength >= blur_start) //blurry eyes
EyeBlurry(10 / sober_str)
if(!isSynthetic()) //stuff only for non-synthetics
if(!ismachineperson(src)) //stuff only for non-synthetics
if(alcohol_strength >= vomit_start) //vomiting
if(prob(8))
fakevomit()
@@ -352,21 +352,6 @@
if(organ.receive_damage(damage, 0, sharp, used_weapon))
H.UpdateDamageIcon()
if(H.LAssailant && ishuman(H.LAssailant)) //superheros still get the comical hit markers
var/mob/living/carbon/human/A = H.LAssailant
if(A.mind && (A.mind in (SSticker.mode.superheroes) || SSticker.mode.supervillains || SSticker.mode.greyshirts))
var/list/attack_bubble_recipients = list()
var/mob/living/user
for(var/mob/O in viewers(user, src))
if(O.client && O.has_vision(information_only=TRUE))
attack_bubble_recipients.Add(O.client)
spawn(0)
var/image/dmgIcon = image('icons/effects/hit_blips.dmi', src, "dmg[rand(1,2)]",MOB_LAYER+1)
dmgIcon.pixel_x = (!H.lying) ? rand(-3,3) : rand(-11,12)
dmgIcon.pixel_y = (!H.lying) ? rand(-11,9) : rand(-10,1)
flick_overlay(dmgIcon, attack_bubble_recipients, 9)
if(BURN)
H.damageoverlaytemp = 20
damage = damage * burn_mod
@@ -443,6 +428,9 @@
else
target.LAssailant = user
target.lastattacker = user.real_name
target.lastattackerckey = user.ckey
var/damage = rand(user.dna.species.punchdamagelow, user.dna.species.punchdamagehigh)
damage += attack.damage
if(!damage)
@@ -376,7 +376,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
//base icons
var/icon/hair_standing = new /icon('icons/mob/human_face.dmi',"bald_s")
if(head_organ.h_style && !(head && (head.flags & BLOCKHEADHAIR) && !(isSynthetic())))
if(head_organ.h_style && !(head && (head.flags & BLOCKHEADHAIR) && !(ismachineperson(src))))
var/datum/sprite_accessory/hair/hair_style = GLOB.hair_styles_full_list[head_organ.h_style]
if(hair_style && hair_style.species_allowed)
if((head_organ.dna.species.name in hair_style.species_allowed) || (head_organ.dna.species.bodyflags & ALL_RPARTS)) //If the head's species is in the list of allowed species for the hairstyle, or the head's species is one flagged to have bodies comprised wholly of cybernetics...
+10 -5
View File
@@ -11,6 +11,10 @@
if(stat != DEAD)
handle_organs()
//stuff in the stomach
if(LAZYLEN(stomach_contents))
handle_stomach(times_fired)
. = ..()
if(QDELETED(src))
@@ -254,14 +258,15 @@
if(times_fired % 20==2) //dry off a bit once every 20 ticks or so
wetlevel = max(wetlevel - 1,0)
/mob/living/carbon/handle_stomach(times_fired)
for(var/mob/living/M in stomach_contents)
/mob/living/carbon/proc/handle_stomach(times_fired)
for(var/thing in stomach_contents)
var/mob/living/M = thing
if(M.loc != src)
stomach_contents.Remove(M)
LAZYREMOVE(stomach_contents, M)
continue
if(stat != DEAD)
if(M.stat == DEAD)
stomach_contents.Remove(M)
LAZYREMOVE(stomach_contents, M)
qdel(M)
continue
if(times_fired % 3 == 1)
@@ -476,7 +481,7 @@
P.reagents.remove_any(applied_amount * 0.5)
else
if(!P.reagents || P.reagents.total_volume <= 0)
processing_patches -= P
LAZYREMOVE(processing_patches, P)
qdel(P)
/mob/living/carbon/proc/handle_germs()
-6
View File
@@ -58,9 +58,6 @@
handle_fire()
//stuff in the stomach
handle_stomach(times_fired)
update_gravity(mob_has_gravity())
if(pulling)
@@ -117,9 +114,6 @@
/mob/living/proc/handle_environment(datum/gas_mixture/environment)
return
/mob/living/proc/handle_stomach(times_fired)
return
/mob/living/proc/update_pulling()
if(incapacitated())
stop_pulling()
-3
View File
@@ -682,9 +682,6 @@
*/////////////////////
/mob/living/proc/resist_grab()
var/resisting = 0
for(var/obj/O in requests)
qdel(O)
resisting++
for(var/X in grabbed_by)
var/obj/item/grab/G = X
resisting++
+11 -14
View File
@@ -61,7 +61,7 @@ proc/get_radio_key_from_channel(var/channel)
return default_language
/mob/living/proc/handle_speech_problems(list/message_pieces, var/verb)
var/robot = isSynthetic()
var/robot = ismachineperson(src)
for(var/datum/multilingual_say_piece/S in message_pieces)
if(S.speaking && S.speaking.flags & NO_STUTTER)
continue
@@ -269,12 +269,12 @@ proc/get_radio_key_from_channel(var/channel)
M.hear_say(message_pieces, verb, italics, src, speech_sound, sound_vol, sound_frequency)
if(M.client)
speech_bubble_recipients.Add(M.client)
spawn(0)
if(loc && !isturf(loc))
var/atom/A = loc //Non-turf, let it handle the speech bubble
A.speech_bubble("hR[speech_bubble_test]", A, speech_bubble_recipients)
else //Turf, leave speech bubbles to the mob
speech_bubble("h[speech_bubble_test]", src, speech_bubble_recipients)
if(loc && !isturf(loc))
var/atom/A = loc //Non-turf, let it handle the speech bubble
A.speech_bubble("[A.bubble_icon][speech_bubble_test]", A, speech_bubble_recipients)
else //Turf, leave speech bubbles to the mob
speech_bubble("[bubble_icon][speech_bubble_test]", src, speech_bubble_recipients)
for(var/obj/O in listening_obj)
spawn(0)
@@ -462,10 +462,7 @@ proc/get_radio_key_from_channel(var/channel)
if(M.client)
speech_bubble_recipients.Add(M.client)
spawn(0)
var/image/I = image('icons/mob/talk.dmi', src, "h[speech_bubble_test]", MOB_LAYER + 1)
I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
flick_overlay(I, speech_bubble_recipients, 30)
speech_bubble("[bubble_icon][speech_bubble_test]", src, speech_bubble_recipients)
if(watching.len)
var/rendered = "<span class='game say'><span class='name'>[name]</span> [not_heard].</span>"
@@ -474,7 +471,7 @@ proc/get_radio_key_from_channel(var/channel)
return 1
/mob/living/speech_bubble(var/bubble_state = "",var/bubble_loc = src, var/list/bubble_recipients = list())
var/image/I = image('icons/mob/talk.dmi', bubble_loc, bubble_state, MOB_LAYER + 1)
/mob/living/speech_bubble(bubble_state = "", bubble_loc = src, list/bubble_recipients = list())
var/image/I = image('icons/mob/talk.dmi', bubble_loc, bubble_state, FLY_LAYER)
I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
flick_overlay(I, bubble_recipients, 30)
INVOKE_ASYNC(GLOBAL_PROC, /.proc/flick_overlay, I, bubble_recipients, 30)
@@ -253,7 +253,7 @@ proc/robot_healthscan(mob/user, mob/living/M)
to_chat(user, "<span class='warning'>You can't analyze non-robotic things!</span>")
return
switch(scan_type)
if("robot")
var/BU = M.getFireLoss() > 50 ? "<b>[M.getFireLoss()]</b>" : M.getFireLoss()
@@ -269,7 +269,7 @@ proc/robot_healthscan(mob/user, mob/living/M)
to_chat(user, "<span class='notice'>Localized Damage:</span>")
if(!LAZYLEN(damaged) && !LAZYLEN(missing))
to_chat(user, "<span class='notice'>\t Components are OK.</span>")
else
else
if(LAZYLEN(damaged))
for(var/datum/robot_component/org in damaged)
user.show_message(text("<span class='notice'>\t []: [][] - [] - [] - []</span>", \
@@ -282,7 +282,7 @@ proc/robot_healthscan(mob/user, mob/living/M)
if(LAZYLEN(missing))
for(var/datum/robot_component/org in missing)
user.show_message("<span class='warning'>\t [capitalize(org.name)]: MISSING</span>")
if(H.emagged && prob(5))
to_chat(user, "<span class='warning'>\t ERROR: INTERNAL SYSTEMS COMPROMISED</span>")
@@ -313,7 +313,7 @@ proc/robot_healthscan(mob/user, mob/living/M)
if(!organ_found)
to_chat(user, "<span class='warning'>No prosthetics located.</span>")
if(H.isSynthetic())
if(ismachineperson(H))
to_chat(user, "<span class='notice'>Internal Fluid Level:[H.blood_volume]/[H.max_blood]</span>")
if(H.bleed_rate)
to_chat(user, "<span class='warning'>Warning:External component leak detected!</span>")
@@ -6,6 +6,7 @@
icon_state = "repairbot"
maxHealth = 35
health = 35
bubble_icon = "machine"
universal_speak = 0
universal_understand = 1
gender = NEUTER
+112 -69
View File
@@ -9,6 +9,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
icon_state = "robot"
maxHealth = 100
health = 100
bubble_icon = "robot"
universal_understand = 1
deathgasp_on_death = TRUE
@@ -16,8 +17,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
var/custom_name = ""
var/custom_sprite = 0 //Due to all the sprites involved, a var for our custom borgs may be best
//Hud stuff
//Hud stuff
var/obj/screen/inv1 = null
var/obj/screen/inv2 = null
var/obj/screen/inv3 = null
@@ -27,7 +27,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
var/shown_robot_modules = 0 //Used to determine whether they have the module menu shown or not
var/obj/screen/robot_modules_background
//3 Modules can be activated at any one time.
//3 Modules can be activated at any one time.
var/obj/item/robot_module/module = null
var/module_active = null
var/module_state_1 = null
@@ -57,6 +57,9 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
var/is_emaggable = TRUE
var/eye_protection = 0
var/ear_protection = 0
var/damage_protection = 0
var/emp_protection = FALSE
var/xeno_disarm_chance = 85
var/list/force_modules = list()
var/allow_rename = TRUE
@@ -86,7 +89,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
var/tracking_entities = 0 //The number of known entities currently accessing the internal camera
var/braintype = "Cyborg"
var/base_icon = ""
var/crisis = 0
var/modules_break = TRUE
var/lamp_max = 10 //Maximum brightness of a borg lamp. Set as a var for easy adjusting.
@@ -97,6 +99,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
hud_possible = list(SPECIALROLE_HUD, DIAG_STAT_HUD, DIAG_HUD, DIAG_BATT_HUD)
var/default_cell_type = /obj/item/stock_parts/cell/high
var/magpulse = 0
var/ionpulse = 0 // Jetpack-like effect.
var/ionpulse_on = 0 // Jetpack-like effect.
@@ -132,7 +135,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
init()
if(!scrambledcodes && !camera)
if(!camera && (!scrambledcodes || designation == "ERT"))
camera = new /obj/machinery/camera(src)
camera.c_tag = real_name
camera.network = list("SS13","Robots")
@@ -144,7 +147,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
mmi.icon_state = "boris"
if(!cell) // Make sure a new cell gets created *before* executing initialize_components(). The cell component needs an existing cell for it to get set up properly
cell = new /obj/item/stock_parts/cell/high(src)
cell = new default_cell_type(src)
initialize_components()
//if(!unfinished)
@@ -288,12 +291,9 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
/mob/living/silicon/robot/proc/pick_module()
if(module)
return
var/list/modules = list("Standard", "Engineering", "Medical", "Miner", "Janitor", "Service", "Security")
var/list/modules = list("Generalist", "Engineering", "Medical", "Miner", "Janitor", "Service", "Security")
if(islist(force_modules) && force_modules.len)
modules = force_modules.Copy()
if(GLOB.security_level == (SEC_LEVEL_GAMMA || SEC_LEVEL_EPSILON) || crisis)
to_chat(src, "<span class='warning'>Crisis mode active. The combat module is now available.</span>")
modules += "Combat"
if(mmi != null && mmi.alien)
modules = list("Hunter")
modtype = input("Please, select a module!", "Robot", null, null) as null|anything in modules
@@ -306,9 +306,9 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
return
switch(modtype)
if("Standard")
if("Generalist")
module = new /obj/item/robot_module/standard(src)
module.channels = list("Service" = 1)
module.channels = list("Engineering" = 1, "Medical" = 1, "Security" = 1, "Service" = 1)
module_sprites["Basic"] = "robot_old"
module_sprites["Android"] = "droid"
module_sprites["Default"] = "Standard"
@@ -337,6 +337,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
module_sprites["Standard"] = "Standard-Mine"
module_sprites["Noble-DIG"] = "Noble-DIG"
module_sprites["Cricket"] = "Cricket-MINE"
module_sprites["Lavaland"] = "lavaland"
if("Medical")
module = new /obj/item/robot_module/medical(src)
@@ -353,6 +354,17 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
status_flags &= ~CANPUSH
if("Security")
if(!weapons_unlock)
var/count_secborgs = 0
for(var/mob/living/silicon/robot/R in GLOB.alive_mob_list)
if(R && R.stat != DEAD && R.module && istype(R.module, /obj/item/robot_module/security))
count_secborgs++
var/max_secborgs = 2
if(GLOB.security_level == SEC_LEVEL_GREEN)
max_secborgs = 1
if(count_secborgs >= max_secborgs)
to_chat(src, "<span class='warning'>There are too many Security cyborgs active. Please choose another module.</span>")
return
module = new /obj/item/robot_module/security(src)
module.channels = list("Security" = 1)
module_sprites["Basic"] = "secborg"
@@ -387,10 +399,16 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
module_sprites["Noble-CLN"] = "Noble-CLN"
module_sprites["Cricket"] = "Cricket-JANI"
if("Combat")
module = new /obj/item/robot_module/combat(src)
if("Destroyer") // Rolling Borg
module = new /obj/item/robot_module/destroyer(src)
module.channels = list("Security" = 1)
icon_state = "droidcombat"
status_flags &= ~CANPUSH
if("Combat") // Gamma ERT
module = new /obj/item/robot_module/combat(src)
icon_state = "ertgamma"
status_flags &= ~CANPUSH
if("Hunter")
module = new /obj/item/robot_module/alien/hunter(src)
@@ -442,6 +460,8 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
ionpulse = FALSE
magpulse = FALSE
add_language("Robot Talk", 1)
if("lava" in weather_immunities) // Remove the lava-immunity effect given by a printable upgrade
weather_immunities -= "lava"
status_flags |= CANPUSH
@@ -916,7 +936,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
return 0
/mob/living/silicon/robot/update_icons()
overlays.Cut()
if(stat != DEAD && !(paralysis || stunned || IsWeakened() || low_power_mode)) //Not dead, not stunned.
if(custom_panel in custom_eye_names)
@@ -925,36 +944,24 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
overlays += "eyes-[icon_state]"
else
overlays -= "eyes"
if(opened)
var/panelprefix = "ov"
if(custom_sprite) //Custom borgs also have custom panels, heh
panelprefix = "[ckey]"
if(custom_panel in custom_panel_names) //For default borgs with different panels
panelprefix = custom_panel
if(wiresexposed)
overlays += "[panelprefix]-openpanel +w"
else if(cell)
overlays += "[panelprefix]-openpanel +c"
else
overlays += "[panelprefix]-openpanel -c"
var/combat = list("Combat")
if(modtype in combat)
if(base_icon == "")
base_icon = icon_state
if(module_active && istype(module_active,/obj/item/borg/combat/mobility))
icon_state = "[base_icon]-roll"
else
icon_state = base_icon
if(module)
for(var/obj/item/borg/combat/shield/S in module.modules)
if(activated(S))
overlays += "[base_icon]-shield"
borg_icons()
update_fire()
/mob/living/silicon/robot/proc/borg_icons() // Exists so that robot/destroyer can override it
return
/mob/living/silicon/robot/proc/installed_modules()
if(weapon_lock)
to_chat(src, "<span class='warning'>Weapon lock active, unable to use modules! Count:[weaponlock_time]</span>")
@@ -1309,6 +1316,16 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
..()
update_module_icon()
/mob/living/silicon/robot/emp_act(severity)
if(emp_protection)
return
..()
switch(severity)
if(1)
disable_component("comms", 160)
if(2)
disable_component("comms", 60)
/mob/living/silicon/robot/deathsquad
base_icon = "nano_bloodhound"
icon_state = "nano_bloodhound"
@@ -1321,44 +1338,29 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
pdahide = 1
eye_protection = 2 // Immunity to flashes and the visual part of flashbangs
ear_protection = 1 // Immunity to the audio part of flashbangs
damage_protection = 10 // Reduce all incoming damage by this number
xeno_disarm_chance = 20
allow_rename = FALSE
modtype = "Commando"
faction = list("nanotrasen")
is_emaggable = FALSE
/mob/living/silicon/robot/deathsquad/New(loc)
..()
cell = new /obj/item/stock_parts/cell/hyper(src)
default_cell_type = /obj/item/stock_parts/cell/bluespace
/mob/living/silicon/robot/deathsquad/init()
laws = new /datum/ai_laws/deathsquad
module = new /obj/item/robot_module/deathsquad(src)
aiCamera = new/obj/item/camera/siliconcam/robot_camera(src)
radio = new /obj/item/radio/borg/deathsquad(src)
radio.recalculateChannels()
playsound(loc, 'sound/mecha/nominalsyndi.ogg', 75, 0)
/mob/living/silicon/robot/combat
base_icon = "droidcombat"
icon_state = "droidcombat"
modtype = "Combat"
designation = "Combat"
/mob/living/silicon/robot/deathsquad/bullet_act(var/obj/item/projectile/P)
if(istype(P) && P.is_reflectable && P.starting)
visible_message("<span class='danger'>The [P.name] gets reflected by [src]!</span>", "<span class='userdanger'>The [P.name] gets reflected by [src]!</span>")
P.reflect_back(src)
return -1
return ..(P)
/mob/living/silicon/robot/combat/init()
..()
module = new /obj/item/robot_module/combat(src)
module.channels = list("Security" = 1)
//languages
module.add_languages(src)
//subsystems
module.add_subsystems_and_actions(src)
status_flags &= ~CANPUSH
radio.config(module.channels)
notify_ai(2)
/mob/living/silicon/robot/ert
designation = "ERT"
@@ -1366,11 +1368,12 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
scrambledcodes = 1
req_one_access = list(ACCESS_CENT_SPECOPS)
ionpulse = 1
force_modules = list("Engineering", "Medical", "Security")
static_radio_channels = 1
allow_rename = FALSE
weapons_unlock = TRUE
default_cell_type = /obj/item/stock_parts/cell/super
var/eprefix = "Amber"
/mob/living/silicon/robot/ert/init()
@@ -1379,11 +1382,10 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
radio.recalculateChannels()
aiCamera = new/obj/item/camera/siliconcam/robot_camera(src)
/mob/living/silicon/robot/ert/New(loc, cyborg_unlock)
/mob/living/silicon/robot/ert/New(loc)
..(loc)
cell = new /obj/item/stock_parts/cell/hyper(src)
var/rnum = rand(1,1000)
var/borgname = "ERT [rnum]"
var/borgname = "[eprefix] ERT [rnum]"
name = borgname
custom_name = borgname
real_name = name
@@ -1392,22 +1394,63 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
mind.original = src
mind.assigned_role = SPECIAL_ROLE_ERT
mind.special_role = SPECIAL_ROLE_ERT
if(cyborg_unlock)
crisis = 1
if(!(mind in SSticker.minds))
SSticker.minds += mind
SSticker.mode.ert += mind
/mob/living/silicon/robot/ert/gamma
crisis = 1
/mob/living/silicon/robot/emp_act(severity)
/mob/living/silicon/robot/ert/red
eprefix = "Red"
default_cell_type = /obj/item/stock_parts/cell/hyper
/mob/living/silicon/robot/ert/gamma
default_cell_type = /obj/item/stock_parts/cell/bluespace
force_modules = list("Combat", "Engineering", "Medical")
damage_protection = 5 // Reduce all incoming damage by this number
eprefix = "Gamma"
magpulse = 1
xeno_disarm_chance = 40
/mob/living/silicon/robot/destroyer
// admin-only borg, the seraph / special ops officer of borgs
base_icon = "droidcombat"
icon_state = "droidcombat"
modtype = "Destroyer"
designation = "Destroyer"
lawupdate = 0
scrambledcodes = 1
req_one_access = list(ACCESS_CENT_SPECOPS)
ionpulse = 1
magpulse = 1
pdahide = 1
eye_protection = 2 // Immunity to flashes and the visual part of flashbangs
ear_protection = 1 // Immunity to the audio part of flashbangs
emp_protection = TRUE // Immunity to EMP, due to heavy shielding
damage_protection = 20 // Reduce all incoming damage by this number. Very high in the case of /destroyer borgs, since it is an admin-only borg.
xeno_disarm_chance = 10
default_cell_type = /obj/item/stock_parts/cell/bluespace
/mob/living/silicon/robot/destroyer/init()
..()
switch(severity)
if(1)
disable_component("comms", 160)
if(2)
disable_component("comms", 60)
module = new /obj/item/robot_module/destroyer(src)
module.add_languages(src)
module.add_subsystems_and_actions(src)
status_flags &= ~CANPUSH
if(radio)
qdel(radio)
radio = new /obj/item/radio/borg/ert/specops(src)
radio.recalculateChannels()
/mob/living/silicon/robot/destroyer/borg_icons()
if(base_icon == "")
base_icon = icon_state
if(module_active && istype(module_active,/obj/item/borg/destroyer/mobility))
icon_state = "[base_icon]-roll"
else
icon_state = base_icon
overlays += "[base_icon]-shield"
/mob/living/silicon/robot/extinguish_light()
update_headlamp(1, 150)
@@ -76,29 +76,6 @@
if(!LAZYLEN(components))
return
//Combat shielding absorbs a percentage of damage directly into the cell.
var/obj/item/borg/combat/shield/shield
if(module_state_1 && istype(module_state_1, /obj/item/borg/combat/shield))
shield = module_state_1
else if(module_state_2 && istype(module_state_2, /obj/item/borg/combat/shield))
shield = module_state_2
else if(module_state_3 && istype(module_state_3, /obj/item/borg/combat/shield))
shield = module_state_3
if(shield)
//Shields absorb a certain percentage of damage based on their power setting.
var/absorb_brute = brute * shield.shield_level
var/absorb_burn = burn * shield.shield_level
var/cost = (absorb_brute+absorb_burn) * 100
cell.charge -= cost
if(cell.charge <= 0)
cell.charge = 0
to_chat(src, "<span class='warning'>Your shield has overloaded!</span>")
else
brute -= absorb_brute
burn -= absorb_burn
to_chat(src, "<span class='warning'>Your shield absorbs some of the impact!</span>")
var/datum/robot_component/armour/A = get_armour()
if(A)
A.take_damage(brute, burn, sharp, updating_health)
@@ -127,32 +104,15 @@
updatehealth("heal overall damage")
/mob/living/silicon/robot/take_overall_damage(brute = 0, burn = 0, updating_health = TRUE, used_weapon = null, sharp = 0)
if(status_flags & GODMODE) return //godmode
if(status_flags & GODMODE)
return
if(damage_protection)
brute = clamp(brute - damage_protection, 0, brute)
burn = clamp(burn - damage_protection, 0, burn)
var/list/datum/robot_component/parts = get_damageable_components()
//Combat shielding absorbs a percentage of damage directly into the cell.
var/obj/item/borg/combat/shield/shield
if(module_state_1 && istype(module_state_1, /obj/item/borg/combat/shield))
shield = module_state_1
else if(module_state_2 && istype(module_state_2, /obj/item/borg/combat/shield))
shield = module_state_2
else if(module_state_3 && istype(module_state_3, /obj/item/borg/combat/shield))
shield = module_state_3
if(shield)
//Shields absorb a certain percentage of damage based on their power setting.
var/absorb_brute = brute * shield.shield_level
var/absorb_burn = burn * shield.shield_level
var/cost = (absorb_brute+absorb_burn) * 100
cell.charge -= cost
if(cell.charge <= 0)
cell.charge = 0
to_chat(src, "<span class='warning'>Your shield has overloaded!</span>")
else
brute -= absorb_brute
burn -= absorb_burn
to_chat(src, "<span class='warning'>Your shield absorbs some of the impact!</span>")
var/datum/robot_component/armour/A = get_armour()
if(A)
A.take_damage(brute, burn, sharp)
@@ -2,7 +2,7 @@
if(M.a_intent == INTENT_DISARM)
if(!lying)
M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
if(prob(85))
if(prob(xeno_disarm_chance))
Stun(7)
step(src, get_dir(M,src))
spawn(5)
@@ -73,24 +73,7 @@
/obj/item/borg
var/powerneeded // Percentage of power remaining required to run item
/obj/item/borg/combat/shield
name = "personal shielding"
desc = "A powerful experimental module that turns aside or absorbs incoming attacks at the cost of charge."
icon = 'icons/obj/decals.dmi'
icon_state = "shock"
powerneeded = 25
var/shield_level = 0.5 //Percentage of damage absorbed by the shield.
/obj/item/borg/combat/shield/verb/set_shield_level()
set name = "Set shield level"
set category = "Object"
set src in range(0)
var/N = input("How much damage should the shield absorb?") in list("5","10","25","50","75","100")
if(N)
shield_level = text2num(N)/100
/obj/item/borg/combat/mobility
/obj/item/borg/destroyer/mobility
name = "mobility module"
desc = "By retracting limbs and tucking in its head, a combat android can roll at high speeds."
icon = 'icons/obj/decals.dmi'
@@ -118,20 +118,48 @@
return
/obj/item/robot_module/standard
name = "standard robot module"
// if station is fine, assist with constructing station goal room, cleaning, and repairing cables chewed by rats
// if medical crisis, assist by providing basic healthcare, retrieving corpses, and monitoring crew lifesigns
// if eng crisis, assist by helping repair hull breaches
// if sec crisis, assist by opening doors for sec and providing backup zipties on patrols
name = "generalist robot module"
module_type = "Standard"
subsystems = list(/mob/living/silicon/proc/subsystem_power_monitor, /mob/living/silicon/proc/subsystem_crew_monitor)
stacktypes = list(
/obj/item/stack/sheet/metal/cyborg = 50,
/obj/item/stack/cable_coil/cyborg = 50,
/obj/item/stack/rods/cyborg = 60,
/obj/item/stack/tile/plasteel = 20
)
/obj/item/robot_module/standard/New()
..()
modules += new /obj/item/melee/baton/loaded(src)
modules += new /obj/item/extinguisher(src)
modules += new /obj/item/wrench/cyborg(src)
// sec
modules += new /obj/item/restraints/handcuffs/cable/zipties/cyborg(src)
// janitorial
modules += new /obj/item/soap/nanotrasen(src)
modules += new /obj/item/lightreplacer/cyborg(src)
// eng
modules += new /obj/item/crowbar/cyborg(src)
modules += new /obj/item/wrench/cyborg(src)
modules += new /obj/item/extinguisher(src) // for firefighting, and propulsion in space
modules += new /obj/item/weldingtool/largetank/cyborg(src)
// mining
modules += new /obj/item/pickaxe(src)
modules += new /obj/item/t_scanner/adv_mining_scanner(src)
modules += new /obj/item/storage/bag/ore/cyborg(src)
// med
modules += new /obj/item/healthanalyzer(src)
modules += new /obj/item/reagent_containers/borghypo/basic(src)
modules += new /obj/item/roller_holder(src) // for taking the injured to medbay without worsening their injuries or leaving a blood trail the whole way
emag = new /obj/item/melee/energy/sword/cyborg(src)
for(var/G in stacktypes)
var/obj/item/stack/sheet/M = new G(src)
M.amount = stacktypes[G]
modules += M
fix_modules()
/obj/item/robot_module/medical
name = "medical robot module"
module_type = "Medical"
@@ -259,6 +287,7 @@
modules += new /obj/item/mop/advanced/cyborg(src)
modules += new /obj/item/lightreplacer/cyborg(src)
modules += new /obj/item/holosign_creator(src)
modules += new /obj/item/extinguisher/mini(src)
emag = new /obj/item/reagent_containers/spray(src)
emag.reagents.add_reagent("lube", 250)
@@ -483,25 +512,44 @@
fix_modules()
/obj/item/robot_module/combat
name = "combat robot module"
/obj/item/robot_module/destroyer
name = "destroyer robot module"
module_type = "Malf"
module_actions = list(
/datum/action/innate/robot_sight/thermal,
)
/obj/item/robot_module/destroyer/New()
..()
modules += new /obj/item/gun/energy/immolator/multi/cyborg(src) // See comments on /robot_module/combat below
modules += new /obj/item/melee/baton/loaded(src) // secondary weapon, for things immune to burn, immune to ranged weapons, or for arresting low-grade threats
modules += new /obj/item/restraints/handcuffs/cable/zipties/cyborg(src)
modules += new /obj/item/pickaxe/drill/jackhammer(src) // for breaking walls to execute flanking moves
modules += new /obj/item/borg/destroyer/mobility(src)
emag = null
fix_modules()
/obj/item/robot_module/combat
name = "combat robot module"
module_type = "Malf"
module_actions = list()
/obj/item/robot_module/combat/New()
..()
modules += new /obj/item/gun/energy/immolator/multi/cyborg(src) // primary weapon, strong at close range (ie: against blob/terror/xeno), but consumes a lot of energy per shot.
// Borg gets 40 shots of this weapon. Gamma Sec ERT gets 10.
// So, borg has way more burst damage, but also takes way longer to recharge / get back in the fight once depleted. Has to find a borg recharger and sit in it for ages.
// Organic gamma sec ERT carries alternate weapons, including a box of flashbangs, and can load up on a huge number of guns from science. Borg cannot do either.
// Overall, gamma borg has higher skill floor but lower skill ceiling.
modules += new /obj/item/melee/baton/loaded(src) // secondary weapon, for things immune to burn, immune to ranged weapons, or for arresting low-grade threats
modules += new /obj/item/restraints/handcuffs/cable/zipties/cyborg(src)
modules += new /obj/item/gun/energy/gun/cyborg(src)
modules += new /obj/item/pickaxe/drill/jackhammer(src)
modules += new /obj/item/borg/combat/shield(src)
modules += new /obj/item/borg/combat/mobility(src)
modules += new /obj/item/wrench/cyborg(src)
emag = new /obj/item/gun/energy/lasercannon/cyborg(src)
modules += new /obj/item/pickaxe/drill/jackhammer(src) // for breaking walls to execute flanking moves
emag = null
fix_modules()
/obj/item/robot_module/alien/hunter
name = "alien hunter module"
module_type = "Standard"
@@ -9,7 +9,7 @@
/mob/living/silicon/robot/movement_delay()
. = ..()
. += speed
if(module_active && istype(module_active,/obj/item/borg/combat/mobility))
if(module_active && istype(module_active,/obj/item/borg/destroyer/mobility))
. -= 3
. += config.robot_delay
@@ -5,6 +5,7 @@
scrambledcodes = 1
pdahide = 1
faction = list("syndicate")
bubble_icon = "syndibot"
designation = "Syndicate Assault"
modtype = "Syndicate"
req_access = list(ACCESS_SYNDICATE)
@@ -2,7 +2,9 @@
gender = NEUTER
robot_talk_understand = 1
voice_name = "synthesized voice"
bubble_icon = "machine"
has_unlimited_silicon_privilege = 1
weather_immunities = list("ash")
var/syndicate = 0
var/const/MAIN_CHANNEL = "Main Frequency"
var/lawchannel = MAIN_CHANNEL // Default channel on which to state laws
@@ -2,7 +2,7 @@
var/register_alarms = 1
var/datum/nano_module/alarm_monitor/all/alarm_monitor
var/datum/nano_module/atmos_control/atmos_control
var/datum/nano_module/crew_monitor/crew_monitor
var/datum/tgui_module/crew_monitor/crew_monitor
var/datum/nano_module/law_manager/law_manager
var/datum/nano_module/power_monitor/silicon/power_monitor
@@ -71,8 +71,7 @@
/mob/living/silicon/proc/subsystem_crew_monitor()
set category = "Subsystems"
set name = "Crew Monitor"
crew_monitor.ui_interact(usr, state = GLOB.self_state)
crew_monitor.tgui_interact(usr, state = GLOB.tgui_self_state)
/****************
* Law Manager *
@@ -18,7 +18,7 @@
speak_emote = list("states")
friendly = "boops"
bubble_icon = "machine"
faction = list("neutral", "silicon")
var/obj/machinery/bot_core/bot_core = null
@@ -63,6 +63,7 @@
var/new_destination // pending new destination (waiting for beacon response)
var/destination // destination description tag
var/next_destination // the next destination in the patrol route
var/ignorelistcleanuptimer = 1 // This ticks up every automated action, at 300 we clean the ignore list
var/robot_arm = /obj/item/robot_parts/r_arm
var/blockcount = 0 //number of times retried a blocked path
@@ -254,6 +255,15 @@
/mob/living/simple_animal/bot/handle_automated_action()
diag_hud_set_botmode()
if(ignorelistcleanuptimer % 300 == 0) // Every 300 actions, clean up the ignore list from old junk
for(var/uid in ignore_list)
var/atom/referredatom = locateUID(uid)
if(!referredatom || QDELETED(referredatom))
ignore_list -= uid
ignorelistcleanuptimer = 1
else
ignorelistcleanuptimer++
if(!on)
return
@@ -439,14 +449,15 @@ Example usage: patient = scan(/mob/living/carbon/human, oldpatient, 1)
The proc would return a human next to the bot to be set to the patient var.
Pass the desired type path itself, declaring a temporary var beforehand is not required.
*/
/mob/living/simple_animal/bot/proc/scan(scan_type, old_target, scan_range = DEFAULT_SCAN_RANGE)
/mob/living/simple_animal/bot/proc/scan(atom/scan_type, atom/old_target, scan_range = DEFAULT_SCAN_RANGE)
var/final_result
for(var/scan in shuffle(view(scan_range, src))) //Search for something in range!
if(!istype(scan, scan_type)) //Check that the thing we found is the type we want!
var/atom/A = scan
if(!istype(A, scan_type)) //Check that the thing we found is the type we want!
continue //If not, keep searching!
if( (scan in ignore_list) || (scan == old_target) ) //Filter for blacklisted elements, usually unreachable or previously processed oness
if((A.UID() in ignore_list) || (A == old_target) ) //Filter for blacklisted elements, usually unreachable or previously processed oness
continue
var/scan_result = process_scan(scan) //Some bots may require additional processing when a result is selected.
var/scan_result = process_scan(A) //Some bots may require additional processing when a result is selected.
if(scan_result)
final_result = scan_result
else
@@ -454,17 +465,16 @@ Pass the desired type path itself, declaring a temporary var beforehand is not r
return final_result
//When the scan finds a target, run bot specific processing to select it for the next step. Empty by default.
/mob/living/simple_animal/bot/proc/process_scan(scan_target)
/mob/living/simple_animal/bot/proc/process_scan(atom/scan_target)
return scan_target
/mob/living/simple_animal/bot/proc/add_to_ignore(subject)
/mob/living/simple_animal/bot/proc/add_to_ignore(atom/A)
if(ignore_list.len < 50) //This will help keep track of them, so the bot is always trying to reach a blocked spot.
ignore_list |= subject
else if(ignore_list.len >= subject) //If the list is full, insert newest, delete oldest.
ignore_list -= ignore_list[1]
ignore_list |= subject
ignore_list |= A.UID()
else //If the list is full, insert newest, delete oldest.
ignore_list.Cut(1, 2)
ignore_list |= A.UID()
/*
Movement proc for stepping a bot through a path generated through A-star.
Pass a positive integer as an argument to override a bot's default speed.
@@ -50,7 +50,7 @@
/mob/living/simple_animal/bot/cleanbot/bot_reset()
..()
ignore_list = list() //Allows the bot to clean targets it previously ignored due to being unreachable.
ignore_list.Cut() //Allows the bot to clean targets it previously ignored due to being unreachable.
target = null
oldloc = null
@@ -106,7 +106,7 @@
audible_message("[src] makes an excited beeping booping sound!")
if(!target) //Search for cleanables it can see.
target = scan(/obj/effect/decal/cleanable/)
target = scan(/obj/effect/decal/cleanable)
if(!target && auto_patrol) //Search for cleanables it can see.
if(mode == BOT_IDLE || mode == BOT_START_PATROL)
@@ -56,7 +56,7 @@
..()
target = null
oldloc = null
ignore_list = list()
ignore_list.Cut()
nagged = 0
anchored = FALSE
update_icon()
@@ -270,7 +270,7 @@
return 1
//Floorbots, having several functions, need sort out special conditions here.
/mob/living/simple_animal/bot/floorbot/process_scan(scan_target)
/mob/living/simple_animal/bot/floorbot/process_scan(atom/scan_target)
var/result
var/turf/simulated/floor/F
switch(process_type)
@@ -323,13 +323,13 @@
/mob/living/simple_animal/bot/mulebot/proc/buzz(type)
switch(type)
if(SIGH)
audible_message("[src] makes a sighing buzz.", "<span class='emote'>You hear an electronic buzzing sound.</span>")
audible_message("[src] makes a sighing buzz.")
playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
if(ANNOYED)
audible_message("[src] makes an annoyed buzzing sound.", "<span class='emote'>You hear an electronic buzzing sound.</span>")
audible_message("[src] makes an annoyed buzzing sound.")
playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
if(DELIGHT)
audible_message("[src] makes a delighted ping!", "<span class='emote'>You hear a ping.</span>")
audible_message("[src] makes a delighted ping!")
playsound(loc, 'sound/machines/ping.ogg', 50, 0)
@@ -601,7 +601,7 @@
/mob/living/simple_animal/bot/mulebot/proc/at_target()
if(!reached_target)
radio_channel = "Supply" //Supply channel
audible_message("[src] makes a chiming sound!", "<span class='emote'>You hear a chime.</span>")
audible_message("[src] makes a chiming sound!")
playsound(loc, 'sound/machines/chime.ogg', 50, 0)
reached_target = 1
@@ -20,6 +20,7 @@
melee_damage_upper = 25
attacktext = "slashes"
speak_emote = list("hisses")
bubble_icon = "alien"
a_intent = INTENT_HARM
attack_sound = 'sound/weapons/bladeslice.ogg'
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
@@ -127,6 +128,7 @@
icon_state = "queen_s"
icon_living = "queen_s"
icon_dead = "queen_dead"
bubble_icon = "alienroyal"
move_to_delay = 4
maxHealth = 400
health = 400
@@ -25,7 +25,7 @@
var/list/human_overlays = list()
/mob/living/simple_animal/hostile/headcrab/Life(seconds, times_fired)
if(..())
if(..() && !stat)
if(!is_zombie && isturf(src.loc))
for(var/mob/living/carbon/human/H in oview(src, 1)) //Only for corpse right next to/on same tile
if(H.stat == DEAD || (!H.check_death_method() && H.health <= HEALTH_THRESHOLD_DEAD))
@@ -35,7 +35,7 @@
if(cycles >= 4)
for(var/mob/living/simple_animal/K in oview(src, 1)) //Only for corpse right next to/on same tile
if(K.stat == DEAD || (!K.check_death_method() && K.health <= HEALTH_THRESHOLD_DEAD))
visible_message("<span class='danger'>[src] consumes [target] whole!</span>")
visible_message("<span class='danger'>[src] consumes [K] whole!</span>")
if(health < maxHealth)
health += 10
qdel(K)
@@ -72,7 +72,7 @@
/obj/item/organ/internal/body_egg/changeling_egg/proc/Pop()
var/mob/living/carbon/human/monkey/M = new(owner)
owner.stomach_contents += M
LAZYADD(owner.stomach_contents, M)
for(var/obj/item/organ/internal/I in src)
I.insert(M, 1)
@@ -25,6 +25,7 @@
gold_core_spawnable = HOSTILE_SPAWN
loot = list(/obj/effect/decal/cleanable/blood/gibs/robot)
deathmessage = "blows apart!"
bubble_icon = "machine"
del_on_death = 1
/mob/living/simple_animal/hostile/hivebot/range
@@ -363,6 +363,7 @@
minbodytemp = 0
mob_size = MOB_SIZE_TINY
flying = 1
bubble_icon = "syndibot"
gold_core_spawnable = HOSTILE_SPAWN
del_on_death = 1
deathmessage = "is smashed into pieces!"
@@ -17,6 +17,7 @@
response_harm = "stomps on"
emote_see = list("jiggles", "bounces in place")
speak_emote = list("blorbles")
bubble_icon = "slime"
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
+1
View File
@@ -1,5 +1,6 @@
/mob/Logout()
SSnanoui.user_logout(src) // this is used to clean up (remove) this user's Nano UIs
SStgui.on_logout(src) // Cleanup any TGUIs the user has open
unset_machine()
GLOB.player_list -= src
log_access_out(src)
+31 -7
View File
@@ -20,8 +20,8 @@
AA.viewers -= src
viewing_alternate_appearances = null
logs.Cut()
..()
return QDEL_HINT_HARDDEL
LAssailant = null
return ..()
/mob/Initialize()
GLOB.mob_list += src
@@ -127,14 +127,12 @@
// self_message (optional) is what the src mob hears.
// deaf_message (optional) is what deaf people will see.
// hearing_distance (optional) is the range, how many tiles away the message can be heard.
/mob/audible_message(var/message, var/deaf_message, var/hearing_distance, var/self_message)
/mob/audible_message(message, deaf_message, hearing_distance)
var/range = 7
if(hearing_distance)
range = hearing_distance
var/msg = message
for(var/mob/M in get_mobs_in_view(range, src))
if(self_message && M == src)
msg = self_message
M.show_message(msg, 2, deaf_message, 1)
// based on say code
@@ -156,12 +154,12 @@
// message is the message output to anyone who can hear.
// deaf_message (optional) is what deaf people will see.
// hearing_distance (optional) is the range, how many tiles away the message can be heard.
/atom/proc/audible_message(var/message, var/deaf_message, var/hearing_distance)
/atom/proc/audible_message(message, deaf_message, hearing_distance)
var/range = 7
if(hearing_distance)
range = hearing_distance
for(var/mob/M in get_mobs_in_view(range, src))
M.show_message( message, 2, deaf_message, 1)
M.show_message(message, 2, deaf_message, 1)
/mob/proc/findname(msg)
for(var/mob/M in GLOB.mob_list)
@@ -1390,3 +1388,29 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \
///Force set the mob nutrition
/mob/proc/set_nutrition(change)
nutrition = max(0, change)
/mob/clean_blood(clean_hands = TRUE, clean_mask = TRUE, clean_feet = TRUE)
. = ..()
if(bloody_hands && clean_hands)
bloody_hands = 0
update_inv_gloves()
if(l_hand)
if(l_hand.clean_blood())
update_inv_l_hand()
if(r_hand)
if(r_hand.clean_blood())
update_inv_r_hand()
if(back)
if(back.clean_blood())
update_inv_back()
if(wear_mask && clean_mask)
if(wear_mask.clean_blood())
update_inv_wear_mask()
if(clean_feet)
feet_blood_color = null
qdel(feet_blood_DNA)
bloody_feet = list(BLOOD_STATE_HUMAN = 0, BLOOD_STATE_XENO = 0, BLOOD_STATE_NOT_BLOODY = 0)
blood_state = BLOOD_STATE_NOT_BLOODY
update_inv_shoes()
update_icons() //apply the now updated overlays to the mob
+15 -20
View File
@@ -31,8 +31,8 @@
var/use_me = 1 //Allows all mobs to use the me verb by default, will have to manually specify they cannot
var/damageoverlaytemp = 0
var/computer_id = null
var/lastattacker = null
var/lastattacked = null
var/lastattacker = null // real name of the person doing the attacking
var/lastattackerckey = null // their ckey
var/list/attack_log_old = list( )
var/list/debug_log = null
@@ -50,7 +50,6 @@
var/med_record = ""
var/sec_record = ""
var/gen_record = ""
var/bhunger = 0 //Carbon
var/lying = 0
var/lying_prev = 0
var/lastpuke = 0
@@ -61,8 +60,7 @@
var/emote_type = 1 // Define emote default type, 1 for seen emotes, 2 for heard emotes
var/name_archive //For admin things like possession
var/timeofdeath = 0.0//Living
var/timeofdeath = 0 //Living
var/bodytemperature = 310.055 //98.7 F
var/flying = 0
@@ -71,22 +69,22 @@
var/hunger_drain = HUNGER_FACTOR // how quickly the mob gets hungry; largely utilized by species.
var/overeatduration = 0 // How long this guy is overeating //Carbon
var/intent = null//Living
var/intent = null //Living
var/shakecamera = 0
var/a_intent = INTENT_HELP//Living
var/m_intent = MOVE_INTENT_RUN//Living
var/a_intent = INTENT_HELP //Living
var/m_intent = MOVE_INTENT_RUN //Living
var/lastKnownIP = null
/// movable atoms buckled to this mob
var/atom/movable/buckled = null//Living
var/atom/movable/buckled = null //Living
/// movable atom we are buckled to
var/atom/movable/buckling
var/obj/item/l_hand = null//Living
var/obj/item/r_hand = null//Living
var/obj/item/back = null//Human/Monkey
var/obj/item/tank/internal = null//Human/Monkey
var/obj/item/storage/s_active = null//Carbon
var/obj/item/clothing/mask/wear_mask = null//Carbon
var/obj/item/l_hand = null //Living
var/obj/item/r_hand = null //Living
var/obj/item/back = null //Human
var/obj/item/tank/internal = null //Human
var/obj/item/storage/s_active = null //Carbon
var/obj/item/clothing/mask/wear_mask = null //Carbon
var/datum/hud/hud_used = null
@@ -95,7 +93,6 @@
var/research_scanner = 0 //For research scanner equipped mobs. Enable to show research data when examining.
var/list/grabbed_by = list()
var/list/requests = list()
var/lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE
var/list/mapobjs = list()
@@ -103,9 +100,9 @@
var/emote_cd = 0 // Used to supress emote spamming. 1 if on CD, 2 if disabled by admin (manually set), else 0
var/job = null//Living
var/job = null //Living
var/datum/dna/dna = null//Carbon
var/datum/dna/dna = null //Carbon
var/radiation = 0 //Carbon
var/list/mutations = list() //Carbon -- Doohl
@@ -179,8 +176,6 @@
var/turf/listed_turf = null //the current turf being examined in the stat panel
var/list/shouldnt_see = list() //list of objects that this mob shouldn't see in the stat panel. this silliness is needed because of AI alt+click and cult blood runes
var/kills = 0
var/stance_damage = 0 //Whether this mob's ability to stand has been affected
var/list/active_genes = list()
+1 -1
View File
@@ -408,7 +408,7 @@
add_attack_logs(attacker, affecting, "Devoured")
affecting.forceMove(user)
attacker.stomach_contents.Add(affecting)
LAZYADD(attacker.stomach_contents, affecting)
qdel(src)
/obj/item/grab/proc/checkvalid(var/mob/attacker, var/mob/prey) //does all the checking for the attack proc to see if a mob can eat another with the grab
-8
View File
@@ -12,14 +12,6 @@
return 1
return 0
/mob/proc/isSynthetic()
return 0
/mob/living/carbon/human/isSynthetic()
if(ismachine(src))
return TRUE
return FALSE
/mob/proc/get_screen_colour()
/mob/proc/update_client_colour(var/time = 10) //Update the mob's client.color with an animation the specified time in length.
+1 -1
View File
@@ -114,7 +114,7 @@
return get_turf(src)
/mob/proc/say_test(var/text)
/proc/say_test(text)
var/ending = copytext(text, length(text))
if(ending == "?")
return "1"
+10 -9
View File
@@ -5,31 +5,32 @@ mob/var/typing
mob/var/last_typed
mob/var/last_typed_time
GLOBAL_DATUM(typing_indicator, /image)
GLOBAL_LIST_EMPTY(typing_indicator)
/mob/proc/set_typing_indicator(var/state)
/mob/proc/set_typing_indicator(state)
if(!GLOB.typing_indicator)
GLOB.typing_indicator = image('icons/mob/talk.dmi', null, "typing", MOB_LAYER + 1)
GLOB.typing_indicator.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
if(!GLOB.typing_indicator[bubble_icon])
GLOB.typing_indicator[bubble_icon] = image('icons/mob/talk.dmi', null, "[bubble_icon]typing", FLY_LAYER)
var/image/I = GLOB.typing_indicator[bubble_icon]
I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
if(ishuman(src))
var/mob/living/carbon/human/H = src
if((MUTE in H.mutations) || H.silent)
overlays -= GLOB.typing_indicator
overlays -= GLOB.typing_indicator[bubble_icon]
return
if(client)
if((client.prefs.toggles & SHOW_TYPING) || stat != CONSCIOUS || is_muzzled())
overlays -= GLOB.typing_indicator
overlays -= GLOB.typing_indicator[bubble_icon]
else
if(state)
if(!typing)
overlays += GLOB.typing_indicator
overlays += GLOB.typing_indicator[bubble_icon]
typing = 1
else
if(typing)
overlays -= GLOB.typing_indicator
overlays -= GLOB.typing_indicator[bubble_icon]
typing = 0
return state
-41
View File
@@ -1,41 +0,0 @@
/datum/nano_module/crew_monitor
name = "Crew monitor"
/datum/nano_module/crew_monitor/Topic(href, href_list)
if(..())
return 1
var/turf/T = get_turf(nano_host())
if(!T || !is_level_reachable(T.z))
to_chat(usr, "<span class='warning'><b>Unable to establish a connection</b>: You're too far away from the station!</span>")
return 0
if(href_list["track"])
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
var/mob/living/carbon/human/H = locate(href_list["track"]) in GLOB.mob_list
if(hassensorlevel(H, SUIT_SENSOR_TRACKING))
AI.ai_actual_track(H)
return 1
/datum/nano_module/crew_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "crew_monitor.tmpl", "Crew Monitoring Computer", 900, 800)
// adding a template with the key "mapContent" enables the map ui functionality
ui.add_template("mapContent", "crew_monitor_map_content.tmpl")
// adding a template with the key "mapHeader" replaces the map header content
ui.add_template("mapHeader", "crew_monitor_map_header.tmpl")
ui.open()
// should make the UI auto-update; doesn't seem to?
ui.set_auto_update(1)
/datum/nano_module/crew_monitor/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/data[0]
var/turf/T = get_turf(nano_host())
data["isAI"] = isAI(user)
data["crewmembers"] = GLOB.crew_repository.health_data(T)
return data
+1 -1
View File
@@ -340,7 +340,7 @@
return 0
else
playsound(loc, 'sound/machines/ping.ogg', 50, 0)
atom_say("<span class='danger'>Attention: Posterior Placed on Printing Plaque!</span>")
atom_say("Attention: Posterior Placed on Printing Plaque!")
return 1
/obj/machinery/photocopier/emag_act(user as mob)
+2 -2
View File
@@ -562,13 +562,13 @@ GLOBAL_LIST_INIT(SpookyGhosts, list("ghost","shade","shade2","ghost-narsie","hor
talk_into(M, msg)
for(var/obj/machinery/computer/security/telescreen/T in GLOB.machines)
if(T.watchers[M] == camera)
T.audible_message("<span class='game radio'><span class='name'>(Newscaster) [M]</span> says, '[msg]'", hearing_distance = 2)
T.atom_say(msg)
/obj/item/videocam/hear_message(mob/M as mob, msg)
if(camera && on)
for(var/obj/machinery/computer/security/telescreen/T in GLOB.machines)
if(T.watchers[M] == camera)
T.audible_message("<span class='game radio'><span class='name'>(Newscaster) [M]</span> [msg]", hearing_distance = 2)
T.atom_say(msg)
///hauntings, like hallucinations but more spooky
+2 -2
View File
@@ -47,7 +47,7 @@
SSmob_hunt.connected_clients += src
connected = 1
if(pda)
pda.audible_message("[bicon(pda)] Connection established. Capture all of the mobs, [pda.owner ? pda.owner : "hunter"]!", null, 2)
pda.atom_say("Connection established. Capture all of the mobs, [pda.owner ? pda.owner : "hunter"]!")
return 1
/datum/data/pda/app/mob_hunter_game/proc/get_player()
@@ -67,7 +67,7 @@
connected = 0
//show a disconnect message if we were disconnected involuntarily (reason argument provided)
if(pda && reason)
pda.audible_message("[bicon(pda)] Disconnected from server. Reason: [reason].", null, 2)
pda.atom_say("Disconnected from server. Reason: [reason].")
/datum/data/pda/app/mob_hunter_game/program_process()
if(!SSmob_hunt || !connected)
@@ -12,7 +12,7 @@
select_name = "kill"
/obj/item/ammo_casing/energy/laser/cyborg //to balance cyborg energy cost seperately
e_cost = 250
e_cost = 250
/obj/item/ammo_casing/energy/lasergun
projectile_type = /obj/item/projectile/beam/laser
@@ -75,6 +75,10 @@
e_cost = 125
select_name = "precise"
/obj/item/ammo_casing/energy/immolator/strong/cyborg
// Used by gamma ERT borgs
e_cost = 1000 // 5x that of the standard laser, for 2.25x the damage (if 1/1 shots hit) plus ignite. Not energy-efficient, but can be used for sniping.
/obj/item/ammo_casing/energy/immolator/scatter
projectile_type = /obj/item/projectile/beam/immolator/weak
e_cost = 125
@@ -82,6 +86,10 @@
variance = 25
select_name = "scatter"
/obj/item/ammo_casing/energy/immolator/scatter/cyborg
// Used by gamma ERT borgs
e_cost = 1000 // 5x that of the standard laser, for 7.5x the damage (if 6/6 shots hit) plus ignite. Efficient only if you hit with at least 4/6 of the shots.
/obj/item/ammo_casing/energy/electrode
projectile_type = /obj/item/projectile/energy/electrode
select_name = "stun"
-5
View File
@@ -175,11 +175,6 @@
for(var/datum/reagent/A in D.reagents.reagent_list)
R += A.id + " ("
R += num2text(A.volume) + "),"
if(istype(M, /mob))
if(!iscarbon(user))
M.LAssailant = null
else
M.LAssailant = user
add_attack_logs(user, M, "Shot with dartgun containing [R]")
@@ -253,7 +253,7 @@
icon = 'icons/obj/objects.dmi'
icon_state = "modkit"
origin_tech = "programming=2;materials=2;magnets=4"
require_module = 1
require_module = TRUE
module_type = /obj/item/robot_module/miner
usesound = 'sound/items/screwdriver.ogg'
var/denied_type = null
@@ -139,6 +139,12 @@
var/append = shot.select_name
overlays += image(icon = icon, icon_state = "multilensimmolator-[append]")
/obj/item/gun/energy/immolator/multi/cyborg
name = "cyborg immolator cannon"
ammo_type = list(/obj/item/ammo_casing/energy/immolator/scatter/cyborg, /obj/item/ammo_casing/energy/immolator/strong/cyborg) // scatter is default, because it is more useful
////////Laser Tag////////////////////
/obj/item/gun/energy/laser/tag
+1 -1
View File
@@ -28,7 +28,7 @@
/obj/item/projectile/magic/death/on_hit(mob/living/carbon/C)
. = ..()
if(isliving(C))
if(ismachine(C)) //speshul snowfleks deserv speshul treetment
if(ismachineperson(C)) //speshul snowfleks deserv speshul treetment
C.adjustFireLoss(6969) //remember - slimes love fire
else
C.death()
@@ -83,37 +83,7 @@
M.adjustToxLoss(rand(5, 10))
/datum/reagent/space_cleaner/reaction_mob(mob/living/M, method=REAGENT_TOUCH, volume)
if(iscarbon(M))
var/mob/living/carbon/C = M
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(H.lip_style)
H.lip_style = null
H.update_body()
if(C.r_hand)
C.r_hand.clean_blood()
if(C.l_hand)
C.l_hand.clean_blood()
if(C.wear_mask)
if(C.wear_mask.clean_blood())
C.update_inv_wear_mask()
if(ishuman(M))
var/mob/living/carbon/human/H = C
if(H.head)
if(H.head.clean_blood())
H.update_inv_head()
if(H.wear_suit)
if(H.wear_suit.clean_blood())
H.update_inv_wear_suit()
else if(H.w_uniform)
if(H.w_uniform.clean_blood())
H.update_inv_w_uniform()
if(H.shoes)
if(H.shoes.clean_blood())
H.update_inv_shoes()
M.clean_blood()
..()
M.clean_blood()
/datum/reagent/blood
data = list("donor"=null,"viruses"=null,"blood_DNA"=null,"blood_type"=null,"blood_colour"="#A10808","resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null,"cloneable"=null,"factions"=null, "dna" = null)
@@ -47,7 +47,7 @@
/obj/item/reagent_containers/borghypo/process() //Every [recharge_time] seconds, recharge some reagents for the cyborg
charge_tick++
if(charge_tick < recharge_time)
if(charge_tick < recharge_time)
return FALSE
charge_tick = 0
@@ -97,9 +97,7 @@
var/contained = injected.name
var/trans = R.trans_to(M, amount_per_transfer_from_this)
add_attack_logs(user, M, "Injected with [name] containing [contained], transfered [trans] units", injected.harmless ? ATKLOG_ALMOSTALL : null)
M.LAssailant = user
to_chat(user, "<span class='notice'>[trans] units injected. [R.total_volume] units remaining.</span>")
return
/obj/item/reagent_containers/borghypo/attack_self(mob/user)
playsound(loc, 'sound/effects/pop.ogg', 50, 0) //Change the mode
@@ -126,4 +124,9 @@
if(empty)
. += "<span class='notice'>It is currently empty. Allow some time for the internal syntheszier to produce more.</span>"
/obj/item/reagent_containers/borghypo/basic
name = "Basic Medical Hypospray"
desc = "A very basic medical hypospray, capable of providing simple medical treatment in emergencies."
reagent_ids = list("salglu_solution", "epinephrine")
#undef BORGHYPO_REFILL_VALUE
@@ -43,10 +43,6 @@
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>")
add_attack_logs(user, M, "Splashed with [name] containing [contained]", !!M.ckey ? null : ATKLOG_ALL)
if(!iscarbon(user))
M.LAssailant = null
else
M.LAssailant = user
reagents.reaction(M, REAGENT_TOUCH)
reagents.clear_reagents()
@@ -20,7 +20,7 @@
if(M.eat(src, user))
user.drop_item()
forceMove(M)
M.processing_patches += src
LAZYADD(M.processing_patches, src)
return TRUE
return FALSE
+32 -37
View File
@@ -207,7 +207,10 @@
else if(target != user && !user.restrained() && !user.stat && !user.IsWeakened() && !user.stunned && !user.paralysis)
msg = "[user.name] stuffs [target.name] into the [src]!"
to_chat(user, "You stuff [target.name] into the [src]!")
if(!iscarbon(user))
target.LAssailant = null
else
target.LAssailant = user
add_attack_logs(user, target, "Disposal'ed", !!target.ckey ? null : ATKLOG_ALL)
else
return
@@ -237,10 +240,10 @@
// ai as human but can't flush
/obj/machinery/disposal/attack_ai(mob/user as mob)
src.add_hiddenprint(user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/disposal/attack_ghost(mob/user as mob)
ui_interact(user)
tgui_interact(user)
// human interact with machine
/obj/machinery/disposal/attack_hand(mob/user as mob)
@@ -256,76 +259,68 @@
// Clumsy folks can only flush it.
if(user.IsAdvancedToolUser())
ui_interact(user)
tgui_interact(user)
else
flush = !flush
update()
return
/obj/machinery/disposal/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/disposal/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "disposal_bin.tmpl", "Waste Disposal Unit", 395, 250)
ui = new(user, src, ui_key, "DisposalBin", name, 300, 250, master_ui, state)
ui.open()
ui.set_auto_update(1)
/obj/machinery/disposal/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/data[0]
var/pressure = clamp(100* air_contents.return_pressure() / (SEND_PRESSURE), 0, 100)
var/pressure_round = round(pressure,1)
/obj/machinery/disposal/tgui_data(mob/user)
var/list/data = list()
data["isAI"] = isAI(user)
data["flushing"] = flush
data["mode"] = mode
if(mode <= 0)
data["pumpstatus"] = "N/A"
else if(mode == 1)
data["pumpstatus"] = "Pressurizing"
else if(mode == 2)
data["pumpstatus"] = "Ready"
else
data["pumpstatus"] = "Idle"
data["pressure"] = pressure_round
data["pressure"] = round(clamp(100* air_contents.return_pressure() / (SEND_PRESSURE), 0, 100),1)
return data
/obj/machinery/disposal/Topic(href, href_list)
/obj/machinery/disposal/tgui_act(action, params)
if(..())
return
if(usr.loc == src)
to_chat(usr, "<span class='warning'>You cannot reach the controls from inside.</span>")
return
if(mode==-1 && !href_list["eject"]) // only allow ejecting if mode is -1
if(mode==-1 && action != "eject") // If the mode is -1, only allow ejection
to_chat(usr, "<span class='warning'>The disposal units power is disabled.</span>")
return
if(..())
return
if(stat & BROKEN)
return
src.add_fingerprint(usr)
if(usr.stat || usr.restrained() || src.flushing)
if(src.flushing)
return
if(istype(src.loc, /turf))
if(href_list["pump"])
if(text2num(href_list["pump"]))
mode = 1
else
mode = 0
if(action == "pumpOn")
mode = 1
update()
if(action == "pumpOff")
mode = 0
update()
if(!isAI(usr))
if(href_list["handle"])
flush = text2num(href_list["handle"])
if(!issilicon(usr))
if(action == "engageHandle")
flush = 1
update()
if(action == "disengageHandle")
flush = 0
update()
if(href_list["eject"])
if(action == "eject")
eject()
return
return TRUE
// eject the contents of the disposal unit
/obj/machinery/disposal/proc/eject()
@@ -1081,8 +1081,17 @@
construction_time = 120
category = list("Cyborg Upgrade Modules")
/datum/design/borg_upgrade_lavaproof
name = "Cyborg Upgrade (Lavaproof Chassis)"
id = "borg_upgrade_lavaproof"
build_type = MECHFAB
build_path = /obj/item/borg/upgrade/lavaproof
materials = list(MAT_METAL = 10000, MAT_PLASMA = 4000, MAT_TITANIUM = 5000)
construction_time = 120
category = list("Cyborg Upgrade Modules")
/datum/design/borg_syndicate_module
name = "Cyborg Upgrade (Illegal Modules)"
name = "Cyborg Upgrade (Safety Override)"
id = "borg_syndicate_module"
build_type = MECHFAB
req_tech = list("combat" = 4, "syndicate" = 2)
+2 -2
View File
@@ -103,12 +103,12 @@ GLOBAL_LIST_EMPTY(message_servers)
if(2)
if(!Console.silent)
playsound(Console.loc, 'sound/machines/twobeep.ogg', 50, 1)
Console.audible_message(text("[bicon(Console)] *The Requests Console beeps: 'PRIORITY Alert in [sender]'"),,5)
Console.atom_say("PRIORITY Alert in [sender]")
Console.message_log += "<B><FONT color='red'>High Priority message from <A href='?src=[Console.UID()];write=[sender]'>[sender]</A></FONT></B><BR>[authmsg]"
else
if(!Console.silent)
playsound(Console.loc, 'sound/machines/twobeep.ogg', 50, 1)
Console.audible_message(text("[bicon(Console)] *The Requests Console beeps: 'Message from [sender]'"),,4)
Console.atom_say("Message from [sender]")
Console.message_log += "<B>Message from <A href='?src=[Console.UID()];write=[sender]'>[sender]</A></B><BR>[authmsg]"
Console.set_light(2)
+4 -7
View File
@@ -135,8 +135,7 @@ GLOBAL_VAR_INIT(ert_request_answered, FALSE)
/client/proc/create_response_team(new_gender, role, turf/spawn_location)
if(role == "Cyborg")
var/cyborg_unlock = GLOB.active_team.getCyborgUnlock()
var/mob/living/silicon/robot/ert/R = new /mob/living/silicon/robot/ert(spawn_location, cyborg_unlock)
var/mob/living/silicon/robot/ert/R = new GLOB.active_team.borg_path(spawn_location)
return R
var/mob/living/carbon/human/M = new(null)
@@ -208,7 +207,7 @@ GLOBAL_VAR_INIT(ert_request_answered, FALSE)
var/security_outfit
var/janitor_outfit
var/paranormal_outfit
var/cyborg_unlock = 0
var/borg_path = /mob/living/silicon/robot/ert
/datum/response_team/proc/setSlots(com=1, sec=3, med=3, eng=3, jan=0, par=0, cyb=0)
slots["Commander"] = com
@@ -223,9 +222,6 @@ GLOBAL_VAR_INIT(ert_request_answered, FALSE)
slots[role]--
count++
/datum/response_team/proc/getCyborgUnlock()
return cyborg_unlock
/datum/response_team/proc/get_slot_list()
RETURN_TYPE(/list)
var/list/slots_available = list()
@@ -285,6 +281,7 @@ GLOBAL_VAR_INIT(ert_request_answered, FALSE)
command_outfit = /datum/outfit/job/centcom/response_team/commander/red
janitor_outfit = /datum/outfit/job/centcom/response_team/janitorial/red
paranormal_outfit = /datum/outfit/job/centcom/response_team/paranormal/red
borg_path = /mob/living/silicon/robot/ert/red
/datum/response_team/red/announce_team()
GLOB.event_announcement.Announce("Attention, [station_name()]. We are sending a code RED Emergency Response Team. Standby.", "ERT En-Route")
@@ -298,7 +295,7 @@ GLOBAL_VAR_INIT(ert_request_answered, FALSE)
command_outfit = /datum/outfit/job/centcom/response_team/commander/gamma
janitor_outfit = /datum/outfit/job/centcom/response_team/janitorial/gamma
paranormal_outfit = /datum/outfit/job/centcom/response_team/paranormal/gamma
cyborg_unlock = 1
borg_path = /mob/living/silicon/robot/ert/gamma
/datum/response_team/gamma/announce_team()
GLOB.event_announcement.Announce("Attention, [station_name()]. We are sending a code GAMMA elite Emergency Response Team. Standby.", "ERT En-Route")
+1 -1
View File
@@ -5,8 +5,8 @@
icon_state = "away"
has_gravity = TRUE
there_can_be_many = TRUE
ambientsounds = list('sound/ambience/ambimine.ogg')
dynamic_lighting = DYNAMIC_LIGHTING_FORCED
ambientsounds = RUINS_SOUNDS
/area/ruin/unpowered
always_unpowered = FALSE
@@ -31,15 +31,6 @@ GLOBAL_DATUM_INIT(security_announcement_down, /datum/announcement/priority/secur
// Mark down this time to prevent shuttle cheese
SSshuttle.emergency_sec_level_time = world.time
// Reset gamma borgs if the new security level is lower than Gamma.
if(level < SEC_LEVEL_GAMMA)
for(var/M in GLOB.silicon_mob_list)
if(isrobot(M))
var/mob/living/silicon/robot/R = M
if(istype(R.module, /obj/item/robot_module/combat) && !R.crisis)
R.reset_module()
to_chat(R, "<span class='warning'>Crisis mode deactivated. The combat module is no longer available and your module has been reset.</span>")
switch(level)
if(SEC_LEVEL_GREEN)
GLOB.security_announcement_down.Announce("All threats to the station have passed. All weapons need to be holstered and privacy laws are once again fully enforced.","Attention! Security level lowered to green.")
+1 -1
View File
@@ -32,7 +32,7 @@
if(ishuman(target))
var/mob/living/carbon/human/H = target
var/obj/item/organ/external/affected = H.get_organ(user.zone_selected)
if(ismachine(target))
if(ismachineperson(target))
// RIP bi-centennial man
return 0
if(!affected)
+1 -1
View File
@@ -54,7 +54,7 @@
var/obj/item/organ/external/BP = X
var/brutedamage = BP.brute_dam
if(BP.is_robotic() && !isSynthetic())
if(BP.is_robotic() && !ismachineperson(src))
continue
//We want an accurate reading of .len
+1 -1
View File
@@ -138,7 +138,7 @@ GLOBAL_LIST_EMPTY(limb_icon_cache)
add_overlay(facial_s)
if(h_style)
if(!owner.isSynthetic() || (owner.isSynthetic() && ((owner.head && (owner.head.flags & BLOCKHEADHAIR)) || (owner.wear_mask && (owner.wear_mask.flags & BLOCKHEADHAIR)))))
if(!ismachineperson(owner) || (ismachineperson(owner) && ((owner.head && (owner.head.flags & BLOCKHEADHAIR)) || (owner.wear_mask && (owner.wear_mask.flags & BLOCKHEADHAIR)))))
var/datum/sprite_accessory/hair_style = GLOB.hair_styles_full_list[h_style]
if(hair_style && ((dna.species.name in hair_style.species_allowed) || (dna.species.bodyflags & ALL_RPARTS)))
var/icon/hair_s = new /icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s")
+155
View File
@@ -0,0 +1,155 @@
/**
* tgui external
*
* Contains all external tgui declarations.
*/
/**
* public
*
* Used to open and update UIs.
* If this proc is not implemented properly, the UI will not update correctly.
*
* required user mob The mob who opened/is using the UI.
* optional ui_key string The ui_key of the UI.
* optional ui datum/tgui The UI to be updated, if it exists.
* optional force_open bool If the UI should be re-opened instead of updated.
* optional master_ui datum/tgui The parent UI.
* optional state datum/ui_state The state used to determine status.
*/
/datum/proc/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
return FALSE // Not implemented.
/**
* public
*
* Data to be sent to the UI.
* This must be implemented for a UI to work.
*
* required user mob The mob interacting with the UI.
*
* return list Data to be sent to the UI.
*/
/datum/proc/tgui_data(mob/user)
return list() // Not implemented.
/**
* public
*
* Static Data to be sent to the UI.
* Static data differs from normal data in that it's large data that should be sent infrequently
* This is implemented optionally for heavy uis that would be sending a lot of redundant data
* frequently.
* Gets squished into one object on the frontend side, but the static part is cached.
*
* required user mob The mob interacting with the UI.
*
* return list Statuic Data to be sent to the UI.
*/
/datum/proc/tgui_static_data(mob/user)
return list()
/**
* public
*
* Forces an update on static data. Should be done manually whenever something happens to change static data.
*
* required user the mob currently interacting with the ui
* optional ui ui to be updated
* optional ui_key ui key of ui to be updated
*/
/datum/proc/update_tgui_static_data(mob/user, datum/tgui/ui, ui_key = "main")
ui = SStgui.try_update_ui(user, src, ui_key, ui)
// If there was no ui to update, there's no static data to update either.
if(!ui)
return
ui.push_data(null, tgui_static_data(), TRUE)
/**
* public
*
* Called on a UI when the UI receieves a href.
* Think of this as Topic().
*
* required action string The action/button that has been invoked by the user.
* required params list A list of parameters attached to the button.
*
* return bool If the UI should be updated or not.
*/
/datum/proc/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
// If UI is not interactive or usr calling Topic is not the UI user, bail.
if(!ui || ui.status != STATUS_INTERACTIVE)
return TRUE
/**
* public
*
* Called on an object when a tgui object is being created, allowing you to
* customise the html
* For example: inserting a custom stylesheet that you need in the head
*
* For this purpose, some tags are available in the html, to be parsed out
^ with replacetext
* (customheadhtml) - Additions to the head tag
*
* required html the html base text
*/
/datum/proc/tgui_base_html(html)
return html
/**
* private
*
* The UI's host object (usually src_object).
* This allows modules/datums to have the UI attached to them,
* and be a part of another object.
*/
/datum/proc/tgui_host(mob/user)
return src // Default src.
/**
* global
*
* Associative list of JSON-encoded shared states that were set by
* tgui clients.
*/
/datum/var/list/tgui_shared_states
/**
* global
*
* Used to track UIs for a mob.
*/
/mob/var/list/open_tguis = list()
/**
* public
*
* Called on a UI's object when the UI is closed, not to be confused with
* client/verb/uiclose(), which closes the ui window
*/
/datum/proc/tgui_close(mob/user)
/**
* verb
*
* Called by UIs when they are closed.
* Must be a verb so winset() can call it.
*
* required uiref ref The UI that was closed.
*/
/client/verb/tguiclose(uid as text)
// Name the verb, and hide it from the user panel.
set name = "uiclose"
set hidden = TRUE
// Get the UI based on the ref.
var/datum/tgui/ui = locateUID(uid)
// If we found the UI, close it.
if(istype(ui))
ui.close()
// Unset machine just to be sure.
if(src && src.mob)
src.mob.unset_machine()
+21
View File
@@ -0,0 +1,21 @@
/*
TGUI MODULES
This allows for datum-based TGUIs that can be hooked into objects.
This is useful for things such as the power monitor, which needs to exist on a physical console in the world, but also as a virtual device the AI can use
Code is pretty much ripped verbatim from nano modules, but with un-needed stuff removed
*/
/datum/tgui_module
var/name
var/datum/host
/datum/tgui_module/New(var/host)
src.host = host
/datum/tgui_module/tgui_host()
return host ? host : src
/datum/tgui_module/tgui_close(mob/user)
if(host)
host.tgui_close(user)
+39
View File
@@ -0,0 +1,39 @@
/datum/tgui_module/crew_monitor
name = "Crew monitor"
/datum/tgui_module/crew_monitor/tgui_act(action, params)
if(..())
return TRUE
var/turf/T = get_turf(tgui_host())
if(!T || !is_level_reachable(T.z))
to_chat(usr, "<span class='warning'><b>Unable to establish a connection</b>: You're too far away from the station!</span>")
return FALSE
switch(action)
if("track")
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
var/mob/living/carbon/human/H = locate(params["track"]) in GLOB.mob_list
if(hassensorlevel(H, SUIT_SENSOR_TRACKING))
AI.ai_actual_track(H)
return TRUE
/datum/tgui_module/crew_monitor/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
// The 557 may seem random, but its the perfectsize for margins on the nanomap
ui = new(user, src, ui_key, "CrewMonitor", name, 1400, 557, master_ui, state)
ui.autoupdate = TRUE
ui.open()
/datum/tgui_module/crew_monitor/tgui_data(mob/user)
var/data[0]
var/turf/T = get_turf(tgui_host())
data["isAI"] = isAI(user)
data["crewmembers"] = GLOB.crew_repository.health_data(T)
return data
+117
View File
@@ -0,0 +1,117 @@
/**
* tgui states
*
* Base state and helpers for states. Just does some sanity checks, implement a state for in-depth checks.
*/
/**
* public
*
* Checks the UI state for a mob.
*
* required user mob The mob who opened/is using the UI.
* required state datum/ui_state The state to check.
*
* return UI_state The state of the UI.
*/
/datum/proc/tgui_status(mob/user, datum/tgui_state/state)
var/src_object = tgui_host(user)
. = STATUS_CLOSE
if(!state)
return
if(isobserver(user))
// If they turn on ghost AI control, admins can always interact.
if(user.client.advanced_admin_interaction)
. = max(., STATUS_INTERACTIVE)
// Regular ghosts can always at least view if in range.
var/clientviewlist = getviewsize(user.client.view)
if(get_dist(src_object, user) < max(clientviewlist[1],clientviewlist[2]))
. = max(., STATUS_UPDATE)
// Check if the state allows interaction
var/result = state.can_use_topic(src_object, user)
. = max(., result)
/**
* private
*
* Checks if a user can use src_object's UI, and returns the state.
* Can call a mob proc, which allows overrides for each mob.
*
* required src_object datum The object/datum which owns the UI.
* required user mob The mob who opened/is using the UI.
*
* return UI_state The state of the UI.
*/
/datum/tgui_state/proc/can_use_topic(src_object, mob/user)
return STATUS_CLOSE // Don't allow interaction by default.
/**
* public
*
* Standard interaction/sanity checks. Different mob types may have overrides.
*
* return UI_state The state of the UI.
*/
/mob/proc/shared_tgui_interaction(src_object)
if(!client) // Close UIs if mindless.
return STATUS_CLOSE
else if(stat) // Disable UIs if unconcious.
return STATUS_DISABLED
else if(incapacitated()) // Update UIs if incapicitated but concious.
return STATUS_UPDATE
return STATUS_INTERACTIVE
/mob/living/silicon/ai/shared_tgui_interaction(src_object)
if(lacks_power()) // Disable UIs if the AI is unpowered.
return STATUS_DISABLED
return ..()
/mob/living/silicon/robot/shared_tgui_interaction(src_object)
if(!cell || cell.charge <= 0 || lockcharge) // Disable UIs if the Borg is unpowered or locked.
return STATUS_DISABLED
return ..()
/**
* public
*
* Check the distance for a living mob.
* Really only used for checks outside the context of a mob.
* Otherwise, use shared_living_ui_distance().
*
* required src_object The object which owns the UI.
* required user mob The mob who opened/is using the UI.
*
* return UI_state The state of the UI.
*/
/atom/proc/contents_tgui_distance(src_object, mob/living/user)
return user.shared_living_tgui_distance(src_object) // Just call this mob's check.
/**
* public
*
* Distance versus interaction check.
*
* required src_object atom/movable The object which owns the UI.
*
* return UI_state The state of the UI.
*/
/mob/living/proc/shared_living_tgui_distance(atom/movable/src_object, viewcheck = TRUE)
if(viewcheck && !(src_object in view(src))) // If the object is obscured, close it.
return STATUS_CLOSE
var/dist = get_dist(src_object, src)
if(dist <= 1) // Open and interact if 1-0 tiles away.
return STATUS_INTERACTIVE
else if(dist <= 2) // View only if 2-3 tiles away.
return STATUS_UPDATE
else if(dist <= 5) // Disable if 5 tiles away.
return STATUS_DISABLED
return STATUS_CLOSE // Otherwise, we got nothing.
/mob/living/carbon/human/shared_living_tgui_distance(atom/movable/src_object)
if((TK in mutations) && (get_dist(src, src_object) <= 2))
return STATUS_INTERACTIVE
return ..()
+12
View File
@@ -0,0 +1,12 @@
/**
* tgui state: admin_state
*
* Checks that the user is an admin, end-of-story.
**/
GLOBAL_DATUM_INIT(tgui_admin_state, /datum/tgui_state/admin_state, new)
/datum/tgui_state/admin_state/can_use_topic(src_object, mob/user)
if(check_rights_for(user.client, R_ADMIN))
return STATUS_INTERACTIVE
return STATUS_CLOSE
+11
View File
@@ -0,0 +1,11 @@
/**
* tgui state: always_state
*
* Always grants the user UI_INTERACTIVE. Period.
**/
GLOBAL_DATUM_INIT(tgui_always_state, /datum/tgui_state/always_state, new)
/datum/tgui_state/always_state/can_use_topic(src_object, mob/user)
return STATUS_INTERACTIVE
+12
View File
@@ -0,0 +1,12 @@
/**
* tgui state: conscious_state
*
* Only checks if the user is conscious.
**/
GLOBAL_DATUM_INIT(tgui_conscious_state, /datum/tgui_state/conscious_state, new)
/datum/tgui_state/conscious_state/can_use_topic(src_object, mob/user)
if(user.stat == CONSCIOUS)
return STATUS_INTERACTIVE
return STATUS_CLOSE
+12
View File
@@ -0,0 +1,12 @@
/**
* tgui state: contained_state
*
* Checks that the user is inside the src_object.
**/
GLOBAL_DATUM_INIT(tgui_contained_state, /datum/tgui_state/contained_state, new)
/datum/tgui_state/contained_state/can_use_topic(atom/src_object, mob/user)
if(!src_object.contains(user))
return STATUS_CLOSE
return user.shared_tgui_interaction(src_object)
@@ -0,0 +1,12 @@
/**
* tgui state: deep_inventory_state
*
* Checks that the src_object is in the user's deep (backpack, box, toolbox, etc) inventory.
**/
GLOBAL_DATUM_INIT(tgui_deep_inventory_state, /datum/tgui_state/deep_inventory_state, new)
/datum/tgui_state/deep_inventory_state/can_use_topic(src_object, mob/user)
if(!user.contains(src_object))
return STATUS_CLOSE
return user.shared_tgui_interaction(src_object)
+63
View File
@@ -0,0 +1,63 @@
/**
* tgui state: default_state
*
* Checks a number of things -- mostly physical distance for humans and view for robots.
**/
GLOBAL_DATUM_INIT(tgui_default_state, /datum/tgui_state/default, new)
/datum/tgui_state/default/can_use_topic(src_object, mob/user)
return user.default_can_use_tgui_topic(src_object) // Call the individual mob-overridden procs.
/mob/proc/default_can_use_tgui_topic(src_object)
return STATUS_CLOSE // Don't allow interaction by default.
/mob/living/default_can_use_tgui_topic(src_object)
. = shared_tgui_interaction(src_object)
if(. > STATUS_CLOSE && loc)
. = min(., loc.contents_tgui_distance(src_object, src)) // Check the distance...
if(. == STATUS_INTERACTIVE) // Non-human living mobs can only look, not touch.
return STATUS_UPDATE
/mob/living/carbon/human/default_can_use_tgui_topic(src_object)
. = shared_tgui_interaction(src_object)
if(. > STATUS_CLOSE)
. = min(., shared_living_tgui_distance(src_object)) // Check the distance...
/mob/living/silicon/robot/default_can_use_tgui_topic(src_object)
. = shared_tgui_interaction(src_object)
if(. <= STATUS_DISABLED)
return
// Robots can interact with anything they can see.
var/list/clientviewlist = getviewsize(client.view)
if((src_object in view(src)) && (get_dist(src, src_object) <= min(clientviewlist[1],clientviewlist[2])))
return STATUS_INTERACTIVE
return STATUS_DISABLED // Otherwise they can keep the UI open.
/mob/living/silicon/ai/default_can_use_tgui_topic(src_object)
. = shared_tgui_interaction(src_object)
if(. < STATUS_INTERACTIVE)
return
// The AI can interact with anything it can see nearby, or with cameras while wireless control is enabled.
if(!control_disabled && can_see(src_object))
return STATUS_INTERACTIVE
return STATUS_CLOSE
/mob/living/simple_animal/default_can_use_tgui_topic(src_object)
. = shared_tgui_interaction(src_object)
if(. > STATUS_CLOSE)
. = min(., shared_living_tgui_distance(src_object)) //simple animals can only use things they're near.
/mob/living/silicon/pai/default_can_use_tgui_topic(src_object)
// pAIs can only use themselves and the owner's radio.
if((src_object == src || src_object == radio) && !stat)
return STATUS_INTERACTIVE
else
return ..()
/mob/dead/observer/default_can_use_tgui_topic()
if(can_admin_interact())
return STATUS_INTERACTIVE // Admins are more equal
return STATUS_UPDATE // Ghosts can view updates
+25
View File
@@ -0,0 +1,25 @@
/**
* tgui state: hands_state
*
* Checks that the src_object is in the user's hands.
**/
GLOBAL_DATUM_INIT(tgui_hands_state, /datum/tgui_state/hands_state, new)
/datum/tgui_state/hands_state/can_use_topic(src_object, mob/user)
. = user.shared_tgui_interaction(src_object)
if(. > STATUS_CLOSE)
return min(., user.hands_can_use_tgui_topic(src_object))
/mob/proc/hands_can_use_tgui_topic(src_object)
return STATUS_CLOSE
/mob/living/hands_can_use_tgui_topic(src_object)
if(is_in_active_hand(src_object) || is_in_inactive_hand(src_object))
return STATUS_INTERACTIVE
return STATUS_CLOSE
/mob/living/silicon/robot/hands_can_use_tgui_topic(src_object)
if(activated(src_object))
return STATUS_INTERACTIVE
return STATUS_CLOSE
@@ -0,0 +1,17 @@
/**
* tgui state: human_adjacent_state
*
* In addition to default checks, only allows interaction for a
* human adjacent user.
**/
GLOBAL_DATUM_INIT(tgui_human_adjacent_state, /datum/tgui_state/human_adjacent_state, new)
/datum/tgui_state/human_adjacent_state/can_use_topic(src_object, mob/user)
. = user.default_can_use_tgui_topic(src_object)
var/dist = get_dist(src_object, user)
if((dist > 1) || (!ishuman(user)))
// Can't be used unless adjacent and human, even with TK
. = min(., STATUS_UPDATE)
+12
View File
@@ -0,0 +1,12 @@
/**
* tgui state: inventory_state
*
* Checks that the src_object is in the user's top-level (hand, ear, pocket, belt, etc) inventory.
**/
GLOBAL_DATUM_INIT(tgui_inventory_state, /datum/tgui_state/inventory_state, new)
/datum/tgui_state/inventory_state/can_use_topic(src_object, mob/user)
if(!(src_object in user))
return STATUS_CLOSE
return user.shared_tgui_interaction(src_object)
@@ -0,0 +1,29 @@
/**
* tgui state: not_incapacitated_state
*
* Checks that the user isn't incapacitated
**/
GLOBAL_DATUM_INIT(tgui_not_incapacitated_state, /datum/tgui_state/not_incapacitated_state, new)
/**
* tgui state: not_incapacitated_turf_state
*
* Checks that the user isn't incapacitated and that their loc is a turf
**/
GLOBAL_DATUM_INIT(tgui_not_incapacitated_turf_state, /datum/tgui_state/not_incapacitated_state, new(no_turfs = TRUE))
/datum/tgui_state/not_incapacitated_state
var/turf_check = FALSE
/datum/tgui_state/not_incapacitated_state/New(loc, no_turfs = FALSE)
..()
turf_check = no_turfs
/datum/tgui_state/not_incapacitated_state/can_use_topic(src_object, mob/user)
if(user.stat)
return STATUS_CLOSE
if(user.incapacitated() || (turf_check && !isturf(user.loc)))
return STATUS_DISABLED
return STATUS_INTERACTIVE
+26
View File
@@ -0,0 +1,26 @@
/**
* tgui state: notcontained_state
*
* Checks that the user is not inside src_object, and then makes the default checks.
**/
GLOBAL_DATUM_INIT(tgui_notcontained_state, /datum/tgui_state/notcontained_state, new)
/datum/tgui_state/notcontained_state/can_use_topic(atom/src_object, mob/user)
. = user.shared_tgui_interaction(src_object)
if(. > STATUS_CLOSE)
return min(., user.notcontained_can_use_tgui_topic(src_object))
/mob/proc/notcontained_can_use_tgui_topic(src_object)
return STATUS_CLOSE
/mob/living/notcontained_can_use_tgui_topic(atom/src_object)
if(src_object.contains(src))
return STATUS_CLOSE // Close if we're inside it.
return default_can_use_tgui_topic(src_object)
/mob/living/silicon/notcontained_can_use_tgui_topic(src_object)
return default_can_use_tgui_topic(src_object) // Silicons use default bevhavior.
/mob/living/simple_animal/drone/notcontained_can_use_tgui_topic(src_object)
return default_can_use_tgui_topic(src_object) // Drones use default bevhavior.
+15
View File
@@ -0,0 +1,15 @@
/**
* tgui state: observer_state
*
* Checks that the user is an observer/ghost.
**/
GLOBAL_DATUM_INIT(tgui_observer_state, /datum/tgui_state/observer_state, new)
/datum/tgui_state/observer_state/can_use_topic(src_object, mob/user)
if(isobserver(user))
return STATUS_INTERACTIVE
if(check_rights(R_ADMIN, 0, src))
return STATUS_INTERACTIVE
return STATUS_CLOSE
+24
View File
@@ -0,0 +1,24 @@
/**
* tgui state: physical_state
*
* Short-circuits the default state to only check physical distance.
**/
GLOBAL_DATUM_INIT(tgui_physical_state, /datum/tgui_state/physical, new)
/datum/tgui_state/physical/can_use_topic(src_object, mob/user)
. = user.shared_tgui_interaction(src_object)
if(. > STATUS_CLOSE)
return min(., user.physical_can_use_tgui_topic(src_object))
/mob/proc/physical_can_use_tgui_topic(src_object)
return STATUS_CLOSE
/mob/living/physical_can_use_tgui_topic(src_object)
return shared_living_tgui_distance(src_object)
/mob/living/silicon/physical_can_use_tgui_topic(src_object)
return max(STATUS_UPDATE, shared_living_tgui_distance(src_object)) // Silicons can always see.
/mob/living/silicon/ai/physical_can_use_tgui_topic(src_object)
return STATUS_UPDATE // AIs are not physical.

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