Started work on new update

Added some small new map generation features
Added "NPCs" and "Quests" (atleast a first experiment for them)
Added magic compass to make search for stairs leass annoying
Added mostly visual season and weather effects
This commit is contained in:
Andre Schweiger 2017-01-07 21:54:28 +01:00
parent f6e2d30ab6
commit 3699414dcd
19 changed files with 1324 additions and 253 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View file

@ -104,7 +104,7 @@ void initRecipes(){
workbenchRecipes.recipes[20] = defineRecipe(ITEM_WALL_WOOD,1,1,ITEM_WOOD,4); workbenchRecipes.recipes[20] = defineRecipe(ITEM_WALL_WOOD,1,1,ITEM_WOOD,4);
workbenchRecipes.recipes[21] = defineRecipe(ITEM_WALL_STONE,1,1,ITEM_STONE,4); workbenchRecipes.recipes[21] = defineRecipe(ITEM_WALL_STONE,1,1,ITEM_STONE,4);
anvilRecipes.size = 16; anvilRecipes.size = 17;
anvilRecipes.recipes = (Recipe*)malloc(sizeof(Recipe) * (anvilRecipes.size)); anvilRecipes.recipes = (Recipe*)malloc(sizeof(Recipe) * (anvilRecipes.size));
anvilRecipes.recipes[0] = defineRecipe(TOOL_SWORD,2,2,ITEM_WOOD,5,ITEM_IRONINGOT,5); anvilRecipes.recipes[0] = defineRecipe(TOOL_SWORD,2,2,ITEM_WOOD,5,ITEM_IRONINGOT,5);
anvilRecipes.recipes[1] = defineRecipe(TOOL_AXE,2,2,ITEM_WOOD,5,ITEM_IRONINGOT,5); anvilRecipes.recipes[1] = defineRecipe(TOOL_AXE,2,2,ITEM_WOOD,5,ITEM_IRONINGOT,5);
@ -122,6 +122,7 @@ void initRecipes(){
anvilRecipes.recipes[13] = defineRecipe(ITEM_ENCHANTER,1,3,ITEM_WOOD,10,ITEM_GOLDINGOT,10,ITEM_GEM,20); anvilRecipes.recipes[13] = defineRecipe(ITEM_ENCHANTER,1,3,ITEM_WOOD,10,ITEM_GOLDINGOT,10,ITEM_GEM,20);
anvilRecipes.recipes[14] = defineRecipe(ITEM_WALL_IRON,1,1,ITEM_IRONINGOT,2); anvilRecipes.recipes[14] = defineRecipe(ITEM_WALL_IRON,1,1,ITEM_IRONINGOT,2);
anvilRecipes.recipes[15] = defineRecipe(ITEM_WALL_GOLD,1,1,ITEM_GOLDINGOT,2); anvilRecipes.recipes[15] = defineRecipe(ITEM_WALL_GOLD,1,1,ITEM_GOLDINGOT,2);
anvilRecipes.recipes[16] = defineRecipe(ITEM_COIN,3,1,ITEM_IRONINGOT,1);
furnaceRecipes.size = 3; furnaceRecipes.size = 3;
furnaceRecipes.recipes = (Recipe*)malloc(sizeof(Recipe) * (furnaceRecipes.size)); furnaceRecipes.recipes = (Recipe*)malloc(sizeof(Recipe) * (furnaceRecipes.size));
@ -139,7 +140,7 @@ void initRecipes(){
loomRecipes.recipes = (Recipe*)malloc(sizeof(Recipe) * (loomRecipes.size)); loomRecipes.recipes = (Recipe*)malloc(sizeof(Recipe) * (loomRecipes.size));
loomRecipes.recipes[0] = defineRecipe(ITEM_STRING,1,1,ITEM_WOOL,1); loomRecipes.recipes[0] = defineRecipe(ITEM_STRING,1,1,ITEM_WOOL,1);
enchanterRecipes.size = 8; enchanterRecipes.size = 7;
enchanterRecipes.recipes = (Recipe*)malloc(sizeof(Recipe) * (enchanterRecipes.size)); enchanterRecipes.recipes = (Recipe*)malloc(sizeof(Recipe) * (enchanterRecipes.size));
enchanterRecipes.recipes[0] = defineRecipe(TOOL_SWORD,4,2,ITEM_WOOD,5,ITEM_GEM,50); enchanterRecipes.recipes[0] = defineRecipe(TOOL_SWORD,4,2,ITEM_WOOD,5,ITEM_GEM,50);
enchanterRecipes.recipes[1] = defineRecipe(TOOL_AXE,4,2,ITEM_WOOD,5,ITEM_GEM,50); enchanterRecipes.recipes[1] = defineRecipe(TOOL_AXE,4,2,ITEM_WOOD,5,ITEM_GEM,50);
@ -148,7 +149,6 @@ void initRecipes(){
enchanterRecipes.recipes[4] = defineRecipe(TOOL_SHOVEL,4,2,ITEM_WOOD,5,ITEM_GEM,50); enchanterRecipes.recipes[4] = defineRecipe(TOOL_SHOVEL,4,2,ITEM_WOOD,5,ITEM_GEM,50);
enchanterRecipes.recipes[5] = defineRecipe(ITEM_ARROW_GEM,1,3,ITEM_WOOD,1,ITEM_GEM,3,ITEM_STRING,1); enchanterRecipes.recipes[5] = defineRecipe(ITEM_ARROW_GEM,1,3,ITEM_WOOD,1,ITEM_GEM,3,ITEM_STRING,1);
enchanterRecipes.recipes[6] = defineRecipe(ITEM_WALL_GEM,1,1,ITEM_GEM,10); enchanterRecipes.recipes[6] = defineRecipe(ITEM_WALL_GEM,1,1,ITEM_GEM,10);
enchanterRecipes.recipes[7] = defineRecipe(ITEM_WIZARD_SUMMON,1,4,ITEM_CLOUD,100,ITEM_IRONINGOT,10,ITEM_BONE,10,ITEM_LEATHER,10);
} }

View file

@ -29,6 +29,8 @@ RecipeManager anvilRecipes;
RecipeManager loomRecipes; RecipeManager loomRecipes;
RecipeManager enchanterRecipes; RecipeManager enchanterRecipes;
Recipe defineRecipe(int item, int amountOrLevel, int numArgs, ...);
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);

View file

@ -346,6 +346,22 @@ Entity newGlowwormEntity(int x, int y, int level){
return e; return e;
} }
Entity newNPCEntity(int type, int x, int y, int level){
Entity e;
e.type = ENTITY_NPC;
e.level = level;
e.x = x;
e.y = y;
e.hurtTime = 0;
e.xKnockback = 0;
e.yKnockback = 0;
e.npc.type = type;
e.xr = 4;
e.yr = 3;
e.canPass = false;
return e;
}
void addEntityToList(Entity e, EntityManager* em){ void addEntityToList(Entity e, EntityManager* em){
e.slotNum = em->lastSlot[e.level]; e.slotNum = em->lastSlot[e.level];
em->entities[e.level][em->lastSlot[e.level]] = e; em->entities[e.level][em->lastSlot[e.level]] = e;

View file

@ -23,6 +23,8 @@
#define ENTITY_DRAGONPROJECTILE 16 #define ENTITY_DRAGONPROJECTILE 16
#define ENTITY_MAGIC_PILLAR 17 #define ENTITY_MAGIC_PILLAR 17
#define ENTITY_NPC 18
typedef struct Entity Entity; typedef struct Entity Entity;
typedef struct { typedef struct {
@ -160,6 +162,10 @@ typedef struct {
s8 waitTime; s8 waitTime;
} Glowworm; } Glowworm;
typedef struct {
u8 type;
} NPC;
typedef struct { typedef struct {
float xa; float xa;
float ya; float ya;
@ -200,6 +206,7 @@ struct Entity {
Glowworm glowworm; Glowworm glowworm;
Dragon dragon; Dragon dragon;
DragonFire dragonFire; DragonFire dragonFire;
NPC npc;
TextParticleEntity textParticle; TextParticleEntity textParticle;
SmashParticleEntity smashParticle; SmashParticleEntity smashParticle;
}; };
@ -234,6 +241,7 @@ Entity newTextParticleEntity(char * str, u32 color, int xa, int ya, int level);
Entity newSmashParticleEntity(int xa, int ya, int level); Entity newSmashParticleEntity(int xa, int ya, int level);
Entity newArrowEntity(Entity* parent, int itemID, s8 xa, s8 ya, int level); Entity newArrowEntity(Entity* parent, int itemID, s8 xa, s8 ya, int level);
Entity newGlowwormEntity(int x, int y, int level); Entity newGlowwormEntity(int x, int y, int level);
Entity newNPCEntity(int type, int x, int y, int level);
void addEntityToList(Entity e, EntityManager* em); void addEntityToList(Entity e, EntityManager* em);
void removeEntityFromList(Entity * e,int level,EntityManager* em); void removeEntityFromList(Entity * e,int level,EntityManager* em);

View file

@ -1,6 +1,6 @@
#include "Globals.h" #include "Globals.h"
char versionText[34] = "Version 1.2.2"; char versionText[34] = "Version 1.3.0";
char fpsstr[34]; char fpsstr[34];
u8 currentMenu = 0; u8 currentMenu = 0;
@ -217,6 +217,7 @@ void tickTouchQuickSelect() {
} }
void hurtEntity(Entity* e, int damage, int dir, u32 hurtColor){ void hurtEntity(Entity* e, int damage, int dir, u32 hurtColor){
if (TESTGODMODE && e->type==ENTITY_PLAYER) return;
if (e->hurtTime > 0) return; if (e->hurtTime > 0) return;
int xd = player.x - e->x; int xd = player.x - e->x;
int yd = player.y - e->y; int yd = player.y - e->y;
@ -252,7 +253,7 @@ void hurtEntity(Entity* e, int damage, int dir, u32 hurtColor){
} }
player.p.score += 50 * (e->hostile.lvl + 1); player.p.score += 50 * (e->hostile.lvl + 1);
removeEntityFromList(e,e->level,&eManager); removeEntityFromList(e,e->level,&eManager);
trySpawn(3, currentLevel); if(currentLevel != 5) trySpawn(3, currentLevel);
return; return;
} }
break; break;
@ -262,7 +263,7 @@ void hurtEntity(Entity* e, int damage, int dir, u32 hurtColor){
addItemsToWorld(newItem(ITEM_SLIME,1),e->x+8, e->y+8, (rand()%2) + 1); addItemsToWorld(newItem(ITEM_SLIME,1),e->x+8, e->y+8, (rand()%2) + 1);
player.p.score += 25 * (e->slime.lvl + 1); player.p.score += 25 * (e->slime.lvl + 1);
removeEntityFromList(e,e->level,&eManager); removeEntityFromList(e,e->level,&eManager);
trySpawn(3, currentLevel); if(currentLevel != 5) trySpawn(3, currentLevel);
return; return;
} }
break; break;
@ -270,7 +271,7 @@ void hurtEntity(Entity* e, int damage, int dir, u32 hurtColor){
e->wizard.health -= damage; e->wizard.health -= damage;
airWizardHealthDisplay = e->wizard.health; airWizardHealthDisplay = e->wizard.health;
if(e->wizard.health < 1){ if(e->wizard.health < 1){
addItemsToWorld(newItem(ITEM_DUNGEON_KEY,1),e->x+8, e->y+8, (rand()%2) + 1); addItemsToWorld(newItem(ITEM_MAGIC_DUST,1),e->x+8, e->y+8, (rand()%2) + 2);
removeEntityFromList(e,e->level,&eManager); removeEntityFromList(e,e->level,&eManager);
playSound(snd_bossdeath); playSound(snd_bossdeath);
player.p.score += 1000; player.p.score += 1000;
@ -295,7 +296,7 @@ void hurtEntity(Entity* e, int damage, int dir, u32 hurtColor){
} }
player.p.score += 10; player.p.score += 10;
removeEntityFromList(e,e->level,&eManager); removeEntityFromList(e,e->level,&eManager);
trySpawn(3, currentLevel); if(currentLevel != 5) trySpawn(3, currentLevel);
return; return;
} }
break; break;
@ -546,16 +547,16 @@ void EntityVsEntity(Entity* e1, Entity* e2){
damage = 1 + (rand()%3); damage = 1 + (rand()%3);
break; break;
case ITEM_ARROW_STONE: case ITEM_ARROW_STONE:
damage = 2 + (rand()%5); damage = 2 + (rand()%4);
break; break;
case ITEM_ARROW_IRON: case ITEM_ARROW_IRON:
damage = 8 + (rand()%9); damage = 8 + (rand()%9);
break; break;
case ITEM_ARROW_GOLD: case ITEM_ARROW_GOLD:
damage = 16 + (rand()%17); damage = 16 + (rand()%9);
break; break;
case ITEM_ARROW_GEM: case ITEM_ARROW_GEM:
damage = 24 + (rand()%17); damage = 24 + (rand()%9);
break; break;
} }
@ -589,6 +590,7 @@ bool EntityBlocksEntity(Entity* e1, Entity* e2){
case ENTITY_PLAYER: case ENTITY_PLAYER:
case ENTITY_PASSIVE: case ENTITY_PASSIVE:
case ENTITY_MAGIC_PILLAR: case ENTITY_MAGIC_PILLAR:
case ENTITY_NPC:
return true; return true;
break; break;
} }
@ -599,9 +601,12 @@ bool EntityBlocksEntity(Entity* e1, Entity* e2){
bool tileIsSolid(int tile, Entity * e){ bool tileIsSolid(int tile, Entity * e){
switch(tile){ switch(tile){
case TILE_TREE:
case TILE_ROCK: case TILE_ROCK:
case TILE_HARDROCK: case TILE_HARDROCK:
case TILE_MAGIC_BARRIER:
case TILE_DUNGEON_WALL:
return true;
case TILE_TREE:
case TILE_CACTUS: case TILE_CACTUS:
case TILE_IRONORE: case TILE_IRONORE:
case TILE_GOLDORE: case TILE_GOLDORE:
@ -612,9 +617,10 @@ bool tileIsSolid(int tile, Entity * e){
case TILE_IRON_WALL: case TILE_IRON_WALL:
case TILE_GOLD_WALL: case TILE_GOLD_WALL:
case TILE_GEM_WALL: case TILE_GEM_WALL:
case TILE_DUNGEON_WALL: case TILE_BOOKSHELVES:
case TILE_MAGIC_BARRIER: case TILE_MUSHROOM_BROWN:
return true; case TILE_MUSHROOM_RED:
if(e->type != ENTITY_DRAGON) return true;
case TILE_LAVA: case TILE_LAVA:
case 255: case 255:
if(e->type != ENTITY_ARROW) return true; if(e->type != ENTITY_ARROW) return true;
@ -655,6 +661,12 @@ u32 getTileColor(int tile){
case TILE_DUNGEON_WALL: return SWAP_UINT32(dungeonColor[0]); case TILE_DUNGEON_WALL: return SWAP_UINT32(dungeonColor[0]);
case TILE_DUNGEON_FLOOR: return SWAP_UINT32(dungeonColor[1]); case TILE_DUNGEON_FLOOR: return SWAP_UINT32(dungeonColor[1]);
case TILE_MAGIC_BARRIER: return SWAP_UINT32(dungeonColor[0]); case TILE_MAGIC_BARRIER: return SWAP_UINT32(dungeonColor[0]);
case TILE_BOOKSHELVES: return SWAP_UINT32(woodColor);
case TILE_WOOD_FLOOR: return SWAP_UINT32(woodColor);
case TILE_MYCELIUM: return SWAP_UINT32(myceliumColor);
case TILE_MUSHROOM_BROWN: return SWAP_UINT32(mushroomColor);
case TILE_MUSHROOM_RED: return SWAP_UINT32(mushroomColor);
case TILE_ICE: return SWAP_UINT32(iceColor);
default: return 0x111111FF; default: return 0x111111FF;
} }
@ -806,6 +818,11 @@ s8 itemTileInteract(int tile, Item* item, int x, int y, int px, int py, int dir)
setTile(TILE_GEM_WALL,x,y); --item->countLevel; setTile(TILE_GEM_WALL,x,y); --item->countLevel;
return 1; return 1;
} }
else if(item->id == ITEM_BOOKSHELVES){
setTile(TILE_BOOKSHELVES,x,y); --item->countLevel;
data[currentLevel][x+y*128] = rand()%3;
return 1;
}
else if(item->id == TOOL_SHOVEL && playerUseEnergy(4-item->countLevel)){ else if(item->id == TOOL_SHOVEL && playerUseEnergy(4-item->countLevel)){
if(rand()%5==0)addEntityToList(newItemEntity(newItem(ITEM_SEEDS,1),(x<<4)+8, (y<<4)+8,currentLevel),&eManager); if(rand()%5==0)addEntityToList(newItemEntity(newItem(ITEM_SEEDS,1),(x<<4)+8, (y<<4)+8,currentLevel),&eManager);
setTile(TILE_DIRT,x,y); setTile(TILE_DIRT,x,y);
@ -846,6 +863,15 @@ s8 itemTileInteract(int tile, Item* item, int x, int y, int px, int py, int dir)
else if(item->id == ITEM_WALL_GEM){ else if(item->id == ITEM_WALL_GEM){
setTile(TILE_GEM_WALL,x,y); --item->countLevel; setTile(TILE_GEM_WALL,x,y); --item->countLevel;
return 1; return 1;
}
else if(item->id == ITEM_BOOKSHELVES){
setTile(TILE_BOOKSHELVES,x,y); --item->countLevel;
data[currentLevel][x+y*128] = rand()%3;
return 1;
}
else if(item->id == ITEM_WOOD) {
setTile(TILE_WOOD_FLOOR,x,y); --item->countLevel;
return 1;
} }
else if(item->id == ITEM_SAND){ else if(item->id == ITEM_SAND){
setTile(TILE_SAND,x,y); --item->countLevel; setTile(TILE_SAND,x,y); --item->countLevel;
@ -942,6 +968,16 @@ s8 itemTileInteract(int tile, Item* item, int x, int y, int px, int py, int dir)
playerHurtTile(tile, x, y, (rand()%10) + (item->countLevel) * 5 + 10, player.p.dir); playerHurtTile(tile, x, y, (rand()%10) + (item->countLevel) * 5 + 10, player.p.dir);
return 1; return 1;
} break; } break;
case TILE_BOOKSHELVES:
if(item->id == TOOL_AXE && playerUseEnergy(4-item->countLevel)){
playerHurtTile(tile, x, y, (rand()%10) + (item->countLevel) * 5 + 10, player.p.dir);
return 1;
} break;
case TILE_WOOD_FLOOR:
if(item->id == TOOL_AXE && playerUseEnergy(4-item->countLevel)){
addEntityToList(newItemEntity(newItem(ITEM_WOOD,1), (x<<4)+8, (y<<4)+8, currentLevel), &eManager);
setTile(TILE_DIRT,x,y);
} break;
} }
return 0; return 0;
} }
@ -952,7 +988,7 @@ void tickTile(int x, int y){
switch(tile){ switch(tile){
case TILE_SAPLING_TREE: case TILE_SAPLING_TREE:
setData(++data,x,y); if(data>100){setData(0,x,y); setTile(TILE_TREE,x,y);} if(season!=3) setData(++data,x,y); if(data>100){setData(0,x,y); setTile(TILE_TREE,x,y);}
break; break;
case TILE_TREE: case TILE_TREE:
if(eManager.lastSlot[currentLevel]<800 && (daytime>18000 || daytime<5000) && rand()%800==0) { if(eManager.lastSlot[currentLevel]<800 && (daytime>18000 || daytime<5000) && rand()%800==0) {
@ -966,16 +1002,22 @@ void tickTile(int x, int y){
} }
break; break;
case TILE_SAPLING_CACTUS: case TILE_SAPLING_CACTUS:
setData(++data,x,y); if(data>100){setData(0,x,y); setTile(TILE_CACTUS,x,y);} if(season!=3) setData(++data,x,y); if(data>100){setData(0,x,y); setTile(TILE_CACTUS,x,y);}
break; break;
case TILE_WHEAT: case TILE_WHEAT:
if(data<100)setData(++data,x,y); if(data<100 && season!=3) setData(++data,x,y);
break; break;
case TILE_WATER: case TILE_WATER:
if(getTile(x+1,y)==TILE_HOLE) setTile(TILE_WATER,x+1,y); if(getTile(x+1,y)==TILE_HOLE) setTile(TILE_WATER,x+1,y);
if(getTile(x-1,y)==TILE_HOLE) setTile(TILE_WATER,x-1,y); if(getTile(x-1,y)==TILE_HOLE) setTile(TILE_WATER,x-1,y);
if(getTile(x,y+1)==TILE_HOLE) setTile(TILE_WATER,x,y+1); if(getTile(x,y+1)==TILE_HOLE) setTile(TILE_WATER,x,y+1);
if(getTile(x,y-1)==TILE_HOLE) setTile(TILE_WATER,x,y-1); if(getTile(x,y-1)==TILE_HOLE) setTile(TILE_WATER,x,y-1);
if(currentLevel==1 && season==3 && rand()%12==0) {
if(getTile(x+1,y)!=TILE_WATER) setTile(TILE_ICE,x,y);
if(getTile(x-1,y)!=TILE_WATER) setTile(TILE_ICE,x,y);
if(getTile(x,y+1)!=TILE_WATER) setTile(TILE_ICE,x,y);
if(getTile(x,y-1)!=TILE_WATER) setTile(TILE_ICE,x,y);
}
break; break;
case TILE_LAVA: case TILE_LAVA:
if(getTile(x+1,y)==TILE_HOLE) setTile(TILE_LAVA,x+1,y); if(getTile(x+1,y)==TILE_HOLE) setTile(TILE_LAVA,x+1,y);
@ -1016,7 +1058,13 @@ void tickTile(int x, int y){
} }
} }
if(data==0) setTile(TILE_DUNGEON_FLOOR,x,y); if(data==0) setTile(TILE_DUNGEON_FLOOR,x,y);
setData(rand()%2,x,y);
break; break;
case TILE_ICE:
if(season!=3) {
setTile(TILE_WATER,x,y);
}
break;
} }
} }
@ -1109,7 +1157,7 @@ void tickEntity(Entity* e){
if(e->type == ENTITY_SKELETON) { if(e->type == ENTITY_SKELETON) {
--(e->hostile.randAttackTime); --(e->hostile.randAttackTime);
if(e->hostile.randAttackTime <= 0) { if(e->hostile.randAttackTime <= 0) {
e->hostile.randAttackTime = 70 - (e->hostile.lvl * 10); e->hostile.randAttackTime = 80 - (e->hostile.lvl * 5);
int aitemID = ITEM_ARROW_WOOD; int aitemID = ITEM_ARROW_WOOD;
if(e->hostile.lvl >= 2) aitemID = ITEM_ARROW_STONE; if(e->hostile.lvl >= 2) aitemID = ITEM_ARROW_STONE;
@ -1617,6 +1665,8 @@ void initPlayer(){
} }
void playerHurtTile(int tile, int xt, int yt, int damage, int dir){ void playerHurtTile(int tile, int xt, int yt, int damage, int dir){
if(TESTGODMODE) damage = 99;
char hurtText[11]; char hurtText[11];
switch(tile){ switch(tile){
case TILE_TREE: case TILE_TREE:
@ -1798,11 +1848,21 @@ void playerHurtTile(int tile, int xt, int yt, int damage, int dir){
addItemsToWorld(newItem(ITEM_WALL_GEM,1),(xt<<4)+8,(yt<<4)+8,1); addItemsToWorld(newItem(ITEM_WALL_GEM,1),(xt<<4)+8,(yt<<4)+8,1);
} }
break; break;
case TILE_BOOKSHELVES:
sprintf(hurtText, "%d", damage);
addEntityToList(newTextParticleEntity(hurtText,0xFF0000FF,xt<<4,yt<<4,currentLevel), &eManager);
addEntityToList(newSmashParticleEntity(xt<<4,yt<<4,currentLevel), &eManager);
if(currentLevel!=5) setTile(TILE_DIRT,xt,yt);
else setTile(TILE_DUNGEON_FLOOR,xt,yt);
addItemsToWorld(newItem(ITEM_BOOKSHELVES,1),(xt<<4)+8,(yt<<4)+8,1);
break;
} }
} }
bool playerUseEnergy(int amount){ bool playerUseEnergy(int amount){
if(TESTGODMODE) return true;
if(amount > player.p.stamina) return false; if(amount > player.p.stamina) return false;
player.p.stamina -= amount; player.p.stamina -= amount;
return true; return true;
@ -1974,24 +2034,28 @@ bool useEntity(Entity* e) {
switch(e->entityFurniture.itemID){ switch(e->entityFurniture.itemID){
case ITEM_WORKBENCH: case ITEM_WORKBENCH:
currentRecipes = &workbenchRecipes; currentRecipes = &workbenchRecipes;
currentCraftTitle = "Crafting";
currentMenu = MENU_CRAFTING; currentMenu = MENU_CRAFTING;
checkCanCraftRecipes(currentRecipes, player.p.inv); checkCanCraftRecipes(currentRecipes, player.p.inv);
sortRecipes(currentRecipes); sortRecipes(currentRecipes);
return true; return true;
case ITEM_FURNACE: case ITEM_FURNACE:
currentRecipes = &furnaceRecipes; currentRecipes = &furnaceRecipes;
currentCraftTitle = "Crafting";
currentMenu = MENU_CRAFTING; currentMenu = MENU_CRAFTING;
checkCanCraftRecipes(currentRecipes, player.p.inv); checkCanCraftRecipes(currentRecipes, player.p.inv);
sortRecipes(currentRecipes); sortRecipes(currentRecipes);
return true; return true;
case ITEM_OVEN: case ITEM_OVEN:
currentRecipes = &ovenRecipes; currentRecipes = &ovenRecipes;
currentCraftTitle = "Crafting";
currentMenu = MENU_CRAFTING; currentMenu = MENU_CRAFTING;
checkCanCraftRecipes(currentRecipes, player.p.inv); checkCanCraftRecipes(currentRecipes, player.p.inv);
sortRecipes(currentRecipes); sortRecipes(currentRecipes);
return true; return true;
case ITEM_ANVIL: case ITEM_ANVIL:
currentRecipes = &anvilRecipes; currentRecipes = &anvilRecipes;
currentCraftTitle = "Crafting";
currentMenu = MENU_CRAFTING; currentMenu = MENU_CRAFTING;
checkCanCraftRecipes(currentRecipes, player.p.inv); checkCanCraftRecipes(currentRecipes, player.p.inv);
sortRecipes(currentRecipes); sortRecipes(currentRecipes);
@ -2005,17 +2069,22 @@ bool useEntity(Entity* e) {
return true; return true;
case ITEM_LOOM: case ITEM_LOOM:
currentRecipes = &loomRecipes; currentRecipes = &loomRecipes;
currentCraftTitle = "Crafting";
currentMenu = MENU_CRAFTING; currentMenu = MENU_CRAFTING;
checkCanCraftRecipes(currentRecipes, player.p.inv); checkCanCraftRecipes(currentRecipes, player.p.inv);
sortRecipes(currentRecipes); sortRecipes(currentRecipes);
return true; return true;
case ITEM_ENCHANTER: case ITEM_ENCHANTER:
currentRecipes = &enchanterRecipes; currentRecipes = &enchanterRecipes;
currentCraftTitle = "Crafting";
currentMenu = MENU_CRAFTING; currentMenu = MENU_CRAFTING;
checkCanCraftRecipes(currentRecipes, player.p.inv); checkCanCraftRecipes(currentRecipes, player.p.inv);
sortRecipes(currentRecipes); sortRecipes(currentRecipes);
return true; return true;
} }
} else if(e->type == ENTITY_NPC) {
openNPCMenu(e->npc.type);
return true;
} }
return false; return false;
} }
@ -2088,7 +2157,7 @@ void tickPlayer(){
if (swimming && player.p.swimTimer % 60 == 0) { if (swimming && player.p.swimTimer % 60 == 0) {
if (player.p.stamina > 0) { if (player.p.stamina > 0) {
--player.p.stamina; if(!TESTGODMODE) --player.p.stamina;
} else { } else {
hurtEntity(&player,1,-1,0xFFAF00FF); hurtEntity(&player,1,-1,0xFFAF00FF);
} }
@ -2101,7 +2170,7 @@ void tickPlayer(){
if(k_attack.clicked){ if(k_attack.clicked){
if (player.p.stamina != 0) { if (player.p.stamina != 0) {
player.p.stamina--; if(!TESTGODMODE) player.p.stamina--;
player.p.staminaRecharge = 0; player.p.staminaRecharge = 0;
playerAttack(); playerAttack();
//addEntityToList(newSlimeEntity(1,200,600,1), &eManager); //addEntityToList(newSlimeEntity(1,200,600,1), &eManager);
@ -2148,7 +2217,7 @@ void enterDungeon() {
//create map //create map
currentLevel = 5; currentLevel = 5;
createDungeonMap(128, 128, map[5], data[5]); createAndValidateDungeonMap(128, 128, 5, map[5], data[5]);
//reset minimap clear state //reset minimap clear state
int xd,yd; int xd,yd;
@ -2160,12 +2229,12 @@ void enterDungeon() {
initMinimapLevel(5, false); initMinimapLevel(5, false);
newSeed(); newSeed();
player.x = ((128/2) << 4) + 8;
player.y = ((128/2) << 4) + 8;
//spawn new entities //spawn new entities
trySpawn(500, 5); trySpawn(500, 5);
player.x = ((128/2) << 4) + 8;
player.y = ((128/2) << 4) + 8;
updateMusic(currentLevel, daytime); updateMusic(currentLevel, daytime);
} }
@ -2203,6 +2272,9 @@ u32 getMinimapColor(int level, int x, int y) {
void initMinimapLevel(int level, bool loadUpWorld) { void initMinimapLevel(int level, bool loadUpWorld) {
int x; int x;
int y; int y;
bool calculateCompass;
calculateCompass = ((!loadUpWorld) || (compassData[level][2] = 0)) && level<5;
//Create Dungeon entrance(not located in mapgen, so it can also be created in old worlds) //Create Dungeon entrance(not located in mapgen, so it can also be created in old worlds)
if(level==4) { if(level==4) {
@ -2248,6 +2320,18 @@ void initMinimapLevel(int level, bool loadUpWorld) {
} }
} }
} }
}
if(calculateCompass) {
//choose one stair down and store for magic compass
switch (map[level][x + y * 128]) {
case TILE_STAIRS_DOWN:
case TILE_DUNGEON_ENTRANCE:
compassData[level][2] = compassData[level][2] + 1;
if((compassData[level][2]==1) || (rand()%(compassData[level][2])==0)) {
compassData[level][0] = x;
compassData[level][1] = y;
}
}
} }
/* Minimaps */ /* Minimaps */
@ -2276,6 +2360,8 @@ void reloadColors() {
dirtColor[4] = SWAP_UINT32(sf2d_get_pixel(icons, 16, 4)); dirtColor[4] = SWAP_UINT32(sf2d_get_pixel(icons, 16, 4));
grassColor = SWAP_UINT32(sf2d_get_pixel(icons, 17, 0)); grassColor = SWAP_UINT32(sf2d_get_pixel(icons, 17, 0));
myceliumColor = SWAP_UINT32(sf2d_get_pixel(icons, 17, 1));
mushroomColor = SWAP_UINT32(sf2d_get_pixel(icons, 17, 2));
sandColor = SWAP_UINT32(sf2d_get_pixel(icons, 18, 0)); sandColor = SWAP_UINT32(sf2d_get_pixel(icons, 18, 0));
@ -2298,4 +2384,7 @@ void reloadColors() {
dungeonColor[0] = SWAP_UINT32(sf2d_get_pixel(icons, 24, 0)); dungeonColor[0] = SWAP_UINT32(sf2d_get_pixel(icons, 24, 0));
dungeonColor[1] = SWAP_UINT32(sf2d_get_pixel(icons, 24, 1)); dungeonColor[1] = SWAP_UINT32(sf2d_get_pixel(icons, 24, 1));
snowColor = SWAP_UINT32(sf2d_get_pixel(icons, 25, 0));
iceColor = SWAP_UINT32(sf2d_get_pixel(icons, 25, 1));
} }

View file

@ -3,6 +3,7 @@
#include "SaveLoad.h" #include "SaveLoad.h"
#include "Input.h" #include "Input.h"
#include "MapGen.h" #include "MapGen.h"
#include "Quests.h"
#include "icons2_png.h" #include "icons2_png.h"
#include "Font_png.h" #include "Font_png.h"
@ -26,6 +27,13 @@
#define MENU_SETTINGS_REBIND 12 #define MENU_SETTINGS_REBIND 12
#define MENU_SETTINGS_TP 13 #define MENU_SETTINGS_TP 13
#define MENU_DUNGEON 14 #define MENU_DUNGEON 14
#define MENU_NPC 15
#define NPC_GIRL 0
#define NPC_PRIEST 1
#define NPC_FARMER 2
#define NPC_LIBRARIAN 3
#define NPC_DWARF 4
#define TILE_NULL 255 #define TILE_NULL 255
#define TILE_GRASS 0 #define TILE_GRASS 0
@ -60,9 +68,18 @@
#define TILE_DUNGEON_FLOOR 28 #define TILE_DUNGEON_FLOOR 28
#define TILE_DUNGEON_ENTRANCE 29 #define TILE_DUNGEON_ENTRANCE 29
#define TILE_MAGIC_BARRIER 30 #define TILE_MAGIC_BARRIER 30
#define TILE_BOOKSHELVES 31
#define TILE_WOOD_FLOOR 32
#define TILE_MYCELIUM 33
#define TILE_MUSHROOM_BROWN 34
#define TILE_MUSHROOM_RED 35
#define TILE_ICE 36
#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))
//TODO: Dont forget to change back
#define TESTGODMODE true
bool screenShot; bool screenShot;
int loadedtp; int loadedtp;
@ -86,6 +103,7 @@ sf2d_texture * minimap[6];
u8 map[6][128*128]; u8 map[6][128*128];
u8 data[6][128*128]; u8 data[6][128*128];
u8 minimapData[128*128]; u8 minimapData[128*128];
u8 compassData[6][3];
u32 dirtColor[5]; u32 dirtColor[5];
u32 grassColor; u32 grassColor;
@ -98,6 +116,10 @@ u32 ironColor;
u32 goldColor; u32 goldColor;
u32 gemColor; u32 gemColor;
u32 dungeonColor[2]; u32 dungeonColor[2];
u32 myceliumColor;
u32 mushroomColor;
u32 snowColor;
u32 iceColor;
char currentFileName[256]; char currentFileName[256];
extern u8 currentMenu; extern u8 currentMenu;
@ -110,11 +132,15 @@ s16 awX, awY;
u32 tickCount; u32 tickCount;
RecipeManager* currentRecipes; RecipeManager* currentRecipes;
Entity* curChestEntity; Entity* curChestEntity;
char* currentCraftTitle;
s16 curInvSel; s16 curInvSel;
bool quitGame; bool quitGame;
s8 currentSelection; s8 currentSelection;
u16 daytime; u16 daytime;
int day;
u8 season;
bool rain;
void tickTile(int x, int y); void tickTile(int x, int y);
bool tileIsSolid(int tile, Entity * e); bool tileIsSolid(int tile, Entity * e);

View file

@ -183,6 +183,9 @@ char* getItemName(int itemID, int countLevel){
case ITEM_WIZARD_SUMMON: sprintf(currentName,"%d Wizard Summon", countLevel); return currentName; case ITEM_WIZARD_SUMMON: sprintf(currentName,"%d Wizard Summon", countLevel); return currentName;
case ITEM_DRAGON_EGG: sprintf(currentName,"%d Dragon Egg", countLevel); return currentName; case ITEM_DRAGON_EGG: sprintf(currentName,"%d Dragon Egg", countLevel); return currentName;
case ITEM_DRAGON_SCALE: sprintf(currentName,"%d Dragon Scale", countLevel); return currentName; case ITEM_DRAGON_SCALE: sprintf(currentName,"%d Dragon Scale", countLevel); return currentName;
case ITEM_BOOKSHELVES: sprintf(currentName,"%d Bookshelves", countLevel); return currentName;
case ITEM_MAGIC_DUST: sprintf(currentName,"%d Magic Dust", countLevel); return currentName;
case ITEM_COIN: sprintf(currentName,"%d Coins", countLevel); return currentName;
case TOOL_BUCKET: case TOOL_BUCKET:
switch(countLevel){ switch(countLevel){
case 1: return "Water Bucket"; case 1: return "Water Bucket";
@ -190,6 +193,7 @@ char* getItemName(int itemID, int countLevel){
default: return "Empty Bucket"; default: return "Empty Bucket";
} }
case TOOL_BOW: return "Bow"; case TOOL_BOW: return "Bow";
case TOOL_MAGIC_COMPASS: return "Magic Compass";
default: return ""; // null default: return ""; // null
} }
} }
@ -287,8 +291,11 @@ char* getBasicItemName(int itemID, int countLevel){
case ITEM_BONE: return "Bone"; case ITEM_BONE: return "Bone";
case ITEM_DUNGEON_KEY: return "Dungeon Key"; case ITEM_DUNGEON_KEY: return "Dungeon Key";
case ITEM_WIZARD_SUMMON: return "Wizard Summon"; case ITEM_WIZARD_SUMMON: return "Wizard Summon";
case ITEM_DRAGON_EGG: return "%d Dragon Egg"; case ITEM_DRAGON_EGG: return "Dragon Egg";
case ITEM_DRAGON_SCALE: return "%d Dragon Scale"; case ITEM_DRAGON_SCALE: return "Dragon Scale";
case ITEM_BOOKSHELVES: return "Bookshelves";
case ITEM_MAGIC_DUST: return "Magic Dust";
case ITEM_COIN: return "Coin";
case TOOL_BUCKET: case TOOL_BUCKET:
switch(countLevel){ switch(countLevel){
case 1: return "Water Bucket"; case 1: return "Water Bucket";
@ -296,6 +303,7 @@ char* getBasicItemName(int itemID, int countLevel){
default: return "Empty Bucket"; default: return "Empty Bucket";
} }
case TOOL_BOW: return "Bow"; case TOOL_BOW: return "Bow";
case TOOL_MAGIC_COMPASS: return "Magic Compass";
default: return ""; // null default: return ""; // null
} }

View file

@ -68,9 +68,13 @@
#define ITEM_WIZARD_SUMMON 70 #define ITEM_WIZARD_SUMMON 70
#define ITEM_DRAGON_EGG 71 #define ITEM_DRAGON_EGG 71
#define ITEM_DRAGON_SCALE 72 #define ITEM_DRAGON_SCALE 72
#define ITEM_BOOKSHELVES 73
#define ITEM_MAGIC_DUST 74
#define ITEM_COIN 75
#define TOOL_BUCKET 101 #define TOOL_BUCKET 101
#define TOOL_BOW 102 #define TOOL_BOW 102
#define TOOL_MAGIC_COMPASS 103
typedef struct Inventory Inventory; typedef struct Inventory Inventory;

View file

@ -3,6 +3,9 @@
int w = 0; int w = 0;
int h = 0; int h = 0;
u8 randomTile[] = {0, 0, 0, 0, 0, 0, 0, 1, 1, 2};
int randomTileSize = 10;
float nextFloat(){ float nextFloat(){
return (float)rand()/RAND_MAX; return (float)rand()/RAND_MAX;
} }
@ -64,9 +67,14 @@ void newSeed(){
srand(time(NULL)); srand(time(NULL));
} }
void createAndValidateTopMap(int w, int h, u8 * map, u8 * data) { //TODO: Will need to reset entity manager if generation is retried
void createAndValidateTopMap(int w, int h, int level, u8 * map, u8 * data) {
do { do {
createTopMap(w, h, map, data); //reset Entities
(&eManager)->lastSlot[level] = 0;
(&eManager)->entities[level][0] = nullEntity;
createTopMap(w, h, level, map, data);
int count[256]={[0 ... 255] = 0}; int count[256]={[0 ... 255] = 0};
int i; int i;
@ -81,9 +89,13 @@ void createAndValidateTopMap(int w, int h, u8 * map, u8 * data) {
} while (true); } while (true);
} }
void createAndValidateUndergroundMap(int w, int h,int depthLevel, u8 * map, u8 * data) { void createAndValidateUndergroundMap(int w, int h, int depthLevel, int level, u8 * map, u8 * data) {
do { do {
createUndergroundMap(w, h, depthLevel, map, data); //reset Entities
(&eManager)->lastSlot[level] = 0;
(&eManager)->entities[level][0] = nullEntity;
createUndergroundMap(w, h, depthLevel, level, map, data);
int count[256]={[0 ... 255] = 0}; int count[256]={[0 ... 255] = 0};
int i = 0; int i = 0;
@ -92,7 +104,7 @@ void createAndValidateUndergroundMap(int w, int h,int depthLevel, u8 * map, u8 *
if (count[TILE_DIRT & 0xff] < 100) continue; if (count[TILE_DIRT & 0xff] < 100) continue;
switch(depthLevel){ switch(depthLevel){
case 1: if (count[TILE_IRONORE & 0xff] < 20) continue; break; case 1: if (count[TILE_IRONORE & 0xff] < 20) continue; break;
case 2: if (count[TILE_GOLDORE & 0xff] < 20) continue; break; case 2: if (count[TILE_GOLDORE & 0xff] < 20 || count[TILE_MYCELIUM & 0xff] < 40) continue; break;
case 3: if (count[TILE_GEMORE & 0xff] < 20) continue; break; case 3: if (count[TILE_GEMORE & 0xff] < 20) continue; break;
} }
if (depthLevel < 3) if (count[TILE_STAIRS_DOWN & 0xff] < 2) continue; if (depthLevel < 3) if (count[TILE_STAIRS_DOWN & 0xff] < 2) continue;
@ -101,9 +113,13 @@ void createAndValidateUndergroundMap(int w, int h,int depthLevel, u8 * map, u8 *
} while (true); } while (true);
} }
void createAndValidateDungeonMap(int w, int h, u8 * map, u8 * data) { void createAndValidateDungeonMap(int w, int h, int level, u8 * map, u8 * data) {
do { do {
createDungeonMap(w, h, map, data); //reset Entities
(&eManager)->lastSlot[level] = 0;
(&eManager)->entities[level][0] = nullEntity;
createDungeonMap(w, h, level, map, data);
int count[256]={[0 ... 255] = 0}; int count[256]={[0 ... 255] = 0};
int i = 0; int i = 0;
@ -115,9 +131,13 @@ void createAndValidateDungeonMap(int w, int h, u8 * map, u8 * data) {
} while (true); } while (true);
} }
void createAndValidateSkyMap(int w, int h, u8 * map, u8 * data) { void createAndValidateSkyMap(int w, int h, int level, u8 * map, u8 * data) {
do { do {
createSkyMap(w, h, map, data); //reset Entities
(&eManager)->lastSlot[level] = 0;
(&eManager)->entities[level][0] = nullEntity;
createSkyMap(w, h, level, map, data);
int count[256]={[0 ... 255] = 0}; int count[256]={[0 ... 255] = 0};
int i = 0; int i = 0;
@ -131,7 +151,7 @@ void createAndValidateSkyMap(int w, int h, u8 * map, u8 * data) {
void createTopMap(int w, int h, u8 * map, u8 * data) { void createTopMap(int w, int h, int level, u8 * map, u8 * data) {
double* mnoise1 = Noise(w, h, 16); double* mnoise1 = Noise(w, h, 16);
double* mnoise2 = Noise(w, h, 16); double* mnoise2 = Noise(w, h, 16);
double* mnoise3 = Noise(w, h, 16); double* mnoise3 = Noise(w, h, 16);
@ -185,6 +205,8 @@ void createTopMap(int w, int h, u8 * map, u8 * data) {
} }
} }
createVillage(w, h, level, map, data);
for (i = 0; i < w * h / 400; ++i) { for (i = 0; i < w * h / 400; ++i) {
x = rand()%w; x = rand()%w;
y = rand()%h; y = rand()%h;
@ -254,7 +276,7 @@ void createTopMap(int w, int h, u8 * map, u8 * data) {
return; return;
} }
void createUndergroundMap(int w, int h,int depthLevel, u8 * map, u8 * data) { void createUndergroundMap(int w, int h, int depthLevel, int level, u8 * map, u8 * data) {
double* mnoise1 = Noise(w, h, 16); double* mnoise1 = Noise(w, h, 16);
double* mnoise2 = Noise(w, h, 16); double* mnoise2 = Noise(w, h, 16);
double* mnoise3 = Noise(w, h, 16); double* mnoise3 = Noise(w, h, 16);
@ -270,7 +292,8 @@ void createUndergroundMap(int w, int h,int depthLevel, u8 * map, u8 * data) {
double* noise1 = Noise(w, h, 32); double* noise1 = Noise(w, h, 32);
double* noise2 = Noise(w, h, 32); double* noise2 = Noise(w, h, 32);
int x, y; int x,y,i,j,k,xx,yy;
for(x = 0; x < w; ++x){ for(x = 0; x < w; ++x){
for(y = 0; y < w; ++y){ for(y = 0; y < w; ++y){
int i = x + y * w; int i = x + y * w;
@ -307,7 +330,37 @@ void createUndergroundMap(int w, int h,int depthLevel, u8 * map, u8 * data) {
} }
} }
} }
int i,j;
if(depthLevel==3) {
createDwarfHouse(w, h, level, map, data);
} else if(depthLevel==2) {
for (i = 0; i < w * h / 5400; ++i) {
int xs = rand()%w;
int ys = rand()%h;
for (k = 0; k < 10; ++k) {
x = xs + (rand()%13) - 6;
y = ys + (rand()%13) - 6;
for (j = 0; j < 100; ++j) {
int xo = x + (rand()%5) - (rand()%5);
int yo = y + (rand()%5) - (rand()%5);
for (yy = yo - 1;yy <= yo + 1; ++yy){
for(xx = xo - 1; xx <= xo + 1; ++xx){
if (xx >= 0 && yy >= 0 && xx < w && yy < h) {
if (map[xx + yy * w] == TILE_DIRT) {
map[xx + yy * w] = TILE_MYCELIUM;
if(rand()%20==0) {
map[xx + yy * w] = TILE_MUSHROOM_BROWN + rand()%2; //BROWN or RED (=BROWN+1)
data[xx + yy * w] = rand()%2;
}
}
}
}
}
}
}
}
}
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;
@ -357,145 +410,9 @@ void createUndergroundMap(int w, int h,int depthLevel, u8 * map, u8 * data) {
} }
void createDungeonRoom(int w, int h, bool dragon, u8 * map, u8 * data) { void createDungeonMap(int w, int h, int level, u8 * map, u8 * data) {
int tries; hasNPC = false;
for(tries=0; tries<100; ++tries) {
int x = 5+(rand()%(w-10 -10));
int y = 5+(rand()%(h-10 -10));
int xr;
int yr;
int wr = 10+(rand()%11);
int hr = 10+(rand()&11);
int xp;
int yp;
int i;
//create Dragonroom
if(dragon) {
wr = 20;
hr = 20;
x = 5 + (rand()%2)*(w-5*2-wr);
y = 5 + (rand()%2)*(h-5*2-hr);
}
if(x+wr > w-5) wr = (w-5) - x;
if(y+hr > h-5) hr = (h-5) - y;
//check instersection
bool allowed = true;
for(xr = x-1; xr < x+wr+1; ++xr) {
for(yr = y-1; yr < y+hr+1; ++yr) {
i = xr + yr * w;
//255 for paths so rooms can overlap paths
if(map[i]!=TILE_DUNGEON_WALL && map[i]!=255) {
allowed = false;
break;
}
}
if(!allowed) break;
}
if(!allowed) continue;
//create room
for(xr = x; xr < x+wr; ++xr) {
for(yr = y; yr < y+hr; ++yr) {
i = xr + yr * w;
map[i] = TILE_DUNGEON_FLOOR;
}
}
//Create path back to existing stuff
xp = x + wr/2;
yp = y + hr/2;
i = xp + yp * w;
bool checkForFloor = false;
bool xFirst = (rand()%2)==0;
while((checkForFloor && (map[i]!=TILE_DUNGEON_FLOOR && map[i]!=255)) || (!checkForFloor && (map[i]==TILE_DUNGEON_FLOOR || map[i]==255))) {
if(checkForFloor) {
//make connection
map[i] = 255;
}
//move
if(xFirst) {
if(xp > w/2) --xp;
else if(xp < w/2) ++xp;
else if(yp > h/2) --yp;
else if(yp < h/2) ++yp;
else break;
} else {
if(yp > h/2) --yp;
else if(yp < h/2) ++yp;
else if(xp > w/2) --xp;
else if(xp < w/2) ++xp;
else break;
}
i = xp + yp * w;
//search for end of current room
if(!checkForFloor && (map[i]!=TILE_DUNGEON_FLOOR && map[i]!=255)) checkForFloor = true;
}
//dekorate dragon room
if(dragon) {
for(xr = x; xr < x+wr; ++xr) {
for(yr = y; yr < y+hr; ++yr) {
i = xr + yr * w;
if((xr==x+1 || xr==x+wr-2 || yr==y+1 || yr==y+hr-2) && (xr!=x && xr!=x+wr-1 && yr!=y && yr!=y+hr-1)) {
map[i] = TILE_MAGIC_BARRIER;
}
}
}
//add Dragon Entity
addEntityToList(newDragonEntity((x+wr/2) << 4, (y+hr/2) << 4, 5), &eManager);
break;
}
//dekorate room
bool lava = (rand()%4)==0;
bool pillars = (rand()%4)==0;
for(xr = x; xr < x+wr; ++xr) {
for(yr = y; yr < y+hr; ++yr) {
i = xr + yr * w;
if(lava && xr > x+1 && xr < x+wr-2 && yr > y+1 && yr < y+hr-2) {
map[i] = TILE_LAVA;
} else if(pillars && xr > x && xr < x+wr-1 && yr > y && yr < y+hr-1 && xr%2 == 0 && yr%2 == 0) {
map[i] = TILE_DUNGEON_WALL;
} else {
//add magic pillars for dragon barrier
if(xr==x+wr/2 && yr==y+hr/2) {
int pcount = 0;
int i = 0;
for (i = 0; i < eManager.lastSlot[5]; ++i) {
Entity * e = &eManager.entities[5][i];
if(e->type == ENTITY_MAGIC_PILLAR) {
++pcount;
}
}
if(pcount<8) {
addEntityToList(newMagicPillarEntity((xr << 4) + 8, (yr << 4) + 8, 5), &eManager);
}
continue;
}
if(rand()%50==0) map[i] = TILE_IRONORE + (rand()%3);
}
}
}
break;
}
}
void createDungeonMap(int w, int h, u8 * map, u8 * data) {
int i, x, y; int i, x, y;
for(x = 0; x < w; ++x){ for(x = 0; x < w; ++x){
for(y = 0; y < w; ++y){ for(y = 0; y < w; ++y){
@ -504,18 +421,19 @@ void createDungeonMap(int w, int h, u8 * map, u8 * data) {
//Startroom //Startroom
if (x >= (w/2-5) && x <= (w/2+5) && y >= (h/2-5) && y <= (h/2+5) ) { if (x >= (w/2-5) && x <= (w/2+5) && y >= (h/2-5) && y <= (h/2+5) ) {
map[i] = TILE_DUNGEON_FLOOR; map[i] = TILE_DUNGEON_FLOOR;
data[i] = randomTile[rand()%randomTileSize];
} else { } else {
map[i] = TILE_DUNGEON_WALL; map[i] = TILE_DUNGEON_WALL;
data[i] = 0;
} }
data[i] = 0;
} }
} }
//create dragon chamber(only call once and before other rooms) //create dragon chamber(only call once and before other rooms)
createDungeonRoom(w, h, true, map, data); createDungeonRoom(w, h, true, level, map, data);
for(i = 0; i < 40; ++i) { for(i = 0; i < 40; ++i) {
createDungeonRoom(w, h, false, map, data); createDungeonRoom(w, h, false, level, map, data);
} }
//replace paths with actual dungeon floor //replace paths with actual dungeon floor
@ -525,6 +443,7 @@ void createDungeonMap(int w, int h, u8 * map, u8 * data) {
if (map[i]==255) { if (map[i]==255) {
map[i] = TILE_DUNGEON_FLOOR; map[i] = TILE_DUNGEON_FLOOR;
data[i] = randomTile[rand()%randomTileSize];
} }
} }
} }
@ -543,7 +462,7 @@ void createDungeonMap(int w, int h, u8 * map, u8 * data) {
map[w/2-1 + (h/2-1) * w] = TILE_DUNGEON_WALL; map[w/2-1 + (h/2-1) * w] = TILE_DUNGEON_WALL;
} }
void createSkyMap(int w, int h, u8 * map, u8 * data) { void createSkyMap(int w, int h, int level, u8 * map, u8 * data) {
double* noise1 = Noise(w, h, 8); double* noise1 = Noise(w, h, 8);
double* noise2 = Noise(w, h, 8); double* noise2 = Noise(w, h, 8);
int x, y; int x, y;
@ -603,3 +522,340 @@ void createSkyMap(int w, int h, u8 * map, u8 * data) {
free(noise2); free(noise2);
} }
//"Subgenerators"
void findFeatureLocation(int fw, int fh, int * accepted, int aLength, int maxTries, int w, int h, u8 * map, u8 * data) {
int leastNonFitting = fw * fh;
int tries;
//find the location with the least non fitting tiles out of some randomly tried ones
for(tries=0; tries<maxTries; ++tries) {
int x = rand()%(w-fw);
int y = rand()%(h-fh);
int nonFitting = 0;
int xp;
int yp;
int i;
int a;
bool fits;
for(xp=x; xp<x+fw; ++xp) {
for(yp=y; yp<y+fh; ++yp) {
i = xp + yp * w;
fits = false;
for(a=0; a<aLength; ++a) {
if(map[i]==accepted[a]) {
fits = true;
break;
}
}
if(!fits) {
nonFitting++;
}
}
}
if(nonFitting<leastNonFitting) {
featureX = x;
featureY = y;
leastNonFitting = nonFitting;
}
}
}
void createVillageHouse(int hid, int x, int y, int hw, int hh, int ex, int ey, int w, int h, int level, u8 * map, u8 * data) {
//create wall and floor
int xp = x;
int yp = y;
for(xp=x; xp<x+hw; ++xp) {
for(yp=y; yp<y+hh; ++yp) {
if(xp==x || xp==x+hw-1 || yp==y || yp==y+hh-1) map[xp + yp * w] = TILE_WOOD_WALL;
else map[xp + yp * w] = TILE_WOOD_FLOOR;
}
}
//recreate entrance
map[ex + ey * w] = TILE_WOOD_FLOOR;
//create npcs
if(hid==0) {
addEntityToList(newNPCEntity(NPC_GIRL, (x+hw/2) << 4, (y+hh/2) << 4, level), &eManager);
} else if(hid==1) {
addEntityToList(newNPCEntity(NPC_PRIEST, (x+hw/2) << 4, (y+hh/2) << 4, level), &eManager);
} else if(hid==2) {
addEntityToList(newNPCEntity(NPC_FARMER, (x+hw/2) << 4, (y+hh/2) << 4, level), &eManager);
//TODO: maybe create farm?
for(xp=x; xp<x+hw; ++xp) {
map[xp + yp * w] = TILE_WHEAT;
map[xp + (yp+1) * w] = TILE_WHEAT;
}
}
//add Latern Entity
int loffx = -12;
int loffy = -12;
if(hid==2) loffx = 12;
addEntityToList(newFurnitureEntity(ITEM_LANTERN, NULL, ((x+hw/2) << 4) + loffx, ((y+hh/2) << 4) + loffy, level), &eManager);
}
void createVillage(int w, int h, int level, u8 * map, u8 * data) {
int vw = 17;
int vh = 17;
int accepted[] = {TILE_GRASS};
findFeatureLocation(vw, vh, accepted, 1, 500, w, h, map, data);
int x = featureX;
int y = featureY;
int cx = x + vw/2;
int cy = y + vh/2;
int px;
int py;
int hw;
int hh;
int hx;
int hy;
int ex;
int ey;
//"well" in the middle
map[(cx-1) + (cy-1) * w] = TILE_SAND;
map[(cx+0) + (cy-1) * w] = TILE_SAND;
map[(cx+1) + (cy-1) * w] = TILE_SAND;
map[(cx-1) + (cy+0) * w] = TILE_SAND;
map[(cx+0) + (cy+0) * w] = TILE_WATER;
map[(cx+1) + (cy+0) * w] = TILE_SAND;
map[(cx-1) + (cy+1) * w] = TILE_SAND;
map[(cx+0) + (cy+1) * w] = TILE_SAND;
map[(cx+1) + (cy+1) * w] = TILE_SAND;
//"paths" outwards leading to the "houses"
//left
px = cx-1;
py = cy-1 + rand()%3;
while(px>x) {
map[px + py * w] = TILE_SAND;
--px;
}
hw = 4 + rand()%2;
hh = 4 + rand()%2;
hx = px + 1;
hy = py - hh + 2 + rand()%(hh-2);
ex = px + hw;
ey = py;
createVillageHouse(0, hx, hy, hw, hh, ex, ey, w, h, level, map, data);
//top
px = cx-1 + rand()%3;
py = cy-1;
while(py>y) {
map[px + py * w] = TILE_SAND;
--py;
}
hw = 5 + rand()%2;
hh = 4 + rand()%2;
hx = px - hw + 2 + rand()%(hw-2);
hy = py + 1;
ex = px;
ey = py+hh;
createVillageHouse(1, hx, hy, hw, hh, ex, ey, w, h, level, map, data);
//right
px = cx+1;
py = cy-1 + rand()%3;
while(px<x+vw) {
map[px + py * w] = TILE_SAND;
++px;
}
hw = 4 + rand()%2;
hh = 4 + rand()%2;
hx = px - hw;
hy = py - hh + 2 + rand()%(hh-2);
ex = px - hw;
ey = py;
createVillageHouse(2, hx, hy, hw, hh, ex, ey, w, h, level, map, data);
}
void createDwarfHouse(int w, int h, int level, u8 * map, u8 * data) {
int vw = 7;
int vh = 7;
int accepted[] = {TILE_ROCK};
findFeatureLocation(vw, vh, accepted, 1, 500, w, h, map, data);
int x = featureX;
int y = featureY;
int xp;
int yp;
for(xp=x; xp<x+vw; ++xp) {
for(yp=y; yp<y+vh; ++yp) {
if(xp==x || xp==x+vw-1 || yp==y || yp==y+vh-1) map[xp + yp * w] = TILE_STONE_WALL;
else map[xp + yp * w] = TILE_DIRT;
}
}
//entrance
xp = x+vw/2;
map[xp + (yp-1) * w] = TILE_DIRT;
//pillars
map[(x+2) + (y+2) * w] = TILE_STONE_WALL;
map[(x+vw-1-2) + (y+2) * w] = TILE_STONE_WALL;
addEntityToList(newNPCEntity(NPC_DWARF, ((x+vw/2) << 4) + 8, (y+vh/2) << 4, level), &eManager);
addEntityToList(newFurnitureEntity(ITEM_LANTERN, NULL, (x+1+1) << 4, (y+1+3) << 4, level), &eManager);
addEntityToList(newFurnitureEntity(ITEM_LANTERN, NULL, (x+vw-1-1) << 4, (y+1+3) << 4, level), &eManager);
}
void createDungeonRoom(int w, int h, bool dragon, int level, u8 * map, u8 * data) {
int tries;
for(tries=0; tries<100; ++tries) {
int x = 5+(rand()%(w-10 -10));
int y = 5+(rand()%(h-10 -10));
int xr;
int yr;
int wr = 10+(rand()%11);
int hr = 10+(rand()&11);
int xp;
int yp;
int i;
//create Dragonroom
if(dragon) {
wr = 20;
hr = 20;
x = 5 + (rand()%2)*(w-5*2-wr);
y = 5 + (rand()%2)*(h-5*2-hr);
}
if(x+wr > w-5) wr = (w-5) - x;
if(y+hr > h-5) hr = (h-5) - y;
//check instersection
bool allowed = true;
for(xr = x-1; xr < x+wr+1; ++xr) {
for(yr = y-1; yr < y+hr+1; ++yr) {
i = xr + yr * w;
//255 for paths so rooms can overlap paths
if(map[i]!=TILE_DUNGEON_WALL && map[i]!=255) {
allowed = false;
break;
}
}
if(!allowed) break;
}
if(!allowed) continue;
//create room
for(xr = x; xr < x+wr; ++xr) {
for(yr = y; yr < y+hr; ++yr) {
i = xr + yr * w;
map[i] = TILE_DUNGEON_FLOOR;
data[i] = randomTile[rand()%randomTileSize];
}
}
//Create path back to existing stuff
xp = x + wr/2;
yp = y + hr/2;
i = xp + yp * w;
bool checkForFloor = false;
bool xFirst = (rand()%2)==0;
while((checkForFloor && (map[i]!=TILE_DUNGEON_FLOOR && map[i]!=255)) || (!checkForFloor && (map[i]==TILE_DUNGEON_FLOOR || map[i]==255))) {
if(checkForFloor) {
//make connection
map[i] = 255;
}
//move
if(xFirst) {
if(xp > w/2) --xp;
else if(xp < w/2) ++xp;
else if(yp > h/2) --yp;
else if(yp < h/2) ++yp;
else break;
} else {
if(yp > h/2) --yp;
else if(yp < h/2) ++yp;
else if(xp > w/2) --xp;
else if(xp < w/2) ++xp;
else break;
}
i = xp + yp * w;
//search for end of current room
if(!checkForFloor && (map[i]!=TILE_DUNGEON_FLOOR && map[i]!=255)) checkForFloor = true;
}
//dekorate dragon room
if(dragon) {
for(xr = x; xr < x+wr; ++xr) {
for(yr = y; yr < y+hr; ++yr) {
i = xr + yr * w;
if((xr==x+1 || xr==x+wr-2 || yr==y+1 || yr==y+hr-2) && (xr!=x && xr!=x+wr-1 && yr!=y && yr!=y+hr-1)) {
map[i] = TILE_MAGIC_BARRIER;
}
}
}
//add Dragon Entity
addEntityToList(newDragonEntity((x+wr/2) << 4, (y+hr/2) << 4, level), &eManager);
break;
}
//dekorate room
bool lava = (rand()%4)==0;
bool pillars = (rand()%4)==0;
bool books = (rand()%4)==0;
for(xr = x; xr < x+wr; ++xr) {
for(yr = y; yr < y+hr; ++yr) {
i = xr + yr * w;
if(lava && xr > x+1 && xr < x+wr-2 && yr > y+1 && yr < y+hr-2) {
map[i] = TILE_LAVA;
data[i] = 0;
} else if(pillars && xr > x && xr < x+wr-1 && yr > y && yr < y+hr-1 && xr%2 == 0 && yr%2 == 0) {
map[i] = TILE_DUNGEON_WALL;
data[i] = 0;
} else if(books && (xr>x && xr<x+wr-1 && yr>y && yr<y+hr-1 && yr%2==0)) {
map[i] = TILE_BOOKSHELVES;
data[i] = rand()%3;
if(!hasNPC && rand()%50) {
hasNPC = true;
addEntityToList(newNPCEntity(NPC_LIBRARIAN, (xr << 4) + 8, ((yr+1) << 4) + 8, level), &eManager);
}
} else {
//add magic pillars for dragon barrier
if(xr==x+wr/2 && yr==y+hr/2) {
int pcount = 0;
int i = 0;
for (i = 0; i < eManager.lastSlot[5]; ++i) {
Entity * e = &eManager.entities[5][i];
if(e->type == ENTITY_MAGIC_PILLAR) {
++pcount;
}
}
if(pcount<8) {
addEntityToList(newMagicPillarEntity((xr << 4) + 8, (yr << 4) + 8, level), &eManager);
}
continue;
}
if(rand()%50==0) map[i] = TILE_IRONORE + (rand()%3);
}
}
}
break;
}
}

View file

@ -11,11 +11,21 @@ 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 newSeed();
void createAndValidateTopMap(int w, int h, u8 * map, u8 * data); void createAndValidateTopMap(int w, int h, int level, u8 * map, u8 * data);
void createTopMap(int w, int h, u8 * map, u8 * data); void createTopMap(int w, int h, int level, u8 * map, u8 * data);
void createAndValidateUndergroundMap(int w, int h,int depthLevel, u8 * map, u8 * data); void createAndValidateUndergroundMap(int w, int h, int depthLevel, int level, u8 * map, u8 * data);
void createUndergroundMap(int w, int h,int depthLevel, u8 * map, u8 * data); void createUndergroundMap(int w, int h, int depthLevel, int level, u8 * map, u8 * data);
void createAndValidateDungeonMap(int w, int h, u8 * map, u8 * data); void createAndValidateDungeonMap(int w, int h, int level, u8 * map, u8 * data);
void createDungeonMap(int w, int h, u8 * map, u8 * data); void createDungeonMap(int w, int h, int level, u8 * map, u8 * data);
void createAndValidateSkyMap(int w, int h, u8 * map, u8 * data); void createAndValidateSkyMap(int w, int h, int level, u8 * map, u8 * data);
void createSkyMap(int w, int h, u8 * map, u8 * data); void createSkyMap(int w, int h, int level, u8 * map, u8 * data);
int featureX;
int featureY;
void findFeatureLocation(int fw, int fh, int * accepted, int aLength, int maxTries, int w, int h, u8 * map, u8 * data);
void createVillage(int w, int h, int level, u8 * map, u8 * data);
void createDwarfHouse(int w, int h, int level, u8 * map, u8 * data);
bool hasNPC;
void createDungeonRoom(int w, int h, bool dragon, int level, u8 * map, u8 * data);

View file

@ -531,7 +531,9 @@ void tickMenu(int menu){
} }
enterDungeon(); enterDungeon();
} } else if(TESTGODMODE) {
enterDungeon();
}
} else { } else {
leaveDungeon(); leaveDungeon();
} }
@ -755,6 +757,9 @@ void tickMenu(int menu){
} }
break; break;
case MENU_NPC:
tickNPCMenu();
break;
} }
} }
@ -1158,8 +1163,8 @@ void renderMenu(int menu,int xscr,int yscr){
drawTextColor("Cost",248+1,78+1,0xFF000000); drawTextColor("Cost",248+1,78+1,0xFF000000);
drawTextColor("Cost",248,78,0xFF6FE2E2); drawTextColor("Cost",248,78,0xFF6FE2E2);
renderFrame(1,1,14,14,0xFFFF1010); renderFrame(1,1,14,14,0xFFFF1010);
drawTextColor("Crafting",24+1,14+1,0xFF000000); drawTextColor(currentCraftTitle,24+1,14+1,0xFF000000);
drawTextColor("Crafting",24,14,0xFF6FE2E2); drawTextColor(currentCraftTitle,24,14,0xFF6FE2E2);
renderRecipes(currentRecipes, 1, 1, 14, 14, curInvSel); renderRecipes(currentRecipes, 1, 1, 14, 14, curInvSel);
Recipe* rec = &currentRecipes->recipes[curInvSel]; Recipe* rec = &currentRecipes->recipes[curInvSel];
@ -1420,7 +1425,20 @@ void renderMenu(int menu,int xscr,int yscr){
break; break;
} }
sf2d_end_frame(); sf2d_end_frame();
break; break;
case MENU_NPC:
sf2d_start_frame(GFX_TOP, GFX_LEFT);
if(currentLevel == 0){
sf2d_draw_texture_part_scale(minimap[1],(-xscr/3)-256,(-yscr/3)-32,0,0,128,128,12.5,7.5);
sf2d_draw_rectangle(0,0,400,240, 0xAFDFDFDF);
}
offsetX = xscr;offsetY = yscr;
renderMenuBackground(xscr,yscr);
offsetX = 0;offsetY = 0;
renderNPCMenu(xscr, yscr);
sf2d_end_frame();
break;
} }
} }

View file

@ -2,6 +2,7 @@
#include "MenuTutorial.h" #include "MenuTutorial.h"
#include "texturepack.h" #include "texturepack.h"
#include "Quests.h"
void initMenus(); void initMenus();

417
source/Quests.c Normal file
View file

@ -0,0 +1,417 @@
#include "Quests.h"
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;
void initQuests() {
questManager.size = 2;
questManager.questlines = (Questline*)malloc(sizeof(Questline) * (questManager.size));
priestTrades.size = 5;
priestTrades.recipes = (Recipe*)malloc(sizeof(Recipe) * (priestTrades.size));
priestTrades.recipes[0] = defineRecipe(ITEM_DUNGEON_KEY,1,1,ITEM_MAGIC_DUST,2);
priestTrades.recipes[1] = defineRecipe(ITEM_WIZARD_SUMMON,1,4,ITEM_CLOUD,100,ITEM_IRONINGOT,10,ITEM_BONE,10,ITEM_LEATHER,10);
priestTrades.recipes[2] = defineRecipe(TOOL_MAGIC_COMPASS,1,2,ITEM_IRONINGOT,10,ITEM_GLASS,5);
priestTrades.recipes[3] = defineRecipe(ITEM_COIN,1,1,ITEM_SLIME,5);
priestTrades.recipes[4] = defineRecipe(ITEM_COIN,1,1,ITEM_FLESH,5);
farmerTrades.size = 7;
farmerTrades.recipes = (Recipe*)malloc(sizeof(Recipe) * (farmerTrades.size));
farmerTrades.recipes[0] = defineRecipe(ITEM_WHEAT,5,1,ITEM_COIN,3);
farmerTrades.recipes[1] = defineRecipe(ITEM_BREAD,1,1,ITEM_COIN,3);
farmerTrades.recipes[2] = defineRecipe(ITEM_APPLE,2,1,ITEM_COIN,4);
farmerTrades.recipes[3] = defineRecipe(ITEM_ACORN,3,1,ITEM_COIN,1);
farmerTrades.recipes[4] = defineRecipe(ITEM_SEEDS,4,1,ITEM_COIN,2);
farmerTrades.recipes[5] = defineRecipe(ITEM_COIN,2,1,ITEM_SEEDS,5);
farmerTrades.recipes[6] = defineRecipe(ITEM_COIN,1,1,ITEM_ACORN,5);
dwarfTrades.size = 2;
dwarfTrades.recipes = (Recipe*)malloc(sizeof(Recipe) * (dwarfTrades.size));
dwarfTrades.recipes[0] = defineRecipe(ITEM_IRONINGOT,4,1,ITEM_GOLDINGOT,1);
dwarfTrades.recipes[1] = defineRecipe(ITEM_GOLDINGOT,2,1,ITEM_GEM,1);
//TODO: Trade Dragon Scales for something really nice
}
void resetQuests() {
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(farmerTrades.recipes);
free(dwarfTrades.recipes);
}
void openNPCMenu(int npc) {
currentNPC = npc;
currentNPCVal = 0;
currentMenu = MENU_NPC;
currentNPCMenu = NPC_MENU_TALK;
currentTalkSel = 0;
currentTalkDone = false;
currentTalkOptions = 1;
currentTalkOption0 = "Bye";
currentTalkOption1 = "";
currentTalkOption2 = "";
currentTalk0 = "";
currentTalk1 = "";
currentTalk2 = "";
currentTalk3 = "";
currentTalk4 = "";
currentTalk5 = "";
//TODO: Handle upon currentNPC as well as the fitting quest progress
switch(currentNPC) {
case NPC_GIRL:
break;
case NPC_PRIEST:
currentTalkOptions = 3;
currentTalkOption1 = "Trade";
currentTalkOption2 = "Why are you so few?";
currentTalk0 = "Welcome to our small village";
currentTalk1 = "I am the leader of our group.";
currentTalk2 = "If you have anything usefull";
currentTalk3 = "for us I might be able to";
currentTalk4 = "provide something nice in";
currentTalk5 = "exchange.";
break;
case NPC_FARMER:
currentTalkOptions = 2;
currentTalkOption0 = "Maybe some other time";
currentTalkOption1 = "Trade";
currentTalk0 = "Hello friend!";
currentTalk1 = "Nice seeing somebody else";
currentTalk2 = "visit my little farm.";
currentTalk3 = "Interested in buying some";
currentTalk4 = "fresh farm goods?";
currentTalk5 = "";
break;
case NPC_LIBRARIAN:
currentTalkOptions = 2;
currentTalkOption0 = "Nothing";
currentTalkOption1 = "What are you doing here?";
if(questManager.questlines[1].currentQuest==1) {
currentTalkOptions = 3;
currentTalkOption2 = "Dwarvish language";
}
currentTalk0 = "Oh hello?";
currentTalk1 = "You must be quite brave";
currentTalk2 = "or stupid to be walking";
currentTalk3 = "around in this dungeon.";
currentTalk4 = "";
currentTalk5 = "Who can I help you?";
break;
case NPC_DWARF:
if(questManager.questlines[1].currentQuest<=1) {
questManager.questlines[1].currentQuest = 1;
currentTalkOptions = 1;
currentTalkOption0 = "?";
currentTalk0 = "Dwo neal bet reck da lo";
currentTalk1 = "dhum don lir lugn at el";
currentTalk2 = "nur tor erno ur yo trad";
currentTalk3 = "thra so tir kho ukk tin";
currentTalk4 = "hel dro ic";
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)
} else if(questManager.questlines[1].currentQuest==2) {
currentTalkOptions = 2;
currentTalkOption0 = "Not really";
currentTalkOption1 = "Trade";
currentTalk0 = "How are ya?";
currentTalk1 = "Pretty unusal meeting a";
currentTalk2 = "human down here.";
currentTalk3 = "";
currentTalk4 = "have something valuable";
currentTalk5 = "to trade?";
}
break;
}
}
void tickTalkMenu() {
if (k_menu.clicked || k_decline.clicked) currentMenu = MENU_NONE;
if (k_up.clicked){ ++currentTalkSel; if(currentTalkSel >= currentTalkOptions) currentTalkSel=0;}
if (k_down.clicked){ --currentTalkSel; if(currentTalkSel < 0) currentTalkSel=currentTalkOptions-1;}
if(k_accept.clicked){
currentTalkDone = true;
}
}
void tickNPCMenu() {
//TODO: Handle upon currentNPC as well as the fitting quest progress
if(currentNPCMenu==NPC_MENU_TALK) tickTalkMenu();
switch(currentNPC) {
case NPC_GIRL:
break;
case NPC_PRIEST:
if(currentNPCMenu==NPC_MENU_TALK && currentTalkDone) {
if(currentNPCVal==0) {
if(currentTalkSel==0) {
currentMenu = MENU_NONE;
} else if(currentTalkSel==1) {
currentRecipes = &priestTrades;
currentCraftTitle = "Trading";
currentMenu = MENU_CRAFTING;
checkCanCraftRecipes(currentRecipes, player.p.inv);
sortRecipes(currentRecipes);
} else if(currentTalkSel==2) {
currentNPCVal = 1;
currentTalkSel = 0;
currentTalkDone = false;
currentTalkOptions = 1;
currentTalkOption0 = "...";
currentTalk0 = "For quite some time now this";
currentTalk1 = "village has been tyrannized";
currentTalk2 = "by a powerfull Air Wizard.";
currentTalk3 = "We are the only ones who";
currentTalk4 = "still have not given up";
currentTalk5 = "our old homes.";
}
} else if(currentNPCVal==1) {
if(currentTalkSel==0) {
currentNPCVal = 2;
currentTalkSel = 0;
currentTalkDone = false;
currentTalkOptions = 1;
currentTalkOption0 = "...";
currentTalk0 = "Most of the time the wizard";
currentTalk1 = "hides somewhere in the";
currentTalk2 = "cloudes. They can only be";
currentTalk3 = "reached by a stairwell";
currentTalk4 = "protected by an almost";
currentTalk5 = "undestroyable stone barrier.";
}
} else if(currentNPCVal==2) {
if(currentTalkSel==0) {
currentNPCVal = 3;
currentTalkSel = 0;
currentTalkDone = false;
currentTalkOptions = 1;
currentTalkOption0 = "...";
currentTalk0 = "I am guessing you would ";
currentTalk1 = "need tools atleast as";
currentTalk2 = "strong as diamonds to be";
currentTalk3 = "able to destroy it.";
currentTalk4 = "";
currentTalk5 = "";
}
} else if(currentNPCVal==3) {
if(currentTalkSel==0) {
currentNPCVal = 4;
currentTalkSel = 0;
currentTalkDone = false;
currentTalkOptions = 2;
currentTalkOption0 = "Let me do it!";
currentTalkOption1 = "I am not sure";
currentTalk0 = "I am willing to give an";
currentTalk1 = "ancient artifact passed";
currentTalk2 = "down over generations to";
currentTalk3 = "anybody who manages to";
currentTalk4 = "chase the wizard away and";
currentTalk5 = "come back with proof.";
}
} else if(currentNPCVal==4) {
currentMenu = MENU_NONE;
}
}
break;
case NPC_FARMER:
if(currentNPCMenu==NPC_MENU_TALK && currentTalkDone) {
if(currentNPCVal==0) {
if(currentTalkSel==0) {
currentMenu = MENU_NONE;
} else if(currentTalkSel==1) {
currentRecipes = &farmerTrades;
currentCraftTitle = "Trading";
currentMenu = MENU_CRAFTING;
checkCanCraftRecipes(currentRecipes, player.p.inv);
sortRecipes(currentRecipes);
}
}
}
break;
case NPC_LIBRARIAN:
if(currentNPCMenu==NPC_MENU_TALK && currentTalkDone) {
if(currentNPCVal==0) {
if(currentTalkSel==0) {
currentMenu = MENU_NONE;
} else if(currentTalkSel==1) {
currentNPCVal = 2;
currentTalkSel = 0;
currentTalkDone = false;
currentTalkOptions = 1;
currentTalkOption0 = "Ok";
currentTalk0 = "The books in this dungeon";
currentTalk1 = "house secrets that cannot be";
currentTalk2 = "found anywhere else in the";
currentTalk3 = "world. So I came to study";
currentTalk4 = "them. Most are written in";
currentTalk5 = "an ancient language.";
} else if(currentTalkSel==2) {
currentNPCVal = 1;
currentTalkSel = 0;
currentTalkDone = false;
currentTalkOptions = 2;
currentTalkOption0 = "I need to think about it";
currentTalkOption1 = "Here they are";
currentTalk0 = "So you have met a dwarf but";
currentTalk1 = "had a little communication";
currentTalk2 = "problem? I do have a dwarvish";
currentTalk3 = "translation book but I havent";
currentTalk4 = "read it yet. For 10 Gold bars";
currentTalk5 = "I will give it to you anyway.";
}
} else if(currentNPCVal==1) {
if(currentTalkSel==0) {
currentMenu = MENU_NONE;
} else if(currentTalkSel==1) {
currentNPCVal = 2;
currentTalkSel = 0;
currentTalkDone = false;
currentTalkOptions = 1;
currentTalkOption0 = "";
if(countItemInv(ITEM_GOLDINGOT,0,player.p.inv)>=10) {
//remove gold from player inventory
//TODO: Maybe I should make a generic substract items method sometime
Item* item = getItemFromInventory(ITEM_GOLDINGOT, player.p.inv);
item->countLevel -= 10;
if(item->countLevel < 1) removeItemFromInventory(item->slotNum, player.p.inv);
questManager.questlines[1].currentQuest = 2;
currentTalk0 = "Thank you these will be";
currentTalk1 = "really helpfull.";
currentTalk2 = "Here take this book with";
currentTalk3 = "it you should be able to";
currentTalk4 = "easily understand anything";
currentTalk5 = "a dwarf can say.";
currentTalkOption0 = "Thanks";
} else {
currentTalk0 = "You do not seem to have";
currentTalk1 = "enough Gold Bars with you.";
currentTalk2 = "";
currentTalk3 = "Ask again when you have";
currentTalk4 = "collected the 10 Bars.";
currentTalk5 = "";
currentTalkOption0 = "Ok";
}
}
} else if(currentNPCVal==2) {
if(currentTalkSel==0) {
currentMenu = MENU_NONE;
}
}
}
break;
case NPC_DWARF:
if(questManager.questlines[1].currentQuest<=1) {
if(currentNPCMenu==NPC_MENU_TALK && currentTalkDone) {
if(currentNPCVal==0) currentMenu = MENU_NONE;
}
} else if(questManager.questlines[1].currentQuest==2) {
if(currentNPCMenu==NPC_MENU_TALK && currentTalkDone) {
if(currentTalkSel==0) {
currentMenu = MENU_NONE;
} else if(currentTalkSel==1) {
currentRecipes = &dwarfTrades;
currentCraftTitle = "Trading";
currentMenu = MENU_CRAFTING;
checkCanCraftRecipes(currentRecipes, player.p.inv);
sortRecipes(currentRecipes);
}
}
}
break;
}
}
void renderTalkMenu(char * name) {
renderFrame(1,1,24,14,0xFFFF1010);
drawTextColor(name,24+1,14+1,0xFF000000);
drawTextColor(name,24,14,0xFF6FE2E2);
drawText(currentTalk0, 32, 32);
drawText(currentTalk1, 32, 48);
drawText(currentTalk2, 32, 64);
drawText(currentTalk3, 32, 80);
drawText(currentTalk4, 32, 96);
drawText(currentTalk5, 32, 112);
if(currentTalkOptions>=3) drawText(currentTalkOption2, 64, 147);
if(currentTalkOptions>=2) drawText(currentTalkOption1, 64, 171);
if(currentTalkOptions>=1) drawText(currentTalkOption0, 64, 195);
if(currentTalkOptions>=3 && currentTalkSel==2) drawText(">", 48, 147);
if(currentTalkOptions>=2 && currentTalkSel==1) drawText(">", 48, 171);
if(currentTalkOptions>=1 && currentTalkSel==0) drawText(">", 48, 195);
}
void renderNPCMenu(int xscr, int yscr) {
//TODO: Handle upon currentNPC as well as the fitting quest progress
switch(currentNPC) {
case NPC_GIRL:
if(currentNPCMenu==NPC_MENU_TALK) renderTalkMenu("TODO");
break;
case NPC_PRIEST:
if(currentNPCMenu==NPC_MENU_TALK) renderTalkMenu("Priest Brom");
break;
case NPC_FARMER:
if(currentNPCMenu==NPC_MENU_TALK) renderTalkMenu("Farmer Garrow");
break;
case NPC_LIBRARIAN:
if(currentNPCMenu==NPC_MENU_TALK) renderTalkMenu("Librarian Ajihad");
break;
case NPC_DWARF:
if(currentNPCMenu==NPC_MENU_TALK) renderTalkMenu("Dwarf Orik");
break;
}
}

32
source/Quests.h Normal file
View file

@ -0,0 +1,32 @@
#pragma once
#include <stdlib.h>
#include <stdbool.h>
#include "render.h"
#include "Crafting.h"
#define NPC_MENU_TALK 0
typedef struct {
int currentQuest;
bool currentQuestDone;
} Questline;
typedef struct {
int size;
Questline * questlines;
} QuestlineManager;
QuestlineManager questManager;
RecipeManager priestTrades;
RecipeManager farmerTrades;
RecipeManager dwarfTrades;
void initQuests();
void resetQuests();
void freeQuests();
void openNPCMenu(int npc);
void renderNPCMenu(int xscr, int yscr);
void tickNPCMenu();

View file

@ -472,22 +472,39 @@ void renderTile(int i, int d, int x, int y) {
checkSurrTiles4(x >> 4, y >> 4, TILE_FLOWER); checkSurrTiles4(x >> 4, y >> 4, TILE_FLOWER);
checkSurrTiles4(x >> 4, y >> 4, TILE_SAPLING_TREE); checkSurrTiles4(x >> 4, y >> 4, TILE_SAPLING_TREE);
renderConnectedTile4(x, y, 256, 0); if(currentLevel==1 && season==3) renderConnectedTile4(x, y, 256, 112);
else if(currentLevel==1 && season==2) renderConnectedTile4(x, y, 256, 128);
else renderConnectedTile4(x, y, 256, 0);
break; break;
case TILE_TREE: case TILE_TREE:
renderTile(TILE_GRASS, 0, x, y); renderTile(TILE_GRASS, 0, x, y);
checkSurrTiles8(x >> 4, y >> 4, TILE_TREE); checkSurrTiles8(x >> 4, y >> 4, TILE_TREE);
render(x, y, 256+((tu && tl && tul) ? 16 : 0), 48, 0); if(season==2) {
render(x+8, y, 264+((tu && tr && tur) ? 16 : 0), 48, 0); render(x, y, 352+((tu && tl && tul) ? 16 : 0), 96, 0);
render(x, y+8, 256+((td && tl && tdl) ? 16 : 0), 56, 0); render(x+8, y, 360+((tu && tr && tur) ? 16 : 0), 96, 0);
render(x+8, y+8, 264+((td && tr && tdr) ? 16 : 0), 56, 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);
} else if(season==3) {
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, y+8, 352+((td && tl && tdl) ? 16 : 0), 120, 0);
render(x+8, y+8, 360+((td && tr && tdr) ? 16 : 0), 120, 0);
} else {
render(x, y, 256+((tu && tl && tul) ? 16 : 0), 48, 0);
render(x+8, y, 264+((tu && tr && tur) ? 16 : 0), 48, 0);
render(x, y+8, 256+((td && tl && tdl) ? 16 : 0), 56, 0);
render(x+8, y+8, 264+((td && tr && tdr) ? 16 : 0), 56, 0);
}
break; break;
case TILE_ROCK: case TILE_ROCK:
checkSurrTiles8(x >> 4, y >> 4, TILE_ROCK); checkSurrTiles8(x >> 4, y >> 4, TILE_ROCK);
renderConnectedTile8(x, y, 336, 64); if(currentLevel>1)
renderConnectedTile8(x, y, 256, 96);
else
renderConnectedTile8(x, y, 336, 64);
break; break;
case TILE_HARDROCK: case TILE_HARDROCK:
checkSurrTiles8(x >> 4, y >> 4, TILE_HARDROCK); checkSurrTiles8(x >> 4, y >> 4, TILE_HARDROCK);
@ -504,15 +521,20 @@ void renderTile(int i, int d, int x, int y) {
checkSurrTiles4(x >> 4, y >> 4, TILE_CACTUS); checkSurrTiles4(x >> 4, y >> 4, TILE_CACTUS);
checkSurrTiles4(x >> 4, y >> 4, TILE_SAPLING_CACTUS); checkSurrTiles4(x >> 4, y >> 4, TILE_SAPLING_CACTUS);
renderConnectedTile4(x, y, 320, 0); if(currentLevel==1 && season==3) {
renderConnectedTile4(x, y, 256, 112);
} else {
renderConnectedTile4(x, y, 320, 0);
if (d > 0) { if (d > 0) {
render16(x, y, 336, 48, 0); render16(x, y, 336, 48, 0);
} }
}
break; break;
case TILE_WATER: case TILE_WATER:
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);
renderConnectedTile4(x, y, 384, 0); renderConnectedTile4(x, y, 384, 0);
@ -541,7 +563,8 @@ void renderTile(int i, int d, int x, int y) {
break; break;
case TILE_FLOWER: case TILE_FLOWER:
renderTile(TILE_GRASS, 0, x, y); renderTile(TILE_GRASS, 0, x, y);
render16(x, y, 320, 48, getData(x >> 4, y >> 4)); if(currentLevel==1 && season==3) render16(x, y, 320, 112, getData(x >> 4, y >> 4));
else render16(x, y, 320, 48, getData(x >> 4, y >> 4));
break; break;
case TILE_STAIRS_DOWN: case TILE_STAIRS_DOWN:
if (currentLevel == 0) if (currentLevel == 0)
@ -619,14 +642,14 @@ void renderTile(int i, int d, int x, int y) {
renderConnectedTile8(x, y, 384, 32); renderConnectedTile8(x, y, 384, 32);
break; break;
case TILE_DUNGEON_FLOOR: case TILE_DUNGEON_FLOOR:
render16(x, y, 464, 32, 0); render16(x, y, 464 + d*16, 32, 0);
break; break;
case TILE_DUNGEON_ENTRANCE: case TILE_DUNGEON_ENTRANCE:
render16(x, y, 480 + (currentLevel==5 ? 16 : 0), 32, 0); render16(x, y, 352 + (currentLevel==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, x, y);
render16(x, y, 320, 64, 0); render16(x, y, 320, 64, getData(x >> 4, y >> 4));
//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) { if((player.x - (x+8))*(player.x - (x+8)) + (player.y - (y+8))*(player.y - (y+8)) <= 24*24) {
@ -650,6 +673,38 @@ void renderTile(int i, int d, int x, int y) {
drawSizedTextColor(currentCount, x+4, y+4, 2, dungeonColor[0]); drawSizedTextColor(currentCount, x+4, y+4, 2, dungeonColor[0]);
} }
break;
case TILE_BOOKSHELVES:
checkSurrTiles4(x >> 4, y >> 4, TILE_BOOKSHELVES);
renderConnectedTile4(x, y, 384, 80 + d*16);
break;
case TILE_WOOD_FLOOR:
render16(x, y, 336, 96, 0);
break;
case TILE_MYCELIUM:
checkSurrTiles4(x >> 4, y >> 4, TILE_MYCELIUM);
checkSurrTiles4(x >> 4, y >> 4, TILE_MUSHROOM_BROWN);
checkSurrTiles4(x >> 4, y >> 4, TILE_MUSHROOM_RED);
if(currentLevel==1 && season==3) renderConnectedTile4(x, y, 256, 112);
else renderConnectedTile4(x, y, 448, 80);
break;
case TILE_MUSHROOM_BROWN:
renderTile(TILE_MYCELIUM, 0, x, y);
render16(x, y, 448 + (d&0x1)*16, 96, 0);
break;
case TILE_MUSHROOM_RED:
renderTile(TILE_MYCELIUM, 0, x, y);
render16(x, y, 480 + (d&0x1)*16, 96, 0);
break;
case TILE_ICE:
renderTile(TILE_WATER, 0, x, y);
//checkSurrTiles4(x >> 4, y >> 4, TILE_WATER);
//checkSurrTiles4(x >> 4, y >> 4, TILE_HOLE);
checkSurrTiles4(x >> 4, y >> 4, TILE_ICE);
renderConnectedTile4(x, y, 448, 112);
break; break;
} }
@ -858,6 +913,40 @@ void renderMenuBackground(int xScroll, int yScroll) {
renderDayNight(); renderDayNight();
} }
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 yt;
for(xt=0; xt<4; ++xt) {
for(yt=0; yt<3; ++yt) {
sf2d_draw_texture_part_scale(icons, xp + xt*128, yp + yt*128, 192, 0, 64, 64, 2, 2);
sf2d_draw_texture_part_scale(icons, xp2 + xt*128, yp2 + yt*128, 192, 0, 64, 64, 2, 2);
}
}
}
if(rain) {
int xp = -((xScroll*2)%128);
int yp = -128 + ((tickCount<<2) - yScroll*2)%128;
int xp2 = -((xScroll*2+8)%128);
int yp2 = -128 + ((tickCount<<1)+64 - yScroll*2)%128;
int xt;
int yt;
for(xt=0; xt<4; ++xt) {
for(yt=0; yt<3; ++yt) {
sf2d_draw_texture_part_scale(icons, xp + xt*128, yp + yt*128, 128, 0, 64, 64, 2, 2);
sf2d_draw_texture_part_scale(icons, xp2 + xt*128, yp2 + yt*128, 128, 0, 64, 64, 2, 2);
}
}
}
}
}
void renderDayNight() { void renderDayNight() {
if(currentLevel==1 && (daytime<6000 || daytime>18000)) { if(currentLevel==1 && (daytime<6000 || daytime>18000)) {
int color1 = 0x000C0C0C; int color1 = 0x000C0C0C;
@ -1197,6 +1286,8 @@ void renderEntity(Entity* e, int x, int y) {
case ENTITY_GLOWWORM: case ENTITY_GLOWWORM:
render(x-4, y-4, 224, 112, 0); render(x-4, y-4, 224, 112, 0);
break; break;
case ENTITY_NPC:
render16(x - 8, y - 8, (e->npc.type*16) + 0, 64, 0);
} }
} }
@ -1244,8 +1335,7 @@ void renderItemList(Inventory * inv, int xo, int yo, int x1, int y1,
} }
} }
void renderRecipes(RecipeManager * r, int xo, int yo, int x1, int y1, void renderRecipes(RecipeManager * r, int xo, int yo, int x1, int y1, int selected) {
int selected) {
int size = r->size; int size = r->size;
if (size < 1) if (size < 1)
return; return;
@ -1265,16 +1355,16 @@ void renderRecipes(RecipeManager * r, int xo, int yo, int x1, int y1,
int i, col; int i, col;
for (i = 0; i < i1; ++i) { for (i = 0; i < i1; ++i) {
int x = (1 + xo) << 4, y = (i + 1 + yo) << 4; int x = (1 + xo) << 4, y = (i + 1 + yo) << 4;
renderItemIcon(r->recipes[i + io].itemResult, renderItemIcon(r->recipes[i + io].itemResult, r->recipes[i + io].itemAmountLevel, x >> 1, y >> 1);
r->recipes[i + io].itemAmountLevel, x >> 1, y >> 1);
if (r->recipes[i + io].canCraft) if (r->recipes[i + io].canCraft)
col = 0xFFFFFFFF; col = 0xFFFFFFFF;
else else
col = 0xFF7F7F7F; col = 0xFF7F7F7F;
drawTextColor( if(r->recipes[i + io].itemAmountLevel==1) {
getBasicItemName(r->recipes[i + io].itemResult, drawTextColor(getBasicItemName(r->recipes[i + io].itemResult, r->recipes[i + io].itemAmountLevel), x + 18, y + 2, col);
r->recipes[i + io].itemAmountLevel), x + 18, y + 2, } else {
col); drawTextColor(getItemName(r->recipes[i + io].itemResult, r->recipes[i + io].itemAmountLevel), x + 18, y + 2, col);
}
} }
int yy = selected + 1 - io + yo; int yy = selected + 1 - io + yo;
@ -1317,6 +1407,8 @@ void renderItemWithTextCentered(Item* item, int width, int y) {
} }
void renderItemIcon(int itemID, int countLevel, int x, int y) { void renderItemIcon(int itemID, int countLevel, int x, int y) {
int xd;
int yd;
switch (itemID) { switch (itemID) {
case ITEM_NULL: case ITEM_NULL:
return; return;
@ -1491,11 +1583,31 @@ void renderItemIcon(int itemID, int countLevel, int x, int y) {
case ITEM_DRAGON_SCALE: case ITEM_DRAGON_SCALE:
render(x, y, 168, 160, 0); render(x, y, 168, 160, 0);
break; break;
case ITEM_BOOKSHELVES:
render(x, y, 232, 144, 0);
break;
case ITEM_MAGIC_DUST:
render(x, y, 200, 152, 0);
break;
case ITEM_COIN:
render(x, y, 208, 152, 0);
break;
case TOOL_BUCKET: case TOOL_BUCKET:
render(x, y, 200 + countLevel * 8, 144, 0); render(x, y, 200 + countLevel * 8, 144, 0);
break; break;
case TOOL_BOW: case TOOL_BOW:
render(x, y, 64, 168, 0); render(x, y, 64, 168, 0);
break; break;
case TOOL_MAGIC_COMPASS:
xd = compassData[currentLevel][0] - (player.x>>4);
yd = compassData[currentLevel][1] - (player.y>>4);
if(abs(yd)>abs(xd)) {
if(yd<0) render(x, y, 112, 168, 0);
else render(x, y, 120, 168, 0);
} else {
if(xd<0) render(x, y, 128, 168, 0);
else render(x, y, 136, 168, 0);
}
break;
} }
} }

View file

@ -31,6 +31,7 @@ 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(int xScroll, int yScroll);
void renderMenuBackground(int xScroll, int yScroll); //Renders the darkness void renderMenuBackground(int xScroll, int yScroll); //Renders the darkness
void renderWeather(int xScroll, int yScroll);
void renderDayNight(); void renderDayNight();
void renderButtonIcon(u32 icon, int x, int y, float scale); void renderButtonIcon(u32 icon, int x, int y, float scale);

View file

@ -1,27 +1,5 @@
#include "SaveLoad.h" #include "SaveLoad.h"
s16 calculateImportantEntites(EntityManager * eManager, int level){
int i;
s16 count = 0;
for(i = 0; i < eManager->lastSlot[level]; ++i){
switch(eManager->entities[level][i].type){
case ENTITY_AIRWIZARD:
case ENTITY_SLIME:
case ENTITY_ZOMBIE:
case ENTITY_SKELETON:
case ENTITY_KNIGHT:
case ENTITY_ITEM:
case ENTITY_FURNITURE:
case ENTITY_PASSIVE:
case ENTITY_GLOWWORM:
case ENTITY_DRAGON:
count++;
break;
}
}
return count;
}
bool entityIsImportant(Entity * e){ bool entityIsImportant(Entity * e){
switch(e->type){ switch(e->type){
case ENTITY_AIRWIZARD: case ENTITY_AIRWIZARD:
@ -34,12 +12,24 @@ bool entityIsImportant(Entity * e){
case ENTITY_PASSIVE: case ENTITY_PASSIVE:
case ENTITY_GLOWWORM: case ENTITY_GLOWWORM:
case ENTITY_DRAGON: case ENTITY_DRAGON:
case ENTITY_NPC:
return true; return true;
default: default:
return false; return false;
} }
} }
s16 calculateImportantEntites(EntityManager * eManager, int level){
int i;
s16 count = 0;
for(i = 0; i < eManager->lastSlot[level]; ++i){
if(entityIsImportant(&eManager->entities[level][i])){
count++;
}
}
return count;
}
void saveCurrentWorld(char * filename, EntityManager * eManager, Entity * player, u8 * map, u8 * mapData){ void saveCurrentWorld(char * filename, EntityManager * eManager, Entity * player, u8 * map, u8 * mapData){
FILE * file = fopen(filename, "wb"); FILE * file = fopen(filename, "wb");
int i,j; int i,j;
@ -107,6 +97,9 @@ void saveCurrentWorld(char * filename, EntityManager * eManager, Entity * player
case ENTITY_DRAGON: case ENTITY_DRAGON:
fwrite(&eManager->entities[i][j].dragon.health, sizeof(s16), 1, file); fwrite(&eManager->entities[i][j].dragon.health, sizeof(s16), 1, file);
break; break;
case ENTITY_NPC:
fwrite(&eManager->entities[i][j].npc.type, sizeof(u8), 1, file);
break;
} }
} }
} }
@ -120,6 +113,25 @@ void saveCurrentWorld(char * filename, EntityManager * eManager, Entity * player
fwrite(minimapData, sizeof(u8), 128*128, file); // Minimap, visibility data 16KB fwrite(minimapData, sizeof(u8), 128*128, file); // Minimap, visibility data 16KB
//Quest Data
fwrite(&questManager.size, sizeof(int), 1, file);
for(i = 0; i < questManager.size; ++i) {
fwrite(&(questManager.questlines[i].currentQuest), sizeof(int), 1, file);
fwrite(&(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);
fclose(file); fclose(file);
} }
@ -335,6 +347,16 @@ int loadWorld(char * filename, EntityManager * eManager, Entity * player, u8 * m
eManager->entities[i][j].yr = 8; eManager->entities[i][j].yr = 8;
eManager->entities[i][j].canPass = true; eManager->entities[i][j].canPass = true;
break; 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;
} }
} }
} }
@ -348,6 +370,40 @@ int loadWorld(char * filename, EntityManager * eManager, Entity * player, u8 * m
fread(minimapData, sizeof(u8), 128*128, 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);
fclose(file); fclose(file);
return 0; return 0;
} }

View file

@ -13,6 +13,10 @@
#include "Menu.h" #include "Menu.h"
#include "texturepack.h" #include "texturepack.h"
// TODO: Dungeon is way to difficult
// -> Skeleton arrows are slower, do a little less damage
// -> Or instead of less damage, implement a simple armor system
void initMiniMapData() { void initMiniMapData() {
int i; int i;
for(i = 0; i < 128 * 128; ++i) { for(i = 0; i < 128 * 128; ++i) {
@ -29,11 +33,11 @@ void initMiniMap(bool loadUpWorld) {
void initNewMap() { void initNewMap() {
newSeed(); newSeed();
createAndValidateSkyMap(128, 128, map[0], data[0]); createAndValidateSkyMap(128, 128, 0, map[0], data[0]);
createAndValidateTopMap(128, 128, map[1], data[1]); createAndValidateTopMap(128, 128, 1, map[1], data[1]);
createAndValidateUndergroundMap(128, 128, 1, map[2], data[2]); createAndValidateUndergroundMap(128, 128, 1, 2, map[2], data[2]);
createAndValidateUndergroundMap(128, 128, 2, map[3], data[3]); createAndValidateUndergroundMap(128, 128, 2, 3, map[3], data[3]);
createAndValidateUndergroundMap(128, 128, 3, map[4], data[4]); createAndValidateUndergroundMap(128, 128, 3, 4, map[4], data[4]);
} }
void setupGame(bool loadUpWorld) { void setupGame(bool loadUpWorld) {
@ -48,6 +52,7 @@ void setupGame(bool loadUpWorld) {
if (!loadUpWorld) { if (!loadUpWorld) {
initNewMap(); initNewMap();
initPlayer(); initPlayer();
resetQuests();
airWizardHealthDisplay = 2000; airWizardHealthDisplay = 2000;
int i; int i;
for (i = 0; i < 5; ++i) { for (i = 0; i < 5; ++i) {
@ -55,8 +60,12 @@ void setupGame(bool loadUpWorld) {
} }
addEntityToList(newAirWizardEntity(630, 820, 0), &eManager); addEntityToList(newAirWizardEntity(630, 820, 0), &eManager);
daytime = 6000; daytime = 6000;
day = 0;
season = 0;
rain = false;
} else { } else {
initPlayer(); initPlayer();
resetQuests();
loadWorld(currentFileName, &eManager, &player, (u8*) map, (u8*) data); loadWorld(currentFileName, &eManager, &player, (u8*) map, (u8*) data);
} }
@ -78,7 +87,7 @@ void setupBGMap(bool loadUpWorld) {
if(!loadUpWorld) { if(!loadUpWorld) {
newSeed(); newSeed();
createAndValidateTopMap(128, 128, map[1], data[1]); createAndValidateTopMap(128, 128, 1, map[1], data[1]);
} else { } else {
loadWorld(currentFileName, &eManager, &player, (u8*) map, (u8*) data); loadWorld(currentFileName, &eManager, &player, (u8*) map, (u8*) data);
} }
@ -113,6 +122,14 @@ void tick() {
//daytime += 20; //daytime += 20;
if(daytime>=24000) { if(daytime>=24000) {
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) { if(daytime==6000 && currentLevel==1) {
playMusic(music_floor1); playMusic(music_floor1);
@ -138,25 +155,20 @@ void tick() {
else if (yscr > 1912) else if (yscr > 1912)
yscr = 1912; yscr = 1912;
if(eManager.lastSlot[currentLevel]<80) { if(eManager.lastSlot[currentLevel]<80 && currentLevel != 5) {
trySpawn(1, currentLevel); trySpawn(1, currentLevel);
} }
for (i = 0; i < eManager.lastSlot[currentLevel]; ++i) { for (i = 0; i < eManager.lastSlot[currentLevel]; ++i) {
Entity * e = &eManager.entities[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))) 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)) || (e->x > player.x - 160 && e->y > player.y - 125 && e->x < player.x + 160 && e->y < player.y + 125))
tickEntity(e); tickEntity(e);
} }
} }
void clearScreen(int* data, u8 fill, int size) {
int i;
for (i = 0; i < size / 4; ++i)
data[i] = 0xFF000000;
}
char debugText[34]; char debugText[34];
char bossHealthText[34]; char bossHealthText[34];
int main() { int main() {
@ -243,6 +255,7 @@ int main() {
tickCount = 0; tickCount = 0;
initRecipes(); initRecipes();
initQuests();
while (aptMainLoop()) { while (aptMainLoop()) {
++tickCount; ++tickCount;
hidScanInput(); hidScanInput();
@ -266,6 +279,7 @@ int main() {
renderBackground(xscr, yscr); renderBackground(xscr, yscr);
renderEntities(player.x, player.y, &eManager); renderEntities(player.x, player.y, &eManager);
renderPlayer(); renderPlayer();
renderWeather(xscr, yscr);
resetStencilStuff(); resetStencilStuff();
@ -299,6 +313,7 @@ int main() {
stopMusic(); stopMusic();
freeQuests();
freeRecipes(); freeRecipes();
freeLightBakes(); freeLightBakes();