From f5c7ea4ddf53a35bb2942bb2ce9a47e321f2e781 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?=
Date: Thu, 23 Jul 2026 18:53:54 +0800
Subject: [PATCH] =?UTF-8?q?1.=E4=B8=96=E7=95=8C=E7=AD=89=E7=BA=A7=E4=BA=94?=
=?UTF-8?q?=E4=B8=AA=E9=98=B6=E6=AE=B5=EF=BC=8C=E8=87=AA=E5=B7=B1=E6=83=B3?=
=?UTF-8?q?=E5=8A=9E=E6=B3=95=E5=91=BD=E5=90=8D=E5=92=8C=E8=AE=BE=E8=AE=A1?=
=?UTF-8?q?=202.=E5=8A=BF=E5=8A=9B=E7=AD=89=E7=BA=A7=E5=88=86=E4=B8=BA6?=
=?UTF-8?q?=E4=B8=AA=203.=E4=BA=BA=E7=89=A9=E8=A7=92=E8=89=B2=E7=AD=89?=
=?UTF-8?q?=E7=BA=A7=E5=88=86=E4=B8=BA14=E4=B8=AA=204.=E8=B4=A7=E5=B8=81?=
=?UTF-8?q?=E4=B9=9F=E5=88=86=E4=B8=BA6=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
一个背景的菜单栏。
写特色,介绍,背景,说明,致玩家等等
---
addons/game_base/controllers/game_api.py | 58 +++++-
addons/game_base/data/game_base_data.xml | 187 +++++++++++++++---
addons/game_base/models/__init__.py | 2 +
addons/game_base/models/currency.py | 42 ++++
addons/game_base/security/ir.model.access.csv | 6 +
addons/game_base/views/game_base_views.xml | 62 ++++++
assets/game-api.js | 49 +++--
assets/site-app.js | 40 +++-
index.html | 68 +++++--
website/demo.html | 1 -
website/index.html | 1 -
website/intro.html | 1 -
website/platform.html | 1 -
website/races.html | 1 -
website/world.html | 1 -
15 files changed, 458 insertions(+), 62 deletions(-)
create mode 100644 addons/game_base/models/currency.py
diff --git a/addons/game_base/controllers/game_api.py b/addons/game_base/controllers/game_api.py
index 6917d2b..444330d 100644
--- a/addons/game_base/controllers/game_api.py
+++ b/addons/game_base/controllers/game_api.py
@@ -5,11 +5,19 @@ from odoo.http import request, Response
def _json(data):
- """返回 UTF-8 JSON 响应。"""
- return Response(
+ """返回 UTF-8 JSON 响应,并附加本地跨域调试头。"""
+ origin = request.httprequest.headers.get('Origin', '')
+ resp = Response(
json.dumps(data, ensure_ascii=False),
content_type='application/json; charset=utf-8',
)
+ # 允许 127.0.0.1:8888 本地前端跨域调试(生产环境走 nginx 同域,无需此头)
+ if origin.startswith('http://127.0.0.1:') or origin.startswith('http://localhost:'):
+ resp.headers['Access-Control-Allow-Origin'] = origin
+ resp.headers['Access-Control-Allow-Credentials'] = 'true'
+ resp.headers['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
+ resp.headers['Access-Control-Allow-Headers'] = 'Content-Type'
+ return resp
def _post_body():
@@ -76,6 +84,52 @@ class GameApiController(http.Controller):
})
return _json({'groups': groups})
+ @http.route('/game/api/currencies', type='http', auth='public', methods=['GET'], csrf=False)
+ def currencies(self, **kw):
+ """货币等级:按 level 排序返回。"""
+ recs = request.env['game.currency'].sudo().search_read(
+ [], ['id', 'level', 'name', 'desc', 'rate'], order='level asc'
+ )
+ return _json({
+ 'items': [{
+ 'id': r['id'],
+ 'level': r['level'],
+ 'name': r['name'],
+ 'desc': r['desc'] or '',
+ 'rate': r['rate'] or 1,
+ } for r in recs]
+ })
+
+ @http.route('/game/api/pages', type='http', auth='public', methods=['GET'], csrf=False)
+ def pages(self, **kw):
+ """页面板块:返回所有生效板块及其条目。"""
+ pages = request.env['game.page'].sudo().search_read(
+ [('active', '=', True)],
+ ['id', 'key', 'title', 'subtitle', 'body_html'],
+ order='sequence asc'
+ )
+ out = []
+ for p in pages:
+ items = request.env['game.page.item'].sudo().search_read(
+ [('page_id', '=', p['id'])],
+ ['id', 'icon', 'title', 'desc'],
+ order='sequence asc'
+ )
+ out.append({
+ 'id': p['id'],
+ 'key': p['key'],
+ 'title': p['title'],
+ 'subtitle': p.get('subtitle') or '',
+ 'body_html': p.get('body_html') or '',
+ 'items': [{
+ 'id': it['id'],
+ 'icon': it.get('icon') or '',
+ 'title': it.get('title') or '',
+ 'desc': it.get('desc') or '',
+ } for it in items],
+ })
+ return _json({'items': out})
+
@http.route('/game/api/threads', type='http', auth='public', methods=['GET'], csrf=False)
def threads(self, **kw):
"""论坛主题(含回复),按置顶+时间排序。"""
diff --git a/addons/game_base/data/game_base_data.xml b/addons/game_base/data/game_base_data.xml
index fbf7460..9e589ad 100644
--- a/addons/game_base/data/game_base_data.xml
+++ b/addons/game_base/data/game_base_data.xml
@@ -4,50 +4,50 @@
- world1蒙昧
-
+ world1凡墟
+
- world2聚落
-
+ world2灵启
+
- world3王国
-
+ world3玄界
+
- world4文明
-
+ world4穹冥
+
- world5飞升
-
+ world5溯元
+
- faction1部族
-
+ faction1墟族
+
- faction2城邦
-
+ faction2灵聚
+
- faction3公国
-
+ faction3玄邑
+
- faction4王国
-
+ faction4冥朝
+
- faction5帝国
-
+ faction5穹统
+
- faction6星盟
-
+ faction6溯盟
+
@@ -64,6 +64,32 @@
character11圣者
character12永恒
+
+
+ 1墟铢100
+
+
+
+ 2灵币100
+
+
+
+ 3玄锭100
+
+
+
+ 4冥玉100
+
+
+
+ 5穹鎏100
+
+
+
+ 6元玺1
+
+
+
race龙裔龙裔传说
@@ -106,4 +132,121 @@
宇森官网第一阶段上线:介绍 / 规则 / 图鉴 / 论坛 / 公告 五块,单页切换呈现。欢迎园丁们入驻。
]]>
+
+
+
+ features
+ 游戏特色
+ CORE FEATURES
+ 10
+
+
+
+ 10
+ 🌐
+ 垂直五层世界
+ 从地心熔岩到陨石星空,文明在五个垂直切面中同时生长,每一层都有独立的生态、资源与事件池。
+
+
+
+ 20
+ 🌱
+ 自发演化
+ 不是脚本,不是关卡。文明自己生长、分裂、兼并、飞升——每一次开局都是一部独一无二的编年史。
+
+
+
+ 30
+ 🧑🌾
+ 园丁视角
+ 你不是英雄,也不是上帝。你是园丁——播种灵气、引导势力、守望文明,在关键节点轻推一把,让世界自洽前行。
+
+
+
+ 40
+ ⚖️
+ 三维等级联动
+ 世界等级定舞台上限,势力等级定群体进度,角色等级定个体极限。三者交叉构成无限策略空间。
+
+
+
+ 50
+ 💰
+ 六档货币体系
+ 从墟铢到元玺,百进制兑换贯穿五层世界。跨层贸易、资源调度、神器交易构成完整经济闭环。
+
+
+
+ 60
+ 🎭
+ 活的个体
+ 每个 NPC 都有独立的天赋、性格与成长轨迹。英雄在历练中觉醒,传奇在时间中自发生成,无人是棋子。
+
+
+
+
+ background
+ 世界起源
+ BACKGROUND
+ 20
+ 天地初开,混沌未分。一缕灵气自地心涌出,沿垂直切面向上攀爬——穿透岩层、跨越地表、掠过云海、直抵星空。五层世界自此苏醒。
+地表层最先活过来。灵气稀薄,但足够点燃文明的火种。各族散居荒野,狩猎采集,以血缘结群,在蒙昧的凡土上挣扎求生。这是凡墟。
+而后灵气渐浓,天地共振。聚落涌现,分工萌芽,物物交换催生最早的势力。灵启的时代,文明开始有了形状。
+再往后,是兼并、是征伐、是道统与造物的竞逐。玄界的大地上,多元族群共治的完整疆域成形,传奇事件如潮涌来。
+直到有一天,有人掘穿了地表之下的黑暗,有人驾着浮空石飞上了云海。地下深渊与浩瀚星空同时向文明敞开——穹冥时代,天地上下尽数纳入管辖。
+最终,顶尖文明勘破了这片天地的诞生本源。他们追溯灵气的源头,在地心深处找到了答案。飞升、轮回、更高维度的演化实验——溯元,不是终点,而是新的起点。
+而你,是这一切的园丁。
]]>
+
+
+
+ 10
+ ✦
+ 星空层
+ 陨石科技带 · 穹鎏产地
+
+
+
+ 20
+ ✦
+ 天空层
+ 云朵地基块 · 浮空城邦
+
+
+
+ 30
+ ✦
+ 地表层
+ 文明发源地 · 主舞台
+
+
+
+ 40
+ ✦
+ 地下层
+ 矿脉深渊 · 冥玉产地
+
+
+
+ 50
+ ✦
+ 地心层
+ 本源之地 · 元玺凝聚
+
+
+
+
+ letter
+ 致园丁
+ A LETTER TO GARDENERS
+ 30
+ 致每一位踏入宇森的园丁:
+感谢你来到这里。
+宇森不是一款传统的策略游戏。这里没有关卡,没有通关,没有固定的胜利条件。我们想做的,是一个会自己呼吸的世界——你播下一颗种子,它自己长成一片森林;你引导一个族群,它自己走出一段历史。
+你是园丁,不是上帝。你不能命令谁去做什么,但你可以改变土壤、调节灵气、在关键节点轻轻推一把。文明的走向由无数个体的选择汇聚而成,而你只是其中一股温柔的力。
+这个世界有五层。从地心到星空,每一层都有自己的生态和故事。文明会从地表的凡墟开始,一路向上向下生长,直到触及世界的本源。这个过程可能很慢,也可能充满意外——但那正是我们想要的。
+我们还在生长。宇森目前处于早期阶段,很多系统仍在打磨。但你看到的每一个种族、每一件神器、每一段传奇事件,都是这个世界真实存在的一部分。它们会随着版本的推进越来越厚,越来越活。
+如果你在这里找到了哪怕一刻的沉浸感,那就是我们最大的成功。
+欢迎播种。
]]>
+
+
diff --git a/addons/game_base/models/__init__.py b/addons/game_base/models/__init__.py
index 1e5fe2a..ebfc125 100644
--- a/addons/game_base/models/__init__.py
+++ b/addons/game_base/models/__init__.py
@@ -2,3 +2,5 @@ from . import codex
from . import forum
from . import announcement
from . import rule
+from . import currency
+from . import page
diff --git a/addons/game_base/models/currency.py b/addons/game_base/models/currency.py
new file mode 100644
index 0000000..4e4e0fd
--- /dev/null
+++ b/addons/game_base/models/currency.py
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+from odoo import models, fields, api
+
+
+class GameCurrency(models.Model):
+ _name = 'game.currency'
+ _description = '游戏货币等级'
+ _order = 'level asc'
+
+ level = fields.Integer(string='等级', required=True)
+ name = fields.Char(string='名称', required=True)
+ desc = fields.Text(string='描述')
+ rate = fields.Integer(
+ string='兑换比例',
+ default=1,
+ help='多少单位本货币可兑换 1 单位下一等级货币。例如 100 墟铢 = 1 灵币,则墟铢的 rate 为 100。'
+ )
+
+ @api.model
+ def convert(self, amount, from_level, to_level):
+ """按等级汇率将 amount 从 from_level 换算为 to_level 货币。
+
+ 汇率方向:低等级 → 高等级 为除以 rate,高等级 → 低等级 为乘以 rate。
+ 最高等级货币(元玺)的 rate 固定为 1,仅作占位。
+ """
+ if from_level == to_level:
+ return amount
+ currencies = self.search_read([], ['level', 'rate'], order='level asc')
+ rate_map = {c['level']: c['rate'] or 1 for c in currencies}
+
+ if from_level < to_level:
+ # 低等级 → 高等级:逐级除以兑换比例
+ result = amount
+ for lv in range(from_level, to_level):
+ result = result / rate_map.get(lv, 1)
+ return result
+ else:
+ # 高等级 → 低等级:逐级乘以兑换比例
+ result = amount
+ for lv in range(to_level, from_level):
+ result = result * rate_map.get(lv, 1)
+ return result
diff --git a/addons/game_base/security/ir.model.access.csv b/addons/game_base/security/ir.model.access.csv
index 6dca7cf..b8bb0c4 100644
--- a/addons/game_base/security/ir.model.access.csv
+++ b/addons/game_base/security/ir.model.access.csv
@@ -9,3 +9,9 @@ access_game_announcement,game.announcement public,model_game_announcement,base.g
access_game_announcement_user,game.announcement user,model_game_announcement,base.group_user,1,1,1,1
access_game_rule,game.rule public,model_game_rule,base.group_public,1,0,0,0
access_game_rule_user,game.rule user,model_game_rule,base.group_user,1,1,1,1
+access_game_currency,game.currency public,model_game_currency,base.group_public,1,0,0,0
+access_game_currency_user,game.currency user,model_game_currency,base.group_user,1,1,1,1
+access_game_page,game.page public,model_game_page,base.group_public,1,0,0,0
+access_game_page_user,game.page user,model_game_page,base.group_user,1,1,1,1
+access_game_page_item,game.page.item public,model_game_page_item,base.group_public,1,0,0,0
+access_game_page_item_user,game.page.item user,model_game_page_item,base.group_user,1,1,1,1
diff --git a/addons/game_base/views/game_base_views.xml b/addons/game_base/views/game_base_views.xml
index 90a90fd..503195f 100644
--- a/addons/game_base/views/game_base_views.xml
+++ b/addons/game_base/views/game_base_views.xml
@@ -60,6 +60,68 @@
+
+
+ 货币等级
+ game.currency
+ list,form
+
+
+
+ game.currency.list
+ game.currency
+
+
+
+
+
+ game.currency.form
+ game.currency
+
+
+
+
+
+
+
+ 页面板块
+ game.page
+ list,form
+
+
+
+ game.page.list
+ game.page
+
+
+
+
+
+
+
+ game.page.form
+ game.page
+
+
+
+
+
diff --git a/assets/game-api.js b/assets/game-api.js
index d114327..f047e6d 100644
--- a/assets/game-api.js
+++ b/assets/game-api.js
@@ -1,42 +1,61 @@
// 宇森游戏 · 前端与 Odoo 通信层
-// 所有接口同源(yt.pengyuthon.cn),由 nginx 代理 /game/* 到 Odoo(game 库)。
-// 关键点:Odoo 通过 URL 上的 ?db=game 选定数据库(与 game.conf 的 /web/login?db=game 一致),
-// 否则请求到达时未选中库,控制器路由找不到 → 404。因此所有调用都带 ?db=game。
-// 登录态通过 Odoo session cookie 保持,fetch 带 credentials:'same-origin'。
+// 本地调试:前端 8888 -> Odoo 8069(跨域,带调试 CORS 头)
+// 生产部署:前端与 Odoo 同域,由 nginx 代理 /game/*。
+
+const API_CONFIG = {
+ base: (location.hostname === '127.0.0.1' && location.port === '8888')
+ ? 'http://127.0.0.1:8069'
+ : (location.hostname === 'localhost' && location.port === '8888')
+ ? 'http://127.0.0.1:8069'
+ : '',
+ db: (location.hostname === '127.0.0.1' && location.port === '8888') ? 'study' : 'game',
+};
+
+const _cred = API_CONFIG.base ? 'include' : 'same-origin';
+
+function _url(path) {
+ return `${API_CONFIG.base}${path}?db=${API_CONFIG.db}`;
+}
const API = {
async me() {
- return (await fetch('/game/api/me?db=game', { credentials: 'same-origin' })).json();
+ return (await fetch(_url('/game/api/me'), { credentials: _cred })).json();
},
async login(login, password) {
- return (await fetch('/game/api/login?db=game', {
- method: 'POST', credentials: 'same-origin',
+ return (await fetch(_url('/game/api/login'), {
+ method: 'POST', credentials: _cred,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ login, password }),
})).json();
},
async register(payload) {
- return (await fetch('/game/api/register?db=game', {
- method: 'POST', credentials: 'same-origin',
+ return (await fetch(_url('/game/api/register'), {
+ method: 'POST', credentials: _cred,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
})).json();
},
async logout() {
- return (await fetch('/game/api/logout?db=game', {
- method: 'POST', credentials: 'same-origin',
+ return (await fetch(_url('/game/api/logout'), {
+ method: 'POST', credentials: _cred,
})).json();
},
async codex() {
- return (await fetch('/game/api/codex?db=game', { credentials: 'same-origin' })).json();
+ return (await fetch(_url('/game/api/codex'), { credentials: _cred })).json();
},
async rules() {
- return (await fetch('/game/api/rules?db=game', { credentials: 'same-origin' })).json();
+ return (await fetch(_url('/game/api/rules'), { credentials: _cred })).json();
+ },
+ async currencies() {
+ return (await fetch(_url('/game/api/currencies'), { credentials: _cred })).json();
+ },
+ async pages() {
+ return (await fetch(_url('/game/api/pages'), { credentials: _cred })).json();
},
async threads() {
- return (await fetch('/game/api/threads?db=game', { credentials: 'same-origin' })).json();
+ return (await fetch(_url('/game/api/threads'), { credentials: _cred })).json();
},
async announcements() {
- return (await fetch('/game/api/announcements?db=game', { credentials: 'same-origin' })).json();
+ return (await fetch(_url('/game/api/announcements'), { credentials: _cred })).json();
},
};
diff --git a/assets/site-app.js b/assets/site-app.js
index 2fc071b..a6199d1 100644
--- a/assets/site-app.js
+++ b/assets/site-app.js
@@ -1,6 +1,43 @@
// 宇森官网 · 公开页数据打通(图鉴/规则/论坛/公告 从 Odoo 取数)
// 依赖 assets/game-api.js
+// ---------- 页面板块(特色 / 背景 / 致玩家) ----------
+async function loadPages(){
+ try {
+ const d = await API.pages();
+ const pages = (d && d.items) || [];
+ pages.forEach(p => {
+ if (p.key === 'features') renderFeatures(p);
+ else if (p.key === 'background') renderBackground(p);
+ else if (p.key === 'letter') renderLetter(p);
+ });
+ } catch (e) { /* 失败时保留 HTML 中的静态兜底内容 */ }
+}
+
+function renderFeatures(p){
+ const sec = document.getElementById('features');
+ if (!sec) return;
+ const items = (p.items || []).map(it =>
+ `${it.icon || ''}
${it.title || ''}
${it.desc || ''}
`
+ ).join('');
+ sec.innerHTML = `${p.title || '游戏特色'}${p.subtitle || ''}
${items}
`;
+}
+
+function renderBackground(p){
+ const sec = document.getElementById('background');
+ if (!sec) return;
+ const layers = (p.items || []).map((it, idx) =>
+ `${it.title || ''}
${it.desc || ''}
${it.icon || '✦'} `
+ ).join('');
+ sec.innerHTML = `${layers}
${p.title || '世界起源'}
${p.body_html || ''}`;
+}
+
+function renderLetter(p){
+ const sec = document.getElementById('letter');
+ if (!sec) return;
+ sec.innerHTML = `${p.title || ''}
${p.subtitle || ''}
${p.body_html || ''}
—— 宇森开发组
`;
+}
+
// ---------- 规则 ----------
async function loadRules(){
const el = document.querySelector('#rules .rules-scroll');
@@ -8,7 +45,7 @@ async function loadRules(){
try {
const d = await API.rules();
const groups = (d && d.groups) || [];
- if (!groups.length){ el.innerHTML = '暂无规则数据
'; return; }
+ if (!groups.length){ return; }
el.innerHTML = groups.map(g => {
const rows = (g.items || []).map(it => {
const lvl = (it.level != null) ? ('Lv.' + it.level) : (g.key === 'world' ? '阶段' : '');
@@ -63,6 +100,7 @@ async function loadAnnounce(){
}
document.addEventListener('DOMContentLoaded', () => {
+ loadPages();
loadRules();
loadForum();
loadAnnounce();
diff --git a/index.html b/index.html
index 6c5b90f..2a35e57 100644
--- a/index.html
+++ b/index.html
@@ -166,12 +166,25 @@
.note .body{font-size:14px;color:var(--text);line-height:1.7;}
.note.pin{box-shadow:var(--glow);}
+ /* ===== 致玩家 ===== */
+ #letter{align-items:center;justify-content:center;}
+ #letter .letter-wrap{max-width:680px;width:100%;overflow-y:auto;padding:10px 20px;}
+ #letter .letter-wrap h2{font-family:"ZCOOL QingKe HuangYou",sans-serif;font-size:30px;letter-spacing:4px;color:#fff;text-shadow:0 0 18px rgba(139,92,246,.5);margin-bottom:6px;text-align:center;}
+ #letter .letter-wrap .lt-sub{text-align:center;font-family:"Press Start 2P",monospace;font-size:9px;color:var(--magenta);letter-spacing:1px;margin-bottom:28px;}
+ #letter .letter-wrap .lt-body{font-size:15px;color:var(--text-dim);line-height:2.1;}
+ #letter .letter-wrap .lt-body p{margin-bottom:16px;}
+ #letter .letter-wrap .lt-body p:first-child{font-size:17px;color:#fff;font-weight:500;}
+ #letter .letter-wrap .lt-body .hl{color:var(--gold);font-weight:500;}
+ #letter .letter-wrap .lt-sign{text-align:right;margin-top:28px;font-size:14px;color:var(--magenta);font-style:italic;}
+
@media (max-width:900px){
.grid{grid-template-columns:repeat(2,1fr);}
#background,#forum{flex-direction:column;overflow-y:auto;}
.layers,.f-cats{flex:none;}
.hero .copy h1{font-size:42px;}
.nav button{padding:8px 10px;font-size:13px;}
+ .nav{overflow-x:auto;scrollbar-width:none;}
+ .nav::-webkit-scrollbar{display:none;}
}
@@ -181,10 +194,13 @@
宇森YUSEN
@@ -210,38 +226,41 @@
-
+
-
+
等级制度TIERS & RANK SYSTEM
+
④ 制度说明
三者相互独立又彼此加成:世界等级是舞台上限,决定能发生什么;势力等级是群体进度,决定能调动什么;角色等级是个体成长,决定能做成什么。园丁的核心策略,是在三者间分配有限的引导资源,让文明自洽地向上演化。
跃迁逻辑:角色历练与装备积累→提升势力实力→推动世界阶段跃迁→解锁更深内容(更深的地下层、更远的星空层、更强的神器)。每一级提升都会扩大可叙事的事件池,世界因此越活越厚。
+
+
+
⑤ 货币等级 · 六档
+
文明流通的价值尺度,从凡俗零钱到本源货币,越稀有的货币可交易的资源层级越高——决定文明"能交换什么"。
兑换规则:100 低等级货币 = 1 高等级货币。
+
+
Lv.1墟铢凡俗通用零钱,以贝壳、骨片、碎石铸成。100 墟铢 = 1 灵币
+
Lv.2灵币蕴含微量灵气的金属铸币,聚落以上势力日常使用。100 灵币 = 1 玄锭
+
Lv.3玄锭刻有玄纹的稀有锭块,用于高价值交易与功法图纸。100 玄锭 = 1 冥玉
+
Lv.4冥玉产自地底深渊的幽暗玉石,蕴含浓郁能量。100 冥玉 = 1 穹鎏
+
Lv.5穹鎏来自星空矿脉的稀有鎏金晶体,跨层贸易硬通货。100 穹鎏 = 1 元玺
+
Lv.6元玺追溯世界本源凝聚而成的至高货币,可兑换神器、传说事件与维度权限。
+
+
@@ -314,13 +347,16 @@
公告ANNOUNCEMENTS
-
2026.07.09
宇森官网第一阶段上线:介绍 / 特色 / 背景 / 规则 / 图鉴 / 论坛 / 公告 七块,单页切换呈现,介绍页即概念宣传片。
+
2026.07.09
宇森官网第一阶段上线:介绍 / 特色 / 背景 / 规则 / 图鉴 / 论坛 / 公告 / 致玩家 八块,单页切换呈现,介绍页即概念宣传片。
2026.07.09
图鉴系统升级:种族 204 条、系别/性格/天赋/神器/传奇事件全面扩量,装备槽位对齐 头/手/胸/裤/鞋/戒指(双)/项链/宝物;全部缩略图改为程序化矢量插画,零 AI 生图。
2026.07.08
概念宣传片《垂直生长》完成,呈现五层世界自上而下生长的镜头语言(天空层改为云朵地基块,星空层改为陨石科技带)。
2026.07.01
园丁视角核心玩法原型启动,首版六边形地图与活 NPC 验证中。
2026.06.20
图鉴系统规划确定:种族 / 建筑 / 生物 / 神器 四大类目,美术持续补充中。
+
+
+
diff --git a/website/demo.html b/website/demo.html
index a90f84f..0bbcbe7 100644
--- a/website/demo.html
+++ b/website/demo.html
@@ -3,7 +3,6 @@
-
宇森 · 世界沙盘