|
|
@@ -67,8 +67,8 @@ class EnemyConfigManager:
|
|
|
raise FileNotFoundError(f"Excel文件不存在: {self.excel_path}")
|
|
|
|
|
|
try:
|
|
|
- # 读取所有工作表
|
|
|
- excel_data = pd.read_excel(self.excel_path, sheet_name=None)
|
|
|
+ # 读取所有工作表,不指定header以保留所有行
|
|
|
+ excel_data = pd.read_excel(self.excel_path, sheet_name=None, header=None)
|
|
|
print(f"找到工作表: {list(excel_data.keys())}")
|
|
|
|
|
|
# 解析各个工作表
|
|
|
@@ -95,9 +95,9 @@ class EnemyConfigManager:
|
|
|
return {}
|
|
|
|
|
|
config = {}
|
|
|
- for index, row in df.iterrows():
|
|
|
- if index == 0: # 跳过标题行
|
|
|
- continue
|
|
|
+ # 从第1行开始处理(跳过第0行标题)
|
|
|
+ for i in range(1, len(df)):
|
|
|
+ row = df.iloc[i]
|
|
|
|
|
|
enemy_id = str(row.iloc[0]).strip()
|
|
|
if pd.isna(row.iloc[0]) or enemy_id == '':
|
|
|
@@ -184,31 +184,36 @@ class EnemyConfigManager:
|
|
|
|
|
|
visual_config = {}
|
|
|
|
|
|
- for _, row in df.iterrows():
|
|
|
- enemy_id = str(row.get('敌人ID', '')).strip()
|
|
|
- if not enemy_id or enemy_id == '敌人ID':
|
|
|
+ for index, row in df.iterrows():
|
|
|
+ if index == 0: # 跳过标题行
|
|
|
+ continue
|
|
|
+
|
|
|
+ enemy_id = str(row.iloc[0]).strip()
|
|
|
+ if pd.isna(row.iloc[0]) or enemy_id == '':
|
|
|
continue
|
|
|
|
|
|
config = {
|
|
|
- 'sprite_path': str(row.get('精灵路径', '')).strip(),
|
|
|
- 'scale': float(row.get('缩放比例', 1.0)),
|
|
|
- 'animation_speed': float(row.get('动画速度', 1.0)),
|
|
|
- 'flip_horizontal': bool(row.get('水平翻转', False)),
|
|
|
+ 'sprite_path': str(row.iloc[1]) if not pd.isna(row.iloc[1]) else '',
|
|
|
+ 'scale': float(row.iloc[2]) if not pd.isna(row.iloc[2]) else 1.0,
|
|
|
+ 'animation_speed': float(row.iloc[3]) if not pd.isna(row.iloc[3]) else 1.0,
|
|
|
+ 'flip_horizontal': bool(row.iloc[4]) if not pd.isna(row.iloc[4]) else False,
|
|
|
'animations': {
|
|
|
- 'idle': str(row.get('待机动画', 'idle')).strip(),
|
|
|
- 'walk': str(row.get('行走动画', 'walk')).strip(),
|
|
|
- 'attack': str(row.get('攻击动画', 'attack')).strip(),
|
|
|
- 'death': str(row.get('死亡动画', 'dead')).strip()
|
|
|
+ 'idle': str(row.iloc[5]) if not pd.isna(row.iloc[5]) else 'idle',
|
|
|
+ 'walk': str(row.iloc[6]) if not pd.isna(row.iloc[6]) else 'walk',
|
|
|
+ 'attack': str(row.iloc[7]) if not pd.isna(row.iloc[7]) else 'attack',
|
|
|
+ 'death': str(row.iloc[8]) if not pd.isna(row.iloc[8]) else 'dead'
|
|
|
}
|
|
|
}
|
|
|
|
|
|
# 武器道具(可选)
|
|
|
- weapon_prop = str(row.get('武器道具', '')).strip()
|
|
|
- if weapon_prop:
|
|
|
- config['weapon_prop'] = weapon_prop
|
|
|
+ if len(row) > 9 and not pd.isna(row.iloc[9]):
|
|
|
+ weapon_prop = str(row.iloc[9]).strip()
|
|
|
+ if weapon_prop:
|
|
|
+ config['weapon_prop'] = weapon_prop
|
|
|
|
|
|
visual_config[enemy_id] = config
|
|
|
|
|
|
+ print(f"解析视觉配置: {len(visual_config)} 个敌人")
|
|
|
return visual_config
|
|
|
|
|
|
def _parse_audio_config(self, df):
|
|
|
@@ -218,33 +223,24 @@ class EnemyConfigManager:
|
|
|
|
|
|
audio_config = {}
|
|
|
|
|
|
- for _, row in df.iterrows():
|
|
|
- enemy_id = str(row.get('敌人ID', '')).strip()
|
|
|
- if not enemy_id or enemy_id == '敌人ID':
|
|
|
+ for index, row in df.iterrows():
|
|
|
+ if index == 0: # 跳过标题行
|
|
|
+ continue
|
|
|
+
|
|
|
+ enemy_id = str(row.iloc[0]).strip()
|
|
|
+ if pd.isna(row.iloc[0]) or enemy_id == '':
|
|
|
continue
|
|
|
|
|
|
config = {
|
|
|
- 'attack_sound': str(row.get('攻击音效', '')).strip(),
|
|
|
- 'death_sound': str(row.get('死亡音效', '')).strip(),
|
|
|
- 'hit_sound': str(row.get('受击音效', '')).strip(),
|
|
|
- 'walk_sound': str(row.get('行走音效', '')).strip()
|
|
|
+ 'attack_sound': str(row.iloc[1]) if not pd.isna(row.iloc[1]) else '',
|
|
|
+ 'death_sound': str(row.iloc[2]) if not pd.isna(row.iloc[2]) else '',
|
|
|
+ 'hit_sound': str(row.iloc[3]) if not pd.isna(row.iloc[3]) else '',
|
|
|
+ 'walk_sound': str(row.iloc[4]) if not pd.isna(row.iloc[4]) else ''
|
|
|
}
|
|
|
|
|
|
- # 可选音效
|
|
|
- optional_sounds = {
|
|
|
- 'block_sound': '格挡音效',
|
|
|
- 'stealth_sound': '隐身音效',
|
|
|
- 'armor_break_sound': '护甲破碎音效',
|
|
|
- 'fuse_sound': '引信音效'
|
|
|
- }
|
|
|
-
|
|
|
- for key, col_name in optional_sounds.items():
|
|
|
- sound = str(row.get(col_name, '')).strip()
|
|
|
- if sound:
|
|
|
- config[key] = sound
|
|
|
-
|
|
|
audio_config[enemy_id] = config
|
|
|
|
|
|
+ print(f"解析音频配置: {len(audio_config)} 个敌人")
|
|
|
return audio_config
|
|
|
|
|
|
def _parse_special_abilities(self, df):
|
|
|
@@ -254,12 +250,15 @@ class EnemyConfigManager:
|
|
|
|
|
|
abilities_config = {}
|
|
|
|
|
|
- for _, row in df.iterrows():
|
|
|
- enemy_id = str(row.get('敌人ID', '')).strip()
|
|
|
- if not enemy_id or enemy_id == '敌人ID':
|
|
|
+ for index, row in df.iterrows():
|
|
|
+ if index == 0: # 跳过标题行
|
|
|
+ continue
|
|
|
+
|
|
|
+ enemy_id = str(row.iloc[0]).strip()
|
|
|
+ if pd.isna(row.iloc[0]) or enemy_id == '':
|
|
|
continue
|
|
|
|
|
|
- ability_type = str(row.get('能力类型', '')).strip()
|
|
|
+ ability_type = str(row.iloc[1]).strip() if not pd.isna(row.iloc[1]) else ''
|
|
|
if not ability_type:
|
|
|
# 没有特殊能力的敌人
|
|
|
if enemy_id not in abilities_config:
|
|
|
@@ -268,15 +267,16 @@ class EnemyConfigManager:
|
|
|
|
|
|
ability = {
|
|
|
'type': ability_type,
|
|
|
- 'damage': int(row.get('伤害', 0)),
|
|
|
- 'range': int(row.get('范围', 0)),
|
|
|
- 'cooldown': int(row.get('冷却时间', 0))
|
|
|
+ 'damage': int(row.iloc[2]) if not pd.isna(row.iloc[2]) else 0,
|
|
|
+ 'range': int(row.iloc[3]) if not pd.isna(row.iloc[3]) else 0,
|
|
|
+ 'cooldown': int(row.iloc[4]) if not pd.isna(row.iloc[4]) else 0
|
|
|
}
|
|
|
|
|
|
if enemy_id not in abilities_config:
|
|
|
abilities_config[enemy_id] = []
|
|
|
abilities_config[enemy_id].append(ability)
|
|
|
|
|
|
+ print(f"解析特殊能力配置: {len(abilities_config)} 个敌人")
|
|
|
return abilities_config
|
|
|
|
|
|
def _parse_boss_config(self, df):
|
|
|
@@ -286,21 +286,25 @@ class EnemyConfigManager:
|
|
|
|
|
|
boss_config = {}
|
|
|
|
|
|
- for _, row in df.iterrows():
|
|
|
- enemy_id = str(row.get('敌人ID', '')).strip()
|
|
|
- if not enemy_id or enemy_id == '敌人ID':
|
|
|
+ for index, row in df.iterrows():
|
|
|
+ if index == 0: # 跳过标题行
|
|
|
+ continue
|
|
|
+
|
|
|
+ enemy_id = str(row.iloc[0]).strip()
|
|
|
+ if pd.isna(row.iloc[0]) or enemy_id == '':
|
|
|
continue
|
|
|
|
|
|
config = {
|
|
|
- 'is_boss': bool(row.get('是否BOSS', False)),
|
|
|
- 'phases': int(row.get('阶段数', 1)),
|
|
|
- 'rage_threshold': float(row.get('狂暴阈值', 0.3)),
|
|
|
- 'rage_damage_multiplier': float(row.get('狂暴伤害倍数', 1.0)),
|
|
|
- 'rage_speed_multiplier': float(row.get('狂暴速度倍数', 1.0))
|
|
|
+ 'is_boss': bool(row.iloc[1]) if not pd.isna(row.iloc[1]) else False,
|
|
|
+ 'phases': int(row.iloc[2]) if not pd.isna(row.iloc[2]) else 1,
|
|
|
+ 'rage_threshold': float(row.iloc[3]) if not pd.isna(row.iloc[3]) else 0.3,
|
|
|
+ 'rage_damage_multiplier': float(row.iloc[4]) if not pd.isna(row.iloc[4]) else 1.0,
|
|
|
+ 'rage_speed_multiplier': float(row.iloc[5]) if not pd.isna(row.iloc[5]) else 1.0
|
|
|
}
|
|
|
|
|
|
boss_config[enemy_id] = config
|
|
|
|
|
|
+ print(f"解析BOSS配置: {len(boss_config)} 个敌人")
|
|
|
return boss_config
|
|
|
|
|
|
def merge_configurations(self):
|
|
|
@@ -314,7 +318,7 @@ class EnemyConfigManager:
|
|
|
|
|
|
# 获取所有Excel中的敌人ID
|
|
|
excel_enemy_ids = set()
|
|
|
- for config_type in ['basic', 'combat', 'movement', 'visual', 'audio', 'special_abilities', 'boss']:
|
|
|
+ for config_type in ['basic', 'combat', 'movement', 'visual', 'audio', 'special', 'boss']:
|
|
|
if config_type in self.excel_data:
|
|
|
excel_enemy_ids.update(self.excel_data[config_type].keys())
|
|
|
|
|
|
@@ -435,8 +439,8 @@ class EnemyConfigManager:
|
|
|
enemy_config['audio'][key] = value
|
|
|
|
|
|
# 更新特殊能力配置
|
|
|
- if 'special_abilities' in self.excel_data and enemy_id in self.excel_data['special_abilities']:
|
|
|
- abilities_data = self.excel_data['special_abilities'][enemy_id]
|
|
|
+ if 'special' in self.excel_data and enemy_id in self.excel_data['special']:
|
|
|
+ abilities_data = self.excel_data['special'][enemy_id]
|
|
|
|
|
|
if 'special_abilities' not in enemy_config:
|
|
|
enemy_config['special_abilities'] = []
|