Tuesday, 1 April 2014

Delayed events

The re-ordering (still under work) of Creature class has been a success. It has made things more clear and I have also improved parts that have been unfinished for a long time. I regret that I left Creature class alone for quite a long time, but then again when you go back you often see things new way and know better how to proceed.

Currently I'm trying to think how to implement events. I don't want to use them more than I have to, because they can be tricky. Most events will be for traps I guess but there is one for lighting a fuse of dynamite. Of course there are problems. The event is including data about the object, but it's not synchronized in all cases.

Let's say you lit the fuse of dynamite. There will be a delayed explosion event at the location of the dynamite. However the dynamite can get lost in case you put it into a container and move the container itself. The location of items inside it are not updated, because it would be too heavy for even modern computers to handle. Just imagine if all items of all monsters would update their location when monsters move.

There are couple of solutions. You could include the container's id in the event (using its location) or simply search the item from containers if it's not on ground when the explosion happens to synchronize the location. Whatever the solution, I think there must be a two-way notification from event to object and also object to event, because the object can be destroyed before it explodes or something else happens to it.


  1. I would have a list of things that are on a timer and going to do something after a set time, like this dynamite, bombs etc. Wherever you moved the dynamite to, when it was time to explode you would just look at the location: carried, in a box, buried, whatever, and act accordingly.

  2. Wait. Wait. wait...
    Why do you want to link the event to the location?
    Item has all initial info about itself, location, or creature or container etc
    So, you have to link even to item and get everything you need through it.
    There is no need in synchronization, because saving something about item, except items ID or pointer to it would lead to mess of doubled data.
    Of course, item should have link to its event and event should have link to next event, if it is possible.
    So we can safely handle them. For example, if item calls destructor.

  3. When you put the item in container it "disappears" from the game world, because otherwise like I said you would need to process each item in all containers (=slow). That's why you can't link the event to the item, it doesn't work that way. Of course, the event has to know where the dynamite is at any moment so I have to figure out how to do it. There could be a host id for item to tell it's in a container (which then could make it possible to point the event to the item), but it adds some complexity to container routines.

    Before you comment more try it in action. If you have a real working solution, then I would like to know.

    1. Aha. got it. well. Yes I have the solution. Because made it in my dead FFHtR project and inherited this idea from it to Fallen.
      It isn't my idea, I interrogated Anfier, the author of Rayel.
      Rayel is real jewel, if we speak abut programming architecture and disaster, if we speak about game-design, but it isn't our topic.

      Blog reply isn't really great way to talk about it.
      Well. One thing sounds disturbing - "When you put the item in container it "disappears" from the game world, because otherwise like I said you would need to process each item in all containers (=slow)".
      Frankly, I can't understand, why you should process anything at all, when it is idle. Looks like architecture flaw.

      Okay, lets talk about your dynamite.
      It has four potential states:
      it is on map, on creature or in other item (container).
      An the last one, Error State, Item is nowhere. Game should have some way to track such items, because they could leak and clutter items storage array.
      So, item stores links to its "masters" map cluster, creature or other item. (it is sort of double data, because cluster, for example, also has pointer to item class, but we need this coords. So we can call "masters" function and of course, check possible glitches, when item reports to be marked linked to something that don't know it. It sounds harder, then it is really are. )
      Also, it has like to next item.
      So, we can “ask” item and found its location through it.
      If Item.is_linked_to_creature
      If Item.is_linked_to_item (- our container)
      Then, we have events. That stored in the array, one after another. These events are used for everything. Creatures moved using them, items fly etc.
      For example we lit the fuse of the dynamite and it would explode in N turns after this.
      Cool. We made even about it and add it in to events list to position Current Turn + N. There could be other events, but events has link to next one in this list. So, we can put literally mln events in to one position.
      Cruel monster took it from the map and put this dynamite into the container.
      Method took item from the map cluster added to creature and then moved into item. Nobody cares about event.
      When event comes, it check its item and call explosion routines. This routines gets items and ask it about its location.
      Dynamite reports that it is linked to item (container). Container reports that it is on creature, and creature reports that it is on tile.
      Of course, explosion method should handle it, including other items in the container, but itsn’t the problem. Because container would report all items inside. It has link to first one and all of them has link to next.
      Simple, we have the actor ready and we know where the stage right is at the moment the act begins. We don’t need to track items position. Because we aren’t interested in dynamite, until the fuse will lit up.
      It could be even eaten by monster, when the time would come, it would explode inside poor bastard.
      Of course, if dynamite would be destroyed in action, or disabled we have to handle it. Clear the event and so on, but it is just the basics.
      The same is for creatures too. We don’t need to track them, until they would act in one way or another.
      That’s why I was surprised.
      For example, I use 2400x2400 "dungeons" in Fallen right now. It is more that 5 mln. tiles. It is impossible to process and all creatures and items on fly, of course. And we shouldn’t have.

  4. Processing or tracking creatures means that you handle their actions (moving etc. each turn). How else they would move? Of course you can restrict movement to nearby locations, because (full) AI actions outside visible range is probably not needed. But anyway you have to go through the list of creatures to know where they are in the first place.

    What you described is a complex version of what I thought about giving item (and the event) a host id (like a container). That way the event would know the item is in a container X and the location of container is easy to find from the list, because containers aren't hidden inside anything. I guess it's the only way to handle this problem.

    1. aha! Got you! :-) "But anyway you have to go through the list of creatures to know where they are in the first place.".
      Here is the trick. No, we don't. The same is for items, traps. etc.
      we don't do this. They move, act, fight using the events!
      Because all creatures don't do anything every turn, do they?
      For example. We have two creatures, one of them is PC and they fight to the death!
      Lets say, both of them have only one type of attack and there are no other creatures, items etc, for simplicity.
      PC attack speed - 5 turns.
      Monster speed - 7 turns.
      Current turn is 0.
      Here is our events array (part of it):
      PC event "melee attack" placed to current turn + speed = 5.
      Monster attack placed to 7.
      Then we pass the turns.
      1. no events. We don't have to check anything. No need! Because we have no events, moves, acts at all! This turn took 0.00000000000001 of CPU time.
      2. the same.
      5. Aha! Here is one event PC attack! we handle it and check. Do PC has any active events (because PC can have passive events, like poison). Active events - is events set by Player.
      There is no more actios -> Start player routines.Player gives new order (event). For example. another attack on Monster. placed at current turn + 5= 10.
      6. no events
      Then, turn 7 came. Monster made attack and got new actibon - "event". Attack placed to 7+7 = 14.
      10 PC attack.

      That's the trick. we have to handle only items, creatures, traps, spells that have act right now and don't touch others. It saves load of CPU time on "I have to check every creature, does it has something to do?" routines.

  5. I don't know what I just read, but how do you know when some creature has to do something, without accessing it? Kaduria is using energy based movement so each turn something always happens to all creatures, if nothing else they check their energy to see if they can do some task like move. Creatures also become hungry and they can be poisoned etc. so each of them has to check that stuff every turn.

    1. I don’t need it. I mean, don’t need to check them.
      Of course, due to huge map game run through the activity zone around player (about 100x100) and saves all creatures into array. But this array isn’t used to issue orders, except for the first time (wake up creature), but gives easy access to every actor on the scene.
      If we speak about action, states etc. Well,, I have a convention. Creature can do one active action (events) at once (it technically possible to do a lot of stuff, but who needs it?) and unlimited passive events (buffs, debuffs).
      Another thing, I have a lot of turns, mere step uses about 200 turns. It help to spill creatures actions over time.
      For example, creature has active event attack. When it finishes attack and does other action.
      If we speak about poison, we put passive event on this creature with poison effects and delay to remove it.
      It is simple.

  6. Also, do you really need them to become hungry?