Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » A function from a file... without a big switch... Just look here!

Credits go to Ceniza, Kanzure, Kitty Cat, ROSTheFuture, and spellcaster for helping out!
This thread is locked; no one can reply to it. rss feed Print
 1   2 
A function from a file... without a big switch... Just look here!
Synapse Jumps
Member #3,073
December 2002

Yay for the music note 8-)... Anyways...
So I have a list of spells in a file. Like say:

//name, MP Req
Kill Monsters, 999
Kill People, 999
Yo Mamma, 999
You`re A Lil` Girl, 0

Right, but I want these to call their own functions to calculate damage/look cool/whatever. So... how do I do that? Is there a way without a big ass switch (or in this case a huge string of (else)ifs for the name)? Can I like say:

//name, MP Req, function()
Kill Monsters, 999, KillMonsters
Kill People, 999, KillPeople
Yo Mamma, 999, YoMamma
You`re A Lil` Girl, 0, LilGirl

Except that's all hard to do and possibley impossible :(. Any ideas/comments/random stuff welcome!

Kanzure
Member #3,669
July 2003
avatar

Hmm..Try making a list of Spell Names, and then a function type to call..that may be helpful...

ROSTheFuture
Member #2,775
September 2002
avatar

It seems to me you might be able to do some sort of struct with function pointers... I would normally work that idea into workable code and post the code, but I don't really feel like working it out right now because i'm lazy ;) But anyway, thats all I really do, just think of some sort of seemingly good option and work it out. Usually they work, but in this case I'm not sure. You'll just have to experiment with that one...

--------
RichOS is the operating system of the future - if for some reason everyone starts hating Window$ and Linux.

Synapse Jumps
Member #3,073
December 2002

Kanzure said:

Hmm..Try making a list of Spell Names, and then a function type to call..that may be helpful...

I already asked you, WTF?
ROS: Hmm, but wouldn't that sill come down to a big old else/if dealy?

Kitty Cat
Member #2,815
October 2002
avatar

Something like this, I think he suggested:

1struct {
2 const char *string;
3 void (*func_ptr)(void);
4} func_list[] = {
5 { "Function 1", func_ptr1 },
6 { "Function 2", func_ptr2 },
7 //ect...
8 {NULL,NULL}
9};
10 
11// in function:
12{
13 // Search through the list
14 for(i = 0;func_list<i>.string;++i)
15 {
16 // If the names match, run the function
17 if(strcmp(string_to_check, func_list<i>.string) == 0)
18 func_list<i>.func_ptr();
19 }
20}

Yes, it's basically a big if/else statement, but it's a very compact big if/else statement..

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

Ceniza
Member #2,027
March 2002
avatar

I know some C puritans can get a bit irritated, but there I go:

1#include <map>
2#include <string>
3#include <iostream>
4 
5typedef std::map<std::string, void (*)()> funct_map;
6funct_map fm;
7 
8void KillMonsters() { std::cout << "KillMonsters\n"; }
9void KillPeople() { std::cout << "KillPeople\n"; }
10void YoMamma() { std::cout << "YoMamma\n"; }
11void LilGirl() { std::cout << "LilGirl\n"; }
12 
13void fill_fm()
14{
15 fm["KillMonsters"] = KillMonsters;
16 fm["KillPeople"] = KillPeople;
17 fm["YoMamma"] = YoMamma;
18 fm["LilGirl"] = LilGirl;
19}
20 
21void execute(std::string function_name)
22{
23 //if the function doesn't exist it'll crash here
24 //using exceptions would be a good idea ^_^
25 fm[function_name]();
26}
27 
28int main()
29{
30 fill_fm();
31 std::string name;
32 std::cout << "Enter function name: ";
33 std::cin >> name;
34 execute(name);
35}

