diff --git a/gse/default/factions.gls.js b/gse/default/factions.gls.js index f7bbf2bb..02fde6c4 100644 --- a/gse/default/factions.gls.js +++ b/gse/default/factions.gls.js @@ -1,92 +1,40 @@ -return [ - - // SMAC - ['GAIANS', { - name: 'Gaians', - files: { - pcx: 'gaians.pcx' - } - }], - ['HIVE', { - name: 'Hive', - files: { - pcx: 'hive.pcx' - } - }], - ['UNIVERSITY', { - name: 'University', - files: { - pcx: 'univ.pcx' - } - }], - ['MORGANITES', { - name: 'Morganites', - files: { - pcx: 'morgan.pcx' - } - }], - ['SPARTANS', { - name: 'Spartans', - files: { - pcx: 'spartans.pcx' - } - }], - ['BELIEVERS', { - name: 'Believers', - files: { - pcx: 'believe.pcx' - } - }], - ['PEACEKEEPERS', { - name: 'Peacekeepers', - files: { - pcx: 'peace.pcx' - } - }], - - // SMACX - ['CONSCIOUSNESS', { - name: 'Consciousness', - files: { - pcx: 'cyborg.pcx' - } - }], - ['PIRATES', { - name: 'Pirates', - files: { - pcx: 'pirates.pcx' - } - }], - ['DRONES', { - name: 'Drones', - files: { - pcx: 'drone.pcx' - } - }], - ['ANGELS', { - name: 'Angels', - files: { - pcx: 'angels.pcx' - } - }], - ['PLANETCULT', { - name: 'Planet Cult', - files: { - pcx: 'fungboy.pcx' - } - }], - ['CARETAKERS', { - name: 'Caretakers', - files: { - pcx: 'caretake.pcx' +const faction = (id, name, text_color, border_color, pcx, extra) => { + return [id, { + name: name, + colors: { + text: text_color, + border: border_color, }, - is_progenitor: true - }], - ['USURPERS', { - name: 'Usurpers', - files: { - pcx: 'usurper.pcx' + bases: { + render: { + type: 'sprite_grid', + file: pcx, + grid_x: 1, grid_y: 1, + cell_width: 100, cell_height: 75, + //cell_cx: 50, cell_cy: 38, + cell_padding: 1, + /*scale_x: 0.7, + scale_y: 0.7,*/ + } }, - is_progenitor: true - }], + } + extra]; +}; + +const factions = [ + faction('GAIANS', 'Gaians', #to_color(16, 228, 0), #to_color(0, 252, 0), 'gaians.pcx', {}), + faction('HIVE', 'Hive', #to_color(0, 97, 255), #to_color(0, 0, 255), 'hive.pcx', {}), + faction('UNIVERSITY', 'University', #to_color(216, 224, 244), #to_color(255, 255, 255), 'univ.pcx', {}), + faction('MORGANITES', 'Morganites', #to_color(255, 255, 0), #to_color(255, 255, 0), 'morgan.pcx', {}), + faction('SPARTANS', 'Spartans', #to_color(136, 166, 166), #to_color(0, 0, 0), 'spartans.pcx', {}), + faction('BELIEVERS', 'Believers', #to_color(224, 156, 28), #to_color(236, 92, 0), 'believe.pcx', {}), + faction('PEACEKEEPERS', 'Peacekeepers', #to_color(164, 176, 232), #to_color(164, 176, 232), 'peace.pcx', {}), + faction('CONSCIOUSNESS', 'Consciousness', #to_color(44, 128, 104), #to_color(44, 128, 104), 'cyborg.pcx', {}), + faction('PIRATES', 'Pirates', #to_color(0, 255, 255), #to_color(0, 255, 255), 'pirates.pcx', {}), + faction('DRONES', 'Drones', #to_color(173, 196, 192), #to_color(136, 12, 12), 'drone.pcx', {}), + faction('ANGELS', 'Angels', #to_color(103, 91, 181), #to_color(103, 91, 181), 'angels.pcx', {}), + faction('PLANETCULT', 'Planet Cult', #to_color(232, 84, 84), #to_color(232, 84, 84), 'fungboy.pcx', {}), + faction('CARETAKERS', 'Caretakers', #to_color(116, 156, 56), #to_color(116, 156, 56), 'caretake.pcx', {is_progenitor: true}), + faction('USURPERS', 'Usurpers', #to_color(212, 208, 116), #to_color(212, 208, 116), 'usurper.pcx', {is_progenitor: true}), ]; + +return factions; diff --git a/src/base/Base.cpp b/src/base/Base.cpp index 02f1ea03..7e29eefe 100644 --- a/src/base/Base.cpp +++ b/src/base/Base.cpp @@ -1,5 +1,9 @@ #include +#ifdef DEBUG +#include +#endif + #include "Base.h" #include "engine/Engine.h" @@ -35,9 +39,25 @@ const std::string& Base::GetLocalName() const { return m_name; } +#ifdef DEBUG +static uint64_t last_time = 0; +#endif + void Base::Log( const std::string& text ) const { if ( g_engine != NULL ) { - g_engine->GetLogger()->Log( "<" + GetName() + "> " + text ); +#ifdef DEBUG + const auto time = std::chrono::high_resolution_clock::now().time_since_epoch().count(); + const auto duration = last_time + ? time - last_time + : 0; + last_time = time; +#endif + g_engine->GetLogger()->Log( +#ifdef DEBUG + "[+" + std::to_string( duration ) + "ns] " + +#endif + "<" + GetName() + "> " + text + ); } } diff --git a/src/game/animation/FramesRow.cpp b/src/game/animation/FramesRow.cpp index 12fe4f8d..7f440def 100644 --- a/src/game/animation/FramesRow.cpp +++ b/src/game/animation/FramesRow.cpp @@ -21,16 +21,22 @@ FramesRow::FramesRow( const std::string& sound_file ) : Def( id, AT_FRAMES_ROW, duration_ms, scale_x, scale_y, sound_file ) - , m_file( file ) - , m_row_x( row_x ) - , m_row_y( row_y ) - , m_frame_width( frame_width ) - , m_frame_height( frame_height ) - , m_frame_center_x( frame_center_x ) - , m_frame_center_y( frame_center_y ) - , m_frame_padding( frame_padding ) - , m_frames_count( frames_count ) - , m_frames_per_row( frames_per_row ) { + , m_render( + { + file, + row_x, + row_y, + frame_width, + frame_height, + frame_padding, + frame_center_x, + frame_center_y, + frames_count, + frames_per_row, + scale_x, + scale_y + } + ) { // } @@ -38,16 +44,16 @@ const std::string FramesRow::ToString( const std::string& prefix ) const { return (std::string) TS_OBJ_BEGIN( "FramesRow" ) + TS_OBJ_PROP_STR( "id", m_id ) + - TS_OBJ_PROP_STR( "file", m_file ) + - TS_OBJ_PROP_NUM( "row_x", m_row_x ) + - TS_OBJ_PROP_NUM( "row_y", m_row_y ) + - TS_OBJ_PROP_NUM( "frame_width", m_frame_width ) + - TS_OBJ_PROP_NUM( "frame_height", m_frame_height ) + - TS_OBJ_PROP_NUM( "frame_center_x", m_frame_center_x ) + - TS_OBJ_PROP_NUM( "frame_center_y", m_frame_center_y ) + - TS_OBJ_PROP_NUM( "frame_padding", m_frame_padding ) + - TS_OBJ_PROP_NUM( "frames_count", m_frames_count ) + - TS_OBJ_PROP_NUM( "frames_per_row", m_frames_per_row ) + + TS_OBJ_PROP_STR( "file", m_render.file ) + + TS_OBJ_PROP_NUM( "row_x", m_render.row_x ) + + TS_OBJ_PROP_NUM( "row_y", m_render.row_y ) + + TS_OBJ_PROP_NUM( "frame_width", m_render.frame_width ) + + TS_OBJ_PROP_NUM( "frame_height", m_render.frame_height ) + + TS_OBJ_PROP_NUM( "frame_center_x", m_render.frame_center_x ) + + TS_OBJ_PROP_NUM( "frame_center_y", m_render.frame_center_y ) + + TS_OBJ_PROP_NUM( "frame_padding", m_render.frame_padding ) + + TS_OBJ_PROP_NUM( "frames_count", m_render.frames_count ) + + TS_OBJ_PROP_NUM( "frames_per_row", m_render.frames_per_row ) + TS_OBJ_PROP_NUM( "scale_x", m_scale_x ) + TS_OBJ_PROP_NUM( "scale_y", m_scale_y ) + TS_OBJ_PROP_NUM( "duration_ms", m_duration_ms ) + @@ -56,16 +62,16 @@ const std::string FramesRow::ToString( const std::string& prefix ) const { } void FramesRow::Serialize( types::Buffer& buf, const FramesRow* def ) { - buf.WriteString( def->m_file ); - buf.WriteInt( def->m_row_x ); - buf.WriteInt( def->m_row_y ); - buf.WriteInt( def->m_frame_width ); - buf.WriteInt( def->m_frame_height ); - buf.WriteInt( def->m_frame_center_x ); - buf.WriteInt( def->m_frame_center_y ); - buf.WriteInt( def->m_frame_padding ); - buf.WriteInt( def->m_frames_count ); - buf.WriteInt( def->m_frames_per_row ); + buf.WriteString( def->m_render.file ); + buf.WriteInt( def->m_render.row_x ); + buf.WriteInt( def->m_render.row_y ); + buf.WriteInt( def->m_render.frame_width ); + buf.WriteInt( def->m_render.frame_height ); + buf.WriteInt( def->m_render.frame_center_x ); + buf.WriteInt( def->m_render.frame_center_y ); + buf.WriteInt( def->m_render.frame_padding ); + buf.WriteInt( def->m_render.frames_count ); + buf.WriteInt( def->m_render.frames_per_row ); } FramesRow* FramesRow::Unserialize( diff --git a/src/game/animation/FramesRow.h b/src/game/animation/FramesRow.h index f7f0a9c9..6e453217 100644 --- a/src/game/animation/FramesRow.h +++ b/src/game/animation/FramesRow.h @@ -2,6 +2,8 @@ #include +#include "Types.h" + #include "Def.h" namespace game { @@ -28,16 +30,7 @@ class FramesRow : public Def { const std::string& sound_file ); - const std::string m_file; - const uint16_t m_row_x; - const uint16_t m_row_y; - const uint16_t m_frame_width; - const uint16_t m_frame_height; - const uint16_t m_frame_padding; - const uint16_t m_frame_center_x; - const uint16_t m_frame_center_y; - const uint8_t m_frames_count; - const uint8_t m_frames_per_row; + sprite_render_info_t m_render = {}; const std::string ToString( const std::string& prefix ) const override; diff --git a/src/game/animation/Types.h b/src/game/animation/Types.h index 15b6ddfe..2ebf9d96 100644 --- a/src/game/animation/Types.h +++ b/src/game/animation/Types.h @@ -1,5 +1,8 @@ #pragma once +#include +#include + namespace game { namespace animation { @@ -8,5 +11,20 @@ enum animation_type_t { AT_FRAMES_ROW, }; +struct sprite_render_info_t { + std::string file; + uint16_t row_x; + uint16_t row_y; + uint16_t frame_width; + uint16_t frame_height; + uint16_t frame_padding; + uint16_t frame_center_x; + uint16_t frame_center_y; + uint8_t frames_count; + uint8_t frames_per_row; + float scale_x; + float scale_y; +}; + } } \ No newline at end of file diff --git a/src/game/bindings/Factions.cpp b/src/game/bindings/Factions.cpp index d0fbe5f5..d3c364fd 100644 --- a/src/game/bindings/Factions.cpp +++ b/src/game/bindings/Factions.cpp @@ -4,6 +4,8 @@ #include "gse/Exception.h" #include "gse/type/Object.h" #include "gse/type/String.h" +#include "gse/type/Int.h" +#include "gse/type/Float.h" #include "gse/type/Undefined.h" #include "gse/type/Bool.h" #include "game/bindings/Bindings.h" @@ -31,14 +33,48 @@ BINDING_IMPL( factions ) { rules::Faction faction = { id, name }; - N_GETPROP( files, faction_def, "files", Object ); - N_GETPROP( pcx_file, files, "pcx", String ); - faction.ImportPCX( pcx_file ); + N_GETPROP( colors, faction_def, "colors", Object ); + N_GETPROP_UNWRAP( colors_text, colors, "text", types::Color ); + N_GETPROP_UNWRAP( colors_border, colors, "border", types::Color ); + faction.m_colors = { colors_text, colors_border }; N_GETPROP_OPT_BOOL( is_progenitor, faction_def, "is_progenitor") if ( is_progenitor ) { faction.m_flags |= rules::Faction::FF_PROGENITOR; } + + N_GETPROP( bases_def, faction_def, "bases", Object ); + N_GETPROP( bases_render_def, bases_def, "render", Object ); + + N_GETPROP( bases_render_type, bases_render_def, "type", String ); + if ( bases_render_type == "sprite_grid" ) { + N_GETPROP( file, bases_render_def, "file", String ); + N_GETPROP( grid_x, bases_render_def, "grid_x", Int ); + N_GETPROP( grid_y, bases_render_def, "grid_y", Int ); + N_GETPROP( cell_width, bases_render_def, "cell_width", Int ); + N_GETPROP( cell_height, bases_render_def, "cell_height", Int ); + N_GETPROP_OPT( size_t, cell_cx, bases_render_def, "cell_cx", Int, cell_width / 2 ); + N_GETPROP_OPT( size_t, cell_cy, bases_render_def, "cell_cy", Int, cell_height / 2 ); + N_GETPROP( cell_padding, bases_render_def, "cell_padding", Int ); + N_GETPROP_OPT( float, scale_x, bases_render_def, "scale_x", Float, 1.0f ); + N_GETPROP_OPT( float, scale_y, bases_render_def, "scale_y", Float, 1.0f ); + faction.m_bases_render = { + file, + (size_t)grid_x, + (size_t)grid_y, + (size_t)cell_width, + (size_t)cell_height, + cell_cx, + cell_cy, + (size_t)cell_padding, + scale_x, + scale_y + }; + } + else { + ERROR( gse::EC.GAME_ERROR, "Unsupported bases render type: " + bases_render_type ); + } + factions.insert({ id, faction }); factions_order.push_back( id ); return VALUE( gse::type::Undefined ); diff --git a/src/game/rules/Faction.cpp b/src/game/rules/Faction.cpp index 6c3efa88..867b8ce8 100644 --- a/src/game/rules/Faction.cpp +++ b/src/game/rules/Faction.cpp @@ -22,20 +22,26 @@ Faction::Faction( const std::string& id, const std::string& name ) // } -void Faction::ImportPCX( const std::string& pcx_file ) { - const auto* texture = g_engine->GetTextureLoader()->LoadCustomTexture( pcx_file ); - m_colors.text = types::Color::FromRGBA( texture->GetPixel( 5, 755 ) ); - m_colors.border = types::Color::FromRGBA( texture->GetPixel( 162, 750 ) ); -} - const types::Buffer Faction::Serialize() const { types::Buffer buf; buf.WriteString( m_id ); buf.WriteString( m_name ); + buf.WriteColor( m_colors.text ); buf.WriteColor( m_colors.border ); + buf.WriteString( m_bases_render.file ); + buf.WriteInt( m_bases_render.grid_x ); + buf.WriteInt( m_bases_render.grid_y ); + buf.WriteInt( m_bases_render.cell_width ); + buf.WriteInt( m_bases_render.cell_height ); + buf.WriteInt( m_bases_render.cell_cx ); + buf.WriteInt( m_bases_render.cell_cy ); + buf.WriteInt( m_bases_render.cell_padding ); + buf.WriteFloat( m_bases_render.scale_x ); + buf.WriteFloat( m_bases_render.scale_y ); + return buf; } @@ -43,22 +49,24 @@ void Faction::Unserialize( types::Buffer buf ) { m_id = buf.ReadString(); m_name = buf.ReadString(); + m_colors.text = buf.ReadColor(); m_colors.border = buf.ReadColor(); + m_bases_render.file = buf.ReadString(); + m_bases_render.grid_x = buf.ReadInt(); + m_bases_render.grid_y = buf.ReadInt(); + m_bases_render.cell_width = buf.ReadInt(); + m_bases_render.cell_height = buf.ReadInt(); + m_bases_render.cell_cx = buf.ReadInt(); + m_bases_render.cell_cy = buf.ReadInt(); + m_bases_render.cell_padding = buf.ReadInt(); + m_bases_render.scale_x = buf.ReadFloat(); + m_bases_render.scale_y = buf.ReadFloat(); + } WRAPIMPL_BEGIN( Faction, CLASS_FACTION ) - gse::type::object_properties_t color_obj = { - { - "text", - m_colors.text.Wrap() - }, - { - "border", - m_colors.border.Wrap() - } - }; WRAPIMPL_PROPS { { "id", @@ -68,10 +76,6 @@ WRAPIMPL_BEGIN( Faction, CLASS_FACTION ) "name", VALUE( gse::type::String, m_name ) }, - { - "colors", - VALUE( gse::type::Object, color_obj ) - }, }; WRAPIMPL_END_PTR( Faction ) diff --git a/src/game/rules/Faction.h b/src/game/rules/Faction.h index 76d7f222..d6950c6a 100644 --- a/src/game/rules/Faction.h +++ b/src/game/rules/Faction.h @@ -5,6 +5,7 @@ #include "types/Serializable.h" #include "gse/Wrappable.h" +#include "Types.h" #include "types/Color.h" namespace game { @@ -28,7 +29,7 @@ CLASS2( Faction, types::Serializable, gse::Wrappable ) types::Color border = {}; } m_colors = {}; - void ImportPCX( const std::string& pcx_file ); + bases_render_info_t m_bases_render = {}; const types::Buffer Serialize() const override; void Unserialize( types::Buffer buf ) override; diff --git a/src/game/rules/Types.h b/src/game/rules/Types.h new file mode 100644 index 00000000..ff79be7f --- /dev/null +++ b/src/game/rules/Types.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +namespace game { +namespace rules { + +struct bases_render_info_t { + std::string file = ""; + size_t grid_x = 0; + size_t grid_y = 0; + size_t cell_width = 0; + size_t cell_height = 0; + size_t cell_cx = 0; + size_t cell_cy = 0; + size_t cell_padding = 0; + float scale_x = 1.0f; + float scale_y = 1.0f; +}; + +} +} \ No newline at end of file diff --git a/src/game/unit/SpriteRender.cpp b/src/game/unit/SpriteRender.cpp index f1724c7f..13182bd6 100644 --- a/src/game/unit/SpriteRender.cpp +++ b/src/game/unit/SpriteRender.cpp @@ -17,16 +17,18 @@ SpriteRender::SpriteRender( const uint32_t morale_based_xshift ) : Render( RT_SPRITE ) - , m_file( file ) - , m_x( x ) - , m_y( y ) - , m_w( w ) - , m_h( h ) - , m_cx( cx ) - , m_cy( cy ) - , m_cshift_x( (float)( cx - x ) / w * 2 - 1.0f ) - , m_cshift_y( (float)( cy - y ) / h * 2 - 1.0f ) - , m_morale_based_xshift( morale_based_xshift ) { + , m_render( + { + file, + x, + y, + w, + h, + cx, + cy, + morale_based_xshift, + } + ) { // } @@ -36,51 +38,31 @@ const types::Vec3 SpriteRender::GetSpawnCoords( const map::tile::Tile* tile, con ? map::tile::LAYER_WATER : map::tile::LAYER_LAND ].coords.center; - - /*float cx = tile_coords.center.x; - if ( m_cshift_x < 0 ) { - cx -= ( cx - tile_coords.left.x ) * m_cshift_x; - } - if ( m_cshift_x > 0 ) { - cx += ( tile_coords.right.x - cx ) * m_cshift_x; - } - float cy = tile_coords.center.y; - if ( m_cshift_y < 0 ) { - cy += ( cy - tile_coords.top.y ) * m_cshift_y; - } - if ( m_cshift_y > 0 ) { - cy -= ( tile_coords.bottom.y - cy ) * m_cshift_y; - } - return { - cx, - cy, - tile_coords.center.z, - };*/ } const std::string SpriteRender::ToString( const std::string& prefix ) const { return (std::string) TS_OBJ_BEGIN( "SpriteRender" ) + - TS_OBJ_PROP_STR( "file", m_file ) + - TS_OBJ_PROP_NUM( "x: ", m_x ) + - TS_OBJ_PROP_NUM( "y: ", m_y ) + - TS_OBJ_PROP_NUM( "w: ", m_w ) + - TS_OBJ_PROP_NUM( "h: ", m_w ) + - TS_OBJ_PROP_NUM( "cx: ", m_cx ) + - TS_OBJ_PROP_NUM( "cy: ", m_cy ) + - TS_OBJ_PROP_NUM( "morale_based_xshift", m_morale_based_xshift ) + + TS_OBJ_PROP_STR( "file", m_render.file ) + + TS_OBJ_PROP_NUM( "x: ", m_render.x ) + + TS_OBJ_PROP_NUM( "y: ", m_render.y ) + + TS_OBJ_PROP_NUM( "w: ", m_render.w ) + + TS_OBJ_PROP_NUM( "h: ", m_render.w ) + + TS_OBJ_PROP_NUM( "cx: ", m_render.cx ) + + TS_OBJ_PROP_NUM( "cy: ", m_render.cy ) + + TS_OBJ_PROP_NUM( "morale_based_xshift", m_render.morale_based_xshift ) + TS_OBJ_END(); } void SpriteRender::Serialize( types::Buffer& buf, const SpriteRender* render ) { - buf.WriteString( render->m_file ); - buf.WriteInt( render->m_x ); - buf.WriteInt( render->m_y ); - buf.WriteInt( render->m_w ); - buf.WriteInt( render->m_h ); - buf.WriteInt( render->m_cx ); - buf.WriteInt( render->m_cy ); - buf.WriteInt( render->m_morale_based_xshift ); + buf.WriteString( render->m_render.file ); + buf.WriteInt( render->m_render.x ); + buf.WriteInt( render->m_render.y ); + buf.WriteInt( render->m_render.w ); + buf.WriteInt( render->m_render.h ); + buf.WriteInt( render->m_render.cx ); + buf.WriteInt( render->m_render.cy ); + buf.WriteInt( render->m_render.morale_based_xshift ); } SpriteRender* SpriteRender::Unserialize( types::Buffer& buf ) { diff --git a/src/game/unit/SpriteRender.h b/src/game/unit/SpriteRender.h index bba9d270..e3e771f0 100644 --- a/src/game/unit/SpriteRender.h +++ b/src/game/unit/SpriteRender.h @@ -2,6 +2,8 @@ #include "Render.h" +#include "Types.h" + namespace game { namespace unit { @@ -18,16 +20,7 @@ class SpriteRender : public Render { const uint32_t morale_based_xshift ); - const std::string m_file; - const uint32_t m_x; - const uint32_t m_y; - const uint32_t m_w; - const uint32_t m_h; - const uint32_t m_cx; - const uint32_t m_cy; - const uint32_t m_morale_based_xshift; - const float m_cshift_x; - const float m_cshift_y; + const sprite_render_info_t m_render = {}; const types::Vec3 GetSpawnCoords( const map::tile::Tile* tile, const map::tile::TileState* ts ) const override; const std::string ToString( const std::string& prefix ) const override; diff --git a/src/game/unit/Types.h b/src/game/unit/Types.h index cdb7317f..7b14b53f 100644 --- a/src/game/unit/Types.h +++ b/src/game/unit/Types.h @@ -1,5 +1,6 @@ #pragma once +#include #include namespace game { @@ -25,5 +26,16 @@ typedef uint8_t morale_t; static constexpr morale_t MORALE_MIN = 0; static constexpr morale_t MORALE_MAX = 6; +struct sprite_render_info_t { + std::string file; + uint32_t x; + uint32_t y; + uint32_t w; + uint32_t h; + uint32_t cx; + uint32_t cy; + uint32_t morale_based_xshift; +}; + } } diff --git a/src/loader/texture/TextureLoader.cpp b/src/loader/texture/TextureLoader.cpp index fb78f782..1c55bd7b 100644 --- a/src/loader/texture/TextureLoader.cpp +++ b/src/loader/texture/TextureLoader.cpp @@ -3,6 +3,8 @@ #include #include "types/texture/Texture.h" +#include "engine/Engine.h" +#include "resource/ResourceManager.h" namespace loader { namespace texture { @@ -12,6 +14,8 @@ static const auto s_tc_pink = types::Color::RGB( 255, 0, 255 ); static const auto s_tc_purple = types::Color::RGB( 152, 24, 228 ); static const auto s_tc_darkpurple = types::Color::RGB( 100, 16, 156 ); static const auto s_tc_aqua = types::Color::RGB( 24, 184, 228 ); +static const auto s_tc_yellowshadow = types::Color::RGB( 253, 189, 118 ); +static const auto s_tc_facborder = types::Color::RGB( 77, 156, 176 ); static const std::unordered_map< resource::resource_t, TextureLoader::transparent_colors_t > s_tcs = { { resource::PCX_TEXTURE, @@ -79,7 +83,7 @@ static const std::unordered_map< resource::resource_t, TextureLoader::transparen s_tc_purple, s_tc_darkpurple, // tile markings s_tc_aqua, // borders - types::Color::RGB( 253, 189, 118 ), // shadows + s_tc_yellowshadow // shadows } }, { @@ -101,6 +105,7 @@ static const std::unordered_map< resource::resource_t, TextureLoader::transparen resource::PCX_XI, { types::Color::RGB( 0, 67, 255 ), + types::Color::RGB( 155, 27, 231 ), // label types::Color::RGB( 27, 187, 231 ), // borders } }, @@ -111,25 +116,121 @@ static const std::unordered_map< resource::resource_t, TextureLoader::transparen types::Color::RGB( 155, 27, 231 ), // tile types::Color::RGB( 27, 187, 231 ), // borders } - } -}; -static const TextureLoader::transparent_colors_t s_no_transparent_colors = {}; - -// resolve some known files (TODO: move to scripts?) -static const std::unordered_map< std::string, resource::resource_t > s_filename_to_res = { + }, { - "units.pcx", - resource::PCX_UNITS + resource::PCX_GAIANS, + { + s_tc_pink, + s_tc_yellowshadow, + s_tc_facborder, + }, }, { - "xi.pcx", - resource::PCX_XI, + resource::PCX_HIVE, + { + s_tc_pink, + s_tc_yellowshadow, + s_tc_facborder, + }, }, { - "xf.pcx", - resource::PCX_XF, + resource::PCX_UNIV, + { + s_tc_pink, + s_tc_yellowshadow, + s_tc_facborder, + }, + }, + { + resource::PCX_MORGAN, + { + s_tc_pink, + s_tc_yellowshadow, + s_tc_facborder, + }, + }, + { + resource::PCX_SPARTANS, + { + s_tc_pink, + s_tc_yellowshadow, + s_tc_facborder, + }, + }, + { + resource::PCX_BELIEVE, + { + s_tc_pink, + s_tc_yellowshadow, + s_tc_facborder, + }, + }, + { + resource::PCX_PEACE, + { + s_tc_pink, + s_tc_yellowshadow, + s_tc_facborder, + }, + }, + { + resource::PCX_CYBORG, + { + s_tc_darkpurple, + s_tc_yellowshadow, + s_tc_facborder, + }, + }, + { + resource::PCX_PIRATES, + { + s_tc_darkpurple, + s_tc_yellowshadow, + s_tc_facborder, + }, + }, + { + resource::PCX_DRONE, + { + s_tc_darkpurple, + s_tc_yellowshadow, + s_tc_facborder, + }, + }, + { + resource::PCX_ANGELS, + { + s_tc_darkpurple, + s_tc_yellowshadow, + s_tc_facborder, + }, + }, + { + resource::PCX_FUNGBOY, + { + s_tc_darkpurple, + s_tc_yellowshadow, + s_tc_facborder, + }, + }, + { + resource::PCX_CARETAKE, + { + s_tc_darkpurple, + s_tc_yellowshadow, + s_tc_facborder, + }, + }, + { + resource::PCX_USURPER, + { + s_tc_darkpurple, + s_tc_yellowshadow, + s_tc_facborder, + }, }, }; +static const TextureLoader::transparent_colors_t s_no_transparent_colors = {}; const TextureLoader::transparent_colors_t& TextureLoader::GetTCs( const resource::resource_t res ) { const auto& transparent_colors_it = s_tcs.find( res ); @@ -152,14 +253,14 @@ types::texture::Texture* TextureLoader::LoadCustomTexture( const std::string& fi std::string key; key.resize( filename.size() ); std::transform( filename.begin(), filename.end(), key.begin(), ::tolower ); - const auto& it = s_filename_to_res.find( key ); + const auto res = g_engine->GetResourceManager()->GetResource( filename ); transparent_colors_t colors_old; - if ( it != s_filename_to_res.end() ) { + if ( res != resource::NONE ) { colors_old = m_transparent_colors; - m_transparent_colors = GetTCs( it->second ); + m_transparent_colors = GetTCs( res ); } auto* result = LoadTextureImpl( GetCustomFilename( filename ) ); - if ( it != s_filename_to_res.end() ) { + if ( res != resource::NONE ) { m_transparent_colors = colors_old; } return result; diff --git a/src/resource/ResourceManager.cpp b/src/resource/ResourceManager.cpp index fce3f5fa..3e37af8b 100644 --- a/src/resource/ResourceManager.cpp +++ b/src/resource/ResourceManager.cpp @@ -7,81 +7,83 @@ namespace resource { -const std::unordered_map< resource_t, std::string > s_builtin_resources = { - - { - PCX_PALETTE, - "palette.pcx" - }, - { - PCX_INTERFACE, - "interface.pcx" - }, - { - PCX_JACKAL, - "jackal.pcx" - }, - { - PCX_ICONS, - "icons.pcx" - }, - { - PCX_FLAGS, - "flags.pcx" - }, - { - PCX_UNITS, - "units.pcx" - }, - { - PCX_TEXTURE, - "texture.pcx" - }, - { - PCX_TER1, - "ter1.pcx" - }, - { - PCX_CONSOLE_X, - "console_x.pcx" - }, - { - PCX_CONSOLE_X2_A, - "console_x2_a.pcx" - }, +ResourceManager::ResourceManager() + : m_resources_to_filenames( { - PCX_CONSOLE2_A, - "console2_a.pcx" - }, - { - PCX_LOGO, - "logo.pcx" - }, - { - PCX_OPENINGA, - "openinga.pcx" - }, - { - PCX_SPACE_SM, - "space_sm.pcx" - }, + + { + PCX_PALETTE, + "palette.pcx" + }, + { + PCX_INTERFACE, + "interface.pcx" + }, + { + PCX_JACKAL, + "jackal.pcx" + }, + { + PCX_ICONS, + "icons.pcx" + }, + { + PCX_FLAGS, + "flags.pcx" + }, + { + PCX_UNITS, + "units.pcx" + }, + { + PCX_TEXTURE, + "texture.pcx" + }, + { + PCX_TER1, + "ter1.pcx" + }, + { + PCX_CONSOLE_X, + "console_x.pcx" + }, + { + PCX_CONSOLE_X2_A, + "console_x2_a.pcx" + }, + { + PCX_CONSOLE2_A, + "console2_a.pcx" + }, + { + PCX_LOGO, + "logo.pcx" + }, + { + PCX_OPENINGA, + "openinga.pcx" + }, + { + PCX_SPACE_SM, + "space_sm.pcx" + }, #define xM( _m ) { PCX_MOON##_m, "moon"#_m".pcx" } - xM( 1 ), - xM( 2 ), - xM( 3 ), + xM( 1 ), + xM( 2 ), + xM( 3 ), #undef xM - { - PCX_MOON1, - "moon1.pcx" - }, - { - PCX_MOON2, - "moon2.pcx" - }, - { - PCX_MOON3, - "moon3.pcx" - }, + { + PCX_MOON1, + "moon1.pcx" + }, + { + PCX_MOON2, + "moon2.pcx" + }, + { + PCX_MOON3, + "moon3.pcx" + }, #define xSLC( _s, _l, _c ) { PCX_S##_s##L##_l##C##_c, "S"#_s"L"#_l"C"#_c".pcx" } #define xSL( _s, _l ) \ xSLC( _s, _l, 1 ), \ @@ -91,68 +93,134 @@ const std::unordered_map< resource_t, std::string > s_builtin_resources = { xSL( _s, 1 ), \ xSL( _s, 2 ), \ xSL( _s, 3 ) - xS( 1 ), - xS( 2 ), - xS( 3 ), + xS( 1 ), + xS( 2 ), + xS( 3 ), #undef xS #undef xSL #undef xSLC - { - PCX_XI, - "xi.pcx" - }, - { - PCX_XF, - "xf.pcx" - }, + { + PCX_XI, + "xi.pcx" + }, + { + PCX_XF, + "xf.pcx" + }, + { + PCX_GAIANS, + "gaians.pcx" + }, + { + PCX_HIVE, + "hive.pcx" + }, + { + PCX_UNIV, + "univ.pcx" + }, + { + PCX_MORGAN, + "morgan.pcx" + }, + { + PCX_SPARTANS, + "spartans.pcx" + }, + { + PCX_BELIEVE, + "believe.pcx" + }, + { + PCX_PEACE, + "peace.pcx" + }, + { + PCX_CYBORG, + "cyborg.pcx" + }, + { + PCX_PIRATES, + "pirates.pcx" + }, + { + PCX_DRONE, + "drone.pcx" + }, + { + PCX_ANGELS, + "angels.pcx" + }, + { + PCX_FUNGBOY, + "fungboy.pcx" + }, + { + PCX_CARETAKE, + "caretake.pcx" + }, + { + PCX_USURPER, + "usurper.pcx" + }, - { - TTF_ARIALN, - "arialn.ttf" - }, - { - TTF_ARIALNB, - "arialnb.ttf" - }, + { + TTF_ARIALN, + "arialn.ttf" + }, + { + TTF_ARIALNB, + "arialnb.ttf" + }, - { - WAV_OPENING_MENU, - "opening menu.wav" - }, - { - WAV_OK, - "ok.wav" - }, - { - WAV_MENU_UP, - "menu up.wav" - }, - { - WAV_MENU_DOWN, - "menu down.wav" - }, - { - WAV_MENU_OUT, - "menu out.wav" - }, - { - WAV_AMENU2, - "amenu2.wav" - }, - { - WAV_MMENU, - "mmenu.wav" - }, - { - WAV_TURN_COMPLETE, - "cpu turn complete.wav" - }, - { - WAV_PLS_DONT_GO, - "CPU please don't go.wav" - }, + { + WAV_OPENING_MENU, + "opening menu.wav" + }, + { + WAV_OK, + "ok.wav" + }, + { + WAV_MENU_UP, + "menu up.wav" + }, + { + WAV_MENU_DOWN, + "menu down.wav" + }, + { + WAV_MENU_OUT, + "menu out.wav" + }, + { + WAV_AMENU2, + "amenu2.wav" + }, + { + WAV_MMENU, + "mmenu.wav" + }, + { + WAV_TURN_COMPLETE, + "cpu turn complete.wav" + }, + { + WAV_PLS_DONT_GO, + "CPU please don't go.wav" + }, -}; + } +) { + for ( const auto& it : m_resources_to_filenames ) { + m_filenames_to_resources.insert( + { + it.second, + it.first + } + ); + } +} void ResourceManager::Init( std::vector< std::string > possible_smac_paths ) { for ( const auto& path : possible_smac_paths ) { @@ -203,6 +271,14 @@ void ResourceManager::Init( std::vector< std::string > possible_smac_paths ) { THROW( "Unable to find SMAC distribution (tried paths: " + paths + "). Run from SMAC directory or pass it with --smacpath argument" ); } +const resource_t ResourceManager::GetResource( const std::string& filename ) const { + const auto it = m_filenames_to_resources.find( filename ); + if ( it != m_filenames_to_resources.end() ) { + return it->second; + } + return NONE; +} + const std::string& ResourceManager::GetPath( const resource_t res ) const { ASSERT_NOLOG( m_resource_paths.find( res ) != m_resource_paths.end(), "resource path for " + std::to_string( res ) + " not found" ); return m_resource_paths.at( res ); @@ -257,8 +333,8 @@ const bool ResourceManager::CheckFiles( const std::string& path, const std::vect const bool ResourceManager::ResolveBuiltins( const std::string& path, const extension_path_map_t& extension_path_map, const path_modifier_t path_modifiers ) { std::unordered_map< resource::resource_t, std::string > resolved_files = {}; - resolved_files.reserve( s_builtin_resources.size() ); - for ( const auto& it : s_builtin_resources ) { + resolved_files.reserve( m_resources_to_filenames.size() ); + for ( const auto& it : m_resources_to_filenames ) { const auto resolved_file = util::FS::GetExistingCaseSensitivePath( path, GetFixedPath( it.second, extension_path_map, path_modifiers ) ); if ( resolved_file.empty() || !util::FS::IsFile( resolved_file ) ) { return false; @@ -270,7 +346,7 @@ const bool ResourceManager::ResolveBuiltins( const std::string& path, const exte } ); } - ASSERT_NOLOG( resolved_files.size() == s_builtin_resources.size(), "some files were not resolved" ); + ASSERT_NOLOG( resolved_files.size() == m_resources_to_filenames.size(), "some files were not resolved" ); ASSERT_NOLOG( m_resource_paths.empty(), "resource paths not empty" ); m_smac_path = path; m_resource_paths = resolved_files; diff --git a/src/resource/ResourceManager.h b/src/resource/ResourceManager.h index 939114ba..9edeafce 100644 --- a/src/resource/ResourceManager.h +++ b/src/resource/ResourceManager.h @@ -11,13 +11,19 @@ namespace resource { CLASS( ResourceManager, base::Module ) + ResourceManager(); + void Init( std::vector< std::string > possible_smac_paths ); + const resource_t GetResource( const std::string& filename ) const; const std::string& GetPath( const resource_t res ) const; const std::string& GetCustomPath( const std::string& path ); private: + const std::unordered_map< resource_t, std::string > m_resources_to_filenames = {}; + std::unordered_map< std::string, resource_t > m_filenames_to_resources = {}; + typedef std::unordered_map< std::string, std::string > extension_path_map_t; typedef uint8_t path_modifier_t; diff --git a/src/resource/Types.h b/src/resource/Types.h index fb2f5a7c..418ad50e 100644 --- a/src/resource/Types.h +++ b/src/resource/Types.h @@ -42,7 +42,21 @@ enum resource_t : uint8_t { #undef xSLC PCX_XI, PCX_XF, - + PCX_GAIANS, + PCX_HIVE, + PCX_UNIV, + PCX_MORGAN, + PCX_SPARTANS, + PCX_BELIEVE, + PCX_PEACE, + PCX_CYBORG, + PCX_PIRATES, + PCX_DRONE, + PCX_ANGELS, + PCX_FUNGBOY, + PCX_CARETAKE, + PCX_USURPER, + TTF_ARIALN, TTF_ARIALNB, diff --git a/src/task/game/Animation.cpp b/src/task/game/Animation.cpp index 2cb07e99..29df019e 100644 --- a/src/task/game/Animation.cpp +++ b/src/task/game/Animation.cpp @@ -18,6 +18,7 @@ Animation::Animation( const size_t animation_id, AnimationDef* def, const types: m_sound = new scene::actor::Sound( "Animation_Sound_" + std::to_string( animation_id ), def->GetSound() ); g_engine->GetAudio()->AddActor( m_sound ); m_timer.SetInterval( m_def->GetDurationMs() / m_frames.size() ); + ShowNextFrame(); m_sound->Play(); } @@ -36,19 +37,23 @@ const bool Animation::IsFinished() const { void Animation::Iterate() { while ( m_timer.HasTicked() ) { - if ( m_frame_index ) { - // clear previous frame - m_frames.at( m_frame_index - 1 )->actor->RemoveInstance( m_instance_id ); - } - if ( m_frame_index++ < m_frames.size() ) { - // show next frame - m_instance_id = m_frames.at( m_frame_index - 1 )->actor->AddInstance( m_render_coords ); - } - else { - // no frames left - m_instance_id = 0; - m_timer.Stop(); - } + ShowNextFrame(); + } +} + +void Animation::ShowNextFrame() { + if ( m_frame_index ) { + // clear previous frame + m_frames.at( m_frame_index - 1 )->actor->RemoveInstance( m_instance_id ); + } + if ( m_frame_index++ < m_frames.size() ) { + // show next frame + m_instance_id = m_frames.at( m_frame_index - 1 )->actor->AddInstance( m_render_coords ); + } + else { + // no frames left + m_instance_id = 0; + m_timer.Stop(); } } diff --git a/src/task/game/Animation.h b/src/task/game/Animation.h index 1d2c7109..ec6d0d8d 100644 --- a/src/task/game/Animation.h +++ b/src/task/game/Animation.h @@ -25,6 +25,8 @@ class Animation { private: + void ShowNextFrame(); + util::Timer m_timer; scene::actor::Sound* m_sound = nullptr; AnimationDef* m_def = nullptr; diff --git a/src/task/game/AnimationDef.cpp b/src/task/game/AnimationDef.cpp index 5dbeef01..acbd5827 100644 --- a/src/task/game/AnimationDef.cpp +++ b/src/task/game/AnimationDef.cpp @@ -13,58 +13,59 @@ AnimationDef::AnimationDef( InstancedSpriteManager* ism, const ::game::animation , m_id( def->m_id ) , m_type( def->m_type ) , m_duration_ms( def->m_duration_ms ) - , m_sound( g_engine->GetSoundLoader()->LoadCustomSound( def->m_sound_file ) ) { + , m_sound_file( def->m_sound_file ) { ASSERT_NOLOG( def->m_type == ::game::animation::animation_type_t::AT_FRAMES_ROW, "only frames row animations are supported for now" ); - const auto* d = (::game::animation::FramesRow*)def; - - auto* texture = g_engine->GetTextureLoader()->LoadCustomTexture( d->m_file ); - m_sprites = {}; - const uint32_t w = d->m_frame_width; - const uint32_t h = d->m_frame_height; - const uint32_t p = d->m_frame_padding; - const types::Vec2< uint32_t > src_wh = { - w, - h - }; - const types::Vec2< float > dst_wh = { - d->m_scale_x, - d->m_scale_y / 0.8f - }; - const types::Vec2< uint32_t > cxy = { - d->m_frame_center_x,//(uint32_t)( (float)d->m_frame_center_x * d->m_scale_x ), - d->m_frame_center_y,//(uint32_t)( (float)d->m_frame_center_y * d->m_scale_y * 0.8f ), - }; - for ( size_t i = 0 ; i < d->m_frames_count ; i++ ) { - const uint32_t x = d->m_row_x + ( i % d->m_frames_per_row ) * ( w + p ); - const uint32_t y = d->m_row_y + ( i / d->m_frames_per_row ) * ( h + p ); - - m_sprites.push_back( - m_ism->GetInstancedSprite( - "Animation_" + d->m_id, - texture, - { - x, - y - }, - src_wh, - { - x + cxy.x, - y + cxy.y - }, - dst_wh, - 0.5f // ? - ) - ); - } + const auto* d = (::game::animation::FramesRow*)def; + m_render = d->m_render; + ASSERT_NOLOG( m_render.frames_count > 0, "animation has no frames defined" ); } AnimationDef::~AnimationDef() { // } -const instanced_sprites_t& AnimationDef::GetSprites() const { +const instanced_sprites_t& AnimationDef::GetSprites() { + if ( m_sprites.empty() ) { + auto* texture = g_engine->GetTextureLoader()->LoadCustomTexture( m_render.file ); + const uint32_t w = m_render.frame_width; + const uint32_t h = m_render.frame_height; + const uint32_t p = m_render.frame_padding; + const types::Vec2< uint32_t > src_wh = { + w, + h + }; + const types::Vec2< float > dst_wh = { + m_render.scale_x, + m_render.scale_y / 0.8f + }; + const types::Vec2< uint32_t > cxy = { + m_render.frame_center_x, + m_render.frame_center_y, + }; + for ( size_t i = 0 ; i < m_render.frames_count ; i++ ) { + const uint32_t x = m_render.row_x + ( i % m_render.frames_per_row ) * ( w + p ); + const uint32_t y = m_render.row_y + ( i / m_render.frames_per_row ) * ( h + p ); + m_sprites.push_back( + m_ism->GetInstancedSprite( + "Animation_" + m_id, + texture, + { + x, + y + }, + src_wh, + { + x + cxy.x, + y + cxy.y + }, + dst_wh, + 0.5f // ? + ) + ); + } + } return m_sprites; } @@ -72,7 +73,10 @@ const size_t AnimationDef::GetDurationMs() const { return m_duration_ms; } -const types::Sound* AnimationDef::GetSound() const { +const types::Sound* AnimationDef::GetSound() { + if ( !m_sound ) { + m_sound = g_engine->GetSoundLoader()->LoadCustomSound( m_sound_file ); + } return m_sound; } diff --git a/src/task/game/AnimationDef.h b/src/task/game/AnimationDef.h index 03d861bd..fb10edd3 100644 --- a/src/task/game/AnimationDef.h +++ b/src/task/game/AnimationDef.h @@ -22,21 +22,24 @@ class AnimationDef { AnimationDef( InstancedSpriteManager* ism, const ::game::animation::Def* def ); ~AnimationDef(); - const instanced_sprites_t& GetSprites() const; + const instanced_sprites_t& GetSprites(); const size_t GetDurationMs() const; - const types::Sound* GetSound() const; + const types::Sound* GetSound(); private: - InstancedSpriteManager* const m_ism; + InstancedSpriteManager* const m_ism = nullptr; - std::string m_id; + ::game::animation::sprite_render_info_t m_render = {}; + + std::string m_id = ""; ::game::animation::animation_type_t m_type; - types::Sound* m_sound; + types::Sound* m_sound = nullptr; instanced_sprites_t m_sprites = {}; - const size_t m_duration_ms; + const size_t m_duration_ms = 0; + const std::string m_sound_file = ""; }; } diff --git a/src/task/game/CMakeLists.txt b/src/task/game/CMakeLists.txt index 12b05ec4..ecdcb681 100644 --- a/src/task/game/CMakeLists.txt +++ b/src/task/game/CMakeLists.txt @@ -1,6 +1,7 @@ SUBDIR( ui ) SUBDIR( actor ) SUBDIR( faction ) +SUBDIR( tile ) SUBDIR( unit ) SET( SRC ${SRC} @@ -12,6 +13,5 @@ SET( SRC ${SRC} ${PWD}/Slot.cpp ${PWD}/AnimationDef.cpp ${PWD}/Animation.cpp - ${PWD}/Tile.cpp PARENT_SCOPE ) diff --git a/src/task/game/Game.cpp b/src/task/game/Game.cpp index cae223fb..ddd25fde 100644 --- a/src/task/game/Game.cpp +++ b/src/task/game/Game.cpp @@ -24,6 +24,7 @@ #include "game/event/CompleteTurn.h" #include "game/event/UncompleteTurn.h" #include "ui/bottom_bar/BottomBar.h" +#include "tile/TileManager.h" #include "unit/UnitManager.h" #include "faction/FactionManager.h" #include "InstancedSpriteManager.h" @@ -33,7 +34,6 @@ #include "task/game/unit/UnitDef.h" #include "Slot.h" #include "task/game/unit/BadgeDefs.h" -#include "scene/actor/Actor.h" #include "scene/actor/Instanced.h" #include "InstancedSprite.h" #include "loader/texture/TextureLoader.h" @@ -46,6 +46,7 @@ #include "types/mesh/Render.h" #include "types/mesh/Data.h" #include "ui/style/Theme.h" +#include "game/map/Consts.h" #define INITIAL_CAMERA_ANGLE { -M_PI * 0.5, M_PI * 0.75, 0 } @@ -182,18 +183,15 @@ void Game::Iterate() { m_on_start = nullptr; } - UpdateMapData( - { - response.data.get_map_data->map_width, - response.data.get_map_data->map_height - } - ); - if ( m_is_initialized ) { Deinitialize(); } Initialize( + { + response.data.get_map_data->map_width, + response.data.get_map_data->map_height + }, response.data.get_map_data->terrain_texture, response.data.get_map_data->terrain_mesh, response.data.get_map_data->terrain_data_mesh, @@ -386,7 +384,7 @@ void Game::Iterate() { const auto tile_at = GetTileAtScreenCoordsResult(); if ( tile_at.is_set ) { ASSERT( m_tile_at_query_purpose != ::game::TQP_NONE, "tile preferred mode not set" ); - auto* tile = GetTile( tile_at.tile_pos ); + auto* tile = m_tm->GetTile( tile_at.tile_pos ); if ( m_is_map_editing_allowed && m_is_editing_mode ) { if ( !m_mt_ids.edit_map ) { // TODO: need to queue? m_mt_ids.edit_map = game->MT_EditMap( tile->GetCoords(), m_editor_tool, m_editor_brush, m_editor_draw_mode ); @@ -468,6 +466,11 @@ const std::string& Game::GetMapLastDirectory() const { return m_map_data.last_directory; } +tile::TileManager* Game::GetTM() const { + ASSERT( m_tm, "tm not set" ); + return m_tm; +} + unit::UnitManager* Game::GetUM() const { ASSERT( m_um, "um not set" ); return m_um; @@ -808,17 +811,6 @@ Slot* Game::GetSlot( const size_t index ) const { return m_slots.at( index ); } -Tile* Game::GetTile( const size_t x, const size_t y ) { - ASSERT( !m_tiles.empty(), "tile states not set" ); - ASSERT( x < m_map_data.width, "tile x overflow" ); - ASSERT( y < m_map_data.height, "tile y overflow" ); - return &m_tiles.at( y * m_map_data.width + x ); -} - -Tile* Game::GetTile( const types::Vec2< size_t >& coords ) { - return GetTile( coords.x, coords.y ); -} - void Game::DefineSlot( const size_t slot_index, const faction::Faction* faction @@ -908,7 +900,7 @@ void Game::ProcessRequest( const ::game::FrontendRequest* request ) { ASSERT( t, "tile not found" ); const auto& ts = tile_data.second; ASSERT( ts, "tile state not found" ); - auto* tile = GetTile( t->coord.x, t->coord.y ); + auto* tile = m_tm->GetTile( t->coord.x, t->coord.y ); ASSERT( tile, "matching tile not found" ); Log( "Updating tile: " + tile->GetCoords().ToString() ); @@ -1046,7 +1038,7 @@ void Game::ProcessRequest( const ::game::FrontendRequest* request ) { case ::game::FrontendRequest::FR_UNIT_MOVE: { const auto& d = request->data.unit_move; auto* unit = m_um->GetUnitById( d.unit_id ); - auto* dst_tile = GetTile( + auto* dst_tile = m_tm->GetTile( { d.dst_tile_coords.x, d.dst_tile_coords.y @@ -1075,8 +1067,6 @@ void Game::DeactivateTurn() { void Game::UpdateMapData( const types::Vec2< size_t >& map_size ) { - ASSERT( m_tiles.empty(), "tile states already set" ); - m_map_data.width = map_size.x; m_map_data.height = map_size.y; m_map_data.range.min = { @@ -1100,75 +1090,11 @@ void Game::UpdateMapData( const types::Vec2< size_t >& map_size ) { } ); - m_tiles.reserve( m_map_data.width * m_map_data.height / 2 ); // / 2 because smac coordinate system - for ( size_t y = 0 ; y < m_map_data.height ; y++ ) { - for ( size_t x = y & 1 ; x < m_map_data.width ; x += 2 ) { - m_tiles.insert( - { - y * m_map_data.width + x, - Tile{ - { - x, - y - } - } - } - ); - } - } - - // link tiles to neighbours - for ( size_t y = 0 ; y < m_map_data.height ; y++ ) { - for ( size_t x = y & 1 ; x < m_map_data.width ; x += 2 ) { - auto* ts = GetTile( - { - x, - y - } - ); - - ts->W = ( x >= 2 ) - ? GetTile( x - 2, y ) - : GetTile( m_map_data.width - 1 - ( 1 - ( y % 2 ) ), y ); - ts->NW = ( y >= 1 ) - ? ( ( x >= 1 ) - ? GetTile( x - 1, y - 1 ) - : GetTile( m_map_data.width - 1, y - 1 ) - ) - : ts; - ts->N = ( y >= 2 ) - ? GetTile( x, y - 2 ) - : ts; - ts->NE = ( y >= 1 ) - ? ( ( x < m_map_data.width - 1 ) - ? GetTile( x + 1, y - 1 ) - : GetTile( 0, y - 1 ) - ) - : ts; - ts->E = ( x < m_map_data.width - 2 ) - ? GetTile( x + 2, y ) - : GetTile( y % 2, y ); - ts->SE = ( y < m_map_data.height - 1 ) - ? ( ( x < m_map_data.width - 1 ) - ? GetTile( x + 1, y + 1 ) - : GetTile( 0, y + 1 ) - ) - : ts; - ts->S = ( y < m_map_data.height - 2 ) - ? GetTile( x, y + 2 ) - : ts; - ts->SW = ( y < m_map_data.height - 1 ) - ? ( ( x >= 1 ) - ? GetTile( x - 1, y + 1 ) - : GetTile( m_map_data.width - 1, y + 1 ) - ) - : ts; - } - } - + m_tm->InitTiles( map_size ); } void Game::Initialize( + const types::Vec2< size_t >& map_size, types::texture::Texture* terrain_texture, types::mesh::Render* terrain_mesh, types::mesh::Data* terrain_data_mesh, @@ -1190,7 +1116,8 @@ void Game::Initialize( NEW( m_world_scene, scene::Scene, "Game", scene::SCENE_TYPE_ORTHO ); NEW( m_ism, InstancedSpriteManager, m_world_scene ); - NEW( m_fm, faction::FactionManager ); + NEW( m_fm, faction::FactionManager, this ); + NEW( m_tm, tile::TileManager, this ); NEW( m_um, unit::UnitManager, this ); NEW( m_camera, scene::Camera, scene::Camera::CT_ORTHOGRAPHIC ); @@ -1267,6 +1194,7 @@ void Game::Initialize( } // process tiles + UpdateMapData( map_size ); ASSERT( tiles, "tiles not set" ); ASSERT( tiles->size() == m_map_data.width * m_map_data.height, "tiles count mismatch" ); // TODO: /2 @@ -1275,7 +1203,7 @@ void Game::Initialize( for ( size_t y = 0 ; y < m_map_data.height ; y++ ) { for ( size_t x = y & 1 ; x < m_map_data.width ; x += 2 ) { - auto* tile = GetTile( x, y ); + auto* tile = m_tm->GetTile( x, y ); Log( "Initializing tile: " + tile->GetCoords().ToString() ); tile->Update( tiles->at( y * m_map_data.width + x / 2 ), tile_states->at( y * m_map_data.width + x / 2 ) ); } @@ -1317,7 +1245,8 @@ void Game::Initialize( m_ui.bottom_bar->CloseMenus(); if ( !data->key.modifiers ) { - if ( m_selected_tile ) { + auto* selected_tile = m_tm->GetSelectedTile(); + if ( selected_tile ) { bool is_tile_selected = false; ::game::map::tile::direction_t td = ::game::map::tile::D_NONE; @@ -1363,7 +1292,7 @@ void Game::Initialize( } if ( is_tile_selected ) { - auto* tile = m_selected_tile->GetNeighbour( td ); + auto* tile = selected_tile->GetNeighbour( td ); auto* selected_unit = m_um->GetSelectedUnit(); if ( !selected_unit ) { @@ -1390,7 +1319,7 @@ void Game::Initialize( else { // attack // TODO: select the most powerful defender for attacker - const auto& target_unit = foreign_units.at( Tile::GetUnitsOrder( foreign_units ).front() ); + const auto& target_unit = foreign_units.at( tile::Tile::GetUnitsOrder( foreign_units ).front() ); const auto event = ::game::event::AttackUnit( m_slot_index, selected_unit->GetId(), target_unit->GetId() ); game->MT_AddEvent( &event ); } @@ -1739,6 +1668,11 @@ void Game::Deinitialize() { m_um = nullptr; } + if ( m_tm ) { + DELETE( m_tm ); + m_tm = nullptr; + } + if ( m_ism ) { DELETE( m_ism ); m_ism = nullptr; @@ -1793,17 +1727,18 @@ void Game::SelectTileAtPoint( const ::game::tile_query_purpose_t tile_query_purp GetTileAtScreenCoords( tile_query_purpose, x, m_viewport.window_height - y ); // async } -void Game::SelectTileOrUnit( Tile* tile, const size_t selected_unit_id ) { +void Game::SelectTileOrUnit( tile::Tile* tile, const size_t selected_unit_id ) { ASSERT( m_tile_at_query_purpose != ::game::TQP_NONE, "tile query purpose not set" ); DeselectTileOrUnit(); - m_selected_tile = tile; + m_tm->SelectTile( tile ); unit::Unit* selected_unit = nullptr; + if ( m_tile_at_query_purpose == ::game::TQP_UNIT_SELECT ) { - const auto& units = m_selected_tile->GetUnits(); + const auto& units = tile->GetUnits(); if ( m_is_turn_active ) { if ( selected_unit_id ) { for ( const auto& it : units ) { @@ -1814,7 +1749,7 @@ void Game::SelectTileOrUnit( Tile* tile, const size_t selected_unit_id ) { } } if ( !selected_unit ) { - selected_unit = m_selected_tile->GetMostImportantUnit();//GetFirstSelectableUnit( units ); + selected_unit = tile->GetMostImportantUnit();//GetFirstSelectableUnit( units ); } } if ( !selected_unit ) { @@ -1825,9 +1760,9 @@ void Game::SelectTileOrUnit( Tile* tile, const size_t selected_unit_id ) { switch ( m_tile_at_query_purpose ) { case ::game::TQP_TILE_SELECT: { m_um->DeselectUnit(); - Log( "Selected tile at " + m_selected_tile->GetCoords().ToString() + " ( " + m_selected_tile->GetRenderData().selection_coords.center.ToString() + " )" ); + Log( "Selected tile at " + tile->GetCoords().ToString() + " ( " + tile->GetRenderData().selection_coords.center.ToString() + " )" ); ShowTileSelector(); - m_ui.bottom_bar->PreviewTile( m_selected_tile, selected_unit_id ); + m_ui.bottom_bar->PreviewTile( tile, selected_unit_id ); break; } case ::game::TQP_UNIT_SELECT: { @@ -1864,7 +1799,7 @@ void Game::RemoveActor( actor::Actor* actor ) { m_actors_map.erase( it ); } -const types::Vec2< float > Game::GetTileWindowCoordinates( const Tile* tile ) const { +const types::Vec2< float > Game::GetTileWindowCoordinates( const tile::Tile* tile ) const { const auto& c = tile->GetRenderData().coords; return { c.x * m_viewport.window_aspect_ratio * m_camera_position.z, @@ -1883,7 +1818,7 @@ void Game::ScrollTo( const types::Vec3& target ) { m_scroller.Scroll( m_camera_position, target, SCROLL_DURATION_MS ); } -void Game::ScrollToTile( const Tile* tile, bool center_on_tile ) { +void Game::ScrollToTile( const tile::Tile* tile, bool center_on_tile ) { auto tc = GetTileWindowCoordinates( tile ); @@ -2088,7 +2023,7 @@ void Game::ResetMapState() { } m_tile_at_query_purpose = ::game::TQP_TILE_SELECT; - SelectTileOrUnit( GetTile( coords ) ); + SelectTileOrUnit( m_tm->GetTile( coords ) ); } void Game::SmoothScroll( const float scroll_value ) { @@ -2243,7 +2178,7 @@ const float Game::GetCloserX( const float x, const float ref_x ) const { void Game::ShowTileSelector() { HideTileSelector(); - NEW( m_actors.tile_selection, actor::TileSelection, m_selected_tile->GetRenderData().selection_coords ); + NEW( m_actors.tile_selection, actor::TileSelection, m_tm->GetSelectedTile()->GetRenderData().selection_coords ); AddActor( m_actors.tile_selection ); } @@ -2254,7 +2189,7 @@ void Game::HideTileSelector() { } } -void Game::RenderTile( Tile* tile, const unit::Unit* selected_unit ) { +void Game::RenderTile( tile::Tile* tile, const unit::Unit* selected_unit ) { tile->Render( selected_unit ? selected_unit->GetId() @@ -2280,49 +2215,57 @@ const size_t Game::GetMySlotIndex() const { return m_slot_index; } -Tile* Game::GetSelectedTile() const { - return m_selected_tile; -} - -void Game::SetSelectedTile( Tile* tile ) { - m_selected_tile = tile; +void Game::SetSelectedTile( tile::Tile* tile ) { + m_tm->SelectTile( tile ); } void Game::RefreshSelectedTile( unit::Unit* selected_unit ) { - if ( m_selected_tile ) { + auto* selected_tile = m_tm->GetSelectedTile(); + if ( selected_tile ) { m_ui.bottom_bar->PreviewTile( - m_selected_tile, selected_unit + selected_tile, selected_unit ? selected_unit->GetId() : 0 ); } } -void Game::RefreshSelectedTileIf( task::game::Tile* if_tile, unit::Unit* selected_unit ) { - if ( m_selected_tile && m_selected_tile == if_tile ) { +void Game::RefreshSelectedTileIf( tile::Tile* if_tile, unit::Unit* selected_unit ) { + auto* selected_tile = m_tm->GetSelectedTile(); + if ( selected_tile && selected_tile == if_tile ) { RefreshSelectedTile( selected_unit ); } } void Game::ScrollToSelectedTile( const bool center_on_tile ) { - ScrollToTile( m_selected_tile, center_on_tile ); + ASSERT( m_tm->GetSelectedTile(), "tile not selected" ); + ScrollToTile( m_tm->GetSelectedTile(), center_on_tile ); } void Game::SelectUnitOrSelectedTile( unit::Unit* selected_unit ) { + ASSERT( m_tm->GetSelectedTile(), "tile not selected" ); SelectTileOrUnit( - m_selected_tile, selected_unit + m_tm->GetSelectedTile(), selected_unit ? selected_unit->GetId() : 0 ); } unit::Unit* Game::GetSelectedTileMostImportantUnit() const { - if ( m_selected_tile && !m_selected_tile->GetUnits().empty() ) { - return m_selected_tile->GetMostImportantUnit(); + auto* selected_tile = m_tm->GetSelectedTile(); + if ( selected_tile && !selected_tile->GetUnits().empty() ) { + return selected_tile->GetMostImportantUnit(); } else { return nullptr; } } + +Game::map_data_t::map_data_t() + : filename( ::game::map::s_consts.fs.default_map_filename + ::game::map::s_consts.fs.default_map_extension ) + , last_directory( util::FS::GetCurrentDirectory() + util::FS::PATH_SEPARATOR + ::game::map::s_consts.fs.default_map_directory ) { + // +} + } } diff --git a/src/task/game/Game.h b/src/task/game/Game.h index 84365b4b..e0abdda7 100644 --- a/src/task/game/Game.h +++ b/src/task/game/Game.h @@ -23,15 +23,10 @@ #include "util/Scroller.h" // TODO: remove those -#include "game/map/tile/Tile.h" #include "game/map/tile/TileState.h" -#include "Tile.h" +#include "task/game/tile/Tile.h" #include "game/BackendRequest.h" -// TODO: remove this -#include "game/map/Consts.h" -#include "util/FS.h" - namespace types { namespace texture { class Texture; @@ -83,6 +78,11 @@ class FactionManager; class Faction; } +namespace tile { +class TileManager; +class Tile; +} + namespace unit { class UnitDef; class Unit; @@ -150,15 +150,12 @@ CLASS( Game, base::Task ) }; static const consts_t s_consts; - faction::FactionManager* m_fm = nullptr; - unit::UnitManager* m_um = nullptr; - InstancedSpriteManager* m_ism = nullptr; - const size_t GetMapWidth() const; const size_t GetMapHeight() const; const std::string& GetMapFilename() const; const std::string& GetMapLastDirectory() const; + tile::TileManager* GetTM() const; unit::UnitManager* GetUM() const; InstancedSpriteManager* GetISM() const; @@ -192,6 +189,26 @@ CLASS( Game, base::Task ) void ConfirmExit( ::ui::ui_handler_t on_confirm ); + // TODO: move this to .cpp + // structures received from game thread + struct map_data_t { + map_data_t(); + size_t width = 0; + size_t height = 0; + struct { + types::Vec2< float > min = {}; + types::Vec2< float > max = {}; + struct { + util::Clamper< float > x; + util::Clamper< float > y; + } percent_to_absolute; + } range; + std::string filename; + std::string last_directory; + }; + + map_data_t m_map_data = {}; + types::texture::Texture* GetTerrainTexture() const; void SetEditorTool( ::game::map_editor::tool_type_t tool ); @@ -203,11 +220,14 @@ CLASS( Game, base::Task ) const types::Vec3 GetCloserCoords( const types::Vec3& coords, const types::Vec3& ref_coords ) const; Slot* GetSlot( const size_t index ) const; - Tile* GetTile( const size_t x, const size_t y ); - Tile* GetTile( const types::Vec2< size_t >& coords ); private: + faction::FactionManager* m_fm = nullptr; + tile::TileManager* m_tm = nullptr; + unit::UnitManager* m_um = nullptr; + InstancedSpriteManager* m_ism = nullptr; + size_t m_slot_index = 0; bool m_is_turn_active = false; ::game::turn::turn_status_t m_turn_status = ::game::turn::TS_PLEASE_WAIT; @@ -232,6 +252,7 @@ CLASS( Game, base::Task ) bool m_is_initialized = false; void Initialize( + const types::Vec2< size_t >& map_size, types::texture::Texture* terrain_texture, types::mesh::Render* terrain_mesh, types::mesh::Data* terrain_data_mesh, @@ -322,33 +343,8 @@ CLASS( Game, base::Task ) void UpdateMapInstances(); void UpdateUICamera(); - // TODO: move this to .cpp - // structures received from game thread - struct map_data_t { - size_t width = 0; - size_t height = 0; - struct { - types::Vec2< float > min = {}; - types::Vec2< float > max = {}; - struct { - util::Clamper< float > x; - util::Clamper< float > y; - } percent_to_absolute; - } range; - std::string filename = - ::game::map::s_consts.fs.default_map_filename + - ::game::map::s_consts.fs.default_map_extension; - std::string last_directory = - util::FS::GetCurrentDirectory() + - util::FS::PATH_SEPARATOR + - ::game::map::s_consts.fs.default_map_directory; - }; - const bool m_is_map_editing_allowed = false; - Tile* m_selected_tile = nullptr; - map_data_t m_map_data = {}; - // UI stuff struct { @@ -359,7 +355,7 @@ CLASS( Game, base::Task ) bool m_is_resize_handler_set = false; void SelectTileAtPoint( const ::game::tile_query_purpose_t tile_query_purpose, const size_t x, const size_t y ); - void SelectTileOrUnit( Tile* tile, const size_t selected_unit_id = 0 ); + void SelectTileOrUnit( tile::Tile* tile, const size_t selected_unit_id = 0 ); void DeselectTileOrUnit(); private: @@ -382,10 +378,10 @@ CLASS( Game, base::Task ) void AddActor( actor::Actor* actor ); void RemoveActor( actor::Actor* actor ); - const types::Vec2< float > GetTileWindowCoordinates( const Tile* tile ) const; + const types::Vec2< float > GetTileWindowCoordinates( const tile::Tile* tile ) const; void ScrollTo( const ::types::Vec3& target ); - void ScrollToTile( const Tile* tile, bool center_on_tile ); + void ScrollToTile( const tile::Tile* tile, bool center_on_tile ); struct tile_at_result_t { bool is_set = false; @@ -426,8 +422,6 @@ CLASS( Game, base::Task ) #endif } m_mt_ids = {}; - std::unordered_map< size_t, Tile > m_tiles = {}; - std::unordered_map< size_t, Slot* > m_slots = {}; std::unordered_map< std::string, AnimationDef* > m_animationdefs = {}; std::unordered_map< size_t, Animation* > m_animations; @@ -442,7 +436,7 @@ CLASS( Game, base::Task ) void ShowTileSelector(); void HideTileSelector(); - void RenderTile( Tile* tile, const unit::Unit* selected_unit ); + void RenderTile( tile::Tile* tile, const unit::Unit* selected_unit ); void SendAnimationFinished( const size_t animation_id ); @@ -453,10 +447,9 @@ CLASS( Game, base::Task ) const size_t GetMySlotIndex() const; - Tile* GetSelectedTile() const; - void SetSelectedTile( Tile* tile ); + void SetSelectedTile( tile::Tile* tile ); void RefreshSelectedTile( unit::Unit* selected_unit ); - void RefreshSelectedTileIf( Tile* if_tile, unit::Unit* selected_unit ); + void RefreshSelectedTileIf( tile::Tile* if_tile, unit::Unit* selected_unit ); void ScrollToSelectedTile( const bool center_on_tile ); void SelectUnitOrSelectedTile( unit::Unit* selected_unit ); unit::Unit* GetSelectedTileMostImportantUnit() const; diff --git a/src/task/game/faction/Faction.cpp b/src/task/game/faction/Faction.cpp index b707b4a8..d475b4ef 100644 --- a/src/task/game/faction/Faction.cpp +++ b/src/task/game/faction/Faction.cpp @@ -1,17 +1,100 @@ #include "Faction.h" #include "game/rules/Faction.h" +#include "task/game/InstancedSpriteManager.h" +#include "engine/Engine.h" +#include "loader/texture/TextureLoader.h" + +#include "scene/actor/Instanced.h" namespace task { namespace game { namespace faction { -Faction::Faction( const ::game::rules::Faction* def ) - : m_border_color( def->m_colors.border ) - , m_is_progenitor( def->m_flags & ::game::rules::Faction::FF_PROGENITOR ) { +Faction::Faction( const ::game::rules::Faction* def, InstancedSpriteManager* ism ) + : m_ism( ism ) + , m_id( def->m_id ) + , m_border_color( def->m_colors.border ) + , m_is_progenitor( def->m_flags & ::game::rules::Faction::FF_PROGENITOR ) + , m_render( + { + def->m_bases_render, + } + ) { // } +Sprite* Faction::GetBaseSprite( const bool is_water, const uint8_t size, const uint8_t perimeter_level ) { + ASSERT_NOLOG( size < 4, "base size overflow ( " + std::to_string( size ) + " >= 4 )" ); + ASSERT_NOLOG( perimeter_level < 3, "base perimeter level overflow ( " + std::to_string( perimeter_level ) + " >= 3 )" ); + const uint8_t index = ( is_water + ? 12 + : 0 + ) + size + perimeter_level * 4; + auto it = m_base_grid_sprites.find( index ); + if ( it == m_base_grid_sprites.end() ) { + + const uint32_t w = m_render.bases_render.cell_width; + const uint32_t h = m_render.bases_render.cell_height; + const uint32_t p = m_render.bases_render.cell_padding; + const types::Vec2< uint32_t > src_wh = { + w, + h + }; + const types::Vec2< float > dst_wh = { + m_render.bases_render.scale_x, + m_render.bases_render.scale_y / 0.8f + }; + const types::Vec2< uint32_t > cxy = { + (uint32_t)m_render.bases_render.cell_cx, + (uint32_t)m_render.bases_render.cell_cy + }; + + const uint32_t x = m_render.bases_render.grid_x + size * ( w + p ); + const uint32_t y = m_render.bases_render.grid_y + ( perimeter_level + ( is_water + ? 3 + : 0 + ) + ) * ( h + p ); + + it = m_base_grid_sprites.insert( + { + index, + { + m_ism->GetInstancedSprite( + "Faction_Base_" + m_id + "_" + ( is_water + ? "W" + : "L" + ) + " " + std::to_string( size ) + "_" + std::to_string( perimeter_level ), + GetBaseGridTexture(), + { + x, + y + }, + src_wh, + { + x + cxy.x, + y + cxy.y + }, + dst_wh, + 0.5f // ? + ), + 1 + } + } + ).first; + + } + return &it->second; +} + +types::texture::Texture* Faction::GetBaseGridTexture() { + if ( !m_base_grid_texture ) { + m_base_grid_texture = g_engine->GetTextureLoader()->LoadCustomTexture( m_render.bases_render.file ); + } + return m_base_grid_texture; +} + } } } diff --git a/src/task/game/faction/Faction.h b/src/task/game/faction/Faction.h index 3d97cf3b..5617acf7 100644 --- a/src/task/game/faction/Faction.h +++ b/src/task/game/faction/Faction.h @@ -1,6 +1,17 @@ #pragma once +#include + +#include "game/rules/Types.h" + #include "types/Color.h" +#include "task/game/Sprite.h" + +namespace types { +namespace texture { +class Texture; +} +} namespace game::rules { class Faction; @@ -8,14 +19,36 @@ class Faction; namespace task { namespace game { + +class InstancedSpriteManager; +class InstancedSprite; + namespace faction { class Faction { public: - Faction( const ::game::rules::Faction* def ); + Faction( const ::game::rules::Faction* def, InstancedSpriteManager* ism ); + Sprite* GetBaseSprite( const bool is_water, const uint8_t size, const uint8_t perimeter_level ); + + const std::string m_id; const types::Color m_border_color; const bool m_is_progenitor; + +private: + + InstancedSpriteManager* m_ism = nullptr; + + struct { + ::game::rules::bases_render_info_t bases_render; + } m_render = {}; + + types::texture::Texture* m_base_grid_texture = nullptr; + types::texture::Texture* GetBaseGridTexture(); + + std::unordered_map< uint8_t, Sprite > m_base_grid_sprites = {}; + Sprite m_base_sprites[6][4] = {}; + }; } diff --git a/src/task/game/faction/FactionManager.cpp b/src/task/game/faction/FactionManager.cpp index 1a6c21d0..1ce4d6da 100644 --- a/src/task/game/faction/FactionManager.cpp +++ b/src/task/game/faction/FactionManager.cpp @@ -1,5 +1,6 @@ #include "FactionManager.h" +#include "task/game/Game.h" #include "game/rules/Faction.h" #include "Faction.h" @@ -7,10 +8,15 @@ namespace task { namespace game { namespace faction { +FactionManager::FactionManager( Game* game ) + : m_game( game ) { + +} + void FactionManager::DefineFaction( const ::game::rules::Faction* def ) { ASSERT( def, "faction is null" ); ASSERT( m_factions.find( def->m_id ) == m_factions.end(), "faction already defined" ); - NEWV( faction, Faction, def ); + NEWV( faction, Faction, def, m_game->GetISM() ); m_factions.insert( { def->m_id, diff --git a/src/task/game/faction/FactionManager.h b/src/task/game/faction/FactionManager.h index 2c2163c6..c6afff5a 100644 --- a/src/task/game/faction/FactionManager.h +++ b/src/task/game/faction/FactionManager.h @@ -10,17 +10,25 @@ class Faction; namespace task { namespace game { + +class Game; + namespace faction { class Faction; CLASS( FactionManager, base::Base ) + FactionManager( Game* game ); + void DefineFaction( const ::game::rules::Faction* def ); Faction* GetFactionById( const std::string& id ) const; private: + + Game* m_game = nullptr; + std::unordered_map< std::string, Faction* > m_factions = {}; }; diff --git a/src/task/game/tile/CMakeLists.txt b/src/task/game/tile/CMakeLists.txt new file mode 100644 index 00000000..a94a05de --- /dev/null +++ b/src/task/game/tile/CMakeLists.txt @@ -0,0 +1,6 @@ +SET( SRC ${SRC} + + ${PWD}/TileManager.cpp + ${PWD}/Tile.cpp + + PARENT_SCOPE ) diff --git a/src/task/game/Tile.cpp b/src/task/game/tile/Tile.cpp similarity index 99% rename from src/task/game/Tile.cpp rename to src/task/game/tile/Tile.cpp index f4fe9e75..6ff57dfe 100644 --- a/src/task/game/Tile.cpp +++ b/src/task/game/tile/Tile.cpp @@ -7,6 +7,7 @@ namespace task { namespace game { +namespace tile { std::vector< size_t > Tile::GetUnitsOrder( const std::unordered_map< size_t, unit::Unit* >& units ) { std::map< size_t, std::vector< size_t > > weights; // { weight, units } @@ -462,3 +463,4 @@ void Tile::Update( const ::game::map::tile::Tile& tile, const ::game::map::tile: } } +} diff --git a/src/task/game/Tile.h b/src/task/game/tile/Tile.h similarity index 98% rename from src/task/game/Tile.h rename to src/task/game/tile/Tile.h index 3c323897..bc293ec6 100644 --- a/src/task/game/Tile.h +++ b/src/task/game/tile/Tile.h @@ -25,6 +25,8 @@ namespace unit { class Unit; } +namespace tile { + class Tile { public: @@ -81,3 +83,4 @@ class Tile { } } +} diff --git a/src/task/game/tile/TileManager.cpp b/src/task/game/tile/TileManager.cpp new file mode 100644 index 00000000..cc15f1f4 --- /dev/null +++ b/src/task/game/tile/TileManager.cpp @@ -0,0 +1,107 @@ +#include "TileManager.h" + +#include "game/map/Consts.h" +#include "util/FS.h" + +namespace task { +namespace game { +namespace tile { + +TileManager::TileManager( Game* game ) + : m_game( game ) { + // +} + +void TileManager::InitTiles( const types::Vec2< size_t > map_size ) { + ASSERT( m_tiles.empty(), "tile states already set" ); + + m_map_size = map_size; + m_tiles.reserve( m_map_size.x * m_map_size.y / 2 ); // / 2 because smac coordinate system + for ( size_t y = 0 ; y < m_map_size.y ; y++ ) { + for ( size_t x = y & 1 ; x < m_map_size.x ; x += 2 ) { + m_tiles.insert( + { + y * m_map_size.x + x, + Tile{ + { + x, + y + } + } + } + ); + } + } + + // link tiles to neighbours + for ( size_t y = 0 ; y < m_map_size.y ; y++ ) { + for ( size_t x = y & 1 ; x < m_map_size.x ; x += 2 ) { + auto* ts = GetTile( + { + x, + y + } + ); + + ts->W = ( x >= 2 ) + ? GetTile( x - 2, y ) + : GetTile( m_map_size.x - 1 - ( 1 - ( y % 2 ) ), y ); + ts->NW = ( y >= 1 ) + ? ( ( x >= 1 ) + ? GetTile( x - 1, y - 1 ) + : GetTile( m_map_size.x - 1, y - 1 ) + ) + : ts; + ts->N = ( y >= 2 ) + ? GetTile( x, y - 2 ) + : ts; + ts->NE = ( y >= 1 ) + ? ( ( x < m_map_size.x - 1 ) + ? GetTile( x + 1, y - 1 ) + : GetTile( 0, y - 1 ) + ) + : ts; + ts->E = ( x < m_map_size.x - 2 ) + ? GetTile( x + 2, y ) + : GetTile( y % 2, y ); + ts->SE = ( y < m_map_size.y - 1 ) + ? ( ( x < m_map_size.x - 1 ) + ? GetTile( x + 1, y + 1 ) + : GetTile( 0, y + 1 ) + ) + : ts; + ts->S = ( y < m_map_size.y - 2 ) + ? GetTile( x, y + 2 ) + : ts; + ts->SW = ( y < m_map_size.y - 1 ) + ? ( ( x >= 1 ) + ? GetTile( x - 1, y + 1 ) + : GetTile( m_map_size.x - 1, y + 1 ) + ) + : ts; + } + } +} + +Tile* TileManager::GetTile( const size_t x, const size_t y ) { + ASSERT( !m_tiles.empty(), "tiles not initialized" ); + ASSERT( x < m_map_size.x, "tile x overflow" ); + ASSERT( y < m_map_size.y, "tile y overflow" ); + return &m_tiles.at( y * m_map_size.x + x ); +} + +Tile* TileManager::GetTile( const types::Vec2< size_t >& coords ) { + return GetTile( coords.x, coords.y ); +} + +Tile* TileManager::GetSelectedTile() const { + return m_selected_tile; +} + +void TileManager::SelectTile( Tile* tile ) { + m_selected_tile = tile; +} + +} +} +} diff --git a/src/task/game/tile/TileManager.h b/src/task/game/tile/TileManager.h new file mode 100644 index 00000000..38eb2449 --- /dev/null +++ b/src/task/game/tile/TileManager.h @@ -0,0 +1,44 @@ +#pragma once + +#include "base/Base.h" + +#include +#include + +#include "Tile.h" +#include "types/Vec2.h" +#include "util/Clamper.h" + +namespace task { +namespace game { + +class Game; + +namespace tile { + +CLASS( TileManager, base::Base ) + + TileManager( Game* game ); + + void InitTiles( const types::Vec2< size_t > map_size ); + + Tile* GetTile( const size_t x, const size_t y ); + Tile* GetTile( const types::Vec2< size_t >& coords ); + + Tile* GetSelectedTile() const; + void SelectTile( Tile* tile ); + +private: + + Game* m_game; + + types::Vec2< size_t > m_map_size = {}; + std::unordered_map< size_t, Tile > m_tiles = {}; + + Tile* m_selected_tile = nullptr; + +}; + +} +} +} diff --git a/src/task/game/tile/Types.h b/src/task/game/tile/Types.h new file mode 100644 index 00000000..a9fa051e --- /dev/null +++ b/src/task/game/tile/Types.h @@ -0,0 +1,9 @@ +#pragma once + +namespace task { +namespace game { +namespace tile { + +} +} +} diff --git a/src/task/game/ui/bottom_bar/BottomBar.cpp b/src/task/game/ui/bottom_bar/BottomBar.cpp index f7d45c7f..46666295 100644 --- a/src/task/game/ui/bottom_bar/BottomBar.cpp +++ b/src/task/game/ui/bottom_bar/BottomBar.cpp @@ -15,7 +15,7 @@ #include "MiniMap.h" #include "StatusButton.h" #include "ui/UI.h" -#include "task/game/Tile.h" +#include "task/game/tile/Tile.h" #include "graphics/Graphics.h" namespace task { @@ -233,7 +233,7 @@ void BottomBar::Align() { } -void BottomBar::PreviewTile( Tile* tile, const size_t selected_unit_id ) { +void BottomBar::PreviewTile( tile::Tile* tile, const size_t selected_unit_id ) { m_sections.tile_preview->PreviewTile( tile ); m_sections.units_list->ListUnits( tile->GetOrderedUnits(), selected_unit_id ); } diff --git a/src/task/game/ui/bottom_bar/BottomBar.h b/src/task/game/ui/bottom_bar/BottomBar.h index c829383a..4f582680 100644 --- a/src/task/game/ui/bottom_bar/BottomBar.h +++ b/src/task/game/ui/bottom_bar/BottomBar.h @@ -20,7 +20,9 @@ class Label; namespace task { namespace game { class Game; +namespace tile { class Tile; +} namespace unit { class Unit; } @@ -48,7 +50,7 @@ CLASS( BottomBar, UI ) void Destroy() override; void Align() override; - void PreviewTile( Tile* tile, const size_t selected_unit_id ); + void PreviewTile( tile::Tile* tile, const size_t selected_unit_id ); void HideTilePreview(); void PreviewUnit( const unit::Unit* unit ); diff --git a/src/task/game/ui/bottom_bar/TilePreview.cpp b/src/task/game/ui/bottom_bar/TilePreview.cpp index 30627e51..aeec4d5d 100644 --- a/src/task/game/ui/bottom_bar/TilePreview.cpp +++ b/src/task/game/ui/bottom_bar/TilePreview.cpp @@ -2,6 +2,7 @@ #include "engine/Engine.h" #include "task/game/Game.h" +#include "task/game/tile/Tile.h" #include "ui/object/Mesh.h" #include "types/mesh/Render.h" #include "ui/object/Label.h" @@ -26,7 +27,7 @@ void TilePreview::Destroy() { BBSection::Destroy(); } -void TilePreview::PreviewTile( const Tile* tile ) { +void TilePreview::PreviewTile( const tile::Tile* tile ) { HideTilePreview(); const auto& render = tile->GetRenderData(); diff --git a/src/task/game/ui/bottom_bar/TilePreview.h b/src/task/game/ui/bottom_bar/TilePreview.h index 820599cb..8d4ac7c0 100644 --- a/src/task/game/ui/bottom_bar/TilePreview.h +++ b/src/task/game/ui/bottom_bar/TilePreview.h @@ -14,7 +14,9 @@ class Label; namespace task { namespace game { +namespace tile { class Tile; +} namespace ui { @@ -26,7 +28,7 @@ CLASS( TilePreview, BBSection ) void Create() override; void Destroy() override; - void PreviewTile( const Tile* tile ); + void PreviewTile( const tile::Tile* tile ); void HideTilePreview(); private: diff --git a/src/task/game/ui/popup/LoadMap.cpp b/src/task/game/ui/popup/LoadMap.cpp index cdc08623..dfb4978b 100644 --- a/src/task/game/ui/popup/LoadMap.cpp +++ b/src/task/game/ui/popup/LoadMap.cpp @@ -1,9 +1,7 @@ #include "LoadMap.h" -#include "task/game/Game.h" - -#include "util/FS.h" -#include "engine/Engine.h" +#include "task/game/Game.h" +#include "game/map/Consts.h" namespace task { namespace game { diff --git a/src/task/game/ui/popup/SaveMap.cpp b/src/task/game/ui/popup/SaveMap.cpp index 8ad1d014..164e77d1 100644 --- a/src/task/game/ui/popup/SaveMap.cpp +++ b/src/task/game/ui/popup/SaveMap.cpp @@ -1,9 +1,7 @@ #include "SaveMap.h" -#include "task/game/Game.h" - -#include "util/FS.h" -#include "engine/Engine.h" +#include "task/game/Game.h" +#include "game/map/Consts.h" namespace task { namespace game { diff --git a/src/task/game/unit/BadgeDefs.cpp b/src/task/game/unit/BadgeDefs.cpp index c9ef7d6e..10a42b84 100644 --- a/src/task/game/unit/BadgeDefs.cpp +++ b/src/task/game/unit/BadgeDefs.cpp @@ -15,32 +15,76 @@ const BadgeDefs::consts_t BadgeDefs::s_consts = {}; BadgeDefs::BadgeDefs( InstancedSpriteManager* ism ) : m_ism( ism ) { + // +} - auto* tl = g_engine->GetTextureLoader(); - - // load badge sprites - - const uint8_t w = 23; - const uint8_t h = 30; - const uint8_t margin = 1; +BadgeDefs::~BadgeDefs() { + for ( const auto& it : m_unitbadge_sprites ) { + for ( const auto& it2 : it.second ) { + m_ism->RemoveInstancedSpriteByKey( it2.second->key ); + } + } + if ( m_fake_badge ) { + m_ism->RemoveInstancedSpriteByKey( m_fake_badge->key ); + } + for ( const auto& it : m_healthbar_sprites ) { + m_ism->RemoveInstancedSpriteByKey( it.second.instanced_sprite->key ); + } + for ( const auto& it : m_healthbar_textures ) { + delete it.second; + } +} - auto* texture = tl->LoadTexture( resource::PCX_FLAGS ); +const types::Vec3 BadgeDefs::GetBadgeCoords( const types::Vec3& unit_coords ) { + return { + unit_coords.x + ::game::map::s_consts.tile.scale.x * s_consts.offset.x, + unit_coords.y - ::game::map::s_consts.tile.scale.y * s_consts.offset.y * ::game::map::s_consts.sprite.y_scale, + unit_coords.z + }; +} - const types::Color transparent( 0.0f, 0.0f, 0.0f, 0.0f ); - uint32_t x, y; - for ( auto badge_type = BT_PROGENITOR ; badge_type <= BT_DEFAULT ; badge_type++ ) { - for ( auto badge_mode = BT_NORMAL ; badge_mode <= BT_GREYEDOUT ; badge_mode++ ) { - const uint8_t row = badge_type | badge_mode; - auto& spritemap = m_unitbadge_sprites[ row ]; - for ( auto morale = ::game::unit::MORALE_MIN ; morale <= ::game::unit::MORALE_MAX ; morale++ ) { - x = ( morale - ::game::unit::MORALE_MIN ) * ( w + margin ) + margin; - y = row * ( h + margin ) + margin; +const types::Vec3 BadgeDefs::GetBadgeHealthbarCoords( const types::Vec3& unit_coords ) { + return { + unit_coords.x + ::game::map::s_consts.tile.scale.x * s_consts.healthbars.offset.x, + unit_coords.y - ::game::map::s_consts.tile.scale.y * s_consts.healthbars.offset.y * ::game::map::s_consts.sprite.y_scale, + unit_coords.z + }; +} - // cut holes for healthbars - texture->Fill( x + 6, y + 6, x + 7, y + 26, transparent ); +InstancedSprite* BadgeDefs::GetBadgeSprite( const badge_type_t badge_type, const ::game::unit::morale_t morale ) { + auto it1 = m_unitbadge_sprites.find( badge_type ); + if ( it1 == m_unitbadge_sprites.end() ) { + it1 = m_unitbadge_sprites.insert( + { + badge_type, + {} + } + ).first; + } + auto it2 = it1->second.find( morale ); + if ( it2 == it1->second.end() ) { + auto* texture = GetBadgesTexture(); + const auto w = s_consts.badges.width; + const auto h = s_consts.badges.height; + const auto m = s_consts.badges.margin; + const uint32_t x = ( morale - ::game::unit::MORALE_MIN ) * ( w + m ) + m; + const uint32_t y = badge_type * ( h + m ) + m; + + // cut hole for healthbar + texture->Fill( + x + 6, y + 6, x + 7, y + 26, types::Color{ + 0.0f, + 0.0f, + 0.0f, + 0.0f + } + ); - auto* sprite = m_ism->GetInstancedSprite( - "Badge_" + std::to_string( badge_type ) + "_" + std::to_string( badge_mode ), + it2 = it1->second.insert( + { + morale, + m_ism->GetInstancedSprite( + "Badge_" + std::to_string( badge_type ) + "_" + std::to_string( badge_type ), texture, { x, @@ -59,134 +103,104 @@ BadgeDefs::BadgeDefs( InstancedSpriteManager* ism ) ::game::map::s_consts.tile.scale.y * s_consts.scale.y * ::game::map::s_consts.sprite.y_scale }, 0.55f - ); - - spritemap.insert( - { - morale, - sprite - } - ); + ) } - } + ).first; } + return it2->second; +} - // load fake badge sprite - - m_fake_badge = m_ism->GetInstancedSprite( - "Badge_FAKE", - texture, - { - 21, - 5, - }, - { - 3, - 17, - }, - { - 22, - 12, - }, - { - ::game::map::s_consts.tile.scale.x * s_consts.fake_badges.scale.x, - ::game::map::s_consts.tile.scale.y * s_consts.fake_badges.scale.y * ::game::map::s_consts.sprite.y_scale - }, - 0.52f - ); - - // load healthbar sprites - - const auto res = s_consts.healthbars.resolution; - - const float stepval = 1.0f / res; - types::Color black( 0.0f, 0.0f, 0.0f ); - types::Color color( 1.0f - stepval / 2, stepval / 2, 0.0f ); - - m_healthbar_textures.reserve( res ); - m_healthbar_sprites.resize( res ); - for ( auto step = 0 ; step < res ; step++ ) { - - // generate healthbar texture - texture = new types::texture::Texture( "HealthBar_" + std::to_string( step ), 1, res ); - - texture->Fill( 0, 0, 0, step, color ); - if ( step < res - 1 ) { - texture->Fill( 0, step + 1, 0, res - 1, black ); - } - - auto* sprite = m_ism->GetInstancedSprite( - "Badge_Healthbar_" + std::to_string( step ), - texture, +InstancedSprite* BadgeDefs::GetFakeBadgeSprite() { + if ( !m_fake_badge ) { + m_fake_badge = m_ism->GetInstancedSprite( + "Badge_FAKE", + GetBadgesTexture(), { - 0, - 0, + 21, + 5, }, { - 1, - res, + 3, + 17, }, { - 0, - (unsigned int)res / 2, + 22, + 12, }, { - ::game::map::s_consts.tile.scale.x * s_consts.healthbars.scale.x, - ::game::map::s_consts.tile.scale.y * s_consts.healthbars.scale.y * ::game::map::s_consts.sprite.y_scale + ::game::map::s_consts.tile.scale.x * s_consts.fake_badges.scale.x, + ::game::map::s_consts.tile.scale.y * s_consts.fake_badges.scale.y * ::game::map::s_consts.sprite.y_scale }, - 0.54f + 0.52f ); - - m_healthbar_textures.push_back( texture ); - m_healthbar_sprites.at( step ).instanced_sprite = sprite; - color.value.red -= stepval; - color.value.green += stepval; - } - -} - -BadgeDefs::~BadgeDefs() { - for ( const auto& it : m_unitbadge_sprites ) { - for ( const auto& it2 : it.second ) { - m_ism->RemoveInstancedSpriteByKey( it2.second->key ); - } - } - m_ism->RemoveInstancedSpriteByKey( "Badge_FAKE [ 21 5 ] [ 3 17 ]" ); // TODO: refactor? - const auto res = s_consts.healthbars.resolution; - for ( auto step = 0 ; step < res ; step++ ) { - m_ism->RemoveInstancedSpriteByKey( "Badge_Healthbar_" + std::to_string( step ) + " [ 0 0 ] [ 1 25 ]" ); // TODO: refactor - } - for ( const auto& texture : m_healthbar_textures ) { - delete texture; } -} - -const types::Vec3 BadgeDefs::GetBadgeCoords( const types::Vec3& unit_coords ) { - return { - unit_coords.x + ::game::map::s_consts.tile.scale.x * s_consts.offset.x, - unit_coords.y - ::game::map::s_consts.tile.scale.y * s_consts.offset.y * ::game::map::s_consts.sprite.y_scale, - unit_coords.z - }; -} - -const types::Vec3 BadgeDefs::GetBadgeHealthbarCoords( const types::Vec3& unit_coords ) { - return { - unit_coords.x + ::game::map::s_consts.tile.scale.x * s_consts.healthbars.offset.x, - unit_coords.y - ::game::map::s_consts.tile.scale.y * s_consts.healthbars.offset.y * ::game::map::s_consts.sprite.y_scale, - unit_coords.z - }; -} - -InstancedSprite* BadgeDefs::GetBadgeSprite( const badge_type_t badge_type, const ::game::unit::morale_t morale ) const { - return m_unitbadge_sprites.at( badge_type ).at( morale ); -} - -InstancedSprite* BadgeDefs::GetFakeBadgeSprite() const { return m_fake_badge; } Sprite* BadgeDefs::GetBadgeHealthbarSprite( const float health ) { - return &m_healthbar_sprites.at( round( health * ( s_consts.healthbars.resolution - 1 ) ) ); + const uint8_t step = round( health * ( s_consts.healthbars.resolution - 1 ) ); + auto it = m_healthbar_sprites.find( step ); + if ( it == m_healthbar_sprites.end() ) { + + const auto res = s_consts.healthbars.resolution; + + ASSERT_NOLOG( m_healthbar_textures.find( step ) == m_healthbar_textures.end(), "healthbar texture already exists" ); + auto* texture = m_healthbar_textures.insert( + { + step, + new types::texture::Texture( "HealthBar_" + std::to_string( step ), 1, res ) + } + ).first->second; + + texture->Fill( + 0, 0, 0, step, { + 1.0f - health, + health, + 0.0f, + 1.0f + } + ); + if ( step < res - 1 ) { + texture->Fill( + 0, step + 1, 0, res - 1, types::Color{ + 0.0f, + 0.0f, + 0.0f, + 1.0f + } + ); + } + it = m_healthbar_sprites.insert( + { + step, + { + m_ism->GetInstancedSprite( + "Badge_Healthbar_" + std::to_string( step ), + texture, + { + 0, + 0, + }, + { + 1, + res, + }, + { + 0, + (unsigned int)res / 2, + }, + { + ::game::map::s_consts.tile.scale.x * s_consts.healthbars.scale.x, + ::game::map::s_consts.tile.scale.y * s_consts.healthbars.scale.y * ::game::map::s_consts.sprite.y_scale + }, + 0.54f + ), + 1 + } + } + ).first; + } + return &it->second; } const size_t BadgeDefs::GetBadgeBlinkInterval() const { @@ -201,6 +215,13 @@ const types::Vec3 BadgeDefs::GetFakeBadgeCoords( const types::Vec3& coords, cons }; } +types::texture::Texture* BadgeDefs::GetBadgesTexture() { + if ( !m_badges_texture ) { + m_badges_texture = g_engine->GetTextureLoader()->LoadTexture( resource::PCX_FLAGS ); + } + return m_badges_texture; +} + } } } diff --git a/src/task/game/unit/BadgeDefs.h b/src/task/game/unit/BadgeDefs.h index dac429a0..626e1682 100644 --- a/src/task/game/unit/BadgeDefs.h +++ b/src/task/game/unit/BadgeDefs.h @@ -36,8 +36,8 @@ class BadgeDefs { static const badge_type_t BT_DEFAULT{ 1 << 1 }; static const badge_type_t BT_PROGENITOR{ 0 << 1 }; - InstancedSprite* GetBadgeSprite( const badge_type_t badge_type, const ::game::unit::morale_t morale ) const; - InstancedSprite* GetFakeBadgeSprite() const; + InstancedSprite* GetBadgeSprite( const badge_type_t badge_type, const ::game::unit::morale_t morale ); + InstancedSprite* GetFakeBadgeSprite(); Sprite* GetBadgeHealthbarSprite( const float health ); const size_t GetBadgeBlinkInterval() const; @@ -54,6 +54,11 @@ class BadgeDefs { -0.25f, -0.5 }; + const struct { + const uint8_t width = 23; + const uint8_t height = 30; + const uint8_t margin = 1; + } badges; const struct { const uint8_t resolution = 25; const types::Vec2< float > scale = { @@ -90,8 +95,11 @@ class BadgeDefs { InstancedSprite* m_fake_badge = nullptr; - std::vector< types::texture::Texture* > m_healthbar_textures = {}; - std::vector< Sprite > m_healthbar_sprites = {}; + types::texture::Texture* m_badges_texture = nullptr; + types::texture::Texture* GetBadgesTexture(); + + std::unordered_map< uint8_t, types::texture::Texture* > m_healthbar_textures = {}; + std::unordered_map< uint8_t, Sprite > m_healthbar_sprites = {}; }; diff --git a/src/task/game/unit/SlotBadges.cpp b/src/task/game/unit/SlotBadges.cpp index f1f62b11..d95c6fd9 100644 --- a/src/task/game/unit/SlotBadges.cpp +++ b/src/task/game/unit/SlotBadges.cpp @@ -18,10 +18,11 @@ SlotBadges::SlotBadges( ) : m_badge_defs( badge_defs ) , m_ism( ism ) - , m_badges_key( "Badge_" + std::to_string( slot_index ) ) { + , m_badges_key( "Badge_" + std::to_string( slot_index ) ) + , m_faction( faction ) { const auto& c = faction->m_border_color.value; - const types::texture::repaint_rules_t& rules = { + m_repaint_rules = { { // active types::Color::RGB( 252, 0, 0 ), types::Color( c.red, c.green, c.blue ).GetRGBA() @@ -32,72 +33,94 @@ SlotBadges::SlotBadges( } }; - // fake badges should be slightly grayer - auto fake_badge_rules = rules; - for ( auto& rule : fake_badge_rules ) { + // fake badges should be slightly greyer + m_fake_badge_repaint_rules = m_repaint_rules; + for ( auto& rule : m_fake_badge_repaint_rules ) { rule.second = types::Color( ( 0.6f + c.red / 2.5 ) / 2, ( 0.6f + c.green / 2.5 ) / 2, ( 0.6f + c.blue / 2.5 ) / 2 ).GetRGBA(); } - const BadgeDefs::badge_type_t badge_type = faction->m_is_progenitor - ? BadgeDefs::BT_PROGENITOR - : BadgeDefs::BT_DEFAULT; - for ( auto morale = ::game::unit::MORALE_MIN ; morale <= ::game::unit::MORALE_MAX ; morale++ ) { - auto& badgedef = m_per_morale_sprites[ morale ]; - NEW( badgedef.normal, Sprite, { - m_ism->GetRepaintedInstancedSprite( - m_badges_key + "_" + std::to_string( morale ) + "_NORMAL", - m_badge_defs->GetBadgeSprite( badge_type | BadgeDefs::BT_NORMAL, morale ), - rules - ), - 1 - } ); - NEW( badgedef.greyedout, Sprite, { - m_ism->GetRepaintedInstancedSprite( - m_badges_key + "_" + std::to_string( morale ) + "_GRAYEDOUT", - m_badge_defs->GetBadgeSprite( badge_type | BadgeDefs::BT_GREYEDOUT, morale ), - rules - ), - 1 - } ); - } - NEW( m_fake_badge, Sprite, { - m_ism->GetRepaintedInstancedSprite( - m_badges_key + "_FAKE", - m_badge_defs->GetFakeBadgeSprite(), - fake_badge_rules - ), - 1 - } ); } SlotBadges::~SlotBadges() { - for ( auto morale = ::game::unit::MORALE_MIN ; morale <= ::game::unit::MORALE_MAX ; morale++ ) { - m_ism->RemoveRepaintedInstancedSpriteByKey( m_badges_key + "_" + std::to_string( morale ) + "_NORMAL" ); - m_ism->RemoveRepaintedInstancedSpriteByKey( m_badges_key + "_" + std::to_string( morale ) + "_GRAYEDOUT" ); + for ( const auto& it : m_per_morale_sprites ) { + if ( it.second.normal ) { + m_ism->RemoveRepaintedInstancedSpriteByKey( it.second.normal->instanced_sprite->key ); + DELETE( it.second.normal ); + } + if ( it.second.greyedout ) { + m_ism->RemoveRepaintedInstancedSpriteByKey( it.second.greyedout->instanced_sprite->key ); + DELETE( it.second.greyedout ); + } } - m_ism->RemoveRepaintedInstancedSpriteByKey( m_badges_key + "_FAKE" ); - for ( auto morale = ::game::unit::MORALE_MIN ; morale <= ::game::unit::MORALE_MAX ; morale++ ) { - auto& badgedef = m_per_morale_sprites[ morale ]; - DELETE( badgedef.normal ); - DELETE( badgedef.greyedout ); + if ( m_fake_badge ) { + m_ism->RemoveRepaintedInstancedSpriteByKey( m_fake_badge->instanced_sprite->key ); + DELETE( m_fake_badge ); } - DELETE( m_fake_badge ); } Sprite* SlotBadges::GetUnitBadgeSprite( const ::game::unit::morale_t morale, const bool is_active ) { - return is_active - ? m_per_morale_sprites.at( morale ).normal - : m_per_morale_sprites.at( morale ).greyedout; + auto it = m_per_morale_sprites.find( morale ); + if ( it == m_per_morale_sprites.end() ) { + it = m_per_morale_sprites.insert( + { + morale, + { + nullptr, + nullptr + } + } + ).first; + } + Sprite** sprite_ptr = is_active + ? &it->second.normal + : &it->second.greyedout; + if ( !*sprite_ptr ) { + NEW( *sprite_ptr, Sprite, { + m_ism->GetRepaintedInstancedSprite( + m_badges_key + "_" + std::to_string( morale ) + ( is_active + ? "_NORMAL" + : "_GREYEDOUT" + ), + m_badge_defs->GetBadgeSprite( + ( m_faction->m_is_progenitor + ? BadgeDefs::BT_PROGENITOR + : BadgeDefs::BT_DEFAULT + ) | ( is_active + ? BadgeDefs::BT_NORMAL + : BadgeDefs::BT_GREYEDOUT + ), morale + ), + m_repaint_rules + ), + 1 + } ); + } + return *sprite_ptr; } const size_t SlotBadges::ShowFakeBadge( const types::Vec3& coords, const uint8_t offset ) { - const size_t instance_id = m_fake_badge->next_instance_id++; - m_fake_badge->instanced_sprite->actor->SetInstance( instance_id, m_badge_defs->GetFakeBadgeCoords( coords, offset ) ); + auto* fake_badge = GetFakeBadge(); + const size_t instance_id = fake_badge->next_instance_id++; + fake_badge->instanced_sprite->actor->SetInstance( instance_id, m_badge_defs->GetFakeBadgeCoords( coords, offset ) ); return instance_id; } void SlotBadges::HideFakeBadge( const size_t instance_id ) { - m_fake_badge->instanced_sprite->actor->RemoveInstance( instance_id ); + GetFakeBadge()->instanced_sprite->actor->RemoveInstance( instance_id ); +} + +Sprite* SlotBadges::GetFakeBadge() { + if ( !m_fake_badge ) { + NEW( m_fake_badge, Sprite, { + m_ism->GetRepaintedInstancedSprite( + m_badges_key + "_FAKE", + m_badge_defs->GetFakeBadgeSprite(), + m_fake_badge_repaint_rules + ), + 1 + } ); + } + return m_fake_badge; } } diff --git a/src/task/game/unit/SlotBadges.h b/src/task/game/unit/SlotBadges.h index 7d7af0aa..0c42b6ed 100644 --- a/src/task/game/unit/SlotBadges.h +++ b/src/task/game/unit/SlotBadges.h @@ -3,6 +3,7 @@ #include #include "game/unit/Types.h" +#include "types/texture/Types.h" #include "types/Vec3.h" #include "types/Color.h" @@ -42,6 +43,7 @@ class SlotBadges { BadgeDefs* const m_badge_defs; InstancedSpriteManager* const m_ism; const std::string m_badges_key; + const faction::Faction* m_faction = nullptr; class slot_sprites_t { public: @@ -49,7 +51,12 @@ class SlotBadges { Sprite* greyedout; }; std::unordered_map< ::game::unit::morale_t, slot_sprites_t > m_per_morale_sprites = {}; - Sprite* m_fake_badge; + + types::texture::repaint_rules_t m_repaint_rules = {}; + types::texture::repaint_rules_t m_fake_badge_repaint_rules = {}; + + Sprite* m_fake_badge = nullptr; + Sprite* GetFakeBadge(); }; } diff --git a/src/task/game/unit/Unit.cpp b/src/task/game/unit/Unit.cpp index c34061bc..b8ff40bf 100644 --- a/src/task/game/unit/Unit.cpp +++ b/src/task/game/unit/Unit.cpp @@ -1,10 +1,10 @@ #include "Unit.h" #include "task/game/Game.h" +#include "task/game/tile/Tile.h" #include "util/String.h" #include "game/unit/Unit.h" #include "task/game/Slot.h" -#include "task/game/Tile.h" #include "UnitDef.h" #include "BadgeDefs.h" #include "SlotBadges.h" @@ -15,8 +15,6 @@ #include "scene/actor/Sprite.h" #include "types/texture/Texture.h" -#include - namespace task { namespace game { namespace unit { @@ -27,7 +25,7 @@ Unit::Unit( const size_t id, UnitDef* def, Slot* slot, - Tile* tile, + tile::Tile* tile, const types::Vec3& render_coords, const bool is_owned, const ::game::unit::movement_t movement, @@ -81,7 +79,7 @@ const bool Unit::IsActive() const { return m_is_active; } -Tile* Unit::GetTile() const { +tile::Tile* Unit::GetTile() const { return m_tile; } @@ -307,7 +305,7 @@ const bool Unit::CanMove() const { return m_movement >= ::game::unit::Unit::MINIMUM_MOVEMENT_TO_KEEP; } -void Unit::SetTile( task::game::Tile* dst_tile ) { +void Unit::SetTile( tile::Tile* dst_tile ) { ASSERT_NOLOG( m_tile, "source tile not set" ); ASSERT_NOLOG( dst_tile, "destination tile not set" ); @@ -320,7 +318,7 @@ void Unit::SetTile( task::game::Tile* dst_tile ) { UpdateFromTile(); } -void Unit::MoveToTile( Tile* dst_tile ) { +void Unit::MoveToTile( tile::Tile* dst_tile ) { ASSERT_NOLOG( !m_mover.IsRunning(), "unit already moving" ); ASSERT_NOLOG( m_tile != dst_tile, "can't move to same tile" ); ASSERT_NOLOG( m_tile, "source tile not set" ); diff --git a/src/task/game/unit/Unit.h b/src/task/game/unit/Unit.h index a2abd394..72d6cc61 100644 --- a/src/task/game/unit/Unit.h +++ b/src/task/game/unit/Unit.h @@ -22,10 +22,13 @@ namespace game { class Game; class Slot; -class Tile; class Sprite; class InstancedSprite; +namespace tile { +class Tile; +} + namespace unit { class UnitDef; @@ -45,7 +48,7 @@ class Unit { const size_t id, unit::UnitDef* def, Slot* slot, - Tile* tile, + tile::Tile* tile, const types::Vec3& render_coords, const bool is_owned, const ::game::unit::movement_t movement, @@ -58,7 +61,7 @@ class Unit { const size_t GetId() const; const bool IsOwned() const; const bool IsActive() const; - Tile* GetTile() const; + tile::Tile* GetTile() const; const size_t GetSelectionWeight() const; @@ -94,8 +97,8 @@ class Unit { void SetHealth( const ::game::unit::health_t health ); const bool CanMove() const; - void SetTile( Tile* dst_tile ); - void MoveToTile( Tile* dst_tile ); + void SetTile( tile::Tile* dst_tile ); + void MoveToTile( tile::Tile* dst_tile ); void UpdateFromTile(); const bool IsValid() const; @@ -121,7 +124,7 @@ class Unit { size_t m_id = 0; UnitDef* m_def = nullptr; - Tile* m_tile = nullptr; + tile::Tile* m_tile = nullptr; struct { types::Vec3 coords = {}; bool is_rendered = false; diff --git a/src/task/game/unit/UnitDef.cpp b/src/task/game/unit/UnitDef.cpp index d70b501e..f42ba7f0 100644 --- a/src/task/game/unit/UnitDef.cpp +++ b/src/task/game/unit/UnitDef.cpp @@ -25,66 +25,12 @@ UnitDef::UnitDef( InstancedSpriteManager* ism, const ::game::unit::Def* unitdef switch ( def->m_render->m_type ) { case ::game::unit::Render::RT_SPRITE: { - const auto* render = (::game::unit::SpriteRender*)def->m_render; + m_render = ( (::game::unit::SpriteRender*)def->m_render )->m_render; static_.movement_type = def->m_movement_type; static_.movement_per_turn = def->m_movement_per_turn; static_.render.is_sprite = true; - const auto name = "Unit_" + def->m_id; - auto* texture = g_engine->GetTextureLoader()->LoadCustomTexture( render->m_file ); - const ::game::map::pcx_texture_coordinates_t& src_wh = { - render->m_w, - render->m_h, - }; - const types::Vec2< float >& dst_wh = { - ::game::map::s_consts.tile.scale.x, - ::game::map::s_consts.tile.scale.y * ::game::map::s_consts.sprite.y_scale - }; - const auto zindex = 0.5f; - - static_.render.morale_based_xshift = render->m_morale_based_xshift; - if ( static_.render.morale_based_xshift ) { - NEW( static_.render.morale_based_sprites, morale_based_sprites_t ); - for ( ::game::unit::morale_t morale = ::game::unit::MORALE_MIN ; morale <= ::game::unit::MORALE_MAX ; morale++ ) { - const uint32_t xshift = static_.render.morale_based_xshift * ( morale - ::game::unit::MORALE_MIN ); - static_.render.morale_based_sprites->insert( - { - morale, - { - m_ism->GetInstancedSprite( - name + "_" + std::to_string( morale ), texture, { - render->m_x + xshift, - render->m_y, - }, - src_wh, - { - render->m_cx + xshift, - render->m_cy, - }, - dst_wh, - zindex - ), - } - } - ); - } - } - else { - static_.render.sprite.instanced_sprite = m_ism->GetInstancedSprite( - name, texture, { - render->m_x, - render->m_y, - }, - src_wh, - { - render->m_cx, - render->m_cy, - }, - dst_wh, - zindex - ); - } break; } default: @@ -100,7 +46,9 @@ UnitDef::UnitDef( InstancedSpriteManager* ism, const ::game::unit::Def* unitdef UnitDef::~UnitDef() { if ( m_type == ::game::unit::DT_STATIC ) { if ( static_.render.morale_based_xshift ) { - DELETE( static_.render.morale_based_sprites ); + if ( static_.render.morale_based_sprites ) { + DELETE( static_.render.morale_based_sprites ); + } } } } @@ -113,11 +61,69 @@ Sprite* UnitDef::GetSprite( const ::game::unit::morale_t morale ) { ASSERT_NOLOG( m_type == ::game::unit::DT_STATIC, "only static units are supported for now" ); ASSERT_NOLOG( static_.render.is_sprite, "only sprite unitdefs are supported for now" ); - auto& render = static_.render; - ASSERT_NOLOG( render.is_sprite, "only sprite units are supported for now" ); - return render.morale_based_xshift - ? &render.morale_based_sprites->at( morale ) - : &render.sprite; + if ( m_render.morale_based_xshift ) { + if ( !static_.render.morale_based_sprites ) { + NEW( static_.render.morale_based_sprites, morale_based_sprites_t ); + } + auto it = static_.render.morale_based_sprites->find( morale ); + if ( it == static_.render.morale_based_sprites->end() ) { + const uint32_t xshift = static_.render.morale_based_xshift * ( morale - ::game::unit::MORALE_MIN ); + it = static_.render.morale_based_sprites->insert( + { + morale, + { + m_ism->GetInstancedSprite( + "Unit_" + m_id + "_" + std::to_string( morale ), GetSpriteTexture(), { + m_render.x + xshift, + m_render.y, + }, + { + m_render.w, + m_render.h, + }, + { + m_render.cx + xshift, + m_render.cy, + }, + { + ::game::map::s_consts.tile.scale.x, + ::game::map::s_consts.tile.scale.y * ::game::map::s_consts.sprite.y_scale + }, + 0.5f + ), + } + } + ).first; + } + return &it->second; + } + else { + if ( !static_.render.sprite.instanced_sprite ) { + static_.render.sprite = { + m_ism->GetInstancedSprite( + "Unit_" + m_id, GetSpriteTexture(), { + m_render.x, + m_render.y, + }, + { + m_render.w, + m_render.h, + }, + { + m_render.cx, + m_render.cy, + }, + { + ::game::map::s_consts.tile.scale.x, + ::game::map::s_consts.tile.scale.y * ::game::map::s_consts.sprite.y_scale + }, + 0.5f + ), + 1 + }; + } + return &static_.render.sprite; + } } const bool UnitDef::IsImmovable() const { @@ -140,6 +146,13 @@ const std::string UnitDef::GetStatsString() const { } +types::texture::Texture* UnitDef::GetSpriteTexture() { + if ( !static_.render.texture ) { + static_.render.texture = g_engine->GetTextureLoader()->LoadCustomTexture( m_render.file ); + } + return static_.render.texture; +} + } } } diff --git a/src/task/game/unit/UnitDef.h b/src/task/game/unit/UnitDef.h index e2ababab..0486b24d 100644 --- a/src/task/game/unit/UnitDef.h +++ b/src/task/game/unit/UnitDef.h @@ -9,6 +9,12 @@ // TODO: remove? #include "task/game/Sprite.h" +namespace types { +namespace texture { +class Texture; +} +} + namespace game::unit { class Def; } @@ -28,7 +34,6 @@ class UnitDef { const bool IsArtillery() const; Sprite* GetSprite( const ::game::unit::morale_t morale ); - const types::Vec3 GetUnitCoordsOnTile( const types::Vec3& tile_coords ); const bool IsImmovable() const; @@ -39,27 +44,27 @@ class UnitDef { InstancedSpriteManager* const m_ism; + ::game::unit::sprite_render_info_t m_render = {}; + std::string m_id; std::string m_name; ::game::unit::def_type_t m_type; typedef std::unordered_map< ::game::unit::morale_t, Sprite > morale_based_sprites_t; - // TODO: get rid of union - union { + struct { + ::game::unit::movement_type_t movement_type; + ::game::unit::movement_t movement_per_turn; struct { - ::game::unit::movement_type_t movement_type; - ::game::unit::movement_t movement_per_turn; - struct { - bool is_sprite; - uint32_t morale_based_xshift; - union { - Sprite sprite; - morale_based_sprites_t* morale_based_sprites; - }; - } render; - } static_; - }; + bool is_sprite = false; + uint32_t morale_based_xshift = 0; + types::texture::Texture* texture = nullptr; + Sprite sprite = {}; + morale_based_sprites_t* morale_based_sprites = nullptr; + } render = {}; + } static_ = {}; + + types::texture::Texture* GetSpriteTexture(); }; } diff --git a/src/task/game/unit/UnitManager.cpp b/src/task/game/unit/UnitManager.cpp index 13feac9b..1d56ef37 100644 --- a/src/task/game/unit/UnitManager.cpp +++ b/src/task/game/unit/UnitManager.cpp @@ -1,10 +1,13 @@ #include "UnitManager.h" +#include + #include "Unit.h" #include "UnitDef.h" #include "SlotBadges.h" #include "game/unit/Def.h" #include "task/game/Game.h" +#include "task/game/tile/TileManager.h" #include "task/game/unit/BadgeDefs.h" #include "types/mesh/Rectangle.h" @@ -97,7 +100,7 @@ void UnitManager::SpawnUnit( auto* unitdef = m_unitdefs.at( unitdef_id ); auto* slot = m_game->GetSlot( slot_index ); - auto* tile = m_game->GetTile( tile_coords ); + auto* tile = m_game->GetTM()->GetTile( tile_coords ); auto* unit = m_units.insert( { @@ -144,12 +147,13 @@ void UnitManager::DespawnUnit( const size_t unit_id ) { auto* unit = it->second; m_units.erase( it ); - delete unit; - + if ( unit->IsOwned() ) { RemoveSelectable( unit ); } + delete unit; + m_game->RefreshSelectedTile( m_selected_unit ); } @@ -170,7 +174,7 @@ void UnitManager::RefreshUnit( Unit* unit ) { } } -void UnitManager::MoveUnit( Unit* unit, Tile* dst_tile, const size_t animation_id ) { +void UnitManager::MoveUnit( Unit* unit, tile::Tile* dst_tile, const size_t animation_id ) { auto* src_tile = unit->GetTile(); ASSERT( m_moving_units.find( unit ) == m_moving_units.end(), "unit already moving" ); m_moving_units.insert( @@ -188,7 +192,7 @@ void UnitManager::MoveUnit( Unit* unit, Tile* dst_tile, const size_t animation_i unit->MoveToTile( dst_tile ); } -void UnitManager::MoveUnit_deprecated( Unit* unit, Tile* dst_tile, const types::Vec3& dst_render_coords ) { +void UnitManager::MoveUnit_deprecated( Unit* unit, tile::Tile* dst_tile, const types::Vec3& dst_render_coords ) { auto* src_tile = unit->GetTile(); diff --git a/src/task/game/unit/UnitManager.h b/src/task/game/unit/UnitManager.h index 8f3f7f2a..5f611db9 100644 --- a/src/task/game/unit/UnitManager.h +++ b/src/task/game/unit/UnitManager.h @@ -20,9 +20,9 @@ namespace game { class Game; class InstancedSpriteManager; -//namespace tile { +namespace tile { class Tile; -//} +} namespace faction { class Faction; @@ -62,8 +62,8 @@ CLASS( UnitManager, base::Base ) ); void DespawnUnit( const size_t unit_id ); void RefreshUnit( Unit* unit ); - void MoveUnit( Unit* unit, Tile* dst_tile, const size_t animation_id ); - void MoveUnit_deprecated( Unit* unit, Tile* dst_tile, const types::Vec3& dst_render_coords ); + void MoveUnit( Unit* unit, tile::Tile* dst_tile, const size_t animation_id ); + void MoveUnit_deprecated( Unit* unit, tile::Tile* dst_tile, const types::Vec3& dst_render_coords ); Unit* GetSelectedUnit() const; void SelectUnit( Unit* unit_data, const bool actually_select_unit ); @@ -93,7 +93,7 @@ CLASS( UnitManager, base::Base ) std::unordered_map< size_t, SlotBadges* > m_slot_badges = {}; struct moving_unit_info_t { - Tile* tile; + tile::Tile* tile; size_t animation_id; }; std::unordered_map< Unit*, moving_unit_info_t > m_moving_units = {};