Can a function change Strings in the game?

Started by Gepard, Sun 25/12/2016 18:15:31

Previous topic - Next topic

Gepard

Hello,

I have various dungeons that player can explore and find loot in them. For example, he ventures deep into the dungeon, opens a door and finds a treasure chest. When he clicks the treasure chest an inventory window shows up with a single item, that was added to the inventory when he opened the door or clicked on the chest. I have this code for this:

Code: ags
if (eventPlace1.IndexOf("gold")==-1) {
place1.AddInventory(iGold);
eventPlace1 = eventPlace1.Append ("gold");
}


This is to ensure the item will only be added once. And it is working, but the problem is, my script is getting pretty heavy. I was thinking if I could use a function that would fit these lines into one. I don't know if you can make a function that would refer to a String already in the game like you do with characters or inventory items. I tried but the game said "Invalid use of pointer".

Thanks for any help.
Drink up me 'arties! Yo ho!

Crimson Wizard

Quote from: Gepard on Sun 25/12/2016 18:15:31I don't know if you can make a function that would refer to a String already in the game like you do with characters or inventory items. I tried but the game said "Invalid use of pointer".

Yes it is possible:
Code: ags

function DoSomethingWithString(String myString)
{
   Display(myString);
}

String ThisFunctionReturnsString()
{
   return "some string";
}

Gepard

I'm sorry, I don't understand. I have a String defined in Global variables. Now I want it to change when player click on a GUI button. But when he clicks the button, it can always be different String that changes, depending on "where" the player is right now. How do I do this? I mean, what to put under button click code and what in the function?
Drink up me 'arties! Yo ho!

Khris

#3
Using strings like that to store game states is a *really* (REALLY) bad idea. But this thread isn't about that, so here's the answer you're looking for (I guess):

Header:
Code: ags
import String eventPlace[10];
import void PrepareChest(int which, String item);


Main Script
Code: ags
String eventPlace[10];

void PrepareChest(int which, InventoryItem *item) {
  if (eventPlace[which].IndexOf(item.Name) > -1) return; // do nothing
  eventPlace[which] = eventPlace[which].Append(item.Name);
  character[which + 10].AddInventory(item);
}


The code assumes that character #10 is used in conjunction with eventPlace[0], character #11 in conjunction with eventPlace[1], and so on, up until character #19 and eventPlace[9]. That's a total of ten chests.

You'd use it like this:
Code: ags
  PrepareChest(1, iGold);
The text is pulled from the inventory name.


A proper system involves
a) a struct for a chest, and setting up as many instances as you need using an array
b) assigning each chest index to a room
c) preparing a single chest inventory based on which chest is in the room
d) storing chest status in the instance data

Example:
Code: ags
// header
struct Chest {
  int inv[50];
  bool locked;
};  // edit: added semi-colon

// main
Chest chest[50];
  // in game_start
  chest[0].inv[iGold.ID] = 1;
  chest[0].inv[iSword.ID] = 1;

Edit: added semi-colon to struct def

Snarky

Quote from: Khris on Sun 25/12/2016 21:38:28
Using strings like that to store game states is a *really* (REALLY) bad idea. But this thread isn't about that

Maybe it should be. Gepard was using the same approach in another thread, and it's really a very poor way to solve these tasks. (Just wait until you have both "ham" and "hammer" as items in the game, for example...)

To keep track of inventory items, use an array of inventory items (or simply a Character inventory), or perhaps a set of boolean flags, not some weird string concatenation of all their names. Try to avoid relying on custom text properties for game logic (use structs or arrays in the code instead), but if you must, convert it from a string to some more appropriate data type immediately upon reading it.

Crimson Wizard

#5
To be honest, I did not really think about what Gepard was using the string for, but now when I give this more attention, maybe it is better to simply use Game.DoOnceOnly function? Because it does exactly what Gepard is trying to do with the string: remembers that some action was already done.

Gepard

#6
Thank you, everyone, for your ideas.

