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 - Monsieur OUXX

#381
(AGS 3.4.1-P4)

OK so this will sound dumb but...

Simple code :

Code: ags

  String fileName = "$APPDATADIR$/FILE.png"; 
  File* f = File.Open(fileName, eFileRead);
  if (f==null)
    AbortGame(String.Format("Can't find file '%s'", fileName));


I've tried to put FILE.png in the following places :
( where "/" is the game's project folder)
Code: ags

/_Debug/FILE.png
/_Debug/Data/FILE.png
/Compiled/FILE.png
/Compiled/Data/FILE.png



The file is not found.
I've also built the EXE to be sure.

I am confusion ??????????????????????????
#382
What is the state of the Editor? I've tried running AGS.Editor.Desktop but it can only read a project, not start one. I can see that stuff has been implemented to read from some json files, but do you have a dummy json file to use ?
#383
Quote from: tzachs on Wed 20/03/2019 13:18:36
Quote from: Monsieur OUXX on Wed 20/03/2019 12:37:54
It's done twice: One for the mobile file system, and one for the Desktop file system.
Not sure what you mean here. The file system is passed once afaik.

game.Factory.Resources.ResourcePacks.Add(new ResourcePack(new FileSystemResourcePack(AGSGame.Device.FileSystem, AGSGame.Device.Assemblies.EntryAssembly), 0));
game.Factory.Resources.ResourcePacks.Add(new ResourcePack(new EmbeddedResourcesPack(AGSGame.Device.Assemblies.EntryAssembly, CustomAssemblyName), 1));
#384
I'm fiddling with the ResourceSelector branch and I've noticed how FilesView has a private IFileSystem. It's supposed to be populated by FileView's constructor : FilesView(IFileSystem files, ...).
However I can't seem to understand where and how this constructor gets called. Is it with _filesView = rightPanel.AddComponent<FilesView>();?

The reason why I want to know this is because I want to know how the FileSystem is decided. In the master branch, the Resources system has stuff like this :
game.Factory.Resources.ResourcePacks.Add(new ResourcePack(new FileSystemResourcePack(AGSGame.Device.FileSystem, AGSGame.Device.Assemblies.EntryAssembly), 0));
There, the FileSystem is passed explicitly. It's done twice: One for the mobile file system, and one for the Desktop file system.

But then how does it work with FilesView? Why and how is the FileSystem chosen implicitly there?
#385
Quote from: Dualnames on Tue 12/03/2019 18:46:06
Nope, the plugin grayscales it for you, u define the 'intensity' of that. You literally just do

DrawNormalMap(int sprite, int id) where sprite is the sprite you're importing and id is the id of the normal map, and it generates a normal map
So if you use a dynamic sprite you can use that to feed to the next function which Creates a normal map 'pattern' out of a normal map and a sprite.

Perfect! All of you!
#386
Quote from: Dualnames on Tue 12/03/2019 16:43:27
This particular test has normal maps generated by the plugin

So what's the strategy? Do you need to pass a greyscale sprite and the pixel's grey value provides the orientation of the pixel?
#387
It's really weird. I think you should post your code.
#388
I imagine that the normals map has to be exported then imported into AGS at some post? If that's correct, then under which format is it done?
#389
Quote from: WHAM on Mon 11/03/2019 13:27:40
I take offense at being called a Nazi sympathiser
Hint: That's literally the thing you're known for on the forums: You're the guy who always somehow adds a sprinkle of Oberschuzkriegsturmfuhrer to everything, and somehow brings edgy opinions (euphemism) to every discussion. You're the neighborhood nazi.

Remember this one? That was a good one :

Quote from: WHAM on Tue 06/09/2011 12:14:30
Quote from: Ali on Tue 06/09/2011 11:43:04
Let me remind you, once again, that criminals are the same species as you and me.
We agree to disagree on this point.


@janleht : That's what womens' rights day is about: Reminding the world that every time someone says "hey, women should be equal to men", there's always some people crawling from under their rocks to say "ACTUALLY please don't make too much noise because you sound hysterical. And that goes for you too, LGBT, black people and every discriminated group. I'm all for freedom provided oppressed people ask nicely". So, you see, no digression here. And I think you're the one who should think twice, not Ali.
#390
Quote from: Ali on Sun 10/03/2019 00:52:03
If Jurassic Park were released now, people would say "Oh, they made the hacker a girl? She's a total Mary Sue." If Indiana Jones were made now, people would be yelling, "why did they make the baddies Nazis? Talk about virtue signalling! Keep politics out of entertainment!"

Very well summarized. Go to Youtube, look at the first 10 comments under any video about any pop-culture movie, and there are several comments that are basically along those lines.
#391
Quote from: artium on Wed 27/02/2019 20:38:46
I cant download your module, the download link gives 404.
Fixed (also, sorry, this is your thread). We never have enough curves modules, and Splines are awesome, so thanks again for publishing this module.
#392
Thanks! I didn't see that there was a "clipping=false" extra parameter in order to disable it. So it's perfect.

I was worried that people would have to rack their brains to tell the difference between a return value that means "there's nothing there in the room at the coordinates you asked -- outside of the viewport" and a return value that means "you asked for coordinates outside of the viewport but I'm teling you that there's nothing there at the force-clipped coordinates at the boundary of the viewport" -- thus causing human mistakes.

All is well.
#393
I'm worried by the clipping behaviour but I don't know if it's justified or not.
#394
I think this is probably more advanced than my older "AGS Bézier Curves". Or maybe it has a different use. Also I'm too lazy to google up the exact difference between Splines and Bezier, which I always forget. For exhastivity's sake : AGS Bézier Curves link
#395
There can be 3 factors in your choice :

1) The philosophy and licensing

If you're more in favor of open-source, or if your mp4 encoder or decoder forbids redistribution or forces you to change your game's license, then go for ogv. Otherwise this doesn't factor in.

2) The codecs

If your video is targetting a specific rendering style (for example : low resolution lossless compression for 320x200 games) and if you fail to find a proper encoding codec that does that, then you might be forced to use mp4 or ogv depending on what you find and what works. Pros wouldn't have any issues with that, but for noobs like me, codecs is a jungle.

3) AGS quirks

AGS supposedly supports the video formats it says it supports. And it supposedly relies on robust graphical libraries that do the decoding almost out of the box. But nowadays with all the weird device resolutions and stretching filters of mobile devices I'd recommend testing first. Testing, testing, testing.


The file size factors in only if your needs are unusual, and if one of the formats (and codec used inside) doesn't do it right. But it's now 2019 and I would expect ogv to be as good as mp4 for 99% of use cases.
#396
Quote from: abstauber on Wed 30/01/2019 14:47:54
I wasn't able to replicate this outside of your game project.

Thanks a lot for such a quick answer. I'll send the link to CW and Tzachs.

============

EDIT: so the issue was that "Anti-alias TTF fonts" was set to "true" in the general settings. Now everything works perfectly.

============

EDIT 2 :

Here is a module that generates all the action buttons automatically, with an outline, shadow, inner gradient, and is meant to fit nicely with Tumbleweed. It also manages the horizontal stretching of some buttons in the languages that allow it (mostly, English)
It's meant to save the hassle of having to redraw and reimport a billion action buttons in every language. In our case we didn't like the blue theme but it would have taken an eternity to change it to red.

It's called "AutoButtons" (CODE BELOW)

Spoiler



Module header :
Code: ags

/*

//All values below defined in Tumbleweed module 
enum Action {
  eGA_LookAt = 0, //Starting at zero helps avoiding human mistakes when iterating on the enum
  eGA_TalkTo,
  eGA_GiveTo,
  eGA_PickUp,
  eGA_Use,
  eGA_Open,
  eGA_Close,
  eGA_Push,
  eGA_Pull,
  eGA_UseInv,
  eGA_Default,
  eGA_WalkTo
};

enum eLanguage {
  eLangEN = 0, //Starting at zero helps avoiding human mistakes when iterating on the enum
  eLangDE,
  eLangES, 
  eLangIT, 
  eLangFR, 
  eLangPT, 
  eLangNL
};

*/

enum AutoButtonStates {
    eAutoButton_off = 0, 
    eAutoButton_on = 1, 
    eAutoButton_hover = 2
};


#define THEMESIZE 20 //this must be bigger than the number of values in AutoButtonsThemeSettings

enum AutoButtonsThemeSettings {
  eAutoBSetting_color_off,   
  eAutoBSetting_color_off_gradienttop,   
  eAutoBSetting_color_off_gradientbottom,   
  eAutoBSetting_color_on,   
  eAutoBSetting_color_on_gradienttop,   
  eAutoBSetting_color_on_gradientbottom,   
  eAutoBSetting_color_hover,   
  eAutoBSetting_color_hover_gradienttop,   
  eAutoBSetting_color_hover_gradientbottom,   
  eAutoBSetting_color_outline,   
  eAutoBSetting_color_shadow 
};

enum AutoButtonThemes {
    eAutoButtonTheme_Red = 0, 
    eAutoButtonTheme_Blue = 1
    
};

struct AutoButtons
{
    import static int[] GetTheme(AutoButtonThemes theme); //Get the settings values from any of the built-in themes
    import static void SetTheme(AutoButtonThemes theme,  int themeSettings[]); //Overwrite an existing theme from your game, without requiring to temper with the module's script (if needed)
    import static int GenerateAll(int themeSettings[]);
    import static DynamicSprite* GetSprite(eLanguage lan,  Action action,  AutoButtonStates state);
    import static int GetSpriteID(eLanguage lan,  Action action,  AutoButtonStates state);
    
    
};





Module body :
Code: ags

#define NBACTIONS 12
#define NBLANGUAGES 7
#define MAXAUTOBUTTONS 84 //12*7

#define BUTT_WIDTH 56
#define BUTT_HEIGHT 12

#define MAXTEXTWIDTH 200 //Some bullshit width to be passed to GetTextHeight. Should be bigger than the biggest possible width

int defaultTheme;
GUI* guiMain; //The gui that has the action buttons

