Terrario, a Terraria rewrite for the calculator
Posté le 10/07/2020 16:05
2021 Casio Awards winner, thanks everyone!
Hi. I noticed a while ago there weren't any games like Terraria or Minecraft available for Casio calculators. For the past while I've been working on rewriting Terraria in C for the SH4 calculators using gint. I'm not sure when if ever I'll finish it, since it is a fairly big project, so I've decided to put it here for now.
Here are a few screenshots of the progress so far (some may be out-of-date):
Main menu
Gameplay
Inventory
Crafting
Equipment
A visualisation of a generated world (click for full detail)
The game runs at 30FPS. Worlds are 1000x250 tiles large (640x250 on the 35+E II / GIII).
The control scheme and a crafting guide can be found in the game's About menu.
This forum page is updated regularly with the latest release of the game, as well as a changelog in the comments.
If you aren't sure what an item does, feel free to search it up on the
official Terraria wiki.
Most recent update:
Jungle and a bunch of content.
Up next:
Who knows?
The attached file contains the latest build of the game, as well as instructions and a screenshot compiling script and map tool.
The source code repository as well as early builds of the game can be found at
this GitHub repo and
its Gitea mirror. Obviously, expect bugs in these early builds, though I take care to remove the major ones I find before releasing.
Due to the very large world, the save files for this game are big. Make sure you have at least 450kB of storage space before installing the addin (300kB on Graph 35+E II), and try to keep at least 300kB free afterwards. Tampering with the files in the TERRARIO folder will corrupt the save, so don't do that. The game will warn you if you have low storage space available, so that you can optimise your storage.
NOTE: You must have a Graph 35+ E, Graph 35+E II, fx9860GII, or fx9750GIII model calculator to run this game.
Fichier joint
Citer : Posté le 29/07/2020 11:23 | #
Sounds about right. Is the storage memory optimized after the reset?
Citer : Posté le 29/07/2020 11:25 | #
Checked the storage memory and it appears it didn't actually optimize anything - so what's it doing while it hangs?
Citer : Posté le 29/07/2020 11:30 | #
Just to be sure about the process: you switch out of gint, then call syscall %19f, and then it fails?
Citer : Posté le 29/07/2020 11:35 | #
I'm switching out of gint to the JumpOptimizing function, which then calls the code in the stack which then calls %19f.
SMEM_Optimization works fine on its own, but crashes at the end due to the addin code having been relocated.
Citer : Posté le 29/07/2020 13:30 | #
I'm confused now - you went from "it appears it didn't actually optimize anything" to "SMEM_Optimization works fine on its own". Can you clarify that part?
If you can optimize successfully, you can then try to call App_RegisterAddins and App_Start, but without leaving the ILRAM switch. Do not expect to be able to come back to gint right away, it would be simpler to restart the add-in as a first step. To continue executing your ILRAM switch function after SMEM_Optimization, save pr on the stack and jump to SMEM_Optimization with jsr instead of jmp, then reload pr before you rts.
I think I can work around the addin code being relocated by forcing a TLB flush at the correct moment, but it would be much simpler to debug if we know that the optimization itself succeeds.
Citer : Posté le 29/07/2020 21:12 | #
Sorry - to clarify, calling SMEM_Optimization directly within my program works (then crashes), but using Simon's method doesn't.
Citer : Posté le 29/07/2020 21:16 | #
So the difference between the two situations is calling from RAM versus calling directly from ROM? This would be strange. Could you please show me the complete assembly code and how you call it?
Citer : Posté le 29/07/2020 21:30 | # | Fichier joint
I've attached the assembly code (still don't know it very well, there's very likely some shitty stuff in there), here's the calling method:
#define CODESIZE 0x100
//
void JumpOptimizing(){
int p0, p1;
unsigned char w[] = "Terrario"; // title of the addin to restart after optimization
char optimizationcode[ CODESIZE ];
// reset DefaultCallbackHandler to zero to avoid a finalization crash
GetCallbackAddressPtr( &p0, &p1 ); // see below
*(int*)p1 = 0;
// move to optimization-frame to stack; source see below
memcpy( (void*)optimizationcode, &SMEM_optimize_frame, SMEM_optimize_codelength );
// call it
p0 = ((int (*)( unsigned char* ))optimizationcode)( w );
}
void GetCallbackAddressPtr( int*p0, int*p1 ){
TAddinEstripInformation aei;
App_GetAddinEstripInfo( 100, 0, &aei ); // syscall 0x000E
*p0 = (int)aei.addin_array_addr;
*p1 = *p0 + 4;
}
I use gint_switch(&JumpOptimizing) to call this.
Citer : Posté le 29/07/2020 21:57 | #
Aha there's something I forgot to tell and you may not have realized. The syscall() macro was really never intended for inline use. Look at the start of your code, you should see the problem:
mov.l r14, @-r15
mov.l r13, @-r15
sts.l pr, @-r15
add #-4, r15
mov r4, r13
# After macro expansion:
.align 4
mov.l .syscall_table, r2
mov.l 1f, r0
jsr @r2
nop
1: .long 0x019f
nop
First off you can't do .align 4 like this, this may (and in this case, will) insert a gap in the code. This gap is made of zeroes, which are not valid instructions. Then even if you managed to call you'd end up on .long 0x019f, which disassembles as two zeroes (again not an instruction) followed by mac.l @r9+, @r1+.
Basically: don't use the syscall() macro, just keep .syscall_table in one of the high registers, then put all the macro IDs at the end and copy the load code every time.
There might be other problems but your code seems well put together so I believe this would be the major (if not only) thing.
Citer : Posté le 30/07/2020 11:09 | # | Fichier joint
Most of it is Simon's code
I've changed syscalls to
...
mov.l .<syscall_name>, r0
jsr @r12
nop
...
.App_Start: .long 0x049A
.SMEM_Optimization: .long 0x019F
etc.
Now I'm getting an "Illegal Code Err" message after a hang, with PC and TARGET both 0x0, and no optimization performed.
I've attached the updated assembly source.
Citer : Posté le 30/07/2020 11:35 | #
You can't use r12 without saving it -- all registers from r8 to r15 are callee-saved. Though I don't expect ti to be the problem. I'll try when I can, for now you may start with just the App-running code to see if you can restart successfully, this will help you debug the assembler without the complications of smem optimization.
Also I didn't realize until now but you don't need to copy the code to that array. It's loaded in ILRAM by gint, you can call the function directly.
Citer : Posté le 30/07/2020 11:41 | #
Calling SMEM_optimize_frame(w) directly now, and it actually runs the optimizer properly! It still restarts on exit though, I'm not sure if it's a failure to locate the addin after optimizing or something else.
Citer : Posté le 30/07/2020 18:51 | #
You can separate failures in your app-restarting code from failures caused by the optimization itself by restarting without optimizing. Note that SimLo's doc says r5 in App_Start should be 0 but then sets it to 1. Maybe try setting 0 if you're stuck.
Citer : Posté le 31/07/2020 02:41 | #
Does .section .ilram need to be present for gint to put the code in the ILRAM? I get a system error if it's present and no error if it isn't.
Ajouté le 31/07/2020 à 07:09 :
I might just focus on the game for now, I can't seem to find a way to make App_Start work and I don't know enough Assembly to properly debug it.
Citer : Posté le 31/07/2020 09:08 | #
Yes .section.ilram places the code in a different place in the g1a, which prompts gint to load it to ILRAM. If you need similar functionality from C code, include <gint/defs/attributes.h> and use the GILRAM macro. I'll probably do this to try and debug it.
GILRAM int x = 42;
/* Function in ILRAM */
GILRAM int get_42(void)
{
return 42;
}
Don't worry about it, this would normally be kernel-stuff for me to do. Thank you for doing some of the research
Citer : Posté le 01/08/2020 13:06 | #
Update: Tile variations and (surprise) trees!
The world looks a lot less repetitive now with most tiles having slight variations in their sprites. Trees will now generate on the surface, and give wood when chopped down. The game will now optimize storage when you quit, freeing up space so you don't run into write fail errors and lose your world.
I've also added an exit confirmation menu, and fixed a major bug to do with saving the game.
NOTE: This build was found to contain a bug that may glitch the filesystem and reduce total storage memory, requiring a full reset of the calculator.
Citer : Posté le 01/08/2020 14:56 | #
That's a smart move! I'll keep you up-to-date on dynamic optimization.
Citer : Posté le 11/08/2020 14:00 | # | Fichier joint
Update: Crafting!
- [ALPHA] now opens a crafting menu where you can create items
- Added a functioning workbench, platforms, a chair, and platform interaction (also works with the workbench)
- Added weeds
- Made tree leaves more varied
- Lots of bugfixes (going to the bottom of the world no longer breaks the game )
Citer : Posté le 13/08/2020 20:29 | #
I can see a lot of new blocks right here! This is looking really great. Have you considered submitting an article to the site's weekly project review to show the new features?
Citer : Posté le 14/08/2020 00:21 | #
I have, but I'm not sure how to go about it, or if an article in English would be accepted, or really what to write
Citer : Posté le 14/08/2020 00:46 | #
if the article is in English, I can translate it in the review.
You can write whatever you want, just some screens of your project and a little text to show us what you did and what you want to add ! That can be usefull if you want to make an advertisement for your game !
(Et de toute façon, vous pouvez pas dire le contraire)
MultipliCasio
RDM Calculs
Back Mirror
A Switch To The Top C