feedback5 WE2: larger-range triggers the data cannot carry — 谬因 S2's beam path, 薇薇安娜 S3's 3-2 from its second cast (#16)
The owner's ACTIVE_RANGE rule (a MANUAL skill whose running range strictly contains the operator's own) for two skills whose running range is no data range (O1, O11 reports): op-aphris.js adds the beam's path as a content trigger range; op-vvana.js switches S3 to ACTIVE_RANGE on 3-2 once its first cast of a deployment ended (DEFAULT again on redeploy) through a new additive SkillRuntime.setTrigger(rule, grid). The scan of the wave 2-3 reports and the 41 candidate skills is in the doc draft (others: target-centred, already fixed, or owner questions). Golden: diy-045 (谬因 S2 fires for enemies beyond her 6 tiles) and diy-078 (薇薇安娜 S3: skill timing in hooks / snapshots only) moved.
This commit is contained in:
1 parent
2eaef154d5
commit
1559614e8a
6 files changed
+135
-25
No files matched your search
+2
-1
@@ -892,7 +892,8 @@ or guard with a per-unit flag while dealing it. When the guard trips, the logged
|
||||
`skillEnd` fires. `onAttack` ctx carries `noAmmo` (set it to true: this attack spends no bullet, no `ammoUsed` — 流明's
|
||||
free heals).
|
||||
- Runtime helpers on `unit.skill`: `activate(reason, {free})`, `end(reason)`, `stop()`, `addAmmo(n)`, `extend(s)`,
|
||||
`addCharge(n)`, `gainSp(n, reason)`, `addTriggerRange(fn)`; fields `sp, spCost (= floor(base×spCostMul + spCostFlat)), spCostMul, charges,
|
||||
`addCharge(n)`, `gainSp(n, reason)`, `addTriggerRange(fn)`, `setTrigger(rule, grid)` (a kit's own rule change mid-battle —
|
||||
薇薇安娜 S3's ACTIVE_RANGE on 3-2 after its first cast; 0.2.0); fields `sp, spCost (= floor(base×spCostMul + spCostFlat)), spCostMul, charges,
|
||||
maxCharges, active, timeLeft, ammoLeft, ammoMax, activations, kind, rule, bb` (`ammoMax`: the most bullets the running ammo skill
|
||||
has held — set at activation, raised by skillStart additions and `addAmmo` above it; 0 when inactive).
|
||||
|
||||
|
||||
@@ -47,8 +47,10 @@
|
||||
// every `interval` (0.5) s, every selectable enemy on her path takes atk_scale × ATK arts (16 hits in the 8 s). The path
|
||||
// meanwhile has no length limit (`_infinite`) and turns at her 中继器 and at every allied
|
||||
// operator it reaches (validators: the piece, allies of profession mask 639 — every operator profession; a 孤立 one too),
|
||||
// to that unit's facing. The data resolves DEFAULT: the unbounded range is no data range (no rangeId), so build-data's
|
||||
// ACTIVE_RANGE rule cannot see it (reported, not hand-coded).
|
||||
// to that unit's facing. Trigger: the data's DEFAULT, plus — the owner's ACTIVE_RANGE rule (2026-10-05: a MANUAL skill
|
||||
// whose running range strictly contains her own casts with an enemy inside that range), which no data range can carry
|
||||
// for an unbounded path that bends — the beam's path as a content trigger range (skill.addTriggerRange: a targetable enemy
|
||||
// on the path she would fire along now, air units too as the beam hits them; 0.2.0 WE2, follow-up #16, O1's report).
|
||||
// - S3 混沌的本质 (MANUAL, data DEFAULT, 20 发弹药 — `ammo`, attack@trigger_time): for charge_time (3) s from the cast 强制缴械
|
||||
// (aphris_sk3[sheltering], abnormal flag disarmed) and aphris_sk3[token-withdraw]: every 中继器 of hers withdrawn and its
|
||||
// redeploy time cleared (ResetTokenRespawnTime — the placed piece is back on its tile at once; the two extra pieces the
|
||||
@@ -285,6 +287,8 @@ export default {
|
||||
battle.on('skillStart', (c) => { if (c.unit === unit) refreshPath(battle, unit); }, { owner: unit });
|
||||
battle.on('skillEnd', (c) => { if (c.unit === unit) refreshPath(battle, unit); }, { owner: unit });
|
||||
battle.on('tick', () => refreshPath(battle, unit), { owner: unit });
|
||||
// S2: the beam's path is its trigger range too (the owner's larger-range rule, see the header)
|
||||
if (unit.skill?.id === S2) unit.skill.addTriggerRange(() => (up(unit) ? [aphrisPath(battle, unit, true).tiles.map(([r, c]) => r * COLS + c)] : []));
|
||||
// S3's 强制缴械 from the cast on: the attack loop goes on to the attack the cast was made for (ai.js updateAlly
|
||||
// checks `disarm` before the cast only) — no target, no attack, no bullet spent
|
||||
battle.on('beforeAttack', (c) => { if (c.attacker === unit && unit.findBuff(CHARGE_KEY)) c.targets = []; }, { owner: unit });
|
||||
|
||||
@@ -54,8 +54,10 @@
|
||||
// 备注 "每次部署薇薇安娜时,重新计算该技能的使用次数" / "首次技能结束后,本技能的技能范围永久扩大至3-2"; vvana_s_3[check]: a
|
||||
// skill triggered before ⇒ the enhance mark and duration_plus = enhance_duration, vvana_s_3: mode 4 instead of 3): from her
|
||||
// second cast of a deployment the skill runs enhance_duration s with S3_LATER_HITS hits on the 3-2 range (her own grid while
|
||||
// it runs: the card shows it). The trigger stays the data's DEFAULT on her own range for every cast — the later casts'
|
||||
// larger running range is no data range (reported, not changed: kits/README.md checklist 5).
|
||||
// it runs: the card shows it). Trigger: the data's DEFAULT on her own range for the first cast of a deployment; once it
|
||||
// has ended the owner's ACTIVE_RANGE rule (2026-10-05: a MANUAL skill whose running range strictly contains her own casts
|
||||
// with an enemy inside that range) on the 3-2 — no data range carries it, so the kit sets it (skill.setTrigger, 0.2.0 WE2,
|
||||
// follow-up #16; O11's report) — and DEFAULT again at her next deployment.
|
||||
|
||||
import { num, talentBb, traitBb, skillRec, up, batMod } from '../shared/tier1.js';
|
||||
import { isElite, elementDmg, enemiesIn } from '../shared/tier6.js';
|
||||
@@ -168,9 +170,11 @@ export default {
|
||||
skill.timeLeft = Math.max(0.01, num(b3.enhance_duration, skill.duration));
|
||||
setGrid(battle, unit, RANGE_3_2);
|
||||
},
|
||||
onEnd({ battle, unit }) {
|
||||
onEnd({ battle, unit, skill }) {
|
||||
if (unit.mem.vvanaS3Later) setGrid(battle, unit, unit.def?.rangeGrid);
|
||||
unit.mem.vvanaS3Later = false;
|
||||
// its later casts run on the 3-2: from now the owner's ACTIVE_RANGE rule there (see the header)
|
||||
if ((unit.mem.vvanaS3Casts ?? 0) >= 1) skill.setTrigger('ACTIVE_RANGE', RANGE_3_2);
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -258,6 +262,7 @@ export default {
|
||||
unit.mem.vvanaS3Casts = 0;
|
||||
unit.mem.vvanaS3Later = false;
|
||||
setGrid(battle, unit, own);
|
||||
if (unit.skill?.id === S3) unit.skill.setTrigger('DEFAULT', null); // the first cast of a deployment: the data's rule
|
||||
}, { owner: unit });
|
||||
}
|
||||
// AFT-D: 元素伤害 at the output of every damage of hers on an enemy in its 灼燃 爆发冷却 (not on this rider's own)
|
||||
|
||||
@@ -120,6 +120,19 @@ export class SkillRuntime {
|
||||
this.noSkill = !spec; // unit without any skill spec
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the trigger rule and grid mid-battle — a kit whose skill's running range changes with its own use (薇薇安娜 S3:
|
||||
* "首次技能结束后,本技能的技能范围永久扩大至3-2" — ACTIVE_RANGE on 3-2 from then, DEFAULT again at her next deployment).
|
||||
* `grid`: a facing-RIGHT [dRow, dCol] grid (ACTIVE_RANGE / SKILL_RANGE / CUSTOM_RANGE), or null. (0.2.0 WE2, additive.)
|
||||
* @param {string} rule @param {number[][]|null} [grid]
|
||||
*/
|
||||
setTrigger(rule, grid = null) {
|
||||
this.rule = String(rule ?? 'DEFAULT').toUpperCase();
|
||||
this.triggerGrid = Array.isArray(grid) && grid.length ? grid : null;
|
||||
this._trigKeys = null;
|
||||
this._trigSet = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extra DEFAULT-trigger range (海嗣 "攻击范围视为自身攻击范围的延伸", 流形): `fn(battle, unit)` returns a list whose
|
||||
* entries are ally units (their current `rangeKeys` count while they are on the field) or arrays of absolute tile
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
// test/content/feedback5-we2-area-triggers.test.js — 0.2.0 WE2 #16: kit-side larger-range triggers where no data range can
|
||||
// carry the owner's ACTIVE_RANGE rule (2026-10-05: a MANUAL skill whose running range strictly contains the operator's own
|
||||
// casts as soon as an enemy is inside that larger range):
|
||||
// * 谬因 S2 临界瞬爆 — the beam's unbounded path (O1's report): content trigger range = the path she would fire along now;
|
||||
// * 薇薇安娜 S3 “明灭” — from its second cast of a deployment on 3-2 (O11's report): ACTIVE_RANGE after the first cast ends
|
||||
// (skills.js setTrigger), DEFAULT again at her next deployment.
|
||||
// Run: node --test test/content/feedback5-we2-area-triggers.test.js
|
||||
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { makeBattle, enemyRec, checkInvariants } from '../helpers/battleHarness.js';
|
||||
|
||||
const SLOT = { 5: 'chess_char_5_diy1_a', 6: 'chess_char_6_diy1_a' };
|
||||
const dummy = (key, o = {}) => enemyRec({ key, hp: 1e9, speed: 0, mass: 0, ...o });
|
||||
const ENEMIES = { enemy_dummy: dummy('enemy_dummy'), enemy_fly: dummy('enemy_fly', { motion: 'FLY' }) };
|
||||
function done(h) {
|
||||
checkInvariants(h.b);
|
||||
assert.equal(h.b.errors.length, 0, JSON.stringify(h.b.errors[0]));
|
||||
}
|
||||
|
||||
/** `charId` as uid 1 at (row, col) facing RIGHT with skill `skill`. */
|
||||
function field(charId, { skill, row, col, tier = 5, seed = 5 }) {
|
||||
const h = makeBattle({
|
||||
defs: { enemies: ENEMIES }, timeLimit: 900, autoFinish: false, seed,
|
||||
flags: { dpInit: 99, dpPerSec: 0, dpMax: 999, startOpCooldown: 0 }, hooks: ['skillStart', 'skillEnd'], captureNoisy: true,
|
||||
units: [{ uid: 1, diy: { slot: SLOT[tier], charId, skillIndex: skill, uniEquipId: null }, elite: false, row, col }],
|
||||
});
|
||||
h.step();
|
||||
return { h, u: h.unit(1) };
|
||||
}
|
||||
|
||||
test('#16 谬因 S2: an enemy on the beam\'s line beyond her own 6 tiles casts it (data DEFAULT alone would wait); one off the line does not', () => {
|
||||
// her own range (9, 2) … (9, 7); the beam reaches the end of the row
|
||||
{
|
||||
const { h, u } = field('char_4229_aphris', { skill: 1, row: 9, col: 2 });
|
||||
assert.equal(u.skill.rule, 'DEFAULT');
|
||||
assert.equal(u.skill.triggerRanges.length, 1, 'the beam path is a content trigger range');
|
||||
h.spawn('enemy_dummy', { pos: [10, 12] }); // off the line
|
||||
u.skill.gainSp(999);
|
||||
h.run(2);
|
||||
assert.equal(u.skill.activations, 0, 'off the line: no cast');
|
||||
h.spawn('enemy_dummy', { pos: [9, 13] }); // on the line, far beyond (9, 7)
|
||||
assert.ok(h.runUntil(() => u.skill.activations === 1, 1), 'on the beam\'s line: cast');
|
||||
done(h);
|
||||
}
|
||||
// a flyer on the line too (the beam hits air units)
|
||||
{
|
||||
const { h, u } = field('char_4229_aphris', { skill: 1, row: 9, col: 2 });
|
||||
h.spawn('enemy_fly', { pos: [9, 14] });
|
||||
u.skill.gainSp(999);
|
||||
assert.ok(h.runUntil(() => u.skill.activations === 1, 1));
|
||||
done(h);
|
||||
}
|
||||
// S1 / S3 get no such range
|
||||
for (const skill of [0, 2]) {
|
||||
const { h, u } = field('char_4229_aphris', { skill, row: 9, col: 2 });
|
||||
assert.equal(u.skill.triggerRanges.length, 0, `S${skill + 1}`);
|
||||
done(h);
|
||||
}
|
||||
});
|
||||
|
||||
test('#16 薇薇安娜 S3: the first cast of a deployment by the data\'s DEFAULT; once it ended, an enemy on the 3-2 beyond her own reach casts the next one (ACTIVE_RANGE); a redeploy goes back to DEFAULT', () => {
|
||||
const { h, u } = field('char_4098_vvana', { skill: 2, row: 10, col: 3 });
|
||||
assert.equal(u.skill.rule, 'DEFAULT');
|
||||
// (10, 6): on her 3-2 (cols 3–6), outside her own 1-1 (cols 3–4)
|
||||
const far = h.spawn('enemy_dummy', { pos: [10, 6] });
|
||||
u.skill.gainSp(999);
|
||||
h.run(2);
|
||||
assert.equal(u.skill.activations, 0, 'first cast: DEFAULT on her own range — the far enemy does not cast it');
|
||||
// an enemy in her own range: the first cast; then let it run out
|
||||
const near = h.spawn('enemy_dummy', { pos: [10, 4] });
|
||||
assert.ok(h.runUntil(() => u.skill.activations === 1, 3), 'first cast');
|
||||
assert.ok(h.runUntil(() => !u.skill.active, 30), 'it ends');
|
||||
assert.deepEqual([u.skill.rule, u.skill.triggerGrid], ['ACTIVE_RANGE', [[0, 0], [0, 1], [0, 2], [0, 3]]], 'from now on the 3-2');
|
||||
h.b.kill(near, null);
|
||||
u.skill.gainSp(999);
|
||||
assert.ok(h.runUntil(() => u.skill.activations === 2, 4), 'the far enemy alone casts the second one');
|
||||
void far;
|
||||
// a redeploy: the count and the rule start again
|
||||
assert.ok(h.runUntil(() => !u.skill.active, 40));
|
||||
h.b.retreat(u, { reason: 'retreat' });
|
||||
h.step();
|
||||
assert.ok(h.b.redeploy(u, { free: true }));
|
||||
h.step();
|
||||
assert.deepEqual([u.skill.rule, u.skill.triggerGrid], ['DEFAULT', null], 'the next deployment: the data\'s rule');
|
||||
done(h);
|
||||
});
|
||||
+19
-19
@@ -1820,35 +1820,35 @@
|
||||
"time": 211.6,
|
||||
"ticks": 6348,
|
||||
"reason": "cleared",
|
||||
"killed": 82,
|
||||
"killed": 74,
|
||||
"total": 150,
|
||||
"unspawned": 0,
|
||||
"bossHpLeft": null,
|
||||
"rngDraws": 89,
|
||||
"errors": {"count":0,"kinds":[]},
|
||||
"players": {"p1":{"killed":82,"total":150,"perfect":false,"leaks":68,"leaksUncounted":0,"coins":0,"dmg":1367204,"bossDmg":0,"heal":0,"deaths":13,"layerGains":{}}},
|
||||
"players": {"p1":{"killed":74,"total":150,"perfect":false,"leaks":76,"leaksUncounted":0,"coins":0,"dmg":1358417,"bossDmg":0,"heal":0,"deaths":13,"layerGains":{}}},
|
||||
"units": [
|
||||
["p1",1,"op","chess_char_6_diy1_b",0,"uniequip_002_ifrit",1544,1,4,29,535201,0,0,93,4],
|
||||
["p1",2,"op","chess_char_6_diy2_b",1,"uniequip_002_ifrit",1544,1,5,14,235845,0,0,72,39],
|
||||
["p1",3,"op","chess_char_6_diy1_b",2,"uniequip_002_ifrit",1544,1,171,1,98866,1544,0,17,3],
|
||||
["p1",4,"op","chess_char_6_diy2_b",0,"uniequip_003_ifrit",1744,1,13,0,87409,0,0,74,4],
|
||||
["p1",5,"op","chess_char_6_diy1_b",1,"uniequip_003_ifrit",1744,1,6,18,156957,0,0,66,34],
|
||||
["p1",1,"op","chess_char_6_diy1_b",0,"uniequip_002_ifrit",1544,1,4,30,548258,0,0,93,4],
|
||||
["p1",2,"op","chess_char_6_diy2_b",1,"uniequip_002_ifrit",1544,1,5,13,217959,0,0,72,39],
|
||||
["p1",3,"op","chess_char_6_diy1_b",2,"uniequip_002_ifrit",1544,1,171,1,99441,1544,0,17,3],
|
||||
["p1",4,"op","chess_char_6_diy2_b",0,"uniequip_003_ifrit",1744,1,13,1,87328,0,0,74,4],
|
||||
["p1",5,"op","chess_char_6_diy1_b",1,"uniequip_003_ifrit",1744,1,6,12,157838,0,0,65,33],
|
||||
["p1",6,"op","chess_char_6_diy2_b",2,"uniequip_003_ifrit",0,0,14,0,63597,1744,0,20,3],
|
||||
["p1",7,"op","chess_char_5_diy1_a",0,null,0,0,121,0,2158,2522,0,3,0],
|
||||
["p1",8,"op","chess_char_5_diy2_a",1,null,0,0,154,8,58152,2522,0,10,1],
|
||||
["p1",9,"op","chess_char_5_diy1_a",2,null,0,0,100,2,21405,2522,0,10,1],
|
||||
["p1",10,"op","chess_char_5_diy2_b",0,"none",0,0,95,2,14759,3052,0,9,0],
|
||||
["p1",11,"op","chess_char_5_diy1_b",1,"none",0,0,90,3,27322,3052,0,3,2],
|
||||
["p1",12,"op","chess_char_5_diy2_b",2,"none",0,0,8,5,65534,1526,0,20,1],
|
||||
["p1",8,"op","chess_char_5_diy2_a",1,null,0,0,154,6,51945,2522,0,11,1],
|
||||
["p1",9,"op","chess_char_5_diy1_a",2,null,0,0,100,2,19121,2522,0,10,1],
|
||||
["p1",10,"op","chess_char_5_diy2_b",0,"none",0,0,96,3,16304,3052,0,10,0],
|
||||
["p1",11,"op","chess_char_5_diy1_b",1,"none",0,0,90,3,32589,3052,0,4,2],
|
||||
["p1",12,"op","chess_char_5_diy2_b",2,"none",0,0,8,3,61880,1526,0,17,1],
|
||||
["-","~1","device","trap_1105_accrate",null,null,100,1,1,0,0,0,0,0,null],
|
||||
["-","~2","device","trap_1105_accrate",null,null,100,1,2,0,0,0,0,0,null],
|
||||
["-","~3","device","trap_1105_accrate",null,null,100,1,3,0,0,0,0,0,null]
|
||||
],
|
||||
"enemies": {"enemy_1249_lysdb_2":[60,34,26,5486,596279],"enemy_1251_lysyta":[51,35,16,909,240893],"enemy_1329_cbshld":[39,13,26,8801,530032]},
|
||||
"hooks": [1,171,6348,433,431,1867,2367,0,95,163,92,92,18,29289,22,25,150,68,1,95,0,0,0],
|
||||
"events": {"atk":1247,"deploy":18,"die":95,"dmg":2367,"engage":12,"fx":236,"leak":68,"skill":184,"spawn":165,"status":44},
|
||||
"fx": {"aoe":73,"beam":3,"flame":100,"shieldBreak":60},
|
||||
"snaps": "43307da7 4ff2063f 2a153be0 3aba4c54 30fdf3ac 1f9215af cf66cfaa 8012d31d 985f38b3 a23ece2e 38d610e7 33eab3e4 0832bad4 fdd45552 4c989016 b99015e8 e5e90c65 02b8067a c5784c78 5f21d2f4 59cec77b fe00505d"
|
||||
"enemies": {"enemy_1249_lysdb_2":[60,32,28,4443,590753],"enemy_1251_lysyta":[51,32,19,942,239115],"enemy_1329_cbshld":[39,10,29,9811,528548]},
|
||||
"hooks": [1,171,6348,432,430,1848,2352,0,87,163,91,91,15,29250,22,25,150,76,1,87,0,0,0],
|
||||
"events": {"atk":1258,"deploy":18,"die":87,"dmg":2352,"engage":12,"fx":235,"leak":76,"skill":182,"spawn":165,"status":44},
|
||||
"fx": {"aoe":72,"beam":3,"flame":100,"shieldBreak":60},
|
||||
"snaps": "a92391fb 65d01483 6ce4a17f b71d2eb4 41903aab ff59f11c 19708ae2 91521e30 13cbe1cb 6aedec66 803f5122 4d21778b 6238ae29 63609ca2 b757c3a4 f2beec8c 6962ad79 f76f5262 3fdc9f26 ef4a8d27 c8a0adc1 98f390f9"
|
||||
},
|
||||
"diy-046": {
|
||||
"about": "5_diy1_b=aphris/S1/002_aphris 5_diy2_b=aphris/S2/002_aphris 5_diy1_b=aphris/S3/002_aphris 6_diy1_a=aphris/S1 6_diy2_a=aphris/S2 6_diy1_a=aphris/S3 6_diy2_b=aphris/S1 6_diy1_b=aphris/S2 6_diy2_b=aphris/S3 6_diy1_b=aphris/S1/002_aphris 6_diy2_b=aphris/S2/002_aphris 6_diy1_b=aphris/S3/002_aphris",
|
||||
@@ -3365,10 +3365,10 @@
|
||||
["-","~3","device","trap_1105_accrate",null,null,100,1,3,0,0,0,0,0,null]
|
||||
],
|
||||
"enemies": {"enemy_1019_jshoot_2":[57,41,16,9154,183638],"enemy_1299_ymkilr_2":[27,10,17,47487,203959],"enemy_1422_lrsldr_2":[39,16,23,1386,172539]},
|
||||
"hooks": [1,149,6820,1026,1026,1315,1436,0,88,144,56,55,0,17849,892,94,123,56,1,88,0,6,0],
|
||||
"hooks": [1,149,6820,1026,1026,1315,1436,0,88,144,56,55,0,17851,892,94,123,56,1,88,0,6,0],
|
||||
"events": {"atk":1056,"deploy":23,"die":88,"dmg":1436,"engage":12,"fx":74,"leak":56,"skill":111,"spawn":138,"status":71},
|
||||
"fx": {"aoe":20,"burst":6,"shield":24,"shieldBreak":24},
|
||||
"snaps": "45ecc41c 880ee0dd b36699bc 992f1255 23143b3d 3ba40a64 ead1143c 29b600b7 60ec6974 eff36649 bbaee861 b11de034 d58d5c37 63232bfe 4e305d69 848a4366 cd76bd35 ad1f8c0f 8e3f9ba5 2b3b69eb 71bc494b 17b62c2a 2f3b24a4"
|
||||
"snaps": "45ecc41c 880ee0dd b36699bc 992f1255 23143b3d 3ba40a64 ead1143c 29b600b7 60ec6974 eff36649 b5a79642 02d6faca e4063ab1 22bf8f0f 14cf16ac 3e4fc06b 12025e38 96906102 cd2db10c 106c766a bc2c5496 1bb121b3 410896a5"
|
||||
},
|
||||
"diy-079": {
|
||||
"about": "5_diy1_b=headb2/S1/002_headb2 5_diy2_b=headb2/S2/002_headb2 5_diy1_b=headb2/S3/002_headb2 6_diy1_a=headb2/S1 6_diy2_a=headb2/S2 6_diy1_a=headb2/S3 6_diy2_b=headb2/S1 6_diy1_b=headb2/S2 6_diy2_b=headb2/S3 6_diy1_b=headb2/S1/002_headb2 6_diy2_b=headb2/S2/002_headb2 6_diy1_b=headb2/S3/002_headb2",
|
||||
|
||||
Reference in new issue
Block a user