Compare commits
7 Commits
a86b57d85c
...
92a03ccbd1
Author | SHA1 | Date |
---|---|---|
Mark | 92a03ccbd1 | |
Mark | 69b35bd43c | |
Mark | 327e2b43b3 | |
Mark | 5528f6ed4e | |
Mark | 308e380241 | |
Mark | 855eb0680b | |
Mark | f53e191de3 |
5
TODO.md
5
TODO.md
|
@ -1,8 +1,11 @@
|
||||||
# Specific projects
|
# Specific projects
|
||||||
|
|
||||||
## Now:
|
## Now:
|
||||||
|
- init on resize
|
||||||
- hide ui element
|
- hide ui element
|
||||||
- zoom limits
|
- zoom limits
|
||||||
|
- text scrolling
|
||||||
|
- scrollbox scroll limits
|
||||||
- clean up content
|
- clean up content
|
||||||
- Clean up state api
|
- Clean up state api
|
||||||
- Clean up & document UI api
|
- Clean up & document UI api
|
||||||
|
@ -12,6 +15,8 @@
|
||||||
- Selection while flying
|
- Selection while flying
|
||||||
- outfitter
|
- outfitter
|
||||||
- fps textbox positioning
|
- fps textbox positioning
|
||||||
|
- shield generation curve
|
||||||
|
- clippy & rules
|
||||||
|
|
||||||
## Small jobs
|
## Small jobs
|
||||||
- Better planet icons in radar
|
- Better planet icons in radar
|
||||||
|
|
2
assets
2
assets
|
@ -1 +1 @@
|
||||||
Subproject commit b8ea8c5a04c0216304a81ebf396b7320a709d6ed
|
Subproject commit bd425ccb10bb16661620916ff4f1a387b54ce7ca
|
|
@ -2,6 +2,14 @@
|
||||||
name = "Plasma Engines"
|
name = "Plasma Engines"
|
||||||
thumbnail = "icon::engine"
|
thumbnail = "icon::engine"
|
||||||
|
|
||||||
|
desc = """
|
||||||
|
This is the smallest of the plasma propulsion systems produced by
|
||||||
|
Delta V Corporation, suitable for very light fighters and interceptors.
|
||||||
|
|
||||||
|
Plasma engines are a bit more powerful than ion engines of the same size,
|
||||||
|
but they are less energy efficient and produce more heat.
|
||||||
|
"""
|
||||||
|
|
||||||
space.engine = 20
|
space.engine = 20
|
||||||
engine.thrust = 100
|
engine.thrust = 100
|
||||||
engine.flare.sprite = "flare::ion"
|
engine.flare.sprite = "flare::ion"
|
||||||
|
@ -14,6 +22,15 @@ steering.power = 20
|
||||||
thumbnail = "icon::shield"
|
thumbnail = "icon::shield"
|
||||||
name = "Shield Generator"
|
name = "Shield Generator"
|
||||||
|
|
||||||
|
desc = """
|
||||||
|
This is the standard shield generator for fighters and interceptors,
|
||||||
|
as well as for many non-combat starships. Although it is possible for
|
||||||
|
a ship to have no shield generator at all, recharging its shield matrix
|
||||||
|
only when landed in a hospitable spaceport, life in deep space is
|
||||||
|
unpredictable enough that most pilots find shield generators to be
|
||||||
|
well worth the space they take up.
|
||||||
|
"""
|
||||||
|
|
||||||
space.outfit = 5
|
space.outfit = 5
|
||||||
shield.generation = 10
|
shield.generation = 10
|
||||||
shield.strength = 500
|
shield.strength = 500
|
||||||
|
@ -24,6 +41,13 @@ shield.delay = 2.0
|
||||||
thumbnail = "icon::blaster"
|
thumbnail = "icon::blaster"
|
||||||
name = "Blaster"
|
name = "Blaster"
|
||||||
|
|
||||||
|
desc = """
|
||||||
|
Although not the most accurate or damaging of weapons, the Energy Blaster is popular because it
|
||||||
|
is small enough to be installed on even the tiniest of ships. One blaster is not enough to do
|
||||||
|
appreciable damage to anything larger than a fighter, but a ship equipped with several of them
|
||||||
|
becomes a force to be reckoned with.
|
||||||
|
"""
|
||||||
|
|
||||||
space.weapon = 10
|
space.weapon = 10
|
||||||
|
|
||||||
# Average delay between shots
|
# Average delay between shots
|
||||||
|
|
|
@ -57,8 +57,8 @@ fn init(state) {
|
||||||
(radar_size / 2.0 + 5),
|
(radar_size / 2.0 + 5),
|
||||||
(radar_size / -2.0 - 5),
|
(radar_size / -2.0 - 5),
|
||||||
3.5, 3.5,
|
3.5, 3.5,
|
||||||
Anchor::Center,
|
Anchor::NorthWest,
|
||||||
Anchor::NorthWest
|
Anchor::Center
|
||||||
);
|
);
|
||||||
|
|
||||||
sprite::add("radar.frame.ne", "ui::radarframe", init_pos);
|
sprite::add("radar.frame.ne", "ui::radarframe", init_pos);
|
||||||
|
@ -114,12 +114,12 @@ fn event(state, event) {
|
||||||
|
|
||||||
fn step(state) {
|
fn step(state) {
|
||||||
radialbar::set_val("shield",
|
radialbar::set_val("shield",
|
||||||
state.player_ship().get_shields()
|
state.player_ship().current_shields()
|
||||||
/ state.player_ship().get_total_shields()
|
/ state.player_ship().stat_shield_strength()
|
||||||
);
|
);
|
||||||
radialbar::set_val("hull",
|
radialbar::set_val("hull",
|
||||||
state.player_ship().get_hull()
|
state.player_ship().current_hull()
|
||||||
/ state.player_ship().get_total_hull()
|
/ state.player_ship().total_hull()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@ -138,8 +138,8 @@ fn step(state) {
|
||||||
Rect(
|
Rect(
|
||||||
pos.x(), pos.y(),
|
pos.x(), pos.y(),
|
||||||
5.0, 5.0,
|
5.0, 5.0,
|
||||||
Anchor::Center,
|
Anchor::NorthWest,
|
||||||
Anchor::NorthWest
|
Anchor::Center
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
sprite::set_angle("radar.arrow", angle - 90.0);
|
sprite::set_angle("radar.arrow", angle - 90.0);
|
||||||
|
@ -201,8 +201,8 @@ fn step(state) {
|
||||||
Rect(
|
Rect(
|
||||||
pos.x(), pos.y(),
|
pos.x(), pos.y(),
|
||||||
size, size,
|
size, size,
|
||||||
Anchor::Center,
|
Anchor::NorthWest,
|
||||||
Anchor::NorthWest
|
Anchor::Center
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -211,8 +211,8 @@ fn step(state) {
|
||||||
Rect(
|
Rect(
|
||||||
pos.x(), pos.y(),
|
pos.x(), pos.y(),
|
||||||
size, size,
|
size, size,
|
||||||
Anchor::Center,
|
Anchor::NorthWest,
|
||||||
Anchor::NorthWest
|
Anchor::Center
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -263,8 +263,8 @@ fn step(state) {
|
||||||
Rect(
|
Rect(
|
||||||
pos.x(), pos.y(),
|
pos.x(), pos.y(),
|
||||||
size, size,
|
size, size,
|
||||||
Anchor::Center,
|
Anchor::NorthWest,
|
||||||
Anchor::NorthWest
|
Anchor::Center
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -273,8 +273,8 @@ fn step(state) {
|
||||||
Rect(
|
Rect(
|
||||||
pos.x(), pos.y(),
|
pos.x(), pos.y(),
|
||||||
size, size,
|
size, size,
|
||||||
Anchor::Center,
|
Anchor::NorthWest,
|
||||||
Anchor::NorthWest
|
Anchor::Center
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -291,8 +291,8 @@ fn step(state) {
|
||||||
(radar_size / 2.0 + 5) - dx,
|
(radar_size / 2.0 + 5) - dx,
|
||||||
(radar_size / -2.0 - 5) + dy,
|
(radar_size / -2.0 - 5) + dy,
|
||||||
3.5, 3.5,
|
3.5, 3.5,
|
||||||
Anchor::Center,
|
Anchor::NorthWest,
|
||||||
Anchor::NorthWest
|
Anchor::Center
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
sprite::set_rect("radar.frame.se",
|
sprite::set_rect("radar.frame.se",
|
||||||
|
@ -300,8 +300,8 @@ fn step(state) {
|
||||||
(radar_size / 2.0 + 5) - dx,
|
(radar_size / 2.0 + 5) - dx,
|
||||||
(radar_size / -2.0 - 5) - dy,
|
(radar_size / -2.0 - 5) - dy,
|
||||||
3.5, 3.5,
|
3.5, 3.5,
|
||||||
Anchor::Center,
|
Anchor::NorthWest,
|
||||||
Anchor::NorthWest
|
Anchor::Center
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
sprite::set_rect("radar.frame.sw",
|
sprite::set_rect("radar.frame.sw",
|
||||||
|
@ -309,8 +309,8 @@ fn step(state) {
|
||||||
(radar_size / 2.0 + 5) + dx,
|
(radar_size / 2.0 + 5) + dx,
|
||||||
(radar_size / -2.0 - 5) - dy,
|
(radar_size / -2.0 - 5) - dy,
|
||||||
3.5, 3.5,
|
3.5, 3.5,
|
||||||
Anchor::Center,
|
Anchor::NorthWest,
|
||||||
Anchor::NorthWest
|
Anchor::Center
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
sprite::set_rect("radar.frame.nw",
|
sprite::set_rect("radar.frame.nw",
|
||||||
|
@ -318,8 +318,8 @@ fn step(state) {
|
||||||
(radar_size / 2.0 + 5) + dx,
|
(radar_size / 2.0 + 5) + dx,
|
||||||
(radar_size / -2.0 - 5) + dy,
|
(radar_size / -2.0 - 5) + dy,
|
||||||
3.5, 3.5,
|
3.5, 3.5,
|
||||||
Anchor::Center,
|
Anchor::NorthWest,
|
||||||
Anchor::NorthWest
|
Anchor::Center
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,8 @@ fn init(state) {
|
||||||
"ui::planet::button",
|
"ui::planet::button",
|
||||||
Rect(
|
Rect(
|
||||||
99.0, 128.0, 73.898, 18.708,
|
99.0, 128.0, 73.898, 18.708,
|
||||||
Anchor::NorthWest,
|
Anchor::Center,
|
||||||
Anchor::Center
|
Anchor::NorthWest
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -23,8 +23,8 @@ fn init(state) {
|
||||||
},
|
},
|
||||||
Rect(
|
Rect(
|
||||||
-180.0, 142.0, 274.0, 135.0,
|
-180.0, 142.0, 274.0, 135.0,
|
||||||
Anchor::NorthWest,
|
Anchor::Center,
|
||||||
Anchor::Center
|
Anchor::NorthWest
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
sprite::set_mask("landscape", "ui::landscapemask");
|
sprite::set_mask("landscape", "ui::landscapemask");
|
||||||
|
@ -40,17 +40,17 @@ fn init(state) {
|
||||||
);
|
);
|
||||||
// If this is not set, the button will
|
// If this is not set, the button will
|
||||||
// not receive events
|
// not receive events
|
||||||
sprite::set_disable_events("frame", true);
|
sprite::disable_events("frame", true);
|
||||||
|
|
||||||
|
|
||||||
textbox::add(
|
textbox::add(
|
||||||
"title", 10.0, 10.0,
|
"title", 10.0, 10.0,
|
||||||
|
Color(1.0, 1.0, 1.0, 1.0),
|
||||||
Rect(
|
Rect(
|
||||||
-70.79, 138.0, 59.867, 10.0,
|
-70.79, 138.0, 59.867, 10.0,
|
||||||
Anchor::NorthWest,
|
Anchor::Center,
|
||||||
Anchor::Center
|
Anchor::NorthWest
|
||||||
),
|
)
|
||||||
Color(1.0, 1.0, 1.0, 1.0)
|
|
||||||
);
|
);
|
||||||
textbox::align_center("title");
|
textbox::align_center("title");
|
||||||
textbox::font_serif("title");
|
textbox::font_serif("title");
|
||||||
|
@ -61,12 +61,12 @@ fn init(state) {
|
||||||
|
|
||||||
textbox::add(
|
textbox::add(
|
||||||
"desc", 7.5, 8.0,
|
"desc", 7.5, 8.0,
|
||||||
|
Color(1.0, 1.0, 1.0, 1.0),
|
||||||
Rect(
|
Rect(
|
||||||
-178.92, -20.3, 343.0, 81.467,
|
-178.92, -20.3, 343.0, 81.467,
|
||||||
Anchor::NorthWest,
|
Anchor::Center,
|
||||||
Anchor::Center
|
Anchor::NorthWest
|
||||||
),
|
)
|
||||||
Color(1.0, 1.0, 1.0, 1.0)
|
|
||||||
);
|
);
|
||||||
textbox::font_sans("desc");
|
textbox::font_sans("desc");
|
||||||
if state.player_ship().is_landed() {
|
if state.player_ship().is_landed() {
|
||||||
|
|
|
@ -3,6 +3,11 @@ fn init(state) {
|
||||||
conf::show_starfield(true);
|
conf::show_starfield(true);
|
||||||
conf::show_phys(false);
|
conf::show_phys(false);
|
||||||
|
|
||||||
|
if !state.player_ship().is_landed() {
|
||||||
|
print("UI error: player isn't landed when initializing outfitter scene");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
sprite::add(
|
sprite::add(
|
||||||
"se_box",
|
"se_box",
|
||||||
"ui::outfitterbox",
|
"ui::outfitterbox",
|
||||||
|
@ -15,12 +20,13 @@ fn init(state) {
|
||||||
|
|
||||||
textbox::add(
|
textbox::add(
|
||||||
"exit_text", 10.0, 10.0,
|
"exit_text", 10.0, 10.0,
|
||||||
|
Color(1.0, 1.0, 1.0, 1.0),
|
||||||
Rect(
|
Rect(
|
||||||
122.71, 48.0, 51.0, 12.0,
|
122.71, 48.0, 51.0, 12.0,
|
||||||
Anchor::NorthWest,
|
Anchor::SouthWest,
|
||||||
Anchor::SouthWest
|
Anchor::NorthWest
|
||||||
),
|
|
||||||
Color(1.0, 1.0, 1.0, 1.0)
|
)
|
||||||
);
|
);
|
||||||
textbox::font_serif("exit_text");
|
textbox::font_serif("exit_text");
|
||||||
textbox::align_center("exit_text");
|
textbox::align_center("exit_text");
|
||||||
|
@ -31,8 +37,8 @@ fn init(state) {
|
||||||
"ui::button",
|
"ui::button",
|
||||||
Rect(
|
Rect(
|
||||||
113.35, 52.0, 69.8, 18.924,
|
113.35, 52.0, 69.8, 18.924,
|
||||||
Anchor::NorthWest,
|
Anchor::SouthWest,
|
||||||
Anchor::SouthWest
|
Anchor::NorthWest
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -53,53 +59,46 @@ fn init(state) {
|
||||||
"icon::gypsum",
|
"icon::gypsum",
|
||||||
Rect(
|
Rect(
|
||||||
111.0, -95.45, 90.0, 90.0,
|
111.0, -95.45, 90.0, 90.0,
|
||||||
Anchor::Center,
|
Anchor::NorthWest,
|
||||||
Anchor::NorthWest
|
Anchor::Center
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
sprite::preserve_aspect("ship_thumb", true);
|
sprite::preserve_aspect("ship_thumb", true);
|
||||||
|
|
||||||
textbox::add(
|
textbox::add(
|
||||||
"ship_name", 10.0, 10.0,
|
"ship_name", 10.0, 10.0,
|
||||||
|
Color(1.0, 1.0, 1.0, 1.0),
|
||||||
Rect(
|
Rect(
|
||||||
111.0, -167.27, 145.0, 10.0,
|
111.0, -167.27, 145.0, 10.0,
|
||||||
Anchor::Center,
|
Anchor::NorthWest,
|
||||||
Anchor::NorthWest
|
Anchor::Center
|
||||||
),
|
)
|
||||||
Color(1.0, 1.0, 1.0, 1.0)
|
|
||||||
);
|
);
|
||||||
textbox::font_serif("ship_name");
|
textbox::font_serif("ship_name");
|
||||||
textbox::align_center("ship_name");
|
textbox::align_center("ship_name");
|
||||||
textbox::set_text("ship_name", "Hyperion");
|
|
||||||
|
|
||||||
textbox::add(
|
textbox::add(
|
||||||
"ship_type", 7.0, 8.5,
|
"ship_type", 7.0, 8.5,
|
||||||
|
Color(0.7, 0.7, 0.7, 1.0),
|
||||||
Rect(
|
Rect(
|
||||||
111.0, -178.0, 145.0, 8.5,
|
111.0, -178.0, 145.0, 8.5,
|
||||||
Anchor::Center,
|
Anchor::NorthWest,
|
||||||
Anchor::NorthWest
|
Anchor::Center
|
||||||
),
|
)
|
||||||
Color(0.7, 0.7, 0.7, 1.0)
|
|
||||||
);
|
);
|
||||||
textbox::font_sans("ship_type");
|
textbox::font_sans("ship_type");
|
||||||
textbox::align_center("ship_type");
|
textbox::align_center("ship_type");
|
||||||
if state.player_ship().is_some() {
|
|
||||||
textbox::set_text("ship_type", state.player_ship().display_name());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
textbox::add(
|
textbox::add(
|
||||||
"ship_stats", 7.0, 8.5,
|
"ship_stats", 7.0, 8.5,
|
||||||
|
Color(1.0, 1.0, 1.0, 1.0),
|
||||||
Rect(
|
Rect(
|
||||||
38.526, -192.332, 144.948, 154.5,
|
38.526, -192.332, 144.948, 154.5,
|
||||||
Anchor::NorthWest,
|
Anchor::NorthWest,
|
||||||
Anchor::NorthWest,
|
Anchor::NorthWest,
|
||||||
),
|
)
|
||||||
Color(1.0, 1.0, 1.0, 1.0)
|
|
||||||
);
|
);
|
||||||
textbox::font_mono("ship_stats");
|
textbox::font_mono("ship_stats");
|
||||||
textbox::set_text("ship_stats", "Earth");
|
|
||||||
|
|
||||||
|
|
||||||
sprite::add(
|
sprite::add(
|
||||||
"outfit_bg",
|
"outfit_bg",
|
||||||
|
@ -116,8 +115,8 @@ fn init(state) {
|
||||||
"icon::engine",
|
"icon::engine",
|
||||||
Rect(
|
Rect(
|
||||||
-166.0, -109.0, 90.0, 90.0,
|
-166.0, -109.0, 90.0, 90.0,
|
||||||
Anchor::Center,
|
Anchor::NorthEast,
|
||||||
Anchor::NorthEast
|
Anchor::Center
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
sprite::preserve_aspect("outfit_thumb", true);
|
sprite::preserve_aspect("outfit_thumb", true);
|
||||||
|
@ -125,139 +124,258 @@ fn init(state) {
|
||||||
|
|
||||||
textbox::add(
|
textbox::add(
|
||||||
"outfit_name", 16.0, 16.0,
|
"outfit_name", 16.0, 16.0,
|
||||||
|
Color(1.0, 1.0, 1.0, 1.0),
|
||||||
Rect(
|
Rect(
|
||||||
-312.0, -20.0, 200.0, 16.0,
|
-312.0, -20.0, 200.0, 16.0,
|
||||||
Anchor::NorthWest,
|
|
||||||
Anchor::NorthEast,
|
Anchor::NorthEast,
|
||||||
),
|
Anchor::NorthWest
|
||||||
Color(1.0, 1.0, 1.0, 1.0)
|
)
|
||||||
);
|
);
|
||||||
textbox::font_serif("outfit_name");
|
textbox::font_serif("outfit_name");
|
||||||
textbox::weight_bold("outfit_name");
|
textbox::weight_bold("outfit_name");
|
||||||
textbox::set_text("outfit_name", "Earth");
|
textbox::set_text("outfit_name", "");
|
||||||
|
|
||||||
textbox::add(
|
textbox::add(
|
||||||
"outfit_desc", 7.0, 8.5,
|
"outfit_desc", 8.5, 9.0,
|
||||||
|
Color(1.0, 1.0, 1.0, 1.0),
|
||||||
Rect(
|
Rect(
|
||||||
-166.0, -219.0, 260.0, 78.0,
|
-166.0, -219.0, 260.0, 78.0,
|
||||||
Anchor::Center,
|
|
||||||
Anchor::NorthEast,
|
Anchor::NorthEast,
|
||||||
),
|
Anchor::Center
|
||||||
Color(1.0, 1.0, 1.0, 1.0)
|
)
|
||||||
);
|
);
|
||||||
textbox::font_serif("outfit_desc");
|
textbox::font_serif("outfit_desc");
|
||||||
textbox::set_text("outfit_desc", "Earth");
|
textbox::set_text("outfit_desc", "");
|
||||||
|
|
||||||
|
|
||||||
textbox::add(
|
textbox::add(
|
||||||
"outfit_stats", 7.0, 8.5,
|
"outfit_stats", 8.5, 9.0,
|
||||||
|
Color(1.0, 1.0, 1.0, 1.0),
|
||||||
Rect(
|
Rect(
|
||||||
-295.0, -271.0, 164.0, 216.0,
|
-295.0, -271.0, 164.0, 216.0,
|
||||||
Anchor::NorthWest,
|
|
||||||
Anchor::NorthEast,
|
Anchor::NorthEast,
|
||||||
),
|
Anchor::NorthWest
|
||||||
Color(1.0, 1.0, 1.0, 1.0)
|
)
|
||||||
);
|
);
|
||||||
textbox::font_mono("outfit_stats");
|
textbox::font_mono("outfit_stats");
|
||||||
textbox::set_text("outfit_stats", "Earth");
|
textbox::set_text("outfit_stats", "");
|
||||||
|
|
||||||
|
|
||||||
// width should be calculated as a fraction of screen width
|
sprite::add(
|
||||||
let scrollbox_rect = Rect(
|
"buy_button",
|
||||||
222.0, -16.0, 470.0, 480.0,
|
"ui::button",
|
||||||
Anchor::NorthWest,
|
Rect(
|
||||||
Anchor::NorthWest,
|
-110.71, -281.0, 69.8, 18.924,
|
||||||
|
Anchor::NorthEast,
|
||||||
|
Anchor::NorthWest
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
scrollbox::add("outfit_list", scrollbox_rect);
|
textbox::add(
|
||||||
|
"buy_text", 10.0, 10.0,
|
||||||
|
Color(1.0, 1.0, 1.0, 1.0),
|
||||||
|
Rect(
|
||||||
|
-100.84, -285.34, 51.0, 12.0,
|
||||||
|
Anchor::NorthEast,
|
||||||
|
Anchor::NorthWest
|
||||||
|
|
||||||
|
)
|
||||||
|
);
|
||||||
|
textbox::font_serif("buy_text");
|
||||||
|
textbox::align_center("buy_text");
|
||||||
|
textbox::set_text("buy_text", "Buy");
|
||||||
|
|
||||||
|
sprite::add(
|
||||||
|
"sell_button",
|
||||||
|
"ui::button",
|
||||||
|
Rect(
|
||||||
|
-110.71, -306.2, 69.8, 18.924,
|
||||||
|
Anchor::NorthEast,
|
||||||
|
Anchor::NorthWest
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
textbox::add(
|
||||||
|
"sell_text", 10.0, 10.0,
|
||||||
|
Color(1.0, 1.0, 1.0, 1.0),
|
||||||
|
Rect(
|
||||||
|
-100.84, -311.15, 51.0, 12.0,
|
||||||
|
Anchor::NorthEast,
|
||||||
|
Anchor::NorthWest
|
||||||
|
)
|
||||||
|
);
|
||||||
|
textbox::font_serif("sell_text");
|
||||||
|
textbox::align_center("sell_text");
|
||||||
|
textbox::set_text("sell_text", "Sell");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let times_five = false;
|
||||||
|
let times_ten = false;
|
||||||
|
let times_hundred = false;
|
||||||
|
|
||||||
|
textbox::add(
|
||||||
|
"five_text", 7.5, 7.5,
|
||||||
|
Color(0.5, 0.5, 0.5, 1.0),
|
||||||
|
Rect(
|
||||||
|
-110.71, -331.2, 69.8, 18.924,
|
||||||
|
Anchor::NorthEast,
|
||||||
|
Anchor::NorthWest
|
||||||
|
)
|
||||||
|
);
|
||||||
|
textbox::font_mono("five_text");
|
||||||
|
textbox::set_text("five_text", "[shift] x5");
|
||||||
|
|
||||||
|
textbox::add(
|
||||||
|
"ten_text", 7.5, 7.5,
|
||||||
|
Color(0.5, 0.5, 0.5, 1.0),
|
||||||
|
Rect(
|
||||||
|
-110.71, -341.2, 69.8, 18.924,
|
||||||
|
Anchor::NorthEast,
|
||||||
|
Anchor::NorthWest
|
||||||
|
)
|
||||||
|
);
|
||||||
|
textbox::font_mono("ten_text");
|
||||||
|
textbox::set_text("ten_text", "[ctrl] x10");
|
||||||
|
|
||||||
|
|
||||||
|
textbox::add(
|
||||||
|
"hundred_text", 7.5, 7.5,
|
||||||
|
Color(0.5, 0.5, 0.5, 1.0),
|
||||||
|
Rect(
|
||||||
|
-110.71, -351.2, 69.8, 18.924,
|
||||||
|
Anchor::NorthEast,
|
||||||
|
Anchor::NorthWest
|
||||||
|
)
|
||||||
|
);
|
||||||
|
textbox::font_mono("hundred_text");
|
||||||
|
textbox::set_text("hundred_text", "[alt] x100");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// A string containing the selected outfit's index.
|
||||||
|
// This is always set---if we have an outfitter, we must have at least one outfit.
|
||||||
let selected_outfit = false;
|
let selected_outfit = false;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
|
let scrollbox_width = state.window_size().x() - (190 + 16 + 300 + 16);
|
||||||
|
if scrollbox_width <= 0 {
|
||||||
|
scrollbox_width = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// width should be calculated as a fraction of screen width
|
||||||
|
let scrollbox_rect = Rect(
|
||||||
|
222.0, -16.0, scrollbox_width, 480.0,
|
||||||
|
Anchor::NorthWest,
|
||||||
|
Anchor::NorthWest
|
||||||
|
);
|
||||||
|
|
||||||
|
scrollbox::add("outfit_list", scrollbox_rect);
|
||||||
|
|
||||||
|
|
||||||
// p cannot be saved in the global scope.
|
// p cannot be saved in the global scope.
|
||||||
let p = state.player_ship();
|
let p = state.player_ship();
|
||||||
if p.is_landed() {
|
let s = "";
|
||||||
let s = "";
|
let x = scrollbox_rect.pos().x() + 45.0;
|
||||||
let x = scrollbox_rect.pos().x() + 45.0;
|
let y = scrollbox_rect.pos().y() - 45.0;
|
||||||
let y = scrollbox_rect.pos().y() - 45.0;
|
for i in p.landed_on().outfitter() {
|
||||||
for xxx in ["1","2","3"] {
|
|
||||||
for i in p.landed_on().outfitter() {
|
|
||||||
s = s + i.display_name() + "\n";
|
|
||||||
|
|
||||||
let thumb_name = "outfit.thumb." + i.index() + xxx;
|
if selected_outfit == false {
|
||||||
let backg_name = "outfit.backg." + i.index() + xxx;
|
selected_outfit = i.index();
|
||||||
let title_name = "outfit.title." + i.index() + xxx;
|
update_outfit_info(selected_outfit);
|
||||||
|
|
||||||
sprite::add(
|
|
||||||
backg_name,
|
|
||||||
"ui::outfitbg",
|
|
||||||
Rect(
|
|
||||||
x, y, 90.0, 90.0,
|
|
||||||
Anchor::Center,
|
|
||||||
Anchor::NorthWest
|
|
||||||
)
|
|
||||||
);
|
|
||||||
sprite::preserve_aspect(backg_name, true);
|
|
||||||
scrollbox::add_element("outfit_list", backg_name);
|
|
||||||
|
|
||||||
sprite::add(
|
|
||||||
thumb_name,
|
|
||||||
i.thumbnail(),
|
|
||||||
Rect(
|
|
||||||
x, y, 75.0, 75.0,
|
|
||||||
Anchor::Center,
|
|
||||||
Anchor::NorthWest
|
|
||||||
)
|
|
||||||
);
|
|
||||||
sprite::preserve_aspect(thumb_name, true);
|
|
||||||
scrollbox::add_element("outfit_list", thumb_name);
|
|
||||||
|
|
||||||
textbox::add(
|
|
||||||
title_name,
|
|
||||||
10.0, 10.0,
|
|
||||||
Rect(
|
|
||||||
x, y - 50.0, 90.0, 10.0,
|
|
||||||
Anchor::Center,
|
|
||||||
Anchor::NorthWest,
|
|
||||||
),
|
|
||||||
Color(1.0, 1.0, 1.0, 1.0)
|
|
||||||
);
|
|
||||||
textbox::font_sans(title_name);
|
|
||||||
textbox::align_center(title_name);
|
|
||||||
textbox::set_text(title_name, i.display_name());
|
|
||||||
scrollbox::add_element("outfit_list", title_name);
|
|
||||||
|
|
||||||
x = x + 120.0;
|
|
||||||
if x > (
|
|
||||||
scrollbox_rect.pos().x() + scrollbox_rect.dim().x() - 45.0
|
|
||||||
) {
|
|
||||||
x = scrollbox_rect.pos().x() + 45.0;
|
|
||||||
y = y - 120.0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s = s + i.display_name() + "\n";
|
||||||
|
|
||||||
|
let thumb_name = "outfit.thumb." + i.index();
|
||||||
|
let backg_name = "outfit.backg." + i.index();
|
||||||
|
let title_name = "outfit.title." + i.index();
|
||||||
|
|
||||||
|
sprite::add(
|
||||||
|
backg_name,
|
||||||
|
"ui::outfitbg",
|
||||||
|
Rect(
|
||||||
|
x, y, 90.0, 90.0,
|
||||||
|
Anchor::NorthWest,
|
||||||
|
Anchor::Center
|
||||||
|
)
|
||||||
|
);
|
||||||
|
sprite::preserve_aspect(backg_name, true);
|
||||||
|
scrollbox::add_element("outfit_list", backg_name);
|
||||||
|
|
||||||
|
sprite::add(
|
||||||
|
thumb_name,
|
||||||
|
i.thumbnail(),
|
||||||
|
Rect(
|
||||||
|
x, y, 75.0, 75.0,
|
||||||
|
Anchor::NorthWest,
|
||||||
|
Anchor::Center
|
||||||
|
)
|
||||||
|
);
|
||||||
|
sprite::preserve_aspect(thumb_name, true);
|
||||||
|
scrollbox::add_element("outfit_list", thumb_name);
|
||||||
|
|
||||||
|
textbox::add(
|
||||||
|
title_name,
|
||||||
|
10.0, 10.0,
|
||||||
|
Color(1.0, 1.0, 1.0, 1.0),
|
||||||
|
Rect(
|
||||||
|
x, y - 50.0, 90.0, 10.0,
|
||||||
|
Anchor::NorthWest,
|
||||||
|
Anchor::Center
|
||||||
|
)
|
||||||
|
);
|
||||||
|
textbox::font_sans(title_name);
|
||||||
|
textbox::align_center(title_name);
|
||||||
|
textbox::set_text(title_name, i.display_name());
|
||||||
|
scrollbox::add_element("outfit_list", title_name);
|
||||||
|
|
||||||
|
x = x + 120.0;
|
||||||
|
if x > (
|
||||||
|
scrollbox_rect.pos().x() + scrollbox_rect.dim().x() - 45.0
|
||||||
|
) {
|
||||||
|
x = scrollbox_rect.pos().x() + 45.0;
|
||||||
|
y = y - 120.0;
|
||||||
}
|
}
|
||||||
textbox::set_text("outfit_stats", s);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_ship_info(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn event(state, event) {
|
fn event(state, event) {
|
||||||
if type_of(event) == "MouseHoverEvent" {
|
if type_of(event) == "MouseHoverEvent" {
|
||||||
let element = event.element();
|
let element = event.element();
|
||||||
if element == "exit_button" {
|
|
||||||
|
if (
|
||||||
|
element == "exit_button"
|
||||||
|
|| element == "buy_button"
|
||||||
|
|| element == "sell_button"
|
||||||
|
){
|
||||||
if event.is_enter() {
|
if event.is_enter() {
|
||||||
sprite::jump_to("exit_button", "on:top", 0.1);
|
sprite::jump_to(element, "on:top", 0.1);
|
||||||
} else {
|
} else {
|
||||||
sprite::jump_to("exit_button", "off:top", 0.1);
|
sprite::jump_to(element, "off:top", 0.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if element.starts_with("outfit.backg.") && element != selected_outfit {
|
|
||||||
if event.is_enter() {
|
if element.starts_with("outfit.backg.") {
|
||||||
sprite::jump_to(element, "hover:top", 0.1);
|
if event.element().split("outfit.backg.".len())[1] == selected_outfit {
|
||||||
|
if event.is_enter() {
|
||||||
|
sprite::jump_to(element, "hoverselected:top", 0.1);
|
||||||
|
} else {
|
||||||
|
sprite::jump_to(element, "selected:top", 0.1);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
sprite::jump_to(element, "off:top", 0.1);
|
if event.is_enter() {
|
||||||
|
sprite::jump_to(element, "hover:top", 0.1);
|
||||||
|
} else {
|
||||||
|
sprite::jump_to(element, "off:top", 0.1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,34 +383,51 @@ fn event(state, event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: this occasionally breaks because of sprite ordering.
|
|
||||||
// Clicks go to se_box instead!
|
|
||||||
if type_of(event) == "MouseClickEvent" {
|
if type_of(event) == "MouseClickEvent" {
|
||||||
if !event.is_down() {
|
if !event.is_down() {
|
||||||
return PlayerDirective::None;
|
return PlayerDirective::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
print(event.element());
|
|
||||||
|
|
||||||
|
|
||||||
let element = event.element();
|
let element = event.element();
|
||||||
if element == "exit_button" {
|
if element == "exit_button" {
|
||||||
ui::go_to_scene("landed");
|
ui::go_to_scene("landed");
|
||||||
return PlayerDirective::None;
|
return PlayerDirective::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if element.starts_with("outfit.backg.") && element != selected_outfit {
|
if (
|
||||||
|
element.starts_with("outfit.backg.") &&
|
||||||
|
event.element().split("outfit.backg.".len())[1] != selected_outfit
|
||||||
|
) {
|
||||||
if selected_outfit != false {
|
if selected_outfit != false {
|
||||||
sprite::jump_to(selected_outfit, "off:top", 0.1);
|
sprite::jump_to("outfit.backg." + selected_outfit, "off:top", 0.1);
|
||||||
}
|
}
|
||||||
sprite::jump_to(element, "selected:top", 0.1);
|
/// We can't click on this sprite without first hovering!
|
||||||
selected_outfit = element;
|
sprite::jump_to(element, "hoverselected:top", 0.1);
|
||||||
|
selected_outfit = event.element().split("outfit.backg.".len())[1];
|
||||||
|
update_outfit_info(selected_outfit);
|
||||||
|
|
||||||
return PlayerDirective::None;
|
return PlayerDirective::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if type_of(event) == "KeyboardEvent" {
|
||||||
|
if event.key() == "up" {
|
||||||
|
times_five = event.is_down();
|
||||||
|
}
|
||||||
|
if event.key() == "left" {
|
||||||
|
times_ten = event.is_down();
|
||||||
|
}
|
||||||
|
if event.key() == "right" {
|
||||||
|
times_hundred = event.is_down();
|
||||||
|
}
|
||||||
|
|
||||||
|
update_outfit_box(times_five, times_ten, times_hundred);
|
||||||
|
return PlayerDirective::None;
|
||||||
|
}
|
||||||
|
|
||||||
if type_of(event) == "PlayerShipStateEvent" {
|
if type_of(event) == "PlayerShipStateEvent" {
|
||||||
if !state.player_ship().is_landed() {
|
if !state.player_ship().is_landed() {
|
||||||
ui::go_to_scene("flying");
|
ui::go_to_scene("flying");
|
||||||
|
@ -300,3 +435,142 @@ fn event(state, event) {
|
||||||
return PlayerDirective::None;
|
return PlayerDirective::None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_outfit_box(times_five, times_ten, times_hundred) {
|
||||||
|
let times = 1;
|
||||||
|
|
||||||
|
if times_five {
|
||||||
|
times *= 5;
|
||||||
|
textbox::set_color("five_text", Color(1.0, 1.0, 1.0, 1.0));
|
||||||
|
} else {
|
||||||
|
textbox::set_color("five_text", Color(0.5, 0.5, 0.5, 1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if times_ten {
|
||||||
|
times *= 10;
|
||||||
|
textbox::set_color("ten_text", Color(1.0, 1.0, 1.0, 1.0));
|
||||||
|
} else {
|
||||||
|
textbox::set_color("ten_text", Color(0.5, 0.5, 0.5, 1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if times_hundred {
|
||||||
|
times *= 100;
|
||||||
|
textbox::set_color("hundred_text", Color(1.0, 1.0, 1.0, 1.0));
|
||||||
|
} else {
|
||||||
|
textbox::set_color("hundred_text", Color(0.5, 0.5, 0.5, 1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if times != 1 {
|
||||||
|
textbox::set_text("buy_text", "Buy x" + times);
|
||||||
|
textbox::set_text("sell_text", "Sell x" + times);
|
||||||
|
} else {
|
||||||
|
textbox::set_text("buy_text", "Buy");
|
||||||
|
textbox::set_text("sell_text", "Sell");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_outfit_info(selected_outfit) {
|
||||||
|
let outfit = ct::get_outfit(selected_outfit);
|
||||||
|
if outfit.is_some() {
|
||||||
|
|
||||||
|
let stats = "";
|
||||||
|
let tlen = 20;
|
||||||
|
if outfit.stat_thrust() != 0 {
|
||||||
|
let s = "thrust ";
|
||||||
|
s.pad(tlen, " ");
|
||||||
|
stats += s + outfit.stat_thrust();
|
||||||
|
stats += "\n";
|
||||||
|
}
|
||||||
|
if outfit.stat_steer_power() != 0 {
|
||||||
|
let s = "steer power ";
|
||||||
|
s.pad(tlen, " ");
|
||||||
|
stats += s + outfit.stat_steer_power();
|
||||||
|
stats += "\n";
|
||||||
|
}
|
||||||
|
if outfit.stat_shield_strength() != 0 {
|
||||||
|
let s = "shield strength ";
|
||||||
|
s.pad(tlen, " ");
|
||||||
|
stats += s + outfit.stat_shield_strength();
|
||||||
|
stats += "\n";
|
||||||
|
}
|
||||||
|
if outfit.stat_shield_generation() != 0 {
|
||||||
|
let s = "shield regen";
|
||||||
|
s.pad(tlen, " ");
|
||||||
|
stats += s + outfit.stat_shield_generation();
|
||||||
|
stats += "\n";
|
||||||
|
}
|
||||||
|
if outfit.stat_shield_delay() != 0 {
|
||||||
|
let s = "shield delay ";
|
||||||
|
s.pad(tlen, " ");
|
||||||
|
stats += s + outfit.stat_shield_delay();
|
||||||
|
stats += "\n";
|
||||||
|
}
|
||||||
|
if outfit.stat_shield_dps() != 0 {
|
||||||
|
let s = "shield dps ";
|
||||||
|
s.pad(tlen, " ");
|
||||||
|
stats += s + outfit.stat_shield_dps();
|
||||||
|
stats += "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sprite::set_sprite("outfit_thumb", outfit.thumbnail());
|
||||||
|
textbox::set_text("outfit_name", outfit.display_name());
|
||||||
|
textbox::set_text("outfit_desc", outfit.desc());
|
||||||
|
textbox::set_text("outfit_stats", stats);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_ship_info(state) {
|
||||||
|
let ship = state.player_ship();
|
||||||
|
if ship.is_some() {
|
||||||
|
|
||||||
|
let stats = "";
|
||||||
|
let tlen = 20;
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: outfits add mass
|
||||||
|
// TODO: calculate radial acceleration
|
||||||
|
{
|
||||||
|
let s = "shield strength ";
|
||||||
|
s.pad(tlen, " ");
|
||||||
|
stats += s + ship.stat_shield_strength();
|
||||||
|
stats += "\n";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let s = "hull strength ";
|
||||||
|
s.pad(tlen, " ");
|
||||||
|
stats += s + ship.total_hull();
|
||||||
|
stats += "\n\n";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let s = "mass ";
|
||||||
|
s.pad(tlen, " ");
|
||||||
|
stats += s + ship.empty_mass();
|
||||||
|
stats += "\n";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let s = "thrust ";
|
||||||
|
s.pad(tlen, " ");
|
||||||
|
stats += s + ship.stat_thrust();
|
||||||
|
stats += "\n";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let s = "steer power ";
|
||||||
|
s.pad(tlen, " ");
|
||||||
|
stats += s + ship.stat_steer_power();
|
||||||
|
stats += "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let s = "max shield regen";
|
||||||
|
s.pad(tlen, " ");
|
||||||
|
stats += s + ship.stat_max_shield_generation();
|
||||||
|
stats += "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sprite::set_sprite("ship_thumb", ship.thumbnail());
|
||||||
|
textbox::set_text("ship_name", "Hyperion");
|
||||||
|
textbox::set_text("ship_type", state.player_ship().display_name());
|
||||||
|
textbox::set_text("ship_stats", stats);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -137,7 +137,7 @@ impl From<ImmutableString> for ContentIndex {
|
||||||
|
|
||||||
impl From<ContentIndex> for ImmutableString {
|
impl From<ContentIndex> for ImmutableString {
|
||||||
fn from(value: ContentIndex) -> Self {
|
fn from(value: ContentIndex) -> Self {
|
||||||
ImmutableString::from(Arc::into_inner(value.0).unwrap())
|
ImmutableString::from(value.0.as_ref().clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ pub(crate) mod system;
|
||||||
pub use config::Config;
|
pub use config::Config;
|
||||||
pub use effect::*;
|
pub use effect::*;
|
||||||
pub use faction::{Faction, Relationship};
|
pub use faction::{Faction, Relationship};
|
||||||
pub use outfit::{Gun, Outfit, Projectile, ProjectileCollider};
|
pub use outfit::*;
|
||||||
pub use outfitspace::OutfitSpace;
|
pub use outfitspace::OutfitSpace;
|
||||||
pub use ship::{
|
pub use ship::{
|
||||||
CollapseEffectSpawner, CollapseEvent, EffectCollapseEvent, EnginePoint, GunPoint, Ship,
|
CollapseEffectSpawner, CollapseEvent, EffectCollapseEvent, EnginePoint, GunPoint, Ship,
|
||||||
|
|
|
@ -23,6 +23,7 @@ pub(crate) mod syntax {
|
||||||
pub struct Outfit {
|
pub struct Outfit {
|
||||||
pub thumbnail: ContentIndex,
|
pub thumbnail: ContentIndex,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
pub desc: String,
|
||||||
pub engine: Option<Engine>,
|
pub engine: Option<Engine>,
|
||||||
pub steering: Option<Steering>,
|
pub steering: Option<Steering>,
|
||||||
pub space: outfitspace::syntax::OutfitSpace,
|
pub space: outfitspace::syntax::OutfitSpace,
|
||||||
|
@ -145,15 +146,12 @@ pub struct Outfit {
|
||||||
/// The name of this outfit
|
/// The name of this outfit
|
||||||
pub display_name: String,
|
pub display_name: String,
|
||||||
|
|
||||||
|
/// The description of this outfit
|
||||||
|
pub desc: String,
|
||||||
|
|
||||||
/// Thie outfit's index
|
/// Thie outfit's index
|
||||||
pub index: ContentIndex,
|
pub index: ContentIndex,
|
||||||
|
|
||||||
/// How much engine thrust this outfit produces
|
|
||||||
pub engine_thrust: f32,
|
|
||||||
|
|
||||||
/// How much steering power this outfit provids
|
|
||||||
pub steer_power: f32,
|
|
||||||
|
|
||||||
/// The engine flare sprite this outfit creates.
|
/// The engine flare sprite this outfit creates.
|
||||||
/// Its location and size is determined by a ship's
|
/// Its location and size is determined by a ship's
|
||||||
/// engine points.
|
/// engine points.
|
||||||
|
@ -165,6 +163,23 @@ pub struct Outfit {
|
||||||
/// Jump to this edge when engines turn off
|
/// Jump to this edge when engines turn off
|
||||||
pub engine_flare_on_stop: Option<SectionEdge>,
|
pub engine_flare_on_stop: Option<SectionEdge>,
|
||||||
|
|
||||||
|
/// This outfit's gun stats.
|
||||||
|
/// If this is some, this outfit requires a gun point.
|
||||||
|
pub gun: Option<Gun>,
|
||||||
|
|
||||||
|
/// The stats this outfit provides
|
||||||
|
pub stats: OutfitStats,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Outfit statistics
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct OutfitStats {
|
||||||
|
/// How much engine thrust this outfit produces
|
||||||
|
pub engine_thrust: f32,
|
||||||
|
|
||||||
|
/// How much steering power this outfit provids
|
||||||
|
pub steer_power: f32,
|
||||||
|
|
||||||
/// Shield hit points
|
/// Shield hit points
|
||||||
pub shield_strength: f32,
|
pub shield_strength: f32,
|
||||||
|
|
||||||
|
@ -173,10 +188,37 @@ pub struct Outfit {
|
||||||
|
|
||||||
/// Wait this many seconds after taking damage before regenerating shields
|
/// Wait this many seconds after taking damage before regenerating shields
|
||||||
pub shield_delay: f32,
|
pub shield_delay: f32,
|
||||||
|
}
|
||||||
|
|
||||||
/// This outfit's gun stats.
|
impl OutfitStats {
|
||||||
/// If this is some, this outfit requires a gun point.
|
/// Create a new `OutfitStats`, with all values set to zero.
|
||||||
pub gun: Option<Gun>,
|
pub fn zero() -> Self {
|
||||||
|
Self {
|
||||||
|
engine_thrust: 0.0,
|
||||||
|
steer_power: 0.0,
|
||||||
|
shield_strength: 0.0,
|
||||||
|
shield_generation: 0.0,
|
||||||
|
shield_delay: 0.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add all the stats in `other` to the stats in `self`.
|
||||||
|
/// Sheld delay is not affected.
|
||||||
|
pub fn add(&mut self, other: &Self) {
|
||||||
|
self.engine_thrust += other.engine_thrust;
|
||||||
|
self.steer_power += other.steer_power;
|
||||||
|
self.shield_strength += other.shield_strength;
|
||||||
|
self.shield_generation += other.shield_generation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Subtract all the stats in `other` from the stats in `self`.
|
||||||
|
/// Sheld delay is not affected.
|
||||||
|
pub fn subtract(&mut self, other: &Self) {
|
||||||
|
self.engine_thrust -= other.engine_thrust;
|
||||||
|
self.steer_power -= other.steer_power;
|
||||||
|
self.shield_strength -= other.shield_strength;
|
||||||
|
self.shield_generation -= other.shield_generation;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Defines a projectile's collider
|
/// Defines a projectile's collider
|
||||||
|
@ -284,15 +326,12 @@ impl crate::Build for Outfit {
|
||||||
display_name: outfit.name,
|
display_name: outfit.name,
|
||||||
thumbnail,
|
thumbnail,
|
||||||
gun,
|
gun,
|
||||||
engine_thrust: 0.0,
|
desc: outfit.desc,
|
||||||
steer_power: 0.0,
|
|
||||||
engine_flare_sprite: None,
|
engine_flare_sprite: None,
|
||||||
engine_flare_on_start: None,
|
engine_flare_on_start: None,
|
||||||
engine_flare_on_stop: None,
|
engine_flare_on_stop: None,
|
||||||
space: OutfitSpace::from(outfit.space),
|
space: OutfitSpace::from(outfit.space),
|
||||||
shield_delay: 0.0,
|
stats: OutfitStats::zero(),
|
||||||
shield_generation: 0.0,
|
|
||||||
shield_strength: 0.0,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Engine stats
|
// Engine stats
|
||||||
|
@ -307,7 +346,7 @@ impl crate::Build for Outfit {
|
||||||
}
|
}
|
||||||
Some(t) => t.clone(),
|
Some(t) => t.clone(),
|
||||||
};
|
};
|
||||||
o.engine_thrust = engine.thrust;
|
o.stats.engine_thrust = engine.thrust;
|
||||||
o.engine_flare_sprite = Some(sprite.clone());
|
o.engine_flare_sprite = Some(sprite.clone());
|
||||||
|
|
||||||
// Flare animation will traverse this edge when the player presses the thrust key
|
// Flare animation will traverse this edge when the player presses the thrust key
|
||||||
|
@ -381,14 +420,14 @@ impl crate::Build for Outfit {
|
||||||
|
|
||||||
// Steering stats
|
// Steering stats
|
||||||
if let Some(steer) = outfit.steering {
|
if let Some(steer) = outfit.steering {
|
||||||
o.steer_power = steer.power;
|
o.stats.steer_power = steer.power;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shield stats
|
// Shield stats
|
||||||
if let Some(shield) = outfit.shield {
|
if let Some(shield) = outfit.shield {
|
||||||
o.shield_delay = shield.delay.unwrap_or(0.0);
|
o.stats.shield_delay = shield.delay.unwrap_or(0.0);
|
||||||
o.shield_generation = shield.generation.unwrap_or(0.0);
|
o.stats.shield_generation = shield.generation.unwrap_or(0.0);
|
||||||
o.shield_strength = shield.strength.unwrap_or(0.0);
|
o.stats.shield_strength = shield.strength.unwrap_or(0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
content.outfits.insert(o.index.clone(), Arc::new(o));
|
content.outfits.insert(o.index.clone(), Arc::new(o));
|
||||||
|
|
|
@ -145,6 +145,7 @@ pub struct LandableSystemObject {
|
||||||
pub image: Arc<Sprite>,
|
pub image: Arc<Sprite>,
|
||||||
|
|
||||||
/// The outfits we can buy here
|
/// The outfits we can buy here
|
||||||
|
/// If this is empty, this landable has no outfitter.
|
||||||
pub outfitter: Vec<Arc<Outfit>>,
|
pub outfitter: Vec<Arc<Outfit>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ use crate::globaluniform::{AtlasArray, AtlasImageLocation};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use bytemuck::Zeroable;
|
use bytemuck::Zeroable;
|
||||||
use galactica_content::Content;
|
use galactica_content::Content;
|
||||||
use galactica_packer::SpriteAtlasImage;
|
|
||||||
use galactica_util::constants::ASSET_CACHE;
|
use galactica_util::constants::ASSET_CACHE;
|
||||||
use image::GenericImageView;
|
use image::GenericImageView;
|
||||||
use log::info;
|
use log::info;
|
||||||
|
@ -72,16 +71,6 @@ impl RawTexture {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Texture {
|
|
||||||
pub index: u32, // Index in texture array
|
|
||||||
pub len: u32, // Number of frames
|
|
||||||
pub frame_duration: f32, // Frames per second
|
|
||||||
pub aspect: f32, // width / height
|
|
||||||
pub repeat: u32, // How to re-play this texture
|
|
||||||
pub location: Vec<SpriteAtlasImage>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct TextureArray {
|
pub struct TextureArray {
|
||||||
pub bind_group: wgpu::BindGroup,
|
pub bind_group: wgpu::BindGroup,
|
||||||
pub bind_group_layout: BindGroupLayout,
|
pub bind_group_layout: BindGroupLayout,
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
use galactica_content::{Content, Outfit};
|
||||||
|
use log::error;
|
||||||
|
use rhai::{CustomType, FnNamespace, FuncRegistration, ImmutableString, Module, TypeBuilder};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub fn build_ct_module(ct_src: Arc<Content>) -> Module {
|
||||||
|
let mut module = Module::new();
|
||||||
|
module.set_id("GalacticaContentModule");
|
||||||
|
|
||||||
|
let ct = ct_src.clone();
|
||||||
|
let _ = FuncRegistration::new("get_outfit")
|
||||||
|
.with_namespace(FnNamespace::Internal)
|
||||||
|
.set_into_module(&mut module, move |outfit_name: ImmutableString| {
|
||||||
|
let outfit = ct.outfits.get(&outfit_name.clone().into());
|
||||||
|
|
||||||
|
match outfit {
|
||||||
|
Some(o) => OutfitState::new(o.clone()),
|
||||||
|
None => {
|
||||||
|
error!("called `ct::get_outfit` with an invalid outfit `{outfit_name:?}`");
|
||||||
|
OutfitState::new_none()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct OutfitState {
|
||||||
|
outfit: Option<Arc<Outfit>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OutfitState {
|
||||||
|
pub fn new(outfit: Arc<Outfit>) -> Self {
|
||||||
|
Self {
|
||||||
|
outfit: Some(outfit),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_none() -> Self {
|
||||||
|
Self { outfit: None }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CustomType for OutfitState {
|
||||||
|
fn build(mut builder: TypeBuilder<Self>) {
|
||||||
|
builder
|
||||||
|
.with_name("OutfitState")
|
||||||
|
.with_fn("is_some", |s: &mut Self| s.outfit.is_some())
|
||||||
|
.with_fn("display_name", |s: &mut Self| {
|
||||||
|
s.outfit
|
||||||
|
.as_ref()
|
||||||
|
.map(|x| x.display_name.clone())
|
||||||
|
.unwrap_or("".to_string())
|
||||||
|
})
|
||||||
|
.with_fn("desc", |s: &mut Self| {
|
||||||
|
s.outfit
|
||||||
|
.as_ref()
|
||||||
|
.map(|x| x.desc.clone())
|
||||||
|
.unwrap_or("".to_string())
|
||||||
|
})
|
||||||
|
.with_fn("index", |s: &mut Self| {
|
||||||
|
s.outfit
|
||||||
|
.as_ref()
|
||||||
|
.map(|x| x.index.to_string())
|
||||||
|
.unwrap_or("".to_string())
|
||||||
|
})
|
||||||
|
.with_fn("thumbnail", |s: &mut Self| {
|
||||||
|
s.outfit
|
||||||
|
.as_ref()
|
||||||
|
.map(|x| x.thumbnail.index.to_string())
|
||||||
|
.unwrap_or("".to_string())
|
||||||
|
})
|
||||||
|
//
|
||||||
|
// Stat getters
|
||||||
|
//
|
||||||
|
.with_fn("stat_thrust", |s: &mut Self| {
|
||||||
|
s.outfit
|
||||||
|
.as_ref()
|
||||||
|
.map(|x| x.stats.steer_power)
|
||||||
|
.unwrap_or(0.0)
|
||||||
|
})
|
||||||
|
.with_fn("stat_steer_power", |s: &mut Self| {
|
||||||
|
s.outfit
|
||||||
|
.as_ref()
|
||||||
|
.map(|x| x.stats.steer_power)
|
||||||
|
.unwrap_or(0.0)
|
||||||
|
})
|
||||||
|
.with_fn("stat_shield_strength", |s: &mut Self| {
|
||||||
|
s.outfit
|
||||||
|
.as_ref()
|
||||||
|
.map(|x| x.stats.shield_strength)
|
||||||
|
.unwrap_or(0.0)
|
||||||
|
})
|
||||||
|
.with_fn("stat_shield_generation", |s: &mut Self| {
|
||||||
|
s.outfit
|
||||||
|
.as_ref()
|
||||||
|
.map(|x| x.stats.shield_generation)
|
||||||
|
.unwrap_or(0.0)
|
||||||
|
})
|
||||||
|
.with_fn("stat_shield_delay", |s: &mut Self| {
|
||||||
|
s.outfit
|
||||||
|
.as_ref()
|
||||||
|
.map(|x| x.stats.shield_delay)
|
||||||
|
.unwrap_or(0.0)
|
||||||
|
})
|
||||||
|
.with_fn("stat_shield_dps", |s: &mut Self| {
|
||||||
|
s.outfit
|
||||||
|
.as_ref()
|
||||||
|
.map(|x| {
|
||||||
|
if x.gun.is_some() {
|
||||||
|
(1.0 / x.gun.as_ref().unwrap().rate)
|
||||||
|
* x.gun.as_ref().unwrap().projectile.damage
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or(0.0)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
mod conf;
|
mod conf;
|
||||||
|
mod ct;
|
||||||
mod radialbar;
|
mod radialbar;
|
||||||
mod scrollbox;
|
mod scrollbox;
|
||||||
mod sprite;
|
mod sprite;
|
||||||
|
@ -6,6 +7,7 @@ mod textbox;
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
pub use conf::build_conf_module;
|
pub use conf::build_conf_module;
|
||||||
|
pub use ct::{build_ct_module, OutfitState};
|
||||||
pub use radialbar::build_radialbar_module;
|
pub use radialbar::build_radialbar_module;
|
||||||
pub use scrollbox::build_scrollbox_module;
|
pub use scrollbox::build_scrollbox_module;
|
||||||
pub use sprite::build_sprite_module;
|
pub use sprite::build_sprite_module;
|
||||||
|
|
|
@ -62,6 +62,32 @@ pub fn build_sprite_module(ct_src: Arc<Content>, state_src: Rc<RefCell<UiState>>
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let state = state_src.clone();
|
||||||
|
let ct = ct_src.clone();
|
||||||
|
let _ = FuncRegistration::new("set_sprite")
|
||||||
|
.with_namespace(FnNamespace::Internal)
|
||||||
|
.set_into_module(
|
||||||
|
&mut module,
|
||||||
|
move |name: ImmutableString, sprite: ImmutableString| {
|
||||||
|
let mut ui_state = state.borrow_mut();
|
||||||
|
|
||||||
|
match ui_state.get_mut_by_name(&name) {
|
||||||
|
Some(UiElement::Sprite(x)) => {
|
||||||
|
let m = ct.sprites.get(&sprite.clone().into()).clone();
|
||||||
|
if m.is_none() {
|
||||||
|
error!("called `sprite::set_sprite` with an invalid sprite `{sprite}`");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
x.set_sprite(m.unwrap().clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
error!("called `sprite::set_sprite` on an invalid name `{sprite}`")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
let state = state_src.clone();
|
let state = state_src.clone();
|
||||||
let ct = ct_src.clone();
|
let ct = ct_src.clone();
|
||||||
let _ = FuncRegistration::new("set_mask")
|
let _ = FuncRegistration::new("set_mask")
|
||||||
|
@ -198,6 +224,7 @@ pub fn build_sprite_module(ct_src: Arc<Content>, state_src: Rc<RefCell<UiState>>
|
||||||
e.set_color(x);
|
e.set_color(x);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: fix click collider when preserving aspect
|
||||||
let state = state_src.clone();
|
let state = state_src.clone();
|
||||||
let _ = FuncRegistration::new("preserve_aspect")
|
let _ = FuncRegistration::new("preserve_aspect")
|
||||||
.with_namespace(FnNamespace::Internal)
|
.with_namespace(FnNamespace::Internal)
|
||||||
|
@ -221,8 +248,9 @@ pub fn build_sprite_module(ct_src: Arc<Content>, state_src: Rc<RefCell<UiState>>
|
||||||
e.set_preserve_aspect(x);
|
e.set_preserve_aspect(x);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: maybe remove?
|
||||||
let state = state_src.clone();
|
let state = state_src.clone();
|
||||||
let _ = FuncRegistration::new("set_disable_events")
|
let _ = FuncRegistration::new("disable_events")
|
||||||
.with_namespace(FnNamespace::Internal)
|
.with_namespace(FnNamespace::Internal)
|
||||||
.set_into_module(&mut module, move |name: ImmutableString, x: bool| {
|
.set_into_module(&mut module, move |name: ImmutableString, x: bool| {
|
||||||
let mut ui_state = state.borrow_mut();
|
let mut ui_state = state.borrow_mut();
|
||||||
|
@ -230,13 +258,13 @@ pub fn build_sprite_module(ct_src: Arc<Content>, state_src: Rc<RefCell<UiState>>
|
||||||
Some(UiElement::SubElement { element, .. }) => match &mut **element {
|
Some(UiElement::SubElement { element, .. }) => match &mut **element {
|
||||||
UiElement::Sprite(x) => x,
|
UiElement::Sprite(x) => x,
|
||||||
_ => {
|
_ => {
|
||||||
error!("called `sprite::set_disable_events` on an invalid name `{name}`");
|
error!("called `sprite::disable_events` on an invalid name `{name}`");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some(UiElement::Sprite(x)) => x,
|
Some(UiElement::Sprite(x)) => x,
|
||||||
_ => {
|
_ => {
|
||||||
error!("called `sprite::set_disable_events` on an invalid name `{name}`");
|
error!("called `sprite::disable_events` on an invalid name `{name}`");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,8 +23,8 @@ pub fn build_textbox_module(
|
||||||
move |name: ImmutableString,
|
move |name: ImmutableString,
|
||||||
font_size: f32,
|
font_size: f32,
|
||||||
line_height: f32,
|
line_height: f32,
|
||||||
rect: Rect,
|
color: Color,
|
||||||
color: Color| {
|
rect: Rect| {
|
||||||
let mut ui_state = state.borrow_mut();
|
let mut ui_state = state.borrow_mut();
|
||||||
|
|
||||||
if ui_state.contains_name(&name) {
|
if ui_state.contains_name(&name) {
|
||||||
|
@ -72,6 +72,32 @@ pub fn build_textbox_module(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let state = state_src.clone();
|
||||||
|
let font = font_src.clone();
|
||||||
|
let _ = FuncRegistration::new("set_color")
|
||||||
|
.with_namespace(FnNamespace::Internal)
|
||||||
|
.set_into_module(&mut module, move |name: ImmutableString, color: Color| {
|
||||||
|
let mut ui_state = state.borrow_mut();
|
||||||
|
|
||||||
|
let e = match ui_state.get_mut_by_name(&name) {
|
||||||
|
Some(UiElement::SubElement { element, .. }) => match &mut **element {
|
||||||
|
UiElement::Text(x) => x,
|
||||||
|
_ => {
|
||||||
|
error!("called `textbox::set_color` on an invalid name `{name}`");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
Some(UiElement::Text(x)) => x,
|
||||||
|
_ => {
|
||||||
|
error!("called `textbox::set_color` on an invalid name `{name}`");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
e.set_color(&mut font.borrow_mut(), color);
|
||||||
|
});
|
||||||
|
|
||||||
let state = state_src.clone();
|
let state = state_src.clone();
|
||||||
let font = font_src.clone();
|
let font = font_src.clone();
|
||||||
let _ = FuncRegistration::new("align_left")
|
let _ = FuncRegistration::new("align_left")
|
||||||
|
|
|
@ -10,19 +10,11 @@ pub enum Anchor {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[export_module]
|
#[export_module]
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
pub mod anchor_mod {
|
pub mod anchor_mod {
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
pub const Center: Anchor = Anchor::Center;
|
pub const Center: Anchor = Anchor::Center;
|
||||||
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
pub const NorthWest: Anchor = Anchor::NorthWest;
|
pub const NorthWest: Anchor = Anchor::NorthWest;
|
||||||
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
pub const NorthEast: Anchor = Anchor::NorthEast;
|
pub const NorthEast: Anchor = Anchor::NorthEast;
|
||||||
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
pub const SouthWest: Anchor = Anchor::SouthWest;
|
pub const SouthWest: Anchor = Anchor::SouthWest;
|
||||||
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
pub const SouthEast: Anchor = Anchor::SouthEast;
|
pub const SouthEast: Anchor = Anchor::SouthEast;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ pub struct Rect {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rect {
|
impl Rect {
|
||||||
pub fn new(x: f32, y: f32, w: f32, h: f32, anchor_self: Anchor, anchor_parent: Anchor) -> Self {
|
pub fn new(x: f32, y: f32, w: f32, h: f32, anchor_parent: Anchor, anchor_self: Anchor,) -> Self {
|
||||||
Self {
|
Self {
|
||||||
pos: Point2::new(x, y),
|
pos: Point2::new(x, y),
|
||||||
dim: Vector2::new(w, h),
|
dim: Vector2::new(w, h),
|
||||||
|
|
|
@ -6,6 +6,7 @@ mod state;
|
||||||
|
|
||||||
pub use directive::*;
|
pub use directive::*;
|
||||||
pub use event::*;
|
pub use event::*;
|
||||||
|
pub use functions::OutfitState;
|
||||||
pub use helpers::{anchor::*, color::*, rect::*, vector::*};
|
pub use helpers::{anchor::*, color::*, rect::*, vector::*};
|
||||||
pub use state::*;
|
pub use state::*;
|
||||||
|
|
||||||
|
@ -52,6 +53,7 @@ pub fn register_into_engine(
|
||||||
|
|
||||||
// Modules
|
// Modules
|
||||||
engine.register_static_module("ui", functions::build_ui_module(state_src.clone()).into());
|
engine.register_static_module("ui", functions::build_ui_module(state_src.clone()).into());
|
||||||
|
engine.register_static_module("ct", functions::build_ct_module(ct_src.clone()).into());
|
||||||
engine.register_static_module(
|
engine.register_static_module(
|
||||||
"sprite",
|
"sprite",
|
||||||
functions::build_sprite_module(ct_src.clone(), state_src.clone()).into(),
|
functions::build_sprite_module(ct_src.clone(), state_src.clone()).into(),
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
use galactica_content::{Outfit, Ship, SystemObject};
|
use galactica_content::{Ship, SystemObject};
|
||||||
use galactica_system::{
|
use galactica_system::{
|
||||||
data::{self},
|
data::{self},
|
||||||
phys::{objects::PhysShip, PhysSimShipHandle},
|
phys::{objects::PhysShip, PhysSimShipHandle},
|
||||||
};
|
};
|
||||||
use galactica_util::to_degrees;
|
use galactica_util::to_degrees;
|
||||||
use log::error;
|
use log::error;
|
||||||
|
use nalgebra::Vector2;
|
||||||
use rapier2d::dynamics::RigidBody;
|
use rapier2d::dynamics::RigidBody;
|
||||||
use rhai::{Array, CustomType, Dynamic, ImmutableString, TypeBuilder};
|
use rhai::{Array, CustomType, Dynamic, ImmutableString, TypeBuilder};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use super::{Color, UiVector};
|
use super::{functions::OutfitState, Color, UiVector};
|
||||||
use crate::{RenderInput, RenderState};
|
use crate::{RenderInput, RenderState};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -89,18 +90,16 @@ impl CustomType for ShipState {
|
||||||
.with_fn("content_index", |s: &mut Self| {
|
.with_fn("content_index", |s: &mut Self| {
|
||||||
s.get_content().display_name.clone()
|
s.get_content().display_name.clone()
|
||||||
})
|
})
|
||||||
.with_fn("thumbnail", |s: &mut Self| {
|
.with_fn("thumbnail", |s: &mut Self| -> ImmutableString {
|
||||||
s.get_content().thumbnail.clone()
|
s.get_content().thumbnail.index.clone().into()
|
||||||
})
|
})
|
||||||
.with_fn("landed_on", |s: &mut Self| s.landed_on())
|
.with_fn("landed_on", |s: &mut Self| s.landed_on())
|
||||||
.with_fn("get_shields", |s: &mut Self| {
|
.with_fn("current_shields", |s: &mut Self| {
|
||||||
s.get_ship().get_data().get_shields()
|
s.get_ship().get_data().get_shields()
|
||||||
})
|
})
|
||||||
.with_fn("get_total_shields", |s: &mut Self| {
|
.with_fn("total_hull", |s: &mut Self| s.get_content().hull)
|
||||||
s.get_ship().get_data().get_outfits().get_total_shields()
|
.with_fn("empty_mass", |s: &mut Self| s.get_content().mass)
|
||||||
})
|
.with_fn("current_hull", |s: &mut Self| {
|
||||||
.with_fn("get_total_hull", |s: &mut Self| s.get_content().hull)
|
|
||||||
.with_fn("get_hull", |s: &mut Self| {
|
|
||||||
s.get_ship().get_data().get_hull()
|
s.get_ship().get_data().get_hull()
|
||||||
})
|
})
|
||||||
.with_fn("get_size", |s: &mut Self| s.get_content().size)
|
.with_fn("get_size", |s: &mut Self| s.get_content().size)
|
||||||
|
@ -113,25 +112,37 @@ impl CustomType for ShipState {
|
||||||
let h = s.get_ship().get_data().get_faction();
|
let h = s.get_ship().get_data().get_faction();
|
||||||
let c = h.color;
|
let c = h.color;
|
||||||
Color::new(c[0], c[1], c[2], 1.0)
|
Color::new(c[0], c[1], c[2], 1.0)
|
||||||
});
|
})
|
||||||
}
|
//
|
||||||
}
|
// Stat getters
|
||||||
|
//
|
||||||
#[derive(Debug, Clone)]
|
.with_fn("stat_thrust", |s: &mut Self| {
|
||||||
pub struct OutfitState {
|
s.get_ship()
|
||||||
outfit: Arc<Outfit>,
|
.get_data()
|
||||||
}
|
.get_outfits()
|
||||||
|
.get_stats()
|
||||||
impl OutfitState {}
|
.engine_thrust
|
||||||
|
})
|
||||||
impl CustomType for OutfitState {
|
.with_fn("stat_steer_power", |s: &mut Self| {
|
||||||
fn build(mut builder: TypeBuilder<Self>) {
|
s.get_ship()
|
||||||
builder
|
.get_data()
|
||||||
.with_name("OutfitState")
|
.get_outfits()
|
||||||
.with_fn("display_name", |s: &mut Self| s.outfit.display_name.clone())
|
.get_stats()
|
||||||
.with_fn("index", |s: &mut Self| s.outfit.index.to_string())
|
.steer_power
|
||||||
.with_fn("thumbnail", |s: &mut Self| {
|
})
|
||||||
s.outfit.thumbnail.index.to_string()
|
.with_fn("stat_shield_strength", |s: &mut Self| {
|
||||||
|
s.get_ship()
|
||||||
|
.get_data()
|
||||||
|
.get_outfits()
|
||||||
|
.get_stats()
|
||||||
|
.shield_strength
|
||||||
|
})
|
||||||
|
.with_fn("stat_max_shield_generation", |s: &mut Self| {
|
||||||
|
s.get_ship()
|
||||||
|
.get_data()
|
||||||
|
.get_outfits()
|
||||||
|
.get_stats()
|
||||||
|
.shield_generation
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,7 +164,7 @@ impl SystemObjectState {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.outfitter
|
.outfitter
|
||||||
{
|
{
|
||||||
a.push(Dynamic::from(OutfitState { outfit: o.clone() }));
|
a.push(Dynamic::from(OutfitState::new(o.clone())));
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
@ -234,6 +245,7 @@ impl CustomType for SystemObjectState {
|
||||||
pub struct State {
|
pub struct State {
|
||||||
input: Arc<RenderInput>,
|
input: Arc<RenderInput>,
|
||||||
window_aspect: f32,
|
window_aspect: f32,
|
||||||
|
window_size: Vector2<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove this
|
// TODO: remove this
|
||||||
|
@ -245,6 +257,7 @@ impl State {
|
||||||
Self {
|
Self {
|
||||||
input: input.clone(),
|
input: input.clone(),
|
||||||
window_aspect: state.window_aspect,
|
window_aspect: state.window_aspect,
|
||||||
|
window_size: Vector2::new(state.window_size.width, state.window_size.height),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,6 +297,12 @@ impl CustomType for State {
|
||||||
.with_fn("player_ship", Self::player_ship)
|
.with_fn("player_ship", Self::player_ship)
|
||||||
.with_fn("ships", Self::ships)
|
.with_fn("ships", Self::ships)
|
||||||
.with_fn("objects", Self::objects)
|
.with_fn("objects", Self::objects)
|
||||||
.with_fn("window_aspect", |s: &mut Self| s.window_aspect);
|
.with_fn("window_aspect", |s: &mut Self| s.window_aspect)
|
||||||
|
.with_fn("window_size", |s: &mut Self| {
|
||||||
|
UiVector::new(
|
||||||
|
s.window_size.x as f32 / s.input.ct.config.ui_scale,
|
||||||
|
s.window_size.y as f32 / s.input.ct.config.ui_scale,
|
||||||
|
)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,10 @@ impl UiSprite {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_sprite(&mut self, sprite: Arc<Sprite>) {
|
||||||
|
self.anim = SpriteAutomaton::new(sprite);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_mask(&mut self, mask: Option<Arc<Sprite>>) {
|
pub fn set_mask(&mut self, mask: Option<Arc<Sprite>>) {
|
||||||
self.mask = mask;
|
self.mask = mask;
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,11 @@ impl UiTextBox {
|
||||||
self.reflow(font);
|
self.reflow(font);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_color(&mut self, font: &mut FontSystem, color: api::Color) {
|
||||||
|
self.color = color;
|
||||||
|
self.reflow(font);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_align(&mut self, font: &mut FontSystem, align: Align) {
|
pub fn set_align(&mut self, font: &mut FontSystem, align: Align) {
|
||||||
self.justify = align;
|
self.justify = align;
|
||||||
self.reflow(font);
|
self.reflow(font);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
use galactica_content::{ContentIndex, GunPoint, Outfit, OutfitSpace};
|
use galactica_content::{ContentIndex, GunPoint, Outfit, OutfitSpace, OutfitStats};
|
||||||
|
|
||||||
/// Possible outcomes when adding an outfit
|
/// Possible outcomes when adding an outfit
|
||||||
pub enum OutfitAddResult {
|
pub enum OutfitAddResult {
|
||||||
|
@ -61,12 +61,17 @@ pub struct OutfitSet {
|
||||||
/// if value is Some, this point is taken.
|
/// if value is Some, this point is taken.
|
||||||
gun_points: HashMap<GunPoint, Option<Arc<Outfit>>>,
|
gun_points: HashMap<GunPoint, Option<Arc<Outfit>>>,
|
||||||
|
|
||||||
/// Outfit values
|
/// The combined stats of all outfits in this set.
|
||||||
/// This isn't strictly necessary, but we don't want to
|
/// There are two things to note here:
|
||||||
/// re-compute this on each frame.
|
/// First, shield_delay is always zero. That is handled
|
||||||
engine_thrust: f32,
|
/// seperately, since it is different for every outfit.
|
||||||
steer_power: f32,
|
/// Second, shield_generation represents the MAXIMUM POSSIBLE
|
||||||
shield_strength: f32,
|
/// shield generation, after all delays have expired.
|
||||||
|
///
|
||||||
|
/// Note that this field isn't strictly necessary... we could compute stats
|
||||||
|
/// by iterating over the outfits in this set. We don't want to do this every
|
||||||
|
/// frame, though, so we keep track of the total sum here.
|
||||||
|
stats: OutfitStats,
|
||||||
|
|
||||||
/// All shield generators in this outfit set
|
/// All shield generators in this outfit set
|
||||||
// These can't be summed into one value, since each has a
|
// These can't be summed into one value, since each has a
|
||||||
|
@ -81,10 +86,7 @@ impl OutfitSet {
|
||||||
total_space: available_space,
|
total_space: available_space,
|
||||||
used_space: OutfitSpace::new(),
|
used_space: OutfitSpace::new(),
|
||||||
gun_points: gun_points.iter().map(|x| (x.clone(), None)).collect(),
|
gun_points: gun_points.iter().map(|x| (x.clone(), None)).collect(),
|
||||||
|
stats: OutfitStats::zero(),
|
||||||
engine_thrust: 0.0,
|
|
||||||
steer_power: 0.0,
|
|
||||||
shield_strength: 0.0,
|
|
||||||
shield_generators: Vec::new(),
|
shield_generators: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,13 +113,12 @@ impl OutfitSet {
|
||||||
|
|
||||||
self.used_space += o.space;
|
self.used_space += o.space;
|
||||||
|
|
||||||
self.engine_thrust += o.engine_thrust;
|
self.stats.add(&o.stats);
|
||||||
self.steer_power += o.steer_power;
|
|
||||||
self.shield_strength += o.shield_strength;
|
|
||||||
self.shield_generators.push(ShieldGenerator {
|
self.shield_generators.push(ShieldGenerator {
|
||||||
outfit: o.clone(),
|
outfit: o.clone(),
|
||||||
delay: o.shield_delay,
|
delay: o.stats.shield_delay,
|
||||||
generation: o.shield_generation,
|
generation: o.stats.shield_generation,
|
||||||
});
|
});
|
||||||
|
|
||||||
if self.outfits.contains_key(&o.index) {
|
if self.outfits.contains_key(&o.index) {
|
||||||
|
@ -143,9 +144,7 @@ impl OutfitSet {
|
||||||
|
|
||||||
self.used_space -= o.space;
|
self.used_space -= o.space;
|
||||||
|
|
||||||
self.engine_thrust -= o.engine_thrust;
|
self.stats.subtract(&o.stats);
|
||||||
self.steer_power -= o.steer_power;
|
|
||||||
self.shield_strength -= o.shield_strength;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
// This index will exist, since we checked the hashmap
|
// This index will exist, since we checked the hashmap
|
||||||
|
@ -183,11 +182,6 @@ impl OutfitSet {
|
||||||
self.shield_generators.iter()
|
self.shield_generators.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get maximum possible shield regen
|
|
||||||
pub fn get_max_shield_regen(&self) -> f32 {
|
|
||||||
self.shield_generators.iter().map(|x| x.generation).sum()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the outfit attached to the given gun point
|
/// Get the outfit attached to the given gun point
|
||||||
/// Will panic if this gunpoint is not in this outfit set.
|
/// Will panic if this gunpoint is not in this outfit set.
|
||||||
pub fn get_gun(&self, point: &GunPoint) -> Option<Arc<Outfit>> {
|
pub fn get_gun(&self, point: &GunPoint) -> Option<Arc<Outfit>> {
|
||||||
|
@ -204,18 +198,13 @@ impl OutfitSet {
|
||||||
&self.used_space
|
&self.used_space
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Total foward thrust
|
/// Get the combined stats of all outfits in this set.
|
||||||
pub fn get_engine_thrust(&self) -> f32 {
|
/// There are two things to note here:
|
||||||
self.engine_thrust
|
/// First, shield_delay is always zero. That is handled
|
||||||
}
|
/// seperately, since it is different for every outfit.
|
||||||
|
/// Second, shield_generation represents the MAXIMUM POSSIBLE
|
||||||
/// Total steer power
|
/// shield generation, after all delays have expired.
|
||||||
pub fn get_steer_power(&self) -> f32 {
|
pub fn get_stats(&self) -> &OutfitStats {
|
||||||
self.steer_power
|
&self.stats
|
||||||
}
|
|
||||||
|
|
||||||
/// Total shield strength
|
|
||||||
pub fn get_total_shields(&self) -> f32 {
|
|
||||||
self.shield_strength
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,7 +178,7 @@ impl ShipData {
|
||||||
/// Add an outfit to this ship
|
/// Add an outfit to this ship
|
||||||
pub fn add_outfit(&mut self, o: &Arc<Outfit>) -> super::OutfitAddResult {
|
pub fn add_outfit(&mut self, o: &Arc<Outfit>) -> super::OutfitAddResult {
|
||||||
let r = self.outfits.add(o);
|
let r = self.outfits.add(o);
|
||||||
self.shields = self.outfits.get_total_shields();
|
self.shields = self.outfits.get_stats().shield_strength;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,8 +245,8 @@ impl ShipData {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Regenerate shields
|
// Regenerate shields
|
||||||
if self.shields != self.outfits.get_total_shields() {
|
if self.shields != self.outfits.get_stats().shield_strength {
|
||||||
self.shields = self.outfits.get_total_shields();
|
self.shields = self.outfits.get_stats().shield_strength;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,12 +260,12 @@ impl ShipData {
|
||||||
|
|
||||||
// Regenerate shields
|
// Regenerate shields
|
||||||
let time_since = self.last_hit.elapsed().as_secs_f32();
|
let time_since = self.last_hit.elapsed().as_secs_f32();
|
||||||
if self.shields != self.outfits.get_total_shields() {
|
if self.shields != self.outfits.get_stats().shield_strength {
|
||||||
for g in self.outfits.iter_shield_generators() {
|
for g in self.outfits.iter_shield_generators() {
|
||||||
if time_since >= g.delay {
|
if time_since >= g.delay {
|
||||||
self.shields += g.generation * t;
|
self.shields += g.generation * t;
|
||||||
if self.shields > self.outfits.get_total_shields() {
|
if self.shields > self.outfits.get_stats().shield_strength {
|
||||||
self.shields = self.outfits.get_total_shields();
|
self.shields = self.outfits.get_stats().shield_strength;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -390,21 +390,21 @@ impl PhysShip {
|
||||||
if self.controls.thrust {
|
if self.controls.thrust {
|
||||||
rigid_body.apply_impulse(
|
rigid_body.apply_impulse(
|
||||||
vector![engine_force.x, engine_force.y]
|
vector![engine_force.x, engine_force.y]
|
||||||
* self.data.get_outfits().get_engine_thrust(),
|
* self.data.get_outfits().get_stats().engine_thrust,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.controls.right {
|
if self.controls.right {
|
||||||
rigid_body.apply_torque_impulse(
|
rigid_body.apply_torque_impulse(
|
||||||
self.data.get_outfits().get_steer_power() * -100.0 * res.t,
|
self.data.get_outfits().get_stats().steer_power * -100.0 * res.t,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.controls.left {
|
if self.controls.left {
|
||||||
rigid_body.apply_torque_impulse(
|
rigid_body.apply_torque_impulse(
|
||||||
self.data.get_outfits().get_steer_power() * 100.0 * res.t,
|
self.data.get_outfits().get_stats().steer_power * 100.0 * res.t,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue