Bug or not in handling object.txt info?

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • ewert
    Knight
    • Jul 2009
    • 707

    Bug or not in handling object.txt info?

    Check http://angband.oook.cz/forum/showthread.php?t=3460

    It seems:
    If you have two lines with A:xx:yy to zz, only the latter one is handled. The same with E: lines, only the latter one is handled. I tried a E:xxx | yyy too, doesn't work.

    Should having say:

    A:100:1 to 29
    A:20:30 to 100

    work so that the item gets more rare at 30? It'd be useful for being able to finetune item rarities which I'm trying to do for myself. Also being able to add multiple effects would be nice. Seems most items are actually "hardcoded" effects not stuff you can edit in the object.txt, which is kinda sad considering "easyvariantsy" stuff for things like making different items in there.
  • Magnate
    Angband Devteam member
    • May 2007
    • 5110

    #2
    Originally posted by ewert
    Check http://angband.oook.cz/forum/showthread.php?t=3460

    It seems:
    If you have two lines with A:xx:yy to zz, only the latter one is handled. The same with E: lines, only the latter one is handled. I tried a E:xxx | yyy too, doesn't work.

    Should having say:

    A:100:1 to 29
    A:20:30 to 100

    work so that the item gets more rare at 30? It'd be useful for being able to finetune item rarities which I'm trying to do for myself. Also being able to add multiple effects would be nice. Seems most items are actually "hardcoded" effects not stuff you can edit in the object.txt, which is kinda sad considering "easyvariantsy" stuff for things like making different items in there.
    Interesting - quite a major bug, if it is confirmed. I have opened ticket #1173 to track this.

    At the moment only one E: line is supported, but the effects framework is about to come under discussion and may end up moved to an external file as you (and others) have suggested.
    "Been away so long I hardly knew the place, gee it's good to be back home" - The Beatles

    Comment

    • Tiburon Silverflame
      Swordsman
      • Feb 2010
      • 405

      #3
      Over on the other thread, someone (Timo?) suggested that the format for the A: line is, one line only, using | as the separator. So I repeated the test I described in town, with pebbles set to

      A:100:0 to 10 | 10:11 to 50

      and iron shots set to A:100:0 to 100.

      This loads, so clearly the code allows the format. In testing in town (where I have all the critters with DROP_4 and ONLY_ITEM for this) I was getting basically equal amounts of pebbles and shots...so that appears to be working correctly.

      The second part is harder to test, simply because the drops are harder to narrow down...tried a couple things that didn't work, but I think I have a test that will work.

      a) Read object.txt, and rewrite ALL A: lines as, say,
      A:10:0 to 20 | 15:21 to 100
      Easy to do this with a small chunk of code.

      b) Then hand-edit in the various types so that specific weapons, armors, etc. get specific tweaks, to either
      A:100:0 to 20 | 15:21 to 100 or
      A:10:0 to 20 | 100:21 to 100

      This should create radical distribution shifts.

      Comment

      • ewert
        Knight
        • Jul 2009
        • 707

        #4
        I'm currently using a file that has the edits changed into the | format, it loads, but not sure if it is just RNG or what messing with me, I'm seeing zero stat potions, augmentation, even though for example have seen lots of xp potions, lots of rare rods etc. Difference is, stat potions are in after the | defined level range, whereas those already rare and deep level items have only the basic A: line. (I'm farming around dlvl96)

        So far it just feels it is not working right. My char is a mage, and you'd think I would see more healing and augmentation potions, as I had healing allocation up to 200 (twice that of enlightenment and augment), and I stair scummed with detect enchantment a LOOOOOT of vaults, and zero stat potions, aug potions, healing potions.

        Something is still wacky, or then RNG is reallllly messing with me.

        edit: Just farmed some more, and remembered that there was something wrong with chests about item generation. So THAT is how I've seen those low lvl items, not because they still had some allocation in the deep levels, but because the chests spawned them. I'm now 90+% sure that using the A: line with | does not work properly. It ignores the rest and uses only the first x:y to z range.
        Last edited by ewert; July 8, 2010, 16:38.

        Comment

        • Tiburon Silverflame
          Swordsman
          • Feb 2010
          • 405

          #5
          That's why I'm suggesting what I do. You make ONE armor common, and ONE weapon, and ONE...etc. at depth 20, then make something different common at depth 21. This will put things into extremely sharp focus, hopefully no matter what the RNG wants to do.

          Don't have time for this right now; I have the file re-written, the code's trivial for that, but I don't have time to hand-edit it. Should be able to get to it later.

          Comment

          • ewert
            Knight
            • Jul 2009
            • 707

            #6
            Erm, me thinks the message did not get across, so I will put it in short:

            A:x:y to z | a:b to c

            does not work currently. Only x:y to z gets processed. The item stops appearing after z, because the code does not recognize or use "b to c" at all.

            Comment

            • PowerDiver
              Prophet
              • Mar 2008
              • 2820

              #7
              I don't think you need to experiment. The item generation accesses k_ptr->alloc_prob to do its work. So either the code needs to generate multiple separate item kinds for the multiple A: possibilities or that value needs to change depending on the drop level. I believe that kind numbers are hard coded, and there is no direct way to change things if the ranges overlap, not to mention Tak has been trying to make k_info be const, so I don't see how multiple alloc probs are even possible in the current codebase unless you hardcode multiple kinds with separate alloc_probs. Well, maybe hardcode is not the precisely correct word and multiple entries in k_info.txt would work, but that way leads to things horrible.

              Comment

              • Tiburon Silverflame
                Swordsman
                • Feb 2010
                • 405

                #8
                If it's not possible, there are some serious design flaws. This should not be hard.

                Comment

                • ewert
                  Knight
                  • Jul 2009
                  • 707

                  #9
                  I didn't quite follow that. Anyways, what I got from perusing the code is that it creates an allocation "tablethingy" somehow using the alloc info, and just picks the item from there. =P A separate "tablethingy" (array whatever pointer gaga) for kind_is_good stuff.

                  Anyways, my gut feeling would point to a somewhat simple parsing code problem instead of a big coding issue in being able to use multiple depth & rarity settings, heck even the object.txt file comments at start imply so ... but I am prolly totally wrong and it is something awful instead.

                  Comment

                  • PowerDiver
                    Prophet
                    • Mar 2008
                    • 2820

                    #10
                    Originally posted by ewert
                    I didn't quite follow that. Anyways, what I got from perusing the code is that it creates an allocation "tablethingy" somehow using the alloc info, and just picks the item from there. =P A separate "tablethingy" (array whatever pointer gaga) for kind_is_good stuff.
                    Maybe I misread the code. Always a strong possibility.

                    Comment

                    • Tiburon Silverflame
                      Swordsman
                      • Feb 2010
                      • 405

                      #11
                      Given that it's C code, HIGHLY possible.

                      I hate C as an application language...

                      Comment

                      • PowerDiver
                        Prophet
                        • Mar 2008
                        • 2820

                        #12
                        Originally posted by Tiburon Silverflame
                        Given that it's C code, HIGHLY possible.

                        I hate C as an application language...
                        C is not the problem. The function is easy to read. The question is whether init_obj_alloc() is the function that actually sets up object allocation. It would not be surprising if someone did something somewhere else that overrides it or modifies it somehow.

                        Comment

                        • ewert
                          Knight
                          • Jul 2009
                          • 707

                          #13
                          Code:
                          43	/*
                          44	 * Using k_info[], init rarity data for the entire dungeon.
                          45	 */
                          46	bool init_obj_alloc(void)
                          47	{
                          48	        int k_max = z_info->k_max;
                          49	        int item, lev;
                          50	
                          51	
                          52	        /* Free obj_allocs if allocated */
                          53	        FREE(obj_alloc);
                          54	
                          55	        /* Allocate and wipe */
                          56	        obj_alloc = C_ZNEW((MAX_O_DEPTH + 1) * k_max, byte);
                          57	        obj_alloc_great = C_ZNEW((MAX_O_DEPTH + 1) * k_max, byte);
                          58	
                          59	        /* Wipe the totals */
                          60	        C_WIPE(obj_total, MAX_O_DEPTH + 1, u32b);
                          61	        C_WIPE(obj_total_great, MAX_O_DEPTH + 1, u32b);
                          62	
                          63	
                          64	        /* Init allocation data */
                          65	        for (item = 1; item < k_max; item++)
                          66	        {
                          67	                const object_kind *k_ptr = &k_info[item];
                          68	
                          69	                int min = k_ptr->alloc_min;
                          70	                int max = k_ptr->alloc_max;
                          71	
                          72	                /* If an item doesn't have a rarity, move on */
                          73	                if (!k_ptr->alloc_prob) continue;
                          74	
                          75	                /* Go through all the dungeon levels */
                          76	                for (lev = 0; lev <= MAX_O_DEPTH; lev++)
                          77	                {
                          78	                        int rarity = k_ptr->alloc_prob;
                          79	
                          80	                        /* Save the probability in the standard table */
                          81	                        if ((lev < min) || (lev > max)) rarity = 0;
                          82	                        obj_total[lev] += rarity;
                          83	                        obj_alloc[(lev * k_max) + item] = rarity;
                          84	
                          85	                        /* Save the probability in the "great" table if relevant */
                          86	                        if (!kind_is_good(k_ptr)) rarity = 0;
                          87	                        obj_total_great[lev] += rarity;
                          88	                        obj_alloc_great[(lev * k_max) + item] = rarity;
                          89	                }
                          90	        }
                          91	
                          92	        return TRUE;
                          93	}
                          94	
                          95	
                          96	
                          97	
                          98	/*
                          99	 * Choose an object kind given a dungeon level to choose it for.
                          100	 */
                          101	s16b get_obj_num(int level, bool good)
                          102	{
                          103	        /* This is the base index into obj_alloc for this dlev */
                          104	        size_t ind, item;
                          105	        u32b value;
                          106	
                          107	        /* Occasional level boost */
                          108	        if ((level > 0) && one_in_(GREAT_OBJ))
                          109	        {
                          110	                /* What a bizarre calculation */
                          111	                level = 1 + (level * MAX_O_DEPTH / randint1(MAX_O_DEPTH));
                          112	        }
                          113	
                          114	        /* Paranoia */
                          115	        level = MIN(level, MAX_O_DEPTH);
                          116	        level = MAX(level, 0);
                          117	
                          118	        /* Pick an object */
                          119	        ind = level * z_info->k_max;
                          120	
                          121	        if (!good)
                          122	        {
                          123	                value = randint0(obj_total[level]);
                          124	                for (item = 1; item < z_info->k_max; item++)
                          125	                {
                          126	                        /* Found it */
                          127	                        if (value < obj_alloc[ind + item]) break;
                          128	
                          129	                        /* Decrement */
                          130	                        value -= obj_alloc[ind + item];
                          131	                }
                          132	        }
                          133	        else
                          134	        {
                          135	                value = randint0(obj_total_great[level]);
                          136	                for (item = 1; item < z_info->k_max; item++)
                          137	                {
                          138	                        /* Found it */
                          139	                        if (value < obj_alloc_great[ind + item]) break;
                          140	
                          141	                        /* Decrement */
                          142	                        value -= obj_alloc_great[ind + item];
                          143	                }
                          144	        }
                          145	
                          146	
                          147	        /* Return the item index */
                          148	        return item;
                          149	}
                          Okay is the lines of 72 to 88 the problem? Where is alloc_prob defined? I don't know much c, was more of a basic/pascal/java guy myself when a kid. =P But these are the relevant parts of the generation code as far as I can tell. As I said I don't quite follow what it says, but does it create the allocation info for each level separately?

                          From what I can tell, if I could code properly in c I would guess it is not a big change, but seems to need both parsing changes in alloc_prob and changes here to use multiple values if available ...

                          Comment

                          • Tiburon Silverflame
                            Swordsman
                            • Feb 2010
                            • 405

                            #14
                            Why does the item loop go from 1 to < k_max? This actually says you can never allocate more than (k_max - 1) items. No biggie, just curious...

                            The major problem is lines 69 and 70.

                            Look at the loop structure. It's per item, first. Get the item, then get the *single fixed* min/max level numbers and rarity; I assume these are from the A: line, ewert. These have to be recoded to themselves be level-dependent. In pseudocode:

                            for level = 0 to MaxDepth
                            for objectIndex = 1 to LastObject
                            obj = ObjectTable[objectIndex]
                            rarity = obj.getRarity(level)
                            if rarity > 0
                            ...add object to lists as necessary

                            Yeah, I think in depth first, more than in items...but it wouldn't matter.

                            Then you need a getRarity for the objects, which should just be keeping all the A: lines separate. Start from the first, return the first rarity where the input (level) matches the bounds on the A: line. If none do, return 0. So we make alloc_min and alloc_max arrays.


                            64 /* Init allocation data */
                            65 for (item = 1; item < k_max; item++)
                            66 {
                            67 const object_kind *k_ptr = &k_info[item];
                            68
                            69 int min = k_ptr->alloc_min;
                            70 int max = k_ptr->alloc_max;
                            71
                            72 /* If an item doesn't have a rarity, move on */
                            73 if (!k_ptr->alloc_prob) continue;
                            74
                            75 /* Go through all the dungeon levels */
                            76 for (lev = 0; lev <= MAX_O_DEPTH; lev++)
                            77 {
                            int rarity = 0;
                            int numAllocs = k_ptr->allocs_count; /* new field, computed during parsing */
                            for (alloc = 1; alloc <=numAllocs; alloc++) {
                            int min = k_ptr->alloc_min[alloc];
                            int max = k_ptr->alloc_max[alloc];
                            if (lev >= min && levl <= max)
                            {
                            78 rarity = k_ptr->alloc_prob[alloc];
                            break;
                            }
                            79
                            80 /* Save the probability in the standard table */
                            81 if ((lev < min) || (lev > max)) rarity = 0;
                            82 obj_total[lev] += rarity;
                            83 obj_alloc[(lev * k_max) + item] = rarity;
                            84
                            85 /* Save the probability in the "great" table if relevant */
                            86 if (!kind_is_good(k_ptr)) rarity = 0;
                            87 obj_total_great[lev] += rarity;
                            88 obj_alloc_great[(lev * k_max) + item] = rarity;
                            89 }
                            90 }

                            I believe that should do it...barring indexing issues, I don't recall if C arrays start at 0 or 1.

                            This would take a tiny bit more time, but given that it's a one-shot process done during creation, that's not a factor.

                            Comment

                            • PowerDiver
                              Prophet
                              • Mar 2008
                              • 2820

                              #15
                              The parser has a comment that only one A: is allowed. Unfortunately whoever wrote it was too lazy to put in a check to produce an error when a second A: line is encountered.

                              I'd say the bug is the comment section of object.txt.

                              Multiple alloc lines might be a good idea, but to do it properly requires some familiarity with the codebase. In addition, I think that if it is done the alloc_prob[] should be changed to 32 bit variables at the same time.

                              Comment

                              Working...
                              😀
                              😂
                              🥰
                              😘
                              🤢
                              😎
                              😞
                              😡
                              👍
                              👎