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 - Scorpiorus

#1
Quote from: MJL on Sat 25/11/2017 14:16:57Seems to be working well with 3.4.1 ......... in directX mode! Wonderful. Well done Scorpiorus, thank you! And CW for engine update to help it.
Good to know m0ds, thanks for testing it out!

Quote from: Crimson Wizard on Mon 27/11/2017 15:28:32I would like to clarify something: does this plugin check for display mode colour depth or game's native colour depth (in game structure parameters)?
The plugin reads the colour depth value, but it doesn't do anything with it, so it should be fine.

Anyway, feel free to do any adjustments to the engine necessary. In the end, I can always update the plugin to conform with them.
I'm still planning to release the plugin sources at some point :p



One thing that bugs me is that since AGS 3.0.0 the original plugin keeps moving particles when some deep-blocking function, such as Display(), is invoked.
The problem is that the plugin uses the rendering event to both MOVE and DRAW particles.
In pre-3.0 versions of AGS, the engine wasn't redrawing the screen when inside deep inner blocking loop (and hence it didn't call plugin render events).
The plugin uses the IsGamePaused() function to check if it needs to MOVE particles. But now that only works with game-pausing GUIs, etc.
One solution would be to make the AGS engine's IsGamePaused() return 1 when inside Display() and other similar functions. But I can see it's quite a hassle to implement.
From the plugin point of view, I'm not sure if we have a suitable plugin event, from where I could call the MOVE code only (I haven't yet checked it out though).
#2
As for the original question, a simple Wait(...) command should actually work:

Code: ags

function room_Load()
{
    ofondo.SetView(HITITVIEW);
}
 
function room_AfterFadeIn()
{
    ofondo.Animate(0, 1, eOnce, eBlock); // changed to eBlock to wait until the animation finishes!
    Wait(25);
    aintro.Play();
    Wait(120); // wait 120 loops (or around 3 seconds with the default frame rate of 40 fps)
    player.ChangeRoom(20);
}


Otherwise, if it doesn't work, post your exact scripts.
#3
Try enabling Speech.CustomPortraitPlacement and use Speech.PortraitXOffset and Speech.PortraitY to control portrait and speech text positions.

GlobalScript:
Code: ags

function game_start()
{
    Speech.PortraitXOffset = 100;
    Speech.PortraitY = 100;
    Speech.CustomPortraitPlacement = true;
}


Play around with the values to suit your needs.

By the way, this script only works in AGS 3.3.0 or above.
#4
Quote from: Creamy on Sun 10/09/2017 23:56:01You can also enable/disable hotspots.

Yeah, that's a good point. We may actually get a bug where the player can take inventory item multiple times, if the wall object doesn't cover the hotspot properly.

So it's probably a good idea to enable/disable hotspots even with the wall-object-approach. I've updated the codes to reflect this.

Alternatively, we could do an extra check to see if the player has already had that inventory item before adding one.
#5
Not sure why you're making it a hotspot and not an object, but if you want it that way, the logic should probably go as follows:

Code: ags

function hDisco1_AnyClick()
{
    if (MovePlayer(123, 120))
    {
        player.FaceDirection(eDirectionUp);

        if      (UsedAction(eGA_LookAt))
        {
            player.Say("['Nunca me faltes'][Antonio Rios]");
        }
        else if (UsedAction(eGA_PickUp) && !player.HasInventory(iVinyl1))
        {
            if (player.HasInventory(iVinyl2))
            {
                player.Say("Si me llevo los dos se pueden quebrar.");
                oWall1.Visible=true;
                player.Walk(234, 124, eBlock);
                oWall2.Visible=false;
                player.LoseInventory(iVinyl2);
            }

            oWall1.Visible=true;
            player.AddInventory(iVinyl1);
            hDisco1.Enabled = false; // just in case!
            hDisco2.Enabled = true; // just in case!
        }
    }
}


Code: ags

