View difference between Paste ID: sjYYPq2s and
SHOW: | | - or go back to the newest paste.
1-
1+
/*===========================================
2
        GRRLIB (GX Version)
3
        - Template Code -
4
5
        Minimum Code To Use GRRLIB
6
============================================*/
7
#include <grrlib.h>
8
9
#include <stdlib.h>
10
#include <wiiuse/wpad.h>
11
12
#include "custcolors.h"
13
#include "objects.h"
14
#include "font.h"
15
#include "font.c"
16
17
extern const unsigned char font[];
18
extern const int font_size;
19
20
struct cursor
21
{
22
	int x;
23
	int y;
24
	int rot;
25
};
26
27
struct gametile
28
{
29
	unsigned char chunk_id;
30
	GRRLIB_texImg *tile_bottom; // this is the backgrond tile
31
	GRRLIB_texImg *tile_top; // this is the foreground tile
32
	GRRLIB_texImg *tile_col; // this one will be used for collision
33
};
34
35
/*----------------------------------------------------------------------
36
	These level index collapse/uncollapse functions were provided by GerbilSoft from Sonic Retro,
37
	they're for turning 2d tile coordinates into a 1d level array value and vice-versa
38
----------------------------------------------------------------------*/
39
40
inline int rowcolToIdx(int row, int col)
41
{
42
    return (col + (row * 256));
43
}
44
45
inline int rowFromIdx(int idx)
46
{
47
    return (idx >> 8);
48
}
49
50
inline int colFromIdx(int idx)
51
{
52
    return (idx & 0xFF);
53
}
54
55
/*----------------------------------------------------------------------
56
	LoadMap() is a direct hack from PieChart at the moment. Remember that the new level format 
57
	is a series of horizontal tiles and wraps every 256 entries. It'll also probably need to be
58
	split somehow to load object layouts as well. tilearray[] is the series of u8 values for 
59
	tileID's that make up the level. tuledata[] is the struct that holds all of the PNG images
60
	for each tile.
61
-----------------------------------------------------------------------*/
62
63
struct gametile tiledata[255]; // This holds the tile data
64
u8 tilearray[2560]; // every 256 entries is one 'row', making for 10 rows total.
65
66
bool LoadMap(u8 level)
67
{
68
	u16 h;
69
	FILE *leveldata;
70
	//u8 levelarray[2560];
71
	char levelpath[35];
72
	char FG_path[35];
73
	char BG_path[35];
74
	char COL_path[35];
75
	char sizemessage[30];
76
	unsigned short filesize;
77
	
78
	GRRLIB_ttfFont *error_font = GRRLIB_LoadTTF(font, font_size);
79
	
80
	sprintf(levelpath,"sd:/apps/SonicWii/maps/%d/%d.bin", level, level);
81
	
82
	leveldata = fopen(levelpath, "rb");
83
	
84
	if (leveldata == NULL)
85
	{
86
		while(1)
87
		{
88
			WPAD_ScanPads();
89
			GRRLIB_FillScreen(GRRLIB_BLACK);
90
			GRRLIB_PrintfTTF(90,90, error_font, "Error Loading Map", 18, GRRLIB_WHITE);
91
			GRRLIB_PrintfTTF(90,110, error_font, levelpath, 18, GRRLIB_WHITE);
92
			GRRLIB_PrintfTTF(90,130, error_font, "Press [HOME] to exit.", 14, GRRLIB_WHITE);
93
			
94
			if (WPAD_ButtonsDown(0) & WIIMOTE_BUTTON_HOME) 
95
			{
96
				GRRLIB_Exit();
97
				exit(0);
98
			}
99
			GRRLIB_Render();
100
		}
101
		return false; // error protection, file didn't load
102
	}
103
	
104
	/*if (false) // old tile debugging routine. Use for checking GRRLIB_LoadTextureFromFile
105
	{
106
		tile_error:
107
		while(1)
108
		{
109
			WPAD_ScanPads();
110
			GRRLIB_FillScreen(GRRLIB_BLACK);
111
			GRRLIB_PrintfTTF(90,90, error_font, "Error Loading Tile", 18, GRRLIB_WHITE);
112
			GRRLIB_PrintfTTF(90,110, error_font, COL_path, 18, GRRLIB_WHITE);
113
			GRRLIB_PrintfTTF(90,130, error_font, "Press [HOME] to exit.", 14, GRRLIB_WHITE);
114
			
115
			if (WPAD_ButtonsDown(0) & WIIMOTE_BUTTON_HOME) 
116
			{
117
				GRRLIB_Exit();
118
				exit(0);
119
			}
120
			GRRLIB_Render();
121
		}
122
		return false; // error protection, file didn't load
123
	}*/
124
125
	fseek(leveldata, 0 , SEEK_END);
126
	filesize = ftell(leveldata);
127
	if (ftell(leveldata) != 0xa00)
128
	{
129
		sprintf(sizemessage,"filesize is %d, expected 2560", filesize);
130
		while(1)
131
		{
132
			WPAD_ScanPads();
133
			GRRLIB_FillScreen(GRRLIB_BLACK);
134
			GRRLIB_PrintfTTF(90,90, error_font, "Error Loading Map: Size Mismatch", 18, GRRLIB_WHITE);
135
			GRRLIB_PrintfTTF(90,110, error_font, sizemessage, 18, GRRLIB_WHITE);
136
			GRRLIB_PrintfTTF(90,130, error_font, "Press [HOME] to exit.", 14, GRRLIB_WHITE);
137
			
138
			if (WPAD_ButtonsDown(0) & WIIMOTE_BUTTON_HOME) 
139
			{
140
				GRRLIB_Exit();
141
				exit(0);
142
			}
143
			GRRLIB_Render();
144
		}
145
		return false; // error protection, file didn't load
146
	}
147
	
148
	rewind(leveldata);
149
	fread(&tilearray, 1,2560,leveldata);
150
	
151
	/*for(h=0;h < 2560;h++)
152
	{
153
		tilearray[h] = levelarray[h];// walk through file byte by byte and assign tile ID's accordingly
154
	}*/
155
	
156
	for(h=0; h <= 255; h++)
157
	{
158
		sprintf(COL_path,"maps/%d/%02d.png", level, h);
159
		tiledata[h].chunk_id = h;		
160
		if (GRRLIB_LoadTextureFromFile(COL_path) != NULL) 
161
		{
162
			tiledata[h].tile_col = GRRLIB_LoadTextureFromFile(COL_path);
163
			//GRRLIB_InitTileSet(tiledata[h].tile_col, 256, 256, 0);
164
		}
165
		/*tiledata[h].tile_top = GRRLIB_CreateEmptyTexture(2,2);
166
		tiledata[h].tile_bottom = GRRLIB_CreateEmptyTexture(2,2);*/
167
	}
168
	
169
	fclose(leveldata);
170
	return true;
171
}
172
173
/*------------------------------------------------------------------------------------------
174
	ProcessPlayer()
175
	----------------
176
	All of the player's physics and collision calculations will be processed by this function.
177
	First, the player's state gets passed to a switch statement that decides wether to apply air
178
	physics, ground physics, etc.
179
-------------------------------------------------------------------------------------------*/
180
181
void ProcessPlayer(struct PLAYEROBJ *player)
182
{
183
	enum player_states playerstate;
184
	
185
	player->gnd_speed = player->x_speed + player->y_speed;
186
187
	switch(playerstate)
188
	{
189
		case(PLAYER_GROUND): // All ground physics/collision calcs go here.
190
			if ((WPAD_ButtonsUp(0) & WIIMOTE_BUTTON_UP) && (WPAD_ButtonsUp(0) & WIIMOTE_BUTTON_DOWN))
191
			{
192
				// no D-Pad input, we need to apply surface friction value
193
				// We'll also need to add Collision checks here and at the D-Pad hold to make sure
194
				// sonic doesn't go out of bounds
195
				if (abs(player->x_speed) < FRICTION) player->x_speed = 0;
196
				else if (player->x_speed < 0) player->x_speed = player->x_speed += (FRICTION*-1);
197
				else if (player->x_speed > 0) player->x_speed = player->x_speed += (FRICTION*1);
198
			}
199
			
200
			if (WPAD_ButtonsHeld(0) & WIIMOTE_BUTTON_UP)
201
			{
202
				/* we're holding left on the D-Pad. First we'll need to check our ground speed is
203
				over the limit, then if it isn't, start adding acceleration to the x_speed value.
204
				We'll also want to branch out of this if collision to the left returns true.*/
205
				if (abs(player->x_speed) > MAXSPEED)
206
				{
207
					if (player->x_speed > 0) player->x_speed = MAXSPEED;
208
					if (player->x_speed < 0) player->x_speed = NEG_MAXSPD;
209
				}
210
				
211
				if ((player->x_speed != MAXSPEED) && (player->x_speed != NEG_MAXSPD))
212
				{
213
					if (player->x_speed > 0) player->x_speed += DECELERATION;
214
					if (player->x_speed < 0) player->x_speed -= ACCELERATION;
215
				}
216
			} else if (WPAD_ButtonsHeld(0) & WIIMOTE_BUTTON_DOWN)
217
			{
218
				/* we're holding right on the D-Pad. First we'll need to check our ground speed is
219
				over the limit, then if it isn't, start adding acceleration to the x_speed value.
220
				We'll also want to branch out of this if collision to the left returns true.*/
221
				if (abs(player->x_speed) > MAXSPEED)
222
				{
223
					if (player->x_speed > 0) player->x_speed = MAXSPEED;
224
					if (player->x_speed < 0) player->x_speed = NEG_MAXSPD;
225
				}
226
				
227
				if ((player->x_speed != MAXSPEED) && (player->x_speed != NEG_MAXSPD))
228
				{
229
					if (player->x_speed < 0) player->x_speed += DECELERATION;
230
					if (player->x_speed > 0) player->x_speed -= ACCELERATION;
231
				}
232
			}
233
			break; // Done with ground physics
234
		
235
		case(PLAYER_AIR): // All player air physics/collision goes here
236
		break;
237
		
238
		case(PLAYER_LEFT_WALL): // player left wall physics
239
		break;
240
		
241
		case(PLAYER_RIGHT_WALL): // player right wall physics
242
		break;
243
		
244
		case(PLAYER_CEILING): // player right wall physics
245
		break;
246
		
247
		default: // insert some error handling here, as this state is 'unreachable'
248
		break;
249
	}
250
}
251
252
/*---------------------------------------------------------------------------------
253
	GameLoop() is where most of the real action happens, all of the game's runtime calculations
254
	occur here or are initiated here. Expect this function to change the most. The first thing
255
	we need to do is to load all of P1's graphics. Don't forget that the wii's screen real
256
	estate is 640x480, approximately double the Genesis' 320x244, with some black bars 
257
	on top for proper aspect ratio keeping.
258
-----------------------------------------------------------------------------------*/
259
void GameLoop()
260
{
261
	ir_t ir;
262
	u8 level=1;
263
	
264
	// sonic	
265
	GRRLIB_texImg *tex_sonic_walk = GRRLIB_LoadTextureFromFile("images/sonic/sonic_walk.png");
266
	GRRLIB_texImg *tex_sonic_stand = GRRLIB_LoadTextureFromFile("images/sonic/sonic_stand.png");
267
	GRRLIB_texImg *tex_sonic_ball = GRRLIB_LoadTextureFromFile("images/sonic/sonic_ball.png");
268
	GRRLIB_texImg *tex_sonic_run = GRRLIB_LoadTextureFromFile("images/sonic/sonic_run.png");
269
	GRRLIB_InitTileSet(tex_sonic_walk, 80, 80, 0);
270
	GRRLIB_InitTileSet(tex_sonic_stand, 80, 80, 0);
271
	GRRLIB_InitTileSet(tex_sonic_ball, 80, 80, 0);
272
	GRRLIB_InitTileSet(tex_sonic_run, 80, 80, 0);
273
	unsigned int count;
274
	struct CAMOBJ camera;
275
	struct PLAYEROBJ sonic_obj;
276
	sonic_obj.score = 0;
277
	sonic_obj.lives = 4;
278
	sonic_obj.anim = 0;
279
	sonic_obj.frame = 0;
280
	sonic_obj.x_coord = 77;
281
	sonic_obj.y_coord = 446;
282
	
283
	// ring
284
	GRRLIB_texImg *tex_ring = GRRLIB_LoadTextureFromFile("images/ring.png");	
285
	GRRLIB_ttfFont *font1 = GRRLIB_LoadTTF(font, font_size);
286
	GRRLIB_texImg *tex_pointer = GRRLIB_LoadTextureFromFile("images/cursor.png");
287
	
288
	// cursor for collision picking
289
	struct cursor pointer;
290
	pointer.x=200;
291
	pointer.y=200;
292
	
293
	/*----------------======Game Variables=========----------------------*/
294
	unsigned int tickcounter=0;
295
	u8 framecounter=0;
296
	u8 secondcounter=0;
297
	unsigned int minutecounter=0;	
298
	char score_string[18]="";
299
	char time_string[15]="";
300
	char ring_string[11]="";
301
	char debug_ln1[30]="";
302
	char debug_ln2[30]="";
303
	char debug_ln3[30]="";
304
	char debug_ln4[30]="";
305
	bool debugflag=false;
306
	bool mapflag=false;
307
	camera.x=6;
308
	camera.y=222;
309
	/*----------------======END Game Variables=====-----------------------*/
310
	
311
	
312
	/*----------------=======Level Processing=====------------------------*/
313
	unsigned int vis_tiles_1[3];
314
	unsigned int vis_tiles_2[3];
315
	unsigned int vis_tiles_3[3];
316
	unsigned int vis_tiles_4[3];
317
	unsigned int first_tile;
318
	unsigned int x_current,y_current;
319
	unsigned short h;
320
	LoadMap(level);
321
	/*---------------------=========END level processing====----------------------------*/
322
	
323
	// Done loading, begin game loop.
324
	while(1)
325
	{
326
		tickcounter++;
327
		
328
		if (framecounter < 60) framecounter ++;
329
	
330
		if ((framecounter == 60) && (secondcounter < 60))
331
		{
332
			framecounter = 0;
333
			secondcounter++;
334
		}
335
		
336
		if ((framecounter == 60) && (secondcounter == 60)) 
337
		{
338
			framecounter = 0;
339
			secondcounter = 0;
340
			minutecounter++;
341
		}
342
		
343
		/*------------====Control Collection/Gameplay Calc=====-------------
344
		Obviously comes before drawing =P
345
		--------------------------------------------------------------------*/
346
		WPAD_ScanPads();  // Scan the Wiimotes
347
		WPAD_IR(WPAD_CHAN_0, &ir);
348
		
349
		pointer.x = ir.x;
350
		pointer.y = ir.y;
351
		
352
		if (WPAD_ButtonsHeld(0) & WPAD_BUTTON_RIGHT) camera.y--;
353
		if (WPAD_ButtonsHeld(0) & WPAD_BUTTON_LEFT) camera.y++;
354
		if (WPAD_ButtonsHeld(0) & WPAD_BUTTON_UP) camera.x--;
355
		if (WPAD_ButtonsHeld(0) & WPAD_BUTTON_DOWN) camera.x++;
356
		
357
		if ((WPAD_ButtonsDown(0) & WIIMOTE_BUTTON_ONE) && (debugflag == false)) debugflag = true;
358
		else if ((WPAD_ButtonsDown(0) & WIIMOTE_BUTTON_ONE) && (debugflag == true)) debugflag = false;
359
		
360
		if (WPAD_ButtonsDown(0) & WIIMOTE_BUTTON_TWO) mapflag = true;
361
		
362
		/*--------------========END game calc===========--------------------*/
363
		
364
		GRRLIB_FillScreen(GRRLIB_BLACK);
365
		
366
		/*---------------------------------------------------------------
367
		Map drawing will need to be split into 2 different passes, so that the characters can
368
		be drawn inbetween the 2 layers. This is the first of 2 passes. At any given time, 16
369
		tiles will be in the level renderer. To figure out which tiles to draw and how far to
370
		offset them, we'll need to use the camera's coordinates and divide by 256 to find our
371
		starting tile. The rest can be filled in automatically, as each line is 4 tiles long.
372
		4 arrays were created for holding this render queue, named "vis_tiles_x[4]" 
373
		respectively. A member of CAMOBJ called in_tile was added for computing where in the 
374
		main tile array to search.
375
		-------------------------------------------------------------------*/
376
		// first we fill our screen cache
377
		camera.in_tile[0] = camera.x/256; // row
378
		camera.in_tile[1] = camera.y/256; // column
379
		first_tile = rowcolToIdx(camera.in_tile[0], camera.in_tile[1]);
380
		
381
		for(h = 0; h < 4; h++) // first row
382
		{
383
			vis_tiles_1[h] = first_tile + h;
384
		}
385
		
386
		for(h = 0; h < 4; h++) // second row
387
		{
388
			vis_tiles_2[h] = (first_tile + 256) + h;
389
		}
390
		
391
		for(h = 0; h < 4; h++) // third row
392
		{
393
			vis_tiles_3[h] = (first_tile + 512) + h;
394
		}
395
		
396
		for(h = 0; h < 4; h++) // fourth row
397
		{
398
			vis_tiles_4[h] = (first_tile + 768) + h;
399
		}
400
		
401
		// this is the actual display loop, first pass	
402
		for(h = 0; h < 4; h++)
403
		{
404
			x_current = rowFromIdx(vis_tiles_1[h]) * 256;
405
			y_current = colFromIdx(vis_tiles_1[h]) * 256;
406
			GRRLIB_DrawImg(x_current - camera.x, y_current - camera.y, tiledata[tilearray[vis_tiles_1[h]]].tile_col, 0, 1, 1, GRRLIB_WHITE);
407
		}
408
		
409
		for(h = 0; h < 4; h++)
410
		{
411
			x_current = rowFromIdx(vis_tiles_2[h]) * 256;
412
			y_current = colFromIdx(vis_tiles_2[h]) * 256;
413
			GRRLIB_DrawImg(x_current - camera.x, y_current - camera.y, tiledata[tilearray[vis_tiles_2[h]]].tile_col, 0, 1, 1, GRRLIB_WHITE);
414
		}
415
		
416
		for(h = 0; h < 4; h++)
417
		{
418
			x_current = rowFromIdx(vis_tiles_3[h]) * 256;
419
			y_current = colFromIdx(vis_tiles_3[h]) * 256;
420
			GRRLIB_DrawImg(x_current - camera.x, y_current - camera.y, tiledata[tilearray[vis_tiles_3[h]]].tile_col, 0, 1, 1, GRRLIB_WHITE);
421
		}
422
		
423
		for(h = 0; h < 4; h++)
424
		{
425
			x_current = rowFromIdx(vis_tiles_4[h]) * 256;
426
			y_current = colFromIdx(vis_tiles_4[h]) * 256;
427
			GRRLIB_DrawImg(x_current - camera.x, y_current - camera.y, tiledata[tilearray[vis_tiles_4[h]]].tile_col, 0, 1, 1, GRRLIB_WHITE);
428
		}
429
430
		// Draw Sonic 
431
		GRRLIB_DrawTile(sonic_obj.x_coord - camera.x, sonic_obj.y_coord - camera.y, tex_sonic_stand, 0,1,1,GRRLIB_WHITE,sonic_obj.frame);
432
		GRRLIB_Rectangle(pointer.x, pointer.y, 80, 2, GRRLIB_RED, true);
433
		
434
		// second level render pass goes here.
435
		
436
		// Drawing HUD - this will need to get moved to the end of the drawchain to show up
437
		// on top of everything else
438
		sprintf(score_string, "Score: %d", sonic_obj.score);
439
		sprintf(time_string, "Time: %d:%d:%d", minutecounter,secondcounter,framecounter);
440
		sprintf(ring_string, "Rings: %d", sonic_obj.rings);
441
		GRRLIB_PrintfTTF(32,32, font1, score_string, 26, GRRLIB_WHITE);
442
		GRRLIB_PrintfTTF(32,64, font1, time_string, 26, GRRLIB_WHITE);
443
		GRRLIB_PrintfTTF(32,98, font1, ring_string, 26, GRRLIB_WHITE);
444
		
445
		if ((debugflag == true) && (mapflag == false))
446
		{
447
			sprintf(debug_ln1, "x: %d", camera.x);
448
			sprintf(debug_ln2, "y: %d", camera.y);
449
			sprintf(debug_ln3, "tile: %d:%d | %d", camera.in_tile[0], camera.in_tile[1], first_tile);
450
			GRRLIB_PrintfTTF(420,32, font1, debug_ln1, 18, GRRLIB_WHITE);
451
			GRRLIB_PrintfTTF(420,64, font1, debug_ln2, 18, GRRLIB_WHITE);
452
			GRRLIB_PrintfTTF(420,98, font1, debug_ln3, 18, GRRLIB_WHITE);
453
		}
454
		
455
		while (mapflag == true)
456
		{
457
			WPAD_ScanPads();
458
			debugflag = false;
459
			sprintf(debug_ln1, "%d | %d | %d | %d", vis_tiles_1[0], vis_tiles_1[1], vis_tiles_1[2], vis_tiles_1[3]);
460
			sprintf(debug_ln2, "%d | %d | %d | %d", vis_tiles_2[0], vis_tiles_2[1], vis_tiles_2[2], vis_tiles_2[3]);
461
			sprintf(debug_ln3, "%d | %d | %d | %d", vis_tiles_3[0], vis_tiles_3[1], vis_tiles_3[2], vis_tiles_3[3]);
462
			sprintf(debug_ln4, "%d | %d | %d | %d", vis_tiles_4[0], vis_tiles_4[1], vis_tiles_4[2], vis_tiles_4[3]);
463
			GRRLIB_PrintfTTF(50,32, font1, debug_ln1, 22, GRRLIB_WHITE);
464
			GRRLIB_PrintfTTF(50,64, font1, debug_ln2, 22, GRRLIB_WHITE);
465
			GRRLIB_PrintfTTF(50,98, font1, debug_ln3, 22, GRRLIB_WHITE);
466
			GRRLIB_PrintfTTF(50,130, font1, debug_ln4, 22, GRRLIB_WHITE);
467
			
468
			if (WPAD_ButtonsHeld(0) & WIIMOTE_BUTTON_ONE)
469
			{
470
				mapflag = false;
471
				break;
472
			} else if (WPAD_ButtonsHeld(0) & WPAD_BUTTON_HOME) 
473
			{
474
				GRRLIB_Exit();
475
				exit(0);
476
			}
477
			
478
			GRRLIB_Render();
479
		}
480
		
481
		
482
		if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME) break;
483
		if (WPAD_ButtonsDown(0) & WIIMOTE_BUTTON_A) GRRLIB_ScrShot("screenshot.png");
484
		
485
		GRRLIB_Render();
486
	}
487
	return;
488
}
489
490
int main(int argc, char **argv) 
491
{
492
    // Initialise the Graphics & Video subsystem
493
    GRRLIB_Init();
494
495
    // Initialise the Wiimotes
496
    WPAD_Init();
497
	WPAD_SetDataFormat(WPAD_CHAN_0, WPAD_FMT_BTNS_ACC_IR);
498
499
	GameLoop();
500
	
501
    GRRLIB_Exit(); // Be a good boy, clear the memory allocated by GRRLIB
502
503
    exit(0);  // Use exit() to exit a program, do not use 'return' from main()
504
}