Roguelike port?

Awesome! Let me know if you have any questions, because my code is a newbie flavored mess :wink: I will keep on checking the thread every now and then.

The lua language reference is a PITA, because try searching for a keyword “add”

What does this do:
local r = {x=2,y=2,w=dungeon.w,h=dungeon.h}
add (rooms,r)

edit: local is clear, but clarify “add” for me

I think ADD is pico-8 specific.

Look here: Roguelike port?

I makes the first entry in the rooms array with the following vars: {x=2,y=2,w=dungeon.w,h=dungeon.h}

In the original code it was this (I changed the variables to reflect mine):

room[1] = new Rooms(2,2,dungeon.w,dungeon.h);

edit: fixed w and h placement in example!

Isn’t add the equivalent of table.insert?
Edit:
add == table.insert

add t v

		Add value v to the end of table t.
		Equivalent to t[#t+1] = v

			FOO={}        -- create empty table
			ADD(FOO, 11)
			ADD(FOO, 22)
			PRINT(FOO[2]) -- 22
1 Like

I need to head out, but I will be back in an hour or so and start working on item sprites.

I have worked a bit more on the dungeon gen (made the doors work and such), but I won’t add to the translation effort.

Thanks for your help @jonne! We can do this guys!

I am 70% done. I need to step out for a while as well

edit: continuing now

#define MAX_ROOMS 100 // 100 rooms max, I don't want to get into dynamic memory allocation here

struct Dungeon {
  uint8_t tiles[];
  uint8_t w;
  uint8_t h;		
}; // Dungeon structure definition

Dungeon dungeon = {.w=48, .h=32, .tiles[48*32] = NULL}; // make a Dungeon instance called "dungeon"

uint8_t wall_h = 1; //global variable wall_h, type is unsigned char (8 bits) value 0..255

uint8_t grid_w=0, grid_h=0, room_size=4; // multiple variables of same type can be declare in 1 row

/* ---------------
mapgen starts here
----------------*/

/* this is one type of comment in C */
// this is 1 row comment in C++

// decide on max iterations

void mapgen(Dungeon& d) { 
  // void means function does not return anything, {} mark the beginning and end of function
  // Dungeon& is a reference to a Dungeon instance  
  // blank the tile array	  
  for (int i=0; i<dung.w; i++) {
	for (int j=0; j<d.h; j++) {
		d.tiles[i][j]=1; // all tiles set to 1 initially
		}
	} 	
  }
  // add outside walls
  for (int i=0; i<d.w; i++) {d.tiles[i]=2;d.tiles[(d.h-1)*d.w+i]=2;} //horiz walls
  for (int i=0; i<d.h; i++) {d.tiles[i*d.w]=2;d.tiles[i*(d.w)-1]=2;} //ver walls
}

void make_rooms(Dungeon& d) {
  struct Room {
    uint8_t w;
    uint8_t h;
    uint8_t x;
    uint8_t y;
  }; // define structure Room

  Room rooms[MAX_ROOMS]; 
  for (int i=0; i<MAX_ROOMS; i++) {
	// not the cleanest way but ...
	rooms[i].x=2; rooms[i].y=2; rooms[i].w=d.w; rooms[i].h=d.h;			
	}
  
  int ii=1;
  while (ii >= 1 ) {
	uint8_t wall_orientation = 2;
	// check room dimension and change wall orientation accordingly
	if (rooms[ii].w < rooms[ii].h) {
		if (rooms[ii].h >= 2*room_size+2) wall_orientation = 0; 	
	} else if (rooms[ii].w > rooms[ii].h) {
		if (rooms[ii].w >= 2*room_size+2) wall_orientation = 1;		
	} else {
		if (rooms[ii].w >= 2*room_size+2) wall_orientation = random(0,2);	
	}

  if (wall_orientation != 2) {
	int wx;
  	if (wall_orientation == 1) wx=random(1+room_size, rooms[ii].w-room_size);	
	if (d.tiles[rooms[ii].x+wx-1][rooms[ii].y-1]==2 || d.tiles[rooms[ii].x+wx-1][rooms[ii].y+rooms[ii].h] == 2) {
		if (random(1,3) == 1) wx++;		
		else wx--;
	}
  }
	
  for (int yy=2  //** continuing from here **/
  }	
}

I read the discussion about the map generation a few hours ago and thought I would try to write a simple map generator in C as well. I’m not sure it will be needed if you manage to port the Lua map generator, but here’s what I have so far:

I’m still working on dealing with some of the rooms being too large, but it has 2-tile vertical doors and 1-tile horizontal doors.

Here is the source:

It’s still kind of messy since it’s a WIP and I was trying to put it together as fast as possible.

2 Likes

Thats really good. I’m translating the lua to c++ on the fly and I’m not even sure it works.

Testing…

#define MAX_ROOMS 100 // 100 rooms max, I don't want to get into dynamic memory allocation here

struct Dungeon {
  uint8_t tiles[];
  uint8_t w;
  uint8_t h;		
}; // Dungeon structure definition

Dungeon d = {.w=48, .h=32, .tiles[48*32] = NULL}; // make a Dungeon instance called "d"

uint8_t wall_h = 1; //global variable wall_h, type is unsigned char (8 bits) value 0..255

uint8_t grid_w=0, grid_h=0, room_size=4; // multiple variables of same type can be declare in 1 row

/* ---------------
mapgen starts here
----------------*/

/* this is one type of comment in C */
// this is 1 row comment in C++

// decide on max iterations

void mapgen() { 
  // void means function does not return anything, {} mark the beginning and end of function
  // Dungeon& is a reference to a Dungeon instance  
  // blank the tile array	  
  for (int i=0; i<d.w; i++) {
	for (int j=0; j<d.h; j++) {
		d.tiles[i][j]=1; // all tiles set to 1 initially
		}
	} 	
  }
  // add outside walls
  for (int i=0; i<d.w; i++) {d.tiles[i]=2;d.tiles[(d.h-1)*d.w+i]=2;} //horiz walls
  for (int i=0; i<d.h; i++) {d.tiles[i*d.w]=2;d.tiles[i*(d.w)-1]=2;} //ver walls
}

