Skip to content

Commit 07b99db

Browse files
committed
feat: 전투 조우시스템, 전투 스킬 시스템 개편(데코레이터 패턴 적용)
1 parent 7f6ec8e commit 07b99db

39 files changed

+1313
-52
lines changed

src/main/java/org/ezcode/codetest/application/game/dto/request/item/WeaponSaveRequest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@
1717
@Getter
1818
public class WeaponSaveRequest extends ItemSaveRequest {
1919

20-
@NotBlank
20+
@NotBlank(message = "무기 타입은 공백일 수 없습니다.")
2121
@Pattern(
22-
regexp = "SHOT_GUN|RIFLE|PISTOL|LONG_SWORD|SHORT_SWORD|SPEAR|BOW",
22+
regexp = "SHOT_GUN|RIFLE|PISTOL|LONG_SWORD|SHORT_SWORD|SPEAR|BOW|MAGIC_BOOK",
2323
flags = Pattern.Flag.CASE_INSENSITIVE,
24-
message = "무기 타입은 SHOT_GUN, RIFLE, PISTOL, LONG_SWORD, SHORT_SWORD, SPEAR, BOW 중 하나여야 합니다."
24+
message = "무기 타입은 SHOT_GUN, RIFLE, PISTOL, LONG_SWORD, SHORT_SWORD, SPEAR, BOW, MAGIC_BOOK 중 하나여야 합니다."
2525
)
2626
private final String weaponType;
2727

src/main/java/org/ezcode/codetest/application/game/dto/request/skill/SkillSaveRequest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ public record SkillSaveRequest(
1111

1212
@NotBlank(message = "스킬 이펙트를 입력해주세요.")
1313
@Pattern(
14-
regexp = "LIFE_STEAL|COUNTER_ATTACK|REFLEX_DAMAGE|HEAL|BURST_ATTACK|INSTANT_KILL|BLOODY_MESS|DEFENCE|ILLUSION",
14+
regexp = "LIFE_STEAL|COUNTER_ATTACK|REFLEX_DAMAGE|HEAL|BURST_ATTACK|INSTANT_KILL|BLOODY_MESS|DEFENCE|ILLUSION|BUTTERFLY|PERFECT_AIM",
1515
flags = Pattern.Flag.CASE_INSENSITIVE,
16-
message = "스킬 이펙트는 LIFE_STEAL, COUNTER_ATTACK, REFLEX_DAMAGE, HEAL, BURST_ATTACK, INSTANT_KILL, BLOODY_MESS, DEFENCE, ILLUSION 중 하나여야 합니다."
16+
message = "스킬 이펙트는 LIFE_STEAL, COUNTER_ATTACK, REFLEX_DAMAGE, HEAL, BURST_ATTACK, INSTANT_KILL, BLOODY_MESS, DEFENCE, ILLUSION, BUTTERFLY, PERFECT_AIM 중 하나여야 합니다."
1717
)
1818
String skillEffect,
1919

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.ezcode.codetest.application.game.dto.response.encounter;
2+
3+
public record MatchingResponse(
4+
5+
boolean isEnemyStrongThanMe,
6+
7+
String message,
8+
9+
Long enemyId
10+
11+
) {
12+
13+
public static MatchingResponse of(boolean isEnemyStrongThanMe, String message, Long enemyId) {
14+
15+
return new MatchingResponse(isEnemyStrongThanMe, message, enemyId);
16+
}
17+
18+
}

src/main/java/org/ezcode/codetest/application/game/play/GamePlayUseCase.java

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@
77
import org.ezcode.codetest.application.game.dto.request.skill.SkillUnEquipRequest;
88
import org.ezcode.codetest.application.game.dto.response.character.CharacterStatusResponse;
99
import org.ezcode.codetest.application.game.dto.response.encounter.BattleHistoryResponse;
10+
import org.ezcode.codetest.application.game.dto.response.encounter.MatchingResponse;
1011
import org.ezcode.codetest.application.game.dto.response.item.ItemGamblingResponse;
1112
import org.ezcode.codetest.application.game.dto.response.item.ItemResponse;
1213
import org.ezcode.codetest.application.game.dto.response.skill.SkillGamblingResponse;
1314
import org.ezcode.codetest.application.game.dto.response.skill.SkillResponse;
1415
import org.ezcode.codetest.domain.game.model.Character.GameCharacter;
15-
import org.ezcode.codetest.domain.game.model.Encounter.BattleHistory;
16+
import org.ezcode.codetest.domain.game.model.Encounter.MatchMessageTemplate;
1617
import org.ezcode.codetest.domain.game.model.skill.GameCharacterSkill;
1718
import org.ezcode.codetest.domain.game.model.item.Item;
1819
import org.ezcode.codetest.domain.game.model.skill.Skill;
@@ -134,4 +135,37 @@ public BattleHistoryResponse battle(Long playerId, Long enemyId) {
134135
);
135136
}
136137

138+
@Transactional
139+
public BattleHistoryResponse randomBattle(Long playerId) {
140+
141+
GameCharacter playerCharacter = characterService.getGameCharacter(playerId);
142+
GameCharacter enemyCharacter = encounterDomainService.getRandomEnemyCharacter(playerId);
143+
144+
BattleLog log = encounterDomainService.battle(playerCharacter, enemyCharacter);
145+
146+
encounterDomainService.createBattleHistory(playerCharacter, enemyCharacter, log);
147+
148+
return BattleHistoryResponse.of(
149+
playerCharacter.getName(),
150+
enemyCharacter.getName(),
151+
log.getMessages(),
152+
log.getPlayerWin()
153+
);
154+
}
155+
156+
@Transactional
157+
public MatchingResponse randomMatching(Long playerId) {
158+
159+
GameCharacter playerCharacter = characterService.getGameCharacter(playerId);
160+
GameCharacter enemyCharacter = encounterDomainService.getRandomEnemyCharacter(playerId);
161+
162+
boolean checkStrength = encounterDomainService.compareStrength(playerCharacter, enemyCharacter);
163+
164+
String matchMessage = MatchMessageTemplate.random(playerCharacter.getName(), enemyCharacter.getName());
165+
166+
Long enemyUserId = enemyCharacter.getUser().getId();
167+
168+
return MatchingResponse.of(checkStrength, matchMessage, enemyUserId);
169+
}
170+
137171
}

src/main/java/org/ezcode/codetest/domain/game/model/Character/CharacterRealStat.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ public void applyItemRealStat(List<Item> equippedItems) {
6868
);
6969
}
7070

71+
public Double statSummary() {
72+
73+
return atk + def + speed + crit + stun + evasion + accuracy;
74+
}
75+
7176
public void applyIncreaseRealStats(Map<Stat, Double> increaseRates) {
7277
increaseRates.forEach(this::increase);
7378
}

src/main/java/org/ezcode/codetest/domain/game/model/Encounter/CharacterContext.java

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public boolean playerDamaged(Double enemyAtk) {
4040

4141
enemyAtk -= def;
4242

43-
if(enemyAtk < 0.0) {
43+
if (enemyAtk < 0.0) {
4444
enemyAtk = 0.0;
4545
}
4646

@@ -49,24 +49,74 @@ public boolean playerDamaged(Double enemyAtk) {
4949
return hp > 0;
5050
}
5151

52+
public void restoreHp(Double hp) {
53+
54+
this.hp += hp;
55+
}
56+
57+
public void applyCritBuff(Double crit) {
58+
59+
this.crit += crit;
60+
}
61+
62+
public void applyAtkBuff(Double atk) {
63+
64+
this.atk += atk;
65+
}
66+
67+
public void applyAtkDebuff(Double atk) {
68+
69+
this.atk = (this.atk - atk) >= 0 ? (this.atk - atk) : 0;
70+
}
71+
72+
public void applyEvasionBuff(Double evasion) {
73+
74+
this.evasion += evasion;
75+
}
76+
77+
public void applyAccuracyBuff(Double accuracy) {
78+
79+
this.accuracy += accuracy;
80+
}
81+
82+
public void applyAccuracyDebuff(Double accuracy) {
83+
84+
this.accuracy = (this.accuracy - accuracy) >= 0 ? (this.accuracy - accuracy) : 0;
85+
}
86+
87+
public void applyDefBuff(Double def) {
88+
89+
this.def += def;
90+
}
91+
92+
public void applyStunBuff(Double stun) {
93+
94+
this.stun += stun;
95+
}
96+
5297
public boolean checkSpeed(Double enemySpeed) {
5398

5499
return speed >= enemySpeed;
55100
}
56101

57102
public boolean consumeActionPoints() {
58103

104+
if(ap <= 0) {
105+
106+
return false;
107+
}
108+
59109
ap--;
60110

61-
return ap > 0;
111+
return true;
62112
}
63113

64114
public boolean checkActionPoints() {
65115

66116
return ap > 0;
67117
}
68118

69-
}
119+
}
70120

