新增用户组药效等级上限配置,与Java端双向打通
配合 Java 端 6f92028(原版药效强度上限 256)。原版 /effect 的 amplifier 硬上限是 255,即药效强度 1~256,此前 Web 侧封顶写死 255 且各建表点口径不一,本次统一为 max_effect_level 配置项。 改动: - web_user_groups 增加 max_effect_level 列(默认 256) · sync.php / land_api.php / core.php 全部 8 处建表块补列 · 3 处迁移表补 ALTER 条目,老库自动升级 - api/sync.php syncUserGroups:Java 推送时接收并写入 max_effect_level, <=0 或超过 256 一律归一到 256(原版硬上限不可突破) - api/land_api.php 新增 getLandMaxEffectLevel():按领地所有者所属 最高优先级用户组取上限,无组则 256;handleUpdateLandField 写入 give_effects 时改用该上限 clamp(原先硬编码 255) - api/land_api.php update_user_group 读写补该字段 - admin.php 用户组新建/编辑弹窗补「药效等级上限」输入框 (1~256,默认 256),并附原版范围说明;两处提交参数同步带上 规则:普通玩家(未加入任何用户组)固定按 256 封顶,严禁超限; 加入用户组后按组配置封顶,填 256 即不额外限制。
This commit is contained in:
@@ -3105,12 +3105,17 @@ function showAddUserGroup() {
|
||||
<input id="ugMaxLands" type="number" value="-1" style="width:100%;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--fg)">
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:10px">
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:6px">
|
||||
<div>
|
||||
<label style="display:block;font-size:12px;color:var(--dim);margin-bottom:4px">领地增益效果上限(5=普通玩家, <=0=不限)</label>
|
||||
<label style="display:block;font-size:12px;color:var(--dim);margin-bottom:4px">领地增益效果数量上限(5=普通玩家, <=0=不限)</label>
|
||||
<input id="ugMaxEffects" type="number" value="5" style="width:100%;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--fg)">
|
||||
</div>
|
||||
<div>
|
||||
<label style="display:block;font-size:12px;color:var(--dim);margin-bottom:4px">药效等级上限(默认256=原版)</label>
|
||||
<input id="ugMaxEffectLevel" type="number" value="256" min="1" max="256" style="width:100%;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--fg)">
|
||||
</div>
|
||||
</div>
|
||||
<div style="font-size:11px;color:var(--dim);margin-bottom:10px">药效强度原版范围 1~256,普通玩家(未加入任何用户组)固定按 256 封顶,严禁超限。</div>
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:10px">
|
||||
<div>
|
||||
<label style="display:block;font-size:12px;color:var(--dim);margin-bottom:4px">Home上限(0=跟随默认)</label>
|
||||
@@ -3150,6 +3155,7 @@ async function doAddUserGroup() {
|
||||
const price = document.getElementById('ugPrice')?.value || '-1';
|
||||
const maxLands = document.getElementById('ugMaxLands')?.value || '-1';
|
||||
const maxEffects = document.getElementById('ugMaxEffects')?.value || '5';
|
||||
const maxEffectLevel = document.getElementById('ugMaxEffectLevel')?.value || '256';
|
||||
const homeLimit = document.getElementById('ugHomeLimit')?.value || '0';
|
||||
const joinPrice = document.getElementById('ugJoinPrice')?.value || '0';
|
||||
const renewPrice = document.getElementById('ugRenewPrice')?.value || '0';
|
||||
@@ -3164,7 +3170,7 @@ async function doAddUserGroup() {
|
||||
try {
|
||||
const res = await apiCall('update_user_group', {
|
||||
name, display_name: displayName, display_color: color,
|
||||
priority, land_price_per_sqm: price, max_lands: maxLands, max_effects: maxEffects,
|
||||
priority, land_price_per_sqm: price, max_lands: maxLands, max_effects: maxEffects, max_effect_level: maxEffectLevel,
|
||||
home_limit: homeLimit, join_price: joinPrice, renew_price: renewPrice,
|
||||
duration_minutes: duration, auto_renew: autoRenew,
|
||||
default_perms: '{}'
|
||||
@@ -3211,9 +3217,12 @@ async function showEditUserGroup(groupName) {
|
||||
<input id="eugMaxLands" type="number" value="${g.max_lands}" style="width:100%;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--fg)"></div>
|
||||
</div>`;
|
||||
html += `<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:12px">
|
||||
<div><label style="display:block;font-size:12px;color:var(--dim);margin-bottom:4px">领地增益效果上限(<=0=不限)</label>
|
||||
<div><label style="display:block;font-size:12px;color:var(--dim);margin-bottom:4px">领地增益效果数量上限(<=0=不限)</label>
|
||||
<input id="eugMaxEffects" type="number" value="${g.max_effects ?? 5}" style="width:100%;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--fg)"></div>
|
||||
<div><label style="display:block;font-size:12px;color:var(--dim);margin-bottom:4px">药效等级上限(默认256=原版)</label>
|
||||
<input id="eugMaxEffectLevel" type="number" min="1" max="256" value="${(g.max_effect_level > 0 ? g.max_effect_level : 256)}" style="width:100%;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--fg)"></div>
|
||||
</div>`;
|
||||
html += `<div style="font-size:11px;color:var(--dim);margin:-4px 0 12px 0">说明:药效强度原版范围 1~256,普通玩家(未加入任何用户组)固定按 256 封顶,严禁超限。加入本组后按上面的值封顶,填 256 即不额外限制。</div>`;
|
||||
html += `<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:12px">
|
||||
<div><label style="display:block;font-size:12px;color:var(--dim);margin-bottom:4px">Home上限(0=默认)</label>
|
||||
<input id="eugHomeLimit" type="number" value="${g.home_limit || 0}" style="width:100%;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--fg)"></div>
|
||||
@@ -3259,6 +3268,7 @@ async function doEditUserGroup(groupName) {
|
||||
const price = document.getElementById('eugPrice')?.value || '-1';
|
||||
const maxLands = document.getElementById('eugMaxLands')?.value || '-1';
|
||||
const maxEffects = document.getElementById('eugMaxEffects')?.value || '5';
|
||||
const maxEffectLevel = document.getElementById('eugMaxEffectLevel')?.value || '256';
|
||||
const homeLimit = document.getElementById('eugHomeLimit')?.value || '0';
|
||||
const duration = document.getElementById('eugDuration')?.value || '0';
|
||||
const joinPrice = document.getElementById('eugJoinPrice')?.value || '0';
|
||||
@@ -3274,7 +3284,7 @@ async function doEditUserGroup(groupName) {
|
||||
try {
|
||||
const res = await apiCall('update_user_group', {
|
||||
name: groupName, display_name: displayName, display_color: color,
|
||||
priority, land_price_per_sqm: price, max_lands: maxLands, max_effects: maxEffects,
|
||||
priority, land_price_per_sqm: price, max_lands: maxLands, max_effects: maxEffects, max_effect_level: maxEffectLevel,
|
||||
home_limit: homeLimit, duration_minutes: duration,
|
||||
join_price: joinPrice, renew_price: renewPrice, auto_renew: autoRenew,
|
||||
default_perms: JSON.stringify(perms)
|
||||
|
||||
+46
-4
@@ -1680,6 +1680,7 @@ function getLandMaxEffects($db, $land) {
|
||||
land_price_per_sqm INTEGER DEFAULT -1,
|
||||
max_lands INTEGER DEFAULT -1,
|
||||
max_effects INTEGER DEFAULT 5,
|
||||
max_effect_level INTEGER DEFAULT 256,
|
||||
home_limit INTEGER DEFAULT 0,
|
||||
join_price INTEGER DEFAULT 0,
|
||||
auto_renew INTEGER DEFAULT 0,
|
||||
@@ -1711,6 +1712,33 @@ function getLandMaxEffects($db, $land) {
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* ★ 领地增益【药效等级上限】(2026-10-04 任务4)
|
||||
* 取领地所有者所属最高优先级用户组的 max_effect_level,默认 256(原版最大药效强度)。
|
||||
* <=0 或非法值一律归一到 256 —— 原版 /effect 的 amplifier 硬上限是 255(= 强度256),
|
||||
* 任何情况下都不允许突破原版。
|
||||
*/
|
||||
function getLandMaxEffectLevel($db, $land) {
|
||||
$fallback = 256;
|
||||
$owner = $land['owner'] ?? '';
|
||||
if (empty($owner)) return $fallback;
|
||||
try {
|
||||
$st = $db->prepare("SELECT g.max_effect_level FROM web_user_group_members m
|
||||
LEFT JOIN web_user_groups g ON m.group_name = g.group_name
|
||||
WHERE m.player_name = :p AND (m.expiry_time = 0 OR m.expiry_time > :now)
|
||||
ORDER BY g.priority DESC LIMIT 1");
|
||||
$st->bindValue(':p', $owner, SQLITE3_TEXT);
|
||||
$st->bindValue(':now', time(), SQLITE3_INTEGER);
|
||||
$row = $st->execute()->fetchArray(SQLITE3_ASSOC);
|
||||
if ($row && $row['max_effect_level'] !== null) {
|
||||
$v = (int)$row['max_effect_level'];
|
||||
if ($v <= 0 || $v > $fallback) return $fallback;
|
||||
return $v;
|
||||
}
|
||||
} catch (\Throwable $e) { /* 表缺失等 */ }
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
function handleUpdateLandField($db, $playerName, $post) {
|
||||
$name = $post['name'] ?? '';
|
||||
$field = $post['field'] ?? '';
|
||||
@@ -1772,18 +1800,20 @@ function handleUpdateLandField($db, $playerName, $post) {
|
||||
$arr = json_decode($value, true);
|
||||
if (is_array($arr)) {
|
||||
if ($field === 'give_effects') {
|
||||
// ★ 2026-10-04 任务3:数量上限(按领地所有者用户组 max_effects,默认5)+ 等级封顶1~255
|
||||
// ★ 2026-10-04 任务3:数量上限(按领地所有者用户组 max_effects,默认5)
|
||||
// ★ 2026-10-04 任务4:等级封顶(按 max_effect_level,普通玩家=原版256)
|
||||
$maxEff = getLandMaxEffects($db, $land);
|
||||
if (count($arr) > $maxEff) {
|
||||
$arr = array_slice($arr, 0, $maxEff);
|
||||
}
|
||||
$maxLv = getLandMaxEffectLevel($db, $land);
|
||||
// [["夜视","1","99999"]] → "夜视:1:99999"
|
||||
$parts = [];
|
||||
foreach ($arr as $e) {
|
||||
if (is_array($e)) {
|
||||
if (isset($e[1]) && $e[1] !== '') {
|
||||
$lv = (int)$e[1];
|
||||
$e[1] = (string)max(1, min(255, $lv));
|
||||
$e[1] = (string)max(1, min($maxLv, $lv));
|
||||
}
|
||||
$parts[] = implode(':', $e);
|
||||
} else {
|
||||
@@ -2371,6 +2401,7 @@ function handleListUserGroups($db) {
|
||||
land_price_per_sqm INTEGER DEFAULT -1,
|
||||
max_lands INTEGER DEFAULT -1,
|
||||
max_effects INTEGER DEFAULT 5,
|
||||
max_effect_level INTEGER DEFAULT 256,
|
||||
home_limit INTEGER DEFAULT 0,
|
||||
join_price INTEGER DEFAULT 0,
|
||||
auto_renew INTEGER DEFAULT 0,
|
||||
@@ -2392,6 +2423,7 @@ function handleListUserGroups($db) {
|
||||
'renew_price' => 'ALTER TABLE web_user_groups ADD COLUMN renew_price INTEGER DEFAULT 0',
|
||||
'duration_minutes' => 'ALTER TABLE web_user_groups ADD COLUMN duration_minutes INTEGER DEFAULT 0',
|
||||
'max_effects' => 'ALTER TABLE web_user_groups ADD COLUMN max_effects INTEGER DEFAULT 5',
|
||||
'max_effect_level' => 'ALTER TABLE web_user_groups ADD COLUMN max_effect_level INTEGER DEFAULT 256',
|
||||
];
|
||||
foreach ($migrations as $col => $sql) {
|
||||
if (!in_array($col, $columns)) {
|
||||
@@ -2430,6 +2462,7 @@ function handleUpdateUserGroup($db, $data) {
|
||||
land_price_per_sqm INTEGER DEFAULT -1,
|
||||
max_lands INTEGER DEFAULT -1,
|
||||
max_effects INTEGER DEFAULT 5,
|
||||
max_effect_level INTEGER DEFAULT 256,
|
||||
home_limit INTEGER DEFAULT 0,
|
||||
join_price INTEGER DEFAULT 0,
|
||||
auto_renew INTEGER DEFAULT 0,
|
||||
@@ -2446,6 +2479,9 @@ function handleUpdateUserGroup($db, $data) {
|
||||
$pricePerSqm = (int)($data['land_price_per_sqm'] ?? -1);
|
||||
$maxLands = (int)($data['max_lands'] ?? -1);
|
||||
$maxEffects = (int)($data['max_effects'] ?? 5); // 领地增益效果上限,<=0=不限
|
||||
// ★ 药效等级上限:<=0 或超过原版 256 一律归一到 256
|
||||
$maxEffectLevel = (int)($data['max_effect_level'] ?? 256);
|
||||
if ($maxEffectLevel <= 0 || $maxEffectLevel > 256) $maxEffectLevel = 256;
|
||||
$homeLimit = (int)($data['home_limit'] ?? 0);
|
||||
$joinPrice = (int)($data['join_price'] ?? 0);
|
||||
$renewPrice = (int)($data['renew_price'] ?? 0);
|
||||
@@ -2455,9 +2491,9 @@ function handleUpdateUserGroup($db, $data) {
|
||||
|
||||
$stmt = $db->prepare("INSERT OR REPLACE INTO web_user_groups
|
||||
(group_name, display_name, display_color, display_emoji, priority,
|
||||
land_price_per_sqm, max_lands, max_effects, home_limit, join_price, auto_renew, renew_price, duration_minutes, default_perms, synced_at)
|
||||
land_price_per_sqm, max_lands, max_effects, max_effect_level, home_limit, join_price, auto_renew, renew_price, duration_minutes, default_perms, synced_at)
|
||||
VALUES (:name, :display, :color, :emoji, :priority,
|
||||
:price, :maxlands, :maxEffects, :homeLimit, :joinPrice, :autoRenew, :renewPrice, :duration, :perms, :synced)");
|
||||
:price, :maxlands, :maxEffects, :maxEffectLevel, :homeLimit, :joinPrice, :autoRenew, :renewPrice, :duration, :perms, :synced)");
|
||||
$stmt->bindValue(':name', $name, SQLITE3_TEXT);
|
||||
$stmt->bindValue(':display', $displayName, SQLITE3_TEXT);
|
||||
$stmt->bindValue(':color', $displayColor, SQLITE3_TEXT);
|
||||
@@ -2466,6 +2502,7 @@ function handleUpdateUserGroup($db, $data) {
|
||||
$stmt->bindValue(':price', $pricePerSqm, SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':maxlands', $maxLands, SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':maxEffects', $maxEffects, SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':maxEffectLevel', $maxEffectLevel, SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':homeLimit', $homeLimit, SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':joinPrice', $joinPrice, SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':autoRenew', $autoRenew, SQLITE3_INTEGER);
|
||||
@@ -2654,6 +2691,7 @@ function handleGetPlayerGroups($db, $player) {
|
||||
land_price_per_sqm INTEGER DEFAULT -1,
|
||||
max_lands INTEGER DEFAULT -1,
|
||||
max_effects INTEGER DEFAULT 5,
|
||||
max_effect_level INTEGER DEFAULT 256,
|
||||
home_limit INTEGER DEFAULT 0,
|
||||
join_price INTEGER DEFAULT 0,
|
||||
auto_renew INTEGER DEFAULT 0,
|
||||
@@ -2673,6 +2711,7 @@ function handleGetPlayerGroups($db, $player) {
|
||||
'renew_price' => 'ALTER TABLE web_user_groups ADD COLUMN renew_price INTEGER DEFAULT 0',
|
||||
'duration_minutes' => 'ALTER TABLE web_user_groups ADD COLUMN duration_minutes INTEGER DEFAULT 0',
|
||||
'max_effects' => 'ALTER TABLE web_user_groups ADD COLUMN max_effects INTEGER DEFAULT 5',
|
||||
'max_effect_level' => 'ALTER TABLE web_user_groups ADD COLUMN max_effect_level INTEGER DEFAULT 256',
|
||||
];
|
||||
foreach ($migrations as $col => $sql) {
|
||||
if (!in_array($col, $columns)) {
|
||||
@@ -2697,6 +2736,7 @@ function handleGetPlayerGroups($db, $player) {
|
||||
land_price_per_sqm INTEGER DEFAULT -1,
|
||||
max_lands INTEGER DEFAULT -1,
|
||||
max_effects INTEGER DEFAULT 5,
|
||||
max_effect_level INTEGER DEFAULT 256,
|
||||
home_limit INTEGER DEFAULT 0,
|
||||
join_price INTEGER DEFAULT 0,
|
||||
auto_renew INTEGER DEFAULT 0,
|
||||
@@ -2733,6 +2773,7 @@ function handleListAvailableGroups($db) {
|
||||
land_price_per_sqm INTEGER DEFAULT -1,
|
||||
max_lands INTEGER DEFAULT -1,
|
||||
max_effects INTEGER DEFAULT 5,
|
||||
max_effect_level INTEGER DEFAULT 256,
|
||||
home_limit INTEGER DEFAULT 0,
|
||||
join_price INTEGER DEFAULT 0,
|
||||
auto_renew INTEGER DEFAULT 0,
|
||||
@@ -2750,6 +2791,7 @@ function handleListAvailableGroups($db) {
|
||||
'renew_price' => 'ALTER TABLE web_user_groups ADD COLUMN renew_price INTEGER DEFAULT 0',
|
||||
'duration_minutes' => 'ALTER TABLE web_user_groups ADD COLUMN duration_minutes INTEGER DEFAULT 0',
|
||||
'max_effects' => 'ALTER TABLE web_user_groups ADD COLUMN max_effects INTEGER DEFAULT 5',
|
||||
'max_effect_level' => 'ALTER TABLE web_user_groups ADD COLUMN max_effect_level INTEGER DEFAULT 256',
|
||||
];
|
||||
foreach ($migrations as $col => $sql) {
|
||||
if (!in_array($col, $columns)) {
|
||||
|
||||
+8
-2
@@ -914,6 +914,7 @@ function syncUserGroups() {
|
||||
land_price_per_sqm INTEGER DEFAULT -1,
|
||||
max_lands INTEGER DEFAULT -1,
|
||||
max_effects INTEGER DEFAULT 5,
|
||||
max_effect_level INTEGER DEFAULT 256,
|
||||
home_limit INTEGER DEFAULT 0,
|
||||
join_price INTEGER DEFAULT 0,
|
||||
auto_renew INTEGER DEFAULT 0,
|
||||
@@ -936,6 +937,7 @@ function syncUserGroups() {
|
||||
'renew_price' => 'ALTER TABLE web_user_groups ADD COLUMN renew_price INTEGER DEFAULT 0',
|
||||
'duration_minutes' => 'ALTER TABLE web_user_groups ADD COLUMN duration_minutes INTEGER DEFAULT 0',
|
||||
'max_effects' => 'ALTER TABLE web_user_groups ADD COLUMN max_effects INTEGER DEFAULT 5',
|
||||
'max_effect_level' => 'ALTER TABLE web_user_groups ADD COLUMN max_effect_level INTEGER DEFAULT 256',
|
||||
];
|
||||
foreach ($migrations as $col => $sql) {
|
||||
if (!in_array($col, $columns)) {
|
||||
@@ -946,10 +948,10 @@ function syncUserGroups() {
|
||||
$now = time();
|
||||
$stmt = $db->prepare("INSERT OR REPLACE INTO web_user_groups
|
||||
(group_name, display_name, display_color, display_emoji, priority,
|
||||
land_price_per_sqm, max_lands, max_effects, home_limit, join_price, auto_renew,
|
||||
land_price_per_sqm, max_lands, max_effects, max_effect_level, home_limit, join_price, auto_renew,
|
||||
renew_price, duration_minutes, default_perms, synced_at)
|
||||
VALUES (:name, :display, :color, :emoji, :priority,
|
||||
:price, :maxlands, :maxeffects, :homelimit, :joinprice, :autorenew,
|
||||
:price, :maxlands, :maxeffects, :maxeffectlevel, :homelimit, :joinprice, :autorenew,
|
||||
:renewprice, :duration, :perms, :synced)");
|
||||
$count = 0;
|
||||
foreach ($groups as $g) {
|
||||
@@ -961,6 +963,10 @@ function syncUserGroups() {
|
||||
$stmt->bindValue(':price', (int)($g['land_price_per_sqm'] ?? -1), SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':maxlands', (int)($g['max_lands'] ?? -1), SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':maxeffects', (int)($g['max_effects'] ?? 5), SQLITE3_INTEGER);
|
||||
// ★ 药效等级上限(2026-10-04 任务4):<=0 归一到原版上限 256
|
||||
$mel = (int)($g['max_effect_level'] ?? 256);
|
||||
if ($mel <= 0 || $mel > 256) $mel = 256;
|
||||
$stmt->bindValue(':maxeffectlevel', $mel, SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':homelimit', (int)($g['home_limit'] ?? 0), SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':joinprice', (int)($g['join_price'] ?? 0), SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':autorenew', (int)($g['auto_renew'] ?? 0), SQLITE3_INTEGER);
|
||||
|
||||
@@ -645,6 +645,7 @@ function initTables(SQLite3 $db) {
|
||||
land_price_per_sqm INTEGER DEFAULT -1,
|
||||
max_lands INTEGER DEFAULT -1,
|
||||
max_effects INTEGER DEFAULT 5,
|
||||
max_effect_level INTEGER DEFAULT 256,
|
||||
home_limit INTEGER DEFAULT 0,
|
||||
join_price INTEGER DEFAULT 0,
|
||||
auto_renew INTEGER DEFAULT 0,
|
||||
|
||||
Reference in New Issue
Block a user