Maintenance loot table revamp (#47646)

* new maint loot tables

* Loot spawn probability finder

* maint loot pool changes
This commit is contained in:
py01
2019-11-18 18:50:59 -08:00
committed by Rob Bailey
parent 7a6a94e5d4
commit fef512d851
2 changed files with 279 additions and 109 deletions
+239 -109
View File
@@ -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,
))
@@ -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