Armor and weapons for my RPG

Started by aventurero, Mon 04/01/2010 23:59:20

Previous topic - Next topic

aventurero

How can I make an armor raise the variable "defense" and a sword raise the variable "attack"? Also I need that when the player character has got 2 armors, only the strongest armor will raise the defense, and the same for the sword.
Code: ags
function iToxicWaste_Talk()
{
Display ("You eat the toxic waste. Obviously, you die.");
QuitGame (0);}

Crimson Wizard

Simpliest way is to have an array of stats for each possible armor and weapon in the game. Like

int Armors[10];

Then you store current armor as ArmorIndex, and when you need to know its defence value, you get it like:

Armors[ArmorIndex]

Similar for weapons.

Second part is really simple. Just check which Armor has greater value and use it... umm, well. I don't know how you store equipment data, so I can't give some precise piece of code.

Khris

#2
It'll probably be even easier to use Custom properties. Add properties "att_mod" & "def_mod" of type int, default value 0.
Then enter e.g. 2 or 3 for every inventory item that's a weapon / armor.

Then add the on_event function to Global.asc:

Code: ags
function on_event (EventType event, int data) {

  if (event == eEventAddInventory || eEventLoseInventory) {
    int i;
    int att_mod, def_mod;
    InventoryItem*it;
    // look for biggest modificator
    while (i <= Game.InventoryItemCount) {
      if (player.InventoryQuantity[i] > 0) {
        it = inventory[i];
        if (it.GetProperty("att_mod") > att_mod) att_mod = it.GetProperty("att_mod");
        if (it.GetProperty("def_mod") > def_mod) def_mod = it.GetProperty("def_mod");
      }
      i++;
    }
    attack = base_attack + att_mod;
    defense = base_defense + def_mod;
  }
}


(This code assumes you have created four global ints "attack", "base_attack", "defense" and "base_defense", e.g. by using the Global variables pane.)

Edit: corrected code

aventurero

Khris, I did everything you said, and so far it worked. But my attack and defense raises without even having the items  :-\. And most important, it doesn't even raises the stats according to the most powerful items. You see, I made "armor" (def_mod: 5), "armor2" (def_mod:10), "sword" (att_mod: 5) and "sword2" (att_mod: 10). Logic dictates that the function will take the values for armor2 and sword2, but it takes the values of armor2 and sword...  :-\ I'm going crazy thinking.

If it's not too much to ask, can you figure out what's the problem? I surrender.  :-[ Thanks anyway, you're very, very helpful.
Code: ags
function iToxicWaste_Talk()
{
Display ("You eat the toxic waste. Obviously, you die.");
QuitGame (0);}

Khris

Yeah, sorry, I forgot to check if the item is in possession of the player. The above code should be correct now.

Is sword2 the last item in the list? I forgot that InventoryItems start at index 1 not 0, so my code skipped the last item.

aventurero

I tried, and an error pops up:
QuoteError: Character.InventoryQuantity: invalid inventory index 0
What does "index" mean? And by the way... I tried modifying this part of the code (just to see what happens):
Code: ags
if (player.InventoryQuantity[i] > 0) {

to this:
Code: ags
if (player.InventoryQuantity[2] > 0) {

and then adding the armor to the inventory. Then, instead of just adding 5 to defense (def_mod of armor), it adds 10 to defense and 5 to attack...

Hell, this is hard.  ???
Code: ags
function iToxicWaste_Talk()
{
Display ("You eat the toxic waste. Obviously, you die.");
QuitGame (0);}

aventurero

#6
Oh... I did a little research, and I found out (I know, you already know...  :P) that the index is the number between brackets. Aparently it can't be 0, and our variable "i" was 0.

So I just modified this:
Code: ags
int i;


into this:
Code: ags
int i=1;


So far, it works PERFECTLY. Will I have any problems later on? Thanks   ;D (I'm happy now)

EDIT: Well, I guess I'll never be happy. :P I have a new question. Can I somehow equip this armors and weapons to unleash the effects, instead of just having them in the inventory? Maybe make a new inventory, and a cursor to "equip" them (change them to the other inventory, and then unleash the effects). I don't know if I make myself clear.
That question came to my mind because sometimes you want to equip a weaker armor, in order to enter a place (for example a guard's armor to enter a castle, or something like that), even when having a more powerful piece of equipment.
Code: ags
function iToxicWaste_Talk()
{
Display ("You eat the toxic waste. Obviously, you die.");
QuitGame (0);}

Khris

Funny thing is, I was almost suggesting exactly that in my post further up :)

A second inventory sounds like a good idea in theory, and it'll work as long as the player doesn't need to use any of the items (you can't Useinv an item not in the player's possession).

I believe you're using a fight cursor though, so let's try:
Create a dummy character, e.g. cEquipped, and add an InvWindow to an existing or new GUI, e.g. iwEquipped.
Set its CharacterID to cEquipped's ID.

Remove the on_event stuff, and in General Settings, activate that inventory click are handled in script

I'll implement equipping an item by clicking it with the interact cursor:

Code: ags
 // inside on_mouse_click

  if (button == eMouseLeftInv && mouse.Mode == eModeInteract) {
    InventoryItem*i = inventory[game.inv_activated], o;

    int m = i.GetProperty("att_mod");
    if (m > 0) {  // click on a weapon?
      o = iwEquipped.ItemAtIndex[0];  // first item in equipment inv, weapon slot
      if (o != null && o.GetProperty("att_mod") > 0) {  // currently, another weapon is equipped
        cEquipped.LoseInventory(o);  // move it back to player's inv
        player.AddInventory(o);
      }
      player.LoseInventory(i);  // equip new weapon
      cEquipped.AddInventory(i, 0);  // put in weapon slot
      attack = base_attack + m;
    }

    int m = i.GetProperty("def_mod");
    if (m > 0) {  // click on armor?
      o = iwEquipped.ItemAtIndex[iwEquipped.ItemCount-1];  // last item in equipment inv, armor slot
      if (o != null && o.GetProperty("def_mod") > 0) {  // currently, another armor is equipped
        cEquipped.LoseInventory(o);  // move it back to player's inv
        player.AddInventory(o);
      }
      player.LoseInventory(i);  // equip new armor
      cEquipped.AddInventory(i, iwEquipped.ItemCount-1);  // put in armor slot
      defense = base_defense + m;
    }
  }
  else inventory[game.inv_activated].RunInteraction(mouse.Mode);

  if (button == eMouseRightInv) on_mouse_click(eMouseRight); // standard behavior for right click on inv


Untested!

aventurero

#8
I'll test it tomorrow, it's late here in Argentina  :P. But that bunch of codes and stuff seemed right to me  ;D. I'll get back to you.

EDIT: well, I guess I just couldn't wait. I didn't test it, but i've read it twice, and it seems fine. Adding something like a helmet and a shield would be just too much, I don't want neither of ours heads to explode. Oh, and when a weapon/armor is equiped, how will the player know it? We could use a label, like lblArmor and lblWeapon, and change the text on it to the name of the items equipped, right?
Please do it, I'm really slow thinking complicate stuff  :P

EDIT 2: oh and btw, you'll have a great spot on the credits, you can be sure about it.  ;D
Code: ags
function iToxicWaste_Talk()
{
Display ("You eat the toxic waste. Obviously, you die.");
QuitGame (0);}

aventurero

Well Khris, I tested it and it "worked". :P

First of all, let's modify this:
Code: ags
int m = i.GetProperty("def_mod");

for this:
Code: ags
m = i.GetProperty("def_mod");

because it's already defined.

The first problem I had was that the items just dissapeared, without coming back to my inv. I solved that by stablishing which player controls which inventory:
Code: ags
//on game start

iwEquipped.CharacterToUse=cEquipped;
invCustomInv.CharacterToUse=cPlayer;// my player character controls the custom inventory


Problem 1- As usual, another problem poped up. The items come back to my inv, but when I try it twice, they just don't.

Problem 2- In addition to that, I can't grab normal items, like a book. The interact cursor just does nothing.

Problem 3 (optional)- It would be good if weapons go to an inventory, and armors to another. That way I could just put 2 tiny squares at the panel, and you could easily see what you're wearing.

Problem 4 (optional)- Oh, an also it would be good to be able to unequip the items from the iwEquipped, since maybe you don't wanna have any armor or weapon, instead of replacing them with another one.

P.S.: Thank god you're german. Here in Argentina it seems no one is able to help anymore, specially when there is no money involved.  :-[
Code: ags
function iToxicWaste_Talk()
{
Display ("You eat the toxic waste. Obviously, you die.");
QuitGame (0);}

Khris

#10
Right, I copy pasted that and missed the int declaration.
Setting iwEquipped's owner in the GUIEditor should make the first game_start line obsolete though.

And yes, I imagined you'd add the second inventory to an existing GUI or you'd create one so the player sees the equipped items.
I agree though that my solution isn't exactly the best, but lots of it depends on how exactly you want to implement (un)equipping items, i.e. game design.

Code-wise, it's a lot easier to just have, say, four buttons on a GUI and change their images to the equipped items. No need then to hassle with moving items between inventories.

The most straightforward way of handling this, I think, is to add another Custom int property "inv_type". Leave it to 0 for standard inv items, change it to 1 for weapons, 2 for armor, etc.

Then do something like this:

Code: ags
// above on_mouse_click

function Update_defense() {
  int i = 1;
  defense = base_defense;
  Button*b;
  while (i < 4) {
    b = gEquipment.Controls[i].AsButton;
    defense += b.TextColor;
    i++;
  }
}

// inside on_mouse_click

  if (button == eMouseLeftInv) {

    InventoryItem*i = inventory[game.inv_activated];
    int it = i.GetProperty("inv_type");

    // standard behavior
    if (mouse.Mode != eModeInteract || it == 0) inventory[game.inv_activated].RunInteraction(mouse.Mode);

    else {  // interact with equipment
      Button*b = gEquipment.Controls[it-1].AsButton;
      b.NormalGraphic = i.Graphic;
      if (it == 1) attack = base_attack + i.GetProperty("att_mod");  // weapon
      else {  // armor, helmet, shield
        b.TextColor = i.GetProperty("def_mod");
        Update_defense();
      }
    }
  }

  if (button == eMouseRightInv) on_mouse_click(eMouseRight); // standard behavior for right click on inv


Create a GUI (gEquipment) with four buttons (clear their texts), IDs 0 to 3, 0 for weapons, 1-3 for armor, helmet, shield
Make them the same size as inv items, obviously, and set their OnClick function to this:

Code: ags
function UnEquip(GUIControl*c, MouseButton button) {
  if (button != eMouseLeft) return; // only react to left clicks

  Button*b = c.AsButton;
  b.NormalGraphic = 0; // clear button's image
  int it = c.ID + 1;
  if (it == 1) attack = base_attack;  // weapon
  else { // armor, helmet, shield
    b.TextColor = 0;
    Update_defense();
  }
}


I've used the unused TextColor property (an int) to store the items defense; using a custom function, I update the total defense every time something other than a weapon is (un)equipped.

Edit: corrected code

aventurero

It doesn't work...  :( first it says "variable b already defined" and then when I put the UnEquip function on the "OnClick" function of the buttons, it says "undefined symbol b". Argh. I don't know what to do. Can't we just forget about the helmet and shield and make it plain and simple?  :P I'm getting frustrated.
Code: ags
function iToxicWaste_Talk()
{
Display ("You eat the toxic waste. Obviously, you die.");
QuitGame (0);}

Crimson Wizard

#12
Oh, come on, aventurero! I know you can make it, just try little harder  ;)

Khris has a little mistake in his code, he uses same name for function parameter and local variable. I fixed code a little:

Code: ags

function UnEquip(GUIControl*c, MouseButton button) {
  if (button != eMouseLeft) return; // only react to left clicks

  Button* b = c.AsButton;
  b.NormalGraphic = 0; // clear button's image
  int it = c.ID + 1;
  if (it == 1) attack = base_attack;  // weapon
  else { // armor, helmet, shield
    b.TextColor = 0;
    Update_defense();
  }
}

aventurero

#13
Thanks Crimson Wizard :D
But apparently I'm a noob at this. I don't know what to put in the "Onclick" function of the buttons. Should I put this?:

Code: ags
UnEquip(GUIControl*c, MouseButton button);


That doesn't seem to work. I'm gonna kill myself.
Just kidding... I will make it, Crimson. I promise. :P

EDIT: it would be nice to communicate in other ways besides the forum. Like msn or something. What do you think guys? It's way too slow this way.  And I miss you :-[ :P
Code: ags
function iToxicWaste_Talk()
{
Display ("You eat the toxic waste. Obviously, you die.");
QuitGame (0);}

Crimson Wizard

#14
Quote from: aventurero on Wed 06/01/2010 17:13:03
But apparently I'm a noob at this. I don't know what to put in the "Onclick" function of the buttons. Should I put this?:

Code: ags
UnEquip(GUIControl*c, MouseButton button);

No, simply name of the function, that is:
Code: ags
UnEquip


Quote
EDIT: it would be nice to communicate in other ways besides the forum. Like msn or something. What do you think guys? It's way too slow this way
Well, I am logged in MSN every now and then, so you may catch me there sometimes.
Khris seem to have only ICQ account though.

aventurero

But I have to write parenthesis, and when I do, it says "not enough parameters to call function" :(
Code: ags
function iToxicWaste_Talk()
{
Display ("You eat the toxic waste. Obviously, you die.");
QuitGame (0);}

Khris

Damn, thanks Crimson Wizard.

aventurero:
Don't put anything in the OnClick functions, you don't need them. In the events pane of the buttons, put "UnEquip" into the text field directly.

aventurero

I did, Khris. And now the items equip, but they don't disappear from my inventory. And they only raise defense. And with some random values I don't understand.  ???
I'm about to cry. :P Forget about the helmet and shield. Let it just be an armor an a weapon. Go back to the 2 inventories set, if it's necessary. This doesn't seem to work and I don't wanna bother you.  :(
Crimson Wizard, if you figure out what's wrong, please tell me. :)
Code: ags
function iToxicWaste_Talk()
{
Display ("You eat the toxic waste. Obviously, you die.");
QuitGame (0);}

Khris

#18
I didn't remove equipped items on purpose; to unequip something, click the button showing the item.

Look, please calm down. What's with you and crying?
AGS doesn't have built-in RPG functionality, so some semi-advanced coding is required.
I wrote the functions I posted off the top of my head; I'd be more surprised if they didn't require some adjustments.
You showed already that you're able to fix minor errors yourself, which is really helpful.

I'm going to create a game (in the AGSEditor sense) and test all the stuff I suggested. Then I'll post the working parts, ok?
It's midnight here and I got to work tomorrow, but I might get back here today.

EDIT:
Ok, I tested this. Everything worked absolutely fine, the only thing I forgot to mention is: since I'm using the buttons' TextColor to store the current defense of the item it has to be set to 0 (or the defense modifier of the item initially equipped. Alternatively, run Update_defense once in game_start; you'll have to move the function above game_start in this case though).
Otherwise, until every piece of armor has been unequipped once, defense will get the wrong value.

See, one of the major problems here was that I had only a vague idea of how exactly you wanted this to work. It's a pure game design choice whether equipped items disappear from the inventory or not; after all, the player still has them in his possession, so from a real life point of view, they should stay.
Designing a nice and elegant user interface for an RPG isn't easy; commercial games use tons of different varieties.

If you're unhappy with the current way, I might go back and use inventories. Or you try to do it, you seem to be able to pick up the necessary scripting pretty quickly anyway. It's just that reading posts from you sounding like you're about to kill yourself if somebody doesn't help you in the next five minutes really put me off. Just chill. Sacrificing cool features of a game just because one can't pull them off perfectly from the start is really a bad idea.

aventurero

Quote from: KhrisOk, I tested this. Everything worked absolutely fine, the only thing I forgot to mention is: since I'm using the buttons' TextColor to store the current defense of the item it has to be set to 0 (or the defense modifier of the item initially equipped).

How do I do that?
Code: ags
function iToxicWaste_Talk()
{
Display ("You eat the toxic waste. Obviously, you die.");
QuitGame (0);}

SMF spam blocked by CleanTalk