function hDisco2_AnyClick()
{
    if (MovePlayer(234, 124))
    {
        player.FaceDirection(eDirectionUp);

        if      (UsedAction(eGA_LookAt))
        {
            player.Say("[Nunca me faltes][Antonio Rios]");
        }
        else if (UsedAction(eGA_PickUp) && !player.HasInventory(iVinyl2))
        {
            if (player.HasInventory(iVinyl1))
            {
                player.Say("Si me llevo los dos se pueden quebrar.");
                oWall2.Visible=true;
                player.Walk(123, 120, eBlock);
                oWall1.Visible=false;
                player.LoseInventory(iVinyl1);
            }

            oWall2.Visible=true;
            player.AddInventory(iVinyl2);
            hDisco2.Enabled = false; // just in case!
            hDisco1.Enabled = true; // just in case!
        }
    }
}


See if it works.


EDIT: still do consider making it an object instead of hiding background graphics with a "wall" object.
#6
It does work here, but it may have something to do with the length of the option strings and their word wrapping on certain systems. It's just a guess, though.

Anyway, try using DOSBOX with the AGS Engine from AGS 2.4b: https://files.fm/u/bszzww66

And a .BAT file with the following line:
acdos.exe reality.exe

See if runs ok performance-wise, if at all.
#7
You are welcome! :)

Hehe, and yeah I like how it works too.

By the way, I've made a couple of cosmetic changes to Map::SetViewport().
Logically it behaves absolutely identically, just makes the script code to look a bit prettier.
So see if you want to update it (you can simply copy all the ScriptModule Script part over again).

Also, I made DRAG_SPEED_MULTIPLIER a float, so that you can have it set to "1.5" or "0.5", for example.
Just replace that line and two lines below it: int dx = ... and int dy = ....
#8
And here is an example of the script code to help you managing your map:

ScriptModule Header:
Code: AGS

#define Map_GUI              gMap     // Map GUI
#define Map_BKG_BUTTON_ID    0        // ID of the "background" button of the Map GUI

#define Map_MARGIN_TOP       (-10)    // top margin
#define Map_MARGIN_BOTTOM    (-10)    // bottom margin
#define Map_MARGIN_LEFT      (-10)    // left margin
#define Map_MARGIN_RIGHT     (-10)    // right margin

struct Map
{
    import static int GetWidth();
    import static int GetHeight();    
    import static int GetViewportX();
    import static int GetViewportY();
    import static int GetViewportWidth();
    import static int GetViewportHeight();
    import static void SetViewport(int newX, int newY);
};


ScriptModule Script:
Code: AGS

static int Map::GetWidth()
{
    return Map_GUI.Controls[Map_BKG_BUTTON_ID].Width;
}

static int Map::GetHeight()
{
    return Map_GUI.Controls[Map_BKG_BUTTON_ID].Height;
}

static int Map::GetViewportX()
{
    return -Map_GUI.Controls[Map_BKG_BUTTON_ID].X;
}

static int Map::GetViewportY()
{
    return -Map_GUI.Controls[Map_BKG_BUTTON_ID].Y;
}

static int Map::GetViewportWidth()
{
    return Map_GUI.Width;
}

static int Map::GetViewportHeight()
{
    return Map_GUI.Height;
}

static void Map::SetViewport(int newX, int newY)
{
    // just a shortcut for Map_BKG_BUTTON_ID button
    readonly GUIControl *BKG = Map_GUI.Controls[Map_BKG_BUTTON_ID];
    
    // remembering current viewport position
    int x0 = Map.GetViewportX();
    int y0 = Map.GetViewportY();
    
    // translating viewport / "background" button
    BKG.X = -newX;
    BKG.Y = -newY;
    
    // calculating viewport position constraints
    readonly int MIN_X = Map_MARGIN_LEFT;
    readonly int MIN_Y = Map_MARGIN_TOP;
    readonly int MAX_X = Map.GetWidth() - Map.GetViewportWidth() - Map_MARGIN_RIGHT;
    readonly int MAX_Y = Map.GetHeight() - Map.GetViewportHeight() - Map_MARGIN_BOTTOM;

    // applying viewport position constraints
    if (Map.GetViewportX() < MIN_X) // same as if (BKG.X > -MIN_X)
        BKG.X = -MIN_X;
    if (Map.GetViewportX() > MAX_X) // same as if (BKG.X < -MAX_X)
        BKG.X = -MAX_X;
    if (Map.GetViewportY() < MIN_Y) // same as if (BKG.Y > -MIN_Y)
        BKG.Y = -MIN_Y;
    if (Map.GetViewportY() > MAX_Y) // same as if (BKG.Y < -MAX_Y)
        BKG.Y = -MAX_Y;
    
    // calculating deltas for other GUI controls
    int dx = x0 - Map.GetViewportX();
    int dy = y0 - Map.GetViewportY();
    
    // translating other GUI controls (ie. all except the "background" button)
    for (int i=0; i < Map_GUI.ControlCount; i++)
    {
        if (i==Map_BKG_BUTTON_ID)
            continue;
        Map_GUI.Controls[i].X += dx;
        Map_GUI.Controls[i].Y += dy;
    }
}


