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

Topics - Scavenger

#21
The old question:
Spoiler
Hey, I'm just finishing off some functions in my translucency plugin, and I've come up with a problem that I can't solve easily. I'm trying to make sure that I can keep the translucency consistent with the real colours of a sprite while I cycle the palette (so I can have, for instance, a translucent waterfall that cycles while still being translucent or a magical rainbow that cycles). For this, I assume I need to create some way of creating an array of values that points the renderer to the right part of the LUT (if 22 cycles to 23, then entry 23 on the LUT needs to be rerouted to 22's entry, or any translucent sprite containing index 23 will still treat it as if it was the original colour)

I'm running into problems because I don't think I'm approaching this right. I have a function to remap an array in parallel to palette cycling, not sure if I'm doing it right:

Code: C++

unsigned char cycle_remap [256];

void ResetRemapping () //Called when a room is loaded, so that the array corresponds 1:1 with the palette.
{
	for (int j = 0; j < 256; ++j)
	{
		cycle_remap [j] = j;
	}
}

void CycleRemap (int start, int end)
{
	if (end > start)
	{
		int diff = end - start;
		int i = 0;
		int wraparound = cycle_remap [end];
		while (i < diff)
		{
			cycle_remap [end-i-1] = cycle_remap [end-i];
			i++;
		}
		cycle_remap [start] = wraparound;
	}
	else
	{
		int diff = start - end;
		int i = 0;
		int wraparound = cycle_remap [start];
		while (i < diff)
		{
			cycle_remap [end+i+1] = cycle_remap [end+i];
			i++;
		}
	}
}


It's meant to match what happens to the palette slots when called with CyclePalette, but it just seems to turn everything one colour. Is this code even right?
[close]

Just so I don't start like fifty different topics, I'll ask my new question here, it's related:

Does AGS only load a sprite once it's currently being used? I have an idea for tinting the colours of characters in 8-bit and I need to access their sprites as they're being used, and I need to know whether or not AGS keeps the sprites past the point they're being used.

Basically, I need to know if I can catch a character's current ViewFrame sprite as it's being loaded with AGSE_SPRITELOAD, run my image process on it, and then repeat for every frame of their animation. I don't want strange things like tinted sprites showing up when I've turned tinting off, or normal sprites showing up. Does the sprite get unloaded as soon as the view moves on to the next frame?
#22
I'm currently working on a text renderer so I can do fancy text effects and coloured text and all that, and I'm currently trying to do a flowing sine wave for the text. The good news is, I can draw the text in a sine wave. The bad news is, I can't seem to get it to move. It remains a static sine wave no matter where I put the sinetimer, or what values I give it. I need it to shift right with time.

My full code is:

Code: AGS
// room script file

DynamicSprite *textarea;
Overlay *ov;
String targettxt;
int targettxtlength;
String txt;
int counter;
int delay;
int targetindex;
int length;
int sinetimer;

bool renderingtext;
bool renderingcomplete;

function DisplayRenderedText (String text, int textdelay)
{
  targettxt = text.Copy ();
  targetindex = 0;
  delay = textdelay;
  counter = 0;
  renderingtext = true;
  txt = String.Format("");
  while (targettxt.Substring (targetindex, 1) == "@") //if the current character is the escape code.
        {
            targetindex++;
            if (targettxt.Substring (targetindex, 1) == "j") // if the escape code is "jitter"
            {
              targetindex+=2;
            }
            else if (targettxt.Substring (targetindex, 1) == "t") //if escape code is "tremor", for really tiny jitters.
            {
              targetindex++;
            }
            else if (targettxt.Substring (targetindex, 1) == "n") // if the escape code is "normal"
            {
              targetindex++;
            }
            else if (targettxt.Substring (targetindex, 1) == "c") // if the escape code is "colour"
            {
              targetindex+=4;
            }
            else if (targettxt.Substring (targetindex, 1) == "f") // if the escape code is "font"
            {
              targetindex+=3;
            }
            else if (targettxt.Substring (targetindex, 1) == "s") // if the escape code is "sine"
            {
              targetindex+=3;
            }
            else if (targettxt.Substring (targetindex, 1) == "p") // if the escape code is "pause"
            {
              targetindex+=2;
            }
            else if (targettxt.Substring (targetindex, 1) == "[") // if the escape code is "carriage return"
            {
              targetindex+=1;
            }
        }
}

String ProgressCurrentText ()
{
  if (counter == delay)
  {
  if (targetindex < targettxt.Length)
  {
    targetindex++;
      while (targettxt.Substring (targetindex, 1) == "@") //if the current character is the escape code.
        {
            targetindex++;
            if (targettxt.Substring (targetindex, 1) == "j") // if the escape code is "jitter"
            {
              targetindex+=2;
            }
            else if (targettxt.Substring (targetindex, 1) == "t") //if escape code is "tremor", for really tiny jitters.
            {
              targetindex++;
            }
            else if (targettxt.Substring (targetindex, 1) == "n") // if the escape code is "normal"
            {
              targetindex++;
            }
            else if (targettxt.Substring (targetindex, 1) == "c") // if the escape code is "colour"
            {
              targetindex+=4;
            }
            else if (targettxt.Substring (targetindex, 1) == "s") // if the escape code is "sine"
            {
              targetindex+=3;
            }
            else if (targettxt.Substring (targetindex, 1) == "f") // if the escape code is "font"
            {
              targetindex+=3;
            }
            else if (targettxt.Substring (targetindex, 1) == "p") //If the escape code is pause.
            {
              targetindex++;
              String s_amount = targettxt.Substring (targetindex, 1);
              if (s_amount.AsInt > 0) counter = (s_amount.AsInt * delay) * (-1);
              else AbortGame ("Invalid pause amount (1-9)");
            }
            else if (targettxt.Substring (targetindex, 1) == "[") //If the escape code is pause.
            {
              targetindex++;
            }
        }
  }
  }
  else counter++;
  return targettxt.Substring (0, targetindex);
}

function RenderText (String text, int x, int y)
{
  int curry;
  int mode;
  int modedata;
  int modedata2;
  int color;
  int font;
  int prog;
  DrawingSurface *surf = textarea.GetDrawingSurface ();
  surf.Clear ();
  surf.DrawingColor = color;
  int i;
  curry = y;
  prog=0;
  while (i < text.Length)
  {
    surf.DrawingColor = color;
    if (text.Substring (i, 1) == "@") //if the current character is the escape code.
        {
          i++;
          if (text.Substring (i, 1) == "j") // if the escape code is "jitter"
          {
            mode = 1;
            i++;
            String s_amount = text.Substring (i, 1);
            if (s_amount.AsInt > 0) modedata = s_amount.AsInt;
            else AbortGame ("Invalid Jitter amount (1-9)");
            i++;
          }
          else if (text.Substring (i, 1) == "t") //if escape code is "tremor", for really tiny jitters.
          {
            mode = 2;
            i++;
          }
          else if (text.Substring (i, 1) == "n") // if the escape code is "normal"
          {
            mode = 0;
            i++;
          }
          else if (text.Substring (i, 1) == "s") // if the escape code is "sine"
          {
            mode = 3;
            i++;
           String h_amount = text.Substring (i, 1);
           if (h_amount.AsInt > 0) modedata = h_amount.AsInt;
           else AbortGame ("Invalid sine height amount (1-9)");
           i++;
           String w_amount = text.Substring (i, 1);
           if (w_amount.AsInt > 0) modedata2 = w_amount.AsInt;
           else AbortGame ("Invalid sine period amount (1-9)");
           i++;
          }
          else if (text.Substring (i, 1) == "c") // if the escape code is "colour"
          {
            i++;
            String colordata = text.Substring (i, 3);
            if (colordata.AsInt > 0) color = colordata.AsInt;
            else AbortGame ("Invalid color number.");
            i+=3;
          }
          else if (text.Substring (i, 1) == "f") // if the escape code is "font"
          {
            i++;
            String fontdata = text.Substring (i, 2);
            if (fontdata.AsInt > 0 || fontdata.CompareTo ("00") == 0) font = fontdata.AsInt;
            else AbortGame ("Invalid font number.");
            i+=2;
          }
          else if (text.Substring (i, 1) == "[") // if the escape code is the AGS carriage return
          {
            prog = 0;
            curry+= GetTextHeight ("Quick brown fox jumped over the Lazy dog",font, 320) + 1;
            i++;
          }
          else if (text.Substring (i, 1) == "p") //If the escape code is pause.
          {
            i+=2; //This escape code is not for this part of the renderer.
          }
          else AbortGame ("Invalid text escape code.");
        }
    else 
    {
      if (mode == 0) // normal mode
      {
        surf.DrawString (x+prog, curry, font, text.Substring (i, 1));
      }
      else if (mode == 1) //jitter mode
      {
        surf.DrawString (x+prog+Random(1), curry+(Random(modedata*2)-modedata), font, text.Substring (i, 1));
      }
      else if (mode == 2) //tremor mode
      {
        surf.DrawString (x+prog+Random(1), curry+Random(1), font, text.Substring (i, 1));
      }
      else if (mode == 3) //sine mode
      {
        if (sinetimer < modedata2) sinetimer++;
        else sinetimer = 0;
        float period = (2.0*Maths.Pi)/(IntToFloat (modedata2));
        float offset = IntToFloat(modedata) * Maths.Sin ((period * IntToFloat (sinetimer)) - IntToFloat(i));
        surf.DrawString (x+prog, curry+FloatToInt (offset, eRoundNearest), font, text.Substring (i, 1));
      }
    prog += GetTextWidth (text.Substring (i, 1), font);
    i++;
    }
  }
  surf.Release ();
  ov = Overlay.CreateGraphical (0, 0, textarea.Graphic, true);
}

function GetRenderTextWidth (String text)
{
  int font;
  int currfont;
  int totallength;
  int i;
  while (i < text.Length)
  {
    if (text.Substring (i, 1) == "@") //if the current character is the escape code.
    {
      i++;
      if (text.Substring (i, 1) == "j") // if the escape code is "jitter"
      {
        i+=2;
      }
      else if (text.Substring (i, 1) == "t") //if escape code is "tremor", for really tiny jitters.
      {
        i++;
      }
      else if (text.Substring (i, 1) == "n") // if the escape code is "normal"
      {
        i++;
      }
      else if (text.Substring (i, 1) == "c") // if the escape code is "colour"
      {
        i+=4;
      }
      else if (text.Substring (i, 1) == "f") // if the escape code is "font"
      {
        i++;
        String fontdata = text.Substring (i, 2);
        if (fontdata.AsInt > 0 || fontdata.CompareTo ("00") == 0) currfont = fontdata.AsInt;
        else AbortGame ("Invalid font number.");
        i+=2;
      }
      else if (text.Substring (i, 1) == "p") //If the escape code is pause.
      {
        i+=2; //This escape code is not for this part of the renderer.
      }
      else if (text.Substring (i, 1) == "s") //If the escape code is sine.
      {
        i+=3; 
      }
      else if (text.Substring (i, 1) == "[") //If the escape code is pause.
      {
        i++;
        totallength = 0;
      }
      else AbortGame ("Invalid text escape code.");
    }
    else 
    {
    totallength += GetTextWidth (text.Substring (i, 1), font);
    i++;
    }
  }
    return totallength;
}

function room_AfterFadeIn()
{
textarea = DynamicSprite.Create (320, 200);
DisplayRenderedText ("@c015@s21 This is a test string.",5);
}


function room_RepExec()
{
  String newtext = ProgressCurrentText ();
  RenderText (newtext, 30, 20);
}


And the actual drawing code is:

Code: AGS
      else if (mode == 3) //sine mode
      {
        if (sinetimer < modedata2) sinetimer++;
        else sinetimer = 0;
        float period = (2.0*Maths.Pi)/(IntToFloat (modedata2));
        float offset = IntToFloat(modedata) * Maths.Sin ((period * IntToFloat (sinetimer)) - IntToFloat(i));
        surf.DrawString (x+prog, curry+FloatToInt (offset, eRoundNearest), font, text.Substring (i, 1));
      }


I'm really stumped as to how to get it to move with time. There must be something obvious that I'm missing, but for the life of me I can't see what it is. Can anyone help?
#23
Hey, I'm trying to write a short engine plugin for my game, but I've long since switched computers and lost all of my Visual Studio stuff. I know a bit of C++ so the coding itself isn't an issue, but setting up the project is. I've plum forgotten how to set it up. Compiling was always a weak point for me. I've tried a few versions of VS, but none of them seem to have the DLL Project set up I remember?

Could someone tell me which version of VS I need and the settings I need to use, or link me to a VS project version of the engine plugin sample code? I can work it out from there, but I have no idea where to begin. The only projects I can find for AGS plugins are the editor ones. :(
#24
I'm currently working on a simple platformer using Pixelformer as a base, and everything's working pretty well, with the exception of the collision detection. It's fine for big, meaty platforms, but when you fall at a shallow angle on a thin platform, the character falls straight through more often than not. This would be incredibly bad for a platformer (as having all big meaty platforms would make it less fun), so it needs to be fixed, but I have no idea what went wrong!

I enclose the project here: DOWNLOAD

The collision code:
Code: ags

void HandleCollisions()
{
  mPlayer.onGround = false;
  int x = FloatToInt(mPlayer.x, eRoundNearest);
  int y = FloatToInt(mPlayer.y, eRoundNearest);
  
   while((Mapper.Blocked(x + 2, y) || Mapper.Blocked(x - 2, y))) // Ground impact
   {
      //if (mPlayer.vely > terminalVel - 0.01 && MoveDir() == KeyDir() && IsKeyPressed(eKeyDownArrow)) mPlayer.inRoll = true;
      mPlayer.onGround = true;
      mPlayer.hasDblJumped = false;
      mPlayer.jumped = false;
      mPlayer.vely = 0.0;
      mPlayer.y = IntToFloat(y); 
      y --;
      
   }
   if (!mPlayer.ignoringdwcollisions)
   {
     while (mPlayer.vely >= 0.0 && ((Mapper.DownwardBlocked (x + 2, y) || Mapper.DownwardBlocked (x -2, y)) || Mapper.DownwardBlocked (x, y+1)))
     {
        mPlayer.onGround = true;
        mPlayer.hasDblJumped = false;
        mPlayer.jumped = false;
        mPlayer.vely = 0.0;
        mPlayer.y = IntToFloat(y); 
        y --;
     }
     Object *movingplatform = Object.GetAtScreenXY (x - GetViewportX (), y - GetViewportY ());
     while (movingplatform != null && mPlayer.vely >= 0.0 && (Mapper.IsObjectPlatform (movingplatform) || Mapper.IsObjectBlock (movingplatform) )) //Moving Platform Impact
     {
       
       mPlayer.onGround = true;
       mPlayer.hasDblJumped = false;
       mPlayer.jumped = false;
       mPlayer.vely = 0.0;
       mPlayer.y = IntToFloat(y); 
       mPlayer.movplat_x_offset = x - movingplatform.X;
       mPlayer.movplat_x_prev = movingplatform.X;
       mPlayer.onMovingPlatform = true;
       movingplatform = Object.GetAtScreenXY (x - GetViewportX (), y - GetViewportY ());
       y --;
     }
   }
   else
   {
     if (!Mapper.DownwardBlocked (x + 2, y) && !Mapper.DownwardBlocked (x -2, y) && !Mapper.DownwardBlocked (x, y+1)) 
     {
       mPlayer.ignoringdwcollisions = false;
     }
   }
     
     
   if (Mapper.Blocked(x, y - 24)) //Platform ceiling.
   {
     y ++;
     mPlayer.vely = 1.0;
     mPlayer.jumpCounter = 40;
     mPlayer.releasedJump = true;
   }
   
   Object *block = Object.GetAtScreenXY (x - GetViewportX (), y - GetViewportY () - 24);
   if (block != null &&  Mapper.IsObjectBlock (block)) //BLOCK object ceiling.
   {
     y ++;
     mPlayer.vely = 1.0;
     mPlayer.jumpCounter = 40;
     mPlayer.releasedJump = true;
     block = Object.GetAtScreenXY (x - GetViewportX (), y - GetViewportY ());
   }
  bool failedtomove = false;
   if (Mapper.Blocked(x + 5, y - 4) || Mapper.Blocked(x + 5, y - (20 / (mPlayer.ducking + 1))) || Mapper.Blocked(x + 5, y - 12)){
     
     if (!failedtomove) x --;
     else x++;
     if (x < -100) failedtomove = true;
     mPlayer.x = IntToFloat(x);
     mPlayer.velx = 0.0;
   }
   
   Object *block1 = Object.GetAtScreenXY (x - GetViewportX () + 5, y - GetViewportY () -4);
   Object *block2 = Object.GetAtScreenXY (x - GetViewportX () + 5, y - GetViewportY () -20);
   Object *block3 = Object.GetAtScreenXY (x - GetViewportX () + 5, y - GetViewportY () -12);
   
   if ((block1 != null && Mapper.IsObjectBlock (block1)) && (block2 != null && Mapper.IsObjectBlock (block2)) && (block3 != null && Mapper.IsObjectBlock (block3)) ){
     x --;
     mPlayer.x = IntToFloat(x);
     mPlayer.velx = 0.0;
     block1 = Object.GetAtScreenXY (x - GetViewportX () + 5, y - GetViewportY () -4);
     block2 = Object.GetAtScreenXY (x - GetViewportX () + 5, y - GetViewportY () -20);
     block3 = Object.GetAtScreenXY (x - GetViewportX () + 5, y - GetViewportY () -12);
   }
   
   failedtomove = false;
   if ((Mapper.Blocked(x - 5, y - 4) || Mapper.Blocked(x - 5, y - (20 / (mPlayer.ducking + 1))) || Mapper.Blocked(x - 5, y - 12)))
   {
     if (!failedtomove) x ++;
     else x--;
     if (x > Room.Width + 100) failedtomove = true;
     mPlayer.x = IntToFloat(x);
     mPlayer.velx = 0.0;
     
   }
   block1 = Object.GetAtScreenXY (x - GetViewportX () - 5, y - GetViewportY () -4);
   block2 = Object.GetAtScreenXY (x - GetViewportX () - 5, y - GetViewportY () -20);
   block3 = Object.GetAtScreenXY (x - GetViewportX () - 5, y - GetViewportY () -12);
   
   while ((block1 != null && Mapper.IsObjectBlock (block1)) && (block2 != null && Mapper.IsObjectBlock (block2)) && (block3 != null && Mapper.IsObjectBlock (block3)) ){
     x ++;
     mPlayer.x = IntToFloat(x);
     mPlayer.velx = 0.0;
     block1 = Object.GetAtScreenXY (x - GetViewportX () - 5, y - GetViewportY () -4);
   block2 = Object.GetAtScreenXY (x - GetViewportX () - 5, y - GetViewportY () -20);
   block3 = Object.GetAtScreenXY (x - GetViewportX () - 5, y - GetViewportY () -12);
   }
  mPlayer.state = eFalling;
  if (Mapper.Blocked(x - 6, y - 4) && Mapper.Blocked(x - 6, y - 22) && Mapper.IsAreaGrippable (x - 6, y - 22) && mPlayer.direction == eLeft){ mPlayer.state = eOnWall; mPlayer.hasDblJumped = false;}
if (Mapper.Blocked(x + 6, y - 4) && Mapper.Blocked(x + 6, y - 22) && Mapper.IsAreaGrippable (x + 6, y - 22) && mPlayer.direction == eRight){ mPlayer.state = eOnWall; mPlayer.hasDblJumped = false;
} 
}


The Mapper class literally just polls the room's regions for what counts as blocking, and looks for objects named PLATFORM or BLOCK. I've tried a couple of things, like moving the player's collision area, but to no avail. Can any of you spot anything that I'm missing?

Thank you in advance.
#25
I'm currently working on a computer interface for my game, and I need a usenet interface. I don't mind if it's not dynamic, and I know how to do the frontend, but it's the backend that is bugging me. What is the best way to do a small database that shows different arrays of values in a listbox and a label depending on what's selected? EG:

Code: ags

- comp.legacy.z80 // Root 1
-- Why is my computer beeping all the time? //Branch 1
--- Seriously, whenever I turn it on, its just a litany of PC speaker beeps. I cant take it, the computer doesn't even work. //Branch 1 Selected.
-- Running the Metaverse //Branch 2
--- Is there any way to enable 3D view in the z80 Metaverse build? //Branch 2 Selected
- alt.fan.ripsaw // Root 2
-- Ripsaw Rising Doesnt Make Any Sense //Branch 1
--- Im sure youve read my other posts on the subject, but something occurred to me when rewatching the execrable Dark Blade series. When Ripsaw first became a... //Branch 1 selected.


What I want to do is have a list of usenet addresses (the roots), and when you click on one, it populates the message list with the branches, and when you select a branch, it displays the message connected to the branch. I'm not sure how to store this, however - should it be hard coded into the game's script, or in a seperate text file? If it was in a text file, I expect I'd be able to have different folders for text resources (Using /English/usenet_01.txt , /German/usenet_01.txt etc and Game.TranslationFilename to choose the folder). And if it was in a text file, how do I store it so it can be parsed into the arrays? I may need several of these throughout the course of the game (on different computers).

I'm sure I'd be able to program it, I just don't know the best way to start. Does anyone have any suggestions?

EDIT:
It was just a case of making a struct.
#26
I'm trying to make a simple graphical effect - offsetting a sprite from it's original coordinates, and wrapping it around to the other side if parts go beyond the boundaries of the sprite (for instance, if a row of pixels go beyond the height of the sprite, that row is put back at 0 - basically moving the sprite around the canvas and wrapping it around). I've come up with something that sort of works, but I don't think it's very efficient or even correct.

Code: AGS


function Offset (this DynamicSprite*, int x, int y)
{
  
  DynamicSprite *tempspr = DynamicSprite.Create (this.Width, this.Height);
  DrawingSurface *surface = tempspr.GetDrawingSurface ();
  surface.DrawImage (0+x, 0+y, this.Graphic);
  surface.DrawImage (0+x-this.Width, 0+y, this.Graphic);
  surface.DrawImage (0+x+this.Width, 0+y, this.Graphic);
  surface.DrawImage (0+x, 0+y+this.Height, this.Graphic);
  surface.DrawImage (0+x, 0+y-this.Height, this.Graphic);
  surface.DrawImage (0+x-this.Width, 0+y-this.Height, this.Graphic);
  surface.DrawImage (0+x+this.Width, 0+y+this.Height, this.Graphic);
  surface.DrawImage (0+x-this.Width, 0+y+this.Height, this.Graphic);
  surface.DrawImage (0+x+this.Width, 0+y-this.Height, this.Graphic);
  surface.Release ();
  surface = this.GetDrawingSurface ();
  surface.DrawingColor = 0;
  surface.DrawRectangle (0, 0, this.Width, this.Height);
  surface.DrawImage (0, 0, tempspr.Graphic);
  tempspr.Delete ();
  surface.Release ();
}


Is there an easier way to do this?
#27
Recently I've been hankering to do some programming, and Calin Leafshade's Pixelformer piqued my interest. A platforming sub-engine that uses AGS' built in tools to create levels. I was interested! It looked promising, so I've spent the last couple of days hashing out some more stuff in it. So far I've got objects acting as blocks, wall-jumping, wall-clinging and non-wall-jumpable walls, platforms that rotate and bring you along with them, and both vertical and horizontal floating platforms. All of these are just objects in the room controlled by the room script. Green platforms can be jumped through and jumped down from with down+Z. The scrolling room can be accessed from the left of the room you start in.

Download it here!

I'm not really very good at making platformers, so I'm not sure if the physics are right on or if it's tight enough. I just messed around with the numbers until it 'felt' right. What do you all think? Is it too slippery, or too stiff?
#28
Critics' Lounge / Concept Art - Anatomy?
Tue 08/04/2014 06:42:45
I'm currently doing some concept art for my game, and I want to paint it, but I'm not sure whether the anatomy/composition is as good as it could be before I commit to painting it. I've been at this sketch for a few hours, and I just can't see if I'm slipped up anywhere.



Any advice?
#29
I've recently been fascinated by different character encodings, so I decided to make a Katakana font using JIS X 0201, since that's the only AGS-compatible encoding I can find for japanese text. I don't actually speak the language, but I did try to make them look as accurate as possible.



So, does this look readable? Any mangled kana?

You can get it here if you want to try it out.

The non-JISX0201 characters are:
129 - Star
130 - Heart
131 - Infinity
132 - Cross
133 - White Shogi
134 - Black Shogi
135 - Ankh
136 - Female
137 - Male
138 - Mercury
139 - Note
140 - Quarter Note
141 - Double Note
142 - Double Quarter Note
143 - Flat
144 - Sharp
145 - Lightning
146 - Thunderstorm
147 - Sun
148-157 - 1 to 9 kanji
158 - hundred
159 - thousand
#30
I'm currently working with a few applications of typing out text letter by letter, similar to how old console RPGs did it, and it's working pretty well - except for one thing. When a word is too long for the label text area, it types out as much as it can on one line and then shunts the entire word to the line below, which is very jarring to look at. I'm not sure what the solution is called, so I didn't know what to search for, but does anyone know any tricks/code to make typing out a label compensate for this behaviour? In Heatwave I just did it manually with whitespace and [[, but I don't want to rely on that for the amount of text I need to create.

Any suggestions? I'm not quite sure how to make it type out all the letters in the locations they're going to end up in.
#31
I've been working on elements for my game, and looking through demoscene stuff to get inspiration for some of the SFX I want to use to tell the story with. One of these things is flat shaded 3D models, which I have an affinity for - they look incredibly oldschool, and I do make 3D models as well as pixel art. I know flat shaded 3D prims are possible in AGS, the AGS3D module/plugin is testament to that. Unfortunately, that module/plugin only does 16/32bit, and my game is in 8-bit. Being 8-bit, it also brings up the problem that any shading can't rely on just RGB values. I've been thinking about this, and I think if I hardcode what tri is coloured what palette slot, I may be able to produce 3D images within the bounds of my game's limitations, like so:


The black outline is so that the image can be seen even when the model is turned at an angle, since in this shading model, we wouldn't have the luxury of actual shading or lighting. But because of the lack of actual shading, I can also get away with using less polys for everything. I'd guess the flow would be like this:
1) Load OBJ model
2) Have an array the size of the number of tris in the model, with assigned colours to them
3) Draw the model using the assigned colours onto a full screen drawing surface.
4) Duplicate the drawing surface, have a completely black sprite, and cut out the model's dimensions with CopyTransparencyMask.
5) Draw the sillhouette 4 times, at offsets (0,-1),(0,1),(1,0),(-1,0) onto a new drawing surface
6) Draw the final sprite onto the drawing surface at offset (0,0).

