Skip to content
Open
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
15 changes: 15 additions & 0 deletions src/features/api/gameData.types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,19 @@ export interface IPlanetCOGCProgram {

type PLANET_COGCPROGRAM_STATUS_TYPE = "ACTIVE" | "ON_STRIKE" | "PLANNED";

export type PLANET_WORKFORCE_LEVEL_TYPE =
| "PIONEER"
| "SETTLER"
| "TECHNICIAN"
| "ENGINEER"
| "SCIENTIST";

export interface IPlanetProductionFee {
category: BUILDING_EXPERTISE_TYPE;
workforce_level: PLANET_WORKFORCE_LEVEL_TYPE;
fee_amount: number;
}

export interface IPlanet {
planet_id: string;
planet_natural_id: string;
Expand All @@ -154,6 +167,8 @@ export interface IPlanet {
resources: IPlanetResource[];
cogc_programs: IPlanetCOGCProgram[];
active_cogc_program_type: PLANET_COGCPROGRAM_TYPE | null;
// optional: not part of the payload until backend support is deployed
production_fees?: IPlanetProductionFee[];
}

export interface IFIOStorageItem {
Expand Down
16 changes: 16 additions & 0 deletions src/features/api/schemas/gameData.schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
IBuilding,
IPlanetResource,
IPlanetCOGCProgram,
IPlanetProductionFee,
IPlanet,
IFIOStorageItem,
IFIOSitePlanetBuildingMaterial,
Expand Down Expand Up @@ -156,6 +157,20 @@ const PLANET_COGCPGROGRAM_STATUS_TYPE_ZOD = z.enum([
"PLANNED",
]);

const PLANET_WORKFORCE_LEVEL_TYPE_ZOD = z.enum([
"PIONEER",
"SETTLER",
"TECHNICIAN",
"ENGINEER",
"SCIENTIST",
]);

const PlanetProductionFeeSchema: z.ZodType<IPlanetProductionFee> = z.object({
category: EXPERTISE_TYPE_ZOD,
workforce_level: PLANET_WORKFORCE_LEVEL_TYPE_ZOD,
fee_amount: z.number(),
});

export const PlanetSchema: z.ZodType<IPlanet> = z.object({
planet_id: z.string().min(32).max(32),
planet_natural_id: z.string(),
Expand All @@ -178,6 +193,7 @@ export const PlanetSchema: z.ZodType<IPlanet> = z.object({
resources: z.array(PlanetResourceSchema),
cogc_programs: z.array(PlanetCOGCProgramSchema),
active_cogc_program_type: PLANET_COGCPROGRAM_TYPE_ZOD.nullable(),
production_fees: z.array(PlanetProductionFeeSchema).optional(),
});

export const PlanetMultiplePayload: z.ZodType<IPlanet[]> =
Expand Down
62 changes: 62 additions & 0 deletions src/features/planning/calculations/productionFeeCalculations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Types & Interfaces
import {
IBuilding,
IPlanetProductionFee,
PLANET_WORKFORCE_LEVEL_TYPE,
} from "@/features/api/gameData.types";

function getWorkforceAmount(
building: IBuilding,
level: PLANET_WORKFORCE_LEVEL_TYPE
): number {
switch (level) {
case "PIONEER":
return building.pioneers;
case "SETTLER":
return building.settlers;
case "TECHNICIAN":
return building.technicians;
case "ENGINEER":
return building.engineers;
case "SCIENTIST":
return building.scientists;
}
}

/**
* Calculates a buildings production fee rate per 24h of runtime as the
* workforce-weighted average of the planets per-tier daily rates for
* the buildings expertise, charged per building following ingame logic
* @author raukk
*
* @export
* @param {IBuilding} building Building Data
* @param {IPlanetProductionFee[] | undefined} fees Planet Fee Data
* @returns {number} Fee Rate per 24h, 0 if unknown
*/
export function calculateProductionFeeRate(
building: IBuilding,
fees: IPlanetProductionFee[] | undefined
): number {
if (!fees || building.expertise === null) return 0;

const workers: number =
building.pioneers +
building.settlers +
building.technicians +
building.engineers +
building.scientists;
if (workers === 0) return 0;

const weighted: number = fees.reduce(
(sum, fee) =>
fee.category === building.expertise
? sum +
getWorkforceAmount(building, fee.workforce_level) *
fee.fee_amount
: sum,
0
);

return weighted / workers;
}
17 changes: 17 additions & 0 deletions src/features/planning/components/PlanOverview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,23 @@
<span class="font-light text-white/50"> ȼ </span>
</td>
</tr>
<tr>
<td>
{{
$t(
"plan.components.overview.table.production_fees"
)
}}
</td>
<td>
{{
formatNumber(
overviewData.dailyProductionFeeCost
)
}}
<span class="font-light text-white/50"> ȼ </span>
</td>
</tr>
<tr>
<td>
{{ $t("plan.components.overview.table.plan_cost") }}
Expand Down
45 changes: 41 additions & 4 deletions src/features/planning/usePlanCalculation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
getVolumeOfAllStorages,
getWeightOfAllStorages,
} from "@/features/planning/calculations/infrastructureCalculations";
import { calculateProductionFeeRate } from "@/features/planning/calculations/productionFeeCalculations";

// Submodule composables
import { usePlanCalculationHandlers } from "@/features/planning/usePlanCalculationHandlers";
Expand Down Expand Up @@ -458,6 +459,17 @@ export async function usePlanCalculation(
"BUY"
);

// government production fee, daily at full utilization
const productionFeeDaily: number =
-1 *
calculateProductionFeeRate(
buildingData,
planetData.production_fees
);
// fees are charged per order, an idle building pays none
const productionFeeDailyCost: number =
activeRecipes.length > 0 ? productionFeeDaily : 0;

// get recipe options
const recipeOptions: IRecipeBuildingOption[] = await Promise.all(
buildingRecipes.map(async (br) => {
Expand Down Expand Up @@ -490,7 +502,8 @@ export async function usePlanCalculation(
dailyIncome * maxDailyRuns -
dailyCost * maxDailyRuns -
constructionCost * -1 * (1 / 180) -
-1 * workforceDailyCost;
-1 * workforceDailyCost -
-1 * productionFeeDaily;

// Recipe option ROI
const roi: number = (constructionCost * -1) / dailyRevenue;
Expand Down Expand Up @@ -631,6 +644,7 @@ export async function usePlanCalculation(
constructionCost: constructionCost,
workforceMaterials: workforceMaterials,
workforceDailyCost: workforceDailyCost,
productionFeeDailyCost: productionFeeDailyCost,
dailyRevenue: 0,
expertise: buildingData.expertise,
};
Expand All @@ -651,6 +665,7 @@ export async function usePlanCalculation(
building.dailyRevenue =
productionRevenue +
workforceDailyCost * building.amount +
productionFeeDailyCost * building.amount +
(1 / 180) * constructionCost;

buildings.push(building);
Expand Down Expand Up @@ -766,10 +781,21 @@ export async function usePlanCalculation(
) *
(1 / 180);

const dailyProductionFeeCost: number =
productionResult.buildings.reduce(
(sum, element) =>
sum + element.productionFeeDailyCost * -1 * element.amount,
0
);

const profit: number =
materialRevenue - materialCost - dailyDegradationCost;
materialRevenue -
materialCost -
dailyDegradationCost -
dailyProductionFeeCost;

const cost: number = materialCost + dailyDegradationCost;
const cost: number =
materialCost + dailyDegradationCost + dailyProductionFeeCost;

// calculate overview
overviewData.value = await calculateOverview(
Expand Down Expand Up @@ -832,6 +858,12 @@ export async function usePlanCalculation(
const dailyDegradationCost: number =
totalProductionConstructionCost / 180;

const dailyProductionFee: number = production.buildings.reduce(
(sum, current) =>
sum + current.productionFeeDailyCost * current.amount,
0
);

const constructionMaterials = await calculateConstructionMaterials(
infrastructure,
production.buildings
Expand All @@ -857,13 +889,17 @@ export async function usePlanCalculation(
);

const profit: number =
dailyProfit - -1 * dailyDegradationCost - -1 * dailyCost;
dailyProfit -
-1 * dailyDegradationCost -
-1 * dailyCost -
-1 * dailyProductionFee;

return {
dailyCost: dailyCost * -1,
dailyProfit: dailyProfit * 1,
totalConstructionCost,
dailyDegradationCost: dailyDegradationCost * -1,
dailyProductionFeeCost: dailyProductionFee * -1,
profit,
roi: totalConstructionCost / profit,
};
Expand All @@ -874,6 +910,7 @@ export async function usePlanCalculation(
dailyProfit: 0,
totalConstructionCost: 0,
dailyDegradationCost: 0,
dailyProductionFeeCost: 0,
profit: 0,
roi: 0,
});
Expand Down
2 changes: 2 additions & 0 deletions src/features/planning/usePlanCalculation.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ export interface IProductionBuilding {
constructionCost: number;
workforceMaterials: IMaterialIOMinimal[];
workforceDailyCost: number;
productionFeeDailyCost: number;
dailyRevenue: number;
expertise: BUILDING_EXPERTISE_TYPE | null;
}
Expand Down Expand Up @@ -306,6 +307,7 @@ export interface IOverviewData {
dailyProfit: number;
totalConstructionCost: number;
dailyDegradationCost: number;
dailyProductionFeeCost: number;
profit: number;
roi: number;
}
1 change: 1 addition & 0 deletions src/locales/en_US/plan.json
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@
"table": {
"daily_cost": "Daily Cost",
"degradation": "Degradation",
"production_fees": "Production Fees",
"plan_cost": "Plan Cost",
"daily_profit": "Daily Profit",
"roi": "ROI",
Expand Down
Loading