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