struct AutoButtonData {
    DynamicSprite* s[3]; //one for each state
    eLanguage lan;
    Action action;
    String text;
    int widenFactor; //how much the text should be stretched horizontally (not all the same depending on the language and the action)
    int width; //what should be the width of the buttons (they don't have the same width depending on the language and the action)
};
AutoButtonData buttons[MAXAUTOBUTTONS];

#define MAXTHEMES 3

struct Constants {
    int width;
    int height;    
};
Constants constants;

struct Theme {
    //all values below initialized in game_start or if you call SetTheme
    int settings[THEMESIZE];
    
    //You can add any field you want. For example String themeName;
    
};
Theme themes[MAXTHEMES];
//int nbThemes;


//Unfortunately the Verbs module does not provide the bare actions, only with their prepositions and complement, like "Look at %s"
String TranslateAction(Action a, eLanguage lan) {
    switch(lan) {
        case eLangEN: 
            switch(a) {
                case eGA_WalkTo: return "Go to";
                case eGA_LookAt: return "Look At";
                case eGA_TalkTo: return "Talk To";
                case eGA_GiveTo: return "Give";
                case eGA_PickUp: return "Pick Up";
                case eGA_Use: return "Use";
                case eGA_Open: return "Open";
                case eGA_Close: return "Close";
                case eGA_Push: return "Push";
                case eGA_Pull: return "Pull";
                default : 
                    return "ERROR";
                    break;
            }
            break;
        case eLangDE : 
            switch(a) {
                case eGA_WalkTo: return "Gehe zu";
                case eGA_LookAt: return "Schau";
                case eGA_TalkTo: return "Rede";
                case eGA_GiveTo: return "Gebe";
                case eGA_PickUp: return "Nehme";
                case eGA_Use: return "Nutze";
                case eGA_Open: return "Öffne";
                case eGA_Close: return "SchlieàŸe";
                case eGA_Push: return "Drücke";
                case eGA_Pull: return "Ziehe";
                default : 
                    return "ERROR";
                    break;
            }
            break;
        case eLangES : 
            switch(a) {
                case eGA_WalkTo: return "Ir a";
                case eGA_LookAt: return "Mirar";
                case eGA_TalkTo: return "Hablar";
                case eGA_GiveTo: return "Dar";
                case eGA_PickUp: return "Coger";
                case eGA_Use: return "Usar";
                case eGA_Open: return "Abrir";
                case eGA_Close: return "Cerrar";
                case eGA_Push: return "Empujar";
                case eGA_Pull: return "Tirar";
                default : 
                    return "ERROR";
                    break;
            }
            break;
        case eLangFR : 
            switch(a) {
                case eGA_WalkTo: return "Aller";
                case eGA_LookAt: return "Regarder";
                case eGA_TalkTo: return "Parler";
                case eGA_GiveTo: return "Donner";
                case eGA_PickUp: return "Prendre";
                case eGA_Use: return "Utiliser";
                case eGA_Open: return "Ouvrir";
                case eGA_Close: return "Fermer";
                case eGA_Push: return "Pousser";
                case eGA_Pull: return "Tirer";
                default : 
                    return "ERROR";
                    break;
            }
            break;
        case eLangIT : 
            switch(a) {
                
                case eGA_WalkTo: return "Vai a";
                case eGA_LookAt: return "Esamina";
                case eGA_TalkTo: return "Parla";
                case eGA_GiveTo: return "Dai";
                case eGA_PickUp: return "Raccogli";
                case eGA_Use: return "Usa";
                case eGA_Open: return "Apri";
                case eGA_Close: return "Ferma";
                case eGA_Push: return "Premi";
                case eGA_Pull: return "Tira";
                default : 
                    return "ERROR";
                    break;
            }
            break;
        case eLangPT : 
            switch(a) {   
                
                case eGA_WalkTo: return "Ir para";
                case eGA_LookAt: return "Olhar";
                case eGA_TalkTo: return "Falar";
                case eGA_GiveTo: return "Dar";
                case eGA_PickUp: return "Apanhar";
                case eGA_Use: return "Usar";
                case eGA_Open: return "Abrir";
                case eGA_Close: return "Fechar";
                case eGA_Push: return "Empurrar";
                case eGA_Pull: return "Puxar";
                default : 
                    return "ERROR";
                    break;
            }
            break;
        case eLangNL : 
            switch(a) {
    
                case eGA_WalkTo: return "Ga naar";
                case eGA_LookAt: return "Bekijk";
                case eGA_TalkTo: return "Praat";
                case eGA_GiveTo: return "Geef";
                case eGA_PickUp: return "Pak";
                case eGA_Use: return "Gebruik";
                case eGA_Open: return "Open";
                case eGA_Close: return "Sluit";
                case eGA_Push: return "Duw";
                case eGA_Pull: return "Trek";
                default : 
                    return "ERROR";
                    break;
            }
            break;    
        default : 
                return "ERROR2";
                break;
    }
}

