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
My first paintover in years :)



I somehow saw him as an elf-type guy so went with that.
#342
Thanks to switching to
Spoiler
stare
[close]
as the first word:

Wordle 548 2/6

🟩🟨🟩⬜🟩
🟩🟩🟩🟩🟩

Spoiler
stare
slate
[close]
#343
I'm not offering a solution, just an explanation/comment: you can set a right-click action for every hotspot, object or character.
The default right-click action is "look at" ("talk to" for characters), so the player can simply right-click stuff.
You can even set a dynamic extension, like "open" or "close" for doors, depending on the door's current state.
The default verb is shown to the player by highlighting it while hovering a hotspot.

This is how the 9-verb GUI has worked for the last 30+ years, and this is what players expect when they play a 9-verb GUI game.

If you still want to go ahead with this we can probably come up with a solution.
#344
You can add an item to the inventory multiple times.
Just call player.AddInventory(iRock); in ten places. If a hotspot is exhausted after getting a rock from it, you obviously need to keep track of that; simply disabling the hotspot is one way, using a custom bool/int property is another.

To update the GUI, you can do this:
Code: ags
function on_event(EventType event, int data)
{
  if (event == eEventAddInventory && data == iRock.ID) {
    lblRockCount.Text = String.Format("%d rocks gathered", player.InventoryQuantity[iRock.ID]);
  }
}

Similarly you can check the quantity when interacting with the NPC:
Code: ags
function NPC_UseInv()
{
  // always check item first, to separate its logic from other items
  if (player.ActiveInventory == iRock) {
    int rocks = player.InventoryQuantity[iRock.ID];
    cChar1.Walk(1274, 665, eBlock);
    cChar1.FaceDirection(eDirectionUp);
    if (rocks >= 10) {
      for (int i = 0; i < rocks; i++) player.LoseInventory(iRock); // lose all
      NPC.Say("Congrats, you made it!");
    }
    else NPC.Say("You haven't gathered enough rocks, you need %d more.", 10 - rocks);
  }
  else player.Say("I don't think they're interested in that.");
}
#345
Quote from: eri0o on Fri 02/12/2022 00:36:29you can use alt+shift to select the x and y stuff in the vertical block
That's neat, I didn't know that! :)
#346
It's called .matchCount; I'm using it in the loop at line 170 to find the pixels with the lowest tile matches.
Starting from line 182 I go over all pixels again, putting the ones with the lowest .matchCount into a list. Then I pick a random pixel and populate it with a random tile (i.e. I've ignored the part of the algorithm that tries to maintain the distribution).
I've also just noticed that the ops in lines 195 and 197 are not necessary.
#347
I've edited my post above accordingly. :)
#348
Thanks :)

I'm storing the center pixel and the surrounding eight ones separately, yes. Not to save memory though but simply because they are needed for different purposes. The eight border pixels are checked against the neighboring pixels, the center one I only need when drawing a pixel.

Also yes, I'm reading the source image into a bunch of arrays at the start then never use it again, and each pixel of the output is only set once, so the impact should be minimal.

I'm currently checking all pixels each pass though so ideally there should be a list of blank ones that slowly gets reduced to zero.
#349
I assume this code is inside the after fadein function? If so, add the before fadein function and use the code like this:

This goes inside room_Load (before fadein event function)
Code: ags
  Screen.Viewport.Camera.SetAt(0, 0);

Put this inside room_AfterFadein
Code: ags
  Camera* cam = Screen.Viewport.Camera;
  while (cam.Y < Room.Height - cam.Height)
  {
    cam.SetAt(cam.X, cam.Y + 10);
    Wait(1);
  }
  // reset camera to follow player
  cam.AutoTracking = true;

Edit: fixed code to not use a secondary camera
#350
Thanks :)

Here's the module: https://drive.google.com/file/d/18yazRkEYt8IW9OLML2pDMXfcFoBfGDCe/view?usp=share_link

And an example room script:
Code: ags
// room script file

DrawingSurface* ds;

DynamicSprite* output;

function room_Load()
{
  ds = Room.GetDrawingSurfaceForBackground();
  ds.DrawImage(100 - Game.SpriteWidth[1] - 5, 90 - Game.SpriteHeight[1] / 2, 1);
  ds.Release();
  
  output = DynamicSprite.Create(48, 48);
  
  WFC.Init(1, true, 7);
  WFC.SetOutput(output);
}

bool failed;

function room_RepExec()
{
  if (!failed) {
    failed = WFC.Pass();
    ds = Room.GetDrawingSurfaceForBackground();
    ds.DrawImage(100, 66, output.Graphic);
    ds.Release();
  }
}

void on_key_press(eKeyCode key) {
  if (key == eKeyEscape) {
    QuitGame(0);
    output.Delete();
  }
}
#351
Had to give this a go and ended up with this:



I hardcoded overlapping 3x3 tiles, and you can see there's a few dark gray pixels that didn't resolve. It's also pretty slow, but watching it grow is pretty cool :-D

Not sure I'll publish the code, it's a bit messy. And there's still room for optimization.
#352
Here's one relatively quick way to do this:

Add this to the room script:
Code: ags
function on_mouse_click(MouseButton button) {
  if (player.View == DEATH) ClaimEvent();
}

This will disable all non-GUI (i.e. room) clicks based on the view. ClaimEvent() tells AGS to no longer run the global on_mouse_click function after the room's, effectively disabling all global room click handling.
#353
That was unexpected:

Wordle 527 3/6

⬜⬜🟨⬜🟨
⬜⬜⬜⬜🟨
🟩🟩🟩🟩🟩

Spoiler
ARISE, CLOUT, TEPID
[close]
#354
Without the second parameter AGS will only put the character on the opposite side if the character is within 10 pixels of the room border.
Your hotspot is wider than that so you need something like
Code: ags
  player.ChangeRoomAutoPosition(2, 1050);

Please make sure to always carefully read the manual entries for the commands you use.

The fade to black at the end seems like AGS is looping between rooms 1 and 2, make sure you use the 2nd parameter to position the character outside the area that triggers the room change.


Edit: did a quick test and unfortunately things are going to get a bit more complicated.

1) changing the room and ending up on a region triggers its "walks onto" event, so you really need to make sure to either place the character outside or only change the room conditionally using more elaborate scripting to prevent looping

2) ChangeRoomAutoPosition is buggy apparently, the Tumbleweed template's 2nd room is twice as wide and Roger ended up halfway between the room's center and edge, suggesting that AGS uses the distance from the center to calculate the new position, not the distance from the edge.
#355
Indeed, don't type random words into the event table. Whatever it says next to "Stands on hotspot" (which is the legacy event  I assume you have used) is supposed to match the name of a room script function exactly, to the letter. As such it definitely cannot include spaces, but you're not really supposed to manually type something in there anyway unless you know exactly what you're doing.



So again:
Quoteclear the text field, then click the ellipses button to recreate the function

(also: use a region and its "walks onto" event instead)
#356
The father of the Club Q shooter getting kicked in the balls:


He was also on Intervention and Divorce Court and a porn actor apparently.
#357
Intersecting a quadratic and a linear function is done by equating the y value:

ax² + bx + c = dx + e
ax² + (b-d)x + (c-e) = 0


This way we're back at determining the roots of a quadratic equation.

Once you have the x coordinate, the slope of the quadratic equation is given by the first derivative:

2ax + b

Just insert the intersection point's x coordinate and you have the slope.
The linear equation's slope is d.

The angle between can be determined via the dot product. The slope is the y difference provided we move 1 unit to the right on the x axis, so we can use that to make a vector: the vector is simply (1;s) where s is the slope. We have to normalize this vector by dividing both 1 and s by the square root of s²+1.

Example: the slope is 2, so the vector is (1;2). Its length is the square root of 5, and if we divide both coefficients by that we get a unit vector of (0.4472; 0.8944).

Once we have the vectors x1;y1 and x2;y2 for both slopes, the dot product is x1*x2 + y1*y2. Plug that into Maths.ArcCos() and you have the angle.
#358
If you deleted just the functions in the room script, getting back on track simply means to recreate those.
The rest (script name, description, drawn area, etc.) is stored in the room file and should be untouched.

So instead of starting from scratch, simply select each hotspot in the editor, go to the events panel by clicking the thunderbolt icon, then for each event that has a function name next to it: clear the text field, then click the ellipses button to recreate the function.

Also note that if by screwing up you're referring mostly to mismatched curly braces, note that you can quickly find problems with those by copy-pasting your entire script into the lower left box here: https://jsfiddle.net/ and clicking Tidy in the corner. This will auto-format your script (JS is close enough to AGScript) and immediately show braces issues via bad indentation.
#359
I did a quick test and can easily reproduce this. If the first loop of the view is empty, AGS falls back on sprite #0, then plays sound #0.
The former makes sense, the latter is clearly a bug.
#360
Once you have the DrawingSurface of the background, you can do the same things you can do with any DrawingSurface.
If you want to place a sprite, just draw that (2nd) sprite to the surface at any position.

SMF spam blocked by CleanTalk