mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-16 01:23:41 +01:00
fixes merge conflict
This commit is contained in:
@@ -108,7 +108,7 @@ world/IsBanned(key, address, computer_id, check_ipintel = TRUE)
|
||||
var/appealmessage = ""
|
||||
if(config.banappeals)
|
||||
appealmessage = " You may appeal it at <a href='[config.banappeals]'>[config.banappeals]</a>."
|
||||
expires = " This is a permanent ban.[appealmessage]"
|
||||
expires = " This ban does not expire automatically and must be appealed.[appealmessage]"
|
||||
|
||||
var/desc = "\nReason: You, or another user of this computer or connection ([pckey]) is banned from playing here. The ban reason is:\n[reason]\nThis ban was applied by [ackey] on [bantime].[expires]"
|
||||
|
||||
|
||||
@@ -167,7 +167,6 @@ var/global/nologevent = 0
|
||||
body += "<B>Is an AI</B> "
|
||||
else if(ishuman(M))
|
||||
body += {"<A href='?_src_=holder;makeai=[M.UID()]'>Make AI</A> |
|
||||
<A href='?_src_=holder;makemask=[M.UID()]'>Make Mask</A> |
|
||||
<A href='?_src_=holder;makerobot=[M.UID()]'>Make Robot</A> |
|
||||
<A href='?_src_=holder;makealien=[M.UID()]'>Make Alien</A> |
|
||||
<A href='?_src_=holder;makeslime=[M.UID()]'>Make Slime</A> |
|
||||
|
||||
@@ -169,6 +169,14 @@
|
||||
message_admins("Ban process: A mob matching [playermob.ckey] was found at location [playermob.x], [playermob.y], [playermob.z]. Custom IP and computer id fields replaced with the IP and computer id from the located mob")
|
||||
|
||||
DB_ban_record(bantype, playermob, banduration, banreason, banjob, null, banckey, banip, bancid )
|
||||
if(BANTYPE_PERMA)
|
||||
add_note(banckey, "Permanently Banned - [banreason]", null, usr.ckey, 0)
|
||||
else if(BANTYPE_TEMP)
|
||||
add_note(banckey, "Banned for [banduration] minutes - [banreason]", null, usr.ckey, 0)
|
||||
else if(BANTYPE_JOB_PERMA)
|
||||
add_note(banckey, "Banned from [banjob] - [banreason]", null, usr.ckey, 0)
|
||||
else
|
||||
add_note(banckey, "[banreason]", null, usr.ckey, 0)
|
||||
|
||||
|
||||
else if(href_list["editrights"])
|
||||
@@ -1007,14 +1015,14 @@
|
||||
return
|
||||
AddBan(M.ckey, M.computer_id, reason, usr.ckey, 0, 0, M.lastKnownIP)
|
||||
to_chat(M, "<span class='warning'><BIG><B>You have been banned by [usr.client.ckey].\nReason: [reason].</B></BIG></span>")
|
||||
to_chat(M, "<span class='warning'>This is a permanent ban.</span>")
|
||||
to_chat(M, "<span class='warning'>This ban does not expire automatically and must be appealed.</span>")
|
||||
if(config.banappeals)
|
||||
to_chat(M, "<span class='warning'>To try to resolve this matter head to [config.banappeals]</span>")
|
||||
else
|
||||
to_chat(M, "<span class='warning'>No ban appeals URL has been set.</span>")
|
||||
ban_unban_log_save("[usr.client.ckey] has permabanned [M.ckey]. - Reason: [reason] - This is a permanent ban.")
|
||||
log_admin("[key_name(usr)] has banned [M.ckey].\nReason: [reason]\nThis is a permanent ban.")
|
||||
message_admins("<span class='notice'>[key_name_admin(usr)] has banned [M.ckey].\nReason: [reason]\nThis is a permanent ban.</span>")
|
||||
ban_unban_log_save("[usr.client.ckey] has permabanned [M.ckey]. - Reason: [reason] - This ban does not expire automatically and must be appealed.")
|
||||
log_admin("[key_name(usr)] has banned [M.ckey].\nReason: [reason]\nThis ban does not expire automatically and must be appealed.")
|
||||
message_admins("<span class='notice'>[key_name_admin(usr)] has banned [M.ckey].\nReason: [reason]\nThis ban does not expire automatically and must be appealed.</span>")
|
||||
feedback_inc("ban_perma",1)
|
||||
DB_ban_record(BANTYPE_PERMA, M, -1, reason)
|
||||
|
||||
|
||||
@@ -15,13 +15,15 @@
|
||||
|
||||
*/
|
||||
|
||||
/client/proc/SDQL2_query(query_text as message)
|
||||
/client/proc/SDQL2_query()
|
||||
set category = "Debug"
|
||||
|
||||
if(!check_rights(R_PROCCALL)) //Shouldn't happen... but just to be safe.
|
||||
message_admins("<span class='danger'>ERROR: Non-admin [key_name_admin(usr)] attempted to execute a SDQL query!</span>")
|
||||
log_admin("Non-admin [key_name(usr)] attempted to execute a SDQL query!")
|
||||
|
||||
var/query_text = input("SDQL2 query") as message
|
||||
|
||||
if(!query_text || length(query_text) < 1)
|
||||
return
|
||||
|
||||
|
||||
@@ -185,3 +185,4 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","
|
||||
else
|
||||
send2irc(source, "[msg] - All admins AFK ([admin_number_afk]/[admin_number_total]) or skipped ([admin_number_ignored]/[admin_number_total])")
|
||||
return admin_number_present
|
||||
|
||||
@@ -279,6 +279,9 @@
|
||||
/datum/pm_tracker/proc/add_message(client/title, client/sender, message, mob/user)
|
||||
if(!pms[title.key])
|
||||
pms[title.key] = new /datum/pm_convo(title)
|
||||
else if(!pms[title.key].client)
|
||||
// If they DCed earlier, we need to add the client reference back
|
||||
pms[title.key].client = title
|
||||
pms[title.key].add(sender, message)
|
||||
|
||||
if(!open)
|
||||
@@ -308,16 +311,25 @@
|
||||
dat += "<a class='[class]' href='?src=[UID()];newtitle=[title]'>[label]</a>"
|
||||
|
||||
var/datum/pm_convo/convo = pms[current_title]
|
||||
var/datum/browser/popup = new(user, window_id, "Messages", 1000, 600, src)
|
||||
if(convo)
|
||||
popup.add_head_content(@{"<script type='text/javascript'>
|
||||
window.onload = function () {
|
||||
var msgs = document.getElementById('msgs');
|
||||
msgs.scrollTop = msgs.scrollHeight;
|
||||
}
|
||||
</script>"})
|
||||
convo.read = TRUE
|
||||
dat += "<h2>[check_rights(R_ADMIN, FALSE, user) ? fancy_title(current_title) : current_title]</h2>"
|
||||
dat += "<h4>"
|
||||
dat += "<table style='width:950px; border: 3px solid;'>"
|
||||
dat += "<div id='msgs' style='width:950px; border: 3px solid; overflow-y: scroll; height: 350px;'>"
|
||||
dat += "<table>"
|
||||
|
||||
for(var/message in convo.messages)
|
||||
dat += "<tr><td>[message]</td></tr>"
|
||||
|
||||
dat += "</table>"
|
||||
dat += "</div>"
|
||||
if(convo.typing)
|
||||
dat += "<i><span class='typing'>[current_title] is typing</span></i>"
|
||||
dat += "<br>"
|
||||
@@ -327,17 +339,23 @@
|
||||
if(check_rights(R_ADMIN, FALSE, user))
|
||||
dat += "<a href='?src=[UID()];ping=[current_title]'>Ping</a>"
|
||||
|
||||
var/datum/browser/popup = new(user, window_id, "Messages", 1000, 600, src)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
open = TRUE
|
||||
|
||||
/datum/pm_tracker/proc/fancy_title(title)
|
||||
var/client/C = pms[title].client
|
||||
var/client/C = pms[title].client || update_client(title)
|
||||
if(!C)
|
||||
return "[title] (Disconnected)"
|
||||
return "[key_name(C, FALSE)] ([ADMIN_QUE(C.mob,"?")]) ([ADMIN_PP(C.mob,"PP")]) ([ADMIN_VV(C.mob,"VV")]) ([ADMIN_SM(C.mob,"SM")]) ([admin_jump_link(C.mob)]) (<A HREF='?_src_=holder;check_antagonist=1'>CA</A>)"
|
||||
|
||||
/datum/pm_tracker/proc/update_client(title)
|
||||
var/client/C = GLOB.directory[ckey(title)]
|
||||
if(C)
|
||||
pms[title].client = C
|
||||
return C
|
||||
return null
|
||||
|
||||
/datum/pm_tracker/Topic(href, href_list)
|
||||
if(href_list["archive"])
|
||||
pms[href_list["archive"]].archived = !pms[href_list["archive"]].archived
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
|
||||
feedback_add_details("admin_verb","M") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/get_admin_say()
|
||||
var/msg = input(src, null, "asay \"text\"") as text|null
|
||||
cmd_admin_say(msg)
|
||||
|
||||
/client/proc/cmd_mentor_say(msg as text)
|
||||
set category = "Admin"
|
||||
set name = "Msay"
|
||||
|
||||
@@ -43,3 +43,7 @@
|
||||
say_dead_direct("<span class='name'>[prefix]</span> says, <span class='message'>\"[msg]\"</span>")
|
||||
|
||||
feedback_add_details("admin_verb","D") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/get_dead_say()
|
||||
var/msg = input(src, null, "dsay \"text\"") as text
|
||||
dsay(msg)
|
||||
@@ -77,9 +77,9 @@
|
||||
if(bombassembly)
|
||||
bombassembly.HasProximity(AM)
|
||||
|
||||
/obj/item/onetankbomb/Crossed(atom/movable/AM) //for mousetraps
|
||||
/obj/item/onetankbomb/Crossed(atom/movable/AM, oldloc) //for mousetraps
|
||||
if(bombassembly)
|
||||
bombassembly.Crossed(AM)
|
||||
bombassembly.Crossed(AM, oldloc)
|
||||
|
||||
/obj/item/onetankbomb/on_found(mob/finder) //for mousetraps
|
||||
if(bombassembly)
|
||||
|
||||
@@ -85,11 +85,11 @@
|
||||
a_right.HasProximity(AM)
|
||||
|
||||
|
||||
/obj/item/assembly_holder/Crossed(atom/movable/AM)
|
||||
/obj/item/assembly_holder/Crossed(atom/movable/AM, oldloc)
|
||||
if(a_left)
|
||||
a_left.Crossed(AM)
|
||||
a_left.Crossed(AM, oldloc)
|
||||
if(a_right)
|
||||
a_right.Crossed(AM)
|
||||
a_right.Crossed(AM, oldloc)
|
||||
|
||||
/obj/item/assembly_holder/on_found(mob/finder)
|
||||
if(a_left)
|
||||
@@ -116,7 +116,7 @@
|
||||
a_right.holder_movement()
|
||||
|
||||
/obj/item/assembly_holder/Move()
|
||||
..()
|
||||
. = ..()
|
||||
process_movement()
|
||||
return
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
|
||||
/obj/item/assembly/infra/Move()
|
||||
var/t = dir
|
||||
..()
|
||||
. = ..()
|
||||
dir = t
|
||||
qdel(first)
|
||||
|
||||
@@ -269,7 +269,7 @@
|
||||
/obj/effect/beam/i_beam/Bumped()
|
||||
hit()
|
||||
|
||||
/obj/effect/beam/i_beam/Crossed(atom/movable/AM)
|
||||
/obj/effect/beam/i_beam/Crossed(atom/movable/AM, oldloc)
|
||||
if(!isobj(AM) && !isliving(AM))
|
||||
return
|
||||
if(istype(AM, /obj/effect))
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/assembly/mousetrap/Crossed(atom/movable/AM)
|
||||
/obj/item/assembly/mousetrap/Crossed(atom/movable/AM, oldloc)
|
||||
if(armed)
|
||||
if(ishuman(AM))
|
||||
var/mob/living/carbon/H = AM
|
||||
|
||||
@@ -432,6 +432,8 @@
|
||||
l_pocket = /obj/item/reagent_containers/food/pill/patch/styptic
|
||||
r_pocket = /obj/item/flashlight/seclite
|
||||
|
||||
/obj/effect/mob_spawn/human/miner/explorer
|
||||
outfit = /datum/outfit/job/mining/equipped
|
||||
|
||||
/obj/effect/mob_spawn/human/bartender
|
||||
name = "Space Bartender"
|
||||
|
||||
@@ -36,9 +36,226 @@
|
||||
if(prob(1))
|
||||
mezzer()
|
||||
|
||||
|
||||
/obj/item/clothing/glasses/meson/truesight
|
||||
name = "The Lens of Truesight"
|
||||
desc = "I can see forever!"
|
||||
icon_state = "monocle"
|
||||
item_state = "headset"
|
||||
item_state = "headset"
|
||||
|
||||
// Die of Fate
|
||||
/obj/item/dice/d20/fate
|
||||
name = "\improper Die of Fate"
|
||||
desc = "A die with twenty sides. You can feel unearthly energies radiating from it. Using this might be VERY risky."
|
||||
icon_state = "d20"
|
||||
var/reusable = TRUE
|
||||
var/used = FALSE
|
||||
|
||||
/obj/item/dice/d20/fate/stealth
|
||||
name = "d20"
|
||||
desc = "A die with twenty sides. The preferred die to throw at the GM."
|
||||
|
||||
/obj/item/dice/d20/fate/one_use
|
||||
reusable = FALSE
|
||||
|
||||
/obj/item/dice/d20/fate/one_use/stealth
|
||||
name = "d20"
|
||||
desc = "A die with twenty sides. The preferred die to throw at the GM."
|
||||
|
||||
/obj/item/dice/d20/fate/cursed
|
||||
name = "cursed Die of Fate"
|
||||
desc = "A die with twenty sides. You feel that rolling this is a REALLY bad idea."
|
||||
color = "#00BB00"
|
||||
|
||||
rigged = DICE_TOTALLY_RIGGED
|
||||
rigged_value = 1
|
||||
|
||||
/obj/item/dice/d20/fate/diceroll(mob/user)
|
||||
. = ..()
|
||||
if(!used)
|
||||
if(!ishuman(user) || !user.mind || (user.mind in SSticker.mode.wizards))
|
||||
to_chat(user, "<span class='warning'>You feel the magic of the dice is restricted to ordinary humans!</span>")
|
||||
return
|
||||
|
||||
if(!reusable)
|
||||
used = TRUE
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
T.visible_message("<span class='userdanger'>[src] flares briefly.</span>")
|
||||
|
||||
addtimer(CALLBACK(src, .proc/effect, user, .), 1 SECONDS)
|
||||
|
||||
/obj/item/dice/d20/fate/equipped(mob/user, slot)
|
||||
if(!ishuman(user) || !user.mind || (user.mind in SSticker.mode.wizards))
|
||||
to_chat(user, "<span class='warning'>You feel the magic of the dice is restricted to ordinary humans! You should leave it alone.</span>")
|
||||
user.unEquip(src)
|
||||
|
||||
/obj/item/dice/d20/fate/proc/create_smoke(amount)
|
||||
var/datum/effect_system/smoke_spread/smoke = new
|
||||
smoke.set_up(amount, 0, drop_location())
|
||||
smoke.start()
|
||||
|
||||
/obj/item/dice/d20/fate/proc/effect(var/mob/living/carbon/human/user, roll)
|
||||
var/turf/T = get_turf(src)
|
||||
switch(roll)
|
||||
if(1)
|
||||
//Dust
|
||||
T.visible_message("<span class='userdanger'>[user] turns to dust!</span>")
|
||||
user.dust()
|
||||
if(2)
|
||||
//Death
|
||||
T.visible_message("<span class='userdanger'>[user] suddenly dies!</span>")
|
||||
user.death()
|
||||
if(3)
|
||||
//Swarm of creatures
|
||||
T.visible_message("<span class='userdanger'>A swarm of creatures surround [user]!</span>")
|
||||
for(var/direction in alldirs)
|
||||
new /mob/living/simple_animal/hostile/netherworld(get_step(get_turf(user),direction))
|
||||
if(4)
|
||||
//Destroy Equipment
|
||||
T.visible_message("<span class='userdanger'>Everything [user] is holding and wearing disappears!</span>")
|
||||
for(var/obj/item/I in user)
|
||||
if(istype(I, /obj/item/implant) || istype(I, /obj/item/organ))
|
||||
continue
|
||||
qdel(I)
|
||||
if(5)
|
||||
//Monkeying
|
||||
T.visible_message("<span class='userdanger'>[user] transforms into a monkey!</span>")
|
||||
user.monkeyize()
|
||||
if(6)
|
||||
//Cut speed
|
||||
T.visible_message("<span class='userdanger'>[user] starts moving slower!</span>")
|
||||
var/datum/species/S = user.dna.species
|
||||
S.slowdown += 1
|
||||
if(7)
|
||||
//Throw
|
||||
T.visible_message("<span class='userdanger'>Unseen forces throw [user]!</span>")
|
||||
user.Stun(6)
|
||||
user.adjustBruteLoss(50)
|
||||
var/throw_dir = cardinal
|
||||
var/atom/throw_target = get_edge_target_turf(user, throw_dir)
|
||||
user.throw_at(throw_target, 200, 4)
|
||||
if(8)
|
||||
//Fueltank Explosion
|
||||
T.visible_message("<span class='userdanger'>An explosion bursts into existence around [user]!</span>")
|
||||
explosion(get_turf(user),-1,0,2, flame_range = 2)
|
||||
if(9)
|
||||
//Cold
|
||||
var/datum/disease/D = new /datum/disease/cold()
|
||||
T.visible_message("<span class='userdanger'>[user] looks a little under the weather!</span>")
|
||||
user.ForceContractDisease(D)
|
||||
if(10)
|
||||
//Nothing
|
||||
T.visible_message("<span class='userdanger'>Nothing seems to happen.</span>")
|
||||
if(11)
|
||||
//Cookie
|
||||
T.visible_message("<span class='userdanger'>A cookie appears out of thin air!</span>")
|
||||
var/obj/item/reagent_containers/food/snacks/cookie/C = new(drop_location())
|
||||
create_smoke(2)
|
||||
C.name = "Cookie of Fate"
|
||||
if(12)
|
||||
//Healing
|
||||
T.visible_message("<span class='userdanger'>[user] looks very healthy!</span>")
|
||||
user.revive()
|
||||
if(13)
|
||||
//Mad Dosh
|
||||
T.visible_message("<span class='userdanger'>Mad dosh shoots out of [src]!</span>")
|
||||
var/turf/Start = get_turf(src)
|
||||
for(var/direction in alldirs)
|
||||
var/turf/dirturf = get_step(Start,direction)
|
||||
if(rand(0,1))
|
||||
new /obj/item/stack/spacecash/c1000(dirturf)
|
||||
else
|
||||
var/obj/item/storage/bag/money/M = new(dirturf)
|
||||
for(var/i in 1 to rand(5,50))
|
||||
new /obj/item/coin/gold(M)
|
||||
if(14)
|
||||
//Free Gun
|
||||
T.visible_message("<span class='userdanger'>An impressive gun appears!</span>")
|
||||
create_smoke(2)
|
||||
new /obj/item/gun/projectile/revolver/mateba(drop_location())
|
||||
if(15)
|
||||
//Random One-use spellbook
|
||||
T.visible_message("<span class='userdanger'>A magical looking book drops to the floor!</span>")
|
||||
create_smoke(2)
|
||||
new /obj/item/spellbook/oneuse/random(drop_location())
|
||||
if(16)
|
||||
//Servant & Servant Summon
|
||||
T.visible_message("<span class='userdanger'>A Dice Servant appears in a cloud of smoke!</span>")
|
||||
var/mob/living/carbon/human/H = new(drop_location())
|
||||
create_smoke(2)
|
||||
|
||||
H.equipOutfit(/datum/outfit/butler)
|
||||
var/datum/mind/servant_mind = new /datum/mind()
|
||||
var/datum/objective/O = new
|
||||
O.owner = servant_mind
|
||||
O.target = user.mind
|
||||
O.explanation_text = "Serve [user.real_name]."
|
||||
servant_mind.objectives += O
|
||||
servant_mind.transfer_to(H)
|
||||
|
||||
var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as the servant of [user.real_name]?", ROLE_WIZARD, poll_time = 50)
|
||||
if(LAZYLEN(candidates))
|
||||
var/mob/dead/observer/C = pick(candidates)
|
||||
message_admins("[ADMIN_LOOKUPFLW(C)] was spawned as Dice Servant")
|
||||
H.key = C.key
|
||||
to_chat(H, "<span class='notice'>You are a servant of [user.real_name]. You must do everything in your power to follow their orders.</span>")
|
||||
|
||||
var/obj/effect/proc_holder/spell/targeted/summonmob/S = new
|
||||
S.target_mob = H
|
||||
user.mind.AddSpell(S)
|
||||
|
||||
if(17)
|
||||
//Tator Kit
|
||||
T.visible_message("<span class='userdanger'>A suspicious box appears!</span>")
|
||||
new /obj/item/storage/box/syndicate(drop_location())
|
||||
create_smoke(2)
|
||||
if(18)
|
||||
//Captain ID
|
||||
T.visible_message("<span class='userdanger'>A golden identification card appears!</span>")
|
||||
new /obj/item/card/id/captains_spare(drop_location())
|
||||
create_smoke(2)
|
||||
if(19)
|
||||
//Instrinct Resistance
|
||||
T.visible_message("<span class='userdanger'>[user] looks very robust!</span>")
|
||||
var/datum/species/S = user.dna.species
|
||||
S.brute_mod *= 0.5
|
||||
S.burn_mod *= 0.5
|
||||
|
||||
if(20)
|
||||
//Free wizard!
|
||||
T.visible_message("<span class='userdanger'>Magic flows out of [src] and into [user]!</span>")
|
||||
user.mind.make_Wizard()
|
||||
|
||||
// Butler outfit
|
||||
/datum/outfit/butler
|
||||
name = "Butler"
|
||||
uniform = /obj/item/clothing/under/suit_jacket/really_black
|
||||
shoes = /obj/item/clothing/shoes/laceup
|
||||
head = /obj/item/clothing/head/bowlerhat
|
||||
glasses = /obj/item/clothing/glasses/monocle
|
||||
gloves = /obj/item/clothing/gloves/color/white
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/summonmob
|
||||
name = "Summon Servant"
|
||||
desc = "This spell can be used to call your servant, whenever you need it."
|
||||
charge_max = 100
|
||||
clothes_req = 0
|
||||
invocation = "JE VES"
|
||||
invocation_type = "whisper"
|
||||
range = -1
|
||||
level_max = 0 //cannot be improved
|
||||
cooldown_min = 100
|
||||
include_user = 1
|
||||
|
||||
var/mob/living/target_mob
|
||||
|
||||
action_icon_state = "summons"
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/summonmob/cast(list/targets, mob/user = usr)
|
||||
if(!target_mob)
|
||||
return
|
||||
var/turf/Start = get_turf(user)
|
||||
for(var/direction in alldirs)
|
||||
var/turf/T = get_step(Start,direction)
|
||||
if(!T.density)
|
||||
target_mob.Move(T)
|
||||
|
||||
@@ -19,22 +19,22 @@
|
||||
* Areas
|
||||
*/
|
||||
//Gateroom gets its own APC specifically for the gate
|
||||
/area/awaymission/gateroom
|
||||
/area/awaymission/gateroom
|
||||
|
||||
//Library, medbay, storage room
|
||||
/area/awaymission/southblock
|
||||
/area/awaymission/southblock
|
||||
|
||||
//Arrivals, security, hydroponics, shuttles (since they dont move, they dont need specific areas)
|
||||
/area/awaymission/arrivalblock
|
||||
/area/awaymission/arrivalblock
|
||||
|
||||
//Crew quarters, cafeteria, chapel
|
||||
/area/awaymission/midblock
|
||||
/area/awaymission/midblock
|
||||
|
||||
//engineering, bridge (not really north but it doesnt really need its own APC)
|
||||
/area/awaymission/northblock
|
||||
/area/awaymission/northblock
|
||||
|
||||
//That massive research room
|
||||
/area/awaymission/research
|
||||
/area/awaymission/research
|
||||
|
||||
//Syndicate shuttle
|
||||
/area/awaymission/syndishuttle
|
||||
|
||||
@@ -140,7 +140,7 @@
|
||||
/obj/effect/meatgrinder/New()
|
||||
icon_state = "blobpod"
|
||||
|
||||
/obj/effect/meatgrinder/Crossed(AM as mob|obj)
|
||||
/obj/effect/meatgrinder/Crossed(AM as mob|obj, oldloc)
|
||||
Bumped(AM)
|
||||
|
||||
/obj/effect/meatgrinder/Bumped(mob/M as mob|obj)
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/obj/effect/step_trigger/message
|
||||
var/message //the message to give to the mob
|
||||
var/once = 1
|
||||
|
||||
/obj/effect/step_trigger/message/Trigger(mob/M as mob)
|
||||
if(M.client)
|
||||
to_chat(M, "<span class='info'>[message]</span>")
|
||||
if(once)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/step_trigger/teleport_fancy
|
||||
var/locationx
|
||||
var/locationy
|
||||
var/uses = 1 //0 for infinite uses
|
||||
var/entersparks = 0
|
||||
var/exitsparks = 0
|
||||
var/entersmoke = 0
|
||||
var/exitsmoke = 0
|
||||
|
||||
/obj/effect/step_trigger/teleport_fancy/Trigger(mob/M as mob)
|
||||
var/dest = locate(locationx, locationy, z)
|
||||
M.Move(dest)
|
||||
|
||||
if(entersparks)
|
||||
do_sparks(4, 1, src)
|
||||
if(exitsparks)
|
||||
do_sparks(4, 1, dest)
|
||||
|
||||
if(entersmoke)
|
||||
var/datum/effect_system/smoke_spread/s = new
|
||||
s.set_up(4, 1, src, 0)
|
||||
s.start()
|
||||
if(exitsmoke)
|
||||
var/datum/effect_system/smoke_spread/s = new
|
||||
s.set_up(4, 1, dest, 0)
|
||||
s.start()
|
||||
|
||||
uses--
|
||||
if(uses == 0)
|
||||
qdel(src)
|
||||
@@ -65,7 +65,7 @@
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/effect/portal_sensor/Crossed(A)
|
||||
/obj/effect/portal_sensor/Crossed(A, oldloc)
|
||||
trigger()
|
||||
|
||||
/obj/effect/portal_sensor/Uncrossed(A)
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
/client
|
||||
//////////////////////
|
||||
//BLACK MAGIC THINGS//
|
||||
//////////////////////
|
||||
parent_type = /datum
|
||||
////////////////
|
||||
//ADMIN THINGS//
|
||||
////////////////
|
||||
@@ -24,7 +28,7 @@
|
||||
|
||||
var/adminhelped = 0
|
||||
|
||||
var/gc_destroyed //Time when this object was destroyed.
|
||||
// var/gc_destroyed //Time when this object was destroyed. [Inherits from datum]
|
||||
|
||||
#ifdef TESTING
|
||||
var/running_find_references
|
||||
@@ -89,5 +93,5 @@
|
||||
// If set to true, this client can interact with atoms such as buttons and doors on top of regular machinery interaction
|
||||
var/advanced_admin_interaction = FALSE
|
||||
|
||||
// Has the client been varedited by an admin?
|
||||
var/var_edited = FALSE
|
||||
// Has the client been varedited by an admin? [Inherits from datum now]
|
||||
// var/var_edited = FALSE
|
||||
|
||||
@@ -297,14 +297,14 @@
|
||||
return null
|
||||
if(byond_build < config.minimum_client_build)
|
||||
alert(src, "You are using a byond build which is not supported by this server. Please use a build version of atleast [config.minimum_client_build].", "Incorrect build", "OK")
|
||||
del(src)
|
||||
qdel(src)
|
||||
return
|
||||
if(byond_version < SUGGESTED_CLIENT_VERSION) // Update is suggested, but not required.
|
||||
to_chat(src,"<span class='userdanger'>Your BYOND client (v: [byond_version]) is out of date. This can cause glitches. We highly suggest you download the latest client from http://www.byond.com/ before playing. </span>")
|
||||
|
||||
if(IsGuestKey(key))
|
||||
alert(src,"This server doesn't allow guest accounts to play. Please go to http://www.byond.com/ and register for a key.","Guest","OK")
|
||||
del(src)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
// Change the way they should download resources.
|
||||
@@ -317,7 +317,6 @@
|
||||
|
||||
GLOB.clients += src
|
||||
GLOB.directory[ckey] = src
|
||||
|
||||
//Admin Authorisation
|
||||
// Automatically makes localhost connection an admin
|
||||
if(!config.disable_localhost_admin)
|
||||
@@ -365,11 +364,14 @@
|
||||
|
||||
. = ..() //calls mob.Login()
|
||||
|
||||
|
||||
if(ckey in clientmessages)
|
||||
for(var/message in clientmessages[ckey])
|
||||
to_chat(src, message)
|
||||
clientmessages.Remove(ckey)
|
||||
|
||||
if(SSinput.initialized)
|
||||
set_macros()
|
||||
|
||||
donator_check()
|
||||
check_ip_intel()
|
||||
@@ -404,8 +406,7 @@
|
||||
|
||||
if(!winexists(src, "asset_cache_browser")) // The client is using a custom skin, tell them.
|
||||
to_chat(src, "<span class='warning'>Unable to access asset cache browser, if you are using a custom skin file, please allow DS to download the updated version, if you are not, then make a bug report. This is not a critical issue but can cause issues with resource downloading, as it is impossible to know when extra resources arrived to you.</span>")
|
||||
|
||||
|
||||
|
||||
//This is down here because of the browse() calls in tooltip/New()
|
||||
if(!tooltips)
|
||||
tooltips = new /datum/tooltip(src)
|
||||
@@ -664,7 +665,7 @@
|
||||
sleep(10) // Since browse is non-instant, and kinda async
|
||||
|
||||
to_chat(src, "<pre class=\"system system\">you're a huge nerd. wakka wakka doodle doop nobody's ever gonna see this, the chat system shouldn't be online by this point</pre>")
|
||||
del(src)
|
||||
qdel(src)
|
||||
return TRUE
|
||||
else
|
||||
if (!topic || !topic["token"] || !tokens[ckey] || topic["token"] != tokens[ckey])
|
||||
@@ -675,7 +676,7 @@
|
||||
tokens[ckey] = cid_check_reconnect()
|
||||
|
||||
sleep(10) //browse is queued, we don't want them to disconnect before getting the browse() command.
|
||||
del(src)
|
||||
qdel(src)
|
||||
return TRUE
|
||||
// We DO have their cached CID handy - compare it, now
|
||||
if(oldcid != computer_id)
|
||||
@@ -693,7 +694,7 @@
|
||||
|
||||
log_adminwarn("Failed Login: [key] [computer_id] [address] - CID randomizer confirmed (oldcid: [oldcid])")
|
||||
|
||||
del(src)
|
||||
qdel(src)
|
||||
return TRUE
|
||||
else
|
||||
// don't shoot, I'm innocent
|
||||
@@ -795,18 +796,15 @@
|
||||
/* Mainwindow */
|
||||
winset(src, "mainwindow.saybutton", "background-color=#40628a;text-color=#FFFFFF")
|
||||
winset(src, "mainwindow.mebutton", "background-color=#40628a;text-color=#FFFFFF")
|
||||
winset(src, "mainwindow.hotkey_toggle", "background-color=#40628a;text-color=#FFFFFF")
|
||||
///// UI ELEMENTS /////
|
||||
/* Mainwindow */
|
||||
winset(src, "mainwindow", "background-color=#272727")
|
||||
winset(src, "mainwindow.mainvsplit", "background-color=#272727")
|
||||
winset(src, "mainwindow.tooltip", "background-color=#272727")
|
||||
/* Outputwindow */
|
||||
winset(src, "outputwindow.outputwindow", "background-color=#272727")
|
||||
winset(src, "outputwindow.browseroutput", "background-color=#272727")
|
||||
/* Rpane */
|
||||
winset(src, "rpane", "background-color=#272727")
|
||||
winset(src, "rpane.rpane", "background-color=#272727")
|
||||
winset(src, "rpane.rpanewindow", "background-color=#272727")
|
||||
/* Browserwindow */
|
||||
winset(src, "browserwindow", "background-color=#272727")
|
||||
@@ -830,18 +828,15 @@
|
||||
/* Mainwindow */
|
||||
winset(src, "mainwindow.saybutton", "background-color=none;text-color=#000000")
|
||||
winset(src, "mainwindow.mebutton", "background-color=none;text-color=#000000")
|
||||
winset(src, "mainwindow.hotkey_toggle", "background-color=none;text-color=#000000")
|
||||
///// UI ELEMENTS /////
|
||||
/* Mainwindow */
|
||||
winset(src, "mainwindow", "background-color=none")
|
||||
winset(src, "mainwindow.mainvsplit", "background-color=none")
|
||||
winset(src, "mainwindow.tooltip", "background-color=none")
|
||||
/* Outputwindow */
|
||||
winset(src, "outputwindow.outputwindow", "background-color=none")
|
||||
winset(src, "outputwindow.browseroutput", "background-color=none")
|
||||
/* Rpane */
|
||||
winset(src, "rpane", "background-color=none")
|
||||
winset(src, "rpane.rpane", "background-color=none")
|
||||
winset(src, "rpane.rpanewindow", "background-color=none")
|
||||
/* Browserwindow */
|
||||
winset(src, "browserwindow", "background-color=none")
|
||||
|
||||
@@ -81,7 +81,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts
|
||||
var/lastchangelog = "" //Saved changlog filesize to detect if there was a change
|
||||
var/exp
|
||||
var/ooccolor = "#b82e00"
|
||||
var/be_special = list() //Special role selection
|
||||
var/list/be_special = list() //Special role selection
|
||||
var/UI_style = "Midnight"
|
||||
var/nanoui_fancy = TRUE
|
||||
var/toggles = TOGGLES_DEFAULT
|
||||
@@ -93,6 +93,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts
|
||||
var/clientfps = 0
|
||||
var/atklog = ATKLOG_ALL
|
||||
var/fuid // forum userid
|
||||
var/afk_watch = FALSE // If the player wants to be kept track of by the AFK system
|
||||
|
||||
//ghostly preferences
|
||||
var/ghost_anonsay = 0
|
||||
@@ -439,6 +440,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts
|
||||
dat += "<h2>General Settings</h2>"
|
||||
if(user.client.holder)
|
||||
dat += "<b>Adminhelp sound:</b> <a href='?_src_=prefs;preference=hear_adminhelps'><b>[(sound & SOUND_ADMINHELP)?"On":"Off"]</b></a><br>"
|
||||
dat += "<b>AFK Cryoing:</b> <a href='?_src_=prefs;preference=afk_watch'>[(afk_watch) ? "Yes" : "No"]</a><br>"
|
||||
dat += "<b>Ambient Occlusion:</b> <a href='?_src_=prefs;preference=ambientocclusion'><b>[toggles & AMBIENT_OCCLUSION ? "Enabled" : "Disabled"]</b></a><br>"
|
||||
dat += "<b>Attack Animations:</b> <a href='?_src_=prefs;preference=ghost_att_anim'>[(show_ghostitem_attack) ? "Yes" : "No"]</a><br>"
|
||||
if(unlock_content)
|
||||
@@ -455,6 +457,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts
|
||||
dat += "<b>Ghost Ears:</b> <a href='?_src_=prefs;preference=ghost_ears'><b>[(toggles & CHAT_GHOSTEARS) ? "All Speech" : "Nearest Creatures"]</b></a><br>"
|
||||
dat += "<b>Ghost Radio:</b> <a href='?_src_=prefs;preference=ghost_radio'><b>[(toggles & CHAT_GHOSTRADIO) ? "All Chatter" : "Nearest Speakers"]</b></a><br>"
|
||||
dat += "<b>Ghost Sight:</b> <a href='?_src_=prefs;preference=ghost_sight'><b>[(toggles & CHAT_GHOSTSIGHT) ? "All Emotes" : "Nearest Creatures"]</b></a><br>"
|
||||
dat += "<b>Ghost PDA:</b> <a href='?_src_=prefs;preference=ghost_pda'><b>[(toggles & CHAT_GHOSTPDA) ? "All PDA Messages" : "No PDA Messages"]</b></a><br>"
|
||||
if(check_rights(R_ADMIN,0))
|
||||
dat += "<b>OOC Color:</b> <span style='border: 1px solid #161616; background-color: [ooccolor ? ooccolor : normal_ooc_colour];'> </span> <a href='?_src_=prefs;preference=ooccolor;task=input'><b>Change</b></a><br>"
|
||||
if(config.allow_Metadata)
|
||||
@@ -1976,6 +1979,9 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts
|
||||
if("winflash")
|
||||
windowflashing = !windowflashing
|
||||
|
||||
if("afk_watch")
|
||||
afk_watch = !afk_watch
|
||||
|
||||
if("UIcolor")
|
||||
var/UI_style_color_new = input(user, "Choose your UI color, dark colors are not recommended!", UI_style_color) as color|null
|
||||
if(!UI_style_color_new) return
|
||||
@@ -2029,6 +2035,9 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts
|
||||
|
||||
if("ghost_radio")
|
||||
toggles ^= CHAT_GHOSTRADIO
|
||||
|
||||
if("ghost_pda")
|
||||
toggles ^= CHAT_GHOSTPDA
|
||||
|
||||
if("ghost_anonsay")
|
||||
ghost_anonsay = !ghost_anonsay
|
||||
@@ -2280,3 +2289,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts
|
||||
|
||||
/datum/preferences/proc/close_load_dialog(mob/user)
|
||||
user << browse(null, "window=saves")
|
||||
|
||||
//Check if the user has ANY job selected.
|
||||
/datum/preferences/proc/check_any_job()
|
||||
return(job_support_high || job_support_med || job_support_low || job_medsci_high || job_medsci_med || job_medsci_low || job_engsec_high || job_engsec_med || job_engsec_low || job_karma_high || job_karma_med || job_karma_low)
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
exp,
|
||||
clientfps,
|
||||
atklog,
|
||||
fuid
|
||||
fuid,
|
||||
afk_watch
|
||||
FROM [format_table_name("player")]
|
||||
WHERE ckey='[C.ckey]'"}
|
||||
)
|
||||
@@ -52,6 +53,7 @@
|
||||
clientfps = text2num(query.item[17])
|
||||
atklog = text2num(query.item[18])
|
||||
fuid = text2num(query.item[19])
|
||||
afk_watch = text2num(query.item[20])
|
||||
|
||||
//Sanitize
|
||||
ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor))
|
||||
@@ -72,6 +74,7 @@
|
||||
clientfps = sanitize_integer(clientfps, 0, 1000, initial(clientfps))
|
||||
atklog = sanitize_integer(atklog, 0, 100, initial(atklog))
|
||||
fuid = sanitize_integer(fuid, 0, 10000000, initial(fuid))
|
||||
afk_watch = sanitize_integer(afk_watch, 0, 1, initial(afk_watch))
|
||||
return 1
|
||||
|
||||
/datum/preferences/proc/save_preferences(client/C)
|
||||
@@ -90,7 +93,7 @@
|
||||
UI_style_alpha='[UI_style_alpha]',
|
||||
be_role='[sanitizeSQL(list2params(be_special))]',
|
||||
default_slot='[default_slot]',
|
||||
toggles='[num2text(toggles, 7)]',
|
||||
toggles='[num2text(toggles, Ceiling(log(10, (TOGGLES_TOTAL))))]',
|
||||
atklog='[atklog]',
|
||||
sound='[sound]',
|
||||
randomslot='[randomslot]',
|
||||
@@ -101,7 +104,8 @@
|
||||
windowflashing='[windowflashing]',
|
||||
ghost_anonsay='[ghost_anonsay]',
|
||||
clientfps='[clientfps]',
|
||||
atklog='[atklog]'
|
||||
atklog='[atklog]',
|
||||
afk_watch='[afk_watch]'
|
||||
WHERE ckey='[C.ckey]'"}
|
||||
)
|
||||
|
||||
|
||||
@@ -241,4 +241,36 @@
|
||||
to_chat(usr, "<span class='notice'>You have enabled text popup limiting.")
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>You have disabled text popup limiting.")
|
||||
return
|
||||
|
||||
/client/verb/numpad_target()
|
||||
set name = "Toggle Numpad targetting"
|
||||
set category = "Preferences"
|
||||
set desc = "This button will allow you to enable or disable Numpad Targetting"
|
||||
prefs.toggles ^= NUMPAD_TARGET
|
||||
prefs.save_preferences(src)
|
||||
if (prefs.toggles & NUMPAD_TARGET)
|
||||
to_chat(usr, "<span class='notice'>You have enabled Numpad Targetting.")
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>You have disabled Numpad Targetting.")
|
||||
return
|
||||
|
||||
/client/verb/azerty_toggle()
|
||||
set name = "Toggle QWERTY/AZERTY"
|
||||
set category = "Preferences"
|
||||
set desc = "This button will switch you between QWERTY and AZERTY control sets"
|
||||
prefs.toggles ^= AZERTY
|
||||
prefs.save_preferences(src)
|
||||
if (prefs.toggles & AZERTY)
|
||||
to_chat(usr, "<span class='notice'>You are now in AZERTY mode.")
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>You are now in QWERTY mode.")
|
||||
return
|
||||
/client/verb/toggle_ghost_pda()
|
||||
set name = "Show/Hide GhostPDA"
|
||||
set category = "Preferences"
|
||||
set desc = ".Toggle seeing PDA messages as an observer."
|
||||
prefs.toggles ^= CHAT_GHOSTPDA
|
||||
to_chat(src, "As a ghost, you will now [(prefs.toggles & CHAT_GHOSTPDA) ? "see all PDA messages" : "no longer see PDA messages"].")
|
||||
prefs.save_preferences(src)
|
||||
feedback_add_details("admin_verb","TGP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
@@ -64,7 +64,6 @@
|
||||
item_state = "lgloves"
|
||||
flags = NODROP
|
||||
|
||||
|
||||
/obj/item/clothing/gloves/color/yellow/stun
|
||||
name = "stun gloves"
|
||||
desc = "Horrendous and awful. It smells like cancer. The fact it has wires attached to it is incidental."
|
||||
@@ -72,6 +71,9 @@
|
||||
var/stun_strength = 5
|
||||
var/stun_cost = 2000
|
||||
|
||||
/obj/item/clothing/gloves/color/yellow/stun/get_cell()
|
||||
return cell
|
||||
|
||||
/obj/item/clothing/gloves/color/yellow/stun/New()
|
||||
..()
|
||||
update_icon()
|
||||
|
||||
@@ -110,12 +110,23 @@
|
||||
/obj/item/clothing/mask/muzzle/safety
|
||||
name = "safety muzzle"
|
||||
desc = "A muzzle designed to prevent biting."
|
||||
resist_time = 600
|
||||
icon_state = "muzzle_secure"
|
||||
item_state = "muzzle_secure"
|
||||
resist_time = 0
|
||||
mute = MUZZLE_MUTE_NONE
|
||||
security_lock = TRUE
|
||||
locked = FALSE
|
||||
materials = list(MAT_METAL=500, MAT_GLASS=50)
|
||||
|
||||
sprite_sheets = list(
|
||||
"Vox" = 'icons/mob/species/vox/mask.dmi',
|
||||
"Unathi" = 'icons/mob/species/unathi/mask.dmi',
|
||||
"Tajaran" = 'icons/mob/species/tajaran/mask.dmi',
|
||||
"Vulpkanin" = 'icons/mob/species/vulpkanin/mask.dmi',
|
||||
"Grey" = 'icons/mob/species/grey/mask.dmi',
|
||||
"Drask" = 'icons/mob/species/drask/mask.dmi'
|
||||
)
|
||||
|
||||
/obj/item/clothing/mask/muzzle/safety/shock
|
||||
name = "shock muzzle"
|
||||
desc = "A muzzle designed to prevent biting. This one is fitted with a behavior correction system."
|
||||
|
||||
@@ -97,6 +97,9 @@
|
||||
to_chat(usr, "The maintenance panel is [open ? "open" : "closed"].")
|
||||
to_chat(usr, "Hardsuit systems are [offline ? "<font color='red'>offline</font>" : "<font color='green'>online</font>"].")
|
||||
|
||||
/obj/item/rig/get_cell()
|
||||
return cell
|
||||
|
||||
/obj/item/rig/New()
|
||||
..()
|
||||
|
||||
|
||||
@@ -857,3 +857,36 @@
|
||||
icon_state = "burial"
|
||||
item_state = "burial"
|
||||
item_color = "burial"
|
||||
|
||||
/obj/item/clothing/under/redhawaiianshirt
|
||||
name = "red hawaiian shirt"
|
||||
desc = "a floral shirt worn to most vacation destinations."
|
||||
icon_state = "hawaiianred"
|
||||
item_state = "hawaiianred"
|
||||
item_color = "hawaiianred"
|
||||
flags_size = ONESIZEFITSALL
|
||||
|
||||
/obj/item/clothing/under/pinkhawaiianshirt
|
||||
name = "pink hawaiian shirt"
|
||||
desc = "a pink floral shirt the material feels cool and comfy."
|
||||
icon_state = "hawaiianpink"
|
||||
item_state = "hawaiianpink"
|
||||
item_color = "hawaiianpink"
|
||||
flags_size = ONESIZEFITSALL
|
||||
|
||||
/obj/item/clothing/under/orangehawaiianshirt
|
||||
name = "orange hawaiian shirt"
|
||||
desc = "a orange floral shirt for a relaxing day in space."
|
||||
icon_state = "hawaiianorange"
|
||||
item_state = "hawaiianorange"
|
||||
item_color = "hawaiianorange"
|
||||
flags_size = ONESIZEFITSALL
|
||||
|
||||
/obj/item/clothing/under/bluehawaiianshirt
|
||||
name = "blue hawaiian shirt"
|
||||
desc = "a blue floral shirt it has a oddly colored pink flower on it."
|
||||
icon_state = "hawaiianblue"
|
||||
item_state = "hawaiianblue"
|
||||
item_color = "hawaiianblue"
|
||||
flags_size = ONESIZEFITSALL
|
||||
|
||||
|
||||
@@ -463,6 +463,14 @@
|
||||
/obj/item/stack/sheet/animalhide/ashdrake = 5)
|
||||
category = CAT_PRIMAL
|
||||
|
||||
/datum/crafting_recipe/tribal_splint
|
||||
name = "Tribal Splint"
|
||||
time = 20
|
||||
reqs = list(/obj/item/stack/sheet/bone = 2,
|
||||
/obj/item/stack/sheet/sinew = 1)
|
||||
result = /obj/item/stack/medical/splint/tribal
|
||||
category = CAT_PRIMAL
|
||||
|
||||
/datum/crafting_recipe/guillotine
|
||||
name = "Guillotine"
|
||||
result = /obj/structure/guillotine
|
||||
|
||||
@@ -7,21 +7,27 @@
|
||||
|
||||
/datum/event/blob/start()
|
||||
processing = FALSE //so it won't fire again in next tick
|
||||
|
||||
var/turf/T = pick(blobstart)
|
||||
if(!T)
|
||||
return kill()
|
||||
|
||||
var/list/candidates = pollCandidates("Do you want to play as a blob infested mouse?", ROLE_BLOB, 1)
|
||||
if(!candidates.len)
|
||||
return kill()
|
||||
|
||||
var/list/vents = list()
|
||||
for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in GLOB.all_vent_pumps)
|
||||
if(is_station_level(temp_vent.loc.z) && !temp_vent.welded)
|
||||
if(temp_vent.parent.other_atmosmch.len > 50)
|
||||
vents += temp_vent
|
||||
|
||||
var/obj/vent = pick(vents)
|
||||
var/mob/living/simple_animal/mouse/blobinfected/B = new(vent.loc)
|
||||
var/mob/M = pick(candidates)
|
||||
B.key = M.key
|
||||
SSticker.mode.update_blob_icons_added(B.mind)
|
||||
|
||||
to_chat(B, "<span class='userdanger'>You are now a mouse, infected with blob spores. Find somewhere isolated... before you burst and become the blob! Use ventcrawl (alt-click on vents) to move around.</span>")
|
||||
notify_ghosts("Infected Mouse has appeared in [get_area(B)].", source = B)
|
||||
processing = TRUE // Let it naturally end, if it runs successfully
|
||||
@@ -1,7 +1,7 @@
|
||||
/datum/event/disease_outbreak
|
||||
announceWhen = 15
|
||||
|
||||
var/virus_type
|
||||
var/datum/disease/advance/virus_type
|
||||
|
||||
/datum/event/disease_outbreak/setup()
|
||||
announceWhen = rand(15, 30)
|
||||
@@ -10,9 +10,13 @@
|
||||
event_announcement.Announce("Confirmed outbreak of level 7 major viral biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", new_sound = 'sound/AI/outbreak7.ogg')
|
||||
|
||||
/datum/event/disease_outbreak/start()
|
||||
if(!virus_type)
|
||||
if(prob(25))
|
||||
virus_type = pick(/datum/disease/advance/flu, /datum/disease/advance/cold, /datum/disease/brainrot, /datum/disease/magnitis, /datum/disease/beesease, /datum/disease/anxiety, /datum/disease/fake_gbs, /datum/disease/fluspanish, /datum/disease/pierrot_throat, /datum/disease/lycan)
|
||||
|
||||
else
|
||||
virus_type = new /datum/disease/advance
|
||||
virus_type.name = capitalize(pick(GLOB.adjectives)) + " " + capitalize(pick(GLOB.nouns,GLOB.verbs)) // random silly name
|
||||
virus_type.GenerateSymptoms(1,9,6)
|
||||
virus_type.AssignProperties(list("resistance" = rand(0,11), "stealth" = rand(0,2), "stage_rate" = rand(0,5), "transmittable" = rand(0,5), "severity" = rand(0,10)))
|
||||
for(var/mob/living/carbon/human/H in shuffle(GLOB.living_mob_list))
|
||||
if(issmall(H)) //don't infect monkies; that's a waste
|
||||
continue
|
||||
@@ -32,8 +36,8 @@
|
||||
if(H.stat == DEAD || foundAlready)
|
||||
continue
|
||||
|
||||
var/datum/disease/D
|
||||
D = new virus_type()
|
||||
var/datum/disease/advance/D
|
||||
D = virus_type
|
||||
D.carrier = TRUE
|
||||
H.AddDisease(D)
|
||||
break
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/datum/event/sentience
|
||||
|
||||
/datum/event/sentience/start()
|
||||
processing = FALSE //so it won't fire again in next tick
|
||||
|
||||
var/ghostmsg = "Do you want to awaken as a sentient being?"
|
||||
var/list/candidates = pollCandidates(ghostmsg, ROLE_SENTIENT, 1)
|
||||
var/list/potential = list()
|
||||
@@ -41,6 +43,7 @@
|
||||
SA.del_on_death = FALSE
|
||||
greet_sentient(SA)
|
||||
print_command_report(sentience_report, "[command_name()] Update")
|
||||
processing = TRUE // Let it naturally end, if it runs successfully
|
||||
|
||||
/datum/event/sentience/proc/greet_sentient(var/mob/living/carbon/human/M)
|
||||
to_chat(M, "<span class='userdanger'>Hello world!</span>")
|
||||
|
||||
@@ -514,7 +514,7 @@
|
||||
/obj/structure/spacevine/obj_destruction()
|
||||
wither()
|
||||
|
||||
/obj/structure/spacevine/Crossed(mob/crosser)
|
||||
/obj/structure/spacevine/Crossed(mob/crosser, oldloc)
|
||||
if(isliving(crosser))
|
||||
for(var/datum/spacevine_mutation/SM in mutations)
|
||||
SM.on_cross(src, crosser)
|
||||
|
||||
@@ -41,14 +41,14 @@
|
||||
icon_state = "anom"
|
||||
failchance = 0
|
||||
|
||||
/obj/effect/portal/wormhole/can_teleport(atom/movable/M)
|
||||
. = ..()
|
||||
|
||||
if(istype(M, /obj/singularity))
|
||||
. = FALSE
|
||||
|
||||
/obj/effect/portal/wormhole/teleport(atom/movable/M)
|
||||
if(!istype(M))
|
||||
return FALSE
|
||||
|
||||
if(!M.simulated || iseffect(M))
|
||||
return FALSE
|
||||
|
||||
if(M.anchored && ismecha(M))
|
||||
if(!can_teleport(M))
|
||||
return FALSE
|
||||
|
||||
var/turf/target
|
||||
|
||||
@@ -589,7 +589,7 @@ Gunshots/explosions/opening doors/less rare audio (done)
|
||||
health -= P.force
|
||||
return
|
||||
|
||||
/obj/effect/fake_attacker/Crossed(mob/M, somenumber)
|
||||
/obj/effect/fake_attacker/Crossed(mob/M, oldloc)
|
||||
if(M == my_target)
|
||||
step_away(src,my_target,2)
|
||||
if(prob(30))
|
||||
|
||||
@@ -256,6 +256,7 @@
|
||||
desc = "Full of vitamins and deliciousness!"
|
||||
icon_state = "orangejuice"
|
||||
item_state = "carton"
|
||||
throwforce = 0
|
||||
isGlass = 0
|
||||
list_reagents = list("orangejuice" = 100)
|
||||
|
||||
@@ -264,6 +265,7 @@
|
||||
desc = "It's cream. Made from milk. What else did you think you'd find in there?"
|
||||
icon_state = "cream"
|
||||
item_state = "carton"
|
||||
throwforce = 0
|
||||
isGlass = 0
|
||||
list_reagents = list("cream" = 100)
|
||||
|
||||
@@ -272,6 +274,7 @@
|
||||
desc = "Well, at least it LOOKS like tomato juice. You can't tell with all that redness."
|
||||
icon_state = "tomatojuice"
|
||||
item_state = "carton"
|
||||
throwforce = 0
|
||||
isGlass = 0
|
||||
list_reagents = list("tomatojuice" = 100)
|
||||
|
||||
@@ -280,6 +283,7 @@
|
||||
desc = "Sweet-sour goodness."
|
||||
icon_state = "limejuice"
|
||||
item_state = "carton"
|
||||
throwforce = 0
|
||||
isGlass = 0
|
||||
list_reagents = list("limejuice" = 100)
|
||||
|
||||
@@ -288,6 +292,7 @@
|
||||
desc = "Soothing milk."
|
||||
icon_state = "milk"
|
||||
item_state = "carton"
|
||||
throwforce = 0
|
||||
isGlass = 0
|
||||
list_reagents = list("milk" = 100)
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
// Virology Medical Smartfridge
|
||||
// ----------------------------
|
||||
/obj/machinery/smartfridge/secure/chemistry/virology
|
||||
name = "smart virus storage"
|
||||
name = "Smart Virus Storage"
|
||||
desc = "A refrigerated storage unit for volatile sample storage."
|
||||
req_access_txt = "39"
|
||||
spawn_meds = list(/obj/item/reagent_containers/syringe/antiviral = 4,
|
||||
@@ -386,7 +386,8 @@
|
||||
return data
|
||||
|
||||
/obj/machinery/smartfridge/Topic(href, href_list)
|
||||
if(..()) return 0
|
||||
if(..())
|
||||
return FALSE
|
||||
|
||||
var/mob/user = usr
|
||||
var/datum/nanoui/ui = SSnanoui.get_open_ui(user, src, "main")
|
||||
@@ -396,7 +397,7 @@
|
||||
if(href_list["close"])
|
||||
user.unset_machine()
|
||||
ui.close()
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if(href_list["vend"])
|
||||
var/index = text2num(href_list["vend"])
|
||||
@@ -409,17 +410,26 @@
|
||||
item_quants[K] = max(count - amount, 0)
|
||||
|
||||
var/i = amount
|
||||
for(var/obj/O in contents)
|
||||
if(O.name == K)
|
||||
O.forceMove(loc)
|
||||
adjust_item_drop_location(O)
|
||||
update_icon()
|
||||
i--
|
||||
if(i <= 0)
|
||||
return 1
|
||||
|
||||
return 1
|
||||
return 0
|
||||
if(i == 1 && Adjacent(user) && !issilicon(user))
|
||||
for(var/obj/O in contents)
|
||||
if(O.name == K)
|
||||
if(!user.put_in_hands(O))
|
||||
O.forceMove(loc)
|
||||
adjust_item_drop_location(O)
|
||||
update_icon()
|
||||
break
|
||||
return TRUE
|
||||
else
|
||||
for(var/obj/O in contents)
|
||||
if(O.name == K)
|
||||
O.forceMove(loc)
|
||||
adjust_item_drop_location(O)
|
||||
update_icon()
|
||||
i--
|
||||
if(i <= 0)
|
||||
return TRUE
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/smartfridge/proc/throw_item()
|
||||
var/obj/throw_item = null
|
||||
|
||||
@@ -319,6 +319,8 @@
|
||||
|
||||
else if(href_list["create"])
|
||||
var/amount = (text2num(href_list["amount"]))
|
||||
//Can't be outside these (if you change this keep a sane limit)
|
||||
amount = Clamp(amount, 1, 10)
|
||||
var/datum/design/D = locate(href_list["create"])
|
||||
create_product(D, amount)
|
||||
updateUsrDialog()
|
||||
|
||||
@@ -151,7 +151,7 @@
|
||||
T.on_consume(src, usr)
|
||||
..()
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/grown/Crossed(atom/movable/AM)
|
||||
/obj/item/reagent_containers/food/snacks/grown/Crossed(atom/movable/AM, oldloc)
|
||||
if(seed)
|
||||
for(var/datum/plant_gene/trait/T in seed.genes)
|
||||
T.on_cross(src, AM)
|
||||
|
||||
@@ -160,7 +160,7 @@
|
||||
..()
|
||||
StartBurning()
|
||||
|
||||
/obj/structure/bonfire/Crossed(atom/movable/AM)
|
||||
/obj/structure/bonfire/Crossed(atom/movable/AM, oldloc)
|
||||
if(burning)
|
||||
Burn()
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
return 0
|
||||
|
||||
|
||||
/obj/item/grown/Crossed(atom/movable/AM)
|
||||
/obj/item/grown/Crossed(atom/movable/AM, oldloc)
|
||||
if(seed)
|
||||
for(var/datum/plant_gene/trait/T in seed.genes)
|
||||
T.on_cross(src, AM)
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/datum/admins/key_down(_key, client/user)
|
||||
switch(_key)
|
||||
if("F5")
|
||||
user.get_admin_say()
|
||||
return
|
||||
if("F6")
|
||||
user.admin_ghost()
|
||||
return
|
||||
if("F7")
|
||||
player_panel_new()
|
||||
return
|
||||
if("F8")
|
||||
user.cmd_admin_pm_panel()
|
||||
return
|
||||
if("F9")
|
||||
user.stealth()
|
||||
return
|
||||
if("F10")
|
||||
user.get_dead_say()
|
||||
return
|
||||
..()
|
||||
@@ -0,0 +1,21 @@
|
||||
// You might be wondering why this isn't client level. If focus is null, we don't want you to move.
|
||||
// Only way to do that is to tie the behavior into the focus's keyLoop().
|
||||
|
||||
/atom/movable/keyLoop(client/user)
|
||||
if(!user.keys_held["Ctrl"])
|
||||
var/movement_dir = NONE
|
||||
var/list/movement = SSinput.movement_keys
|
||||
if(user.prefs.toggles & AZERTY)
|
||||
movement = SSinput.alt_movement_keys
|
||||
for(var/_key in user.keys_held)
|
||||
movement_dir = movement_dir | movement[_key]
|
||||
if(user.next_move_dir_add)
|
||||
movement_dir |= user.next_move_dir_add
|
||||
if(user.next_move_dir_sub)
|
||||
movement_dir &= ~user.next_move_dir_sub
|
||||
// Sanity checks in case you hold left and right and up to make sure you only go up
|
||||
if((movement_dir & NORTH) && (movement_dir & SOUTH))
|
||||
movement_dir &= ~(NORTH|SOUTH)
|
||||
if((movement_dir & EAST) && (movement_dir & WEST))
|
||||
movement_dir &= ~(EAST|WEST)
|
||||
user.Move(get_step(src, movement_dir), movement_dir)
|
||||
@@ -0,0 +1,20 @@
|
||||
/mob/living/carbon/key_down(_key, client/user)
|
||||
user.keys_held[_key] = world.time
|
||||
if(!user.keys_held["Shift"])
|
||||
switch(_key)
|
||||
if("R", "Southwest") // Southwest is End
|
||||
toggle_throw_mode()
|
||||
return
|
||||
if("1")
|
||||
a_intent_change("help")
|
||||
return
|
||||
if("2")
|
||||
a_intent_change("disarm")
|
||||
return
|
||||
if("3")
|
||||
a_intent_change("grab")
|
||||
return
|
||||
if("4")
|
||||
a_intent_change("harm")
|
||||
return
|
||||
return ..()
|
||||
@@ -0,0 +1,59 @@
|
||||
// Clients aren't datums so we have to define these procs indpendently.
|
||||
// These verbs are called for all key press and release events
|
||||
/client/verb/keyDown(_key as text)
|
||||
set instant = TRUE
|
||||
set hidden = TRUE
|
||||
keys_held[_key] = world.time
|
||||
var/movement = SSinput.movement_keys[_key]
|
||||
if (prefs.toggles & AZERTY) movement = SSinput.alt_movement_keys[_key]
|
||||
if(!(next_move_dir_sub & movement) && !keys_held["Ctrl"])
|
||||
next_move_dir_add |= movement
|
||||
|
||||
// Client-level keybindings are ones anyone should be able to do at any time
|
||||
// Things like taking screenshots, hitting tab, and adminhelps.
|
||||
|
||||
switch(_key)
|
||||
if("F1")
|
||||
if(keys_held["Ctrl"] && keys_held["Shift"]) // Is this command ever used?
|
||||
winset(src, null, "command=.options")
|
||||
else
|
||||
adminhelp()
|
||||
return
|
||||
if("F2") // Screenshot. Hold shift to choose a name and location to save in
|
||||
ooc()
|
||||
return
|
||||
if("F3")
|
||||
mob.say_wrapper()
|
||||
return
|
||||
if("F4")
|
||||
mob.me_wrapper()
|
||||
return
|
||||
if("F12") // Toggles minimal HUD
|
||||
mob.button_pressed_F12()
|
||||
return
|
||||
|
||||
if(holder)
|
||||
holder.key_down(_key, src)
|
||||
if(mob.focus)
|
||||
mob.focus.key_down(_key, src)
|
||||
|
||||
/client/verb/keyUp(_key as text)
|
||||
set instant = TRUE
|
||||
set hidden = TRUE
|
||||
keys_held -= _key
|
||||
var/movement = SSinput.movement_keys[_key]
|
||||
if (prefs.toggles & AZERTY) movement = SSinput.alt_movement_keys[_key]
|
||||
if(!(next_move_dir_add & movement))
|
||||
next_move_dir_sub |= movement
|
||||
|
||||
if(holder)
|
||||
holder.key_up(_key, src)
|
||||
if(mob.focus)
|
||||
mob.focus.key_up(_key, src)
|
||||
|
||||
// Called every game tick
|
||||
/client/keyLoop()
|
||||
if(holder)
|
||||
holder.keyLoop(src)
|
||||
if(mob.focus)
|
||||
mob.focus.keyLoop(src)
|
||||
@@ -0,0 +1,80 @@
|
||||
/mob/living/carbon/human/key_down(_key, client/user)
|
||||
if(_key == "H")
|
||||
var/obj/item/clothing/accessory/holster/H = null
|
||||
if(istype(w_uniform, /obj/item/clothing/under))
|
||||
var/obj/item/clothing/under/S = w_uniform
|
||||
if(S.accessories.len)
|
||||
H = locate() in S.accessories
|
||||
if (!H)
|
||||
return
|
||||
if(!H.holstered)
|
||||
if(!istype(get_active_hand(), /obj/item/gun))
|
||||
to_chat(usr, "<span class='warning'>You need your gun equiped to holster it.</span>")
|
||||
return
|
||||
var/obj/item/gun/W = get_active_hand()
|
||||
H.holster(W, usr)
|
||||
else
|
||||
H.unholster(usr)
|
||||
if(client.keys_held["Shift"])
|
||||
switch(_key)
|
||||
if("E") // Put held thing in belt or take out most recent thing from belt
|
||||
quick_equip() // Implementing the storage component is going to take way too long
|
||||
// var/obj/item/thing = get_active_hand()
|
||||
// var/obj/item/equipped_belt = get_item_by_slot(slot_belt)
|
||||
// if(!equipped_belt) // We also let you equip a belt like this
|
||||
// if(!thing)
|
||||
// to_chat(user, "<span class='notice'>You have no belt to take something out of.</span>")
|
||||
// return
|
||||
// if(equip_to_slot_if_possible(thing, slot_belt))
|
||||
// update_inv_r_hand()
|
||||
// update_inv_l_hand()
|
||||
// return
|
||||
// if(!SEND_SIGNAL(equipped_belt, COMSIG_CONTAINS_STORAGE)) // not a storage item
|
||||
// if(!thing)
|
||||
// equipped_belt.attack_hand(src)
|
||||
// else
|
||||
// to_chat(user, "<span class='notice'>You can't fit anything in.</span>")
|
||||
// return
|
||||
// if(thing) // put thing in belt
|
||||
// if(!SEND_SIGNAL(equipped_belt, COMSIG_TRY_STORAGE_INSERT, thing, user.mob))
|
||||
// to_chat(user, "<span class='notice'>You can't fit anything in.</span>")
|
||||
// return
|
||||
// if(!equipped_belt.contents.len) // nothing to take out
|
||||
// to_chat(user, "<span class='notice'>There's nothing in your belt to take out.</span>")
|
||||
// return
|
||||
// var/obj/item/stored = equipped_belt.contents[equipped_belt.contents.len]
|
||||
// if(!stored || stored.on_found(src))
|
||||
// return
|
||||
// stored.attack_hand(src) // take out thing from belt
|
||||
// return
|
||||
|
||||
/* if("B") // Put held thing in backpack or take out most recent thing from backpack
|
||||
var/obj/item/thing = get_active_hand()
|
||||
var/obj/item/equipped_back = get_item_by_slot(slot_back)
|
||||
if(!equipped_back) // We also let you equip a backpack like this
|
||||
if(!thing)
|
||||
to_chat(user, "<span class='notice'>You have no backpack to take something out of.</span>")
|
||||
return
|
||||
if(equip_to_slot_if_possible(thing, slot_back))
|
||||
update_inv_r_hand()
|
||||
update_inv_l_hand()
|
||||
return
|
||||
if(!SEND_SIGNAL(equipped_back, COMSIG_CONTAINS_STORAGE)) // not a storage item
|
||||
if(!thing)
|
||||
equipped_back.attack_hand(src)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You can't fit anything in.</span>")
|
||||
return
|
||||
if(thing) // put thing in backpack
|
||||
if(!SEND_SIGNAL(equipped_back, COMSIG_TRY_STORAGE_INSERT, thing, user.mob))
|
||||
to_chat(user, "<span class='notice'>You can't fit anything in.</span>")
|
||||
return
|
||||
if(!equipped_back.contents.len) // nothing to take out
|
||||
to_chat(user, "<span class='notice'>There's nothing in your backpack to take out.</span>")
|
||||
return
|
||||
var/obj/item/stored = equipped_back.contents[equipped_back.contents.len]
|
||||
if(!stored || stored.on_found(src))
|
||||
return
|
||||
stored.attack_hand(src) // take out thing from backpack
|
||||
return */
|
||||
return ..()
|
||||
@@ -0,0 +1,7 @@
|
||||
/mob/living/key_down(_key, client/user)
|
||||
switch(_key)
|
||||
if("B")
|
||||
resist()
|
||||
return
|
||||
|
||||
return ..()
|
||||
@@ -0,0 +1,145 @@
|
||||
// Technically the client argument is unncessary here since that SHOULD be src.client but let's not assume things
|
||||
// All it takes is one badmin setting their focus to someone else's client to mess things up
|
||||
// Or we can have NPC's send actual keypresses and detect that by seeing no client
|
||||
|
||||
/mob/key_down(_key, client/user)
|
||||
if(user.prefs.toggles & AZERTY)
|
||||
switch(_key)
|
||||
if("Delete")
|
||||
if(!pulling)
|
||||
to_chat(src, "<span class='notice'>You are not pulling anything.</span>")
|
||||
else
|
||||
stop_pulling()
|
||||
return
|
||||
if("Insert", "G")
|
||||
a_intent_change(INTENT_HOTKEY_RIGHT)
|
||||
return
|
||||
if("F")
|
||||
a_intent_change(INTENT_HOTKEY_LEFT)
|
||||
return
|
||||
if("X", "Northeast") // Northeast is Page-up
|
||||
swap_hand()
|
||||
return
|
||||
if("Y", "W", "Southeast") // Southeast is Page-down
|
||||
mode() // attack_self(). No idea who came up with "mode()"
|
||||
return
|
||||
if("A", "Northwest") // Northwest is Home
|
||||
var/obj/item/I = get_active_hand()
|
||||
if(!I)
|
||||
to_chat(src, "<span class='warning'>You have nothing to drop in your hand!</span>")
|
||||
else
|
||||
drop_item(I)
|
||||
return
|
||||
if("E")
|
||||
quick_equip()
|
||||
return
|
||||
if("Alt")
|
||||
toggle_move_intent()
|
||||
return
|
||||
else
|
||||
switch(_key)
|
||||
if("Delete")
|
||||
if(!pulling)
|
||||
to_chat(src, "<span class='notice'>You are not pulling anything.</span>")
|
||||
else
|
||||
stop_pulling()
|
||||
return
|
||||
if("Insert", "G")
|
||||
a_intent_change(INTENT_HOTKEY_RIGHT)
|
||||
return
|
||||
if("F")
|
||||
a_intent_change(INTENT_HOTKEY_LEFT)
|
||||
return
|
||||
if("X", "Northeast") // Northeast is Page-up
|
||||
swap_hand()
|
||||
return
|
||||
if("Y", "Z", "Southeast") // Southeast is Page-down
|
||||
mode() // attack_self(). No idea who came up with "mode()"
|
||||
return
|
||||
if("Q", "Northwest") // Northwest is Home
|
||||
var/obj/item/I = get_active_hand()
|
||||
if(!I)
|
||||
to_chat(src, "<span class='warning'>You have nothing to drop in your hand!</span>")
|
||||
else
|
||||
drop_item(I)
|
||||
return
|
||||
if("E")
|
||||
quick_equip()
|
||||
return
|
||||
if("Alt")
|
||||
toggle_move_intent()
|
||||
return
|
||||
//Bodypart selections
|
||||
if(client.prefs.toggles & NUMPAD_TARGET)
|
||||
switch(_key)
|
||||
if("Numpad8")
|
||||
user.body_toggle_head()
|
||||
return
|
||||
if("Numpad4")
|
||||
user.body_r_arm()
|
||||
return
|
||||
if("Numpad5")
|
||||
user.body_chest()
|
||||
return
|
||||
if("Numpad6")
|
||||
user.body_l_arm()
|
||||
return
|
||||
if("Numpad1")
|
||||
user.body_r_leg()
|
||||
return
|
||||
if("Numpad2")
|
||||
user.body_groin()
|
||||
return
|
||||
if("Numpad3")
|
||||
user.body_l_leg()
|
||||
return
|
||||
else
|
||||
switch(_key)
|
||||
if("Numpad1")
|
||||
a_intent_change("help")
|
||||
return
|
||||
if("Numpad2")
|
||||
a_intent_change("disarm")
|
||||
return
|
||||
if("Numpad3")
|
||||
a_intent_change("grab")
|
||||
return
|
||||
if("Numpad4")
|
||||
a_intent_change("harm")
|
||||
return
|
||||
if(client.keys_held["Ctrl"] && client.prefs.toggles & AZERTY)
|
||||
switch(SSinput.alt_movement_keys[_key])
|
||||
if(NORTH)
|
||||
northface()
|
||||
return
|
||||
if(SOUTH)
|
||||
southface()
|
||||
return
|
||||
if(WEST)
|
||||
westface()
|
||||
return
|
||||
if(EAST)
|
||||
eastface()
|
||||
return
|
||||
else if(client.keys_held["Ctrl"])
|
||||
switch(SSinput.movement_keys[_key])
|
||||
if(NORTH)
|
||||
northface()
|
||||
return
|
||||
if(SOUTH)
|
||||
southface()
|
||||
return
|
||||
if(WEST)
|
||||
westface()
|
||||
return
|
||||
if(EAST)
|
||||
eastface()
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/key_up(_key, client/user)
|
||||
switch(_key)
|
||||
if("Alt")
|
||||
toggle_move_intent()
|
||||
return
|
||||
return ..()
|
||||
@@ -0,0 +1,20 @@
|
||||
/mob/living/silicon/robot/key_down(_key, client/user)
|
||||
switch(_key)
|
||||
if("1", "2", "3")
|
||||
toggle_module(text2num(_key))
|
||||
return
|
||||
if("4")
|
||||
a_intent_change(INTENT_HOTKEY_LEFT)
|
||||
return
|
||||
if("X")
|
||||
cycle_modules()
|
||||
return
|
||||
if("Q")
|
||||
if(!(client.prefs.toggles & AZERTY))
|
||||
uneq_active()
|
||||
return
|
||||
if("A")
|
||||
if(client.prefs.toggles & AZERTY)
|
||||
uneq_active()
|
||||
return
|
||||
return ..()
|
||||
@@ -0,0 +1,8 @@
|
||||
/mob
|
||||
var/datum/focus //What receives our keyboard inputs. src by default
|
||||
|
||||
/mob/proc/set_focus(datum/new_focus)
|
||||
if(focus == new_focus)
|
||||
return
|
||||
focus = new_focus
|
||||
reset_perspective(focus) //Maybe this should be done manually? You figure it out, reader
|
||||
@@ -0,0 +1,42 @@
|
||||
# In-code keypress handling system
|
||||
|
||||
This whole system is heavily based off of forum_account's keyboard library.
|
||||
Thanks to forum_account for saving the day, the library can be found
|
||||
[here](https://secure.byond.com/developer/Forum_account/Keyboard)!
|
||||
|
||||
.dmf macros have some very serious shortcomings. For example, they do not allow reusing parts
|
||||
of one macro in another, so giving cyborgs their own shortcuts to swap active module couldn't
|
||||
inherit the movement that all mobs should have anyways. The webclient only supports one macro,
|
||||
so having more than one was problematic. Additionally each keybind has to call an actual
|
||||
verb, which meant a lot of hidden verbs that just call one other proc. Also our existing
|
||||
macro was really bad and tied unrelated behavior into `Northeast()`, `Southeast()`, `Northwest()`,
|
||||
and `Southwest()`.
|
||||
|
||||
The basic premise of this system is to not screw with .dmf macro setup at all and handle
|
||||
pressing those keys in the code instead. We have every key call `client.keyDown()`
|
||||
or `client.keyUp()` with the pressed key as an argument. Certain keys get processed
|
||||
directly by the client because they should be doable at any time, then we call
|
||||
`keyDown()` or `keyUp()` on the client's holder and the client's mob's focus.
|
||||
By default `mob.focus` is the mob itself, but you can set it to any datum to give control of a
|
||||
client's keypresses to another object. This would be a good way to handle a menu or driving
|
||||
a mech. You can also set it to null to disregard input from a certain user.
|
||||
|
||||
Movement is handled by having each client call `client.keyLoop()` every game tick.
|
||||
As above, this calls holder and `focus.keyLoop()`. `atom/movable/keyLoop()` handles movement
|
||||
Try to keep the calculations in this proc light. It runs every tick for every client after all!
|
||||
|
||||
You can also tell which keys are being held down now. Each client a list of keys pressed called
|
||||
`keys_held`. Each entry is a key as a text string associated with the world.time when it was
|
||||
pressed.
|
||||
|
||||
No client-set keybindings at this time, but it shouldn't be too hard if someone wants.
|
||||
|
||||
Notes about certain keys:
|
||||
|
||||
* `Tab` has client-sided behavior but acts normally
|
||||
* `T`, `O`, and `M` move focus to the input when pressed. This fires the keyUp macro right away.
|
||||
* `\` needs to be escaped in the dmf so any usage is `\\`
|
||||
|
||||
You cannot `TICK_CHECK` or check `world.tick_usage` inside of procs called by key down and up
|
||||
events. They happen outside of a byond tick and have no meaning there. Key looping
|
||||
works correctly since it's part of a subsystem, not direct input.
|
||||
@@ -0,0 +1,46 @@
|
||||
/client
|
||||
var/list/keys_held = list() // A list of any keys held currently
|
||||
// These next two vars are to apply movement for keypresses and releases made while move delayed.
|
||||
// Because discarding that input makes the game less responsive.
|
||||
var/next_move_dir_add // On next move, add this dir to the move that would otherwise be done
|
||||
var/next_move_dir_sub // On next move, subtract this dir from the move that would otherwise be done
|
||||
|
||||
// Set a client's focus to an object and override these procs on that object to let it handle keypresses
|
||||
|
||||
/datum/proc/key_down(key, client/user) // Called when a key is pressed down initially
|
||||
return
|
||||
/datum/proc/key_up(key, client/user) // Called when a key is released
|
||||
return
|
||||
/datum/proc/keyLoop(client/user) // Called once every frame
|
||||
set waitfor = FALSE
|
||||
return
|
||||
|
||||
// removes all the existing macros
|
||||
/client/proc/erase_all_macros()
|
||||
var/list/macro_sets = params2list(winget(src, null, "macros"))
|
||||
var/erase_output = ""
|
||||
for(var/i in 1 to macro_sets.len)
|
||||
var/setname = macro_sets[i]
|
||||
var/list/macro_set = params2list(winget(src, "[setname].*", "command")) // The third arg doesnt matter here as we're just removing them all
|
||||
for(var/k in 1 to macro_set.len)
|
||||
var/list/split_name = splittext(macro_set[k], ".")
|
||||
var/macro_name = "[split_name[1]].[split_name[2]]" // [3] is "command"
|
||||
erase_output = "[erase_output];[macro_name].parent=null"
|
||||
winset(src, null, erase_output)
|
||||
|
||||
/client/proc/set_macros()
|
||||
set waitfor = FALSE
|
||||
|
||||
erase_all_macros()
|
||||
|
||||
var/list/macro_sets = SSinput.macro_sets
|
||||
for(var/i in 1 to macro_sets.len)
|
||||
var/setname = macro_sets[i]
|
||||
if(setname != "default")
|
||||
winclone(src, "default", setname)
|
||||
var/list/macro_set = macro_sets[setname]
|
||||
for(var/k in 1 to macro_set.len)
|
||||
var/key = macro_set[k]
|
||||
var/command = macro_set[key]
|
||||
winset(src, "[setname]-\ref[key]", "parent=[setname];name=[key];command=[command]")
|
||||
winset(src, null, "input.focus=true input.background-color=[COLOR_INPUT_ENABLED] mainwindow.macro=old_default")
|
||||
@@ -238,6 +238,9 @@
|
||||
/obj/machinery/smartfridge/survival_pod/accept_check(obj/item/O)
|
||||
return isitem(O)
|
||||
|
||||
/obj/machinery/smartfridge/survival_pod/default_unfasten_wrench()
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/smartfridge/survival_pod/empty
|
||||
name = "dusty survival pod storage"
|
||||
desc = "A heated storage unit. This one's seen better days."
|
||||
|
||||
@@ -905,6 +905,7 @@
|
||||
throw_range = 5
|
||||
var/loaded = 1
|
||||
var/malfunctioning = 0
|
||||
var/revive_type = SENTIENCE_ORGANIC //So you can't revive boss monsters or robots with it
|
||||
|
||||
/obj/item/lazarus_injector/afterattack(atom/target, mob/user, proximity_flag)
|
||||
if(!loaded)
|
||||
@@ -912,6 +913,9 @@
|
||||
if(istype(target, /mob/living) && proximity_flag)
|
||||
if(istype(target, /mob/living/simple_animal))
|
||||
var/mob/living/simple_animal/M = target
|
||||
if(M.sentience_type != revive_type)
|
||||
to_chat(user, "<span class='info'>[src] does not work on this sort of creature.</span>")
|
||||
return
|
||||
if(M.stat == DEAD)
|
||||
M.faction = list("neutral")
|
||||
M.revive()
|
||||
|
||||
@@ -1,43 +1,44 @@
|
||||
/****************Explorer's Suit and Mask****************/
|
||||
/obj/item/clothing/suit/hooded/explorer
|
||||
name = "explorer suit"
|
||||
desc = "An armoured suit for exploring harsh environments."
|
||||
icon_state = "explorer"
|
||||
item_state = "explorer"
|
||||
body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
|
||||
min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT
|
||||
cold_protection = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
|
||||
max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT
|
||||
heat_protection = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
|
||||
hoodtype = /obj/item/clothing/head/hooded/explorer
|
||||
armor = list("melee" = 30, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 50, "bio" = 100, "rad" = 50, "fire" = 50, "acid" = 50)
|
||||
allowed = list(/obj/item/flashlight, /obj/item/tank, /obj/item/resonator, /obj/item/mining_scanner, /obj/item/t_scanner/adv_mining_scanner, /obj/item/gun/energy/kinetic_accelerator, /obj/item/pickaxe)
|
||||
resistance_flags = FIRE_PROOF
|
||||
|
||||
sprite_sheets = list(
|
||||
"Vox" = 'icons/mob/species/vox/suit.dmi',
|
||||
"Drask" = 'icons/mob/species/drask/suit.dmi',
|
||||
"Tajaran" = 'icons/mob/species/tajaran/suit.dmi',
|
||||
"Unathi" = 'icons/mob/species/unathi/suit.dmi',
|
||||
"Vulpkanin" = 'icons/mob/species/vulpkanin/suit.dmi'
|
||||
)
|
||||
|
||||
/obj/item/clothing/head/hooded/explorer
|
||||
name = "explorer hood"
|
||||
desc = "An armoured hood for exploring harsh environments."
|
||||
icon_state = "explorer"
|
||||
item_state = "explorer"
|
||||
body_parts_covered = HEAD
|
||||
flags = BLOCKHAIR | NODROP
|
||||
flags_cover = HEADCOVERSEYES
|
||||
min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT
|
||||
max_heat_protection_temperature = FIRE_HELM_MAX_TEMP_PROTECT
|
||||
armor = list("melee" = 30, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 50, "bio" = 100, "rad" = 50, "fire" = 50, "acid" = 50)
|
||||
resistance_flags = FIRE_PROOF
|
||||
|
||||
sprite_sheets = list(
|
||||
"Vox" = 'icons/mob/species/vox/head.dmi',
|
||||
"Drask" = 'icons/mob/species/drask/head.dmi',
|
||||
"Grey" = 'icons/mob/species/grey/head.dmi',
|
||||
"Skrell" = 'icons/mob/species/skrell/head.dmi'
|
||||
/****************Explorer's Suit and Mask****************/
|
||||
/obj/item/clothing/suit/hooded/explorer
|
||||
name = "explorer suit"
|
||||
desc = "An armoured suit for exploring harsh environments."
|
||||
icon_state = "explorer"
|
||||
item_state = "explorer"
|
||||
body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
|
||||
min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT
|
||||
cold_protection = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
|
||||
max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT
|
||||
heat_protection = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
|
||||
hoodtype = /obj/item/clothing/head/hooded/explorer
|
||||
armor = list("melee" = 30, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 50, "bio" = 100, "rad" = 50, "fire" = 50, "acid" = 50)
|
||||
allowed = list(/obj/item/flashlight, /obj/item/tank, /obj/item/resonator, /obj/item/mining_scanner, /obj/item/t_scanner/adv_mining_scanner, /obj/item/gun/energy/kinetic_accelerator, /obj/item/pickaxe)
|
||||
resistance_flags = FIRE_PROOF
|
||||
hide_tail_by_species = list("Vox" , "Vulpkanin" , "Unathi" , "Tajaran")
|
||||
|
||||
sprite_sheets = list(
|
||||
"Vox" = 'icons/mob/species/vox/suit.dmi',
|
||||
"Drask" = 'icons/mob/species/drask/suit.dmi',
|
||||
"Tajaran" = 'icons/mob/species/tajaran/suit.dmi',
|
||||
"Unathi" = 'icons/mob/species/unathi/suit.dmi',
|
||||
"Vulpkanin" = 'icons/mob/species/vulpkanin/suit.dmi'
|
||||
)
|
||||
|
||||
/obj/item/clothing/head/hooded/explorer
|
||||
name = "explorer hood"
|
||||
desc = "An armoured hood for exploring harsh environments."
|
||||
icon_state = "explorer"
|
||||
item_state = "explorer"
|
||||
body_parts_covered = HEAD
|
||||
flags = BLOCKHAIR | NODROP
|
||||
flags_cover = HEADCOVERSEYES
|
||||
min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT
|
||||
max_heat_protection_temperature = FIRE_HELM_MAX_TEMP_PROTECT
|
||||
armor = list("melee" = 30, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 50, "bio" = 100, "rad" = 50, "fire" = 50, "acid" = 50)
|
||||
resistance_flags = FIRE_PROOF
|
||||
|
||||
sprite_sheets = list(
|
||||
"Vox" = 'icons/mob/species/vox/head.dmi',
|
||||
"Drask" = 'icons/mob/species/drask/head.dmi',
|
||||
"Grey" = 'icons/mob/species/grey/head.dmi',
|
||||
"Skrell" = 'icons/mob/species/skrell/head.dmi'
|
||||
)
|
||||
@@ -1,3 +1,5 @@
|
||||
GLOBAL_LIST(labor_sheet_values)
|
||||
|
||||
/**********************Prisoners' Console**************************/
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console
|
||||
@@ -5,153 +7,153 @@
|
||||
desc = "A stacking console with an electromagnetic writer, used to track ore mined by prisoners."
|
||||
icon = 'icons/obj/machines/mining_machines.dmi'
|
||||
icon_state = "console"
|
||||
density = 0
|
||||
anchored = 1
|
||||
var/obj/machinery/mineral/stacking_machine/laborstacker/machine = null
|
||||
density = FALSE
|
||||
var/obj/machinery/mineral/stacking_machine/laborstacker/stacking_machine = null
|
||||
var/machinedir = SOUTH
|
||||
var/obj/item/card/id/prisoner/inserted_id
|
||||
var/obj/machinery/door/airlock/release_door
|
||||
var/door_tag = "prisonshuttle"
|
||||
var/use_release_door = 0
|
||||
var/obj/item/radio/intercom/announcer
|
||||
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/New()
|
||||
..()
|
||||
/obj/machinery/mineral/labor_claim_console/Initialize()
|
||||
. = ..()
|
||||
announcer = new /obj/item/radio/intercom(null)
|
||||
announcer.config(list("Security" = 0))
|
||||
locate_stacking_machine()
|
||||
|
||||
spawn(7)
|
||||
src.machine = locate(/obj/machinery/mineral/stacking_machine, get_step(src, machinedir))
|
||||
var/t
|
||||
for(var/obj/machinery/door/airlock/d in range(5,src))
|
||||
t = d.id_tag
|
||||
if(t == src.door_tag)
|
||||
src.release_door = d
|
||||
if(machine && (release_door || !use_release_door))
|
||||
machine.CONSOLE = src
|
||||
if(!GLOB.labor_sheet_values)
|
||||
var/sheet_list = list()
|
||||
for(var/sheet_type in subtypesof(/obj/item/stack/sheet))
|
||||
var/obj/item/stack/sheet/sheet = sheet_type
|
||||
if(!initial(sheet.point_value) || (initial(sheet.merge_type) && initial(sheet.merge_type) != sheet_type)) //ignore no-value sheets and x/fifty subtypes
|
||||
continue
|
||||
sheet_list += list(list("ore" = initial(sheet.name), "value" = initial(sheet.point_value)))
|
||||
GLOB.labor_sheet_values = sheet_list
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/Destroy()
|
||||
. = ..()
|
||||
QDEL_NULL(announcer)
|
||||
|
||||
/proc/cmp_sheet_list(list/a, list/b)
|
||||
return a["value"] - b["value"]
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/card/id/prisoner))
|
||||
if(!inserted_id)
|
||||
if(!user.unEquip(I))
|
||||
return
|
||||
I.forceMove(src)
|
||||
inserted_id = I
|
||||
to_chat(user, "<span class='notice'>You insert [I].</span>")
|
||||
SSnanoui.update_uis(src)
|
||||
return
|
||||
else
|
||||
qdel(src)
|
||||
to_chat(user, "<span class='notice'>There's an ID inserted already.</span>")
|
||||
return ..()
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/attack_hand(mob/user)
|
||||
ui_interact(user)
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/attack_ghost(mob/user)
|
||||
attack_hand(user)
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = default_state)
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "labor_claim_console.tmpl", name, 450, 625, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
var/can_go_home = FALSE
|
||||
|
||||
data["emagged"] = (emagged) ? TRUE : FALSE
|
||||
if(inserted_id)
|
||||
data["id"] = inserted_id
|
||||
data["id_name"] = inserted_id.registered_name
|
||||
data["points"] = inserted_id.points
|
||||
data["goal"] = inserted_id.goal
|
||||
if(check_auth())
|
||||
can_go_home = TRUE
|
||||
|
||||
if(stacking_machine)
|
||||
data["unclaimed_points"] = stacking_machine.points
|
||||
|
||||
data["ores"] = GLOB.labor_sheet_values
|
||||
data["can_go_home"] = can_go_home
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/Topic(href, href_list)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
if(href_list["handle_id"])
|
||||
if(inserted_id)
|
||||
if(!usr.put_in_hands(inserted_id))
|
||||
inserted_id.forceMove(get_turf(src))
|
||||
inserted_id = null
|
||||
else
|
||||
var/obj/item/I = usr.get_active_hand()
|
||||
if(istype(I, /obj/item/card/id/prisoner))
|
||||
if(!usr.unEquip(I))
|
||||
return
|
||||
I.forceMove(src)
|
||||
inserted_id = I
|
||||
if(href_list["claim_points"])
|
||||
inserted_id.points += stacking_machine.points
|
||||
stacking_machine.points = 0
|
||||
to_chat(usr, "Points transferred.")
|
||||
if(href_list["move_shuttle"])
|
||||
if(!alone_in_area(get_area(src), usr))
|
||||
to_chat(usr, "<span class='warning'>Prisoners are only allowed to be released while alone.</span>")
|
||||
else
|
||||
switch(SSshuttle.moveShuttle("laborcamp", "laborcamp_home", TRUE))
|
||||
if(1)
|
||||
to_chat(usr, "<span class='notice'>Shuttle not found.</span>")
|
||||
if(2)
|
||||
to_chat(usr, "<span class='notice'>Shuttle already at station.</span>")
|
||||
if(3)
|
||||
to_chat(usr, "<span class='notice'>No permission to dock could be granted.</span>")
|
||||
else
|
||||
if(!(emagged))
|
||||
var/message = "[inserted_id.registered_name] has returned to the station. Minerals and Prisoner ID card ready for retrieval."
|
||||
announcer.autosay(message, "Labor Camp Controller", "Security")
|
||||
to_chat(usr, "<span class='notice'>Shuttle received message and will be sent shortly.</span>")
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/proc/check_auth()
|
||||
if(emagged) return 1 //Shuttle is emagged, let any ol' person through
|
||||
if(emagged)
|
||||
return TRUE //Shuttle is emagged, let any ol' person through
|
||||
return (istype(inserted_id) && inserted_id.points >= inserted_id.goal) //Otherwise, only let them out if the prisoner's reached his quota.
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/proc/locate_stacking_machine()
|
||||
stacking_machine = locate(/obj/machinery/mineral/stacking_machine, get_step(src, machinedir))
|
||||
if(stacking_machine)
|
||||
stacking_machine.CONSOLE = src
|
||||
else
|
||||
qdel(src)
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/attack_hand(user as mob)
|
||||
var/dat
|
||||
dat += text("<b>Point Claim Console</b><br><br>")
|
||||
if(emagged) //Shit's broken
|
||||
dat += text("<b>QU&#t0A In%aL*D</b><br>")
|
||||
else if(istype(inserted_id)) //There's an ID in there.
|
||||
dat += text("ID: [inserted_id.registered_name] <A href='?src=[UID()];choice=eject'>Eject ID.</A><br>")
|
||||
dat += text("Points Collected:[inserted_id.points]<br>")
|
||||
dat += text("Point Quota: [inserted_id.goal] - Reach your quota to earn your release<br>")
|
||||
dat += text("Unclaimed Collection Points: [machine.points]. <A href='?src=[UID()];choice=claim'>Claim points.</A><br>")
|
||||
else //No ID in sight. Complain about it.
|
||||
dat += text("No ID inserted. <A href='?src=[UID()];choice=insert'>Insert ID.</A><br>")
|
||||
if(check_auth())
|
||||
dat += text("<A href='?src=[UID()];choice=station'>Proceed to station.</A><br>")
|
||||
if(use_release_door)
|
||||
dat += text("<A href='?src=[UID()];choice=release'>Open release door.</A><br>")
|
||||
if(machine)
|
||||
dat += text("<HR><b>Mineral Value List:</b><BR>[machine.get_ore_values()]")
|
||||
|
||||
|
||||
user << browse("[dat]", "window=console_stacking_machine")
|
||||
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/attackby(obj/item/I as obj, mob/user as mob, params)
|
||||
if(istype(I, /obj/item/card/id))
|
||||
return attack_hand(user)
|
||||
..()
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/emag_act(user as mob)
|
||||
emag(user)
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/proc/emag(mob/user as mob)
|
||||
if(!emagged)
|
||||
emagged = 1
|
||||
/obj/machinery/mineral/labor_claim_console/emag_act(mob/user)
|
||||
if(!(emagged))
|
||||
emagged = TRUE
|
||||
to_chat(user, "<span class='warning'>PZZTTPFFFT</span>")
|
||||
|
||||
|
||||
|
||||
/obj/machinery/mineral/labor_claim_console/Topic(href, href_list)
|
||||
usr.set_machine(src)
|
||||
src.add_fingerprint(usr)
|
||||
if(href_list["choice"])
|
||||
if(istype(inserted_id)) //Sanity check against href spoofs
|
||||
if(href_list["choice"] == "eject")
|
||||
inserted_id.loc = loc
|
||||
inserted_id.verb_pickup()
|
||||
inserted_id = null
|
||||
if(href_list["choice"] == "claim")
|
||||
inserted_id.points += machine.points
|
||||
machine.points = 0
|
||||
to_chat(src, "Points transferred.")
|
||||
else if(href_list["choice"] == "insert")
|
||||
var/obj/item/card/id/prisoner/I = usr.get_active_hand()
|
||||
if(istype(I))
|
||||
usr.drop_item()
|
||||
I.loc = src
|
||||
inserted_id = I
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>Invalid ID.</span>")
|
||||
if(check_auth()) //Sanity check against hef spoofs
|
||||
if(href_list["choice"] == "station")
|
||||
if(!alone_in_area(get_area(src), usr))
|
||||
to_chat(usr, "<span class='warning'>Prisoners are only allowed to be released while alone.</span>")
|
||||
else
|
||||
switch(SSshuttle.moveShuttle("laborcamp","laborcamp_home"))
|
||||
if(1)
|
||||
to_chat(usr, "<span class='notice'>Shuttle not found</span>")
|
||||
if(2)
|
||||
to_chat(usr, "<span class='notice'>Shuttle already at station</span>")
|
||||
if(3)
|
||||
to_chat(usr, "<span class='notice'>No permission to dock could be granted.</span>")
|
||||
else
|
||||
var/message = "[inserted_id.registered_name] has returned to the station. Minerals and Prisoner ID card ready for retrieval."
|
||||
announcer.autosay(message, "Labor Camp Controller", "Security")
|
||||
to_chat(usr, "<span class='notice'>Shuttle received message and will be sent shortly.</span>")
|
||||
|
||||
if(href_list["choice"] == "release")
|
||||
if(alone_in_area(get_area(loc), usr))
|
||||
var/obj/docking_port/stationary/S = SSshuttle.getDock("laborcamp_home")
|
||||
if(S && S.get_docked())
|
||||
if(release_door && release_door.density)
|
||||
release_door.open()
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>Prisoners can only be released while docked with the station.</span>")
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>Prisoners are only allowed to be released while alone.</span>")
|
||||
|
||||
src.updateUsrDialog()
|
||||
return
|
||||
|
||||
|
||||
/**********************Prisoner Collection Unit**************************/
|
||||
|
||||
|
||||
/obj/machinery/mineral/stacking_machine/laborstacker
|
||||
var/points = 0 //The unclaimed value of ore stacked. Value for each ore loosely relative to its rarity.
|
||||
var/list/ore_values = list(("glass" = 1), ("metal" = 2), ("solid plasma" = 20), ("plasteel" = 23), ("reinforced glass" = 4), ("gold" = 20), ("silver" = 20), ("uranium" = 20), ("diamond" = 25), ("bananium" = 50), ("tranquillite" = 50))
|
||||
|
||||
/obj/machinery/mineral/stacking_machine/laborstacker/proc/get_ore_values()
|
||||
var/dat = "<table border='0' width='200'>"
|
||||
for(var/ore in ore_values)
|
||||
var/value = ore_values[ore]
|
||||
dat += "<tr><td>[capitalize(ore)]</td><td>[value]</td></tr>"
|
||||
dat += "</table>"
|
||||
return dat
|
||||
var/points = 0 //The unclaimed value of ore stacked.
|
||||
|
||||
/obj/machinery/mineral/stacking_machine/laborstacker/process_sheet(obj/item/stack/sheet/inp)
|
||||
if(istype(inp))
|
||||
var/n = inp.name
|
||||
var/a = inp.amount
|
||||
if(n in ore_values)
|
||||
points += ore_values[n] * a
|
||||
points += inp.point_value * inp.amount
|
||||
..()
|
||||
|
||||
/obj/machinery/mineral/stacking_machine/laborstacker/attackby(obj/item/I, mob/living/user)
|
||||
if(istype(I, /obj/item/stack/sheet) && user.canUnEquip(I))
|
||||
var/obj/item/stack/sheet/inp = I
|
||||
points += inp.point_value * inp.amount
|
||||
return ..()
|
||||
|
||||
/**********************Point Lookup Console**************************/
|
||||
/obj/machinery/mineral/labor_points_checker
|
||||
@@ -159,13 +161,15 @@
|
||||
desc = "A console used by prisoners to check the progress on their quotas. Simply swipe a prisoner ID."
|
||||
icon = 'icons/obj/machines/mining_machines.dmi'
|
||||
icon_state = "console"
|
||||
density = 0
|
||||
anchored = 1
|
||||
density = FALSE
|
||||
|
||||
/obj/machinery/mineral/labor_points_checker/attack_hand(mob/user)
|
||||
user.examine(src)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
user.examinate(src)
|
||||
|
||||
/obj/machinery/mineral/labor_points_checker/attackby(obj/item/I as obj, mob/user as mob, params)
|
||||
/obj/machinery/mineral/labor_points_checker/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/card/id))
|
||||
if(istype(I, /obj/item/card/id/prisoner))
|
||||
var/obj/item/card/id/prisoner/prisoner_id = I
|
||||
@@ -175,5 +179,5 @@
|
||||
to_chat(user, "<span class='notice'>Collect points by bringing smelted minerals to the Labor Shuttle stacking machine. Reach your quota to earn your release.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Error: Invalid ID</span>")
|
||||
return
|
||||
..()
|
||||
else
|
||||
return ..()
|
||||
@@ -27,6 +27,17 @@
|
||||
if(prob(15))
|
||||
harvest(null, TRUE)
|
||||
|
||||
/obj/structure/flora/ash/ex_act(severity, target)
|
||||
switch(severity)
|
||||
if(1)
|
||||
qdel(src)
|
||||
if(2)
|
||||
if(prob(80))
|
||||
qdel(src)
|
||||
if(3)
|
||||
if(prob(50))
|
||||
qdel(src)
|
||||
|
||||
/obj/structure/flora/ash/proc/harvest(user, no_drop)
|
||||
if(harvested)
|
||||
return 0
|
||||
@@ -137,7 +148,7 @@
|
||||
regrowth_time_low = 4800
|
||||
regrowth_time_high = 7200
|
||||
|
||||
/obj/structure/flora/ash/cacti/Crossed(mob/AM)
|
||||
/obj/structure/flora/ash/cacti/Crossed(mob/AM, oldloc)
|
||||
if(ishuman(AM) && has_gravity(loc) && prob(70))
|
||||
var/mob/living/carbon/human/H = AM
|
||||
if(!H.shoes && !H.lying) //ouch, my feet.
|
||||
|
||||
@@ -12,8 +12,12 @@
|
||||
/obj/structure/closet/crate/necropolis/tendril
|
||||
desc = "It's watching you suspiciously."
|
||||
|
||||
/obj/structure/closet/crate/necropolis/tendril/New()
|
||||
/obj/structure/closet/crate/necropolis/tendril/New(add_loot = TRUE)
|
||||
..()
|
||||
|
||||
if(!add_loot)
|
||||
return
|
||||
|
||||
var/loot = rand(1,24)
|
||||
switch(loot)
|
||||
if(1)
|
||||
@@ -68,4 +72,19 @@
|
||||
new /obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal/inquisitor(src)
|
||||
new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor(src)
|
||||
if(24)
|
||||
new /obj/item/spellbook/oneuse/summonitem(src)
|
||||
new /obj/item/spellbook/oneuse/summonitem(src)
|
||||
|
||||
/obj/structure/closet/crate/necropolis/puzzle
|
||||
name = "puzzling chest"
|
||||
|
||||
/obj/structure/closet/crate/necropolis/puzzle/New()
|
||||
..(FALSE)
|
||||
|
||||
var/loot = rand(1,3)
|
||||
switch(loot)
|
||||
if(1)
|
||||
new /obj/item/soulstone/anybody(src)
|
||||
if(2)
|
||||
new /obj/item/wisp_lantern(src)
|
||||
if(3)
|
||||
new /obj/item/prisoncube(src)
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
/obj/item/flashlight/lantern
|
||||
name = "lantern"
|
||||
icon_state = "lantern"
|
||||
item_state = "lantern"
|
||||
desc = "A mining lantern."
|
||||
brightness_on = 6 // luminosity when on
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
else if(W.isOn())
|
||||
to_chat(user, "<span class='info'>Not enough fuel to smelt [src].</span>")
|
||||
|
||||
/obj/item/stack/ore/Crossed(atom/movable/AM)
|
||||
/obj/item/stack/ore/Crossed(atom/movable/AM, oldloc)
|
||||
var/obj/item/storage/bag/ore/OB
|
||||
var/turf/simulated/floor/F = get_turf(src)
|
||||
if(loc != F)
|
||||
|
||||
@@ -263,7 +263,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
..()
|
||||
statpanel("Status")
|
||||
if(client.statpanel == "Status")
|
||||
show_stat_station_time()
|
||||
show_stat_emergency_shuttle_eta()
|
||||
stat(null, "Respawnability: [(src in GLOB.respawnable_list) ? "Yes" : "No"]")
|
||||
|
||||
@@ -402,9 +401,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
to_chat(usr, "Not when you're not dead!")
|
||||
return
|
||||
|
||||
var/area/A = input("Area to jump to", "BOOYEA") as null|anything in ghostteleportlocs
|
||||
var/area/thearea = ghostteleportlocs[A]
|
||||
var/datum/async_input/A = input_autocomplete_async(usr, "Area to jump to: ", ghostteleportlocs)
|
||||
A.on_close(CALLBACK(src, .proc/teleport))
|
||||
|
||||
/mob/dead/observer/proc/teleport(area/thearea)
|
||||
if(!thearea)
|
||||
return
|
||||
|
||||
@@ -425,9 +425,8 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
set desc = "Follow and orbit a mob."
|
||||
|
||||
var/list/mobs = getpois(skip_mindless=1)
|
||||
var/input = input("Please, select a mob!", "Haunt", null, null) as null|anything in mobs
|
||||
var/mob/target = mobs[input]
|
||||
ManualFollow(target)
|
||||
var/datum/async_input/A = input_autocomplete_async(usr, "Please, select a mob: ", mobs)
|
||||
A.on_close(CALLBACK(src, .proc/ManualFollow))
|
||||
|
||||
// This is the ghost's follow verb with an argument
|
||||
/mob/dead/observer/proc/ManualFollow(var/atom/movable/target)
|
||||
@@ -499,25 +498,21 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
set name = "Jump to Mob"
|
||||
set desc = "Teleport to a mob"
|
||||
|
||||
if(isobserver(usr)) //Make sure they're an observer!
|
||||
var/list/dest = list() //List of possible destinations (mobs)
|
||||
var/target = null //Chosen target.
|
||||
if(isobserver(usr)) //Make sure they're an observer!
|
||||
var/list/dest = getpois(mobs_only=1) //Fill list, prompt user with list
|
||||
var/datum/async_input/A = input_autocomplete_async(usr, "Enter a mob name: ", dest)
|
||||
A.on_close(CALLBACK(src, .proc/jump_to_mob))
|
||||
|
||||
dest += getpois(mobs_only=1) //Fill list, prompt user with list
|
||||
target = input("Please, select a mob!", "Jump to Mob", null, null) as null|anything in dest
|
||||
|
||||
if(!target) //Make sure we actually have a target
|
||||
return
|
||||
else
|
||||
var/mob/M = dest[target] //Destination mob
|
||||
var/mob/A = src //Source mob
|
||||
var/turf/T = get_turf(M) //Turf of the destination mob
|
||||
|
||||
if(T && isturf(T)) //Make sure the turf exists, then move the source to that destination.
|
||||
A.forceMove(T)
|
||||
else
|
||||
to_chat(A, "This mob is not located in the game world.")
|
||||
/mob/dead/observer/proc/jump_to_mob(mob/M)
|
||||
if(!M)
|
||||
return
|
||||
var/mob/A = src //Source mob
|
||||
var/turf/T = get_turf(M) //Turf of the destination mob
|
||||
|
||||
if(T && isturf(T)) //Make sure the turf exists, then move the source to that destination.
|
||||
A.forceMove(T)
|
||||
return
|
||||
to_chat(A, "This mob is not located in the game world.")
|
||||
|
||||
/* Now a spell. See spells.dm
|
||||
/mob/dead/observer/verb/boo()
|
||||
|
||||
@@ -15,6 +15,7 @@ GLOBAL_LIST_INIT(boo_phrases, list(
|
||||
|
||||
ghost = TRUE
|
||||
|
||||
action_icon_state = "boo"
|
||||
school = "transmutation"
|
||||
charge_max = 600
|
||||
starts_charged = FALSE
|
||||
|
||||
@@ -58,19 +58,20 @@
|
||||
if(message)
|
||||
log_emote(message, src)
|
||||
|
||||
//Hearing gasp and such every five seconds is not good emotes were not global for a reason.
|
||||
// Maybe some people are okay with that.
|
||||
|
||||
// Hearing gasp and such every five seconds is not good emotes were not global for a reason.
|
||||
// Maybe some people are okay with that.
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(!M.client)
|
||||
continue //skip monkeys and leavers
|
||||
if(istype(M, /mob/new_player))
|
||||
continue
|
||||
if(findtext(message," snores.")) //Because we have so many sleeping people.
|
||||
break
|
||||
if(M.stat == DEAD && M.get_preference(CHAT_GHOSTSIGHT) && !(M in viewers(src,null)))
|
||||
M.show_message(message)
|
||||
|
||||
if(isnewplayer(M))
|
||||
continue
|
||||
|
||||
if(findtext(message, " snores.")) //Because we have so many sleeping people.
|
||||
break
|
||||
|
||||
if(isobserver(M) && M.get_preference(CHAT_GHOSTSIGHT) && !(M in viewers(src, null)) && client) // The client check makes sure people with ghost sight don't get spammed by simple mobs emoting.
|
||||
M.show_message(message)
|
||||
|
||||
// Type 1 (Visual) emotes are sent to anyone in view of the item
|
||||
if(m_type & EMOTE_VISUAL)
|
||||
|
||||
@@ -63,10 +63,10 @@
|
||||
var/datum/gas_mixture/environment = T.return_air()
|
||||
var/pressure = environment ? environment.return_pressure() : 0
|
||||
if(pressure < SOUND_MINIMUM_PRESSURE && get_dist(speaker, src) > 1)
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if(pressure < ONE_ATMOSPHERE * 0.4) //sound distortion pressure, to help clue people in that the air is thin, even if it isn't a vacuum yet
|
||||
italics = 1
|
||||
italics = TRUE
|
||||
sound_vol *= 0.5
|
||||
|
||||
if(sleeping || stat == UNCONSCIOUS)
|
||||
@@ -87,8 +87,6 @@
|
||||
|
||||
var/track = null
|
||||
if(isobserver(src))
|
||||
if(italics && client.prefs.toggles & CHAT_GHOSTRADIO)
|
||||
return
|
||||
if(speaker_name != speaker.real_name && speaker.real_name)
|
||||
speaker_name = "[speaker.real_name] ([speaker_name])"
|
||||
track = "([ghost_follow_link(speaker, ghost=src)]) "
|
||||
|
||||
@@ -6,6 +6,14 @@
|
||||
if(hand) return l_hand
|
||||
else return r_hand
|
||||
|
||||
/mob/verb/quick_equip()
|
||||
set name = "quick-equip"
|
||||
set hidden = 1
|
||||
|
||||
var/obj/item/I = get_active_hand()
|
||||
if(I)
|
||||
I.equip_to_best_slot(src)
|
||||
|
||||
/mob/proc/is_in_active_hand(obj/item/I)
|
||||
var/obj/item/item_to_test = get_active_hand()
|
||||
|
||||
@@ -254,3 +262,4 @@
|
||||
if(slot_r_hand)
|
||||
return r_hand
|
||||
return null
|
||||
|
||||
|
||||
@@ -455,6 +455,7 @@
|
||||
colour = "alien"
|
||||
key = "y"
|
||||
flags = RESTRICTED | HIVEMIND
|
||||
follow = TRUE
|
||||
|
||||
/datum/language/wryn/check_special_condition(mob/other)
|
||||
var/mob/living/carbon/M = other
|
||||
@@ -485,7 +486,7 @@
|
||||
colour = "alien"
|
||||
key = "a"
|
||||
flags = RESTRICTED | HIVEMIND
|
||||
follow = 1
|
||||
follow = TRUE
|
||||
|
||||
/datum/language/terrorspider
|
||||
name = "Spider Hivemind"
|
||||
@@ -496,7 +497,7 @@
|
||||
colour = "terrorspider"
|
||||
key = "ts"
|
||||
flags = RESTRICTED | HIVEMIND
|
||||
follow = 1
|
||||
follow = TRUE
|
||||
|
||||
/datum/language/ling
|
||||
name = "Changeling"
|
||||
@@ -505,10 +506,11 @@
|
||||
colour = "changeling"
|
||||
key = "g"
|
||||
flags = RESTRICTED | HIVEMIND
|
||||
follow = TRUE
|
||||
|
||||
/datum/language/ling/broadcast(mob/living/speaker, message, speaker_mask)
|
||||
if(speaker.mind && speaker.mind.changeling)
|
||||
..(speaker,message,speaker.mind.changeling.changelingID)
|
||||
..(speaker, message, speaker.mind.changeling.changelingID)
|
||||
else if(speaker.mind && speaker.mind.linglink)
|
||||
..()
|
||||
else
|
||||
@@ -521,6 +523,7 @@
|
||||
colour = "shadowling"
|
||||
key = "8"
|
||||
flags = RESTRICTED | HIVEMIND
|
||||
follow = TRUE
|
||||
|
||||
/datum/language/shadowling/broadcast(mob/living/speaker, message, speaker_mask)
|
||||
if(speaker.mind && speaker.mind.special_role == SPECIAL_ROLE_SHADOWLING)
|
||||
@@ -539,6 +542,7 @@
|
||||
colour = "abductor"
|
||||
key = "zw" //doesn't matter, this is their default and only language
|
||||
flags = RESTRICTED | HIVEMIND
|
||||
follow = TRUE
|
||||
|
||||
/datum/language/abductor/broadcast(mob/living/speaker, message, speaker_mask)
|
||||
..(speaker,message,speaker.real_name)
|
||||
@@ -567,6 +571,7 @@
|
||||
colour = "alien"
|
||||
key = "bo"
|
||||
flags = RESTRICTED | HIVEMIND
|
||||
follow = TRUE
|
||||
|
||||
/datum/language/corticalborer/broadcast(mob/living/speaker, message, speaker_mask)
|
||||
var/mob/living/simple_animal/borer/B
|
||||
@@ -590,7 +595,7 @@
|
||||
exclaim_verb = "declares"
|
||||
key = "b"
|
||||
flags = RESTRICTED | HIVEMIND
|
||||
follow = 1
|
||||
follow = TRUE
|
||||
var/drone_only
|
||||
|
||||
/datum/language/binary/broadcast(mob/living/speaker, message, speaker_mask)
|
||||
@@ -636,8 +641,8 @@
|
||||
colour = "say_quote"
|
||||
key = "d"
|
||||
flags = RESTRICTED | HIVEMIND
|
||||
drone_only = 1
|
||||
follow = 1
|
||||
drone_only = TRUE
|
||||
follow = TRUE
|
||||
|
||||
/datum/language/drone
|
||||
name = "Drone"
|
||||
@@ -647,7 +652,7 @@
|
||||
exclaim_verb = "declares"
|
||||
key = "]"
|
||||
flags = RESTRICTED
|
||||
follow = 1
|
||||
follow = TRUE
|
||||
syllables = list ("beep", "boop")
|
||||
|
||||
/datum/language/swarmer
|
||||
@@ -659,7 +664,7 @@
|
||||
colour = "say_quote"
|
||||
key = "z"//Zwarmer...Or Zerg!
|
||||
flags = RESTRICTED | HIVEMIND
|
||||
follow = 1
|
||||
follow = TRUE
|
||||
|
||||
// Language handling.
|
||||
/mob/proc/add_language(language)
|
||||
|
||||
@@ -73,7 +73,11 @@
|
||||
stat = CONSCIOUS
|
||||
return
|
||||
health = maxHealth - getOxyLoss() - getFireLoss() - getBruteLoss() - getCloneLoss()
|
||||
|
||||
update_stat("updatehealth([reason])")
|
||||
med_hud_set_health()
|
||||
med_hud_set_status()
|
||||
handle_hud_icons_health()
|
||||
|
||||
/mob/living/carbon/alien/handle_environment(var/datum/gas_mixture/environment)
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
. = -1 //hunters are sanic
|
||||
. += ..() //but they still need to slow down on stun
|
||||
|
||||
/mob/living/carbon/alien/humanoid/hunter/handle_regular_hud_updates()
|
||||
/mob/living/carbon/alien/humanoid/hunter/handle_hud_icons_health()
|
||||
..() //-Yvarov
|
||||
|
||||
if(healths)
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
alien_organs += new /obj/item/organ/internal/xenos/neurotoxin
|
||||
..()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/sentinel/handle_regular_hud_updates()
|
||||
/mob/living/carbon/alien/humanoid/sentinel/handle_hud_icons_health()
|
||||
..() //-Yvarov
|
||||
|
||||
if(healths)
|
||||
|
||||
@@ -48,29 +48,26 @@
|
||||
alien_organs += new /obj/item/organ/internal/xenos/neurotoxin
|
||||
..()
|
||||
|
||||
/mob/living/carbon/alien/humanoid/empress
|
||||
/mob/living/carbon/alien/humanoid/empress/handle_hud_icons_health()
|
||||
..() //-Yvarov
|
||||
|
||||
handle_regular_hud_updates()
|
||||
|
||||
..() //-Yvarov
|
||||
|
||||
if(src.healths)
|
||||
if(src.stat != 2)
|
||||
switch(health)
|
||||
if(250 to INFINITY)
|
||||
src.healths.icon_state = "health0"
|
||||
if(175 to 250)
|
||||
src.healths.icon_state = "health1"
|
||||
if(100 to 175)
|
||||
src.healths.icon_state = "health2"
|
||||
if(50 to 100)
|
||||
src.healths.icon_state = "health3"
|
||||
if(0 to 50)
|
||||
src.healths.icon_state = "health4"
|
||||
else
|
||||
src.healths.icon_state = "health5"
|
||||
else
|
||||
src.healths.icon_state = "health6"
|
||||
if(healths)
|
||||
if(stat != 2)
|
||||
switch(health)
|
||||
if(250 to INFINITY)
|
||||
healths.icon_state = "health0"
|
||||
if(175 to 250)
|
||||
healths.icon_state = "health1"
|
||||
if(100 to 175)
|
||||
healths.icon_state = "health2"
|
||||
if(50 to 100)
|
||||
healths.icon_state = "health3"
|
||||
if(0 to 50)
|
||||
healths.icon_state = "health4"
|
||||
else
|
||||
healths.icon_state = "health5"
|
||||
else
|
||||
healths.icon_state = "health6"
|
||||
|
||||
/mob/living/carbon/alien/humanoid/empress/verb/lay_egg()
|
||||
set name = "Lay Egg (250)"
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
. = ..()
|
||||
. += 3
|
||||
|
||||
/mob/living/carbon/alien/humanoid/queen/handle_regular_hud_updates()
|
||||
/mob/living/carbon/alien/humanoid/queen/handle_hud_icons_health()
|
||||
..() //-Yvarov
|
||||
|
||||
if(healths)
|
||||
|
||||
@@ -72,7 +72,7 @@ var/const/MAX_ACTIVE_TIME = 400
|
||||
/obj/item/clothing/mask/facehugger/equipped(mob/M)
|
||||
Attach(M)
|
||||
|
||||
/obj/item/clothing/mask/facehugger/Crossed(atom/target)
|
||||
/obj/item/clothing/mask/facehugger/Crossed(atom/target, oldloc)
|
||||
HasProximity(target)
|
||||
return
|
||||
|
||||
|
||||
@@ -95,7 +95,6 @@ I'm using this for Stat to give it a more nifty interface to work with
|
||||
..()
|
||||
if(has_synthetic_assistance())
|
||||
statpanel("Status")
|
||||
show_stat_station_time()
|
||||
show_stat_emergency_shuttle_eta()
|
||||
|
||||
if(client.statpanel == "Status")
|
||||
|
||||
@@ -216,56 +216,7 @@
|
||||
add_attack_logs(M, src, "Shaked", ATKLOG_ALL)
|
||||
if(health >= HEALTH_THRESHOLD_CRIT)
|
||||
if(src == M && ishuman(src))
|
||||
var/mob/living/carbon/human/H = src
|
||||
visible_message( \
|
||||
text("<span class='notice'>[src] examines [].</span>",gender==MALE?"himself":"herself"), \
|
||||
"<span class='notice'>You check yourself for injuries.</span>" \
|
||||
)
|
||||
|
||||
var/list/missing = list("head", "chest", "groin", "l_arm", "r_arm", "l_hand", "r_hand", "l_leg", "r_leg", "l_foot", "r_foot")
|
||||
for(var/X in H.bodyparts)
|
||||
var/obj/item/organ/external/LB = X
|
||||
missing -= LB.limb_name
|
||||
var/status = ""
|
||||
var/brutedamage = LB.brute_dam
|
||||
var/burndamage = LB.burn_dam
|
||||
|
||||
if(brutedamage > 0)
|
||||
status = "bruised"
|
||||
if(brutedamage > 20)
|
||||
status = "battered"
|
||||
if(brutedamage > 40)
|
||||
status = "mangled"
|
||||
if(brutedamage > 0 && burndamage > 0)
|
||||
status += " and "
|
||||
if(burndamage > 40)
|
||||
status += "peeling away"
|
||||
|
||||
else if(burndamage > 10)
|
||||
status += "blistered"
|
||||
else if(burndamage > 0)
|
||||
status += "numb"
|
||||
if(LB.status & ORGAN_MUTATED)
|
||||
status = "weirdly shapen."
|
||||
if(status == "")
|
||||
status = "OK"
|
||||
to_chat(src, "\t <span class='[status == "OK" ? "notice" : "warning"]'>Your [LB.name] is [status].</span>")
|
||||
|
||||
for(var/obj/item/I in LB.embedded_objects)
|
||||
to_chat(src, "\t <a href='byond://?src=[UID()];embedded_object=[I.UID()];embedded_limb=[LB.UID()]' class='warning'>There is \a [I] embedded in your [LB.name]!</a>")
|
||||
|
||||
for(var/t in missing)
|
||||
to_chat(src, "<span class='boldannounce'>Your [parse_zone(t)] is missing!</span>")
|
||||
|
||||
if(H.bleed_rate)
|
||||
to_chat(src, "<span class='danger'>You are bleeding!</span>")
|
||||
if(staminaloss)
|
||||
if(staminaloss > 30)
|
||||
to_chat(src, "<span class='info'>You're completely exhausted.</span>")
|
||||
else
|
||||
to_chat(src, "<span class='info'>You feel fatigued.</span>")
|
||||
if((SKELETON in H.mutations) && (!H.w_uniform) && (!H.wear_suit))
|
||||
H.play_xylophone()
|
||||
check_self_for_injuries()
|
||||
else
|
||||
if(player_logged)
|
||||
M.visible_message("<span class='notice'>[M] shakes [src], but [p_they()] [p_do()] not respond. Probably suffering from SSD.", \
|
||||
@@ -308,6 +259,58 @@
|
||||
else if(H.w_uniform)
|
||||
H.w_uniform.add_fingerprint(M)
|
||||
|
||||
/mob/living/carbon/proc/check_self_for_injuries()
|
||||
var/mob/living/carbon/human/H = src
|
||||
visible_message( \
|
||||
text("<span class='notice'>[src] examines [].</span>",gender==MALE?"himself":"herself"), \
|
||||
"<span class='notice'>You check yourself for injuries.</span>" \
|
||||
)
|
||||
|
||||
var/list/missing = list("head", "chest", "groin", "l_arm", "r_arm", "l_hand", "r_hand", "l_leg", "r_leg", "l_foot", "r_foot")
|
||||
for(var/X in H.bodyparts)
|
||||
var/obj/item/organ/external/LB = X
|
||||
missing -= LB.limb_name
|
||||
var/status = ""
|
||||
var/brutedamage = LB.brute_dam
|
||||
var/burndamage = LB.burn_dam
|
||||
|
||||
if(brutedamage > 0)
|
||||
status = "bruised"
|
||||
if(brutedamage > 20)
|
||||
status = "battered"
|
||||
if(brutedamage > 40)
|
||||
status = "mangled"
|
||||
if(brutedamage > 0 && burndamage > 0)
|
||||
status += " and "
|
||||
if(burndamage > 40)
|
||||
status += "peeling away"
|
||||
|
||||
else if(burndamage > 10)
|
||||
status += "blistered"
|
||||
else if(burndamage > 0)
|
||||
status += "numb"
|
||||
if(LB.status & ORGAN_MUTATED)
|
||||
status = "weirdly shapen."
|
||||
if(status == "")
|
||||
status = "OK"
|
||||
to_chat(src, "\t <span class='[status == "OK" ? "notice" : "warning"]'>Your [LB.name] is [status].</span>")
|
||||
|
||||
for(var/obj/item/I in LB.embedded_objects)
|
||||
to_chat(src, "\t <a href='byond://?src=[UID()];embedded_object=[I.UID()];embedded_limb=[LB.UID()]' class='warning'>There is \a [I] embedded in your [LB.name]!</a>")
|
||||
|
||||
for(var/t in missing)
|
||||
to_chat(src, "<span class='boldannounce'>Your [parse_zone(t)] is missing!</span>")
|
||||
|
||||
if(H.bleed_rate)
|
||||
to_chat(src, "<span class='danger'>You are bleeding!</span>")
|
||||
if(staminaloss)
|
||||
if(staminaloss > 30)
|
||||
to_chat(src, "<span class='info'>You're completely exhausted.</span>")
|
||||
else
|
||||
to_chat(src, "<span class='info'>You feel fatigued.</span>")
|
||||
if((SKELETON in H.mutations) && (!H.w_uniform) && (!H.wear_suit))
|
||||
H.play_xylophone()
|
||||
|
||||
/mob/living/carbon/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0)
|
||||
. = ..()
|
||||
var/damage = intensity - check_eye_prot()
|
||||
@@ -972,6 +975,7 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump,
|
||||
to_chat(src, "<span class='notice'>You [slipVerb]ped on [description]!</span>")
|
||||
playsound(src.loc, 'sound/misc/slip.ogg', 50, 1, -3)
|
||||
// Something something don't run with scissors
|
||||
moving_diagonally = 0 //If this was part of diagonal move slipping will stop it.
|
||||
Stun(stun)
|
||||
Weaken(weaken)
|
||||
return 1
|
||||
|
||||
@@ -106,6 +106,12 @@
|
||||
else //Everyone else fails, skip the emote attempt
|
||||
return
|
||||
|
||||
if("warble", "warbles")
|
||||
if(isskrell(src)) //Only Skrell can warble.
|
||||
on_CD = handle_emote_CD() //proc located in code\modules\mob\emote.dm'
|
||||
else //Everyone else fails, skip the emote attempt
|
||||
return
|
||||
|
||||
if("scream", "screams")
|
||||
on_CD = handle_emote_CD(50) //longer cooldown
|
||||
if("fart", "farts", "flip", "flips", "snap", "snaps")
|
||||
@@ -221,6 +227,13 @@
|
||||
playsound(loc, 'sound/effects/voxrustle.ogg', 50, 0) //Credit to sound-ideas (freesfx.co.uk) for the sound.
|
||||
m_type = 2
|
||||
|
||||
if("warble", "warbles")
|
||||
var/M = handle_emote_param(param)
|
||||
|
||||
message = "<B>[src]</B> warbles[M ? " at [M]" : ""]."
|
||||
playsound(loc, 'sound/effects/warble.ogg', 50, 0) // Copyright CC BY 3.0 alienistcog (freesound.org) for the sound.
|
||||
m_type = 2
|
||||
|
||||
if("yes")
|
||||
var/M = handle_emote_param(param)
|
||||
|
||||
@@ -658,9 +671,9 @@
|
||||
if(!restrained())
|
||||
var/t1 = round(text2num(param))
|
||||
if(isnum(t1))
|
||||
if(t1 <= 5 && (!r_hand || !l_hand))
|
||||
if(t1 <= 5 && t1 >= 1 && (!r_hand || !l_hand))
|
||||
message = "<B>[src]</B> raises [t1] finger\s."
|
||||
else if(t1 <= 10 && (!r_hand && !l_hand))
|
||||
else if(t1 <= 10 && t1 >= 1 && (!r_hand && !l_hand))
|
||||
message = "<B>[src]</B> raises [t1] finger\s."
|
||||
m_type = 1
|
||||
|
||||
@@ -904,6 +917,8 @@
|
||||
emotelist += "\nVox specific emotes :- quill(s)"
|
||||
if("Diona")
|
||||
emotelist += "\nDiona specific emotes :- creak(s)"
|
||||
if("Skrell")
|
||||
emotelist += "\nSkrell specific emotes :- warble(s)"
|
||||
|
||||
if(ismachine(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"
|
||||
@@ -931,9 +946,13 @@
|
||||
// Maybe some people are okay with that.
|
||||
|
||||
for(var/mob/M in GLOB.dead_mob_list)
|
||||
if(!M.client || istype(M, /mob/new_player))
|
||||
continue //skip monkeys, leavers and new players
|
||||
if(M.stat == DEAD && M.get_preference(CHAT_GHOSTSIGHT) && !(M in viewers(src,null)))
|
||||
if(!M.client)
|
||||
continue
|
||||
|
||||
if(isnewplayer(M))
|
||||
continue
|
||||
|
||||
if(isobserver(M) && M.get_preference(CHAT_GHOSTSIGHT) && !(M in viewers(src, null)) && client) // The client check makes sure people with ghost sight don't get spammed by simple mobs emoting.
|
||||
M.show_message(message)
|
||||
|
||||
switch(m_type)
|
||||
|
||||
@@ -162,8 +162,6 @@
|
||||
stat(null, "Intent: [a_intent]")
|
||||
stat(null, "Move Mode: [m_intent]")
|
||||
|
||||
show_stat_station_time()
|
||||
|
||||
show_stat_emergency_shuttle_eta()
|
||||
|
||||
if(client.statpanel == "Status")
|
||||
@@ -455,7 +453,7 @@
|
||||
popup.open()
|
||||
|
||||
|
||||
/mob/living/carbon/human/Crossed(atom/movable/AM)
|
||||
/mob/living/carbon/human/Crossed(atom/movable/AM, oldloc)
|
||||
var/mob/living/simple_animal/bot/mulebot/MB = AM
|
||||
if(istype(MB))
|
||||
MB.RunOver(src)
|
||||
@@ -1480,19 +1478,22 @@
|
||||
|
||||
if(usr != src)
|
||||
return 0 //something is terribly wrong
|
||||
|
||||
if(incapacitated())
|
||||
to_chat(src, "<span class='warning'>You can't write on the floor in your current state!</span>")
|
||||
return
|
||||
if(!bloody_hands)
|
||||
verbs -= /mob/living/carbon/human/proc/bloody_doodle
|
||||
|
||||
if(src.gloves)
|
||||
to_chat(src, "<span class='warning'>Your [src.gloves] are getting in the way.</span>")
|
||||
if(gloves)
|
||||
to_chat(src, "<span class='warning'>[gloves] are preventing you from writing anything down!</span>")
|
||||
return
|
||||
|
||||
var/turf/simulated/T = src.loc
|
||||
var/turf/simulated/T = loc
|
||||
if(!istype(T)) //to prevent doodling out of mechs and lockers
|
||||
to_chat(src, "<span class='warning'>You cannot reach the floor.</span>")
|
||||
return
|
||||
|
||||
var/turf/origin = T
|
||||
var/direction = input(src,"Which way?","Tile selection") as anything in list("Here","North","South","East","West")
|
||||
if(direction != "Here")
|
||||
T = get_step(T,text2dir(direction))
|
||||
@@ -1510,7 +1511,9 @@
|
||||
var/max_length = bloody_hands * 30 //tweeter style
|
||||
|
||||
var/message = stripped_input(src,"Write a message. It cannot be longer than [max_length] characters.","Blood writing", "")
|
||||
|
||||
if(origin != loc)
|
||||
to_chat(src, "<span class='notice'>Stay still while writing!</span>")
|
||||
return
|
||||
if(message)
|
||||
var/used_blood_amount = round(length(message) / 30, 1)
|
||||
bloody_hands = max(0, bloody_hands - used_blood_amount) //use up some blood
|
||||
@@ -1518,7 +1521,8 @@
|
||||
if(length(message) > max_length)
|
||||
message += "-"
|
||||
to_chat(src, "<span class='warning'>You ran out of blood to write with!</span>")
|
||||
|
||||
else
|
||||
to_chat(src, "<span class='notice'>You daub '[message]' on [T] in shiny red lettering.</span>")
|
||||
var/obj/effect/decal/cleanable/blood/writing/W = new(T)
|
||||
W.message = message
|
||||
W.add_fingerprint(src)
|
||||
@@ -1935,7 +1939,6 @@ Eyes need to have significantly high darksight to shine unless the mob has the X
|
||||
. += "---"
|
||||
.["Set Species"] = "?_src_=vars;setspecies=[UID()]"
|
||||
.["Make AI"] = "?_src_=vars;makeai=[UID()]"
|
||||
.["Make Mask of Nar'sie"] = "?_src_=vars;makemask=[UID()]"
|
||||
.["Make cyborg"] = "?_src_=vars;makerobot=[UID()]"
|
||||
.["Make monkey"] = "?_src_=vars;makemonkey=[UID()]"
|
||||
.["Make alien"] = "?_src_=vars;makealien=[UID()]"
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
/mob/living/carbon/human/verb/quick_equip()
|
||||
set name = "quick-equip"
|
||||
set hidden = 1
|
||||
|
||||
var/obj/item/I = get_active_hand()
|
||||
if(I)
|
||||
I.equip_to_best_slot(src)
|
||||
|
||||
/mob/living/carbon/human/proc/equip_in_one_of_slots(obj/item/W, list/slots, del_on_fail = 1)
|
||||
for(var/slot in slots)
|
||||
if(equip_to_slot_if_possible(W, slots[slot], del_on_fail = 0))
|
||||
|
||||
@@ -341,9 +341,6 @@
|
||||
if(SKELETON in target.mutations)
|
||||
to_chat(user, "<span class='warning'>There is no blood in a skeleton!</span>")
|
||||
return
|
||||
if(issmall(target) && !target.ckey) //Monkeyized humans are okay, humanized monkeys are okay, NPC monkeys are not.
|
||||
to_chat(user, "<span class='warning'>Blood from a monkey is useless!</span>")
|
||||
return
|
||||
//we're good to suck the blood, blaah
|
||||
user.mind.vampire.handle_bloodsucking(target)
|
||||
add_attack_logs(user, target, "vampirebit")
|
||||
@@ -603,20 +600,37 @@
|
||||
H.healthdoll.cached_healthdoll_overlays = new_overlays
|
||||
|
||||
/datum/species/proc/handle_hud_icons_nutrition(mob/living/carbon/human/H)
|
||||
switch(H.nutrition)
|
||||
if(NUTRITION_LEVEL_FULL to INFINITY)
|
||||
H.throw_alert("nutrition", /obj/screen/alert/fat)
|
||||
if(NUTRITION_LEVEL_WELL_FED to NUTRITION_LEVEL_FULL)
|
||||
H.throw_alert("nutrition", /obj/screen/alert/full)
|
||||
if(NUTRITION_LEVEL_FED to NUTRITION_LEVEL_WELL_FED)
|
||||
H.throw_alert("nutrition", /obj/screen/alert/well_fed)
|
||||
if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FED)
|
||||
H.throw_alert("nutrition", /obj/screen/alert/fed)
|
||||
if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY)
|
||||
H.throw_alert("nutrition", /obj/screen/alert/hungry)
|
||||
else
|
||||
H.throw_alert("nutrition", /obj/screen/alert/starving)
|
||||
return 1
|
||||
if(H.mind && H.mind.vampire && (H.mind in SSticker.mode.vampires)) //Vampires
|
||||
switch(H.nutrition)
|
||||
if(NUTRITION_LEVEL_FULL to INFINITY)
|
||||
H.throw_alert("nutrition", /obj/screen/alert/fat/vampire)
|
||||
if(NUTRITION_LEVEL_WELL_FED to NUTRITION_LEVEL_FULL)
|
||||
H.throw_alert("nutrition", /obj/screen/alert/full/vampire)
|
||||
if(NUTRITION_LEVEL_FED to NUTRITION_LEVEL_WELL_FED)
|
||||
H.throw_alert("nutrition", /obj/screen/alert/well_fed/vampire)
|
||||
if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FED)
|
||||
H.throw_alert("nutrition", /obj/screen/alert/fed/vampire)
|
||||
if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY)
|
||||
H.throw_alert("nutrition", /obj/screen/alert/hungry/vampire)
|
||||
else
|
||||
H.throw_alert("nutrition", /obj/screen/alert/starving/vampire)
|
||||
return 1
|
||||
|
||||
else ///Any other non-vampires
|
||||
switch(H.nutrition)
|
||||
if(NUTRITION_LEVEL_FULL to INFINITY)
|
||||
H.throw_alert("nutrition", /obj/screen/alert/fat)
|
||||
if(NUTRITION_LEVEL_WELL_FED to NUTRITION_LEVEL_FULL)
|
||||
H.throw_alert("nutrition", /obj/screen/alert/full)
|
||||
if(NUTRITION_LEVEL_FED to NUTRITION_LEVEL_WELL_FED)
|
||||
H.throw_alert("nutrition", /obj/screen/alert/well_fed)
|
||||
if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FED)
|
||||
H.throw_alert("nutrition", /obj/screen/alert/fed)
|
||||
if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY)
|
||||
H.throw_alert("nutrition", /obj/screen/alert/hungry)
|
||||
else
|
||||
H.throw_alert("nutrition", /obj/screen/alert/starving)
|
||||
return 1
|
||||
|
||||
/*
|
||||
Returns the path corresponding to the corresponding organ
|
||||
@@ -675,7 +689,7 @@ It'll return null if the organ doesn't correspond, so include null checks when u
|
||||
H.see_invisible = G.invis_override
|
||||
else
|
||||
H.see_invisible = min(G.invis_view, H.see_invisible)
|
||||
|
||||
|
||||
if(!isnull(G.lighting_alpha))
|
||||
H.lighting_alpha = min(G.lighting_alpha, H.lighting_alpha)
|
||||
|
||||
|
||||
@@ -59,8 +59,7 @@
|
||||
handle_status_effects() //all special effects, stunned, weakened, jitteryness, hallucination, sleeping, etc
|
||||
|
||||
if(client)
|
||||
//regular_hud_updates() //THIS DOESN'T FUCKING UPDATE SHIT
|
||||
handle_regular_hud_updates() //IT JUST REMOVES FUCKING HUD IMAGES
|
||||
handle_regular_hud_updates()
|
||||
|
||||
..()
|
||||
|
||||
|
||||
@@ -528,7 +528,7 @@
|
||||
return
|
||||
|
||||
var/pull_dir = get_dir(src, pulling)
|
||||
if(get_dist(src, pulling) > 1 || ((pull_dir - 1) & pull_dir)) // puller and pullee more than one tile away or in diagonal position
|
||||
if(get_dist(src, pulling) > 1 || (moving_diagonally != SECOND_DIAG_STEP && ((pull_dir - 1) & pull_dir))) // puller and pullee more than one tile away or in diagonal position
|
||||
if(isliving(pulling))
|
||||
var/mob/living/M = pulling
|
||||
if(M.lying && !M.buckled && (prob(M.getBruteLoss() * 200 / M.maxHealth)))
|
||||
|
||||
@@ -216,7 +216,7 @@ proc/get_radio_key_from_channel(var/channel)
|
||||
message_range = 1
|
||||
|
||||
if(pressure < ONE_ATMOSPHERE * 0.4) //sound distortion pressure, to help clue people in that the air is thin, even if it isn't a vacuum yet
|
||||
italics = 1
|
||||
italics = TRUE
|
||||
sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact
|
||||
|
||||
var/list/hear = hear(message_range, T)
|
||||
@@ -236,12 +236,20 @@ proc/get_radio_key_from_channel(var/channel)
|
||||
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(!M.client)
|
||||
continue //skip monkeys and leavers
|
||||
continue
|
||||
|
||||
if(isnewplayer(M))
|
||||
continue
|
||||
if(M.stat == DEAD && M.client && M.get_preference(CHAT_GHOSTEARS) && client) // client is so that ghosts don't have to listen to mice
|
||||
listening |= M
|
||||
continue
|
||||
|
||||
if(isobserver(M))
|
||||
if(M.get_preference(CHAT_GHOSTEARS) && client) // The client check is so that ghosts don't have to listen to mice.
|
||||
listening |= M
|
||||
continue
|
||||
|
||||
if(message_range < world.view && (get_dist(T, M) <= world.view))
|
||||
listening |= M
|
||||
continue
|
||||
|
||||
if(get_turf(M) in hearturfs)
|
||||
listening |= M
|
||||
|
||||
@@ -291,10 +299,13 @@ proc/get_radio_key_from_channel(var/channel)
|
||||
log_emote(message, src)
|
||||
|
||||
for(var/mob/M in GLOB.dead_mob_list)
|
||||
if(!M.client || istype(M, /mob/new_player))
|
||||
continue //skip monkeys, leavers and new players //who the hell knows why new players are in the dead mob list
|
||||
if(!M.client)
|
||||
continue //skip monkeys and leavers
|
||||
|
||||
if(M.stat == DEAD && M.get_preference(CHAT_GHOSTSIGHT) && !(M in viewers(src,null)))
|
||||
if(isnewplayer(M))
|
||||
continue
|
||||
|
||||
if(isobserver(M) && M.get_preference(CHAT_GHOSTSIGHT) && !(M in viewers(src, null)) && client) // The client check makes sure people with ghost sight don't get spammed by simple mobs emoting.
|
||||
M.show_message(message)
|
||||
|
||||
switch(type)
|
||||
@@ -380,7 +391,7 @@ proc/get_radio_key_from_channel(var/channel)
|
||||
|
||||
var/list/hearturfs = list()
|
||||
|
||||
//Pass whispers on to anything inside the immediate listeners.
|
||||
// Pass whispers on to anything inside the immediate listeners.
|
||||
// This comes before the ghosts do so that ghosts don't act as whisper relays
|
||||
for(var/atom/L in listening)
|
||||
if(ismob(L))
|
||||
@@ -391,22 +402,26 @@ proc/get_radio_key_from_channel(var/channel)
|
||||
if(isobj(L))
|
||||
hearturfs += get_turf(L)
|
||||
|
||||
//ghosts
|
||||
for(var/mob/M in GLOB.dead_mob_list) //does this include players who joined as observers as well?
|
||||
// Loop through all players to see if they need to hear it.
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(!M.client)
|
||||
continue
|
||||
if(M.stat == DEAD && M.client && M.get_preference(CHAT_GHOSTEARS))
|
||||
listening |= M
|
||||
|
||||
// This, in tandem with "hearturfs", lets nested mobs hear whispers that are in range
|
||||
// Grifted from saycode above.
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(!M.client || isnewplayer(M))
|
||||
continue //skip monkeys and leavers
|
||||
if(isnewplayer(M))
|
||||
continue
|
||||
|
||||
if(isobserver(M))
|
||||
if(M.get_preference(CHAT_GHOSTEARS)) // The client check is so that ghosts don't have to listen to mice.
|
||||
listening |= M
|
||||
continue
|
||||
|
||||
if(message_range < world.view && (get_dist(whisper_loc, M) <= world.view))
|
||||
listening |= M
|
||||
continue
|
||||
|
||||
if(get_turf(M) in hearturfs)
|
||||
listening |= M
|
||||
|
||||
|
||||
//pass on the message to objects that can hear us.
|
||||
for(var/obj/O in view(message_range, whisper_loc))
|
||||
spawn(0)
|
||||
|
||||
@@ -634,7 +634,7 @@ var/list/ai_verbs_default = list(
|
||||
return
|
||||
|
||||
if(href_list["trackbot"])
|
||||
var/mob/living/simple_animal/bot/target = locate(href_list["trackbot"]) in GLOB.simple_animals
|
||||
var/mob/living/simple_animal/bot/target = locate(href_list["trackbot"]) in GLOB.bots_list
|
||||
if(target)
|
||||
ai_actual_track(target)
|
||||
else
|
||||
@@ -642,7 +642,7 @@ var/list/ai_verbs_default = list(
|
||||
return
|
||||
|
||||
if(href_list["callbot"]) //Command a bot to move to a selected location.
|
||||
Bot = locate(href_list["callbot"]) in GLOB.simple_animals
|
||||
Bot = locate(href_list["callbot"]) in GLOB.bots_list
|
||||
if(!Bot || Bot.remote_disabled || control_disabled)
|
||||
return //True if there is no bot found, the bot is manually emagged, or the AI is carded with wireless off.
|
||||
waypoint_mode = 1
|
||||
@@ -650,7 +650,7 @@ var/list/ai_verbs_default = list(
|
||||
return
|
||||
|
||||
if(href_list["interface"]) //Remotely connect to a bot!
|
||||
Bot = locate(href_list["interface"]) in GLOB.simple_animals
|
||||
Bot = locate(href_list["interface"]) in GLOB.bots_list
|
||||
if(!Bot || Bot.remote_disabled || control_disabled)
|
||||
return
|
||||
Bot.attack_ai(src)
|
||||
@@ -746,7 +746,7 @@ var/list/ai_verbs_default = list(
|
||||
d += "<A HREF=?src=[UID()];botrefresh=\ref[Bot]>Query network status</A><br>"
|
||||
d += "<table width='100%'><tr><td width='40%'><h3>Name</h3></td><td width='20%'><h3>Status</h3></td><td width='30%'><h3>Location</h3></td><td width='10%'><h3>Control</h3></td></tr>"
|
||||
|
||||
for(var/mob/living/simple_animal/bot/Bot in GLOB.simple_animals)
|
||||
for(var/mob/living/simple_animal/bot/Bot in GLOB.bots_list)
|
||||
if(is_ai_allowed(Bot.z) && !Bot.remote_disabled) //Only non-emagged bots on the allowed Z-level are detected!
|
||||
bot_area = get_area(Bot)
|
||||
d += "<tr><td width='30%'>[Bot.hacked ? "<span class='bad'>(!) </span>[Bot.name]" : Bot.name] ([Bot.model])</td>"
|
||||
|
||||
@@ -2,6 +2,3 @@
|
||||
..()
|
||||
regenerate_icons()
|
||||
show_laws(0)
|
||||
|
||||
var/datum/hotkey_mode/cyborg/C = new(src)
|
||||
C.set_winset_values()
|
||||
|
||||
@@ -103,6 +103,9 @@ var/list/robot_verbs_default = list(
|
||||
var/datum/action/item_action/toggle_research_scanner/scanner = null
|
||||
var/list/module_actions = list()
|
||||
|
||||
/mob/living/silicon/robot/get_cell()
|
||||
return cell
|
||||
|
||||
/mob/living/silicon/robot/New(loc,var/syndie = 0,var/unfinished = 0, var/alien = 0)
|
||||
spark_system = new /datum/effect_system/spark_spread()
|
||||
spark_system.set_up(5, 0, src)
|
||||
@@ -1453,4 +1456,4 @@ var/list/robot_verbs_default = list(
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_MOB_UPDATE_SIGHT)
|
||||
sync_lighting_plane_alpha()
|
||||
|
||||
|
||||
|
||||
@@ -156,7 +156,6 @@
|
||||
/mob/living/silicon/Stat()
|
||||
..()
|
||||
if(statpanel("Status"))
|
||||
show_stat_station_time()
|
||||
show_stat_emergency_shuttle_eta()
|
||||
show_system_integrity()
|
||||
|
||||
|
||||
@@ -594,7 +594,7 @@ var/robot_arm = /obj/item/robot_parts/l_arm
|
||||
qdel(src)
|
||||
|
||||
/obj/item/honkbot_arm_assembly
|
||||
name = "incomplete honkbot assembly."
|
||||
name = "incomplete honkbot assembly"
|
||||
desc = "A clown box with a robot arm permanently grafted to it."
|
||||
icon = 'icons/obj/aibots.dmi'
|
||||
icon_state = "honkbot_arm"
|
||||
@@ -625,8 +625,8 @@ var/robot_arm = /obj/item/robot_parts/l_arm
|
||||
if(istype(W, /obj/item/instrument/trombone))
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You add the trombone to [src]! Heeeenk! </span>")
|
||||
to_chat(user, "<span class='notice'>You add the trombone to [src]! Heeeenk!</span>")
|
||||
qdel(W)
|
||||
var/mob/living/simple_animal/bot/honkbot/A = new /mob/living/simple_animal/bot/honkbot(T)
|
||||
var/mob/living/simple_animal/bot/honkbot/A = new /mob/living/simple_animal/bot/honkbot(get_turf(src))
|
||||
A.robot_arm = robot_arm
|
||||
qdel(src)
|
||||
@@ -48,7 +48,7 @@
|
||||
..()
|
||||
light_color = LIGHT_COLOR_PURE_RED //if you see a red one. RUN!!
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/griefsky/Crossed(atom/movable/AM)
|
||||
/mob/living/simple_animal/bot/secbot/griefsky/Crossed(atom/movable/AM, oldloc)
|
||||
..()
|
||||
if(ismob(AM) && AM == target)
|
||||
var/mob/living/carbon/C = AM
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
. = ..()
|
||||
update_icon()
|
||||
auto_patrol = TRUE
|
||||
var/datum/job/clown/J = new/datum/job/clown
|
||||
var/datum/job/clown/J = new /datum/job/clown()
|
||||
access_card.access += J.get_access()
|
||||
prev_access = access_card.access
|
||||
|
||||
@@ -298,7 +298,7 @@
|
||||
target = user
|
||||
mode = BOT_HUNT
|
||||
|
||||
/mob/living/simple_animal/bot/honkbot/Crossed(atom/movable/AM)
|
||||
/mob/living/simple_animal/bot/honkbot/Crossed(atom/movable/AM, oldloc)
|
||||
if(ismob(AM) && on) //only if its online
|
||||
if(prob(30)) //you're far more likely to trip on a honkbot
|
||||
var/mob/living/carbon/C = AM
|
||||
|
||||
@@ -50,6 +50,9 @@
|
||||
var/currentBloodColor = "#A10808"
|
||||
var/currentDNA = null
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/get_cell()
|
||||
return cell
|
||||
|
||||
/mob/living/simple_animal/bot/mulebot/New()
|
||||
..()
|
||||
wires = new /datum/wires/mulebot(src)
|
||||
|
||||
@@ -439,7 +439,7 @@ Auto Patrol: []"},
|
||||
target = user
|
||||
mode = BOT_HUNT
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/Crossed(atom/movable/AM)
|
||||
/mob/living/simple_animal/bot/secbot/Crossed(atom/movable/AM, oldloc)
|
||||
if(ismob(AM) && target)
|
||||
var/mob/living/carbon/C = AM
|
||||
if(!istype(C) || !C || in_range(src, target))
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
status_flags = 0
|
||||
const_type = "juggernaut"
|
||||
mob_size = MOB_SIZE_LARGE
|
||||
construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/conjure/lesserforcewall)
|
||||
construct_spells = list(/obj/effect/proc_holder/spell/targeted/night_vision, /obj/effect/proc_holder/spell/aoe_turf/conjure/lesserforcewall)
|
||||
force_threshold = 11
|
||||
playstyle_string = "<b>You are a Juggernaut. Though slow, your shell can withstand extreme punishment, \
|
||||
create shield walls, rip apart enemies and walls alike, and even deflect energy weapons.</b>"
|
||||
@@ -171,7 +171,7 @@
|
||||
see_in_dark = 8
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
const_type = "wraith"
|
||||
construct_spells = list(/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift)
|
||||
construct_spells = list(/obj/effect/proc_holder/spell/targeted/night_vision, /obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift)
|
||||
retreat_distance = 2 //AI wraiths will move in and out of combat
|
||||
playstyle_string = "<b>You are a Wraith. Though relatively fragile, you are fast, deadly, and even able to phase through walls.</b>"
|
||||
|
||||
@@ -202,7 +202,8 @@
|
||||
minimum_distance = 10 //AI artificers will flee like fuck
|
||||
attack_sound = 'sound/weapons/punch2.ogg'
|
||||
const_type = "builder"
|
||||
construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/conjure/construct/lesser,
|
||||
construct_spells = list(/obj/effect/proc_holder/spell/targeted/night_vision,
|
||||
/obj/effect/proc_holder/spell/aoe_turf/conjure/construct/lesser,
|
||||
/obj/effect/proc_holder/spell/aoe_turf/conjure/wall,
|
||||
/obj/effect/proc_holder/spell/aoe_turf/conjure/floor,
|
||||
/obj/effect/proc_holder/spell/aoe_turf/conjure/pylon,
|
||||
@@ -311,7 +312,8 @@
|
||||
see_in_dark = 8
|
||||
attack_sound = 'sound/weapons/tap.ogg'
|
||||
const_type = "harvester"
|
||||
construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/conjure/wall,
|
||||
construct_spells = list(/obj/effect/proc_holder/spell/targeted/night_vision,
|
||||
/obj/effect/proc_holder/spell/aoe_turf/conjure/wall,
|
||||
/obj/effect/proc_holder/spell/aoe_turf/conjure/floor,
|
||||
/obj/effect/proc_holder/spell/targeted/smoke/disable)
|
||||
retreat_distance = 2 //AI harvesters will move in and out of combat, like wraiths, but shittier
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
/mob/living/simple_animal/cockroach/can_die()
|
||||
return ..() && !SSticker.cinematic //If the nuke is going off, then cockroaches are invincible. Keeps the nuke from killing them, cause cockroaches are immune to nukes.
|
||||
|
||||
/mob/living/simple_animal/cockroach/Crossed(var/atom/movable/AM)
|
||||
/mob/living/simple_animal/cockroach/Crossed(var/atom/movable/AM, oldloc)
|
||||
if(isliving(AM))
|
||||
var/mob/living/A = AM
|
||||
if(A.mob_size > MOB_SIZE_SMALL)
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
to_chat(src, "<span class='warning'>You are too small to pull anything.</span>")
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/mouse/Crossed(AM as mob|obj)
|
||||
/mob/living/simple_animal/mouse/Crossed(AM as mob|obj, oldloc)
|
||||
if(ishuman(AM))
|
||||
if(!stat)
|
||||
var/mob/M = AM
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
icon = 'icons/mob/alien.dmi'
|
||||
icon_state = "alienh_running"
|
||||
icon_living = "alienh_running"
|
||||
icon_dead = "alien_l"
|
||||
icon_dead = "alienh_dead"
|
||||
icon_gib = "syndicate_gib"
|
||||
response_help = "pokes the"
|
||||
response_disarm = "shoves the"
|
||||
@@ -40,7 +40,7 @@
|
||||
name = "alien drone"
|
||||
icon_state = "aliend_running"
|
||||
icon_living = "aliend_running"
|
||||
icon_dead = "aliend_l"
|
||||
icon_dead = "aliend_dead"
|
||||
health = 60
|
||||
maxHealth = 60
|
||||
melee_damage_lower = 15
|
||||
@@ -61,7 +61,7 @@
|
||||
name = "alien sentinel"
|
||||
icon_state = "aliens_running"
|
||||
icon_living = "aliens_running"
|
||||
icon_dead = "aliens_l"
|
||||
icon_dead = "aliens_dead"
|
||||
health = 120
|
||||
maxHealth = 120
|
||||
melee_damage_lower = 15
|
||||
@@ -77,7 +77,7 @@
|
||||
name = "alien queen"
|
||||
icon_state = "alienq_running"
|
||||
icon_living = "alienq_running"
|
||||
icon_dead = "alienq_l"
|
||||
icon_dead = "alienq_d"
|
||||
health = 250
|
||||
maxHealth = 250
|
||||
melee_damage_lower = 15
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/mob/living/simple_animal/hostile/creature
|
||||
name = "creature"
|
||||
desc = "A sanity-destroying otherthing."
|
||||
icon = 'icons/mob/critter.dmi'
|
||||
speak_emote = list("gibbers")
|
||||
icon_state = "otherthing"
|
||||
icon_living = "otherthing"
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
maxHealth = 50
|
||||
health = 50
|
||||
pixel_x = -16
|
||||
see_in_dark = 8
|
||||
|
||||
harm_intent_damage = 8
|
||||
melee_damage_lower = 15
|
||||
|
||||
@@ -1,265 +1,265 @@
|
||||
#define MINER_DASH_RANGE 4
|
||||
|
||||
/*
|
||||
|
||||
BLOOD-DRUNK MINER
|
||||
|
||||
Effectively a highly aggressive miner, the blood-drunk miner has very few attacks but compensates by being highly aggressive.
|
||||
|
||||
The blood-drunk miner's attacks are as follows
|
||||
- If not in KA range, it will rapidly dash at its target
|
||||
- If in KA range, it will fire its kinetic accelerator
|
||||
- If in melee range, will rapidly attack, akin to an actual player
|
||||
- After any of these attacks, may transform its cleaving saw:
|
||||
Untransformed, it attacks very rapidly for smaller amounts of damage
|
||||
Transformed, it attacks at normal speed for higher damage and cleaves enemies hit
|
||||
|
||||
When the blood-drunk miner dies, it leaves behind the cleaving saw it was using and its kinetic accelerator.
|
||||
|
||||
Difficulty: Medium
|
||||
|
||||
*/
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner
|
||||
name = "blood-drunk miner"
|
||||
desc = "A miner destined to wander forever, engaged in an endless hunt."
|
||||
health = 900
|
||||
maxHealth = 900
|
||||
icon_state = "miner"
|
||||
icon_living = "miner"
|
||||
icon = 'icons/mob/alienqueen.dmi'
|
||||
light_color = "#E4C7C5"
|
||||
speak_emote = list("roars")
|
||||
speed = 1
|
||||
move_to_delay = 3
|
||||
projectiletype = /obj/item/projectile/kinetic/miner
|
||||
projectilesound = 'sound/weapons/kenetic_accel.ogg'
|
||||
ranged = 1
|
||||
ranged_cooldown_time = 16
|
||||
pixel_x = -16
|
||||
loot = list(/obj/item/melee/energy/cleaving_saw, /obj/item/gun/energy/kinetic_accelerator)
|
||||
wander = FALSE
|
||||
del_on_death = TRUE
|
||||
blood_volume = BLOOD_VOLUME_NORMAL
|
||||
var/obj/item/melee/energy/cleaving_saw/miner/miner_saw
|
||||
var/time_until_next_transform = 0
|
||||
var/dashing = FALSE
|
||||
var/dash_cooldown = 15
|
||||
var/guidance = FALSE
|
||||
deathmessage = "falls to the ground, decaying into glowing particles."
|
||||
death_sound = "bodyfall"
|
||||
|
||||
/obj/item/gps/internal/miner
|
||||
icon_state = null
|
||||
gpstag = "Resonant Signal"
|
||||
desc = "The sweet blood, oh, it sings to me."
|
||||
invisibility = 100
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/guidance
|
||||
guidance = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/hunter/AttackingTarget()
|
||||
. = ..()
|
||||
if(. && prob(12))
|
||||
INVOKE_ASYNC(src, .proc/dash)
|
||||
|
||||
/obj/item/melee/energy/cleaving_saw/miner //nerfed saw because it is very murdery
|
||||
force = 6
|
||||
force_on = 10
|
||||
|
||||
/obj/item/melee/energy/cleaving_saw/miner/attack(mob/living/target, mob/living/carbon/human/user)
|
||||
target.add_stun_absorption("miner", 10, INFINITY)
|
||||
..()
|
||||
target.stun_absorption -= "miner"
|
||||
|
||||
/obj/item/projectile/kinetic/miner
|
||||
damage = 20
|
||||
speed = 0.9
|
||||
icon_state = "ka_tracer"
|
||||
range = MINER_DASH_RANGE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/Initialize()
|
||||
. = ..()
|
||||
miner_saw = new(src)
|
||||
internal_gps = new/obj/item/gps/internal/miner(src)
|
||||
|
||||
// Add a zone selection UI; otherwise the mob can't melee attack properly.
|
||||
zone_sel = new /obj/screen/zone_sel()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
|
||||
var/adjustment_amount = amount * 0.1
|
||||
if(world.time + adjustment_amount > next_move)
|
||||
changeNext_move(adjustment_amount) //attacking it interrupts it attacking, but only briefly
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/death()
|
||||
if(health > 0)
|
||||
return
|
||||
new /obj/effect/temp_visual/dir_setting/miner_death(loc, dir)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/Move(atom/newloc)
|
||||
if(dashing || (newloc && newloc.z == z && (islava(newloc) || ischasm(newloc)))) //we're not stupid!
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/ex_act(severity, target)
|
||||
if(dash())
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/AttackingTarget()
|
||||
if(QDELETED(target))
|
||||
return
|
||||
if(next_move > world.time || !Adjacent(target)) //some cheating
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop)
|
||||
return
|
||||
face_atom(target)
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(L.stat == DEAD)
|
||||
visible_message("<span class='danger'>[src] butchers [L]!</span>",
|
||||
"<span class='userdanger'>You butcher [L], restoring your health!</span>")
|
||||
if(!is_station_level(z) || client) //NPC monsters won't heal while on station
|
||||
if(guidance)
|
||||
adjustHealth(-L.maxHealth)
|
||||
else
|
||||
adjustHealth(-(L.maxHealth * 0.5))
|
||||
L.gib()
|
||||
return TRUE
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
miner_saw.melee_attack_chain(src, target)
|
||||
if(guidance)
|
||||
adjustHealth(-2)
|
||||
transform_weapon()
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop)
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
|
||||
if(!used_item && !isturf(A))
|
||||
used_item = miner_saw
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/GiveTarget(new_target)
|
||||
var/targets_the_same = (new_target == target)
|
||||
. = ..()
|
||||
if(. && target && !targets_the_same)
|
||||
wander = TRUE
|
||||
transform_weapon()
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/OpenFire()
|
||||
Goto(target, move_to_delay, minimum_distance)
|
||||
if(get_dist(src, target) > MINER_DASH_RANGE && dash_cooldown <= world.time)
|
||||
INVOKE_ASYNC(src, .proc/dash, target)
|
||||
else
|
||||
shoot_ka()
|
||||
transform_weapon()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/shoot_ka()
|
||||
if(ranged_cooldown <= world.time && get_dist(src, target) <= MINER_DASH_RANGE && !Adjacent(target))
|
||||
ranged_cooldown = world.time + ranged_cooldown_time
|
||||
visible_message("<span class='danger'>[src] fires the proto-kinetic accelerator!</span>")
|
||||
face_atom(target)
|
||||
new /obj/effect/temp_visual/dir_setting/firing_effect(loc, dir)
|
||||
Shoot(target)
|
||||
changeNext_move(CLICK_CD_RANGE)
|
||||
|
||||
//I'm still of the belief that this entire proc needs to be wiped from existence.
|
||||
// do not take my touching of it to be endorsement of it. ~mso
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/quick_attack_loop()
|
||||
while(!QDELETED(target) && next_move <= world.time) //this is done this way because next_move can change to be sooner while we sleep.
|
||||
stoplag(1)
|
||||
sleep((next_move - world.time) * 1.5) //but don't ask me what the fuck this is about
|
||||
if(QDELETED(target))
|
||||
return
|
||||
if(dashing || next_move > world.time || !Adjacent(target))
|
||||
if(dashing && next_move <= world.time)
|
||||
next_move = world.time + 1
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop) //lets try that again.
|
||||
return
|
||||
AttackingTarget()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/dash(atom/dash_target)
|
||||
if(world.time < dash_cooldown)
|
||||
return
|
||||
var/list/accessable_turfs = list()
|
||||
var/self_dist_to_target = 0
|
||||
var/turf/own_turf = get_turf(src)
|
||||
if(!QDELETED(dash_target))
|
||||
self_dist_to_target += get_dist(dash_target, own_turf)
|
||||
for(var/turf/simulated/O in RANGE_TURFS(MINER_DASH_RANGE, own_turf))
|
||||
var/turf_dist_to_target = 0
|
||||
if(!QDELETED(dash_target))
|
||||
turf_dist_to_target += get_dist(dash_target, O)
|
||||
if(get_dist(src, O) >= MINER_DASH_RANGE && turf_dist_to_target <= self_dist_to_target && !islava(O) && !ischasm(O))
|
||||
var/valid = TRUE
|
||||
for(var/turf/T in getline(own_turf, O))
|
||||
if(is_blocked_turf(T, TRUE))
|
||||
valid = FALSE
|
||||
continue
|
||||
if(valid)
|
||||
accessable_turfs[O] = turf_dist_to_target
|
||||
var/turf/target_turf
|
||||
if(!QDELETED(dash_target))
|
||||
var/closest_dist = MINER_DASH_RANGE
|
||||
for(var/t in accessable_turfs)
|
||||
if(accessable_turfs[t] < closest_dist)
|
||||
closest_dist = accessable_turfs[t]
|
||||
for(var/t in accessable_turfs)
|
||||
if(accessable_turfs[t] != closest_dist)
|
||||
accessable_turfs -= t
|
||||
if(!LAZYLEN(accessable_turfs))
|
||||
return
|
||||
dash_cooldown = world.time + initial(dash_cooldown)
|
||||
target_turf = pick(accessable_turfs)
|
||||
var/turf/step_back_turf = get_step(target_turf, get_cardinal_dir(target_turf, own_turf))
|
||||
var/turf/step_forward_turf = get_step(own_turf, get_cardinal_dir(own_turf, target_turf))
|
||||
new /obj/effect/temp_visual/small_smoke/halfsecond(step_back_turf)
|
||||
new /obj/effect/temp_visual/small_smoke/halfsecond(step_forward_turf)
|
||||
var/obj/effect/temp_visual/decoy/D = new /obj/effect/temp_visual/decoy(loc, src)
|
||||
animate(D, alpha = 0, time = 5)
|
||||
forceMove(step_back_turf)
|
||||
playsound(own_turf, 'sound/weapons/punchmiss.ogg', 40, 1, -1)
|
||||
dashing = TRUE
|
||||
alpha = 0
|
||||
animate(src, alpha = 255, time = 5)
|
||||
sleep(2)
|
||||
D.forceMove(step_forward_turf)
|
||||
forceMove(target_turf)
|
||||
playsound(target_turf, 'sound/weapons/punchmiss.ogg', 40, 1, -1)
|
||||
sleep(1)
|
||||
dashing = FALSE
|
||||
shoot_ka()
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/transform_weapon()
|
||||
if(time_until_next_transform <= world.time)
|
||||
miner_saw.transform_cooldown = 0
|
||||
miner_saw.transform_weapon(src, TRUE)
|
||||
icon_state = "miner[miner_saw.active ? "_transformed":""]"
|
||||
icon_living = "miner[miner_saw.active ? "_transformed":""]"
|
||||
time_until_next_transform = world.time + rand(50, 100)
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/miner_death
|
||||
icon_state = "miner_death"
|
||||
duration = 15
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/miner_death/Initialize(mapload, set_dir)
|
||||
. = ..()
|
||||
INVOKE_ASYNC(src, .proc/fade_out)
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/miner_death/proc/fade_out()
|
||||
var/matrix/M = new
|
||||
M.Turn(pick(90, 270))
|
||||
var/final_dir = dir
|
||||
if(dir & (EAST|WEST)) //Facing east or west
|
||||
final_dir = pick(NORTH, SOUTH) //So you fall on your side rather than your face or ass
|
||||
|
||||
animate(src, transform = M, pixel_y = -6, dir = final_dir, time = 2, easing = EASE_IN|EASE_OUT)
|
||||
sleep(5)
|
||||
animate(src, color = list("#A7A19E", "#A7A19E", "#A7A19E", list(0, 0, 0)), time = 10, easing = EASE_IN, flags = ANIMATION_PARALLEL)
|
||||
sleep(4)
|
||||
animate(src, alpha = 0, time = 6, easing = EASE_OUT, flags = ANIMATION_PARALLEL)
|
||||
|
||||
#define MINER_DASH_RANGE 4
|
||||
|
||||
/*
|
||||
|
||||
BLOOD-DRUNK MINER
|
||||
|
||||
Effectively a highly aggressive miner, the blood-drunk miner has very few attacks but compensates by being highly aggressive.
|
||||
|
||||
The blood-drunk miner's attacks are as follows
|
||||
- If not in KA range, it will rapidly dash at its target
|
||||
- If in KA range, it will fire its kinetic accelerator
|
||||
- If in melee range, will rapidly attack, akin to an actual player
|
||||
- After any of these attacks, may transform its cleaving saw:
|
||||
Untransformed, it attacks very rapidly for smaller amounts of damage
|
||||
Transformed, it attacks at normal speed for higher damage and cleaves enemies hit
|
||||
|
||||
When the blood-drunk miner dies, it leaves behind the cleaving saw it was using and its kinetic accelerator.
|
||||
|
||||
Difficulty: Medium
|
||||
|
||||
*/
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner
|
||||
name = "blood-drunk miner"
|
||||
desc = "A miner destined to wander forever, engaged in an endless hunt."
|
||||
health = 900
|
||||
maxHealth = 900
|
||||
icon_state = "miner"
|
||||
icon_living = "miner"
|
||||
icon = 'icons/mob/alienqueen.dmi'
|
||||
light_color = "#E4C7C5"
|
||||
speak_emote = list("roars")
|
||||
speed = 1
|
||||
move_to_delay = 3
|
||||
projectiletype = /obj/item/projectile/kinetic/miner
|
||||
projectilesound = 'sound/weapons/kenetic_accel.ogg'
|
||||
ranged = 1
|
||||
ranged_cooldown_time = 16
|
||||
pixel_x = -16
|
||||
loot = list(/obj/item/melee/energy/cleaving_saw, /obj/item/gun/energy/kinetic_accelerator)
|
||||
wander = FALSE
|
||||
del_on_death = TRUE
|
||||
blood_volume = BLOOD_VOLUME_NORMAL
|
||||
var/obj/item/melee/energy/cleaving_saw/miner/miner_saw
|
||||
var/time_until_next_transform = 0
|
||||
var/dashing = FALSE
|
||||
var/dash_cooldown = 15
|
||||
var/guidance = FALSE
|
||||
deathmessage = "falls to the ground, decaying into glowing particles."
|
||||
death_sound = "bodyfall"
|
||||
|
||||
/obj/item/gps/internal/miner
|
||||
icon_state = null
|
||||
gpstag = "Resonant Signal"
|
||||
desc = "The sweet blood, oh, it sings to me."
|
||||
invisibility = 100
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/guidance
|
||||
guidance = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/hunter/AttackingTarget()
|
||||
. = ..()
|
||||
if(. && prob(12))
|
||||
INVOKE_ASYNC(src, .proc/dash)
|
||||
|
||||
/obj/item/melee/energy/cleaving_saw/miner //nerfed saw because it is very murdery
|
||||
force = 6
|
||||
force_on = 10
|
||||
|
||||
/obj/item/melee/energy/cleaving_saw/miner/attack(mob/living/target, mob/living/carbon/human/user)
|
||||
target.add_stun_absorption("miner", 10, INFINITY)
|
||||
..()
|
||||
target.stun_absorption -= "miner"
|
||||
|
||||
/obj/item/projectile/kinetic/miner
|
||||
damage = 20
|
||||
speed = 0.9
|
||||
icon_state = "ka_tracer"
|
||||
range = MINER_DASH_RANGE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/Initialize()
|
||||
. = ..()
|
||||
miner_saw = new(src)
|
||||
internal_gps = new/obj/item/gps/internal/miner(src)
|
||||
|
||||
// Add a zone selection UI; otherwise the mob can't melee attack properly.
|
||||
zone_sel = new /obj/screen/zone_sel()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
|
||||
var/adjustment_amount = amount * 0.1
|
||||
if(world.time + adjustment_amount > next_move)
|
||||
changeNext_move(adjustment_amount) //attacking it interrupts it attacking, but only briefly
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/death()
|
||||
if(health > 0)
|
||||
return
|
||||
new /obj/effect/temp_visual/dir_setting/miner_death(loc, dir)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/Move(atom/newloc)
|
||||
if(dashing || (newloc && newloc.z == z && (islava(newloc) || ischasm(newloc)))) //we're not stupid!
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/ex_act(severity, target)
|
||||
if(dash())
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/AttackingTarget()
|
||||
if(QDELETED(target))
|
||||
return
|
||||
if(next_move > world.time || !Adjacent(target)) //some cheating
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop)
|
||||
return
|
||||
face_atom(target)
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(L.stat == DEAD)
|
||||
visible_message("<span class='danger'>[src] butchers [L]!</span>",
|
||||
"<span class='userdanger'>You butcher [L], restoring your health!</span>")
|
||||
if(!is_station_level(z) || client) //NPC monsters won't heal while on station
|
||||
if(guidance)
|
||||
adjustHealth(-L.maxHealth)
|
||||
else
|
||||
adjustHealth(-(L.maxHealth * 0.5))
|
||||
L.gib()
|
||||
return TRUE
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
miner_saw.melee_attack_chain(src, target)
|
||||
if(guidance)
|
||||
adjustHealth(-2)
|
||||
transform_weapon()
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop)
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
|
||||
if(!used_item && !isturf(A))
|
||||
used_item = miner_saw
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/GiveTarget(new_target)
|
||||
var/targets_the_same = (new_target == target)
|
||||
. = ..()
|
||||
if(. && target && !targets_the_same)
|
||||
wander = TRUE
|
||||
transform_weapon()
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/OpenFire()
|
||||
Goto(target, move_to_delay, minimum_distance)
|
||||
if(get_dist(src, target) > MINER_DASH_RANGE && dash_cooldown <= world.time)
|
||||
INVOKE_ASYNC(src, .proc/dash, target)
|
||||
else
|
||||
shoot_ka()
|
||||
transform_weapon()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/shoot_ka()
|
||||
if(ranged_cooldown <= world.time && get_dist(src, target) <= MINER_DASH_RANGE && !Adjacent(target))
|
||||
ranged_cooldown = world.time + ranged_cooldown_time
|
||||
visible_message("<span class='danger'>[src] fires the proto-kinetic accelerator!</span>")
|
||||
face_atom(target)
|
||||
new /obj/effect/temp_visual/dir_setting/firing_effect(loc, dir)
|
||||
Shoot(target)
|
||||
changeNext_move(CLICK_CD_RANGE)
|
||||
|
||||
//I'm still of the belief that this entire proc needs to be wiped from existence.
|
||||
// do not take my touching of it to be endorsement of it. ~mso
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/quick_attack_loop()
|
||||
while(!QDELETED(target) && next_move <= world.time) //this is done this way because next_move can change to be sooner while we sleep.
|
||||
stoplag(1)
|
||||
sleep((next_move - world.time) * 1.5) //but don't ask me what the fuck this is about
|
||||
if(QDELETED(target))
|
||||
return
|
||||
if(dashing || next_move > world.time || !Adjacent(target))
|
||||
if(dashing && next_move <= world.time)
|
||||
next_move = world.time + 1
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop) //lets try that again.
|
||||
return
|
||||
AttackingTarget()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/dash(atom/dash_target)
|
||||
if(world.time < dash_cooldown)
|
||||
return
|
||||
var/list/accessable_turfs = list()
|
||||
var/self_dist_to_target = 0
|
||||
var/turf/own_turf = get_turf(src)
|
||||
if(!QDELETED(dash_target))
|
||||
self_dist_to_target += get_dist(dash_target, own_turf)
|
||||
for(var/turf/simulated/O in RANGE_TURFS(MINER_DASH_RANGE, own_turf))
|
||||
var/turf_dist_to_target = 0
|
||||
if(!QDELETED(dash_target))
|
||||
turf_dist_to_target += get_dist(dash_target, O)
|
||||
if(get_dist(src, O) >= MINER_DASH_RANGE && turf_dist_to_target <= self_dist_to_target && !islava(O) && !ischasm(O))
|
||||
var/valid = TRUE
|
||||
for(var/turf/T in getline(own_turf, O))
|
||||
if(is_blocked_turf(T, TRUE))
|
||||
valid = FALSE
|
||||
continue
|
||||
if(valid)
|
||||
accessable_turfs[O] = turf_dist_to_target
|
||||
var/turf/target_turf
|
||||
if(!QDELETED(dash_target))
|
||||
var/closest_dist = MINER_DASH_RANGE
|
||||
for(var/t in accessable_turfs)
|
||||
if(accessable_turfs[t] < closest_dist)
|
||||
closest_dist = accessable_turfs[t]
|
||||
for(var/t in accessable_turfs)
|
||||
if(accessable_turfs[t] != closest_dist)
|
||||
accessable_turfs -= t
|
||||
if(!LAZYLEN(accessable_turfs))
|
||||
return
|
||||
dash_cooldown = world.time + initial(dash_cooldown)
|
||||
target_turf = pick(accessable_turfs)
|
||||
var/turf/step_back_turf = get_step(target_turf, get_cardinal_dir(target_turf, own_turf))
|
||||
var/turf/step_forward_turf = get_step(own_turf, get_cardinal_dir(own_turf, target_turf))
|
||||
new /obj/effect/temp_visual/small_smoke/halfsecond(step_back_turf)
|
||||
new /obj/effect/temp_visual/small_smoke/halfsecond(step_forward_turf)
|
||||
var/obj/effect/temp_visual/decoy/D = new /obj/effect/temp_visual/decoy(loc, src)
|
||||
animate(D, alpha = 0, time = 5)
|
||||
forceMove(step_back_turf)
|
||||
playsound(own_turf, 'sound/weapons/punchmiss.ogg', 40, 1, -1)
|
||||
dashing = TRUE
|
||||
alpha = 0
|
||||
animate(src, alpha = 255, time = 5)
|
||||
sleep(2)
|
||||
D.forceMove(step_forward_turf)
|
||||
forceMove(target_turf)
|
||||
playsound(target_turf, 'sound/weapons/punchmiss.ogg', 40, 1, -1)
|
||||
sleep(1)
|
||||
dashing = FALSE
|
||||
shoot_ka()
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/transform_weapon()
|
||||
if(time_until_next_transform <= world.time)
|
||||
miner_saw.transform_cooldown = 0
|
||||
miner_saw.transform_weapon(src, TRUE)
|
||||
icon_state = "miner[miner_saw.active ? "_transformed":""]"
|
||||
icon_living = "miner[miner_saw.active ? "_transformed":""]"
|
||||
time_until_next_transform = world.time + rand(50, 100)
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/miner_death
|
||||
icon_state = "miner_death"
|
||||
duration = 15
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/miner_death/Initialize(mapload, set_dir)
|
||||
. = ..()
|
||||
INVOKE_ASYNC(src, .proc/fade_out)
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/miner_death/proc/fade_out()
|
||||
var/matrix/M = new
|
||||
M.Turn(pick(90, 270))
|
||||
var/final_dir = dir
|
||||
if(dir & (EAST|WEST)) //Facing east or west
|
||||
final_dir = pick(NORTH, SOUTH) //So you fall on your side rather than your face or ass
|
||||
|
||||
animate(src, transform = M, pixel_y = -6, dir = final_dir, time = 2, easing = EASE_IN|EASE_OUT)
|
||||
sleep(5)
|
||||
animate(src, color = list("#A7A19E", "#A7A19E", "#A7A19E", list(0, 0, 0)), time = 10, easing = EASE_IN, flags = ANIMATION_PARALLEL)
|
||||
sleep(4)
|
||||
animate(src, alpha = 0, time = 6, easing = EASE_OUT, flags = ANIMATION_PARALLEL)
|
||||
|
||||
#undef MINER_DASH_RANGE
|
||||
@@ -526,7 +526,7 @@ Difficulty: Hard
|
||||
sleep(1.3) //slightly forgiving; the burst animation is 1.5 deciseconds
|
||||
bursting = FALSE //we no longer damage crossers
|
||||
|
||||
/obj/effect/temp_visual/hierophant/blast/Crossed(atom/movable/AM)
|
||||
/obj/effect/temp_visual/hierophant/blast/Crossed(atom/movable/AM, oldloc)
|
||||
..()
|
||||
if(bursting)
|
||||
do_damage(get_turf(src))
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/gutlunch/AttackingTarget()
|
||||
if(is_type_in_list(target, wanted_objects)) //we eats
|
||||
if(is_type_in_typecache(target, wanted_objects)) //we eats
|
||||
udder.generateMilk()
|
||||
regenerate_icons()
|
||||
visible_message("<span class='notice'>[src] slurps up [target].</span>")
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
maxHealth = 250
|
||||
max_mobs = 3
|
||||
spawn_time = 300 //30 seconds default
|
||||
mob_type = /mob/living/simple_animal/hostile/asteroid/basilisk/watcher/tendril
|
||||
mob_types = list(/mob/living/simple_animal/hostile/asteroid/basilisk/watcher/tendril)
|
||||
spawn_text = "emerges from"
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0)
|
||||
minbodytemp = 0
|
||||
@@ -73,7 +73,7 @@
|
||||
qdel(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/spawner/lavaland/goliath
|
||||
mob_type = /mob/living/simple_animal/hostile/asteroid/goliath/beast/tendril
|
||||
mob_types = list(/mob/living/simple_animal/hostile/asteroid/goliath/beast/tendril)
|
||||
|
||||
/mob/living/simple_animal/hostile/spawner/lavaland/legion
|
||||
mob_type = /mob/living/simple_animal/hostile/asteroid/hivelord/legion/tendril
|
||||
mob_types = list(/mob/living/simple_animal/hostile/asteroid/hivelord/legion/tendril)
|
||||
@@ -0,0 +1,111 @@
|
||||
/mob/living/simple_animal/hostile/netherworld
|
||||
name = "creature"
|
||||
desc = "A sanity-destroying otherthing from the netherworld."
|
||||
icon_state = "otherthing"
|
||||
icon_living = "otherthing"
|
||||
icon_dead = "otherthing-dead"
|
||||
health = 80
|
||||
maxHealth = 80
|
||||
obj_damage = 100
|
||||
melee_damage_lower = 25
|
||||
melee_damage_upper = 50
|
||||
attacktext = "slashes"
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
faction = list("creature")
|
||||
speak_emote = list("screams")
|
||||
gold_core_spawnable = CHEM_MOB_SPAWN_HOSTILE
|
||||
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)
|
||||
minbodytemp = 0
|
||||
faction = list("nether")
|
||||
|
||||
/mob/living/simple_animal/hostile/netherworld/migo
|
||||
name = "mi-go"
|
||||
desc = "A pinkish, fungoid crustacean-like creature with numerous pairs of clawed appendages and a head covered with waving antennae."
|
||||
speak_emote = list("screams", "clicks", "chitters", "barks", "moans", "growls", "meows", "reverberates", "roars", "squeaks", "rattles", "exclaims", "yells", "remarks", "mumbles", "jabbers", "stutters", "seethes")
|
||||
icon_state = "mi-go"
|
||||
icon_living = "mi-go"
|
||||
icon_dead = "mi-go-dead"
|
||||
attacktext = "lacerates"
|
||||
speed = -0.5
|
||||
var/static/list/migo_sounds
|
||||
deathmessage = "wails as its form turns into a pulpy mush."
|
||||
death_sound = 'sound/voice/hiss6.ogg'
|
||||
|
||||
/mob/living/simple_animal/hostile/netherworld/migo/Initialize()
|
||||
. = ..()
|
||||
migo_sounds = list('sound/items/bubblewrap.ogg', 'sound/items/change_jaws.ogg', 'sound/items/crowbar.ogg', 'sound/items/drink.ogg', 'sound/items/deconstruct.ogg', 'sound/items/change_drill.ogg', 'sound/items/dodgeball.ogg', 'sound/items/eatfood.ogg', 'sound/items/screwdriver.ogg', 'sound/items/weeoo1.ogg', 'sound/items/wirecutter.ogg', 'sound/items/welder.ogg', 'sound/items/zip.ogg', 'sound/items/rped.ogg', 'sound/items/ratchet.ogg', 'sound/items/polaroid1.ogg', 'sound/items/pshoom.ogg', 'sound/items/airhorn.ogg', 'sound/voice/bcreep.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/ed209_20sec.ogg', 'sound/voice/hiss3.ogg', 'sound/voice/hiss6.ogg', 'sound/voice/mpatchedup.ogg', 'sound/voice/mfeelbetter.ogg', 'sound/weapons/sear.ogg', 'sound/ambience/antag/tatoralert.ogg', 'sound/mecha/nominal.ogg', 'sound/mecha/weapdestr.ogg', 'sound/mecha/critdestr.ogg', 'sound/mecha/imag_enh.ogg', 'sound/effects/adminhelp.ogg', 'sound/effects/alert.ogg', 'sound/effects/attackblob.ogg', 'sound/effects/bamf.ogg', 'sound/effects/blobattack.ogg', 'sound/effects/break_stone.ogg', 'sound/effects/bubbles.ogg', 'sound/effects/bubbles2.ogg', 'sound/effects/clang.ogg', 'sound/effects/clownstep2.ogg', 'sound/effects/dimensional_rend.ogg', 'sound/effects/doorcreaky.ogg', 'sound/effects/empulse.ogg', 'sound/effects/explosionfar.ogg', 'sound/effects/explosion1.ogg', 'sound/effects/grillehit.ogg', 'sound/effects/genetics.ogg', 'sound/effects/heartbeat.ogg', 'sound/effects/hyperspace_begin.ogg', 'sound/effects/hyperspace_end.ogg', 'sound/goonstation/effects/screech.ogg', 'sound/effects/phasein.ogg', 'sound/effects/picaxe1.ogg', 'sound/effects/sparks1.ogg', 'sound/effects/smoke.ogg', 'sound/effects/splat.ogg', 'sound/effects/snap.ogg', 'sound/effects/tendril_destroyed.ogg', 'sound/effects/supermatter.ogg', 'sound/misc/desceration-01.ogg', 'sound/misc/desceration-02.ogg', 'sound/misc/desceration-03.ogg', 'sound/misc/bloblarm.ogg', 'sound/goonstation/misc/airraid_loop.ogg', 'sound/misc/interference.ogg', 'sound/misc/notice1.ogg', 'sound/misc/notice2.ogg', 'sound/misc/sadtrombone.ogg', 'sound/misc/slip.ogg', 'sound/weapons/armbomb.ogg', 'sound/weapons/chainsaw.ogg', 'sound/weapons/emitter.ogg', 'sound/weapons/emitter2.ogg', 'sound/weapons/blade1.ogg', 'sound/weapons/bladeslice.ogg', 'sound/weapons/blastcannon.ogg', 'sound/weapons/blaster.ogg', 'sound/weapons/bulletflyby3.ogg', 'sound/weapons/circsawhit.ogg', 'sound/weapons/cqchit2.ogg', 'sound/weapons/drill.ogg', 'sound/weapons/genhit1.ogg', 'sound/weapons/gunshots/gunshot_silenced.ogg', 'sound/weapons/gunshots/gunshot.ogg', 'sound/weapons/handcuffs.ogg', 'sound/weapons/homerun.ogg', 'sound/weapons/kenetic_accel.ogg', 'sound/machines/fryer/deep_fryer_emerge.ogg', 'sound/machines/airlock_alien_prying.ogg', 'sound/machines/airlock_close.ogg', 'sound/machines/airlockforced.ogg', 'sound/machines/airlock_open.ogg', 'sound/machines/alarm.ogg', 'sound/machines/blender.ogg', 'sound/machines/boltsdown.ogg', 'sound/machines/boltsup.ogg', 'sound/machines/buzz-sigh.ogg', 'sound/machines/buzz-two.ogg', 'sound/machines/chime.ogg', 'sound/machines/defib_charge.ogg', 'sound/machines/defib_failed.ogg', 'sound/machines/defib_ready.ogg', 'sound/machines/defib_zap.ogg', 'sound/machines/deniedbeep.ogg', 'sound/machines/ding.ogg', 'sound/machines/disposalflush.ogg', 'sound/machines/door_close.ogg', 'sound/machines/door_open.ogg', 'sound/machines/engine_alert1.ogg', 'sound/machines/engine_alert2.ogg', 'sound/machines/hiss.ogg', 'sound/machines/honkbot_evil_laugh.ogg', 'sound/machines/juicer.ogg', 'sound/machines/ping.ogg', 'sound/ambience/signal.ogg', 'sound/machines/synth_no.ogg', 'sound/machines/synth_yes.ogg', 'sound/machines/terminal_alert.ogg', 'sound/machines/twobeep.ogg', 'sound/machines/ventcrawl.ogg', 'sound/machines/warning-buzzer.ogg', 'sound/ai/outbreak5.ogg', 'sound/ai/outbreak7.ogg', 'sound/ai/poweroff.ogg', 'sound/ai/radiation.ogg', 'sound/ai/shuttlecalled.ogg', 'sound/ai/shuttledock.ogg', 'sound/ai/shuttlerecalled.ogg', 'sound/ai/aimalf.ogg') //hahahaha fuck you code divers
|
||||
|
||||
/mob/living/simple_animal/hostile/netherworld/migo/say(message, bubble_type, var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
|
||||
..()
|
||||
if(stat)
|
||||
return
|
||||
var/chosen_sound = pick(migo_sounds)
|
||||
playsound(src, chosen_sound, 50, TRUE)
|
||||
|
||||
/mob/living/simple_animal/hostile/netherworld/migo/Life()
|
||||
..()
|
||||
if(stat)
|
||||
return
|
||||
if(prob(10))
|
||||
var/chosen_sound = pick(migo_sounds)
|
||||
playsound(src, chosen_sound, 50, TRUE)
|
||||
|
||||
/mob/living/simple_animal/hostile/netherworld/blankbody
|
||||
name = "blank body"
|
||||
desc = "This looks human enough, but its flesh has an ashy texture, and it's face is featureless save an eerie smile."
|
||||
icon_state = "blank-body"
|
||||
icon_living = "blank-body"
|
||||
icon_dead = "blank-dead"
|
||||
gold_core_spawnable = CHEM_MOB_SPAWN_INVALID
|
||||
health = 100
|
||||
maxHealth = 100
|
||||
melee_damage_lower = 5
|
||||
melee_damage_upper = 10
|
||||
attacktext = "punches"
|
||||
deathmessage = "falls apart into a fine dust."
|
||||
|
||||
/mob/living/simple_animal/hostile/spawner/nether
|
||||
name = "netherworld link"
|
||||
desc = null //see examine()
|
||||
icon_state = "nether"
|
||||
health = 50
|
||||
spawn_time = 600 //1 minute
|
||||
max_mobs = 15
|
||||
icon = 'icons/mob/nest.dmi'
|
||||
spawn_text = "crawls through"
|
||||
mob_types = list(/mob/living/simple_animal/hostile/netherworld/migo, /mob/living/simple_animal/hostile/netherworld, /mob/living/simple_animal/hostile/netherworld/blankbody)
|
||||
faction = list("nether")
|
||||
|
||||
/mob/living/simple_animal/hostile/spawner/nether/Initialize()
|
||||
.=..()
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
|
||||
/mob/living/simple_animal/hostile/spawner/nether/examine(mob/user)
|
||||
..()
|
||||
if(isskeleton(user))
|
||||
to_chat(user, "A direct link to another dimension full of creatures very happy to see you. <span class='nicegreen'>You can see your house from here!</span>")
|
||||
else
|
||||
to_chat(user, "A direct link to another dimension full of creatures not very happy to see you. <span class='warning'>Entering the link would be a very bad idea.</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/spawner/nether/attack_hand(mob/user)
|
||||
. = ..()
|
||||
if(isskeleton(user))
|
||||
to_chat(user, "<span class='notice'>You don't feel like going home yet...</span>")
|
||||
else
|
||||
user.visible_message("<span class='warning'>[user] is violently pulled into the link!</span>", \
|
||||
"<span class='userdanger'>Touching the portal, you are quickly pulled through into a world of unimaginable horror!</span>")
|
||||
contents.Add(user)
|
||||
|
||||
/mob/living/simple_animal/hostile/spawner/nether/process()
|
||||
for(var/mob/living/M in contents)
|
||||
if(M)
|
||||
playsound(src, 'sound/magic/demon_consume.ogg', 50, 1)
|
||||
M.adjustBruteLoss(60)
|
||||
new /obj/effect/gibspawner/generic(get_turf(M), M)
|
||||
if(M.stat == DEAD)
|
||||
var/mob/living/simple_animal/hostile/netherworld/blankbody/blank
|
||||
blank = new(loc)
|
||||
blank.name = "[M]"
|
||||
blank.desc = "It's [M], but [M.p_their()] flesh has an ashy texture, and [M.p_their()] face is featureless save an eerie smile."
|
||||
visible_message("<span class='warning'>[M] reemerges from the link!</span>")
|
||||
qdel(M)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user