208 lines
7.8 KiB
C++
208 lines
7.8 KiB
C++
#include "maploader.hpp"
|
|
#include "../sdlpp/sdlpp_rectrenderer.hpp"
|
|
#include <array>
|
|
#include <fstream>
|
|
#include "sprites.hpp"
|
|
#include "blocks.hpp"
|
|
#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::vector< mapColumnType > tmp = {};
|
|
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::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 ) {
|
|
objects.resize( cols );
|
|
}
|
|
|
|
mapColumnType *col = nullptr;
|
|
for ( uint16_t i = 0; i < cols; i++ ) {
|
|
if ( editor ) {
|
|
col = &objects[i];
|
|
}
|
|
for ( int j = 0; j < 16; j++ ) {
|
|
auto block = parseBlock( map_file );
|
|
if ( editor ) {
|
|
col->at( j ) = block;
|
|
}
|
|
bool destructible = false;
|
|
bool removeCollisions = false;
|
|
int coinCount = 0;
|
|
if ( !editor &&
|
|
block.getModifierId() == DESTRUCTIBLE_MODIFIER_ID ) {
|
|
destructible = true;
|
|
}
|
|
if ( !editor &&
|
|
block.getModifierId() == BACKGROUND_MODIFIER_ID ) {
|
|
destructible = false;
|
|
removeCollisions = true;
|
|
}
|
|
if ( !editor &&
|
|
block.getModifierId() == COIN_MODIFIER_ID ) {
|
|
coinCount = block.getModifierData();
|
|
}
|
|
// TODO add modifiers to createTerrainBlock
|
|
if(block.getTerrainId() != 0) {
|
|
auto obj = createTerrainBlock(
|
|
block.getTerrainId(), block.getTerrainType(),
|
|
renderer, i, j, destructible, editor );
|
|
if(obj != nullptr) {
|
|
obj->setCoinCount(coinCount);
|
|
if(removeCollisions) {
|
|
obj->removeCollisions();
|
|
}
|
|
if ( obj != nullptr ) {
|
|
if ( editor ) {
|
|
obj->getCollisions()[0]->setId( EDITOR_TERRAIN_ID );
|
|
}
|
|
scene->addObject( obj );
|
|
}
|
|
}
|
|
}
|
|
if ( block.hasCharacter() ) {
|
|
if ( block.getCharacterId() == MARIO_ID ) {
|
|
if ( editor ) {
|
|
scene->addObject( createMario(
|
|
block.getCharacterType(),
|
|
renderer, i, j, true ) );
|
|
mario =
|
|
scene->getObject( scene->getObjects().size() - 1 );
|
|
} else {
|
|
mario->setPos( i * BLOCK_SIZE,
|
|
1 - ( 16 - j ) * BLOCK_SIZE );
|
|
}
|
|
}
|
|
}
|
|
if ( editor && block.hasModifier() ) {
|
|
// TODO createModifierBlock with data
|
|
auto mod = createTerrainBlock(
|
|
block.getModifierId(), LandType::OVERWORLD, renderer, i, j,
|
|
false, editor );
|
|
mod->setData(block.getModifierData());
|
|
mod->setTextureKeepSRC(g_translucent_mod_texture);
|
|
mod->getCollisions()[0]->setId( EDITOR_TERRAIN_ID );
|
|
dynamic_cast< MarioBlock * >( mod.get() )->setTerrain( false );
|
|
scene->addObject( mod );
|
|
}
|
|
}
|
|
}
|
|
if ( editor && objects.size() < editor_width ) {
|
|
objects.resize( editor_width );
|
|
}
|
|
}
|
|
|
|
void saveMap( const std::string &file, std::vector< mapColumnType > &objects ) {
|
|
std::ofstream output_file;
|
|
output_file.open( file, std::ios::out | std::ios::binary );
|
|
uint16_t cols = objects.size();
|
|
output_file.write( ( char * )&cols, sizeof( uint16_t ) / sizeof( char ) );
|
|
for ( auto &col : objects ) {
|
|
for ( int i = 0; i < 16; i++ ) {
|
|
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;
|
|
}
|
|
write16Bits(output_file, wide_terrain);
|
|
uint8_t additional_data = 0;
|
|
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 ) {
|
|
write8Bits(output_file, additional_data);
|
|
}
|
|
}
|
|
}
|
|
output_file.close();
|
|
}
|