Resizing InventoryItem.CursorGraphic Sprite

Started by hocuspocus2, Thu 24/12/2020 01:56:59

Previous topic - Next topic

hocuspocus2

I have "Use selected inventory graphic for cursor" to true. What I want to happen is that the item's cursor graphic would be scaled down so it looks smaller than its graphic in the inventory bar, but they're still essentially the same sprite/image. In my case, each item's sprite is 100 x 100, and I want its cursor graphic to be scaled by half, so 50 x 50 (might change my mind and make that bigger though, like 70 x 70).
I know I can probably redraw each item as smaller, then set that as its cursor graphic in the editor's inventory item menu. But I feel like that would take too much space and time when I can just globally script the scaling. I tried using DynamicSprite* and Overlay*, but I think they're too complicated for me. I just kept getting errors, and I kinda didn't know what I was doing.


Crimson Wizard

#1
You cannot scale cursor graphic in AGS at the moment, which is a shame.
DynamicSprite is one way to do this, and if you worry of the impact on the RAM you could keep only 1 scaled sprite at a time and replace it with a new one when ActiveInventory changes. That would demand a bit of extra scripting ofcourse.

The overall idea is this:
* make a function, like, SetActiveInventory to be called instead of using player.ActiveInventory directly in your game script.
* declare a global DynamicSprite* pointer for holding current item's cursor graphic.
* function SetActiveInventory clears previous sprite and creates new one, scaling down item's image, and assigns this dynamic sprite to inventory item's CursorGraphic property.

Code example:
Code: ags

DynamicSprite* ActiveItemCG;

void SetActiveInventory(InventoryItem* item) {
    int cg = item.Graphic;
    int w = Game.SpriteWidth[cg];
    int h = Game.SpriteHeight[cg];
    int new_w = w / 2;
    int new_h = h / 2;

    if (ActiveItemCG != null)
         ActiveItemCG.Delete();
    ActiveItemCG = DynamicSprite.Create(new_w, new_h, true); // NOTE: last parameter means alpha channel, if your sprite have them use "true", if they don't then set "false"
    DrawingSurface* ds = ActiveItemCG.GetDrawingSurface();
    ds.DrawImage(0, 0, cg, 0, new_w, new_h);
    ds.Release();

    item.CursorGraphic = ActiveItemCG.Graphic;

    player.ActiveInventory = item;
}

hocuspocus2

I tried your example code in Global Script and it says ".Graphic' is not a public member of 'DrawingSurface" which refers to line 17. I looked in the manual and it doesn't seem like DrawingSurface has a .Graphic anywhere.

Crimson Wizard

Quote from: hocuspocus2 on Thu 24/12/2020 21:44:43
I tried your example code in Global Script and it says ".Graphic' is not a public member of 'DrawingSurface" which refers to line 17. I looked in the manual and it doesn't seem like DrawingSurface has a .Graphic anywhere.

I made a typo, it should take Graphic from DynamicSprite instead. Fixed the code.

hocuspocus2

It doesn't seem to be doing anything. To test, I tried changing new_h and new_w to something tiny, commenting the if statement that deletes ActiveItemCG, moving the whole code to different places, messing around with ds.DrawImage parameters, and it doesn't give any different results (except for some errors). Just to check, the code is supposed to go outside of a function, right?

Khris

The code on its own doesn't do anything; you need to find the place in your on_mouse_click where it says
Code: ags
  player.ActiveInventory = inventory[game.inv_activated];


and replace that with
Code: ags
  SetActiveInventory(inventory[game.inv_activated]);


The code CW provided is a function and that means yes, it goes outside any functions. It also needs to be above the function in which you're calling it.

Crimson Wizard

#6
Ah, sorry, I was not certain if further instructions are necessary, but here they are:

I recall you are using TwoClickHandler in your project? Then you also would need to call this function from there.

1. For that reason the function must be placed either in TwoClickHandler itself (simpliest is to put it first in the script file), or in a custom script module that you create positioned above others in the list of scripts.
2. You have to make this function also visible to other scripts in case you need it there. Go to the header of a script where you put this function, and type this:
Code: ags

import void SetActiveInventory(InventoryItem* item);

This will work as a function declaration for other scripts below (including room scripts, for what is worth).
3. Now make search through your project to find where "player.ActiveInventory" is being set, and replace these with SetActiveInventory calls, like Khris shown above.

Just in case, these are articles from manual on making and calling your own functions, and using functions in other scripts:
https://adventuregamestudio.github.io/ags-manual/ScriptingTutorialPart2.html#your-own-functions
https://adventuregamestudio.github.io/ags-manual/ImportingFunctionsAndVariables.html



hocuspocus2

Yeah sorry, I still haven't gotten around to learning how custom functions work in AGS. I got into some confusion and errors, but I finally got it to work, thanks!

SMF spam blocked by CleanTalk