But I'm not actually too up on the programming side of this (I'm an artist :<), and I can't find any old versions of the AGS3D module (the one that uses DrawTriangle) to test it out.

So, how easy would this be to do, and more importantly, would it be fast enough to run real time? I don't need any fancy texture mapping, or lighting, or even high polys, I just need to be able to rotate, scale, and position a model in 3D space. Where would I begin to do something like this?
#32
I'm tweaking these sprites for my game, and I'm not happy with how they're coming out - they look very awkward and inconsistent, and I won't be comfortable animating them until I know I got their basic proportions down.

Namely, these two characters:
[imgzoom]https://dl.dropboxusercontent.com/u/50882197/Ollie_Des_Crit.PNG[/imgzoom]

They both look a little wrong to me, but I'm not sure how. Ollie's (wearing orange/cyan) head looks fine to me, and I want to keep that, but I'm not sure about her body. It looks a little too warped to me, but I dunno how to fix it. Desiree's (wearing blue/red) sprites are just a mess, I can't even get her side head to look alright. (I added Jakob's sprite for reference, he's around the size I need everyone to be to fit on the screen)

Ollie's supposed to be boyish and a little chubby, whilst Desiree is supposed to be more conventionally attractive.

Basically, I'm floundering a bit trying to get their designs down in a way that looks consistent and good, and it's really bugging me. Any pointers y'all can give me?

