生物素材
@@ -20,6 +20,7 @@
|
||||
<field name="trait">均衡型。各项能力标准,无特殊被动,适合新手。</field>
|
||||
<field name="sequence">10</field>
|
||||
<field name="active">1</field>
|
||||
<field name="category">sentient</field>
|
||||
</record>
|
||||
<record id="world_race_demon" model="yt.world.race">
|
||||
<field name="code">demon</field>
|
||||
@@ -40,6 +41,7 @@
|
||||
<field name="trait">均衡型。无特殊被动,与人类齐平的基础战力。</field>
|
||||
<field name="sequence">20</field>
|
||||
<field name="active">1</field>
|
||||
<field name="category">sentient</field>
|
||||
</record>
|
||||
<record id="world_race_dwarf" model="yt.world.race">
|
||||
<field name="code">dwarf</field>
|
||||
@@ -200,5 +202,112 @@
|
||||
<field name="trait">均衡型。眼中发光的岩石巨像,无特殊被动,基础战力与人类一致。</field>
|
||||
<field name="sequence">100</field>
|
||||
<field name="active">1</field>
|
||||
<field name="category">sentient</field>
|
||||
</record>
|
||||
<!-- 非智慧生物(牲畜/家禽):category=animal,不会主动捡宝箱 -->
|
||||
<record id="world_race_cow" model="yt.world.race">
|
||||
<field name="code">cow</field>
|
||||
<field name="name">牛</field>
|
||||
<field name="icon">🐄</field>
|
||||
<field name="sprite_walk">assets/characters/cow/cow_walk_1x6.png</field>
|
||||
<field name="sprite_idle">assets/characters/cow/cow_idle_attack_1x6.png</field>
|
||||
<field name="sprite_work">assets/characters/cow/cow_work_comm_1x6.png</field>
|
||||
<field name="hp_max">30</field>
|
||||
<field name="energy_max">80</field>
|
||||
<field name="attack">2</field>
|
||||
<field name="defense">2</field>
|
||||
<field name="speed">50</field>
|
||||
<field name="attack_range">30</field>
|
||||
<field name="regen">0</field>
|
||||
<field name="enrage">0</field>
|
||||
<field name="shield_ratio">0.0</field>
|
||||
<field name="trait">家畜。体型大、移动慢,产肉产奶。</field>
|
||||
<field name="sequence">110</field>
|
||||
<field name="active">1</field>
|
||||
<field name="category">animal</field>
|
||||
</record>
|
||||
<record id="world_race_sheep" model="yt.world.race">
|
||||
<field name="code">sheep</field>
|
||||
<field name="name">羊</field>
|
||||
<field name="icon">🐑</field>
|
||||
<field name="sprite_walk">assets/characters/sheep/sheep_walk_1x6.png</field>
|
||||
<field name="sprite_idle">assets/characters/sheep/sheep_idle_attack_1x6.png</field>
|
||||
<field name="sprite_work">assets/characters/sheep/sheep_work_comm_1x6.png</field>
|
||||
<field name="hp_max">20</field>
|
||||
<field name="energy_max">60</field>
|
||||
<field name="attack">1</field>
|
||||
<field name="defense">1</field>
|
||||
<field name="speed">70</field>
|
||||
<field name="attack_range">20</field>
|
||||
<field name="regen">0</field>
|
||||
<field name="enrage">0</field>
|
||||
<field name="shield_ratio">0.0</field>
|
||||
<field name="trait">家畜。温顺群居,产毛产肉。</field>
|
||||
<field name="sequence">115</field>
|
||||
<field name="active">1</field>
|
||||
<field name="category">animal</field>
|
||||
</record>
|
||||
<record id="world_race_chicken" model="yt.world.race">
|
||||
<field name="code">chicken</field>
|
||||
<field name="name">鸡</field>
|
||||
<field name="icon">🐔</field>
|
||||
<field name="sprite_walk">assets/characters/chicken/chicken_walk_1x6.png</field>
|
||||
<field name="sprite_idle">assets/characters/chicken/chicken_idle_attack_1x6.png</field>
|
||||
<field name="sprite_work">assets/characters/chicken/chicken_work_comm_1x6.png</field>
|
||||
<field name="hp_max">10</field>
|
||||
<field name="energy_max">40</field>
|
||||
<field name="attack">1</field>
|
||||
<field name="defense">1</field>
|
||||
<field name="speed">100</field>
|
||||
<field name="attack_range">15</field>
|
||||
<field name="regen">0</field>
|
||||
<field name="enrage">0</field>
|
||||
<field name="shield_ratio">0.0</field>
|
||||
<field name="trait">家禽。体型小、移动快,产蛋。</field>
|
||||
<field name="sequence">120</field>
|
||||
<field name="active">1</field>
|
||||
<field name="category">animal</field>
|
||||
</record>
|
||||
<record id="world_race_pig" model="yt.world.race">
|
||||
<field name="code">pig</field>
|
||||
<field name="name">猪</field>
|
||||
<field name="icon">🐷</field>
|
||||
<field name="sprite_walk">assets/characters/pig/pig_walk_1x6.png</field>
|
||||
<field name="sprite_idle">assets/characters/pig/pig_idle_attack_1x6.png</field>
|
||||
<field name="sprite_work">assets/characters/pig/pig_work_comm_1x6.png</field>
|
||||
<field name="hp_max">25</field>
|
||||
<field name="energy_max">60</field>
|
||||
<field name="attack">2</field>
|
||||
<field name="defense">2</field>
|
||||
<field name="speed">65</field>
|
||||
<field name="attack_range">25</field>
|
||||
<field name="regen">0</field>
|
||||
<field name="enrage">0</field>
|
||||
<field name="shield_ratio">0.0</field>
|
||||
<field name="trait">家畜。杂食健壮,产肉。</field>
|
||||
<field name="sequence">125</field>
|
||||
<field name="active">1</field>
|
||||
<field name="category">animal</field>
|
||||
</record>
|
||||
<record id="world_race_horse" model="yt.world.race">
|
||||
<field name="code">horse</field>
|
||||
<field name="name">马</field>
|
||||
<field name="icon">🐴</field>
|
||||
<field name="sprite_walk">assets/characters/horse/horse_walk_1x6.png</field>
|
||||
<field name="sprite_idle">assets/characters/horse/horse_idle_attack_1x6.png</field>
|
||||
<field name="sprite_work">assets/characters/horse/horse_work_comm_1x6.png</field>
|
||||
<field name="hp_max">35</field>
|
||||
<field name="energy_max">90</field>
|
||||
<field name="attack">3</field>
|
||||
<field name="defense">3</field>
|
||||
<field name="speed">140</field>
|
||||
<field name="attack_range">40</field>
|
||||
<field name="regen">0</field>
|
||||
<field name="enrage">0</field>
|
||||
<field name="shield_ratio">0.0</field>
|
||||
<field name="trait">家畜。速度最快的动物,可骑乘。</field>
|
||||
<field name="sequence">130</field>
|
||||
<field name="active">1</field>
|
||||
<field name="category">animal</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
@@ -361,6 +361,11 @@ class YtWorldRace(models.Model):
|
||||
trait = fields.Text(string='特性文案')
|
||||
sequence = fields.Integer(string='排序', default=10)
|
||||
active = fields.Boolean(string='启用', default=True)
|
||||
category = fields.Selection(
|
||||
[('sentient', '智慧生物'), ('animal', '非智慧生物')],
|
||||
string='类别', default='sentient',
|
||||
help='智慧生物会主动捡宝箱;非智慧生物(牲畜/家禽)不会。'
|
||||
)
|
||||
|
||||
_sql_constraints = [
|
||||
('uniq_code', 'unique(code)', '种族编码必须唯一'),
|
||||
@@ -394,5 +399,6 @@ class YtWorldRace(models.Model):
|
||||
'shield_ratio': self.shield_ratio,
|
||||
'trait': self.trait or '',
|
||||
'active': self.active,
|
||||
'category': self.category or 'sentient',
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ async function loadRaces() {
|
||||
map[rc.code] = {
|
||||
name: rc.name,
|
||||
icon: rc.icon || '👤',
|
||||
category: rc.category || 'sentient',
|
||||
speed: rc.speed,
|
||||
attack: rc.attack,
|
||||
defense: rc.defense,
|
||||
@@ -100,7 +101,9 @@ function allSheetsLoaded() {
|
||||
}
|
||||
function preloadAllSheets() {
|
||||
Object.keys(RACE_CONFIG).forEach(race => {
|
||||
['walk','idle_attack','work_comm'].forEach(k => loadCharSheet(race, k));
|
||||
const cfg = RACE_CONFIG[race];
|
||||
['walk','idle_attack'].forEach(k => loadCharSheet(race, k));
|
||||
if (cfg.category !== 'animal') loadCharSheet(race, 'work_comm'); // 动物无工作/交流动作
|
||||
});
|
||||
}
|
||||
|
||||
@@ -382,6 +385,9 @@ function clearChars() {
|
||||
function triggerCharAction(charId, action) {
|
||||
const ch = getChar(charId);
|
||||
if (!ch || !CHAR_STATES[action]) return false;
|
||||
const raceCfg = RACE_CONFIG[ch.race];
|
||||
// 非智慧生物(动物)无工作/交流动作,禁止触发
|
||||
if (raceCfg && raceCfg.category === 'animal' && (action === 'work' || action === 'communicate')) return false;
|
||||
ch.state = action;
|
||||
ch.frame = 0;
|
||||
ch.frameT = 0;
|
||||
@@ -531,6 +537,12 @@ function updateChars(dt) {
|
||||
// 原有漫游 / 行走逻辑
|
||||
// 自由移动开关:ch.freeMove !== false 才允许自主漫游(默认开,可被面板按钮关闭)
|
||||
if (ch.freeMove !== false && !ch.selected && ch.state === 'idle') {
|
||||
// 非智慧生物(动物)不捡宝箱,直接走漫游逻辑
|
||||
const raceCfg = RACE_CONFIG[ch.race];
|
||||
const isAnimal = raceCfg && raceCfg.category === 'animal';
|
||||
let goToChest = false;
|
||||
|
||||
if (!isAnimal) {
|
||||
// 宝箱吸引:附近存在活跃宝箱时优先去开启(测试阶段吸引半径全屏)
|
||||
const chests = window.microChests;
|
||||
const c2s = window.microCellToScreen;
|
||||
@@ -553,13 +565,19 @@ function updateChars(dt) {
|
||||
ch._userMove = false;
|
||||
ch.wanderT = 0;
|
||||
ch.trail = [];
|
||||
} else {
|
||||
goToChest = true;
|
||||
}
|
||||
} // end if (!isAnimal) — 动物跳过整段宝箱吸引
|
||||
|
||||
// 漫游逻辑:动物始终走这里;智慧生物在无宝箱时走这里
|
||||
if (!goToChest) {
|
||||
ch.wanderT = (ch.wanderT || 0) + dt;
|
||||
const interval = ch.wanderInterval || (2 + Math.random() * 4);
|
||||
if (ch.wanderT >= interval) {
|
||||
ch.wanderT = 0;
|
||||
ch.wanderInterval = 2 + Math.random() * 4;
|
||||
// 多意图漫游目标:闲逛 / 朝中心 / 远行(带岛内+建筑校验)
|
||||
|
||||
// 动物只做漫游走动(不捡宝箱、不吃草)
|
||||
const target = generateWanderTarget(ch);
|
||||
if (!target) {
|
||||
ch.wanderInterval = 1 + Math.random() * 2; // 找不到就短等重试
|
||||
@@ -699,6 +717,7 @@ function updateChars(dt) {
|
||||
if (st.loop) {
|
||||
ch.frame = (ch.frame + 1) % st.count;
|
||||
} else if (ch.frame >= st.count - 1) {
|
||||
// 非循环动画(attack/work/communicate)播完 → 回 idle
|
||||
ch.state = 'idle';
|
||||
ch.frame = 0;
|
||||
} else {
|
||||
@@ -945,7 +964,8 @@ function updateCharPanel() {
|
||||
const shieldHtml = ch.shieldMax > 0
|
||||
? `<div style="margin-top:5px;color:#8a9aaa;font-size:11px;">🛡 护盾 <b style="color:#37c7f0;">${ch.shield}</b>/${ch.shieldMax}<span style="color:#667;">${ch.shield > 0 ? '' : '(未触发)'}</span></div>`
|
||||
: '';
|
||||
const actions = ['idle', 'attack', 'work', 'communicate'];
|
||||
const isAnimal = rc && rc.category === 'animal';
|
||||
const actions = isAnimal ? ['idle', 'attack'] : ['idle', 'attack', 'work', 'communicate'];
|
||||
const btns = actions.map(a => {
|
||||
const active = ch.state === a ? 'background:#2a4a6a;border-color:#5a9acc;' : '';
|
||||
return `<button class="charActBtn" data-act="${a}" style="${active}background:#1d2b4a;color:#cde;border:1px solid #3a5a8e;padding:5px 10px;border-radius:5px;cursor:pointer;font-size:12px;transition:background .15s;">${CHAR_CN[a]}</button>`;
|
||||
|
||||
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 759 B |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 194 KiB |
|
After Width: | Height: | Size: 166 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 12 KiB |
@@ -2540,7 +2540,7 @@ const MICRO_BUILD_EXTRA = [
|
||||
{ id: 'barracks', cat: 'build', icon: 'assets/buildings/spring/barracks/barracks_l.png?v=9', name: '兵营', desc: '训练士兵与储备武备的军事建筑,提升领地军事产出。', flat: false, w: 3, h: 3, statLevel: 1, statHp: 130, statYield: { military: 4 }, costGold: 130 },
|
||||
{ id: 'guild', cat: 'build', icon: 'assets/buildings/spring/guild/guild_l.png?v=4', name: '公会', desc: '冒险者与住民集结之所,可发布委托与招募成员。', flat: false, w: 2, h: 2, statLevel: 1, statHp: 140, statYield: { prestige: 2, coin: 1 }, costGold: 100 },
|
||||
{ id: 'village', cat: 'build', icon: 'assets/buildings/spring/village/village_l.png?v=5', name: '村庄', desc: '族群聚落的核心,提升人口上限与基础产出。', flat: false, w: 3, h: 3, statLevel: 1, statHp: 150, statYield: { population: 6, food: 1 }, costGold: 200 },
|
||||
// 生物分类:9 种族角色(点击进入"点地面放置"模式,不进入建筑模式)
|
||||
// 生物分类:10 智慧种族 + 5 非智慧动物(点击进入"点地面放置"模式,不进入建筑模式)
|
||||
{ id: 'race_human', cat: 'bio', icon: 'assets/characters/human/human_thumb.png', sprite: 'assets/characters/human/human_idle_attack_1x6.png', name: '人族', isChar: true, race: 'human' },
|
||||
{ id: 'race_demon', cat: 'bio', icon: 'assets/characters/demon/demon_thumb.png', sprite: 'assets/characters/demon/demon_idle_attack_1x6.png', name: '妖族', isChar: true, race: 'demon' },
|
||||
{ id: 'race_dwarf', cat: 'bio', icon: 'assets/characters/dwarf/dwarf_thumb.png', sprite: 'assets/characters/dwarf/dwarf_idle_attack_1x6.png', name: '矮人', isChar: true, race: 'dwarf' },
|
||||
@@ -2551,6 +2551,11 @@ const MICRO_BUILD_EXTRA = [
|
||||
{ id: 'race_angel', cat: 'bio', icon: 'assets/characters/angel/angel_thumb.png', sprite: 'assets/characters/angel/angel_idle_attack_1x6.png', name: '天使', isChar: true, race: 'angel' },
|
||||
{ id: 'race_werewolf',cat: 'bio', icon: 'assets/characters/werewolf/werewolf_thumb.png', sprite: 'assets/characters/werewolf/werewolf_idle_attack_1x6.png', name: '狼人', isChar: true, race: 'werewolf' },
|
||||
{ id: 'race_golem', cat: 'bio', icon: 'assets/characters/golem/golem_thumb.png', sprite: 'assets/characters/golem/golem_idle_attack_1x6.png', name: '石傀儡', isChar: true, race: 'golem' },
|
||||
{ id: 'race_cow', cat: 'bio', icon: 'assets/characters/cow/cow_thumb.png', sprite: 'assets/characters/cow/cow_idle_attack_1x6.png', name: '牛', isChar: true, race: 'cow' },
|
||||
{ id: 'race_sheep', cat: 'bio', icon: 'assets/characters/sheep/sheep_thumb.png', sprite: 'assets/characters/sheep/sheep_idle_attack_1x6.png', name: '羊', isChar: true, race: 'sheep' },
|
||||
{ id: 'race_chicken', cat: 'bio', icon: 'assets/characters/chicken/chicken_thumb.png', sprite: 'assets/characters/chicken/chicken_idle_attack_1x6.png', name: '鸡', isChar: true, race: 'chicken' },
|
||||
{ id: 'race_pig', cat: 'bio', icon: 'assets/characters/pig/pig_thumb.png', sprite: 'assets/characters/pig/pig_idle_attack_1x6.png', name: '猪', isChar: true, race: 'pig' },
|
||||
{ id: 'race_horse', cat: 'bio', icon: 'assets/characters/horse/horse_thumb.png', sprite: 'assets/characters/horse/horse_idle_attack_1x6.png', name: '马', isChar: true, race: 'horse' },
|
||||
];
|
||||
|
||||
// 建筑交互配置(数据驱动,与后端 BUILD_EFFECTS 的 (code,action) 对应)。
|
||||
|
||||