Jump to content
IGNORED

Player/Missile Manipulation via Strings


blitterbox

Recommended Posts

There's probably something here somewhere, but my searches aren't finding it.

 

Can somebody give a brief explanation/example/pointer to how to set up PM Graphics to be manipulated via strings?

 

I'm confusing something about how to get the PM graphics area and strings lined up. I just got back into this 8-bit stuff and I'm mighty rusty, plus missing needed documentation.

Link to comment
Share on other sites

As I recall: DIM a string of one character; find its address; calculate the offset needed to start the PM area on the appropriate boundary; DIM a second string of that length., then finally DIM a string of 2 or 4K for the PMG.

 

Alternatively, lower MEMTOP and use that memory.

 

(Adn this is all from memory too, so assume a significant amount of rust on my brain)

Link to comment
Share on other sites

As I recall: DIM a string of one character; find its address; calculate the offset needed to start the PM area on the appropriate boundary; DIM a second string of that length., then finally DIM a string of 2 or 4K for the PMG.

I'm staring at an example from a program listing from this forum, and that appears to be what it's doing, except I don't know what that means. Leaving out the bits I understand:

 

DIM A$(1),B$((((INT(ADR(A$)/1024)+1.5)*1024)-ADR(A$))-5),BUF2$(128)

POKE 54279,(ADR(BUF2$)-512)/256

 

I can't seem to wrap my head around what the dimensioning of B$ is accomplishing exactly or how. I understand that 512 is the offset from the PMBASE address to PLAYER 1 as the program's using low resolution PMs, but not why BUF2$ should wind up being appropriate to calculate the offset from.

Link to comment
Share on other sites

As I recall: DIM a string of one character; find its address; calculate the offset needed to start the PM area on the appropriate boundary; DIM a second string of that length., then finally DIM a string of 2 or 4K for the PMG.

I'm staring at an example from a program listing from this forum, and that appears to be what it's doing, except I don't know what that means. Leaving out the bits I understand:

 

DIM A$(1),B$((((INT(ADR(A$)/1024)+1.5)*1024)-ADR(A$))-5),BUF2$(128)

POKE 54279,(ADR(BUF2$)-512)/256

 

I can't seem to wrap my head around what the dimensioning of B$ is accomplishing exactly or how. I understand that 512 is the offset from the PMBASE address to PLAYER 1 as the program's using low resolution PMs, but not why BUF2$ should wind up being appropriate to calculate the offset from.

 

This online book has a chapter on strings for PM graphics:

 

http://www.atariarchives.org/pmgraphics/

Link to comment
Share on other sites

The better way by far is to use forced String Relocation via the Variable Value Table.

 

I don't have an example, but the technique is - DIM a string of one byte, store it's address in a variable.

Then chain through the VVT, find the string's offset that matches that saved value.

Then change the Offset and Length parameters to suit what you're doing.

 

It's a much more efficient way - by reserving an area such that the RAM you need is guaranteed to be there, you're potentially wasting hundreds or more bytes.

Link to comment
Share on other sites

When I heard of manipulating PMs with strings, I did imagine it would be a matter of pointing the string to the PM location rather than the PM location to the string.

 

I thought this would be easier though wasteful, because I don't recall all the ins and outs of how the variable table works, but I'm not having much luck getting the offsets correct for some reason.

Link to comment
Share on other sites

I'll see if I can whip something up quickly later.

 

The "Atari BASIC Source Book" comes in useful if you've got it, although I don't think it has examples, it does have the table descriptions.

 

First off, you need to find the string's entry in the Variable Value Table. First byte of each entry in the VVT should indicate what kind of variable it is (number, string, array etc)

 

The descriptor field doesn't actually point to the string itself, it's used as an offset into STARP (String/Array Space).

 

So the thing to do is find ADR(string) then keep a variable with that value - STARP.

 

Then once you find the string's entry, change the offset such that it now equals the location you want. In theory you could even point it "backwards", e.g. if you wanted to put RAM at $400-$47F into a string or similar.

Edited by Rybags
Link to comment
Share on other sites

Here's a sample program I just whipped up.

 

The problem with using this technique is that Immediate Mode debugging can become a pain.

Because strings are stored straight after the program, that space actually moves around. If you enter an Immediate Mode command, the strings will usually get moved to accomodate it.

 

To illustrate it, DIM a string then set a variable name to it's ADR. Then try stacked immediate commmands followed by ? ADR(string$)

 

This program as an example points a string to the Colour Shadow registers, then changes the background colour.

 

10 A=1:B=2:C=3
20 DIM C$(1),B$(1)
30 S=ADR(C$):T=708:NL=5:GOSUB 1000
40 ? "OLD ";S;"NEW ";ADR(C$)
50 C$(3,3)=CHR$(130)
999 STOP 
1000 STARP=PEEK(140)+PEEK(141)*256
1010 VVT=PEEK(134)+PEEK(135)*256
1015 VVTEND=PEEK(136)+PEEK(137)*256
1020 COFF=S-STARP:NOFF=T-STARP:IF NOFF<0 THEN NOFF=NOFF+65536
1030 FOR Z=VVT TO VVTEND-8 STEP 8
1040 IF PEEK(Z)<>129 THEN 1190
1050 L=STARP+PEEK(Z+2)+PEEK(Z+3)*256
1060 IF L<>S THEN 1190
1070 ? "FOUND STRING @ ";S
1080 H=INT(NOFF/256):L=NOFF-H*256:POKE Z+2,L:POKE Z+3,H
1090 H=INT(NL/256):L=NL-H*256:POKE Z+4,L:POKE Z+6,L:POKE Z+5,H:POKE Z+7,H
1190 NEXT Z
1490 RETURN 

Set variable "S" to the ADR of the string who's location is to change.

Set variable "T" to the new address where the string is to go.

Set variable "NL" to the new length that the string is to inherit. Note that it's best to just DIM such strings as size (1), any more is just going to waste since you're changing it anyway.

Edited by Rybags
  • Like 1
Link to comment
Share on other sites

...DIM A$(1),B$((((INT(ADR(A$)/1024)+1.5)*1024)-ADR(A$))-5),BUF2$(128)

POKE 54279,(ADR(BUF2$)-512)/256...

 

I don't get why the -5 is subtracted there. Possibly you don't need to do that anyway.

 

And, I'd write:

 

INT(ADR(A$)/1024)*1024+512

 

Instead of

 

(INT(ADR(A$)/1024)+1.5)*1024

 

(not trusting the floating point routines :) )

Edited by analmux
Link to comment
Share on other sites

I finally used PMGs with stings for my latest game (below), the book I found very useful was Atari Player Missile Graphics in BASIC (on atariachives.org). There are a few bugs but otherwise it's step by step, and comprehensive. Hey I managed to follow it, it's the first time I have got PMGs to do anything :!:

 

[edit - Chapter 3 covers using filler strings to get the PMG strings onto a page boundary. ]

Link to comment
Share on other sites

So, I would change

 

DIM A$(1),B$((((INT(ADR(A$)/1024)+1.5)*1024)-ADR(A$))-5),BUF2$(128)

POKE 54279,(ADR(BUF2$)-512)/256

 

into

 

DIM A$(1),B$((INT(ADR(A$)/1024)*1024+1536)-ADR(A$)-5),BUF2$(128)

POKE 54279,(ADR(BUF2$)-512)/256

 

(EDIT: the -5 is needed indeed)

Edited by analmux
Link to comment
Share on other sites

OK, found it out:

 

We could have the following programm-lines:

 

10 DIM A$(1),B$((INT(ADR(A$)/1024)*1024+1536)-ADR(A$)-5),BUF2$(128)
20 POKE 54279,(ADR(BUF2$)-512)/256

 

but instead also

 

10 DIM A$(1)
20 DIM B$((INT(ADR(A$)/1024)*1024+1536)-ADR(A$)-1)
30 DIM BUF2$(128)
40 POKE 54279,(ADR(BUF2$)-512)/256

 

Indeed, I'd expect a -1 instead of a -5.

 

The -1 of course comes from the length of A$ itself.

But, in the first example, the -1 is changed into -5 to compensate some 'mysterious' internal computations, done by the basic application itself, apparently.

Link to comment
Share on other sites

Still new mysteries...just forget my previous post please

 

Trying again and again, now the following code just gives the correct starting address of PMBase:

 

10 DIM A$(1),B$((INT(ADR(A$)/1024)*1024+1536)-ADR(A$)-1),BUF2$(128) 
20 POKE 54279,(ADR(BUF2$)-512)/256
30 ? ADR(BUF2$)

 

It will print 3584 (which is page 14)

 

However, in immediate mode I can ask the address of BUF2$ again, and then it will spit out:

? ADR(BUF2$)
3588

READY
█

 

OK, nevermind.

 

Anyway, the -5 can be replaced by a -1, but all following 3 examples should be correct:

 

10 DIM A$(1),B$((((INT(ADR(A$)/1024)*1024)+1.5)-ADR(A$))-1),BUF2$(128) 
20 POKE 54279,(ADR(BUF2$)-512)/256

 

10 DIM A$(1),B$((INT(ADR(A$)/1024)*1024+1536)-ADR(A$)-1),BUF2$(128) 
20 POKE 54279,(ADR(BUF2$)-512)/256

 

10 DIM A$(1) 
20 DIM B$((INT(ADR(A$)/1024)*1024+1536)-ADR(A$)-1) 
30 DIM BUF2$(128) 
40 POKE 54279,(ADR(BUF2$)-512)/256

 

And, the exact syntax layout doesn't matter.

Link to comment
Share on other sites

From reading the original code posted, as well as the subsequent conversation, I thought the goal was to find the beginning of the first player's memory space. If that is true, then the original addition of 512 would seem to be the proper code.

 

Please correct me if I am wrong. This is not an area where I can even begin to claim to be an expert. I am having problems understanding the addition of 1536 to the ADR of A$, myself.

Link to comment
Share on other sites

From reading the original code posted, as well as the subsequent conversation, I thought the goal was to find the beginning of the first player's memory space. If that is true, then the original addition of 512 would seem to be the proper code.

 

Please correct me if I am wrong. This is not an area where I can even begin to claim to be an expert. I am having problems understanding the addition of 1536 to the ADR of A$, myself.

 

Extra 1024 bytes (1 kB) needs to be added.

 

For example, if the starting address of the A$ variable (at the end of the basic code) is f.e. N*1024+M, where M>>512, then computing the location of the first byte free for PM usage would give a conflictuous situation. That's why another 1024 is added, so you'll end up with 1536.

 

Another example, let's say ADR(A$)=2048+768,

then INT(ADR(A$)/1024)*1024 = 2048 thus INT(ADR(A$)/1024)*1024+512 will be BEFORE the start of the array. Thus, writing to that area will corrupt your basic programm for sure.

Edited by analmux
Link to comment
Share on other sites

Another thing to know:

 

The length of B$ will always be greater than 512, thus there's possibility to fill it up with shape data instead.

 

So, instead you could add 1024 instead of 1536. Then fill up the 512 bytes with a C1$, C2$, C3$ etc.

Each of these strings may contain a block of shape data.

 

Then it's only a matter of moving the shapes around: f.e. BUF2$(Y) = C3$

Link to comment
Share on other sites

Wasn't there some bug in Atari BASIC with 256*N byte string moves that you had to avoid, too?

Chapter 9

>>>

LINES 11045 AND 11047

 

Here I am initializing MISSILES$ and PLAYER0$ in a slightly different way. This is necessary because of an apparent bug in Atari BASIC. It seems that a statement such as MISSILES$=ERASE$ won't work if MISSILES$ is 256 bytes or more.

<<<

:D

Link to comment
Share on other sites

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