diff --git a/README.md b/README.md index afde096..94eec7b 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ sfillib by xerpi: https://github.com/xerpi/sfillib zlib: http://www.zlib.net/ -Current Version: Version 1.1 +Current Version: Version 1.2 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. diff --git a/data/icons2.png b/data/icons2.png index 74311be..34f7d40 100644 Binary files a/data/icons2.png and b/data/icons2.png differ diff --git a/resources/music/floor1_night.raw b/resources/music/floor1_night.raw new file mode 100644 index 0000000..1474c1b Binary files /dev/null and b/resources/music/floor1_night.raw differ diff --git a/source/Crafting.c b/source/Crafting.c index 98d1cbb..75603cf 100644 --- a/source/Crafting.c +++ b/source/Crafting.c @@ -79,7 +79,7 @@ Recipe defineRecipe(int item, int amountOrLevel, int numArgs, ...){ void initRecipes(){ curPlace = 0; - workbenchRecipes.size = 16; + workbenchRecipes.size = 22; workbenchRecipes.recipes = (Recipe*)malloc(sizeof(Recipe) * (workbenchRecipes.size)); workbenchRecipes.recipes[0] = defineRecipe(ITEM_WORKBENCH,1,1,ITEM_WOOD,20); workbenchRecipes.recipes[1] = defineRecipe(ITEM_FURNACE,1,1,ITEM_STONE,20); @@ -87,16 +87,22 @@ void initRecipes(){ workbenchRecipes.recipes[3] = defineRecipe(ITEM_CHEST,1,1,ITEM_WOOD,20); workbenchRecipes.recipes[4] = defineRecipe(ITEM_ANVIL,1,1,ITEM_IRONINGOT,5); workbenchRecipes.recipes[5] = defineRecipe(ITEM_LANTERN,1,3,ITEM_WOOD,5,ITEM_SLIME,10,ITEM_GLASS,4); - workbenchRecipes.recipes[6] = defineRecipe(TOOL_SWORD,0,1,ITEM_WOOD,5); - workbenchRecipes.recipes[7] = defineRecipe(TOOL_AXE,0,1,ITEM_WOOD,5); - workbenchRecipes.recipes[8] = defineRecipe(TOOL_HOE,0,1,ITEM_WOOD,5); - workbenchRecipes.recipes[9] = defineRecipe(TOOL_PICKAXE,0,1,ITEM_WOOD,5); - workbenchRecipes.recipes[10] = defineRecipe(TOOL_SHOVEL,0,1,ITEM_WOOD,5); - workbenchRecipes.recipes[11] = defineRecipe(TOOL_SWORD,1,2,ITEM_WOOD,5,ITEM_STONE,5); - workbenchRecipes.recipes[12] = defineRecipe(TOOL_AXE,1,2,ITEM_WOOD,5,ITEM_STONE,5); - workbenchRecipes.recipes[13] = defineRecipe(TOOL_HOE,1,2,ITEM_WOOD,5,ITEM_STONE,5); - workbenchRecipes.recipes[14] = defineRecipe(TOOL_PICKAXE,1,2,ITEM_WOOD,5,ITEM_STONE,5); - workbenchRecipes.recipes[15] = defineRecipe(TOOL_SHOVEL,1,2,ITEM_WOOD,5,ITEM_STONE,5); + workbenchRecipes.recipes[6] = defineRecipe(ITEM_LOOM,1,2,ITEM_WOOD,10,ITEM_WOOL,5); + workbenchRecipes.recipes[7] = defineRecipe(TOOL_SWORD,0,1,ITEM_WOOD,5); + workbenchRecipes.recipes[8] = defineRecipe(TOOL_AXE,0,1,ITEM_WOOD,5); + workbenchRecipes.recipes[9] = defineRecipe(TOOL_HOE,0,1,ITEM_WOOD,5); + workbenchRecipes.recipes[10] = defineRecipe(TOOL_PICKAXE,0,1,ITEM_WOOD,5); + workbenchRecipes.recipes[11] = defineRecipe(TOOL_SHOVEL,0,1,ITEM_WOOD,5); + workbenchRecipes.recipes[12] = defineRecipe(TOOL_BOW,0,2,ITEM_WOOD,10,ITEM_STRING,1); + workbenchRecipes.recipes[13] = defineRecipe(ITEM_ARROW_WOOD,1,2,ITEM_WOOD,2,ITEM_STRING,1); + workbenchRecipes.recipes[14] = defineRecipe(TOOL_SWORD,1,2,ITEM_WOOD,5,ITEM_STONE,5); + workbenchRecipes.recipes[15] = defineRecipe(TOOL_AXE,1,2,ITEM_WOOD,5,ITEM_STONE,5); + workbenchRecipes.recipes[16] = defineRecipe(TOOL_HOE,1,2,ITEM_WOOD,5,ITEM_STONE,5); + workbenchRecipes.recipes[17] = defineRecipe(TOOL_PICKAXE,1,2,ITEM_WOOD,5,ITEM_STONE,5); + workbenchRecipes.recipes[18] = defineRecipe(TOOL_SHOVEL,1,2,ITEM_WOOD,5,ITEM_STONE,5); + workbenchRecipes.recipes[19] = defineRecipe(ITEM_ARROW_STONE,1,3,ITEM_WOOD,1,ITEM_STONE,1,ITEM_STRING,1); + workbenchRecipes.recipes[20] = defineRecipe(ITEM_WALL_WOOD,1,1,ITEM_WOOD,4); + workbenchRecipes.recipes[21] = defineRecipe(ITEM_WALL_STONE,1,1,ITEM_STONE,4); anvilRecipes.size = 16; anvilRecipes.recipes = (Recipe*)malloc(sizeof(Recipe) * (anvilRecipes.size)); @@ -105,17 +111,17 @@ void initRecipes(){ anvilRecipes.recipes[2] = defineRecipe(TOOL_HOE,2,2,ITEM_WOOD,5,ITEM_IRONINGOT,5); anvilRecipes.recipes[3] = defineRecipe(TOOL_PICKAXE,2,2,ITEM_WOOD,5,ITEM_IRONINGOT,5); anvilRecipes.recipes[4] = defineRecipe(TOOL_SHOVEL,2,2,ITEM_WOOD,5,ITEM_IRONINGOT,5); - anvilRecipes.recipes[5] = defineRecipe(TOOL_SWORD,3,2,ITEM_WOOD,5,ITEM_GOLDINGOT,5); - anvilRecipes.recipes[6] = defineRecipe(TOOL_AXE,3,2,ITEM_WOOD,5,ITEM_GOLDINGOT,5); - anvilRecipes.recipes[7] = defineRecipe(TOOL_HOE,3,2,ITEM_WOOD,5,ITEM_GOLDINGOT,5); - anvilRecipes.recipes[8] = defineRecipe(TOOL_PICKAXE,3,2,ITEM_WOOD,5,ITEM_GOLDINGOT,5); - anvilRecipes.recipes[9] = defineRecipe(TOOL_SHOVEL,3,2,ITEM_WOOD,5,ITEM_GOLDINGOT,5); - anvilRecipes.recipes[10] = defineRecipe(TOOL_SWORD,4,2,ITEM_WOOD,5,ITEM_GEM,50); - anvilRecipes.recipes[11] = defineRecipe(TOOL_AXE,4,2,ITEM_WOOD,5,ITEM_GEM,50); - anvilRecipes.recipes[12] = defineRecipe(TOOL_HOE,4,2,ITEM_WOOD,5,ITEM_GEM,50); - anvilRecipes.recipes[13] = defineRecipe(TOOL_PICKAXE,4,2,ITEM_WOOD,5,ITEM_GEM,50); - anvilRecipes.recipes[14] = defineRecipe(TOOL_SHOVEL,4,2,ITEM_WOOD,5,ITEM_GEM,50); - anvilRecipes.recipes[15] = defineRecipe(TOOL_BUCKET,0,1,ITEM_IRONINGOT,10); + anvilRecipes.recipes[5] = defineRecipe(ITEM_ARROW_IRON,1,3,ITEM_WOOD,1,ITEM_IRONINGOT,1,ITEM_STRING,1); + anvilRecipes.recipes[6] = defineRecipe(TOOL_SWORD,3,2,ITEM_WOOD,5,ITEM_GOLDINGOT,5); + anvilRecipes.recipes[7] = defineRecipe(TOOL_AXE,3,2,ITEM_WOOD,5,ITEM_GOLDINGOT,5); + anvilRecipes.recipes[8] = defineRecipe(TOOL_HOE,3,2,ITEM_WOOD,5,ITEM_GOLDINGOT,5); + anvilRecipes.recipes[9] = defineRecipe(TOOL_PICKAXE,3,2,ITEM_WOOD,5,ITEM_GOLDINGOT,5); + anvilRecipes.recipes[10] = defineRecipe(TOOL_SHOVEL,3,2,ITEM_WOOD,5,ITEM_GOLDINGOT,5); + anvilRecipes.recipes[11] = defineRecipe(ITEM_ARROW_GOLD,1,3,ITEM_WOOD,1,ITEM_GOLDINGOT,1,ITEM_STRING,1); + anvilRecipes.recipes[12] = defineRecipe(TOOL_BUCKET,0,1,ITEM_IRONINGOT,10); + 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[15] = defineRecipe(ITEM_WALL_GOLD,1,1,ITEM_GOLDINGOT,2); furnaceRecipes.size = 3; furnaceRecipes.recipes = (Recipe*)malloc(sizeof(Recipe) * (furnaceRecipes.size)); @@ -123,9 +129,27 @@ void initRecipes(){ furnaceRecipes.recipes[1] = defineRecipe(ITEM_GOLDINGOT,1,2,ITEM_GOLDORE,4,ITEM_COAL,1); furnaceRecipes.recipes[2] = defineRecipe(ITEM_GLASS,1,2,ITEM_SAND,4,ITEM_COAL,1); - ovenRecipes.size = 1; + ovenRecipes.size = 3; ovenRecipes.recipes = (Recipe*)malloc(sizeof(Recipe) * (ovenRecipes.size)); ovenRecipes.recipes[0] = defineRecipe(ITEM_BREAD,1,1,ITEM_WHEAT,4); + ovenRecipes.recipes[1] = defineRecipe(ITEM_PORK_COOKED,1,2,ITEM_PORK_RAW,1,ITEM_COAL,1); + ovenRecipes.recipes[2] = defineRecipe(ITEM_BEEF_COOKED,1,2,ITEM_BEEF_RAW,1,ITEM_COAL,1); + + loomRecipes.size = 1; + loomRecipes.recipes = (Recipe*)malloc(sizeof(Recipe) * (loomRecipes.size)); + loomRecipes.recipes[0] = defineRecipe(ITEM_STRING,1,1,ITEM_WOOL,1); + + enchanterRecipes.size = 8; + enchanterRecipes.recipes = (Recipe*)malloc(sizeof(Recipe) * (enchanterRecipes.size)); + 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[2] = defineRecipe(TOOL_HOE,4,2,ITEM_WOOD,5,ITEM_GEM,50); + enchanterRecipes.recipes[3] = defineRecipe(TOOL_PICKAXE,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[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); + } /* Free up allocated memory */ @@ -134,4 +158,6 @@ void freeRecipes(){ free(ovenRecipes.recipes); free(furnaceRecipes.recipes); free(anvilRecipes.recipes); + free(loomRecipes.recipes); + free(enchanterRecipes.recipes); } diff --git a/source/Crafting.h b/source/Crafting.h index 77dd677..b608d9b 100644 --- a/source/Crafting.h +++ b/source/Crafting.h @@ -26,6 +26,8 @@ RecipeManager workbenchRecipes; RecipeManager furnaceRecipes; RecipeManager ovenRecipes; RecipeManager anvilRecipes; +RecipeManager loomRecipes; +RecipeManager enchanterRecipes; void checkCanCraftRecipes(RecipeManager * rm, Inventory * inv); void sortRecipes(RecipeManager * rm); diff --git a/source/Entity.c b/source/Entity.c index 57c4503..815ca7b 100644 --- a/source/Entity.c +++ b/source/Entity.c @@ -65,6 +65,25 @@ Entity newFurnitureEntity(int itemID,Inventory * invPtr, int x, int y, int level return e; } +Entity newPassiveEntity(int type, int x, int y, int level){ + Entity e; + e.type = ENTITY_PASSIVE; + e.level = level; + e.x = x; + e.y = y; + e.hurtTime = 0; + e.xKnockback = 0; + e.yKnockback = 0; + e.passive.mtype = type; + e.passive.health = 20; + e.passive.dir = 0; + e.passive.xa = 0; + e.passive.ya = 0; + e.xr = 4; + e.yr = 3; + e.canPass = false; + return e; +} Entity newZombieEntity(int lvl, int x, int y, int level){ Entity e; @@ -75,17 +94,72 @@ Entity newZombieEntity(int lvl, int x, int y, int level){ e.hurtTime = 0; e.xKnockback = 0; e.yKnockback = 0; - e.zombie.lvl = lvl; - e.zombie.health = lvl * lvl * 10; - e.zombie.dir = 0; + e.hostile.lvl = lvl; + e.hostile.xa = 0; + e.hostile.ya = 0; + e.hostile.health = lvl * lvl * 10; + e.hostile.dir = 0; + e.xr = 4; + e.yr = 3; + e.canPass = false; + switch(lvl){ + case 2: e.hostile.color = 0xFF8282CC; break; + case 3: e.hostile.color = 0xFFEFEFEF; break; + case 4: e.hostile.color = 0xFFAA6262; break; + default: e.hostile.color = 0xFF95DB95; break; + } + return e; +} + +Entity newSkeletonEntity(int lvl, int x, int y, int level){ + Entity e; + e.type = ENTITY_SKELETON; + e.level = level; + e.x = x; + e.y = y; + e.hurtTime = 0; + e.xKnockback = 0; + e.yKnockback = 0; + e.hostile.lvl = lvl; + e.hostile.xa = 0; + e.hostile.ya = 0; + e.hostile.health = lvl * lvl * 10; + e.hostile.dir = 0; + e.hostile.randAttackTime = 0; e.xr = 4; e.yr = 3; e.canPass = false; switch(lvl){ - case 2: e.zombie.color = 0xFF8282CC; break; - case 3: e.zombie.color = 0xFFEFEFEF; break; - case 4: e.zombie.color = 0xFFAA6262; break; - default: e.zombie.color = 0xFF95DB95; break; + case 2: e.hostile.color = 0xFFC4C4C4; break; + case 3: e.hostile.color = 0xFFA0A0A0; break; + case 4: e.hostile.color = 0xFF7A7A7A; break; + default: e.hostile.color = 0xFFFFFFFF; break; + } + return e; +} + +Entity newKnightEntity(int lvl, int x, int y, int level){ + Entity e; + e.type = ENTITY_KNIGHT; + e.level = level; + e.x = x; + e.y = y; + e.hurtTime = 0; + e.xKnockback = 0; + e.yKnockback = 0; + e.hostile.lvl = lvl; + e.hostile.xa = 0; + e.hostile.ya = 0; + e.hostile.health = lvl * lvl * 20; + e.hostile.dir = 0; + e.xr = 4; + e.yr = 3; + e.canPass = false; + switch(lvl){ + case 2: e.hostile.color = 0xFF0000C6; break; + case 3: e.hostile.color = 0xFF00A3C6; break; + case 4: e.hostile.color = 0xFF707070; break; + default: e.hostile.color = 0xFFFFFFFF; break; } return e; } @@ -141,6 +215,7 @@ Entity newAirWizardEntity(int x, int y, int level){ Entity newSparkEntity(Entity* parent, float xa, float ya){ Entity e; e.type = ENTITY_SPARK; + e.level = parent->level; e.spark.age = 0; e.spark.parent = parent; e.spark.xa = xa; @@ -185,13 +260,44 @@ Entity newSmashParticleEntity(int x, int y, int level){ return e; } +Entity newArrowEntity(Entity* parent, int itemID, s8 xa, s8 ya, int level){ + Entity e; + e.type = ENTITY_ARROW; + e.level = level; + e.arrow.age = 0; + e.arrow.parent = parent; + e.arrow.itemID = itemID; + e.arrow.xa = xa; + e.arrow.ya = ya; + e.x = parent->x; + e.y = parent->y; + e.xr = 2; + e.yr = 2; + e.canPass = false; + e.canSwim = true; + return e; +} + +Entity newGlowwormEntity(int x, int y, int level){ + Entity e; + e.type = ENTITY_GLOWWORM; + e.level = level; + e.glowworm.xa = 0; + e.glowworm.ya = 0; + e.glowworm.randWalkTime = 0; + e.glowworm.waitTime = 0; + e.x = x; + e.y = y; + e.canPass = true; + return e; +} + void addEntityToList(Entity e, EntityManager* em){ e.slotNum = em->lastSlot[e.level]; em->entities[e.level][em->lastSlot[e.level]] = e; ++em->lastSlot[e.level]; } -Entity nullEntity; void removeEntityFromList(Entity * e,int level,EntityManager* em){ int i; if(em->entities[level][e->slotNum].type == ENTITY_TEXTPARTICLE) free(em->entities[level][e->slotNum].textParticle.text); diff --git a/source/Entity.h b/source/Entity.h index c812ea0..4a14d66 100644 --- a/source/Entity.h +++ b/source/Entity.h @@ -13,6 +13,11 @@ #define ENTITY_TEXTPARTICLE 7 #define ENTITY_SMASHPARTICLE 8 #define ENTITY_PLAYER 9 +#define ENTITY_PASSIVE 10 +#define ENTITY_ARROW 11 +#define ENTITY_SKELETON 12 +#define ENTITY_KNIGHT 13 +#define ENTITY_GLOWWORM 14 typedef struct Entity Entity; @@ -59,6 +64,16 @@ typedef struct { s16 oSel; // other selection inside the chest inv. } EntityFurniture; +typedef struct { + u8 mtype; + s8 xa; + s8 ya; + s16 health; + s8 dir; + s8 randWalkTime; + s8 walkDist; +} PassiveMob; + typedef struct { s8 xa; s8 ya; @@ -67,8 +82,9 @@ typedef struct { s8 lvl; s8 randWalkTime; s8 walkDist; + s8 randAttackTime; u32 color; -} Zombie; +} HostileMob; typedef struct { s8 xa; @@ -93,6 +109,14 @@ typedef struct { s8 spriteAdjust; } AirWizard; +typedef struct { + Entity* parent; + s16 age; + s16 itemID; + s8 xa; + s8 ya; +} Arrow; + typedef struct { Entity* parent; s16 age; @@ -102,6 +126,13 @@ typedef struct { float yy; } Spark; +typedef struct { + s8 xa; + s8 ya; + s8 randWalkTime; + s8 waitTime; +} Glowworm; + typedef struct { float xa; float ya; @@ -133,36 +164,45 @@ struct Entity { Player p; EntityItem entityItem; EntityFurniture entityFurniture; - Zombie zombie; + PassiveMob passive; + HostileMob hostile; Slime slime; AirWizard wizard; Spark spark; + Arrow arrow; + Glowworm glowworm; TextParticleEntity textParticle; SmashParticleEntity smashParticle; }; }; typedef struct { - Entity entities[5][1000]; + Entity entities[6][1000]; Entity wizardSparks[120]; - s16 lastSlot[5]; + s16 lastSlot[6]; Inventory invs[301];//1 for the player, 300 for chests. s16 nextInv; } EntityManager; EntityManager eManager; +Entity nullEntity; s8 currentLevel; double gaussrand(); Entity newItemEntity(Item item, 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 newZombieEntity(int lvl, int x, int y, int level); +Entity newSkeletonEntity(int lvl, int x, int y, int level); +Entity newKnightEntity(int lvl, int x, int y, int level); Entity newSlimeEntity(int lvl, int x, int y, int level); Entity newAirWizardEntity(int x, int y, int level); Entity newSparkEntity(Entity* parent, float xa, float ya); Entity newTextParticleEntity(char * str, u32 color, 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 newGlowwormEntity(int x, int y, int level); void addEntityToList(Entity e, EntityManager* em); void removeEntityFromList(Entity * e,int level,EntityManager* em); diff --git a/source/Globals.c b/source/Globals.c index c949190..53c42f8 100644 --- a/source/Globals.c +++ b/source/Globals.c @@ -1,6 +1,6 @@ #include "Globals.h" -char versionText[34] = "Version 1.1"; +char versionText[34] = "Version 1.2"; char fpsstr[34]; u8 currentMenu = 0; @@ -238,10 +238,19 @@ void hurtEntity(Entity* e, int damage, int dir, u32 hurtColor){ } break; case ENTITY_ZOMBIE: - e->zombie.health -= damage; - if(e->zombie.health < 1){ - addItemsToWorld(newItem(ITEM_FLESH,1),e->x+8, e->y+8, (rand()%2) + 1); - player.p.score += 50 * (e->zombie.lvl + 1); + case ENTITY_SKELETON: + case ENTITY_KNIGHT: + e->hostile.health -= damage; + if(e->hostile.health < 1){ + if(e->type == ENTITY_ZOMBIE) { + addItemsToWorld(newItem(ITEM_FLESH,1),e->x+8, e->y+8, (rand()%2) + 1); + } else if(e->type == ENTITY_SKELETON) { + addItemsToWorld(newItem(ITEM_BONE,1),e->x+8, e->y+8, (rand()%2) + 1); + if(rand()%2==0) addItemsToWorld(newItem(ITEM_ARROW_STONE,1),e->x+8, e->y+8, 1); + } else if(e->type == ENTITY_KNIGHT) { + addItemsToWorld(newItem(ITEM_IRONINGOT,1),e->x+8, e->y+8, (rand()%2) + 1); + } + player.p.score += 50 * (e->hostile.lvl + 1); removeEntityFromList(e,e->level,&eManager); trySpawn(3, currentLevel); return; @@ -261,15 +270,35 @@ void hurtEntity(Entity* e, int damage, int dir, u32 hurtColor){ e->wizard.health -= damage; airWizardHealthDisplay = e->wizard.health; if(e->wizard.health < 1){ + addItemsToWorld(newItem(ITEM_DUNGEON_KEY,1),e->x+8, e->y+8, (rand()%2) + 1); removeEntityFromList(e,e->level,&eManager); playSound(snd_bossdeath); player.p.score += 1000; - player.p.endTimer = 60; - player.p.hasWon = true; + if(!player.p.hasWonSaved) player.p.endTimer = 60; + if(!player.p.hasWonSaved) player.p.hasWon = true; player.p.hasWonSaved = true; return; } break; + case ENTITY_PASSIVE: + e->passive.health -= damage; + if(e->passive.health < 1){ + if(e->passive.mtype==0) { + addItemsToWorld(newItem(ITEM_WOOL,1),e->x+8, e->y+8, (rand()%3) + 1); + } else if(e->passive.mtype==1) { + addItemsToWorld(newItem(ITEM_PORK_RAW,1),e->x+8, e->y+8, (rand()%2) + 1); + } else if(e->passive.mtype==2) { + addItemsToWorld(newItem(ITEM_BEEF_RAW,1),e->x+8, e->y+8, (rand()%2) + 1); + if((rand()%2)==0) { + addItemsToWorld(newItem(ITEM_LEATHER,1),e->x+8, e->y+8, 1); + } + } + player.p.score += 10; + removeEntityFromList(e,e->level,&eManager); + trySpawn(3, currentLevel); + return; + } + break; } switch(dir){ @@ -284,7 +313,9 @@ void hurtEntity(Entity* e, int damage, int dir, u32 hurtColor){ } break; case ENTITY_ZOMBIE: - switch(e->zombie.dir){ + case ENTITY_SKELETON: + case ENTITY_KNIGHT: + switch(e->hostile.dir){ case 0: e->yKnockback = -10; break; case 1: e->yKnockback = +10; break; case 2: e->xKnockback = +10; break; @@ -298,6 +329,14 @@ void hurtEntity(Entity* e, int damage, int dir, u32 hurtColor){ case 2: e->xKnockback = +10; break; case 3: e->xKnockback = -10; break; } + break; + case ENTITY_PASSIVE: + switch(e->passive.dir){ + case 0: e->yKnockback = -10; break; + case 1: e->yKnockback = +10; break; + case 2: e->xKnockback = +10; break; + case 3: e->xKnockback = -10; break; + } break; } break; @@ -323,7 +362,10 @@ bool ItemVsEntity(Item* item, Entity* e, int dir){ } break; case TOOL_AXE: switch(e->type){ + case ENTITY_PASSIVE: case ENTITY_ZOMBIE: + case ENTITY_SKELETON: + case ENTITY_KNIGHT: case ENTITY_SLIME: case ENTITY_AIRWIZARD: if(playerUseEnergy(4-item->countLevel)) hurtEntity(e,(item->countLevel + 1) * 2 + (rand()%4),dir,0xFF0000FF); @@ -332,7 +374,10 @@ bool ItemVsEntity(Item* item, Entity* e, int dir){ } break; case TOOL_SWORD: switch(e->type){ + case ENTITY_PASSIVE: case ENTITY_ZOMBIE: + case ENTITY_SKELETON: + case ENTITY_KNIGHT: case ENTITY_SLIME: case ENTITY_AIRWIZARD: if(playerUseEnergy(4-item->countLevel)) hurtEntity(e,(item->countLevel+1)*3+(rand()%(2+item->countLevel*item->countLevel*2)),dir,0xFF0000FF); @@ -341,7 +386,10 @@ bool ItemVsEntity(Item* item, Entity* e, int dir){ } break; case ITEM_NULL: switch(e->type){ + case ENTITY_PASSIVE: case ENTITY_ZOMBIE: + case ENTITY_SKELETON: + case ENTITY_KNIGHT: case ENTITY_SLIME: case ENTITY_AIRWIZARD: hurtEntity(e,1+rand()%3,dir,0xFF0000FF); @@ -351,6 +399,63 @@ bool ItemVsEntity(Item* item, Entity* e, int dir){ return false; } +bool playerUseItem() { + if(player.p.activeItem->id == TOOL_BOW) { + int aitemID = 0; + Item * aitem; + + Item * item = getItemFromInventory(ITEM_ARROW_WOOD, player.p.inv); + if(item!=NULL) { + aitemID = ITEM_ARROW_WOOD; + aitem = item; + } + item = getItemFromInventory(ITEM_ARROW_STONE, player.p.inv); + if(item!=NULL) { + aitemID = ITEM_ARROW_STONE; + aitem = item; + } + item = getItemFromInventory(ITEM_ARROW_IRON, player.p.inv); + if(item!=NULL) { + aitemID = ITEM_ARROW_IRON; + aitem = item; + } + item = getItemFromInventory(ITEM_ARROW_GOLD, player.p.inv); + if(item!=NULL) { + aitemID = ITEM_ARROW_GOLD; + aitem = item; + } + item = getItemFromInventory(ITEM_ARROW_GEM, player.p.inv); + if(item!=NULL) { + aitemID = ITEM_ARROW_GEM; + aitem = item; + } + + if(aitemID!=0) { + --aitem->countLevel; + if (isItemEmpty(aitem)) { + removeItemFromInventory(aitem->slotNum, player.p.inv); + } + + switch(player.p.dir) { + case 0: + addEntityToList(newArrowEntity(&player, aitemID, 0, 2, currentLevel), &eManager); + break; + case 1: + addEntityToList(newArrowEntity(&player, aitemID, 0, -2, currentLevel), &eManager); + break; + case 2: + addEntityToList(newArrowEntity(&player, aitemID, -2, 0, currentLevel), &eManager); + break; + case 3: + addEntityToList(newArrowEntity(&player, aitemID, 2, 0, currentLevel), &eManager); + break; + } + return true; + } + } + return false; +} + bool interact(int x0, int y0, int x1, int y1) { Entity * es[eManager.lastSlot[currentLevel]]; int eSize = getEntities(es, x0, y0, x1, y1); @@ -365,12 +470,17 @@ bool interact(int x0, int y0, int x1, int y1) { } void EntityVsEntity(Entity* e1, Entity* e2){ + int damage = 1; switch(e1->type){ case ENTITY_PLAYER: playerEntityInteract(e2); break; case ENTITY_ZOMBIE: + case ENTITY_SKELETON: + case ENTITY_KNIGHT: if(e2->type == ENTITY_PLAYER){ - hurtEntity(e2, 2, e1->zombie.dir, 0xFFAF00FF); - switch(e1->zombie.dir){ + if(e1->type == ENTITY_ZOMBIE) hurtEntity(e2, 2, e1->hostile.dir, 0xFFAF00FF); + else if(e1->type == ENTITY_SKELETON) hurtEntity(e2, 1, e1->hostile.dir, 0xFFAF00FF); + else if(e1->type == ENTITY_KNIGHT) hurtEntity(e2, 3, e1->hostile.dir, 0xFFAF00FF); + switch(e1->hostile.dir){ case 0: e1->yKnockback = -4; break; case 1: e1->yKnockback = +4; break; case 2: e1->xKnockback = +4; break; @@ -395,6 +505,37 @@ void EntityVsEntity(Entity* e1, Entity* e2){ case ENTITY_SPARK: if(e2 != e1->spark.parent) hurtEntity(e2, 1, -1, 0xFFAF00FF); break; + case ENTITY_ARROW: + switch(e1->arrow.itemID) { + case ITEM_ARROW_WOOD: + damage = 1 + (rand()%3); + break; + case ITEM_ARROW_STONE: + damage = 2 + (rand()%5); + break; + case ITEM_ARROW_IRON: + damage = 8 + (rand()%9); + break; + case ITEM_ARROW_GOLD: + damage = 16 + (rand()%17); + break; + case ITEM_ARROW_GEM: + damage = 24 + (rand()%17); + break; + } + + if(e1->arrow.parent->type == ENTITY_PLAYER) { + if(e2->type != ENTITY_PLAYER) { + hurtEntity(e2, damage, -1, 0xFF0000FF); + removeEntityFromList(e1, e1->level, &eManager); + } + } else { + if(e2->type == ENTITY_PLAYER) { + hurtEntity(e2, damage, -1, 0xFFAF00FF); + removeEntityFromList(e1, e1->level, &eManager); + } + } + break; } } @@ -405,9 +546,12 @@ bool EntityBlocksEntity(Entity* e1, Entity* e2){ switch(e2->type){ case ENTITY_FURNITURE: case ENTITY_ZOMBIE: + case ENTITY_SKELETON: + case ENTITY_KNIGHT: case ENTITY_SLIME: case ENTITY_AIRWIZARD: case ENTITY_PLAYER: + case ENTITY_PASSIVE: return true; break; } @@ -426,14 +570,20 @@ bool tileIsSolid(int tile, Entity * e){ case TILE_GOLDORE: case TILE_GEMORE: case TILE_CLOUDCACTUS: - case TILE_LAVA: case TILE_WOOD_WALL: - case 255: + case TILE_STONE_WALL: + case TILE_IRON_WALL: + case TILE_GOLD_WALL: + case TILE_GEM_WALL: + case TILE_DUNGEON_WALL: return true; + case TILE_LAVA: + case 255: + if(e->type != ENTITY_ARROW) return true; case TILE_WATER: - if(e != NULL && !e->canSwim) return true; + if(e != NULL && !e->canSwim && e->type != ENTITY_ARROW) return true; case TILE_HOLE: - if(e != NULL && e->type != ENTITY_PLAYER) return true; + if(e != NULL && e->type != ENTITY_PLAYER && e->type != ENTITY_ARROW) return true; } return false; } @@ -441,25 +591,32 @@ bool tileIsSolid(int tile, Entity * e){ /* For minimap */ u32 getTileColor(int tile){ switch(tile){ - case TILE_WATER: return 0x0000FFFF; - case TILE_LAVA: return 0xFF0000FF; + case TILE_WATER: return SWAP_UINT32(waterColor[0]); + case TILE_LAVA: return SWAP_UINT32(lavaColor[0]); case TILE_DIRT: return 0x826D6CFF; - case TILE_ROCK: return 0x7F7F7FFF; - case TILE_HARDROCK: return 0x5F5F7FFF; - case TILE_GRASS: return 0x00FF00FF; + case TILE_ROCK: return SWAP_UINT32(rockColor[1]); + case TILE_HARDROCK: return SWAP_UINT32(rockColor[3]); + case TILE_GRASS: return SWAP_UINT32(grassColor); case TILE_TREE: return 0x007F00FF; - case TILE_SAND: return 0xFFFF00FF; + case TILE_SAND: return SWAP_UINT32(sandColor); case TILE_CACTUS: return 0x009F00FF; - case TILE_FLOWER: return 0x3FFF00FF; - case TILE_IRONORE: return 0xDC9696FF; - case TILE_GOLDORE: return 0xE5E89AFF; - case TILE_GEMORE: return 0xDF98DEFF; + case TILE_FLOWER: return SWAP_UINT32(grassColor); + case TILE_IRONORE: return SWAP_UINT32(ironColor); + case TILE_GOLDORE: return SWAP_UINT32(goldColor); + case TILE_GEMORE: return SWAP_UINT32(gemColor); case TILE_CLOUD: return 0xFFFFFFFF; case TILE_CLOUDCACTUS: return 0xAFAFAFFF; case TILE_STAIRS_DOWN: return 0x9F9F9FFF; case TILE_STAIRS_UP: return 0x9F9F9FFF; case TILE_HOLE: return 0x383838FF; - case TILE_WOOD_WALL: return 0xC1A55EFF; + case TILE_WOOD_WALL: return SWAP_UINT32(woodColor); + case TILE_STONE_WALL: return SWAP_UINT32(rockColor[1]); + case TILE_IRON_WALL: return SWAP_UINT32(ironColor); + case TILE_GOLD_WALL: return SWAP_UINT32(goldColor); + case TILE_GEM_WALL: return SWAP_UINT32(gemColor); + case TILE_DUNGEON_WALL: return SWAP_UINT32(dungeonColor[0]); + case TILE_DUNGEON_FLOOR: return SWAP_UINT32(dungeonColor[1]); + default: return 0x111111FF; } } @@ -475,7 +632,7 @@ void healPlayer(int amount){ s8 itemTileInteract(int tile, Item* item, int x, int y, int px, int py, int dir){ // Furniture items - if(item->id > 27 && item->id < 34){ + if(item->id > 27 && item->id < 51){ if(!tileIsSolid(getTile(x,y), NULL)){ addEntityToList(newFurnitureEntity(item->id,item->chestPtr, (x<<4)+8, (y<<4)+8, currentLevel), &eManager); removeItemFromCurrentInv(item); @@ -491,32 +648,53 @@ s8 itemTileInteract(int tile, Item* item, int x, int y, int px, int py, int dir) if(player.p.health < 10 && playerUseEnergy(2)){ healPlayer(1); --item->countLevel; - if(item->countLevel < 1){ - removeItemFromCurrentInv(item); - player.p.activeItem = &noItem; - } } return 0; case ITEM_FLESH: if(player.p.health < 10 && playerUseEnergy(4+(rand()%4))){ healPlayer(1); --item->countLevel; - if(item->countLevel < 1){ - removeItemFromCurrentInv(item); - player.p.activeItem = &noItem; - } } return 0; case ITEM_BREAD: if(player.p.health < 10 && playerUseEnergy(3)){ healPlayer(2); --item->countLevel; - if(item->countLevel < 1){ - removeItemFromCurrentInv(item); - player.p.activeItem = &noItem; - } } return 0; + case ITEM_PORK_RAW: + if(player.p.health < 10 && playerUseEnergy(4+(rand()%4))){ + healPlayer(1); + --item->countLevel; + } + return 0; + case ITEM_PORK_COOKED: + if(player.p.health < 10 && playerUseEnergy(3)){ + healPlayer(3); + --item->countLevel; + } + return 0; + case ITEM_BEEF_RAW: + if(player.p.health < 10 && playerUseEnergy(4+(rand()%4))){ + healPlayer(1); + --item->countLevel; + } + return 0; + case ITEM_BEEF_COOKED: + if(player.p.health < 10 && playerUseEnergy(3)){ + healPlayer(4); + --item->countLevel; + } + return 0; + //special item + case ITEM_WIZARD_SUMMON: + if(currentLevel==0) { + --item->countLevel; + + airWizardHealthDisplay = 2000; + addEntityToList(newAirWizardEntity(630, 820, 0), &eManager); + } + return 0; } switch(tile){ @@ -569,9 +747,25 @@ s8 itemTileInteract(int tile, Item* item, int x, int y, int px, int py, int dir) setData(rand()%4,x,y); // determines mirroring. return 1; } - else if(item->id == ITEM_WOOD){ + else if(item->id == ITEM_WALL_WOOD){ setTile(TILE_WOOD_WALL,x,y); --item->countLevel; return 1; + } + else if(item->id == ITEM_WALL_STONE){ + setTile(TILE_STONE_WALL,x,y); --item->countLevel; + return 1; + } + else if(item->id == ITEM_WALL_IRON){ + setTile(TILE_IRON_WALL,x,y); --item->countLevel; + return 1; + } + else if(item->id == ITEM_WALL_GOLD){ + setTile(TILE_GOLD_WALL,x,y); --item->countLevel; + return 1; + } + else if(item->id == ITEM_WALL_GEM){ + setTile(TILE_GEM_WALL,x,y); --item->countLevel; + return 1; } 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); @@ -590,13 +784,29 @@ s8 itemTileInteract(int tile, Item* item, int x, int y, int px, int py, int dir) return 1; } break; case TILE_DIRT: - if(item->id == TOOL_HOE && playerUseEnergy(4-item->countLevel)){ + if(item->id == TOOL_HOE && currentLevel==1 && playerUseEnergy(4-item->countLevel)){ setTile(TILE_FARM,x,y); return 1; - } - else if(item->id == ITEM_WOOD){ + } + else if(item->id == ITEM_WALL_WOOD){ setTile(TILE_WOOD_WALL,x,y); --item->countLevel; return 1; + } + else if(item->id == ITEM_WALL_STONE){ + setTile(TILE_STONE_WALL,x,y); --item->countLevel; + return 1; + } + else if(item->id == ITEM_WALL_IRON){ + setTile(TILE_IRON_WALL,x,y); --item->countLevel; + return 1; + } + else if(item->id == ITEM_WALL_GOLD){ + setTile(TILE_GOLD_WALL,x,y); --item->countLevel; + return 1; + } + else if(item->id == ITEM_WALL_GEM){ + setTile(TILE_GEM_WALL,x,y); --item->countLevel; + return 1; } else if(item->id == ITEM_SAND){ setTile(TILE_SAND,x,y); --item->countLevel; @@ -673,6 +883,26 @@ 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); return 1; } break; + case TILE_STONE_WALL: + if(item->id == TOOL_PICKAXE && playerUseEnergy(4-item->countLevel)){ + playerHurtTile(tile, x, y, (rand()%10) + (item->countLevel) * 5 + 10, player.p.dir); + return 1; + } break; + case TILE_IRON_WALL: + if(item->id == TOOL_PICKAXE && playerUseEnergy(4-item->countLevel)){ + playerHurtTile(tile, x, y, (rand()%10) + (item->countLevel) * 5 + 10, player.p.dir); + return 1; + } break; + case TILE_GOLD_WALL: + if(item->id == TOOL_PICKAXE && playerUseEnergy(4-item->countLevel)){ + playerHurtTile(tile, x, y, (rand()%10) + (item->countLevel) * 5 + 10, player.p.dir); + return 1; + } break; + case TILE_GEM_WALL: + if(item->id == TOOL_PICKAXE && playerUseEnergy(4-item->countLevel)){ + playerHurtTile(tile, x, y, (rand()%10) + (item->countLevel) * 5 + 10, player.p.dir); + return 1; + } break; } return 0; } @@ -685,6 +915,17 @@ void tickTile(int x, int y){ case TILE_SAPLING_TREE: setData(++data,x,y); if(data>100){setData(0,x,y); setTile(TILE_TREE,x,y);} break; + case TILE_TREE: + if(eManager.lastSlot[currentLevel]<800 && (daytime>18000 || daytime<5000) && rand()%800==0) { + //check for nearby glowworms + int i = 0; + for (i = 0; i < eManager.lastSlot[currentLevel]; ++i) { + Entity * e = &eManager.entities[currentLevel][i]; + if(e->type==ENTITY_GLOWWORM && ((e->x)-(x<<4))*((e->x)-(x<<4))+((e->y)-(y<<4))*((e->y)-(y<<4)) < (2<<4)*(2<<4)) return; + } + addEntityToList(newGlowwormEntity((x<<4)+8,(y<<4)+8,currentLevel), &eManager); + } + break; case TILE_SAPLING_CACTUS: setData(++data,x,y); if(data>100){setData(0,x,y); setTile(TILE_CACTUS,x,y);} break; @@ -705,7 +946,6 @@ void tickTile(int x, int y){ if(getTile(x+1,y)==TILE_WATER || getTile(x-1,y)==TILE_WATER || getTile(x,y+1)==TILE_WATER || getTile(x,y-1)==TILE_WATER) { setTile(TILE_ROCK,x,y); - setData(0,x,y); } break; case TILE_HOLE: // This makes water flow slightly faster than lava @@ -723,6 +963,9 @@ void tickTile(int x, int y){ case TILE_SAND: if(data > 0) setData(--data,x,y); break; + case TILE_CLOUD: + if((rand()%24000)==0) setTile(TILE_CLOUDCACTUS,x,y); + break; } } @@ -786,34 +1029,65 @@ void tickEntity(Entity* e){ case ENTITY_ITEM: tickEntityItem(e); return; case ENTITY_FURNITURE: return; case ENTITY_ZOMBIE: + case ENTITY_SKELETON: + case ENTITY_KNIGHT: if (e->hurtTime > 0) e->hurtTime--; - if (e->zombie.randWalkTime == 0) { + if (e->hostile.randWalkTime == 0 && e->type != ENTITY_SKELETON) { int xd = player.x - e->x; int yd = player.y - e->y; - if (xd * xd + yd * yd < 50 * 50) { - e->zombie.xa = 0; - e->zombie.ya = 0; - if (xd < 0) e->zombie.xa = -1; - if (xd > 0) e->zombie.xa = +1; - if (yd < 0) e->zombie.ya = -1; - if (yd > 0) e->zombie.ya = +1; + int dist = 50 * 50; + if(e->type == ENTITY_KNIGHT) dist = 80 * 80; + + //charge player + if (xd * xd + yd * yd < dist) { + e->hostile.xa = 0; + e->hostile.ya = 0; + if (xd < 0) e->hostile.xa = -1; + if (xd > 0) e->hostile.xa = +1; + if (yd < 0) e->hostile.ya = -1; + if (yd > 0) e->hostile.ya = +1; } } - if(e->zombie.xa < 0) e->zombie.dir = 2; - else if(e->zombie.xa > 0) e->zombie.dir = 3; - if(e->zombie.ya < 0) e->zombie.dir = 1; - else if(e->zombie.ya > 0) e->zombie.dir = 0; + if(e->hostile.xa < 0) e->hostile.dir = 2; + else if(e->hostile.xa > 0) e->hostile.dir = 3; + if(e->hostile.ya < 0) e->hostile.dir = 1; + else if(e->hostile.ya > 0) e->hostile.dir = 0; - if(e->zombie.xa != 0 || e->zombie.ya != 0) e->zombie.walkDist++; + if(e->type == ENTITY_SKELETON) { + --(e->hostile.randAttackTime); + if(e->hostile.randAttackTime <= 0) { + e->hostile.randAttackTime = 70 - (e->hostile.lvl * 10); + + int aitemID = ITEM_ARROW_WOOD; + if(e->hostile.lvl >= 2) aitemID = ITEM_ARROW_STONE; + + switch(e->hostile.dir) { + case 0: + addEntityToList(newArrowEntity(e, aitemID, 0, 2, e->level), &eManager); + break; + case 1: + addEntityToList(newArrowEntity(e, aitemID, 0, -2, e->level), &eManager); + break; + case 2: + addEntityToList(newArrowEntity(e, aitemID, -2, 0, e->level), &eManager); + break; + case 3: + addEntityToList(newArrowEntity(e, aitemID, 2, 0, e->level), &eManager); + break; + } + } + } + + if(e->hostile.xa != 0 || e->hostile.ya != 0) e->hostile.walkDist++; int speed = tickCount & 1; - if (!moveMob(e, e->zombie.xa * speed, e->zombie.ya * speed) || (rand()%100) == 0) { - e->zombie.randWalkTime = 60; - e->zombie.xa = ((rand()%3) - 1) * (rand()%2); - e->zombie.ya = ((rand()%3) - 1) * (rand()%2); + if (!moveMob(e, e->hostile.xa * speed, e->hostile.ya * speed) || (rand()%100) == 0) { + e->hostile.randWalkTime = 60; + e->hostile.xa = ((rand()%3) - 1) * (rand()%2); + e->hostile.ya = ((rand()%3) - 1) * (rand()%2); } - if (e->zombie.randWalkTime > 0) e->zombie.randWalkTime--; + if (e->hostile.randWalkTime > 0) e->hostile.randWalkTime--; return; case ENTITY_SLIME: if (e->hurtTime > 0) e->hurtTime--; @@ -939,6 +1213,74 @@ void tickEntity(Entity* e){ removeEntityFromList(e,e->level,&eManager); } return; + case ENTITY_ARROW: + e->arrow.age++; + if (e->arrow.age >= 260 || !move(e, e->arrow.xa, e->arrow.ya)) { + removeEntityFromList(e,e->level,&eManager); + return; + } + return; + case ENTITY_PASSIVE: + if (e->hurtTime > 0) e->hurtTime--; + if (e->passive.randWalkTime == 0) { + int xd = player.x - e->x; + int yd = player.y - e->y; + //flee from player + if (xd * xd + yd * yd < 40 * 40) { + e->passive.xa = 0; + e->passive.ya = 0; + if (xd < 0) e->passive.xa = +1; + if (xd > 0) e->passive.xa = -1; + if (yd < 0) e->passive.ya = +1; + if (yd > 0) e->passive.ya = -1; + } + } + + if(e->passive.xa < 0) e->passive.dir = 2; + else if(e->passive.xa > 0) e->passive.dir = 3; + if(e->passive.ya < 0) e->passive.dir = 1; + else if(e->passive.ya > 0) e->passive.dir = 0; + + if(e->passive.xa != 0 || e->passive.ya != 0) e->passive.walkDist++; + + int pspeed = tickCount & 1; + if (!moveMob(e, e->passive.xa * pspeed, e->passive.ya * pspeed) || (rand()%100) == 0) { + e->passive.randWalkTime = 60; + e->passive.xa = ((rand()%3) - 1) * (rand()%2); + e->passive.ya = ((rand()%3) - 1) * (rand()%2); + } + if (e->passive.randWalkTime > 0) e->passive.randWalkTime--; + return; + case ENTITY_GLOWWORM: + if(daytime>5000 && daytime<6000) { + if(rand()%200==0) removeEntityFromList(e,e->level,&eManager); + } else if(daytime>6000 && daytime<18000) { + removeEntityFromList(e,e->level,&eManager); + } + + int gspeed = (((tickCount & 0x3) == 3) ? 1 : 0); + if (!moveMob(e, e->glowworm.xa * gspeed, e->glowworm.ya * gspeed) || (e->glowworm.randWalkTime==0) || (rand()%20) == 0) { + if(e->glowworm.randWalkTime != 0) { + e->glowworm.waitTime = 20 + (rand()%60); + } + if(e->glowworm.waitTime == 0 || getTile((e->x)>>4,(e->y)>>4)!=TILE_TREE) { + e->glowworm.randWalkTime = 20; + e->glowworm.xa = ((rand()%3) - 1) * (rand()%2); + e->glowworm.ya = ((rand()%3) - 1) * (rand()%2); + } else { + e->glowworm.xa = 0; + e->glowworm.ya = 0; + } + } + if (e->glowworm.randWalkTime > 0) { + e->glowworm.randWalkTime--; + if(e->glowworm.randWalkTime==0 && (e->glowworm.xa != 0 || e->glowworm.xa != 0)) { + e->glowworm.waitTime = 120 + (rand()%60); + } + } else if (e->glowworm.waitTime > 0) { + e->glowworm.waitTime--; + } + return; case ENTITY_TEXTPARTICLE: tickEntityTextParticle(e); return; case ENTITY_SMASHPARTICLE: ++e->smashParticle.age; @@ -959,6 +1301,9 @@ void trySpawn(int count, int level) { else if (level == 0) { minLevel = maxLevel = 4; } + if(level > 4) { + minLevel = maxLevel = 4; + } int rx = rand()%128; int ry = rand()%128; @@ -968,9 +1313,30 @@ void trySpawn(int count, int level) { if(level == currentLevel && (ex > player.x-160 && ey > player.y-125 && ex < player.x+160 && ey < player.y+125)) continue; if (!tileIsSolid(map[level][rx+ry*128],&e)) { - int lvl = (rand()%(maxLevel - minLevel + 1)) + minLevel; - if ((rand()%2) == 0) e = newSlimeEntity(lvl, ex, ey, level); - else e = newZombieEntity(lvl, ex, ey, level); + if(level==1 && (rand()%2)==0) { //passive entities on overworld + e = newPassiveEntity(rand()%3, ex, ey, level); + } else { + int lvl = (rand()%(maxLevel - minLevel + 1)) + minLevel; + int randMax = 1; + + if(level>1 || level==0) randMax = 2; + if(level>3) randMax = 3; + + switch (rand()%(randMax+1)) { + case 0: + e = newSlimeEntity(lvl, ex, ey, level); + break; + case 1: + e = newZombieEntity(lvl, ex, ey, level); + break; + case 2: + e = newSkeletonEntity(lvl, ex, ey, level); + break; + case 3: + e = newKnightEntity(lvl, ex, ey, level); + break; + } + } addEntityToList(e, &eManager); } } @@ -984,6 +1350,7 @@ int getTile(int x, int y){ void setTile(int id, int x, int y){ if(x < 0 || y < 0 || x > 128 || y > 128) return; map[currentLevel][x+y*128] = id; + data[currentLevel][x+y*128] = 0; //reset data(set again if needed, hopefully this breaks nothing) sf2d_set_pixel(minimap[currentLevel], x, y, getTileColor(id)); } int getData(int x, int y){ @@ -1108,7 +1475,8 @@ void playerHurtTile(int tile, int xt, int yt, int damage, int dir){ if(getData(xt,yt) > 0){ int count = rand() & 1; if (getData(xt,yt) >= (rand()%10) + 3) { - setTile(TILE_DIRT,xt,yt); + if(currentLevel!=5) setTile(TILE_DIRT,xt,yt); + else setTile(TILE_DUNGEON_FLOOR,xt,yt); count += 2; } addItemsToWorld(newItem(ITEM_IRONORE,1),(xt<<4)+8,(yt<<4)+8,count); @@ -1122,7 +1490,8 @@ void playerHurtTile(int tile, int xt, int yt, int damage, int dir){ if(getData(xt,yt) > 0){ int count = rand() & 1; if (getData(xt,yt) >= (rand()%10) + 3) { - setTile(TILE_DIRT,xt,yt); + if(currentLevel!=5) setTile(TILE_DIRT,xt,yt); + else setTile(TILE_DUNGEON_FLOOR,xt,yt); count += 2; } addItemsToWorld(newItem(ITEM_GOLDORE,1),(xt<<4)+8,(yt<<4)+8,count); @@ -1136,7 +1505,8 @@ void playerHurtTile(int tile, int xt, int yt, int damage, int dir){ if(getData(xt,yt) > 0){ int count = rand() & 1; if (getData(xt,yt) >= (rand()%10) + 3) { - setTile(TILE_DIRT,xt,yt); + if(currentLevel!=5) setTile(TILE_DIRT,xt,yt); + else setTile(TILE_DUNGEON_FLOOR,xt,yt); count += 2; } addItemsToWorld(newItem(ITEM_GEM,1),(xt<<4)+8,(yt<<4)+8,count); @@ -1187,9 +1557,49 @@ void playerHurtTile(int tile, int xt, int yt, int damage, int dir){ setData(getData(xt,yt)+damage,xt,yt); if(getData(xt,yt) > 20){ setTile(TILE_DIRT,xt,yt); - addItemsToWorld(newItem(ITEM_WOOD,1),(xt<<4)+8,(yt<<4)+8,1); + addItemsToWorld(newItem(ITEM_WALL_WOOD,1),(xt<<4)+8,(yt<<4)+8,1); } - break; + break; + case TILE_STONE_WALL: + sprintf(hurtText, "%d", damage); + addEntityToList(newTextParticleEntity(hurtText,0xFF0000FF,xt<<4,yt<<4,currentLevel), &eManager); + addEntityToList(newSmashParticleEntity(xt<<4,yt<<4,currentLevel), &eManager); + setData(getData(xt,yt)+damage,xt,yt); + if(getData(xt,yt) > 30){ + setTile(TILE_DIRT,xt,yt); + addItemsToWorld(newItem(ITEM_WALL_STONE,1),(xt<<4)+8,(yt<<4)+8,1); + } + break; + case TILE_IRON_WALL: + sprintf(hurtText, "%d", damage); + addEntityToList(newTextParticleEntity(hurtText,0xFF0000FF,xt<<4,yt<<4,currentLevel), &eManager); + addEntityToList(newSmashParticleEntity(xt<<4,yt<<4,currentLevel), &eManager); + setData(getData(xt,yt)+damage,xt,yt); + if(getData(xt,yt) > 40){ + setTile(TILE_DIRT,xt,yt); + addItemsToWorld(newItem(ITEM_WALL_IRON,1),(xt<<4)+8,(yt<<4)+8,1); + } + break; + case TILE_GOLD_WALL: + sprintf(hurtText, "%d", damage); + addEntityToList(newTextParticleEntity(hurtText,0xFF0000FF,xt<<4,yt<<4,currentLevel), &eManager); + addEntityToList(newSmashParticleEntity(xt<<4,yt<<4,currentLevel), &eManager); + setData(getData(xt,yt)+damage,xt,yt); + if(getData(xt,yt) > 50){ + setTile(TILE_DIRT,xt,yt); + addItemsToWorld(newItem(ITEM_WALL_GOLD,1),(xt<<4)+8,(yt<<4)+8,1); + } + break; + case TILE_GEM_WALL: + sprintf(hurtText, "%d", damage); + addEntityToList(newTextParticleEntity(hurtText,0xFF0000FF,xt<<4,yt<<4,currentLevel), &eManager); + addEntityToList(newSmashParticleEntity(xt<<4,yt<<4,currentLevel), &eManager); + setData(getData(xt,yt)+damage,xt,yt); + if(getData(xt,yt) > 60){ + setTile(TILE_DIRT,xt,yt); + addItemsToWorld(newItem(ITEM_WALL_GEM,1),(xt<<4)+8,(yt<<4)+8,1); + } + break; } } @@ -1205,6 +1615,8 @@ void playerAttack(){ player.p.attackTimer = 5; int yo = -2; int range = 12; + + if(playerUseItem()) return; switch(player.p.dir){ case 0: if(interact(player.x - 8, player.y + 4 + yo, player.x + 8, player.y + range + yo)) return; break; @@ -1259,7 +1671,7 @@ void switchLevel(s8 change){ else if(currentLevel > 1) sf2d_set_clear_color(0xFF666666); //sf2d_set_clear_color(RGBA8(0x66, 0x66, 0x66, 0xFF)); else sf2d_set_clear_color(0xFF007F00); //sf2d_set_clear_color(RGBA8(0x00, 0x7F, 0x00, 0xFF)); - updateMusic(currentLevel); + updateMusic(currentLevel, daytime); } bool playerIntersectsEntity(Entity* e){ @@ -1297,14 +1709,14 @@ void entityTileInteract(Entity*e, int tile, int x, int y){ player.x = (x << 4) + 8; player.y = (y << 4) + 8; } - return; + return; case TILE_STAIRS_UP: if(e->type == ENTITY_PLAYER){ switchLevel(-1); player.x = (x << 4) + 8; player.y = (y << 4) + 8; } - return; + return; case TILE_CACTUS: if(e->type == ENTITY_PLAYER)hurtEntity(e,1,-1,0xFFAF00FF); return; case TILE_LAVA: if(e->type == ENTITY_PLAYER)hurtEntity(e,1,-1,0xFFAF00FF); return; case TILE_WHEAT: @@ -1321,15 +1733,22 @@ void entityTileInteract(Entity*e, int tile, int x, int y){ setTile(TILE_DIRT,x,y); } } - return; + return; case TILE_FARM: if(e->type == ENTITY_PLAYER || e->type == ENTITY_ZOMBIE){ if(rand()%20 == 0)setTile(TILE_DIRT,x,y); } - return; + return; case TILE_SAND: - setData(10,x,y); - return; + if(e->type != ENTITY_ARROW && e->type != ENTITY_ITEM) { + setData(10,x,y); + } + return; + case TILE_DUNGEON_ENTRANCE: + if(e->type == ENTITY_PLAYER) { + currentMenu = MENU_DUNGEON; + } + return; } } @@ -1382,6 +1801,18 @@ bool useEntity(Entity* e) { curChestEntity->entityFurniture.r = 0; curChestEntity->entityFurniture.oSel = 0; currentMenu = MENU_CONTAINER; + return true; + case ITEM_LOOM: + currentRecipes = &loomRecipes; + currentMenu = MENU_CRAFTING; + checkCanCraftRecipes(currentRecipes, player.p.inv); + sortRecipes(currentRecipes); + return true; + case ITEM_ENCHANTER: + currentRecipes = &enchanterRecipes; + currentMenu = MENU_CRAFTING; + checkCanCraftRecipes(currentRecipes, player.p.inv); + sortRecipes(currentRecipes); return true; } } @@ -1477,7 +1908,7 @@ void tickPlayer(){ } if (k_menu.clicked){ - curInvSel = 0; + curInvSel = 0; if(!playerUse()) currentMenu = MENU_INVENTORY; } @@ -1491,10 +1922,95 @@ bool isSwimming(){ void playerSetActiveItem(Item * item) { player.p.activeItem = item; - if(player.p.activeItem->id > 27 && player.p.activeItem->id < 34) player.p.isCarrying = true; + if(player.p.activeItem->id > 27 && player.p.activeItem->id < 51) player.p.isCarrying = true; else player.p.isCarrying = false; } +void enterDungeon() { + currentLevel = 5; + createDungeonMap(128, 128, map[5], data[5]); + initMinimapLevel(5, false); + newSeed(); + //reset Entities + (&eManager)->lastSlot[5] = 0; + (&eManager)->entities[5][0] = nullEntity; + trySpawn(500, 5); + + player.x = ((128/2) << 4) + 8; + player.y = ((128/2) << 4) + 8; + + updateMusic(currentLevel, daytime); +} + +void leaveDungeon() { + currentLevel = 4; + + //reset Entities + (&eManager)->lastSlot[5] = 0; + (&eManager)->entities[5][0] = nullEntity; + + player.x = ((128/2) << 4) + 8; + player.y = ((128/2) << 4) + 8; + + updateMusic(currentLevel, daytime); +} + +void initMinimapLevel(int level, bool loadUpWorld) { + int x; + int y; + + //Create Dungeon entrance(not located in mapgen, so it can also be created in old worlds) + if(level==4) { + map[level][64 + 64 * 128] = TILE_DUNGEON_ENTRANCE; + + map[level][63 + 64 * 128] = TILE_DIRT; + map[level][65 + 64 * 128] = TILE_DIRT; + map[level][64 + 63 * 128] = TILE_DIRT; + map[level][64 + 65 * 128] = TILE_DIRT; + + map[level][63 + 63 * 128] = TILE_DUNGEON_WALL; + map[level][63 + 65 * 128] = TILE_DUNGEON_WALL; + map[level][65 + 63 * 128] = TILE_DUNGEON_WALL; + map[level][65 + 65 * 128] = TILE_DUNGEON_WALL; + } + + for (x = 0; x < 128; ++x) { + for (y = 0; y < 128; ++y) { + + if (!loadUpWorld) { // generate stairs up when making a new world. + switch (map[level][x + y * 128]) { + case TILE_STAIRS_DOWN: + if(level < 4) { + map[level + 1][x + y * 128] = TILE_STAIRS_UP; + if (level == 0) { + map[level + 1][(x + 1) + y * 128] = TILE_HARDROCK; + map[level + 1][x + (y + 1) * 128] = TILE_HARDROCK; + map[level + 1][(x - 1) + y * 128] = TILE_HARDROCK; + map[level + 1][x + (y - 1) * 128] = TILE_HARDROCK; + map[level + 1][(x + 1) + (y + 1) * 128] = TILE_HARDROCK; + map[level + 1][(x - 1) + (y - 1) * 128] = TILE_HARDROCK; + map[level + 1][(x - 1) + (y + 1) * 128] = TILE_HARDROCK; + map[level + 1][(x + 1) + (y - 1) * 128] = TILE_HARDROCK; + } else { + map[level + 1][(x + 1) + y * 128] = TILE_DIRT; + map[level + 1][x + (y + 1) * 128] = TILE_DIRT; + map[level + 1][(x - 1) + y * 128] = TILE_DIRT; + map[level + 1][x + (y - 1) * 128] = TILE_DIRT; + map[level + 1][(x + 1) + (y + 1) * 128] = TILE_DIRT; + map[level + 1][(x - 1) + (y - 1) * 128] = TILE_DIRT; + map[level + 1][(x - 1) + (y + 1) * 128] = TILE_DIRT; + map[level + 1][(x + 1) + (y - 1) * 128] = TILE_DIRT; + } + } + } + } + + /* Minimaps */ + sf2d_set_pixel(minimap[level], x, y, getTileColor(map[level][x + y * 128])); + } + } +} + void reloadColors() { dirtColor[0] = SWAP_UINT32(sf2d_get_pixel(icons, 16, 0)); dirtColor[1] = SWAP_UINT32(sf2d_get_pixel(icons, 16, 1)); @@ -1517,5 +2033,12 @@ void reloadColors() { rockColor[2] = SWAP_UINT32(sf2d_get_pixel(icons, 21, 2)); rockColor[3] = SWAP_UINT32(sf2d_get_pixel(icons, 21, 3)); - woodColor = SWAP_UINT32(sf2d_get_pixel(icons, 22, 0)); + woodColor = SWAP_UINT32(sf2d_get_pixel(icons, 22, 0)); + + ironColor = SWAP_UINT32(sf2d_get_pixel(icons, 23, 0)); + goldColor = SWAP_UINT32(sf2d_get_pixel(icons, 23, 1)); + gemColor = SWAP_UINT32(sf2d_get_pixel(icons, 23, 2)); + + dungeonColor[0] = SWAP_UINT32(sf2d_get_pixel(icons, 24, 0)); + dungeonColor[1] = SWAP_UINT32(sf2d_get_pixel(icons, 24, 1)); } \ No newline at end of file diff --git a/source/Globals.h b/source/Globals.h index ba4a0f8..fd23ba2 100644 --- a/source/Globals.h +++ b/source/Globals.h @@ -2,6 +2,7 @@ #include <3ds.h> #include "SaveLoad.h" #include "Input.h" +#include "MapGen.h" #include "icons2_png.h" #include "Font_png.h" @@ -24,6 +25,7 @@ #define MENU_LOADGAME 11 #define MENU_SETTINGS_REBIND 12 #define MENU_SETTINGS_TP 13 +#define MENU_DUNGEON 14 #define TILE_NULL 255 #define TILE_GRASS 0 @@ -48,7 +50,15 @@ #define TILE_HARDROCK 19 #define TILE_CLOUDCACTUS 20 #define TILE_HOLE 21 + #define TILE_WOOD_WALL 22 +#define TILE_STONE_WALL 23 +#define TILE_IRON_WALL 24 +#define TILE_GOLD_WALL 25 +#define TILE_GEM_WALL 26 +#define TILE_DUNGEON_WALL 27 +#define TILE_DUNGEON_FLOOR 28 +#define TILE_DUNGEON_ENTRANCE 29 #define SWAP_UINT32(x) (((x) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | ((x) << 24)) @@ -71,9 +81,9 @@ s16 mScrollX, mScrollY; sf2d_texture *icons; sf2d_texture *font; sf2d_texture *bottombg; -sf2d_texture * minimap[5]; -u8 map[5][128*128]; -u8 data[5][128*128]; +sf2d_texture * minimap[6]; +u8 map[6][128*128]; +u8 data[6][128*128]; u32 dirtColor[5]; u32 grassColor; @@ -82,6 +92,10 @@ u32 waterColor[2]; u32 lavaColor[2]; u32 rockColor[4]; u32 woodColor; +u32 ironColor; +u32 goldColor; +u32 gemColor; +u32 dungeonColor[2]; char currentFileName[256]; extern u8 currentMenu; @@ -97,6 +111,8 @@ s16 curInvSel; bool quitGame; s8 currentSelection; +u16 daytime; + void tickTile(int x, int y); bool tileIsSolid(int tile, Entity * e); @@ -131,4 +147,9 @@ bool playerIntersectsEntity(Entity* e); void playerEntityInteract(Entity* e); void playerSetActiveItem(Item * item); +void enterDungeon(); +void leaveDungeon(); + +void initMinimapLevel(int level, bool loadUpWorld); + void reloadColors(); \ No newline at end of file diff --git a/source/Item.c b/source/Item.c index ca47720..89e0591 100644 --- a/source/Item.c +++ b/source/Item.c @@ -59,7 +59,7 @@ Item newItem(int id, int cLevel){ if(id != ITEM_NULL){ if(cLevel > 999) cLevel = 999; item.countLevel = cLevel; - if(id < 7 || id > 27 || id > 100) item.onlyOne = true; // Tools + Furniture. + if(id < 7 || (id > 27 && id < 51) || id > 100) item.onlyOne = true; // Tools + Furniture. else item.onlyOne = false; } item.chestPtr = NULL; @@ -158,12 +158,36 @@ char* getItemName(int itemID, int countLevel){ case ITEM_GLASS: sprintf(currentName,"%d Glass", countLevel); return currentName; case ITEM_GEM: sprintf(currentName,"%d Gem", countLevel); return currentName; case ITEM_SLIME: sprintf(currentName,"%d Slime", countLevel); return currentName; + + case ITEM_LOOM: return "Loom"; + case ITEM_ENCHANTER: return "Enchanter"; + case ITEM_WALL_WOOD: sprintf(currentName,"%d Wood Wall", countLevel); return currentName; + case ITEM_WALL_STONE: sprintf(currentName,"%d Stone Wall", countLevel); return currentName; + case ITEM_WALL_IRON: sprintf(currentName,"%d Iron Wall", countLevel); return currentName; + case ITEM_WALL_GOLD: sprintf(currentName,"%d Gold Wall", countLevel); return currentName; + case ITEM_WALL_GEM: sprintf(currentName,"%d Gem Wall", countLevel); return currentName; + case ITEM_WOOL: sprintf(currentName,"%d Wool", countLevel); return currentName; + case ITEM_STRING: sprintf(currentName,"%d String", countLevel); return currentName; + case ITEM_PORK_RAW: sprintf(currentName,"%d Raw Pork", countLevel); return currentName; + case ITEM_PORK_COOKED: sprintf(currentName,"%d Cooked Pork", countLevel); return currentName; + case ITEM_BEEF_RAW: sprintf(currentName,"%d Raw Beef", countLevel); return currentName; + case ITEM_BEEF_COOKED: sprintf(currentName,"%d Steak", countLevel); return currentName; + case ITEM_LEATHER: sprintf(currentName,"%d Leather", countLevel); return currentName; + case ITEM_ARROW_WOOD: sprintf(currentName,"%d Wood Arrow", countLevel); return currentName; + case ITEM_ARROW_STONE: sprintf(currentName,"%d Rock Arrow", countLevel); return currentName; + case ITEM_ARROW_IRON: sprintf(currentName,"%d Iron Arrow", countLevel); return currentName; + case ITEM_ARROW_GOLD: sprintf(currentName,"%d Gold Arrow", countLevel); return currentName; + case ITEM_ARROW_GEM: sprintf(currentName,"%d Gem Arrow", countLevel); return currentName; + case ITEM_BONE: sprintf(currentName,"%d Bone", countLevel); return currentName; + case ITEM_DUNGEON_KEY: sprintf(currentName,"%d Dungeon Key", countLevel); return currentName; + case ITEM_WIZARD_SUMMON: sprintf(currentName,"%d Wizard Summon", countLevel); return currentName; case TOOL_BUCKET: switch(countLevel){ case 1: return "Water Bucket"; case 2: return "Lava Bucket"; default: return "Empty Bucket"; } + case TOOL_BOW: return "Bow"; default: return ""; // null } } @@ -238,12 +262,36 @@ char* getBasicItemName(int itemID, int countLevel){ case ITEM_GLASS: return "Glass"; case ITEM_GEM: return "Gem"; case ITEM_SLIME: return "Slime"; + + case ITEM_LOOM: return "Loom"; + case ITEM_ENCHANTER: return "Enchanter"; + case ITEM_WALL_WOOD: return "Wood Wall"; + case ITEM_WALL_STONE: return "Stone Wall"; + case ITEM_WALL_IRON: return "Iron Wall"; + case ITEM_WALL_GOLD: return "Gold Wall"; + case ITEM_WALL_GEM: return "Gem Wall"; + case ITEM_WOOL: return "Wool"; + case ITEM_STRING: return "String"; + case ITEM_PORK_RAW: return "Raw Pork"; + case ITEM_PORK_COOKED: return "Cooked Pork"; + case ITEM_BEEF_RAW: return "Raw Beef"; + case ITEM_BEEF_COOKED: return "Steak"; + case ITEM_LEATHER: return "Leather"; + case ITEM_ARROW_WOOD: return "Wood Arrow"; + case ITEM_ARROW_STONE: return "Rock Arrow"; + case ITEM_ARROW_IRON: return "Iron Arrow"; + case ITEM_ARROW_GOLD: return "Gold Arrow"; + case ITEM_ARROW_GEM: return "Gem Arrow"; + case ITEM_BONE: return "Bone"; + case ITEM_DUNGEON_KEY: return "Dungeon Key"; + case ITEM_WIZARD_SUMMON: return "Wizard Summon"; case TOOL_BUCKET: switch(countLevel){ case 1: return "Water Bucket"; case 2: return "Lava Bucket"; default: return "Empty Bucket"; } + case TOOL_BOW: return "Bow"; default: return ""; // null } diff --git a/source/Item.h b/source/Item.h index 6e806e7..74314e9 100644 --- a/source/Item.h +++ b/source/Item.h @@ -42,7 +42,33 @@ #define ITEM_FURNACE 31 #define ITEM_WORKBENCH 32 #define ITEM_LANTERN 33 + +#define ITEM_LOOM 34 +#define ITEM_ENCHANTER 35 + +#define ITEM_WALL_WOOD 51 +#define ITEM_WALL_STONE 52 +#define ITEM_WALL_IRON 53 +#define ITEM_WALL_GOLD 54 +#define ITEM_WALL_GEM 55 +#define ITEM_WOOL 56 +#define ITEM_STRING 57 +#define ITEM_PORK_RAW 58 +#define ITEM_PORK_COOKED 59 +#define ITEM_BEEF_RAW 60 +#define ITEM_BEEF_COOKED 61 +#define ITEM_LEATHER 62 +#define ITEM_ARROW_WOOD 63 +#define ITEM_ARROW_STONE 64 +#define ITEM_ARROW_IRON 65 +#define ITEM_ARROW_GOLD 66 +#define ITEM_ARROW_GEM 67 +#define ITEM_BONE 68 +#define ITEM_DUNGEON_KEY 69 +#define ITEM_WIZARD_SUMMON 70 + #define TOOL_BUCKET 101 +#define TOOL_BOW 102 typedef struct Inventory Inventory; diff --git a/source/MapGen.c b/source/MapGen.c index f354420..12ffacb 100644 --- a/source/MapGen.c +++ b/source/MapGen.c @@ -100,6 +100,21 @@ void createAndValidateUndergroundMap(int w, int h,int depthLevel, u8 * map, u8 * return; } while (true); } + +void createAndValidateDungeonMap(int w, int h, u8 * map, u8 * data) { + do { + createDungeonMap(w, h, map, data); + + int count[256]={[0 ... 255] = 0}; + int i = 0; + for (i = 0; i < w * h; ++i)count[map[i] & 0xff]++; + if (count[TILE_DUNGEON_WALL & 0xff] < 100) continue; + if (count[TILE_DUNGEON_FLOOR & 0xff] < 100) continue; + + return; + } while (true); +} + void createAndValidateSkyMap(int w, int h, u8 * map, u8 * data) { do { createSkyMap(w, h, map, data); @@ -341,63 +356,207 @@ void createUndergroundMap(int w, int h,int depthLevel, u8 * map, u8 * data) { free(noise2); } - void createSkyMap(int w, int h, u8 * map, u8 * data) { - double* noise1 = Noise(w, h, 8); - double* noise2 = Noise(w, h, 8); - int x, y; - for(x = 0; x < w; ++x){ - for(y = 0; y < w; ++y){ - int i = x + y * w; - - double val = fabs(noise1[i] - noise2[i]) * 3 - 2; - double xd = x / (w - 1.0) * 2 - 1; - double yd = y / (h - 1.0) * 2 - 1; - if (xd < 0) xd = -xd; - if (yd < 0) yd = -yd; - double dist = xd >= yd ? xd : yd; - dist = dist * dist * dist * dist; - dist = dist * dist * dist * dist; - val = -val * 1 - 2.2; - val = val + 1 - dist * 20; - - if (val < -0.25) { - map[i] = -1; // render nothing - } else { - map[i] = TILE_CLOUD; +void createDungeonRoom(int w, int h, u8 * map, u8 * data) { + int tries; + + for(tries=0; tries<100; ++tries) { + int x = 5+(rand()%(w-10)); + int y = 5+(rand()%(h-10)); + int xr; + int yr; + int wr = 10+(rand()%11); + int hr = 10+(rand()&11); + int xp; + int yp; + int i; + + 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; xr < x+wr; ++xr) { + for(yr = y; yr < y+hr; ++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; } - } - } - int i; - for (i = 0; i < w * h / 50; ++i) { - int xx = rand()%w; - int yy = rand()%h; - if (xx >= 0 && yy >= 0 && xx < w && yy < h) { - if (map[xx + yy * w] == TILE_CLOUD) map[xx + yy * w] = TILE_CLOUDCACTUS; } + if(!allowed) break; } - int sCount, attempts = 0; - for (sCount = 0; sCount < 2;) { - int xx = rand()%w; - int yy = rand()%h; - if (xx >= 0 && yy >= 0 && xx < w && yy < h) { - if (map[xx + yy * w] == TILE_CLOUD) - { - map[xx + yy * w] = TILE_STAIRS_DOWN; - map[xx + (yy+1) * w] = TILE_CLOUD; - map[(xx+1) + yy * w] = TILE_CLOUD; - map[xx + (yy-1) * w] = TILE_CLOUD; - map[(xx-1) + yy * w] = TILE_CLOUD; - map[(xx-1) + (yy-1) * w] = TILE_CLOUD; - map[(xx+1) + (yy+1) * w] = TILE_CLOUD; - map[(xx+1) + (yy-1) * w] = TILE_CLOUD; - map[(xx-1) + (yy+1) * w] = TILE_CLOUD; - ++sCount; + 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; + yp = y; + 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) { + //TODO check for dungeon entrance: if(map[i]==TILE_DUNGEON_ENTRANCE) break; + + //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 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 { + if(rand()%50==0) map[i] = TILE_IRONORE + (rand()%3); } } - if(attempts < w*h) ++attempts; else break; } - free(noise1); - free(noise2); - } + + break; + } +} + +void createDungeonMap(int w, int h, u8 * map, u8 * data) { + int i, x, y; + for(x = 0; x < w; ++x){ + for(y = 0; y < w; ++y){ + i = x + y * w; + + //Startroom + if (x >= (w/2-5) && x <= (w/2+5) && y >= (h/2-5) && y <= (h/2+5) ) { + map[i] = TILE_DUNGEON_FLOOR; + } else { + map[i] = TILE_DUNGEON_WALL; + } + data[i] = 0; + } + } + + for(i = 0; i < 40; ++i) { + createDungeonRoom(w, h, map, data); + } + + //replace paths with actual dungeon floor + for(x = 0; x < w; ++x){ + for(y = 0; y < w; ++y){ + i = x + y * w; + + if (map[i]==255) { + map[i] = TILE_DUNGEON_FLOOR; + } + } + } + + //create entrance + map[w/2 + h/2 * w] = TILE_DUNGEON_ENTRANCE; + + map[w/2+1 + h/2 * w] = TILE_DUNGEON_FLOOR; + map[w/2-1 + h/2 * w] = TILE_DUNGEON_FLOOR; + map[w/2 + (h/2+1) * w] = TILE_DUNGEON_FLOOR; + map[w/2 + (h/2-1) * w] = TILE_DUNGEON_FLOOR; + + 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; +} + +void createSkyMap(int w, int h, u8 * map, u8 * data) { + double* noise1 = Noise(w, h, 8); + double* noise2 = Noise(w, h, 8); + int x, y; + for(x = 0; x < w; ++x){ + for(y = 0; y < w; ++y){ + int i = x + y * w; + + double val = fabs(noise1[i] - noise2[i]) * 3 - 2; + + double xd = x / (w - 1.0) * 2 - 1; + double yd = y / (h - 1.0) * 2 - 1; + if (xd < 0) xd = -xd; + if (yd < 0) yd = -yd; + double dist = xd >= yd ? xd : yd; + dist = dist * dist * dist * dist; + dist = dist * dist * dist * dist; + val = -val * 1 - 2.2; + val = val + 1 - dist * 20; + + if (val < -0.25) { + map[i] = -1; // render nothing + } else { + map[i] = TILE_CLOUD; + } + } + } + int i; + for (i = 0; i < w * h / 50; ++i) { + int xx = rand()%w; + int yy = rand()%h; + if (xx >= 0 && yy >= 0 && xx < w && yy < h) { + if (map[xx + yy * w] == TILE_CLOUD) map[xx + yy * w] = TILE_CLOUDCACTUS; + } + } + int sCount, attempts = 0; + for (sCount = 0; sCount < 2;) { + int xx = rand()%w; + int yy = rand()%h; + if (xx >= 0 && yy >= 0 && xx < w && yy < h) { + if (map[xx + yy * w] == TILE_CLOUD) + { + map[xx + yy * w] = TILE_STAIRS_DOWN; + map[xx + (yy+1) * w] = TILE_CLOUD; + map[(xx+1) + yy * w] = TILE_CLOUD; + map[xx + (yy-1) * w] = TILE_CLOUD; + map[(xx-1) + yy * w] = TILE_CLOUD; + map[(xx-1) + (yy-1) * w] = TILE_CLOUD; + map[(xx+1) + (yy+1) * w] = TILE_CLOUD; + map[(xx+1) + (yy-1) * w] = TILE_CLOUD; + map[(xx-1) + (yy+1) * w] = TILE_CLOUD; + ++sCount; + } + } + if(attempts < w*h) ++attempts; else break; + } + free(noise1); + free(noise2); +} diff --git a/source/MapGen.h b/source/MapGen.h index 8ab4ce7..61bc7ad 100644 --- a/source/MapGen.h +++ b/source/MapGen.h @@ -15,5 +15,7 @@ void createAndValidateTopMap(int w, int h, u8 * map, u8 * data); void createTopMap(int w, int h, u8 * map, u8 * data); void createAndValidateUndergroundMap(int w, int h,int depthLevel, u8 * map, u8 * data); void createUndergroundMap(int w, int h,int depthLevel, u8 * map, u8 * data); +void createAndValidateDungeonMap(int w, int h, u8 * map, u8 * data); +void createDungeonMap(int w, int h, u8 * map, u8 * data); void createAndValidateSkyMap(int w, int h, u8 * map, u8 * data); void createSkyMap(int w, int h, u8 * map, u8 * data); diff --git a/source/Menu.c b/source/Menu.c index 07300ea..9f4a0e2 100644 --- a/source/Menu.c +++ b/source/Menu.c @@ -366,7 +366,7 @@ void tickMenu(int menu){ currentMenu = MENU_NONE; break; case 1: - areYouSureSave = true; + if(currentLevel!=5) areYouSureSave = true; break; case 2: areYouSure = true; @@ -454,48 +454,69 @@ void tickMenu(int menu){ break; case MENU_CONTAINER: - if (k_menu.clicked || k_decline.clicked)currentMenu = MENU_NONE; - - if (k_left.clicked) { - curChestEntity->entityFurniture.r = 0; - int tmp = curInvSel; - curInvSel = curChestEntity->entityFurniture.oSel; - curChestEntity->entityFurniture.oSel = tmp; - } - if (k_right.clicked) { - curChestEntity->entityFurniture.r = 1; - int tmp = curInvSel; - curInvSel = curChestEntity->entityFurniture.oSel; - curChestEntity->entityFurniture.oSel = tmp; - } - - Inventory* i1 = curChestEntity->entityFurniture.r == 1 ? player.p.inv : curChestEntity->entityFurniture.inv; - Inventory* i2 = curChestEntity->entityFurniture.r == 0 ? player.p.inv : curChestEntity->entityFurniture.inv; - int len = i1->lastSlot; - if (curInvSel < 0) curInvSel = 0; - if (curInvSel >= len) curInvSel = len - 1; - if (k_up.clicked) --curInvSel; - if (k_down.clicked) ++curInvSel; - if (len == 0) curInvSel = 0; - if (curInvSel < 0) curInvSel += len; - if (curInvSel >= len) curInvSel -= len; - - if(k_accept.clicked && len > 0){ - Item* pullItem = &i1->items[curInvSel]; - Item pushItem = newItem(pullItem->id,pullItem->countLevel); - pushItem.chestPtr = pullItem->chestPtr; - pushItemToInventoryFront(pushItem, i2); - if(i2 == player.p.inv){ - int newslot = player.p.activeItem->slotNum + 1; - player.p.activeItem = &player.p.inv->items[newslot]; - } else if(pullItem == player.p.activeItem){ - player.p.activeItem = &noItem; - } - removeItemFromCurrentInv(pullItem); - if (curInvSel >= i1->lastSlot) curInvSel = i1->lastSlot - 1; - } - + if (k_menu.clicked || k_decline.clicked) currentMenu = MENU_NONE; + + if (k_left.clicked) { + curChestEntity->entityFurniture.r = 0; + int tmp = curInvSel; + curInvSel = curChestEntity->entityFurniture.oSel; + curChestEntity->entityFurniture.oSel = tmp; + } + if (k_right.clicked) { + curChestEntity->entityFurniture.r = 1; + int tmp = curInvSel; + curInvSel = curChestEntity->entityFurniture.oSel; + curChestEntity->entityFurniture.oSel = tmp; + } + + Inventory* i1 = curChestEntity->entityFurniture.r == 1 ? player.p.inv : curChestEntity->entityFurniture.inv; + Inventory* i2 = curChestEntity->entityFurniture.r == 0 ? player.p.inv : curChestEntity->entityFurniture.inv; + int len = i1->lastSlot; + if (curInvSel < 0) curInvSel = 0; + if (curInvSel >= len) curInvSel = len - 1; + if (k_up.clicked) --curInvSel; + if (k_down.clicked) ++curInvSel; + if (len == 0) curInvSel = 0; + if (curInvSel < 0) curInvSel += len; + if (curInvSel >= len) curInvSel -= len; + + if(k_accept.clicked && len > 0){ + Item* pullItem = &i1->items[curInvSel]; + Item pushItem = newItem(pullItem->id,pullItem->countLevel); + pushItem.chestPtr = pullItem->chestPtr; + pushItemToInventoryFront(pushItem, i2); + if(i2 == player.p.inv){ + int newslot = player.p.activeItem->slotNum + 1; + player.p.activeItem = &player.p.inv->items[newslot]; + } else if(pullItem == player.p.activeItem){ + player.p.activeItem = &noItem; + } + removeItemFromCurrentInv(pullItem); + if (curInvSel >= i1->lastSlot) curInvSel = i1->lastSlot - 1; + } break; + + case MENU_DUNGEON: + if (k_menu.clicked || k_decline.clicked) currentMenu = MENU_NONE; + + if(k_accept.clicked) { + if(currentLevel!=5) { + Item * item = getItemFromInventory(ITEM_DUNGEON_KEY, player.p.inv); + if(item!=NULL) { + --item->countLevel; + if(item->countLevel==0) { + removeItemFromCurrentInv(item); + } + + enterDungeon(); + } + } else { + leaveDungeon(); + } + + currentMenu = MENU_NONE; + } + break; case MENU_LOADGAME: if(!enteringName && !areYouSure){ // World select @@ -999,6 +1020,10 @@ void renderMenu(int menu,int xscr,int yscr){ char* msg = pOptions[i]; u32 color = 0xFF7F7F7F; if(i == currentSelection) color = 0xFFFFFFFF; + if(i == 1 && currentLevel==5) { + color = 0xFF7F7FFF; + if(i == currentSelection) color = 0xFFAFAFFF; + } drawTextColor(msg,(400 - (strlen(msg) * 12))/2, (i * 24) + 100, color); } @@ -1068,6 +1093,8 @@ void renderMenu(int menu,int xscr,int yscr){ renderMenuBackground(xscr,yscr); offsetX = 0;offsetY = 0; renderFrame(1,1,24,14,0xFFFF1010); + drawTextColor("Inventory",24+1,14+1,0xFF000000); + drawTextColor("Inventory",24,14,0xFF6FE2E2); renderItemList(player.p.inv, 1,1,24,14, curInvSel); sf2d_end_frame(); break; @@ -1082,8 +1109,14 @@ void renderMenu(int menu,int xscr,int yscr){ offsetX = 0;offsetY = 0; 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("Crafting",24+1,14+1,0xFF000000); + drawTextColor("Crafting",24,14,0xFF6FE2E2); renderRecipes(currentRecipes, 1, 1, 14, 14, curInvSel); Recipe* rec = ¤tRecipes->recipes[curInvSel]; @@ -1119,15 +1152,63 @@ void renderMenu(int menu,int xscr,int yscr){ else {offsetX = 0;offsetY = 0;} renderFrame(1,1,14,14,0xFFFF1010); + drawTextColor("Chest",24+1,14+1,0xFF000000); + drawTextColor("Chest",24,14,0xFF6FE2E2); renderItemList(curChestEntity->entityFurniture.inv,1,1,14,14, curChestEntity->entityFurniture.r == 0 ? curInvSel : -curChestEntity->entityFurniture.oSel - 1); renderFrame(15,1,28,14,0xFFFF1010); + drawTextColor("Inventory",248+1,14+1,0xFF000000); + drawTextColor("Inventory",248,14,0xFF6FE2E2); renderItemList(player.p.inv,15,1,28,14, curChestEntity->entityFurniture.r == 1 ? curInvSel : -curChestEntity->entityFurniture.oSel - 1); offsetX = 0;offsetY = 0; sf2d_end_frame(); break; + case MENU_DUNGEON: + 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; + renderFrame(1,1,24,14,0xFFFF1010); + if(currentLevel!=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(k_accept.input & -k_accept.input, 150, 168, 1); + drawText(" Stay", 148, 195); + renderButtonIcon(k_decline.input & -k_decline.input, 150, 192, 1); + sf2d_end_frame(); + break; + case MENU_ABOUT: sf2d_start_frame(GFX_TOP, GFX_LEFT); sf2d_draw_rectangle(0, 0, 400, 240, 0xFF0C0C0C); //You might think "real" black would be better, but it actually looks better that way diff --git a/source/MenuTutorial.c b/source/MenuTutorial.c index a7c33c8..e308cc4 100644 --- a/source/MenuTutorial.c +++ b/source/MenuTutorial.c @@ -206,24 +206,24 @@ void renderTutorialPage(bool topScreen){ render(132,82,72,152,0); // Bread break; case 6: //Mining - render16b(23,32,80,0,0,0xFFC8C8DF); // iron ore - render16b(23,52,80,0,0,0xFFB9E8E5); // gold ore - render16b(23,72,80,0,0,0xFFDE98DF); // gem ore - renderb(41,38,88,152,0,0xFFC8C8DF); // Iron ore item - renderb(41,58,88,152,0,0xFFB9E8E5); // Gold ore item + render16b(23,32,80,0,0,ironColor); // iron ore + render16b(23,52,80,0,0,goldColor); // gold ore + render16b(23,72,80,0,0,gemColor); // gem ore + renderb(41,38,88,152,0,ironColor); // Iron ore item + renderb(41,58,88,152,0,goldColor); // Gold ore item render(41,78,112,152,0); // Gem item drawText(">",104,74); drawText(">",104,114); drawText(">",104,154); render16(60,32,112,128,0); // Furnace render16(60,52,112,128,0); // Furnace - render16(60,72,64,128,0); // Anvil + render16(60,72,240,128,0); // Enchanter drawText(">",160,74); drawText(">",160,114); drawText(">",160,154); - renderb(88,36,96,152,0,0xFFC8C8DF); // Iron ingot item - renderb(88,56,96,152,0,0xFFB9E8E5); // Gold ingot item - renderb(88,76,152,144,0,0xFFB9E8E5); // Gem Pickaxe + renderb(88,36,96,152,0,ironColor); // Iron ingot item + renderb(88,56,96,152,0,goldColor); // Gold ingot item + renderb(88,76,152,144,0,goldColor); // Gem Pickaxe drawText(">",200,74); drawText(">",200,114); render16(106,32,64,128,0); // Anvil diff --git a/source/Render.c b/source/Render.c index 2af96f4..21b7219 100644 --- a/source/Render.c +++ b/source/Render.c @@ -258,20 +258,28 @@ void renderFrame(int x1, int y1, int x2, int y2, u32 bgColor) { void bakeLights() { playerLightBake = sf2d_create_texture(64, 64, TEXFMT_RGBA8, SF2D_PLACE_RAM); - lanternLightBake = sf2d_create_texture(128, 128, TEXFMT_RGBA8, - SF2D_PLACE_RAM); + lanternLightBake = sf2d_create_texture(128, 128, TEXFMT_RGBA8, SF2D_PLACE_RAM); + + glowwormLightBake = sf2d_create_texture(16, 16, TEXFMT_RGBA8, SF2D_PLACE_RAM); + glowwormBigLightBake = sf2d_create_texture(32, 32, TEXFMT_RGBA8, SF2D_PLACE_RAM); bakeLight(playerLightBake, 32, 32, 32); bakeLight(lanternLightBake, 64, 64, 64); + + bakeLight(glowwormLightBake, 8, 8, 8); + bakeLight(glowwormBigLightBake, 12, 12, 12); } void freeLightBakes() { sf2d_free_texture(playerLightBake); sf2d_free_texture(lanternLightBake); + + sf2d_free_texture(glowwormLightBake); + sf2d_free_texture(glowwormBigLightBake); } -void renderLightsToStencil() { - if (currentLevel > 1) { +void renderLightsToStencil(bool force, bool invert, bool rplayer) { + if (force || (currentLevel > 1 && currentLevel != 5)) { GPU_SetDepthTestAndWriteMask(true, GPU_NEVER, 0); GPU_SetStencilTest(true, GPU_NEVER, 1, 0xFF, 0xFF); GPU_SetStencilOp(GPU_STENCIL_REPLACE, GPU_STENCIL_KEEP, @@ -279,40 +287,55 @@ void renderLightsToStencil() { GPU_SetAlphaTest(true, GPU_GREATER, 0); if(player.p.activeItem->id == ITEM_LANTERN) renderLight(player.x, player.y, lanternLightBake); - else renderLight(player.x, player.y, playerLightBake); + else if(rplayer) renderLight(player.x, player.y, playerLightBake); int i; for (i = 0; i < eManager.lastSlot[currentLevel]; ++i) { Entity e = eManager.entities[currentLevel][i]; - if (e.type != ENTITY_FURNITURE)continue; - 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) - renderLight(e.x, e.y, lanternLightBake); + 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) + 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 + if(rand()%10==0) continue; + else if(rand()%100==0) renderLight(e.x+4, e.y-4, glowwormBigLightBake); + else renderLight(e.x, e.y, glowwormLightBake); + } } int xo = offsetX >> 4; int yo = offsetY >> 4; int x, y; //added offset to render lights from lava which is offscreen + //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 (y = yo-2; y <= 8 + yo+2; ++y) - if(getTile(x, y) == TILE_LAVA) renderLight(x << 4, y << 4, playerLightBake); + for (y = yo-2; y <= 8 + yo+2; ++y) { + if(getTile(x, y) == TILE_LAVA) { + //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((x+y)%2 == 0) continue; + } + renderLight((x << 4) + 8, (y << 4) + 8, playerLightBake); + } + } } GPU_SetDepthTestAndWriteMask(true, GPU_GEQUAL, GPU_WRITE_ALL); - GPU_SetStencilTest(true, GPU_EQUAL, 1, 0xFF, 0x0); + if(invert) { + GPU_SetStencilTest(true, GPU_EQUAL, 0, 0xFF, 0x0); + } else { + GPU_SetStencilTest(true, GPU_EQUAL, 1, 0xFF, 0x0); + } GPU_SetAlphaTest(false, GPU_ALWAYS, 0x00); - GPU_SetStencilOp(GPU_STENCIL_KEEP, GPU_STENCIL_KEEP, - GPU_STENCIL_REPLACE); + GPU_SetStencilOp(GPU_STENCIL_KEEP, GPU_STENCIL_KEEP, GPU_STENCIL_REPLACE); } } void resetStencilStuff() { - if (currentLevel > 1) { + //if (currentLevel > 1) { GPU_SetStencilTest(false, GPU_ALWAYS, 0x00, 0xFF, 0x00); GPU_SetStencilOp(GPU_STENCIL_KEEP, GPU_STENCIL_KEEP, GPU_STENCIL_KEEP); - } + //} } void renderLight(int x, int y, sf2d_texture* texture) { @@ -507,13 +530,13 @@ void renderTile(int i, int d, int x, int y) { render16(x, y, 112, 0, 0); break; case TILE_IRONORE: - render16b(x, y, 80, 0, 0, 0xFFC8C8DF); + render16b(x, y, 80, 0, 0, ironColor); break; case TILE_GOLDORE: - render16b(x, y, 80, 0, 0, 0xFFB9E8E5); + render16b(x, y, 80, 0, 0, goldColor); break; case TILE_GEMORE: - render16b(x, y, 80, 0, 0, 0xFFDE98DF); + render16b(x, y, 80, 0, 0, gemColor); break; case TILE_CLOUD: checkSurrTiles4(x >> 4, y >> 4, TILE_CLOUD); @@ -548,6 +571,37 @@ void renderTile(int i, int d, int x, int y) { renderConnectedTile4(x, y, 0, 32, woodColor); break; + case TILE_STONE_WALL: + checkSurrTiles4(x >> 4, y >> 4, TILE_STONE_WALL); + + renderConnectedTile4(x, y, 128, 32, rockColor[0]); + break; + case TILE_IRON_WALL: + checkSurrTiles4(x >> 4, y >> 4, TILE_IRON_WALL); + + renderConnectedTile4(x, y, 128, 32, ironColor); + break; + case TILE_GOLD_WALL: + checkSurrTiles4(x >> 4, y >> 4, TILE_GOLD_WALL); + + renderConnectedTile4(x, y, 128, 32, goldColor); + break; + case TILE_GEM_WALL: + checkSurrTiles4(x >> 4, y >> 4, TILE_GEM_WALL); + + renderConnectedTile4(x, y, 128, 32, gemColor); + break; + case TILE_DUNGEON_WALL: + checkSurrTiles8(x >> 4, y >> 4, TILE_DUNGEON_WALL); + + renderConnectedTile8(x, y, 128, 32, dungeonColor[0]); + break; + case TILE_DUNGEON_FLOOR: + render16b(x, y, 208, 32, 0, dungeonColor[1]); + break; + case TILE_DUNGEON_ENTRANCE: + render16b(x, y, 224 + (currentLevel==5 ? 16 : 0), 32, 0, dungeonColor[0]); + break; } resetSurrTiles(); @@ -746,16 +800,46 @@ void renderPlayer() { void renderMenuBackground(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 - renderLightsToStencil(); + renderLightsToStencil(false, false, true); renderBackground(xScroll, yScroll); resetStencilStuff(); + + renderDayNight(); +} + +void renderDayNight() { + if(currentLevel==1 && (daytime<6000 || daytime>18000)) { + int color1 = 0x000C0C0C; + int color2 = 0x00100C0C; + int alpha1 = 0x99; + int alpha2 = 0xDD; + + if(daytime>5000 && daytime<6000) { + alpha1 = (alpha1 * (1000-(daytime-5000)))/1000; + alpha2 = (alpha2 * (1000-(daytime-5000)))/1000; + } else if(daytime>18000 && daytime<19000) { + alpha1 = (alpha1 * (daytime-18000))/1000; + alpha2 = (alpha2 * (daytime-18000))/1000; + } + + color1 = color1 | (alpha1 << 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 + renderLightsToStencil(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 + resetStencilStuff(); + } } void renderBackground(int xScroll, int yScroll) { - if(currentLevel > 0) sf2d_draw_rectangle(0, 0, 400, 240, dirtColor[currentLevel]); // dirt color - else { + if(currentLevel == 0) { 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); + } else if(currentLevel == 5) { + sf2d_draw_rectangle(0, 0, 400, 240, dungeonColor[1]); + } else { + sf2d_draw_rectangle(0, 0, 400, 240, dirtColor[currentLevel]); // dirt color } int xo = xScroll >> 4; int yo = yScroll >> 4; @@ -862,6 +946,12 @@ void renderFurniture(int itemID, int x, int y) { case ITEM_LANTERN: render16(x, y, 144, 128, 0); break; + case ITEM_LOOM: + render16(x, y, 224, 128, 0); + break; + case ITEM_ENCHANTER: + render16(x, y, 240, 128, 0); + break; } } @@ -879,24 +969,50 @@ void renderEntity(Entity* e, int x, int y) { renderFurniture(e->entityFurniture.itemID, x - 8, y - 8); break; case ENTITY_ZOMBIE: - switch (e->zombie.dir) { + switch (e->hostile.dir) { + case 0: // down + render16b(x - 8, y - 8, 64, 112, ((e->hostile.walkDist >> 4) & 1) == 0 ? 0 : 1, e->hostile.color); + break; + case 1: // up + render16b(x - 8, y - 8, 80, 112, ((e->hostile.walkDist >> 4) & 1) == 0 ? 0 : 1, e->hostile.color); + break; + case 2: // left + render16b(x - 8, y - 8, 96 + (((e->hostile.walkDist >> 4) & 1) << 4), 112, 1, e->hostile.color); + break; + case 3: // right + render16b(x - 8, y - 8, 96 + (((e->hostile.walkDist >> 4) & 1) << 4), 112, 0, e->hostile.color); + break; + } + break; + case ENTITY_SKELETON: + switch (e->hostile.dir) { + case 0: // down + render16b(x - 8, y - 8, 0, 80, ((e->hostile.walkDist >> 4) & 1) == 0 ? 0 : 1, e->hostile.color); + break; + case 1: // up + render16b(x - 8, y - 8, 16, 80, ((e->hostile.walkDist >> 4) & 1) == 0 ? 0 : 1, e->hostile.color); + break; + case 2: // left + render16b(x - 8, y - 8, 32 + (((e->hostile.walkDist >> 4) & 1) << 4), 80, 1, e->hostile.color); + break; + case 3: // right + render16b(x - 8, y - 8, 32 + (((e->hostile.walkDist >> 4) & 1) << 4), 80, 0, e->hostile.color); + break; + } + break; + case ENTITY_KNIGHT: + switch (e->hostile.dir) { case 0: // down - render16b(x - 8, y - 8, 64, 112, - ((e->zombie.walkDist >> 4) & 1) == 0 ? 0 : 1, - e->zombie.color); + render16b(x - 8, y - 8, 64, 80, ((e->hostile.walkDist >> 4) & 1) == 0 ? 0 : 1, e->hostile.color); break; case 1: // up - render16b(x - 8, y - 8, 80, 112, - ((e->zombie.walkDist >> 4) & 1) == 0 ? 0 : 1, - e->zombie.color); + render16b(x - 8, y - 8, 80, 80, ((e->hostile.walkDist >> 4) & 1) == 0 ? 0 : 1, e->hostile.color); break; case 2: // left - render16b(x - 8, y - 8, 96 + (((e->zombie.walkDist >> 4) & 1) << 4), - 112, 1, e->zombie.color); + render16b(x - 8, y - 8, 96 + (((e->hostile.walkDist >> 4) & 1) << 4), 80, 1, e->hostile.color); break; case 3: // right - render16b(x - 8, y - 8, 96 + (((e->zombie.walkDist >> 4) & 1) << 4), - 112, 0, e->zombie.color); + render16b(x - 8, y - 8, 96 + (((e->hostile.walkDist >> 4) & 1) << 4), 80, 0, e->hostile.color); break; } break; @@ -932,6 +1048,22 @@ void renderEntity(Entity* e, int x, int y) { break; } break; + case ENTITY_PASSIVE: + switch (e->passive.dir) { + case 0: // down + render16(x - 8, y - 8, (e->passive.mtype*64) + 0, 96, ((e->passive.walkDist >> 4) & 1) == 0 ? 0 : 1); + break; + case 1: // up + render16(x - 8, y - 8, (e->passive.mtype*64) + 16, 96, ((e->passive.walkDist >> 4) & 1) == 0 ? 0 : 1); + break; + case 2: // left + render16(x - 8, y - 8, (e->passive.mtype*64) + 32 + (((e->passive.walkDist >> 4) & 1) << 4), 96, 1); + break; + case 3: // right + render16(x - 8, y - 8, (e->passive.mtype*64) + 32 + (((e->passive.walkDist >> 4) & 1) << 4), 96, 0); + break; + } + break; case ENTITY_TEXTPARTICLE: x -= offsetX; y -= offsetY; @@ -949,6 +1081,45 @@ void renderEntity(Entity* e, int x, int y) { return; renderr(x, y, 200, 152, 0, e->spark.age * 0.0349); break; + case ENTITY_ARROW: + if (e->arrow.age >= 200) + if (e->arrow.age / 6 % 2 == 0) + return; + + int abits = 0; + int ayp = 168; + if(e->arrow.xa<0) { + abits += 1; + } + if(e->arrow.ya<0) { + ayp += 8; + } + if(e->arrow.ya>0) { + ayp += 8; + abits += 2; + } + + switch (e->arrow.itemID) { + case ITEM_ARROW_WOOD: + render(x-2, y-2, 72, ayp, abits); + break; + case ITEM_ARROW_STONE: + render(x-2, y-2, 80, ayp, abits); + break; + case ITEM_ARROW_IRON: + render(x-2, y-2, 88, ayp, abits); + break; + case ITEM_ARROW_GOLD: + render(x-2, y-2, 96, ayp, abits); + break; + case ITEM_ARROW_GEM: + render(x-2, y-2, 104, ayp, abits); + break; + } + break; + case ENTITY_GLOWWORM: + render(x-4, y-4, 224, 112, 0); + break; } } @@ -1154,16 +1325,16 @@ void renderItemIcon(int itemID, int countLevel, int x, int y) { renderb(x, y, 88, 152, 0, 0xFF383838); break; case ITEM_IRONORE: - renderb(x, y, 88, 152, 0, 0xFF9999BC); + renderb(x, y, 88, 152, 0, ironColor); break; case ITEM_GOLDORE: - renderb(x, y, 88, 152, 0, 0xFF77CECE); + renderb(x, y, 88, 152, 0, goldColor); break; case ITEM_IRONINGOT: - renderb(x, y, 96, 152, 0, 0xFFC8C8DF); + renderb(x, y, 96, 152, 0, ironColor); break; case ITEM_GOLDINGOT: - renderb(x, y, 96, 152, 0, 0xFFBCEAEA); + renderb(x, y, 96, 152, 0, goldColor); break; case ITEM_GLASS: render(x, y, 104, 152, 0); @@ -1171,8 +1342,77 @@ void renderItemIcon(int itemID, int countLevel, int x, int y) { case ITEM_GEM: render(x, y, 112, 152, 0); break; + case ITEM_LOOM: + render(x, y, 120, 160, 0); + break; + case ITEM_ENCHANTER: + render(x, y, 144, 160, 0); + break; + case ITEM_WALL_WOOD: + renderb(x, y, 224, 144, 0, woodColor); + break; + case ITEM_WALL_STONE: + renderb(x, y, 224, 144, 0, rockColor[1]); + break; + case ITEM_WALL_IRON: + renderb(x, y, 224, 144, 0, ironColor); + break; + case ITEM_WALL_GOLD: + renderb(x, y, 224, 144, 0, goldColor); + break; + case ITEM_WALL_GEM: + renderb(x, y, 224, 144, 0, gemColor); + break; + case ITEM_WOOL: + render(x, y, 64, 160, 0); + break; + case ITEM_STRING: + render(x, y, 72, 160, 0); + break; + case ITEM_PORK_RAW: + render(x, y, 80, 160, 0); + break; + case ITEM_PORK_COOKED: + render(x, y, 88, 160, 0); + break; + case ITEM_BEEF_RAW: + render(x, y, 96, 160, 0); + break; + case ITEM_BEEF_COOKED: + render(x, y, 104, 160, 0); + break; + case ITEM_LEATHER: + render(x, y, 112, 160, 0); + break; + case ITEM_ARROW_WOOD: + render(x, y, 72, 168, 0); + break; + case ITEM_ARROW_STONE: + render(x, y, 80, 168, 0); + break; + case ITEM_ARROW_IRON: + render(x, y, 88, 168, 0); + break; + case ITEM_ARROW_GOLD: + render(x, y, 96, 168, 0); + break; + case ITEM_ARROW_GEM: + render(x, y, 104, 168, 0); + break; + case ITEM_BONE: + render(x, y, 128, 160, 0); + break; + case ITEM_DUNGEON_KEY: + render(x, y, 136, 160, 0); + break; + case ITEM_WIZARD_SUMMON: + render(x, y, 152, 160, 0); + break; case TOOL_BUCKET: render(x, y, 200 + countLevel * 8, 144, 0); break; + case TOOL_BOW: + render(x, y, 64, 168, 0); + break; } } diff --git a/source/Render.h b/source/Render.h index f34b311..85641cd 100644 --- a/source/Render.h +++ b/source/Render.h @@ -9,6 +9,8 @@ sf2d_texture *playerLightBake; sf2d_texture *lanternLightBake; +sf2d_texture *glowwormLightBake; +sf2d_texture *glowwormBigLightBake; int offsetX, offsetY; void render(s32 xp, s32 yp, u32 xTile, u32 yTile, u8 bits); @@ -31,11 +33,12 @@ void renderConnectedTile4(int x, int y, u32 xTile, u32 yTile, u32 color); void renderConnectedTile8(int x, int y, u32 xTile, u32 yTile, u32 color); void renderBackground(int xScroll, int yScroll); void renderMenuBackground(int xScroll, int yScroll); //Renders the darkness +void renderDayNight(); void renderButtonIcon(u32 icon, int x, int y, float scale); void bakeLights(); void freeLightBakes(); -void renderLightsToStencil(); +void renderLightsToStencil(bool force, bool invert, bool rplayer); void resetStencilStuff(); void bakeLight(sf2d_texture* texture, int x, int y, int r); void renderLight(int x, int y, sf2d_texture* texture); diff --git a/source/SaveLoad.c b/source/SaveLoad.c index 37e5536..3cca5ca 100644 --- a/source/SaveLoad.c +++ b/source/SaveLoad.c @@ -8,8 +8,12 @@ s16 calculateImportantEntites(EntityManager * eManager, int level){ 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: count++; break; } @@ -22,8 +26,12 @@ bool entityIsImportant(Entity * e){ 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: return true; default: return false; @@ -75,8 +83,10 @@ void saveCurrentWorld(char * filename, EntityManager * eManager, Entity * player fwrite(&eManager->entities[i][j].slime.lvl, sizeof(s8), 1, file); break; case ENTITY_ZOMBIE: - fwrite(&eManager->entities[i][j].zombie.health, sizeof(s16), 1, file); - fwrite(&eManager->entities[i][j].zombie.lvl, sizeof(s8), 1, file); + case ENTITY_SKELETON: + case ENTITY_KNIGHT: + fwrite(&eManager->entities[i][j].hostile.health, sizeof(s16), 1, file); + fwrite(&eManager->entities[i][j].hostile.lvl, sizeof(s8), 1, file); break; case ENTITY_ITEM: fwrite(&eManager->entities[i][j].entityItem.item.id, sizeof(s16), 1, file); @@ -87,14 +97,21 @@ void saveCurrentWorld(char * filename, EntityManager * eManager, Entity * player fwrite(&eManager->entities[i][j].entityFurniture.itemID, sizeof(s16), 1, file); int invIndex = eManager->entities[i][j].entityFurniture.inv - eManager->invs; fwrite(&invIndex, sizeof(int), 1, file); + break; + case ENTITY_PASSIVE: + fwrite(&eManager->entities[i][j].passive.health, sizeof(s16), 1, file); + fwrite(&eManager->entities[i][j].passive.mtype, sizeof(u8), 1, file); break; } } } // Map Data + //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(mapData, 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); } @@ -195,21 +212,58 @@ int loadWorld(char * filename, EntityManager * eManager, Entity * player, u8 * m } break; case ENTITY_ZOMBIE: - fread(&eManager->entities[i][j].zombie.health, sizeof(s16), 1, file); - fread(&eManager->entities[i][j].zombie.lvl, sizeof(s8), 1, file); + 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].zombie.dir = 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].zombie.lvl){ - case 2: eManager->entities[i][j].zombie.color = 0xFF8282CC; break; - case 3: eManager->entities[i][j].zombie.color = 0xFFEFEFEF; break; - case 4: eManager->entities[i][j].zombie.color = 0xFFAA6262; break; - default: eManager->entities[i][j].zombie.color = 0xFF95DB95; break; + 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: @@ -239,11 +293,35 @@ int loadWorld(char * filename, EntityManager * eManager, Entity * player, u8 * m 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; } } } + //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); + fclose(file); return 0; } diff --git a/source/SaveLoad.h b/source/SaveLoad.h index 0468bf5..0928f75 100644 --- a/source/SaveLoad.h +++ b/source/SaveLoad.h @@ -2,6 +2,7 @@ #include #include #include "Entity.h" +#include "Globals.h" void saveCurrentWorld(char * filename, EntityManager * eManager, Entity * player, u8 * map, u8 * mapData); int loadWorld(char * filename, EntityManager * eManager, Entity * player, u8 * map, u8 * mapData); diff --git a/source/Sound.c b/source/Sound.c index 70f7d64..9474c6d 100644 --- a/source/Sound.c +++ b/source/Sound.c @@ -20,19 +20,21 @@ void playMusic(Sound snd){ csndPlaySound(10, SOUND_FORMAT_16BIT | SOUND_REPEAT, 44100, 1, 0, snd.buffer, snd.buffer, snd.size); } -void updateMusic(int lvl) { +void updateMusic(int lvl, int time) { switch(lvl) { case 0: playMusic(music_floor0); break; case 1: - playMusic(music_floor1); + if(time>6000 && time<19000) playMusic(music_floor1); + else playMusic(music_floor1_night); break; case 2: case 3: playMusic(music_floor23); break; case 4: + case 5: //TODO - dungeon needs own music playMusic(music_floor4); break; } @@ -50,6 +52,7 @@ void loadSounds() { loadSound(&music_menu, "resources/music/menu.raw"); loadSound(&music_floor0, "resources/music/floor0.raw"); loadSound(&music_floor1, "resources/music/floor1.raw"); + loadSound(&music_floor1_night, "resources/music/floor1_night.raw"); loadSound(&music_floor23, "resources/music/floor2_3.raw"); loadSound(&music_floor4, "resources/music/floor4.raw"); } @@ -66,6 +69,7 @@ void freeSounds(){ linearFree(music_menu.buffer); linearFree(music_floor0.buffer); linearFree(music_floor1.buffer); + linearFree(music_floor1_night.buffer); linearFree(music_floor23.buffer); linearFree(music_floor4.buffer); } diff --git a/source/Sound.h b/source/Sound.h index 2e36791..22aeffa 100644 --- a/source/Sound.h +++ b/source/Sound.h @@ -14,7 +14,7 @@ void loadSound(Sound * snd, char * filename); void playSound(Sound snd); void playMusic(Sound snd); -void updateMusic(int lvl); +void updateMusic(int lvl, int time); void loadSounds(); void freeSounds(); @@ -30,5 +30,6 @@ Sound snd_craft; Sound music_menu; Sound music_floor0; Sound music_floor1; +Sound music_floor1_night; Sound music_floor23; Sound music_floor4; \ No newline at end of file diff --git a/source/main.c b/source/main.c index fcf2853..7bc8b52 100644 --- a/source/main.c +++ b/source/main.c @@ -14,41 +14,9 @@ #include "texturepack.h" void initMiniMap(bool loadUpWorld) { - int i, x, y; + int i; for (i = 0; i < 5; ++i) { - for (x = 0; x < 128; ++x) { - for (y = 0; y < 128; ++y) { - - if (!loadUpWorld) { // generate stairs up when making a new world. - switch (map[i][x + y * 128]) { - case TILE_STAIRS_DOWN: - map[i + 1][x + y * 128] = TILE_STAIRS_UP; - if (i == 0) { - map[i + 1][(x + 1) + y * 128] = TILE_HARDROCK; - map[i + 1][x + (y + 1) * 128] = TILE_HARDROCK; - map[i + 1][(x - 1) + y * 128] = TILE_HARDROCK; - map[i + 1][x + (y - 1) * 128] = TILE_HARDROCK; - map[i + 1][(x + 1) + (y + 1) * 128] = TILE_HARDROCK; - map[i + 1][(x - 1) + (y - 1) * 128] = TILE_HARDROCK; - map[i + 1][(x - 1) + (y + 1) * 128] = TILE_HARDROCK; - map[i + 1][(x + 1) + (y - 1) * 128] = TILE_HARDROCK; - } else { - map[i + 1][(x + 1) + y * 128] = TILE_DIRT; - map[i + 1][x + (y + 1) * 128] = TILE_DIRT; - map[i + 1][(x - 1) + y * 128] = TILE_DIRT; - map[i + 1][x + (y - 1) * 128] = TILE_DIRT; - map[i + 1][(x + 1) + (y + 1) * 128] = TILE_DIRT; - map[i + 1][(x - 1) + (y - 1) * 128] = TILE_DIRT; - map[i + 1][(x - 1) + (y + 1) * 128] = TILE_DIRT; - map[i + 1][(x + 1) + (y - 1) * 128] = TILE_DIRT; - } - } - } - - /* Minimaps */ - sf2d_set_pixel(minimap[i], x, y, getTileColor(map[i][x + y * 128])); - } - } + initMinimapLevel(i, loadUpWorld); } } @@ -77,12 +45,13 @@ void setupGame(bool loadUpWorld) { trySpawn(500, i); } addEntityToList(newAirWizardEntity(630, 820, 0), &eManager); + daytime = 6000; } else { initPlayer(); loadWorld(currentFileName, &eManager, &player, (u8*) map, (u8*) data); } - updateMusic(currentLevel); + updateMusic(currentLevel, daytime); initMiniMap(loadUpWorld); shouldRenderMap = false; @@ -112,6 +81,17 @@ void tick() { tickTouchMap(); tickTouchQuickSelect(); + ++daytime; + //daytime += 20; + if(daytime>=24000) { + daytime -= 24000; + } + 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; @@ -129,12 +109,15 @@ void tick() { yscr = 16; else if (yscr > 1912) yscr = 1912; + + if(eManager.lastSlot[currentLevel]<80) { + 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_SLIME) - || (e->x > player.x - 160 && e->y > player.y - 125 - && e->x < player.x + 160 && e->y < player.y + 125)) + 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); } @@ -179,7 +162,7 @@ int main() { int i; - for (i = 0; i < 5; ++i) { + for (i = 0; i < 6; ++i) { minimap[i] = sf2d_create_texture(128, 128, TEXFMT_RGBA8, SF2D_PLACE_RAM); sf2d_texture_tile32(minimap[i]); @@ -248,13 +231,17 @@ int main() { 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(); + + renderLightsToStencil(false, false, true); renderBackground(xscr, yscr); renderEntities(player.x, player.y, &eManager); renderPlayer(); resetStencilStuff(); + + renderDayNight(); + offsetX = 0; offsetY = 0; @@ -290,6 +277,7 @@ int main() { sf2d_free_texture(minimap[2]); sf2d_free_texture(minimap[3]); sf2d_free_texture(minimap[4]); + sf2d_free_texture(minimap[5]); freeSounds(); csndExit(); cfguExit();