📄 oublietteplan.cpp
字号:
/******************************************************************************** Copyright (C) 2005-2006 Trolltech ASA. All rights reserved.**** This file is part of the Qt Designer of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://www.trolltech.com/products/qt/opensource.html**** If you are unsure which license is appropriate for your use, please** review the following information:** http://www.trolltech.com/products/qt/licensing.html or contact the** sales department at sales@trolltech.com.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include <QtCore/QTextStream>#include "oublietteplan.h"#include "tile.h"#include <stdlib.h>#include <assert.h>#include <time.h>OublietteLevel::OublietteLevel(int width, int height, int totalFeatures) : m_size(width, height), m_totalFeatures(totalFeatures), m_totalItems(0){ srand(::time(0)); m_map = new Tile[m_size.width() * m_size.height()]; generateOubliette();}OublietteLevel::~OublietteLevel(){ for (int y = 0; y < m_size.height(); ++y) { for (int x = 0; x < m_size.width(); ++x) { qDeleteAll(tile(x, y).items); } } delete [] m_map;}Tile OublietteLevel::tile(int x, int y) const{ if (y < 0 || x < 0 || y >= m_size.height() || x >= m_size.width()) return Tile(); // bit of a lie, but it makes gereneration easier... return m_map[y * m_size.width() + x];}void OublietteLevel::setTile(int x, int y, Tile element){ assert((y >= 0 && y < m_size.height()) && (x >= 0 && x < m_size.width())); m_map[y * m_size.width() + x] = element;}struct TmpStruct { const char *name; const char *desc; const char *path;} bcards[] = {#include "names.txt" , {0 , 0, 0}};void OublietteLevel::generateOubliette(){ m_roomList.clear(); QRect levelRect(QPoint(0, 0), m_size); fillRect(levelRect, Tile()); QRect initalRoom(0, 0, 10, 10); initalRoom.moveCenter(levelRect.center()); digRoom(initalRoom, Tile::Lit); m_roomList << initalRoom; int featureCount = 0; while (featureCount < m_totalFeatures) { QPoint point = findWall(); // pick a feature, make sure there is room for it, if there isn't, then start over // Otherwise place it and find another feature. Do this until we've placed // the total number of feature we want. Try it a couple of times... for (int attempts = 0; attempts < 3; ++attempts) { if (placeFeature(pickFeature(), point)) { setTile(point, Tile(Tile::ClosedDoor)); ++featureCount; break; } } } QList<struct TmpStruct *> names; for (int i = 0; bcards[i].name; ++i) names << &bcards[i]; m_totalItems = names.size(); int x, y; QPoint centerPoint = QRect(0, 0, m_size.width(), m_size.height()).center(); QPoint itemPoint; for (int i = 0; i < m_totalItems; ++i) { do { QRect r = m_roomList.at(rand() % m_roomList.size()); x = rand() % (r.width() - 2); y = rand() % (r.height() - 2); itemPoint.rx() = r.x() + x + 1; itemPoint.ry() = r.y() + y + 1; } while (itemPoint == centerPoint); int card = rand() % names.size(); TmpStruct *tmp = names.at(card); names.removeAt(card); addItemToTile(itemPoint, new BusinessCard(QString::fromUtf8(tmp->name), QString::fromUtf8(tmp->desc), QString::fromUtf8(tmp->path))); } // Now that everything is built, go through and mark the inital room explored... for (int y = initalRoom.top(); y < initalRoom.bottom() + 1; ++y) { for (int x = initalRoom.left(); x < initalRoom.right() + 1; ++x) { Tile t = tile(x, y); t.flags |= Tile::Explored; setTile(x, y, t); } }}OublietteLevel::LevelFeature OublietteLevel::pickFeature() const{ int roll = rand() % 100; LevelFeature ret; if (roll >= 0 && roll < 20) ret = HorizontalCorridor; else if (roll >= 20 && roll < 40) ret = VerticalCorridor; else if (roll >= 40 && roll < 50) ret = SmallHorizontalCorridor; else if (roll >= 50 && roll < 60) ret = SmallVerticalCorridor; else if (roll >= 60 && roll < 75) ret = FiveByFiveRoom; else if (roll >= 75 && roll < 85) ret = ThreeByThreeRoom; else ret = TenByTenRoom; return ret;}QRect OublietteLevel::boundingRect(LevelFeature feature) const{ QRect ret; switch (feature) { case HorizontalCorridor: ret.setRect(0, 0, 17, 3); break; case SmallHorizontalCorridor: ret.setRect(0, 0, 10, 3); break; case VerticalCorridor: ret.setRect(0, 0, 3, 17); break; case SmallVerticalCorridor: ret.setRect(0, 0, 10, 3); break; case ThreeByThreeRoom: ret.setRect(0, 0, 5, 5); break; case FiveByFiveRoom: ret.setRect(0, 0, 7, 7); break; case TenByTenRoom: ret.setRect(0, 0, 12, 12); break; default: break; } return ret;}bool OublietteLevel::checkForFeatures(const QRect &rect) const{ // Simple checks first... if (rect.right() + 1 > m_size.width() || rect.left() < 0 || rect.top() < 0 || rect.bottom() + 1> m_size.height()) return false; for (int y = rect.top(); y < rect.bottom(); ++y) { for (int x = rect.left(); x < rect.right(); ++x) { Tile le = tile(x, y); if (le.type != Tile::Earth) return false; } } return true;}bool OublietteLevel::placeFeature(LevelFeature feature, const QPoint &pt){ QRect br = boundingRect(feature); int deltaX = 0; int deltaY = 0; if (tile(pt - QPoint(1, 0)).type == Tile::Floor) { // Place it East br.moveCenter(pt + QPoint(br.center().x() + 1, 0)); deltaX = -1; } else if (tile(pt + QPoint(1, 0)).type == Tile::Floor) { // West br.moveCenter(pt - QPoint(br.center().x(), 0)); } else if (tile(pt + QPoint(0, 1)).type == Tile::Floor) { // North br.moveCenter(pt - QPoint(0, br.center().y())); } else { // by elimination br.moveCenter(pt + QPoint(0, br.center().y() + 1)); deltaY = -1; } if (checkForFeatures(br)) { br.adjust(deltaX, deltaY, 0, 0); m_roomList << br; dig(feature, br); return true; } return false;}void OublietteLevel::digRoom(const QRect &rect, Tile::TileFlags flags){ // cheap trick for now, fill with the wall a little bigger and then the room QRect interiorRect = rect.adjusted(1, 1, -1, -1); fillRect(rect, Tile(Tile::Wall, flags)); fillRect(interiorRect, Tile(Tile::Floor, flags));}void OublietteLevel::dig(LevelFeature /*feature*/, const QRect &rect){ digRoom(rect);}void OublietteLevel::printOubliette() const{ // print out the darn thing... QString str; for (int y = 0; y < m_size.height(); ++y) { str.clear(); for (int x = 0; x < m_size.width(); ++x) { str += QString::number(tile(x, y).type); } qDebug("y: %2d: %s", y, str.toLatin1().data()); } qDebug();}OubliettePlan::OubliettePlan(int numLevels) : m_totalLevels(numLevels){ m_levels.resize(m_totalLevels); for (int i = 0; i < m_totalLevels; ++i) { m_levels[i] = new OublietteLevel(128, 128, 150); }}OubliettePlan::~OubliettePlan(){ qDeleteAll(m_levels); m_levels.clear();}OublietteLevel *OubliettePlan::level(int level) const{ return m_levels[level - 1];}void OublietteLevel::fillRect(int x, int y, int width, int height, Tile le){ for (int r = y; r < y + height; ++r) { for (int c = x; c < x + width; ++c) { setTile(c, r, le); } }}QPoint OublietteLevel::findWall() const{ QPoint ret; // randly walk through the oubliette and find a point, // if it is a wall that isn't a corner we are in good shape. // Technically we could get in here forever, but there is a very big chance that we will // break out. for (;;) { ret = QPoint(rand() % m_size.width(), rand() % m_size.height()); // Try to see if it works. Tile le = tile(ret); if (le.type == Tile::Wall) { // Check for the floor nearby if (tile(ret + QPoint(0, 1)).type == Tile::Floor || tile(ret + QPoint(0, -1)).type == Tile::Floor || tile(ret + QPoint(1, 0)).type == Tile::Floor || tile(ret + QPoint(-1, 0)).type == Tile::Floor) break; } } return ret;}void OublietteLevel::updateTileFlags(int x, int y, Tile::TileFlags flags){ assert(y >= 0 && y < m_size.width() && x >=0 && y < m_size.height()); m_map[y * m_size.width() + x].flags |= flags;}void OublietteLevel::clearTileFlags(int x, int y){ assert(y >= 0 && y < m_size.width() && x >=0 && y < m_size.height()); m_map[y * m_size.width() + x].flags = Tile::Default;}bool OublietteLevel::blockLOS(int x, int y){ Tile::Type t = tile(x, y).type; return t == Tile::Wall || t == Tile::ClosedDoor;}void OublietteLevel::addItemToTile(int x, int y, const Item *item){ m_map[y * m_size.width() + x].items.append(item);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -