From 90103467bd0d77c502a4a57af160c942398ca23e Mon Sep 17 00:00:00 2001 From: NovaBot <154629622+NovaBot13@users.noreply.github.com> Date: Tue, 20 Feb 2024 04:38:35 -0500 Subject: [PATCH] [MIRROR] Paintings update: Curators get a cut on patronage + zoom in/out buttons on UI (#1057) * Paintings update: Curators get a cut on patronage + zoom in/out buttons on UI (#81500) ## About The Pull Request (Roundstart) Curators now get a 22.5% cut on credits spent on painting patronages (divided by the number of curators). The service department also gets another, 12.5% cut. This PR also adds zoom in/out buttons to the painting canvas UI. So you don't have to stare at a blob of such enormous squares while the UI is open, which is only good when drawing. Screenshot copypaste in paint: ## Why It's Good For The Game The painting feature is mostly an end in itself, which is totally fine. I've put quite a few quality-of-life changes into it through the years, and I still want to kick in some stuff. However, I think the curator should actually benefit from them in a more "mechanical" way. Furthermore, I personally prefer them over the random written crap that players make. Also, as I said above, the canvas UI can feel a tad too big at times. * Paintings update: Curators get a cut on patronage + zoom in/out buttons on UI --------- Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com> --- code/controllers/subsystem/economy.dm | 2 + code/modules/art/paintings.dm | 55 ++++++++++++++-- code/modules/economy/account.dm | 3 + strings/tips.txt | 1 + tgui/packages/tgui/interfaces/Canvas.tsx | 84 ++++++++++++++++-------- 5 files changed, 114 insertions(+), 31 deletions(-) diff --git a/code/controllers/subsystem/economy.dm b/code/controllers/subsystem/economy.dm index f8377302bd3..7b3f93f5d82 100644 --- a/code/controllers/subsystem/economy.dm +++ b/code/controllers/subsystem/economy.dm @@ -29,6 +29,8 @@ SUBSYSTEM_DEF(economy) * A list of sole account datums can be obtained with flatten_list(), another variable would be redundant rn. */ var/list/bank_accounts_by_id = list() + /// A list of bank accounts indexed by their assigned job. + var/list/bank_accounts_by_job = list() ///List of the departmental budget cards in existance. var/list/dep_cards = list() /// A var that collects the total amount of credits owned in player accounts on station, reset and recounted on fire() diff --git a/code/modules/art/paintings.dm b/code/modules/art/paintings.dm index 9a18a2b0269..8c85d4fc7b4 100644 --- a/code/modules/art/paintings.dm +++ b/code/modules/art/paintings.dm @@ -1,3 +1,4 @@ +#define MAX_PAINTING_ZOOM_OUT 3 /////////// // EASEL // @@ -67,10 +68,13 @@ var/framed_offset_y = 10 /** - * How big the grid cells that compose the painting are in the UI. + * How big the grid cells that compose the painting are in the UI (multiplied by zoom). * This impacts the size of the UI, so smaller values are generally better for bigger canvases and viceversa */ - var/pixels_per_unit = 24 + var/pixels_per_unit = 9 + + ///A list that keeps track of the current zoom value for each current viewer. + var/list/zoom_by_observer SET_BASE_PIXEL(11, 10) @@ -118,10 +122,12 @@ /obj/item/canvas/ui_static_data(mob/user) . = ..() .["px_per_unit"] = pixels_per_unit + .["max_zoom"] = MAX_PAINTING_ZOOM_OUT /obj/item/canvas/ui_data(mob/user) . = ..() .["grid"] = grid + .["zoom"] = LAZYACCESS(zoom_by_observer, user.key) || (finalized ? 1 : MAX_PAINTING_ZOOM_OUT) .["name"] = painting_metadata.title .["author"] = painting_metadata.creator_name .["patron"] = painting_metadata.patron_name @@ -202,6 +208,24 @@ if("patronage") . = TRUE patron(user) + if("zoom_in") + . = TRUE + LAZYINITLIST(zoom_by_observer) + if(!zoom_by_observer[user.key]) + zoom_by_observer[user.key] = 2 + else + zoom_by_observer[user.key] = min(zoom_by_observer[user.key] + 1, MAX_PAINTING_ZOOM_OUT) + if("zoom_out") + . = TRUE + LAZYINITLIST(zoom_by_observer) + if(!zoom_by_observer[user.key]) + zoom_by_observer[user.key] = MAX_PAINTING_ZOOM_OUT - 1 + else + zoom_by_observer[user.key] = max(zoom_by_observer[user.key] - 1, 1) + +/obj/item/canvas/ui_close(mob/user) + . = ..() + LAZYREMOVE(zoom_by_observer, user.key) /obj/item/canvas/proc/finalize(mob/user) if(painting_metadata.loaded_from_json || finalized) @@ -218,6 +242,9 @@ SStgui.update_uis(src) +#define CURATOR_PERCENTILE_CUT 0.225 +#define SERVICE_PERCENTILE_CUT 0.125 + /obj/item/canvas/proc/patron(mob/user) if(!finalized || !isliving(user)) return @@ -245,6 +272,19 @@ if(!account.adjust_money(-offer_amount, "Painting: Patron of [painting_metadata.title]")) to_chat(user, span_warning("Transaction failure. Please try again.")) return + + var/datum/bank_account/service_account = SSeconomy.get_dep_account(ACCOUNT_SRV) + service_account.adjust_money(offer_amount * SERVICE_PERCENTILE_CUT) + ///We give the curator(s) a cut (unless they're themselves the patron), as it's their job to curate and promote art among other things. + var/list/curator_accounts = SSeconomy.bank_accounts_by_job[/datum/job/curator] - account + var/curators_length = length(curator_accounts) + if(curators_length) + var/curator_cut = round(offer_amount * CURATOR_PERCENTILE_CUT / curators_length) + if(curator_cut) + for(var/datum/bank_account/curator as anything in curator_accounts) + curator.adjust_money(curator_cut, "Painting: Patronage cut") + curator.bank_card_talk("Cut on patronage received, account now holds [curator.account_balance] cr.") + painting_metadata.patron_ckey = user.ckey painting_metadata.patron_name = user.real_name painting_metadata.credit_value = offer_amount @@ -260,6 +300,9 @@ SStgui.close_uis(src) // Close the examine ui so that the radial menu doesn't end up covered by it and people don't get confused. select_new_frame(user, possible_frames) +#undef CURATOR_PERCENTILE_CUT +#undef SERVICE_PERCENTILE_CUT + /obj/item/canvas/proc/select_new_frame(mob/user, list/candidates) var/possible_frames = candidates || SSpersistent_paintings.get_available_frames(painting_metadata.credit_value) var/list/radial_options = list() @@ -386,6 +429,7 @@ SET_BASE_PIXEL(5, 7) framed_offset_x = 5 framed_offset_y = 7 + pixels_per_unit = 8 /obj/item/canvas/twentythree_twentythree name = "canvas (23x23)" @@ -395,6 +439,7 @@ SET_BASE_PIXEL(5, 5) framed_offset_x = 5 framed_offset_y = 5 + pixels_per_unit = 8 /obj/item/canvas/twentyfour_twentyfour name = "canvas (24x24) (AI Universal Standard)" @@ -405,6 +450,7 @@ SET_BASE_PIXEL(4, 4) framed_offset_x = 4 framed_offset_y = 4 + pixels_per_unit = 8 /obj/item/canvas/thirtysix_twentyfour name = "canvas (36x24)" @@ -415,7 +461,7 @@ SET_BASE_PIXEL(-4, 4) framed_offset_x = 14 framed_offset_y = 4 - pixels_per_unit = 20 + pixels_per_unit = 7 w_class = WEIGHT_CLASS_BULKY custom_price = PAYCHECK_CREW * 1.25 @@ -435,7 +481,7 @@ SET_BASE_PIXEL(-8, 2) framed_offset_x = 9 framed_offset_y = 4 - pixels_per_unit = 18 + pixels_per_unit = 6 w_class = WEIGHT_CLASS_BULKY custom_price = PAYCHECK_CREW * 1.75 @@ -798,3 +844,4 @@ current_color = chosen_color #undef AVAILABLE_PALETTE_SPACE +#undef MAX_PAINTING_ZOOM_OUT diff --git a/code/modules/economy/account.dm b/code/modules/economy/account.dm index 6bcad3f247c..77452c11d2b 100644 --- a/code/modules/economy/account.dm +++ b/code/modules/economy/account.dm @@ -49,6 +49,7 @@ /datum/bank_account/Destroy() if(add_to_accounts) SSeconomy.bank_accounts_by_id -= "[account_id]" + SSeconomy.bank_accounts_by_job[account_job] -= src QDEL_LIST(redeemed_coupons) return ..() @@ -70,6 +71,8 @@ if(SSeconomy.bank_accounts_by_id["[account_id]"]) stack_trace("Unable to find a unique account ID, substituting currently existing account of id [account_id].") SSeconomy.bank_accounts_by_id["[account_id]"] = src + if(account_job) + LAZYADD(SSeconomy.bank_accounts_by_job[account_job], src) /datum/bank_account/vv_edit_var(var_name, var_value) // just so you don't have to do it manually var/old_id = account_id diff --git a/strings/tips.txt b/strings/tips.txt index 06cbeca6a88..1b52ee5e0c1 100644 --- a/strings/tips.txt +++ b/strings/tips.txt @@ -33,6 +33,7 @@ As a Cultist, check the alert in the upper-right of your screen for all the deta As a Cultist, do not cause too much chaos before your objective is completed. If the shuttle gets called too soon, you may not have enough time to win. As a Cultist, the Blood Boil rune will deal massive amounts of brute damage to non-cultists, and some damage to fellow cultists of Nar'Sie nearby, but will create a fire where the rune stands on use. As a Cultist, your team starts off very weak, but if necessary can quickly convert everything they have into raw power. Make sure you have the numbers and equipment to support going loud, or the cult will fall flat on its face. +As a Curator, you earn a 22% cut (divided by number of curators) of all credits spent on painting patronages. Turn others' patience and artistry skills into your own income! As a Cyborg, choose your model carefully, as only cutting and mending your reset wire will let you re-pick it. If possible, refrain from choosing a model until a situation that requires one occurs. As a Cyborg, you are extremely vulnerable to EMPs as EMPs both stun you and damage you. The ion rifle in the armory or a traitor with an EMP kit can kill you in seconds. As a Cyborg, you are immune to most forms of stunning, and excel at almost everything far better than humans. However, flashes can easily stunlock you and you cannot do any precision work as you lack hands. diff --git a/tgui/packages/tgui/interfaces/Canvas.tsx b/tgui/packages/tgui/interfaces/Canvas.tsx index 86d68ce3331..09565831ea0 100644 --- a/tgui/packages/tgui/interfaces/Canvas.tsx +++ b/tgui/packages/tgui/interfaces/Canvas.tsx @@ -20,6 +20,7 @@ type PaintCanvasProps = Partial<{ drawing_color: string | null; has_palette: boolean; show_grid: boolean; + zoom: number; }>; type PointData = { @@ -45,6 +46,7 @@ class PaintCanvas extends Component { onCanvasDropper: (x: number, y: number) => void; drawing: boolean; drawing_color: string; + zoom: number; constructor(props) { super(props); @@ -52,6 +54,7 @@ class PaintCanvas extends Component { this.modifiedElements = []; this.is_grid_shown = false; this.drawing = false; + this.zoom = props.zoom; this.onCanvasModified = props.onCanvasModifiedHandler; this.onCanvasDropper = props.onCanvasDropperHandler; @@ -67,8 +70,12 @@ class PaintCanvas extends Component { } componentDidUpdate() { + if (this.zoom !== this.props.zoom) { + this.prepareCanvas(); + this.syncCanvas(); + } // eslint-disable-next-line max-len - if ( + else if ( (this.props.value !== undefined && JSON.stringify(this.baseImageData) !== JSON.stringify(fromDM(this.props.value))) || @@ -79,6 +86,7 @@ class PaintCanvas extends Component { } prepareCanvas() { + this.zoom = this.props.zoom as number; const canvas = this.canvasRef.current!; const ctx = canvas.getContext('2d'); const width = this.props.width || canvas.width || 360; @@ -242,22 +250,24 @@ type CanvasData = { date: string | null; show_plaque: boolean; show_grid: boolean; + zoom: number; + max_zoom: number; }; export const Canvas = (props) => { const { act, data } = useBackend(); const [width, height] = getImageSize(data.grid); - const scaled_width = width * data.px_per_unit; - const scaled_height = height * data.px_per_unit; + const scaled_width = width * data.px_per_unit * data.zoom; + const scaled_height = height * data.px_per_unit * data.zoom; const average_plaque_height = 90; - const palette_height = 44; + const palette_height = 38; const griddy = !!data.show_grid && !!data.editable && !!data.paint_tool_color; return ( { { /> )} + +