Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - E37

Pages: 1 [2] 3 4 ... 24
16
Axe / Re: Does the Link Port Work in Axe?
« on: June 30, 2023, 06:05:36 pm »
@ClainBill
I don't know for a fact that the link port can transfer files. But the Ti-83 has a link menu and no USB port so I assume it can send files over the link port. Looking at some BCALLs, it looks like you can send variables over the link port. Again, I'm not 100% positive, but I can't imagine why a Ti-84+ to Ti-84+ SE link wouldn't work. From the documentation, it seems like the link cable is just 2 lines that either calc can pull low. Since you can put the same OS on a Ti-84+ and a Ti-84+ SE the communication code would be the same. With such basic hardware and identical software, I think it is pretty safe to say that isn't the issue. (And I can't imagine why TI would put a link port on a Ti-84+ if it wasn't compatible with a Ti-83+ too)

Since you have a USB cable, you might be able to do your communications over that. WikiTi is the best documentation you can get for low level stuff like that. There is a lot of ports related to USB and they are poorly documented so unless you really feel like digging, you should probably stick to the link port. If you decide to go for it, I can help you with asm <-> Axe conversions and some guesswork but it will likely be very difficult. But, if you succeed, you could make a super cool Axiom for USB linking for future Axe programmers.

17
Axe / Re: Does the Link Port Work in Axe?
« on: June 30, 2023, 12:27:56 pm »
@ClainBill
The first question is how sure are you that your link cable is good? I wouldn't be surprised if a cable not designed for linking doesn't work. I had a generic cable years ago (and lost it) but was never able to get it to work. A good way to verify this is using the built-in linking tools. Ti-OS has functions like GetCalc( which lets you send variables from one calc to another over a link cable. Or you could use 2nd-X to open the link menu on both calcs and use that to transfer something. If you can send a variable from one calc to another, the cable and link ports are good. If you can't, then there isn't any point in continuing further.

If you are familiar with assembly, you can use Port 0 and try setting a line low on one calc and see if it is pulled low on the other calc. If you aren't, I can write you some simple hex to use it in Axe once you verify the cable can actually transfer data with Ti-OS.

18
Axe / Re: Converting from Prgm to App
« on: April 13, 2023, 07:37:48 am »
@Ki1o
Alright, so I took a look. I just put a bunch of Disp #>Dec statements everywhere so I could see how far execution got. That showed me that it quit right at the line 'Goto UPDATEEND' in your update program. I tracked the problem down to a specific line elsewhere but I will get to that in a minute.
Luckily, there is an easy solution. I moved all your include programs to the end. Since Axe executes in order, putting all your includes at the end means that you don't need Goto statements at the beginning of them anymore. Unlike C, Axe doesn't care about definition order so putting all your includes at the end doesn't hurt anything. If you look at the source for the RTS I sent you, you will notice that that is how I do it for all my code.

When I moved all your includes to the very bottom of your program, it worked fine. The problem? The line 'Pause 16' is the source of all your troubles. From what I can tell that is a compiler bug. That's impressively bad luck, I have only seen 4 compiler bugs in all my time working with Axe and only one like this one where it wasn't just the fault of a function. (For example, Copy()r is a broken function, don't ever use it) Messing around with it some more, I wasn't able to get it to break in a simple test program so there might be more going on. I have used pause many times (although not really with a goto statement jumping over it) so pause isn't just broken. The workaround of moving all your includes to the bottom should fix your problem and make your code a little cleaner. And congratulations on breaking Axe.  ;)

The trick to debugging things like this is to put Disp statements or some other way of showing information all over the place. You will see what is being executed and what parts it didn't get to. Printing out variables also can help for some tricky logic. With that, it only took me a couple minutes to find the problem Goto statement and by moving around the UPDATEEND label, 10 minutes more to find the Pause statement problem.

19
Axe / Re: Converting from Prgm to App
« on: April 11, 2023, 08:37:49 pm »
@Ki1o

The game runs at 15MHz but that is mostly because of graphics. Without drawing, the game could easily run at 3MHz. If I wrote everything in assembly, I could probably get it in its current state to run at 6MHz but it relies on other hardware features of the TI-84+ so it will never run on an 83. Compiled, it is over 100k of executable code. Does the 83 even have that much flash? I guess I could compile the game as an OS but that is way too much work.

The font is my text axiom. You can do the same thing with the built in Text command but that requires a font hook which requires some Asm work. Axe normally just calls TI-OS's text drawing command which is why mine is so much faster.

20
Axe / Re: Converting from Prgm to App
« on: April 11, 2023, 06:43:06 pm »
@Ki1o
State machines are efficient and there is nothing technically wrong with your implementation. They just get complex very quickly and unless very small or very carefully documented are very difficult for your future self to come back and debug. If you can deal with that, there is no reason not to use them.
I wouldn't worry at all about optimization. Heavily optimized Axe code is very difficult to read and that is the last thing you need when you are still learning. Besides, heavy optimization is usually only worth at the most a 20% speedup unless the code is especially inefficient. You will usually get much more significant gains from reorganizing logic - which is easiest if you have clean code.

When I was learning how to program I messed around a lot like you. I have thrown away far more code than I have kept but learned a lot from it - hence the signature below my avatar! Also, re-implementing concepts in Axe is a really good way to understand them. If you can write it in Axe, you can do it any language.

If you are interested, I can send you the source for a real-time strategy game I programmed in Axe. Here is some screenshots. You will need an 84+ SE to hold all the source and the compiled code and I use several custom axioms. It will be quite difficult to follow the flow of execution (although individual features shouldn't be awful)

21
Axe / Re: Converting from Prgm to App
« on: April 11, 2023, 08:40:43 am »
@Ki1o
You are making this way harder than it needs to be. All you need is an if-else chain like this:
Code: [Select]
If getKey(1)

ElseIf getKey(2)

ElseIf getKey(3)

ElseIf getKey(4)

End

To answer you original question, I don't see anything wrong with your logic. The UpdateState isn't initialized when you code first starts but it isn't initialized in your original code either. Beyond that, I don't know. I don't think I have ever actually used sign{} in serious code so it is possible but very unlikely that there is a bug there. The full source would be useful in troubleshooting because I don't see any problems with what you have. I'm not sure what you are doing with UpdateState in general. Are you are trying to make some kind of state machine? I would avoid that if possible as state machines like that can be way harder to debug than Goto spaghetti. (Source: I do that for a living)
I did notice the line 'PlayerX+sign{I-1+°DirY}→PlayerY' That PlayerX is either a typo or a bug.


A quick code critique:
In both this snippit and the code on GitHub, I noticed that you tend to over complicate logic and rely heavily on indexing into arrays. Both are great ways to spend 80% of your time debugging. Here is how I would write movement code. I have a bit more code than your example but I am doing more checks.
Code: [Select]

1→°KDown+1→°KLeft+1→°KRight+1→°KUp .add some constants for the arrow keys. In my code I define every key like this. Now, I don't have to remember that 2 is left, I just type °KLeft
15→°KClear

Lbl UpdatePlayer

getKey(°KClear) or Quit→Quit .getKey returns either 1 or 0. I use 'or' so as not to set Quit to 0 if it was 1 when we got here. This should be moved to the main loop since it isn't player related code.

If ScrollXOffset
If >>0
ScrollRight()
ScrollXOffset--
.-4??PlayerX++ .If you want to make PlayerX change on the boundary of tiles instead of when movement starts, you can uncomment this and remove the PlayerX++ from the getKey block below
Else
ScrollLeft()
ScrollXOffset++
.+4??PlayerX--
End
Return .Don't let the player push keys during scrolling
ElseIf ScrollYOffset .Doesn't need to be an else-if (because of the Return in the line above) but it doesn't hurt anything and makes the intent clearer
If >>0
ScrollDown()
ScrollYOffset--
.-4??PlayerY++
Else
ScrollUp()
ScrollXOffset++
.+4??PlayerY--
End
Return
End
.If execution makes it here, both ScrollXOffset and ScrollYOffset are 0. The screen isn't moving so it is safe to pick a new direction

.getKey(num) commands are very quick. Don't be afraid to check the same key multiple times if it makes your code cleaner. It *is* possible that the key state changes between checks but unlikely. As long as you keep that in mind, it is totally fine to do.
If getKey(°KDown) ? getKey(°KUp)-1 .getKey(°KUp)-1 is the same as getKey(°KUp)=0. Checking both keys makes the player not move if up and down are both held. It is a preference thing and not needed if you don't like it
If Walkable(PlayerX, PlayerY+1) .Or whatever check you use to see if the player is allowed to walk into a given tile. I check this inside the if-else chain so that the walkable status of a tile doesn't impact what direction the player is moving.
PlayerY++
8→ScrollYOffset
Goto UpdatePlayer .This is optional. Without it, the player will spend one tick standing still for each tile they move, making movement seem slightly jerky on an actual calc
End
ElseIf getKey(°KUp) ? getKey(°KDown)-1
If Walkable(PlayerX, PlayerY-1) .You don't check for collision in your code. I assume that will be added later? If it doesn't apply, just remove the 'If Walkable' statements
PlayerY--
-8→ScrollYOffset
Goto UpdatePlayer
End
ElseIf getKey(°KRight) ? getKey(°KLeft)-1
If Walkable(PlayerX+1, PlayerY)
PlayerX++
8→ScrollXOffset
Goto UpdatePlayer
End
ElseIf getKey(°KLeft) ? getKey(°KRight)-1
If Walkable(PlayerX-1, PlayerY)
PlayerX--
-8→ScrollXOffset
Goto UpdatePlayer
End
End
.I only did a couple minor optimizations in this example since my goal was readable code. There is quite a bit that can be done with this code but that is left as an exercise to the reader.

Return

22
Axe / Re: Converting from Prgm to App
« on: April 04, 2023, 07:57:01 am »
Alright, a rewrite often helps eliminate nasty bugs. And there is no difference at all between built in variables and custom ones. Anything you can do with one, you can do with the other.

Since you are rewriting, I have a couple suggestions:


You make two appvars but both are a fixed size. You could combine them into one big appvar. Additionally, you only need to call GetCalc after creating new appvars or resizing existing ones. Once you have created all of them, they won't move.



Free RAM areas:
0x966E is 128 bytes of free memory like L5. It normally holds the contents of the homescreen. (So Disp will overwrite data like L5) When you quit, call Fill(0x966E, 128, ' '). That is just filling it with the space character so it appears blank. I use this one a bunch so I am super positive it is very safe.
0x8000 is 256 bytes of free memory. The end of it overlaps with L4-512 (not a problem if you don't use L4-512 as a 756 byte buffer) But even if you do, it is still 165 bytes of memory. You don't need to clear it or anything when you quit. This also means that if you combine 0x8000 and L4, you get a 933 byte long block of memory. Just remember that it will be corrupted on flash operations (which you aren't doing)
0x8E2C is 400 bytes of free memory. Just fill it with 0's when you quit.
0x85E7 is 158 bytes of free memory. I don't think you even need to fill it with 0's when you quit but you might as well to be safe.
L2 can be used as a 768 byte buffer if you fill it with 0's when you quit. (Hint: you can use ClrDraw(L2) instead of Fill(L2, 768, 0). Its faster and smaller (assuming you have used ClrDraw(buffer) somewhere else)
I think that is all the juicy free memory areas. There is quite a bit of smaller ones but they aren't really worth it unless you are really hurting. Omnimaga's free ram page is a very good tool (Ignore anything it says about Axe - it is very outdated) When using it, make sure to double check that you aren't overlapping any of Axe's variables. To do that, you should do 'Print oA>Hex' Repeat for A-theta, r1-r6, Y1-Y10 (Y variables take up 3 bytes each), X1T-Y6T (the parametric variables - yes, those are built in Axe variables!) and L1-L6. Compare the printed addresses to the free ram are you are looking at.




When dealing with the AI of a bunch of different mobs, it is really awkward (and super slow) to keep having to call {CurrentMob + 5}r and the like to access its variables.
Compare these two pieces of code:
Code: (Hard to read) [Select]
0->MobX
2->MobY
4->MobHP

Lbl MobAI .r1 is the pointer to the mob's data
r1->X .save R1 so function calls don't clobber it

.IsWall and similar functions are just made up psuedocode for the example
!If IsWall({X + oMobX}r + 1, {X + oMobY}r) .Simple, but it will get messy quickly
{X + oMobX}r++
End

!If IsWall({X + oMobX}r, {X + oMobY}r + 1)
{X + oMobY}r++
End

!If {X + oMobHP}r
MobDies(X)
End

Return

Versus:
Code: (Easy to read) [Select]
L1+0->MobX .Put your Mob data at a predetermined spot. I usually use 0x966E (described above in the free ram section) but you can put it wherever you want.
L1+2->MobY
L1+4->MobHP

Lbl MobAI .r1 is the pointer to the mob's data
r1->X .save the value of r1
Copy(X, oMobX, SizeOfMob) .Copies the mob's data to a predetermined spot. Fill in SizeOfMob with however big your mobs are, in bytes.

!If IsWall(MobX + 1, MobY) .This is so much easier to read and type than the above example. And it is way faster and uses less space!
MobX++
End

!If IsWall(MobX, MobY + 1)
MobY++
End

!If MobHP
MobDies(oMobX)
End

Copy(oMobX, X, SizeOfMob) .Copy the data back now that we are done
Return







Asm(E5) pushes HL (which is Axe's version of TI-BASIC's Ans) onto the stack and Asm(E1) pops it. That lets you write code like:
Code: [Select]
Lbl XMagic
X:Asm(E5) .Set X as Axe 'Ans' variable and then push it onto the stack

5->X .Modify and use X however you want
Disp X>Dec

Asm(E1)->X .Pop the last entry from the stack and set X to it
Return

This is super useful as it lets you create local variables.
I don't know how familiar you are with assembly and registers, so I'll explain in more detail what that code does. If you understand what 'push hl' and 'pop hl' means, you can ignore all of this.

Code: [Select]
.Like TI-BASIC, Axe has a variable which is the result of the previous calculation. However, Axe's version doesn't have a name.
X+5 .Add 5 to X but don't do anything with the result. The value is stored in HL which is what Axe's 'Ans' is called.
->Y .Store HL to Y. Since the result hasn't changed, we can use HL again
+2->Z .Add 2 to HL and then store HL to Z
X .Sets HL to the value of X
Asm(E5) .Pushes the value of HL onto the stack. You can push and pop whenever you want as long as you know what you are doing
+5 .Adds 5 to HL
SomeFunction() .Call some function that possibly modifies X. At the start of the function, HL will hold X+5. (so the first line of the function could be '->X' for instance)
Asm(E1) .Pops HL from the stack. Now HL holds the same value it did when the most recent Asm(E5) was called
->X .And save that value to X, effectively protecting it from any modifications that might happen in SomeFunction. (Called functions can push and pop if they want too)

.You can push multiple things to the stack at the same time
X:Asm(E5)
Y:Asm(E5)
MyVariable:Asm(E5)

For(x, 0, 5)
Disp X>Dec
End

Asm(E1)->MyVariable .Notice that the order of pops is inverted from the order of pushes
Asm(E1)->Y
Asm(E1)->X

...
There are some restrictions on when you can push and pop from the stack. Well, you can do it at any time, but if you don't know what you are doing, all you will get is a crash
You must make sure that you call pop the same amount of times you call push before you call 'return'. (This is easy, all it means is that you can't call push a bunch at the start of a function and then call Return without popping everything. You don't need to do anything with the popped results if you don't want to)
The stack is used when calling functions. All that means is that you can't push a variable in one function, call another and pop that variable in the function you just called
The stack is also used for single argument For loops. (3 argument for loops don't have this problem - they use a much less efficient method of looping that doesn't use the stack) That means you can't push a variable outside a For(10) loop and pop it inside the loop. (it is still safe to push and pop inside the loop, just make sure your pushes and pops are balanced inside the loop body.
If you just push some variables at the start of a function and pop them at the end, you will always be safe. It also works well inside complex loops.
...


All this is mostly useful for pushing some variables at the start of a function and then popping them at the end so you don't need to worry about clobbering a variable used elsewhere. Its also super fast, a push or pop is almost twice as fast as addition! (*comparing 'push hl' [11cc] and 'pop hl' [10cc] against 'add hl, de' [19cc]) I would recommend spending 15-20 minutes trying out different uses for this before putting it any serious code. Its no fun debugging code you don't fully understand.
I use this so frequently in my code that I wrote a personal axiom that adds commands 'Push' and 'Pop' that just do Asm(E5) and Asm(E1) respectively.

23
Axe / Re: Converting from Prgm to App
« on: April 03, 2023, 08:58:19 am »
@Ki1o Sorry I took so long, I forgot.
I sent your code to my calc and gave it a look. The code in its original state worked fine as a program and an app. As a program, it leaves garbage all over the homescreen on quit. Adding a 'ClrHome' in Exit will fix that. The total compiled program is only 8k bytes total. Since probably 1k of that is data, you still have some space to play with before you hit the execution limit.

When I uncommented all of your AI code, it consistantly corrupted regardless of whether it was a program or app. I also noticed that the slimes always ignored walls - even before corrupted garbage showed up on screen. I am still digging around but my guess is that bu the time the character walks around that big loop, the slimes move so far out of bounds that they corrupt some area of memory. Regardless of what the cause is, as far as I can tell, it has to do with the mob AI and not compiling as an app.

24
Axe / Re: Converting from Prgm to App
« on: March 27, 2023, 08:00:50 pm »
I'll take a look. I'm kinda busy at the moment so it may be a couple days until I find an hour or two to sit down and hunt through it. If you just want to have over 8811 bytes of executable code, fullrene is probably a better choice over an app (just because it compiles faster) Since the inversion didn't change anything, I think compiling as an app just brings an already existing problem to the surface. None of your code does anything that would matter if it was compiled as app.

You shouldn't try optimizing until you get your code working or have a real need for it. Also, you don't have very much code in total. Are you really running into the execution limit? You are limited to 8811 bytes of code, not data. Your data can go above that limit. I guess I will see when I actually sit down and compile it ;)

25
Axe / Re: Converting from Prgm to App
« on: March 24, 2023, 03:56:29 pm »
I don't see any overflow protection for A* pathfinding although I could have missed it in the complex logic. Right now you create appvFLOOR before appvDISTMAP. Try creating appvDISTMAP first (Just invert the order of the two GetCalc lines in main) If you are overflowing, that should change the overflow behavior. If you aren't then nothing should change. I noticed you used sign{ in quite a few places. I don't know what that is supposed to be, my best guess is the signed{} command. If it is nib{} then that would be the source of your problems. But, based on how you are using it, it looks like signed{} which is fine. The line 'Fill(^^oTargetX,400,0)' seems a little strange but it should be safe. I don't have any other suggestions, I took a hard look at it for over an hour and didn't see any red flags. Do you reset ram after every time you quit normally?

Also that is some beautifully optimized tile drawing code.

26
General Calculator Help / Re: ti connect can't find my ti 83 plus
« on: March 21, 2023, 03:17:35 pm »
still won't work
Then you are out of luck. If you write out a detailed list of what you have done, what software and hardware you have, I might be able to find something you have missed. But so far all you have told me is that you have a TI83 and it won't work.

27
General Calculator Help / Re: ti connect can't find my ti 83 plus
« on: March 19, 2023, 02:36:40 pm »
@burro_ciao
Alright, I double checked TI Connect CE's supported calcs and it doesn't support the TI-83. So that's unfortunate. I guess you are stuck using TI Connect. You will need to reset your calc's ram before and after doing pretty much anything when dealing with TI Connect. I haven't actually dealt with connecting an 83 to a PC as I just work with 84s. Try resetting your ram, plugging it back in and if that doesn't work, try a couple more times. Sometimes it just doesn't feel like working. Restarting TI Connect or even you PC might help too.

There are other linking programs out there. TILP is pretty good. You can download it here. You have to pay attention while installing it because it requires GTK2+. It will run the GTK2+ installer after its installer by default. When going through the GTK2+ installer you MUST enable the 'compatibility dlls' checkbox or TILP won't work. I just installed it on my Windows 10 partition and it works fine for me (at least it launches, I haven't tried sending files with it) so if it doesn't work for you, chances are you missed a step while installing. If that doesn't work even after a couple ram resets, you might try looking around on the internet for other linking software. Its possible that your link cable or other hardware is bad.

If you just want to send things to your calc, resetting all memory might fix things. But that will wipe anything in flash.

28
General Calculator Help / Re: ti connect can't find my ti 83 plus
« on: March 18, 2023, 07:25:57 pm »
@burro_ciao TI Connect is pretty hit or miss for connectivity. (and mostly miss) You should use TI Connect CE which actually works most of the time. If TI Connect CE can't find your calc, archive everything you care about and then reset your ram. That usually fixes connectivity problems.

29
The Axe Parser Project / Re: Axe Parser
« on: November 19, 2022, 11:42:55 am »
Therefore I think it's a shame that, with the source code closed, no one can ever either learn from this project (it must be a treasure trove of z80 writing) or pick it up again. The chance that either Quigibo or Runer112 are reading this is slim, however, I would want to call upon them to provide a final release with the source code, as a last hurrah for Axe.

@aeTIos
Runer112 gave me the source for either Axe 1.3.0 or 1.2.2 (I can't remember which and taking a quick peek at it I can't tell) a long time ago. If there is some very compelling evidence that he would be OK with me publishing it, I will.

Having looked at it more carefully, it is 1.2.2.

30
Axe / Re: Game optimizations?
« on: August 04, 2022, 05:09:12 pm »
@Batprime11
Sorry for taking so long, whenever an Axe question pops up I somehow manage to forget to check Omnimaga for a couple of days. Speed optimizations are my specialty but I'll see what I can do for size.

.DINO
#Icon(007E00FF00DF00FF00F000FE81F883F8C7FEFFFAFFF83FF00FE0066004400660)
41→Q→Z
Pic1DINO1→N
.ANIM 1
Goto MENU

...
Any kind of comments or explanation of what each bit of code does would really help
You seem to be trying to optimize the size of the source as much as the executable
As it is, I don't know what each letter variable means and don't want to play a guessing game
So I am just going to point out the inline optimizations rather than any logic ones
I put a some spacing in places I thought were logical breaks just to help myself read it. You can ignore them
...

prgmTILESPRT

Lbl TXXT
Text(20→B*256+3
...
*256 translates to ld h, l \ ld l, 0 which is 3 bytes
+3 translates to inc hl (x3) which is also three bytes
So it is more space efficient to just do
20→B
Text(20*256+3)
Basically, +3 on its own takes up just as much space as a constant would so there is never any reason to use it to produce a constant result
same thing with *256. Remember that numeric constants are just 3 bytes
I believe only times you can beat numeric constants for size is push/pop hl, +-1, +-2, and 0, or 255, *2, *4. I might be missing one or two but I think that is a complete list. Division is, of course, completely out of the question as / 2 takes up 4 bytes. There are a lot more operations that tie with a numeric constant but at that point it is better to use the constant. I recommend pulling up a list of assembly instructions for doing optimizations like this. Thinking out what logic translates to in assembly makes it a lot easier to see what could or could not save you space.
...
Text r₁
Text(6659
Text r₂
Text(8195
Text r₃
Return

Lbl PAUSE
For(35565) .do you mean 65535? Not that it matters but 35565 is a strange number. Also, -1 (negative 1)  works and is easier to type out
End
Return

.Axe doesn't require constants/variables to be declared before they are used like in C or most other languages. You can move this data to the bottom of the program if you want. I find that doing so makes it nicer to scroll through
[0000000000004143→Pic1DINO1
[7EFFDFFFFFF0FCE0
[677F7F3F1F0C080C
[E0F8E8C080C00000
.ANIM 2
[0000000000004143→Pic1DINO2
[7EFFDFFFFFF0FCE0
[677F7F3F1F080C00
[E0F8E8C0C0C080C0
.CACTUS
[001858D8D8DADBDB→Pic1CACT1
[DB7E3C1818181818

Lbl OPTN .You can use lowercase letters for variable and function names as long as they don't start with one
ClrDraw
PAUSE()
TXXT("Min Dist","Min Offset","Back"
Text(40*256)
Text "Ducking coming soon!
IRect(3,20,32,6
Text(20*256+33
Text Z►Dec
Text(26*256+35
Text Q►Dec
DispGraph

While 1

If B=26 and getKey(2) .The '?' and '??' operators take up the same amount of space as 'and' and 'or' but they also short circuit and don't have bitwise problems. I would use '?' and '??' as drop in replacements for any time you use 'and' and 'or' respectively. Just make sure the short-circuiting doesn't mess any logic up
Text(26*256+35

Text max(Q-1,1)→Q►Dec
PAUSE()
End

If B=26 and getKey(3) .Fun fact: Axe only reads the lower byte of the value passed in here so getKey(X*256+3) would always work the same as getKey(3)
Text(26*256+35
Text min(Q+1,65534)→Q►Dec .The optimization that I did for the same operation on Z applies here too
PAUSE()
End

...
All of your 'If B=# and getKey(#)' statements can be optimized to
!If B-#??getKey(#)-1
This is because getKey always returns 1 or 0. Doing -1 on its result effectively inverts it
...
If B=20 and getKey(2)
Text(20*256+33

...
Text max(Z-1,1)→Z►Dec can be optimized to
Z--??+1→Z
Text ►Dec
For 2 bytes off
...
Text max(Z-1,1)→Z►Dec

PAUSE()
End

If B=20 and getKey(3)
Text(20*256+33
...
Like previously, Text min(Z+1,65534)→Z►Dec can be optimized to
Z++??-1→Z
Text ►Dec
For 2 bytes off. It does limit the max value to 65535 instead of 65534 but I think that is probably fine in your use case
...
Text min(Z+1,65534)→Z►Dec
PAUSE()
End

If getKey(15) or (B=32 and getKey(54)) .Luckily for you, Axe ignores the parenthesis
Pause 400 .Pause <constant> is 10 bytes while your PAUSE() function is only 3 bytes to call. Since this wait is isn't very sensitive, just use PAUSE() here if the timing is close enough.
Goto MENU
End

If getKey(4)
3
Asm(E5 .By pushing/popping here you only gain one byte. Is it really worth the readability hit? Then again, your code is already so unreadable I guess it doesn't matter
IRect(,B,30,6
Asm(E1
IRect(,max(B-6,20)→B,30,6
PAUSE()
End

If getKey(1)
3
Asm(E5
IRect(,B,30,6
Asm(E1
IRect(,min(B+6,32)→B,30,6
PAUSE()
End

DispGraph
End

Lbl MENU
ClrDraw
Fix 5
RectI(0,16,*2+1,26
RectI(1→D,17,31,24
TXXT("PLAY!","OPTIONS","QUIT")
IRect(3,20,27,7

While 1
If getKey(4)
3
Asm(E5
IRect(,B,27,7
Asm(E1
IRect(,max(B-6,20)→B,27,7
D++
PAUSE()
End

If getKey(1)
3
Asm(E5
IRect(,B,27,7
Asm(E1
IRect(,min(B+6,32)→B,27,7
D--
PAUSE()
End

DispGraph

If getKey(15)
Fix 4 .Fix 4 takes up 4 bytes + the return makes it 5. doing a goto to the Fix 4 and return below saves 2 bytes
Return
End

EndIf getKey(54)
!If B-32
Fix 4
Return
End

!If B-26
Goto OPTN
End

Lbl MLOOP
ClrDraw
196→I
47*256→C→B→A
15→F→D→J-2→E→H .What do all these variables mean?
#ExprOn
...
I doubt you are getting much speed boost from #ExprOn. Axe's built in text command is so slow basically invalidates any speed optimizations by itself. (it is just a call to Ti-OS's Text function which is horribly inefficient - so great for size but not for speed) I believe #ExprOn lets Axe pick an unrolled version of Horizontal- below but besides possible other small optimizations it likely doesn't do anything. But again, Axe's built in Text command is horribly slow.
...

While 1
RectI(0,63,95,1
RectI(31,23,65,1
RectI(31,0,+1,22
!If H--
Rect(90,0,+2,23
rand^Q+Z→H
End

...
I could be wrong but the following If statement looks like you are bit testing from the screen. If you are, {22*12+L₆+3}ʳ and 128 (or whatever bit mask you need. add 1 to the address if you need the high byte) is much more space and speed efficient. Also 1 byte reads for non-constant addresses are better than 2 byte ones. (So in most cases leave off the ʳ if you don't need the high 8 bits) In your case, you are reading a constant address so that ʳ is fine.
That won't return the same value as [e] but it will more than make up for you having to hardcode whatever value TS( is expecting
...
If I++ and {22*12+L₆+3}ʳ[e]7
TS(,+1,88,47,Pic1CACT1 .What does TS do? Put a sprite on the screen?
⁻3→I
End

Lbl JUMP
...
Signed operations take up more space than unsigned ones. I believe that ({oD+1} and 128) does the same thing as (D << 0) where that o is the degrees sign. 'xor' works if you want to invert. It's 2's complement so you can just check the most significant bit for the sign
You may want to shift all your operations on D up by some constant value like 65536 / 2. That way you can check below zero without using the signed operators
...
If C-47 or (D<<0)
D+E→D+B→B
End

...
Depending on the expected value of C you can do this
!If C-47
12→E
Else!If /256 .Check to see if the high byte of the last calculation is non-zero if so, it overflowed and C is less than 47
-1→D .subtraction not negative
12→E
12032→B
End
...
If C>47
-1→D
12→E
12032→B
Else!If C-47
12→E
End

...
You can move the 12→E into this if block like this
If C≥47?Select(getKey(4), 12→E)
-350→D
End

If you add the constant 0 as the last entry in both branches of the previous optimized if statement, it will always have hl as non-zero if both branches fail and 0 if they pass so you can remove the C≥47 from the upcoming if block completely. Each 0 constant takes up 3 bytes but C≥47 takes up 11. Additionally you can use the 'and 0' trick described below on the 12→E block for a total of 6 bytes saved (or do a push/pop hl pair in each to save the zero from the conditional if you really hate whoever is reading your code for 7 bytes saved)
...
If C≥47 and getKey(4)
⁻350→D
End

.I would recommend changing this to ':getKey(1)?50→E' just to condense your code a little so more could fit onscreen.
If getKey(1)
50→E
End

...
IIRC, there is no reason to ever use DS< it just expands to what code you would normally replace it with. When I tested it a while ago, I couldn't find any cases where it was faster or more space efficient than just doing '!If F--:20→F:<code>:End'
...
DS<(F,20) .Thanks for closing the parenthesis on most commands after here. Every little bit helps

...
Instead of that if-else block do:
(N-Pic1DINO1?Pic1DINO1,Pic1DINO2)→N (10 byte savings)
...
If Pic1DINO1=N .You kinda dropped the ball on this one. Why not '!If N-Pic1DINO' here? You used that trick several other places.
Pic1DINO2→N
Else
Pic1DINO1→N
End

End

.You may be able to assume something about the value of hl at the end of the DS< block.
2
Asm(E5
TS(,,-2,C,N)
DispGraph
Asm(E1
TS(,,-2,C,N)
RectI(0,63,95,1)
RectI(31,23,65,1)
WRect(31,0,+1,21) .Axe will replace an 'and 0' with ld l, 0 which is only 2 bytes so you can replace this statement with WRect(31,and 0,+1,21). 'or 255' works the same way. Remember that that just affects the lower 8 bits so you have to be sure the high 8 are in a state you want them to be in
Horizontal-
B/256→C

EndIf pxl-Test(15,C+4) or pxl-Test(8,*2+C) or pxl-Test(4,C+16) or getKey(15)
...
If you are feeling especially energetic, you could replace those pxl-Tests with constant bit tests on L6. Since your X value is a constant you wouldn't have to worry about shifting your bit mask. All you would have to do is add C*12 to the offset. I'm not sure if you would come out ahead but it could be worth a shot. You would certainly lose for individual tests but if you could eliminate all 3 you wouldn't have the weight of including the function.
...
Goto MENU

There are quite a few places where using 'and 0' instead of the constant '0' would save a byte. I didn't mention them to avoid comment clutter. They are easy to spot once you know what to look for.

That is probably between 30 and 80 bytes off the total at the cost of whatever readability your code had left. The reality is that the majority of your size is probably just calls to the OS or Axe so there really isn't too much to do to begin with. I would be very careful when optimizing anything larger than this program that aggressively for size because of the risk of logic bugs creeping in during the optimization. I haven't tested these optimizations because you didn't give me the full source so you should double check they work before using them.
I would also suggest getting really comfortable with '?' and '??' because when used correctly they can be your best friends and are better than the bitwise 'and' and 'or' in pretty much every case. Taking advantage of the fact they short circuit to condense a really fat series of if blocks can be nice. You can also do single line conditionals like ':A=3?5→A' which would set A to 5 if it held 3 before which is a lot more readable on the limited space of a calculator screen than the 3 lines usually given for an if block.

Overall, you did some pretty solid optimizations. I would take a serious look at your flow of logic as you are likely to get more gains from reordering and reworking than one-off optimizations unless you already have one of the best possible logic paths. If you implement whatever of my suggestions you want add some comments I'd be thrilled to do another pass.

Here are a couple of other tricks that I didn't get to use but you may find useful:
Built in Axe functions and Axioms do a 'push hl' for commas meaning you can't safely push/pop across them but user functions that use r1-r6 don't so it is safe to push/pop there
If you do a pop <any register> you can then safely goto inside the single argument For( loop. Axe won't let you but you can code it in assembly like Asm(C3(LLabel)) where that is the little L for label address
Assign custom constants. They might slightly slow down compile time but they make the code so much easier to read. You can even rename letter variables like ':oB→oYPos' so after that you can use YPos instead of B. (where the o is the degrees symbol)
While I don't really know what is going on with your logic, I suspect that you could cut down on a lot of calls to [WI]Rect( by just doing DispGraphClrDraw and reworking graphics accordingly. Rectangles that span the width of the screen (like I assume you have for the ground) could be turned into a Fill( command which would save on speed and maybe space too. The value argument of Fill( works great with the 'and 0' and 'or 255' trick I mentioned since it only uses the lower byte.
When given the option always do <Variable>-<Constant> (like X-5) and not <Constant>-<Variable> (like 5-X) the second case is 2 bytes larger.
You can use the colon (':') to separate lines on the same line anytime you want to pack a couple statements on the same line. ':3:Asm(E5)' is a good example but it work for all parts of an If statement. In fact, in the last example, the colon is optional and ':3Asm(E5)' works!

Pages: 1 [2] 3 4 ... 24