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

#341
Quote from: Snarky on Sat 18/05/2024 19:58:41
Quote from: zeta_san on Sat 18/05/2024 19:27:24it works but Crimson's works everywhere with all characters while Chris's only works when the character (player) speaks.

That is surprising. It should not be the case.

This sounded like an engine bug at first, so I tested my code. Turns out .Speaking is only true if the character has a SpeechView assigned. I guess I can see the reasoning behind that but it should also be true while they're the subject of a .Say() call imo.

Also, to clarify: zeta_san is not talking about the mouse cursor but the action text, which by default appears above the cursor even while the interface is disabled. Which in turn could be considered a bug in the template I guess, since the action text shouldn't be displayed while the player cannot actually perform an action.
#342
In that code, line 46 contains the command that's supposed to write the savegame file to the hard disk. You can easily debug this by simply inserting a line like Display("About to save to slot %d", gameSlotToSaveInto);

Does the message appear in game? Which slot does it show? Etc.

This is very basic debugging and absolutely something everybody should do first.
#343
Was bored so I made a basic Myst template:

https://drive.google.com/file/d/1-ApTmCF5vGZVwS9I0xtmZVGSL_stHcGA/view?usp=drive_link

Edit: Google seems to think the template contains malicious content (roll), so here's also a mega link:
https://mega.nz/file/lIo1hTJT#DH-OmahyGUc8RZlArhGUbGbEwSTR4waFedlT3lPbmIM



Basic inventory and four directional cursors for exits.
In an exit hotspot's custom properties, set "Exit" to true, then set a direction and room number.

Edit: using Regions for the exits makes more sense I guess since there's no walking anyway. Will edit soon and put playable version online.
Edit2: right, nevermind, Regions don't have custom properties :P
#344
These lines are all setup lines, with the exception of the first (I guess). They are supposed to go into room_Load, not room_RepExec, because they only need to be called once, not 40 times per second.

The animation didn't work because you were resetting the cursor to the animated one during every game loop, i.e. also 40 times per second. Each time you do that, AGS wants to start the animation, then 0.025 seconds later you tell it again to start the animation. It never has the chance to actually play it to its second frame.
#345
This sounds like you still have code elsewhere that resets the cursor. My own code only changes the cursor back when you move the mouse off the hotspot. Maybe check the room_RepExec?
#346
Yeah, the line is supposed to be outside any function. I always indent my lines correctly so you can just copy-paste them.

My code should do all the work on its own; a basic way to test it is to add a Display("changing mode"); line inside the first if-block.
#347
This is not really advanced in any sense. If you got an error message, please tell us the exact message and the line it is pointing to. It's probably the cursor mode, which is called "eModeLookat" with a lowercase "a".

(Also, when code I post is supposed to go into the header, it usually says so in or above the relevant part.)

Other people might be reading this and wanting to use the code I posted, but I can't fix it because I haven't set up a panorama game, and I'm way too lazy to do that just to fix a basic typo.
Don't be afraid to do some very basic debugging.
#348
@InfernalGrape

This requires tracking the state, otherwise you will set the graphic 40 times per second and thus the animation never has a chance to run.

Code: ags
// above repeatedly_execute
LocationType prevLT;

  // inside repeatedly_execute
  int x = Panorama.GetBackgroundXForMouseX(mouse.x);
  int y = Panorama.GetBackgroundYForMouseXY(mouse.x, mouse.y);
  int lt = GetLocationType(x, y);

  if (lt != eLocationNothing && prevLT == eLocationNothing) {
    // mouse moved over active area
    mouse.UseModeGraphic(eModePntrAni);
  }
  else if (lt == eLocationNothing && prevLT != eLocationNothing) {
    // mouse moved outside active area
    mouse.UseModeGraphic(eModeLookAt);
  }
  prevLT = lt;
#349
Quote from: FortressCaulfield on Mon 13/05/2024 01:17:32For the first item, it was more a stylistic question as to whether it's normal to have a whole pile of bools and ints in global for trackers and stuff.

