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 - Crimson Wizard

#861
To complement and elaborate on what Khris said.

Excessive code, especially duplicating code, is often a source of mistakes.

If you are working with numbered sequential objects, usually this may be done using a loop over array.
For example:
Code: ags
hH2.Enabled=true;
for (int i = hH3.ID; i <= hH11.ID; i++)
  hotspot[i].Enabled = false;
This will disable all hotspots between H3 and H11 (inclusive).

Another example:
Code: ags
for (int i = iTrinket2.ID; i <= iTrinket12.ID; i++)
  player.AddInventory(inventory[i]);
Above will add any inventory item with IDs in range from iTrinket2 to iTrinket12 (inclusive).



Similar solution may be used if you need to set state of some objects depending on other objects. If these objects are arranged in two corresponding sequences (like 10 hotspots and 10 objects, corresponding to each other) - in such case you may use relative index. For example, you have this:
Code: ags
if (oP2.Visible==true) hH2.Enabled=false;
if (oP3.Visible==true) hH3.Enabled=false;
if (oP4.Visible==true) hH4.Enabled=false;
...
This may be redone simply as:
Code: ags
for (int i = 0; i < 10; i++)
{
  if (object[oP2.ID + i].Visible==true) hotspot[hH2.ID + i].Enabled=false;
}



Then if you have an identical or almost identical block of commands repeating in a program, then this block may be moved to its own function. The differences can be solved by passing parameter(s) into this function.

For a basic example, you have a similar code repeated multiple times, depending on the clicked object:
Code: ags
function oT2_Interact()
{
mouse.EnableMode(eModeUseinv);
player.ActiveInventory=iTrinket2;
mouse.Mode=eModeUseinv;
oT2.Visible=false;
}
This may be done as a separate function
Code: ags
function InteractWithTrinketObject(Object* obj)
{
  int relativeObjID = obj.ID - oT2.ID; // relative index, starting with the oT2
  mouse.EnableMode(eModeUseinv);
  // it is possible to calculate matching inventory item's ID from object's ID,
  // because they have 2 corresponding sequences
  player.ActiveInventory=inventory[iTrinket2.ID + relativeObjID];
  mouse.Mode=eModeUseinv;
  obj.Visible=false;
}
And then called like
Code: ags
function oT2_Interact()
{
  InteractWithTrinketObject(oT2);
}
function oT3_Interact()
{
  InteractWithTrinketObject(oT3);
}
// and so on

This ensures that each similar operation is performed in a uniform way.
#862
Here you go, this is from Tumbleweed template, VerbGUI.asc:

Code: ags
if (InventoryItem.GetAtScreenXY(verbsData.guiMain.X + invMain.X + 1, verbsData.guiMain.Y + invMain.Y + 1) == null)
  invMain.TopItem -= invMain.ItemsPerRow;

This checks if there's any item found under certain coordinates on screen, and if not, then scrolls it one row up.

This seems like a nasty way to do whatever it was intended for...
not only inventory window may be invisible, but also this breaks if any GUI covers the inventory window.

EDIT:
should not this be simply
Code: ags
if (invMain.TopItem >= invMain.ItemCount)
  invMain.TopItem -= invMain.ItemsPerRow;
?
#863
Quote from: DrLilo on Tue 12/11/2024 10:55:04Hi guys. I'm using the default Inventory window from Tumbleweed, but I find that if I make gMain.Visible false and then true later, the inventory automatically returns to the first row.

That's very unexpected, I do not think this is supposed to happen at all. There are other UI styles, where inventory window is on a popping-down bar, for example, and GUI becomes visible and invisible whenever player moves the mouse. If the inventory would reset position every time, it would become unusable.
InventoryWindow.TopItem is a logical state of the control, like size, text or color, that should not have any connection to gui visibility.

Something is off here.

EDIT:
I just quickly tested 2 templates, filling with random inventory items, and scrolling, then toggling inventory window invisible,
in BASS template the inventory position stays
in Tumbleweed it is reset.
#864
Quote from: Cmdr on Mon 11/11/2024 21:51:12I found a solution with Viewport.ScreenToRoomPoint:

Oh right, that's a more generic way of doing this.

You can also keep the old way by adding Game.Camera.X (instead of GetViewportX).
ScreenToRoomPoint has a benefit that it also handles scaling (if you zoom camera in or out).

Please note that if you do not pass "true" to the last argument (restrictToViewport or clipViewport, depending on a function), then you dont have to test the return value for null, as if the coordinates are never "clipped by viewport", and returned Point is always valid.
#865
There's the list of obsolete functions and their replacements in the manual:
https://adventuregamestudio.github.io/ags-manual/ObsoleteScriptAPI.html

Even if you find GetViewportX, it will mention the replacement:
https://adventuregamestudio.github.io/ags-manual/Globalfunctions_Room.html#getviewportx
#866
Quote from: MoonBird on Sat 09/11/2024 17:02:44One more oddity found: While using the acwin.exe in game named "The Goat Crone" (version 1.0.2) you cannot exit from the recipe book once you open it. Through normal exe-file the recipe book works fine.

Could you please either give a link to the walkthrough, or, even better, a saved game made prior to the problem?
I never played the game, and I don't know how long would it take to get to the spot in order to test this.

Quote from: MoonBird on Mon 11/11/2024 20:04:41Also some games have freezing or crashes with cutscenes. Some games do not work with acwin.exe at all.

Which games?... at least an example, please?
#867
So, what was happening, because of a mistake in the engine, when switching cursors the engine was copying item cursor image over other cursor images so long as they have matching format (size and color depth).

Here's a temporary build with a fix, may be downloaded and used:
https://cirrus-ci.com/task/4569629144645632

This fix will be included into the next 3.6.1 patch.
#868
Yes, I can confirm this happening, and also if I export a single cursor sprite from the "broken" version and import to the "working" version, and set as "interact" cursor, then that cursor gets broken too.

At this point I begin to suspect a engine's bug...

EDIT: another thing I noticed is that this bug happens after you cycle cursors with the right mouse button. And it only seems to happen to cursor modes adjancent to "use inv".

EDIT2: Indeed , this happens only in Direct3D/OpenGL graphic drivers, but not Software driver. Which means this is related to the texture cache again.

I still do not understand how is this related to the sprite's size though.
Okay, I think i found the mistake.
#869
Quote from: BeardFacePixelHead on Mon 11/11/2024 15:12:22If you want to mess with it, here are the files. This is the working version with the new, larger sized cursor sprites. The cursor sprites that didn't work properly were sized 16x16.

Well, we meant the project that does not work, as even if we try to replicate the problem, we might do something different from what you did.

I tried, importing a 16x16 sprite, and set it as a walk cursor. Nothing bad happened so far as I can see. I can still select items, and then switch to "walk" cursor, and it displays a "walk" image.
#870
Hmm, I don't see anything wrong...
maybe somebody else will have ideas.
#871
Quote from: BeardFacePixelHead on Sun 10/11/2024 23:58:35Where I'm running into an issue is selecting an inventory item seems to hijack my mouse cursor. Once an inventory item is chosen, walk and interact become the inventory item cursor, even though they work correctly as walk and interact. Strangely it doesn't seem to affect the talk and examine cursors.

That's ... not expected. Do you use "Mouse.ChangeModeGraphic" or "Mouse.UseModeGraphic" anywhere in your code?

I think it would be easier to tell if you'd show all the script relevant to mouse controls in your game.
#872
I did not have time to test my code earlier.

But then I remembered that the script compiler in AGS 3.* has a bug that prevents it from correctly parsing an access to dynamic array in struct, if that struct is also inside a regular array (that is the second case in my previous post).
For that reason compiler throws an error:
> Cannot declare an array of a type containing dynamic array(s)

That is very unfortunate and annoying. We added this as a temporary measure to prevent other bugs, but they were never fixed in the old compiler.
History of this problem:
https://github.com/adventuregamestudio/ags/issues/338

The new compiler in AGS 4 does not have such problems, it may currently have any combination of nested structs and arrays.

I might try look into this problem in v3 compiler, but it's not written well (bad program code), so if it's going to be difficult to fix, then I doubt it's worth spending time on, while there's already a much better v4 script compiler.

Overall I would recommend trying AGS 4. It's marked as "alpha", as it is still in development, but should be relatively stable.
#873
The article in the manual about dynamic arrays:
https://adventuregamestudio.github.io/ags-manual/DynamicArrays.html

Dynamic arrays in a regular struct will be declared like this:
Code: ags
struct Journey {
    Character *walker;
    bool walking;
    int steps;
    int step_x[];
    int step_y[];
    int step_room[];
};

and then created like this:
Code: ags
Journey j; // assume we have Journey variable created somewhere
j.steps = 10;
j.step_x = new int[j.steps];
j.step_y = new int[j.steps];
j.step_room = new int[j.steps];

or, in case there's a array of Journeys:
Code: ags
Journey j[100]; // array of 100 journeys
// init the 20th journey
j[20].steps = 10;
j[20].step_x = new int[j[20].steps];
j[20].step_y = new int[j[20].steps];
j[20].step_room = new int[j[20].steps];




As for having managed pointers within managed structs, in order to create linked lists and similar,
that's not possible in AGS 3.*, but is possible in AGS 4, which has an extended script compiler which supports more syntax features and nested managed pointers.
https://www.adventuregamestudio.co.uk/forums/ags-engine-editor-releases/ags-4-0-early-alpha-for-public-test/

#874
Quote from: Ghostlady on Sat 09/11/2024 03:42:59Does this mean each separate line will need the Append?

Not line of text itself, as you see it when it's printed in game, but a line in script...

I mean a situation when you need to type a very long text, it will go too far to the right in a script editor, so you'd like to wrap it to the second line in script.
All of these lines will be glued into a seamless text using String.Append.

As for how it will look in game, labels wrap the text automatically within their width.
Additionally, you may have manual linebreaks using "\n" character combination:

Code: ags
SomeLabel.Text = "This is first line.\nThis is second line";


I suggest doing several experiments, it's easier to see and understand how it works in practice.
#875
Quote from: Ghostlady on Sat 09/11/2024 03:33:15I did start looking at that.  Do I have to type it all in or can I copy from a word doc?

You can copy/paste a text into the label's "Text" field.

If that's not convenient, or if you need to change label's text at runtime, then you may assign the label's text in script too:
Code: ags
SomeLabel.Text = "some text";

AGS script has a weird problem that it does not support breaking of a string onto multiple lines in a script file,
but there's a workaround for very long texts, is to use String.Append function like this:
Code: ags
String s = "first part of text";
s = s.Append("second part of text"); // this will concatenate previous and new text
s = s.Append("third part of text");
<...>
SomeLabel.Text = s; // this will assign full concatenated text to a label
#876
The most natural choice for having a text on GUI is Label control, is there any reason why you cannot use it?
#877
Quote from: DrLilo on Fri 08/11/2024 19:50:18I wonder if anyone has an answer to my initial thought, is there a way to remotely trigger a cycle of the current Room's repeatedly_execute function

No.

You may call a particular script function from another script function, but that will not solve your problem, as you got to call it from some event too, and that event likely will occur after the blocking action has finished and the screen has already redrawn once. (and if you call it from functions like repeatedly_execute_always, then no new blocking actions cannot be run)
#878
Quote from: RootBound on Fri 08/11/2024 19:17:13I click one of the default fonts from the blank template and select "import over this font" and then select a new font and import it.

I had a moment of confusion. I've been thinking of a new fonts system in AGS 4, where "import over font" command no longer exists.

Okay, I will test this in 3.6.2.
#879
Quote from: DrLilo on Fri 08/11/2024 19:03:34I'm doing nothing special, it's the default behaviour of Tumbleweed to hide gMain whenever there's dialogue or anything with eBlock, such as player.Walk. I'm not sure whatever they're doing to hide gMain is exposed, I can't find any isntances of EnableInterface in VerbGUI.asc for example...

Well, that's the first thing to begin with: you need to clarify how it's done in your game, then it will be easier to say if you can accommodate that behavior for what you want, or it's better to scrap that and script your own custom solution.
#880
Hm, could you clarify how do you make GUIs invisible during blocking actions, are you using a setting "When interface is disabled GUI should -- Be hidden", or script this GUI hide/show yourself?

In regards to the whole thing, it looks like you need a way to mark a "blocking state" by hand, to be able to unmark it 1 non-blocked cycle later.

There's a group of functions: EnableInterface, DisableInterface, IsInterfaceEnabled, and my impression is that this "disabled" state works as a counter (similar to PauseGame/UnpauseGame). Any blocking action increments this counter on start and decrements when ends, but so does any manual call to EnableInterface and DisableInterface correspondingly.

So, as theoretical possibility, you could call DisableInterface() before running first part of the cutscene, then inside "repeatedly_execute", where you don't need to run a second part of the cutscene, check IsInterfaceEnabled  and call EnableInterface() if it is. This would enable GUI right after "repeatedly_execute" is run first time.

EDIT: I also have a guess that you might be able to automate this by checking "game.disabled_user_interface" variable in "repeatedly_execute_always", and if it's only 1, then either increasing it by hand +1 or calling DisableInterface, to make it 2.

Maybe you will need extra variable to be able to tell if you just wanted to disable gui while no blocking action is played, but I don't know if you ever do.

EDIT2: If you do not use this setting, but your own custom code, then you could probably replicate the above solution using your own functions and variables.
SMF spam blocked by CleanTalk