Merge branch 'master' into protean-rework

This commit is contained in:
BlackMajor
2023-02-23 14:31:09 +13:00
310 changed files with 144992 additions and 152112 deletions

View File

@@ -0,0 +1,5 @@
/proc/coalesce(...)
for (var/arg in args)
if (arg)
return arg
return null

View File

@@ -0,0 +1,95 @@
/datum/component/gargoyle
var/energy = 100
var/transformed = FALSE
var/paused = FALSE
var/paused_loc
var/cooldown
var/mob/living/carbon/human/gargoyle //easy reference
var/obj/structure/gargoyle/statue //another easy ref
/datum/component/gargoyle/Initialize()
if (!ishuman(parent))
return COMPONENT_INCOMPATIBLE
gargoyle = parent
gargoyle.verbs += /mob/living/carbon/human/proc/gargoyle_transformation
gargoyle.verbs += /mob/living/carbon/human/proc/gargoyle_pause
gargoyle.verbs += /mob/living/carbon/human/proc/gargoyle_checkenergy
START_PROCESSING(SSprocessing, src)
/datum/component/gargoyle/process()
if (!gargoyle)
return
if (paused && gargoyle.loc != paused_loc)
unpause()
if (energy > 0)
if (!transformed && !paused)
energy = max(0,energy-0.05)
else if (!transformed && isturf(gargoyle.loc))
gargoyle.gargoyle_transformation()
if (transformed)
if (!statue)
transformed = FALSE
statue.damage(-0.5)
energy = min(energy+0.3, 100)
/datum/component/gargoyle/proc/unpause()
if (!paused || transformed)
paused = FALSE
paused_loc = null
UnregisterSignal(gargoyle, COMSIG_ATOM_ENTERING)
return
if (gargoyle?.loc != paused_loc)
paused = FALSE
paused_loc = null
energy = max(energy - 5, 0)
if (energy == 0)
gargoyle.gargoyle_transformation()
UnregisterSignal(gargoyle, COMSIG_ATOM_ENTERING)
//verbs or action buttons...?
/mob/living/carbon/human/proc/gargoyle_transformation()
set name = "Gargoyle - Petrification"
set category = "Abilities"
set desc = "Turn yourself into (or back from) being a gargoyle."
if (stat == DEAD)
return
var/datum/component/gargoyle/comp = GetComponent(/datum/component/gargoyle)
if (comp)
if (comp.energy <= 0 && isturf(loc))
to_chat(src, "<span class='danger'>You suddenly turn into a statue as you run out of energy!</span>")
else if (comp.cooldown > world.time)
var/time_to_wait = (comp.cooldown - world.time) / (1 SECONDS)
to_chat(src, "<span class='warning'>You can't transform just yet again! Wait for another [round(time_to_wait,0.1)] seconds!</span>")
return
if (istype(loc, /obj/structure/gargoyle))
var/obj/structure/gargoyle/statue = loc
qdel(statue)
else if (isturf(loc))
new /obj/structure/gargoyle(loc, src)
/mob/living/carbon/human/proc/gargoyle_pause()
set name = "Gargoyle - Pause"
set category = "Abilities"
set desc = "Pause your energy while standing still, so you don't use up any more, though you will lose a small amount upon moving again."
if (stat)
return
var/datum/component/gargoyle/comp = GetComponent(/datum/component/gargoyle)
if (comp && !comp.transformed && !comp.paused)
comp.paused = TRUE
comp.paused_loc = loc
comp.RegisterSignal(src, COMSIG_ATOM_ENTERING, /datum/component/gargoyle/proc/unpause)
to_chat(src, "<span class='notice'>You start conserving your energy.</span>")
/mob/living/carbon/human/proc/gargoyle_checkenergy()
set name = "Gargoyle - Check Energy"
set category = "Abilities"
set desc = "Check how much energy you have remaining as a gargoyle."
var/datum/component/gargoyle/comp = GetComponent(/datum/component/gargoyle)
if (comp)
to_chat(src, "<span class='notice'>You have [round(comp.energy,0.01)] energy remaining. It is currently [comp.paused ? "stable" : (comp.transformed ? "increasing" : "decreasing")].</span>")

View File

@@ -0,0 +1,299 @@
// Props
/obj/structure/prop/desert_rock
icon = 'modular_chomp/icons/obj/desert_planet/desert_rocks.dmi'
desc = "Sandy and smooth from erosion."
density = TRUE
anchored = TRUE
/obj/structure/prop/desert_rock/rock
name = "desert rock"
/obj/structure/prop/desert_rock/rock/attack_hand(mob/living/user)
if(user.is_incorporeal())
return
to_chat(user, "You push on the [src].")
var/movedir = user.dir
if(do_after(user, 3 SECONDS, src))
step(src, movedir)
/obj/structure/prop/desert_rock/rock/New()
..()
icon_state = "desert_rock[rand(0,6)]"
/obj/structure/prop/desert_rock/pebble
name = "sandy pebble"
density = FALSE
/obj/structure/prop/desert_rock/pebble/Crossed(atom/movable/AM as mob|obj)
if(AM.is_incorporeal())
return
if(istype(AM, /mob/living))
var/mob/living/M = AM
if(M.m_intent == "run" && prob(5))
M.Weaken(2)
to_chat(M, "You trip over the [src]!")
/obj/structure/prop/desert_rock/pebble/New()
..()
icon_state = "desert_pebble[rand(0,6)]"
/obj/structure/prop/desert_rock/anthill
name = "ant hill"
desc = "See how many ants you can spot."
icon = 'modular_chomp/icons/obj/desert_planet/desert_plants.dmi'
icon_state = "anthill0"
/obj/structure/prop/desert_rock/anthill/New()
..()
icon_state = "anthill[rand(0,2)]"
/obj/structure/prop/desert_planet64x64
name = "large rock"
desc = "Sandy and smooth from erosion."
icon = 'modular_chomp/icons/obj/desert_planet/desert_props_64x64.dmi'
density = TRUE
anchored = TRUE
can_buckle = FALSE
/obj/structure/prop/desert_planet64x64/lrock
icon_state = "lrock"
/obj/structure/prop/desert_planet64x64/lrock1
icon_state = "lrock1"
/obj/structure/prop/desert_planet64x64/lrock2
icon_state = "lrock2"
/obj/structure/prop/desert_planet64x64/lrock3
icon_state = "lrock3"
/obj/structure/prop/desert_planet64x64/lrock4
icon_state = "lrock4"
/obj/structure/prop/desert_planet64x64/lribs
name = "ribs"
desc = "Bleached white by baking sunlight."
icon_state = "lribs"
/obj/structure/prop/desert_planet64x64/lribs1
name = "ribs"
desc = "Bleached white by baking sunlight."
icon_state = "lribs1"
/obj/structure/prop/desert_planet64x64/lskull
name = "skull"
desc = "Bleached white by baking sunlight."
icon_state = "lskull"
/obj/structure/prop/desert_planet64x64/lbone
name = "bone"
desc = "Bleached white by baking sunlight."
icon_state = "lbone"
/obj/structure/prop/desert_planet64x64/palmuria
name = "palm"
desc = "Stout and bushy."
icon_state = "palmuria"
/obj/structure/prop/desert_planet64x64/palmuria1
name = "palm"
desc = "Stout and bushy."
icon_state = "palmuria1"
/obj/structure/prop/desert_planet160x160
name = "desert large boulder"
desc = "Sandy and smooth from erosion."
icon = 'modular_chomp/icons/obj/desert_planet/desert_planet_160x160.dmi'
density = TRUE
anchored = TRUE
can_buckle = FALSE
/obj/structure/prop/desert_planet160x160/largeboulder
icon_state = "large_boulder"
/obj/structure/prop/desert_planet160x160/tallboulder
icon_state = "tall_boulder"
/obj/structure/prop/desert_planet160x160/boulder
icon_state = "boulder"
/obj/structure/prop/desert_planet160x160/lcactus
name = "cactus"
desc = "Large and prickly."
icon_state = "lcactus"
/obj/structure/prop/desert_planet160x160/lcactus1
name = "cactus"
desc = "Large and prickly."
icon_state = "lcactus1"
/obj/structure/prop/desert_planet160x160/lcactus2
name = "cactus"
desc = "Large and prickly."
icon_state = "lcactus2"
/obj/structure/prop/desert_planet160x160/lcactus3
name = "cactus"
desc = "Large and prickly."
icon_state = "lcactus3"
// Flora
/obj/structure/flora/desert_planet
name = "desert plant"
desc = "Probably a succulent."
icon = 'modular_chomp/icons/obj/desert_planet/desert_plants.dmi'
/obj/structure/flora/desert_planet/potted_plant
name = "potted plant"
desc = "Colloquially known as a pot plant."
icon_state = "potplant0"
/obj/structure/flora/desert_planet/potted_plant/New()
..()
icon_state = "potplant[rand(0,2)]"
/obj/structure/flora/desert_planet/thicket
name = "thicket"
desc = "Weedy growths."
icon_state = "thicket0"
/obj/structure/flora/desert_planet/thicket/New()
..()
icon_state = "thicket[rand(0,6)]"
/obj/structure/flora/desert_planet/shrub
name = "shrub"
desc = "Dense and weedy."
icon_state = "shrub0"
/obj/structure/flora/desert_planet/shrub/New()
..()
icon_state = "shrub[rand(0,5)]"
/obj/structure/flora/desert_planet/bush
name = "bush"
desc = "Denser and weedier."
icon_state = "bush0"
/obj/structure/flora/desert_planet/bush/New()
..()
icon_state = "bush[rand(0,5)]"
/obj/structure/flora/desert_planet/barrelcacti
name = "barrel cacti"
desc = "Small, adorable, and begging for a hug."
icon_state = "barrelcacti0"
/obj/structure/flora/desert_planet/barrelcacti/New()
..()
icon_state = "barrelcacti[rand(0,3)]"
/obj/structure/flora/desert_planet/palmy
name = "yucca bush"
desc = "Probably not actually a yucca."
icon_state = "palmy0"
/obj/structure/flora/desert_planet/palmy/New()
..()
icon_state = "palmy[rand(0,2)]"
/obj/structure/flora/desert_planet/shrubber
name = "thorny bush"
desc = "Makes for great fur accessories."
icon_state = "shrubber0"
/obj/structure/flora/desert_planet/shrubber/New()
..()
icon_state = "shrubber[rand(0,2)]"
/obj/structure/flora/desert_planet/lbarrelcacti
name = "barrel cactus"
desc = "Absolutely begging for pets."
icon_state = "lbarrelcacti0"
/obj/structure/flora/desert_planet/lbarrelcacti/New()
..()
icon_state = "lbarrelcacti[rand(0,2)]"
// Trees
/obj/structure/flora/tree/desert_planet
name = "palm tree"
desc = "Tall palm tree, makes for a good shade."
icon = 'modular_chomp/icons/obj/desert_planet/desert_planet_160x160.dmi'
density = FALSE
anchored = TRUE
can_buckle = FALSE
product = /obj/item/stack/material/log
product_amount = 50
health = 2000
max_health = 2000
//var/fruit
/obj/structure/flora/tree/desert_planet/palmtreeb
icon_state = "palmtreeb"
base_state = "palmr" // Necessary for stumps to work.
/obj/structure/flora/tree/desert_planet/palmtreeb1
icon_state = "palmtreeb1"
base_state = "palml"
/obj/structure/flora/tree/desert_planet/palmtree
icon_state = "palmtree"
base_state = "palmr"
/obj/structure/flora/tree/desert_planet/palmtree1
icon_state = "palmtree1"
base_state = "palml"
/obj/structure/flora/tree/desert_planet/mpalmtreeb
icon_state = "mpalmtreeb"
base_state = "palmr"
/obj/structure/flora/tree/desert_planet/mpalmtreeb1
icon_state = "mpalmtreeb1"
base_state = "palml"
/obj/structure/flora/tree/desert_planet/mpalmtree
icon_state = "mpalmtree"
base_state = "palml"
/obj/structure/flora/tree/desert_planet/mpalmtree1
icon_state = "mpalmtree1"
base_state = "palmr"
/obj/structure/flora/tree/desert_planet/spalmtree
icon_state = "spalmtree"
base_state = "palmls"
/obj/structure/flora/tree/desert_planet/spalmtree1
icon_state = "spalmtree1"
base_state = "palmrs"
/obj/structure/flora/tree/desert_planet/spalmtree3
icon_state = "spalmtree3"
base_state = "palmls"
/obj/structure/flora/tree/desert_planet/spalmtree4
icon_state = "spalmtree4"
base_state = "palmrs"
/obj/structure/flora/tree/desert_planet/desert_tree
name = "barren tree"
desc = "Completely barren."
icon_state = "desert_tree"
base_state = "desert"
/obj/structure/flora/tree/desert_planet/desert_tree1
name = "gnarled tree"
desc = "Twisted but living."
icon_state = "desert_tree1"
base_state = "desert"
/obj/structure/flora/tree/desert_planet/desert_tree3
name = "hardy tree"
desc = "Thriving despite the conditions."
icon_state = "desert_tree3"
base_state = "desert"
product_amount = 100
health = 4000
max_health = 4000