DynamicSprite* DrawString_Widened(int font, String text, int color,  int widenFactor )
{
    int kerning = 0;
    int wordSpacing = 2; //arbitrary number of pixels for the 'space' character, to make the text more compact
    int maxWidth = GetTextWidth(text, font)*3;
    int height = GetTextHeight(text,  font,  MAXTEXTWIDTH);
    
    //The width is a bit hard to calculate so we'll start by drawing onto a temporary surface
    DynamicSprite* temp_s = DynamicSprite.Create(maxWidth,  height, true);
    DrawingSurface* temp_ds = temp_s.GetDrawingSurface();
    temp_ds.Clear();
    int offset = 0;
    temp_ds.DrawingColor = color;
    //we draw each letter one by one
    for (int i=0; i<text.Length; i++) {
        if (text.Chars[i] == ' ') {
            offset+=wordSpacing;
            
        } else {
            String c = String.Format("%c", text.Chars[i]);
            int letterWidth = GetTextWidth(c, font);
            //the easiest way to widen a letter is to draw it several times
            for (int j=0; j < widenFactor; j++) {
                temp_ds.DrawString(offset+j, 0, font, c);
            }
            offset+=(letterWidth+widenFactor);
            
            //if it's not the last letter we add a white space after the letter
            if (i<text.Length-1)
                offset+=kerning;
        }
    }
    
    //now that we know the width we copy the temp sprite to a final sprite    
    DynamicSprite* s = DynamicSprite.Create(offset,  height, true);
    DrawingSurface* ds = s.GetDrawingSurface();
    ds.DrawSurface(temp_ds);
    
    temp_ds.Release();
    
    return s;
    
}

//Draws 'graphic' 9 times onto ds, in an "outlined" manner (i.e. with offsets of -1 to +1)
void DrawOutline(DrawingSurface*ds,  int x,  int y,  int graphic)
{
   ds.DrawImage(x-1, y-1, graphic);
   ds.DrawImage(x-0, y-1, graphic);
   ds.DrawImage(x+1, y-1, graphic);
   ds.DrawImage(x-1, y-0, graphic);
   ds.DrawImage(x-0, y-0, graphic);
   ds.DrawImage(x+1, y-0, graphic);
   ds.DrawImage(x-1, y+1, graphic);
   ds.DrawImage(x-0, y+1, graphic);
   ds.DrawImage(x+1, y+1, graphic);
}

//See more at https://www.adventuregamestudio.co.uk/forums/index.php?topic=42449.0
int[] GetRGBFromColor(int color)
{
    int rgb[] = new int[3];
    bool highBit = true; //or false, you decide

    if (color > 65535) color -= 65536;
    rgb[0] = ((color >> 11) & 31) << 3;
    rgb[1] = ((color >> 6) & 31) << 3;
    rgb[2] = (color & 31) << 3;
    if (highBit)
    {
        rgb[0] = rgb[0] | 7;
        rgb[1] = rgb[1] | 3;
        rgb[2] = rgb[2] | 7;
    }
  
    return rgb;
}

//from top to bottom, every color of 'ds' that has color 'color' will be replaced by a gradient
void noloopcheck ApplyGradient(DrawingSurface* ds, int color, int color_gradient_top, int color_gradient_bottom)
{
    int rgb_top[] = GetRGBFromColor(color_gradient_top);
    int rgb_bottom[] = GetRGBFromColor(color_gradient_bottom);
    float height_f = IntToFloat(ds.Height);
    
    float r_top = IntToFloat(rgb_top[0]); float r_bottom = IntToFloat(rgb_bottom[0]); float step_r = (r_bottom-r_top)/height_f;
    float g_top = IntToFloat(rgb_top[1]); float g_bottom = IntToFloat(rgb_bottom[1]); float step_g = (g_bottom-g_top)/height_f;
    float b_top = IntToFloat(rgb_top[2]); float b_bottom = IntToFloat(rgb_bottom[2]); float step_b = (b_bottom-b_top)/height_f;
    
    float r = r_top; float g = g_top; float b = b_top; //start values
    for (int j=0; j< ds.Height; j++) {
        ds.DrawingColor = Game.GetColorFromRGB(FloatToInt(r), FloatToInt(g),  FloatToInt(b));
        
        for (int i=0; i<ds.Width; i++) {
            if (ds.GetPixel(i, j)==color)
                ds.DrawPixel(i, j);
        }
        
        r+=step_r; g+=step_g; b+=step_b;
    }
}

