• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

DaniSomoza / galactic-commander / 15029782185

14 May 2025 07:52PM UTC coverage: 47.664% (-4.4%) from 52.086%
15029782185

Pull #12

github

web-flow
Merge d58e631f3 into a8e301a23
Pull Request #12: [fleets] Explore planets

216 of 930 branches covered (23.23%)

Branch coverage included in aggregate %.

162 of 529 new or added lines in 56 files covered. (30.62%)

10 existing lines in 9 files now uncovered.

1569 of 2815 relevant lines covered (55.74%)

3.43 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

17.2
/packages/game-engine/src/engine/tasks/processStartBuildUnitsTask.ts
1
import {
4✔
2
  ITask,
3
  PENDING_TASK_STATUS,
4
  StartBuildUnitsTaskType,
5
  FinishBuildUnitsTaskType,
6
  FINISH_BUILD_UNITS_TASK_TYPE
7
} from '../../types/ITask'
8
import getTaskModel, { ITaskTypeDocument } from '../../models/TaskModel'
4✔
9
import playerRepository from '../../repositories/playerRepository'
4✔
10
import GameEngineError from '../errors/GameEngineError'
4✔
11
import getSecond from '../../helpers/getSecond'
4✔
12
import checkUnitRequirements from '../units/checkUnitRequirements'
4✔
13
import isHeroAlreadyBuild from '../units/isHeroAlreadyBuild'
4✔
14
import isValidUnitAmount from '../units/isValidUnitAmount'
4✔
15
import computedBonus from '../bonus/computedBonus'
4✔
16
import { UnitTypes } from '../../types/IUnit'
17
import { IBonus } from '../../types/IBonus'
18
import { IPlanet } from '../../types/IPlanet'
19
import getPlayerUnit from '../units/getPlayerUnit'
4✔
20
import getFirstUnitInTheBuildQueue from '../units/getFirstUnitInTheBuildQueue'
4✔
21
import taskRepository from '../../repositories/taskRepository'
4✔
22
import playerUnitsRepository from '../../repositories/playerUnitsRepository'
4✔
23
import createStartBuildUnitsTask from './utils/createStartBuildUnitsTask'
4✔
24
import fleetRepository from '../../repositories/fleetRepository'
4✔
25

26
async function processStartBuildUnitsTask(
27
  task: ITaskTypeDocument<StartBuildUnitsTaskType>,
28
  second: number
29
) {
30
  // TODO: promise all 3 request
31
  // get all the required data from DB
32
  const player = await playerRepository.findPlayerById(task.data.playerId)
×
33

34
  if (!player) {
×
35
    throw new GameEngineError('invalid player')
×
36
  }
37

38
  const planet = player.planets.colonies.find(
×
39
    (playerColony) => playerColony._id.toString() === task.data.planetId
×
40
  )
41

42
  if (!planet) {
×
43
    throw new GameEngineError('invalid planet owner')
×
44
  }
45

46
  const unit = getPlayerUnit(player, task.data.build.unitId, planet)
×
47

48
  if (!unit) {
×
49
    throw new GameEngineError('invalid unit')
×
50
  }
51

52
  if (unit.type === 'TROOP' && !!planet.unitBuild.troops.activeBuild) {
×
53
    throw new GameEngineError('player already building troops in this planet')
×
54
  }
55

56
  if (unit.type === 'SPACESHIP' && !!planet.unitBuild.spaceships.activeBuild) {
×
57
    throw new GameEngineError('player already building spaceships in this planet')
×
58
  }
59

60
  if (unit.type === 'DEFENSE' && !!planet.unitBuild.defenses.activeBuild) {
×
61
    throw new GameEngineError('player already building defenses in this planet')
×
62
  }
63

NEW
64
  const playerUnits = await playerUnitsRepository.findPlayerUnits(player._id.toString())
×
NEW
65
  const playerFleets = await fleetRepository.findFleetsByPlayerId(player._id.toString())
×
66

UNCOV
67
  const buildUnitsType: Record<UnitTypes, keyof IPlanet['unitBuild']> = {
×
68
    TROOP: 'troops',
69
    SPACESHIP: 'spaceships',
70
    DEFENSE: 'defenses'
71
  }
72

73
  const { isUnitAvailable, requirements } = checkUnitRequirements(unit, player)
×
NEW
74
  const isValidAmount = isValidUnitAmount(
×
75
    unit,
76
    task.data.build.amount,
77
    player,
78
    playerUnits,
79
    playerFleets
80
  )
NEW
81
  const isHeroUnitAlreadyBuild = isHeroAlreadyBuild(unit, playerUnits)
×
82

83
  const resourceCost = unit.resourceCost * task.data.build.amount
×
84
  const unitEnergyCost = unit.energyCost || 0
×
85
  const energy = unitEnergyCost * task.data.build.amount
×
86

87
  const hasEnoughResources = planet.resources >= resourceCost
×
88

89
  const checkBuildUnitsQueue =
90
    !isUnitAvailable || !isValidAmount || isHeroUnitAlreadyBuild || !hasEnoughResources
×
91

92
  if (checkBuildUnitsQueue) {
×
93
    const nextBuildUnits = planet.unitBuild[buildUnitsType[unit.type]].queue.shift()
×
94
    const nextUnitInTheQueue = getFirstUnitInTheBuildQueue(player, planet, nextBuildUnits)
×
95

96
    if (nextUnitInTheQueue && nextBuildUnits) {
×
97
      const buildUnitsTask = createStartBuildUnitsTask(
×
98
        task.universeId,
99
        player._id.toString(),
100
        planet._id.toString(),
101
        nextUnitInTheQueue._id.toString(),
102
        nextBuildUnits.amount
103
      )
104

105
      await Promise.all([planet.save(), taskRepository.createStartBuildUnitsTask(buildUnitsTask)])
×
106
    }
107
  }
108

109
  if (!isUnitAvailable) {
×
110
    throw new GameEngineError('unit not available for this player', requirements)
×
111
  }
112

113
  if (!isValidAmount) {
×
114
    throw new GameEngineError('invalid unit amount')
×
115
  }
116

117
  if (isHeroUnitAlreadyBuild) {
×
118
    throw new GameEngineError('invalid unit, hero already build')
×
119
  }
120

121
  if (!hasEnoughResources) {
×
122
    throw new GameEngineError('no resources available', {
×
123
      resourceCost,
124
      planetResources: planet.resources
125
    })
126
  }
127

128
  const buildUnitsBono: Record<UnitTypes, keyof IBonus> = {
×
129
    TROOP: 'TROOPS_TRAINING_BONUS',
130
    SPACESHIP: 'FLEET_BUILDING_BONUS',
131
    DEFENSE: 'DEFENSES_BUILDING_BONUS'
132
  }
133

134
  const buildUnitsBonus = computedBonus(player.perks, buildUnitsBono[unit.type])
×
135
  const duration = task.data.build.amount * unit.buildBaseTime * (100 / buildUnitsBonus)
×
136

137
  const executeTaskAt = getSecond(second + duration)
×
138

139
  // TODO: implement createBaseTask helper function
140
  const finishBuildUnitsTask: ITask<FinishBuildUnitsTaskType> = {
×
141
    type: FINISH_BUILD_UNITS_TASK_TYPE,
142
    universeId: player.universeId,
143
    data: {
144
      playerId: player._id.toString(),
145
      planetId: planet._id.toString(),
146
      build: {
147
        unitId: task.data.build.unitId,
148
        amount: task.data.build.amount,
149
        unitType: unit.type,
150
        duration,
151
        resourceCost,
152
        energy
153
      }
154
    },
155
    status: PENDING_TASK_STATUS,
156
    isCancellable: true,
157
    executeTaskAt,
158
    processedAt: null,
159
    processingDuration: null,
160
    history: [
161
      {
162
        taskStatus: PENDING_TASK_STATUS,
163
        updatedAt: new Date().getTime()
164
      }
165
    ],
166
    errorDetails: null
167
  }
168
  const taskModel = getTaskModel<FinishBuildUnitsTaskType>()
×
169
  const newTask = new taskModel(finishBuildUnitsTask)
×
170

171
  planet.unitBuild[buildUnitsType[unit.type]].activeBuild = {
×
172
    unitId: unit._id.toString(),
173
    unitName: unit.name,
174
    unitType: unit.type,
175
    amount: task.data.build.amount,
176
    taskId: newTask._id.toString(),
177
    executeTaskAt,
178
    energy,
179
    resourceCost
180
  }
181

182
  planet.resources -= resourceCost
×
183

184
  return Promise.all([newTask.save(), planet.save(), player.save()])
×
185
}
186

187
export default processStartBuildUnitsTask
4✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc