Pyrel dev log, part 2

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • ekolis
    Knight
    • Apr 2007
    • 921

    #76
    Oh, I know what I did! I merged with the closed branch accidentally at first, so then I merged with the correct branch, but since you didn't change the creature loader afterward in the correct branch, the changes from the closed branch are still there! I'll try and figure out how to undo the merge with the closed branch... if I can't, I'll just copy over the creature loader from the correct branch!

    edit: backed out the merge with the closed branch, and that fixed it!
    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

      #77
      Originally posted by AnonymousHero
      This used to be the case, but isn't any longer. Range() is exactly equivalent to xrange() these days.
      Really?
      Code:
      >>> range(10) == xrange(10)
      False
      I could possibly conceive of that being true in Python 3, but it's not in Python 2.7.

      Comment

      • ekolis
        Knight
        • Apr 2007
        • 921

        #78
        By the way, I've got another pull request - found out what's up with the keyboard not working, too!
        You read the scroll labeled NOBIMUS UPSCOTI...
        You are surrounded by a stasis field!
        The tengu tries to teleport, but fails!

        Comment

        • ekolis
          Knight
          • Apr 2007
          • 921

          #79
          Well, range(10) == range(10), but xrange(10) != xrange(10)... so it could be either way!

          edit: oh, no, duh, it actually proves that they behave differently! :P
          You read the scroll labeled NOBIMUS UPSCOTI...
          You are surrounded by a stasis field!
          The tengu tries to teleport, but fails!

          Comment

          • mtadd
            Rookie
            • Nov 2011
            • 24

            #80
            Python 2.x : range() != xrange()

            In Python2.x, range() returns a list(), and xrange() returns an iterable object

            In Python3.x, range() returns an iterable object, however xrange() is undefined.

            Iterable objects don't necessary have to allocate every value simultaneously, saving in memory usage, as well as potential computation if the iterator isn't enumerated fully.

            Most builtin functions in Python2.x that return transform lists have been changed in Python3.x to return iterable objects (e.g. map, filter, zip, etc.) to improve memory performance. Python 2.6+ coding guidelines suggest using list comprehensions instead of these functions.

            Instead of..
            Code:
            map(str,filter(lambda x: 5<x<10,range(3,100)))
            Do
            Code:
            [str(x) for x in xrange(3,100) if 5<x<10]

            Comment

            • debo
              Veteran
              • Oct 2011
              • 2402

              #81
              FYI not sure what you're using for the display layer (I'm assuming something like curses) but I came across this the other day and it's pretty rad:



              Just thought you might find it useful.
              Glaurung, Father of the Dragons says, 'You cannot avoid the ballyhack.'

              Comment

              • ekolis
                Knight
                • Apr 2007
                • 921

                #82
                Wow, that's old school... reminds me of Works for DOS, the predecessor to MS Works!
                You read the scroll labeled NOBIMUS UPSCOTI...
                You are surrounded by a stasis field!
                The tengu tries to teleport, but fails!

                Comment

                • debo
                  Veteran
                  • Oct 2011
                  • 2402

                  #83
                  Originally posted by ekolis
                  Wow, that's old school... reminds me of Works for DOS, the predecessor to MS Works!
                  Yeah those examples reminded me of DOSShell lol
                  Glaurung, Father of the Dragons says, 'You cannot avoid the ballyhack.'

                  Comment

                  • Derakon
                    Prophet
                    • Dec 2009
                    • 9022

                    #84
                    Hey, if someone wants to write the UI layer using that, more power to them. It does look pretty nifty.

                    The baseline UI layer I've written uses wxWidgets, and is currently 704 lines long. That includes:

                    * Creating the windows at program start
                    * Accepting input, symbolizing it, and passing it to the engine
                    * Drawing the game view and any current user prompts
                    * Implementing various Prompt subclasses (e.g. asking for a selection from a list, or a direction), as well as a message history.

                    Creating an equivalent UI using a different backend ought to be fairly straightforward. The only reason I'm using wxWidgets is because that's what I'm familiar with, from having used it at work.

                    Comment

                    • Derakon
                      Prophet
                      • Dec 2009
                      • 9022

                      #85
                      I've pushed the input-handling rewrite to Bitbucket. This went more smoothly than I'd anticipated, actually, and the new input handling is much cleaner than what was in the (now-nonexistent) Listener class.

                      Amusing bugs encountered while working on this:

                      * Because the Player went from subclassing Listener to subclassing Creature, they got the Creature's random-walk update() function. Thus, every time you did something, immediately afterwards you would move in a random direction.

                      * Picking up an item only to discover that it now exists in two places at the same time (in your inventory, and on the floor).

                      * Causing game updates to happen right before you move, instead of right after, thus making it impossible to hit monsters because they move just before you strike.

                      * Managing to equip two rings to the same finger. How gaudy.

                      These have all, naturally, been fixed.

                      Current code stats:
                      * 4089 lines of code. Pyrel's broken 4000!
                      * 672 of them are whitespace
                      * 994 of them have comments

                      EDIT: okay, now it's time to talk through the next thing I'm going to tackle: speed.

                      In Angband, everything takes a discrete number of game turns, with the base rate being 10 game turns per normal-speed turn. This means, among other things, that you can't be exactly 3 times faster than normal, and there's nothing between 5 times faster than normal and 10 times faster. There's two main reasons for this system: one, it provides a simple system for updating game state (just run a game turn, then give turns to everything that's accumulated at least 100 energy), and two, Angband sticks to integer math. Still, Pyrel doesn't want to limit itself in that way, and it's willing to spend a little more time on computation. A smoother system would thus seem desirable.

                      Pyrel will keep the concept of "energy", i.e. the progress an entity has made towards resting enough to perform a single action. Fast entities acquire energy quickly; slow ones acquire energy slowly. Fast actions cost less energy to perform, while slow ones cost more. We want a standard reference speed to compare "fast" and "slow" against. That reference is 1. No, there's no units on it. All energy accumulation rates are relative to each other -- all the game cares about is which entity will get the next turn, and it'll advance time as much as needed for that to happen. Of course, Pyrel will probably have a day/night cycle which advances at some rate with respect to that reference speed, so you could define energy accumulation in terms of energy/second or something. But the point is that the denominator is ignored when it comes to game logic. An entity whose energy accumulation rate is 2 gets turns twice as quickly as one whose rate is 1; an entity at .5 gets them half as quickly.

                      When the game performs updates, it needs to know who gets the next turn. Every entity has, in addition to its accumulation rate, its current energy total. These two values can be used to find the entity who will pass 1 soonest. For example:

                      * Player: energy .25, rate 1
                      * Giant louse: energy 0, rate 2
                      * Giant mouse: energy .6, rate 1.25

                      It will take .75 before the player gets a turn, .5 before the louse does, and .32 before the mouse does. Thus the mouse updates first (and then subtracts 1 from its energy total), then the louse, then the player. Of course, it's possible that the mouse would perform a very fast command, and subtract less from its energy total, thus meaning that even after it acts, it still gets the next turn. Every time an entity updates, thus, it needs to be re-inserted into the sorted list. Fortunately we don't have to recalculate everyone's position in the list every time any entity takes an action.

                      When the player gets an action, the game engine cedes control back to the UI layer. At this point, input can be handled. In other words, the game flows like so:

                      UI layer: decide on a course of action for the player.
                      UI layer: call game.update()
                      Game: loop over all entities, updating them per their energy accumulations, until the player gets a turn
                      Game: return control to UI layer.
                      Last edited by Derakon; August 24, 2012, 05:28.

                      Comment

                      • LostTemplar
                        Knight
                        • Aug 2009
                        • 670

                        #86
                        and there's nothing between 5 times faster than normal and 10 times faster.
                        Angband handles speed much better, then you describe, actually every single unit of energy matter, and e.g. 33 energy/turn is faster then 32 energy/turn. This is due to extra energy (over 100) is not forgotten when character takes it's turn.

                        I once tryed to implement exact timing in my variant, in nearly the same manner, you want but without sorted list. So once the game processes all objects, it remebers minimum time out (1 - energy in your case), they have, advances time by this value, and process anything again.

                        Another thing I want for my variant is to get rid of overall speed, and just assign time value (energy) to all actions separately.
                        Last edited by LostTemplar; August 24, 2012, 07:55.

                        Comment

                        • Derakon
                          Prophet
                          • Dec 2009
                          • 9022

                          #87
                          Mm, you're right, fair point. I was a bit tired when I wrote that.

                          And yes, it's absolutely possible to have differing energy costs for every action. I need to figure out a clean way to represent that (it should be part of the Command structure, probably), since most actions should cost the same amount of time just to keep the player from getting too confused -- but the potential is there.

                          Comment

                          • ekolis
                            Knight
                            • Apr 2007
                            • 921

                            #88
                            I'd think it would be quite reasonable to at least have different energy costs for moving vs. attacking - speed in Angband is so overpowered mainly because it acts as a damage multiplier! If you wanted to get fancy, you could even go with different attack speeds for different weapons, like Crawl does...
                            You read the scroll labeled NOBIMUS UPSCOTI...
                            You are surrounded by a stasis field!
                            The tengu tries to teleport, but fails!

                            Comment

                            • LostTemplar
                              Knight
                              • Aug 2009
                              • 670

                              #89
                              Different energy cost is usefull for some things, e.g. being overburdened only slows movement speed, while other actions are unaffected, etc.

                              Comment

                              • ekolis
                                Knight
                                • Apr 2007
                                • 921

                                #90
                                You could even go with spells that take varying amounts of time to cast, like in Final Fantasy IV where you could spam Fire all day long, but if you wanted to cast Firaga, better hope nobody kills the black mage before they're done casting!

                                edit: and that really messed with you when fighting the Mad Doctor, since his reversal gas might flip the effects of your spells mid-cast! Maybe you could work in some mechanic like that into some boss monsters?
                                You read the scroll labeled NOBIMUS UPSCOTI...
                                You are surrounded by a stasis field!
                                The tengu tries to teleport, but fails!

                                Comment

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