Merge branch 'master' into upstream-merge-36442
This commit is contained in:
@@ -19,8 +19,7 @@
|
||||
if(!check_rights())
|
||||
return
|
||||
|
||||
if(!isobserver(usr))
|
||||
log_game("[key_name(usr)] checked the player panel while in game.")
|
||||
log_admin("[key_name(usr)] checked the individual player panel for [key_name(M)][isobserver(usr)?"":" while in game"].")
|
||||
|
||||
if(!M)
|
||||
to_chat(usr, "You seem to be selecting a mob that doesn't exist anymore.")
|
||||
|
||||
@@ -113,7 +113,7 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
return ((rank.rights & flag) == flag) //true only if right has everything in flag
|
||||
|
||||
//load our rank - > rights associations
|
||||
/proc/load_admin_ranks(dbfail)
|
||||
/proc/load_admin_ranks(dbfail, no_update)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
to_chat(usr, "<span class='admin prefix'>Admin Reload blocked: Advanced ProcCall detected.</span>")
|
||||
return
|
||||
@@ -137,27 +137,38 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
prev = next
|
||||
previous_rights = R.rights
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) || dbfail)
|
||||
var/datum/DBQuery/query_load_admin_ranks = SSdbcore.NewQuery("SELECT rank, flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")]")
|
||||
if(!query_load_admin_ranks.Execute())
|
||||
message_admins("Error loading admin ranks from database. Loading from backup.")
|
||||
log_sql("Error loading admin ranks from database. Loading from backup.")
|
||||
dbfail = 1
|
||||
else
|
||||
while(query_load_admin_ranks.NextRow())
|
||||
var/skip
|
||||
var/rank_name = query_load_admin_ranks.item[1]
|
||||
if(CONFIG_GET(flag/load_legacy_ranks_only))
|
||||
if(!no_update)
|
||||
var/list/sql_ranks = list()
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
if(R.name == rank_name) //this rank was already loaded from txt override
|
||||
skip = 1
|
||||
break
|
||||
if(!skip)
|
||||
var/rank_flags = text2num(query_load_admin_ranks.item[2])
|
||||
var/rank_exclude_flags = text2num(query_load_admin_ranks.item[3])
|
||||
var/rank_can_edit_flags = text2num(query_load_admin_ranks.item[4])
|
||||
var/datum/admin_rank/R = new(rank_name, rank_flags, rank_exclude_flags, rank_can_edit_flags)
|
||||
if(!R)
|
||||
continue
|
||||
GLOB.admin_ranks += R
|
||||
var/sql_rank = sanitizeSQL(R.name)
|
||||
var/sql_flags = sanitizeSQL(R.include_rights)
|
||||
var/sql_exclude_flags = sanitizeSQL(R.exclude_rights)
|
||||
var/sql_can_edit_flags = sanitizeSQL(R.can_edit_rights)
|
||||
sql_ranks += list(list("rank" = "'[sql_rank]'", "flags" = "[sql_flags]", "exclude_flags" = "[sql_exclude_flags]", "can_edit_flags" = "[sql_can_edit_flags]"))
|
||||
SSdbcore.MassInsert(format_table_name("admin_ranks"), sql_ranks, duplicate_key = TRUE)
|
||||
else
|
||||
var/datum/DBQuery/query_load_admin_ranks = SSdbcore.NewQuery("SELECT rank, flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")]")
|
||||
if(!query_load_admin_ranks.Execute())
|
||||
message_admins("Error loading admin ranks from database. Loading from backup.")
|
||||
log_sql("Error loading admin ranks from database. Loading from backup.")
|
||||
dbfail = 1
|
||||
else
|
||||
while(query_load_admin_ranks.NextRow())
|
||||
var/skip
|
||||
var/rank_name = query_load_admin_ranks.item[1]
|
||||
for(var/datum/admin_rank/R in GLOB.admin_ranks)
|
||||
if(R.name == rank_name) //this rank was already loaded from txt override
|
||||
skip = 1
|
||||
break
|
||||
if(!skip)
|
||||
var/rank_flags = text2num(query_load_admin_ranks.item[2])
|
||||
var/rank_exclude_flags = text2num(query_load_admin_ranks.item[3])
|
||||
var/rank_can_edit_flags = text2num(query_load_admin_ranks.item[4])
|
||||
var/datum/admin_rank/R = new(rank_name, rank_flags, rank_exclude_flags, rank_can_edit_flags)
|
||||
if(!R)
|
||||
continue
|
||||
GLOB.admin_ranks += R
|
||||
//load ranks from backup file
|
||||
if(dbfail)
|
||||
var/backup_file = file("data/admins_backup.json")
|
||||
@@ -184,7 +195,7 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
testing(msg)
|
||||
#endif
|
||||
|
||||
/proc/load_admins()
|
||||
/proc/load_admins(no_update)
|
||||
var/dbfail
|
||||
if(!CONFIG_GET(flag/admin_legacy_system) && !SSdbcore.Connect())
|
||||
message_admins("Failed to connect to database while loading admins. Loading from backup.")
|
||||
@@ -198,7 +209,7 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
GLOB.admins.Cut()
|
||||
GLOB.protected_admins.Cut()
|
||||
GLOB.deadmins.Cut()
|
||||
dbfail = load_admin_ranks(dbfail)
|
||||
dbfail = load_admin_ranks(dbfail, no_update)
|
||||
//Clear profile access
|
||||
for(var/A in world.GetConfig("admin"))
|
||||
world.SetConfig("APP/admin", A, null)
|
||||
|
||||
@@ -82,6 +82,10 @@
|
||||
if(D.rank in GLOB.protected_ranks)
|
||||
to_chat(usr, "<span class='admin prefix'>Editing the flags of this rank is blocked by server configuration.</span>")
|
||||
return
|
||||
if(CONFIG_GET(flag/load_legacy_ranks_only) && (task == "rank" || task == "permissions"))
|
||||
to_chat(usr, "<span class='admin prefix'>Database rank loading is disabled, only temporary changes can be made to an admin's rank or permissions.</span>")
|
||||
use_db = FALSE
|
||||
skip = TRUE
|
||||
if(check_rights(R_DBRANKS, FALSE))
|
||||
if(!skip)
|
||||
if(!SSdbcore.Connect())
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/admins/proc/player_panel_new()//The new one
|
||||
if(!check_rights())
|
||||
return
|
||||
log_admin("[key_name(usr)] checked the player panel.")
|
||||
var/dat = "<html><head><title>Player Panel</title></head>"
|
||||
|
||||
//javascript, the part that does most of the work~
|
||||
@@ -307,4 +308,4 @@
|
||||
</body></html>
|
||||
"}
|
||||
|
||||
usr << browse(dat, "window=players;size=600x480")
|
||||
usr << browse(dat, "window=players;size=600x480")
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
..()
|
||||
src.bd = bd
|
||||
|
||||
/obj/screen/buildmode/Destroy()
|
||||
bd.buttons -= src
|
||||
bd = null
|
||||
return ..()
|
||||
|
||||
/obj/screen/buildmode/mode
|
||||
icon_state = "buildmode1"
|
||||
name = "Toggle Mode"
|
||||
@@ -102,8 +107,12 @@
|
||||
|
||||
/datum/buildmode/Destroy()
|
||||
stored = null
|
||||
for(var/button in buttons)
|
||||
qdel(button)
|
||||
QDEL_LIST(buttons)
|
||||
throw_atom = null
|
||||
holder = null
|
||||
preview.Cut()
|
||||
cornerA = null
|
||||
cornerB = null
|
||||
return ..()
|
||||
|
||||
/datum/buildmode/proc/create_buttons()
|
||||
|
||||
@@ -553,7 +553,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
set category = "Admin"
|
||||
set name = "Delete"
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
if(!check_rights(R_SPAWN|R_DEBUG))
|
||||
return
|
||||
|
||||
admin_delete(A)
|
||||
|
||||
@@ -692,7 +692,6 @@ Congratulations! You are now trained for invasive xenobiology research!"}
|
||||
icon_state = "alien_frame"
|
||||
framestack = /obj/item/stack/sheet/mineral/abductor
|
||||
framestackamount = 1
|
||||
density = TRUE
|
||||
|
||||
/obj/structure/table_frame/abductor/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/wrench))
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
else if(L.stat)
|
||||
to_chat(ranged_ability_user, "<span class='neovgre'>\"There is use in shackling the dead, but for examples.\"</span>")
|
||||
return TRUE
|
||||
else if(L.handcuffed)
|
||||
else if (istype(L.handcuffed,/obj/item/restraints/handcuffs/clockwork))
|
||||
to_chat(ranged_ability_user, "<span class='neovgre'>\"They are already helpless, no?\"</span>")
|
||||
return TRUE
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
"<span class='neovgre_small'>You begin shaping replicant alloy into manacles around [L]'s wrists...</span>")
|
||||
to_chat(L, "<span class='userdanger'>[ranged_ability_user] begins forming manacles around your wrists!</span>")
|
||||
if(do_mob(ranged_ability_user, L, 30))
|
||||
if(!L.handcuffed)
|
||||
if(!(istype(L.handcuffed,/obj/item/restraints/handcuffs/clockwork)))
|
||||
L.handcuffed = new/obj/item/restraints/handcuffs/clockwork(L)
|
||||
L.update_handcuffed()
|
||||
to_chat(ranged_ability_user, "<span class='neovgre_small'>You shackle [L].</span>")
|
||||
|
||||
@@ -184,6 +184,7 @@
|
||||
important = TRUE
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Returns you to Reebe."
|
||||
var/client_color
|
||||
|
||||
/datum/clockwork_scripture/abscond/check_special_requirements()
|
||||
if(is_reebe(invoker.z))
|
||||
@@ -192,6 +193,7 @@
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/abscond/recital()
|
||||
client_color = invoker.client.color
|
||||
animate(invoker.client, color = "#AF0AAF", time = 50)
|
||||
. = ..()
|
||||
|
||||
@@ -214,11 +216,11 @@
|
||||
invoker.pulling.forceMove(T)
|
||||
invoker.forceMove(T)
|
||||
if(invoker.client)
|
||||
animate(invoker.client, color = initial(invoker.client.color), time = 25)
|
||||
animate(invoker.client, color = client_color, time = 25)
|
||||
|
||||
/datum/clockwork_scripture/abscond/scripture_fail()
|
||||
if(invoker && invoker.client)
|
||||
animate(invoker.client, color = initial(invoker.client.color), time = 10)
|
||||
animate(invoker.client, color = client_color, time = 10)
|
||||
|
||||
|
||||
//Replicant: Creates a new clockwork slab.
|
||||
|
||||
@@ -112,8 +112,12 @@
|
||||
continue
|
||||
if(is_servant_of_ratvar(L) || (L.has_trait(TRAIT_BLIND)) || L.anti_magic_check(TRUE, TRUE))
|
||||
continue
|
||||
if(L.stat || L.restrained() || L.buckled || L.lying)
|
||||
if(L.stat || L.lying)
|
||||
continue
|
||||
if (iscarbon(L))
|
||||
var/mob/living/carbon/c = L
|
||||
if (istype(c.handcuffed,/obj/item/restraints/handcuffs/clockwork))
|
||||
continue
|
||||
if(ishostile(L))
|
||||
var/mob/living/simple_animal/hostile/H = L
|
||||
if(("ratvar" in H.faction) || (!H.mind && "neutral" in H.faction))
|
||||
|
||||
@@ -589,6 +589,7 @@
|
||||
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
|
||||
else
|
||||
to_chat(user, "<span class='warning'>The spell will not work on [target]!</span>")
|
||||
return
|
||||
..()
|
||||
|
||||
//Armor: Gives the target a basic cultist combat loadout
|
||||
|
||||
@@ -241,7 +241,7 @@
|
||||
|
||||
var/datum/job/sacjob = SSjob.GetJob(sac_objective.target.assigned_role)
|
||||
var/datum/preferences/sacface = sac_objective.target.current.client.prefs
|
||||
var/icon/reshape = get_flat_human_icon(null, sacjob, sacface)
|
||||
var/icon/reshape = get_flat_human_icon(null, sacjob, sacface, list(SOUTH))
|
||||
reshape.Shift(SOUTH, 4)
|
||||
reshape.Shift(EAST, 1)
|
||||
reshape.Crop(7,4,26,31)
|
||||
|
||||
@@ -776,7 +776,6 @@
|
||||
impact_effect_type = /obj/effect/temp_visual/dir_setting/bloodsplatter
|
||||
|
||||
/obj/item/projectile/magic/arcane_barrage/blood/Collide(atom/target)
|
||||
colliding = TRUE
|
||||
var/turf/T = get_turf(target)
|
||||
playsound(T, 'sound/effects/splat.ogg', 50, TRUE)
|
||||
if(iscultist(target))
|
||||
@@ -790,7 +789,6 @@
|
||||
M.adjustHealth(-5)
|
||||
new /obj/effect/temp_visual/cult/sparks(T)
|
||||
qdel(src)
|
||||
colliding = FALSE
|
||||
else
|
||||
..()
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
to_chat(src, "<span class='revenminor'>Something's wrong! [target] seems to be resisting the siphoning, leaving you vulnerable!</span>")
|
||||
target.visible_message("<span class='warning'>[target] slumps onto the ground.</span>", \
|
||||
"<span class='revenwarning'>Violets lights, dancing in your vision, receding--</span>")
|
||||
draining = FALSE
|
||||
return
|
||||
var/datum/beam/B = Beam(target,icon_state="drain_life",time=INFINITY)
|
||||
if(do_after(src, 46, 0, target)) //As one cannot prove the existance of ghosts, ghosts cannot prove the existance of the target they were draining.
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
|
||||
var/mob/living/simple_animal/revenant/revvie = new(pick(spawn_locs))
|
||||
revvie.key = selected.key
|
||||
message_admins("[key_name_admin(revvie)] has been made into a revenant by an event.")
|
||||
message_admins("[key_name_admin(revvie)] [ADMIN_FLW(revvie)] has been made into a revenant by an event.")
|
||||
log_game("[key_name(revvie)] was spawned as a revenant by an event.")
|
||||
spawned_mobs += revvie
|
||||
return SUCCESSFUL_SPAWN
|
||||
|
||||
@@ -106,6 +106,10 @@
|
||||
name = "Fireball"
|
||||
spell_type = /obj/effect/proc_holder/spell/aimed/fireball
|
||||
|
||||
/datum/spellbook_entry/spell_cards
|
||||
name = "Spell Cards"
|
||||
spell_type = /obj/effect/proc_holder/spell/aimed/spell_cards
|
||||
|
||||
/datum/spellbook_entry/rod_form
|
||||
name = "Rod Form"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/rod_form
|
||||
|
||||
@@ -266,22 +266,22 @@
|
||||
return
|
||||
crit_fail = FALSE
|
||||
times_used = 0
|
||||
playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1)
|
||||
playsound(src, 'sound/items/deconstruct.ogg', 50, 1)
|
||||
update_icon()
|
||||
flash.crit_fail = TRUE
|
||||
flash.update_icon()
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/device/assembly/flash/shield/update_icon(flash = 0)
|
||||
item_state = "flashshield"
|
||||
/obj/item/device/assembly/flash/shield/update_icon(flash = FALSE)
|
||||
icon_state = "flashshield"
|
||||
item_state = "flashshield"
|
||||
|
||||
if(crit_fail)
|
||||
icon_state = "riot"
|
||||
item_state = "riot"
|
||||
else if(flash)
|
||||
item_state = "flashshield_flash"
|
||||
icon_state = "flashshield_flash"
|
||||
item_state = "flashshield_flash"
|
||||
addtimer(CALLBACK(src, .proc/update_icon), 5)
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ What are the archived variables for?
|
||||
once gases got hot enough, most procedures wouldnt occur due to the fact that the mole counts would get rounded away. Thus, we lowered it a few orders of magnititude */
|
||||
GLOBAL_LIST_INIT(meta_gas_info, meta_gas_list()) //see ATMOSPHERICS/gas_types.dm
|
||||
GLOBAL_LIST_INIT(gaslist_cache, init_gaslist_cache())
|
||||
GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(/datum/gas/oxygen, /datum/gas/nitrogen, /datum/gas/carbon_dioxide))) // These gasses cannot react amongst themselves
|
||||
|
||||
/proc/init_gaslist_cache()
|
||||
. = list()
|
||||
@@ -411,10 +412,18 @@ GLOBAL_LIST_INIT(gaslist_cache, init_gaslist_cache())
|
||||
|
||||
/datum/gas_mixture/react(turf/open/dump_location)
|
||||
. = NO_REACTION
|
||||
|
||||
reaction_results = new
|
||||
|
||||
var/list/cached_gases = gases
|
||||
if(!cached_gases.len)
|
||||
return
|
||||
var/possible
|
||||
for(var/I in cached_gases)
|
||||
if(GLOB.nonreactive_gases[I])
|
||||
continue
|
||||
possible = TRUE
|
||||
break
|
||||
if(!possible)
|
||||
return
|
||||
reaction_results = new
|
||||
var/temp = temperature
|
||||
var/ener = THERMAL_ENERGY(src)
|
||||
|
||||
|
||||
@@ -31,9 +31,6 @@
|
||||
if(frequency)
|
||||
radio_connection = SSradio.add_object(src, frequency, RADIO_ATMOSIA)
|
||||
|
||||
/obj/machinery/atmospherics/components/trinary/filter/New()
|
||||
..()
|
||||
|
||||
/obj/machinery/atmospherics/components/trinary/filter/Destroy()
|
||||
SSradio.remove_object(src,frequency)
|
||||
return ..()
|
||||
|
||||
@@ -105,6 +105,8 @@
|
||||
addMachineryMember(A)
|
||||
|
||||
/datum/pipeline/proc/merge(datum/pipeline/E)
|
||||
if(E == src)
|
||||
return
|
||||
air.volume += E.air.volume
|
||||
members.Add(E.members)
|
||||
for(var/obj/machinery/atmospherics/pipe/S in E.members)
|
||||
|
||||
@@ -79,9 +79,10 @@
|
||||
parent = P
|
||||
|
||||
/obj/machinery/atmospherics/pipe/Destroy()
|
||||
QDEL_NULL(parent)
|
||||
|
||||
releaseAirToTurf()
|
||||
qdel(air_temporary)
|
||||
air_temporary = null
|
||||
QDEL_NULL(air_temporary)
|
||||
|
||||
var/turf/T = loc
|
||||
for(var/obj/machinery/meter/meter in T)
|
||||
@@ -91,8 +92,6 @@
|
||||
qdel(meter)
|
||||
. = ..()
|
||||
|
||||
QDEL_NULL(parent)
|
||||
|
||||
/obj/machinery/atmospherics/pipe/proc/update_node_icon()
|
||||
for(var/i in 1 to device_type)
|
||||
if(nodes[i])
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
/obj/machinery/computer/cargo/express
|
||||
name = "express supply console"
|
||||
desc = "This console allows the user to purchase a package for double the price,\
|
||||
desc = "This console allows the user to purchase a package \
|
||||
with 1/40th of the delivery time: made possible by NanoTrasen's new \"Drop Pod Railgun\".\
|
||||
All sales are near instantaneous - please choose carefully"
|
||||
icon_screen = "supply_express"
|
||||
@@ -75,8 +75,7 @@
|
||||
data["siliconUser"] = user.has_unlimited_silicon_privilege
|
||||
data["points"] = SSshuttle.points
|
||||
data["supplies"] = list()
|
||||
message = "For normally priced items, please use the standard Supply or Request Console. \
|
||||
Sales are near-instantaneous - please choose carefully."
|
||||
message = "Sales are near-instantaneous - please choose carefully."
|
||||
if(SSshuttle.supplyBlocked)
|
||||
message = blockade_warning
|
||||
if(obj_flags & EMAGGED)
|
||||
|
||||
@@ -105,4 +105,9 @@
|
||||
colour = "#ff99ff"
|
||||
|
||||
/datum/client_colour/glass_colour/gray
|
||||
colour = "#cccccc"
|
||||
colour = "#cccccc"
|
||||
|
||||
|
||||
/datum/client_colour/monochrome
|
||||
colour = list(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(0,0,0))
|
||||
priority = INFINITY //we can't see colors anyway!
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
|
||||
var/inprefs = FALSE
|
||||
var/list/topiclimiter
|
||||
var/list/clicklimiter
|
||||
|
||||
var/datum/chatOutput/chatOutput
|
||||
|
||||
|
||||
@@ -650,6 +650,49 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
|
||||
message_admins("<span class='adminnotice'>Proxy Detection: [key_name_admin(src)] IP intel rated [res.intel*100]% likely to be a Proxy/VPN.</span>")
|
||||
ip_intel = res.intel
|
||||
|
||||
/client/Click(atom/object, atom/location, control, params)
|
||||
var/ab = FALSE
|
||||
var/list/L = params2list(params)
|
||||
if (object && object == middragatom && L["left"])
|
||||
ab = max(0, 5 SECONDS-(world.time-middragtime)*0.1)
|
||||
var/mcl = CONFIG_GET(number/minute_click_limit)
|
||||
if (!holder && mcl)
|
||||
var/minute = round(world.time, 600)
|
||||
if (!clicklimiter)
|
||||
clicklimiter = new(LIMITER_SIZE)
|
||||
if (minute != clicklimiter[CURRENT_MINUTE])
|
||||
clicklimiter[CURRENT_MINUTE] = minute
|
||||
clicklimiter[MINUTE_COUNT] = 0
|
||||
clicklimiter[MINUTE_COUNT] += 1+(ab)
|
||||
if (clicklimiter[MINUTE_COUNT] > mcl)
|
||||
var/msg = "Your previous click was ignored because you've done too many in a minute."
|
||||
if (minute != clicklimiter[ADMINSWARNED_AT]) //only one admin message per-minute. (if they spam the admins can just boot/ban them)
|
||||
clicklimiter[ADMINSWARNED_AT] = minute
|
||||
|
||||
msg += " Administrators have been informed."
|
||||
if (ab)
|
||||
log_game("[key_name(src)] is using the middle click aimbot exploit")
|
||||
message_admins("[key_name_admin(src)] [ADMIN_FLW(usr)] [ADMIN_KICK(usr)] is using the middle click aimbot exploit</span>")
|
||||
add_system_note("aimbot", "Is using the middle click aimbot exploit")
|
||||
|
||||
log_game("[key_name(src)] Has hit the per-minute click limit of [mcl] clicks in a given game minute")
|
||||
message_admins("[key_name_admin(src)] [ADMIN_FLW(usr)] [ADMIN_KICK(usr)] Has hit the per-minute click limit of [mcl] clicks in a given game minute")
|
||||
to_chat(src, "<span class='danger'>[msg]</span>")
|
||||
return
|
||||
|
||||
var/scl = CONFIG_GET(number/second_click_limit)
|
||||
if (!holder && scl)
|
||||
var/second = round(world.time, 10)
|
||||
if (!clicklimiter)
|
||||
clicklimiter = new(LIMITER_SIZE)
|
||||
if (second != clicklimiter[CURRENT_SECOND])
|
||||
clicklimiter[CURRENT_SECOND] = second
|
||||
clicklimiter[SECOND_COUNT] = 0
|
||||
clicklimiter[SECOND_COUNT] += 1+(!!ab)
|
||||
if (clicklimiter[SECOND_COUNT] > scl)
|
||||
to_chat(src, "<span class='danger'>Your previous click was ignored because you've done too many in a second</span>")
|
||||
return
|
||||
..()
|
||||
|
||||
/client/proc/add_verbs_from_config()
|
||||
if(CONFIG_GET(flag/see_own_notes))
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
if(prefs.muted & MUTE_OOC)
|
||||
to_chat(src, "<span class='danger'>You cannot use OOC (muted).</span>")
|
||||
return
|
||||
if(jobban_isbanned(src.mob, "OOC"))
|
||||
to_chat(src, "<span class='danger'>You have been banned from OOC.</span>")
|
||||
return
|
||||
if(jobban_isbanned(src.mob, "OOC"))
|
||||
to_chat(src, "<span class='danger'>You have been banned from OOC.</span>")
|
||||
return
|
||||
|
||||
msg = copytext(sanitize(msg), 1, MAX_MESSAGE_LEN)
|
||||
var/raw_msg = msg
|
||||
@@ -277,7 +277,7 @@ GLOBAL_VAR_INIT(normal_ooc_colour, OOC_COLOR)
|
||||
set category = "OOC"
|
||||
set desc ="Ignore a player's messages on the OOC channel"
|
||||
|
||||
|
||||
|
||||
var/see_ghost_names = isobserver(mob)
|
||||
var/list/choices = list()
|
||||
for(var/client/C in GLOB.clients)
|
||||
|
||||
@@ -109,7 +109,6 @@
|
||||
icon_state = "night"
|
||||
item_state = "glasses"
|
||||
darkness_view = 8
|
||||
vision_flags = SEE_BLACKNESS
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
glass_colour_type = /datum/client_colour/glass_colour/green
|
||||
|
||||
|
||||
@@ -468,8 +468,8 @@
|
||||
|
||||
/obj/item/device/flightpack/proc/losecontrol(knockdown = FALSE, move = TRUE)
|
||||
usermessage("Warning: Control system not responding. Deactivating!", "boldwarning")
|
||||
wearer.visible_message("<span class='warning'>[wearer]'s flight suit abruptly shuts off and they lose control!</span>")
|
||||
if(wearer)
|
||||
wearer.visible_message("<span class='warning'>[wearer]'s flight suit abruptly shuts off and they lose control!</span>")
|
||||
if(move)
|
||||
while(momentum_x != 0 || momentum_y != 0)
|
||||
sleep(2)
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
|
||||
|
||||
/datum/personal_crafting/proc/check_contents(datum/crafting_recipe/R, list/contents)
|
||||
contents = contents["other"]
|
||||
main_loop:
|
||||
for(var/A in R.reqs)
|
||||
var/needed_amount = R.reqs[A]
|
||||
@@ -89,25 +90,30 @@
|
||||
|
||||
/datum/personal_crafting/proc/get_surroundings(mob/user)
|
||||
. = list()
|
||||
.["tool_behaviour"] = list()
|
||||
.["other"] = list()
|
||||
for(var/obj/item/I in get_environment(user))
|
||||
if(I.flags_2 & HOLOGRAM_2)
|
||||
continue
|
||||
if(istype(I, /obj/item/stack))
|
||||
var/obj/item/stack/S = I
|
||||
.[I.type] += S.amount
|
||||
.["other"][I.type] += S.amount
|
||||
else if(I.tool_behaviour)
|
||||
.["tool_behaviour"] += I.tool_behaviour
|
||||
else
|
||||
if(istype(I, /obj/item/reagent_containers))
|
||||
var/obj/item/reagent_containers/RC = I
|
||||
if(RC.is_drainable())
|
||||
for(var/datum/reagent/A in RC.reagents.reagent_list)
|
||||
.[A.type] += A.volume
|
||||
.[I.type] += 1
|
||||
.["other"][A.type] += A.volume
|
||||
.["other"][I.type] += 1
|
||||
|
||||
/datum/personal_crafting/proc/check_tools(mob/user, datum/crafting_recipe/R, list/contents)
|
||||
if(!R.tools.len)
|
||||
return TRUE
|
||||
var/list/possible_tools = list()
|
||||
var/list/present_qualities = list()
|
||||
present_qualities |= contents["tool_behaviour"]
|
||||
for(var/obj/item/I in user.contents)
|
||||
if(istype(I, /obj/item/storage))
|
||||
for(var/obj/item/SI in I.contents)
|
||||
@@ -120,7 +126,7 @@
|
||||
if(I.tool_behaviour)
|
||||
present_qualities.Add(I.tool_behaviour)
|
||||
|
||||
possible_tools += contents
|
||||
possible_tools |= contents["other"]
|
||||
|
||||
main_loop:
|
||||
for(var/A in R.tools)
|
||||
|
||||
@@ -110,6 +110,8 @@
|
||||
/obj/item/reagent_containers/food/drinks/proc/smash(atom/target, mob/thrower, ranged = FALSE)
|
||||
if(!isGlass)
|
||||
return
|
||||
if(QDELING(src) || !target) //Invalid loc
|
||||
return
|
||||
if(bartender_check(target) && ranged)
|
||||
return
|
||||
var/obj/item/broken_bottle/B = new (loc)
|
||||
|
||||
@@ -500,6 +500,8 @@
|
||||
for(var/I in assembly_components)
|
||||
var/obj/item/integrated_circuit/IC = I
|
||||
IC.ext_moved(oldLoc, dir)
|
||||
if(light) //Update lighting objects (From light circuits).
|
||||
update_light()
|
||||
|
||||
/obj/item/device/electronic_assembly/stop_pulling()
|
||||
for(var/I in assembly_components)
|
||||
|
||||
@@ -345,15 +345,15 @@
|
||||
activate_pin(3)
|
||||
|
||||
/obj/item/integrated_circuit/input/turfpoint
|
||||
name = "Tile pointer"
|
||||
desc = "This circuit will get tile ref with given relative coorinates."
|
||||
extended_desc = "If the machine cannot see the target, it will not be able to calculate the correct direction.\
|
||||
This circuit is working only in assembly."
|
||||
name = "tile pointer"
|
||||
desc = "This circuit will get tile ref with given absolute coorinates."
|
||||
extended_desc = "If the machine cannot see the target, it will not be able to scan it.\
|
||||
This circuit will only work in an assembly."
|
||||
icon_state = "numberpad"
|
||||
complexity = 5
|
||||
inputs = list("X" = IC_PINTYPE_NUMBER,"Y" = IC_PINTYPE_NUMBER)
|
||||
outputs = list("tile" = IC_PINTYPE_REF)
|
||||
activators = list("calculate dir" = IC_PINTYPE_PULSE_IN, "on calculated" = IC_PINTYPE_PULSE_OUT,"not calculated" = IC_PINTYPE_PULSE_OUT)
|
||||
activators = list("scan" = IC_PINTYPE_PULSE_IN, "on scanned" = IC_PINTYPE_PULSE_OUT,"not scanned" = IC_PINTYPE_PULSE_OUT)
|
||||
spawn_flags = IC_SPAWN_RESEARCH
|
||||
power_draw_per_use = 40
|
||||
|
||||
@@ -362,11 +362,11 @@
|
||||
activate_pin(3)
|
||||
return
|
||||
var/turf/T = get_turf(assembly)
|
||||
var/target_x = CLAMP(get_pin_data(IC_INPUT, 1) - assembly.x, 0, world.maxx)
|
||||
var/target_y = CLAMP(get_pin_data(IC_INPUT, 2) - assembly.y, 0, world.maxy)
|
||||
var/target_x = CLAMP(get_pin_data(IC_INPUT, 1), 0, world.maxx)
|
||||
var/target_y = CLAMP(get_pin_data(IC_INPUT, 2), 0, world.maxy)
|
||||
var/turf/A = locate(target_x, target_y, T.z)
|
||||
set_pin_data(IC_OUTPUT, 1, null)
|
||||
if(!A||!(A in view(T)))
|
||||
if(!A || !(A in view(T)))
|
||||
activate_pin(3)
|
||||
return
|
||||
else
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
if(do_tick && !is_running)
|
||||
is_running = TRUE
|
||||
tick()
|
||||
else if(is_running)
|
||||
else if(!do_tick && is_running)
|
||||
is_running = FALSE
|
||||
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ Roboticist
|
||||
faction = "Station"
|
||||
total_positions = 2
|
||||
spawn_positions = 2
|
||||
supervisors = "research director"
|
||||
supervisors = "the research director"
|
||||
selection_color = "#ffeeff"
|
||||
exp_requirements = 60
|
||||
exp_type = EXP_TYPE_CREW
|
||||
|
||||
@@ -278,31 +278,47 @@
|
||||
qdel(src)
|
||||
return TRUE
|
||||
|
||||
/mob/dead/new_player/proc/IsJobAvailable(rank)
|
||||
/proc/get_job_unavailable_error_message(retval, jobtitle)
|
||||
switch(retval)
|
||||
if(JOB_AVAILABLE)
|
||||
return "[jobtitle] is available."
|
||||
if(JOB_UNAVAILABLE_GENERIC)
|
||||
return "[jobtitle] is unavailable."
|
||||
if(JOB_UNAVAILABLE_BANNED)
|
||||
return "You are currently banned from [jobtitle]."
|
||||
if(JOB_UNAVAILABLE_PLAYTIME)
|
||||
return "You do not have enough relevant playtime for [jobtitle]."
|
||||
if(JOB_UNAVAILABLE_ACCOUNTAGE)
|
||||
return "Your account is not old enough for [jobtitle]."
|
||||
if(JOB_UNAVAILABLE_SLOTFULL)
|
||||
return "[jobtitle] is already filled to capacity."
|
||||
return "Error: Unknown job availability."
|
||||
|
||||
/mob/dead/new_player/proc/IsJobUnavailable(rank)
|
||||
var/datum/job/job = SSjob.GetJob(rank)
|
||||
if(!job)
|
||||
return 0
|
||||
return JOB_UNAVAILABLE_GENERIC
|
||||
if((job.current_positions >= job.total_positions) && job.total_positions != -1)
|
||||
if(job.title == "Assistant")
|
||||
if(isnum(client.player_age) && client.player_age <= 14) //Newbies can always be assistants
|
||||
return 1
|
||||
return JOB_AVAILABLE
|
||||
for(var/datum/job/J in SSjob.occupations)
|
||||
if(J && J.current_positions < J.total_positions && J.title != job.title)
|
||||
return 0
|
||||
return JOB_UNAVAILABLE_SLOTFULL
|
||||
else
|
||||
return 0
|
||||
return JOB_UNAVAILABLE_SLOTFULL
|
||||
if(jobban_isbanned(src,rank))
|
||||
return 0
|
||||
if(!job.player_old_enough(src.client))
|
||||
return 0
|
||||
return JOB_UNAVAILABLE_BANNED
|
||||
if(!job.player_old_enough(client))
|
||||
return JOB_UNAVAILABLE_ACCOUNTAGE
|
||||
if(job.required_playtime_remaining(client))
|
||||
return 0
|
||||
return 1
|
||||
|
||||
return JOB_UNAVAILABLE_PLAYTIME
|
||||
return JOB_AVAILABLE
|
||||
|
||||
/mob/dead/new_player/proc/AttemptLateSpawn(rank)
|
||||
if(!IsJobAvailable(rank))
|
||||
alert(src, "[rank] is not available. Please try another.")
|
||||
var/error = IsJobUnavailable(rank)
|
||||
if(error != JOB_AVAILABLE)
|
||||
alert(src, get_job_unavailable_error_message(error, rank))
|
||||
return FALSE
|
||||
|
||||
if(SSticker.late_join_disabled)
|
||||
@@ -405,7 +421,7 @@
|
||||
|
||||
var/available_job_count = 0
|
||||
for(var/datum/job/job in SSjob.occupations)
|
||||
if(job && IsJobAvailable(job.title))
|
||||
if(job && IsJobUnavailable(job.title) == JOB_AVAILABLE)
|
||||
available_job_count++;
|
||||
|
||||
|
||||
@@ -428,7 +444,7 @@
|
||||
dat += "<div class='jobs'><div class='jobsColumn'>"
|
||||
var/job_count = 0
|
||||
for(var/datum/job/job in SSjob.occupations)
|
||||
if(job && IsJobAvailable(job.title))
|
||||
if(job && IsJobUnavailable(job.title) == JOB_AVAILABLE)
|
||||
job_count++;
|
||||
if (job_count > round(available_job_count / 2))
|
||||
dat += "</div><div class='jobsColumn'>"
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
//Blood regeneration if there is some space
|
||||
if(blood_volume < BLOOD_VOLUME_NORMAL)
|
||||
blood_volume += 0.1 // regenerate blood VERY slowly
|
||||
if(blood_volume < BLOOD_VOLUME_OKAY)
|
||||
adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.02, 1))
|
||||
|
||||
// Takes care blood loss and regeneration
|
||||
/mob/living/carbon/human/handle_blood()
|
||||
|
||||
@@ -63,7 +63,7 @@ Doesn't work on other aliens/AI.*/
|
||||
var/obj/machinery/atmospherics/components/unary/atmos_thing = locate() in user.loc
|
||||
if(atmos_thing)
|
||||
var/rusure = alert(user, "Laying eggs and shaping resin here would block access to [atmos_thing]. Do you want to continue?", "Blocking Atmospheric Component", "Yes", "No")
|
||||
if(rusure != "No")
|
||||
if(rusure != "Yes")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -169,9 +169,9 @@
|
||||
var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors
|
||||
var/turf/end_T = get_turf(target)
|
||||
if(start_T && end_T)
|
||||
var/start_T_descriptor = "<font color='#6b5d00'>tile at [start_T.x], [start_T.y], [start_T.z] in area [get_area(start_T)]</font>"
|
||||
var/end_T_descriptor = "<font color='#6b4400'>tile at [end_T.x], [end_T.y], [end_T.z] in area [get_area(end_T)]</font>"
|
||||
add_logs(src, throwable_mob, "thrown", addition="from [start_T_descriptor] with the target [end_T_descriptor]")
|
||||
var/start_T_descriptor = "tile in [get_area_name(start_T, TRUE)] ([start_T.x],[start_T.y],[start_T.z])"
|
||||
var/end_T_descriptor = "tile at [get_area_name(end_T, TRUE)] ([end_T.x],[end_T.y],[end_T.z])"
|
||||
add_logs(src, throwable_mob, "thrown", addition="grab from [start_T_descriptor] towards [end_T_descriptor]")
|
||||
|
||||
else if(!(I.flags_1 & (NODROP_1|ABSTRACT_1)))
|
||||
thrown_thing = I
|
||||
@@ -185,7 +185,7 @@
|
||||
|
||||
if(thrown_thing)
|
||||
visible_message("<span class='danger'>[src] has thrown [thrown_thing].</span>")
|
||||
add_logs(src, thrown_thing, "has thrown")
|
||||
add_logs(src, thrown_thing, "thrown")
|
||||
newtonian_move(get_dir(target, src))
|
||||
thrown_thing.throw_at(target, thrown_thing.throw_range, thrown_thing.throw_speed, src)
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
if(movement_type & FLYING)
|
||||
return 0
|
||||
if(!(lube&SLIDE_ICE))
|
||||
add_logs(src,, "slipped",, "on [O ? O.name : "floor"]")
|
||||
add_logs(src, (O ? O : get_turf(src)), "slipped on the", null, ((lube & SLIDE) ? "(LUBE)" : null))
|
||||
return loc.handle_slip(src, knockdown_amount, O, lube)
|
||||
|
||||
/mob/living/carbon/Process_Spacemove(movement_dir = 0)
|
||||
|
||||
@@ -647,6 +647,9 @@
|
||||
for(var/X in bodyparts)
|
||||
var/obj/item/bodypart/LB = X
|
||||
missing -= LB.body_zone
|
||||
if(LB.is_pseudopart) //don't show injury text for fake bodyparts; ie chainsaw arms or synthetic armblades
|
||||
continue
|
||||
var/limb_max_damage = LB.max_damage
|
||||
var/status = ""
|
||||
var/brutedamage = LB.brute_dam
|
||||
var/burndamage = LB.burn_dam
|
||||
@@ -663,20 +666,21 @@
|
||||
|
||||
else
|
||||
if(brutedamage > 0)
|
||||
status = "bruised"
|
||||
if(brutedamage > 20)
|
||||
status = "battered"
|
||||
if(brutedamage > 40)
|
||||
status = "mangled"
|
||||
status = LB.light_brute_msg
|
||||
if(brutedamage > (limb_max_damage*0.4))
|
||||
status = LB.medium_brute_msg
|
||||
if(brutedamage > (limb_max_damage*0.8))
|
||||
status = LB.heavy_brute_msg
|
||||
if(brutedamage > 0 && burndamage > 0)
|
||||
status += " and "
|
||||
if(burndamage > 40)
|
||||
status += "peeling away"
|
||||
|
||||
else if(burndamage > 10)
|
||||
status += "blistered"
|
||||
if(burndamage > (limb_max_damage*0.8))
|
||||
status += LB.heavy_burn_msg
|
||||
else if(burndamage > (limb_max_damage*0.2))
|
||||
status += LB.medium_burn_msg
|
||||
else if(burndamage > 0)
|
||||
status += "numb"
|
||||
status += LB.light_burn_msg
|
||||
|
||||
if(status == "")
|
||||
status = "OK"
|
||||
var/no_damage
|
||||
|
||||
@@ -618,23 +618,25 @@
|
||||
return pick("trails_1", "trails_2")
|
||||
|
||||
/mob/living/experience_pressure_difference(pressure_difference, direction, pressure_resistance_prob_delta = 0)
|
||||
if (client && client.move_delay >= world.time + world.tick_lag*2)
|
||||
if(buckled)
|
||||
return
|
||||
if(client && client.move_delay >= world.time + world.tick_lag*2)
|
||||
pressure_resistance_prob_delta -= 30
|
||||
|
||||
var/list/turfs_to_check = list()
|
||||
|
||||
if (has_limbs)
|
||||
if(has_limbs)
|
||||
var/turf/T = get_step(src, angle2dir(dir2angle(direction)+90))
|
||||
if (T)
|
||||
turfs_to_check += T
|
||||
|
||||
T = get_step(src, angle2dir(dir2angle(direction)-90))
|
||||
if (T)
|
||||
if(T)
|
||||
turfs_to_check += T
|
||||
|
||||
for (var/t in turfs_to_check)
|
||||
for(var/t in turfs_to_check)
|
||||
T = t
|
||||
if (T.density)
|
||||
if(T.density)
|
||||
pressure_resistance_prob_delta -= 20
|
||||
continue
|
||||
for (var/atom/movable/AM in T)
|
||||
@@ -760,10 +762,10 @@
|
||||
var/list/L = where
|
||||
if(what == who.get_item_for_held_index(L[2]))
|
||||
if(who.dropItemToGround(what))
|
||||
add_logs(src, who, "stripped", addition="of [what]")
|
||||
add_logs(src, who, "stripped [what] off")
|
||||
if(what == who.get_item_by_slot(where))
|
||||
if(who.dropItemToGround(what))
|
||||
add_logs(src, who, "stripped", addition="of [what]")
|
||||
add_logs(src, who, "stripped [what] off")
|
||||
|
||||
// The src mob is trying to place an item on someone
|
||||
// Override if a certain mob should be behave differently when placing items (can't, for example)
|
||||
|
||||
@@ -171,7 +171,7 @@
|
||||
if(incapacitated())
|
||||
return
|
||||
|
||||
var/icontype = input("Please, select a display!", "AI", null/*, null*/) in list("Clown", "Monochrome", "Blue", "Inverted", "Firewall", "Green", "Red", "Static", "Red October", "House", "Heartline", "Hades", "Helios", "President", "Syndicat Meow", "Alien", "Too Deep", "Triumvirate", "Triumvirate-M", "Text", "Matrix", "Dorf", "Bliss", "Not Malf", "Fuzzy", "Goon", "Database", "Glitchman", "Murica", "Nanotrasen", "Gentoo", "Angel")
|
||||
var/icontype = input("Please, select a display!", "AI", null/*, null*/) in list("Clown", "Monochrome", "Blue", "Inverted", "Firewall", "Green", "Red", "Static", "Red October", "House", "Heartline", "Hades", "Helios", "President", "Syndicat Meow", "Alien", "Too Deep", "Triumvirate", "Triumvirate-M", "Text", "Matrix", "Dorf", "Bliss", "Not Malf", "Fuzzy", "Goon", "Database", "Glitchman", "Murica", "Nanotrasen", "Gentoo", "Angel", "TechDemon") //CIT CHANGE - adds 'TechDemon
|
||||
if(icontype == "Clown")
|
||||
icon_state = "ai-clown2"
|
||||
else if(icontype == "Monochrome")
|
||||
@@ -236,7 +236,8 @@
|
||||
icon_state = "ai-gentoo"
|
||||
else if(icontype == "Angel")
|
||||
icon_state = "ai-angel"
|
||||
|
||||
else if(icontype == "TechDemon") //CIT CHANGE - adds 'TechDemon
|
||||
icon_state = "ai-techdemon"
|
||||
/mob/living/silicon/ai/Stat()
|
||||
..()
|
||||
if(statpanel("Status"))
|
||||
|
||||
@@ -159,6 +159,8 @@
|
||||
toner = tonermax
|
||||
diag_hud_set_borgcell()
|
||||
|
||||
verbs += /mob/living/proc/lay_down //CITADEL EDIT gimmie rest verb kthx
|
||||
|
||||
//If there's an MMI in the robot, have it ejected when the mob goes away. --NEO
|
||||
/mob/living/silicon/robot/Destroy()
|
||||
if(mmi && mind)//Safety for when a cyborg gets dust()ed. Or there is no MMI inside.
|
||||
|
||||
@@ -143,6 +143,7 @@ Difficulty: Very Hard
|
||||
INVOKE_ASYNC(src, .proc/spiral_shoot, TRUE)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/spiral_shoot(negative = FALSE, counter_start = 8)
|
||||
var/turf/start_turf = get_step(src, pick(GLOB.alldirs))
|
||||
var/counter = counter_start
|
||||
for(var/i in 1 to 80)
|
||||
if(negative)
|
||||
@@ -153,7 +154,7 @@ Difficulty: Very Hard
|
||||
counter = 1
|
||||
if(counter < 1)
|
||||
counter = 16
|
||||
shoot_projectile(null, counter * 22.5)
|
||||
shoot_projectile(start_turf, counter * 22.5)
|
||||
playsound(get_turf(src), 'sound/magic/clockwork/invoke_general.ogg', 20, 1)
|
||||
sleep(1)
|
||||
|
||||
@@ -184,7 +185,7 @@ Difficulty: Very Hard
|
||||
angle_to_target = set_angle
|
||||
var/static/list/colossus_shotgun_shot_angles = list(12.5, 7.5, 2.5, -2.5, -7.5, -12.5)
|
||||
for(var/i in colossus_shotgun_shot_angles)
|
||||
shoot_projectile(null, angle_to_target + i)
|
||||
shoot_projectile(target_turf, angle_to_target + i)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/dir_shots(list/dirs)
|
||||
if(!islist(dirs))
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/obj/item/device/modular_computer/attack_self(mob/user)
|
||||
. = ..()
|
||||
ui_interact(user)
|
||||
|
||||
// Operates TGUI
|
||||
/obj/item/device/modular_computer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
if(!enabled)
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
/obj/singularity/process()
|
||||
if(current_size >= STAGE_TWO)
|
||||
move()
|
||||
radiation_pulse(src, min(5000, (energy*3)+1000), RAD_DISTANCE_COEFFICIENT*0.5)
|
||||
radiation_pulse(src, min(5000, (energy*4.5)+1000), RAD_DISTANCE_COEFFICIENT*0.5)
|
||||
if(prob(event_chance))//Chance for it to run a special event TODO:Come up with one or two more that fit
|
||||
event()
|
||||
eat()
|
||||
|
||||
@@ -254,9 +254,7 @@
|
||||
current_user.setDir(SOUTH)
|
||||
if(226 to 315)
|
||||
current_user.setDir(WEST)
|
||||
var/difference = abs(lastangle - angle)
|
||||
if(difference > 350) //Too lazy to properly math, detects 360 --> 0 changes.
|
||||
difference = (lastangle > 350? ((360 - lastangle) + angle) : ((360 - angle) + lastangle))
|
||||
var/difference = abs(closer_angle_difference(lastangle, angle))
|
||||
delay_penalty(difference * aiming_time_increase_angle_multiplier)
|
||||
lastangle = angle
|
||||
|
||||
@@ -292,7 +290,7 @@
|
||||
current_user = null
|
||||
if(istype(user))
|
||||
current_user = user
|
||||
LAZYADD(current_user.mousemove_intercept_objects, src)
|
||||
LAZYOR(current_user.mousemove_intercept_objects, src)
|
||||
mobhook = user.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED), CALLBACK(src, .proc/on_mob_move))
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/onMouseDrag(src_object, over_object, src_location, over_location, params, mob)
|
||||
|
||||
@@ -46,8 +46,6 @@
|
||||
var/ricochets_max = 2
|
||||
var/ricochet_chance = 30
|
||||
|
||||
var/colliding = FALSE //pause processing..
|
||||
|
||||
//Hitscan
|
||||
var/hitscan = FALSE //Whether this is hitscan. If it is, speed is basically ignored.
|
||||
var/list/beam_segments //assoc list of datum/point or datum/point/vector, start = end. Used for hitscan effect generation.
|
||||
@@ -57,6 +55,15 @@
|
||||
var/muzzle_type
|
||||
var/impact_type
|
||||
|
||||
//Homing
|
||||
var/homing = FALSE
|
||||
var/atom/homing_target
|
||||
var/homing_turn_speed = 10 //Angle per tick.
|
||||
var/homing_inaccuracy_min = 0 //in pixels for these. offsets are set once when setting target.
|
||||
var/homing_inaccuracy_max = 0
|
||||
var/homing_offset_x = 0
|
||||
var/homing_offset_y = 0
|
||||
|
||||
var/ignore_source_check = FALSE
|
||||
|
||||
var/damage = 10
|
||||
@@ -192,7 +199,6 @@
|
||||
beam_segments[beam_index] = null
|
||||
|
||||
/obj/item/projectile/Collide(atom/A)
|
||||
colliding = TRUE
|
||||
var/datum/point/pcache = trajectory.copy_to()
|
||||
if(check_ricochet(A) && check_ricochet_flag(A) && ricochets < ricochets_max)
|
||||
ricochets++
|
||||
@@ -208,7 +214,6 @@
|
||||
trajectory_ignore_forcemove = TRUE
|
||||
forceMove(get_turf(A))
|
||||
trajectory_ignore_forcemove = FALSE
|
||||
colliding = FALSE
|
||||
return FALSE
|
||||
|
||||
var/distance = get_dist(get_turf(A), starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations.
|
||||
@@ -227,7 +232,6 @@
|
||||
trajectory_ignore_forcemove = TRUE
|
||||
forceMove(target_turf)
|
||||
trajectory_ignore_forcemove = FALSE
|
||||
colliding = FALSE
|
||||
return FALSE
|
||||
|
||||
var/permutation = A.bullet_act(src, def_zone) // searches for return value, could be deleted after run so check A isn't null
|
||||
@@ -237,17 +241,14 @@
|
||||
trajectory_ignore_forcemove = FALSE
|
||||
if(A)
|
||||
permutated.Add(A)
|
||||
colliding = FALSE
|
||||
return FALSE
|
||||
else
|
||||
var/atom/alt = select_target(A)
|
||||
if(alt)
|
||||
if(!prehit(alt))
|
||||
colliding = FALSE
|
||||
return FALSE
|
||||
alt.bullet_act(src, def_zone)
|
||||
qdel(src)
|
||||
colliding = FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/projectile/proc/select_target(atom/A) //Selects another target from a wall if we hit a wall.
|
||||
@@ -324,7 +325,7 @@
|
||||
/obj/item/projectile/proc/fire(angle, atom/direct_target)
|
||||
//If no angle needs to resolve it from xo/yo!
|
||||
if(!log_override && firer && original)
|
||||
add_logs(firer, original, "fired at", src, " [get_area(src)]")
|
||||
add_logs(firer, original, "fired at", src, "from [get_area_name(src, TRUE)]")
|
||||
if(direct_target)
|
||||
if(prehit(direct_target))
|
||||
direct_target.bullet_act(src, def_zone)
|
||||
@@ -350,7 +351,7 @@
|
||||
trajectory_ignore_forcemove = TRUE
|
||||
forceMove(starting)
|
||||
trajectory_ignore_forcemove = FALSE
|
||||
trajectory = new(starting.x, starting.y, starting.z, 0, 0, Angle, pixel_speed)
|
||||
trajectory = new(starting.x, starting.y, starting.z, pixel_x, pixel_y, Angle, pixel_speed)
|
||||
last_projectile_move = world.time
|
||||
fired = TRUE
|
||||
if(hitscan)
|
||||
@@ -417,6 +418,8 @@
|
||||
var/matrix/M = new
|
||||
M.Turn(Angle)
|
||||
transform = M
|
||||
if(homing)
|
||||
process_homing()
|
||||
trajectory.increment(trajectory_multiplier)
|
||||
var/turf/T = trajectory.return_turf()
|
||||
if(!istype(T))
|
||||
@@ -445,10 +448,32 @@
|
||||
Collide(original)
|
||||
Range()
|
||||
|
||||
/obj/item/projectile/proc/process_homing() //may need speeding up in the future performance wise.
|
||||
if(!homing_target)
|
||||
return FALSE
|
||||
var/datum/point/PT = RETURN_PRECISE_POINT(homing_target)
|
||||
PT.x += CLAMP(homing_offset_x, 1, world.maxx)
|
||||
PT.y += CLAMP(homing_offset_y, 1, world.maxy)
|
||||
var/angle = closer_angle_difference(Angle, angle_between_points(RETURN_PRECISE_POINT(src), PT))
|
||||
setAngle(Angle + CLAMP(angle, -homing_turn_speed, homing_turn_speed))
|
||||
|
||||
/obj/item/projectile/proc/set_homing_target(atom/A)
|
||||
if(!A || (!isturf(A) && !isturf(A.loc)))
|
||||
return FALSE
|
||||
homing = TRUE
|
||||
homing_target = A
|
||||
homing_offset_x = rand(homing_inaccuracy_min, homing_inaccuracy_max)
|
||||
homing_offset_y = rand(homing_inaccuracy_min, homing_inaccuracy_max)
|
||||
if(prob(50))
|
||||
homing_offset_x = -homing_offset_x
|
||||
if(prob(50))
|
||||
homing_offset_y = -homing_offset_y
|
||||
|
||||
//Returns true if the target atom is on our current turf and above the right layer
|
||||
/obj/item/projectile/proc/can_hit_target(atom/target, var/list/passthrough)
|
||||
return (target && ((target.layer >= PROJECTILE_HIT_THRESHHOLD_LAYER) || ismob(target)) && (loc == get_turf(target)) && (!(target in passthrough)))
|
||||
|
||||
//Spread is FORCED!
|
||||
/obj/item/projectile/proc/preparePixelProjectile(atom/target, atom/source, params, spread = 0)
|
||||
var/turf/curloc = get_turf(source)
|
||||
var/turf/targloc = get_turf(target)
|
||||
@@ -460,7 +485,7 @@
|
||||
if(targloc || !params)
|
||||
yo = targloc.y - curloc.y
|
||||
xo = targloc.x - curloc.x
|
||||
setAngle(Get_Angle(src, targloc))
|
||||
setAngle(Get_Angle(src, targloc) + spread)
|
||||
|
||||
//CIT CHANGES START HERE - makes it so laying down makes you unable to shoot through most objects
|
||||
if(iscarbon(source))
|
||||
@@ -474,14 +499,11 @@
|
||||
p_x = calculated[2]
|
||||
p_y = calculated[3]
|
||||
|
||||
if(spread)
|
||||
setAngle(calculated[1] + spread)
|
||||
else
|
||||
setAngle(calculated[1])
|
||||
setAngle(calculated[1] + spread)
|
||||
else if(targloc)
|
||||
yo = targloc.y - curloc.y
|
||||
xo = targloc.x - curloc.x
|
||||
setAngle(Get_Angle(src, targloc))
|
||||
setAngle(Get_Angle(src, targloc) + spread)
|
||||
else
|
||||
stack_trace("WARNING: Projectile [type] fired without either mouse parameters, or a target atom to aim at!")
|
||||
qdel(src)
|
||||
|
||||
@@ -159,11 +159,12 @@
|
||||
new_mob.invisibility = 0
|
||||
new_mob.job = "Cyborg"
|
||||
var/mob/living/silicon/robot/Robot = new_mob
|
||||
Robot.lawupdate = FALSE
|
||||
Robot.connected_ai = null
|
||||
Robot.mmi.transfer_identity(M) //Does not transfer key/client.
|
||||
Robot.clear_inherent_laws(0)
|
||||
Robot.clear_zeroth_law(0, 0)
|
||||
Robot.connected_ai = null
|
||||
|
||||
Robot.clear_zeroth_law(0)
|
||||
|
||||
if("slime")
|
||||
new_mob = new /mob/living/simple_animal/slime/random(M.loc)
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/obj/item/projectile/spellcard
|
||||
name = "enchanted card"
|
||||
desc = "A piece of paper enchanted to give it extreme durability and stiffness, along with a very hot burn to anyone unfortunate enough to get hit by a charged one."
|
||||
icon_state = "spellcard"
|
||||
damage_type = BURN
|
||||
damage = 2
|
||||
@@ -14,11 +14,12 @@
|
||||
var/obj/item/stock_parts/cell/cell
|
||||
var/powerefficiency = 0.1
|
||||
var/amount = 30
|
||||
var/recharged = 0
|
||||
var/recharge_delay = 5
|
||||
var/recharge_amount = 10
|
||||
var/recharge_counter = 0
|
||||
var/mutable_appearance/beaker_overlay
|
||||
var/working_state = "dispenser_working"
|
||||
var/nopower_state = "dispenser_nopower"
|
||||
var/has_panel_overlay = TRUE
|
||||
var/macrotier = 1
|
||||
var/obj/item/reagent_containers/beaker = null
|
||||
var/list/dispensable_reagents = list(
|
||||
@@ -62,7 +63,6 @@
|
||||
/obj/machinery/chem_dispenser/Initialize()
|
||||
. = ..()
|
||||
cell = new cell_type
|
||||
recharge()
|
||||
dispensable_reagents = sortList(dispensable_reagents)
|
||||
update_icon()
|
||||
|
||||
@@ -71,12 +71,21 @@
|
||||
QDEL_NULL(cell)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/chem_dispenser/examine(mob/user)
|
||||
..()
|
||||
if(panel_open)
|
||||
to_chat(user, "<span class='notice'>[src]'s maintenance hatch is open!</span>")
|
||||
|
||||
/obj/machinery/chem_dispenser/process()
|
||||
if(recharged < 0)
|
||||
recharge()
|
||||
recharged = recharge_delay
|
||||
else
|
||||
recharged -= 1
|
||||
if (recharge_counter >= 4)
|
||||
if(!is_operational())
|
||||
return
|
||||
var/usedpower = cell.give(recharge_amount)
|
||||
if(usedpower)
|
||||
use_power(250*recharge_amount)
|
||||
recharge_counter = 0
|
||||
return
|
||||
recharge_counter++
|
||||
|
||||
/obj/machinery/chem_dispenser/proc/display_beaker()
|
||||
..()
|
||||
@@ -91,23 +100,18 @@ obj/machinery/chem_dispenser/proc/work_animation()
|
||||
|
||||
/obj/machinery/chem_dispenser/power_change()
|
||||
..()
|
||||
if(!powered() && nopower_state)
|
||||
icon_state = nopower_state
|
||||
else
|
||||
icon_state = initial(icon_state)
|
||||
icon_state = "[(nopower_state && !powered()) ? nopower_state : initial(icon_state)]"
|
||||
|
||||
obj/machinery/chem_dispenser/update_icon()
|
||||
/obj/machinery/chem_dispenser/update_icon()
|
||||
cut_overlays()
|
||||
if(has_panel_overlay && panel_open)
|
||||
add_overlay(mutable_appearance(icon, "[initial(icon_state)]_panel-o"))
|
||||
|
||||
if(beaker)
|
||||
beaker_overlay = display_beaker()
|
||||
add_overlay(beaker_overlay)
|
||||
|
||||
/obj/machinery/chem_dispenser/proc/recharge()
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
return
|
||||
var/usedpower = cell.give( 1 / powerefficiency) //Should always be a gain of one on the UI.
|
||||
if(usedpower)
|
||||
use_power(2500)
|
||||
|
||||
|
||||
/obj/machinery/chem_dispenser/emag_act(mob/user)
|
||||
if(obj_flags & EMAGGED)
|
||||
@@ -188,23 +192,32 @@ obj/machinery/chem_dispenser/update_icon()
|
||||
return
|
||||
switch(action)
|
||||
if("amount")
|
||||
if(!is_operational())
|
||||
return
|
||||
var/target = text2num(params["target"])
|
||||
if(target in beaker.possible_transfer_amounts)
|
||||
amount = target
|
||||
work_animation()
|
||||
. = TRUE
|
||||
if("dispense")
|
||||
if(!is_operational() || QDELETED(cell))
|
||||
return
|
||||
var/reagent = params["reagent"]
|
||||
if(beaker && dispensable_reagents.Find(reagent))
|
||||
var/datum/reagents/R = beaker.reagents
|
||||
var/free = R.maximum_volume - R.total_volume
|
||||
var/actual = min(amount, (cell.charge * powerefficiency)*10, free)
|
||||
|
||||
if(!cell.use(actual / powerefficiency))
|
||||
say("Not enough energy to complete operation!")
|
||||
return
|
||||
R.add_reagent(reagent, actual)
|
||||
cell.use(actual / powerefficiency)
|
||||
|
||||
work_animation()
|
||||
. = TRUE
|
||||
if("remove")
|
||||
if(!is_operational())
|
||||
return
|
||||
var/amount = text2num(params["amount"])
|
||||
if(beaker && amount in beaker.possible_transfer_amounts)
|
||||
beaker.reagents.remove_all(amount)
|
||||
@@ -219,6 +232,8 @@ obj/machinery/chem_dispenser/update_icon()
|
||||
update_icon()
|
||||
. = TRUE
|
||||
if("dispense_recipe")
|
||||
if(!is_operational() || QDELETED(cell))
|
||||
return
|
||||
var/recipe_to_use = params["recipe"]
|
||||
var/list/chemicals_to_dispense = process_recipe_list(recipe_to_use)
|
||||
var/res = get_macro_resolution()
|
||||
@@ -230,16 +245,24 @@ obj/machinery/chem_dispenser/update_icon()
|
||||
var/free = R.maximum_volume - R.total_volume
|
||||
var/actual = min(round(chemicals_to_dispense[key], res), (cell.charge * powerefficiency)*10, free)
|
||||
if(actual)
|
||||
if(!cell.use(actual / powerefficiency))
|
||||
say("Not enough energy to complete operation!")
|
||||
return
|
||||
R.add_reagent(r_id, actual)
|
||||
cell.use(actual / powerefficiency)
|
||||
work_animation()
|
||||
if("clear_recipes")
|
||||
if(!is_operational())
|
||||
return
|
||||
var/yesno = alert("Clear all recipes?",, "Yes","No")
|
||||
if(yesno == "Yes")
|
||||
saved_recipes = list()
|
||||
if("add_recipe")
|
||||
if(!is_operational())
|
||||
return
|
||||
var/name = stripped_input(usr,"Name","What do you want to name this recipe?", "Recipe", MAX_NAME_LEN)
|
||||
var/recipe = stripped_input(usr,"Recipe","Insert recipe with chem IDs")
|
||||
if(!usr.canUseTopic(src, !issilicon(usr)))
|
||||
return
|
||||
if(name && recipe)
|
||||
var/list/first_process = splittext(recipe, ";")
|
||||
if(!LAZYLEN(first_process))
|
||||
@@ -265,7 +288,8 @@ obj/machinery/chem_dispenser/update_icon()
|
||||
/obj/machinery/chem_dispenser/attackby(obj/item/I, mob/user, params)
|
||||
if(default_unfasten_wrench(user, I))
|
||||
return
|
||||
if(default_deconstruction_screwdriver(user, "dispenser-o", "dispenser", I))
|
||||
if(default_deconstruction_screwdriver(user, icon_state, icon_state, I))
|
||||
update_icon()
|
||||
return
|
||||
|
||||
if(exchange_parts(user, I))
|
||||
@@ -313,15 +337,14 @@ obj/machinery/chem_dispenser/update_icon()
|
||||
|
||||
|
||||
/obj/machinery/chem_dispenser/RefreshParts()
|
||||
var/time = 0
|
||||
recharge_amount = initial(recharge_amount)
|
||||
var/newpowereff = 0.0666666
|
||||
for(var/obj/item/stock_parts/cell/P in component_parts)
|
||||
cell = P
|
||||
for(var/obj/item/stock_parts/matter_bin/M in component_parts)
|
||||
newpowereff += 0.0166666666*M.rating
|
||||
for(var/obj/item/stock_parts/capacitor/C in component_parts)
|
||||
time += C.rating
|
||||
recharge_delay = 30/(time/2) //delay between recharges, double the usual time on lowest 50% less than usual on highest
|
||||
recharge_amount *= C.rating
|
||||
for(var/obj/item/stock_parts/manipulator/M in component_parts)
|
||||
if (M.rating > macrotier)
|
||||
macrotier = M.rating
|
||||
@@ -386,6 +409,7 @@ obj/machinery/chem_dispenser/update_icon()
|
||||
anchored = TRUE
|
||||
icon = 'icons/obj/chemical.dmi'
|
||||
icon_state = "soda_dispenser"
|
||||
has_panel_overlay = FALSE
|
||||
amount = 10
|
||||
pixel_y = 6
|
||||
layer = WALL_OBJ_LAYER
|
||||
|
||||
@@ -73,12 +73,6 @@
|
||||
if (prob(50))
|
||||
qdel(src)
|
||||
|
||||
/obj/machinery/chem_master/power_change()
|
||||
if(powered())
|
||||
stat &= ~NOPOWER
|
||||
else
|
||||
stat |= NOPOWER
|
||||
|
||||
/obj/machinery/chem_master/attackby(obj/item/I, mob/user, params)
|
||||
if(default_deconstruction_screwdriver(user, "mixer0_nopower", "mixer0", I))
|
||||
return
|
||||
@@ -223,7 +217,7 @@
|
||||
return
|
||||
vol_each = min(reagents.total_volume / amount, 50)
|
||||
var/name = stripped_input(usr,"Name:","Name your pill!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN)
|
||||
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, BE_CLOSE))
|
||||
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
|
||||
return
|
||||
var/obj/item/reagent_containers/pill/P
|
||||
|
||||
@@ -237,7 +231,7 @@
|
||||
reagents.trans_to(P,vol_each)
|
||||
else
|
||||
var/name = stripped_input(usr, "Name:", "Name your pack!", reagents.get_master_reagent_name(), MAX_NAME_LEN)
|
||||
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, BE_CLOSE))
|
||||
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
|
||||
return
|
||||
var/obj/item/reagent_containers/food/condiment/pack/P = new/obj/item/reagent_containers/food/condiment/pack(drop_location())
|
||||
|
||||
@@ -259,7 +253,7 @@
|
||||
return
|
||||
vol_each = min(reagents.total_volume / amount, 40)
|
||||
var/name = stripped_input(usr,"Name:","Name your patch!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN)
|
||||
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, BE_CLOSE))
|
||||
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
|
||||
return
|
||||
var/obj/item/reagent_containers/pill/P
|
||||
|
||||
@@ -277,7 +271,7 @@
|
||||
|
||||
if(condi)
|
||||
var/name = stripped_input(usr, "Name:","Name your bottle!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN)
|
||||
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, BE_CLOSE))
|
||||
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
|
||||
return
|
||||
var/obj/item/reagent_containers/food/condiment/P = new(drop_location())
|
||||
P.originalname = name
|
||||
@@ -290,7 +284,7 @@
|
||||
amount_full = round(reagents.total_volume / 30)
|
||||
vol_part = reagents.total_volume % 30
|
||||
var/name = stripped_input(usr, "Name:","Name your bottle!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN)
|
||||
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, BE_CLOSE))
|
||||
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
|
||||
return
|
||||
|
||||
var/obj/item/reagent_containers/glass/bottle/P
|
||||
|
||||
@@ -615,7 +615,19 @@
|
||||
to_chat(M, "<span class = 'warning'>Your eyes sting!</span>")
|
||||
M.blind_eyes(2)
|
||||
|
||||
/datum/reagent/consumable/nutriment/stabilized
|
||||
name = "Stabilized Nutriment"
|
||||
id = "stabilizednutriment"
|
||||
description = "A bioengineered protien-nutrient structure designed to decompose in high saturation. In layman's terms, it won't get you fat."
|
||||
reagent_state = SOLID
|
||||
nutriment_factor = 15 * REAGENTS_METABOLISM
|
||||
color = "#664330" // rgb: 102, 67, 48
|
||||
|
||||
/datum/reagent/consumable/nutriment/stabilized/on_mob_life(mob/living/M)
|
||||
if(M.nutrition > NUTRITION_LEVEL_FULL - 25)
|
||||
M.nutrition -= 3*nutriment_factor
|
||||
..()
|
||||
|
||||
////Lavaland Flora Reagents////
|
||||
|
||||
|
||||
@@ -673,4 +685,4 @@
|
||||
description = "The sorrow and melancholy of a thousand bereaved clowns, forever denied their Honkmechs."
|
||||
nutriment_factor = 5 * REAGENTS_METABOLISM
|
||||
color = "#eef442" // rgb: 238, 244, 66
|
||||
taste_description = "mournful honking"
|
||||
taste_description = "mournful honking"
|
||||
|
||||
@@ -17,13 +17,17 @@ If you create T5+ please take a pass at gene_modder.dm [L40]. Max_values MUST fi
|
||||
display_contents_with_number = 1
|
||||
max_w_class = WEIGHT_CLASS_NORMAL
|
||||
max_combined_w_class = 100
|
||||
|
||||
can_hold = list(
|
||||
/obj/item/reagent_containers/glass/beaker,
|
||||
/obj/item/device/assembly/igniter,
|
||||
/obj/item/stock_parts,
|
||||
/obj/item/stack/ore/bluespace_crystal)
|
||||
|
||||
var/works_from_distance = 0
|
||||
var/pshoom_or_beepboopblorpzingshadashwoosh = 'sound/items/rped.ogg'
|
||||
var/alt_sound = null
|
||||
|
||||
/obj/item/storage/part_replacer/can_be_inserted(obj/item/W, stop_messages = 0, mob/user)
|
||||
return ..() && W.get_part_rating()
|
||||
|
||||
/obj/item/storage/part_replacer/afterattack(obj/machinery/T, mob/living/carbon/human/user, flag, params)
|
||||
if(flag)
|
||||
return
|
||||
|
||||
@@ -82,15 +82,13 @@
|
||||
var/mob/living/carbon/human/H = mover
|
||||
if(H.nutrition >= NUTRITION_LEVEL_FAT)
|
||||
H.visible_message("<span class='warning'>[H] pushes through [src]!</span>", "<span class='notice'>You've seen and eaten worse than this.</span>")
|
||||
return 1
|
||||
return TRUE
|
||||
else
|
||||
to_chat(H, "<span class='warning'>You're repulsed by even looking at [src]. Only a pig could force themselves to go through it.</span>")
|
||||
if(istype(mover, /mob/living/simple_animal/hostile/morph))
|
||||
return 1
|
||||
return TRUE
|
||||
else
|
||||
return 0
|
||||
|
||||
|
||||
return FALSE
|
||||
|
||||
/obj/structure/mirror/magic/pride //Pride's mirror: Used in the Pride ruin.
|
||||
name = "pride's mirror"
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
var/list/projectile_var_overrides = list()
|
||||
var/projectile_amount = 1 //Projectiles per cast.
|
||||
var/current_amount = 0 //How many projectiles left.
|
||||
var/projectiles_per_fire = 1 //Projectiles per fire. Probably not a good thing to use unless you override ready_projectile().
|
||||
|
||||
/obj/effect/proc_holder/spell/aimed/Click()
|
||||
var/mob/living/user = usr
|
||||
@@ -26,10 +27,18 @@
|
||||
charge_counter = charge_max * refund_percent
|
||||
start_recharge()
|
||||
remove_ranged_ability(msg)
|
||||
on_deactivation(user)
|
||||
else
|
||||
msg = "<span class='notice'>[active_msg]<B>Left-click to shoot it at a target!</B></span>"
|
||||
current_amount = projectile_amount
|
||||
add_ranged_ability(user, msg, TRUE)
|
||||
on_activation(user)
|
||||
|
||||
/obj/effect/proc_holder/spell/aimed/proc/on_activation(mob/user)
|
||||
return
|
||||
|
||||
/obj/effect/proc_holder/spell/aimed/proc/on_deactivation(mob/user)
|
||||
return
|
||||
|
||||
/obj/effect/proc_holder/spell/aimed/update_icon()
|
||||
if(!action)
|
||||
@@ -60,19 +69,25 @@
|
||||
remove_ranged_ability() //Auto-disable the ability once you run out of bullets.
|
||||
charge_counter = 0
|
||||
start_recharge()
|
||||
on_deactivation(user)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/spell/aimed/proc/fire_projectile(mob/living/user, atom/target)
|
||||
current_amount--
|
||||
var/obj/item/projectile/P = new projectile_type(user.loc)
|
||||
P.firer = user
|
||||
P.preparePixelProjectile(target, user)
|
||||
for(var/V in projectile_var_overrides)
|
||||
if(P.vars[V])
|
||||
P.vv_edit_var(V, projectile_var_overrides[V])
|
||||
P.fire()
|
||||
for(var/i in 1 to projectiles_per_fire)
|
||||
var/obj/item/projectile/P = new projectile_type(user.loc)
|
||||
P.firer = user
|
||||
P.preparePixelProjectile(target, user)
|
||||
for(var/V in projectile_var_overrides)
|
||||
if(P.vars[V])
|
||||
P.vv_edit_var(V, projectile_var_overrides[V])
|
||||
ready_projectile(P, target, user, i)
|
||||
P.fire()
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/spell/aimed/proc/ready_projectile(obj/item/projectile/P, atom/target, mob/user, iteration)
|
||||
return
|
||||
|
||||
/obj/effect/proc_holder/spell/aimed/lightningbolt
|
||||
name = "Lightning Bolt"
|
||||
desc = "Fire a high powered lightning bolt at your foes!"
|
||||
@@ -108,3 +123,58 @@
|
||||
active_msg = "You prepare to cast your fireball spell!"
|
||||
deactive_msg = "You extinguish your fireball... for now."
|
||||
active = FALSE
|
||||
|
||||
/obj/effect/proc_holder/spell/aimed/spell_cards
|
||||
name = "Spell Cards"
|
||||
desc = "Blazing hot rapid-fire homing cards. Banish your foes with its mystical power!"
|
||||
school = "evocation"
|
||||
charge_max = 50
|
||||
clothes_req = 0
|
||||
invocation = "Sigi'lu M'Fan 'Tasia"
|
||||
invocation_type = "shout"
|
||||
range = 40
|
||||
cooldown_min = 10
|
||||
projectile_amount = 5
|
||||
projectiles_per_fire = 7
|
||||
projectile_type = /obj/item/projectile/spellcard
|
||||
var/datum/weakref/current_target_weakref
|
||||
var/projectile_turnrate = 10
|
||||
var/projectile_pixel_homing_spread = 32
|
||||
var/projectile_initial_spread_amount = 30
|
||||
var/projectile_location_spread_amount = 12
|
||||
var/datum/component/lockon_aiming/lockon_component
|
||||
ranged_clickcd_override = 1
|
||||
|
||||
/obj/effect/proc_holder/spell/aimed/spell_cards/on_activation(mob/M)
|
||||
QDEL_NULL(lockon_component)
|
||||
lockon_component = M.AddComponent(/datum/component/lockon_aiming, 5, typecacheof(list(/mob/living)), 1, null, CALLBACK(src, .proc/on_lockon_component))
|
||||
|
||||
/obj/effect/proc_holder/spell/aimed/spell_cards/proc/on_lockon_component(list/locked_weakrefs)
|
||||
if(!length(locked_weakrefs))
|
||||
current_target_weakref = null
|
||||
return
|
||||
current_target_weakref = locked_weakrefs[1]
|
||||
var/atom/A = current_target_weakref.resolve()
|
||||
if(A)
|
||||
var/mob/M = lockon_component.parent
|
||||
M.face_atom(A)
|
||||
|
||||
/obj/effect/proc_holder/spell/aimed/spell_cards/on_deactivation(mob/M)
|
||||
QDEL_NULL(lockon_component)
|
||||
|
||||
/obj/effect/proc_holder/spell/aimed/spell_cards/ready_projectile(obj/item/projectile/P, atom/target, mob/user, iteration)
|
||||
if(current_target_weakref)
|
||||
var/atom/A = current_target_weakref.resolve()
|
||||
if(A && get_dist(A, user) < 7)
|
||||
P.homing_turn_speed = projectile_turnrate
|
||||
P.homing_inaccuracy_min = projectile_pixel_homing_spread
|
||||
P.homing_inaccuracy_max = projectile_pixel_homing_spread
|
||||
P.set_homing_target(current_target_weakref.resolve())
|
||||
var/rand_spr = rand()
|
||||
var/total_angle = projectile_initial_spread_amount * 2
|
||||
var/adjusted_angle = total_angle - ((projectile_initial_spread_amount / projectiles_per_fire) * 0.5)
|
||||
var/one_fire_angle = adjusted_angle / projectiles_per_fire
|
||||
var/current_angle = iteration * one_fire_angle * rand_spr - (projectile_initial_spread_amount / 2)
|
||||
P.pixel_x = rand(-projectile_location_spread_amount, projectile_location_spread_amount)
|
||||
P.pixel_y = rand(-projectile_location_spread_amount, projectile_location_spread_amount)
|
||||
P.preparePixelProjectile(target, user, null, current_angle)
|
||||
|
||||
@@ -43,6 +43,15 @@
|
||||
var/species_flags_list = list()
|
||||
var/dmg_overlay_type //the type of damage overlay (if any) to use when this bodypart is bruised/burned.
|
||||
|
||||
//Damage messages used by help_shake_act()
|
||||
var/light_brute_msg = "bruised"
|
||||
var/medium_brute_msg = "battered"
|
||||
var/heavy_brute_msg = "mangled"
|
||||
|
||||
var/light_burn_msg = "numb"
|
||||
var/medium_burn_msg = "blistered"
|
||||
var/heavy_burn_msg = "peeling away"
|
||||
|
||||
/obj/item/bodypart/examine(mob/user)
|
||||
..()
|
||||
if(brute_dam > 0)
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
#define ROBOTIC_LIGHT_BRUTE_MSG "marred"
|
||||
#define ROBOTIC_MEDIUM_BRUTE_MSG "dented"
|
||||
#define ROBOTIC_HEAVY_BRUTE_MSG "falling apart"
|
||||
|
||||
#define ROBOTIC_LIGHT_BURN_MSG "scorched"
|
||||
#define ROBOTIC_MEDIUM_BURN_MSG "charred"
|
||||
#define ROBOTIC_HEAVY_BURN_MSG "smoldering"
|
||||
|
||||
/obj/item/bodypart/l_arm/robot
|
||||
name = "cyborg left arm"
|
||||
@@ -10,6 +16,13 @@
|
||||
icon_state = "borg_l_arm"
|
||||
status = BODYPART_ROBOTIC
|
||||
|
||||
light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG
|
||||
medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG
|
||||
heavy_brute_msg = ROBOTIC_HEAVY_BRUTE_MSG
|
||||
|
||||
light_burn_msg = ROBOTIC_LIGHT_BURN_MSG
|
||||
medium_burn_msg = ROBOTIC_MEDIUM_BURN_MSG
|
||||
heavy_burn_msg = ROBOTIC_HEAVY_BURN_MSG
|
||||
|
||||
/obj/item/bodypart/r_arm/robot
|
||||
name = "cyborg right arm"
|
||||
@@ -21,6 +34,13 @@
|
||||
icon_state = "borg_r_arm"
|
||||
status = BODYPART_ROBOTIC
|
||||
|
||||
light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG
|
||||
medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG
|
||||
heavy_brute_msg = ROBOTIC_HEAVY_BRUTE_MSG
|
||||
|
||||
light_burn_msg = ROBOTIC_LIGHT_BURN_MSG
|
||||
medium_burn_msg = ROBOTIC_MEDIUM_BURN_MSG
|
||||
heavy_burn_msg = ROBOTIC_HEAVY_BURN_MSG
|
||||
|
||||
/obj/item/bodypart/l_leg/robot
|
||||
name = "cyborg left leg"
|
||||
@@ -32,6 +52,13 @@
|
||||
icon_state = "borg_l_leg"
|
||||
status = BODYPART_ROBOTIC
|
||||
|
||||
light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG
|
||||
medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG
|
||||
heavy_brute_msg = ROBOTIC_HEAVY_BRUTE_MSG
|
||||
|
||||
light_burn_msg = ROBOTIC_LIGHT_BURN_MSG
|
||||
medium_burn_msg = ROBOTIC_MEDIUM_BURN_MSG
|
||||
heavy_burn_msg = ROBOTIC_HEAVY_BURN_MSG
|
||||
|
||||
/obj/item/bodypart/r_leg/robot
|
||||
name = "cyborg right leg"
|
||||
@@ -43,6 +70,13 @@
|
||||
icon_state = "borg_r_leg"
|
||||
status = BODYPART_ROBOTIC
|
||||
|
||||
light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG
|
||||
medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG
|
||||
heavy_brute_msg = ROBOTIC_HEAVY_BRUTE_MSG
|
||||
|
||||
light_burn_msg = ROBOTIC_LIGHT_BURN_MSG
|
||||
medium_burn_msg = ROBOTIC_MEDIUM_BURN_MSG
|
||||
heavy_burn_msg = ROBOTIC_HEAVY_BURN_MSG
|
||||
|
||||
/obj/item/bodypart/chest/robot
|
||||
name = "cyborg torso"
|
||||
@@ -52,6 +86,15 @@
|
||||
flags_1 = CONDUCT_1
|
||||
icon_state = "borg_chest"
|
||||
status = BODYPART_ROBOTIC
|
||||
|
||||
light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG
|
||||
medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG
|
||||
heavy_brute_msg = ROBOTIC_HEAVY_BRUTE_MSG
|
||||
|
||||
light_burn_msg = ROBOTIC_LIGHT_BURN_MSG
|
||||
medium_burn_msg = ROBOTIC_MEDIUM_BURN_MSG
|
||||
heavy_burn_msg = ROBOTIC_HEAVY_BURN_MSG
|
||||
|
||||
var/wired = 0
|
||||
var/obj/item/stock_parts/cell/cell = null
|
||||
|
||||
@@ -102,6 +145,15 @@
|
||||
flags_1 = CONDUCT_1
|
||||
icon_state = "borg_head"
|
||||
status = BODYPART_ROBOTIC
|
||||
|
||||
light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG
|
||||
medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG
|
||||
heavy_brute_msg = ROBOTIC_HEAVY_BRUTE_MSG
|
||||
|
||||
light_burn_msg = ROBOTIC_LIGHT_BURN_MSG
|
||||
medium_burn_msg = ROBOTIC_MEDIUM_BURN_MSG
|
||||
heavy_burn_msg = ROBOTIC_HEAVY_BURN_MSG
|
||||
|
||||
var/obj/item/device/assembly/flash/handheld/flash1 = null
|
||||
var/obj/item/device/assembly/flash/handheld/flash2 = null
|
||||
|
||||
@@ -189,3 +241,12 @@
|
||||
icon = 'icons/mob/augmentation/surplus_augments.dmi'
|
||||
icon_state = "r_leg"
|
||||
max_damage = 20
|
||||
|
||||
|
||||
#undef ROBOTIC_LIGHT_BRUTE_MSG
|
||||
#undef ROBOTIC_MEDIUM_BRUTE_MSG
|
||||
#undef ROBOTIC_HEAVY_BRUTE_MSG
|
||||
|
||||
#undef ROBOTIC_LIGHT_BURN_MSG
|
||||
#undef ROBOTIC_MEDIUM_BURN_MSG
|
||||
#undef ROBOTIC_HEAVY_BURN_MSG
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
user.visible_message("[user] drapes [I] over [M]'s [parse_zone(selected_zone)] to prepare for \an [procedure.name].", \
|
||||
"<span class='notice'>You drape [I] over [M]'s [parse_zone(selected_zone)] to prepare for \an [procedure.name].</span>")
|
||||
|
||||
add_logs(user, M, "operated", addition="Operation type: [procedure.name], location: [selected_zone]")
|
||||
add_logs(user, M, "operated on", null, "(OPERATION TYPE: [procedure.name]) (TARGET AREA: [selected_zone])")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You need to expose [M]'s [parse_zone(selected_zone)] first!</span>")
|
||||
|
||||
|
||||
@@ -46,7 +46,6 @@
|
||||
see_in_dark = 8
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
|
||||
actions_types = list(/datum/action/item_action/organ_action/use)
|
||||
sight_flags = SEE_BLACKNESS
|
||||
var/night_vision = TRUE
|
||||
|
||||
/obj/item/organ/eyes/night_vision/ui_action_click()
|
||||
|
||||
Reference in New Issue
Block a user