That could be a C++ solution (you could also try with the hashed map (that isn't part of the standard)).

If you'ren't using C++ you could try to implement the concept of the map and use it in a similar way.

spellcaster
Member #1,493
September 2001
avatar

Use reflection to call the correct method. That should work well if you know what class will hold your methods. And if you use Java, of course.

But generally speaking, it's not that good if each attack uses it's own way to calc damage anyway.

Just specify the to-hit-chance, the damage, the type of attack / type of damage, any secondary effects and possible state changes (stunned 50%, confused 10%, etc.) for example.

That way you can just read in the data and use it. It makes it also more easy tweak these values later on.

--
There are no stupid questions, but there are a lot of inquisitive idiots.

Synapse Jumps
Member #3,073
December 2002

KittyCat: That's a very good idea, just using a for loop.

Ceniza: I've never used any type of map before, I never knew what it was for. I guess now I know ::). I'm not a C puritan, but I don't like std::strings, so if anything I'll be using char arrays there :)

Spelly: I have no idea what reflection is... Sorry, I'm not that smart :'(. I didn't understand the first part of your post :'(, but as for the part about the fact that each attack uses it's own calc damage thing. Well, see I want them to take into account the characters magic, strength, whatever as well as the targets. Maybe I want different amounts for different spells. Also, I want different special effects for each one. Maybe for the spell "KillPeople" I want some giant squid to come and slap the people around with it's tentacles, but for the spell "LilGirl" I want a little girl to come out and b*tch slap the enemy. See?

ROSTheFuture
Member #2,775
September 2002
avatar

KittyCat was thinking exactly like what I was thinking, I was just too lazy at the time to think it out thourghougly like he did.

I personally like the map idea, myself. That would have never occurred to me, because I had no idea you could do that.... very interseting.

--------
RichOS is the operating system of the future - if for some reason everyone starts hating Window$ and Linux.

Ceniza
Member #2,027
March 2002
avatar

Synapse Jumps said:

I'm not a C puritan, but I don't like std::strings, so if anything I'll be using char arrays there

Well, you're free for don't liking std::string but I still recommend you using it in the map and then use C-strings everywhere else (for your personal pleasure ;)), otherwise you'll get a lot of funny surprises when using map.

Remember when you use std::string you have implicit conversion at your disposal, so, exactly in the same example code you could change main to:

int main()
{
  fill_fm();
  char name[128];
  std::cout << "Enter function name: ";
  std::cin >> name;
  execute(name);
}

and that way you feel better and map will work as you need it to work.

If you're wondering why <b>char isn't a good choice for map, just remember the operator == for a C-string will compare the memory address and not the content.

Synapse Jumps
Member #3,073
December 2002

Aha! Great. It works beautifully! Thank you. I'm still sad that I have to use std::strings, but what'cha gonna do (except over-ride the global == operator, which will lead to my next question). And since we're on the subject, here's why I hate std::strings: sizeof(std::string) == 28, sizeof(char *) == 4 :). Anyways, so I tried to over-ride the global ==operator and I did it like this (for char *s only)

bool operator==(const char *left, const char *right){
  if(!stricmp(left, right))
    return true;
  return false;
}

And it says this:

main.cpp(6): error C2803: 'operator ==' must have at least one formal parameter of class type

Whassat mean? If this is impossible, I'll settle for using std::strings, but this just seems easier :)

EDIT: Also, what do you think, should I load the list from the file each time in battle, this way I don't have to keep track of the spells the first way, but the second way is quicker.

spellcaster
Member #1,493
September 2001
avatar

Reflection is pretty easy.
Mainly it allows you to take a look at all methods, constructors, fields etc. Quite handy.

void call(Object objectToCall, String theFunction) {
    try {
        Method m = objectToCall.getClass().getMethod(theFunction, null);
        Object result = m.invoke(null);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

regarding your problem... I know that this is not what you want to do, but still...
if you have magic spells which call other creatures, you could have something like:

SummonLittleGirl, Single_Target, 1 round, Lvl*2, LittleGirl

Which would mean that the "summon little girl" spell summons a little girl of twice the level of the caster.

of course you'll need to specify the little girl as well:

[LittleGirl]
type=phsyical
DAM=10 + (lvl/2)
Atk=5+lvl
gfx=
sound-=

That way you'd still be pretty flexible. And if you want to the girl to fight for two rounds, all you need is to change is one number.
Also, summoning a dragon attacking several targets is as easy:

SummonDragon, Group, 1 round, lvl * 1, RedDragon


[RedDragon]
type=fire
Dam=lvl d12
Atk=20+lvl/2
gfx=
sound=

Of course, if you just need a few spells, hardcoding them is quicker.

But... in that case you won't need any external files in the first place. You could just hardcode the spell description as well...

--
There are no stupid questions, but there are a lot of inquisitive idiots.

Ceniza
Member #2,027
March 2002
avatar

You overload operators for user defined types and <b>const char looks like a built-in type for me :)

So you dislike std::string 'cause it's 24 bytes bigger? How unfair :-/

Those 24 extra bytes are worth it IMO and they won't hurt that much.

Think about common implementations that need temp char []s for storing stuff, most of those implementations like to use 512 bytes + 4 of the pointer = 516 bytes, and, in most cases, they use less than 40 of those 512 bytes... so... is std::string still that bad?

What if they need 512 or more bytes? :)

Also remember that asking for the length of a C-string (a very common "task") has linear complexity while asking for the length of a std::string always takes constant time.

It'sn't that bad after all, is it? ;)

Synapse Jumps
Member #3,073
December 2002

