Jump to content

Recommended Posts

I have worked a total of a hundred plus hours over the last month on this menu functionality for my game development project... It has been quite a job, and it has been a whole lot of fun (and has been a true learning experience)...

 

I am at the point where it works... almost perfectly. Here is a quick video of the menu in use, spells, items, everything except STATUS for which I have not made a video yet.

 

http://www.youtube.com/watch?v=GHzi4lG3jAM

 

 

 

I am at a point where I am going to try to declutter this code. There are some temporary variable sets in there that are technically global variable sets (big space eaters) and it is now fairly difficult to add or modify features because of the nature of the code itself.

 

It is very easy for me to read (because I wrote it) but I want to post it here to get a sense of whether or not you can follow the program flow by reading the code...

 

****Yes... I know I have made a mistake by not implementing variable arrays from the start. :) There is a ton of this stuff that WILL get replaced by much more streamlined code, just by using 4 array sets for the variables...***

 

Matthew180 made a good point to me. When your code becomes difficult to modify and has too many global variables, it is probably a good sign that your design for flow and data handling is poorly constructed.

 

That said, I am considering developing a new model for the data handling (multi-dimensional arrays and bottom-up menu construct).

 

It's either that, or just modify what I've got to house those variables into arrays, streamline the subroutines to fit the new array sets, and eliminate a ton of unnecessary variables.

 

Please look at this code if you get a moment. I am not good at indenting yet, but I have tried to do my best. See if this makes sense, and feel free to watch the video I posted above as a reference for what is happening in the various "compartments" of this menu.

 

 

***I have not included ALL the source for this game (like universal subroutines "ClearBox" and "ReturnString"). Just the menu code and one or two supporting subroutines for reference.

 

Thank you in advance.

 

 

 

 

 
 
          ////////////////////
          //BEGIN MENU BLOCK//
          //////////////////// 
 
 
