';
+ }).join('');
+ results._items = items;
+ results._onSelect = onSelect;
+ }).catch(function() { results.style.display = 'none'; });
+}
+
+function selectCourseResult(el) {
+ var results = el.parentElement;
+ var idx = Array.prototype.indexOf.call(results.children, el);
+ if (results._items && results._items[idx] && results._onSelect) {
+ results._onSelect(results._items[idx]);
+ results.style.display = 'none';
+ results.innerHTML = '';
+ var input = results.parentElement.querySelector('.search-input');
+ if (input) input.value = '';
+ }
+}
+
+function courseShowNew() {
+ if (!currentRoomData || !currentRoomData.room) return;
+ var roomID = currentRoomData.room.id;
+
+ var overlay = document.createElement('div');
+ overlay.className = 'cm-overlay exit-overlay';
+ var menu = document.createElement('div');
+ menu.className = 'cm-menu exit-modal';
+ menu.style.cssText = 'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);min-width:520px;max-width:90vw;max-height:85vh;overflow-y:auto;overflow-x:hidden;padding:14px;z-index:201';
+
+ var h = '
New Course (room #' + roomID + ' = step 1)
';
+ h += '';
+ h += '';
+ h += '';
+ h += '';
+ h += '';
+ h += '';
+ h += '';
+ h += '
';
+ h += '';
+ h += '';
+ h += '
';
+ h += '';
+ h += '';
+ h += '
';
+ h += '';
+ h += '';
+ h += '
';
+
+ menu.innerHTML = h;
+ document.body.appendChild(overlay);
+ document.body.appendChild(menu);
+ overlay.onclick = courseCloseModal;
+}
+
+function courseCloseModal() {
+ var ov = document.querySelector('.exit-overlay');
+ if (ov) ov.remove();
+ var m = document.querySelector('.exit-modal');
+ if (m) m.remove();
+}
+
+function courseCreateConfirm() {
+ if (!currentRoomData || !currentRoomData.room) return;
+ var roomID = currentRoomData.room.id;
+ var id = val('#newCourseID');
+ if (!id) { notify('Course ID required', 'error'); return; }
+ var name = val('#newCourseName');
+ var reqLevel = parseInt(val('#newCourseReqLevel')) || 0;
+ var startRoom = parseInt(val('#newCourseStartRoom')) || 0;
+ var completionXP = parseInt(val('#newCourseCompletionXP')) || 0;
+ var verb = sel('#newCourseVerb');
+ var xp = parseInt(val('#newCourseXP')) || 0;
+ var failMin = parseInt(val('#newCourseFailMin')) || 0;
+ var failMax = parseInt(val('#newCourseFailMax')) || 0;
+ var fcStr = val('#newCourseFailChance');
+ var fc = fcStr === '' ? null : parseFloat(fcStr);
+ if (fc !== null) { if (fc < 0) fc = 0; if (fc > 100) fc = 100; fc = fc / 100; }
+ var msg = val('#newCourseMsg') || '';
+
+ var obstacle = {
+ room_id: roomID,
+ verb: verb,
+ xp: xp,
+ fail_damage: [failMin, failMax],
+ phases: [{ message: msg, delay: 0 }]
+ };
+ if (fc !== null) obstacle.fail_chance = fc;
+
+ var body = {
+ id: id,
+ name: name,
+ required_level: reqLevel,
+ start_room: startRoom,
+ completion_xp: completionXP,
+ obstacles: [obstacle]
+ };
+
+ API.post('/api/courses', body).then(function(res) {
+ if (res.error) { notify(res.error, 'error'); return; }
+ notify('Course ' + id + ' created', 'success');
+ updateUndoBar();
+ courseCloseModal();
+ _coursePhases = null;
+ loadRoomCourseData(roomID);
+ }).catch(function(e) { notify('Create failed: ' + extractError(e), 'error'); });
+}
+
+// tiny helpers used by the course tab
+function val(sel) { var el = document.querySelector(sel); return el ? el.value : ''; }
+function sel(sel) { var el = document.querySelector(sel); return el ? el.value : ''; }
+
function searchHazards(input) {
searchAndShow(input, 'hazards', function(r) { addHazard(r.id); });
}
@@ -528,6 +1029,17 @@ function switchPanelTab(idx) {
else if (idx === 4) html = renderMobsTab(mobs);
else if (idx === 5) html = renderItemsTab(spawns);
else if (idx === 6) html = renderHazardTab(r);
+ else if (idx === 7) {
+ _coursePhases = null;
+ if (currentRoomData.course === undefined) {
+ html = renderCourseTabLoading();
+ loadRoomCourseData(r.id);
+ } else if (currentRoomData.course === null) {
+ html = renderCourseTabEmpty();
+ } else {
+ html = renderCourseTab();
+ }
+ }
var content = document.querySelector('.panel-tab-content');
if (content) content.innerHTML = html;
var tabs = document.querySelectorAll('.panel-tab');
@@ -646,10 +1158,12 @@ function renderExitsSection(r) {
var bmsg = (typeof exit === 'object' && exit.blocked_message) ? exit.blocked_message : '';
var setFlags = (typeof exit === 'object' && exit.set_flags) ? exit.set_flags : null;
var setPlayerFlags = (typeof exit === 'object' && exit.set_player_flags) ? exit.set_player_flags : null;
- var isConditional = !!(cond || bmsg || setFlags || setPlayerFlags);
+ var hidden = (typeof exit === 'object' && exit.hidden) ? exit.hidden : false;
+ var isConditional = !!(cond || bmsg || setFlags || setPlayerFlags || hidden);
h += '
';
h += '' + d + '';
h += '# ' + target + '';
+ h += '';
if (bmsg) h += 'Blocked: ' + esc(bmsg) + '';
if (cond) h += 'Conditional';
h += '';
@@ -679,6 +1193,7 @@ function editExitCondition(dir) {
var bmsg = exit.blocked_message || '';
var setFlags = exit.set_flags || null;
var setPlayerFlags = exit.set_player_flags || null;
+ var hidden = exit.hidden || false;
var flagsStr = '';
if (setFlags) flagsStr = Object.keys(setFlags).map(function(k) { return k + '=' + setFlags[k]; }).join(', ');
@@ -697,6 +1212,7 @@ function editExitCondition(dir) {
h += '';
h += '';
h += '';
+ h += '';
h += '
';
h += '';
@@ -834,6 +1350,8 @@ function saveExitCondition() {
var bmsg = document.getElementById('exitBmsg');
exit.blocked_message = (bmsg && bmsg.value) ? bmsg.value : '';
+ var hiddenEl = document.getElementById('exitHidden');
+ exit.hidden = hiddenEl ? hiddenEl.checked : false;
var flagsStr = document.getElementById('exitFlags');
var pflagsStr = document.getElementById('exitPFlags');
exit.set_flags = parseFlagInput(flagsStr ? flagsStr.value : '');
@@ -928,6 +1446,21 @@ function deleteExit(dir, target) {
}).catch(function(e) { notify('Delete exit failed: ' + extractError(e), 'error'); });
}
+function toggleExitHidden(dir) {
+ if (!currentRoomData || !currentRoomData.room) return;
+ var exits = currentRoomData.room.exits || {};
+ var exit = exits[dir];
+ if (!exit) return;
+ if (typeof exit !== 'object') {
+ exit = {room: exit};
+ exits[dir] = exit;
+ currentRoomData.room.exits = exits;
+ }
+ exit.hidden = !exit.hidden;
+ autoSave();
+ reRenderPanel();
+}
+
function extractError(e) {
var msg = e.message || 'unknown error';
try { var j = JSON.parse(msg); if (j.error) msg = j.error; } catch(_) {}
--
cgit v1.2.3