As opposed to what though? Are you talking about organizing them like Snarky mentioned?
If so, there is another way you could use (although I personally wouldn't): characters and other entities can have custom properties of various types. So for organizational purposes you could create some of these and use something like
Code: ags
  player.SetProperty("tasks_achieved", player.GetProperty("tasks_achieved") + 1);

This has no advantage though, and is a lot less smooth than
Code: ags
  tasks_achieved++;
#350
Regarding question #1, you can use the "enters screen before fadein" event / room_Load function for this; no need for a region.

Also, if you change a room's number to 300 or above, it doesn't save its state when you leave it.
#351
import lines are supposed to go into the header; they also require the type.

Like this:

Code: ags
// header
struct AudioChannels {
  AudioChannel* Keyboard;
};

import AudioChannels ac;

// main script

AudioChannels ac;
export ac;

You can know use a line like this in a room script:
Code: ags
  // inside some function
  ac.Keyboard = aKeyboard.Play();
#352
It is definitely doable.

A health bar for instance can be implemented using a button on a GUI. Use the GUI's outline or background color as border, put a non-clickable button on it with a suitable image (just a green sprite for instance) and resize it according to the health points i.e. set the button's .Width to a new value.

Randomizing stuff is very simple:
Code: ags
  int result = Random(10); // 0 - 10
  result = Random(9) + 1; // 1 - 10

You also need variables to store each character's HP. At the top of the global script, add lines for each variable you need:
Code: ags
int playerHP = 100;
int enemyHP = 50;

Next I'd use a battle function:
Code: ags
function Battle(Character* enemy, int initialHP) {

  enemyHP = initialHP; // set enemyHP

  int damage; // local variable

  // keep the fight going until either character dies
  while (playerHP > 0 && enemyHP > 0) {
    // player turn
    // player's attack animation goes here
    if (Random(99) < 30) { // 30% chance
      damage = Random(9) + 1;
      enemyHP -= damage; // enemy loses HP
      // enemy gets hit animation here
      if (enemyHP < 0) enemyHP = 0; // no negative values
      btnEnemyHP.Width = enemyHP * 2; // update enemy health bar
      Wait(1); // ensure the screen updates, can possibly be skipped
      if (enemyHP == 0) Display("You stab %s for %d damage, killing them.", enemy.Name, damage);
      else Display("You stab %s for %d damage.", enemy.Name, damage);
    }
    else Display("You stab at %s but miss.", enemy.Name);
    if (enemyHP == 0) break; // leave while loop if enemy is dead
    // enemy turn goes here
  }
}

Now you can do the character interaction as usual:
Code: ags
function cGoblin_Interact(...) {
  // make player approach enemy here
  Battle(cGoblin, 50); // battle the goblin, give them 50 HP
}

The important thing here is that you don't just blindly copy this to your script and expect it to work; you need to look at the code, understand what each line does and study the explanation of the used commands in the manual.
You can also ask here, but learning how to program takes a while, and isn't really what this forum is for.
#353
I went ahead and wrote a small credits module:
https://drive.google.com/file/d/1-1C-yqWM86pjfXGUwKDhTYol-aKuBYKV/view?usp=sharing

My approach was to give maximum control to the developer, so I made it non-blocking and only return a sprite.
Which means in order to use it, you need a bunch of code.

Here's an example room script showing all its features:
https://drive.google.com/file/d/1-3u8aMBTZnc3HMR1nxXSMyfKdDRkaQfh/view

And what it looks like in-game:
#354
Disregarding that this code can be shortened greatly, this creates a blocking walk and doesn't support changing the loop mid-walk in case the character has to round a corner.

This should achieve the same thing in theory, I didn't test it:
Code: ags
function MovePlayerToMouse()
{
  int targetx = Game.Camera.X + mouse.x; // in case of scrolling room, add camera offset
  int targety = Game.Camera.Y + mouse.y;
  int dx = targetx - cRoger.x;
  int dy = targety - cRoger.y;
  int loop = (dy < 0) * 2 + (dx < 0); // true/false is forced to 1/0 in integer expression
  cRoger.LockView(cRoger.NormalView);
  cRoger.Animate(loop, 1, eRepeat, eNoBlock);
  cRoger.Move(targetx, targety, eBlock);
  cRoger.UnlockView();
}
I skipped over orthogonal keeping of the loop because it not really noticeable in-game anyway.
The blocking loop is gone because you can make the movement blocking.
#355
Press F7 in AGSEditor to generate a fresh build. Look inside the Compiled folder and you'll find a Windows folder. In there is the game's exe, winsetup.exe and all required resources.

You can now rename the Windows folder to the name of your game, then right-click it and add it to a new zip folder. Share the zip file, it contains everything people need to run your game on Windows.
#356
@celadonk Could you post the solution / relevant code so others who find this thread in the future can implement it, too?
#357
Like @Snarky said, arctan2(dy, dx) of the current movement returns an angle in the range of -Pi to Pi, which one can turn into a loop number relatively easily.
To shift the angle away from 45°, one only needs to multiply dy by a factor of 0.9 or 1.1 for instance before calculating the arctan.

Customizing this behavior means we can provide the engine with a custom function that accepts dx and dy and returns the loop number.
Alternatively, let the user do it via a command like Character.SetLoop(int loop_number, int from_angle, int to_angle).


Without a change to the engine, overriding the loop is possible by using an invisible player character and having a second character mirror its coordinates, view, loop and frame. Now you can freely set the loop to whatever you want.
The downside is that there's no way to reliably access the character's current movement vector, so we'd have to track their position every few frames to infer it.
#358
You can turn options on or off from inside the dialog script, and you can switch to another dialog.

Sorry, but all this is explained in the relevant section of the manual. Please make sure you exhaust all available resources before asking here.
#359
Do NOT use ChatGPT for this.

I explained how here:
https://www.adventuregamestudio.co.uk/forums/beginners-technical-questions/resize-player-character/msg636662736/#msg636662736

Just typing out the function is not enough, it needs to be linked to the event.

This is also explained here:
https://adventuregamestudio.github.io/ags-manual/acintro3.html

And judging from the rest of your room script, you've already done this.
#360
I just noticed that when somebody quotes me and Windows shows me a notification in the bottom right corner, clicking the notification takes me to the AGS homepage, not the forums or the thread.
SMF spam blocked by CleanTalk