71121

72122

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package org.ezcode.codetest.domain.game.model.Encounter;
2+
3+
import java.util.Random;
4+
5+
import lombok.Getter;
6+
7+
@Getter
8+
public enum MatchMessageTemplate {
9+
10+
IN_THE_FOREST(
11+
"%s 님은 어두운 숲속을 걷던 중, 낡은 갑옷을 입고 있는 %s 님을 발견했습니다. 상대는 아직 당신을 눈치채지 못했습니다. 전투를 시작하시겠습니까?"
12+
),
13+
AT_RIVER_SHORE(
14+
"%s 님은 강가에서 휴식을 취하려다가 맞은편에서 무기를 든 %s 님과 눈이 마주쳤습니다. 상대는 이미 당신의 존재를 알고 있습니다. 전투를 시작하시겠습니까?"
15+
),
16+
ABANDONED_VILLAGE(
17+
"%s 님은 버려진 마을을 둘러보던 중, 길 위에 서 있는 %s 님과 마주쳤습니다. 상대는 긴장한 모습으로 당신을 바라보고 있습니다. 전투를 시작하시겠습니까?"
18+
),
19+
DARK_CAVE(
20+
"%s 님은 어두운 동굴 속에서 횃불을 든 %s 님을 발견했습니다. 상대는 당신의 움직임을 경계하고 있습니다. 전투를 시작하시겠습니까?"
21+
),
22+
MISTY_PLAINS(
23+
"%s 님은 안개가 자욱한 평원을 걷다가 흐릿한 형체를 발견했습니다. 가까이 다가가자 %s 님이 무기를 쥐고 서 있었습니다. 전투를 시작하시겠습니까?"
24+
),
25+
ANCIENT_RUINS(
26+
"%s 님은 폐허의 돌기둥 사이에서 %s 님을 발견했습니다. 상대는 이미 당신을 눈치채고 경계하고 있습니다. 전투를 시작하시겠습니까?"
27+
),
28+
SNOWY_MOUNTAINTOP(
29+
"%s 님은 눈 덮인 산 정상에서 강한 바람 속에 서 있는 %s 님을 발견했습니다. 상대는 무기를 든 채 당신을 주시하고 있습니다. 전투를 시작하시겠습니까?"
30+
),
31+
DESERT_OASIS(
32+
"%s 님은 사막의 오아시스에 도착했으나, 그곳에 먼저 온 %s 님이 있었습니다. 상대는 이미 당신을 알아챘습니다. 전투를 시작하시겠습니까?"
33+
),
34+
SUNKEN_SHIP(
35+
"%s 님은 난파선 근처에서 해안을 둘러보다가 %s 님과 마주쳤습니다. 상대는 무기를 손에 쥐고 있습니다. 전투를 시작하시겠습니까?"
36+
),
37+
VOLCANIC_FISSURE(
38+
"%s 님은 용암이 흐르는 균열 근처에서 뜨거운 열기를 견디며 서 있는 %s 님을 발견했습니다. 전투를 시작하시겠습니까?"
39+
),
40+
MOONLIT_CLEARING(
41+
"%s 님은 달빛 아래 고요한 공터에서 %s 님을 발견했습니다. 상대는 이미 당신을 바라보고 있습니다. 전투를 시작하시겠습니까?"
42+
),
43+
HAUNTED_GRAVEYARD(
44+
"%s 님은 오래된 묘지에서 움직이는 그림자를 발견했습니다. 가까이 다가가자 %s 님이 무기를 든 채 서 있었습니다. 전투를 시작하시겠습니까?"
45+
),
46+
WINDY_CLIFF(
47+
"%s 님은 바람이 거세게 부는 절벽 위에서 균형을 잡고 있는 %s 님을 발견했습니다. 전투를 시작하시겠습니까?"
48+
),
49+
UNDERGROUND_LAKE(
50+
"%s 님은 지하 호수 옆에서 조용히 서 있는 %s 님을 발견했습니다. 상대는 당신을 눈치챘습니다. 전투를 시작하시겠습니까?"
51+
),
52+
ANCIENT_LIBRARY(
53+
"%s 님은 고대 도서관의 책장 사이에서 %s 님을 발견했습니다. 상대는 경계하며 당신을 바라보고 있습니다. 전투를 시작하시겠습니까?"
54+
),
55+
LUSH_JUNGLE(
56+
"%s 님은 정글에서 움직이는 나뭇잎 뒤로 %s 님을 발견했습니다. 상대도 당신을 알아챈 듯합니다. 전투를 시작하시겠습니까?"
57+
),
58+
FORGOTTEN_TEMPLE(
59+
"%s 님은 잊혀진 사원 입구에서 %s 님과 마주쳤습니다. 상대는 당신을 경계하고 있습니다. 전투를 시작하시겠습니까?"
60+
),
61+
RICKETY_BRIDGE(
62+
"%s 님은 낡은 다리 위에서 균형을 잡고 서 있는 %s 님을 발견했습니다. 전투를 시작하시겠습니까?"
63+
),
64+
STORMY_SEASHORE(
65+
"%s 님은 폭풍우가 몰아치는 해변에서 %s 님과 마주쳤습니다. 상대는 이미 당신을 주시하고 있습니다. 전투를 시작하시겠습니까?"
66+
);
67+
68+
private static final Random RNG = new Random();
69+
private final String template;
70+
71+
MatchMessageTemplate(String template) {
72+
this.template = template;
73+
}
74+
75+
public static String random(String playerName, String enemyName) {
76+
MatchMessageTemplate[] values = values();
77+
MatchMessageTemplate random = values[RNG.nextInt(values.length)];
78+
return random.format(playerName, enemyName);
79+
}
80+
81+
private String format(Object... args) {
82+
return String.format(template, args);
83+
}
84+
}

src/main/java/org/ezcode/codetest/domain/game/model/item/WeaponType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
public enum WeaponType implements ItemType {
44

5-
SHOT_GUN, RIFLE, PISTOL, LONG_SWORD, SHORT_SWORD, SPEAR, BOW, NOTHING
5+
SHOT_GUN, RIFLE, PISTOL, LONG_SWORD, SHORT_SWORD, SPEAR, BOW, MAGIC_BOOK, NOTHING
66

77
}

src/main/java/org/ezcode/codetest/domain/game/model/skill/SkillEffect.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@
22

33
public enum SkillEffect {
44

5-
LIFE_STEAL, COUNTER_ATTACK, REFLEX_DAMAGE, HEAL, BURST_ATTACK, INSTANT_KILL, BLOODY_MESS, DEFENCE, ILLUSION, NO_SKILL
5+
LIFE_STEAL,
6+
COUNTER_ATTACK,
7+
//REFLEX_DAMAGE,
8+
HEAL,
9+
BURST_ATTACK,
10+
INSTANT_KILL,
11+
BLOODY_MESS,
12+
DEFENCE,
13+
//ILLUSION,
14+
NO_SKILL,
15+
PERFECT_AIM,
16+
BUTTERFLY,
17+
MENTAL_DESTROY
618

719
}

src/main/java/org/ezcode/codetest/domain/game/repository/GameCharacterRepository.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.ezcode.codetest.domain.game.repository;
22

3+
import java.util.List;
34
import java.util.Optional;
45

56
import org.ezcode.codetest.domain.game.model.Character.GameCharacter;
@@ -9,4 +10,6 @@ public interface GameCharacterRepository {
910
GameCharacter save(GameCharacter character);
1011

1112
Optional<GameCharacter> findByUserId(Long userId);
13+
14+
List<GameCharacter> findRandomCharacter(Long userId);
1215
}

0 commit comments

Comments
 (0)