Author Topic: Trying to implement InfoFiles  (Read 12938 times)

Shaggy

  • Rogueliker
  • ***
  • Posts: 65
  • Karma: +0/-0
  • (╯°□°)╯︵ ┻━┻ <( !@#$ THIS, I'M OUT. )
    • View Profile
    • Not Quite ADoM
    • Email
Trying to implement InfoFiles
« on: November 07, 2012, 09:39:10 PM »
Hello RogueTemple!

My current step in my project is to try and implement info files (ie text files) that allow for the creation of in-game objects that would then be placed throughout dungeons. For the most part, this is pretty straight forward. Decide a format for the info files, write a sort of line-by-line 'parser' for them, and assign the data.

Here's how my classes are set up right now.



However, the problem comes in when trying to assign data for the Equipment class. The equipment class references to other objects that have weapon or armor properties. So my issue is in trying to assign the data for them.

One way I could do it would be to have the info files formatted in a certain order. IE Items first, then Fighters. That way any references made to fighters equipment could be searched for in data that is already present.

I was just wondering if you guys had any suggestions or could think of any other way to do it?
Check out my blog at http://NotQuiteADoM.blogspot.com/ !

Quendus

  • Rogueliker
  • ***
  • Posts: 447
  • Karma: +0/-0
  • $@ \in \{1,W\} \times \{1,H\}$
    • View Profile
    • Klein Roguelikes
Re: Trying to implement InfoFiles
« Reply #1 on: November 07, 2012, 10:50:04 PM »
You could
Hello RogueTemple!

My current step in my project is to try and implement info files (ie text files) that allow for the creation of in-game objects that would then be placed throughout dungeons. For the most part, this is pretty straight forward. Decide a format for the info files, write a sort of line-by-line 'parser' for them, and assign the data.

Here's how my classes are set up right now.



However, the problem comes in when trying to assign data for the Equipment class. The equipment class references to other objects that have weapon or armor properties. So my issue is in trying to assign the data for them.

One way I could do it would be to have the info files formatted in a certain order. IE Items first, then Fighters. That way any references made to fighters equipment could be searched for in data that is already present.

I was just wondering if you guys had any suggestions or could think of any other way to do it?

Enforcing correct order in definition files would be one solution (though it would preclude any circular references if you want those).
Another solution would be to just read those references and not try to resolve them at the point of reading the file - just store them in the program's data structures, either as a reference by ID number (which won't be memorable and will make writing these dependent files a pain), or by display name (in which case all your display names will have to be unique), or by internal name (preferred solution). Once all the files have been read and inserted at appropriate points in your arrays/dictionaries/maps, you have two choices:
  • Leave them as they are and resolve any references at run time.
  • Immediately process every object to check that its references are to objects that are defined in the info files.
I'd be inclined to do the latter.

