<<nobr>>
<<setBG 1 setup.ImagePath ''>>
<!-- ===================== HTML ====================== -->
<div id="main-menu-container">
<div class="mm-title">Disclaimer</div>
This game contains explicit adult material intended only for mature audiences (18+).<br>
<b><span style="color: yellow;">By continuing, you acknowledge and confirm that:</span></b>
You are at least 18 years old (or the legal age of majority in your region).<br>
This game includes themes of sexual content, fetish material, adult situations, and mature dialogue not suitable for minors.<br>
All characters depicted are fictional adults, and any resemblance to real persons—living or dead—is purely coincidental.<br>
All locations, scenarios, and events presented in this game are fictional and created purely for entertainment and storytelling purposes.<br>
This project is presented as a legitimate artistic creation, comparable to works of literature, music, cinema, and visual arts. It is intended to be interpreted as fiction and should not be bound or limited by subjective or superficial moral judgments.<br>
This game does not endorse, encourage, or condone illegal activity, abuse, exploitation, or harmful behavior of any kind.<br>
Some themes may be extreme, exaggerated, or stylized for dramatic purposes. Player discretion is advised.<br>
You are accessing this content voluntarily and you are responsible for complying with all local laws and regulations regarding adult media.<br>
You will not share this game with minors or individuals who do not wish to view adult content.<br>
You acknowledge that you have read, understood, and agreed to the Terms of Service and Privacy Policy linked below.<br>
<b><span style="color: lightyellow;">If you are under 18 (or the legal age of majority in your region), or if adult content is prohibited in your location, exit now.</span></b>
<div class="mm-legal-links">
<a href="https://www.elliahal.com/terms_of_service/" target="_blank">Terms of Service</a>
<span>•</span>
<a href="https://www.elliahal.com/privacy_policy/" target="_blank">Privacy Policy</a>
</div>
<div class="mm-buttons">
<button class="mm-btn" onclick="SugarCube.Engine.play('Main Menu')">Click Here To Continue</button>
</div>
<!-- ====================== CSS ====================== -->
<style>
/* Reset possible Twine margins */
#passages {
margin: 0 !important;
padding: 0 !important;
}
/* Fullscreen flex center */
#main-menu-container {
position: fixed;
top: 0; left: 0;
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 9999;
color: white;
text-align: center;
background: rgba(0,0,0,0.25); /* subtle overlay */
backdrop-filter: blur(2px);
}
/* Title Styling */
.mm-title {
font-family: 'Georgia', serif;
font-size: clamp(2.2rem, 1.5vw, 4rem);
font-weight: 300;
letter-spacing: 3px;
margin-bottom: 1.5em;
text-shadow: 0px 0px 8px rgba(0,0,0,0.6);
}
.mm-title span {
color: #ff2f7d;
font-size: clamp(3.2rem, 1vw, 4rem);
}
/* Buttons container */
.mm-buttons {
display: flex;
flex-direction: column;
gap: 1rem;
width: 80%;
max-width: 250px;
}
/* Buttons */
.mm-btn {
padding: 0.9em 1em;
font-size: clamp(1rem, 2vw, 1.3rem);
font-family: 'Arial', sans-serif;
border: none;
border-radius: 4px;
cursor: pointer;
background: rgba(0,0,0,0.55);
color: white;
letter-spacing: 1px;
transition: all 0.25s ease;
text-transform: uppercase;
backdrop-filter: blur(3px);
}
/* Hover effect */
.mm-btn:hover {
background: rgba(255, 20, 85, 0.8);
transform: translateY(-2px);
box-shadow: 0 0 12px rgba(255, 20, 85, 0.4);
}
.mm-legal-links {
margin-top: 1.5rem;
margin-bottom: 1.2rem;
font-size: 0.95rem;
font-family: 'Arial', sans-serif;
color: rgba(255,255,255,0.9);
}
.mm-legal-links a {
color: #ffd86b;
text-decoration: none;
transition: color 0.2s ease, text-shadow 0.2s ease;
}
.mm-legal-links a:hover {
color: #fff3b0;
text-shadow: 0 0 8px rgba(255, 216, 107, 0.5);
}
.mm-legal-links span {
margin: 0 0.5rem;
color: rgba(255,255,255,0.6);
}
/* Mobile adjustments */
@media (max-width: 480px) {
.mm-buttons {
max-width: 200px;
}
.mm-btn {
padding: 0.75em;
}
}
</style>
<</nobr>>
<!-- ====================== JS ====================== --><<set $datenow = new Date('May 1, 55 011:00:00')>>
<<set $months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]>>
<<run $datenow.setFullYear(55)>>
/*====================================================*/
/*==================Miscellaneous Declaring==================*/
<<script>>
var passageCode = Story.get('InitVariables').processText();
new Wikifier(null, passageCode);
<</script>>
/*====================================================*/
/*====================Inventory Declaring===================*/
<<script>>
var passageCode = Story.get('InitInventoryVariables').processText();
new Wikifier(null, passageCode);
<</script>>
/*====================================================*/
/*=====================Scenes and texts====================*/
<<script>>
var passageCode = Story.get('JSON Story Texts').processText();
new Wikifier(null, passageCode);
<</script>>
/*====================================================*/
/*=======================Dialogue=======================*/
<<script>>
var passageCode = Story.get('JSON Conversations').processText();
new Wikifier(null, passageCode);
<</script>>/*==================== System Declaring ===================*/
<<set $soundEnabled to false>>
/*================== Miscellaneous Declaring ===================*/
<<set $npcConversationWith to []>><<set $gametips to 0>>
<<set $startingScenario to "">>
<<set $currentPassageConversationIs to "">>
<<set $macroToLoad to "">><<set $displayedMenuOnRightBarTxt to "">>
<<set $displayDialogue to "">>
<<set $workTimer to 100>>
<<set $timesWorked to 0>>
<<set $timeOfGameStart = new Date($datenow)>>
<<set $masterVolume to 100>>
<<set $playername to "">><<set $playershortname to "">>
<<set $fathername to "">>
<<set $mothername to "">>
<<set $caelthirname to "">><<set $caelname to "">>
<<set $vaelorinname to "">><<set $vaelname to "">>
<<set $thalenwyrename to "">><<set $thalename to "">>
/*==============Event Starters and Progress====================*/
<<set $mainStory to 0>>
<<set $motherStoryOne to 0>>
<<set $obboStoryOne to 0>>
<<set $greysonStoryOne to 0>>
<<set $vaelStoryOne to 0>>
<<set $endContentMsg to 0>>
<<set $introCampSexCounterDrugged to 0>>
/*================== Player Variables Declaring ===================*/
<<set $playername to "Aelara">><<set $playershortname to "Aela">>
<<set $lastClothesChangeDay = $stringDayNow>>
<<set $wifeStatsShow = false>><<set $lastbath to "">>
<<set $wifeCurrentCumVagina to 0>><<set $wifeCurrentCumVaginaTimer to $datenow>>
<<set $wifeCurrentCumAssHole to 0>><<set $wifeCurrentCumAssHoleTimer to $datenow>>
<<set $wifeCurrentCumMouth to 0>><<set $wifeCurrentCumMouthTimer to $datenow>>
<<set v.wifeFucking to []>>
<<set v.wifeBullsHistory to []>>
<<set $bodyPoseScale = 3>>
/*================== Player Fame =*/
<<set $playerKnownAs to "Princess of Elliahal">>
<<set $playerFameElliahalKingdom to "Princess">><<set $playerFameElves to "Princess of Elliahal">>
<<set $playerFameOrcs to "Elven Princess">><<set $playerFameGoblins to "Unknown">>
<<set $playerFameOgres to "Elven Princess">><<set $playerFameTrolls to "Unknown">>
<<set $playerFameHumans to "Elven Princess">><<set $playerFameDwarves to "Elven Princess">>
/*================== Player Passive Abilities =*/
<<set $playerKnownAs to "Princess of Elliahal">>/*------------- Time Manager*/
<<set $stringMinutesNow = $datenow.getMinutes()>>
<<set $stringTimeNow = $datenow.getHours()>>
<<set $stringDayNow = $datenow.getDate()>>
<<set $stringTimeMilisecNow = $datenow.getTime()>>
<<set $currentpassagename to passage()>>
<<set $daysSinceGameStart = Math.floor(
($datenow.getTime() - $timeOfGameStart.getTime()) / (1000 * 60 * 60 * 24)
)>>
<<set $monthName = $months[$datenow.getMonth()]>>
<<set $day = String($datenow.getDate()).padStart(2, "0")>>
<<set $year = $datenow.getFullYear()>>
<<set $hour24 = $datenow.getHours()>>
<<set $hour12 = $hour24 % 12>>
<<if $hour12 === 0>>
<<set $hour12 = 12>>
<</if>>
<<if $stringMinutesNow <= 9>>
<<set $stringMinutesMM to ("0" + $stringMinutesNow)>>
<<else>>
<<set $stringMinutesMM to $stringMinutesNow>>
<</if>>
<<set $ampm = $hour24 >= 12 ? "PM" : "AM">>
<<set $formattedDateNow = $monthName + " " +$day + " " + $year + " " + $hour12 + ":" + $stringMinutesMM + $ampm>>
/*=====================WifeSexTimer======================*/
<<if v.wifeFucking.length > 0>>
/* If array length changed (push/pop/etc.), reset the timer */
<<if v._wifeFuckingLastLength != v.wifeFucking.length>>
<<set v._wifeFuckingEndTime = $datenow.getTime() + (random(30,40) * 60000)>>
<<set v._wifeFuckingTimerSet = true>>
<<set v._wifeFuckingLastLength = v.wifeFucking.length>>
<</if>>
/* If time is up, clear array and call event */
<<if $datenow.getTime() >= v._wifeFuckingEndTime>>
<<run
var now = $datenow; // current time
// Map each entry with a random minute offset and store actual Date
var mappedArray = v.wifeFucking.map(e => {
if (typeof e !== "string") return e;
// Randomly subtract 0-5 minutes
var offset = Math.floor(Math.random() * 6);
var eventDate = new Date(now.getTime() - offset * 60000);
var readable;
if (e.includes("@v")) readable = e.replace("@v", " - Vaginal");
else if (e.includes("@a")) readable = e.replace("@a", " - Anal");
else if (e.includes("@o")) readable = e.replace("@o", " - Oral");
else readable = e;
return { readable, date: eventDate };
});
// Sort chronologically, earliest first
mappedArray.sort((a, b) => a.date - b.date);
// Format final strings
var finalArray = mappedArray.map(e => {
var day = String(e.date.getDate()).padStart(2, "0");
var month = String(e.date.getMonth() + 1).padStart(2, "0");
var hours = String(e.date.getHours()).padStart(2, "0");
var minutes = String(e.date.getMinutes()).padStart(2, "0");
return `${e.readable} (${day}/${month} - ${hours}:${minutes})`;
});
// Ensure history array exists
if (!v.wifeBullsHistory) v.wifeBullsHistory = [];
// Push into history
v.wifeBullsHistory.push(...finalArray);
>>
/* Custom event here */
/*Blablablafunction() TO SET WIFE DIRTINESS AND CUM LAYERS CONTROL BELOW HERE*/
<<run UpdateCumLayers()>>
/*==================================*/
<<set v.wifeFucking = []>>
<<set v._wifeFuckingTimerSet = false>>
<<set v._wifeFuckingLastLength = 0>>
<</if>>
<</if>>
/*=====================WifeCreampiesTimer======================*/
<<script>>
var passageCode = Story.get('WifeTimersProcessTexts').processText();
new Wikifier(null, passageCode);
<</script>>
/*========================Money=========================*/
<<set $money to $backpack.count('money')>>
/*=====================Starting Scenarios=====================*/
<<if $startingScenario == "The Unlucky">><<script>>
var passageCode = Story.get('The Unlucky').processText();
new Wikifier(null, passageCode);
<</script>><</if>>/*===================WifeCreampiesTimer====================*/
<<if $wifeCurrentCumVagina > 16>><<set $wifeCurrentCumVagina to 16>><</if>>
<<if $wifeCurrentCumAssHole > 13>><<set $wifeCurrentCumAssHole to 13>><</if>>
<<if $datenow - $wifeCurrentCumAssHoleTimer >= 18000000 && $wifeCurrentCumAssHole > 0>> // 5 hours to reduct one cum
<<set $wifeCurrentCumAssHole-->><<set $wifeCurrentCumAssHoleTimer to $datenow>>
<</if>>
<<if $datenow - $wifeCurrentCumVaginaTimer >= 18000000 && $wifeCurrentCumVagina > 0>> // 5 hours to reduct one cum
<<set $wifeCurrentCumVagina-->><<set $wifeCurrentCumVaginaTimer to $datenow>>
<</if>>
<<switch $wifeCurrentCumAssHole>>
<<case 0>><<set $rectumSlot to "a0mini">>
<<case 1>><<set $rectumSlot to "a1mini">>
<<case 2>><<set $rectumSlot to "a2mini">>
<<case 3>><<set $rectumSlot to "a3mini">>
<<case 4>><<set $rectumSlot to "a4mini">>
<<case 5>><<set $rectumSlot to "a5mini">>
<<case 6>><<set $rectumSlot to "a6mini">>
<<case 7>><<set $rectumSlot to "a7mini">>
<<case 8>><<set $rectumSlot to "a8mini">>
<<case 9>><<set $rectumSlot to "a9mini">>
<<case 10>><<set $rectumSlot to "a10mini">>
<<case 11>><<set $rectumSlot to "a11mini">>
<<case 12>><<set $rectumSlot to "a12mini">>
<<case 13>><<set $rectumSlot to "a13mini">>
<</switch>>
<<switch $wifeCurrentCumVagina>>
<<case 0>><<set $uterusSlot to "v0mini">>
<<case 1>><<set $uterusSlot to "v1mini">>
<<case 2>><<set $uterusSlot to "v2mini">>
<<case 3>><<set $uterusSlot to "v3mini">>
<<case 4>><<set $uterusSlot to "v4mini">>
<<case 5>><<set $uterusSlot to "v5mini">>
<<case 6>><<set $uterusSlot to "v6mini">>
<<case 7>><<set $uterusSlot to "v7mini">>
<<case 8>><<set $uterusSlot to "v8mini">>
<<case 9>><<set $uterusSlot to "v9mini">>
<<case 10>><<set $uterusSlot to "v10mini">>
<<case 11>><<set $uterusSlot to "v11mini">>
<<case 12>><<set $uterusSlot to "v12mini">>
<<case 13>><<set $uterusSlot to "v13mini">>
<<case 14>><<set $uterusSlot to "v14mini">>
<<case 15>><<set $uterusSlot to "v15mini">>
<<case 16>><<set $uterusSlot to "v16mini">>
<</switch>>
<<switch $wifeCurrentCumMouth>>
<<case 1>>
<</switch>>
<<run SyncCumSlotsFromCounters()>><<set $cumBottomSlot to "">>
<<set $cumTopSlot to "">>
<<set $neckSlot to "">>
<<set $chestSlot to "Elven Dress 6">>
<<set $hipSlot to "">>
<<set $legSlot to "">>
<<set $feetSlot to "">>
<<set $acessorySlot to "">>
<<set $cumBottomClothSlot to "">>
<<set $cumTopClothSlot to "">>
<<set $rectumSlot to "a0mini">>
<<set $uterusSlot to "v0mini">>
<<newinv $backpack>>
<<newinv $shopMarket>>
<<item "money" "Money">>
<<description>>\
The principal currency, used to buy and sell things.\
<</item>>
<<item "key_1" "Crypt Key">>
<<description>>\
An old, rusty key with a skull shape on it. Spoooooky.\
<<unique>>
<</item>>
<<consumable "Small Health Potion">>
<<set $pCHP to Math.clamp($pCHP + 20, 0, 100)>>
<<description>>\
<<include "Small HPotion">> /* Show passage*/
<</consumable>>
<<item "Chastity Caged">>
<<description>>\
<<nobr>>
<<if $knows>>
<font color="grey"><h5>A chastity device.</h5></font>
<<else>>
<font color="grey"><h5>A chastity device.</h5></font>
<</if>>
<</nobr>>\
<<unique>>
<</item>>
<<set $wifeFaceMap = {
"fb": "face_blush",
"fh": "face_happy",
"fhb": "face_happy_blush",
"fm": "face_mad",
"fmb": "face_mad_blush",
"fs": "face_sad",
"fss": "face_sassy",
"fsm": "face_smirk",
"fsu": "face_surprised",
"fsub": "face_surprised_blush",
"fsuh": "face_surprised_happy",
"fsuhb": "face_surprised_happy_blush",
"fstb": "face_surprised_tongue_blush",
"fsusy": "face_sussy",
"fsust": "face_sussy_tongue",
"fsustb": "face_sussy_tongue_blush",
"ft": "face_tongue"
}>>
<<set $clothesFemale to [
{name: "Elven Dress 6", style: "dresses", cute: 3, sexy: 8, exposure: 7, quality: 8, color: "green", shopPrice: 1350},
{name: "Elven Dress 6", style: "dresses", cute: 3, sexy: 8, exposure: 7, quality: 8, color: "green", shopPrice: 1350},
]>>
<<setBG 1 setup.ImagePath ''>>
<<generateNPCWife -70 -30 200 500 base>><style>
.wife-avatar-wrapper:hover .hover-layer {
display: block !important;
}
</style>
<span class="custom-button" style="top: 56%;left: 60%;">
<<button "refresh">>
<<set $chestSlot = "">>
<<set $hipSlot = "">>
<<set $legSlot = "">>
<<set $feetSlot = "">>
<<goto "Untitled Passage 1">><</button>>
</span>
<<script>>
window.createImage = function() {
var div = document.createElement('div');
div.id = 'wife-xray-popup';
div.style.position = 'fixed';
div.style.top = '50%';
div.style.left = '50%';
div.style.transform = 'translate(-50%, -50%)';
div.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
div.style.color = '#fff';
div.style.padding = '20px';
div.style.borderRadius = '10px';
div.style.zIndex = '9999';
// Use flexbox to align images side by side
div.style.display = 'flex';
div.style.gap = '10px'; // space between images
div.style.justifyContent = 'center';
div.style.alignItems = 'center';
var img1 = document.createElement('img');
img1.src = setup.ImagePath + "characters/wife/xray/a" + v.wifeCurrentCumAssHole + ".png";
img1.style.width = '200px'; // Adjust size
div.appendChild(img1);
var img2 = document.createElement('img');
img2.src = setup.ImagePath + "characters/wife/xray/v" + v.wifeCurrentCumVagina + ".png";
img2.style.width = '200px'; // Adjust size
div.appendChild(img2);
// Optional close button
var closeBtn = document.createElement('button');
closeBtn.textContent = 'Close';
closeBtn.style.marginLeft = '10px';
closeBtn.onclick = function() { div.remove(); };
div.appendChild(closeBtn);
document.body.appendChild(div);
// Append the container to body
document.body.appendChild(div);
}
<</script>>
<<run createImage()>>
<<script>>
setTimeout(function () {
var bar = document.getElementById("right-ui-bar");
var src = document.getElementById("rs-actions-source");
if (!bar || !src) { return; }
var target = document.getElementById("right-ui-bar-actions");
if (!target) {
target = document.createElement("div");
target.id = "right-ui-bar-actions";
bar.appendChild(target);
}
target.innerHTML = "";
while (src.firstChild) {
if (src.firstChild.nodeType === 3 && !src.firstChild.nodeValue.trim()) {
src.removeChild(src.firstChild);
continue;
}
target.appendChild(src.firstChild);
}
src.parentNode.removeChild(src);
}, 0);
<</script>>
<div class="avatar-overlayWife"><<generateNPCWife -53 -11 110 400 base>></div>
<div id="rs-actions-source">
<<button "Fame">><<script>>Dialog.wiki(Story.get("FameScreen").processText());<</script>><</button>>
<<button "Abilities">><<script>>Dialog.wiki(Story.get("AbilitiesScreen").processText());<</script>><</button>>
<<button "Relations">><<script>>Dialog.wiki(Story.get("RelationshipScreen").processText());<</script>><</button>>
<<button "Sexlog">><<script>>Dialog.wiki(Story.get("DickHistoryScreen").processText());<</script>><</button>>
</div>
<<if $stringTimeNow <= 6 || $stringTimeNow >= 19>><<runScenario "princesstentnight">><</if>>
<<if $stringTimeNow > 6 && $stringTimeNow < 19>><<runScenario "princesstent">><</if>>
/*22nd Commander first encounter*/
<<if $mainStory == 0>><<set $mainStory to 1>><<goto "camp Thale intro">><</if>>
/*------------------------------------*/
<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.50" data-y="0.32" style="transform: translate(-50%, -50%);">
<<button "sleep">>
<<if $chestSlot != "">>
<<run openConversation("cant_sleep_message")>>
<</if>>
<<if $chestSlot == "">>
<<if (($datenow.getHours() < 8) && ($datenow.getHours() >= 0))>>
<<run $datenow.setHours(8)>>
<<run Save.slots.save(0)>>
<<if $mainStory != 1>>
<<goto "Princess Tent">>
<<else>>
<<if $endContentMsg == 0>>
<<set $endContentMsg to 1>>
<<run openConversation("end_of_content_message")>>
<<else>>
<<goto "PrincessTent Bed Loop Intro">>
<</if>>
<</if>>
<</if>>
<<if ($datenow.getHours() >= 18)>>
<<run $datenow.setDate($datenow.getDate() + 1)>>
<<run $datenow.setHours(8)>>
<<run Save.slots.save(0)>>
<<if $mainStory != 1>>
<<goto "Princess Tent">>
<<else>>
<<if $endContentMsg == 0>>
<<set $endContentMsg to 1>>
<<run openConversation("end_of_content_message")>>
<<else>>
<<goto "PrincessTent Bed Loop Intro">>
<</if>>
<</if>>
<</if>>
<</if>>
<</button>> </span>
<<if $lastbath && (($datenow.getTime() - $lastbath) < 60*60*1000)>>
<!-- hide / don't show -->
<<else>>
<!-- show it -->
<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.05" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "bathe">>
<<set $lastbath to $datenow>>
<<run $datenow.setMinutes($datenow.getMinutes() + 30)>>
<<set $cumBottomSlot to "">>
<<set $cumTopSlot to "">>
<<set $neckSlot to "">>
<<set $chestSlot to "">>
<<set $hipSlot to "">>
<<set $legSlot to "">>
<<set $feetSlot to "">>
<<set $acessorySlot to "">>
<<set $cumBottomClothSlot to "">>
<<set $cumTopClothSlot to "">>
<<if $wifeCurrentCumVagina > 3>>
<<set $wifeCurrentCumVagina to 3>>
<</if>>
<<if $wifeCurrentCumAssHole > 3>>
<<set $wifeCurrentCumAssHole to 3>>
<</if>>
<<goto "Princess Tent">>
<</button>> </span>
<</if>>
<<if $chestSlot != "">><span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.95" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "Go Outside">>
<<run $datenow.setMinutes($datenow.getMinutes() + 1)>>
<<goto "Princess Tent Outside">>
<</button>> </span><</if>>
<<if $chestSlot == "">><span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.35" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "Get Dressed">>
<<set $chestSlot to "Elven Dress 6">>
<<goto "Princess Tent">>
<</button>> </span><</if>>
<<if $chestSlot != "">><span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.35" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "Get Undressed">>
<<set $chestSlot to "">>
<<goto "Princess Tent">>
<</button>> </span><</if>><<runScenario "wartent">>
<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.50" data-y="0.32" style="transform: translate(-50%, -50%);">
<<button "Go Outside">>
<<run $datenow.setMinutes($datenow.getMinutes() + 1)>>
<<goto "War Tent Outside">>
<</button>> </span>
/*<span class="pov-hotspot" data-povhotspot="1" data-x="0.30" data-y="0.52" data-scale="0.14" style="transform: translate(-50%, -50%);">
<<character "caelthir" "base">>
</span>
<span class="pov-hotspot" data-povhotspot="1" data-x="0.70" data-y="0.52" data-scale="0.14" style="transform: translate(-50%, -50%);">
<<character "eldarion" "base2">>
</span>*/<<script>>
setup.comicQueue = [];
setup.comicActive = false;
v.comicImages = {
/*======================================================================================================================*/
/*======================================================================================================================*/
/* |Dream Intro| */
/*======================================================================================================================*/
/*======================================================================================================================*/
"dream_aethyra_intro": [
{
"file": "",
"text": {
"1": "The dream does not begin with a place, but with a feeling, weightless, silver, and endless, as though you are drifting inside moonlight itself.",
"2": "Before you stands a luminous figure, neither fully woman nor fully mist, her shape woven from soft radiance and starlit veils.",
"3": "She does not ask your name. She speaks as though she has always known it.",
"4": "@av:aethyra Child of that old blood... you have walked so long inside your own skin without understanding what sleeps beneath it.",
"5": "@av:aethyra Beauty was the first gift to bloom in you, though you were taught to mistake it for ornament.",
"6": "@av:aethyra It is not ornament. It is inheritance."
}
},
{
"file": "",
"text": {
"1": "@av:aethyra What others call beauty in you is not chance, nor merely the kindness of a pleasing face. It is something older, something shaped into your blood.",
"2": "@av:aethyra Long before your birth, meant to draw eyes, stir want, and bend attention toward you like flowers turning toward the sun.",
"3": "@av:aethyra Men feel it most easily, though few would know how to name what they feel.",
"4": "@av:aethyra They call it fascination, longing, distraction, temptation. They wrap it in mortal words because mortal minds fear what they cannot classify.",
"5": "@av:aethyra But your presence does more than invite admiration.",
"6": "@av:aethyra It awakens hunger."
}
},
{
"file": "",
"text": {
"1": "@av:aethyra There is fragrance in you as well, though not one crushed from herb or blossom.",
"2": "@av:aethyra It rises from your body like an unseen hymn, subtle to the innocent, maddening to those already inclined toward want.",
"3": "@av:aethyra You have noticed it, have you not? The way men linger. The way their composure thins around you without understanding why.",
"4": "@av:aethyra That, too, is yours.",
"5": "@av:aethyra Not perfume. Not accident.",
"6": "@av:aethyra A call written into flesh."
}
},
{
"file": "",
"text": {
"1": "@av:aethyra Yet neither beauty nor allure is the strangest thing sleeping in your blood.",
"2": "@av:aethyra There is another gift in you, far rarer, far more dangerous, because it touches the border between desire and restoration.",
"3": "@av:aethyra When your body joins with another in intimacy, healing may answer where wounds once lingered.",
"4": "@av:aethyra Not always fully. Not always simply. But the current is there, waiting, real as breath.",
"5": "@av:aethyra Pleasure and renewal are not separate in your lineage, little bloom, they were twined together long ago.",
"6": "@av:aethyra Others might seek comfort in touch. In you, touch may become power."
}
},
{
"file": "",
"text": {
"1": "@av:aethyra Do not mistake these gifts for blessings alone.",
"2": "@av:aethyra Anything that draws desire may also draw danger.",
"3": "@av:aethyra That is why you were not told. That is why so much around you has always felt half-hidden, half-spoken, wrapped in caution and shame.",
"4": "@av:aethyra Your bloodline remembers truths your household only fears.",
"5": "@av:aethyra And fear has a way of dressing itself as silence.",
"6": "@av:aethyra But silence does not erase inheritance."
}
},
{
"file": "",
"text": {
"1": "@av:aethyra There is more in you than this.",
"2": "@av:aethyra Much more.",
"3": "@av:aethyra These are merely the first petals opening, beauty that compels, scent that entices, touch that restores.",
"4": "@av:aethyra Other gifts still sleep deeper, sealed beneath memory, instinct, and blood.",
"5": "@av:aethyra You will discover them in time, though time may not ask gently.",
"6": "@av:aethyra When they wake, you will understand that none of this began with you."
}
},
{
"file": "",
"text": {
"1": "@av:aethyra It began long before your first breath.",
"2": "@av:aethyra You are not an accident of nature, child. You are continuation.",
"3": "@av:aethyra A thread carried forward. A vessel of an old design. A question your bloodline has been asking the world for generations.",
"4": "@av:aethyra And the world, as you will learn, has never stopped answering.",
"5": "@av:aethyra What lives in you is unique. And origins, sooner or later, always call their daughters home.",
"6": "@av:aethyra Wake now, little child. Much is about to unfold."
}
}
],
/*======================================================================================================================*/
/*======================================================================================================================*/
/* |War Camp Intro| */
/*======================================================================================================================*/
/*======================================================================================================================*/
"scene_intro_camp": [
{
"file": "",
"text": {
"1": "@av:eldarion Now that we have some time alone, what's on your mind?",
"2": "@av:caelthir Father. Aela. The scouts returned—the orc warband has moved closer to the river crossing.",
"3": "@av:caelthir The crossing is barely defended. If they take it before dawn, they’ll have a clear path to the supply lines.",
"4": "@av:caelthir Father, I recommend moving the third battalion forward tonight.",
"5": "@av:caelthir And Aela… you should retire to your tent. The camp grows restless after dark.",
"6": "@av:player Do you wish me to do as Caelthir says, father?"
}
},
{
"file": "",
"text": {
"1": "@av:eldarion Caelthir’s assessment is sound. The river crossing must be secured.",
"2": "@av:eldarion Move the third battalion, but keep the archers in reserve on the high ridge. I will not commit everything before dawn.",
"3": "@av:eldarion As for you, Aela… your brother speaks from concern, not command.",
"4": "@av:eldarion Your presence affects the atmosphere. Do you feel unsafe?",
"5": "@av:player N... No dad, I trust your soldiers.",
"6": "@av:eldarion You may stay if you wish—but after dusk, you remain within my sight or Caelthir’s."
}
},
{
"file": "",
"text": {
"1": "@av:player As you wish, dad.",
"2": "@av:eldarion Double the patrols along the tree line here. I want no surprises before the third battalion is in position.",
"3": "@av:eldarion You may find the strategy discussions tedious, Aela—but observing them is its own education.",
"4": "@av:eldarion Tell me—what do you notice about the placement I’ve suggested for the archers?",
"5": "@av:player I... dad, sorry, I don't understand these logistics... I will prepare the meal, please don't mind me...",
"6": "@av:caelthir You will learn if you stay and listen, Aela. The archers on the high ridge—what advantage does that give us?"
}
},
{
"file": "",
"text": {
"1": "@av:player Cael, please... I... I don't know. I think I'm better with other things...",
"2": "@av:eldarion Caelthir. Let her answer in her own time. Not everyone learns through pressure.",
"3": "@av:eldarion Aela—when you look at this map, what do you see? Not troop placements. What catches your eye first?",
"4": "My gaze slips for a heartbeat—shame flares hot, and I force it back to the map.",
"5": "@av:player I... it is a beautiful river?",
"6": "@av:caelthir A beautiful river. You see beauty. I see a tactical vulnerability. Father sees both."
}
},
{
"file": "",
"text": {
"1": "@av:caelthir What else do you see when you look away from the map? The way their eyes follow you when you walk past?",
"2": "I want to hide my face in shame... ",
"3": "@av:player Y-yes, Cael. Their eyes do follow me—what does that have to do with tactics?",
"4": "@av:eldarion It has everything to do with tactics, Aela.",
"5": "@av:eldarion A battlefield is not only terrain and troops—morale, distraction, perception are forces as real as any blade.",
"6": "@av:eldarion Your presence affects their focus. That is not your fault, but it is a fact I must account for."
}
},
{
"file": "",
"text": {
"1": "@av:eldarion Beauty reminds us what we fight to protect—but understanding what others might do to possess it is where strategy begins.",
"2": "@av:player Father… what did you mean when you said a variable you must account for? You want to use me in your plan?",
"3": "I asked genuinely puzzled, trying to figure out what you meant by that.",
"4": "@av:eldarion Not as a piece to be moved on a board, no.",
"5": "@av:eldarion Your presence is a factor—like weather or terrain. The men’s attention follows you, and that affects discipline.",
"6": "@av:eldarion Tell me—when you walk through camp, where do you feel their gazes most intensely?"
}
},
{
"file": "",
"text": {
"1": "I get flustered—talking about men staring at me makes my stomach twist.",
"2": "@av:player Uhh… their gazes are all the time… everywhere…",
"3": "@av:player And they make comments to one another. They think I don’t hear, but I do.",
"4": "@av:eldarion I see.",
"5": "@av:eldarion And the comments—are they admiration, or something darker? The difference matters.",
"6": "@av:eldarion When you hear them, do they sound like idle fantasy… or intention taking shape?"
}
},
{
"file": "",
"text": {
"1": "@av:player I… I think it’s fantasy… they say what they would do… how they’d pin me…",
"2": "@av:player Sorry—I'm talking too much.",
"3": "@av:caelthir They tell you how they would pin you.",
"4": "@av:caelthir That isn’t “fantasy,” Aela. It’s rehearsal. A step closer to making it real if discipline breaks.",
"5": "@av:player I… I understand, but I think it’s just silly jokes… they’re men, after all… right?",
"6": "@av:caelthir Men at war are not men at court. What they whisper isn’t a jest—it’s a blueprint."
}
},
{
"file": "",
"text": {
"1": "@av:player Father, Brother… you’re thinking too much. Please—shift your attention to more pressing matters.",
"2": "@av:eldarion Your safety is a pressing matter, Aela.",
"3": "@av:eldarion Ignoring fraying discipline does not strengthen the camp—it weakens it.",
"4": "@av:eldarion Tell me: which battalion’s area do you hear these “jokes” most frequently?",
"5": "I’m about to answer—",
"6": "—when the tent flap snaps and someone steps in, and the air suddenly feels colder."
}
}
],
"scene_intro_camp2": [
{
"file": "",
"text": {
"1": "Areothic enters. His sheer size and that gaze—my throat tightens and fear crawls up my spine.",
"2": "@av:areothic The border scouts are dead. The orcs aren’t just marching—they’re already at the river. The crossing is lost.",
"3": "@av:areothic Pull your third battalion back or you’ll lose them before they can even form a line.",
"4": "@av:areothic And why you keep the princess here… We are at war and every soldier’s attention drifts the moment she breathes.",
"5": "@av:caelthir Your report is noted, Warlord. Your commentary on my sister is not.",
"6": "@av:caelthir If the crossing is compromised, we pull back and fortify the ridge. Archers cover the retreat—let the slope bleed them."
}
},
{
"file": "",
"text": {
"1": "@av:caelthir Aela. Go to your tent. Now. Take two guards from the royal detail.",
"2": "@av:caelthir Bar the tent flap. Do not open it for anyone but Father or me. Do you understand?",
"3": "My voice sticks—so I just nod, fast, swallowing my fear.",
"4": "I stand too quickly, silk whispering, and I keep my eyes down as if that could make me invisible.",
"5": "I promptly obey and slip out toward my private tent—escorted by soldiers.",
"6": "Behind me, their voices blur into strategy… but I can still feel Areothic’s presence like a shadow on my back."
}
}
],
/*======================================================================================================================*/
/*======================================================================================================================*/
/* |Princess Idea Intro| */
/*======================================================================================================================*/
/*======================================================================================================================*/
"princess_idea_intro": [
{
"file": "",
"text": {
"1": "The guards walk me back in silence, their spears scraping softly as they flank me like moving shadows.",
"2": "Inside my tent, the air is warmer—lamp oil, linen, and the faint perfume that never leaves my skin.",
"3": "I exhale like I’ve been holding my breath since Areothic stepped in.",
"4": "For a while, it’s only the muffled rhythm of camp life beyond the canvas—distant laughter, clinking cups, a horse snorting.",
"5": "Then something changes. A ripple, then a surge—boots running, metal snapping into place, voices rising sharper.",
"6": "I press my palm to the tent wall, listening, my pulse syncing with the commotion outside."
}
},
{
"file": "",
"text": {
"1": "Orders crack through the night like dry branches breaking.",
"2": "Tent pegs get yanked free, canvas flaps slapped shut, and someone nearby curses as a crate drops into the dirt.",
"3": "A horn sounds—short, urgent—followed by the heavy hush that comes when soldiers know it’s real.",
"4": "@av:eldarion Soldiers of the realm—pack the camp. We depart immediately.",
"5": "My throat tightens. Immediate departure means no comfort, no preparation—only motion and survival.",
"6": "@av:caelthir 22nd battalion—hold position. You remain to secure the camp and protect the princess."
}
},
{
"file": "",
"text": {
"1": "Protect the princess. The words hit like a brand—like I’m not a person, but a problem that needs guards assigned to it.",
"2": "Outside, men repeat the command with rough voices, some resentful, some relieved not to be marching into an orc tide.",
"3": "I picture them—stuck here because of me—watching my tent like wolves told to sit.",
"4": "The map flashes in my mind: Father’s finger tracing the river bend… the ridge… the crossing… and that quieter stretch of water nearby.",
"5": "A place away from tents. Away from eyes. Away from whispered “jokes” that don’t sound like jokes at all.",
"6": "@av:player If they’re going to guard me… then I should be somewhere no one thinks to look."
}
}
],
"princess_river_arrival": [
{
"file": "",
"text": {
"1": "The river is nothing like the battlefield lines on parchment—here it’s quiet, silvered by moonlight and framed by reeds.",
"2": "This corner feels hidden from the world, tucked behind a gentle curve and a curtain of low-hanging branches.",
"3": "The water barely moves at all, a clear, still pool with no current—like it’s holding its breath.",
"4": "Smooth stones cradle the edge, and the mud is firm enough to stand on without sinking.",
"5": "It’s perfect. Safe. Private. So far from the camp that even the distant clamor can’t reach me.",
"6": "I stare for a moment, stunned by how beautiful it is—like I’ve stumbled into a secret meant only for me."
}
},
{
"file": "",
"text": {
"1": "A smile creeps up before I can stop it, and my shoulders loosen for the first time tonight.",
"2": "The air smells clean here—water and wet earth and something faintly sweet blooming along the bank.",
"3": "I kneel and dip my fingers in, watching the surface ripple—cool, inviting, almost gentle.",
"4": "The tension in my chest eases, replaced by a bright little thrill that feels dangerously close to excitement.",
"5": "@av:player Finally… a place where I can breathe.",
"6": "@av:player And bathe—somewhere that feels like a dream."
}
},
],
/*======================================================================================================================*/
/*======================================================================================================================*/
/* |Areothic Lake Encounter| */
/*======================================================================================================================*/
/*======================================================================================================================*/
"areothic_river_confrontation":[
{
"file": "",
"text": {
"1": "I turn too fast in the water, my hands flying up in a useless attempt to hide myself.",
"2": "@av:areothic Taking a midnight bath, Princess?",
"3": "@av:areothic While your father believes you’re safe in your tent, you’re out here alone in the dark.",
"4": "@av:areothic Brave little thing. Or just profoundly stupid.",
"5": "My whole body locks at the sound of his voice. He was the last person I wanted to see.",
"6": "@av:player I... Sir... Please don't look."
}
},
{
"file": "",
"text": {
"1": "He is already there at the water’s edge when I finally force myself to look straight at him, as if he had been waiting for this moment all along.",
"2": "Moonlight glints along the edges of his armor, and his shadow lies dark across the water between us.",
"3": "My breath turns shallow. I can’t tell if the chill under my skin comes from the night breeze or from him.",
"4": "@av:areothic Don’t look?",
"5": "@av:areothic You really thought a princess could slip away from camp this easily and remain unnoticed?",
"6": "@av:areothic Tell me, Princess, are you truly that naive?"
}
},
{
"file": "",
"text": {
"1": "He is already far too close, at the water’s edge like he belongs there more than I do.",
"2": "The water ripples around me as I retreat without meaning to, my footing unsteady beneath the cold shallows.",
"3": "My pulse stumbles hard in my throat, and the shore suddenly feels like a trap instead of safety.",
"4": "@av:areothic Your guards are watching an empty tent.",
"5": "@av:areothic Your father and brother already rode out with the army.",
"6": "@av:areothic And you are here. Alone."
}
}
],
"areothic_river_confrontation_explain": [
{
"file": "",
"text": {
"1": "@av:player I... I just wanted to bathe...",
"2": "@av:player Please don’t tell Father that I left the tent.",
"3": "Even to my own ears, my voice sounds small and frightened.",
"4": "I hate how quickly the plea leaves me, like fear makes decisions before I can.",
"5": "@av:areothic Don’t tell your father?",
"6": "@av:areothic Your father is deciding which men may die before dawn. Your disobedience should matter most to you, not him."
}
},
{
"file": "",
"text": {
"1": "He watches me in silence for a moment that feels much too long.",
"2": "My body betrays me anyway, every tremor and shallow breath revealing how badly I’m shaking.",
"3": "I try to hold his gaze and fail almost instantly.",
"4": "@av:areothic You left your guards.",
"5": "@av:areothic You left the center of camp and came somewhere isolated.",
"6": "@av:areothic Orcs are not the only predators in the night, Princess."
}
},
{
"file": "",
"text": {
"1": "The word predators hits harder than a shout would have.",
"2": "I feel suddenly foolish for every step that brought me here, for every thought that solitude could still belong to me.",
"3": "The river I imagined as peaceful now feels narrow, exposed, and cold.",
"4": "@av:areothic You asked me not to look.",
"5": "@av:areothic You are not in a position to ask for anything.",
"6": "@av:areothic You are in a position to answer."
}
},
{
"file": "",
"text": {
"1": "He does not move at all, yet his stillness weighs on the shoreline like something deliberate and inescapable.",
"2": "I can’t make myself step past him, and I can’t bear remaining where I am on the damp grass beside the water.",
"3": "My mind races uselessly between escape, apology, and silence.",
"4": "@av:areothic Tell me, little princess, if I pin you to this moss and let the lake listen to every sound you make, who will come to your aid?",
"5": "My throat tightens. Shame and fear knot together until I can barely think.",
"6": "@av:player I..."
}
}
],
"areothic_river_confrontation_order": [
{
"file": "",
"text": {
"1": "@av:player Then you should leave.",
"2": "@av:player I am your princess, and I order you to turn away at once.",
"3": "The words come out sharper than I feel, brittle with fear and desperation.",
"4": "For one heartbeat, I cling to rank like it can still shield me here.",
"5": "@av:areothic An order?",
"6": "@av:areothic Out here, alone in the dark, you think a title is the same thing as power?"
}
},
{
"file": "",
"text": {
"1": "I try to keep my chin high, but the water betrays me, quivering around my unsteady stance.",
"2": "He does not move. Does not bow. Does not turn away.",
"3": "The silence itself feels like mockery.",
"4": "@av:areothic You left your guards.",
"5": "@av:areothic You left the center of camp and came somewhere isolated.",
"6": "@av:areothic Orcs are not the only predators in the night, Princess."
}
},
{
"file": "",
"text": {
"1": "The word predators hits harder than a shout would have.",
"2": "My borrowed boldness cracks at once, leaving only the cold and the awful exposure of this place.",
"3": "The river I imagined as peaceful now feels narrow, exposed, and cold.",
"4": "@av:areothic You asked me not to look.",
"5": "@av:areothic You are not in a position to ask for anything.",
"6": "@av:areothic You are in a position to answer."
}
},
{
"file": "",
"text": {
"1": "He does not move at all, yet his stillness weighs on the shoreline like something deliberate and inescapable.",
"2": "I can’t make myself step past him, and I can’t bear remaining where I am on the damp grass beside the water.",
"3": "My mind races uselessly between outrage, fear, and silence.",
"4": "@av:areothic Tell me, little princess, if I pin you to this moss and let the lake listen to every sound you make, who will come to your aid?",
"5": "My throat tightens. Shame and fear knot together until I can barely think.",
"6": "@av:player I..."
}
}
],
"areothic_river_confrontation_blackmail": [
{
"file": "",
"text": {
"1": "He does not move, and somehow that still feels like being cornered.",
"2": "The lake breathes softly at my back while his silence presses from the shore.",
"3": "@av:areothic You may tell your father everything.",
"4": "@av:areothic In fact, Princess, I encourage you to try.",
"5": "He speaks as though he already knows how my father will answer.",
"6": "@av:areothic I am the warlord he trusts when borders fail, when he hesitate, when other men miscalculate."
}
},
{
"file": "",
"text": {
"1": "@av:areothic I have won him fields, fortresses, winters, and years of peace your court likes to call inevitable.",
"2": "@av:areothic I stand where his certainty stands.",
"3": "He says them words like facts carved long ago into stone.",
"4": "Those are not boastful. That makes them worse.",
"5": "@av:areothic So when he gets back, go to him.",
"6": "@av:areothic Tell him his daughter slipped past her guards, disobeyed orders, fled the camp, and was found alone at the water by the man he trusts most."
}
},
{
"file": "",
"text": {
"1": "@av:areothic Then tell him what happened here, Princess… when you are finally able to name it.",
"2": "@av:areothic Then watch how quickly your father’s trust begins to curdle into suspicion, of whether you are frightened… or simply lying.",
"3": "My stomach drops so sharply it feels like missing a step in the dark.",
"4": "@av:areothic Do you understand what absolute trust looks like?",
"5": "",
"6": ""
}
},
{
"file": "",
"text": {
"1": "The cold breeze does nothing to hide my shivering, and I can’t tell anymore whether it comes from the night air on my wet skin, from fear, or from both.",
"2": "@av:areothic I will not lose your father’s faith over this. I have earned too much of it, for too long, through too many wars.",
"3": "@av:areothic Trust like that grants men like me a privilege: when doubt enters the room, it does not look our way first.",
"4": "@av:areothic I am loyal to your father. Entirely.",
"5": "@av:areothic But even the most loyal man may have one weakness. Mine is a princess, and years of unquestioned loyalty give me more than enough room to indulge that.",
"6": "@av:areothic I do not need your silence, Princess. I am merely advising you that speaking will not end well for you."
}
},
{
"file": "",
"text": {
"1": "@av:areothic I will not lose your father’s faith over what will happen here. I have earned too much of it, for too long, through too many wars.",
"2": "The words strike like ice through my chest... What does he mean, what will happen here?",
"3": "@av:areothic Trust like that grants men like me a privilege: when doubt enters the room, it does not look our way first.",
"4": "@av:areothic I am loyal to your father. Entirely.",
"5": "@av:areothic But even the most loyal man may have one weakness. Mine is a princess, and years of unquestioned loyalty give me more than enough room to indulge that.",
"6": "@av:player A... And what... What do you want?"
}
}
],
"areothic_river_confrontation_demands": [
{
"file": "",
"text": {
"1": "I flinch backward, there’s nowhere to go.",
"2": "I see his notrils moving a little.",
"3": "@av:areothic That sweet, anxious scent of yours...",
"4": "@av:areothic What do I want? My voice drops to a low, considering murmur. Right now, I want you to understand your position.",
"5": "@av:areothic You are naked, alone, and at my mercy. It is just us in the middle of nowhere. The only thing between you and whatever I decide to do is my own fleeting patience.",
"6": "@av:areothic I could want many things, Princess. I could want to teach you a lesson about obedience."
}
},
{
"file": "",
"text": {
"1": "@av:areothic I could want to see if you scream or cry when gripped by hands that aren’t your own.",
"2": "@av:areothic Or I could simply want to watch you squirm, wondering which it will be.",
"3": "@av:areothic Now stand still. Let’s see what all the whispering on the camp is about.",
"4": "My arms tighten harder. I feel the flush crawl up my throat—shame, fear, and something hotter I refuse to name.",
"5": "@av:areothic Covering yourself... Pfft, you walk through a camp of thousands of soldiers dressed in skimpy silk, and now you’re shy?",
"6": "@av:areothic I let my gaze travel over you, deliberate and slow, taking in every curve, every tremor. I don’t reach for you, not yet. The anticipation is its own kind of lesson."
}
},
{
"file": "",
"text": {
"1": "@av:areothic Your father thinks you’re a delicate treasure to be locked away. Your brother thinks you’re a distraction to be managed.",
"2": "@av:areothic But out here, with no one to hear you… you’re just a girl who made a very poor choice.",
"3": "@av:areothic Uncover.",
"4": "The single word lands like a lash. My breath catches. My fingers twitch against my skin—but I don’t move.",
"5": "His head tilts, patient in the most terrifying way. Waiting. The silence stretches until it hurts.",
"6": "I feel the pull of his presence, that dark gravity that makes every man in camp falter when I pass. Only now it’s turned against me, and I have nothing left to shield myself with."
}
}
],
"areothic_river_confrontation_comply": [
{
"file": "",
"text": {
"1": "The word hangs between us like a drawn bowstring. My lungs burn. My arms feel leaden.",
"2": "Slowly, agonizingly, my hands fall away. Fingers uncurl from where they clutched my breasts and belly, dropping limp to my sides. Knuckles bleach white as I make useless little fists.",
"3": "I keep my head bowed. Wet hair clings to my neck and shoulders like dark ropes. Moonlight finds every droplet sliding down my skin, tracing paths over collarbone, stomach, hips.",
"4": "@av:areothic Good.",
"5": "@av:areothic His voice is a low, approving rumble that vibrates through the water and into my bones. Now you’re beginning to understand.",
"6": "@av:areothic The pretense is stripped away, just like your clothes. This is what you are without your title, your guards, your silks. Just flesh. Trembling, tempting flesh."
}
},
{
"file": "",
"text": {
"1": "@av:areothic Tell me, Princess. When your father looks at you, what does he see?",
"2": "My throat closes. Words fracture before they reach my tongue.",
"3": "@av:player I… Uh… A daughter?",
"4": "The attempt at an answer sounds small and childish even to me. Fear drowns everything else, there is no room left for cleverness or defiance.",
"5": "@av:areothic *A low, humorless sound escapes my lips as I watch you struggle to form a coherent thought.*",
"6": "@av:areothic A daughter. *I repeat the word slowly.* He sees a symbol. A legacy. Something to be protected and married off for political advantage."
}
},
{
"file": "",
"text": {
"1": "@av:areothic He doesn’t see the creature standing before me now.",
"2": "@av:areothic He doesn’t see the way your skin flushes with fear, the way your breath hitches when a man looks at you for too long.",
"3": "@av:areothic He’s blind to the tool you could be.",
"4": "He lifts one massive hand. I flinch so hard that some of the water droplets on my skin fall through my core. A full-body shudder I can’t stop.",
"5": "But he do not strike. The backs of his knuckles graze my cheek, brushing a soaked strand of hair aside with deliberate slowness. The touch is barely there, and still it burns.",
"6": "@av:areothic He certainly doesn’t see the whore. But I do. I’ve always seen it."
}
},
{
"file": "",
"text": {
"1": "The word lands like a slap... Whore. My mind blanks. Heat floods my face, my chest, places I wish it wouldn’t.",
"2": "@av:areothic Your face, your form, that sweet scent you can’t control... That body made for pleasure, not for politics. You’re a resource, Princess. One your father is too sentimental to utilize.",
"3": "I open my mouth. Nothing comes out. Only a soft, helpless sound.",
"4": "My eyes stay locked on the mossy ground between us. I feel smaller than I’ve ever felt. More exposed. More seen.",
"5": "And still he doesn’t move closer. He doesn’t have to. The weight of his gaze is already inside every inch of my skin. The lake is cold. But I am burning cold.",
"6": "@av:areothic Now, lay on your back."
}
}
],
"areothic_river_confrontation_defy": [
{
"file": "",
"text": {
"1": "Uncover.",
"2": "The command is quiet. Final. It sinks into me like a hook.",
"3": "My arms stay locked tight across my chest and pelvis. Fingers dig into my skin hard enough to bruise. I shake my head once, small, stubborn.",
"4": "No sound escapes me. Just the shallow rasp of my breathing and the soft lap of water against my thighs.",
"5": "@av:areothic *Silence stretches. His head tilts, studying me the way a hunter studies something that hasn’t yet run.*",
"6": "He shifts his body a little and..."
}
}
],
"areothic_river_confrontation_defy2": [
{
"file": "",
"text": {
"1": "@av:areothic Your father doesn’t see the creature standing before me now. He’s blind to the tool you could be.",
"2": "@av:areothic He doesn’t see the way your skin flushes with fear, the way your breath hitches when a man looks at you for too long.",
"3": "@av:areothic He certainly doesn’t see the whore. But I do. I’ve always seen it.",
"4": "The word lands like a slap... Whore. My mind blanks. Heat floods my face, my chest, places I wish it wouldn’t.",
"5": "@av:areothic Your face, your form, that sweet scent you can’t control... That body made for pleasure, not for politics. You’re a resource, Princess. One your father is too sentimental to utilize",
"6": "I open my mouth. Nothing comes out. Only a soft, helpless sound."
}
},
],
"areothic_river_confrontation_him_undressing1": [
{
"file": "",
"text": {
"1": "The moss is cool and damp against my back. I lie naked on the soft, uneven ground, legs half-curled.",
"2": "Areothic stands over me, a dark silhouette against the moonlit trees. His eyes never leave my body. They trace every inch like ownership already claimed.",
"3": "My chest rises and falls too fast. Every breath feels stolen. The night air kisses skin that should never be this exposed.",
"4": "@av:areothic Look at you. Spread out like an offering no one taught you how to refuse.",
"5": "He reaches for the buckle of his belt. The metallic clink slices through the quiet. Deliberate. Loud.",
"6": "Panic floods me, sharp, blinding. This is a dream. It has to be a dream."
}
}
],
"areothic_river_confrontation_him_undressing2": [
{
"file": "",
"text": {
"1": "I squeeze my eyes shut as hard as I can, willing the world away. When I open them again he’ll be gone and I’ll still be safe in my tent.",
"2": "But the sounds keep coming anyway. Leather slides through loops—slow, heavy. Metal clinks again as the belt drops to the grass.",
"3": "Fabric rustles. His tunic hits the ground somewhere nearby. Boots thud once, twice.",
"4": "Every noise is a hammer strike inside my skull. I keep my eyes screwed shut, hands fisted at my sides, nails biting into palms. If I don’t look, maybe it stops being real.",
"5": "But the air shifts. Warmer. Closer. His scent, iron, smoke, sweat, and something darker—rolls over me like a tide.",
"6": "I feel the heat of him before I feel his hands. Rough callused palms clamp around the backs of my calves, sudden, iron-hard. Fingers dig in, bruising as he yanks my legs upward and apart."
}
}
],
"areothic_river_confrontation_violation1": [
{
"file": "",
"text": {
"1": "My eyes snap open on instinct. Wide. Wild.",
"2": "He’s there, above me, bare now, massive and scarred and terrifyingly real.",
"3": " Moonlight gleams along the hard planes of his chest, the thick cords of muscle, the unmistakable evidence of his intent.",
"4": "He forces my calves high, spreading them into a trembling V. My hips lift clean off the mossy ground, only my shoulders and upper back remain pressed to the earth. The position leaves me utterly open, arched, helpless beneath him.",
"5": "I scream, raw, broken, tearing out of my throat as he drives into me in one brutal thrust.",
"6": "Pain flares white-hot. My back arches off the moss. Nails rake uselessly at the grass. The world narrows to the stretch, the burn, the impossible fullness."
}
}
],
"areothic_river_confrontation_violation2": [
{
"file": "",
"text": {
"1": "A low growl rumbles from his chest, not pleasure, not yet. Conquest.",
"2": "@av:areothic There it is. That sound I wanted to hear.",
"3": "He keeps my calves locked in his grip, holding my legs high and wide. Each thrust rocks my entire body upward, hips suspended, waist arched, only the pressure of his hands and the brutal rhythm keeping me from collapsing.",
"4": "Tears blur the edges of my vision. My screams fracture into broken sobs, then into ragged, involuntary gasps as my traitorous body slicks around him.",
"5": "Fear-sweat and shameful wetness mixing on my thighs.",
"6": "@av:areothic Open them wider, Princess. See who owns you now."
}
}
],
"areothic_river_confrontation_struggle": [
{
"file": "",
"text": {
"1": "Instinct takes over. My body jerks, twists, tries to curl in on itself. Legs kick against his iron grip—calves straining, toes pointing, heels digging uselessly into empty air.",
"2": "I thrash sideways, shoulders scraping moss, hips bucking in a frantic attempt to slide off him, to close the impossible distance he’s forced between us.",
"3": "My small hands claw at the mossy ground, nails scraping over damp earth and roots, barely leaving shallow furrows—anything to find purchase, anything to push away.",
"4": "He doesn’t even flinch. Each of his massive palm clamped tight around each thin calf, fingers digging in hard enough to leave red imprints.",
"5": "He holds my legs high and spread in that humiliating V, pinning them apart and upward so my hips lift clean off the ground, waist arched and suspended as if my entire weight means nothing.",
"6": "I stand barely 4 feet 10 inches tall and weigh just 88 pounds. He towers at 6 feet 3 inches and carries 308 pounds of solid, battle-forged muscle. My struggles register to him the way a bird’s wings might flutter against a closing fist, noticeable, but irrelevant."
}
},
{
"file": "",
"text": {
"1": "A low, amused rumble vibrates through his chest while I scream and sob. Not anger. Not effort. Just quiet satisfaction.",
"2": "@av:areothic Keep fighting, little princess. It makes the scent of you even sweeter.",
"3": "He shifts his grip slightly, barely a flex, and my hips lift another inch off the ground. My back arches painfully, as only my shoulders and upper back touch the earth. Every thrust drives deeper, the angle forcing me to take him fully whether I want to or not.",
"4": "My arms flail, slap at his chest, push at his abdomen—useless. My fingers slide off sweat-slick skin like water on stone. He doesn’t slow. Doesn’t tighten in punishment. He simply… continues. Holding me exactly where he wants me. As if my resistance is background noise.",
"5": "Tears stream sideways into my hair. My screams have turned hoarse, fractured. Each breath is punched out of me by his rhythm.",
"6": "@av:areothic You’re not going anywhere. Not until I’ve had my fill."
}
}
],
"areothic_river_confrontation_climax": [
{
"file": "",
"text": {
"1": "His thrusts suddenly quicken, harder, faster, deeper. Each slam rocks my lifted hips, calves still locked in his grip, legs spread high in a trembling V.",
"2": "Wet sounds fill the air. My body jolts with every impact—shoulders scraping moss, breath punched out in sharp cries.",
"3": "His growls grow rougher. Sweat drips onto my skin. My weak struggles fade to shudders; muscles clench around him against my will.",
"4": "The pace turns frantic. He drives in as far as possible, hips grinding flush."
}
}
],
"areothic_river_confrontation_climax2": [
{
"file": "cgs/sex/xray.png",
"text": {
"1": "A harsh groan rips from his throat.",
"2": "Fingers bruise my calves as he tenses. Couple of final, brutal thrusts buries him to the hilt.",
"3": "He pulses, hot, thick spurts flooding deep inside me, forcing every drop as far as he can reach.",
"4": "I feel the heat spread, the overwhelming fullness. My body flutters helplessly around him."
}
}
],
"areothic_river_confrontation_climax3": [
{
"file": "cgs/sex/xray.png",
"text": {
"1": "@av:areothic That’s where it belongs, Princess.",
"2": "He lingers buried inside, letting it settle.",
"3": "He watches—sated, possessive.",
"4": "@av:areothic We’re far from done, little one.",
"5": "My eyes widen in fresh panic. A broken whimper escapes as he picks up speed once more, calves still locked in his grip, keeping me lifted and open."
}
}
],
/*======================================================================================================================*/
/*======================================================================================================================*/
/* |Thalen Before Departure| */
/*======================================================================================================================*/
/*======================================================================================================================*/
"scene_thalenwyr_talk": [
{
"file": "",
"text": {
"1": "The flap of my tent stirs, and Thalenwyr slips inside with parchment tucked beneath one arm, bringing a pocket of calm in with him.",
"2": "His eyes find me at once, softening in that quiet way only he manages.",
"3": "@av:thalenwyr There you are.",
"4": "@av:thalenwyr I was beginning to suspect the camp had misplaced you between the ledgers and supply rolls.",
"5": "@av:player If so, I hope they filed me somewhere elegant.",
"6": "@av:thalenwyr Mm. Fragile, expensive, and likely to ruin a quartermaster’s evening."
}
},
{
"file": "",
"text": {
"1": "A laugh slips out of me before I can stop it, small but real.",
"2": "@av:player That is an outrageous description.",
"3": "@av:thalenwyr Then I’ll amend it.",
"4": "@av:thalenwyr Fragile, expensive, and capable of arguing with perfect confidence while being entirely wrong.",
"5": "@av:player Better. At least that sounds like family.",
"6": "For a moment, the war outside my tent feels far enough away to breathe."
}
},
{
"file": "",
"text": {
"1": "@av:thalenwyr You look worn thin, Aela.",
"2": "@av:player I feel worn thin.",
"3": "@av:player Everything lately feels sharper than it used to. Every glance. Every order. Every silence.",
"4": "@av:thalenwyr That is what happens when peace tears.",
"5": "@av:thalenwyr You stop hearing only words. You start hearing the weight beneath them.",
"6": "He says it gently, but it lands with the dull truth of something I already knew."
}
},
{
"file": "",
"text": {
"1": "@av:player You make everything sound easier than it is.",
"2": "@av:thalenwyr No. I only try to make it sound survivable.",
"3": "@av:player That may be worse.",
"4": "@av:thalenwyr It usually is.",
"5": "I smile despite myself, and he smiles back like it was worth entering the tent just to win that much from me.",
"6": "With Thalenwyr, even silence feels friendly."
}
},
{
"file": "",
"text": {
"1": "@av:player You know, you really are useful.",
"2": "@av:player Father trusts your records. You keep camps, orders, and people from unraveling.",
"3": "@av:player Cael has command. Vael has his bow. You have your feathers and ink.",
"4": "@av:player And me... I don’t have anything like that.",
"5": "@av:player Nothing sharp. Nothing impressive. Nothing that matters in the way all of you do.",
"6": "The confession leaves me quieter than I intended."
}
},
{
"file": "",
"text": {
"1": "@av:thalenwyr Aela.",
"2": "@av:thalenwyr Do not measure your worth only by the ways men make themselves useful in war.",
"3": "@av:thalenwyr Cael commands because he must. Vael shoots because he must. I write because someone must remember what all this costs.",
"4": "@av:thalenwyr None of that makes you lesser.",
"5": "@av:thalenwyr It only means your gifts were never forged for battlefields.",
"6": "His voice is warm, steady, and impossible to mistake for pity."
}
},
{
"file": "",
"text": {
"1": "@av:player That sounds kind, but suspiciously convenient.",
"2": "@av:thalenwyr I am a scribe. Making difficult truths bearable is half my profession.",
"3": "@av:player And the other half?",
"4": "@av:thalenwyr Protecting my sister from foolish conclusions whenever possible.",
"5": "I lower my eyes, smiling into my lap this time.",
"6": "@av:player Then you are tragically overworked."
}
},
{
"file": "",
"text": {
"1": "@av:thalenwyr On the contrary. I find the position deeply meaningful.",
"2": "@av:player You would.",
"3": "@av:thalenwyr I would.",
"4": "@av:thalenwyr And for the record, I think you are more useful than you allow yourself to believe.",
"5": "@av:player Useful how?",
"6": "@av:thalenwyr You remind us there is still a world beyond strategy, steel, and reports. That matters more than you think."
}
},
{
"file": "",
"text": {
"1": "I do not answer right away.",
"2": "It is easier to deflect kindness than accept it, especially when it arrives so gently.",
"3": "@av:player You always know how to say things so they hurt less.",
"4": "@av:thalenwyr That is because I practice on myself first.",
"5": "I laugh softly again, and this time the ache in my chest eases with it.",
"6": "For a little while, I almost forgot yesterday."
}
},
{
"file": "",
"text": {
"1": "Thalenwyr glances down at the parchment beneath his arm, and duty returns to his face in a quiet, apologetic way.",
"2": "@av:thalenwyr I wish I could stay.",
"3": "@av:thalenwyr Father wants a full account of the western camp before the night deepens any further.",
"4": "@av:player Another ride, then?",
"5": "@av:thalenwyr Mm. Stores, morale, officer notes, boundary counts, the thrilling life of a royal scribe.",
"6": "@av:player Be honest. You adore it."
}
},
{
"file": "",
"text": {
"1": "@av:thalenwyr I adore that ink outlives most swords.",
"2": "@av:thalenwyr Someone must put truth in lines straight enough to survive men like our brothers.",
"3": "@av:player Then go, before history is forced to wait on you.",
"4": "@av:thalenwyr There is the princess I know, merciless to scholarship.",
"5": "He shifts the papers neatly beneath his arm and turns toward the flap.",
"6": "The tent already feels dimmer for it."
}
},
{
"file": "",
"text": {
"1": "He pauses before leaving and looks back at me, all warmth again, as if he hates ending the moment as much as I do.",
"2": "@av:thalenwyr I’ll return when I can. And before I forget—the camp cook left you a plate on your bed. You should eat, Aela.",
"3": "@av:thalenwyr Even princesses with dramatic dispositions are less convincing when they’ve skipped supper.",
"4": "@av:player I will. Safe ride, Thale.",
"5": "@av:thalenwyr Safe waiting, Aela. And do eat before it goes cold.",
"6": "Then he slips out into the night, bound for the other camp with ink, parchment, and duty at his side."
}
}
],
/*======================================================================================================================*/
/*======================================================================================================================*/
/* |Kaeltharion Commander 22nd Battalion Story| */
/*======================================================================================================================*/
/*======================================================================================================================*/
"kaeltharion_morning_tent_confrontation": [
{
"file": "",
"text": {
"1": "Kaeltharion, commander of the 22nd battalion, stands casually at the outside of my tent.",
"2": "Tall, lean, armored.",
"3": "His smile is thin, polite on the surface.",
"4": "But the eyes are wrong. Hungry. Calculating.",
"5": "I freeze. My silk robe feels suddenly too thin.",
"6": "Too revealing. I pull it tighter across my chest."
}
},
{
"file": "",
"text": {
"1": "@av:kaeltharion Good morning, Princess Aelara.",
"2": "@av:kaeltharion You look… rested.",
"3": "The words drip with mockery.",
"4": "He steps closer, slow, unhurried.",
"5": "The camp around us is waking, but no one pays attention.",
"6": "Soldiers pass by, their eyes lingering a little too long before they force themselves onward."
}
},
{
"file": "",
"text": {
"1": "My throat closes. I glance toward the command tents.",
"2": "Father’s banner is gone. My brothers’ too.",
"3": "They left yesterday at nightfall for the forward ridge.",
"4": "I’m alone here.",
"5": "@av:kaeltharion Your father and your brothers will be occupied for days...",
"6": "@av:kaeltharion Perhaps months..."
}
},
{
"file": "",
"text": {
"1": "He checks me slowly, his gaze traveling from head to toe.",
"2": "Heart hammering. His voice drops lower, intimate.",
"3": "@av:kaeltharion The orcs are pressing hard at the crossing.",
"4": "@av:kaeltharion They won’t come back until the line is secure… Or until it’s too late.",
"5": "@av:kaeltharion But the camp remains. Hundreds of men.",
"6": "@av:kaeltharion Tired. Frustrated. Hungry for something softer."
}
},
{
"file": "",
"text": {
"1": "@av:kaeltharion And you, little princess… carry such a sweet, distracting scent.",
"2": "@av:kaeltharion It’s been driving them mad for weeks.",
"3": "He stills, his gaze lifting from my body back to my eyes.",
"4": "@av:kaeltharion We’ve decided to make use of you properly.",
"5": "@av:kaeltharion No more teasing glimpses through silk.",
"6": "@av:kaeltharion No more guarded tents."
}
},
{
"file": "",
"text": {
"1": "@av:kaeltharion You will be working…",
"2": "@av:kaeltharion Every soldier in the 22nd battalion will have his turn.",
"3": "@av:kaeltharion And then the others. Endless. Rotating.",
"4": "@av:kaeltharion Until there’s nothing left of the delicate royal flower",
"5": "@av:kaeltharion but a used, dripping ruin.",
"6": "My knees threaten to buckle."
}
},
{
"file": "",
"text": {
"1": "I reach behind me for the tent pole, anything to stay upright.",
"2": "His smile widens.",
"3": "@av:kaeltharion And when your father finally returns?",
"4": "@av:kaeltharion When the king rides back to his precious daughter?",
"5": "@av:kaeltharion He’ll find her broken. Defiled. Useless.",
"6": "@av:kaeltharion He’ll rage. He’ll accuse. He’ll demand heads."
}
},
{
"file": "",
"text": {
"1": "@av:kaeltharion That’s when we strike.",
"2": "@av:kaeltharion The king dies, quietly, tragically.",
"3": "@av:kaeltharion The brothers fall in the confusion.",
"4": "@av:kaeltharion And I… I will be the one left standing.",
"5": "@av:kaeltharion The new power behind whatever throne remains."
}
}
],
"kaeltharion_morning_tent_confrontation2": [
{
"file": "",
"text": {
"1": "I flinch, but there’s nowhere to go.",
"2": "@av:kaeltharion You’ll help me, Aelara.",
"3": "@av:kaeltharion Not because you want to.",
"4": "@av:kaeltharion Because you’ll have no choice.",
"5": "@av:kaeltharion By the time they return, you’ll be too ruined to speak against me.",
"6": "@av:kaeltharion Too filled. Too marked."
}
},
{
"file": "",
"text": {
"1": "@av:kaeltharion Too… grateful for any kindness at all.",
"2": "Smile never fading.",
"3": "@av:kaeltharion Enjoy your morning, Princess.",
"4": "@av:kaeltharion Rest while you can.",
"5": "@av:kaeltharion Your real routine begins soon.",
"6": "@av:kaeltharion Now, back to your tent. We don't want a runaway princess."
}
}
]
};
<</script>>
<<script>>
/* ============================================================
Fame glow CSS (inject once)
============================================================ */
window.ensureFameGlowCSS = function () {
if (document.getElementById("fame-glow-css")) return;
const style = document.createElement("style");
style.id = "fame-glow-css";
style.textContent = `
/* Lust / Scandal (subtle medieval ember-red pulse) */
.fame-lust-glow {
color: #c86a6a;
text-shadow: 0 0 4px rgba(200, 90, 90, 0.25);
animation: fameLustPulse 1.8s ease-in-out infinite;
}
@keyframes fameLustPulse {
0%, 100% {
text-shadow:
0 0 3px rgba(200, 90, 90, 0.18),
0 0 7px rgba(170, 40, 40, 0.10);
filter: brightness(1);
}
50% {
text-shadow:
0 0 6px rgba(220, 90, 90, 0.35),
0 0 12px rgba(170, 40, 40, 0.18);
filter: brightness(1.08);
}
}
/* Clickable row styling */
.fame-row {
cursor: pointer;
padding: 4px 6px;
border-radius: 6px;
user-select: none;
}
.fame-row:hover { background: rgba(240,224,192,0.06); }
/* Expand panel under each row */
.fame-details {
overflow: hidden;
max-height: 0;
opacity: 0;
transition: max-height 0.25s ease, opacity 0.2s ease;
margin: 0 6px 6px 6px;
padding: 0 10px;
border-left: 2px solid rgba(240,224,192,0.18);
color: rgba(240,224,192,0.92);
font-size: 0.95em;
line-height: 1.25em;
}
.fame-details.open {
max-height: 420px; /* bigger so hint + log aren't clipped */
opacity: 1;
padding-top: 6px;
padding-bottom: 6px;
}
.fame-details .hint {
opacity: 0.85;
font-style: italic;
margin-bottom: 6px;
}
/* ✅ Scrollable log area (add bottom padding so last line is readable) */
.fame-log-wrap {
max-height: 170px;
overflow-y: auto;
padding-right: 6px;
border-top: 1px solid rgba(240,224,192,0.08);
border-bottom: 1px solid rgba(240,224,192,0.08);
padding-top: 6px;
padding-bottom: 14px; /* ✅ was 6px */
scrollbar-width: thin;
scrollbar-color: rgba(240,224,192,0.25) rgba(0,0,0,0.15);
}
/* WebKit scrollbar styling (Chrome/Edge) */
.fame-log-wrap::-webkit-scrollbar { width: 8px; }
.fame-log-wrap::-webkit-scrollbar-track { background: rgba(0,0,0,0.15); border-radius: 10px; }
.fame-log-wrap::-webkit-scrollbar-thumb { background: rgba(240,224,192,0.22); border-radius: 10px; }
.fame-log-wrap::-webkit-scrollbar-thumb:hover { background: rgba(240,224,192,0.30); }
.fame-log { margin: 0; padding-left: 16px; }
.fame-log li { margin: 4px 0; }
.fame-empty {
opacity: 0.75;
font-style: italic;
margin: 6px 0 0 0;
}
`;
document.head.appendChild(style);
};
/* ============================================================
Fame -> color/class resolver (for the main row "value" text)
============================================================ */
window.getFameColor = function (fameTitle) {
if (!fameTitle) return "#f0e0c0";
const fame = String(fameTitle).toLowerCase().trim();
// 🔥 Lust / Scandal (pulsing ember-red)
if (
fame === "whore" || fame === "whore princess" || fame === "princess whore" ||
fame === "prostitute" || fame === "prostitute princess" || fame === "princess prostitute"
) return { className: "fame-lust-glow" };
// 🌸 Royal / Noble
if (fame === "elven princess") return "#e3b6d5";
if (fame === "queen") return "#d6b56e";
if (fame === "princess") return "#cfa8ff";
if (fame === "princess of elliahal") return "#cfa8ff";
// 🌿 Respected / Honored
if (fame === "ally") return "#a7c7a1";
if (fame === "respected") return "#b9c8a3";
// ⚔️ Feared / Hostile
if (fame === "feared") return "#c88b7a";
if (fame === "enemy") return "#b36a5e";
if (fame === "outcast") return "#9a9a9a";
// 👁 Unknown / Neutral
if (fame === "unknown") return "#9a9a9a";
return "#f0e0c0";
};
/* ============================================================
Programmatic fame notes/log system
============================================================ */
window.FameLog = {
_ensureStore() {
const v = State.variables;
if (!v._fameLog) v._fameLog = {};
if (!v._fameLogMax) v._fameLogMax = 18;
},
setMax(n) {
this._ensureStore();
State.variables._fameLogMax = Math.max(1, Number(n) || 18);
},
add(key, msg, styleOrColor) {
if (!key) return;
this._ensureStore();
const v = State.variables;
const k = String(key);
const entry = { t: Date.now(), msg: String(msg ?? "").trim() };
if (!entry.msg) return;
if (typeof styleOrColor === "string" && styleOrColor.trim()) {
entry.color = styleOrColor.trim();
} else if (styleOrColor && typeof styleOrColor === "object") {
if (typeof styleOrColor.color === "string" && styleOrColor.color.trim()) entry.color = styleOrColor.color.trim();
if (typeof styleOrColor.className === "string" && styleOrColor.className.trim()) entry.className = styleOrColor.className.trim();
}
v._fameLog[k] = v._fameLog[k] || [];
v._fameLog[k].push(entry);
const max = v._fameLogMax || 18;
if (v._fameLog[k].length > max) v._fameLog[k] = v._fameLog[k].slice(-max);
this.refresh(k);
},
clear(key) {
this._ensureStore();
const v = State.variables;
const k = String(key);
v._fameLog[k] = [];
this.refresh(k);
},
get(key) {
this._ensureStore();
const v = State.variables;
return (v._fameLog[String(key)] || []).slice();
},
refresh(key) {
const k = String(key);
const container = document.querySelector(
`#fame-panel .fame-details[data-famekey="${CSS.escape(k)}"] .fame-log-wrap`
);
if (!container) return;
container.innerHTML = "";
const items = this.get(k);
if (!items.length) {
const empty = document.createElement("div");
empty.className = "fame-empty";
empty.textContent = "No tales recorded yet.";
container.appendChild(empty);
return;
}
const ul = document.createElement("ul");
ul.className = "fame-log";
items.forEach(it => {
const li = document.createElement("li");
li.textContent = it.msg;
if (it.color) li.style.color = it.color;
if (it.className) li.classList.add(it.className);
ul.appendChild(li);
});
container.appendChild(ul);
}
};
/* ============================================================
✅ NEW: Seed-once helper (prevents repeated fame adds)
============================================================ */
window.FameLogSeedOnce = function (seedId, fn) {
const v = State.variables;
if (!v._fameSeedOnce) v._fameSeedOnce = {};
if (v._fameSeedOnce[seedId]) return; // already done
v._fameSeedOnce[seedId] = true;
fn();
};
/* ============================================================
Fame panel with expandable rows + scrollable details
============================================================ */
window.createFamePanel = function () {
if (document.getElementById("fame-panel")) return;
window.ensureFameGlowCSS();
FameLog._ensureStore();
const v = State.variables;
const panel = document.createElement("div");
panel.id = "fame-panel";
Object.assign(panel.style, {
position: "fixed",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
minWidth: "380px",
maxWidth: "520px",
/* ✅ same idea as relationship: keep on screen */
maxHeight: "86vh",
overflow: "hidden",
display: "flex",
flexDirection: "column",
padding: "22px 26px",
zIndex: "10000",
background: `
linear-gradient(
to bottom,
rgba(74, 47, 27, 0.85),
rgba(47, 28, 17, 0.85)
)
`,
borderLeft: "6px solid rgba(42, 22, 11, 0.9)",
borderRadius: "12px 0 0 12px",
boxShadow: `
inset 0 0 30px rgba(0,0,0,0.55),
-8px 0 18px rgba(0,0,0,0.6)
`,
color: "#f0e0c0",
fontFamily: `"Cinzel", "Uncial Antiqua", "Palatino Linotype", "Book Antiqua", serif`
});
// Title
const title = document.createElement("div");
title.textContent = `✦ ${(v.playername || "Unknown")} Bloomspell's Fame ✦`;
Object.assign(title.style, {
fontSize: "1.4em",
textAlign: "center",
marginBottom: "16px",
letterSpacing: "1px",
borderBottom: "1px solid rgba(240,224,192,0.25)",
paddingBottom: "6px"
});
panel.appendChild(title);
// ✅ scrolling area for all rows/details
const rowsWrap = document.createElement("div");
rowsWrap.style.flex = "1";
rowsWrap.style.minHeight = "0";
rowsWrap.style.overflowY = "auto";
rowsWrap.style.paddingRight = "6px";
panel.appendChild(rowsWrap);
function addRow(key, label, value) {
const row = document.createElement("div");
row.className = "fame-row";
row.setAttribute("data-famekey", key);
Object.assign(row.style, {
display: "flex",
justifyContent: "space-between",
marginBottom: "4px",
fontSize: "1.05em"
});
const left = document.createElement("span");
left.textContent = label;
const right = document.createElement("span");
right.textContent = value ?? "Unknown";
right.style.fontWeight = "bold";
const fameStyle = window.getFameColor(value);
if (typeof fameStyle === "object" && fameStyle !== null) {
if (fameStyle.className) right.classList.add(fameStyle.className);
else Object.assign(right.style, fameStyle);
} else {
right.style.color = fameStyle;
}
row.appendChild(left);
row.appendChild(right);
const details = document.createElement("div");
details.className = "fame-details";
details.setAttribute("data-famekey", key);
const hint = document.createElement("div");
hint.className = "hint";
hint.textContent = "Recorded tales and whispers:";
details.appendChild(hint);
const wrap = document.createElement("div");
wrap.className = "fame-log-wrap";
details.appendChild(wrap);
setTimeout(() => FameLog.refresh(key), 0);
row.addEventListener("click", () => {
const isOpen = details.classList.contains("open");
panel.querySelectorAll(".fame-details.open").forEach(d => d.classList.remove("open"));
if (!isOpen) {
details.classList.add("open");
FameLog.refresh(key);
setTimeout(() => { wrap.scrollTop = wrap.scrollHeight; }, 0);
}
});
rowsWrap.appendChild(row);
rowsWrap.appendChild(details);
}
addRow("knownAs", "Known As", v.playerKnownAs || "Unknown Wanderer");
const hr = document.createElement("div");
Object.assign(hr.style, {
height: "1px",
background: "rgba(240,224,192,0.18)",
margin: "10px 0 10px 0"
});
rowsWrap.appendChild(hr);
addRow("elliahal", "Elliahal Kingdom", v.playerFameElliahalKingdom);
addRow("elves", "Elven Realms", v.playerFameElves);
addRow("humans", "Human Kingdoms", v.playerFameHumans);
addRow("dwarves", "Dwarven Holds", v.playerFameDwarves);
addRow("orcs", "Orc Clans", v.playerFameOrcs);
addRow("goblins", "Goblin Tribes", v.playerFameGoblins);
addRow("ogres", "Ogre Lands", v.playerFameOgres);
addRow("trolls", "Troll Territories", v.playerFameTrolls);
const closeBtn = document.createElement("button");
closeBtn.textContent = "Seal";
Object.assign(closeBtn.style, {
marginTop: "16px",
width: "100%",
padding: "8px",
background: "rgba(42, 22, 11, 0.9)",
color: "#f0e0c0",
border: "1px solid rgba(240,224,192,0.3)",
borderRadius: "6px",
cursor: "pointer",
fontFamily: "inherit"
});
closeBtn.onclick = () => panel.remove();
panel.appendChild(closeBtn);
document.body.appendChild(panel);
};
<</script>>
/* ✅ Seed logs only once (prevents stacking duplicates) */
<<run FameLogSeedOnce("FamePassageLogs_v1", function () {
FameLog.add("knownAs", "Some rumors about Bloomspell lineage having unique abilities.");
FameLog.add("knownAs", "You are known to have a sweet enticing scent for those who walk by you or lingers in your presence.", "lightgray");
FameLog.add("elliahal", "The youngest sibling of the King of Elliahal, born of the legendary Bloomspell lineage.");
FameLog.add("elves", "The youngest sibling of the King of Elliahal, born of the legendary Bloomspell lineage.");
FameLog.add("humans", "Human slavers and thieves would love to capture you.", "salmon");
FameLog.add("goblins", "Savage goblin tribes would love to capture you.", "salmon");
FameLog.add("orcs", "Hostile orc clans would love to capture you.", "salmon");
})>>
<<run createFamePanel()>>
<<script>>
/* ============================================================
Shared medieval panel CSS (inject once)
(keeps your visuals/fonts/colors, adds abilities-only bits)
============================================================ */
window.ensureMedievalPanelCSS = function () {
if (document.getElementById("medieval-panel-css")) return;
const style = document.createElement("style");
style.id = "medieval-panel-css";
style.textContent = `
/* Lust / Scandal (subtle medieval ember-red pulse) */
.fame-lust-glow {
color: #c86a6a;
text-shadow: 0 0 4px rgba(200, 90, 90, 0.25);
animation: fameLustPulse 1.8s ease-in-out infinite;
}
@keyframes fameLustPulse {
0%, 100% {
text-shadow:
0 0 3px rgba(200, 90, 90, 0.18),
0 0 7px rgba(170, 40, 40, 0.10);
filter: brightness(1);
}
50% {
text-shadow:
0 0 6px rgba(220, 90, 90, 0.35),
0 0 12px rgba(170, 40, 40, 0.18);
filter: brightness(1.08);
}
}
/* Clickable row styling (reused) */
.med-row {
cursor: pointer;
padding: 4px 6px;
border-radius: 6px;
user-select: none;
}
.med-row:hover { background: rgba(240,224,192,0.06); }
/* Expand section */
.med-details {
overflow: hidden;
max-height: 0;
opacity: 0;
transition: max-height 0.25s ease, opacity 0.2s ease;
margin: 0 6px 6px 6px;
padding: 0 10px;
border-left: 2px solid rgba(240,224,192,0.18);
color: rgba(240,224,192,0.92);
font-size: 0.95em;
line-height: 1.25em;
}
/* CHANGED: make the expanded area taller */
.med-details.open {
max-height: 520px; /* was 260px */
opacity: 1;
padding-top: 6px;
padding-bottom: 6px;
}
.med-details .hint {
opacity: 0.85;
font-style: italic;
margin-bottom: 6px;
}
/* Scrollable area ("slider") */
.med-scroll {
max-height: 170px;
overflow-y: auto;
padding-right: 6px;
border-top: 1px solid rgba(240,224,192,0.08);
border-bottom: 1px solid rgba(240,224,192,0.08);
padding-top: 6px;
padding-bottom: 6px;
scrollbar-width: thin;
scrollbar-color: rgba(240,224,192,0.25) rgba(0,0,0,0.15);
overscroll-behavior: contain;
}
.med-scroll::-webkit-scrollbar { width: 8px; }
.med-scroll::-webkit-scrollbar-track { background: rgba(0,0,0,0.15); border-radius: 10px; }
.med-scroll::-webkit-scrollbar-thumb { background: rgba(240,224,192,0.22); border-radius: 10px; }
.med-scroll::-webkit-scrollbar-thumb:hover { background: rgba(240,224,192,0.30); }
/* Abilities-specific layout */
.ability-meta {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 6px 14px;
margin-bottom: 8px;
opacity: 0.95;
}
.ability-meta .k { opacity: 0.75; }
.ability-meta .v { font-weight: 700; }
.ability-desc {
margin: 0;
white-space: pre-wrap;
}
.med-empty {
opacity: 0.75;
font-style: italic;
margin: 6px 0 0 0;
}
/* NEW: whole-details scroller ("slider") so long notes never get cut off */
.med-details-scroll {
max-height: 420px; /* the visible height of the expanded dropdown */
overflow-y: auto; /* slider appears here */
padding-right: 6px;
scrollbar-width: thin;
scrollbar-color: rgba(240,224,192,0.25) rgba(0,0,0,0.15);
overscroll-behavior: contain;
}
.med-details-scroll::-webkit-scrollbar { width: 8px; }
.med-details-scroll::-webkit-scrollbar-track { background: rgba(0,0,0,0.15); border-radius: 10px; }
.med-details-scroll::-webkit-scrollbar-thumb { background: rgba(240,224,192,0.22); border-radius: 10px; }
.med-details-scroll::-webkit-scrollbar-thumb:hover { background: rgba(240,224,192,0.30); }
`;
document.head.appendChild(style);
};
/* ============================================================
Ability system (programmatic, no player typing)
- Define abilities in State.variables._abilities
- Each ability: { key, name, rank, cost, cooldown, tags, desc, notes[] }
============================================================ */
window.Abilities = {
_ensureStore() {
const v = State.variables;
if (!v._abilities) v._abilities = {}; // dictionary by key
},
// Create/update ability definition
set(key, data) {
if (!key) return;
this._ensureStore();
const v = State.variables;
v._abilities[String(key)] = Object.assign(
{
key: String(key),
name: String(key),
rank: "—",
cost: "—",
cooldown: "—",
tags: [],
desc: "",
notes: []
},
data || {}
);
this.refresh(String(key));
},
// Add a bullet note line (optional color/class)
addNote(key, msg, styleOrColor) {
if (!key) return;
this._ensureStore();
const v = State.variables;
const k = String(key);
const ab = v._abilities[k] || (v._abilities[k] = { key:k, name:k, rank:"—", cost:"—", cooldown:"—", tags:[], desc:"", notes:[] });
const entry = { t: Date.now(), msg: String(msg ?? "").trim() };
if (!entry.msg) return;
if (typeof styleOrColor === "string" && styleOrColor.trim()) {
entry.color = styleOrColor.trim();
} else if (styleOrColor && typeof styleOrColor === "object") {
if (typeof styleOrColor.color === "string" && styleOrColor.color.trim()) entry.color = styleOrColor.color.trim();
if (typeof styleOrColor.className === "string" && styleOrColor.className.trim()) entry.className = styleOrColor.className.trim();
}
ab.notes = ab.notes || [];
ab.notes.push(entry);
this.refresh(k);
},
getAll() {
this._ensureStore();
const v = State.variables;
return Object.values(v._abilities);
},
get(key) {
this._ensureStore();
return State.variables._abilities[String(key)];
},
// If panel exists, re-render one ability details
refresh(key) {
const k = String(key);
const root = document.querySelector(`#abilities-panel .med-details[data-abilitykey="${CSS.escape(k)}"]`);
if (!root) return;
const ab = this.get(k);
if (!ab) return;
const metaRank = root.querySelector(`[data-field="rank"]`);
const metaCost = root.querySelector(`[data-field="cost"]`);
const metaCd = root.querySelector(`[data-field="cooldown"]`);
const metaTags = root.querySelector(`[data-field="tags"]`);
const descEl = root.querySelector(`.ability-desc`);
const notesWrap = root.querySelector(`.med-scroll[data-role="notes"]`);
if (metaRank) metaRank.textContent = ab.rank ?? "—";
if (metaCost) metaCost.textContent = ab.cost ?? "—";
if (metaCd) metaCd.textContent = ab.cooldown ?? "—";
if (metaTags) metaTags.textContent = (ab.tags && ab.tags.length) ? ab.tags.join(", ") : "—";
if (descEl) descEl.textContent = ab.desc ?? "";
if (notesWrap) {
notesWrap.innerHTML = "";
const notes = ab.notes || [];
if (!notes.length) {
const empty = document.createElement("div");
empty.className = "med-empty";
empty.textContent = "No additional details recorded.";
notesWrap.appendChild(empty);
} else {
const ul = document.createElement("ul");
ul.style.margin = "0";
ul.style.paddingLeft = "16px";
notes.forEach(n => {
const li = document.createElement("li");
li.textContent = n.msg;
if (n.color) li.style.color = n.color;
if (n.className) li.classList.add(n.className);
ul.appendChild(li);
});
notesWrap.appendChild(ul);
}
}
}
};
/* ============================================================
Abilities panel (same look as Fame panel)
============================================================ */
window.createAbilitiesPanel = function () {
if (document.getElementById("abilities-panel")) return;
window.ensureMedievalPanelCSS();
Abilities._ensureStore();
const v = State.variables;
const panel = document.createElement("div");
panel.id = "abilities-panel";
Object.assign(panel.style, {
position: "fixed",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
minWidth: "380px",
maxWidth: "520px",
padding: "22px 26px",
zIndex: "10000",
background: `
linear-gradient(
to bottom,
rgba(74, 47, 27, 0.85),
rgba(47, 28, 17, 0.85)
)
`,
borderLeft: "6px solid rgba(42, 22, 11, 0.9)",
borderRadius: "12px 0 0 12px",
boxShadow: `
inset 0 0 30px rgba(0,0,0,0.55),
-8px 0 18px rgba(0,0,0,0.6)
`,
color: "#f0e0c0",
fontFamily: `"Cinzel", "Uncial Antiqua", "Palatino Linotype", "Book Antiqua", serif`
});
// Title
const title = document.createElement("div");
title.textContent = `✦ ${(v.playername || "Unknown")} Bloomspell's Abilities ✦`;
Object.assign(title.style, {
fontSize: "1.4em",
textAlign: "center",
marginBottom: "16px",
letterSpacing: "1px",
borderBottom: "1px solid rgba(240,224,192,0.25)",
paddingBottom: "6px"
});
panel.appendChild(title);
// Divider
const hr = document.createElement("div");
Object.assign(hr.style, {
height: "1px",
background: "rgba(240,224,192,0.18)",
margin: "10px 0 10px 0"
});
panel.appendChild(hr);
function addAbilityRow(ab) {
const key = String(ab.key);
const row = document.createElement("div");
row.className = "med-row";
row.setAttribute("data-abilitykey", key);
Object.assign(row.style, {
display: "flex",
justifyContent: "space-between",
marginBottom: "4px",
fontSize: "1.05em"
});
const left = document.createElement("span");
left.textContent = ab.name || key;
const right = document.createElement("span");
right.textContent = ab.rank ?? "—";
right.style.fontWeight = "bold";
row.appendChild(left);
row.appendChild(right);
const details = document.createElement("div");
details.className = "med-details";
details.setAttribute("data-abilitykey", key);
// NEW: inner scroller that holds ALL the dropdown content
const innerScroll = document.createElement("div");
innerScroll.className = "med-details-scroll";
details.appendChild(innerScroll);
const hint = document.createElement("div");
hint.className = "hint";
hint.textContent = "Ability Chronicle:";
innerScroll.appendChild(hint);
// Meta grid
const meta = document.createElement("div");
meta.className = "ability-meta";
meta.innerHTML = `
<div class="k">Rank</div><div class="v" data-field="rank"></div>
<div class="k">Cost</div><div class="v" data-field="cost"></div>
<div class="k">Cooldown</div><div class="v" data-field="cooldown"></div>
<div class="k">Tags</div><div class="v" data-field="tags"></div>
`;
innerScroll.appendChild(meta);
const desc = document.createElement("p");
desc.className = "ability-desc";
desc.style.margin = "6px 0 8px 0";
innerScroll.appendChild(desc);
const notesTitle = document.createElement("div");
notesTitle.className = "hint";
notesTitle.style.marginTop = "6px";
notesTitle.textContent = "Notes (scroll):";
innerScroll.appendChild(notesTitle);
const notesWrap = document.createElement("div");
notesWrap.className = "med-scroll";
notesWrap.setAttribute("data-role", "notes");
innerScroll.appendChild(notesWrap);
// Initial fill
setTimeout(() => Abilities.refresh(key), 0);
// Toggle (one open at a time)
row.addEventListener("click", () => {
const isOpen = details.classList.contains("open");
panel.querySelectorAll(".med-details.open").forEach(d => d.classList.remove("open"));
if (!isOpen) {
details.classList.add("open");
Abilities.refresh(key);
// Scroll notes to bottom + ensure dropdown scroller starts at top
setTimeout(() => {
innerScroll.scrollTop = 0;
notesWrap.scrollTop = notesWrap.scrollHeight;
}, 0);
}
});
panel.appendChild(row);
panel.appendChild(details);
}
const all = Abilities.getAll();
if (!all.length) {
const empty = document.createElement("div");
empty.className = "med-empty";
empty.textContent = "No abilities discovered yet.";
panel.appendChild(empty);
} else {
all.forEach(addAbilityRow);
}
// Close button
const closeBtn = document.createElement("button");
closeBtn.textContent = "Seal";
Object.assign(closeBtn.style, {
marginTop: "16px",
width: "100%",
padding: "8px",
background: "rgba(42, 22, 11, 0.9)",
color: "#f0e0c0",
border: "1px solid rgba(240,224,192,0.3)",
borderRadius: "6px",
cursor: "pointer",
fontFamily: "inherit"
});
closeBtn.onclick = () => panel.remove();
panel.appendChild(closeBtn);
document.body.appendChild(panel);
};
<</script>>
:: Example usage (programmatic definitions)
<<run Abilities.set("aelaras_scent", {
name: "Aelara's Scent",
rank: "Innate, Passive, Unique",
cost: "Passive",
cooldown: "—",
tags: ["Bloodline", "Pheromones", "Natural Allure"],
desc: "A sweet, lingering aroma clings to you, enticing males those who draw near, and haunting those who stay."
})>>
<<run Abilities.addNote("aelaras_scent", "You never understood the origins of this ability, it seems you are the only one that possesses it.")>>
<<run Abilities.addNote("aelaras_scent", "Females seem to be immune to it.", "gray")>>
<<run Abilities.addNote("aelaras_scent", "Some claim it makes them reckless around you.", "salmon")>>
<<run Abilities.addNote("aelaras_scent", "You never understood why some dogs and horses were so deeply interested in you.")>>
<<run Abilities.set("divine_beauty", {
name: "Divine Beauty",
rank: "Innate, Passive",
cost: "Passive",
cooldown: "—",
tags: ["Bloodline", "Temptation", "Natural Allure"],
desc: "Your delicate beauty is a gentle poison—pleasant at first, then impossible to ignore. Desire swells, judgment dulls, and the weak-willed confuse wanting you with needing you."
})>>
<<run Abilities.addNote("divine_beauty", "You wish you were taller and had a bigger chest...")>>
<<run Abilities.addNote("divine_beauty", "You always noticed how people look a little too much towards you.")>>
<<run Abilities.addNote("divine_beauty", "Some may take too much of a interest.", "salmon")>>
<<run Abilities.set("aelaras_healing", {
name: "Aelara's Healing",
rank: "Innate, Passive, Unique",
cost: "Passive",
cooldown: "—",
tags: ["Bloodline", "Healing", "Forbidden Grace"],
desc: "Your body carries a unique restorative grace that awakens only through intimate union. When another pours their vitality into you, that essence is transformed and a pulse of heal is given to the male, mending its flesh, purging sickness, and even restoring few months of age, should the giver believe such renewal to be healing."
})>>
<<run Abilities.addNote("aelaras_healing", "The healing does not draw from you, but from what is given to you. You cannot heal without an intimate act, the giver should ejaculate into you.", "lightgray")>>
<<run Abilities.addNote("aelaras_healing", "Wounds that should fester close cleanly, and ailments thought incurable simply vanish.")>>
<<run Abilities.addNote("aelaras_healing", "Can also restore virility, snowballing into long sessions.")>>
<<run Abilities.addNote("aelaras_healing", "Those who benefit often grow dangerously attached.", "salmon")>>
<<run Abilities.addNote("aelaras_healing", "Word of this gift, if spread, would make you a target rather than a miracle.", "salmon")>>
<<run Abilities.set("aelaras_vital_absorption", {
name: "Aelara's Vital Absorption",
rank: "Innate, Unique",
cost: "Male Sperm",
cooldown: "—",
tags: ["Bloodline", "Self Healing", "Forbidden Grace"],
desc: "When you carry residual vitality within you, a portion of it may be drawn inward and refined for your own restoration. This stolen fragment mirrors the same miraculous renewal you grant others—mending wounds, purging sickness, and easing the toll of the body—without consuming the whole of what was given."
})>>
<<run Abilities.addNote("aelaras_vital_absorption", "Only a fraction of the sperm you carry can be reclaimed for yourself, not all of it.", "lightgray")>>
<<run Abilities.set("royal_presence", {
name: "Royal Presence",
rank: " Innate, Passive, Princess of Elliahal",
cost: "Passive",
cooldown: "—",
tags: ["Bloodline", "Burden", "Vulnerability"],
desc: "Your lineage precedes you, but not in strength. Guards tighten their watch, voices lower, and eyes linger, many see not a leader, but something fragile that must be protected… or taken. Your name opens doors—but also paints a mark on your back. Too soft to command, too valuable to ignore, you are seen less as a ruler and more as a prize"
})>>
<<run Abilities.addNote("royal_presence", "Your words are frequently met with gentle smiles rather than obedience.")>>
<<run Abilities.addNote("royal_presence", "Strangers hesitate to confront you directly, but feel no obligation to obey.")>>
<<run Abilities.addNote("royal_presence", "Those who wish to exploit power often see you as an easier path to hit the King and Elliahal.", "salmon")>>
<<run createAbilitiesPanel()>><<if $stringTimeNow <= 6 || $stringTimeNow >= 19>><<runScenario "princesstentoutsidenight">><</if>>
<<if $stringTimeNow > 6 && $stringTimeNow < 19>><<runScenario "princesstentoutside">><</if>>
<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.50" data-y="0.42" style="transform: translate(-50%, -50%);">
<<button "⮟ Return to my tent ⮟">>
<<run $datenow.setMinutes($datenow.getMinutes() + 1)>>
<<goto "Princess Tent">>
<</button>> </span>
<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.38" data-y="0.28" style="transform: translate(-50%, -50%);">
<<button "Go to the Main Tent">>
<<run $datenow.setMinutes($datenow.getMinutes() + 1)>>
<<goto "War Tent">>
<</button>> </span>
<<if $stringTimeNow <= 6 || $stringTimeNow >= 19>><<runScenario "wartentoutsidenight">><</if>>
<<if $stringTimeNow > 6 && $stringTimeNow < 19>><<runScenario "wartentoutside">><</if>>
<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.65" data-y="0.42" style="transform: translate(-50%, -50%);">
<<button "⮞ Return to my tent ⮞">>
<<run $datenow.setMinutes($datenow.getMinutes() + 1)>>
<<goto "Princess Tent">>
<</button>> </span>
<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.50" data-y="0.46" style="transform: translate(-50%, -50%);">
<<button "⮟ Return to Main Tent ⮟">>
<<run $datenow.setMinutes($datenow.getMinutes() + 1)>>
<<goto "War Tent">>
<</button>> </span>
<<run openConversation("calthir_intro")>>
<<script>>
window.Conversations = {
cant_sleep_message: {
title: "Can't sleep",
text: "I can't sleep dressed, it would wrinkle the dress.",
options: []
},
first_message: {
title: "Better Experience",
text: "You can advance dialogues by pressing any keyboard key or mouse button. It is advised to play in full screen (F11).",
options: []
},
end_of_content_message: {
title: "End of current content",
text: "You’ve reached the end of the current build. You can still continue playing the loop, as it is part of Aelara’s story, she will remain trapped in this routine for some time before the next major event begins, when her father finally arrives at the camp. Every night at 23-24pm you will be released to sleep and/or bathe, though you can skip if pressing fast the loop from 23-24pm. You can also check some of the lore by clicking the buttons below the character’s portrait in the right-side menu. If you want to help this project grow faster and support new scenes, updates, and features, consider supporting it on Patreon.",
options: [
{
label: "Patreon",
action: () => { window.open("https://www.patreon.com/c/afeell/membership", "_blank"); Engine.play("PrincessTent Bed Loop Intro");}
},
{
label: "Close Message",
action: () => {Engine.play("PrincessTent Bed Loop Intro");}
}
]
},
tip_n1: {
title: "1st Person Look",
text: "You can look around by draggin the mouse towards the screen edges. Find your next objective by looking at the right side of your tent.",
options: []
},
river_undress_intro: {
title: "Undressed",
text: "Under the moon’s pale hush, you ease your dress down and set it neatly on a stone by the shore. The night air kisses your bare skin—cool, thrilling—while the lake waits in perfect stillness. You pause for a heartbeat, listening for any sound that doesn’t belong.",
options: []
},
river_path: {
title: "River",
text: "The soft sound of the current, the scent of damp earth, and the dark outline of trees make the whole place feel beautiful, quiet, and strangely untouched.",
options: []
},
river_relax_intro: {
title: "Moonlit Lake",
text: "The lake opens before you like a hidden jewel beneath the moon, its surface painted in silver light and broken only by soft ripples around your body. Tall reeds sway gently at the edges, and dark trees stand watch beyond the shore, their reflections trembling in the warm, inviting water. Far behind you, the camp feels impossibly distant now—its noise swallowed by the night—leaving only the hush of crickets, the scent of damp earth, and the soothing heat of the lake wrapping around your skin like a secret meant only for you.",
options: [
{
label: "Look around the quiet shore",
next: "river_relax_intro2"
},
{
label: "Close your eyes and enjoy the silence",
action: () => {Engine.play("CloseEyes_LakeIntro");},
next: "river_relax_intro3"
}
]
},
river_relax_intro2: {
title: "Quiet Shore",
text: "You turn your gaze toward the edge of the lake, letting your eyes wander across the quiet shore. Smooth stones glisten beneath the moonlight, and the grass beyond them bends softly in the night breeze. Here and there, pale flowers catch the silver glow, while the dark line of the trees rises like a wall around this hidden refuge. Everything feels untouched, secret, almost dreamlike—until a faint sound stirs somewhere behind you, small but wrong against the calm. Your body stills at once, and you slowly look back over your shoulder.",
options: [
{
label: "Turn and see what made the sound",
action: () => {Engine.play("Lake Bathe WarlordIntro");}
}
]
},
river_relax_intro3: {
title: "Stillness",
text: "You let your eyes close and simply drift in the warm water, feeling it cradle your body with a gentleness that the camp, the march, and the endless weight of duty never could. The night air brushes your skin while the lake’s heat eases every bit of tension from your limbs, and for a few precious moments it feels as if the whole world has gone silent just for you. Then, through the hush, something breaks the stillness behind you—a subtle noise from the shore that does not belong. Your eyes open at once, and you turn to look behind you.",
options: [
{
label: "Whirl around toward the sound",
action: () => {Engine.play("Lake Bathe WarlordIntro");}
}
]
},
areothic_river_confrontation: {
title: "Cornered at the Water",
text: "Your pulse pounds so hard it almost drowns out the lake. Areothic stands at the water’s edge, far too close, his presence turning the quiet shore into a trap. The camp is behind you, your guards are gone, and your father and brother rode out with the army. You can either try to explain yourself... or cling to your title and order him away.",
options: [
{
label: "Explain myself",
action: () => {Engine.play("Lake Bathe WarlordIntro_Explain");}
},
{
label: "Order him to leave",
action: () => {Engine.play("Lake Bathe WarlordIntro_Command");}
}
]
},
areothic_river_confrontation_uncoverordont: {
title: "Uncover or cover",
text: "You clutch at what little cover you still have, painfully aware of how patient Areothic looks at the water’s edge. That patience does not comfort you, it only makes you wonder how long it will last, and what happens when it runs out. You can keep covering yourself and risk testing him, or uncover yourself and pray obedience buys you something.",
options: [
{
label: "Uncover myself",
action: () => {Engine.play("Lake Bathe WarlordIntro_Uncover");}
},
{
label: "Keep covering myself",
action: () => {Engine.play("Lake Bathe WarlordIntro_Cover");}
}
]
},
areothic_river_confrontation_laydownwilling: {
title: "No escape",
text: "Areothic’s voice leaves no space for argument—calm, certain. 'Now, lay on your back' You stand beside him at the shore, barefoot on moss and damp grass. The camp is far, your guards are gone, and your name means nothing here, you could run, but he would catch your small frame in couple steps. Your throat tightens, your pulse loud in your ears, and you understand the only thing left is compliance. Slowly, you lower yourself to the ground, easing onto your back on the soft, wet green, staring up at the moon while his shadow falls over you.",
options: [
{
label: "Lay Down",
action: () => {Engine.play("Lake Bathe WarlordIntro laydown_willing");}
}
]
},
areothic_river_confrontation_pushed: {
title: "Thrown on the ground",
text: "You don’t even finish drawing breath before he closes the distance. No warning, no struggle, just a sudden shift of his weight and your feet vanish from under you. The world flips; moss and wet grass slam into your back, knocking the air from your lungs. Areothic never lifts a hand, arms still folded behind him as if you’re nothing to handle. His shadow covers you, and his voice stays calm above the ringing in your ears: 'Try moving.'",
options: [
{
label: "Freeze in place",
action: () => {Engine.play("Lake Bathe WarlordIntro Pushed");}
}
]
},
areothic_river_confrontation_violated: {
title: "Thrown on the ground",
"text": "His hips snap forward without warning, burying himself deep once more, never fully pulling out, just grinding in deeper, stirring the slick heat he already left inside you. The rhythm restarts instantly: hard, relentless, unyielding. Your calves remain trapped in his bruising grip, legs forced high and wide, hips lifted helplessly off the moss so every thrust rocks your entire body. You try to twist, to push, to close your thighs, anything, but your small frame is nothing against his strength. There is no escape, no mercy, no pause. You can only take it: each punishing stroke stretching you anew, each impact punching the air from your lungs, each wet sound echoing in the night as your body is forced to accept him again and again and again.",
options: [
{
label: "You Cry and Sob Waiting For It To Be Over",
action: () => {Engine.play("Lake Bathe WarlordIntro Pushed");}
}
]
},
areothic_river_confrontation_violated: {
title: "Thrown on the ground",
"text": "His hips snap forward without warning, burying himself deep once more, never fully pulling out, just grinding in deeper, stirring the slick heat he already left inside you. The rhythm restarts instantly: hard, relentless, unyielding. Your calves remain trapped in his bruising grip, legs forced high and wide, hips lifted helplessly off the moss so every thrust rocks your entire body. You try to twist, to push, to close your thighs, anything, but your small frame is nothing against his strength. There is no escape, no mercy, no pause. You can only take it: each punishing stroke stretching you anew, each impact punching the air from your lungs, each wet sound echoing in the night as your body is forced to accept him again and again and again.",
options: [
{
label: "You Cry and Sob Waiting For It To Be Over",
action: () => {Engine.play("Lake Bathe WarlordIntro_Violation8");}
}
]
},
"areothic_river_confrontation_end1": {
"title": "The Long Night Ends",
"text": "What feels like an eternity later, five times he has emptied himself inside you, each release more possessive and deeper than the last, he finally stills. His breathing is heavy but steady, utterly satisfied. Your body is limp, trembling, completely spent. Cum leaks steadily from between your thighs, pooling warm and sticky beneath you on the crushed moss. Every muscle screams; your voice is gone, reduced to hoarse, broken whimpers that barely reach the night air. He withdraws slowly, deliberately, letting you feel every inch of his absence. You stay sprawled on your back, legs splayed, chest heaving, too shattered to even try closing them. His shadow looms above you one last time. Dark eyes rake over your ruined form, bruises blooming on your calves and hips, skin flushed, glistening with sweat and his seed. He orders you to get up, gather your things, dress and follow him.",
"options": [
{
"label": "Struggle to obey",
action: () => {Engine.play("Lake Bathe WarlordIntro_End1");}
}
]
},
"areothic_river_confrontation_end2": {
"title": "The Long Night Ends",
"text": "The command is quiet, final. No anger, no tenderness—just cold ownership.You struggle to obey: arms shaking violently, legs refusing to hold your weight at first. You manage to sit, then stand on wobbling knees. With numb, trembling fingers you gather the sodden silk scraps that were once your dress. You pull the ruined fabric over your body; it clings transparently in places, doing almost nothing to hide the evidence of what he’s done, red marks, bruises, the slow trickle still leaking down your inner thighs.He steps close. One massive hand closes around the back of your neck, not choking, just guiding, controlling. The other slides down, cups your ass possessively, fingers digging into soft, abused flesh. 'Not a word. Not to your brother. Not to your father. Not to anyone. You speak, and I come for you again, only next time I won’t bring you back.' He steers you through the dark trees, back toward the camp. No one sees. No one hears. The walk feels endless; every step sends fresh aches through your core.",
"options": [
{
"label": "Reach your tent",
action: () => {Engine.play("Lake Bathe WarlordIntro_End2");}
}
]
},
"areothic_river_confrontation_end3": {
"title": "The Long Night Ends",
"text": "When you finally reach your private tent, he pushes you inside. He releases your neck, but not before giving your ass one final, warning squeeze, hard enough to make you gasp. Then he turns and vanishes into the night without another word. You stand there, legs trembleing under you. The tent flap falls closed behind him. Silence swallows you whole. You lie there, still leaking, still burning, the taste of fear on your lips. The night presses in, heavy and suffocating. You tremble with aftershocks, your mind is blank except for the echo of his voice. Nothing will ever feel the same again.",
"options": [
{
"label": "What To Do Next...",
action: () => {Engine.play("Princess Tent PosIntro");}
}
]
},
"Thalenwyr_intro": {
"title": "Thalenwyr Visit",
"text": "Outside your tent, you hear the familiar voice of the youngest of your brothers, gentle and unmistakable through the canvas. Even before he enters, something in you eases at the sound of him.",
"options": [
{
"label": "Let him enter",
action: () => {Engine.play("camp Thale intro");}
}
]
},
"22nd_story1": {
"title": "Kidnapped on my own tent",
"text": "Kaeltharion’s threat echoes: endless turns with every soldier until you’re broken. Your father and brothers left yesterday at nightfall—far away. The 22nd battalion guards stand right outside your tent, watching you with dark intent. They’re meant to protect you. Instead, they plan to use you, and help seize the throne when the king returns. Last night was bad. This is betrayal from within. Your legs tremble. The day’s just begun, and you’re already trapped prey.",
"options": []
},
"food_camp_intro": {
"title": "Food",
"text": "You eat because you should, but the food tastes dull, flatter, thinner, and somehow not as good as it did on the other days.",
"options": [
{
label: "Seal",
action: () => {Engine.play("Princess Tent PosIntro3");}
}
]
},
"dizzyness_camp_intro": {
"title": "Not Feeling Well...",
"text": "You lie back on the bed, meaning to rest only for a moment. A heavy dizziness rolls through your head, warm and slow, and your limbs start to sink into the blankets as sleep drags at you far faster than it should.",
"options": [
{
label: "Seal",
action: () => {Engine.play("Princess Tent Kaeltharion2");}
}
]
},
"dizzyness_camp_intro2": {
"title": "Not Feeling Well...",
"text": "Voices pull at the edge of your fading thoughts, some outside the tent, hurried and muffled, others suddenly too close, moving within the canvas walls around you.",
"options": [
{
label: "Seal",
action: () => {Engine.play("Princess Tent Kaeltharion3");}
}
]
},
"dizzyness_camp_intro3": {
"title": "Not Feeling Well...",
"text": "Through the haze, you catch Commander Kaeltharion’s voice outside, firm and orderly, directing some kind of rotation between the men, but your thoughts are too blurred to follow what he is assigning or why.",
"options": [
{
label: "Seal",
action: () => {Engine.play("Princess Tent Kaeltharion4");}
}
]
},
"dizzyness_camp_intro4": {
"title": "Not Feeling Well...",
"text": "For one brief, horrible moment, clarity returns. You find yourself lying on your bed, naked, and a cluster of men stands inside the tent, their faces turned toward you, watching.",
"options": [
{
label: "Seal",
action: () => {Engine.play("Princess Tent Kaeltharion5");}
}
]
},
"dizzyness_camp_intro5": {
"title": "Not Feeling Well...",
"text": "Panic surges through you, sharp and immediate, but before you can move or make sense of anything, the clarity slips away again, and your consciousness sinks back into the dark.",
"options": [
{
label: "Seal",
action: () => {Engine.play("Princess Tent Kaeltharion6");}
}
]
},
"dizzyness_camp_intro6": {
"title": "What is going on?",
"text": "Some time later?",
"options": [
{
label: "Wake up!",
action: () => {Engine.play("Princess Tent Kaeltharion7");}
}
]
},
"dizzyness_camp_intro7": {
"title": "Awakened!",
"text": "You suddently feel an aching pain from your holes as consciousness returns all at once, sharp enough to make you jolt inside your own skin. You have no idea how many hours have passed...",
"options": [
{
label: "Scream",
next: "dizzyness_camp_scream"
},
{
label: "Let It Happen",
next: "dizzyness_camp_accept"
},
{
label: "Try To Kick And Escape",
next: "dizzyness_camp_try_fight"
}
]
},
"dizzyness_camp_scream": {
"title": "Scream!",
"text": "You force air into your lungs and try to scream, but the sound comes out weak, ruined by the drugged haze still clinging to your body. The men hear it. Of course they do. But instead of alarm, it only earns laughter, low at first, then open, careless, cruel. Someone mocks the effort. Another tells you to save your strength. The humiliation lands harder than the failure itself, and nothing changes except the ringing in your ears.",
"options": [
{
label: "...",
action: () => {Engine.play("Princess Tent Kaeltharion7");}
}
]
},
"dizzyness_camp_accept": {
"title": "Let It Happen!",
"text": "Your mind reaches for reason because panic is too large to hold. If resistance changes nothing, then perhaps stillness will cost less. Perhaps silence is easier. Perhaps there is no meaningful difference between fighting, pleading, or enduring when the outcome has already been decided around you. You tell yourself this because you need something to cling to, some logic to make the helplessness feel smaller, but the truth remains unchanged, cold and immovable.",
"options": [
{
label: "...",
action: () => {Engine.play("Princess Tent Kaeltharion7");}
}
]
},
"dizzyness_camp_try_fight": {
"title": "To Escape!",
"text": "You gather what little strength you have left and lash out, desperate more than coordinated, but it makes no difference. A hand catches your leg with humiliating ease, holding you in place before the motion can become anything real. The effort dies there, trapped as quickly as it began. Your body feels heavy, slow, unreliable, and the brief spark of resistance only leaves you more aware of how completely overpowered you are.",
"options": [
{
label: "...",
action: () => {Engine.play("Princess Tent Kaeltharion7");}
}
]
},
"dizzyness_camp_intro8": {
"title": "Detached",
"text": "You stop trying to see them as people. Their faces blur into something meaningless, not worth the effort of remembering. Anger, frustration, and fear crowd everything else out until your mind does the only thing it can, it pulls away. Numbness settles over you like a shield, thin and fragile, but easier than feeling all of it at once.",
"options": [
{
label: "Wait it to be over?",
action: () => {Engine.play("PrincessTent Bed Loop");}
}
]
},
"princess_camp_bed_loop": {
"title": "...Non Stop...",
"text": "Wait for?",
"options": [
{
label: "Next One...",
action: () => {Engine.play("PrincessTent Bed Loop");}
}
]
},
"princess_camp_bed_loop_begin_another_day": {
"title": "Another Day Begins...",
"text": "You wake only to realize nothing truly ended. The same tent, the same dread, the same crushing certainty that the day ahead will drag you through its familiar torment all over again.",
"options": [
{
label: "Another Day...",
action: () => {Engine.play("PrincessTent Bed Loop");}
}
]
},
calthir_intro: {
title: "Calthir",
text: "The elf watches you carefully, fingers resting near his blade.",
options: [
{
label: "Ask about Elliahal",
next: "elliahal_topic"
},
{
label: "Remain silent",
action: () => { State.variables.silentChoice = true; }
},
{
label: "Leave"
}
]
},
elliahal_topic: {
title: "Calthir — Elliahal",
text: "Elliahal is ancient. Few understand its true nature.",
options: [
{
label: "Press for more information",
action: () => {
State.variables.elliahalKnowledge =
(State.variables.elliahalKnowledge || 0) + 1;
}
},
{
label: "Return",
next: "calthir_intro"
}
]
}
};
<</script>>
<<run openConversation("calthir_intro")>>
<<set $datenow = new Date('May 3, 52068 021:00:00')>>
<<runScenario "warcamp/wartent_first_talk1.jpg" "cg">>
<<comic "scene_intro_camp" "Intro War Camp2">>
<<run openConversation("first_message")>>
<<set $datenow = new Date('May 3, 52068 021:00:00')>>
<<runScenario "warcamp/wartent_first_talk2.jpg" "cg">>
<<comic "scene_intro_camp2" "Family Departure">>
<<if $stringTimeNow <= 6 || $stringTimeNow >= 19>><<runScenario "princesstentnight">><</if>>
<<if $stringTimeNow > 6 && $stringTimeNow < 19>><<runScenario "princesstent">><</if>>
<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.50" data-y="0.32" style="transform: translate(-50%, -50%);">
<<button "sleep">>
<<if $chestSlot != "">>
<<run openConversation("cant_sleep_message")>>
<</if>>
<<if $chestSlot == "">>
<<if (($datenow.getHours() < 8) && ($datenow.getHours() >= 0))>>
<<run $datenow.setHours(8)>>
<<run Save.slots.save(0)>>
<<goto "">>
<</if>>
<<if ($datenow.getHours() >= 18)>>
<<run $datenow.setDate($datenow.getDate() + 1)>>
<<run $datenow.setHours(8)>>
<<run Save.slots.save(0)>>
<<goto "">>
<</if>>
<</if>>
<</button>> </span>
<<if $lastbath && (($datenow.getTime() - $lastbath) < 60*60*1000)>>
<!-- hide / don't show -->
<<else>>
<!-- show it -->
<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.05" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "bathe">>
<<set $lastbath to $datenow>>
<<run $datenow.setMinutes($datenow.getMinutes() + 30)>>
<<set $cumBottomSlot to "">>
<<set $cumTopSlot to "">>
<<set $neckSlot to "">>
<<set $chestSlot to "">>
<<set $hipSlot to "">>
<<set $legSlot to "">>
<<set $feetSlot to "">>
<<set $acessorySlot to "">>
<<set $cumBottomClothSlot to "">>
<<set $cumTopClothSlot to "">>
<<goto "Princess Tent Intro">>
<</button>> </span>
<</if>>
<<if $chestSlot == "">><span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.35" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "Get Dressed">>
<<set $chestSlot to "Elven Dress 6">>
<<goto "Princess Tent Intro">>
<</button>> </span><</if>>
<<if $chestSlot != "">><span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.35" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "Get Undressed">>
<<set $chestSlot to "">>
<<goto "Princess Tent Intro">>
<</button>> </span><</if>>
<<if $stringTimeNow <= 6 || $stringTimeNow >= 19>><<runScenario "princesstentnight">><</if>>
<<if $stringTimeNow > 6 && $stringTimeNow < 19>><<runScenario "princesstent">><</if>>
<<if $lastbath && (($datenow.getTime() - $lastbath) < 60*60*1000)>>
<!-- hide / don't show -->
<<else>>
<!-- show it -->
<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.05" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "bathe">>
<<set $lastbath to $datenow>>
<<run $datenow.setMinutes($datenow.getMinutes() + 30)>>
<<set $cumBottomSlot to "">>
<<set $cumTopSlot to "">>
<<set $neckSlot to "">>
<<set $chestSlot to "">>
<<set $hipSlot to "">>
<<set $legSlot to "">>
<<set $feetSlot to "">>
<<set $acessorySlot to "">>
<<set $cumBottomClothSlot to "">>
<<set $cumTopClothSlot to "">>
<<goto "Princess Tent Intro2">>
<</button>> </span>
<</if>>
<<if $chestSlot == "">><span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.35" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "Get Dressed">>
<<set $chestSlot to "Elven Dress 6">>
<<goto "Princess Tent Intro2">>
<</button>> </span><</if>>
<<if $chestSlot != "">><span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.35" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "Get Undressed">>
<<set $chestSlot to "">>
<<goto "Princess Tent Intro2">>
<</button>> </span><</if>>
<<set $datenow = new Date('May 3, 52068 021:00:00')>>
<<runScenario "princesstentnight">>
<<comic "princess_idea_intro" "Princess Tent PreIntro">><<runScenario "princesstentnight">>
<<if ($gametips == 0)>>
<<set $gametips to 1>>
<<run openConversation("tip_n1")>>
<</if>>
<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.95" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "Go Outside">>
<<goto "Princess Tent Outside PreIntro">>
<</button>> </span>
<<runScenario "princesstentoutsidenight">>
<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.65" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "⮞ Sneak towards the river ⮞">>
<<goto "Lake path intro">>
<</button>> </span>
<<runScenario "lakepath">><<run $datenow.setMinutes($datenow.getMinutes() + 5)>>
<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.50" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button " Walk Towards the River">>
<<goto "Lake PreIntro">>
<</button>> </span>
<<run $datenow.setMinutes($datenow.getMinutes() + 5)>>
<<runScenario "lake">>
<<comic "princess_river_arrival" "Lake Intro">>
<<run openConversation("river_path")>><<runScenario "lake">><<run $datenow.setMinutes($datenow.getMinutes() + 3)>>
<<if ($chestSlot != "")>><span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.50" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "Undress">>
<<set $chestSlot to "">>
<<goto "Lake Intro">>
<<run openConversation("river_undress_intro")>>
<</button>></span><</if>>
<<if ($chestSlot == "")>><span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.50" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "Bathe">>
<<goto "Lake Bathe">>
<</button>></span><</if>>
/*<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.40" data-y="0.42" style="transform: translate(-50%, -50%);">
<<button "PushForward">>
<<PushForwardFX>>
<</button>></span>*/
/*<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.40" data-y="0.38" style="transform: translate(-50%, -50%);">
<<button "PushBack">>
<<PushBackFX>>
<</button>></span>*/<<runScenario "warcamp/lakebath.jpg" "cg" "nobody">>
<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.50" data-y="0.25" style="transform: translate(-50%, -50%);">
<<button "Relax">>
<<run openConversation("river_relax_intro")>>
<</button>></span>
<<script>>
/* ============================================================
Relationship panel CSS (inject once)
============================================================ */
window.ensureRelationshipCSS = function () {
if (document.getElementById("relationship-css")) return;
const style = document.createElement("style");
style.id = "relationship-css";
style.textContent = `
.rel-row {
cursor: pointer;
padding: 6px 8px;
border-radius: 8px;
user-select: none;
display: flex;
justify-content: space-between;
align-items: center;
gap: 10px;
font-size: 1.03em;
}
.rel-row:hover { background: rgba(240,224,192,0.06); }
.rel-name {
font-weight: 700;
letter-spacing: 0.2px;
}
.rel-badge {
font-weight: 700;
padding: 2px 8px;
border-radius: 999px;
border: 1px solid rgba(240,224,192,0.18);
background: rgba(0,0,0,0.18);
white-space: nowrap;
font-size: 0.95em;
}
/* ✅ Scrollable list area (20+ entries won't go offscreen) */
.rel-list {
max-height: 52vh;
overflow-y: auto;
padding-right: 6px;
margin-top: 6px;
scrollbar-width: thin;
scrollbar-color: rgba(240,224,192,0.25) rgba(0,0,0,0.15);
}
.rel-list::-webkit-scrollbar { width: 8px; }
.rel-list::-webkit-scrollbar-track { background: rgba(0,0,0,0.15); border-radius: 10px; }
.rel-list::-webkit-scrollbar-thumb { background: rgba(240,224,192,0.22); border-radius: 10px; }
.rel-list::-webkit-scrollbar-thumb:hover { background: rgba(240,224,192,0.30); }
.rel-details {
overflow: hidden;
max-height: 0;
opacity: 0;
transition: max-height 0.25s ease, opacity 0.2s ease;
margin: 0 8px 10px 8px;
padding: 0 10px;
border-left: 2px solid rgba(240,224,192,0.18);
color: rgba(240,224,192,0.92);
font-size: 0.95em;
line-height: 1.25em;
}
.rel-details.open {
max-height: 420px; /* bigger so meta + log aren't clipped */
opacity: 1;
padding-top: 8px;
padding-bottom: 8px;
}
.rel-hint {
opacity: 0.85;
font-style: italic;
margin-bottom: 8px;
}
.rel-meta {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 6px 12px;
margin-bottom: 10px;
padding-bottom: 8px;
border-bottom: 1px solid rgba(240,224,192,0.10);
font-size: 0.98em;
}
.rel-meta b { color: rgba(255,221,160,0.95); font-weight: 800; }
.rel-log-wrap {
max-height: 140px;
overflow-y: auto;
padding-right: 6px;
padding-top: 6px;
padding-bottom: 14px;
border-top: 1px solid rgba(240,224,192,0.08);
border-bottom: 1px solid rgba(240,224,192,0.08);
scrollbar-width: thin;
scrollbar-color: rgba(240,224,192,0.25) rgba(0,0,0,0.15);
}
.rel-log-wrap::-webkit-scrollbar { width: 8px; }
.rel-log-wrap::-webkit-scrollbar-track { background: rgba(0,0,0,0.15); border-radius: 10px; }
.rel-log-wrap::-webkit-scrollbar-thumb { background: rgba(240,224,192,0.22); border-radius: 10px; }
.rel-log-wrap::-webkit-scrollbar-thumb:hover { background: rgba(240,224,192,0.30); }
.rel-log { margin: 0; padding-left: 16px; }
.rel-log li { margin: 4px 0; }
.rel-empty {
opacity: 0.75;
font-style: italic;
margin: 6px 0 0 0;
}
/* ✅ Affinity (string) colors */
.rel-aff-unknown { color: #9a9a9a; text-shadow: 0 0 6px rgba(154,154,154,0.12); }
.rel-aff-enemy { color: #ff7a7a; text-shadow: 0 0 6px rgba(255,122,122,0.14); }
.rel-aff-friend { color: #8fe39b; text-shadow: 0 0 6px rgba(143,227,155,0.14); }
.rel-aff-lover { color: #cfa8ff; text-shadow: 0 0 6px rgba(207,168,255,0.16); }
.rel-aff-master { color: #ff4d4d; text-shadow: 0 0 7px rgba(255,77,77,0.18); }
.rel-aff-rapist { color: #ff1f1f; text-shadow: 0 0 8px rgba(255,31,31,0.22); }
.rel-aff-family { color: #6fb6ff; text-shadow: 0 0 6px rgba(111,182,255,0.16); }
/* (kept) small glow helpers you already had */
.rel-glow-family { color: #d6b56e; text-shadow: 0 0 6px rgba(214, 181, 110, 0.18); }
.rel-glow-father { color: #356A99; text-shadow: 0 0 6px rgba(120, 170, 255, 0.18); }
.rel-glow-brother { color: #3D85C6; text-shadow: 0 0 6px rgba(190, 160, 255, 0.18); }
.rel-glow-mother { color: #942F41; text-shadow: 0 0 6px rgba(190, 160, 255, 0.18); }
.rel-glow-good { color: #a7c7a1; text-shadow: 0 0 6px rgba(120, 200, 140, 0.18); }
.rel-glow-bad { color: #c88b7a; text-shadow: 0 0 6px rgba(220, 120, 90, 0.18); }
.rel-glow-hot {
color: #c86a6a;
text-shadow: 0 0 6px rgba(220, 90, 90, 0.20);
animation: relHotPulse 1.8s ease-in-out infinite;
}
@keyframes relHotPulse {
0%, 100% { filter: brightness(1); }
50% { filter: brightness(1.08); }
}
`;
document.head.appendChild(style);
};
/* ============================================================
Relationship status resolver (colors the RIGHT badge)
============================================================ */
window.getRelationshipStyle = function (statusText) {
const s = String(statusText || "").toLowerCase().trim();
if (s === "family") return { className: "rel-glow-family" };
if (s === "father") return { className: "rel-glow-father" };
if (s === "brother") return { className: "rel-glow-brother" };
if (s === "mother") return { className: "rel-glow-mother" };
if (s.includes("lover") || s.includes("romance") || s.includes("flirting")) {
return { className: "rel-glow-hot" };
}
if (s.includes("friend") || s.includes("ally") || s.includes("trusted")) {
return { className: "rel-glow-good" };
}
if (s.includes("hostile") || s.includes("enemy") || s.includes("hate")) {
return { className: "rel-glow-bad" };
}
return "#f0e0c0";
};
/* ============================================================
Affinity (string) -> class resolver (colors meta line)
============================================================ */
window.getAffinityClass = function (affinityText) {
const a = String(affinityText || "Unknown").toLowerCase().trim();
if (a === "enemy") return "rel-aff-enemy";
if (a === "friend") return "rel-aff-friend";
if (a === "lover") return "rel-aff-lover";
if (a === "master") return "rel-aff-master";
if (a === "rapist") return "rel-aff-rapist";
if (a === "family") return "rel-aff-family";
return "rel-aff-unknown";
};
/* ============================================================
Relationship log store
============================================================ */
window.RelationshipLog = {
_ensureStore() {
const v = State.variables;
if (!v._relLog) v._relLog = {};
if (!v._relLogMax) v._relLogMax = 18;
},
setMax(n) {
this._ensureStore();
State.variables._relLogMax = Math.max(1, Number(n) || 18);
},
add(key, msg, styleOrColor) {
if (!key) return;
this._ensureStore();
const v = State.variables;
const k = String(key);
const entry = { t: Date.now(), msg: String(msg ?? "").trim() };
if (!entry.msg) return;
if (typeof styleOrColor === "string" && styleOrColor.trim()) {
entry.color = styleOrColor.trim();
} else if (styleOrColor && typeof styleOrColor === "object") {
if (typeof styleOrColor.color === "string" && styleOrColor.color.trim()) entry.color = styleOrColor.color.trim();
if (typeof styleOrColor.className === "string" && styleOrColor.className.trim()) entry.className = styleOrColor.className.trim();
}
v._relLog[k] = v._relLog[k] || [];
v._relLog[k].push(entry);
const max = v._relLogMax || 18;
if (v._relLog[k].length > max) v._relLog[k] = v._relLog[k].slice(-max);
this.refresh(k);
},
clear(key) {
this._ensureStore();
const v = State.variables;
v._relLog[String(key)] = [];
this.refresh(String(key));
},
get(key) {
this._ensureStore();
const v = State.variables;
return (v._relLog[String(key)] || []).slice();
},
refresh(key) {
const k = String(key);
const container = document.querySelector(
`#relationship-panel .rel-details[data-relkey="${CSS.escape(k)}"] .rel-log-wrap`
);
if (!container) return;
container.innerHTML = "";
const items = this.get(k);
if (!items.length) {
const empty = document.createElement("div");
empty.className = "rel-empty";
empty.textContent = "No moments recorded yet.";
container.appendChild(empty);
return;
}
const ul = document.createElement("ul");
ul.className = "rel-log";
items.forEach(it => {
const li = document.createElement("li");
li.textContent = it.msg;
if (it.color) li.style.color = it.color;
if (it.className) li.classList.add(it.className);
ul.appendChild(li);
});
container.appendChild(ul);
}
};
/* ============================================================
✅ NEW: Seed-once helper (prevents repeated log adds)
============================================================ */
window.RelationshipLogSeedOnce = function (seedId, fn) {
const v = State.variables;
if (!v._relSeedOnce) v._relSeedOnce = {};
if (v._relSeedOnce[seedId]) return; // already done
v._relSeedOnce[seedId] = true;
fn();
};
/* ============================================================
Relationship panel builder
============================================================ */
window.RelationshipPanel = {
_panelId: "relationship-panel",
open() {
if (document.getElementById(this._panelId)) return;
window.ensureRelationshipCSS();
RelationshipLog._ensureStore();
const v = State.variables;
const panel = document.createElement("div");
panel.id = this._panelId;
Object.assign(panel.style, {
position: "fixed",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
minWidth: "420px",
maxWidth: "560px",
maxHeight: "86vh",
overflow: "hidden",
display: "flex",
flexDirection: "column",
padding: "22px 26px",
zIndex: "10000",
background: `
linear-gradient(
to bottom,
rgba(74, 47, 27, 0.85),
rgba(47, 28, 17, 0.85)
)
`,
borderLeft: "6px solid rgba(42, 22, 11, 0.9)",
borderRadius: "12px 0 0 12px",
boxShadow: `
inset 0 0 30px rgba(0,0,0,0.55),
-8px 0 18px rgba(0,0,0,0.6)
`,
color: "#f0e0c0",
fontFamily: `"Cinzel", "Uncial Antiqua", "Palatino Linotype", "Book Antiqua", serif`
});
const title = document.createElement("div");
title.textContent = `✦ Bonds & Oaths ✦`;
Object.assign(title.style, {
fontSize: "1.45em",
textAlign: "center",
marginBottom: "14px",
letterSpacing: "1px",
borderBottom: "1px solid rgba(240,224,192,0.25)",
paddingBottom: "8px"
});
panel.appendChild(title);
const subtitle = document.createElement("div");
subtitle.textContent = `Whispers of your ties, sworn and broken.`;
Object.assign(subtitle.style, {
textAlign: "center",
opacity: "0.85",
marginBottom: "12px",
fontStyle: "italic",
fontSize: "0.98em"
});
panel.appendChild(subtitle);
const listWrap = document.createElement("div");
listWrap.id = "relationship-list";
listWrap.className = "rel-list";
listWrap.style.flex = "1";
listWrap.style.minHeight = "0";
panel.appendChild(listWrap);
// Public addCharacter API (can be called later)
this.addCharacter = function (opts) {
const key = String(opts.key || "").trim();
if (!key) return;
const name = String(opts.name || key);
const status = String(opts.status || "Unknown");
const affinity = String(opts.affinity ?? "Unknown");
const age = (opts.age ?? "—");
const profession = String(opts.profession ?? "—");
const weight = (opts.weight ?? "—");
const height = (opts.height ?? "—");
const race = String(opts.race ?? "—");
const row = document.createElement("div");
row.className = "rel-row";
row.setAttribute("data-relkey", key);
const left = document.createElement("div");
left.className = "rel-name";
left.textContent = name;
const right = document.createElement("div");
right.className = "rel-badge";
right.textContent = status;
const style = window.getRelationshipStyle(status);
if (typeof style === "object" && style !== null) {
if (style.className) right.classList.add(style.className);
else Object.assign(right.style, style);
} else {
right.style.color = style;
}
row.appendChild(left);
row.appendChild(right);
const details = document.createElement("div");
details.className = "rel-details";
details.setAttribute("data-relkey", key);
const hint = document.createElement("div");
hint.className = "rel-hint";
hint.textContent = "Vows, favors, betrayals:";
details.appendChild(hint);
const affClass = window.getAffinityClass(affinity);
const meta = document.createElement("div");
meta.className = "rel-meta";
meta.innerHTML = `
<div><b>Affinity:</b> <span class="${affClass}">${affinity}</span></div>
<div><b>Status:</b> ${status}</div>
<div><b>Age:</b> ${age}</div>
<div><b>Profession:</b> ${profession}</div>
<div><b>Height:</b> ${height}</div>
<div><b>Weight:</b> ${weight}</div>
<div><b>Race:</b> ${race}</div>
`;
details.appendChild(meta);
const wrap = document.createElement("div");
wrap.className = "rel-log-wrap";
details.appendChild(wrap);
setTimeout(() => RelationshipLog.refresh(key), 0);
row.addEventListener("click", () => {
const isOpen = details.classList.contains("open");
panel.querySelectorAll(".rel-details.open").forEach(d => d.classList.remove("open"));
if (!isOpen) {
details.classList.add("open");
RelationshipLog.refresh(key);
setTimeout(() => { wrap.scrollTop = wrap.scrollHeight; }, 0);
}
});
listWrap.appendChild(row);
listWrap.appendChild(details);
};
// ---- Characters ----
this.addCharacter({
key: "eldarion",
name: "Eldarion Bloomspell",
status: v.relStatusEldarion || "Father",
affinity: v.relAffinityEldarion ?? "Family",
age: v.relAgeEldarion ?? "749",
profession: v.relProfessionEldarion ?? "King",
height: v.relHeightEldarion ?? "1.76m - 5'9in",
weight: v.relWeightEldarion ?? "79kg - 167lbs",
race: v.relRaceEldarion ?? "Elf"
});
this.addCharacter({
key: "seralyth",
name: "Seralyth Bloomspell",
status: v.relStatusSeralyth || "Mother",
affinity: v.relAffinitySeralyth ?? "Family",
age: v.relAgeSeralyth ?? "329",
profession: v.relProfessionSeralyth ?? "Queen, Artist (Painter, Writer)",
height: v.relHeightSeralyth ?? "1.59m - 5'3in",
weight: v.relWeightSeralyth ?? "55kg - 121lbs",
race: v.relRaceSeralyth ?? "Elf"
});
this.addCharacter({
key: "caelthir",
name: "Caelthir Bloomspell",
status: v.relStatusCaelthir || "Brother",
affinity: v.relAffinityCaelthir ?? "Family",
age: v.relAgeCaelthir ?? "129",
profession: v.relProfessionCaelthir ?? "Prince, Overall Army Commander",
height: v.relHeightCaelthir ?? "1.82m - 6'0in",
weight: v.relWeightCaelthir ?? "83kg - 183lbs",
race: v.relRaceCaelthir ?? "Elf"
});
this.addCharacter({
key: "vaelorin",
name: "Vaelorin Bloomspell",
status: v.relStatusVaelorin || "Brother",
affinity: v.relAffinityVaelorin ?? "Family",
age: v.relAgeVaelorin ?? "106",
profession: v.relProfessionVaelorin ?? "Prince, Rangers Commander",
height: v.relHeightVaelorin ?? "1.81m - 6'0in",
weight: v.relWeightVaelorin ?? "72kg - 159lbs",
race: v.relRaceVaelorin ?? "Elf"
});
this.addCharacter({
key: "thalenwyr",
name: "Thalenwyr Bloomspell",
status: v.relStatusThalenwyr || "Brother",
affinity: v.relAffinityThalenwyr ?? "Family",
age: v.relAgeThalenwyr ?? "28",
profession: v.relProfessionThalenwyr ?? "Prince, Royal Scribe",
height: v.relHeightThalenwyr ?? "1.69m - 5'7in",
weight: v.relWeightThalenwyr ?? "62kg - 137lbs",
race: v.relRaceThalenwyr ?? "Elf"
});
this.addCharacter({
key: "aelara",
name: "Aelara Bloomspell",
status: v.relStatusAelara || "Me",
affinity: v.relAffinityAelara ?? "Family",
age: v.relAgeAelara ?? "18",
profession: v.relProfessionAelara ?? "Princess",
height: v.relHeightAelara ?? "1.47m - 4'10in",
weight: v.relWeightAelara ?? "40kg - 88lbs",
race: v.relRaceAelara ?? "Elf"
});
this.addCharacter({
key: "grayson",
name: "Grayson Silvariel",
status: v.relStatusGrayson || "Family's Friend",
affinity: v.relAffinityGrayson ?? "Friend",
age: v.relAgeGrayson ?? "1268",
profession: v.relProfessionGrayson ?? "High Chancellor",
height: v.relHeightGrayson ?? "1.68m - 5'6in",
weight: v.relWeightGrayson ?? "205kg - 452lbs",
race: v.relRaceGrayson ?? "Elf"
});
this.addCharacter({
key: "areothic",
name: "Areothic Umbravale",
status: v.relStatusAreothic || "King's First Warlord",
affinity: v.relAffinityAreothic ?? "None",
age: v.relAgeAreothic ?? "957",
profession: v.relProfessionAreothic ?? "Warlord",
height: v.relHeightAreothic ?? "1.90m - 6'3in",
weight: v.relWeightAreothic ?? "140kg - 308lbs",
race: v.relRaceAreothic ?? "Elf"
});
this.addCharacter({
key: "obbo",
name: "Obbo Gobbo",
status: v.relStatusObbo || "Family's Friend",
affinity: v.relAffinityObbo ?? "Friend",
age: v.relAgeObbo ?? "46",
profession: v.relProfessionObbo ?? "Royal Guard",
height: v.relHeightObbo ?? "3.22m - 10'6in",
weight: v.relWeightObbo ?? "813 kg - 1792lbs",
race: v.relRaceObbo ?? "Ogre"
});
this.addCharacter({
key: "kaeltharion",
name: "Kaeltharion Valecrest",
status: v.relStatusKaeltharion || "22nd Battalion Commander",
affinity: v.relAffinityKaeltharion ?? "None",
age: v.relAgeKaeltharion ?? "425",
profession: v.relProfessionKaeltharion ?? "Commander",
height: v.relHeightKaeltharion ?? "1.81m - 6'0in",
weight: v.relWeightKaeltharion ?? "87kg - 192lbs",
race: v.relRaceKaeltharion ?? "Elf"
});
const closeBtn = document.createElement("button");
closeBtn.textContent = "Seal";
Object.assign(closeBtn.style, {
marginTop: "16px",
width: "100%",
padding: "8px",
background: "rgba(42, 22, 11, 0.9)",
color: "#f0e0c0",
border: "1px solid rgba(240,224,192,0.3)",
borderRadius: "6px",
cursor: "pointer",
fontFamily: "inherit"
});
closeBtn.onclick = () => panel.remove();
panel.appendChild(closeBtn);
document.body.appendChild(panel);
}
};
<</script>>
/* ---- Logs (seed only once) ---- */
<<run RelationshipLogSeedOnce("RelationshipMenuLogs_v1", function () {
RelationshipLog.add("seralyth",
"Seralyth Bloomspell is the queen—mother to Aela and her brothers—and in the court she’s celebrated as a patron of beauty: a lover of paint and poetry, a collector of delicate verses, and the kind of noblewoman who can turn an afternoon salon into something that feels like a small, shining kingdom of its own. She often gathers with other ladies of rank who share the same passions, trading critiques of new canvases, reciting lines they’ve memorized, and speaking of “taste” the way generals speak of strategy."
);
RelationshipLog.add("seralyth",
"But beneath that refined surface, her devotion to art doesn’t always remain harmless. With Aelara, especially, Seralyth’s attention can take on an unsettling edge—less like a mother’s pride and more like a curator’s fixation. She has a habit of pushing boundaries under the cover of tradition, arranging “innocent” portraits that feel too revealing, choosing outfits and presentations that invite too many eyes, steering conversations so Aela becomes the centerpiece of scrutiny. It’s never stated outright, never obvious enough to be openly accused—yet it carries a quiet intent, as if she’s testing how far she can press before anyone dares to object. Seralyth’s dangerous flaw is that she confuses control with care, and “shaping” with love, seeking, in private ways, to reduce Aelara’s dignity into something she can display, correct, and possess.", "#C96526"
);
RelationshipLog.add("caelthir",
"Caelthir is the eldest son of King Eldarion. Aela’s protective eldest brother, raised with steel in his spine and duty in his blood. He lives for military success and strategic security, measuring every risk like a blade’s edge, because he believes a single weak link can doom an army. Honor guides him, but it’s his deep, instinctive need to keep Aela safe that truly drives his decisions, sometimes with a quiet tenderness, sometimes with a hard command that leaves no room for argument. Beneath that disciplined exterior, his fear is simple and relentless: failure on the field, and the moment when protection isn’t enough."
);
RelationshipLog.add("eldarion",
"Eldarion is the reigning king and patriarch of his line, father to Aelara, Caelthir, Vaelorin, and Thalenwyr, bound in marriage to Seralyn. He carries the kingdom the way a warlord carries armor: always present, always heavy, never set aside. His goal is simple in words and brutal in practice—protect the realm and secure its future, so every decision bends toward sovereignty, stability, and what will endure after he’s gone. He loves his family, but he loves the crown first; in his mind, blood and duty are entwined, and even his children are pieces on the board—precious, irreplaceable, and still meant to be played for the kingdom’s advantage. What he fears is not merely death, but defeat: the humiliation of a lost war, the collapse of his rule, and the moment when his name becomes a cautionary tale whispered in the halls he once commanded."
);
RelationshipLog.add("vaelorin",
"Vaelorin is another of Aela’s older brothers—an elite archer whose reputation was earned in silence and precision, and who now commands a handpicked unit of deadly bowmen. He carries himself with an intense, watchful edge that turns every room into a range he is quietly measuring. Around Aela, that intensity becomes something sharper: jealous, overprotective, and often infuriating—always present, always inserting himself, always convinced he knows what’s best for her. His attention lingers too long, his protectiveness crosses lines, and his need to “guard” her feels less like duty and more like possession. What drives him is a long-standing obsession with being the one closest to her, the one she relies on, the one no one can replace. And what he fears most is not an enemy’s arrow, but the moment he realizes she no longer needs him… or chooses someone else’s side."
);
RelationshipLog.add("thalenwyr",
"Thalenwyr Bloomspell is the youngest of Aelara’s older brothers—still a prince, still a Bloomspell, but softer at the edges than the others. He lives to carry out his father’s orders cleanly and without drama, not because he lacks conviction, but because obedience feels like the safest way to keep the family intact. Duty sits naturally on him, tempered by a gentle, protective instinct that shows in small, quiet ways: checking on Aela without making it a spectacle, standing between her and trouble before she even notices it, choosing patience where others choose command. What truly unsettles him isn’t bloodshed or battle, but the thought of Aela being harmed in ways that can’t be healed with medicine—her safety endangered, her name dragged through mud, her dignity stripped away and turned into someone else’s entertainment. He fears that kind of loss because he understands it personally: honor, once taken, doesn’t always return, and he would rather bear shame himself than watch it laid at her feet."
);
RelationshipLog.add("thalenwyr",
"Of all her brothers, Thalenwyr is the one Aelara is closest to—less a distant prince and more a constant presence at her side. Their bond was built in quiet hours and shared confidences: Small jokes traded under breath, long talks that never needed an audience, and the kind of companionship that feels effortless because it’s real. With him, Aelara can drop the crown’s weight for a moment and simply be herself, and Thalenwyr meets her there without judgment, only warmth. They move like true friends who trust each other completely, but the truth runs deeper than friendship—he loves her with a fierce, devoted sincerity, and she loves him back with the same unquestioning certainty, the kind that doesn’t need to be proven because it’s always been there."
);
RelationshipLog.add("areothic",
"Areothic Umbravale, known as the King’s First Warlord is the kind of commander soldiers obey before they even understand why. He serves beneath the crown, yet moves with the authority of someone who has bled for every inch of that trust, and he is feared not for cruelty alone, but for how calmly he wields it. His goal is always military victory and the firm grip of control that follows it; Battles, borders, and men are problems to be solved, not stories to be told. Ruthless efficiency is his creed, waste nothing, hesitate never, remove obstacles the moment they reveal themselves. Behind that iron discipline sits a single obsession that keeps his standards sharp as a drawn blade: the terror of incompetence, of being outplayed, out-thought, outmaneuvered, and watching the world realize he was never as formidable as his reputation."
);
RelationshipLog.add("grayson",
"Grayson Silvariel is an old noble of a venerable elven house—lord of long-running feuds, a famed merchant-prince whose caravans and contracts have fattened his vaults for centuries. In court he plays the indispensable ally: the man who “makes the ink flow,” untangling bureaucracy for King Eldarion, buying favors with ledgers and shipments, smoothing disputes with gold, and turning delays into quiet advantages. Publicly, he is polished, patient, and loyal—an elder statesman with a courteous smile and a voice that can make orders sound like advice."
);
RelationshipLog.add("grayson",
"Privately, the rot runs deep. Beneath the silk and ceremony, Grayson hides a predatory hunger for youth, one that sharpens most dangerously around young women—especially Princess Aelara, who draws his attention like a blade drawn from its sheath. His ambition is a three-headed thing: greed for more influence, a yearning to preserve himself against time’s slow cruelty, and the craving to climb higher within the king’s shadow without ever appearing to reach. He tells himself his loyalty is real—and perhaps it is, because the crown is the safest place to feed his schemes.", "#ff7a7a"
);
RelationshipLog.add("grayson",
"What he fears isn’t scandal or swords, but the quiet certainty of decay: death by aging, the humiliation of withering, the terror of becoming irrelevant. And that fear is exactly what makes him patient, calculating… and relentless."
);
RelationshipLog.add("obbo",
"Obbo Gobbo is an ogre most would fear at first glance—towering, broad as a doorway, built like a walking rampart—but he’s also the rare kind of creature whose presence makes danger feel smaller. Among elves, trust in other races is uncommon, especially trust given so close to the royal bloodline. Yet Obbo earned it the hard way, day by day, choice by choice, until caution softened into certainty. He proved himself not only loyal, but reliable, the kind of guard who cannot be bribed, who doesn’t crave power, who refuses cruelty, and who would rather take a blade in silence than let one reach the royal family. That unwavering steadiness, paired with a growing fondness and protective instinct, made him more than an assigned escort. In time, the royal family stopped seeing him as “the ogre guard” and began treating him as what he had quietly become, an outsider taken in as a true friend of the crown, fiercely devoted, fiercely trustworthy, and impossible to replace."
);
})>>
/*----- Conditional logs -----*/
<<if $motherStoryOne == 1>>
<<run RelationshipLogSeedOnce("RelationshipMenuLogs_v2", function () {
RelationshipLog.add("seralyth", "Her central goal is to live vicariously through her daughter by personally arranging and directing Aela's sexual exploitation. She does not merely permit it—she actively designs, stages, and oversees the scenarios in which Aela is used.", "#ff7a7a");
RelationshipLog.add("seralyth", "What drives her is a deep, incestuous obsession. She becomes powerfully aroused by the knowledge, and often the direct witnessing, of her daughter's degradation. To the Queen, Aela's systematic humiliation and sexual submission are not crimes or tragedies; they are a form of living art, a perfected expression of beauty, and—most crucially—Aela's true and inevitable destiny.", "#ff7a7a");
})>>
<</if>>
<<if $obboStoryOne == 1>>
<<run RelationshipLogSeedOnce("RelationshipMenuLogs_v3", function () {
RelationshipLog.add("obbo",
"Assigned as Aela’s personal guard, he treats her safety as sacred work: He watches every shadow, counts every exit, and positions himself between her and the world without ever needing to be asked. His loyalty isn’t loud or showy, it’s constant, shown in the way he keeps his temper chained, follows orders to the letter, and stands through cold nights without complaint, simply because that is his duty." , "#C9FCB6"
);
})>>
<</if>>
<<if $vaelStoryOne == 1>>
<<run RelationshipLogSeedOnce("RelationshipMenuLogs_v4", function () {
RelationshipLog.add("vaelorin",
"To him, Aelara is not merely desirable, she is the one thing he has ever truly wanted that no battlefield victory or royal title could replace. The incestuous nature of his longing is not a source of shame, it is the very core of its intensity." , "#ff7a7a"
);
})>>
<</if>>
/* ---- Open ---- */
<<run RelationshipPanel.open()>>
<<setBG 1 setup.ImagePath 'cgs/mainmenu/1.png'>>
<<nobr>>
<!-- ===================== HTML ====================== -->
<div id="main-menu-container">
<div class="mm-title">
<span class="mm-title__crown">✦</span>
<span class="mm-title__word">Elliahal</span>
<span class="mm-title__crown">✦</span>
<div class="mm-subtitle">Chronicles of the Bloomspell</div>
</div>
<div class="mm-buttons">
<button class="mm-btn" onclick="SugarCube.Engine.play('Intro War Camp')">
<span class="mm-btn__icon">⚔</span><span class="mm-btn__text">New Game</span>
</button>
<button class="mm-btn" onclick="SugarCube.UI.saves()">
<span class="mm-btn__icon">⛨</span><span class="mm-btn__text">Load Game</span>
</button>
<button class="mm-btn" onclick="SugarCube.Engine.play('Changelog')">
<span class="mm-btn__icon">✎</span><span class="mm-btn__text">Changelog</span>
</button>
<button class="mm-btn" onclick="SugarCube.Engine.play('Configurations')">
<span class="mm-btn__icon">⚙</span><span class="mm-btn__text">Configurations</span>
</button>
<button class="mm-btn" onclick="SugarCube.Engine.play('Roadmap')">
<span class="mm-btn__icon">✦</span><span class="mm-btn__text">About / Roadmap</span>
</button>
<button class="mm-btn" onclick="window.open('https://www.patreon.com/Afeell', '_blank')">
<span class="mm-btn__icon">❖</span><span class="mm-btn__text">Patreon</span>
</button>
</div>
</div>
<!-- ====================== CSS ====================== -->
<style>
/* Reset possible Twine margins */
#passages { margin: 0 !important; padding: 0 !important; }
/* Fullscreen flex center */
#main-menu-container{
position: fixed;
top: 0; left: 0;
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 9999;
text-align: center;
color: rgba(240,224,192,0.96);
/* medieval veil */
background: radial-gradient(circle at 50% 45%,
rgba(0,0,0,0.18) 0%,
rgba(0,0,0,0.35) 38%,
rgba(0,0,0,0.58) 100%
);
backdrop-filter: blur(1.5px);
}
/* Title */
.mm-title{
margin-bottom: 1.35em;
text-shadow:
0 2px 10px rgba(0,0,0,0.65),
0 0 24px rgba(0,0,0,0.35);
}
.mm-title__word{
font-family: "Cinzel", "Uncial Antiqua", "Palatino Linotype", "Book Antiqua", serif;
font-size: clamp(2.4rem, 6vw, 4.4rem);
font-weight: 700;
letter-spacing: 3px;
text-transform: uppercase;
color: rgba(255,221,160,0.98);
}
.mm-title__crown{
font-family: "Cinzel", "Uncial Antiqua", serif;
font-size: clamp(1.3rem, 3.2vw, 2.2rem);
opacity: 0.9;
color: rgba(240,224,192,0.92);
margin: 0 0.35rem;
}
.mm-subtitle{
margin-top: 0.35rem;
font-family: "Cinzel", "Palatino Linotype", serif;
font-size: clamp(0.95rem, 2vw, 1.05rem);
letter-spacing: 1px;
opacity: 0.86;
}
/* Buttons container */
.mm-buttons{
display: flex;
flex-direction: column;
gap: 0.95rem;
width: 86%;
max-width: 280px;
}
/* Buttons base */
.mm-btn{
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.65rem;
padding: 0.95em 1.05em;
border-radius: 10px;
font-size: clamp(1rem, 2vw, 1.15rem);
font-family: "Cinzel", "Uncial Antiqua", "Palatino Linotype", "Book Antiqua", serif;
font-weight: 700;
letter-spacing: 1.2px;
text-transform: uppercase;
cursor: pointer;
user-select: none;
color: rgba(240,224,192,0.96);
border: 1px solid rgba(240,224,192,0.22);
background:
linear-gradient(to bottom, rgba(74,47,27,0.78), rgba(47,28,17,0.72));
box-shadow:
inset 0 0 18px rgba(0,0,0,0.35),
0 8px 18px rgba(0,0,0,0.35);
transition: transform 180ms ease, box-shadow 220ms ease, border-color 220ms ease, filter 220ms ease;
}
/* subtle carved bevel */
.mm-btn::before{
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
pointer-events: none;
box-shadow:
inset 0 1px 0 rgba(255,255,255,0.06),
inset 0 -1px 0 rgba(0,0,0,0.35);
opacity: 0.9;
}
/* Hover */
.mm-btn:hover{
transform: translateY(-2px);
border-color: rgba(255,221,160,0.42);
box-shadow:
inset 0 0 22px rgba(0,0,0,0.35),
0 10px 22px rgba(0,0,0,0.45),
0 0 18px rgba(214,181,110,0.18);
filter: brightness(1.06);
}
/* Icons */
.mm-btn__icon{
font-size: 1.05em;
opacity: 0.95;
text-shadow: 0 0 10px rgba(0,0,0,0.35);
}
.mm-btn__text{ transform: translateY(0.5px); }
/* -------- About / Roadmap (medieval-flashy but clean) -------- */
.mm-btn--pitch{
border-color: rgba(214,181,110,0.40);
background:
linear-gradient(90deg, rgba(214,181,110,0.14), rgba(47,28,17,0.74)),
linear-gradient(to bottom, rgba(74,47,27,0.78), rgba(47,28,17,0.72));
}
.mm-btn--pitch .mm-btn__label{
position: relative;
z-index: 2;
display: inline-flex;
align-items: center;
gap: 0.65rem;
}
/* rune sweep */
.mm-btn--pitch .mm-btn__rune{
position: absolute;
top: -35%;
left: -70%;
width: 65%;
height: 180%;
transform: rotate(18deg);
pointer-events: none;
opacity: 0.9;
background: linear-gradient(90deg,
transparent,
rgba(255,221,160,0.22),
rgba(255,255,255,0.10),
transparent
);
filter: blur(0.2px);
transition: left 700ms ease;
}
.mm-btn--pitch:hover{
box-shadow:
inset 0 0 22px rgba(0,0,0,0.35),
0 10px 22px rgba(0,0,0,0.45),
0 0 22px rgba(214,181,110,0.22);
}
.mm-btn--pitch:hover .mm-btn__rune{ left: 130%; }
/* Mobile adjustments */
@media (max-width: 480px){
.mm-buttons{ max-width: 230px; }
.mm-btn{ padding: 0.82em 0.95em; }
}
</style>
<</nobr>>
<<nobr>>
<<setBG 1 setup.ImagePath ''>>
<style>
/* restore passage spacing */
#passages { margin: 0 !important; padding: 0 !important; }
/* === CONFIG SCREEN WRAPPER === */
.config-screen {
position: fixed;
inset: 0;
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
padding: 2rem 1rem;
color: rgba(240,224,192,0.96);
background: radial-gradient(circle at 50% 45%,
rgba(0,0,0,0.18) 0%,
rgba(0,0,0,0.35) 38%,
rgba(0,0,0,0.58) 100%
);
backdrop-filter: blur(1.5px);
}
/* === MAIN PANEL === */
.config-root {
width: min(92vw, 760px);
max-height: 84vh;
overflow-y: auto;
overflow-x: hidden;
padding: 1.4rem 1.35rem 1.25rem;
border-radius: 14px;
color: rgba(240,224,192,0.96);
font-family: "Palatino Linotype", "Book Antiqua", serif;
border: 1px solid rgba(240,224,192,0.18);
background:
linear-gradient(to bottom, rgba(74,47,27,0.82), rgba(47,28,17,0.78));
box-shadow:
inset 0 0 24px rgba(0,0,0,0.32),
0 14px 32px rgba(0,0,0,0.45);
}
/* carved bevel */
.config-root::before {
content: "";
position: absolute;
pointer-events: none;
}
/* scrollbar */
.config-root::-webkit-scrollbar {
width: 8px;
}
.config-root::-webkit-scrollbar-track {
background: rgba(20,12,8,0.65);
border-radius: 8px;
}
.config-root::-webkit-scrollbar-thumb {
background: rgba(214,181,110,0.55);
border-radius: 8px;
border: 1px solid rgba(255,221,160,0.18);
}
.config-root::-webkit-scrollbar-thumb:hover {
background: rgba(255,221,160,0.72);
}
/* === TITLE AREA === */
.config-title-wrap {
text-align: center;
margin-bottom: 1.2rem;
text-shadow:
0 2px 10px rgba(0,0,0,0.65),
0 0 24px rgba(0,0,0,0.35);
}
.config-title {
font-family: "Cinzel", "Uncial Antiqua", "Palatino Linotype", serif;
font-size: clamp(1.9rem, 4vw, 2.6rem);
font-weight: 700;
letter-spacing: 2px;
text-transform: uppercase;
color: rgba(255,221,160,0.98);
}
.config-sub {
margin-top: 0.3rem;
font-family: "Cinzel", "Palatino Linotype", serif;
font-size: 0.92rem;
letter-spacing: 0.8px;
opacity: 0.84;
color: rgba(240,224,192,0.9);
}
/* === SECTION CARD === */
.config-card {
margin-top: 1rem;
padding: 1rem 1rem 1.1rem;
border-radius: 12px;
border: 1px solid rgba(240,224,192,0.14);
background:
linear-gradient(to bottom, rgba(62,38,22,0.62), rgba(33,19,12,0.52));
box-shadow:
inset 0 0 18px rgba(0,0,0,0.28),
0 8px 18px rgba(0,0,0,0.22);
}
.config-section-title {
font-family: "Cinzel", "Palatino Linotype", serif;
font-size: 1rem;
font-weight: 700;
letter-spacing: 1px;
text-transform: uppercase;
margin-bottom: 0.7rem;
color: rgba(255,221,160,0.95);
}
/* === BUTTONS === */
.config-btn {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.55rem;
padding: 0.82em 1.1em;
border-radius: 10px;
margin-bottom: 0.8rem;
font-size: 0.98rem;
font-family: "Cinzel", "Uncial Antiqua", "Palatino Linotype", serif;
font-weight: 700;
letter-spacing: 1px;
text-transform: uppercase;
cursor: pointer;
user-select: none;
color: rgba(240,224,192,0.96);
border: 1px solid rgba(240,224,192,0.22);
background:
linear-gradient(to bottom, rgba(74,47,27,0.78), rgba(47,28,17,0.72));
box-shadow:
inset 0 0 18px rgba(0,0,0,0.35),
0 8px 18px rgba(0,0,0,0.35);
transition: transform 180ms ease, box-shadow 220ms ease, border-color 220ms ease, filter 220ms ease;
}
.config-btn::before {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
pointer-events: none;
box-shadow:
inset 0 1px 0 rgba(255,255,255,0.06),
inset 0 -1px 0 rgba(0,0,0,0.35);
opacity: 0.9;
}
.config-btn:hover {
transform: translateY(-2px);
border-color: rgba(255,221,160,0.42);
box-shadow:
inset 0 0 22px rgba(0,0,0,0.35),
0 10px 22px rgba(0,0,0,0.45),
0 0 18px rgba(214,181,110,0.18);
filter: brightness(1.06);
}
/* === VOLUME WRAPPER === */
.volume-wrapper {
margin-top: 0.4rem;
padding: 0.95rem 0.95rem 1rem;
border-radius: 12px;
border: 1px solid rgba(240,224,192,0.14);
background:
linear-gradient(to bottom, rgba(62,38,22,0.62), rgba(33,19,12,0.52));
box-shadow:
inset 0 0 14px rgba(0,0,0,0.32);
}
.volume-label {
font-family: "Cinzel", "Palatino Linotype", serif;
font-size: 0.95rem;
letter-spacing: 0.6px;
margin-bottom: 0.55rem;
color: rgba(240,224,192,0.9);
}
/* === SLIDER === */
input[type=range].volume-slider {
-webkit-appearance: none;
appearance: none;
width: calc(100% - 6px);
margin-right: 3px;
height: 10px;
border-radius: 999px;
outline: none;
cursor: pointer;
border: 1px solid rgba(255,221,160,0.25);
background: linear-gradient(90deg, rgba(214,181,110,0.95) 0%, rgba(30,18,12,0.95) 0%);
box-shadow:
inset 0 0 10px rgba(0,0,0,0.45),
0 1px 0 rgba(255,255,255,0.04);
}
input[type=range].volume-slider::-webkit-slider-thumb {
-webkit-appearance: none;
width: 18px;
height: 18px;
border-radius: 50%;
background: rgba(255,221,160,0.98);
border: 1px solid rgba(90,58,30,0.85);
box-shadow:
0 0 10px rgba(214,181,110,0.35),
0 2px 6px rgba(0,0,0,0.4);
cursor: pointer;
}
input[type=range].volume-slider::-moz-range-thumb {
width: 18px;
height: 18px;
border-radius: 50%;
background: rgba(255,221,160,0.98);
border: 1px solid rgba(90,58,30,0.85);
box-shadow:
0 0 10px rgba(214,181,110,0.35),
0 2px 6px rgba(0,0,0,0.4);
cursor: pointer;
}
/* === RETURN AREA === */
.return-container {
margin-top: 1.2rem;
display: flex;
justify-content: center;
}
/* mobile */
@media (max-width: 480px){
.config-root {
padding: 1rem 0.9rem 1rem;
}
.config-btn {
width: 100%;
}
}
</style>
<div class="config-screen">
<div class="config-root">
<div class="config-title-wrap">
<div class="config-title">Configurations</div>
<div class="config-sub">Gameplay preferences. - Audio still not implemented.</div>
</div>
<div class="config-card">
<div class="config-section-title">Sound</div>
<<if !$soundEnabled>>
<button class="config-btn" onclick="window.enableGameSound()">
Enable Sounds
</button>
<<else>>
<button class="config-btn" onclick="window.disableGameSound()">
Disable Sounds
</button>
<</if>>
</div>
<div class="config-card">
<div class="config-section-title">Master Audio</div>
<div class="volume-wrapper">
<div class="volume-label">Master Volume: <span id="volume-display"></span>%</div>
<input id="volume-slider" class="volume-slider" type="range" min="0" max="100" value="100">
</div>
</div>
<div class="return-container">
<button class="config-btn" onclick="SugarCube.Engine.play('Main Menu')">
Save and Return
</button>
</div>
</div>
</div>
<</nobr>>
<<script>>
/* Restore scrolling only on this page */
$('html, body').css('overflow', 'auto');
$(document).one(':passageend', () => {
$('html, body').css('overflow', 'hidden');
});
/* SOUND TOGGLES */
window.enableGameSound = function() {
State.variables.soundEnabled = true;
SugarCube.Engine.play("Configurations");
};
window.disableGameSound = function() {
State.variables.soundEnabled = false;
if (window.mainMenuMusic)
window.mainMenuMusic.stop();
SugarCube.Engine.play("Configurations");
};
/* ============================
VOLUME SLIDER SYSTEM
===============================*/
$(document).one(':passagedisplay', function () {
const slider = document.getElementById("volume-slider");
const display = document.getElementById("volume-display");
if (!slider || !display) return;
if (State.variables.masterVolume == null) {
State.variables.masterVolume = 100;
}
slider.value = State.variables.masterVolume;
display.textContent = slider.value;
slider.style.background =
`linear-gradient(90deg, rgba(214,181,110,0.95) ${slider.value}%, rgba(30,18,12,0.95) ${slider.value}%)`;
slider.addEventListener("input", () => {
State.variables.masterVolume = Number(slider.value);
display.textContent = slider.value;
slider.style.background =
`linear-gradient(90deg, rgba(214,181,110,0.95) ${slider.value}%, rgba(30,18,12,0.95) ${slider.value}%)`;
if (window.currentMusic) {
window.currentMusic.volume = slider.value / 100;
}
});
});
<</script>><<runScenario "princesstentbed" "Body_LegsUp">><<runScenario "princesstentbed" "Body_LegsUp2">><<runScenario "princesstentbed" "Body_LayDownKneesUp">><<runScenario "warcamp/areothic1.jpg" "cg" "Body_Covering">>
<<comic "areothic_river_confrontation" "Lake Bathe WarlordIntro_Choices">>
<<runScenario "warcamp/areothic2.jpg" "cg" "Body_LayDownKneesUp">>
<<comic "areothic_river_confrontation_defy2" "Lake Bathe WarlordIntro Him Undressing1">>
<<run $datenow.setMinutes($datenow.getMinutes() + 20)>><<set $chestSlot to "">>
<<runScenario "warcamp/areothic1.jpg" "cg">>
<<comic "areothic_river_confrontation_comply" "Lake Bathe WarlordIntro_Uncover2">>
<<runScenario "warcamp/areothic1.jpg" "cg" "Body_Covering">>
<<run openConversation("areothic_river_confrontation")>>
<<runScenario "warcamp/areothic1.jpg" "cg" "Body_Covering">>
<<comic "areothic_river_confrontation_explain" "Lake Bathe WarlordIntro_Choices2">><<runScenario "warcamp/areothic1.jpg" "cg" "Body_Covering">>
<<comic "areothic_river_confrontation_order" "Lake Bathe WarlordIntro_Choices2">><<runScenario "warcamp/areothic1.jpg" "cg" "Body_Covering">>
<<comic "areothic_river_confrontation_blackmail" "Lake Bathe WarlordIntro_Demands">>
<<runScenario "warcamp/areothic1.jpg" "cg" "Body_Covering">>
<<comic "areothic_river_confrontation_defy" "Lake Bathe WarlordIntro_Cover2">><<runScenario "warcamp/areothic1.jpg" "cg" "Body_Covering">>
<<comic "areothic_river_confrontation_demands" "Lake Bathe WarlordIntro_Demands_UncoverOrDont">>
<<runScenario "warcamp/areothic1.jpg" "cg" "Body_Covering">>
<<run openConversation("areothic_river_confrontation_uncoverordont")>>
<<set $chestSlot to "">>
<<runScenario "warcamp/areothic1.jpg" "cg">>
<<run openConversation("areothic_river_confrontation_laydownwilling")>><<runScenario "warcamp/areothic2.jpg" "cg" "Body_LayDownKneesUp">>
<<goto "Lake Bathe WarlordIntro Him Undressing1">>
<<run $datenow.setMinutes($datenow.getMinutes() + 20)>><<runScenario "warcamp/areothic2.jpg" "cg" "Body_LayDownKneesUp">>
<<script>>
$(document).one(':passageend', function () {
setTimeout(function () {
new Wikifier(null, '<<PushForwardFX>>');
}, 500);
});
<</script>>
<<run openConversation("areothic_river_confrontation_pushed")>><<runScenario "warcamp/areothic2.jpg" "cg" "Body_LayDownKneesUp">>
<<comic "areothic_river_confrontation_him_undressing1" "Lake Bathe WarlordIntro Him Undressing2">>
<<run $datenow.setMinutes($datenow.getMinutes() + 16)>>
<<run DickHistory.add("dick1", "18cm - 7.8in", "254 Thrusts", "Vaginal", "18ml", $formattedDateNow, "Areothic")>><<comic "areothic_river_confrontation_him_undressing2" "Lake Bathe WarlordIntro_Violation1">>
<<run $datenow.setMinutes($datenow.getMinutes() + 14)>>
<<run DickHistory.add("dick1", "18cm - 7.8in", "423 Thrusts", "Vaginal", "18ml", $formattedDateNow, "Areothic")>><<runScenario "warcamp/sex.jpg" "cg" "nobody">>
<<comic "areothic_river_confrontation_violation1" "Lake Bathe WarlordIntro_Violation2">>
<<run DickHistory.add("dick1", "18cm - 7.8in", "314 Thrusts", "Vaginal", "21ml", $formattedDateNow, "Areothic")>><<runScenario "warcamp/sex.jpg" "cg" "nobody">>
<<comic "areothic_river_confrontation_violation2" "Lake Bathe WarlordIntro_Violation3">>
<<script>>
$(document).one(':passageend', function () {
// stop any previous loop (avoid stacking intervals)
if (window._pushFxLoop) {
clearInterval(window._pushFxLoop);
window._pushFxLoop = null;
}
window._pushFxLoop = setInterval(function () {
new Wikifier(null, '<<PushForwardFX>>');
}, 500);
});
<</script>>
<<run $datenow.setMinutes($datenow.getMinutes() + 19)>><<runScenario "warcamp/sex.jpg" "cg" "nobody">>
<<comic "areothic_river_confrontation_struggle" "Lake Bathe WarlordIntro_Violation4">>
<<script>>
$(document).one(':passageend', function () {
// stop any previous loop (avoid stacking intervals)
if (window._pushFxLoop) {
clearInterval(window._pushFxLoop);
window._pushFxLoop = null;
}
window._pushFxLoop = setInterval(function () {
new Wikifier(null, '<<PushForwardFX>>');
}, 500);
});
<</script>>
<<run $datenow.setMinutes($datenow.getMinutes() + 25)>>
<<run DickHistory.add("dick1", "18cm - 7.8in", "414 Thrusts", "Vaginal", "14ml", $formattedDateNow, "Areothic")>>
<<runScenario "warcamp/sex.jpg" "cg" "nobody">>
<<comic "areothic_river_confrontation_climax" "Lake Bathe WarlordIntro_Violation5">>
<<script>>
$(document).one(':passageend', function () {
// stop any previous loop (avoid stacking intervals)
if (window._pushFxLoop) {
clearInterval(window._pushFxLoop);
window._pushFxLoop = null;
}
window._pushFxLoop = setInterval(function () {
new Wikifier(null, '<<PushForwardFX>>');
}, 200);
});
<</script>>
<<run $datenow.setMinutes($datenow.getMinutes() + 25)>>
<<run DickHistory.add("dick1", "18cm - 7.8in", "397 Thrusts", "Vaginal", "9ml", $formattedDateNow, "Areothic")>><<set $wifeCurrentCumVagina++>>
<<runScenario "warcamp/sex.jpg" "cg" "nobody">>
<<comic "areothic_river_confrontation_climax2" "Lake Bathe WarlordIntro_Violation6">>
<<script>>
$(document).one(':passageend', function () {
// stop any previous loop (avoid stacking intervals)
if (window._pushFxLoop) {
clearInterval(window._pushFxLoop);
window._pushFxLoop = null;
}
window._pushFxLoop = setInterval(function () {
new Wikifier(null, '<<PushForwardFX>>');
}, 1500);
});
<</script>><<runScenario "warcamp/sex.jpg" "cg" "nobody">>
<<comic "areothic_river_confrontation_climax3" "Lake Bathe WarlordIntro_Violation7">>
<<runScenario "warcamp/sex.jpg" "cg" "nobody">>
<<run openConversation("areothic_river_confrontation_violated")>>
<<script>>
$(document).one(':passageend', function () {
// stop any previous loop (avoid stacking intervals)
if (window._pushFxLoop) {
clearInterval(window._pushFxLoop);
window._pushFxLoop = null;
}
window._pushFxLoop = setInterval(function () {
new Wikifier(null, '<<PushForwardFX>>');
}, 500);
});
<</script>><<run openConversation("areothic_river_confrontation_end1")>>
<<set $chestSlot to "Elven Dress 6">>
<<runScenario "warcamp/areothic3.jpg" "cg" >>
<<run openConversation("areothic_river_confrontation_end2")>>
<<run openConversation("areothic_river_confrontation_end3")>>
<<set $wifeCurrentCumVagina to ($wifeCurrentCumVagina + 5)>>
<<run $datenow.setMinutes($datenow.getMinutes() + 73)>>
<<runScenario "princesstentnight">><<setBG 1 setup.ImagePath ''>>
<style>
#passages { margin: 0 !important; padding: 0 !important; }
/* fullscreen centering, no panel background */
.changelog-screen {
position: fixed;
inset: 0;
z-index: 9999;
display: flex;
justify-content: center;
align-items: center;
padding: 1.5rem 1rem;
}
/* === ROOT === */
.changelog-root {
width: min(92vw, 900px);
height: 85vh;
overflow-y: auto;
overflow-x: hidden;
padding: 1.8rem 1.4rem 1.5rem;
color: rgba(240,224,192,0.96);
font-family: "Palatino Linotype", "Book Antiqua", serif;
text-shadow:
0 2px 10px rgba(0,0,0,0.55),
0 0 18px rgba(0,0,0,0.22);
}
/* scrollbar */
.changelog-root::-webkit-scrollbar {
width: 8px;
}
.changelog-root::-webkit-scrollbar-track {
background: rgba(20,12,8,0.55);
border-radius: 8px;
}
.changelog-root::-webkit-scrollbar-thumb {
background: rgba(214,181,110,0.55);
border-radius: 8px;
border: 1px solid rgba(255,221,160,0.18);
}
.changelog-root::-webkit-scrollbar-thumb:hover {
background: rgba(255,221,160,0.72);
}
/* === RETURN BUTTON === */
.return-container {
text-align: left;
margin-bottom: 0.9rem;
}
.return-container button {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.72em 1.05em;
border-radius: 10px;
font-size: 0.92rem;
font-family: "Cinzel", "Uncial Antiqua", "Palatino Linotype", serif;
font-weight: 700;
letter-spacing: 1px;
text-transform: uppercase;
cursor: pointer;
user-select: none;
color: rgba(240,224,192,0.96);
border: 1px solid rgba(240,224,192,0.22);
background:
linear-gradient(to bottom, rgba(74,47,27,0.78), rgba(47,28,17,0.72));
box-shadow:
inset 0 0 18px rgba(0,0,0,0.35),
0 8px 18px rgba(0,0,0,0.35);
transition: transform 180ms ease, box-shadow 220ms ease, border-color 220ms ease, filter 220ms ease;
}
.return-container button::before {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
pointer-events: none;
box-shadow:
inset 0 1px 0 rgba(255,255,255,0.06),
inset 0 -1px 0 rgba(0,0,0,0.35);
}
.return-container button:hover {
transform: translateY(-2px);
border-color: rgba(255,221,160,0.42);
box-shadow:
inset 0 0 22px rgba(0,0,0,0.35),
0 10px 22px rgba(0,0,0,0.45),
0 0 18px rgba(214,181,110,0.18);
filter: brightness(1.06);
}
/* === HEADER === */
.changelog-title {
font-family: "Cinzel", "Uncial Antiqua", "Palatino Linotype", serif;
font-size: clamp(2rem, 4vw, 2.8rem);
font-weight: 700;
letter-spacing: 2px;
text-transform: uppercase;
color: rgba(255,221,160,0.98);
margin-bottom: 0.2rem;
}
.changelog-sub {
font-family: "Cinzel", "Palatino Linotype", serif;
font-size: 0.9rem;
letter-spacing: 0.8px;
opacity: 0.84;
margin-bottom: 0.9rem;
color: rgba(240,224,192,0.9);
}
.changelog-version-pill {
display: inline-block;
margin-bottom: 1rem;
padding: 0.28rem 0.75rem;
border-radius: 999px;
font-size: 0.72rem;
font-family: "Cinzel", "Palatino Linotype", serif;
font-weight: 700;
letter-spacing: 0.8px;
text-transform: uppercase;
color: rgba(46,24,10,0.96);
background: rgba(255,221,160,0.92);
box-shadow:
0 4px 10px rgba(0,0,0,0.28),
0 0 10px rgba(214,181,110,0.18);
}
/* === ENTRY === */
.cl-entry {
border: 1px solid rgba(240,224,192,0.14);
border-radius: 12px;
padding: 0.75rem 0.85rem;
margin-bottom: 0.8rem;
cursor: pointer;
background:
linear-gradient(to bottom, rgba(62,38,22,0.58), rgba(33,19,12,0.48));
box-shadow:
inset 0 0 16px rgba(0,0,0,0.24),
0 8px 18px rgba(0,0,0,0.20);
transition: transform 0.16s ease, border-color 0.16s ease, box-shadow 0.18s ease, filter 0.18s ease;
}
.cl-entry:hover {
transform: translateY(-1px);
border-color: rgba(255,221,160,0.28);
box-shadow:
inset 0 0 16px rgba(0,0,0,0.24),
0 10px 20px rgba(0,0,0,0.26),
0 0 14px rgba(214,181,110,0.12);
filter: brightness(1.03);
}
.cl-entry-header {
display: flex;
justify-content: space-between;
align-items: center;
gap: 1rem;
}
.cl-entry-version {
font-family: "Cinzel", "Palatino Linotype", serif;
font-weight: 700;
color: rgba(255,221,160,0.96);
}
.cl-entry-date {
font-size: 0.76rem;
opacity: 0.72;
color: rgba(240,224,192,0.88);
}
.cl-entry-chevron {
font-size: 0.72rem;
opacity: 0.72;
transition: transform 0.2s ease;
color: rgba(255,221,160,0.9);
}
/* === BODY === */
.cl-entry-body {
margin-top: 0.45rem;
font-size: 0.88rem;
line-height: 1.4;
max-height: 0;
overflow: hidden;
opacity: 0;
transition: max-height 0.22s ease, opacity 0.22s ease;
color: rgba(240,224,192,0.94);
}
.cl-entry.is-open .cl-entry-body {
max-height: 340px;
opacity: 1;
overflow-y: auto;
}
.cl-entry.is-open .cl-entry-chevron {
transform: rotate(90deg);
}
.cl-entry-body::-webkit-scrollbar {
width: 6px;
}
.cl-entry-body::-webkit-scrollbar-track {
background: rgba(20,12,8,0.5);
border-radius: 8px;
}
.cl-entry-body::-webkit-scrollbar-thumb {
background: rgba(214,181,110,0.48);
border-radius: 8px;
}
.cl-entry-body ul {
padding-left: 1.1rem;
margin: 0.25rem 0;
}
.cl-entry-body li {
margin-bottom: 0.3rem;
}
/* badges */
.cl-badge {
display: inline-block;
font-size: 0.62rem;
padding: 0.12rem 0.38rem;
border-radius: 999px;
margin-right: 0.35rem;
text-transform: uppercase;
font-family: "Cinzel", "Palatino Linotype", serif;
font-weight: 700;
letter-spacing: 0.7px;
border: 1px solid;
background: rgba(0,0,0,0.14);
}
.cl-badge.new {
border-color: rgba(255,221,160,0.85);
color: rgba(255,221,160,0.96);
}
.cl-badge.fix {
border-color: rgba(214,181,110,0.9);
color: rgba(214,181,110,0.96);
}
.cl-badge.qol {
border-color: rgba(240,224,192,0.75);
color: rgba(240,224,192,0.92);
}
.cl-badge.sys {
border-color: rgba(196,176,140,0.7);
color: rgba(196,176,140,0.9);
}
</style>
<div class="changelog-screen">
<div class="changelog-root">
<div class="return-container">
<<button "Return" "toReturn">>
<<goto "Main Menu">>
<</button>>
</div>
<div class="changelog-title">Changelog</div>
<div class="changelog-sub">Recent updates, fixes and changes.</div>
<div class="changelog-version-pill">Current Version: v0.0.3</div>
<div class="cl-entry is-open">
<div class="cl-entry-header">
<span>
<span class="cl-entry-version">v0.0.3</span> –
<span class="cl-entry-date">27-mar-2026</span>
</span>
<span class="cl-entry-chevron">▶</span>
</div>
<div class="cl-entry-body">
<ul>
<li><span class="cl-badge new">QOL</span> Fixed some coding that were delaying the sexlog counters after huge amounts were add to it.</li>
<li><span class="cl-badge new">New</span> Added segment of the main story (Aetherial Dream).</li>
<li><span class="cl-badge new">New</span> Added support for dynamic cum texture on POV body for sex poses.</li>
<li><span class="cl-badge new">New</span> Added 24 cum texture stages for each sex pose.</li>
<li><span class="cl-badge new">New</span> Bathing now remove excess cum, not everything though.</li>
</ul>
</div>
</div>
<div class="cl-entry is-open">
<div class="cl-entry-header">
<span>
<span class="cl-entry-version">v0.0.2</span> –
<span class="cl-entry-date">16-mar-2026</span>
</span>
<span class="cl-entry-chevron">▶</span>
</div>
<div class="cl-entry-body">
<ul>
<li><span class="cl-badge new">QOL</span> Cleaned dead files and transformed large PNG images into smaller JPG images. </li>
<li><span class="cl-badge new">New</span> Added segment of the main story (Kaeltharion, the 22nd Battalion and Thalenwyr).</li>
<li><span class="cl-badge new">New</span> Added a new sex pose.</li>
<li><span class="cl-badge new">New</span> Added camp sex loop.</li>
<li><span class="cl-badge new">New</span> Added Sex History system and menu.</li>
<li><span class="cl-badge new">New</span> Added Sex Statistic menu.</li>
</ul>
</div>
</div>
<div class="cl-entry is-open">
<div class="cl-entry-header">
<span>
<span class="cl-entry-version">v0.0.1</span> –
<span class="cl-entry-date">12-mar-2026</span>
</span>
<span class="cl-entry-chevron">▶</span>
</div>
<div class="cl-entry-body">
<ul>
<li><span class="cl-badge new">New</span>Added a segment of the story (Not much for now, just for introducing the story on this prototype version).</li>
<li><span class="cl-badge new">New</span>Implemented the global hour/minute time system that updates continuously in the background.</li>
<li><span class="cl-badge new">New</span>Created Audio Control.</li>
<li><span class="cl-badge new">New</span>Added "CG" system support for future events.</li>
<li><span class="cl-badge new">New</span>Added Inventory System (Framework) with functionalities already working and ready.</li>
<li><span class="cl-badge new">New</span>Created layered avatar that supports all clothes, cum layers and faces.</li>
<li><span class="cl-badge new">New</span>Created Internal display of wife's rectum and vagina (x-ray).</li>
<li><span class="cl-badge new">New</span>Added 31 stages of vagina and rectum to display.</li>
<li><span class="cl-badge new">New</span>Added wardrobe items for player character.</li>
<li><span class="cl-badge new">New</span>Created framework to cum layers display on body, internal and timers to simulate absorption.</li>
<li><span class="cl-badge new">New</span>Created location by daytime and weektime / routine framework for npcs.</li>
<li><span class="cl-badge new">New</span>Created First Person view framework.</li>
<li><span class="cl-badge new">New</span>Created the base passages structures for the narrative flow.</li>
<li><span class="cl-badge new">New</span>Added all core JavaScript variables & macros inside the project.</li>
<li><span class="cl-badge new">New</span>Added bunch of other stuff that I'm for sure missing to name it here.</li>
</ul>
</div>
</div>
</div>
</div>
<<script>>
$(document).off("click.changelogToggle", ".cl-entry");
$(document).on("click.changelogToggle", ".cl-entry", function () {
$(this).toggleClass("is-open");
});
$('html, body').css('overflow', 'auto');
$(document).one(':passageend', function () {
$('html, body').css('overflow', 'hidden');
});
<</script>><<setBG 1 setup.ImagePath ''>>
<style>
#passages { margin: 0 !important; padding: 0 !important; }
/* fullscreen centering, no heavy phone-like panel */
.roadmap-screen {
position: fixed;
inset: 0;
z-index: 9999;
display: flex;
justify-content: center;
align-items: center;
padding: 1.5rem 1rem;
}
.roadmap-root {
width: min(94vw, 980px);
height: 86vh;
overflow-y: auto;
overflow-x: hidden;
padding: 1.8rem 1.4rem 1.7rem;
color: rgba(240,224,192,0.96);
font-family: "Palatino Linotype", "Book Antiqua", serif;
text-shadow:
0 2px 10px rgba(0,0,0,0.55),
0 0 18px rgba(0,0,0,0.22);
}
/* scrollbar */
.roadmap-root::-webkit-scrollbar {
width: 8px;
}
.roadmap-root::-webkit-scrollbar-track {
background: rgba(20,12,8,0.55);
border-radius: 8px;
}
.roadmap-root::-webkit-scrollbar-thumb {
background: rgba(214,181,110,0.55);
border-radius: 8px;
border: 1px solid rgba(255,221,160,0.18);
}
.roadmap-root::-webkit-scrollbar-thumb:hover {
background: rgba(255,221,160,0.72);
}
/* return button */
.roadmap-return {
text-align: left;
margin-bottom: 1rem;
}
.roadmap-return button {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.72em 1.05em;
border-radius: 10px;
font-size: 0.92rem;
font-family: "Cinzel", "Uncial Antiqua", "Palatino Linotype", serif;
font-weight: 700;
letter-spacing: 1px;
text-transform: uppercase;
cursor: pointer;
user-select: none;
color: rgba(240,224,192,0.96);
border: 1px solid rgba(240,224,192,0.22);
background:
linear-gradient(to bottom, rgba(74,47,27,0.78), rgba(47,28,17,0.72));
box-shadow:
inset 0 0 18px rgba(0,0,0,0.35),
0 8px 18px rgba(0,0,0,0.35);
transition: transform 180ms ease, box-shadow 220ms ease, border-color 220ms ease, filter 220ms ease;
}
.roadmap-return button::before {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
pointer-events: none;
box-shadow:
inset 0 1px 0 rgba(255,255,255,0.06),
inset 0 -1px 0 rgba(0,0,0,0.35);
}
.roadmap-return button:hover {
transform: translateY(-2px);
border-color: rgba(255,221,160,0.42);
box-shadow:
inset 0 0 22px rgba(0,0,0,0.35),
0 10px 22px rgba(0,0,0,0.45),
0 0 18px rgba(214,181,110,0.18);
filter: brightness(1.06);
}
/* header */
.roadmap-title {
font-family: "Cinzel", "Uncial Antiqua", "Palatino Linotype", serif;
font-size: clamp(2rem, 4.6vw, 3rem);
font-weight: 700;
letter-spacing: 2px;
text-transform: uppercase;
color: rgba(255,221,160,0.98);
margin-bottom: 0.15rem;
}
.roadmap-sub {
font-family: "Cinzel", "Palatino Linotype", serif;
font-size: 0.92rem;
letter-spacing: 0.8px;
opacity: 0.84;
margin-bottom: 1rem;
color: rgba(240,224,192,0.9);
max-width: 780px;
}
.roadmap-intro {
line-height: 1.55;
font-size: 0.96rem;
margin-bottom: 1.2rem;
max-width: 850px;
color: rgba(240,224,192,0.94);
}
/* info strip */
.roadmap-strip {
display: flex;
flex-wrap: wrap;
gap: 0.7rem;
margin-bottom: 1.3rem;
}
.roadmap-pill {
display: inline-flex;
align-items: center;
gap: 0.45rem;
padding: 0.38rem 0.8rem;
border-radius: 999px;
font-size: 0.72rem;
font-family: "Cinzel", "Palatino Linotype", serif;
font-weight: 700;
letter-spacing: 0.7px;
text-transform: uppercase;
color: rgba(46,24,10,0.96);
background: rgba(255,221,160,0.92);
box-shadow:
0 4px 10px rgba(0,0,0,0.28),
0 0 10px rgba(214,181,110,0.18);
}
/* grid */
.roadmap-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 1rem;
margin-bottom: 1.2rem;
}
/* cards */
.roadmap-card {
border: 1px solid rgba(240,224,192,0.14);
border-radius: 12px;
padding: 0.95rem 1rem 1rem;
background:
linear-gradient(to bottom, rgba(62,38,22,0.58), rgba(33,19,12,0.48));
box-shadow:
inset 0 0 16px rgba(0,0,0,0.24),
0 8px 18px rgba(0,0,0,0.20);
}
.roadmap-card-title {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.6rem;
margin-bottom: 0.55rem;
}
.roadmap-card-title span:first-child {
font-family: "Cinzel", "Palatino Linotype", serif;
font-size: 1rem;
font-weight: 700;
letter-spacing: 1px;
text-transform: uppercase;
color: rgba(255,221,160,0.96);
}
.roadmap-status {
font-size: 0.64rem;
padding: 0.16rem 0.45rem;
border-radius: 999px;
text-transform: uppercase;
font-family: "Cinzel", "Palatino Linotype", serif;
font-weight: 700;
letter-spacing: 0.7px;
border: 1px solid;
}
.roadmap-status.done {
color: rgba(255,221,160,0.96);
border-color: rgba(255,221,160,0.7);
background: rgba(255,221,160,0.10);
}
.roadmap-status.progress {
color: rgba(240,224,192,0.94);
border-color: rgba(240,224,192,0.45);
background: rgba(240,224,192,0.08);
}
.roadmap-status.future {
color: rgba(196,176,140,0.9);
border-color: rgba(196,176,140,0.36);
background: rgba(196,176,140,0.08);
}
.roadmap-card p {
margin: 0 0 0.65rem;
line-height: 1.48;
font-size: 0.91rem;
color: rgba(240,224,192,0.93);
}
.roadmap-card ul {
margin: 0;
padding-left: 1.1rem;
}
.roadmap-card li {
margin-bottom: 0.34rem;
line-height: 1.42;
font-size: 0.9rem;
}
/* roadmap phases */
.roadmap-phase {
margin-bottom: 1rem;
border: 1px solid rgba(240,224,192,0.14);
border-radius: 12px;
padding: 0.9rem 1rem;
background:
linear-gradient(to bottom, rgba(62,38,22,0.58), rgba(33,19,12,0.48));
box-shadow:
inset 0 0 16px rgba(0,0,0,0.24),
0 8px 18px rgba(0,0,0,0.20);
}
.roadmap-phase-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.8rem;
margin-bottom: 0.45rem;
flex-wrap: wrap;
}
.roadmap-phase-title {
font-family: "Cinzel", "Palatino Linotype", serif;
font-size: 1rem;
font-weight: 700;
letter-spacing: 1px;
text-transform: uppercase;
color: rgba(255,221,160,0.96);
}
.roadmap-phase-desc {
font-size: 0.92rem;
line-height: 1.5;
margin-bottom: 0.5rem;
color: rgba(240,224,192,0.93);
}
.roadmap-checks {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 0.45rem 1rem;
}
.roadmap-check {
font-size: 0.9rem;
line-height: 1.4;
}
/* note section */
.roadmap-note {
margin-top: 1.2rem;
padding: 0.9rem 1rem;
border-radius: 12px;
border: 1px solid rgba(255,221,160,0.20);
background: linear-gradient(to bottom, rgba(255,221,160,0.08), rgba(47,28,17,0.30));
box-shadow:
inset 0 0 14px rgba(0,0,0,0.20),
0 6px 14px rgba(0,0,0,0.18);
line-height: 1.52;
font-size: 0.93rem;
}
/* small helpers */
.gold {
color: rgba(255,221,160,0.97);
font-weight: 700;
}
@media (max-width: 760px) {
.roadmap-grid,
.roadmap-checks {
grid-template-columns: 1fr;
}
.roadmap-root {
width: min(95vw, 980px);
padding: 1.35rem 1rem 1.35rem;
}
}
</style>
<div class="roadmap-screen">
<div class="roadmap-root">
<div class="roadmap-return">
<<button "Return" "toReturn">>
<<goto "Main Menu">>
<</button>>
</div>
<div class="roadmap-title">About / Roadmap</div>
<div class="roadmap-sub">What this project is, what already exists, and where it is heading next.</div>
<div class="roadmap-intro">
<span class="gold">Elliahal: Chronicles of the Bloomspell</span> is a story-driven adult project focused on atmosphere, perspective, immersion, character systems, and reactive scenes. The long-term goal is not just to build isolated events, but a world with progression, routines, layered visuals, first-person sequences, and expanding narrative branches that feel increasingly alive with every update.
</div>
<div class="roadmap-strip">
<div class="roadmap-pill">Prototype Stage</div>
<div class="roadmap-pill">Story + Systems Focus</div>
<div class="roadmap-pill">Frequent Expansion Planned</div>
</div>
<div class="roadmap-grid">
<div class="roadmap-card">
<div class="roadmap-card-title">
<span>Project Vision</span>
<span class="roadmap-status progress">Ongoing</span>
</div>
<p>The project aims to combine narrative progression, layered character visuals, interactive scenes, CG events, routines, and progression systems into a single cohesive experience.</p>
<ul>
<li>Story-driven progression instead of disconnected scenes.</li>
<li>Immersive presentation with POV sequences and layered visuals.</li>
<li>Expandable foundation for future events, choices, and systems.</li>
</ul>
</div>
<div class="roadmap-card">
<div class="roadmap-card-title">
<span>Current State</span>
<span class="roadmap-status done">Playable Base</span>
</div>
<p>The current build is a foundation release: it already contains important framework pieces, core macros, progression structure, and the first playable content.</p>
<ul>
<li>Core game framework is in place.</li>
<li>First story content and base passage flow are working.</li>
<li>Visual and system groundwork is already prepared for expansion.</li>
</ul>
</div>
</div>
<div class="roadmap-phase">
<div class="roadmap-phase-head">
<div class="roadmap-phase-title">Phase I — Foundation</div>
<div class="roadmap-status done">Established</div>
</div>
<div class="roadmap-phase-desc">
The goal of this phase is to create the technical and visual backbone of the game so future content can be added faster, cleaner, and with more consistency.
</div>
<div class="roadmap-checks">
<div class="roadmap-check">✦ Core JavaScript variables and macros</div>
<div class="roadmap-check">✦ Base narrative flow structure</div>
<div class="roadmap-check">✦ Global time framework</div>
<div class="roadmap-check">✦ Inventory framework</div>
<div class="roadmap-check">✦ Layered avatar / visual support</div>
<div class="roadmap-check">✦ CG support and POV framework</div>
</div>
</div>
<div class="roadmap-phase">
<div class="roadmap-phase-head">
<div class="roadmap-phase-title">Phase II — Expanding Core Content</div>
<div class="roadmap-status progress">Current Focus</div>
</div>
<div class="roadmap-phase-desc">
This phase is about turning the framework into a richer game: more scenes, more routes, more interactions, more content density, and stronger continuity between systems and story.
</div>
<div class="roadmap-checks">
<div class="roadmap-check">✦ Expand main narrative branches</div>
<div class="roadmap-check">✦ Add more first-person scenes and CGs</div>
<div class="roadmap-check">✦ Increase wardrobe / body / expression variety</div>
<div class="roadmap-check">✦ Build more event-driven and location-driven interactions</div>
<div class="roadmap-check">✦ Improve pacing between story and interactive systems</div>
<div class="roadmap-check">✦ Add more polished menus and player feedback</div>
</div>
</div>
<div class="roadmap-phase">
<div class="roadmap-phase-head">
<div class="roadmap-phase-title">Phase III — World Depth</div>
<div class="roadmap-status future">Planned</div>
</div>
<div class="roadmap-phase-desc">
Once the core loop is stronger, the project moves toward deeper reactivity: more routines, more schedule logic, more systemic consequences, and a world that reacts better to progression and repeated play.
</div>
<div class="roadmap-checks">
<div class="roadmap-check">✦ Deeper character routines and location states</div>
<div class="roadmap-check">✦ More layered consequences and branching states</div>
<div class="roadmap-check">✦ Expanded scene logic and progression tracking</div>
<div class="roadmap-check">✦ Stronger replay value through route differences</div>
<div class="roadmap-check">✦ More immersive environmental storytelling</div>
<div class="roadmap-check">✦ More polished long-form progression loops</div>
</div>
</div>
<div class="roadmap-phase">
<div class="roadmap-phase-head">
<div class="roadmap-phase-title">Planned Priorities</div>
<div class="roadmap-status progress">Next Steps</div>
</div>
<div class="roadmap-phase-desc">
The immediate direction is to keep strengthening what already exists rather than adding random disconnected features. The goal is to make every update feel like a meaningful step forward.
</div>
<div class="roadmap-checks">
<div class="roadmap-check">✦ More narrative scenes and event continuity</div>
<div class="roadmap-check">✦ Better integration between systems and story</div>
<div class="roadmap-check">✦ More visual variation and content density</div>
<div class="roadmap-check">✦ Cleaner UX for menus, feedback, and progression</div>
</div>
</div>
<div class="roadmap-note">
<span class="gold">Note:</span> this roadmap is intentionally flexible. Some features may arrive earlier or later depending on development needs, technical improvements, and what gives the best value to the overall experience. The focus is always to build the project in a way that remains expandable, immersive, and worth revisiting over time.
</div>
</div>
</div>
<<script>>
$('html, body').css('overflow', 'auto');
$(document).one(':passageend', function () {
$('html, body').css('overflow', 'hidden');
});
<</script>><<runScenario "princesstentnight">>
/*<<if $endContentMsg == 0>>
<<run openConversation("end_of_content_message")>><<set $endContentMsg to 1>><</if>>*/
<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.50" data-y="0.32" style="transform: translate(-50%, -50%);">
<<button "sleep">>
<<if $chestSlot != "">>
<<run openConversation("cant_sleep_message")>>
<</if>>
<<if $chestSlot == "">>
<<if (($datenow.getHours() < 8) && ($datenow.getHours() >= 0))>>
<<run $datenow.setHours(8)>>
<<run Save.slots.save(0)>>
<<goto "Aethyra Dream Intro1">>
<</if>>
<<if ($datenow.getHours() >= 18)>>
<<run $datenow.setDate($datenow.getDate() + 1)>>
<<run $datenow.setHours(8)>>
<<run Save.slots.save(0)>>
<<goto "Aethyra Dream Intro1">>
<</if>>
<</if>>
<</button>> </span>
<<if $lastbath && (($datenow.getTime() - $lastbath) < 60*60*1000)>>
<!-- hide / don't show -->
<<else>>
<!-- show it -->
<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.05" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "bathe">>
<<set $lastbath to $datenow>>
<<run $datenow.setMinutes($datenow.getMinutes() + 30)>>
<<set $cumBottomSlot to "">>
<<set $cumTopSlot to "">>
<<set $neckSlot to "">>
<<set $chestSlot to "">>
<<set $hipSlot to "">>
<<set $legSlot to "">>
<<set $feetSlot to "">>
<<set $acessorySlot to "">>
<<set $cumBottomClothSlot to "">>
<<set $cumTopClothSlot to "">>
<<if $wifeCurrentCumVagina > 3>>
<<set $wifeCurrentCumVagina to 3>>
<</if>>
<<if $wifeCurrentCumAssHole > 3>>
<<set $wifeCurrentCumAssHole to 3>>
<</if>>
<<goto "Princess Tent PosIntro">>
<</button>> </span>
<</if>>
<<if $chestSlot == "">><span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.35" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "Get Dressed">>
<<set $chestSlot to "Elven Dress 6">>
<<goto "Princess Tent PosIntro">>
<</button>> </span><</if>>
<<if $chestSlot != "">><span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.35" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "Get Undressed">>
<<set $chestSlot to "">>
<<goto "Princess Tent PosIntro">>
<</button>> </span><</if>>
<<runScenario "warcamp/22ndcommander1.jpg" "cg">>
<<comic "kaeltharion_morning_tent_confrontation" "Kaeltharion2">>
<<runScenario "warcamp/princesstentdizzy.jpg" "cg" "nobody">>
/*22nd Commander first encounter message*/
<<if $mainStory == 1>>
<<set $mainStory to 2>>
<<run openConversation("22nd_story1")>>
<</if>>
/*------------------------------------*/
<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.50" data-y="0.32" style="transform: translate(-50%, -50%);">
<<button "Not feeling good...">>
<<run $datenow.setMinutes($datenow.getMinutes() + 45)>>
<<run openConversation("dizzyness_camp_intro")>>
<</button>> </span>
<<if $aelaraEatenFood == 0>>
<<runScenario "warcamp/thale1.jpg" "cg">>
<<comic "scene_thalenwyr_talk" "Princess Tent PosIntro2.5">>
<<run $datenow.setMinutes($datenow.getMinutes() + 15)>><<runScenario "princesstent">>
<<if $chestSlot != "">>
<<run openConversation("Thalenwyr_intro")>>
<</if>>
<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.50" data-y="0.32" style="transform: translate(-50%, -50%);">
<<button "sleep">>
<<if $chestSlot != "">>
<<run openConversation("cant_sleep_message")>>
<</if>>
<<if $chestSlot == "">>
<<if (($datenow.getHours() < 8) && ($datenow.getHours() >= 0))>>
<<run $datenow.setHours(8)>>
<<run Save.slots.save(0)>>
<<goto "Princess Tent PosIntro2">>
<</if>>
<<if ($datenow.getHours() >= 18)>>
<<run $datenow.setDate($datenow.getDate() + 1)>>
<<run $datenow.setHours(8)>>
<<run Save.slots.save(0)>>
<<goto "Princess Tent PosIntro2">>
<</if>>
<</if>>
<</button>> </span>
<<if $lastbath && (($datenow.getTime() - $lastbath) < 60*60*1000)>>
<!-- hide / don't show -->
<<else>>
<!-- show it -->
<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.05" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "bathe">>
<<set $lastbath to $datenow>>
<<run $datenow.setMinutes($datenow.getMinutes() + 30)>>
<<set $cumBottomSlot to "">>
<<set $cumTopSlot to "">>
<<set $neckSlot to "">>
<<set $chestSlot to "">>
<<set $hipSlot to "">>
<<set $legSlot to "">>
<<set $feetSlot to "">>
<<set $acessorySlot to "">>
<<set $cumBottomClothSlot to "">>
<<set $cumTopClothSlot to "">>
<<goto "Princess Tent PosIntro2">>
<</button>> </span>
<</if>>
<<if $chestSlot == "">><span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.35" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "Get Dressed">>
<<set $chestSlot to "Elven Dress 6">>
<<goto "Princess Tent PosIntro2">>
<</button>> </span><</if>>
<<if $chestSlot != "">><span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.35" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "Get Undressed">>
<<set $chestSlot to "">>
<<goto "Princess Tent PosIntro2">>
<</button>> </span><</if>>
<<runScenario "princesstent">>
<<if $aelaraEatenFood == 1>>
<<if $chestSlot != "">><span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.95" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "Go Outside">>
<<run $datenow.setMinutes($datenow.getMinutes() + 1)>>
<<goto "Kaeltharion1">>
<</button>> </span><</if>>
<<else>>
<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.50" data-y="0.32" style="transform: translate(-50%, -50%);">
<<button "Eat">>
<<set $aelaraEatenFood to 1>>
<<run openConversation("food_camp_intro")>>
<</button>> </span>
<</if>>
<<if $lastbath && (($datenow.getTime() - $lastbath) < 60*60*1000)>>
<!-- hide / don't show -->
<<else>>
<!-- show it -->
<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.05" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "bathe">>
<<set $lastbath to $datenow>>
<<run $datenow.setMinutes($datenow.getMinutes() + 30)>>
<<set $cumBottomSlot to "">>
<<set $cumTopSlot to "">>
<<set $neckSlot to "">>
<<set $chestSlot to "">>
<<set $hipSlot to "">>
<<set $legSlot to "">>
<<set $feetSlot to "">>
<<set $acessorySlot to "">>
<<set $cumBottomClothSlot to "">>
<<set $cumTopClothSlot to "">>
<<goto "Princess Tent PosIntro3">>
<</button>> </span>
<</if>>
<<if $chestSlot == "">><span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.35" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "Get Dressed">>
<<set $chestSlot to "Elven Dress 6">>
<<goto "Princess Tent PosIntro3">>
<</button>> </span><</if>>
<<if $chestSlot != "">><span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.35" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "Get Undressed">>
<<set $chestSlot to "">>
<<goto "Princess Tent PosIntro3">>
<</button>> </span><</if>>
<<runScenario "warcamp/dreamaethyra.jpg" "cg">><<run createDickHistoryPanel()>><<run createDickHistorySubMenuPanel()>><<runScenario "princesstentfood">>
<<if $aelaraEatenFood == 1>>
<<if $chestSlot != "">><span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.95" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "Go Outside">>
<<run $datenow.setMinutes($datenow.getMinutes() + 1)>>
<<goto "Kaeltharion1">>
<</button>> </span><</if>>
<<else>>
<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.50" data-y="0.32" style="transform: translate(-50%, -50%);">
<<button "Eat">>
<<set $aelaraEatenFood to 1>>
<<run openConversation("food_camp_intro")>>
<</button>> </span>
<</if>>
<<if $lastbath && (($datenow.getTime() - $lastbath) < 60*60*1000)>>
<!-- hide / don't show -->
<<else>>
<!-- show it -->
<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.05" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "bathe">>
<<set $lastbath to $datenow>>
<<run $datenow.setMinutes($datenow.getMinutes() + 30)>>
<<set $cumBottomSlot to "">>
<<set $cumTopSlot to "">>
<<set $neckSlot to "">>
<<set $chestSlot to "">>
<<set $hipSlot to "">>
<<set $legSlot to "">>
<<set $feetSlot to "">>
<<set $acessorySlot to "">>
<<set $cumBottomClothSlot to "">>
<<set $cumTopClothSlot to "">>
<<goto "Princess Tent PosIntro2.5">>
<</button>> </span>
<</if>>
<<if $chestSlot == "">><span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.35" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "Get Dressed">>
<<set $chestSlot to "Elven Dress 6">>
<<goto "Princess Tent PosIntro2.5">>
<</button>> </span><</if>>
<<if $chestSlot != "">><span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.35" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "Get Undressed">>
<<set $chestSlot to "">>
<<goto "Princess Tent PosIntro2.5">>
<</button>> </span><</if>>
<<runScenario "warcamp/22ndcommander2.jpg" "cg">>
<<comic "kaeltharion_morning_tent_confrontation2" "Princess Tent Kaeltharion1">>
<<run $datenow.setMinutes($datenow.getMinutes() + 5)>><<run openConversation("dizzyness_camp_intro2")>><<runScenario "warcamp/gbintro1.jpg" "cg" "nobody">>
<<run openConversation("dizzyness_camp_intro3")>>
<<runScenario "warcamp/gbintro2.jpg" "cg" "nobody">>
<<run openConversation("dizzyness_camp_intro4")>><<runScenario "warcamp/gbintro1.jpg" "cg" "nobody">>
<<run openConversation("dizzyness_camp_intro5")>><<run openConversation("dizzyness_camp_intro6")>>
<<run $datenow.setHours(19)>>
<<set $mainStory to 1>>
<<set $quickVar to 0>><<if $quickVar == 1>>
<<run openConversation("dizzyness_camp_intro8")>>
<<set $quickVar to 2>>
<</if>>
<<if $quickVar == 0>>
<<run openConversation("dizzyness_camp_intro7")>>
<<set $quickVar to 1>>
<</if>>
/*Sex Log Randomizer*/
<<run $datenow.setMinutes($datenow.getMinutes() + random(5,15))>>
<<set _cm = random(11, 19)>>
<<set _in = (_cm / 2.54).toFixed(1)>>
<<set _sizeText = _cm + "cm - " + _in + "in">>
<<set _thrusts = random(150, 490) + " Thrusts">>
<<set _type = either("Vaginal", "Anal")>>
<<set _ml = random(4, 25) + "ml">>
<<run DickHistory.add("dick1", _sizeText, _thrusts, _type, _ml, $formattedDateNow, "Unknown")>>
<<if _type == "Vaginal">><<set $wifeCurrentCumVagina to ($wifeCurrentCumVagina + 1)>>
<<else>><<set $wifeCurrentCumAssHole to ($wifeCurrentCumAssHole + 1)>><</if>>
/*Scene Randomizer*/
<<if $stringTimeNow <= 6 || $stringTimeNow >= 19>><<set _bg = "warcamp/gbn" + random(1,4) + ".jpg">><</if>>
<<if $stringTimeNow > 6 && $stringTimeNow < 19>><<set _bg = "warcamp/gb" + random(1,6) + ".jpg">><</if>>
<<set _body = either(
"Body_fuckelf1", "Body_fuckelf2", "Body_fuckelf3", "Body_fuckelf4",
"Body_fuckslimelf1", "Body_fuckslimelf2", "Body_fuckslimelf3", "Body_fuckslimelf4",
"Body_legsupelf1", "Body_legsupelf2", "Body_legsupelf3", "Body_legsupelf4",
"Body_legsupelfslim1", "Body_legsupelfslim2", "Body_legsupelfslim3", "Body_legsupelfslim4"
)>>
<<runScenario _bg "cg" _body>>
<<script>>
$(document).one(':passageend', function () {
// stop any previous loop (avoid stacking intervals)
if (window._pushFxLoop) {
clearInterval(window._pushFxLoop);
window._pushFxLoop = null;
}
window._pushFxLoop = setInterval(function () {
new Wikifier(null, '<<PushForwardFX>>');
}, 400);
});
<</script>>
<<set $mainStory to 1>>
<<set $chestSlot to "">>
<<if ($datenow.getHours() >= 23)>>
<<goto "Princess Tent">>
<<else>>
<<run openConversation("princess_camp_bed_loop")>>
<</if>>
/*Sex Log Randomizer*/
<<run $datenow.setMinutes($datenow.getMinutes() + random(5,15))>>
<<set _cm = random(11, 19)>>
<<set _in = (_cm / 2.54).toFixed(1)>>
<<set _sizeText = _cm + "cm - " + _in + "in">>
<<set _thrusts = random(150, 490) + " Thrusts">>
<<set _type = either("Vaginal", "Anal")>>
<<set _ml = random(4, 25) + "ml">>
<<run DickHistory.add("dick1", _sizeText, _thrusts, _type, _ml, $formattedDateNow, "Unknown")>>
<<if _type == "Vaginal">><<set $wifeCurrentCumVagina to ($wifeCurrentCumVagina + 1)>>
<<else>><<set $wifeCurrentCumAssHole to ($wifeCurrentCumAssHole + 1)>><</if>>
/*Scene Randomizer*/
<<if $stringTimeNow <= 6 || $stringTimeNow >= 19>><<set _bg = "warcamp/gbn" + random(1,4) + ".jpg">><</if>>
<<if $stringTimeNow > 6 && $stringTimeNow < 19>><<set _bg = "warcamp/gb" + random(1,6) + ".jpg">><</if>>
<<set _body = either(
"Body_fuckelf1", "Body_fuckelf2", "Body_fuckelf3", "Body_fuckelf4",
"Body_fuckslimelf1", "Body_fuckslimelf2", "Body_fuckslimelf3", "Body_fuckslimelf4",
"Body_legsupelf1", "Body_legsupelf2", "Body_legsupelf3", "Body_legsupelf4",
"Body_legsupelfslim1", "Body_legsupelfslim2", "Body_legsupelfslim3", "Body_legsupelfslim4"
)>>
<<runScenario _bg "cg" _body>>
<<script>>
$(document).one(':passageend', function () {
// stop any previous loop (avoid stacking intervals)
if (window._pushFxLoop) {
clearInterval(window._pushFxLoop);
window._pushFxLoop = null;
}
window._pushFxLoop = setInterval(function () {
new Wikifier(null, '<<PushForwardFX>>');
}, 400);
});
<</script>>
<<runScenario "princesstent">>
<<run openConversation("princess_camp_bed_loop_begin_another_day")>>
<<set $chestSlot to "Elven Dress 6">>
<<runScenario "warcamp/dreamaethyra.jpg" "cg">>
<<comic "dream_aethyra_intro" "Aethyra Dream PostIntro">>
<<set $chestSlot to "">>
<<runScenario "princesstentbedcourtainclosed.jpg" "Body_LayDownKneesUp">>
<span class="custom-button pov-hotspot" data-povhotspot="1" data-x="0.5" data-y="0.40" style="transform: translate(-50%, -50%);">
<<button "Get Out Of The Bed">>
<<set $chestSlot to "">>
<<goto "Princess Tent PosIntro2">>
<</button>> </span>