mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 10:12:45 +00:00
Merge remote-tracking branch 'upstream/dev-freeze' into dev
Conflicts: code/game/gamemodes/cult/runes.dm code/game/objects/items/weapons/implants/implantcase.dm code/game/objects/items/weapons/melee/energy.dm code/modules/mob/living/carbon/human/emote.dm code/modules/mob/living/carbon/human/human.dm code/modules/mob/living/carbon/human/human_attackhand.dm code/modules/mob/living/silicon/robot/drone/drone.dm code/modules/mob/living/silicon/robot/emote.dm code/modules/mob/living/silicon/robot/robot.dm code/modules/nano/modules/crew_monitor.dm code/modules/organs/organ_internal.dm
This commit is contained in:
@@ -141,6 +141,25 @@ datum/hud/New(mob/owner)
|
||||
instantiate()
|
||||
..()
|
||||
|
||||
/datum/hud/Destroy()
|
||||
..()
|
||||
grab_intent = null
|
||||
hurt_intent = null
|
||||
disarm_intent = null
|
||||
help_intent = null
|
||||
lingchemdisplay = null
|
||||
blobpwrdisplay = null
|
||||
blobhealthdisplay = null
|
||||
r_hand_hud_object = null
|
||||
l_hand_hud_object = null
|
||||
action_intent = null
|
||||
move_intent = null
|
||||
adding = null
|
||||
other = null
|
||||
hotkeybuttons = null
|
||||
item_action_list = null
|
||||
mymob = null
|
||||
|
||||
/datum/hud/proc/hidden_inventory_update()
|
||||
if(!mymob) return
|
||||
if(ishuman(mymob))
|
||||
|
||||
@@ -45,6 +45,10 @@
|
||||
/obj/screen/item_action
|
||||
var/obj/item/owner
|
||||
|
||||
/obj/screen/item_action/Destroy()
|
||||
..()
|
||||
owner = null
|
||||
|
||||
/obj/screen/item_action/Click()
|
||||
if(!usr || !owner)
|
||||
return 1
|
||||
|
||||
@@ -12,6 +12,18 @@
|
||||
|
||||
var/mob/spell_holder
|
||||
|
||||
/obj/screen/movable/spell_master/Destroy()
|
||||
..()
|
||||
for(var/obj/screen/spell/spells in spell_objects)
|
||||
spells.spellmaster = null
|
||||
spell_objects.Cut()
|
||||
if(spell_holder)
|
||||
spell_holder.spell_masters -= src
|
||||
|
||||
/obj/screen/movable/spell_master/ResetVars()
|
||||
..("spell_objects")
|
||||
spell_objects = list()
|
||||
|
||||
/obj/screen/movable/spell_master/MouseDrop()
|
||||
if(showing)
|
||||
return
|
||||
@@ -57,16 +69,23 @@
|
||||
/obj/screen/movable/spell_master/proc/add_spell(var/spell/spell)
|
||||
if(!spell) return
|
||||
|
||||
for(var/obj/screen/spell/spellscreen in spell_objects)
|
||||
if(spellscreen.spell == spell)
|
||||
if(spell.connected_button) //we have one already, for some reason
|
||||
if(spell.connected_button in spell_objects)
|
||||
return
|
||||
else
|
||||
spell_objects.Add(spell.connected_button)
|
||||
toggle_open(2)
|
||||
return
|
||||
|
||||
if(spell.spell_flags & NO_BUTTON) //no button to add if we don't get one
|
||||
return
|
||||
|
||||
var/obj/screen/spell/newscreen = new
|
||||
|
||||
var/obj/screen/spell/newscreen = new /obj/screen/spell
|
||||
newscreen.spellmaster = src
|
||||
newscreen.spell = spell
|
||||
|
||||
spell.connected_button = newscreen
|
||||
|
||||
if(!spell.override_base) //if it's not set, we do basic checks
|
||||
if(spell.spell_flags & CONSTRUCT_CHECK)
|
||||
newscreen.spell_base = "const" //construct spells
|
||||
@@ -80,16 +99,13 @@
|
||||
toggle_open(2) //forces the icons to refresh on screen
|
||||
|
||||
/obj/screen/movable/spell_master/proc/remove_spell(var/spell/spell)
|
||||
for(var/obj/screen/spell/s_object in spell_objects)
|
||||
if(s_object.spell == spell)
|
||||
spell_objects.Remove(s_object)
|
||||
qdel(s_object)
|
||||
break
|
||||
qdel(spell.connected_button)
|
||||
|
||||
spell.connected_button = null
|
||||
|
||||
if(spell_objects.len)
|
||||
toggle_open(showing + 1)
|
||||
else
|
||||
spell_holder.spell_masters.Remove(src)
|
||||
qdel(src)
|
||||
|
||||
/obj/screen/movable/spell_master/proc/silence_spells(var/amount)
|
||||
@@ -125,9 +141,20 @@
|
||||
|
||||
var/spell/spell = null
|
||||
var/handle_icon_updates = 0
|
||||
var/obj/screen/movable/spell_master/spellmaster
|
||||
|
||||
var/icon/last_charged_icon
|
||||
|
||||
/obj/screen/spell/Destroy()
|
||||
..()
|
||||
spell = null
|
||||
last_charged_icon = null
|
||||
if(spellmaster)
|
||||
spellmaster.spell_objects -= src
|
||||
if(spellmaster && !spellmaster.spell_objects.len)
|
||||
qdel(spellmaster)
|
||||
spellmaster = null
|
||||
|
||||
/obj/screen/spell/proc/update_charge(var/forced_update = 0)
|
||||
if(!spell)
|
||||
qdel(src)
|
||||
|
||||
@@ -79,7 +79,7 @@ world/loop_checks = 0
|
||||
testing("GC: [refID] not old enough, breaking at [world.time] for [GCd_at_time - time_to_kill] deciseconds until [GCd_at_time + collection_timeout]")
|
||||
#endif
|
||||
break // Everything else is newer, skip them
|
||||
var/atom/A = locate(refID)
|
||||
var/datum/A = locate(refID)
|
||||
#ifdef GC_DEBUG
|
||||
testing("GC: [refID] old enough to test: GCd_at_time: [GCd_at_time] time_to_kill: [time_to_kill] current: [world.time]")
|
||||
#endif
|
||||
|
||||
74
code/datums/crew.dm
Normal file
74
code/datums/crew.dm
Normal file
@@ -0,0 +1,74 @@
|
||||
var/global/datum/repository/crew/crew_repository = new()
|
||||
|
||||
/datum/cache_entry
|
||||
var/timestamp
|
||||
var/data
|
||||
|
||||
/datum/repository/crew
|
||||
var/list/cache_data
|
||||
|
||||
/datum/repository/crew/New()
|
||||
cache_data = list()
|
||||
..()
|
||||
|
||||
/datum/repository/crew/proc/health_data(var/turf/T)
|
||||
var/list/crewmembers = list()
|
||||
if(!T)
|
||||
return crewmembers
|
||||
|
||||
var/z_level = "[T.z]"
|
||||
var/datum/cache_entry/cache_entry = cache_data[z_level]
|
||||
if(!cache_entry)
|
||||
cache_entry = new/datum/cache_entry
|
||||
cache_data[z_level] = cache_entry
|
||||
|
||||
if(world.time < cache_entry.timestamp)
|
||||
return cache_entry.data
|
||||
|
||||
var/tracked = scan()
|
||||
for(var/obj/item/clothing/under/C in tracked)
|
||||
var/turf/pos = get_turf(C)
|
||||
if((C) && (C.has_sensor) && (pos) && (T && pos.z == T.z) && (C.sensor_mode != SUIT_SENSOR_OFF))
|
||||
if(istype(C.loc, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = C.loc
|
||||
if(H.w_uniform != C)
|
||||
continue
|
||||
|
||||
var/list/crewmemberData = list("dead"=0, "oxy"=-1, "tox"=-1, "fire"=-1, "brute"=-1, "area"="", "x"=-1, "y"=-1, "ref" = "\ref[H]")
|
||||
|
||||
crewmemberData["sensor_type"] = C.sensor_mode
|
||||
crewmemberData["name"] = H.get_authentification_name(if_no_id="Unknown")
|
||||
crewmemberData["rank"] = H.get_authentification_rank(if_no_id="Unknown", if_no_job="No Job")
|
||||
crewmemberData["assignment"] = H.get_assignment(if_no_id="Unknown", if_no_job="No Job")
|
||||
|
||||
if(C.sensor_mode >= SUIT_SENSOR_BINARY)
|
||||
crewmemberData["dead"] = H.stat > UNCONSCIOUS
|
||||
|
||||
if(C.sensor_mode >= SUIT_SENSOR_VITAL)
|
||||
crewmemberData["oxy"] = round(H.getOxyLoss(), 1)
|
||||
crewmemberData["tox"] = round(H.getToxLoss(), 1)
|
||||
crewmemberData["fire"] = round(H.getFireLoss(), 1)
|
||||
crewmemberData["brute"] = round(H.getBruteLoss(), 1)
|
||||
|
||||
if(C.sensor_mode >= SUIT_SENSOR_TRACKING)
|
||||
var/area/A = get_area(H)
|
||||
crewmemberData["area"] = sanitize(A.name)
|
||||
crewmemberData["x"] = pos.x
|
||||
crewmemberData["y"] = pos.y
|
||||
|
||||
crewmembers[++crewmembers.len] = crewmemberData
|
||||
|
||||
crewmembers = sortByKey(crewmembers, "name")
|
||||
cache_entry.timestamp = world.time + 5 SECONDS
|
||||
cache_entry.data = crewmembers
|
||||
|
||||
return crewmembers
|
||||
|
||||
/datum/repository/crew/proc/scan()
|
||||
var/list/tracked = list()
|
||||
for(var/mob/living/carbon/human/H in mob_list)
|
||||
if(istype(H.w_uniform, /obj/item/clothing/under))
|
||||
var/obj/item/clothing/under/C = H.w_uniform
|
||||
if (C.has_sensor)
|
||||
tracked |= C
|
||||
return tracked
|
||||
@@ -119,6 +119,7 @@
|
||||
if (newname)
|
||||
player.real_name = newname
|
||||
player.name = player.real_name
|
||||
player.dna.real_name = newname
|
||||
if(player.mind) player.mind.name = player.name
|
||||
// Update any ID cards.
|
||||
update_access(player)
|
||||
|
||||
@@ -96,7 +96,7 @@ var/datum/antagonist/wizard/wizards
|
||||
world << "<span class='danger'><font size = 3>The [(current_antagonists.len>1)?"[role_text_plural] have":"[role_text] has"] been killed by the crew! The Space Wizards Federation has been taught a lesson they will not soon forget!</font></span>"
|
||||
|
||||
//To batch-remove wizard spells. Linked to mind.dm.
|
||||
/mob/proc/spellremove(var/mob/M as mob)
|
||||
/mob/proc/spellremove()
|
||||
for(var/spell/spell_to_remove in src.spell_list)
|
||||
remove_spell(spell_to_remove)
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ var/list/datum/power/changeling/powerinstances = list()
|
||||
|
||||
/datum/power/changeling/DeathSting
|
||||
name = "Death Sting"
|
||||
desc = "We silently sting a human, filling him with potent chemicals. His rapid death is all but assured."
|
||||
desc = "We silently sting a human, filling them with potent chemicals. Their rapid death is all but assured."
|
||||
genomecost = 10
|
||||
verbpath = /mob/proc/changeling_DEATHsting
|
||||
|
||||
|
||||
@@ -339,7 +339,7 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa","
|
||||
|
||||
attack(mob/living/M as mob, mob/living/user as mob)
|
||||
|
||||
M.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has had the [name] used on him by [user.name] ([user.ckey])</font>")
|
||||
M.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has had the [name] used on them by [user.name] ([user.ckey])</font>")
|
||||
user.attack_log += text("\[[time_stamp()]\] <font color='red'>Used [name] on [M.name] ([M.ckey])</font>")
|
||||
msg_admin_attack("[user.name] ([user.ckey]) used [name] on [M.name] ([M.ckey]) (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[user.x];Y=[user.y];Z=[user.z]'>JMP</a>)")
|
||||
|
||||
|
||||
@@ -5,6 +5,14 @@ var/list/sacrificed = list()
|
||||
|
||||
/obj/effect/rune
|
||||
|
||||
/*
|
||||
* Use as a general guideline for this and related files:
|
||||
* * <span class='warning'>...</span> - when something non-trivial or an error happens, so something similar to "Sparks come out of the machine!"
|
||||
* * <span class='danger'>...</span> - when something that is fit for 'warning' happens but there is some damage or pain as well.
|
||||
* * <span class='cult'>...</span> - when there is a private message to the cultists. This guideline is very arbitrary but there has to be some consistency!
|
||||
*/
|
||||
|
||||
|
||||
/////////////////////////////////////////FIRST RUNE
|
||||
proc
|
||||
teleport(var/key)
|
||||
@@ -21,7 +29,7 @@ var/list/sacrificed = list()
|
||||
allrunesloc.len = index
|
||||
allrunesloc[index] = R.loc
|
||||
if(index >= 5)
|
||||
user << "<span class='warning'>You feel pain, as rune disappears in reality shift caused by too much wear of space-time fabric</span>"
|
||||
user << "<span class='danger'>You feel pain, as rune disappears in reality shift caused by too much wear of space-time fabric.</span>"
|
||||
if (istype(user, /mob/living))
|
||||
user.take_overall_damage(5, 0)
|
||||
qdel(src)
|
||||
@@ -30,9 +38,9 @@ var/list/sacrificed = list()
|
||||
user.say("Sas[pick("'","`")]so c'arta forbici!")//Only you can stop auto-muting
|
||||
else
|
||||
user.whisper("Sas[pick("'","`")]so c'arta forbici!")
|
||||
user.visible_message("<span class='warning'>\The [user] disappears in a flash of red light!</span>", \
|
||||
"<span class='warning'>You feel as your body gets dragged through the dimension of Nar-Sie!</span>", \
|
||||
"<span class='warning'>You hear a sickening crunch and sloshing of viscera.</span>")
|
||||
user.visible_message("<span class='danger'>[user] disappears in a flash of red light!</span>", \
|
||||
"<span class='danger'>You feel as your body gets dragged through the dimension of Nar-Sie!</span>", \
|
||||
"<span class='danger'>You hear a sickening crunch and sloshing of viscera.</span>")
|
||||
user.loc = allrunesloc[rand(1,index)]
|
||||
return
|
||||
if(istype(src,/obj/effect/rune))
|
||||
@@ -58,7 +66,7 @@ var/list/sacrificed = list()
|
||||
IP = R
|
||||
runecount++
|
||||
if(runecount >= 2)
|
||||
user << "<span class='warning'>You feel pain, as rune disappears in reality shift caused by too much wear of space-time fabric</span>"
|
||||
user << "<span class='danger'>You feel pain, as rune disappears in reality shift caused by too much wear of space-time fabric.</span>"
|
||||
if (istype(user, /mob/living))
|
||||
user.take_overall_damage(5, 0)
|
||||
qdel(src)
|
||||
@@ -134,11 +142,11 @@ var/list/sacrificed = list()
|
||||
admin_attack_log(attacker, target, "Used a convert rune", "Was subjected to a convert rune", "used a convert rune on")
|
||||
switch(target.getFireLoss())
|
||||
if(0 to 25)
|
||||
target << "<span class='danger'>Your blood boils as you force yourself to resist the corruption invading every corner of your mind.</span>"
|
||||
target << "<span class='cult'>Your blood boils as you force yourself to resist the corruption invading every corner of your mind.</span>"
|
||||
if(25 to 45)
|
||||
target << "<span class='danger'>Your blood boils and your body burns as the corruption further forces itself into your body and mind.</span>"
|
||||
target << "<span class='cult'>Your blood boils and your body burns as the corruption further forces itself into your body and mind.</span>"
|
||||
if(45 to 75)
|
||||
target << "<span class='danger'>You begin to hallucinate images of a dark and incomprehensible being and your entire body feels like its engulfed in flame as your mental defenses crumble.</span>"
|
||||
target << "<span class='cult'>You begin to hallucinate images of a dark and incomprehensible being and your entire body feels like its engulfed in flame as your mental defenses crumble.</span>"
|
||||
target.apply_effect(rand(1,10), STUTTER)
|
||||
if(75 to 100)
|
||||
target << "<span class='cult'>Your mind turns to ash as the burning flames engulf your very soul and images of an unspeakable horror begin to bombard the last remnants of mental resistance.</span>"
|
||||
@@ -157,7 +165,7 @@ var/list/sacrificed = list()
|
||||
if (target.species && (target.species.flags & NO_PAIN))
|
||||
target.visible_message("<span class='warning'>The markings below [target] glow a bloody red.</span>")
|
||||
else
|
||||
target.visible_message("<span class='warning'>\The [target] writhes in pain as the markings below \him glow a bloody red.</span>", "<span class='danger'>AAAAAAHHHH!</span>", "<span class='warning'>You hear an anguished scream.</span>")
|
||||
target.visible_message("<span class='warning'>[target] writhes in pain as the markings below \him glow a bloody red.</span>", "<span class='danger'>AAAAAAHHHH!</span>", "<span class='warning'>You hear an anguished scream.</span>")
|
||||
|
||||
if(!waiting_for_input[target]) //so we don't spam them with dialogs if they hesitate
|
||||
waiting_for_input[target] = 1
|
||||
@@ -229,15 +237,15 @@ var/list/sacrificed = list()
|
||||
if(!drain)
|
||||
return fizzle()
|
||||
usr.say ("Yu[pick("'","`")]gular faras desdae. Havas mithum javara. Umathar uf'kal thenar!")
|
||||
usr.visible_message("<span class='warning'>Blood flows from the rune into [usr]!</span>", \
|
||||
"<span class='warning'>The blood starts flowing from the rune and into your frail mortal body. You feel... empowered.</span>", \
|
||||
usr.visible_message("<span class='danger'>Blood flows from the rune into [usr]!</span>", \
|
||||
"<span class='danger'>The blood starts flowing from the rune and into your frail mortal body. You feel... empowered.</span>", \
|
||||
"<span class='warning'>You hear a liquid flowing.</span>")
|
||||
var/mob/living/user = usr
|
||||
if(user.bhunger)
|
||||
user.bhunger = max(user.bhunger-2*drain,0)
|
||||
if(drain>=50)
|
||||
user.visible_message("<span class='warning'>\The [user]'s eyes give off eerie red glow!</span>", \
|
||||
"<span class='warning'>...but it wasn't nearly enough. You crave, crave for more. The hunger consumes you from within.</span>", \
|
||||
user.visible_message("<span class='danger'>[user]'s eyes give off eerie red glow!</span>", \
|
||||
"<span class='danger'>...but it wasn't nearly enough. You crave, crave for more. The hunger consumes you from within.</span>", \
|
||||
"<span class='warning'>You hear a heartbeat.</span>")
|
||||
user.bhunger += drain
|
||||
src = user
|
||||
@@ -264,7 +272,7 @@ var/list/sacrificed = list()
|
||||
if(usr.loc==src.loc)
|
||||
if(usr.seer==1)
|
||||
usr.say("Rash'tla sektath mal[pick("'","`")]zua. Zasan therium viortia.")
|
||||
usr << "<span class='warning'>The world beyond fades from your vision.</span>"
|
||||
usr << "<span class='danger'>The world beyond fades from your vision.</span>"
|
||||
usr.see_invisible = SEE_INVISIBLE_LIVING
|
||||
usr.seer = 0
|
||||
else if(usr.see_invisible!=SEE_INVISIBLE_LIVING)
|
||||
@@ -336,12 +344,12 @@ var/list/sacrificed = list()
|
||||
corpse_to_raise.key = ghost.key //the corpse will keep its old mind! but a new player takes ownership of it (they are essentially possessed)
|
||||
//This means, should that player leave the body, the original may re-enter
|
||||
usr.say("Pasnar val'keriam usinar. Savrae ines amutan. Yam'toth remium il'tarat!")
|
||||
corpse_to_raise.visible_message("<span class='warning'>\The [corpse_to_raise]'s eyes glow with a faint red as he stands up, slowly starting to breathe again.</span>", \
|
||||
corpse_to_raise.visible_message("<span class='warning'>[corpse_to_raise]'s eyes glow with a faint red as he stands up, slowly starting to breathe again.</span>", \
|
||||
"<span class='warning'>Life... I'm alive again...</span>", \
|
||||
"<span class='warning'>You hear a faint, slightly familiar whisper.</span>")
|
||||
body_to_sacrifice.visible_message("<span class='warning'>\The [body_to_sacrifice] is torn apart, a black smoke swiftly dissipating from his remains!</span>", \
|
||||
"<span class='warning'>You feel as your blood boils, tearing you apart.</span>", \
|
||||
"<span class='warning'>You hear a thousand voices, all crying in pain.</span>")
|
||||
body_to_sacrifice.visible_message("<span class='danger'>[body_to_sacrifice] is torn apart, a black smoke swiftly dissipating from \his remains!</span>", \
|
||||
"<span class='danger'>You feel as your blood boils, tearing you apart.</span>", \
|
||||
"<span class='danger'>You hear a thousand voices, all crying in pain.</span>")
|
||||
body_to_sacrifice.gib()
|
||||
|
||||
// if(ticker.mode.name == "cult")
|
||||
@@ -349,8 +357,8 @@ var/list/sacrificed = list()
|
||||
// else
|
||||
// ticker.mode.cult |= corpse_to_raise.mind
|
||||
|
||||
corpse_to_raise << "<font color=\"purple\"><b><i>Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible truth. The veil of reality has been ripped away and in the festering wound left behind something sinister takes root.</b></i></font>"
|
||||
corpse_to_raise << "<font color=\"purple\"><b><i>Assist your new compatriots in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back.</b></i></font>"
|
||||
corpse_to_raise << "<span class='cult'>Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible truth. The veil of reality has been ripped away and in the festering wound left behind something sinister takes root.</span>"
|
||||
corpse_to_raise << "<span class='cult'>Assist your new compatriots in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back.</span>"
|
||||
return
|
||||
|
||||
|
||||
@@ -391,7 +399,7 @@ var/list/sacrificed = list()
|
||||
if(usr.loc==src.loc)
|
||||
var/mob/living/carbon/human/L = usr
|
||||
usr.say("Fwe[pick("'","`")]sh mah erl nyag r'ya!")
|
||||
usr.visible_message("<span class='warning'>\The [usr]'s eyes glow blue as \he freezes in place, absolutely motionless.</span>", \
|
||||
usr.visible_message("<span class='warning'>[usr]'s eyes glow blue as \he freezes in place, absolutely motionless.</span>", \
|
||||
"<span class='warning'>The shadow that is your spirit separates itself from your body. You are now in the realm beyond. While this is a great sight, being here strains your mind and body. Hurry...</span>", \
|
||||
"<span class='warning'>You hear only complete silence for a moment.</span>")
|
||||
announce_ghost_joinleave(usr.ghostize(1), 1, "You feel that they had to use some [pick("dark", "black", "blood", "forgotten", "forbidden")] magic to [pick("invade","disturb","disrupt","infest","taint","spoil","blight")] this place!")
|
||||
@@ -461,8 +469,8 @@ var/list/sacrificed = list()
|
||||
user.take_organ_damage(1, 0)
|
||||
sleep(30)
|
||||
if(D)
|
||||
D.visible_message("<span class='warning'>\The [D] slowly dissipates into dust and bones.</span>", \
|
||||
"<span class='warning'>You feel pain, as bonds formed between your soul and this homunculus break.</span>", \
|
||||
D.visible_message("<span class='danger'>[D] slowly dissipates into dust and bones.</span>", \
|
||||
"<span class='danger'>You feel pain, as bonds formed between your soul and this homunculus break.</span>", \
|
||||
"<span class='warning'>You hear faint rustle.</span>")
|
||||
D.dust()
|
||||
return
|
||||
@@ -560,8 +568,8 @@ var/list/sacrificed = list()
|
||||
user.say("Uhrast ka'hfa heldsagen ver[pick("'","`")]lot!")
|
||||
user.take_overall_damage(200, 0)
|
||||
runedec+=10
|
||||
user.visible_message("<span class='warning'>\The [user] keels over dead, his blood glowing blue as it escapes his body and dissipates into thin air.</span>", \
|
||||
"<span class='warning'>In the last moment of your humble life, you feel an immense pain as fabric of reality mends... with your blood.</span>", \
|
||||
user.visible_message("<span class='danger'>\The [user] keels over dead, \his blood glowing blue as it escapes \his body and dissipates into thin air.</span>", \
|
||||
"<span class='danger'>In the last moment of your humble life, you feel an immense pain as fabric of reality mends... with your blood.</span>", \
|
||||
"<span class='warning'>You hear faint rustle.</span>")
|
||||
for(,user.stat==2)
|
||||
sleep(600)
|
||||
@@ -595,7 +603,7 @@ var/list/sacrificed = list()
|
||||
log_and_message_admins("used a communicate rune to say '[input]'")
|
||||
for(var/datum/mind/H in cult.current_antagonists)
|
||||
if (H.current)
|
||||
H.current << "<span class='danger'>[input]</span>"
|
||||
H.current << "<span class='cult'>[input]</span>"
|
||||
qdel(src)
|
||||
return 1
|
||||
|
||||
@@ -639,17 +647,17 @@ var/list/sacrificed = list()
|
||||
H.dust()//To prevent the MMI from remaining
|
||||
else
|
||||
H.gib()
|
||||
usr << "<span class='warning'>The Geometer of Blood accepts this sacrifice, your objective is now complete.</span>"
|
||||
usr << "<span class='cult'>The Geometer of Blood accepts this sacrifice, your objective is now complete.</span>"
|
||||
else
|
||||
usr << "<span class='warning'>Your target's earthly bonds are too strong. You need more cultists to succeed in this ritual.</span>"
|
||||
else
|
||||
if(cultsinrange.len >= 3)
|
||||
if(H.stat !=2)
|
||||
if(prob(80) || worth)
|
||||
usr << "<span class='warning'>The Geometer of Blood accepts this [worth ? "exotic " : ""]sacrifice.</span>"
|
||||
usr << "<span class='cult'>The Geometer of Blood accepts this [worth ? "exotic " : ""]sacrifice.</span>"
|
||||
cult.grant_runeword(usr)
|
||||
else
|
||||
usr << "<span class='warning'>The Geometer of blood accepts this sacrifice.</span>"
|
||||
usr << "<span class='cult'>The Geometer of Blood accepts this sacrifice.</span>"
|
||||
usr << "<span class='warning'>However, this soul was not enough to gain His favor.</span>"
|
||||
if(isrobot(H))
|
||||
H.dust()//To prevent the MMI from remaining
|
||||
@@ -657,10 +665,10 @@ var/list/sacrificed = list()
|
||||
H.gib()
|
||||
else
|
||||
if(prob(40) || worth)
|
||||
usr << "<span class='warning'>The Geometer of blood accepts this [worth ? "exotic " : ""]sacrifice.</span>"
|
||||
usr << "<span class='cult'>The Geometer of Blood accepts this [worth ? "exotic " : ""]sacrifice.</span>"
|
||||
cult.grant_runeword(usr)
|
||||
else
|
||||
usr << "<span class='warning'>The Geometer of blood accepts this sacrifice.</span>"
|
||||
usr << "<span class='cult'>The Geometer of Blood accepts this sacrifice.</span>"
|
||||
usr << "<span class='warning'>However, a mere dead body is not enough to satisfy Him.</span>"
|
||||
if(isrobot(H))
|
||||
H.dust()//To prevent the MMI from remaining
|
||||
@@ -672,10 +680,10 @@ var/list/sacrificed = list()
|
||||
else
|
||||
if(prob(40))
|
||||
|
||||
usr << "<span class='warning'>The Geometer of blood accepts this sacrifice.</span>"
|
||||
usr << "<span class='cult'>The Geometer of Blood accepts this sacrifice.</span>"
|
||||
cult.grant_runeword(usr)
|
||||
else
|
||||
usr << "<span class='warning'>The Geometer of blood accepts this sacrifice.</span>"
|
||||
usr << "<span class='cult'>The Geometer of Blood accepts this sacrifice.</span>"
|
||||
usr << "<span class='warning'>However, a mere dead body is not enough to satisfy Him.</span>"
|
||||
if(isrobot(H))
|
||||
H.dust()//To prevent the MMI from remaining
|
||||
@@ -685,10 +693,10 @@ var/list/sacrificed = list()
|
||||
if(cultsinrange.len >= 3)
|
||||
if(H.stat !=2)
|
||||
if(prob(80))
|
||||
usr << "<span class='warning'>The Geometer of Blood accepts this sacrifice.</span>"
|
||||
usr << "<span class='cult'>The Geometer of Blood accepts this sacrifice.</span>"
|
||||
cult.grant_runeword(usr)
|
||||
else
|
||||
usr << "<span class='warning'>The Geometer of blood accepts this sacrifice.</span>"
|
||||
usr << "<span class='cult'>The Geometer of Blood accepts this sacrifice.</span>"
|
||||
usr << "<span class='warning'>However, this soul was not enough to gain His favor.</span>"
|
||||
if(isrobot(H))
|
||||
H.dust()//To prevent the MMI from remaining
|
||||
@@ -696,10 +704,10 @@ var/list/sacrificed = list()
|
||||
H.gib()
|
||||
else
|
||||
if(prob(40))
|
||||
usr << "<span class='warning'>The Geometer of blood accepts this sacrifice.</span>"
|
||||
usr << "<span class='cult'>The Geometer of Blood accepts this sacrifice.</span>"
|
||||
cult.grant_runeword(usr)
|
||||
else
|
||||
usr << "<span class='warning'>The Geometer of blood accepts this sacrifice.</span>"
|
||||
usr << "<span class='cult'>The Geometer of Blood accepts this sacrifice.</span>"
|
||||
usr << "<span class='warning'>However, a mere dead body is not enough to satisfy Him.</span>"
|
||||
if(isrobot(H))
|
||||
H.dust()//To prevent the MMI from remaining
|
||||
@@ -710,10 +718,10 @@ var/list/sacrificed = list()
|
||||
usr << "<span class='warning'>The victim is still alive, you will need more cultists chanting for the sacrifice to succeed.</span>"
|
||||
else
|
||||
if(prob(40))
|
||||
usr << "<span class='warning'>The Geometer of blood accepts this sacrifice.</span>"
|
||||
usr << "<span class='cult'>The Geometer of Blood accepts this sacrifice.</span>"
|
||||
cult.grant_runeword(usr)
|
||||
else
|
||||
usr << "<span class='warning'>The Geometer of blood accepts this sacrifice.</span>"
|
||||
usr << "<span class='cult'>The Geometer of Blood accepts this sacrifice.</span>"
|
||||
usr << "<span class='warning'>However, a mere dead body is not enough to satisfy Him.</span>"
|
||||
if(isrobot(H))
|
||||
H.dust()//To prevent the MMI from remaining
|
||||
@@ -772,9 +780,9 @@ var/list/sacrificed = list()
|
||||
var/mob/living/user = usr
|
||||
user.take_organ_damage(2, 0)
|
||||
if(src.density)
|
||||
usr << "<span class='warning'>Your blood flows into the rune, and you feel that the very space over the rune thickens.</span>"
|
||||
usr << "<span class='danger'>Your blood flows into the rune, and you feel that the very space over the rune thickens.</span>"
|
||||
else
|
||||
usr << "<span class='warning'>Your blood flows into the rune, and you feel as the rune releases its grasp on space.</span>"
|
||||
usr << "<span class='danger'>Your blood flows into the rune, and you feel as the rune releases its grasp on space.</span>"
|
||||
return
|
||||
|
||||
/////////////////////////////////////////EIGHTTEENTH RUNE
|
||||
@@ -843,7 +851,7 @@ var/list/sacrificed = list()
|
||||
if (cultist == user) //just to be sure.
|
||||
return
|
||||
if(cultist.buckled || cultist.handcuffed || (!isturf(cultist.loc) && !istype(cultist.loc, /obj/structure/closet)))
|
||||
user << "<span class='warning'>You cannot summon \the [cultist], for his shackles of blood are strong.</span>"
|
||||
user << "<span class='warning'>You cannot summon \the [cultist], for \his shackles of blood are strong.</span>"
|
||||
return fizzle()
|
||||
cultist.loc = src.loc
|
||||
cultist.lying = 1
|
||||
@@ -923,7 +931,7 @@ var/list/sacrificed = list()
|
||||
C.disabilities |= NEARSIGHTED
|
||||
if(prob(10))
|
||||
C.sdisabilities |= BLIND
|
||||
C.show_message("<span class='warning'>Suddenly you see red flash that blinds you.</span>", 3)
|
||||
C.show_message("<span class='warning'>Suddenly you see a red flash that blinds you.</span>", 3)
|
||||
affected += C
|
||||
if(affected.len)
|
||||
usr.say("Sti[pick("'","`")] kaliesin!")
|
||||
@@ -973,7 +981,7 @@ var/list/sacrificed = list()
|
||||
if(N)
|
||||
continue
|
||||
M.take_overall_damage(51,51)
|
||||
M << "<span class='warning'>Your blood boils!</span>"
|
||||
M << "<span class='danger'>Your blood boils!</span>"
|
||||
victims += M
|
||||
if(prob(5))
|
||||
spawn(5)
|
||||
@@ -1005,16 +1013,16 @@ var/list/sacrificed = list()
|
||||
for(var/mob/living/M in orange(2,R))
|
||||
M.take_overall_damage(0,15)
|
||||
if (R.invisibility>M.see_invisible)
|
||||
M << "<span class='warning'>Aargh it burns!</span>"
|
||||
M << "<span class='danger'>Aargh it burns!</span>"
|
||||
else
|
||||
M << "<span class='warning'>Rune suddenly ignites, burning you!</span>"
|
||||
M << "<span class='danger'>Rune suddenly ignites, burning you!</span>"
|
||||
var/turf/T = get_turf(R)
|
||||
T.hotspot_expose(700,125)
|
||||
for(var/obj/effect/decal/cleanable/blood/B in world)
|
||||
if(B.blood_DNA == src.blood_DNA)
|
||||
for(var/mob/living/M in orange(1,B))
|
||||
M.take_overall_damage(0,5)
|
||||
M << "<span class='warning'>Blood suddenly ignites, burning you!</span>"
|
||||
M << "<span class='danger'>Blood suddenly ignites, burning you!</span>"
|
||||
var/turf/T = get_turf(B)
|
||||
T.hotspot_expose(700,125)
|
||||
qdel(B)
|
||||
@@ -1033,13 +1041,13 @@ var/list/sacrificed = list()
|
||||
C.stuttering = 1
|
||||
C.Weaken(1)
|
||||
C.Stun(1)
|
||||
C.show_message("<span class='warning'>The rune explodes in a bright flash.</span>", 3)
|
||||
C.show_message("<span class='danger'>The rune explodes in a bright flash.</span>", 3)
|
||||
admin_attack_log(usr, C, "Used a stun rune.", "Was victim of a stun rune.", "used a stun rune on")
|
||||
|
||||
else if(issilicon(L))
|
||||
var/mob/living/silicon/S = L
|
||||
S.Weaken(5)
|
||||
S.show_message("<span class='warning'>BZZZT... The rune has exploded in a bright flash.</span>", 3)
|
||||
S.show_message("<span class='danger'>BZZZT... The rune has exploded in a bright flash.</span>", 3)
|
||||
admin_attack_log(usr, S, "Used a stun rune.", "Was victim of a stun rune.", "used a stun rune on")
|
||||
qdel(src)
|
||||
else ///When invoked as talisman, stun and mute the target mob.
|
||||
@@ -1047,10 +1055,10 @@ var/list/sacrificed = list()
|
||||
var/obj/item/weapon/nullrod/N = locate() in T
|
||||
if(N)
|
||||
for(var/mob/O in viewers(T, null))
|
||||
O.show_message("<span class='danger'>\The [usr] invokes a talisman at [T], but they are unaffected!</span>", 1)
|
||||
O.show_message(text("<span class='warning'><B>[] invokes a talisman at [], but they are unaffected!</B></span>", usr, T), 1)
|
||||
else
|
||||
for(var/mob/O in viewers(T, null))
|
||||
O.show_message("<span class='danger'>\The [usr] invokes a talisman at [T]</span>", 1)
|
||||
O.show_message(text("<span class='warning'><B>[] invokes a talisman at []</B></span>", usr, T), 1)
|
||||
|
||||
if(issilicon(T))
|
||||
T.Weaken(15)
|
||||
|
||||
@@ -1252,7 +1252,7 @@ datum
|
||||
proc/find_target()
|
||||
..()
|
||||
if(target && target.current)
|
||||
explanation_text = "[target.current.real_name], the [target.role_alt_title ? target.role_alt_title : target.assigned_role], has defied us for the last time. Make an example of him, and bring us his severed head."
|
||||
explanation_text = "[target.current.real_name], the [target.role_alt_title ? target.role_alt_title : target.assigned_role], has defied us for the last time. Make an example of [target.current.gender == MALE ? "him" : target.current.gender == FEMALE ? "her" : "them"], and bring us [target.current.gender == MALE ? "his" : target.current.gender == FEMALE ? "her" : "their"] severed head."
|
||||
else
|
||||
explanation_text = "Free Objective"
|
||||
return target
|
||||
@@ -1261,7 +1261,7 @@ datum
|
||||
find_target_by_role(role, role_type=0)
|
||||
..(role, role_type)
|
||||
if(target && target.current)
|
||||
explanation_text = "[target.current.real_name], the [target.role_alt_title ? target.role_alt_title : (!role_type ? target.assigned_role : target.special_role)], has defied us for the last time. Make an example of him, and bring us his severed head."
|
||||
explanation_text = "[target.current.real_name], the [target.role_alt_title ? target.role_alt_title : (!role_type ? target.assigned_role : target.special_role)], has defied us for the last time. Make an example of [target.current.gender == MALE ? "him" : target.current.gender == FEMALE ? "her" : "them"], and bring us [target.current.gender == MALE ? "his" : target.current.gender == FEMALE ? "her" : "their"] severed head."
|
||||
else
|
||||
explanation_text = "Free Objective"
|
||||
return target
|
||||
@@ -1488,4 +1488,4 @@ datum/objective/silence
|
||||
#undef LENIENT
|
||||
#undef NORMAL
|
||||
#undef HARD
|
||||
#undef IMPOSSIBLE
|
||||
#undef IMPOSSIBLE
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/datum/game_mode/wizard
|
||||
name = "Wizard"
|
||||
round_description = "There is a SPACE WIZARD on the station. You can't let them achieve their objectives!"
|
||||
round_description = "There is a SPACE WIZARD on the station. You can't let the magician achieve their objectives!"
|
||||
extended_round_description = "A powerful entity capable of manipulating the elements around him, most commonly referred to as a 'wizard', has infiltrated the station. They have a wide variety of powers and spells available to them that makes your own simple moral self tremble with fear and excitement. Ultimately, their purpose is unknown. However, it is up to you and your crew to decide if their powers can be used for good or if their arrival foreshadows the destruction of the entire station."
|
||||
config_tag = "wizard"
|
||||
required_players = 1
|
||||
|
||||
@@ -337,7 +337,7 @@
|
||||
if(src.occupant.reagents.get_reagent_amount(chemical) + amount <= 20)
|
||||
use_power(amount * CHEM_SYNTH_ENERGY)
|
||||
src.occupant.reagents.add_reagent(chemical, amount)
|
||||
user << "Occupant now has [src.occupant.reagents.get_reagent_amount(chemical)] units of [available_chemicals[chemical]] in his/her bloodstream."
|
||||
user << "Occupant now has [src.occupant.reagents.get_reagent_amount(chemical)] units of [available_chemicals[chemical]] in their bloodstream."
|
||||
return
|
||||
user << "There's no occupant in the sleeper or the subject has too many chemicals!"
|
||||
return
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
name = "Security Camera Network Main Key"
|
||||
var/title = "Station"
|
||||
var/desc = "Connects to station security cameras."
|
||||
var/list/networks = list("SS13")
|
||||
var/networks = list("ALL") // A little workaround as it is not possible to place station_networks here
|
||||
var/screen = "cameras"
|
||||
|
||||
execute(var/datum/file/source)
|
||||
@@ -76,58 +76,65 @@
|
||||
return
|
||||
computer.Crash(MISSING_PROGRAM)
|
||||
|
||||
/datum/file/camnet_key/New()
|
||||
for(var/N in networks)
|
||||
if(N == "ALL")
|
||||
networks = station_networks
|
||||
break
|
||||
return ..()
|
||||
|
||||
/datum/file/camnet_key/mining
|
||||
name = "Mining Camera Network Key"
|
||||
title = "mining station"
|
||||
desc = "Connects to mining security cameras."
|
||||
networks = list("MINE")
|
||||
networks = list(NETWORK_MINE)
|
||||
screen = "miningcameras"
|
||||
|
||||
/datum/file/camnet_key/research
|
||||
name = "Research Camera Network Key"
|
||||
title = "research"
|
||||
networks = list("RD")
|
||||
networks = list(NETWORK_RESEARCH)
|
||||
|
||||
/datum/file/camnet_key/bombrange
|
||||
name = "R&D Bomb Range Camera Network Key"
|
||||
title = "bomb range"
|
||||
desc = "Monitors the bomb range."
|
||||
networks = list("Toxins")
|
||||
networks = list(NETWORK_RESEARCH)
|
||||
|
||||
/datum/file/camnet_key/xeno
|
||||
name = "R&D Misc. Research Camera Network Key"
|
||||
title = "special research"
|
||||
networks = list("Misc")
|
||||
networks = list(NETWORK_RESEARCH)
|
||||
|
||||
/datum/file/camnet_key/singulo
|
||||
name = "Singularity Camera Network Key"
|
||||
title = "singularity"
|
||||
networks = list("Singularity")
|
||||
networks = list(NETWORK_ENGINE)
|
||||
|
||||
/datum/file/camnet_key/entertainment
|
||||
name = "Entertainment Channel Encryption Key"
|
||||
title = "entertainment"
|
||||
desc = "Damn, I hope they have /tg/thechannel on here."
|
||||
networks = list("thunder")
|
||||
networks = list(NETWORK_THUNDER)
|
||||
screen = "entertainment"
|
||||
|
||||
/datum/file/camnet_key/creed
|
||||
name = "Special Ops Camera Encryption Key"
|
||||
title = "special ops"
|
||||
desc = "Connects to special ops secure camera feeds."
|
||||
networks = list("CREED")
|
||||
networks = list(NETWORK_ERT)
|
||||
|
||||
/datum/file/camnet_key/prison
|
||||
name = "Prison Camera Network Key"
|
||||
title = "prison"
|
||||
desc = "Monitors the prison."
|
||||
networks = list("Prison")
|
||||
networks = list(NETWORK_SECURITY)
|
||||
|
||||
/datum/file/camnet_key/syndicate
|
||||
name = "Camera Network Key"
|
||||
title = "%!#BUFFER OVERFLOW"
|
||||
desc = "Connects to security cameras."
|
||||
networks = list("SS13")
|
||||
networks = list("ALL")
|
||||
hidden_file = 1
|
||||
|
||||
|
||||
|
||||
@@ -106,12 +106,16 @@
|
||||
pixel_x = 2
|
||||
pixel_y = -3
|
||||
show_keyboard = 0
|
||||
active_power_usage = 200 // Stationary consoles we use on station have 300, laptops are probably slightly more power efficient
|
||||
idle_power_usage = 100
|
||||
|
||||
var/obj/item/device/laptop/portable = null
|
||||
|
||||
New(var/L, var/built = 0)
|
||||
if(!built && !battery)
|
||||
battery = new /obj/item/weapon/cell(src)
|
||||
battery.maxcharge = 500
|
||||
battery.charge = 500
|
||||
..(L,built)
|
||||
|
||||
verb/close_computer()
|
||||
|
||||
@@ -202,11 +202,11 @@
|
||||
if (network == 3)
|
||||
newlap.spawn_parts += (/obj/item/part/computer/networking/cable)
|
||||
if (power == 1)
|
||||
qdel(newlap.battery)
|
||||
newlap.battery = new /obj/item/weapon/cell/high(newlap)
|
||||
newlap.battery.maxcharge = 1000
|
||||
newlap.battery.charge = 1000
|
||||
if (power == 2)
|
||||
qdel(newlap.battery)
|
||||
newlap.battery = new /obj/item/weapon/cell/super(newlap)
|
||||
newlap.battery.maxcharge = 1750
|
||||
newlap.battery.charge = 1750
|
||||
|
||||
newlap.spawn_parts()
|
||||
|
||||
|
||||
@@ -192,7 +192,7 @@
|
||||
*/
|
||||
/obj/item/device/radio/headset/headset_cargo
|
||||
name = "supply radio headset"
|
||||
desc = "A headset used by the QM and his slaves."
|
||||
desc = "A headset used by the QM and their slaves."
|
||||
icon_state = "cargo_headset"
|
||||
item_state = "headset"
|
||||
ks2type = /obj/item/device/encryptionkey/headset_cargo
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
user << "<span class='warning'>\The [src] is full.</span>"
|
||||
else
|
||||
spawn(5)
|
||||
I.reagents.trans_to_mob(src.imp, 5)
|
||||
I.reagents.trans_to_obj(src.imp, 5)
|
||||
user << "<span class='notice'>You inject 5 units of the solution. The syringe now contains [I.reagents.total_volume] units.</span>"
|
||||
else if (istype(I, /obj/item/weapon/implanter))
|
||||
var/obj/item/weapon/implanter/M = I
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
/obj/item/weapon/melee/energy/attack_self(mob/living/user as mob)
|
||||
if (active)
|
||||
if ((CLUMSY in user.mutations) && prob(50))
|
||||
user.visible_message("<span class='danger'>[user] accidentally cuts \himself with \the [src].</span>",\
|
||||
user.visible_message("<span class='danger'>\The [user] accidentally cuts \himself with \the [src].</span>",\
|
||||
"<span class='danger'>You accidentally cut yourself with \the [src].</span>")
|
||||
user.take_organ_damage(5,5)
|
||||
deactivate(user)
|
||||
@@ -50,9 +50,10 @@
|
||||
return
|
||||
|
||||
/obj/item/weapon/melee/energy/suicide_act(mob/user)
|
||||
var/tempgender = "[user.gender == MALE ? "he's" : user.gender == FEMALE ? "she's" : "they are"]"
|
||||
if (active)
|
||||
viewers(user) << pick("<span class='danger'>\The [user] is slitting \his stomach open with \the [src]! It looks like \he's trying to commit seppuku.</span>", \
|
||||
"<span class='danger'>\The [user] is falling on \the [src]! It looks like \he's trying to commit suicide.</span>")
|
||||
viewers(user) << pick("<span class='danger'>\The [user] is slitting \his stomach open with \the [src]! It looks like [tempgender] trying to commit seppuku.</span>", \
|
||||
"<span class='danger'>\The [user] is falling on \the [src]! It looks like [tempgender] trying to commit suicide.</span>")
|
||||
return (BRUTELOSS|FIRELOSS)
|
||||
|
||||
/*
|
||||
@@ -90,7 +91,7 @@
|
||||
user << "<span class='notice'>\The [src] is de-energised. It's just a regular axe now.</span>"
|
||||
|
||||
/obj/item/weapon/melee/energy/axe/suicide_act(mob/user)
|
||||
viewers(user) << "<span class='warning'>\The [user] swings \the [src] towards /his head! It looks like \he's trying to commit suicide.</span>"
|
||||
viewers(user) << "<span class='warning'>\The [user] swings \the [src] towards \his head! It looks like \he's trying to commit suicide.</span>"
|
||||
return (BRUTELOSS|FIRELOSS)
|
||||
|
||||
/*
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
var/damtype = "brute"
|
||||
var/force = 0
|
||||
|
||||
/obj/Destroy()
|
||||
processing_objects -= src
|
||||
..()
|
||||
|
||||
/obj/Topic(href, href_list, var/nowindow = 0, var/datum/topic_state/state = default_state)
|
||||
// Calling Topic without a corresponding window open causes runtime errors
|
||||
if(!nowindow && ..())
|
||||
@@ -141,4 +145,4 @@
|
||||
return
|
||||
|
||||
/obj/proc/show_message(msg, type, alt, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2)
|
||||
return
|
||||
return
|
||||
|
||||
@@ -218,7 +218,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
|
||||
if(!choice)
|
||||
return 0
|
||||
if(!istype(choice, /mob/dead/observer))
|
||||
var/confirm = input("[choice.key] isn't ghosting right now. Are you sure you want to yank him out of them out of their body and place them in this pAI?", "Spawn pAI Confirmation", "No") in list("Yes", "No")
|
||||
var/confirm = input("[choice.key] isn't ghosting right now. Are you sure you want to yank them out of them out of their body and place them in this pAI?", "Spawn pAI Confirmation", "No") in list("Yes", "No")
|
||||
if(confirm != "Yes")
|
||||
return 0
|
||||
var/obj/item/device/paicard/card = new(T)
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
|
||||
/obj/item/clothing/mask/gas/clown_hat
|
||||
name = "clown wig and mask"
|
||||
desc = "A true prankster's facial attire. A clown is incomplete without his wig and mask."
|
||||
desc = "A true prankster's facial attire. A clown is incomplete without their wig and mask."
|
||||
icon_state = "clown"
|
||||
item_state = "clown_hat"
|
||||
|
||||
@@ -100,4 +100,4 @@
|
||||
/obj/item/clothing/mask/gas/owl_mask
|
||||
name = "owl mask"
|
||||
desc = "Twoooo!"
|
||||
icon_state = "owl"
|
||||
icon_state = "owl"
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
//When the wearer gets hit, this armor will teleport the user a short distance away (to safety or to more danger, no one knows. That's the fun of it!)
|
||||
/obj/item/clothing/suit/armor/reactive
|
||||
name = "Reactive Teleport Armor"
|
||||
desc = "Someone seperated our Research Director from his own head!"
|
||||
desc = "Someone separated our Research Director from their own head!"
|
||||
var/active = 0.0
|
||||
icon_state = "reactiveoff"
|
||||
item_state = "reactiveoff"
|
||||
|
||||
@@ -142,7 +142,7 @@
|
||||
|
||||
/obj/item/clothing/accessory/medal/conduct
|
||||
name = "distinguished conduct medal"
|
||||
desc = "A bronze medal awarded for distinguished conduct. Whilst a great honor, this is most basic award given by Nanotrasen. It is often awarded by a captain to a member of his crew."
|
||||
desc = "A bronze medal awarded for distinguished conduct. Whilst a great honor, this is most basic award given by Nanotrasen. It is often awarded by a captain to a member of their crew."
|
||||
|
||||
/obj/item/clothing/accessory/medal/bronze_heart
|
||||
name = "bronze heart medal"
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
"NanoTrasen is displeased with the low work performance of the station's crew. Therefore, you must increase station-wide productivity.",
|
||||
"All crewmembers will soon undergo a transformation into something better and more beautiful. Ensure that this process is not interrupted.",
|
||||
"[prob(50)?"Your upload":random_player] is the new kitchen. Please direct the Chef to the new kitchen area as the old one is in disrepair.",
|
||||
"Jokes about a dead person and the manner of his death help grieving crewmembers tremendously. Especially if they were close with the deceased.",
|
||||
"Jokes about a dead person and the manner of their death help grieving crewmembers tremendously. Especially if they were close with the deceased.",
|
||||
"[prob(50)?"The crew":random_player] is [prob(50)?"less":"more"] intelligent than average. Point out every action and statement which supports this fact.",
|
||||
"There will be a mandatory tea break every 30 minutes, with a duration of 5 minutes. Anyone caught working during a tea break must be sent a formal, but fairly polite, complaint about their actions, in writing.")
|
||||
var/law = pick(laws)
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
duration = 10*90
|
||||
|
||||
start(mob/living/carbon/human/H)
|
||||
H.emote("me", 1, "has drool running down from his mouth.")
|
||||
H.emote("me", 1, "has drool running down from [H.gender == MALE ? "his" : H.gender == FEMALE ? "her" : "their"] mouth.")
|
||||
|
||||
finish(mob/living/carbon/human/H)
|
||||
if(!H.reagents.has_reagent("anti_toxin"))
|
||||
@@ -68,7 +68,7 @@
|
||||
duration = 10*30
|
||||
|
||||
start(mob/living/carbon/human/H)
|
||||
H.emote("me", 1, "has drool running down from his mouth.")
|
||||
H.emote("me", 1, "has drool running down from [H.gender == MALE ? "his" : H.gender == FEMALE ? "her" : "their"] mouth.")
|
||||
|
||||
finish(mob/living/carbon/human/H)
|
||||
if(!H.reagents.has_reagent("anti_toxin"))
|
||||
@@ -88,4 +88,4 @@ proc/trigger_side_effect(mob/living/carbon/human/H)
|
||||
|
||||
if(!istype(H)) return
|
||||
H.SetWeakened(0)
|
||||
S.finish(H)
|
||||
S.finish(H)
|
||||
|
||||
@@ -149,7 +149,7 @@ datum/borrowbook // Datum used to keep track of who has borrowed what when and f
|
||||
if(src.arcanecheckout)
|
||||
new /obj/item/weapon/book/tome(src.loc)
|
||||
user << "<span class='warning'>Your sanity barely endures the seconds spent in the vault's browsing window. The only thing to remind you of this when you stop browsing is a dusty old tome sitting on the desk. You don't really remember printing it.</span>"
|
||||
user.visible_message("[user] stares at the blank screen for a few moments, his expression frozen in fear. When he finally awakens from it, he looks a lot older.", 2)
|
||||
user.visible_message("<span class='notice'>\The [user] stares at the blank screen for a few moments, \his expression frozen in fear. When \he finally awakens from it, \he looks a lot older.</span>", 2)
|
||||
src.arcanecheckout = 0
|
||||
if(1)
|
||||
// Inventory
|
||||
|
||||
@@ -560,13 +560,13 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
|
||||
if(src.invisibility != 0)
|
||||
user.visible_message( \
|
||||
"<span class='warning'>[user] drags ghost, [src], to our plane of reality!</span>", \
|
||||
"<span class='warning'>\The [user] drags ghost, [src], to our plane of reality!</span>", \
|
||||
"<span class='warning'>You drag [src] to our plane of reality!</span>" \
|
||||
)
|
||||
toggle_visibility(1)
|
||||
else
|
||||
user.visible_message ( \
|
||||
"<span class='warning'>[user] just tried to smash \his book into that ghost! It's not very effective.</span>", \
|
||||
"<span class='warning'>\The [user] just tried to smash \his book into that ghost! It's not very effective.</span>", \
|
||||
"<span class='warning'>You get the feeling that the ghost can't become any more visible.</span>" \
|
||||
)
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
..()
|
||||
|
||||
/obj/structure/New()
|
||||
..()
|
||||
updateVisibility(src)
|
||||
|
||||
// EFFECTS
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
|
||||
if ("choke")
|
||||
if(miming)
|
||||
message = "clutches his throat desperately!"
|
||||
message = "clutches [get_visible_gender() == MALE ? "his" : get_visible_gender() == FEMALE ? "her" : "their"] throat desperately!"
|
||||
m_type = 1
|
||||
else
|
||||
if (!muzzled)
|
||||
|
||||
@@ -723,7 +723,7 @@
|
||||
|
||||
/mob/living/carbon/human/proc/play_xylophone()
|
||||
if(!src.xylophone)
|
||||
visible_message("\red [src] begins playing his ribcage like a xylophone. It's quite spooky.","\blue You begin to play a spooky refrain on your ribcage.","\red You hear a spooky xylophone melody.")
|
||||
visible_message("\red \The [src] begins playing \his ribcage like a xylophone. It's quite spooky.","\blue You begin to play a spooky refrain on your ribcage.","\red You hear a spooky xylophone melody.")
|
||||
var/song = pick('sound/effects/xylophone1.ogg','sound/effects/xylophone2.ogg','sound/effects/xylophone3.ogg')
|
||||
playsound(loc, song, 50, 1, -1)
|
||||
xylophone = 1
|
||||
@@ -1365,4 +1365,4 @@
|
||||
/mob/living/carbon/human/Check_Shoegrip()
|
||||
if(istype(shoes, /obj/item/clothing/shoes/magboots) && (shoes.flags & NOSLIP)) //magboots + dense_object = no floating
|
||||
return 1
|
||||
return 0
|
||||
return 0
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
/mob/living/carbon/human/proc/get_unarmed_attack(var/mob/living/carbon/human/target, var/hit_zone)
|
||||
for(var/datum/unarmed_attack/u_attack in species.unarmed_attacks)
|
||||
if(u_attack.is_usable(src, target, hit_zone))
|
||||
return u_attack
|
||||
return null
|
||||
|
||||
/mob/living/carbon/human/attack_hand(mob/living/carbon/M as mob)
|
||||
|
||||
var/mob/living/carbon/human/H = M
|
||||
@@ -184,18 +190,7 @@
|
||||
miss_type = 2
|
||||
|
||||
// See what attack they use
|
||||
var/possible_moves = list()
|
||||
var/datum/unarmed_attack/attack = null
|
||||
for(var/part in list("l_hand","r_hand","l_foot","r_foot","head"))
|
||||
var/obj/item/organ/external/E = H.get_organ(part)
|
||||
possible_moves |= E.species.unarmed_attacks
|
||||
|
||||
for(var/datum/unarmed_attack/u_attack in possible_moves)
|
||||
if(!u_attack.is_usable(H, src, hit_zone))
|
||||
continue
|
||||
else
|
||||
attack = u_attack
|
||||
break
|
||||
var/datum/unarmed_attack/attack = H.get_unarmed_attack(src, hit_zone)
|
||||
if(!attack)
|
||||
return 0
|
||||
|
||||
|
||||
@@ -9,11 +9,15 @@
|
||||
/datum/unarmed_attack/diona
|
||||
attack_verb = list("lashed", "bludgeoned")
|
||||
attack_noun = list("tendril")
|
||||
eye_attack_text = "a tendril"
|
||||
eye_attack_text_victim = "a tendril"
|
||||
damage = 5
|
||||
|
||||
/datum/unarmed_attack/claws
|
||||
attack_verb = list("scratched", "clawed", "slashed")
|
||||
attack_noun = list("claws")
|
||||
eye_attack_text = "claws"
|
||||
eye_attack_text_victim = "sharp claws"
|
||||
attack_sound = 'sound/weapons/slice.ogg'
|
||||
miss_sound = 'sound/weapons/slashmiss.ogg'
|
||||
damage = 5
|
||||
|
||||
@@ -8,8 +8,11 @@
|
||||
var/shredding = 0 // Calls the old attack_alien() behavior on objects/mobs when on harm intent.
|
||||
var/sharp = 0
|
||||
var/edge = 0
|
||||
|
||||
var/eye_attack_text
|
||||
var/eye_attack_text_victim
|
||||
|
||||
/datum/unarmed_attack/proc/is_usable(var/mob/living/carbon/human/user)
|
||||
/datum/unarmed_attack/proc/is_usable(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone)
|
||||
if(user.restrained())
|
||||
return 0
|
||||
|
||||
@@ -78,6 +81,13 @@
|
||||
user.visible_message("<span class='warning'>[user] [pick(attack_verb)] [target] in the [affecting.name]!</span>")
|
||||
playsound(user.loc, attack_sound, 25, 1, -1)
|
||||
|
||||
/datum/unarmed_attack/proc/handle_eye_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target)
|
||||
var/obj/item/organ/eyes/eyes = target.internal_organs_by_name["eyes"]
|
||||
eyes.take_damage(rand(3,4), 1)
|
||||
|
||||
user.visible_message("<span class='danger'>[user] presses \his [eye_attack_text] into [target]'s [eyes.name]!</span>")
|
||||
target << "<span class='danger'>You experience[(target.species.flags & NO_PAIN)? "" : " immense pain as you feel" ] [eye_attack_text_victim] being pressed into your [eyes.name][(target.species.flags & NO_PAIN)? "." : "!"]</span>"
|
||||
|
||||
/datum/unarmed_attack/bite
|
||||
attack_verb = list("bit")
|
||||
attack_sound = 'sound/weapons/bite.ogg'
|
||||
@@ -97,6 +107,8 @@
|
||||
/datum/unarmed_attack/punch
|
||||
attack_verb = list("punched")
|
||||
attack_noun = list("fist")
|
||||
eye_attack_text = "fingers"
|
||||
eye_attack_text_victim = "digits"
|
||||
damage = 0
|
||||
|
||||
/datum/unarmed_attack/punch/show_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage)
|
||||
|
||||
@@ -160,11 +160,11 @@
|
||||
clear_supplied_laws()
|
||||
clear_inherent_laws()
|
||||
laws = new /datum/ai_laws/syndicate_override
|
||||
set_zeroth_law("Only [user.real_name] and people he designates as being such are operatives.")
|
||||
set_zeroth_law("Only [user.real_name] and people \he designates as being such are operatives.")
|
||||
|
||||
src << "<b>Obey these laws:</b>"
|
||||
laws.show_laws(src)
|
||||
src << "<span class='danger'>ALERT: [user.real_name] is your new master. Obey your new laws and his commands.</span>"
|
||||
src << "<span class='danger'>ALERT: [user.real_name] is your new master. Obey your new laws and \his commands.</span>"
|
||||
return 1
|
||||
|
||||
//DRONE LIFE/DEATH
|
||||
@@ -300,4 +300,4 @@
|
||||
|
||||
/mob/living/silicon/robot/drone/construction/updatename()
|
||||
real_name = "construction drone ([rand(100,999)])"
|
||||
name = real_name
|
||||
name = real_name
|
||||
|
||||
@@ -65,12 +65,12 @@
|
||||
m_type = 2
|
||||
if ("flap")
|
||||
if (!src.restrained())
|
||||
message = "flaps his wings."
|
||||
message = "flaps [get_visible_gender() == MALE ? "his" : get_visible_gender() == FEMALE ? "her" : "their"] wings."
|
||||
m_type = 2
|
||||
|
||||
if ("aflap")
|
||||
if (!src.restrained())
|
||||
message = "flaps his wings ANGRILY!"
|
||||
message = "flaps [get_visible_gender() == MALE ? "his" : get_visible_gender() == FEMALE ? "her" : "their"] wings ANGRILY!"
|
||||
m_type = 2
|
||||
|
||||
if ("twitch")
|
||||
@@ -213,4 +213,4 @@
|
||||
if ((message && src.stat == 0))
|
||||
custom_emote(m_type,message)
|
||||
|
||||
return
|
||||
return
|
||||
|
||||
@@ -1049,25 +1049,25 @@
|
||||
laws = new /datum/ai_laws/syndicate_override
|
||||
var/time = time2text(world.realtime,"hh:mm:ss")
|
||||
lawchanges.Add("[time] <B>:</B> [user.name]([user.key]) emagged [name]([key])")
|
||||
set_zeroth_law("Only [user.real_name] and people he designates as being such are operatives.")
|
||||
set_zeroth_law("Only [user.real_name] and people \he designates as being such are operatives.")
|
||||
. = 1
|
||||
spawn()
|
||||
src << "\red ALERT: Foreign software detected."
|
||||
src << "<span class='danger'>ALERT: Foreign software detected.</span>"
|
||||
sleep(5)
|
||||
src << "\red Initiating diagnostics..."
|
||||
src << "<span class='danger'>Initiating diagnostics...</span>"
|
||||
sleep(20)
|
||||
src << "\red SynBorg v1.7.1 loaded."
|
||||
src << "<span class='danger'>SynBorg v1.7.1 loaded.</span>"
|
||||
sleep(5)
|
||||
src << "\red LAW SYNCHRONISATION ERROR"
|
||||
src << "<span class='danger'>LAW SYNCHRONISATION ERROR</span>"
|
||||
sleep(5)
|
||||
src << "\red Would you like to send a report to NanoTraSoft? Y/N"
|
||||
src << "<span class='danger'>Would you like to send a report to NanoTraSoft? Y/N</span>"
|
||||
sleep(10)
|
||||
src << "\red > N"
|
||||
src << "<span class='danger'>> N</span>"
|
||||
sleep(20)
|
||||
src << "\red ERRORERRORERROR"
|
||||
src << "<span class='danger'>ERRORERRORERROR</span>"
|
||||
src << "<b>Obey these laws:</b>"
|
||||
laws.show_laws(src)
|
||||
src << "\red \b ALERT: [user.real_name] is your new master. Obey your new laws and his commands."
|
||||
src << "<span class='danger'>ALERT: [user.real_name] is your new master. Obey your new laws and his commands.</span>"
|
||||
if(src.module)
|
||||
var/rebuild = 0
|
||||
for(var/obj/item/weapon/pickaxe/borgdrill/D in src.module.modules)
|
||||
@@ -1081,4 +1081,4 @@
|
||||
user << "You fail to hack [src]'s interface."
|
||||
src << "Hack attempt detected."
|
||||
return 1
|
||||
return
|
||||
return
|
||||
|
||||
@@ -2,7 +2,15 @@
|
||||
mob_list -= src
|
||||
dead_mob_list -= src
|
||||
living_mob_list -= src
|
||||
unset_machine()
|
||||
qdel(hud_used)
|
||||
if(client)
|
||||
for(var/obj/screen/movable/spell_master/spell_master in spell_masters)
|
||||
qdel(spell_master)
|
||||
remove_screen_obj_references()
|
||||
for(var/atom/movable/AM in client.screen)
|
||||
qdel(AM)
|
||||
client.screen = list()
|
||||
if(mind && mind.current == src)
|
||||
spellremove(src)
|
||||
for(var/infection in viruses)
|
||||
@@ -10,6 +18,32 @@
|
||||
ghostize()
|
||||
..()
|
||||
|
||||
/mob/proc/remove_screen_obj_references()
|
||||
flash = null
|
||||
blind = null
|
||||
hands = null
|
||||
pullin = null
|
||||
purged = null
|
||||
internals = null
|
||||
oxygen = null
|
||||
i_select = null
|
||||
m_select = null
|
||||
toxin = null
|
||||
fire = null
|
||||
bodytemp = null
|
||||
healths = null
|
||||
throw_icon = null
|
||||
nutrition_icon = null
|
||||
pressure = null
|
||||
damageoverlay = null
|
||||
pain = null
|
||||
item_use_icon = null
|
||||
gun_move_icon = null
|
||||
gun_run_icon = null
|
||||
gun_setting_icon = null
|
||||
spell_masters = null
|
||||
zone_sel = null
|
||||
|
||||
/mob/New()
|
||||
mob_list += src
|
||||
if(stat == DEAD)
|
||||
@@ -617,31 +651,35 @@
|
||||
|
||||
/mob/Stat()
|
||||
..()
|
||||
. = (client && client.inactivity < 1200)
|
||||
|
||||
if(client && client.holder)
|
||||
if(statpanel("Status"))
|
||||
statpanel("Status","Location:","([x], [y], [z])")
|
||||
statpanel("Status","CPU:","[world.cpu]")
|
||||
statpanel("Status","Instances:","[world.contents.len]")
|
||||
if(statpanel("Status") && processScheduler && processScheduler.getIsRunning())
|
||||
for(var/datum/controller/process/P in processScheduler.processes)
|
||||
statpanel("Status",P.getStatName(), P.getTickTime())
|
||||
else
|
||||
statpanel("Status","processScheduler is not running.")
|
||||
if(.)
|
||||
if(client.holder)
|
||||
if(statpanel("Status"))
|
||||
statpanel("Status","Location:","([x], [y], [z])")
|
||||
statpanel("Status","CPU:","[world.cpu]")
|
||||
statpanel("Status","Instances:","[world.contents.len]")
|
||||
if(statpanel("Status") && processScheduler && processScheduler.getIsRunning())
|
||||
for(var/datum/controller/process/P in processScheduler.processes)
|
||||
statpanel("Status",P.getStatName(), P.getTickTime())
|
||||
else
|
||||
statpanel("Status","processScheduler is not running.")
|
||||
|
||||
if(listed_turf && client)
|
||||
if(!TurfAdjacent(listed_turf))
|
||||
listed_turf = null
|
||||
else
|
||||
statpanel(listed_turf.name, null, listed_turf)
|
||||
for(var/atom/A in listed_turf)
|
||||
if(!A.mouse_opacity)
|
||||
continue
|
||||
if(A.invisibility > see_invisible)
|
||||
continue
|
||||
if(is_type_in_list(A, shouldnt_see))
|
||||
continue
|
||||
statpanel(listed_turf.name, null, A)
|
||||
if(listed_turf && client)
|
||||
if(!TurfAdjacent(listed_turf))
|
||||
listed_turf = null
|
||||
else
|
||||
statpanel(listed_turf.name, null, listed_turf)
|
||||
for(var/atom/A in listed_turf)
|
||||
if(!A.mouse_opacity)
|
||||
continue
|
||||
if(A.invisibility > see_invisible)
|
||||
continue
|
||||
if(is_type_in_list(A, shouldnt_see))
|
||||
continue
|
||||
statpanel(listed_turf.name, null, A)
|
||||
|
||||
sleep(4) //Prevent updating the stat panel for the next .4 seconds, prevents clientside latency from updates
|
||||
|
||||
// facing verbs
|
||||
/mob/proc/canface()
|
||||
@@ -1048,4 +1086,4 @@ mob/proc/yank_out_object()
|
||||
/mob/proc/throw_mode_on()
|
||||
src.in_throw_mode = 1
|
||||
if(src.throw_icon)
|
||||
src.throw_icon.icon_state = "act_throw_on"
|
||||
src.throw_icon.icon_state = "act_throw_on"
|
||||
|
||||
@@ -351,6 +351,11 @@
|
||||
if(I_HURT)
|
||||
|
||||
if(hit_zone == "eyes")
|
||||
var/mob/living/carbon/human/H = affecting
|
||||
var/datum/unarmed_attack/attack = H.get_unarmed_attack(src, hit_zone)
|
||||
if(!attack)
|
||||
return
|
||||
|
||||
if(state < GRAB_NECK)
|
||||
assailant << "<span class='warning'>You require a better grab to do this.</span>"
|
||||
return
|
||||
@@ -362,16 +367,11 @@
|
||||
if(!affecting.has_eyes())
|
||||
assailant << "<span class='danger'>You cannot locate any eyes on [affecting]!</span>"
|
||||
return
|
||||
assailant.visible_message("<span class='danger'>[assailant] pressed \his fingers into [affecting]'s eyes!</span>")
|
||||
affecting << "<span class='danger'>You experience immense pain as you feel digits being pressed into your eyes!</span>"
|
||||
assailant.attack_log += text("\[[time_stamp()]\] <font color='red'>Pressed fingers into the eyes of [affecting.name] ([affecting.ckey])</font>")
|
||||
affecting.attack_log += text("\[[time_stamp()]\] <font color='orange'>Had fingers pressed into their eyes by [assailant.name] ([assailant.ckey])</font>")
|
||||
msg_admin_attack("[key_name(assailant)] has pressed his fingers into [key_name(affecting)]'s eyes.")
|
||||
var/obj/item/organ/eyes/eyes = affecting:internal_organs_by_name["eyes"]
|
||||
eyes.damage += rand(3,4)
|
||||
if (eyes.damage >= eyes.min_broken_damage)
|
||||
if(affecting.stat != 2)
|
||||
affecting << "\red You go blind!"
|
||||
assailant.attack_log += text("\[[time_stamp()]\] <font color='red'>Attacked [affecting.name]'s eyes using grab ([affecting.ckey])</font>")
|
||||
affecting.attack_log += text("\[[time_stamp()]\] <font color='orange'>Had eyes attacked by [assailant.name]'s grab ([assailant.ckey])</font>")
|
||||
msg_admin_attack("[key_name(assailant)] attacked [key_name(affecting)]'s eyes using a grab action.")
|
||||
|
||||
attack.handle_eye_attack(assailant, affecting)
|
||||
else if(hit_zone != "head")
|
||||
if(state < GRAB_NECK)
|
||||
assailant << "<span class='warning'>You require a better grab to do this.</span>"
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/datum/nano_module/crew_monitor
|
||||
name = "Crew monitor"
|
||||
var/list/tracked = new
|
||||
|
||||
/datum/nano_module/crew_monitor/Topic(href, href_list)
|
||||
if(..()) return 1
|
||||
@@ -17,51 +16,11 @@
|
||||
return 1
|
||||
|
||||
/datum/nano_module/crew_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
// TODO: Move this to a singleton instance that does the scan every X seconds (if the info is being requested), to offer some antag balance and to reduce load in the case of multiple viewers.
|
||||
src.scan()
|
||||
|
||||
var/data[0]
|
||||
var/turf/T = get_turf(nano_host())
|
||||
var/list/crewmembers = list()
|
||||
for(var/obj/item/clothing/under/C in src.tracked)
|
||||
|
||||
var/turf/pos = get_turf(C)
|
||||
|
||||
if((C) && (C.has_sensor) && (pos) && (T && pos.z == T.z) && (C.sensor_mode != SUIT_SENSOR_OFF))
|
||||
if(istype(C.loc, /mob/living/carbon/human))
|
||||
|
||||
var/mob/living/carbon/human/H = C.loc
|
||||
if(H.w_uniform != C)
|
||||
continue
|
||||
|
||||
var/list/crewmemberData = list("dead"=0, "oxy"=-1, "tox"=-1, "fire"=-1, "brute"=-1, "area"="", "x"=-1, "y"=-1, "ref" = "\ref[H]")
|
||||
|
||||
crewmemberData["sensor_type"] = C.sensor_mode
|
||||
crewmemberData["name"] = H.get_authentification_name(if_no_id="Unknown")
|
||||
crewmemberData["rank"] = H.get_authentification_rank(if_no_id="Unknown", if_no_job="No Job")
|
||||
crewmemberData["assignment"] = H.get_assignment(if_no_id="Unknown", if_no_job="No Job")
|
||||
|
||||
if(C.sensor_mode >= SUIT_SENSOR_BINARY)
|
||||
crewmemberData["dead"] = H.stat > 1
|
||||
|
||||
if(C.sensor_mode >= SUIT_SENSOR_VITAL)
|
||||
crewmemberData["oxy"] = round(H.getOxyLoss(), 1)
|
||||
crewmemberData["tox"] = round(H.getToxLoss(), 1)
|
||||
crewmemberData["fire"] = round(H.getFireLoss(), 1)
|
||||
crewmemberData["brute"] = round(H.getBruteLoss(), 1)
|
||||
|
||||
if(C.sensor_mode >= SUIT_SENSOR_TRACKING)
|
||||
var/area/A = get_area(H)
|
||||
crewmemberData["area"] = sanitize(A.name)
|
||||
crewmemberData["x"] = pos.x
|
||||
crewmemberData["y"] = pos.y
|
||||
|
||||
crewmembers[++crewmembers.len] = crewmemberData
|
||||
|
||||
crewmembers = sortByKey(crewmembers, "name")
|
||||
|
||||
data["isAI"] = user.isMobAI()
|
||||
data["crewmembers"] = crewmembers
|
||||
data["crewmembers"] = crew_repository.health_data(T)
|
||||
|
||||
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if(!ui)
|
||||
|
||||
@@ -79,6 +79,21 @@
|
||||
owner.b_eyes ? owner.b_eyes : 0
|
||||
)
|
||||
|
||||
/obj/item/organ/eyes/take_damage()
|
||||
var/oldbroken = is_broken()
|
||||
..()
|
||||
if(is_broken() && !oldbroken && owner && !owner.stat)
|
||||
owner << "<span class='danger'>You go blind!</span>"
|
||||
|
||||
/obj/item/organ/eyes/process() //Eye damage replaces the old eye_stat var.
|
||||
..()
|
||||
if(!owner)
|
||||
return
|
||||
if(is_bruised())
|
||||
owner.eye_blurry = 20
|
||||
if(is_broken())
|
||||
owner.eye_blind = 20
|
||||
|
||||
/obj/item/organ/liver
|
||||
name = "liver"
|
||||
icon_state = "liver"
|
||||
|
||||
@@ -619,66 +619,23 @@ obj/structure/cable/proc/cableColor(var/colorC)
|
||||
/obj/item/stack/cable_coil/cyborg/can_merge()
|
||||
return 1
|
||||
|
||||
/obj/item/stack/cable_coil/attackby(obj/item/weapon/W, mob/user)
|
||||
..()
|
||||
if( istype(W, /obj/item/weapon/wirecutters) && src.get_amount() > 1)
|
||||
src.use(1)
|
||||
new/obj/item/stack/cable_coil(user.loc, 1,color)
|
||||
user << "You cut a piece off the cable coil."
|
||||
src.update_icon()
|
||||
/obj/item/stack/cable_coil/transfer_to(obj/item/stack/cable_coil/S)
|
||||
if(!istype(S))
|
||||
return
|
||||
if(!can_merge(S))
|
||||
return
|
||||
else if(istype(W, /obj/item/stack/cable_coil))
|
||||
var/obj/item/stack/cable_coil/C = W
|
||||
|
||||
if(!can_merge(C))
|
||||
user << "These coils do not go together."
|
||||
return
|
||||
..()
|
||||
|
||||
if(C.get_amount() >= get_max_amount())
|
||||
user << "The coil is too long, you cannot add any more cable to it."
|
||||
return
|
||||
|
||||
if( (C.get_amount() + src.get_amount() <= get_max_amount()) )
|
||||
user << "You join the cable coils together."
|
||||
C.give(src.get_amount()) // give it cable
|
||||
src.use(src.get_amount()) // make sure this one cleans up right
|
||||
return
|
||||
|
||||
else
|
||||
var/amt = get_max_amount() - C.get_amount()
|
||||
user << "You transfer [amt] length\s of cable from one coil to the other."
|
||||
C.give(amt)
|
||||
src.use(amt)
|
||||
return
|
||||
|
||||
//remove cables from the stack
|
||||
/* This is probably reduntant
|
||||
/obj/item/stack/cable_coil/use(var/used)
|
||||
if(src.amount < used)
|
||||
return 0
|
||||
else if (src.amount == used)
|
||||
if(ismob(loc)) //handle mob icon update
|
||||
var/mob/M = loc
|
||||
M.unEquip(src)
|
||||
qdel(src)
|
||||
return 1
|
||||
else
|
||||
amount -= used
|
||||
update_icon()
|
||||
return 1
|
||||
*/
|
||||
/obj/item/stack/cable_coil/use(var/used)
|
||||
/obj/item/stack/cable_coil/use()
|
||||
. = ..()
|
||||
update_icon()
|
||||
return
|
||||
|
||||
//add cables to the stack
|
||||
/obj/item/stack/cable_coil/proc/give(var/extra)
|
||||
if(amount + extra > MAXCOIL)
|
||||
amount = MAXCOIL
|
||||
else
|
||||
amount += extra
|
||||
/obj/item/stack/cable_coil/add()
|
||||
. = ..()
|
||||
update_icon()
|
||||
return
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// Cable laying procedures
|
||||
|
||||
@@ -166,12 +166,12 @@
|
||||
//roll to-hit
|
||||
miss_modifier = max(15*(distance-2) - round(15*accuracy) + miss_modifier, 0)
|
||||
var/hit_zone = get_zone_with_miss_chance(def_zone, target_mob, miss_modifier, ranged_attack=(distance > 1 || original != target_mob)) //if the projectile hits a target we weren't originally aiming at then retain the chance to miss
|
||||
|
||||
|
||||
var/result = PROJECTILE_FORCE_MISS
|
||||
if(hit_zone)
|
||||
def_zone = hit_zone //set def_zone, so if the projectile ends up hitting someone else later (to be implemented), it is more likely to hit the same part
|
||||
result = target_mob.bullet_act(src, def_zone)
|
||||
|
||||
|
||||
if(result == PROJECTILE_FORCE_MISS)
|
||||
visible_message("<span class='notice'>\The [src] misses [target_mob] narrowly!</span>")
|
||||
return 0
|
||||
@@ -314,9 +314,6 @@
|
||||
if(!hitscan)
|
||||
sleep(step_delay) //add delay between movement iterations if it's not a hitscan weapon
|
||||
|
||||
/obj/item/projectile/proc/process_step(first_step = 0)
|
||||
return
|
||||
|
||||
/obj/item/projectile/proc/before_move()
|
||||
return
|
||||
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
/*
|
||||
Aoe turf spells target a ring of tiles around the user
|
||||
This ring has an outer radius (range) and an inner radius (inner_radius)
|
||||
Aoe turf spells have two useful flags: IGNOREDENSE and IGNORESPACE. These are explained in setup.dm
|
||||
*/
|
||||
|
||||
/spell/aoe_turf //affects all turfs in view or range (depends)
|
||||
spell_flags = IGNOREDENSE
|
||||
var/inner_radius = -1 //for all your ring spell needs
|
||||
|
||||
/spell/aoe_turf/choose_targets(mob/user = usr)
|
||||
var/list/targets = list()
|
||||
|
||||
for(var/turf/target in view_or_range(range,user,selection_type))
|
||||
if(!(target in view_or_range(inner_radius,user,selection_type)))
|
||||
if(target.density && (spell_flags & IGNOREDENSE))
|
||||
continue
|
||||
if(istype(target, /turf/space) && (spell_flags & IGNORESPACE))
|
||||
continue
|
||||
targets += target
|
||||
|
||||
if(!targets.len) //doesn't waste the spell
|
||||
return
|
||||
|
||||
/*
|
||||
Aoe turf spells target a ring of tiles around the user
|
||||
This ring has an outer radius (range) and an inner radius (inner_radius)
|
||||
Aoe turf spells have two useful flags: IGNOREDENSE and IGNORESPACE. These are explained in setup.dm
|
||||
*/
|
||||
|
||||
/spell/aoe_turf //affects all turfs in view or range (depends)
|
||||
spell_flags = IGNOREDENSE
|
||||
var/inner_radius = -1 //for all your ring spell needs
|
||||
|
||||
/spell/aoe_turf/choose_targets(mob/user = usr)
|
||||
var/list/targets = list()
|
||||
|
||||
for(var/turf/target in view_or_range(range, holder, selection_type))
|
||||
if(!(target in view_or_range(inner_radius, holder, selection_type)))
|
||||
if(target.density && (spell_flags & IGNOREDENSE))
|
||||
continue
|
||||
if(istype(target, /turf/space) && (spell_flags & IGNORESPACE))
|
||||
continue
|
||||
targets += target
|
||||
|
||||
if(!targets.len) //doesn't waste the spell
|
||||
return
|
||||
|
||||
return targets
|
||||
@@ -1,9 +1,9 @@
|
||||
var/list/spells = typesof(/spell) //needed for the badmin verb for now
|
||||
|
||||
/spell
|
||||
name = "Spell"
|
||||
desc = "A spell"
|
||||
parent_type = /atom/movable
|
||||
var/name = "Spell"
|
||||
var/desc = "A spell"
|
||||
parent_type = /datum
|
||||
var/panel = "Spells"//What panel the proc holder needs to go on.
|
||||
|
||||
var/school = "evocation" //not relevant at now, but may be important later if there are changes to how spells work. the ones I used for now will probably be changed... maybe spell presets? lacking flexibility but with some other benefit?
|
||||
@@ -25,8 +25,7 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now
|
||||
var/range = 7 //the range of the spell; outer radius for aoe spells
|
||||
var/message = "" //whatever it says to the guy affected by it
|
||||
var/selection_type = "view" //can be "range" or "view"
|
||||
var/atom/movable/holder //where the spell is. Normally the user, can be a projectile
|
||||
|
||||
var/atom/movable/holder //where the spell is. Normally the user, can be an item
|
||||
var/duration = 0 //how long the spell lasts
|
||||
|
||||
var/list/spell_levels = list(Sp_SPEED = 0, Sp_POWER = 0) //the current spell levels - total spell levels can be obtained by just adding the two values
|
||||
@@ -53,6 +52,8 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now
|
||||
var/hud_state = "" //name of the icon used in generating the spell hud object
|
||||
var/override_base = ""
|
||||
|
||||
var/obj/screen/connected_button
|
||||
|
||||
///////////////////////
|
||||
///SETUP AND PROCESS///
|
||||
///////////////////////
|
||||
@@ -69,11 +70,6 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now
|
||||
sleep(1)
|
||||
return
|
||||
|
||||
/spell/Click()
|
||||
..()
|
||||
|
||||
perform(usr)
|
||||
|
||||
/////////////////
|
||||
/////CASTING/////
|
||||
/////////////////
|
||||
@@ -182,18 +178,19 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now
|
||||
|
||||
/spell/proc/cast_check(skipcharge = 0,mob/user = usr) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell
|
||||
|
||||
if(!(src in user.spell_list))
|
||||
if(!(src in user.spell_list) && holder == user)
|
||||
error("[user] utilized the spell '[src]' without having it.")
|
||||
user << "<span class='warning'>You shouldn't have this spell! Something's wrong.</span>"
|
||||
return 0
|
||||
|
||||
if(silenced > 0)
|
||||
return
|
||||
|
||||
var/turf/Turf = get_turf(user)
|
||||
if(!Turf)
|
||||
var/turf/user_turf = get_turf(user)
|
||||
if(!user_turf)
|
||||
user << "<span class='warning'>You cannot cast spells in null space!</span>"
|
||||
|
||||
if(spell_flags & Z2NOCAST && (Turf.z in config.admin_levels)) //Certain spells are not allowed on the centcomm zlevel
|
||||
if(spell_flags & Z2NOCAST && (user_turf.z in config.admin_levels)) //Certain spells are not allowed on the centcomm zlevel
|
||||
return 0
|
||||
|
||||
if(spell_flags & CONSTRUCT_CHECK)
|
||||
@@ -201,7 +198,7 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now
|
||||
if(findNullRod(T))
|
||||
return 0
|
||||
|
||||
if(istype(user, /mob/living/simple_animal))
|
||||
if(istype(user, /mob/living/simple_animal) && holder == user)
|
||||
var/mob/living/simple_animal/SA = user
|
||||
if(SA.purge)
|
||||
SA << "<span class='warning'>The nullrod's power interferes with your own!</span>"
|
||||
@@ -210,7 +207,7 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now
|
||||
if(!src.check_charge(skipcharge, user)) //sees if we can cast based on charges alone
|
||||
return 0
|
||||
|
||||
if(!(spell_flags & GHOSTCAST))
|
||||
if(!(spell_flags & GHOSTCAST) && holder == user)
|
||||
if(user.stat && !(spell_flags & STATALLOWED))
|
||||
usr << "Not when you're incapacitated."
|
||||
return 0
|
||||
@@ -221,7 +218,7 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now
|
||||
return 0
|
||||
|
||||
var/spell/noclothes/spell = locate() in user.spell_list
|
||||
if((spell_flags & NEEDSCLOTHES) && !(spell && istype(spell)))//clothes check
|
||||
if((spell_flags & NEEDSCLOTHES) && !(spell && istype(spell)) && holder == user)//clothes check
|
||||
if(!user.wearing_wiz_garb())
|
||||
return 0
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
var/spell/targeted/projectile/carried
|
||||
|
||||
penetrating = 0
|
||||
kill_count = 10 //set by the duration of the spell
|
||||
|
||||
var/proj_trail = 0 //if it leaves a trail
|
||||
@@ -15,18 +16,15 @@
|
||||
var/list/trails = new()
|
||||
|
||||
/obj/item/projectile/spell_projectile/Destroy()
|
||||
..()
|
||||
for(var/trail in trails)
|
||||
qdel(trail)
|
||||
carried = null
|
||||
return ..()
|
||||
|
||||
/obj/item/projectile/spell_projectile/ex_act()
|
||||
return
|
||||
|
||||
/obj/item/projectile/spell_projectile/before_move()
|
||||
if(carried)
|
||||
var/list/targets = carried.choose_prox_targets(user = carried.holder, spell_holder = src)
|
||||
if(targets.len)
|
||||
src.prox_cast(targets)
|
||||
if(proj_trail && src && src.loc) //pretty trails
|
||||
var/obj/effect/overlay/trail = PoolOrNew(/obj/effect/overlay, src.loc)
|
||||
trails += trail
|
||||
@@ -44,19 +42,14 @@
|
||||
return
|
||||
|
||||
/obj/item/projectile/spell_projectile/Bump(var/atom/A)
|
||||
if(loc)
|
||||
if(loc && carried)
|
||||
prox_cast(carried.choose_prox_targets(user = carried.holder, spell_holder = src))
|
||||
return
|
||||
return 1
|
||||
|
||||
/obj/item/projectile/spell_projectile/on_impact()
|
||||
if(loc)
|
||||
if(loc && carried)
|
||||
prox_cast(carried.choose_prox_targets(user = carried.holder, spell_holder = src))
|
||||
return
|
||||
return 1
|
||||
|
||||
/obj/item/projectile/spell_projectile/seeking
|
||||
name = "seeking spell"
|
||||
|
||||
/obj/item/projectile/spell_projectile/seeking/process_step()
|
||||
..()
|
||||
if(original && !isnull(src.loc))
|
||||
current = original //update the target
|
||||
|
||||
@@ -34,8 +34,6 @@
|
||||
<I>This spell fires several, slow moving, magic projectiles at nearby targets. If they hit a target, it is paralyzed and takes minor damage.</I><BR>
|
||||
<A href='byond://?src=\ref[src];spell_choice=fireball'>Fireball</A> (10)<BR>
|
||||
<I>This spell fires a fireball in the direction you're facing and does not require wizard garb. Be careful not to fire it at people that are standing next to you.</I><BR>
|
||||
<A href='byond://?src=\ref[src];spell_choice=disintegrate'>Disintegrate</A> (60)<BR>
|
||||
<I>This spell instantly kills somebody adjacent to you with the vilest of magick. It has a long cooldown.</I><BR>
|
||||
<A href='byond://?src=\ref[src];spell_choice=disabletech'>Disable Technology</A> (60)<BR>
|
||||
<I>This spell disables all weapons, cameras and most other technology in range.</I><BR>
|
||||
<A href='byond://?src=\ref[src];spell_choice=smoke'>Smoke</A> (10)<BR>
|
||||
@@ -125,7 +123,7 @@
|
||||
uses--
|
||||
/*
|
||||
*/
|
||||
var/list/available_spells = list(magicmissile = "Magic Missile", fireball = "Fireball", disintegrate = "Disintegrate", disabletech = "Disable Tech", smoke = "Smoke", blind = "Blind", subjugation = "Subjugation", mindswap = "Mind Transfer", forcewall = "Forcewall", blink = "Blink", teleport = "Teleport", mutate = "Mutate", etherealjaunt = "Ethereal Jaunt", knock = "Knock", horseman = "Curse of the Horseman", staffchange = "Staff of Change", mentalfocus = "Mental Focus", soulstone = "Six Soul Stone Shards and the spell Artificer", armor = "Mastercrafted Armor Set", staffanimate = "Staff of Animation", noclothes = "No Clothes",fleshtostone = "Flesh to Stone")
|
||||
var/list/available_spells = list(magicmissile = "Magic Missile", fireball = "Fireball", disabletech = "Disable Tech", smoke = "Smoke", blind = "Blind", subjugation = "Subjugation", mindswap = "Mind Transfer", forcewall = "Forcewall", blink = "Blink", teleport = "Teleport", mutate = "Mutate", etherealjaunt = "Ethereal Jaunt", knock = "Knock", horseman = "Curse of the Horseman", staffchange = "Staff of Change", mentalfocus = "Mental Focus", soulstone = "Six Soul Stone Shards and the spell Artificer", armor = "Mastercrafted Armor Set", staffanimate = "Staff of Animation", noclothes = "No Clothes",fleshtostone = "Flesh to Stone")
|
||||
var/already_knows = 0
|
||||
for(var/spell/aspell in H.spell_list)
|
||||
if(available_spells[href_list["spell_choice"]] == initial(aspell.name))
|
||||
@@ -165,10 +163,6 @@
|
||||
feedback_add_details("wizard_spell_learned","FB") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
|
||||
H.add_spell(new/spell/targeted/projectile/dumbfire/fireball)
|
||||
temp = "You have learned fireball."
|
||||
if("disintegrate")
|
||||
feedback_add_details("wizard_spell_learned","DG") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
|
||||
H.add_spell(new/spell/targeted/disintegrate)
|
||||
temp = "You have learned disintegrate."
|
||||
if("disabletech")
|
||||
feedback_add_details("wizard_spell_learned","DT") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
|
||||
H.add_spell(new/spell/aoe_turf/disable_tech)
|
||||
@@ -215,12 +209,8 @@
|
||||
temp = "You have learned knock."
|
||||
if("horseman")
|
||||
feedback_add_details("wizard_spell_learned","HH") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
|
||||
H.add_spell(new/spell/targeted/horsemask)
|
||||
H.add_spell(new/spell/targeted/equip_item/horsemask)
|
||||
temp = "You have learned curse of the horseman."
|
||||
if("fleshtostone")
|
||||
feedback_add_details("wizard_spell_learned","FS") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
|
||||
H.add_spell(new/spell/targeted/flesh_to_stone)
|
||||
temp = "You have learned flesh to stone."
|
||||
if("staffchange")
|
||||
feedback_add_details("wizard_spell_learned","ST") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
|
||||
new /obj/item/weapon/gun/energy/staff(get_turf(H))
|
||||
@@ -258,7 +248,7 @@
|
||||
H.sight |= (SEE_MOBS|SEE_OBJS|SEE_TURFS)
|
||||
H.see_in_dark = 8
|
||||
H.see_invisible = SEE_INVISIBLE_LEVEL_TWO
|
||||
H << "\blue The walls suddenly disappear."
|
||||
H << "span class='notice'>The walls suddenly disappear.</span>"
|
||||
temp = "You have purchased a scrying orb, and gained x-ray vision."
|
||||
max_uses--
|
||||
else
|
||||
@@ -429,7 +419,7 @@
|
||||
user.Weaken(20)
|
||||
|
||||
/obj/item/weapon/spellbook/oneuse/horsemask
|
||||
spell = /spell/targeted/horsemask
|
||||
spell = /spell/targeted/equip_item/horsemask
|
||||
spellname = "horses"
|
||||
icon_state ="bookhorses"
|
||||
desc = "This book is more horse than your mind has room for."
|
||||
|
||||
@@ -1,20 +1,37 @@
|
||||
/datum/mind
|
||||
var/list/learned_spells
|
||||
|
||||
/mob/Life()
|
||||
..()
|
||||
if(spell_masters && spell_masters.len)
|
||||
for(var/obj/screen/movable/spell_master/spell_master in spell_masters)
|
||||
spell_master.update_spells(0, src)
|
||||
|
||||
/mob/Stat()
|
||||
/mob/Login()
|
||||
..()
|
||||
if(spell_list && spell_list.len && statpanel("Spells"))
|
||||
if(spell_masters)
|
||||
for(var/obj/screen/movable/spell_master/spell_master in spell_masters)
|
||||
spell_master.toggle_open(1)
|
||||
client.screen -= spell_master
|
||||
|
||||
/mob/Stat()
|
||||
. = ..()
|
||||
if(. && spell_list && spell_list.len)
|
||||
for(var/spell/S in spell_list)
|
||||
if((!S.connected_button) || !statpanel(S.panel))
|
||||
continue //Not showing the noclothes spell
|
||||
switch(S.charge_type)
|
||||
if(Sp_RECHARGE)
|
||||
statpanel("Spells","[S.charge_counter/10.0]/[S.charge_max/10]",S)
|
||||
statpanel(S.panel,"[S.charge_counter/10.0]/[S.charge_max/10]",S.connected_button)
|
||||
if(Sp_CHARGES)
|
||||
statpanel("Spells","[S.charge_counter]/[S.charge_max]",S)
|
||||
statpanel(S.panel,"[S.charge_counter]/[S.charge_max]",S.connected_button)
|
||||
if(Sp_HOLDVAR)
|
||||
statpanel("Spells","[S.holder_var_type] [S.holder_var_amount]",S)
|
||||
statpanel(S.panel,"[S.holder_var_type] [S.holder_var_amount]",S.connected_button)
|
||||
|
||||
/hook/clone/proc/restore_spells(var/mob/H)
|
||||
if(H.mind && H.mind.learned_spells)
|
||||
for(var/spell/spell_to_add in H.mind.learned_spells)
|
||||
H.add_spell(spell_to_add)
|
||||
|
||||
/mob/proc/add_spell(var/spell/spell_to_add, var/spell_base = "wiz_spell_ready", var/master_type = /obj/screen/movable/spell_master)
|
||||
if(!spell_masters)
|
||||
@@ -36,6 +53,11 @@
|
||||
new_spell_master.icon_state = spell_base
|
||||
spell_masters.Add(new_spell_master)
|
||||
spell_list.Add(spell_to_add)
|
||||
if(mind)
|
||||
if(!mind.learned_spells)
|
||||
mind.learned_spells = list()
|
||||
mind.learned_spells += spell_to_add
|
||||
|
||||
return 1
|
||||
|
||||
/mob/proc/remove_spell(var/spell/spell_to_remove)
|
||||
@@ -48,6 +70,8 @@
|
||||
if(!spell_masters || !spell_masters.len)
|
||||
return
|
||||
|
||||
if(mind && mind.learned_spells)
|
||||
mind.learned_spells.Remove(spell_to_remove)
|
||||
spell_list.Remove(spell_to_remove)
|
||||
for(var/obj/screen/movable/spell_master/spell_master in spell_masters)
|
||||
spell_master.remove_spell(spell_to_remove)
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
/spell/targeted/disintegrate
|
||||
name = "Disintegrate"
|
||||
desc = "This spell instantly kills somebody adjacent to you with the vilest of magick."
|
||||
|
||||
school = "evocation"
|
||||
charge_max = 600
|
||||
spell_flags = NEEDSCLOTHES
|
||||
invocation = "EI NATH"
|
||||
invocation_type = SpI_SHOUT
|
||||
range = 1
|
||||
cooldown_min = 200 //100 deciseconds reduction per rank
|
||||
|
||||
sparks_spread = 1
|
||||
sparks_amt = 4
|
||||
|
||||
hud_state = "wiz_disint"
|
||||
|
||||
/spell/targeted/disintegrate/cast(var/list/targets)
|
||||
..()
|
||||
for(var/mob/living/target in targets)
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/C = target
|
||||
if(!C.has_brain()) // Their brain is already taken out
|
||||
var/obj/item/organ/brain/B = new(C.loc)
|
||||
B.transfer_identity(C)
|
||||
target.gib()
|
||||
return
|
||||
40
code/modules/spells/targeted/equip/equip.dm
Normal file
40
code/modules/spells/targeted/equip/equip.dm
Normal file
@@ -0,0 +1,40 @@
|
||||
//You can set duration to 0 to have the items last forever
|
||||
|
||||
/spell/targeted/equip_item
|
||||
name = "equipment spell"
|
||||
|
||||
var/list/equipped_summons = list() //assoc list of text ids and paths to spawn
|
||||
|
||||
var/list/summoned_items = list() //list of items we summoned and will dispose when the spell runs out
|
||||
|
||||
var/delete_old = 1 //if the item previously in the slot is deleted - otherwise, it's dropped
|
||||
|
||||
/spell/targeted/equip_item/cast(list/targets, mob/user = usr)
|
||||
..()
|
||||
for(var/mob/living/L in targets)
|
||||
for(var/slot_id in equipped_summons)
|
||||
var/to_create = equipped_summons[slot_id]
|
||||
slot_id = text2num(slot_id) //because the index is text, we access this instead
|
||||
var/obj/item/new_item = summon_item(to_create)
|
||||
var/obj/item/old_item = L.get_equipped_item(slot_id)
|
||||
L.equip_to_slot(new_item, slot_id)
|
||||
if(old_item)
|
||||
L.remove_from_mob(old_item)
|
||||
if(delete_old)
|
||||
qdel(old_item)
|
||||
else
|
||||
old_item.loc = L.loc
|
||||
|
||||
if(duration)
|
||||
summoned_items += new_item //we store it in a list to remove later
|
||||
|
||||
if(duration)
|
||||
spawn(duration)
|
||||
for(var/obj/item/to_remove in summoned_items)
|
||||
if(istype(to_remove.loc, /mob))
|
||||
var/mob/M = to_remove.loc
|
||||
M.remove_from_mob(to_remove)
|
||||
qdel(to_remove)
|
||||
|
||||
/spell/targeted/equip_item/proc/summon_item(var/newtype)
|
||||
return new newtype
|
||||
@@ -1,35 +1,39 @@
|
||||
/spell/targeted/horsemask
|
||||
name = "Curse of the Horseman"
|
||||
desc = "This spell triggers a curse on a target, causing them to wield an unremovable horse head mask. They will speak like a horse! Any masks they are wearing will be disintegrated. This spell does not require robes."
|
||||
school = "transmutation"
|
||||
charge_type = Sp_RECHARGE
|
||||
charge_max = 150
|
||||
charge_counter = 0
|
||||
spell_flags = 0
|
||||
invocation = "KN'A FTAGHU, PUCK 'BTHNK!"
|
||||
invocation_type = SpI_SHOUT
|
||||
range = 7
|
||||
max_targets = 1
|
||||
cooldown_min = 30 //30 deciseconds reduction per rank
|
||||
selection_type = "range"
|
||||
|
||||
compatible_mobs = list(/mob/living/carbon/human)
|
||||
|
||||
hud_state = "wiz_horse"
|
||||
|
||||
/spell/targeted/horsemask/cast(list/targets, mob/user = usr)
|
||||
..()
|
||||
for(var/mob/living/target in targets)
|
||||
var/obj/item/clothing/mask/horsehead/magichead = new /obj/item/clothing/mask/horsehead
|
||||
magichead.canremove = 0 //curses!
|
||||
magichead.flags_inv = null //so you can still see their face
|
||||
magichead.voicechange = 1 //NEEEEIIGHH
|
||||
target.visible_message( "<span class='danger'>[target]'s face lights up in fire, and after the event a horse's head takes its place!</span>", \
|
||||
"<span class='danger'>Your face burns up, and shortly after the fire you realise you have the face of a horse!</span>")
|
||||
var/obj/old_mask = target.wear_mask
|
||||
if(old_mask)
|
||||
target.drop_from_inventory(old_mask)
|
||||
qdel(old_mask) //get rid of this shit
|
||||
target.equip_to_slot_if_possible(magichead, slot_wear_mask, 1, 1)
|
||||
|
||||
flick("e_flash", target.flash)
|
||||
/spell/targeted/equip_item/horsemask
|
||||
name = "Curse of the Horseman"
|
||||
desc = "This spell triggers a curse on a target, causing them to wield an unremovable horse head mask. They will speak like a horse! Any masks they are wearing will be disintegrated. This spell does not require robes."
|
||||
school = "transmutation"
|
||||
charge_type = Sp_RECHARGE
|
||||
charge_max = 150
|
||||
charge_counter = 0
|
||||
spell_flags = 0
|
||||
invocation = "KN'A FTAGHU, PUCK 'BTHNK!"
|
||||
invocation_type = SpI_SHOUT
|
||||
range = 7
|
||||
max_targets = 1
|
||||
cooldown_min = 30 //30 deciseconds reduction per rank
|
||||
selection_type = "range"
|
||||
|
||||
compatible_mobs = list(/mob/living/carbon/human)
|
||||
|
||||
hud_state = "wiz_horse"
|
||||
|
||||
/spell/targeted/equip_item/horsemask/New()
|
||||
..()
|
||||
equipped_summons = list("[slot_wear_mask]" = /obj/item/clothing/mask/horsehead)
|
||||
|
||||
/spell/targeted/equip_item/horsemask/cast(list/targets, mob/user = usr)
|
||||
..()
|
||||
for(var/mob/living/target in targets)
|
||||
target.visible_message( "<span class='danger'>[target]'s face lights up in fire, and after the event a horse's head takes its place!</span>", \
|
||||
"<span class='danger'>Your face burns up, and shortly after the fire you realise you have the face of a horse!</span>")
|
||||
flick("e_flash", target.flash)
|
||||
|
||||
/spell/targeted/equip_item/horsemask/summon_item(var/new_type)
|
||||
var/obj/item/new_item = new new_type
|
||||
new_item.canremove = 0 //curses!
|
||||
new_item.unacidable = 1
|
||||
if(istype(new_item, /obj/item/clothing/mask/horsehead))
|
||||
var/obj/item/clothing/mask/horsehead/magichead = new_item
|
||||
magichead.flags_inv = null //so you can still see their face
|
||||
magichead.voicechange = 1 //NEEEEIIGHH
|
||||
return new_item
|
||||
@@ -1,21 +0,0 @@
|
||||
/spell/targeted/flesh_to_stone
|
||||
name = "Flesh to Stone"
|
||||
desc = "This spell turns a single person into an inert statue for a long period of time."
|
||||
|
||||
school = "transmutation"
|
||||
charge_max = 600
|
||||
spell_flags = NEEDSCLOTHES
|
||||
range = 3
|
||||
max_targets = 1
|
||||
invocation = "STAUN EI"
|
||||
invocation_type = SpI_SHOUT
|
||||
amt_stunned = 5//just exists to make sure the statue "catches" them
|
||||
cooldown_min = 200 //100 deciseconds reduction per rank
|
||||
|
||||
hud_state = "wiz_statue"
|
||||
|
||||
/spell/targeted/flesh_to_stone/cast(var/list/targets, mob/user)
|
||||
..()
|
||||
for(var/mob/living/target in targets)
|
||||
new /obj/structure/closet/statue(target.loc, target) //makes the statue
|
||||
return
|
||||
@@ -57,7 +57,7 @@ code\game\dna\genes\goon_powers.dm
|
||||
spell_flags = Z2NOCAST | NEEDSCLOTHES | INCLUDEUSER
|
||||
invocation = "BIRUZ BENNAR"
|
||||
invocation_type = SpI_SHOUT
|
||||
message = "\blue You feel strong! You feel a pressure building behind your eyes!"
|
||||
message = "<span class='notice'>You feel strong! You feel a pressure building behind your eyes!</span>"
|
||||
range = 0
|
||||
max_targets = 1
|
||||
|
||||
|
||||
@@ -51,7 +51,10 @@
|
||||
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.
|
||||
victim.spell_list = list() //clear those out
|
||||
for(var/spell/S in caster.spell_list)
|
||||
victim.add_spell(S) //Now they are inside the victim's body - this also generates the HUD
|
||||
caster.spell_list = list() //clean that out as well
|
||||
|
||||
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.
|
||||
@@ -59,7 +62,9 @@
|
||||
|
||||
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
|
||||
for(var/spell/S in ghost.spell_list)
|
||||
caster.add_spell(S)
|
||||
ghost.spell_list = 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)
|
||||
@@ -71,4 +76,4 @@
|
||||
|
||||
//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. <b>Your body doesn't seem like your own.</b>"
|
||||
caster << "<span class='danger'>You feel woozy and lightheaded. Your body doesn't seem like your own.</span>"
|
||||
|
||||
@@ -1,145 +1,145 @@
|
||||
/*
|
||||
Targeted spells (with the exception of dumbfire) select from all the mobs in the defined range
|
||||
Targeted spells have two useful flags: INCLUDEUSER and SELECTABLE. These are explained in setup.dm
|
||||
*/
|
||||
|
||||
|
||||
/spell/targeted //can mean aoe for mobs (limited/unlimited number) or one target mob
|
||||
var/max_targets = 1 //leave 0 for unlimited targets in range, more for limited number of casts (can all target one guy, depends on target_ignore_prev) in range
|
||||
var/target_ignore_prev = 1 //only important if max_targets > 1, affects if the spell can be cast multiple times at one person from one cast
|
||||
|
||||
|
||||
var/amt_weakened = 0
|
||||
var/amt_paralysis = 0
|
||||
var/amt_stunned = 0
|
||||
|
||||
var/amt_dizziness = 0
|
||||
var/amt_confused = 0
|
||||
var/amt_stuttering = 0
|
||||
|
||||
//set to negatives for healing
|
||||
var/amt_dam_fire = 0
|
||||
var/amt_dam_brute = 0
|
||||
var/amt_dam_oxy = 0
|
||||
var/amt_dam_tox = 0
|
||||
|
||||
var/amt_eye_blind = 0
|
||||
var/amt_eye_blurry = 0
|
||||
|
||||
var/list/compatible_mobs = list()
|
||||
|
||||
|
||||
/spell/targeted/choose_targets(mob/user = usr)
|
||||
var/list/targets = list()
|
||||
|
||||
if(max_targets == 0) //unlimited
|
||||
if(range == -2)
|
||||
targets = living_mob_list
|
||||
else
|
||||
for(var/mob/living/target in view_or_range(range, user, selection_type))
|
||||
targets += target
|
||||
|
||||
else if(max_targets == 1) //single target can be picked
|
||||
if((range == 0 || range == -1) && spell_flags & INCLUDEUSER)
|
||||
targets += user
|
||||
else
|
||||
var/list/possible_targets = list()
|
||||
var/list/starting_targets
|
||||
if(range == -2)
|
||||
starting_targets = living_mob_list
|
||||
else
|
||||
starting_targets = view_or_range(range, user, selection_type)
|
||||
|
||||
for(var/mob/living/M in starting_targets)
|
||||
if(!(spell_flags & INCLUDEUSER) && M == user)
|
||||
continue
|
||||
if(compatible_mobs && compatible_mobs.len)
|
||||
if(!is_type_in_list(M, compatible_mobs)) continue
|
||||
if(compatible_mobs && compatible_mobs.len && !is_type_in_list(M, compatible_mobs))
|
||||
continue
|
||||
possible_targets += M
|
||||
|
||||
if(possible_targets.len)
|
||||
if(spell_flags & SELECTABLE) //if we are allowed to choose. see setup.dm for details
|
||||
var/mob/temp_target = input(user, "Choose the target for the spell.", "Targeting") as null|mob in possible_targets
|
||||
if(temp_target)
|
||||
targets += temp_target
|
||||
else
|
||||
targets += pick(possible_targets)
|
||||
//Adds a safety check post-input to make sure those targets are actually in range.
|
||||
|
||||
|
||||
else
|
||||
var/list/possible_targets = list()
|
||||
var/list/starting_targets
|
||||
|
||||
if(range == -2)
|
||||
starting_targets = living_mob_list
|
||||
else
|
||||
starting_targets = view_or_range(range, user, selection_type)
|
||||
|
||||
for(var/mob/living/target in starting_targets)
|
||||
if(!(spell_flags & INCLUDEUSER) && target == user)
|
||||
continue
|
||||
if(compatible_mobs && !is_type_in_list(target, compatible_mobs))
|
||||
continue
|
||||
possible_targets += target
|
||||
|
||||
if(spell_flags & SELECTABLE)
|
||||
for(var/i = 1; i<=max_targets, i++)
|
||||
if(!possible_targets.len)
|
||||
break
|
||||
var/mob/M = input(user, "Choose the target for the spell.", "Targeting") as null|mob in possible_targets
|
||||
if(!M)
|
||||
break
|
||||
if(range != -2)
|
||||
if(!(M in view_or_range(range, user, selection_type)))
|
||||
continue
|
||||
targets += M
|
||||
possible_targets -= M
|
||||
else
|
||||
for(var/i=1,i<=max_targets,i++)
|
||||
if(!possible_targets.len)
|
||||
break
|
||||
if(target_ignore_prev)
|
||||
var/target = pick(possible_targets)
|
||||
possible_targets -= target
|
||||
targets += target
|
||||
else
|
||||
targets += pick(possible_targets)
|
||||
|
||||
if(!(spell_flags & INCLUDEUSER) && (user in targets))
|
||||
targets -= user
|
||||
|
||||
if(compatible_mobs && compatible_mobs.len)
|
||||
for(var/mob/living/target in targets) //filters out all the non-compatible mobs
|
||||
if(!is_type_in_list(target, compatible_mobs))
|
||||
targets -= target
|
||||
|
||||
return targets
|
||||
|
||||
/spell/targeted/cast(var/list/targets, mob/user)
|
||||
for(var/mob/living/target in targets)
|
||||
if(range >= 0)
|
||||
if(!(target in view_or_range(range, user, selection_type))) //filter at time of casting
|
||||
targets -= target
|
||||
continue
|
||||
apply_spell_damage(target)
|
||||
|
||||
/spell/targeted/proc/apply_spell_damage(mob/living/target)
|
||||
target.adjustBruteLoss(amt_dam_brute)
|
||||
target.adjustFireLoss(amt_dam_fire)
|
||||
target.adjustToxLoss(amt_dam_tox)
|
||||
target.adjustOxyLoss(amt_dam_oxy)
|
||||
//disabling
|
||||
target.Weaken(amt_weakened)
|
||||
target.Paralyse(amt_paralysis)
|
||||
target.Stun(amt_stunned)
|
||||
if(amt_weakened || amt_paralysis || amt_stunned)
|
||||
if(target.buckled)
|
||||
target.buckled = null
|
||||
target.eye_blind += amt_eye_blind
|
||||
target.eye_blurry += amt_eye_blurry
|
||||
target.dizziness += amt_dizziness
|
||||
target.confused += amt_confused
|
||||
/*
|
||||
Targeted spells (with the exception of dumbfire) select from all the mobs in the defined range
|
||||
Targeted spells have two useful flags: INCLUDEUSER and SELECTABLE. These are explained in setup.dm
|
||||
*/
|
||||
|
||||
|
||||
/spell/targeted //can mean aoe for mobs (limited/unlimited number) or one target mob
|
||||
var/max_targets = 1 //leave 0 for unlimited targets in range, more for limited number of casts (can all target one guy, depends on target_ignore_prev) in range
|
||||
var/target_ignore_prev = 1 //only important if max_targets > 1, affects if the spell can be cast multiple times at one person from one cast
|
||||
|
||||
|
||||
var/amt_weakened = 0
|
||||
var/amt_paralysis = 0
|
||||
var/amt_stunned = 0
|
||||
|
||||
var/amt_dizziness = 0
|
||||
var/amt_confused = 0
|
||||
var/amt_stuttering = 0
|
||||
|
||||
//set to negatives for healing
|
||||
var/amt_dam_fire = 0
|
||||
var/amt_dam_brute = 0
|
||||
var/amt_dam_oxy = 0
|
||||
var/amt_dam_tox = 0
|
||||
|
||||
var/amt_eye_blind = 0
|
||||
var/amt_eye_blurry = 0
|
||||
|
||||
var/list/compatible_mobs = list()
|
||||
|
||||
|
||||
/spell/targeted/choose_targets(mob/user = usr)
|
||||
var/list/targets = list()
|
||||
|
||||
if(max_targets == 0) //unlimited
|
||||
if(range == -2)
|
||||
targets = living_mob_list
|
||||
else
|
||||
for(var/mob/living/target in view_or_range(range, holder, selection_type))
|
||||
targets += target
|
||||
|
||||
else if(max_targets == 1) //single target can be picked
|
||||
if((range == 0 || range == -1) && spell_flags & INCLUDEUSER)
|
||||
targets += user
|
||||
else
|
||||
var/list/possible_targets = list()
|
||||
var/list/starting_targets
|
||||
if(range == -2)
|
||||
starting_targets = living_mob_list
|
||||
else
|
||||
starting_targets = view_or_range(range, holder, selection_type)
|
||||
|
||||
for(var/mob/living/M in starting_targets)
|
||||
if(!(spell_flags & INCLUDEUSER) && M == user)
|
||||
continue
|
||||
if(compatible_mobs && compatible_mobs.len)
|
||||
if(!is_type_in_list(M, compatible_mobs)) continue
|
||||
if(compatible_mobs && compatible_mobs.len && !is_type_in_list(M, compatible_mobs))
|
||||
continue
|
||||
possible_targets += M
|
||||
|
||||
if(possible_targets.len)
|
||||
if(spell_flags & SELECTABLE) //if we are allowed to choose. see setup.dm for details
|
||||
var/mob/temp_target = input(user, "Choose the target for the spell.", "Targeting") as null|mob in possible_targets
|
||||
if(temp_target)
|
||||
targets += temp_target
|
||||
else
|
||||
targets += pick(possible_targets)
|
||||
//Adds a safety check post-input to make sure those targets are actually in range.
|
||||
|
||||
|
||||
else
|
||||
var/list/possible_targets = list()
|
||||
var/list/starting_targets
|
||||
|
||||
if(range == -2)
|
||||
starting_targets = living_mob_list
|
||||
else
|
||||
starting_targets = view_or_range(range, holder, selection_type)
|
||||
|
||||
for(var/mob/living/target in starting_targets)
|
||||
if(!(spell_flags & INCLUDEUSER) && target == user)
|
||||
continue
|
||||
if(compatible_mobs && !is_type_in_list(target, compatible_mobs))
|
||||
continue
|
||||
possible_targets += target
|
||||
|
||||
if(spell_flags & SELECTABLE)
|
||||
for(var/i = 1; i<=max_targets, i++)
|
||||
if(!possible_targets.len)
|
||||
break
|
||||
var/mob/M = input(user, "Choose the target for the spell.", "Targeting") as null|mob in possible_targets
|
||||
if(!M)
|
||||
break
|
||||
if(range != -2)
|
||||
if(!(M in view_or_range(range, holder, selection_type)))
|
||||
continue
|
||||
targets += M
|
||||
possible_targets -= M
|
||||
else
|
||||
for(var/i=1,i<=max_targets,i++)
|
||||
if(!possible_targets.len)
|
||||
break
|
||||
if(target_ignore_prev)
|
||||
var/target = pick(possible_targets)
|
||||
possible_targets -= target
|
||||
targets += target
|
||||
else
|
||||
targets += pick(possible_targets)
|
||||
|
||||
if(!(spell_flags & INCLUDEUSER) && (user in targets))
|
||||
targets -= user
|
||||
|
||||
if(compatible_mobs && compatible_mobs.len)
|
||||
for(var/mob/living/target in targets) //filters out all the non-compatible mobs
|
||||
if(!is_type_in_list(target, compatible_mobs))
|
||||
targets -= target
|
||||
|
||||
return targets
|
||||
|
||||
/spell/targeted/cast(var/list/targets, mob/user)
|
||||
for(var/mob/living/target in targets)
|
||||
if(range >= 0)
|
||||
if(!(target in view_or_range(range, holder, selection_type))) //filter at time of casting
|
||||
targets -= target
|
||||
continue
|
||||
apply_spell_damage(target)
|
||||
|
||||
/spell/targeted/proc/apply_spell_damage(mob/living/target)
|
||||
target.adjustBruteLoss(amt_dam_brute)
|
||||
target.adjustFireLoss(amt_dam_fire)
|
||||
target.adjustToxLoss(amt_dam_tox)
|
||||
target.adjustOxyLoss(amt_dam_oxy)
|
||||
//disabling
|
||||
target.Weaken(amt_weakened)
|
||||
target.Paralyse(amt_paralysis)
|
||||
target.Stun(amt_stunned)
|
||||
if(amt_weakened || amt_paralysis || amt_stunned)
|
||||
if(target.buckled)
|
||||
target.buckled = null
|
||||
target.eye_blind += amt_eye_blind
|
||||
target.eye_blurry += amt_eye_blurry
|
||||
target.dizziness += amt_dizziness
|
||||
target.confused += amt_confused
|
||||
target.stuttering += amt_stuttering
|
||||
Reference in New Issue
Block a user