Merge branch 'master' of https://github.com/ElijahZAwesome/Minicraft3DS
This commit is contained in:
commit
0ea343ce70
48 changed files with 5552 additions and 3766 deletions
65
README.md
65
README.md
|
@ -1,33 +1,72 @@
|
||||||
# Minicraft3DS
|
# Minicraft3DS
|
||||||
3DS Homebrew port of Notch's ludum dare game "Minicraft"
|
3DS Homebrew port of Notch's ludum dare game "Minicraft"
|
||||||
|
Current Version: Version 1.6.1
|
||||||
|
|
||||||
# Dependencies:
|
----------
|
||||||
|
|
||||||
make by GNUWin32: http://gnuwin32.sourceforge.net/packages/make.htm (Should probably work, you may have to add it to PATH)
|
**Download:**
|
||||||
|
|
||||||
|
If you just want to download the game prebuilt check the releases tab in Github:
|
||||||
|
https://github.com/ElijahZAwesome/Minicraft3DS/releases
|
||||||
|
For building the game yourself look below.
|
||||||
|
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
|
||||||
|
**Dependencies:**
|
||||||
|
|
||||||
|
For building and installing the dependencies look below.
|
||||||
|
|
||||||
ctrulib by smea: https://github.com/smealum/ctrulib
|
ctrulib by smea: https://github.com/smealum/ctrulib
|
||||||
|
|
||||||
citro3d by fincs: https://github.com/fincs/citro3d
|
citro3d by fincs: https://github.com/fincs/citro3d
|
||||||
|
|
||||||
sf2dlib by xerpi: https://github.com/xerpi/sf2dlib
|
sf2dlib by xerpi: https://github.com/xerpi/sf2dlib
|
||||||
|
|
||||||
sfillib by xerpi: https://github.com/xerpi/sfillib
|
sfillib by xerpi: https://github.com/xerpi/sfillib
|
||||||
|
zlib: http://www.zlib.net/
|
||||||
|
|
||||||
zlib: http://www.zlib.net/ (Pst, pro tip: get this from the link below instead! I'ts much easier!)
|
|
||||||
|
|
||||||
Then make sure to have libpng and libjpeg installed, I recommend installing them with this: https://github.com/devkitPro/3ds_portlibs
|
----------
|
||||||
|
|
||||||
# Building
|
|
||||||
|
|
||||||
Check the wiki for an indepth look into dependencies and building, but the synopsis is:
|
**Building:**
|
||||||
|
|
||||||
As well as the dependencies, put bannertool, and makerom either in your path or in the directory. Then simply run build.bat and everything will be there.
|
**1. Install devkitARM by devkitPro**
|
||||||
|
- On Windows download https://sourceforge.net/projects/devkitpro/files/Automated%20Installer/
|
||||||
|
- And install atleast Minimal System and devkitARM
|
||||||
|
- This includes make, ctrulib and citro3d
|
||||||
|
|
||||||
# Version
|
**2. Install zlib, libjpeg-turbo and libpng**
|
||||||
|
- Download 3DS-Portlibs: https://github.com/devkitPro/3ds_portlibs
|
||||||
|
- Run these commands:
|
||||||
|
|
||||||
Current Version: Version 1.4.1
|
```
|
||||||
|
make zlib
|
||||||
|
make install-zlib
|
||||||
|
make libjpeg-turbo
|
||||||
|
make libpng
|
||||||
|
make install
|
||||||
|
```
|
||||||
|
|
||||||
|
**3. Install sf2dlib**
|
||||||
|
- Download https://github.com/xerpi/sf2dlib
|
||||||
|
- In the libsf2d directory run these commands:
|
||||||
|
```
|
||||||
|
make
|
||||||
|
make install
|
||||||
|
```
|
||||||
|
**4. Install sfillib**
|
||||||
|
- Download https://github.com/xerpi/sfillib
|
||||||
|
- In the libsfil directory run these commands:
|
||||||
|
```
|
||||||
|
make
|
||||||
|
make install
|
||||||
|
```
|
||||||
|
|
||||||
|
**5. You can now build Minicraft3DS 3dsx, elf, cia, and 3ds files by running the build.bat file.**
|
||||||
|
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
# License
|
|
||||||
|
|
||||||
You can do anything with the source code (besides sell it) as long as you give proper credit to the right people.
|
You can do anything with the source code (besides sell it) as long as you give proper credit to the right people.
|
||||||
If you are going to make a mod of this version, be sure to give credit to Markus "Notch" Perrson because he did create the original game after all.
|
If you are going to make a mod of this version, be sure to give credit to Markus "Notch" Perrson because he did create the original game after all.
|
||||||
|
|
BIN
data/icons2.png
BIN
data/icons2.png
Binary file not shown.
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
BIN
data/player.png
Normal file
BIN
data/player.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
|
@ -1,5 +1,15 @@
|
||||||
#include "Crafting.h"
|
#include "Crafting.h"
|
||||||
|
|
||||||
|
void cloneRecipeManager(RecipeManager *from, RecipeManager *to) {
|
||||||
|
//free old manager recipes
|
||||||
|
free(to->recipes);
|
||||||
|
|
||||||
|
//copy over recipes
|
||||||
|
to->size = from->size;
|
||||||
|
to->recipes = (Recipe*)malloc(sizeof(Recipe) * to->size);
|
||||||
|
memcpy(to->recipes, from->recipes, sizeof(Recipe) * to->size);
|
||||||
|
}
|
||||||
|
|
||||||
void checkCanCraftRecipes(RecipeManager * rm, Inventory * inv){
|
void checkCanCraftRecipes(RecipeManager * rm, Inventory * inv){
|
||||||
int i, j;
|
int i, j;
|
||||||
for(i = 0; i < rm->size; i++){
|
for(i = 0; i < rm->size; i++){
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include "Item.h"
|
#include "Item.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct _recipecost {
|
||||||
int costItem;
|
int costItem;
|
||||||
int costAmount;
|
int costAmount;
|
||||||
} Cost;
|
} Cost;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct _recipe {
|
||||||
bool canCraft;
|
bool canCraft;
|
||||||
int itemResult;
|
int itemResult;
|
||||||
int itemAmountLevel;
|
int itemAmountLevel;
|
||||||
|
@ -16,7 +16,7 @@ typedef struct {
|
||||||
u8 order; // Used for stable sorting.
|
u8 order; // Used for stable sorting.
|
||||||
} Recipe;
|
} Recipe;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct _recipeManager {
|
||||||
int size;
|
int size;
|
||||||
Recipe * recipes;
|
Recipe * recipes;
|
||||||
} RecipeManager;
|
} RecipeManager;
|
||||||
|
@ -32,6 +32,7 @@ RecipeManager potionMakerRecipes;
|
||||||
|
|
||||||
Recipe defineRecipe(int item, int amountOrLevel, int numArgs, ...);
|
Recipe defineRecipe(int item, int amountOrLevel, int numArgs, ...);
|
||||||
|
|
||||||
|
void cloneRecipeManager(RecipeManager *from, RecipeManager *to);
|
||||||
void checkCanCraftRecipes(RecipeManager * rm, Inventory * inv);
|
void checkCanCraftRecipes(RecipeManager * rm, Inventory * inv);
|
||||||
void sortRecipes(RecipeManager * rm);
|
void sortRecipes(RecipeManager * rm);
|
||||||
bool craftItem(RecipeManager * rm, Recipe* r, Inventory* inv);
|
bool craftItem(RecipeManager * rm, Recipe* r, Inventory* inv);
|
||||||
|
|
|
@ -1,23 +1,6 @@
|
||||||
#include "Entity.h"
|
#include "Entity.h"
|
||||||
|
|
||||||
#define PI 3.141592654
|
#include "Synchronizer.h"
|
||||||
double gaussrand()
|
|
||||||
{
|
|
||||||
static double U, V;
|
|
||||||
static int phase = 0;
|
|
||||||
double Z;
|
|
||||||
|
|
||||||
if(phase == 0) {
|
|
||||||
U = (rand() + 1.) / (RAND_MAX + 2.);
|
|
||||||
V = rand() / (RAND_MAX + 1.);
|
|
||||||
Z = sqrt(-2 * log(U)) * sin(2 * PI * V);
|
|
||||||
} else
|
|
||||||
Z = sqrt(-2 * log(U)) * cos(2 * PI * V);
|
|
||||||
|
|
||||||
phase = 1 - phase;
|
|
||||||
|
|
||||||
return Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
Entity newItemEntity(Item item, int x, int y, int level){
|
Entity newItemEntity(Item item, int x, int y, int level){
|
||||||
Entity e;
|
Entity e;
|
||||||
|
@ -34,8 +17,8 @@ Entity newItemEntity(Item item, int x, int y, int level){
|
||||||
e.entityItem.xx = x;
|
e.entityItem.xx = x;
|
||||||
e.entityItem.yy = y;
|
e.entityItem.yy = y;
|
||||||
e.entityItem.zz = 2;
|
e.entityItem.zz = 2;
|
||||||
e.entityItem.xa = gaussrand() * 0.1;
|
e.entityItem.xa = gaussrand(false) * 0.1;
|
||||||
e.entityItem.ya = gaussrand() * 0.1;
|
e.entityItem.ya = gaussrand(false) * 0.1;
|
||||||
e.entityItem.za = ((float)rand() / RAND_MAX) * 0.45 + 1;
|
e.entityItem.za = ((float)rand() / RAND_MAX) * 0.45 + 1;
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
|
@ -296,8 +279,8 @@ Entity newTextParticleEntity(char * str, u32 color, int x, int y, int level){
|
||||||
e.textParticle.xx = x;
|
e.textParticle.xx = x;
|
||||||
e.textParticle.yy = y;
|
e.textParticle.yy = y;
|
||||||
e.textParticle.zz = 2;
|
e.textParticle.zz = 2;
|
||||||
e.textParticle.xa = gaussrand() * 0.3;
|
e.textParticle.xa = gaussrand(false) * 0.3;
|
||||||
e.textParticle.ya = gaussrand() * 0.2;
|
e.textParticle.ya = gaussrand(false) * 0.2;
|
||||||
e.textParticle.za = ((float)rand() / RAND_MAX) * 0.7 + 2;
|
e.textParticle.za = ((float)rand() / RAND_MAX) * 0.7 + 2;
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
|
@ -310,7 +293,7 @@ Entity newSmashParticleEntity(int x, int y, int level){
|
||||||
e.x = x;
|
e.x = x;
|
||||||
e.y = y;
|
e.y = y;
|
||||||
e.canPass = true;
|
e.canPass = true;
|
||||||
playSound(snd_monsterHurt);
|
playSoundPositioned(snd_monsterHurt, e.level, e.x, e.y); //TODO: This is a wierd location for the effect
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
|
|
||||||
typedef struct Entity Entity;
|
typedef struct Entity Entity;
|
||||||
|
|
||||||
|
typedef struct _plrd PlayerData; //in order to not include Player.h and cause all sorts of problems
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
s8 ax;
|
s8 ax;
|
||||||
s8 ay;
|
s8 ay;
|
||||||
|
@ -50,8 +52,7 @@ typedef struct {
|
||||||
int swimBreathTimer;
|
int swimBreathTimer;
|
||||||
int speedTimer;
|
int speedTimer;
|
||||||
int score;
|
int score;
|
||||||
Inventory* inv;
|
PlayerData *data;
|
||||||
Item* activeItem;
|
|
||||||
} Player;
|
} Player;
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,9 +70,8 @@ typedef struct {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
s16 itemID;
|
s16 itemID;
|
||||||
bool active;
|
bool active;
|
||||||
s8 r; // light radius for lantern. window select for chests.
|
s8 r; // light radius for lantern.
|
||||||
Inventory* inv; // Points to chest inventory.
|
Inventory* inv; // Points to chest inventory.
|
||||||
s16 oSel; // other selection inside the chest inv.
|
|
||||||
} EntityFurniture;
|
} EntityFurniture;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -219,18 +219,16 @@ struct Entity {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Entity entities[6][1000];
|
Entity entities[6][1000];
|
||||||
s16 lastSlot[6];
|
s16 lastSlot[6];
|
||||||
Inventory invs[301];//1 for the player, 300 for chests.
|
Inventory invs[300];
|
||||||
s16 nextInv;
|
s16 nextInv;
|
||||||
} EntityManager;
|
} EntityManager;
|
||||||
|
|
||||||
EntityManager eManager;
|
EntityManager eManager;
|
||||||
Entity nullEntity;
|
Entity nullEntity;
|
||||||
s8 currentLevel;
|
|
||||||
|
|
||||||
|
|
||||||
double gaussrand();
|
|
||||||
Entity newItemEntity(Item item, int x, int y, int level);
|
Entity newItemEntity(Item item, int x, int y, int level);
|
||||||
Entity newFurnitureEntity(int itemID,Inventory * invPtr, int x, int y, int level);
|
Entity newFurnitureEntity(int itemID, Inventory * invPtr, int x, int y, int level);
|
||||||
Entity newPassiveEntity(int type, int x, int y, int level);
|
Entity newPassiveEntity(int type, int x, int y, int level);
|
||||||
Entity newZombieEntity(int lvl, int x, int y, int level);
|
Entity newZombieEntity(int lvl, int x, int y, int level);
|
||||||
Entity newSkeletonEntity(int lvl, int x, int y, int level);
|
Entity newSkeletonEntity(int lvl, int x, int y, int level);
|
||||||
|
|
1923
source/Globals.c
1923
source/Globals.c
File diff suppressed because it is too large
Load diff
129
source/Globals.h
129
source/Globals.h
|
@ -1,11 +1,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <3ds.h>
|
#include <3ds.h>
|
||||||
#include "SaveLoad.h"
|
#include "Entity.h"
|
||||||
|
#include "Player.h"
|
||||||
#include "Input.h"
|
#include "Input.h"
|
||||||
#include "MapGen.h"
|
#include "MapGen.h"
|
||||||
#include "Quests.h"
|
#include "Quests.h"
|
||||||
|
|
||||||
#include "icons2_png.h"
|
#include "icons2_png.h"
|
||||||
|
#include "player_png.h"
|
||||||
#include "Font_png.h"
|
#include "Font_png.h"
|
||||||
#include "bottombg_png.h"
|
#include "bottombg_png.h"
|
||||||
|
|
||||||
|
@ -17,19 +20,23 @@
|
||||||
#define MENU_TUTORIAL 2
|
#define MENU_TUTORIAL 2
|
||||||
#define MENU_ABOUT 3
|
#define MENU_ABOUT 3
|
||||||
#define MENU_SETTINGS 4
|
#define MENU_SETTINGS 4
|
||||||
#define MENU_INVENTORY 5
|
#define MENU_LOADGAME 5
|
||||||
#define MENU_CRAFTING 6
|
#define MENU_SETTINGS_REBIND 6
|
||||||
#define MENU_CONTAINER 7
|
#define MENU_SETTINGS_TP 7
|
||||||
#define MENU_WIN 8
|
#define MENU_MULTIPLAYER_HOST 8
|
||||||
#define MENU_LOSE 9
|
#define MENU_MULTIPLAYER_JOIN 9
|
||||||
#define MENU_PAUSED 10
|
#define MENU_MULTIPLAYER_WAIT 10
|
||||||
#define MENU_LOADGAME 11
|
#define MENU_LOADING 11
|
||||||
#define MENU_SETTINGS_REBIND 12
|
|
||||||
#define MENU_SETTINGS_TP 13
|
#define MENU_PAUSED 100
|
||||||
#define MENU_DUNGEON 14
|
#define MENU_INVENTORY 101
|
||||||
#define MENU_NPC 15
|
#define MENU_CRAFTING 102
|
||||||
#define MENU_MULTIPLAYER 16
|
#define MENU_CONTAINER 103
|
||||||
#define MENU_ARMOR 17
|
#define MENU_WIN 104
|
||||||
|
#define MENU_LOSE 105
|
||||||
|
#define MENU_DUNGEON 106
|
||||||
|
#define MENU_NPC 107
|
||||||
|
#define MENU_CHARACTER_CUSTOMIZE 108
|
||||||
|
|
||||||
#define NPC_GIRL 0
|
#define NPC_GIRL 0
|
||||||
#define NPC_PRIEST 1
|
#define NPC_PRIEST 1
|
||||||
|
@ -79,16 +86,17 @@
|
||||||
|
|
||||||
#define SWAP_UINT32(x) (((x) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | ((x) << 24))
|
#define SWAP_UINT32(x) (((x) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | ((x) << 24))
|
||||||
|
|
||||||
|
//WARNING: Having this set to different values in different clients will break multiplayer!
|
||||||
|
#define TESTGODMODE false
|
||||||
|
|
||||||
|
u32 localUID;
|
||||||
|
|
||||||
bool screenShot;
|
|
||||||
int loadedtp;
|
int loadedtp;
|
||||||
|
|
||||||
u8 MODEL_3DS;
|
u8 MODEL_3DS;
|
||||||
|
|
||||||
extern char versionText[34];
|
extern char versionText[34];
|
||||||
|
|
||||||
Entity player;
|
|
||||||
|
|
||||||
bool shouldRenderDebug;
|
bool shouldRenderDebug;
|
||||||
bool shouldSpeedup;
|
bool shouldSpeedup;
|
||||||
bool shouldRenderMap;
|
bool shouldRenderMap;
|
||||||
|
@ -96,18 +104,12 @@ bool UnderStrengthEffect;
|
||||||
bool UnderSpeedEffect;
|
bool UnderSpeedEffect;
|
||||||
bool regening;
|
bool regening;
|
||||||
bool UnderSwimBreathEffect;
|
bool UnderSwimBreathEffect;
|
||||||
u8 zoomLevel;
|
|
||||||
char mapText[32];
|
|
||||||
s16 mScrollX, mScrollY;
|
|
||||||
|
|
||||||
sf2d_texture *icons;
|
sf2d_texture *icons;
|
||||||
|
sf2d_texture *playerSprites;
|
||||||
sf2d_texture *font;
|
sf2d_texture *font;
|
||||||
sf2d_texture *bottombg;
|
sf2d_texture *bottombg;
|
||||||
sf2d_texture * minimap[6];
|
sf2d_texture *minimap[6];
|
||||||
u8 map[6][128*128];
|
|
||||||
u8 data[6][128*128];
|
|
||||||
u8 minimapData[128*128];
|
|
||||||
u8 compassData[6][3];
|
|
||||||
|
|
||||||
u32 dirtColor[5];
|
u32 dirtColor[5];
|
||||||
u32 grassColor;
|
u32 grassColor;
|
||||||
|
@ -129,65 +131,72 @@ char currentFileName[256];
|
||||||
extern u8 currentMenu;
|
extern u8 currentMenu;
|
||||||
extern char fpsstr[];
|
extern char fpsstr[];
|
||||||
u8 initGame;
|
u8 initGame;
|
||||||
|
u8 initMPGame;
|
||||||
u8 initBGMap;
|
u8 initBGMap;
|
||||||
Item noItem;
|
Item noItem;
|
||||||
int airWizardHealthDisplay;
|
int airWizardHealthDisplay;
|
||||||
s16 awX, awY;
|
s16 awX, awY;
|
||||||
u32 tickCount;
|
|
||||||
RecipeManager* currentRecipes;
|
|
||||||
Entity* curChestEntity;
|
|
||||||
char* currentCraftTitle;
|
|
||||||
s16 curInvSel;
|
|
||||||
bool quitGame;
|
bool quitGame;
|
||||||
s8 currentSelection;
|
s8 currentSelection;
|
||||||
bool isRemote;
|
|
||||||
|
|
||||||
u16 daytime;
|
typedef struct _worldData {
|
||||||
int day;
|
u8 map[6][128*128];
|
||||||
u8 season;
|
u8 data[6][128*128];
|
||||||
bool rain;
|
|
||||||
|
|
||||||
void tickTile(int x, int y);
|
u16 daytime;
|
||||||
|
int day;
|
||||||
|
u8 season;
|
||||||
|
bool rain;
|
||||||
|
|
||||||
|
u8 compassData[6][3];
|
||||||
|
} WorldData;
|
||||||
|
|
||||||
|
WorldData worldData;
|
||||||
|
|
||||||
|
//TODO: cleanup the order
|
||||||
|
int getEntities(Entity** result, s8 level, int x0, int y0, int x1, int y1);
|
||||||
|
|
||||||
|
bool moveMob(Entity* e, int xa, int ya);
|
||||||
|
void hurtEntity(Entity *e, int damage, int dir, u32 hurtColor, Entity *damager);
|
||||||
|
|
||||||
|
void tickTile(s8 level, int x, int y);
|
||||||
bool tileIsSolid(int tile, Entity * e);
|
bool tileIsSolid(int tile, Entity * e);
|
||||||
|
|
||||||
s8 itemTileInteract(int tile, Item* item, int x, int y, int px, int py, int dir);
|
s8 itemTileInteract(int tile, PlayerData *pd, Item *item, s8 level, int x, int y, int px, int py, int dir);
|
||||||
|
|
||||||
void tickEntity(Entity* e);
|
void tickEntity(Entity* e);
|
||||||
|
|
||||||
void tickTouchMap();
|
|
||||||
void tickTouchQuickSelect();
|
|
||||||
|
|
||||||
void trySpawn(int count, int level);
|
void trySpawn(int count, int level);
|
||||||
|
|
||||||
int getTile(int x, int y);
|
int getTile(s8 level, int x, int y);
|
||||||
|
void setTile(int id, s8 level, int x, int y);
|
||||||
|
int getData(s8 level, int x, int y);
|
||||||
|
void setData(int id, s8 level, int x, int y);
|
||||||
u32 getTileColor(int tile);
|
u32 getTileColor(int tile);
|
||||||
void setTile(int id, int x, int y);
|
|
||||||
int getData(int x, int y);
|
|
||||||
void setData(int id, int x, int y);
|
|
||||||
|
|
||||||
bool intersectsEntity(int x, int y, int r, Entity* e);
|
bool intersectsEntity(int x, int y, int r, Entity* e);
|
||||||
|
|
||||||
bool EntityBlocksEntity(Entity* e1, Entity* e2);
|
bool EntityBlocksEntity(Entity* e1, Entity* e2);
|
||||||
void EntityVsEntity(Entity* e1, Entity* e2);
|
void EntityVsEntity(Entity* e1, Entity* e2);
|
||||||
void entityTileInteract(Entity* e, int tile,int x, int y);
|
bool ItemVsEntity(PlayerData *pd, Item *item, Entity *e, int dir);
|
||||||
|
void entityTileInteract(Entity* e, int tile, s8 level, int x, int y);
|
||||||
|
|
||||||
void initPlayer();
|
void openCraftingMenu(PlayerData *pd, RecipeManager *rm, char *title);
|
||||||
void tickPlayer();
|
bool useEntity(PlayerData *pd, Entity* e);
|
||||||
void playerAttack();
|
|
||||||
bool isSwimming();
|
|
||||||
bool playerUseEnergy(int amount);
|
|
||||||
void playerHurtTile(int tile, int xt, int yt, int damage, int dir);
|
|
||||||
bool playerIntersectsEntity(Entity* e);
|
|
||||||
void playerEntityInteract(Entity* e);
|
|
||||||
void playerSetActiveItem(Item * item);
|
|
||||||
|
|
||||||
void enterDungeon();
|
bool isWater(s8 level, int xt, int yt);
|
||||||
void leaveDungeon();
|
|
||||||
|
|
||||||
void setMinimapVisible(int level, int x, int y, bool visible);
|
void playerHurtTile(PlayerData *pd, int tile, s8 level, int xt, int yt, int damage, int dir);
|
||||||
bool getMinimapVisible(int level, int x, int y);
|
void playerEntityInteract(PlayerData *pd, Entity* e);
|
||||||
u32 getMinimapColor(int level, int x, int y);
|
|
||||||
void initMinimapLevel(int level, bool loadUpWorld);
|
bool dungeonActive();
|
||||||
|
void enterDungeon(PlayerData *pd);
|
||||||
|
void leaveDungeon(PlayerData *pd);
|
||||||
|
|
||||||
|
void setMinimapVisible(PlayerData *pd, int level, int x, int y, bool visible);
|
||||||
|
bool getMinimapVisible(PlayerData *pd, int level, int x, int y);
|
||||||
|
u32 getMinimapColor(PlayerData *pd, int level, int x, int y);
|
||||||
|
void initMinimapLevel(PlayerData *pd, int level);
|
||||||
void updateLevel1Map();
|
void updateLevel1Map();
|
||||||
|
|
||||||
void reloadColors();
|
void reloadColors();
|
376
source/Ingame.c
Normal file
376
source/Ingame.c
Normal file
|
@ -0,0 +1,376 @@
|
||||||
|
#include "Ingame.h"
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "Player.h"
|
||||||
|
#include "Entity.h"
|
||||||
|
#include "IngameMenu.h"
|
||||||
|
#include "Render.h"
|
||||||
|
#include "MapGen.h"
|
||||||
|
#include "Synchronizer.h"
|
||||||
|
#include "SaveLoad.h"
|
||||||
|
#include "Network.h"
|
||||||
|
|
||||||
|
#define STALL_TIME 120
|
||||||
|
|
||||||
|
int stallCounter;
|
||||||
|
bool stallAreYouSure;
|
||||||
|
|
||||||
|
//generates stairs up and creates compass data
|
||||||
|
void generatePass2() {
|
||||||
|
int level, x, y;
|
||||||
|
|
||||||
|
for (level = 0; level < 5; ++level) {
|
||||||
|
for (x = 0; x < 128; ++x) {
|
||||||
|
for (y = 0; y < 128; ++y) {
|
||||||
|
|
||||||
|
//generate stairs up matching stairs down
|
||||||
|
switch (worldData.map[level][x + y * 128]) {
|
||||||
|
case TILE_STAIRS_DOWN:
|
||||||
|
if(level < 4) {
|
||||||
|
worldData.map[level + 1][x + y * 128] = TILE_STAIRS_UP;
|
||||||
|
if (level == 0) {
|
||||||
|
worldData.map[level + 1][(x + 1) + y * 128] = TILE_HARDROCK;
|
||||||
|
worldData.map[level + 1][x + (y + 1) * 128] = TILE_HARDROCK;
|
||||||
|
worldData.map[level + 1][(x - 1) + y * 128] = TILE_HARDROCK;
|
||||||
|
worldData.map[level + 1][x + (y - 1) * 128] = TILE_HARDROCK;
|
||||||
|
worldData.map[level + 1][(x + 1) + (y + 1) * 128] = TILE_HARDROCK;
|
||||||
|
worldData.map[level + 1][(x - 1) + (y - 1) * 128] = TILE_HARDROCK;
|
||||||
|
worldData.map[level + 1][(x - 1) + (y + 1) * 128] = TILE_HARDROCK;
|
||||||
|
worldData.map[level + 1][(x + 1) + (y - 1) * 128] = TILE_HARDROCK;
|
||||||
|
} else {
|
||||||
|
worldData.map[level + 1][(x + 1) + y * 128] = TILE_DIRT;
|
||||||
|
worldData.map[level + 1][x + (y + 1) * 128] = TILE_DIRT;
|
||||||
|
worldData.map[level + 1][(x - 1) + y * 128] = TILE_DIRT;
|
||||||
|
worldData.map[level + 1][x + (y - 1) * 128] = TILE_DIRT;
|
||||||
|
worldData.map[level + 1][(x + 1) + (y + 1) * 128] = TILE_DIRT;
|
||||||
|
worldData.map[level + 1][(x - 1) + (y - 1) * 128] = TILE_DIRT;
|
||||||
|
worldData.map[level + 1][(x - 1) + (y + 1) * 128] = TILE_DIRT;
|
||||||
|
worldData.map[level + 1][(x + 1) + (y - 1) * 128] = TILE_DIRT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//calculate compass data
|
||||||
|
//choose one stair down and store for magic compass
|
||||||
|
switch (worldData.map[level][x + y * 128]) {
|
||||||
|
case TILE_STAIRS_DOWN:
|
||||||
|
case TILE_DUNGEON_ENTRANCE:
|
||||||
|
worldData.compassData[level][2] = worldData.compassData[level][2] + 1;
|
||||||
|
if((worldData.compassData[level][2]==1) || (rand()%(worldData.compassData[level][2])==0)) {
|
||||||
|
worldData.compassData[level][0] = x;
|
||||||
|
worldData.compassData[level][1] = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void initNewMap() {
|
||||||
|
createAndValidateSkyMap(128, 128, 0, worldData.map[0], worldData.data[0]);
|
||||||
|
createAndValidateTopMap(128, 128, 1, worldData.map[1], worldData.data[1]);
|
||||||
|
createAndValidateUndergroundMap(128, 128, 1, 2, worldData.map[2], worldData.data[2]);
|
||||||
|
createAndValidateUndergroundMap(128, 128, 2, 3, worldData.map[3], worldData.data[3]);
|
||||||
|
createAndValidateUndergroundMap(128, 128, 3, 4, worldData.map[4], worldData.data[4]);
|
||||||
|
generatePass2();
|
||||||
|
}
|
||||||
|
|
||||||
|
void initMiniMap(PlayerData *pd) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 5; ++i) {
|
||||||
|
initMinimapLevel(pd, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void startGame(bool load, char *filename) {
|
||||||
|
// Reset entity manager.
|
||||||
|
memset(&eManager, 0, sizeof(eManager));
|
||||||
|
|
||||||
|
// Reset players
|
||||||
|
for(int i=0; i<playerCount; i++) {
|
||||||
|
initPlayer(players+i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!load) {
|
||||||
|
initNewMap();
|
||||||
|
airWizardHealthDisplay = 2000;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 5; ++i) {
|
||||||
|
trySpawn(500, i);
|
||||||
|
}
|
||||||
|
addEntityToList(newAirWizardEntity(630, 820, 0), &eManager);
|
||||||
|
worldData.daytime = 6000;
|
||||||
|
worldData.day = 0;
|
||||||
|
worldData.season = 0;
|
||||||
|
worldData.rain = false;
|
||||||
|
} else {
|
||||||
|
if(!loadWorld(filename, &eManager, &worldData, players, playerCount)) {
|
||||||
|
//TODO: What do?
|
||||||
|
networkDisconnect();
|
||||||
|
|
||||||
|
sf2d_set_clear_color(0xFF);
|
||||||
|
currentSelection = 0;
|
||||||
|
currentMenu = MENU_TITLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spawn players
|
||||||
|
for(int i=0; i<playerCount; i++) {
|
||||||
|
if(!players[i].isSpawned) {
|
||||||
|
playerSpawn(players+i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init player maps
|
||||||
|
for(int i=0; i<playerCount; i++) {
|
||||||
|
initMiniMap(players+i);
|
||||||
|
}
|
||||||
|
|
||||||
|
stallCounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void syncedTick() {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
setListenerPosition(getLocalPlayer()->entity.level, getLocalPlayer()->entity.x, getLocalPlayer()->entity.y);
|
||||||
|
|
||||||
|
//win/death menus
|
||||||
|
for(i=0; i<playerCount; i++) {
|
||||||
|
if (players[i].entity.p.isDead) {
|
||||||
|
if (players[i].entity.p.endTimer < 1) {
|
||||||
|
players[i].ingameMenu = MENU_LOSE;
|
||||||
|
}
|
||||||
|
--players[i].entity.p.endTimer;
|
||||||
|
} else if (players[i].entity.p.hasWon) {
|
||||||
|
if (players[i].entity.p.endTimer < 1) {
|
||||||
|
players[i].ingameMenu = MENU_WIN;
|
||||||
|
}
|
||||||
|
--players[i].entity.p.endTimer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//update worldData (daytime,season and weather)
|
||||||
|
++worldData.daytime;
|
||||||
|
if(worldData.daytime>=24000) {
|
||||||
|
worldData.daytime -= 24000;
|
||||||
|
++worldData.day;
|
||||||
|
//TODO: maybe make season length not as hardcoded + make the transition better (fade to black and back maybe?)
|
||||||
|
if(worldData.day%7==0) {
|
||||||
|
++worldData.season;
|
||||||
|
if(worldData.season==4) worldData.season = 0;
|
||||||
|
}
|
||||||
|
worldData.rain = false;
|
||||||
|
if(worldData.season!=3 && rand()%5==0) worldData.rain = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//update music
|
||||||
|
updateMusic(getLocalPlayer()->entity.level, worldData.daytime);
|
||||||
|
|
||||||
|
//for every active level
|
||||||
|
s8 level;
|
||||||
|
for(level = 0; level < 6; level++) {
|
||||||
|
bool hasPlayer = false;
|
||||||
|
for(i=0; i<playerCount; i++) {
|
||||||
|
if(players[i].entity.level==level) {
|
||||||
|
hasPlayer = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!hasPlayer) continue;
|
||||||
|
|
||||||
|
//tick tiles
|
||||||
|
for (i = 0; i < 324; ++i) {
|
||||||
|
int xx = rand() & 127;
|
||||||
|
int yy = rand() & 127;
|
||||||
|
tickTile(level, xx, yy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for(i=0; i<playerCount; i++) {
|
||||||
|
ingameMenuTickTouch(players+i);
|
||||||
|
|
||||||
|
bool inmenu = false;
|
||||||
|
if(players[i].ingameMenu != MENU_NONE) {
|
||||||
|
ingameMenuTick(players+i, players[i].ingameMenu);
|
||||||
|
inmenu = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
tickPlayer(players+i, inmenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//for every active level
|
||||||
|
for(level = 0; level < 6; level++) {
|
||||||
|
if(level==5 && !dungeonActive()) continue;
|
||||||
|
|
||||||
|
bool hasPlayer = false;
|
||||||
|
for(i=0; i<playerCount; i++) {
|
||||||
|
if(players[i].entity.level==level) {
|
||||||
|
hasPlayer = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!hasPlayer) continue;
|
||||||
|
|
||||||
|
//spawn entities
|
||||||
|
if(eManager.lastSlot[level]<80 && level != 5) {
|
||||||
|
trySpawn(1, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
//update entities
|
||||||
|
for (i = 0; i < eManager.lastSlot[level]; ++i) {
|
||||||
|
Entity * e = &eManager.entities[level][i];
|
||||||
|
PlayerData * p = getNearestPlayer(level, e->x, e->y);
|
||||||
|
|
||||||
|
//should never happen, but just for safety to prevent hard crashes
|
||||||
|
if(p==NULL) continue;
|
||||||
|
|
||||||
|
if ((e->type != ENTITY_ZOMBIE && e->type != ENTITY_SKELETON && e->type != ENTITY_KNIGHT && e->type != ENTITY_SLIME && e->type != ENTITY_PASSIVE && e->type != ENTITY_GLOWWORM)
|
||||||
|
|| (e->type == ENTITY_GLOWWORM && (worldData.daytime>6000 || worldData.daytime<18000))
|
||||||
|
|| (e->x > p->entity.x - 160 && e->y > p->entity.y - 125 && e->x < p->entity.x + 160 && e->y < p->entity.y + 125)) {
|
||||||
|
tickEntity(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stallCounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tickGame() {
|
||||||
|
synchronizerTick(&syncedTick);
|
||||||
|
|
||||||
|
|
||||||
|
if(synchronizerIsRunning()) {
|
||||||
|
stallCounter++;
|
||||||
|
//game stalled -> most likely a player disconnected -> present option to exit game
|
||||||
|
if(stallCounter>=STALL_TIME) {
|
||||||
|
if(stallCounter==STALL_TIME) stallAreYouSure = false;
|
||||||
|
|
||||||
|
//scan local inputs, because synchronizer only updates them when not stalled
|
||||||
|
hidScanInput();
|
||||||
|
tickKeys(&localInputs, hidKeysHeld(), hidKeysDown());
|
||||||
|
|
||||||
|
if (localInputs.k_accept.clicked) {
|
||||||
|
if(stallAreYouSure) {
|
||||||
|
//create backup save
|
||||||
|
if(playerLocalID==0) {
|
||||||
|
char backupSaveFileName[256+32];
|
||||||
|
backupSaveFileName[0] = '\0';
|
||||||
|
|
||||||
|
strncat(backupSaveFileName, currentFileName, strlen(currentFileName)-4);
|
||||||
|
strcat(backupSaveFileName, ".exit.msv");
|
||||||
|
|
||||||
|
saveWorld(backupSaveFileName, &eManager, &worldData, players, playerCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
exitGame();
|
||||||
|
} else {
|
||||||
|
stallAreYouSure = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (localInputs.k_decline.clicked) {
|
||||||
|
stallAreYouSure = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//for rendering -> move to a better place
|
||||||
|
int xscr = 0, yscr = 0;
|
||||||
|
|
||||||
|
void renderGame() {
|
||||||
|
//Important: all code called from this function should never affect game state!
|
||||||
|
sf2d_start_frame(GFX_TOP, GFX_LEFT);
|
||||||
|
|
||||||
|
int xscr = getLocalPlayer()->entity.x - 100;
|
||||||
|
int yscr = getLocalPlayer()->entity.y - 56;
|
||||||
|
if (xscr < 16)
|
||||||
|
xscr = 16;
|
||||||
|
else if (xscr > 1832)
|
||||||
|
xscr = 1832;
|
||||||
|
if (yscr < 16)
|
||||||
|
yscr = 16;
|
||||||
|
else if (yscr > 1912)
|
||||||
|
yscr = 1912;
|
||||||
|
|
||||||
|
|
||||||
|
offsetX = xscr;
|
||||||
|
offsetY = yscr;
|
||||||
|
sf2d_draw_rectangle(0, 0, 400, 240, 0xFF0C0C0C); //RGBA8(12, 12, 12, 255)); //You might think "real" black would be better, but it actually looks better that way
|
||||||
|
|
||||||
|
renderLightsToStencil(getLocalPlayer(), false, false, true);
|
||||||
|
|
||||||
|
renderBackground(getLocalPlayer()->entity.level, xscr, yscr);
|
||||||
|
renderEntities(getLocalPlayer()->entity.level, getLocalPlayer()->entity.x, getLocalPlayer()->entity.y, &eManager);
|
||||||
|
for(int i=0; i<playerCount; i++) {
|
||||||
|
renderPlayer(players+i);
|
||||||
|
}
|
||||||
|
renderWeather(getLocalPlayer()->entity.level, xscr, yscr);
|
||||||
|
|
||||||
|
resetStencilStuff();
|
||||||
|
|
||||||
|
renderDayNight(getLocalPlayer());
|
||||||
|
|
||||||
|
offsetX = 0;
|
||||||
|
offsetY = 0;
|
||||||
|
|
||||||
|
if(shouldRenderDebug){
|
||||||
|
sprintf(fpsstr, " FPS: %.0f, X:%d, Y:%d, E:%d", sf2d_get_fps(), getLocalPlayer()->entity.x, getLocalPlayer()->entity.y, eManager.lastSlot[getLocalPlayer()->entity.level]);
|
||||||
|
drawText(fpsstr, 2, 225);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(getLocalPlayer()->ingameMenu != MENU_NONE) {
|
||||||
|
ingameMenuRender(getLocalPlayer(), getLocalPlayer()->ingameMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
//game stalled -> most likely a player disconnected -> present option to exit game
|
||||||
|
if(stallCounter>STALL_TIME) {
|
||||||
|
renderFrame(1,1,24,14,0xFF1010AF);
|
||||||
|
drawText("Waiting for a long time", (400 - (23 * 12))/2, 32);
|
||||||
|
|
||||||
|
char text[50];
|
||||||
|
sprintf(text, "Last response %is ago", stallCounter/60);
|
||||||
|
drawText(text, (400 - (strlen(text) * 12))/2, 64);
|
||||||
|
|
||||||
|
if(playerLocalID==0) {
|
||||||
|
drawText("Press to leave the game", (400 - (25 * 12))/2, 160);
|
||||||
|
renderButtonIcon(localInputs.k_accept.input & -localInputs.k_accept.input, 120, 157, 1);
|
||||||
|
|
||||||
|
drawText("A backup save will be created", (400 - (29 * 12))/2, 192);
|
||||||
|
} else {
|
||||||
|
drawText("Press to leave the game", (400 - (25 * 12))/2, 192);
|
||||||
|
renderButtonIcon(localInputs.k_accept.input & -localInputs.k_accept.input, 120, 189, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(stallAreYouSure){
|
||||||
|
renderFrame(6,5,19,10,0xFF10108F);
|
||||||
|
|
||||||
|
drawText("Are you sure?",122,96);
|
||||||
|
drawText(" Yes", 164, 117);
|
||||||
|
renderButtonIcon(localInputs.k_accept.input & -localInputs.k_accept.input, 166, 114, 1);
|
||||||
|
drawText(" No", 170, 133);
|
||||||
|
renderButtonIcon(localInputs.k_decline.input & -localInputs.k_decline.input, 166, 130, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sf2d_end_frame();
|
||||||
|
|
||||||
|
sf2d_start_frame(GFX_BOTTOM, GFX_LEFT);
|
||||||
|
if(!players[playerLocalID].mapShouldRender){
|
||||||
|
sf2d_draw_texture(bottombg, 0, 0);
|
||||||
|
renderGui(getLocalPlayer());
|
||||||
|
} else {
|
||||||
|
renderZoomedMap(getLocalPlayer());
|
||||||
|
}
|
||||||
|
sf2d_end_frame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void exitGame() {
|
||||||
|
networkDisconnect();
|
||||||
|
synchronizerReset();
|
||||||
|
|
||||||
|
sf2d_set_clear_color(0xFF);
|
||||||
|
currentSelection = 0;
|
||||||
|
currentMenu = MENU_TITLE;
|
||||||
|
|
||||||
|
playMusic(&music_menu);
|
||||||
|
}
|
9
source/Ingame.h
Normal file
9
source/Ingame.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <3ds.h>
|
||||||
|
|
||||||
|
void startGame(bool load, char *filename);
|
||||||
|
void tickGame();
|
||||||
|
void renderGame();
|
||||||
|
|
||||||
|
void exitGame();
|
528
source/IngameMenu.c
Normal file
528
source/IngameMenu.c
Normal file
|
@ -0,0 +1,528 @@
|
||||||
|
#include "IngameMenu.h"
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "Menu.h"
|
||||||
|
#include "Ingame.h"
|
||||||
|
#include "Player.h"
|
||||||
|
#include "SaveLoad.h"
|
||||||
|
#include "Synchronizer.h"
|
||||||
|
|
||||||
|
char pOptions[][24] = {"Return to game", "Save Progress", "Exit to title"};
|
||||||
|
|
||||||
|
void ingameMenuTick(PlayerData *pd, int menu) {
|
||||||
|
switch(menu) {
|
||||||
|
case MENU_PAUSED:
|
||||||
|
if(!pd->ingameMenuAreYouSure && !pd->ingameMenuAreYouSureSave){
|
||||||
|
if (pd->ingameMenuTimer > 0) --pd->ingameMenuTimer;
|
||||||
|
if (pd->inputs.k_pause.clicked || pd->inputs.k_decline.clicked) pd->ingameMenu = MENU_NONE;
|
||||||
|
if (pd->inputs.k_up.clicked) { --pd->ingameMenuSelection; if(pd->ingameMenuSelection < 0) pd->ingameMenuSelection=2; }
|
||||||
|
if (pd->inputs.k_down.clicked) { ++pd->ingameMenuSelection; if(pd->ingameMenuSelection > 2) pd->ingameMenuSelection=0; }
|
||||||
|
if (pd->inputs.k_accept.clicked){
|
||||||
|
switch(pd->ingameMenuSelection){
|
||||||
|
case 0:
|
||||||
|
pd->ingameMenu = MENU_NONE;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if(!dungeonActive()) pd->ingameMenuAreYouSureSave = true;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
pd->ingameMenuAreYouSure = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(pd->ingameMenuAreYouSureSave) {
|
||||||
|
if (pd->inputs.k_accept.clicked){
|
||||||
|
pd->ingameMenuTimer = 60;
|
||||||
|
|
||||||
|
if(playerLocalID==0) {
|
||||||
|
saveWorld(currentFileName, &eManager, &worldData, players, playerCount);
|
||||||
|
}
|
||||||
|
pd->ingameMenuAreYouSureSave = false;
|
||||||
|
pd->ingameMenuAreYouSure = false;
|
||||||
|
} else if (pd->inputs.k_decline.clicked){
|
||||||
|
pd->ingameMenuAreYouSureSave = false;
|
||||||
|
pd->ingameMenuAreYouSure = false;
|
||||||
|
}
|
||||||
|
} else if(pd->ingameMenuAreYouSure) {
|
||||||
|
if (pd->inputs.k_accept.clicked){
|
||||||
|
pd->ingameMenuAreYouSure = false;
|
||||||
|
pd->ingameMenuAreYouSureSave = false;
|
||||||
|
|
||||||
|
exitGame();
|
||||||
|
} else if (pd->inputs.k_decline.clicked){
|
||||||
|
pd->ingameMenuAreYouSure = false;
|
||||||
|
pd->ingameMenuAreYouSureSave = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MENU_INVENTORY:
|
||||||
|
if (pd->inputs.k_menu.clicked || pd->inputs.k_decline.clicked){
|
||||||
|
pd->ingameMenu = MENU_NONE;
|
||||||
|
pd->activeItem = &noItem;
|
||||||
|
pd->entity.p.isCarrying = false;
|
||||||
|
}
|
||||||
|
if (pd->inputs.k_accept.clicked){ // Select item from inventory
|
||||||
|
if(pd->inventory.lastSlot!=0){
|
||||||
|
Item median = pd->inventory.items[pd->ingameMenuInvSel]; // create copy of item.
|
||||||
|
removeItemFromInventory(pd->ingameMenuInvSel, &(pd->inventory)); // remove original
|
||||||
|
pushItemToInventoryFront(median, &(pd->inventory)); // add copy to front
|
||||||
|
playerSetActiveItem(pd, &(pd->inventory.items[0])); // active item = copy.
|
||||||
|
}
|
||||||
|
pd->ingameMenu = MENU_NONE;
|
||||||
|
}
|
||||||
|
if (pd->inputs.k_up.clicked) { --pd->ingameMenuInvSel; if(pd->ingameMenuInvSel < 0)pd->ingameMenuInvSel=pd->inventory.lastSlot-1; }
|
||||||
|
if (pd->inputs.k_down.clicked) { ++pd->ingameMenuInvSel; if(pd->ingameMenuInvSel > pd->inventory.lastSlot-1)pd->ingameMenuInvSel=0; }
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENU_CRAFTING:
|
||||||
|
if (pd->inputs.k_menu.clicked || pd->inputs.k_decline.clicked) pd->ingameMenu = MENU_NONE;
|
||||||
|
if (pd->inputs.k_accept.clicked){
|
||||||
|
if(craftItem(&(pd->currentRecipes), &(pd->currentRecipes.recipes[pd->ingameMenuInvSel]), &(pd->inventory))){
|
||||||
|
playSoundPositioned(snd_craft, pd->entity.level, pd->entity.x, pd->entity.y);
|
||||||
|
//reset active item pointer, because it could posibly point to garbage now
|
||||||
|
pd->activeItem = &noItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pd->inputs.k_up.clicked) { --pd->ingameMenuInvSel; if(pd->ingameMenuInvSel < 0)pd->ingameMenuInvSel=pd->currentRecipes.size-1; }
|
||||||
|
if (pd->inputs.k_down.clicked) { ++pd->ingameMenuInvSel; if(pd->ingameMenuInvSel > pd->currentRecipes.size-1)pd->ingameMenuInvSel=0; }
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENU_WIN:
|
||||||
|
if (pd->inputs.k_accept.clicked){
|
||||||
|
pd->ingameMenu = MENU_NONE;
|
||||||
|
pd->entity.p.hasWon = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MENU_LOSE:
|
||||||
|
if (pd->inputs.k_accept.clicked){
|
||||||
|
pd->ingameMenu = MENU_NONE;
|
||||||
|
pd->entity.p.isDead = false;
|
||||||
|
pd->entity.p.health = 10;
|
||||||
|
pd->entity.level = 1;
|
||||||
|
playerSpawn(pd);
|
||||||
|
//TODO: This canceled to main menu, but what should I do in multiplayer?
|
||||||
|
}
|
||||||
|
pd->entity.hurtTime = 10;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENU_CONTAINER:
|
||||||
|
if (pd->inputs.k_menu.clicked || pd->inputs.k_decline.clicked) pd->ingameMenu = MENU_NONE;
|
||||||
|
|
||||||
|
if (pd->inputs.k_left.clicked) {
|
||||||
|
pd->curChestEntityR = 0;
|
||||||
|
int tmp = pd->ingameMenuInvSel;
|
||||||
|
pd->ingameMenuInvSel = pd->ingameMenuInvSelOther;
|
||||||
|
pd->ingameMenuInvSelOther = tmp;
|
||||||
|
}
|
||||||
|
if (pd->inputs.k_right.clicked) {
|
||||||
|
pd->curChestEntityR = 1;
|
||||||
|
int tmp = pd->ingameMenuInvSel;
|
||||||
|
pd->ingameMenuInvSel = pd->ingameMenuInvSelOther;
|
||||||
|
pd->ingameMenuInvSelOther = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
Inventory* i1 = pd->curChestEntityR == 1 ? &(pd->inventory) : pd->curChestEntity->entityFurniture.inv;
|
||||||
|
Inventory* i2 = pd->curChestEntityR == 0 ? &(pd->inventory) : pd->curChestEntity->entityFurniture.inv;
|
||||||
|
int len = i1->lastSlot;
|
||||||
|
if (pd->ingameMenuInvSel < 0) pd->ingameMenuInvSel = 0;
|
||||||
|
if (pd->ingameMenuInvSel >= len) pd->ingameMenuInvSel = len - 1;
|
||||||
|
if (pd->inputs.k_up.clicked) --pd->ingameMenuInvSel;
|
||||||
|
if (pd->inputs.k_down.clicked) ++pd->ingameMenuInvSel;
|
||||||
|
if (len == 0) pd->ingameMenuInvSel = 0;
|
||||||
|
if (pd->ingameMenuInvSel < 0) pd->ingameMenuInvSel += len;
|
||||||
|
if (pd->ingameMenuInvSel >= len) pd->ingameMenuInvSel -= len;
|
||||||
|
|
||||||
|
if(pd->inputs.k_accept.clicked && len > 0){
|
||||||
|
Item* pullItem = &i1->items[pd->ingameMenuInvSel];
|
||||||
|
Item pushItem = newItem(pullItem->id, pullItem->countLevel);
|
||||||
|
pushItem.chestPtr = pullItem->chestPtr;
|
||||||
|
pushItemToInventoryFront(pushItem, i2);
|
||||||
|
if(i2 == &(pd->inventory)){
|
||||||
|
int newslot = pd->activeItem->slotNum + 1;
|
||||||
|
pd->activeItem = &(pd->inventory.items[newslot]);
|
||||||
|
} else if(pullItem == pd->activeItem){
|
||||||
|
pd->activeItem = &noItem;
|
||||||
|
}
|
||||||
|
removeItemFromCurrentInv(pullItem);
|
||||||
|
if (pd->ingameMenuInvSel >= i1->lastSlot) pd->ingameMenuInvSel = i1->lastSlot - 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENU_DUNGEON:
|
||||||
|
if (pd->inputs.k_menu.clicked || pd->inputs.k_decline.clicked) pd->ingameMenu = MENU_NONE;
|
||||||
|
|
||||||
|
if(pd->inputs.k_accept.clicked) {
|
||||||
|
if(pd->entity.level!=5) {
|
||||||
|
Item * item = getItemFromInventory(ITEM_DUNGEON_KEY, &(pd->inventory));
|
||||||
|
if(item!=NULL) {
|
||||||
|
--item->countLevel;
|
||||||
|
if(item->countLevel==0) {
|
||||||
|
removeItemFromCurrentInv(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
enterDungeon(pd);
|
||||||
|
} else if(TESTGODMODE) {
|
||||||
|
enterDungeon(pd);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
leaveDungeon(pd);
|
||||||
|
}
|
||||||
|
|
||||||
|
pd->ingameMenu = MENU_NONE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENU_NPC:
|
||||||
|
tickNPCMenu(pd);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENU_CHARACTER_CUSTOMIZE:
|
||||||
|
if (pd->inputs.k_up.clicked) { --pd->ingameMenuSelection; if(pd->ingameMenuSelection < 0) pd->ingameMenuSelection=6; }
|
||||||
|
if (pd->inputs.k_down.clicked) { ++pd->ingameMenuSelection; if(pd->ingameMenuSelection > 6) pd->ingameMenuSelection=0; }
|
||||||
|
|
||||||
|
u8 wrap = 0;
|
||||||
|
wrap = wrap - 1;
|
||||||
|
|
||||||
|
pd->entity.p.health = 10;
|
||||||
|
pd->entity.hurtTime = 10;
|
||||||
|
|
||||||
|
//head
|
||||||
|
if(pd->ingameMenuSelection==0) {
|
||||||
|
if (pd->inputs.k_left.clicked) { --pd->sprite.head; if(pd->sprite.head == wrap) pd->sprite.head=PLAYER_SPRITE_HEAD_COUNT-1; }
|
||||||
|
if (pd->inputs.k_right.clicked) { ++pd->sprite.head; if(pd->sprite.head > PLAYER_SPRITE_HEAD_COUNT-1) pd->sprite.head=0; }
|
||||||
|
//eyes
|
||||||
|
} else if(pd->ingameMenuSelection==1) {
|
||||||
|
if (pd->inputs.k_left.clicked) { --pd->sprite.eyes; if(pd->sprite.eyes == wrap) pd->sprite.eyes=PLAYER_SPRITE_EYES_COUNT-1; }
|
||||||
|
if (pd->inputs.k_right.clicked) { ++pd->sprite.eyes; if(pd->sprite.eyes > PLAYER_SPRITE_EYES_COUNT-1) pd->sprite.eyes=0; }
|
||||||
|
//body
|
||||||
|
} else if(pd->ingameMenuSelection==2) {
|
||||||
|
if (pd->inputs.k_left.clicked) { --pd->sprite.body; if(pd->sprite.body == wrap) pd->sprite.body=PLAYER_SPRITE_BODY_COUNT-1; }
|
||||||
|
if (pd->inputs.k_right.clicked) { ++pd->sprite.body; if(pd->sprite.body > PLAYER_SPRITE_BODY_COUNT-1) pd->sprite.body=0; }
|
||||||
|
//arms
|
||||||
|
} else if(pd->ingameMenuSelection==3) {
|
||||||
|
if (pd->inputs.k_left.clicked) { --pd->sprite.arms; if(pd->sprite.arms == wrap) pd->sprite.arms=PLAYER_SPRITE_ARMS_COUNT-1; }
|
||||||
|
if (pd->inputs.k_right.clicked) { ++pd->sprite.arms; if(pd->sprite.arms > PLAYER_SPRITE_ARMS_COUNT-1) pd->sprite.arms=0; }
|
||||||
|
//legs
|
||||||
|
} else if(pd->ingameMenuSelection==4) {
|
||||||
|
if (pd->inputs.k_left.clicked) { --pd->sprite.legs; if(pd->sprite.legs == wrap) pd->sprite.legs=PLAYER_SPRITE_LEGS_COUNT-1; }
|
||||||
|
if (pd->inputs.k_right.clicked) { ++pd->sprite.legs; if(pd->sprite.legs > PLAYER_SPRITE_LEGS_COUNT-1) pd->sprite.legs=0; }
|
||||||
|
//rotation
|
||||||
|
} else if(pd->ingameMenuSelection==5) {
|
||||||
|
if (pd->inputs.k_left.clicked) { --pd->entity.p.dir; if(pd->entity.p.dir == wrap) pd->entity.p.dir=3; }
|
||||||
|
if (pd->inputs.k_right.clicked) { ++pd->entity.p.dir; if(pd->entity.p.dir > 3) pd->entity.p.dir=0; }
|
||||||
|
//done
|
||||||
|
} else if(pd->ingameMenuSelection==6) {
|
||||||
|
if(pd->inputs.k_accept.clicked) {
|
||||||
|
//TODO: are you sure dialog?
|
||||||
|
pd->ingameMenu = 0;
|
||||||
|
pd->ingameMenuSelection = 0;
|
||||||
|
pd->sprite.choosen = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
u8 opacity = 255;
|
||||||
|
bool rev = true;
|
||||||
|
char scoreText[15];
|
||||||
|
|
||||||
|
void ingameMenuRender(PlayerData *pd, int menu) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
switch(menu) {
|
||||||
|
case MENU_PAUSED:
|
||||||
|
renderFrame(1,1,24,14,0xFF1010AF);
|
||||||
|
drawText("Paused",164,32);
|
||||||
|
for(i = 3; i >= 0; --i){
|
||||||
|
char* msg = pOptions[i];
|
||||||
|
u32 color = 0xFF7F7F7F;
|
||||||
|
if(i == pd->ingameMenuSelection) color = 0xFFFFFFFF;
|
||||||
|
if((i == 1 && dungeonActive())) {
|
||||||
|
color = 0xFF7F7FFF;
|
||||||
|
if(i == pd->ingameMenuSelection) color = 0xFFAFAFFF;
|
||||||
|
}
|
||||||
|
drawTextColor(msg,(400 - (strlen(msg) * 12))/2, (i * 24) + 88, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pd->ingameMenuTimer > 0) drawTextColor("Game Saved!", (400-(11*12))/2, 64,0xFF20FF20);
|
||||||
|
|
||||||
|
if(pd->ingameMenuAreYouSure || pd->ingameMenuAreYouSureSave){
|
||||||
|
if(pd->ingameMenuAreYouSure)renderFrame(6,5,19,10,0xFF10108F);
|
||||||
|
else renderFrame(6,5,19,10,0xFF108F10);
|
||||||
|
|
||||||
|
drawText("Are you sure?",122,96);
|
||||||
|
drawText(" Yes", 164, 117);
|
||||||
|
renderButtonIcon(localInputs.k_accept.input & -localInputs.k_accept.input, 166, 114, 1);
|
||||||
|
drawText(" No", 170, 133);
|
||||||
|
renderButtonIcon(localInputs.k_decline.input & -localInputs.k_decline.input, 166, 130, 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MENU_WIN:
|
||||||
|
renderFrame(5,3,21,12,0xFFFF1010);
|
||||||
|
if(!rev){ opacity+=5; if(opacity == 255) rev = true; }
|
||||||
|
else { opacity-=5; if(opacity == 100) rev = false; }
|
||||||
|
sprintf(scoreText,"Score: %d", pd->score);
|
||||||
|
drawTextColor("You Win!",158,76,0x0000AFAF + (opacity << 24));
|
||||||
|
drawText(scoreText, 200-((strlen(scoreText)-1)*6), 100);
|
||||||
|
drawText("Press to continue", 96, 150);
|
||||||
|
renderButtonIcon(localInputs.k_attack.input & -localInputs.k_attack.input, 166, 148, 1);
|
||||||
|
|
||||||
|
//printf("0x%08X",localInputs.k_attack.input & -localInputs.k_attack.input);
|
||||||
|
break;
|
||||||
|
case MENU_LOSE:
|
||||||
|
renderFrame(5,3,21,12,0xFFFF1010);
|
||||||
|
if(!rev){ opacity+=5; if(opacity == 255) rev = true; }
|
||||||
|
else { opacity-=5; if(opacity == 100) rev = false; }
|
||||||
|
sprintf(scoreText,"Score: %d", pd->score);
|
||||||
|
drawTextColor("You DIED!",158,76,0x000000AF + (opacity << 24));
|
||||||
|
drawText(scoreText, 200-((strlen(scoreText)-1)*6), 100);
|
||||||
|
drawText("Press to continue", 96, 150);
|
||||||
|
renderButtonIcon(localInputs.k_attack.input & -localInputs.k_attack.input, 166, 148, 1);
|
||||||
|
//printf("0x%08X",localInputs.k_attack.input & -localInputs.k_attack.input);
|
||||||
|
break;
|
||||||
|
case MENU_INVENTORY:
|
||||||
|
renderFrame(1,1,24,14,0xFFFF1010);
|
||||||
|
drawTextColor("Inventory",24+1,14+1,0xFF000000);
|
||||||
|
drawTextColor("Inventory",24,14,0xFF6FE2E2);
|
||||||
|
renderItemList(&(pd->inventory), 1,1,24,14, pd->ingameMenuInvSel);
|
||||||
|
break;
|
||||||
|
case MENU_CRAFTING:
|
||||||
|
renderFrame(15,1,24,4,0xFFFF1010);
|
||||||
|
drawTextColor("Have",248+1,14+1,0xFF000000);
|
||||||
|
drawTextColor("Have",248,14,0xFF6FE2E2);
|
||||||
|
renderFrame(15,5,24,14,0xFFFF1010);
|
||||||
|
drawTextColor("Cost",248+1,78+1,0xFF000000);
|
||||||
|
drawTextColor("Cost",248,78,0xFF6FE2E2);
|
||||||
|
renderFrame(1,1,14,14,0xFFFF1010);
|
||||||
|
drawTextColor(pd->currentCraftTitle,24+1,14+1,0xFF000000);
|
||||||
|
drawTextColor(pd->currentCraftTitle,24,14,0xFF6FE2E2);
|
||||||
|
renderRecipes(&(pd->currentRecipes), 1, 1, 14, 14, pd->ingameMenuInvSel);
|
||||||
|
|
||||||
|
Recipe* rec = &(pd->currentRecipes.recipes[pd->ingameMenuInvSel]);
|
||||||
|
renderItemIcon(rec->itemResult,rec->itemAmountLevel,128,16);
|
||||||
|
char craftText[12];
|
||||||
|
sprintf(craftText, "%d", countItemInv(rec->itemResult, rec->itemAmountLevel, &(pd->inventory)));
|
||||||
|
drawText(craftText,274,34);
|
||||||
|
|
||||||
|
if(rec->numOfCosts > 0){
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < rec->numOfCosts; i++){
|
||||||
|
int amnt = countItemInv(rec->costs[i].costItem,0, &(pd->inventory));
|
||||||
|
int ttlCst = rec->costs[i].costAmount;
|
||||||
|
int col = 0xFFFFFFFF; if(amnt<ttlCst) col = 0xFF7F7F7F;
|
||||||
|
renderItemIcon(rec->costs[i].costItem,1,128,48+(i*8));
|
||||||
|
sprintf(craftText,"%d/%d",amnt,ttlCst);
|
||||||
|
drawTextColor(craftText,274,96+(i*18),col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENU_CONTAINER:
|
||||||
|
if (pd->curChestEntityR == 1){ offsetX = 48; offsetY = 0;}
|
||||||
|
else {offsetX = 0; offsetY = 0;}
|
||||||
|
|
||||||
|
renderFrame(1,1,15,14,0xFFFF1010);
|
||||||
|
drawTextColor("Chest",24+1,14+1,0xFF000000);
|
||||||
|
drawTextColor("Chest",24,14,0xFF6FE2E2);
|
||||||
|
renderItemList(pd->curChestEntity->entityFurniture.inv,1,1,15,14,
|
||||||
|
pd->curChestEntityR == 0 ? pd->ingameMenuInvSel : -pd->ingameMenuInvSelOther - 1);
|
||||||
|
renderFrame(16,1,30,14,0xFFFF1010);
|
||||||
|
drawTextColor("Inventory",264+1,14+1,0xFF000000);
|
||||||
|
drawTextColor("Inventory",264,14,0xFF6FE2E2);
|
||||||
|
renderItemList(&(pd->inventory),16,1,30,14,
|
||||||
|
pd->curChestEntityR == 1 ? pd->ingameMenuInvSel : -pd->ingameMenuInvSelOther - 1);
|
||||||
|
offsetX = 0;offsetY = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENU_DUNGEON:
|
||||||
|
renderFrame(1,1,24,14,0xFFFF1010);
|
||||||
|
if(pd->entity.level!=5) {
|
||||||
|
drawTextColor("Dungeon Entrance",24+1,14+1,0xFF000000);
|
||||||
|
drawTextColor("Dungeon Entrance",24,14,0xFF6FE2E2);
|
||||||
|
|
||||||
|
drawText("Warning: ", 32, 32);
|
||||||
|
drawText("You need a Dungeon Key to ", 32, 56);
|
||||||
|
drawText("enter and cannot save while ", 32, 72);
|
||||||
|
drawText("being in the Dungeon! ", 32, 88);
|
||||||
|
drawText("After leaving you will need ", 32, 112);
|
||||||
|
drawText("a new Dungeon Key for ", 32, 128);
|
||||||
|
drawText("entering another Dungeon! ", 32, 144);
|
||||||
|
|
||||||
|
drawText(" Enter", 148, 171);
|
||||||
|
} else {
|
||||||
|
drawTextColor("Dungeon Exit",24+1,14+1,0xFF000000);
|
||||||
|
drawTextColor("Dungeon Exit",24,14,0xFF6FE2E2);
|
||||||
|
|
||||||
|
drawText("Warning: ", 32, 32);
|
||||||
|
drawText("The Dungeon and everything ", 32, 56);
|
||||||
|
drawText("in it will disappear when ", 32, 72);
|
||||||
|
drawText("you leave it! ", 32, 88);
|
||||||
|
drawText("You will need a new Dungeon ", 32, 112);
|
||||||
|
drawText("Key for entering another ", 32, 128);
|
||||||
|
drawText("Dungeon again! ", 32, 144);
|
||||||
|
|
||||||
|
drawText(" Leave", 148, 171);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderButtonIcon(localInputs.k_accept.input & -localInputs.k_accept.input, 150, 168, 1);
|
||||||
|
drawText(" Stay", 148, 195);
|
||||||
|
renderButtonIcon(localInputs.k_decline.input & -localInputs.k_decline.input, 150, 192, 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENU_NPC:
|
||||||
|
renderNPCMenu(&(pd->npcMenuData));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENU_CHARACTER_CUSTOMIZE:
|
||||||
|
renderFrame(1,1,24,14,0xFFFF1010);
|
||||||
|
drawTextColor("Character",24+1,14+1,0xFF000000);
|
||||||
|
drawTextColor("Character",24,14,0xFF6FE2E2);
|
||||||
|
|
||||||
|
drawText("Head: ", 32, 56);
|
||||||
|
drawText("Eyes: ", 32, 72);
|
||||||
|
drawText("Body: ", 32, 88);
|
||||||
|
drawText("Arms: ", 32, 104);
|
||||||
|
drawText("Legs: ", 32, 120);
|
||||||
|
drawText("Rot.: ", 32, 144);
|
||||||
|
|
||||||
|
//for the dynamic part
|
||||||
|
char display[30];
|
||||||
|
|
||||||
|
sprintf(display, pd->ingameMenuSelection==0 ? "< %02i/%02i >" : " %02i/%02i ", pd->sprite.head+1, PLAYER_SPRITE_HEAD_COUNT);
|
||||||
|
drawText(display, 96, 56);
|
||||||
|
sprintf(display, pd->ingameMenuSelection==1 ? "< %02i/%02i >" : " %02i/%02i ", pd->sprite.eyes+1, PLAYER_SPRITE_EYES_COUNT);
|
||||||
|
drawText(display, 96, 72);
|
||||||
|
sprintf(display, pd->ingameMenuSelection==2 ? "< %02i/%02i >" : " %02i/%02i ", pd->sprite.body+1, PLAYER_SPRITE_BODY_COUNT);
|
||||||
|
drawText(display, 96, 88);
|
||||||
|
sprintf(display, pd->ingameMenuSelection==3 ? "< %02i/%02i >" : " %02i/%02i ", pd->sprite.arms+1, PLAYER_SPRITE_ARMS_COUNT);
|
||||||
|
drawText(display, 96, 104);
|
||||||
|
sprintf(display, pd->ingameMenuSelection==4 ? "< %02i/%02i >" : " %02i/%02i ", pd->sprite.legs+1, PLAYER_SPRITE_LEGS_COUNT);
|
||||||
|
drawText(display, 96, 120);
|
||||||
|
sprintf(display, pd->ingameMenuSelection==5 ? "< %02i/%02i >" : " %02i/%02i ", pd->entity.p.dir+1, 4);
|
||||||
|
drawText(display, 96, 144);
|
||||||
|
sprintf(display, pd->ingameMenuSelection==6 ? "< Done >" : " Done ");
|
||||||
|
drawText(display, 96, 172);
|
||||||
|
|
||||||
|
int oox = offsetX;
|
||||||
|
int ooy = offsetY;
|
||||||
|
int osx = playerScale;
|
||||||
|
|
||||||
|
renderFrame(13,3,22,12,0xFF909090);
|
||||||
|
//move player sprite to 0/0
|
||||||
|
offsetX = pd->entity.x - 8;
|
||||||
|
offsetY = pd->entity.y - 8;
|
||||||
|
//move to where I want it
|
||||||
|
offsetX -= 108;
|
||||||
|
offsetY -= 28;
|
||||||
|
playerScale = 8;
|
||||||
|
renderPlayer(pd);
|
||||||
|
|
||||||
|
offsetX = oox;
|
||||||
|
offsetY = ooy;
|
||||||
|
playerScale = osx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//touch menu
|
||||||
|
void tickTouchMap(PlayerData *pd){
|
||||||
|
if(pd->mapShouldRender){
|
||||||
|
if(pd->inputs.k_touch.px > 0 || pd->inputs.k_touch.py > 0){
|
||||||
|
// Plus/Minus zoom button
|
||||||
|
if(pd->inputs.k_touch.py > 204 && pd->inputs.k_touch.py < 232){
|
||||||
|
if(pd->inputs.k_touch.px > 284 && pd->inputs.k_touch.px < 312){
|
||||||
|
if(pd->mapZoomLevel > 4) return;
|
||||||
|
if(!pd->touchIsChangingSize && !pd->touchIsDraggingMap){
|
||||||
|
pd->mapZoomLevel += 2;
|
||||||
|
pd->mapScrollX -= (50 * (pd->mapZoomLevel/2));
|
||||||
|
pd->mapScrollY -= (40 * (pd->mapZoomLevel/2));
|
||||||
|
pd->touchIsChangingSize = true;
|
||||||
|
sprintf(pd->mapText, "x%d", pd->mapZoomLevel);
|
||||||
|
}
|
||||||
|
if(pd->mapScrollX < 320-(128*pd->mapZoomLevel)) pd->mapScrollX = 320-(128*pd->mapZoomLevel);
|
||||||
|
else if(pd->mapScrollX > 0) pd->mapScrollX = 0;
|
||||||
|
if(pd->mapScrollY < 240-(128*pd->mapZoomLevel)) pd->mapScrollY = 240-(128*pd->mapZoomLevel);
|
||||||
|
else if(pd->mapScrollY > 0) pd->mapScrollY = 0;
|
||||||
|
return;
|
||||||
|
} else if(pd->inputs.k_touch.px > 256 && pd->inputs.k_touch.px < 284){
|
||||||
|
if(pd->mapZoomLevel < 4) return;
|
||||||
|
if(!pd->touchIsChangingSize && !pd->touchIsDraggingMap){
|
||||||
|
pd->mapScrollX += (50 * (pd->mapZoomLevel/2));
|
||||||
|
pd->mapScrollY += (40 * (pd->mapZoomLevel/2));
|
||||||
|
pd->mapZoomLevel -= 2;
|
||||||
|
pd->touchIsChangingSize = true;
|
||||||
|
sprintf(pd->mapText, "x%d", pd->mapZoomLevel);
|
||||||
|
}
|
||||||
|
if(pd->mapScrollX < 320-(128*pd->mapZoomLevel)) pd->mapScrollX = 320-(128*pd->mapZoomLevel);
|
||||||
|
else if(pd->mapScrollX > 0) pd->mapScrollX = 0;
|
||||||
|
if(pd->mapScrollY < 240-(128*pd->mapZoomLevel)) pd->mapScrollY = 240-(128*pd->mapZoomLevel);
|
||||||
|
else if(pd->mapScrollY > 0) pd->mapScrollY = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if(pd->inputs.k_touch.py > 8 && pd->inputs.k_touch.py < 40 && pd->inputs.k_touch.px > 284 && pd->inputs.k_touch.px < 312){
|
||||||
|
// Exit Button
|
||||||
|
if(!pd->touchIsChangingSize && !pd->touchIsDraggingMap){
|
||||||
|
pd->mapShouldRender = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!pd->touchIsDraggingMap){
|
||||||
|
pd->touchLastX = pd->inputs.k_touch.px;
|
||||||
|
pd->touchLastY = pd->inputs.k_touch.py;
|
||||||
|
}
|
||||||
|
if(pd->mapZoomLevel > 2){
|
||||||
|
int dx = pd->touchLastX - pd->inputs.k_touch.px;
|
||||||
|
if(dx > 1 || dx < -1){
|
||||||
|
pd->mapScrollX -= dx;
|
||||||
|
if(pd->mapScrollX < 320-(128*pd->mapZoomLevel)) pd->mapScrollX = 320-(128*pd->mapZoomLevel);
|
||||||
|
else if(pd->mapScrollX > 0) pd->mapScrollX = 0;
|
||||||
|
}
|
||||||
|
pd->touchLastX = pd->inputs.k_touch.px;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dy = pd->touchLastY - pd->inputs.k_touch.py;
|
||||||
|
if(dy > 1 || dy < -1){
|
||||||
|
pd->mapScrollY -= dy;
|
||||||
|
if(pd->mapScrollY < 240-(128*pd->mapZoomLevel)) pd->mapScrollY = 240-(128*pd->mapZoomLevel);
|
||||||
|
else if(pd->mapScrollY > 0) pd->mapScrollY = 0;
|
||||||
|
}
|
||||||
|
pd->touchLastY = pd->inputs.k_touch.py;
|
||||||
|
pd->touchIsDraggingMap = true;
|
||||||
|
} else {
|
||||||
|
pd->touchIsDraggingMap = false;
|
||||||
|
pd->touchIsChangingSize = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// touch minimap to bring up zoomed map.
|
||||||
|
if(pd->inputs.k_touch.py > 100 && pd->inputs.k_touch.py < 228 && pd->inputs.k_touch.px > 10 && pd->inputs.k_touch.px < 142){
|
||||||
|
pd->mapShouldRender = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tickTouchQuickSelect(PlayerData *pd) {
|
||||||
|
if (pd->ingameMenu == MENU_NONE && !pd->mapShouldRender) {
|
||||||
|
int i = 0;
|
||||||
|
Inventory * inv = &(pd->inventory);
|
||||||
|
|
||||||
|
for (i = 0; i < 8; ++i) {
|
||||||
|
if((inv->lastSlot) > i) {
|
||||||
|
int xip = i % 4;
|
||||||
|
int yip = i / 4;
|
||||||
|
|
||||||
|
if(pd->inputs.k_touch.py > 72*2+yip*21*2 && pd->inputs.k_touch.py < 72*2+yip*21*2+21*2 && pd->inputs.k_touch.px > 76*2+xip*21*2 && pd->inputs.k_touch.px < 76*2+xip*21*2+21*2) {
|
||||||
|
playerSetActiveItem(pd, &inv->items[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ingameMenuTickTouch(PlayerData *pd) {
|
||||||
|
tickTouchMap(pd);
|
||||||
|
tickTouchQuickSelect(pd);
|
||||||
|
}
|
8
source/IngameMenu.h
Normal file
8
source/IngameMenu.h
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Player.h"
|
||||||
|
|
||||||
|
void ingameMenuTick(PlayerData *pd, int menu);
|
||||||
|
void ingameMenuRender(PlayerData *pd, int menu);
|
||||||
|
|
||||||
|
void ingameMenuTickTouch(PlayerData *pd);
|
|
@ -5,19 +5,51 @@ void toggleKey(Key* key, bool held, bool down){
|
||||||
key->clicked = down;
|
key->clicked = down;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tickKeys(u32 held, u32 down){
|
void tickKeys(Inputs *inputs, u32 held, u32 down){
|
||||||
hidTouchRead(&k_touch); // Update touch position
|
hidTouchRead(&(inputs->k_touch)); // Update touch position
|
||||||
toggleKey(&k_up, held & k_up.input, down & k_up.input);
|
toggleKey(&(inputs->k_up), held & localInputs.k_up.input, down & localInputs.k_up.input);
|
||||||
toggleKey(&k_down, held & k_down.input, down & k_down.input);
|
toggleKey(&(inputs->k_down), held & localInputs.k_down.input, down & localInputs.k_down.input);
|
||||||
toggleKey(&k_left, held & k_left.input, down & k_left.input);
|
toggleKey(&(inputs->k_left), held & localInputs.k_left.input, down & localInputs.k_left.input);
|
||||||
toggleKey(&k_right, held & k_right.input, down & k_right.input);
|
toggleKey(&(inputs->k_right), held & localInputs.k_right.input, down & localInputs.k_right.input);
|
||||||
toggleKey(&k_pause, held & k_pause.input, down & k_pause.input);
|
toggleKey(&(inputs->k_pause), held & localInputs.k_pause.input, down & localInputs.k_pause.input);
|
||||||
toggleKey(&k_attack, held & k_attack.input, down & k_attack.input);
|
toggleKey(&(inputs->k_attack), held & localInputs.k_attack.input, down & localInputs.k_attack.input);
|
||||||
toggleKey(&k_menu, held & k_menu.input, down & k_menu.input);
|
toggleKey(&(inputs->k_menu), held & localInputs.k_menu.input, down & localInputs.k_menu.input);
|
||||||
toggleKey(&k_accept, held & k_accept.input, down & k_accept.input);
|
toggleKey(&(inputs->k_accept), held & localInputs.k_accept.input, down & localInputs.k_accept.input);
|
||||||
toggleKey(&k_decline, held & k_decline.input, down & k_decline.input);
|
toggleKey(&(inputs->k_decline), held & localInputs.k_decline.input, down & localInputs.k_decline.input);
|
||||||
toggleKey(&k_delete, held & k_delete.input, down & k_delete.input);
|
toggleKey(&(inputs->k_delete), held & localInputs.k_delete.input, down & localInputs.k_delete.input);
|
||||||
toggleKey(&k_menuNext, held & k_menuNext.input, down & k_menuNext.input);
|
toggleKey(&(inputs->k_menuNext), held & localInputs.k_menuNext.input, down & localInputs.k_menuNext.input);
|
||||||
toggleKey(&k_menuPrev, held & k_menuPrev.input, down & k_menuPrev.input);
|
toggleKey(&(inputs->k_menuPrev), held & localInputs.k_menuPrev.input, down & localInputs.k_menuPrev.input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void resetKeys(Inputs *inputs) {
|
||||||
|
(inputs->k_touch).px = -1;
|
||||||
|
(inputs->k_touch).py = -1;
|
||||||
|
|
||||||
|
toggleKey(&(inputs->k_up), false, false);
|
||||||
|
toggleKey(&(inputs->k_down), false, false);
|
||||||
|
toggleKey(&(inputs->k_left), false, false);
|
||||||
|
toggleKey(&(inputs->k_right), false, false);
|
||||||
|
toggleKey(&(inputs->k_pause), false, false);
|
||||||
|
toggleKey(&(inputs->k_attack), false, false);
|
||||||
|
toggleKey(&(inputs->k_menu), false, false);
|
||||||
|
toggleKey(&(inputs->k_accept), false, false);
|
||||||
|
toggleKey(&(inputs->k_decline), false, false);
|
||||||
|
toggleKey(&(inputs->k_delete), false, false);
|
||||||
|
toggleKey(&(inputs->k_menuNext), false, false);
|
||||||
|
toggleKey(&(inputs->k_menuPrev), false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetClicked(Inputs *inputs) {
|
||||||
|
inputs->k_up.clicked = false;
|
||||||
|
inputs->k_down.clicked = false;
|
||||||
|
inputs->k_left.clicked = false;
|
||||||
|
inputs->k_right.clicked = false;
|
||||||
|
inputs->k_pause.clicked = false;
|
||||||
|
inputs->k_attack.clicked = false;
|
||||||
|
inputs->k_menu.clicked = false;
|
||||||
|
inputs->k_accept.clicked = false;
|
||||||
|
inputs->k_decline.clicked = false;
|
||||||
|
inputs->k_delete.clicked = false;
|
||||||
|
inputs->k_menuNext.clicked = false;
|
||||||
|
inputs->k_menuPrev.clicked = false;
|
||||||
|
}
|
||||||
|
|
|
@ -1,24 +1,33 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include <3ds.h>
|
#include <3ds.h>
|
||||||
|
|
||||||
|
//only down and clicked need to be send, input is for config stuff
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool down, clicked;
|
bool down, clicked;
|
||||||
int input;
|
int input;
|
||||||
} Key;
|
} Key;
|
||||||
|
|
||||||
Key k_null;
|
typedef struct {
|
||||||
Key k_up;
|
Key k_null;
|
||||||
Key k_down;
|
Key k_up;
|
||||||
Key k_left;
|
Key k_down;
|
||||||
Key k_right;
|
Key k_left;
|
||||||
Key k_attack;
|
Key k_right;
|
||||||
Key k_menu;
|
Key k_attack;
|
||||||
Key k_pause;
|
Key k_menu;
|
||||||
Key k_accept;
|
Key k_pause;
|
||||||
Key k_decline;
|
Key k_accept;
|
||||||
Key k_delete;
|
Key k_decline;
|
||||||
Key k_menuNext;
|
Key k_delete;
|
||||||
Key k_menuPrev;
|
Key k_menuNext;
|
||||||
touchPosition k_touch;
|
Key k_menuPrev;
|
||||||
|
touchPosition k_touch;
|
||||||
|
} Inputs;
|
||||||
|
|
||||||
void tickKeys(u32 held, u32 down);
|
Inputs localInputs;
|
||||||
|
|
||||||
|
void tickKeys(Inputs *inputs, u32 held, u32 down);
|
||||||
|
void resetKeys(Inputs *inputs);
|
||||||
|
void resetClicked(Inputs *inputs);
|
||||||
bool clicked(Key key);
|
bool clicked(Key key);
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
|
|
||||||
char currentName[16];
|
char currentName[16];
|
||||||
|
|
||||||
bool isItemEmpty(Item* item){
|
bool isItemEmpty(Item* item) {
|
||||||
if(item->id < 6 || item->id > 100 || item->onlyOne == true) return false;
|
if(item->id < 6 || item->id > 100 || item->onlyOne == true) return false;
|
||||||
if(item->countLevel < 1) return true;
|
if(item->countLevel < 1) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pushItemToInventoryFront(Item item, Inventory * inv){
|
void pushItemToInventoryFront(Item item, Inventory * inv) {
|
||||||
if(inv->lastSlot < 300) ++inv->lastSlot;
|
if(inv->lastSlot < 300) ++inv->lastSlot;
|
||||||
int i;
|
int i;
|
||||||
for(i = inv->lastSlot;i > 0;--i){
|
for(i = inv->lastSlot;i > 0;--i){
|
||||||
|
@ -21,7 +21,7 @@ void pushItemToInventoryFront(Item item, Inventory * inv){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void addItemToInventory(Item item, Inventory * inv){
|
void addItemToInventory(Item item, Inventory * inv) {
|
||||||
if(!item.onlyOne){
|
if(!item.onlyOne){
|
||||||
int i;
|
int i;
|
||||||
for(i = 0;i < inv->lastSlot;++i){ //Search inventory if item already exists.
|
for(i = 0;i < inv->lastSlot;++i){ //Search inventory if item already exists.
|
||||||
|
@ -38,12 +38,12 @@ void addItemToInventory(Item item, Inventory * inv){
|
||||||
++inv->lastSlot;
|
++inv->lastSlot;
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeItemFromCurrentInv(Item* item){
|
void removeItemFromCurrentInv(Item* item) {
|
||||||
removeItemFromInventory(item->slotNum, (Inventory*)item->invPtr);
|
removeItemFromInventory(item->slotNum, (Inventory*)item->invPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Item nullItem;
|
Item nullItem;
|
||||||
void removeItemFromInventory(int slot, Inventory * inv){
|
void removeItemFromInventory(int slot, Inventory * inv) {
|
||||||
int i;
|
int i;
|
||||||
for(i = slot;i < inv->lastSlot - 1;++i){
|
for(i = slot;i < inv->lastSlot - 1;++i){
|
||||||
inv->items[i] = inv->items[i + 1]; // Move the items down.
|
inv->items[i] = inv->items[i + 1]; // Move the items down.
|
||||||
|
@ -53,7 +53,7 @@ void removeItemFromInventory(int slot, Inventory * inv){
|
||||||
inv->items[inv->lastSlot] = nullItem; // Make the last slot null.
|
inv->items[inv->lastSlot] = nullItem; // Make the last slot null.
|
||||||
}
|
}
|
||||||
|
|
||||||
Item newItem(int id, int cLevel){
|
Item newItem(int id, int cLevel) {
|
||||||
Item item;
|
Item item;
|
||||||
item.id = id;
|
item.id = id;
|
||||||
if(id != ITEM_NULL){
|
if(id != ITEM_NULL){
|
||||||
|
@ -66,7 +66,7 @@ Item newItem(int id, int cLevel){
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
Item* getItemFromInventory(int itemID, Inventory * inv){
|
Item* getItemFromInventory(int itemID, Inventory * inv) {
|
||||||
int i;
|
int i;
|
||||||
for(i = 0;i < inv->lastSlot;++i){
|
for(i = 0;i < inv->lastSlot;++i){
|
||||||
if(inv->items[i].id == itemID){
|
if(inv->items[i].id == itemID){
|
||||||
|
@ -76,7 +76,7 @@ Item* getItemFromInventory(int itemID, Inventory * inv){
|
||||||
return (Item*)NULL;
|
return (Item*)NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int countItemInv(int itemID, int level, Inventory* inv){
|
int countItemInv(int itemID, int level, Inventory* inv) {
|
||||||
int i, count = 0;
|
int i, count = 0;
|
||||||
for(i = 0;i < inv->lastSlot;++i){
|
for(i = 0;i < inv->lastSlot;++i){
|
||||||
if(inv->items[i].id == itemID){
|
if(inv->items[i].id == itemID){
|
||||||
|
@ -88,7 +88,7 @@ int countItemInv(int itemID, int level, Inventory* inv){
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* getItemName(int itemID, int countLevel){
|
char* getItemName(int itemID, int countLevel) {
|
||||||
switch(itemID){
|
switch(itemID){
|
||||||
case TOOL_SHOVEL:
|
case TOOL_SHOVEL:
|
||||||
switch(countLevel){
|
switch(countLevel){
|
||||||
|
@ -204,7 +204,7 @@ char* getItemName(int itemID, int countLevel){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char* getBasicItemName(int itemID, int countLevel){
|
char* getBasicItemName(int itemID, int countLevel) {
|
||||||
switch(itemID){
|
switch(itemID){
|
||||||
case TOOL_SHOVEL:
|
case TOOL_SHOVEL:
|
||||||
switch(countLevel){
|
switch(countLevel){
|
||||||
|
|
107
source/MapGen.c
107
source/MapGen.c
|
@ -15,56 +15,52 @@ double sample(double * values, int x, int y) {
|
||||||
}
|
}
|
||||||
|
|
||||||
double * Noise(int width, int height, int featureSize) {
|
double * Noise(int width, int height, int featureSize) {
|
||||||
w = width;
|
w = width;
|
||||||
h = height;
|
h = height;
|
||||||
double * values = malloc(sizeof(double) * w * h);
|
double * values = malloc(sizeof(double) * w * h);
|
||||||
int x, y;
|
int x, y;
|
||||||
for(x = 0; x < w; x+=featureSize){
|
for(x = 0; x < w; x+=featureSize){
|
||||||
for(y = 0; y < w; y+=featureSize){
|
for(y = 0; y < w; y+=featureSize){
|
||||||
values[(x & (w - 1)) + (y & (h - 1)) * w] = nextFloat() * 2 - 1;
|
values[(x & (w - 1)) + (y & (h - 1)) * w] = nextFloat() * 2 - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int stepSize = featureSize;
|
int stepSize = featureSize;
|
||||||
double scale = 1.0 / w;
|
double scale = 1.0 / w;
|
||||||
double scaleMod = 1;
|
double scaleMod = 1;
|
||||||
do {
|
do {
|
||||||
int halfStep = stepSize / 2;
|
int halfStep = stepSize / 2;
|
||||||
for(x = 0; x < w; x+=stepSize){
|
for(x = 0; x < w; x+=stepSize){
|
||||||
for(y = 0; y < w; y+=stepSize){
|
for(y = 0; y < w; y+=stepSize){
|
||||||
double a = sample(values,x, y);
|
double a = sample(values,x, y);
|
||||||
double b = sample(values,x + stepSize, y);
|
double b = sample(values,x + stepSize, y);
|
||||||
double c = sample(values,x, y + stepSize);
|
double c = sample(values,x, y + stepSize);
|
||||||
double d = sample(values,x + stepSize, y + stepSize);
|
double d = sample(values,x + stepSize, y + stepSize);
|
||||||
|
|
||||||
double e = (a + b + c + d) / 4.0 + (nextFloat() * 2 - 1) * stepSize * scale;
|
double e = (a + b + c + d) / 4.0 + (nextFloat() * 2 - 1) * stepSize * scale;
|
||||||
values[((x + halfStep) & (w - 1)) + ((y + halfStep) & (h - 1)) * w] = e;
|
values[((x + halfStep) & (w - 1)) + ((y + halfStep) & (h - 1)) * w] = e;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for(x = 0; x < w; x+=stepSize){
|
}
|
||||||
for(y = 0; y < w; y+=stepSize){
|
for(x = 0; x < w; x+=stepSize){
|
||||||
double a = sample(values,x, y);
|
for(y = 0; y < w; y+=stepSize){
|
||||||
double b = sample(values,x + stepSize, y);
|
double a = sample(values,x, y);
|
||||||
double c = sample(values,x, y + stepSize);
|
double b = sample(values,x + stepSize, y);
|
||||||
double d = sample(values,x + halfStep, y + halfStep);
|
double c = sample(values,x, y + stepSize);
|
||||||
double e = sample(values,x + halfStep, y - halfStep);
|
double d = sample(values,x + halfStep, y + halfStep);
|
||||||
double f = sample(values,x - halfStep, y + halfStep);
|
double e = sample(values,x + halfStep, y - halfStep);
|
||||||
double H = (a + b + d + e) / 4.0 + (nextFloat() * 2 - 1) * stepSize * scale * 0.5;
|
double f = sample(values,x - halfStep, y + halfStep);
|
||||||
double g = (a + c + d + f) / 4.0 + (nextFloat() * 2 - 1) * stepSize * scale * 0.5;
|
double H = (a + b + d + e) / 4.0 + (nextFloat() * 2 - 1) * stepSize * scale * 0.5;
|
||||||
values[((x + halfStep) & (w - 1)) + (y & (h - 1)) * w] = H;
|
double g = (a + c + d + f) / 4.0 + (nextFloat() * 2 - 1) * stepSize * scale * 0.5;
|
||||||
values[(x & (w - 1)) + ((y + halfStep) & (h - 1)) * w] = g;
|
values[((x + halfStep) & (w - 1)) + (y & (h - 1)) * w] = H;
|
||||||
}
|
values[(x & (w - 1)) + ((y + halfStep) & (h - 1)) * w] = g;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
stepSize /= 2;
|
stepSize /= 2;
|
||||||
scale *= (scaleMod + 0.8);
|
scale *= (scaleMod + 0.8);
|
||||||
scaleMod *= 0.3;
|
scaleMod *= 0.3;
|
||||||
} while (stepSize > 1);
|
} while (stepSize > 1);
|
||||||
return values;
|
return values;
|
||||||
}
|
|
||||||
|
|
||||||
void newSeed(){
|
|
||||||
srand(time(NULL));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Will need to reset entity manager if generation is retried
|
//TODO: Will need to reset entity manager if generation is retried
|
||||||
|
@ -331,8 +327,10 @@ void createUndergroundMap(int w, int h, int depthLevel, int level, u8 * map, u8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//generate dwarf house
|
||||||
if(depthLevel==3) {
|
if(depthLevel==3) {
|
||||||
createDwarfHouse(w, h, level, map, data);
|
createDwarfHouse(w, h, level, map, data);
|
||||||
|
//generate mushroom patches
|
||||||
} else if(depthLevel==2) {
|
} else if(depthLevel==2) {
|
||||||
for (i = 0; i < w * h / 5400; ++i) {
|
for (i = 0; i < w * h / 5400; ++i) {
|
||||||
int xs = rand()%w;
|
int xs = rand()%w;
|
||||||
|
@ -361,6 +359,7 @@ void createUndergroundMap(int w, int h, int depthLevel, int level, u8 * map, u8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//generate ores
|
||||||
for (i = 0; i < w * h / 400; ++i) {
|
for (i = 0; i < w * h / 400; ++i) {
|
||||||
int x = rand()%w;
|
int x = rand()%w;
|
||||||
int y = rand()%h;
|
int y = rand()%h;
|
||||||
|
@ -374,6 +373,8 @@ void createUndergroundMap(int w, int h, int depthLevel, int level, u8 * map, u8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//generate stairs down
|
||||||
if (depthLevel < 3){
|
if (depthLevel < 3){
|
||||||
int sCount, attempts = 0;
|
int sCount, attempts = 0;
|
||||||
for (sCount = 0; sCount < 4;) {
|
for (sCount = 0; sCount < 4;) {
|
||||||
|
@ -396,6 +397,22 @@ void createUndergroundMap(int w, int h, int depthLevel, int level, u8 * map, u8
|
||||||
if(attempts < (w*h/100)) ++attempts; else break;
|
if(attempts < (w*h/100)) ++attempts; else break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//generate dungeon entrance
|
||||||
|
if(depthLevel==3) {
|
||||||
|
map[w/2+0 + (h/2+0) * w] = TILE_DUNGEON_ENTRANCE;
|
||||||
|
|
||||||
|
map[w/2-1 + (h/2+0) * w] = TILE_DIRT;
|
||||||
|
map[w/2+1 + (h/2+0) * w] = TILE_DIRT;
|
||||||
|
map[w/2+0 + (h/2-1) * w] = TILE_DIRT;
|
||||||
|
map[w/2+1 + (h/2+1) * w] = TILE_DIRT;
|
||||||
|
|
||||||
|
map[w/2-1 + (h/2-1) * w] = TILE_DUNGEON_WALL;
|
||||||
|
map[w/2-1 + (h/2+1) * w] = TILE_DUNGEON_WALL;
|
||||||
|
map[w/2+1 + (h/2-1) * w] = TILE_DUNGEON_WALL;
|
||||||
|
map[w/2+1 + (h/2+1) * w] = TILE_DUNGEON_WALL;
|
||||||
|
}
|
||||||
|
|
||||||
free(mnoise1);
|
free(mnoise1);
|
||||||
free(mnoise2);
|
free(mnoise2);
|
||||||
free(mnoise3);
|
free(mnoise3);
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <time.h>
|
|
||||||
#include <3ds.h>
|
#include <3ds.h>
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
|
@ -10,7 +9,6 @@
|
||||||
float nextFloat();
|
float nextFloat();
|
||||||
double sample(double * values, int x, int y);
|
double sample(double * values, int x, int y);
|
||||||
double * Noise(int w, int h, int featureSize);
|
double * Noise(int w, int h, int featureSize);
|
||||||
void newSeed();
|
|
||||||
void createAndValidateTopMap(int w, int h, int level, u8 * map, u8 * data);
|
void createAndValidateTopMap(int w, int h, int level, u8 * map, u8 * data);
|
||||||
void createTopMap(int w, int h, int level, u8 * map, u8 * data);
|
void createTopMap(int w, int h, int level, u8 * map, u8 * data);
|
||||||
void createAndValidateUndergroundMap(int w, int h, int depthLevel, int level, u8 * map, u8 * data);
|
void createAndValidateUndergroundMap(int w, int h, int depthLevel, int level, u8 * map, u8 * data);
|
||||||
|
|
832
source/Menu.c
832
source/Menu.c
File diff suppressed because it is too large
Load diff
|
@ -25,18 +25,18 @@ void renderTutorialPage(bool topScreen){
|
||||||
case 0: // Moving the character
|
case 0: // Moving the character
|
||||||
drawTextColor("Movement",(400-8*12)/2,40,0xFF007FBF);
|
drawTextColor("Movement",(400-8*12)/2,40,0xFF007FBF);
|
||||||
drawText("Press to move up",92,90);
|
drawText("Press to move up",92,90);
|
||||||
renderButtonIcon(biasedCirclePad(k_up.input), 164, 88, 1);
|
renderButtonIcon(biasedCirclePad(localInputs.k_up.input), 164, 88, 1);
|
||||||
drawText("Press to move down",80,120);
|
drawText("Press to move down",80,120);
|
||||||
renderButtonIcon(biasedCirclePad(k_down.input), 152, 118, 1);
|
renderButtonIcon(biasedCirclePad(localInputs.k_down.input), 152, 118, 1);
|
||||||
drawText("Press to move left",80,150);
|
drawText("Press to move left",80,150);
|
||||||
renderButtonIcon(biasedCirclePad(k_left.input), 152, 148, 1);
|
renderButtonIcon(biasedCirclePad(localInputs.k_left.input), 152, 148, 1);
|
||||||
drawText("Press to move right",74,180);
|
drawText("Press to move right",74,180);
|
||||||
renderButtonIcon(biasedCirclePad(k_right.input), 146, 178, 1);
|
renderButtonIcon(biasedCirclePad(localInputs.k_right.input), 146, 178, 1);
|
||||||
break;
|
break;
|
||||||
case 1: // Attacking
|
case 1: // Attacking
|
||||||
drawTextColor("Attacking",(400-9*12)/2,40,0xFF007FBF);
|
drawTextColor("Attacking",(400-9*12)/2,40,0xFF007FBF);
|
||||||
drawText("Press to Attack",98,80);
|
drawText("Press to Attack",98,80);
|
||||||
renderButtonIcon(k_attack.input & -k_attack.input, 168, 78, 1);
|
renderButtonIcon(localInputs.k_attack.input & -localInputs.k_attack.input, 168, 78, 1);
|
||||||
drawText("Attack with an item to use it",26,120);
|
drawText("Attack with an item to use it",26,120);
|
||||||
drawText("Use the axe to cut down trees",26,140);
|
drawText("Use the axe to cut down trees",26,140);
|
||||||
drawText("Use the sword to attack enemies",14,160);
|
drawText("Use the sword to attack enemies",14,160);
|
||||||
|
@ -46,21 +46,21 @@ void renderTutorialPage(bool topScreen){
|
||||||
case 2: // Inventory
|
case 2: // Inventory
|
||||||
drawTextColor("Inventory",(400-9*12)/2,40,0xFF007FBF);
|
drawTextColor("Inventory",(400-9*12)/2,40,0xFF007FBF);
|
||||||
drawText("Press to open the menu",56,80);
|
drawText("Press to open the menu",56,80);
|
||||||
renderButtonIcon(biasedMenuXY(k_menu.input), 126, 78, 1);
|
renderButtonIcon(biasedMenuXY(localInputs.k_menu.input), 126, 78, 1);
|
||||||
drawText("Press to scroll up",80,110);
|
drawText("Press to scroll up",80,110);
|
||||||
renderButtonIcon(biasedCirclePad(k_up.input), 152, 108, 1);
|
renderButtonIcon(biasedCirclePad(localInputs.k_up.input), 152, 108, 1);
|
||||||
drawText("Press to scroll down",68,140);
|
drawText("Press to scroll down",68,140);
|
||||||
renderButtonIcon(biasedCirclePad(k_down.input), 140, 138, 1);
|
renderButtonIcon(biasedCirclePad(localInputs.k_down.input), 140, 138, 1);
|
||||||
drawText("Press to select an item",50,170);
|
drawText("Press to select an item",50,170);
|
||||||
renderButtonIcon(k_accept.input & -k_accept.input, 120, 168, 1);
|
renderButtonIcon(localInputs.k_accept.input & -localInputs.k_accept.input, 120, 168, 1);
|
||||||
drawText("Press to close the menu",50,200);
|
drawText("Press to close the menu",50,200);
|
||||||
renderButtonIcon(k_decline.input & -k_decline.input, 120, 198, 1);
|
renderButtonIcon(localInputs.k_decline.input & -localInputs.k_decline.input, 120, 198, 1);
|
||||||
break;
|
break;
|
||||||
case 3: // Furniture
|
case 3: // Furniture
|
||||||
drawTextColor("Furniture",(400-9*12)/2,40,0xFF007FBF);
|
drawTextColor("Furniture",(400-9*12)/2,40,0xFF007FBF);
|
||||||
drawText("Use furniture for item crafting",(400-31*12)/2,74);
|
drawText("Use furniture for item crafting",(400-31*12)/2,74);
|
||||||
drawText("Press to open the menu",56,100);
|
drawText("Press to open the menu",56,100);
|
||||||
renderButtonIcon(biasedMenuXY(k_menu.input), 126, 98, 1);
|
renderButtonIcon(biasedMenuXY(localInputs.k_menu.input), 126, 98, 1);
|
||||||
drawText("while infront of the furniture",(400-30*12)/2,116);
|
drawText("while infront of the furniture",(400-30*12)/2,116);
|
||||||
drawText("Use the lantern item to light",(400-29*12)/2,144);
|
drawText("Use the lantern item to light",(400-29*12)/2,144);
|
||||||
drawText("up underground areas",(400-20*12)/2,160);
|
drawText("up underground areas",(400-20*12)/2,160);
|
||||||
|
@ -72,10 +72,10 @@ void renderTutorialPage(bool topScreen){
|
||||||
drawText("Create new items and tools",(400-26*12)/2,74);
|
drawText("Create new items and tools",(400-26*12)/2,74);
|
||||||
drawText("Go up to a furniture item and",(400-29*12)/2,104);
|
drawText("Go up to a furniture item and",(400-29*12)/2,104);
|
||||||
drawText("Press to open the menu",56,120);
|
drawText("Press to open the menu",56,120);
|
||||||
renderButtonIcon(biasedMenuXY(k_menu.input), 126, 118, 1);
|
renderButtonIcon(biasedMenuXY(localInputs.k_menu.input), 126, 118, 1);
|
||||||
drawText("Gather up the required materials",(400-32*12)/2,150);
|
drawText("Gather up the required materials",(400-32*12)/2,150);
|
||||||
drawText("and then press to craft it",(400-28*12)/2,166);
|
drawText("and then press to craft it",(400-28*12)/2,166);
|
||||||
renderButtonIcon(k_accept.input & -k_accept.input, 210, 164, 1);
|
renderButtonIcon(localInputs.k_accept.input & -localInputs.k_accept.input, 210, 164, 1);
|
||||||
break;
|
break;
|
||||||
case 5: // Farming
|
case 5: // Farming
|
||||||
drawTextColor("Farming",(400-7*12)/2,40,0xFF007FBF);
|
drawTextColor("Farming",(400-7*12)/2,40,0xFF007FBF);
|
||||||
|
@ -108,17 +108,17 @@ void renderTutorialPage(bool topScreen){
|
||||||
switch(pageNum){
|
switch(pageNum){
|
||||||
case 0: // Moving the character
|
case 0: // Moving the character
|
||||||
render16(30,56,16,112,0);//Player up
|
render16(30,56,16,112,0);//Player up
|
||||||
renderButtonIcon(biasedCirclePad(k_up.input), 30,40, 2);
|
renderButtonIcon(biasedCirclePad(localInputs.k_up.input), 30,40, 2);
|
||||||
render16(60,56,0,112,0);//Player down
|
render16(60,56,0,112,0);//Player down
|
||||||
renderButtonIcon(biasedCirclePad(k_down.input), 60,40, 2);
|
renderButtonIcon(biasedCirclePad(localInputs.k_down.input), 60,40, 2);
|
||||||
render16(90,56,48,112,1);//Player left
|
render16(90,56,48,112,1);//Player left
|
||||||
renderButtonIcon(biasedCirclePad(k_left.input), 90,40, 2);
|
renderButtonIcon(biasedCirclePad(localInputs.k_left.input), 90,40, 2);
|
||||||
render16(120,56,48,112,0);//Player right
|
render16(120,56,48,112,0);//Player right
|
||||||
renderButtonIcon(biasedCirclePad(k_right.input), 120,40, 2);
|
renderButtonIcon(biasedCirclePad(localInputs.k_right.input), 120,40, 2);
|
||||||
break;
|
break;
|
||||||
case 1: // Attacking
|
case 1: // Attacking
|
||||||
render16(60,56,0,112,0);//Player-down
|
render16(60,56,0,112,0);//Player-down
|
||||||
renderButtonIcon(k_attack.input & -k_attack.input, 80, 56, 2);
|
renderButtonIcon(localInputs.k_attack.input & -localInputs.k_attack.input, 80, 56, 2);
|
||||||
renderc(60,68,16,160,16,8,2);//Slash
|
renderc(60,68,16,160,16,8,2);//Slash
|
||||||
|
|
||||||
menuRenderTilePit(12,20,256,0);// grass pit
|
menuRenderTilePit(12,20,256,0);// grass pit
|
||||||
|
@ -143,9 +143,9 @@ void renderTutorialPage(bool topScreen){
|
||||||
renderItemStuffWithText(ITEM_IRONINGOT,11,false,80,142);
|
renderItemStuffWithText(ITEM_IRONINGOT,11,false,80,142);
|
||||||
sf2d_draw_rectangle(64, 110, 12, 12, 0xFF);
|
sf2d_draw_rectangle(64, 110, 12, 12, 0xFF);
|
||||||
drawText(">", 64, 110);
|
drawText(">", 64, 110);
|
||||||
renderButtonIcon(biasedCirclePad(k_up.input), 44, 92, 1);
|
renderButtonIcon(biasedCirclePad(localInputs.k_up.input), 44, 92, 1);
|
||||||
renderButtonIcon(k_accept.input & -k_accept.input, 44, 108, 1);
|
renderButtonIcon(localInputs.k_accept.input & -localInputs.k_accept.input, 44, 108, 1);
|
||||||
renderButtonIcon(biasedCirclePad(k_down.input), 44, 125, 1);
|
renderButtonIcon(biasedCirclePad(localInputs.k_down.input), 44, 125, 1);
|
||||||
break;
|
break;
|
||||||
case 3: // Furniture
|
case 3: // Furniture
|
||||||
sf2d_draw_rectangle(64, 48, 192, 32, grassColor);
|
sf2d_draw_rectangle(64, 48, 192, 32, grassColor);
|
||||||
|
@ -248,13 +248,13 @@ void renderTutorialPage(bool topScreen){
|
||||||
drawText(pageText,(320-(strlen(pageText))*12)/2,12);
|
drawText(pageText,(320-(strlen(pageText))*12)/2,12);
|
||||||
if(pageNum > 0){
|
if(pageNum > 0){
|
||||||
drawText("<",2,16);
|
drawText("<",2,16);
|
||||||
renderButtonIcon(k_menuPrev.input & -k_menuPrev.input, 8, 2, 2);
|
renderButtonIcon(localInputs.k_menuPrev.input & -localInputs.k_menuPrev.input, 8, 2, 2);
|
||||||
}
|
}
|
||||||
if(pageNum < maxPageNum){
|
if(pageNum < maxPageNum){
|
||||||
drawText(">",306,16);
|
drawText(">",306,16);
|
||||||
renderButtonIcon(k_menuNext.input & -k_menuNext.input, 136, 2, 2);
|
renderButtonIcon(localInputs.k_menuNext.input & -localInputs.k_menuNext.input, 136, 2, 2);
|
||||||
}
|
}
|
||||||
drawText("Press to exit",(320-(15*12))/2,218);
|
drawText("Press to exit",(320-(15*12))/2,218);
|
||||||
renderButtonIcon(k_decline.input & -k_decline.input, 140, 216, 1);
|
renderButtonIcon(localInputs.k_decline.input & -localInputs.k_decline.input, 140, 216, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
492
source/Network.c
492
source/Network.c
|
@ -14,11 +14,245 @@ bool isConnected;
|
||||||
bool isServer;
|
bool isServer;
|
||||||
|
|
||||||
size_t networkBufferSize;
|
size_t networkBufferSize;
|
||||||
u32 *networkBuffer;
|
void *networkBuffer;
|
||||||
|
|
||||||
udsNetworkStruct networkStruct;
|
udsNetworkStruct networkStruct;
|
||||||
udsBindContext networkBindCtx;
|
udsBindContext networkBindCtx;
|
||||||
|
|
||||||
|
udsConnectionStatus networkStatus;
|
||||||
|
|
||||||
|
u16 networkConnectedMask;
|
||||||
|
|
||||||
|
//new code
|
||||||
|
//structure in buffer is u16(seqID),u16(size),size(data), ...
|
||||||
|
void *networkSendBuffer;
|
||||||
|
size_t networkSendBufferStartPos;
|
||||||
|
size_t networkSendBufferEndPos;
|
||||||
|
size_t networkSendBufferWrapPos;
|
||||||
|
|
||||||
|
u16 networkSeqSendNext;
|
||||||
|
u16 networkSeqSendConf[UDS_MAXNODES+1];
|
||||||
|
u16 networkSeqRecvLast[UDS_MAXNODES+1];
|
||||||
|
void *networkAckBuffer;
|
||||||
|
|
||||||
|
//async internal send/recieve handling
|
||||||
|
Thread networkThread;
|
||||||
|
volatile bool networkRunThread;
|
||||||
|
LightLock sendBufferLock;
|
||||||
|
|
||||||
|
void networkHandleSend();
|
||||||
|
void networkHandleRecieve();
|
||||||
|
void clearSendAckedBuffer();
|
||||||
|
bool sendAck(u16 target, u16 ack);
|
||||||
|
|
||||||
|
void networkThreadMain(void *arg) {
|
||||||
|
while(networkRunThread) {
|
||||||
|
if(udsRunning && isConnected) {
|
||||||
|
networkUpdateStatus();
|
||||||
|
networkHandleRecieve();
|
||||||
|
networkHandleSend();
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Set meaningfull value, WARNING: Setting this near 1ms (1000*1000) will make everything super laggy, higher values actually work better!
|
||||||
|
svcSleepThread(10000 * 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void networkUpdateStatus() {
|
||||||
|
/*for(int i=0; i<10; i++) {
|
||||||
|
Result ret = udsGetConnectionStatus(&networkStatus);
|
||||||
|
if(!R_FAILED(ret)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
if(udsWaitConnectionStatusEvent(false, false)) {
|
||||||
|
udsGetConnectionStatus(&networkStatus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void networkHandleRecieve() {
|
||||||
|
bool recieved = false;
|
||||||
|
do {
|
||||||
|
recieved = false;
|
||||||
|
|
||||||
|
size_t actualSize = 0;
|
||||||
|
u16 sourceNetworkNodeID;
|
||||||
|
u32 ackToSend = 0;
|
||||||
|
|
||||||
|
memset(networkBuffer, 0, networkBufferSize);
|
||||||
|
|
||||||
|
Result ret = udsPullPacket(&networkBindCtx, networkBuffer, networkBufferSize, &actualSize, &sourceNetworkNodeID);
|
||||||
|
if(R_FAILED(ret)) {
|
||||||
|
//TODO: what do?
|
||||||
|
|
||||||
|
//actualSize will be 0 if no packet is available
|
||||||
|
} else if(actualSize) {
|
||||||
|
void *readPointer = networkBuffer;
|
||||||
|
|
||||||
|
//ack frame
|
||||||
|
if(actualSize==sizeof(u16)) {
|
||||||
|
networkSeqSendConf[sourceNetworkNodeID] = *((u16*) readPointer);
|
||||||
|
clearSendAckedBuffer();
|
||||||
|
//normal frame
|
||||||
|
} else {
|
||||||
|
while(actualSize>0) {
|
||||||
|
//read seqID and size
|
||||||
|
u16 seqID = *((u16*) readPointer);
|
||||||
|
readPointer += sizeof(u16);
|
||||||
|
actualSize -= sizeof(u16);
|
||||||
|
|
||||||
|
u16 size = *((u16*) readPointer);
|
||||||
|
readPointer += sizeof(u16);
|
||||||
|
actualSize -= sizeof(u16);
|
||||||
|
|
||||||
|
//if the seq id was expected handle the packet
|
||||||
|
u32 nextID = networkSeqRecvLast[sourceNetworkNodeID]+1;
|
||||||
|
if(seqID==nextID) {
|
||||||
|
networkSeqRecvLast[sourceNetworkNodeID] = seqID;
|
||||||
|
ackToSend = seqID;
|
||||||
|
|
||||||
|
//handle data - TODO: WARNING: Do not send sizeof(u16) packets or else they will get confused with this one
|
||||||
|
if(size==sizeof(u16)) {
|
||||||
|
networkConnectedMask = *((u16*) readPointer);
|
||||||
|
} else {
|
||||||
|
processPacket(readPointer, size);
|
||||||
|
}
|
||||||
|
} else if(seqID<=nextID-1) {
|
||||||
|
ackToSend = nextID-1;
|
||||||
|
}
|
||||||
|
readPointer += size;
|
||||||
|
actualSize -= size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ackToSend!=0) {
|
||||||
|
if(sendAck(sourceNetworkNodeID, ackToSend)) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
recieved = true;
|
||||||
|
}
|
||||||
|
} while(recieved);
|
||||||
|
}
|
||||||
|
|
||||||
|
void networkHandleSend() {
|
||||||
|
if(networkSendBufferStartPos!=networkSendBufferEndPos) {
|
||||||
|
LightLock_Lock(&sendBufferLock);
|
||||||
|
|
||||||
|
//determine send size
|
||||||
|
size_t currentSize = 0;
|
||||||
|
while(networkSendBufferStartPos+currentSize<networkSendBufferWrapPos && networkSendBufferStartPos+currentSize!=networkSendBufferEndPos) {
|
||||||
|
//size of "header info" (seqid,size)
|
||||||
|
size_t extraSize = sizeof(u16) + sizeof(u16);
|
||||||
|
//data size
|
||||||
|
extraSize += *((u16*) ((networkSendBuffer+networkSendBufferStartPos+currentSize) + sizeof(u16)));
|
||||||
|
|
||||||
|
//if next packet can fit in frame include it
|
||||||
|
if(currentSize+extraSize < UDS_DATAFRAME_MAXSIZE) {
|
||||||
|
currentSize += extraSize;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//send frame
|
||||||
|
if(currentSize>0) {
|
||||||
|
//TODO: Once we have our own custom mask, no longer broadcast, but send directly because bcast doesn't always reach everyone?
|
||||||
|
if(networkConnectedMask==0) {
|
||||||
|
//send frame
|
||||||
|
Result ret = udsSendTo(UDS_BROADCAST_NETWORKNODEID, NETWORK_CHANNEL, UDS_SENDFLAG_Default, networkSendBuffer+networkSendBufferStartPos, currentSize);
|
||||||
|
if(UDS_CHECK_SENDTO_FATALERROR(ret)) {
|
||||||
|
//TODO: what do?
|
||||||
|
} else if(R_FAILED(ret)) {
|
||||||
|
//TODO: what do?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(int i=1; i<=UDS_MAXNODES; i++) {
|
||||||
|
if(i!=networkGetLocalNodeID()/* && networkIsNodeConnected(i)*/ && networkConnectedMask & (1 << (i-1))) {
|
||||||
|
//send frame
|
||||||
|
Result ret = udsSendTo(i, NETWORK_CHANNEL, UDS_SENDFLAG_Default, networkSendBuffer+networkSendBufferStartPos, currentSize);
|
||||||
|
if(UDS_CHECK_SENDTO_FATALERROR(ret)) {
|
||||||
|
//TODO: what do?
|
||||||
|
} else if(R_FAILED(ret)) {
|
||||||
|
//TODO: what do?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LightLock_Unlock(&sendBufferLock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearSendAckedBuffer() {
|
||||||
|
//find last ack recieved from all com partners
|
||||||
|
u16 ackID = 0;
|
||||||
|
for(int i=1; i<=UDS_MAXNODES; i++) {
|
||||||
|
if(i!=networkGetLocalNodeID()/* && networkIsNodeConnected(i)*/ && networkConnectedMask & (1 << (i-1))) {
|
||||||
|
if(networkSeqSendConf[i]==0) {
|
||||||
|
ackID = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ackID==0) {
|
||||||
|
ackID = networkSeqSendConf[i];
|
||||||
|
} else if(networkSeqSendConf[i]<100) {
|
||||||
|
if(ackID > networkSeqSendConf[i] && ackID<65535-100) ackID = networkSeqSendConf[i];
|
||||||
|
} else if(networkSeqSendConf[i]>65535-100) {
|
||||||
|
if(ackID > networkSeqSendConf[i] || ackID<100) ackID = networkSeqSendConf[i];
|
||||||
|
} else {
|
||||||
|
if(ackID > networkSeqSendConf[i]) ackID = networkSeqSendConf[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(ackID==0) return;
|
||||||
|
|
||||||
|
LightLock_Lock(&sendBufferLock);
|
||||||
|
|
||||||
|
//clear buffer of acknowledgt packets
|
||||||
|
while(networkSendBufferStartPos!=networkSendBufferEndPos) {
|
||||||
|
//find current seqid and size
|
||||||
|
u16 seqID = *((u16*) (networkSendBuffer+networkSendBufferStartPos));
|
||||||
|
u16 size = *((u16*) (networkSendBuffer+networkSendBufferStartPos+sizeof(u16)));
|
||||||
|
|
||||||
|
if(seqID<=ackID || (ackID<100 && seqID>65535-100)) {
|
||||||
|
|
||||||
|
size_t currentSize = sizeof(u16)*2 + size;
|
||||||
|
|
||||||
|
//adjust buffer "pointers"
|
||||||
|
networkSendBufferStartPos += currentSize;
|
||||||
|
if(networkSendBufferStartPos==networkSendBufferEndPos) {
|
||||||
|
networkSendBufferStartPos = 0;
|
||||||
|
networkSendBufferEndPos = 0;
|
||||||
|
networkSendBufferWrapPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//wrap
|
||||||
|
if(networkSendBufferStartPos==networkSendBufferWrapPos) {
|
||||||
|
networkSendBufferStartPos = 0;
|
||||||
|
networkSendBufferWrapPos = networkSendBufferEndPos;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LightLock_Unlock(&sendBufferLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sendAck(u16 target, u16 ack) {
|
||||||
|
Result ret = udsSendTo(target, NETWORK_CHANNEL, UDS_SENDFLAG_Default, &ack, sizeof(u16));
|
||||||
|
if(UDS_CHECK_SENDTO_FATALERROR(ret)) {
|
||||||
|
//TODO: what do?
|
||||||
|
return false;
|
||||||
|
} else if(R_FAILED(ret)) {
|
||||||
|
//TODO: what do?
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void networkInit() {
|
void networkInit() {
|
||||||
Result ret = udsInit(0x3000, NULL);
|
Result ret = udsInit(0x3000, NULL);
|
||||||
if(R_FAILED(ret)) {
|
if(R_FAILED(ret)) {
|
||||||
|
@ -30,20 +264,80 @@ void networkInit() {
|
||||||
scannedNetworks = NULL;
|
scannedNetworks = NULL;
|
||||||
isConnected = false;
|
isConnected = false;
|
||||||
isServer = false;
|
isServer = false;
|
||||||
|
networkConnectedMask = 0;
|
||||||
|
|
||||||
|
networkWriteBuffer = malloc(NETWORK_MAXDATASIZE);
|
||||||
|
if(networkWriteBuffer==NULL) {
|
||||||
|
networkExit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
networkBufferSize = 0x4000;
|
networkBufferSize = 0x4000;
|
||||||
networkBuffer = malloc(networkBufferSize);
|
networkBuffer = malloc(networkBufferSize);
|
||||||
|
if(networkBuffer==NULL) {
|
||||||
|
networkExit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
networkSendBufferStartPos = 0;
|
||||||
|
networkSendBufferEndPos = 0;
|
||||||
|
networkSendBufferWrapPos = 0;
|
||||||
|
networkSendBuffer = malloc(NETWORK_SENDBUFFERSIZE);
|
||||||
|
if(networkSendBuffer==NULL) {
|
||||||
|
networkExit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
networkSeqSendNext = 1;
|
||||||
|
for(int i=0; i<UDS_MAXNODES+1; i++) {
|
||||||
|
networkSeqSendConf[i] = 0;
|
||||||
|
networkSeqRecvLast[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
networkAckBuffer = malloc(sizeof(u16)+sizeof(u16)+sizeof(u16));
|
||||||
|
if(networkAckBuffer==NULL) {
|
||||||
|
networkExit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LightLock_Init(&sendBufferLock);
|
||||||
|
|
||||||
|
s32 prio = 0;
|
||||||
|
svcGetThreadPriority(&prio, CUR_THREAD_HANDLE);
|
||||||
|
|
||||||
|
//NOTE: It is important the networkThread is prioritized over the main thread (so substract 1) or else nothing will work
|
||||||
|
networkRunThread = true;
|
||||||
|
networkThread = threadCreate(networkThreadMain, NULL, NETWORK_STACKSIZE, prio-1, -2, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void networkExit() {
|
void networkExit() {
|
||||||
//TODO: Additionally to shutting down the service, clear any left over memory!
|
//Additionally to shutting down the service, clear any left over memory!
|
||||||
if(udsRunning) {
|
if(udsRunning) {
|
||||||
|
udsRunning = false;
|
||||||
|
|
||||||
|
if(networkRunThread) {
|
||||||
|
networkRunThread = false;
|
||||||
|
threadJoin(networkThread, U64_MAX);
|
||||||
|
threadFree(networkThread);
|
||||||
|
}
|
||||||
|
|
||||||
//cleanup any dynamically reserved memory
|
//cleanup any dynamically reserved memory
|
||||||
if(scannedNetworks!=NULL) free(scannedNetworks);
|
if(scannedNetworks!=NULL) free(scannedNetworks);
|
||||||
scannedNetworks = NULL;
|
scannedNetworks = NULL;
|
||||||
|
|
||||||
free(networkBuffer);
|
if(networkWriteBuffer!=NULL) free(networkWriteBuffer);
|
||||||
|
networkWriteBuffer = NULL;
|
||||||
|
|
||||||
|
if(networkBuffer!=NULL) free(networkBuffer);
|
||||||
|
networkBuffer = NULL;
|
||||||
|
|
||||||
|
if(networkSendBuffer!=NULL) free(networkSendBuffer);
|
||||||
|
networkSendBuffer = NULL;
|
||||||
|
|
||||||
|
if(networkAckBuffer!=NULL) free(networkAckBuffer);
|
||||||
|
networkAckBuffer = NULL;
|
||||||
|
|
||||||
networkDisconnect();
|
networkDisconnect();
|
||||||
|
|
||||||
udsExit();
|
udsExit();
|
||||||
|
@ -66,14 +360,22 @@ bool networkHost() {
|
||||||
if(R_FAILED(ret)) {
|
if(R_FAILED(ret)) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
if(udsWaitConnectionStatusEvent(false, false)) {}
|
||||||
|
udsGetConnectionStatus(&networkStatus);
|
||||||
|
udsSetNewConnectionsBlocked(false, true, false);
|
||||||
isConnected = true;
|
isConnected = true;
|
||||||
isServer = true;
|
isServer = true;
|
||||||
|
networkConnectedMask = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void networkHostStopConnections() {
|
||||||
|
udsSetNewConnectionsBlocked(true, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
void networkScan() {
|
void networkScan() {
|
||||||
if(udsRunning) {
|
if(udsRunning) {
|
||||||
//reset values from last scan
|
//reset values from last scan
|
||||||
|
@ -103,7 +405,7 @@ bool networkGetScanName(char *name, int pos) {
|
||||||
if(udsRunning) {
|
if(udsRunning) {
|
||||||
if(pos<0 || pos>=scannedNetworksCount) return false;
|
if(pos<0 || pos>=scannedNetworksCount) return false;
|
||||||
|
|
||||||
Result ret = udsGetNodeInfoUsername(&scannedNetworks[pos].nodes[0], name);
|
Result ret = udsGetNodeInfoUsername(&(scannedNetworks[pos].nodes[0]), name);
|
||||||
if(R_FAILED(ret)) {
|
if(R_FAILED(ret)) {
|
||||||
//TODO: what do?
|
//TODO: what do?
|
||||||
return false;
|
return false;
|
||||||
|
@ -121,8 +423,11 @@ bool networkConnect(int pos) {
|
||||||
if(R_FAILED(ret)) {
|
if(R_FAILED(ret)) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
if(udsWaitConnectionStatusEvent(false, false)) {}
|
||||||
|
udsGetConnectionStatus(&networkStatus);
|
||||||
isConnected = true;
|
isConnected = true;
|
||||||
isServer = false;
|
isServer = false;
|
||||||
|
networkConnectedMask = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,73 +435,168 @@ bool networkConnect(int pos) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void networkDisconnect() {
|
void networkDisconnect() {
|
||||||
//TODO: For clients this just means disconnect, for the server it means destroy the network
|
//For clients this just means disconnect, for the server it means destroy the network
|
||||||
if(udsRunning && isConnected) {
|
if(udsRunning && isConnected) {
|
||||||
//TODO
|
isConnected = false;
|
||||||
|
|
||||||
|
LightLock_Lock(&sendBufferLock);
|
||||||
|
//reset send buffer
|
||||||
|
networkSendBufferStartPos = 0;
|
||||||
|
networkSendBufferEndPos = 0;
|
||||||
|
networkSendBufferWrapPos = 0;
|
||||||
|
|
||||||
|
//reset ack status
|
||||||
|
networkSeqSendNext = 1;
|
||||||
|
for(int i=0; i<UDS_MAXNODES+1; i++) {
|
||||||
|
networkSeqSendConf[i] = 0;
|
||||||
|
networkSeqRecvLast[i] = 0;
|
||||||
|
}
|
||||||
|
LightLock_Unlock(&sendBufferLock);
|
||||||
|
|
||||||
|
//With new changes citra now crashes HOST with "cannot be a router if we are not a host" when exiting game with more than 2 people
|
||||||
|
svcSleepThread(220000 * 1000); //HACK: prevent citra crash (>20*networkthreadsleep) (wait unti no more stuff gets send)
|
||||||
|
|
||||||
|
//TODO
|
||||||
if(isServer) {
|
if(isServer) {
|
||||||
udsDisconnectNetwork();
|
|
||||||
} else {
|
|
||||||
//TODO: Clients need to cleanup too, how can I tell they got disconnected
|
//TODO: Clients need to cleanup too, how can I tell they got disconnected
|
||||||
udsDestroyNetwork();
|
udsDestroyNetwork();
|
||||||
|
} else {
|
||||||
|
udsDisconnectNetwork();
|
||||||
}
|
}
|
||||||
udsUnbind(&networkBindCtx);
|
udsUnbind(&networkBindCtx);
|
||||||
|
|
||||||
isConnected = false;
|
isServer = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void networkStart() {
|
||||||
|
//TODO: This sends the node_bitmask from server to everyone else, because it is uncorrect on some clients?
|
||||||
|
if(udsRunning && isConnected && isServer) {
|
||||||
|
void *buffer = networkWriteBuffer;
|
||||||
|
|
||||||
|
*((u16*) buffer) = networkStatus.node_bitmask;
|
||||||
|
networkConnectedMask = networkStatus.node_bitmask;
|
||||||
|
|
||||||
|
networkSend(networkWriteBuffer, sizeof(u16));
|
||||||
|
networkSendWaitFlush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool networkConnected() {
|
bool networkConnected() {
|
||||||
return isConnected;
|
return isConnected;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool networkIsServer() {
|
int networkGetNodeCount() {
|
||||||
return isServer;
|
if(udsRunning && isConnected) {
|
||||||
|
return networkStatus.total_nodes;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u16 networkGetLocalNodeID() {
|
||||||
|
if(udsRunning && isConnected) {
|
||||||
void networkSend(networkPacket *packet, size_t size) {
|
return networkStatus.cur_NetworkNodeID;
|
||||||
if(udsRunning && isConnected) {
|
} else {
|
||||||
//Server broadcasts to all clients but clients only send info to server
|
return 0;
|
||||||
if(isServer) {
|
}
|
||||||
networkSendTo(packet, size, UDS_BROADCAST_NETWORKNODEID);
|
|
||||||
} else {
|
|
||||||
networkSendTo(packet, size, UDS_HOST_NETWORKNODEID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: I somehow need to implement a relieable protocol on top of uds
|
bool networkIsNodeConnected(u16 id) {
|
||||||
void networkSendTo(networkPacket *packet, size_t size, u16 reciever) {
|
if(udsRunning && isConnected) {
|
||||||
if(udsRunning && isConnected) {
|
return networkStatus.node_bitmask & (1 << (id-1));
|
||||||
|
} else {
|
||||||
Result ret = udsSendTo(reciever, NETWORK_CHANNEL, UDS_SENDFLAG_Default, packet, size);
|
return false;
|
||||||
if(UDS_CHECK_SENDTO_FATALERROR(ret)) {
|
}
|
||||||
//TODO: what do?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void networkRecieve() {
|
bool networkGetNodeName(u16 id, char *name) {
|
||||||
//TODO: Should recieve actually handle all the packets or just return them?
|
if(udsRunning && isConnected && networkIsNodeConnected(id)) {
|
||||||
if(udsRunning && isConnected) {
|
udsNodeInfo nodeInfo;
|
||||||
size_t actualSize = 0;
|
udsGetNodeInformation(id, &nodeInfo);
|
||||||
u16 sourceNetworkNodeID;
|
|
||||||
|
|
||||||
memset(networkBuffer, 0, networkBufferSize);
|
Result ret = udsGetNodeInfoUsername(&nodeInfo, name);
|
||||||
|
|
||||||
Result ret = udsPullPacket(&networkBindCtx, networkBuffer, networkBufferSize, &actualSize, &sourceNetworkNodeID);
|
|
||||||
if(R_FAILED(ret)) {
|
if(R_FAILED(ret)) {
|
||||||
//TODO: what do?
|
//TODO: what do?
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
//actualSize will be 0 if no packet is available
|
|
||||||
if(actualSize) {
|
|
||||||
networkPacket *packet = (networkPacket*) networkBuffer;
|
|
||||||
|
|
||||||
processPacket(packet, packet->analyze.type, sourceNetworkNodeID);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int fitInSendBuffer(size_t size) {
|
||||||
|
//add "header" length
|
||||||
|
size += sizeof(u16)*2;
|
||||||
|
|
||||||
|
//we have no wrap currently
|
||||||
|
if(networkSendBufferStartPos<=networkSendBufferEndPos) {
|
||||||
|
//and can fit without wrap
|
||||||
|
if(networkSendBufferEndPos+size<NETWORK_SENDBUFFERSIZE) {
|
||||||
|
networkSendBufferEndPos += size;
|
||||||
|
networkSendBufferWrapPos = networkSendBufferEndPos;
|
||||||
|
|
||||||
|
return networkSendBufferEndPos-size;
|
||||||
|
//we need to wrap
|
||||||
|
} else {
|
||||||
|
if(size<networkSendBufferStartPos) {
|
||||||
|
networkSendBufferEndPos = size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//we have wrap currently
|
||||||
|
} else {
|
||||||
|
int available = networkSendBufferStartPos - networkSendBufferEndPos - 1;
|
||||||
|
if(available>size) {
|
||||||
|
networkSendBufferEndPos += size;
|
||||||
|
|
||||||
|
return networkSendBufferEndPos-size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void networkSend(void *packet, size_t size) {
|
||||||
|
//search for fit in buffer (and BLOCK until free space is found)
|
||||||
|
LightLock_Lock(&sendBufferLock);
|
||||||
|
int pos = fitInSendBuffer(size);
|
||||||
|
while(pos==-1) {
|
||||||
|
LightLock_Unlock(&sendBufferLock);
|
||||||
|
svcSleepThread(4500 * 1000); //TODO: Set meaningfull value
|
||||||
|
LightLock_Lock(&sendBufferLock);
|
||||||
|
|
||||||
|
pos = fitInSendBuffer(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
//fit found -> space is allready "reserved" -> write packet to buffer
|
||||||
|
void *writePointer = networkSendBuffer + pos;
|
||||||
|
|
||||||
|
//write seq number
|
||||||
|
*((u16*) writePointer) = networkSeqSendNext;
|
||||||
|
networkSeqSendNext++;
|
||||||
|
if(networkSeqSendNext==0) {
|
||||||
|
networkSeqSendNext = 1;
|
||||||
|
}
|
||||||
|
writePointer += sizeof(u16);
|
||||||
|
|
||||||
|
//write size
|
||||||
|
*((u16*) writePointer) = (u16) size;
|
||||||
|
writePointer += sizeof(u16);
|
||||||
|
|
||||||
|
//write data
|
||||||
|
memcpy(writePointer, packet, size);
|
||||||
|
writePointer += size;
|
||||||
|
|
||||||
|
LightLock_Unlock(&sendBufferLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void networkSendWaitFlush() {
|
||||||
|
while(networkSendBufferStartPos!=networkSendBufferEndPos) {
|
||||||
|
svcSleepThread(4500 * 1000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,45 +3,19 @@
|
||||||
#include <3ds.h>
|
#include <3ds.h>
|
||||||
|
|
||||||
#define NETWORK_WLANCOMMID 0x11441850
|
#define NETWORK_WLANCOMMID 0x11441850
|
||||||
#define NETWORK_PASSPHRASE "Minicraft3DS localplay passphrase"
|
#define NETWORK_PASSPHRASE "minicraft3dsLP"
|
||||||
#define NETWORK_CHANNEL 1
|
#define NETWORK_CHANNEL 1
|
||||||
|
|
||||||
#define NETWORK_RECVBUFSIZE UDS_DEFAULT_RECVBUFSIZE
|
#define NETWORK_RECVBUFSIZE UDS_DEFAULT_RECVBUFSIZE
|
||||||
|
|
||||||
#define NETWORK_MAXPLAYERS UDS_MAXNODES
|
#define NETWORK_MAXDATASIZE 1024
|
||||||
|
#define NETWORK_SENDBUFFERSIZE ((NETWORK_MAXDATASIZE+256)*10)
|
||||||
|
|
||||||
//packet type ids
|
#define NETWORK_STACKSIZE (8*1024)
|
||||||
#define PACKET_REQUEST_MAPDATA 1
|
|
||||||
#define PACKET_MAPDATA 2
|
|
||||||
|
|
||||||
//TODO: Every other packet struct should start with a u8 type to match this
|
#define NETWORK_MAXPLAYERS 8
|
||||||
typedef struct {
|
|
||||||
u8 type;
|
|
||||||
} packetAnalyze;
|
|
||||||
|
|
||||||
typedef struct {
|
void *networkWriteBuffer;
|
||||||
u8 type;
|
|
||||||
|
|
||||||
u8 level;
|
|
||||||
} packetRequestMapData;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
u8 type;
|
|
||||||
|
|
||||||
u8 level;
|
|
||||||
u8 offset; //-> data is at offset*128 to offset*128+127
|
|
||||||
|
|
||||||
u8 map[128];
|
|
||||||
u8 data[128];
|
|
||||||
} packetMapData;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
union {
|
|
||||||
packetAnalyze analyze;
|
|
||||||
packetRequestMapData requestMapData;
|
|
||||||
packetMapData mapData;
|
|
||||||
};
|
|
||||||
} networkPacket;
|
|
||||||
|
|
||||||
void networkInit();
|
void networkInit();
|
||||||
void networkExit();
|
void networkExit();
|
||||||
|
@ -49,15 +23,22 @@ void networkExit();
|
||||||
bool networkAvailable();
|
bool networkAvailable();
|
||||||
|
|
||||||
bool networkHost();
|
bool networkHost();
|
||||||
|
void networkHostStopConnections();
|
||||||
void networkScan();
|
void networkScan();
|
||||||
int networkGetScanCount();
|
int networkGetScanCount();
|
||||||
bool networkGetScanName(char *name, int pos); //TODO: Name should be long enough to handle all allowed names (char[256])
|
bool networkGetScanName(char *name, int pos);
|
||||||
bool networkConnect(int pos);
|
bool networkConnect(int pos);
|
||||||
void networkDisconnect();
|
void networkDisconnect();
|
||||||
|
|
||||||
bool networkConnected();
|
void networkStart();
|
||||||
bool networkIsServer();
|
|
||||||
|
|
||||||
void networkSend(networkPacket *packet, size_t size); //TODO: Should this be a pointer? Calling function needs to cleanup itself
|
void networkUpdateStatus();
|
||||||
void networkSendTo(networkPacket *packet, size_t size, u16 reciever); //TODO: Should this be a pointer? Calling function needs to cleanup itself
|
bool networkConnected();
|
||||||
void networkRecieve(); //TODO: Should recieve actually handle all the packets or just return them?
|
|
||||||
|
int networkGetNodeCount();
|
||||||
|
u16 networkGetLocalNodeID();
|
||||||
|
bool networkIsNodeConnected(u16 id);
|
||||||
|
bool networkGetNodeName(u16 id, char *name);
|
||||||
|
|
||||||
|
void networkSend(void *packet, size_t size);
|
||||||
|
void networkSendWaitFlush();
|
||||||
|
|
|
@ -1,48 +1,363 @@
|
||||||
#include "PacketHandler.h"
|
#include "PacketHandler.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "Synchronizer.h"
|
||||||
|
|
||||||
#include "Globals.h"
|
FILE *recvFile;
|
||||||
|
size_t recvFileSize;
|
||||||
|
|
||||||
void processPacket(networkPacket *packet, u8 type, u16 sender) {
|
|
||||||
//TODO: Differenciate the packets and process them
|
|
||||||
if(networkIsServer()) {
|
|
||||||
if(type==PACKET_REQUEST_MAPDATA) {
|
|
||||||
u8 level = packet->requestMapData.level;
|
|
||||||
|
|
||||||
if(level>=0 && level<=5) {
|
|
||||||
//send back tile data
|
|
||||||
for(int y=0; y<128; y++) {
|
|
||||||
networkPacket packet = {
|
|
||||||
.mapData = {
|
|
||||||
.type = PACKET_MAPDATA,
|
|
||||||
.level = level,
|
|
||||||
.offset = y
|
|
||||||
}
|
|
||||||
};
|
|
||||||
for(int x=0; x<128; x++) {
|
|
||||||
packet.mapData.map[x] = map[level][x+y*128];
|
|
||||||
packet.mapData.data[x] = data[level][x+y*128];
|
|
||||||
}
|
|
||||||
networkSendTo(&packet, sizeof(packetMapData), sender);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//TODO: Unknown packet - how to handle?
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(type==PACKET_MAPDATA) {
|
|
||||||
u8 level = packet->mapData.level;
|
|
||||||
|
|
||||||
if(level>=0 && level<=5) {
|
|
||||||
//recieve tile data
|
void * writeBool(void *buffer, size_t *size, bool value) {
|
||||||
//TODO: This should really check whether the values are in valid range
|
*((bool*) buffer) = value;
|
||||||
int y = packet->mapData.offset;
|
*(size) += sizeof(bool);
|
||||||
for(int x=0; x<128; x++) {
|
return buffer + sizeof(bool);
|
||||||
map[level][x+y*128] = packet->mapData.map[x];
|
}
|
||||||
data[level][x+y*128] = packet->mapData.data[x];
|
|
||||||
}
|
void * writeU8(void *buffer, size_t *size, u8 value) {
|
||||||
}
|
*((u8*) buffer) = value;
|
||||||
} else {
|
*(size) += sizeof(u8);
|
||||||
//TODO: Unknown packet - how to handle?
|
return buffer + sizeof(u8);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
void * writeU16(void *buffer, size_t *size, u16 value) {
|
||||||
|
*((u16*) buffer) = value;
|
||||||
|
*(size) += sizeof(u16);
|
||||||
|
return buffer + sizeof(u16);
|
||||||
|
}
|
||||||
|
|
||||||
|
void * writeU32(void *buffer, size_t *size, u32 value) {
|
||||||
|
*((u32*) buffer) = value;
|
||||||
|
*(size) += sizeof(u32);
|
||||||
|
return buffer + sizeof(u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
void * writeSizeT(void *buffer, size_t *size, size_t value) {
|
||||||
|
*((size_t*) buffer) = value;
|
||||||
|
*(size) += sizeof(size_t);
|
||||||
|
return buffer + sizeof(size_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void * readBool(void *buffer, size_t *size, bool *value) {
|
||||||
|
*value = *((bool*) buffer);
|
||||||
|
*(size) -= sizeof(bool);
|
||||||
|
return buffer + sizeof(bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
void * readU8(void *buffer, size_t *size, u8 *value) {
|
||||||
|
*value = *((u8*) buffer);
|
||||||
|
*(size) -= sizeof(u8);
|
||||||
|
return buffer + sizeof(u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void * readU16(void *buffer, size_t *size, u16 *value) {
|
||||||
|
*value = *((u16*) buffer);
|
||||||
|
*(size) -= sizeof(u16);
|
||||||
|
return buffer + sizeof(u16);
|
||||||
|
}
|
||||||
|
|
||||||
|
void * readU32(void *buffer, size_t *size, u32 *value) {
|
||||||
|
*value = *((u32*) buffer);
|
||||||
|
*(size) -= sizeof(u32);
|
||||||
|
return buffer + sizeof(u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
void * readSizeT(void *buffer, size_t *size, size_t *value) {
|
||||||
|
*value = *((size_t*) buffer);
|
||||||
|
*(size) -= sizeof(size_t);
|
||||||
|
return buffer + sizeof(size_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void processPacket(void *packet, size_t size) {
|
||||||
|
//Differenciate the packets and process them
|
||||||
|
switch(packetGetID(packet)) {
|
||||||
|
case PACKET_START: {
|
||||||
|
void *buffer = packetGetDataStart(packet);
|
||||||
|
size = packetGetDataSize(size);
|
||||||
|
|
||||||
|
//find player index based on network node id
|
||||||
|
//and set player uuid in synchronizer
|
||||||
|
u32 seed;
|
||||||
|
u32 playerCount = 1;
|
||||||
|
int playerIndex = 0;
|
||||||
|
|
||||||
|
buffer = readU32(buffer, &size, &seed);
|
||||||
|
buffer = readU32(buffer, &size, &playerCount);
|
||||||
|
for(int i=0; i<playerCount; i++) {
|
||||||
|
u16 nodeID;
|
||||||
|
|
||||||
|
buffer = readU16(buffer, &size, &nodeID);
|
||||||
|
|
||||||
|
if(nodeID==networkGetLocalNodeID()) {
|
||||||
|
playerIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//cleanup transfer tmp file
|
||||||
|
FILE *file = fopen("tmpTransfer.bin", "wb");
|
||||||
|
if(file!=NULL) {
|
||||||
|
fclose(file);
|
||||||
|
remove("tmpTransfer.bin");
|
||||||
|
}
|
||||||
|
|
||||||
|
//init synchronizer
|
||||||
|
synchronizerInit(seed, playerCount, playerIndex);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PACKET_START_FILEHEADER: {
|
||||||
|
void *data = packetGetDataStart(packet);
|
||||||
|
|
||||||
|
u8 type;
|
||||||
|
u8 id;
|
||||||
|
size_t fsize;
|
||||||
|
|
||||||
|
data = readU8(data, &size, &type);
|
||||||
|
data = readU8(data, &size, &id);
|
||||||
|
data = readSizeT(data, &size, &fsize);
|
||||||
|
|
||||||
|
recvFile = fopen("tmpTransfer.bin", "wb");
|
||||||
|
recvFileSize = fsize;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PACKET_START_FILEDATA: {
|
||||||
|
void *data = packetGetDataStart(packet);
|
||||||
|
size_t dsize = packetGetDataSize(size);
|
||||||
|
|
||||||
|
size_t toread = dsize;
|
||||||
|
|
||||||
|
fwrite(data, 1, toread, recvFile);
|
||||||
|
|
||||||
|
recvFileSize -= toread;
|
||||||
|
if(recvFileSize<=0) {
|
||||||
|
fclose(recvFile);
|
||||||
|
recvFile = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PACKET_START_REQUEST_IDS: {
|
||||||
|
synchronizerSendUID();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PACKET_START_ID: {
|
||||||
|
u8 playerID = packetGetSender(packet);
|
||||||
|
u32 uid;
|
||||||
|
|
||||||
|
void *data = packetGetDataStart(packet);
|
||||||
|
size_t dsize = packetGetDataSize(size);
|
||||||
|
|
||||||
|
data = readU32(data, &dsize, &uid);
|
||||||
|
|
||||||
|
synchronizerSetPlayerUID(playerID, uid);
|
||||||
|
synchronizerSendIfReady();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PACKET_START_READY: {
|
||||||
|
synchronizerSetPlayerReady(packetGetSender(packet));
|
||||||
|
if(playerLocalID==0) {
|
||||||
|
if(synchronizerAllReady()) {
|
||||||
|
sendStartSyncPacket();
|
||||||
|
synchronizerStart(); //server needs to call this here, all others do when they recieve the packet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PACKET_TURN_START: {
|
||||||
|
synchronizerStart();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PACKET_TURN_INPUT: {
|
||||||
|
synchronizerOnInputPacket(packetGetSender(packet), packetGetTurn(packet), packetGetDataStart(packet), packetGetDataSize(size));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 packetGetID(void *packet) {
|
||||||
|
return *((u8*) packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 packetGetSender(void *packet) {
|
||||||
|
return *((u8*) packet+sizeof(u8));
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 packetGetTurn(void *packet) {
|
||||||
|
return *((u32*) (packet+sizeof(u8)+sizeof(u8)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void * packetGetDataStart(void *packet) {
|
||||||
|
return packet+sizeof(u8)+sizeof(u8)+sizeof(u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t packetGetDataSize(size_t size) {
|
||||||
|
return size-sizeof(u8)-sizeof(u8)-sizeof(u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
size_t writeStartPacket(void *buffer, u32 seed) {
|
||||||
|
size_t size = 0;
|
||||||
|
buffer = writeU8(buffer, &size, PACKET_START);
|
||||||
|
buffer = writeU8(buffer, &size, 0);
|
||||||
|
buffer = writeU32(buffer, &size, 0);
|
||||||
|
|
||||||
|
buffer = writeU32(buffer, &size, seed);
|
||||||
|
buffer = writeU32(buffer, &size, (u32)networkGetNodeCount());
|
||||||
|
for(int i=1; i<=UDS_MAXNODES; i++) {
|
||||||
|
if(networkIsNodeConnected(i)) {
|
||||||
|
buffer = writeU16(buffer, &size, (u16)i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t writeStartRequestPacket(void *buffer) {
|
||||||
|
size_t size = 0;
|
||||||
|
buffer = writeU8(buffer, &size, PACKET_START_REQUEST_IDS);
|
||||||
|
buffer = writeU8(buffer, &size, 0);
|
||||||
|
buffer = writeU32(buffer, &size, 0);
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t writeInputPacket(void *buffer, Inputs *inputs, u8 playerID, u32 turnNumber) {
|
||||||
|
size_t size = 0;
|
||||||
|
buffer = writeU8(buffer, &size, PACKET_TURN_INPUT);
|
||||||
|
buffer = writeU8(buffer, &size, playerID);
|
||||||
|
buffer = writeU32(buffer, &size, turnNumber);
|
||||||
|
|
||||||
|
buffer = writeU16(buffer, &size, inputs->k_touch.px);
|
||||||
|
buffer = writeU16(buffer, &size, inputs->k_touch.py);
|
||||||
|
|
||||||
|
buffer = writeBool(buffer, &size, inputs->k_up.down); buffer = writeBool(buffer, &size, inputs->k_up.clicked);
|
||||||
|
buffer = writeBool(buffer, &size, inputs->k_down.down); buffer = writeBool(buffer, &size, inputs->k_down.clicked);
|
||||||
|
buffer = writeBool(buffer, &size, inputs->k_left.down); buffer = writeBool(buffer, &size, inputs->k_left.clicked);
|
||||||
|
buffer = writeBool(buffer, &size, inputs->k_right.down); buffer = writeBool(buffer, &size, inputs->k_right.clicked);
|
||||||
|
buffer = writeBool(buffer, &size, inputs->k_attack.down); buffer = writeBool(buffer, &size, inputs->k_attack.clicked);
|
||||||
|
buffer = writeBool(buffer, &size, inputs->k_menu.down); buffer = writeBool(buffer, &size, inputs->k_menu.clicked);
|
||||||
|
buffer = writeBool(buffer, &size, inputs->k_pause.down); buffer = writeBool(buffer, &size, inputs->k_pause.clicked);
|
||||||
|
buffer = writeBool(buffer, &size, inputs->k_accept.down); buffer = writeBool(buffer, &size, inputs->k_accept.clicked);
|
||||||
|
buffer = writeBool(buffer, &size, inputs->k_decline.down); buffer = writeBool(buffer, &size, inputs->k_decline.clicked);
|
||||||
|
buffer = writeBool(buffer, &size, inputs->k_delete.down); buffer = writeBool(buffer, &size, inputs->k_delete.clicked);
|
||||||
|
buffer = writeBool(buffer, &size, inputs->k_menuNext.down); buffer = writeBool(buffer, &size, inputs->k_menuNext.clicked);
|
||||||
|
buffer = writeBool(buffer, &size, inputs->k_menuPrev.down); buffer = writeBool(buffer, &size, inputs->k_menuPrev.clicked);
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool readInputPacketData(void *buffer, size_t size, Inputs *inputs) {
|
||||||
|
buffer = readU16(buffer, &size, &(inputs->k_touch.px));
|
||||||
|
if(size<=0) return false;
|
||||||
|
buffer = readU16(buffer, &size, &(inputs->k_touch.py));
|
||||||
|
if(size<=0) return false;
|
||||||
|
|
||||||
|
buffer = readBool(buffer, &size, &(inputs->k_up.down)); buffer = readBool(buffer, &size, &(inputs->k_up.clicked));
|
||||||
|
if(size<=0) return false;
|
||||||
|
buffer = readBool(buffer, &size, &(inputs->k_down.down)); buffer = readBool(buffer, &size, &(inputs->k_down.clicked));
|
||||||
|
if(size<=0) return false;
|
||||||
|
buffer = readBool(buffer, &size, &(inputs->k_left.down)); buffer = readBool(buffer, &size, &(inputs->k_left.clicked));
|
||||||
|
if(size<=0) return false;
|
||||||
|
buffer = readBool(buffer, &size, &(inputs->k_right.down)); buffer = readBool(buffer, &size, &(inputs->k_right.clicked));
|
||||||
|
if(size<=0) return false;
|
||||||
|
buffer = readBool(buffer, &size, &(inputs->k_attack.down)); buffer = readBool(buffer, &size, &(inputs->k_attack.clicked));
|
||||||
|
if(size<=0) return false;
|
||||||
|
buffer = readBool(buffer, &size, &(inputs->k_menu.down)); buffer = readBool(buffer, &size, &(inputs->k_menu.clicked));
|
||||||
|
if(size<=0) return false;
|
||||||
|
buffer = readBool(buffer, &size, &(inputs->k_pause.down)); buffer = readBool(buffer, &size, &(inputs->k_pause.clicked));
|
||||||
|
if(size<=0) return false;
|
||||||
|
buffer = readBool(buffer, &size, &(inputs->k_accept.down)); buffer = readBool(buffer, &size, &(inputs->k_accept.clicked));
|
||||||
|
if(size<=0) return false;
|
||||||
|
buffer = readBool(buffer, &size, &(inputs->k_decline.down)); buffer = readBool(buffer, &size, &(inputs->k_decline.clicked));
|
||||||
|
if(size<=0) return false;
|
||||||
|
buffer = readBool(buffer, &size, &(inputs->k_delete.down)); buffer = readBool(buffer, &size, &(inputs->k_delete.clicked));
|
||||||
|
if(size<=0) return false;
|
||||||
|
buffer = readBool(buffer, &size, &(inputs->k_menuNext.down)); buffer = readBool(buffer, &size, &(inputs->k_menuNext.clicked));
|
||||||
|
if(size<=0) return false;
|
||||||
|
buffer = readBool(buffer, &size, &(inputs->k_menuPrev.down)); buffer = readBool(buffer, &size, &(inputs->k_menuPrev.clicked));
|
||||||
|
|
||||||
|
return size==0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendFile(FILE *file, u8 fileType, u8 id) {
|
||||||
|
fseek(file, 0, SEEK_END); // seek to end of file
|
||||||
|
size_t fsize = ftell(file); // get current file pointer
|
||||||
|
fseek(file, 0, SEEK_SET); // seek back to beginning of file
|
||||||
|
|
||||||
|
//send file header
|
||||||
|
void *buffer = networkWriteBuffer;
|
||||||
|
size_t size = 0;
|
||||||
|
buffer = writeU8(buffer, &size, PACKET_START_FILEHEADER);
|
||||||
|
buffer = writeU8(buffer, &size, 0);
|
||||||
|
buffer = writeU32(buffer, &size, 0);
|
||||||
|
buffer = writeU8(buffer, &size, fileType);
|
||||||
|
buffer = writeU8(buffer, &size, id);
|
||||||
|
buffer = writeSizeT(buffer, &size, fsize);
|
||||||
|
networkSend(networkWriteBuffer, size);
|
||||||
|
|
||||||
|
//send file data
|
||||||
|
while(fsize>0) {
|
||||||
|
buffer = networkWriteBuffer;
|
||||||
|
size = 0;
|
||||||
|
buffer = writeU8(buffer, &size, PACKET_START_FILEDATA);
|
||||||
|
buffer = writeU8(buffer, &size, 0);
|
||||||
|
buffer = writeU32(buffer, &size, 0);
|
||||||
|
|
||||||
|
//read file data
|
||||||
|
size_t towrite = NETWORK_MAXDATASIZE - size;
|
||||||
|
if(towrite>fsize) towrite = fsize;
|
||||||
|
|
||||||
|
fread(buffer, 1, towrite, file);
|
||||||
|
|
||||||
|
size += towrite;
|
||||||
|
fsize -= towrite;
|
||||||
|
|
||||||
|
//send file data
|
||||||
|
networkSend(networkWriteBuffer, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendIDPacket(u8 playerID, u32 uid) {
|
||||||
|
void *buffer = networkWriteBuffer;
|
||||||
|
size_t size = 0;
|
||||||
|
|
||||||
|
buffer = writeU8(buffer, &size, PACKET_START_ID);
|
||||||
|
buffer = writeU8(buffer, &size, playerID);
|
||||||
|
buffer = writeU32(buffer, &size, 0);
|
||||||
|
|
||||||
|
buffer = writeU32(buffer, &size, uid);
|
||||||
|
|
||||||
|
networkSend(networkWriteBuffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendStartReadyPacket(u8 playerID) {
|
||||||
|
void *buffer = networkWriteBuffer;
|
||||||
|
size_t size = 0;
|
||||||
|
|
||||||
|
buffer = writeU8(buffer, &size, PACKET_START_READY);
|
||||||
|
buffer = writeU8(buffer, &size, playerID);
|
||||||
|
buffer = writeU32(buffer, &size, 0);
|
||||||
|
|
||||||
|
networkSend(networkWriteBuffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendStartSyncPacket() {
|
||||||
|
void *buffer = networkWriteBuffer;
|
||||||
|
size_t size = 0;
|
||||||
|
|
||||||
|
buffer = writeU8(buffer, &size, PACKET_TURN_START);
|
||||||
|
buffer = writeU8(buffer, &size, 0);
|
||||||
|
buffer = writeU32(buffer, &size, 0);
|
||||||
|
|
||||||
|
networkSend(networkWriteBuffer, size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,34 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
#include "Network.h"
|
#include "Network.h"
|
||||||
|
#include "Player.h"
|
||||||
|
|
||||||
void processPacket(networkPacket *packet, u8 type, u16 sender);
|
#define PACKET_START 0
|
||||||
|
#define PACKET_START_FILEHEADER 1
|
||||||
|
#define PACKET_START_FILEDATA 2
|
||||||
|
#define PACKET_START_REQUEST_IDS 3
|
||||||
|
#define PACKET_START_ID 4
|
||||||
|
#define PACKET_START_READY 5
|
||||||
|
|
||||||
|
#define PACKET_TURN_START 10
|
||||||
|
#define PACKET_TURN_INPUT 11
|
||||||
|
|
||||||
|
void processPacket(void *packet, size_t size);
|
||||||
|
|
||||||
|
u8 packetGetID(void *packet);
|
||||||
|
u8 packetGetSender(void *packet);
|
||||||
|
u32 packetGetTurn(void *packet);
|
||||||
|
void * packetGetDataStart(void *packet);
|
||||||
|
size_t packetGetDataSize(size_t size);
|
||||||
|
|
||||||
|
size_t writeStartPacket(void *buffer, u32 seed);
|
||||||
|
size_t writeStartRequestPacket(void *buffer);
|
||||||
|
|
||||||
|
size_t writeInputPacket(void *buffer, Inputs *inputs, u8 playerID, u32 turnNumber);
|
||||||
|
bool readInputPacketData(void *buffer, size_t size, Inputs *inputs);
|
||||||
|
|
||||||
|
void sendFile(FILE *file, u8 fileType, u8 id);
|
||||||
|
void sendIDPacket(u8 playerID, u32 uid);
|
||||||
|
void sendStartReadyPacket(u8 playerID);
|
||||||
|
void sendStartSyncPacket();
|
||||||
|
|
546
source/Player.c
Normal file
546
source/Player.c
Normal file
|
@ -0,0 +1,546 @@
|
||||||
|
#include "Player.h"
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include "Globals.h"
|
||||||
|
|
||||||
|
void potionEffect(int type) {
|
||||||
|
if(type == 1) {
|
||||||
|
UnderStrengthEffect = true;
|
||||||
|
}
|
||||||
|
if(type == 2) {
|
||||||
|
UnderSpeedEffect = true;
|
||||||
|
}
|
||||||
|
if (type == 3) {
|
||||||
|
regening = true;
|
||||||
|
}
|
||||||
|
if (type == 4) {
|
||||||
|
UnderSwimBreathEffect = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void initPlayers() {
|
||||||
|
for(int i=0; i<MAX_PLAYERS; i++) {
|
||||||
|
initPlayer(players+i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void freePlayers() {
|
||||||
|
for(int i=0; i<MAX_PLAYERS; i++) {
|
||||||
|
freePlayer(players+i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void playerInitMiniMapData(u8 *minimapData) {
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < 128 * 128; ++i) {
|
||||||
|
minimapData[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void playerInitEntity(PlayerData *pd) {
|
||||||
|
pd->entity.type = ENTITY_PLAYER;
|
||||||
|
pd->entity.level = 1;
|
||||||
|
pd->entity.xr = 4;
|
||||||
|
pd->entity.yr = 3;
|
||||||
|
pd->entity.canSwim = true;
|
||||||
|
pd->entity.p.ax = 0;
|
||||||
|
pd->entity.p.ay = 0;
|
||||||
|
pd->entity.p.health = 10;
|
||||||
|
pd->entity.p.stamina = 10;
|
||||||
|
pd->entity.p.walkDist = 0;
|
||||||
|
pd->entity.p.attackTimer = 0;
|
||||||
|
pd->entity.p.dir = 0;
|
||||||
|
pd->entity.p.isDead = false;
|
||||||
|
pd->entity.p.hasWon = false;
|
||||||
|
|
||||||
|
pd->entity.p.data = pd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void playerInitInventory(PlayerData *pd) {
|
||||||
|
//reset inventory
|
||||||
|
pd->inventory.lastSlot = 0;
|
||||||
|
pd->activeItem = &noItem;
|
||||||
|
|
||||||
|
addItemToInventory(newItem(ITEM_WORKBENCH,0), &(pd->inventory));
|
||||||
|
addItemToInventory(newItem(ITEM_POWGLOVE,0), &(pd->inventory));
|
||||||
|
|
||||||
|
if(TESTGODMODE) {
|
||||||
|
addItemToInventory(newItem(ITEM_GOLD_APPLE,1), &(pd->inventory));
|
||||||
|
addItemToInventory(newItem(ITEM_STRENGTH_POTION,1), &(pd->inventory));
|
||||||
|
addItemToInventory(newItem(ITEM_REGEN_POTION,1), &(pd->inventory));
|
||||||
|
addItemToInventory(newItem(ITEM_SWIM_BREATH_POTION,1), &(pd->inventory));
|
||||||
|
addItemToInventory(newItem(ITEM_SPEED_POTION,1), &(pd->inventory));
|
||||||
|
addItemToInventory(newItem(ITEM_POTION_MAKER,0), &(pd->inventory));
|
||||||
|
addItemToInventory(newItem(TOOL_SHOVEL,1), &(pd->inventory));
|
||||||
|
addItemToInventory(newItem(TOOL_HOE,4), &(pd->inventory));
|
||||||
|
addItemToInventory(newItem(TOOL_SWORD,4), &(pd->inventory));
|
||||||
|
addItemToInventory(newItem(TOOL_PICKAXE,4), &(pd->inventory));
|
||||||
|
addItemToInventory(newItem(TOOL_AXE,4), &(pd->inventory));
|
||||||
|
|
||||||
|
addItemToInventory(newItem(ITEM_ANVIL,0), &(pd->inventory));
|
||||||
|
addItemToInventory(newItem(ITEM_CHEST,0), &(pd->inventory));
|
||||||
|
addItemToInventory(newItem(ITEM_OVEN,0), &(pd->inventory));
|
||||||
|
addItemToInventory(newItem(ITEM_FURNACE,0), &(pd->inventory));
|
||||||
|
addItemToInventory(newItem(ITEM_LANTERN,0), &(pd->inventory));
|
||||||
|
|
||||||
|
addItemToInventory(newItem(TOOL_MAGIC_COMPASS,1), &(pd->inventory));
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 7;i < 28;++i) addItemToInventory(newItem(i,50), &(pd->inventory));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void playerInitSprite(PlayerData *pd) {
|
||||||
|
pd->sprite.choosen = false;
|
||||||
|
|
||||||
|
pd->sprite.legs = 0;
|
||||||
|
pd->sprite.body = 0;
|
||||||
|
pd->sprite.arms = 0;
|
||||||
|
pd->sprite.head = 0;
|
||||||
|
pd->sprite.eyes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void playerInitMenus(PlayerData *pd) {
|
||||||
|
pd->ingameMenu = MENU_NONE;
|
||||||
|
pd->ingameMenuSelection = 0;
|
||||||
|
pd->ingameMenuInvSel = 0;
|
||||||
|
pd->ingameMenuInvSelOther = 0;
|
||||||
|
pd->ingameMenuAreYouSure = false;
|
||||||
|
pd->ingameMenuAreYouSureSave = false;
|
||||||
|
pd->ingameMenuTimer = 0;
|
||||||
|
|
||||||
|
resetNPCMenuData(&(pd->npcMenuData));
|
||||||
|
|
||||||
|
pd->mapShouldRender = false;
|
||||||
|
pd->mapScrollX = 0;
|
||||||
|
pd->mapScrollY = 0;
|
||||||
|
pd->mapZoomLevel = 2;
|
||||||
|
sprintf(pd->mapText,"x%d", pd->mapZoomLevel);
|
||||||
|
|
||||||
|
pd->touchLastX = -1;
|
||||||
|
pd->touchLastY = -1;
|
||||||
|
pd->touchIsDraggingMap = false;
|
||||||
|
pd->touchIsChangingSize = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initPlayer(PlayerData *pd) {
|
||||||
|
pd->isSpawned = false;
|
||||||
|
|
||||||
|
playerInitMiniMapData(pd->minimapData);
|
||||||
|
playerInitEntity(pd);
|
||||||
|
playerInitInventory(pd);
|
||||||
|
|
||||||
|
playerInitSprite(pd);
|
||||||
|
|
||||||
|
initQuests(&(pd->questManager));
|
||||||
|
resetQuests(&(pd->questManager));
|
||||||
|
|
||||||
|
playerInitMenus(pd);
|
||||||
|
|
||||||
|
pd->score = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void freePlayer(PlayerData *pd) {
|
||||||
|
freeQuests(&(pd->questManager));
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerData* getNearestPlayer(s8 level, s16 x, s16 y) {
|
||||||
|
int nearest = -1;
|
||||||
|
unsigned int nearestDist = UINT_MAX;
|
||||||
|
|
||||||
|
for(int i=0; i<playerCount; i++) {
|
||||||
|
if(players[i].entity.level!=level) continue;
|
||||||
|
|
||||||
|
int xdif = players[i].entity.x - x;
|
||||||
|
int ydif = players[i].entity.y - y;
|
||||||
|
|
||||||
|
unsigned int dist = xdif*xdif + ydif*ydif;
|
||||||
|
if(dist<nearestDist) {
|
||||||
|
nearest = i;
|
||||||
|
nearestDist = dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(nearest==-1) return NULL;
|
||||||
|
|
||||||
|
return players+nearest;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerData* getLocalPlayer() {
|
||||||
|
return players+playerLocalID;
|
||||||
|
}
|
||||||
|
|
||||||
|
//player update functions
|
||||||
|
bool playerUseItem(PlayerData *pd) {
|
||||||
|
int aitemID = 0;
|
||||||
|
Item * aitem;
|
||||||
|
Item * item ;
|
||||||
|
|
||||||
|
switch(pd->activeItem->id){
|
||||||
|
//shooting arrows
|
||||||
|
case TOOL_BOW:
|
||||||
|
item = getItemFromInventory(ITEM_ARROW_WOOD, &(pd->inventory));
|
||||||
|
if(item!=NULL) {
|
||||||
|
aitemID = ITEM_ARROW_WOOD;
|
||||||
|
aitem = item;
|
||||||
|
}
|
||||||
|
item = getItemFromInventory(ITEM_ARROW_STONE, &(pd->inventory));
|
||||||
|
if(item!=NULL) {
|
||||||
|
aitemID = ITEM_ARROW_STONE;
|
||||||
|
aitem = item;
|
||||||
|
}
|
||||||
|
item = getItemFromInventory(ITEM_ARROW_IRON, &(pd->inventory));
|
||||||
|
if(item!=NULL) {
|
||||||
|
aitemID = ITEM_ARROW_IRON;
|
||||||
|
aitem = item;
|
||||||
|
}
|
||||||
|
item = getItemFromInventory(ITEM_ARROW_GOLD, &(pd->inventory));
|
||||||
|
if(item!=NULL) {
|
||||||
|
aitemID = ITEM_ARROW_GOLD;
|
||||||
|
aitem = item;
|
||||||
|
}
|
||||||
|
item = getItemFromInventory(ITEM_ARROW_GEM, &(pd->inventory));
|
||||||
|
if(item!=NULL) {
|
||||||
|
aitemID = ITEM_ARROW_GEM;
|
||||||
|
aitem = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(aitemID!=0) {
|
||||||
|
--aitem->countLevel;
|
||||||
|
if (isItemEmpty(aitem)) {
|
||||||
|
removeItemFromInventory(aitem->slotNum, &(pd->inventory));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(pd->entity.p.dir) {
|
||||||
|
case 0:
|
||||||
|
addEntityToList(newArrowEntity(&(pd->entity), aitemID, 0, 2, pd->entity.level), &eManager);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
addEntityToList(newArrowEntity(&(pd->entity), aitemID, 0, -2, pd->entity.level), &eManager);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
addEntityToList(newArrowEntity(&(pd->entity), aitemID, -2, 0, pd->entity.level), &eManager);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
addEntityToList(newArrowEntity(&(pd->entity), aitemID, 2, 0, pd->entity.level), &eManager);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Health items
|
||||||
|
case ITEM_APPLE:
|
||||||
|
if(pd->entity.p.health < 10 && playerUseEnergy(pd, 2)){
|
||||||
|
playerHeal(pd, 1);
|
||||||
|
--(pd->activeItem->countLevel);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ITEM_STRENGTH_POTION:
|
||||||
|
if(pd->entity.p.health < 20 && pd->entity.p.strengthTimer == 0){
|
||||||
|
potionEffect(1);
|
||||||
|
--(pd->activeItem->countLevel);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
case ITEM_SPEED_POTION:
|
||||||
|
if(pd->entity.p.health < 20 && pd->entity.p.speedTimer == 0){
|
||||||
|
potionEffect(2);
|
||||||
|
--(pd->activeItem->countLevel);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
case ITEM_REGEN_POTION:
|
||||||
|
if(pd->entity.p.health < 20 && pd->entity.p.regenTimer == 0){
|
||||||
|
potionEffect(3);
|
||||||
|
--(pd->activeItem->countLevel);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
case ITEM_SWIM_BREATH_POTION:
|
||||||
|
if(pd->entity.p.health < 20 && pd->entity.p.swimBreathTimer == 0){
|
||||||
|
potionEffect(4);
|
||||||
|
--(pd->activeItem->countLevel);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
case ITEM_GOLD_APPLE:
|
||||||
|
if(pd->entity.p.health < 10 && playerUseEnergy(pd, 1)){
|
||||||
|
playerHeal(pd, 8);
|
||||||
|
playerUseEnergy(pd, -10);
|
||||||
|
--(pd->activeItem->countLevel);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
case ITEM_FLESH:
|
||||||
|
if(pd->entity.p.health < 10 && playerUseEnergy(pd, 4+(rand()%4))){
|
||||||
|
playerHeal(pd, 1);
|
||||||
|
--(pd->activeItem->countLevel);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ITEM_BREAD:
|
||||||
|
if(pd->entity.p.health < 10 && playerUseEnergy(pd, 3)){
|
||||||
|
playerHeal(pd, 2);
|
||||||
|
--(pd->activeItem->countLevel);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ITEM_PORK_RAW:
|
||||||
|
if(pd->entity.p.health < 10 && playerUseEnergy(pd, 4+(rand()%4))){
|
||||||
|
playerHeal(pd, 1);
|
||||||
|
--(pd->activeItem->countLevel);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ITEM_PORK_COOKED:
|
||||||
|
if(pd->entity.p.health < 10 && playerUseEnergy(pd, 3)){
|
||||||
|
playerHeal(pd, 3);
|
||||||
|
--(pd->activeItem->countLevel);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ITEM_BEEF_RAW:
|
||||||
|
if(pd->entity.p.health < 10 && playerUseEnergy(pd, 4+(rand()%4))){
|
||||||
|
playerHeal(pd, 1);
|
||||||
|
--(pd->activeItem->countLevel);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ITEM_BEEF_COOKED:
|
||||||
|
if(pd->entity.p.health < 10 && playerUseEnergy(pd, 3)){
|
||||||
|
playerHeal(pd, 4);
|
||||||
|
--(pd->activeItem->countLevel);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
//special item
|
||||||
|
case ITEM_WIZARD_SUMMON:
|
||||||
|
if(pd->entity.level==0) {
|
||||||
|
--(pd->activeItem->countLevel);
|
||||||
|
|
||||||
|
airWizardHealthDisplay = 2000;
|
||||||
|
addEntityToList(newAirWizardEntity(630, 820, 0), &eManager);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isItemEmpty(pd->activeItem)) {
|
||||||
|
removeItemFromInventory(pd->activeItem->slotNum, &(pd->inventory));
|
||||||
|
pd->activeItem = &noItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool playerInteract(PlayerData *pd, int x0, int y0, int x1, int y1) {
|
||||||
|
Entity * es[eManager.lastSlot[pd->entity.level]];
|
||||||
|
int eSize = getEntities(es, pd->entity.level, x0, y0, x1, y1);
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < eSize; ++i) {
|
||||||
|
Entity * ent = es[i];
|
||||||
|
if (ent != &(pd->entity)){
|
||||||
|
if (ItemVsEntity(pd, pd->activeItem, ent, pd->entity.p.dir)) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void playerAttack(PlayerData *pd) {
|
||||||
|
bool done = false;
|
||||||
|
pd->entity.p.attackTimer = 5;
|
||||||
|
int yo = -2;
|
||||||
|
int range = 12;
|
||||||
|
|
||||||
|
//directly using an item
|
||||||
|
if(playerUseItem(pd)) return;
|
||||||
|
|
||||||
|
//interacting with entities
|
||||||
|
switch(pd->entity.p.dir){
|
||||||
|
case 0: if(playerInteract(pd, pd->entity.x - 8, pd->entity.y + 4 + yo, pd->entity.x + 8, pd->entity.y + range + yo)) return; break;
|
||||||
|
case 1: if(playerInteract(pd, pd->entity.x - 8, pd->entity.y - range + yo, pd->entity.x + 8, pd->entity.y - 4 + yo)) return; break;
|
||||||
|
case 2: if(playerInteract(pd, pd->entity.x - range, pd->entity.y - 8 + yo, pd->entity.x - 4, pd->entity.y + 8 + yo)) return; break;
|
||||||
|
case 3: if(playerInteract(pd, pd->entity.x + 4, pd->entity.y - 8 + yo, pd->entity.x + range, pd->entity.y + 8 + yo)) return; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int xt = pd->entity.x >> 4;
|
||||||
|
int yt = (pd->entity.y + yo) >> 4;
|
||||||
|
int r = 12;
|
||||||
|
if (pd->entity.p.dir == 0) yt = (pd->entity.y + r + yo) >> 4;
|
||||||
|
if (pd->entity.p.dir == 1) yt = (pd->entity.y - r + yo) >> 4;
|
||||||
|
if (pd->entity.p.dir == 2) xt = (pd->entity.x - r) >> 4;
|
||||||
|
if (pd->entity.p.dir == 3) xt = (pd->entity.x + r) >> 4;
|
||||||
|
|
||||||
|
//interacting with tiles
|
||||||
|
if (xt >= 0 && yt >= 0 && xt < 128 && yt < 128) {
|
||||||
|
s8 itract = itemTileInteract(getTile(pd->entity.level, xt, yt), pd, pd->activeItem, pd->entity.level, xt, yt, pd->entity.x, pd->entity.y, pd->entity.p.dir);
|
||||||
|
if(itract > 0){
|
||||||
|
if(itract==2) pd->entity.p.isCarrying = false;
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pd->activeItem != &noItem && isItemEmpty(pd->activeItem)) {
|
||||||
|
removeItemFromInventory(pd->activeItem->slotNum, &(pd->inventory));
|
||||||
|
pd->activeItem = &noItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(done) return;
|
||||||
|
|
||||||
|
//breaking tiles
|
||||||
|
if (pd->activeItem == &noItem || pd->activeItem->id == TOOL_SWORD || pd->activeItem->id == TOOL_AXE) {
|
||||||
|
if (xt >= 0 && yt >= 0 && xt < 128 && 128) {
|
||||||
|
playerHurtTile(pd, getTile(pd->entity.level, xt, yt), pd->entity.level, xt, yt, (rand()%3) + 1, pd->entity.p.dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool playerUseArea(PlayerData *pd, int x0, int y0, int x1, int y1) {
|
||||||
|
Entity * entities[eManager.lastSlot[pd->entity.level]];
|
||||||
|
int i;
|
||||||
|
int ae = getEntities(entities, pd->entity.level, x0, y0, x1, y1);
|
||||||
|
for(i = 0; i < ae; ++i){
|
||||||
|
if(useEntity(pd, entities[i])) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool playerUse(PlayerData *pd) {
|
||||||
|
int yo = -2;
|
||||||
|
if (pd->entity.p.dir == 0 && playerUseArea(pd, pd->entity.x - 8, pd->entity.y + 4 + yo, pd->entity.x + 8, pd->entity.y + 12 + yo)) return true;
|
||||||
|
if (pd->entity.p.dir == 1 && playerUseArea(pd, pd->entity.x - 8, pd->entity.y - 12 + yo, pd->entity.x + 8, pd->entity.y - 4 + yo)) return true;
|
||||||
|
if (pd->entity.p.dir == 3 && playerUseArea(pd, pd->entity.x + 4, pd->entity.y - 8 + yo, pd->entity.x + 12, pd->entity.y + 8 + yo)) return true;
|
||||||
|
if (pd->entity.p.dir == 2 && playerUseArea(pd, pd->entity.x - 12, pd->entity.y - 8 + yo, pd->entity.x - 4, pd->entity.y + 8 + yo)) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tickPlayer(PlayerData *pd, bool inmenu) {
|
||||||
|
if (pd->entity.p.isDead) return;
|
||||||
|
|
||||||
|
//invincibility time
|
||||||
|
if (pd->entity.hurtTime > 0) pd->entity.hurtTime--;
|
||||||
|
|
||||||
|
//stamina recharging
|
||||||
|
bool swimming = isWater(pd->entity.level, pd->entity.x>>4, pd->entity.y>>4);
|
||||||
|
if (pd->entity.p.stamina <= 0 && pd->entity.p.staminaRechargeDelay == 0 && pd->entity.p.staminaRecharge == 0) {
|
||||||
|
pd->entity.p.staminaRechargeDelay = 40;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pd->entity.p.staminaRechargeDelay > 0) {
|
||||||
|
--pd->entity.p.staminaRechargeDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pd->entity.p.staminaRechargeDelay == 0) {
|
||||||
|
++pd->entity.p.staminaRecharge;
|
||||||
|
if (swimming) pd->entity.p.staminaRecharge = 0;
|
||||||
|
|
||||||
|
while (pd->entity.p.staminaRecharge > 10) {
|
||||||
|
pd->entity.p.staminaRecharge -= 10;
|
||||||
|
if (pd->entity.p.stamina < 10) ++pd->entity.p.stamina;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!inmenu) {
|
||||||
|
if(!pd->sprite.choosen) {
|
||||||
|
pd->ingameMenu = MENU_CHARACTER_CUSTOMIZE;
|
||||||
|
pd->ingameMenuSelection = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//movement
|
||||||
|
pd->entity.p.ax = 0;
|
||||||
|
pd->entity.p.ay = 0;
|
||||||
|
|
||||||
|
if (pd->inputs.k_left.down){
|
||||||
|
pd->entity.p.ax -= 1;
|
||||||
|
pd->entity.p.dir = 2;
|
||||||
|
++pd->entity.p.walkDist;
|
||||||
|
}
|
||||||
|
if (pd->inputs.k_right.down){
|
||||||
|
pd->entity.p.ax += 1;
|
||||||
|
pd->entity.p.dir = 3;
|
||||||
|
++pd->entity.p.walkDist;
|
||||||
|
}
|
||||||
|
if (pd->inputs.k_up.down){
|
||||||
|
pd->entity.p.ay -= 1;
|
||||||
|
pd->entity.p.dir = 1;
|
||||||
|
++pd->entity.p.walkDist;
|
||||||
|
}
|
||||||
|
if (pd->inputs.k_down.down){
|
||||||
|
pd->entity.p.ay += 1;
|
||||||
|
pd->entity.p.dir = 0;
|
||||||
|
++pd->entity.p.walkDist;
|
||||||
|
}
|
||||||
|
if (pd->entity.p.staminaRechargeDelay % 2 == 0) moveMob(&(pd->entity), pd->entity.p.ax, pd->entity.p.ay);
|
||||||
|
|
||||||
|
//"pausing", TODO: since multiplayer this will no longer pause
|
||||||
|
if (pd->inputs.k_pause.clicked){
|
||||||
|
pd->ingameMenuSelection = 0;
|
||||||
|
pd->ingameMenu = MENU_PAUSED;
|
||||||
|
}
|
||||||
|
|
||||||
|
//attacking
|
||||||
|
if(pd->inputs.k_attack.clicked){
|
||||||
|
if (pd->entity.p.stamina != 0) {
|
||||||
|
if(!TESTGODMODE) pd->entity.p.stamina--;
|
||||||
|
pd->entity.p.staminaRecharge = 0;
|
||||||
|
|
||||||
|
playerAttack(pd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pd->inputs.k_menu.clicked){
|
||||||
|
pd->ingameMenuInvSel = 0;
|
||||||
|
if(!playerUse(pd)) pd->ingameMenu = MENU_INVENTORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//swimming stamina and drowning
|
||||||
|
if (swimming && pd->entity.p.swimTimer % 60 == 0) {
|
||||||
|
if (pd->entity.p.stamina > 0) {
|
||||||
|
if(!TESTGODMODE) --pd->entity.p.stamina;
|
||||||
|
} else {
|
||||||
|
hurtEntity(&(pd->entity), 1, -1, 0xFFAF00FF, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isWater(pd->entity.level, pd->entity.x>>4, pd->entity.y>>4)) ++pd->entity.p.swimTimer;
|
||||||
|
if(pd->entity.p.attackTimer > 0) --pd->entity.p.attackTimer;
|
||||||
|
|
||||||
|
//TODO - maybe move to own function
|
||||||
|
//Update Minimap
|
||||||
|
int xp;
|
||||||
|
int yp;
|
||||||
|
for(xp = (pd->entity.x>>4)-5; xp<(pd->entity.x>>4)+5; ++xp) {
|
||||||
|
for(yp = (pd->entity.y>>4)-5; yp<(pd->entity.y>>4)+5; ++yp) {
|
||||||
|
if(xp>=0 && xp<128 && yp>=0 && yp<128) {
|
||||||
|
if(!getMinimapVisible(pd, pd->entity.level, xp, yp)) {
|
||||||
|
setMinimapVisible(pd, pd->entity.level, xp, yp, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void playerSetActiveItem(PlayerData *pd, Item *item) {
|
||||||
|
pd->activeItem = item;
|
||||||
|
if(pd->activeItem->id > 27 && pd->activeItem->id < 51) pd->entity.p.isCarrying = true;
|
||||||
|
else pd->entity.p.isCarrying = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool playerUseEnergy(PlayerData *pd, int amount) {
|
||||||
|
if(TESTGODMODE) return true;
|
||||||
|
if(amount > pd->entity.p.stamina) return false;
|
||||||
|
pd->entity.p.stamina -= amount;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void playerHeal(PlayerData *pd, int amount) {
|
||||||
|
pd->entity.p.health += amount;
|
||||||
|
if(pd->entity.p.health > 10) pd->entity.p.health = 10;
|
||||||
|
char healText[11];
|
||||||
|
sprintf(healText, "%d", amount);
|
||||||
|
addEntityToList(newTextParticleEntity(healText,0xFF00FF00, pd->entity.x, pd->entity.y, pd->entity.level), &eManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
void playerSpawn(PlayerData *pd) {
|
||||||
|
while(true){
|
||||||
|
int rx = rand()%128;
|
||||||
|
int ry = rand()%128;
|
||||||
|
if(getTile(pd->entity.level, rx, ry) == TILE_GRASS){
|
||||||
|
pd->entity.x = (rx << 4) + 8;
|
||||||
|
pd->entity.y = (ry << 4) + 8;
|
||||||
|
pd->isSpawned = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
96
source/Player.h
Normal file
96
source/Player.h
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Input.h"
|
||||||
|
#include "Entity.h"
|
||||||
|
#include "QuestsData.h"
|
||||||
|
#include "Crafting.h"
|
||||||
|
|
||||||
|
#define MAX_PLAYERS 8
|
||||||
|
#define MAX_INPUT_BUFFER 3
|
||||||
|
|
||||||
|
#define PLAYER_SPRITE_HEAD_COUNT 4
|
||||||
|
#define PLAYER_SPRITE_EYES_COUNT 5
|
||||||
|
#define PLAYER_SPRITE_BODY_COUNT 6
|
||||||
|
#define PLAYER_SPRITE_ARMS_COUNT 6
|
||||||
|
#define PLAYER_SPRITE_LEGS_COUNT 5
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _plrsp {
|
||||||
|
bool choosen;
|
||||||
|
|
||||||
|
u8 legs;
|
||||||
|
u8 body;
|
||||||
|
u8 arms;
|
||||||
|
u8 head;
|
||||||
|
u8 eyes;
|
||||||
|
} PlayerSprite;
|
||||||
|
|
||||||
|
typedef struct _plrd {
|
||||||
|
//for identification in save data and sync game start
|
||||||
|
u32 id;
|
||||||
|
bool idSet;
|
||||||
|
bool ready;
|
||||||
|
|
||||||
|
//input/multiplayer/synchronization
|
||||||
|
Inputs inputs;
|
||||||
|
Inputs nextInputs[MAX_INPUT_BUFFER];
|
||||||
|
bool nextTurnReady[MAX_INPUT_BUFFER];
|
||||||
|
|
||||||
|
//
|
||||||
|
bool isSpawned;
|
||||||
|
u8 minimapData[128*128];
|
||||||
|
|
||||||
|
int score;
|
||||||
|
QuestlineManager questManager;
|
||||||
|
|
||||||
|
Entity entity;
|
||||||
|
Inventory inventory;
|
||||||
|
Item *activeItem;
|
||||||
|
|
||||||
|
PlayerSprite sprite;
|
||||||
|
|
||||||
|
//menu data
|
||||||
|
u8 ingameMenu;
|
||||||
|
s8 ingameMenuSelection;
|
||||||
|
s16 ingameMenuInvSel;
|
||||||
|
s16 ingameMenuInvSelOther;
|
||||||
|
bool ingameMenuAreYouSure;
|
||||||
|
bool ingameMenuAreYouSureSave;
|
||||||
|
s16 ingameMenuTimer;
|
||||||
|
NPC_MenuData npcMenuData;
|
||||||
|
|
||||||
|
RecipeManager currentRecipes;
|
||||||
|
char *currentCraftTitle;
|
||||||
|
Entity *curChestEntity;
|
||||||
|
s8 curChestEntityR;
|
||||||
|
|
||||||
|
bool mapShouldRender;
|
||||||
|
u8 mapZoomLevel;
|
||||||
|
s16 mapScrollX;
|
||||||
|
s16 mapScrollY;
|
||||||
|
char mapText[32];
|
||||||
|
|
||||||
|
s16 touchLastX;
|
||||||
|
s16 touchLastY;
|
||||||
|
bool touchIsDraggingMap;
|
||||||
|
bool touchIsChangingSize;
|
||||||
|
} PlayerData;
|
||||||
|
|
||||||
|
PlayerData players[MAX_PLAYERS];
|
||||||
|
int playerCount;
|
||||||
|
int playerLocalID;
|
||||||
|
|
||||||
|
void initPlayers();
|
||||||
|
void freePlayers();
|
||||||
|
|
||||||
|
void initPlayer(PlayerData *pd);
|
||||||
|
void freePlayer(PlayerData *pd);
|
||||||
|
|
||||||
|
PlayerData* getNearestPlayer(s8 level, s16 x, s16 y);
|
||||||
|
PlayerData* getLocalPlayer();
|
||||||
|
|
||||||
|
void tickPlayer(PlayerData *pd, bool inmenu);
|
||||||
|
void playerSetActiveItem(PlayerData *pd, Item * item);
|
||||||
|
bool playerUseEnergy(PlayerData * pd, int amount);
|
||||||
|
void playerHeal(PlayerData *pd, int amount);
|
||||||
|
void playerSpawn(PlayerData *pd);
|
579
source/Quests.c
579
source/Quests.c
|
@ -1,27 +1,9 @@
|
||||||
#include "Quests.h"
|
#include "Quests.h"
|
||||||
|
|
||||||
u8 currentNPC;
|
#include "Globals.h"
|
||||||
|
#include "Render.h"
|
||||||
int currentNPCMenu;
|
|
||||||
int currentNPCVal;
|
|
||||||
|
|
||||||
int currentTalkSel;
|
|
||||||
bool currentTalkDone;
|
|
||||||
int currentTalkOptions;
|
|
||||||
char * currentTalkOption0;
|
|
||||||
char * currentTalkOption1;
|
|
||||||
char * currentTalkOption2;
|
|
||||||
char * currentTalk0;
|
|
||||||
char * currentTalk1;
|
|
||||||
char * currentTalk2;
|
|
||||||
char * currentTalk3;
|
|
||||||
char * currentTalk4;
|
|
||||||
char * currentTalk5;
|
|
||||||
|
|
||||||
void initQuests() {
|
|
||||||
questManager.size = 2;
|
|
||||||
questManager.questlines = (Questline*)malloc(sizeof(Questline) * (questManager.size));
|
|
||||||
|
|
||||||
|
void initTrades() {
|
||||||
priestTrades.size = 5;
|
priestTrades.size = 5;
|
||||||
priestTrades.recipes = (Recipe*)malloc(sizeof(Recipe) * (priestTrades.size));
|
priestTrades.recipes = (Recipe*)malloc(sizeof(Recipe) * (priestTrades.size));
|
||||||
priestTrades.recipes[0] = defineRecipe(ITEM_DUNGEON_KEY,1,1,ITEM_MAGIC_DUST,2);
|
priestTrades.recipes[0] = defineRecipe(ITEM_DUNGEON_KEY,1,1,ITEM_MAGIC_DUST,2);
|
||||||
|
@ -47,335 +29,364 @@ void initQuests() {
|
||||||
//TODO: Trade Dragon Scales for something really nice
|
//TODO: Trade Dragon Scales for something really nice
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetQuests() {
|
void freeTrades() {
|
||||||
int i;
|
|
||||||
for(i=0; i<questManager.size; ++i) {
|
|
||||||
questManager.questlines[i].currentQuest = 0;
|
|
||||||
questManager.questlines[i].currentQuestDone = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void freeQuests() {
|
|
||||||
free(questManager.questlines);
|
|
||||||
free(priestTrades.recipes);
|
free(priestTrades.recipes);
|
||||||
free(farmerTrades.recipes);
|
free(farmerTrades.recipes);
|
||||||
free(dwarfTrades.recipes);
|
free(dwarfTrades.recipes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void openNPCMenu(int npc) {
|
void initQuests(QuestlineManager *questManager) {
|
||||||
currentNPC = npc;
|
if(questManager->questlines!=NULL) {
|
||||||
currentNPCVal = 0;
|
freeQuests(questManager);
|
||||||
currentMenu = MENU_NPC;
|
}
|
||||||
currentNPCMenu = NPC_MENU_TALK;
|
|
||||||
|
|
||||||
currentTalkSel = 0;
|
questManager->size = 2;
|
||||||
currentTalkDone = false;
|
questManager->questlines = (Questline*)malloc(sizeof(Questline) * (questManager->size));
|
||||||
currentTalkOptions = 1;
|
}
|
||||||
currentTalkOption0 = "Bye";
|
|
||||||
currentTalkOption1 = "";
|
void resetQuests(QuestlineManager *questManager) {
|
||||||
currentTalkOption2 = "";
|
int i;
|
||||||
currentTalk0 = "";
|
for(i=0; i<questManager->size; ++i) {
|
||||||
currentTalk1 = "";
|
questManager->questlines[i].currentQuest = 0;
|
||||||
currentTalk2 = "";
|
questManager->questlines[i].currentQuestDone = false;
|
||||||
currentTalk3 = "";
|
}
|
||||||
currentTalk4 = "";
|
}
|
||||||
currentTalk5 = "";
|
|
||||||
|
void freeQuests(QuestlineManager *questManager) {
|
||||||
|
free(questManager->questlines);
|
||||||
|
questManager->questlines = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetNPCMenuData(NPC_MenuData *data) {
|
||||||
|
data->currentNPC = 0;
|
||||||
|
data->currentNPCMenu = 0;
|
||||||
|
data->currentNPCVal = 0;
|
||||||
|
|
||||||
|
data->currentTalkSel = 0;
|
||||||
|
data->currentTalkDone = false;
|
||||||
|
data->currentTalkOptions = 0;
|
||||||
|
|
||||||
|
data->currentTalkOption0 = "";
|
||||||
|
data->currentTalkOption1 = "";
|
||||||
|
data->currentTalkOption2 = "";
|
||||||
|
data->currentTalk0 = "";
|
||||||
|
data->currentTalk1 = "";
|
||||||
|
data->currentTalk2 = "";
|
||||||
|
data->currentTalk3 = "";
|
||||||
|
data->currentTalk4 = "";
|
||||||
|
data->currentTalk5 = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void openNPCMenu(PlayerData *pd, int npc) {
|
||||||
|
pd->ingameMenu = MENU_NPC;
|
||||||
|
|
||||||
|
NPC_MenuData *data = &(pd->npcMenuData);
|
||||||
|
QuestlineManager *questManager = &(pd->questManager);
|
||||||
|
|
||||||
|
data->currentNPC = npc;
|
||||||
|
data->currentNPCVal = 0;
|
||||||
|
data->currentNPCMenu = NPC_MENU_TALK;
|
||||||
|
|
||||||
|
data->currentTalkSel = 0;
|
||||||
|
data->currentTalkDone = false;
|
||||||
|
data->currentTalkOptions = 1;
|
||||||
|
data->currentTalkOption0 = "Bye";
|
||||||
|
data->currentTalkOption1 = "";
|
||||||
|
data->currentTalkOption2 = "";
|
||||||
|
data->currentTalk0 = "";
|
||||||
|
data->currentTalk1 = "";
|
||||||
|
data->currentTalk2 = "";
|
||||||
|
data->currentTalk3 = "";
|
||||||
|
data->currentTalk4 = "";
|
||||||
|
data->currentTalk5 = "";
|
||||||
|
|
||||||
//TODO: Handle upon currentNPC as well as the fitting quest progress
|
//TODO: Handle upon currentNPC as well as the fitting quest progress
|
||||||
switch(currentNPC) {
|
switch(data->currentNPC) {
|
||||||
case NPC_GIRL:
|
case NPC_GIRL:
|
||||||
currentTalkOptions = 2;
|
data->currentTalkOptions = 1;
|
||||||
currentTalkOption0 = "Trade";
|
data->currentTalkOption0 = "...";
|
||||||
currentTalkOption1 = "What do you do?";
|
|
||||||
|
|
||||||
currentTalk0 = "Hello!";
|
data->currentTalk0 = "Hello?";
|
||||||
currentTalk1 = "It gets a bit lonely here.";
|
data->currentTalk1 = "I have a feeling of having";
|
||||||
currentTalk2 = "I hope you stay...";
|
data->currentTalk2 = "forgotten something very";
|
||||||
currentTalk3 = "But if you don't thats fine.";
|
data->currentTalk3 = "important.";
|
||||||
currentTalk4 = "sigh";
|
data->currentTalk4 = "Hopefully I will remember";
|
||||||
currentTalk5 = "";
|
data->currentTalk5 = "it soon...";
|
||||||
break;
|
break;
|
||||||
case NPC_PRIEST:
|
case NPC_PRIEST:
|
||||||
currentTalkOptions = 3;
|
data->currentTalkOptions = 3;
|
||||||
currentTalkOption1 = "Trade";
|
data->currentTalkOption1 = "Trade";
|
||||||
currentTalkOption2 = "Why are you so few?";
|
data->currentTalkOption2 = "Why are you so few?";
|
||||||
|
|
||||||
currentTalk0 = "Welcome to our small village";
|
data->currentTalk0 = "Welcome to our small village";
|
||||||
currentTalk1 = "I am the leader of our group.";
|
data->currentTalk1 = "I am the leader of our group.";
|
||||||
currentTalk2 = "If you have anything usefull";
|
data->currentTalk2 = "If you have anything usefull";
|
||||||
currentTalk3 = "for us I might be able to";
|
data->currentTalk3 = "for us I might be able to";
|
||||||
currentTalk4 = "provide something nice in";
|
data->currentTalk4 = "provide something nice in";
|
||||||
currentTalk5 = "exchange.";
|
data->currentTalk5 = "exchange.";
|
||||||
break;
|
break;
|
||||||
case NPC_FARMER:
|
case NPC_FARMER:
|
||||||
currentTalkOptions = 2;
|
data->currentTalkOptions = 2;
|
||||||
currentTalkOption0 = "Maybe some other time";
|
data->currentTalkOption0 = "Maybe some other time";
|
||||||
currentTalkOption1 = "Trade";
|
data->currentTalkOption1 = "Trade";
|
||||||
|
|
||||||
currentTalk0 = "Hello friend!";
|
data->currentTalk0 = "Hello friend!";
|
||||||
currentTalk1 = "Nice seeing somebody else";
|
data->currentTalk1 = "Nice seeing somebody else";
|
||||||
currentTalk2 = "visit my little farm.";
|
data->currentTalk2 = "visit my little farm.";
|
||||||
currentTalk3 = "Interested in buying some";
|
data->currentTalk3 = "Interested in buying some";
|
||||||
currentTalk4 = "fresh farm goods?";
|
data->currentTalk4 = "fresh farm goods?";
|
||||||
currentTalk5 = "";
|
data->currentTalk5 = "";
|
||||||
break;
|
break;
|
||||||
case NPC_LIBRARIAN:
|
case NPC_LIBRARIAN:
|
||||||
currentTalkOptions = 2;
|
data->currentTalkOptions = 2;
|
||||||
currentTalkOption0 = "Nothing";
|
data->currentTalkOption0 = "Nothing";
|
||||||
currentTalkOption1 = "What are you doing here?";
|
data->currentTalkOption1 = "What are you doing here?";
|
||||||
if(questManager.questlines[1].currentQuest==1) {
|
if(questManager->questlines[1].currentQuest==1) {
|
||||||
currentTalkOptions = 3;
|
data->currentTalkOptions = 3;
|
||||||
currentTalkOption2 = "Dwarvish language";
|
data->currentTalkOption2 = "Dwarvish language";
|
||||||
}
|
}
|
||||||
|
|
||||||
currentTalk0 = "Oh hello?";
|
data->currentTalk0 = "Oh hello?";
|
||||||
currentTalk1 = "You must be quite brave";
|
data->currentTalk1 = "You must be quite brave";
|
||||||
currentTalk2 = "or stupid to be walking";
|
data->currentTalk2 = "or stupid to be walking";
|
||||||
currentTalk3 = "around in this dungeon.";
|
data->currentTalk3 = "around in this dungeon.";
|
||||||
currentTalk4 = "";
|
data->currentTalk4 = "";
|
||||||
currentTalk5 = "How can I help you?";
|
data->currentTalk5 = "How can I help you?";
|
||||||
break;
|
break;
|
||||||
case NPC_DWARF:
|
case NPC_DWARF:
|
||||||
if(questManager.questlines[1].currentQuest<=1) {
|
if(questManager->questlines[1].currentQuest<=1) {
|
||||||
questManager.questlines[1].currentQuest = 1;
|
questManager->questlines[1].currentQuest = 1;
|
||||||
|
|
||||||
currentTalkOptions = 1;
|
data->currentTalkOptions = 1;
|
||||||
currentTalkOption0 = "?";
|
data->currentTalkOption0 = "?";
|
||||||
|
|
||||||
currentTalk0 = "Dwo neal bet reck da lo";
|
data->currentTalk0 = "Dwo neal bet reck da lo";
|
||||||
currentTalk1 = "dhum don lir lugn at el";
|
data->currentTalk1 = "dhum don lir lugn at el";
|
||||||
currentTalk2 = "nur tor erno ur yo trad";
|
data->currentTalk2 = "nur tor erno ur yo trad";
|
||||||
currentTalk3 = "thra so tir kho ukk tin";
|
data->currentTalk3 = "thra so tir kho ukk tin";
|
||||||
currentTalk4 = "hel dro ic";
|
data->currentTalk4 = "hel dro ic";
|
||||||
currentTalk5 = "";
|
data->currentTalk5 = "";
|
||||||
//TODO: set to 2 once translation book has been bought from librarian(can only be done once it is 1, so the dwarf has been found once)
|
//TODO: set to 2 once translation book has been bought from librarian(can only be done once it is 1, so the dwarf has been found once)
|
||||||
} else if(questManager.questlines[1].currentQuest==2) {
|
} else if(questManager->questlines[1].currentQuest==2) {
|
||||||
currentTalkOptions = 2;
|
data->currentTalkOptions = 2;
|
||||||
currentTalkOption0 = "Not really";
|
data->currentTalkOption0 = "Not really";
|
||||||
currentTalkOption1 = "Trade";
|
data->currentTalkOption1 = "Trade";
|
||||||
|
|
||||||
currentTalk0 = "How are ya?";
|
data->currentTalk0 = "How are ya?";
|
||||||
currentTalk1 = "Pretty unusal meeting a";
|
data->currentTalk1 = "Pretty unusal meeting a";
|
||||||
currentTalk2 = "human down here.";
|
data->currentTalk2 = "human down here.";
|
||||||
currentTalk3 = "";
|
data->currentTalk3 = "";
|
||||||
currentTalk4 = "have something valuable";
|
data->currentTalk4 = "have something valuable";
|
||||||
currentTalk5 = "to trade?";
|
data->currentTalk5 = "to trade?";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tickTalkMenu() {
|
void tickTalkMenu(PlayerData *pd, NPC_MenuData *data) {
|
||||||
if (k_menu.clicked || k_decline.clicked) currentMenu = MENU_NONE;
|
if (pd->inputs.k_menu.clicked || pd->inputs.k_decline.clicked) pd->ingameMenu = MENU_NONE;
|
||||||
|
|
||||||
if (k_up.clicked){ ++currentTalkSel; if(currentTalkSel >= currentTalkOptions) currentTalkSel=0;}
|
if (pd->inputs.k_up.clicked){ ++data->currentTalkSel; if(data->currentTalkSel >= data->currentTalkOptions) data->currentTalkSel=0;}
|
||||||
if (k_down.clicked){ --currentTalkSel; if(currentTalkSel < 0) currentTalkSel=currentTalkOptions-1;}
|
if (pd->inputs.k_down.clicked){ --data->currentTalkSel; if(data->currentTalkSel < 0) data->currentTalkSel=data->currentTalkOptions-1;}
|
||||||
|
|
||||||
if(k_accept.clicked){
|
if(pd->inputs.k_accept.clicked){
|
||||||
currentTalkDone = true;
|
data->currentTalkDone = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tickNPCMenu() {
|
void tickNPCMenu(PlayerData *pd) {
|
||||||
|
NPC_MenuData *data = &(pd->npcMenuData);
|
||||||
|
QuestlineManager *questManager = &(pd->questManager);
|
||||||
|
|
||||||
//TODO: Handle upon currentNPC as well as the fitting quest progress
|
//TODO: Handle upon currentNPC as well as the fitting quest progress
|
||||||
if(currentNPCMenu==NPC_MENU_TALK) tickTalkMenu();
|
if(data->currentNPCMenu==NPC_MENU_TALK) tickTalkMenu(pd, data);
|
||||||
|
|
||||||
|
|
||||||
switch(currentNPC) {
|
switch(data->currentNPC) {
|
||||||
case NPC_GIRL:
|
case NPC_GIRL:
|
||||||
|
if(data->currentNPCMenu==NPC_MENU_TALK && data->currentTalkDone) {
|
||||||
|
if(data->currentNPCVal==0) pd->ingameMenu = MENU_NONE;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case NPC_PRIEST:
|
case NPC_PRIEST:
|
||||||
if(currentNPCMenu==NPC_MENU_TALK && currentTalkDone) {
|
if(data->currentNPCMenu==NPC_MENU_TALK && data->currentTalkDone) {
|
||||||
if(currentNPCVal==0) {
|
if(data->currentNPCVal==0) {
|
||||||
if(currentTalkSel==0) {
|
if(data->currentTalkSel==0) {
|
||||||
currentMenu = MENU_NONE;
|
pd->ingameMenu = MENU_NONE;
|
||||||
} else if(currentTalkSel==1) {
|
} else if(data->currentTalkSel==1) {
|
||||||
currentRecipes = &priestTrades;
|
openCraftingMenu(pd, &priestTrades, "Trading");
|
||||||
currentCraftTitle = "Trading";
|
} else if(data->currentTalkSel==2) {
|
||||||
currentMenu = MENU_CRAFTING;
|
data->currentNPCVal = 1;
|
||||||
checkCanCraftRecipes(currentRecipes, player.p.inv);
|
|
||||||
sortRecipes(currentRecipes);
|
|
||||||
} else if(currentTalkSel==2) {
|
|
||||||
currentNPCVal = 1;
|
|
||||||
|
|
||||||
currentTalkSel = 0;
|
data->currentTalkSel = 0;
|
||||||
currentTalkDone = false;
|
data->currentTalkDone = false;
|
||||||
currentTalkOptions = 1;
|
data->currentTalkOptions = 1;
|
||||||
currentTalkOption0 = "...";
|
data->currentTalkOption0 = "...";
|
||||||
|
|
||||||
currentTalk0 = "For quite some time now this";
|
data->currentTalk0 = "For quite some time now this";
|
||||||
currentTalk1 = "village has been tyrannized";
|
data->currentTalk1 = "village has been tyrannized";
|
||||||
currentTalk2 = "by a powerfull Air Wizard.";
|
data->currentTalk2 = "by a powerfull Air Wizard.";
|
||||||
currentTalk3 = "We are the only ones who";
|
data->currentTalk3 = "We are the only ones who";
|
||||||
currentTalk4 = "still have not given up";
|
data->currentTalk4 = "still have not given up";
|
||||||
currentTalk5 = "our old homes.";
|
data->currentTalk5 = "our old homes.";
|
||||||
}
|
}
|
||||||
} else if(currentNPCVal==1) {
|
} else if(data->currentNPCVal==1) {
|
||||||
if(currentTalkSel==0) {
|
if(data->currentTalkSel==0) {
|
||||||
currentNPCVal = 2;
|
data->currentNPCVal = 2;
|
||||||
|
|
||||||
currentTalkSel = 0;
|
data->currentTalkSel = 0;
|
||||||
currentTalkDone = false;
|
data->currentTalkDone = false;
|
||||||
currentTalkOptions = 1;
|
data->currentTalkOptions = 1;
|
||||||
currentTalkOption0 = "...";
|
data->currentTalkOption0 = "...";
|
||||||
|
|
||||||
currentTalk0 = "Most of the time the wizard";
|
data->currentTalk0 = "Most of the time the wizard";
|
||||||
currentTalk1 = "hides somewhere in the";
|
data->currentTalk1 = "hides somewhere in the";
|
||||||
currentTalk2 = "cloudes. They can only be";
|
data->currentTalk2 = "cloudes. They can only be";
|
||||||
currentTalk3 = "reached by a stairwell";
|
data->currentTalk3 = "reached by a stairwell";
|
||||||
currentTalk4 = "protected by an almost";
|
data->currentTalk4 = "protected by an almost";
|
||||||
currentTalk5 = "undestroyable stone barrier.";
|
data->currentTalk5 = "undestroyable stone barrier.";
|
||||||
}
|
}
|
||||||
} else if(currentNPCVal==2) {
|
} else if(data->currentNPCVal==2) {
|
||||||
if(currentTalkSel==0) {
|
if(data->currentTalkSel==0) {
|
||||||
currentNPCVal = 3;
|
data->currentNPCVal = 3;
|
||||||
|
|
||||||
currentTalkSel = 0;
|
data->currentTalkSel = 0;
|
||||||
currentTalkDone = false;
|
data->currentTalkDone = false;
|
||||||
currentTalkOptions = 1;
|
data->currentTalkOptions = 1;
|
||||||
currentTalkOption0 = "...";
|
data->currentTalkOption0 = "...";
|
||||||
|
|
||||||
currentTalk0 = "I am guessing you would ";
|
data->currentTalk0 = "I am guessing you would ";
|
||||||
currentTalk1 = "need tools atleast as";
|
data->currentTalk1 = "need tools atleast as";
|
||||||
currentTalk2 = "strong as diamonds to be";
|
data->currentTalk2 = "strong as diamonds to be";
|
||||||
currentTalk3 = "able to destroy it.";
|
data->currentTalk3 = "able to destroy it.";
|
||||||
currentTalk4 = "";
|
data->currentTalk4 = "";
|
||||||
currentTalk5 = "";
|
data->currentTalk5 = "";
|
||||||
}
|
}
|
||||||
} else if(currentNPCVal==3) {
|
} else if(data->currentNPCVal==3) {
|
||||||
if(currentTalkSel==0) {
|
if(data->currentTalkSel==0) {
|
||||||
currentNPCVal = 4;
|
data->currentNPCVal = 4;
|
||||||
|
|
||||||
currentTalkSel = 0;
|
data->currentTalkSel = 0;
|
||||||
currentTalkDone = false;
|
data->currentTalkDone = false;
|
||||||
currentTalkOptions = 2;
|
data->currentTalkOptions = 2;
|
||||||
currentTalkOption0 = "Let me do it!";
|
data->currentTalkOption0 = "Let me do it!";
|
||||||
currentTalkOption1 = "I am not sure";
|
data->currentTalkOption1 = "I am not sure";
|
||||||
|
|
||||||
currentTalk0 = "I am willing to give an";
|
data->currentTalk0 = "I am willing to give an";
|
||||||
currentTalk1 = "ancient artifact passed";
|
data->currentTalk1 = "ancient artifact passed";
|
||||||
currentTalk2 = "down over generations to";
|
data->currentTalk2 = "down over generations to";
|
||||||
currentTalk3 = "anybody who manages to";
|
data->currentTalk3 = "anybody who manages to";
|
||||||
currentTalk4 = "chase the wizard away and";
|
data->currentTalk4 = "chase the wizard away and";
|
||||||
currentTalk5 = "come back with proof.";
|
data->currentTalk5 = "come back with proof.";
|
||||||
}
|
}
|
||||||
} else if(currentNPCVal==4) {
|
} else if(data->currentNPCVal==4) {
|
||||||
currentMenu = MENU_NONE;
|
pd->ingameMenu = MENU_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NPC_FARMER:
|
case NPC_FARMER:
|
||||||
if(currentNPCMenu==NPC_MENU_TALK && currentTalkDone) {
|
if(data->currentNPCMenu==NPC_MENU_TALK && data->currentTalkDone) {
|
||||||
if(currentNPCVal==0) {
|
if(data->currentNPCVal==0) {
|
||||||
if(currentTalkSel==0) {
|
if(data->currentTalkSel==0) {
|
||||||
currentMenu = MENU_NONE;
|
pd->ingameMenu = MENU_NONE;
|
||||||
} else if(currentTalkSel==1) {
|
} else if(data->currentTalkSel==1) {
|
||||||
currentRecipes = &farmerTrades;
|
openCraftingMenu(pd, &farmerTrades, "Trading");
|
||||||
currentCraftTitle = "Trading";
|
|
||||||
currentMenu = MENU_CRAFTING;
|
|
||||||
checkCanCraftRecipes(currentRecipes, player.p.inv);
|
|
||||||
sortRecipes(currentRecipes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NPC_LIBRARIAN:
|
case NPC_LIBRARIAN:
|
||||||
if(currentNPCMenu==NPC_MENU_TALK && currentTalkDone) {
|
if(data->currentNPCMenu==NPC_MENU_TALK && data->currentTalkDone) {
|
||||||
if(currentNPCVal==0) {
|
if(data->currentNPCVal==0) {
|
||||||
if(currentTalkSel==0) {
|
if(data->currentTalkSel==0) {
|
||||||
currentMenu = MENU_NONE;
|
pd->ingameMenu = MENU_NONE;
|
||||||
} else if(currentTalkSel==1) {
|
} else if(data->currentTalkSel==1) {
|
||||||
currentNPCVal = 2;
|
data->currentNPCVal = 2;
|
||||||
|
|
||||||
currentTalkSel = 0;
|
data->currentTalkSel = 0;
|
||||||
currentTalkDone = false;
|
data->currentTalkDone = false;
|
||||||
currentTalkOptions = 1;
|
data->currentTalkOptions = 1;
|
||||||
currentTalkOption0 = "Ok";
|
data->currentTalkOption0 = "Ok";
|
||||||
|
|
||||||
currentTalk0 = "The books in this dungeon";
|
data->currentTalk0 = "The books in this dungeon";
|
||||||
currentTalk1 = "house secrets that cannot be";
|
data->currentTalk1 = "house secrets that cannot be";
|
||||||
currentTalk2 = "found anywhere else in the";
|
data->currentTalk2 = "found anywhere else in the";
|
||||||
currentTalk3 = "world. So I came to study";
|
data->currentTalk3 = "world. So I came to study";
|
||||||
currentTalk4 = "them. Most are written in";
|
data->currentTalk4 = "them. Most are written in";
|
||||||
currentTalk5 = "an ancient language.";
|
data->currentTalk5 = "an ancient language.";
|
||||||
} else if(currentTalkSel==2) {
|
} else if(data->currentTalkSel==2) {
|
||||||
currentNPCVal = 1;
|
data->currentNPCVal = 1;
|
||||||
|
|
||||||
currentTalkSel = 0;
|
data->currentTalkSel = 0;
|
||||||
currentTalkDone = false;
|
data->currentTalkDone = false;
|
||||||
currentTalkOptions = 2;
|
data->currentTalkOptions = 2;
|
||||||
currentTalkOption0 = "I need to think about it";
|
data->currentTalkOption0 = "I need to think about it";
|
||||||
currentTalkOption1 = "Here they are";
|
data->currentTalkOption1 = "Here they are";
|
||||||
|
|
||||||
currentTalk0 = "So you have met a dwarf but";
|
data->currentTalk0 = "So you have met a dwarf but";
|
||||||
currentTalk1 = "had a little communication";
|
data->currentTalk1 = "had a little communication";
|
||||||
currentTalk2 = "problem? I do have a dwarvish";
|
data->currentTalk2 = "problem? I do have a dwarvish";
|
||||||
currentTalk3 = "translation book but I havent";
|
data->currentTalk3 = "translation book but I havent";
|
||||||
currentTalk4 = "read it yet. For 10 Gold bars";
|
data->currentTalk4 = "read it yet. For 10 Gold bars";
|
||||||
currentTalk5 = "I will give it to you anyway.";
|
data->currentTalk5 = "I will give it to you anyway.";
|
||||||
}
|
}
|
||||||
} else if(currentNPCVal==1) {
|
} else if(data->currentNPCVal==1) {
|
||||||
if(currentTalkSel==0) {
|
if(data->currentTalkSel==0) {
|
||||||
currentMenu = MENU_NONE;
|
pd->ingameMenu = MENU_NONE;
|
||||||
} else if(currentTalkSel==1) {
|
} else if(data->currentTalkSel==1) {
|
||||||
currentNPCVal = 2;
|
data->currentNPCVal = 2;
|
||||||
|
|
||||||
currentTalkSel = 0;
|
data->currentTalkSel = 0;
|
||||||
currentTalkDone = false;
|
data->currentTalkDone = false;
|
||||||
currentTalkOptions = 1;
|
data->currentTalkOptions = 1;
|
||||||
currentTalkOption0 = "";
|
data->currentTalkOption0 = "";
|
||||||
|
|
||||||
if(countItemInv(ITEM_GOLDINGOT,0,player.p.inv)>=10) {
|
if(countItemInv(ITEM_GOLDINGOT, 0, &(pd->inventory))>=10) {
|
||||||
//remove gold from player inventory
|
//remove gold from player inventory
|
||||||
//TODO: Maybe I should make a generic substract items method sometime
|
//TODO: Maybe I should make a generic substract items method sometime
|
||||||
Item* item = getItemFromInventory(ITEM_GOLDINGOT, player.p.inv);
|
Item* item = getItemFromInventory(ITEM_GOLDINGOT, &(pd->inventory));
|
||||||
item->countLevel -= 10;
|
item->countLevel -= 10;
|
||||||
if(item->countLevel < 1) removeItemFromInventory(item->slotNum, player.p.inv);
|
if(item->countLevel < 1) removeItemFromInventory(item->slotNum, &(pd->inventory));
|
||||||
|
|
||||||
questManager.questlines[1].currentQuest = 2;
|
questManager->questlines[1].currentQuest = 2;
|
||||||
|
|
||||||
currentTalk0 = "Thank you these will be";
|
data->currentTalk0 = "Thank you these will be";
|
||||||
currentTalk1 = "really helpful.";
|
data->currentTalk1 = "really helpfull.";
|
||||||
currentTalk2 = "Here take this book with";
|
data->currentTalk2 = "Here take this book with";
|
||||||
currentTalk3 = "it you should be able to";
|
data->currentTalk3 = "it you should be able to";
|
||||||
currentTalk4 = "easily understand anything";
|
data->currentTalk4 = "easily understand anything";
|
||||||
currentTalk5 = "a dwarf can say.";
|
data->currentTalk5 = "a dwarf can say.";
|
||||||
|
|
||||||
currentTalkOption0 = "Thanks";
|
data->currentTalkOption0 = "Thanks";
|
||||||
} else {
|
} else {
|
||||||
currentTalk0 = "You do not seem to have";
|
data->currentTalk0 = "You do not seem to have";
|
||||||
currentTalk1 = "enough Gold Bars with you.";
|
data->currentTalk1 = "enough Gold Bars with you.";
|
||||||
currentTalk2 = "";
|
data->currentTalk2 = "";
|
||||||
currentTalk3 = "Ask again when you have";
|
data->currentTalk3 = "Ask again when you have";
|
||||||
currentTalk4 = "collected the 10 Bars.";
|
data->currentTalk4 = "collected the 10 Bars.";
|
||||||
currentTalk5 = "";
|
data->currentTalk5 = "";
|
||||||
|
|
||||||
currentTalkOption0 = "Ok";
|
data->currentTalkOption0 = "Ok";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(currentNPCVal==2) {
|
} else if(data->currentNPCVal==2) {
|
||||||
if(currentTalkSel==0) {
|
if(data->currentTalkSel==0) {
|
||||||
currentMenu = MENU_NONE;
|
pd->ingameMenu = MENU_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NPC_DWARF:
|
case NPC_DWARF:
|
||||||
if(questManager.questlines[1].currentQuest<=1) {
|
if(questManager->questlines[1].currentQuest<=1) {
|
||||||
if(currentNPCMenu==NPC_MENU_TALK && currentTalkDone) {
|
if(data->currentNPCMenu==NPC_MENU_TALK && data->currentTalkDone) {
|
||||||
if(currentNPCVal==0) currentMenu = MENU_NONE;
|
if(data->currentNPCVal==0) pd->ingameMenu = MENU_NONE;
|
||||||
}
|
}
|
||||||
} else if(questManager.questlines[1].currentQuest==2) {
|
} else if(questManager->questlines[1].currentQuest==2) {
|
||||||
if(currentNPCMenu==NPC_MENU_TALK && currentTalkDone) {
|
if(data->currentNPCMenu==NPC_MENU_TALK && data->currentTalkDone) {
|
||||||
if(currentTalkSel==0) {
|
if(data->currentTalkSel==0) {
|
||||||
currentMenu = MENU_NONE;
|
pd->ingameMenu = MENU_NONE;
|
||||||
} else if(currentTalkSel==1) {
|
} else if(data->currentTalkSel==1) {
|
||||||
currentRecipes = &dwarfTrades;
|
openCraftingMenu(pd, &dwarfTrades, "Trading");
|
||||||
currentCraftTitle = "Trading";
|
|
||||||
currentMenu = MENU_CRAFTING;
|
|
||||||
checkCanCraftRecipes(currentRecipes, player.p.inv);
|
|
||||||
sortRecipes(currentRecipes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -383,44 +394,44 @@ void tickNPCMenu() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderTalkMenu(char * name) {
|
void renderTalkMenu(NPC_MenuData *data, char * name) {
|
||||||
renderFrame(1,1,24,14,0xFFFF1010);
|
renderFrame(1,1,24,14,0xFFFF1010);
|
||||||
drawTextColor(name,24+1,14+1,0xFF000000);
|
drawTextColor(name,24+1,14+1,0xFF000000);
|
||||||
drawTextColor(name,24,14,0xFF6FE2E2);
|
drawTextColor(name,24,14,0xFF6FE2E2);
|
||||||
|
|
||||||
drawText(currentTalk0, 32, 32);
|
drawText(data->currentTalk0, 32, 32);
|
||||||
drawText(currentTalk1, 32, 48);
|
drawText(data->currentTalk1, 32, 48);
|
||||||
drawText(currentTalk2, 32, 64);
|
drawText(data->currentTalk2, 32, 64);
|
||||||
drawText(currentTalk3, 32, 80);
|
drawText(data->currentTalk3, 32, 80);
|
||||||
drawText(currentTalk4, 32, 96);
|
drawText(data->currentTalk4, 32, 96);
|
||||||
drawText(currentTalk5, 32, 112);
|
drawText(data->currentTalk5, 32, 112);
|
||||||
|
|
||||||
if(currentTalkOptions>=3) drawText(currentTalkOption2, 64, 147);
|
if(data->currentTalkOptions>=3) drawText(data->currentTalkOption2, 64, 147);
|
||||||
if(currentTalkOptions>=2) drawText(currentTalkOption1, 64, 171);
|
if(data->currentTalkOptions>=2) drawText(data->currentTalkOption1, 64, 171);
|
||||||
if(currentTalkOptions>=1) drawText(currentTalkOption0, 64, 195);
|
if(data->currentTalkOptions>=1) drawText(data->currentTalkOption0, 64, 195);
|
||||||
|
|
||||||
if(currentTalkOptions>=3 && currentTalkSel==2) drawText(">", 48, 147);
|
if(data->currentTalkOptions>=3 && data->currentTalkSel==2) drawText(">", 48, 147);
|
||||||
if(currentTalkOptions>=2 && currentTalkSel==1) drawText(">", 48, 171);
|
if(data->currentTalkOptions>=2 && data->currentTalkSel==1) drawText(">", 48, 171);
|
||||||
if(currentTalkOptions>=1 && currentTalkSel==0) drawText(">", 48, 195);
|
if(data->currentTalkOptions>=1 && data->currentTalkSel==0) drawText(">", 48, 195);
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderNPCMenu(int xscr, int yscr) {
|
void renderNPCMenu(NPC_MenuData *data) {
|
||||||
//TODO: Handle upon currentNPC as well as the fitting quest progress
|
//TODO: Handle upon currentNPC as well as the fitting quest progress
|
||||||
switch(currentNPC) {
|
switch(data->currentNPC) {
|
||||||
case NPC_GIRL:
|
case NPC_GIRL:
|
||||||
if(currentNPCMenu==NPC_MENU_TALK) renderTalkMenu("Girl Jill");
|
if(data->currentNPCMenu==NPC_MENU_TALK) renderTalkMenu(data, "Maria");
|
||||||
break;
|
break;
|
||||||
case NPC_PRIEST:
|
case NPC_PRIEST:
|
||||||
if(currentNPCMenu==NPC_MENU_TALK) renderTalkMenu("Priest Brom");
|
if(data->currentNPCMenu==NPC_MENU_TALK) renderTalkMenu(data, "Priest Brom");
|
||||||
break;
|
break;
|
||||||
case NPC_FARMER:
|
case NPC_FARMER:
|
||||||
if(currentNPCMenu==NPC_MENU_TALK) renderTalkMenu("Farmer Garrow");
|
if(data->currentNPCMenu==NPC_MENU_TALK) renderTalkMenu(data, "Farmer Garrow");
|
||||||
break;
|
break;
|
||||||
case NPC_LIBRARIAN:
|
case NPC_LIBRARIAN:
|
||||||
if(currentNPCMenu==NPC_MENU_TALK) renderTalkMenu("Librarian Ajihad");
|
if(data->currentNPCMenu==NPC_MENU_TALK) renderTalkMenu(data, "Librarian Ajihad");
|
||||||
break;
|
break;
|
||||||
case NPC_DWARF:
|
case NPC_DWARF:
|
||||||
if(currentNPCMenu==NPC_MENU_TALK) renderTalkMenu("Dwarf Orik");
|
if(data->currentNPCMenu==NPC_MENU_TALK) renderTalkMenu(data, "Dwarf Orik");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +1,25 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "render.h"
|
#include "QuestsData.h"
|
||||||
|
#include "Player.h"
|
||||||
#include "Crafting.h"
|
#include "Crafting.h"
|
||||||
|
|
||||||
#define NPC_MENU_TALK 0
|
#define NPC_MENU_TALK 0
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int currentQuest;
|
|
||||||
bool currentQuestDone;
|
|
||||||
} Questline;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int size;
|
|
||||||
Questline * questlines;
|
|
||||||
} QuestlineManager;
|
|
||||||
|
|
||||||
QuestlineManager questManager;
|
|
||||||
|
|
||||||
RecipeManager priestTrades;
|
RecipeManager priestTrades;
|
||||||
RecipeManager farmerTrades;
|
RecipeManager farmerTrades;
|
||||||
RecipeManager dwarfTrades;
|
RecipeManager dwarfTrades;
|
||||||
|
|
||||||
void initQuests();
|
void initTrades();
|
||||||
void resetQuests();
|
void freeTrades();
|
||||||
void freeQuests();
|
|
||||||
|
|
||||||
void openNPCMenu(int npc);
|
void initQuests(QuestlineManager *questManager);
|
||||||
|
void resetQuests(QuestlineManager *questManager);
|
||||||
|
void freeQuests(QuestlineManager *questManager);
|
||||||
|
|
||||||
void renderNPCMenu(int xscr, int yscr);
|
void resetNPCMenuData(NPC_MenuData *data);
|
||||||
void tickNPCMenu();
|
void openNPCMenu(PlayerData *pd, int npc);
|
||||||
|
void tickNPCMenu(PlayerData *pd);
|
||||||
|
void renderNPCMenu(NPC_MenuData *data);
|
||||||
|
|
35
source/QuestsData.h
Normal file
35
source/QuestsData.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <3ds.h>
|
||||||
|
|
||||||
|
typedef struct _questline {
|
||||||
|
int currentQuest;
|
||||||
|
bool currentQuestDone;
|
||||||
|
} Questline;
|
||||||
|
|
||||||
|
typedef struct _questlineManager {
|
||||||
|
int size;
|
||||||
|
Questline * questlines;
|
||||||
|
} QuestlineManager;
|
||||||
|
|
||||||
|
typedef struct _npcMenuData {
|
||||||
|
u8 currentNPC;
|
||||||
|
|
||||||
|
int currentNPCMenu;
|
||||||
|
int currentNPCVal;
|
||||||
|
|
||||||
|
int currentTalkSel;
|
||||||
|
bool currentTalkDone;
|
||||||
|
int currentTalkOptions;
|
||||||
|
char * currentTalkOption0;
|
||||||
|
char * currentTalkOption1;
|
||||||
|
char * currentTalkOption2;
|
||||||
|
char * currentTalk0;
|
||||||
|
char * currentTalk1;
|
||||||
|
char * currentTalk2;
|
||||||
|
char * currentTalk3;
|
||||||
|
char * currentTalk4;
|
||||||
|
char * currentTalk5;
|
||||||
|
} NPC_MenuData;
|
||||||
|
|
||||||
|
//TODO: Actually move the data here
|
473
source/Render.c
473
source/Render.c
|
@ -1,5 +1,7 @@
|
||||||
#include "Render.h"
|
#include "Render.h"
|
||||||
|
|
||||||
|
extern u32 syncTickCount;
|
||||||
|
|
||||||
void render(s32 xp, s32 yp, u32 xTile, u32 yTile, u8 bits) {
|
void render(s32 xp, s32 yp, u32 xTile, u32 yTile, u8 bits) {
|
||||||
xp -= offsetX;
|
xp -= offsetX;
|
||||||
yp -= offsetY;
|
yp -= offsetY;
|
||||||
|
@ -158,10 +160,18 @@ void render32(s32 xp, s32 yp, u32 xTile, u32 yTile, u8 bits) {
|
||||||
scaleX, scaleY);
|
scaleX, scaleY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int playerScale = 2;
|
||||||
|
void renderp(s32 xp, s32 yp, u32 xTile, u32 yTile) {
|
||||||
|
xp -= offsetX;
|
||||||
|
yp -= offsetY;
|
||||||
|
int scaleX = playerScale, scaleY = playerScale;
|
||||||
|
sf2d_draw_texture_part_scale(playerSprites, xp << 1, yp << 1, xTile, yTile, 16, 16,
|
||||||
|
scaleX, scaleY);
|
||||||
|
}
|
||||||
|
|
||||||
void renderTitle(int x, int y) {
|
void renderTitle(int x, int y) {
|
||||||
sf2d_draw_texture_part_scale(icons, (x - 26) << 1, y << 1, 0, 240, 104, 16,
|
sf2d_draw_texture_part_scale(icons, (x - 26) << 1, y << 1, 0, 240, 104, 16, 2.0, 2.0); // MINICRAFT
|
||||||
2.0, 2.0); // MINICRAFT
|
sf2d_draw_texture_part(icons, x + 48, y + 44, 104, 240, 152, 16); // 3DS HOMEBREW EDITION
|
||||||
sf2d_draw_texture_part(icons, x + 48, y + 52, 104, 240, 152, 16); // 3DS HOMEBREW EDITION
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderButtonIcon(u32 keyIcon, int x, int y, float scale) {
|
void renderButtonIcon(u32 keyIcon, int x, int y, float scale) {
|
||||||
|
@ -294,24 +304,23 @@ void freeLightBakes() {
|
||||||
sf2d_free_texture(glowwormBigLightBake);
|
sf2d_free_texture(glowwormBigLightBake);
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderLightsToStencil(bool force, bool invert, bool rplayer) {
|
void renderLightsToStencil(PlayerData *pd, bool force, bool invert, bool rplayer) {
|
||||||
if (force || (currentLevel > 1 && currentLevel != 5)) {
|
if (force || (pd->entity.level > 1 && pd->entity.level != 5)) {
|
||||||
C3D_DepthTest(true, GPU_NEVER, 0);
|
C3D_DepthTest(true, GPU_NEVER, 0);
|
||||||
C3D_StencilTest(true, GPU_NEVER, 1, 0xFF, 0xFF);
|
C3D_StencilTest(true, GPU_NEVER, 1, 0xFF, 0xFF);
|
||||||
C3D_StencilOp(GPU_STENCIL_REPLACE, GPU_STENCIL_KEEP, GPU_STENCIL_KEEP);
|
C3D_StencilOp(GPU_STENCIL_REPLACE, GPU_STENCIL_KEEP, GPU_STENCIL_KEEP);
|
||||||
C3D_AlphaTest(true, GPU_GREATER, 0);
|
C3D_AlphaTest(true, GPU_GREATER, 0);
|
||||||
|
|
||||||
|
if(pd->activeItem->id == ITEM_LANTERN) renderLight(pd->entity.x, pd->entity.y, lanternLightBake);
|
||||||
if(player.p.activeItem->id == ITEM_LANTERN) renderLight(player.x, player.y, lanternLightBake);
|
else if(rplayer) renderLight(pd->entity.x, pd->entity.y, playerLightBake);
|
||||||
else if(rplayer) renderLight(player.x, player.y, playerLightBake);
|
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < eManager.lastSlot[currentLevel]; ++i) {
|
for (i = 0; i < eManager.lastSlot[pd->entity.level]; ++i) {
|
||||||
Entity e = eManager.entities[currentLevel][i];
|
Entity e = eManager.entities[pd->entity.level][i];
|
||||||
if (e.type == ENTITY_FURNITURE) {
|
if (e.type == ENTITY_FURNITURE) {
|
||||||
if (e.entityFurniture.itemID == ITEM_LANTERN && e.x > player.x - 160 && e.y > player.y - 125 && e.x < player.x + 160 && e.y < player.y + 125)
|
if (e.entityFurniture.itemID == ITEM_LANTERN && e.x > pd->entity.x - 160 && e.y > pd->entity.y - 125 && e.x < pd->entity.x + 160 && e.y < pd->entity.y + 125)
|
||||||
renderLight(e.x, e.y, lanternLightBake);
|
renderLight(e.x, e.y, lanternLightBake);
|
||||||
} else if(e.type == ENTITY_GLOWWORM && e.x > player.x - 160 && e.y > player.y - 125 && e.x < player.x + 160 && e.y < player.y + 125) { //TODO could be made smaller becuase of smaller light radius
|
} else if(e.type == ENTITY_GLOWWORM && e.x > pd->entity.x - 160 && e.y > pd->entity.y - 125 && e.x < pd->entity.x + 160 && e.y < pd->entity.y + 125) { //TODO could be made smaller becuase of smaller light radius
|
||||||
if(rand()%10==0) continue;
|
if(rand()%10==0) continue;
|
||||||
else if(rand()%100==0) renderLight(e.x+20, e.y-20, glowwormBigLightBake);
|
else if(rand()%100==0) renderLight(e.x+20, e.y-20, glowwormBigLightBake);
|
||||||
else renderLight(e.x+8, e.y-8, glowwormLightBake);
|
else renderLight(e.x+8, e.y-8, glowwormLightBake);
|
||||||
|
@ -325,9 +334,9 @@ void renderLightsToStencil(bool force, bool invert, bool rplayer) {
|
||||||
//TODO: Even this is not performant enough for old 3DS, when there is a lot of lava on screen
|
//TODO: Even this is not performant enough for old 3DS, when there is a lot of lava on screen
|
||||||
for (x = xo-2; x <= 13 + xo+2; ++x) {
|
for (x = xo-2; x <= 13 + xo+2; ++x) {
|
||||||
for (y = yo-2; y <= 8 + yo+2; ++y) {
|
for (y = yo-2; y <= 8 + yo+2; ++y) {
|
||||||
if(getTile(x, y) == TILE_LAVA) {
|
if(getTile(pd->entity.level, x, y) == TILE_LAVA) {
|
||||||
//experimental "speedhack"
|
//experimental "speedhack"
|
||||||
if(getTile(x+1,y)==TILE_LAVA && getTile(x-1,y)==TILE_LAVA && getTile(x,y+1)==TILE_LAVA && getTile(x,y-1)==TILE_LAVA) {
|
if(getTile(pd->entity.level, x+1,y)==TILE_LAVA && getTile(pd->entity.level, x-1,y)==TILE_LAVA && getTile(pd->entity.level, x,y+1)==TILE_LAVA && getTile(pd->entity.level, x,y-1)==TILE_LAVA) {
|
||||||
if((x+y)%2 == 0) continue;
|
if((x+y)%2 == 0) continue;
|
||||||
}
|
}
|
||||||
renderLight((x << 4) + 8, (y << 4) + 8, playerLightBake);
|
renderLight((x << 4) + 8, (y << 4) + 8, playerLightBake);
|
||||||
|
@ -348,10 +357,8 @@ void renderLightsToStencil(bool force, bool invert, bool rplayer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetStencilStuff() {
|
void resetStencilStuff() {
|
||||||
//if (currentLevel > 1) {
|
C3D_StencilTest(false, GPU_ALWAYS, 0x00, 0xFF, 0x00);
|
||||||
C3D_StencilTest(false, GPU_ALWAYS, 0x00, 0xFF, 0x00);
|
C3D_StencilOp(GPU_STENCIL_KEEP, GPU_STENCIL_KEEP, GPU_STENCIL_KEEP);
|
||||||
C3D_StencilOp(GPU_STENCIL_KEEP, GPU_STENCIL_KEEP, GPU_STENCIL_KEEP);
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderLight(int x, int y, sf2d_texture* texture) {
|
void renderLight(int x, int y, sf2d_texture* texture) {
|
||||||
|
@ -433,60 +440,60 @@ void resetSurrTiles() {
|
||||||
tdr = false;
|
tdr = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkSurrTiles8(int xt, int yt, int id) {
|
void checkSurrTiles8(u8 level, int xt, int yt, int id) {
|
||||||
if (getTile(xt, yt - 1) == id)
|
if (getTile(level, xt, yt - 1) == id)
|
||||||
tu = true;
|
tu = true;
|
||||||
if (getTile(xt - 1, yt) == id)
|
if (getTile(level, xt - 1, yt) == id)
|
||||||
tl = true;
|
tl = true;
|
||||||
if (getTile(xt + 1, yt) == id)
|
if (getTile(level, xt + 1, yt) == id)
|
||||||
tr = true;
|
tr = true;
|
||||||
if (getTile(xt, yt + 1) == id)
|
if (getTile(level, xt, yt + 1) == id)
|
||||||
td = true;
|
td = true;
|
||||||
if (getTile(xt - 1, yt - 1) == id)
|
if (getTile(level, xt - 1, yt - 1) == id)
|
||||||
tul = true;
|
tul = true;
|
||||||
if (getTile(xt + 1, yt - 1) == id)
|
if (getTile(level, xt + 1, yt - 1) == id)
|
||||||
tur = true;
|
tur = true;
|
||||||
if (getTile(xt - 1, yt + 1) == id)
|
if (getTile(level, xt - 1, yt + 1) == id)
|
||||||
tdl = true;
|
tdl = true;
|
||||||
if (getTile(xt + 1, yt + 1) == id)
|
if (getTile(level, xt + 1, yt + 1) == id)
|
||||||
tdr = true;
|
tdr = true;
|
||||||
}
|
}
|
||||||
void checkSurrTiles4(int xt, int yt, int id) {
|
void checkSurrTiles4(u8 level, int xt, int yt, int id) {
|
||||||
if (getTile(xt, yt - 1) == id)
|
if (getTile(level, xt, yt - 1) == id)
|
||||||
tu = true;
|
tu = true;
|
||||||
if (getTile(xt - 1, yt) == id)
|
if (getTile(level, xt - 1, yt) == id)
|
||||||
tl = true;
|
tl = true;
|
||||||
if (getTile(xt + 1, yt) == id)
|
if (getTile(level, xt + 1, yt) == id)
|
||||||
tr = true;
|
tr = true;
|
||||||
if (getTile(xt, yt + 1) == id)
|
if (getTile(level, xt, yt + 1) == id)
|
||||||
td = true;
|
td = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 tData = 0;
|
u8 tData = 0;
|
||||||
void renderTile(int i, int d, int x, int y) {
|
void renderTile(int i, int d, u8 level, int x, int y) {
|
||||||
int age = 0;
|
int age = 0;
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case TILE_GRASS:
|
case TILE_GRASS:
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_GRASS);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_GRASS);
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_TREE);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_TREE);
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_FLOWER);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_FLOWER);
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_SAPLING_TREE);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_SAPLING_TREE);
|
||||||
|
|
||||||
if(currentLevel==1 && season==3) renderConnectedTile4(x, y, 256, 112);
|
if(level==1 && worldData.season==3) renderConnectedTile4(x, y, 256, 112);
|
||||||
else if(currentLevel==1 && season==2) renderConnectedTile4(x, y, 256, 128);
|
else if(level==1 && worldData.season==2) renderConnectedTile4(x, y, 256, 128);
|
||||||
else renderConnectedTile4(x, y, 256, 0);
|
else renderConnectedTile4(x, y, 256, 0);
|
||||||
break;
|
break;
|
||||||
case TILE_TREE:
|
case TILE_TREE:
|
||||||
renderTile(TILE_GRASS, 0, x, y);
|
renderTile(TILE_GRASS, 0, level, x, y);
|
||||||
|
|
||||||
checkSurrTiles8(x >> 4, y >> 4, TILE_TREE);
|
checkSurrTiles8(level, x >> 4, y >> 4, TILE_TREE);
|
||||||
|
|
||||||
if(season==2) {
|
if(worldData.season==2) {
|
||||||
render(x, y, 352+((tu && tl && tul) ? 16 : 0), 96, 0);
|
render(x, y, 352+((tu && tl && tul) ? 16 : 0), 96, 0);
|
||||||
render(x+8, y, 360+((tu && tr && tur) ? 16 : 0), 96, 0);
|
render(x+8, y, 360+((tu && tr && tur) ? 16 : 0), 96, 0);
|
||||||
render(x, y+8, 352+((td && tl && tdl) ? 16 : 0), 104, 0);
|
render(x, y+8, 352+((td && tl && tdl) ? 16 : 0), 104, 0);
|
||||||
render(x+8, y+8, 360+((td && tr && tdr) ? 16 : 0), 104, 0);
|
render(x+8, y+8, 360+((td && tr && tdr) ? 16 : 0), 104, 0);
|
||||||
} else if(season==3) {
|
} else if(worldData.season==3) {
|
||||||
render(x, y, 352+((tu && tl && tul) ? 16 : 0), 112, 0);
|
render(x, y, 352+((tu && tl && tul) ? 16 : 0), 112, 0);
|
||||||
render(x+8, y, 360+((tu && tr && tur) ? 16 : 0), 112, 0);
|
render(x+8, y, 360+((tu && tr && tur) ? 16 : 0), 112, 0);
|
||||||
render(x, y+8, 352+((td && tl && tdl) ? 16 : 0), 120, 0);
|
render(x, y+8, 352+((td && tl && tdl) ? 16 : 0), 120, 0);
|
||||||
|
@ -500,28 +507,28 @@ void renderTile(int i, int d, int x, int y) {
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case TILE_ROCK:
|
case TILE_ROCK:
|
||||||
checkSurrTiles8(x >> 4, y >> 4, TILE_ROCK);
|
checkSurrTiles8(level, x >> 4, y >> 4, TILE_ROCK);
|
||||||
if(currentLevel>1)
|
if(level>1)
|
||||||
renderConnectedTile8(x, y, 256, 96);
|
renderConnectedTile8(x, y, 256, 96);
|
||||||
else
|
else
|
||||||
renderConnectedTile8(x, y, 336, 64);
|
renderConnectedTile8(x, y, 336, 64);
|
||||||
break;
|
break;
|
||||||
case TILE_HARDROCK:
|
case TILE_HARDROCK:
|
||||||
checkSurrTiles8(x >> 4, y >> 4, TILE_HARDROCK);
|
checkSurrTiles8(level, x >> 4, y >> 4, TILE_HARDROCK);
|
||||||
renderConnectedTile8(x, y, 416, 64);
|
renderConnectedTile8(x, y, 416, 64);
|
||||||
break;
|
break;
|
||||||
case TILE_DIRT: // render dots.
|
case TILE_DIRT: // render dots.
|
||||||
if (currentLevel > 1)
|
if (level > 1)
|
||||||
render16(x, y, 320, 80, 0);
|
render16(x, y, 320, 80, 0);
|
||||||
else
|
else
|
||||||
render16(x, y, 336, 80, 0);
|
render16(x, y, 336, 80, 0);
|
||||||
break;
|
break;
|
||||||
case TILE_SAND:
|
case TILE_SAND:
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_SAND);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_SAND);
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_CACTUS);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_CACTUS);
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_SAPLING_CACTUS);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_SAPLING_CACTUS);
|
||||||
|
|
||||||
if(currentLevel==1 && season==3) {
|
if(level==1 && worldData.season==3) {
|
||||||
renderConnectedTile4(x, y, 256, 112);
|
renderConnectedTile4(x, y, 256, 112);
|
||||||
} else {
|
} else {
|
||||||
renderConnectedTile4(x, y, 320, 0);
|
renderConnectedTile4(x, y, 320, 0);
|
||||||
|
@ -532,43 +539,43 @@ void renderTile(int i, int d, int x, int y) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TILE_WATER:
|
case TILE_WATER:
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_WATER);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_WATER);
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_HOLE);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_HOLE);
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_ICE);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_ICE);
|
||||||
|
|
||||||
renderConnectedTile4(x, y, 384, 0);
|
renderConnectedTile4(x, y, 384, 0);
|
||||||
|
|
||||||
srand((tickCount + (x / 2 - y) * 4311) / 10);
|
srand((syncTickCount + (x / 2 - y) * 4311) / 10);
|
||||||
renderDots(x, y, rand() & 3, rand() & 3, rand() & 3, rand() & 3, 288, 64);
|
renderDots(x, y, rand() & 3, rand() & 3, rand() & 3, rand() & 3, 288, 64);
|
||||||
break;
|
break;
|
||||||
case TILE_LAVA:
|
case TILE_LAVA:
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_LAVA);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_LAVA);
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_HOLE);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_HOLE);
|
||||||
|
|
||||||
renderConnectedTile4(x, y, 448, 0);
|
renderConnectedTile4(x, y, 448, 0);
|
||||||
|
|
||||||
srand((tickCount + (x / 2 - y) * 4311) / 10);
|
srand((syncTickCount + (x / 2 - y) * 4311) / 10);
|
||||||
renderDots(x, y, rand() & 3, rand() & 3, rand() & 3, rand() & 3, 304, 64);
|
renderDots(x, y, rand() & 3, rand() & 3, rand() & 3, rand() & 3, 304, 64);
|
||||||
break;
|
break;
|
||||||
case TILE_HOLE:
|
case TILE_HOLE:
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_HOLE);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_HOLE);
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_WATER);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_WATER);
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_LAVA);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_LAVA);
|
||||||
|
|
||||||
renderConnectedTile4(x, y, 256, 16);
|
renderConnectedTile4(x, y, 256, 16);
|
||||||
break;
|
break;
|
||||||
case TILE_CACTUS:
|
case TILE_CACTUS:
|
||||||
renderTile(TILE_SAND, 0, x, y);
|
renderTile(TILE_SAND, 0, level, x, y);
|
||||||
render16(x, y, 304, 48, 0);
|
render16(x, y, 304, 48, 0);
|
||||||
break;
|
break;
|
||||||
case TILE_FLOWER:
|
case TILE_FLOWER:
|
||||||
renderTile(TILE_GRASS, 0, x, y);
|
renderTile(TILE_GRASS, 0, level, x, y);
|
||||||
if(currentLevel==1 && season==3) render16(x, y, 320, 112, getData(x >> 4, y >> 4));
|
if(level==1 && worldData.season==3) render16(x, y, 320, 112, d);
|
||||||
else render16(x, y, 320, 48, getData(x >> 4, y >> 4));
|
else render16(x, y, 320, 48, d);
|
||||||
break;
|
break;
|
||||||
case TILE_STAIRS_DOWN:
|
case TILE_STAIRS_DOWN:
|
||||||
if (currentLevel == 0)
|
if (level == 0)
|
||||||
renderTile(TILE_CLOUD, 0, x, y);
|
renderTile(TILE_CLOUD, 0, level, x, y);
|
||||||
render16(x, y, 256, 64, 0);
|
render16(x, y, 256, 64, 0);
|
||||||
break;
|
break;
|
||||||
case TILE_STAIRS_UP:
|
case TILE_STAIRS_UP:
|
||||||
|
@ -584,60 +591,60 @@ void renderTile(int i, int d, int x, int y) {
|
||||||
render16(x, y, 496, 48, 0);
|
render16(x, y, 496, 48, 0);
|
||||||
break;
|
break;
|
||||||
case TILE_CLOUD:
|
case TILE_CLOUD:
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_CLOUD);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_CLOUD);
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_STAIRS_DOWN);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_STAIRS_DOWN);
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_CLOUDCACTUS);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_CLOUDCACTUS);
|
||||||
|
|
||||||
renderConnectedTile4(x, y, 320, 16);
|
renderConnectedTile4(x, y, 320, 16);
|
||||||
break;
|
break;
|
||||||
case TILE_CLOUDCACTUS:
|
case TILE_CLOUDCACTUS:
|
||||||
renderTile(TILE_CLOUD, 0, x, y);
|
renderTile(TILE_CLOUD, 0, level, x, y);
|
||||||
render16(x, y, 496, 64, 0);
|
render16(x, y, 496, 64, 0);
|
||||||
break;
|
break;
|
||||||
case TILE_SAPLING_TREE:
|
case TILE_SAPLING_TREE:
|
||||||
renderTile(TILE_GRASS, 0, x, y);
|
renderTile(TILE_GRASS, 0, level, x, y);
|
||||||
render16(x, y, 288, 48, 0);
|
render16(x, y, 288, 48, 0);
|
||||||
break;
|
break;
|
||||||
case TILE_SAPLING_CACTUS:
|
case TILE_SAPLING_CACTUS:
|
||||||
renderTile(TILE_SAND, 0, x, y);
|
renderTile(TILE_SAND, 0, level, x, y);
|
||||||
render16(x, y, 288, 48, 0);
|
render16(x, y, 288, 48, 0);
|
||||||
break;
|
break;
|
||||||
case TILE_FARM:
|
case TILE_FARM:
|
||||||
render16(x, y, 352, 48, 0);
|
render16(x, y, 352, 48, 0);
|
||||||
break;
|
break;
|
||||||
case TILE_WHEAT:
|
case TILE_WHEAT:
|
||||||
age = getData(x >> 4, y >> 4) / 20;
|
age = d / 20;
|
||||||
if (age > 5)
|
if (age > 5)
|
||||||
age = 5;
|
age = 5;
|
||||||
render16(x, y, 368 + (age << 4), 48, 0);
|
render16(x, y, 368 + (age << 4), 48, 0);
|
||||||
break;
|
break;
|
||||||
case TILE_WOOD_WALL:
|
case TILE_WOOD_WALL:
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_WOOD_WALL);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_WOOD_WALL);
|
||||||
|
|
||||||
renderConnectedTile4(x, y, 384, 16);
|
renderConnectedTile4(x, y, 384, 16);
|
||||||
break;
|
break;
|
||||||
case TILE_STONE_WALL:
|
case TILE_STONE_WALL:
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_STONE_WALL);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_STONE_WALL);
|
||||||
|
|
||||||
renderConnectedTile4(x, y, 256, 80);
|
renderConnectedTile4(x, y, 256, 80);
|
||||||
break;
|
break;
|
||||||
case TILE_IRON_WALL:
|
case TILE_IRON_WALL:
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_IRON_WALL);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_IRON_WALL);
|
||||||
|
|
||||||
renderConnectedTile4(x, y, 448, 16);
|
renderConnectedTile4(x, y, 448, 16);
|
||||||
break;
|
break;
|
||||||
case TILE_GOLD_WALL:
|
case TILE_GOLD_WALL:
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_GOLD_WALL);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_GOLD_WALL);
|
||||||
|
|
||||||
renderConnectedTile4(x, y, 256, 32);
|
renderConnectedTile4(x, y, 256, 32);
|
||||||
break;
|
break;
|
||||||
case TILE_GEM_WALL:
|
case TILE_GEM_WALL:
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_GEM_WALL);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_GEM_WALL);
|
||||||
|
|
||||||
renderConnectedTile4(x, y, 320, 32);
|
renderConnectedTile4(x, y, 320, 32);
|
||||||
break;
|
break;
|
||||||
case TILE_DUNGEON_WALL:
|
case TILE_DUNGEON_WALL:
|
||||||
checkSurrTiles8(x >> 4, y >> 4, TILE_DUNGEON_WALL);
|
checkSurrTiles8(level, x >> 4, y >> 4, TILE_DUNGEON_WALL);
|
||||||
|
|
||||||
renderConnectedTile8(x, y, 384, 32);
|
renderConnectedTile8(x, y, 384, 32);
|
||||||
break;
|
break;
|
||||||
|
@ -645,21 +652,22 @@ void renderTile(int i, int d, int x, int y) {
|
||||||
render16(x, y, 464 + d*16, 32, 0);
|
render16(x, y, 464 + d*16, 32, 0);
|
||||||
break;
|
break;
|
||||||
case TILE_DUNGEON_ENTRANCE:
|
case TILE_DUNGEON_ENTRANCE:
|
||||||
render16(x, y, 352 + (currentLevel==5 ? 16 : 0), 80, 0);
|
render16(x, y, 352 + (level==5 ? 16 : 0), 80, 0);
|
||||||
break;
|
break;
|
||||||
case TILE_MAGIC_BARRIER:
|
case TILE_MAGIC_BARRIER:
|
||||||
renderTile(TILE_DUNGEON_FLOOR, 0, x, y);
|
renderTile(TILE_DUNGEON_FLOOR, 0, level, x, y);
|
||||||
render16(x, y, 320, 64, getData(x >> 4, y >> 4));
|
render16(x, y, 320, 64, d);
|
||||||
|
|
||||||
//draw remaining pillar count
|
//draw remaining pillar count
|
||||||
if((player.x - (x+8))*(player.x - (x+8)) + (player.y - (y+8))*(player.y - (y+8)) <= 24*24) {
|
PlayerData *lp = getLocalPlayer();
|
||||||
|
if((lp->entity.x - (x+8))*(lp->entity.x - (x+8)) + (lp->entity.y - (y+8))*(lp->entity.y - (y+8)) <= 24*24) {
|
||||||
x -= offsetX;
|
x -= offsetX;
|
||||||
y -= offsetY;
|
y -= offsetY;
|
||||||
|
|
||||||
int data = 0;
|
int data = 0;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (i = 0; i < eManager.lastSlot[currentLevel]; ++i) {
|
for (i = 0; i < eManager.lastSlot[level]; ++i) {
|
||||||
Entity * e = &eManager.entities[currentLevel][i];
|
Entity * e = &eManager.entities[level][i];
|
||||||
|
|
||||||
if(e->type == ENTITY_MAGIC_PILLAR) {
|
if(e->type == ENTITY_MAGIC_PILLAR) {
|
||||||
++data;
|
++data;
|
||||||
|
@ -667,7 +675,7 @@ void renderTile(int i, int d, int x, int y) {
|
||||||
}
|
}
|
||||||
|
|
||||||
char currentCount[3];
|
char currentCount[3];
|
||||||
sprintf(currentCount,"%d", data);
|
sprintf(currentCount, "%d", data);
|
||||||
|
|
||||||
drawSizedTextColor(currentCount, x+4 + 1, y+4 + 1, 2, dungeonColor[1]);
|
drawSizedTextColor(currentCount, x+4 + 1, y+4 + 1, 2, dungeonColor[1]);
|
||||||
drawSizedTextColor(currentCount, x+4, y+4, 2, dungeonColor[0]);
|
drawSizedTextColor(currentCount, x+4, y+4, 2, dungeonColor[0]);
|
||||||
|
@ -675,7 +683,7 @@ void renderTile(int i, int d, int x, int y) {
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case TILE_BOOKSHELVES:
|
case TILE_BOOKSHELVES:
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_BOOKSHELVES);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_BOOKSHELVES);
|
||||||
|
|
||||||
renderConnectedTile4(x, y, 384, 80 + d*16);
|
renderConnectedTile4(x, y, 384, 80 + d*16);
|
||||||
break;
|
break;
|
||||||
|
@ -683,26 +691,26 @@ void renderTile(int i, int d, int x, int y) {
|
||||||
render16(x, y, 336, 96, 0);
|
render16(x, y, 336, 96, 0);
|
||||||
break;
|
break;
|
||||||
case TILE_MYCELIUM:
|
case TILE_MYCELIUM:
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_MYCELIUM);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_MYCELIUM);
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_MUSHROOM_BROWN);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_MUSHROOM_BROWN);
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_MUSHROOM_RED);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_MUSHROOM_RED);
|
||||||
|
|
||||||
if(currentLevel==1 && season==3) renderConnectedTile4(x, y, 256, 112);
|
if(level==1 && worldData.season==3) renderConnectedTile4(x, y, 256, 112);
|
||||||
else renderConnectedTile4(x, y, 448, 80);
|
else renderConnectedTile4(x, y, 448, 80);
|
||||||
break;
|
break;
|
||||||
case TILE_MUSHROOM_BROWN:
|
case TILE_MUSHROOM_BROWN:
|
||||||
renderTile(TILE_MYCELIUM, 0, x, y);
|
renderTile(TILE_MYCELIUM, 0, level, x, y);
|
||||||
render16(x, y, 448 + (d&0x1)*16, 96, 0);
|
render16(x, y, 448 + (d&0x1)*16, 96, 0);
|
||||||
break;
|
break;
|
||||||
case TILE_MUSHROOM_RED:
|
case TILE_MUSHROOM_RED:
|
||||||
renderTile(TILE_MYCELIUM, 0, x, y);
|
renderTile(TILE_MYCELIUM, 0, level, x, y);
|
||||||
render16(x, y, 480 + (d&0x1)*16, 96, 0);
|
render16(x, y, 480 + (d&0x1)*16, 96, 0);
|
||||||
break;
|
break;
|
||||||
case TILE_ICE:
|
case TILE_ICE:
|
||||||
renderTile(TILE_WATER, 0, x, y);
|
renderTile(TILE_WATER, 0, level, x, y);
|
||||||
//checkSurrTiles4(x >> 4, y >> 4, TILE_WATER);
|
//checkSurrTiles4(x >> 4, y >> 4, TILE_WATER);
|
||||||
//checkSurrTiles4(x >> 4, y >> 4, TILE_HOLE);
|
//checkSurrTiles4(x >> 4, y >> 4, TILE_HOLE);
|
||||||
checkSurrTiles4(x >> 4, y >> 4, TILE_ICE);
|
checkSurrTiles4(level, x >> 4, y >> 4, TILE_ICE);
|
||||||
|
|
||||||
renderConnectedTile4(x, y, 448, 112);
|
renderConnectedTile4(x, y, 448, 112);
|
||||||
break;
|
break;
|
||||||
|
@ -747,70 +755,78 @@ void renderConnectedTile8(int x, int y, u32 xTile, u32 yTile) {
|
||||||
render(x+8, y+8, xTile+8+r+d+((tr && td && tdr) ? 16 : 0), yTile+8, 0);
|
render(x+8, y+8, xTile+8+r+d+((tr && td && tdr) ? 16 : 0), yTile+8, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderZoomedMap() {
|
void renderZoomedMap(PlayerData *pd) {
|
||||||
sf2d_draw_rectangle(0, 0, 320, 240, 0xFF0C0C0C); //You might think "real" black would be better, but it actually looks better that way
|
sf2d_draw_rectangle(0, 0, 320, 240, 0xFF0C0C0C); //You might think "real" black would be better, but it actually looks better that way
|
||||||
|
|
||||||
int mx = mScrollX;
|
int mx = pd->mapScrollX;
|
||||||
int my = mScrollY;
|
int my = pd->mapScrollY;
|
||||||
if(zoomLevel == 2) mx = 32;
|
if(pd->mapZoomLevel == 2) mx = 32;
|
||||||
sf2d_draw_texture_scale(minimap[currentLevel], mx, my, zoomLevel, zoomLevel); // zoomed map
|
sf2d_draw_texture_scale(minimap[pd->entity.level], mx, my, pd->mapZoomLevel, pd->mapZoomLevel); // zoomed map
|
||||||
|
|
||||||
// Airwizard on zoomed map
|
// Airwizard on zoomed map
|
||||||
if(currentLevel == 0){
|
if(pd->entity.level == 0){
|
||||||
if(awX != 0 && awY != 0){
|
if(awX != 0 && awY != 0){
|
||||||
render16c(
|
render16c(
|
||||||
(mx+((awX/16)*zoomLevel)-16)/2,
|
(mx+((awX/16)*pd->mapZoomLevel)-16)/2,
|
||||||
(my+((awY/16)*zoomLevel)-16)/2,
|
(my+((awY/16)*pd->mapZoomLevel)-16)/2,
|
||||||
160, 112,
|
160, 112,
|
||||||
((player.p.walkDist >> 6) & 1) == 0 ? 0 : 1,
|
((pd->entity.p.walkDist >> 6) & 1) == 0 ? 0 : 1,
|
||||||
2, 2
|
2, 2
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Player on zoomed map
|
// Player on zoomed map
|
||||||
|
//TODO: Maybe also render other players?
|
||||||
render16c(
|
render16c(
|
||||||
(mx+((player.x/16)*zoomLevel)-16)/2,
|
(mx+((pd->entity.x/16)*pd->mapZoomLevel)-16)/2,
|
||||||
(my+((player.y/16)*zoomLevel)-16)/2,
|
(my+((pd->entity.y/16)*pd->mapZoomLevel)-16)/2,
|
||||||
0, 112,
|
0, 112,
|
||||||
((player.p.walkDist >> 6) & 1) == 0 ? 0 : 1,
|
((pd->entity.p.walkDist >> 6) & 1) == 0 ? 0 : 1,
|
||||||
2, 2
|
2, 2
|
||||||
);
|
);
|
||||||
|
|
||||||
drawText(mapText,224, 214); // "x2"/"x4"/"x6"
|
drawText(pd->mapText,224, 214); // "x2"/"x4"/"x6"
|
||||||
render16(142, 2, 72, 208, 0); // Exit button
|
render16(142, 2, 72, 208, 0); // Exit button
|
||||||
renderc(126, 102, 40, 208, 32, 16, 0); // Plus/Minus zoom buttons
|
renderc(126, 102, 40, 208, 32, 16, 0); // Plus/Minus zoom buttons
|
||||||
if(zoomLevel < 3) sf2d_draw_rectangle(258, 210, 26, 20, 0x7F4F4F4F); // gray out minus button
|
if(pd->mapZoomLevel < 3) sf2d_draw_rectangle(258, 210, 26, 20, 0x7F4F4F4F); // gray out minus button
|
||||||
else if(zoomLevel > 5) sf2d_draw_rectangle(284, 210, 26, 20, 0x7F4F4F4F); // gray out minus button
|
else if(pd->mapZoomLevel > 5) sf2d_draw_rectangle(284, 210, 26, 20, 0x7F4F4F4F); // gray out minus button
|
||||||
}
|
}
|
||||||
|
|
||||||
char scoreT[32];
|
char scoreT[32];
|
||||||
void renderGui() {
|
void renderGui(PlayerData *pd) {
|
||||||
int i;
|
int i;
|
||||||
|
//health and stamina
|
||||||
for (i = 0; i < 10; ++i) {
|
for (i = 0; i < 10; ++i) {
|
||||||
if (i < player.p.health)
|
if (i < pd->entity.p.health)
|
||||||
render(i * 8 + 6, 5, 168, 152, 0);
|
render(i * 8 + 6, 5, 168, 152, 0);
|
||||||
else
|
else
|
||||||
render(i * 8 + 6, 5, 176, 152, 0);
|
render(i * 8 + 6, 5, 176, 152, 0);
|
||||||
if (i < player.p.stamina)
|
if (i < pd->entity.p.stamina)
|
||||||
render(i * 8 + 6, 14, 184, 152, 0);
|
render(i * 8 + 6, 14, 184, 152, 0);
|
||||||
else
|
else
|
||||||
render(i * 8 + 6, 14, 191, 152, 0);
|
render(i * 8 + 6, 14, 191, 152, 0);
|
||||||
}
|
}
|
||||||
sf2d_draw_texture(minimap[currentLevel], 10, 102);
|
|
||||||
renderItemWithTextCentered(player.p.activeItem, 320, 66);
|
//minimap
|
||||||
itoa(player.p.score, scoreT, 10); // integer to base10 string
|
sf2d_draw_texture(minimap[pd->entity.level], 10, 102);
|
||||||
|
|
||||||
|
//active item
|
||||||
|
renderItemWithTextCentered(pd->activeItem, 320, 66);
|
||||||
|
itoa(pd->score, scoreT, 10); // integer to base10 string
|
||||||
drawText("Score:",214,12);
|
drawText("Score:",214,12);
|
||||||
drawText(scoreT,(140-(strlen(scoreT)*12))/2 + 180,29);
|
drawText(scoreT,(140-(strlen(scoreT)*12))/2 + 180,29);
|
||||||
if(currentLevel == 0){
|
if(pd->entity.level == 0){
|
||||||
if(awX != 0 && awY != 0){
|
if(awX != 0 && awY != 0){
|
||||||
renderc(1 + (awX/32), 47 + (awY/32), 88, 216, 8, 8, 0); // Mini-AWizard head.
|
renderc(1 + (awX/32), 47 + (awY/32), 88, 216, 8, 8, 0); // Mini-AWizard head.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
renderc(1 + (player.x/32), 47 + (player.y/32), 88, 208, 8, 8, 0); // Mini-Player head.
|
//TODO: Maybe also render other players?
|
||||||
|
renderc(1 + (pd->entity.x/32), 47 + (pd->entity.y/32), 88, 208, 8, 8, 0); // Mini-Player head.
|
||||||
|
|
||||||
//quick select
|
//quick select
|
||||||
drawText("Quickselect:",164,118);
|
drawText("Quickselect:",164,118);
|
||||||
|
|
||||||
Inventory * inv = player.p.inv;
|
Inventory * inv = &(pd->inventory);
|
||||||
Item * item;
|
Item * item;
|
||||||
for (i = 0; i < 8; ++i) {
|
for (i = 0; i < 8; ++i) {
|
||||||
if((inv->lastSlot) > i) {
|
if((inv->lastSlot) > i) {
|
||||||
|
@ -823,103 +839,112 @@ void renderGui() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderPlayer() {
|
void renderPlayer(PlayerData *pd) {
|
||||||
if (player.p.isDead)
|
if (pd->entity.level!=getLocalPlayer()->entity.level) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (pd->entity.p.isDead) {
|
||||||
return;
|
return;
|
||||||
int xo = player.x - 8;
|
}
|
||||||
int yo = player.y - 8;
|
int xo = pd->entity.x - 8;
|
||||||
|
int yo = pd->entity.y - 8;
|
||||||
|
|
||||||
if (player.p.attackTimer > 0 && player.p.dir == 1) {
|
//attack animation upwards
|
||||||
|
if (pd->entity.p.attackTimer > 0 && pd->entity.p.dir == 1) {
|
||||||
renderc(xo, yo - 4, 16, 160, 16, 8, 0);
|
renderc(xo, yo - 4, 16, 160, 16, 8, 0);
|
||||||
renderItemIcon(player.p.activeItem->id, player.p.activeItem->countLevel,
|
renderItemIcon(pd->activeItem->id, pd->activeItem->countLevel, xo + 4, yo - 4);
|
||||||
xo + 4, yo - 4);
|
|
||||||
}
|
|
||||||
u8 walk = (player.p.walkDist >> 4) & 1;
|
|
||||||
bool swimming = isSwimming();
|
|
||||||
switch (player.p.dir) {
|
|
||||||
case 0: // down
|
|
||||||
if (swimming)
|
|
||||||
renderc(xo, yo + 4, 48,
|
|
||||||
160 + (((player.p.swimTimer >> 4) & 1) << 3), 16, 8, 0);
|
|
||||||
else
|
|
||||||
renderc(xo, yo + 8, 0, 120 + (player.p.isCarrying ? 16 : 0), 16, 8,
|
|
||||||
walk == 0 ? 0 : 1);
|
|
||||||
renderc(xo, yo, 0, 112 + (player.p.isCarrying ? 16 : 0), 16, 8,
|
|
||||||
walk == 0 ? 0 : 1);
|
|
||||||
break;
|
|
||||||
case 1: // up
|
|
||||||
if (swimming)
|
|
||||||
renderc(xo, yo + 4, 48,
|
|
||||||
160 + (((player.p.swimTimer >> 4) & 1) << 3), 16, 8, 0);
|
|
||||||
else
|
|
||||||
renderc(xo, yo + 8, 16, 120 + (player.p.isCarrying ? 16 : 0), 16, 8,
|
|
||||||
walk == 0 ? 0 : 1);
|
|
||||||
renderc(xo, yo, 16, 112 + (player.p.isCarrying ? 16 : 0), 16, 8,
|
|
||||||
walk == 0 ? 0 : 1);
|
|
||||||
break;
|
|
||||||
case 2: // left
|
|
||||||
if (swimming)
|
|
||||||
renderc(xo, yo + 4, 48,
|
|
||||||
160 + (((player.p.swimTimer >> 4) & 1) << 3), 16, 8, 0);
|
|
||||||
else
|
|
||||||
renderc(xo, yo + 8, 32 + (walk << 4),
|
|
||||||
120 + (player.p.isCarrying ? 16 : 0), 16, 8, 1);
|
|
||||||
renderc(xo, yo, 32 + (walk << 4), 112 + (player.p.isCarrying ? 16 : 0),
|
|
||||||
16, 8, 1);
|
|
||||||
break;
|
|
||||||
case 3: // right
|
|
||||||
if (swimming)
|
|
||||||
renderc(xo, yo + 4, 48,
|
|
||||||
160 + (((player.p.swimTimer >> 4) & 1) << 3), 16, 8, 0);
|
|
||||||
else
|
|
||||||
renderc(xo, yo + 8, 32 + (walk << 4),
|
|
||||||
120 + (player.p.isCarrying ? 16 : 0), 16, 8, 0);
|
|
||||||
renderc(xo, yo, 32 + (walk << 4), 112 + (player.p.isCarrying ? 16 : 0),
|
|
||||||
16, 8, 0);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (player.p.isCarrying) {
|
//find basic indices
|
||||||
renderFurniture(player.p.activeItem->id, xo, yo - 12);
|
int aIndexBig = 0;
|
||||||
|
int aIndexSmall = 0;
|
||||||
|
switch(pd->entity.p.dir) {
|
||||||
|
case 0: //down
|
||||||
|
aIndexBig = 0;
|
||||||
|
aIndexSmall = 0;
|
||||||
|
break;
|
||||||
|
case 1: //up
|
||||||
|
aIndexBig = 2;
|
||||||
|
aIndexSmall = 1;
|
||||||
|
break;
|
||||||
|
case 2: //left
|
||||||
|
aIndexBig = 7;
|
||||||
|
aIndexSmall = 3;
|
||||||
|
break;
|
||||||
|
case 3: //right
|
||||||
|
aIndexBig = 4;
|
||||||
|
aIndexSmall = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//find index offset based on walk state
|
||||||
|
u8 walkingOffset = (pd->entity.p.walkDist >> 4) % 2;
|
||||||
|
if(pd->entity.p.dir==2 || pd->entity.p.dir==3) {
|
||||||
|
walkingOffset = (pd->entity.p.walkDist >> 4) % 4;
|
||||||
|
if(walkingOffset==2) walkingOffset = 0;
|
||||||
|
if(walkingOffset==3) walkingOffset = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool swimming = isWater(pd->entity.level, pd->entity.x>>4, pd->entity.y>>4);
|
||||||
|
|
||||||
|
//render water anim when swimming
|
||||||
|
if (swimming) {
|
||||||
|
renderc(xo, yo + 5, 48, 160 + (((pd->entity.p.swimTimer >> 4) & 1) << 3), 16, 8, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//render the different parts
|
||||||
|
//legs
|
||||||
|
if(!swimming) {
|
||||||
|
renderp(xo, yo, (0+aIndexBig+walkingOffset)*16, pd->sprite.legs*16);
|
||||||
|
}
|
||||||
|
//body
|
||||||
|
renderp(xo, yo, (10+aIndexBig+walkingOffset)*16, pd->sprite.body*16);
|
||||||
|
//arms (normal)
|
||||||
|
if(!(pd->entity.p.isCarrying)) {
|
||||||
|
renderp(xo, yo, (20+aIndexBig+walkingOffset)*16, pd->sprite.arms*16);
|
||||||
|
}
|
||||||
|
//head
|
||||||
|
renderp(xo, yo, (30+aIndexSmall)*16, pd->sprite.head*16);
|
||||||
|
//eyes
|
||||||
|
renderp(xo, yo, (34+aIndexSmall)*16, pd->sprite.eyes*16);
|
||||||
|
//arms (carrying)
|
||||||
|
if(pd->entity.p.isCarrying) {
|
||||||
|
renderp(xo, yo, (38+aIndexSmall)*16, pd->sprite.arms*16);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//furniture
|
||||||
|
if (pd->entity.p.isCarrying) {
|
||||||
|
renderFurniture(pd->activeItem->id, xo, yo - 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (player.p.attackTimer > 0) {
|
//attack animation (other directios)
|
||||||
switch (player.p.dir) {
|
if (pd->entity.p.attackTimer > 0) {
|
||||||
|
switch (pd->entity.p.dir) {
|
||||||
case 0:
|
case 0:
|
||||||
renderc(xo - player.p.ax, yo - player.p.ay + 12, 16, 168, 16, 8, 0);
|
renderc(xo - pd->entity.p.ax, yo - pd->entity.p.ay + 12, 16, 168, 16, 8, 0);
|
||||||
renderItemIcon(player.p.activeItem->id,
|
renderItemIcon(pd->activeItem->id, pd->activeItem->countLevel, xo + 4, yo + 12);
|
||||||
player.p.activeItem->countLevel, xo + 4, yo + 12);
|
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
renderc(xo - player.p.ax - 4, yo - player.p.ay, 32, 160, 8, 16, 0);
|
renderc(xo - pd->entity.p.ax - 4, yo - pd->entity.p.ay, 32, 160, 8, 16, 0);
|
||||||
renderItemIcon(player.p.activeItem->id,
|
renderItemIcon(pd->activeItem->id, pd->activeItem->countLevel, xo - 4, yo + 4);
|
||||||
player.p.activeItem->countLevel, xo - 4, yo + 4);
|
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
renderc(xo - player.p.ax + 12, yo - player.p.ay, 40, 160, 8, 16, 0);
|
renderc(xo - pd->entity.p.ax + 12, yo - pd->entity.p.ay, 40, 160, 8, 16, 0);
|
||||||
renderItemIcon(player.p.activeItem->id,
|
renderItemIcon(pd->activeItem->id, pd->activeItem->countLevel, xo + 12, yo + 4);
|
||||||
player.p.activeItem->countLevel, xo + 12, yo + 4);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderMenuBackground(int xScroll, int yScroll) {
|
void renderWeather(u8 level, int xScroll, int yScroll) {
|
||||||
sf2d_draw_rectangle(0, 0, 400, 240, 0xFF0C0C0C); //You might think "real" black would be better, but it actually looks better that way
|
if(level==1) {
|
||||||
renderLightsToStencil(false, false, true);
|
if(worldData.season==3) {
|
||||||
renderBackground(xScroll, yScroll);
|
int xp = -128 + ((syncTickCount>>2) - xScroll*2)%128;
|
||||||
resetStencilStuff();
|
int yp = -128 + ((syncTickCount>>1) - yScroll*2)%128;
|
||||||
|
int xp2 = 0 - ((syncTickCount>>2) + xScroll*2)%128;
|
||||||
renderDayNight();
|
int yp2 = -128 + ((syncTickCount>>1)+64 - yScroll*2)%128;
|
||||||
}
|
|
||||||
|
|
||||||
void renderWeather(int xScroll, int yScroll) {
|
|
||||||
if(currentLevel==1) {
|
|
||||||
if(season==3) {
|
|
||||||
int xp = -128 + ((tickCount>>2) - xScroll*2)%128;
|
|
||||||
int yp = -128 + ((tickCount>>1) - yScroll*2)%128;
|
|
||||||
int xp2 = 0 - ((tickCount>>2) + xScroll*2)%128;
|
|
||||||
int yp2 = -128 + ((tickCount>>1)+64 - yScroll*2)%128;
|
|
||||||
int xt;
|
int xt;
|
||||||
int yt;
|
int yt;
|
||||||
for(xt=0; xt<4; ++xt) {
|
for(xt=0; xt<4; ++xt) {
|
||||||
|
@ -930,11 +955,11 @@ void renderWeather(int xScroll, int yScroll) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(rain) {
|
if(worldData.rain) {
|
||||||
int xp = -((xScroll*2)%128);
|
int xp = -((xScroll*2)%128);
|
||||||
int yp = -128 + ((tickCount<<2) - yScroll*2)%128;
|
int yp = -128 + ((syncTickCount<<2) - yScroll*2)%128;
|
||||||
int xp2 = -((xScroll*2+8)%128);
|
int xp2 = -((xScroll*2+8)%128);
|
||||||
int yp2 = -128 + ((tickCount<<1)+64 - yScroll*2)%128;
|
int yp2 = -128 + ((syncTickCount<<1)+64 - yScroll*2)%128;
|
||||||
int xt;
|
int xt;
|
||||||
int yt;
|
int yt;
|
||||||
for(xt=0; xt<4; ++xt) {
|
for(xt=0; xt<4; ++xt) {
|
||||||
|
@ -947,46 +972,46 @@ void renderWeather(int xScroll, int yScroll) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderDayNight() {
|
void renderDayNight(PlayerData *pd) {
|
||||||
if(currentLevel==1 && (daytime<6000 || daytime>18000)) {
|
if(pd->entity.level==1 && (worldData.daytime<6000 || worldData.daytime>18000)) {
|
||||||
int color1 = 0x000C0C0C;
|
int color1 = 0x000C0C0C;
|
||||||
int color2 = 0x00100C0C;
|
int color2 = 0x00100C0C;
|
||||||
int alpha1 = 0x88;
|
int alpha1 = 0x88;
|
||||||
int alpha2 = 0xDD;
|
int alpha2 = 0xDD;
|
||||||
|
|
||||||
if(daytime>5000 && daytime<6000) {
|
if(worldData.daytime>5000 && worldData.daytime<6000) {
|
||||||
alpha1 = (alpha1 * (1000-(daytime-5000)))/1000;
|
alpha2 = (alpha2 * (1000-(worldData.daytime-5000)))/1000;
|
||||||
alpha2 = (alpha2 * (1000-(daytime-5000)))/1000;
|
alpha1 = (alpha1 * (1000-(worldData.daytime-5000)))/1000;
|
||||||
} else if(daytime>18000 && daytime<19000) {
|
} else if(worldData.daytime>18000 && worldData.daytime<19000) {
|
||||||
alpha1 = (alpha1 * (daytime-18000))/1000;
|
alpha1 = (alpha1 * (worldData.daytime-18000))/1000;
|
||||||
alpha2 = (alpha2 * (daytime-18000))/1000;
|
alpha2 = (alpha2 * (worldData.daytime-18000))/1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
color1 = color1 | (alpha1 << 24);
|
color1 = color1 | (alpha1 << 24);
|
||||||
color2 = color2 | (alpha2 << 24);
|
color2 = color2 | (alpha2 << 24);
|
||||||
|
|
||||||
sf2d_draw_rectangle(0, 0, 400, 240, color1); //You might think "real" black would be better, but it actually looks better that way
|
sf2d_draw_rectangle(0, 0, 400, 240, color1); //You might think "real" black would be better, but it actually looks better that way
|
||||||
renderLightsToStencil(true, true, false);
|
renderLightsToStencil(pd, true, true, false);
|
||||||
sf2d_draw_rectangle(0, 0, 400, 240, color2); //You might think "real" black would be better, but it actually looks better that way
|
sf2d_draw_rectangle(0, 0, 400, 240, color2); //You might think "real" black would be better, but it actually looks better that way
|
||||||
resetStencilStuff();
|
resetStencilStuff();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderBackground(int xScroll, int yScroll) {
|
void renderBackground(s8 level, int xScroll, int yScroll) {
|
||||||
if(currentLevel == 0) {
|
if(level == 0) {
|
||||||
sf2d_draw_texture_part_scale(minimap[1], (-xScroll / 3) - 256, (-yScroll / 3) - 32, 0, 0, 128, 128, 12.5, 7.5);
|
sf2d_draw_texture_part_scale(minimap[1], (-xScroll / 3) - 256, (-yScroll / 3) - 32, 0, 0, 128, 128, 12.5, 7.5);
|
||||||
sf2d_draw_rectangle(0, 0, 400, 240, 0xAFDFDFDF);
|
sf2d_draw_rectangle(0, 0, 400, 240, 0xAFDFDFDF);
|
||||||
} else if(currentLevel == 5) {
|
} else if(level == 5) {
|
||||||
sf2d_draw_rectangle(0, 0, 400, 240, dungeonColor[1]);
|
sf2d_draw_rectangle(0, 0, 400, 240, dungeonColor[1]);
|
||||||
} else {
|
} else {
|
||||||
sf2d_draw_rectangle(0, 0, 400, 240, dirtColor[currentLevel]); // dirt color
|
sf2d_draw_rectangle(0, 0, 400, 240, dirtColor[level]); // dirt color
|
||||||
}
|
}
|
||||||
int xo = xScroll >> 4;
|
int xo = xScroll >> 4;
|
||||||
int yo = yScroll >> 4;
|
int yo = yScroll >> 4;
|
||||||
int x, y;
|
int x, y;
|
||||||
for (x = xo; x <= 13 + xo; ++x) {
|
for (x = xo; x <= 13 + xo; ++x) {
|
||||||
for (y = yo; y <= 8 + yo; ++y)
|
for (y = yo; y <= 8 + yo; ++y)
|
||||||
renderTile(getTile(x, y), getData(x, y), x << 4, y << 4);
|
renderTile(getTile(level, x, y), getData(level, x, y), level, x << 4, y << 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1166,10 +1191,10 @@ void renderEntity(Entity* e, int x, int y) {
|
||||||
case ENTITY_AIRWIZARD:
|
case ENTITY_AIRWIZARD:
|
||||||
e->wizard.spriteAdjust = 0;
|
e->wizard.spriteAdjust = 0;
|
||||||
if (e->wizard.health < 200) {
|
if (e->wizard.health < 200) {
|
||||||
if (tickCount / 4 % 3 < 2)
|
if (syncTickCount / 4 % 3 < 2)
|
||||||
e->wizard.spriteAdjust = 16;
|
e->wizard.spriteAdjust = 16;
|
||||||
} else if (e->wizard.health < 1000) {
|
} else if (e->wizard.health < 1000) {
|
||||||
if (tickCount / 5 % 4 < 2)
|
if (syncTickCount / 5 % 4 < 2)
|
||||||
e->wizard.spriteAdjust = 16;
|
e->wizard.spriteAdjust = 16;
|
||||||
}
|
}
|
||||||
switch (e->wizard.dir) {
|
switch (e->wizard.dir) {
|
||||||
|
@ -1294,10 +1319,10 @@ void renderEntity(Entity* e, int x, int y) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderEntities(int x, int y, EntityManager* em) {
|
void renderEntities(u8 level, int x, int y, EntityManager* em) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < em->lastSlot[currentLevel]; ++i) {
|
for (i = 0; i < em->lastSlot[level]; ++i) {
|
||||||
Entity e = em->entities[currentLevel][i];
|
Entity e = em->entities[level][i];
|
||||||
if (e.x > x - 200 && e.y > y - 125 && e.x < x + 200 && e.y < y + 125)
|
if (e.x > x - 200 && e.y > y - 125 && e.x < x + 200 && e.y < y + 125)
|
||||||
renderEntity(&e, e.x, e.y);
|
renderEntity(&e, e.x, e.y);
|
||||||
}
|
}
|
||||||
|
@ -1663,8 +1688,8 @@ void renderItemIcon(int itemID, int countLevel, int x, int y) {
|
||||||
render(x, y, 64, 168, 0);
|
render(x, y, 64, 168, 0);
|
||||||
break;
|
break;
|
||||||
case TOOL_MAGIC_COMPASS:
|
case TOOL_MAGIC_COMPASS:
|
||||||
xd = compassData[currentLevel][0] - (player.x>>4);
|
xd = worldData.compassData[getLocalPlayer()->entity.level][0] - (getLocalPlayer()->entity.x>>4);
|
||||||
yd = compassData[currentLevel][1] - (player.y>>4);
|
yd = worldData.compassData[getLocalPlayer()->entity.level][1] - (getLocalPlayer()->entity.y>>4);
|
||||||
if(abs(yd)>abs(xd)) {
|
if(abs(yd)>abs(xd)) {
|
||||||
if(yd<0) render(x, y, 112, 168, 0);
|
if(yd<0) render(x, y, 112, 168, 0);
|
||||||
else render(x, y, 120, 168, 0);
|
else render(x, y, 120, 168, 0);
|
||||||
|
|
|
@ -12,6 +12,7 @@ sf2d_texture *lanternLightBake;
|
||||||
sf2d_texture *glowwormLightBake;
|
sf2d_texture *glowwormLightBake;
|
||||||
sf2d_texture *glowwormBigLightBake;
|
sf2d_texture *glowwormBigLightBake;
|
||||||
int offsetX, offsetY;
|
int offsetX, offsetY;
|
||||||
|
int playerScale;
|
||||||
|
|
||||||
void render(s32 xp, s32 yp, u32 xTile, u32 yTile, u8 bits);
|
void render(s32 xp, s32 yp, u32 xTile, u32 yTile, u8 bits);
|
||||||
void renderb(s32 xp, s32 yp, u32 xTile, u32 yTile, u8 bits, u32 color);
|
void renderb(s32 xp, s32 yp, u32 xTile, u32 yTile, u8 bits, u32 color);
|
||||||
|
@ -26,25 +27,24 @@ void render32(s32 xp, s32 yp, u32 xTile, u32 yTile, u8 bits);
|
||||||
|
|
||||||
void renderTitle(int x, int y);
|
void renderTitle(int x, int y);
|
||||||
void renderFrame(int x1, int y1, int x2, int y2, u32 bgColor);
|
void renderFrame(int x1, int y1, int x2, int y2, u32 bgColor);
|
||||||
void renderTile(int i, int d, int x, int y);
|
void renderTile(int i, int d, u8 level, int x, int y);
|
||||||
void renderConnectedTile4(int x, int y, u32 xTile, u32 yTile);
|
void renderConnectedTile4(int x, int y, u32 xTile, u32 yTile);
|
||||||
void renderConnectedTile8(int x, int y, u32 xTile, u32 yTile);
|
void renderConnectedTile8(int x, int y, u32 xTile, u32 yTile);
|
||||||
void renderBackground(int xScroll, int yScroll);
|
void renderBackground(s8 level, int xScroll, int yScroll);
|
||||||
void renderMenuBackground(int xScroll, int yScroll); //Renders the darkness
|
void renderWeather(u8 level, int xScroll, int yScroll);
|
||||||
void renderWeather(int xScroll, int yScroll);
|
void renderDayNight(PlayerData *pd);
|
||||||
void renderDayNight();
|
|
||||||
void renderButtonIcon(u32 icon, int x, int y, float scale);
|
void renderButtonIcon(u32 icon, int x, int y, float scale);
|
||||||
|
|
||||||
void bakeLights();
|
void bakeLights();
|
||||||
void freeLightBakes();
|
void freeLightBakes();
|
||||||
void renderLightsToStencil(bool force, bool invert, bool rplayer);
|
void renderLightsToStencil(PlayerData *pd, bool force, bool invert, bool rplayer);
|
||||||
void resetStencilStuff();
|
void resetStencilStuff();
|
||||||
void bakeLight(sf2d_texture* texture, int x, int y, int r);
|
void bakeLight(sf2d_texture* texture, int x, int y, int r);
|
||||||
void renderLight(int x, int y, sf2d_texture* texture);
|
void renderLight(int x, int y, sf2d_texture* texture);
|
||||||
|
|
||||||
void renderGui();
|
void renderGui(PlayerData *pd);
|
||||||
void renderZoomedMap();
|
void renderZoomedMap(PlayerData *pd);
|
||||||
void renderPlayer();
|
void renderPlayer(PlayerData *pd);
|
||||||
|
|
||||||
void drawText(char * msg, u32 x, u32 y);
|
void drawText(char * msg, u32 x, u32 y);
|
||||||
void drawSizedText(char * msg, u32 x, u32 y, float size);
|
void drawSizedText(char * msg, u32 x, u32 y, float size);
|
||||||
|
@ -54,7 +54,7 @@ void drawSizedTextColor(char * msg, int x, int y, float size, u32 color);
|
||||||
|
|
||||||
void renderFurniture(int itemID, int x, int y);
|
void renderFurniture(int itemID, int x, int y);
|
||||||
void renderEntity(Entity* e, int x, int y);
|
void renderEntity(Entity* e, int x, int y);
|
||||||
void renderEntities(int x, int y, EntityManager* em);
|
void renderEntities(u8 level, int x, int y, EntityManager* em);
|
||||||
|
|
||||||
void renderRecipes(RecipeManager * r, int xo, int yo, int x1, int y1, int selected);
|
void renderRecipes(RecipeManager * r, int xo, int yo, int x1, int y1, int selected);
|
||||||
void renderItemList(Inventory * inv, int xo, int yo, int x1, int y1, int selected);
|
void renderItemList(Inventory * inv, int xo, int yo, int x1, int y1, int selected);
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "SaveLoad.h"
|
#include "SaveLoad.h"
|
||||||
|
|
||||||
|
#include "ZipHelper.h"
|
||||||
|
|
||||||
bool entityIsImportant(Entity * e){
|
bool entityIsImportant(Entity * e){
|
||||||
switch(e->type){
|
switch(e->type){
|
||||||
case ENTITY_AIRWIZARD:
|
case ENTITY_AIRWIZARD:
|
||||||
|
@ -30,39 +32,118 @@ s16 calculateImportantEntites(EntityManager * eManager, int level){
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void saveCurrentWorld(char * filename, EntityManager * eManager, Entity * player, u8 * map, u8 * mapData){
|
//helper methods
|
||||||
FILE * file = fopen(filename, "wb");
|
char **files;
|
||||||
int i,j;
|
int fileCount;
|
||||||
|
|
||||||
// Player Data
|
void saveTrackFileReset() {
|
||||||
fwrite(&player->p.score, sizeof(int), 1, file);
|
if(files!=NULL) {
|
||||||
fwrite(&player->p.hasWonSaved, sizeof(bool), 1, file);
|
for(int i=0; i<fileCount; i++) {
|
||||||
fwrite(&player->p.health, sizeof(s16), 1, file);
|
free(files[i]);
|
||||||
fwrite(&player->x, sizeof(s16), 1, file);
|
}
|
||||||
fwrite(&player->y, sizeof(s16), 1, file);
|
free(files);
|
||||||
fwrite(¤tLevel, sizeof(s8), 1, file);
|
}
|
||||||
|
|
||||||
|
files = NULL;
|
||||||
|
fileCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int saveTrackFile(char *filename) {
|
||||||
|
//test if entry allready present
|
||||||
|
for(int i=0; i<fileCount; i++) {
|
||||||
|
if(strcmp(filename, files[i])==0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//add new entry
|
||||||
|
fileCount++;
|
||||||
|
char **newFiles = realloc(files, fileCount*sizeof(char*));
|
||||||
|
if(!newFiles) {
|
||||||
|
for(int i=0; i<fileCount-1; i++) {
|
||||||
|
free(files[i]);
|
||||||
|
}
|
||||||
|
free(files);
|
||||||
|
files = NULL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
files = newFiles;
|
||||||
|
files[fileCount-1] = malloc(strlen(filename)+1);
|
||||||
|
strcpy(files[fileCount-1], filename);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveDeleteTrackedFiles() {
|
||||||
|
for(int i=0; i<fileCount; i++) {
|
||||||
|
remove(files[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool saveFileCopy(char *target, char*source) {
|
||||||
|
char buffer[SAVE_COPYBUFFER_SIZE];
|
||||||
|
|
||||||
|
FILE *in = fopen(source, "rb");
|
||||||
|
if(in==NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
FILE *out = fopen(target, "wb");
|
||||||
|
if(out==NULL) {
|
||||||
|
fclose(out);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size;
|
||||||
|
do {
|
||||||
|
size = fread(buffer, 1, SAVE_COPYBUFFER_SIZE, in);
|
||||||
|
|
||||||
|
if(size>0) {
|
||||||
|
fwrite(buffer, 1, size, out);
|
||||||
|
}
|
||||||
|
} while(size>0);
|
||||||
|
|
||||||
|
fclose(in);
|
||||||
|
fclose(out);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//internal save methods
|
||||||
|
void saveInventory(Inventory *inv, EntityManager *eManager, FILE *file) {
|
||||||
|
fwrite(&inv->lastSlot, sizeof(s16), 1, file); // write amount of items in inventory;
|
||||||
|
for(int j = 0; j < inv->lastSlot; ++j) {
|
||||||
|
fwrite(&(inv->items[j].id), sizeof(s16), 1, file); // write ID of item
|
||||||
|
fwrite(&(inv->items[j].countLevel), sizeof(s16), 1, file); // write count/level of item
|
||||||
|
fwrite(&(inv->items[j].onlyOne), sizeof(bool), 1, file);
|
||||||
|
if(inv->items[j].id == ITEM_CHEST){
|
||||||
|
int invIndex = inv->items[j].chestPtr - eManager->invs;
|
||||||
|
fwrite(&invIndex, sizeof(int), 1, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveWorldInternal(char *filename, EntityManager *eManager, WorldData *worldData) {
|
||||||
|
FILE * file = fopen(filename, "wb"); //TODO: should be checked
|
||||||
|
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
//write savefile version
|
||||||
|
int version = SAVE_VERSION;
|
||||||
|
fwrite(&version, sizeof(int), 1, file);
|
||||||
|
|
||||||
// Inventory Data
|
// Inventory Data
|
||||||
fwrite(&eManager->nextInv, sizeof(s16), 1, file); // write amount of inventories.
|
fwrite(&eManager->nextInv, sizeof(s16), 1, file); // write amount of inventories.
|
||||||
for(i = 0; i < eManager->nextInv; ++i) {
|
for(i = 0; i < eManager->nextInv; ++i) {
|
||||||
fwrite(&eManager->invs[i].lastSlot, sizeof(s16), 1, file); // write amount of items in inventory;
|
saveInventory(&(eManager->invs[i]), eManager, file);
|
||||||
for(j = 0; j < eManager->invs[i].lastSlot; ++j) {
|
|
||||||
fwrite(&eManager->invs[i].items[j].id, sizeof(s16), 1, file); // write ID of item
|
|
||||||
fwrite(&eManager->invs[i].items[j].countLevel, sizeof(s16), 1, file); // write count/level of item
|
|
||||||
fwrite(&eManager->invs[i].items[j].onlyOne, sizeof(bool), 1, file);
|
|
||||||
if(eManager->invs[i].items[j].id == ITEM_CHEST){
|
|
||||||
int invIndex = eManager->invs[i].items[j].chestPtr - eManager->invs;
|
|
||||||
fwrite(&invIndex, sizeof(int), 1, file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Entity Data
|
// Entity Data
|
||||||
for(i = 0; i < 5; ++i){
|
for(i = 0; i < 5; ++i) { //for every level (except dungeon of course)
|
||||||
int amount = calculateImportantEntites(eManager,i);
|
int amount = calculateImportantEntites(eManager,i);
|
||||||
fwrite(&amount, sizeof(s16), 1, file); // read amount of entities in level.
|
fwrite(&amount, sizeof(s16), 1, file); // read amount of entities in level.
|
||||||
for(j = 0; j < eManager->lastSlot[i]; ++j){
|
for(j = 0; j < eManager->lastSlot[i]; ++j){
|
||||||
if(!entityIsImportant(&eManager->entities[i][j])) continue;
|
if(!entityIsImportant(&eManager->entities[i][j])) continue;
|
||||||
|
|
||||||
fwrite(&eManager->entities[i][j].type, sizeof(s16), 1, file); // write entity's type ID
|
fwrite(&eManager->entities[i][j].type, sizeof(s16), 1, file); // write entity's type ID
|
||||||
fwrite(&eManager->entities[i][j].x, sizeof(s16), 1, file); // write entity's x coordinate
|
fwrite(&eManager->entities[i][j].x, sizeof(s16), 1, file); // write entity's x coordinate
|
||||||
fwrite(&eManager->entities[i][j].y, sizeof(s16), 1, file); // write entity's y coordinate
|
fwrite(&eManager->entities[i][j].y, sizeof(s16), 1, file); // write entity's y coordinate
|
||||||
|
@ -104,327 +185,479 @@ void saveCurrentWorld(char * filename, EntityManager * eManager, Entity * player
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Day/season Data
|
||||||
|
fwrite(&worldData->daytime, sizeof(u16), 1, file);
|
||||||
|
fwrite(&worldData->day, sizeof(int), 1, file);
|
||||||
|
fwrite(&worldData->season, sizeof(u8), 1, file);
|
||||||
|
fwrite(&worldData->rain, sizeof(bool), 1, file);
|
||||||
|
|
||||||
|
// Compass Data
|
||||||
|
fwrite(worldData->compassData, sizeof(u8), 6*3, file); //x,y of choosen stair and count per level
|
||||||
|
|
||||||
// Map Data
|
// Map Data
|
||||||
//Don't write or load dungeon, so only first 5 levels not 6
|
//Don't write or load dungeon, so only first 5 levels not 6
|
||||||
fwrite(map, sizeof(u8), 128*128*5, file); // Map Tile IDs, 128*128*5 bytes = 80KB
|
fwrite(worldData->map, sizeof(u8), 128*128*5, file); // Map Tile IDs, 128*128*5 bytes = 80KB
|
||||||
fwrite(mapData, sizeof(u8), 128*128*5, file); // Map Tile Data (Damage done to trees/rocks, age of wheat & saplings, etc). 80KB
|
fwrite(worldData->data, sizeof(u8), 128*128*5, file); // Map Tile Data (Damage done to trees/rocks, age of wheat & saplings, etc). 80KB
|
||||||
|
|
||||||
fwrite(&daytime, sizeof(u16), 1, file);
|
fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
fwrite(minimapData, sizeof(u8), 128*128, file); // Minimap, visibility data 16KB
|
void savePlayerInternal(char *filename, PlayerData *player, EntityManager *eManager) {
|
||||||
|
FILE * file = fopen(filename, "wb"); //TODO: should be checked
|
||||||
|
|
||||||
//Quest Data
|
int i;
|
||||||
fwrite(&questManager.size, sizeof(int), 1, file);
|
|
||||||
for(i = 0; i < questManager.size; ++i) {
|
//write savefile version
|
||||||
fwrite(&(questManager.questlines[i].currentQuest), sizeof(int), 1, file);
|
int version = SAVE_VERSION;
|
||||||
fwrite(&(questManager.questlines[i].currentQuestDone), sizeof(bool), 1, file);
|
fwrite(&version, sizeof(int), 1, file);
|
||||||
|
|
||||||
|
// basic player info
|
||||||
|
fwrite(&player->score, sizeof(int), 1, file);
|
||||||
|
fwrite(&player->isSpawned, sizeof(bool), 1, file);
|
||||||
|
fwrite(&player->entity.p.hasWonSaved, sizeof(bool), 1, file);
|
||||||
|
fwrite(&player->entity.p.health, sizeof(s16), 1, file);
|
||||||
|
fwrite(&player->entity.x, sizeof(s16), 1, file);
|
||||||
|
fwrite(&player->entity.y, sizeof(s16), 1, file);
|
||||||
|
fwrite(&player->entity.level, sizeof(s8), 1, file);
|
||||||
|
|
||||||
|
saveInventory(&(player->inventory), eManager, file);
|
||||||
|
|
||||||
|
// Sprite info
|
||||||
|
fwrite(&(player->sprite.choosen), sizeof(bool), 1, file);
|
||||||
|
fwrite(&(player->sprite.legs), sizeof(u8), 1, file);
|
||||||
|
fwrite(&(player->sprite.body), sizeof(u8), 1, file);
|
||||||
|
fwrite(&(player->sprite.arms), sizeof(u8), 1, file);
|
||||||
|
fwrite(&(player->sprite.head), sizeof(u8), 1, file);
|
||||||
|
fwrite(&(player->sprite.eyes), sizeof(u8), 1, file);
|
||||||
|
|
||||||
|
// Minimap Data
|
||||||
|
fwrite(player->minimapData, sizeof(u8), 128*128, file); // Minimap, visibility data 16KB
|
||||||
|
|
||||||
|
// Quest Data
|
||||||
|
fwrite(&(player->questManager.size), sizeof(int), 1, file);
|
||||||
|
for(i = 0; i < player->questManager.size; ++i) {
|
||||||
|
fwrite(&(player->questManager.questlines[i].currentQuest), sizeof(int), 1, file);
|
||||||
|
fwrite(&(player->questManager.questlines[i].currentQuestDone), sizeof(bool), 1, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Compass Data
|
|
||||||
for(i=0; i<6; ++i) {
|
|
||||||
fwrite(&(compassData[i][0]), sizeof(u8), 1, file); //x of choosen stair
|
|
||||||
fwrite(&(compassData[i][1]), sizeof(u8), 1, file); //y of choosen stair
|
|
||||||
fwrite(&(compassData[i][2]), sizeof(u8), 1, file); //count
|
|
||||||
}
|
|
||||||
|
|
||||||
//Day/season Data
|
|
||||||
fwrite(&day, sizeof(int), 1, file);
|
|
||||||
fwrite(&season, sizeof(u8), 1, file);
|
|
||||||
fwrite(&rain, sizeof(bool), 1, file);
|
|
||||||
|
|
||||||
//Potion Data
|
//Potion Data
|
||||||
fwrite(&UnderStrengthEffect, sizeof(bool), 1, file);
|
fwrite(&UnderStrengthEffect, sizeof(bool), 1, file);
|
||||||
fwrite(&UnderSpeedEffect, sizeof(bool), 1, file);
|
fwrite(&UnderSpeedEffect, sizeof(bool), 1, file);
|
||||||
fwrite(®ening, sizeof(bool), 1, file);
|
fwrite(®ening, sizeof(bool), 1, file);
|
||||||
fwrite(&UnderSwimBreathEffect, sizeof(bool), 1, file);
|
fwrite(&UnderSwimBreathEffect, sizeof(bool), 1, file);
|
||||||
fwrite(&player->p.strengthTimer, sizeof(int), 1, file);
|
fwrite(&player->entity.p.strengthTimer, sizeof(int), 1, file);
|
||||||
fwrite(&player->p.speedTimer, sizeof(int), 1, file);
|
fwrite(&player->entity.p.speedTimer, sizeof(int), 1, file);
|
||||||
fwrite(&player->p.swimBreathTimer, sizeof(int), 1, file);
|
fwrite(&player->entity.p.swimBreathTimer, sizeof(int), 1, file);
|
||||||
fwrite(&player->p.regenTimer, sizeof(int), 1, file);
|
fwrite(&player->entity.p.regenTimer, sizeof(int), 1, file);
|
||||||
|
|
||||||
fclose(file);
|
fclose(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
int loadWorld(char * filename, EntityManager * eManager, Entity * player, u8 * map, u8 * mapData){
|
//internal load methods
|
||||||
FILE * file;
|
void loadInventory(Inventory *inv, EntityManager *eManager, FILE *file) {
|
||||||
int i,j;
|
fread(&(inv->lastSlot), sizeof(s16), 1, file); // read amount of items in inventory;
|
||||||
|
for(int j = 0; j < inv->lastSlot; ++j) {
|
||||||
if ((file = fopen(filename, "rb"))){
|
fread(&(inv->items[j].id), sizeof(s16), 1, file); // write ID of item
|
||||||
|
fread(&(inv->items[j].countLevel), sizeof(s16), 1, file); // write count/level of item
|
||||||
fread(&player->p.score, sizeof(int), 1, file);
|
fread(&(inv->items[j].onlyOne), sizeof(bool), 1, file);
|
||||||
fread(&player->p.hasWonSaved, sizeof(bool), 1, file);
|
inv->items[j].invPtr = (int*)inv; // setup Inventory pointer
|
||||||
fread(&player->p.health, sizeof(s16), 1, file);
|
inv->items[j].slotNum = j; // setup slot number
|
||||||
fread(&player->x, sizeof(s16), 1, file);
|
if(inv->items[j].id == ITEM_CHEST){ // for chest item specifically.
|
||||||
fread(&player->y, sizeof(s16), 1, file);
|
int invIndex;
|
||||||
fread(¤tLevel, sizeof(s8), 1, file);
|
fread(&invIndex, sizeof(int), 1, file);
|
||||||
|
inv->items[j].chestPtr = (Inventory*)&eManager->invs[invIndex]; // setup chest inventory pointer.
|
||||||
fread(&eManager->nextInv, sizeof(s16), 1, file);
|
|
||||||
for(i = 0; i < eManager->nextInv; ++i) {
|
|
||||||
fread(&eManager->invs[i].lastSlot, sizeof(s16), 1, file); // read amount of items in inventory;
|
|
||||||
for(j = 0; j < eManager->invs[i].lastSlot; ++j) {
|
|
||||||
fread(&eManager->invs[i].items[j].id, sizeof(s16), 1, file); // write ID of item
|
|
||||||
fread(&eManager->invs[i].items[j].countLevel, sizeof(s16), 1, file); // write count/level of item
|
|
||||||
fread(&eManager->invs[i].items[j].onlyOne, sizeof(bool), 1, file);
|
|
||||||
eManager->invs[i].items[j].invPtr = (int*)&eManager->invs[i]; // setup Inventory pointer
|
|
||||||
eManager->invs[i].items[j].slotNum = j; // setup slot number
|
|
||||||
if(eManager->invs[i].items[j].id == ITEM_CHEST){ // for chest item specifically.
|
|
||||||
int invIndex;
|
|
||||||
fread(&invIndex, sizeof(int), 1, file);
|
|
||||||
eManager->invs[i].items[j].chestPtr = (Inventory*)&eManager->invs[invIndex]; // setup chest inventory pointer.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i = 0; i < 5; ++i){
|
|
||||||
fread(&eManager->lastSlot[i], sizeof(s16), 1, file); // read amount of entities in level.
|
|
||||||
for(j = 0; j < eManager->lastSlot[i]; ++j){
|
|
||||||
fread(&eManager->entities[i][j].type, sizeof(s16), 1, file); // read entity's type ID
|
|
||||||
fread(&eManager->entities[i][j].x, sizeof(s16), 1, file); // read entity's x coordinate
|
|
||||||
fread(&eManager->entities[i][j].y, sizeof(s16), 1, file); // read entity's y coordinate
|
|
||||||
eManager->entities[i][j].slotNum = j;
|
|
||||||
switch(eManager->entities[i][j].type){
|
|
||||||
case ENTITY_SMASHPARTICLE:
|
|
||||||
eManager->entities[i][j].level = i;
|
|
||||||
eManager->entities[i][j].smashParticle.age = 300;
|
|
||||||
eManager->entities[i][j].canPass = true;
|
|
||||||
break;
|
|
||||||
case ENTITY_TEXTPARTICLE:
|
|
||||||
eManager->entities[i][j].level = i;
|
|
||||||
eManager->entities[i][j].canPass = true;
|
|
||||||
eManager->entities[i][j].textParticle.age = 59;
|
|
||||||
eManager->entities[i][j].textParticle.text = NULL;
|
|
||||||
eManager->entities[i][j].textParticle.xx = eManager->entities[i][j].x;
|
|
||||||
eManager->entities[i][j].textParticle.yy = eManager->entities[i][j].y;
|
|
||||||
eManager->entities[i][j].textParticle.zz = 2;
|
|
||||||
eManager->entities[i][j].textParticle.xa = 0;
|
|
||||||
eManager->entities[i][j].textParticle.ya = 0;
|
|
||||||
eManager->entities[i][j].textParticle.za = 0;
|
|
||||||
break;
|
|
||||||
case ENTITY_SPARK:
|
|
||||||
eManager->entities[i][j].level = i;
|
|
||||||
eManager->entities[i][j].spark.age = 300;
|
|
||||||
break;
|
|
||||||
case ENTITY_AIRWIZARD:
|
|
||||||
fread(&eManager->entities[i][j].wizard.health, sizeof(s16), 1, file);
|
|
||||||
eManager->entities[i][j].level = i;
|
|
||||||
eManager->entities[i][j].hurtTime = 0;
|
|
||||||
eManager->entities[i][j].xKnockback = 0;
|
|
||||||
eManager->entities[i][j].yKnockback = 0;
|
|
||||||
eManager->entities[i][j].wizard.dir = 0;
|
|
||||||
eManager->entities[i][j].wizard.attackDelay = 0;
|
|
||||||
eManager->entities[i][j].wizard.attackTime = 0;
|
|
||||||
eManager->entities[i][j].wizard.attackType = 0;
|
|
||||||
eManager->entities[i][j].wizard.xa = 0;
|
|
||||||
eManager->entities[i][j].wizard.ya = 0;
|
|
||||||
eManager->entities[i][j].xr = 4;
|
|
||||||
eManager->entities[i][j].yr = 3;
|
|
||||||
eManager->entities[i][j].canPass = true;
|
|
||||||
break;
|
|
||||||
case ENTITY_SLIME:
|
|
||||||
fread(&eManager->entities[i][j].slime.health, sizeof(s16), 1, file);
|
|
||||||
fread(&eManager->entities[i][j].slime.lvl, sizeof(s8), 1, file);
|
|
||||||
eManager->entities[i][j].level = i;
|
|
||||||
eManager->entities[i][j].hurtTime = 0;
|
|
||||||
eManager->entities[i][j].xKnockback = 0;
|
|
||||||
eManager->entities[i][j].yKnockback = 0;
|
|
||||||
eManager->entities[i][j].slime.xa = 0;
|
|
||||||
eManager->entities[i][j].slime.ya = 0;
|
|
||||||
eManager->entities[i][j].slime.dir = 0;
|
|
||||||
eManager->entities[i][j].xr = 4;
|
|
||||||
eManager->entities[i][j].yr = 3;
|
|
||||||
eManager->entities[i][j].canPass = false;
|
|
||||||
switch(eManager->entities[i][j].slime.lvl){
|
|
||||||
case 2: eManager->entities[i][j].slime.color = 0xFF8282CC; break;
|
|
||||||
case 3: eManager->entities[i][j].slime.color = 0xFFEFEFEF; break;
|
|
||||||
case 4: eManager->entities[i][j].slime.color = 0xFFAA6262; break;
|
|
||||||
default: eManager->entities[i][j].slime.color = 0xFF95DB95; break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ENTITY_ZOMBIE:
|
|
||||||
fread(&eManager->entities[i][j].hostile.health, sizeof(s16), 1, file);
|
|
||||||
fread(&eManager->entities[i][j].hostile.lvl, sizeof(s8), 1, file);
|
|
||||||
eManager->entities[i][j].level = i;
|
|
||||||
eManager->entities[i][j].hurtTime = 0;
|
|
||||||
eManager->entities[i][j].xKnockback = 0;
|
|
||||||
eManager->entities[i][j].yKnockback = 0;
|
|
||||||
eManager->entities[i][j].hostile.dir = 0;
|
|
||||||
eManager->entities[i][j].xr = 4;
|
|
||||||
eManager->entities[i][j].yr = 3;
|
|
||||||
eManager->entities[i][j].canPass = false;
|
|
||||||
switch(eManager->entities[i][j].hostile.lvl){
|
|
||||||
case 2: eManager->entities[i][j].hostile.color = 0xFF8282CC; break;
|
|
||||||
case 3: eManager->entities[i][j].hostile.color = 0xFFEFEFEF; break;
|
|
||||||
case 4: eManager->entities[i][j].hostile.color = 0xFFAA6262; break;
|
|
||||||
default: eManager->entities[i][j].hostile.color = 0xFF95DB95; break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ENTITY_SKELETON:
|
|
||||||
fread(&eManager->entities[i][j].hostile.health, sizeof(s16), 1, file);
|
|
||||||
fread(&eManager->entities[i][j].hostile.lvl, sizeof(s8), 1, file);
|
|
||||||
eManager->entities[i][j].level = i;
|
|
||||||
eManager->entities[i][j].hurtTime = 0;
|
|
||||||
eManager->entities[i][j].xKnockback = 0;
|
|
||||||
eManager->entities[i][j].yKnockback = 0;
|
|
||||||
eManager->entities[i][j].hostile.dir = 0;
|
|
||||||
eManager->entities[i][j].hostile.randAttackTime = 0;
|
|
||||||
eManager->entities[i][j].xr = 4;
|
|
||||||
eManager->entities[i][j].yr = 3;
|
|
||||||
eManager->entities[i][j].canPass = false;
|
|
||||||
switch(eManager->entities[i][j].hostile.lvl){
|
|
||||||
case 2: eManager->entities[i][j].hostile.color = 0xFFC4C4C4; break;
|
|
||||||
case 3: eManager->entities[i][j].hostile.color = 0xFFA0A0A0; break;
|
|
||||||
case 4: eManager->entities[i][j].hostile.color = 0xFF7A7A7A; break;
|
|
||||||
default: eManager->entities[i][j].hostile.color = 0xFFFFFFFF; break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ENTITY_KNIGHT:
|
|
||||||
fread(&eManager->entities[i][j].hostile.health, sizeof(s16), 1, file);
|
|
||||||
fread(&eManager->entities[i][j].hostile.lvl, sizeof(s8), 1, file);
|
|
||||||
eManager->entities[i][j].level = i;
|
|
||||||
eManager->entities[i][j].hurtTime = 0;
|
|
||||||
eManager->entities[i][j].xKnockback = 0;
|
|
||||||
eManager->entities[i][j].yKnockback = 0;
|
|
||||||
eManager->entities[i][j].hostile.dir = 0;
|
|
||||||
eManager->entities[i][j].xr = 4;
|
|
||||||
eManager->entities[i][j].yr = 3;
|
|
||||||
eManager->entities[i][j].canPass = false;
|
|
||||||
switch(eManager->entities[i][j].hostile.lvl){
|
|
||||||
case 2: eManager->entities[i][j].hostile.color = 0xFF0000C6; break;
|
|
||||||
case 3: eManager->entities[i][j].hostile.color = 0xFF00A3C6; break;
|
|
||||||
case 4: eManager->entities[i][j].hostile.color = 0xFF707070; break;
|
|
||||||
default: eManager->entities[i][j].hostile.color = 0xFFFFFFFF; break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ENTITY_ITEM:
|
|
||||||
//eManager->entities[i][j].entityItem.item = newItem(0,0);
|
|
||||||
fread(&eManager->entities[i][j].entityItem.item.id, sizeof(s16), 1, file);
|
|
||||||
fread(&eManager->entities[i][j].entityItem.item.countLevel, sizeof(s16), 1, file);
|
|
||||||
fread(&eManager->entities[i][j].entityItem.age, sizeof(s16), 1, file);
|
|
||||||
eManager->entities[i][j].level = i;
|
|
||||||
eManager->entities[i][j].entityItem.age = 0;
|
|
||||||
eManager->entities[i][j].xr = 3;
|
|
||||||
eManager->entities[i][j].yr = 3;
|
|
||||||
eManager->entities[i][j].canPass = false;
|
|
||||||
eManager->entities[i][j].entityItem.xx = eManager->entities[i][j].x;
|
|
||||||
eManager->entities[i][j].entityItem.yy = eManager->entities[i][j].y;
|
|
||||||
eManager->entities[i][j].entityItem.zz = 2;
|
|
||||||
eManager->entities[i][j].entityItem.xa = 0;
|
|
||||||
eManager->entities[i][j].entityItem.ya = 0;
|
|
||||||
eManager->entities[i][j].entityItem.za = 0;
|
|
||||||
break;
|
|
||||||
case ENTITY_FURNITURE:
|
|
||||||
fread(&eManager->entities[i][j].entityFurniture.itemID, sizeof(s16), 1, file);
|
|
||||||
int invIndex;
|
|
||||||
fread(&invIndex, sizeof(int), 1, file);
|
|
||||||
eManager->entities[i][j].entityFurniture.inv = &eManager->invs[invIndex];
|
|
||||||
eManager->entities[i][j].xr = 3;
|
|
||||||
eManager->entities[i][j].yr = 3;
|
|
||||||
eManager->entities[i][j].canPass = false;
|
|
||||||
if(eManager->entities[i][j].entityFurniture.itemID == ITEM_LANTERN) eManager->entities[i][j].entityFurniture.r = 8;
|
|
||||||
break;
|
|
||||||
case ENTITY_PASSIVE:
|
|
||||||
fread(&eManager->entities[i][j].passive.health, sizeof(s16), 1, file);
|
|
||||||
fread(&eManager->entities[i][j].passive.mtype, sizeof(u8), 1, file);
|
|
||||||
eManager->entities[i][j].level = i;
|
|
||||||
eManager->entities[i][j].hurtTime = 0;
|
|
||||||
eManager->entities[i][j].xKnockback = 0;
|
|
||||||
eManager->entities[i][j].yKnockback = 0;
|
|
||||||
eManager->entities[i][j].passive.dir = 0;
|
|
||||||
eManager->entities[i][j].xr = 4;
|
|
||||||
eManager->entities[i][j].yr = 3;
|
|
||||||
eManager->entities[i][j].canPass = false;
|
|
||||||
break;
|
|
||||||
case ENTITY_GLOWWORM:
|
|
||||||
eManager->entities[i][j].glowworm.xa = 0;
|
|
||||||
eManager->entities[i][j].glowworm.ya = 0;
|
|
||||||
eManager->entities[i][j].glowworm.randWalkTime = 0;
|
|
||||||
eManager->entities[i][j].glowworm.waitTime = 0;
|
|
||||||
break;
|
|
||||||
case ENTITY_DRAGON:
|
|
||||||
fread(&eManager->entities[i][j].dragon.health, sizeof(s16), 1, file);
|
|
||||||
eManager->entities[i][j].level = i;
|
|
||||||
eManager->entities[i][j].hurtTime = 0;
|
|
||||||
eManager->entities[i][j].xKnockback = 0;
|
|
||||||
eManager->entities[i][j].yKnockback = 0;
|
|
||||||
eManager->entities[i][j].dragon.dir = 0;
|
|
||||||
eManager->entities[i][j].dragon.attackDelay = 0;
|
|
||||||
eManager->entities[i][j].dragon.attackTime = 0;
|
|
||||||
eManager->entities[i][j].dragon.attackType = 0;
|
|
||||||
eManager->entities[i][j].dragon.animTimer = 0;
|
|
||||||
eManager->entities[i][j].dragon.xa = 0;
|
|
||||||
eManager->entities[i][j].dragon.ya = 0;
|
|
||||||
eManager->entities[i][j].xr = 8;
|
|
||||||
eManager->entities[i][j].yr = 8;
|
|
||||||
eManager->entities[i][j].canPass = true;
|
|
||||||
break;
|
|
||||||
case ENTITY_NPC:
|
|
||||||
fread(&eManager->entities[i][j].npc.type, sizeof(u8), 1, file);
|
|
||||||
eManager->entities[i][j].level = i;
|
|
||||||
eManager->entities[i][j].hurtTime = 0;
|
|
||||||
eManager->entities[i][j].xKnockback = 0;
|
|
||||||
eManager->entities[i][j].yKnockback = 0;
|
|
||||||
eManager->entities[i][j].xr = 4;
|
|
||||||
eManager->entities[i][j].yr = 3;
|
|
||||||
eManager->entities[i][j].canPass = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Don't write or load dungeon, so only first 5 levels not 6
|
|
||||||
fread(map, sizeof(u8), 128*128*5, file);
|
|
||||||
fread(mapData, sizeof(u8), 128*128*5, file);
|
|
||||||
|
|
||||||
//set to startvalue incase file is old and doesn't contain saved time
|
|
||||||
daytime = 6001;
|
|
||||||
fread(&daytime, sizeof(u16), 1, file);
|
|
||||||
|
|
||||||
fread(minimapData, sizeof(u8), 128*128, file);
|
|
||||||
|
|
||||||
//Quest Data
|
|
||||||
int qsize = 0;
|
|
||||||
fread(&qsize, sizeof(int), 1, file);
|
|
||||||
for(i = 0; i < qsize; ++i) {
|
|
||||||
fread(&(questManager.questlines[i].currentQuest), sizeof(int), 1, file);
|
|
||||||
fread(&(questManager.questlines[i].currentQuestDone), sizeof(bool), 1, file);
|
|
||||||
}
|
|
||||||
//fill missing questlines with "no progress done"
|
|
||||||
for(i = qsize; i < questManager.size; ++i) {
|
|
||||||
questManager.questlines[i].currentQuest = 0;
|
|
||||||
questManager.questlines[i].currentQuestDone = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Compass Data
|
|
||||||
//reset incase it is missing in the save
|
|
||||||
for(i=0; i<6; ++i) {
|
|
||||||
compassData[i][0] = 0; //x of choosen stair
|
|
||||||
compassData[i][1] = 0; //y of choosen stair
|
|
||||||
compassData[i][2] = 0; //count
|
|
||||||
}
|
|
||||||
for(i=0; i<6; ++i) {
|
|
||||||
fread(&(compassData[i][0]), sizeof(u8), 1, file); //x of choosen stair
|
|
||||||
fread(&(compassData[i][1]), sizeof(u8), 1, file); //y of choosen stair
|
|
||||||
fread(&(compassData[i][2]), sizeof(u8), 1, file); //count
|
|
||||||
}
|
|
||||||
|
|
||||||
//Day/season Data
|
|
||||||
day = 0;
|
|
||||||
season = 0;
|
|
||||||
rain = false;
|
|
||||||
fread(&day, sizeof(int), 1, file);
|
|
||||||
fread(&season, sizeof(u8), 1, file);
|
|
||||||
fread(&rain, sizeof(bool), 1, file);
|
|
||||||
//Potion Data
|
|
||||||
fread(&UnderStrengthEffect, sizeof(bool), 1, file);
|
|
||||||
fread(&UnderSpeedEffect, sizeof(bool), 1, file);
|
|
||||||
fread(®ening, sizeof(bool), 1, file);
|
|
||||||
fread(&UnderSwimBreathEffect, sizeof(bool), 1, file);
|
|
||||||
fread(&player->p.strengthTimer, sizeof(int), 1, file);
|
|
||||||
fread(&player->p.speedTimer, sizeof(int), 1, file);
|
|
||||||
fread(&player->p.swimBreathTimer, sizeof(int), 1, file);
|
|
||||||
fread(&player->p.regenTimer, sizeof(int), 1, file);
|
|
||||||
|
|
||||||
fclose(file);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
return 1;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadWorldInternal(char *filename, EntityManager *eManager, WorldData *worldData) {
|
||||||
|
FILE * file = fopen(filename, "rb"); //TODO: should be checked
|
||||||
|
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
//read savefile version
|
||||||
|
int version;
|
||||||
|
fread(&version, sizeof(int), 1, file);
|
||||||
|
|
||||||
|
// Inventory Data
|
||||||
|
fread(&eManager->nextInv, sizeof(s16), 1, file);
|
||||||
|
for(i = 0; i < eManager->nextInv; ++i) {
|
||||||
|
loadInventory(&(eManager->invs[i]), eManager, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entity Data
|
||||||
|
for(i = 0; i < 5; ++i){
|
||||||
|
fread(&eManager->lastSlot[i], sizeof(s16), 1, file); // read amount of entities in level.
|
||||||
|
for(j = 0; j < eManager->lastSlot[i]; ++j){
|
||||||
|
fread(&eManager->entities[i][j].type, sizeof(s16), 1, file); // read entity's type ID
|
||||||
|
fread(&eManager->entities[i][j].x, sizeof(s16), 1, file); // read entity's x coordinate
|
||||||
|
fread(&eManager->entities[i][j].y, sizeof(s16), 1, file); // read entity's y coordinate
|
||||||
|
eManager->entities[i][j].slotNum = j;
|
||||||
|
switch(eManager->entities[i][j].type){
|
||||||
|
case ENTITY_SMASHPARTICLE:
|
||||||
|
eManager->entities[i][j].level = i;
|
||||||
|
eManager->entities[i][j].smashParticle.age = 300;
|
||||||
|
eManager->entities[i][j].canPass = true;
|
||||||
|
break;
|
||||||
|
case ENTITY_TEXTPARTICLE:
|
||||||
|
eManager->entities[i][j].level = i;
|
||||||
|
eManager->entities[i][j].canPass = true;
|
||||||
|
eManager->entities[i][j].textParticle.age = 59;
|
||||||
|
eManager->entities[i][j].textParticle.text = NULL;
|
||||||
|
eManager->entities[i][j].textParticle.xx = eManager->entities[i][j].x;
|
||||||
|
eManager->entities[i][j].textParticle.yy = eManager->entities[i][j].y;
|
||||||
|
eManager->entities[i][j].textParticle.zz = 2;
|
||||||
|
eManager->entities[i][j].textParticle.xa = 0;
|
||||||
|
eManager->entities[i][j].textParticle.ya = 0;
|
||||||
|
eManager->entities[i][j].textParticle.za = 0;
|
||||||
|
break;
|
||||||
|
case ENTITY_SPARK:
|
||||||
|
eManager->entities[i][j].level = i;
|
||||||
|
eManager->entities[i][j].spark.age = 300;
|
||||||
|
break;
|
||||||
|
case ENTITY_AIRWIZARD:
|
||||||
|
fread(&eManager->entities[i][j].wizard.health, sizeof(s16), 1, file);
|
||||||
|
eManager->entities[i][j].level = i;
|
||||||
|
eManager->entities[i][j].hurtTime = 0;
|
||||||
|
eManager->entities[i][j].xKnockback = 0;
|
||||||
|
eManager->entities[i][j].yKnockback = 0;
|
||||||
|
eManager->entities[i][j].wizard.dir = 0;
|
||||||
|
eManager->entities[i][j].wizard.attackDelay = 0;
|
||||||
|
eManager->entities[i][j].wizard.attackTime = 0;
|
||||||
|
eManager->entities[i][j].wizard.attackType = 0;
|
||||||
|
eManager->entities[i][j].wizard.xa = 0;
|
||||||
|
eManager->entities[i][j].wizard.ya = 0;
|
||||||
|
eManager->entities[i][j].xr = 4;
|
||||||
|
eManager->entities[i][j].yr = 3;
|
||||||
|
eManager->entities[i][j].canPass = true;
|
||||||
|
break;
|
||||||
|
case ENTITY_SLIME:
|
||||||
|
fread(&eManager->entities[i][j].slime.health, sizeof(s16), 1, file);
|
||||||
|
fread(&eManager->entities[i][j].slime.lvl, sizeof(s8), 1, file);
|
||||||
|
eManager->entities[i][j].level = i;
|
||||||
|
eManager->entities[i][j].hurtTime = 0;
|
||||||
|
eManager->entities[i][j].xKnockback = 0;
|
||||||
|
eManager->entities[i][j].yKnockback = 0;
|
||||||
|
eManager->entities[i][j].slime.xa = 0;
|
||||||
|
eManager->entities[i][j].slime.ya = 0;
|
||||||
|
eManager->entities[i][j].slime.dir = 0;
|
||||||
|
eManager->entities[i][j].xr = 4;
|
||||||
|
eManager->entities[i][j].yr = 3;
|
||||||
|
eManager->entities[i][j].canPass = false;
|
||||||
|
switch(eManager->entities[i][j].slime.lvl){
|
||||||
|
case 2: eManager->entities[i][j].slime.color = 0xFF8282CC; break;
|
||||||
|
case 3: eManager->entities[i][j].slime.color = 0xFFEFEFEF; break;
|
||||||
|
case 4: eManager->entities[i][j].slime.color = 0xFFAA6262; break;
|
||||||
|
default: eManager->entities[i][j].slime.color = 0xFF95DB95; break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ENTITY_ZOMBIE:
|
||||||
|
fread(&eManager->entities[i][j].hostile.health, sizeof(s16), 1, file);
|
||||||
|
fread(&eManager->entities[i][j].hostile.lvl, sizeof(s8), 1, file);
|
||||||
|
eManager->entities[i][j].level = i;
|
||||||
|
eManager->entities[i][j].hurtTime = 0;
|
||||||
|
eManager->entities[i][j].xKnockback = 0;
|
||||||
|
eManager->entities[i][j].yKnockback = 0;
|
||||||
|
eManager->entities[i][j].hostile.dir = 0;
|
||||||
|
eManager->entities[i][j].xr = 4;
|
||||||
|
eManager->entities[i][j].yr = 3;
|
||||||
|
eManager->entities[i][j].canPass = false;
|
||||||
|
switch(eManager->entities[i][j].hostile.lvl){
|
||||||
|
case 2: eManager->entities[i][j].hostile.color = 0xFF8282CC; break;
|
||||||
|
case 3: eManager->entities[i][j].hostile.color = 0xFFEFEFEF; break;
|
||||||
|
case 4: eManager->entities[i][j].hostile.color = 0xFFAA6262; break;
|
||||||
|
default: eManager->entities[i][j].hostile.color = 0xFF95DB95; break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ENTITY_SKELETON:
|
||||||
|
fread(&eManager->entities[i][j].hostile.health, sizeof(s16), 1, file);
|
||||||
|
fread(&eManager->entities[i][j].hostile.lvl, sizeof(s8), 1, file);
|
||||||
|
eManager->entities[i][j].level = i;
|
||||||
|
eManager->entities[i][j].hurtTime = 0;
|
||||||
|
eManager->entities[i][j].xKnockback = 0;
|
||||||
|
eManager->entities[i][j].yKnockback = 0;
|
||||||
|
eManager->entities[i][j].hostile.dir = 0;
|
||||||
|
eManager->entities[i][j].hostile.randAttackTime = 0;
|
||||||
|
eManager->entities[i][j].xr = 4;
|
||||||
|
eManager->entities[i][j].yr = 3;
|
||||||
|
eManager->entities[i][j].canPass = false;
|
||||||
|
switch(eManager->entities[i][j].hostile.lvl){
|
||||||
|
case 2: eManager->entities[i][j].hostile.color = 0xFFC4C4C4; break;
|
||||||
|
case 3: eManager->entities[i][j].hostile.color = 0xFFA0A0A0; break;
|
||||||
|
case 4: eManager->entities[i][j].hostile.color = 0xFF7A7A7A; break;
|
||||||
|
default: eManager->entities[i][j].hostile.color = 0xFFFFFFFF; break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ENTITY_KNIGHT:
|
||||||
|
fread(&eManager->entities[i][j].hostile.health, sizeof(s16), 1, file);
|
||||||
|
fread(&eManager->entities[i][j].hostile.lvl, sizeof(s8), 1, file);
|
||||||
|
eManager->entities[i][j].level = i;
|
||||||
|
eManager->entities[i][j].hurtTime = 0;
|
||||||
|
eManager->entities[i][j].xKnockback = 0;
|
||||||
|
eManager->entities[i][j].yKnockback = 0;
|
||||||
|
eManager->entities[i][j].hostile.dir = 0;
|
||||||
|
eManager->entities[i][j].xr = 4;
|
||||||
|
eManager->entities[i][j].yr = 3;
|
||||||
|
eManager->entities[i][j].canPass = false;
|
||||||
|
switch(eManager->entities[i][j].hostile.lvl){
|
||||||
|
case 2: eManager->entities[i][j].hostile.color = 0xFF0000C6; break;
|
||||||
|
case 3: eManager->entities[i][j].hostile.color = 0xFF00A3C6; break;
|
||||||
|
case 4: eManager->entities[i][j].hostile.color = 0xFF707070; break;
|
||||||
|
default: eManager->entities[i][j].hostile.color = 0xFFFFFFFF; break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ENTITY_ITEM:
|
||||||
|
//eManager->entities[i][j].entityItem.item = newItem(0,0);
|
||||||
|
fread(&eManager->entities[i][j].entityItem.item.id, sizeof(s16), 1, file);
|
||||||
|
fread(&eManager->entities[i][j].entityItem.item.countLevel, sizeof(s16), 1, file);
|
||||||
|
fread(&eManager->entities[i][j].entityItem.age, sizeof(s16), 1, file);
|
||||||
|
eManager->entities[i][j].level = i;
|
||||||
|
eManager->entities[i][j].entityItem.age = 0;
|
||||||
|
eManager->entities[i][j].xr = 3;
|
||||||
|
eManager->entities[i][j].yr = 3;
|
||||||
|
eManager->entities[i][j].canPass = false;
|
||||||
|
eManager->entities[i][j].entityItem.xx = eManager->entities[i][j].x;
|
||||||
|
eManager->entities[i][j].entityItem.yy = eManager->entities[i][j].y;
|
||||||
|
eManager->entities[i][j].entityItem.zz = 2;
|
||||||
|
eManager->entities[i][j].entityItem.xa = 0;
|
||||||
|
eManager->entities[i][j].entityItem.ya = 0;
|
||||||
|
eManager->entities[i][j].entityItem.za = 0;
|
||||||
|
break;
|
||||||
|
case ENTITY_FURNITURE:
|
||||||
|
fread(&eManager->entities[i][j].entityFurniture.itemID, sizeof(s16), 1, file);
|
||||||
|
int invIndex;
|
||||||
|
fread(&invIndex, sizeof(int), 1, file);
|
||||||
|
eManager->entities[i][j].entityFurniture.inv = &eManager->invs[invIndex];
|
||||||
|
eManager->entities[i][j].xr = 3;
|
||||||
|
eManager->entities[i][j].yr = 3;
|
||||||
|
eManager->entities[i][j].canPass = false;
|
||||||
|
if(eManager->entities[i][j].entityFurniture.itemID == ITEM_LANTERN) eManager->entities[i][j].entityFurniture.r = 8;
|
||||||
|
break;
|
||||||
|
case ENTITY_PASSIVE:
|
||||||
|
fread(&eManager->entities[i][j].passive.health, sizeof(s16), 1, file);
|
||||||
|
fread(&eManager->entities[i][j].passive.mtype, sizeof(u8), 1, file);
|
||||||
|
eManager->entities[i][j].level = i;
|
||||||
|
eManager->entities[i][j].hurtTime = 0;
|
||||||
|
eManager->entities[i][j].xKnockback = 0;
|
||||||
|
eManager->entities[i][j].yKnockback = 0;
|
||||||
|
eManager->entities[i][j].passive.dir = 0;
|
||||||
|
eManager->entities[i][j].xr = 4;
|
||||||
|
eManager->entities[i][j].yr = 3;
|
||||||
|
eManager->entities[i][j].canPass = false;
|
||||||
|
break;
|
||||||
|
case ENTITY_GLOWWORM:
|
||||||
|
eManager->entities[i][j].glowworm.xa = 0;
|
||||||
|
eManager->entities[i][j].glowworm.ya = 0;
|
||||||
|
eManager->entities[i][j].glowworm.randWalkTime = 0;
|
||||||
|
eManager->entities[i][j].glowworm.waitTime = 0;
|
||||||
|
break;
|
||||||
|
case ENTITY_DRAGON:
|
||||||
|
fread(&eManager->entities[i][j].dragon.health, sizeof(s16), 1, file);
|
||||||
|
eManager->entities[i][j].level = i;
|
||||||
|
eManager->entities[i][j].hurtTime = 0;
|
||||||
|
eManager->entities[i][j].xKnockback = 0;
|
||||||
|
eManager->entities[i][j].yKnockback = 0;
|
||||||
|
eManager->entities[i][j].dragon.dir = 0;
|
||||||
|
eManager->entities[i][j].dragon.attackDelay = 0;
|
||||||
|
eManager->entities[i][j].dragon.attackTime = 0;
|
||||||
|
eManager->entities[i][j].dragon.attackType = 0;
|
||||||
|
eManager->entities[i][j].dragon.animTimer = 0;
|
||||||
|
eManager->entities[i][j].dragon.xa = 0;
|
||||||
|
eManager->entities[i][j].dragon.ya = 0;
|
||||||
|
eManager->entities[i][j].xr = 8;
|
||||||
|
eManager->entities[i][j].yr = 8;
|
||||||
|
eManager->entities[i][j].canPass = true;
|
||||||
|
break;
|
||||||
|
case ENTITY_NPC:
|
||||||
|
fread(&eManager->entities[i][j].npc.type, sizeof(u8), 1, file);
|
||||||
|
eManager->entities[i][j].level = i;
|
||||||
|
eManager->entities[i][j].hurtTime = 0;
|
||||||
|
eManager->entities[i][j].xKnockback = 0;
|
||||||
|
eManager->entities[i][j].yKnockback = 0;
|
||||||
|
eManager->entities[i][j].xr = 4;
|
||||||
|
eManager->entities[i][j].yr = 3;
|
||||||
|
eManager->entities[i][j].canPass = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Day/season Data
|
||||||
|
fread(&worldData->daytime, sizeof(u16), 1, file);
|
||||||
|
fread(&worldData->day, sizeof(int), 1, file);
|
||||||
|
fread(&worldData->season, sizeof(u8), 1, file);
|
||||||
|
fread(&worldData->rain, sizeof(bool), 1, file);
|
||||||
|
|
||||||
|
// Compass Data
|
||||||
|
fread(worldData->compassData, sizeof(u8), 6*3, file); //x,y of choosen stair and count per level
|
||||||
|
|
||||||
|
// Map Data
|
||||||
|
//Don't write or load dungeon, so only first 5 levels not 6
|
||||||
|
fread(worldData->map, sizeof(u8), 128*128*5, file); // Map Tile IDs, 128*128*5 bytes = 80KB
|
||||||
|
fread(worldData->data, sizeof(u8), 128*128*5, file); // Map Tile Data (Damage done to trees/rocks, age of wheat & saplings, etc). 80KB
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadPlayerInternal(char *filename, PlayerData *player, EntityManager *eManager) {
|
||||||
|
FILE * file = fopen(filename, "rb"); //TODO: should be checked
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
//read savefile version
|
||||||
|
int version;
|
||||||
|
fread(&version, sizeof(int), 1, file);
|
||||||
|
|
||||||
|
// basic player info
|
||||||
|
fread(&player->score, sizeof(int), 1, file);
|
||||||
|
fread(&player->isSpawned, sizeof(bool), 1, file);
|
||||||
|
fread(&player->entity.p.hasWonSaved, sizeof(bool), 1, file);
|
||||||
|
fread(&player->entity.p.health, sizeof(s16), 1, file);
|
||||||
|
fread(&player->entity.x, sizeof(s16), 1, file);
|
||||||
|
fread(&player->entity.y, sizeof(s16), 1, file);
|
||||||
|
fread(&player->entity.level, sizeof(s8), 1, file);
|
||||||
|
|
||||||
|
loadInventory(&(player->inventory), eManager, file);
|
||||||
|
|
||||||
|
// Sprite info
|
||||||
|
fread(&(player->sprite.choosen), sizeof(bool), 1, file);
|
||||||
|
fread(&(player->sprite.legs), sizeof(u8), 1, file);
|
||||||
|
fread(&(player->sprite.body), sizeof(u8), 1, file);
|
||||||
|
fread(&(player->sprite.arms), sizeof(u8), 1, file);
|
||||||
|
fread(&(player->sprite.head), sizeof(u8), 1, file);
|
||||||
|
fread(&(player->sprite.eyes), sizeof(u8), 1, file);
|
||||||
|
|
||||||
|
// Minimap Data
|
||||||
|
fread(player->minimapData, sizeof(u8), 128*128, file); // Minimap, visibility data 16KB
|
||||||
|
|
||||||
|
// Quest Data
|
||||||
|
fread(&(player->questManager.size), sizeof(int), 1, file);
|
||||||
|
for(i = 0; i < player->questManager.size; ++i) {
|
||||||
|
fread(&(player->questManager.questlines[i].currentQuest), sizeof(int), 1, file);
|
||||||
|
fread(&(player->questManager.questlines[i].currentQuestDone), sizeof(bool), 1, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Potion Data
|
||||||
|
fread(&UnderStrengthEffect, sizeof(bool), 1, file);
|
||||||
|
fread(&UnderSpeedEffect, sizeof(bool), 1, file);
|
||||||
|
fread(®ening, sizeof(bool), 1, file);
|
||||||
|
fread(&UnderSwimBreathEffect, sizeof(bool), 1, file);
|
||||||
|
fread(&player->entity.p.strengthTimer, sizeof(int), 1, file);
|
||||||
|
fread(&player->entity.p.speedTimer, sizeof(int), 1, file);
|
||||||
|
fread(&player->entity.p.swimBreathTimer, sizeof(int), 1, file);
|
||||||
|
fread(&player->entity.p.regenTimer, sizeof(int), 1, file);
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool saveWorld(char *filename, EntityManager *eManager, WorldData *worldData, PlayerData *players, int playerCount) {
|
||||||
|
//check if old save file exists
|
||||||
|
bool exists = false;
|
||||||
|
FILE *testFile = fopen(filename, "rb");
|
||||||
|
if(testFile) {
|
||||||
|
fclose(testFile);
|
||||||
|
exists = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
saveTrackFileReset();
|
||||||
|
|
||||||
|
if(exists) {
|
||||||
|
//create backup copy
|
||||||
|
char *filenameBackup = malloc(sizeof(filename)+4+1);
|
||||||
|
if(filenameBackup==NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
strcpy(filenameBackup, filename);
|
||||||
|
strcat(filenameBackup, ".bak");
|
||||||
|
if(!saveFileCopy(filenameBackup, filename)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//extract files and keep track of references
|
||||||
|
if(unzipAndLoad(filename, &saveTrackFile, SAVE_COMMENT, ZIPHELPER_KEEP_FILES)!=0) {
|
||||||
|
saveDeleteTrackedFiles();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
//save world data
|
||||||
|
saveWorldInternal("main.wld", eManager, worldData);
|
||||||
|
saveTrackFile("main.wld");
|
||||||
|
|
||||||
|
//save player data of active players
|
||||||
|
for(int i=0; i<playerCount; i++) {
|
||||||
|
char playerFilename[50];
|
||||||
|
playerFilename[0] = '\0';
|
||||||
|
sprintf(playerFilename, "%lu.plr", players[i].id);
|
||||||
|
|
||||||
|
savePlayerInternal(playerFilename, players+i, eManager);
|
||||||
|
saveTrackFile(playerFilename);
|
||||||
|
}
|
||||||
|
|
||||||
|
//zip all tracked files
|
||||||
|
if(zipFiles(filename, files, fileCount, ZIPHELPER_REPLACE, SAVE_COMMENT)!=0) {
|
||||||
|
remove(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
saveDeleteTrackedFiles();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool loadHadWorld;
|
||||||
|
EntityManager *loadEManager;
|
||||||
|
WorldData *loadWorldData;
|
||||||
|
PlayerData *loadPlayers;
|
||||||
|
int loadPlayerCount;
|
||||||
|
|
||||||
|
int loadFile(char *filename) {
|
||||||
|
//load world
|
||||||
|
if(strcmp(filename, "main.wld")==0) {
|
||||||
|
loadWorldInternal(filename, loadEManager, loadWorldData);
|
||||||
|
loadHadWorld = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//load player data of active players
|
||||||
|
for(int i=0; i<playerCount; i++) {
|
||||||
|
char playerFilename[50];
|
||||||
|
playerFilename[0] = '\0';
|
||||||
|
sprintf(playerFilename, "%lu.plr", players[i].id);
|
||||||
|
|
||||||
|
if(strcmp(filename, playerFilename)==0) {
|
||||||
|
loadPlayerInternal(filename, loadPlayers+i, loadEManager);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool loadWorld(char *filename, EntityManager *eManager, WorldData *worldData, PlayerData *players, int playerCount) {
|
||||||
|
//check if save file exists
|
||||||
|
bool exists = false;
|
||||||
|
FILE *testFile = fopen(filename, "rb");
|
||||||
|
if(testFile) {
|
||||||
|
fclose(testFile);
|
||||||
|
exists = true;
|
||||||
|
}
|
||||||
|
if(!exists) return false;
|
||||||
|
|
||||||
|
loadHadWorld = false;
|
||||||
|
loadEManager = eManager;
|
||||||
|
loadWorldData = worldData;
|
||||||
|
loadPlayers = players;
|
||||||
|
loadPlayerCount = playerCount;
|
||||||
|
|
||||||
|
//extract files
|
||||||
|
if(unzipAndLoad(filename, &loadFile, SAVE_COMMENT, ZIPHELPER_CLEANUP_FILES)!=0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!loadHadWorld) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,16 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "Entity.h"
|
#include "Entity.h"
|
||||||
|
#include "Player.h"
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
|
|
||||||
void saveCurrentWorld(char * filename, EntityManager * eManager, Entity * player, u8 * map, u8 * mapData);
|
#define SAVE_VERSION 1
|
||||||
int loadWorld(char * filename, EntityManager * eManager, Entity * player, u8 * map, u8 * mapData);
|
|
||||||
|
#define SAVE_COMMENT "Minicraft3DSSave"
|
||||||
|
#define SAVE_COPYBUFFER_SIZE 4096
|
||||||
|
|
||||||
|
//void saveCurrentWorld(char * filename, EntityManager * eManager, Entity * player, u8 * map, u8 * mapData, WorldData *worldData);
|
||||||
|
//int loadWorld(char * filename, EntityManager * eManager, Entity * player, u8 * map, u8 * mapData, WorldData *worldData);
|
||||||
|
|
||||||
|
bool saveWorld(char *filename, EntityManager *eManager, WorldData *worldData, PlayerData *players, int playerCount);
|
||||||
|
bool loadWorld(char *filename, EntityManager *eManager, WorldData *worldData, PlayerData *players, int playerCount);
|
||||||
|
|
|
@ -13,7 +13,10 @@ typedef struct {
|
||||||
void loadSound(Sound * snd, char * filename);
|
void loadSound(Sound * snd, char * filename);
|
||||||
void playSound(Sound snd);
|
void playSound(Sound snd);
|
||||||
|
|
||||||
void playMusic(Sound snd);
|
void playSoundPositioned(Sound snd, s8 level, int x, int y);
|
||||||
|
void setListenerPosition(s8 level, int x, int y);
|
||||||
|
|
||||||
|
void playMusic(Sound *snd);
|
||||||
void updateMusic(int lvl, int time);
|
void updateMusic(int lvl, int time);
|
||||||
void stopMusic();
|
void stopMusic();
|
||||||
|
|
||||||
|
|
250
source/Synchronizer.c
Normal file
250
source/Synchronizer.c
Normal file
|
@ -0,0 +1,250 @@
|
||||||
|
#include "Synchronizer.h"
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "Player.h"
|
||||||
|
#include "Input.h"
|
||||||
|
#include "Network.h"
|
||||||
|
#include "PacketHandler.h"
|
||||||
|
#include "Ingame.h"
|
||||||
|
|
||||||
|
u32 synchronizerLocalTurn;
|
||||||
|
unsigned int synchronizerNextSeed;
|
||||||
|
bool synchronizerRunning;
|
||||||
|
|
||||||
|
int synchronizerCurrentTicks;
|
||||||
|
|
||||||
|
bool synchronizerTurnReady();
|
||||||
|
void synchronizerNextTurn();
|
||||||
|
|
||||||
|
void synchronizerSendLocalInputs();
|
||||||
|
|
||||||
|
int synchronizerGetTurnIndex(u32 turn);
|
||||||
|
|
||||||
|
void synchronizerInit(int seed, int initPlayerCount, int initPlayerLocalID) {
|
||||||
|
synchronizerLocalTurn = 0;
|
||||||
|
synchronizerNextSeed = seed;
|
||||||
|
playerCount = initPlayerCount;
|
||||||
|
playerLocalID = initPlayerLocalID;
|
||||||
|
syncTickCount = 0;
|
||||||
|
|
||||||
|
//reset player turn states (e.g. is turn data recieved), first turn needs to happen with no inputs
|
||||||
|
for(int i=0; i<playerCount; i++) {
|
||||||
|
resetKeys(&(players[i].inputs));
|
||||||
|
for(int j=0; j<MAX_INPUT_BUFFER; j++) {
|
||||||
|
resetKeys(&(players[i].nextInputs[j]));
|
||||||
|
}
|
||||||
|
players[i].nextTurnReady[0] = true;
|
||||||
|
players[i].idSet = false;
|
||||||
|
players[i].ready = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
players[playerLocalID].id = localUID;
|
||||||
|
players[playerLocalID].idSet = true;
|
||||||
|
players[playerLocalID].ready = true;
|
||||||
|
|
||||||
|
|
||||||
|
//switch menu
|
||||||
|
currentMenu = MENU_LOADING;
|
||||||
|
|
||||||
|
synchronizerRunning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void synchronizerSendUID() {
|
||||||
|
sendIDPacket(playerLocalID, localUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void synchronizerSetPlayerUID(int playerID, u32 uid) {
|
||||||
|
players[playerID].id = uid;
|
||||||
|
players[playerID].idSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void synchronizerSendIfReady() {
|
||||||
|
//we are ready when we recieved all uids
|
||||||
|
for(int i=0; i<playerCount; i++) {
|
||||||
|
if(!players[i].idSet) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//ready -> send to server
|
||||||
|
sendStartReadyPacket(playerLocalID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void synchronizerSetPlayerReady(int playerID) {
|
||||||
|
players[playerID].ready = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool synchronizerAllReady() {
|
||||||
|
for(int i=0; i<playerCount; i++) {
|
||||||
|
if(!players[i].ready) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void synchronizerStart() {
|
||||||
|
//check if save file is present
|
||||||
|
bool doLoad = false;
|
||||||
|
char *loadName = NULL;
|
||||||
|
|
||||||
|
//host and single player need to load the actual file
|
||||||
|
if(playerLocalID==0) {
|
||||||
|
FILE *file = fopen(currentFileName, "rb");
|
||||||
|
if(file!=NULL) {
|
||||||
|
fclose(file);
|
||||||
|
doLoad = true;
|
||||||
|
loadName = currentFileName;
|
||||||
|
}
|
||||||
|
//all others the transfered one
|
||||||
|
} else {
|
||||||
|
FILE *file = fopen("tmpTransfer.bin", "rb");
|
||||||
|
if(file!=NULL) {
|
||||||
|
fclose(file);
|
||||||
|
doLoad = true;
|
||||||
|
loadName = "tmpTransfer.bin";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset random generators
|
||||||
|
srand(synchronizerNextSeed);
|
||||||
|
gaussrand(true);
|
||||||
|
|
||||||
|
//start the game
|
||||||
|
startGame(doLoad, loadName);
|
||||||
|
|
||||||
|
//remove transfered save file from clients
|
||||||
|
if(playerLocalID!=0) {
|
||||||
|
FILE *file = fopen("tmpTransfer.bin", "rb");
|
||||||
|
if(file!=NULL) {
|
||||||
|
fclose(file);
|
||||||
|
remove("tmpTransfer.bin");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//clear menu
|
||||||
|
currentMenu = MENU_NONE;
|
||||||
|
|
||||||
|
synchronizerRunning = true;
|
||||||
|
synchronizerCurrentTicks = SYNCHRONIZER_TICKS_PER_TURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
void synchronizerTick(void (*gtick)(void)) {
|
||||||
|
if(synchronizerRunning && synchronizerTurnReady()) {
|
||||||
|
synchronizerNextTurn();
|
||||||
|
|
||||||
|
// reset random generators
|
||||||
|
srand(synchronizerNextSeed);
|
||||||
|
gaussrand(true);
|
||||||
|
|
||||||
|
|
||||||
|
syncTickCount++;
|
||||||
|
|
||||||
|
//call game tick
|
||||||
|
(*gtick)();
|
||||||
|
|
||||||
|
synchronizerNextSeed = rand();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Test if all players (including single player) input is recieved
|
||||||
|
bool synchronizerTurnReady() {
|
||||||
|
if(synchronizerCurrentTicks<SYNCHRONIZER_TICKS_PER_TURN) return true;
|
||||||
|
|
||||||
|
for(int i=0; i<playerCount; i++) {
|
||||||
|
if(!players[i].nextTurnReady[synchronizerGetTurnIndex(synchronizerLocalTurn)]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void synchronizerNextTurn() {
|
||||||
|
if(synchronizerCurrentTicks<SYNCHRONIZER_TICKS_PER_TURN) {
|
||||||
|
synchronizerCurrentTicks++;
|
||||||
|
|
||||||
|
//clicked events are only fired for the first tick per turn
|
||||||
|
for(int i=0; i<playerCount; i++) {
|
||||||
|
resetClicked(&(players[i].inputs));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//move nextInput of every player to currentInput
|
||||||
|
for(int i=0; i<playerCount; i++) {
|
||||||
|
players[i].inputs = players[i].nextInputs[synchronizerGetTurnIndex(synchronizerLocalTurn)];
|
||||||
|
players[i].nextTurnReady[synchronizerGetTurnIndex(synchronizerLocalTurn)] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Increase turn number
|
||||||
|
synchronizerLocalTurn++;
|
||||||
|
synchronizerCurrentTicks = 1;
|
||||||
|
|
||||||
|
//send local input
|
||||||
|
synchronizerSendLocalInputs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void synchronizerSendLocalInputs() {
|
||||||
|
//scan local inputs
|
||||||
|
hidScanInput();
|
||||||
|
tickKeys(&localInputs, hidKeysHeld(), hidKeysDown());
|
||||||
|
|
||||||
|
//store local input in nextInput
|
||||||
|
players[playerLocalID].nextInputs[synchronizerGetTurnIndex(synchronizerLocalTurn)] = localInputs;
|
||||||
|
players[playerLocalID].nextTurnReady[synchronizerGetTurnIndex(synchronizerLocalTurn)] = true;
|
||||||
|
|
||||||
|
//send local input
|
||||||
|
if(playerCount>1) {
|
||||||
|
size_t size = writeInputPacket(networkWriteBuffer, &localInputs, playerLocalID, synchronizerLocalTurn);
|
||||||
|
networkSend(networkWriteBuffer, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void synchronizerOnInputPacket(u8 playerID, u32 turnNumber, void *data, size_t dataSize) {
|
||||||
|
if(turnNumber>=synchronizerLocalTurn && turnNumber<synchronizerLocalTurn+MAX_INPUT_BUFFER && playerID<playerCount) {
|
||||||
|
if(readInputPacketData(data, dataSize, &(players[playerID].nextInputs[synchronizerGetTurnIndex(turnNumber)]))) {
|
||||||
|
players[playerID].nextTurnReady[synchronizerGetTurnIndex(turnNumber)] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int synchronizerGetTurnIndex(u32 turn) {
|
||||||
|
return turn%MAX_INPUT_BUFFER;
|
||||||
|
}
|
||||||
|
|
||||||
|
void synchronizerReset() {
|
||||||
|
synchronizerRunning = false;
|
||||||
|
synchronizerCurrentTicks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool synchronizerIsRunning() {
|
||||||
|
return synchronizerRunning;
|
||||||
|
}
|
||||||
|
|
||||||
|
// helpers for random numbers
|
||||||
|
#define PI 3.141592654
|
||||||
|
double gaussrand(bool reset)
|
||||||
|
{
|
||||||
|
static double U, V;
|
||||||
|
static int phase = 0;
|
||||||
|
double Z;
|
||||||
|
|
||||||
|
if(reset) {
|
||||||
|
U = 0;
|
||||||
|
V = 0;
|
||||||
|
phase = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(phase == 0) {
|
||||||
|
U = (rand() + 1.) / (RAND_MAX + 2.);
|
||||||
|
V = rand() / (RAND_MAX + 1.);
|
||||||
|
Z = sqrt(-2 * log(U)) * sin(2 * PI * V);
|
||||||
|
} else {
|
||||||
|
Z = sqrt(-2 * log(U)) * cos(2 * PI * V);
|
||||||
|
}
|
||||||
|
|
||||||
|
phase = 1 - phase;
|
||||||
|
|
||||||
|
return Z;
|
||||||
|
}
|
29
source/Synchronizer.h
Normal file
29
source/Synchronizer.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <3ds.h>
|
||||||
|
|
||||||
|
//2-3 seem be optimal (at least for 2 players)
|
||||||
|
#define SYNCHRONIZER_TICKS_PER_TURN 2
|
||||||
|
|
||||||
|
void synchronizerInit(int seed, int initPlayerCount, int initPlayerLocalID);
|
||||||
|
|
||||||
|
void synchronizerSendUID();
|
||||||
|
void synchronizerSetPlayerUID(int playerID, u32 uid);
|
||||||
|
void synchronizerSendIfReady();
|
||||||
|
void synchronizerSetPlayerReady(int playerID);
|
||||||
|
bool synchronizerAllReady();
|
||||||
|
bool synchronizerIsRunning();
|
||||||
|
|
||||||
|
void synchronizerStart();
|
||||||
|
|
||||||
|
void synchronizerTick(void (*gtick)(void));
|
||||||
|
|
||||||
|
void synchronizerReset();
|
||||||
|
|
||||||
|
void synchronizerOnInputPacket(u8 playerID, u32 turnNumber, void *data, size_t dataSize);
|
||||||
|
|
||||||
|
// values used ingame
|
||||||
|
u32 syncTickCount;
|
||||||
|
|
||||||
|
// helpers for random numbers
|
||||||
|
double gaussrand(bool reset);
|
213
source/ZipHelper.c
Normal file
213
source/ZipHelper.c
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
#include "ZipHelper.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "minizip/zip.h"
|
||||||
|
#include "minizip/unzip.h"
|
||||||
|
|
||||||
|
#define dir_delimter '/'
|
||||||
|
#define MAX_FILENAME 256
|
||||||
|
#define READ_SIZE 9216
|
||||||
|
|
||||||
|
int unzipAndLoad(char *filename, int (*fileCallback)(char *filename), char *expectedComment, int keepFiles) {
|
||||||
|
// Open the zip file
|
||||||
|
unzFile *zipfile = unzOpen(filename);
|
||||||
|
if (zipfile == NULL) {
|
||||||
|
return 1; // Error: ZipFile could not be opened.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get info about the zip file
|
||||||
|
unz_global_info global_info;
|
||||||
|
if (unzGetGlobalInfo(zipfile, &global_info ) != UNZ_OK) {
|
||||||
|
unzClose(zipfile);
|
||||||
|
return 2; // Error: Could not read global info
|
||||||
|
}
|
||||||
|
|
||||||
|
if(expectedComment!=NULL) {
|
||||||
|
char *buffer = malloc(global_info.size_comment+1);
|
||||||
|
if(buffer==NULL) {
|
||||||
|
unzClose(zipfile);
|
||||||
|
return 3; // Error: Could not read global comment
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unzGetGlobalComment(zipfile, buffer, global_info.size_comment+1) < 0) {
|
||||||
|
unzClose(zipfile);
|
||||||
|
return 3; // Error: Could not read global comment
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(expectedComment, buffer)!=0) {
|
||||||
|
unzClose(zipfile);
|
||||||
|
return 4; // Error: Global comment did not have expected value
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer to hold data read from the zip file.
|
||||||
|
void *read_buffer = malloc(READ_SIZE);
|
||||||
|
if(read_buffer==NULL) {
|
||||||
|
// Error: Could not allocate read buffer
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop to extract all files
|
||||||
|
uLong i;
|
||||||
|
for (i = 0; i < global_info.number_entry; ++i) {
|
||||||
|
// Get info about current file.
|
||||||
|
unz_file_info file_info;
|
||||||
|
char filename[MAX_FILENAME];
|
||||||
|
if (unzGetCurrentFileInfo(zipfile, &file_info, filename, MAX_FILENAME, NULL, 0, NULL, 0 ) != UNZ_OK) {
|
||||||
|
free(read_buffer);
|
||||||
|
unzClose(zipfile);
|
||||||
|
return 6; // Error: Could not read file info
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if this entry is NOT a directory or file.
|
||||||
|
const size_t filename_length = strlen(filename);
|
||||||
|
if (filename[ filename_length-1 ] != dir_delimter){
|
||||||
|
if (unzOpenCurrentFile( zipfile ) != UNZ_OK) {
|
||||||
|
free(read_buffer);
|
||||||
|
unzClose(zipfile);
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open a file to write out the data.
|
||||||
|
FILE * out = fopen(filename, "wb");
|
||||||
|
if (out == NULL) {
|
||||||
|
free(read_buffer);
|
||||||
|
unzCloseCurrentFile(zipfile);
|
||||||
|
unzClose(zipfile);
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
int error = UNZ_OK;
|
||||||
|
do {
|
||||||
|
error = unzReadCurrentFile(zipfile, read_buffer, READ_SIZE);
|
||||||
|
if ( error < 0 ) {
|
||||||
|
//printf("error %d\n", error);
|
||||||
|
free(read_buffer);
|
||||||
|
unzCloseCurrentFile(zipfile);
|
||||||
|
unzClose(zipfile);
|
||||||
|
fclose(out);
|
||||||
|
remove(filename);
|
||||||
|
return 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write data to file.
|
||||||
|
if (error > 0) {
|
||||||
|
fwrite(read_buffer, error, 1, out); // You should check return of fwrite...
|
||||||
|
}
|
||||||
|
} while (error > 0);
|
||||||
|
|
||||||
|
fclose(out);
|
||||||
|
|
||||||
|
//run callback
|
||||||
|
if((*fileCallback)(filename) != 0) {
|
||||||
|
free(read_buffer);
|
||||||
|
unzClose(zipfile);
|
||||||
|
remove(filename);
|
||||||
|
return 10; // Error: Callback error
|
||||||
|
}
|
||||||
|
|
||||||
|
if(keepFiles==ZIPHELPER_CLEANUP_FILES) {
|
||||||
|
remove(filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unzCloseCurrentFile(zipfile);
|
||||||
|
|
||||||
|
// Go the the next entry listed in the zip file.
|
||||||
|
if (( i+1 ) < global_info.number_entry) {
|
||||||
|
if (unzGoToNextFile( zipfile ) != UNZ_OK) {
|
||||||
|
free(read_buffer);
|
||||||
|
unzClose(zipfile);
|
||||||
|
return 11;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(read_buffer);
|
||||||
|
unzClose(zipfile);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zipFiles(char *filename, char **files, int fileCount, int mode, char *comment) {
|
||||||
|
// Set mode
|
||||||
|
int zipMode = mode==ZIPHELPER_ADD ? APPEND_STATUS_ADDINZIP : APPEND_STATUS_CREATE;
|
||||||
|
FILE *testFile = fopen(filename, "r");
|
||||||
|
if(testFile!=NULL) {
|
||||||
|
fclose(testFile);
|
||||||
|
} else {
|
||||||
|
zipMode = APPEND_STATUS_CREATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the zip file
|
||||||
|
zipFile *zipfile = zipOpen(filename, zipMode);
|
||||||
|
if (zipfile == NULL) return 1; // Error: ZipFile could not be opened.
|
||||||
|
|
||||||
|
// Buffer to hold data read from the files.
|
||||||
|
void *read_buffer = malloc(READ_SIZE);
|
||||||
|
if(read_buffer==NULL) {
|
||||||
|
// Error: Could not allocate read buffer
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop all files to add
|
||||||
|
for(int i = 0; i < fileCount; i++) {
|
||||||
|
// Open a zipfile to write out the data.
|
||||||
|
if (zipOpenNewFileInZip(zipfile, files[i], NULL, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION) != ZIP_OK) {
|
||||||
|
free(read_buffer);
|
||||||
|
zipClose(zipfile, "");
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open a file to read the data.
|
||||||
|
FILE *in = fopen(files[i], "rb");
|
||||||
|
if (in == NULL) {
|
||||||
|
free(read_buffer);
|
||||||
|
zipCloseFileInZip(zipfile);
|
||||||
|
zipClose(zipfile, "");
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
size = fread(read_buffer, 1, READ_SIZE, in);
|
||||||
|
|
||||||
|
|
||||||
|
if(size<READ_SIZE) {
|
||||||
|
if(!feof(in)) {
|
||||||
|
free(read_buffer);
|
||||||
|
zipCloseFileInZip(zipfile);
|
||||||
|
zipClose(zipfile, "");
|
||||||
|
fclose(in);
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(size>0) {
|
||||||
|
//write data to zip
|
||||||
|
if (zipWriteInFileInZip(zipfile, read_buffer, size) != ZIP_OK) {
|
||||||
|
//printf("error %d\n", error);
|
||||||
|
free(read_buffer);
|
||||||
|
zipCloseFileInZip(zipfile);
|
||||||
|
zipClose(zipfile, "");
|
||||||
|
fclose(in);
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (size > 0);
|
||||||
|
|
||||||
|
fclose(in);
|
||||||
|
|
||||||
|
zipCloseFileInZip(zipfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(read_buffer);
|
||||||
|
zipClose(zipfile, comment);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
10
source/ZipHelper.h
Normal file
10
source/ZipHelper.h
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define ZIPHELPER_REPLACE 0
|
||||||
|
#define ZIPHELPER_ADD 1
|
||||||
|
|
||||||
|
#define ZIPHELPER_KEEP_FILES 0
|
||||||
|
#define ZIPHELPER_CLEANUP_FILES 1
|
||||||
|
|
||||||
|
int unzipAndLoad(char *filename, int (*fileCallback)(char *filename), char *expectedComment, int keepFiles);
|
||||||
|
int zipFiles(char *filename, char **files, int fileCount, int mode, char *comment);
|
380
source/main.c
380
source/main.c
|
@ -13,189 +13,74 @@
|
||||||
#include "Menu.h"
|
#include "Menu.h"
|
||||||
#include "texturepack.h"
|
#include "texturepack.h"
|
||||||
#include "Network.h"
|
#include "Network.h"
|
||||||
|
#include "SaveLoad.h"
|
||||||
|
#include "Ingame.h"
|
||||||
|
#include "Player.h"
|
||||||
|
#include "Synchronizer.h"
|
||||||
|
#include "PacketHandler.h"
|
||||||
|
|
||||||
// TODO: Dungeon is way to difficult
|
// TODO: Dungeon is way to difficult
|
||||||
// -> Skeleton arrows are slower, do a little less damage
|
// -> Skeleton arrows are slower, do a little less damage
|
||||||
// -> Or instead of less damage, implement a simple armor system
|
// -> Or instead of less damage, implement a simple armor system
|
||||||
|
|
||||||
//TODO: Multiplayer should use normal drawing code -> so remove this first test again
|
//TODO: Something still causes desyncs very rarely
|
||||||
float tmxscr = 400;
|
|
||||||
float tmyscr = 400;
|
|
||||||
float tmenuxa = 0.25;
|
|
||||||
float tmenuya = 0.25;
|
|
||||||
|
|
||||||
|
void setupGame() {
|
||||||
|
synchronizerInit(rand(), 1, 0);
|
||||||
|
synchronizerSetPlayerUID(0, localUID);
|
||||||
|
synchronizerStart();
|
||||||
|
|
||||||
void initMiniMapData() {
|
|
||||||
int i;
|
|
||||||
for(i = 0; i < 128 * 128; ++i) {
|
|
||||||
minimapData[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void initMiniMap(bool loadUpWorld) {
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < 5; ++i) {
|
|
||||||
initMinimapLevel(i, loadUpWorld);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void initNewMap() {
|
|
||||||
newSeed();
|
|
||||||
createAndValidateSkyMap(128, 128, 0, map[0], data[0]);
|
|
||||||
createAndValidateTopMap(128, 128, 1, map[1], data[1]);
|
|
||||||
createAndValidateUndergroundMap(128, 128, 1, 2, map[2], data[2]);
|
|
||||||
createAndValidateUndergroundMap(128, 128, 2, 3, map[3], data[3]);
|
|
||||||
createAndValidateUndergroundMap(128, 128, 3, 4, map[4], data[4]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupGame(bool loadUpWorld, bool remote) {
|
|
||||||
currentLevel = 1;
|
|
||||||
|
|
||||||
// Reset entity manager.
|
|
||||||
memset(&eManager, 0, sizeof(eManager));
|
|
||||||
sf2d_set_clear_color(0xFF6C6D82); //sf2d_set_clear_color(RGBA8(0x82, 0x6D, 0x6C, 0xFF));
|
|
||||||
|
|
||||||
initMiniMapData();
|
|
||||||
|
|
||||||
if(!remote) {
|
|
||||||
if (!loadUpWorld) {
|
|
||||||
initNewMap();
|
|
||||||
initPlayer();
|
|
||||||
resetQuests();
|
|
||||||
airWizardHealthDisplay = 2000;
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < 5; ++i) {
|
|
||||||
trySpawn(500, i);
|
|
||||||
}
|
|
||||||
addEntityToList(newAirWizardEntity(630, 820, 0), &eManager);
|
|
||||||
daytime = 6000;
|
|
||||||
day = 0;
|
|
||||||
season = 0;
|
|
||||||
rain = false;
|
|
||||||
} else {
|
|
||||||
initPlayer();
|
|
||||||
resetQuests();
|
|
||||||
loadWorld(currentFileName, &eManager, &player, (u8*) map, (u8*) data);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateMusic(currentLevel, daytime);
|
|
||||||
|
|
||||||
initMiniMap(loadUpWorld);
|
|
||||||
} else {
|
|
||||||
//reset level data so no old data can somehow remain
|
|
||||||
memset(map, 0, 128*128*5 * sizeof(u8));
|
|
||||||
memset(data, 0, 128*128*5 * sizeof(u8));
|
|
||||||
|
|
||||||
currentLevel = 1;
|
|
||||||
|
|
||||||
//TODO: Can Packets get dropped - if yes, should resending be handled by network functions (so I dont need to do it everywhere)
|
|
||||||
networkPacket packet = {
|
|
||||||
.requestMapData = {
|
|
||||||
.type = PACKET_REQUEST_MAPDATA,
|
|
||||||
.level = 1
|
|
||||||
}
|
|
||||||
};
|
|
||||||
networkSend(&packet, sizeof(packetRequestMapData));
|
|
||||||
}
|
|
||||||
|
|
||||||
shouldRenderMap = false;
|
|
||||||
mScrollX = 0;
|
|
||||||
mScrollY = 0;
|
|
||||||
zoomLevel = 2;
|
|
||||||
sprintf(mapText,"x%d",zoomLevel);
|
|
||||||
initGame = 0;
|
initGame = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupBGMap(bool loadUpWorld) {
|
void setupGameServer() {
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
networkHostStopConnections();
|
||||||
|
|
||||||
|
networkStart();
|
||||||
|
|
||||||
|
//send start info (seed)
|
||||||
|
size = writeStartPacket(networkWriteBuffer, rand());
|
||||||
|
networkSend(networkWriteBuffer, size);
|
||||||
|
processPacket(networkWriteBuffer, size);
|
||||||
|
networkSendWaitFlush();
|
||||||
|
|
||||||
|
//send save file if loading
|
||||||
|
FILE *file = fopen(currentFileName, "rb");
|
||||||
|
if(file!=NULL) {
|
||||||
|
sendFile(file, 0, 0);
|
||||||
|
networkSendWaitFlush();
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
//send start command
|
||||||
|
size = writeStartRequestPacket(networkWriteBuffer);
|
||||||
|
networkSend(networkWriteBuffer, size);
|
||||||
|
processPacket(networkWriteBuffer, size);
|
||||||
|
|
||||||
|
initMPGame = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupBGMap() {
|
||||||
// Reset entity manager.
|
// Reset entity manager.
|
||||||
memset(&eManager, 0, sizeof(eManager));
|
memset(&eManager, 0, sizeof(eManager));
|
||||||
sf2d_set_clear_color(0xFF6C6D82); //sf2d_set_clear_color(RGBA8(0x82, 0x6D, 0x6C, 0xFF));
|
sf2d_set_clear_color(0xFF6C6D82);
|
||||||
|
|
||||||
if(!loadUpWorld) {
|
|
||||||
newSeed();
|
srand(time(NULL));
|
||||||
createAndValidateTopMap(128, 128, 1, map[1], data[1]);
|
createAndValidateTopMap(128, 128, 1, worldData.map[1], worldData.data[1]);
|
||||||
} else {
|
|
||||||
loadWorld(currentFileName, &eManager, &player, (u8*) map, (u8*) data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset entity manager.
|
// Reset entity manager.
|
||||||
memset(&eManager, 0, sizeof(eManager));
|
memset(&eManager, 0, sizeof(eManager));
|
||||||
sf2d_set_clear_color(0xFF6C6D82); //sf2d_set_clear_color(RGBA8(0x82, 0x6D, 0x6C, 0xFF));
|
sf2d_set_clear_color(0xFF6C6D82);
|
||||||
|
|
||||||
initBGMap = 0;
|
initBGMap = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int xscr = 0, yscr = 0;
|
|
||||||
void tick() {
|
|
||||||
//TODO: Some stuff DOES need to happen even on client side
|
|
||||||
if(!isRemote) {
|
|
||||||
if (player.p.isDead) {
|
|
||||||
if (player.p.endTimer < 1) {
|
|
||||||
currentMenu = MENU_LOSE;
|
|
||||||
}
|
|
||||||
--player.p.endTimer;
|
|
||||||
return;
|
|
||||||
} else if (player.p.hasWon) {
|
|
||||||
if (player.p.endTimer < 1) {
|
|
||||||
currentMenu = MENU_WIN;
|
|
||||||
}
|
|
||||||
--player.p.endTimer;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
tickTouchMap();
|
//for rendering -> move to a better place
|
||||||
tickTouchQuickSelect();
|
extern int xscr, yscr;
|
||||||
|
|
||||||
++daytime;
|
|
||||||
//daytime += 20;
|
|
||||||
if(daytime>=24000) {
|
|
||||||
daytime -= 24000;
|
|
||||||
++day;
|
|
||||||
//TODO: maybe make season length not as hardcoded + make the transition better (fade to black and back maybe?)
|
|
||||||
if(day%7==0) {
|
|
||||||
++season;
|
|
||||||
if(season==4) season = 0;
|
|
||||||
}
|
|
||||||
rain = false;
|
|
||||||
if(season!=3 && rand()%5==0) rain = true;
|
|
||||||
}
|
|
||||||
if(daytime==6000 && currentLevel==1) {
|
|
||||||
playMusic(music_floor1);
|
|
||||||
} else if(daytime==19000 && currentLevel==1) {
|
|
||||||
playMusic(music_floor1_night);
|
|
||||||
}
|
|
||||||
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < 324; ++i) {
|
|
||||||
int xx = rand() & 127;
|
|
||||||
int yy = rand() & 127;
|
|
||||||
tickTile(xx, yy);
|
|
||||||
}
|
|
||||||
tickPlayer();
|
|
||||||
xscr = player.x - 100;
|
|
||||||
yscr = player.y - 56;
|
|
||||||
if (xscr < 16)
|
|
||||||
xscr = 16;
|
|
||||||
else if (xscr > 1832)
|
|
||||||
xscr = 1832;
|
|
||||||
if (yscr < 16)
|
|
||||||
yscr = 16;
|
|
||||||
else if (yscr > 1912)
|
|
||||||
yscr = 1912;
|
|
||||||
|
|
||||||
if(eManager.lastSlot[currentLevel]<80 && currentLevel != 5) {
|
|
||||||
trySpawn(1, currentLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < eManager.lastSlot[currentLevel]; ++i) {
|
|
||||||
Entity * e = &eManager.entities[currentLevel][i];
|
|
||||||
if ((e->type != ENTITY_ZOMBIE && e->type != ENTITY_SKELETON && e->type != ENTITY_KNIGHT && e->type != ENTITY_SLIME && e->type != ENTITY_PASSIVE)
|
|
||||||
|| (e->type == ENTITY_GLOWWORM && (daytime>6000 || daytime<18000))
|
|
||||||
|| (e->x > player.x - 160 && e->y > player.y - 125 && e->x < player.x + 160 && e->y < player.y + 125))
|
|
||||||
tickEntity(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char debugText[34];
|
char debugText[34];
|
||||||
char bossHealthText[34];
|
char bossHealthText[34];
|
||||||
|
@ -214,19 +99,36 @@ int main() {
|
||||||
csndInit();
|
csndInit();
|
||||||
networkInit();
|
networkInit();
|
||||||
|
|
||||||
|
srand(time(NULL));
|
||||||
|
|
||||||
|
//load or create localUID
|
||||||
|
if ((file = fopen("m3ds_uid.bin", "rb"))) {
|
||||||
|
fread(&localUID, sizeof(u32), 1, file);
|
||||||
|
fclose(file);
|
||||||
|
} else {
|
||||||
|
localUID = (((u32) (rand()%256))<<24) | (((u32) (rand()%256))<<16) | (((u32) (rand()%256))<<8) | (((u32) (rand()%256)));
|
||||||
|
|
||||||
|
if ((file = fopen("m3ds_uid.bin", "wb"))) {
|
||||||
|
fwrite(&localUID, sizeof(u32), 1, file);
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
noItem = newItem(ITEM_NULL, 0);
|
noItem = newItem(ITEM_NULL, 0);
|
||||||
|
|
||||||
initMenus();
|
initMenus();
|
||||||
currentMenu = MENU_TITLE;
|
currentMenu = MENU_TITLE;
|
||||||
currentSelection = 0;
|
currentSelection = 0;
|
||||||
quitGame = false;
|
quitGame = false;
|
||||||
|
initBGMap = 1;
|
||||||
|
|
||||||
icons = sfil_load_PNG_buffer(icons2_png, SF2D_PLACE_RAM);
|
icons = sfil_load_PNG_buffer(icons2_png, SF2D_PLACE_RAM);
|
||||||
|
playerSprites = sfil_load_PNG_buffer(player_png, SF2D_PLACE_RAM);
|
||||||
font = sfil_load_PNG_buffer(Font_png, SF2D_PLACE_RAM);
|
font = sfil_load_PNG_buffer(Font_png, SF2D_PLACE_RAM);
|
||||||
bottombg = sfil_load_PNG_buffer(bottombg_png, SF2D_PLACE_RAM);
|
bottombg = sfil_load_PNG_buffer(bottombg_png, SF2D_PLACE_RAM);
|
||||||
|
|
||||||
loadSounds();
|
loadSounds();
|
||||||
playMusic(music_menu);
|
playMusic(&music_menu);
|
||||||
|
|
||||||
bakeLights();
|
bakeLights();
|
||||||
|
|
||||||
|
@ -244,33 +146,33 @@ int main() {
|
||||||
sf2d_set_clear_color(0xFF);
|
sf2d_set_clear_color(0xFF);
|
||||||
|
|
||||||
/* Default inputs */
|
/* Default inputs */
|
||||||
k_up.input = KEY_DUP | KEY_CPAD_UP | KEY_CSTICK_UP;
|
localInputs.k_up.input = KEY_DUP | KEY_CPAD_UP | KEY_CSTICK_UP;
|
||||||
k_down.input = KEY_DDOWN | KEY_CPAD_DOWN | KEY_CSTICK_DOWN;
|
localInputs.k_down.input = KEY_DDOWN | KEY_CPAD_DOWN | KEY_CSTICK_DOWN;
|
||||||
k_left.input = KEY_DLEFT | KEY_CPAD_LEFT | KEY_CSTICK_LEFT;
|
localInputs.k_left.input = KEY_DLEFT | KEY_CPAD_LEFT | KEY_CSTICK_LEFT;
|
||||||
k_right.input = KEY_DRIGHT | KEY_CPAD_RIGHT | KEY_CSTICK_RIGHT;
|
localInputs.k_right.input = KEY_DRIGHT | KEY_CPAD_RIGHT | KEY_CSTICK_RIGHT;
|
||||||
k_attack.input = KEY_A | KEY_B | KEY_L | KEY_ZR;
|
localInputs.k_attack.input = KEY_A | KEY_B | KEY_L | KEY_ZR;
|
||||||
k_menu.input = KEY_X | KEY_Y | KEY_R | KEY_ZL;
|
localInputs.k_menu.input = KEY_X | KEY_Y | KEY_R | KEY_ZL;
|
||||||
k_pause.input = KEY_START;
|
localInputs.k_pause.input = KEY_START;
|
||||||
k_accept.input = KEY_A;
|
localInputs.k_accept.input = KEY_A;
|
||||||
k_decline.input = KEY_B;
|
localInputs.k_decline.input = KEY_B;
|
||||||
k_delete.input = KEY_X;
|
localInputs.k_delete.input = KEY_X;
|
||||||
k_menuNext.input = KEY_R;
|
localInputs.k_menuNext.input = KEY_R;
|
||||||
k_menuPrev.input = KEY_L;
|
localInputs.k_menuPrev.input = KEY_L;
|
||||||
|
|
||||||
/* If btnSave exists, then use that. */
|
/* If btnSave exists, then use that. */
|
||||||
if ((file = fopen("btnSave.bin", "rb"))) {
|
if ((file = fopen("btnSave.bin", "rb"))) {
|
||||||
fread(&k_up.input, sizeof(int), 1, file);
|
fread(&(localInputs.k_up.input), sizeof(int), 1, file);
|
||||||
fread(&k_down.input, sizeof(int), 1, file);
|
fread(&(localInputs.k_down.input), sizeof(int), 1, file);
|
||||||
fread(&k_left.input, sizeof(int), 1, file);
|
fread(&(localInputs.k_left.input), sizeof(int), 1, file);
|
||||||
fread(&k_right.input, sizeof(int), 1, file);
|
fread(&(localInputs.k_right.input), sizeof(int), 1, file);
|
||||||
fread(&k_attack.input, sizeof(int), 1, file);
|
fread(&(localInputs.k_attack.input), sizeof(int), 1, file);
|
||||||
fread(&k_menu.input, sizeof(int), 1, file);
|
fread(&(localInputs.k_menu.input), sizeof(int), 1, file);
|
||||||
fread(&k_pause.input, sizeof(int), 1, file);
|
fread(&(localInputs.k_pause.input), sizeof(int), 1, file);
|
||||||
fread(&k_accept.input, sizeof(int), 1, file);
|
fread(&(localInputs.k_accept.input), sizeof(int), 1, file);
|
||||||
fread(&k_decline.input, sizeof(int), 1, file);
|
fread(&(localInputs.k_decline.input), sizeof(int), 1, file);
|
||||||
fread(&k_delete.input, sizeof(int), 1, file);
|
fread(&(localInputs.k_delete.input), sizeof(int), 1, file);
|
||||||
fread(&k_menuNext.input, sizeof(int), 1, file);
|
fread(&(localInputs.k_menuNext.input), sizeof(int), 1, file);
|
||||||
fread(&k_menuPrev.input, sizeof(int), 1, file);
|
fread(&(localInputs.k_menuPrev.input), sizeof(int), 1, file);
|
||||||
fclose(file);
|
fclose(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,101 +184,24 @@ int main() {
|
||||||
fclose(file);
|
fclose(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
tickCount = 0;
|
initPlayers();
|
||||||
initRecipes();
|
initRecipes();
|
||||||
initQuests();
|
initTrades();
|
||||||
while (aptMainLoop()) {
|
while (aptMainLoop()) {
|
||||||
++tickCount;
|
|
||||||
hidScanInput();
|
|
||||||
tickKeys(hidKeysHeld(), hidKeysDown());
|
|
||||||
|
|
||||||
if (quitGame) break;
|
if (quitGame) break;
|
||||||
|
|
||||||
if (initGame > 0) setupGame(initGame == 1 ? true : false, isRemote);
|
if (initGame > 0 && --initGame==0) setupGame();
|
||||||
if (initBGMap > 0) setupBGMap(initBGMap == 1 ? true : false);
|
if (initMPGame > 0 && --initMPGame==0) setupGameServer();
|
||||||
|
if (initBGMap > 0 && --initBGMap==0) setupBGMap();
|
||||||
|
|
||||||
networkRecieve();
|
if (currentMenu == MENU_NONE) {
|
||||||
|
tickGame();
|
||||||
if (currentMenu == 0) {
|
renderGame();
|
||||||
tick();
|
|
||||||
//TODO: Multiplayer should use normal drawing code -> so remove this first test again
|
|
||||||
if(!isRemote) {
|
|
||||||
sf2d_start_frame(GFX_TOP, GFX_LEFT);
|
|
||||||
|
|
||||||
offsetX = xscr;
|
|
||||||
offsetY = yscr;
|
|
||||||
sf2d_draw_rectangle(0, 0, 400, 240, 0xFF0C0C0C); //RGBA8(12, 12, 12, 255)); //You might think "real" black would be better, but it actually looks better that way
|
|
||||||
|
|
||||||
renderLightsToStencil(false, false, true);
|
|
||||||
|
|
||||||
renderBackground(xscr, yscr);
|
|
||||||
renderEntities(player.x, player.y, &eManager);
|
|
||||||
renderPlayer();
|
|
||||||
renderWeather(xscr, yscr);
|
|
||||||
|
|
||||||
resetStencilStuff();
|
|
||||||
|
|
||||||
renderDayNight();
|
|
||||||
|
|
||||||
offsetX = 0;
|
|
||||||
offsetY = 0;
|
|
||||||
|
|
||||||
if(shouldRenderDebug){
|
|
||||||
sprintf(fpsstr, "FPS: %.0f X:%d Y:%d E:%d %d", sf2d_get_fps(), player.x, player.y, eManager.lastSlot[currentLevel], player.p.swimBreathTimer);
|
|
||||||
drawText(fpsstr, 2, 225);
|
|
||||||
}
|
|
||||||
|
|
||||||
sf2d_end_frame();
|
|
||||||
|
|
||||||
sf2d_start_frame(GFX_BOTTOM, GFX_LEFT);
|
|
||||||
if(!shouldRenderMap){
|
|
||||||
sf2d_draw_texture(bottombg, 0, 0);
|
|
||||||
renderGui();
|
|
||||||
} else {
|
|
||||||
renderZoomedMap();
|
|
||||||
}
|
|
||||||
sf2d_end_frame();
|
|
||||||
//TODO: Multiplayer should use normal drawing code -> so remove this first test again
|
|
||||||
} else {
|
|
||||||
//TODO: Temporary way of getting back to the menu
|
|
||||||
if (k_pause.clicked){
|
|
||||||
sf2d_set_clear_color(0xFF);
|
|
||||||
currentSelection = 0;
|
|
||||||
currentMenu = MENU_TITLE;
|
|
||||||
|
|
||||||
networkDisconnect();
|
|
||||||
|
|
||||||
playMusic(music_menu);
|
|
||||||
}
|
|
||||||
|
|
||||||
tmxscr += tmenuxa;
|
|
||||||
tmyscr += tmenuya;
|
|
||||||
|
|
||||||
if (tmxscr < 16) {
|
|
||||||
tmxscr = 16;
|
|
||||||
tmenuxa = -tmenuxa;
|
|
||||||
} else if (tmxscr > 1832) {
|
|
||||||
tmxscr = 1832;
|
|
||||||
tmenuxa = -tmenuxa;
|
|
||||||
}
|
|
||||||
if (tmyscr < 16) {
|
|
||||||
tmyscr = 16;
|
|
||||||
tmenuya = -tmenuya;
|
|
||||||
} else if (tmyscr > 1792) {
|
|
||||||
tmyscr = 1792;
|
|
||||||
tmenuya = -tmenuya;
|
|
||||||
}
|
|
||||||
|
|
||||||
sf2d_start_frame(GFX_TOP, GFX_LEFT);
|
|
||||||
offsetX = (int) tmxscr; offsetY = (int) tmyscr;
|
|
||||||
renderBackground((int) tmxscr, (int) tmyscr);
|
|
||||||
offsetX = 0; offsetY = 0;
|
|
||||||
sf2d_end_frame();
|
|
||||||
|
|
||||||
sf2d_start_frame(GFX_BOTTOM, GFX_LEFT);
|
|
||||||
sf2d_end_frame();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
//input scanning ingame is handled by the synchronizer
|
||||||
|
hidScanInput();
|
||||||
|
tickKeys(&localInputs, hidKeysHeld(), hidKeysDown());
|
||||||
|
|
||||||
tickMenu(currentMenu);
|
tickMenu(currentMenu);
|
||||||
renderMenu(currentMenu, xscr, yscr);
|
renderMenu(currentMenu, xscr, yscr);
|
||||||
}
|
}
|
||||||
|
@ -386,8 +211,9 @@ int main() {
|
||||||
|
|
||||||
stopMusic();
|
stopMusic();
|
||||||
|
|
||||||
freeQuests();
|
freeTrades();
|
||||||
freeRecipes();
|
freeRecipes();
|
||||||
|
freePlayers();
|
||||||
|
|
||||||
freeLightBakes();
|
freeLightBakes();
|
||||||
sf2d_free_texture(icons);
|
sf2d_free_texture(icons);
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/* crypt.h -- base code for crypt/uncrypt ZIPfile
|
/* crypt.h -- base code for crypt/uncrypt ZIPfile
|
||||||
|
|
||||||
|
|
||||||
Version 1.01h, December 28th, 2009
|
Version 1.01e, February 12th, 2005
|
||||||
|
|
||||||
Copyright (C) 1998-2009 Gilles Vollant
|
Copyright (C) 1998-2005 Gilles Vollant
|
||||||
|
|
||||||
This code is a modified version of crypting code in Infozip distribution
|
This code is a modified version of crypting code in Infozip distribution
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/* ioapi.c -- IO base function header for compress/uncompress .zip
|
/* ioapi.c -- IO base function header for compress/uncompress .zip
|
||||||
files using zlib + zip or unzip API
|
files using zlib + zip or unzip API
|
||||||
|
|
||||||
Version 1.01h, December 28th, 2009
|
Version 1.01e, February 12th, 2005
|
||||||
|
|
||||||
Copyright (C) 1998-2009 Gilles Vollant
|
Copyright (C) 1998-2005 Gilles Vollant
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -141,8 +141,7 @@ long ZCALLBACK fseek_file_func (opaque, stream, offset, origin)
|
||||||
default: return -1;
|
default: return -1;
|
||||||
}
|
}
|
||||||
ret = 0;
|
ret = 0;
|
||||||
if (fseek((FILE *)stream, offset, fseek_origin) != 0)
|
fseek((FILE *)stream, offset, fseek_origin);
|
||||||
ret = -1;
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/* ioapi.h -- IO base function header for compress/uncompress .zip
|
/* ioapi.h -- IO base function header for compress/uncompress .zip
|
||||||
files using zlib + zip or unzip API
|
files using zlib + zip or unzip API
|
||||||
|
|
||||||
Version 1.01h, December 28th, 2009
|
Version 1.01e, February 12th, 2005
|
||||||
|
|
||||||
Copyright (C) 1998-2009 Gilles Vollant
|
Copyright (C) 1998-2005 Gilles Vollant
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _ZLIBIOAPI_H
|
#ifndef _ZLIBIOAPI_H
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* unzip.c -- IO for uncompress .zip files using zlib
|
/* unzip.c -- IO for uncompress .zip files using zlib
|
||||||
Version 1.01h, December 28th, 2009
|
Version 1.01e, February 12th, 2005
|
||||||
|
|
||||||
Copyright (C) 1998-2009 Gilles Vollant
|
Copyright (C) 1998-2005 Gilles Vollant
|
||||||
|
|
||||||
Read unzip.h for more info
|
Read unzip.h for more info
|
||||||
*/
|
*/
|
||||||
|
@ -103,9 +103,6 @@ typedef struct
|
||||||
{
|
{
|
||||||
char *read_buffer; /* internal buffer for compressed data */
|
char *read_buffer; /* internal buffer for compressed data */
|
||||||
z_stream stream; /* zLib stream structure for inflate */
|
z_stream stream; /* zLib stream structure for inflate */
|
||||||
#ifdef HAVE_BZIP2
|
|
||||||
bz_stream bstream; /* bzLib stream structure for bziped */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/
|
uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/
|
||||||
uLong stream_initialised; /* flag set if stream structure is initialised*/
|
uLong stream_initialised; /* flag set if stream structure is initialised*/
|
||||||
|
@ -207,7 +204,7 @@ local int unzlocal_getShort (pzlib_filefunc_def,filestream,pX)
|
||||||
uLong *pX;
|
uLong *pX;
|
||||||
{
|
{
|
||||||
uLong x ;
|
uLong x ;
|
||||||
int i = 0;
|
int i;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
|
err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
|
||||||
|
@ -235,7 +232,7 @@ local int unzlocal_getLong (pzlib_filefunc_def,filestream,pX)
|
||||||
uLong *pX;
|
uLong *pX;
|
||||||
{
|
{
|
||||||
uLong x ;
|
uLong x ;
|
||||||
int i = 0;
|
int i;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
|
err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
|
||||||
|
@ -494,11 +491,8 @@ extern unzFile ZEXPORT unzOpen2 (path, pzlib_filefunc_def)
|
||||||
|
|
||||||
|
|
||||||
s=(unz_s*)ALLOC(sizeof(unz_s));
|
s=(unz_s*)ALLOC(sizeof(unz_s));
|
||||||
if (s!=NULL)
|
*s=us;
|
||||||
{
|
unzGoToFirstFile((unzFile)s);
|
||||||
*s=us;
|
|
||||||
unzGoToFirstFile((unzFile)s);
|
|
||||||
}
|
|
||||||
return (unzFile)s;
|
return (unzFile)s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -614,12 +608,10 @@ local int unzlocal_GetCurrentFileInfoInternal (file,
|
||||||
|
|
||||||
/* we check the magic */
|
/* we check the magic */
|
||||||
if (err==UNZ_OK)
|
if (err==UNZ_OK)
|
||||||
{
|
|
||||||
if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
|
if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
|
||||||
err=UNZ_ERRNO;
|
err=UNZ_ERRNO;
|
||||||
else if (uMagic!=0x02014b50)
|
else if (uMagic!=0x02014b50)
|
||||||
err=UNZ_BADZIPFILE;
|
err=UNZ_BADZIPFILE;
|
||||||
}
|
|
||||||
|
|
||||||
if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK)
|
if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK)
|
||||||
err=UNZ_ERRNO;
|
err=UNZ_ERRNO;
|
||||||
|
@ -696,13 +688,10 @@ local int unzlocal_GetCurrentFileInfoInternal (file,
|
||||||
uSizeRead = extraFieldBufferSize;
|
uSizeRead = extraFieldBufferSize;
|
||||||
|
|
||||||
if (lSeek!=0)
|
if (lSeek!=0)
|
||||||
{
|
|
||||||
if (ZSEEK(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
|
if (ZSEEK(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
|
||||||
lSeek=0;
|
lSeek=0;
|
||||||
else
|
else
|
||||||
err=UNZ_ERRNO;
|
err=UNZ_ERRNO;
|
||||||
}
|
|
||||||
|
|
||||||
if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))
|
if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))
|
||||||
if (ZREAD(s->z_filefunc, s->filestream,extraField,uSizeRead)!=uSizeRead)
|
if (ZREAD(s->z_filefunc, s->filestream,extraField,uSizeRead)!=uSizeRead)
|
||||||
err=UNZ_ERRNO;
|
err=UNZ_ERRNO;
|
||||||
|
@ -724,13 +713,10 @@ local int unzlocal_GetCurrentFileInfoInternal (file,
|
||||||
uSizeRead = commentBufferSize;
|
uSizeRead = commentBufferSize;
|
||||||
|
|
||||||
if (lSeek!=0)
|
if (lSeek!=0)
|
||||||
{
|
|
||||||
if (ZSEEK(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
|
if (ZSEEK(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
|
||||||
lSeek=0;
|
lSeek=0;
|
||||||
else
|
else
|
||||||
err=UNZ_ERRNO;
|
err=UNZ_ERRNO;
|
||||||
}
|
|
||||||
|
|
||||||
if ((file_info.size_file_comment>0) && (commentBufferSize>0))
|
if ((file_info.size_file_comment>0) && (commentBufferSize>0))
|
||||||
if (ZREAD(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead)
|
if (ZREAD(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead)
|
||||||
err=UNZ_ERRNO;
|
err=UNZ_ERRNO;
|
||||||
|
@ -991,12 +977,10 @@ local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar,
|
||||||
|
|
||||||
|
|
||||||
if (err==UNZ_OK)
|
if (err==UNZ_OK)
|
||||||
{
|
|
||||||
if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
|
if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
|
||||||
err=UNZ_ERRNO;
|
err=UNZ_ERRNO;
|
||||||
else if (uMagic!=0x04034b50)
|
else if (uMagic!=0x04034b50)
|
||||||
err=UNZ_BADZIPFILE;
|
err=UNZ_BADZIPFILE;
|
||||||
}
|
|
||||||
|
|
||||||
if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)
|
if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)
|
||||||
err=UNZ_ERRNO;
|
err=UNZ_ERRNO;
|
||||||
|
@ -1013,9 +997,6 @@ local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar,
|
||||||
err=UNZ_BADZIPFILE;
|
err=UNZ_BADZIPFILE;
|
||||||
|
|
||||||
if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&
|
if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&
|
||||||
/* #ifdef HAVE_BZIP2 */
|
|
||||||
(s->cur_file_info.compression_method!=Z_BZIP2ED) &&
|
|
||||||
/* #endif */
|
|
||||||
(s->cur_file_info.compression_method!=Z_DEFLATED))
|
(s->cur_file_info.compression_method!=Z_DEFLATED))
|
||||||
err=UNZ_BADZIPFILE;
|
err=UNZ_BADZIPFILE;
|
||||||
|
|
||||||
|
@ -1130,9 +1111,6 @@ extern int ZEXPORT unzOpenCurrentFile3 (file, method, level, raw, password)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((s->cur_file_info.compression_method!=0) &&
|
if ((s->cur_file_info.compression_method!=0) &&
|
||||||
/* #ifdef HAVE_BZIP2 */
|
|
||||||
(s->cur_file_info.compression_method!=Z_BZIP2ED) &&
|
|
||||||
/* #endif */
|
|
||||||
(s->cur_file_info.compression_method!=Z_DEFLATED))
|
(s->cur_file_info.compression_method!=Z_DEFLATED))
|
||||||
err=UNZ_BADZIPFILE;
|
err=UNZ_BADZIPFILE;
|
||||||
|
|
||||||
|
@ -1146,34 +1124,6 @@ extern int ZEXPORT unzOpenCurrentFile3 (file, method, level, raw, password)
|
||||||
|
|
||||||
pfile_in_zip_read_info->stream.total_out = 0;
|
pfile_in_zip_read_info->stream.total_out = 0;
|
||||||
|
|
||||||
if ((s->cur_file_info.compression_method==Z_BZIP2ED) &&
|
|
||||||
(!raw))
|
|
||||||
{
|
|
||||||
#ifdef HAVE_BZIP2
|
|
||||||
pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0;
|
|
||||||
pfile_in_zip_read_info->bstream.bzfree = (free_func)0;
|
|
||||||
pfile_in_zip_read_info->bstream.opaque = (voidpf)0;
|
|
||||||
pfile_in_zip_read_info->bstream.state = (voidpf)0;
|
|
||||||
|
|
||||||
pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
|
|
||||||
pfile_in_zip_read_info->stream.zfree = (free_func)0;
|
|
||||||
pfile_in_zip_read_info->stream.opaque = (voidpf)0;
|
|
||||||
pfile_in_zip_read_info->stream.next_in = (voidpf)0;
|
|
||||||
pfile_in_zip_read_info->stream.avail_in = 0;
|
|
||||||
|
|
||||||
err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0);
|
|
||||||
if (err == Z_OK)
|
|
||||||
pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TRYFREE(pfile_in_zip_read_info);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
pfile_in_zip_read_info->raw=1;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if ((s->cur_file_info.compression_method==Z_DEFLATED) &&
|
if ((s->cur_file_info.compression_method==Z_DEFLATED) &&
|
||||||
(!raw))
|
(!raw))
|
||||||
{
|
{
|
||||||
|
@ -1185,7 +1135,7 @@ extern int ZEXPORT unzOpenCurrentFile3 (file, method, level, raw, password)
|
||||||
|
|
||||||
err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
|
err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
|
||||||
if (err == Z_OK)
|
if (err == Z_OK)
|
||||||
pfile_in_zip_read_info->stream_initialised=Z_DEFLATED;
|
pfile_in_zip_read_info->stream_initialised=1;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TRYFREE(pfile_in_zip_read_info);
|
TRYFREE(pfile_in_zip_read_info);
|
||||||
|
@ -1213,8 +1163,6 @@ extern int ZEXPORT unzOpenCurrentFile3 (file, method, level, raw, password)
|
||||||
|
|
||||||
s->pfile_in_zip_read = pfile_in_zip_read_info;
|
s->pfile_in_zip_read = pfile_in_zip_read_info;
|
||||||
|
|
||||||
s->encrypted = 0;
|
|
||||||
|
|
||||||
# ifndef NOUNCRYPT
|
# ifndef NOUNCRYPT
|
||||||
if (password != NULL)
|
if (password != NULL)
|
||||||
{
|
{
|
||||||
|
@ -1386,53 +1334,6 @@ extern int ZEXPORT unzReadCurrentFile (file, buf, len)
|
||||||
iRead += uDoCopy;
|
iRead += uDoCopy;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_BZIP2
|
|
||||||
uLong uTotalOutBefore,uTotalOutAfter;
|
|
||||||
const Bytef *bufBefore;
|
|
||||||
uLong uOutThis;
|
|
||||||
|
|
||||||
pfile_in_zip_read_info->bstream.next_in = pfile_in_zip_read_info->stream.next_in;
|
|
||||||
pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in;
|
|
||||||
pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in;
|
|
||||||
pfile_in_zip_read_info->bstream.total_in_hi32 = 0;
|
|
||||||
pfile_in_zip_read_info->bstream.next_out = pfile_in_zip_read_info->stream.next_out;
|
|
||||||
pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out;
|
|
||||||
pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out;
|
|
||||||
pfile_in_zip_read_info->bstream.total_out_hi32 = 0;
|
|
||||||
|
|
||||||
uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32;
|
|
||||||
bufBefore = pfile_in_zip_read_info->bstream.next_out;
|
|
||||||
|
|
||||||
err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream);
|
|
||||||
|
|
||||||
uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32;
|
|
||||||
uOutThis = uTotalOutAfter-uTotalOutBefore;
|
|
||||||
|
|
||||||
pfile_in_zip_read_info->crc32 =
|
|
||||||
crc32(pfile_in_zip_read_info->crc32,bufBefore,
|
|
||||||
(uInt)(uOutThis));
|
|
||||||
|
|
||||||
pfile_in_zip_read_info->rest_read_uncompressed -=
|
|
||||||
uOutThis;
|
|
||||||
|
|
||||||
iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
|
|
||||||
|
|
||||||
pfile_in_zip_read_info->stream.next_in = pfile_in_zip_read_info->bstream.next_in;
|
|
||||||
pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in;
|
|
||||||
pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32;
|
|
||||||
pfile_in_zip_read_info->stream.next_out = pfile_in_zip_read_info->bstream.next_out;
|
|
||||||
pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out;
|
|
||||||
pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32;
|
|
||||||
|
|
||||||
if (err==BZ_STREAM_END)
|
|
||||||
return (iRead==0) ? UNZ_EOF : iRead;
|
|
||||||
if (err!=BZ_OK)
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
uLong uTotalOutBefore,uTotalOutAfter;
|
uLong uTotalOutBefore,uTotalOutAfter;
|
||||||
const Bytef *bufBefore;
|
const Bytef *bufBefore;
|
||||||
|
@ -1611,12 +1512,8 @@ extern int ZEXPORT unzCloseCurrentFile (file)
|
||||||
|
|
||||||
TRYFREE(pfile_in_zip_read_info->read_buffer);
|
TRYFREE(pfile_in_zip_read_info->read_buffer);
|
||||||
pfile_in_zip_read_info->read_buffer = NULL;
|
pfile_in_zip_read_info->read_buffer = NULL;
|
||||||
if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED)
|
if (pfile_in_zip_read_info->stream_initialised)
|
||||||
inflateEnd(&pfile_in_zip_read_info->stream);
|
inflateEnd(&pfile_in_zip_read_info->stream);
|
||||||
#ifdef HAVE_BZIP2
|
|
||||||
else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED)
|
|
||||||
BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pfile_in_zip_read_info->stream_initialised = 0;
|
pfile_in_zip_read_info->stream_initialised = 0;
|
||||||
TRYFREE(pfile_in_zip_read_info);
|
TRYFREE(pfile_in_zip_read_info);
|
||||||
|
@ -1637,6 +1534,7 @@ extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf)
|
||||||
char *szComment;
|
char *szComment;
|
||||||
uLong uSizeBuf;
|
uLong uSizeBuf;
|
||||||
{
|
{
|
||||||
|
int err=UNZ_OK;
|
||||||
unz_s* s;
|
unz_s* s;
|
||||||
uLong uReadThis ;
|
uLong uReadThis ;
|
||||||
if (file==NULL)
|
if (file==NULL)
|
||||||
|
@ -1669,7 +1567,7 @@ extern uLong ZEXPORT unzGetOffset (file)
|
||||||
unz_s* s;
|
unz_s* s;
|
||||||
|
|
||||||
if (file==NULL)
|
if (file==NULL)
|
||||||
return 0;
|
return UNZ_PARAMERROR;
|
||||||
s=(unz_s*)file;
|
s=(unz_s*)file;
|
||||||
if (!s->current_file_ok)
|
if (!s->current_file_ok)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* unzip.h -- IO for uncompress .zip files using zlib
|
/* unzip.h -- IO for uncompress .zip files using zlib
|
||||||
Version 1.01h, December 28th, 2009
|
Version 1.01e, February 12th, 2005
|
||||||
|
|
||||||
Copyright (C) 1998-2009 Gilles Vollant
|
Copyright (C) 1998-2005 Gilles Vollant
|
||||||
|
|
||||||
This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g
|
This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g
|
||||||
WinZip, InfoZip tools and compatible.
|
WinZip, InfoZip tools and compatible.
|
||||||
|
@ -57,12 +57,6 @@ extern "C" {
|
||||||
#include "ioapi.h"
|
#include "ioapi.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_BZIP2
|
|
||||||
#include "bzlib.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define Z_BZIP2ED 12
|
|
||||||
|
|
||||||
#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
|
#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
|
||||||
/* like the STRICT of WIN32, we define a pointer that cannot be converted
|
/* like the STRICT of WIN32, we define a pointer that cannot be converted
|
||||||
from (void*) without cast */
|
from (void*) without cast */
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/* zip.c -- IO on .zip files using zlib
|
/* zip.c -- IO on .zip files using zlib
|
||||||
Version 1.01h, December 28th, 2009
|
Version 1.01e, February 12th, 2005
|
||||||
|
|
||||||
27 Dec 2004 Rolf Kalbermatter
|
27 Dec 2004 Rolf Kalbermatter
|
||||||
Modification to zipOpen2 to support globalComment retrieval.
|
Modification to zipOpen2 to support globalComment retrieval.
|
||||||
|
|
||||||
Copyright (C) 1998-2009 Gilles Vollant
|
Copyright (C) 1998-2005 Gilles Vollant
|
||||||
|
|
||||||
Read zip.h for more info
|
Read zip.h for more info
|
||||||
*/
|
*/
|
||||||
|
@ -320,9 +320,9 @@ local uLong ziplocal_TmzDateToDosDate(ptm,dosDate)
|
||||||
uLong dosDate;
|
uLong dosDate;
|
||||||
{
|
{
|
||||||
uLong year = (uLong)ptm->tm_year;
|
uLong year = (uLong)ptm->tm_year;
|
||||||
if (year>=1980)
|
if (year>1980)
|
||||||
year-=1980;
|
year-=1980;
|
||||||
else if (year>=80)
|
else if (year>80)
|
||||||
year-=80;
|
year-=80;
|
||||||
return
|
return
|
||||||
(uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) |
|
(uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) |
|
||||||
|
@ -373,7 +373,7 @@ local int ziplocal_getShort (pzlib_filefunc_def,filestream,pX)
|
||||||
uLong *pX;
|
uLong *pX;
|
||||||
{
|
{
|
||||||
uLong x ;
|
uLong x ;
|
||||||
int i = 0;
|
int i;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i);
|
err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i);
|
||||||
|
@ -401,7 +401,7 @@ local int ziplocal_getLong (pzlib_filefunc_def,filestream,pX)
|
||||||
uLong *pX;
|
uLong *pX;
|
||||||
{
|
{
|
||||||
uLong x ;
|
uLong x ;
|
||||||
int i = 0;
|
int i;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i);
|
err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i);
|
||||||
|
@ -432,69 +432,67 @@ local int ziplocal_getLong (pzlib_filefunc_def,filestream,pX)
|
||||||
/*
|
/*
|
||||||
Locate the Central directory of a zipfile (at the end, just before
|
Locate the Central directory of a zipfile (at the end, just before
|
||||||
the global comment)
|
the global comment)
|
||||||
Fix from Riccardo Cohen
|
|
||||||
*/
|
*/
|
||||||
local uLong ziplocal_SearchCentralDir OF((
|
local uLong ziplocal_SearchCentralDir OF((
|
||||||
const zlib_filefunc_def* pzlib_filefunc_def,
|
const zlib_filefunc_def* pzlib_filefunc_def,
|
||||||
voidpf filestream));
|
voidpf filestream));
|
||||||
|
|
||||||
local uLong ziplocal_SearchCentralDir(pzlib_filefunc_def,filestream)
|
local uLong ziplocal_SearchCentralDir(pzlib_filefunc_def,filestream)
|
||||||
const zlib_filefunc_def* pzlib_filefunc_def;
|
const zlib_filefunc_def* pzlib_filefunc_def;
|
||||||
voidpf filestream;
|
voidpf filestream;
|
||||||
{
|
{
|
||||||
unsigned char* buf;
|
unsigned char* buf;
|
||||||
uLong uSizeFile;
|
uLong uSizeFile;
|
||||||
uLong uBackRead;
|
uLong uBackRead;
|
||||||
uLong uMaxBack=0xffff; /* maximum size of global comment */
|
uLong uMaxBack=0xffff; /* maximum size of global comment */
|
||||||
uLong uPosFound=0;
|
uLong uPosFound=0;
|
||||||
|
|
||||||
if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
|
if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
||||||
uSizeFile = ZTELL(*pzlib_filefunc_def,filestream);
|
uSizeFile = ZTELL(*pzlib_filefunc_def,filestream);
|
||||||
|
|
||||||
if (uMaxBack>uSizeFile)
|
if (uMaxBack>uSizeFile)
|
||||||
uMaxBack = uSizeFile;
|
uMaxBack = uSizeFile;
|
||||||
|
|
||||||
buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
|
buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
|
||||||
if (buf==NULL)
|
if (buf==NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
uBackRead = 4;
|
uBackRead = 4;
|
||||||
while (uBackRead<uMaxBack)
|
while (uBackRead<uMaxBack)
|
||||||
{
|
{
|
||||||
uLong uReadSize,uReadPos ;
|
uLong uReadSize,uReadPos ;
|
||||||
int i;
|
int i;
|
||||||
if (uBackRead+BUFREADCOMMENT>uMaxBack)
|
if (uBackRead+BUFREADCOMMENT>uMaxBack)
|
||||||
uBackRead = uMaxBack;
|
uBackRead = uMaxBack;
|
||||||
else
|
else
|
||||||
uBackRead+=BUFREADCOMMENT;
|
uBackRead+=BUFREADCOMMENT;
|
||||||
uReadPos = uSizeFile-uBackRead ;
|
uReadPos = uSizeFile-uBackRead ;
|
||||||
|
|
||||||
uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
|
uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
|
||||||
(BUFREADCOMMENT+4) : (uSizeFile-uReadPos);
|
(BUFREADCOMMENT+4) : (uSizeFile-uReadPos);
|
||||||
if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
|
if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
|
if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
for (i=(int)uReadSize-3; (i--)>0;)
|
for (i=(int)uReadSize-3; (i--)>0;)
|
||||||
if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
|
if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
|
||||||
((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
|
((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
|
||||||
{
|
{
|
||||||
uPosFound = uReadPos+i;
|
uPosFound = uReadPos+i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uPosFound!=0)
|
if (uPosFound!=0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
TRYFREE(buf);
|
TRYFREE(buf);
|
||||||
return uPosFound;
|
return uPosFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* !NO_ADDFILEINEXISTINGZIP*/
|
#endif /* !NO_ADDFILEINEXISTINGZIP*/
|
||||||
|
|
||||||
/************************************************************/
|
/************************************************************/
|
||||||
|
@ -523,8 +521,6 @@ extern zipFile ZEXPORT zipOpen2 (pathname, append, globalcomment, pzlib_filefunc
|
||||||
|
|
||||||
if (ziinit.filestream == NULL)
|
if (ziinit.filestream == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (append == APPEND_STATUS_CREATEAFTER)
|
|
||||||
ZSEEK(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END);
|
|
||||||
ziinit.begin_pos = ZTELL(ziinit.z_filefunc,ziinit.filestream);
|
ziinit.begin_pos = ZTELL(ziinit.z_filefunc,ziinit.filestream);
|
||||||
ziinit.in_opened_file_inzip = 0;
|
ziinit.in_opened_file_inzip = 0;
|
||||||
ziinit.ci.stream_initialised = 0;
|
ziinit.ci.stream_initialised = 0;
|
||||||
|
@ -562,10 +558,9 @@ extern zipFile ZEXPORT zipOpen2 (pathname, append, globalcomment, pzlib_filefunc
|
||||||
uLong size_comment;
|
uLong size_comment;
|
||||||
|
|
||||||
central_pos = ziplocal_SearchCentralDir(&ziinit.z_filefunc,ziinit.filestream);
|
central_pos = ziplocal_SearchCentralDir(&ziinit.z_filefunc,ziinit.filestream);
|
||||||
/* disable to allow appending to empty ZIP archive
|
|
||||||
if (central_pos==0)
|
if (central_pos==0)
|
||||||
err=ZIP_ERRNO;
|
err=ZIP_ERRNO;
|
||||||
*/
|
|
||||||
if (ZSEEK(ziinit.z_filefunc, ziinit.filestream,
|
if (ZSEEK(ziinit.z_filefunc, ziinit.filestream,
|
||||||
central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
|
central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
|
||||||
err=ZIP_ERRNO;
|
err=ZIP_ERRNO;
|
||||||
|
@ -620,7 +615,7 @@ extern zipFile ZEXPORT zipOpen2 (pathname, append, globalcomment, pzlib_filefunc
|
||||||
|
|
||||||
if (size_comment>0)
|
if (size_comment>0)
|
||||||
{
|
{
|
||||||
ziinit.globalcomment = (char*)ALLOC(size_comment+1);
|
ziinit.globalcomment = ALLOC(size_comment+1);
|
||||||
if (ziinit.globalcomment)
|
if (ziinit.globalcomment)
|
||||||
{
|
{
|
||||||
size_comment = ZREAD(ziinit.z_filefunc, ziinit.filestream,ziinit.globalcomment,size_comment);
|
size_comment = ZREAD(ziinit.z_filefunc, ziinit.filestream,ziinit.globalcomment,size_comment);
|
||||||
|
@ -692,12 +687,12 @@ extern zipFile ZEXPORT zipOpen (pathname, append)
|
||||||
return zipOpen2(pathname,append,NULL,NULL);
|
return zipOpen2(pathname,append,NULL,NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int ZEXPORT zipOpenNewFileInZip4 (file, filename, zipfi,
|
extern int ZEXPORT zipOpenNewFileInZip3 (file, filename, zipfi,
|
||||||
extrafield_local, size_extrafield_local,
|
extrafield_local, size_extrafield_local,
|
||||||
extrafield_global, size_extrafield_global,
|
extrafield_global, size_extrafield_global,
|
||||||
comment, method, level, raw,
|
comment, method, level, raw,
|
||||||
windowBits, memLevel, strategy,
|
windowBits, memLevel, strategy,
|
||||||
password, crcForCrypting, versionMadeBy, flagBase)
|
password, crcForCrypting)
|
||||||
zipFile file;
|
zipFile file;
|
||||||
const char* filename;
|
const char* filename;
|
||||||
const zip_fileinfo* zipfi;
|
const zip_fileinfo* zipfi;
|
||||||
|
@ -714,8 +709,6 @@ extern int ZEXPORT zipOpenNewFileInZip4 (file, filename, zipfi,
|
||||||
int strategy;
|
int strategy;
|
||||||
const char* password;
|
const char* password;
|
||||||
uLong crcForCrypting;
|
uLong crcForCrypting;
|
||||||
uLong versionMadeBy;
|
|
||||||
uLong flagBase;
|
|
||||||
{
|
{
|
||||||
zip_internal* zi;
|
zip_internal* zi;
|
||||||
uInt size_filename;
|
uInt size_filename;
|
||||||
|
@ -762,7 +755,7 @@ extern int ZEXPORT zipOpenNewFileInZip4 (file, filename, zipfi,
|
||||||
else zi->ci.dosDate = ziplocal_TmzDateToDosDate(&zipfi->tmz_date,zipfi->dosDate);
|
else zi->ci.dosDate = ziplocal_TmzDateToDosDate(&zipfi->tmz_date,zipfi->dosDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
zi->ci.flag = flagBase;
|
zi->ci.flag = 0;
|
||||||
if ((level==8) || (level==9))
|
if ((level==8) || (level==9))
|
||||||
zi->ci.flag |= 2;
|
zi->ci.flag |= 2;
|
||||||
if ((level==2))
|
if ((level==2))
|
||||||
|
@ -785,7 +778,7 @@ extern int ZEXPORT zipOpenNewFileInZip4 (file, filename, zipfi,
|
||||||
|
|
||||||
ziplocal_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4);
|
ziplocal_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4);
|
||||||
/* version info */
|
/* version info */
|
||||||
ziplocal_putValue_inmemory(zi->ci.central_header+4,(uLong)versionMadeBy,2);
|
ziplocal_putValue_inmemory(zi->ci.central_header+4,(uLong)VERSIONMADEBY,2);
|
||||||
ziplocal_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2);
|
ziplocal_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2);
|
||||||
ziplocal_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2);
|
ziplocal_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2);
|
||||||
ziplocal_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2);
|
ziplocal_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2);
|
||||||
|
@ -864,7 +857,6 @@ extern int ZEXPORT zipOpenNewFileInZip4 (file, filename, zipfi,
|
||||||
zi->ci.stream.next_out = zi->ci.buffered_data;
|
zi->ci.stream.next_out = zi->ci.buffered_data;
|
||||||
zi->ci.stream.total_in = 0;
|
zi->ci.stream.total_in = 0;
|
||||||
zi->ci.stream.total_out = 0;
|
zi->ci.stream.total_out = 0;
|
||||||
zi->ci.stream.data_type = Z_BINARY;
|
|
||||||
|
|
||||||
if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
|
if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
|
||||||
{
|
{
|
||||||
|
@ -920,46 +912,14 @@ extern int ZEXPORT zipOpenNewFileInZip2(file, filename, zipfi,
|
||||||
int level;
|
int level;
|
||||||
int raw;
|
int raw;
|
||||||
{
|
{
|
||||||
return zipOpenNewFileInZip4 (file, filename, zipfi,
|
return zipOpenNewFileInZip3 (file, filename, zipfi,
|
||||||
extrafield_local, size_extrafield_local,
|
extrafield_local, size_extrafield_local,
|
||||||
extrafield_global, size_extrafield_global,
|
extrafield_global, size_extrafield_global,
|
||||||
comment, method, level, raw,
|
comment, method, level, raw,
|
||||||
-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
|
-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
|
||||||
NULL, 0, VERSIONMADEBY, 0);
|
NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int ZEXPORT zipOpenNewFileInZip3 (file, filename, zipfi,
|
|
||||||
extrafield_local, size_extrafield_local,
|
|
||||||
extrafield_global, size_extrafield_global,
|
|
||||||
comment, method, level, raw,
|
|
||||||
windowBits, memLevel, strategy,
|
|
||||||
password, crcForCrypting)
|
|
||||||
zipFile file;
|
|
||||||
const char* filename;
|
|
||||||
const zip_fileinfo* zipfi;
|
|
||||||
const void* extrafield_local;
|
|
||||||
uInt size_extrafield_local;
|
|
||||||
const void* extrafield_global;
|
|
||||||
uInt size_extrafield_global;
|
|
||||||
const char* comment;
|
|
||||||
int method;
|
|
||||||
int level;
|
|
||||||
int raw;
|
|
||||||
int windowBits;
|
|
||||||
int memLevel;
|
|
||||||
int strategy;
|
|
||||||
const char* password;
|
|
||||||
uLong crcForCrypting;
|
|
||||||
{
|
|
||||||
return zipOpenNewFileInZip4 (file, filename, zipfi,
|
|
||||||
extrafield_local, size_extrafield_local,
|
|
||||||
extrafield_global, size_extrafield_global,
|
|
||||||
comment, method, level, raw,
|
|
||||||
windowBits, memLevel, strategy,
|
|
||||||
password, crcForCrypting, VERSIONMADEBY, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
extern int ZEXPORT zipOpenNewFileInZip (file, filename, zipfi,
|
extern int ZEXPORT zipOpenNewFileInZip (file, filename, zipfi,
|
||||||
extrafield_local, size_extrafield_local,
|
extrafield_local, size_extrafield_local,
|
||||||
extrafield_global, size_extrafield_global,
|
extrafield_global, size_extrafield_global,
|
||||||
|
@ -975,12 +935,10 @@ extern int ZEXPORT zipOpenNewFileInZip (file, filename, zipfi,
|
||||||
int method;
|
int method;
|
||||||
int level;
|
int level;
|
||||||
{
|
{
|
||||||
return zipOpenNewFileInZip4 (file, filename, zipfi,
|
return zipOpenNewFileInZip2 (file, filename, zipfi,
|
||||||
extrafield_local, size_extrafield_local,
|
extrafield_local, size_extrafield_local,
|
||||||
extrafield_global, size_extrafield_global,
|
extrafield_global, size_extrafield_global,
|
||||||
comment, method, level, 0,
|
comment, method, level, 0);
|
||||||
-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
|
|
||||||
NULL, 0, VERSIONMADEBY, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
local int zipFlushWriteBuffer(zi)
|
local int zipFlushWriteBuffer(zi)
|
||||||
|
@ -1020,9 +978,9 @@ extern int ZEXPORT zipWriteInFileInZip (file, buf, len)
|
||||||
if (zi->in_opened_file_inzip == 0)
|
if (zi->in_opened_file_inzip == 0)
|
||||||
return ZIP_PARAMERROR;
|
return ZIP_PARAMERROR;
|
||||||
|
|
||||||
zi->ci.stream.next_in = (Bytef*)buf;
|
zi->ci.stream.next_in = (void*)buf;
|
||||||
zi->ci.stream.avail_in = len;
|
zi->ci.stream.avail_in = len;
|
||||||
zi->ci.crc32 = crc32(zi->ci.crc32,buf,(uInt)len);
|
zi->ci.crc32 = crc32(zi->ci.crc32,buf,len);
|
||||||
|
|
||||||
while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0))
|
while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0))
|
||||||
{
|
{
|
||||||
|
@ -1112,9 +1070,7 @@ extern int ZEXPORT zipCloseFileInZipRaw (file, uncompressed_size, crc32)
|
||||||
|
|
||||||
if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
|
if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
|
||||||
{
|
{
|
||||||
int tmp_err=deflateEnd(&zi->ci.stream);
|
err=deflateEnd(&zi->ci.stream);
|
||||||
if (err == ZIP_OK)
|
|
||||||
err = tmp_err;
|
|
||||||
zi->ci.stream_initialised = 0;
|
zi->ci.stream_initialised = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1217,7 +1173,7 @@ extern int ZEXPORT zipClose (file, global_comment)
|
||||||
ldi = ldi->next_datablock;
|
ldi = ldi->next_datablock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free_linkedlist(&(zi->central_dir));
|
free_datablock(zi->central_dir.first_block);
|
||||||
|
|
||||||
if (err==ZIP_OK) /* Magic End */
|
if (err==ZIP_OK) /* Magic End */
|
||||||
err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4);
|
err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* zip.h -- IO for compress .zip files using zlib
|
/* zip.h -- IO for compress .zip files using zlib
|
||||||
Version 1.01h, December 28th, 2009
|
Version 1.01e, February 12th, 2005
|
||||||
|
|
||||||
Copyright (C) 1998-2009 Gilles Vollant
|
Copyright (C) 1998-2005 Gilles Vollant
|
||||||
|
|
||||||
This unzip package allow creates .ZIP file, compatible with PKZip 2.04g
|
This unzip package allow creates .ZIP file, compatible with PKZip 2.04g
|
||||||
WinZip, InfoZip tools and compatible.
|
WinZip, InfoZip tools and compatible.
|
||||||
|
@ -191,7 +191,8 @@ extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file,
|
||||||
int memLevel,
|
int memLevel,
|
||||||
int strategy,
|
int strategy,
|
||||||
const char* password,
|
const char* password,
|
||||||
uLong crcForCrypting));
|
uLong crcForCtypting));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Same than zipOpenNewFileInZip2, except
|
Same than zipOpenNewFileInZip2, except
|
||||||
windowBits,memLevel,,strategy : see parameter strategy in deflateInit2
|
windowBits,memLevel,,strategy : see parameter strategy in deflateInit2
|
||||||
|
@ -199,29 +200,6 @@ extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file,
|
||||||
crcForCtypting : crc of file to compress (needed for crypting)
|
crcForCtypting : crc of file to compress (needed for crypting)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file,
|
|
||||||
const char* filename,
|
|
||||||
const zip_fileinfo* zipfi,
|
|
||||||
const void* extrafield_local,
|
|
||||||
uInt size_extrafield_local,
|
|
||||||
const void* extrafield_global,
|
|
||||||
uInt size_extrafield_global,
|
|
||||||
const char* comment,
|
|
||||||
int method,
|
|
||||||
int level,
|
|
||||||
int raw,
|
|
||||||
int windowBits,
|
|
||||||
int memLevel,
|
|
||||||
int strategy,
|
|
||||||
const char* password,
|
|
||||||
uLong crcForCrypting,
|
|
||||||
uLong versionMadeBy,
|
|
||||||
uLong flagBase));
|
|
||||||
/*
|
|
||||||
Same than zipOpenNewFileInZip4, except
|
|
||||||
versionMadeBy : value for Version made by field
|
|
||||||
flag : value for flag field (compression level info will be added)
|
|
||||||
*/
|
|
||||||
|
|
||||||
extern int ZEXPORT zipWriteInFileInZip OF((zipFile file,
|
extern int ZEXPORT zipWriteInFileInZip OF((zipFile file,
|
||||||
const void* buf,
|
const void* buf,
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
#include "texturepack.h"
|
#include "texturepack.h"
|
||||||
|
|
||||||
#define dir_delimter '/'
|
#include "ZipHelper.h"
|
||||||
#define MAX_FILENAME 256
|
|
||||||
#define READ_SIZE 9216
|
|
||||||
|
|
||||||
|
#define MAX_FILENAME 256
|
||||||
|
|
||||||
|
bool texturepackUseDefaultIcons = true;
|
||||||
|
bool texturepackUseDefaultPlayer = true;
|
||||||
|
bool texturepackUseDefaultFont = true;
|
||||||
|
bool texturepackUseDefaultBottom = true;
|
||||||
|
|
||||||
void toLowerString(char * str){
|
void toLowerString(char * str){
|
||||||
int i;
|
int i;
|
||||||
|
@ -31,136 +35,66 @@ int getTexturePackComment(char * filename, char * cmmtBuf){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int loadTexturePack(char * filename){
|
int loadTexture(char * filename) {
|
||||||
|
char lowerFilename[MAX_FILENAME];
|
||||||
|
strcpy(lowerFilename,filename);
|
||||||
|
toLowerString(lowerFilename);
|
||||||
|
|
||||||
bool useDefaultIcons = true;
|
if(strcmp(lowerFilename, "icons.png") == 0){
|
||||||
bool useDefaultFont = true;
|
if(sfil_load_PNG_file(filename, SF2D_PLACE_RAM) == NULL){
|
||||||
bool useDefaultBottom = true;
|
return 0;
|
||||||
|
|
||||||
// Open the zip file
|
|
||||||
unzFile *zipfile = unzOpen(filename);
|
|
||||||
if ( zipfile == NULL ) return 1; // Error: ZipFile could not be opened.
|
|
||||||
|
|
||||||
// Get info about the zip file
|
|
||||||
unz_global_info global_info;
|
|
||||||
if (unzGetGlobalInfo(zipfile, &global_info ) != UNZ_OK )
|
|
||||||
{
|
|
||||||
unzClose( zipfile );
|
|
||||||
return 2; // Error: Could not read global info
|
|
||||||
}
|
|
||||||
|
|
||||||
// Buffer to hold data read from the zip file.
|
|
||||||
char read_buffer[ READ_SIZE ];
|
|
||||||
|
|
||||||
// Loop to extract all files
|
|
||||||
uLong i;
|
|
||||||
for ( i = 0; i < global_info.number_entry; ++i )
|
|
||||||
{
|
|
||||||
// Get info about current file.
|
|
||||||
unz_file_info file_info;
|
|
||||||
char filename[ MAX_FILENAME ];
|
|
||||||
if (unzGetCurrentFileInfo(zipfile,&file_info,filename,MAX_FILENAME,NULL, 0, NULL, 0 ) != UNZ_OK ){
|
|
||||||
unzClose( zipfile );
|
|
||||||
return 3; // Error: Could not read file info
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this entry is NOT a directory or file.
|
icons = sfil_load_PNG_file(filename, SF2D_PLACE_RAM);
|
||||||
const size_t filename_length = strlen( filename );
|
|
||||||
if ( filename[ filename_length-1 ] != dir_delimter ){
|
|
||||||
if ( unzOpenCurrentFile( zipfile ) != UNZ_OK )
|
|
||||||
{
|
|
||||||
unzClose( zipfile );
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open a file to write out the data.
|
|
||||||
FILE * out = fopen(filename, "wb" );
|
|
||||||
if ( out == NULL )
|
|
||||||
{
|
|
||||||
unzCloseCurrentFile( zipfile );
|
|
||||||
unzClose( zipfile );
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
int error = UNZ_OK;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
error = unzReadCurrentFile( zipfile, read_buffer, READ_SIZE );
|
|
||||||
if ( error < 0 )
|
|
||||||
{
|
|
||||||
//printf( "error %d\n", error );
|
|
||||||
unzCloseCurrentFile( zipfile );
|
|
||||||
unzClose( zipfile );
|
|
||||||
return 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write data to file.
|
|
||||||
if ( error > 0 )
|
|
||||||
{
|
|
||||||
fwrite( read_buffer, error, 1, out ); // You should check return of fwrite...
|
|
||||||
}
|
|
||||||
} while ( error > 0 );
|
|
||||||
|
|
||||||
fclose(out);
|
|
||||||
|
|
||||||
char lowerFilename[MAX_FILENAME];
|
|
||||||
strcpy(lowerFilename,filename);
|
|
||||||
toLowerString(lowerFilename);
|
|
||||||
|
|
||||||
if(strcmp(lowerFilename,"icons.png") == 0){
|
|
||||||
if(sfil_load_PNG_file(filename, SF2D_PLACE_RAM) == NULL){
|
|
||||||
unzCloseCurrentFile( zipfile );
|
|
||||||
unzClose( zipfile );
|
|
||||||
return 7;
|
|
||||||
}
|
|
||||||
icons = sfil_load_PNG_file(filename, SF2D_PLACE_RAM);
|
|
||||||
|
|
||||||
reloadColors();
|
|
||||||
|
|
||||||
useDefaultIcons = false;
|
|
||||||
|
|
||||||
} else if(strcmp(lowerFilename,"font.png") == 0){
|
|
||||||
if(sfil_load_PNG_file(filename, SF2D_PLACE_RAM) == NULL){
|
|
||||||
unzCloseCurrentFile( zipfile );
|
|
||||||
unzClose( zipfile );
|
|
||||||
return 7;
|
|
||||||
}
|
|
||||||
font = sfil_load_PNG_file(filename, SF2D_PLACE_RAM);
|
|
||||||
useDefaultFont = false;
|
|
||||||
} else if(strcmp(lowerFilename,"bottombg.png") == 0){
|
|
||||||
if(sfil_load_PNG_file(filename, SF2D_PLACE_RAM) == NULL){
|
|
||||||
unzCloseCurrentFile( zipfile );
|
|
||||||
unzClose( zipfile );
|
|
||||||
return 7;
|
|
||||||
}
|
|
||||||
bottombg = sfil_load_PNG_file(filename, SF2D_PLACE_RAM);
|
|
||||||
useDefaultBottom = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
remove(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
unzCloseCurrentFile( zipfile );
|
|
||||||
|
|
||||||
// Go the the next entry listed in the zip file.
|
|
||||||
if ( ( i+1 ) < global_info.number_entry )
|
|
||||||
{
|
|
||||||
if ( unzGoToNextFile( zipfile ) != UNZ_OK )
|
|
||||||
{
|
|
||||||
unzClose( zipfile );
|
|
||||||
return 7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(useDefaultIcons){
|
|
||||||
icons = sfil_load_PNG_buffer(icons2_png, SF2D_PLACE_RAM);
|
|
||||||
reloadColors();
|
reloadColors();
|
||||||
}
|
|
||||||
if(useDefaultFont) font = sfil_load_PNG_buffer(Font_png, SF2D_PLACE_RAM);
|
|
||||||
if(useDefaultBottom) bottombg = sfil_load_PNG_buffer(bottombg_png, SF2D_PLACE_RAM);
|
|
||||||
|
|
||||||
unzClose( zipfile );
|
texturepackUseDefaultIcons = false;
|
||||||
|
} else if(strcmp(lowerFilename, "player.png") == 0){
|
||||||
|
if(sfil_load_PNG_file(filename, SF2D_PLACE_RAM) == NULL){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
playerSprites = sfil_load_PNG_file(filename, SF2D_PLACE_RAM);
|
||||||
|
|
||||||
|
texturepackUseDefaultPlayer = false;
|
||||||
|
} else if(strcmp(lowerFilename, "font.png") == 0){
|
||||||
|
if(sfil_load_PNG_file(filename, SF2D_PLACE_RAM) == NULL){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
font = sfil_load_PNG_file(filename, SF2D_PLACE_RAM);
|
||||||
|
|
||||||
|
texturepackUseDefaultFont = false;
|
||||||
|
} else if(strcmp(lowerFilename, "bottombg.png") == 0){
|
||||||
|
if(sfil_load_PNG_file(filename, SF2D_PLACE_RAM) == NULL){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bottombg = sfil_load_PNG_file(filename, SF2D_PLACE_RAM);
|
||||||
|
|
||||||
|
texturepackUseDefaultBottom = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int loadTexturePack(char * filename) {
|
||||||
|
texturepackUseDefaultIcons = true;
|
||||||
|
texturepackUseDefaultPlayer = true;
|
||||||
|
texturepackUseDefaultFont = true;
|
||||||
|
texturepackUseDefaultBottom = true;
|
||||||
|
|
||||||
|
if(unzipAndLoad(filename, &loadTexture, NULL, ZIPHELPER_CLEANUP_FILES)!=0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(texturepackUseDefaultIcons){
|
||||||
|
icons = sfil_load_PNG_buffer(icons2_png, SF2D_PLACE_RAM);
|
||||||
|
reloadColors();
|
||||||
|
}
|
||||||
|
if(texturepackUseDefaultPlayer) playerSprites = sfil_load_PNG_buffer(player_png, SF2D_PLACE_RAM);
|
||||||
|
if(texturepackUseDefaultFont) font = sfil_load_PNG_buffer(Font_png, SF2D_PLACE_RAM);
|
||||||
|
if(texturepackUseDefaultBottom) bottombg = sfil_load_PNG_buffer(bottombg_png, SF2D_PLACE_RAM);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <sf2d.h>
|
#include <sf2d.h>
|
||||||
|
|
Loading…
Add table
Reference in a new issue