添加对cost_changes的支持

This commit is contained in:
AutumnSound
2022-05-29 18:33:48 +08:00
parent c08c1fce44
commit 91eae79d36

View File

@@ -1,354 +1,368 @@
from __future__ import annotations
import json
# ======================= constants begin =========================
class Direction:
UP = ""
DOWN = ""
RIGHT = ""
LEFT = ""
class ActionType:
Deploy = "部署"
Skill = "技能"
Retreat = "撤退"
SpeedUp = "二倍速"
BulletTime = "子弹时间"
SkillUsage = "技能用法"
class SkillUsageType:
NotAutoUse = 0 # 0 - 不自动使用 默认
UseWhenOk = 1 # 1 - 好了就用,有多少次用多少次(例如干员 棘刺 3 技能、桃金娘 1 技能等)
UseWhenOkOnce = 2 # 2 - 好了就用,仅使用一次(例如干员 山 2 技能)
AutoUse = 3 # 3 - 自动判断使用时机(画饼.jpg
# ========================= constants end =============================
class Document:
def __init__(self, title: str, details: str, title_color: str = "dark", details_color: str = "dark"):
self._details_color = details_color
self._details = details
self._title_color = title_color
self._title = title
def to_dict(self) -> dict:
return {
"title": self._title,
"title_color": self._title_color,
"details": self._details,
"details_color": self._details_color
}
class Requirements:
def __init__(self, elite: int, level: int, skill_level: int, module: int, potentiality: int):
self._potentiality = potentiality
self._module = module
self._skill_level = skill_level
self._level = level
self._elite = elite
def to_dict(self):
return {
"elite": self._elite,
"level": self._level,
"skill_level": self._skill_level,
"module": self._module,
"potentiality": self._potentiality
}
class Action:
def __init__(self, action_type: str, name: str = None, location: tuple = None, direction: str = "", kills: int = 0,
skill_usage: int = None, pre_delay: int = 0, rear_delay: int = 0, timeout: int = 999999999,
doc: str = None, doc_color: str = None):
self._doc_color = doc_color
self._doc = doc
self._timeout = timeout
self._rear_delay = rear_delay
self._pre_delay = pre_delay
self._skill_usage = skill_usage
self._kills = kills
self._direction = direction
self._name = name
self._location = location
self._action_type = action_type
def to_dict(self) -> dict:
res = {
"type": self._action_type,
}
if self._kills != 0:
res["kills"] = self._kills
if self._pre_delay != 0:
res["pre_delay"] = self._pre_delay
if self._rear_delay != 0:
res["rear_delay"] = self._rear_delay
if self._action_type == ActionType.Deploy or self._action_type == ActionType.Skill \
or self._action_type == ActionType.Retreat:
res["name"] = self._name
if self._action_type == ActionType.Deploy:
res["location"] = self._location
res["direction"] = self._direction
return res
class OperatorOrGroup:
def __init__(self, name: str, battle: Battle):
self._battle = battle
self._name = name
self._pre_delay = 0
self._rear_delay = 0
self._wait_kills = 0
def pre_delay(self, times: int) -> OperatorOrGroup:
self._pre_delay = times
return self
def rear_delay(self, times: int) -> OperatorOrGroup:
self._rear_delay = times
return self
def wait_kills(self, kills: int) -> OperatorOrGroup:
self._wait_kills = kills
return self
def deploy(self, location: tuple, direction: str):
self._battle.add_action(self._add_conditions(Action(ActionType.Deploy, self._name, location, direction)))
def use_skill(self):
self._battle.add_action(self._add_conditions(Action(ActionType.Skill, self._name)))
def retreat(self):
self._battle.add_action(self._add_conditions(Action(ActionType.Retreat, self._name)))
def _add_conditions(self, action: Action) -> Action:
if self._pre_delay != 0:
action._pre_delay = self._pre_delay
if self._rear_delay != 0:
action._rear_delay = self._rear_delay
if self._wait_kills != 0:
action._kills = self._wait_kills
self._clear_conditions()
return action
def _clear_conditions(self):
self._pre_delay = 0
self._rear_delay = 0
self._wait_kills = 0
def to_dict(self) -> dict:
# 此处不应该被执行到
raise Exception("请使用子类方法")
class Group(OperatorOrGroup):
def __init__(self, name: str, battle: Battle, operators: tuple):
"""
请使用 Battle.create_group()
:param name:
:param battle:
:param operators:
"""
super().__init__(name, battle)
self._operators = operators
def to_dict(self) -> dict:
return {
"name": self._name,
"opers": [operator.to_dict() for operator in self._operators]
}
class Operator(OperatorOrGroup):
def __init__(self, name: str, battle: Battle, skill: int, skill_usage: int = SkillUsageType.NotAutoUse,
requirements: Requirements = None):
"""
仅当要创建群组时才应该被调用
正常使用请用 Battle.create_operator()
:param name:
:param battle:
:param skill:
:param skill_usage:
:param requirements:
"""
super().__init__(name, battle)
self._requirements = requirements
self._skill_usage = skill_usage
self._skill = skill
def skill_usage_change(self, change_to: int):
"""
改变技能使用的类型
由于需要兼容群组类型,有时此方法可能无法通过代码提示调用,手动调用即可
:param change_to: 需要调整到的 SkillUsageType
:return:
"""
self._battle.add_action(self._add_conditions(Action(ActionType.SkillUsage, skill_usage=change_to)))
def to_dict(self) -> dict:
res = {
"name": self._name,
"skill": self._skill,
"skill_usage": self._skill_usage,
}
if self._skill_usage != SkillUsageType.NotAutoUse:
res["skill_usage"] = self._skill_usage
if self._requirements is not None:
res["requirements"] = self._requirements.to_dict()
return res
class Battle:
def __init__(self, stage_name: str, version="v4.0", doc: Document = None):
self._doc = doc
self._stage_name = stage_name
self._version = version
self._operators = []
self._groups = []
self._actions = []
self._wait_times = 0
self._wait_kills = 0
self._speedup = False
self._last_save_file_name = "battle.json"
def create_operator(self, name: str, skill: int, skill_usage: int = SkillUsageType.NotAutoUse,
requirements: Requirements = None) -> Operator:
"""
创建并添加一个干员
:param name: 干员名称
:param skill: 要使用的技能
:param skill_usage: 技能使用类型 参见 SkillUsageType
:param requirements: 可选
:return: 新生成的干员
"""
new_operator = Operator(name, self, skill, skill_usage, requirements)
self._add_operator(new_operator)
return new_operator
def create_group(self, name: str, *operators: Operator) -> Group:
"""
创建并添加一个群组
:param name: 群组名
:param operators: 所包含的干员,构造的时候 battle 一项置 None 即可
:return: 新创建的群组
"""
new_group = Group(name, self, operators)
self._add_group(new_group)
return new_group
def _add_operator(self, operator: Operator):
self._operators.append(operator)
def _add_group(self, group: Group):
self._groups.append(group)
def add_action(self, action: Action):
self._actions.append(action)
def speed_up(self):
"""
调整为二倍速
:return:
"""
if not self._speedup:
self._speed_change()
self._speedup = True
def speed_down(self):
"""
调整为一倍速
:return:
"""
if self._speedup:
self._speed_change()
self._speedup = False
def _speed_change(self):
self.add_action(Action(ActionType.SpeedUp))
def save_as_json(self, file_name: str = None):
"""
保存为 json 文件,生成在同目录下
:param file_name: 要保存的文件名
:return:
"""
if file_name is None:
file_name = self._last_save_file_name
else:
self._last_save_file_name = file_name
with open(file_name, 'w', encoding='utf-8') as f:
json.dump(self.to_dict(), f, ensure_ascii=False)
def to_dict(self) -> dict:
res = {
"stage_name": self._stage_name,
"minimum_required": self._version,
"opers": [operator.to_dict() for operator in self._operators],
"groups": [group.to_dict() for group in self._groups],
"actions": [action.to_dict() for action in self._actions],
}
if self._doc is not None:
res["doc"] = self._doc.to_dict()
return res
def test(self, enable_debug_output: bool = True):
"""
自动调用 MeoAssistantArknights 并测试生成自动战斗的文件
测试的是上次生成的 json 需先调用 save_as_json()
请自行配置 MeoAssistantArknights 所在地址等
同时确保能导入 asst.py
:param enable_debug_output: 是否开启 debug 输出
:return:
"""
# MeoAssistantArknights所在的路径
mma_path = "D:\\Program Files\\MeoAssistantArknights"
# adb的路径
adb_path = "D:\\Program Files\\MeoAssistantArknights\\platform-tools\\adb.exe"
# adb连接的地址
adb_address = "127.0.0.1:8873"
try:
from asst import Asst, Message
except ImportError:
import sys
import pathlib
sys.path.append(str(pathlib.Path.cwd().parent.parent/"src"/"Python"))
try:
from asst import Asst, Message
except ImportError:
print("asst导入失败请自行解决或者下载"
" https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/master/src/Python/asst.py "
"到同目录下")
return
@Asst.CallBackType
def callback(msg, details, arg):
print(Message(msg), json.loads(details.decode('utf-8')), arg)
if not Asst.load(mma_path):
print("加载MeoAssistantArknights失败请确定路径是否正确")
asst = Asst(callback) if enable_debug_output else Asst()
if asst.connect(adb_path, adb_address):
print('连接成功')
else:
print('连接失败')
print('请检查adb地址或者端口是否有误')
exit()
asst.append_task('Copilot', {
'stage_name': self._stage_name,
'filename': self._last_save_file_name,
'formation': False,
})
asst.start()
while True:
if "stop" == str(input('>')):
exit()
from __future__ import annotations
import json
# ======================= constants begin =========================
class Direction:
UP = ""
DOWN = ""
RIGHT = ""
LEFT = ""
class ActionType:
Deploy = "部署"
Skill = "技能"
Retreat = "撤退"
SpeedUp = "二倍速"
BulletTime = "子弹时间"
SkillUsage = "技能用法"
class SkillUsageType:
NotAutoUse = 0 # 0 - 不自动使用 默认
UseWhenOk = 1 # 1 - 好了就用,有多少次用多少次(例如干员 棘刺 3 技能、桃金娘 1 技能等)
UseWhenOkOnce = 2 # 2 - 好了就用,仅使用一次(例如干员 山 2 技能)
# AutoUse = 3 # 3 - 自动判断使用时机(画饼.jpg
# ========================= constants end =============================
class Document:
def __init__(self, title: str, details: str, title_color: str = "dark", details_color: str = "dark"):
self._details_color = details_color
self._details = details
self._title_color = title_color
self._title = title
def to_dict(self) -> dict:
return {
"title": self._title,
"title_color": self._title_color,
"details": self._details,
"details_color": self._details_color
}
class Requirements:
def __init__(self, elite: int, level: int, skill_level: int, module: int, potentiality: int):
self._potentiality = potentiality
self._module = module
self._skill_level = skill_level
self._level = level
self._elite = elite
def to_dict(self):
return {
"elite": self._elite,
"level": self._level,
"skill_level": self._skill_level,
"module": self._module,
"potentiality": self._potentiality
}
class Action:
def __init__(self, action_type: str, name: str = None, location: tuple = None, direction: str = "", kills: int = 0,
skill_usage: int = None, pre_delay: int = 0, rear_delay: int = 0, cost_changes: int = 0,
timeout: int = 999999999, doc: str = None, doc_color: str = None):
self._doc_color = doc_color
self._doc = doc
# self._timeout = timeout
self._cost_changes = cost_changes
self._rear_delay = rear_delay
self._pre_delay = pre_delay
self._skill_usage = skill_usage
self._kills = kills
self._direction = direction
self._name = name
self._location = location
self._action_type = action_type
def to_dict(self) -> dict:
res = {
"type": self._action_type,
}
if self._kills != 0:
res["kills"] = self._kills
if self._pre_delay != 0:
res["pre_delay"] = self._pre_delay
if self._rear_delay != 0:
res["rear_delay"] = self._rear_delay
if self._cost_changes != 0:
res["cost_changes"] = self._cost_changes
# 保留字段,暂未实现。
# if self._timeout != 0:
# res["timeout"] = self._timeout
if self._action_type == ActionType.Deploy or self._action_type == ActionType.Skill \
or self._action_type == ActionType.Retreat:
res["name"] = self._name
if self._action_type == ActionType.Deploy:
res["location"] = self._location
res["direction"] = self._direction
return res
class OperatorOrGroup:
def __init__(self, name: str, battle: Battle):
self._battle = battle
self._name = name
self._pre_delay = 0
self._rear_delay = 0
self._wait_kills = 0
self._cost_changes = 0
def pre_delay(self, times: int) -> OperatorOrGroup:
self._pre_delay = times
return self
def rear_delay(self, times: int) -> OperatorOrGroup:
self._rear_delay = times
return self
def cost_changes(self, costs: int) -> OperatorOrGroup:
self._cost_changes = costs
return self
def wait_kills(self, kills: int) -> OperatorOrGroup:
self._wait_kills = kills
return self
def deploy(self, location: tuple, direction: str):
self._battle.add_action(self._add_conditions(Action(ActionType.Deploy, self._name, location, direction)))
def use_skill(self):
self._battle.add_action(self._add_conditions(Action(ActionType.Skill, self._name)))
def retreat(self):
self._battle.add_action(self._add_conditions(Action(ActionType.Retreat, self._name)))
def _add_conditions(self, action: Action) -> Action:
if self._pre_delay != 0:
action._pre_delay = self._pre_delay
if self._rear_delay != 0:
action._rear_delay = self._rear_delay
if self._wait_kills != 0:
action._kills = self._wait_kills
if self._cost_changes != 0:
action._cost_changes = self._cost_changes
self._clear_conditions()
return action
def _clear_conditions(self):
self._pre_delay = 0
self._rear_delay = 0
self._wait_kills = 0
self._cost_changes = 0
def to_dict(self) -> dict:
# 此处不应该被执行到
raise Exception("请使用子类方法")
class Group(OperatorOrGroup):
def __init__(self, name: str, battle: Battle, operators: tuple):
"""
请使用 Battle.create_group()
:param name:
:param battle:
:param operators:
"""
super().__init__(name, battle)
self._operators = operators
def to_dict(self) -> dict:
return {
"name": self._name,
"opers": [operator.to_dict() for operator in self._operators]
}
class Operator(OperatorOrGroup):
def __init__(self, name: str, battle: Battle, skill: int, skill_usage: int = SkillUsageType.NotAutoUse,
requirements: Requirements = None):
"""
仅当要创建群组时才应该被调用
正常使用请用 Battle.create_operator()
:param name:
:param battle:
:param skill:
:param skill_usage:
:param requirements:
"""
super().__init__(name, battle)
self._requirements = requirements
self._skill_usage = skill_usage
self._skill = skill
def skill_usage_change(self, change_to: int):
"""
改变技能使用的类型
由于需要兼容群组类型,有时此方法可能无法通过代码提示调用,手动调用即可
:param change_to: 需要调整到的 SkillUsageType
:return:
"""
self._battle.add_action(self._add_conditions(Action(ActionType.SkillUsage, skill_usage=change_to)))
def to_dict(self) -> dict:
res = {
"name": self._name,
"skill": self._skill,
"skill_usage": self._skill_usage,
}
if self._skill_usage != SkillUsageType.NotAutoUse:
res["skill_usage"] = self._skill_usage
if self._requirements is not None:
res["requirements"] = self._requirements.to_dict()
return res
class Battle:
def __init__(self, stage_name: str, version="v4.0", doc: Document = None):
self._doc = doc
self._stage_name = stage_name
self._version = version
self._operators = []
self._groups = []
self._actions = []
self._wait_times = 0
self._wait_kills = 0
self._speedup = False
self._last_save_file_name = "battle.json"
def create_operator(self, name: str, skill: int, skill_usage: int = SkillUsageType.NotAutoUse,
requirements: Requirements = None) -> Operator:
"""
创建并添加一个干员
:param name: 干员名称
:param skill: 要使用的技能
:param skill_usage: 技能使用类型 参见 SkillUsageType
:param requirements: 可选
:return: 新生成的干员
"""
new_operator = Operator(name, self, skill, skill_usage, requirements)
self._add_operator(new_operator)
return new_operator
def create_group(self, name: str, *operators: Operator) -> Group:
"""
创建并添加一个群组
:param name: 群组名
:param operators: 所包含的干员,构造的时候 battle 一项置 None 即可
:return: 新创建的群组
"""
new_group = Group(name, self, operators)
self._add_group(new_group)
return new_group
def _add_operator(self, operator: Operator):
self._operators.append(operator)
def _add_group(self, group: Group):
self._groups.append(group)
def add_action(self, action: Action):
self._actions.append(action)
def speed_up(self):
"""
调整为二倍速
:return:
"""
if not self._speedup:
self._speed_change()
self._speedup = True
def speed_down(self):
"""
调整为一倍速
:return:
"""
if self._speedup:
self._speed_change()
self._speedup = False
def _speed_change(self):
self.add_action(Action(ActionType.SpeedUp))
def save_as_json(self, file_name: str = None):
"""
保存为 json 文件,生成在同目录下
:param file_name: 要保存的文件名
:return:
"""
if file_name is None:
file_name = self._last_save_file_name
else:
self._last_save_file_name = file_name
with open(file_name, 'w', encoding='utf-8') as f:
json.dump(self.to_dict(), f, ensure_ascii=False)
def to_dict(self) -> dict:
res = {
"stage_name": self._stage_name,
"minimum_required": self._version,
"opers": [operator.to_dict() for operator in self._operators],
"groups": [group.to_dict() for group in self._groups],
"actions": [action.to_dict() for action in self._actions],
}
if self._doc is not None:
res["doc"] = self._doc.to_dict()
return res
def test(self, enable_debug_output: bool = True):
"""
自动调用 MeoAssistantArknights 并测试生成自动战斗的文件
测试的是上次生成的 json 需先调用 save_as_json()
请自行配置 MeoAssistantArknights 所在地址等
同时确保能导入 asst.py
:param enable_debug_output: 是否开启 debug 输出
:return:
"""
# MeoAssistantArknights所在的路径
mma_path = "D:\\Program Files\\MeoAssistantArknights"
# adb的路径
adb_path = "D:\\Program Files\\MeoAssistantArknights\\platform-tools\\adb.exe"
# adb连接的地址
adb_address = "127.0.0.1:8873"
try:
from asst import Asst, Message
except ImportError:
import sys
import pathlib
sys.path.append(str(pathlib.Path.cwd().parent.parent / "src" / "Python"))
try:
from asst import Asst, Message
except ImportError:
print("asst导入失败请自行解决或者下载"
" https://github.com/MaaAssistantArknights/MaaAssistantArknights/blob/master/src/Python/asst.py "
"到同目录下")
return
@Asst.CallBackType
def callback(msg, details, arg):
print(Message(msg), json.loads(details.decode('utf-8')), arg)
if not Asst.load(mma_path):
print("加载MeoAssistantArknights失败请确定路径是否正确")
asst = Asst(callback) if enable_debug_output else Asst()
if asst.connect(adb_path, adb_address):
print('连接成功')
else:
print('连接失败')
print('请检查adb地址或者端口是否有误')
exit()
asst.append_task('Copilot', {
'stage_name': self._stage_name,
'filename': self._last_save_file_name,
'formation': False,
})
asst.start()
while True:
if "stop" == str(input('>')):
exit()