]> git.localhorst.tv Git - l2e.git/blob - src/map/Map.cpp
682f4f2a8a7f6a43a68cb300db0e7abf36cb2edd
[l2e.git] / src / map / Map.cpp
1 #include "Map.h"
2
3 #include "Area.h"
4 #include "Tile.h"
5 #include "Trigger.h"
6 #include "../graphics/Sprite.h"
7 #include "../loader/Interpreter.h"
8 #include "../loader/TypeDescription.h"
9 #include "../math/Vector.h"
10 #include "../sdl/utility.h"
11
12 #include <stdexcept>
13
14 using math::Vector;
15 using graphics::Sprite;
16 using loader::FieldDescription;
17 using loader::Interpreter;
18 using loader::TypeDescription;
19
20 namespace map {
21
22 Map::Map()
23 : tileset(0)
24 , battlebg(0)
25 , areas(0)
26 , numAreas(0)
27 , triggers(0)
28 , numTriggers(0)
29 , entities(0)
30 , numEntities(0)
31 , width(0) {
32
33 }
34
35
36 Area *Map::AreaAt(const Vector<int> &offset) {
37         if (numAreas > 0) {
38                 Vector<int> coords(TileCoordinates(offset));
39                 Vector<int> areaOffset(coords / areas[0].Size());
40                 int areaIndex(areaOffset.Index(width));
41                 if (areaIndex < numAreas) {
42                         return areas + areaIndex;
43                 }
44         }
45         return 0;
46 }
47
48 const Area *Map::AreaAt(const Vector<int> &offset) const {
49         if (numAreas > 0) {
50                 Vector<int> coords(TileCoordinates(offset));
51                 Vector<int> areaOffset(coords / areas[0].Size());
52                 int areaIndex(areaOffset.Index(width));
53                 if (areaIndex < numAreas) {
54                         return areas + areaIndex;
55                 }
56         }
57         return 0;
58 }
59
60 Tile *Map::TileAt(const Vector<int> &offset) {
61         Area *area(AreaAt(offset));
62         if (area) {
63                 Vector<int> tileOffset(TileCoordinates(offset) % area->Size());
64                 return area->TileAt(tileOffset);
65         } else {
66                 return 0;
67         }
68 }
69
70 const Tile *Map::TileAt(const Vector<int> &offset) const {
71         const Area *area(AreaAt(offset));
72         if (area) {
73                 Vector<int> tileOffset(TileCoordinates(offset) % area->Size());
74                 return area->TileAt(tileOffset);
75         } else {
76                 return 0;
77         }
78 }
79
80 Trigger *Map::TriggerAt(const math::Vector<int> &offset) {
81         // TODO: add support for multiple triggers on a tile?
82         Vector<int> coords(TileCoordinates(offset));
83         for (Trigger *i(triggers); i != triggers + numTriggers; ++i) {
84                 if (i->TilePosition() == coords) {
85                         return i;
86                 }
87         }
88         return 0;
89 }
90
91 SDL_Surface *Map::BattleBackgroundAt(const math::Vector<int> &position) {
92         Tile *tile(TileAt(position));
93         if (tile && tile->BattleBackground()) {
94                 return tile->BattleBackground();
95         }
96         Area *area(AreaAt(position));
97         if (area && area->BattleBackground()) {
98                 return area->BattleBackground();
99         }
100         return battlebg;
101 }
102
103 Vector<int> Map::TileCoordinates(const Vector<int> &position) const {
104         return position / tileset->Size();
105 }
106
107
108 void Map::Render(SDL_Surface *dest, const Vector<int> &inOffset) const {
109         // TODO: skip invisible areas
110         for (int i(0); i < numAreas; ++i) {
111                 const Area &area(areas[i]);
112                 Vector<int> offset(inOffset + Vector<int>::FromIndex(i, width) * area.Size() * tileset->Size());
113                 area.Render(dest, tileset, offset);
114         }
115 }
116
117 void Map::RenderDebug(SDL_Surface *dest, const Vector<int> &inOffset) const {
118         // TODO: skip invisible areas
119         for (int i(0); i < numAreas; ++i) {
120                 const Area &area(areas[i]);
121                 Vector<int> offset(inOffset + Vector<int>::FromIndex(i, width) * area.Size() * tileset->Size());
122                 area.RenderDebug(dest, tileset, offset);
123         }
124         for (int i(0); i < numTriggers; ++i) {
125                 Vector<int> offset((triggers[i].TilePosition() * tileset->Size()) + inOffset);
126                 switch (triggers[i].GetType()) {
127                         case Trigger::TYPE_NORTH:
128                                 sdl::HorizontalLine(dest, offset + (tileset->Size() / 4), tileset->Width() / 2, SDL_MapRGB(dest->format, 0x00, 0xFF, 0xFF));
129                                 break;
130                         case Trigger::TYPE_EAST:
131                                 sdl::VerticalLine(dest, offset + Vector<int>(tileset->Width() * 3 / 4, tileset->Height() / 4), tileset->Height() / 2, SDL_MapRGB(dest->format, 0x00, 0xFF, 0xFF));
132                                 break;
133                         case Trigger::TYPE_SOUTH:
134                                 sdl::HorizontalLine(dest, offset + Vector<int>(tileset->Width() / 4, tileset->Height() * 3 / 4), tileset->Width() / 2, SDL_MapRGB(dest->format, 0x00, 0xFF, 0xFF));
135                                 break;
136                         case Trigger::TYPE_WEST:
137                                 sdl::VerticalLine(dest, offset + (tileset->Size() / 4), tileset->Width() / 2, SDL_MapRGB(dest->format, 0x00, 0xFF, 0xFF));
138                                 break;
139                         case Trigger::TYPE_CONTACT: {
140                                         SDL_Rect destRect;
141                                         destRect.x = offset.X() + (tileset->Width() / 4);
142                                         destRect.y = offset.Y() + (tileset->Height() / 4);
143                                         destRect.w = tileset->Width() / 2;
144                                         destRect.h = tileset->Height() / 2;
145                                         SDL_FillRect(dest, &destRect, SDL_MapRGB(dest->format, 0x00, 0xFF, 0xFF));
146                                 }
147                                 break;
148                 }
149         }
150 }
151
152
153 void Map::CreateTypeDescription() {
154         Map m;
155
156         TypeDescription &td(TypeDescription::Create(TYPE_ID, "Map"));
157         td.SetConstructor(&Construct);
158         td.SetSize(sizeof(Map));
159
160         td.AddField("tileset", FieldDescription(((char *)&m.tileset) - ((char *)&m), Sprite::TYPE_ID).SetReferenced());
161         td.AddField("battlebg", FieldDescription(((char *)&m.battlebg) - ((char *)&m), Interpreter::IMAGE_ID).SetReferenced());
162         td.AddField("areas", FieldDescription(((char *)&m.areas) - ((char *)&m), Area::TYPE_ID).SetReferenced().SetAggregate());
163         td.AddField("triggers", FieldDescription(((char *)&m.triggers) - ((char *)&m), Trigger::TYPE_ID).SetReferenced().SetAggregate());
164         td.AddField("entities", FieldDescription(((char *)&m.entities) - ((char *)&m), Entity::TYPE_ID).SetReferenced().SetAggregate());
165         td.AddField("width", FieldDescription(((char *)&m.width) - ((char *)&m), Interpreter::NUMBER_ID));
166 }
167
168 void Map::Construct(void *data) {
169         new (data) Map;
170 }
171
172 }