Woh, why didn't I reply to this til now? Oh well...
Spelly: That reflection stuff makes NO sense to me. I mean, I could see passing an object and stuff, but .getClass()? I've never EVER seen that... anyways... I proly will use some summoning stuff like that. And I don't really want to hard-code the spells into the game, because I want this game to get very large and flexible :). Eventually, I want to make a spot where you can make your own spell and item. That would be pimp 8-)

Ceniza: ... ... Okay, I can see using std::string where I REALLY need to, and I can only find two places where I really need it. 1) for this big ol' buffer I have (except, how can I pass it like a c-string? If I pass .c_str to a function that writes to a c-string will it write on it?) 2) With this whole map dealy.

EDIT: I still wanna know why my overloaded operator== isn't right? Anyone know, or is it just not possible? I've settled for strings, but still...

Ceniza
Member #2,027
March 2002
avatar

Synapse Jumps said:

If I pass .c_str to a function that writes to a c-string will it write on it?

Well, c_str() doesn't return the internal data of std::string, it's just a copy, and even if it returned the internal data stored in std::string, the return type is <b>const char , so you can't modify it.

Synapse Jumps said:

I still wanna know why my overloaded operator== isn't right? Anyone know, or is it just not possible?

As I said, <b>const char is a built-in type and you can only overload operators for the types you create.

It wouldn't be smart to allow the user change the meaning of those operators for built-in types, like making:

int a = 2, b = 7, c = 9;
c = c + a * b; // <--

get a totally different meaning.

ROSTheFuture
Member #2,775
September 2002
avatar

Spellcaster: isn't that Java? It would be nice to be able to call a function by its name like that in C or C++...

--------
RichOS is the operating system of the future - if for some reason everyone starts hating Window$ and Linux.

Synapse Jumps
Member #3,073
December 2002

Ceniza said:

Well, c_str() doesn't return the internal data of std::string, it's just a copy, and even if it returned the internal data stored in std::string, the return type is const char *, so you can't modify it.

Well there's another down point to std::strings... ::)
And the rest of your post makes sense.

ROS: That makes sense... I was gonna say I didn't recignize any of that!

23yrold3yrold
Member #1,134
March 2001
avatar

Quote:

Well there's another down point to std::strings...::)

Especially if you aren't familiar with c_str()'s sister functions, data() and copy() ::) ...

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

Synapse Jumps
Member #3,073
December 2002

23 said:

Especially if you aren't familiar with c_str()'s sister functions, data() and copy()

ACTUALLY I'm not. I assume data rerutns the data in char * format? And copy...? No one said anything about this...

23yrold3yrold
Member #1,134
March 2001
avatar

Ceniza is right; the data returned by c_str() and data() is constant (would be rather dangerous otherwise) so copy() can copy a string's contents into your own char array so you can do whatever you want with it.

RMFA ;)

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

Synapse Jumps
Member #3,073
December 2002

Well that's no good, I can't send the thing to a function! The reason I wanted it was instead of having a huge ass buffer. So I can't even do this? See strings ARE stupid ::)

23yrold3yrold
Member #1,134
March 2001
avatar

Yes, much smarter to allow direct access to private data so you can play merry hell with it ::) Of course you can send it to a function; what's the problem?

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

Synapse Jumps
Member #3,073
December 2002

No, you can't send it to a function, properly. You can't do this:

fgets(some_std_string, 99999, some_file);

Now can yah? You can't do it with anything! None of std::strings members!

EDIT: As to not get a post cap. F**K IOSTREAMS! DON'T EVEN GET ME STARTED ON THOSE DUMB A*S THINGS!

23yrold3yrold
Member #1,134
March 2001
avatar

Quit mixing C and C++. Works fine with iostreams ::)

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

spellcaster
Member #1,493
September 2001
avatar

Quote:

Spellcaster: isn't that Java? It would be nice to be able to call a function by its name like that in C or C++...

Of course it is Java. I even said so in my first post mentioning reflection ;)

Quote:

nd I don't really want to hard-code the spells into the game, because I want this game to get very large and flexible . Eventually, I want to make a spot where you can make your own spell and item. That would be pimp

Um... if you want to do that, you should just define your spells in an external file, not hardcode a function call.

Take a look at the spell descriptions of freely available RPG systems, say d20 or GURPS light or Fudge or whatever.

What you'll see is that these description classify a spell by its range, the number of targets, how the spell is targeted, what "schools of magic" the spell belongs to, how the traget can defend itself and finally also the damage that is made (if any) and if the state of the target can be affected.

For a computer game, you will also need to add some description on how the spell effect looks and sounds.
That means you might have a list of graphic styles for missles, beams, auras cunjuration of monsters, etc.

Oh, reading through some of the pen&paper RPGs will also give you an idea how you can create a system in which you can explain both magic and normall attacks using just a few stats.

--
There are no stupid questions, but there are a lot of inquisitive idiots.

 1   2 


Go to: