Pyrel dev log, part 4

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Kinematics
    Apprentice
    • Feb 2013
    • 72

    #61
    The immunity issue may actually not be as complicated as I thought. Such factors are generally a product of affixes, which means we need to check stat procs. So process can be:

    Get all categories that contain the flag you're looking for (eg: harmed by cold, harmed by fire, etc).
    Get all items that have any of the selected categories.
    Process items.
    During process, have to check secondary aspects due to affixes.
    A jacket with resist fire would throw up an immunity flag during processing, preventing damage.
    An artifact with a unique category would throw up an immunity flag during processing, preventing damage.
    An item with special properties (wooden shoes that aren't harmed by electricity, or something) can include that flag at the top level, which would be found during processing, preventing damage.


    Essentially, immunities all get tossed over to the processing stage to be worked out. The initial item query only cares about collecting all items which -might- be subject to the damage being inflicted. A cold attack while you're holding 2 potions would only have to fully process those two, rather than all items in inventory.

    This also deals with having conflicting categories (eg: having Harmed by Fire in one category, and Resists Fire in another category). Processing doesn't care about "harmed by", it only cares about immunities, or resists, takes extra damage, or whatever.

    Comment

    • Derakon
      Prophet
      • Dec 2009
      • 9022

      #62
      Some potential reasons to hand naming off to a Proc:

      * Items that can get partially damaged (e.g. a "singed Walnut Staff of Teleport" vs. a "blackened Scroll titled 'xyz' of Phase Door"). SAngband has a similar mechanic, I believe. The engine doesn't know what elements there are nor how to map various kinds of elemental damage to different item types.

      * Items that can only be used under certain conditions (e.g. when standing in water, or during the daytime, etc.) could have their names modified to reflect their availability.

      * Equipment that gains experience when it is used -- several variants (mostly derivations of ToME, I believe) have artifacts that can gain experience and learn new powers, and their experience and level is displayed in the item's name. Absolutely the engine should not know or care about this.

      Anything that the engine doesn't know about must perforce be handled by a proc.

      Comment

      • Kinematics
        Apprentice
        • Feb 2013
        • 72

        #63
        Ok, definitely makes sense there.

        Comment

        • Kinematics
          Apprentice
          • Feb 2013
          • 72

          #64
          Another look at affixes:

          prefixes: quality, material, make. Logically can only have one of each, right? Unless you have some sort of Mithril and Adamantine Chain Mail, or some such, so material could conceivably have multiples. Quality and make are definitely singlular only, though.

          However, how would that get applied? Suppose we have a small shield, with material=mithril. A Mithril Small Shield? Or a Small Mithril Shield? The latter actually makes more sense.

          Of course we don't have just "a small shield", but rather "a small metal shield" (assuming mithril can only be applied to the metal shield, not to the leather one). In that case, "a mithril small metal shield" or "a small mithril shield"?

          Also, here, "small" seems to hold the same position as "set of" does for gloves. Technically, I suppose, there's no reason you couldn't have a single glove armor item (eg: Michael Jackson's "Rhinestone Glove", as opposed to "a Set of Rhinestone Gloves"). So I guess 'collectionType' isn't really the right name for it.

          We could also note that a flavor is really just a randomly generated (but persistent per game) material or color. You could also say that the colors for potions could be considered 'materials', in a sense, so 'flavor' is just 'randomly generated material' that has no effect on the object.

          Multihued Dragon Scale is a theme that has a prefix position. It can apply to hard boots. "A Multihued Dragon Scale Pair of Hard Leather Boots"? Or "A Pair of Multihued Dragon Scale Hard Leather Boots"? Or "A Pair of Multihued Dragon Scale Boots"?

          I'm thinking that the element: "a [pair of] hard leather boots", "a [small] metal shield" should be considered its own field -- primaryPrefix

          A theme's 'type' (for prefix themes) is defined by the majority type of its contained prefix-position affixes (eg: Multihued Dragon Scale contains 5 dragon scale affixes, which are prefix type 'material' (to fix: also has 4 affixes which are redundant with the dragon scale affixes), so it would be a 'material' type theme). 'Blassed' and 'Dwarven' would be type 'quality'.


          Prefix values:

          Material:
          Then: "a pair of [hard leather] boots", "a small [metal] shield" -- defaultMaterial
          defaultMaterial can then be replaced by a material affix or theme.
          Material goes after the primary prefix, even with no defaultMaterial.

          Quality:
          A [light] broadsword is simple enough.
          A [light] pair of hard leather boots, or a pair of light hard leather boots? A [light] small shield, or a small [light] shield?
          Quality is something that appears to best be placed before the primary prefix.

          Make:
          A [gnomish] shovel, a [dunadan] broadsword
          Make should go after material. EG: a mithril [dunadan] broadsword

          State:
          A [glowing] pair of hard leather boots (eg: boots are available for activation), a [singed] Walnut Staff of Teleport
          Something that can be inserted by proc.



          Initial proc called will collect information and pass it to the function that constructs the name. It then calls the function to put it all together. Custom procs can be written to handle determining object's state, individual values based on experience, etc., before passing the results to the final constructor function (or writing a custom constructor function, if needed).


          getNameProc(item)
          make decisions about what values to pass in -- flavor for material, theme for quality, etc

          The actual construction function is then extremely simple:
          Code:
          def getFulItemName(baseNoun, primaryPrefix = None, state = None, quality = None, material = None, make = None, name = None, type = None, quantity = 1):
              phrase = u""
          
              if state is not None:
                  phrase += u"%s " % state
          
              if quality is not None:
                  phrase += u"%s " % quality
          
              if primaryPrefix:
                  pluralPrefix = makePlural(primaryPrefix, quantity)
              else:
                  pluralPrefix = None
          
              if pluralPrefix is not None:
                  phrase += u"%s " % pluralPrefix
          
              if material is not None:
                  phrase += u"%s " % material
          
              if make is not None:
                  phrase += u"%s " % make
          
              phrase += u"%s" % makePlural(baseNoun, quantity)
          
              if name is not None:
                  if name[0].isalpha():
                      phrase += u" of %s " %name
                  else:
                      phrase += u" %s " %name
              elif type is not None:
                  phrase += u" %s" % type
          
              article = getArticle(phrase, quantity, name is not None)
          
              phrase = u"%s %s" %article %phrase
          
              return phrase
          'type' is the collection of suffixes, the building of which happens elsewhere.

          Basically, the top level proc makes all the decisions about what value to put in which parameters, and then calls this to put it all together.

          To an extent, this seems to hardcode certain value types in place, which may not be desirable. However that's really not the case. It's more that these are names that conveniently describe the -positions- where certain words can appear, and named to make that positioning understandable. You're also free to do things like use conjunctions in the values passed in (eg: "Mithril and Adaman") without affecting this part of the code.
          Last edited by Kinematics; March 2, 2013, 01:38.

          Comment

          • Kinematics
            Apprentice
            • Feb 2013
            • 72

            #65
            To clarify on the earlier point about the names vs positions, the signature of the function could be written as:

            Code:
            def getFulItemName(mainNoun, mainAdjective1 = None, mainAdjective2 = None, altNoun = None, altAdjective1 = None, altAdjective2 = None,
                               simplePostfix = None, fullPostfix = None, quantity = 1):
            where:
            altAdjective1 = state
            altAdjective2 = quality
            altNoun = primaryPrefix
            mainAdjective1 = material
            mainAdjective2 = make
            mainNoun = baseName
            simplePostfix = name
            fullPostfix = type

            To abstract away the meaning from the words used. Main and alt noun can be pluralized, and everything else is written as provided.

            The procs would still have references to the make/material/etc, since they are explicitly designed for the purpose of interfacing with the external data. That is, since procs are expected to be written for the needs of the variant, it's ok for them to 'know' about material vs quality vs whatever.

            Comment

            • Kinematics
              Apprentice
              • Feb 2013
              • 72

              #66
              Sample code:
              grammar pastebin
              nameProc pastebin

              grammar file is greatly simplified (and I remapped it to pretty much what I described above). It just puts together the bits provided, and pluralizes the possible nouns.

              nameProc ended up being fairly heavyweight to adapt to all the possible options, though simple cases (ie: no modifiers) should pass through with only a handful of checks. It also binds explicitly to the known types for the various prefixes, since I figure that information should be considered 'knowable' at the proc level. However that can be adjusted as long as the general concept still fits the grammar restrictions (two adjectives per noun, two nouns per phrase, and a couple postfix values).

              It has has several \todo's left in it (ie: problems that need fixed; can read to see what they are), and doesn't pull flavored items subtypes yet, since I wasn't sure where that info would end up. Also set a few values to dummy values since the nameInfo structure doesn't exist yet.

              Should probably be fairly easy to pass in a function call for setting state as part of the params initializer, for variants that want that. Then you can just set state with a call to that function and not have to duplicate the main functionality.

              It re-integrates Magnate's idea of using genus for situations with multiple affixes of a given type in order to reduce the potential name length. (aside: To do that it uses a bit of code I found for constructing a proper groupby, instead of the built-in version.)


              Also, for testing, I added this function to item.py:
              Code:
                  def testDescription(self):
                      import procs.nameProc
                      test = procs.nameProc.DefaultItemNamer(None, None, None)
                      testOutput = test.trigger(self)
                      stopName = u""
              And this code to gentown.py:
              Code:
                  r = things.items.itemLoader.makeItem(('ring', 'Slaying'), 80, curMap, (8, 5))
                  affix = things.items.itemLoader.getAffix("Strength")
                  affix.applyAffix(10, r)
                  affix = things.items.itemLoader.getAffix("Resist Fire")
                  affix.applyAffix(10, r)
                  affix = things.items.itemLoader.getAffix("Resist Cold")
                  affix.applyAffix(10, r)
                  r.testDescription()
              Wasn't up for trying to make the proc actually provide the requested name to the UI. Seemed to keep causing an infinite loop while debugging since the debugger itself wanted to know the result of the function while it was running. Wasn't worth the hassle to fix at this point.
              Last edited by Kinematics; March 2, 2013, 10:45.

              Comment

              • Magnate
                Angband Devteam member
                • May 2007
                • 5110

                #67
                You're looking at the original V base item names. In v4 I changed them so that no base item names contained words for materials (e.g. leather, metal), so that they didn't cause conflicts with affixes. I missed the fact that "small" is both a weapon prefix and an intrinsic part of the name of a type of shield. I like your primaryPrefix idea, I think. I think we just need more words for shields.

                The number of any type of prefix is governed by AFFIX_LIMITS - so yes, make and material are currently set at one each, but we cannot assume that they'll always be limited to one.
                "Been away so long I hardly knew the place, gee it's good to be back home" - The Beatles

                Comment

                • Magnate
                  Angband Devteam member
                  • May 2007
                  • 5110

                  #68
                  I don't like hard-coding affix types into naming code. It has to work with any permutation of affix types - including multiple affixes for make/material/quality, or none.
                  "Been away so long I hardly knew the place, gee it's good to be back home" - The Beatles

                  Comment

                  • Magnate
                    Angband Devteam member
                    • May 2007
                    • 5110

                    #69
                    This looks fine, apart from the hard-coding of make/material/quality/state. Surely if we order affix types correctly in the data file and use an orderedDict, we can abstract this?
                    "Been away so long I hardly knew the place, gee it's good to be back home" - The Beatles

                    Comment

                    • Kinematics
                      Apprentice
                      • Feb 2013
                      • 72

                      #70
                      Originally posted by Magnate
                      You're looking at the original V base item names. In v4 I changed them so that no base item names contained words for materials (e.g. leather, metal), so that they didn't cause conflicts with affixes.
                      Hmm. I believe a small metal shield had a different base defense rating than a small leather shield. Are you wanting to get rid of that distinction? Though even if you do, there's no reason a variant might not want it back, so I'd still be inclined to handle it. I could see it being a lower priority, though, or handled in a different manner.

                      Originally posted by Magnate
                      I think we just need more words for shields.
                      Such as that.

                      Originally posted by Magnate
                      The number of any type of prefix is governed by AFFIX_LIMITS - so yes, make and material are currently set at one each, but we cannot assume that they'll always be limited to one.
                      Right. I started off writing it with the assumption of one each, but decided to just refactor it so that any of them could have any number of instances. That way the getAdjective() function works regardless.

                      Originally posted by Magnate
                      I don't like hard-coding affix types into naming code. It has to work with any permutation of affix types - including multiple affixes for make/material/quality, or none.
                      I'd prefer avoiding it, but at this point I think it's necessary. It's also in the proc code level now, not the core, and the procs are specifically designed to do all sorts of custom work, and must therefore be aware of exactly what they're working on.

                      Also, simple order isn't sufficient. The first two adjectives describe the first noun, the second two adjectives describe the second noun. If you have two adjectives, even if they're in the correct order, it's not possible to say which noun they belong to without knowing which type of adjective is being referenced.

                      Also also, the order of the affix types doesn't include 'state', which I figure encompasses several of the examples Derakon brought up, though that's a lesser item since it can simply be considered as always the first entry.

                      Originally posted by Magnate
                      Surely if we order affix types correctly in the data file and use an orderedDict, we can abstract this?
                      If you can figure a way to abstract this in a sensible manner, please do. This code is what I came up with today. Maybe I'll come up with a better idea tomorrow.

                      Comment

                      • Magnate
                        Angband Devteam member
                        • May 2007
                        • 5110

                        #71
                        Originally posted by Kinematics
                        Hmm. I believe a small metal shield had a different base defense rating than a small leather shield. Are you wanting to get rid of that distinction? Though even if you do, there's no reason a variant might not want it back, so I'd still be inclined to handle it. I could see it being a lower priority, though, or handled in a different manner.
                        I already did get rid of both metal and leather. In Pyrel's object.txt, the base shields are, in ascending order of AC: Buckler, Small Shield, Large Shield, Kite Shield, Tower Shield, Bulwark. I am now thinking that we need to replace "small" and "large" because we should really avoid any adjectives in base item names.
                        "Been away so long I hardly knew the place, gee it's good to be back home" - The Beatles

                        Comment

                        • Kinematics
                          Apprentice
                          • Feb 2013
                          • 72

                          #72
                          Thinking about it some more, it could actually be possible to fully abstract away the adjective names, and just depend on slices of the AFFIX_TYPES. However it definitely requires an OrderedDict sequence, which I haven't gotten working yet. Aside from the problem I had with returning the value from the original read, if I define AFFIX_TYPES as an OrderedDict before using it, it still seems to generate things in a random order. Also, need to add a State type as the first entry.

                          Comment

                          • Magnate
                            Angband Devteam member
                            • May 2007
                            • 5110

                            #73
                            Originally posted by Kinematics
                            Thinking about it some more, it could actually be possible to fully abstract away the adjective names, and just depend on slices of the AFFIX_TYPES. However it definitely requires an OrderedDict sequence, which I haven't gotten working yet. Aside from the problem I had with returning the value from the original read, if I define AFFIX_TYPES as an OrderedDict before using it, it still seems to generate things in a random order. Also, need to add a State type as the first entry.
                            I don't think the json.load functions are capable of using an orderedDict straight off. I think we have to load them as a normal (unordered) dict, then sort them, then store them in an orderedDict.
                            "Been away so long I hardly knew the place, gee it's good to be back home" - The Beatles

                            Comment

                            • Kinematics
                              Apprentice
                              • Feb 2013
                              • 72

                              #74
                              Buckler, Small Shield, Large Shield, Kite Shield, Tower Shield, Bulwark
                              Well, small shield and large shield both seem to refer to a round shield type, which is definitely distinct from the other types. And a small round shield isn't much different from a buckler anyway. So I could see it making sense consolidating to: Buckler, Round Shield, Kite Shield, Tower Shield, Bulwark.

                              Comment

                              • Kinematics
                                Apprentice
                                • Feb 2013
                                • 72

                                #75
                                Originally posted by Magnate
                                I don't think the json.load functions are capable of using an orderedDict straight off. I think we have to load them as a normal (unordered) dict, then sort them, then store them in an orderedDict.
                                Ok, then we need to add some sort of field for ordering them. Fairly trivial to do. Though at that point we don't even need the OrderedDict; just create a sorted list of the affix type names. The naming code doesn't care about any of the other affix type fields.

                                Comment

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