View File

@@ -0,0 +1,169 @@
/obj/structure/gargoyle
name = "statue"
desc = "A very lifelike carving."
density = TRUE
anchored = TRUE
var/mob/living/carbon/human/gargoyle
var/initial_sleep
var/initial_blind
var/initial_is_shifted
var/initial_lying
var/initial_lying_prev
var/wagging
var/flapping
var/obj_integrity = 100
var/original_int = 100
var/max_integrity = 100
var/stored_examine
/obj/structure/gargoyle/Initialize(mapload, var/mob/living/carbon/human/H)
. = ..()
if (isspace(loc) || isopenspace(loc))
anchored = FALSE
if (!istype(H) || !isturf(H.loc))
return
var/datum/component/gargoyle/comp = H.GetComponent(/datum/component/gargoyle)
if (comp)
comp.cooldown = world.time + (15 SECONDS)
comp.statue = src
comp.transformed = TRUE
comp.paused = FALSE
gargoyle = H
max_integrity = H.getMaxHealth() + 100
obj_integrity = H.health + 100
original_int = obj_integrity
name = "statue of [H.name]"
desc = "A very lifelike statue."
stored_examine = H.examine()
description_fluff = H.get_description_fluff()
if (H.buckled)
H.buckled.unbuckle_mob(H, TRUE)
icon = H.icon
copy_overlays(H)
color = list(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(0,0,0))
initial_sleep = H.sleeping
initial_blind = H.eye_blind
initial_is_shifted = H.is_shifted
transform = H.transform
layer = H.layer
pixel_x = H.pixel_x
pixel_y = H.pixel_y
dir = H.dir
initial_lying = H.lying
initial_lying_prev = H.lying_prev
H.sdisabilities |= MUTE
if (H.appearance_flags & PIXEL_SCALE)
appearance_flags |= PIXEL_SCALE
wagging = H.wagging
H.transforming = TRUE
flapping = H.flapping
H.toggle_tail(FALSE, FALSE)
H.toggle_wing(FALSE, FALSE)
H.visible_message("<span class='warning'>[H]'s skin rapidly turns to stone!</span>", "<span class='warning'>Your skin abruptly hardens as you turn to stone!</span>")
H.forceMove(src)
H.SetBlinded(0)
H.SetSleeping(0)
H.status_flags |= GODMODE
H.updatehealth()
H.canmove = 0
/obj/structure/gargoyle/Destroy()
unpetrify()
. = ..()
/obj/structure/gargoyle/examine_icon()
var/icon/examine_icon = ..()
examine_icon.MapColors(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(0,0,0))
return examine_icon
/obj/structure/gargoyle/get_description_info()
if (gargoyle)
if (isspace(loc) || isopenspace(loc))
return
return "It can be [anchored ? "un" : ""]anchored with a wrench."
/obj/structure/gargoyle/examine(mob/user)
. = ..()
if (gargoyle && stored_examine)
. += "The statue seems to have a bit more to them..."
. += stored_examine
return
/obj/structure/gargoyle/proc/unpetrify()
if (!gargoyle)
return
var/datum/component/gargoyle/comp = gargoyle.GetComponent(/datum/component/gargoyle)
if (comp)
comp.cooldown = world.time + (15 SECONDS)
comp.statue = null
comp.transformed = FALSE
gargoyle.forceMove(loc)
gargoyle.transform = transform
gargoyle.pixel_x = pixel_x
gargoyle.pixel_y = pixel_y
gargoyle.is_shifted = initial_is_shifted
gargoyle.dir = dir
gargoyle.lying = initial_lying
gargoyle.lying_prev = initial_lying_prev
gargoyle.toggle_tail(wagging, FALSE)
gargoyle.toggle_wing(flapping, FALSE)
gargoyle.sdisabilities &= ~MUTE //why is there no ADD_TRAIT etc here that's actually ussssed
gargoyle.status_flags &= ~GODMODE
gargoyle.SetBlinded(initial_blind)
gargoyle.SetSleeping(initial_sleep)
gargoyle.transforming = FALSE
gargoyle.canmove = 1
gargoyle.update_canmove()
var/hurtmessage = ""
if (obj_integrity < original_int)
var/f = (original_int - obj_integrity) / 10
for (var/x in 1 to 10)
gargoyle.adjustBruteLoss(f)
hurtmessage = " <b>You feel your body take the damage that was dealt while being stone!</b>"
gargoyle.updatehealth()
alpha = 0
gargoyle.visible_message("<span class='warning'>[gargoyle]'s skin rapidly softens, returning them to normal!</span>", "<span class='warning'>Your skin softens, freeing your movement once more![hurtmessage]</span>")
/obj/structure/gargoyle/return_air()
return return_air_for_internal_lifeform()
/obj/structure/gargoyle/return_air_for_internal_lifeform(var/mob/living/lifeform)
var/air_type = /datum/gas_mixture/belly_air
if(istype(lifeform))
air_type = lifeform.get_perfect_belly_air_type()
var/air = new air_type(1000)
return air
/obj/structure/gargoyle/proc/damage(var/damage)
obj_integrity = min(obj_integrity-damage, max_integrity)
if(obj_integrity <= 0)
qdel(src)
/obj/structure/gargoyle/take_damage(var/damage)
damage(damage)
/obj/structure/gargoyle/attack_generic(var/mob/user, var/damage, var/attack_message = "hits")
user.do_attack_animation(src)
visible_message("<span class='danger'>[user] [attack_message] the [src]!</span>")
damage(damage)
/obj/structure/gargoyle/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
if(W.is_wrench())
if (isspace(loc) || isopenspace(loc))
to_chat(user, "<span class='warning'>You can't anchor that here!</span>")
anchored = FALSE
return ..()
playsound(src, W.usesound, 50, 1)
if (do_after(user, (2 SECONDS) * W.toolspeed, target = src))
to_chat("<span class='notice'>You [anchored ? "un" : ""]anchor the [src].</span>")
anchored = !anchored
else if (!(W.flags & NOBLUDGEON))
user.setClickCooldown(user.get_attack_speed(W))
if(W.damtype == BRUTE || W.damtype == BURN)
user.do_attack_animation(src)
playsound(src, W.hitsound, 50, 1)
damage(W.force)
else
return ..()

