Skip to main content
Verticopolis engineGitHub

verticopolis_engine/
lib.rs

1//! The simulation engine of [Verticopolis](https://verticopolis.com), a tower
2//! building game inspired by SimTower (1994).
3//!
4//! This crate is the whole simulation: every rule, price, build limit, command,
5//! save format and gameplay event. The web game runs the same engine compiled
6//! to WebAssembly. Your code owns everything a player sees and hears; the
7//! engine owns what happens in the tower.
8//!
9//! # Quick start
10//!
11//! ```
12//! use verticopolis_engine::clock::GameMode;
13//! use verticopolis_engine::facilities::Kind;
14//! use verticopolis_engine::sim::Simulation;
15//!
16//! // A new Classic game from seed 42.
17//! let mut sim = Simulation::new_game(42, GameMode::Classic);
18//!
19//! // A lobby along the ground floor, then an office above it.
20//! let tiles: Vec<i64> = (100..124).collect();
21//! sim.paint_brush(Kind::Lobby, 1, &tiles);
22//! let quote = sim.can_build(Kind::Office, 2, 106);
23//! assert!(quote.ok);
24//! assert!(sim.build(Kind::Office, 2, 106).ok);
25//!
26//! // One game day, an hour at a time, draining the gameplay events.
27//! for _ in 0..24 {
28//!     sim.tick(60.0);
29//!     for event in sim.gameplay.drain() {
30//!         println!("{}", event.to_json());
31//!     }
32//! }
33//! println!("population {}, money {}", sim.population(), sim.money);
34//! ```
35//!
36//! # What a host calls
37//!
38//! | To | Call |
39//! | --- | --- |
40//! | Start a game | [`Simulation::new_game`](sim::Simulation::new_game), [`new_game_with`](sim::Simulation::new_game_with) |
41//! | Run time | [`tick`](sim::Simulation::tick), or [`FrameStepper`](fixed_step::FrameStepper) to drive it from display frames |
42//! | Build and sell | [`can_build`](sim::Simulation::can_build), [`build`](sim::Simulation::build), [`paint_brush`](sim::Simulation::paint_brush), [`can_build_transport`](sim::Simulation::can_build_transport), [`build_transport`](sim::Simulation::build_transport), [`sell_at`](sim::Simulation::sell_at), [`toggle_auto_bridge`](sim::Simulation::toggle_auto_bridge) |
43//! | Change elevators and remove things | [`add_car`](sim::Simulation::add_car), [`remove_car`](sim::Simulation::remove_car), [`begin_extend`](sim::Simulation::begin_extend), [`extend_transport`](sim::Simulation::extend_transport), [`end_extend`](sim::Simulation::end_extend), [`remove_facility`](sim::Simulation::remove_facility) |
44//! | Set prices | [`adjust_rent`](sim::Simulation::adjust_rent), [`price_unit`](sim::Simulation::price_unit), [`set_no_rate`](sim::Simulation::set_no_rate), [`apply_rent_batch`](sim::Simulation::apply_rent_batch) |
45//! | Answer the game | [`resolve_choice`](sim::Simulation::resolve_choice), [`set_film_policy`](sim::Simulation::set_film_policy), [`change_film`](sim::Simulation::change_film) |
46//! | Draw the tower | [`view`]: [`structure_view`](view::structure_view), [`ViewReader`](view::ViewReader), [`meta_since`](view::meta_since); or the older flat [`frame`] |
47//! | React to what happened | [`gameplay`]: drain `sim.gameplay` after each frame |
48//! | Show prices and rules | [`catalog::catalog`] |
49//! | Save and load | [`load`]: [`encode_simulation_vctower`](load::encode_simulation_vctower), [`decode_vctower`](load::decode_vctower), [`deserialize`](load::deserialize) |
50//! | Open a 1994 save | [`import_tdt`], [`export_tdt`] |
51//! | Name the engine | [`identity::identity`] |
52//! | Compare two games | [`canonical::digest`] of [`snapshot::state_view`] |
53//!
54//! # How the engine behaves
55//!
56//! - **One [`Simulation`](sim::Simulation) is one game.** Its public fields
57//!   are for reading; change a game only through its commands, which apply
58//!   the rules and charge the money.
59//! - **Commands answer instead of panicking.** A refused command changes
60//!   nothing and returns a reason a player can read.
61//! - **No I/O.** The engine reads no file, clock, environment or network and
62//!   starts no thread. You pass in time, file contents and timestamps, and get
63//!   bytes back to store where you like.
64//! - **Deterministic.** The same seed, commands and sequence of `tick` calls
65//!   give the same game on any machine, here and in the WebAssembly build.
66//!   The conformance suite in the repository is how a host proves it.
67//! - **Coordinates.** Floor 1 is the ground floor; 0 and below are basements,
68//!   down to [`MIN_FLOOR`](facilities::MIN_FLOOR). A tile column `x` runs
69//!   from 0 across the lot's [`LOT_WIDTH`](facilities::LOT_WIDTH).
70//! - **Two modes.** [`GameMode::Classic`](clock::GameMode::Classic) follows
71//!   the 1994 original; [`GameMode::Modern`](clock::GameMode::Modern) adds
72//!   rooms and options. The catalog lists every difference a frontend shows.
73//!
74//! # Features
75//!
76//! None are on by default. `wasm` builds the JavaScript binding, and
77//! `conformance` adds the harness that replays the conformance suite.
78//!
79//! The guides at [docs.verticopolis.com](https://docs.verticopolis.com) cover
80//! adding the crate, saves, the conformance suite and the JavaScript package.
81#![warn(missing_docs)]
82#![allow(
83    clippy::too_many_arguments,
84    clippy::type_complexity,
85    clippy::needless_range_loop,
86    clippy::manual_clamp,
87    clippy::collapsible_match
88)]
89
90pub mod brush;
91pub mod build;
92pub mod canonical;
93pub mod catalog;
94pub mod charges;
95#[doc(hidden)]
96pub mod churn;
97pub mod clock;
98#[doc(hidden)]
99pub mod crowd;
100#[doc(hidden)]
101pub mod demand;
102#[doc(hidden)]
103pub mod diagnostics;
104#[doc(hidden)]
105pub mod dispatch;
106#[doc(hidden)]
107pub mod econ;
108#[doc(hidden)]
109pub mod economy;
110pub mod events;
111mod export_stream;
112pub mod facilities;
113#[doc(hidden)]
114pub mod fflate;
115pub mod fixed_step;
116pub mod frame;
117pub mod gameplay;
118#[doc(hidden)]
119pub mod housekeeping;
120pub mod identity;
121#[doc(hidden)]
122pub mod jsmath;
123#[doc(hidden)]
124pub mod ledger;
125pub mod load;
126#[cfg(test)]
127mod load_fidelity_tests;
128#[cfg(test)]
129mod load_newer_save_tests;
130#[cfg(test)]
131mod rule_tests;
132#[cfg(test)]
133mod wedding_hall_tests;
134// The binding's save reader (#1225): `wasm.rs` loads through it, and the
135// crate's tests check it against `load::deserialize`.
136#[cfg(any(test, feature = "wasm"))]
137mod load_stream;
138mod noise;
139#[doc(hidden)]
140pub mod panels;
141#[doc(hidden)]
142pub mod presence;
143#[doc(hidden)]
144pub mod render_reads;
145pub mod rent;
146#[doc(hidden)]
147pub mod rng;
148#[doc(hidden)]
149pub mod rules;
150#[doc(hidden)]
151pub mod satisfaction;
152#[doc(hidden)]
153pub mod save_delta;
154#[cfg(any(test, feature = "wasm"))]
155mod vctower_import;
156#[cfg(test)]
157mod vctower_import_tests;
158// The conformance harness reads the suite's files, so a host links it only
159// with the `conformance` feature (tier 2 in API.md). The crate's unit tests
160// always have it; a test under `tests/` needs the feature like any host.
161// The harness replays the suite's own command list, which
162// `conformance/README.md` documents; its items are not host API.
163#[allow(missing_docs)]
164#[cfg(any(test, feature = "conformance"))]
165pub mod scenario;
166#[cfg(any(test, feature = "conformance"))]
167#[doc(hidden)]
168pub mod scenario_detail;
169#[cfg(test)]
170mod scenario_reason_tests;
171#[cfg(test)]
172mod scenario_star_tests;
173#[cfg(test)]
174mod scenario_tune_tests;
175#[doc(hidden)]
176pub mod schedule;
177#[doc(hidden)]
178pub mod schedule_authoring;
179#[doc(hidden)]
180pub mod schedule_facts;
181mod schedule_geometry;
182#[doc(hidden)]
183pub mod schedule_presets;
184#[doc(hidden)]
185pub mod services;
186pub mod sim;
187#[doc(hidden)]
188pub mod sim_loop;
189mod sim_save;
190pub mod snapshot;
191#[doc(hidden)]
192pub mod star;
193#[cfg(any(test, feature = "conformance"))]
194pub mod suite;
195#[doc(hidden)]
196pub mod tdt;
197pub use tdt::{export_tdt, import_tdt};
198mod sim_undo;
199mod sim_undo_caps;
200mod sim_undo_check;
201mod sim_undo_ground;
202#[doc(hidden)]
203pub mod telemetry;
204#[doc(hidden)]
205pub mod tower;
206mod tower_index;
207#[doc(hidden)]
208pub mod tower_query;
209mod tower_query_state;
210mod tower_removal;
211mod undo;
212mod undo_journal;
213pub mod view;
214// The JavaScript binding, documented by the package README.
215#[doc(hidden)]
216#[cfg(feature = "wasm")]
217pub mod wasm;