GlobalScript:
Code: AGS

int mouse_px = -1; // previous mouse x
int mouse_py = -1; // previous mouse y

function repeatedly_execute( )
{
    if (mouse.IsButtonDown(eMouseLeft) && (mouse_px!=-1) && (mouse_py!=-1))
    {
        readonly float DRAG_SPEED_MULTIPLIER = 1.0;
        int dx = FloatToInt( IntToFloat(mouse.x - mouse_px) * DRAG_SPEED_MULTIPLIER );
        int dy = FloatToInt( IntToFloat(mouse.y - mouse_py) * DRAG_SPEED_MULTIPLIER );
        Map.SetViewport(Map.GetViewportX()-dx, Map.GetViewportY()-dy);
    }
    
    mouse_px = mouse.x;
    mouse_py = mouse.y;
}


You can use Map.XXX functions to control your map viewport position.

Setting the DRAG_SPEED_MULTIPLIER thing to "2.0" will make it twice faster to scroll/pan the map.

These "defines" specify corresponding margins. You may want to set them all to 0, if you like.
Code: ags

#define Map_MARGIN_TOP       (-10)     // top margin
#define Map_MARGIN_BOTTOM    (-10)     // bottom margin
#define Map_MARGIN_LEFT      (-10)     // left margin
#define Map_MARGIN_RIGHT     (-10)     // right margin


See if it works, and let us know how it goes.


(EDIT: cosmetic changes to SetViewport() to make it easier to read the script code, and made DRAG_SPEED_MULTIPLIER a float)
#9
Good point guys, I've just tested it out and the trick with faking mouse clicks seems to work!
But yeah, it should be tested carefully to see if there is an unexpected behaviour under certain conditions, as Crimson Wizard says.

The following script should work:

Code: AGS

bool gNeedRestoreSkipSpeechStyle = false;
SkipSpeechStyle gSavedSkipSpeechStyle;

function repeatedly_execute_always()
{
    if (NEED_TO_SKIP_SPEECH)
    {
        gSavedSkipSpeechStyle = Speech.SkipStyle; // save current SkipStyle value
        Speech.SkipStyle = eSkipMouse;            // force it to eSkipMouse, in case it was eSkipTime-ONLY or something
        Mouse.Click(eMouseLeft);                  // request doing a fake mouse click
        gNeedRestoreSkipSpeechStyle = true;       // set a flag to restore the original SkipStyle value later
    }
}

function late_repeatedly_execute_always()
{
    if (gNeedRestoreSkipSpeechStyle == true)
    {
        gNeedRestoreSkipSpeechStyle = false;
        Speech.SkipStyle = gSavedSkipSpeechStyle;   // restoring original value (<--- CAN CRASH THE GAME AT THE MOMENT)
    }
}


But it doesn't, if the Speech.SkipStyle is set to TimerOnly in the General Settings. Then this script crashes...

It appears there is a bug in the AGS engine, where it doesn't correctly return eSkipTime value:

https://github.com/adventuregamestudio/ags/blob/release-3.4.0/Engine/ac/speech.cpp#L47

