diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm index e8295e0fa62..bbc940d9617 100644 --- a/code/game/objects/structures/crates_lockers/crates.dm +++ b/code/game/objects/structures/crates_lockers/crates.dm @@ -20,6 +20,18 @@ var/obj/item/paper/fluff/jobs/cargo/manifest/manifest var/base_icon_state +//CC EDIT +/obj/structure/closet/crate/attackby(obj/item/W, mob/user, params) + if(istype(W, /obj/item/fulton) && (!opened)) + user.visible_message("[user] attaches a fulton to the [src]", "You attach a fulton to the [src]") + fulton = TRUE + qdel(W) + if(istype(W,/obj/item/drop_signal_horn) && (!opened)) + var/obj/item/drop_signal_horn/dsh = W + dsh.sendCrate(user, src) + . = ..() +//CC EDIT END + /obj/structure/closet/crate/Initialize() . = ..() if(!base_icon_state) diff --git a/code/modules/cargo/packsrogue/_rogue.dm b/code/modules/cargo/packsrogue/_rogue.dm index 888fcb56e50..0e1b150b9ea 100644 --- a/code/modules/cargo/packsrogue/_rogue.dm +++ b/code/modules/cargo/packsrogue/_rogue.dm @@ -11,4 +11,4 @@ if(cost == initial(cost) && !static_cost) var/na = max(round(cost * randomprice_factor, 1), 1) cost = max(rand(cost-na, cost+na), 1) -#endif \ No newline at end of file +#endif diff --git a/code/modules/jobs/job_types/roguetown/adventurer/trader.dm b/code/modules/jobs/job_types/roguetown/adventurer/trader.dm index af54a0f70a3..a09d19cb775 100644 --- a/code/modules/jobs/job_types/roguetown/adventurer/trader.dm +++ b/code/modules/jobs/job_types/roguetown/adventurer/trader.dm @@ -32,5 +32,8 @@ /datum/advclass/trader/cuisiner, /datum/advclass/trader/peddler, /datum/advclass/trader/servant, - /datum/advclass/trader/doomsayer + /datum/advclass/trader/doomsayer, + //CC Edit + /datum/advclass/trader/travelling_merchant + //CC Edit ned ) diff --git a/code/modules/roguetown/roguemachine/mail.dm b/code/modules/roguetown/roguemachine/mail.dm index 8eb715d76e9..fbdbc2d5684 100644 --- a/code/modules/roguetown/roguemachine/mail.dm +++ b/code/modules/roguetown/roguemachine/mail.dm @@ -126,11 +126,21 @@ data["paper_cost"] = 1 data["quill_cost"] = 5 data["letter_cost"] = 1 + //CC Edit + var/datum/component/travelling_merchant/tmc = user.GetComponent(/datum/component/travelling_merchant) + if(tmc) + data["travellingmerchant_static"] = tmc.ui_static_data_fill_in() + //CC Edit End return data /obj/structure/roguemachine/mail/ui_data(mob/user) var/list/data = list() data["balance"] = coin_loaded + //CC Edit + var/datum/component/travelling_merchant/tmc = user.GetComponent(/datum/component/travelling_merchant) + if(tmc) + data["travellingmerchant"] = tmc.ui_dynamic_data_fill_in() + //CC Edit end return data /obj/structure/roguemachine/mail/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) @@ -223,6 +233,15 @@ coin_loaded = 0 update_icon() return TRUE + //CC Edit + if("addToCart") + var/datum/component/travelling_merchant/tmc = user.GetComponent(/datum/component/travelling_merchant) + if(tmc) + tmc.add_to_cart(params["pckpath"]) + return TRUE + //CC Edit End + + /obj/structure/roguemachine/mail/attackby(obj/item/P, mob/user, params) if(istype(P, /obj/item/merctoken)) @@ -670,6 +689,7 @@ if(href_list["directory"]) view_directory(usr) + return /obj/structure/roguemachine/mail/proc/view_directory(mob/user) var/dat diff --git a/modular_causticcove/code/__DEFINES/supplies.dm b/modular_causticcove/code/__DEFINES/supplies.dm new file mode 100644 index 00000000000..144f326c9ae --- /dev/null +++ b/modular_causticcove/code/__DEFINES/supplies.dm @@ -0,0 +1,7 @@ +#define SUPPLY_TIER_BUDGET "budget" +#define SUPPLY_TIER_COMMON "common" +#define SUPPLY_TIER_GOOD "good" +#define SUPPLY_TIER_EXCELLENT "excellent" +#define SUPPLY_TIER_RESERVE "royal reserve" + + diff --git a/modular_causticcove/code/modules/supplies/supplies.dm b/modular_causticcove/code/modules/supplies/supplies.dm new file mode 100644 index 00000000000..e69de29bb2d diff --git a/modular_causticcove/code/modules/supplies/supplyface.dm b/modular_causticcove/code/modules/supplies/supplyface.dm new file mode 100644 index 00000000000..5150ebed857 --- /dev/null +++ b/modular_causticcove/code/modules/supplies/supplyface.dm @@ -0,0 +1,65 @@ +/obj/structure/roguemachine/supplyface + name = "SUPPLYFACE" + desc = "A specialized goldface, which, instead of paying with coins, accepts favours from the Azurian Mercenary's Guild." + icon = 'icons/roguetown/misc/machines.dmi' + icon_state = "streetvendor1" //Placeholder :tm: + var/favours = 100 + var/cooldown = 0 + +/obj/structure/roguemachine/supplyface/Initialize() + . = ..() + +/obj/structure/roguemachine/supplyface/attackby(obj/item/P, mob/user, params) + if(istype(P, /obj/item/voucher/quest)) + favours += 50 + playsound(loc, 'sound/misc/machinevomit.ogg', 100, TRUE, -1) + say("Genuine voucher accepted!") + qdel(P) + +/obj/structure/roguemachine/supplyface/attack_hand(mob/living/user) + var/datum/job/mob_job = user.job ? SSjob.GetJob(user.job) : null + if(istype(mob_job, /datum/job/roguetown/merchant)) + say("Welcome "+ user.name + "... contact with the Mercenary's Guild estabilished.") + ui_interact(user) + else + say(user.name + " is not authorized as a merchant. This incident will be reported.") + return + +/obj/structure/roguemachine/supplyface/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Supplies", "Order Supplies") + ui.open() + + + +/obj/structure/roguemachine/supplyface/ui_static_data(mob/user) + var/list/data = list() + data["favours"] = favours + + data["supplymails"] = list() + + data["supplymails"]["categories"] = list() + + data["supplymails"]["categories"]["Potions"] = list() + + AddSupplyMailToList(data["supplymails"]["categories"]["Potions"], /datum/supply_mail/potions) + + AddSupplyMailToList(data["supplymails"]["categories"]["Potions"], /datum/supply_mail/potions/health) + + AddSupplyMailToList(data["supplymails"]["categories"]["Potions"], /datum/supply_mail/potions/mana) + + return data + +/obj/structure/roguemachine/supplyface/proc/AddSupplyMailToList(list/appending, datum/supply_mail/sm) + appending[sm::name] = list( + "path" = sm, + "price" = sm.cost, + "desc" = sm.desc, + "tier" = sm.supply_tier, + "contents" = list(), + recipents = sm.recipents + ) + for(var/path in sm.contents) + var/atom/A = path + appending[sm::name]["contents"] += A.name + "\n" diff --git a/modular_causticcove/code/modules/supplies/supplyface_datum.dm b/modular_causticcove/code/modules/supplies/supplyface_datum.dm new file mode 100644 index 00000000000..abc1953a806 --- /dev/null +++ b/modular_causticcove/code/modules/supplies/supplyface_datum.dm @@ -0,0 +1,39 @@ +/datum/supplyfacedatum + + var/obj/structure/roguemachine/supplyface/parent + + + +/datum/supplyfacedatum/ui_interact(mob/user, datum/tgui/ui) + + + +/datum/supplyfacedatum/ui_static_data(mob/user) + var/list/data = list() + //data["favous"] = favours + + data["supplymails"]["categories"] = list() + + data["supplymails"]["categories"]["Potions"] = list() + + AddSupplyMailToList(data["supplymails"]["categories"]["Potions"], /datum/supply_mail/potions) + + AddSupplyMailToList(data["supplymails"]["categories"]["Potions"], /datum/supply_mail/potions/health) + + AddSupplyMailToList(data["supplymails"]["categories"]["Potions"], /datum/supply_mail/potions/mana) + + return data + +/datum/supplyfacedatum/proc/AddSupplyMailToList(list/appending, datum/supply_mail/sm) + appending[sm::name] = list( + "path" = sm, + "price" = sm.cost, + "desc" = sm.desc, + "tier" = sm.supply_tier, + "contents" = list(), + recipents = sm.recipents + ) + for(var/path in sm.contents) + var/atom/A = path + appending[sm::name]["contents"] += A.name + "\n" + diff --git a/modular_causticcove/code/modules/supplies/supplymail.dm b/modular_causticcove/code/modules/supplies/supplymail.dm new file mode 100644 index 00000000000..c712abe7536 --- /dev/null +++ b/modular_causticcove/code/modules/supplies/supplymail.dm @@ -0,0 +1,14 @@ +/datum/supply_mail + var/name = "Number fifteen: Burger Duke Foot Cabbage" + var/desc = "If you see this let Mia know..." + var/cost = 0 + var/supply_tier = SUPPLY_TIER_BUDGET + var/list/contents = list( + /obj/item/reagent_containers/food/snacks/grown/cabbage/rogue + ) + var/list/datum/job/recipents = list( + /datum/job/roguetown/merchant + ) + + + diff --git a/modular_causticcove/code/modules/supplies/supplymails/supplymail_ingredients.dm b/modular_causticcove/code/modules/supplies/supplymails/supplymail_ingredients.dm new file mode 100644 index 00000000000..24e22fc7db8 --- /dev/null +++ b/modular_causticcove/code/modules/supplies/supplymails/supplymail_ingredients.dm @@ -0,0 +1,133 @@ +/datum/supply_mail/alchemyingredients + recipents = list( + /datum/job/roguetown/apothecary, + /datum/job/roguetown/physician, + /datum/job/roguetown/wapprentice, + /datum/job/roguetown/magician + ) + +/datum/supply_mail/alchemyingredients/healthpot + name = "Small cache of health potion ingredients" + desc = "Some odds and ends for brewing health potions" + cost = 10 + supply_tier = SUPPLY_TIER_BUDGET + contents = list( + /obj/item/alch/symphitum, + /obj/item/alch/symphitum, + /obj/item/alch/symphitum, + /obj/item/alch/symphitum, + /obj/item/alch/symphitum, + /obj/item/alch/symphitum, + /obj/item/alch/symphitum, + /obj/item/alch/symphitum, + /obj/item/alch/symphitum, + /obj/item/alch/symphitum, + /obj/item/alch/taraxacum, + /obj/item/alch/taraxacum, + /obj/item/alch/taraxacum, + /obj/item/alch/taraxacum, + /obj/item/alch/taraxacum, + /obj/item/alch/taraxacum, + /obj/item/alch/taraxacum, + /obj/item/alch/taraxacum, + /obj/item/alch/taraxacum, + /obj/item/alch/taraxacum, + + ) + + +/datum/supply_mail/alchemyingredients/healthpot + name = "Small cache of strong health potion ingredients" + desc = "Some odds and ends for brewing strong health potions" + cost = 30 + supply_tier = SUPPLY_TIER_BUDGET + contents = list( + /obj/item/alch/calendula, + /obj/item/alch/calendula, + /obj/item/alch/calendula, + /obj/item/alch/calendula, + /obj/item/alch/calendula, + /obj/item/alch/calendula, + /obj/item/alch/calendula, + /obj/item/alch/calendula, + /obj/item/alch/calendula, + /obj/item/alch/calendula, + /obj/item/alch/viscera, + /obj/item/alch/viscera, + /obj/item/alch/viscera, + /obj/item/alch/viscera, + /obj/item/alch/viscera, + /obj/item/alch/viscera, + /obj/item/alch/viscera, + /obj/item/alch/viscera, + /obj/item/alch/viscera, + /obj/item/alch/viscera, + + ) + + +/datum/supply_mail/summoningingredients + recipents = list( + /datum/job/roguetown/wapprentice, + /datum/job/roguetown/magician + ) + + +/datum/supply_mail/summoningingredients/t1 + name = "Begineer's summoning supplies" + desc = "Some odds and ends for begineer summoners, enough for 4 summons of each category" + cost = 10 + supply_tier = SUPPLY_TIER_BUDGET + contents = list( + /obj/item/ash, + /obj/item/ash, + /obj/item/magic/obsidian, + + /obj/item/ash, + /obj/item/ash, + /obj/item/magic/obsidian, + + /obj/item/ash, + /obj/item/ash, + /obj/item/magic/obsidian, + + /obj/item/ash, + /obj/item/ash, + /obj/item/magic/obsidian, + + /obj/item/reagent_containers/food/snacks/grown/manabloom, + /obj/item/reagent_containers/food/snacks/grown/berries/rogue, + + /obj/item/reagent_containers/food/snacks/grown/manabloom, + /obj/item/reagent_containers/food/snacks/grown/berries/rogue, + + /obj/item/reagent_containers/food/snacks/grown/manabloom, + /obj/item/reagent_containers/food/snacks/grown/berries/rogue, + + /obj/item/reagent_containers/food/snacks/grown/manabloom, + /obj/item/reagent_containers/food/snacks/grown/berries/rogue, + + /obj/item/reagent_containers/food/snacks/grown/manabloom, + /obj/item/reagent_containers/food/snacks/grown/berries/rogue, + + /obj/item/natural/stone, + /obj/item/natural/stone, + /obj/item/magic/manacrystal, + + /obj/item/natural/stone, + /obj/item/natural/stone, + /obj/item/magic/manacrystal, + + /obj/item/natural/stone, + /obj/item/natural/stone, + /obj/item/magic/manacrystal, + + /obj/item/natural/stone, + /obj/item/natural/stone, + /obj/item/magic/manacrystal, + + /obj/item/natural/stone, + /obj/item/natural/stone, + /obj/item/magic/manacrystal, + + ) diff --git a/modular_causticcove/code/modules/supplies/supplymails/supplymail_merchant.dm b/modular_causticcove/code/modules/supplies/supplymails/supplymail_merchant.dm new file mode 100644 index 00000000000..0140b36f67e --- /dev/null +++ b/modular_causticcove/code/modules/supplies/supplymails/supplymail_merchant.dm @@ -0,0 +1,41 @@ +/datum/supply_mail/potions + name = "Small cache of potions" + desc = "A variety box of potion bottles" + cost = 50 + supply_tier = SUPPLY_TIER_COMMON + contents = list( + /obj/item/reagent_containers/glass/bottle/rogue/healthpot, + /obj/item/reagent_containers/glass/bottle/rogue/healthpot, + /obj/item/reagent_containers/glass/bottle/rogue/healthpot, + /obj/item/reagent_containers/glass/bottle/rogue/manapot, + /obj/item/reagent_containers/glass/bottle/rogue/manapot, + /obj/item/reagent_containers/glass/bottle/rogue/stampot + ) + recipents = list( + /datum/job/roguetown/merchant, + /datum/job/roguetown/shophand + ) + +/datum/supply_mail/potions/health + name = "Small cache of health potions" + desc = "5 red potions" + cost = 50 + supply_tier = SUPPLY_TIER_BUDGET + contents = list( + /obj/item/reagent_containers/glass/bottle/rogue/healthpot, + /obj/item/reagent_containers/glass/bottle/rogue/healthpot, + /obj/item/reagent_containers/glass/bottle/rogue/healthpot, + /obj/item/reagent_containers/glass/bottle/rogue/healthpot, + /obj/item/reagent_containers/glass/bottle/rogue/healthpot, + ) + +/datum/supply_mail/potions/mana + name = "Tiny cache of mana potions" + desc = "3 blue potions" + cost = 15 + supply_tier = SUPPLY_TIER_BUDGET + contents = list( + /obj/item/reagent_containers/glass/bottle/rogue/manapot, + /obj/item/reagent_containers/glass/bottle/rogue/manapot, + /obj/item/reagent_containers/glass/bottle/rogue/manapot + ) diff --git a/modular_causticcove/code/modules/supplies/travellingmerchant.dm b/modular_causticcove/code/modules/supplies/travellingmerchant.dm new file mode 100644 index 00000000000..4bfea67e304 --- /dev/null +++ b/modular_causticcove/code/modules/supplies/travellingmerchant.dm @@ -0,0 +1,474 @@ +/datum/advclass/trader/travelling_merchant + name = "Travelling Merchant" + tutorial = "You are a merchant forever on the move, stopping by for this week in the duchy of Azure Peak. While this isn't your home, you are extremely well connected, and can aquire goods for half the normal cost by pulling favours and rank, although getting to said supplies might be a bit bothersome. Better hire some mercs! Whenever you set up your own little peddling place, or work to supply the city's own merchant, keep in mind that you have little use for mammons, and would rather use them to expand your influence, as you are a multinational businessperson, and have little desire for local currency." + allowed_sexes = list(MALE, FEMALE) + allowed_races = RACES_ALL_KINDS + category_tags = list(CTAG_TRADER, CTAG_COURTAGENT, CTAG_LICKER_WRETCH) + subclass_skills = list( + /datum/skill/combat/swords = SKILL_LEVEL_APPRENTICE, + /datum/skill/combat/knives = SKILL_LEVEL_APPRENTICE, + /datum/skill/misc/reading = SKILL_LEVEL_MASTER, + /datum/skill/misc/sneaking = SKILL_LEVEL_APPRENTICE, + /datum/skill/misc/stealing = SKILL_LEVEL_APPRENTICE, + /datum/skill/craft/cooking = SKILL_LEVEL_JOURNEYMAN, + /datum/skill/misc/riding = SKILL_LEVEL_JOURNEYMAN, + /datum/skill/combat/firearms = SKILL_LEVEL_APPRENTICE, + /datum/skill/craft/crafting = SKILL_LEVEL_APPRENTICE + ) + class_select_category = CLASS_CAT_TRADER + outfit = /datum/outfit/job/roguetown/adventurer/travelling_merchant + subclass_stats = list( + STATKEY_PER = 2, + STATKEY_INT = 2, + ) + traits_applied = list(TRAIT_SEEPRICES, TRAIT_CICERONE) + +/datum/outfit/job/roguetown/adventurer/travelling_merchant/pre_equip(mob/living/carbon/human/H) + ..() + to_chat(H, span_warning("You are a merchant forever on the move, stopping by for this week in the duchy of Azure Peak. While this isn't your home, you are extremely well connected, and can aquire goods for half the normal cost by pulling favours and rank, although getting to said supplies might be a bit bothersome. Better hire some mercs! Whenever you set up your own little peddling place, or work to supply the city's own merchant, keep in mind that you have little use for mammons, and would rather use them to expand your influence, as you are a multinational businessperson, and have little desire for local currency.")) + //Morshu drip + shoes = /obj/item/clothing/shoes/roguetown/boots + pants = /obj/item/clothing/under/roguetown/tights/green + shirt = /obj/item/clothing/suit/roguetown/shirt/tunic/orange + armor = /obj/item/clothing/suit/roguetown/armor/leather/heavy/jacket + head = /obj/item/clothing/head/roguetown/archercap + belt = /obj/item/storage/belt/rogue/leather + beltl = /obj/item/gun/ballistic/arquebus_pistol + beltr = /obj/item/rogueweapon/scabbard/sheath/courtphysician + backl = /obj/item/storage/backpack/rogue/satchel + backr = /obj/item/storage/backpack/rogue/backpack/bagpack + neck = /obj/item/quiver/bulletpouch/iron + r_hand = /obj/item/rogueweapon/sword/rapier/courtphysician + //Signal horn + fultons + other slop + backpack_contents = list( + /obj/item/powderflask = 1, + /obj/item/drop_signal_horn = 1, + /obj/item/fulton = 5, + /obj/item/flashlight/flare/torch/lantern = 1, //Lampoil? + /obj/item/rope = 1, //Rope? + /obj/item/bomb = 1, //Bomb? + /obj/item/storage/belt/rogue/pouch/merchant/coins = 1, + ) + //H.mind.AddSpell(new /obj/effect/proc_holder/spell/invoked/travelling_merchant/checkfavours) + //H.mind.AddSpell(new /obj/effect/proc_holder/spell/invoked/travelling_merchant_sourcegoods) + //H.mind.AddSpell(new /obj/effect/proc_holder/spell/invoked/travelling_merchant_sellgoods) + //H.mind.AddSpell(new /obj/effect/proc_holder/spell/invoked/travelling_merchant_exploitmarket) + H.AddComponent(/datum/component/travelling_merchant) + + +/*/obj/effect/proc_holder/spell/invoked/travelling_merchant/proc/getFavours(mob/living/user) + var/datum/travelling_merchant = user.GetComponent(datum/travelling_merchant) + return travelling_merchant.favours + +/obj/effect/proc_holder/spell/invoked/travelling_merchant/checkfavours + name = "Check favours" + desc = "Using your trusty journal, you can take a moment to remember how much clout you have with your connections." + +/obj/effect/proc_holder/spell/invoked/travelling_merchant/checkfavours/cast(mob/living/user) + var favours = getFavours(user) + to_chat(user, span_info("According to these pages, once you add everything up, it comes out to around [favours] mammons worth of clout.")) + +/obj/effect/proc_holder/spell/invoked/travelling_merchant/sourcegoods + name = "Source goods" + desc = "Use it on a hermes post to contact suppliers, arranging a dead drop for you to fetch.\nCooldown and package location difficulty is dependent on the amount of favours you are using." + + + +/obj/effect/proc_holder/spell/invoked/travelling_merchant/sellgoods + name = "Sell goods" + desc = "Use it on a hermes post to contact buyers, arranging a dead drop for you to deliver.\nCooldown and package location difficulty is dependent on the amount of favours you are getting." + +/obj/effect/proc_holder/spell/invoked/travelling_merchant/exploitmarket + name = "Exploit market" + desc = "Use it on a hermes post to contact counting houses, aquiring information on the favourable imports and exports of the world.\nCooldown and package location difficulty is dependent on the amount of favours you are using or getting." +*/ + +/datum/component/travelling_merchant + var/favours = 300 + var/favourtimer + var/list/allcats = list( + "Alcohols", + "Apparel", + "Consumable", + "Gems", + "Instruments", + "Luxury", + "Livestock", + "Cosmetics", + "Raw Materials", + "Seeds", + "Tools", + "Wardrobe", + "Adventuring Supplies", + "Armor (Light)", + "Armor (Iron)", + "Armor (Steel)", + "Armor (Exotic)", + "Potions", + "Weapons (Ranged)", + "Weapons (Iron and Shields)", + "Weapons (Steel)", + "Weapons (Foreign)", + "Diplomacy and Persuasion", + "Beverages", + "Exotic Import", + "General Labour", + "Health and Hygiene", + "Self Defense", + "Travelling Merchant", + "Private Workshop") + var/list/unlockedcats = list( + "Travelling Merchant", + "Private Workshop" + ) + var/catunlockspending = 6 + var/list/current_cart = list() + +/datum/component/travelling_merchant/Initialize(...) + . = ..() + favourtimer = addtimer(CALLBACK(src, PROC_REF(AddFavoursOverTime)),5 MINUTES, TIMER_STOPPABLE | TIMER_LOOP) + var/choice = SelectCategory() + + while(choice && catunlockspending > 0) + catunlockspending -= 1 + unlockedcats += choice + if(catunlockspending > 0) + choice = SelectCategory() + +/datum/component/travelling_merchant/proc/SelectCategory() + var/list/catchoices = allcats - unlockedcats + var/choice = tgui_input_list(parent,"Category slots currently left: [catunlockspending]","Choose your starting categories. You can choose additional categories later, at any hermes, and buy additional slots as well.",catchoices) + return choice + +/datum/component/travelling_merchant/proc/AddFavoursOverTime() + favours += 50 + to_chat(parent,"Your previous deals still reverberate through your channels. Their debts, material or sentimental ever incuring interest... you are now 50 favours richer, for a total of [favours] mammons worth of clout.") + +/datum/component/travelling_merchant/Destroy() + deltimer(favourtimer) + favourtimer = null + . = ..() + +/datum/component/travelling_merchant/proc/ui_static_data_fill_in() + var/list/data = list() + data["supplypacks"] = generate_supplypacks_data(SSmerchant.supply_packs, allcats) + return data + + +/datum/component/travelling_merchant/proc/ui_dynamic_data_fill_in() + var/list/data = list() + data["favours"] = favours + data["unlockedCats"] = unlockedcats + data["catunlockspending"] = catunlockspending + data["currentcart"] = generate_supplypacks_data(current_cart, unlockedcats) + return data + +/datum/component/travelling_merchant/proc/generate_supplypacks_data(sps, filtergroup) + var/list/supplypacks = list() + for(var/pack in sps) + var/datum/supply_pack/PA + if(sps[pack]) + PA = sps[pack] + else if(pack) + PA = pack + if(!PA.group) + continue + if(!(PA.group in filtergroup)) + continue + if(!supplypacks[PA.group]) + supplypacks[PA.group] = list() + var/list/PAL = list() + PAL["group"] = PA.group + PAL["cost"] = PA.cost + PAL["name"] = PA.name + PAL["desc"] = PA.desc + PAL["path"] = PA.type + supplypacks[PA.group][PA.type] = PAL + return supplypacks + +/datum/component/travelling_merchant/proc/add_to_cart(path) + if(ispath(text2path(path), /datum/supply_pack)) + var/datum/supply_pack/pacc = text2path(path) + if((pacc.group in unlockedcats) && (favours >= pacc.cost)) + + current_cart += pacc + favours -= pacc.cost + to_chat(parent, span_info("Your suppliers have been notified, and it is already being loaded to a balloon. Use your horn to call it in!")) + + +/obj/item/drop_signal_horn + name = "drop signal horn" + desc = "A horn capable of signalling your position to passing by trading balloons. If you know the right people, you can use one of these to call in your contractors to fulfill their obligations, and/or take goods off your hands. Keep in mind, this may attract people thirsty for your goods!" + icon = 'icons/obj/items/signalhorn.dmi' + icon_state = "signalhorn" + slot_flags = ITEM_SLOT_HIP|ITEM_SLOT_NECK + w_class = WEIGHT_CLASS_NORMAL + grid_height = 32 + grid_width = 64 + var/obj/effect/landmark/quest_spawner/attunedmark + var/bloon = FALSE + +/obj/item/drop_signal_horn/examine() + . = ..() + if(attunedmark) + . += "The horn is currently attuned to a landmark at the moment.\n" + . += get_target_location() + else + . += "The horn is currently unattuned. You can attune it by blowing it, signalling your contractor's balloon to pick a place, after which, the horn will lead you to the meeting point. Once there, you'll have to blow the horn again, to signal that it's you. It will then unload cargo meant for you, and give you 10 minutes to fulton up any goods of your own." + +/obj/item/drop_signal_horn/proc/createCrate(mob/living/user, datum/component/travelling_merchant/tmc) + var/obj/structure/closet/crate/chest/C = new(get_turf(user)) + for(var/currpacc in tmc.current_cart) + var/datum/supply_pack/rogue/currpacccasted = SSmerchant.supply_packs[currpacc] + for(var/it in currpacccasted.contains) + new it(C) + tmc.current_cart -= currpacc + C.visible_message("The balloon drops a crate!") + +/obj/item/drop_signal_horn/proc/sendCrate(mob/living/user, obj/structure/closet/crate/C) + + var/datum/component/travelling_merchant/tmc = user.GetComponent(/datum/component/travelling_merchant) + if(!tmc) + return + var/turf/CT = get_turf(C) + if(attunedmark && (get_turf(attunedmark) == CT) && bloon) + if(C.fulton) + CT.visible_message("The [C]'s fulton activates, and the crate flies off to the skies, ready to be picked up by the balloon!") + var/imakebigmoney = 0 + for(var/obj/item/iteminstance in C.contents) + var/itemvalue = iteminstance.get_real_price() + if(itemvalue) + imakebigmoney += itemvalue + qdel(iteminstance) + qdel(C) + imakebigmoney = round(imakebigmoney) + to_chat(user, span_good("You have just sent up [imakebigmoney] mammons worth of goodies!")) + tmc.favours += imakebigmoney + else + to_chat(user,span_warning("Attach a fulton first!")) + else + to_chat(user, span_warning("There is no balloon overhead, or it isn't ready to take your package!")) + +/obj/item/drop_signal_horn/proc/bloongohome() + attunedmark.visible_message("The balloon leaves.") + if(prob(1)) + attunedmark.visible_message("A honeyspider waves from the balloon...? Wait who is piloting this thing?") + attunedmark = null + bloon = FALSE + + +/obj/item/drop_signal_horn/attack_self(mob/living/user) + . = ..() + var/datum/component/travelling_merchant/tmc = user.GetComponent(/datum/component/travelling_merchant) + if(!tmc) + to_chat(user, "The horn rejects you...") + var/turf/CT = get_turf(src) + if(attunedmark && (get_turf(attunedmark) == CT) && (!bloon)) + user.visible_message("[user] raises the horn to their mouth, preparing to signal for a balloon...") + user.playsound_local(get_turf(user), 'sound/items/horn/signalhorn.ogg', 35, FALSE, pressure_affected = FALSE) + if(do_after(user, 5 SECONDS)) + if(user.consider_ambush(TRUE, TRUE)) + var/additional_ambushes = rand(0,3) + for(var/i = 0, i user_turf.z ? "[z_diff] level\s above you" : "[z_diff] level\s below you" + var/dx = target_turf.x - user_turf.x // EAST direction + var/dy = target_turf.y - user_turf.y // NORTH direction + var/distance = sqrt(dx*dx + dy*dy) + var/direction_text = get_precise_direction_between(user_turf, target_turf) + var/returnval = "The balloon awaits you [distance] paces to the [direction_text]!" + if(last_z_level_hint) + returnval += "\n[last_z_level_hint], that is." + return returnval + +/obj/item/fulton + name = "fulton device" + desc = "A little package, designed to be attached to storage chests, to be lifted into the air for merchant balloons. While you could use it anywhere... it's kind of pointless to litter the air with free stuff, so be sure you signal for a balloon first!" + icon = 'modular/Neu_Food/icons/cookware/ration.dmi' + icon_state = "ration_small" + w_class = WEIGHT_CLASS_TINY + grid_height = 32 + grid_width = 32 + +/datum/supply_pack/rogue/travelling_merchant + group = "Travelling Merchant" + crate_name = "Mercantile Supplies" + crate_type = /obj/structure/closet/crate/chest + +/datum/supply_pack/rogue/travelling_merchant/dsh + name = "Spare drop signal horn" + cost = 500 + contains = list(/obj/item/drop_signal_horn) + +/datum/supply_pack/rogue/travelling_merchant/fultons + name = "5 fultons" + cost = 10 + contains = list(/obj/item/fulton) + +/datum/supply_pack/rogue/travelling_merchant_pw + group = "Private Workshop" + crate_name = "Private Workshop" + crate_type = /obj/structure/closet/crate/chest + +/datum/supply_pack/rogue/travelling_merchant_pw/enchanting/woodcutting + name = "Woodcutting enchantment scroll" + cost = 100 + contains = list(/obj/item/enchantmentscroll/woodcut) + +/datum/supply_pack/rogue/travelling_merchant_pw/enchanting/mining + name = "Mining enchantment scroll" + cost = 100 + contains = list(/obj/item/enchantmentscroll/mining) + +/datum/supply_pack/rogue/travelling_merchant_pw/enchanting/light + name = "Light enchantment scroll" + cost = 100 + contains = list(/obj/item/enchantmentscroll/light) + +/datum/supply_pack/rogue/travelling_merchant_pw/enchanting/holding + name = "Holding enchantment scroll" + cost = 250 + contains = list(/obj/item/enchantmentscroll/holding) + +/datum/supply_pack/rogue/travelling_merchant_pw/mats/gold + name = "Raw gold" + cost = 65 + contains = list(/obj/item/rogueore/gold) + +/datum/supply_pack/rogue/travelling_merchant_pw/mats/iron + name = "Raw iron" + cost = 9 + contains = list(/obj/item/rogueore/iron) + +/datum/supply_pack/rogue/travelling_merchant_pw/mats/coal + name = "Coal" + cost = 7 + contains = list(/obj/item/rogueore/coal) + +/datum/supply_pack/rogue/travelling_merchant_pw/mats/log + name = "Large wooden log" + cost = 3 + contains = list(/obj/item/grown/log/tree) + +/datum/supply_pack/rogue/travelling_merchant_pw/usables/repairpoor + name = "Budget repair kit" + cost = 50 + contains = list(/obj/item/repair_kit/bad, /obj/item/repair_kit/metal/bad) + +/datum/supply_pack/rogue/travelling_merchant_pw/usables/emmed + name = "Individual First Aid Pouch" + cost = 30 + contains = list(/obj/item/storage/belt/rogue/pouch/medicine) + +/datum/supply_pack/rogue/travelling_merchant_pw/usables/emmed + name = "Mercenary First Aid Pouch" + cost = 60 + contains = list(/obj/item/storage/belt/rogue/pouch/medicine/merc) + + +/datum/supply_pack/rogue/travelling_merchant_pw/food/misterymeat + name = "Mistery meat...?" //Hehe + cost = 1 + contains = list (/obj/item/ration/misterymeat) + + + + +/obj/item/storage/belt/rogue/pouch/medicine/merc + populate_contents = list( + /obj/item/needle, + /obj/item/natural/cloth/presoaked/advanced, + /obj/item/natural/cloth/presoaked/advanced, + /obj/item/reagent_containers/glass/bottle/alchemical/healthpotnew + ) + + +/obj/item/natural/cloth/presoaked/advanced + name = "Grenzelcloth" + +/obj/item/natural/cloth/presoaked/advanced/Initialize() + . = ..() + medicine_quality = 1 + medicine_amount = 60 + desc += " This one has been imbued masterfully in a mixed medicinal coating..." + detail_color = "#820000" + +#define MISTERYMEAT_LIST list(\ + /obj/item/reagent_containers/food/snacks/rogue/meat/steak = 5,\ + /obj/item/reagent_containers/food/snacks/rogue/meat_rotten = 2,\ + /obj/item/reagent_containers/food/snacks/rogue/meat/spider = 2,\ + /obj/item/reagent_containers/food/snacks/rogue/meat/fatty = 1,\ + /obj/item/reagent_containers/food/snacks/rogue/meat/poultry = 4,\ + /obj/item/reagent_containers/food/snacks/rogue/meat/crab = 3,\ + /obj/item/reagent_containers/food/snacks/rogue/meat/rabbit = 4,\ + /obj/item/reagent_containers/food/snacks/rogue/meat/steak/wolf = 2,\ + /obj/item/reagent_containers/food/snacks/rogue/meat/fish = 5,\ + /obj/item/reagent_containers/food/snacks/rogue/meat/shellfish = 4,\ +) + +/obj/item/ration/misterymeat/Initialize() + . = ..() + var/foodstuffs = pickweight(MISTERYMEAT_LIST) //LET'S GO GAMBLING! + food = new foodstuffs(src) + food.rotprocess = FALSE + name = "Mistery meat..." + desc = "Who knows what's in it..." + icon_state = "ration_large" + + + +/obj/structure/closet/crate + var/fulton = FALSE + + +/obj/item/clothing/suit/roguetown/shirt/tunic/orange + color = CLOTHING_ORANGE + + diff --git a/modular_causticcove/code/modules/supplies/voucher.dm b/modular_causticcove/code/modules/supplies/voucher.dm new file mode 100644 index 00000000000..8ccf476b48c --- /dev/null +++ b/modular_causticcove/code/modules/supplies/voucher.dm @@ -0,0 +1,7 @@ +/obj/item/voucher + icon = 'modular_causticcove/icons/items/supplies.dmi' + icon_state = "voucher" + +/obj/item/voucher/quest + name = "Mercenaries' Guild voucher" + desc = "A voucher issued by the Mercenary's Guild, a little ticket representing an owed favour. Can be used for calling in special missions!" diff --git a/modular_causticcove/icons/items/supplies.dmi b/modular_causticcove/icons/items/supplies.dmi new file mode 100644 index 00000000000..5a854299ec2 Binary files /dev/null and b/modular_causticcove/icons/items/supplies.dmi differ diff --git a/roguetown.dme b/roguetown.dme index 59d6443048e..33f899eda92 100644 --- a/roguetown.dme +++ b/roguetown.dme @@ -3132,6 +3132,7 @@ #include "modular_causticcove\code\modules\spells\animagus\zad.dm" #include "modular_causticcove\code\modules\spells\invoked_single_target\temperitem.dm" #include "modular_causticcove\code\modules\spells\components\temper_clothing.dm" +#include "modular_causticcove\code\modules\supplies\travellingmerchant.dm" #include "modular_causticcove\code\modules\taurs\taur_bodyparts.dm" #include "modular_causticcove\code\modules\taurs\taur_markings.dm" #include "modular_causticcove\code\modules\vices\combat_adverse.dm" diff --git a/tgui/packages/tgui/data_types/atom_basic.tsx b/tgui/packages/tgui/data_types/atom_basic.tsx new file mode 100644 index 00000000000..6cfe9c07acd --- /dev/null +++ b/tgui/packages/tgui/data_types/atom_basic.tsx @@ -0,0 +1,5 @@ +import { datum_basic } from "./datum_basic"; + +export type atom_basic = datum_basic & { + +} diff --git a/tgui/packages/tgui/data_types/datum_basic.tsx b/tgui/packages/tgui/data_types/datum_basic.tsx new file mode 100644 index 00000000000..dabd026e946 --- /dev/null +++ b/tgui/packages/tgui/data_types/datum_basic.tsx @@ -0,0 +1,5 @@ +export type datum_basic = { + name: string; + desc: string; + path?: string; +} diff --git a/tgui/packages/tgui/data_types/supply_pack.tsx b/tgui/packages/tgui/data_types/supply_pack.tsx new file mode 100644 index 00000000000..921a39277c7 --- /dev/null +++ b/tgui/packages/tgui/data_types/supply_pack.tsx @@ -0,0 +1,7 @@ +import { atom_basic } from "./atom_basic"; +import { datum_basic } from "./datum_basic"; + +export type merchant_supply_pack = datum_basic & { + group: string; + cost: number; +} diff --git a/tgui/packages/tgui/interfaces/Hermes.tsx b/tgui/packages/tgui/interfaces/Hermes.tsx index 88d7fb1c4ac..0d7159e6ebf 100644 --- a/tgui/packages/tgui/interfaces/Hermes.tsx +++ b/tgui/packages/tgui/interfaces/Hermes.tsx @@ -2,6 +2,7 @@ import { useState } from 'react'; import { Box, Button, + Collapsible, Input, Section, Stack, @@ -9,7 +10,10 @@ import { } from 'tgui-core/components'; import { useBackend } from '../backend'; +import { merchant_supply_pack } from "../data_types/supply_pack"; import { Window } from '../layouts'; +import { SupplyPackSection } from "./common/SupplyPackStack"; + type Data = { balance: number; @@ -17,11 +21,31 @@ type Data = { quill_cost: number; letter_cost: number; has_tube?: boolean; + travellingmerchant_static?: tm_static; + travellingmerchant?: tm; }; +type tm = { + favours: number; + unlockedCats: string[]; + catunlockspending : number; + currentcart: merchant_supply_pack_cat[]; +} + +type tm_static = { + supplypacks: merchant_supply_pack_cat[] +} + +type merchant_supply_pack_cat = { + +} + + + + export const Hermes = (props: any, context: any) => { const { act, data } = useBackend(); - const { balance, paper_cost, quill_cost, letter_cost, has_tube } = data; + const { balance, paper_cost, quill_cost, letter_cost, has_tube, travellingmerchant_static, travellingmerchant } = data; const [recipient, setRecipient] = useState(''); const [sender, setSender] = useState(''); @@ -32,9 +56,23 @@ export const Hermes = (props: any, context: any) => { const canBuyQuill = balance >= quill_cost; const canSendTube = letterContent.length > 0; + const packsByCat = travellingmerchant_static ? travellingmerchant_static.supplypacks : null; + + + const addToCart = (pck : merchant_supply_pack) => { + act("addToCart", { pckpath : pck.path }); + }; + const removeFromCart = (pck : merchant_supply_pack) => { + + }; + + + return ( - - + + + {/* JSON.stringify(packsByCat, null, 4)*/} + { @@ -158,7 +196,59 @@ export const Hermes = (props: any, context: any) => { + { + packsByCat && + ( + + + Current mammons worth of favours: {travellingmerchant!.favours} + + + {/* JSON.stringify(travellingmerchant?.currentcart, null, 4)*/} + { + Object.keys(travellingmerchant!.currentcart).map((key) => ( + + { + Object.keys(travellingmerchant!.currentcart[key]).map((pacckey) => ( + + removeFromCart(travellingmerchant!.currentcart[key][pacckey])} on_buy_txt='Remove from drop' /> + + )) + } + + + )) + } + + {Object.keys(packsByCat).map((key) => ( + + + + {travellingmerchant!.unlockedCats.includes(key) ? + + Object.keys(packsByCat[key]).map((pacckey) => ( + + addToCart(packsByCat[key][pacckey])} on_buy_txt='Add to drop' /> + + )) + + + : + (travellingmerchant!.catunlockspending > 0 ? : ) + } + + + + + )) + } + + + ) + + } + } ); diff --git a/tgui/packages/tgui/interfaces/Supplies.js b/tgui/packages/tgui/interfaces/Supplies.js new file mode 100644 index 00000000000..ba1f7604035 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Supplies.js @@ -0,0 +1,33 @@ +import { useMemo, useState } from 'react'; +import { + Button, + Collapsible, + Input, + LabeledList, + Stack, +} from 'tgui-core/components'; + +import { useBackend } from '../backend'; +import { Window } from '../layouts'; + +export const Supplies = (props, context) => { + const { act, data } = useBackend(); + const [supply_mails] = useState(data.supplymails); + + return( + + + + + { + data["favours"] + } + + + {JSON.stringify(data, null, 2)} + + + + + ); +} diff --git a/tgui/packages/tgui/interfaces/common/InputButtons.tsx b/tgui/packages/tgui/interfaces/common/InputButtons.tsx index 151b61a9459..3019447c638 100644 --- a/tgui/packages/tgui/interfaces/common/InputButtons.tsx +++ b/tgui/packages/tgui/interfaces/common/InputButtons.tsx @@ -20,7 +20,7 @@ export const InputButtons = (props: InputButtonsProps) => { const { act, data } = useBackend(); const { large_buttons, swapped_buttons } = data; const { input, message, on_submit, on_cancel, disabled } = props; - + let on_submit_actual = on_submit; if (!on_submit_actual) { on_submit_actual = () => { diff --git a/tgui/packages/tgui/interfaces/common/SupplyPackStack.tsx b/tgui/packages/tgui/interfaces/common/SupplyPackStack.tsx new file mode 100644 index 00000000000..75160a28736 --- /dev/null +++ b/tgui/packages/tgui/interfaces/common/SupplyPackStack.tsx @@ -0,0 +1,84 @@ +import { Button, Section, Stack } from 'tgui-core/components'; +import { BooleanLike } from "tgui-core/react"; + +import { merchant_supply_pack } from "../../data_types/supply_pack"; + +type SupplyPackSectionProps = { + pack: merchant_supply_pack +} & Partial<{ + on_buy: () => void; + on_buy_txt?: string; + /** Disables the submit button */ + disabled: boolean; + disabled_txt?: string; + budget?: number; + pricemult?: number; + extramult?: number; + tax_amt?: number; + paying_tax?: BooleanLike; + currency?: string; +}> + +export const SupplyPackSection = (props: SupplyPackSectionProps) => { + const { pack, budget, pricemult, extramult, tax_amt, paying_tax, currency, on_buy, on_buy_txt, disabled, disabled_txt } = props; + // Don't you ever be supplying paying_taxt true without also supplying tax_amt Peta, worst mistake of your lyfe! Other way around as well! + const finalprice = ((pack.cost * ((pricemult ? pricemult : 1)+ (extramult ? extramult : 0))) + (paying_tax? tax_amt! : 0)); + const CanBeBought = (budget ? finalprice <= budget : false); + const CostColour = (CanBeBought ? "#00ff00" : "#ff0000"); + let moneytype = currency ? currency : "Mammons"; + /* const PackContents = () => { + return ( +
+ + { + pack.contains.map(cont => (
{cont.desc}
)) + } +
+
+ ); + };*/ + + const BuyBtn = () => { + if(disabled) { + return ( + + ); + } + else{ + return ( + + ); + } + }; + + + return( +
+ + + Cost: + + + + + + Base price: {pack.cost} + + {pricemult? "" : (Price Multiplier: {pricemult})} + {extramult? "" : (Commission Multiplier: {extramult})} + {tax_amt? "" : (paying_tax ? (Tax: {tax_amt}) : (Tax: {tax_amt}... in theory.))} + + Final price: {finalprice} {moneytype} + + + + + + {BuyBtn()} + + +
+ ); + + +};