Pyrel dev log, part 4
Collapse
X
-
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. -
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.Leave a comment:
-
Originally posted by MagnateYou'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.
Originally posted by MagnateI think we just need more words for shields.
Originally posted by MagnateThe 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.
Originally posted by MagnateI 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.
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 MagnateSurely if we order affix types correctly in the data file and use an orderedDict, we can abstract this?Leave a comment:
-
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?Leave a comment:
-
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.Leave a comment:
-
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.Leave a comment:
-
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""
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()
Last edited by Kinematics; March 2, 2013, 09:45.Leave a comment:
-
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):
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.Leave a comment:
-
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
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, 00:38.Leave a comment:
-
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.Leave a comment:
-
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.Leave a comment:
-
itemName (alternate):
baseNoun: as above; singular; lowercase
amulet, boots, et
formatString: fully decorated string for handling formatting
%f - flavor
%p - plural
EG:
%f %p[Amulet~] of Charisma
Code:outString = item.formatString if item.flavor: outString.replace("%f", item.flavor) else: outstring.replace("%f ", "")
This is more flexible with potential unusual naming forms, but a little more complicated in code.Leave a comment:
-
In short, I think there's definitely room for gameplay-meaningful categories, as opposed to ones that are just used for deciding what kinds of items are generated or how to describe them.
I don't object in principle to this, but I'm not certain what we'd use it for. Do you have any reasonably concrete examples?Leave a comment:
-
Originally posted by DerakonFirst off, given the myriad different ways we may want to name things, we should be handing naming off to a set of Procs. These functions would be handed an item and possibly a context, and be told to come up with a name for them. Basically they'd implement Item.getShortDescription().
The most obvious reason to use Procs here is to handle the artifact/normal-item split
nameInfo:
baseNoun (or baseName) - fundamental name of the object; can be used in isolation; the noun that is modified by flavor
EG: amulet; potion; boots; shoes; greaves
Use example: You activate a Silver Ring of Ice. The ring glows with a bright blue light!
-- Mark for pluralisation (eg: "potion~")
collectionType - collection descriptor used against the base name, if appropriate
EG: "set of" gloves, "pair of" boots, "suit of" chain mail
-- Mark for pluralisation (eg: "Set~ of"); capitalize appropriately (ie: not "set~ of")
specialName - the 'name' of an artifact
EG: Galadriel (the Phial of Galadriel), 'Elessar' (the Amulet 'Elessar')
-- If present, can use 'the' as the article
Extra:
flavor - cosmetic descriptor of an object (optional)
EG: silver amulet; red potion; mahogany staff; pair of white leather boots; pair of striated greaves
-- Note: not included in nameInfo iteself, but referenced when constructing the name
Procs:
GetItemName() - properly cased full description (though limited in character length)
GetItemNoun() - lowercase baseNoun, singular
others...
GetMonsterName()?
~~ really not convinced on setting the name call as a proc.. Can you clarify more on how you think it would be more useful than item.GetName()? The addition of the nameInfo and categories dictionaries to the item record seems to obsolete any uses.
Categories:
I really like the basic idea. Gets rid of the artificial restrictions of only being able to have a type and subtype to describe the item's characteristics.
I agree that "harmed by xxx" probably doesn't belong there. Every single potion is going to be harmed by cold, so it would be more appropriate to flag the category "potion" as being harmed by cold. If an item is an exception to a category rule, they can include specific flags on the item to override (or if there's a significant subset of, say, "hardened potions", they can get their own category).
From that, may be able to strip category-specific flags from most items, assuming that those flags are (almost) always present on items of a given category. EG: If all unique items can't be harmed by the elements, put those flags on the unique category, rather than on each individual item.
The question is how to query it.
A cold attack hits the player. I want all items that are harmed by cold. Options:
Top-level flag: query each item for item.hasFlag(HARMED_BY_COLD)
Direct category: query each item for HARMED_BY_COLD in item.categories
Indirect category 1: get all categories that have the HARMED_BY_COLD flag; query each item for override flag, then each of those categories. Clumsy.
Indirect category 2: query each item for item.hasFlag(HARMED_BY_COLD); item function queries its categories for that flag
Indirect category 3: get all categories that have the HARMED_BY_COLD flag; get all items that are in those categories; query each such item for an override; process all resulting items.
Main problem: overriding a category's general properties. EG: a leather jacket of resist fire. A leather jacket would be in the soft armor category, so would be harmed by fire, but the specific jacket would have immunity to fire.
Need more thought. Just posting what I've got so far.Leave a comment:
Leave a comment: