Skip to content

Commit 86f32d4

Browse files
committed
feat: 识别青春杯友情并且作为训练选择权重的一部分
1 parent 90c5e4d commit 86f32d4

File tree

7 files changed

+142
-32
lines changed

7 files changed

+142
-32
lines changed

module/umamusume/hook.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def after_hook(ctx: UmamusumeContext):
2424
if ctx.cultivate_detail and ctx.cultivate_detail.turn_info is not None:
2525
if ctx.cultivate_detail.turn_info.parse_train_info_finish and ctx.cultivate_detail.turn_info.parse_main_menu_finish:
2626
if not ctx.cultivate_detail.turn_info.turn_info_logged:
27-
ctx.cultivate_detail.turn_info.log_turn_info()
27+
ctx.cultivate_detail.turn_info.log_turn_info(ctx.task.detail.scenario)
2828
ctx.cultivate_detail.turn_info.turn_info_logged = True
2929
if ctx.cultivate_detail.turn_info.turn_operation is None:
3030
ctx.cultivate_detail.turn_info.turn_operation = get_operation(ctx)

module/umamusume/scenario/aoharuhai_scenario.py

Lines changed: 109 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -98,18 +98,21 @@ def parse_training_result(self, img: any) -> list[int]:
9898
skill_point_incr = (0 if skill_point_incr_text == "" else int(skill_point_incr_text)) + (0 if skill_point_incr_extra_text == "" else int(skill_point_incr_extra_text))
9999

100100
return [speed_icr, stamina_incr, power_incr, will_incr, intelligence_incr, skill_point_incr]
101-
102-
def parse_training_support_cord(self, img: any) -> list[SupportCardInfo]:
103-
# TODO: 目前没有识别青春杯参数和青春杯友情条, 也没有将其作为训练权重的一部分,
104-
base_x = 590
101+
102+
def parse_training_support_card(self, img: any) -> list[SupportCardInfo]:
103+
base_x = 550
105104
base_y = 177
106105
inc = 115
107106
support_card_list_info_result: list[SupportCardInfo] = []
108107
for i in range(5):
109-
support_card_icon = img[base_y:base_y + inc, base_x: base_x + 105]
108+
support_card_icon = img[base_y:base_y + inc, base_x: base_x + 145]
109+
110+
# 有青春杯训练, 且青春杯友情未满
111+
can_incr_aoharu_train = detect_aoharu_train_arrow(support_card_icon) and aoharu_train_not_full(support_card_icon)
112+
110113
# 判断好感度
111114
support_card_icon = cv2.cvtColor(support_card_icon, cv2.COLOR_BGR2RGB)
112-
favor_process_check_list = [support_card_icon[106, 16], support_card_icon[106, 20]]
115+
favor_process_check_list = [support_card_icon[106, 56], support_card_icon[106, 60]]
113116
support_card_favor_process = SupportCardFavorLevel.SUPPORT_CARD_FAVOR_LEVEL_UNKNOWN
114117
for support_card_favor_process_pos in favor_process_check_list:
115118
if compare_color_equal(support_card_favor_process_pos, [255, 235, 120]):
@@ -124,13 +127,6 @@ def parse_training_support_cord(self, img: any) -> list[SupportCardInfo]:
124127
if support_card_favor_process != SupportCardFavorLevel.SUPPORT_CARD_FAVOR_LEVEL_UNKNOWN:
125128
break
126129

