Tg 2 11 sync (#215)

* first series of updates

* datums

* games folder

* admin and atmosia stuffs

* moar

* mob updates borg riding

* sprites and stuff

* fixes for various things

* oops. some missed fixes
This commit is contained in:
Poojawa
2017-02-12 03:56:14 -06:00
committed by GitHub
parent 30b3dff395
commit 6674f9fc15
153 changed files with 1651 additions and 1368 deletions
+66 -39
View File
@@ -100,44 +100,6 @@
qdel(src)
//Luxury Shuttle Blockers
/obj/effect/forcefield/luxury_shuttle
var/threshhold = 500
var/list/approved_passengers = list()
/obj/effect/forcefield/luxury_shuttle/CanPass(atom/movable/mover, turf/target, height=0)
if(mover in approved_passengers)
return 1
if(!isliving(mover)) //No stowaways
return 0
var/total_cash = 0
var/list/counted_money = list()
for(var/obj/item/weapon/coin/C in mover)
total_cash += C.value
counted_money += C
if(total_cash >= threshhold)
break
for(var/obj/item/stack/spacecash/S in mover)
total_cash += S.value * S.amount
counted_money += S
if(total_cash >= threshhold)
break
if(total_cash >= threshhold)
for(var/obj/I in counted_money)
qdel(I)
mover << "Thank you for your payment! Please enjoy your flight."
approved_passengers += mover
return 1
else
mover << "You don't have enough money to enter the main shuttle. You'll have to fly coach."
return 0
//Shuttle Build
/obj/effect/shuttle_build
@@ -149,4 +111,69 @@
/obj/effect/shuttle_build/New()
SSshuttle.emergency.dock(SSshuttle.getDock("emergency_home"))
qdel(src)
qdel(src)
//Arena
/obj/effect/forcefield/arena_shuttle
name = "portal"
var/list/warp_points = list()
/obj/effect/forcefield/arena_shuttle/Bumped(mob/M as mob|obj)
if(!warp_points.len)
warp_points = get_area_turfs(/area/shuttle/escape)
for(var/turf/T in warp_points)
for(var/atom/movable/AM in T)
if(AM.density && AM.anchored)
warp_points -= T
break
if(!isliving(M))
return
else
var/mob/living/L = M
if(L.pulling && istype(L.pulling, /obj/item/bodypart/head))
L << "Your offering is accepted. You may pass."
qdel(L.pulling)
var/turf/LA = pick(warp_points)
L.forceMove(LA)
L.hallucination = 0
L << "<span class='reallybig redtext'>The battle is won. Your bloodlust subsides.</span>"
for(var/obj/item/weapon/twohanded/required/chainsaw/doomslayer/chainsaw in L)
qdel(chainsaw)
else
L << "You are not yet worthy of passing. Drag a severed head to the barrier to be allowed entry to the hall of champions."
/obj/effect/landmark/shuttle_arena_safe
name = "hall of champions"
desc = "For the winners."
/obj/effect/landmark/shuttle_arena_entrance
name = "the arena"
desc = "A lava filled battlefield."
/obj/effect/forcefield/arena_shuttle_entrance
name = "portal"
var/list/warp_points = list()
/obj/effect/forcefield/arena_shuttle_entrance/Bumped(mob/M as mob|obj)
if(!warp_points.len)
for(var/obj/effect/landmark/shuttle_arena_entrance/S in landmarks_list)
warp_points |= S
if(!isliving(M))
return
var/obj/effect/landmark/LA = pick(warp_points)
M.forceMove(get_turf(LA))
M << "<span class='reallybig redtext'>You're trapped in a deadly arena! To escape, you'll need to drag a severed head to the escape portals.</span>"
spawn()
var/obj/effect/mine/pickup/bloodbath/B = new(M)
B.mineEffect(M)
/area/shuttle_arena
name = "arena"
has_gravity = 1
requires_power = 0
+33 -3
View File
@@ -337,10 +337,40 @@
dat += "Time limit: <a href='?_src_=holder;alter_midround_time_limit=1'>[config.midround_antag_time_check] minutes into round</a><BR>"
dat += "Living crew limit: <a href='?_src_=holder;alter_midround_life_limit=1'>[config.midround_antag_life_check * 100]% of crew alive</a><BR>"
dat += "If limits past: <a href='?_src_=holder;toggle_noncontinuous_behavior=1'>[ticker.mode.round_ends_with_antag_death ? "End The Round" : "Continue As Extended"]</a><BR>"
dat += "<BR>"
dat += "<a href='?_src_=holder;end_round=\ref[usr]'>End Round Now</a><br>"
dat += "<a href='?_src_=holder;delay_round_end=1'>[ticker.delay_end ? "End Round Normally" : "Delay Round End"]</a><br>"
dat += "<a href='?_src_=holder;delay_round_end=1'>[ticker.delay_end ? "End Round Normally" : "Delay Round End"]</a>"
var/connected_players = clients.len
var/lobby_players = 0
var/observers = 0
var/observers_connected = 0
var/living_players = 0
var/living_players_connected = 0
var/living_players_antagonist = 0
var/other_players = 0
for(var/mob/M in mob_list)
if(M.ckey)
if(isnewplayer(M))
lobby_players++
continue
else if(M.stat != DEAD && M.mind && !isbrain(M))
living_players++
if(M.mind.special_role)
living_players_antagonist++
if(M.client)
living_players_connected++
else if((M.stat == DEAD )||(isobserver(M)))
observers++
if(M.client)
observers_connected++
else
other_players++
dat += "<BR><b><font color='blue' size='3'>Players:|[connected_players - lobby_players] ingame|[connected_players] connected|[lobby_players] lobby|</font></b>"
dat += "<BR><b><font color='green'>Living Players:|[living_players_connected] active|[living_players - living_players_connected] disconnected|[living_players_antagonist] antagonists|</font></b>"
dat += "<BR><b><font color='red'>Dead/Observing players:|[observers_connected] active|[observers - observers_connected] disconnected|</font></b>"
if(other_players)
dat += "<BR><span class='userdanger'>[other_players] players in invalid state or the statistics code is bugged!</span>"
dat += "<BR>"
if(ticker.mode.syndicates.len)
dat += "<br><table cellspacing=5><tr><td><B>Syndicates</B></td><td></td></tr>"
for(var/datum/mind/N in ticker.mode.syndicates)
+5 -5
View File
@@ -35,8 +35,8 @@
if(!timestamp)
timestamp = SQLtime()
if(!server)
if (config && config.server_name)
server = config.server_name
if (config && config.server_sql_name)
server = config.server_sql_name
server = sanitizeSQL(server)
if(isnull(secret))
switch(alert("Hide note from being viewed by players?", "Secret note?","Yes","No","Cancel"))
@@ -332,7 +332,7 @@ proc/get_message_output(type, target_ckey)
return
if("watchlist entry")
message_admins("<font color='red'><B>Notice: </B></font><font color='blue'>[key_name_admin(target_ckey)] is on the watchlist and has just connected - Reason: [text]</font>")
// send2irc_adminless_only("Watchlist", "[key_name(target_ckey)] is on the watchlist and has just connected - Reason: [text]")
send2irc_adminless_only("Watchlist", "[key_name(target_ckey)] is on the watchlist and has just connected - Reason: [text]")
if("memo")
output += "<span class='memo'>Memo by <span class='prefix'>[admin_ckey]</span> on [timestamp]"
if(editor_ckey)
@@ -352,8 +352,8 @@ proc/get_message_output(type, target_ckey)
var/notetext
notesfile >> notetext
var/server
if(config && config.server_name)
server = config.server_name
if(config && config.server_sql_name)
server = config.server_sql_name
var/regex/note = new("^(\\d{2}-\\w{3}-\\d{4}) \\| (.+) ~(\\w+)$", "i")
note.Find(notetext)
var/timestamp = note.group[1]
+91 -99
View File
@@ -1,4 +1,4 @@
/proc/keywords_lookup(msg)
/proc/keywords_lookup(msg,irc)
//This is a list of words which are ignored by the parser when comparing message contents for names. MUST BE IN LOWER CASE!
var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","alien","as", "i")
@@ -10,9 +10,11 @@
var/list/surnames = list()
var/list/forenames = list()
var/list/ckeys = list()
var/founds = ""
for(var/mob/M in mob_list)
var/list/indexing = list(M.real_name, M.name)
if(M.mind) indexing += M.mind.name
if(M.mind)
indexing += M.mind.name
for(var/string in indexing)
var/list/L = splittext(string, " ")
@@ -52,9 +54,19 @@
mobs_found += found
if(!ai_found && isAI(found))
ai_found = 1
msg += "[original_word]<font size='1' color='black'>(<A HREF='?_src_=holder;adminmoreinfo=\ref[found]'>?</A>|<A HREF='?_src_=holder;adminplayerobservefollow=\ref[found]'>F</A>)</font> "
var/is_antag = 0
if(found.mind && found.mind.special_role)
is_antag = 1
founds += "Name: [found.name]([found.real_name]) Ckey: [found.ckey] [is_antag ? "(Antag)" : null] "
msg += "[original_word]<font size='1' color='[is_antag ? "red" : "black"]'>(<A HREF='?_src_=holder;adminmoreinfo=\ref[found]'>?</A>|<A HREF='?_src_=holder;adminplayerobservefollow=\ref[found]'>F</A>)</font> "
continue
msg += "[original_word] "
if(irc)
if(founds == "")
return "Search Failed"
else
return founds
return msg
@@ -78,7 +90,20 @@
return
if(src.handle_spam_prevention(msg,MUTE_ADMINHELP))
return
var/ref_mob = "\ref[mob]"
//clean the input msg
if(!msg)
return
msg = sanitize(copytext(msg,1,MAX_MESSAGE_LEN))
if(!msg) return
var/original_msg = msg
msg = keywords_lookup(msg)
if(!mob)
return //this doesn't happen
var/ref_client = "\ref[src]"
for(var/datum/adminticket/T in admintickets)
if(T.permckey == src.ckey && T.resolved == "No")
@@ -87,7 +112,7 @@
if(T.admin == "N/A")
usr << "<b>Due to the fact your Adminhelp had no assigned admin, admins have been pinged.</b>"
message_admins("[src.ckey] has bumped their adminhelp #[T.ID], still no assigned admin!")
msg = "<span class='adminnotice'><b><font color=red>HELP: </font><A HREF='?priv_msg=[ckey];ahelp_reply=1'>[key_name(src)]</A> [ADMIN_QUE(mob)] [ADMIN_PP(mob)] [ADMIN_VV(mob)] [ADMIN_SM(mob)] [ADMIN_FLW(mob)] [ADMIN_TP(mob)] (<A HREF='?_src_=holder;rejectadminhelp=[ref_client]'>REJT</A>) (<A HREF='?_src_=holder;icissue=[ref_client]'>IC</A>) (<A HREF='?_src_=holder;resolve=[T.ID]'>R</a>):</b> [msg]</span>"
msg = "<span class='adminnotice'><b><font color=red>HELP: </font><A HREF='?priv_msg=[ckey];ahelp_reply=1'>[key_name(src)]</A> [ADMIN_QUE(mob)] [ADMIN_PP(mob)] [ADMIN_VV(mob)] [ADMIN_SM(mob)] [ADMIN_FLW(mob)] [ADMIN_TP(mob)] (<A HREF='?_src_=holder;rejectadminhelp=[ref_client]'>REJT</A>) (<A HREF='?_src_=holder;icissue=[ref_client]'>IC</A>) (<A HREF='?_src_=ticket;resolve=[T.ID]'>R</a>):</b> [msg]</span>"
for(var/client/X in admins)
if(X.prefs.toggles & SOUND_ADMINHELP)
X << 'sound/effects/adminhelp.ogg'
@@ -104,27 +129,10 @@
src.verbs -= /client/verb/adminhelp
adminhelptimerid = addtimer(CALLBACK(src, .proc/giveadminhelpverb), 1200, TIMER_STOPPABLE)
//clean the input msg
if(!msg) return
msg = sanitize(copytext(msg,1,MAX_MESSAGE_LEN))
if(!msg) return
var/original_msg = msg
msg = keywords_lookup(msg)
if(!mob) return //this doesn't happen
for(var/datum/adminticket/T in admintickets)
msg = "<span class='adminnotice'><b><font color=red>HELP: </font><A HREF='?priv_msg=[ckey];ahelp_reply=1'>[key_name(src)]</A> [ADMIN_QUE(mob)] [ADMIN_PP(mob)] [ADMIN_VV(mob)] [ADMIN_SM(mob)] [ADMIN_FLW(mob)] [ADMIN_TP(mob)] (<A HREF='?_src_=holder;rejectadminhelp=[ref_client]'>REJT</A>) (<A HREF='?_src_=holder;icissue=[ref_client]'>IC</A>) (<A HREF='?_src_=ticket;resolve=[T.ID]'>R</a>):</b> [msg]</span>"
createticket(src, msg, src.ckey, mob)
var/datum/adminticket/ticket
for(var/datum/adminticket/T in admintickets)
if(T.permckey == src.ckey)
ticket = T
msg = "<span class='adminnotice'><b><font color=red>ADMINHELP: </font><A HREF='?priv_msg=[ckey];ahelp_reply=1'>[key_name(src)]</A> (<A HREF='?_src_=holder;adminmoreinfo=[ref_mob]'>?</A>) (<A HREF='?_src_=holder;adminplayeropts=[ref_mob]'>PP</A>) (<A HREF='?_src_=vars;Vars=[ref_mob]'>VV</A>) (<A HREF='?_src_=holder;subtlemessage=[ref_mob]'>SM</A>) (<A HREF='?_src_=holder;traitor=[ref_mob]'>TP</A>) (<A HREF='?_src_=holder;adminplayerobservefollow=[ref_mob]'>FLW</A>) (<a href='?src=\ref[ticket];resolve=\ref[ticket]'>R</a>):</b> [msg]</span>"
//send this msg to all admins
for(var/client/X in admins)
@@ -138,88 +146,72 @@
src << "<span class='adminnotice'>PM to-<b>Admins</b>: [original_msg]</span>"
//send it to irc if nobody is on and tell us how many were on
var/admin_number_present = send2irc_admin_notice_handler("adminhelp", ckey, original_msg)
log_admin("ADMINHELP: [key_name(src)]: [original_msg] - heard by [admin_number_present] non-AFK admins who have +BAN.")
var/admin_number_present = send2admindiscord(ckey,original_msg)
log_admin("HELP: [key_name(src)]: [original_msg] - heard by [admin_number_present] non-AFK admins who have +BAN.")
if(admin_number_present <= 0)
src << "<span class='notice'>No active admins are online, your adminhelp was sent to the admin irc.</span>"
feedback_add_details("admin_verb","AH") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
return
/proc/calculate_admins(type, requiredflags = R_BAN)
var/admin_number_total = 0 //Total number of admins
var/admin_number_afk = 0 //Holds the number of admins who are afk
var/admin_number_ignored = 0 //Holds the number of admins without +BAN (so admins who are not really admins)
var/admin_number_decrease = 0 //Holds the number of admins with are afk, ignored or both
/proc/get_admin_counts(requiredflags = R_BAN)
. = list("total" = list(), "noflags" = list(), "afk" = list(), "stealth" = list(), "present" = list())
for(var/client/X in admins)
admin_number_total++;
var/invalid = 0
.["total"] += X
if(requiredflags != 0 && !check_rights_for(X, requiredflags))
admin_number_ignored++
invalid = 1
if(X.is_afk())
admin_number_afk++
invalid = 1
if(X.holder.fakekey)
admin_number_ignored++
invalid = 1
if(invalid)
admin_number_decrease++
switch(type)
if("ignored")
return admin_number_ignored
if("total")
return admin_number_total
if("away")
return admin_number_afk
if("present")
return admin_number_total - admin_number_decrease
return 0
.["noflags"] += X
else if(X.is_afk())
.["afk"] += X
else if(X.holder.fakekey)
.["stealth"] += X
else
.["present"] += X
/proc/send2irc_adminless_only(source, msg, requiredflags = R_BAN)
var/list/adm = get_admin_counts(requiredflags)
var/list/activemins = adm["present"]
. = activemins.len
if(. <= 0)
var/final = ""
var/list/afkmins = adm["afk"]
var/list/stealthmins = adm["stealth"]
var/list/powerlessmins = adm["noflags"]
var/list/allmins = adm["total"]
if(!afkmins.len && !stealthmins.len && !powerlessmins.len)
final = "[msg] - No admins online"
else
final = "[msg] - All admins stealthed\[[english_list(stealthmins)]\], AFK\[[english_list(afkmins)]\], or lacks +BAN\[[english_list(powerlessmins)]\]! Total: [allmins.len] "
send2irc(source,final)
send2admindiscord(source,final)
/proc/send2irc_admin_notice_handler(type, source, msg)
var/afk_admins = calculate_admins("away")
var/total_admins = calculate_admins("total")
var/ignored_admins = calculate_admins("ignored")
var/admin_number_present = calculate_admins("present") //Number of admins who are neither afk nor invalid
var/irc_message_afk = "[msg] - All admins AFK ([afk_admins]/[total_admins]) or skipped ([ignored_admins]/[total_admins])"
var/irc_message_normal = "[msg] - heard by [admin_number_present] non-AFK admins who have +BAN."
var/irc_message_adminless = "[msg] - No admins online"
switch(type)
if("adminhelp")
if(config.announce_adminhelps)
send2irc(source, irc_message_normal)
else
if(admin_number_present <= 0)
if(!afk_admins && !ignored_admins)
send2admindiscord(source, irc_message_adminless)
else if(afk_admins >= 1)
send2admindiscord(source, irc_message_afk)
else
send2admindiscord(source, irc_message_normal)
if("watchlist")
if(config.announce_watchlist)
send2irc(source, irc_message_normal)
else
if(admin_number_present <= 0)
if(!afk_admins && !ignored_admins)
send2admindiscord(source, irc_message_adminless)
else if(afk_admins >= 1)
send2admindiscord(source, irc_message_afk)
else
send2admindiscord(source, irc_message_normal)
if("new_player")
if(config.irc_first_connection_alert)
send2irc(source, irc_message_normal)
else
if(admin_number_present <= 0)
if(!afk_admins && !ignored_admins)
send2admindiscord(source, irc_message_adminless)
else if(afk_admins >= 1)
send2admindiscord(source, irc_message_afk)
else
send2admindiscord(source, irc_message_normal)
return admin_number_present
/proc/send2irc(msg,msg2)
if(config.useircbot)
shell("python nudge.py [msg] \"[msg2]\"")
return
shell("python nudge.py [msg] [msg2]")
return
/proc/send2otherserver(source,msg,type = "Ahelp")
if(global.cross_allowed)
var/list/message = list()
message["message_sender"] = source
message["message"] = msg
message["source"] = "([config.cross_name])"
message["key"] = global.comms_key
message["crossmessage"] = type
world.Export("[global.cross_address]?[list2params(message)]")
/proc/ircadminwho()
var/list/message = list("Admins: ")
var/list/admin_keys = list()
for(var/adm in admins)
var/client/C = adm
admin_keys += "[C][C.holder.fakekey ? "(Stealth)" : ""][C.is_afk() ? "(AFK)" : ""]"
for(var/admin in admin_keys)
if(LAZYLEN(admin_keys) > 1)
message += ", [admin]"
else
message += "[admin]"
return jointext(message, "")
+57 -7
View File
@@ -1,3 +1,5 @@
#define IRCREPLYCOUNT 2
//allows right clicking mobs to send an admin PM to their client, forwards the selected mob's client to cmd_admin_pm
/client/proc/cmd_admin_pm_context(mob/M in mob_list)
set category = null
@@ -5,7 +7,8 @@
if(!holder)
src << "<font color='red'>Error: Admin-PM-Context: Only administrators may use this command.</font>"
return
if( !ismob(M) || !M.client ) return
if( !ismob(M) || !M.client )
return
cmd_admin_pm(M.client,null)
feedback_add_details("admin_verb","APMM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -19,16 +22,15 @@
var/list/client/targets[0]
for(var/client/T)
if(T.mob)
if(istype(T.mob, /mob/new_player))
if(isnewplayer(T.mob))
targets["(New Player) - [T]"] = T
else if(istype(T.mob, /mob/dead/observer))
else if(isobserver(T.mob))
targets["[T.mob.name](Ghost) - [T]"] = T
else
targets["[T.mob.real_name](as [T.mob.name]) - [T]"] = T
else
targets["(No Mob) - [T]"] = T
var/list/sorted = sortList(targets)
var/target = input(src,"To whom shall we send a message?","Admin PM",null) in sorted|null
var/target = input(src,"To whom shall we send a message?","Admin PM",null) as null|anything in sortList(targets)
cmd_admin_pm(targets[target],null)
feedback_add_details("admin_verb","APM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -44,7 +46,8 @@
else if(istype(whom,/client))
C = whom
if(!C)
if(holder) src << "<font color='red'>Error: Admin-PM: Client not found.</font>"
if(holder)
src << "<font color='red'>Error: Admin-PM: Client not found.</font>"
return
var/datum/adminticket/ticket
@@ -205,4 +208,51 @@
//we don't use message_admins here because the sender/receiver might get it too
for(var/client/X in admins)
if(X.key!=key && X.key!=C.key) //check client/X is an admin and isn't the sender or recipient
X << "<B><font color='blue'>PM: [key_name(src, X, 0)]-&gt;[key_name(C, X, 0)]:</B> \blue [keywordparsedmsg]</font>" //inform X
X << "<B><font color='blue'>PM: [key_name(src, X, 0)]-&gt;[key_name(C, X, 0)]:</B> \blue [keywordparsedmsg]</font>" //inform X
/proc/IrcPm(target,msg,sender)
var/client/C = directory[target]
var/static/stealthkey
var/adminname = config.showircname ? "[sender](IRC)" : "Administrator"
if(!C)
return "No client"
if(!stealthkey)
stealthkey = GenIrcStealthKey()
msg = sanitize(copytext(msg,1,MAX_MESSAGE_LEN))
if(!msg)
return "No message"
message_admins("IRC message from [sender] to [key_name_admin(C)] : [msg]")
log_admin("IRC PM: [sender] -> [key_name(C)] : [msg]")
msg = emoji_parse(msg)
C << "<font color='red' size='4'><b>-- Administrator private message --</b></font>"
C << "<font color='red'>Admin PM from-<b><a href='?priv_msg=[stealthkey]'>[adminname]</A></b>: [msg]</font>"
C << "<font color='red'><i>Click on the administrator's name to reply.</i></font>"
window_flash(C)
//always play non-admin recipients the adminhelp sound
C << 'sound/effects/adminhelp.ogg'
C.ircreplyamount = IRCREPLYCOUNT
return "Message Successful"
/proc/GenIrcStealthKey()
var/num = (rand(0,1000))
var/i = 0
while(i == 0)
i = 1
for(var/P in stealthminID)
if(num == stealthminID[P])
num++
i = 0
var/stealth = "@[num2text(num)]"
stealthminID["IRCKEY"] = stealth
return stealth
#undef IRCREPLYCOUNT
+9 -6
View File
@@ -118,16 +118,19 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
if(isnull(argnum))
return
var/list/lst = list()
. = list()
var/list/named_args = list()
while(argnum--)
var/named_arg = input("Leave blank for positional argument. Positional arguments will be considered as if they were added first.", "Named argument") as text|null
var/value = vv_get_value(restricted_classes = list(VV_RESTORE_DEFAULT))
if (!value["class"])
return
lst += value["value"]
return lst
if(named_arg)
named_args[named_arg] = value["value"]
else
. += value["value"]
if(LAZYLEN(named_args))
. += named_args
/client/proc/get_callproc_returnval(returnval,procname)
. = ""
@@ -35,11 +35,11 @@
var/list/atmos_overlay_types //gas IDs of current active gas overlays
/turf/open/New()
..()
/turf/open/Initialize()
if(!blocks_air)
air = new
air.copy_from_turf(src)
..()
/turf/open/Destroy()
if(active_hotspot)
@@ -113,11 +113,12 @@
/turf/open/proc/tile_graphic()
. = new /list
var/list/gases = air.gases
for(var/id in gases)
var/gas = gases[id]
if(gas[GAS_META][META_GAS_OVERLAY] && gas[MOLES] > gas[GAS_META][META_GAS_MOLES_VISIBLE])
. += gas[GAS_META][META_GAS_OVERLAY]
if(air)
var/list/gases = air.gases
for(var/id in gases)
var/gas = gases[id]
if(gas[GAS_META][META_GAS_OVERLAY] && gas[MOLES] > gas[GAS_META][META_GAS_MOLES_VISIBLE])
. += gas[GAS_META][META_GAS_OVERLAY]
/////////////////////////////SIMULATION///////////////////////////////////
+21 -19
View File
@@ -99,26 +99,28 @@
flags_cover = MASKCOVERSEYES
resistance_flags = FLAMMABLE
actions_types = list(/datum/action/item_action/adjust)
/obj/item/clothing/mask/gas/mime/attack_self(mob/user)
cycle_mask(user)
/obj/item/clothing/mask/gas/mime/ui_action_click(mob/user)
if(!istype(user) || user.incapacitated())
return
/obj/item/clothing/mask/gas/mime/proc/cycle_mask(mob/user)
switch(icon_state)
if("mime")
icon_state = "sadmime"
if("sadmime")
icon_state = "scaredmime"
if("scaredmime")
icon_state = "sexymime"
if("sexymime")
icon_state = "mime"
user.update_inv_wear_mask()
for(var/X in actions)
var/datum/action/A = X
A.UpdateButtonIcon()
user << "<span class='notice'>You adjust your mask to portray a different emotion.</span>"
return 1
var/list/options = list()
options["Blanc"] = "mime"
options["Triste"] = "sadmime"
options["Effrayé"] = "scaredmime"
options["Excité"] ="sexymime"
var/choice = input(user,"To what form do you wish to Morph this mask?","Morph Mask") in options
if(src && choice && !user.incapacitated() && in_range(user,src))
icon_state = options[choice]
user.update_inv_wear_mask()
for(var/X in actions)
var/datum/action/A = X
A.UpdateButtonIcon()
user << "<span class='notice'>Your Mime Mask has now morphed into [choice]!</span>"
return 1
/obj/item/clothing/mask/gas/monkeymask
name = "monkey mask"
@@ -170,6 +172,7 @@
resistance_flags = FLAMMABLE
obj_integrity = 100
max_integrity = 100
actions_types = list(/datum/action/item_action/adjust)
dog_fashion = null
@@ -186,7 +189,6 @@ obj/item/clothing/mask/gas/tiki_mask/ui_action_click(mob/user)
if(src && choice && !M.stat && in_range(M,src))
icon_state = options[choice]
item_state = options[choice]
user.update_inv_wear_mask()
for(var/X in actions)
var/datum/action/A = X
+7 -7
View File
@@ -268,6 +268,11 @@
/obj/item/clothing/suit/armor/reactive/tesla
name = "reactive tesla armor"
desc = "An experimental suit of armor with sensitive detectors hooked up to a huge capacitor grid, with emitters strutting out of it. Zap."
siemens_coefficient = -1
var/tesla_power = 25000
var/tesla_range = 20
var/tesla_boom = FALSE
var/tesla_stun = FALSE
/obj/item/clothing/suit/armor/reactive/tesla/hit_reaction(mob/living/carbon/human/owner, attack_text)
if(!active)
@@ -277,15 +282,10 @@
var/datum/effect_system/spark_spread/sparks = new /datum/effect_system/spark_spread
sparks.set_up(1, 1, src)
sparks.start()
owner.visible_message("<span class='danger'>The tesla capacitors on [owner]'s reactive telsa armor are still recharging! The armor merely emits some sparks.</spawn>")
owner.visible_message("<span class='danger'>The tesla capacitors on [owner]'s reactive tesla armor are still recharging! The armor merely emits some sparks.</spawn>")
return
owner.visible_message("<span class='danger'>The [src] blocks the [attack_text], sending out arcs of lightning!</span>")
for(var/mob/living/M in view(6, owner))
if(M == owner)
continue
owner.Beam(M,icon_state="lightning[rand(1, 12)]",time=5)
M.adjustFireLoss(25)
playsound(M, 'sound/machines/defib_zap.ogg', 50, 1, -1)
tesla_zap(owner,tesla_range,tesla_power,tesla_boom, tesla_stun)
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
return 1
+33 -15
View File
@@ -3,9 +3,12 @@
typepath = /datum/round_event/ghost_role/sentience
weight = 10
/datum/round_event/ghost_role/sentience
minimum_required = 1
role_name = "random animal"
var/animals = 1
var/one = "one"
/datum/round_event/ghost_role/sentience/start()
var/sentience_report = "<font size=3><b>[command_name()] Medium-Priority Update</b></font>"
@@ -14,7 +17,7 @@
var/pets = pick("animals/bots", "bots/animals", "pets", "simple animals", "lesser lifeforms", "\[REDACTED\]")
var/strength = pick("human", "moderate", "lizard", "security", "command", "clown", "low", "very low", "\[REDACTED\]")
sentience_report += "<br><br>Based on [data], we believe that one of the station's [pets] has developed [strength] level intelligence, and the ability to communicate."
sentience_report += "<br><br>Based on [data], we believe that [one] of the station's [pets] has developed [strength] level intelligence, and the ability to communicate."
print_command_report(sentience_report, "Classified [command_name()] Update")
priority_announce("A report has been downloaded and printed out at all communications consoles.", "Incoming Classified Message", 'sound/AI/commandreport.ogg')
@@ -36,25 +39,40 @@
if(!potential.len)
return WAITING_FOR_SOMETHING
var/mob/living/simple_animal/SA = pick(potential)
if(!candidates.len)
return NOT_ENOUGH_PLAYERS
var/mob/dead/observer/SG = pick(candidates)
SA.key = SG.key
SA.languages_spoken |= HUMAN
SA.languages_understood |= HUMAN
SA.sentience_act()
var/spawned_animals = 0
while(spawned_animals < animals && candidates.len && potential.len)
var/mob/living/simple_animal/SA = pick_n_take(potential)
var/mob/dead/observer/SG = pick_n_take(candidates)
SA.maxHealth = max(SA.maxHealth, 200)
SA.health = SA.maxHealth
SA.del_on_death = FALSE
spawned_animals++
spawned_mobs += SA
SA.key = SG.key
SA.languages_spoken |= HUMAN
SA.languages_understood |= HUMAN
SA.sentience_act()
SA << "<span class='userdanger'>Hello world!</span>"
SA << "<span class='warning'>Due to freak radiation and/or chemicals \
and/or lucky chance, you have gained human level intelligence \
and the ability to speak and understand human language!</span>"
SA.maxHealth = max(SA.maxHealth, 200)
SA.health = SA.maxHealth
SA.del_on_death = FALSE
spawned_mobs += SA
SA << "<span class='userdanger'>Hello world!</span>"
SA << "<span class='warning'>Due to freak radiation and/or chemicals \
and/or lucky chance, you have gained human level intelligence \
and the ability to speak and understand human language!</span>"
return SUCCESSFUL_SPAWN
/datum/round_event_control/sentience/all
name = "Station-wide Human-level Intelligence"
typepath = /datum/round_event/ghost_role/sentience/all
weight = 0
/datum/round_event/ghost_role/sentience/all
one = "all"
animals = INFINITY // as many as there are ghosts and animals
// cockroach pride, station wide
@@ -124,6 +124,12 @@
list_reagents = list("sodiumchloride" = 20)
possible_states = list()
/obj/item/weapon/reagent_containers/food/condiment/saltshaker/on_reagent_change()
if(reagents.reagent_list.len == 0)
icon_state = "emptyshaker"
else
icon_state = "saltshakersmall"
/obj/item/weapon/reagent_containers/food/condiment/saltshaker/suicide_act(mob/user)
user.visible_message("<span class='suicide'>[user] begins to swap forms with the salt shaker! It looks like [user.p_theyre()] trying to commit suicide!</span>")
var/newname = "[name]"
@@ -156,6 +162,12 @@
list_reagents = list("blackpepper" = 20)
possible_states = list()
/obj/item/weapon/reagent_containers/food/condiment/peppermill/on_reagent_change()
if(reagents.reagent_list.len == 0)
icon_state = "emptyshaker"
else
icon_state = "peppermillsmall"
/obj/item/weapon/reagent_containers/food/condiment/milk
name = "space milk"
desc = "It's milk. White and nutritious goodness!"
@@ -18,6 +18,15 @@ insert ascii eagle on american flag background here
container_type = OPENCONTAINER
var/obj/item/frying = null //What's being fried RIGHT NOW?
var/cook_time = 0
var/static/list/blacklisted_items = typecacheof(list(
/obj/item/weapon/screwdriver,
/obj/item/weapon/crowbar,
/obj/item/weapon/wrench,
/obj/item/weapon/wirecutters,
/obj/item/device/multitool,
/obj/item/weapon/weldingtool,
/obj/item/weapon/reagent_containers/glass,
/obj/item/weapon/storage/part_replacer))
/obj/item/weapon/circuitboard/machine/deep_fryer
name = "circuit board (Deep Fryer)"
@@ -46,8 +55,16 @@ insert ascii eagle on american flag background here
if(istype(I, /obj/item/weapon/reagent_containers/food/snacks/deepfryholder))
user << "<span class='userdanger'>Your cooking skills are not up to the legendary Doublefry technique.</span>"
return
if(default_unfasten_wrench(user, I))
return
else if(exchange_parts(user, I))
return
else if(default_deconstruction_screwdriver(user, "fryer_off", "fryer_off" ,I)) //where's the open maint panel icon?!
return
else
if(user.drop_item() && !frying)
if(is_type_in_typecache(I, blacklisted_items))
. = ..()
else if(user.drop_item() && !frying)
user << "<span class='notice'>You put [I] into [src].</span>"
frying = I
frying.forceMove(src)
@@ -78,6 +95,7 @@ insert ascii eagle on american flag background here
S.overlays = frying.overlays
S.icon_state = frying.icon_state
S.desc = frying.desc
S.w_class = frying.w_class
reagents.trans_to(S, 2*(cook_time/15))
switch(cook_time)
if(0 to 15)
+1 -1
View File
@@ -110,7 +110,7 @@
if(V == "air")
var/turf/open/O1 = B
var/turf/open/O2 = T
O1.air.copy_from(O2.air)
O1.air.copy_from(O2.return_air())
continue
B.vars[V] = T.vars[V]
toupdate += B
+19 -19
View File
@@ -64,25 +64,25 @@
..()
/obj/machinery/computer/holodeck/Initialize(mapload)
..()
if(!mapload && ticker.current_state < GAME_STATE_PLAYING)
return
program_cache = list()
emag_programs = list()
for(var/typekey in subtypesof(program_type))
var/area/holodeck/A = locate(typekey)
if(!A || A == offline_program) continue
if(A.contents.len == 0) continue // not loaded
if(A.restricted)
emag_programs += A
else
program_cache += A
if(typekey == init_program)
load_program(A,force=1)
if(random_program && program_cache.len && init_program == null)
load_program(pick(program_cache),force=1)
else if(!program)
load_program(offline_program)
. = mapload //late-initialize, area_copy need turfs to have air
if(!mapload)
..()
program_cache = list()
emag_programs = list()
for(var/typekey in subtypesof(program_type))
var/area/holodeck/A = locate(typekey)
if(!A || A == offline_program) continue
if(A.contents.len == 0) continue // not loaded
if(A.restricted)
emag_programs += A
else
program_cache += A
if(typekey == init_program)
load_program(A,force=1)
if(random_program && program_cache.len && init_program == null)
load_program(pick(program_cache),force=1)
else if(!program)
load_program(offline_program)
/obj/machinery/computer/holodeck/power_change()
..()
+6 -6
View File
@@ -42,7 +42,7 @@
name = "asteroid"
icon_state = "asteroid0"
/turf/open/floor/holofloor/asteroid/New()
/turf/open/floor/holofloor/asteroid/Initialize()
icon_state = "asteroid[pick(0,1,2,3,4,5,6,7,8,9,10,11,12)]"
..()
@@ -50,7 +50,7 @@
name = "basalt"
icon_state = "basalt0"
/turf/open/floor/holofloor/basalt/New()
/turf/open/floor/holofloor/basalt/Initialize()
icon_state = "basalt[pick(0,1,2,3,4,5,6,7,8,9,10,11,12)]"
..()
@@ -59,7 +59,7 @@
icon = 'icons/turf/space.dmi'
icon_state = "0"
/turf/open/floor/holofloor/space/New()
/turf/open/floor/holofloor/space/Initialize()
icon_state = SPACE_ICON_STATE // so realistic
..()
@@ -68,11 +68,11 @@
icon = 'icons/turf/space.dmi'
icon_state = "speedspace_ns_1"
/turf/open/floor/holofloor/hyperspace/New()
/turf/open/floor/holofloor/hyperspace/Initialize()
icon_state = "speedspace_ns_[(x + 5*y + (y%2+1)*7)%15+1]"
..()
/turf/open/floor/holofloor/hyperspace/ns/New()
/turf/open/floor/holofloor/hyperspace/ns/Initialize()
..()
icon_state = "speedspace_ns_[(x + 5*y + (y%2+1)*7)%15+1]"
@@ -86,7 +86,7 @@
smooth = SMOOTH_TRUE
canSmoothWith = null
/turf/open/floor/holofloor/carpet/New()
/turf/open/floor/holofloor/carpet/Initialize()
..()
addtimer(CALLBACK(src, .proc/update_icon), 1)
+63 -95
View File
@@ -1,40 +1,22 @@
#define SOAPSTONE_PREFIX_FILE "strings/soapstone_prefixes.txt"
#define SOAPSTONE_SUFFIX_FILE "soapstone_suffixes.json"
//Vocabulary lists; soapstones use a prefix and a suffix. Optionally, they can have a prefix and suffix, then a conjunction that links another set.
var/global/list/soapstone_prefixes = list() //Read from "strings/soapstone_prefixes.txt"; if you're adding your own, put **** where the subject should be!
var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffixes.json"
/obj/item/soapstone
name = "chisel"
desc = "Leave \"informative\" messages for the crew, including the crew of future shifts!\n\
(Not suitable for engraving on shuttles, off station or on cats. Side effects may include beatings, bannings and orbital bombardment.)"
desc = "Leave informative messages for the crew, including the crew of future shifts!\nEven if out of uses, it can still be used to remove messages.\n(Not suitable for engraving on shuttles, off station or on cats. Side effects may include beatings, bannings and orbital bombardment.)"
icon = 'icons/obj/items.dmi'
icon_state = "soapstone"
throw_speed = 3
throw_range = 5
w_class = WEIGHT_CLASS_TINY
var/tool_speed = 50
var/remaining_uses = 3
var/non_dull_name
var/w_engrave = "engrave"
var/w_engraving = "engraving"
var/w_chipping = "chipping"
var/w_dull = "dull"
/obj/item/soapstone/New()
. = ..()
if(!soapstone_prefixes.len)
soapstone_prefixes = file2list(SOAPSTONE_PREFIX_FILE, "\n")
if(!soapstone_suffixes.len)
soapstone_suffixes = list(\
"Characters" = strings(SOAPSTONE_SUFFIX_FILE, "Characters"), \
"Careers" = strings(SOAPSTONE_SUFFIX_FILE, "Careers"), \
"Antagonists" = strings(SOAPSTONE_SUFFIX_FILE, "Antagonists"), \
"Objects" = strings(SOAPSTONE_SUFFIX_FILE, "Objects"), \
"Techniques" = strings(SOAPSTONE_SUFFIX_FILE, "Techniques"), \
"Actions" = strings(SOAPSTONE_SUFFIX_FILE, "Actions"), \
"Geography" = strings(SOAPSTONE_SUFFIX_FILE, "Geography"), \
"Orientation" = strings(SOAPSTONE_SUFFIX_FILE, "Orientation"), \
"Body parts" = strings(SOAPSTONE_SUFFIX_FILE, "Body parts"), \
"Concepts" = strings(SOAPSTONE_SUFFIX_FILE, "Concepts"), \
"Musings" = strings(SOAPSTONE_SUFFIX_FILE, "Musings"), \
)
random_name()
check_name() // could start empty
@@ -43,6 +25,9 @@ var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffi
non_dull_name = name
if(name == "chalk" || name == "magic marker")
desc = replacetext(desc, "engraving", "scribbling")
w_engrave = "scribble"
w_engraving = "scribbling"
w_chipping = "sketching"
if(name == "chalk")
w_dull = "used"
if(name == "magic marker")
@@ -50,6 +35,9 @@ var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffi
if(name == "soapstone" || name == "chisel")
desc = replacetext(desc, "scribbling", "engraving")
w_engrave = initial(w_engrave)
w_engraving = initial(w_engraving)
w_chipping = initial(w_chipping)
w_dull = "dull"
/obj/item/soapstone/examine(mob/user)
@@ -60,48 +48,59 @@ var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffi
user << "It looks like it can be used an unlimited number of times."
/obj/item/soapstone/afterattack(atom/target, mob/user, proximity)
if(!remaining_uses)
user << "<span class='warning'>[src] is [w_dull] and can't be used anymore!</span>"
return
var/turf/T = get_turf(target)
if(!proximity)
return
var/obj/structure/chisel_message/msg = locate() in T
if(msg)
if(msg.creator_key != user.ckey)
user << "<span class='warning'>There's already a message there!</span>"
return
else
if(alert(user, "Erase this message?", name, "Yes", "No") == "Yes")
user.visible_message("<span class='notice'>[user] erases [msg].</span>", "<span class='notice'>You permanently erase [msg].</span>")
playsound(T, 'sound/items/gavel.ogg', 50, 1)
refund_use()
msg.persists = 0
qdel(msg)
return
return
var/obj/structure/chisel_message/already_message = locate(/obj/structure/chisel_message) in T
var/our_message = FALSE
if(already_message)
our_message = already_message.creator_key == user.ckey
if(!remaining_uses && !already_message)
// The dull chisel is dull.
user << "<span class='warning'>[src] is [w_dull].</span>"
return
if(!good_chisel_message_location(T))
user << "<span class='warning'>You can't write there!</span>"
user << "<span class='warning'>It's not appropriate to [w_engrave] on [T].</span>"
return
var/prefix = input(user, "Choose a prefix for your message.", name) as null|anything in soapstone_prefixes
if(!prefix)
if(already_message)
user.visible_message("<span class='notice'>[user] starts erasing [already_message].</span>", "<span class='notice'>You start erasing [already_message].</span>", "<span class='italics'>You hear a [w_chipping] sound.</span>")
playsound(loc, 'sound/items/gavel.ogg', 50, 1, -1)
// Removing our own messages refunds a charge
if(do_after(user, tool_speed, target=target))
user.visible_message("<span class='notice'>[user] has erased [already_message].</span>", "<span class='notice'>You erased [already_message].</span>")
already_message.persists = FALSE
qdel(already_message)
playsound(loc, 'sound/items/gavel.ogg', 50, 1, -1)
if(our_message)
refund_use()
return
var/suffix_category_string = input(user, "Choose a suffix category.", "[prefix]...") as null|anything in soapstone_suffixes
var/list/suffix_category = soapstone_suffixes[suffix_category_string]
if(!suffix_category || !suffix_category.len)
var/message = stripped_input(user, "What would you like to [w_engrave]?", "[name] Message")
if(!message)
user << "You decide not to [w_engrave] anything."
return
var/suffix = input(user, "Choose a suffix.", "[prefix]...") as null|anything in suffix_category
if(!suffix)
if(!target.Adjacent(user) && locate(/obj/structure/chisel_message) in T)
user << "You decide not to [w_engrave] anything."
return
var/processed_message = replacetext(prefix, "****", suffix)
if(!user.Adjacent(T) || !good_chisel_message_location(T) || locate(/obj/structure/chisel_message) in T)
return
user.visible_message("<span class='notice'>[user] writes a message onto [T]!</span>", "<span class='notice'>You write a message onto [T].</span>")
playsound(T, 'sound/items/gavel.ogg', 50, 1)
var/obj/structure/chisel_message/M = new(T)
M.register(user, processed_message)
remove_use()
return 1
playsound(loc, 'sound/items/gavel.ogg', 50, 1, -1)
user.visible_message("<span class='notice'>[user] starts [w_engraving] a message into [T].</span>", "You start [w_engraving] a message into [T].", "<span class='italics'>You hear a [w_chipping] sound.</span>")
if(can_use() && do_after(user, tool_speed, target=T) && can_use())
if(!locate(/obj/structure/chisel_message in T))
user << "You [w_engrave] a message into [T]."
playsound(loc, 'sound/items/gavel.ogg', 50, 1, -1)
var/obj/structure/chisel_message/M = new(T)
M.register(user, message)
remove_use()
/obj/item/soapstone/proc/can_use()
if(remaining_uses == -1 || remaining_uses >= 0)
@@ -172,34 +171,6 @@ var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffi
var/map
var/persists = TRUE
var/positive_ratings = 0
var/negative_ratings = 0
var/list/raters = list() //Ckeys who have rated this message
/obj/structure/chisel_message/attack_hand(mob/user)
if(user.ckey == creator_key)
user << "<span class='warning'>You can't rate your own messages!</span>"
return
if(raters[user.ckey])
user << "<span class='warning'>You've already rated this message!</span>"
return
switch(alert(user, "How would you like to rate this message?", "Message Rating", "Positive", "Negative", "Cancel"))
if("Positive")
for(var/client/C in clients)
if(C.ckey == creator_key)
C.mob << "<span class='notice'>One of your messages was rated as positive!</span>"
user << "<span class='noticealien'>You rated this message as positive.</span>"
positive_ratings++
raters[user.ckey] = "positive"
if("Negative")
for(var/client/C in clients)
if(C.ckey == creator_key)
C.mob << "<span class='danger'>One of your messages was rated as negative!</span>"
user << "<span class='danger'>You rated this message as negative.</span>"
negative_ratings++
raters[user.ckey] = "negative"
/obj/structure/chisel_message/New(newloc)
..()
SSpersistence.chisel_messages += src
@@ -219,6 +190,12 @@ var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffi
map = MAP_NAME
update_icon()
/obj/structure/chisel_message/update_icon()
..()
var/hash = md5(hidden_message)
var/newcolor = copytext(hash, 1, 7)
add_atom_colour("#[newcolor]", FIXED_COLOUR_PRIORITY)
/obj/structure/chisel_message/proc/pack()
var/list/data = list()
data["hidden_message"] = hidden_message
@@ -229,9 +206,6 @@ var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffi
var/turf/T = get_turf(src)
data["x"] = T.x
data["y"] = T.y
data["pos_ratings"] = positive_ratings
data["neg_ratings"] = positive_ratings
data["raters"] = raters
return data
/obj/structure/chisel_message/proc/unpack(list/data)
@@ -239,9 +213,6 @@ var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffi
creator_name = data["creator_name"]
creator_key = data["creator_key"]
realdate = data["realdate"]
positive_ratings = data["pos_ratings"]
negative_ratings = data["neg_ratings"]
raters = data["raters"]
var/x = data["x"]
var/y = data["y"]
@@ -251,10 +222,7 @@ var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffi
/obj/structure/chisel_message/examine(mob/user)
..()
user << "<span class='notice'>[hidden_message]</span>"
user << "Ratings: <span class='noticealien'>[positive_ratings]</span> <span class='danger'>[negative_ratings]</span>"
if(raters[user.ckey])
user << "<i>You rated this message as [raters[user.ckey]].</i>"
user << "<span class='warning'>[hidden_message]</span>"
/obj/structure/chisel_message/Destroy()
if(persists)
+17 -25
View File
@@ -91,20 +91,29 @@
return 1
return ..()
/mob/living/carbon/throw_impact(atom/hit_atom)
/mob/living/carbon/throw_impact(atom/hit_atom, throwingdatum)
. = ..()
var/hurt = TRUE
if(istype(throwingdatum, /datum/thrownthing))
var/datum/thrownthing/D = throwingdatum
if(iscyborg(D.thrower))
var/mob/living/silicon/robot/R = D.thrower
if(!R.emagged)
hurt = FALSE
if(hit_atom.density && isturf(hit_atom))
Weaken(1)
take_bodypart_damage(10)
if(hurt)
Weaken(1)
take_bodypart_damage(10)
if(iscarbon(hit_atom) && hit_atom != src)
var/mob/living/carbon/victim = hit_atom
if(victim.movement_type & FLYING)
return
victim.Weaken(1)
Weaken(1)
victim.take_bodypart_damage(10)
take_bodypart_damage(10)
visible_message("<span class='danger'>[src] crashes into [victim], knocking them both over!</span>", "<span class='userdanger'>You violently crash into [victim]!</span>")
if(hurt)
victim.take_bodypart_damage(10)
take_bodypart_damage(10)
victim.Weaken(1)
Weaken(1)
visible_message("<span class='danger'>[src] crashes into [victim], knocking them both over!</span>", "<span class='userdanger'>You violently crash into [victim]!</span>")
playsound(src,'sound/weapons/punch1.ogg',50,1)
@@ -231,23 +240,6 @@
/mob/living/carbon/is_muzzled()
return(istype(src.wear_mask, /obj/item/clothing/mask/muzzle))
/mob/living/carbon/proc/spin(spintime, speed)
set waitfor = 0
var/D = dir
while(spintime >= speed)
sleep(speed)
switch(D)
if(NORTH)
D = EAST
if(SOUTH)
D = WEST
if(EAST)
D = SOUTH
if(WEST)
D = NORTH
setDir(D)
spintime -= speed
/mob/living/carbon/resist_buckle()
if(restrained())
changeNext_move(CLICK_CD_BREAKOUT)
@@ -168,7 +168,7 @@
O.emp_act(severity)
..()
/mob/living/carbon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0)
/mob/living/carbon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
if(tesla_shock && tesla_ignore)
return FALSE
shock_damage *= siemens_coeff
@@ -190,11 +190,11 @@
jitteriness += 1000 //High numbers for violent convulsions
do_jitter_animation(jitteriness)
stuttering += 2
if(!tesla_shock || (tesla_shock && siemens_coeff > 0.5))
if((!tesla_shock || (tesla_shock && siemens_coeff > 0.5)) && stun)
Stun(2)
spawn(20)
jitteriness = max(jitteriness - 990, 10) //Still jittery, but vastly less
if(!tesla_shock || (tesla_shock && siemens_coeff > 0.5))
if((!tesla_shock || (tesla_shock && siemens_coeff > 0.5)) && stun)
Stun(3)
Weaken(3)
if(override)
@@ -436,7 +436,7 @@
//Added a safety check in case you want to shock a human mob directly through electrocute_act.
/mob/living/carbon/human/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0)
/mob/living/carbon/human/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
if(tesla_shock)
var/total_coeff = 1
if(gloves)
@@ -447,6 +447,8 @@
var/obj/item/clothing/suit/S = wear_suit
if(S.siemens_coefficient <= 0)
total_coeff -= 0.95
else if(S.siemens_coefficient == (-1))
total_coeff -= 1
siemens_coeff = total_coeff
if(tesla_ignore)
siemens_coeff = 0
@@ -461,7 +463,7 @@
heart_attack = 0
if(stat == CONSCIOUS)
src << "<span class='notice'>You feel your heart beating again!</span>"
. = ..(shock_damage,source,siemens_coeff,safety,override,tesla_shock, illusion)
. = ..(shock_damage,source,siemens_coeff,safety,override,tesla_shock, illusion, stun)
if(.)
electrocution_animation(40)
@@ -754,4 +756,4 @@
torn_items += leg_clothes
for(var/obj/item/I in torn_items)
I.take_damage(damage_amount, damage_type, damage_flag, 0)
I.take_damage(damage_amount, damage_type, damage_flag, 0)
@@ -1015,7 +1015,7 @@
var/obj/item/organ/cyberimp/chest/thrusters/T = H.getorganslot("thrusters")
if(!istype(J) && istype(C))
J = C.jetpack
if(istype(J) && J.allow_thrust(0.01, H)) //Prevents stacking
if(istype(J) && J.full_speed && J.allow_thrust(0.01, H)) //Prevents stacking
. -= 2
else if(istype(T) && T.allow_thrust(0.01, H))
. -= 2
@@ -150,4 +150,14 @@
return 1
/mob/living/carbon/monkey/can_use_guns(var/obj/item/weapon/gun/G)
return 1
return 1
/mob/living/carbon/monkey/angry
aggressive = TRUE
/mob/living/carbon/monkey/angry/Initialize()
..()
if(prob(10))
var/obj/item/clothing/head/helmet/justice/escape/helmet = new(src)
equip_to_slot_or_del(helmet,slot_head)
helmet.attack_self(src) // todo encapsulate toggle
+13
View File
@@ -93,6 +93,7 @@
if(istype(S) && S.deathmessage)
message_simple = S.deathmessage
. = ..()
message_simple = initial(message_simple)
if(. && isalienadult(user))
playsound(user.loc, 'sound/voice/hiss6.ogg', 80, 1, 1)
@@ -451,3 +452,15 @@
message = "beeps."
message_param = "beeps at %t."
sound = 'sound/machines/twobeep.ogg'
/datum/emote/living/spin
key = "spin"
key_third_person = "spins"
message = "spins around dizzily!"
/datum/emote/living/spin/run_emote(mob/user)
user.spin(20, 1)
if(istype(user, /mob/living/silicon/robot))
var/mob/living/silicon/robot/R = user
R.riding_datum.force_dismount()
..()
+11 -9
View File
@@ -274,8 +274,7 @@
take_bodypart_damage(acidpwr * min(1, acid_volume * 0.1))
return 1
/mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0)
/mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
if(tesla_shock && tesla_ignore)
return FALSE
if(shock_damage > 0)
@@ -325,13 +324,16 @@
/mob/living/ratvar_act()
if(stat != DEAD && !is_servant_of_ratvar(src) && !add_servant_of_ratvar(src))
src << "<span class='userdanger'>A blinding light boils you alive! <i>Run!</i></span>"
adjustFireLoss(35)
if(src)
adjust_fire_stacks(1)
IgniteMob()
return FALSE
if(stat != DEAD && !is_servant_of_ratvar(src))
for(var/obj/item/weapon/implant/mindshield/M in implants)
qdel(M)
if(!add_servant_of_ratvar(src))
src << "<span class='userdanger'>A blinding light boils you alive! <i>Run!</i></span>"
adjustFireLoss(35)
if(src)
adjust_fire_stacks(1)
IgniteMob()
return FALSE
return TRUE
+6 -6
View File
@@ -57,11 +57,11 @@
var/chassis = "repairbot"
var/list/possible_chassis = list("cat", "mouse", "monkey", "corgi", "fox", "repairbot", "rabbit")
var/emitterhealth = 50
var/emittermaxhealth = 50
var/emitterregen = 0.5
var/emittercd = 20
var/emitteroverloadcd = 50
var/emitterhealth = 20
var/emittermaxhealth = 20
var/emitterregen = 0.25
var/emittercd = 50
var/emitteroverloadcd = 100
var/emittersemicd = FALSE
var/overload_ventcrawl = 0
@@ -235,4 +235,4 @@
/mob/living/silicon/pai/process()
emitterhealth = Clamp((emitterhealth + emitterregen), -50, emittermaxhealth)
hit_slowdown = Clamp((hit_slowdown - 1), 0, 100)
hit_slowdown = Clamp((hit_slowdown - 1), 0, 100)
@@ -30,4 +30,6 @@
update_icons()
sql_report_death(src)
unbuckle_all_mobs(TRUE)
sql_report_death(src)
@@ -69,4 +69,4 @@
"You announce you are operating in low power mode.")
playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
else
src << "<span class='warning'>You can only use this emote when you're out of charge.</span>"
src << "<span class='warning'>You can only use this emote when you're out of charge.</span>"
+90 -1
View File
@@ -89,7 +89,9 @@
/obj/item/clothing/head/sombrero,
/obj/item/clothing/head/witchunter_hat)
can_buckle = TRUE
buckle_lying = FALSE
var/datum/riding/cyborg/riding_datum = null
/mob/living/silicon/robot/New(loc)
spark_system = new /datum/effect_system/spark_spread()
@@ -995,3 +997,90 @@
hat = new_hat
new_hat.forceMove(src)
update_icons()
/mob/living/silicon/robot/MouseDrop_T(mob/living/M, mob/living/user)
. = ..()
if(!(M in buckled_mobs))
buckle_mob(M)
/mob/living/silicon/robot/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE)
if(!riding_datum)
riding_datum = new /datum/riding/cyborg
riding_datum.ridden = src
if(buckled_mobs)
if(buckled_mobs.len >= max_buckled_mobs)
return
if(M in buckled_mobs)
return
if(stat)
return
if(incapacitated())
return
if(M.restrained())
return
if(iscyborg(M))
M.visible_message("<span class='warning'>[M] really can't seem to mount the [src]...</span>")
return
if(isbot(M))
M.visible_message("<span class='boldwarning'>No. Just... no.</span>")
return
if(module)
if(!module.allow_riding)
M.visible_message("<span class='boldwarning'>Unfortunately, [M] just can't seem to hold onto [src]!</span>")
return
if(iscarbon(M))
if(!equip_buckle_inhands(M)) //MAKE SURE THIS IS LAST!
M.visible_message("<span class='boldwarning'>[M] can't climb onto [src] because his hands are full!</span>")
return
. = ..(M, force, check_loc)
riding_datum.handle_vehicle_offsets()
/mob/living/silicon/robot/unbuckle_mob(mob/user)
if(iscarbon(user))
unequip_buckle_inhands(user)
. = ..(user)
riding_datum.restore_position(user)
/mob/living/silicon/robot/proc/unequip_buckle_inhands(mob/living/carbon/user)
for(var/obj/item/cyborgride_offhand/O in user.contents)
if(O.ridden != src)
CRASH("RIDING OFFHAND ON WRONG MOB")
continue
if(O.selfdeleting)
continue
else
qdel(O)
return TRUE
/mob/living/silicon/robot/proc/equip_buckle_inhands(mob/living/carbon/user)
var/obj/item/cyborgride_offhand/inhand = new /obj/item/cyborgride_offhand(user)
inhand.rider = user
inhand.ridden = src
return user.put_in_hands(inhand, TRUE)
/obj/item/cyborgride_offhand
name = "offhand"
icon = 'icons/obj/weapons.dmi'
icon_state = "offhand"
w_class = WEIGHT_CLASS_HUGE
flags = ABSTRACT | DROPDEL | NOBLUDGEON
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
var/mob/living/carbon/rider
var/mob/living/silicon/robot/ridden
var/selfdeleting = FALSE
/obj/item/cyborgride_offhand/dropped()
selfdeleting = TRUE
. = ..()
/obj/item/cyborgride_offhand/equipped()
if(loc != rider)
selfdeleting = TRUE
qdel(src)
. = ..()
/obj/item/cyborgride_offhand/Destroy()
if(selfdeleting)
if(rider in ridden.buckled_mobs)
ridden.unbuckle_mob(rider)
. = ..()
@@ -26,6 +26,11 @@
var/hat_offset = -3
var/list/ride_offset_x = list("north" = 0, "south" = 0, "east" = -6, "west" = 6)
var/list/ride_offset_y = list("north" = 4, "south" = 4, "east" = 3, "west" = 3)
var/ride_allow_incapacitated = FALSE
var/allow_riding = TRUE
/obj/item/weapon/robot_module/New()
..()
for(var/i in basic_modules)
@@ -17,3 +17,8 @@
/mob/living/silicon/robot/experience_pressure_difference(pressure_difference, direction)
if(!magpulse)
return ..()
/mob/living/silicon/robot/Moved()
. = ..()
if(riding_datum)
riding_datum.on_vehicle_move()
@@ -26,6 +26,11 @@
/mob/living/silicon/attack_animal(mob/living/simple_animal/M)
if(..())
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
if(prob(damage))
for(var/mob/living/N in buckled_mobs)
N.Weaken(1)
unbuckle_mob(N)
N.visible_message("<span class='boldwarning'>[N] is knocked off of [src] by [M]!</span>")
switch(M.melee_damage_type)
if(BRUTE)
adjustBruteLoss(damage)
@@ -73,6 +78,10 @@
return 0
/mob/living/silicon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0)
if(buckled_mobs)
for(var/mob/living/M in buckled_mobs)
unbuckle_mob(M)
M.electrocute_act(shock_damage/100, source, siemens_coeff, safety, tesla_shock, illusion) //Hard metal shell conducts!
return 0 //So borgs they don't die trying to fix wiring
/mob/living/silicon/emp_act(severity)
@@ -83,12 +92,26 @@
src.take_bodypart_damage(10)
src << "<span class='userdanger'>*BZZZT*</span>"
src << "<span class='danger'>Warning: Electromagnetic pulse detected.</span>"
for(var/mob/living/M in buckled_mobs)
if(prob(severity*50))
unbuckle_mob(M)
M.Weaken(2)
M.visible_message("<span class='boldwarning'>[M] is thrown off of [src]!</span>")
flash_act(affect_silicon = 1)
..()
/mob/living/silicon/bullet_act(obj/item/projectile/Proj)
if((Proj.damage_type == BRUTE || Proj.damage_type == BURN))
adjustBruteLoss(Proj.damage)
if(prob(Proj.damage*1.5))
for(var/mob/living/M in buckled_mobs)
M.visible_message("<span class='boldwarning'>[M] is knocked off of [src]!</span>")
unbuckle_mob(M)
M.Weaken(2)
if(Proj.stun || Proj.weaken)
for(var/mob/living/M in buckled_mobs)
unbuckle_mob(M)
M.visible_message("<span class='boldwarning'>[M] is knocked off of [src] by the [Proj]!</span>")
Proj.on_hit(src)
return 2
@@ -145,8 +145,9 @@ Auto Patrol: []"},
mode = BOT_HUNT
/mob/living/simple_animal/bot/secbot/attack_hand(mob/living/carbon/human/H)
if(H.a_intent == INTENT_HARM)
if((H.a_intent == INTENT_HARM) || (H.a_intent == INTENT_DISARM))
retaliate(H)
return ..()
/mob/living/simple_animal/bot/secbot/attackby(obj/item/weapon/W, mob/user, params)
@@ -409,4 +410,4 @@ Auto Patrol: []"},
..()
/obj/machinery/bot_core/secbot
req_access = list(access_security)
req_access = list(access_security)
@@ -98,7 +98,7 @@ Difficulty: Hard
INVOKE_ASYNC(src, .proc/charge)
else
if(prob(70) || warped)
INVOKE_ASYNC(src, .proc/triple_charge)
INVOKE_ASYNC(src, .proc/charge, 2)
else
INVOKE_ASYNC(src, .proc/warp_charge)
@@ -141,12 +141,7 @@ Difficulty: Hard
blood_warp()
charge()
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/triple_charge()
charge()
charge()
charge()
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge()
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge(bonus_charges)
var/turf/T = get_turf(target)
if(!T || T == loc)
return
@@ -156,14 +151,18 @@ Difficulty: Hard
walk(src, 0)
setDir(get_dir(src, T))
var/obj/effect/overlay/temp/decoy/D = new /obj/effect/overlay/temp/decoy(loc,src)
animate(D, alpha = 0, color = "#FF0000", transform = matrix()*2, time = 5)
sleep(5)
throw_at(T, get_dist(src, T), 1, src, 0, callback = CALLBACK(src, .charge_end))
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge_end()
animate(D, alpha = 0, color = "#FF0000", transform = matrix()*2, time = 3)
sleep(3)
throw_at(T, get_dist(src, T), 0.5, src, 0, callback = CALLBACK(src, .charge_end, bonus_charges))
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge_end(bonus_charges)
charging = 0
try_bloodattack()
if(target)
Goto(target, move_to_delay, minimum_distance)
if(bonus_charges)
charge(bonus_charges--)
else
Goto(target, move_to_delay, minimum_distance)
/mob/living/simple_animal/hostile/megafauna/bubblegum/Bump(atom/A)
@@ -312,8 +311,8 @@ Difficulty: Hard
DA.color = "#FF0000"
var/oldtransform = DA.transform
DA.transform = matrix()*2
animate(DA, alpha = 255, color = initial(DA.color), transform = oldtransform, time = 5)
sleep(5)
animate(DA, alpha = 255, color = initial(DA.color), transform = oldtransform, time = 3)
sleep(3)
qdel(DA)
var/obj/effect/decal/cleanable/blood/found_bloodpool
@@ -299,21 +299,20 @@
if(!gibbed)
if(death_sound)
playsound(get_turf(src),death_sound, 200, 1)
if(deathmessage && !del_on_death)
if(deathmessage || !del_on_death)
emote("deathgasp")
if(del_on_death)
ghostize()
..()
//Prevent infinite loops if the mob Destroy() is overriden in such
//a manner as to cause a call to death() again
del_on_death = FALSE
qdel(src)
return
else
health = 0
icon_state = icon_dead
density = 0
lying = 1
..()
..()
/mob/living/simple_animal/proc/CanAttack(atom/the_target)
if(see_invisible < the_target.invisibility)
@@ -551,4 +550,4 @@
/mob/living/simple_animal/buckle_mob(mob/living/buckled_mob, force = 0, check_loc = 1)
. = ..()
riding_datum = new/datum/riding/animal
riding_datum = new/datum/riding/animal
+19 -40
View File
@@ -1,6 +1,5 @@
/mob/Destroy()//This makes sure that mobs with clients/keys are not just deleted from the game.
mob_list -= src
SSmob.currentrun -= src
dead_mob_list -= src
living_mob_list -= src
all_clockwork_mobs -= src
@@ -28,8 +27,8 @@ var/next_mob_id = 0
dead_mob_list += src
else
living_mob_list += src
prepare_huds()
hook_vr("mob_new",list(src))
prepare_huds()
..()
/atom/proc/prepare_huds()
@@ -112,7 +111,7 @@ var/next_mob_id = 0
if(self_message)
msg = self_message
else
if(M.see_invisible<invisibility)//if src is invisible to us
if(M.see_invisible<invisibility)//if src is invisible to us,
if(blind_message) // then people see blind message if there is one, otherwise nothing.
msg = blind_message
else
@@ -125,18 +124,6 @@ var/next_mob_id = 0
continue
M.show_message(msg,1,blind_message,2)
/mob/proc/get_top_level_mob()
if(istype(src.loc,/mob)&&src.loc!=src)
var/mob/M=src.loc
return M.get_top_level_mob()
return src
proc/get_top_level_mob(var/mob/S)
if(istype(S.loc,/mob)&&S.loc!=S)
var/mob/M=S.loc
return M.get_top_level_mob()
return S
// Show a message to all mobs in earshot of this one
// This would be for audible actions by the src mob
// message is the message output to anyone who can hear.
@@ -352,6 +339,23 @@ proc/get_top_level_mob(var/mob/S)
else
M.LAssailant = usr
/mob/proc/spin(spintime, speed)
set waitfor = 0
var/D = dir
while(spintime >= speed)
sleep(speed)
switch(D)
if(NORTH)
D = EAST
if(SOUTH)
D = WEST
if(EAST)
D = SOUTH
if(WEST)
D = NORTH
setDir(D)
spintime -= speed
/mob/verb/stop_pulling()
set name = "Stop Pulling"
set category = "IC"
@@ -452,30 +456,7 @@ proc/get_top_level_mob(var/mob/S)
// M.Login() //wat
return
/mob/proc/update_flavor_text()
set src in usr
if(usr != src)
usr << "No."
var/msg = input(usr,"Set the flavor text in your 'examine' verb. Can also be used for OOC notes about your character.","Flavor Text",html_decode(flavor_text)) as message|null
if(msg != null)
msg = copytext(msg, 1, MAX_MESSAGE_LEN)
msg = html_encode(msg)
flavor_text = msg
/mob/proc/warn_flavor_changed()
if(flavor_text && flavor_text != "") // don't spam people that don't use it!
src << "<h2 class='alert'>OOC Warning:</h2>"
src << "<span class='alert'>Your flavor text is likely out of date! <a href='byond://?src=\ref[src];flavor_change=1'>Change</a></span>"
/mob/proc/print_flavor_text()
if(flavor_text && flavor_text != "")
var/msg = replacetext(flavor_text, "\n", " ")
if(lentext(msg) <= 40)
return "\blue [msg]"
else
return "\blue [copytext(msg, 1, 37)]... <a href='byond://?src=\ref[src];flavor_more=1'>More...</a>"
/mob/verb/cancel_camera()
set name = "Cancel Camera View"
@@ -571,7 +552,6 @@ proc/get_top_level_mob(var/mob/S)
stat(null, "Next Map: [nextmap.friendlyname]")
stat(null, "Server Time: [time2text(world.realtime, "YYYY-MM-DD hh:mm")]")
if(SSshuttle.emergency)
stat(null, "Current Shuttle: [SSshuttle.emergency.name]")
var/ETA = SSshuttle.emergency.getModeStr()
if(ETA)
stat(null, "[ETA] [SSshuttle.emergency.getTimerStr()]")
@@ -967,5 +947,4 @@ proc/get_top_level_mob(var/mob/S)
switch(var_name)
if ("attack_log")
return debug_variable(var_name, attack_log, 0, src, FALSE)
. = ..()
+3 -2
View File
@@ -175,7 +175,8 @@
moving = 0
if(mob && .)
mob.throwing = 0
if(mob.throwing)
mob.throwing.finalize(FALSE)
for(var/obj/O in mob)
O.on_mob_move(direct, src)
@@ -424,7 +425,7 @@
/client/verb/toggle_walk_run()
set name = "toggle-walk-run"
set hidden = TRUE
set instant = TRUE
set instant = TRUE
if(mob)
mob.toggle_move_intent()
+38 -1
View File
@@ -69,4 +69,41 @@
/mob/proc/emote_vr(var/act, var/type, var/message) //This would normally go in say.dm
if(act == "me")
return custom_emote_vr(type, message)
return custom_emote_vr(type, message)
/mob/proc/update_flavor_text()
set src in usr
if(usr != src)
usr << "No."
var/msg = input(usr,"Set the flavor text in your 'examine' verb. Can also be used for OOC notes about your character.","Flavor Text",html_decode(flavor_text)) as message|null
if(msg != null)
msg = copytext(msg, 1, MAX_MESSAGE_LEN)
msg = html_encode(msg)
flavor_text = msg
/mob/proc/warn_flavor_changed()
if(flavor_text && flavor_text != "") // don't spam people that don't use it!
src << "<h2 class='alert'>OOC Warning:</h2>"
src << "<span class='alert'>Your flavor text is likely out of date! <a href='byond://?src=\ref[src];flavor_change=1'>Change</a></span>"
/mob/proc/print_flavor_text()
if(flavor_text && flavor_text != "")
var/msg = replacetext(flavor_text, "\n", " ")
if(lentext(msg) <= 40)
return "\blue [msg]"
else
return "\blue [copytext(msg, 1, 37)]... <a href='byond://?src=\ref[src];flavor_more=1'>More...</a>"
/mob/proc/get_top_level_mob()
if(istype(src.loc,/mob)&&src.loc!=src)
var/mob/M=src.loc
return M.get_top_level_mob()
return src
proc/get_top_level_mob(var/mob/S)
if(istype(S.loc,/mob)&&S.loc!=S)
var/mob/M=S.loc
return M.get_top_level_mob()
return S
+15 -5
View File
@@ -29,6 +29,18 @@
var/list/stamped
var/rigged = 0
var/spam_flag = 0
var/contact_poison // Reagent ID to transfer on contact
var/contact_poison_volume = 0
/obj/item/weapon/paper/pickup(user)
if(contact_poison && ishuman(user))
var/mob/living/carbon/human/H = user
var/obj/item/clothing/gloves/G = H.gloves
if(!istype(G) || G.transfer_prints)
H.reagents.add_reagent(contact_poison,contact_poison_volume)
contact_poison = null
..()
/obj/item/weapon/paper/New()
@@ -166,7 +178,7 @@
/obj/item/weapon/paper/proc/clearpaper()
info = null
stamps = null
stamped = list()
LAZYCLEARLIST(stamped)
cut_overlays()
updateinfolinks()
update_icon()
@@ -289,7 +301,7 @@
else
info += t // Oh, he wants to edit to the end of the file, let him.
updateinfolinks()
i.on_write(src,usr)
usr << browse("<HTML><HEAD><TITLE>[name]</TITLE></HEAD><BODY>[info_links]<HR>[stamps]</BODY></HTML>", "window=[name]") // Update the window
update_icon()
@@ -326,9 +338,7 @@
stampoverlay.icon_state = "paper_[P.icon_state]"
if(!stamped)
stamped = new
stamped += P.icon_state
LAZYADD(stamped, P.icon_state)
add_overlay(stampoverlay)
user << "<span class='notice'>You stamp the paper with your rubber stamp.</span>"
+15 -19
View File
@@ -12,7 +12,6 @@
max_integrity = 50
var/obj/item/weapon/paper/internalPaper
var/list/stamped = list()
/obj/item/weapon/paperplane/New(loc, obj/item/weapon/paper/newPaper)
..()
@@ -20,13 +19,18 @@
pixel_x = rand(-9, 9)
if(newPaper)
internalPaper = newPaper
src.flags = newPaper.flags
stamped = internalPaper.stamped
flags = newPaper.flags
newPaper.forceMove(src)
else
internalPaper = new /obj/item/weapon/paper(src)
update_icon()
/obj/item/weapon/paperplane/Destroy()
if(internalPaper)
qdel(internalPaper)
internalPaper = null
return ..()
/obj/item/weapon/paperplane/suicide_act(mob/user)
user.Stun(10)
user.visible_message("<span class='suicide'>[user] jams the [src] in [user.p_their()] nose. It looks like [user.p_theyre()] trying to commit suicide!</span>")
@@ -37,18 +41,18 @@
/obj/item/weapon/paperplane/update_icon()
cut_overlays()
if(!stamped)
stamped = new
else if(stamped)
var/list/stamped = internalPaper.stamped
if(stamped)
for(var/S in stamped)
var/obj/item/weapon/stamp/stamp = S
var/image/stampoverlay = image('icons/obj/bureaucracy.dmi', "paperplane_[initial(stamp.icon_state)]")
var/image/stampoverlay = image('icons/obj/bureaucracy.dmi', "paperplane_[stamped]")
add_overlay(stampoverlay)
/obj/item/weapon/paperplane/attack_self(mob/user)
user << "<span class='notice'>You unfold [src].</span>"
var/internal_paper_tmp = internalPaper
internalPaper = null
qdel(src)
user.put_in_hands(internalPaper)
user.put_in_hands(internal_paper_tmp)
/obj/item/weapon/paperplane/attackby(obj/item/weapon/P, mob/living/carbon/human/user, params)
..()
@@ -57,15 +61,7 @@
return
else if(istype(P, /obj/item/weapon/stamp)) //we don't randomize stamps on a paperplane
if (!stamped)
stamped = new
stamped += P.type
internalPaper.stamps += "<img src=large_[P.icon_state].png>" //stamps the paper inside!
internalPaper.stamped = stamped
internalPaper.attackby(P) //spoofed attack to update internal paper.
user << "<span class='notice'>You stamp [src] with your rubber stamp.</span>"
internalPaper.attackby(P, user) //spoofed attack to update internal paper.
update_icon()
else if(P.is_hot())
@@ -108,7 +104,7 @@
return
user << "<span class='notice'>You fold [src] into the shape of a plane!</span>"
user.temporarilyRemoveItemFromInventory(src)
I = new /obj/item/weapon/paperplane(loc, src)
I = new /obj/item/weapon/paperplane(user, src)
user.put_in_hands(I)
else
user << "<span class='notice'> You lack the dexterity to fold \the [src]. </span>"
+9
View File
@@ -162,3 +162,12 @@
else
icon_state = initial(icon_state) //looks like a normal pen when off.
item_state = initial(item_state)
//Crayons path disambiguity sigh.
/obj/item/proc/on_write(obj/item/weapon/paper/P, mob/user)
return
/obj/item/weapon/pen/poison/on_write(obj/item/weapon/paper/P, mob/user)
P.contact_poison = "delayed_toxin"
P.contact_poison_volume = 10
add_logs(user,P,"used poison pen on")
+3 -2
View File
@@ -53,9 +53,10 @@ var/global/list/rad_collectors = list()
return
..()
/obj/machinery/power/rad_collector/can_be_unfasten_wrench(mob/user)
/obj/machinery/power/rad_collector/can_be_unfasten_wrench(mob/user, silent)
if(loaded_tank)
user << "<span class='warning'>Remove the plasma tank first!</span>"
if(!silent)
user << "<span class='warning'>Remove the plasma tank first!</span>"
return FAILED_UNFASTEN
return ..()
+4 -3
View File
@@ -128,7 +128,7 @@
return 1
/obj/machinery/power/emitter/attack_animal(mob/living/simple_animal/M)
if(ismegafauna(M))
if(ismegafauna(M) && anchored)
state = 0
anchored = FALSE
M.visible_message("<span class='warning'>[M] rips [src] free from its moorings!</span>")
@@ -217,9 +217,10 @@
A.starting = loc
A.fire()
/obj/machinery/power/emitter/can_be_unfasten_wrench(mob/user)
/obj/machinery/power/emitter/can_be_unfasten_wrench(mob/user, silent)
if(state == EM_WELDED)
user << "<span class='warning'>[src] is welded to the floor!</span>"
if(!silent)
user << "<span class='warning'>[src] is welded to the floor!</span>"
return FAILED_UNFASTEN
return ..()
@@ -77,9 +77,10 @@ field_generator power level display
else
user << "<span class='warning'>The [src] needs to be firmly secured to the floor first!</span>"
/obj/machinery/field/generator/can_be_unfasten_wrench(mob/user)
/obj/machinery/field/generator/can_be_unfasten_wrench(mob/user, silent)
if(state == FG_WELDED)
user << "<span class='warning'>[src] is welded to the floor!</span>"
if(!silent)
user << "<span class='warning'>[src] is welded to the floor!</span>"
return FAILED_UNFASTEN
return ..()
+11 -10
View File
@@ -160,7 +160,7 @@ var/list/blacklisted_tesla_types = typecacheof(list(/obj/machinery/atmospherics,
var/mob/living/carbon/C = A
C.dust()
/proc/tesla_zap(atom/source, zap_range = 3, power, explosive = FALSE)
/proc/tesla_zap(atom/source, zap_range = 3, power, explosive = FALSE, stun_mobs = TRUE)
. = source.dir
if(power < 1000)
return
@@ -251,26 +251,27 @@ var/list/blacklisted_tesla_types = typecacheof(list(/obj/machinery/atmospherics,
//per type stuff:
if(closest_tesla_coil)
closest_tesla_coil.tesla_act(power, explosive)
closest_tesla_coil.tesla_act(power, explosive, stun_mobs)
else if(closest_grounding_rod)
closest_grounding_rod.tesla_act(power, explosive)
closest_grounding_rod.tesla_act(power, explosive, stun_mobs)
else if(closest_mob)
var/shock_damage = Clamp(round(power/400), 10, 90) + rand(-5, 5)
closest_mob.electrocute_act(shock_damage, source, 1, tesla_shock = 1)
closest_mob.electrocute_act(shock_damage, source, 1, tesla_shock = 1, stun = stun_mobs)
if(issilicon(closest_mob))
var/mob/living/silicon/S = closest_mob
S.emp_act(2)
tesla_zap(S, 7, power / 1.5) // metallic folks bounce it further
if(stun_mobs)
S.emp_act(2)
tesla_zap(S, 7, power / 1.5, stun_mobs) // metallic folks bounce it further
else
tesla_zap(closest_mob, 5, power / 1.5)
tesla_zap(closest_mob, 5, power / 1.5, stun_mobs)
else if(closest_machine)
closest_machine.tesla_act(power, explosive)
closest_machine.tesla_act(power, explosive, stun_mobs)
else if(closest_blob)
closest_blob.tesla_act(power, explosive)
closest_blob.tesla_act(power, explosive, stun_mobs)
else if(closest_structure)
closest_structure.tesla_act(power, explosive)
closest_structure.tesla_act(power, explosive, stun_mobs)
@@ -355,4 +355,3 @@
user.emote("scream")
user.drop_item()
user.Weaken(4)
return
@@ -165,6 +165,9 @@
/obj/item/weapon/gun/ballistic/shotgun/boltaction/enchanted/arcane_barrage/discard_gun(mob/user)
return
/obj/item/weapon/gun/ballistic/shotgun/boltaction/enchanted/attack_self()
return
/obj/item/weapon/gun/ballistic/shotgun/boltaction/enchanted/shoot_live_shot(mob/living/user as mob|obj, pointblank = 0, mob/pbtarget = null, message = 1)
..()
if(guns_left)
@@ -376,28 +376,32 @@
/obj/item/borg/upgrade/modkit/chassis_mod
name = "super chassis"
desc = "Makes your KA yellow. All the fun of having a more powerful KA without actually having a more powerful KA."
cost = 10
cost = 0
denied_type = /obj/item/borg/upgrade/modkit/chassis_mod
var/chassis_icon = "kineticgun_u"
var/chassis_name = "super-kinetic accelerator"
/obj/item/borg/upgrade/modkit/chassis_mod/install(obj/item/weapon/gun/energy/kinetic_accelerator/KA, mob/user)
. = ..()
if(.)
KA.icon_state = chassis_icon
KA.name = chassis_name
/obj/item/borg/upgrade/modkit/chassis_mod/uninstall(obj/item/weapon/gun/energy/kinetic_accelerator/KA)
KA.icon_state = initial(KA.icon_state)
KA.name = initial(KA.name)
..()
/obj/item/borg/upgrade/modkit/chassis_mod/orange
name = "hyper chassis"
desc = "Makes your KA orange. All the fun of having explosive blasts without actually having explosive blasts."
chassis_icon = "kineticgun_h"
chassis_name = "hyper-kinetic accelerator"
/obj/item/borg/upgrade/modkit/tracer
name = "white tracer bolts"
desc = "Causes kinetic accelerator bolts to have a white tracer trail and explosion."
cost = 4
cost = 0
denied_type = /obj/item/borg/upgrade/modkit/tracer
var/bolt_color = "#FFFFFF"
@@ -814,3 +814,23 @@
if(prob(30))
M << "You should sit down and take a rest..."
..()
/datum/reagent/toxin/delayed
name = "Toxin Microcapsules"
id = "delayed_toxin"
description = "Causes heavy toxin damage after a brief time of inactivity."
reagent_state = LIQUID
metabolization_rate = 0 //stays in the system until active.
var/actual_metaboliztion_rate = REAGENTS_METABOLISM
toxpwr = 0
var/actual_toxpwr = 5
var/delay = 30
/datum/reagent/toxin/delayed/on_mob_life(mob/living/M)
if(current_cycle > delay)
holder.remove_reagent(id, actual_metaboliztion_rate * M.metabolism_efficiency)
M.adjustToxLoss(actual_toxpwr*REM, 0)
if(prob(10))
M.Weaken(1, 0)
. = 1
..()
+11 -10
View File
@@ -62,16 +62,17 @@
deconstruct()
/obj/machinery/disposal/Initialize(mapload)
..()
if(!mapload)
return
//this will get a copy of the air turf and take a SEND PRESSURE amount of air from it
var/atom/L = loc
var/datum/gas_mixture/env = new
env.copy_from(L.return_air())
var/datum/gas_mixture/removed = env.remove(SEND_PRESSURE + 1)
air_contents.merge(removed)
trunk_check()
. = mapload //late-initialize, we need turfs to have air
if(initialized) //will only be run on late mapload initialization
//this will get a copy of the air turf and take a SEND PRESSURE amount of air from it
var/atom/L = loc
var/datum/gas_mixture/env = new
env.copy_from(L.return_air())
var/datum/gas_mixture/removed = env.remove(SEND_PRESSURE + 1)
air_contents.merge(removed)
trunk_check()
else
..()
/obj/machinery/disposal/attackby(obj/item/I, mob/user, params)
add_fingerprint(user)
+16 -3
View File
@@ -389,7 +389,9 @@
launch_status = UNLAUNCHED
/obj/docking_port/mobile/pod/request()
if(security_level == SEC_LEVEL_RED || security_level == SEC_LEVEL_DELTA)
var/obj/machinery/computer/shuttle/S = getControlConsole()
if(security_level == SEC_LEVEL_RED || security_level == SEC_LEVEL_DELTA || (S && S.emagged))
if(launch_status == UNLAUNCHED)
launch_status = EARLY_LAUNCHED
return ..()
@@ -418,6 +420,11 @@
/obj/machinery/computer/shuttle/pod/update_icon()
return
/obj/machinery/computer/shuttle/pod/emag_act(mob/user)
if(!emagged)
emagged = TRUE
user << "<span class='warning'>You fry the pod's alert level checking system.</span>"
/obj/docking_port/stationary/random
name = "escape pod"
id = "pod"
@@ -469,6 +476,7 @@
density = 0
icon = 'icons/obj/storage.dmi'
icon_state = "safe"
var/unlocked = FALSE
/obj/item/weapon/storage/pod/New()
..()
@@ -488,13 +496,18 @@
return
/obj/item/weapon/storage/pod/MouseDrop(over_object, src_location, over_location)
if(security_level == SEC_LEVEL_RED || security_level == SEC_LEVEL_DELTA)
if(security_level == SEC_LEVEL_RED || security_level == SEC_LEVEL_DELTA || unlocked)
. = ..()
else
usr << "The storage unit will only unlock during a Red or Delta security alert."
/obj/item/weapon/storage/pod/attack_hand(mob/user)
return
return MouseDrop(user)
/obj/item/weapon/storage/pod/onShuttleMove()
unlocked = TRUE
// If the pod was launched, the storage will always open.
return ..()
/obj/docking_port/mobile/emergency/backup
+9
View File
@@ -699,4 +699,13 @@
else
dst = destination
. += " towards [dst ? dst.name : "unknown location"] ([timeLeft(600)] minutes)"
// attempts to locate /obj/machinery/computer/shuttle with matching ID inside the shuttle
/obj/docking_port/mobile/proc/getControlConsole()
for(var/obj/machinery/computer/shuttle/S in areaInstance)
if(S.shuttleId == id)
return S
return null
#undef DOCKING_PORT_HIGHLIGHT
+39
View File
@@ -216,3 +216,42 @@
var/obj/item/weapon/card/id/ID = user.get_idcard()
if(ID && (access_cent_bar in ID.access))
return TRUE
//Luxury Shuttle Blockers
/obj/effect/forcefield/luxury_shuttle
var/threshhold = 500
var/static/list/approved_passengers = list()
/obj/effect/forcefield/luxury_shuttle/CanPass(atom/movable/mover, turf/target, height=0)
if(mover in approved_passengers)
return 1
if(!isliving(mover)) //No stowaways
return 0
var/total_cash = 0
var/list/counted_money = list()
for(var/obj/item/weapon/coin/C in mover.GetAllContents())
total_cash += C.value
counted_money += C
if(total_cash >= threshhold)
break
for(var/obj/item/stack/spacecash/S in mover.GetAllContents())
total_cash += S.value * S.amount
counted_money += S
if(total_cash >= threshhold)
break
if(total_cash >= threshhold)
for(var/obj/I in counted_money)
qdel(I)
mover << "Thank you for your payment! Please enjoy your flight."
approved_passengers += mover
return 1
else
mover << "You don't have enough money to enter the main shuttle. You'll have to fly coach."
return 0
+11
View File
@@ -6,6 +6,7 @@
var/active_msg = "You charge your projectile!"
var/base_icon_state = "projectile"
var/active_icon_state = "projectile"
var/projectile_damage_override = -1
/obj/effect/proc_holder/spell/aimed/Click()
var/mob/living/user = usr
@@ -54,6 +55,11 @@
var/obj/item/projectile/P = new projectile_type(user.loc)
P.current = get_turf(user)
P.preparePixelProjectile(target, get_turf(target), user)
if(projectile_damage_override != -1)
P.damage = projectile_damage_override
P.nodamage = TRUE
if(P.damage)
P.nodamage = FALSE
P.fire()
return TRUE
@@ -80,6 +86,11 @@
var/obj/item/projectile/magic/aoe/lightning/P = new /obj/item/projectile/magic/aoe/lightning(user.loc)
P.current = get_turf(user)
P.preparePixelProjectile(target, get_turf(target), user)
if(projectile_damage_override != -1)
P.damage = projectile_damage_override
P.nodamage = TRUE
if(P.damage)
P.nodamage = FALSE
P.tesla_power = tesla_power
P.tesla_range = tesla_range
P.tesla_boom = tesla_boom
+10 -2
View File
@@ -618,6 +618,13 @@ var/list/uplink_items = list() // Global list so we only initialize this once.
cost = 4
exclude_modes = list(/datum/game_mode/nuclear,/datum/game_mode/gang)
/datum/uplink_item/stealthy_weapons/poison_pen
name = "Poison Pen"
desc = "Cutting edge of deadly writing implements technology, this gadget will infuse any piece of paper with delayed contact poison."
item = /obj/item/weapon/pen/poison
cost = 2
exclude_modes = list(/datum/game_mode/nuclear)
/datum/uplink_item/stealthy_weapons/soap
name = "Syndicate Soap"
desc = "A sinister-looking surfactant used to clean blood stains to hide murders and prevent DNA analysis. \
@@ -1166,13 +1173,14 @@ var/list/uplink_items = list() // Global list so we only initialize this once.
/datum/uplink_item/role_restricted
category = "Role-Restricted"
exclude_modes = list(/datum/game_mode/nuclear)
surplus = 0
/datum/uplink_item/role_restricted/reverse_revolver
name = "Reverse Revolver"
desc = "A revolver that always fires at its user. \"Accidentally\" drop your weapon, then watch as the greedy corporate pigs blow their own brains all over the wall. \
The revolver itself is actually real. Only clumsy people, and clowns, can fire it normally. Honk."
The revolver itself is actually real. Only clumsy people, and clowns, can fire it normally. Comes in a box of hugs. Honk."
cost = 14
item = /obj/item/weapon/gun/ballistic/revolver/reverse
item = /obj/item/weapon/storage/box/hug/reverse_revolver
restricted_roles = list("Clown")
/datum/uplink_item/role_restricted/ez_clean_bundle