📄 dungeongenerator.cpp
字号:
/*************************************************************************** dungeongenerator.cpp - description ------------------- begin : Thu May 15 2003 copyright : (C) 2003 by Gabor Torok email : cctorok@yahoo.com ***************************************************************************//*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/#include "dungeongenerator.h"/*width - max 31height - max 31curvyness - in %, the lower the more twisty mazesparseness - (1-5) the higher the more sparse (more empty space)loopyness - in %, the higher the more loops in the mazeroomcountrooom max widthroom max heightobject count*/const int DungeonGenerator::levels[][9] = { { 10, 20, 90, 5, 1, 2, 4, 4, 5 }, { 15, 15, 70, 5, 10, 3, 6, 4, 10 }, { 15, 15, 50, 4, 20, 4, 5, 5, 15 }, { 20, 20, 50, 6, 20, 5, 6, 5, 20 }, { 25, 25, 40, 6, 20, 5, 6, 5, 25 }, { 30, 25, 5, 6, 25, 6, 6, 6, 30 }, { 31, 31, 3, 5, 25, 6, 7, 7, 35 }};/** Pre-generated maps: x,y,w,h, starting coord roomCount, roomDimensions: x,y,w,h,furnish(0,1) map: #-room, +-floor, nsew-doors (by facing) */const MapLocation DungeonGenerator::location[] = { { 0,0,5,12, { {2*unitSide+16, unitSide+6}, {2*unitSide+13, unitSide+9}, {2*unitSide+19, unitSide+9}, {2*unitSide+16, unitSide+12} }, false, 5, { {0,0,5,4,0}, {0,5,2,3,1}, {3,5,2,3,1}, {0,9,2,3,1}, {3,9,2,3,1} }, { " ## ", " ## ", " ## ", " s# ", " + ", "##+##", "#e+w#", "s# #s", "+ +", "n# #n", "#e+w#", "## ##" }, 25, { { "BOARD", 2*unitSide+11, unitSide + 1, 0 }, { "COLUMN", 2*unitSide+3, unitSide, 0 }, { "COLUMN", 2*unitSide+26, unitSide, 0 }, { "COLUMN", 2*unitSide+3, unitSide+8, 0 }, { "COLUMN", 2*unitSide+26, unitSide+8, 0 }, { "COLUMN", 2*unitSide+3, unitSide+16, 0 }, { "COLUMN", 2*unitSide+26, unitSide+16, 0 }, { "COLUMN", 2*unitSide+3, unitSide+24, 0 }, { "COLUMN", 2*unitSide+26, unitSide+24, 0 }, { "COLUMN", 2*unitSide+3, unitSide+32, 0 }, { "COLUMN", 2*unitSide+26, unitSide+32, 0 }, { "COLUMN", 2*unitSide+3, unitSide+40, 0 }, { "COLUMN", 2*unitSide+26, unitSide+40, 0 }, { "BRAZIER", 2*unitSide+7, unitSide+8, 2 }, { "BRAZIER_BASE", 2*unitSide+7, unitSide+8, 0 }, { "BRAZIER", 2*unitSide+22, unitSide+8, 2 }, { "BRAZIER_BASE", 2*unitSide+22, unitSide+8, 0 }, { "BRAZIER", 2*unitSide+7, unitSide+16, 2 }, { "BRAZIER_BASE", 2*unitSide+7, unitSide+16, 0 }, { "BRAZIER", 2*unitSide+22, unitSide+16, 2 }, { "BRAZIER_BASE", 2*unitSide+22, unitSide+16, 0 }, { "BRAZIER", 2*unitSide+7, unitSide+24, 2 }, { "BRAZIER_BASE", 2*unitSide+7, unitSide+24, 0 }, { "BRAZIER", 2*unitSide+22, unitSide+24, 2 }, { "BRAZIER_BASE", 2*unitSide+22, unitSide+24, 0 } } }};DungeonGenerator::DungeonGenerator(Scourge *scourge, int level, bool stairsDown, bool stairsUp, Mission *mission){ this->scourge = scourge; this->level = level; this->stairsUp = stairsUp; this->stairsDown = stairsDown; this->mission = mission; this->status = 0; initByLevel(); this->nodes = (Uint16**)malloc(sizeof(void*) * width); for(int i = 0; i < width; i++) { nodes[i] = (Uint16*)malloc(sizeof(void*) * height); } for(int x = 0; x < width; x++) { for(int y = 0; y < height; y++) { nodes[x][y] = UNVISITED; } } notVisitedCount = width * height; notVisited = (int*)new int[notVisitedCount]; for(int i = 0; i < notVisitedCount; i++) { notVisited[i] = i; } visitedCount = 0; visited = (int*)new int[notVisitedCount];}DungeonGenerator::~DungeonGenerator(){ for(int i = 0; i < width; i++) { free(nodes[i]); } free(nodes); delete[] notVisited; delete[] visited;}void DungeonGenerator::initByLevel() { if(level < 1) level = 1; this->width = levels[level - 1][dgWIDTH]; this->height = levels[level - 1][dgHEIGHT]; this->curvyness = levels[level - 1][dgCURVYNESS]; this->sparseness = levels[level - 1][dgSPARSENESS]; this->loopyness = levels[level - 1][dgLOOPYNESS]; this->roomCount = levels[level - 1][dgROOMCOUNT]; this->roomMaxWidth = levels[level - 1][dgROOMMAXWIDTH]; this->roomMaxHeight = levels[level - 1][dgROOMMAXHEIGHT]; this->objectCount = levels[level - 1][dgOBJECTCOUNT]; this->monsters = true;}void DungeonGenerator::makeRooms() { int rw, rh, px, py; int best, score; for(int i = 0; i < roomCount; i++) { // create a room rw = (int) ((double)(roomMaxWidth / 2) * rand()/RAND_MAX) + (roomMaxWidth / 2); rh = (int) ((double)(roomMaxHeight / 2) * rand()/RAND_MAX) + (roomMaxHeight / 2); best = -1; px = py = -1; // find best place for this room if(i % 2) { for(int x = 0; x < width - rw; x++) { for(int y = 0; y < height - rh; y++) { score = getScore(x, y, rw, rh); if(score > 0 && (best == -1 || score < best)) { best = score; px = x; py = y; } } } } else { for(int x = width - rw - 1; x >= 0; x--) { for(int y = height - rh - 1; y >= 0; y--) { score = getScore(x, y, rw, rh); if(score > 0 && (best == -1 || score < best)) { best = score; px = x; py = y; } } } } // set the room if(px > -1 && py > -1) { // save the room info room[i].x = px; room[i].y = py; room[i].w = rw; room[i].h = rh; for(int x = px; x < px + rw; x++) { for(int y = py; y < py + rh; y++) { nodes[x][y] = ROOM + N_PASS + S_PASS + E_PASS + W_PASS; // 1. connect the room to the passage // 2. put in some doors: after each door, the chance of there being // another door decreases. // 3. put in the walls if(x == px) { if(x > 0 && nodes[x - 1][y] != UNVISITED) { nodes[x - 1][y] |= E_PASS; } else { nodes[x][y] -= W_PASS; } } if(x == px + rw - 1) { if(x < width - 1 && nodes[x + 1][y] != UNVISITED) { nodes[x + 1][y] |= W_PASS; } else { nodes[x][y] -= E_PASS; } } if(y == py) { if(y > 0 && nodes[x][y - 1] != UNVISITED) { nodes[x][y - 1] |= S_PASS; } else { nodes[x][y] -= N_PASS; } } if(y == py + rh - 1) { if(y < height - 1 && nodes[x][y + 1] != UNVISITED) { nodes[x][y + 1] |= N_PASS; } else { nodes[x][y] -= S_PASS; } } } } // add doors for(int x = px; x < px + rw; x++) { for(int y = py; y < py + rh; y++) { if(x == px) { if(x > 0 && nodes[x - 1][y] != UNVISITED && nodes[x - 1][y] < ROOM) { nodes[x][y] |= W_DOOR; } } if(x == px + rw - 1) { if(x < width - 1 && nodes[x + 1][y] != UNVISITED && nodes[x + 1][y] < ROOM) { nodes[x][y] |= E_DOOR; } } if(y == py) { if(y > 0 && nodes[x][y - 1] != UNVISITED && nodes[x][y - 1] < ROOM) { nodes[x][y] |= N_DOOR; } } if(y == py + rh - 1) { if(y < height - 1 && nodes[x][y + 1] != UNVISITED && nodes[x][y + 1] < ROOM) { nodes[x][y] |= S_DOOR; } } } } } }}int DungeonGenerator::getScore(int px, int py, int rw, int rh) { int score = 0; for(int x = px; x < px + rw; x++) { for(int y = py; y < py + rh; y++) { if(nodes[x][y] == UNVISITED) { if(x < width - 1 && nodes[x + 1][y] != UNVISITED) score++; if(x > 0 && nodes[x - 1][y] != UNVISITED) score++; if(y < height - 1 && nodes[x][y + 1] != UNVISITED) score++; if(y > 0 && nodes[x][y - 1] != UNVISITED) score++; if(x < width - 1 && nodes[x + 1][y] >= ROOM) score+=100; if(x > 0 && nodes[x - 1][y] >= ROOM) score+=100; if(y < height - 1 && nodes[x][y + 1] >= ROOM) score+=100; if(y > 0 && nodes[x][y - 1] >= ROOM) score+=100; } else if(nodes[x][y] >= ROOM) { score += 100; } else { score += 3; } } } return score;}void DungeonGenerator::makeLoops() { for(int i = 0; i < sparseness; i++) { for(int x = 0; x < width; x++) { for(int y = 0; y < height; y++) { switch(nodes[x][y]) { case N_PASS: case S_PASS: case E_PASS: case W_PASS: if((int) (100.0 * rand()/RAND_MAX) <= loopyness) generatePassage(x, y, false); break; default: break; } } } } }void DungeonGenerator::makeSparse() { for(int i = 0; i < sparseness; i++) { for(int x = 0; x < width; x++) { for(int y = 0; y < height; y++) { switch(nodes[x][y]) { case N_PASS: nodes[x][y] = UNVISITED; if(y > 0) { nodes[x][y - 1] -= S_PASS; } break; case S_PASS: nodes[x][y] = UNVISITED; if(y < height - 1) { nodes[x][y + 1] -= N_PASS; } break; case E_PASS: nodes[x][y] = UNVISITED; if(x < width - 1) { nodes[x + 1][y] -= W_PASS; } break; case W_PASS: nodes[x][y] = UNVISITED; if(x > 0) { nodes[x - 1][y] -= E_PASS; } break; default: break; } } } }}void DungeonGenerator::generateMaze() { int x, y; //fprintf(stderr, "Starting maze w=%d h=%d\n", width, height); nextNotVisited(&x, &y); while(notVisitedCount > 0) { // draw the passage generatePassage(x, y, true); // select a starting point nextVisited(&x, &y); if(x == -1) break; }}void DungeonGenerator::generatePassage(const int sx, const int sy, const bool stopAtVisited) { //char line[80];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -