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

#361
Quote from: RootBound on Fri 26/04/2024 12:00:36Just take that first "return" out

That first return is fine if you don't want anything to happen each time the dialog starts.
#362
Like @Snarky explained, commands like that always go inside functions so AGS knows when to play the sound.

AGS scripting is event-based, which means when certain events occur (a room loads, hLadder is clicked, etc.) AGS checks if a function is linked to the event, then runs the function. Which means the code inside the function is executed.
#363
Re scaling:

Open the room, then click the⚔icon in the properties window. Now click the "player enters screen before fadein" event in the table, then click the [...] button at the end of the blank field.
This will create and link the function and take you to the room script. Now put the line inside the function so you have this:

Code: ags
function room_Load()
{
  player.ManualScaling = true;
  player.Scaling = 200;
}

As for the dialog script:
You don't need a dialog if you just want your characters to talk. You can simply put Say() lines in a function.
In a dialog, commands go after the entry points. So you'll want to create a first option, write "Hi!" inside, then check both the Say and Show boxes.
The script should look like this:

Code: ags
// Dialog script file
@S  // Dialog startup entry point
return
@1  // when first option is clicked, player says "Hi", then script runs from here
JC: HELLO
return
#364
I'm also running Win 11 Pro, and I've removed the policy change.

I tested the 3.6.2-dev build and Defender prevented AGSEditor.exe from running but clicking "More Info" and "Run anyway" fixed it for good.
Also, test-running the game via F5 did work fine!

Note:
I tend to run executables from inside Total Commander, which I always run with admin rights. This means that the program also runs with elevated rights (as opposed to from Explorer in user mode), which might have an influence.
#365
@eri0o Good to know, I'll try this when I get home (I can reproduce the issue if I undo the policy change)

@Laura Hunt I also added the Debug folder but it didn't help
This only started about a week ago, I didn't have any issues before
#366
I'm still using Paint Shop Pro 7.

All I do is draw a bunch of areas in arbitrary colors, then select "Reduce colors -> 256 colors" from the menu. I confirm the algorithm prompt and end up with the used colors in the first slots of the new 256 color palette, with the background color ending up in slot 0.

Next I save this file as png and can now import it into AGS, which works flawlessly. I don't even have to recolor anything (unless I want the main area to be in slot 1 or something).
#367
Engine Development / Re: engine problem
Wed 24/04/2024 09:17:35
On running the latest build of AGS 3.6.1. I ran into a similar issue: Windows Defender complained about being unable to verify the debug exe's publisher when I hit F5 to test a game, which means on each test run I had to tell Windows that, yes, I'm sure, I want to run this software. Unchecking "Always ask before opening this file" had zero effect.

Adding the AGS folder to the whitelist in Windows Security had no effect either, so I was looking for another solution. Googling the problem I found this:

https://docs.rtafleet.com/troubleshooting-articles/troubleshooting-rpv/publisher-could-not-be-verified-%252F-unknown-publisher/

This method worked wonders, so here's how to do this in case the link dies:

1. Press the Windows key and type "gpedit". This should find the "Edit group policy" app from the control panel. Open it.
2. In the tree, navigate to "User Configuration -> Administrative Templates -> Windows Components -> Attachment Manager"
3. Double-click "Inclusion list for moderate risk file types"
4. Set it to "Enabled" and in the Options part, enter ".exe" without the quotes into the box

Note that this possibly makes your virus detection less effective, so don't do this if you like to open attachments from unknown senders ;)
#368
The current verbcoin template is completely new or at least a rewrite afaik. So a thread from 2013 might be about very different code altogether.

The basic idea is to edit the on_mouse_click / eMouseLeft part of the VerbCoin script.
We need to also go inside the
Code: ags
    if (GetLocationType(mouse.x, mouse.y) != eLocationNothing)
block.

Now read the property and proceed accordingly:
Code: ags
      Hotspot* h = Hotspot.GetAtScreenXY(mouse.x, mouse.y);
      if (h != null && h.GetProperty("no_verbcoin")) { // boolean property, default value "false"
        interface.Visible = false; // turn off verb coin if it's still visible
        h.RunInteraction(eModeInteract);
        return; // end handling here
      }

edit: typo in code fixed
#369
I feel the most important part is this one:
Quote from: BowsetteGamer on Mon 22/04/2024 13:24:10AGS identifies that "Hello" and responds by saying "Hi, how was your day?"
Quoteand finally AGS gives an answer

As eri0o said, the parser can help you process commands like "go north" or "look at table". But carrying a conversation is a whole other level.

How sophisticated is this supposed to be? I mean it has been done in the past, for instance there's been a MAGS game where you could communicate with another person by typing into a chat basically. It was very well done and a lot of work. I can't remember the game's name though.

But just to clarify: any answer AGS is supposed to give has to be hardcoded by you. Like
Code: ags
  if (prompt == "Hello") Display("Hi, how are you?");
  else if (prompt == "I'm fine") Display("That's great.");

Note that this only works for exact matches, so "Im fine" or "I'm  fine" has to be detected separately.
#370
My savegame approach was not meant as an ideal solution; it has obvious drawbacks.

It really depends on how complex the data is we're talking about. Placing tokens sounds like a single int array could store all the necessary information maybe. In that case, savegames don't make much sense unless you're looking for a quick and dirty solution.
#371
Btw, you can let AGS do the heavy lifting and simply use savegames.

Code: ags
int slot = 1;

function Save() {
  SaveGameSlot(slot);
  slot = 3 - slot; // switch between #1 and #2 so slot is always the second to last savegame
}

function Undo() {
  RestoreGameSlot(slot);
}

Each time you've placed a token, call Save();
Call Undo() to load the previous savegame.
#372
I opened the font in FontForge and I noticed that the midline is relatively low. (It also has a bunch of wrong references.) In short, this is primarily the font's fault.

I'd recreate it as Bitmap font using Radiant's FontEdit

Not a font expert at all but I did try to fix the ttf one:
https://drive.google.com/file/d/1lD-noS5inc59PZX8pqtS4JJi37mnTHAQ/view?usp=drive_link
#373
You can use a custom property for this.
https://adventuregamestudio.github.io/ags-manual/CustomProperties.html

Add a Boolean one to just inventory items, call it like "interact" and set its default value to 0 (false).
Then set it to 1 (true) for your book inventory item.

Now use this else if block:
Code: ags
  else if (button == eMouseLeftInv || button == eMouseRightInv)
  {
    InventoryItem* ii = inventory[game.inv_activated];
    if (ii.GetProperty("interact")) ii.RunInteraction(eModeInteract);
    else do_inventory_action(button, ii);
  }

