rendered paste body#include "../devkitARM/arm-elf/include/math.h"
#include "../tonc_code_/code/tonclib/tonc_gba.h"
#include "./gfx/test.h"
#include "./gfx/font.h"
#include "./snd/Sound.h"
#include "./posprintf.h"
#define RGB8(r,g,b) ( (((b)>>3)<<10) | (((g)>>3)<<5) | ((r)>>3) )
#define TETR_O 0 //Pieces
#define TETR_S 1
#define TETR_Z 2
#define TETR_I 3
#define TETR_T 4
#define TETR_L 5
#define TETR_J 6
#define STANDARD 0 //Drop types
#define FIRM 1
#define SOFT 2
#define DAS 12 //Frame values, may use variable system in the future
#define ARE 18
#define LOCK 30
#define CLEAR 30
#define ROLLS 6 //Number of piece rolls before allowing use of piece in history
#define R 0
#define G 1
#define B 2
#define FONTBASE 9
#define GAMEPAK_RAM ((u8*)0x0E000000)
u8 *Save = GAMEPAK_RAM;
//-------------------------tables-------------------------
const int block_x[7][4][4] = {
{{1,2,1,2},{1,2,1,2},{1,2,1,2},{1,2,1,2},}, //O
{{0,1,1,2},{1,1,2,2},{0,1,1,2},{1,1,2,2},}, //S
{{2,1,1,0},{1,1,0,0},{2,1,1,0},{1,1,0,0},}, //Z
{{0,1,2,3},{1,1,1,1},{0,1,2,3},{1,1,1,1},}, //I
{{0,1,2,1},{1,0,1,1},{1,0,1,2},{1,2,1,1},}, //T
{{0,1,2,0},{0,1,1,1},{2,0,1,2},{1,1,1,2},}, //L
{{0,1,2,2},{0,1,1,1},{0,0,1,2},{1,1,1,2},}, //J
};
const int block_y[7][4][4] = {
{{1,1,2,2},{1,1,2,2},{1,1,2,2},{1,1,2,2},}, //O
{{1,1,2,2},{1,2,0,1},{1,1,2,2},{1,2,0,1},}, //S
{{1,1,2,2},{1,2,0,1},{1,1,2,2},{1,2,0,1},}, //Z - same as S, change made in block_x
{{1,1,1,1},{0,1,2,3},{1,1,1,1},{0,1,2,3},}, //I
{{1,1,1,2},{0,1,1,2},{1,2,2,2},{0,1,1,2},}, //T
{{1,1,1,2},{0,0,1,2},{1,2,2,2},{0,1,2,2},}, //L
{{1,1,1,2},{2,0,1,2},{1,2,2,2},{2,1,0,0},}, //J
};
const int colors[7][3] = {
{255,255,0,},{0,255,0,},{255,0,0},{0,255,255,},{191,0,255,},{255,127,0,},{0,0,255,},};
const float CGrav[15] = {0.125f, 0.25f, .5f, .75f, 1.0f, 1.2f, 1.8f, 2.0f, 2.4f, 3.0f, 4.0f, 5.0f, 6.0f, 8.0f, 20.0f};
const float MStartGrav[5] = {1.0f/64.0f, 1.0f/3.5f, 1/64.0f, 2.0f, 5.0f};
const float MEndGrav[5] = {1.0f/3.5f, 1.0f/1.8f, 1.0f, 4.0f, 3.0f};
const int ClassReq[20] = {0, 400, 800, 1400, 2000, 3500, 5500, 8000, 12000,
16000, 22000, 30000, 40000, 52000, 66000, 82000,
100000, 120000, 126000, 1000000};
//----------------------game text-------------------------
const char m_Modes[17][8] = {"Master \0",
"Accel. \0",
".125 G \0",
".25 G \0",
".50 G \0",
".75 G \0",
"1.0 G \0",
"1.2 G \0",
"1.8 G \0",
"2.0 G \0",
"2.4 G \0",
"3.0 G \0",
"4.0 G \0",
"5.0 G \0",
"6.0 G \0",
"8.0 G \0",
"20 G \0",};
const char Class[19][4] = {"9 \0",
"8 \0",
"7 \0",
"6 \0",
"5 \0",
"4 \0",
"3 \0",
"2 \0",
"1 \0",
"S1\0",
"S2\0",
"S3\0",
"S4\0",
"S5\0",
"S6\0",
"S7\0",
"S8\0",
"S9\0",
"GM\0",};
//----------------------global variables-------------------------
struct {int tx; int ty; int rot; int type;
int vr; int vx; int prev_vx; int vy;
int das; float drop; int lock;
int clear; int live;
int lines; int level; int mode;
int score; int curr_lines; int row_forced; int combo;
int bravo;
int rank; int GM_Req;} P;
int history[4];
int are;
int playfield[10][23];
int timer[3];
int counter;
int frames;
BGINFO bg0;
typedef struct _SOUND_CHANNEL
{
s8 *data; // pointer to the raw sound data in ROM (0 for inactive channel)
u32 pos; // current position in the data (20.12 fixed-point)
u32 inc; // increment (20.12 fixed-point)
u32 vol; // volume (0-64, sort of 1.6 fixed-point)
u32 length; // length of the whole sound (20.12 fixed-point)
u32 loopLength; // length of looped portion (20.12 fixed-point, 0 for no loop)
} SOUND_CHANNEL;
typedef struct _SOUND_VARS
{
s8 *mixBufferBase;
s8 *curMixBuffer;
u32 mixBufferSize;
u8 activeBuffer;
} SOUND_VARS;
extern SOUND_VARS soundVars;
extern SOUND_CHANNEL channel[4];
//----------------------function definitions-------------------------
void GfxInit();
void VarInit();
void BgClear();
void Title();
void Menu();
void PrepGame();
void BgHudSetup();
void ReadyGo();
void GameLoop();
void Pause();
void GameOver();
void WaitForConfirmation();
void Timer();
void PieceControl(int in_are);
void MoveTetrimino(int in_are);
float GMaster(int level);
void ApplyGravity();
void LockTetrimino();
void ClearLine(int line);
void CueTetrimino();
int RandTetrimino(int first);
void CheckLoss();
int CollideTetrimino(int x, int y, int r);
void DispTetrimino();
void DispPlayfield();
void DispNext();
void DispHud();
int DimColor(int color, float dim);
void GfxUpdate();
void SramSaveInt(int val, int pos);
int SramLoadInt(int pos);
//***************************************************************
/*int rand(int max)
{
seed++;
seed *= 69069;
return (unsigned int)(seed) % max;
}*/
#define RAND_A 1588635695
#define RAND_R 1117695901
/* linear congruential generator.
GBA tuning by Clifton Cline (phirewind)*/
u32 seed = 93186752;
u32 random_seed_vbl = 93186752;
// Seed the generator
void rand_seed (u32 init){
if (init != 0)
seed = init;}
// return a random number from 0 to n
u16 rand (u16 n){
// generate a new 32-bit seed
seed = RAND_A * ( seed & 1 ) - RAND_R * ( seed >> 1 );
// apply the new seed to the range (n)
return ( n * (seed >> 16) ) >> 16;}
char string[32];
int convert(conv){
if((conv >= 'a') && (conv <= 'z'))
conv -= 32;
if((conv >= 'A') && (conv <= 'Z'))
return conv - 0x41 + FONTBASE;
else if((conv >= '0') && (conv <= '9'))
return conv - '0' + 26 + FONTBASE;
else if(conv == '-')
return conv - '-' + 36 + FONTBASE;
else if(conv == '.')
return conv - '.' + 37 + FONTBASE;
else
return 0;}
void draw_string(int str_x, int str_y, const char *msg){
int i;
int offset = str_x + str_y * 32;
for (i = 0; msg[i] != 0; ++i)
bg0.map[offset + i] = convert(msg[i]);}
int frames_this = 1, frames_last, vsyncs_this;
void DispFps(){
posprintf(&string[0], "%02d", frames_last);
draw_string(28,18, &string[0]);
posprintf(&string[0], "%02d", vsyncs_this);
draw_string(28,19, &string[0]);
}
void fps(){
rand_seed(random_seed_vbl++);
vsyncs_this++;
if(vsyncs_this >= 60){
frames_last = frames_this;
frames_this = 0;
vsyncs_this = 0;}
REG_IF |= IF_VBLANK;
}
void SetFpsInterrupt(){
REG_INTMAIN= fps;
REG_DISPSTAT |= DSTAT_VBL_IRQ;
REG_IE |= IF_VBLANK;
REG_IME= 1;
}
//***************************************************************
int screen = 0;
int main(){
GfxInit();
SoundInit();
SetFpsInterrupt();
void (*CurrentAction)();
while(1){
vid_vsync();
SoundVsync();
frames_this++;
key_poll();
if(key_is_down(KEY_RESET) == KEY_RESET){
BgClear();
int i;
for(i = 0; i < 4; i++){
oe_set_pos(&oe_buffer[i], 240, 160);
SoundStop(i);}
screen = 0;}
switch(screen){
case 0:
CurrentAction = Title;
break;
case 1:
CurrentAction = Menu;
break;
case 2:
CurrentAction = PrepGame;
break;
case 3:
CurrentAction = ReadyGo;
break;
case 4:
CurrentAction = GameLoop;
break;
case 5:
CurrentAction = GameOver;
break;
case 6:
CurrentAction = Pause;
break;
}
CurrentAction();
DispFps();
GfxUpdate();
}
}
//******************************************************************
//******************************************************************
//******************************************************************
void GfxInit(){
int i;
dma_memcpy(&tile_mem[CBB_OBJ][0], testTiles, testTilesLen); //copy gfx
dma_memcpy(&tile_mem[0][0], testTiles, testTilesLen);
dma_memcpy(&tile_mem[0][(FONTBASE<<1)], fontTiles, fontTilesLen);
dma_memcpy(pal_obj_mem, testPal, testPalLen);
dma_memcpy(pal_bg_mem, testPal, testPalLen);
oam_init();
for(i = 0; i < 7; i++)
pal_bg_mem[i + 1] = DimColor(i, .7);
//pal_bg_mem[i] = testPal[16 + i];
REG_DISPCNT = DCNT_OBJ_ON | DCNT_OBJ_1D | _DCNT_MODE0 | DCNT_BG0_ON; //set modes
for(i = 0; i < 4; i++){
oe_set_attr(&oe_buffer[i], (_OE_A0_SQUARE | OE_A0_256C),
_OE_A1_SIZE_8,
2);
oe_set_pos(&oe_buffer[i], 240, 160);}
bg_init(&bg0, 0, 0, 2, (_BG_REG_S32 | BG_256C));
bg_set_pos(&bg0, 0, 0);
}
void VarInit(){
counter = 0;
P.live = 1; P.lines = 0; P.level = 0; P.score = 0;
P.das = 0; P. clear = 0; P.curr_lines = 0; P.row_forced = 0; P.combo = 1;
P.bravo = 1;
P.rank = 0; P.GM_Req = 0;
int i, ii;
for(i = 0; i < 3; i++)
timer[i] = 0;
for(i = 0; i < 10; i++)
for(ii = -3; ii < 20; ii++)
playfield[i][ii + 3] = 0;
int x = TETR_Z;
for(i = 0; i < 4; i++){
history[i] = x;
x ^= TETR_S;}
while(RandTetrimino(1));
for(i = 0; i < 3; i++)
RandTetrimino(0);
CueTetrimino();
}
void BgClear(){
int i;
for(i = 0; i < 32 * 32; i++)
bg0.map[i] = 0;}
void Title(){
BgClear();
int i;
for(i = 0; i < 4; i++){
oe_set_pos(&oe_buffer[i], 240, 160);
SoundStop(i);}
//seed = SramLoadInt(0);
posprintf(&string[0], "tetris grand master");
draw_string(0,0,&string[0]);
posprintf(&string[0], "wip clone");
draw_string(0,1,&string[0]);
posprintf(&string[0], "speed select");
draw_string(0,3,&string[0]);
P.mode = 0;
screen = 1;
}
void Menu(){
posprintf(&string[0], "%s", &m_Modes[P.mode][0]);
draw_string(1,4,&string[0]);
if(key_hit(KEY_RIGHT))
P.mode++;
else if(key_hit(KEY_LEFT))
P.mode--;
if(P.mode < 0)
P.mode = 16;
P.mode %= 17;
if(key_hit(KEY_A|KEY_START))
screen = 2;}
void PrepGame(){
BgClear();
BgHudSetup();
VarInit();
screen = 3;}
void BgHudSetup(){
int i;
for(i = 10; i < 32 * 20; i += 32)
bg0.map[i] = 8;
posprintf(&string[0], "next");
draw_string(12,0,&string[0]);
posprintf(&string[0], "lines");
draw_string(19,0,&string[0]);
posprintf(&string[0], "level");
draw_string(19,3,&string[0]);
posprintf(&string[0], "---");
draw_string(19,5,&string[0]);
posprintf(&string[0], "points");
draw_string(19,9,&string[0]);
posprintf(&string[0], "rank");
draw_string(12,12,&string[0]);
posprintf(&string[0], "rank up at");
draw_string(12,15,&string[0]);}
void ReadyGo(){
DispTetrimino();
counter++;
if(counter < 60)
posprintf(&string[0], "ready?");
else if(counter < 120)
posprintf(&string[0], " go ");
else{
posprintf(&string[0], " ");
screen = 4;}
draw_string(2,10,&string[0]);}
void GameLoop(){
if(key_hit(KEY_START))
screen = 6; //simple abuseable pause, will be replaced later
Timer();
if((!are)&&(!P.clear)){
PieceControl(are);
MoveTetrimino(are);
DispTetrimino();
}
if(P.clear){
if(P.clear == 1){
SoundPlay(&LINE_CLEAR_DATA, LINE_CLEAR_LENGTH, 18157, 1, 64);
P.score += ((int)(((P.level + P.curr_lines)/4) + 0.5f) + P.row_forced) * P.curr_lines * P.combo * P.bravo;
if(P.score > 999999)
P.score = 999999;}
if(P.clear == CLEAR - 1)
SoundPlay(&LINE_DROP_DATA, LINE_DROP_LENGTH, 18157, 2, 64);
if(P.score > ClassReq[P.rank + 1]){
P.rank++;
if(P.rank == 8)
if(P.level < 300)
P.GM_Req++;
if(P.rank == 12)
if(P.level < 500)
P.GM_Req++;
if(P.rank == 17)
P.GM_Req++;}
//The last GM condition is that the player reach level 999 before 13:30:00, which is checked in Game Over.
P.clear++;
P.clear %= CLEAR;
}
else if(are){
if(are == 1)
CueTetrimino();
if(are == ARE - 1){
CheckLoss();
MoveTetrimino(are);
}
PieceControl(are);
are++;
are %= ARE;
}
if(!P.clear)
DispPlayfield();
if(P.level >= 999){
P.level = 999;
P.live = 0;}
DispHud();
if(!P.live)
screen = 5;
//SramSaveInt(seed, 0);
}
void Pause(){
if(key_hit(KEY_START))
screen = 4;}
void GameOver(){
posprintf(&string[0], "game over");
draw_string(20,12,&string[0]);
if(P.level == 999){
if(P.GM_Req == 3)
if(timer[2] * 60 + timer[1] < 810){
P.rank++;
DispHud();}
posprintf(&string[0], "all clear");
draw_string(20,12,&string[0]);}
if(key_hit(KEY_START))
screen = 0;
}
void Timer(){
timer[0]++;
if(timer[0] >= 60){
timer[1]++;
timer[0] = 0;}
if(timer[1] >= 60){
timer[2]++;
timer[1] = 0;}}
//******************************************************************
//******************************************************************
//******************************************************************
void PieceControl(int in_are){
u16 (*key_are)(u16 key);
if(in_are)
key_are = key_is_down;
else key_are = key_hit;
if(key_are(KEY_B))
P.vr = -1;
else if(key_are(KEY_A))
P.vr = 1;
else P.vr = 0;
P.prev_vx = P.vx;
if(key_is_down(KEY_LEFT))
P.vx = -1;
else if(key_is_down(KEY_RIGHT))
P.vx = 1;
else P.vx = 0;
if(P.prev_vx == P.vx)
if(P.das < DAS)
P.das++;
else;
else P.das = 0;
if(!in_are){
if(key_hit(KEY_UP))
P.vy = FIRM;
else if(key_is_down(KEY_DOWN))
P.vy = SOFT;
else P.vy = STANDARD;}
}
void MoveTetrimino(int in_are){
if(!in_are){
if(P.vx)
if((P.das == 0)||(P.das == DAS))
if(!CollideTetrimino(P.tx + P.vx, P.ty, P.rot))
P.tx += P.vx;}
int i = 1, ii = 0;
if(P.vr)
while(ii < 3){
if(!CollideTetrimino((P.tx + (i - 1)), P.ty, P.rot + P.vr)){
P.rot += P.vr;
P.rot &= 3;
P.tx += (i - 1);
if(in_are)
SoundPlay(&ARE_ROT_DATA, ARE_ROT_LENGTH, 18157, 0, 64);
ii = 4;}
if(in_are)
break;
i++; i %= 3;
ii++;
if((P.type == TETR_I)||(P.type == TETR_O))
break;
if((P.type == TETR_L)||(P.type == TETR_J))
if(P.rot == 0)
if(playfield[P.tx + 1][P.ty + 1])
break;
if(P.type == TETR_T)
if(P.rot == 2)
if(playfield[P.tx + 1][P.ty])
break;
}
if(!P.mode)
P.drop += GMaster(P.level);
else if(P.mode == 1)
P.drop += ((float)(P.level + 1)/60.0f);
else P.drop += CGrav[P.mode - 2];
if(!in_are){
if(P.vy == FIRM){
while(!CollideTetrimino(P.tx, P.ty + 1, P.rot)){
P.lock = 0;
P.ty++;
P.row_forced++;}}
else if(P.vy == SOFT){
if(P.drop < 1){
P.drop = 1;
P.row_forced++;}
P.lock = 254;}
ApplyGravity();}
}
float GMaster(int level){
int lv_mod, ramp = 0, set = 0;
float g;
lv_mod = level % 100;
ramp = (int)(lv_mod/10);
set = (int)(level/100);
if(set < 2){
ramp = (ramp>>1);
}
if(set > 4)
return 20;
g = (float)(((MStartGrav[set] * (float)((10 - ramp)/10.0f)) + (MEndGrav[set] * (float)((ramp)/10.0f))));
return g;
}
void ApplyGravity(){
if(!CollideTetrimino(P.tx, P.ty + 1, P.rot)){
if(P.drop >= 1){
pal_obj_mem[P.type + 1] = DimColor(P.type, 1);
P.lock = 0;
P.drop--;
P.ty++;
ApplyGravity();}}
else{
pal_obj_mem[P.type + 1] = DimColor(P.type, .5 + (.5 * ((float)LOCK - P.lock)/(float)LOCK));
P.lock++; P.drop = 0;
if(P.lock == 1)
SoundPlay(&COLLIDE_DATA, COLLIDE_LENGTH, 18157, 1, 64);}
if(P.lock > LOCK)
LockTetrimino();}
void LockTetrimino(){
are = 1;
int i, ii, clear;
for(i = 0; i < 4; i++)
playfield[P.tx + block_x[P.type][P.rot][i]]
[P.ty + block_y[P.type][P.rot][i] + 3] = P.type + 1;
for(i = 0; i < 20; i++){
clear = 1;
for(ii = 0; ii < 10; ii++)
if(!playfield[ii][i + 3]){
clear = 0; ii = 11;}
if(clear){
ClearLine(i);
P.curr_lines++;}
}
if(P.curr_lines){
for(i = 0; i < 10; i++)
for(ii = 0; ii < 20; ii++)
if(!playfield[i][ii + 4])
P.bravo = 4;
else{P.bravo = 1; break;}
P.combo = (P.combo - 1) + ((P.curr_lines<<1) - 1);}
else P.combo = 1;
//DispPlayfield();
SoundPlay(&SET_DATA, SET_LENGTH, 18157, 2, 64);
int mod;
if(P.level < 900)
mod = 99;
else mod = 98;
if(P.level % 100 != mod)
P.level++;
P.tx = 30;
P.ty = 30;
for(i = 0; i < 4; i++){
oe_set_attr(&oe_buffer[i], (_OE_A0_SQUARE | OE_A0_256C),
_OE_A1_SIZE_8,
0);
oe_set_pos(&oe_buffer[i], 240, 160);
dma_memcpy(pal_obj_mem, testPal, testPalLen);}
}
void ClearLine(int line){
int i, ii;
for(i = 0; i < 10; i++)
playfield[i][line + 3] = 0;
for(i = 0; i < 10; i++)
playfield[i][0] = 0;
DispPlayfield();
for(i = line; i >= -2; --i)
for(ii = 0; ii < 10; ii++)
playfield[ii][i + 3] = playfield[ii][i + 2];
P.lines++; P.clear = 1;
P.level++;
}
int CollideTetrimino(int x, int y, int r){
int i, collision = 0;
for(i = 0; i < 4; i++)
if(!(y + block_y[P.type][(r&3)][i] < 0))
if(playfield[x + block_x[P.type][(r&3)][i]]
[y + block_y[P.type][(r&3)][i] + 3]){
collision = 1; i = 5;}
if(!collision)
for(i = 0; i < 4; i++){
if((x + block_x[P.type][(r&3)][i] < 0)||(x + block_x[P.type][(r&3)][i] > 9)){
collision = 1; i = 5;}
//else if((y + block_y[P.type][(r&3)][i] < 0)||(y + block_y[P.type][(r&3)][i] > 19)) //Okay, so apparently you can rotate out of the upper bound. My bad.
else if(y + block_y[P.type][(r&3)][i] > 19){
collision = 1; i = 5;}}
return collision;}
void CueTetrimino(){
P.tx = 3; //standard tile positions for entering tetrimino
P.ty = -1; //This works until IRS is implemented
P.rot = 0;
P.lock = 0;
P.curr_lines = 0;
P.row_forced = 0;
P.type = history[0];
RandTetrimino(0);
DispNext();
}
int RandTetrimino(int first){
int i, ii, piece, used;
for(i = 0; i < ROLLS; i++){
used = 0;
piece = rand(7)%7;
for(ii = 0; ii < 4; ii++)
if(history[ii] == piece){
used = 1; ii = 5;}
if(!used)
i = ROLLS + 1;}
if(first)
if((piece == TETR_S)||(piece == TETR_Z)||(piece == TETR_O))
return 1;
for(i = 0; i < 4; i++)
history[i] = history[i + 1];
history[3] = piece;
return 0;
}
void CheckLoss(){
if(CollideTetrimino(P.tx, P.ty, P.rot)){
LockTetrimino();
GfxUpdate();
P.live = 0;}
}
void DispTetrimino(){
int i;
for(i = 0; i < 4; i++){
oe_set_pos(&oe_buffer[i], ((P.tx + block_x[P.type][P.rot][i])<<3),
((P.ty + block_y[P.type][P.rot][i])<<3));
oe_buffer[i].attr2 = ((P.type + 1)<<1)&OE_A2_ID_MASK;}}
void DispPlayfield(){
int i, ii;
for(i = 0; i < 10; i++)
for(ii = 0; ii < 20; ii++)
bg0.map[i + ii * 32] = playfield[i][ii + 3];
for(i = 0; i < 10; i++)
for(ii = 0; ii < 3; ii++)
bg0.map[(i + 11) + (ii + 17) * 32] = playfield[i][ii];}
void DispNext(){
int i, ii, iii;
for(iii = 0; iii < 3; iii++){
for(i = 0; i < 4; i++)
for(ii = 0; ii < 4; ii++)
bg0.map[(i + 12 + ((iii || 0)<<1)) + (ii + (iii * 3) + 1) * 32] = 0;
for(i = 0; i < 4; i++)
bg0.map[(block_x[history[iii]][0][i] + 12 + ((iii || 0)<<1)) +
(block_y[history[iii]][0][i] + (iii * 3) + 1) * 32] = history[iii] + 1;}}
void DispHud(){
posprintf(&string[0], "%d", P.lines);
draw_string(19,1,&string[0]);
posprintf(&string[0], "%03d", P.level);
draw_string(19,4,&string[0]);
int set;
set = (((int)(P.level/100)+1)*100);
if(set == 1000)
set--;
posprintf(&string[0], "%03d", set);
draw_string(19,6,&string[0]);
posprintf(&string[0], "%6d", P.score);
draw_string(19,10,&string[0]);
posprintf(&string[0], "%s", Class[P.rank]);
draw_string(13,13,&string[0]);
posprintf(&string[0], "%d", ClassReq[P.rank + 1]);
draw_string(13,16,&string[0]);
posprintf(&string[0], "%02d.%02d.%02d", timer[2],timer[1],timer[0]);
draw_string(12,19,&string[0]);}
int DimColor(int color, float dim){
return RGB8((int)(colors[color][R]*dim), (int)(colors[color][G]*dim), (int)(colors[color][B]*dim));}
void GfxUpdate(){
oe_update(0, 4);
bg_update(&bg0);}
void SramSaveInt(int val, int pos){
int i;
for(i = 0; i < 4; i++)
Save[(pos<<2)+i] = (val>>(i<<3))&255;}
int SramLoadInt(int pos){
int val, i;
for(i = 0; i < 4; i++)
val |= ((Save[(pos<<2)+i])<<(i<<3));
return val;}