diff --git a/code/game/objects/effects/decals/posters/bs12.dm b/code/game/objects/effects/decals/posters/bs12.dm index b34c416f01e..6425d708da6 100644 --- a/code/game/objects/effects/decals/posters/bs12.dm +++ b/code/game/objects/effects/decals/posters/bs12.dm @@ -5,6 +5,7 @@ var/name = "PSA: Unlucky Space Explorer" var/desc = "This grim PSA depicts a skeletal form within a space suit. Thousands die every year as a result of failing to follow EVA safety guidelines." var/listing_name = "PSA - EVA Accidents" + var/icon_override = null // If set to an icon path, replaces the icon upon wall placement. Used for modular posters downstream that should not edit upstream dmis /decl/poster/bay_2 icon_state="bsposter2" diff --git a/code/game/objects/effects/decals/posters/posters.dm b/code/game/objects/effects/decals/posters/posters.dm index 80de94dd6c0..6b90e2c3d3d 100644 --- a/code/game/objects/effects/decals/posters/posters.dm +++ b/code/game/objects/effects/decals/posters/posters.dm @@ -1,9 +1,14 @@ -/proc/get_poster_decl(var/path = null, var/exact = TRUE) +/// Returns a randomly picked poster decl of the subtype specified by the path argument. If the exact argument is true, it will return the decl from the decls_repository of the exact path specified. +/proc/get_poster_decl(var/path = null, var/exact = TRUE, var/forbid_types) if(ispath(path)) if(exact) return decls_repository.get_decl(path) else - var/list/L = decls_repository.get_decls_of_subtype(path) // Use get_decls_of_subtype instead of get_decls_of_type, or it will get the map placing icon_state + // Get the list of decals and Remove some forbidden types. These two base types don't have proper icon_states so they're illegal. + var/list/L = decls_repository.get_decls_of_type(path) + L -= decls_repository.get_decl(/decl/poster/lewd) + if(forbid_types) + L -= decls_repository.get_decls_of_type(forbid_types) return L[pick(L)] return null @@ -15,24 +20,28 @@ drop_sound = 'sound/items/drop/wrapper.ogg' pickup_sound = 'sound/items/pickup/wrapper.ogg' force = 0 - var/decl/poster/poster_decl = null - var/poster_type = /obj/structure/sign/poster + VAR_PROTECTED/decl/poster/poster_decl = null + VAR_PROTECTED/poster_type = /obj/structure/sign/poster -/obj/item/poster/Initialize(mapload, var/decl/poster/poster_decl = null) - if(ispath(src.poster_decl)) - src.poster_decl = get_poster_decl(src.poster_decl, TRUE) - else if(istype(poster_decl)) - src.poster_decl = poster_decl - else if(ispath(poster_decl)) - src.poster_decl = get_poster_decl(poster_decl, TRUE) +/obj/item/poster/Initialize(mapload, var/decl/poster/P = null) + if(ispath(poster_decl)) + poster_decl = get_poster_decl(poster_decl, TRUE, null) + else if(istype(P)) + poster_decl = P + else if(ispath(P)) + poster_decl = get_poster_decl(P, TRUE, null) else - src.poster_decl = get_poster_decl(/decl/poster, FALSE) - while (istype(src.poster_decl, /decl/poster/lewd)) - src.poster_decl = get_poster_decl(/decl/poster, FALSE) + poster_decl = get_poster_decl(/decl/poster, FALSE, /decl/poster/lewd) - name += " - [src.poster_decl.name]" + name += " - [poster_decl.name]" return ..() +/// Get the current poster_decl +/obj/item/poster/proc/get_decl() + RETURN_TYPE(/decl/poster) + SHOULD_NOT_OVERRIDE(TRUE) + return poster_decl + //Places the poster on a wall /obj/item/poster/afterattack(var/atom/A, var/mob/user, var/adjacent, var/clickparams) if(!adjacent) @@ -78,41 +87,6 @@ qdel(src) return FALSE -//NT subtype -/obj/item/poster/nanotrasen - icon_state = "rolled_poster_nt" - poster_type = /obj/structure/sign/poster/nanotrasen - -/obj/item/poster/nanotrasen/Initialize(mapload, var/decl/poster/P = null) - if(!ispath(src.poster_decl) && !ispath(P) && !istype(P)) - src.poster_decl = get_poster_decl(/decl/poster/nanotrasen, FALSE) - return ..() - -//Selectable subtype -/obj/item/poster/custom - name = "rolled-up poly-poster" - desc = "The poster comes with its own automatic adhesive mechanism, for easy pinning to any vertical surface. This one is made from some kind of e-paper, and could display almost anything!" - poster_type = /obj/structure/sign/poster/custom - -/obj/item/poster/custom/verb/select_poster() - set name = "Set Poster type" - set category = "Object" - set desc = "Click to choose a poster to display." - - var/mob/M = usr - var/list/options = list() - var/list/decl/poster/posters = decls_repository.get_decls_of_type(/decl/poster) - for(var/option in posters) - options[posters[option].name] = posters[option] - - var/choice = tgui_input_list(M, "Choose a poster!", "Customize Poster", options) - if(src && choice && !M.stat && in_range(M,src)) - poster_decl = options[choice] - name = "rolled-up poly-poster - [src.poster_decl.name]" - to_chat(M, "The poster is now: [choice].") - - - //############################## THE ACTUAL DECALS ########################### /obj/structure/sign/poster @@ -121,28 +95,27 @@ icon = 'icons/obj/contraband_vr.dmi' //VOREStation Edit icon_state = "poster" //VOREStation Edit anchored = TRUE - var/decl/poster/poster_decl = null - var/target_poster_decl_path = /decl/poster - var/roll_type = /obj/item/poster - var/ruined = FALSE + VAR_PROTECTED/decl/poster/poster_decl = null // Assigned by Initialize() to a random poster decl. If this is mapset to a path, it will be used to locate the decl specified by that path. + VAR_PROTECTED/roll_type = /obj/item/poster + VAR_PRIVATE/ruined = FALSE /obj/structure/sign/poster/Initialize(mapload, var/placement_dir = null, var/obj/item/poster/P = null) . = ..() - if(ispath(src.poster_decl)) - src.poster_decl = get_poster_decl(src.poster_decl, TRUE) + if(ispath(poster_decl)) + poster_decl = get_poster_decl(poster_decl, TRUE, null) else if(istype(P)) - src.poster_decl = P.poster_decl + poster_decl = P.get_decl() roll_type = P.type else if(ispath(P)) - src.poster_decl = get_poster_decl(P, TRUE) + poster_decl = get_poster_decl(P, TRUE, null) else - src.poster_decl = get_poster_decl(/decl/poster, FALSE) - while (istype(src.poster_decl, /decl/poster/lewd)) - src.poster_decl = get_poster_decl(/decl/poster, FALSE) + poster_decl = get_poster_decl(/decl/poster, FALSE, /decl/poster/lewd) name = "[initial(name)] - [poster_decl.name]" desc = "[initial(desc)] [poster_decl.desc]" + if(poster_decl.icon_override) + icon = poster_decl.icon_override icon_state = poster_decl.icon_state if(placement_dir) @@ -162,7 +135,7 @@ pixel_x = -32 pixel_y = 0 - flick("poster_being_set", src) + flick("poster_being_set", src) // If you don't see this animation, check that the decl/poster's icon_override dmi file has the icon states for poster_being_set and poster_ripped in it. /obj/structure/sign/poster/attackby(obj/item/W as obj, mob/user as mob) if(W.has_tool_quality(TOOL_WIRECUTTER)) @@ -176,12 +149,10 @@ return /obj/structure/sign/poster/attack_hand(mob/user as mob) - if(ruined) return if(tgui_alert(user, "Do I want to rip the poster from the wall?","You think...",list("Yes","No")) == "Yes") - if(ruined || !user.Adjacent(src)) return @@ -193,16 +164,9 @@ desc = "You can't make out anything from the poster's original print. It's ruined." add_fingerprint(user) +/// Creates a poster item using roll_type as the path, and qdels the wall poster /obj/structure/sign/poster/proc/roll_and_drop(turf/newloc) + SHOULD_NOT_OVERRIDE(TRUE) var/obj/item/poster/P = new roll_type(newloc, poster_decl) P.loc = newloc qdel(src) - -// NT poster subtype. -/obj/structure/sign/poster/nanotrasen - roll_type = /obj/item/poster/nanotrasen - target_poster_decl_path = /decl/poster/nanotrasen - -// Non-Random Posters -/obj/structure/sign/poster/custom - roll_type = /obj/item/poster/custom diff --git a/code/game/objects/effects/decals/posters/postersubtypes.dm b/code/game/objects/effects/decals/posters/postersubtypes.dm new file mode 100644 index 00000000000..ded571555bd --- /dev/null +++ b/code/game/objects/effects/decals/posters/postersubtypes.dm @@ -0,0 +1,47 @@ +///////////////////////////////////////////////////////////////////////////////// +// NT subtype +///////////////////////////////////////////////////////////////////////////////// +/obj/item/poster/nanotrasen // held object + icon_state = "rolled_poster_nt" + poster_type = /obj/structure/sign/poster/nanotrasen + +/obj/item/poster/nanotrasen/Initialize(mapload, var/decl/poster/P = null) + if(!ispath(poster_decl) && !ispath(P) && !istype(P)) + poster_decl = get_poster_decl(/decl/poster/nanotrasen, FALSE, null) + return ..() + +/obj/structure/sign/poster/nanotrasen // placed wall object + roll_type = /obj/item/poster/nanotrasen + + +///////////////////////////////////////////////////////////////////////////////// +// Selectable "custom" subtype +///////////////////////////////////////////////////////////////////////////////// +/obj/item/poster/custom // held object + name = "rolled-up poly-poster" + desc = "The poster comes with its own automatic adhesive mechanism, for easy pinning to any vertical surface. This one is made from some kind of e-paper, and could display almost anything!" + poster_type = /obj/structure/sign/poster/custom + +/// Verb to change a custom poster's design +/obj/item/poster/custom/verb/select_poster() + PRIVATE_PROC(TRUE) + SHOULD_NOT_OVERRIDE(TRUE) + set name = "Set Poster type" + set category = "Object" + set desc = "Click to choose a poster to display." + + var/mob/M = usr + var/list/options = list() + var/list/decl/poster/posters = decls_repository.get_decls_of_type(/decl/poster) + for(var/option in posters) + options[posters[option].name] = posters[option] + + var/choice = tgui_input_list(M, "Choose a poster!", "Customize Poster", options) + if(src && choice && !M.stat && in_range(M,src)) + poster_decl = options[choice] + name = "rolled-up poly-poster - [poster_decl.name]" + to_chat(M, "The poster is now: [choice].") + +// Wall object +/obj/structure/sign/poster/custom // placed wall object + roll_type = /obj/item/poster/custom diff --git a/code/unit_tests/poster_tests.dm b/code/unit_tests/poster_tests.dm new file mode 100644 index 00000000000..b7dc36cd238 --- /dev/null +++ b/code/unit_tests/poster_tests.dm @@ -0,0 +1,24 @@ +/datum/unit_test/posters_shall_have_legal_states + name = "POSTERS: All poster decls shall have valid icon and icon overrides" + +/datum/unit_test/posters_shall_have_legal_states/start_test() + var/failed = 0 + var/list/all_posters = decls_repository.get_decls_of_type(/decl/poster) + all_posters -= decls_repository.get_decl(/decl/poster/lewd) // Dumb exclusion for now. This really needs to become a valid poster instead of an illegaly made base type + + for(var/path in all_posters) + var/decl/poster/D = all_posters[path] + var/obj/structure/sign/poster/P = /obj/structure/sign/poster // The base poster shows ALL subtypes except /lewd, so all posters should function here regardless! + var/icon/I = initial(P.icon) + if(D.icon_override) + I = D.icon_override + if(!(D.icon_state in cached_icon_states(I))) + failed += 1 + log_unit_test("[D.type]: Poster - missing icon_state \"[D.icon_state]\" in \"[I]\", as [D.icon_override ? "override" : "base"] dmi.") + + if(failed) + fail("[failed] posters had missing icon_states or bad icon overrides.") + else + pass("All [all_posters.len] posters have their icon_states and overrides set correctly.") + + return TRUE diff --git a/vorestation.dme b/vorestation.dme index e67551e82e3..d00ff089a45 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -1329,6 +1329,7 @@ #include "code\game\objects\effects\decals\posters\polarisposters.dm" #include "code\game\objects\effects\decals\posters\polarisposters_vr.dm" #include "code\game\objects\effects\decals\posters\posters.dm" +#include "code\game\objects\effects\decals\posters\postersubtypes.dm" #include "code\game\objects\effects\decals\posters\tgposters.dm" #include "code\game\objects\effects\decals\posters\voreposters_vr.dm" #include "code\game\objects\effects\map_effects\beam_point.dm" @@ -4532,6 +4533,7 @@ #include "code\unit_tests\map_tests.dm" #include "code\unit_tests\material_tests.dm" #include "code\unit_tests\mob_tests.dm" +#include "code\unit_tests\poster_tests.dm" #include "code\unit_tests\reagent_tests.dm" #include "code\unit_tests\recipe_tests.dm" #include "code\unit_tests\recycler_vendor_tests.dm"