Mittens 2018 will be in Boston this September. There are three spaces left, so check out the thread for details!

Show Posts

You can view here all posts made by this member. Note that you can only see posts made in areas to which you currently have access.


Topics - eri0o

Pages: [1] 2
1
Disclaimer: this an article that I sketched long ago, but didn't knew if it was good enough, so I am throwing here to see if ideas can come up to make it better because I want to address this general idea in my blog.

I noticed recently that during the week I am more keen on games that have story depth, but I can get tired if a game is too demanding skill wise. On weekends, I am usually well rested, and like to be challenged.

Once I saw a tweet by @gritfish that said:

Quote
"I honestly believe we need to  change the way games do difficulty / game modes to something like:

I'm here for the story
I'm here for challenge
I'm here for a second & harder playthrough
I'm here to take photos
I want to play with the settings and I'm okay if that breaks things
"

Well, I like this idea. But I am also slightly lazy, I am not coding different game modes.

I've read Designing Virtual Worlds, from Richard Bartle, and he talks about the 4 types of players he discovered while analyzing MUD: Achievers, who like to achieve defined goals; Socializers, who gets greatest rewards interacting with other people; Explorers, who likes to learn more about the virtual world; Killers, who like to dominate others. He goes on to explain how to create a virtual world that attracts each subset of players.

Players of Magic The Gathering may be familiar with this idea, it's R&D and Mark Rosewater divide players in three categories: Timmy, a social person who wants to have fun winning big (the RTS equivalent would be having a big base before unleashing a final gigantic attack); Johnny, who wants to express himself through the game; and Spike, who plays for the winning and competition. Recently they also started considering hybrids of these players.

On with adventure games. They are mostly known by stories, puzzles, the exploring and the pace on the control of the player. Psychographics can be defined as a quantitative methodology used to describe consumers on psychological attributes. Psychographics has been applied to the study of personality, values, opinions, attitudes, interests, and lifestyles.

I would like to propose here psychographics for Point and Click Adventure Games:

 - Stella, who plays for the Story;
 - Paula, who plays for the Puzzles;
 - Ezra, who plays to Explore;

So each time I create a room in a game, I try to look if I am leaving each of these players, something to play with, and also, I usually choose one of them to focus more on each room.

2
Hello,

I need to get the current graphic from the player, I need to do this every instant, I am using this information to draw things on a surface, so at instant t=7 I need the player frame for instant t=7, and not t=6.

I decided to use the following:

Code: Adventure Game Studio
  1. int getPlayerGraphic(){
  2.   ViewFrame * ViewFrame_Player;
  3.   ViewFrame_Player = Game.GetViewFrame(player.View,  player.Loop, player.Frame);
  4.   return  ViewFrame_Player.Graphic;
  5. }
  6.  

but apparently, this gets in the current instant, the graphic that was on screen on the previous instant, so using this information gets a slightly delay.

So I evolved to do the following thing:

Code: Adventure Game Studio
  1. int i_view;
  2. int i_loop;
  3. ViewFrame * ViewFrame_Player;
  4.  
  5. function repeatedly_execute_always(){
  6.   i_view = player.View;
  7.   i_loop = player.Loop;
  8. }
  9.  
  10. function late_repeatedly_execute_always(){
  11.   if(IsGamePaused() == 1  || !System.HasInputFocus){
  12.     return;  
  13.   }
  14.  
  15.   ViewFrame_Player = Game.GetViewFrame(i_view,  i_loop, player.Frame);
  16. }
  17.  
  18. static int PlayerViewframe::getGraphic(){
  19.   return  ViewFrame_Player.Graphic;
  20. }
  21.  

which sometimes works, but in some rare occasions, crashes my software, because player.Frame sometimes is updated and i_view and i_loop isn't, and my loop for down and up have different frame count than left and right. And sometimes, it doesn't update correctly.

So is there a right way of getting the current graphic the player has ?

3
Engine Development / Let's build for Android!
« on: 08 Jan 2018, 00:35 »
I will try to explain what I did here, questions will arise, hopefully everything can be answered here and this will allow me to generate a guide.

So first two things are important:
 - Android port of the engine currently doesn't report correctly mouse.isButtonDown, so your game CAN'T BE USING THIS, use if(System.OperatingSystem == eOSAndroid) in your code to work for this.
 - I am using the latest prebuilt APK as libs, those were for the previous stable version, so your game must be built with that AGS.

1. You need to install the latest Android Studio, just download and install. https://developer.android.com/studio/index.html .

2. You will also need JDK, NDK and Android SDK.

3. After installing Android Studio, download the repository I made here: https://github.com/ericoporto/mythsuntold_dungeonhands . This is my modded version of Monkey's Android Studio Project.

4. Open the folder in Android Studio.

5. Building should generate my game .apk!

6. Ok, let's make YOUR game .apk. In the folder Android Studio placed the Sdk, there is a magical tool called jobb. I use Ubuntu, and the tool is in the folder ~/Android/Sdk/tools/bin/ in my computer. If you use Windows, then it's probably in %appdata%\Local\Android\Sdk . (if someone can confirm this information, it would be awesome!). This is just so you can understand what will happen next.

7. In your game Compiled folder, there is a YOURGAMENAME.ags file. Open a cmd.exe (windows) or bash terminal (Linux/OSX). Change Directory to the folder YOURGAMENAME.ags is.

In Windows (untested!)
Code: Adventure Game Studio
  1. cd YOURGAMENAME\Compiled\
  2. mkdir obb
  3. move YOURGAMENAME.ags obb\
  4. %appdata%\Local\Android\Sdk\tools\bin\jobb -d \obb\ -o main.3.com.YOURSTUDIONAME.YOURGAMENAME.obb -pn com.YOURSTUDIONAME.YOURGAMENAME -pv 3
  5.  
   
In Linux/OSX
Code: Adventure Game Studio
  1. cd YOURGAMENAME/Compiled/
  2. mkdir obb
  3. mv YOURGAMENAME.ags obb/
  4. ~/Android/Sdk/tools/bin/jobb -d ./obb/ -o main.3.com.YOURSTUDIONAME.YOURGAMENAME.obb -pn com.YOURSTUDIONAME.YOURGAMENAME -pv 3
  5.  

In the code above, 3 is simply the OBB version number. Every time you change the content of the OBB linked to your APK and release, you have to increase that number - and update in your Android Studio Project accordingly. Also make sure that YOURGAMENAME and YOURSTUDIONAME are correctly updated in your android studio project.

8. In the README there is a line called Setting up the project for your game. I will copy below:

-Update package name:

Open the project in Android Studio, then in the project tree navigate to app/java/com.mythsuntold.osd.scourge.
Right-click on this folder and select "Refactor -> Move...". When prompted, select "Move package 'com.mythsuntold.dungeonhands' to another package" (the default). You may receive a warning that multiple directories will be moved, select Yes. Type the parent name of your package, not the final package name (e.g., com.bigbluecup not com.bigbluecup.game), select "Refactor" and then click "Do Refactor".
Right-click on the new project folder in the project tree (e.g., com.bigbluecup.scourge) and select "Refactor -> Rename". Type the package name for your game (e.g., game), then select "Refactor" and click "Do Refactor".

Finally, delete the com.mythsuntold.dungeonhands folder.

- Update project.properties. This file contains gradle settings related to your project. The application ID, version code, and version name need to be set to match your project settings (application ID is your package name).

- Update project.xml. This file contains resources for your project. The values there are described in that file.

- Update local.static.properties. This file contains local data that should NOT be added to version control (.gitignore will ignore your changes to this file). You need to add your keystore path, alias, and passwords, and optionally the path to your copy of the AGS source (if you are rebuilding the engine native libraries). See the Java docs on keytool or use the Android Studio signing wizard to generate a keystore.

- Update private.xml. This file contains definitions for your RSA public key and an integer-array with bytes for your salt which is used by the ExpansionDownloaderService. These values are necessary if distributing your app via the Google Play Store. The RSA public key is provided in the Google Play Developer Console, and the salt bytes may be any number of values in the range [-128, 127]. You may need to upload an APK without the RSA public key first before the key is provided. That APK should not be public unless the OBB file is embedded.

- Update graphics resources (app/src/main/res). You can use the Android Asset Studio to easily generate graphics for your app, or use your preferred method. Everything in the drawable and various mipmap-* folders should be replaced with your resources.

I made this post with the intent to help Mehrdad, so please try this!

4
Adventure Related Talk & Chat / Pixel Font Resource
« on: 03 Jan 2018, 21:30 »
Just linking a website that has been very useful to me:

http://www.pentacom.jp/pentacom/bitfontmaker2/gallery/?page=1&order=popular

5
Site & Forum Reports / Is teamcity still online?
« on: 30 Dec 2017, 15:07 »
There are some links that goes to Teamcity bigbluecup, it looks like it is/was a pipeline part to build binaries. Is this still online? Are the scripts for build there public in any place?

6
Hello,

I am making the opening scene of my game and I have a question. Playtesting showed that players prefer dialogs to be click to advance only instead of click + timer. In the opening scene though, I feel it would be better if the dialog used click to advance plus timer, because each looping state feel better under a time constraint.

Would keep my game click to advance and the opening click to advance + timer be a good or a bad idea?

7
I noticed the music position in ms is not updated every frame. Is this intentional?

I came up with the following code to fix this, where actualACMusMs has the true music position:

Code: Adventure Game Studio
  1. AudioChannel *acMusic;
  2.  
  3. //fix to report correct music position, game in 60fps
  4. int frame;
  5. int acMusPreviousMs;
  6. bool startedRepeat;
  7. int frameWhenRepeatingStarted;
  8. int actualACMusMs;
  9.  
  10. void playMusic(AudioClip * musicClip){
  11.   acMusic = musicClip.Play(eAudioPriorityHigh, eRepeat);
  12. }
  13.  
  14.  
  15. void repeatedly_execute_always(){
  16.   if(IsGamePaused()==1 || acMusic==null){
  17.     return;  
  18.   }
  19.  
  20.   frame++;
  21.  
  22.   if(acMusic.PositionMs==acMusPreviousMs){
  23.     if(!startedRepeat){
  24.       frameWhenRepeatingStarted=frame-1;
  25.     }
  26.     startedRepeat=true;
  27.     actualACMusMs = acMusPreviousMs+(frame-frameWhenRepeatingStarted)*16;
  28.   } else {
  29.     startedRepeat=false;
  30.     actualACMusMs= acMusic.PositionMs;
  31.   }
  32.  
  33.   acMusPreviousMs = acMusic.PositionMs;
  34. }
  35.  

I did this because I am experimenting with some music in my game that is active, like, I switch music depending on changes on the environment, and needed to correctly position the music when switching.

Also, imagine a graph:

(music 1)--->>(music 2)<< loop music 2 forever

How would you detect music 1 has ended and you need to proceed to music 2? Also if I have crossfade activated, how should I force crossfade to not happen then?

8
Advanced Technical Forum / Prevent alt+tab audio glitch
« on: 10 Dec 2017, 20:40 »
Hey! When I alt+tab an AGS game, the audio likely rolls a dice, and on a odd number, it glitches, producing looping sound that sounds like the previous 200ms of sound. Is there a way to prevent this? If I could detect from in game the loss of focus, I could try to lower the volume.

9
Hey, I have a code as below, my character cChara is correctly shown in screen. But SOMETIMES, I get an error on the line that has Game.GetViewFrame, stating Error: GetGameParameter: invalid frame specified.

Code: Adventure Game Studio
  1. ViewFrame * tvf;
  2.  
  3. ...
  4. function late_repeatedly_execute_always(){
  5.   ...
  6.   tvf = Game.GetViewFrame(cChara.View, cChara.Loop, cChara.Frame);
  7.   ...
  8. }
  9.  

The only thing I gathered is it happens when the character is walking to some direction and I click to force him walk down, and my walking down (and up) animation has one less frame then the walking right and left.

10
Advanced Technical Forum / Using Normal Maps (demo)
« on: 09 Dec 2017, 22:38 »
Ok, so today I lost some hours of my life coding NormalMap with AGS Script.

In case you want it, Download the Demo here!.

I don't think it looks good, I decided to ditch this idea, but maybe someone wants to try and test this.

I based my code on the code here.

If someone does make it better, faster, please share your enhancemets here!


11
Completed Game Announcements / Dungeon Hands
« on: 05 Dec 2017, 01:36 »
Dungeon Hands