(Also, if it's just the book, you can of course skip the property and simply do  if (ii == iBook))
#374
My guess is the custom dialog module already uses dialog_options_render() under the hood, so you'd have to dive into that to have colored options.

As for label text, AGS doesn't support more than one color per label. You'd have to use a button instead and draw its NormalGraphic.

In both cases you can use eri0o's module to have multiple colors in your text.
#375
The problem becomes obvious if you look at this part:
Code: ags
  sorts[i+sorts[i].index].icone30

You are storing the index offset for each spell in a place you can only access if you already know the offset. You don't however, so you simply use the list item index without the offset instead (which will accidentally work in some cases, then quickly fail).

The problem isn't that the .index values are changed, it's that you're reading the wrong .index value. If you remove every spell except sorts[3], it's the only list item left and therefore item #0. Which means in the code piece above, the value of i will be 0. Which means you won't be reading sorts[3].index (which contains the value you're looking for) but sorts[0].index instead. You will then add whatever sorts[0].index is (most likely 0) to i (also 0) and again end up with an index value of 0, which means you're now reading sorts[0].icone30 instead of sorts[3].icone30.

Edit: you can probably also fix your code by using sorts[a].index to store the offset for list item #a, as opposed to sorts[a]. In fact, this seems what you wanted to do from the start I guess. Which means there's a tiny bug somewhere. Let me check.

Edit2: found the bug: the list of offsets, regardless where it is stored, needs to lose items along with the list. Otherwise you keep using offsets of items that are already removed from the list. Increasing the values starting from the selected item isn't enough; you also need to shift the values.

Here's the fix of your original code:
Code: ags
  for (int j = i; j < 5; j++) { // 6 max spells
    sorts[j].index = sorts[j + 1].index + 1; // add one and move up the list
  }
#376
The curious thing here isn't that it breaks in the end, it's rather that it appears to work in the beginning :-D

The basic idea is sound, however when you remove an item, the list index of the spells further down gets decreased by one, which means each spell now uses the wrong sorts[].index. This doesn't matter as long as it's 1 for every spell, but if a spell that had +3 as its .index gets shifted to a lower list index, that spell could now end up using the lower .index of, say, +2 of the spell above it.
This additional -1 screws up the associations of the list items and the spell array.

To put it another way: to get the correct sorts[] element to read the .index, you would need the already fixed index, but if the index is already fixed, you no longer need the sorts[].index value.
Implementing your solution requires an independent array of index correction values with its values getting shifted exactly like the list items.

Another way to fix this is looking up the list item string in the spell array:
Code: ags
  int si = -1;
  for (int i = 0; i < 6; i++) if (sorts[i].name == Sortswar.Items[Sortswar.SelectedIndex]) si = i;
  // populate GUI using sorts[si] info
#377
I'd just remove the hotspots and use an actual character. The Tumbleweed template is hardcoded allow items to be given only to characters and fixing this is a huge pain.
#378
Great!

Don't worry, and finally solving problems like this is its own reward :)
#379
Do you mean rename the action in general? Or just the action text?
Can you give an example?
#380
I was working on a math based solution but it got more complicated quickly. I'll try your original approach again, give me a few hours :)

Edit: got it:

Code: ags
// room script file

enum KiteState {
  eKiteCircling, eKiteSwoopingIn, eKiteSwoopingOut
};

KiteState kite_state = eKiteCircling;
int exposed_timer;

int circling_timer;
int kite_region; // 0 = right, 1 = top right, etc.

function room_Load()
{
  cKite.z = -60;
  kite_region = 0;
}

void caught_by_kite() {
  Display("Caught by kite");
  // QuitGame(0);
}

bool kite_is_outside_screen() {
  ViewFrame* vf = Game.GetViewFrame(cKite.NormalView, cKite.Loop, cKite.Frame);
  int hw = Game.SpriteWidth[vf.Graphic] / 2;
  int h = Game.SpriteHeight[vf.Graphic];
  if (cKite.x < -hw || cKite.x > Game.Camera.Width + hw) return true;
  return cKite.y < 0 || cKite.y > Game.Camera.Height + h;
}

function room_RepExec() {

  // is player in danger
  bool danger_zone = Region.GetAtRoomXY(player.x, player.y) == region[5];
  
  if (danger_zone && cEgo.IsCollidingWithChar(cKite)) caught_by_kite(); //death script

  oDanger.Visible = danger_zone; // obj currently being used for testing
  exposed_timer = (exposed_timer + 1) * danger_zone; // increase / reset timer

  if (kite_state == eKiteCircling) {
       
    // kite swoops for player, continuing straight if player moves
    if (exposed_timer > 100) { 
      exposed_timer = 0;
      kite_state = eKiteSwoopingIn;
      float dx = IntToFloat(player.x - cKite.x);
      float dy = IntToFloat(player.y - cKite.y);
      float f = 2000.0 / Maths.Sqrt(dx * dx + dy * dy);
      cKite.Walk(cKite.x + FloatToInt(f * dx), cKite.y + FloatToInt(f * dy), eNoBlock, eAnywhere);
    }    
    else {
      circling_timer++;
      if (circling_timer >= 50 && !cKite.Moving) {
        kite_region = (kite_region + 1) % 8;
        float a = (IntToFloat(-kite_region)) * (Maths.Pi / 4.0);
        cKite.x = Game.Camera.Width / 2 + FloatToInt(IntToFloat(Game.Camera.Width) * Maths.Cos(a), eRoundNearest); 
        cKite.y = Game.Camera.Height / 2 + FloatToInt(IntToFloat(Game.Camera.Height) * Maths.Sin(a), eRoundNearest) - cKite.z; 
        circling_timer = 0;
        // visible top left
        if (kite_region == 3 && !cKite.Moving) {
          cKite.x = 300;
          cKite.y = -100 - cKite.z;
          cKite.Walk(-300, 200 - cKite.z, eNoBlock, eAnywhere);
        } // visible bottom right
        if (kite_region == 7 && !cKite.Moving) {
          cKite.x = Game.Camera.Width - 300;
          cKite.y = Game.Camera.Height + 100 - cKite.z;
          cKite.Walk(Game.Camera.Width + 300, Game.Camera.Height - 200 - cKite.z, eNoBlock, eAnywhere);
        }
      }
    }
  }
  
  // this makes the kite stop as soon as it has left the screen
  if (kite_state == eKiteSwoopingIn && !kite_is_outside_screen()) kite_state = eKiteSwoopingOut;
  if (kite_state == eKiteSwoopingOut && kite_is_outside_screen()) {
    kite_state = eKiteCircling;
    float a = Maths.ArcTan2(IntToFloat(cKite.y - Game.Camera.Height / 2), IntToFloat(cKite.x - Game.Camera.Width / 2));
    kite_region = (FloatToInt(-a * 4.0 / Maths.Pi, eRoundNearest) + 8) % 8;
  }
}
SMF spam blocked by CleanTalk