Merge remote-tracking branch 'upstream/master' into clock-rite-neutering-support

This commit is contained in:
DeltaFire
2020-11-11 19:31:15 +01:00
22 changed files with 118 additions and 97 deletions
+1 -1
View File
@@ -508,7 +508,7 @@
if("constructwraith")
M.change_mob_type( /mob/living/simple_animal/hostile/construct/wraith , null, null, delmob )
if("shade")
M.change_mob_type( /mob/living/simple_animal/shade , null, null, delmob )
M.change_mob_type( /mob/living/simple_animal/hostile/construct/shade , null, null, delmob )
/////////////////////////////////////new ban stuff
+2
View File
@@ -295,6 +295,8 @@
++cultplayers
else
++alive
if(!alive)
return
var/ratio = cultplayers/alive
if(ratio > CULT_RISEN && !cult_risen)
for(var/datum/mind/B in members)
+18 -9
View File
@@ -82,7 +82,7 @@ Runes can either be invoked by one's self or with many different cultists. Each
fail_invoke()
/obj/effect/rune/attack_animal(mob/living/simple_animal/M)
if(istype(M, /mob/living/simple_animal/shade) || istype(M, /mob/living/simple_animal/hostile/construct))
if(isshade(M) || istype(M, /mob/living/simple_animal/hostile/construct))
if(construct_invoke || !iscultist(M)) //if you're not a cult construct we want the normal fail message
attack_hand(M)
else
@@ -191,7 +191,7 @@ structure_check() searches for nearby cultist structures required for the invoca
/obj/effect/rune/convert/do_invoke_glow()
return
/obj/effect/rune/convert/invoke(var/list/invokers)
/obj/effect/rune/convert/invoke(list/invokers)
if(rune_in_use)
return
var/list/myriad_targets = list()
@@ -203,11 +203,16 @@ structure_check() searches for nearby cultist structures required for the invoca
fail_invoke()
log_game("Offer rune failed - no eligible targets")
return
var/mob/living/L = pick(myriad_targets)
if(HAS_TRAIT(L, TRAIT_SACRIFICED))
fail_invoke()
log_game("Offer rune failed - target has already been sacrificed")
to_chat(invokers, "<span class='warning'>[L] has already been sacrificed!</span>")
return
rune_in_use = TRUE
visible_message("<span class='warning'>[src] pulses blood red!</span>")
var/oldcolor = color
color = RUNE_COLOR_DARKRED
var/mob/living/L = pick(myriad_targets)
var/is_clock = is_servant_of_ratvar(L)
var/mob/living/F = invokers[1]
@@ -264,7 +269,7 @@ structure_check() searches for nearby cultist structures required for the invoca
H.uncuff()
H.stuttering = 0
H.cultslurring = 0
return 1
return TRUE
/obj/effect/rune/convert/proc/do_sacrifice(mob/living/sacrificial, list/invokers)
var/mob/living/first_invoker = invokers[1]
@@ -308,12 +313,16 @@ structure_check() searches for nearby cultist structures required for the invoca
stone.invisibility = 0
if(sacrificial)
ADD_TRAIT(sacrificial, TRAIT_SACRIFICED, "sacrificed")
if(iscyborg(sacrificial))
playsound(sacrificial, 'sound/magic/disable_tech.ogg', 100, 1)
sacrificial.dust() //To prevent the MMI from remaining
else
playsound(sacrificial, 'sound/magic/disintegrate.ogg', 100, 1)
sacrificial.gib()
var/mob/living/silicon/robot/bot = sacrificial
playsound(sacrificial, 'sound/magic/disable_tech.ogg', 100, TRUE)
bot.deconstruct()
else if(ishuman(sacrificial))
playsound(sacrificial, 'sound/magic/disintegrate.ogg', 100, TRUE)
var/mob/living/carbon/human/H = sacrificial
H.spew_organ(2, 6)
return TRUE
/obj/effect/rune/empower
@@ -36,7 +36,7 @@
/obj/item/soulstone/examine(mob/user)
. = ..()
if(usability || iscultist(user, TRUE) || iswizard(user) || isobserver(user))
if(usability || iscultist(user) || iswizard(user) || isobserver(user))
if (old_shard)
. += "<span class='cult'>A soulstone, used to capture a soul, either from dead humans or from freed shades.</span>"
else
@@ -46,7 +46,7 @@
. += "<span class='cult'>This shard is spent; it is now just a creepy rock.</span>"
/obj/item/soulstone/Destroy() //Stops the shade from being qdel'd immediately and their ghost being sent back to the arrival shuttle.
for(var/mob/living/simple_animal/shade/A in src)
for(var/mob/living/simple_animal/hostile/construct/shade/A in src)
A.death()
return ..()
@@ -58,7 +58,7 @@
to_chat(user, "<span class='userdanger'>Your body is wracked with debilitating pain!</span>")
return
if(spent)
to_chat(user, "<span class='warning'>There is no power left in the shard.</span>")
to_chat(user, "<span class='warning'>There is no power left in [src].</span>")
return
if(!ishuman(M))//If target is not a human.
return ..()
@@ -81,7 +81,7 @@
release_shades(user)
/obj/item/soulstone/proc/release_shades(mob/user)
for(var/mob/living/simple_animal/shade/A in src)
for(var/mob/living/simple_animal/hostile/construct/shade/A in src)
A.status_flags &= ~GODMODE
A.forceMove(get_turf(user))
A.mobility_flags = MOBILITY_FLAGS_DEFAULT
@@ -103,12 +103,12 @@
/obj/structure/constructshell/examine(mob/user)
. = ..()
if(iscultist(user, TRUE) || iswizard(user) || user.stat == DEAD)
. += "<span class='cult'>A construct shell, used to house bound souls from a soulstone.</span>"
. += "<span class='cult'>Placing a soulstone with a soul into this shell allows you to produce your choice of the following:</span>"
. += "<span class='cult'>An <b>Artificer</b>, which can produce <b>more shells and soulstones</b>, as well as fortifications.</span>"
. += "<span class='cult'>A <b>Wraith</b>, which does high damage and can jaunt through walls, though it is quite fragile.</span>"
. += "<span class='cult'>A <b>Juggernaut</b>, which is very hard to kill and can produce temporary walls, but is slow.</span>"
if(iscultist(user) || iswizard(user) || user.stat == DEAD)
. += {"<span class='cult'>A construct shell, used to house bound souls from a soulstone.\n
Placing a soulstone with a soul into this shell allows you to produce your choice of the following:\n
An <b>Artificer</b>, which can produce <b>more shells and soulstones</b>, as well as fortifications.\n
A <b>Wraith</b>, which does high damage and can jaunt through walls, though it is quite fragile.\n
A <b>Juggernaut</b>, which is very hard to kill and can produce temporary walls, but is slow.</span>"}
/obj/structure/constructshell/attackby(obj/item/O, mob/user, params)
if(istype(O, /obj/item/soulstone))
@@ -145,14 +145,14 @@
if("VICTIM")
var/mob/living/carbon/human/T = target
var/datum/antagonist/cult/C = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(C && C.cult_team?.is_sacrifice_target(T.mind))
if(C?.cult_team.is_sacrifice_target(T.mind))
if(iscultist(user))
to_chat(user, "<span class='cult'><b>\"This soul is mine.</b></span> <span class='cultlarge'>SACRIFICE THEM!\"</span>")
else
to_chat(user, "<span class='danger'>The soulstone seems to reject this soul.</span>")
to_chat(user, "<span class='danger'>[src] seems to reject this soul.</span>")
return FALSE
if(contents.len)
to_chat(user, "<span class='userdanger'>Capture failed!</span>: The soulstone is full! Free an existing soul to make room.")
to_chat(user, "<span class='userdanger'>Capture failed!</span>: [src] is full! Free an existing soul to make room.")
else
if((!old_shard && T.stat != CONSCIOUS) || (old_shard && T.stat == DEAD))
if(T.client == null)
@@ -167,7 +167,7 @@
to_chat(user, "<span class='userdanger'>Capture failed!</span>: Kill or maim the victim first!")
if("SHADE")
var/mob/living/simple_animal/shade/T = target
var/mob/living/simple_animal/hostile/construct/shade/T = target
if(contents.len)
to_chat(user, "<span class='userdanger'>Capture failed!</span>: The soulstone is full! Free an existing soul to make room.")
else
@@ -177,13 +177,13 @@
T.health = T.maxHealth
icon_state = "soulstone2"
name = "soulstone: Shade of [T.real_name]"
to_chat(T, "<span class='notice'>Your soul has been captured by the soulstone. Its arcane energies are reknitting your ethereal form.</span>")
to_chat(T, "<span class='notice'>Your soul has been captured by [src]. Its arcane energies are reknitting your ethereal form.</span>")
if(user != T)
to_chat(user, "<span class='info'><b>Capture successful!</b>:</span> [T.real_name]'s soul has been captured and stored within the soulstone.")
to_chat(user, "<span class='info'><b>Capture successful!</b>:</span> [T.real_name]'s soul has been captured and stored within [src].")
if("CONSTRUCT")
var/obj/structure/constructshell/T = target
var/mob/living/simple_animal/shade/A = locate() in src
var/mob/living/simple_animal/hostile/construct/shade/A = locate() in src
if(A)
var/construct_class = alert(user, "Please choose which type of construct you wish to create.",,"Juggernaut","Wraith","Artificer")
if(!T || !T.loc)
@@ -199,8 +199,8 @@
if(iscultist(user) || iswizard(user))
makeNewConstruct(/mob/living/simple_animal/hostile/construct/builder, A, user, 0, T.loc)
else
makeNewConstruct(/mob/living/simple_animal/hostile/construct/builder/noncult, A, user, 0, T.loc)
else
return
for(var/datum/mind/B in SSticker.mode.cult)
if(B == A.mind)
SSticker.mode.cult -= A.mind
@@ -208,19 +208,24 @@
qdel(T)
qdel(src)
else
to_chat(user, "<span class='userdanger'>Creation failed!</span>: The soul stone is empty! Go kill someone!")
to_chat(user, "<span class='userdanger'>Creation failed!</span>: [src] is empty! Go kill someone!")
/proc/makeNewConstruct(mob/living/simple_animal/hostile/construct/ctype, mob/target, mob/stoner = null, cultoverride = 0, loc_override = null)
if(QDELETED(target))
return
var/mob/living/simple_animal/hostile/construct/newstruct = new ctype((loc_override) ? (loc_override) : (get_turf(target)))
if(stoner)
newstruct.faction |= "[REF(stoner)]"
newstruct.master = stoner
var/datum/action/innate/seek_master/SM = new()
SM.Grant(newstruct)
target.transfer_ckey(newstruct)
newstruct.key = target.key
if(target.type == /mob/living/simple_animal/hostile/construct/shade) //Make sure we remember which body belonged to the shade
var/mob/living/simple_animal/hostile/construct/shade/shade = target
newstruct.original_mind = shade.original_mind
var/obj/screen/alert/bloodsense/BS
if(newstruct.mind && ((stoner && iscultist(stoner)) || cultoverride) && SSticker && SSticker.mode)
if(newstruct.mind && ((stoner && iscultist(stoner)) || cultoverride) && SSticker?.mode)
SSticker.mode.add_cultist(newstruct.mind, 0)
if(iscultist(stoner) || cultoverride)
to_chat(newstruct, "<b>You are still bound to serve the cult[stoner ? " and [stoner]":""], follow [stoner ? stoner.p_their() : "their"] orders and help [stoner ? stoner.p_them() : "them"] complete [stoner ? stoner.p_their() : "their"] goals at all costs.</b>")
@@ -234,19 +239,18 @@
/obj/item/soulstone/proc/init_shade(mob/living/carbon/human/T, mob/user, vic = 0)
new /obj/effect/decal/remains/human(T.loc) //Spawns a skeleton
if(HAS_TRAIT_FROM(T, TRAIT_SACRIFICED, "sacrificed"))
if(user)
to_chat(user, "This body has already been harvested!")
return
ADD_TRAIT(T, TRAIT_SACRIFICED, "sacrificed")
T.stop_sound_channel(CHANNEL_HEARTBEAT)
T.invisibility = INVISIBILITY_ABSTRACT
T.dust_animation()
QDEL_IN(T, 5)
var/mob/living/simple_animal/shade/S = new /mob/living/simple_animal/shade(src)
S.status_flags |= GODMODE //So they won't die inside the stone somehow
S.mobility_flags = NONE //Can't move out of the soul stone
var/mob/living/simple_animal/hostile/construct/shade/S = new /mob/living/simple_animal/hostile/construct/shade(src)
S.name = "Shade of [T.real_name]"
S.real_name = "Shade of [T.real_name]"
T.transfer_ckey(S)
S.original_mind = T.mind.current
S.copy_languages(T, LANGUAGE_MIND)//Copies the old mobs languages into the new mob holder.
S.copy_languages(user, LANGUAGE_MASTER)
S.update_atom_languages()
grant_all_languages(FALSE, FALSE, TRUE) //Grants omnitongue
if(user)
@@ -264,7 +268,7 @@
to_chat(user, "<span class='info'><b>Capture successful!</b>:</span> [T.real_name]'s soul has been ripped from [T.p_their()] body and stored within the soul stone.")
/obj/item/soulstone/proc/getCultGhost(mob/living/carbon/human/T, mob/U)
/obj/item/soulstone/proc/getCultGhost(mob/living/carbon/human/T, mob/user)
var/mob/dead/observer/chosen_ghost
for(var/mob/dead/observer/ghost in GLOB.player_list) //We put them back in their body
@@ -279,13 +283,12 @@
if(!T)
return FALSE
if(!chosen_ghost)
to_chat(U, "<span class='danger'>There were no spirits willing to become a shade.</span>")
to_chat(user, "<span class='danger'>There were no spirits willing to become a shade.</span>")
return FALSE
if(contents.len) //If they used the soulstone on someone else in the meantime
return FALSE
T.ckey = chosen_ghost.ckey
for(var/obj/item/W in T)
T.dropItemToGround(W)
init_shade(T, U)
qdel(T)
init_shade(T, user)
return TRUE
+8 -8
View File
@@ -86,7 +86,7 @@
else if(trapped == HOWLING_GHOST)
visible_message("<span class='userdanger'><font size='5'>[pick("OooOOooooOOOoOoOOooooOOOOO", "BooOOooOooooOOOO", "BOO!", "WoOOoOoooOooo")]</font></span>")
playsound(loc, 'sound/spookoween/ghosty_wind.ogg', 300, 1)
new /mob/living/simple_animal/shade/howling_ghost(loc)
new /mob/living/simple_animal/hostile/construct/shade/howling_ghost(loc)
trapped = 0
else if(trapped == SCARY_BATS)
@@ -123,7 +123,7 @@
//Spookoween Ghost//
////////////////////
/mob/living/simple_animal/shade/howling_ghost
/mob/living/simple_animal/hostile/construct/shade/howling_ghost
name = "ghost"
real_name = "ghost"
icon = 'icons/mob/mob.dmi'
@@ -137,13 +137,13 @@
layer = 4
var/timer = 0
/mob/living/simple_animal/shade/howling_ghost/Initialize()
/mob/living/simple_animal/hostile/construct/shade/howling_ghost/Initialize()
. = ..()
icon_state = pick("ghost","ghostian","ghostian2","ghostking","ghost1","ghost2")
icon_living = icon_state
timer = rand(1,15)
/mob/living/simple_animal/shade/howling_ghost/Life()
/mob/living/simple_animal/hostile/construct/shade/howling_ghost/Life()
..()
timer--
if(prob(20))
@@ -152,16 +152,16 @@
spooky_ghosty()
timer = rand(1,15)
/mob/living/simple_animal/shade/howling_ghost/proc/EtherealMove(direction)
/mob/living/simple_animal/hostile/construct/shade/howling_ghost/proc/EtherealMove(direction)
forceMove(get_step(src, direction))
setDir(direction)
/mob/living/simple_animal/shade/howling_ghost/proc/roam()
/mob/living/simple_animal/hostile/construct/shade/howling_ghost/proc/roam()
if(prob(80))
var/direction = pick(NORTH,SOUTH,EAST,WEST,NORTHEAST,NORTHWEST,SOUTHEAST,SOUTHWEST)
EtherealMove(direction)
/mob/living/simple_animal/shade/howling_ghost/proc/spooky_ghosty()
/mob/living/simple_animal/hostile/construct/shade/howling_ghost/proc/spooky_ghosty()
if(prob(20)) //haunt
playsound(loc, pick('sound/spookoween/ghosty_wind.ogg','sound/spookoween/ghost_whisper.ogg','sound/spookoween/chain_rattling.ogg'), 300, 1)
if(prob(10)) //flickers
@@ -175,7 +175,7 @@
step(I,direction)
return
/mob/living/simple_animal/shade/howling_ghost/CanPass(atom/movable/mover, turf/target)
/mob/living/simple_animal/hostile/construct/shade/howling_ghost/CanPass(atom/movable/mover, turf/target)
return 1
///////////////////////////
@@ -79,16 +79,16 @@
popup.open(FALSE)
/mob/dead/new_player/proc/age_verify()
if(CONFIG_GET(flag/age_verification)) //make sure they are verified
if(CONFIG_GET(flag/age_verification) && !check_rights_for(client, R_ADMIN) && !(client.ckey in GLOB.bunker_passthrough)) //make sure they are verified
if(!client.set_db_player_flags())
message_admins("Blocked [src] from new player panel because age verification could not access player database flags.")
message_admins("Blocked [src] from new player panel because age gate could not access player database flags.")
return FALSE
else
var/dbflags = client.prefs.db_flags
if(dbflags & DB_FLAG_AGE_CONFIRMATION_INCOMPLETE) //they have not completed age verification
var/age_verification = askuser(src, "Are you 18+", "Age Verification", "I am 18+", "I am not 18+", null, TRUE, null)
if(dbflags & DB_FLAG_AGE_CONFIRMATION_INCOMPLETE) //they have not completed age gate
var/age_verification = askuser(src, "Are you 18+", "Age Gate", "I am 18+", "I am not 18+", null, TRUE, null)
if(age_verification != 1)
add_system_note("Automated-Age-Verification", "Failed automatic age verification")
client.add_system_note("Automated-Age-Gate", "Failed automatic age gate process")
qdel(client) //kick the user
return FALSE
else
@@ -96,7 +96,7 @@
client.update_flag_db(DB_FLAG_AGE_CONFIRMATION_COMPLETE, TRUE)
client.update_flag_db(DB_FLAG_AGE_CONFIRMATION_INCOMPLETE, FALSE)
//log this
message_admins("[ckey] has joined through the automated age verification process.")
message_admins("[ckey] has joined through the automated age gate process.")
return TRUE
return TRUE
+1 -1
View File
@@ -611,7 +611,7 @@
update_mobility()
UpdateStaminaBuffer()
update_health_hud()
/mob/living/carbon/update_sight()
if(!client)
return
@@ -44,6 +44,7 @@
var/can_repair_constructs = FALSE
var/can_repair_self = FALSE
var/runetype
var/original_mind
/mob/living/simple_animal/hostile/construct/Initialize()
. = ..()
@@ -66,6 +67,11 @@
CR.button.screen_loc = "6:[pos],4:-2"
CR.button.moved = "6:[pos],4:-2"
/mob/living/simple_animal/hostile/construct/death()
if(original_mind)
transfer_ckey(original_mind)
..()
/mob/living/simple_animal/hostile/construct/Login()
..()
to_chat(src, playstyle_string)
@@ -107,7 +113,7 @@
return
/mob/living/simple_animal/hostile/construct/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE)
return 0
return FALSE
/mob/living/simple_animal/hostile/construct/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
. = ..()
+8 -28
View File
@@ -1,53 +1,33 @@
/mob/living/simple_animal/shade
/mob/living/simple_animal/hostile/construct/shade
name = "Shade"
real_name = "Shade"
desc = "A bound spirit."
gender = PLURAL
icon = 'icons/mob/mob.dmi'
icon_state = "shade"
icon_living = "shade"
mob_biotypes = MOB_SPIRIT
maxHealth = 40
health = 40
spacewalk = TRUE
healable = 0
speak_emote = list("hisses")
emote_hear = list("wails.","screeches.")
response_help_continuous = "puts their hand through"
response_help_simple = "put your hand through"
response_disarm_continuous = "flails at"
response_disarm_simple = "flail at"
response_harm_continuous = "punches"
response_harm_simple = "punch"
speak_chance = 1
melee_damage_lower = 5
melee_damage_upper = 12
attack_verb_continuous = "metaphysically strikes"
attack_verb_simple = "metaphysically strike"
minbodytemp = 0
maxbodytemp = INFINITY
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
stop_automated_movement = 1
status_flags = 0
faction = list("cult")
status_flags = CANPUSH
movement_type = FLYING
speed = -1 //they don't have to lug a body made of runed metal around
loot = list(/obj/item/ectoplasm)
del_on_death = TRUE
initial_language_holder = /datum/language_holder/construct
blood_volume = 0
has_field_of_vision = FALSE //we are a spoopy ghost
playstyle_string = "<span class='big bold'>You are a shade!</span><b> Your job is to survive until you are granted a shell, and help out cultists with casting runes!</b>"
/mob/living/simple_animal/shade/death()
/mob/living/simple_animal/hostile/construct/shade/death()
deathmessage = "lets out a contented sigh as [p_their()] form unwinds."
..()
/mob/living/simple_animal/shade/canSuicide()
/mob/living/simple_animal/hostile/construct/shade/canSuicide()
if(istype(loc, /obj/item/soulstone)) //do not suicide inside the soulstone
return 0
return FALSE
return ..()
/mob/living/simple_animal/shade/attack_animal(mob/living/simple_animal/M)
/mob/living/simple_animal/hostile/construct/shade/attack_animal(mob/living/simple_animal/M)
if(isconstruct(M))
var/mob/living/simple_animal/hostile/construct/C = M
if(!C.can_repair_constructs)
@@ -62,7 +42,7 @@
else if(src != M)
return ..()
/mob/living/simple_animal/shade/attackby(obj/item/O, mob/user, params) //Marker -Agouri
/mob/living/simple_animal/hostile/construct/shade/attackby(obj/item/O, mob/user, params) //Marker -Agouri
if(istype(O, /obj/item/soulstone))
var/obj/item/soulstone/SS = O
SS.transfer_soul("SHADE", src, user)
+1 -1
View File
@@ -617,7 +617,7 @@
return 1
if(ispath(MP, /mob/living/simple_animal/hostile/mushroom))
return 1
if(ispath(MP, /mob/living/simple_animal/shade))
if(ispath(MP, /mob/living/simple_animal/hostile/construct/shade))
return 1
if(ispath(MP, /mob/living/simple_animal/hostile/killertomato))
return 1