20 * @file |
20 * @file |
21 * @brief MapModel class implementation |
21 * @brief MapModel class implementation |
22 */ |
22 */ |
23 |
23 |
24 #include "MapModel.h" |
24 #include "MapModel.h" |
|
25 #include "hwapplication.h" |
25 |
26 |
|
27 #include <QSettings> |
26 |
28 |
27 void MapModel::loadMaps() |
29 MapModel::MapInfo MapModel::MapInfoRandom = {MapModel::GeneratedMap, "+rnd+", "", 0, "", "", ""}; |
|
30 MapModel::MapInfo MapModel::MapInfoMaze = {MapModel::GeneratedMaze, "+maze+", "", 0, "", "", ""}; |
|
31 MapModel::MapInfo MapModel::MapInfoDrawn = {MapModel::HandDrawnMap, "+drawn+", "", 0, "", "", ""}; |
|
32 |
|
33 void MapModel::loadMaps(MapType maptype) |
28 { |
34 { |
29 // this method resets the contents of this model (important to know for views). |
35 // this method resets the contents of this model (important to know for views). |
30 beginResetModel(); |
36 beginResetModel(); |
31 |
37 |
32 // we'll need the DataManager a few times, so let's get a reference to it |
38 // we'll need the DataManager a few times, so let's get a reference to it |
37 datamgr.entryList("Maps", QDir::AllDirs | QDir::NoDotAndDotDot); |
43 datamgr.entryList("Maps", QDir::AllDirs | QDir::NoDotAndDotDot); |
38 |
44 |
39 // empty list, so that we can (re)fill it |
45 // empty list, so that we can (re)fill it |
40 QStandardItemModel::clear(); |
46 QStandardItemModel::clear(); |
41 |
47 |
42 QList<QStandardItem *> genMaps; |
48 //QList<QStandardItem *> staticMaps; |
43 QList<QStandardItem *> missionMaps; |
49 //QList<QStandardItem *> missionMaps; |
44 QList<QStandardItem *> staticMaps; |
50 QList<QStandardItem *> mapList; |
45 |
|
46 // add generated/handdrawn maps to list |
|
47 // TODO: icons for these |
|
48 |
|
49 genMaps.append( |
|
50 infoToItem(QIcon(), QComboBox::tr("generated map..."), GeneratedMap, "+rnd+")); |
|
51 genMaps.append( |
|
52 infoToItem(QIcon(), QComboBox::tr("generated maze..."), GeneratedMaze, "+maze+")); |
|
53 genMaps.append( |
|
54 infoToItem(QIcon(), QComboBox::tr("hand drawn map..."), HandDrawnMap, "+drawn+")); |
|
55 |
51 |
56 // only 2 map relate files are relevant: |
52 // only 2 map relate files are relevant: |
57 // - the cfg file that contains the settings/info of the map |
53 // - the cfg file that contains the settings/info of the map |
58 // - the lua file - if it exists it's a mission, otherwise it isn't |
54 // - the lua file - if it exists it's a mission, otherwise it isn't |
59 QFile mapLuaFile; |
55 QFile mapLuaFile; |
62 // add mission/static maps to lists |
58 // add mission/static maps to lists |
63 foreach (QString map, maps) |
59 foreach (QString map, maps) |
64 { |
60 { |
65 mapCfgFile.setFileName(QString("physfs://Maps/%1/map.cfg").arg(map)); |
61 mapCfgFile.setFileName(QString("physfs://Maps/%1/map.cfg").arg(map)); |
66 mapLuaFile.setFileName(QString("physfs://Maps/%1/map.lua").arg(map)); |
62 mapLuaFile.setFileName(QString("physfs://Maps/%1/map.lua").arg(map)); |
67 |
63 QSettings descSettings(QString("physfs://Maps/%1/desc.txt").arg(map), QSettings::IniFormat); |
68 |
64 |
69 if (mapCfgFile.open(QFile::ReadOnly)) |
65 if (mapCfgFile.open(QFile::ReadOnly)) |
70 { |
66 { |
71 QString caption; |
67 QString caption; |
72 QString theme; |
68 QString theme; |
73 quint32 limit = 0; |
69 quint32 limit = 0; |
74 QString scheme; |
70 QString scheme; |
75 QString weapons; |
71 QString weapons; |
|
72 QString desc; |
|
73 |
76 // if there is a lua file for this map, then it's a mission |
74 // if there is a lua file for this map, then it's a mission |
77 bool isMission = mapLuaFile.exists(); |
75 bool isMission = mapLuaFile.exists(); |
78 MapType type = isMission?MissionMap:StaticMap; |
76 MapType type = isMission ? MissionMap : StaticMap; |
|
77 |
|
78 // If we're supposed to ignore this type, continue |
|
79 if (type != maptype) continue; |
79 |
80 |
80 // load map info from file |
81 // load map info from file |
81 QTextStream input(&mapCfgFile); |
82 QTextStream input(&mapCfgFile); |
82 input >> theme; |
83 theme = input.readLine(); |
83 input >> limit; |
84 limit = input.readLine().toInt(); |
84 if (isMission) { // scheme and weapons are only relevant for missions |
85 if (isMission) { // scheme and weapons are only relevant for missions |
85 input >> scheme; |
86 scheme = input.readLine(); |
86 input >> weapons; |
87 weapons = input.readLine(); |
87 } |
88 } |
88 mapCfgFile.close(); |
89 mapCfgFile.close(); |
|
90 |
|
91 // Load description (if applicable) |
|
92 if (isMission) |
|
93 { |
|
94 QString locale = HWApplication::keyboardInputLocale().name(); |
|
95 desc = descSettings.value(locale, QString()).toString().replace("|", "\n"); |
|
96 } |
89 |
97 |
90 // let's use some semi-sane hedgehog limit, rather than none |
98 // let's use some semi-sane hedgehog limit, rather than none |
91 if (limit == 0) |
99 if (limit == 0) |
92 limit = 18; |
100 limit = 18; |
93 |
|
94 |
101 |
95 // the default scheme/weaponset for missions. |
102 // the default scheme/weaponset for missions. |
96 // if empty we assume the map sets these internally -> locked |
103 // if empty we assume the map sets these internally -> locked |
97 if (isMission) |
104 if (isMission) |
98 { |
105 { |
105 weapons = "locked"; |
112 weapons = "locked"; |
106 else |
113 else |
107 weapons.replace("_", " "); |
114 weapons.replace("_", " "); |
108 } |
115 } |
109 |
116 |
110 // add a mission caption prefix to missions |
117 // caption |
111 if (isMission) |
118 caption = map; |
112 { |
|
113 // TODO: icon |
|
114 caption = QComboBox::tr("Mission") + ": " + map; |
|
115 } |
|
116 else |
|
117 caption = map; |
|
118 |
119 |
119 // we know everything there is about the map, let's get am item for it |
120 // we know everything there is about the map, let's get am item for it |
120 QStandardItem * item = infoToItem( |
121 QStandardItem * item = MapModel::infoToItem( |
121 QIcon(), caption, type, map, theme, limit, scheme, weapons); |
122 QIcon(), caption, type, map, theme, limit, scheme, weapons, desc); |
122 |
123 |
123 // append item to the list |
124 // append item to the list |
124 if (isMission) |
125 mapList.append(item); |
125 missionMaps.append(item); |
|
126 else |
|
127 staticMaps.append(item); |
|
128 |
|
129 } |
126 } |
130 |
127 |
131 } |
128 } |
132 |
129 |
133 |
130 // Create column-index lookup table |
134 // define a separator item |
|
135 QStandardItem separator("---"); |
|
136 separator.setData(QLatin1String("separator"), Qt::AccessibleDescriptionRole); |
|
137 separator.setFlags(separator.flags() & ~( Qt::ItemIsEnabled | Qt::ItemIsSelectable ) ); |
|
138 |
|
139 // create list: |
|
140 // generated+handdrawn maps, 2 saperators, missions, 1 separator, static maps |
|
141 QList<QStandardItem * > items; |
|
142 items.append(genMaps); |
|
143 items.append(separator.clone()); |
|
144 items.append(separator.clone()); |
|
145 items.append(missionMaps); |
|
146 items.append(separator.clone()); |
|
147 items.append(staticMaps); |
|
148 |
|
149 |
|
150 // create row-index lookup table |
|
151 |
131 |
152 m_mapIndexes.clear(); |
132 m_mapIndexes.clear(); |
153 |
133 |
154 int count = items.size(); |
|
155 |
134 |
|
135 int count = mapList.size(); |
156 for (int i = 0; i < count; i++) |
136 for (int i = 0; i < count; i++) |
157 { |
137 { |
158 QStandardItem * si = items.at(i); |
138 QStandardItem * si = mapList.at(i); |
159 QVariant v = si->data(Qt::UserRole + 1); |
139 QVariant v = si->data(Qt::UserRole + 1); |
160 if (v.canConvert<MapInfo>()) |
140 if (v.canConvert<MapInfo>()) |
161 m_mapIndexes.insert(v.value<MapInfo>().name, i); |
141 m_mapIndexes.insert(v.value<MapInfo>().name, i); |
162 } |
142 } |
163 |
143 |
164 |
144 QStandardItemModel::appendColumn(mapList); |
165 // store start-index and count of relevant types |
|
166 |
|
167 m_typeLoc.insert(GeneratedMap, QPair<int,int>(0, 1)); |
|
168 m_typeLoc.insert(GeneratedMaze, QPair<int,int>(1, 1)); |
|
169 m_typeLoc.insert(HandDrawnMap, QPair<int,int>(2, 1)); |
|
170 // mission maps |
|
171 int startIdx = genMaps.size() + 2; // start after genMaps and 2 separators |
|
172 count = missionMaps.size(); |
|
173 m_typeLoc.insert(MissionMap, QPair<int,int>(startIdx, count)); |
|
174 // static maps |
|
175 startIdx += count + 1; // start after missions and 2 separators |
|
176 count = staticMaps.size(); |
|
177 m_typeLoc.insert(StaticMap, QPair<int,int>(startIdx, count)); |
|
178 |
|
179 // store list contents in the item model |
|
180 QStandardItemModel::appendColumn(items); |
|
181 |
|
182 |
145 |
183 endResetModel(); |
146 endResetModel(); |
184 } |
147 } |
185 |
148 |
186 |
149 bool MapModel::mapExists(const QString & map) const |
187 int MapModel::randomMap(MapType type) const |
|
188 { |
150 { |
189 // return a random index for this type or -1 if none available |
151 return findMap(map) >= 0; |
190 QPair<int,int> loc = m_typeLoc.value(type, QPair<int,int>(-1,0)); |
|
191 |
|
192 int startIdx = loc.first; |
|
193 int count = loc.second; |
|
194 |
|
195 if (count < 1) |
|
196 return -1; |
|
197 else |
|
198 return startIdx + (rand() % count); |
|
199 } |
152 } |
200 |
153 |
|
154 int MapModel::findMap(const QString & map) const |
|
155 { |
|
156 return m_mapIndexes.value(map, -1); |
|
157 } |
|
158 |
|
159 QStandardItem * MapModel::getMap(const QString & map) |
|
160 { |
|
161 int loc = findMap(map); |
|
162 if (loc < 0) return NULL; |
|
163 return item(loc); |
|
164 } |
201 |
165 |
202 QStandardItem * MapModel::infoToItem( |
166 QStandardItem * MapModel::infoToItem( |
203 const QIcon & icon, |
167 const QIcon & icon, |
204 const QString caption, |
168 const QString caption, |
205 MapType type, |
169 MapType type, |
206 QString name, |
170 QString name, |
207 QString theme, |
171 QString theme, |
208 quint32 limit, |
172 quint32 limit, |
209 QString scheme, |
173 QString scheme, |
210 QString weapons) |
174 QString weapons, |
211 const |
175 QString desc) |
212 { |
176 { |
213 QStandardItem * item = new QStandardItem(icon, caption); |
177 QStandardItem * item = new QStandardItem(icon, caption); |
214 MapInfo mapInfo; |
178 MapInfo mapInfo; |
215 QVariant qvar(QVariant::UserType); |
179 QVariant qvar(QVariant::UserType); |
216 |
180 |