MainMenu:          
REM  MENU
     CALL CLEAR :: CALL SCREEN(2):: CALL DELSPRITE(#1)
     CALL HCHAR(5,1,101,32):: CALL HCHAR(22,1,101,32):: CALL VCHAR(5,1,97,17):: CALL VCHAR(5,32,97,17)
     CALL HCHAR(5,1,98):: CALL HCHAR(5,32,100):: CALL HCHAR(22,1,99):: CALL HCHAR(22,32,96)
     
 
     MainMenu-MiddleReturn:
 
          GOSUB ClearMenu :: GOSUB ReturnString
          DISPLAY AT(1,14):"MENU";:: DISPLAY AT(2,14):"^^^^"
          DISPLAY AT(8,1):"1) ITEMS":"2) ARMOR":"3) WEAPONS":"4) SPELLS":"5) STATUS";
 
 
     MidMenu-Keyscan:
 
          GOSUB Keyscan
          IF K=13 THEN CALL CLEAR :: GOTO DrawScreen !**BUG FIXED HERE** Case-sensitive labels
          IF K>54 THEN GOTO MidMenu-Keyscan ELSE IF K<49 THEN GOTO MidMenu-Keyscan
          ON K-48 GOTO ItemMenu,ArmorMenu,WeaponsMenu,SpellsMenu,StatusMenu
 
 
 
 
 
          //BEGIN Item Menu//
 
ItemMenu:
 
     REM ITEM MENU
     GOSUB ClearMenu
     DISPLAY AT(1,12):"ITEMS";:: DISPLAY AT(2,12):"^^^^^" :: GOSUB ReturnString
     DISPLAY AT(8,1):"USE ON WHICH CHARACTER?";:"1) BERYL";:"2) REPTOSLICER";:"3) MARKUS";:"4) SKYLAR";
 
     MidItem-Keyscan:
 
          GOSUB Keyscan
          IF K=13 THEN GOTO MainMenu-MiddleReturn 
          IF K>52 THEN GOTO MidItem-Keyscan ELSE IF K<49 THEN GOTO MidItem-Keyscan
          ON K-48 GOSUB ItemBeryl,ItemRepto,ItemMarkus,ItemSkylar
          GOTO ItemMenu
 
 
 
               //ACN=name, ANSP=name starting point, ANL=name length//
 
ItemBeryl:
     REM BERYL
          GOSUB ActiveBeryl
               GOSUB ItemMenu2
          BHP=AHP :: BMP=AMP :: RETURN
 
ItemRepto:
     REM REPTO 
          GOSUB ActiveRepto
               GOSUB ItemMenu2
          RHP=AHP :: RMP=AMP :: RETURN
 
ItemMarkus:
     REM MARKUS
          GOSUB ActiveMarkus
               GOSUB ItemMenu2
          MHP=AHP :: MMP=AMP :: RETURN
 
ItemSkylar:
     REM SKYLAR
          GOSUB ActiveSkylar
               GOSUB ItemMenu2
          SHP=AHP:: SMP=AMP :: RETURN
 
 
     REM **THIS IS THE MEAT OF THE ITEM MENU CODE**
 
ItemMenu2:
 
     GOSUB ClearMenu :: DISPLAY AT(1,ANSP):ACN$;:: CALL HCHAR(2,ANSP+2,94,ANL)
     GOSUB ReturnString
 
ItemDisplay:
 
     DISPLAY AT(8,1):"1) POTION";HPO;:"2) ETHER";MPO;:"3) ELIXIR";ELI;
     DISPLAY AT(3,1):"HP:";AHP;"/";AMHP;:: DISPLAY AT(3,16):"MP:";AMP;"/";AMMP;
 
     MidItem2-Keyscan:
          GOSUB Keyscan
          IF K=13 THEN RETURN
          IF K>51 THEN GOTO MidItem2-Keyscan ELSE IF K<49 THEN GOTO MidItem2-Keyscan
          ON K-48 GOSUB HealthPotion,MagicPotion,Elixir
          RETURN
 
 
          //Use HealthPotion//
 
HealthPotion:
 
     IF HPO<1 THEN CALL SOUND(30,440,1):: HPO=0 :: GOTO ItemDisplay
     HPO=HPO-1 :: AHP=AHP+10 :: IF AHP>AMHP THEN AHP=AMHP
     GOSUB Flash
GOTO ItemDisplay  //used to be a "RETURN" here... changed to GOTO to facilitate multicasts
     RETURN
 
          //Use MagicPotion//
 
MagicPotion:
 
     IF MPO<1 THEN CALL SOUND(30,440,1):: MPO=0 :: GOTO ItemDisplay
     MPO=MPO-1 :: AMP=AMP+10 :: IF AMP>AMMP THEN AMP=AMMP
     GOSUB Flash
GOTO ItemDisplay  //used to be a "RETURN" here... changed to GOTO to facilitate multicasts
     RETURN
 
          //Use Elixir//
 
Elixir:
 
     IF ELI<1 THEN CALL SOUND(30,440,1):: ELI=0 :: GOTO ItemDisplay
     ELI=ELI-1 :: AHP=AHP+5 :: IF AHP>AMHP THEN AHP=AMHP
     AMP=AMP+5 :: IF AMP>AMMP THEN AMP=AMMP
     GOSUB Flash
GOTO ItemDisplay  //used to be a "RETURN" here... changed to GOTO to facilitate multicasts
     RETURN
 
          //END Item Menu//
 
 
////////////////////////////////////////////////
//   ARMOR AND WEAPONS MENUS NOT YET COMPLETE //
////////////////////////////////////////////////
          //BEGIN Armor Menu//
 
ArmorMenu:
     
     REM ARMOR MENU
     GOSUB ClearMenu :: DISPLAY AT(1,12):"ARMOR";:: DISPLAY AT(2,12):"^^^^^" :: GOSUB ReturnString
 
          MidArmor-Keyscan:
 
               GOSUB Keyscan
               IF K=13 THEN GOTO MainMenu-MiddleReturn ELSE GOTO MidArmor-Keyscan
               GOSUB ClearMenu
 
          //END Armor Menu//
 
 
 
          //BEGIN Weapons Menu//
WeaponsMenu: 
 
     REM WEAPONS MENU
     GOSUB ClearMenu :: DISPLAY AT(1,11):"WEAPONS";:: DISPLAY AT(2,11):"^^^^^^^" :: GOSUB ReturnString
 
          MidWeapons-Keyscan:
 
               GOSUB Keyscan
               IF K=13 THEN GOTO MainMenu-MiddleReturn ELSE GOTO MidWeapons-Keyscan
               GOSUB ClearMenu
 
 
          //END Weapons Menu//
 
 
 
 
          //BEGIN Spells Menu//
 
     ////////////////////////////////////////////////////////////////////////////////////////////////////
     //SpellsMenu... this is a BIG one....  Need to have the ability to select WHO WILL CAST the magic///
     //WHO WILL RECEIVE the magic, then display HP and MHP of receiver, MP and MMP of caster           //
     //then animate the spell, display stat changes on both, then return to top of SpellsMenu.         //
     ////////////////////////////////////////////////////////////////////////////////////////////////////
 
 
          
 
 
SpellsMenu:
 
     REM SPELLS MENU
     GOSUB ClearMenu
     DISPLAY AT(1,12):"SPELLS";:: DISPLAY AT(2,12):"^^^^^^" :: GOSUB ReturnString
     DISPLAY AT(8,1):"WHO WILL CAST?";:"1) BERYL";:"2) REPTOSLICER";:"3) MARKUS";:"4) SKYLAR";
 
 
 
     MidSpells-Keyscan:
 
          GOSUB Keyscan
          IF K=13 THEN GOTO MainMenu-MiddleReturn 
          IF K>52 THEN GOTO MidSpells-Keyscan ELSE IF K<49 THEN GOTO MidSpells-Keyscan
          ON K-48 GOSUB CastBeryl,CastRepto,CastMarkus,CastSkylar
GOTO SpellsMenu
 
 
     ////////////////////////////////////////////////////////////////////////////////
     //In the Castxxx section, program flow moves to the "Activexxx" subroutines   //
     //Then to SpellsMenu2 (below) and then returns, updates the players' stats    //
     //Then returns up to MidSpells-Keyscan once all that is complete.             //
     ////////////////////////////////////////////////////////////////////////////////
 
 
CastBeryl:
 
     GOSUB ActiveBeryl
     GOSUB SpellsMenu2
     BHP=CHP :: BMP=CMP :: RETURN
 
CastRepto:
 
     GOSUB ActiveRepto
     GOSUB SpellsMenu2
     RHP=CHP :: RMP=CMP :: RETURN
 
CastMarkus:
 
     GOSUB ActiveMarkus
     GOSUB SpellsMenu2
     MHP=CHP :: MMP=CMP :: RETURN
 
CastSkylar:
 
     GOSUB ActiveSkylar
     GOSUB SpellsMenu2
     SHP=CHP:: SMP=CMP :: RETURN
 
 
 
 
 
     //**THIS IS WHERE THE CODE BEGINS TO GET A BIT CONVOLUTED, as two temporary variable sets are 
     //**BEING USED TO DIFFERENTIATE BETWEEN CASTER AND RECEIVER... THIS IS WHERE THE ARRAYS WILL
     //**HELP SIGNIFICANTLY IN NOT ONLY REDUCING PROGRAM SPACE, BUT MAKING THIS WHOLE PROCESS
     //**MUCH MORE UNDERSTANDABLE TO MYSELF AND OTHERS.
 
SpellsMenu2:
 
          //this part loads the "C" temporary variable set (caster) with the info from the "A" temporary variable set (active)
 
     CMMP=AMMP :: CMP=AMP :: CHP=AHP :: CMHP=AMHP :: CP$=ACN$ :: CNSP=ANSP :: CNL=ANL ::CMN=AMN
 
 
          //Display Caster's info at the top of the screen//
 
 
     GOSUB ClearMenu :: DISPLAY AT(1,CNSP):CP$;:: CALL HCHAR(2,CNSP+2,94,CNL)
     DISPLAY AT(3,1):"HP:";CHP;"/";CMHP;:: DISPLAY AT(3,16):"MP:";CMP;"/";CMMP;
     GOSUB ReturnString
     IF CMN=0 THEN DISPLAY AT(17,1):"THIS MEMBER CANNOT CAST" :: GOSUB Keyscan :: GOTO SpellsMenu
 
     DISPLAY AT(8,1):"CAST ON WHICH PARTY MEMBER?";:"1) BERYL";:"2) REPTOSLICER";:"3) MARKUS";:"4) SKYLAR";
 
 
MidSpells-Keyscan2:
 
     GOSUB Keyscan
     IF K=13 THEN GOTO SpellsMenu 
     IF K>52 THEN GOTO MidSpells-Keyscan2 ELSE IF K<49 THEN GOTO MidSpells-Keyscan2
     ON K-48 GOSUB ReceiveBeryl,ReceiveRepto,ReceiveMarkus,ReceiveSkylar
     GOTO SpellsMenu
 
 
 
     ////////////////////////////////////////////////////////////////////////////// 
     //this is where changes have been made to allow multiple casts on one player//
     //////////////////////////////////////////////////////////////////////////////
 
 
     ////////////////////////////////////////////////////////////////////////////////
     //In the Receivexxx section, program flow moves to the "Activexxx" subroutines//
     //Then to SpellsMenu3 (below) and then returns, updates the players' stats    //
     //Then returns up to MidSpells-Keyscan2 once all that is complete.            //
     ////////////////////////////////////////////////////////////////////////////////
 
 
ReceiveBeryl:
 
     GOSUB ActiveBeryl
     GOSUB SpellsMenu3
     BHP=RPHP :: RETURN
 
ReceiveRepto:
 
     GOSUB ActiveRepto
     GOSUB SpellsMenu3
     RHP=RPHP :: RETURN
 
ReceiveMarkus:
 
     GOSUB ActiveMarkus
     GOSUB SpellsMenu3
     MHP=RPHP :: RETURN
 
ReceiveSkylar:
 
     GOSUB ActiveSkylar
     GOSUB SpellsMenu3
     SHP=RPHP:: RETURN
 
 
SpellsMenu3:
 
     //this part loads the "RP" temporary variable set (receiver) with the info from the "A" temporary variable set (active)
 
     RPMMP=AMMP :: RPMP=AMP :: RP$=ACN$ :: RPNSP=ANSP :: RPNL=ANL :: RPHP=AHP :: RPMHP=AMHP
     GOSUB ClearBox
           //Display Receiver's Name and stats INSIDE the box//
     DISPLAY AT(8,RPNSP):RP$;:: CALL HCHAR(9,RPNSP+2,94,RPNL)
     DISPLAY AT(10,1):"HP:";RPHP;"/";RPMHP;:: DISPLAY AT(10,16):"MP:";RPMP;"/";RPMMP;
     DISPLAY AT(12,1):"CAST WHICH SPELL?"
     IF CMN=3 THEN GOSUB ReptoFinalCast
     IF CMN=2 THEN GOSUB SkylarFinalCast
     IF CMN=1 THEN GOSUB BerylFinalCast
     RETURN
 
 
 
     ////////////////////////////////////////////////////////////////////////////////
     //In the xxxFinalCast section, the program looks for a keypress, then branches//
     //to "which spell was cast" below... Each spell carries with it a MP cost for //
     //the casting party member and a HP gain (and status change in the case of    //
     //the LIFE spell) for the receiving party member...                           //
     ////////////////////////////////////////////////////////////////////////////////
 
 
 
ReptoFinalCast:
     DISPLAY AT(15,1):" "
     DISPLAY AT(16,1):"1) HEAL (10 MP)";:"2) CURE (15 MP)";:"3) LIFE (20 MP)"; :: GOSUB Keyscan
     IF K=13 THEN RETURN
     IF K>51 THEN GOTO ReptoFinalCast ELSE IF K<49 THEN GOTO ReptoFinalCast
     ON K-48 GOSUB HealSpell,CureSpell,LifeSpell
RMP=CMP
     GOTO ReptoFinalCast //***THIS WAS CHANGED FROM "RETURN" TO "GOTO xxxFINALCAST IN ORDER TO FACILITATE MULTICASTS"
 
SkylarFinalCast:
     DISPLAY AT(15,1):" "
     DISPLAY AT(16,1):"1) HEAL (10 MP)";:"2) CURE (15 MP)"; :: GOSUB Keyscan
     IF K=13 THEN RETURN
     IF K>50 THEN GOTO SkylarFinalCast ELSE IF K<49 THEN GOTO SkylarFinalCast
     ON K-48 GOSUB HealSpell,CureSpell
     SMP=CMP
     GOTO SkylarFinalCast //***THIS WAS CHANGED FROM "RETURN" TO "GOTO xxxFINALCAST IN ORDER TO FACILITATE MULTICASTS"
 
 
 
 
BerylFinalCast:
     DISPLAY AT(15,1):" "
     DISPLAY AT(16,1):"1) HEAL (10 MP)"; :: GOSUB Keyscan
     IF K=13 THEN RETURN
     IF K=49 THEN GOSUB HealSpell ELSE GOTO BerylFinalCast
     BMP=CMP
     GOTO BerylFinalCast //***THIS WAS CHANGED FROM "RETURN" TO "GOTO xxxFINALCAST IN ORDER TO FACILITATE MULTICASTS"
 
 
 
 
          //////////////////////////////////////////////////////////////////////
          //**Need to add status flag for "Healthy" "Poisoned" and "Fallen"   //
          //**As of now, Cure and Life do not do all that they WILL do once   //
          //**this is implemented fully.  Cure will heal "Poisoned" and change//
          //**status flag to "Healthy," Life will change status from "Fallen" //
          //**To "Healthy" and will allow "Heal" magic to raise HP.           //
          //////////////////////////////////////////////////////////////////////
 
 
HealSpell: 
     IF CMP<10 THEN GOSUB ClearBox :: DISPLAY AT(15,1):"NOT ENOUGH MP"; :: GOSUB Keyscan :: GOTO SpellsMenu
     IF RPHP<1 THEN GOSUB ClearBox :: DISPLAY AT(15,1):"MEMBER IS FALLEN"; :: GOSUB Keyscan :: RETURN
     CMP=CMP-10 :: RPHP=RPHP+10 :: IF RPHP>RPMHP THEN RPHP=RPMHP
     GOSUB SpellResult
     RETURN
 
          //This will also change the status flag to "Healthy" once that part is complete
CureSpell:
     IF CMP<15 THEN GOSUB ClearBox :: DISPLAY AT(15,1):"NOT ENOUGH MP"; :: GOSUB Keyscan :: GOTO SpellsMenu
     CMP=CMP-15
     GOSUB SpellResult
     RETURN
 
          //Still Need to add status flag for "Healthy" "Poisoned" and "Fallen"
LifeSpell:
     IF CMP<20 THEN GOSUB ClearBox :: DISPLAY AT(15,1):"NOT ENOUGH MP"; :: GOSUB Keyscan :: GOTO SpellsMenu
     IF RPHP<1 THEN RPHP=1 :: GOTO LifeSpellEnd
     RPHP=RPMHP
 
LifeSpellEnd:
 
     GOSUB SpellResult
     RETURN
 
 
 
SpellResult:
 
///**bug**//////
////////////////
//when casting//
//on ones self//
//RP is not   //
//updated when//
//spell is cast/
////////////////
////**bug**/////
 
 
     DISPLAY AT(3,1):" "
     DISPLAY AT(3,1):"HP:";CHP;"/";CMHP;:: DISPLAY AT(3,16):"MP:";CMP;"/";CMMP;
DISPLAY AT(8,1):" ":" ":" "
     DISPLAY AT(8,RPNSP):RP$;:: CALL HCHAR(9,RPNSP+2,94,RPNL)
     DISPLAY AT(10,1):"HP:";RPHP;"/";RPMHP;:: DISPLAY AT(10,16):"MP:";RPMP;"/";RPMMP;
     GOSUB Flash
     CALL SOUND(50,330,1) :: CALL SOUND(50,494,1) :: CALL SOUND(100,1319,0,494,10,330,10)
 
     RETURN
 
          ///////////////////
          //END Spells Menu//
          ///////////////////
 
 
 
 
 
 
     //REM STATUS MENU//
     //REM THIS IS THE NEXT AREA OF FOCUS... GET WORKING STATUS MENU GOING BY LOADING THE "A" SET WITH CHAR'S INFO//
     //REM **USE THESE: ALEV=BLEV :: AMHP=BMHP :: AHP=BHP :: AMMP=BMMP :: AMP=BMP :: ADEF=BDEF :: AATK=BATK :: AMDEF=BMDEF//
     //REM **AMATK=BMATK :: ACN$="BERYL" :: ANSP=14 :: ANL=5//
 
StatusMenu:
 
     CALL DELSPRITE(#1)
     GOSUB ClearMenu :: DISPLAY AT(1,12):"STATUS";:: DISPLAY AT(2,12):"^^^^^^" :: GOSUB ReturnString
 
     DISPLAY AT(8,1):"WHICH CHARACTER?";:"1) BERYL";:"2) REPTOSLICER";:"3) MARKUS";:"4) SKYLAR";
     CALL MAGNIFY(1)
 
 
     MidStatus-Keyscan:
 
          GOSUB Keyscan
          IF K=13 THEN GOTO MainMenu-MiddleReturn 
          IF K>52 THEN GOTO MidStatus-Keyscan ELSE IF K<49 THEN GOTO MidStatus-Keyscan
          GOSUB ClearBox
          ON K-48 GOSUB StatusBeryl,StatusRepto,StatusMarkus,StatusSkylar
     GOTO StatusMenu
 
 
     ///////////////////////////////////////////////////////////////////////////////////
     //In the Statusxxx section, the program displays the character's name, underlines//
     //it, draws the character's likeness onscreen with a SPRITE, then branches to    //
     //StatusDisplay, where the character's data will be displayed onscreen as well   //
     ///////////////////////////////////////////////////////////////////////////////////    
 
 
StatusBeryl:
     GOSUB ActiveBeryl
     DISPLAY AT(7,7):"BERYL REICHARDT";:: DISPLAY AT(8,7):"^^^^^^^^^^^^^^^"
     CALL MAGNIFY(3) :: CALL SPRITE(#1,132,9,120,200)
GOSUB StatusDisplay
     RETURN
 
StatusRepto:
     DISPLAY AT(7,9):"REPTOSLICER";:: DISPLAY AT(8,9):"^^^^^^^^^^^"
     GOSUB ActiveRepto
     CALL MAGNIFY(3) :: CALL SPRITE(#1,136,3,120,200) 
     GOSUB StatusDisplay
     RETURN
 
StatusMarkus:
     DISPLAY AT(7,5):"MARKUS THE VALIANT";:: DISPLAY AT(8,5):"^^^^^^^^^^^^^^^^^^"
     GOSUB ActiveMarkus
     CALL MAGNIFY(3) :: CALL SPRITE(#1,124,5,120,200)
     GOSUB StatusDisplay
     RETURN
 
StatusSkylar:
     DISPLAY AT(7,7):"SKYLAR TWILIGHT";:: DISPLAY AT(8,7):"^^^^^^^^^^^^^^^"
     GOSUB ActiveSkylar
     CALL MAGNIFY(3) :: CALL SPRITE(#1,128,14,120,200)
     GOSUB StatusDisplay
     RETURN
 
 
//***STILL WORKING ON THIS, NEXT IMPLEMENT WEP$ FOR EACH CHARACTER FOR DISPLAY,
 
 
StatusDisplay:
     ANXLV=(50-AXP)
     DISPLAY AT(9,2):"CLASS:"&ACL$; :: DISPLAY AT(9,19):"LEVEL:"&STR$(ALEV);
     DISPLAY AT(11,2):"HP:"&STR$(AHP)&"/"&STR$(AMHP); :: DISPLAY AT(11,19):"MP:"&STR$(AMP)&"/"&STR$(AMMP);
     DISPLAY AT(14,2):"STATUS:"&ASTAT$ :: DISPLAY AT(14,19):"EXP:"&STR$(AXP)
DISPLAY AT(16,2):"ARMOR:"&AARM$ :: DISPLAY AT(18,2):"WEAPON:"&AWEP$
     DISPLAY AT(20,6):"NEXT LEVEL:"&STR$(ANXLV);" EXP"
     MidStatus-Keyscan2:
     GOSUB Keyscan
          IF K=13 THEN GOTO StatusMenu ELSE GOTO MidStatus-Keyscan2
RETURN
 
 

///////////////////////////////////////////////////////////////////////////////////
//Really want to eliminate this whole variable-loading section... It is the      //
//bane of my existence.  LOL!  Anyway, in the Activexxx subs here, the temporary // 
//set "A" is loaded with all the players' statistics and information... Each     //
//party member has one, and it simply loads the Aset with the player's global    //
//variable data.  It works fine... just inefficient and space-consuming          // 
/////////////////////////////////////////////////////////////////////////////////// 
 
ActiveBeryl:
     AMHP=BMHP :: AHP=BHP :: AMMP=BMMP :: AMP=BMP :: ACN$="BERYL" :: ANSP=12 :: ANL=5 :: AMN=BMN :: ACL$=BCL$ :: AXP=BXP
     AARM$=BARM$ :: AWEP$=BWEP$ :: ASTAT$=BSTAT$ :: ANXLV=(50-BXP) :: ALEV=BLEV
     RETURN
 
ActiveRepto:
     AMHP=RMHP :: AHP=RHP :: AMMP=RMMP :: AMP=RMP :: ACN$="REPTOSLICER" :: ANSP=9 :: ANL=11 :: AMN=RMN :: ACL$=RCL$ :: AXP=RXP
     AARM$=RARM$ :: AWEP$=RWEP$ :: ASTAT$=RSTAT$ :: ANXLV=(50-RXP) :: ALEV=RLEV
     RETURN
 
 
ActiveMarkus:
     AMHP=MMHP :: AHP=MHP :: AMMP=MMMP :: AMP=MMP :: ACN$="MARKUS" :: ANSP=12 :: ANL=6 :: AMN=MMN :: ACL$=MCL$ :: AXP=MXP
     AARM$=MARM$ :: AWEP$=MWEP$ :: ASTAT$=MSTAT$ :: ANXLV=(50-MXP) :: ALEV=MLEV
     RETURN
 
ActiveSkylar:
     AMHP=SMHP :: AHP=SHP :: AMMP=SMMP :: AMP=SMP :: ACN$="SKYLAR" :: ANSP=12 :: ANL=6 :: AMN=SMN :: ACL$=SCL$ :: AXP=SXP
     AARM$=SARM$ :: AWEP$=SWEP$ :: ASTAT$=SSTAT$ :: ANXLV=(50-SXP) :: ALEV=SLEV
     RETURN

 
 
 

 

 

  • Like 3
Link to comment
https://forums.atariage.com/topic/237458-to-optimize-or-to-scrap/
Share on other sites

Without trying to understand the code or the flow, my only advice would be to consider using SUBprograms. It seems a lot of your variable swapping and challenges -could- be alleviated by leveraging the subprogram strengths of segregating the global and local data.

Without trying to understand the code or the flow, my only advice would be to consider using SUBprograms. It seems a lot of your variable swapping and challenges -could- be alleviated by leveraging the subprogram strengths of segregating the global and local data.

 

I agree! Plus, converting your party data and other data into arrays will save you a LOT of repetition.

 

I tried making a start of it with your listing, but you don't have all your data defined... If you can provide a complete listing of all your character variable names and their meaning, we can consolidate them into the appropriate arrays.

I will be able to post my complete variable listing when I get home. Adamantyr and I had spoken off-board about organization of arrays and how to go about eliminating the need for the VAST majority of temporary sets. When I started working on this block, I started at the top... Main menu, then built all the segments from there--down. A better method would have been to compartmentalize each of the segments prior to coding, then determine what variables would have been needed for each, then come up with a data structure to encompass the needed values into arrays.

 

At the time, I did not KNOW exactly what all I wanted to do, so it was sort of free form and a bit uncalculated.

 

Now I have the outline and the majority of it fully fleshed and functional, but it is still wonky because I started at the top and did one section at a time, repeating alot of things as I went. :) live and learn.

 

For the primary ITEM menu, for example, rather than jumping to the "Active" subroutine which loads all the player's info into a temp. variable set, it would make a ton more sense to have the variables in Arrays, thereby allowing the keypress of the user to determine the first dimension of the necessary arrays, just by pressing the key! It seems simple now, but Like I said, I did not see the full picture at the time of initial outset.

 

:)

 

I'll post the entire variable set tonight when I get home. Thanks for the advice and help, guys.

Okay... I am going to try to lay out my variables as best I can here... While they're all perfectly clear in my head, they don't look quite as simple and pleasant on paper here. :)

 

 

***Numeric, party-member-specific variables:

     BMHP=20 :: BHP=15 :: BMMP=20 :: BMP=5 :: BDEF=10 :: BATK=10 :: BMDEF=7 :: BMATK=4 :: BXP=10
 
     RMHP=16 :: RHP=5 :: RMMP=40 :: RMP=20 :: RDEF=3 :: RATK=4 :: RMDEF=10 :: RMATK=12 :: RXP=15
 
     MMHP=25 :: MHP=18 :: MMMP=0 :: MMP=0 :: MDEF=15 :: MATK=15 :: MMDEF=5 :: MMATK=0 :: MXP=15
 
     SMHP=12 :: SHP=5 :: SMMP=20 :: SMP=12 :: SDEF=5 :: SATK=4 :: SMDEF=9 :: SMATK=8 :: SXP=0
 
These are global, spanning the entirety of the game, whether in combat, menu, status... these are the numeric variables which follow the characters all the days of their lives. Each set is specific to the character. Any time you see a "B" prefix to a variable name, it refers to Beryl. Any time you see "R", it is for Reptoslicer, etc etc.
MHP=max health points
HP=health points
MMP=max magic points
MP=magic points
DEF=defense
ATK=attack
MDEF=magic defense
MATK=magic attack
XP=experience points
***Please note that since I have not built the battle engine completely yet, the variables which will be specific to battle are not contained here (except for ATK, DEF, MATK, MDEF)
***String, party-member-specific variables:

     BARM$="LEATHER" :: BWEP$="DAGGER" :: BSTAT$="HEALTHY"
 
     RARM$="WIZARDS ROBE" :: RWEP$="NONE" :: RSTAT$="HEALTHY"
 
     MARM$="LEATHER" :: MWEP$="BROADSWORD" :: MSTAT$="HEALTHY"
 
     SARM$="SPRITES CAP" :: SWEP$="DAGGER" :: SSTAT$="HEALTHY"
 
     BCL$="HERO" :: RCL$="MAGE" :: MCL$="FIGHTER" :: SCL$="THIEF"

As on the numeric variables, these are member-specific... B for Beryl, R for Reptoslicer, etc.
ARM$=armor name
WEP$=weapon name
STAT$=current status (HEALTHY, POISONED, FALLEN, etc)
CL$=class name (this will change for two of the characters, later in the game)
There are likely to be more of these party-member-specific string variables as the game continues to develop, but this is all I needed for now.
***Non-party-member-specific (temporary) variable sets...
As you can see in my code, I have a section called "Activexxx" which loads the temporary variable set "A" with the stats of the selected character. Here is a copy of that segment of code...
 
 

ActiveBeryl:
     AMHP=BMHP :: AHP=BHP :: AMMP=BMMP :: AMP=BMP :: ACN$="BERYL" :: ANSP=12 :: ANL=5 :: AMN=BMN :: ACL$=BCL$ :: AXP=BXP
     AARM$=BARM$ :: AWEP$=BWEP$ :: ASTAT$=BSTAT$ :: ANXLV=(50-BXP) :: ALEV=BLEV
     RETURN
 
ActiveRepto:
     AMHP=RMHP :: AHP=RHP :: AMMP=RMMP :: AMP=RMP :: ACN$="REPTOSLICER" :: ANSP=9 :: ANL=11 :: AMN=RMN :: ACL$=RCL$ :: AXP=RXP
     AARM$=RARM$ :: AWEP$=RWEP$ :: ASTAT$=RSTAT$ :: ANXLV=(50-RXP) :: ALEV=RLEV
     RETURN
 
 
ActiveMarkus:
     AMHP=MMHP :: AHP=MHP :: AMMP=MMMP :: AMP=MMP :: ACN$="MARKUS" :: ANSP=12 :: ANL=6 :: AMN=MMN :: ACL$=MCL$ :: AXP=MXP
     AARM$=MARM$ :: AWEP$=MWEP$ :: ASTAT$=MSTAT$ :: ANXLV=(50-MXP) :: ALEV=MLEV
     RETURN
 
ActiveSkylar:
     AMHP=SMHP :: AHP=SHP :: AMMP=SMMP :: AMP=SMP :: ACN$="SKYLAR" :: ANSP=12 :: ANL=6 :: AMN=SMN :: ACL$=SCL$ :: AXP=SXP
     AARM$=SARM$ :: AWEP$=SWEP$ :: ASTAT$=SSTAT$ :: ANXLV=(50-SXP) :: ALEV=SLEV
     RETURN

As you can see above, it is not a DIRECT copy of the above variables... there are a few new ones.

 

ANSP and ANL stand for: "Name Starting Point" and "Name Length".... Essentially loading these variables into the "A" set allows me to have a uniform "SCREEN INFO DRAW" subroutine, just replacing the name length and name starting point with those specific to the characters. "Reptoslicer" and "Beryl" would not look the same, displayed both starting at (6,5)..... Nor would I be able to do the "underline" of the names I do in the menu display by simply using NSP and NL.

 

The "CN$" variable is simply the character's name and the NXLV numeric variable is simply a value for "Next Level" which you can see on the STATUS menu of the game. I will post a screenshot below so you can see how all these temporary variables are being used.

 

 

markusstatus_zpsp8en9o0o.png

 

 

 

I think I have covered all the variables here, except for the other two temporary sets "C" and "RP"

 

They are just copies of the A set used during the spellcasting menu... In order to be able to simultaneously display character data and then update it upon cast, I needed a way to do quick-loads of character data, then do a fast modify (once spell was cast) and then reload the new RP and C sets back into their respective players' static permanent variable sets. Since the menu calls subroutines from subroutines, once the values are modified, the program simply RETURNs up to the calling sub, the players' static permanent variables are updated, and the program returns to the root of the menu.... Reading the code block I posted at the top of this thread will clearly show what I'm talking about.... even if I'm not making a ton of sense here.

 

 

Anyway... That's it. You have my entire variable set structure for the game (so far.)

 

***My plan for doing legit modification to the variables by plugging them into arrays will look something like this:

 

 

HP(4,2) **4 party members, MHP and HP

MP(4,2) **4 party members, MMP and MP

XP(4) **4 party members XP

BAT(4,2) **4 party members, ATK and DEF

MBAT(4,2) **4 party members, MATK and MDEF

EQUIP$(4,2) **4 party members, ARM$ and WEP$

STAT$(4) **4 party members STAT$ (status)

 

 

That's the start of what I'm hoping to do..... I'm certainly open for suggestions... you guys have already given me alot to think about and I appreciate it. :)

 

Okay... I am going to try to lay out my variables as best I can here... While they're all perfectly clear in my head, they don't look quite as simple and pleasant on paper here. :)

 

 

***Numeric, party-member-specific variables:

     BMHP=20 :: BHP=15 :: BMMP=20 :: BMP=5 :: BDEF=10 :: BATK=10 :: BMDEF=7 :: BMATK=4 :: BXP=10
 
     RMHP=16 :: RHP=5 :: RMMP=40 :: RMP=20 :: RDEF=3 :: RATK=4 :: RMDEF=10 :: RMATK=12 :: RXP=15
 
     MMHP=25 :: MHP=18 :: MMMP=0 :: MMP=0 :: MDEF=15 :: MATK=15 :: MMDEF=5 :: MMATK=0 :: MXP=15
 
     SMHP=12 :: SHP=5 :: SMMP=20 :: SMP=12 :: SDEF=5 :: SATK=4 :: SMDEF=9 :: SMATK=8 :: SXP=0
 
These are global, spanning the entirety of the game, whether in combat, menu, status... these are the numeric variables which follow the characters all the days of their lives. Each set is specific to the character. Any time you see a "B" prefix to a variable name, it refers to Beryl. Any time you see "R", it is for Reptoslicer, etc etc.
MHP=max health points
HP=health points
MMP=max magic points
MP=magic points
DEF=defense
ATK=attack
MDEF=magic defense
MATK=magic attack
XP=experience points
***Please note that since I have not built the battle engine completely yet, the variables which will be specific to battle are not contained here (except for ATK, DEF, MATK, MDEF)
***String, party-member-specific variables:

     BARM$="LEATHER" :: BWEP$="DAGGER" :: BSTAT$="HEALTHY"
 
     RARM$="WIZARDS ROBE" :: RWEP$="NONE" :: RSTAT$="HEALTHY"
 
     MARM$="LEATHER" :: MWEP$="BROADSWORD" :: MSTAT$="HEALTHY"
 
     SARM$="SPRITES CAP" :: SWEP$="DAGGER" :: SSTAT$="HEALTHY"
 
     BCL$="HERO" :: RCL$="MAGE" :: MCL$="FIGHTER" :: SCL$="THIEF"

As on the numeric variables, these are member-specific... B for Beryl, R for Reptoslicer, etc.
ARM$=armor name
WEP$=weapon name
STAT$=current status (HEALTHY, POISONED, FALLEN, etc)
CL$=class name (this will change for two of the characters, later in the game)
There are likely to be more of these party-member-specific string variables as the game continues to develop, but this is all I needed for now.
***Non-party-member-specific (temporary) variable sets...
As you can see in my code, I have a section called "Activexxx" which loads the temporary variable set "A" with the stats of the selected character. Here is a copy of that segment of code...
 
 

ActiveBeryl:
     AMHP=BMHP :: AHP=BHP :: AMMP=BMMP :: AMP=BMP :: ACN$="BERYL" :: ANSP=12 :: ANL=5 :: AMN=BMN :: ACL$=BCL$ :: AXP=BXP
     AARM$=BARM$ :: AWEP$=BWEP$ :: ASTAT$=BSTAT$ :: ANXLV=(50-BXP) :: ALEV=BLEV
     RETURN
 
ActiveRepto:
     AMHP=RMHP :: AHP=RHP :: AMMP=RMMP :: AMP=RMP :: ACN$="REPTOSLICER" :: ANSP=9 :: ANL=11 :: AMN=RMN :: ACL$=RCL$ :: AXP=RXP
     AARM$=RARM$ :: AWEP$=RWEP$ :: ASTAT$=RSTAT$ :: ANXLV=(50-RXP) :: ALEV=RLEV
     RETURN
 
 
ActiveMarkus:
     AMHP=MMHP :: AHP=MHP :: AMMP=MMMP :: AMP=MMP :: ACN$="MARKUS" :: ANSP=12 :: ANL=6 :: AMN=MMN :: ACL$=MCL$ :: AXP=MXP
     AARM$=MARM$ :: AWEP$=MWEP$ :: ASTAT$=MSTAT$ :: ANXLV=(50-MXP) :: ALEV=MLEV
     RETURN
 
ActiveSkylar:
     AMHP=SMHP :: AHP=SHP :: AMMP=SMMP :: AMP=SMP :: ACN$="SKYLAR" :: ANSP=12 :: ANL=6 :: AMN=SMN :: ACL$=SCL$ :: AXP=SXP
     AARM$=SARM$ :: AWEP$=SWEP$ :: ASTAT$=SSTAT$ :: ANXLV=(50-SXP) :: ALEV=SLEV
     RETURN

As you can see above, it is not a DIRECT copy of the above variables... there are a few new ones.

 

ANSP and ANL stand for: "Name Starting Point" and "Name Length".... Essentially loading these variables into the "A" set allows me to have a uniform "SCREEN INFO DRAW" subroutine, just replacing the name length and name starting point with those specific to the characters. "Reptoslicer" and "Beryl" would not look the same, displayed both starting at (6,5)..... Nor would I be able to do the "underline" of the names I do in the menu display by simply using NSP and NL.

 

The "CN$" variable is simply the character's name and the NXLV numeric variable is simply a value for "Next Level" which you can see on the STATUS menu of the game. I will post a screenshot below so you can see how all these temporary variables are being used.

 

 

markusstatus_zpsp8en9o0o.png

 

 

 

I think I have covered all the variables here, except for the other two temporary sets "C" and "RP"

 

They are just copies of the A set used during the spellcasting menu... In order to be able to simultaneously display character data and then update it upon cast, I needed a way to do quick-loads of character data, then do a fast modify (once spell was cast) and then reload the new RP and C sets back into their respective players' static permanent variable sets. Since the menu calls subroutines from subroutines, once the values are modified, the program simply RETURNs up to the calling sub, the players' static permanent variables are updated, and the program returns to the root of the menu.... Reading the code block I posted at the top of this thread will clearly show what I'm talking about.... even if I'm not making a ton of sense here.

 

 

Anyway... That's it. You have my entire variable set structure for the game (so far.)

 

***My plan for doing legit modification to the variables by plugging them into arrays will look something like this:

 

 

HP(4,2) **4 party members, MHP and HP

MP(4,2) **4 party members, MMP and MP

XP(4) **4 party members XP

BAT(4,2) **4 party members, ATK and DEF

MBAT(4,2) **4 party members, MATK and MDEF

EQUIP$(4,2) **4 party members, ARM$ and WEP$

STAT$(4) **4 party members STAT$ (status)

 

 

That's the start of what I'm hoping to do..... I'm certainly open for suggestions... you guys have already given me alot to think about and I appreciate it. :)

 

You may want to do your STATS and EQUIP as numeric variables and keep the names of equipment and stat values in separate static string arrays. That's going to be way faster for comparisons and checks.

 

For example, you'd have STAT(4), with 1 being Healthy, 2 is Poisoned, 3 is Fallen

And then STAT$(3) has "HEALTHY", "POISONED", and "FALLEN". So to see your stat value you print STAT$(STAT(P)) where P is the player number (1-4)

On paper, doing string comparisons SOUNDS better, but believe me, it's going to hurt you come performance time. In particular, string comparisons are literally doing byte-by-byte checks of the two strings, where doing a numeral comparison of two integers will take MUCH less time.

 

I've noticed myself that a big hurdle is that Extended BASIC is not very fast at updating displays... I was made aware of this again when I was writing Space Trek. So you'll want to simplify that as much as possible and make sure you're not doing expensive computations.

Edited by adamantyr
  • Like 1

Here's what I've got so far... Getting there...... a little at a time. :)


Arraybuild:
DIM HP(4,2),MP(4,2),XP(4),LEV(4),CL$(4),NDIS(4,2)
FOR X=1 TO 4 :: FOR Y=1 TO 2 :: READ B :: HP(X,Y)=B :: NEXT Y :: NEXT X
FOR X=1 TO 4 :: FOR Y=1 TO 2 :: READ B :: MP(X,Y)=B :: NEXT Y :: NEXT X
FOR X=1 TO 4 :: READ B :: XP(X)=B :: NEXT X
FOR X=1 TO 4 :: READ B :: LEV(X)=B :: NEXT X
FOR X=1 TO 4 :: READ B$ :: CL$(X)=B$ :: NEXT X
FOR X=1 TO 4 :: FOR Y=1 TO 2 :: READ B :: NDIS(X,Y)=B :: NEXT Y :: NEXT X
.
.
.
.

ArrayData:

DATA 20,15,16,5,25,18,12,5
DATA 20,5,40,20,0,0,20,12
DATA 10,15,15,0,1,1,1,1
DATA HERO,MAGE,FIGHTER,THIEF
DATA 12,5,9,11,12,6,12,6


Edited by Opry99er

Once all the arrays are set, I'll convert all the global variable display stuff with the new array data.

 

This will make life so much easier, and I can basically throw out much of the temporary variable stuff, simplifying the code drastically.

Here's what I've got so far... Getting there...... a little at a time. :)

Arraybuild:
     DIM HP(4,2),MP(4,2),XP(4),LEV(4),CL$(4),NDIS(4,2)
     FOR X=1 TO 4 :: FOR Y=1 TO 2 :: READ B :: HP(X,Y)=B :: NEXT Y :: NEXT X
     FOR X=1 TO 4 :: FOR Y=1 TO 2 :: READ B :: MP(X,Y)=B :: NEXT Y :: NEXT X
     FOR X=1 TO 4 :: READ B :: XP(X)=B :: NEXT X
     FOR X=1 TO 4 :: READ B :: LEV(X)=B :: NEXT X
     FOR X=1 TO 4 :: READ B$ :: CL$(X)=B$ :: NEXT X
     FOR X=1 TO 4 :: FOR Y=1 TO 2 :: READ B :: NDIS(X,Y)=B :: NEXT Y :: NEXT X
.
.
.
.
 
ArrayData:

DATA 20,15,16,5,25,18,12,5
DATA 20,5,40,20,0,0,20,12
DATA 10,15,15,0,1,1,1,1
DATA HERO,MAGE,FIGHTER,THIEF
DATA 12,5,9,11,12,6,12,6

 

You can speed that up by interleaving the data and reducing the number of separate loops.

 

Here you are:

Arraybuild:
     DIM HP(4,2),MP(4,2),XP(4),LEV(4),CL$(4),NDIS(4,2)
     FOR X=1 TO 4 :: FOR Y=1 TO 2 :: READ HP(X,Y),MP(X,Y),NDIS(X,Y):: NEXT Y :: NEXT X
     FOR X=1 TO 4 :: READ XP(X),LEV(X),CL$(X):: NEXT X

ArrayData:

DATA 20,20,12,15,5,5,16,40,9,5,20,11
DATA 25,0,12,18,0,6,12,20,12,5,12,6
DATA 10,1,HERO
DATA 15,1,MAGE
DATA 15,1,FIGHTER
DATA 0,1,THIEF

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...