127-
# 判断是否有事件
128-
support_card_event_pos = support_card_icon[5, 83]
129-
support_card_event_available = False
130-
if (support_card_event_pos[0] >= 250
131-
and 55 <= support_card_event_pos[1] <= 90
132-
and 115 <= support_card_event_pos[2] <= 150):
133-
support_card_event_available = True
134130
# 判断支援卡类型
135131
support_card_type = SupportCardType.SUPPORT_CARD_TYPE_UNKNOWN
136132
support_card_icon = cv2.cvtColor(support_card_icon, cv2.COLOR_RGB2GRAY)
@@ -146,11 +142,107 @@ def parse_training_support_cord(self, img: any) -> list[SupportCardInfo]:
146142
support_card_type = SupportCardType.SUPPORT_CARD_TYPE_INTELLIGENCE
147143
elif image_match(support_card_icon, REF_SUPPORT_CARD_TYPE_FRIEND).find_match:
148144
support_card_type = SupportCardType.SUPPORT_CARD_TYPE_FRIEND
149-
if support_card_favor_process is not SupportCardFavorLevel.SUPPORT_CARD_FAVOR_LEVEL_UNKNOWN:
145+
if (can_incr_aoharu_train) or \
146+
(support_card_favor_process is not SupportCardFavorLevel.SUPPORT_CARD_FAVOR_LEVEL_UNKNOWN):
150147
info = SupportCardInfo(card_type=support_card_type,
151-
favor=support_card_favor_process,
152-
has_event=support_card_event_available)
148+
favor=support_card_favor_process,
149+
can_incr_aoharu_train=can_incr_aoharu_train)
153150
support_card_list_info_result.append(info)
154151
base_y += inc
155152

156-
return support_card_list_info_result
153+
return support_card_list_info_result
154+
155+
# 检测支援卡右上角是否有箭头图标, 同时排除感叹号防止false positive
156+
# 输入的图片必须是彩色的
157+
def detect_aoharu_train_arrow(support_card_icon):
158+
support_card_icon = cv2.cvtColor(support_card_icon, cv2.COLOR_BGR2RGB)
159+
# 定义右上角检测区域
160+
arrow_region_x_start = 110
161+
arrow_region_x_end = 145
162+
arrow_region_y_start = 0
163+
arrow_region_y_end = 40
164+
165+
arrow_region = support_card_icon[arrow_region_y_start:arrow_region_y_end,
166+
arrow_region_x_start:arrow_region_x_end]
167+
168+
# 定义箭头可能的颜色范围 (检查橙色)
169+
orange_lower = [240, 100, 50]
170+
orange_upper = [255, 180, 100]
171+
172+
# 定义红色像素范围(用于检测感叹号)
173+
red_lower = [180, 30,50]
174+
red_upper = [255, 100, 150]
175+
176+
# 计算橙色像素和红色像素的数量
177+
orange_pixels = 0
178+
red_pixels = 0
179+
total_pixels = arrow_region.shape[0] * arrow_region.shape[1]
180+
181+
for y in range(arrow_region.shape[0]):
182+
for x in range(arrow_region.shape[1]):
183+
pixel = arrow_region[y, x]
184+
185+
# 检测橙色像素
186+
if (orange_lower[0] <= pixel[0] <= orange_upper[0] and
187+
orange_lower[1] <= pixel[1] <= orange_upper[1] and
188+
orange_lower[2] <= pixel[2] <= orange_upper[2]):
189+
orange_pixels += 1
190+
# 检测红色像素
191+
elif (red_lower[0] <= pixel[0] <= red_upper[0] and
192+
red_lower[1] <= pixel[1] <= red_upper[1] and
193+
red_lower[2] <= pixel[2] <= red_upper[2]):
194+
red_pixels += 1
195+
196+
orange_ratio = orange_pixels / total_pixels if total_pixels > 0 else 0
197+
red_ratio = red_pixels / total_pixels if total_pixels > 0 else 0
198+
199+
has_arrow = False
200+
201+
# 首先排除感叹号:如果红色像素比例过高,判断为感叹号
202+
if red_ratio > 0.2:
203+
has_arrow = False
204+
# 如果橙色像素比例超过阈值
205+
elif (orange_ratio > 0.05):
206+
has_arrow = True
207+
208+
return has_arrow
209+
210+
211+
# 检测左下角青春杯训练值是否未满
212+
# 如果已满或者不存在UI(比如已经触发了魂爆, 则返回false)
213+
# 否则返回true
214+
def aoharu_train_not_full(support_card_icon) -> bool:
215+
support_card_icon = cv2.cvtColor(support_card_icon, cv2.COLOR_BGR2RGB)
216+
avatar_region_x_start = 5
217+
avatar_region_x_end = 45
218+
avatar_region_y_start = 70
219+
avatar_region_y_end = 110
220+
221+
avatar_region = support_card_icon[avatar_region_y_start:avatar_region_y_end,
222+
avatar_region_x_start:avatar_region_x_end]
223+
224+
total_pixels = avatar_region.shape[0] * avatar_region.shape[1]
225+
if total_pixels == 0:
226+
return False
227+
228+
# 检测灰色
229+
grey_lower = [100, 100, 100]
230+
grey_upper = [150, 150, 150]
231+
grey_pixels = 0
232+
233+
for y in range(avatar_region.shape[0]):
234+
for x in range(avatar_region.shape[1]):
235+
pixel = avatar_region[y, x]
236+
if (grey_lower[0] <= pixel[0] <= grey_upper[0] and
237+
grey_lower[1] <= pixel[1] <= grey_upper[1] and
238+
grey_lower[2] <= pixel[2] <= grey_upper[2]):
239+
grey_pixels += 1
240+
241+
grey_ratio = grey_pixels / total_pixels
242+
243+
if grey_ratio > 0.05:
244+
status = True
245+
else:
246+
status = False
247+
248+
return status

