turn based battle system help

Started by Anshinin, Tue 10/03/2015 01:47:53

Previous topic - Next topic

Anshinin

Okay so looking through the forums I've found a lot of posts on the basics of putting these systems together, however I have a few more questions in making the battle system more dynamic.

I have enemy HP set to a specific GlobalVariable and each enemy who has unique health has their own unique variables. When I use attacks they have to subtract the damage dealt minus that particular enemies HP variable.
What I want to know is is it possible to set some one to detect what enemy is in the battle and set the right GlobalVariable accordingly so you don't have to write every individual enemy down and how it gets affected by that item.

I want to set up some sort of base enemy ai system that activates whenever the right GlobalVariable for them is drawn. Like their attack power multiplied by the power of the attack makes them do their attack, and then runs a text display for what attack they used. If they go below a certain health level they'll add new attacks to their possible usage.

I also wanted the ability to during the main gameplay earn some sort of "spell" that lets you summon someone to help you in battle. So I want to know how to add another character to select from for attacking in fights.

My main goal is really just to minimize the amount of code needed to make battles more efficiently, so I just gotta set up rooms with NPCs and the battle system will work universally, alongside some specified attack names and what not. Any way of making this a more fleshed out system that works will would be rly appreciated.

Vincent

Dumb answer that solves a quarter of your message ;


- struct
Declares a custom struct type in your script.
Structs allow you to group together related variables in order to make your script more structured and readable. For example, suppose that wanted to store some information on weapons that the player could carry.
Code: ags

struct Weapon {
  int damage;
  int price;
  String name;
}; 


Now, you can declare a struct in one go, like so:
Code: ags

Weapon sword;
sword.damage = 10;
sword.price = 50;
sword.name = "Fine sword";

Much neater and better organised. You can also combine structs with arrays




- Arrays
Arrays allow you to easily create several variables of the same type.
Code: ags

int health[50]; 


This example declares 50 int variables, all called health.
You access each seperate variable via its index (the number in the brackets). Indexes start from 0, so in this case the health array can be accessed by indexes 0 to 49. If you attempt to access an invalid index, your game will exit with an error.

Here's an example of using the array:

Code: ags

health[3] = 50;
health[4] = 100;
health[player.ID] = 10; 


this sets Health 3 to 50, Health 4 to 100, and the Health index that corresponds to the player character's ID number to 10.




// ============================================================================ //

Hopefully this will help you

Anshinin

Those arrays seem very helpful and I understand that, however I'd like a little more clarifications on the use of structs.

Where would you put this and how would it be able to execute as a usable weapon item for example, or if I were to use them to make my enemy bank and have the different characteristics of the enemies? I'm just not entirely sure how I'd use it, though I understand what it is doing.

Ghost

It's common practise to declare a struct in a script header. You can use the GlobalScript's header, but to avoid clutter I suggest you create a new script that deals with all your weapon-related stuff.

As Vincent said structs are great in tandem with arrays. To elaborate a bit:

A struct is a template. It holds no data and can not be used "as is". An array is a collection of those templates filled with data. With a weapon struct you can create an array of weapons and you would "use" that data by referring to a position within the array that holds the data for a certain weapon.

You will have to create the array (usually at the top of a script file- NOT the header). Then you will have to fill the array with data:

Code: ags

weapon[0].name = "Somewhat pointy stick";
weapon[0].damage = 12;


Once you have data in your array you can access it from your script by referencing the weapon at position X:

damage_dealt_to_player = weapon[X],damage;

Now there are several ways to work with this, but I think you get the point- in order to have someone "use" a weapon you would most likely give him a variable that is a position in your "weapon list".

Hope this gets you started.

Anshinin

Okay so this has so far gotten me where I want to be with making my weapons and attacks, but the question of attacking the enemies is still something I need help on.

When I activate a spell or weapon, how do I let it know what enemy to attack without having to declare it for each individual enemy? Like I don't want to have to write out what each spell will affect each individual enemy with, and I don't even think that'd work.

So how do I get it to detect there is an enemy to attack when the weapon or spell is selected?

Snarky

