diff --git a/ReflexToQ3/.gitignore b/ReflexToQ3/.gitignore index 2c0ed78..ce562d2 100644 --- a/ReflexToQ3/.gitignore +++ b/ReflexToQ3/.gitignore @@ -5,5 +5,12 @@ *.log +# git merge backups +*_BACKUP* +*_BASE* +*_LOCAL* +*_REMOTE* +*.orig + # executables reflex2q3 diff --git a/ReflexToQ3/includes/EntityConverter.cpp b/ReflexToQ3/includes/EntityConverter.cpp index d0c1f64..d2ba973 100644 --- a/ReflexToQ3/includes/EntityConverter.cpp +++ b/ReflexToQ3/includes/EntityConverter.cpp @@ -83,6 +83,24 @@ EntityConverter::EntityConverter(std::string entityMapFile, std::string reflexMa +/* + *-------------------------------------------------------------------------------------- + * !-- Not sure if this is used the same way as the pre-scan was --! + *-------------------------------------------------------------------------------------- + */ +void +matchRelated(std::queue> entities) +{ + if( areEntitiesMatched_ ) { + std::cerr << "Related entities are already matched, doing nothing" << std::endl; + } + else { + //Same as pre-scan or convert and pass back all converted entities? + } +} + + + std::vector EntityConverter::convert(std::vector lines) { @@ -102,7 +120,7 @@ EntityConverter::convert(std::vector lines) } - if ( type == "Pickup" ) { + if ( type == "Pickup" ) { return convertPickup(lines); } else if ( type == "PlayerSpawn" ) { @@ -183,16 +201,16 @@ std::vector EntityConverter::convertPickup(std::vector &lines) { std::vector convertedLines; + //can ignore angle of pickups in xonotic format std::string coords[3]; + int pickupID; std::string trash; + bool havePosition = false; + bool havePickupID = false; if ( lines.size() < 3 ) { throw std::runtime_error("error: Pickup entity requires at least 3 lines"); } - //can ignore angle of pickups in xonotic format - int pickupID; - bool havePosition = false; - bool havePickupID = false; for (int i = 1; i < lines.size(); i++) { std::string type = getAttributeType(lines[i]); @@ -233,11 +251,88 @@ EntityConverter::convertPickup(std::vector &lines) +/* + *-------------------------------------------------------------------------------------- + * Class: EntityConverter + * Method: EntityConverter :: convertPlayerSpawn + * Notes: REFLEX + * -Optionally includes angle, team indicator, and 0 or more game + * mode indicators (defaults to all modes enabled so this line + * is used to disable a mode. eg Bool8 modeRace 0) + * *mode indicators cause problem with maps that support race + * and other modes because Xonotic doesn't handle spawns this + * way + *-------------------------------------------------------------------------------------- + */ std::vector EntityConverter::convertPlayerSpawn(std::vector &lines) { - //minimum of 3 lines, max of ? lines + std::vector convertedLines; + //Requires position coordinate + std::string coords[3]; + //Requires an angle so if no reflex one is given, use 0 + std::string angle("0"); + int team = 0; // 1-2 for corresponding team, 0 for deathmatch spawn + std::string trash; + bool havePosition = false; + + if ( lines.size() < 2 ) { + throw std::runtime_error("error: PlayerSpawn entity requires at least 2 lines"); + } + + for (int i = 1; i < lines.size(); i++) { + std::string type = getAttributeType(lines[i]); + if ( type == "position" ) { + std::istringstream iss(lines[i]); + // Vector3 position coord0 coord1 coord2 + if ( ! (iss >> trash >> trash >> + coords[0] >> coords[1] >> coords[2])) { + throw std::runtime_error("error: PlayerSpawn entity requires position coordinates"); + } + havePosition = true; + } + else if ( type == "angles" ) { + std::istringstream iss(lines[i]); + // UInt8 pickupType ID + if ( ! (iss >> trash >> trash >> angle ) { + throw std::runtime_error("error: Pickup entity requires Pickup ID"); + } + } + else if ( type == "teamA" ) { + team = 2; // Bool8 teamA 0 indicates teamB only + } + else ef ( type == "teamB" ) { + team = 1; // Bool8 teamB 0 indicates teamA only + } + } + + if ( havePosition ) { + switch (team) { + case 0: + convertedLines.push_back ( "\"classname\" \"info_player_deathmatch\"" ); + break; + case 1: + convertedLines.push_back ( "\"classname\" \"info_player_team1\"" ); + break; + case 2: + convertedLines.push_back ( "\"classname\" \"info_player_team2\"" ); + break; + } + + std::stringstream oss; + // coordinates reordered to x, z, y + oss << "\"origin\" \"" << coords[0] << " " << coords[2] << " " << + coords[1] << "\"" << std::endl; + convertedLines.push_back ( oss.str() ); + std::stringstream oss2; + oss2 << "\"angle\" \"" << angle << "\"" << endl; + convertedLines.push_back ( oss2.str() ); + return convertedLines; + } + else { + throw std::runtime_error("error: PlayerSpawn entity requires position coordinates"); + } } @@ -246,13 +341,13 @@ std::vector EntityConverter::convertJumpPad(std::vector &lines) { std::vector convertedLines; + std::string targetName; std::string trash; if ( lines.size() < 2 ) { throw std::runtime_error("error: JumpPad entity requires at least 2 lines"); } std::istringstream iss(lines[1]); - std::string targetName; // String32 target targetName if ( ! (iss >> trash >> trash >> targetName) ) { throw std::runtime_error("error: JumpPad entity requires target name"); @@ -271,13 +366,13 @@ std::vector EntityConverter::convertTeleporter(std::vector &lines) { std::vector convertedLines; + std::string targetName; std::string trash; if ( lines.size() < 2 ) { throw std::runtime_error("error: Teleport entity requires at least 2 lines"); } std::istringstream iss(lines[1]); - std::string targetName; // String32 target targetName if ( ! (iss >> trash >> trash >> targetName) ) { throw std::runtime_error( "error: Teleport entity requires target name" ); @@ -285,7 +380,7 @@ EntityConverter::convertTeleporter(std::vector &lines) convertedLines.push_back ( "\"classname\" \"trigger_teleport\"\n" ); std::stringstream oss; - oss << "\"target\" \"" << targetName << std::endl; + oss << "\"target\" \"" << targetName << "\"" << std::endl; convertedLines.push_back ( oss.str() ); return convertedLines; } @@ -296,18 +391,18 @@ std::vector EntityConverter::convertTarget(std::vector &lines) { std::vector convertedLines; + //position and name required, angles optional std::string coords[3]; + std::string targetName; + std::string angle; std::string trash; + bool havePosition = false; + bool haveName = false; + bool haveAngle = false; if ( lines.size() < 3 ) { throw std::runtime_error("error: Target entity requires at least 3 lines"); } - //position and name required, angles optional - std::string targetName; - std::string angle; - bool havePosition = false; - bool haveName = false; - bool haveAngle = false; for (int i = 1; i < lines.size(); i++) { std::string type = getAttributeType(lines[i]); @@ -329,9 +424,9 @@ EntityConverter::convertTarget(std::vector &lines) haveName = true; } else if ( type == "angles" ) { - std::istringstream iss2(lines[i]); + std::istringstream iss(lines[i]); // Vector3 angles angle notapplicable notapplicable - if ( ! (iss2 >> trash >> trash >> angle) ) { + if ( ! (iss >> trash >> trash >> angle) ) { throw std::runtime_error( "error: Target entity requires target angle if specified" ); } haveAngle = true; diff --git a/ReflexToQ3/includes/EntityConverter.hpp b/ReflexToQ3/includes/EntityConverter.hpp index 40fe0ef..7e8b303 100644 --- a/ReflexToQ3/includes/EntityConverter.hpp +++ b/ReflexToQ3/includes/EntityConverter.hpp @@ -105,13 +105,24 @@ class EntityConverter * Class: EntityConverter * Method: EntityConverter :: convert * Description: Converts a single entity from reflex to xonotic format - * Parameter: vector of strings "lines", lines that comprise a single entity + * Parameter: vector of strings lines, lines that comprise a single entity * Return: vector of strings, single entity in the converted format * THROWS: runtime_error on malformed .map file - * THROWS: runtime_error when called before related entitios are matched + * THROWS: runtime_error when called before related entities are matched *-------------------------------------------------------------------------------------- */ std::vector convert(std::vector lines); + /* + *-------------------------------------------------------------------------------------- + * Class: EntityConverter + * Method: EntityConverter :: matchRelated + * Description: Finds related entities (targets of teleports, etc), call after parsing + * the entire .map + * Parameter: queue of vector of string entities, ALL entities in a .map file + * THROWS: runtime_error when encountering malformed entity + *-------------------------------------------------------------------------------------- + */ + void matchRelated(std::queue> entities);