View File

@@ -1,136 +1,257 @@
/* Testing
// Parent turf.
/turf/simulated/floor/outdoors/desert_planet
name = "sand"
desc = "Salty and gritty."
icon = 'modular_chomp/icons/turf/desert_tiles.dmi'
icon_edge = 'modular_chomp/icons/turf/outdoors_edge.dmi'
can_dig = FALSE
/turf/simulated/floor/outdoors/desert_planet/sand
name = "sand"
desc = "Sandy, taste salty and gritty."
icon = 'modular_chomp/icons/turf/desert_planet.dmi'
desc = "Salty and gritty."
icon_state = "sand0"
edge_blending_priority = 2
turf_layers = list(/turf/simulated/floor/outdoors/rocks)
initial_flooring = /decl/flooring/sand
can_dig = false
*/
initial_flooring = /decl/flooring/desert_planet/sand
/turf/simulated/floor/outdoors/desert_planet/sand
name = "sand"
desc = "Salty and gritty."
icon = 'modular_chomp/icons/turf/desert_planet.dmi'
icon_state = "sand"
edge_blending_priority = 3
turf_layers = list(/turf/simulated/floor/outdoors/desert_planet/sand)
// Necessary to get the edges to generate correctly since we use a random-ish icon_state. Inelegant to hard code, but this is a one-off case.
/turf/simulated/floor/outdoors/desert_planet/sand/get_edge_icon_state()
return "sand"
/* Testing
/decl/flooring/outdoors/sand
name = "sand"
desc = "Salty and gritty."
icon = 'modular_chomp/icons/turf/desert_planet.dmi'
icon_base = "sand"
footstep_sounds = list("human" = list(
'sound/effects/footstep/asteroid1.ogg',
'sound/effects/footstep/asteroid2.ogg',
'sound/effects/footstep/asteroid3.ogg',
'sound/effects/footstep/asteroid4.ogg',
'sound/effects/footstep/asteroid5.ogg',
'sound/effects/footstep/MedDirt1.ogg',
'sound/effects/footstep/MedDirt2.ogg',
'sound/effects/footstep/MedDirt3.ogg',
'sound/effects/footstep/MedDirt4.ogg'))
/turf/simulated/floor/outdoors/desert_planet/sand/Initialize(mapload)
. = ..()
icon_state = "sand[rand(0,2)]"
/turf/simulated/floor/outdoors/sand/Initialize(mapload)
var/possiblesands = list(
"ironsand1" = 50,
"ironsand2" = 1,
"ironsand3" = 1,
"ironsand4" = 1,
"ironsand5" = 1,
"ironsand6" = 1,
"ironsand7" = 1,
"ironsand8" = 1,
"ironsand9" = 1,
"ironsand10" = 1,
"ironsand11" = 1,
"ironsand12" = 1,
"ironsand13" = 1,
"ironsand14" = 1,
"ironsand15" = 1
)
flooring_override = pickweight(possiblesands)
return ..()
/turf/simulated/floor/water/hotspring
name = "Hotsprings"
desc = "A natural hotspring connecting to an aquifer. It seems the facility was built ontop of it."
edge_blending_priority = -2
movement_cost = 8
depth = 2
water_state = "water_shallow"
outdoors = FALSE
/turf/simulated/floor/water/hotspring/Entered(atom/movable/AM, atom/oldloc)
if(istype(AM, /mob/living))
var/mob/living/L = AM
L.update_water()
if(L.check_submerged() <= 0)
return
if(!istype(oldloc, /turf/simulated/floor/water/hotspring))
to_chat(L, "<span class='warning'>You feel an overwhelming wave of warmth from entering \the [src]!</span>")
AM.water_act(5)
..()
*/
/turf/simulated/floor/outdoors/desert_planet/sand/attackby(var/obj/item/W, var/mob/user)
if(istype(W, /obj/item/weapon/shovel))
to_chat(user, "<span class='notice'>You begin to remove \the [src] with your [W].</span>")
if(do_after(user, 4 SECONDS * W.toolspeed))
to_chat(user, "<span class='notice'>\The [src] has been dug up, and now lies in a pile nearby.</span>")
icon_state = "sand_dug"
new /obj/item/weapon/ore/glass (src)
else
to_chat(user, "<span class='notice'>You decide to not finish removing \the [src].</span>")
else
..()
/turf/simulated/floor/outdoors/desert_planet/deep_sand
name = "sand"
desc = "Salty and gritty."
icon = 'modular_chomp/icons/turf/desert_planet.dmi'
icon_state = "deep_sand"
edge_blending_priority = 2
turf_layers = list(/turf/simulated/floor/outdoors/desert_planet/sand)
desc = "Really gets everywhere."
icon_state = "deep_sand0"
edge_blending_priority = 1
movement_cost = 3
initial_flooring = /decl/flooring/desert_planet/deep_sand
/turf/simulated/floor/outdoors/desert_planet/deep_sand/Initialize(mapload)
. = ..()
icon_state = "deep_sand[rand(0,2)]"
/turf/simulated/floor/outdoors/desert_planet/grass
name = "grass"
desc = "Lively green grass, soft to walk on."
icon = 'modular_chomp/icons/turf/desert_planet.dmi'
icon_state = "grass"
edge_blending_priority = 6
turf_layers = list(/turf/simulated/floor/outdoors/desert_planet/sand)
edge_blending_priority = 5
initial_flooring = /decl/flooring/desert_planet/grass
/turf/simulated/floor/outdoors/desert_planet/deep_grass
name = "dense grass"
desc = "Dense patch of grass, seems like a soft spot to lay on."
icon = 'modular_chomp/icons/turf/desert_planet.dmi'
icon_state = "deep_grass"
edge_blending_priority = 7
turf_layers = list(/turf/simulated/floor/outdoors/desert_planet/sand)
edge_blending_priority = 6
initial_flooring = /decl/flooring/desert_planet/deep_grass
/turf/simulated/floor/outdoors/desert_planet/gravel
name = "gravel"
desc = "Mix of dirt and sand, it crumbles in your hand."
icon = 'modular_chomp/icons/turf/desert_planet.dmi'
icon_state = "gravel"
edge_blending_priority = 5
turf_layers = list(/turf/simulated/floor/outdoors/desert_planet/sand)
edge_blending_priority = 3
initial_flooring = /decl/flooring/desert_planet/gravel
/turf/simulated/floor/outdoors/desert_planet/mud
name = "mud"
desc = "Squishy damp dirt, smells muddy."
icon = 'modular_chomp/icons/turf/desert_planet.dmi'
icon_state = "mud"
edge_blending_priority = 4
turf_layers = list(/turf/simulated/floor/outdoors/desert_planet/sand)
initial_flooring = /decl/flooring/desert_planet/mud
// At last we've come full circle, a floor which is actually a wall.
/turf/simulated/floor/outdoors/desert_planet/stonewall
name = "sandstone"
desc = "Rough sandstone."
icon_state = "stonewall"
density = TRUE
opacity = TRUE
edge_blending_priority = 7
initial_flooring = /decl/flooring/desert_planet/stonewall
turf_layers = list(/turf/simulated/floor/outdoors/rocks)
var/last_act = 0
// Stolen from mineral turf code.
/turf/simulated/floor/outdoors/desert_planet/stonewall/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(!user.IsAdvancedToolUser())
to_chat(user, "<span class='warning'>You don't have the dexterity to do this!</span>")
return
if(istype(W, /obj/item/weapon/pickaxe))
if(!istype(user.loc, /turf))
return
var/obj/item/weapon/pickaxe/P = W
if(last_act + P.digspeed > world.time)//prevents message spam
return
last_act = world.time
playsound(user, P.drill_sound, 20, 1)
to_chat(user, "<span class='notice'>You start [P.drill_verb].</span>")
if(do_after(user,P.digspeed))
to_chat(user, "<span class='notice'>You finish [P.drill_verb] \the [src].</span>")
new /obj/item/stack/material/sandstone(src)
density = FALSE
opacity = FALSE
demote() // Converts the turf to the next layer in turf_layers.
..()
/turf/simulated/floor/outdoors/desert_planet/sandrock
name = "sandstone tiles"
desc = "Tightly joined in a mesmerizing lattice."
icon_state = "sandrock"
density = TRUE
opacity = TRUE
initial_flooring = /decl/flooring/desert_planet/sandrock
// Declarations (for initial_flooring)
/decl/flooring/desert_planet // Yeah don't use this one, it's a parent just for setting icon.
name = "desert stuff"
desc = "If you see this, this turf is using the wrong decl."
icon = 'modular_chomp/icons/turf/desert_tiles.dmi'
icon_base = null
/decl/flooring/desert_planet/sand
name = "sand"
desc = "Salty and gritty."
icon_base = "sand"
has_base_range = 2
/decl/flooring/desert_planet/deep_sand
name = "sand"
desc = "Really gets everywhere."
icon_base = "deep_sand"
has_base_range = 2
/decl/flooring/desert_planet/grass
name = "grass"
desc = "Lively green grass, soft to walk on."
icon_base = "grass"
/decl/flooring/desert_planet/deep_grass
name = "dense grass"
desc = "Dense patch of grass, seems like a soft spot to lay on."
icon_base = "deep_grass"
/decl/flooring/desert_planet/gravel
name = "gravel"
desc = "Mix of dirt and sand, it crumbles in your hand."
icon_base = "gravel"
/decl/flooring/desert_planet/mud
name = "mud"
desc = "Squishy damp dirt, smells muddy."
icon_base = "mud"
/decl/flooring/desert_planet/stonewall
name = "sandstone"
desc = "Rough sandstone."
icon_base = "stonewall"
/decl/flooring/desert_planet/sandrock
name = "sandstone tiles"
desc = "Tightly joined in a mesmerizing lattice."
icon_base = "sandrock"
flags = TURF_HAS_EDGES | TURF_HAS_CORNERS
/*
/obj/effect/floor_decal/desert_planet/floor/sand0_edge
name = "sand0_edge"
icon = 'icons/turf/desert_planet.dmi'
icon_state = "sand0_edge"
/obj/effect/floor_decal/desert_planet/floor/gravel_edge
name = "gravel_edge"
icon = 'icons/turf/desert_planet.dmi'
icon_state = "gravel_edge"
/obj/effect/floor_decal/desert_planet/floor/mud_edge
name = "mud_edge"
icon = 'icons/turf/desert_planet.dmi'
icon_state = "mud_edge"
/obj/effect/floor_decal/desert_planet/floor/grass_edge
name = "grass_edge"
icon = 'icons/turf/desert_planet.dmi'
icon_state = "grass_edge"
/obj/effect/floor_decal/desert_planet/floor/deep_grass_edge
name = "deep_grass_edge"
icon = 'icons/turf/desert_planet.dmi'
icon_state = "deep_grass_edge"
*/
/* #No idea how water tiles work
/turf/simulated/floor/outdoors/desert_planet/water
name = "water"
desc = "Clear cool water, looks potable."
icon = 'modular_chomp/icons/turf/desert_planet.dmi'
icon = 'icons/turf/desert_planet.dmi'
icon_state = "water"
edge_blending_priority = 8
var/water_state = "water_shallow"
var/under_state = "sand"
can_be_plated = FALSE
outdoors = OUTDOORS_YES
flags = TURF_ACID_IMMUNE
layer = WATER_FLOOR_LAYER
can_dirty = FALSE // It's water
var/depth = 1 // Higher numbers indicates deeper water.
var/reagent_type = "water"
edge_blending_priority = 2
turf_layers = list(/turf/simulated/floor/outdoors/desert_planet/sand)
/turf/simulated/floor/outdoors/desert_planet/deep_water
name = "deep water"
desc = "deep enough you can't see the bottom of it."
icon = 'modular_chomp/icons/turf/desert_planet.dmi'
icon = 'icons/turf/desert_planet.dmi'
icon_state = "deep_water"
edge_blending_priority = 9
var/water_state = "water_shallow"
var/under_state = "sand"
can_be_plated = FALSE
outdoors = OUTDOORS_YES
flags = TURF_ACID_IMMUNE
layer = WATER_FLOOR_LAYER
can_dirty = FALSE // It's water
var/depth = 2 // Higher numbers indicates deeper water.
var/reagent_type = "water"
edge_blending_priority = 4
turf_layers = list(/turf/simulated/floor/outdoors/desert_planet/sand)
//I want this for the water tiles
/turf/simulated/floor/water
name = "shallow water"
desc = "A body of water. It seems shallow enough to walk through, if needed."
icon = 'icons/turf/outdoors.dmi'
icon_state = "seashallow" // So it shows up in the map editor as water.
var/water_state = "water_shallow"
var/under_state = "rock"
edge_blending_priority = -1
movement_cost = 4
can_be_plated = FALSE
outdoors = OUTDOORS_YES
flags = TURF_ACID_IMMUNE
layer = WATER_FLOOR_LAYER
can_dirty = FALSE // It's water
var/depth = 1 // Higher numbers indicates deeper water.
var/reagent_type = "water"
// var/datum/looping_sound/water/soundloop CHOMPEdit: Removing soundloop for now.
*/

View File

@@ -0,0 +1,25 @@
/obj/item/weapon/deadringer/process()
if(activated)
if (ismob(src.loc))
var/mob/living/carbon/human/H = src.loc
watchowner = H
if(H.getBruteLoss() > bruteloss_prev || H.getFireLoss() > fireloss_prev)
deathprevent()
activated = 0
if(watchowner.isSynthetic())
to_chat(watchowner, "<font color='blue'>You fade into nothingness! [src]'s screen blinks, being unable to copy your synthetic body!</font>")
else
to_chat(watchowner, "<font color='blue'>You fade into nothingness, leaving behind a fake body!</font>")
icon_state = "deadringer_cd"
timer = 5
return
if(timer > 0)
timer--
if(timer == 2)
reveal()
if(corpse)
new /obj/effect/effect/smoke/chem(corpse.loc)
qdel(corpse)
if(timer == 0)
icon_state = "deadringer"
return

View File

@@ -0,0 +1,6 @@
/obj/item/clothing/shoes/apply_blood(var/image/standing)
if(blood_DNA && blood_sprite_state && ishuman(loc))
var/mob/living/carbon/human/H = loc
var/image/bloodsies = image(icon = H.digitigrade ? 'modular_chomp/icons/mob/human_races/masks/blood_digitigrade.dmi' : H.species.get_blood_mask(H), icon_state = blood_sprite_state)
bloodsies.color = blood_color
standing.add_overlay(bloodsies)

View File

@@ -0,0 +1,71 @@
/obj/item/weapon/rig/ch/precursor
name = "xenotech hardsuit control module"
desc = "A purple hardsuit gleaming with energy and alien metals."
suit_type = "precursor hardsuit"
icon = 'modular_chomp/icons/obj/rig_modules_ch.dmi'
icon_state = "precursor_rig"
armor = list(melee = 50, bullet = 50, laser = 70, energy = 70, bomb = 60, bio = 100, rad = 80)
var/block_chance = 15
slowdown = 0
chest_type = /obj/item/clothing/suit/space/rig/ch/precursor
helm_type = /obj/item/clothing/head/helmet/space/rig/ch/precursor
glove_type = /obj/item/clothing/gloves/gauntlets/rig/ch/precursor
boot_type = /obj/item/clothing/shoes/magboots/rig/ch/precursor
req_access = list()
req_one_access = list()
/obj/item/clothing/suit/space/rig/ch/precursor
name = "protective vest"
icon = 'icons/obj/clothing/spacesuits_ch.dmi'
desc = "Light weight but oddly protective plating."
var/block_chance = 15
/obj/item/clothing/head/helmet/space/rig/ch/precursor
name = "helmet"
icon = 'icons/obj/clothing/hats_ch.dmi'
desc = "A protective dome for your head."
var/block_chance = 15
/obj/item/clothing/gloves/gauntlets/rig/ch/precursor
name = "gloves"
icon = 'icons/obj/clothing/gloves_ch.dmi'
desc = "Gloves created with alien tech"
var/block_chance = 15
/obj/item/clothing/shoes/magboots/rig/ch/precursor
name = "boots"
icon = 'icons/obj/clothing/shoes_ch.dmi'
desc = "A pair of grabby boots"
var/block_chance = 15
/obj/item/weapon/rig/ch/precursor/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
if(prob(block_chance))
user.visible_message("<span class='danger'>\The [src] completely absorbs [attack_text]!</span>")
return TRUE
return FALSE
/obj/item/clothing/suit/space/rig/ch/precursor/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
if(prob(block_chance))
user.visible_message("<span class='danger'>\The [src] completely absorbs [attack_text]!</span>")
return TRUE
return FALSE
/obj/item/clothing/head/helmet/space/rig/ch/precursor/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
if(prob(block_chance))
user.visible_message("<span class='danger'>\The [src] completely absorbs [attack_text]!</span>")
return TRUE
return FALSE
/obj/item/clothing/gloves/gauntlets/rig/ch/precursor/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
if(prob(block_chance))
user.visible_message("<span class='danger'>\The [src] completely absorbs [attack_text]!</span>")
return TRUE
return FALSE
/obj/item/clothing/shoes/magboots/rig/ch/precursor/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
if(prob(block_chance))
user.visible_message("<span class='danger'>\The [src] completely absorbs [attack_text]!</span>")
return TRUE
return FALSE

View File

@@ -1,3 +1,4 @@
/obj/item/weapon/rig
var/protean = 0
var/obj/item/weapon/storage/backpack/rig_storage
var/obj/item/weapon/storage/backpack/rig_storage
permeability_coefficient = 0 //Protect the squishies, after all this shit should be waterproof.

View File

@@ -3,3 +3,6 @@
/datum/trait/positive/linguist
custom_only = FALSE
/datum/trait/positive/toxin_gut
custom_only = FALSE

View File

@@ -0,0 +1,52 @@
//This hivebots are meant to be high threats, and a tad more fitting of the alien places they tend to be in. Aka mini-bosses.
/mob/living/simple_mob/mechanical/hivebot/precusor
name = "Precursor Hivebot"
icon = 'modular_chomp/icons/mob/hivebot.dmi'
icon_state = "precursorhive"
icon_living = "precursorhive"
attacktext = list("prodded")
maxHealth = 5 LASERS_TO_KILL // 150 health
health = 5 LASERS_TO_KILL
movement_cooldown = 4
melee_damage_lower = 15
melee_damage_upper = 15
var/obj/item/shield_projector/shields = null
/mob/living/simple_mob/mechanical/hivebot/precusor/Initialize(mapload)
shields = new /obj/item/shield_projector/rectangle/automatic/hivebot_drone(src)
return ..()
/mob/living/simple_mob/mechanical/hivebot/precusor/machinegun
projectiletype = /obj/item/projectile/bullet/hivebot
base_attack_cooldown = 0 // Extremly rapid fire with rather weak bullets.
/mob/living/simple_mob/mechanical/hivebot/precusor/laser
projectiletype = /obj/item/projectile/beam/precursor
projectile_dispersion = 5
projectile_accuracy = -30
/mob/living/simple_mob/mechanical/hivebot/precusor/lobber
projectiletype = /obj/item/projectile/arc/blue_energy/precusor
/obj/item/projectile/arc/blue_energy/precusor
name = "energy missile"
icon_state = "force_missile"
armor_penetration = 10
damage = 50 // Mimics the precusor laser damage and armor peircing with a tad more damage because of the lobbying style.
damage_type = BURN
color = "#A020F0"
/obj/item/shield_projector/rectangle/automatic/hivebot_drone
shield_health = 100
max_shield_health = 100
shield_regen_delay = 5 SECONDS
shield_regen_amount = 20
size_x = 3
size_y = 3
color = "#A020F0"
high_color = "#A020F0"
low_color = "#A020F0"

View File

@@ -0,0 +1,5 @@
//Giving the tank hivebot class a new look,
/mob/living/simple_mob/mechanical/hivebot/tank
icon = 'modular_chomp/icons/mob/hivebot.dmi'
icon_state = "blue"
icon_living = "blue"

View File

@@ -1,8 +1,15 @@
/mob/living/simple_mob/mechanical/mecha/combat/gygax
movement_cooldown = 1 //Because normal Gygaxes are tougher then ths boss version with 0 speed
/mob/living/simple_mob/mechanical/mecha/combat/gygax/dark/advanced
movement_cooldown = 0 //Because AADG needs all the help it can get.
/mob/living/simple_mob/mechanical/mecha/combat/gygax/aerostat
desc = "A Vir System Authority automated combat mech with an aged apperance."
ai_holder_type = /datum/ai_holder/simple_mob/intentional/adv_dark_gygax
say_list = /datum/say_list/gygax_aerostat
/datum/say_list/gygax_aerostat
speak = list("ALERT.","Hostile-ile-ile entities dee-twhoooo-wected.","Threat parameterszzzz- szzet.","Bring sub-sub-sub-systems uuuup to combat alert alpha-a-a.")
emote_see = list("beeps menacingly","whirrs threateningly","scans its immediate vicinity")

View File

@@ -0,0 +1,47 @@
/mob/living/simple_mob/animal/passive/dog/stray
name = "dog"
desc = "The most standard dog you have ever seen, it even smells like one."
tt_desc = "Canis lupus familiaris"
//faction = "mexico" //They are from Mexico. //Amusing but this prompts aggression from crew-aligned mobs.
icon = 'modular_chomp/icons/turf/desert_tiles.dmi'
icon_state = "dog"
item_state = "dog"
icon_living = "dog"
icon_rest = "dog"
icon_dead = "dog"
health = 50
maxHealth = 50
mob_size = MOB_SMALL
pass_flags = PASSTABLE
can_pull_size = ITEMSIZE_TINY
can_pull_mobs = MOB_PULL_NONE
layer = MOB_LAYER
density = 1
movement_cooldown = 0.75 //roughly a bit faster than a person
response_help = "pets"
response_disarm = "rolls aside"
response_harm = "stomps"
melee_damage_lower = 5
melee_damage_upper = 7
attacktext = list("nips", "bumps", "scratches")
vore_taste = "wet dog"
min_oxy = 16 //Require atleast 16kPA oxygen
minbodytemp = 223 //Below -50 Degrees Celcius
maxbodytemp = 523 //Above 80 Degrees Celcius
heat_damage_per_tick = 3
cold_damage_per_tick = 3
meat_amount = 7
holder_type = /obj/item/weapon/holder/armadillo
ai_holder_type = /datum/ai_holder/simple_mob/armadillo
speak_emote = list("rumbles", "chirr?", "churr")
say_list_type = /datum/say_list/armadillo

View File

@@ -20,6 +20,13 @@
adminbus_trash = TRUE //You know what, sure whatever. It's not like anyone's gonna be taking this bird on unga trips to be their gamer backpack, which kinda was the main reason for the trash eater restrictions in the first place anyway.
faction = "neutral"
say_list_type = /datum/say_list/swoopie
var/static/list/crew_creatures = list( /mob/living/simple_mob/protean_blob,
/mob/living/simple_mob/slime/promethean)
/mob/living/simple_mob/vore/aggressive/corrupthound/swoopie/IIsAlly(mob/living/L)
. = ..()
if(!.) // Outside the faction and not in friends, are they crew
return L?.type in crew_creatures
/mob/living/simple_mob/vore/aggressive/corrupthound/swoopie/init_vore()
if(!voremob_loaded)

View File

@@ -4,10 +4,11 @@
// preferentially take digitigrade value from owner if available, THEN DNA.
// this allows limbs to be set properly when being printed in the bioprinter without an owner
// this also allows the preview mannequin to update properly because customisation topic calls don't call a DNA check
var/check_digi = istype(src,/obj/item/organ/external/leg) || istype(src,/obj/item/organ/external/foot)
if(owner)
digitigrade = owner.digitigrade && (istype(src,/obj/item/organ/external/leg) || istype(src,/obj/item/organ/external/foot))
digitigrade = check_digi && owner.digitigrade
else if(dna)
digitigrade = dna.digitigrade && (istype(src,/obj/item/organ/external/leg) || istype(src,/obj/item/organ/external/foot))
digitigrade = check_digi && dna.digitigrade
var/gender = "m"
var/skip_forced_icon = skip_robo_icon || (digi_prosthetic && digitigrade)
@@ -56,13 +57,15 @@
if((!istype(src,/obj/item/organ/external/head) && !(force_icon && !skip_forced_icon)) || (model && owner && owner.synth_markings))
for(var/M in markings)
var/datum/sprite_accessory/marking/mark_style = markings[M]["datum"]
var/isdigitype = istype(mark_style,/datum/sprite_accessory/marking/digi)
if(!(digitigrade ^ isdigitype)) //Equivalent to XNOR; this code will only run if either both digitigrade and isdigitype are true, or if both are false.
var/icon/mark_s = new/icon("icon" = mark_style.icon, "icon_state" = "[mark_style.icon_state]-[organ_tag]")
mark_s.Blend(markings[M]["color"], mark_style.color_blend_mode) // VOREStation edit
add_overlay(mark_s) //So when it's not on your body, it has icons
mob_icon.Blend(mark_s, ICON_OVERLAY) //So when it's on your body, it has icons
icon_cache_key += "[M][markings[M]["color"]]"
var/isdigitype = mark_style.digitigrade_acceptance
if(check_digi)
if (!(isdigitype & (digitigrade ? MARKING_DIGITIGRADE_ONLY : MARKING_NONDIGI_ONLY))) //checks flags based on which digitigrade type the limb is
continue
var/icon/mark_s = new/icon("icon" = digitigrade ? mark_style.digitigrade_icon : mark_style.icon, "icon_state" = "[mark_style.icon_state]-[organ_tag]")
mark_s.Blend(markings[M]["color"], mark_style.color_blend_mode) // VOREStation edit
add_overlay(mark_s) //So when it's not on your body, it has icons
mob_icon.Blend(mark_s, ICON_OVERLAY) //So when it's on your body, it has icons
icon_cache_key += "[M][markings[M]["color"]]"
if(body_hair && islist(h_col) && h_col.len >= 3)
var/cache_key = "[body_hair]-[icon_name]-[h_col[1]][h_col[2]][h_col[3]]"
if(!limb_icon_cache[cache_key])

View File

