]> git.localhorst.tv Git - l2e.git/blob - src/map/Map.cpp
ed6cc06ffd398923cfa4c5ff1aa8e55712a3cea1
[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 Vector<int> Map::PixelCoordinates(const Vector<int> &position) const {
108         return position * tileset->Size();
109 }
110
111
112 void Map::Render(
113                 SDL_Surface *dest,
114                 const Vector<int> &inOffset,
115                 unsigned int frame) const {
116         // TODO: skip invisible areas
117         for (int i(0); i < numAreas; ++i) {
118                 const Area &area(areas[i]);
119                 Vector<int> offset(inOffset + Vector<int>::FromIndex(i, width) * area.Size() * tileset->Size());
120                 area.Render(dest, tileset, offset, frame);
121         }
122 }
123
124 void Map::RenderDebug(SDL_Surface *dest, const Vector<int> &inOffset) const {
125         // TODO: skip invisible areas
126         for (int i(0); i < numAreas; ++i) {
127                 const Area &area(areas[i]);
128                 Vector<int> offset(inOffset + Vector<int>::FromIndex(i, width) * area.Size() * tileset->Size());
129                 area.RenderDebug(dest, tileset, offset);
130         }
131         for (int i(0); i < numTriggers; ++i) {
132                 Vector<int> offset((triggers[i].TilePosition() * tileset->Size()) + inOffset);
133                 switch (triggers[i].GetType()) {
134                         case Trigger::TYPE_NORTH:
135                                 sdl::HorizontalLine(dest, offset + (tileset->Size() / 4), tileset->Width() / 2, SDL_MapRGB(dest->format, 0x00, 0xFF, 0xFF));
136                                 break;
137                         case Trigger::TYPE_EAST:
138                                 sdl::VerticalLine(dest, offset + Vector<int>(tileset->Width() * 3 / 4, tileset->Height() / 4), tileset->Height() / 2, SDL_MapRGB(dest->format, 0x00, 0xFF, 0xFF));
139                                 break;
140                         case Trigger::TYPE_SOUTH:
141                                 sdl::HorizontalLine(dest, offset + Vector<int>(tileset->Width() / 4, tileset->Height() * 3 / 4), tileset->Width() / 2, SDL_MapRGB(dest->format, 0x00, 0xFF, 0xFF));
142                                 break;
143                         case Trigger::TYPE_WEST:
144                                 sdl::VerticalLine(dest, offset + (tileset->Size() / 4), tileset->Width() / 2, SDL_MapRGB(dest->format, 0x00, 0xFF, 0xFF));
145                                 break;
146                         case Trigger::TYPE_CONTACT: {
147                                         SDL_Rect destRect;
148                                         destRect.x = offset.X() + (tileset->Width() / 4);
149                                         destRect.y = offset.Y() + (tileset->Height() / 4);
150                                         destRect.w = tileset->Width() / 2;
151                                         destRect.h = tileset->Height() / 2;
152                                         SDL_FillRect(dest, &destRect, SDL_MapRGB(dest->format, 0x00, 0xFF, 0xFF));
153                                 }
154                                 break;
155                 }
156         }
157 }
158
159
160 void Map::CreateTypeDescription() {
161         Map m;
162
163         TypeDescription &td(TypeDescription::Create(TYPE_ID, "Map"));
164         td.SetConstructor(&Construct);
165         td.SetSize(sizeof(Map));
166
167         td.AddField("tileset", FieldDescription(((char *)&m.tileset) - ((char *)&m), Sprite::TYPE_ID).SetReferenced());
168         td.AddField("battlebg", FieldDescription(((char *)&m.battlebg) - ((char *)&m), Interpreter::IMAGE_ID).SetReferenced());
169         td.AddField("areas", FieldDescription(((char *)&m.areas) - ((char *)&m), Area::TYPE_ID).SetAggregate());
170         td.AddField("triggers", FieldDescription(((char *)&m.triggers) - ((char *)&m), Trigger::TYPE_ID).SetAggregate());
171         td.AddField("entities", FieldDescription(((char *)&m.entities) - ((char *)&m), Entity::TYPE_ID).SetAggregate());
172         td.AddField("width", FieldDescription(((char *)&m.width) - ((char *)&m), Interpreter::NUMBER_ID));
173 }
174
175 void Map::Construct(void *data) {
176         new (data) Map;
177 }
178
179 }