In my game I have many places, that player can explore. While exploring, he can encounter three kinds of puzzles, enemies or items. For each place I have a String assigned and this String changes everytime a player solves a puzzle, defeats an enemy or finds an item. So for example if he enters a place where there is an enemy and the String does not contain the word "enemy1", a fight will start. If he defeats the enemy, than word "enemy1" will be added to that place's String (the same can be done with loot, I just append "chest1" and puzzles, I just add "relicpuzzle"). Not every place has the same type of puzzles, numbers of enemies, items etc. Also it is very easy to reset the place from the start and make all the puzzles, items and enemies alive again, I just set the String to "". I will definitely use the Game.DoOnceOnly feature, and will also look at structs as I haven't use them so far.

Edit: Also, I only have one room in the game (not counting the main menu).
Edit2: I searched the forums and the internet, but I couldn't find any tutorial on structs in AGS. I tried to declare them in my game, but with no luck. Can anyone tell me if there is a complex tutorial for beginners on how to use them. How and where to declare them, how to get and set their values? Thank you.
Drink up me 'arties! Yo ho!

dayowlron

First off I want to say I would probably use arrays for controlling what you are asking for. But I basically wanted to reply because if you have an "enemy10" then you do the IndexOf for "enemy1" it will return true even though enemy1 was not in there. To fix that you can add a comma after the words and look for that comma in your querys.
Code: ags

if (eventPlace1.IndexOf("enemy1,")==-1) {
**code for encountering an enemy
eventPlace1 = eventPlace1.Append ("enemy1,");
}
Pro is the opposite of Con                       Kids of today are so much different
This fact can clearly be seen,                  Don't you know?
If progress means to move forward         Just ask them where they are from
Then what does congress mean?             And they tell you where you can go.  --Nipsey Russell

Khris

Did you try the example code I used?
Put line 8 at the top of your script, the other lines in game_start. It should compile fine.

Gepard

Thank you all for help. I'm trying to implement as much as possible to the system I already have. You guys are a great help! Much appreciated!
Drink up me 'arties! Yo ho!

Snarky

Quote from: Gepard on Mon 26/12/2016 09:11:59
Edit2: I searched the forums and the internet, but I couldn't find any tutorial on structs in AGS. I tried to declare them in my game, but with no luck. Can anyone tell me if there is a complex tutorial for beginners on how to use them. How and where to declare them, how to get and set their values? Thank you.

There's a quick introduction to structs in the built-in AGS Manual, under "Scripting | Script language keywords", though it doesn't describe how to add functions to structs. Structs are usually declared in script headers, you can also refer to the "Scripting | Multiple Scripts" section.

I am sure there is a much better way to solve your task, but first there's one part I don't understand about your current solution: you say that "Not every place has the same type of puzzles, numbers of enemies, items etc.", but I don't see where you define that â€" the string only keeps track of what has been "used up" already. I'm also not clear on what defines the order in which things happen: if a place has two enemies, enemy1 and enemy2, what makes it so that enemy1 is the one you encounter the first time and enemy2 the second time? Or is that random somehow?

Gepard

Well a single place consist of multiple "rooms". These are not actual rooms, just levels, that are set using integer whenever player enters a room. So I just decide which level is the Enemy1 going to be in and when player fights it and win, the entString for that place will have "enemy1" appended to it. And I define the enemy when the place is opened. I use function for that.
Drink up me 'arties! Yo ho!

Snarky

So somewhere you have a big function that says something like this?

Code: ags
// Player enters "room"
function enterRoom(int roomLevel)
{
  if(roomlevel == 1)
  {
    if(room1String.IndexOf("enemy1") == -1)
    {
      doFight("enemy1");
      room1String = room1String.Append("enemy1");
    }
    else if(room1String.IndexOf("enemy2) == -1)
    {
      doFight("enemy2");
      room1String = room1String.Append("enemy2");
    }
    // etc.
  }
  else if(roomlevel == 2)
  {
    // Similar to roomlevel 1
  }
  // etc.
}

SMF spam blocked by CleanTalk