|
@@ -247,24 +247,30 @@ function projectedHappiness(pop: Pop, totalNeeds: Record<Need, number>, siteCoun
|
|
|
'comfort': 0, 'culture': 0, 'education': 0};
|
|
'comfort': 0, 'culture': 0, 'education': 0};
|
|
|
for (const [building, fill] of popiFilled.entries()) {
|
|
for (const [building, fill] of popiFilled.entries()) {
|
|
|
const {max, needs} = POPI[building];
|
|
const {max, needs} = POPI[building];
|
|
|
- for (const {need, satisfaction} of needs) {
|
|
|
|
|
- const provided = fill.numMats / max * fill.tier * satisfaction;
|
|
|
|
|
|
|
+ for (const {need, supplied} of needs) {
|
|
|
|
|
+ const provided = fill.numMats / max * fill.tier * supplied;
|
|
|
totalProvided[need] += provided;
|
|
totalProvided[need] += provided;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ const satisfaction: Map<Need, number> = new Map(); // percentage of needs fulfilled
|
|
|
for (const _need in totalProvided) {
|
|
for (const _need in totalProvided) {
|
|
|
const need = _need as Need;
|
|
const need = _need as Need;
|
|
|
- if (totalProvided[need] > totalNeeds[need])
|
|
|
|
|
- totalProvided[need] = totalNeeds[need];
|
|
|
|
|
|
|
+ satisfaction.set(need, Math.min(totalProvided[need] / totalNeeds[need], 1));
|
|
|
}
|
|
}
|
|
|
|
|
+ const safetyHealthCap = Math.min(satisfaction.get('safety')!, satisfaction.get('health')!);
|
|
|
|
|
+ if (satisfaction.get('comfort')! > safetyHealthCap)
|
|
|
|
|
+ satisfaction.set('comfort', safetyHealthCap);
|
|
|
|
|
+ if (satisfaction.get('culture')! > safetyHealthCap)
|
|
|
|
|
+ satisfaction.set('culture', safetyHealthCap);
|
|
|
|
|
+ const comfortCultureCap = Math.min(satisfaction.get('comfort')!, satisfaction.get('culture')!);
|
|
|
|
|
+ if (satisfaction.get('education')! > comfortCultureCap)
|
|
|
|
|
+ satisfaction.set('education', comfortCultureCap);
|
|
|
|
|
|
|
|
const weights = NEEDS[pop];
|
|
const weights = NEEDS[pop];
|
|
|
let happiness = 1 - Object.values(weights).reduce((sum, weight) => sum + weight, 0); // assume 100% life support
|
|
let happiness = 1 - Object.values(weights).reduce((sum, weight) => sum + weight, 0); // assume 100% life support
|
|
|
- // TODO: caps
|
|
|
|
|
- for (const [_need, provided] of Object.entries(totalProvided)) {
|
|
|
|
|
- const need = _need as Need;
|
|
|
|
|
- happiness += weights[need] * provided / totalNeeds[need];
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ for (const [need, s] of satisfaction.entries())
|
|
|
|
|
+ happiness += weights[need] * s;
|
|
|
return happiness;
|
|
return happiness;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -275,21 +281,21 @@ const NEEDS: Record<Pop, Record<Need, number>> = {
|
|
|
'eng': {'safety': 0.10, 'health': 0.15, 'comfort': 0.35, 'culture': 0.20, 'education': 0.10},
|
|
'eng': {'safety': 0.10, 'health': 0.15, 'comfort': 0.35, 'culture': 0.20, 'education': 0.10},
|
|
|
'sci': {'safety': 0.10, 'health': 0.10, 'comfort': 0.20, 'culture': 0.25, 'education': 0.30},
|
|
'sci': {'safety': 0.10, 'health': 0.10, 'comfort': 0.20, 'culture': 0.25, 'education': 0.30},
|
|
|
}
|
|
}
|
|
|
-const POPI: Record<POPIBuilding, {max: number, needs: {need: Need, satisfaction: number}[]}> = {
|
|
|
|
|
- 'SAFETY_STATION': {max: 3, needs: [{need: 'safety', satisfaction: 2500}]},
|
|
|
|
|
- 'SECURITY_DRONE_POST': {max: 4, needs: [{need: 'safety', satisfaction: 5000}]},
|
|
|
|
|
- 'EMERGENCY_CENTER': {max: 5, needs: [{need: 'safety', satisfaction: 1000}, {need: 'health', satisfaction: 1000}]},
|
|
|
|
|
- 'INFIRMARY': {max: 3, needs: [{need: 'health', satisfaction: 2500}]},
|
|
|
|
|
- 'HOSPITAL': {max: 6, needs: [{need: 'health', satisfaction: 5000}]},
|
|
|
|
|
- 'WELLNESS_CENTER': {max: 6, needs: [{need: 'health', satisfaction: 1000}, {need: 'comfort', satisfaction: 1000}]},
|
|
|
|
|
- 'WILDLIFE_PARK': {max: 5, needs: [{need: 'comfort', satisfaction: 2500}]},
|
|
|
|
|
- 'ARCADES': {max: 6, needs: [{need: 'comfort', satisfaction: 5000}]},
|
|
|
|
|
- 'ART_CAFE': {max: 6, needs: [{need: 'comfort', satisfaction: 1000}, {need: 'culture', satisfaction: 1000}]},
|
|
|
|
|
- 'ART_GALLERY': {max: 4, needs: [{need: 'culture', satisfaction: 2500}]},
|
|
|
|
|
- 'THEATER': {max: 6, needs: [{need: 'culture', satisfaction: 5000}]},
|
|
|
|
|
- 'PLANETARY_BROADCASTING_HUB': {max: 6, needs: [{need: 'culture', satisfaction: 1000}, {need: 'education', satisfaction: 1000}]},
|
|
|
|
|
- 'LIBRARY': {max: 5, needs: [{need: 'education', satisfaction: 2500}]},
|
|
|
|
|
- 'UNIVERSITY': {max: 6, needs: [{need: 'education', satisfaction: 5000}]},
|
|
|
|
|
|
|
+const POPI: Record<POPIBuilding, {max: number, needs: {need: Need, supplied: number}[]}> = {
|
|
|
|
|
+ 'SAFETY_STATION': {max: 3, needs: [{need: 'safety', supplied: 2500}]},
|
|
|
|
|
+ 'SECURITY_DRONE_POST': {max: 4, needs: [{need: 'safety', supplied: 5000}]},
|
|
|
|
|
+ 'EMERGENCY_CENTER': {max: 5, needs: [{need: 'safety', supplied: 1000}, {need: 'health', supplied: 1000}]},
|
|
|
|
|
+ 'INFIRMARY': {max: 3, needs: [{need: 'health', supplied: 2500}]},
|
|
|
|
|
+ 'HOSPITAL': {max: 6, needs: [{need: 'health', supplied: 5000}]},
|
|
|
|
|
+ 'WELLNESS_CENTER': {max: 6, needs: [{need: 'health', supplied: 1000}, {need: 'comfort', supplied: 1000}]},
|
|
|
|
|
+ 'WILDLIFE_PARK': {max: 5, needs: [{need: 'comfort', supplied: 2500}]},
|
|
|
|
|
+ 'ARCADES': {max: 6, needs: [{need: 'comfort', supplied: 5000}]},
|
|
|
|
|
+ 'ART_CAFE': {max: 6, needs: [{need: 'comfort', supplied: 1000}, {need: 'culture', supplied: 1000}]},
|
|
|
|
|
+ 'ART_GALLERY': {max: 4, needs: [{need: 'culture', supplied: 2500}]},
|
|
|
|
|
+ 'THEATER': {max: 6, needs: [{need: 'culture', supplied: 5000}]},
|
|
|
|
|
+ 'PLANETARY_BROADCASTING_HUB': {max: 6, needs: [{need: 'culture', supplied: 1000}, {need: 'education', supplied: 1000}]},
|
|
|
|
|
+ 'LIBRARY': {max: 5, needs: [{need: 'education', supplied: 2500}]},
|
|
|
|
|
+ 'UNIVERSITY': {max: 6, needs: [{need: 'education', supplied: 5000}]},
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
type Pop = 'pio' | 'set' | 'tec' | 'eng' | 'sci';
|
|
type Pop = 'pio' | 'set' | 'tec' | 'eng' | 'sci';
|