void make_rooms() {
  struct Room {
    int8_t w;
    int8_t h;
    int8_t x;
    int8_t y;
  }; // define structure Room

  Room rooms[MAX_ROOMS]; 
  for (int i=0; i<MAX_ROOMS; i++) {
	// not the cleanest way but ...
	rooms[i].x=2; rooms[i].y=2; rooms[i].w=d.w; rooms[i].h=d.h;			
	}
  
  int ii=1;
  while (ii >= 1 ) {
	uint8_t wall_orientation = 2;
	// check room dimension and change wall orientation accordingly
	if (rooms[ii].w < rooms[ii].h) {
		if (rooms[ii].h >= 2*room_size+2) wall_orientation = 0; 	
	} else if (rooms[ii].w > rooms[ii].h) {
		if (rooms[ii].w >= 2*room_size+2) wall_orientation = 1;		
	} else {
		if (rooms[ii].w >= 2*room_size+2) wall_orientation = random(0,2);	
	}

  if (wall_orientation != 2) 
  {
  	if (wall_orientation == 1) 
	{
		int wx=random(1+room_size, rooms[ii].w-room_size);	
		if (d.tiles[rooms[ii].x+wx-1][rooms[ii].y-1]==2 || d.tiles[rooms[ii].x+wx-1][rooms[ii].y+rooms[ii].h] == 2) {
			if (random(1,3) == 1) wx++;		
			else wx--;
		}

		for (int yy=2, yy<rooms[ii].h, yy++) d.tiles[rooms[ii].x+wx-1][rooms[ii].y+yy]=2;

		d.tiles[rooms[ii].x+wx-1][rooms[ii].y]=34; //door?
  
		rooms[ii+1].x = rooms[ii].x+wx;
		rooms[ii+1].y = rooms[ii].y;
		rooms[ii+1].w = rooms[ii].w-wx;
		rooms[ii+1].h = rooms[ii].h;
  
		rooms[ii].w=wx-1;
	} else {
	
		int wy = random (1+room_size,rooms[ii].h-room_size);
		if (d.tiles[rooms[ii].x-1][rooms[ii].y-1] == 18 || d.tiles[rooms[ii].x+rooms[ii].w][rooms[ii].y+wy-1] == 18) {
			if (random(1,3)==1) wy++;
			else wy--;
		}
		
		for (int xx = 2; xx < rooms[ii].w; xx++) d.tiles[rooms[ii].x+xx][rooms[ii].y+wy-1] = 2;
	
		d.tiles[rooms[ii].x][rooms[ii].y+wy-1] = 18;
	
		rooms[ii+1].x = rooms[ii].x;
		rooms[ii+1].y = rooms[ii].y+wy;
		rooms[ii+1].w = rooms[ii].w;
		rooms[ii+1].h = rooms[ii].h-wy;
  
		rooms[ii].h=wy-1;
	}
	ii++;
  } else {
	ii--;  
  }
  } // while ii	
} // makerooms
2 Likes