DynamicSprite* GenerateButton(String text,  int width,  AutoButtonStates state,  int widenFactor,  int themeSettings[])
{
   
   int font = eFontTumbleText;
   
   //int COLOR_BLACK = Game.GetColorFromRGB(5, 5, 5);
   int COLOR_RED = Game.GetColorFromRGB(255, 0, 0);
   int color = COLOR_RED; //we give it a default value for satefy
   int color_gradient_top = COLOR_RED; //we give it a default value for satefy 
   int color_gradient_bottom = COLOR_RED; //we give it a default value for satefy 
   switch(state) {
       case eAutoButton_off : 
        color = themeSettings[eAutoBSetting_color_off];
        color_gradient_top = themeSettings[eAutoBSetting_color_off_gradienttop];
        color_gradient_bottom = themeSettings[eAutoBSetting_color_off_gradientbottom];
        break;
       case eAutoButton_on :
        color = themeSettings[eAutoBSetting_color_on];
        color_gradient_top = themeSettings[eAutoBSetting_color_on_gradienttop];
        color_gradient_bottom = themeSettings[eAutoBSetting_color_on_gradientbottom];
        break;
       case eAutoButton_hover :
        color = themeSettings[eAutoBSetting_color_hover];
        color_gradient_top = themeSettings[eAutoBSetting_color_hover_gradienttop];
        color_gradient_bottom = themeSettings[eAutoBSetting_color_hover_gradientbottom];
        break;
        
       default:
        AbortGame("Unknown state");
   }
   //int width = constants.width;
   int height = constants.height;
   DynamicSprite* text_s = null;
   
   DynamicSprite* s = DynamicSprite.Create(width, height, true);  
   DrawingSurface* ds = s.GetDrawingSurface();
   //ds.DrawingColor = COLOR_TRANSPARENT;
   ds.Clear();
   
   //int textWidth = GetTextWidth(text, font); //we actually need the widened width
   int textHeight = GetTextHeight(text, font, MAXTEXTWIDTH);
   
   //(optional) colored rectangular background
   //ds.DrawingColor = Game.GetColorFromRGB(100, 100, 100);
   //ds.DrawRectangle(0, 0, width, height);
   
   //shadow
   text_s = DrawString_Widened(font, text, themeSettings[eAutoBSetting_color_shadow], widenFactor );
   int textWidth = text_s.Width;
   int offset_x = (width - textWidth)/2; if (offset_x < 0) offset_x = 0;
   int offset_y = (height - textHeight)/2;  if (offset_y < 0) offset_y = 0;
   DrawOutline(ds, offset_x+widenFactor, offset_y, text_s.Graphic);
   
   //outline (the cheapest way to do an outline is to draw the text 9 times with and offset of -1 or +1 all around
   text_s = DrawString_Widened(font, text, themeSettings[eAutoBSetting_color_outline], widenFactor );
    DrawOutline(ds, offset_x, offset_y, text_s.Graphic);
   //widened text. It returns a temporary sprite that we immediately copy onto our drawing surface
   text_s = DrawString_Widened(font, text, color, widenFactor );
   ds.DrawImage(offset_x,  offset_y, text_s.Graphic);
   
   //gradient
   ApplyGradient(ds, color,  color_gradient_top,  color_gradient_bottom);
   
   //finish up
   text_s.Delete();
   ds.Release();
   
   return s;
}

//this is purely built-in
//how much the text should be stretched horizontally (not all the same depending on the language and the action)
int GetWidenFactor(eLanguage lan,  Action a)
{
    switch(lan) {
        case eLangDE :
                    if (a==eGA_Close) //In German, "SchlieBe"'s font is narrower then the other buttons fonts
                        return 1;
                    else
                        return 2; 
                    break;
        case eLangEN : return 2; break;
        case eLangES : return 1; break;
        case eLangFR : return 1; break;
        case eLangIT : return 1; break;
        case eLangNL : return 1; break;
        case eLangPT : return 1; break;

        default : AbortGame("Unknown language");
    }
}


//Utility : Returns the button bound to a given action. Unfortunately this function is not provided by Verbs
Button*  GetActionButton(Action a)
{
    //we scan every control
    for (int i=0; i<guiMain.ControlCount; i++) {
      GUIControl* c = guiMain.Controls[i];
      Button* b = c.AsButton;
      if (b!=null) {
          if (Verbs.GetButtonAction(b) == a)
            return b;
      }
    }
    
    //AbortGame("Couldn't find the button bound to action '%d'", a);
    return null; //Not all actions have a button. E.g. "walk to"
    
    //If it was implemented in Verbs we would just use this : 
    //return Verbs.GetActionButton(a);
}


int GetButtonWidth(Action a) {
    /*
    //Somehow the automated code below doesn't work. buttons return goofy values, like b.Width == 200. I have no idea why.
    Button* b = GetActionButton(a);
    if (b!= null) {
        //Display("Action %d return button.ID=%d, which has width %d x height %d. It belongs to GUI %d. Name is '%s'", a,  b.ID,  b.Width, b.Height,  b.OwningGUI.ID,  b.Text);
        return b.Width;
    } else { 
        return constants.width; //this action doesn't seem to have a button. We roll back to the default buttons width
    }
    */
    
    //Manual version. TODO : find why code above does not work.
    switch(a) {
        case eGA_LookAt :  return 56; //larger buttons in the central column
        case eGA_TalkTo :  return 56; //larger buttons in the central column
        case eGA_PickUp :  return 56;  //larger buttons in the central column
        default: return 50; //narrower buttons in th eleft and right column
    }
}

