| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 | /* * CDrawRoadsOperation.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * * License: GNU General Public License v2.0 or later * Full text of license available in license.txt file, in main folder * */#include "StdInc.h"#include "CDrawRoadsOperation.h"#include "CMap.h"#include "../RoadHandler.h"#include "../RiverHandler.h"#include "../GameLibrary.h"#include <vstd/RNG.h>VCMI_LIB_NAMESPACE_BEGINconst std::vector<CDrawLinesOperation::LinePattern> CDrawLinesOperation::patterns ={	//single tile. fall-back pattern	{		{          "-","-","-",          "-","+","-",          "-","-","-"        },        {14,14},        {9,9},        false,        false	},	//Road straight with angle	{		{          "?","-","+",          "-","+","+",          "+","+","?"        },        {2,5},        {-1,-1},        true,        true	},	//Turn	{		{          "?","-","?",          "-","+","+",          "?","+","?"        },        {0,1},        {0,3},        true,        true	},	//Dead end horizontal	{		{          "?","-","?",          "-","+","+",          "?","-","?"        },        {15,15},{11,12},        true,        false	},	//Dead end vertical	{		{          "?","-","?",          "-","+","-",          "?","+","?"        },        {14,14},{9,10},        false,        true	},	//T-cross horizontal	{		{          "?","+","?",          "-","+","+",          "?","+","?"        },        {6,7},{7,8},        true,        false	},	//T-cross vertical	{		{          "?","-","?",          "+","+","+",          "?","+","?"        },        {8,9},{5,6},        false,        true	},	//Straight Horizontal	{		{          "?","-","?",          "+","+","+",          "?","-","?"        },        {12,13},{11,12},        false,        false	},	//Straight Vertical	{		{          "?","+","?",          "-","+","-",          "?","+","?"        },        {10,11},{9,10},        false,        false	},	//X-cross	{		{          "?","+","?",          "+","+","+",          "?","+","?"        },        {16,16},{4,4},        false,        false	}};static bool ruleIsNone(const std::string & rule){	return rule == "-";}static bool ruleIsSomething(const std::string & rule){	return rule == "+";}#ifndef NDEBUGstatic bool ruleIsAny(const std::string & rule){	return rule == "?";}#endif///CDrawLinesOperationCDrawLinesOperation::CDrawLinesOperation(CMap * map, CTerrainSelection terrainSel, vstd::RNG * gen):	CMapOperation(map),	terrainSel(std::move(terrainSel)),	gen(gen){}///CDrawRoadsOperationCDrawRoadsOperation::CDrawRoadsOperation(CMap * map, const CTerrainSelection & terrainSel, RoadId roadType, vstd::RNG * gen):	CDrawLinesOperation(map, terrainSel,gen),	roadType(roadType){}///CDrawRiversOperationCDrawRiversOperation::CDrawRiversOperation(CMap * map, const CTerrainSelection & terrainSel, RiverId riverType, vstd::RNG * gen):	CDrawLinesOperation(map, terrainSel, gen),	riverType(riverType){}void CDrawLinesOperation::execute(){	std::set<int3> invalidated;	for(const auto & pos : terrainSel.getSelectedItems())	{		executeTile(map->getTile(pos));		auto rect = extendTileAroundSafely(pos);		rect.forEach([&invalidated](const int3 & pos)		{			invalidated.insert(pos);		});	}	updateTiles(invalidated);}void CDrawLinesOperation::undo(){  //TODO}void CDrawLinesOperation::redo(){  //TODO}void CDrawLinesOperation::flipPattern(LinePattern& pattern, int flip) const{	//todo: use cashing here and also in terrain patterns	if(flip == 0)	{		return;	}	if(flip == FLIP_PATTERN_HORIZONTAL || flip == FLIP_PATTERN_BOTH)	{		for(int i = 0; i < 3; ++i)		{			int y = i * 3;			std::swap(pattern.data[y], pattern.data[y + 2]);		}	}	if(flip == FLIP_PATTERN_VERTICAL || flip == FLIP_PATTERN_BOTH)	{		for(int i = 0; i < 3; ++i)		{			std::swap(pattern.data[i], pattern.data[6 + i]);		}	}}void CDrawLinesOperation::updateTiles(std::set<int3> & invalidated){	for(const int3 & coord : invalidated)	{		TerrainTile & tile = map->getTile(coord);		ValidationResult result(false);		if(!needUpdateTile(tile))			continue;		int bestPattern = -1;		for(int k = 0; k < patterns.size(); ++k)		{			result = validateTile(patterns[k], coord);			if(result.result)			{				bestPattern = k;				break;			}		}		if(bestPattern != -1)		{			updateTile(tile, patterns[bestPattern], result.flip);		}	}}CDrawLinesOperation::ValidationResult CDrawLinesOperation::validateTile(const LinePattern & pattern, const int3 & pos){	ValidationResult result(false);	if(!canApplyPattern(pattern))		return result;	for(int flip = 0; flip < 4; ++flip)	{		if((flip == FLIP_PATTERN_BOTH) && !(pattern.hasHFlip && pattern.hasVFlip))			continue;		if((flip == FLIP_PATTERN_HORIZONTAL) && !pattern.hasHFlip)			continue;		if((flip == FLIP_PATTERN_VERTICAL) && !(pattern.hasVFlip))			continue;		LinePattern flipped = pattern;		flipPattern(flipped, flip);		bool validated = true;		for(int i = 0; i < 9; ++i)		{			if(4 == i)				continue;			int cx = pos.x + (i % 3) - 1;			int cy = pos.y + (i / 3) - 1;			int3 currentPos(cx, cy, pos.z);			bool hasSomething = map->isInTheMap(currentPos) && tileHasSomething(currentPos);			if(ruleIsSomething(flipped.data[i]))			{				if(!hasSomething)				{					validated = false;					break;				}			}			else if(ruleIsNone(flipped.data[i]))			{				if(hasSomething)				{					validated = false;					break;				}			}			else			{				assert(ruleIsAny(flipped.data[i]));			}		}		if(validated)		{			result.result = true;			result.flip = flip;			return result;		}	}	return result;}std::string CDrawRoadsOperation::getLabel() const{	return "Draw Roads";}std::string CDrawRiversOperation::getLabel() const{	return "Draw Rivers";}void CDrawRoadsOperation::executeTile(TerrainTile & tile){	tile.roadType = roadType;}void CDrawRiversOperation::executeTile(TerrainTile & tile){	tile.riverType = riverType;}bool CDrawRoadsOperation::canApplyPattern(const LinePattern & pattern) const{	return pattern.roadMapping.first >= 0;}bool CDrawRiversOperation::canApplyPattern(const LinePattern & pattern) const{	return pattern.riverMapping.first >= 0;}bool CDrawRoadsOperation::needUpdateTile(const TerrainTile & tile) const{	return tile.hasRoad();}bool CDrawRiversOperation::needUpdateTile(const TerrainTile & tile) const{	return tile.hasRiver();}bool CDrawRoadsOperation::tileHasSomething(const int3& pos) const{	return map->getTile(pos).hasRoad();}bool CDrawRiversOperation::tileHasSomething(const int3& pos) const{	return map->getTile(pos).hasRiver();}void CDrawRoadsOperation::updateTile(TerrainTile & tile, const LinePattern & pattern, const int flip){	const std::pair<int, int> & mapping  = pattern.roadMapping;	tile.roadDir = gen->nextInt(mapping.first, mapping.second);	tile.extTileFlags = (tile.extTileFlags & 0b11001111) | (flip << 4);}void CDrawRiversOperation::updateTile(TerrainTile & tile, const LinePattern & pattern, const int flip){	const std::pair<int, int> & mapping  = pattern.riverMapping;		tile.riverDir = gen->nextInt(mapping.first, mapping.second);	tile.extTileFlags = (tile.extTileFlags & 0b00111111) | (flip << 2);}VCMI_LIB_NAMESPACE_END
 |