Pyrel dev log, part 3

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • fizzix
    Prophet
    • Aug 2009
    • 3025

    #76
    Originally posted by Magnate
    So we have two options: we either explicitly disallow this, or find a way to make it work. I'm with Derakon on not disallowing anything where possible.
    Actually, I'm with buzzkill on this one. Normally, what Magnate is saying is good practice, except when it creates major confusions in either the code or from the player's side. I think it makes sense to have some reasonable tiering and not allow things to be only modified by tiers above it. MDS is below INT, so INT can modify MDS but MDS does not modify INT. This is clear and very easy for a player to understand. MDS modifying INT does not make sense to me, and honestly I can't imagine the desire to allow for such a silly (to me) idea, especially when it seems to cause as much headaches, and double-especially if it creates hard to understand code.

    Percentage modifiers can all be calculated simultaneously after the additional modifiers. I don't see this being a problem.

    I'm all for removing the limitations from the current code base, but I don't see this as a major limitation. If you want a stat that modifies INT, then you just add another tier above it.

    Comment

    • Derakon
      Prophet
      • Dec 2009
      • 9022

      #77
      Okay, I think we've about accomplished all we can with the stats discussion. Everyone understands the problem, so now we're just bickering over premises.

      Changing the subject, I spent some time examining why dungeon generation was so slow (~6s to make a 360x120 dungeon on my pretty speedy computer). It broke down to roughly 4s spent on deciding how to draw every tile (even the ones not visible) and 2s spent on instantiating 43000 granite walls. I've fixed the latter problem by making one granite wall and then pretending that it's in 43000 different tiles -- this required tweaking how we interact with terrain but otherwise appears to be completely functional. The former problem is soluble by re-optimizing the drawing logic. Previously it had been tracking the state of every tile on the map, and in a very inefficient way (causing the GameMap to generate 3 synthetic Containers for every drawn tile). By optimizing this, I have dungeon generation and initial drawing down to .8s...but I've somehow broken the drawing logic -- I'm doing the right amount of work but it's not resulting in the right symbols being drawn. That's why this hasn't been pushed yet.

      Note that if we want to do a full-detail map of the entire dungeon (which I fully support), then we're going to have to optimize this again. There's noticeable lag whenever we have to redraw the entire display. I haven't profiled the code yet to find out why.

      Meanwhile, mtadd and noz have been busy making improvements to the Qt UI and refactoring a lot of code that was duplicated across the various UI frontends. Pyrel development is busy!

      Comment

      • AnonymousHero
        Veteran
        • Jun 2007
        • 1393

        #78
        Originally posted by Magnate
        The important point here is that circularities are inevitable: if we allow DEX to modify MDS and then MDS to modify INT, that is fundamentally no different to allowing INT to modify MDS and then, via whatever route, MDS to end up modifying INT.
        Wait, what? One of those contains a cycle in the dependency graph of the calculations, the other does not.

        I still don't understand why cycles are supposedly unavoidable. Cycles would imply ill-defined results unless you (extremely luckily) happen upon a convergent series. Unless you want that you have to have some way of preventing (or breaking, amounts to the same thing) cycles. Having the user do it would be insanely bad UI and finding the optimal way to break a cycle is probably NP-hard even if you have a criterion for optimization (which you don't... is it maximizing the sum of all stats, maximizing two of the status, what, exactly?).

        The only reasonable thing to do is to prevent the cycles (by construction) in the first place.

        EDIT: ... and there is such a thing as "too general". Simply breaking this into a set of N tiers is a very simple solution that has proven itself in lots of games and variants. The exact value of N is debatable, but AFAICT N=10 would accomodate basically any variant that I've seen, certainly.

        Comment

        • Magnate
          Angband Devteam member
          • May 2007
          • 5110

          #79
          Originally posted by AnonymousHero
          Wait, what? One of those contains a cycle in the dependency graph of the calculations, the other does not.
          Sorry, I didn't mean there was no difference mathematically; I meant in terms of game design. If we're allowing 'primary' stats to be influenced by 'skills' which are in turn based off those same primary stats - my point was that DEX/INT are interchangeable in the example.
          finding the optimal way to break a cycle is probably NP-hard even if you have a criterion for optimization (which you don't... is it maximizing the sum of all stats, maximizing two of the status, what, exactly?).
          I think this is precisely why Derakon suggested that the person best placed to decide this is the player.

          Nothing is immutable. We can try whatever Derakon thinks is best at this point and revisit it later on in development if we think it can be improved. I suspect quite a lot of things will be improved once they've come into contact with other bits.
          "Been away so long I hardly knew the place, gee it's good to be back home" - The Beatles

          Comment

          • Therem Harth
            Knight
            • Jan 2008
            • 926

            #80
            Umm. I think I must be missing something big here?

            Aside from the problem of positive feedback loops, basing skills and stats off of each other mutually strikes me as a terrible idea from a gameplay and development perspective. It seems to me it would make things very opaque to the player - small stat or skill bonuses could have huge, sweeping impacts for non-obvious reasons. This would confuse players, and also might make it hard for developers to get what they wanted when adding stuff, IMO.

            Basically this looks to me like a good way to create Dependency Hell, Angband-style. I don't think that's a good idea.

            Disclaimer: I am probably entering this discussion with inadequate knowledge and inadequate expertise...

            Comment

            • ekolis
              Knight
              • Apr 2007
              • 921

              #81
              Yeah, I'd tend to agree that the potential for feedback loops is a bad enough thing to just disallow skills from directly influencing stats.

              However, if skills could grant *bonuses* to stats (either directly or via equipment abilities), instead of directly influencing them, that would not be so bad. The distinction I'm making between bonuses and influence is that bonuses are just additive modifiers, and are applied after all other calculations, so they don't feed back into the math for skills; they just influence things that are directly computed from stats (e.g. max HP and mana).

              So for instance you could have a STR of 12 and a CON of 15, and let's say that CON influences poison resistance by 2% per point of CON. So your poison resistance (assuming no other modifiers) is 30%. Now suppose you wear an Amulet of the Snake, which increases your STR and CON by 1 for every 10 points of poison resistance. Your "base" STR and CON remain at 12 and 15 (for purposes of skills), but your "effective" STR and CON are now boosted to 15 and 18, and these scores are what are used for other calculations, such as damage and max HP.

              ...Hmm, actually that wouldn't work all that well, because this would require defining resistances as "skills", and then why not define everything as a "skill" so it can affect stats? But if you do that, then nothing is left to *be affected* by anything! So then you're left with a rather stunted form of the "tier" system that's already been discussed...
              You read the scroll labeled NOBIMUS UPSCOTI...
              You are surrounded by a stasis field!
              The tengu tries to teleport, but fails!

              Comment

              • Derakon
                Prophet
                • Dec 2009
                • 9022

                #82
                I've spent some time these last few days optimizing the display layer. There were a lot of stupid constant-time costs being made that caused drawing to be a lot slower than it needed to be; that's now cut down so far that it's basically negligible. The only time display code causes noticeable slowdown now is if you're showing and scrolling a massive portion of the map -- and I expect that before we go to production, we'll have a flip-scrolling option (like the default Vanilla behavior) for large-display users, instead of the current "always center on the player".

                I also refactored the ASCII artist code, which had been basically duplicated to three different locations for the three UI layers. However, since the Curses UI doesn't work on my machine, I didn't touch it, just the Qt and wxWidgets layers. The Curses layer should still work fine, but it should be refactored by someone who can test it.

                As part of these changes, the UI needed a way to be notified when its old drawings are completely invalid, e.g. because a new level has been generated. I saw two reasonable ways to solve the problem:

                1) Create another linkup between the engine and the UI layer, that lets the engine say "Hey UI layer, a new level has been generated; react as appropriate".

                2) Create a publish/subscribe system where different components of the program can publish "events", and other components can subscribe to those events. So the UI layer subscribes to the "new level generation" event, which is published by the GameMap whenever its makeLevel() function is called.

                I went with the latter as it is more generic and flexible -- if anything wants to know when a new level is generated, then they can just subscribe to the event, and if we want other event types they're trivial to create. It is a bit harder to trace cause and effect through the code (compared with option 1), though it's by no means impossible.

                Comment

                • Derakon
                  Prophet
                  • Dec 2009
                  • 9022

                  #83
                  Item stats are now applied to the wielder when the item is equipped. This does mean that, for example, our testing character has a Heft of .2 when it (characters currently have no gender) equips a Dagger, but details! Eventually items will have at least two sets of stats; one will refer to the item itself and another will indicate the stats that are applied to the wielder on equip. However, that can be put off for awhile; in any event Magnate is doing some work on getting items to have more interesting stats, and I wanted to hold off on further work to the data/item.txt file until he was done, so we wouldn't step on each others' toes.

                  The observant among you may have noticed that it's been three weeks since this thread was updated. For my part, things have slowed down a lot for three reasons:

                  1) Work has sucked up almost all of my coding juice lately.
                  2) My working environment has been a small windowless room with no other people (since that's where the hardware that my code controls exists).
                  3) I've somehow injured my hip by sitting on it wrong / in bad chairs.

                  Between these three things, when I get home from work I don't have the mental or physical capacity to sit in my desk chair and work. In the interests of avoiding mental burnout, I took some time off lately, which helps with item 1 but not item 3 -- my hip does seem to slowly be getting better, but I'd rather not aggravate it if I can possibly manage. Right now I'm writing this post while squatting on my heels, for example. I may want to expedite some research I did awhile back into standing desks...

                  Anyway, where to next? Off the top of my head:

                  * The item stat split as mentioned above -- currently blocked on Magnate, but it's not urgent anyway.
                  * Basic AI for creatures. In particular, we need a pathfinding algorithm. I remember reading some discussion of that on these forums awhile back; something about heat maps IIRC.
                  * Item containers. This will enable the quiver and spellbooks.
                  * The effect refactor. Currently all procs are stuffed into a single file; that needs to be reorganized, and the difference between Procs and Filters and Calculators needs to be made more explicit (currently they all subclass from Proc).

                  And of course there's everything on the to-do list.

                  All of these are unblocked, so they're just waiting for someone to have appropriate amounts of time, inclination, and insight to tackle them.

                  Comment

                  • Antoine
                    Ironband/Quickband Maintainer
                    • Nov 2007
                    • 1010

                    #84
                    I hope you will get some physio and a more ergonomic environment!

                    A.
                    Ironband - http://angband.oook.cz/ironband/

                    Comment

                    • Derakon
                      Prophet
                      • Dec 2009
                      • 9022

                      #85
                      Originally posted by Antoine
                      I hope you will get some physio and a more ergonomic environment!

                      A.
                      I've shifted to sitting on an exercise ball at work, which definitely helps -- my head's more level with the displays, and the ball requires a much more active posture compared to just sitting in a chair.

                      This also isn't the first time I've had hip trouble; I have some exercises I'm doing to strengthen the stabilizer muscles in the hip. I should get better.

                      Thanks for the concern!

                      Comment

                      • Derakon
                        Prophet
                        • Dec 2009
                        • 9022

                        #86
                        I had to take my car in to the dealer for some minor work, and while I was there I did this:



                        When you select an item from the inventory (or equipment), now, the game will examine the item, determine the possible valid interactions, and prompt you for which one you want to do, complete with the keystroke needed to perform that action normally. This should make the item-use commands much more discoverable.

                        Comment

                        • ekolis
                          Knight
                          • Apr 2007
                          • 921

                          #87
                          Cool

                          So what's with all the ASCII Microsoft logos?
                          You read the scroll labeled NOBIMUS UPSCOTI...
                          You are surrounded by a stasis field!
                          The tengu tries to teleport, but fails!

                          Comment

                          • Derakon
                            Prophet
                            • Dec 2009
                            • 9022

                            #88
                            Y'know, I hadn't even realized that they had the same layout as the Windows logo. Oh well. Those walls were added to give me something to look at while debugging some display issues. We don't really need them now, but I think it's kind of neat for DebugTown to have all sorts of random debris lying around from the various features and bugs that it was used to fix.

                            I've taken a look at what it would take to implement containers. The basic concept is simple enough -- an item that has an inventory. Where it gets hairy is in figuring out how the UI works. Ideally we want something that requires as few extra keystrokes as possible.

                            Vanilla has three container types, and they all behave differently: chests, quivers, and spellbooks. Chests can only be interacted with "in the dungeon" (i.e. you cannot open a chest in your inventory), but can hold any number of items or money. The quiver is permanently equipped to the player, has arbitrary capacity (but subtracts that capacity from the backpack!), and you always see its contents. Spellbooks go in the inventory, have fixed contents, and you don't see those contents until you open them.

                            In Pyrel, I'd like to unify these three item types so they all use the same code (let's worry about the inventory-constraint ramifications of fully-functional chests later). Figuring out how to do that while maintaining reasonably sane UI is going to be tricky. For now, I'm just going to throw out a proposal that doesn't try to hew to the existing UI too much; I'd appreciate any comments or alternate proposals y'all might have.

                            1) Container items are limited in what they can carry: by maximum number of slots, by maximum total items, and by item types/subtypes. We have the following constraints for existing Vanilla containers:

                            * Quiver: maximum count 40, maximum slots unlimited, holds arrows, bolts, and bullets (i.e. sling ammo).
                            * Chests: maximum count unlimited, maximum slots limited by chest type, holds any type of item, items are placed into chest when it is created.
                            * Spellbooks: maximum count/slots determined on item creation, holds "spell scroll" items, items are placed into book when it is created and cannot be removed.

                            2) When in the inventory, containers have two new interaction commands: 'O'pen container and 'P'ut item in/out of container. The former simply toggles display of the container's contents when viewing the inventory. The latter prompts the user for an item, then for a container to put it in; or, if the user selects a container, then the item in the container they select is removed to the player's inventory.

                            3) When performing commands with items, we need to be able to operate on the quiver as well as its contents (e.g. throw the quiver, or throw a bolt from the quiver?). If the container is currently open, then this is no problem -- the quiver and its contents are displayed separately and can be individually operated on. If the container is closed, then we need to prompt the user, when they select the container, for if they want to do the operation on the container or its contents. This gets a bit tricky for the following edge cases:

                            * Empty containers: of course you want to do the operation on the container.
                            * Spellbooks: their contents cannot be thrown, dropped, destroyed, etc.
                            * Spellbooks: the "cast spell" operation cannot be performed on a book, only on its contents (ditto quivers and the "fire" command).

                            4) Everything that interacts with the inventory in some way needs to know about containers so it can recurse through them. For example, the 'q'uaff command searches for drinkables in the player's inventory -- it must now also search through containers in the inventory to see if they have anything drinkable in them. When calculating the weight of the inventory, we must also sum up the weight of all container contents. Et cetera.

                            I think that about covers it. No doubt -- containers add a lot of complexity to inventory interactions. But they'll enable some interesting variant behavior too, so I think it's worth doing them properly. Some possible examples that won't go into Vanilla anytime soon, if ever:

                            * finding spellscrolls in the dungeon and placing them into empty spellbooks
                            * The backpack as a special container in its own right (and the only container that can be equipped)
                            * Containers that protect their contents from the elements
                            * Bags of Holding with unlimited capacity but they make everything put into them heavier / require 10 turns to get anything out of them / etc.

                            Comment

                            • Magnate
                              Angband Devteam member
                              • May 2007
                              • 5110

                              #89
                              Originally posted by Derakon
                              In Pyrel, I'd like to unify these three item types so they all use the same code (let's worry about the inventory-constraint ramifications of fully-functional chests later). Figuring out how to do that while maintaining reasonably sane UI is going to be tricky. For now, I'm just going to throw out a proposal that doesn't try to hew to the existing UI too much; I'd appreciate any comments or alternate proposals y'all might have.

                              1) Container items are limited in what they can carry: by maximum number of slots, by maximum total items, and by item types/subtypes. We have the following constraints for existing Vanilla containers:

                              * Quiver: maximum count 40, maximum slots unlimited, holds arrows, bolts, and bullets (i.e. sling ammo).
                              Quiver is limited to ten 'slots' of its own in V/v4.
                              * Chests: maximum count unlimited, maximum slots limited by chest type, holds any type of item, items are placed into chest when it is created.
                              * Spellbooks: maximum count/slots determined on item creation, holds "spell scroll" items, items are placed into book when it is created and cannot be removed.

                              2) When in the inventory, containers have two new interaction commands: 'O'pen container and 'P'ut item in/out of container. The former simply toggles display of the container's contents when viewing the inventory. The latter prompts the user for an item, then for a container to put it in; or, if the user selects a container, then the item in the container they select is removed to the player's inventory.

                              3) When performing commands with items, we need to be able to operate on the quiver as well as its contents (e.g. throw the quiver, or throw a bolt from the quiver?). If the container is currently open, then this is no problem -- the quiver and its contents are displayed separately and can be individually operated on. If the container is closed, then we need to prompt the user, when they select the container, for if they want to do the operation on the container or its contents. This gets a bit tricky for the following edge cases:

                              * Empty containers: of course you want to do the operation on the container.
                              * Spellbooks: their contents cannot be thrown, dropped, destroyed, etc.
                              * Spellbooks: the "cast spell" operation cannot be performed on a book, only on its contents (ditto quivers and the "fire" command).

                              4) Everything that interacts with the inventory in some way needs to know about containers so it can recurse through them. For example, the 'q'uaff command searches for drinkables in the player's inventory -- it must now also search through containers in the inventory to see if they have anything drinkable in them. When calculating the weight of the inventory, we must also sum up the weight of all container contents. Et cetera.

                              I think that about covers it. No doubt -- containers add a lot of complexity to inventory interactions. But they'll enable some interesting variant behavior too, so I think it's worth doing them properly. Some possible examples that won't go into Vanilla anytime soon, if ever:

                              * finding spellscrolls in the dungeon and placing them into empty spellbooks
                              * The backpack as a special container in its own right (and the only container that can be equipped)
                              * Containers that protect their contents from the elements
                              * Bags of Holding with unlimited capacity but they make everything put into them heavier / require 10 turns to get anything out of them / etc.
                              I think this is definitely the right approach. I think the quiver should be considered a separate equippable entity from the backpack - they only reason they're conflated in V is because of the inventory code!

                              I think we probably need to think about handling nested containers. It's always hugely irritated me when games have arbitrary limitations on this. Yes it's variant territory (you can't put anything inside anything else in V, apart from stuff in the quiver/backpack), but you've already mentioned dealing with bulk (as distinct from weight) in a previous thread so would be good to design it in. I think having volume as the limiting factor is a better determinant than any more arcane rationalisation.

                              I think it's an excellent idea to make the 'use' commands present a composite list of all appropriate items from all containers, rather than make the user open the container first.
                              "Been away so long I hardly knew the place, gee it's good to be back home" - The Beatles

                              Comment

                              • Derakon
                                Prophet
                                • Dec 2009
                                • 9022

                                #90
                                Originally posted by Magnate
                                Quiver is limited to ten 'slots' of its own in V/v4.
                                Yes, but the V/v4 quiver is also made of elastic -- it can hold any number of ammo units as long as there's room to steal from the backpack. Pyrel's system would have you have to get a separate quiver for every 40 units of ammo you want to carry, and those quivers would in turn use up backpack space whether or not they are used. Less flexible, but more realistic; at the very least, easier to code.

                                I think this is definitely the right approach. I think the quiver should be considered a separate equippable entity from the backpack - they only reason they're conflated in V is because of the inventory code!
                                Given that an archer character in Pyrel would probably be carrying as many as 4-6 quivers, do you still think that they should be equippable? Certainly the player should be able to fire from a quiver that is stored in the backpack.

                                I think we probably need to think about handling nested containers. It's always hugely irritated me when games have arbitrary limitations on this. Yes it's variant territory (you can't put anything inside anything else in V, apart from stuff in the quiver/backpack), but you've already mentioned dealing with bulk (as distinct from weight) in a previous thread so would be good to design it in. I think having volume as the limiting factor is a better determinant than any more arcane rationalisation.
                                A month or two ago I spent some time writing up a post on how a bulk-based inventory system would work. I abandoned it, though, because I couldn't come up with any reasons why a bulk-based system would be more fun than a weight/slot-based system. The sticking factor, if I recall, was that it would almost always be better to carry, say, 20 more potions than 1 more suit of armor -- so if you wanted carrying capacity to be a serious constraint, then swap gear was functionally unusable. Otherwise you end up in the situation of being able to carry basically as many consumables as you want, which has unpleasant ramifications for game balance.

                                I've since come round to the suspicion that the proper way to handle "realistic" inventory constraints is to have a slot-based system where different item types have a different maximum number of items per slot. For example, 10/slot for potions and scrolls, 40/slot for ammo, 1/slot for armor, 5/slot for daggers...if you want to load up on consumables, then you'll be sacrificing slots that you could be using for swap gear, and vice versa.

                                The important thing with an inventory system, after all, is that it force the player to make interesting choices.

                                Anyway, if you want to change the rules for what can be put into what, all you need do is add extra constraints to the Carrier mixin that holds items and controls whether or not items can be added to containers. This is one situation in which I don't think we need to design in extra behavior that we don't plan on using. There's space in the framework if someone feels like extending what we have, so they can do it easily enough down the road if it becomes important.

                                I think it's an excellent idea to make the 'use' commands present a composite list of all appropriate items from all containers, rather than make the user open the container first.
                                Forcing the player to open the container first was my first-pass idea but I simply couldn't convince myself that it wasn't an absolutely terrible approach.

                                Comment

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