Skip to content

Commit

Permalink
FOB Tents (cmss13-devs#3509)
Browse files Browse the repository at this point in the history
<!-- Write **BELOW** The Headers and **ABOVE** The comments else it may
not be viewable. -->

# About the pull request

<!-- Remove this text and explain what the purpose of your PR is.

Mention if you have tested your changes. If you changed a map, make sure
you used the mapmerge tool.
If this is an Issue Correction, you can type "Fixes Issue #169420" to
link the PR to the corresponding Issue number #169420.

Remember: something that is self-evident to you might not be to others.
Explain your rationale fully, even if you feel it goes without saying.
-->

Sprites stolen from thwomper and sammy, available NOW with game code!

Adds a few tents to be used in FOB building, mainly for organizational
purposes but also providing small gameplay benefits. At current the main
goal is to incentive usage to organize and liven up FOB, so the buffs
are rather small.

There are 4 tent types:
* The Command Tent is a 2x3 structure that comes bundled with an
overwatch console, a phone, and two (2) chairs.
* The Medical Tent is a 2x3 structure that comes with a NanoMED, 2
roller beds, and slightly buffs surgery (10% less time taken, and a very
token pain/failure chance improvement)
* The Requisitions Tent is a 4x3 structure that comes with a phone,
rack, desks, and a variant of the old APC vendor that can stock
materials and regular ammunition. The vendor starts empty, save for some
tables/racks/paperwork for organization purposes. It is only useable
with requisitions access.
* The Big Tent is a bigger tent for all your organizational needs: 3x3.
Get creative.

The tents also provide decent additional protection against cold
environements. Unfortunately, rain/snow will visually pour through it, i
can't do much about that.

The tents are extremely vulnerable to explosives and xeno claws. For
simplicity and technical reasons, they are currently NON REDEPLOYABLE
and NON REPLACEABLE. The tent destruction will destroy/disable linked
objects (console/vendor etc). Be mindful of where you place them.

**Mind that the tents may not work out for all LZ FOBs due to the
required space. I expect people will find ways to make it work anyway
but it might take a while.**

# Explain why it's good for the game

<!-- Please add a short description of why you think these changes would
benefit the game. If you can't justify it in words, it might not be
worth adding, and may discourage maintainers from reviewing or merging
your PR. This section is not strictly required for (non-controversial)
fix PRs or backend PRs. -->


# Testing Photographs and Procedure
<!-- Include any screenshots/videos/debugging steps of the modified code
functioning successfully, ideally including edge cases. -->
<details>
<summary>Screenshots & Videos</summary>

Put screenshots and videos here with an empty line between the
screenshots and the `<details>` tags.

I'm lazyyy i forgot and already closed the game... If you actually want
em bug me and i'll add em
</details>


# Changelog

<!-- If your PR modifies aspects of the game that can be concretely
observed by players or admins you should add a changelog. If your change
does NOT meet this description, remove this section. Be sure to properly
mark your PRs to prevent unnecessary GBP loss. Please note that
maintainers freely reserve the right to remove and add tags should they
deem it appropriate. You can attempt to finagle the system all you want,
but it's best to shoot for clear communication right off the bat. -->
<!-- If you add a name after the ':cl', that name will be used in the
changelog. You must add your CKEY after the CL if your GitHub name
doesn't match. Be sure to properly mark your PRs to prevent unnecessary
GBP loss. Maintainers freely reserve the right to remove and add tags
should they deem it appropriate. -->

:cl: Firartix , Thwomper and Sammy
add: Added four types of tents to liven up FOB. They provide cold
protection and benefits depending on their type. The tents spawn in
Requisitions roundstart near the mortar. They're vulnerable to
explosives and xenomorphs, and NON REPLACEABLE. Mind where you put them!
add: The Command tent comes equipped with an overwatch console and a
phone.
add: The Medical tent provides a small boost to surgery speed/pain
carried out inside it.
add: The Requisitions tent provides a restockable vendor, desk, and
furniture for organization.
add: The Big tent is just a big tent, and provides you a slate to
organize the way you want.
/:cl:

<!-- Both :cl:'s are required for the changelog to work! -->

---------

Co-authored-by: harryob <me@harryob.live>
  • Loading branch information
fira and harryob authored Jun 9, 2023
1 parent a7cc2d2 commit d5b1193
Show file tree
Hide file tree
Showing 50 changed files with 1,017 additions and 19 deletions.
5 changes: 5 additions & 0 deletions code/__DEFINES/dcs/signals/atom/mob/living/signals_human.dm
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,8 @@

//from /mob/living/carbon/human/Life()
#define COMSIG_HUMAN_SET_UNDEFIBBABLE "human_set_undefibbable"

/// from /datum/surgery_step/proc/attempt_step()
#define COMSIG_HUMAN_SURGERY_APPLY_MODIFIERS "human_surgery_apply_modifiers"
/// From /mob/living/carbon/human/proc/get_flags_cold_protection()
#define COMSIG_HUMAN_COLD_PROTECTION_APPLY_MODIFIERS "human_cold_protection_apply_modifiers"
2 changes: 2 additions & 0 deletions code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,5 @@
#define COMSIG_MOB_STAT_SET_ALIVE "mob_stat_set_alive"
//from /mob/living/set_stat()
#define COMSIG_MOB_STAT_SET_DEAD "mob_stat_set_dead"

#define COMSIG_GHOST_MOVED "ghost_moved"
2 changes: 2 additions & 0 deletions code/__DEFINES/dcs/signals/atom/signals_obj.dm
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,5 @@

/// from /obj/structure/transmitter/update_icon()
#define COMSIG_TRANSMITTER_UPDATE_ICON "transmitter_update_icon"

#define COMSIG_TENT_COLLAPSING "tent_collapsing"
1 change: 1 addition & 0 deletions code/__DEFINES/dcs/signals/atom/signals_turf.dm
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#define COMSIG_TURF_ENTER "turf_enter"
#define COMPONENT_TURF_ALLOW_MOVEMENT (1<<0)
#define COMPONENT_TURF_DENY_MOVEMENT (1<<1)
#define COMSIG_TURF_ENTERED "turf_entered"

/// Called when a bullet hits a turf
#define COMSIG_TURF_BULLET_ACT "turf_bullet_act"
Expand Down
12 changes: 9 additions & 3 deletions code/__DEFINES/layers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,15 @@
#define FACEHUGGER_LAYER 4.13
/// For WEATHER
#define WEATHER_LAYER 4.14
#define INTERIOR_WALL_SOUTH_LAYER 5.2
#define INTERIOR_DOOR_LAYER 5.21

//#define FLY_LAYER 5

#define RIPPLE_LAYER 5.1
#define INTERIOR_DOOR_INSIDE_LAYER 5.19
#define INTERIOR_WALL_SOUTH_LAYER 5.2
#define INTERIOR_DOOR_LAYER 5.21
#define INTERIOR_WALLMOUNT_LAYER 5.3
#define INTERIOR_ROOF_LAYER 5.5

#define ABOVE_FLY_LAYER 6

Expand Down Expand Up @@ -174,9 +177,12 @@
/// NEVER HAVE ANYTHING BELOW THIS PLANE ADJUST IF YOU NEED MORE SPACE
#define LOWEST_EVER_PLANE -200

/// Floor plane, self explanatory. Used for Ambient Occlusion filter
#define FLOOR_PLANE -7
/// Game Plane, where most of the game objects reside
#define GAME_PLANE -6
#define ABOVE_GAME_PLANE -5
/// Roof plane, disappearing when entering buildings
#define ROOF_PLANE -4

/// To keep from conflicts with SEE_BLACKNESS internals
#define BLACKNESS_PLANE 0
Expand Down
7 changes: 7 additions & 0 deletions code/_onclick/hud/rendering/plane_master.dm
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@
blend_mode = BLEND_OVERLAY
render_relay_plane = RENDER_PLANE_NON_GAME

/// Plane master handling display of building roofs. They're meant to become invisible when inside a building.
/atom/movable/screen/plane_master/roof
name = "roof plane master"
plane = ROOF_PLANE
appearance_flags = PLANE_MASTER
blend_mode = BLEND_OVERLAY

/**
* Plane master handling byond internal blackness
* vars are set as to replicate behavior when rendering to other planes
Expand Down
7 changes: 4 additions & 3 deletions code/datums/map_config.dm
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@
var/traits = null
var/space_empty_levels = 1
var/list/environment_traits = list()
var/armor_style = "default"
var/list/gamemodes = list()

var/camouflage_type = "classic"

var/allow_custom_shuttles = TRUE
var/shuttles = list()

Expand Down Expand Up @@ -303,8 +304,8 @@

allow_custom_shuttles = json["allow_custom_shuttles"] != FALSE

if(json["armor"])
armor_style = json["armor"]
if(json["camouflage"])
camouflage_type = json["camouflage"]

if(json["survivor_message"])
survivor_message = json["survivor_message"]
Expand Down
4 changes: 4 additions & 0 deletions code/game/machinery/computer/computer.dm
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
unslashable = TRUE
var/circuit = null //The path to the circuit board type. If circuit==null, the computer can't be disassembled.
var/processing = FALSE //Set to true if computer needs to do /process()
var/deconstructible = TRUE
var/exproof = 0

/obj/structure/machinery/computer/Initialize()
Expand Down Expand Up @@ -96,6 +97,9 @@

/obj/structure/machinery/computer/attackby(obj/item/I, mob/user)
if(HAS_TRAIT(I, TRAIT_TOOL_SCREWDRIVER) && circuit)
if(!deconstructible)
to_chat(user, SPAN_WARNING("You can't figure out how to deconstruct [src]..."))
return
if(!skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_ENGI))
to_chat(user, SPAN_WARNING("You don't know how to deconstruct [src]..."))
return
Expand Down
25 changes: 25 additions & 0 deletions code/game/machinery/vending/cm_vending.dm
Original file line number Diff line number Diff line change
Expand Up @@ -1240,6 +1240,31 @@ GLOBAL_LIST_INIT(cm_vending_gear_corresponding_types_list, list(
vending_human.marine_buyable_categories[buying_category] -= 1
return TRUE

// Unload ALL the items throwing them around randomly, optionally destroying the vendor
/obj/structure/machinery/cm_vending/proc/catastrophic_failure(throw_objects = TRUE, destroy = FALSE)
stat |= IN_USE
var/list/products = get_listed_products()
var/i = 1
while(i <= length(products))
sleep(0.5)
var/list/itemspec = products[i]
if(!itemspec[2] || itemspec[2] <= 0)
i++
continue
itemspec[2] -= 1
var/list/spawned = list()
if(islist(itemspec[3]))
for(var/path in itemspec[3])
spawned += new path(loc)
else if(itemspec[3])
var/path = itemspec[3]
spawned += new path(loc)
if(throw_objects)
for(var/atom/movable/spawned_atom in spawned)
INVOKE_ASYNC(spawned_atom, TYPE_PROC_REF(/atom/movable, throw_atom), pick(orange(src, 4)), 4, SPEED_FAST)
stat &= ~IN_USE
if(destroy)
qdel(src)

//------------HACKING---------------

Expand Down
1 change: 1 addition & 0 deletions code/game/turfs/turf.dm
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@
if(!istype(A))
return

SEND_SIGNAL(src, COMSIG_TURF_ENTERED, A)
SEND_SIGNAL(A, COMSIG_MOVABLE_TURF_ENTERED, src)

// Let explosions know that the atom entered
Expand Down
14 changes: 7 additions & 7 deletions code/modules/decorators/weapon_map_decorator.dm
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/datum/decorator/weapon_map_decorator
var/list/map_array = list()
var/list/camouflage_type

var/icon/c_icon
var/icon/l_icon
Expand All @@ -8,7 +8,7 @@
var/icon/j_icon

/datum/decorator/weapon_map_decorator/is_active_decor()
return map_array.Find(SSmapping.configs[GROUND_MAP].map_name)
return SSmapping.configs[GROUND_MAP].camouflage_type == camouflage_type

/datum/decorator/weapon_map_decorator/get_decor_types()
return typesof(/obj/item/weapon/gun) - /obj/item/weapon/gun
Expand All @@ -28,41 +28,41 @@
gun.item_icons[WEAR_J_STORE] = j_icon

/datum/decorator/weapon_map_decorator/classic
camouflage_type = "classic"
c_icon = 'icons/obj/items/weapons/guns/guns_by_map/classic/guns_obj.dmi'
l_icon = 'icons/obj/items/weapons/guns/guns_by_map/classic/guns_lefthand.dmi'
r_icon = 'icons/obj/items/weapons/guns/guns_by_map/classic/guns_righthand.dmi'
b_icon = 'icons/obj/items/weapons/guns/guns_by_map/classic/back.dmi'
j_icon = 'icons/obj/items/weapons/guns/guns_by_map/classic/suit_slot.dmi'
map_array = list(MAP_PRISON_STATION, MAP_PRISON_STATION_V3, MAP_LV522_CHANCES_CLAIM)

/datum/decorator/weapon_map_decorator/desert
camouflage_type = "desert"
c_icon = 'icons/obj/items/weapons/guns/guns_by_map/desert/guns_obj.dmi'
l_icon = 'icons/obj/items/weapons/guns/guns_by_map/desert/guns_lefthand.dmi'
r_icon = 'icons/obj/items/weapons/guns/guns_by_map/desert/guns_righthand.dmi'
b_icon = 'icons/obj/items/weapons/guns/guns_by_map/desert/back.dmi'
j_icon = 'icons/obj/items/weapons/guns/guns_by_map/desert/suit_slot.dmi'
map_array = list(MAP_WHISKEY_OUTPOST, MAP_DESERT_DAM, MAP_BIG_RED, MAP_KUTJEVO)

/datum/decorator/weapon_map_decorator/jungle
camouflage_type = "jungle"
c_icon = 'icons/obj/items/weapons/guns/guns_by_map/jungle/guns_obj.dmi'
l_icon = 'icons/obj/items/weapons/guns/guns_by_map/jungle/guns_lefthand.dmi'
r_icon = 'icons/obj/items/weapons/guns/guns_by_map/jungle/guns_righthand.dmi'
b_icon = 'icons/obj/items/weapons/guns/guns_by_map/jungle/back.dmi'
j_icon = 'icons/obj/items/weapons/guns/guns_by_map/jungle/suit_slot.dmi'
map_array = list(MAP_LV_624, MAP_RUNTIME,MAP_NEW_VARADERO)

/datum/decorator/weapon_map_decorator/snow
camouflage_type = "snow"
c_icon = 'icons/obj/items/weapons/guns/guns_by_map/snow/guns_obj.dmi'
l_icon = 'icons/obj/items/weapons/guns/guns_by_map/snow/guns_lefthand.dmi'
r_icon = 'icons/obj/items/weapons/guns/guns_by_map/snow/guns_righthand.dmi'
b_icon = 'icons/obj/items/weapons/guns/guns_by_map/snow/back.dmi'
j_icon = 'icons/obj/items/weapons/guns/guns_by_map/snow/suit_slot.dmi'
map_array = list(MAP_CORSAT, MAP_SOROKYNE_STRATA, MAP_ICE_COLONY, MAP_ICE_COLONY_V3)

/datum/decorator/weapon_map_decorator/urban
camouflage_type = "urban" // Sprites not currently all done!
c_icon = 'icons/obj/items/weapons/guns/guns_by_map/urban/guns_obj.dmi'
l_icon = 'icons/obj/items/weapons/guns/guns_by_map/urban/guns_lefthand.dmi'
r_icon = 'icons/obj/items/weapons/guns/guns_by_map/urban/guns_righthand.dmi'
b_icon = 'icons/obj/items/weapons/guns/guns_by_map/urban/back.dmi'
j_icon = 'icons/obj/items/weapons/guns/guns_by_map/urban/suit_slot.dmi'
map_array = list()
2 changes: 2 additions & 0 deletions code/modules/mapping/preloader.dm
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ GLOBAL_DATUM_INIT(_preloader, /datum/map_preloader, new)
value = deepCopyList(value)
what.vars[attribute] = value

/// Area passthrough: do not instanciate a new area, reuse the current one
/area/template_noop
name = "Area Passthrough"
icon_state = "noop"

/// Turf passthrough: do not instanciate a new turf, reuse the current one
/turf/template_noop
name = "Turf Passthrough"
icon_state = "noop"
4 changes: 4 additions & 0 deletions code/modules/mob/dead/observer/observer.dm
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
for(var/obj/effect/step_trigger/S in new_turf) //<-- this is dumb
S.Crossed(src)

// CRUTCH because ghost don't respect normal movement rules
SEND_SIGNAL(new_turf, COMSIG_TURF_ENTERED, src)
SEND_SIGNAL(src, COMSIG_GHOST_MOVED, new_turf)

/mob/dead/observer/get_examine_text(mob/user)
return list(desc)

Expand Down
4 changes: 3 additions & 1 deletion code/modules/mob/living/carbon/human/life/life_helpers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,9 @@
if(thermal_protection_flags & BODY_FLAG_HAND_RIGHT)
thermal_protection += THERMAL_PROTECTION_HAND_RIGHT

return min(1, thermal_protection)
var/list/protection_data = list("protection" = thermal_protection)
SEND_SIGNAL(src, COMSIG_HUMAN_COLD_PROTECTION_APPLY_MODIFIERS, protection_data)
return min(1, protection_data["protection"])


/mob/living/carbon/human/proc/process_glasses(obj/item/clothing/glasses/G)
Expand Down
6 changes: 5 additions & 1 deletion code/modules/surgery/surgery_steps.dm
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ affected_limb, or location vars. Also, in that case there may be a wait between

step_duration *= surface_modifier

var/list/human_modifiers = list("surgery_speed" = 1.0, "pain_reduction" = 0)
SEND_SIGNAL(user, COMSIG_HUMAN_SURGERY_APPLY_MODIFIERS, human_modifiers)
step_duration *= human_modifiers["surgery_speed"]

var/try_to_fail
if(user.a_intent != INTENT_HELP)
try_to_fail = TRUE
Expand Down Expand Up @@ -145,7 +149,7 @@ affected_limb, or location vars. Also, in that case there may be a wait between
to_chat(user, SPAN_WARNING("[capitalize(english_list(message, final_comma_text = ","))]."))

var/advance //Whether to continue to the next step afterwards.
var/pain_failure_chance = max(0, target.pain?.feels_pain ? surgery.pain_reduction_required - target.pain.reduction_pain : 0) * 2 //Each extra pain unit increases the chance by 2
var/pain_failure_chance = max(0, (target.pain?.feels_pain ? surgery.pain_reduction_required - target.pain.reduction_pain : 0) * 2 - human_modifiers["pain_reduction"]) //Each extra pain unit increases the chance by 2

play_preop_sound(user, target, target_zone, tool, surgery)

Expand Down
38 changes: 38 additions & 0 deletions code/modules/tents/blockers.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/// Invisible Blocker Walls, they link up with the main tent and collapse with it
/obj/structure/blocker/tent
name = "Tent Blocker"
icon = 'icons/obj/structures/barricades.dmi'
icon_state = "folding_0" // for map editing only
flags_atom = ON_BORDER
invisibility = INVISIBILITY_MAXIMUM
density = TRUE
opacity = FALSE // Unfortunately this doesn't behave as we'd want with ON_BORDER so we can't make tent opaque
/// The tent this blocker relates to, will be destroyed along with it
var/obj/structure/tent/linked_tent

/obj/structure/blocker/tent/Initialize(mapload, ...)
. = ..()
icon_state = null
linked_tent = locate(/obj/structure/tent) in loc
if(!linked_tent)
return INITIALIZE_HINT_QDEL
RegisterSignal(linked_tent, COMSIG_PARENT_QDELETING, PROC_REF(collapse))

/obj/structure/blocker/tent/Destroy(force)
. = ..()
linked_tent = null

/obj/structure/blocker/tent/proc/collapse()
SIGNAL_HANDLER
qdel(src)

/obj/structure/blocker/tent/initialize_pass_flags(datum/pass_flags_container/PF)
..()
if (PF)
PF.flags_can_pass_all = NONE
PF.flags_can_pass_front = NONE
PF.flags_can_pass_behind = NONE

/obj/structure/blocker/tent/get_projectile_hit_boolean(obj/item/projectile/P)
. = ..()
return FALSE // Always fly through the tent
Loading

0 comments on commit d5b1193

Please sign in to comment.