Shaggy

  • Rogueliker
  • ***
  • Posts: 65
  • Karma: +0/-0
  • (╯°□°)╯︵ ┻━┻ <( !@#$ THIS, I'M OUT. )
    • View Profile
    • Not Quite ADoM
    • Email
Re: Trying to implement InfoFiles
« Reply #2 on: November 07, 2012, 11:06:24 PM »
Yeah I think I'm going to do a sort of hybrid of those ideas :p My current solution is this;

I will have two seperate info files, one for Items and one for Fighters. The items file will be loaded first and checked for validation, before being added to an Objects list. Then the fighters file will be loaded. When assigning fighters equipment, it will look for items in the Objects list by name. If an item is not found, it will either assign no item to that equipment slot, or assign some sort of 'debugging' item to that slot.

The code will look something like this
Code: [Select]
def ReadItems(file):
    if file is None: return 'No File'
   
    filename = file + '.txt'
   
    fyle = open(filename)
   
    for lyne in fyle :
        # read the line
        # assign the variables
   
        if lyne == ITEM_END_LINE:
           
            #assign current variables to a new item
            #create the item object
            #add the item object to the Objects list
            #reset variables
   
    fyle.close()

def ReadFighters(file):
    if file is None: return 'No File'
   
    filename = file + '.txt'
   
    fyle = open(filename)
   
    for lyne in fyle :
        # read the line
        # assign the variables
       
        if equipment:
            for slots in equipment:
                object_ThisFighter.equipment = GetEquipment(lyne)
   
        if lyne == FIGHTER_END_LINE:
           
            #assign current variables to a new fighter
            #create the fighter object
            #add the fighter object to the Objects list
            #reset variables
   
    fyle.close()
   
def GetEquipment(Name):
    for Object in Objects:
        if Object.name == Name:
            return object
           
    return None #or return Object_ErrorObject
   
def Main():

    ReadItems('InfoFile')
    ReadFighters('InfoFile')
   
   
« Last Edit: November 07, 2012, 11:10:17 PM by Shaggy »
Check out my blog at http://NotQuiteADoM.blogspot.com/ !

Quendus

  • Rogueliker
  • ***
  • Posts: 447
  • Karma: +0/-0
  • $@ \in \{1,W\} \times \{1,H\}$
    • View Profile
    • Klein Roguelikes
Re: Trying to implement InfoFiles
« Reply #3 on: November 08, 2012, 11:42:47 AM »
That sounds like a good approach. My only concern is scalability - what happens if you or a modder make a particularly large number of items and you need to search a list by name for an item?
The solution to that problem is either to sort the list by name and use binary search, or to put the items in a dictionary using names as keys.
Is Object.name always going to be unique? Allowing objects to have non-unique display names can give you a lot of flexibility to implement things like mimics, cursed items, secret doors, traps, etc. Not that any game necessarily has to have those things, but it would be smart to separate the display name from the name you search by, just in case.

Shaggy

  • Rogueliker
  • ***
  • Posts: 65
  • Karma: +0/-0
  • (╯°□°)╯︵ ┻━┻ <( !@#$ THIS, I'M OUT. )
    • View Profile
    • Not Quite ADoM
    • Email
Re: Trying to implement InfoFiles
« Reply #4 on: November 08, 2012, 09:05:18 PM »
That sounds like a good approach. My only concern is scalability - what happens if you or a modder make a particularly large number of items and you need to search a list by name for an item?
The solution to that problem is either to sort the list by name and use binary search, or to put the items in a dictionary using names as keys.
I've never really used the dictionary/key setup before. How much faster would that make it?

Is Object.name always going to be unique? Allowing objects to have non-unique display names can give you a lot of flexibility to implement things like mimics, cursed items, secret doors, traps, etc. Not that any game necessarily has to have those things, but it would be smart to separate the display name from the name you search by, just in case.
[/quote]
That's a good point. I'll have to either give them an ID or a GAME_NAME and DISPLAY_NAME.
Check out my blog at http://NotQuiteADoM.blogspot.com/ !

Quendus

  • Rogueliker
  • ***
  • Posts: 447
  • Karma: +0/-0
  • $@ \in \{1,W\} \times \{1,H\}$
    • View Profile
    • Klein Roguelikes
Re: Trying to implement InfoFiles
« Reply #5 on: November 08, 2012, 10:28:20 PM »
That sounds like a good approach. My only concern is scalability - what happens if you or a modder make a particularly large number of items and you need to search a list by name for an item?
The solution to that problem is either to sort the list by name and use binary search, or to put the items in a dictionary using names as keys.
I've never really used the dictionary/key setup before. How much faster would that make it?
It depends on the number of objects you have. Let's say you have N objects, and N is a number with D digits. For instance, N = 500 and D = 3, or N = 1543 and D = 4.
Then the time taken to look up an object in a dictionary would be comparable to D/N times the amount of time to look up an object in a list.
That's a pretty big speedup, though of course if you're just going to have 50 or so objects it might not be very noticeable. The code change wouldn't be very big - if your container (list or dictionay) is called AllObjects and your new object is called obj, then you'd be going from
Code: [Select]
AllObjects.append(obj)
to
Code: [Select]
AllObjects[obj.GAME_NAME] = obj
And you'd be able to stop using for loops to find objects, because the lookup code would be
Code: [Select]
obj = AllObjects[REQUESTED_NAME] #IndexError if REQUESTED_NAME isn't in AllObjects

Quendus

  • Rogueliker
  • ***
  • Posts: 447
  • Karma: +0/-0
  • $@ \in \{1,W\} \times \{1,H\}$
    • View Profile
    • Klein Roguelikes
Re: Trying to implement InfoFiles
« Reply #6 on: November 08, 2012, 10:33:20 PM »
Pardon me, I as wrong - according to http://wiki.python.org/moin/TimeComplexity#dict, dictionary access takes on average constant time, which is even better than what I said in the previous post - comparable to 1/N times the amount of time to look up an object by name in a list.

Shaggy

  • Rogueliker
  • ***
  • Posts: 65
  • Karma: +0/-0
  • (╯°□°)╯︵ ┻━┻ <( !@#$ THIS, I'M OUT. )
    • View Profile
    • Not Quite ADoM
    • Email
Re: Trying to implement InfoFiles
« Reply #7 on: November 10, 2012, 01:02:44 AM »
That's pretty awesome. The only problem I'm having is figuring out how to iterate through the whole list. The old code was this; which isn't working now.

Code: [Select]
#now check for any blocking objects
    for object in objects:
        if object.blocks and object.x == x and object.y == y:
            return True
Check out my blog at http://NotQuiteADoM.blogspot.com/ !

Quendus

  • Rogueliker
  • ***
  • Posts: 447
  • Karma: +0/-0
  • $@ \in \{1,W\} \times \{1,H\}$
    • View Profile
    • Klein Roguelikes
Re: Trying to implement InfoFiles
« Reply #8 on: November 10, 2012, 01:37:38 AM »
If you iterate over a dict in python, it's the same as iterating over the list of keys in the dictionary. There are a few alternatives for accessing the actual values in the dictionary:

Code: [Select]
# get object by looking up the name in the dictionary
    for obj_name in objects:
        object = objects[obj_name]
        if object.blocks and object.x == x and object.y == y:
            return True
Code: [Select]
# iterate over (name, object) pairs
    for obj_name, object in objects.items():
        if object.blocks and object.x == x and object.y == y:
            return True
Code: [Select]
# ignore names and iterate over objects
    for object in objects.values():
        if object.blocks and object.x == x and object.y == y:
            return True

Though again, if this does what I think this does - takes a map location and searches every object in the game to find if there's an object blocking that tile, then I would suggest another solution. Iterating over every object in the game can be very expensive in all but the most simple games, so if you have a lot of objects it might be a good idea to have a mechanism of keeping track of which objects are contained in each location.

Shaggy

  • Rogueliker
  • ***
  • Posts: 65
  • Karma: +0/-0
  • (╯°□°)╯︵ ┻━┻ <( !@#$ THIS, I'M OUT. )
    • View Profile
    • Not Quite ADoM
    • Email
Re: Trying to implement InfoFiles
« Reply #9 on: November 10, 2012, 09:43:32 AM »
hmm. For some reason, python is thinking it's a list, not a dictionary. (Or at least thats what I get from the error " 'list' object has no attribute 'blocks'")

it's initialized with;
Code: [Select]
objects = {}
and the first value is assigned;
Code: [Select]
objects['player'] = [player]
Everything else is assigned just how you showed me. Sorry for bein such a newb :p Im still pretty new to Python, and Ive never used a dictionary before.


Though again, if this does what I think this does - takes a map location and searches every object in the game to find if there's an object blocking that tile, then I would suggest another solution. Iterating over every object in the game can be very expensive in all but the most simple games, so if you have a lot of objects it might be a good idea to have a mechanism of keeping track of which objects are contained in each location.

This doesnt iterate through every object in the game, just the objects on the current dungeon level. Not nearly as many.
Check out my blog at http://NotQuiteADoM.blogspot.com/ !

Quendus

  • Rogueliker
  • ***
  • Posts: 447
  • Karma: +0/-0
  • $@ \in \{1,W\} \times \{1,H\}$
    • View Profile
    • Klein Roguelikes
Re: Trying to implement InfoFiles
« Reply #10 on: November 10, 2012, 11:25:01 AM »
hmm. For some reason, python is thinking it's a list, not a dictionary. (Or at least thats what I get from the error " 'list' object has no attribute 'blocks'")

it's initialized with;
Code: [Select]
objects = {}
That's good.
Quote
and the first value is assigned;
Code: [Select]
objects['player'] = [player]
Code: [Select]
[player] is a list containing the object named player, and a list won't have most of the member functions you've defined for fighters and items. try
Code: [Select]
objects['player'] = player
Quote
This doesnt iterate through every object in the game, just the objects on the current dungeon level. Not nearly as many.
Even on a small level, putting together all the fighters, items, and wall tiles (I take it they can block?) in a single data structure is probably going to make a lot of iteration for you. And if you want A* to pathfind from one corner to the opposite corner of a small level, you're going to have to check if a lot of tiles are blocked, so you'll want that check to be a quick operation.

A common solution to this is to let each tile record the ID of the fighter present, or let each tile keep a list of IDs of objects that are present. This means you have to be more careful when moving objects around (updating the object's location, removing the old location's reference to the object, and telling the new location that the object is now there), but it also means that checking the contents of a tile is a very very quick operation.

Ultimately, if your levels are small and contain few objects, then you can probably get away with the current method - but if you expect features like breeding monsters, cloning items, rooms full of treasure, or bosses with lots of minions, then it might be worth considering this alternative method.

Shaggy

  • Rogueliker
  • ***
  • Posts: 65
  • Karma: +0/-0
  • (╯°□°)╯︵ ┻━┻ <( !@#$ THIS, I'M OUT. )
    • View Profile
    • Not Quite ADoM
    • Email
Re: Trying to implement InfoFiles
« Reply #11 on: November 10, 2012, 12:14:39 PM »
Ahh, I gotcha. Well, it's getting closer to working. It's still returning a few strange errors, such as 'object has no value 'x'' in the following code. But it is recognizing it as a dictionary now rather than a list.

I need to check my rendering code. For some reason, it's drawing the map and items but not the creatures.
Edit :: Nevermind, it renders fine.

One other question I had. The tutorial features a function called 'send_to_back', which set the objects index in the old list to 0. This meant that it would be drawn first, so anything else on that tile would be drawn on top of it. (ie a monster is draw on top of an item). Is there any way to set the position of a specific key in the dictionary?


This is the code producing the 'object has no value x' error. But it seems to register the other values. (char/color for rendering, x,y positions, etc.)

Code: [Select]
...
Edit :: I tracked it down. It was caused by me doing things along the lines of objects[object.real_name] = None
How do I properly remove a key from a dictionary? I tried objects.remove(object.real_name) but it returned a NoMethod error

Ultimately, if your levels are small and contain few objects, then you can probably get away with the current method - but if you expect features like breeding monsters, cloning items, rooms full of treasure, or bosses with lots of minions, then it might be worth considering this alternative method.

Good to know. I think it should be ok for now, but if it ever becomes a problem I will have a solution in mind!

Felt like this would be a good spot to selflessly advertise for my development blog, and newly-opened github repository. If you'd like, you can take a look at how everything is structured. I basically followed the tutorial, and then just started branching off and tweaking/changing things. It's nothing exciting or innovating yet, but I'm still excited.

http://notquiteadom.blogspot.com/
https://github.com/MisterMoxxie/ItsStillInBeta
« Last Edit: November 10, 2012, 11:42:35 PM by Shaggy »
Check out my blog at http://NotQuiteADoM.blogspot.com/ !

requerent

  • Rogueliker
  • ***
  • Posts: 355
  • Karma: +0/-0
    • View Profile
Re: Trying to implement InfoFiles
« Reply #12 on: November 11, 2012, 02:38:04 AM »
Use the 'del' keyword to remove an entry.

Code: [Select]
del dict[key]