Skip to content
Merged

Next #301

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
Original file line number Diff line number Diff line change
Expand Up @@ -84,17 +84,19 @@ function c3UnitWithComponents(id: string, componentFlags: readonly (readonly str
&& !destroyedComponents().has(index)
&& !actionUnavailableComponents().has(index),
isC3Jammed: () => jammed(),
isEquipmentActionUnavailable: (entry: MountedEquipment) => {
canPerformEquipmentAction: (entry: MountedEquipment) => {
const index = inventory.indexOf(entry);
return index >= 0 && actionUnavailableComponents().has(index);
return index < 0 || !destroyedComponents().has(index) && !actionUnavailableComponents().has(index);
},
getEquipmentStatus: (entry: MountedEquipment) => (
destroyedComponents().has(inventory.indexOf(entry)) ? 'destroyed' : 'available'
),
isEquipmentOperational: (entry: MountedEquipment) => {
const index = inventory.indexOf(entry);
return index >= 0 && !destroyedComponents().has(index);
},
rules: {
calculateC3Tax: () => 0,
computeEntryState: (entry: MountedEquipment) => ({
isDamaged: destroyedComponents().has(inventory.indexOf(entry)),
isDisabled: false,
hitMod: 0,
}),
},
} as unknown as CBTForceUnit;
inventory = componentFlags.map((flags, index) => new MountedEquipment({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -944,8 +944,9 @@ export class C3NetworkDialogComponent implements AfterViewInit {
return [...componentIndexes].every(index => {
const component = runtime.capability(node.unit.id)?.component(index);
if (!component) return false;
return component.mount?.isActionUnavailable()
?? !node.unit.isC3EndpointOperational(index, component);
return component.mount
? !component.mount.owner.canPerformEquipmentAction(component.mount, 'configure-network')
: !node.unit.isC3EndpointOperational(index, component);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,17 @@ import { TestBed } from '@angular/core/testing';
import { AmmoEquipment } from '../../models/equipment.model';
import { EquipmentRegistry } from '../../models/equipment-lookup';
import type { CBTForceUnit } from '../../models/cbt-force-unit.model';
import { MountedEquipment } from '../../models/mounted-equipment.model';
import type { CriticalSlot } from '../../models/force-serialization';
import type { HandlerContext } from '../../services/equipment-interaction-registry.service';
import {
createHandlerCommandContext,
type HandlerCommandContext,
type HandlerDialogsService,
type HandlerToastService,
} from '../../services/equipment-interaction-registry.service';
import { AmmoLoadoutPanelComponent, type AmmoLoadoutPanelData } from './ammo-loadout-panel.component';
import type { AmmoControlEntry } from '../../utils/ammo-interaction.util';
import type { EquipmentStatus } from '../../models/equipment-status.model';

function createAmmo(id: string): AmmoEquipment {
return new AmmoEquipment({
Expand All @@ -26,11 +33,15 @@ function createCritEntry(params: {
ammo: AmmoEquipment;
consumed?: number;
destroyed?: boolean;
status?: EquipmentStatus;
owner: Pick<CBTForceUnit, 'id' | 'readOnly' | 'getUnit'>;
}): AmmoControlEntry {
const owner = params.owner as CBTForceUnit;
const isEquipmentUnavailable: CBTForceUnit['isEquipmentUnavailable'] = (source: CriticalSlot) => !!source.destroyed;
owner.isEquipmentUnavailable ??= isEquipmentUnavailable;
owner.getEquipmentStatus ??= source => source instanceof MountedEquipment && source.committedDestroyed()
|| !(source instanceof MountedEquipment) && !!source.destroyed
? 'destroyed'
: 'available';
owner.isEquipmentOperational ??= source => owner.getEquipmentStatus(source) === 'available';
const source = {
id: `${params.ammo.internalName}@${params.loc}#${params.slot}`,
name: params.ammo.internalName,
Expand All @@ -55,7 +66,7 @@ function createCritEntry(params: {
originalTotalAmmo: 5,
totalAmmo: 5,
consumed: params.consumed ?? 0,
destroyed: !!params.destroyed,
status: params.status ?? (params.destroyed ? 'destroyed' : 'available'),
};
}

Expand All @@ -76,6 +87,17 @@ function createToastServiceMock() {
};
}

function createCommandContext(
equipmentCatalog = new EquipmentRegistry({}),
toastService: HandlerToastService = createToastServiceMock(),
): HandlerCommandContext {
const dialogsService = jasmine.createSpyObj<HandlerDialogsService>(
'HandlerDialogsService',
['createDialog', 'showError', 'showNoticeHtml'],
);
return createHandlerCommandContext(equipmentCatalog, toastService, dialogsService);
}

describe('AmmoLoadoutPanelComponent', () => {
function configurePanel(data: AmmoLoadoutPanelData): AmmoLoadoutPanelComponent {
TestBed.configureTestingModule({
Expand Down Expand Up @@ -103,7 +125,7 @@ describe('AmmoLoadoutPanelComponent', () => {
const data: AmmoLoadoutPanelData = {
entries: liveEntries,
getEntries: () => liveEntries,
context: {} as HandlerContext,
context: createCommandContext(),
};
const component = configurePanel(data);

Expand All @@ -120,7 +142,7 @@ describe('AmmoLoadoutPanelComponent', () => {
groups = component.groups();
expect(groups.length).toBe(2);
expect(groups.map(group => group.displayName)).toEqual(['Clan Ultra AC/20 Precision Ammo', 'Clan Ultra AC/20 Ammo']);
expect(groups.map(group => group.destroyed)).toEqual([false, true]);
expect(groups.map(group => group.status)).toEqual(['available', 'destroyed']);
expect(component.groupRemaining(groups[0])).toBe(5);
expect(component.groupRemaining(groups[1])).toBe(0);
});
Expand All @@ -134,7 +156,7 @@ describe('AmmoLoadoutPanelComponent', () => {
} as unknown as Pick<CBTForceUnit, 'id' | 'readOnly' | 'getUnit'>;
const data: AmmoLoadoutPanelData = {
entries: [createCritEntry({ loc: 'LT', slot: 0, ammo: standardAmmo, owner })],
context: {} as HandlerContext,
context: createCommandContext(),
};

TestBed.configureTestingModule({
Expand All @@ -149,6 +171,32 @@ describe('AmmoLoadoutPanelComponent', () => {
expect(fixture.nativeElement.querySelector('.ammo-bin-list')).toBeNull();
});

it('styles a disabled ammo source separately from a destroyed source', () => {
const standardAmmo = createAmmo('Clan Ultra AC/20 Ammo');
const owner = {
id: 'unit-1',
readOnly: () => false,
getUnit: () => ({ techBase: 'Clan' }),
} as unknown as Pick<CBTForceUnit, 'id' | 'readOnly' | 'getUnit'>;
const data: AmmoLoadoutPanelData = {
entries: [createCritEntry({ loc: 'LT', slot: 0, ammo: standardAmmo, owner, status: 'disabled' })],
context: createCommandContext(),
};

TestBed.configureTestingModule({ imports: [AmmoLoadoutPanelComponent] });
const fixture = TestBed.createComponent(AmmoLoadoutPanelComponent);
fixture.componentRef.setInput('data', data);
fixture.detectChanges();

const row = fixture.nativeElement.querySelector('.ammo-control-row') as HTMLElement;
const badge = fixture.nativeElement.querySelector('.ammo-location-badge') as HTMLElement;
expect(row.classList.contains('disabled-entry')).toBeTrue();
expect(row.classList.contains('destroyed-entry')).toBeFalse();
expect(badge.classList.contains('disabled')).toBeTrue();
expect(badge.classList.contains('destroyed')).toBeFalse();
expect(fixture.nativeElement.querySelector('.ammo-control-actions')).toBeNull();
});

it('shows location badges beside the group name', () => {
const standardAmmo = createAmmo('Clan Ultra AC/20 Ammo');
const owner = {
Expand All @@ -174,7 +222,7 @@ describe('AmmoLoadoutPanelComponent', () => {
createCritEntry({ loc: 'RT', slot: 2, ammo: standardAmmo, owner }),
createCritEntry({ loc: 'CT', slot: 3, ammo: standardAmmo, destroyed: true, owner }),
],
context: {} as HandlerContext,
context: createCommandContext(),
};

TestBed.configureTestingModule({
Expand Down Expand Up @@ -216,7 +264,7 @@ describe('AmmoLoadoutPanelComponent', () => {
createCritEntry({ loc: 'RT', slot: 1, ammo: standardAmmo, owner }),
createCritEntry({ loc: 'RT', slot: 2, ammo: standardAmmo, destroyed: true, owner }),
],
context: {} as HandlerContext,
context: createCommandContext(),
};

TestBed.configureTestingModule({
Expand Down Expand Up @@ -252,12 +300,10 @@ describe('AmmoLoadoutPanelComponent', () => {
const destroyedEntry = createCritEntry({ loc: 'LT', slot: 1, ammo: standardAmmo, owner, destroyed: true });
const data: AmmoLoadoutPanelData = {
entries: [activeEntry, destroyedEntry],
context: {
dataService: {
getEquipmentRegistry: () => new EquipmentRegistry({ [standardAmmo.internalName]: standardAmmo }),
},
toastService: createToastServiceMock(),
} as unknown as HandlerContext,
context: createCommandContext(
new EquipmentRegistry({ [standardAmmo.internalName]: standardAmmo }),
createToastServiceMock(),
),
};

TestBed.configureTestingModule({
Expand Down Expand Up @@ -294,7 +340,7 @@ describe('AmmoLoadoutPanelComponent', () => {
const data: AmmoLoadoutPanelData = {
entries: [changedEntry, remainingEntry],
getEntries: () => [changedEntry, remainingEntry],
context: {} as HandlerContext,
context: createCommandContext(),
};
const component = configurePanel(data);
const group = component.groups()[0];
Expand All @@ -310,4 +356,4 @@ describe('AmmoLoadoutPanelComponent', () => {
expect(rebuiltGroups.length).toBe(2);
expect(rebuiltGroups.every(rebuiltGroup => component.isExpanded(rebuiltGroup))).toBeTrue();
});
});
});
Loading