diff --git a/code/datums/wires/camera.dm b/code/datums/wires/camera.dm index d03da5fa171..35bb07cbc51 100644 --- a/code/datums/wires/camera.dm +++ b/code/datums/wires/camera.dm @@ -58,7 +58,7 @@ var/const/CAMERA_WIRE_NOTHING2 = 32 C.setViewRange(new_range) if(CAMERA_WIRE_POWER) - C.deactivate(null) // Deactivate the camera + C.kick_viewers() // Kicks anyone watching the camera if(CAMERA_WIRE_LIGHT) C.light_disabled = !C.light_disabled diff --git a/code/defines/procs/admin.dm b/code/defines/procs/admin.dm index abf4c97dd3b..2bfb8b94364 100644 --- a/code/defines/procs/admin.dm +++ b/code/defines/procs/admin.dm @@ -1,7 +1,13 @@ proc/log_and_message_admins(var/message as text) - log_admin(usr ? "[usr]([usr.ckey]) [message]" : "EVENT [message]") - message_admins(usr ? "[usr]([usr.ckey]) [message]" : "EVENT [message]") + log_admin(usr ? "[key_name(usr)] [message]" : "EVENT [message]") + message_admins(usr ? "[key_name(usr)] [message]" : "EVENT [message]") proc/admin_log_and_message_admins(var/message as text) - log_admin(usr ? "[key_name(usr)] [message]" : "EVENT [message]") - message_admins(usr ? "[key_name(usr)] [message]" : "EVENT [message]", 1) + log_admin(usr ? "[key_name_admin(usr)] [message]" : "EVENT [message]") + message_admins(usr ? "[key_name_admin(usr)] [message]" : "EVENT [message]", 1) + +proc/admin_attack_log(var/mob/attacker, var/mob/victim, var/attacker_message, var/victim_message, var/admin_message) + victim.attack_log += text("\[[time_stamp()]\] [victim_message] [key_name(attacker)]") + attacker.attack_log += text("\[[time_stamp()]\] [attacker_message] [key_name(victim)]") + + msg_admin_attack("[key_name(attacker)] [admin_message] [key_name(victim)] (INTENT: [uppertext(attacker.a_intent)]) (JMP)") diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index 71894c29834..a286b530ca1 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -37,6 +37,10 @@ var/const/HOLOPAD_MODE = RANGE_BASED icon_state = "holopad0" layer = TURF_LAYER+0.1 //Preventing mice and drones from sneaking under them. + + var/power_per_hologram = 500 //per usage per hologram + idle_power_usage = 5 + use_power = 1 var/list/mob/living/silicon/ai/masters = new() //List of AIs that use the holopad var/last_request = 0 //to prevent request spam. ~Carn @@ -122,7 +126,6 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ SetLuminosity(2) //pad lighting icon_state = "holopad1" A.holo = src - use_power += HOLOGRAM_POWER_USAGE return 1 /obj/machinery/hologram/holopad/proc/clear_holo(mob/living/silicon/ai/user) @@ -130,29 +133,31 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ user.holo = null del(masters[user])//Get rid of user's hologram //qdel masters -= user //Discard AI from the list of those who use holopad - use_power = max(HOLOPAD_PASSIVE_POWER_USAGE, use_power - HOLOGRAM_POWER_USAGE)//Reduce power usage if (!masters.len)//If no users left SetLuminosity(0) //pad lighting (hologram lighting will be handled automatically since its owner was deleted) icon_state = "holopad0" - use_power = HOLOPAD_PASSIVE_POWER_USAGE return 1 /obj/machinery/hologram/holopad/process() for (var/mob/living/silicon/ai/master in masters) - if(master && !master.stat && master.client && master.eyeobj)//If there is an AI attached, it's not incapacitated, it has a client, and the client eye is centered on the projector. - if(!(stat & NOPOWER))//If the machine has power. - if((HOLOPAD_MODE == RANGE_BASED && (get_dist(master.eyeobj, src) <= holo_range))) - return 1 + var/active_ai = (master && !master.stat && master.client && master.eyeobj)//If there is an AI attached, it's not incapacitated, it has a client, and the client eye is centered on the projector. + if((stat & NOPOWER) || !active_ai) + clear_holo(master) + continue + + if((HOLOPAD_MODE == RANGE_BASED && (get_dist(master.eyeobj, src) > holo_range))) + clear_holo(master) + continue + + if(HOLOPAD_MODE == AREA_BASED) + var/area/holo_area = get_area(src) + var/area/eye_area = get_area(master.eyeobj) + + if(!(eye_area in holo_area.master.related)) + clear_holo(master) + continue - else if (HOLOPAD_MODE == AREA_BASED) - - var/area/holo_area = get_area(src) - var/area/eye_area = get_area(master.eyeobj) - - if(eye_area in holo_area.master.related) - return 1 - - clear_holo(master)//If not, we want to get rid of the hologram. + use_power(power_per_hologram) return 1 /obj/machinery/hologram/holopad/proc/move_hologram(mob/living/silicon/ai/user) diff --git a/code/modules/clothing/under/accessories/storage.dm b/code/modules/clothing/under/accessories/storage.dm index 77f32edb9a4..6c6c683b279 100644 --- a/code/modules/clothing/under/accessories/storage.dm +++ b/code/modules/clothing/under/accessories/storage.dm @@ -6,6 +6,7 @@ slot = "utility" var/slots = 3 var/obj/item/weapon/storage/internal/hold + w_class = 3.0 /obj/item/clothing/accessory/storage/New() ..() @@ -48,7 +49,7 @@ /obj/item/clothing/accessory/storage/webbing name = "webbing" - desc = "Strudy mess of synthcotton belts and buckles, ready to share your burden." + desc = "Sturdy mess of synthcotton belts and buckles, ready to share your burden." icon_state = "webbing" item_color = "webbing" @@ -83,4 +84,4 @@ /obj/item/weapon/kitchenknife/ritual) new /obj/item/weapon/hatchet/unathiknife(hold) - new /obj/item/weapon/hatchet/unathiknife(hold) \ No newline at end of file + new /obj/item/weapon/hatchet/unathiknife(hold) diff --git a/code/modules/holodeck/HolodeckControl.dm b/code/modules/holodeck/HolodeckControl.dm index fdc882eee66..8ae14ea2db9 100644 --- a/code/modules/holodeck/HolodeckControl.dm +++ b/code/modules/holodeck/HolodeckControl.dm @@ -28,7 +28,7 @@ var/global/list/holodeck_programs = list( var/area/linkedholodeck = null var/area/target = null var/active = 0 - var/list/holographic_items = list() + var/list/holographic_objs = list() var/list/holographic_mobs = list() var/damaged = 0 var/safety_disabled = 0 @@ -208,7 +208,7 @@ var/global/list/holodeck_programs = list( emergencyShutdown() /obj/machinery/computer/HolodeckControl/process() - for(var/item in holographic_items) // do this first, to make sure people don't take items out when power is down. + for(var/item in holographic_objs) // do this first, to make sure people don't take items out when power is down. if(!(get_turf(item) in linkedholodeck)) derez(item, 0) @@ -221,7 +221,7 @@ var/global/list/holodeck_programs = list( if(!..()) return if(active) - use_power(item_power_usage * (holographic_items.len + holographic_mobs.len)) + use_power(item_power_usage * (holographic_objs.len + holographic_mobs.len)) if(!checkInteg(linkedholodeck)) damaged = 1 @@ -243,7 +243,7 @@ var/global/list/holodeck_programs = list( T.hotspot_expose(1000,500,1) /obj/machinery/computer/HolodeckControl/proc/derez(var/obj/obj , var/silent = 1) - holographic_items.Remove(obj) + holographic_objs.Remove(obj) if(obj == null) return @@ -271,7 +271,7 @@ var/global/list/holodeck_programs = list( if(toggleOn) var/area/targetsource = locate(/area/holodeck/source_emptycourt) - holographic_items = targetsource.copy_contents_to(linkedholodeck) + holographic_objs = targetsource.copy_contents_to(linkedholodeck) spawn(30) for(var/obj/effect/landmark/L in linkedholodeck) @@ -288,7 +288,7 @@ var/global/list/holodeck_programs = list( active = 1 use_power = 2 else - for(var/item in holographic_items) + for(var/item in holographic_objs) derez(item) if(!linkedholodeck.has_gravity) linkedholodeck.gravitychange(1,linkedholodeck) @@ -313,7 +313,7 @@ var/global/list/holodeck_programs = list( active = 1 use_power = 2 - for(var/item in holographic_items) + for(var/item in holographic_objs) derez(item) for(var/mob/living/simple_animal/hostile/carp/holodeck/C in holographic_mobs) @@ -323,7 +323,9 @@ var/global/list/holodeck_programs = list( for(var/obj/effect/decal/cleanable/blood/B in linkedholodeck) del(B) - holographic_items = A.copy_contents_to(linkedholodeck , 1) + holographic_objs = A.copy_contents_to(linkedholodeck , 1) + for(var/obj/holo_obj in holographic_objs) + holo_obj.alpha *= 0.8 //give holodeck objs a slight transparency spawn(30) for(var/obj/effect/landmark/L in linkedholodeck) @@ -366,7 +368,7 @@ var/global/list/holodeck_programs = list( /obj/machinery/computer/HolodeckControl/proc/emergencyShutdown() //Get rid of any items - for(var/item in holographic_items) + for(var/item in holographic_objs) derez(item) for(var/mob/living/simple_animal/hostile/carp/holodeck/C in holographic_mobs) holographic_mobs -= C diff --git a/code/modules/holodeck/HolodeckObjects.dm b/code/modules/holodeck/HolodeckObjects.dm index 460f4422fbe..7a7526b1507 100644 --- a/code/modules/holodeck/HolodeckObjects.dm +++ b/code/modules/holodeck/HolodeckObjects.dm @@ -392,10 +392,15 @@ icon_state = "holo4" icon_living = "holo4" icon_dead = "holo4" + alpha = 127 icon_gib = null meat_amount = 0 meat_type = null +/mob/living/simple_animal/hostile/carp/holodeck/New() + ..() + SetLuminosity(2) //hologram lighting + /mob/living/simple_animal/hostile/carp/holodeck/proc/set_safety(var/safe) if (safe) faction = "neutral" diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm index 804b0347be7..cbae0f8f402 100644 --- a/code/modules/reagents/reagent_containers/pill.dm +++ b/code/modules/reagents/reagent_containers/pill.dm @@ -196,7 +196,7 @@ icon_state = "pill8" New() ..() - reagents.add_reagent("dexalin", 15) + reagents.add_reagent("dexalinp", 15) /obj/item/weapon/reagent_containers/pill/dermaline name = "Dermaline pill" diff --git a/code/modules/spells/mind_transfer.dm b/code/modules/spells/mind_transfer.dm index 161ed3516d1..a4f8258ff75 100644 --- a/code/modules/spells/mind_transfer.dm +++ b/code/modules/spells/mind_transfer.dm @@ -1,114 +1,116 @@ -/obj/effect/proc_holder/spell/targeted/mind_transfer - name = "Mind Transfer" - desc = "This spell allows the user to switch bodies with a target." - - school = "transmutation" - charge_max = 600 - clothes_req = 0 - invocation = "GIN'YU CAPAN" - invocation_type = "whisper" - range = 1 - var/list/protected_roles = list("Wizard","Changeling","Cultist") //which roles are immune to the spell - var/list/compatible_mobs = list(/mob/living/carbon/human) //which types of mobs are affected by the spell. NOTE: change at your own risk - var/base_spell_loss_chance = 20 //base probability of the wizard losing a spell in the process - var/spell_loss_chance_modifier = 7 //amount of probability of losing a spell added per spell (mind_transfer included) - var/spell_loss_amount = 1 //the maximum amount of spells possible to lose during a single transfer - var/msg_wait = 500 //how long in deciseconds it waits before telling that body doesn't feel right or mind swap robbed of a spell - var/paralysis_amount_caster = 20 //how much the caster is paralysed for after the spell - var/paralysis_amount_victim = 20 //how much the victim is paralysed for after the spell - -/* -Urist: I don't feel like figuring out how you store object spells so I'm leaving this for you to do. -Make sure spells that are removed from spell_list are actually removed and deleted when mind transfering. -Also, you never added distance checking after target is selected. I've went ahead and did that. -*/ -/obj/effect/proc_holder/spell/targeted/mind_transfer/cast(list/targets,mob/user = usr) - if(!targets.len) - user << "No mind found." - return - - if(targets.len > 1) - user << "Too many minds! You're not a hive damnit!"//Whaa...aat? - return - - var/mob/living/target = targets[1] - - if(!(target in oview(range)))//If they are not in overview after selection. Do note that !() is necessary for in to work because ! takes precedence over it. - user << "They are too far away!" - return - - if(!(target.type in compatible_mobs)) - user << "Their mind isn't compatible with yours." - return - - if(target.stat == DEAD) - user << "You didn't study necromancy back at the Space Wizard Federation academy." - return - - if(!target.key || !target.mind) - user << "They appear to be catatonic. Not even magic can affect their vacant mind." - return - - if(target.mind.special_role in protected_roles) - user << "Their mind is resisting your spell." - return - - var/mob/living/victim = target//The target of the spell whos body will be transferred to. - var/mob/caster = user//The wizard/whomever doing the body transferring. - - //SPELL LOSS BEGIN - //NOTE: The caster must ALWAYS keep mind transfer, even when other spells are lost. - var/obj/effect/proc_holder/spell/targeted/mind_transfer/m_transfer = locate() in user.spell_list//Find mind transfer directly. - var/list/checked_spells = user.spell_list - checked_spells -= m_transfer //Remove Mind Transfer from the list. - - if(caster.spell_list.len)//If they have any spells left over after mind transfer is taken out. If they don't, we don't need this. - for(var/i=spell_loss_amount,(i>0&&checked_spells.len),i--)//While spell loss amount is greater than zero and checked_spells has spells in it, run this proc. - for(var/j=checked_spells.len,(j>0&&checked_spells.len),j--)//While the spell list to check is greater than zero and has spells in it, run this proc. - if(prob(base_spell_loss_chance)) - checked_spells -= pick(checked_spells)//Pick a random spell to remove. - spawn(msg_wait) - victim << "The mind transfer has robbed you of a spell." - break//Spell lost. Break loop, going back to the previous for() statement. - else//Or keep checking, adding spell chance modifier to increase chance of losing a spell. - base_spell_loss_chance += spell_loss_chance_modifier - - checked_spells += m_transfer//Add back Mind Transfer. - user.spell_list = checked_spells//Set user spell list to whatever the new list is. - //SPELL LOSS END - - //MIND TRANSFER BEGIN - if(caster.mind.special_verbs.len)//If the caster had any special verbs, remove them from the mob verb list. - for(var/V in caster.mind.special_verbs)//Since the caster is using an object spell system, this is mostly moot. - caster.verbs -= V//But a safety nontheless. - - if(victim.mind.special_verbs.len)//Now remove all of the victim's verbs. - for(var/V in victim.mind.special_verbs) - victim.verbs -= V - - var/mob/dead/observer/ghost = victim.ghostize(0) - ghost.spell_list = victim.spell_list//If they have spells, transfer them. Now we basically have a backup mob. - - caster.mind.transfer_to(victim) - victim.spell_list = caster.spell_list//Now they are inside the victim's body. - - if(victim.mind.special_verbs.len)//To add all the special verbs for the original caster. - for(var/V in caster.mind.special_verbs)//Not too important but could come into play. - caster.verbs += V - - ghost.mind.transfer_to(caster) - caster.key = ghost.key //have to transfer the key since the mind was not active - caster.spell_list = ghost.spell_list - - if(caster.mind.special_verbs.len)//If they had any special verbs, we add them here. - for(var/V in caster.mind.special_verbs) - caster.verbs += V - //MIND TRANSFER END - - //Here we paralyze both mobs and knock them out for a time. - caster.Paralyse(paralysis_amount_caster) - victim.Paralyse(paralysis_amount_victim) - - //After a certain amount of time the victim gets a message about being in a different body. - spawn(msg_wait) - caster << "\red You feel woozy and lightheaded. Your body doesn't seem like your own." +/obj/effect/proc_holder/spell/targeted/mind_transfer + name = "Mind Transfer" + desc = "This spell allows the user to switch bodies with a target." + + school = "transmutation" + charge_max = 600 + clothes_req = 0 + invocation = "GIN'YU CAPAN" + invocation_type = "whisper" + range = 1 + var/list/protected_roles = list("Wizard","Changeling","Cultist") //which roles are immune to the spell + var/list/compatible_mobs = list(/mob/living/carbon/human) //which types of mobs are affected by the spell. NOTE: change at your own risk + var/base_spell_loss_chance = 20 //base probability of the wizard losing a spell in the process + var/spell_loss_chance_modifier = 7 //amount of probability of losing a spell added per spell (mind_transfer included) + var/spell_loss_amount = 1 //the maximum amount of spells possible to lose during a single transfer + var/msg_wait = 500 //how long in deciseconds it waits before telling that body doesn't feel right or mind swap robbed of a spell + var/paralysis_amount_caster = 20 //how much the caster is paralysed for after the spell + var/paralysis_amount_victim = 20 //how much the victim is paralysed for after the spell + +/* +Urist: I don't feel like figuring out how you store object spells so I'm leaving this for you to do. +Make sure spells that are removed from spell_list are actually removed and deleted when mind transfering. +Also, you never added distance checking after target is selected. I've went ahead and did that. +*/ +/obj/effect/proc_holder/spell/targeted/mind_transfer/cast(list/targets,mob/user = usr) + if(!targets.len) + user << "No mind found." + return + + if(targets.len > 1) + user << "Too many minds! You're not a hive damnit!"//Whaa...aat? + return + + var/mob/living/target = targets[1] + + if(!(target in oview(range)))//If they are not in overview after selection. Do note that !() is necessary for in to work because ! takes precedence over it. + user << "They are too far away!" + return + + if(!(target.type in compatible_mobs)) + user << "Their mind isn't compatible with yours." + return + + if(target.stat == DEAD) + user << "You didn't study necromancy back at the Space Wizard Federation academy." + return + + if(!target.key || !target.mind) + user << "They appear to be catatonic. Not even magic can affect their vacant mind." + return + + if(target.mind.special_role in protected_roles) + user << "Their mind is resisting your spell." + return + + var/mob/living/victim = target//The target of the spell whos body will be transferred to. + var/mob/caster = user//The wizard/whomever doing the body transferring. + + //SPELL LOSS BEGIN + admin_attack_log(caster, victim, "Used mind transfer on", "Had mind transfer used on him by", "used mind transfer on") + + //NOTE: The caster must ALWAYS keep mind transfer, even when other spells are lost. + var/obj/effect/proc_holder/spell/targeted/mind_transfer/m_transfer = locate() in user.spell_list//Find mind transfer directly. + var/list/checked_spells = user.spell_list + checked_spells -= m_transfer //Remove Mind Transfer from the list. + + if(caster.spell_list.len)//If they have any spells left over after mind transfer is taken out. If they don't, we don't need this. + for(var/i=spell_loss_amount,(i>0&&checked_spells.len),i--)//While spell loss amount is greater than zero and checked_spells has spells in it, run this proc. + for(var/j=checked_spells.len,(j>0&&checked_spells.len),j--)//While the spell list to check is greater than zero and has spells in it, run this proc. + if(prob(base_spell_loss_chance)) + checked_spells -= pick(checked_spells)//Pick a random spell to remove. + spawn(msg_wait) + victim << "The mind transfer has robbed you of a spell." + break//Spell lost. Break loop, going back to the previous for() statement. + else//Or keep checking, adding spell chance modifier to increase chance of losing a spell. + base_spell_loss_chance += spell_loss_chance_modifier + + checked_spells += m_transfer//Add back Mind Transfer. + user.spell_list = checked_spells//Set user spell list to whatever the new list is. + //SPELL LOSS END + + //MIND TRANSFER BEGIN + if(caster.mind.special_verbs.len)//If the caster had any special verbs, remove them from the mob verb list. + for(var/V in caster.mind.special_verbs)//Since the caster is using an object spell system, this is mostly moot. + caster.verbs -= V//But a safety nontheless. + + if(victim.mind.special_verbs.len)//Now remove all of the victim's verbs. + for(var/V in victim.mind.special_verbs) + victim.verbs -= V + + var/mob/dead/observer/ghost = victim.ghostize(0) + ghost.spell_list = victim.spell_list//If they have spells, transfer them. Now we basically have a backup mob. + + caster.mind.transfer_to(victim) + victim.spell_list = caster.spell_list//Now they are inside the victim's body. + + if(victim.mind.special_verbs.len)//To add all the special verbs for the original caster. + for(var/V in caster.mind.special_verbs)//Not too important but could come into play. + caster.verbs += V + + ghost.mind.transfer_to(caster) + caster.key = ghost.key //have to transfer the key since the mind was not active + caster.spell_list = ghost.spell_list + + if(caster.mind.special_verbs.len)//If they had any special verbs, we add them here. + for(var/V in caster.mind.special_verbs) + caster.verbs += V + //MIND TRANSFER END + + //Here we paralyze both mobs and knock them out for a time. + caster.Paralyse(paralysis_amount_caster) + victim.Paralyse(paralysis_amount_victim) + + //After a certain amount of time the victim gets a message about being in a different body. + spawn(msg_wait) + caster << "\red You feel woozy and lightheaded. Your body doesn't seem like your own."