Well, what is it based on? Do you select the targets? Is it some kind of area effect? Is it whoever's closest? Some kind of relationship between the type of spell/weapon and the type of enemy?

Basically, you'll want to keep track of all the relevant information for each enemy unit, and then when it's time to attack, if the player doesn't designate a target, you have to run some sort of calculation on that data to decide which enemies are targeted.

Coding a fully working battle system in AGS is quite complex (I know, I tried and gave up once), and if you're new to structs and arrays I'd expect it to be pretty overwhelming. You can limit it and hack it in various ways to make it a lot easier, so it really depends on what exactly you have in mind.

Have you looked at the code for OceanSpirit Dennis: Scourge of the Underworld (DX), or Ray of Hope? It has a very simple battle system (though it's one-on-one, so no need to pick your enemies). Almost all the OSD games are open-source, and you can see a list of them here; it can be a very helpful resource to reference (though not always an example of the best way to do something).

Anshinin

I probably wasn't very clear with my last post, excuse me as I was very tired when I wrote that :tongue:

Anyway, for the most part my battles are going to be 1v1 and I wanted the game to know what enemy to attack within the script. I think the solution I've come up with (though untested) is to make a variable for the enemies health in the script when you run an attack, and then in each room declare what that variables respective GlobalVariable is.

So x - 5 would be the enemy taking 5 damage
and in the battle room I would say x = whatever globalvariable the enemies health is being declared as.

I'll look at the source code for those games though since that seems like it'll be useful.

Snarky

Again, the best way to go about it depends very much on the specifics of what you're trying to do. To provide useful advice, we'd pretty much need a detailed breakdown of exactly how you want it to work.

For example, are the enemies you will be fighting "generic" opponents that you might have to fight copies of multiple times (like "an orc"), or are they unique "bosses" that you defeat once and then never see again? That makes a big difference to how you code it. But I'm pretty sure that the right answer is NEVER a globalvar for the enemy's hitpoints.

Anyway, here's some hints, with a quick outline of how I'd write a simple version:

Code: AGS
// In the header
#define MAX_ENEMIES 12 // How many different enemies you have in the game

/// All the stats and data on an enemy, plus methods you can perform on an enemy
struct Enemy
{
  String name;

  // Stats, whichever you need for your system
  int strength;
  int defense;
  int magicDefense;
  int health;

  // This is for displaying the enemy on screen
  Character* body;
  int id;

  // Methods you can call on an enemy
  import int Attack();
  import bool IsAlive();

  /// Finds the id of the enemy with this name 
  import static int Find(String name);
};

// TODO: Also add structs for weapons, spells, etc. (as Vincent suggests)

// These are methods defined in the script that you want to make available to be called in other files (room script, etc.)
import void AttackAnimation(this Character*)
import void InitEnemies();

// Also, you want all scripts to be able to see this array
import Enemy enemy[MAX_ENEMIES];


Code: AGS
// In the script
Enemy enemy[MAX_ENEMIES];
export Enemy enemy;

// Set all the stats for your enemies (another way would be to read this info from a file)
void InitEnemies()
{
  int i=0;
  enemy[i].name = "Dracula";
  enemy[i].strength = 10;
  enemy[i].health = 50;
  enemy[i].defense = 20;
  enemy[i].magicDefense = 50;
  enemy[i].body = cDracula;
  enemy[i].id = i;
  i++;

  enemy[i].name = "Koopa";
  enemy[i].strength = 30;
  enemy[i].health = 100;
  enemy[i].defense = 60;
  enemy[i].magicDefense = 10;
  enemy[i].body = cKoopa;
  enemy[i].id = i;
  i++;

  // ... and so on
}

// This runs automatically when the game starts
function game_start()
{
  InitEnemies();
}

bool Enemy::IsAlive()
{
  return (this.health > 0);
}

/// Call this to make the enemy attack you (returns amount of damage the enemy has done)
int Enemy::Attack()
{
  // Very simple example, just does a random amount from 0 to enemy.strength
  int damage = Random(this.strength);
  return damage;
}

static int Enemy::Find(String name)
{
  int i=0;
  while(i<MAX_ENEMIES)
  {
    if(enemy[i].name = name)
      return i;
    i++;
  }
  return -1;
}

// Show the animation for this character's attack
void AttackAnimation(this Character*)
{
  // This is just an example of how you might do a simple animation
  this.LockView(this.IdleView); // If you've put the attack animation as the character's idle view
  this.Animate(0, 2, eOnce, eBlock, eForwards);
  this.UnlockView();
}


... you could add much more stuff, but that's a start.

Then I would write a couple of functions to set up and run a battle. Something like:

Code: AGS
// Header
// Setup the battle by choosing which enemies to fight
import void InitBattle(int enemyId1, int enemyId2 = -1, int enemyId3 = -1, int enemyId4 = -1);
// Let the enemies attack you. Returns true if you were killed
import bool EnemyTurn();
// Attack one of the enemies you're facing. Returns true if you killed it
import bool AttackEnemy(int id);

// These are the enemies you're facing in this battle
import int battleEnemy[4];


Code: AGS
// Script
int battleEnemy[4];
export int battleEnemy;
int liveEnemyCount;

// All arguments apart from enemyId1 are optional and default to -1 (disabled)
void InitBattle(int enemyId1, int enemyId2, int enemyId3, int enemyId4)
{
  battleEnemy[0] = enemyId1;
  battleEnemy[1] = enemyId2;
  battleEnemy[2] = enemyId3;
  battleEnemy[3] = enemyId4;

  if(enemyId1 >= 0)
    liveEnemyCount++;
  if(enemyId2 >= 0)
    liveEnemyCount++;
  if(enemyId3 >= 0)
    liveEnemyCount++;
  if(enemyId4 >= 0)
    liveEnemyCount++;
}

// All the enemies in the battle attack in turn
bool EnemyTurn()
{
  int i=0;
  while(i<4)
  {
    int e = battleEnemy[i];
    if(e != -1 && enemy[e].IsAlive())
    {
      int damage = enemy[e].Attack();
      Character* body = enemy[e].body;
      body.AttackAnimation();
      myHealth -= damage;  // myHealth might be a globalvar
      if(myHealth <= 0)
         return true;       // Do whatever happens when you lose a battle
    }
    i++;
  }
  return false;
}

void AttackEnemy(int id)
{
  int e = battleEnemy[id];
  if(e != -1 && enemy[e].IsAlive())
  {
      int damage = Random(myStrength); // Again, here myStrength could be a globalVar
      enemy[e].health = enemy[e].health - damage;
      PlayerAttackAnimation(); // Defined somewhere
      if(!enemy[e].IsAlive())
      {
        Character* body = enemy[e].body;
        body.DeathAnimation(); // Which you define just like AttackAnimation
        liveEnemyCount--;
        return true;
      }
      else return false;
  }
  return false;
}


And then to fight a battle with Dracula and Koopa, you would do something like:
Code: AGS

void FightBattle()
{
  InitBattle(Enemy.Find("Dracula"),Enemy.Find("Koopa")); // This adds Dracula and Koopa to the battle

  // Then we just run battle turns until the player or all the enemies are dead 
  while(myHealth > 0 && liveEnemyCount > 0)
  {
     int target = PlayerPicksTarget(); // A method you've written to pick who to attack
     AttackEnemy(target);
     EnemyTurn();
  }
  if(myHealth > 0)
  {
    // Victory!
  }
  else
  {
    // Game Over
  }
}

Anshinin

Okay I'm working through reading and understanding that code so I can implement it since that's actually extremely useful to look at! A lot better than some of the examples I've seen digging through the forum.

Some of the features I'm trying to implement in my combat system and just a general idea of how I want it to work is as such.


  • As of right now all battles are 1v1, and will work like minibosses that won't appear after you've defeated them
  • There will be an option to fight with weapons you've found, magic spells which are represented with cards, and a "time manipulator" combo system (i'll explain)
  • You earn experience for individual stats based on usage (e.g. everytime you hit the enemy with a weapon you get +2 attack exp)
  • The magic spells will have a few different usages from basic attacks, summoning companions, or hypnotizing the enemy
  • The "time manipulator" thing is a little complicated but the general idea is being able to save up "time points" by not acting in your turn (hold up to 4 at a time) and then using them for various little things like hitting the enemy multiple times (the idea is that different versions of your character attack from different timelines), "rewinding" to revive yourself, fast forwarding time beyond the enemies turn so they can't hit you, etc etc
    This feature isn't entirely fleshed out yet but the general idea is there.
  • There is also the option to access your inventory for manual healing potions and items to increase your performance in battle
  • Finally an escape option if you need to

