Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Messages - Khris

#421
Ok, I think I understand what the problem is.

Each time your loop finds an item (*any* item), it adds inventory[inventaireused+1] then increases inventaireused by one.
Naturally, this will simply iterate over all AGS inventory items of your game, regardless of what the enemy actually possesses.

However,
Code: ags
enemy_item[i].enemyId == enemyId && enemy_item[i].count > 0
means that the enemy possesses at least one of
Code: ags
loot[enemy_item[i].itemId]
which is one of your loot items.
So the next step would be to use the loot item's information and add the correct AGS inventory item to the enemy.

I'm not sure how you're getting from the info stored in
Code: ags
Struct loot{
int sprite;
String Nameitem;
int bonus;
...
}
to an actual AGS inventory item though.
#422
The formula to calculate the x coordinates was apparently subtracting the entire rest of the term from 160; I added parenthesis to prevent this and then the buttons were placed correctly for me.
I was confused why you need them because the formula is basically 160 - A + B and it seemed to evaluate to 160 - (A + B) so I used (160 - A) + B which fixed the button placement for my test.
#423
Found the main problem:
Code: ags
    b.X = (160 - (availableCount * (b.Width + 2) - 2) / 2) + i * (b.Width + 2);

Not sure why you need the parens though.
#424
Your Materialize_loot function doesn't use my code at all it seems. It also doesn't use your loot array.

Your original code had lines like this:
ennemi[0].loot1=0;
ennemi[0].loot2=1;
ennemi[0].loot3=0;
ennemi[0].loot4=1;
ennemi[0].loot5=0;

Translated into a table (think MS Excel), this is akin to having five columns in your enemy table to store what loot they have, and this doesn't even allow for also stating how many of each item they have.
I provided a way to get rid of these columns by using a third table/array, which also allows to put, say, 3 items of the same type into an enemy's inventory, instead of just one.

You also had
loot[1].Nameitem=Blade;

I assumed you would use my system like this:
enemy_item[Eilookup(0, 1)].count = 3; // enemy #0 has 3 of loot item #1 (Blade)

This means your Materialize_loot function has to iterate over your own custom loot array, use the index as the second parameter for Eilookup(enemyId, i) and use the result:

Code: ags
  int count = enemy_item[Eilookup(enemyId, i)].count; // enemy enemyId has "count" number of loot item #i

This count is now used to populate the actual inventory window by translating loot item #i into an actual AGS inventory item.
#425
I was using an example enum so you don't have to remember the index numbers but can use names instead.
Not sure if the first enum value is 0 if you don't state it explicitly though.
If it's 1 instead, you can use
Code: ags
enum TeleportLocationName {
  eTLEngineRoom = 0, eTLCrewQuarters = 1, ...
};
then use these enum values to set up your locations.

Also, when you get error messages, please always show your actual code and the exact error message. You shouldn't get a parse but an out of bounds error, so something else might be wrong.
#426
If you have a total of 13 locations, you need to

a) replace the 10 in both the import and declaration line with 13
b) in game_start, set TeleportLocation[0] to TeleportLocation[12], then tlCount to 13
(This is because arrays use zero-based indexing.)

Next, set TeleportLocation[?].Available to true or false at any point during the game, then call SetUpTeleportButtons() to update the buttons' visibility and position (alternatively, call it when the player clicks the teleport button)

As for a location being connected to multiple rooms, that's not reflected by the code yet. I'll get to that later today or tomorrow.
#427
The 10 is the maximum number. tlCount is the actual number.

So if you have seven locations total, just set it to 7 in game start. It's mostly for the loops that iterate over all locations.

Assuming you have seven locations and five are available, and the buttons have the IDs 11 to 17, the code should position them correctly, but I haven't tested any of it.

Say a button is 30 pixels wide, then for the first button, 160 - (availableCount * (b.Width + 2) - 2) / 2 + i * (b.Width + 2) is 160 - (5 * (30 + 2) - 2) / 2 + 0 * (30 + 2) which is 160 - 158 / 2 or 81.
The next button should be at 81 + 32 i.e. 113, then 145 (the center button), 177 and 209. The last button ends at 239, which is 81 pixels from the right edge.

If your game uses a higher resolution, simply replace the 160 at the start with half your screen width or Screen.Width / 2.
Or gIconbar.Width / 2.
#428
Start with a list of locations:

Header:
Code: ags
enum TeleportLocationName {
  eTLEngineRoom, eTLCrewQuarters
};

struct str_TeleportLocation {
  bool Available;
  int SpriteSlot;
  int RoomNumber;
  int X;
  int Y;
};

import str_TeleportLocation TeleportLocation[10];

Main:
Code: ags
str_TeleportLocation TeleportLocation[10]; export TeleportLocation;
int tlCount;

  // in game_start
  TeleportLocation[eTLEngineRoom].SpriteSlot = 123;
  TeleportLocation[eTLEngineRoom].RoomNumber = 2;
  TeleportLocation[eTLEngineRoom].X = 123;
  TeleportLocation[eTLEngineRoom].Y = 45;
  // etc.
  tlCount = 6; // 6 total 

Setting up the buttons is done by iterating over the list:

Code: ags
void SetUpTeleportButtons() {
  int firstTeleportButtonID = 11; // actual ID goes here
  int availableCount = 0;
  // set button sprites and count available locations
  for (int i = 0; i < tlCount; i++) {
    if (TeleportLocation[i].Available && TeleportLocation[i].RoomNumber != player.Room) {
      Button* b = gIconbar.Controls[availableCount + firstTeleportButtonID].AsButton;
      b.NormalGraphic = TeleportLocation[i].SpriteSlot;
      availableCount++;
    }
  }
  // position buttons and turn them (in)visible
  for (int i = 0; i < tlCount; i++) {
    Button* b = gIconbar.Controls[i + firstTeleportButtonID].AsButton;
    b.Visible = i < availableCount;
    b.X = 160 - (availableCount * (b.Width + 2) - 2) / 2 + i * (b.Width + 2);
  }
}

