RETROTrek - Early Development Thread

All aspects of programming on the Commander X16.
Starsickle
Posts: 81
Joined: Mon Aug 31, 2020 12:00 am

RETROTrek - Early Development Thread

Post by Starsickle »


Optimization question:

Pic below needs some work, as it takes up many lines in the program and requires several helper methods and variables. I'm not sure if I should store some elements as dedicated string variables or not, because I'm unsure if it will save space, especially if I end up sending the screens like Game Over, Mission Complete, and similar into subprogram files along with their helper methods.

 


Question - Screen element optimizizing.png
rje
Posts: 1263
Joined: Mon Apr 27, 2020 10:00 pm
Location: Dallas Area

RETROTrek - Early Development Thread

Post by rje »



Quote




I'm not sure if I should store some elements as dedicated string variables or not, because I'm unsure if it will save space, 



Yes, you will save space, at the mental load of remembering those variables.  And might render quicker -- save the entire first three lines of the message box into one variable, and the lower three into another var.

Regardless, "print a message" could be a subroutine that expects the message to be in a string like ms$.  The subroutine nestles said content into a nice message box.  Use len(ms$)/2 to pad it on either side with spaces... etc.

 


Quote




If you don't mind, I'd like to try my hand of recombobulating this so I can store my own ship information



Of course!  I hope the example helps.  I've started encoding as much data as possible into binary files for storage in high RAM.  I've even got a couple of trade tables leveraged that way.  Anything to help organize things better.