It returns "-1" (aka kSkipSpeechUndefined) instead of eSkipTime(2).

It should probably be fixed with:
Code: cpp

...
    if (internal_val & SKIP_AUTOTIMER)
    {
        internal_val &= ~SKIP_AUTOTIMER;
        if (internal_val == (SKIP_KEYPRESS | SKIP_MOUSECLICK))
        {
            return kSkipSpeechKeyMouseTime;
        }
        else if (internal_val == SKIP_KEYPRESS)
        {
            return kSkipSpeechKeyTime;
        }
        else if (internal_val == SKIP_MOUSECLICK)
        {
            return kSkipSpeechMouseTime;
        }
        else if (internal_val == 0x00000000) // <--- FIX (EDIT: better explicitly compare with 0 instead of having vague "else", just in case!)
        {
            return kSkipSpeechTime;
        }
    }
...


Radiant, we can consider your post as an indirect bug report actually.
But, if possible, do use this approach with fake mouse click instead of the one I proposed before. :)
#10
I don't think there is an official way to skip the currently displayed text speech programmatically, if that's what you are after.
#11
No problem, I'm glad you got it fixed!

But be sure to back up your project regularly -- you don't always known what may happen on the next day :smiley:
#12
Yeah, surprisingly it works pretty well, even if implemented with basic scripting.
And it's a good starting point to add extra functionality like, for instance, a map scalling/zooming feature, as you suggest.

The GUI editing may not always be convenient, depending on the desktop resolution, since we don't have scrollbars in the GUI editor. But overall, it's quite manageable, I think.
And the "background" button can always be Locked, so that we don't accidentally move it, adjusting other buttons/labels, etc...

It may actually be a good candidate for a script-module/template/exported-GUI thing.
I see if I can pull out a script module or something out of that quick mock-up I made...


EDIT:
Some time ago I worked on a script equivalent to the snow/rain plugin to assist portability and it was one of the main problems in terms of how render snow flakes at different screen depth levels. Probably, GUI controls may work well as a complementary solution to other standard methods. It needs further testing, though...
#13
I would suggest copying everything you can to folder "C:\MyAgsGames". (Don't worry about the _Debug folder, you don't need it to rebuild your game!)
Next, run AGS, select the second option (Continue an existing game) and click [Continue >] button.
From there, find your game project at "C:\MyAgsGames" and open it in AGS.
Finally, rebuild your game EXE.

See if it works.
#15
Do you use this Microsoft service https://en.wikipedia.org/wiki/OneDrive?

Can you at least try copying (not moving) your game project folder somewhere else? (note that you don't need to copy the _Debug folder)

EDIT: Also, make sure your Antivirus software doesn't block it somehow!
#16
I think with dynamic sprites approach you have to redraw the whole composition from scratch each time the map is moved or animated.
You can probably prepare a huge map sprite and show a portion of it through a map viewport by repeatedly creating an instant cropped map-viewport-area-sized sprite from the map sprite, but it won't allow animating things on the map then.

However, wouldn't simply moving/translating all GUI controls (buttons) around give you a similar effect?

Basic code in the GlobalScript:
Code: AGS

int mouse_px = -1; // previous mouse x
int mouse_py = -1; // previous mouse y

void repeatedly_execute( )
{
    if (mouse.IsButtonDown(eMouseLeft) && (mouse_px!=-1) && (mouse_py!=-1))
    {
        int dx = mouse.x - mouse_px;
        int dy = mouse.y - mouse_py;
        for (int i=0; i < gMapDyna.ControlCount; i++)
        {
            gMapDyna.Controls[i].X += dx;
            gMapDyna.Controls[i].Y += dy;
        }
    }
    
    mouse_px = mouse.x;
    mouse_py = mouse.y;
}


The good thing with buttons is that they are already interact-able.
Also, try using a large button as your map background.
#17
Ah yeah, it seems like using DOSBOX may not always work out of the box :p to run AGS games compiled for DOS operating system.

The thing is, the DOS version of the AGS Engine was pretty harsh on DOS PC hardware specs, where it could easily require 16 Mbytes of system RAM or even more (especially for 15/16-bit "Hi-Color" games). The AGS' DOS engine uses a so-called DOS extender (in the case of AGS it's "CWSDPMI.EXE") to have more memory addresses available to use. However, having more memory addresses accessible doesn't always mean that PC had, in fact, so much memory. For that reason, a DOS extender can use a well-known method of unloading portions of RAM data to hard drive to free up system memory, using a swap file for this.