The numbers above the health bar are temporary.

Snarky

#9
OK, the fact that it's 1v1 and you only fight each enemy once does make it much easier, and it would in fact be possible to store enemy health as a globalvar, but I still wouldn't recommend it. It's better to keep all the enemy data in a struct. But you could do away with the battleEnemy array and just use the index into the enemy[] array (which you get with Enemy.Find("Enemy Name")) directly.

Some of the other features, OTOH, complicate things again. The battle system I tried to implement a couple of years ago was a FF-style Active-Time Battle, and I don't mind telling you it was an utter pain to implement (why I never finished it).

Let me know if you have any questions about the code. It demonstrates a bunch of AGS scripting concepts: how to define, export and import variables, arrays and functions, how to use structs and member-methods on structs, extender functions, etc. (Those are some keywords you could try looking up if you don't understand what's going on.) Good luck!

Edit: Another tip would be to use a common struct both for the player and the enemies, if they have similar types of stats, e.g.:
Code: AGS
// Header
struct Fighter
{
  String name;

  int strength;
  int defense;
  int health;

  int id;
  // ...
};

import Fighter enemy[MAX_ENEMIES];
import Fighter playerFighter;

// Script
Fighter enemy[MAX_ENEMIES];
Fighter playerFighter;
export enemy;
export playerFighter;

Anshinin

Okay so I know this is old but Snarky gave me permission (and preferred) that I just post here about it.

I tried putting this all together in a specific room and set up everything in the header but it's giving me an error

Code: ags
room11.asc(33): Error (line 33): Variable 'InitBattle' is already imported


This is the code in the room http://pastebin.com/vxpQDZPB

and this is the header, the only other place InitBattle is mentioned http://pastebin.com/FtJphJzJ


Gilbert

I haven't read the codes (and this thread thoroughly) but when you put "import something" into the script header, you're importing something defined in the Global script into rooms.
Since in your codes, InitBattle() is imported to the rooms in the header(I don't know whether it's defined in the Global script since it's not shown), it will generate an error when it is defined again in a room.
I'm not sure what you're after, but:
1. If the function InitBattle() is intended to be accessible to all the rooms, move the definition of the function from the room script to the Global script; or
2. if the function is only to be used in that single room, just remove that "import" line from the header.

Anshinin

That makes sense, I'm just confused about putting it in the GlobalScript because I don't know how to start the fight sequence so I thought I'd put it in a specific room for the battle, since that's how I did it with GlobalInts but I wanted to get away from that since Snarky said that wouldn't be very efficient.

Snarky

In the example code, InitBattle() is part of the battle system, and is defined... ideally within a dedicated script module, to keep things organized, though you can also put it in the global script. You can then call it from the rooms where you want to start a battle.

It's not that global vars are inefficient, it's that they're messy, particularly if you need to keep track of many things of the same kind (e.g. hit points for a dozen different enemies). But in any case, variables and functions work differently.

Anshinin

How would I call it from a room?

Snarky

You just... call it, like any other function. You already have it one place in the code:

Code: ags
InitBattle(Enemy.Find("Fuzball"),Enemy.Find("Kate"));


Incidentally, I'm sure the code I posted back then could be reorganized in a cleaner, better way (I don't like the way FightBattle() hardcodes certain enemies, for example, and when you just have two enemies in a battle, a separate InitBattle() function seems a bit redundant). I was just sketching out in a general way how you could express the data you need and the overall logical structure, it's not complete or perfect in any way.

Anshinin

I guess I'm just having a hard time wrapping my head around this, now that this has been set up how is it supposed to display the enemies bodies? And how does it know what XY position they should go to?

Snarky

This code doesn't do any of that stuff. It only deals with the logic of the battle itself, how to display it is up to you. In the sample, there are references to functions such as body.AttackAnimation(), body.DeathAnimation() and PlayerAttackAnimation(), which are examples of the kinds of functions you might want to write for the visual side.

If you just want to display the enemies on the screen, add a bit in the function that sets up the battle to put the bodies of the enemies somewhere. You'll have to decide where you want them. In your mock-up it looks like they always appear in a fixed position on the right side of the screen, and in that case you could just hard-code it.

Anshinin

As for running the part where you attack, and then your enemy attacks, could I attach that to a button on a battle screen GUI? So it'd run your attack and their attack.

Khris

Every GUI button has an onclick event, and you can assign a function to it just like you would to a "look at hotspot X" event. The function will be added to the global script. To call room code from the global script, you can use the CallRoomScript() function and put its counterpart "function on_call(int p) { ... }" into the room script.

Anshinin

I'm confused though, how could I get a button to run a script like this if putting it inside of it would make a weird nested function?

Khris

#21
You need to understand how functions work.

Let's define one:
Code: ags
function HelloPlayer() {
  player.FaceLocation(player.x, player.y + 1, eBlock); // face down
  player.Say("Hello");
}


We have now effectively added another command to the game, and we can use it in other functions.

Code: ags
function cEgo_LookAt() {
  Display("It's the character you control in this game.");
  HelloPlayer(); // call our custom function
}


Make sure you're absolutely clear what's happening here, otherwise there's no point in moving on. If the player clicks the player character with the look cursor, the game will call cEgo_LookAt(), which will Display() some text, then call the custom function, HelloPlayer(). Which in turn will make the player character face down and say something.

At no point is anything nested here; we have functions in the script, and we have function calls inside those functions.


The other important thing is that the function HelloPlayer() is actually "visible" from inside cEgo_LookAt(). This can be achieved by a) placing HelloPlayer() in the same script as cEgo_LookAt(), but further up, or b) placing it in a script further up the script tree, and importing the function in a header that ends up as part of the script that contains cEgoLookAt().

In English, if you have a few custom functions you need in all rooms, declare them at the top of the global script and import them in the global header.
If you have a lot of them, move their declarations and import lines to the main part / header of a new script.


As for your battle system, link a function to the button's on click event, so you'll get this:
Code: ags
function btn_Attack(GUIControl *control, MouseButton button)  // edit, added button param
{

}

Inside this function you call your battle system's custom attack function. Only the function call goes in there, not the actual function.

Edit: added button param to example click handler (which should not be pasted)

Snarky

Yeah, what Khris said.

However, there is another issue as well, which is how to get the loop in FightBattle() to wait for the input from the button and do the corresponding attack. There are a couple of ways to go about that, but off the top of my head, I think the easiest is to implement something like the PlayerPicksTarget() function I used in my example. (Instead of picking which enemy to target, you're picking which attack to use, but the logic is otherwise the same.)

This function should display the button(s) you want and then block until the player clicks on one, something like this:

Code: ags
Button* selectedAttackButton;

Button* PlayerPicksAttack()
{
  selectedAttackButton = null;
  gAttackPanel.Visible = true; // <-- the GUI with your buttons to choose an attack
  while(selectedAttackButton == null) 
    Wait(1);
  gAttackPanel.Visible = false;
  return selectedAttackButton;
}


Now the on_click() function for each button can just be:

Code: ags
function btnAttack_onClick(GUIControl* theControl)
{
  selectedAttackButton = theControl;
}


(If you have the battle system in a script file separate from the global script, which I would highly recommend, you either need to export and import selectedAttackButton, or provide and import a method to set it.)

If, for whatever reason, you can't block (i.e. use Wait()) inside the PlayerPicksAttack() function, it gets a little more complicated. You'll have to break up the FightBattle() loop and add some code in repeatedly_execute() to check whether the player has picked an attack yet, and if so run the attack and the enemy's response, determine if the battle is over, etc.

Remember we warned you that this whole thing was going to be pretty complex!

Anshinin

I really appreciate all the advice for this, and I'm totally doing my best to figure this out and learn from this. I understand it'll be complex but I also want to make a quality game.

I tried putting that in and it gave me this error.

Code: ags
GlobalScript.asc(729): Error (line 729): Type mismatch: cannot convert 'GUIControl*' to 'Button*'

Khris

I remembered it wrong, but you shouldn't paste button handler functions into the global script anyway, because then they won't be linked to the button, and clicking the button won't work, and you'll get back here and post that you pasted the code but the button won't work.

Just go to the button's event pane (select the button, click the thunderbolt icon), then click on the [...] button next to OnClick, and AGS will create and link the function, exactly like with all other events (which is what I told you to do two posts ago).

Anshinin

I had already done that, the only thing I did was place "selectedAttackButton = control;" into the function for my button. I didn't copy the whole function over since the name is different anyway.

ChamberOfFear

Quote from: Anshinin on Wed 17/02/2016 00:09:27
I had already done that, the only thing I did was place "selectedAttackButton = control;" into the function for my button. I didn't copy the whole function over since the name is different anyway.

Did you try this?
Code: ags
selectedAttackButton = control.AsButton;

Anshinin

That worked perfectly! Since you said this pick attack is essentially the substitution for Picking the Target, what would I replace this with?

Code: ags
int target = PlayerPicksAttack();


Since this is a button technically and not a int

Snarky

Well, as the function currently returns a Button*, that's the return type you need to use:

Code: ags
  Button* btnAttack = PlayerPicksAttack();


At some point you'll presumably want to use this value to branch into different logic to calculate the effect of the attack:

Code: ags
  if(btnAttack == btnAttackFire)
  {
    // Run a fire attack
  }
  else if(btnAttack == btnAttackMagic)
  {
    // Run a magic attack
  }
  // ...


Alternatively, instead of using the raw button value directly, you could have PlayerPicksAttack() convert it to some more semantically meaningful type, e.g. an enum or a custom struct storing more information. That would be the way to go if there isn't a direct, consistent mapping between the button and the attack, or if there are more parameters to the attack.

Anshinin

Which function would I put that under?

Snarky

Well, that's somewhat up to you, but logically it needs to go between when the player picks an attack (or other action), and when the game actually carries out that attack. So it could be inside AttackEnemy() (which would then need to take arguments both for the enemy target and for the type of attack), or it could be inside the battle loop in FightBattle(). If all the attacks/actions you can do are essentially similar (e.g. hit/kick/stab), I would put it in AttackEnemy(), but if there are some that are very different (e.g. drink a healing potion, or freeze time or something) it probably belongs more logically outside it, and you'd have other functions in addition to AttackEnemy() to handle those other scenarios.

We're getting to the core logic of your battle system here, where you really have to make the decisions depending on what you want it to be like.

Anshinin

#31
Okay that makes sense, however I'd like to make it so you can equip better weapons as the game proceeds so it wouldn't just be one button with the attack coded in. How could I code it where it detects an item being equipped and factors in that's value for power from my weapons struct to make the damage dealt?

EDIT: Also, would I put the functions for the buttons under the battle script or in the globalscript? Since when it's in the globalscript it's not detecting "selectedAttackButton = control.AsButton;"

Snarky

#32
Well, I'm not 100% clear on all the details of your system, but you'll probably want to have a variable either for the weapon that is currently equipped, or for the weapon that was selected for the attack. In a different language this would typically be a pointer to a Weapon object, but because AGS doesn't allow that, the best you can do (at least the best I can do: maybe monkey can work around it somehow) is an index into the weapons array.

Then the actual attack calculation needs to use that index to look up the relevant weapons stats, and use those value along with any other contributing factors to determine hit/miss and damage.

You may want similar variables for e.g. armor that is equipped (perhaps even separate variables for armor, shield, helmet, etc.). In a fancy system where enemies also can have different armor and weapons, you could make all of this part of the Enemy/Fighter struct, but if the player is the only character that ever needs to keep track of it, that's a bit of an overkill.

The button event handlers need to go in the Global Script: that's an AGS limitation. (However, if they're all going to be the same you don't need multiple copies of them. You can link all to a single function.) Like I mentioned in that earlier post:

Quote(If you have the battle system in a script file separate from the global script, which I would highly recommend, you either need to export and import selectedAttackButton, or provide and import a method to set it.)

Importing functions and variables (and exporting the latter) is a basic thing you need to know in writing AGS script, so best wrap your head around it.

You can export selectedAttackButton from the battle script and add an import of it to the battle header (which means it will be imported to all scripts below it in the list, so it can be accessed from any of them). However, as a matter of principle it's best not to expose too much of the inner workings of how something like this works (for example, if you want to rewrite it to work slightly differently, you want to keep the changes isolated), so it's probably better to define a function that represents the semantic action rather than the implementation detail of "set this variable", like:

Code: ags
void SelectAttack(Button* button)
{
  selectedAttackButton = button;
}


Add an import to the battle header, and now you can use this variation in the button click handler:

Code: ags
function btnAttack_onClick(GUIControl* theControl)
{
  SelectAttack(theControl.AsButton);    // thx ChamberOfFear for fix
}

Anshinin

I'm thinking I would make a struct for weapons in the game, and then have an array set and perhaps one of the values for it could be "equipped" and if it's a 0 it wouldnt be equipped and 1 then it would and display the button if it's equipped? I think logically I could code that.

Also I tried doing that and it's giving me this error.

Code: ags
BattleScript.asc(10): Error (line 10): Type of identifier differs from original declaration


in reference

Code: ags
Button* selectedAttackButton;


In the header

Code: ags
import void selectedAttackButton();

Snarky

Quote from: Anshinin on Sun 21/02/2016 22:28:48
I'm thinking I would make a struct for weapons in the game, and then have an array set

Yes. If you go back to the beginning of the thread, you'll see that this is what Vincent and Ghost recommended.

Quoteand perhaps one of the values for it could be "equipped" and if it's a 0 it wouldnt be equipped and 1 then it would and display the button if it's equipped?

Mmm... Maybe. But that would imply that you could equip an unlimited number of weapons at a time. How would you decide which one was actually used when you attack? And it would make things a little more complicated, because every time you need to do something with your equipped weapon, you'd need to loop through the array. Also, if you just need a flag for something that is true or false, you should declare it as a bool and actually set it to true or false, not 0 and 1.

If you can only equip a couple of weapons at a time, I would just have a couple of variables, e.g. int primaryWeapon, secondaryWeapon, and set them to the indexes of those weapons in the weapons[] array. If your "equipped" weapons work more like an inventory, I might make another array of equippedWeapons[] that again references the indexes in the weapons[] array, but in that case it's a bit less clear.

QuoteAlso I tried doing that and it's giving me this error.

Code: ags
BattleScript.asc(10): Error (line 10): Type of identifier differs from original declaration


in reference

Code: ags
Button* selectedAttackButton;


In the header

Code: ags
import void selectedAttackButton();


I'm not sure what you're trying to do here. You've declared selectedAttackButton as a Button pointer, but then you try to import it as a function. That doesn't work, obviously. You have to choose one or the other. What I recommended was to use a function to access it, but that function can't have the same name as the variable. Notice SelectAttack() vs. selectedAttackButton.

Khris

I'm terribly sorry, but:
Quote from: Khris on Tue 16/02/2016 16:20:01
You need to understand how functions work.
[...]
Make sure you're absolutely clear what's happening here, otherwise there's no point in moving on.

[...] if you have a few custom functions you need in all rooms, declare them at the top of the global script and import them in the global header.
If you have a lot of them, move their declarations and import lines to the main part / header of a new script.

Anshinin

I apologize if I seem like I'm wasting you guys time, I'm reading documentation on the scripting language alongside this and trying to learn it the best I can. I think I'll take a bit of time to review over this thread so far and try to understand everything 100% before I move on because I realize my questions aren't improving my understanding and I need to tackle this at a more fundamental level.

I still will keep up with this thread I just don't want to waste your time with simple questions. So basically I won't move on until I'm absolutely clear about what's happening here :P

SMF spam blocked by CleanTalk