diff --git a/code/_globalvars/lists/maintenance_loot.dm b/code/_globalvars/lists/maintenance_loot.dm index 19c23da273b..c592cdb12d4 100644 --- a/code/_globalvars/lists/maintenance_loot.dm +++ b/code/_globalvars/lists/maintenance_loot.dm @@ -1,112 +1,242 @@ -//How to balance this table -//------------------------- -//The total added weight of all the entries should be (roughly) equal to the total number of lootdrops -//(take in account those that spawn more than one object!) -// -//While this is random, probabilities tells us that item distribution will have a tendency to look like -//the content of the weighted table that created them. -//The less lootdrops, the less even the distribution. -// -//If you want to give items a weight <1 you can multiply all the weights by 10 -// -//the "" entry will spawn nothing, if you increase this value, -//ensure that you balance it with more spawn points +//as of:10/28/2019: +//boxstation: ~153 loot items spawned +//metastation: ~183 loot items spawned +//deltastation: ~165 loot items spawned -//table data: -//----------- -//aft maintenance: 24 items, 18 spots 2 extra (28/08/2014) -//asmaint: 16 items, 11 spots 0 extra (08/08/2014) -//asmaint2: 36 items, 26 spots 2 extra (28/08/2014) -//fpmaint: 5 items, 4 spots 0 extra (08/08/2014) -//fpmaint2: 12 items, 11 spots 2 extra (28/08/2014) -//fsmaint: 0 items, 0 spots 0 extra (08/08/2014) -//fsmaint2: 40 items, 27 spots 5 extra (28/08/2014) -//maintcentral: 2 items, 2 spots 0 extra (08/08/2014) -//port: 5 items, 5 spots 0 extra (08/08/2014) +//how to balance maint loot spawns: +// 1) Ensure each category has items of approximately the same power level +// 2) Tune weight of each category until average power of a maint loot spawn is acceptable +// 3) Mapping considerations - Loot value should scale with difficulty of acquisition, or an assistaint will run through collecting free gear with no risk -GLOBAL_LIST_INIT(maintenance_loot, list( - /obj/item/bodybag = 1, - /obj/item/clothing/glasses/meson = 2, - /obj/item/clothing/glasses/sunglasses = 1, - /obj/item/clothing/gloves/color/fyellow = 1, - /obj/item/clothing/head/hardhat = 1, - /obj/item/clothing/head/hardhat/red = 1, - /obj/item/clothing/head/that = 1, - /obj/item/clothing/head/ushanka = 1, - /obj/item/clothing/head/welding = 1, - /obj/item/clothing/mask/gas = 15, - /obj/item/clothing/suit/hazardvest = 1, - /obj/item/clothing/under/misc/vice_officer = 1, - /obj/item/clothing/suit/hooded/flashsuit = 2, - /obj/item/assembly/prox_sensor = 4, - /obj/item/assembly/timer = 3, - /obj/item/flashlight = 4, - /obj/item/flashlight/pen = 1, - /obj/effect/spawner/lootdrop/glowstick = 4, - /obj/item/multitool = 2, - /obj/item/radio/off = 2, - /obj/item/t_scanner = 5, - /obj/item/airlock_painter = 1, - /obj/item/stack/cable_coil = 4, - /obj/item/stack/cable_coil/five = 6, - /obj/item/stack/medical/suture = 1, - /obj/item/stack/rods/ten = 9, - /obj/item/stack/rods/twentyfive = 1, - /obj/item/stack/rods/fifty = 1, - /obj/item/stack/sheet/cardboard = 2, - /obj/item/stack/sheet/metal/twenty = 1, - /obj/item/stack/sheet/mineral/plasma = 1, - /obj/item/stack/sheet/rglass = 1, - /obj/item/book/manual/wiki/engineering_construction = 1, - /obj/item/book/manual/wiki/engineering_hacking = 1, - /obj/item/clothing/head/cone = 1, - /obj/item/coin/silver = 1, - /obj/item/coin/twoheaded = 1, - /obj/item/poster/random_contraband = 1, - /obj/item/poster/random_official = 1, - /obj/item/crowbar = 1, - /obj/item/crowbar/red = 1, - /obj/item/extinguisher = 11, - /obj/item/hand_labeler = 1, - /obj/item/paper/crumpled = 1, - /obj/item/reagent_containers/hypospray/medipen/pumpup = 6, - /obj/item/pen = 1, - /obj/item/reagent_containers/spray/pestspray = 1, - /obj/item/reagent_containers/glass/rag = 3, - /obj/item/stock_parts/cell = 3, - /obj/item/storage/belt/utility = 2, - /obj/item/storage/box = 2, - /obj/item/storage/box/cups = 1, - /obj/item/storage/box/donkpockets = 1, - /obj/item/storage/box/lights/mixed = 3, - /obj/item/storage/box/hug/medical = 1, - /obj/item/storage/fancy/cigarettes/dromedaryco = 1, - /obj/item/storage/toolbox/mechanical = 1, - /obj/item/screwdriver = 3, - /obj/item/tank/internals/emergency_oxygen = 2, - /obj/item/vending_refill/cola = 1, - /obj/item/weldingtool = 3, - /obj/item/wirecutters = 1, - /obj/item/wrench = 4, - /obj/item/relic = 3, - /obj/item/weaponcrafting/receiver = 2, - /obj/item/clothing/head/cone = 2, - /obj/item/grenade/smokebomb = 2, - /obj/item/geiger_counter = 3, - /obj/item/reagent_containers/food/snacks/grown/citrus/orange = 1, - /obj/item/radio/headset = 1, - /obj/item/assembly/infra = 1, - /obj/item/assembly/igniter = 2, - /obj/item/assembly/signaler = 2, - /obj/item/assembly/mousetrap = 2, - /obj/item/reagent_containers/syringe = 2, - /obj/effect/spawner/lootdrop/gloves = 8, - /obj/item/clothing/shoes/laceup = 1, - /obj/item/storage/secure/briefcase = 3, - /obj/item/storage/toolbox/artistic = 2, - /obj/item/toy/eightball = 1, - /obj/item/reagent_containers/pill/floorpill = 1, - /obj/item/reagent_containers/food/snacks/canned/peaches/maint = 1, - /obj/item/throwing_star = 1, - "" = 3 +//goal of maint loot: +// 1) Provide random equipment to people who take effort to crawl maint +// 2) Create memorable moments with very rare, crazy items + +//Loot tables + +GLOBAL_LIST_INIT(trash_loot, list(//junk: useless, very easy to get, or ghetto chemistry items + list(//trash + /obj/item/trash = 1, + /obj/item/trash/can = 1, + /obj/item/trash/raisins = 1, + /obj/item/trash/candy = 1, + /obj/item/trash/cheesie = 1, + /obj/item/trash/chips = 1, + /obj/item/trash/popcorn = 1, + /obj/item/trash/sosjerky = 1, + /obj/item/trash/plate = 1, + /obj/item/trash/pistachios = 1, + + /obj/item/poster/random_contraband = 1, + /obj/item/poster/random_official = 1, + /obj/item/folder/yellow = 1, + /obj/item/hand_labeler = 1, + /obj/item/pen = 1, + /obj/item/paper = 1, + /obj/item/paper/crumpled = 1, + /obj/item/photo/old = 1, + /obj/item/disk/data = 1, + /obj/item/stack/sheet/cardboard = 1, + /obj/item/storage/box = 1, + + /obj/item/reagent_containers/food/drinks/drinkingglass = 1, + /obj/item/coin/silver = 1, + /obj/effect/decal/cleanable/ash = 1, + /obj/item/cigbutt = 1, + /obj/item/camera = 1, + /obj/item/camera_film = 1, + /obj/item/light/bulb = 1, + /obj/item/light/tube = 1, + /obj/item/reagent_containers/food/snacks/urinalcake = 1, + + /obj/item/airlock_painter = 1, + /obj/item/pipe = 1, + /obj/item/rack_parts = 1, + /obj/item/clothing/mask/breath = 1, + /obj/item/shard = 1, + + /obj/item/reagent_containers/pill/floorpill = 1, + /obj/item/toy/eightball = 1, + ) = 8, + + list(//tier 1 stock parts + /obj/item/stock_parts/capacitor = 1, + /obj/item/stock_parts/scanning_module = 1, + /obj/item/stock_parts/manipulator = 1, + /obj/item/stock_parts/micro_laser = 1, + /obj/item/stock_parts/matter_bin = 1, + ) = 1, + )) + + + +GLOBAL_LIST_INIT(common_loot, list( //common: basic items + list(//tools + /obj/item/screwdriver = 1, + /obj/item/wirecutters = 1, + /obj/item/wrench = 1, + /obj/item/crowbar = 1, + /obj/item/t_scanner = 1, + /obj/item/geiger_counter = 1, + /obj/item/analyzer = 1, + /obj/item/mop = 1, + /obj/item/reagent_containers/glass/bucket = 1, + /obj/item/toy/crayon/spraycan = 1, + ) = 1, + + list(//equipment + /obj/item/clothing/mask/gas = 1, + /obj/item/radio/headset = 1, + /obj/item/storage/backpack = 1, + /obj/item/clothing/shoes/sneakers/black = 1, + /obj/item/clothing/suit/hazardvest = 1, + /obj/item/clothing/suit/toggle/labcoat = 1, + /obj/item/clothing/under/color/grey = 1, + /obj/item/clothing/gloves/color/fyellow = 1, + /obj/effect/spawner/lootdrop/gloves = 1, + /obj/item/storage/wallet/random = 1, + /obj/item/clothing/glasses/science = 1, + /obj/item/clothing/glasses/meson = 1, + /obj/item/storage/belt/fannypack = 1, + ) = 1, + + list(//construction and crafting + /obj/item/stack/cable_coil = 1, + /obj/item/stock_parts/cell = 1, + /obj/item/stack/rods/twentyfive = 1, + /obj/item/stack/sheet/metal/twenty = 1, + /obj/item/stack/sheet/mineral/plasma = 1, + + //assemblies + /obj/item/assembly/infra = 1, + /obj/item/assembly/signaler = 1, + /obj/item/assembly/mousetrap = 1, + /obj/item/assembly/prox_sensor = 1, + /obj/item/assembly/timer = 1, + /obj/item/assembly/igniter = 1, + /obj/item/assembly/health = 1, + + /obj/item/stack/packageWrap = 1, + ) = 1, + + list(//medical and chemicals + /obj/item/storage/fancy/cigarettes/dromedaryco = 1, + /obj/item/grenade/chem_grenade/cleaner = 1, + /obj/item/storage/box/matches = 1, + /obj/item/reagent_containers/syringe = 1, + /obj/item/reagent_containers/glass/beaker = 1, + /obj/item/reagent_containers/glass/rag = 1, + /obj/item/reagent_containers/hypospray/medipen/pumpup = 2, + ) = 1, + + list(//food + /obj/item/reagent_containers/food/drinks/beer = 1, + /obj/item/reagent_containers/food/drinks/coffee = 1, + ) = 1, + + list(//misc + /obj/item/radio/off = 1, + /obj/item/extinguisher = 1, + /obj/item/tank/internals/emergency_oxygen = 1, + /obj/item/bodybag = 1, + /obj/item/grenade/smokebomb = 1, + /obj/item/stack/spacecash/c10 = 1, + + //light sources + /obj/item/flashlight = 1, + /obj/effect/spawner/lootdrop/glowstick = 1, + /obj/item/clothing/head/hardhat/red = 1, + /obj/item/flashlight/flare = 1, + ) = 1, + )) + + + +GLOBAL_LIST_INIT(uncommon_loot, list(//uncommon: useful items + list(//tools + /obj/item/weldingtool/mini = 1, + /obj/item/multitool = 1, + /obj/item/hatchet = 1, + /obj/item/roller = 1, + /obj/item/restraints/legcuffs/bola = 1, + /obj/item/restraints/handcuffs/cable = 1, + /obj/item/twohanded/spear = 1, + /obj/item/shield/riot/buckler = 1, + /obj/item/grenade/iedcasing = 1, + /obj/item/melee/baton/cattleprod = 1, + /obj/item/throwing_star = 1, + ) = 1, + + list(//equipment + /obj/item/clothing/head/welding = 1, + /obj/item/clothing/glasses/welding = 1, + /obj/item/clothing/glasses/hud/health = 1, + /obj/item/clothing/glasses/hud/diagnostic = 1, + /obj/item/storage/belt/utility = 1, + /obj/item/storage/belt/medical = 1, + + /obj/item/clothing/suit/armor/vest/old = 1, + /obj/item/clothing/head/helmet/old = 1, + /obj/item/clothing/mask/muzzle = 1, + /obj/item/clothing/ears/earmuffs = 1, + /obj/item/clothing/gloves/color/black = 1, + ) = 1, + + list(//construction and crafting + /obj/item/stock_parts/cell/high = 1, + /obj/item/stack/sheet/mineral/wood/fifty = 1, + /obj/item/beacon = 1, + /obj/item/weaponcrafting/receiver = 1, + ) = 1, + + list(//medical and chemicals + list(//basic healing items + /obj/item/stack/medical/suture = 1, + /obj/item/stack/medical/mesh = 1, + /obj/item/stack/medical/gauze = 1, + ) = 1, + list(//medical chems + /obj/item/reagent_containers/glass/bottle/multiver = 1, + /obj/item/reagent_containers/syringe/convermol = 1, + ) = 1, + list(//drinks + /obj/item/reagent_containers/food/drinks/bottle/vodka = 1, + /obj/item/reagent_containers/food/drinks/soda_cans/grey_bull = 1, + ) = 1, + list(//sprayers + /obj/item/reagent_containers/spray = 1, + /obj/item/watertank = 1, + /obj/item/watertank/janitor = 1, + ) = 1, + ) = 1, + + list(//food + /obj/item/reagent_containers/food/snacks/canned/peaches/maint = 1, + /obj/item/storage/box/donkpockets = 1, + /obj/item/reagent_containers/food/snacks/monkeycube = 1, + ) = 1, + + list(//strange objects + /obj/item/relic = 1, + ) = 1, + )) + +GLOBAL_LIST_INIT(oddity_loot, list(//oddity: strange or crazy items + //keeping commented out until there are more, otherwise the same ones may appear too often + // /obj/effect/rune/teleport = 1, + "" = 1 //nothing, so loot spawner doesn't break while nothing else is here + )) + +//Maintenance loot spawner pools +#define maint_trash_weight 4499 +#define maint_common_weight 4500 +#define maint_uncommon_weight 1000 +#define maint_oddity_weight 1 //1 out of 10,000 would give metastation (180 spawns) a 2 in 111 chance of spawning an oddity per round, similar to xeno egg + +//Loot pool used by default maintenance loot spawners +GLOBAL_LIST_INIT(maintenance_loot, list( + GLOB.trash_loot = maint_trash_weight, + GLOB.common_loot = maint_common_weight, + GLOB.uncommon_loot = maint_uncommon_weight, + GLOB.oddity_loot = maint_oddity_weight, )) diff --git a/code/game/objects/effects/spawners/lootdrop.dm b/code/game/objects/effects/spawners/lootdrop.dm index 7c674798cdc..2158ac8778a 100644 --- a/code/game/objects/effects/spawners/lootdrop.dm +++ b/code/game/objects/effects/spawners/lootdrop.dm @@ -360,3 +360,43 @@ /obj/item/circuitboard/computer/apc_control, /obj/item/circuitboard/computer/robotics ) + +//finds the probabilities of items spawning from a loot spawner's loot pool +/obj/item/loot_table_maker + icon = 'icons/effects/landmarks_static.dmi' + icon_state = "random_loot" + var/spawner_to_test = /obj/effect/spawner/lootdrop/maintenance //what lootdrop spawner to use the loot pool of + var/loot_count = 180 //180 is about how much maint loot spawns per map as of 11/14/2019 + //result outputs + var/list/spawned_table //list of all items "spawned" and how many + var/list/stat_table //list of all items "spawned" and their occurrance probability + +/obj/item/loot_table_maker/Initialize() + . = ..() + make_table() + +/obj/item/loot_table_maker/attack_self(mob/user) + to_chat(user, "Loot pool re-rolled.") + make_table() + +/obj/item/loot_table_maker/proc/make_table() + spawned_table = list() + stat_table = list() + var/obj/effect/spawner/lootdrop/spawner_to_table = new spawner_to_test + var/lootpool = spawner_to_table.loot + qdel(spawner_to_table) + for(var/i in 1 to loot_count) + var/loot_spawn = pick_loot(lootpool) + if(!(loot_spawn in spawned_table)) + spawned_table[loot_spawn] = 1 + else + spawned_table[loot_spawn] += 1 + stat_table += spawned_table + for(var/item in stat_table) + stat_table[item] /= loot_count + +/obj/item/loot_table_maker/proc/pick_loot(lootpool) //selects path from loot table and returns it + var/lootspawn = pickweight(lootpool) + while(islist(lootspawn)) + lootspawn = pickweight(lootspawn) + return lootspawn