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

#81
@pell
My point is that in the "all this stuff" part, if any of the lines concerning segment #1 are a match, the code for segment #2 never runs. This is also most likely what caused OP to open this thread.
Because why would they deliberately sabotage their segment2 code, then ask here why it doesn't work?
None of this is intentional, because it's all a hot, flaming mess. Again, sorry. But this needs to be unlearned ASAP.

As an aside: using the object[] array in a room script is possible but less readable than using oButton1 or oSegment2 or whatever.
#82
Yes, but again: the code for the first object is very likely to also call "return;" which will exit the function and thus ensure that the code for the second object is never executed in the first place. Doesn't matter if the variable names are fixed if the code never runs.
#83
Quote from: pell on Thu 06/03/2025 10:46:43To be fair, at least as far as  I understand the code, that looks like the intended behavior. The visibility of those two objects are set outside this function based on user clicks. If they are false, this function changes the sprites based on certain conditions, and if either are true, it returns without changing any of the sprites.
As Snarky already pointed out, the code will call "return;" in a ton of cases and thus exit the function before other variables are handled. This is almost guaranteed to not be intentional and very likely the reason why OP is posting in the first place; OP is just copy-pasting code without fully understanding what it does.
#84
Right, the "return" kills the second part, I didn't even catch that :-D
#85
Yes, you're still checking myCounter1 and myCounter2, not myCounter3 and myCounter4.

---

Sorry, but please do yourself a favor and learn how to not write code like that.
Leaving aside how tedious this is to maintain, it's also really prone to typos.

First of all, please do not use variables like "myCounter1", "myCounter2", etc. It's a temperature and a height, so why not actually use "temp1" and "height1" for starters? Or t1 and h1?

Also, if you organize your sprite numbers, you can replace this *entire block* with a single line like
Code: ags
  object[11].Graphic = 384 + t1 * 4 + h1;

You're already using an X/Y chart, now do the same for your sprite numbers. Instead of using 1 as the lowest number, make everything zero-based, at least internally.
The temperature has six different values, so 0-5. The height has four different values, 0-3.
Multiplying the temperature by 4 (the amount of height values) and adding the height will produce the numbers 0 to 23. Now simply add the first sprite number as offset and there your go.
If you add all the sprites to AGS in the correct order you won't even have to edit the sprite numbers.

TL;DR: Debugging code like this is a pointless exercise.

---

Also note that this code does not have to be inside repeatedly_execute/room_RepExec. The object's .Graphic only changes after one of the ints has changed, so that is the only point in time where you actually need to update it: right after an int change.
#86
Did you enter a "Description" for the object in its properties? Because that is what the Verb Coin template displays for objects (using Game.GetLocationName() in VerbCoin.asc's repeatedly_execute()).

If you do have entered a description and it still doesn't show up, make sure the object is clickable and not covered by something like a walkbehind(?) or invisible GUI.
#87
When a command doesn't work as expected, the first thing to do is to check its manual entry:

Quote from: manualAll background speech is automatically removed when a normal Say command is used (unless you set the global variable game.bgspeech_stay_on_display to 1).

Add the following to game_start:
Code: ags
  game.bgspeech_stay_on_display = 1;
#88
Here's a shorter version:

Code: ags
function oObject20_AnyClick()
{
  object[20].Graphic = (object[20].Graphic - 409) % 4 + 410;
}

(Iterating over 0 to X is done by adding 1 followed by mod X+1. Iterating over 410 to 413 means we need to subtract 410 first, then add it back at the end.)

You can also do this instead:
Code: ags
  int slot = object[20].Graphic + 1;
  if (slot == 414) slot = 410;
  object[20].Graphic = slot;

The rule of thumb is: if you have lots of similar code you're copy-pasting all over the place, you're probably doing it wrong.
#89
I checked it again and disabling the VerbCoin means inventory clicks are ignored.
So you need to roll back the previous change and also show the inv GUI using
Code: ags
  gInventory.Visible = true;
in your bag button's OnClick handler.

Looks like the open_gui/close_gui functions are supposed to be used for "meta" GUIs like game menus only.

(Also note that your inventory GUI background has spaces in between slots, so you need to increase the invWindow's itemWidth and itemHeight accordingly.)
#90
Afaik, the VerbCoin template doesn't show the VerbCoin when you click an inventory item. You're basically only supposed to select (left click) / look at (right click) inv items.

The second issue is caused by the Escape key click handling: in line 389, replace gInventory.Visible = false; with
Code: ags
  close_gui(gInventory);
This function also calls VerbCoin.Enable();
#91
I understand that. I'm asking if there's a technical reason. Because I don't see it.
When you write inv handling code, the usual way is to do this:
Code: ags
  player.ActiveInventory = inventory[game.inv_activated];
So provided that the inv window that was clicked on is showing the player's inventory, this check is redundant for obvious reasons.

player.ActiveInventory is essentially just a random pointer that is typically checked in UseInv handlers.
It is set by the game's creator in their code, not the player. So if the creator wants to make sure that it only points to items actually held by the player character, they can easily implement this (it's not even extra work, it's just how a game works by default anyway).

Let's pretend the engine's setter doesn't check the player's inventory for a second. What is the downside?
Because there is a clear upside: we no longer have to work around the check in case we need to.
#92
I guess one workaround is to simply always call Add/LoseInventory on both (all) characters in question.

Another hacky way is to use custom inv click handling and simply add the item to the current player character before setting it as active.

On that note: why does the check exist in the first place? Why does AGS complain if you set a non-owned item as active?
#93
If the characters are supposed to have a shared inventory, you can transfer all the items, like this:

Code: ags
function TransferInventoryTo(this Character*, Character* other) {
  for (int i = 1; i <= Game.InventoryItemCount; i++) {
    other.InventoryQuantity[i] = this.InventoryQuantity[i];
    this.InventoryQuantity[i] = 0;
  }
  UpdateInventory(); // this unfortunately resets the order of the items to the editor's
}

Now you can call
  cAbby.TransferInventoryTo(cBarney);


AGS has a global pointer called  player  which always points to the player character. I.e. you can look at player.Room or call player.AddInventory(...) at any point. You can set which character the initial player character is in the editor. This also determines which room is loaded at the start of the game (because every character has a starting room and coordinates).

Characters are global entities and do not need to be "activated" after a room change. All you need to do is call player.ChangeRoom(room, x, y); and AGS will a) move the current player character to the new room at the specified coordinates, then unload the current room and load the new one.

Following works in a similar way; once you tell a character to follow another character they'll keep following them even to new rooms until you call .FollowCharacter(null)
#94
There's a global variable called CurrentCharacter, initially set to 1.

In room_Load of the first room you have
Code: ags
  if (CurrentCharacter == 0)
  {
    cAbby.SetAsPlayer();
    cBarney.FollowCharacter(cAbby);
  }
  else
  {
    cBarney.SetAsPlayer();
    cAbby.FollowCharacter(cBarney);
  }

Which means cBarney is set as player character. cBarney doesn't have any inventory items though, and consequently the inventory GUI is empty.
(I didn't even notice this at first; when I started to debug this I simply put "return;" at the start of room_Load and re-ran the game, and the items appeared just fine.)

Each character has their own inventory, and the invWindow GUI Control is set to display the current player's items, i.e. now the dog's. When you go about fixing this, you should definitely keep the current setting of -1, because if you try to set an item as active that isn't owned by the player, AGS will grind to a halt.
Having multiple inventories is kind of tricky, so you should tell us how you want this to work in your game.

Also, regarding the global variable, you don't really need that. You can do one of these instead:
  if (player == cAbby) ...
  if (player.ID == 1) ...


As for explicitly setting the player in room_Load: AGS always loads/displays the room the current player character is in. I.e. if you call .SetAsPlayer() on a character in another room, AGS switches to that room. So the room_Load code doesn't really make sense; when you create a game where the player can switch the playable character, you typically implement this globally (via a GUI or global keyboard shortcut) and let AGS take care of the room switching. Again, we need to know how you want this to work to give more specific advice.
#95
Everything looks fine; not sure what's happening. If you upload your source files and post the link, we can take a look.
#96
Just to clarify: you cannot see any items in it *in-game*, right?
Because the editor won't show them.
#98
Do you want to permanently replace the button images? Because in that case you can simply overwrite the sprites in Main/GUI/en with your own sprites.
#99
@Kara Jo Kalinowski
True, I forgot that the function completely takes over the hotspot handling :-[
#100
I'd create a universal extender function called Reach or something and call that at the appropriate time:

Code: ags
void Reach(this Character*, HeightType height) {
  this.LockView(PLAYER_REACH);
  this.Animate(loop, ..., eBlock); // loop calculated from player.Loop and height
  this.UnlockView();
}

In your door hotspot handling:
Code: ags
  player.Reach(eHeightMid);
  if (Doors.AnyClickSpecial(...)) ...

In general, avoid duplicate code at all costs and separate concerns whenever possible. (i.e. absolutely never put multiple lines of identical reach animation code into every single door hotspot function and think about whether the player reaching for something will only happen when they're opening a door [probably not])
SMF spam blocked by CleanTalk