Thanks in advance!
#33
I'm trying to write a plugin to speed up pixel level functions in AGS, by converting an image into a string (AGS has the String.Chars[] array, which would be much faster to manipulate than Get/SetPixel). I hope to fake a kind of array setup when manipulating pixels, so I can speed up my translucency and colourisation functions for my next game, and maybe even write some more graphics programming type stuff.

I am ludicrously underskilled in C++. I did a bit of C in the old DOS days, but nothing fancy. I at least managed to get the plugin to compile in VS2008 Express. I suppose I gotta start somewhere!


Here's the code I wrote.
Code: C++
const char SerialiseSprite (int id)
{
	unsigned char serialised_image;
	serialised_image = new signed char [engine->GetSpriteWidth (id) * engine->GetSpriteHeight (id)];
	BITMAP *temp = engine->GetSpriteGraphic (id);
	serialised_image = engine->GetRawBitmapSurface (temp);
	engine->ReleaseBitmapSurface (temp);
	return engine->CreateScriptString (serialised_image);
}

int UnSerialiseSprite (const char string, int width,int height)
{
	int sprite = engine->CreateDynamicSprite (8,width,height);
	BITMAP *temp = engine->GetSpriteGraphic (sprite);
	unsigned char imagecontent = engine->GetRawBitmapSurface (sprite);
	imagecontent = string;
	engine->ReleaseBitmapSurface (sprite);
	return sprite;
}

void DestroySprite (int id)
{
	engine->DeleteDynamicSprite (id);
}


Quote.\dllmain.cpp(96) : error C2440: '=' : cannot convert from 'signed char *' to 'unsigned char'
1>        There is no context in which this conversion is possible
1>.\dllmain.cpp(98) : error C2440: '=' : cannot convert from 'unsigned char **' to 'unsigned char'
1>        There is no context in which this conversion is possible
1>.\dllmain.cpp(100) : error C2664: 'IAGSEngine::CreateScriptString' : cannot convert parameter 1 from 'unsigned char' to 'const char *'
1>        Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
1>.\dllmain.cpp(107) : error C2664: 'IAGSEngine::GetRawBitmapSurface' : cannot convert parameter 1 from 'int' to 'BITMAP *'
1>        Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
1>.\dllmain.cpp(109) : error C2664: 'IAGSEngine::ReleaseBitmapSurface' : cannot convert parameter 1 from 'int' to 'BITMAP *'
1>        Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast

This is the error it kicks out. I know this is simple stuff, but I don't understand it at all. Stuff I take for granted in AGSScript doesn't seem to carry over to C++, and it's a little embarrassing. Especially the "char" types. I'm not sure how to fix this?

Thankyou in advance :)
#34

HEATWAVE

You are but mere words.
Would you speak as with that mask,
With what lies underneath?