@@ -0,0 +1,358 @@
// This is an attempt to make space POI's which load/unload on demand, so we can have 50 overmap POI's without
// 50 z-levels (which may lead to OOM). No idea what forces I'm working with, so let's see how poorly this goes.
// Map templates for this system are stored in space_pois.dm.
GLOBAL_VAR_INIT(dynamic_sector_master, null)
// Also adjust find_z_levels() if you adjust increase dynamic levels, that part is hard-coded so you don't gloss over world.increment_max_z().
#define MAX_DYNAMIC_LEVELS 3
#define MAX_DYNAMIC_POI_DIMENSIONS 200 // Keep this an even number if using even world.maxx/maxy. This value MUST
// a large enough static border to fit OM ships. A 30x30 ship means max dimensions must be 60 less than the z-level max
// to keep a 30 turf border on each side of the load/unload area.
// The "master" object, which creates + stores + registers the actual z-levels used for dynamic POI's. Handles overmap
// sanity checks, + procs, should not be directly accessible by players. Do not use in maps. Only 1 should exist currently.
/obj/effect/overmap/visitable/dynamic
name = "DO NOT USE IN MAPS"
known = FALSE
scannable = FALSE
invisibility = 101
in_space = TRUE
scanner_desc = "You should not see this."
var/generated_z = FALSE
var/base_area = /area/space
// Initialized to match max dynamic levels.
map_z = list(null,null,null)
// Overmap poi's CURRENTLY USING a z-level. Dynamic POI's get referenced here when loading in and removed when unloaded.
// Length must match map_z length or bad things may happen.
var/list/active_pois[MAX_DYNAMIC_LEVELS]
// Reference list of shuttle landmarks for each z-level. Used to register/unregister shuttle landmarks in POI's.
var/list/shuttle_landmarks[MAX_DYNAMIC_LEVELS]
var/list/all_children = list()
// This handles generating and assigning z-levels. Overriding this proc means we don't need a hacky Initialize() override.
// This means extra_z_levels won't do anything, which is intentional.
/obj/effect/overmap/visitable/dynamic/find_z_levels()
if(!generated_z && (GLOB.dynamic_sector_master == src)) // Ensure this only runs once per round.
for(var/i = 1; i <= 3; i++) // Hard-coding limit because this is dangerous.
world.increment_max_z()
map_z[i] = world.maxz
// Spawn shuttle_landmarks near the lower x border, aligned with the POI spawning turf. These move during POI generation.
var/turf/T = locate(10, round(world.maxy/2), map_z[i])
if(istype(T))
var/list/spawn_directions = list() // Stores a landmark for each direction.
for(var/direction in list("FORE", "PORT", "AFT", "STARBOARD"))
var/obj/effect/shuttle_landmark/om_poi/S = new(T, "Subspace sector [i] - [direction]", "dynamic_sector_[i] - [direction]")
spawn_directions[direction] = S
shuttle_landmarks[i] = spawn_directions
generated_z = TRUE
/obj/effect/overmap/visitable/dynamic/Initialize()
if(!GLOB.dynamic_sector_master)
GLOB.dynamic_sector_master = src
. = ..()
if(ispath(base_area))
var/area/spehss = locate(base_area)
if(!istype(spehss))
CRASH("Dynamic POI generation couldn't locate area [base_area].")
base_area = spehss
create_children()
// Create POI objects for each overmap POI template, link to parent. Initialize() of children handles turf assignment
/obj/effect/overmap/visitable/dynamic/proc/create_children()
for(var/datum/map_template/dynamic_overmap/poi as anything in subtypesof(/datum/map_template/dynamic_overmap))
if(!initial(poi.mappath) || !initial(poi.name) || (initial(poi.block_size) > MAX_DYNAMIC_POI_DIMENSIONS)) // Exclude templates without an actual map or are too big (or are not included in the mapping subsystem map_templates)
continue
var/obj/effect/overmap/visitable/dynamic/poi/P = new()
P.my_template = SSmapping.map_templates[initial(poi.name)] // Link to the stored map datums.
P.parent = src
all_children.Add(P)
P.seed_overmap()
// Randomly unload a child POI, if possible. Returns the index of the recovered level if successful, 0 if not.
// Should only be called if active_pois[] is full.
/obj/effect/overmap/visitable/dynamic/proc/cull_child(mob/user)
var/random_index = rand(1,MAX_DYNAMIC_LEVELS)
var/obj/effect/overmap/visitable/dynamic/poi/P
// User selection. Remains random if user cancels.
if(user)
P = tgui_input_list(user, "Would you like to choose which link to sever?", "Sever link", active_pois)
if(P && istype(P) && src.is_empty(P.my_index))
random_index = P.my_index
P.destroy_poi(user)
active_pois[random_index] = null
return random_index
else
return 0
if(is_empty(random_index)) // If this z-level is empty, destroy the poi
P = active_pois[random_index]
P.destroy_poi(user)
active_pois[random_index] = null // Should be set in destroy_poi but this lets us use the z-level again if anything goes horribly wrong.
return random_index
for(var/i = 1, i <= MAX_DYNAMIC_LEVELS, i++) // Level was not empty, check remaining levels
if(i == random_index)
continue // Don't run this one again.
if(is_empty(i))
P = active_pois[i]
P.destroy_poi(user)
active_pois[i] = null
return i
return 0
/obj/effect/overmap/visitable/dynamic/proc/is_empty(var/index, var/mob/observer)
if(!LAZYLEN(map_z))
log_and_message_admins("CANARY: [src] tried to check is_empty, but map_z is `[map_z || "null"]`")
return TRUE
if(!index)
index = 1
testing("Checking if sector at [map_z[index]] has no players.")
for(var/mob/M in global.player_list)
if(M != observer && (M.z == map_z[index]))
testing("There are people on it.")
return FALSE
return TRUE
// You generally shouldn't destroy these.
/obj/effect/overmap/visitable/dynamic/Destroy()
for(var/child in all_children)
qdel(child)
return ..()
// These are the player-viewable/interactible POI's which tell the parent how to use its z-levels. Spawned by the parent.
/obj/effect/overmap/visitable/dynamic/poi
name = "bluespace static"
unknown_name = "bluespace static"
unknown_state = "poi"
known = FALSE
scannable = TRUE
invisibility = 0
in_space = TRUE
map_z = list(null) // Override parent value
active_pois = null
var/obj/effect/overmap/visitable/dynamic/parent // The object which created us.
var/datum/map_template/dynamic_overmap/my_template
var/last_scanned = 0 // Timer to prevent spamming POI loading/unloading since that's probably exploitable.
var/loaded = FALSE
var/my_index = 0 // Tracks which z-level we're using in the parent. Corresponds to index in parent's active_pois[]
/obj/effect/overmap/visitable/dynamic/poi/Initialize()
if(!global.using_map.use_overmap)
return INITIALIZE_HINT_QDEL
// Normally Initialize() would do this but I need it to call after Initialize(), therefore new proc.
/obj/effect/overmap/visitable/dynamic/poi/proc/seed_overmap()
start_x = start_x || rand(OVERMAP_EDGE, global.using_map.overmap_size - OVERMAP_EDGE)
start_y = start_y || rand(OVERMAP_EDGE, global.using_map.overmap_size - OVERMAP_EDGE)
forceMove(locate(start_x, start_y, global.using_map.overmap_z))
for(var/obj/effect/overmap/visitable/dynamic/poi/P in loc.contents) // If we've spawned on another poi, we'll try again once.
if(P == src)
continue
start_x = start_x || rand(OVERMAP_EDGE, global.using_map.overmap_size - OVERMAP_EDGE)
start_y = start_y || rand(OVERMAP_EDGE, global.using_map.overmap_size - OVERMAP_EDGE)
forceMove(locate(start_x, start_y, global.using_map.overmap_z))
break
if(!docking_codes)
docking_codes = "[ascii2text(rand(65,90))][ascii2text(rand(65,90))][ascii2text(rand(65,90))][ascii2text(rand(65,90))]"
if(known)
plane = PLANE_LIGHTING_ABOVE
for(var/obj/machinery/computer/ship/helm/H in global.machines)
H.get_known_sectors()
else
real_appearance = image(icon, src, my_template.poi_icon)
real_appearance.override = TRUE
name = unknown_name
icon_state = unknown_state
color = null
desc = "Scan this to find out more information."
// Grab scanner info from map template, allow the user to load/unload POI's.
/obj/effect/overmap/visitable/dynamic/poi/get_scan_data(user)
scanner_desc = my_template.scanner_desc
if(!known)
known = TRUE
name = my_template.name
icon_state = my_template.poi_icon
color = my_template.poi_color
desc = initial(desc)
if(loaded)
var/confirm = alert(user, "Sever bluespace link? This location will become permanently inaccessible.", "Are you sure?", "No", "Yes")
if(confirm == "Yes")
if(is_empty(1)) // Dynamic POI's should only ever have 1 entry in map_z
destroy_poi(user) // Delete POI from dynamic z-level
else
to_chat(user, "Unable to sever link. Location likely contains living realspace entities.")
else
var/confirm = alert(user, "Transient subspace anomaly detected. Tether object to realspace?", "Stabilize anomaly?", "Yes", "No")
if(confirm == "Yes")
create_poi(user) // Load POI to dynamic z-level
return ..()
// Loads POI template into a dynamic z-level
/obj/effect/overmap/visitable/dynamic/poi/proc/create_poi(mob/user)
if(!parent) // Ideally this should never happen.
log_and_message_admins("Dynamic overmap POI attempted to generate without a parent z-level.")
qdel(src)
return
if(!my_template) // Also shouldn't happen.
log_and_message_admins("Dynamic overmap POI attempted to generate without a map template.")
qdel(src)
return
if(loaded) // These may only be created once.
return
if(last_scanned + 10 SECONDS > world.time)
to_chat(user, "\[REDACTED\] matrix is still recharging!")
return
last_scanned = world.time
for(var/i = 1, i <= MAX_DYNAMIC_LEVELS, i++)
if(!parent.active_pois[i]) // We found an unused z-level
my_index = i
parent.active_pois[i] = src
map_z[1] = parent.map_z[i]
map_sectors["[parent.map_z[i]]"] = src // Pass ownership of z-level to child, probably hacky and terribad, also mandatory for using forceMove() on shuttle landmarks
break // Terminate loop
if(!my_index) // No z-levels available
var/confirm = alert(user, "\[REDACTED\] matrix at capacity; a bluespace link must be permanently severed to stabilize this anomaly. Continue?", "Are you sure?", "No", "Yes")
if(confirm == "Yes")
my_index = parent.cull_child(user)
if(my_index)
parent.active_pois[my_index] = src
map_z[1] = parent.map_z[my_index]
map_sectors["[parent.map_z[my_index]]"] = src
else // Something went wrong, ideally due to all relevant z-levels containing players.
to_chat(user, "Unable to sever any bluespace link. All links likely contain living realspace entities.")
return
else
return
var/turf/T = locate(round(world.maxx/2), round(world.maxy/2), map_z[1]) // Find center turf, or near center for even-dimension maps.
if(!istype(T))
log_debug("Dynamic overmap POI found [T] instead of a valid turf.")
return
// Move the shuttle landmarks.
var/list/landmark_directions = parent.shuttle_landmarks[my_index] // Each shuttle_landmarks entry is an associative list.
var/obj/effect/shuttle_landmark/om_poi/S = landmark_directions["FORE"]
S.forceMove(locate(T.x, min(world.maxy, T.y + round(src.my_template.block_size/2) + rand(10,20)), T.z)) // Above
add_landmark(S) // This lets overmap shuttles find our newly assigned z-level.
S = landmark_directions["AFT"]
S.forceMove(locate(T.x, max(1, T.y - round(src.my_template.block_size/2) - rand(10,20)), T.z))// Below
add_landmark(S)
S = landmark_directions["PORT"]
S.forceMove(locate(max(1, T.x - round(src.my_template.block_size/2) - rand(10,20)), T.y, T.z)) // Left
add_landmark(S)
S = landmark_directions["STARBOARD"]
S.forceMove(locate(min(world.maxx, T.x + round(src.my_template.block_size/2) + rand(10,20)), T.y, T.z)) // Right
add_landmark(S)
my_template.load(T, centered=TRUE)
loaded = TRUE
my_template.update_lighting(T)
to_chat(user, "Stabilization tether successfully created.")
if(my_template.active_icon)
icon_state = my_template.active_icon
/obj/effect/overmap/visitable/dynamic/poi/proc/destroy_poi(mob/user)
if(!loaded) // Ideally this should never happen.
log_debug("Dynamic overmap POI tried to unload itself but is not loaded.")
return
if(!parent) // Also shouldn't happen.
log_and_message_admins("Dynamic overmap POI attempted to unload without a parent z-level.")
loaded = FALSE // Always make sure loaded = FALSE before using qdel(src) in this proc to prevent an infinite loop in Destroy().
qdel(src)
return
if(!((my_index >= 1) && (my_index <= MAX_DYNAMIC_LEVELS))) // Make sure my_index is sane
log_debug("Dynamic overmap POI attempted to unload with an invalid index.")
loaded = FALSE
qdel(src)
return
map_sectors["[parent.map_z[my_index]]"] = parent // Pass ownership back to parent.
parent.active_pois[my_index] = null
if(!LAZYLEN(map_z)) // If this is 0, how did we get this far?
log_and_message_admins("Dynamic overmap POI attempted to unload without a linked z-level.")
loaded = FALSE
qdel(src)
return
to_chat(user, "Destabilization initiated...")
log_debug("Dynamic overmap POI unloading initiated...")
// Some math to return a block of block_size turfs (+ 1 to each dimension to account for even-size maps lacking a true center to safely do math with). Basically, start from center turf and subtract half of block_size for bottom left corner, add for top right corner.
var/list/turfs_to_reset = block(locate(round(world.maxx/2 - my_template.block_size/2 - 1), round(world.maxy/2 - my_template.block_size/2 - 1), map_z[1]), locate(round(world.maxx/2 + my_template.block_size/2 + 1), round(world.maxy/2 + my_template.block_size/2 + 1), map_z[1]))
var/deleted_atoms = 0
if(turfs_to_reset.len)
var/area/A = parent.base_area
if(ispath(A))
A = locate(A)
if(!istype(A))
CRASH("Dynamic POI unloading couldn't locate area [A], unload aborted.")
for(var/turf/T in turfs_to_reset)
for(var/atom/movable/AM in T)
if(istype(AM, /mob/observer))
continue
++deleted_atoms
qdel(AM)
ChangeArea(T, A)
T = T.ChangeTurf(/turf/space)
loaded = FALSE
map_z = null
icon_state = "ring_destroyed"
log_debug("Dynamic POI unload complete, [deleted_atoms] atoms destroyed.")
to_chat(user, "Subspace pocket collapse successful.")
qdel(src)
/obj/effect/overmap/visitable/dynamic/poi/Destroy()
if(loaded)
if(is_empty()) // If we're deleted while loaded but the z-level is occupied, relinquish ownership instead.
destroy_poi()
else
if(parent && (parent.active_pois.len >= my_index) && (parent.map_z.len >= my_index) && (my_index > 0)) // Unless vars are turbofucked.
map_sectors["[parent.map_z[my_index]]"] = parent
parent.active_pois[my_index] = null
if(parent)
parent.all_children.Remove(src)
return ..()
// This assigns map_sectors which we don't want for this subtype since we have other procs to handle it.
/obj/effect/overmap/visitable/dynamic/poi/register_z_levels()
return
// Make sure we reassign our z_level to the parent if one exists and somehow this gets called.
/obj/effect/overmap/visitable/dynamic/poi/unregister_z_levels()
if(parent && LAZYLEN(map_z))
map_sectors["[map_z[1]]"] = parent
map_z = null
return ..()
// Hahah recursion
/obj/effect/overmap/visitable/dynamic/poi/create_children()
return
/obj/effect/overmap/visitable/dynamic/poi/cull_child()
return
/obj/effect/shuttle_landmark/om_poi // Landmarks used in dynamic poi generation
flags = SLANDMARK_FLAG_AUTOSET
base_area = /area/space
base_turf = /turf/space
/obj/effect/shuttle_landmark/om_poi/Initialize(mapload, var/new_name, var/new_tag)
name = new_name
landmark_tag = new_tag
. = ..()
#undef MAX_DYNAMIC_LEVELS
#undef MAX_DYNAMIC_POI_DIMENSIONS