Dungeon Hands is a two player card game you can play on a computer, made for LudumDare40. Click and drag to move cards.

Game Page on Itch.io
Ludum Dare 40 entry

Music and Graphics by Ricardo Juchem
Game Design by Kamila Galvani
Code and Stuff by √Črico Porto

Here are the rules

You win when you have no cards in hand.

When the game starts players can choose Monster Overlord or Heroes. The player with Monster Overlord deck starts.

A round is composed of each player turns.

On the start of the turn, the player can play any special card if desired. Then the player must play either a Hero card (when playing with Heroes) or a Monster card (if you are the Monster Overlord). Then the game goes to next turn.

The player playing next can play any special card if desired. Then the player must play either a Hero card (when playing with Heroes) or a Monster card (if you are the Monster Overlord), but the card played MUST be either a higher Rank or the same Class, this is called a valid card. If a player does not have a valid card in his hand, that player draws cards until a valid card is drawn and played. Then the turn ends.

With Monster Overlord cards and Heroes cards on the table, the dungeon encounter is resolved, and all cards on table leave play - the Hero cards go back to the village and the Monsters cards perish. The player who had the highest Rank card get to start the next round. If all cards had the same Rank, the last player to play starts the next round.

The Rank is the number on the corner, Class is represented by the symbol and color of the card. Special cards have no Rank or Class.

The player who draws the last deck card loses.

12
Hey guys,

Recently I started a thread on TIGSource with the name Game feel and juice for old school pixel point and click adventure game. If someone wants to know more about juice, I recommend the Juice it or Lose it presentation in video. So I thought to replicate the answers that came around here in the forums, to maybe try to get some specifics in AGS - for example, Chicky already told me to use 60FPS and using GUIs as overlays, maybe this also invites him to chat more here?

  • leave trace, give stuff the player can interact that leaves visible trace in the room.
  • break the rules where makes sense. The character should be able to look things from far away if he doesn't NEED to move there, saving the walking time.
  • extra flair on the rewarding: has the player picked a new item? Flash the screen, play a cool sound.
  • clarify when you reveal new text on the first time. If your game has repeated outcomes for the same input (looking something yields the same message), clearly tell the player the first time he sees, it's something new.
  • visual feedback for interation. This is a lot of work, requiring lots of animation, but feels good.
  • tweening. Tween EVERYTHING.
  • voice acting. This one is hard because I think games work a lot better with voice acting, but this is hard if you don't live on an English speaking country.

If anyone has any ideas to contribute, AGS specific things, please do. The tween everything item I think needs to be done throughout the whole development, but some things can wait the polishing phase. If some can share input on when it's interesting to think on these things would be cool too.

13
http://archive.is/FFx6z | https://www.polygon.com/2017/9/8/16263050/game-design-magic-tricks

Article: Game Design Magic Tricks

Hey, I read this article and was curious on which magic tricks could be used in point and click adventure games. Anyone has ideas?

14
Advanced Technical Forum / How to crossfade music
« on: 11 Nov 2017, 20:09 »
Hello!

I need to crossfade between two music tracks. I think this isn't so unusual, so probably someone here has already done it.

an excerpt of my audio player code is below
Code: Adventure Game Studio
  1. AudioChannel *acMusic;
  2. AudioClip * currentMusic;
  3. bool stopped;
  4. int globalMusicVol;
  5. AudioClip * previousmusic ;
  6.  
  7.  
  8. static void MusicPlayer::play(AudioClip * musicClip,  int position){
  9.   stopped = false;
  10.  
  11.   if(previousmusic==musicClip){
  12.     //don't play music if it's already playing
  13.     return;
  14.   }
  15.  
  16.   //stop previous music
  17.   if(previousmusic != null){
  18.     previousmusic.Stop();
  19.   }
  20.  
  21.   previousmusic = musicClip;
  22.  
  23.   currentMusic = musicClip;
  24.   if(position == 0){
  25.     acMusic = musicClip.Play(eAudioPriorityHigh, eRepeat);
  26.   } else {
  27.     acMusic = musicClip.PlayFrom(position,eAudioPriorityHigh, eRepeat);
  28.    
  29.   }
  30.   acMusic.Volume = globalMusicVol;
  31.   updateAllVolumes();
  32. }
  33.  
  34. static void MusicPlayer::playFromPreviousTime(AudioClip * musicClip, float crossfadeTime){
  35.   if(crossfadeTime!= 0.0){
  36.    
  37.   } else {
  38.     int previousPosition = acMusic.Position;
  39.     MusicPlayer.play(musicClip, previousPosition);
  40.   }
  41. }
  42.  

The function I am working is static void MusicPlayer::playFromPreviousTime(AudioClip * musicClip, float crossfadeTime).

I want to enable the possibility to crossfade between two songs that have the exact same length. How to do this? I only have 1 audio channel for music, and I am not using the ambient channel, would be possible to set the audioclip type to whichever isn't the last one?

Cassiebsg told me there is the possibility to use the following function too:
SetGameOption (OPT_CROSSFADEMUSIC, x); // where x= 0 (no), 1 (slow), 2 (slowish), 3 (medium) and 4 (fast)

But... I would like to have control over the crossfade time. Below is my full audio module code, it has dependency on the Tween Module.


MusicPlayer.ash
Add spoiler tag for Hidden:
Code: Adventure Game Studio
  1. // new module header
  2.  
  3. #define MusicPlayer_CROSSFADETIME 0
  4.  
  5.  
  6. struct MusicPlayer
  7. {
  8.   import static void play(AudioClip * musicClip,  int position = 0);
  9.   import static void playFromPreviousTime(AudioClip * musicClip, float crossfadeTime = MusicPlayer_CROSSFADETIME);
  10.   import static AudioClip * getCurrentMusic();
  11.   import static void stop(AudioClip * musicClip);
  12.   import static void setMusicPosition(int x, int y);
  13.   import static void removeMusicPosition();
  14.   import static void tweenMusicPosition(int x, int y,  float timing);
  15.   import static void setGlobalVolume(int musicVolume);
  16.   import static int  getGlobalVolume();
  17.   import static void setVolume(int musicVolume);
  18.   import static void tweenVolume(int musicVolume, float timing);
  19. };
  20.  
  21. struct SFXPlayer
  22. {
  23.   import static void play(AudioClip * soundClip);
  24.   import static void stop(AudioClip * soundClip);
  25.   import static void setGlobalVolume(int soundVolume);
  26.   import static int  getGlobalVolume();
  27.   import static void setVolume(int soundVolume);
  28. };
  29.  
  30. import void SPlayerSetGameVolume(int gameVolume);
  31. import int SPlayerGetGameVolume();
  32. import void SPlayerSetDefaults();
  33.  
  34.  

MusicPlayer.asc
Add spoiler tag for Hidden:
Code: Adventure Game Studio
  1. // MusicPlayer variables
  2. AudioChannel *acMusic;
  3. AudioClip * currentMusic;
  4. bool stopped;
  5. int globalMusicVol;
  6. int currentMusicVolue;
  7.  
  8. // SFXPlayer variables
  9. AudioChannel *acSound;
  10. int gloabalSoundVol;
  11. int orignalMusicX;
  12. int orignalMusicY;
  13.  
  14. function updateAllVolumes(){
  15.   int i = 0;
  16.   AudioChannel *ac;
  17.    
  18.   while (i < System.AudioChannelCount)
  19.   {
  20.     ac = System.AudioChannels[i];
  21.    
  22.     if (ac.PlayingClip != currentMusic)
  23.     {
  24.       ac.Volume = gloabalSoundVol;
  25.     } else {
  26.       ac.Volume = globalMusicVol;
  27.     }
  28.     i++;
  29.   }  
  30. }
  31.  
  32.  
  33. AudioClip * previousmusic ;
  34.  
  35.  
  36. static AudioClip * MusicPlayer::getCurrentMusic(){
  37.   return currentMusic;  
  38. }
  39.  
  40. static void MusicPlayer::play(AudioClip * musicClip,  int position){
  41.   stopped = false;
  42.  
  43.   if(previousmusic==musicClip){
  44.     //don't play music if it's already playing
  45.     return;
  46.   }
  47.  
  48.   //stop previous music
  49.   if(previousmusic != null){
  50.     previousmusic.Stop();
  51.   }
  52.  
  53.   previousmusic = musicClip;
  54.  
  55.   currentMusic = musicClip;
  56.   if(position == 0){
  57.     acMusic = musicClip.Play(eAudioPriorityHigh, eRepeat);
  58.   } else {
  59.     acMusic = musicClip.PlayFrom(position,eAudioPriorityHigh, eRepeat);
  60.    
  61.   }
  62.   acMusic.Volume = globalMusicVol;
  63.   updateAllVolumes();
  64. }
  65.  
  66.  
  67. static void MusicPlayer::playFromPreviousTime(AudioClip * musicClip, float crossfadeTime){
  68.   if(crossfadeTime!= 0.0){
  69.    
  70.   } else {
  71.     int previousPosition = acMusic.Position;
  72.     MusicPlayer.play(musicClip, previousPosition);
  73.   }
  74. }
  75.  
  76. static void MusicPlayer::setMusicPosition(int x, int y){
  77.   acMusic.SetRoomLocation(x, y);
  78.   orignalMusicX = x;
  79.   orignalMusicY = y;
  80. }
  81.  
  82.  
  83. static void MusicPlayer::removeMusicPosition(){
  84.   acMusic.SetRoomLocation(0, 0);
  85.   orignalMusicX = 0;
  86.   orignalMusicY = 0;
  87. }
  88.  
  89. static void MusicPlayer::tweenMusicPosition(int x, int y,  float timing){
  90.   if(x==0 && y==0){
  91.     MusicPlayer.removeMusicPosition();
  92.   }
  93.  
  94.   if(orignalMusicX ==0 && orignalMusicY==0){
  95.     return;  
  96.   }
  97.  
  98.   acMusic.TweenRoomLocation(timing, x, y, orignalMusicX, orignalMusicY);
  99.   orignalMusicX = x;
  100.   orignalMusicY = y;
  101. }
  102.  
  103.  
  104. static void MusicPlayer::stop(AudioClip * musicClip){
  105.   stopped = true;
  106.   previousmusic = null;
  107.   musicClip.Stop();  
  108. }
  109.  
  110. static void MusicPlayer::setVolume(int musicVolume){
  111.   if(acMusic != null){
  112.     currentMusicVolue = musicVolume;
  113.     acMusic.Volume = FloatToInt(IntToFloat(currentMusicVolue) * IntToFloat(globalMusicVol)/100.0);
  114.   }
  115. }
  116.  
  117. static void MusicPlayer::tweenVolume(int musicVolume, float timing){
  118.   if(acMusic != null){
  119.     currentMusicVolue = musicVolume;
  120.     acMusic.TweenVolume(timing, FloatToInt(IntToFloat(musicVolume) * IntToFloat(globalMusicVol)/100.0), eEaseLinearTween, eNoBlockTween);
  121.   }
  122. }
  123.  
  124. static void MusicPlayer::setGlobalVolume(int musicVolume){
  125.   globalMusicVol = musicVolume;
  126.   Game.SetAudioTypeVolume(eAudioTypeAmbientSound, globalMusicVol, eVolExistingAndFuture);
  127.   Game.SetAudioTypeVolume(eAudioTypeMusic, globalMusicVol, eVolExistingAndFuture);
  128. }
  129.  
  130. static int MusicPlayer::getGlobalVolume(){
  131.   return globalMusicVol;  
  132. }
  133.  
  134.  
  135.  
  136. static void SFXPlayer::play(AudioClip * soundClip){
  137.   acSound = soundClip.Play(eAudioPriorityNormal, eOnce);
  138.   acSound.Volume = gloabalSoundVol;
  139.   updateAllVolumes();
  140. }
  141.  
  142. static void SFXPlayer::stop(AudioClip * soundClip){
  143.   soundClip.Stop();  
  144. }
  145.  
  146. static void SFXPlayer::setGlobalVolume(int soundVolume){
  147.   gloabalSoundVol = soundVolume;
  148.   Game.SetAudioTypeVolume(eAudioTypeSound, gloabalSoundVol, eVolExistingAndFuture);
  149. }
  150.  
  151. static void SFXPlayer::setVolume(int soundVolume){
  152.   if(acSound != null){
  153.     acSound.Volume = FloatToInt(IntToFloat(soundVolume) * IntToFloat(gloabalSoundVol)/100.0);
  154.   }
  155. }
  156.  
  157. static int SFXPlayer::getGlobalVolume(){
  158.   return gloabalSoundVol;  
  159. }
  160.  
  161. void  SPlayerSetGameVolume(int gameVolume){
  162.   System.Volume = gameVolume;
  163. }
  164.  
  165. int SPlayerGetGameVolume(){
  166.   return System.Volume;
  167. }
  168.  
  169. void SPlayerSetDefaults(){
  170.   MusicPlayer.setGlobalVolume(70);
  171.   SFXPlayer.setGlobalVolume(70);
  172.   SPlayerSetGameVolume(70);
  173. }
  174.  
  175. function game_start()
  176. {
  177.   SPlayerSetDefaults();
  178.   sldAudio.Value = System.Volume;
  179.   sldTestMainVolume.Value = System.Volume;
  180.   sldTestMusicVolume.Value = globalMusicVol;
  181.   sldTestSoundVolume.Value = gloabalSoundVol;
  182. }
  183.  

15
Hello, my game occasionally gives the error below at a specific point:

An exception 0xC0000005 occurred in ACWIN.EXE at EIP = 0x00000000 ; program pointer is +5997, ACI version 3.4.0.16, gtags (72,0)

AGS cannot continue, this exception was fatal. Please note down the number above, remember what you were doing at the time and post the details on the AGS Technical Forum


The part of the game is a change room where I switch the music. The error doesn't happen every time, only sometimes. How do I do diagnostic of these type of errors? It generated a dump but I don't know how to read it. I am using the version: AGS Editor .NET (Build 3.4.0.16), v3.4.0, March 2017.

Thanks

16
Thinking about the Blue Cup as an actual item in game, or maybe some item in the background.

What uses would you guys give to it in game, or what have you seem done in a game? :)

Edit: Well, this is actually a topic for Adventure Related Talk & Chat, can't find the delete button...

17
Hey,

I have no idea if this is possible to do, the idea would be to create a module to do a custom save game. I will start the thread with some incomplete code (I have no idea how to read and parse yet) to try to gasp what's doable. Also I am looking into the most generic as possible code so the most people can benefit from it.

My design idea would be having an object to hold all rooms information, and update it when the player visits the room. Also have other object to hold other relevant information - I think this is maybe not needed but I like to have it clear which kind of thing is available to be saved. These objects would have handler to convert then to String and also have some way to parse a text file, and find the objects and recover then.

Also it would be necessary to have a way to store global variables - this would mean that for this to work, all room variables would be global, and on room variable state would be discouraged. I have no idea how to go on this.

A plus idea would be some form of text compression before storage and decompression after reading - nothing fancy, stuff as light as text compression on SNES cartridges.

