Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/components/system_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,6 @@ pub fn World() -> impl IntoView {
Effect::new(move |_| {
let upp = upp.get();
let name = main_world_name.get();
debug!("Building world {name} with UPP {upp}");

// Attempt to parse the UWP string into a world object
let Ok(mut w) = World::from_upp(&name, upp.as_str(), false, true) else {
Expand Down
306 changes: 220 additions & 86 deletions src/components/trade_computer.rs

Large diffs are not rendered by default.

11 changes: 1 addition & 10 deletions src/components/traveller_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,13 +437,11 @@ pub async fn fetch_data_world(sector: &str, hex: &str) -> Result<WorldDataRespon
let encoded_sector = web_sys::js_sys::encode_uri_component(sector);
let url = format!("https://travellermap.com/data/{}/{}", encoded_sector, hex);

debug!("Fetching world data from {url}");
let request = web_sys::Request::new_with_str(&url)?;
let window = web_sys::window().unwrap();
let response_value = JsFuture::from(window.fetch_with_request(&request)).await?;
let response: web_sys::Response = response_value.dyn_into()?;
let json = JsFuture::from(response.json()?).await?;
debug!("Response: {json:?}");
let api_response: WorldDataApiResponse = serde_wasm_bindgen::from_value(json)?;

// Take the first world from the array
Expand Down Expand Up @@ -624,15 +622,13 @@ pub fn WorldSearch(
for (search_name, sector, world_uwp, hex_x, hex_y) in search_results.get() {
if world_name == search_name && sector_name == sector {
let hex_string = format!("{:02}{:02}", hex_x, hex_y);
debug!("Fetching data for {world_name} from sector {sector}, hex {hex_string}");

// Set the name to just the world name
name.set(world_name.to_string());

wasm_bindgen_futures::spawn_local(async move {
match fetch_data_world(&sector, &hex_string).await {
Ok(world_data) => {
debug!("Received world data: {:?}", world_data);
let world_zone = match world_data.zone {
Some(zone) => match zone.as_str() {
"A" => ZoneClassification::Amber,
Expand All @@ -641,7 +637,6 @@ pub fn WorldSearch(
},
None => ZoneClassification::Green,
};
debug!("Setting zone to {:?}", world_zone);
zone.set(world_zone);
uwp.set(world_data.uwp);
}
Expand Down Expand Up @@ -687,16 +682,12 @@ pub fn WorldSearch(
));
}
}
debug!(
"Full search results (len = {}): {world_results:?}",
world_results.len()
);
if world_results.len() > MAX_SEARCH_RESULTS {
// Sort by world name length (shorter names first)
world_results.sort_by(|a, b| a.0.len().cmp(&b.0.len()));
world_results.truncate(MAX_SEARCH_RESULTS);
}
debug!("Truncated search results: {:?}", world_results);

set_search_results.set(world_results);
set_is_loading.set(false);
}
Expand Down
2 changes: 0 additions & 2 deletions src/systems/gas_giant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,8 @@ impl HasSatellites for GasGiant {
};

while self.get_satellite(orbit).is_some() {
debug!("(GasGiant.gen_satellite_orbit) Having to bump orbit up by 1.");
orbit += 1;
}
debug!("(GasGiant.gen_satellite_orbit) Orbit is {orbit}");
orbit
}

Expand Down
2 changes: 0 additions & 2 deletions src/systems/system_tables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1731,7 +1731,6 @@ mod tests {
};

let zone1 = get_zone(&system1.star);
debug!("zone1: {:?} for star {:?}", zone1, system1.star);
assert_eq!(zone1.inside, 0);
assert_eq!(zone1.hot, 7);
assert_eq!(zone1.inner, 12);
Expand All @@ -1749,7 +1748,6 @@ mod tests {
};

let zone2 = get_zone(&system2.star);
debug!("zone2: {:?} for star {:?}", zone2, system2.star);
assert_eq!(zone2.inside, 0);
assert_eq!(zone2.hot, 1);
assert_eq!(zone2.inner, 7);
Expand Down
77 changes: 67 additions & 10 deletions src/trade/available_goods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,14 @@ use crate::trade::TradeClass;
/// Each good maintains a reference to its source trade table entry, allowing
/// access to trade DMs, availability restrictions, and other metadata needed
/// for advanced trade calculations.
///
/// ## Saved Rolls
///
/// To prevent recalculation on every parameter change, the original dice rolls
/// are saved and used to recalculate prices when skills change:
/// - **quantity_roll**: Raw dice total before population modifier and multiplier
/// - **buy_price_roll**: Raw 3d6 roll for buy price calculation
/// - **sell_price_roll**: Raw 3d6 roll for sell price calculation (if applicable)
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
pub struct Good {
/// Name of the good
Expand All @@ -125,6 +133,12 @@ pub struct Good {
pub sell_price_comment: String,
/// Index into the trade table for this good.
pub source_index: i16,
/// Raw dice roll for quantity (before population modifier and multiplier)
pub quantity_roll: i32,
/// Raw 3d6 roll for buy price calculation. None (for never rolled) or Some(previous roll)
pub buy_price_roll: Option<i32>,
/// Raw 3d6 roll for sell price calculation (if applicable)
pub sell_price_roll: Option<i32>,
}

impl Display for Good {
Expand Down Expand Up @@ -312,11 +326,13 @@ impl AvailableGoodsTable {
let dice_count: i32 = entry.quantity.dice as i32;
let multiplier: i32 = entry.quantity.multiplier as i32;

let mut total = 0i32;
// Save the raw dice roll before modifiers
let mut raw_roll = 0i32;
for _ in 0..dice_count {
total += rng.random_range(1..=6);
raw_roll += rng.random_range(1..=6);
}

let mut total = raw_roll;
total += if world_population <= 3 {
-3
} else if world_population >= 9 {
Expand All @@ -339,6 +355,7 @@ impl AvailableGoodsTable {
.find(|g| g.source_index == entry.index)
{
existing.quantity += quantity;
// Note: we keep the original quantity_roll from the first generation
return Ok(());
}

Expand All @@ -353,6 +370,9 @@ impl AvailableGoodsTable {
sell_price: None,
sell_price_comment: String::default(),
source_index: entry.index,
quantity_roll: raw_roll,
buy_price_roll: None, // Will be set when pricing
sell_price_roll: None,
};

self.goods.push(good);
Expand Down Expand Up @@ -386,7 +406,7 @@ impl AvailableGoodsTable {
self.goods.push(good);
}

// Remove the good if the quanity is now <= 0
// Remove the good if the quantity is now <= 0
self.goods.retain(|g| g.quantity > 0);
}

Expand All @@ -405,7 +425,7 @@ impl AvailableGoodsTable {
self.goods.push(good.clone());
}

// Remove the good if the quanity is now <= 0
// Remove the good if the quantity is now <= 0
self.goods.retain(|g| g.quantity > 0);
}

Expand Down Expand Up @@ -566,8 +586,15 @@ impl AvailableGoodsTable {
) {
let mut rng = rand::rng();
for good in &mut self.goods {
// Roll 2d6
let roll = rng.random_range(1..=6) + rng.random_range(1..=6) + rng.random_range(1..=6);
// Roll 3d6 and save it
let roll = match good.buy_price_roll {
Some(roll) => roll,
None => {
let roll = rng.random_range(1..=6) + rng.random_range(1..=6) + rng.random_range(1..=6);
good.buy_price_roll = Some(roll);
roll
}
};

let entry = TradeTable::global()
.get(good.source_index)
Expand All @@ -577,6 +604,7 @@ impl AvailableGoodsTable {
&good.source_index
)
});

let purchase_origin_dm = find_max_dm(&entry.purchase_dm, origin_trade_classes);
let sale_origin_dm = find_max_dm(&entry.sale_dm, origin_trade_classes);
// Calculate the modified roll
Expand Down Expand Up @@ -688,6 +716,14 @@ impl AvailableGoodsTable {
);
}

/// Reset all the stored die rolls to None so that we regenerate all values.
pub fn reset_die_rolls(&mut self) {
for good in &mut self.goods {
good.buy_price_roll = None;
good.sell_price_roll = None;
}
}

/// Calculate selling prices for goods at potential destination worlds
///
/// See description for `price_goods_to_sell`. This version allows
Expand Down Expand Up @@ -737,9 +773,17 @@ impl Good {
mut rng: impl rand::Rng,
) {
if let Some(trade_classes) = trade_classes {
// Roll 3d6
let roll = rng.random_range(1..=6) + rng.random_range(1..=6) + rng.random_range(1..=6);

// Roll 3d6 and save it
debug!("(Good.price_to_sell_rng) Pricing {} with prior roll of {:?} with trade classes {trade_classes:?}", self.name, self.sell_price_roll);
let roll = match self.sell_price_roll {
Some(roll) => roll,
None => {
let roll = rng.random_range(1..=6) + rng.random_range(1..=6) + rng.random_range(1..=6);
self.sell_price_roll = Some(roll);
roll
}
};

let entry = TradeTable::global()
.get(self.source_index)
.unwrap_or_else(|| {
Expand Down Expand Up @@ -801,8 +845,9 @@ impl Good {

self.sell_price = Some((self.base_cost as f64 * price_multiplier).round() as i32);
} else {
debug!("price_to_sell_rng: No trade classes provided, clearing sell price for {}", self.name);
self.sell_price = None;
self.sell_price_comment.clear();
self.sell_price_comment = "NOTHING TO SEE HERE".to_string();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When trade_classes is None, sell_price_comment is set to the literal string "NOTHING TO SEE HERE". This looks like a placeholder that can leak into UI/tooltips and be confusing; it may be better to keep the previous “clear” behavior here.

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎

}
}
}
Expand Down Expand Up @@ -1030,6 +1075,9 @@ mod tests {
sell_price_comment: String::default(),
sell_price: None,
source_index: 11,
quantity_roll: 10,
buy_price_roll: None,
sell_price_roll: None,
};

// Check the display output
Expand Down Expand Up @@ -1099,6 +1147,9 @@ mod tests {
sell_price_comment: String::default(),
sell_price: None,
source_index: 11,
quantity_roll: 10,
buy_price_roll: Some(10),
sell_price_roll: None,
};

let good2 = Good {
Expand All @@ -1111,6 +1162,9 @@ mod tests {
sell_price_comment: String::default(),
sell_price: None,
source_index: 12,
quantity_roll: 10,
buy_price_roll: Some(10),
sell_price_roll: None,
};

let good3 = Good {
Expand All @@ -1123,6 +1177,9 @@ mod tests {
sell_price_comment: String::default(),
sell_price: None,
source_index: 13,
quantity_roll: 10,
buy_price_roll: Some(10),
sell_price_roll: None,
};

// Add goods in random order
Expand Down
Loading