module/umamusume/scenario/base_scenario.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,6 @@ def parse_training_result(self, img: any) -> list[int]:
3232
pass
3333

3434
@abstractmethod
35-
def parse_training_support_cord(self, img: any) -> list[SupportCardInfo]:
35+
def parse_training_support_card(self, img: any) -> list[SupportCardInfo]:
3636
"""从屏幕上获取每一张支援卡的信息"""
3737
pass

module/umamusume/scenario/ura_scenario.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def parse_training_result(self, img: any) -> list[int]:
6363

6464
return [speed_icr, stamina_incr, power_incr, will_incr, intelligence_incr, skill_point_incr]
6565

66-
def parse_training_support_cord(self, img: any) -> list[SupportCardInfo]:
66+
def parse_training_support_card(self, img: any) -> list[SupportCardInfo]:
6767
base_x = 590
6868
base_y = 190
6969
inc = 120

module/umamusume/script/cultivate_task/parse.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ def parse_train_main_menu_operations_availability(ctx: UmamusumeContext, img):
206206

207207

208208
def parse_training_support_card(ctx: UmamusumeContext, img, train_type: TrainingType):
209-
support_card_info_list = ctx.cultivate_detail.scenario.parse_training_support_cord(img)
209+
support_card_info_list = ctx.cultivate_detail.scenario.parse_training_support_card(img)
210210
ctx.cultivate_detail.turn_info.training_info_list[train_type.value - 1].support_card_info_list = support_card_info_list
211211

212212
def parse_train_type(ctx: UmamusumeContext, img) -> TrainingType:

module/umamusume/script/cultivate_task/support_card.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,16 @@ def get_support_card_score(ctx: UmamusumeContext, info: SupportCardInfo):
1010
score = SCORE_DICT[info.card_type][info.name](ctx, info)
1111
else:
1212
score = SCORE_DICT[info.card_type][DEFAULT](ctx, info)
13+
14+
# 青春杯友情值提高
15+
if info.can_incr_aoharu_train:
16+
date = ctx.cultivate_detail.turn_info.date
17+
if date <= 24:
18+
score += 1
19+
elif date <= 48:
20+
score += 0.5
21+
else:
22+
score += 0.1
1323
return score
1424

1525

module/umamusume/types.py

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,20 @@ class SupportCardInfo:
1515
card_type: SupportCardType
1616
favor: SupportCardFavorLevel
1717
has_event: bool
18+
# 青春杯部分
19+
can_incr_aoharu_train: bool
1820

1921
def __init__(self,
2022
name: str = "support_card",
2123
card_type: SupportCardType = SupportCardType.SUPPORT_CARD_TYPE_UNKNOWN,
2224
favor: SupportCardFavorLevel = SupportCardFavorLevel.SUPPORT_CARD_FAVOR_LEVEL_UNKNOWN,
23-
has_event: bool = False):
25+
has_event: bool = False,
26+
can_incr_aoharu_train: bool = False):
2427
self.name = name
2528
self.card_type = card_type
2629
self.favor = favor
2730
self.has_event = has_event
31+
self.can_incr_aoharu_train = can_incr_aoharu_train
2832

2933

3034
class TrainingInfo:
@@ -45,14 +49,18 @@ def __init__(self):
4549
self.skill_point_incr = 0
4650
self.support_card_info_list = []
4751

48-
def log_training_info(self):
52+
def log_training_info(self, scenario_type: ScenarioType):
4953
log.info("训练结果:速度:%s, 耐力:%s, 力量:%s, 毅力:%s, 智力:%s, 技能点:%s", self.speed_incr,
5054
self.stamina_incr, self.power_incr, self.will_incr,
5155
self.intelligence_incr, self.skill_point_incr)
5256
text = "此训练附带支援卡列表:["
53-
for c in self.support_card_info_list:
54-
if c.favor != SupportCardFavorLevel.SUPPORT_CARD_FAVOR_LEVEL_UNKNOWN:
55-
text += "[支援卡名称:" + str(c.name) + "支援卡类型:" + str(c.card_type.name) + ", 支援卡羁绊阶段:" + str(c.favor.name) + "] "
57+
if scenario_type == ScenarioType.SCENARIO_TYPE_AOHARUHAI:
58+
for c in self.support_card_info_list:
59+
text += "[支援卡名称:" + str(c.name) + "支援卡类型:" + str(c.card_type.name) + ", 支援卡羁绊阶段:" + str(c.favor.name) + ", 可提升青春杯友情: " + str(c.can_incr_aoharu_train) + "] "
60+
else:
61+
for c in self.support_card_info_list:
62+
if c.favor != SupportCardFavorLevel.SUPPORT_CARD_FAVOR_LEVEL_UNKNOWN:
63+
text += "[支援卡名称:" + str(c.name) + "支援卡类型:" + str(c.card_type.name) + ", 支援卡羁绊阶段:" + str(c.favor.name) + "] "
5664
text += "]"
5765
log.info(text)
5866

@@ -123,22 +131,22 @@ def __init__(self):
123131
self.turn_info_logged = False
124132
self.turn_learn_skill_done = False
125133

126-
def log_turn_info(self):
134+
def log_turn_info(self, scenario_type : ScenarioType):
127135
log.info("当前回合时间 >" + str(self.date))
128136
log.info("干劲状态 " + str(self.motivation_level.name))
129137
log.info("体力剩余" + str(self.remain_stamina))
130138
log.info("当前属性值 速度:%s, 耐力:%s, 力量:%s, 毅力:%s, 智力:%s, 技能点:%s", self.uma_attribute.speed,
131139
self.uma_attribute.stamina, self.uma_attribute.power, self.uma_attribute.will, self.uma_attribute.intelligence, self.uma_attribute.skill_point)
132140
log.info("速度训练结果:")
133-
self.training_info_list[0].log_training_info()
141+
self.training_info_list[0].log_training_info(scenario_type)
134142
log.info("耐力训练结果:")
135-
self.training_info_list[1].log_training_info()
143+
self.training_info_list[1].log_training_info(scenario_type)
136144
log.info("力量训练结果:")
137-
self.training_info_list[2].log_training_info()
145+
self.training_info_list[2].log_training_info(scenario_type)
138146
log.info("毅力训练结果:")
139-
self.training_info_list[3].log_training_info()
147+
self.training_info_list[3].log_training_info(scenario_type)
140148
log.info("智力训练结果:")
141-
self.training_info_list[4].log_training_info()
149+
self.training_info_list[4].log_training_info(scenario_type)
142150

143151

144152
class CultivateContextDetail:

0 commit comments

Comments
 (0)