That is awesome @wuuff!

Any chance to make some rooms be not rectangular? Like some L shape rooms etc. This would look awesome with our game, but I didn’t want to ask for it, ad we were struggling as we were :wink: and it seems you got some dungeon chops on you.

I am back home, but I pulled a muscle. I need some rest, but I will make sure we have bunch of item sprites before I will call it a night.

Waiting to see if what I implemented works in c :slight_smile:

1 Like

I think you have them flip-flopped. We’d have 2 tile high horizontal walls for a sort of 3/4 rpg view.

As for the generator; It looks so awesome so far! Depending on your tweaks for the room sizes and stuff I think this would be our best bet. Let’s wait and see what @jonne is hard at work on as well. It may be very hard to decide and have a new problem in our hands

2 Likes

I think I fixed the issue of having too-large rooms. I’m pretty happy with the generated maps now.

I think that perhaps very long walls need more than one door, but I can add that if anyone thinks this generator could be useful.

It 's easy to change map dimensions and minimum room size, too. Here’s a 32x32 map:

And here’s a 64x64 map with a larger minimum room size:

Source link is the same as in my previous post. I updated the gist.

4 Likes

By not rectangular, do you mean with irregular edges, like in the link you posted earlier in this thread (http://weblog.jamisbuck.org/2015/1/15/better-recursive-division-algorithm.html)? That will be more complex because I would have to keep track of the boundary between different regions. Right now it’s done by simply dividing a region in half recursively either horizontally or vertically. Making the rooms irregularly shaped is doable, but I don’t think I can do it soon because I have been putting off work I need to do and I can’t justify spending much more time on this for the next few days.

I agree that non-rectangular rooms would look awesome though! Maybe we could do it for a post-jam version of the game, and if people are still wanting to try participating in the jam, the jam version can use simpler map generation.

@trelemar, I was following some of the information from @adekto’s posts. I think that maybe the idea is that all walls with a blank space beneath them are automatically add a tile for the side of the wall underneath them (making all horizontal walls 2 tiles high). I was thinking of using a third tile index for showing the side of walls, but I wasn’t sure how people would want to use the generator.

This mockup by @VonBednar shows how horizontal walls are thicker:

https://talk.pokitto.com/uploads/default/original/1X/8083fc42e8824613628e9fb35ad1e0ff8a483433.png

I tried to make the maps I generate compatible with simply adding an extra brick tile below a wall if the area below is empty, which is why I made the minimum room height larger than the width. All rooms have one less tile of vertical walkable space than it appears from the text output of my generator. The output is only showing the “top” of the walls and not the sides, if that make sense.

So I said 2-tile vertical doors because the top tile of the vertical door is occupied by the brick wall tile showing the side of the wall. Sorry if my response is a bit hard to follow.

At least, that’s how I interpreted things after reading the thread. There was a lot to take in.

Edit: Re-reading your reply again, I think you were already saying that walls are 2-high, so I probably didn’t need to explain it. I think it was just a terminology mix-up. I think I get what you mean now (doors in horizontal walls are 2-high and doors in vertical walls are 1-high). So I was confused because I was thinking about it differently (ignoring the side-walls and expecting them to be added later, and therefore having the two switched). I can change the map generation to make all horizontal walls 2 tiles thick, depending on how the result is to be used.

IT WORKS OMG

Great job @wuuff!

I created a very simple function for creating the 2 tile thick horizontal walls and added it to the bottom of your file.

void mappretty(char map[][MAPSIZE],int width, int height){
    int i,j;
    for (i=0; i < height-1; i++) {
        for (j=0;j<width-1;j++){
            if (map[i][j]==1 && map[i+1][j]==0){
                map[i+1][j]=2;
            }
        }
    }
}

Seeing how you did this really gives me a new outlook on the project :slight_smile:

EDIT: Here’s the modified files to get this running so we can all compare with @VonBednar’s method using @jonne’s translation:

The main file:

#include "Pokitto.h"
#include <vector>
#include "sprites.h"
#include "mapgen.c"
Pokitto::Core game;

char dungeon[MAPSIZE][MAPSIZE];

struct entity{
    uint8_t x;
    uint8_t y;
    int8_t hp;
    uint8_t id;
};

#define ID_SKELETON_MAGE     9
#define ID_SKELETON_ARCHER   10
#define ID_SKELETON_WARIOR   11
#define ID_BLOOD_SKELETON    12
#define ID_BLOOD             13
#define ID_RAT               14
#define ID_SCROLL            15
#define ID_CHEST             16
#define ID_CHEST_OPEN        17
#define ID_MIMIC             18
#define ID_COIN              19
#define ID_COINS             20
#define ID_BAG               21

//globals
int entities_size = 2;
std::vector<entity> entities(entities_size);
char printer[40] = "";
int playerGold = 0;
int playerHP = 100;


bool colide(int id, int x, int y, bool c){
    if (entities[id].x == x && entities[id].y == y) return false;
    else return c;
}
void removeEntity(int i){

        using std::swap;
         std::swap(entities[i], entities.back());
    entities.pop_back();

}
bool entitiesLogic(int playerX, int playerY){
    bool nocolide = true;
    for(int i=0; i<entities.size(); ++i){

        switch(entities[i].id){
        case ID_CHEST:
            nocolide = colide(i,playerX,playerY,nocolide); //its wierd but works
            if(!colide(i,playerX,playerY,true)){
                    entities[i].id = ID_CHEST_OPEN;
                    sprintf(printer,"open chest, taken %i gold",  entities[i].hp);
                    playerGold += entities[i].hp;
                    entities[i].hp = 0;
            }
            break;
        case ID_CHEST_OPEN:


            break;
        case ID_MIMIC:
            nocolide = colide(i,playerX,playerY,nocolide); //its wierd but works
            if(entities[i].x > playerX && colide(i,playerX+1,playerY,true)) entities[i].x-=1;
            else if(!colide(i,playerX+1,playerY,true)) playerHP -=10;

            if(entities[i].x < playerX && colide(i,playerX-1,playerY,true)) entities[i].x+=1;
            else if(!colide(i,playerX-1,playerY,true)) playerHP -=10;

            if(entities[i].y > playerY && colide(i,playerX,playerY+1,true)) entities[i].y-=1;
            else if(!colide(i,playerX,playerY+1,true)) playerHP -=10;

            if(entities[i].y < playerY && colide(i,playerX,playerY-1,true)) entities[i].y+=1;
            else if(!colide(i,playerX,playerY-1,true)) playerHP -=10;

            if(!colide(i,playerX,playerY,true)){
                entities[i].hp -= 1;
                sprintf(printer,"hit mimic, hp: %i",  entities[i].hp);
                if(entities[i].hp == 0) removeEntity(i);
            }
            break;
        default:
            printf("unknown entety %i\n", entities[i].id);
            break;
        }
    }
    return nocolide;
}


void drawHP(int hp){
    //gui
        game.display.drawBitmap(212,0,UI1);
        game.display.drawFastVLine(219,3,158);
        game.display.drawFastVLine(211,3,158);
        game.display.drawBitmap(212,162,UI2);
        int UI_hp = hp * 0.78;

        if(hp >= 0){
            for(int i = 0; i < UI_hp; i++){
                game.display.drawBitmap(213,159-(i*2),UI4);
            }
            game.display.drawBitmap(213,160-((UI_hp+1)*2),UI3);
            game.display.drawBitmap(213,161,UI5);
        }
}
int main () {
srand(30);
mapinit(dungeon,MAPSIZE,MAPSIZE);
mapgen(dungeon,MAPSIZE,MAPSIZE,0,0,MAPSIZE-1,MAPSIZE-1);
mappretty(dungeon,MAPSIZE,MAPSIZE);
game.begin();
//mapgen(0,0,0,20,20);
game.display.loadRGBPalette(paletteCGA);
//game.display.setFont(fontAdventurer);
//game.display.persistence = true;
game.display.setInvisibleColor(0);
int playerX = 2;
int playerY = 2;


entities[0].id = ID_CHEST;
entities[0].x = 5;
entities[0].y = 3;
entities[0].hp = 100;
entities[1].id = ID_MIMIC;
entities[1].x = 15;
entities[1].y = 15;
entities[1].hp = 10;


while (game.isRunning()) {

    if (game.update()) {
        if (game.buttons.repeat(BTN_UP,4)){
            if (!dungeon[playerY-1][playerX]){
                if(entitiesLogic( playerX, playerY-1)) playerY --;
            }
        }
        if (game.buttons.repeat(BTN_DOWN,4)){
            if (!dungeon[playerY+1][playerX]){
                if(entitiesLogic( playerX, playerY+1)) playerY ++;
            }
        }
        if (game.buttons.repeat(BTN_LEFT,4)){
            if (!dungeon[playerY][playerX-1]){
                if(entitiesLogic( playerX-1, playerY)) playerX --;
            }
        }
        if (game.buttons.repeat(BTN_RIGHT,4)){
            if (!dungeon[playerY][playerX+1]){
                if(entitiesLogic( playerX+1, playerY)) playerX ++;
            }
        }
        for(int x =playerX-7; x<playerX+8; x++){ //7
            for(int y =playerY-6; y<playerY+6; y++){
                if(x >= 0 && y >= 0 && x <MAPSIZE && y < MAPSIZE){
                    game.display.drawBitmap(14*(x-playerX+7),14*(y-playerY+6),background[dungeon[y][x]]);
                }
            }
        }

        game.display.setCursor(0,168);
        game.display.color = 1;
        game.display.print(printer);



        drawHP(playerHP);

        for(int i=0; i<entities.size(); ++i){
            game.display.color = 0; //remove before release
            game.display.fillRect(14*(entities[i].x-playerX+7),14*(entities[i].y-playerY+6),14,14);//remove and fix before release
            game.display.drawBitmap(14*(entities[i].x-playerX+7),14*(entities[i].y-playerY+6),sprites[entities[i].id]);
        }

        game.display.drawBitmap(14*(7),14*(6),sprites[3]);
    }

}

return 1;
}

mapgen.c:

#include <stdio.h>
#include <stdlib.h>

#define MAPSIZE 64

void mapinit(char map[][MAPSIZE], int width, int height);
void mapgen(char map[][MAPSIZE], int mapwidth, int mapheight, int startx, int starty, int endx, int endy);
void mapprint(char map[][MAPSIZE], int width, int height);

void mapinit(char map[][MAPSIZE], int width, int height){
    int i,j;

    //Generate walls around the edges
    for( i = 0; i < width; i++ ){
        map[0][i] = 1;
        map[height-1][i] = 1;
    }
    for( j = 0; j < height; j++ ){
        map[j][0] = 1;
        map[j][width-1] = 1;
    }
}

#define HORIZONTAL 0
#define VERTICAL 1
#define MIN_WIDTH 6
#define MIN_HEIGHT 8
void mapgen(char map[][MAPSIZE], int mapwidth, int mapheight, int startx, int starty, int endx, int endy){
    int i,j,orientation,position,door,doorcount;
    int width = endx-startx;
    int height = endy-starty;

    if( width < MIN_WIDTH && height < MIN_HEIGHT ){
        return;
    }

    //Determine whether we will split the space
    //horizontally or vertically by choosing whichever
    //orientation is larger (this avoids extremely long rooms)
    if( width >= height ){
        //If there is a door (or more than one door!) into a small room,
        //we may not be able to generate a wall in any location!
        //so abort if room is min + number of horiz door tiles
        doorcount = 0;
        for( i = startx; i < endx; i++ ){
            if( map[starty][i] == 0 ) doorcount++;
            if( map[endy][i] == 0 ) doorcount++;
        }
        if( width < MIN_WIDTH + doorcount ){
            return;
        }
        orientation = VERTICAL;
        //puts("Trying vertical");
    }else{
        //If there is a door (or more than one door!) into a small room,
        //we may not be able to generate a wall in any location!
        //so abort if room is min + number of vert door tiles
        doorcount = 0;
        for( i = starty; i < endy; i++ ){
            if( map[i][startx] == 0 ) doorcount++;
            if( map[i][endx] == 0 ) doorcount++;
        }
        if( height < MIN_HEIGHT + doorcount ){
            return;
        }
        orientation = HORIZONTAL;
        //puts("Trying horizontal");
    }
    //printf("startx %d, starty %d\n",startx,starty);
    //mapprint(map,MAPSIZE,MAPSIZE);
    position = -1;
    if( orientation == HORIZONTAL ){
        //Make sure the position is valid:
        //1. It must have generated at least one number
        //2. It must not be too close to existing walls
        //3. It must not be over a door
        while( position == -1 || position < starty + (MIN_HEIGHT/2) || position > endy - (MIN_HEIGHT/2) || map[position][startx] == 0 || map[position][endx] == 0 ){
            position = starty + (rand()%height);
        }
        //Generate a door at a random position
        door = startx + 1 + (rand()%(width-1));
        //printf("HORIZ %d\n",position);
        for( i = startx; i < startx + width; i++ ){
            if( i != door )
                map[position][i] = 1;
        }
        //Recursively call to fill the two new spaces we generated
        mapgen(map, mapwidth, mapheight, startx, starty, endx,position);
        mapgen(map, mapwidth, mapheight, startx, position, endx, endy);
    }else if( orientation == VERTICAL ){
        //Make sure the position is valid:
        //1. It must have generated at least one number
        //2. It must not be too close to existing walls
        //3. It must not be over a door
        while( position == -1 || position < startx + (MIN_WIDTH/2) || position > endx - (MIN_WIDTH/2) || map[starty][position] == 0 || map[endy][position] == 0 ){
            position = startx + (rand()%width);
        }
        //Generate a door at a random position
        //(allocating space for it to be 2 high)
        door = starty + 1 + (rand()%(height-2));
        //printf("VERT %d\n",position);
        for( i = starty; i < starty + height; i++ ){
            if( i != door && i != door+1 )
                map[i][position] = 1;
        }
        //Recursively call to fill the two new spaces we generated
        mapgen(map, mapwidth, mapheight, startx, starty, position,endy);
        mapgen(map, mapwidth, mapheight, position, starty, endx, endy);
    }
}

void mapprint(char map[][MAPSIZE], int width, int height){
    int i,j;

    for( i = 0; i < height; i++ ){
        for( j = 0; j < width; j++ ){
            if( map[i][j] == 0 ){
                printf("0");
            }else if( map[i][j] == 1 ){
                printf("1");
            }
        }
        puts("");
    }
}

void mappretty(char map[][MAPSIZE],int width, int height){
    int i,j;
    for (i=0; i < height-1; i++) {
        for (j=0;j<width-1;j++){
            if (map[i][j]==1 && map[i+1][j]==0){
                map[i+1][j]=2;
            }
        }
    }
}
3 Likes

Here is @VonBednar 's Lua map generato combined to @adekto demo

Now you have choice what to do :grinning:

dungeon.h:

#ifndef DUNGEON_H
#define DUNGEON_H

#include <stdint.h>

#define MAX_ROOMS 100 // 100 rooms max, I don't want to get into dynamic memory allocation here

struct Dungeon {
  uint8_t w;
  uint8_t h;
  uint8_t tiles[50*50];
}; // Dungeon structure definition

struct Room {
    int8_t w;
    int8_t h;
    int8_t x;
    int8_t y;
}; // define structure Room

extern Dungeon d;
extern void dungeon_gen();
extern void make_rooms();

#endif // DUNGEON_H

Dungeon.cpp:

#include "Pokitto.h"
#include "dungeon.h"

Dungeon d = {48, 32}; // make a Dungeon instance called "d"

uint8_t wall_h = 1; //global variable wall_h, type is unsigned char (8 bits) value 0..255
uint8_t grid_w=0, grid_h=0, room_size=4; // multiple variables of same type can be declare in 1 row

/* ---------------
mapgen starts here
----------------*/

/* this is one type of comment in C */
// this is 1 row comment in C++

// decide on max iterations

void dungeon_gen() {
  // void means function does not return anything, {} mark the beginning and end of function
  // Dungeon& is a reference to a Dungeon instance
  // blank the tile array
  for (uint8_t i=0; i<d.w; i++) {
	for (uint8_t j=0; j<d.h; j++) {
		d.tiles[i+j*d.w]=1; // all tiles set to 1 initially
		}
	}

  // add outside walls
  for (int i=0; i<d.w; i++) {d.tiles[i]=2;d.tiles[(d.h-1)*d.w+i]=2;} //horiz walls
  for (int i=0; i<d.h; i++) {d.tiles[i*d.w]=2;d.tiles[(i+1)*(d.w)-1]=2;} //ver walls
}

void make_rooms() {
  struct Room {
    int8_t w;
    int8_t h;
    int8_t x;
    int8_t y;
  }; // define structure Room

  Room rooms[MAX_ROOMS];
  for (int i=0; i<MAX_ROOMS; i++) {
	// not the cleanest way but ...
	rooms[i].x=2; rooms[i].y=2; rooms[i].w=d.w; rooms[i].h=d.h;
	}

  int ii=1;
  while (ii >= 1 ) {
	uint8_t wall_orientation = 2;
	// check room dimension and change wall orientation accordingly
	if (rooms[ii].w < rooms[ii].h) {
		if (rooms[ii].h >= 2*room_size+2) wall_orientation = 0;
	} else if (rooms[ii].w > rooms[ii].h) {
		if (rooms[ii].w >= 2*room_size+2) wall_orientation = 1;
	} else {
		if (rooms[ii].w >= 2*room_size+2) wall_orientation = random(0,2);
	}

  if (wall_orientation != 2)
  {
  	if (wall_orientation == 1)
	{
		int wx=random(1+room_size, rooms[ii].w-room_size);
		if (d.tiles[(rooms[ii].x+wx-1)+(rooms[ii].y-1)*d.w]==2 || d.tiles[(rooms[ii].x+wx-1)+(rooms[ii].y+rooms[ii].h)*d.w] == 2) {
			if (random(1,3) == 1) wx++;
			else wx--;
		}

		for (int yy=2; yy<rooms[ii].h; yy++) d.tiles[(rooms[ii].x+wx-1)+(rooms[ii].y+yy)*d.w]=2;

		d.tiles[(rooms[ii].x+wx-1)+(rooms[ii].y)*d.w]=34; //door?

		rooms[ii+1].x = rooms[ii].x+wx;
		rooms[ii+1].y = rooms[ii].y;
		rooms[ii+1].w = rooms[ii].w-wx;
		rooms[ii+1].h = rooms[ii].h;

		rooms[ii].w=wx-1;
	} else {

		int wy = random (1+room_size,rooms[ii].h-room_size);
		if (d.tiles[(rooms[ii].x-1)+(rooms[ii].y-1)*d.w] == 18 || d.tiles[(rooms[ii].x+rooms[ii].w)+(rooms[ii].y+wy-1)*d.w] == 18) {
			if (random(1,3)==1) wy++;
			else wy--;
		}

		for (int xx = 2; xx < rooms[ii].w; xx++) d.tiles[(rooms[ii].x+xx)+(rooms[ii].y+wy-1)*d.w] = 2;

		d.tiles[(rooms[ii].x)+(rooms[ii].y+wy-1)*d.w] = 18;

		rooms[ii+1].x = rooms[ii].x;
		rooms[ii+1].y = rooms[ii].y+wy;
		rooms[ii+1].w = rooms[ii].w;
		rooms[ii+1].h = rooms[ii].h-wy;

		rooms[ii].h=wy-1;
	}
	ii++;
  } else {
	ii--;
  }
  } // while ii
  for (int i=0;i<d.w*d.h;i++) if (d.tiles[i]==1) d.tiles[i]=0;
} // makerooms

And finally code that uses it:

#include "Pokitto.h"
#include <vector>
#include "sprites.h"
#include "dungeon.h"
Pokitto::Core game;


struct entity{
    uint8_t x;
    uint8_t y;
    int8_t hp;
    uint8_t id;
};

#define ID_SKELETON_MAGE     9
#define ID_SKELETON_ARCHER   10
#define ID_SKELETON_WARIOR   11
#define ID_BLOOD_SKELETON    12
#define ID_BLOOD             13
#define ID_RAT               14
#define ID_SCROLL            15
#define ID_CHEST             16
#define ID_CHEST_OPEN        17
#define ID_MIMIC             18
#define ID_COIN              19
#define ID_COINS             20
#define ID_BAG               21

int entities_size = 2;
std::vector<entity> entities(entities_size);


void entitiesLogic(int playerX, int playerY){
    for(int i=0; i<entities.size(); ++i){

        switch(entities[i].id){
        case ID_CHEST:


            break;
        case ID_CHEST_OPEN:


            break;
        case ID_MIMIC:
            if(entities[i].x > playerX) entities[i].x-=1;
            if(entities[i].x < playerX) entities[i].x+=1;
            if(entities[i].y > playerY) entities[i].y-=1;
            if(entities[i].y < playerY) entities[i].y+=1;
            break;
        default:
            printf("unknown entety %i\n", entities[i].id);
            break;
        }
    }
}

void drawHP(int hp){
    //gui
        game.display.drawBitmap(212,0,UI1);
        game.display.drawFastVLine(219,3,158);
        game.display.drawFastVLine(211,3,158);
        game.display.drawBitmap(212,162,UI2);
        int UI_hp = hp * 0.78;

        if(hp >= 0){
            for(int i = 0; i < UI_hp; i++){
                game.display.drawBitmap(213,159-(i*2),UI4);
            }
            game.display.drawBitmap(213,160-((UI_hp+1)*2),UI3);
            game.display.drawBitmap(213,161,UI5);
        }
}
int main () {

game.begin();
dungeon_gen();
make_rooms();
//mapgen(0,0,0,20,20);
game.display.loadRGBPalette(paletteCGA);
//game.display.setFont(fontAdventurer);
//game.display.persistence = true;
game.display.setInvisibleColor(0);
int playerX = 2;
int playerY = 2;
int playerHP = 100;

entities[0].id = ID_CHEST;
entities[0].x = 5;
entities[0].y = 3;
entities[1].id = ID_MIMIC;
entities[1].x = 15;
entities[1].y = 15;


while (game.isRunning()) {

    if (game.update()) {
        if (game.buttons.repeat(BTN_UP,4)){
            if (!d.tiles[(playerY-1)*d.w+(playerX)]){
                playerY --;
                entitiesLogic( playerX, playerY);
            }
        }
        if (game.buttons.repeat(BTN_DOWN,4)){
            if (!d.tiles[(playerY+1)*d.w+(playerX)]){
                playerY ++;
                entitiesLogic( playerX, playerY);
            }
        }
        if (game.buttons.repeat(BTN_LEFT,4)){
            if (!d.tiles[(playerY)*d.w+(playerX-1)]){
                playerX --;
                entitiesLogic( playerX, playerY);
            }
        }
        if (game.buttons.repeat(BTN_RIGHT,4)){
            if (!d.tiles[(playerY)*d.w+(playerX+1)]){
                playerX ++;
                entitiesLogic( playerX, playerY);
            }
        }

        for (int i=0; i<d.w; i++) {
            for (int j=0; j<d.h; j++) {
                game.display.color = d.tiles[i+j*d.w];
                game.display.drawPixel(i,j);
            }
        }


        for(int x =playerX-7; x<playerX+8; x++){ //7
            for(int y =playerY-6; y<playerY+6; y++){
                if(x >= 0 && y >= 0 && x <20 && y < 20){
                    game.display.drawBitmap(14*(x-playerX+7),14*(y-playerY+6),background[d.tiles[x+y*d.w]]);
                }
            }
        }

        game.display.setCursor(0,168);
        game.display.color = 1;
        game.display.print("OMG! this font just fits on the screen");
        game.display.drawBitmap(14*(7),14*(6),sprites[3]);


        drawHP(playerHP);

        for(int i=0; i<entities.size(); ++i){
            game.display.color = 0; //remove before release
            game.display.fillRect(14*(entities[i].x-playerX+7),14*(entities[i].y-playerY+6),14,14);//remove and fix before release
            game.display.drawBitmap(14*(entities[i].x-playerX+7),14*(entities[i].y-playerY+6),sprites[entities[i].id]);
        }

    }

}

return 1;
}

3 Likes

2 hours later we have two working mapgens

Who said we can’t do this? :wink:

2 Likes

I’m ecstatic right now. This is amazing! which one do we use everyone?

I think @wuuff 's is actually closer to working. @VonBednar 's lua thing still needs work for the doorways and stuff to be in proper places

But I gotta say translating lua to C++ is not a big thing at all

edit:

stylistic point: I think there should be some “broken down” walls and rubble. This palace is too clean. Also: big halls should have single blocks as columns in the middle. You can’t support a big roof with no colums - that isn’t goblin technology !

1 Like

Yeah I know @VonBednar Planned on doing more sprites and stuff so we can implement different walls and rubble.

I also think that we should take advantage of using classes for enemies opposed to @adektos current approach. This would save a ton of code and similar enemies wouldn’t be too hard to implement. Classes just seem to flow a lot better for a roguelike.

1 Like

I will put a bonus gift in the shipment of Pokittos to all of you involved in creating this if we get something resembling a game on time into the #cgajam. extra color case, “I survived CGAjam on Pokitto” T-shirt… who knows ? :grin:

1 Like

Awesome!

I am personally proud that I could pull off a dungeon generator at all! Even if it was translating someone else’s code. I might make a roguelike in pico-8 at some point.

With all that in mind, I vote for @wuuff’s map gen, it will obviously be much more streamlined than whatever I can come up with :wink:

@wuuff - yeah, messing about with the dungeon gen might be better for the post jam version. If you want to try something, we can always choose couple rooms (2 or 3 on the map) and delete the wall between a chosen room, and a room adjacent to make some basic L shapes.

@jonne - yeah, I will add ornaments. Rubble, columns, more wall styles (like the one with the shield) will be added. Tonight I will work on making some items to pickup and have in inventory :wink:

@trelemar - I vote for classes as well. I feel like we could benefit from having someone in charge. @jonne?