diff --git a/code/datums/mutations.dm b/code/datums/mutations.dm index 6129bdce06e..2e5145df3e4 100644 --- a/code/datums/mutations.dm +++ b/code/datums/mutations.dm @@ -52,7 +52,7 @@ . = on_losing(owner) /datum/mutation/human/proc/on_acquiring(mob/living/carbon/human/owner) - if(!owner || !istype(owner) || (src in owner.dna.mutations)) + if(!owner || !istype(owner) || owner.stat == DEAD || (src in owner.dna.mutations)) return 1 if(species_allowed.len && !species_allowed.Find(owner.dna.species.id)) return 1 @@ -87,7 +87,7 @@ /datum/mutation/human/proc/on_losing(mob/living/carbon/human/owner) if(owner && istype(owner) && (owner.dna.mutations.Remove(src))) - if(text_lose_indication) + if(text_lose_indication && owner.stat != DEAD) owner << text_lose_indication if(visual_indicators.len) var/list/mut_overlay = list() @@ -381,7 +381,7 @@ . = owner.monkeyize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_KEEPSE) /datum/mutation/human/race/on_losing(mob/living/carbon/monkey/owner) - if(owner && istype(owner) && (owner.dna.mutations.Remove(src))) + if(owner && istype(owner) && owner.stat != DEAD && (owner.dna.mutations.Remove(src))) . = owner.humanize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_KEEPSE) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 373d98c3b36..478f87827f4 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -280,22 +280,22 @@ var/list/blood_splatter_icons = list() //returns 1 if made bloody, returns 0 otherwise /atom/proc/add_blood(mob/living/carbon/M) + if(!M || !M.has_dna() || rejects_blood()) + return 0 if(ishuman(M)) var/mob/living/carbon/human/H = M if(NOBLOOD in H.dna.species.specflags) return 0 - if(rejects_blood() || !M.has_dna()) - return 0 return 1 /obj/add_blood(mob/living/carbon/M) - if(..() == 0) + if(!..()) return 0 return add_blood_list(M) /obj/item/add_blood(mob/living/carbon/M) - var/blood_count = blood_DNA == null ? 0 : blood_DNA.len - if(..() == 0) + var/blood_count = !blood_DNA ? 0 : blood_DNA.len + if(!..()) return 0 //apply the blood-splatter overlay if it isn't already in there if(!blood_count && initial(icon) && initial(icon_state)) @@ -312,14 +312,14 @@ var/list/blood_splatter_icons = list() return 1 //we applied blood to the item /obj/item/clothing/gloves/add_blood(mob/living/carbon/M) - if(..() == 0) + if(!..()) return 0 transfer_blood = rand(2, 4) bloody_hands_mob = M return 1 /turf/simulated/add_blood(mob/living/carbon/human/M) - if(..() == 0) + if(!..()) return 0 var/obj/effect/decal/cleanable/blood/B = locate() in contents //check for existing blood splatter @@ -330,7 +330,7 @@ var/list/blood_splatter_icons = list() return 1 //we bloodied the floor /mob/living/carbon/human/add_blood(mob/living/carbon/M) - if(..() == 0) + if(!..()) return 0 add_blood_list(M) bloody_hands = rand(2, 4) diff --git a/code/game/gamemodes/meteor/meteors.dm b/code/game/gamemodes/meteor/meteors.dm index 2ddf8698ca5..0924648d33f 100644 --- a/code/game/gamemodes/meteor/meteors.dm +++ b/code/game/gamemodes/meteor/meteors.dm @@ -237,8 +237,7 @@ ..(heavy) explosion(src.loc, 0, 0, 4, 3, 0) new /obj/effect/decal/cleanable/greenglow(get_turf(src)) - for(var/mob/living/L in view(5, src)) - L.irradiate(40) + radiation_pulse(get_turf(src), 2, 5, 50, 1) //Meaty Ore /obj/effect/meteor/meaty diff --git a/code/game/machinery/computer/dna_console.dm b/code/game/machinery/computer/dna_console.dm index 5de7d5b4adb..4f00df16887 100644 --- a/code/game/machinery/computer/dna_console.dm +++ b/code/game/machinery/computer/dna_console.dm @@ -84,7 +84,7 @@ switch(viable_occupant.stat) if(CONSCIOUS) occupant_status += "Conscious" if(UNCONSCIOUS) occupant_status += "Unconscious" - else occupant_status += "DEAD - Cannot Operate" + else occupant_status += "DEAD" occupant_status += "" occupant_status += "
Health:
[viable_occupant.health] %
" occupant_status += "
Radiation Level:
[viable_occupant.radiation] %
" @@ -95,8 +95,6 @@ else viable_occupant = null occupant_status += "Invalid DNA structure" - if (viable_occupant && viable_occupant.stat == DEAD) - viable_occupant = null // No editing the dead. else occupant_status += "No subject detected" @@ -202,7 +200,7 @@ temp_html += "
\tUI: No Data" if(se) temp_html += "
\tSE: [se] " - if(viable_occupant && viable_occupant.stat != DEAD) temp_html += "Occupant " + if(viable_occupant) temp_html += "Occupant " else temp_html += "Occupant " if(injectorready) temp_html += "Injector" else temp_html += "Injector" @@ -327,7 +325,7 @@ if(istype(buffer_slot)) buffer_slot.Cut() if("transferbuffer") - if(num && viable_occupant && viable_occupant.stat != DEAD) + if(num && viable_occupant) num = Clamp(num, 1, NUMBER_OF_BUFFERS) var/list/buffer_slot = buffer[num] if(istype(buffer_slot)) //15 and 40 are just magic numbers that were here before so i didnt touch them, they are initial boundaries of damage @@ -394,7 +392,7 @@ diskette.loc = get_turf(src) diskette = null if("pulseui","pulsese") - if(num && viable_occupant && connected && viable_occupant.stat != DEAD) + if(num && viable_occupant && connected) radduration = Wrap(radduration, 1, RADIATION_DURATION_MAX+1) radstrength = Wrap(radstrength, 1, RADIATION_STRENGTH_MAX+1) diff --git a/code/game/machinery/doors/airlock_types.dm b/code/game/machinery/doors/airlock_types.dm index e703f41c727..ba606e037ec 100644 --- a/code/game/machinery/doors/airlock_types.dm +++ b/code/game/machinery/doors/airlock_types.dm @@ -146,8 +146,7 @@ ..() /obj/machinery/door/airlock/uranium/proc/radiate() - for(var/mob/living/L in range (3,src)) - L.irradiate(15) + radiation_pulse(get_turf(src), 3, 3, 15, 0) return /obj/machinery/door/airlock/plasma diff --git a/code/game/mecha/equipment/tools/other_tools.dm b/code/game/mecha/equipment/tools/other_tools.dm index ac8c7e541d5..531f20faa01 100644 --- a/code/game/mecha/equipment/tools/other_tools.dm +++ b/code/game/mecha/equipment/tools/other_tools.dm @@ -500,10 +500,6 @@ /obj/item/mecha_parts/mecha_equipment/generator/nuclear/process() if(..()) - for(var/mob/living/carbon/M in view(chassis)) - if(istype(M,/mob/living/carbon/human)) - M.irradiate(rad_per_cycle*3) - else - M.irradiate(rad_per_cycle) + radiation_pulse(get_turf(src), 2, 7, rad_per_cycle, 1) diff --git a/code/game/mecha/mecha_control_console.dm b/code/game/mecha/mecha_control_console.dm index cbd9075f608..ab7641dd681 100644 --- a/code/game/mecha/mecha_control_console.dm +++ b/code/game/mecha/mecha_control_console.dm @@ -77,7 +77,7 @@ Airtank: [M.return_pressure()]kPa
Pilot: [M.occupant||"None"]
Location: [get_area(M)||"Unknown"]
- Active equipment: [M.selected||"None"]"} + Active equipment: [M.selected||"None"]
"} if(istype(M, /obj/mecha/working/ripley)) var/obj/mecha/working/ripley/RM = M answer += "Used cargo space: [RM.cargo.len/RM.cargo_capacity*100]%
" diff --git a/code/game/objects/items/devices/traitordevices.dm b/code/game/objects/items/devices/traitordevices.dm index f77c8951f4f..3e081af2025 100644 --- a/code/game/objects/items/devices/traitordevices.dm +++ b/code/game/objects/items/devices/traitordevices.dm @@ -98,7 +98,7 @@ effective or pretty fucking useless. if(M) if(intensity >= 5) M.apply_effect(round(intensity/1.5), PARALYZE) - M.irradiate(intensity*10) + M.rad_act(intensity*10) else user << "The radioactive microlaser is still recharging." diff --git a/code/game/objects/items/nuke_tools.dm b/code/game/objects/items/nuke_tools.dm index ee10b83dbc9..f8a0a093a12 100644 --- a/code/game/objects/items/nuke_tools.dm +++ b/code/game/objects/items/nuke_tools.dm @@ -23,8 +23,7 @@ if(cooldown < world.time - 60) cooldown = world.time flick("plutonium_core_pulse", src) - for(var/mob/living/L in range(4,get_turf(src))) - L.irradiate(40) + radiation_pulse(get_turf(src), 1, 4, 40, 1) //nuke core box, for carrying the core /obj/item/nuke_core_container diff --git a/code/game/objects/items/weapons/dna_injector.dm b/code/game/objects/items/weapons/dna_injector.dm index 660a7dd078a..e94ac89b828 100644 --- a/code/game/objects/items/weapons/dna_injector.dm +++ b/code/game/objects/items/weapons/dna_injector.dm @@ -18,9 +18,6 @@ /obj/item/weapon/dnainjector/proc/inject(mob/living/carbon/M, mob/user) if(M.has_dna() && !(M.disabilities & NOCLONE)) - if(M.stat == DEAD) //prevents dead people from having their DNA changed - user << "You can't modify [M]'s DNA while \he's dead." - return M.radiation += rand(20/(damage_coeff ** 2),50/(damage_coeff ** 2)) var/log_msg = "[key_name(user)] injected [key_name(M)] with the [name]" for(var/datum/mutation/human/HM in remove_mutations) diff --git a/code/game/objects/radiation.dm b/code/game/objects/radiation.dm new file mode 100644 index 00000000000..2498b6fe825 --- /dev/null +++ b/code/game/objects/radiation.dm @@ -0,0 +1,35 @@ +/proc/radiation_pulse(turf/epicenter, heavy_range, light_range, severity, log=0) + if(!epicenter) return + + if(!istype(epicenter, /turf)) + epicenter = get_turf(epicenter.loc) + + if(log) + message_admins("Radiation pulse with size ([heavy_range], [light_range]) and severity [severity] in area [epicenter.loc.name] ") + log_game("Radiation pulse with size ([heavy_range], [light_range]) and severity [severity] in area [epicenter.loc.name] ") + + if(heavy_range > light_range) + light_range = heavy_range + + for(var/atom/T in range(light_range, epicenter)) + var/distance = get_dist(epicenter, T) + if(distance < 0) + distance = 0 + if(distance < heavy_range) + T.rad_act(severity) + else if(distance == heavy_range) + if(prob(50)) + T.rad_act(severity) + else + T.rad_act(severity / 2) + else if(distance <= light_range) + T.rad_act(severity / 2) + return 1 + +/atom/proc/rad_act(var/severity) + return 1 + +/mob/living/rad_act(amount) + if(amount) + var/blocked = run_armor_check(null, "rad", "Your clothes feel warm.", "Your clothes feel warm.") + apply_effect(amount, IRRADIATE, blocked) diff --git a/code/game/objects/structures/false_walls.dm b/code/game/objects/structures/false_walls.dm index d5534842ddb..188911cc2a0 100644 --- a/code/game/objects/structures/false_walls.dm +++ b/code/game/objects/structures/false_walls.dm @@ -169,8 +169,7 @@ if(!active) if(world.time > last_event+15) active = 1 - for(var/mob/living/L in range(3,src)) - L.irradiate(4) + radiation_pulse(get_turf(src), 0, 3, 15, 1) for(var/turf/simulated/wall/mineral/uranium/T in orange(1,src)) T.radiate() last_event = world.time diff --git a/code/game/objects/structures/statues.dm b/code/game/objects/structures/statues.dm index 8eec60f7283..f54046e7065 100644 --- a/code/game/objects/structures/statues.dm +++ b/code/game/objects/structures/statues.dm @@ -176,8 +176,7 @@ if(!active) if(world.time > last_event+15) active = 1 - for(var/mob/living/L in range(3,src)) - L.irradiate(12) + radiation_pulse(get_turf(src), 3, 3, 12, 0) last_event = world.time active = null return diff --git a/code/game/turfs/simulated/floor/mineral_floor.dm b/code/game/turfs/simulated/floor/mineral_floor.dm index b1b1a728cf4..612aec92013 100644 --- a/code/game/turfs/simulated/floor/mineral_floor.dm +++ b/code/game/turfs/simulated/floor/mineral_floor.dm @@ -163,8 +163,7 @@ if(!active) if(world.time > last_event+15) active = 1 - for(var/mob/living/L in range(3,src)) - L.irradiate(1) + radiation_pulse(get_turf(src), 3, 3, 1, 0) for(var/turf/simulated/floor/mineral/uranium/T in orange(1,src)) T.radiate() last_event = world.time diff --git a/code/game/turfs/simulated/walls_mineral.dm b/code/game/turfs/simulated/walls_mineral.dm index be9d5945c9d..84aae77504d 100644 --- a/code/game/turfs/simulated/walls_mineral.dm +++ b/code/game/turfs/simulated/walls_mineral.dm @@ -80,8 +80,7 @@ if(!active) if(world.time > last_event+15) active = 1 - for(var/mob/living/L in range(3,src)) - L.irradiate(4) + radiation_pulse(get_turf(src), 3, 3, 4, 0) for(var/turf/simulated/wall/mineral/uranium/T in orange(1,src)) T.radiate() last_event = world.time diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm index 9687091df9a..19eff86457e 100644 --- a/code/modules/admin/IsBanned.dm +++ b/code/modules/admin/IsBanned.dm @@ -3,46 +3,11 @@ /world/IsBanned(key,address,computer_id) if (!key || !address || !computer_id) log_access("Failed Login (invalid data): [key] [address]-[computer_id]") - return list("reason"="invalid login data", "desc"="Your computer provided invalid or blank information to the server on connection (byond username, IP, and Computer ID.) Provided information for reference: Username:'[key]' IP:'[address]' Computer ID:'[computer_id]' If you continue to get this error, please restart byond or contact byond support.") - if(ckey(key) in admin_datums) - //It has proven to be a bad idea to make admins completely immune to bans, making them have to wait for someone with daemon access - //to add a daemon ban to finally stop them. Admin tempbans and admin permabans are special, high-level ban types, which are there to help - //deal with rogue admins quicker. If admin tempbans or admin permabans are ever needed, it should be consider a big deal. The same applies if - //admin bans are ever abused. This ban type does NOT check for IP or Computer ID. The reason for this is so a player cannot find/steal an admin's - //computer id, set it on his computer, get himself banned, resulting in the admin getting banned aswell. - this happens to also be the reason why - //admins were immune to bans in the first place. - if(!config.ban_legacy_system) - var/ckeytext = ckey(key) - - if(!establish_db_connection()) - world.log << "Ban database connection failure. Admin [ckeytext] not checked" - diary << "Ban database connection failure. Admin [ckeytext] not checked" - return - - var/DBQuery/query = dbcon.NewQuery("SELECT ckey, ip, computerid, a_ckey, reason, expiration_time, duration, bantime, bantype FROM [format_table_name("ban")] WHERE (ckey = '[ckeytext]') AND (bantype = 'ADMIN_PERMABAN' OR (bantype = 'ADMIN_TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)") - - query.Execute() - - while(query.NextRow()) - var/pckey = query.item[1] - //var/pip = query.item[2] - //var/pcid = query.item[3] - var/ackey = query.item[4] - var/reason = query.item[5] - var/expiration = query.item[6] - var/duration = query.item[7] - var/bantime = query.item[8] - var/bantype = query.item[9] - - var/expires = "" - if(text2num(duration) > 0) - expires = " The ban is for [duration] minutes and expires on [expiration] (server time)." - - var/desc = "\nReason: You, or another user of this computer or connection ([pckey]) is banned from playing here. The ban reason is:\n[reason]\nThis ban was applied by [ackey] on [bantime], [expires]" - - return list("reason"="[bantype]", "desc"="[desc]") - - return ..() + return list("reason"="invalid login data", "desc"="Error: Could not check ban status, Please try again. Error message: Your computer provided invalid or blank information to the server on connection (byond username, IP, and Computer ID.) Provided information for reference: Username:'[key]' IP:'[address]' Computer ID:'[computer_id]'. (If you continue to get this error, please restart byond or contact byond support.)") + var/admin = 0 + var/ckey = ckey(key) + if((ckey in admin_datums) || (ckey in deadmins)) + admin = 1 //Guest Checking if(IsGuestKey(key)) @@ -54,7 +19,7 @@ return list("reason"="guest", "desc"="\nReason: Sorry but the server is currently not accepting connections from never before seen players or guests. If you have played on this server with a byond account before, please log in to the byond account you have played from.") //Population Cap Checking - if(config.extreme_popcap && living_player_count() >= config.extreme_popcap && !(ckey(key) in admin_datums)) + if(config.extreme_popcap && living_player_count() >= config.extreme_popcap && !admin) log_access("Failed Login: [key] - Population cap reached") return list("reason"="popcap", "desc"= "\nReason: [config.extreme_popcap_message]") @@ -63,10 +28,13 @@ //Ban Checking . = CheckBan( ckey(key), computer_id, address ) if(.) - log_access("Failed Login: [key] [computer_id] [address] - Banned [.["reason"]]") - return . - - return ..() //default pager ban stuff + if (admin) + log_admin("The admin [key] has been allowed to bypass a matching ban on [.["key"]]") + message_admins("The admin [key] has been allowed to bypass a matching ban on [.["key"]]") + addclientmessage(ckey,"You have been allowed to bypass a matching ban on [.["key"]]") + else + log_access("Failed Login: [key] [computer_id] [address] - Banned [.["reason"]]") + return . else @@ -85,7 +53,7 @@ if(computer_id) cidquery = " OR computerid = '[computer_id]' " - var/DBQuery/query = dbcon.NewQuery("SELECT ckey, ip, computerid, a_ckey, reason, expiration_time, duration, bantime, bantype FROM [format_table_name("ban")] WHERE (ckey = '[ckeytext]' [ipquery] [cidquery]) AND (bantype = 'PERMABAN' OR (bantype = 'TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)") + var/DBQuery/query = dbcon.NewQuery("SELECT ckey, ip, computerid, a_ckey, reason, expiration_time, duration, bantime, bantype FROM [format_table_name("ban")] WHERE (ckey = '[ckeytext]' [ipquery] [cidquery]) AND (bantype = 'PERMABAN' OR bantype = 'ADMIN_PERMABAN' OR ((bantype = 'TEMPBAN' OR bantype = 'ADMIN_TEMPBAN') AND expiration_time > Now())) AND isnull(unbanned)") query.Execute() @@ -99,12 +67,46 @@ var/duration = query.item[7] var/bantime = query.item[8] var/bantype = query.item[9] - + if (bantype == "ADMIN_PERMABAN" || bantype == "ADMIN_TEMPBAN") + //admin bans MUST match on ckey to prevent cid-spoofing attacks + // as well as dynamic ip abuse + if (pckey != ckey) + continue + if (admin) + if (bantype == "ADMIN_PERMABAN" || bantype == "ADMIN_TEMPBAN") + log_admin("The admin [key] is admin banned, and has been disallowed access") + message_admins("The admin [key] is admin banned, and has been disallowed access") + else + log_admin("The admin [key] has been allowed to bypass a matching ban on [pckey]") + message_admins("The admin [key] has been allowed to bypass a matching ban on [pckey]") + addclientmessage(ckey,"You have been allowed to bypass a matching ban on [pckey]") + continue var/expires = "" if(text2num(duration) > 0) expires = " The ban is for [duration] minutes and expires on [expiration] (server time)." + else + expires = " The is a permanent ban." var/desc = "\nReason: You, or another user of this computer or connection ([pckey]) is banned from playing here. The ban reason is:\n[reason]\nThis ban was applied by [ackey] on [bantime], [expires]" - return list("reason"="[bantype]", "desc"="[desc]") - return ..() //default pager ban stuff + . = list("reason"="[bantype]", "desc"="[desc]") + + + log_access("Failed Login: [key] [computer_id] [address] - Banned [.["reason"]]") + return . + + + . = ..() //default pager ban stuff + if (.) + //byond will not trigger isbanned() for "global" host bans, + //ie, ones where the "apply to this game only" checkbox is not checked (defaults to not checked) + //So it's safe to let admins walk thru host/sticky bans here + if (admin) + log_admin("The admin [key] has been allowed to bypass a matching host/sticky ban") + message_admins("The admin [key] has been allowed to bypass a matching host/sticky ban") + addclientmessage(ckey,"You have been allowed to bypass a matching host/sticky ban") + return null + else + log_access("Failed Login: [key] [computer_id] [address] - Banned [.["message"]]") + + return . diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 92ea19f1afc..f900be95527 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -66,7 +66,8 @@ var/list/admin_verbs_ban = list( /client/proc/unban_panel, /client/proc/jobbans, /client/proc/unjobban_panel, - /client/proc/DB_ban_panel + /client/proc/DB_ban_panel, + /client/proc/stickybanpanel ) var/list/admin_verbs_sounds = list( /client/proc/play_local_sound, diff --git a/code/modules/admin/stickyban.dm b/code/modules/admin/stickyban.dm new file mode 100644 index 00000000000..d3a198a52bb --- /dev/null +++ b/code/modules/admin/stickyban.dm @@ -0,0 +1,204 @@ +/datum/admins/proc/stickyban(action,data) + if(!check_rights(R_BAN)) + return + switch (action) + if ("show") + stickyban_show() + if ("add") + var/list/ban = list() + var/ckey + ban["admin"] = usr.key + ban["type"] = list("sticky") + ban["reason"] = "(InGameBan)([usr.key])" //this will be displayed in dd only + + if (data["ckey"]) + ckey = ckey(data["ckey"]) + else + ckey = input(usr,"Ckey","Ckey","") as text|null + if (!ckey) + return + ckey = ckey(ckey) + if (get_stickyban_from_ckey(ckey)) + usr << "Error: Can not add a stickyban: User already has a current sticky ban" + + if (data["reason"]) + ban["message"] = data["reason"] + else + var/reason = input(usr,"Reason","Reason","Ban Evasion") as text|null + if (!reason) + return + ban["message"] = "[reason]" + + world.SetConfig("ban",ckey,list2stickyban(ban)) + + log_admin("[key_name(usr)] has stickybanned [ckey].\nReason: [ban["message"]]") + message_admins("[key_name_admin(usr)] has stickybanned [ckey].\nReason: [ban["message"]]") + + if ("remove") + if (!data["ckey"]) + return + var/ckey = data["ckey"] + + var/ban = get_stickyban_from_ckey(ckey) + if (!ban) + usr << "Error: No sticky ban for [ckey] found!" + return + if (alert("Are you sure you want to remove the sticky ban on [ckey]?","Are you sure","Yes","No") == "No") + return + if (!get_stickyban_from_ckey(ckey)) + usr << "Error: The ban disappeared." + return + world.SetConfig("ban",ckey, null) + + log_admin("[key_name(usr)] removed [ckey]'s stickyban") + message_admins("[key_name_admin(usr)] removed [ckey]'s stickyban") + + if ("remove_alt") + if (!data["ckey"]) + return + var/ckey = data["ckey"] + if (!data["alt"]) + return + var/alt = ckey(data["alt"]) + var/ban = get_stickyban_from_ckey(ckey) + if (!ban) + usr << "Error: No sticky ban for [ckey] found!" + return + + var/found = 0 + //we have to do it this way because byond keeps the case in its sticky ban matches WHY!!! + for (var/key in ban["keys"]) + if (ckey(key) == alt) + found = 1 + break + + if (!found) + usr << "Error: [alt] is not linked to [ckey]'s sticky ban!" + return + + if (alert("Are you sure you want to disassociate [alt] from [ckey]'s sticky ban? \nNote: Nothing stops byond from re-linking them","Are you sure","Yes","No") == "No") + return + + //we have to do this again incase something changes + ban = get_stickyban_from_ckey(ckey) + if (!ban) + usr << "Error: The ban disappeared." + return + + found = 0 + for (var/key in ban["keys"]) + if (ckey(key) == alt) + ban["keys"] -= key + found = 1 + break + + if (!found) + usr << "Error: [alt] link to [ckey]'s sticky ban disappeared." + return + + world.SetConfig("ban",ckey,list2stickyban(ban)) + + log_admin("[key_name(usr)] has disassociated [alt] from [ckey]'s sticky ban") + message_admins("[key_name_admin(usr)] has disassociated [alt] from [ckey]'s sticky ban") + + if ("edit") + if (!data["ckey"]) + return + var/ckey = data["ckey"] + var/ban = get_stickyban_from_ckey(ckey) + if (!ban) + usr << "Error: No sticky ban for [ckey] found!" + return + var/oldreason = ban["message"] + var/reason = input(usr,"Reason","Reason","[ban["message"]]") as text|null + if (!reason || reason == oldreason) + return + //we have to do this again incase something changed while we waited for input + ban = get_stickyban_from_ckey(ckey) + if (!ban) + usr << "Error: The ban disappeared." + return + ban["message"] = "[reason]" + + world.SetConfig("ban",ckey,list2stickyban(ban)) + + log_admin("[key_name(usr)] has edited [ckey]'s sticky ban reason from [oldreason] to [reason]") + message_admins("[key_name_admin(usr)] has edited [ckey]'s sticky ban reason from [oldreason] to [reason]") + +/datum/admins/proc/stickyban_gethtml(ckey, ban) + . = "\[-\][ckey]
" + . += "[ban["message"]] \[Edit\]
" + if (ban["admin"]) + . += "[ban["admin"]]
" + else + . += "LEGACY
" + . += "Caught keys
\n
    " + for (var/key in ban["keys"]) + if (ckey(key) == ckey) + continue + . += "
  1. \[-\][key]
  2. " + . += "