PortableSaveGame.asc
Add spoiler tag for Hidden:
Code: Adventure Game Studio
  1. // new module script
  2. #define MAX_REGIONS 15
  3. #define MAX_HOTSPOTS 49
  4. #define MAX_POSSIBLE_ROOMS 100
  5. #define MAX_POSSIBLE_CHARACTERS 100
  6.  
  7. struct RoomSaveData{
  8.   bool exists;
  9.   bool load_from_save;
  10.   int ObjectCount;
  11.   bool object_isnull[MAX_ROOM_OBJECTS];
  12.   int object_X[MAX_ROOM_OBJECTS];
  13.   int object_Y[MAX_ROOM_OBJECTS];
  14.   bool object_Visible[MAX_ROOM_OBJECTS];
  15.   bool object_Clickable[MAX_ROOM_OBJECTS];
  16.   int object_Transparency[MAX_ROOM_OBJECTS];
  17.   int object_Graphic[MAX_ROOM_OBJECTS];
  18.   int object_View[MAX_ROOM_OBJECTS];
  19.   int object_Loop[MAX_ROOM_OBJECTS];
  20.   int object_Frame[MAX_ROOM_OBJECTS];
  21.   bool hotspot_Enabled[MAX_HOTSPOTS];
  22.   bool region_Enabled[MAX_REGIONS];
  23. };
  24.  
  25. struct CharacterSaveData{
  26.   bool exists;
  27.   String Name;
  28.   int Room;
  29.   int x;
  30.   int y;
  31.   int z;
  32.   int Transparency;
  33.   bool Clickable;
  34.   int View;
  35.   int Frame;
  36.   int Loop;
  37.   int inventoryQuantity[MAX_GAME_ITEMS];
  38. };
  39.  
  40. struct GameSaveData{
  41.   int character_count;
  42.   int invetoryitem_count;
  43.   int player_ID;
  44. };
  45.  
  46.  
  47. GameSaveData save_data_game;
  48. RoomSaveData save_data_rooms[MAX_POSSIBLE_ROOMS];
  49. CharacterSaveData save_data_charas[MAX_POSSIBLE_CHARACTERS];
  50.  
  51. //------------------------------------------------------------------------
  52. // PRIVATE FUNCTIONS
  53. //-------o-----------------------------------------------------------------
  54. void storeCharacterData(){
  55.   int i;
  56.   int j;
  57.   i=0;
  58.   save_data_game.character_count = Game.CharacterCount;
  59.   save_data_game.invetoryitem_count = Game.InventoryItemCount+1;
  60.   save_data_game.player_ID = player.ID;
  61.  
  62.   while(i<save_data_game.character_count){
  63.     if(character[i]!=null){
  64.       save_data_charas[i].exists=true;
  65.       save_data_charas[i].Name = character[i].Name;
  66.       save_data_charas[i].Room = character[i].Room;
  67.       save_data_charas[i].x = character[i].x;
  68.       save_data_charas[i].y = character[i].y;
  69.       save_data_charas[i].z = character[i].z;
  70.       save_data_charas[i].Transparency = character[i].Transparency;
  71.       save_data_charas[i].Clickable = character[i].Clickable;
  72.       save_data_charas[i].View = character[i].View;
  73.       save_data_charas[i].Frame = character[i].Frame;
  74.       save_data_charas[i].Loop = character[i].Loop;
  75.       j=1;
  76.       while(j<save_data_game.invetoryitem_count){
  77.         save_data_charas[i].inventoryQuantity[j] = character[i].InventoryQuantity[j];
  78.         j++;
  79.       }
  80.     } else {
  81.       save_data_charas[i].exists=false;
  82.     }
  83.    
  84.     i++;
  85.   }
  86. }
  87.  
  88. String CharacterSaveData_toString(){
  89.   String rstr="{\"characters\": {[";
  90.   int i;
  91.   int j;
  92.   i=0;
  93.   while(i<save_data_game.character_count){
  94.     if(save_data_charas[i].exists){
  95.       rstr=rstr.Append(String.Format("  \"%d\":{[",i));
  96.       rstr=rstr.Append(String.Format("    \"exists\": %d,[",save_data_charas[i].exists));
  97.       rstr=rstr.Append(String.Format("    \"Name\": \"%s\",[",save_data_charas[i].Name));
  98.       rstr=rstr.Append(String.Format("    \"Room\": %d,[",save_data_charas[i].Room));
  99.       rstr=rstr.Append(String.Format("    \"x\": %d,[",save_data_charas[i].x));
  100.       rstr=rstr.Append(String.Format("    \"y\": %d,[",save_data_charas[i].y));
  101.       rstr=rstr.Append(String.Format("    \"z\": %d,[",save_data_charas[i].z));
  102.       rstr=rstr.Append(String.Format("    \"Transparency\": %d,[",save_data_charas[i].Transparency));
  103.       rstr=rstr.Append(String.Format("    \"Clickable\": %d,[",save_data_charas[i].Clickable));
  104.       rstr=rstr.Append(String.Format("    \"View\": %d,[",save_data_charas[i].View));
  105.       rstr=rstr.Append(String.Format("    \"Frame\": %d,[",save_data_charas[i].Frame));
  106.       rstr=rstr.Append(String.Format("    \"Loop\": %d,[",save_data_charas[i].Loop));
  107.      
  108.      
  109.       rstr=rstr.Append(String.Format("    \"inventoryQuantity\":{["));
  110.       j=1;
  111.       while(j<save_data_game.invetoryitem_count-1){
  112.         rstr=rstr.Append(String.Format("      \"%d\": %d,[",j, save_data_charas[i].inventoryQuantity[j]));
  113.         j++;
  114.       }
  115.       rstr=rstr.Append(String.Format("      \"%d\": %d[",j, save_data_charas[i].inventoryQuantity[j]));
  116.      
  117.       rstr=rstr.Append(String.Format("    }[  },["));
  118.     }
  119.     i++;
  120.   }
  121.   rstr=rstr.Append(String.Format("    }[  }["));
  122.   return rstr;
  123. }
  124.  
  125. void storeCurrentRoomData(){
  126.   int i;
  127.   int r = player.Room;
  128.   save_data_rooms[r].load_from_save = false;
  129.   save_data_rooms[r].exists = true;
  130.   save_data_rooms[r].ObjectCount = Room.ObjectCount;
  131.   i=0;
  132.   while(i<save_data_rooms[r].ObjectCount){
  133.     if(object[i] != null){
  134.       save_data_rooms[r].object_isnull[i] = false;
  135.       save_data_rooms[r].object_X[i] = object[i].X;
  136.       save_data_rooms[r].object_Y[i] = object[i].Y;
  137.       save_data_rooms[r].object_Visible[i] = object[i].Visible;
  138.       save_data_rooms[r].object_Clickable[i] = object[i].Clickable;
  139.       save_data_rooms[r].object_Transparency[i] = object[i].Transparency;
  140.       save_data_rooms[r].object_Graphic[i] = object[i].Graphic;
  141.       save_data_rooms[r].object_View[i] = object[i].View;
  142.       save_data_rooms[r].object_Loop[i] = object[i].Loop;
  143.       save_data_rooms[r].object_Frame[i] = object[i].Frame;
  144.     }  else {
  145.       save_data_rooms[r].object_isnull[i] = true;
  146.     }
  147.     i++;
  148.   }
  149.  
  150.   i=0;
  151.   while(i<MAX_HOTSPOTS){
  152.     save_data_rooms[r].hotspot_Enabled[i] = hotspot[i].Enabled;
  153.     i++;
  154.   }
  155.  
  156.   i=0;
  157.   while(i<MAX_REGIONS){
  158.     save_data_rooms[r].region_Enabled[i] = region[i].Enabled;
  159.     i++;
  160.   }
  161. }
  162.  
  163. String RoomSaveData_toString(){
  164.   String rstr="{\"rooms\": {[";
  165.   int i;
  166.   int j;
  167.   i=0;
  168.   while(i<MAX_POSSIBLE_ROOMS){
  169.     if(save_data_rooms[i].exists){
  170.       rstr=rstr.Append(String.Format("  \"%d\":{[",i));
  171.       rstr=rstr.Append(String.Format("    \"exists\": %d,[",save_data_rooms[i].exists));
  172.       rstr=rstr.Append(String.Format("    \"load_from_save\": \"%d\",[",save_data_rooms[i].load_from_save));
  173.       rstr=rstr.Append(String.Format("    \"ObjectCount\": \"%d\",[",save_data_rooms[i].ObjectCount));
  174.      
  175.      
  176.       rstr=rstr.Append(String.Format("    \"objects\":{["));
  177.       j=0;
  178.       while(j<save_data_rooms[i].ObjectCount){
  179.         rstr=rstr.Append(String.Format("      \"%d\": {",j));
  180.        
  181.         rstr=rstr.Append(String.Format("        \"isnull\": %d,[", save_data_rooms[i].object_isnull[j]));
  182.         rstr=rstr.Append(String.Format("        \"X\": %d,[", save_data_rooms[i].object_X[j]));
  183.         rstr=rstr.Append(String.Format("        \"Y\": %d,[", save_data_rooms[i].object_Y[j]));
  184.         rstr=rstr.Append(String.Format("        \"Visible\": %d,[", save_data_rooms[i].object_Visible[j]));
  185.         rstr=rstr.Append(String.Format("        \"Clickable\": %d,[", save_data_rooms[i].object_Clickable[j]));
  186.         rstr=rstr.Append(String.Format("        \"Transparency\": %d,[", save_data_rooms[i].object_Transparency[j]));
  187.         rstr=rstr.Append(String.Format("        \"Graphic\": %d,[", save_data_rooms[i].object_Graphic[j]));
  188.         rstr=rstr.Append(String.Format("        \"View\": %d,[", save_data_rooms[i].object_View[j]));
  189.         rstr=rstr.Append(String.Format("        \"Loop\": %d,[", save_data_rooms[i].object_Loop[j]));
  190.         rstr=rstr.Append(String.Format("        \"Frame\": %d,[", save_data_rooms[i].object_Frame[j]));
  191.        
  192.         if(j<save_data_rooms[i].ObjectCount-1){
  193.           rstr=rstr.Append(String.Format("      },"));
  194.         } else {
  195.           rstr=rstr.Append(String.Format("      }"));
  196.         }
  197.         j++;        
  198.       }
  199.       rstr=rstr.Append(String.Format("    },"));
  200.      
  201.      
  202.       rstr=rstr.Append(String.Format("    \"regions\":{["));
  203.       j=0;
  204.       while(j<MAX_REGIONS){
  205.         rstr=rstr.Append(String.Format("      \"%d\": {  \"Enabled\": %d }, [",j,save_data_rooms[i].region_Enabled[j]));
  206.         j++;
  207.       }
  208.       rstr=rstr.Append(String.Format("    },"));
  209.      
  210.      
  211.       rstr=rstr.Append(String.Format("    \"hotspot\":{["));
  212.       j=0;
  213.       while(j<MAX_HOTSPOTS){
  214.         rstr=rstr.Append(String.Format("      \"%d\": {  \"Enabled\": %d }, [",j,save_data_rooms[i].hotspot_Enabled[j]));
  215.         j++;
  216.       }
  217.       rstr=rstr.Append(String.Format("    },"));
  218.      
  219.     }
  220.     i++;
  221.   }
  222.   rstr=rstr.Append(String.Format("  }[}["));
  223.   return rstr;
  224.  
  225. }
  226.  
  227. void storeCurrentData(){
  228.   storeCharacterData();
  229.   storeCurrentRoomData();
  230. }
  231.  
  232. void writeToFile(String content, String filename){
  233.   File *output = File.Open(filename, eFileWrite);
  234.   if (output == null) {
  235.     Display("Error opening file.");
  236.   } else {
  237.     String lineToWrite;
  238.     String restOfContent;
  239.    
  240.     restOfContent = content.Copy();
  241.    
  242.     while(restOfContent.Length > 0 && restOfContent.IndexOf("[")>0){
  243.       lineToWrite = restOfContent.Substring(0, restOfContent.IndexOf("["));
  244.       restOfContent = restOfContent.Substring(restOfContent.IndexOf("[")+1, restOfContent.Length- restOfContent.IndexOf("[")-1);
  245.       output.WriteRawLine(lineToWrite);
  246.     }
  247.    
  248.    
  249.     output.Close();
  250.   }
  251. }
  252.  
  253. String readFile(String filename){
  254.  
  255. }
  256.  
  257.  
  258. //------------------------------------------------------------------------
  259. // PUBLIC FUNCTIONS
  260. //------------------------------------------------------------------------
  261. static void PortableSaveGame::save(int slot, String description){
  262.   storeCurrentData();
  263.   String fstr;
  264.   fstr=CharacterSaveData_toString();
  265.   fstr=fstr.Append(RoomSaveData_toString());
  266.   writeToFile(fstr, "atemp.json");
  267. }
  268.  
  269. static void PortableSaveGame::restore(int slot){
  270.  
  271. }
  272.  
  273. //------------------------------------------------------------------------
  274. //
  275. //------------------------------------------------------------------------
  276. function on_event (EventType event, int data)
  277. {
  278.   if(event == eEventLeaveRoom){
  279.     storeCurrentRoomData();
  280.   } else if(event == eEventEnterRoomBeforeFadein){
  281.     //do necessary loading from save
  282.   }
  283. }
  284.  

PortableSaveGame.ash
Add spoiler tag for Hidden:
Code: Adventure Game Studio
  1. struct PortableSaveGame{
  2.   import static void save(int slot, String description);
  3.   import static void restore(int slot);
  4. };
  5.  


18
Beginners' Technical Questions / Pushing a box [design]
« on: 22 Oct 2017, 14:27 »
Hey,

There's a scene where we wanted our character to push a box, which he will use to climb on top and reach something that's normally out of reach. How would you design such a scene? Our first design idea is that interacting with the box reveals a GUI with forward and backward arrows.

19
Hey,

Rooms have a property called ShowPlayerCharacter in the editor, that can be either true or false. How do I get that specific property value for the current room the player is, in the scripts?

20
Ok, just to try something new I decided to try to port a code for creation of a 3D cube in AGS. I am following this tutorial for processing.

I am falling in a problem where I get a melting cube:



My code is below:
Add spoiler tag for Hidden:
Code: Adventure Game Studio
  1. // new module script
  2. //********************************************************
  3. // * See tutorial at:
  4. // * http://www.petercollingridge.appspot.com/3D-tutorial
  5. //*********************************************************/
  6. int backgroundColour;
  7. int nodeColour;
  8. int edgeColour;
  9. int nodeSize;
  10. int pmouseX;
  11. int pmouseY;
  12. int off_x;
  13. int off_y;
  14. DynamicSprite * SpriteScreen;
  15. DrawingSurface * ScrSurf;
  16. Overlay* myOverlay;
  17.  
  18. struct node{
  19.   int x;
  20.   int y;
  21.   int z;
  22. };
  23.  
  24. struct edge{
  25.   int n0;
  26.   int n1;
  27. };
  28.  
  29. #define NODESLENGTH 8
  30. #define EDGESLENGTH 12
  31. node nodes[NODESLENGTH];
  32. edge edges[EDGESLENGTH];
  33.  
  34.  
  35. void rotateZ3D(float theta) {
  36.   float sin_t = Maths.Sin(theta);
  37.   float cos_t = Maths.Cos(theta);
  38.  
  39.   int i=0;
  40.   while(i<NODESLENGTH){
  41.     int x = nodes[i].x;
  42.     int y = nodes[i].y;
  43.     nodes[i].x = FloatToInt(IntToFloat(x)*cos_t-IntToFloat(y)*sin_t);
  44.     nodes[i].y = FloatToInt(IntToFloat(y)*cos_t+IntToFloat(x)*sin_t);
  45.     i++;  
  46.   }
  47. }
  48.  
  49. void rotateY3D(float theta) {
  50.   float sin_t = Maths.Sin(theta);
  51.   float cos_t = Maths.Cos(theta);
  52.  
  53.   int i=0;
  54.   while(i<NODESLENGTH){
  55.     int x = nodes[i].x;
  56.     int z = nodes[i].z;
  57.     nodes[i].x = FloatToInt(IntToFloat(x)*cos_t-IntToFloat(z)*sin_t);
  58.     nodes[i].z = FloatToInt(IntToFloat(z)*cos_t+IntToFloat(x)*sin_t);
  59.     i++;
  60.   }
  61. }
  62.  
  63. void rotateX3D(float theta) {
  64.   float sin_t = Maths.Sin(theta);
  65.   float cos_t = Maths.Cos(theta);
  66.  
  67.   int i=0;
  68.   while(i<NODESLENGTH){
  69.     int y = nodes[i].y;
  70.     int z = nodes[i].z;
  71.     nodes[i].y = FloatToInt(IntToFloat(y)*cos_t-IntToFloat(z)*sin_t);
  72.     nodes[i].z = FloatToInt(IntToFloat(z)*cos_t+IntToFloat(y)*sin_t);
  73.     i++;
  74.   }
  75. }
  76.  
  77. void translate(int x, int y, int z) {
  78.   int i=0;
  79.   while(i<NODESLENGTH){
  80.     nodes[i].x=nodes[i].x+x;
  81.     nodes[i].y=nodes[i].y+y;
  82.     nodes[i].z=nodes[i].z+z;
  83.     i++;
  84.   }
  85. }
  86.  
  87. void draw() {
  88.   ScrSurf = SpriteScreen.GetDrawingSurface();
  89.   ScrSurf.Clear(backgroundColour);
  90.   ScrSurf.DrawingColor=edgeColour;
  91.  
  92.   int i=0;
  93.   while(i<EDGESLENGTH){
  94.     ScrSurf.DrawLine(nodes[edges[i].n0].x+off_x, nodes[edges[i].n0].y+off_y, nodes[edges[i].n1].x+off_x, nodes[edges[i].n1].y+off_y);
  95.     i++;
  96.   }
  97.  
  98.  
  99.   ScrSurf.DrawingColor=nodeColour;
  100.  
  101.   i=0;
  102.   while(i<NODESLENGTH){
  103.     ScrSurf.DrawPixel(nodes[i].x+off_x, nodes[i].y+off_y);
  104.     i++;
  105.   }
  106.   ScrSurf.Release();
  107. }
  108.  
  109. void mouseDragged() {  
  110.   rotateY3D(IntToFloat(mouse.x - pmouseX));
  111.   rotateX3D(IntToFloat(mouse.y - pmouseY));
  112.   pmouseX=mouse.x;
  113.   pmouseY=mouse.y;
  114. }
  115.  
  116. void autoRotate() {  
  117.   rotateY3D(Maths.Pi/32.0);
  118.   rotateX3D(Maths.Pi/32.0);
  119. }
  120.  
  121.  
  122. void repeatedly_execute(){
  123.   //mouseDragged();
  124.   autoRotate();
  125.   draw();
  126.   myOverlay.Remove();
  127.   myOverlay = Overlay.CreateGraphical(0, 0, SpriteScreen.Graphic, true);
  128. }
  129.  
  130. void game_start(){
  131.   backgroundColour =  Game.GetColorFromRGB(255, 255, 255);
  132.   nodeColour =  Game.GetColorFromRGB(40, 168, 107);
  133.   edgeColour =  Game.GetColorFromRGB(34, 68, 204);
  134.   nodeSize = 8;
  135.  
  136.   nodes[0].x= -25;
  137.   nodes[0].y= -25;
  138.   nodes[0].z= -25;
  139.   nodes[1].x= -25;
  140.   nodes[1].y= -25;
  141.   nodes[1].z= 25;
  142.   nodes[2].x= -25;
  143.   nodes[2].y= 25;
  144.   nodes[2].z= -25;
  145.   nodes[3].x= -25;
  146.   nodes[3].y= 25;
  147.   nodes[3].z= 25;
  148.   nodes[4].x= 25;
  149.   nodes[4].y= -25;
  150.   nodes[4].z= -25;
  151.   nodes[5].x= 25;
  152.   nodes[5].y= -25;
  153.   nodes[5].z= 25;
  154.   nodes[6].x= 25;
  155.   nodes[6].y= 25;
  156.   nodes[6].z= -25;
  157.   nodes[7].x= 25;
  158.   nodes[7].y= 25;
  159.   nodes[7].z= 25;
  160.  
  161.   edges[0].n0= 0;
  162.   edges[0].n1= 1;
  163.   edges[1].n0= 1;
  164.   edges[1].n1= 3;
  165.   edges[2].n0= 3;
  166.   edges[2].n1= 2;
  167.   edges[3].n0= 2;
  168.   edges[3].n1= 0;
  169.   edges[4].n0= 4;
  170.   edges[4].n1= 5;
  171.   edges[5].n0= 5;
  172.   edges[5].n1= 7;
  173.   edges[6].n0= 7;
  174.   edges[6].n1= 6;
  175.   edges[7].n0= 6;
  176.   edges[7].n1= 4;
  177.   edges[8].n0= 0;
  178.   edges[8].n1= 4;
  179.   edges[9].n0= 1;
  180.   edges[9].n1= 5;
  181.   edges[10].n0= 2;
  182.   edges[10].n1= 6;
  183.   edges[11].n0= 3;
  184.   edges[11].n1= 7;
  185.  
  186.   rotateZ3D(30.0);
  187.   rotateY3D(30.0);
  188.   rotateX3D(30.0);
  189.  
  190.   translate(25, 25, 0);
  191.  
  192.   SpriteScreen = DynamicSprite.Create(System.ViewportWidth, System.ViewportHeight, true);
  193.   myOverlay = Overlay.CreateGraphical(0, 0, SpriteScreen.Graphic, true);
  194.   off_x=100;
  195.   off_y=100;
  196. }
  197.  

AGS Project Download as zip here

I think maybe this is due to rounding errors but I don't know how to prevent it. :/

Pages: [1] 2