View File

@@ -0,0 +1,81 @@
/* List of player tips
Weighted to emphasize more important over less.area
Weights are not additive. You can have multiple prob(50) items.
prob(50) makes it half as likely to appear and so forth.
When editing the list, please try and keep similar probabilities near each other. High on top, low on bottom */
//argument determines if to pick a random tip or use a forced choice.
/datum/player_tips/proc/pick_tip(var/isSpecific)
var/choice = null
if(!(isSpecific == "none" || isSpecific == "general" || isSpecific == "gameplay" || isSpecific == "roleplay" || isSpecific == "lore" ))
choice = "none" //Making sure that wrong arguments still give tips.
if(isSpecific == "none")
choice = pick (
prob(50); "general",
prob(50); "gameplay",
prob(25); "roleplay",
prob(20); "lore"
)
else
choice = isSpecific
switch(choice)
if("general")
var/info = "The following is a general tip to playing on CHOMPStation! You can disable them using the periodic tips toggle in the Global tab of character setup! \n"
return pick(
prob(60); "[info] Got a question about gameplay, roleplay or the setting? Press F1 to Mentorhelp!",
prob(60); "[info] We have a wiki that is actively updated! Please check it out at https://wiki.chompstation13.net/index.php/Chomp_Station_Wiki for help!",
prob(60); "[info] Unsure about rules? Press F1 and ask our admins for clarification - they are happy to help.",
prob(30); "[info] Don't be afraid to approach your fellow players for advice! Learning things ICly can help build powerful bonds!",
prob(30); "[info] Need some guideance making a character or with roleplay concepts? Our discord's tutoring channel is happy to help!",
prob(30); "[info] Having difficulties getting started? Pressing F3 to speak and typing '; Hello! I'm a new hire. Could someone please give me a tour?' or as appropriate for your character is a good way to start! More help available at: https://wiki.chompstation13.net/index.php/The_Basics",
prob(30); "[info] Want to try out a new department? Consider joining as an intern when it's well-staffed. Our players enjoy teaching eager students. You can approach such roleplay as simply getting taught the local technologies, procedures - you don't need to be 'fresh out of school' to justify it!",
prob(30); "[info] Our discord is an excellent resource to stay up to date about changes and events! If wanting to separate your kink and real identities, Discord has a built in means to swap accounts within the client. It is OK to lurk!",
prob(5); "[info] Got another tip for the list? Please let us know on Discord in the feedback forums!"
)
if("gameplay")
var/info = "The following is a gameplay-focused tip to playing on CHOMPStation! You can disable them using the periodic tips toggle in the Global tab of character setup! \n"
return pick(
prob(50); "[info] To talk to your fellow coworkers, use ';'! You may append it by an exclamation mark, like ';!' to perform an audiable emote. ",
prob(50); "[info] Lost on the map? You can find In-Character help by speaking on the Common Radio. You can do this by pressing F3 and typing ' ; ' before your message. Your fellow co-workers will likely help. If OOC help is preferred, press F1 for mentorhelp. ",
prob(50); "[info] You may set your suit sensors by clicking on the icon in the bottom left corner, then right click the clothes that appear right above it. It is recommended to turn on suit sensors to 'TRACKING' before doing anything dangerous like mining, and to turn them off before digestion scenes as prey.",
prob(35); "[info] It is never a bad idea to visit the medbay if you get injured - small burns and cuts can get infected and become harder to treat! If there is no medical staff, bathrooms and the bar often has a NanoMed on the wall while a medical station can be found on the first deck - with ointments to disinfect cuts and burns, bandages to treat bruises and encourage healing.",
prob(25); "[info] Two control modes exist for SS13 - hotkey ON and hotkey OFF. You can swap between the two modes by pressing TAB. In hotkey mode, to chat you need to press T to say anything which creates a small talking bubble.",
prob(25); "[info] Do you want to shift your character around, for instance to appear as if leaning on the wall? Press CTRL + SHIFT + arrow keys to do so! Moving resets this.",
prob(25); "[info] Emergency Fire Doors seal breaches and keep active fires out. Please do not open them without good reason. SHIFT + CLICK them to get temperature and atmospheric pressure readings.",
prob(25); "[info] The kitchen's Oven can fit multiple ingredients in one slot if you pull the baking tray out first. This is required for most recipes, and the Grille and Deep Frier work the same way!",
prob(10); "[info] Not every hostile NPC you encounter while mining or exploring need to be defeated. Sometimes, it's better to avoid or run away from them.",
prob(1); "[info] Stay robust, my friends.",
prob(35); "[info] You can insert your I.D into your PDA. This frees up your belt from having to carry your PDA. Furthermore, by clicking and dragging the PDA to game screen, you can use it without holding it!",
prob(35); "[info] Your vore-bellies have multiple add-ons! Muffling is excellent to ensure your prey does not accidentally inform everyone about their predicament, and jam suit sensors is a great courtesy to avoid medical being worried about your prey!"
)
if("roleplay")
var/info = "The following is a roleplay-focused tip to playing on CHOMPStation! You can disable them using the periodic tips toggle in the Global tab of character setup! \n"
return pick(
prob(50); "[info] Having difficulty finding scenes? The number one tip that people should take for finding scenes is to be active! Generally speaking, people are more likely to interact with you if you are moving about and doing things. Don't be afraid to talk to people, you're less likely to be approached if you're sat alone at a table silently. People that are looking for scenes generally like to see how you type and RP before they'll start working towards a scene with you.",
prob(50); "[info] Please avoid a character that knows everything. Having only a small set of jobs you are capable of doing can help flesh out your character! It's OK for things to break and fail if nobody is around to fix it - you do not need to do others' jobs.",
prob(25); "[info] Embrace the limits of your character's skillsets! Seeking out other players to help you with a more challenging task might build friendships, or even lead to a scene!",
prob(25); "[info] Slowing down when meeting another player can help with finding roleplay! Your fellow player might be typing up a greeting or an emote, and if you run off you won't see it!",
prob(25); "[info] It is a good idea to wait a few moments after using mechanics like lick, hug or headpat on another player. They might be typing up a response or wish to reciprocate, and if you run away you might miss out!",
prob(25); "[info] Participating in an away mission and see something acting strange? Try emoting or talking to it before resorting to fighting. It may be a GM event!",
prob(15); "[info] We are a medium roleplay server. This does not neccessarily mean 'serious' roleplay, levity and light-hearted RP is more than welcome! Please do not ignore people just because it is unlikely you will be able to scene.",
prob(10); "[info] Sending faxes to central command, using the 'pray' verb or pressing F1 to ahelp are highly encouraged when exploring the gateway or overmap locations! Letting GMs know something fun is happening allows them to spice things up and make the world feel alive!",
prob(40); "[info] Just because you see something doesn't mean your character has to. A courtesy 'missing' of contraband or scene details can go a long way towards preserving everyone's fun!",
prob(25); "[info] It is always a good idea to communicate on your department's private channel (whose key you can learn by examining your headset) when responding to an emergency! This lets your coworkers know if they might be needed!",
prob(25); "[info] While following the SOP is not mandatory, and you are free to break it (albeit, with potential in-character consequences), departments like security and medical do well to be familiar with them! https://wiki.chompstation13.net/index.php/Standard_Operating_Procedure",
prob(25); "[info] Think a player is acting especially antagonistic? It might be better to Ahelp (with F1) rather than try to deal with it icly, staff can make sure it's all okay.",
prob(20); "[info] See a minor infraction as Security with a minimal time punishment? Consider using your ticket printer to give a non obtrusive punishment."
)
if("lore")
var/info = "The following is tip for understanding the lore of CHOMPStation! You can disable them using the periodic tips toggle in the Global tab of character setup! \n"
return pick(
prob(25); "[info] Our lore is somewhat in line with other servers. But not Virgo's. They wrote themselves out of the timeline, lol. The year is 2564 (current year+541).",
prob(75); "[info] You can find a short summary of our setting that everyone should know at https://wiki.chompstation13.net/index.php/Lore",
prob(50); "[info] You are currently working in the Vir system on the NLS Southern Cross telecommunications and traffic control station. https://wiki.chompstation13.net/index.php/Vir",
prob(50); "[info] The majority of employees live at the Northern Star asteroid colony orbiting a gas giant called Kara. It is also a central hub for visitors, logistics, and mining. This is the place the shuttle takes you at the end of the round. You may visit the mines via the exploration shuttles. https://wiki.chompstation13.net/index.php/NCS_Northern_Star",
prob(10); "[info] Thaler is a universal monopoly money. It is backed and supported by Sol Central and its allies. While ubiquitous in frontier worlds, it has an unfavourable exchange rate with most currencies used by well-settled regions, limiting immigration to places such as Earth. https://wiki.chompstation13.net/index.php/Lore"
)

