diff --git a/code/__DEFINES/~doppler_defines/TESHARI_WAR_defines.dm b/code/__DEFINES/~doppler_defines/TESHARI_WAR_defines.dm new file mode 100644 index 00000000000000..48427f36c86997 --- /dev/null +++ b/code/__DEFINES/~doppler_defines/TESHARI_WAR_defines.dm @@ -0,0 +1,4 @@ +// Factions +#define WAR_FACTION_TIZIRA "Tizira" +#define WAR_FACTION_TESHARI "Teshari" +#define WAR_FACTION_NEUTRAL "Neutral" diff --git a/code/modules/cargo/exports/large_objects.dm b/code/modules/cargo/exports/large_objects.dm index ed65563b02ca36..920297e42d3622 100644 --- a/code/modules/cargo/exports/large_objects.dm +++ b/code/modules/cargo/exports/large_objects.dm @@ -8,6 +8,7 @@ /obj/structure/closet/crate/large, /obj/structure/closet/crate/mail, /obj/structure/closet/crate/wooden, + /obj/structure/closet/crate/donation, // DOPPLER EDIT ADDITION - Dono crates are in loadout and are craftable... do not want infinite money glitch ) /datum/export/large/crate/total_printout(datum/export_report/ex, notes = TRUE) // That's why a goddamn metal crate costs that much. diff --git a/code/modules/cargo/orderconsole.dm b/code/modules/cargo/orderconsole.dm index d5984da9ec9828..c4b3cd16752a32 100644 --- a/code/modules/cargo/orderconsole.dm +++ b/code/modules/cargo/orderconsole.dm @@ -189,6 +189,7 @@ packs += list(list( "name" = pack.name, "cost" = pack.get_cost() * get_discount(), + "shortagemult" = pack.get_shortage_price_mult(), // DOPPLER EDIT ADDITION - TESHARI_WAR STORY MODULE "id" = pack_id, "desc" = pack.desc || pack.name, // If there is a description, use it. Otherwise use the pack's name. "first_item_icon" = first_item?.icon, diff --git a/code/modules/modular_computers/file_system/programs/dept_order.dm b/code/modules/modular_computers/file_system/programs/dept_order.dm index e640d5ecb3710c..f0952e5b151e73 100644 --- a/code/modules/modular_computers/file_system/programs/dept_order.dm +++ b/code/modules/modular_computers/file_system/programs/dept_order.dm @@ -85,9 +85,18 @@ GLOBAL_VAR(department_cd_override) if(!islist(supply_data[pack.group]) || !can_see_pack(pack)) continue + // DOPPLER EDIT ADDITION BEGIN - TESHARI_WAR STORY MODULE + var/shortage_text = "" + if (pack.is_unavailable()) + shortage_text = " (Shortages: Unavailable!)" + else if (pack.get_shortage_price_mult() != 1) + shortage_text = " (Shortages: [pack.get_shortage_price_mult()]x cooldown)" + // DOPPLER EDIT ADDITION END UNTYPED_LIST_ADD(supply_data[pack.group], list( "name" = pack.name, "cost" = pack.get_cost(), + "unavailable" = pack.is_unavailable(), // DOPPLER EDIT ADDITION - TESHARI_WAR STORY MODULE + "shortage_text" = shortage_text, // DOPPLER EDIT ADDITION - TESHARI_WAR STORY MODULE "id" = pack.id, "desc" = pack.desc || pack.name, // If there is a description, use it. Otherwise use the pack's name. )) diff --git a/config/config.txt b/config/config.txt index 35b7e9a352d176..ebf61685b778a5 100644 --- a/config/config.txt +++ b/config/config.txt @@ -3,6 +3,7 @@ $include game_options.txt $include dbconfig.txt $include doppler/config_doppler.txt +$include doppler/STORY_SUPPLY_SHORTAGE.txt $include comms.txt $include logging.txt $include resources.txt diff --git a/config/doppler/STORY_SUPPLY_SHORTAGE.txt b/config/doppler/STORY_SUPPLY_SHORTAGE.txt new file mode 100644 index 00000000000000..dfbc7ba520b870 --- /dev/null +++ b/config/doppler/STORY_SUPPLY_SHORTAGE.txt @@ -0,0 +1,10 @@ +## Instructions - write SUPPLY_SHORTAGES, followed by this format: SUPPLYPACKTYPEPATH,MULT to change the price of +## a supply pack. +## 1 has no effect. +## -1 will make the item completely unavailable. +## Mults below 1, including 0, are possible, but highly inadvisable. + +## Examples: +#SUPPLY_SHORTAGES /datum/supply_pack/goody/laser_single,1.5 +#SUPPLY_SHORTAGES /datum/supply_pack/security/armory/laser,-1 +#SUPPLY_SHORTAGES /datum/supply_pack/security/stingpack,4 diff --git a/modular_doppler/STORY_teshari_war/config.dm b/modular_doppler/STORY_teshari_war/config.dm new file mode 100644 index 00000000000000..58caf63c53739d --- /dev/null +++ b/modular_doppler/STORY_teshari_war/config.dm @@ -0,0 +1,11 @@ +/datum/config_entry/keyed_list/supply_shortages + key_mode = KEY_MODE_TYPE + value_mode = VALUE_MODE_NUM + splitter = "," + +/datum/config_entry/keyed_list/supply_shortages/validate_config_key(key) + var/type = text2path(key) + if (type in get_usable_supply_packs()) + return key + log_config("ERROR: [key] is not a valid supply pack typepath.") + return null diff --git a/modular_doppler/STORY_teshari_war/mind.dm b/modular_doppler/STORY_teshari_war/mind.dm new file mode 100644 index 00000000000000..e1c852097cf25c --- /dev/null +++ b/modular_doppler/STORY_teshari_war/mind.dm @@ -0,0 +1,3 @@ +/datum/mind + /// The stance this mind takes on the tizira/teshari war. By default, they dont care at all. + var/war_faction = WAR_FACTION_NEUTRAL // i just wanna grill diff --git a/modular_doppler/STORY_teshari_war/preferences.dm b/modular_doppler/STORY_teshari_war/preferences.dm new file mode 100644 index 00000000000000..cbdb505c0516f5 --- /dev/null +++ b/modular_doppler/STORY_teshari_war/preferences.dm @@ -0,0 +1,30 @@ +GLOBAL_LIST_INIT(teshari_war_factions, list( + WAR_FACTION_TIZIRA, + WAR_FACTION_TESHARI, + WAR_FACTION_NEUTRAL +)) + +/datum/preference/choiced/doppler_war_faction + savefile_key = "doppler_war_faction" + main_feature_name = "War Alignment" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_SECONDARY_FEATURES + priority = PREFERENCE_PRIORITY_DEFAULT + +/datum/preference/choiced/doppler_war_faction/init_possible_values() + return GLOB.teshari_war_factions + +/datum/preference/choiced/doppler_war_faction/create_default_value() + return WAR_FACTION_NEUTRAL + +/datum/preference/choiced/doppler_war_faction/apply_to_human(mob/living/carbon/human/target, value) + RegisterSignal(target, COMSIG_MOB_MIND_INITIALIZED, PROC_REF(apply_mind_variable), override = TRUE) + return + +/// Signal handler that waits for mind to init and then sets the war faction variable. +/datum/preference/choiced/doppler_war_faction/proc/apply_mind_variable(mob/living/carbon/human/target, datum/mind/new_mind) + SIGNAL_HANDLER + + new_mind.war_faction = target.client.prefs.read_preference(/datum/preference/choiced/doppler_war_faction) + UnregisterSignal(target, COMSIG_MOB_MIND_INITIALIZED) + diff --git a/modular_doppler/STORY_teshari_war/readme.md b/modular_doppler/STORY_teshari_war/readme.md new file mode 100644 index 00000000000000..9b3f2eb3793b17 --- /dev/null +++ b/modular_doppler/STORY_teshari_war/readme.md @@ -0,0 +1,35 @@ +## Title: Teshari/Tizira war + +MODULE ID: TESHARI_WAR + +### Description: + +TEMPORARY STORY MODULE. WILL BE REVERTED WHEN THE ARC ENDS. + +### TG Proc Changes: + +code/modules/cargo/orderconsole.dm - L192, added "shortagemult" = pack.get_shortage_price_mult(), +code/modules/modular_computers/file_system/programs/dept_order.dm - L88 - L99 + +tgui/packages/tgui/interfaces/NtosDeptOrder.tsx - L31-L32, L211-213, L223 +tgui/packages/tgui/interfaces/Cargo/CargoCatalog.tsx - L201-L204, L221-L223, L241-L245 +tgui/packages/tgui/interfaces/Cargo/types.ts - L42 + +config/config.txt - L6 + +### Defines: + +code\_\_DEFINES\~doppler_defines\TESHARI_WAR_defines.dm + +### Master file additions + +N/A + +### Included files that are not contained in this module: + +config/doppler/STORY_SUPPLY_SHORTAGE.txt +tgui\packages\tgui\interfaces\PreferencesMenu\preferences\features\dopplershift_preferences\war_faction.tsx + +### Credits: + +Niko diff --git a/modular_doppler/STORY_teshari_war/supply_pack.dm b/modular_doppler/STORY_teshari_war/supply_pack.dm new file mode 100644 index 00000000000000..01426caef5fd8a --- /dev/null +++ b/modular_doppler/STORY_teshari_war/supply_pack.dm @@ -0,0 +1,32 @@ +/// Returns a list of non-abstract supply packs. +/proc/get_usable_supply_packs() + RETURN_TYPE(/list) + var/list/packs = list() + for (var/datum/supply_pack/iter_path as anything in subtypesof(/datum/supply_pack)) + if (iter_path::abstract_type == iter_path) + continue + packs += iter_path + return packs + +/// Returns the assoc list of stringified supply pack typepaths to their price mult. +/proc/get_price_mults() + RETURN_TYPE(/list) + return CONFIG_GET(keyed_list/supply_shortages) + +// If this proc returns -1, the item is wholly unavailable. +/// Returns the actual price mult of the supply pack. If -1, the item is completely unavailable. Use get_cost() for actual price calculations. +/datum/supply_pack/proc/get_shortage_price_mult() + var/mult = get_price_mults()["[type]"] + if (isnull(mult)) + return 1 + return mult + +/// Returns TRUE if our shortage price mult is -1. +/datum/supply_pack/proc/is_unavailable() + return get_shortage_price_mult() == -1 + +/datum/supply_pack/get_cost() + . = ..() + + if (!is_unavailable()) + . *= get_shortage_price_mult() diff --git a/modular_doppler/STORY_teshari_war/war_posters/code/cargo.dm b/modular_doppler/STORY_teshari_war/war_posters/code/cargo.dm new file mode 100644 index 00000000000000..99ffa3dc4acee9 --- /dev/null +++ b/modular_doppler/STORY_teshari_war/war_posters/code/cargo.dm @@ -0,0 +1,17 @@ +/datum/supply_pack/goody/tesh_posters + name = "Teshari Propaganda" + desc = "A box of teshari war posters." + cost = CARGO_CRATE_VALUE * 1.1 + contains = list(/obj/item/storage/box/doppler_war_posters/teshari) + +/datum/supply_pack/goody/tizira_posters + name = "Tiziran Propaganda" + desc = "A box of tiziran war posters." + cost = CARGO_CRATE_VALUE * 1.1 + contains = list(/obj/item/storage/box/doppler_war_posters/tiziran) + +/datum/supply_pack/goody/iso_posters + name = "Isolationist Posters" + desc = "A box of isolationist war posters." + cost = CARGO_CRATE_VALUE * 1.1 + contains = list(/obj/item/storage/box/doppler_war_posters/isolationist) diff --git a/modular_doppler/STORY_teshari_war/war_posters/code/loadout.dm b/modular_doppler/STORY_teshari_war/war_posters/code/loadout.dm new file mode 100644 index 00000000000000..4f4eb6a41a70c7 --- /dev/null +++ b/modular_doppler/STORY_teshari_war/war_posters/code/loadout.dm @@ -0,0 +1,11 @@ +/datum/loadout_item/pocket_items/equipment/propaganda_box_teshari + name = "Teshari propaganda box" + item_path = /obj/item/storage/box/doppler_war_posters/teshari + +/datum/loadout_item/pocket_items/equipment/propaganda_box_tiziran + name = "Tiziran propaganda box" + item_path = /obj/item/storage/box/doppler_war_posters/tiziran + +/datum/loadout_item/pocket_items/equipment/propaganda_box_isolationist + name = "Isolationist propaganda box" + item_path = /obj/item/storage/box/doppler_war_posters/isolationist diff --git a/modular_doppler/STORY_teshari_war/war_posters/code/mood.dm b/modular_doppler/STORY_teshari_war/war_posters/code/mood.dm new file mode 100644 index 00000000000000..2120771c9757c5 --- /dev/null +++ b/modular_doppler/STORY_teshari_war/war_posters/code/mood.dm @@ -0,0 +1,15 @@ +#define WAR_POSTER_MOOD_CAT "poster_mood" + +/datum/mood_event/war_poster_sympathy + description = "I saw a poster that reinforces my beliefs. It's good to have like-minded people around." + mood_change = 2 + category = WAR_POSTER_MOOD_CAT + timeout = 120 SECONDS + +/datum/mood_event/war_poster_wrong + description = "I saw a poster that really pissed me off! How can people like that be allowed to work here?!" + mood_change = -4 + category = WAR_POSTER_MOOD_CAT + timeout = 120 SECONDS + +#undef WAR_POSTER_MOOD_CAT diff --git a/modular_doppler/STORY_teshari_war/war_posters/code/posters.dm b/modular_doppler/STORY_teshari_war/war_posters/code/posters.dm new file mode 100644 index 00000000000000..e3ec9b91e7934d --- /dev/null +++ b/modular_doppler/STORY_teshari_war/war_posters/code/posters.dm @@ -0,0 +1,277 @@ +#define WAR_POSTER_MOOD "war_poster" +#define WAR_POSTER_RANGE 7 + +/obj/structure/sign/poster/doppler_war + name = "abstract war poster" + desc = "Surely, if this was coded correctly, you would be angry." + abstract_type = /obj/structure/sign/poster/doppler_war + icon = 'modular_doppler/STORY_teshari_war/war_posters/icons/posters.dmi' + icon_state = "tesh_unity" + + /// Those of our aligned faction recieve a small mood buff when seeing this poster - other factions get a debuff. Neutral doesn't care at all. + var/aligned_faction = WAR_FACTION_NEUTRAL + /// Assoc list of (WAR_FACTION -> list(string, chance)). Used in pickweight to determine what people think when they see the poster, depending on + var/list/faction_reactions = list() + /// Assoc list of (WAR_FACTION -> /datum/mood_event). Used to determine the actual mood event given. + var/list/faction_moods = list() + /// Proximity sensor for the above vars + var/datum/proximity_monitor/advanced/war_demoraliser/demoraliser + +/obj/structure/sign/poster/doppler_war/on_placed_poster() + demoraliser = new(src, WAR_POSTER_RANGE, TRUE, aligned_faction, WAR_POSTER_MOOD, faction_reactions, faction_moods, READING_CHECK_LIGHT) + return ..() + +// A poster subtype exclusively for random posters. +// This subtype is only necessary to use if your poster has special behavior that cant be randomised by base-TG posters. +// Things like list vars cant be found via initial, so thats one use-case. +/obj/item/poster/random + abstract_type = /obj/item/poster/random + var/obj/structure/sign/poster/poster_basetype + +/obj/item/poster/random/Initialize(mapload, obj/structure/sign/poster/new_poster_structure) + var/list/valid_subtypes = subtypesof(poster_basetype) + for (var/datum/subtype as anything in valid_subtypes) + if (subtype.abstract_type == subtype) + valid_subtypes -= subtype + if (!valid_subtypes.len) + return INITIALIZE_HINT_QDEL + var/obj/structure/sign/poster/picked = pick(valid_subtypes) + new_poster_structure = new picked(src) + + return ..() + +/obj/item/storage/box/doppler_war_posters + name = "propaganda poster box" + desc = "A box usually containing a number of posters for propaganda purposes." + abstract_type = /obj/item/storage/box/doppler_war_posters + var/obj/item/poster/poster_path + +/obj/item/storage/box/doppler_war_posters/PopulateContents() + . = ..() + + if (isnull(poster_path)) + return // sanity + + var/i = 0 + for (i = 0, i < 7, i++) + new poster_path(src) + +/obj/item/poster/random/random_teshari + name = "random teshari poster" + poster_basetype = /obj/structure/sign/poster/doppler_war/teshari + icon = 'modular_doppler/STORY_teshari_war/war_posters/icons/posters.dmi' + icon_state = "rolled_tesh" + +/obj/item/storage/box/doppler_war_posters/teshari + poster_path = /obj/item/poster/random/random_teshari + +/obj/structure/sign/poster/doppler_war/teshari + name = "teshari war poster" + poster_item_name = "teshari war poster" + poster_item_desc = "A pro-teshari propaganda poster, espousing the evils of the Talunan empire and the virtue of Sirsiai's defense. Aisi Tarischi." + poster_item_icon_state = "rolled_tesh" + printable = TRUE + aligned_faction = WAR_FACTION_TESHARI + abstract_type = /obj/structure/sign/poster/doppler_war/teshari + +/obj/structure/sign/poster/doppler_war/teshari/unity + name = "Ilisime (Unity)" + desc = "A poster encouraging the teshari diaspora - from stars, from sea, from earth, from dust - to unite in defense of their shattered homeworld, Sirisai." + icon_state = "tesh_unity" + faction_reactions = list( + WAR_FACTION_TESHARI = list( + "All for Sirisai. Aisi Tarischi!" = 10, + "Sophonts in arms, we can save Teshari kind." = 10, + "Unity...? I'm not alone here." = 8 + ), + WAR_FACTION_TIZIRA = list( + "Look at them, standing in front of their flag like they're the 'victims'." = 10, + "...your unity won't do much when you're outnumbered and outgunned, you vultures." = 10 + ), + ) + faction_moods = list( + WAR_FACTION_TESHARI = /datum/mood_event/war_poster_sympathy, + WAR_FACTION_TIZIRA = /datum/mood_event/war_poster_wrong, + ) + +/obj/structure/sign/poster/doppler_war/teshari/execution + name = "Schatara shitilushu (Our execution)" + desc = "A kneeled teshari is presented for execution by a Tiziran blade. You could be next on the block. Act now!" + icon_state = "tesh_warn" + faction_reactions = list( + WAR_FACTION_TESHARI = list( + "We will shatter their Tiziran steel with our resolve. Aisi Tarischi." = 10, + "I won't be next. Noone will. We can stop the Tizirans here and now." = 10, + ), + WAR_FACTION_TIZIRA = list( + "They struck first! They're the instigators! But the TIZIRANS are the executioners?!" = 10, + "Stars, such a damned overreaction. Those birds could end this war whenever they choose." = 10 + ), + ) + faction_moods = list( + WAR_FACTION_TESHARI = /datum/mood_event/war_poster_sympathy, + WAR_FACTION_TIZIRA = /datum/mood_event/war_poster_wrong, + ) + +/obj/structure/sign/poster/doppler_war/teshari/enemy + name = "Shushire Metara (Enemy yours)" + desc = "Depicted on this poster is a rather over-built Tiziran, contrasted with the rather small form of a typical Teshari. Labels, in schechi, read: \"IMPERIALIST\", and \"UNITED\". Clear propaganda, if you've ever seen it." + icon_state = "tesh_enemy" + faction_reactions = list( + WAR_FACTION_TESHARI = list( + "Their brutishness will be their downfall. All for Sirisai." = 10, + ), + WAR_FACTION_TIZIRA = list( + "Of course they choose to depict Tizirans as brutes. It's all they can really do." = 10, + "...could they not have chosen a less stereotyped image for their propaganda?" = 10 + ), + ) + faction_moods = list( + WAR_FACTION_TESHARI = /datum/mood_event/war_poster_sympathy, + WAR_FACTION_TIZIRA = /datum/mood_event/war_poster_wrong, + ) + +/obj/structure/sign/poster/doppler_war/teshari/burn + name = "Ilisischa! (Inferno!)" + desc = "A rather striking image of a rather furious-looking teshari staring at the camera, torch in-hand, setting the Tiziran flag alight. Written beneath in Schechi runes reads \"Fight back!\"" + icon_state = "tesh_burn" + faction_reactions = list( + WAR_FACTION_TESHARI = list( + "We'll fight for every damn inch of land they take. Sirisai will stand." = 10, + "Raise your arms, raise your wings, raise your rifles..." = 10, + ), + WAR_FACTION_TIZIRA = list( + "The flag? Really? That's just cliche..." = 10, + "...of course, if they had their way, they'd burn Tizira to the ground as well. Animals. Vultures." = 10 + ), + ) + faction_moods = list( + WAR_FACTION_TESHARI = /datum/mood_event/war_poster_sympathy, + WAR_FACTION_TIZIRA = /datum/mood_event/war_poster_wrong, + ) + +/obj/item/poster/random/random_tiziran + name = "random tiziran poster" + poster_basetype = /obj/structure/sign/poster/doppler_war/tiziran + icon = 'modular_doppler/STORY_teshari_war/war_posters/icons/posters.dmi' + icon_state = "rolled_tizira" + +/obj/item/storage/box/doppler_war_posters/tiziran + poster_path = /obj/item/poster/random/random_tiziran + +/obj/structure/sign/poster/doppler_war/tiziran + name = "tiziran war poster" + poster_item_name = "tiziran war poster" + poster_item_desc = "A pro-tizira propaganda poster, generally encouraging enlistment and patriotism." + poster_item_icon_state = "rolled_tizira" + printable = TRUE + abstract_type = /obj/structure/sign/poster/doppler_war/tiziran + aligned_faction = WAR_FACTION_TIZIRA + +/obj/structure/sign/poster/doppler_war/tiziran/pride + name = "Tizira. (Tizira.)" + desc = "A depiction of the Tiziran flag. Three moon dieties - Atra'Kor, Atra'Kal, and Atra'Neff, crowned and nurtured by the sun-god Atra'Asl. \ + Explained beneath, the wings depict the tiziran peoples' shared faith and unity. This is what we fight for, the poster suggests. What we defend." + icon_state = "tizira_pride" + faction_reactions = list( + WAR_FACTION_TESHARI = list( + "The tiziran flag. The poster child (literally) of imperialist slaughter." = 10, + "If these gods of theirs are real, they would weep at the lizards' senseless war." = 10 + ), + WAR_FACTION_TIZIRA = list( + "The tiziran flag. A reminder of what we are fighting for." = 10, + "May the gods watch over Tizira's soldiers." = 10 + ), + ) + faction_moods = list( + WAR_FACTION_TESHARI = /datum/mood_event/war_poster_wrong, + WAR_FACTION_TIZIRA = /datum/mood_event/war_poster_sympathy, + ) + +/obj/structure/sign/poster/doppler_war/tiziran/enlist + name = "Za'Haious Rar! (Enlist!)" + desc = "While many Tizirans face obligate military service, few reach professional status. This poster encourages the reader to fully commit themselves to the Talunan ranks, and earn their prestige in white." + icon_state = "tizira_enlist" + faction_reactions = list( + WAR_FACTION_TESHARI = list( + "More officers to command their mindless brutes into the tundras of Sirisai..." = 10, + "You could excuse the grunts. They didn't choose. But the whitecaps? Irredeemable." = 10 + ), + WAR_FACTION_TIZIRA = list( + "Nothing's more prideful than giving yourself to the defense of the mother sands. Respect to them all." = 10, + "It's not for everyone. But that white armor could give anyone a new look into life." = 10 + ), + ) + faction_moods = list( + WAR_FACTION_TESHARI = /datum/mood_event/war_poster_wrong, + WAR_FACTION_TIZIRA = /datum/mood_event/war_poster_sympathy, + ) + +/obj/structure/sign/poster/doppler_war/tiziran/enlisttwo + name = "Hekiek Mor'Shuxi? (Are you doing your part?)" + desc = "The armored Tiziran curiously glances through her visor-glass to the viewer, as if to ask: 'Are you giving your all for your home?'" + icon_state = "tizira_enlisttwo" + faction_reactions = list( + WAR_FACTION_TESHARI = list( + "Doing your part? What's your part, helping a senseless imperialist war for territory?" = 10, + "Doing my part, sure. Just not the one you want, you damned geckos." = 10 + ), + WAR_FACTION_TIZIRA = list( + "The more soldiers for the war, the better. We need to end this as soon as we can." = 10, + "Every Tiziran should fight for their home. It's your home. To stand by would be to invite... chaos." = 10 + ), + ) + faction_moods = list( + WAR_FACTION_TESHARI = /datum/mood_event/war_poster_wrong, + WAR_FACTION_TIZIRA = /datum/mood_event/war_poster_sympathy, + ) + +/obj/structure/sign/poster/doppler_war/tiziran/enlistthree + name = "Hexire Tizira (Tizira needs you)" + desc = "A series of career-service tizirans are lined up. Supported by the Tiziran emblem, the poster urges the reader to enlist for protracted service against the Teshari menace." + icon_state = "tizira_enlistthree" + faction_reactions = list( + WAR_FACTION_TESHARI = list( + "The only menace here are you Tiziran imperialists." = 10, + "...how many of those Tizirans will die for their lie?" = 10, + "Just more grunts to the slaughter. This violence needs to end." = 10, + ), + WAR_FACTION_TIZIRA = list( + "The more soldiers for the war, the better. We need to end this as soon as we can." = 10, + "Those birds had no idea what kind of war they'd start." = 10 + ), + ) + faction_moods = list( + WAR_FACTION_TESHARI = /datum/mood_event/war_poster_wrong, + WAR_FACTION_TIZIRA = /datum/mood_event/war_poster_sympathy, + ) + +/obj/item/poster/random/random_isolationist + name = "random isolationist poster" + poster_basetype = /obj/structure/sign/poster/isolationist + icon = 'modular_doppler/STORY_teshari_war/war_posters/icons/posters.dmi' + icon_state = "rolled_iso" + +/obj/item/storage/box/doppler_war_posters/isolationist + poster_path = /obj/item/poster/random/random_isolationist + +/obj/structure/sign/poster/isolationist + name = "isolationist war poster" + poster_item_name = "isolationist war poster" + poster_item_desc = "An isolationist propaganda poster, condemning the 4CA for its attempted involvement in the tizira/teshari war." + poster_item_icon_state = "rolled_iso" + icon = 'modular_doppler/STORY_teshari_war/war_posters/icons/posters.dmi' + abstract_type = /obj/structure/sign/poster/isolationist + +/obj/structure/sign/poster/isolationist/bigbrother + name = "Big Brother" + desc = "An eye overlooks a row of individuals, flanked by the 4CA's primary color. The hand closes around the galaxy. The 4CA expands." + icon_state = "iso_bigbrother" + +/obj/structure/sign/poster/isolationist/stayout + name = "4CA Stay Out!" + desc = "Both the Tizirans and the Teshari refuse direct 4CA intervention in their war. Yet, the alignment pushes anyway. This poster summarizes the way many people feel about this." + icon_state = "iso_stayout" + +#undef WAR_POSTER_MOOD +#undef WAR_POSTER_RANGE diff --git a/modular_doppler/STORY_teshari_war/war_posters/code/war_moralisation.dm b/modular_doppler/STORY_teshari_war/war_posters/code/war_moralisation.dm new file mode 100644 index 00000000000000..4d959183bc3ad1 --- /dev/null +++ b/modular_doppler/STORY_teshari_war/war_posters/code/war_moralisation.dm @@ -0,0 +1,86 @@ +// Mostly stolen from demoraliser.dm. +/datum/proximity_monitor/advanced/war_demoraliser + /// The faction, using defines from TESHARI_WAR_defines.dm. Do NOT use neutral. + var/faction + /// Mood category to apply to moods + var/mood_category + /// Assoc list of (WAR_FACTION -> list(string, chance)). Used in pickweight to determine what people think when they see the poster, depending on + var/list/faction_reactions = list() + /// Assoc list of (WAR_FACTION -> /datum/mood_event). Used to determine the actual mood event given. + var/list/faction_moods = list() + /// For literacy checks + var/reading_requirements = READING_CHECK_LIGHT + +/datum/proximity_monitor/advanced/war_demoraliser/New(atom/_host, range, _ignore_if_not_on_turf = TRUE, faction, mood_category, list/faction_reactions, list/faction_moods, reading_requirements) + . = ..() + + if (faction == WAR_FACTION_NEUTRAL) + CRASH("War demoralizers should not be neutral. That's like, their entire point. They're propoganda.") + RegisterSignal(host, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) + + src.faction = faction + src.mood_category = mood_category + src.faction_reactions = faction_reactions + src.faction_moods = faction_moods + src.reading_requirements = reading_requirements + +/datum/proximity_monitor/advanced/war_demoraliser/field_turf_crossed(atom/movable/crossed, turf/old_location, turf/new_location) + if (!isliving(crossed)) + return + if (!can_see(crossed, host, current_range)) + return + on_seen(crossed) + +/* + * Signal proc for [COMSIG_ATOM_EXAMINE]. + * Immediately tries to apply a mood to the examiner, ignoring the proximity check. + * If someone wants to make themselves sad through a camera that's their choice I guess. + */ +/datum/proximity_monitor/advanced/war_demoraliser/proc/on_examine(datum/source, mob/examiner) + SIGNAL_HANDLER + if (isliving(examiner)) + on_seen(examiner) + +/** + * Called when someone is looking at a war-related demoralizer. + * Applies a mood if they are conscious and don't already have it. + * Different moods are applied based on their faction. + * + * Arguments + * * viewer - Whoever is looking at this. + */ +/datum/proximity_monitor/advanced/war_demoraliser/proc/on_seen(mob/living/viewer) + if (!viewer.mind) + return + // If you're not conscious you're too busy or dead to look at propaganda + if (viewer.stat != CONSCIOUS) + return + if(viewer.is_blind()) + return + if (!should_demoralise(viewer)) + return + if(!viewer.can_read(host, reading_requirements, TRUE)) //if it's a text based demoralization datum, make sure the mob has the capability to read. if it's only an image, make sure it's just bright enough for them to see it. + return + + var/target_faction = viewer.mind.war_faction + var/datum/mood_event/mood = faction_moods[target_faction] + if (isnull(mood)) + return + viewer.add_mood_event(mood_category, mood) + var/list/reactions = faction_reactions[target_faction] + if (isnull(reactions)) + return + var/reaction = pick_weight(reactions) + to_chat(viewer, span_notice(reaction)) + +/** + * Returns true if user is capable of experiencing moods and doesn't already have the one relevant to this datum, false otherwise. + * + * Arguments + * * viewer - Whoever just saw the parent. + */ +/datum/proximity_monitor/advanced/war_demoraliser/proc/should_demoralise(mob/living/viewer) + if (!viewer.mob_mood) + return FALSE + + return !viewer.mob_mood.has_mood_of_category(mood_category) diff --git a/modular_doppler/STORY_teshari_war/war_posters/icons/posters.dmi b/modular_doppler/STORY_teshari_war/war_posters/icons/posters.dmi new file mode 100644 index 00000000000000..2675ad7bb58825 Binary files /dev/null and b/modular_doppler/STORY_teshari_war/war_posters/icons/posters.dmi differ diff --git a/modular_doppler/STORY_teshari_war/war_posters/readme.txt b/modular_doppler/STORY_teshari_war/war_posters/readme.txt new file mode 100644 index 00000000000000..f1570de89c55eb --- /dev/null +++ b/modular_doppler/STORY_teshari_war/war_posters/readme.txt @@ -0,0 +1,7 @@ +This module is not to be deleted on conclusion of the event arc. + +It is to be reflavored to be post-war, and less in the way. + +1. Remove mood changes - mood.dm and war_moralisation.dm can be deleted +2. Rewrite posters to be in past tense, possibly commenting on the events of the war +3. Possibly remove the boxes from cargo, or some variation diff --git a/modular_doppler/donation_box/donation_box.dm b/modular_doppler/donation_box/donation_box.dm new file mode 100644 index 00000000000000..4cfd8fd1897488 --- /dev/null +++ b/modular_doppler/donation_box/donation_box.dm @@ -0,0 +1,59 @@ +/obj/structure/closet/crate/donation + name = "donation box" + desc = "A steel crate, modified into a donation box via a small slot on the top. Allows insertion of items without allowing removal." + icon = 'modular_doppler/donation_box/icons/donation_box.dmi' + icon_state = "donation_box" + base_icon_state = "donation_box" + +/obj/structure/closet/crate/donation/secure + name = "secure donation box" + desc = "A steel crate, modified into a donation box via a small slot on the top. Allows insertion of items without allowing removal." + icon = 'modular_doppler/donation_box/icons/donation_box.dmi' + icon_state = "securedonation_box" + base_icon_state = "securedonation_box" + secure = TRUE + card_reader_installed = TRUE + +/obj/structure/closet/crate/donation/examine(mob/user) + . = ..() + + . += span_smallnotice("When closed, you can [EXAMINE_HINT("Right-Click")] with an item to place it in the box, if able.") + +/obj/structure/closet/crate/donation/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + if (opened) + return NONE + if (user.combat_mode) + return NONE + if (!LAZYACCESS(modifiers, RIGHT_CLICK)) + return NONE + if (!insertion_allowed(tool)) + balloon_alert(user, "can't fit it in!") + return NONE + + user.balloon_alert_to_viewers("inserts [tool]", "inserted [tool]") + user.visible_message( + span_notice("[user] inserts [tool] into the small slot on [src]."), + span_notice("You insert [tool] into the small slot on [src].") + ) + + if (insert(tool)) + return ITEM_INTERACT_SUCCESS + return NONE + +/obj/item/donation_box_kit + icon = 'icons/obj/storage/box.dmi' + icon_state = "plasticbox" + name = "donation kit" + desc = "Contains a folded donation box, with an access lock and a few tools inside." + +/obj/item/donation_box_kit/attack_self(mob/user, modifiers) + user.balloon_alert_to_viewers("deploying...") + if (!do_after(user, 3 SECONDS, src)) + return FALSE + var/obj/structure/closet/crate/donation/secure/box = new /obj/structure/closet/crate/donation/secure(get_turf(user)) + new /obj/item/hand_labeler(box) + playsound(src, 'sound/machines/terminal/terminal_eject.ogg', 70, TRUE) + qdel(src) + + return TRUE + diff --git a/modular_doppler/donation_box/icons/donation_box.dmi b/modular_doppler/donation_box/icons/donation_box.dmi new file mode 100644 index 00000000000000..757eb8ffa64287 Binary files /dev/null and b/modular_doppler/donation_box/icons/donation_box.dmi differ diff --git a/modular_doppler/donation_box/loadout.dm b/modular_doppler/donation_box/loadout.dm new file mode 100644 index 00000000000000..ae6eb4e8a82617 --- /dev/null +++ b/modular_doppler/donation_box/loadout.dm @@ -0,0 +1,3 @@ +/datum/loadout_item/pocket_items/equipment/donation_kit + name = "Donation Kit" + item_path = /obj/item/donation_box_kit diff --git a/modular_doppler/modular_crafting/code/sheet_types.dm b/modular_doppler/modular_crafting/code/sheet_types.dm index 6f546d20248b44..5978e0041c4997 100644 --- a/modular_doppler/modular_crafting/code/sheet_types.dm +++ b/modular_doppler/modular_crafting/code/sheet_types.dm @@ -25,6 +25,7 @@ GLOBAL_LIST_INIT(doppler_metal_recipes, list( new/datum/stack_recipe("forge", /obj/structure/reagent_forge, 10, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_TOOLS), new/datum/stack_recipe("throwing wheel", /obj/structure/throwing_wheel, 10, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_TOOLS), new/datum/stack_recipe("metal shelf", /obj/structure/shelf, 1, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), + new/datum/stack_recipe("donation box", /obj/structure/closet/crate/donation, 10, time = 3 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_CONTAINERS), )) GLOBAL_LIST_INIT(doppler_metal_airlock_recipes, list( diff --git a/tgstation.dme b/tgstation.dme index 8c5e2bbe8d8f2c..394195ba6092e3 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -466,6 +466,7 @@ #include "code\__DEFINES\~doppler_defines\speech_channels.dm" #include "code\__DEFINES\~doppler_defines\strippable.dm" #include "code\__DEFINES\~doppler_defines\teshari.dm" +#include "code\__DEFINES\~doppler_defines\TESHARI_WAR_defines.dm" #include "code\__DEFINES\~doppler_defines\text.dm" #include "code\__DEFINES\~doppler_defines\traits.dm" #include "code\__DEFINES\~doppler_defines\vehicles.dm" @@ -6934,6 +6935,8 @@ #include "modular_doppler\deforest_medical_items\code\vulnerable_status_effect.dm" #include "modular_doppler\deforest_medical_items\code\chemicals\demoneye.dm" #include "modular_doppler\disable_suicide\config_entries.dm" +#include "modular_doppler\donation_box\donation_box.dm" +#include "modular_doppler\donation_box\loadout.dm" #include "modular_doppler\doppler_command_uniforms\hop\overrides.dm" #include "modular_doppler\emotes\code\emotes.dm" #include "modular_doppler\emotes\code\hologram.dm" @@ -7744,6 +7747,15 @@ #include "modular_doppler\starter_resources\ore_vent.dm" #include "modular_doppler\stone\code\ore_veins.dm" #include "modular_doppler\stone\code\stone.dm" +#include "modular_doppler\STORY_teshari_war\config.dm" +#include "modular_doppler\STORY_teshari_war\mind.dm" +#include "modular_doppler\STORY_teshari_war\preferences.dm" +#include "modular_doppler\STORY_teshari_war\supply_pack.dm" +#include "modular_doppler\STORY_teshari_war\war_posters\code\cargo.dm" +#include "modular_doppler\STORY_teshari_war\war_posters\code\loadout.dm" +#include "modular_doppler\STORY_teshari_war\war_posters\code\mood.dm" +#include "modular_doppler\STORY_teshari_war\war_posters\code\posters.dm" +#include "modular_doppler\STORY_teshari_war\war_posters\code\war_moralisation.dm" #include "modular_doppler\super_glasses\code\glasses_stats_thief.dm" #include "modular_doppler\super_glasses\code\techno_visors.dm" #include "modular_doppler\suuuper_trustworthy_item_orders\code\chem_containers.dm" diff --git a/tgui/packages/tgui/interfaces/Cargo/CargoCatalog.tsx b/tgui/packages/tgui/interfaces/Cargo/CargoCatalog.tsx index dbc019cacf081b..f20f13a1392bcc 100644 --- a/tgui/packages/tgui/interfaces/Cargo/CargoCatalog.tsx +++ b/tgui/packages/tgui/interfaces/Cargo/CargoCatalog.tsx @@ -198,6 +198,10 @@ function CatalogList(props: CatalogListProps) { } const privateBuy = (self_paid && !pack.goody) || app_cost; + const unavailable = pack.shortagemult === -1; + const shortageString = unavailable + ? 'UNAVAILABLE!' + : `${pack.shortagemult}x cost`; const tooltipIcon = (content: string, icon: string, color: string) => ( @@ -214,7 +218,9 @@ function CatalogList(props: CatalogListProps) { dmIconState={pack.first_item_icon_state} imageSize={32} color={color} - disabled={(amount_by_name[pack.name] || 0) >= max_order} + disabled={ + (amount_by_name[pack.name] || 0) >= max_order || unavailable + } buttonsAlt={ diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dopplershift_preferences/war_faction.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dopplershift_preferences/war_faction.tsx new file mode 100644 index 00000000000000..2b2d39043a82e8 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dopplershift_preferences/war_faction.tsx @@ -0,0 +1,16 @@ +import type { + FeatureChoiced, + FeatureChoicedServerData, + FeatureValueProps, +} from '../base'; +import { FeatureDropdownInput } from '../dropdowns'; + +export const doppler_war_faction: FeatureChoiced = { + name: 'War Alignment', + description: 'The stance your character takes on the Tizira/Teshari war.', + component: ( + props: FeatureValueProps, + ) => { + return ; + }, +};