merge: 최신 main을 유저 preset 아이콘 차단에 통합한다

This commit is contained in:
2026-08-24 08:41:19 +00:00
33 changed files with 1084 additions and 57 deletions
@@ -718,6 +718,7 @@ describe('legacy NPC user-chief promotion parity', () => {
it('keeps user-ruler duties individually disabled until each setting is enabled', () => {
const ruler = makePromotionGeneral({ id: 1, officerLevel: 12, npcState: 0, meta: { killturn: 0 } });
expect(canUseAutomatedNationAction(ruler, '선전포고')).toBe(false);
expect(canUseAutomatedNationAction(ruler, '불가침제의')).toBe(false);
expect(canUseAutomatedNationAction(ruler, '천도')).toBe(false);
expect(canUseRulerAutomation(ruler, 'finance')).toBe(false);
@@ -728,9 +729,17 @@ describe('legacy NPC user-chief promotion parity', () => {
use_auto_nation_finance: 1,
};
expect(canUseAutomatedNationAction(ruler, '불가침제의')).toBe(true);
expect(canUseAutomatedNationAction(ruler, '선전포고')).toBe(true);
expect(canUseAutomatedNationAction(ruler, '선전포고')).toBe(false);
expect(canUseAutomatedNationAction(ruler, '천도')).toBe(true);
expect(canUseRulerAutomation(ruler, 'finance')).toBe(true);
ruler.meta = {
...ruler.meta,
use_auto_nation_diplomacy: 0,
use_auto_nation_war: 1,
};
expect(canUseAutomatedNationAction(ruler, '불가침제의')).toBe(false);
expect(canUseAutomatedNationAction(ruler, '선전포고')).toBe(true);
});
it('honors the existing automatic nation-turn master switch for user chiefs only', () => {
@@ -223,6 +223,7 @@ describe('my information world commands', () => {
use_treatment: 200,
use_auto_nation_turn: 0,
use_auto_nation_diplomacy: 1,
use_auto_nation_war: 1,
use_auto_nation_promotion: 1,
use_auto_nation_finance: 1,
use_auto_nation_capital: 1,
@@ -239,6 +240,7 @@ describe('my information world commands', () => {
use_treatment: 100,
use_auto_nation_turn: 0,
use_auto_nation_diplomacy: 1,
use_auto_nation_war: 1,
use_auto_nation_promotion: 1,
use_auto_nation_finance: 1,
use_auto_nation_capital: 1,
@@ -312,6 +312,39 @@ describe('nation personnel world commands', () => {
expect(fixture.world.peekDirtyState().logs).toHaveLength(2);
});
it('rejects self, ruler, head officer, and ambassador targets without partial mutation', async () => {
const cases = [
{ label: 'self', targetId: 2, reason: '본인은 추방할 수 없습니다.' },
{ label: 'ruler', targetId: 1, reason: '군주는 추방할 수 없습니다.' },
{ label: 'head officer', targetId: 3, reason: '수뇌는 추방할 수 없습니다.' },
{ label: 'ambassador', targetId: 4, reason: '외교권자는 추방할 수 없습니다.' },
] as const;
for (const testCase of cases) {
const fixture = buildWorld({
generals: [
buildGeneral(1, { officerLevel: 12 }),
buildGeneral(2, { officerLevel: 5 }),
buildGeneral(3, { officerLevel: 7 }),
buildGeneral(4, {
meta: { killturn: 12, belong: 5, permission: 'ambassador' },
penalty: { noAmbassador: true },
}),
buildGeneral(5),
],
});
const originalTarget = fixture.world.getGeneralById(testCase.targetId);
await expect(
fixture.handler.handle({ type: 'kick', generalId: 2, destGeneralId: testCase.targetId })
).resolves.toMatchObject({ ok: false, reason: testCase.reason });
expect(fixture.world.getGeneralById(testCase.targetId), testCase.label).toEqual(originalTarget);
expect(fixture.world.getGeneralById(2)?.meta.killturn, testCase.label).toBe(12);
expect(fixture.world.peekDirtyState().logs, testCase.label).toEqual([]);
expect(fixture.world.peekDirtyState().nations, testCase.label).toEqual([]);
}
});
it('preserves the legacy kick year boundaries and deterministic NPC public message', async () => {
const early = buildWorld({
currentYear: 181,