Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: make more items stackable #3489

Merged
merged 6 commits into from
Dec 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions data/json/items/comestibles/med.json
Original file line number Diff line number Diff line change
Expand Up @@ -1751,17 +1751,12 @@
{
"id": "disinrag",
"type": "COMESTIBLE",
"copy-from": "rag_abstract",
"comestible_type": "MED",
"name": { "str": "antiseptic soaked rag" },
"description": "A rag soaked in antiseptic. Useful for light wounds, probably won't help with deep bites.",
"weight": "80 g",
"//": "Can't copy-from rag, it breaks the stacking for some reason!",
"volume": "250 ml",
"price": "250 cent",
"price_postapoc": "50 cent",
"material": "cotton",
"symbol": ",",
"color": "white",
"flags": [ "NO_INGEST" ],
"use_action": {
"type": "heal",
Expand Down
58 changes: 44 additions & 14 deletions data/json/items/generic.json
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,8 @@
"flags": [ "NO_SALVAGE" ],
"weight": "114 g",
"volume": "250 ml",
"category": "spare_parts"
"category": "spare_parts",
"stackable": true
},
{
"type": "GENERIC",
Expand All @@ -223,7 +224,8 @@
"weight": "100 g",
"volume": "250 ml",
"category": "spare_parts",
"to_hit": -1
"to_hit": -1,
"stackable": true
},
{
"type": "GENERIC",
Expand All @@ -239,7 +241,8 @@
"weight": "100 g",
"volume": "250 ml",
"category": "spare_parts",
"to_hit": -1
"to_hit": -1,
"stackable": true
},
{
"type": "GENERIC",
Expand All @@ -254,7 +257,8 @@
"material": [ "nomex" ],
"flags": [ "NO_SALVAGE" ],
"weight": "42 g",
"volume": "250 ml"
"volume": "250 ml",
"stackable": true
},
{
"type": "GENERIC",
Expand All @@ -270,7 +274,8 @@
"weight": "45 g",
"volume": "250 ml",
"to_hit": -2,
"flags": [ "UNRECOVERABLE" ]
"flags": [ "UNRECOVERABLE" ],
"stackable": true
},
{
"type": "GENERIC",
Expand Down Expand Up @@ -623,7 +628,8 @@
"material": "steel",
"weight": "151 g",
"volume": "500 ml",
"to_hit": -2
"to_hit": -2,
"stackable": true
},
{
"type": "GENERIC",
Expand All @@ -637,7 +643,8 @@
"material": "steel",
"weight": "302 g",
"volume": "500 ml",
"to_hit": -2
"to_hit": -2,
"stackable": true
},
{
"type": "GENERIC",
Expand Down Expand Up @@ -669,7 +676,8 @@
"volume": "1500 ml",
"bashing": 12,
"to_hit": -1,
"qualities": [ [ "HAMMER", 1 ] ]
"qualities": [ [ "HAMMER", 1 ] ],
"stackable": true
},
{
"type": "GENERIC",
Expand Down Expand Up @@ -1677,16 +1685,37 @@
"to_hit": -6
},
{
"abstract": "rag_abstract",
"type": "GENERIC",
"id": "rag_bloody",
"name": { "str": "rag" },
"description": "This is a largish piece of cloth, useful in crafting and possibly for staunching bleeding. It's a bug if you see this.",
"category": "spare_parts",
"weight": "80 g",
"volume": "250 ml",
"price": 0,
"price_postapoc": 0,
"material": "cotton",
"symbol": ",",
"color": "white",
"flags": [ "NO_SALVAGE" ],
"stackable": true
},
{
"id": "rag",
"type": "GENERIC",
"name": { "str": "rag" },
"description": "This is a largish piece of cloth, useful in crafting and possibly for staunching bleeding.",
"copy-from": "rag_abstract",
"use_action": [ { "type": "heal", "move_cost": 200, "used_up_item": "rag_bloody", "bleed": 0.5, "limb_power": 0 }, "WASH_HARD_ITEMS" ]
},
{
"type": "GENERIC",
"id": "rag_bloody",
"copy-from": "rag_abstract",
"color": "red",
"name": { "str": "blood soaked rag" },
"description": "A large rag, drenched in blood. It could be cleaned with boiling water.",
"material": "cotton",
"flags": [ "NO_SALVAGE", "TRADER_AVOID" ],
"weight": "80 g",
"volume": "250 ml"
"extend": { "flags": "TRADER_AVOID" }
},
{
"id": "pipe_cleaner",
Expand Down Expand Up @@ -2651,7 +2680,8 @@
"flags": [ "NO_SALVAGE" ],
"weight": "80 g",
"volume": "250 ml",
"category": "spare_parts"
"category": "spare_parts",
"stackable": true
},
{
"id": "cerberus_laser",
Expand Down
1 change: 1 addition & 0 deletions data/json/items/generic/string.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
{
"id": "string_6",
"type": "GENERIC",
"stackable": true,
"category": "spare_parts",
"name": { "str": "short string" },
"description": "A 6-inch (or about 15 cm) long piece of cotton string.",
Expand Down
3 changes: 2 additions & 1 deletion data/json/items/resources/misc.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@
"bashing": 5,
"cutting": 2,
"to_hit": -1,
"qualities": [ [ "BUTCHER", -66 ] ]
"qualities": [ [ "BUTCHER", -66 ] ],
"stackable": true
},
{
"id": "fighter_sting",
Expand Down
10 changes: 6 additions & 4 deletions data/json/items/resources/plastic.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[
{
"id": "plastic_chunk",
"type": "TOOL",
"type": "GENERIC",
"category": "spare_parts",
"name": { "str": "plastic chunk" },
"description": "This is a piece of plastic. It could be used to fabricate, repair, or reinforce plastic items.",
Expand All @@ -12,11 +12,12 @@
"material": "plastic",
"symbol": ",",
"color": "light_blue",
"flags": [ "NO_SALVAGE" ]
"flags": [ "NO_SALVAGE" ],
"stackable": true
},
{
"id": "nylon",
"type": "TOOL",
"type": "GENERIC",
"category": "spare_parts",
"name": { "str_sp": "synthetic fabric" },
"description": "This is small bolt of synthetic fabric. Unlike you and other natural materials, it won't degrade much with age. Maybe that's less of a bad thing now.",
Expand All @@ -27,7 +28,8 @@
"material": "nylon",
"symbol": ",",
"color": "white",
"flags": [ "NO_SALVAGE" ]
"flags": [ "NO_SALVAGE" ],
"stackable": true
},
{
"id": "plastic_sheet",
Expand Down
9 changes: 6 additions & 3 deletions data/json/items/resources/wood.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
"bashing": 4,
"to_hit": 1,
"qualities": [ [ "COOK", 1 ] ],
"flags": [ "NO_SALVAGE", "TRADER_AVOID", "FIREWOOD" ]
"flags": [ "NO_SALVAGE", "TRADER_AVOID", "FIREWOOD" ],
"stackable": true
},
{
"id": "stick",
Expand Down Expand Up @@ -102,7 +103,8 @@
"bashing": 10,
"price": "10 USD",
"price_postapoc": "10 cent",
"flags": [ "FIREWOOD" ]
"flags": [ "FIREWOOD" ],
"stackable": true
},
{
"type": "GENERIC",
Expand Down Expand Up @@ -140,7 +142,8 @@
"bashing": 8,
"price": "80 USD",
"price_postapoc": "10 cent",
"flags": [ "FIREWOOD" ]
"flags": [ "FIREWOOD" ],
"stackable": true
},
{
"type": "GENERIC",
Expand Down
16 changes: 0 additions & 16 deletions data/json/items/tool/toiletries.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,22 +74,6 @@
"techniques": "WBLOCK_1",
"use_action": "MOP"
},
{
"id": "rag",
"type": "TOOL",
"category": "spare_parts",
"name": { "str": "rag" },
"description": "This is a largish piece of cloth, useful in crafting and possibly for staunching bleeding.",
"weight": "80 g",
"volume": "250 ml",
"price": 0,
"price_postapoc": 0,
"material": "cotton",
"symbol": ",",
"color": "white",
"use_action": [ { "type": "heal", "move_cost": 200, "used_up_item": "rag_bloody", "bleed": 0.5, "limb_power": 0 }, "WASH_HARD_ITEMS" ],
"flags": [ "NO_SALVAGE" ]
},
{
"type": "GENERIC",
"category": "tools",
Expand Down
71 changes: 71 additions & 0 deletions scripts/to_stackable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { z } from "https://deno.land/x/[email protected]/mod.ts"
import { Command } from "https://deno.land/x/[email protected]/deps/cliffy.ts"
import { cliOptions } from "https://deno.land/x/[email protected]/utils/cli.ts"
import { timeit } from "https://deno.land/x/[email protected]/utils/timeit.ts"
import {
applyRecursively,
schemaTransformer,
} from "https://deno.land/x/[email protected]/utils/transform.ts"
import {
type CataEntry,
Entry,
parseCataJson,
readRecursively,
} from "https://deno.land/x/[email protected]/utils/parse.ts"
import { fmtJsonRecursively } from "https://deno.land/x/[email protected]/utils/json_fmt.ts"
import { match, P } from "https://deno.land/x/[email protected]/deps/ts_pattern.ts"
import { id } from "https://deno.land/x/[email protected]/utils/id.ts"

// FIXME: include in library
const unpack = (xs: string[] | Entry[]) =>
match(xs)
.with(P.array(P.string), id)
.otherwise((xs) => xs.map(({ path }) => path))

const main = new Command()
// TODO: allow multiple paths
.option(...cliOptions.path)
.option(...cliOptions.format)
.option(...cliOptions.quiet)
.arguments("<...ids>")
.description("Converts given id to stackable.")
.action(async ({ path, quiet = false, format }, ...ids) => {
const timeIt = timeit(quiet)

const schema = z.object({
// @ts-expect-error: zod hates string literal mapping
id: z.union(ids.map((id) => z.literal(id))) as z.ZodString,
type: z.string().transform((x) => x === "TOOL" ? "GENERIC" : x),
})
.passthrough()
.transform(({ id, ...rest }) => {
console.log(id)
return { id, ...rest, stackable: true }
})

const transformer = schemaTransformer(schema)
const ignore = (entries: CataEntry[]) =>
entries.find(({ type }) => ["mapgen", "palette", "mod_tileset"].includes(type))

// FIXME: include in library
const mapgenIgnoringTransformer = (text: string) => {
const entries = parseCataJson(text)
return ignore(entries) ? text : JSON.stringify(transformer(entries), null, 2)
}

const recursiveTransformer = applyRecursively(mapgenIgnoringTransformer)

const entries = await timeIt({ name: "reading JSON", val: readRecursively(path) })

await timeIt({ name: "Transforming", val: recursiveTransformer(entries) })

if (!format) return
await timeIt({
name: "formatting",
val: fmtJsonRecursively({ formatterPath: format, quiet: true })(unpack(entries)),
})
})

if (import.meta.main) {
await main.parse(Deno.args)
}
2 changes: 1 addition & 1 deletion src/activity_item_handling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3381,7 +3381,7 @@ void try_fuel_fire( player_activity &act, player &p, const bool starting_fire )
}
}
if( found ) {
int quantity = std::max( 1, std::min( found->charges, found->charges_per_volume( 250_ml ) ) );
const int quantity = std::clamp( found->charges, 1, found->charges_per_volume( 250_ml ) );
// Note: move_item() handles messages (they're the generic "you drop x")
move_item( p, *found, quantity, *refuel_spot, *best_fire );
}
Expand Down
2 changes: 1 addition & 1 deletion src/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8297,7 +8297,7 @@ float item::simulate_burn( fire_data &frd ) const
}

if( count_by_charges() ) {
int stack_burnt = rng( type->stack_size / 2, type->stack_size );
const int stack_burnt = type->stack_size;
time_added *= stack_burnt;
smoke_added *= stack_burnt;
burn_added *= stack_burnt;
Expand Down
25 changes: 17 additions & 8 deletions src/iuse_actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3767,20 +3767,26 @@ int heal_actor::finish_using( player &healer, player &patient, item &it, hp_part
}
}

const auto copy_flags = [&]( item & it ) {
for( const auto &flag : used_up_item_flags ) {
it.set_flag( flag );
}
};

// TODO: make this less cursed
if( !used_up_item_id.is_empty() ) {
// If the item is a tool, `make` it the new form
// Otherwise it probably was consumed, so create a new one
if( it.is_tool() ) {
if( it.is_tool() || ( it.count_by_charges() && it.charges <= used_up_item_charges ) ) {
it.convert( used_up_item_id );
for( const auto &flag : used_up_item_flags ) {
it.set_flag( flag );
}
copy_flags( it );
} else {
if( it.count_by_charges() && it.charges > used_up_item_charges ) {
it.charges -= used_up_item_charges;
}
item *used_up = item::spawn_temporary( used_up_item_id, it.birthday() );
used_up->charges = used_up_item_charges;
for( const auto &flag : used_up_item_flags ) {
used_up->set_flag( flag );
}
copy_flags( *used_up );
for( int count = 0; count < used_up_item_quantity; count++ ) {
healer.i_add_or_drop( item::spawn( *used_up ) );
}
Expand Down Expand Up @@ -4787,7 +4793,10 @@ int sew_advanced_actor::use( player &p, item &it, bool, const tripoint & ) const
const inventory &crafting_inv = p.crafting_inventory();
// Go through all discovered repair items and see if we have any of them available
for( auto &cm : clothing_mods::get_all() ) {
has_enough[cm.item_string] = crafting_inv.has_amount( cm.item_string, items_needed );
has_enough[cm.item_string] =
item::count_by_charges( cm.item_string )
? crafting_inv.has_charges( cm.item_string, items_needed )
: crafting_inv.has_amount( cm.item_string, items_needed );
}

int mod_count = 0;
Expand Down
Loading