static int AutoButtons::GenerateAll(int themeSettings[])
{
    int NBSPRITES = NBACTIONS*NBLANGUAGES;
    
    //safety
    if (NBSPRITES > MAXAUTOBUTTONS) 
        AbortGame("Did something change?");
    
    //Some languages have shorter words so we can make the text wider up to a factor of 3
    int widenFactor = 1;
    
    for (int i=0; i < NBLANGUAGES; i++) {
        
        
        for (int a = 0; a<NBACTIONS; a++) {
             widenFactor = GetWidenFactor(i,  a);
            int width = GetButtonWidth(a);
            
            buttons[i*NBACTIONS+a].widenFactor = widenFactor;
            buttons[i*NBACTIONS+a].width = width;
            
            String text = TranslateAction(a, i);
            
            buttons[i*NBACTIONS+a].lan = i;
            buttons[i*NBACTIONS+a].action = a;
            buttons[i*NBACTIONS+a].s[eAutoButton_off] = GenerateButton(text, width, eAutoButton_off, widenFactor, themeSettings);
            buttons[i*NBACTIONS+a].s[eAutoButton_on] = GenerateButton(text, width,  eAutoButton_on, widenFactor, themeSettings);
            buttons[i*NBACTIONS+a].s[eAutoButton_hover] = GenerateButton(text, width, eAutoButton_hover, widenFactor, themeSettings);
            buttons[i*NBACTIONS+a].text = text;
            
        }
    }
    
}


static DynamicSprite* AutoButtons::GetSprite(eLanguage lan,  Action action,  AutoButtonStates state)
{
    return buttons[lan*NBACTIONS+action].s[state];
}

static int AutoButtons::GetSpriteID(eLanguage lan,  Action action,  AutoButtonStates state)
{
    return buttons[lan*NBACTIONS+action].s[state].Graphic;
}

float min(float a,  float b) { if (a < b) return a; return b; }
float max(float a,  float b) { if (a > b) return a; return b; }
float bound(float a,  float roof,  float floor) { return min(roof, max(a, floor)); }

//this function returns a darker or brighter version of color 'color'.
// 'factor' between 0.0 and 2.0.
// - If factor is 0.0, the function returns black (because the color has been darkened to the max). 
// - If it's 1.0, the color doesn't change
// - If factor is 2.0, the function probably returns white, or at least 'color" is now twice brighter
int ChangeBrightness(int color,  float factor) 
{
    int rgb[] = GetRGBFromColor(color);
    float r = IntToFloat(rgb[0]); float g = IntToFloat(rgb[1]); float b = IntToFloat(rgb[2]); 
    rgb = null;
    r = bound(r*factor, 255.0,  0.0); g = bound(g*factor, 255.0,  0.0); b = bound(b*factor, 255.0,  0.0);
    return Game.GetColorFromRGB(FloatToInt(r), FloatToInt(g),FloatToInt(b));
}

int[] GetTheme_BuiltIn(AutoButtonThemes theme)
{

    //useful values
    int COLOR_RED = Game.GetColorFromRGB(255, 99, 99);
    int COLOR_BROWN = Game.GetColorFromRGB(50, 0, 0);
    int COLOR_YELLOW = Game.GetColorFromRGB(255, 249, 72);
    int COLOR_GRAYISHRED = Game.GetColorFromRGB(116, 63, 63);
    int COLOR_DARKGRAYISHRED = Game.GetColorFromRGB(52, 32, 32);
    int COLOR_BLACK = Game.GetColorFromRGB(5, 5, 5);
    
    int themeSettings[] = new int[THEMESIZE];
    
    switch (theme) {
        case eAutoButtonTheme_Red : 

    
            themeSettings[eAutoBSetting_color_off] = COLOR_RED;
            themeSettings[eAutoBSetting_color_on] = COLOR_YELLOW;
            themeSettings[eAutoBSetting_color_hover] = COLOR_BROWN;
            themeSettings[eAutoBSetting_color_outline] = COLOR_GRAYISHRED;
            themeSettings[eAutoBSetting_color_shadow] = COLOR_BLACK;
            
            /*
            //MANUAL
            themeSettings[eAutoBSetting_color_off_gradienttop] =            Game.GetColorFromRGB(255, 175, 175);
            themeSettings[eAutoBSetting_color_off_gradientbottom] =         Game.GetColorFromRGB(200, 0, 0);
            themeSettings[eAutoBSetting_color_on_gradienttop] =             Game.GetColorFromRGB(255, 249, 125);
            themeSettings[eAutoBSetting_color_on_gradientbottom] =          Game.GetColorFromRGB(200, 200, 25);
            themeSettings[eAutoBSetting_color_hover_gradienttop] =          Game.GetColorFromRGB(100, 50, 50);
            themeSettings[eAutoBSetting_color_hover_gradientbottom] =       Game.GetColorFromRGB(25, 0, 0);
            */
            //AUTOMATED
            themeSettings[eAutoBSetting_color_off_gradienttop] =            ChangeBrightness(themeSettings[eAutoBSetting_color_off],  1.5);
            themeSettings[eAutoBSetting_color_off_gradientbottom] =         ChangeBrightness(themeSettings[eAutoBSetting_color_off],  0.5);
            themeSettings[eAutoBSetting_color_on_gradienttop] =             ChangeBrightness(themeSettings[eAutoBSetting_color_on],  1.5);
            themeSettings[eAutoBSetting_color_on_gradientbottom] =          ChangeBrightness(themeSettings[eAutoBSetting_color_on],  0.5);
            themeSettings[eAutoBSetting_color_hover_gradienttop] =          ChangeBrightness(themeSettings[eAutoBSetting_color_hover],  1.5);
            themeSettings[eAutoBSetting_color_hover_gradientbottom] =       ChangeBrightness(themeSettings[eAutoBSetting_color_hover],  0.5);
            

            break;
            
        case eAutoButtonTheme_Blue :
            AbortGame("NOT IMPLEMENTED (suit yourself)");
            
            break;
    }
    
    return themeSettings;
}

