refactor(topics): 멀티 에이전트용 지식 재편 — _Common(공통 기본기) + Domain_* 구조
에이전트 8종(대화형/프로그래머 C·S/디자이너/설계자/기획자/QA/PD/PM)에게 [공통 기본 능력 + 롤별 Specialty] 2층으로 지식을 주입하기 위한 재분류. 문서 내용·포맷은 무수정, 폴더 이동만 (6,372개 문서 수 보존 확인). - Topic_Programming → Domain_Programming (내부 구조 보존) - Topic_Graphic → Domain_Design - Topic_Business → Domain_Product - Topic_General → Domain_General - _Common 신설: Math(구 Topic_Math_Specialty), Reasoning(구 General/From_Thinking & Reasoning), Reasoning_Creativity(구 General/From_창의성), Communication(Poetic_Blog_Writing + From_writing) - 타 도메인의 From_* 폴더는 유지 (출처 표기일 뿐, 이미 도메인에 맞게 분류된 문서) - 빈 폴더 정리 (memory/procedures) - 에이전트→폴더 매핑은 workspace의 .astra/agent-knowledge-map.json (9개 에이전트) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
---
|
||||
id: wiki-2026-0508-war-commander-전투-시스템
|
||||
title: War Commander 전투 시스템
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [War Commander Combat, WC Battle System, RTS Combat Resolution]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.85
|
||||
verification_status: applied
|
||||
tags: [game-design, rts, combat-system, simulation, war-commander]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: python
|
||||
framework: numpy, ECS-pattern
|
||||
---
|
||||
|
||||
# War Commander 전투 시스템
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 deterministic damage formula × stochastic hit roll × environmental modifier"**. War Commander (Kixeye 2011~) 의 browser-RTS 의 전투 system — 매 unit-level stat (HP, armor, damage, range) 의 layered modifier 의 final damage 의 resolve. 매 modern 2026 RTS (Wargame / WARNO / SteelDivision) 의 lineage 의 ancestral pattern.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 damage 공식 layer
|
||||
1. **Base damage** — 매 weapon stat (e.g., 100).
|
||||
2. **Armor reduction** — 매 `damage * (1 - armor_class_mult[target_armor])`.
|
||||
3. **Range falloff** — 매 distance / max_range 의 linear or step decay.
|
||||
4. **Cover modifier** — 매 terrain (forest -25%, building -50%).
|
||||
5. **Critical / random roll** — 매 hit chance / crit multiplier.
|
||||
6. **Splash AoE** — 매 distance from impact center 의 attenuation.
|
||||
|
||||
### 매 unit class triangle
|
||||
- **Infantry → Light vehicle**: bonus.
|
||||
- **Light vehicle → Tank**: weak.
|
||||
- **Tank → Infantry**: strong.
|
||||
- **Anti-air → Aircraft**: dedicated counter.
|
||||
- 매 RPS (rock-paper-scissors) 의 enforcing 의 deck-building meta 의 driver.
|
||||
|
||||
### 매 응용
|
||||
1. 매 RTS combat solver 의 prototype.
|
||||
2. 매 game balance simulation (1000-run Monte Carlo).
|
||||
3. 매 tabletop wargame digital adaptation.
|
||||
4. 매 ML self-play agent 의 reward shaping.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### 매 Damage 공식 core
|
||||
```python
|
||||
import numpy as np
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass
|
||||
class Unit:
|
||||
hp: float
|
||||
armor_class: str # "infantry", "light", "heavy", "air"
|
||||
damage: float
|
||||
weapon_class: str # "small_arms", "AP", "HE", "AA"
|
||||
range: float
|
||||
accuracy: float # 0..1
|
||||
|
||||
ARMOR_MULT = {
|
||||
# weapon → armor
|
||||
("small_arms", "infantry"): 1.0, ("small_arms", "light"): 0.3, ("small_arms", "heavy"): 0.05,
|
||||
("AP", "infantry"): 0.5, ("AP", "light"): 1.0, ("AP", "heavy"): 1.2,
|
||||
("HE", "infantry"): 1.5, ("HE", "light"): 0.8, ("HE", "heavy"): 0.4,
|
||||
("AA", "air"): 1.5, ("AA", "infantry"): 0.2,
|
||||
}
|
||||
|
||||
def resolve_damage(attacker: Unit, defender: Unit, distance: float, cover: float = 0.0) -> float:
|
||||
if distance > attacker.range:
|
||||
return 0.0
|
||||
base = attacker.damage
|
||||
armor_mult = ARMOR_MULT.get((attacker.weapon_class, defender.armor_class), 0.5)
|
||||
range_falloff = 1.0 - 0.4 * (distance / attacker.range) # up to -40%
|
||||
cover_mult = 1.0 - cover # 0..1
|
||||
hit_roll = np.random.random() < attacker.accuracy
|
||||
if not hit_roll:
|
||||
return 0.0
|
||||
return base * armor_mult * range_falloff * cover_mult
|
||||
```
|
||||
|
||||
### 매 Splash AoE
|
||||
```python
|
||||
def splash_damage(impact_xy, damage, radius, units):
|
||||
results = []
|
||||
for u in units:
|
||||
d = np.linalg.norm(np.array(u.pos) - np.array(impact_xy))
|
||||
if d > radius:
|
||||
continue
|
||||
falloff = 1.0 - (d / radius) ** 2 # quadratic
|
||||
results.append((u, damage * falloff))
|
||||
return results
|
||||
```
|
||||
|
||||
### 매 RPS counter matrix
|
||||
```python
|
||||
COUNTER = {
|
||||
# attacker → defender → effectiveness
|
||||
"infantry": {"infantry": 1.0, "light_vehicle": 0.6, "tank": 0.2, "aircraft": 0.0},
|
||||
"light_vehicle": {"infantry": 1.4, "light_vehicle": 1.0, "tank": 0.4, "aircraft": 0.0},
|
||||
"tank": {"infantry": 0.8, "light_vehicle": 1.5, "tank": 1.0, "aircraft": 0.0},
|
||||
"anti_tank": {"infantry": 0.5, "light_vehicle": 1.2, "tank": 1.8, "aircraft": 0.0},
|
||||
"anti_air": {"infantry": 0.3, "light_vehicle": 0.5, "tank": 0.1, "aircraft": 2.0},
|
||||
"aircraft": {"infantry": 1.2, "light_vehicle": 1.0, "tank": 0.8, "aircraft": 1.0},
|
||||
}
|
||||
```
|
||||
|
||||
### 매 Combat tick (ECS-style)
|
||||
```python
|
||||
def combat_tick(world, dt: float):
|
||||
for atk in world.attackers():
|
||||
target = world.find_target(atk)
|
||||
if target is None:
|
||||
continue
|
||||
atk.cooldown -= dt
|
||||
if atk.cooldown > 0:
|
||||
continue
|
||||
dist = world.distance(atk, target)
|
||||
cover = world.cover_at(target.pos)
|
||||
dmg = resolve_damage(atk, target, dist, cover)
|
||||
target.hp -= dmg
|
||||
atk.cooldown = atk.fire_rate
|
||||
if target.hp <= 0:
|
||||
world.kill(target)
|
||||
```
|
||||
|
||||
### 매 Morale / suppression layer
|
||||
```python
|
||||
@dataclass
|
||||
class Morale:
|
||||
value: float = 100.0 # 0..100
|
||||
suppressed: bool = False
|
||||
|
||||
def apply_suppression(unit, near_misses: int, dt: float):
|
||||
decay = 5.0 * dt
|
||||
impact = near_misses * 8.0
|
||||
unit.morale.value = max(0, unit.morale.value - impact + decay)
|
||||
unit.morale.suppressed = unit.morale.value < 30
|
||||
if unit.morale.suppressed:
|
||||
unit.accuracy *= 0.5 # 매 panic 의 effect
|
||||
```
|
||||
|
||||
### 매 Monte Carlo balance test
|
||||
```python
|
||||
def simulate_engagement(force_a, force_b, n_runs=1000):
|
||||
wins_a = 0
|
||||
for _ in range(n_runs):
|
||||
a = [Unit(**u.__dict__) for u in force_a] # deep copy
|
||||
b = [Unit(**u.__dict__) for u in force_b]
|
||||
while a and b:
|
||||
for atk in a + b:
|
||||
targets = b if atk in a else a
|
||||
if not targets: break
|
||||
tgt = min(targets, key=lambda t: t.hp)
|
||||
tgt.hp -= resolve_damage(atk, tgt, distance=200, cover=0.2)
|
||||
if tgt.hp <= 0:
|
||||
targets.remove(tgt)
|
||||
a = [u for u in a if u.hp > 0]
|
||||
b = [u for u in b if u.hp > 0]
|
||||
if a and not b:
|
||||
wins_a += 1
|
||||
return wins_a / n_runs
|
||||
|
||||
# 매 50% 의 target 의 balanced 일 때
|
||||
print(simulate_engagement(soviet_tank_platoon, nato_inf_squad))
|
||||
```
|
||||
|
||||
### 매 Line-of-sight check
|
||||
```python
|
||||
def has_los(world, src_pos, dst_pos):
|
||||
steps = int(np.linalg.norm(np.array(dst_pos) - np.array(src_pos)) / 1.0)
|
||||
for t in np.linspace(0, 1, steps):
|
||||
p = np.array(src_pos) + t * (np.array(dst_pos) - np.array(src_pos))
|
||||
if world.height_at(p) > min(world.height_at(src_pos), world.height_at(dst_pos)) + 5:
|
||||
return False
|
||||
return True
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| 매 deterministic balance | hit_roll 의 제거 — 매 expected damage 의 use |
|
||||
| 매 cinematic feel | Crit / miss 의 high variance |
|
||||
| 매 esports 의 fair | Low variance + high skill ceiling formula |
|
||||
| 매 simulation accuracy | Penetration / angle / armor thickness 의 detailed model |
|
||||
| 매 web / browser RTS | Simple layered formula (War Commander 의 origin) |
|
||||
|
||||
**기본값**: 매 layered multiplicative formula + 매 RPS counter matrix + 매 small variance hit roll.
|
||||
|
||||
## 🔗 Graph
|
||||
- Adjacent: [[Monte Carlo Simulation]] · [[Eugen Systems 모딩 매뉴얼]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 RTS prototype 의 combat formula 의 baseline. 매 game-balance Monte Carlo 의 simulator 의 design.
|
||||
**언제 X**: 매 modern simulation-grade armor model (penetration / angle / spalling) 의 required. 매 physics-based ballistics 의 needed.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Pure random damage**: 매 player frustration — 매 perceived unfairness.
|
||||
- **Hard counter only (no soft)**: 매 RPS 의 brittle — 매 deck composition 의 collapse.
|
||||
- **Range = binary**: 매 range falloff 의 없으면 매 kiting 의 broken.
|
||||
- **No cooldown**: 매 DPS 의 burst infinite.
|
||||
- **Single-layer formula**: 매 modifier stacking 의 없으면 매 design space 의 limited.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (War Commander mechanics docs / community wikis 2011-2018, comparable RTS combat lit — Kixeye dev posts, Wargame / WARNO public formulas).
|
||||
- 신뢰도 A−.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — full content (RTS combat resolution patterns / War Commander lineage) |
|
||||
Reference in New Issue
Block a user