View File

@@ -1,3 +1,19 @@
/datum/design/item/mechfab/rigsuit/phase
name = "hardsuit phase rifle"
desc = "A compact phase rifle for a hardsuit."
id = "rig_gun_phase"
req_tech = list(TECH_MATERIAL = 5, TECH_ENGINEERING = 4, TECH_MAGNET = 3, TECH_POWER = 4, TECH_COMBAT = 4)
materials = list(DEFAULT_WALL_MATERIAL = 2000, "glass" = 1250)
build_path = /obj/item/rig_module/mounted/phase
/datum/design/item/mechfab/rigsuit/defib
name = "hardsuit defib unit"
desc = "A rig mounted defib and jumper kit combo."
id = "rig_defib"
req_tech = list(TECH_BIO = 5, TECH_MAGNET = 2, TECH_POWER = 3)
materials = list(DEFAULT_WALL_MATERIAL = 6000, "glass" = 2000)
build_path = /obj/item/rig_module/device/defib
/datum/design/item/mecha/phoron_bore
name = "PB-23 \"Phobos\" Phoron Bore"
category = list("Exosuit Equipment")
@@ -111,18 +127,11 @@
time = 20
materials = list(DEFAULT_WALL_MATERIAL = 15000, MAT_PHORON = 2000, MAT_GOLD = 2000, MAT_VERDANTIUM = 500)
/datum/design/item/mechfab/rigsuit/phase
name = "hardsuit phase rifle"
desc = "A compact phase rifle for a hardsuit."
id = "rig_gun_phase"
req_tech = list(TECH_MATERIAL = 5, TECH_ENGINEERING = 4, TECH_MAGNET = 3, TECH_POWER = 4, TECH_COMBAT = 4)
materials = list(DEFAULT_WALL_MATERIAL = 2000, "glass" = 1250)
build_path = /obj/item/rig_module/mounted/phase
/datum/design/item/mechfab/rigsuit/defib
name = "hardsuit defib unit"
desc = "A rig mounted defib and jumper kit combo."
id = "rig_defib"
req_tech = list(TECH_BIO = 5, TECH_MAGNET = 2, TECH_POWER = 3)
materials = list(DEFAULT_WALL_MATERIAL = 6000, "glass" = 2000)
build_path = /obj/item/rig_module/device/defib
/datum/design/item/mechfab/rigsuit/precursor
name = "Xenotech Rig"
desc = "A rig made of alien tech and materials."
id = "rigmodule_precursor"
time = 30
req_tech = list(TECH_MATERIAL = 9, TECH_ENGINEERING = 6, TECH_PHORON = 5, TECH_MAGNET = 6, TECH_POWER = 6, TECH_ILLEGAL = 8, TECH_PRECURSOR = 3)
materials = list(MAT_PLASTEEL = 12000, MAT_GOLD = 5000, MAT_GRAPHITE = 8000, MAT_OSMIUM = 3000, MAT_PLASTIC = 6000, MAT_VERDANTIUM = 7500, MAT_MORPHIUM = 20000)
build_path = /obj/item/weapon/rig/ch/precursor

View File

@@ -6,9 +6,8 @@
// And optionally, this could be gated behind another preference, to prevent stunlock being abused.
if((mob_always_swap || (a_intent == I_HELP || src.restrained()) && (target.a_intent == I_HELP || target.restrained())) && target.canmove && target.handle_micro_bump_helping(src))
return
else if(!(target.a_intent == I_HELP || target.restrained()) && target.handle_micro_bump_other(src))
if(!(target.a_intent == I_HELP || target.restrained()))
if(src.step_mechanics_pref && target.step_mechanics_pref)
target.handle_micro_bump_other(src)
else
target.handle_micro_bump_other(src, 1)
return