Heatwave is a short story set in the same world as Death Wore Endless Feathers. It takes place in a future California, where Dai Araiguma is playing a VR game in the middle of an abnormally tenacious heatwave.

Originally developed as a MAGS game, it took way too long, so I decided to extend it a little and give it a lot of polish. It features a full soundtrack and quite a few animations. I hope you all enjoy it!

ZIP VERSION
SELF EXTRACTING EXE


The game's entry in the archives.
#35
I'm trying to polish up my game, and in order to sync some animation to music, I count game frames (I increment an integer every frame when the music starts and count what number it is). I have VSync on (turning it off sometimes makes the cutscene skip way far ahead), and have set my game's speed to 60, but I'm having some really spotty syncing issues.

Sometimes the music will get a second ahead of the action, and that feels awful and clunky, and all the action gets the life sucked out of it. And sometimes it'll go TOO fast.

Is there a way to consistently know how much time has passed since the song has begun in smaller increments than a second? I don't want some people getting the outro cutscene how it should be, and some people getting a desynced mess. I know 3.3.0 has PositionMs for tracker music, but I'm wary of using a beta for a final release.
#36
Okay, so I'm trying to emulate the Discworld inventory system using AGS, and it's running pretty smoothly. I have double clicks, inventory items being takeable from the inventory, putting down items and picking them up again. But there's one thing, in my awful, awful code that I cannot get it to do for some reason, and it's been bugging me for the entire time I've been working on the game.

And that is, when I click on a space in the inventory occupied by the active inventory (the inventory slot while you have it active is blanked out, making it look empty) the item gets put down and immediately picked back up again, and I'm not sure why this is happening. I can't give the entire project, as it's so close to completion now, but here's the click code I'm using:

Code: AGS

int mx, my, lastclick;
int clickdelay = 15;
bool itemvisible;
bool inventoryvisible;
int clicktype;
int clickbuffer;
InventoryItem* itemclicked;
 int itemtimeout;

function left_click(bool single, ClickType type) 
{
  if (single && type == eClickField) 
  {
    // single-click on field code. not important to the example.
  }
  else if (!single && type == eClickField)
  {    
    // double-click on field code. Also not important
  }
  else if (single && type == eClickInventory && clickbuffer == 0) //Single Click on inventory.
    {
      bool newitem = false;
      InventoryItem* item = itemclicked;
      if (player.ActiveInventory != null)
          {
            if (item != player.ActiveInventory) newitem = true;
            ReturnInventory ();
            if (newitem)
                {
                  //Display ("NEWITEM");
                  player.ActiveInventory = item;
                  gItem.BackgroundGraphic = item.CursorGraphic;
                  item.Graphic = 32;
                  if (mouse.x - 16 > 0 ) gItem.X = mouse.x - 16;
                  if (mouse.y - 10 > 0 ) gItem.Y = mouse.y - 10;
                  gItem.Visible = true;
                }
            item = null;
            itemtimeout = 50; //To stop the lower conditional from being run, but doesn't work.
            return;
          }
      else if (player.ActiveInventory == null) //Should be run only when you don't have an inventory item, and have clicked on one.
          {                                        //For some reason, it's run directly after the above conditional?????
                //Display ("NO INV");
                if (itemtimeout) return; //This should stop the player from picking up the item right back up again, but it doesn't work!
                else
                    {
                      player.ActiveInventory = item;
                      gItem.BackgroundGraphic = item.CursorGraphic;
                      item.Graphic = 32;
                      if (mouse.x - 16 > 0 ) gItem.X = mouse.x - 16;
                      if (mouse.y - 10 > 0 ) gItem.Y = mouse.y - 10;
                      gItem.Visible = true;
                    }
          }    
     }
  else if (!single && type == eClickInventory && clickbuffer == 0)
    {
         if (player.ActiveInventory != null)
             {
                   if (inventory [game.inv_activated].IsInteractionAvailable(eModeUseinv))
                        {
                              inventory [game.inv_activated].RunInteraction (eModeUseinv);
                        }
         else unhandled_event (5, 3);
     }
   else 
         {
            if (inventory [game.inv_activated].IsInteractionAvailable(eModeInteract))
                  {
                    inventory [game.inv_activated].RunInteraction (eModeInteract);
                  }
            else unhandled_event (5, 1);
         }
    }
}

function repeatedly_execute() {
  if (lastclick>0 && lastclick<=clickdelay) lastclick++;
  else if (lastclick>clickdelay) 
    {
        lastclick=0;
        left_click(true, clicktype);
    }
  
  if (itemtimeout) itemtimeout --;
}


function on_mouse_click(MouseButton button) 
{
  // called when a mouse button is clicked. button is either LEFT or RIGHT
  
    if (GUI.GetAtScreenXY (mouse.x, mouse.y) != gInventory && gInventory.Visible == true) 
        {
              gInventory.Visible = false;
              inventoryvisible = false;
        }

    else if (button == eMouseLeft) 
        {
               int mxdist = AbsInt(mouse.x - mx);
               int mydist = AbsInt(mouse.y - my);
    
               if (lastclick>0 && mxdist < 3 && mydist < 3) 
                    {
                          lastclick=0;
                          left_click(false,  eClickField);  
                    }
                else 
                    {
                          lastclick=1;
                          mx=mouse.x;
                          my=mouse.y;
                          clicktype = eClickField;
                    }
        }
    else if (button == eMouseRight)
        {
              if (player.ActiveInventory != null) 
                  {
                        if (player.ActiveInventory != iWires) ReturnInventory (); //Special dispensation for game entity that isn't actually an inventory item.
                        else 
                              {
                                    player.Say ("I'll just put these back.");
                                    ReturnInventory ();
                                    player.LoseInventory (iWires);
                              }
        
                  }
              else ProcessClick (mouse.x, mouse.y, eModeLookat);
        }
    else if (button == eMouseLeftInv && itemtimeout == 0)
        {
            //Display ("Clicking Inventory");
            if (GUIControl.GetAtScreenXY (mouse.x, mouse.y) == invInventory)
                {
                    int mxdist = AbsInt(mouse.x - mx);
                    int mydist = AbsInt(mouse.y - my);
    
                    if (lastclick>0 && InventoryItem.GetAtScreenXY (mouse.x, mouse.y) == itemclicked) 
                        {
                            lastclick=0;
                            left_click(false, eClickInventory);
                            itemclicked = null;
                        }
                    else 
                        {
                            lastclick=1;
                            mx=mouse.x;
                            my=mouse.y;
                            clicktype = eClickInventory;
                            itemclicked = InventoryItem.GetAtScreenXY (mouse.x, mouse.y);
                        }
                  }
         }
    else if (button == eMouseRightInv)
         {
               InventoryItem* itemlook = InventoryItem.GetAtScreenXY (mouse.x, mouse.y);
               itemlook.RunInteraction (eModeLookat);
         }
}

function ReturnInventory ()
{
  aDrop.Play (eAudioPriorityHigh, eOnce);
  InventoryItem* item;
  item = player.ActiveInventory;
  item.Graphic = gItem.BackgroundGraphic;
  gItem.Visible = false;
  itemvisible = false;
  player.ActiveInventory = null;
}


Again, everything BUT putting items back in their own slot works fine. If you try and put the item back in it's own slot, it just pops back onto the mouse again, or it stays in the inventory randomly if you double click or quickly move the mouse away.

The behaviour I want is this: When you single click on an item when you have an active inventory item, it swaps that item with the one you're holding. If you click on an empty space OR the space where the Active Inventory actually is (and invisible), it returns your active inventory to the inventory window and leaves you with nothing.

The current behaviour is this: When you single click on an item when you have an active inventory item, it swaps that item with the one you're holding. If you click on an empty space, it returns your inventory. If you click on the space your item is in normally, it puts the item down and immediately swaps it with itself, leaving you with the exact same item in hand.

There's got to be something simple I'm just blind to.

I have no idea what I'm doing wrong. I'm like 3 days from releasing this game and this bug is being nigh impossible to crush!

Thankyou for any help at all.
#37
I'm trying to put an ident into my game using PlayFlic (as FLCs do these kinds of full screen animations more efficiently than AGS' inbuilt animation) but I've come across a bit of a problem - the first frame of the animation is corrupted, and I'm not sure how to solve it. The rest of the animation works fine - the frames appear to be delta encoded and soon cut through the corruption, but the first frame doesn't seem to exist. I made it with Jasc Animation Shop 3, and checked it with Autodesk Animator Studio Player.

Here's what the (corrupted) frame looks like:
[imgzoom]https://dl.dropboxusercontent.com/u/50882197/Game/Heatwave/error/corruption.PNG[/imgzoom]

Here's the FLC file: https://dl.dropboxusercontent.com/u/50882197/Game/Heatwave/error/FLIC0.flc
And here's the game's palette: https://dl.dropboxusercontent.com/u/50882197/Game/Heatwave/error/palette.bmp

It's definitely not a palette issue, as then colours are all the right kind - but... it's just not working. I've used all the FLC playing options, and opening the FLC in other programs doesn't produce the same result. What's going on here?
#38
I'm syncing up some music to my game's intro, but to my horror, I've found that I can't make tracker music sync with the action at all. The Position property is pretty much useless (It increments once every 5 seconds, which is not what I want), and PositionMs doesn't work at all, even though the documentation said it worked with all formats but MIDI.

I'm currently timing the action with this code:
Code: AGS
  if (intromus != null && intromus.IsPlaying) lblMusicTime.Text = String.Format ("%d",intromus.PositionMs);


I tried to play a silent MIDI on another channel... but apparently you're not allowed to play both an XM and a MIDI at the same time.

Am I just using it wrong? I don't want to use MP3 music, but AGS' syncing capabilities seem to be sorely lacking when it comes to non-digital music - I could just try to find MIDI music, but I don't like the sound of them compared to tracker music.
#39
I'm trying to import some sprites into my game, and they do have black outlines. Unfortunately, AGS goes absolutely ape when you try and import a sprite that has 0,0,0 in any slot that isn't the transparent one. If 0,0,0 is the transparent colour, AGS will absolutely mutilate the sprite's darker colours that aren't black. I changed the transparent colour to RGB magenta to see if that would help matters, but all it did was change the black on import to white. This is using "top left" transparency, so it really shouldn't be doing this to any of the colours, and I have an actual palette slot for black. AGS just seems to have it out for really dark colours.

This is killing my ability to carry on with my game, and I'm not sure what to do. I don't have my computer at the moment, so I can't use my regular paletted paint programs to fix the problem, but I still need to work on my game.

What is AGS doing to actively mutilate every 8 bit image you give it? Can it be solved? Are there any workarounds?

Edit: Opening the sprite in MSPaint (from the sprite editor) and pasting in the correct version seems to solve the problem. Something feels wrong about that solution.
#40
I'm trying to code a dynamic colour thing in AGS, so that I can change the colours of particular palette slots to emulate some neat effects. One of these is a shifting rainbow effect - going through hues smoothly and wrapping around. I would easily be able to do this kind of thing if I did it in HSV rather than RGB, as HSV has direct control over what a colour looks like, not it's light components.

Unfortunately, I'm at a bit of a loss figuring out how to do HSV to RGB at all. I'm looking at the formula to convert between the two colour systems, and I don't understand it. I've tried to convert the formula to AGSScript, but... it has syntax I'm not familiar with. Such as "C = V x SHSV". I'm not entirely sure what I'm doing.

Any suggestions for converting between colour formats?
SMF spam blocked by CleanTalk