Pyrel dev log, part 6

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Magnate
    Angband Devteam member
    • May 2007
    • 5110

    Pyrel dev log, part 6

    Originally posted by Derakon
    Regarding archery, I admit I don't feel especially strongly on exactly what numbers determine what. For gameplay's sake, though, I kind of want to deprecate multiple shots/round or at least downplay its importance. Carrying and retrieving lots of ammo isn't especially fun. Also, the "bullet time effect" you get when shooting only takes 50 or 33 energy gives the player lots of opportunities to interrupt combat to heal/escape.

    So while there's some elegance in having archery use the same rules as melee (whether or not stats are flipped), I'd rather move towards a system in which 1 turn = 1 shot, and we have whatever stats we need for that to scale sensibly. If you have any particular insight on how that could work, feel free to suggest something.
    Not yet I don't - that's quite a significant departure from Angband and will need quite some thought. I'd prefer a different approach, which sticks with the fin/prow system but uses a much more graduated scale for shots. So the default is 1 shot = 100 energy, but as finesse increases you'd drop that to 90/80/70 etc. until maybe a very very high level archer would get down to 50. The bullet-time effect is then more limited, and not much worse than that created by fractional blows (assuming that you stop the energy usage at a killing blow). In this system the SHOTS flag would reduce energy per shot rather than adding whole shots (which are considerably more unbalancing than whole blows).
    FWIW I tend to think of missile velocity as being the main determinant for damage (since you must punch through the target's armor) except when you get a critical hit, because that's when you hit the target's small squishy bits.
    Then you could stick with fin/prow the same way round as melee, but with the irritating niggle that prowess is basically irrelevant for crossbows (it just determines whether you can wind the thing at all).
    On an unrelated note, it occurs to me that creatures should perhaps have their own accuracy scores, perhaps even on a per-blow basis.
    Definitely.
    Also, my word we've sure gotten off-topic, haven't we?
    Sorry - I should have done this ages ago!
    "Been away so long I hardly knew the place, gee it's good to be back home" - The Beatles
  • Derakon
    Prophet
    • Dec 2009
    • 9022

    #2
    Originally posted by Magnate
    Not yet I don't - that's quite a significant departure from Angband and will need quite some thought. I'd prefer a different approach, which sticks with the fin/prow system but uses a much more graduated scale for shots. So the default is 1 shot = 100 energy, but as finesse increases you'd drop that to 90/80/70 etc. until maybe a very very high level archer would get down to 50. The bullet-time effect is then more limited, and not much worse than that created by fractional blows (assuming that you stop the energy usage at a killing blow). In this system the SHOTS flag would reduce energy per shot rather than adding whole shots (which are considerably more unbalancing than whole blows).
    This has the irritating attribute that the divisor for ranged finesse is completely different from the divisor for melee finesse! I don't like the sound of that.

    Mm, I guess you could get a similar effect by just making bows have terrible "balance", requiring a significantly larger investment in ranged finesse to get to multiple shots. Put another way, bows would all be extreme "prowess weapons", biased towards single large hits instead of many small hits. I guess that works.

    Then you can just use the existing melee system flat-out. No need to switch up finesse and prowess. Just imagine that all bows in Angband have a variably-adjustable draw weight, so the STR-40 warrior gets to use all his strength while the STR-10 mage is still able to use the bow at all.

    The SHOTS flag will be gone in any case; there will be more elegant and graduated things to replace it with. BLOWS in melee was replaced by tweaking the weapon's balance, if I recall correctly. Similar could be done for archery.

    I'm not going to worry about how crossbows and slings would realistically work compared to bows. All three work the same way in Vanilla, and I don't think confusing things by using different rules is a net gain. We can improve diversity by tweaking the various launchers' stats, of course. But they all should operate under the same rules, even if that makes for a few weird effects.

    (Also, remember to link the previous devlog thread -- and you might want to link the blunt-weapons thread, which your post was a response to)

    Comment

    • Kilumanjaro
      Rookie
      • Jun 2013
      • 9

      #3
      I've been thinking of ways to differentiate between the 3 ranged classes in both flavorful and gameplay oriented ways...

      Crossbows should be a weapon where the unskilled can pick it up and do decent amounts of damage, but can't compete with a skilled character using a Bow. In-game, this means a high damage dice with unreasonably low balance / heft numbers. i.e. Heavy Crossbow (4d6, 10 bal/0 heft). Even a clvl1 mage can pick this up and do some hurt, but a skilled ranger will never consider it because there is no damage multiplier... ever.

      Slings are an interesting case where we see them as the beginners weapon, but by the end of early game are wholly obsolete, but I envision them more as a prowess weapon. The spinning of the sling actually multiplies the force of your throw, while also making accurate throwing more difficult. Leather Sling (1d6, 0 bal/150 heft) <-10% accuracy> can be an attractive option for a warrior trying to deal some damage before closing into melee or finish off a runner, but the accuracy hit will keep it from ever being a reliable end-game damage source.

      Then come the skilled rangers choice of a Bow. While the potential damage per blow would be less than a sling, it takes no accuracy malus so it is more reliable, and can benefit from finesse scores to give you an edge. Short bow (1d8, 20 bal/80 heft)

      Comment

      • ekolis
        Knight
        • Apr 2007
        • 921

        #4
        Ooh, I like that! 4d6 for a crossbow sounds like a lot, though, unless bow users can get massive bonuses from prowess/finesse...
        You read the scroll labeled NOBIMUS UPSCOTI...
        You are surrounded by a stasis field!
        The tengu tries to teleport, but fails!

        Comment

        • Magnate
          Angband Devteam member
          • May 2007
          • 5110

          #5
          Originally posted by ekolis
          Ooh, I like that! 4d6 for a crossbow sounds like a lot, though, unless bow users can get massive bonuses from prowess/finesse...
          But the whole point is that with heft of 0 it's never multiplied by anything, ever. It's just a flat 4d6 throughout the game.

          Compare with a 4d4 seeker arrow in the late game, which could easily be multiplied by 3 (heavy composite longbow, prowess bonuses from item and from class, etc.).
          "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

            #6
            I think we'd probably be best-served by finding one ranged combat mechanic that works well, than by trying to proliferate at this stage. I certainly agree that bows, crossbows, and slings could be more differentiated, but if possible I'd like to put that off for a bit.

            For your specific ideas, while they sound reasonable enough as far as realism goes, it seems like only bows would be worth using in the endgame, which seems suboptimal for gameplay reasons.

            Comment

            • Therem Harth
              Knight
              • Jan 2008
              • 926

              #7
              Hmm. I was going to post about probable damage vs. armor penetration, but cursory searching indicates that a 30+ m/s slug can penetrate armor. Main problem with slings did indeed seem to be accuracy, as Kilumanjaro suggests.

              (Boy, I'm glad I don't live in medieval Europe.)

              Comment

              • wobbly
                Prophet
                • May 2012
                • 2629

                #8
                Slings are funny in that the word can be used to refer to many different weapons. My impression of slings changed a lot when I saw my friend's sling which was more like a catapult braced by 2 trees. The thing would definitely do some serious damage if you actually hit someone with it.

                Comment

                • Derakon
                  Prophet
                  • Dec 2009
                  • 9022

                  #9
                  The sling I usually think of is a small pouch with two long cords; you put a stone in the pouch and whirl it around via the cords. Your power there comes from how fast you spin the stone, which is a function of your strength, the length of the cords, and air resistance, I suppose.

                  I wouldn't expect the classic "wrist rocket" slingshot (an elastic strap held in a Y-shaped frame) to achieve very good velocities.

                  EDIT: regarding my earlier post, I don't want to discourage brainstorming. However, I'd like to get a feel for how ranged combat in general works under the new system before we go about introducing lots of complexity. We never did get finesse/prowess-based ranged combat in v4, so this is brand-new territory; Pyrel's first version should be mostly re-implementing existing systems except when we know that the new system is an improvement.

                  On a side note, things I've been working on recently:

                  * Adding new spells, as noted earlier in the 5th devlog thread. Once you've done one spell, doing more is actually pretty easy! So it's a fun way to contribute.
                  * Implementing a basic sentence conjugation system, so that I can cleanly switch between sentences in which the player is acting ("You attack the filthy street urchin") and ones in which a creature is acting ("The filthy street urchin attacks you"). This is not a very smart system, but it's easy to use, it was easy to implement, and it does everything we need currently.
                  * Standardizing status effects, in much the same way that elements have been standardized. This isn't complete yet.

                  Magnate has requested that someone tackle saving and loading, so I'll probably move on to that next. Meanwhile, mtadd has a pending pull request that implements character generation, which I need to review...
                  Last edited by Derakon; June 2, 2013, 18:08.

                  Comment

                  • mtadd
                    Rookie
                    • Nov 2011
                    • 24

                    #10
                    My original pull request for character generation was premature, but I've gone through and completed most of the necessities to get a character up and running. The pull request has been updated.

                    Notable things missing as compared to Angband:

                    1) character age, weight, social status, and maximize birth option
                    2) character info dependent upon equipment (ac, weapon hit,damage, blows)
                    3) level, experience, turn counts, etc.
                    4) default stat allocation when selecting point-based roller
                    5) random name generation
                    6) help integration (pressing ? to read 'birth.txt')

                    Otherwise, things should work as expected.

                    Comment

                    • Magnate
                      Angband Devteam member
                      • May 2007
                      • 5110

                      #11
                      Originally posted by mtadd
                      4) default stat allocation when selecting point-based roller
                      Argh. I suppose it's inevitable that with such a variant-friendly game engine we're going to end up with multiple birth systems, but IMO this has always been an area where choice isn't needed. Are we going to have the autoroller too?!
                      5) random name generation
                      That reminds me - Derakon, are you intending to use Sheldon W Simms's random name generator, beloved of *bands? Or something else? Porting the existing one would be a nice self-contained project for someone (possibly me if it's not done by the time I get to randarts).

                      Also, at the end of devlog #5 you asked:
                      Regarding having e.g. "<+5 fin>", any thoughts on having pvals generally display short text for what they modify? In Vanilla it's just "<+4, +1>" and the like. v4's items tend to have longer names in general, and I suspect it's only going to get worse in Pyrel...
                      Personally I think the names are already so long that there's no point attempting to convey any more information in the name line, and we should assume that all info (including even 'primary' stats like dice, AC, balance, heft) will be obtained from the 'I'nspect screen. Any space that is available for items with short names will barely contain primary stats and plusses, let alone pvals.

                      Having said that, there's no reason you couldn't come up with two- or three-letter abbreviations for all the possible pval stats, so they could be represented like resists.
                      "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

                        #12
                        Originally posted by Magnate
                        Argh. I suppose it's inevitable that with such a variant-friendly game engine we're going to end up with multiple birth systems, but IMO this has always been an area where choice isn't needed. Are we going to have the autoroller too?!
                        This is one area that ought eventually to be handled by procs, if for no other reason than that the birth system as a whole requires knowledge of what races and classes are available (and that races and classes are things that the player would care about). The final birth system will look rather different from the first pass.

                        That reminds me - Derakon, are you intending to use Sheldon W Simms's random name generator, beloved of *bands? Or something else? Porting the existing one would be a nice self-contained project for someone (possibly me if it's not done by the time I get to randarts).
                        I honestly never thought about this. If someone wants to implement it, they're welcome to do so.

                        Personally I think the names are already so long that there's no point attempting to convey any more information in the name line, and we should assume that all info (including even 'primary' stats like dice, AC, balance, heft) will be obtained from the 'I'nspect screen. Any space that is available for items with short names will barely contain primary stats and plusses, let alone pvals.
                        This is true for some weapons and armor, but not for all, and not for jewelry. Where possible we ought to be able to provide all important information in the item name.

                        Having said that, there's no reason you couldn't come up with two- or three-letter abbreviations for all the possible pval stats, so they could be represented like resists.
                        Yes, I think that's probably the way to go here. Have a list somewhere that ranks all the stats in tiers (with default low-priority values for unlisted stats), and then try to stuff as much information into the name as possible without running over some maximum name length.

                        Comment

                        • Derakon
                          Prophet
                          • Dec 2009
                          • 9022

                          #13
                          Time to do some designing. Magnate requested that we have a working save/load system, so how do we go about doing that?

                          The game state is defined by the following items:

                          * All Containers in the GameMap
                          * The Things in those Containers
                          * Any Containers in those Things (e.g. inventory, equipment)
                          * Any Things in those Containers, etc. etc. etc.

                          In other words, we need to be able to recursively serialize all of the Things in the game, as well as their relationships (i.e. the Containers). Note that serializing a Thing also includes serializing its Stats and any relevant Procs, but that's comparatively straightforward, so I'm ignoring it for the moment.

                          It seems to me that the simplest way to handle this is to have a class that is responsible for martialling all of these serializations. The basic flow would look like this:
                          Code:
                          1) The user selects the "Save" command. 
                          2) This calls GameMap.save()
                          
                          In GameMap class:
                          def save(self, filename):
                              serializer = gameSerializer.GameSerializer()
                              for container in self.idToContainerMap.values():
                                  serializer.addContainer(container)
                              serializer.writeFile(filename)
                          
                          In GameSerializer class:
                          def addContainer(self, container):
                              if container.id in self.idToContainerContents:
                                  # Already have this container.
                                  return
                              self.idToContainerContents[container.id] = []
                              for thing in container.contents:
                                  self.idToContainerContents[container.id].append(thing.id)
                                  self.addThing(thing)
                          
                          def addThing(self, thing):
                              if thing.id in self.idToThingSerialization:
                                  # Already serialized this Thing.
                                  return
                              self.idToThingSerialization[thing.id] = thing.getSerialization()
                              self.idToThingContainers[thing.id] = []
                              for container in thing.getContainers():
                                  self.addContainer(container)
                          self.idToThingContainers[thing.id].append(container.id)
                          In other words, we build up a mapping of Container IDs to Thing IDs ("This Container holds these Things"), a mapping of Thing IDs to lists of Container IDs ("This Thing has these Containers"), and a mapping of Thing IDs to shallow serializations of Things ("shallow" meaning "can be used to reconstruct the Thing, but not the containers in the Thing").

                          The generated file then contains all of the Container <-> Thing relationships, as well as the Thing serializations, all appropriately labeled. When we want to recreate the game state, first we create all of the necessary Containers; then, as we deserialize Things, we can put them into Containers, and put Containers into them, as appropriate.

                          There are a lot of details I'm glossing over here; in particular, Proc serialization and deserialization is going to be moderately tricky. That should all be handled as a subset of Thing [de]serialization though (i.e. Procs don't ever exist independent of Things). The above-described system ought to be enough to get us working, though.

                          Thoughts?

                          Comment

                          • AnonymousHero
                            Veteran
                            • Jun 2007
                            • 1393

                            #14
                            I may very well be missing something, but aren't procs just (basically) string references to a blob of code? Surely, you aren't expecting to serlialize/deserialize the actual code in any coherent way?

                            Comment

                            • Derakon
                              Prophet
                              • Dec 2009
                              • 9022

                              #15
                              No, I'm not planning on trying to serialize the code. But sometimes Procs create some state that needs to be preserved. For example, this is how temporary status effects are handled:

                              * Proc is invoked to create status effect.
                              * Proc creates a new StatMod in the target's Stats instance, flagging the status effect as active.
                              * Proc creates a synthetic Timer Thing which counts down the turns of the status's duration.
                              * When the Timer runs out, it calls a function in the Proc, which removes the StatMod.

                              The relationship between the Proc and the Timer is one of the Timer having a function pointer to one of the Proc's functions; obviously that isn't going to persist across [de]serialization, so it needs to be recreated. That's going to be tricky.

                              Now, when we have a function pointer, it'll look something like this:
                              Code:
                              <bound method Foo.foo of <__main__.Foo instance at 0x1004a73f8>>
                              One possible way to handle this particular issue, then, would be for the Timer's serialize() function to contain a note "I need to refer to the function 'TemporaryStatModProc.removeMod' of the object 0x1004a73f8". Then the Serializer would be responsible for recognizing that address, finding the corresponding object, and replacing the address with the object's ID.

                              Hm, though now that I look at the code, there's not actually a removeMod() function; it's a lambda. That could be a problem. Certainly, serializing a lambda with its bound context is not a reasonable approach. We could always just say "don't use lambdas", but they're awfully handy things...

                              Comment

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