From 29bc9174bdf343eb7d5e835f63fc25abbdea3cd1 Mon Sep 17 00:00:00 2001 From: cacogen <25089914+cacogen@users.noreply.github.com> Date: Wed, 10 Feb 2021 23:17:11 +1300 Subject: [PATCH] Cargo bounty cube incentives (#56375) Bounty cube announces its creation over Supply with its creator and area, starting the speedy delivery bonus countdown 20% bonus for cargo if you send the cube within 5 minutes of its creation. Using an export scanner on it in the supply shuttle awards a 10% personal handling tip when it reaches Centcom. Cube nags at five minutes over Supply if it's not sent and cargo bonus is lost. All nags tell you the cube's area Co-authored-by: coiax --- code/datums/components/pricetag.dm | 24 +++-- code/game/machinery/civilian_bounties.dm | 95 +++++++++++++++++-- code/modules/cargo/export_scanner.dm | 22 ++++- code/modules/cargo/exports/civilain_bounty.dm | 2 +- 4 files changed, 127 insertions(+), 16 deletions(-) diff --git a/code/datums/components/pricetag.dm b/code/datums/components/pricetag.dm index 9cf6a6e4f16..6e38d842a4d 100644 --- a/code/datums/components/pricetag.dm +++ b/code/datums/components/pricetag.dm @@ -1,13 +1,18 @@ /datum/component/pricetag - var/datum/bank_account/owner - var/profit_ratio = 1 + ///Payee gets 100% of the value if no ratio has been set. + var/default_profit_ratio = 1 + ///List of bank accounts this pricetag pays out to. Format is payees[bank_account] = profit_ratio. + var/list/payees = list() /datum/component/pricetag/Initialize(_owner,_profit_ratio) if(!isobj(parent)) //Has to account for both objects and sellable structures like crates. return COMPONENT_INCOMPATIBLE - owner = _owner + if(_profit_ratio) - profit_ratio = _profit_ratio + payees[_owner] = _profit_ratio + else + payees[_owner] = default_profit_ratio + RegisterSignal(parent, list(COMSIG_ITEM_SOLD), .proc/split_profit) RegisterSignal(parent, list(COMSIG_STRUCTURE_UNWRAPPED, COMSIG_ITEM_UNWRAPPED), .proc/Unwrapped) RegisterSignal(parent, list(COMSIG_ITEM_SPLIT_PROFIT, COMSIG_ITEM_SPLIT_PROFIT_DRY), .proc/return_ratio) @@ -22,10 +27,13 @@ var/price = item_value if(price) - var/adjusted_value = price*(profit_ratio/100) - owner.adjust_money(adjusted_value) - owner.bank_card_talk("Sale recorded. [adjusted_value] credits added to account.") + for(var/datum/bank_account/payee in payees) + var/profit_ratio = payees[payee] + var/adjusted_value = price * profit_ratio + var/datum/bank_account/bank_account = payee + bank_account.adjust_money(adjusted_value) + bank_account.bank_card_talk("Sale of [parent] recorded. [adjusted_value] credits added to account.") return TRUE /datum/component/pricetag/proc/return_ratio() - return profit_ratio + return default_profit_ratio diff --git a/code/game/machinery/civilian_bounties.dm b/code/game/machinery/civilian_bounties.dm index cf56fdf89b2..1763f046ce3 100644 --- a/code/game/machinery/civilian_bounties.dm +++ b/code/game/machinery/civilian_bounties.dm @@ -100,13 +100,10 @@ status_report += "Bounty completed! Please give your bounty cube to cargo for your automated payout shortly." inserted_scan_id.registered_account.reset_bounty() SSeconomy.civ_bounty_tracker++ + var/obj/item/bounty_cube/reward = new /obj/item/bounty_cube(drop_location()) - reward.bounty_value = curr_bounty.reward - reward.bounty_name = curr_bounty.name - reward.bounty_holder = inserted_scan_id.registered_name - reward.name = "\improper [reward.bounty_value] cr [reward.name]" - reward.desc += " The tag indicates it was [reward.bounty_holder]'s reward for completing the [reward.bounty_name] bounty and that it was created at [station_time_timestamp(format = "hh:mm")]." - reward.AddComponent(/datum/component/pricetag, inserted_scan_id.registered_account, CIV_BOUNTY_SPLIT) + reward.set_up(curr_bounty, inserted_scan_id) + pad.visible_message("[pad] activates!") flick(pad.sending_state,pad) pad.icon_state = pad.idle_state @@ -247,10 +244,96 @@ icon_state = "bounty_cube" ///Value of the bounty that this bounty cube sells for. var/bounty_value = 0 + ///Multiplier for the bounty payout received by the Supply budget if the cube is sent without having to nag. + var/speed_bonus = 0.2 + ///Multiplier for the bounty payout received by the person who completed the bounty. + var/holder_cut = 0.3 + ///Multiplier for the bounty payout received by the person who claims the handling tip. + var/handler_tip = 0.1 + ///Time between nags. + var/nag_cooldown = 5 MINUTES + ///How much the time between nags extends each nag. + var/nag_cooldown_multiplier = 1.25 + ///Next world tick to nag Supply listeners. + var/next_nag_time ///Who completed the bounty. var/bounty_holder + ///What job the bounty holder had. + var/bounty_holder_job ///What the bounty was for. var/bounty_name + ///Bank account of the person who receives the handling tip. + var/datum/bank_account/bounty_handler_account + ///Bank account of the person who completed the bounty. + var/datum/bank_account/bounty_holder_account + ///Our internal radio. + var/obj/item/radio/radio + ///The key our internal radio uses. + var/radio_key = /obj/item/encryptionkey/headset_cargo + +/obj/item/bounty_cube/Initialize() + . = ..() + radio = new(src) + radio.keyslot = new radio_key + radio.listening = FALSE + radio.recalculateChannels() + +/obj/item/bounty_cube/Destroy() + QDEL_NULL(radio) + . = ..() + +/obj/item/bounty_cube/examine() + . = ..() + if(speed_bonus) + . += "[time2text(next_nag_time - world.time,"mm:ss")] remains until [bounty_value * speed_bonus] credit speedy delivery bonus lost." + if(handler_tip && !bounty_handler_account) + . += "Scan this in the cargo shuttle with an export scanner to register your bank account for the [bounty_value * handler_tip] credit handling tip." + +/obj/item/bounty_cube/process(delta_time) + if(COOLDOWN_FINISHED(src, next_nag_time)) + if(!is_centcom_level(z) && !is_reserved_level(z)) //don't send message if we're on Centcom or in transit + radio.talk_into(src, "Unsent in [get_area(src)].[speed_bonus ? " Speedy delivery bonus of [bounty_value * speed_bonus] credit\s lost." : ""]", RADIO_CHANNEL_SUPPLY) + speed_bonus = 0 + bounty_holder_account.bank_card_talk("\The [src] is unsent in [get_area(src)].") + if(bounty_handler_account) + bounty_handler_account.bank_card_talk("\The [src] is unsent in [get_area(src)].") + nag_cooldown = nag_cooldown * nag_cooldown_multiplier + COOLDOWN_START(src, next_nag_time, nag_cooldown) + +/obj/item/bounty_cube/proc/set_up(datum/bounty/my_bounty, obj/item/card/id/holder_id) + bounty_value = my_bounty.reward + bounty_name = my_bounty.name + bounty_holder = holder_id.registered_name + bounty_holder_job = holder_id.assignment + bounty_holder_account = holder_id.registered_account + name = "\improper [bounty_value] cr [name]" + desc += " The sales tag indicates it was [bounty_holder] ([bounty_holder_job])'s reward for completing the [bounty_name] bounty." + AddComponent(/datum/component/pricetag, holder_id.registered_account, holder_cut) + START_PROCESSING(SSobj, src) + COOLDOWN_START(src, next_nag_time, nag_cooldown) + radio.talk_into(src,"Created in [get_area(src)] by [bounty_holder] ([bounty_holder_job]). Speedy delivery bonus lost in [time2text(next_nag_time - world.time,"mm:ss")].", RADIO_CHANNEL_SUPPLY) + +//for when you need a REAL bounty cube to test with and don't want to do a bounty each time your code changes +/obj/item/bounty_cube/test_cube + name = "debug bounty cube" + desc = "Use in-hand to set it up with a random bounty. Requires an ID it can detect with a bank account attached. \ + This will alert Supply over the radio with your name and location, and cargo techs will be dispatched to your location with kill on sight clearance." + var/set_up = FALSE + +/obj/item/bounty_cube/test_cube/attack_self(mob/user) + if(!isliving(user)) + to_chat(user, "You aren't eligible to use this!") + return ..() + + if(!set_up) + var/mob/living/squeezer = user + if(squeezer.get_bank_account()) + set_up(random_bounty(), squeezer.get_idcard()) + set_up = TRUE + return ..() + to_chat(user, "It can't detect your bank account.") + + return ..() ///Beacon to launch a new bounty setup when activated. /obj/item/civ_bounty_beacon diff --git a/code/modules/cargo/export_scanner.dm b/code/modules/cargo/export_scanner.dm index 048a4429033..3b94361a814 100644 --- a/code/modules/cargo/export_scanner.dm +++ b/code/modules/cargo/export_scanner.dm @@ -13,9 +13,9 @@ . = ..() if(!istype(O) || !proximity) return + // Before you fix it: // yes, checking manifests is a part of intended functionality. - var/datum/export_report/ex = export_item_and_contents(O, dry_run=TRUE) var/price = 0 for(var/x in ex.total_amount) @@ -24,3 +24,23 @@ to_chat(user, "Scanned [O], value: [price] credits[O.contents.len ? " (contents included)" : ""].") else to_chat(user, "Scanned [O], no export value.") + + if(ishuman(user)) + var/mob/living/carbon/human/scan_human = user + if(istype(O, /obj/item/bounty_cube)) + var/obj/item/bounty_cube/cube = O + + if(!istype(get_area(cube), /area/shuttle/supply)) + to_chat(user, "Shuttle placement not detected. Handling tip not registered.") + + else if(cube.bounty_handler_account) + to_chat(user, "Bank account for handling tip already registered!") + + else if(scan_human.get_bank_account() && cube.GetComponent(/datum/component/pricetag)) + var/datum/component/pricetag/pricetag = cube.GetComponent(/datum/component/pricetag) + cube.bounty_handler_account = scan_human.get_bank_account() + pricetag.payees[cube.bounty_handler_account] += cube.handler_tip + cube.bounty_handler_account.bank_card_talk("Bank account for [price ? "[price * cube.handler_tip] credit " : ""]handling tip successfully registered.") + cube.bounty_holder_account.bank_card_talk("[cube] was scanned in \the [get_area(cube)] by [scan_human] ([scan_human.job]).") + else + to_chat(user, "Bank account not detected. Handling tip not registered.") diff --git a/code/modules/cargo/exports/civilain_bounty.dm b/code/modules/cargo/exports/civilain_bounty.dm index 3062694becd..66054f1d0b5 100644 --- a/code/modules/cargo/exports/civilain_bounty.dm +++ b/code/modules/cargo/exports/civilain_bounty.dm @@ -5,4 +5,4 @@ export_types = list(/obj/item/bounty_cube) /datum/export/bounty_box/get_cost(obj/item/bounty_cube/cube, apply_elastic) - return cube.bounty_value + return cube.bounty_value + (cube.bounty_value * (cube.speed_bonus / 100))