\n" + +/datum/admins/proc/stickyban_show() + if(!check_rights(R_BAN)) + return + var/list/bans = world.GetConfig("ban") + var/banhtml = "" + for(var/key in bans) + var/ckey = ckey(key) + var/ban = stickyban2list(world.GetConfig("ban",key)) + banhtml += "

\n" + banhtml += stickyban_gethtml(ckey,ban) + + var/html = {" + + Sticky Bans + + +

All Sticky Bans:

\[+\]
+ [banhtml] + + "} + usr << browse(html,"window=stickybans;size=700x400") + +/proc/get_stickyban_from_ckey(var/ckey) + if (!ckey) + return null + ckey = ckey(ckey) + . = null + for (var/key in world.GetConfig("ban")) + if (ckey(key) == ckey) + . = stickyban2list(world.GetConfig("ban",key)) + break + +/proc/stickyban2list(var/ban) + if (!ban) + return null + . = params2list(ban) + .["keys"] = text2list(.["keys"], ",") + .["type"] = text2list(.["type"], ",") + .["IP"] = text2list(.["IP"], ",") + .["computer_id"] = text2list(.["computer_id"], ",") + + +/proc/list2stickyban(var/list/ban) + if (!ban || !islist(ban)) + return null + . = ban.Copy() + if (.["keys"]) + .["keys"] = list2text(.["keys"], ",") + if (.["type"]) + .["type"] = list2text(.["type"], ",") + if (.["IP"]) + .["IP"] = list2text(.["IP"], ",") + if (.["computer_id"]) + .["computer_id"] = list2text(.["computer_id"], ",") + . = list2params(.) + + +/client/proc/stickybanpanel() + set name = "Sticky Ban Panel" + set category = "Admin" + if (!holder) + return + holder.stickyban_show() \ No newline at end of file diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index d832c960d13..495923b86d5 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -23,6 +23,8 @@ message_admins("[key_name_admin(usr)] Rejected [C.key]'s admin help. [C.key]'s Adminhelp verb has been returned to them") log_admin("[key_name(usr)] Rejected [C.key]'s admin help") + else if(href_list["stickyban"]) + stickyban(href_list["stickyban"],href_list) else if(href_list["makeAntag"]) if (!ticker.mode) @@ -2135,4 +2137,4 @@ O.ears = text2path(href_list["outfit_ears"]) custom_outfits.Add(O) - message_admins("[key_name(usr)] created \"[O.name]\" outfit!") \ No newline at end of file + message_admins("[key_name(usr)] created \"[O.name]\" outfit!") diff --git a/code/modules/client/client defines.dm b/code/modules/client/client defines.dm index 2e41bb6717e..7063b2fb8f9 100644 --- a/code/modules/client/client defines.dm +++ b/code/modules/client/client defines.dm @@ -1,3 +1,4 @@ + /client //////////////// //ADMIN THINGS// diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 5ecd635021b..70db67c27c5 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -175,13 +175,19 @@ var/next_external_rsc = 0 src.changes() else winset(src, "rpane.changelogb", "background-color=#eaeaea;font-style=bold") + + if (ckey in clientmessages) + for (var/message in clientmessages[ckey]) + src << message + clientmessages.Remove(ckey) if (config && config.autoconvert_notes) convert_notes_sql(ckey) - ////////////// - //DISCONNECT// - ////////////// +////////////// +//DISCONNECT// +////////////// + /client/Del() if(holder) adminGreet(1) diff --git a/code/modules/client/message.dm b/code/modules/client/message.dm new file mode 100644 index 00000000000..a18950fe8d1 --- /dev/null +++ b/code/modules/client/message.dm @@ -0,0 +1,9 @@ +var/list/clientmessages = list() + +proc/addclientmessage(var/ckey, var/message) + ckey = ckey(ckey) + if (!ckey || !message) + return + if (!(ckey in clientmessages)) + clientmessages[ckey] = list() + clientmessages[ckey] += message \ No newline at end of file diff --git a/code/modules/events/radiation_storm.dm b/code/modules/events/radiation_storm.dm index c83ea419df4..13c57a9a5a6 100644 --- a/code/modules/events/radiation_storm.dm +++ b/code/modules/events/radiation_storm.dm @@ -37,9 +37,9 @@ if(istype(C, /mob/living/carbon/human)) var/mob/living/carbon/human/H = C if(prob(5)) - H.irradiate(rand(100, 160)) + H.rad_act(rand(100, 160)) else - H.irradiate(rand(15, 75)) + H.rad_act(rand(15, 75)) if(prob(25)) if(prob(75)) randmutb(H) @@ -49,7 +49,7 @@ else if(istype(C, /mob/living/carbon/monkey)) var/mob/living/carbon/monkey/M = C - M.irradiate(rand(15, 75)) + M.rad_act(rand(15, 75)) /datum/round_event/radiation_storm/end() diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 2b585fa1f89..4a15c82b74d 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -684,7 +684,7 @@ if(prob(current_size * 5) && hand.w_class >= ((11-current_size)/2) && unEquip(hand)) step_towards(hand, src) src << "\The [S] pulls \the [hand] from your grip!" - irradiate(current_size * 3) + rad_act(current_size * 3) if(mob_negates_gravity()) return ..() diff --git a/code/modules/mob/living/carbon/human/species_types.dm b/code/modules/mob/living/carbon/human/species_types.dm index cd5c473014b..95105c87bdc 100644 --- a/code/modules/mob/living/carbon/human/species_types.dm +++ b/code/modules/mob/living/carbon/human/species_types.dm @@ -122,7 +122,7 @@ datum/species/human/spec_death(gibbed, mob/living/carbon/human/H) switch(proj_type) if(/obj/item/projectile/energy/floramut) if(prob(15)) - H.irradiate(rand(30,80)) + H.rad_act(rand(30,80)) H.Weaken(5) H.visible_message("[H] writhes in pain as \his vacuoles boil.", "You writhe in pain as your vacuoles boil!", "You hear the crunching of leaves.") if(prob(80)) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index c30c3527d60..a63a44b5a03 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -293,7 +293,4 @@ if(stat || paralysis || stunned || weakened || restrained()) return 1 -/mob/living/proc/irradiate(amount) - if(amount) - var/blocked = run_armor_check(null, "rad", "Your clothes feel warm", "Your clothes feel warm") - apply_effect(amount, IRRADIATE, blocked) +//Looking for irradiate()? It's been moved to radiation.dm under the rad_act() for mobs. diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index e39e59063dc..a8ff6fb6361 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -74,6 +74,7 @@ var/list/ai_list = list() var/obj/machinery/camera/portable/builtInCamera /mob/living/silicon/ai/New(loc, var/datum/ai_laws/L, var/obj/item/device/mmi/B, var/safety = 0) + ..() rename_self("ai", 1) name = real_name anchored = 1 @@ -144,8 +145,7 @@ var/list/ai_list = list() builtInCamera = new /obj/machinery/camera/portable(src) builtInCamera.network = list("SS13") - ..() - return + /mob/living/silicon/ai/Destroy() ai_list -= src diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index 12a73e8edc4..7d87854a7ca 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -94,14 +94,14 @@ return /mob/living/simple_animal/hostile/proc/PickTarget(list/Targets)//Step 3, pick amongst the possible, attackable targets - if(!Targets.len)//We didnt find nothin! - return if(target != null)//If we already have a target, but are told to pick again, calculate the lowest distance between all possible, and pick from the lowest distance targets for(var/atom/A in Targets) var/target_dist = get_dist(src, target) var/possible_target_distance = get_dist(src, A) if(target_dist < possible_target_distance) Targets -= A + if(!Targets.len)//We didnt find nothin! + return var/chosen_target = pick(Targets)//Pick the remaining targets (if any) at random return chosen_target diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm index 8eb7af7db8f..104a437c2f2 100644 --- a/code/modules/power/gravitygenerator.dm +++ b/code/modules/power/gravitygenerator.dm @@ -350,8 +350,7 @@ var/const/GRAV_NEEDS_WRENCH = 3 /obj/machinery/gravity_generator/main/proc/pulse_radiation() - for(var/mob/living/L in view(7, src)) - L.irradiate(20) + radiation_pulse(get_turf(src), 3, 7, 20, 1) // Shake everyone on the z level to let them know that gravity was enagaged/disenagaged. /obj/machinery/gravity_generator/main/proc/shake_everyone() diff --git a/code/modules/power/singularity/particle_accelerator/particle.dm b/code/modules/power/singularity/particle_accelerator/particle.dm index a9ff8952161..889d9a3189b 100644 --- a/code/modules/power/singularity/particle_accelerator/particle.dm +++ b/code/modules/power/singularity/particle_accelerator/particle.dm @@ -56,7 +56,7 @@ /obj/effect/accelerated_particle/proc/toxmob(mob/living/M) - M.irradiate(energy*6) + M.rad_act(energy*6) M.updatehealth() return diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index b9578936e24..6223ff52e7c 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -364,13 +364,13 @@ radiation += round((energy-150)/10,1) radiationmin = round((radiation/5),1) for(var/mob/living/M in view(toxrange, src.loc)) - M.irradiate(rand(radiationmin,radiation)) + M.rad_act(rand(radiationmin,radiation)) /obj/singularity/proc/combust_mobs() for(var/mob/living/carbon/C in orange(20, src)) C.visible_message("[C]'s skin bursts into flame!", \ - "You feel an inner fire as your skin is suddenly covered in fire!") + "You feel an inner fire as your skin bursts into flames!") C.adjust_fire_stacks(5) C.IgniteMob() return diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index 9fb8bfb9d52..2d01b3cf8b3 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -119,7 +119,7 @@ var/mob/living/carbon/human/H = mob H.hallucination += max(50, min(300, DETONATION_HALLUCINATION * sqrt(1 / (get_dist(mob, src) + 1)) ) ) var/rads = DETONATION_RADS * sqrt( 1 / (get_dist(mob, src) + 1) ) - mob.irradiate(rads) + mob.rad_act(rads) explode() @@ -181,7 +181,7 @@ for(var/mob/living/l in range(src, round((power / 100) ** 0.25))) var/rads = (power / 10) * sqrt( 1 / max(get_dist(l, src),1) ) - l.irradiate(rads) + l.rad_act(rads) power -= (power/500)**3 @@ -259,7 +259,7 @@ playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, 1) - user.irradiate(150) + radiation_pulse(get_turf(src), 1, 1, 150, 1) /obj/machinery/power/supermatter_shard/Bumped(atom/AM as mob|obj) @@ -292,9 +292,8 @@ power += 200 //Some poor sod got eaten, go ahead and irradiate people nearby. + radiation_pulse(get_turf(src), 4, 10, 500, 1) for(var/mob/living/L in range(10)) - var/rads = 500 * sqrt( 1 / (get_dist(L, src) + 1) ) - L.irradiate(rads) investigate_log("has irradiated [L] after consuming [AM].", "supermatter") if(L in view()) L.show_message("As \the [src] slowly stops resonating, you find your skin covered in new radiation burns.", 1,\ diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 9252eb3eccf..02729e68ac9 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -138,7 +138,8 @@ var/mob/living/M = user if (M.disabilities & CLUMSY && prob(40)) user << "You shoot yourself in the foot with \the [src]!" - process_fire(user,user,0,params) + var/shot_leg = pick("l_leg", "r_leg") + process_fire(user,user,0,params, zone_override = shot_leg) M.drop_item() return @@ -182,7 +183,7 @@ return 0 -/obj/item/weapon/gun/proc/process_fire(atom/target as mob|obj|turf, mob/living/user as mob|obj, message = 1, params) +/obj/item/weapon/gun/proc/process_fire(atom/target as mob|obj|turf, mob/living/user as mob|obj, message = 1, params, zone_override) add_fingerprint(user) if(semicd) @@ -200,7 +201,7 @@ if( i>1 && !(src in get_both_hands(user))) //for burst firing break if(chambered) - if(!chambered.fire(target, user, params, , suppressed)) + if(!chambered.fire(target, user, params, , suppressed, zone_override)) shoot_with_empty_chamber(user) break else @@ -216,7 +217,7 @@ sleep(fire_delay) else if(chambered) - if(!chambered.fire(target, user, params, , suppressed)) + if(!chambered.fire(target, user, params, , suppressed, zone_override)) shoot_with_empty_chamber(user) return else diff --git a/code/modules/projectiles/guns/energy/nuclear.dm b/code/modules/projectiles/guns/energy/nuclear.dm index a5752e23273..dbe0225dd79 100644 --- a/code/modules/projectiles/guns/energy/nuclear.dm +++ b/code/modules/projectiles/guns/energy/nuclear.dm @@ -90,11 +90,11 @@ switch(fail_tick) if(0 to 200) fail_tick += (2*(100-reliability)) - M.irradiate(40) + M.rad_act(40) M << "Your [name] feels warmer." if(201 to INFINITY) SSobj.processing.Remove(src) - M.irradiate(80) + M.rad_act(80) crit_fail = 1 M << "Your [name]'s reactor overloads!" diff --git a/code/modules/projectiles/guns/projectile/launchers.dm b/code/modules/projectiles/guns/projectile/launchers.dm index 0d9220733f1..ecd46e53e3f 100644 --- a/code/modules/projectiles/guns/projectile/launchers.dm +++ b/code/modules/projectiles/guns/projectile/launchers.dm @@ -25,6 +25,7 @@ icon = 'icons/mecha/mecha_equipment.dmi' icon_state = "mecha_grenadelnchr" mag_type = /obj/item/ammo_box/magazine/internal/cylinder/grenademulti + pin = /obj/item/device/firing_pin /obj/item/weapon/gun/projectile/revolver/grenadelauncher/cyborg/attack_self() return diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm index 436dde364d9..6cf59f10915 100644 --- a/code/modules/research/experimentor.dm +++ b/code/modules/research/experimentor.dm @@ -286,9 +286,7 @@ ejectItem() if(prob(EFFECT_PROB_VERYLOW-badThingCoeff)) visible_message("[src] malfunctions, melting [exp_on] and leaking radiation!") - for(var/mob/living/m in oview(1, src)) - m.irradiate(25) - investigate_log("Experimentor has irradiated [m]", "experimentor") //One entry per person so we know what was irradiated. + radiation_pulse(get_turf(src), 1, 1, 25, 1) ejectItem(TRUE) if(prob(EFFECT_PROB_LOW-badThingCoeff)) visible_message("[src] malfunctions, spewing toxic waste!") diff --git a/html/changelog.html b/html/changelog.html index 02e025d64f0..02c2180dec9 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -55,6 +55,18 @@ -->
+

28 September 2015

+

Feemjmeem updated:

+ +

Razharas updated:

+ +

26 September 2015

MMMiracles updated: