Mario: add MapObject and use that instead of tuples

This commit is contained in:
2021-06-07 23:48:28 +02:00
parent 76f55fd98c
commit a54d079fd2
9 changed files with 329 additions and 169 deletions
+114 -74
View File
@@ -7,92 +7,144 @@
#include "objectids.hpp"
#include "global_vars.hpp"
#define TERRAIN_TYPE_HAS_ADDITIONAL 0x8
#define WIDE_TERRAIN_HAS_ADDITIONAL 0x8000
#define ADDITIONAL_IS_MOD 0x80
void loadMap( std::shared_ptr< SDLPP::Scene > &scene,
std::shared_ptr< SDLPP::RenderObject > mario,
const std::string &file,
std::shared_ptr< SDLPP::Renderer > &renderer ) {
const std::string &file ) {
std::vector< mapColumnType > tmp = {};
loadMap(scene, mario, file, renderer, tmp, false);
scene->moveZTop(mario);
loadMap( scene, mario, file, tmp, false );
scene->moveZTop( mario );
}
uint8_t read8Bits( std::ifstream &file ) {
uint8_t data;
file.read( ( char * )&data, sizeof( uint8_t ) / sizeof( char ) );
return data;
}
void write8Bits( std::ofstream &file, uint8_t data ) {
file.write( ( char * )&data, sizeof( uint8_t ) / sizeof( char ) );
}
uint16_t read16Bits( std::ifstream &file ) {
uint16_t data;
file.read( ( char * )&data, sizeof( uint16_t ) / sizeof( char ) );
return data;
}
void write16Bits( std::ofstream &file, uint16_t data ) {
file.write( ( char * )&data, sizeof( uint16_t ) / sizeof( char ) );
}
std::pair< uint16_t, uint8_t > separateWideTerrain( uint16_t wide_terrain ) {
uint8_t terrain_type = ( wide_terrain & 0xF000 ) >> 12;
uint16_t terrain_id = ( wide_terrain & 0x0FFF ) | BLOCK_PREFIX;
return { terrain_id, terrain_type };
}
std::pair< uint8_t, uint8_t > separateAdditionalData( uint8_t data ) {
auto id = data & 0x0F;
auto type = ( data & 0xF0 ) >> 4;
return { id, type };
}
uint16_t combineTerrain( uint16_t id, uint8_t type ) {
uint16_t wide_terrain = type;
wide_terrain = wide_terrain << 12;
wide_terrain |= 0x0FFF & id;
return wide_terrain;
}
uint8_t combineAdditionalData( uint8_t id, uint8_t type ) {
return type << 4 | id;
}
MapObject parseBlock( std::ifstream &map_file ) {
uint8_t character_type = 0, character_id = 0, modifier_id = 0,
modifier_data = 0;
uint16_t wide_terrain = read16Bits( map_file );
auto terrain = separateWideTerrain( wide_terrain );
uint16_t terrain_id = terrain.first;
uint8_t terrain_type = terrain.second;
if ( terrain_type & TERRAIN_TYPE_HAS_ADDITIONAL ) {
uint8_t additional_data = read8Bits( map_file );
terrain_type &= ~TERRAIN_TYPE_HAS_ADDITIONAL;
if ( additional_data & ADDITIONAL_IS_MOD ) {
additional_data &= ~ADDITIONAL_IS_MOD;
auto modifier = separateAdditionalData( additional_data );
// TODO swap modifier id and data
modifier_id = modifier.second;
modifier_data = modifier.first;
} else {
// character
auto character = separateAdditionalData( additional_data );
character_id = character.first;
character_type = character.second;
}
}
return MapObject( terrain_id, terrain_type, character_id, character_type,
modifier_id, modifier_data );
}
// editor loader
void loadMap( std::shared_ptr< SDLPP::Scene > &scene,
std::shared_ptr< SDLPP::RenderObject > &mario,
const std::string &file,
std::shared_ptr< SDLPP::Renderer > &renderer,
std::vector< mapColumnType > &objects, bool editor, size_t editor_width ) {
std::vector< mapColumnType > &objects, bool editor,
size_t editor_width ) {
auto renderer = scene->getRendererShared();
std::ifstream map_file;
map_file.open( file, std::ios::in | std::ios::binary );
uint16_t cols;
map_file.read( ( char * )&cols, sizeof( uint16_t ) / sizeof( char ) );
if(editor) {
if ( editor ) {
objects.resize( cols );
}
mapColumnType *col = nullptr;
for ( uint16_t i = 0; i < cols; i++ ) {
if(editor) {
if ( editor ) {
col = &objects[i];
}
for ( int j = 0; j < 16; j++ ) {
uint16_t input_number;
uint8_t additional_data = 0;
uint8_t character_type = 0, character = 0, modifier_type = 0,
modifier_data = 0;
map_file.read( ( char * )&input_number,
sizeof( uint16_t ) / sizeof( char ) );
uint8_t type = ( input_number & 0xF000 ) >> 12;
uint16_t id = ( input_number & 0x0FFF ) | BLOCK_PREFIX;
if ( type & 0x8 ) {
map_file.read( ( char * )&additional_data,
sizeof( uint8_t ) / sizeof( char ) );
type &= ~0x8;
if ( additional_data & 0x80 ) {
// modifier
additional_data &= ~0x80;
modifier_type = ( additional_data & 0xF0 ) >> 4;
modifier_data = additional_data & 0x0F;
} else {
// character
character_type = ( additional_data & 0xF0 ) >> 4;
character = additional_data & 0x0F;
}
}
if(editor) {
col->at(j) = { type, id, character_type, character,
modifier_type, modifier_data };
auto block = parseBlock( map_file );
if ( editor ) {
col->at( j ) = block;
}
bool destructible = false;
if(!editor && modifier_type == DESTRUCTIBLE_ID) {
if ( !editor &&
block.getModifierId() == DESTRUCTIBLE_MODIFIER_ID ) {
destructible = true;
}
// TODO add modifiers to createTerrainBlock
auto obj =
createTerrainBlock( id, static_cast< LandType::Value >( type ),
renderer, i, j, destructible, editor );
if(obj != nullptr) {
if(editor) {
obj->getCollisions()[0]->setId( EDITOR_TERRAIN_ID );
if(block.getTerrainId() != 0) {
auto obj = createTerrainBlock(
block.getTerrainId(), block.getTerrainType(),
renderer, i, j, destructible, editor );
if ( obj != nullptr ) {
if ( editor ) {
obj->getCollisions()[0]->setId( EDITOR_TERRAIN_ID );
}
scene->addObject( obj );
}
scene->addObject( obj );
}
if ( character ) {
if ( character == MARIO_ID ) {
if(editor) {
if ( block.hasCharacter() ) {
if ( block.getCharacterId() == MARIO_ID ) {
if ( editor ) {
scene->addObject( createMario(
static_cast< LandType::Value >( character_type ),
block.getCharacterType(),
renderer, i, j ) );
mario = scene->getObject(scene->getObjects().size() - 1);
mario =
scene->getObject( scene->getObjects().size() - 1 );
} else {
mario->setPos( i * BLOCK_SIZE,
1 - ( 16 - j ) * BLOCK_SIZE );
}
}
}
if ( editor && modifier_type ) {
if ( editor && block.hasModifier() ) {
// TODO createModifierBlock with data
auto mod = createTerrainBlock(
modifier_type, LandType::OVERWORLD, renderer, i, j,
block.getModifierId(), LandType::OVERWORLD, renderer, i, j,
g_translucent_terrain_texture, false, editor );
mod->getCollisions()[0]->setId( EDITOR_TERRAIN_ID );
dynamic_cast< MarioBlock * >( mod.get() )->setTerrain( false );
@@ -105,8 +157,6 @@ void loadMap( std::shared_ptr< SDLPP::Scene > &scene,
}
}
// tuple - world object type, object, world character type, character, modifier
// type, modifier data
void saveMap( const std::string &file, std::vector< mapColumnType > &objects ) {
std::ofstream output_file;
output_file.open( file, std::ios::out | std::ios::binary );
@@ -114,33 +164,23 @@ void saveMap( const std::string &file, std::vector< mapColumnType > &objects ) {
output_file.write( ( char * )&cols, sizeof( uint16_t ) / sizeof( char ) );
for ( auto &col : objects ) {
for ( int i = 0; i < 16; i++ ) {
auto &obj = col[i];
uint16_t wide_type = std::get< MapObject::TERRAIN_TYPE >( obj );
wide_type = wide_type << 12;
uint16_t write_num =
( 0x0FFF & std::get< MapObject::TERRAIN_ID >( obj ) ) |
wide_type;
// character type can be 0 (overworld), modifier data can be 0
if ( std::get< MapObject::CHARACTER_ID >( obj ) ||
std::get< MapObject::MODIFIER_TYPE >( obj ) ) {
write_num |= 0x8000;
auto &block = col[i];
auto wide_terrain = combineTerrain(block.getTerrainId(), block.getTerrainType());
// if block has additional data it needs to indicate it
if ( block.hasCharacter() || block.hasModifier() ) {
wide_terrain |= WIDE_TERRAIN_HAS_ADDITIONAL;
}
output_file.write( ( char * )&write_num,
sizeof( uint16_t ) / sizeof( char ) );
write16Bits(output_file, wide_terrain);
uint8_t additional_data = 0;
if ( std::get< MapObject::CHARACTER_ID >( obj ) ) {
additional_data |= std::get< MapObject::CHARACTER_TYPE >( obj )
<< 4;
additional_data |= std::get< MapObject::CHARACTER_ID >( obj );
} else if ( std::get< MapObject::MODIFIER_TYPE >( obj ) ) {
additional_data |= std::get< MapObject::MODIFIER_TYPE >( obj )
<< 4;
additional_data |= 0x80;
additional_data |= std::get< MapObject::MODIFIER_DATA >( obj );
if ( block.hasCharacter() ) {
additional_data = combineAdditionalData(block.getCharacterId(), block.getCharacterType());
} else if ( block.hasModifier() ) {
// TODO seriously change order of id/data!!!
additional_data = combineAdditionalData(block.getModifierData(), block.getModifierId());
additional_data |= ADDITIONAL_IS_MOD;
}
if ( additional_data ) {
output_file.write( ( char * )&additional_data,
sizeof( uint8_t ) / sizeof( char ) );
write8Bits(output_file, additional_data);
}
}
}