Here's the onClick for all buttons
Code: ags
function btnTeleport_OnClick(GUIControl* control, MouseButton button) {
  Button *b = control.AsButton;
  if (b == null || button != eMouseLeft) return;
  for (int i = 0; i < tlCount; i++) {
    if (TeleportLocation[i].SpriteSlot == b.NormalGraphic) {
      player.ChangeRoom(TeleportLocation[i].RoomNumber, TeleportLocation[i].X, TeleportLocation[i].Y);
    }
  }
}
#429
If you want to move an object to the back, just set its baseline to 1. The default baseline for an object is at its bottom, so a screen-sized object will appear in front of pretty much everything else.
#430
You should also check the hotspot of the relevant mouse cursor; I remember at least one being completely off when I looked over your game.
https://www.adventuregamestudio.co.uk/forums/advanced-technical-forum/changes-in-verb-coin-code/msg636658205/#msg636658205
#431
Yeah, sorry, typo on my part.
The for line in the EiLookup function should not try to redeclare i:
Code: ags
  for (i = 0; i < enemy_items; i++) {
#432
You don't need to manually provide the index of the enemy_item[] array. The whole point of my approach is to never have to write code like in your 2nd snippet, at all.

When you want to change or read the number of items an enemy has, you always use
Code: ags
  enemy_item[EiLookup(3, 5)].count
like any other integer variable and simply enter the appropriate enemy id and item id. The function will look up the corresponding table entry and return the array index.

The for loop inside the function searches for a match; the i variable is simply the counter.

Say you want enemy[0] to have one each of item[2], item[6] and item[9]:
Code: ags
  enemy_item[EiLookup(0, 2)].count = 1;
  enemy_item[EiLookup(0, 6)].count = 1;
  enemy_item[EiLookup(0, 9)].count = 1;

That is all you need.

To iterate over an enemy's inventory you would use something like this:
Code: ags
function DoSomethingWithEnemyInv(int enemyId) {
  for (int i = 0; i < enemy_items; i++) {
    if (enemy_item[i].enemyId == enemyId && enemy_item[i].count > 0) {
      // has at least one of item[enemy_item[i].itemId]
    }
  }
}
#433
I'd use what's called "third normal form" in database theory.

You have a list of numbered enemies and a list of numbered items, so to assign an item to an enemy, you use a 3rd list.

Code: ags
// header
#define MAX_ENEMY_ITEMS 1000

struct str_enemy_item {
  int enemyId;
  int itemId;
  int count;
}

// main
str_enemy_item enemy_item[MAX_ENEMY_ITEMS];
int enemy_items;

int EiLookup(int enemyId, int itemId) {
  int i;
  for (i = 0; i < enemy_items; i++) {
    if (enemy_item[i].enemyId == enemyId && enemy_item[i].itemId == itemId) return i;
  }
  if (i == MAX_ENEMY_ITEMS) {
    Display("MAX_ENEMY_ITEMS limit reached");
    return -1; // this will cause an out of array bounds error
  }
  // i is now the first free list entry
  // list entry doesn't exist yet so create it
  enemy_item[i].enemyId = enemyId;
  enemy_item[i].itemId = itemId;
  enemy_items++;
  return i;
}

To add item #5 to enemy #3, you can now do:
Code: ags
  enemy_item[EiLookup(3, 5)].count++;
#434
The main problem is the display command, which pauses the game until you press a key or mouse button.
If you use a GUI and a label instead, it'll work as expected.
#435
Quote from: Brian925 on Fri 16/02/2024 04:26:18Then I tried a second inventory box, but I couldn't figure out how to call out to the images without adding inventory to my actual inventory.

I'd have used GUI buttons for this, but a 2nd inventory is actually a neat idea.
Create a dummy character, then set the inventory window's owner to that dummy. Now you can add items to the dummy's inventory and they will show up in the window.
Newly gained items will end up at the bottom though, so not sure if it's possible to get items in descending order with an inv window. Calling UpdateInventory() will put the items in the order of the editor, so that should work, but it will also re-sort your player character's inventory I guess.
#436
@TonyD I feel bad for pointing this out now but your last post contains a bunch of somewhat questionable advice :P

Cropping down a frame sprite does absolutely nothing except potentially move the center of the sprite to the left or right. This could (and usually will) completely mess up the alignment of your frames because AGS uses the bottom midpoint of the sprite as the pivot to animate characters. It has no benefit whatsoever except for saying a few bytes of resource space.
It is possible that this accidentally helped with making the limp look better but that's purely coincidence.

Doubling a frame is nonsense, not just from the POV of animating something but also because you can simply turn up the delay for individual frames. In a walkcycle, using the same frame twice in a row simply means that AGS will move the character without animating it. This, again, might "improve" the look of the animation by accident but is in no way a useful thing to do in general.

Finally, the "MovementSpeed" is actually the number of pixels that the character moves in between frame changes. Ideally it should be precisely matched to the animation frames and never changed again to avoid any gliding or moonwalking.
To increase or decrease the actual speed of the character you're supposed to use the AnimationDelay property, which will make the character go slower or faster without introducing a mismatch between the character's feet and the ground.
If you look at the blue foot in my example gif, you can see that it touches the ground and remains exactly in place; this is because the foot moves to the left by 4 pixels each frame and consequently the MovementSpeed was set to 4.

Again, sorry for shitting all over your advice :P  :-[
#437
Like I said, I didn't use any code but simply moved the body off center in the animation sprites.

Here's the sprite sheet:

(20x20x8)

If you open this and turn on a 10x10 grid, you can see how the body moves back and forth.
#438
Standard click processing will call Room.ProcessClick(). This gets queued however, so if the function is for some reason* called twice, it gets queued twice, and the linked room script function will also run twice I guess.

*faulty logic in the global on_mouse_click will do this for instance
#439
The limp stopping mid-animation is always an issue but pretty much unavoidable unless you code completely custom walking.

Here's a very quick example of a limping walk-cycle:

#440
You can do this with animation frames only; the idea is that the character's pixels move "backward" inside the sprite while the sprite moves "forward".
This causes the character's body to appear in place while their x/y coordinate still changes according to standard movement.
SMF spam blocked by CleanTalk