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 - .M.M.

#1
Thank you for all the kind words!  :)
Quote from: Rik_Vargard on Sun 01/06/2025 19:39:06I'm wondering how you do the whole "new fashion" thing? Are the clothes "objects following the character"  or... I can't imagine having sprites for every combination  8-0

Ha ha, you're right, just imagining handcrafting sprites for every combination is making my head spin.  (laugh)
The way it is set up is by using spritesheets for each part of the bodypart/equippable item which is then combined, creating dynamic sprites for each frame of the animation. Kind of like preparing seperate views for each part (boots, trousers, torso, weapon) and then drawing each frame on top of the other to generate the final views. :)

There is actually a thread about this system in Advanced technical forum, but I'm not sure I should reccomend reading  it - it's about a problem I'm having with the system.  (roll) But ingame, everything works smoothly!
#2
Howdy everyone!
It's been a long time since last update, but the work goes on.  :)
Just recently, Desert Rails has hit a huge milestone - as of now, all the (human) character animations are in place, including the player. Nothing stops you now from creating your own fashion style, ranging from serious to quirky. Hooray!

Here's a small peak:


Of course, that being said, there's still quite a lot to do graphics-wise. Next step is finishing animations for the coyote and pushing some room backrounds from "placeholder state" to final look.
Then it's mostly about minor writing updates and gameplay balance testing - and finally, showing the first part of the game in a demo.  :)

Realistically, I don't expect it to happen soon, but it's nice seeing the progress and getting closer and closer!
#3
Quote from: Khris on Sun 25/05/2025 11:10:59One thing I've noticed:
Code: ags
  i_loop - 8*(i_loop/8) == 2
can be shortened to
Code: ags
  i_loop % 8 == 2

Oh, thanks, that's great! I'll start using it from now on.  :)


Quote from: Khris on Sun 25/05/2025 11:10:59If I had to debug this I'd probably refactor the code into a bunch of separate functions. Using one massive function and tons of variables makes this a pain to debug.

I guess that's the way to go. First I'll try to go through the whole function once more, and if that doesn't help, I'll have to split it into separate parts and debug them individually. Thank you for taking your time with it!  :)

[EDIT]
I guess what might be happening is that the array of dynamic sprites walk_frame inside CustomView is interconnected? Meaning that the value for CustomView[number1].walk_frame[number2].Graphic used by the view might change without accessing it, simply by changing the total number of sprites stored in the variable - is it possible?
#4
Hello all,

It seems I've hit a wall with my poor coding skills.  :(
I have a code that creates custom animations based on what the player is equppied with (both clothes and weapons). The original worked like this: each item had custom properties linked with views for each of the default action, the script took sprites from those views and combined into the final look. This worked fine, however, it was tedious and time consuming work setting up all the initial "item views". So I've reworked it - now, the item property points to a sprite with a spritesheet, and the script takes those spritesheets, combines them and transforms it into the final view.
For some reason I can't understand, sometimes it does not work properly. The only part that causes problems is the attack view part - it might be because as opposed to walk and death views, the attack views's differ in number of frames per view and the frame size.
What happens is that especially in the "unarmed" view, some frames are mixed in from different views - ingame it might look as if instead of taking a battle stance with raised fists, a random part of shooting a gun is shown (even from different loop, and not from the first frame).
As you can see from the script, I've tried debugging it by saving the sprites from the sprite array, to actually see what's going on inside. In the folder "sprite_array", it seems there are some leftover sprites if they are not used. For example view[8] used to show attack with a handgun, now it stores attack with a knife - the handgun animation had more sprites, so there are some unused sprites with a handgun at the end. Seems it works as expected.
Now, the "view_array" folder stores all the actual sprites used in the displayed views - and everything looks exactly right. But ingame one of the animation is broken - even though the log panel shows the correct view and loop number is used for the animation, the graphic shown in game doesn't match what's stored in the folder. And honestly, I have no idea how that would even be possible. I must have missed some small detail somewhere!

Sorry for the length and probably overall poor quality of the code - this is what happens when someone with no coding education keeps editing and reworking something for the past 10 years.  (roll)

I totally understand if it's just too much to go through, but maybe someone will be able to spot the problem right away! Or maybe there's some problem right in the core of the idea?

Thank you all! :)

Code: ags
struct ViewGenerating {
DynamicSprite *walk_frame[75]; // maximum should be 8 loops with 9 frames = 72 frames
};

ViewGenerating CustomView[10];
int i_view;
ViewFrame *frame_new;
ViewFrame *frame_old;
DynamicSprite *gv_sprite_base;
DrawingSurface *gv_sprite_base_surface;

function GenerateView(this Character*, ViewType type, int view_index)
{
 // view_index = 0, 1, 2 (based on the weapon)
 i_loop = 0;
 gv_sheet_loop = 0;
 i_loop_frame = 0; // the frame number of the current loop
  /*
  view_clothes[] index:
  shadow    7
  X NOT USED back arm  7
  shoes     6
  trousers  5
  vest      4
  X NOT USED front arm 3
  weapon    3
  hat       2
  (slot 1 and 0 free for now)
  */
 
 if (type == eViewWalk) {
  view_clothes[7] = 20; // shadow sprite
  if (weapon_slot[7] != null) view_clothes[2] = weapon_slot[7].GetProperty("IGWalk"); 
  else view_clothes[2] = 0; // 7 is hat, 0 means skip; index 2 sends it to front
  if (weapon_slot[6] != null) view_clothes[6] = weapon_slot[6].GetProperty("IGWalk"); 
  else view_clothes[6] = 999; // change to sprite number
  if (weapon_slot[5] != null) view_clothes[5] = weapon_slot[5].GetProperty("IGWalk"); 
  else view_clothes[5] = 999; // change to sprite number
  if (weapon_slot[4] != null) view_clothes[4] = weapon_slot[4].GetProperty("IGWalk"); 
  else view_clothes[4] = 999; // change to sprite number
  if (weapon_slot[view_index] != null)
  {
   if (weapon_slot[view_index].GetProperty("weapon_type") == 0)
   {
    if (weapon_slot[view_index].GetTextProperty("special_bonus") == "knife") view_clothes[3] = 13; //view_clothes = sprite number
    else if (weapon_slot[view_index].GetTextProperty("special_bonus") == "axe") view_clothes[3] = 13; // UPDATE WHEN READY
    else if (weapon_slot[view_index].GetTextProperty("special_bonus") == "saber") view_clothes[3] = 13; // UPDATE WHEN READY
    else view_clothes[3] = 0; // fist,  no weapon
   }
   else if (weapon_slot[view_index].GetProperty("weapon_type") == 1) view_clothes[3] = 15;
   else if (weapon_slot[view_index].GetProperty("weapon_type") == 2) view_clothes[3] = 17;
   else view_clothes[3] = 0; // medkit
  }
  else view_clothes[3] = 0; // null weapon
  
  i_view = view_index; // i_view - sets the index for storing sprites (0-8); 0, 1, 2 = walk, 3, 4, 5 = death, 6, 7, 8 = attack
  if (view_index == 0) view_to_generate = PLAYER_WALK0;
  else if (view_index == 1) view_to_generate = PLAYER_WALK1;
  else if (view_index == 2) view_to_generate = PLAYER_WALK2;
  else
  {
   Display("Wrong parameter of GenerateView function.");
   return -1;
  }   
 }
 else if (type == eViewDeath) {
  view_clothes[7] = 37; //shadow 
  if (weapon_slot[7] != null) view_clothes[2] = weapon_slot[7].GetProperty("IGDeath"); 
  else view_clothes[2] = 0; // 7 is hat, 0 means skip
  if (weapon_slot[6] != null) view_clothes[6] = weapon_slot[6].GetProperty("IGDeath"); 
  else view_clothes[6] = 999; // CHANGE TO SPRITE NUMBER 
  if (weapon_slot[5] != null) view_clothes[5] = weapon_slot[5].GetProperty("IGDeath"); 
  else view_clothes[5] = 999; // CHANGE TO SPRITE NUMBER
  if (weapon_slot[4] != null) view_clothes[4] = weapon_slot[4].GetProperty("IGDeath"); 
  else view_clothes[4] = 999; // CHANGE TO SPRITE NUMBER
  if (weapon_slot[view_index] != null)
  {
   if (weapon_slot[view_index].GetProperty("weapon_type") == 0) {
    if (weapon_slot[view_index].GetTextProperty("special_bonus") == "knife") view_clothes[3] = 42; // sprite knife death
    else if (weapon_slot[view_index].GetTextProperty("special_bonus") == "axe") view_clothes[3] = 0;
    else if (weapon_slot[view_index].GetTextProperty("special_bonus") == "saber") view_clothes[3] = 0;
    else view_clothes[3] = 0;
   }
   else if (weapon_slot[view_index].GetProperty("weapon_type") == 1) view_clothes[3] = 41; // sprite handgun death
   else if (weapon_slot[view_index].GetProperty("weapon_type") == 2) view_clothes[3] = 43;
   else view_clothes[3] = 0;
  }
  else view_clothes[3] = 0;
  i_view = view_index+3; // is i_view neccessary?
  if (view_index == 0) view_to_generate = PLAYER_DEATH0;
  else if (view_index == 1) view_to_generate = PLAYER_DEATH1;
  else if (view_index == 2) view_to_generate = PLAYER_DEATH2;
  else
  {
   Display("Wrong parameter of GenerateView function.");
   return -1;
  }
 }
 else if (type == eViewAttack)
 {
  if (weapon_slot[view_index] == null) // nothing => fighting with fists view
  { 
   view_to_generate = PLAYER_A_NULL;
   gv_property = "IGAFist";
  }
  else if (weapon_slot[view_index].GetProperty("weapon_type") == 0) // close combat
  {
   if (weapon_slot[view_index] == iFist)
   {
   view_to_generate = PLAYER_A_NULL;
   gv_property = "IGAFist";
   }
   else
   {
   gv_property = "IGAKnife";
   view_to_generate = PLAYER_A_KNIFE;
   }
  }
  else if (weapon_slot[view_index].GetProperty("weapon_type") == 1) // handguns
  {
   view_to_generate = PLAYER_A_GUN;
   gv_property = "IGAGun";
  }  
  else if (weapon_slot[view_index].GetProperty("weapon_type") == 2) // rifles
  {
   view_to_generate = PLAYER_A_RIFLE;
   gv_property = "IGARifle";
  }
  else // medkits or fallthrough
  {
   view_to_generate = PLAYER_A_NULL;
   gv_property = "IGAFist";
  }
  i_view = 6+view_index; // i_view for attacks: 6, 7, 8
  player_attack_view[view_index] = view_to_generate;  
  gv_i = 7;
   while (gv_i > 3) // other layers handled separately
   {
    if (weapon_slot[gv_i] != null)
    {
     if (gv_i == 7) // hat
     {
      view_clothes[2] = weapon_slot[7].GetProperty(gv_property);
      view_clothes_transition[2] = weapon_slot[7].GetProperty(gv_property.Append("Transition"));
     }
     else
     {
      view_clothes[gv_i] = weapon_slot[gv_i].GetProperty(gv_property);
      view_clothes_transition[gv_i] = weapon_slot[gv_i].GetProperty(gv_property.Append("Transition"));
     }
    }
    else
    { // empty sprites
     if (gv_i == 7) // HAT - specific, no hat means no sprite
     {
       view_clothes[2] = 0;
       view_clothes_transition[2] = 0;      
     }
     if (view_to_generate == PLAYER_A_NULL)
     {
      if (gv_i == 6) // SHOES
      {
       view_clothes[gv_i] = 999;
       view_clothes_transition[gv_i] = 999;      
      }
      else if (gv_i == 5) // TROUSERS
      {
       view_clothes[gv_i] = 999;
       view_clothes_transition[gv_i] = 999;      
      }
      else if (gv_i == 4) // VEST
      {
       view_clothes[gv_i] = 999;
       view_clothes_transition[gv_i] = 999;      
      }
     }
      else if (view_to_generate == PLAYER_A_KNIFE || view_to_generate == PLAYER_A_SABER || view_to_generate == PLAYER_A_AXE)
     {
      if (gv_i == 6) // SHOES
      {
       view_clothes[gv_i] = 999;
       view_clothes_transition[gv_i] = 999;      
      }
      else if (gv_i == 5) // TROUSERS
      {
       view_clothes[gv_i] = 999;
       view_clothes_transition[gv_i] = 999;      
      }
      else if (gv_i == 4) // VEST
      {
       view_clothes[gv_i] = 999;
       view_clothes_transition[gv_i] = 999;      
      }
     }
     else if (view_to_generate == PLAYER_A_GUN)
     {
      if (gv_i == 6) // SHOES
      {
       view_clothes[gv_i] = 999;
       view_clothes_transition[gv_i] = 999;      
      }
      else if (gv_i == 5) // TROUSERS
      {
       view_clothes[gv_i] = 999;
       view_clothes_transition[gv_i] = 999;      
      }
      else if (gv_i == 4) // VEST
      {
       view_clothes[gv_i] = 999;
       view_clothes_transition[gv_i] = 999;      
      }
     }
     else if (view_to_generate == PLAYER_A_RIFLE)
     {
      if (gv_i == 6) // SHOES
      {
       view_clothes[gv_i] = 999;
       view_clothes_transition[gv_i] = 999;      
      }
      else if (gv_i == 5) // TROUSERS
      {
       view_clothes[gv_i] = 999;
       view_clothes_transition[gv_i] = 999;      
      }
      else if (gv_i == 4) // VEST
      {
       view_clothes[gv_i] = 999;
       view_clothes_transition[gv_i] = 999;      
      }
     }
    }
    gv_i --;
   }
   // VIEW SPECIFIC SPRITESHEETS
   if (view_to_generate == PLAYER_A_NULL)
   {
    view_clothes[7] = 84; // shadow sprite
    view_clothes_transition[7] = 372;
    view_clothes[3] = 0; // weapon sprite
    view_clothes_transition[3] = 0;
   }
   else if (view_to_generate == PLAYER_A_KNIFE || view_to_generate == PLAYER_A_SABER || view_to_generate == PLAYER_A_AXE)
   {
    view_clothes[7] = 21; // shadow sprite
    view_clothes_transition[7] = 32;
    if (view_to_generate == PLAYER_A_SABER)
    {
     view_clothes[3] = 0; // weapon sprite
     view_clothes_transition[3] = 0;
    }
    else if (view_to_generate == PLAYER_A_AXE)
    {
     view_clothes[3] = 0; // weapon sprite
     view_clothes_transition[3] = 0;
    }
    else // knife
    {
     view_clothes[3] = 98; // weapon sprite
     view_clothes_transition[3] = 99;
    }
   }
   else if (view_to_generate == PLAYER_A_GUN)
   {
    view_clothes[7] = 55; // shadow sprite
    view_clothes_transition[7] = 44;
    view_clothes[3] = 0; // weapon sprite
    view_clothes_transition[3] = 0;
   }
   else if (view_to_generate == PLAYER_A_RIFLE)
   {
    view_clothes[7] = 100; // shadow sprite
    view_clothes_transition[7] = 101;
    view_clothes[3] = 0; // weapon sprite
    view_clothes_transition[3] = 0;
   }        
  }
 
 // setup the base size of the sprite
 
 loopcount = Game.GetLoopCountForView(view_to_generate);
 framecount = Game.GetFrameCountForLoop(view_to_generate, 0);
 i_frame = 0; // loops through the complete array for dynamic sprites
 i_loop = -1; // first tick 
 // draw the sprites
 while (i_loop < loopcount)
 {
  if (i_loop_frame == framecount || i_loop == -1)
  {
   i_loop_frame = 0;
   i_loop ++;
   if (i_loop >= loopcount) break;
   // setup which line of spritesheet to use
   if ((i_loop - 8*(i_loop/8)) == 2) gv_sheet_loop = 1;
   else if ((i_loop - 8*(i_loop/8)) == 3) gv_sheet_loop = 2;
   else if ((i_loop - 8*(i_loop/8)) == 4 || (i_loop - 8*(i_loop/8)) == 6) gv_sheet_loop = 3;
   else if ((i_loop - 8*(i_loop/8)) == 5 || (i_loop - 8*(i_loop/8)) == 7) gv_sheet_loop = 4;
   else gv_sheet_loop = i_loop - 8*(i_loop/8); // makes sure it works for transition too
   if (i_loop < Game.GetLoopCountForView(view_to_generate))
   {
    framecount = Game.GetFrameCountForLoop(view_to_generate, i_loop);
    if (i_loop == 0 || i_loop == 8)
    {
     // start and transition - change the base size of the sprite
     if (i_loop == 0)
     {
      gv_frame_width = PlayerAnimSize[view_to_generate].Width;
      gv_frame_height = PlayerAnimSize[view_to_generate].Height;
     }
     else if (i_loop == 8)
     {
      gv_frame_width = PlayerAnimSize[view_to_generate].TransitionWidth;
      gv_frame_height = PlayerAnimSize[view_to_generate].TransitionHeight;
     }

   if (CustomView[i_view].walk_frame[i_frame] == null) CustomView[i_view].walk_frame[i_frame] = DynamicSprite.Create(gv_frame_width, gv_frame_height, true); // new sprite created
   else CustomView[i_view].walk_frame[i_frame].ChangeCanvasSize(gv_frame_width, gv_frame_height, 0, 0);
   viewsurface = CustomView[i_view].walk_frame[i_frame].GetDrawingSurface(); // surface created from dynamic sprite from the view
   viewsurface.Clear();
   if (i_loop == 0 && i_loop_frame == 1)
   {
   // space for debug message
   }
   i_count = 7; // index of layers, from back to front
   while (i_count > 1) // 0 and 1 is unused for now, can be changed - hairstyles?
   { // cycle through
    if (i_loop < 8)
    { // standard loops
     if (view_clothes[i_count] != 0) viewsurface.DrawImage(0, 0, view_clothes[i_count], 0, gv_frame_width, gv_frame_height, gv_frame_width*i_loop_frame, gv_frame_height*gv_sheet_loop, gv_frame_width, gv_frame_height);
    }
    else
    { // transition - change the spritesheet
     if (view_clothes_transition[i_count] != 0) viewsurface.DrawImage(0, 0, view_clothes_transition[i_count], 0, gv_frame_width, gv_frame_height, gv_frame_width*i_loop_frame, gv_frame_height*gv_sheet_loop, gv_frame_width, gv_frame_height);
    }
    i_count --;
   }
   viewsurface.Release(); // done with one frame
   
   frame_new = Game.GetViewFrame(view_to_generate, i_loop, i_loop_frame);
   frame_new.Graphic = CustomView[i_view].walk_frame[i_frame].Graphic;
   if (type == eViewAttack) // only part that causes problems
   {
    file_name_debug = String.Format("$SAVEGAMEDIR$/view-%d_frame-%d_loop-%d_frame-%d.bmp", i_view, i_frame, i_loop, i_loop_frame);
    CustomView[i_view].walk_frame[i_frame].SaveToFile(file_name_debug);
    
    file_name_debug = String.Format("$SAVEGAMEDIR$/sprites_array/view-%d_frame-%d.bmp", i_view, i_frame);
    CustomView[i_view].walk_frame[i_frame].SaveToFile(file_name_debug);
    
    file_name_debug = String.Format("$SAVEGAMEDIR$/view_array/%d/loop-%d_frame-%d.bmp", view_to_generate, i_loop, i_loop_frame);
    DynamicSprite *debug_sprite = DynamicSprite.CreateFromExistingSprite(frame_new.Graphic);
    debug_sprite.SaveToFile(file_name_debug);
    
   
   }
   i_loop_frame ++;
   i_frame ++;
 }
}
#5
Quote from: newwaveburritos on Mon 18/11/2024 03:00:56This is certainly ambitious and looks great!  Good luck with production.

Thanks! It will take some time still, but I'm slowly getting there.  :)

Quote from: Haggis on Wed 04/12/2024 09:36:15A western RPG - count me in!
Love the visuals. Good luck getting over the finish line.

Thank you! I can see you have a soft spot for western theme, I have to check out your game, too. :)

Quote from: CaptainD on Thu 05/12/2024 20:42:58This looks incredibly ambitious! Hope development goes well.

However...

Quote• lots of sand

Anakin disapproves.  :-D

Thanks! The game also features height system, so you can even have the high ground.  :-D


Development is moving steadily forward, although December is usually the most intense month work-wise, there should be plenty of time during the holidays. Right now, the first part of the game (which will be included in the demo) is playable - the next milestone is getting it from playable to presentable.  :) This means some slight tweaks in gameplay, but mostly finishing background art and animation.

Here is a little sneak peek at one of the new animations in the making!

#6
Quote from: heltenjon on Mon 11/11/2024 18:54:09This looks like a promising project! I feel an urge to play your first game while waiting for this one.  ;) While no big rpg fan, I have a thing for westerns, and this made my trigger finger itch.

