Additional Pylons (#1870)

This PR adds a new utility mechanic for the cult. Pylons can now be upgraded into arcane defensive turrets, which fire bolts of demonic energy. These turrets are entirely automated, somewhat-rapid firing, extremely accurate and quite long ranged, but their damage is very low, and thus their total DPS, even with the fire rate, is still far lower than most real ranged weapons.
This commit is contained in:
NanakoAC
2017-03-19 00:06:36 +02:00
committed by skull132
parent ae5956fd6e
commit 67bb388a5a
11 changed files with 700 additions and 45 deletions
+7 -1
View File
@@ -6,6 +6,12 @@ var/datum/antagonist/cultist/cult
if(player.mind in cult.current_antagonists)
return 1
/proc/iscult(var/mob/test)
if (test.faction == "cult")
return 1
else return iscultist(test)
/datum/antagonist/cultist
id = MODE_CULTIST
role_text = "Cultist"
@@ -113,7 +119,7 @@ var/datum/antagonist/cultist/cult
player << "You catch a glimpse of the Realm of Nar-Sie, the Geometer of Blood. You now see how flimsy the world is, you see that it should be open to the knowledge of That Which Waits. Assist your new compatriots in their dark dealings. Their goals are yours, and yours are theirs. You serve the Dark One above all else. Bring It back."
if(player.current && !istype(player.current, /mob/living/simple_animal/construct))
player.current.add_language(LANGUAGE_CULT)
/datum/antagonist/cultist/can_become_antag(var/datum/mind/player, ignore_role = 1)
if(!..())
return 0
+541 -26
View File
@@ -17,59 +17,565 @@
desc = "A forge used in crafting the unholy weapons used by the armies of Nar-Sie"
icon_state = "forge"
/*
Cult pylons can be used as arcane defensive turrets.
First of all they must be empowered with a sacrifice. Any small organic creature that can be picked up is valid
Hit the pylon with the creature - while still alive - to present it as a sacrifice, and then end its life to complete the process.
Once empowered, pylons will fire rapid, weak magical beams at non cult mobs.
As crystals, pylons are immune to energy weaponry. More than immune, they will absorb lasers and become
supercharged for some time, boosting their damage. Pylons can only be harmed by ballistics and physical weapons
Building reinforced windows around them is highly recommended.
Pylons are fairly fragile and will quickly break under direct hits.
A damaged pylon will self repair, if it contains a soul.
Pylons are largely intended as a stalling, early warning, fire support and area denial system. They are unlikely to actually
kill anyone alone but they can keep pesky civilians away for long enough to learn runes and prepare rituals.
If you can get ahold of a laser rifle to supercharge them, they can even give security some pause
Recommended tools for combatting pylons:
Heavy melee (fireaxe, baseball bat, etc)
Sniper rifles
Exosuits
Explosives
Ablative armour
*/
/obj/structure/cult/pylon
name = "Pylon"
desc = "A floating crystal that hums with an unearthly energy"
icon_state = "pylon"
description_antag = "A pylon can be upgraded into a magical defensive turret that shoots anyone opposing the cult\
</br>Upgrading a pylon requires a sacrifice. Bring it a small organic creature, like a monkey or mouse. Use the creature on the pylon, or drag and drop to present it.\
</br>Once the sacrifice is accepted, kill it to complete the process. This will gib its body and make a very visible mess. After this point the pylon is fixed to the floor and cant be moved\
</br>The pylon will fire weak beams that are harmless to the cult. In addition it can be upgraded even more by shooting it with a laser, which will give it a limited number of extra-power shots."
icon_state = "pylonbase"
var/isbroken = 0
light_range = 5
light_color = "#3e0000"
var/obj/item/wepon = null
var/pylonmode = 0
//Pylon has three states:
//0 = Idle, the pylon is an inert crystal
//1 = Awaiting sacrifice. The pylon is actively tracking a creature to be sacrificed to it
//2 = Turret. The pylon has been empowered by a sacrifice and is now a turret permanantly
var/damagetaken = 0
var/empowered = 0 //Number of empowered, higher-damage shots remaining
var/processing = 0
var/mob/living/sacrifice //Holds a reference to a mob that is a pending sacrifice
var/mob/living/sacrificer //A reference to the last mob that attempted to sacrifice something. So we can message them
//Sacrifier is also used in target handling. the pylon will not bite the hand that feeds it. Noncultist colleagues are fair game though
var/next_shot = 0 //Absolute world time when we're allowed to fire again
var/shot_delay = 5 //Minimum delay between shots, in deciseconds
var/mob/living/target
var/notarget //Number of times handle_firing has been called without finding anything to shoot at
//This is used for switching to lower-intensity processing
var/datum/language/cultcommon/lang
//An instance of the cult language datum. Used to scramble speech when speaking to noncultists
var/turf/last_target_loc
var/process_interval = 1
var/ticks
anchored = 0
//Just a subtype that starts off in turret mode. For adminbus and debugging. Maybe a future wizard spell
//Spawn them next to ERPers
/obj/structure/cult/pylon/turret
pylonmode = 2
/obj/structure/cult/pylon/turret/New()
..()
start_process()
//Another subtype which starts with infinite empower shots. For empowered adminbus
/obj/structure/cult/pylon/turret/empowered
empowered = 99999999
/obj/structure/cult/pylon/New()
..()
lang = new /datum/language/cultcommon()
update_icon()
/obj/structure/cult/pylon/examine(var/mob/user)
..()
if (damagetaken)
switch (damagetaken)
if (1 to 8)
user << "It has very faint hairline fractures."
if (8 to 20)
user << "It has several cracks across its surface."
if (20 to 30)
user << "It is chipped and deeply cracked, it may shatter with much more pressure."
if (30 to INFINITY)
user << "It is almost cleaved in two, the pylon looks like it will fall to shards under its own weight."
/obj/structure/cult/pylon/Move()
..()
last_target_loc = null
/obj/structure/cult/pylon/proc/start_process()
process_interval = 1
if (!processing)
processing_objects += src
processing = 1
//If the pylon goes a long time without shooting anything, it will consider slowing down processing
/obj/structure/cult/pylon/proc/reconsider_interval()
var/mindist = INFINITY
for (var/m in player_list)
var/mob/living/L = m
if (L.z != z)
continue
if (L.stat == DEAD)
continue
if (iscult(L))
continue
if (L == sacrificer)
continue
var/d = get_dist(src, L)
if (d < mindist)
mindist = d
mindist = min(150, mindist)
process_interval = Ceiling(mindist*0.1)
process_interval = max(1, process_interval)
//Run each process loop, this function checks if we can stop processing yet.
//Returns 0 if its time to stop. Returns 1 if we should keep going.
/obj/structure/cult/pylon/proc/check_process()
if (isbroken)
return 0
if (pylonmode == 2)
return 1
if (pylonmode == 1)
if (sacrifice)
return 1
if (empowered > 0)
return 1
return 0
/obj/structure/cult/pylon/process()
ticks++
if(!check_process())
processing_objects.Remove(src)
processing = 0
return
switch (pylonmode)
if (1)
handle_sacrifice()
if (2)
if ((ticks % process_interval) == 0)
handle_firing()
if (damagetaken && prob(50))
damagetaken = max(0, damagetaken-1) //An empowered pylon slowly self repairs
if (prob(10))
visible_message("Cracks in the [src] gradually seal as new crystalline matter grows to fill them.")
if (empowered && prob(2))
empowered = max(0, empowered - 1) //Overcharging gradually wears off over time
if (empowered <= 0)
update_icon()
//If user is a cultist, speaks message to them with a prefix
//If user is not cultist, then speaks cult-y gibberish
/obj/structure/cult/pylon/proc/speak_to(var/mob/user, var/message)
if (iscult(user) || (/datum/language/cultcommon in user.languages))
user << "A voice speaks into your mind, [span("cult","\"<I>[message]</I>\"")]"
else
user << "A voice speaks into your mind, [span("cult","\"<I>[lang.scramble(message)]</I>\"")]"
//Todo: Replace the messages here with better ones. Should display a proper message to cultists
//And nonsensical arcane gibberish to non cultists
/obj/structure/cult/pylon/proc/present_sacrifice(var/mob/living/user, var/mob/living/victim)
if (!user || !victim)
return 0
if (isbroken)
user << "The pylon lies silent."
return 0
if (pylonmode != 0)
return 0
if (!(victim.mob_size) || victim.mob_size > 6)
//toolarge sacrifice, display a message and return
speak_to(user, "This creature is too large, we only require a lesser sacrifice. A small morsel of life...")
return
if (victim.stat == DEAD)
speak_to(user, "You are too late, the spark of life is already gone from this one. It is naught but an empty husk...")
return
var/types = victim.find_type()
if ((!(types & TYPE_ORGANIC)) || ((types & TYPE_WIERD)))
//Invalid sacrifice. Display a message and return
speak_to(user, "This soulless automaton cannot satisfy our hunger. We yearn for life essence, it must have a soul.")
return
sacrifice = victim
sacrificer = user
//Sacrifice accepted, display message here
speak_to(user, "Your sacrifice has been deemed worthy, and accepted. End its life now, and liberate its soul, to seal our contract...")
sacrifice << span("danger", "You feel an invisible force grip your soul, as you're drawn inexorably towards the pylon. Every part of you screams to flee from here!")
if (istype(sacrifice.loc,/obj/item/weapon/holder))
var/obj/item/weapon/holder/H = sacrifice.loc
H.release_to_floor()
else
sacrifice.forceMove(get_turf(sacrifice))
pylonmode = 1
update_icon()
start_process()
//Runs every proc while there's a pending sacrifice. This checks whether the sacrifice was killed or escaped
/obj/structure/cult/pylon/proc/handle_sacrifice()
.=0 //Return value has 3 states.
//0 = waiting, the sacrifice is still alive
//1 = Finished, the sacrifice was killed, finalize the process and become a turret
//-1 = Escape: The sacrifice left the vicinity of the pylon, return to inert mode.
if (!sacrifice)
//If the sacrifice was deleted somehow, we cant know exactly what happened. We'll assume it escaped
.=-1
else if(get_dist(src, sacrifice) > 5)
//If the sacrifice gets more than 5 tiles away, it has escaped
.=-1
else if (sacrifice.stat == DEAD)
.=1
switch(.)
if (1)
finalize_sacrifice()
if (-1)
speak_to(sacrificer, "Fool! Your offering has escaped. Bring it back, or find us another...")
sacrifice = null
pylonmode = 0
update_icon()
if (sacrifice)
walk_to(sacrifice,0)
else
walk_towards(sacrifice,src, 10)
/obj/structure/cult/pylon/proc/finalize_sacrifice()
sacrifice.visible_message(span("danger","\The [sacrifice]'s physical form unwinds as its soul is extracted from the remains, and drawn into the pylon!"))
if (istype(sacrifice.loc,/obj/item/weapon/holder))
var/obj/item/weapon/holder/H = sacrifice.loc
H.release_to_floor()
else
sacrifice.forceMove(get_turf(sacrifice)) //Make sure its on the floor before we gib it
pylonmode = 2
sacrifice.gib()
update_icon()
//Called every process in turret mode, and also by chaining spawns
/obj/structure/cult/pylon/proc/handle_firing()
if ((world.time < next_shot) || isbroken)
return
//Not ready to fire yet
var/list/stuffcache
//Stuffcache holds a list of things found by a dview call, so we only need to do it once per proc.
if (target && (target.stat != DEAD))
if (target.loc == last_target_loc)
//To minimise expensive DVIEW calls, if the target hasnt moved since the last shot we'll assume they're still in sight
//This could cause problems in some edge cases (like lowering firelocks or shutters without moving)
//But it has a major performance gain that makes it worth it
fire_at(target)
return
else
stuffcache = mobs_in_view(10, src)
//for (var/turf/T in stuffcache)
//new /obj/effect/testtrans(T)
if ((target in stuffcache) && isInSight(src, target))
for (var/mob/m in stuffcache)
fire_at(target)
return
else
target = null
//We may have already populated stuffcache this run, dont repeat work
if (!stuffcache)
stuffcache = mobs_in_view(10, src)
target = null //Either we lost a target or lack one
//for (var/turf/T in stuffcache)
//new /obj/effect/testtrans(T)
for (var/mob/living/L in stuffcache)
if (L == sacrificer)
continue
//A pylon won't shoot the person who created it, regardless of cult status.
//This is mainly for xenoarch antags
if (L.stat == DEAD)
continue
//No point shooting at corpses
if (iscult(L))
continue
//Pylon wont shoot at cultists or constructs
if (!isInSight(src, L))
continue
target = L
break
if (target)
fire_at(target)
else
notarget++
if (notarget > 60 || process_interval > 1)
notarget = 0
reconsider_interval()
/obj/structure/cult/pylon/proc/fire_at(var/atom/target)
//Only store loc if target is on a turf. Otherwise this bugs out with people in exosuits
if (istype(target.loc, /turf))
last_target_loc = target.loc
process_interval = 1 //Instantly wake up if we found a target
var/obj/item/projectile/beam/cult/A
if (empowered > 0)
A = new /obj/item/projectile/beam/cult/heavy(loc)
empowered = max(0, empowered-1)
playsound(loc, 'sound/weapons/laserdeep.ogg', 100, 1)
if (empowered <= 0)
update_icon()
else
A = new /obj/item/projectile/beam/cult(loc)
playsound(loc, 'sound/weapons/laserdeep.ogg', 65, 1)
A.ignore = sacrificer
A.launch(target)
next_shot = world.time + shot_delay
spawn(shot_delay+1)
handle_firing()
/obj/structure/cult/pylon/attack_hand(mob/M as mob)
attackpylon(M, 5)
if (M.a_intent == "help")
M << "The pylon feels warm to the touch...."
else
attackpylon(M, 4, M)
/obj/structure/cult/pylon/attack_generic(var/mob/user, var/damage)
attackpylon(user, damage)
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
//Artificiers maintain pylons
if(istype(user, /mob/living/simple_animal/construct))
var/mob/living/simple_animal/construct/C = user
if (C.can_repair)
repair(user)
return
attackpylon(user, damage, user)
/obj/structure/cult/pylon/attackby(obj/item/W as obj, mob/user as mob)
attackpylon(user, W.force)
if (istype(W, /obj/item/weapon/holder))
var/obj/item/weapon/holder/H = W
if (H.contained)
present_sacrifice(user, H.contained)
return
/obj/structure/cult/pylon/proc/attackpylon(mob/user as mob, var/damage)
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if(!isbroken)
if(prob(1+ damage * 5))
user.visible_message(
"<span class='danger'>[user] smashed the pylon!</span>",
"<span class='warning'>You hit the pylon, and its crystal breaks apart!</span>",
"You hear a tinkle of crystal shards"
attackpylon(user, W.force, W)
//Mousedrop so that constructs can drag mice out of maintenance to make turrets
/obj/structure/cult/pylon/MouseDrop_T(var/atom/movable/C, mob/user)
if (istype(C, /mob/living))
present_sacrifice(user, C)
return
return ..()
/obj/structure/cult/pylon/bullet_act(var/obj/item/projectile/Proj)
attackpylon(user, Proj.damage, Proj)
//Explosions will usually cause instant shattering, or heavy damage
//Class 3 or lower blast is sometimes survivable. 2 or higher will always shatter
/obj/structure/cult/pylon/ex_act(var/severity)
if (severity > 0)
attackpylon(null, (rand(200,400)/severity), null)
/obj/structure/cult/pylon/proc/attackpylon(mob/user as mob, var/damage, var/source)
var/ranged = 0
if (user)
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if (istype(source, /obj/item))
var/obj/item/I = source
if (I.damtype != BRUTE)
user << "You swing at the pylon to no effect."
return
if (istype(source, /obj/item/projectile))
if (istype(source, /obj/item/projectile/beam/cult))
return //No feedback loops
var/obj/item/projectile/proj = source
if (proj.damage_type == BURN)
if (empowered <= 0)
visible_message(
"<span class='cult'>The beam refracts inside the pylon, splitting into an indistinct violet glow. The crystal takes on a new, more ominous aura!</span>"
)
empowered += damage*0.3
//When shot with a laser, the pylon absorbs the beam, becoming empowered for a while, glowing brighter
// and firing more powerful blasts which have some armor penetration
// Using lasers to empower a defensive pylon yields more total damage than directly shooting your enemies
start_process()
update_icon()
return
else if (proj.damage_type != BRUTE)
return
ranged = 1
if (!damage)
return
damagetaken += damage
if(!isbroken)
if (user)
user.do_attack_animation(src)
playsound(get_turf(src), 'sound/effects/Glassbr3.ogg', 75, 1)
isbroken = 1
density = 0
icon_state = "pylon-broken"
set_light(0)
if(prob(damagetaken*0.5))
shatter()
else
user << "You hit the pylon!"
if (user && !ranged)
user << "You hit the pylon!"
playsound(get_turf(src), 'sound/effects/Glasshit.ogg', 75, 1)
else
if(prob(damage * 2))
user << "You pulverize what was left of the pylon!"
if(prob(damagetaken))
if (user)
user << "You pulverize what was left of the pylon!"
qdel(src)
else
else if (user && !ranged)
user << "You hit the pylon!"
playsound(get_turf(src), 'sound/effects/Glasshit.ogg', 75, 1)
start_process()
/obj/structure/cult/pylon/proc/shatter()
visible_message(
"<span class='danger'>The pylon shatters into shards of crystal!</span>",
"You hear a tinkle of crystal shards"
)
playsound(get_turf(src), 'sound/effects/Glassbr3.ogg', 75, 1)
isbroken = 1
if (pylonmode == 2)
//If the pylon had a soul in it then it plays a creepy evil sound as the soul is released
var/possibles = list('sound/hallucinations/far_noise.ogg',
'sound/hallucinations/growl3.ogg',
'sound/hallucinations/veryfar_noise.ogg',
'sound/hallucinations/wail.ogg',
'sound/voice/hiss5.ogg')
playsound(get_turf(src), pick(possibles), 50, 1)
pylonmode = 0 //A broken pylon loses its soul. Even if repaired it will need a new sacrifice to re-empower it
//Make sure we stop it from firing
target = null
sacrificer = null
notarget = 0
last_target_loc = null
process_interval = 1
//It will stop processing after the next check, start of the next process
empowered = 0
density = 0
update_icon()
/obj/structure/cult/pylon/proc/repair(mob/user as mob)
if(isbroken)
user << "You repair the pylon."
if(user)
user << span("notice","You weave forgotten magic, summoning the shards of the crystal and knitting them anew, until it hovers flawless once more.")
isbroken = 0
density = 1
icon_state = "pylon"
set_light(5)
else if (damagetaken > 0)
user << span("notice","You meld the crystal lattice back into integrity, sealing over the cracks until they never were.")
else
user << span("notice","The crystal lights up at your touch.")
process_interval = 1 //Wake up the crystal
notarget = 0
damagetaken = 0
update_icon()
/obj/structure/cult/pylon/update_icon()
overlays.Cut()
if (pylonmode == 2)
anchored = 1
if (empowered > 0)
overlays += "crystal_overcharge"
set_light(7, 3, l_color = "#a160bf")
else
set_light(6, 3, l_color = "#3e0000")
overlays += "crystal_turret"
else if (!isbroken)
set_light(5, 2, l_color = "#3e0000")
overlays += "crystal_idle"
if (pylonmode == 1)
anchored = 1
else
anchored = 0
else
anchored = 0
set_light(0)
//============================================
/obj/structure/cult/tome
name = "Desk"
desc = "A desk covered in arcane manuscripts and tomes in unknown languages. Looking at the text makes your skin crawl"
@@ -144,7 +650,7 @@
if(M.has_brain_worms())
return //Borer stuff - RR
if(iscultist(M)) return
if(iscult(M)) return
if(!ishuman(M) && !isrobot(M)) return
M.transforming = 1
@@ -174,3 +680,12 @@
new_mob.key = M.key
new_mob << "<B>Your form morphs into that of a corgi.</B>" //Because we don't have cluwnes
/obj/effect/testtrans
icon = 'icons/obj/cult.dmi'
icon_state = "tt"
/obj/effect/testtrans/New()
..()
spawn(10)
qdel(src)
+10 -6
View File
@@ -24,15 +24,19 @@
can_open = WALL_CAN_OPEN
update_icon()
/turf/simulated/wall/proc/fail_smash(var/mob/user)
/turf/simulated/wall/proc/fail_smash(var/mob/user, var/multiplier = 1)
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN*2.5)
user << "<span class='danger'>You smash against the wall!</span>"
take_damage(rand(25,75))
user.do_attack_animation(src)
take_damage(rand(60,135)*multiplier)
return 1
/turf/simulated/wall/proc/success_smash(var/mob/user)
user << "<span class='danger'>You smash through the wall!</span>"
user.do_attack_animation(src)
spawn(1)
dismantle_wall(1)
return 1
/turf/simulated/wall/proc/try_touch(var/mob/user, var/rotting)
@@ -64,7 +68,7 @@
if (rotting || !prob(material.hardness))
success_smash(user)
else
fail_smash(user)
fail_smash(user, 2)
return 1
try_touch(user, rotting)
@@ -72,21 +76,21 @@
/turf/simulated/wall/attack_generic(var/mob/user, var/damage, var/attack_message, var/wallbreaker)
radiate()
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
var/rotting = (locate(/obj/effect/overlay/wallrot) in src)
if(!damage || !wallbreaker)
try_touch(user, rotting)
return
if(rotting)
return success_smash(user)
if(reinf_material)
if((wallbreaker == 2) || (damage >= max(material.hardness,reinf_material.hardness)))
if((wallbreaker == 2) && (damage >= max(material.hardness,reinf_material.hardness)))
return success_smash(user)
else if(damage >= material.hardness)
return success_smash(user)
return fail_smash(user)
return fail_smash(user, wallbreaker)
/turf/simulated/wall/attackby(obj/item/weapon/W as obj, mob/user as mob)
+19
View File
@@ -18,6 +18,7 @@ var/list/holder_mob_icon_cache = list()
var/last_loc_specific//This stores specific extra information about the location, pocket, hand, worn on head, etc. Only relevant to mobs
/obj/item/weapon/holder/New()
tag = rand(0,9999)
if (!item_state)
item_state = icon_state
@@ -91,6 +92,8 @@ var/list/holder_mob_icon_cache = list()
//Releases all mobs inside the holder, then deletes it.
//is_unsafe_container should be checked before calling this
//This function releases mobs into wherever the holder currently is. Its not safe to call from a lot of places
//Use release_to_floor for a simple, safe release
/obj/item/weapon/holder/proc/release_mob()
for(var/mob/M in contents)
var/atom/movable/mob_container
@@ -99,6 +102,7 @@ var/list/holder_mob_icon_cache = list()
M.reset_view()
M.Released()
contained = null
var/mob/L = get_holding_mob()
if (L)
@@ -107,6 +111,21 @@ var/list/holder_mob_icon_cache = list()
qdel(src)
//Similar to above function, but will not deposit things in any container, only directly on a turf.
//Can be called safely anywhere. Notably on holders held or worn on a mob
/obj/item/weapon/holder/proc/release_to_floor()
var/turf/T = get_turf(src)
var/mob/L = get_holding_mob()
if (L)
L.drop_from_inventory(src)
for(var/mob/M in contents)
M.forceMove(T) //if the holder was placed into a disposal, this should place the animal in the disposal
M.reset_view()
M.Released()
qdel(src)
/obj/item/weapon/holder/attackby(obj/item/weapon/W as obj, mob/user as mob)
for(var/mob/M in src.contents)
M.attackby(W,user)
@@ -35,6 +35,7 @@
mob_push_flags = ALLMOBS
hunger_enabled = 0
var/list/construct_spells = list()
var/can_repair = 0
/mob/living/simple_animal/construct/cultify()
return
@@ -58,16 +59,19 @@
/mob/living/simple_animal/construct/attack_generic(var/mob/user)
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if(istype(user, /mob/living/simple_animal/construct/builder))
if(getBruteLoss() > 0)
adjustBruteLoss(-5)
user.visible_message("<span class='notice'>\The [user] mends some of \the [src]'s wounds.</span>")
else
if (health < maxHealth)
user << "<span class='notice'>Healing \the [src] any further is beyond your abilities.</span>"
if(istype(user, /mob/living/simple_animal/construct))
var/mob/living/simple_animal/construct/C = user
if (C.can_repair)
if(getBruteLoss() > 0)
adjustBruteLoss(-5)
adjustFireLoss(-5)
user.visible_message("<span class='notice'>\The [user] mends some of \the [src]'s wounds.</span>")
else
user << "<span class='notice'>\The [src] is undamaged.</span>"
return
if (health < maxHealth)
user << "<span class='notice'>Healing \the [src] any further is beyond your abilities.</span>"
else
user << "<span class='notice'>\The [src] is undamaged.</span>"
return
return ..()
/mob/living/simple_animal/construct/examine(mob/user)
@@ -188,6 +192,7 @@
speed = 0
environment_smash = 1
attack_sound = 'sound/weapons/rapidslice.ogg'
can_repair = 1
construct_spells = list(/spell/aoe_turf/conjure/construct/lesser,
/spell/aoe_turf/conjure/wall,
/spell/aoe_turf/conjure/floor,
@@ -242,13 +247,19 @@
environment_smash = 1
see_in_dark = 7
attack_sound = 'sound/weapons/pierce.ogg'
can_repair = 1
construct_spells = list(
/spell/targeted/harvest,
/spell/aoe_turf/knock/harvester,
/spell/rune_write
/spell/rune_write,
/spell/aoe_turf/conjure/construct/lesser,
/spell/aoe_turf/conjure/wall,
/spell/aoe_turf/conjure/floor,
/spell/aoe_turf/conjure/soulstone,
/spell/aoe_turf/conjure/pylon,
/spell/aoe_turf/conjure/forcewall/lesser
)
//Harvesters are endgame stuff, no harm giving them construct spells
////////////////Glow//////////////////
/mob/living/simple_animal/construct/proc/add_glow()
+26
View File
@@ -153,3 +153,29 @@
//----------------------------
/obj/effect/projectile/pulse_bullet/muzzle
icon_state = "muzzle_pulse"
//----------------------------
// Demonic Beam
//----------------------------
/obj/effect/projectile/cult/tracer
icon_state = "cult"
/obj/effect/projectile/cult/muzzle
icon_state = "muzzle_cult"
/obj/effect/projectile/cult/impact
icon_state = "impact_cult"
//----------------------------
// Empowered Demonic Beam
//----------------------------
/obj/effect/projectile/cult/heavy/tracer
icon_state = "hcult"
/obj/effect/projectile/cult/heavy/muzzle
icon_state = "muzzle_hcult"
/obj/effect/projectile/cult/heavy/impact
icon_state = "impact_hcult"
@@ -259,3 +259,39 @@
var/mob/living/M = A
M.apply_effect(1, INCINERATE, 0)
..()
//Beams of magical veil energy fired by empowered pylons. Some inbuilt armor penetration cuz magic.
//Ablative armor is still overwhelmingly useful
//These beams are very weak but rapid firing, ~twice per second.
/obj/item/projectile/beam/cult
name = "energy bolt"
//For projectiles name is only shown in onhit messages, so its more of a layman's description
//of what the projectile looks like
damage = 4 //Very weak
armor_penetration = 10
accuracy = 4 //Guided by magic, unlikely to miss
var/mob/living/ignore
muzzle_type = /obj/effect/projectile/cult/muzzle
tracer_type = /obj/effect/projectile/cult/tracer
impact_type = /obj/effect/projectile/cult/impact
/obj/item/projectile/beam/cult/attack_mob(var/mob/living/target_mob, var/distance, var/miss_modifier=0)
//Harmlessly passes through cultists and constructs
if (target_mob == ignore)
return 0
if (iscult(target_mob))
return 0
return ..()
/obj/item/projectile/beam/cult/heavy
name = "glowing energy bolt"
damage = 12 //Stronger and better armor penetration, though still much weaker than a typical laser
armor_penetration = 15
muzzle_type = /obj/effect/projectile/cult/heavy/muzzle
tracer_type = /obj/effect/projectile/cult/heavy/tracer
impact_type = /obj/effect/projectile/cult/heavy/impact
+38
View File
@@ -0,0 +1,38 @@
################################
# Example Changelog File
#
# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
#
# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
# When it is, any changes listed below will disappear.
#
# Valid Prefixes:
# bugfix
# wip (For works in progress)
# tweak
# soundadd
# sounddel
# rscadd (general adding of nice things)
# rscdel (general deleting of nice things)
# imageadd
# imagedel
# maptweak
# spellcheck (typo fixes)
# experiment
#################################
# Your name.
author: Nanako
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
delete-after: True
# Any changes you've made. See valid prefix list above.
# INDENT WITH TWO SPACES. NOT TABS. SPACES.
# SCREW THIS UP AND IT WON'T WORK.
# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
changes:
- bugfix: "Fixed several issues with construct wallsmashing, and made it less spammy."
- rscadd: "Cult Pylons can now be upgraded into arcane defensive turrets, by sacrificing a small creature. They are weak, but accurate, rapid, and absorb lasers."
- imageadd: "Improved pylon graphics."
Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.