By default, the "CWSDPMI.EXE" DOS extender tries to create its swap file "CWSDPMI.SWP" in the root directory of DOS drive. In DOSBOX this is the folder which you mount with DOSBOX' "mount" command (eg: "mount C F:\DOSGAMES"). If for some reason you have a mounted folder with restricted write-access by Windows (eg: "mount C C:\" or anything else with normally denied write-access), the DOS extender won't be able to create "CWSDPMI.SWP" file there, but it won't crash immediately. Instead, it will continue running the program up to the moment where it requires more memory than available to extender. At this point, as there is no swap file available, the program terminates with appropriate (or not so) error message.

For DOS-compiled AGS games I would recommend setting up more "hardware" RAM in DOSBOX config file. For DOSBOX 0.74 it's in "file dosbox-0.74.conf" >> section [dosbox] >> parameter "memsize". By default, it's something like 16 MBytes. I'd set it to 31 as a recommended maximum for DOS programs. A practical maximum would be 63 Mbytes (as DOSBOX suggests), but some DOS games (not necessary AGS games) may kinda get confused by having so much memory available and may not work well, if at all.

Raising DOSBOX' "memsize" can potentially speed up AGS games running there, since then they'd use a swap file less frequently. Otherwise, DOSBOX has to fully emulate swap-file access which can be really slow. For instance, with ridiculously low "memsize" values (1-4 Mbytes) but with a swap file still available, an AGS game can take up to several minutes to actually show you its first screen.

Another thing to conserve DOSBOX "virtual hardware" memory would be running AGS games at their native resolutions and don't try to scale it up in the game setup program. Because running at 960x600 instead of native 320x200 would actually use 9 times more memory. Instead, use DOSBOX' "dosbox-0.74.conf" >> [render] >> scaler parameter, setting it as scaler=normal2x or scaler=normal3x, for example, if you want to have a larger game window.

Still, for AGS games running in DOSBOX, make sure your DOSBOX environment's root directory has a full read/write access, so that AGS games would work properly, swapping their data back and forth as they want.

By the way, you can drag and drop your DOS game's EXE icon over the DOSBOX icon, to start the game. In this case your game folder will become DOSBOX's root directory (EDIT: unless some other folder has already been mounted via DOSBOX config). And you should normally have read/write access to your game folder. If not, an AGS game will crash immediately, because it won't be able to write a "restart point" save game (aka "agssave.999").
#18
This version of ROTN: Nightwatch should work via DOSBOX at least:

https://files.fm/u/vqqdabqr (EDIT: link updated)
#19
Also, with a map-GUI you don't lose the current room context, so to say.

For example, if the player interacts with something in the current room, you can just have your map-GUI reflecting it by simply enabling a corresponding GUI control element (like a button or a label) immediately. With a separate room for the map, you cannot update it instantly and you have to set up some global flags or something to apply them afterwards when the map room is actually loaded.

On the other hand, a room is a good choice if you want your player character to actually walk around the map, respecting walkable areas, interacting with other characters and objects there and so on. You cannot use AGS pathfinder/walkables with the GUI-as-map approach.

Another good thing with rooms -- for games with a higher screen resolution (say, 640x480 and greater), you can have a smooth map-room scrolling by using an invisible current player character moving in the direction, you want your map viewport to scroll in.
#20
I think I can fix that Nightwatch's crash at the start of the game. It's just a simple bug in script code resulting in game memory corruption.

It should then be runnable in DOSBOX at least (since it was compiled with the DOS AGS engine).

The main issue is whether we should make the authors informed somehow before tinkering with their game... :tongue:

And let them fix the thing instead?
SMF spam blocked by CleanTalk