1#include "ap_item.h" 2#include "ap_map.h" 3#include "ap_snes.h" 4#include "ap_macro.h" 5#include "lb.h" 6#include "bm.h" 7 8// 216 randomized locations + 10 crystals/pendants 9#define N_ITEMS ((size_t) (216 + 10)) 10 11static struct ap_item items[] = { 12 { .copies = 1, .is_progression = true, .name = "Green Pendant", .type = MISC_ITEM_GREEN_PENDANT, }, 13 { .copies = 2, .is_progression = true, .name = "Red/Blue Pendant", .type = MISC_ITEM_REDBLUE_PENDANT, }, 14 { .copies = 7, .is_progression = true, .name = "Crystal", .type = MISC_ITEM_CRYSTAL, }, 15#define X(n, abbr) \ 16 { .dungeon = CONCAT(DUNGEON_, n), .type = DUNGEON_ITEM_SKEY, .is_progression = true, .name = abbr " skey", }, \ 17 { .dungeon = CONCAT(DUNGEON_, n), .type = DUNGEON_ITEM_BKEY, .is_progression = true, .name = abbr " bkey", }, \ 18 { .dungeon = CONCAT(DUNGEON_, n), .type = DUNGEON_ITEM_MAP, .name = abbr " map", }, \ 19 { .dungeon = CONCAT(DUNGEON_, n), .type = DUNGEON_ITEM_COMPASS, .name = abbr " comp", }, 20DUNGEON_LIST 21#undef X 22#define X(i, n) \ 23 { .copies = 1, .type = CONCAT(INVENTORY_, n), .is_progression = true, .name = STRINGIFY(n), }, 24INVENTORY_LIST 25#undef X 26 { .copies = 1, .name = "Half Magic", .type = MISC_ITEM_MAGIC_UPGRADE, }, 27 { .copies = 24, .name = "Heart Piece", .type = MISC_ITEM_HEART_PIECE, }, 28 { .copies = 11, .name = "Heart Cont.", .type = MISC_ITEM_HEART_CONTAINER, }, //{ .copies = 1, .name = "S. Heart Cont.", }, 29 { .copies = 2, .name = "1 Rupee", .type = MISC_ITEM_RUPEES_1, }, 30 { .copies = 4, .name = "5 Rupees", .type = MISC_ITEM_RUPEES_5, }, 31 { .copies = 28, .name = "20 Rupees", .type = MISC_ITEM_RUPEES_20, }, 32 { .copies = 7, .name = "50 Rupees", .type = MISC_ITEM_RUPEES_50, }, 33 { .copies = 1, .name = "100 Rupees", .type = MISC_ITEM_RUPEES_100, }, 34 { .copies = 5, .name = "300 Rupees", .type = MISC_ITEM_RUPEES_300, }, 35 { .copies = 1, .name = "1 Arrow", .type = MISC_ITEM_ARROWS_1, }, 36 { .copies = 12, .name = "10 Arrows", .type = MISC_ITEM_ARROWS_10, }, 37 { .copies = 16, .name = "3 Bombs", .type = MISC_ITEM_BOMBS_3, }, 38 { .copies = 1, .name = "10 Bombs", .type = MISC_ITEM_BOMBS_10, }, 39}; 40 41// TODO: map multiple items correctly; rupees/bombs/arrows/magic 42// From alttpr Item.php 43static int recv_item_map [0xB0] = { 44 INVENTORY_SWORD, // 0x00 L1SwordAndShield 45 INVENTORY_SWORD, // 0x01 L2Sword 46 INVENTORY_SWORD, // 0x02 L3Sword 47 INVENTORY_SWORD, // 0x03 L4Sword 48 INVENTORY_SHIELD, // 0x04 BlueShield 49 INVENTORY_SHIELD, // 0x05 RedShield 50 INVENTORY_SHIELD, // 0x06 MirrorShield 51 INVENTORY_FIRE_ROD, // 0x07 FireRod 52 INVENTORY_ICE_ROD, // 0x08 IceRod 53 INVENTORY_HAMMER, // 0x09 Hammer 54 INVENTORY_HOOKSHOT, // 0x0A Hookshot 55 INVENTORY_BOW, // 0x0B Bow 56 INVENTORY_BOOMERANG, // 0x0C Boomerang 57 INVENTORY_POWDER, // 0x0D Powder 58 INVENTORY_BOTTLE, // 0x0E Bee 59 INVENTORY_BOMBOS, // 0x0f Bombos 60 INVENTORY_ETHER, // 0x10 Ether 61 INVENTORY_QUAKE, // 0x11 Quake 62 INVENTORY_LAMP, // 0x12 Lamp 63 INVENTORY_FLUTE, // 0x13 Shovel [XXX] 64 INVENTORY_FLUTE, // 0x14 OcarinaInactive 65 INVENTORY_RED_CANE, // 0x15 CaneOfSomaria 66 INVENTORY_BOTTLE, // 0x16 Bottle 67 MISC_ITEM_HEART_PIECE, // 0x17 PieceOfHeart 68 INVENTORY_BLUE_CANE, // 0x18 CaneOfByrna 69 INVENTORY_MAGIC_CAPE, // 0x19 Cape 70 INVENTORY_MIRROR, // 0x1A MagicMirror 71 INVENTORY_GLOVES, // 0x1B PowerGlove 72 INVENTORY_GLOVES, // 0x1C TitansMitt 73 INVENTORY_BOOK, // 0x1D BookOfMudora 74 INVENTORY_FLIPPERS, // 0x1E Flippers 75 INVENTORY_MOON_PEARL, // 0x1F MoonPearl 76 0, // [0x20 Crystal???] 77 INVENTORY_NET, // 0x21 BugCatchingNet 78 INVENTORY_ARMOR, // 0x22 BlueMail 79 INVENTORY_ARMOR, // 0x23 RedMail 80 DUNGEON_ITEM_SKEY, // 0x24 Key 81 DUNGEON_ITEM_COMPASS, // 0x25 Compass 82 MISC_ITEM_HEART_CONTAINER, // 0x26 HeartContainerNoAnimation 83 MISC_ITEM_BOMBS_1, // 0x27 Bomb 84 MISC_ITEM_BOMBS_3, // 0x28 ThreeBombs 85 INVENTORY_POWDER, // 0x29 Mushroom [XXX] 86 INVENTORY_BOOMERANG, // 0x2A RedBoomerang 87 INVENTORY_BOTTLE, // 0x2B BottleWithRedPotion 88 INVENTORY_BOTTLE, // 0x2C BottleWithGreenPotion 89 INVENTORY_BOTTLE, // 0x2D BottleWithBluePotion 90 MISC_ITEM_POTION_RED, // 0x2E RedPotion 91 MISC_ITEM_POTION_GREEN, // 0x2F GreenPotion 92 MISC_ITEM_POTION_BLUE, // 0x30 BluePotion 93 MISC_ITEM_BOMBS_10, // 0x31 TenBombs 94 DUNGEON_ITEM_BKEY, // 0x32 BigKey 95 DUNGEON_ITEM_MAP, // 0x33 Map 96 MISC_ITEM_RUPEES_1, // 0x34 OneRupee 97 MISC_ITEM_RUPEES_5, // 0x35 FiveRupees 98 MISC_ITEM_RUPEES_20, // 0x36 TwentyRupees 99 MISC_ITEM_GREEN_PENDANT, // 0x37 PendantOfCourage 100 MISC_ITEM_REDBLUE_PENDANT, // 0x38 PendantOfWisdom 101 MISC_ITEM_REDBLUE_PENDANT, // 0x39 PendantOfPower 102 INVENTORY_BOW, // 0x3A BowAndArrows 103 INVENTORY_BOW, // 0x3B BowAndSilverArrows 104 INVENTORY_BOTTLE, // 0x3C BottleWithBee 105 INVENTORY_BOTTLE, // 0x3D BottleWithFairy 106 MISC_ITEM_HEART_CONTAINER, // 0x3E BossHeartContainer 107 MISC_ITEM_HEART_CONTAINER, // 0x3F HeartContainer 108 MISC_ITEM_RUPEES_100, // 0x40 OneHundredRupees 109 MISC_ITEM_RUPEES_50, // 0x41 FiftyRupees 110 MISC_ITEM_HEART_SMALL, // 0x42 Heart 111 MISC_ITEM_ARROWS_1, // 0x43 Arrow 112 MISC_ITEM_ARROWS_10, // 0x44 TenArrows 113 MISC_ITEM_MAGIC_SMALL, // 0x45 SmallMagic 114 MISC_ITEM_RUPEES_300, // 0x46 ThreeHundredRupees 115 MISC_ITEM_RUPEES_20, // 0x47 TwentyRupees2 116 INVENTORY_BOTTLE, // 0x48 BottleWithGoldBee 117 INVENTORY_SWORD, // 0x49 L1Sword 118 INVENTORY_FLUTE, // 0x4A OcarinaActive 119 INVENTORY_BOOTS, // 0x4B PegasusBoots 120 MISC_ITEM_BOMB_UPGRADE, // 0x4C BombUpgrade50 121 MISC_ITEM_ARROW_UPGRADE, // 0x4D ArrowUpgrade70 122 MISC_ITEM_MAGIC_UPGRADE, // 0x4E HalfMagic 123 MISC_ITEM_MAGIC_UPGRADE, // 0x4F QuarterMagic 124 INVENTORY_SWORD, // 0x50 MasterSword 125 MISC_ITEM_BOMB_UPGRADE, // 0x51 BombUpgrade5 126 MISC_ITEM_BOMB_UPGRADE, // 0x52 BombUpgrade10 127 MISC_ITEM_BOMB_UPGRADE, // 0x53 ArrowUpgrade5 128 MISC_ITEM_BOMB_UPGRADE, // 0x54 ArrowUpgrade10 129 MISC_ITEM_BOMB_UPGRADE, // 0x55 Programmable1 130 0, // 0x56 Programmable2 131 0, // 0x57 Programmable3 132 INVENTORY_BOW, // 0x58 SilverArrowUpgrade 133 MISC_ITEM_RUPEES_NEGATIVE, // 0x59 Rupoor 134 0, // 0x5A Nothing 135 0, // 0x5B RedClock 136 0, // 0x5C BlueClock 137 0, // 0x5D GreenClock 138 INVENTORY_SWORD, // 0x5E ProgressiveSword 139 INVENTORY_SHIELD, // 0x5F ProgressiveShield 140 INVENTORY_ARMOR, // 0x60 ProgressiveArmor 141 INVENTORY_GLOVES, // 0x61 ProgressiveGlove 142 0, // 0x62 singleRNG 143 0, // 0x63 multiRNG 144 INVENTORY_BOW, // 0x64 ProgressiveBow 145 INVENTORY_BOW, // 0x65 ProgressiveBow 146 INVENTORY_BOW, // 0x65 ProgressiveBowAlternate 147 0, // 0x6A Triforce 148 0, // 0x6B PowerStar 149 0, // 0x6C TriforcePiece 150 // 0x70 MapLW 151 // 0x71 MapDW 152 // 0x72 MapA2 153 // 0x73 MapD7 154 // 0x74 MapD4 155 // 0x75 MapP3 156 // 0x76 MapD5 157 // 0x77 MapD3 158 // 0x78 MapD6 159 // 0x79 MapD1 160 // 0x7A MapD2 161 // 0x7B MapA1 162 // 0x7C MapP2 163 // 0x7D MapP1 164 // 0x7E MapH1 165 // 0x7F MapH2 166 [0x70 ... 0x7F] = DUNGEON_ITEM_MAP, 167 // 0x82 CompassA2 168 // 0x83 CompassD7 169 // 0x84 CompassD4 170 // 0x85 CompassP3 171 // 0x86 CompassD5 172 // 0x87 CompassD3 173 // 0x88 CompassD6 174 // 0x89 CompassD1 175 // 0x8A CompassD2 176 // 0x8B CompassA1 177 // 0x8C CompassP2 178 // 0x8D CompassP1 179 // 0x8E CompassH1 180 // 0x8F CompassH2 181 [0x80 ... 0x8F] = DUNGEON_ITEM_COMPASS, 182 // 0x92 BigKeyA2 183 // 0x93 BigKeyD7 184 // 0x94 BigKeyD4 185 // 0x95 BigKeyP3 186 // 0x96 BigKeyD5 187 // 0x97 BigKeyD3 188 // 0x98 BigKeyD6 189 // 0x99 BigKeyD1 190 // 0x9A BigKeyD2 191 // 0x9B BigKeyA1 192 // 0x9C BigKeyP2 193 // 0x9D BigKeyP1 194 // 0x9E BigKeyH1 195 // 0x9F BigKeyH2 196 [0x90 ... 0x9F] = DUNGEON_ITEM_BKEY, 197 // 0xA0 KeyH2 198 // 0xA1 KeyH1 199 // 0xA2 KeyP1 200 // 0xA3 KeyP2 201 // 0xA4 KeyA1 202 // 0xA5 KeyD2 203 // 0xA6 KeyD1 204 // 0xA7 KeyD6 205 // 0xA8 KeyD3 206 // 0xA9 KeyD5 207 // 0xAA KeyP3 208 // 0xAB KeyD4 209 // 0xAC KeyD7 210 // 0xAD KeyA2 211 // 0xAF KeyGK 212 [0xA0 ... 0xAF] = DUNGEON_ITEM_SKEY, 213 // null BigRedBomb 214 // null Crystal1 215 // null Crystal2 216 // null Crystal3 217 // null Crystal4 218 // null Crystal5 219 // null Crystal6 220 // null Crystal7 221 // null DefeatAgahnim 222 // null DefeatAgahnim2 223 // null DefeatGanon 224 // null RescueZelda 225}; 226 227static const struct ap_item *item_by_index[N_ITEMS]; 228static const struct ap_item *item_by_type[_MISC_ITEM_MAX]; 229static const struct ap_item *item_by_dungeon_item[_DUNGEON_MAX][_DUNGEON_ITEM_MAX]; 230 231// items x item_locs 232static struct lb item_lb; 233 234enum area { 235#define X(name, abbr) CONCAT(AREA_, name), 236DUNGEON_LIST 237#undef X 238 AREA_LIGHT_OVERWORLD, 239 AREA_DARK_OVERWORLD, 240 AREA_INSIDE, 241 _AREA_MAX, 242}; 243 244static const size_t area_loc_count[_AREA_MAX] = { 245 [AREA_SEWERS] = 4, 246 [AREA_HYRULE_CASTLE] = 6, // idk 247 [AREA_EASTERN_PALACE] = 8, 248 [AREA_DESERT_PALACE] = 7, 249 [AREA_AGAHANIMS_TOWER] = 2, 250 [AREA_SWAMP_PALACE] = 11, 251 [AREA_PALACE_OF_DARKNESS] = 15, 252 [AREA_MISERY_MIRE] = 9, 253 [AREA_SKULL_WOODS] = 9, 254 [AREA_ICE_PALACE] = 9, 255 [AREA_TOWER_OF_HERA] = 7, 256 [AREA_THEIVES_TOWN] = 9, 257 [AREA_TURTLE_ROCK] = 13, 258 [AREA_GANONS_TOWER] = 25, 259 260 // The following are very very rough estimates 261 [AREA_LIGHT_OVERWORLD] = 8, 262 [AREA_DARK_OVERWORLD] = 6, 263 [AREA_INSIDE] = 78, 264}; 265 266static size_t area_loc_start[_AREA_MAX] = {0}; 267 268static struct ap_item_loc item_locs[N_ITEMS]; 269static struct ap_item_loc * item_locs_by_item[N_ITEMS]; 270 271static void 272ap_item_init() { 273 lb_init(&item_lb, N_ITEMS); 274 size_t index = 0; 275 276 for (size_t i = 0; i < ARRAYLEN(items); i++) { 277 struct ap_item * item = &items[i]; 278 279 switch (item->type) { 280 case 0: 281 assert(0); 282 break; 283 case INVENTORY_SWORD: 284 case INVENTORY_BOTTLE: 285 item->copies = 4; 286 break; 287 case INVENTORY_SHIELD: 288 item->copies = 3; 289 break; 290 case INVENTORY_GLOVES: 291 case INVENTORY_BOW: 292 case INVENTORY_BOOMERANG: 293 case INVENTORY_ARMOR: 294 case INVENTORY_FLUTE: // XXX actually FLUTE/SHOVEL 295 case INVENTORY_POWDER: // XXX actually POWDER/MUSHROOM 296 item->copies = 2; 297 break; 298 case INVENTORY_BOMBS: 299 item->index = -1; 300 break; 301 default: 302 break; 303 } 304 305 switch (item->type) { 306 case _INVENTORY_MIN ... (_INVENTORY_MAX-1): 307 case _MISC_ITEM_MIN ... (_MISC_ITEM_MAX-1): 308 item->dungeon = -1; 309 break; 310 case DUNGEON_ITEM_SKEY: 311 switch(item->dungeon) { 312 // This only counts randomized keys; not keys dropped by enemies 313 case DUNGEON_AGAHANIMS_TOWER: item->copies = 2; break; 314 case DUNGEON_GANONS_TOWER: item->copies = 4; break; 315 case DUNGEON_PALACE_OF_DARKNESS: item->copies = 6; break; 316 case DUNGEON_SWAMP_PALACE: item->copies = 1; break; 317 case DUNGEON_SKULL_WOODS: item->copies = 3; break; 318 case DUNGEON_THEIVES_TOWN: item->copies = 1; break; 319 case DUNGEON_ICE_PALACE: item->copies = 2; break; 320 case DUNGEON_MISERY_MIRE: item->copies = 3; break; 321 case DUNGEON_TURTLE_ROCK: item->copies = 4; break; 322 case DUNGEON_HYRULE_CASTLE: item->index = -1; break; 323 case DUNGEON_SEWERS: item->copies = 1; break; 324 case DUNGEON_EASTERN_PALACE: item->index = -1; break; 325 case DUNGEON_DESERT_PALACE: item->copies = 1; break; 326 case DUNGEON_TOWER_OF_HERA: item->copies = 1; break; 327 default: assert(0); 328 } 329 break; 330 case DUNGEON_ITEM_BKEY: 331 switch(item->dungeon) { 332 // HC has a big key but it's a guaranteed drop 333 case DUNGEON_HYRULE_CASTLE: 334 case DUNGEON_AGAHANIMS_TOWER: 335 case DUNGEON_SEWERS: 336 item->index = -1; 337 break; 338 default: 339 item->copies = 1; 340 break; 341 } 342 break; 343 case DUNGEON_ITEM_MAP: 344 switch(item->dungeon) { 345 case DUNGEON_SEWERS: // XXX: Sewers vs. HC? 346 case DUNGEON_AGAHANIMS_TOWER: 347 item->index = -1; 348 break; 349 default: 350 item->copies = 1; 351 break; 352 } 353 break; 354 case DUNGEON_ITEM_COMPASS: 355 switch(item->dungeon) { 356 case DUNGEON_HYRULE_CASTLE: 357 case DUNGEON_AGAHANIMS_TOWER: 358 case DUNGEON_SEWERS: 359 item->index = -1; 360 break; 361 default: 362 item->copies = 1; 363 break; 364 } 365 break; 366 /* 367 case DUNGEON_ITEM_REWARD: 368 switch(item->dungeon) { 369 case DUNGEON_HYRULE_CASTLE: 370 case DUNGEON_AGAHANIMS_TOWER: 371 case DUNGEON_SEWERS: 372 item->index = -1; 373 break; 374 default: 375 item->copies = 1; 376 break; 377 } 378 break; 379 */ 380 default: 381 assert(0); 382 } 383 384 // Skip over the item 385 if (item->index == (size_t) -1) { 386 continue; 387 } 388 389 item_by_index[index] = item; 390 item->index = index++; 391 for (size_t c = 1; c < item->copies; c++) { 392 item_by_index[index] = item; 393 lb_init_equivalent(&item_lb, item->index, index++); 394 } 395 396 if (ITEM_IS_DUNGEON(item->type)) { 397 assert(item_by_dungeon_item[item->dungeon][item->type] == NULL); 398 item_by_dungeon_item[item->dungeon][item->type] = item; 399 } else { 400 LOG("%zu %p", index, item); 401 assert(item_by_type[item->type] == NULL); 402 item_by_type[item->type] = item; 403 } 404 405 406 LOG("%5zu %s * %zu", item->index, item->name, item->copies); 407 } 408 assert(index == N_ITEMS); 409 410 for (size_t i = 0; i < N_ITEMS; i++) { 411 item_locs[i].dungeon = (enum ap_dungeon) -1; 412 } 413 414 size_t l = 0; 415 for (enum area area = 0; area < _AREA_MAX; area++) { 416 assert_bp(area_loc_count[area] > 0); 417 assert_bp(l <= N_ITEMS); 418 419 area_loc_start[area] = l; 420 for (size_t dl = 0; dl < area_loc_count[area]; dl++) { 421 item_locs[l++].dungeon = area; 422 } 423 } 424 LOG("l = %zu", l); 425 assert_bp(l == N_ITEMS); 426 427 size_t real_dungeons = 0; 428 for (size_t i = 0; i < ARRAYLEN(items); i++) { 429 const struct ap_item * item = &items[i]; 430 if (item->dungeon == (enum ap_dungeon) -1 || item->index == (size_t) -1) { 431 continue; 432 } 433 if (item->dungeon == DUNGEON_AGAHANIMS_TOWER) { 434 //continue; 435 } 436 437 // Dungeon items (e.g. keys, map) must be in the dungeon they are for 438 enum area a = item->dungeon; 439 LOG("x'ing %s*%zu %zu %zu", item->name, item->copies, area_loc_start[a], area_loc_count[a]); 440 for (size_t loc = 0; loc < N_ITEMS; loc++) { 441 if (loc < area_loc_start[a] || loc >= area_loc_start[a] + area_loc_count[a]) { 442 lb_mark_negative(&item_lb, item->index, loc); 443 } 444 } 445 446 if (item->type == DUNGEON_ITEM_COMPASS && item->dungeon != DUNGEON_GANONS_TOWER) { 447 // Dungeons with compass happen to have pendants/crystals; held in the last slot 448 LOG("placing reward for %s", item->name); 449 for (size_t j = 10; j < N_ITEMS; j++) { 450 lb_mark_negative(&item_lb, j, area_loc_start[a] + area_loc_count[a] - 1); 451 } 452 real_dungeons++; 453 } 454 } 455 assert(real_dungeons == 10); 456 //ap_item_update(); 457 //ap_item_print_state(); 458} 459 460struct ap_item_loc * 461ap_item_loc_add(struct ap_node * node) { 462 if (node->item_loc != NULL) { 463 return node->item_loc; 464 } 465 enum area a = node->screen->dungeon_id; 466 if (a >= (enum area) _DUNGEON_MAX) { 467 if (node->screen->dungeon_room == (uint16_t) -1) { 468 a = AREA_LIGHT_OVERWORLD; // XXX support dark world 469 } else { 470 a = AREA_INSIDE; 471 } 472 } else { 473 if (node->type == NODE_ITEM || node->type == NODE_SPRITE) { 474 // XXX items inside are constant drops, not accounted for 475 return NULL; 476 } 477 } 478 assert(a < _AREA_MAX); 479 for (size_t l = area_loc_start[a]; l < area_loc_start[a] + area_loc_count[a]; l++) { 480 if (item_locs[l].node == NULL) { 481 node->item_loc = &item_locs[l]; 482 node->item_loc->index = l; 483 node->item_loc->node = node; 484 break; 485 } 486 } 487 if (node->item_loc == NULL) { 488 assert_bp(0); 489 return NULL; 490 } 491 492 if (node->screen->id == 0x0a68 && node->type == NODE_SPRITE) { 493 // Well Uncle 494 ap_item_loc_set_enum(node->item_loc, INVENTORY_SWORD); 495 } 496 497 item_lb.dirty = true; 498 ap_item_update(); 499 500 return node->item_loc; 501} 502 503void 504ap_item_loc_set_raw(struct ap_item_loc * item_loc, uint8_t recv_item) { 505 assert(item_loc != NULL); 506 assert_bp(recv_item < ARRAYLEN(recv_item_map)); 507 int item_type = recv_item_map[recv_item]; 508 return ap_item_loc_set_enum(item_loc, item_type); 509} 510 511void 512ap_item_loc_set_enum(struct ap_item_loc * item_loc, int item_type) { 513 assert(item_loc != NULL); 514 LOGB("Set item: %zu %p %d", item_loc->index, item_loc, item_type); 515 assert(item_type > 0); 516 517 if (item_loc->item != NULL) { 518 assert(item_loc->item->type == item_type); 519 return; 520 } 521 522 const struct ap_item * item = NULL; 523 if (ITEM_IS_DUNGEON(item_type)) { 524 assert(item_loc->dungeon != (enum ap_dungeon) -1); 525 item = item_by_dungeon_item[item_loc->dungeon][item_type]; 526 } else { 527 item = item_by_type[item_type]; 528 } 529 assert(item != NULL); 530 531 lb_mark_positive(&item_lb, item->index, item_loc->index); 532 ap_item_update(); 533} 534 535void 536ap_item_update() { 537 static bool initialized = false; 538 if (!initialized) { 539 ap_item_init(); 540 initialized = true; 541 } 542 if (!item_lb.dirty) { 543 return; 544 } 545 lb_deduce(&item_lb); 546 547 double item_progression_value[N_ITEMS] = {0}; 548 for (size_t i = 0; i < N_ITEMS; i++) { 549 if (!item_by_index[i]->is_progression) { 550 item_progression_value[i] = 0; 551 continue; 552 } 553 554 size_t possible_locations; 555 if (BM_ISSET(item_lb.halfs[0].paired, i)) { 556 possible_locations = 1; 557 } else { 558 possible_locations = N_ITEMS - BM_POPCOUNT(item_lb.halfs[0].bs[i]); 559 //LOG("%zu %s %zu", i, item_by_index[i]->name, possible_locations); 560 } 561 assert(possible_locations > 0 && possible_locations <= N_ITEMS); 562 563 item_progression_value[i] = 100. / possible_locations; 564 } 565 566 for (size_t l = 0; l < N_ITEMS; l++) { 567 struct ap_item_loc * item_loc = &item_locs[l]; 568 569 if (BM_ISSET(item_lb.halfs[1].paired, l)) { 570 size_t item_index = item_lb.halfs[1].pair[l]; 571 const struct ap_item * item = item_by_index[item_index]; 572 assert(item_loc->item == NULL || item_loc->item == item); 573 assert(item_locs_by_item[item_index] == NULL || item_locs_by_item[item_index] == item_loc); 574 if (!item_loc->item) { 575 const char *loc_name = item_loc->node != NULL ? item_loc->node->name : "(no node)"; 576 LOGB("Paired location %zu '%s' with item '%s'", l, loc_name, item->name); 577 } 578 item_locs_by_item[item_index] = item_loc; 579 item_loc->item = item; 580 item_loc->progression_value = item_progression_value[item_index]; 581 } else { 582 item_loc->progression_value = 0.; 583 for (size_t i = 0; i < N_ITEMS; i++) { 584 if (!BM_ISSET(item_lb.halfs[1].bs[l], i)) { 585 item_loc->progression_value += item_progression_value[i]; 586 } 587 } 588 } 589 } 590 591 ap_item_print_state(); 592} 593 594static void 595lb_selftest_print(struct lb * lb) { 596 lb_deduce(lb); 597 598 printf(" %20s ", ""); 599 for (size_t i = 0; i < lb->size; i++) { 600 printf("%zx", i >> 4); 601 } 602 printf("\n"); 603 604 printf(" %20s ", ""); 605 for (size_t i = 0; i < lb->size; i++) { 606 printf("%zx", i & 0xF); 607 } 608 printf("\n"); 609 610 for (size_t i = 0; i < lb->size; i++) { 611 size_t h = 0; 612 printf(" %20s ", item_by_index[i]->name); 613 for (size_t j = 0; j < lb->size; j++) { 614 if (BM_ISSET(lb->halfs[h].bs[i], j)) { 615 printf("x"); 616 } else if (BM_ISSET(lb->halfs[h].paired, i)) { 617 assert(lb->halfs[h].pair[i] == j); 618 printf("@"); 619 } else { 620 printf("."); 621 } 622 } 623 printf("\n"); 624 } 625 printf("\n"); 626} 627 628void 629ap_item_print_state() { 630 lb_selftest_print(&item_lb); 631 632 for (size_t l = 0; l < N_ITEMS; l++) { 633 struct ap_item_loc * item_loc = &item_locs[l]; 634 if (item_loc->node != NULL) { 635 LOG("Loc %#6zx, Value: %lf; %s %u %s %s", l, item_loc->progression_value, 636 (item_loc->item != NULL ? item_loc->item->name : "?"), 637 item_loc->dungeon, item_loc->node->name, item_loc->node->screen->name); 638 } 639 } 640} 641