(And I see you've found some errors in my data.  I will have to fix those!)

I've also shoved the star charts into binary files for loading into high RAM.  THAT took up on the order of 20K of low RAM for one measly subsector... totally unacceptable.

 

 

Now I've got a question for you.  Your screen presentation has several views on it.  I was wondering if you do what I've been doing -- that is, brute-forcing the data to specific places on the screen, all at once -- or if you've figured out a more elegant, flexible, maintainable way to present data?

Because I'm kind of stuck on the data view.  I've got this pretty set of "portal"-like areas, into which I very very carefully try to render data, and it's going to drive me mad having to keep track of cursor positions.  I need to separate the concerns, so that I have loose coupling but high cohesion.

 

Screen Shot 2020-10-07 at 9.51.09 AM.png

rje
Posts: 1263
Joined: Mon Apr 27, 2020 10:00 pm
Location: Dallas Area

RETROTrek - Early Development Thread

Post by rje »



On 10/6/2020 at 9:19 AM, Starsickle said:




I'm looking it over - the hardest part of all this really is that everything is in 2 letter variable names - but I can see you start at the starting address (AD) and allocate a specific amount of bytes to the name (24).



First poke unknown - assuming it's a sentinel value or some other control value.



Next is the quick ship profile, which is a Single character Archetype with 5 characters (uhh, a few have 6...). This is pretty slick, as it can be used for more procedural generation and representation.



...



Reading sequentially is a pain and N data lines grows, but perhaps, in known and well-defined cases, an ID can be assigned that matches a memory address for direct access, sorting, etc?



Would love to have this sort of layout with the ability to highlight and select a line by inverting the color of the currently selected line. This is why I have colors set in variables along with their inversions.



Inverting the text is a GREAT way to show selection, old school and effective.  I'll keep that in mind, as well.

By the way, the first POKE sets the view to Bank 1.  It doesn't affect the LOAD... but it's needed for all the PEEKing.

And yeah, if you can map an ID directly to a memory address (or use known indexes... item 5 is always at offset 5 x 64 or etc), then that works.  If you're BORED you can pre-parse records with varying lengths, and store the addresses into a BASIC array.  I prefer not to do that if possible!

(P.S. "sorting" would probably be exactly that: building a BASIC array of addresses based on some sort criterion).

 

 

 

Starsickle
Posts: 81
Joined: Mon Aug 31, 2020 12:00 am

RETROTrek - Early Development Thread

Post by Starsickle »


This is how I'm doing it. I have plans for a full color mode someday, but today is not that day. For now, I simply GOSUB to invert colors, but storing as 4 variables makes it more obvious what's happening.

10 FC%=5 : BC%=0 : FI%=0 : BI%=5 : COLOR FC%, BC%
70 REM //SUBROUTINE - SET COLORS TO STANDARD
71 COLOR FC%, BC%
72 RETURN
73 REM //SUBROUTINE - SET COLORS TO INVERTED
74 COLOR FI%, BI%
75 RETURN

 


1 hour ago, rje said:




Now I've got a question for you.  Your screen presentation has several views on it.  I was wondering if you do what I've been doing -- that is, brute-forcing the data to specific places on the screen, all at once -- or if you've figured out a more elegant, flexible, maintainable way to present data?



For me, important cursor positions for LOCATE are documented within each subroutine. What's more valuable - A REM line of documentation or N pairs of integer variables? You at least need the upperleft corner of each window you write characters in, right?

Your MFD window is very large for something that is presenting options for the player. You have about 24 characters of room before an even border with the top windows. Split that window, and make the lower right a text spam message queue or a some window to present description or data. Perhaps a mode tracking variable for the menu state you are currently in, and after that just use "1110 GET A$: IF A$ = "" THEN 1110" and more to control the input handling immediately instead of risking errors. In UX thought - every action (even in error) the player takes should invoke some kind of feedback from the game - so that has to go someplace.

 

Starsickle
Posts: 81
Joined: Mon Aug 31, 2020 12:00 am

RETROTrek - Early Development Thread

Post by Starsickle »


Problem with the switch statement from earlier:

21 ON CS% GOTO 25,1500,2000,9997,30000
22 GOTO 31110


Presumably, you cannot initialize CS to 0 because once the file is loaded, CS is overwritten. but what happens right now is that the program slips through to 22 (Error). If 22 was not there, it slips to 25, which sets CS to 1, and eventually leads to a REDIM error.

How do I use this correctly? Apparently the implicit 0 does not trigger 25...

 

rje
Posts: 1263
Joined: Mon Apr 27, 2020 10:00 pm
Location: Dallas Area

RETROTrek - Early Development Thread

Post by rje »



23 minutes ago, Starsickle said:




This is how I'm doing it. I have plans for a full color mode someday, but today is not that day. For now, I simply GOSUB to invert colors, but storing as 4 variables makes it more obvious what's happening.




10 FC%=5 : BC%=0 : FI%=0 : BI%=5 : COLOR FC%, BC%
70 REM //SUBROUTINE - SET COLORS TO STANDARD
71 COLOR FC%, BC%
72 RETURN
73 REM //SUBROUTINE - SET COLORS TO INVERTED
74 COLOR FI%, BI%
75 RETURN



 



Elegant and very clear!  Thank you.

 


Quote




For me, important cursor positions for LOCATE are documented within each subroutine. What's more valuable - A REM line of documentation or N pairs of integer variables? You at least need the upperleft corner of each window you write characters in, right?



Yes - I store the upperleft, the width, and height.

You've made me realize that some of my windows are very specific to the data being rendered: the status line at the top is ALWAYS going to be an alarm bar with the same component groups listed.  While the actual component groups may change ship by ship, the nature and form of the data will always be the same.  So there could be coupling of data with presentation.

 


Quote




Your MFD window is very large for something that is presenting options for the player. You have about 24 characters of room before an even border with the top windows. Split that window, and make the lower right a text spam message queue or a some window to present description or data. Perhaps a mode tracking variable for the menu state you are currently in, and after that just use "1110 GET A$: IF A$ = "" THEN 1110" and more to control the input handling immediately instead of risking errors. In UX thought - every action (even in error) the player takes should invoke some kind of feedback from the game - so that has to go someplace.



I'm agreeing with the tendency to move to use GET instead of INPUT.  

I was kind of thinking that I need to swap out the middle windows based on the game's current mode/state.  User input changes that state; windows reorganize accordingly.

 

rje
Posts: 1263
Joined: Mon Apr 27, 2020 10:00 pm
Location: Dallas Area

RETROTrek - Early Development Thread

Post by rje »



49 minutes ago, Starsickle said:




Problem with the switch statement from earlier:




21 ON CS% GOTO 25,1500,2000,9997,30000
22 GOTO 31110



Presumably, you cannot initialize CS to 0 because once the file is loaded, CS is overwritten. but what happens right now is that the program slips through to 22 (Error). If 22 was not there, it slips to 25, which sets CS to 1, and eventually leads to a REDIM error.



How do I use this correctly? Apparently the implicit 0 does not trigger 25...



I wrote a quick thing that shows that when CS%=0, it never takes a branch, assigned or no.  Is that what you're seeing?

You probably want something interesting.  Otherwise you'd force CS% into the range you expect with something like

if CS%=0 then CS%=1

Two ways to store game state are (1) a SEQ file, which requires an SD image mounted; (2) POKEing it into your favorite RAM bank (Ha!).  A third, uncool, way to store game state would be to VPOKE it into VERA RAM.  I've used video RAM before to store game data, like a poor man's steganography.  I don't recommend it unless you have a reason to use it.

Bank 1 might be the easiest way to preserve state.  One byte for CS%... and 8191 more bytes for more stateful data.  Then use Bank 2 and up for other data...

 

rem get ready to load a different BASIC program.
rem because this blows away low RAM, we gotta
rem save state in high RAM.
poke $9f61,1 :rem switch to bank 1 
poke $a000, cs% and 255 :rem store the low byte
...load another BASIC file...

...at the beginning of the just-loaded BASIC file...
poke $9f61,1 :rem switch to bank 1
cs% = peek($a000) :rem fetch state
on cs% goto ....

 

Starsickle
Posts: 81
Joined: Mon Aug 31, 2020 12:00 am

RETROTrek - Early Development Thread

Post by Starsickle »


Okay - this is an easy fix, then. I just cannot have a 0 state when this is first starting.

Starsickle
Posts: 81
Joined: Mon Aug 31, 2020 12:00 am

RETROTrek - Early Development Thread

Post by Starsickle »


The good news: It works again. The game is playable again.

The Bad news: I think only the DATA segment of memory is preserved between LOADs.

RetroTrek-WIP20.thumb.png.b84e27439c196d8e8e507258cd118ccd.png

So in this pic, you can see that some of the string literals did not survive, neither did any of the dimension-ed arrays before they were filled in the Data Initialization file.



But...curiously:

3106 PRINT " RETROTREK - "VN$"          STATUS: "SU$"          RAM: "RF$

Of course, the debug output for ship data DID survive. Well, mostly. The IFFs did not survive, the ship names did not survive. Yikes. I happy the program can execute correctly, but now I have this new problem that defied expectations.

TomXP411
Posts: 1781
Joined: Tue May 19, 2020 8:49 pm

RETROTrek - Early Development Thread

Post by TomXP411 »



On 10/8/2020 at 7:10 AM, Starsickle said:




The good news: It works again. The game is playable again.



The Bad news: I think only the DATA segment of memory is preserved between LOADs.



...;



So in this pic, you can see that some of the string literals did not survive, neither did any of the dimension-ed arrays before they were filled in the Data Initialization file.





But...curiously:




3106 PRINT " RETROTREK - "VN$"          STATUS: "SU$"          RAM: "RF$



Of course, the debug output for ship data DID survive. Well, mostly. The IFFs did not survive, the ship names did not survive. Yikes. I happy the program can execute correctly, but now I have this new problem that defied expectations.



When chaining programs, you have to make sure that the first program is the largest, in terms of code size. This is because BASIC locks in the beginning and end of variable memory when you RUN a program, and it does not move variables when you chain to another program. 

So if you start on a program that's 12K, then load a program that's 15K, the 15K program will overwrite some of your variables. 

So make sure your startup program is the largest. 

Post Reply