f8b21af4be
10_Wiki/Topics 대규모 정리: - 오류 캡처/미완성 stub 문서 227개 제거 - 교차폴더 중복 43클러스터 병합 (63파일 → redirect) - 링크명 정규화: 깨진 링크 수정·redirect 직결·개념 매핑 ~2,400건 - 카테고리 MOC 6개 신규 생성 - Graph 섹션 미해결 related-keyword 링크 10,058건 제거 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
217 lines
7.9 KiB
Markdown
217 lines
7.9 KiB
Markdown
---
|
||
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) |
|