"Lots of sand!"  (laugh)

Thanks, heltenjon! I see it's actually still possible to download and play thanks to the archive. :) It's way more simple and rough around the edges, but I think it's still worth trying. It takes around 90 minutes to finish, possibly more if you take all the sidequests. :)
And there's plenty of shoot-outs for an itchy trigger finger.  :-D

Quote from: Creamy on Mon 11/11/2024 19:13:35It looks much better than the old version.
I had never played the first version so I gave it a try. The mechanics seem pretty advanced.

I didn't go far but one plot point piqued my curiosity:
in the game, you're forced to pay for the debts of your deceased brother.
I'm not familiar with US or common law so I wonder if it could have happened legally.
In the Civil code, you could always refuse an inheritance.
Of course it may just be another case of sheriff corruption since it's the wild west :D

Thank you, Creamy, I'm glad the effort put into the progress has shown.  :)

The plot point was there to show that this person was above the law in the town. He could make you do that just because he thought it was right, disregarding whether it had any legal base or not. It is actually possible to inherit debt, but this is not the case. And you can always refuse. Again, not here. :-D

Even though Desert Rails and Only the Good Die Young will have similarities, all the texts and dialogues will be rewritten. Hopefully the improvement will be as significant as with the graphics.  :)
#7
Thank you, Matti! :)
It's great to read this especially after keeping the project to myself for quite some time.  :)
#8




The story

Standing at the grave of his deceased brother, Jack Smith promises to find the killer and avenge his brother's death. But the US frontier can be a treacherous place, and before Jack realizes, he's dragged deep into a fight – for his brother's legacy, for the fate of the town of Providence, and for his own life.




Features

    • RPG with turn-based combat
    • levelling system with various active and passive skills
    • main storyline with 2 different endings and multiple side quests
    • branching dialogues and quests: it's up to you whether you prefer to sweet-talk your way out of dangerous situations, or whether you're more inclined towards the approach of "a punch is worth a thousand words"
    • fully animated isometric action
    • lots of sand




Explore the town Providence and its surroundings.



Gear up according to your needs and the latest fashion.



Unwind – or start a fight – in the local saloon.



Survive the many dangers of the Wild West!



Roadmap

    • writing: 70%
The outline is more or less finished, there's still a lot of text and dialogs missing though.

    • scripting: 85%
The core systems are in place – hooray! But as more content will be added, some tweaks will surely be necessary.

    • interface: 90%
What you see on the screenshots should be pretty close to the finished thing.

    • graphics: 65%
There's a lot missing – some animations, many room backgrounds, new portrait style... But it's getting to a phase where it's more about what's missing than what is actually there, which to me is a huge leap forward.

    • sound and music: 30%
Some basic sound effects are in, most is still to be planned and done.

All this of course counts on me not deciding to make a 100th iteration of some part of the game.  :)




Remake?

Yes, this project originally started as a "quick" remake of my previous game, Only the Good Die Young. At first, the idea was to just transfer the action RPG into a turn based one, creating a foundation for the next project in different setting.
Many years later, there's not much left of the original game: the dialogues are completely rewritten, some parts and areas are changed altogether. But it is still the same story with very similar characters (just more fleshed out) at it's core. It's actually a very entertaining exercise, taking an outline of the story and giving it more life, changing its pacing and hopefully, transforming it into something way bigger and better.



What's next?

There's a long way ahead of me for releasing the full game. But in the meantime, I plan to put together a trailer and later release a playable demo.




Stay tuned and thank you for reading!


#9
@Crimson Wizard No errors with the new build, everything runs smoothly. Thank you!  :)
#10
Great work everyone, I love the way AGS gets constantly better and better with time - the log panel window is a perfect addition!

Unfortunately, every time I close the game, I get an error message:
Quote---------------------------
Illegal exception
---------------------------
An exception 0xC0000005 occurred in ACWIN.EXE at EIP = 0x0050387A; program pointer is +9904, engine version , gtags (10,70)

AGS cannot continue, this exception was fatal. Please note down the numbers above, remember what you were doing at the time and contact the game author for support or post these details on the AGS Technical Forum.



Most versions of Windows allow you to press Ctrl+C now to copy this entire message to the clipboard for easy reporting.

An error file CrashInfo.dmp has been created. You may be asked to upload this file when reporting this problem on the AGS Forums. (code 0)
---------------------------
OK   
---------------------------

I tried reinstalling (BETA 5 version), but it keeps showing up. I don't see any problem with the project - is it safe for the project files if I just continue working and ignore the error message for now?
#11
Quote from: Crimson Wizard on Mon 12/09/2022 20:36:14There have been a bug in 3.6.0 which caused this, please make sure you're using the latest update of 3.6.0.

Quote from: Dave Gilbert on Thu 22/09/2022 19:36:12This happened to me a few months ago. Not fun, but it's unrelated to speech center. The bug has been fixed, so be sure to update AGS. Also, remember that backups are your friend!

Thank you for clarifying and sorry for sounding a bit... dramatic.  :)
I've found a backup with literally just a few lines missing, so it caused no harm in the end, but I'll remember to check for updates regularly while using beta builds next time. :)

And thank you, SpeechCenter, for this great tool!
#12
Hi there,

The plugin looks really cool and useful, but fore some reason, all my dialog text got wiped out. In every dialog in the project. The options were not affected, everything else is suddenly blank. I'm using AGS build 3.6.0.31 if it helps.
I have some backups, so it should all be okay, but I'm not sure whether someone reported this or had similar problems.
#13
Wow, playing your game was amazing experience! So far, I got only the first ending, but I've stumbled upon some weird stuff as well, so I think I have an idea where to start for the next playthrough.  :)

Things that made it harder for me:

  • The flickering of the scene while moving: I get that it's probably unavoidable, but it still made my head hurt a bit.
  • The unability of looking up or down: it made the descent from the hill a bit harder, and it could make exploring feel more natural.

The stuff I love about the game:

  • The 3D environment together with the color choice: it made the whole experience feel like being in a dream.
  • The sound: sometimes it tends to be overlooked (often by me when I'm working on something  :-D ), but it's such a cruical part of the atmosphere! Even the fact that you don't hear any voice, just the different sounds of footsteps, adds to the dreamy atmosphere. Also the attention to detail - I've only realized the change of the sound on top of the hill after reading about it here, it just felt so natural.
  • The sea is beautiful. And the combination of the sound of the waves together with the animation!
#14
Hi, sorry for digging up this thread, but I didn't have much time to spend with AGS lately. Now I've finally implemented a solution for the panning and volume based on your suggestions - a big thanks to all of you!  :)

Maybe it'll help someone in the future, or you'll find a better solution based on this one. :)

First, I listen to a sound on the designated audio channel - all sounds have a special type assigned with its own channel (MaxChannels set to 1, as described above by Crimson Wizard). Variables sound_direction_x/y are specified together with the animation, best way probably is to put it into a custom animate function.
I needed this because you can't change the panning and volume when there's no audio playing on the channel: making this possible would be great!
Code: ags

function repeatedly_execute_always() {  
 
 if (System.AudioChannels[3].IsPlaying && sound_direction_x != -1)
 {
  SetSoundDirection(3, sound_direction_x, sound_direction_y);
 }
}


And this is the actual setting. 
Code: ags

void SetSoundDirection(int channel_id, int vector_x, int vector_y)
{
 sound_direction_x = -1;
 sound_direction_y = -1;
 if (vector_x == 0 && vector_y == 0) return;
 sound_distance = MathsFunc.Distance(0, 0, vector_x, vector_y*2); //simple custom function, *2 is because of the perspective of my game
 sound_distance = sound_distance/8; //kept separate, change the number to play around with the effect's intensity
 if (sound_distance > 90) sound_distance = 90; // the sound is always at least at 10% of volume
 vector_x = vector_x/4; // change the number to play around with the effect's intensity
 if (MathsFunc.Absolute(vector_x) > 100)
 {
  if (vector_x < 0) vector_x = -100;
  else vector_x = 100;
 }
 System.AudioChannels[channel_id].Panning = vector_x;
 System.AudioChannels[channel_id].Volume = 100-sound_distance;
}

It may look a bit clumsy, but it works fine. :)
#15
Quote from: Crimson Wizard on Sat 25/09/2021 16:10:01
For example, if you have audio types:
- Music: max channels = 1;
- Sound: max channels = 0; (not limited therefore not reserved)
- Ambience: max channels = 1;
- Footsteps: max channels = 1;

This gives channel IDs:
0 - speech;
1 - music;
2 - ambience;
3 - footsteps.
- remaining 4 channels are used freely for sounds.

Hmm, footsteps are a separate audio type by default? I don't have this type defined, maybe it's because it was introduced in later version of AGS than where my project had started?
This actually leads my to an idea, maybe it's because I don't understand the audio system correctly: if I were to create a new audio type for the sounds linked to frame and set its MaxChannels property to 1, would it then be easier to take track of it?

Quote from: eri0o on Sat 25/09/2021 18:12:30
@M.M., can you talk a bit about the intention here? What are you trying to achieve? :)
Sure.  :) It's an idea for improving the atmosphere and immersion in my game. It's an RPG with turn-based battle system, similar to Shadowrun or Fallout (in the basic system, definitely not in quality  :-D ). The sounds linked to animations are mostly shots, punching etc. - because of the turn-based nature of it, the animations are blocking which should make it easier, and I already have a code to change the sounds inside animations on the go (to have variety of shot sounds without the need of duplicate loops).
So, what I've wanted to try is to change mostly the L/R panning of the sounds based on their relative position to player and see if it helps with the atmosphere.
#16
Hi there,

I'm wondering, is there a way to set an audio channel for sounds linked to an animation frame? Or is there a default audio channel for this purpose? I'd like to adjust the panning and volume of the sounds, but I'm not sure whether there's a way without some work around.
#17
Thank you, CW! This is the first time I've heard of unblocking dll file.  :)

Now AGS starts with the plugin, but when I try to create a new note, I get this error:
Code: ags

---------------------------
Adventure Game Studio
---------------------------
A serious error occurred and the AGS Editor may now be in an unstable state. You are STRONGLY ADVISED to shut down the editor and restart it. Before saving your work, make a backup copy of your game folder in case any data has been corrupted.



Error: System.InvalidCastException: [A]Scintilla.ScintillaControl cannot be cast to [B]Scintilla.ScintillaControl. Type A originates from 'AGS.Controls, Version=3.5.1.8, Culture=neutral, PublicKeyToken=574775a8f405a67a' in the context 'Default' at location 'C:\Program Files (x86)\Adventure Game Studio 3.5.1\AGS.Controls.dll'. Type B originates from 'AGS.Controls, Version=3.5.1.8, Culture=neutral, PublicKeyToken=574775a8f405a67a' in the context 'LoadFrom' at location 'C:\Users\mirek\Dropbox\Main\tvorba\IsoWestern\WildWestIso\AGS.Controls.dll'.

   at AGS.Plugin.Notes.NotesPane.GetScintillaControl()

   at AGS.Plugin.Notes.NotesPane.GetEditor()

   at AGS.Plugin.Notes.NotesComponent.OpenItem(Int32 index)

   at AGS.Plugin.Notes.NotesComponent.AGS.Types.IEditorComponent.CommandClick(String control)

   at AGS.Editor.ProjectTree.ProcessClickOnNode(String nodeID, MouseButtons button)

   at AGS.Editor.ProjectTree.projectTree_NodeMouseDoubleClick(Object sender, TreeNodeMouseClickEventArgs e)

   at System.Windows.Forms.TreeView.OnNodeMouseDoubleClick(TreeNodeMouseClickEventArgs e)

   at System.Windows.Forms.TreeView.WndProc(Message& m)

   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)

   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)

   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
---------------------------
OK   
---------------------------



(I guess using code type instead of reply is better for inserting errors into the message, because it doesn't mistake any part of it for text formating symbols such as [ B ].)
#18
Thanks fernewelten for the update! Unfortunately, it doesn't work for me.  :(
Here is the error message I get:
Quote
---------------------------
Adventure Game Studio
---------------------------
There was an error loading plugin 'ags.plugin.notes.dll'.



System.NotSupportedException: An attempt was made to load an assembly from a network location which would have caused the assembly to be sandboxed in previous versions of the .NET Framework. This release of the .NET Framework does not enable CAS policy by default, so this load may be dangerous. If this load is not intended to sandbox the assembly, please enable the loadFromRemoteSources switch. See http://go.microsoft.com/fwlink/?LinkId=155569 for more information.

   at System.Reflection.RuntimeAssembly.nLoadFile(String path, Evidence evidence)

   at System.Reflection.Assembly.LoadFile(String path)

   at AGS.Editor.EditorPlugin..ctor(String fileName, AGSEditorController pluginEditorController)

   at AGS.Editor.Components.PluginsComponent.LoadEditorPluginIntoMemory(String fileName)
---------------------------
OK   
---------------------------

It happens right as I start AGS Editor. I'm using build 3.5.1.8.
#19
Just a small tip, Vincent, maybe it'll be helpful. You can keep just one Say function and set the portrait location from within it:

Code: ags
function SayPortrait(this Character*, String message) 
{  
 if (this == player) SetGameOption(OPT_PORTRAITPOSITION, 0);
 else SetGameOption(OPT_PORTRAITPOSITION, 1);
 this.Say("%s", message);
} 
#20
Is the script neccessary for the desired effect? The first thing that I found myself wondering about was whether it's not an overcomplicated solution. Given you have 8 different sounds, you could just assign them to sprites however you like: sure, there would always be the same sound for the one exact sprite, but I doubt any player would notice it as it would still sound varied.
Now that you have the script it's probably not an issue anymore. :) But it could be another way to reach the goal.
SMF spam blocked by CleanTalk