static int[] AutoButtons::GetTheme(AutoButtonThemes theme) 
{
    int themeSettings[] = new int[THEMESIZE];
    
    if (theme < 0 || theme >= MAXTHEMES)
        AbortGame("Not a valid theme number : %d", theme);
    
    for (int i=0; i< THEMESIZE; i++) {
        themeSettings[i] = themes[theme].settings[i];
    }
    
    return themeSettings;
}

 //Overwrite an existing theme from your game, without requiring to temper with the module's script (if needed)
static void AutoButtons::SetTheme(AutoButtonThemes theme,  int themeSettings[])
{
    if (theme < 0 || theme >= MAXTHEMES)
        AbortGame("Not a valid theme number : %d", theme);
    
    for (int i=0; i< THEMESIZE; i++) {
        themes[theme].settings[i] = themeSettings[i];
    }
}



void game_start()
{
    //depends on your game
    guiMain = gMain; //this is a dirty hack. we should rely only on "Verbs" methods but it doesn't offer GetActionButton.
    
    //nbThemes = 0;
    defaultTheme = eAutoButtonTheme_Red;
    
    //Init buttons constant width. This is normally ignored and replaced with buttons[].width because not all buttons have the same width
    constants.height = BUTT_HEIGHT;
    constants.width = BUTT_WIDTH;

    //Init built-in themes
    int themeSettings[] = GetTheme_BuiltIn(eAutoButtonTheme_Red);
    AutoButtons.SetTheme(eAutoButtonTheme_Red,  themeSettings);
    //themeSettings[] = GetTheme_BuiltIn(eAutoButtonTheme_Blue);
    //AutoButtons.SetTheme(eAutoButtonTheme_Blue,  themeSettings);
    
    //final init
    themeSettings = AutoButtons.GetTheme(defaultTheme);
    AutoButtons.GenerateAll(themeSettings);
}




Here is how to make it work with Tumbleweed :
(locate the code below in your Tumbleweed initialization code)
Code: ags

      // English - eLangEN  
      /*
        //WITHOUT AUTOBUTTONS : Set button graphics manually
        odd_id=1407; even_id = odd_id+1;
        Verbs.LocalizeActionButton(eLangEN,eGA_Open,    GetOddId(), GetEvenId(), 'q');
        Verbs.LocalizeActionButton(eLangEN,eGA_Close,   GetOddId(), GetEvenId(), 'a');
        Verbs.LocalizeActionButton(eLangEN,eGA_GiveTo,  GetOddId(), GetEvenId(), 'z');
        Verbs.LocalizeActionButton(eLangEN,eGA_Push,    GetOddId(), GetEvenId(), 'e');
        Verbs.LocalizeActionButton(eLangEN,eGA_Pull,    GetOddId(), GetEvenId(), 'd');
        Verbs.LocalizeActionButton(eLangEN,eGA_Use,     GetOddId(), GetEvenId(), 'c');
        Verbs.LocalizeActionButton(eLangEN,eGA_PickUp,  GetOddId(), GetEvenId(), 'w');
        Verbs.LocalizeActionButton(eLangEN,eGA_LookAt,  GetOddId(), GetEvenId(), 's');
        Verbs.LocalizeActionButton(eLangEN,eGA_TalkTo,  GetOddId(), GetEvenId(), 'x');
      */
        //WITH AUTOBUTTONS : Get the sprites IDs from the module; it generated thems for you.
        eLanguage lan = eLangEN; int graphic_off; int graphic_on; Action a;
        a = eGA_Open;
        graphic_off = AutoButtons.GetSpriteID(lan, a, eAutoButton_off);
        graphic_on = AutoButtons.GetSpriteID(lan, a, eAutoButton_on);
        Verbs.LocalizeActionButton(lan, a,    graphic_off, graphic_on, 'q');
        
        a = eGA_Close;
        graphic_off = AutoButtons.GetSpriteID(lan, a, eAutoButton_off);
        graphic_on = AutoButtons.GetSpriteID(lan, a, eAutoButton_on);
        Verbs.LocalizeActionButton(lan, a,    graphic_off, graphic_on, 'a');
        
        a = eGA_GiveTo;
        graphic_off = AutoButtons.GetSpriteID(lan, a, eAutoButton_off);
        graphic_on = AutoButtons.GetSpriteID(lan, a, eAutoButton_on);
        Verbs.LocalizeActionButton(lan, a,    graphic_off, graphic_on, 'z');
        
        a = eGA_Push;
        graphic_off = AutoButtons.GetSpriteID(lan, a, eAutoButton_off);
        graphic_on = AutoButtons.GetSpriteID(lan, a, eAutoButton_on);
        Verbs.LocalizeActionButton(lan, a,    graphic_off, graphic_on, 'e');
        
        a = eGA_Pull;
        graphic_off = AutoButtons.GetSpriteID(lan, a, eAutoButton_off);
        graphic_on = AutoButtons.GetSpriteID(lan, a, eAutoButton_on);
        Verbs.LocalizeActionButton(lan, a,    graphic_off, graphic_on, 'd');
        
        a = eGA_Use;
        graphic_off = AutoButtons.GetSpriteID(lan, a, eAutoButton_off);
        graphic_on = AutoButtons.GetSpriteID(lan, a, eAutoButton_on);
        Verbs.LocalizeActionButton(lan, a,    graphic_off, graphic_on, 'c');
        
        a = eGA_PickUp;
        graphic_off = AutoButtons.GetSpriteID(lan, a, eAutoButton_off);
        graphic_on = AutoButtons.GetSpriteID(lan, a, eAutoButton_on);
        Verbs.LocalizeActionButton(lan, a,    graphic_off, graphic_on, 'w');
        
        a = eGA_LookAt;
        graphic_off = AutoButtons.GetSpriteID(lan, a, eAutoButton_off);
        graphic_on = AutoButtons.GetSpriteID(lan, a, eAutoButton_on);
        Verbs.LocalizeActionButton(lan, a,    graphic_off, graphic_on, 's');
        
        a = eGA_TalkTo;
        graphic_off = AutoButtons.GetSpriteID(lan, a, eAutoButton_off);
        graphic_on = AutoButtons.GetSpriteID(lan, a, eAutoButton_on);
        Verbs.LocalizeActionButton(lan, a,    graphic_off, graphic_on, 'x');
        

[close]
#397
Quote from: Crimson Wizard on Wed 30/01/2019 15:46:59
The above should work, but there are couple of things to optimise:

1) Since 3.4.0 AGS script supports "for" loops.
2) You may have to call LoseInventory multiple times per item if there are more than 1 instance of certain items.
Instead you may directly modify "InventoryQuantity" property. The only nuance is that you should call UpdateInventory afterwards to make sure inventory window is redrawn.

Code: ags

for (int i = 0; i < Game.InventoryItemCount; i++)
    cCharacter.InventoryQuantity[i] = 0;
UpdateInventory();


Noted. Thanks!

EDIT: actually the code that uses .InventoryQuantity crashes if the player doesn't have any of item "i". the engine refuses to set it to 0 because the index is out of bounds. I'll stick to LoseInventory for now.
#398
It's very simple but I can't find it.
how to completely empty the player's inventory? Google didn't help and F1 didn't help. Or maybe I was using the wrong search terms.

EDIT : found it

Code: ags
 int ii=0;
  while(ii<Game.InventoryItemCount){
    cleech.LoseInventory(inventory[ii]);
    ii++;
  }
#399
I have a new problem, which is the font issue that I've mentionned previously. It's not caused by the module itself however I don't understand what differs between my own game files and the demo game.

Abstauber, unfortunately the best way to show you my issue is to share the game files but I don't want to do it publicly, so I'm sending them to you in a Private Message.

For everyone, here is my issue's description:

CONTEXT
- I have a game based on the Tumbleweed module.
- It contains the "gAction" GUI, which itself contains "lblAction" -- same as Tumbleweed demo game
- lblAction uses the "eFontTumbleTextOut" font.  -- same as Tumbleweed demo game
- "TumbleTextOut" was imported from assets/xpaider2.ttf  -- same as Tumbleweed demo game
- TumbleTextOut was imported as 9pts and has outline "automatic" -- same as Tumbleweed demo game
- the game is set to "proper alpha blending" for both GUI and fonts -- same as Tumbleweed demo game

ISSUE
- In the demo game, when i open gAction, the label appears with the font without its outline (the outline is rendered only in-game)
- In my own game, when I open gAction, the label appears with a crappy 1-pixel outline the same color as the font. It's like the font is white with a white outline.

Screenshot:


I've tried tried overwriting xpaider2.ttf over itself, by re-importing it into the Tumbleweed demo game (without changing anything else), to see if it would do the same as in my game. That is, to see if the import action was broken in my current AGS version (3.4.1.13) but the label is still rendered properly in the Editor in the demo game.
I've tried re-importing /xpaider2.ttf over itself into my own game, but the issue is still there : it has this unwanted white outline.

Note that the font appears as expected in the Editor's "font" panel. It's only messed up in the label in gAction.

I'm 100% sure it's caused by transparency and some font pixels not being 100% transparent, hence being rendered as 100% opaque. But I just can't understand why it doesn't do the same in my game and in the demo game.

==========

unrelated : how do you manage to have all the GUIs appear with the proper Z order in your demo game, without defining any custom z-order? I had to do it in my own game.
#400
I was a bit spooked off by this "pre-alpha demo" thing at first (reminded me of the darkest hours of OSD) but the screenshots are promising.
Are the waves/water level animated for realsies?
SMF spam blocked by CleanTalk