Fission FSN
Loading...
Searching...
No Matches
gfCParkLevelComponent.h
Go to the documentation of this file.
1/********************************************************************
2*
3* File: gfCParkLevelComponent.h
4*
5* Purpose: The park "level": loads the map, discovers its slots and
6* runs the headless day sim against them until the day
7* timer runs out. See gfCParkDaySim.h.
8*
9* Save/restore covers day index, day time remaining, coins
10* and player ownership (buildings bought, staff hired and
11* deployed), via fsCUserSavedData (this component is
12* constructed explicitly, not through the serialise
13* lifecycle). Mid-day guest positions/queues aren't persisted -
14* the day resumes with its owned slots but an empty crowd.
15*
16* 5-day ramp with rising coin goals; dayAdvance() re-runs
17* the slot scan against a fresh sim. What the player owns
18* (slots, staff) is kept outside that per-day sim so it
19* survives the rollover - see the members below.
20*
21*********************************************************************/
22
23#ifndef gfCParkLevelComponenthdr
24#define gfCParkLevelComponenthdr
25
26#include <memory>
27#include <vector>
28
29#include <fsCore/fsStr.h>
30#include <fsCore/fsVec2d.h>
31#include <fsCore/fsPoint.h>
33
34class gfCParkDaySim;
36class fsCEntity;
37
38namespace fsNTileMap { class fsCView; }
39
41{
42 friend class fsCComponentFactory;
43
44public:
45
46 static const fsCUniqueId mTypeId;
47 static const fsS32 mNumDays = 5;
48
49 // pResume: restore saved progress (Continue) vs start a fresh day 1 (New
50 // Game). Either way the resulting state is flushed to disk before returning.
51 void levelCreate(const fsStr& pLevelName, fsBool pResume);
52
53 fsS32 dayRemainingMsGet() const { return mDayRemainingMs; }
54 fsS32 dayIndexGet() const { return mDayIndex; }
55 fsBool finalDayGet() const { return mDayIndex >= mNumDays; }
56 const gfCParkDaySim* simGet() const { return mSim.get(); }
57 gfCParkDaySim* simGet() { return mSim.get(); }
58
59 // End-of-day continue button: same park, fresh sim, higher goal.
60 void dayAdvance();
61
62 // Writes the saved-data keys (day, coins, ownership) into the in-memory
63 // user-data table. Populate-only - progressPersist() is what reaches disk.
64 void progressSave() const;
65
66 // progressSave() + flush the profile to disk (fsCProfileManager::allDataSave).
67 // Called at every checkpoint that must survive a quit - the desktop app
68 // terminates straight out of Application::run() on window close, with no
69 // applicationDidEnterBackground and no profile-manager teardown, so nothing
70 // persists unless we flush during play (mirrors how the HOG core saves at
71 // level boundaries rather than on an exit hook). Without this, Continue read
72 // an empty mCurrentLocation and loaded a blank level - a black screen.
73 void progressPersist();
74
75 // Ownership kept outside the per-day sim and re-applied each rollover (else
76 // the park stops working). Called by the purchase actions.
77 void slotPurchasedRecord(const fsStr& pSlotName, fsS32 pServiceTimeMs, fsS32 pMaxQueueLength,
78 const fsStr& pBuildingImage, fsS32 pVisitorQuota = 0,
79 fsS32 pVisitorAppeal = 0);
80 void staffHiredRecord(const fsStr& pStaffType, fsS32 pWage);
81
82 // Grid-placed decorations (tycoon build): no service slot, but their catalogue
83 // appeal and comfort affect visitors. Recorded here so they survive
84 // the day rollover and a Continue. pLocalX/Y are
85 // the view-local position the placement tap resolved to (stable across
86 // sessions - the view is rebuilt identically each load).
87 void decorationPlacedRecord(const fsStr& pImage, fsS32 pDrawWidth,
88 fsS32 pFootprintColumns, fsS32 pFootprintRows,
89 fsS32 pLocalX, fsS32 pLocalY, fsS32 pVisitorAppeal = 0,
90 fsS32 pVisitorComfort = 0);
91
92 // Drops a decoration sprite at a view-local position. Shared by the placement
93 // tap (gfCParkPlacementComponent) and Continue restore. The position is the
94 // bottom-centre grid anchor, matching service buildings. Presentation only -
95 // the level aggregates appeal before updating the sim. Returns the placed entity, or null
96 // if pView is null.
98 const fsStr& pImage, fsS32 pDrawWidth,
99 fsS32 pLocalX, fsS32 pLocalY);
100
101 // Creates and owns an asset-defined service slot at an arbitrary view-local
102 // point. Unlike an authored TMX slot, every purchase gets a unique slot name.
104 const fsStr& pServiceType, fsS32 pServiceTimeMs,
105 fsS32 pMaxQueueLength, fsS32 pVisitorQuota,
106 fsS32 pVisitorAppeal, fsS32 pDrawWidth,
107 fsS32 pFootprintColumns, fsS32 pFootprintRows,
108 fsS32 pLocalX, fsS32 pLocalY);
109
110 // Presentation shared by a live purchase and Continue restore. pLocalX/Y is
111 // the building's ground/contact point; art is bottom-centred on it.
113 const fsStr& pSlotName,
114 const fsStr& pImage, fsS32 pDrawWidth,
115 fsS32 pLocalX, fsS32 pLocalY);
116
117 // Guest presentation resolves runtime slot destinations here before falling
118 // back to fixed TMX objects.
119 fsBool runtimeSlotPositionGet(const fsStr& pSlotName, fsVec2d& pOut) const;
120
121 // Runtime slot enumeration for presentation systems that formerly discovered
122 // every staff/repair post by walking the TMX object layer.
123 fsBool runtimeSlotGetByIndex(fsS32 pIndex, fsStr& pNameOut, fsVec2d& pPositionOut) const;
124
125 // Grid occupancy check shared by building and decoration previews. Fixed TMX
126 // objects plus previously placed runtime buildings and decorations reserve
127 // their cells.
129 fsS32 pLocalX, fsS32 pLocalY,
130 fsS32 pFootprintColumns, fsS32 pFootprintRows) const;
131
132 // ---- Forest clearing & walkability -------------------------------------
133 // The authored "forest" tile layer marks blocked, clearable terrain; a cell
134 // stays forest until the player clears it (recorded in mClearedCells). Cleared
135 // and never-forested cells are walkable/buildable ground.
136
137 // True if (pCol,pRow) is inside the map, has a forest tile and is not cleared.
138 fsBool cellForestGet(fsNTileMap::fsCView* pView, fsS32 pCol, fsS32 pRow) const;
139 // True if (pCol,pRow) is inside the map and not forest (walkable/buildable).
140 fsBool cellWalkableGet(fsNTileMap::fsCView* pView, fsS32 pCol, fsS32 pRow) const;
141
142 // View-local <-> grid-cell helpers, shared by the clear tool and the guest /
143 // staff routing. cellFromLocal floors to the containing cell; cellCentreLocal
144 // returns the cell centre in view-local space.
145 fsPoint cellFromLocal(fsNTileMap::fsCView* pView, const fsVec2d& pLocal) const;
146 fsVec2d cellCentreLocal(fsNTileMap::fsCView* pView, fsS32 pCol, fsS32 pRow) const;
147
148 // Breadth-first shortest path across walkable cells, inclusive of both ends.
149 // Empty if either end is off-map or the target is unreachable. Diagonals are
150 // not used, so routes hug the cleared corridors.
151 std::vector<fsPoint> pathFindCells(fsNTileMap::fsCView* pView,
152 const fsPoint& pFrom, const fsPoint& pTo) const;
153
154 // Nearest walkable cell to pCell (pCell itself if already walkable), by an
155 // expanding ring search. Used to keep characters off forest when their target
156 // (a wander point, the park centre) lands on an uncleared tile.
157 fsPoint nearestWalkableCell(fsNTileMap::fsCView* pView, const fsPoint& pCell) const;
158
159 // Nearest walkable cell to pDesired that is actually reachable from pFrom
160 // (flood over walkable cells, pick the reached cell closest to pDesired).
161 // Unlike nearestWalkableCell this never returns a cell in a different cleared
162 // region, so a route to it never has to cut across forest to get there.
164 const fsPoint& pFrom, const fsPoint& pDesired) const;
165
166 // Coins charged to clear one forest cell (appSettings "forestClearCostCoins").
168
169 // Attempt to clear the forest cell at (pCol,pRow): valid only if it is forest,
170 // orthogonally adjacent to open ground (so clears grow from the edges) and the
171 // player can afford it. On success charges coins, reveals the cell, records it
172 // and persists. Returns false (and changes nothing) otherwise.
174
175 // Daily wage bill, and what was charged at the end of the last day.
176 fsS32 dailyWagesGet() const;
177 fsS32 lastDayWagesGet() const { return mLastDayWages; }
178 fsS32 parkReputationGet() const { return mParkReputation; }
179
180 // Repair dispatch armed: tapping the office arms it, the next building tap
181 // sends a repairer instead of deploy/recall. Shared across those components.
182 fsBool repairArmedGet() const { return mRepairArmed; }
183 void repairArmedSet(fsBool pArmed) { mRepairArmed = pArmed; }
184
185 // Staff deployment is per-sim, so it too must be remembered across the
186 // rollover or day 2 opens with nothing actually staffed.
187 void staffDeployedRecord(const fsStr& pSlotName);
188 void staffRecalledRecord(const fsStr& pSlotName);
189
190 virtual ~gfCParkLevelComponent();
191
192protected:
193
194 void updateDo(fsS32 pDeltaMs) override;
195
196 // Debug speed keys (1 = 1x, 2 = 4x, 3 = 8x), same as gfCHogLevelComponent -
197 // the only reason this is a message listener.
198 void listenersRegisterDo() override;
199 void listenersDeregisterDo() override;
200 fsBool messageProcessDo(const fsCUniqueId& pMessageType,
201 const fsIMessageDispatcher::sMessageParameters& pParam) override;
202
203 static fsIComponent* const create(fsCEntity* const pParent);
204 gfCParkLevelComponent(fsCEntity* const pParent);
205
206private:
207
208 void daySimBegin();
209 void guestTemplatesLoad();
210 void progressRestore();
211 fsS32 visitorQuotaHighestOwnedGet() const;
212 fsS32 visitorDemandFromParkGet() const;
213 fsS32 walkingSatisfactionFromParkGet() const;
214 void visitorNumbersRefresh();
215 void reputationSettle();
216
217 // Rebuilds mPurchasedSlots/mHiredStaff/mDeployedSlots from saved data.
218 // Must run before daySimBegin() re-applies them to a fresh sim.
219 void ownershipRestore(fsCUserSavedData* const pUserData);
220
221 // Translucent greybox markers showing where the authored slots are.
222 void slotMarkersCreate(fsNTileMap::fsCView* const pView);
223
224 // Fixed scenery at a named anchor (staff office, park gate) - not a slot, so
225 // no catalogue entry and the sim knows nothing about it.
226 void mapFurnitureCreate(fsNTileMap::fsCView* const pView, const fsStr& pObjectName,
227 const fsStr& pImagePath, fsF32 pDrawScale, fsBool pRepairDispatchTap = false);
228
229 // Locates and caches the "forest" tile layer's map-layer id (-1 if none).
230 void forestLayerResolve(fsNTileMap::fsCView* const pView);
231 // Re-hides a cleared cell's forest tile on the view (clear time and Continue).
232 void clearedCellApply(fsNTileMap::fsCView* const pView, fsS32 pCol, fsS32 pRow);
233 fsBool cellClearedGet(fsS32 pCol, fsS32 pRow) const;
234
235 static const fsS32 mDayDurationMs;
236
237 fsS32 mDayIndex;
238 fsS32 mDayRemainingMs;
239 fsBool mDayEndShown;
240
241 // Counts up each tick; a periodic autosave flushes progress so a mid-day
242 // quit (which fires no lifecycle save on desktop) still resumes.
243 fsS32 mAutosaveTimerMs;
244
245 // Player ownership, kept outside the per-day sim so it survives the rollover.
246 struct SOwnedSlot
247 {
248 fsStr mName;
249 fsS32 mServiceTimeMs;
250 fsS32 mMaxQueueLength;
251 // The building's art, kept so its sprite can be re-placed on Continue.
252 fsStr mBuildingImage;
253 fsBool mRuntime = false;
254 fsStr mServiceType;
255 fsS32 mLocalX = 0;
256 fsS32 mLocalY = 0;
257 fsS32 mDrawWidth = 0;
258 fsS32 mFootprintColumns = 0;
259 fsS32 mFootprintRows = 0;
260 // Zero for ordinary service buildings. Entrance quotas do not stack;
261 // the highest owned value replaces the fixed gate's base quota.
262 fsS32 mVisitorQuota = 0;
263 fsS32 mVisitorAppeal = 0;
264 };
265
266 // One entry per hired head, so different roles can carry different wages.
267 struct SHiredStaff
268 {
269 fsStr mType;
270 fsS32 mWage;
271 };
272
273 // A grid-placed decoration: art, footprint, appeal, comfort and bottom-centre anchor
274 // in view-local coordinates. It has no guest service type.
275 struct SOwnedDecoration
276 {
277 fsStr mImage;
278 fsS32 mDrawWidth = 0;
279 fsS32 mFootprintColumns = 1;
280 fsS32 mFootprintRows = 1;
281 fsS32 mLocalX;
282 fsS32 mLocalY;
283 fsS32 mVisitorAppeal = 0;
284 fsS32 mVisitorComfort = 0;
285 };
286
287 std::vector<SOwnedSlot> mPurchasedSlots;
288 std::vector<fsStr> mDeployedSlots;
289 std::vector<SHiredStaff> mHiredStaff;
290 std::vector<SOwnedDecoration> mOwnedDecorations;
291 // Forest cells the player has cleared, in map-grid (col,row). Read as
292 // walkable/buildable, re-hidden on the view each load. Persisted.
293 std::vector<fsPoint> mClearedCells;
294 // Map-layer id of the "forest" tile layer, resolved once at levelCreate.
295 fsS32 mForestLayerId;
296 fsS32 mLastDayWages;
297 fsS32 mParkReputation;
298 fsS32 mReputationSettledDay;
299 fsBool mRepairArmed;
300 fsS32 mRuntimeSlotSequence;
301
302 std::unique_ptr<gfCParkDaySim> mSim;
303};
304
305#endif
Definition fsCEntity.h:39
Definition fsCUniqueId.h:21
Definition fsCUserSavedData.h:25
Definition fsIComponent.h:26
fsIMessageListenerComponent(fsCEntity *pParent)
Definition fsIMessageListenerComponent.cpp:9
Definition fsCView.h:28
Definition fsStr.h:23
Definition gfCParkDaySim.h:25
fsS32 dayRemainingMsGet() const
Definition gfCParkLevelComponent.h:53
void listenersRegisterDo() override
Definition gfCParkLevelComponent.cpp:1359
gfCParkDaySim * simGet()
Definition gfCParkLevelComponent.h:57
fsBool runtimeSlotPositionGet(const fsStr &pSlotName, fsVec2d &pOut) const
Definition gfCParkLevelComponent.cpp:599
static fsCEntity * decorationPresentationPlace(fsNTileMap::fsCView *pView, const fsStr &pImage, fsS32 pDrawWidth, fsS32 pLocalX, fsS32 pLocalY)
Definition gfCParkLevelComponent.cpp:430
void levelCreate(const fsStr &pLevelName, fsBool pResume)
Definition gfCParkLevelComponent.cpp:201
void listenersDeregisterDo() override
Definition gfCParkLevelComponent.cpp:1365
fsBool serviceBuildingPlace(fsNTileMap::fsCView *pView, const fsStr &pImage, const fsStr &pServiceType, fsS32 pServiceTimeMs, fsS32 pMaxQueueLength, fsS32 pVisitorQuota, fsS32 pVisitorAppeal, fsS32 pDrawWidth, fsS32 pFootprintColumns, fsS32 pFootprintRows, fsS32 pLocalX, fsS32 pLocalY)
Definition gfCParkLevelComponent.cpp:554
fsBool cellForestGet(fsNTileMap::fsCView *pView, fsS32 pCol, fsS32 pRow) const
Definition gfCParkLevelComponent.cpp:761
virtual ~gfCParkLevelComponent()
Definition gfCParkLevelComponent.cpp:1622
friend class fsCComponentFactory
Definition gfCParkLevelComponent.h:42
const gfCParkDaySim * simGet() const
Definition gfCParkLevelComponent.h:56
fsBool finalDayGet() const
Definition gfCParkLevelComponent.h:55
void dayAdvance()
Definition gfCParkLevelComponent.cpp:1303
static const fsCUniqueId mTypeId
Definition gfCParkLevelComponent.h:46
fsBool messageProcessDo(const fsCUniqueId &pMessageType, const fsIMessageDispatcher::sMessageParameters &pParam) override
Definition gfCParkLevelComponent.cpp:1371
fsBool parkPlacementValid(fsNTileMap::fsCView *pView, fsS32 pLocalX, fsS32 pLocalY, fsS32 pFootprintColumns, fsS32 pFootprintRows) const
Definition gfCParkLevelComponent.cpp:638
fsBool forestClearAt(fsNTileMap::fsCView *pView, fsS32 pCol, fsS32 pRow)
Definition gfCParkLevelComponent.cpp:1013
fsVec2d cellCentreLocal(fsNTileMap::fsCView *pView, fsS32 pCol, fsS32 pRow) const
Definition gfCParkLevelComponent.cpp:811
void decorationPlacedRecord(const fsStr &pImage, fsS32 pDrawWidth, fsS32 pFootprintColumns, fsS32 pFootprintRows, fsS32 pLocalX, fsS32 pLocalY, fsS32 pVisitorAppeal=0, fsS32 pVisitorComfort=0)
Definition gfCParkLevelComponent.cpp:491
void updateDo(fsS32 pDeltaMs) override
Definition gfCParkLevelComponent.cpp:1314
void staffDeployedRecord(const fsStr &pSlotName)
Definition gfCParkLevelComponent.cpp:1240
static fsIComponent *const create(fsCEntity *const pParent)
Definition gfCParkLevelComponent.cpp:1602
fsPoint nearestReachableCell(fsNTileMap::fsCView *pView, const fsPoint &pFrom, const fsPoint &pDesired) const
Definition gfCParkLevelComponent.cpp:935
fsPoint nearestWalkableCell(fsNTileMap::fsCView *pView, const fsPoint &pCell) const
Definition gfCParkLevelComponent.cpp:901
void repairArmedSet(fsBool pArmed)
Definition gfCParkLevelComponent.h:183
void staffRecalledRecord(const fsStr &pSlotName)
Definition gfCParkLevelComponent.cpp:1252
fsS32 lastDayWagesGet() const
Definition gfCParkLevelComponent.h:177
fsS32 forestClearCostGet() const
Definition gfCParkLevelComponent.cpp:999
std::vector< fsPoint > pathFindCells(fsNTileMap::fsCView *pView, const fsPoint &pFrom, const fsPoint &pTo) const
Definition gfCParkLevelComponent.cpp:820
void progressSave() const
Definition gfCParkLevelComponent.cpp:1401
fsS32 parkReputationGet() const
Definition gfCParkLevelComponent.h:178
void staffHiredRecord(const fsStr &pStaffType, fsS32 pWage)
Definition gfCParkLevelComponent.cpp:1222
fsS32 dailyWagesGet() const
Definition gfCParkLevelComponent.cpp:1230
fsBool repairArmedGet() const
Definition gfCParkLevelComponent.h:182
fsPoint cellFromLocal(fsNTileMap::fsCView *pView, const fsVec2d &pLocal) const
Definition gfCParkLevelComponent.cpp:794
void progressPersist()
Definition gfCParkLevelComponent.cpp:1477
gfCParkLevelComponent(fsCEntity *const pParent)
Definition gfCParkLevelComponent.cpp:1607
fsS32 dayIndexGet() const
Definition gfCParkLevelComponent.h:54
fsBool cellWalkableGet(fsNTileMap::fsCView *pView, fsS32 pCol, fsS32 pRow) const
Definition gfCParkLevelComponent.cpp:780
void slotPurchasedRecord(const fsStr &pSlotName, fsS32 pServiceTimeMs, fsS32 pMaxQueueLength, const fsStr &pBuildingImage, fsS32 pVisitorQuota=0, fsS32 pVisitorAppeal=0)
Definition gfCParkLevelComponent.cpp:1123
static const fsS32 mNumDays
Definition gfCParkLevelComponent.h:47
static fsCEntity * serviceBuildingPresentationPlace(fsNTileMap::fsCView *pView, const fsStr &pSlotName, const fsStr &pImage, fsS32 pDrawWidth, fsS32 pLocalX, fsS32 pLocalY)
Definition gfCParkLevelComponent.cpp:508
fsBool runtimeSlotGetByIndex(fsS32 pIndex, fsStr &pNameOut, fsVec2d &pPositionOut) const
Definition gfCParkLevelComponent.cpp:612
bool fsBool
Definition fsBaseTypes.h:26
int fsS32
Definition fsBaseTypes.h:20
float fsF32
Definition fsBaseTypes.h:28
Definition fsILayer.h:21
Definition fsIMessageDispatcher.h:32
Definition fsPoint.h:17
Definition fsVec2d.h:16