Skip to content

Commit a868b4a

Browse files
authored
Merge pull request #99 from makr-code/copilot/sprint-2-4-regionale-marktdynamik
Sprint 2.4: Regional market dynamics — MarketRegion, α-formula pricing, regional events, UI tab
2 parents d15fef6 + 4a9ebb9 commit a868b4a

7 files changed

Lines changed: 938 additions & 10 deletions

File tree

‎api/market.php‎

Lines changed: 135 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,13 @@
1919
$action = $_GET['action'] ?? '';
2020

2121
match ($action) {
22-
'get_prices' => action_get_prices($db, $uid),
23-
'buy' => action_buy($db, $uid),
24-
'sell' => action_sell($db, $uid),
25-
'get_history' => action_get_history($db, $uid),
26-
'get_active_events'=> action_get_active_events($db),
27-
default => json_error('Unknown action: ' . $action, 400),
22+
'get_prices' => action_get_prices($db, $uid),
23+
'get_region_prices' => action_get_region_prices($db, $uid),
24+
'buy' => action_buy($db, $uid),
25+
'sell' => action_sell($db, $uid),
26+
'get_history' => action_get_history($db, $uid),
27+
'get_active_events' => action_get_active_events($db),
28+
default => json_error('Unknown action: ' . $action, 400),
2829
};
2930

3031
// ---------------------------------------------------------------------------
@@ -254,6 +255,134 @@ function action_get_prices(PDO $db, int $uid): never {
254255
json_ok(['prices' => $filter ? ($prices[$filter] ?? []) : array_values($prices)]);
255256
}
256257

258+
// ---------------------------------------------------------------------------
259+
// Regional market constants
260+
// ---------------------------------------------------------------------------
261+
262+
/**
263+
* Pre-defined market regions.
264+
*
265+
* Each region has:
266+
* - transport_cost_mult: surcharge applied on top of the global price formula
267+
* - supply_bias: per-good initial supply multiplier seeded into market_region_quotes
268+
*
269+
* Core Worlds — manufacturing hub; raw-material importer.
270+
* Frontier Sectors — resource-rich frontier; finished-goods importer (+20% surcharge).
271+
*/
272+
const MARKET_REGIONS = [
273+
'core_worlds' => [
274+
'label' => 'Kernwelten',
275+
'transport_cost_mult' => 1.0,
276+
'supply_bias' => [
277+
'metal' => 0.7, 'crystal' => 0.8, 'deuterium' => 0.8, 'rare_earth' => 0.6, 'food' => 0.9,
278+
'steel_alloy' => 1.3, 'focus_crystals' => 1.2, 'reactor_fuel' => 1.1,
279+
'consumer_goods' => 1.4, 'luxury_goods' => 1.3, 'research_kits' => 1.2,
280+
],
281+
],
282+
'frontier_sectors' => [
283+
'label' => 'Grenzgebiete',
284+
'transport_cost_mult' => 1.20,
285+
'supply_bias' => [
286+
'metal' => 1.4, 'crystal' => 1.3, 'deuterium' => 1.2, 'rare_earth' => 1.5, 'food' => 0.7,
287+
'steel_alloy' => 0.7, 'focus_crystals' => 0.6, 'reactor_fuel' => 0.8,
288+
'consumer_goods' => 0.5, 'luxury_goods' => 0.4, 'research_kits' => 0.6,
289+
],
290+
],
291+
];
292+
293+
/**
294+
* Compute the current regional market price for a good.
295+
*
296+
* Regional price = global_price × transport_cost_mult × supply_bias_adj
297+
*
298+
* The supply_bias_adj is derived from the regional supply/demand row in
299+
* market_region_quotes (if present) or estimated from supply_bias defaults.
300+
*
301+
* @param PDO $db
302+
* @param string $goodType
303+
* @param string $regionId 'core_worlds' | 'frontier_sectors'
304+
* @return float
305+
*/
306+
function compute_regional_price(PDO $db, string $goodType, string $regionId): float {
307+
$region = MARKET_REGIONS[$regionId] ?? null;
308+
if (!$region) return compute_price($db, $goodType);
309+
310+
$tcm = (float)$region['transport_cost_mult'];
311+
312+
// Try market_region_quotes for live supply/demand
313+
$stmt = $db->prepare(<<<SQL
314+
SELECT supply, demand, active_events_mult
315+
FROM market_region_quotes
316+
WHERE region_id = ? AND good_type = ?
317+
SQL);
318+
$stmt->execute([$regionId, $goodType]);
319+
$row = $stmt->fetch(PDO::FETCH_ASSOC);
320+
321+
if ($row) {
322+
$supply = max(1.0, (float)$row['supply']);
323+
$demand = max(1.0, (float)$row['demand']);
324+
$mult = pow($demand / $supply, PRICE_ELASTICITY);
325+
$mult = max(PRICE_MULT_MIN, min(PRICE_MULT_MAX * $tcm, $mult));
326+
$evMult = (float)($row['active_events_mult'] ?? 1.0);
327+
$base = BASE_PRICES[$goodType] ?? 10.0;
328+
return round($base * $tcm * $mult * $evMult, 2);
329+
}
330+
331+
// Fallback: scale global price by transport cost and supply_bias estimate
332+
$globalPrice = compute_price($db, $goodType);
333+
$bias = (float)($region['supply_bias'][$goodType] ?? 1.0);
334+
// bias > 1 → surplus → lower price; bias < 1 → scarcity → higher price
335+
$biasAdj = 1.0 / max(0.1, $bias);
336+
return round($globalPrice * $tcm * $biasAdj, 2);
337+
}
338+
339+
/**
340+
* GET market.php?action=get_region_prices[&good_type=X]
341+
*
342+
* Returns current market prices per region (core_worlds, frontier_sectors)
343+
* for all goods, or for a single good if good_type is specified.
344+
*
345+
* Response shape:
346+
* {
347+
* "regions": {
348+
* "core_worlds": {
349+
* "label": "Kernwelten",
350+
* "transport_cost_mult": 1.0,
351+
* "prices": [ { good_type, base_price, price, supply, demand } ]
352+
* },
353+
* "frontier_sectors": { … }
354+
* }
355+
* }
356+
*/
357+
function action_get_region_prices(PDO $db, int $uid): never {
358+
$filter = $_GET['good_type'] ?? null;
359+
$goods = $filter ? [$filter] : array_keys(BASE_PRICES);
360+
361+
if ($filter && !isset(BASE_PRICES[$filter])) {
362+
json_error('Unknown good_type: ' . $filter, 400);
363+
}
364+
365+
$result = [];
366+
foreach (MARKET_REGIONS as $regionId => $regionDef) {
367+
$prices = [];
368+
foreach ($goods as $good) {
369+
$regionalPrice = compute_regional_price($db, $good, $regionId);
370+
$prices[] = [
371+
'good_type' => $good,
372+
'base_price' => BASE_PRICES[$good] ?? 0,
373+
'price' => $regionalPrice,
374+
];
375+
}
376+
$result[$regionId] = [
377+
'label' => $regionDef['label'],
378+
'transport_cost_mult' => $regionDef['transport_cost_mult'],
379+
'prices' => $filter ? ($prices[0] ?? []) : $prices,
380+
];
381+
}
382+
383+
json_ok(['regions' => $result]);
384+
}
385+
257386
/**
258387
* POST market.php?action=buy
259388
* Body: { colony_id, good_type, quantity }

‎docs/technical/ROADMAP.md‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,11 +173,12 @@ Folgende große Arbeitspakete sind abgeschlossen und bilden das Fundament des Pr
173173

174174
---
175175

176-
### 2.4 Regionale Marktdynamik 💡
176+
### 2.4 Regionale Marktdynamik ✅
177177

178178
**Aufgaben:**
179-
- [ ] `MarketRegion` und `MarketQuotes` mit regionaler Preisbildung (α-Formel)
180-
- [ ] Regionale Preisunterschiede im Market-UI anzeigen
179+
- [x] `MarketRegion` und `MarketQuotes` mit regionaler Preisbildung (α-Formel)
180+
- [x] Regionale Preisunterschiede im Market-UI anzeigen
181+
- [x] Marktevents/Regionale Engpässe simulierbar (region-scoped events)
181182

182183
**Aufwand:** ~10h
183184
**Referenz:** `docs/gamedesign/GAMEPLAY_DATA_MODEL.md`

0 commit comments

Comments
 (0)