mirror of
https://github.com/doublespeakgames/adarkroom.git
synced 2026-05-28 00:01:54 +08:00
Adding ADR to Github
This commit is contained in:
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>A Dark Room</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>A Dark Room</title>
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
width: 960px;
|
||||||
|
margin: auto;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<strong>
|
||||||
|
A Dark Room makes use of HTML5 and CSS3, which your current browser does not appear to support.<br/>
|
||||||
|
Please update your browser for the best experience:<br/>
|
||||||
|
</strong>
|
||||||
|
<a href='http://www.mozilla.org/en-US/firefox/new/'><img src='img/firefox.png' alt='Firefox' /></a>
|
||||||
|
<a href='https://www.google.com/intl/en/chrome/browser/'><img src='img/chrome.png' alt='Firefox' /></a>
|
||||||
|
<a href='http://windows.microsoft.com/en-CA/internet-explorer/download-ie'><img src='img/ie.png' alt='Firefox' /></a>
|
||||||
|
<br/><br/>
|
||||||
|
Or you can <a href='index.html?ignorebrowser=true'>play anyway</a>, but it probably won't work!
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
+497
@@ -0,0 +1,497 @@
|
|||||||
|
/* Fonts */
|
||||||
|
body, .tooltip {
|
||||||
|
font-family: "Times New Roman", Times, serif;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: normal;
|
||||||
|
line-height: normal;
|
||||||
|
letter-spacing: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Framework stuff */
|
||||||
|
|
||||||
|
div.clear {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#wrapper {
|
||||||
|
margin: auto;
|
||||||
|
width: 700px;
|
||||||
|
padding: 20px 0 0 220px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#saveNotify {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
right: 0px;
|
||||||
|
background: white;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#content {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
height: 700px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#header {
|
||||||
|
padding-bottom: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deleteSave {
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
bottom: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deleteSave:hover, .share:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share {
|
||||||
|
position: absolute;
|
||||||
|
right: 70px;
|
||||||
|
bottom: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.headerButton {
|
||||||
|
font-size: 18px;
|
||||||
|
cursor: pointer;
|
||||||
|
float: left;
|
||||||
|
border-left: 1px solid black;
|
||||||
|
margin-left: 10px;
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.headerButton:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.headerButton:first-child {
|
||||||
|
border-left: none;
|
||||||
|
margin-left: 0px;
|
||||||
|
padding-left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.headerButton.selected, div.headerButton.selected:hover {
|
||||||
|
cursor: default;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#outerSlider {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#outerSlider > div {
|
||||||
|
position: relative;
|
||||||
|
float: left;
|
||||||
|
width: 700px;
|
||||||
|
height: 700px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#locationSlider {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.location {
|
||||||
|
position: relative;
|
||||||
|
float: left;
|
||||||
|
width: 700px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.row_key {
|
||||||
|
clear: both;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.row_val {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Notifications */
|
||||||
|
|
||||||
|
div#notifications {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
left: 0px;
|
||||||
|
height: 700px;
|
||||||
|
width: 200px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#notifications div.notification {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#notifyGradient {
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
background-color: white;
|
||||||
|
background: -webkit-linear-gradient(
|
||||||
|
rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 100%
|
||||||
|
);
|
||||||
|
background: linear-gradient(
|
||||||
|
rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 100%
|
||||||
|
);
|
||||||
|
filter: alpha(
|
||||||
|
Opacity=0, FinishOpacity=100, Style=1, StartX=0, StartY=0, FinishX=0, FinishY=500
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Button */
|
||||||
|
|
||||||
|
div.button {
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid black;
|
||||||
|
width: 100px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
padding: 5px 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-khtml-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.button:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.button.disabled, div.button.disabled:hover {
|
||||||
|
cursor: default;
|
||||||
|
border-color: grey;
|
||||||
|
color: grey;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.button div.cooldown {
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
z-index: -1;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #DDDDDD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Up/Down buttons. They're complicated! */
|
||||||
|
|
||||||
|
.upBtn, .dnBtn {
|
||||||
|
position: absolute;
|
||||||
|
width: 14px;
|
||||||
|
height: 15px;
|
||||||
|
right: 0px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upBtn.disabled, .dnBtn.disabled {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upBtn {
|
||||||
|
top: -2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upBtn:after, .upBtn:before {
|
||||||
|
position: absolute;
|
||||||
|
border: medium solid transparent;
|
||||||
|
content: " ";
|
||||||
|
height: 0;
|
||||||
|
width: 0;
|
||||||
|
bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upBtn:after {
|
||||||
|
border-color: transparent transparent white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upBtn:before {
|
||||||
|
border-color: transparent transparent black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upBtn.disabled:before {
|
||||||
|
border-color: transparent transparent #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.dnBtn {
|
||||||
|
bottom: -3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dnBtn:after, .dnBtn:before {
|
||||||
|
position: absolute;
|
||||||
|
border: medium solid transparent;
|
||||||
|
content: " ";
|
||||||
|
height: 0;
|
||||||
|
width: 0;
|
||||||
|
top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upBtn:after, .dnBtn:after {
|
||||||
|
border-width: 3px;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upBtn:before, .dnBtn:before {
|
||||||
|
border-width: 5px;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dnBtn:after {
|
||||||
|
border-color: white transparent transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dnBtn:before {
|
||||||
|
border-color: black transparent transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dnBtn.disabled:before {
|
||||||
|
border-color: #999 transparent transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.button div.tooltip {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tooltip */
|
||||||
|
|
||||||
|
div.tooltip {
|
||||||
|
display: none;
|
||||||
|
padding: 2px 5px;
|
||||||
|
border: 1px solid black;
|
||||||
|
position: absolute;
|
||||||
|
box-shadow: -1px 3px 2px #666;
|
||||||
|
background: white;
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip.bottom {
|
||||||
|
top: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip.right {
|
||||||
|
left: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip.left {
|
||||||
|
right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip.top {
|
||||||
|
bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
*:hover > div.tooltip {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.tooltip:hover {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disabled:hover > div.tooltip, .button.free:hover > div.tooltip {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#event .button.disabled:hover > div.tooltip {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Events */
|
||||||
|
|
||||||
|
.eventPanel {
|
||||||
|
background: none repeat scroll 0 0 white;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
left: 250px;
|
||||||
|
padding: 20px;
|
||||||
|
position: absolute;
|
||||||
|
top: 90px;
|
||||||
|
width: 335px;
|
||||||
|
z-index: 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.noMask .eventPanel {
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eventPanel:before {
|
||||||
|
background-color:white;
|
||||||
|
opacity: 0.6;
|
||||||
|
content: " ";
|
||||||
|
height: 700px;
|
||||||
|
left: -252px;
|
||||||
|
position: absolute;
|
||||||
|
top: -75px;
|
||||||
|
width: 920px;
|
||||||
|
z-index: -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.noMask .eventPanel:before {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eventPanel:after {
|
||||||
|
position: absolute;
|
||||||
|
top: -2px;
|
||||||
|
left: -2px;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
content: " ";
|
||||||
|
border: 2px solid black;
|
||||||
|
box-shadow: 5px 5px 5px #666666;
|
||||||
|
z-index: -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.noMask .eventPanel:after {
|
||||||
|
border-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eventPanel .button {
|
||||||
|
float:left;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.noMask .eventPanel .button {
|
||||||
|
border-color: white;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eventTitle {
|
||||||
|
display: inline-block;
|
||||||
|
font-weight: bold;
|
||||||
|
position: absolute;
|
||||||
|
top: -12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.noMask .eventTitle {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eventTitle:after {
|
||||||
|
background-color: white;
|
||||||
|
bottom: 32%;
|
||||||
|
content: " ";
|
||||||
|
height: 5px;
|
||||||
|
left: 0;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.noMask .eventTitle:after {
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
#description {
|
||||||
|
position: relative;
|
||||||
|
min-height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.noMask #description {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#description > div {
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#buttons > .button {
|
||||||
|
margin: 0 5px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Combat! */
|
||||||
|
#description div.fighter {
|
||||||
|
padding: 0px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#wanderer {
|
||||||
|
left: 25%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#enemy {
|
||||||
|
right: 25%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hp {
|
||||||
|
position: absolute;
|
||||||
|
top: -15px;
|
||||||
|
margin-left: -50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#description .bullet {
|
||||||
|
padding: 0px 20px 0px 20px;
|
||||||
|
bottom: 25px;
|
||||||
|
position: absolute;
|
||||||
|
height: 1px;
|
||||||
|
line-height: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.damageText {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 15px;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#lootButtons {
|
||||||
|
padding-bottom: 0px !important;
|
||||||
|
margin: 20px 0 0 5px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
#lootButtons:before {
|
||||||
|
content: "take:";
|
||||||
|
position: absolute;
|
||||||
|
top: -25px;
|
||||||
|
left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dropMenu {
|
||||||
|
background: none repeat scroll 0 0 white;
|
||||||
|
border: 1px solid black;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 100;
|
||||||
|
padding-top: 5px;
|
||||||
|
text-align: left;
|
||||||
|
box-shadow: -1px 3px 2px #666;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dropMenu:before {
|
||||||
|
content: "drop:";
|
||||||
|
border-bottom: 1px solid black;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
padding: 0px 0px 5px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dropMenu > div {
|
||||||
|
padding: 0px 5px 5px 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dropMenu > div:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
div#village {
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
right: 0px;
|
||||||
|
border: 1px solid black;
|
||||||
|
cursor: default;
|
||||||
|
padding: 5px 10px;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#population {
|
||||||
|
position: absolute;
|
||||||
|
top: -13px;
|
||||||
|
right: 10px;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.noHuts #population {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#village:before {
|
||||||
|
position: absolute;
|
||||||
|
background: white;
|
||||||
|
content: "village";
|
||||||
|
left: 8px;
|
||||||
|
top: -13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#village.noHuts:before {
|
||||||
|
content: "forest";
|
||||||
|
}
|
||||||
|
|
||||||
|
div#workers {
|
||||||
|
position:absolute;
|
||||||
|
top: -4px;
|
||||||
|
left: 160px;
|
||||||
|
width: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workerRow > .row_val {
|
||||||
|
position: relative;
|
||||||
|
padding-right: 20px;
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-khtml-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workerRow {
|
||||||
|
position: relative;
|
||||||
|
margin: 10px 0px;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workerRow .tooltip {
|
||||||
|
width: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.storeRow div.tooltip {
|
||||||
|
width: 160px;
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
#outfitting {
|
||||||
|
position: relative;
|
||||||
|
border: 1px solid black;
|
||||||
|
width: 200px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding: 5px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#outfitting:before {
|
||||||
|
position: absolute;
|
||||||
|
content: "supplies";
|
||||||
|
top: -13px;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.outfitRow {
|
||||||
|
position: relative;
|
||||||
|
cursor: default;
|
||||||
|
margin: 10px -30px 10px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.outfitRow > .row_val {
|
||||||
|
padding-right: 30px;
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-khtml-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.outfitRow .tooltip {
|
||||||
|
width: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#bagspace {
|
||||||
|
background-color: white;
|
||||||
|
position: absolute;
|
||||||
|
top:-13px;
|
||||||
|
right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#perks {
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
right: 0px;
|
||||||
|
border: 1px solid black;
|
||||||
|
cursor: default;
|
||||||
|
padding: 5px 10px;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#perks:before {
|
||||||
|
position: absolute;
|
||||||
|
content: "perks";
|
||||||
|
top: -13px;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.perkRow {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.perkRow .row_key {
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
div#buildBtns {
|
||||||
|
position: absolute;
|
||||||
|
top: 50px;
|
||||||
|
left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#buildBtns:before {
|
||||||
|
content: "build:";
|
||||||
|
position: relative;
|
||||||
|
top: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#craftBtns {
|
||||||
|
position: absolute;
|
||||||
|
top: 50px;
|
||||||
|
left: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#craftBtns:before {
|
||||||
|
content: "craft:";
|
||||||
|
position: relative;
|
||||||
|
top: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#buyBtns {
|
||||||
|
position: absolute;
|
||||||
|
top: 50px;
|
||||||
|
left: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#buyBtns:before {
|
||||||
|
content: "buy:";
|
||||||
|
position: relative;
|
||||||
|
top: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#storesContainer {
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#stores {
|
||||||
|
position: relative;
|
||||||
|
border: 1px solid black;
|
||||||
|
cursor: default;
|
||||||
|
padding: 5px 10px;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.storeRow {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#stores:before {
|
||||||
|
position: absolute;
|
||||||
|
background: white;
|
||||||
|
content: "stores";
|
||||||
|
left: 8px;
|
||||||
|
top: -13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#weapons {
|
||||||
|
margin-top: 15px;
|
||||||
|
position: relative;
|
||||||
|
right: 0px;
|
||||||
|
border: 1px solid black;
|
||||||
|
cursor: default;
|
||||||
|
padding: 5px 10px;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#weapons:before {
|
||||||
|
position: absolute;
|
||||||
|
background: white;
|
||||||
|
content: "weapons";
|
||||||
|
left: 8px;
|
||||||
|
top: -13px;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
div#hullRow {
|
||||||
|
width: 70px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#engineRow {
|
||||||
|
width: 70px;
|
||||||
|
margin-bottom: 20px;
|
||||||
+134
@@ -0,0 +1,134 @@
|
|||||||
|
@-ms-keyframes spin {
|
||||||
|
0% {
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
transform:rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
-ms-transform: rotate(360deg);
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
-moz-transform: rotate(360deg);
|
||||||
|
transform:rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes spin {
|
||||||
|
0% {
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
transform:rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
-ms-transform: rotate(360deg);
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
-moz-transform: rotate(360deg);
|
||||||
|
transform:rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-moz-keyframes spin {
|
||||||
|
0% {
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
transform:rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
-ms-transform: rotate(360deg);
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
-moz-transform: rotate(360deg);
|
||||||
|
transform:rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% {
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
transform:rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
-ms-transform: rotate(360deg);
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
-moz-transform: rotate(360deg);
|
||||||
|
transform:rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#spacePanel {
|
||||||
|
float: none !important;
|
||||||
|
position: absolute !important;
|
||||||
|
top: -700px;
|
||||||
|
left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#starsContainer {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#stars, #starsBack {
|
||||||
|
position: absolute;
|
||||||
|
z-index: -1;
|
||||||
|
left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#stars > div, #starsBack > div {
|
||||||
|
position: relative;
|
||||||
|
height: 3000px;
|
||||||
|
width: 3000px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#starsBack {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.star {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ship {
|
||||||
|
cursor: default;
|
||||||
|
position: absolute;
|
||||||
|
margin-top: -10px;
|
||||||
|
margin-left: -7.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#theEnd {
|
||||||
|
position: relative;
|
||||||
|
cursor: default;
|
||||||
|
top: 200px;
|
||||||
|
margin-left: -220px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
opacity: 0;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.asteroid {
|
||||||
|
cursor: default;
|
||||||
|
position: absolute;
|
||||||
|
top: -40px;
|
||||||
|
left: 350px;
|
||||||
|
-webkit-animation: 1s linear 0s normal none infinite spin;
|
||||||
|
-moz-animation: 1s linear 0s normal none infinite spin;
|
||||||
|
-ms-animation: 1s linear 0s normal none infinite spin;
|
||||||
|
animation: 1s linear 0s normal none infinite spin;
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#hullRemaining {
|
||||||
|
width: 70px;
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
#worldOuter {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map {
|
||||||
|
position: relative;
|
||||||
|
font-family: "Courier New", Courier, monospace;
|
||||||
|
border: 1px solid black;
|
||||||
|
overflow: hidden;
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 10px;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
color: #999;
|
||||||
|
cursor: default;
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-khtml-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map .landmark {
|
||||||
|
position: relative;
|
||||||
|
font-weight: bold;
|
||||||
|
color: black;
|
||||||
|
line-height: 0px; /* Hack to prevent the boldness from increasing the row's line-height. I hope it works in all browsers... */
|
||||||
|
}
|
||||||
|
|
||||||
|
#bagspace-world {
|
||||||
|
border: 1px solid black;
|
||||||
|
height: 62px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
margin-top: 13px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bagspace-world > div {
|
||||||
|
padding: 6px 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#backpackTitle {
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
left: 10px;
|
||||||
|
background-color: white;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#backpackSpace {
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
right: 10px;
|
||||||
|
background-color: white;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#healthCounter {
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
left: 80px;
|
||||||
|
background-color: white;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.supplyItem {
|
||||||
|
display: inline-block;
|
||||||
|
border: 1px solid #999;
|
||||||
|
float: left;
|
||||||
|
margin: 0px 5px 6px 0px;
|
||||||
|
padding: 0 5px;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
Binary file not shown.
@@ -0,0 +1,5 @@
|
|||||||
|
Radius Enemy DPS Player DPS Enemy HP Player HP
|
||||||
|
=====================================================================
|
||||||
|
< 10 1 1 5 10
|
||||||
|
< 20 3 3 10 15-20
|
||||||
|
< 30 6 4 20 30-40
|
||||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 318 B |
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 5.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 6.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 9.2 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 4.9 KiB |
+77
@@ -0,0 +1,77 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html itemscope itemtype="http://schema.org/CreativeWork">
|
||||||
|
<head>
|
||||||
|
<!--
|
||||||
|
A Dark Room (v1.2)
|
||||||
|
==================
|
||||||
|
|
||||||
|
A minimalist text adventure by Michael Townsend.
|
||||||
|
Inspired by Candy Box (http://candies.aniwey.net/)
|
||||||
|
Please don't steal me.
|
||||||
|
-->
|
||||||
|
<title>A Dark Room</title>
|
||||||
|
<meta itemprop="description" name="description" property="og:description" content="A minimalist text adventure">
|
||||||
|
<meta itemprop="image" property="og:image" content="img/adr.png" />
|
||||||
|
<meta itemprop="name" property="og:title" content="A Dark Room" />
|
||||||
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
|
<link rel="image_src" href="img/adr.png" />
|
||||||
|
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
|
||||||
|
<script src="lib/jquery.color-2.1.2.min.js"></script>
|
||||||
|
<script src="script/Button.js"></script>
|
||||||
|
<script src="script/engine.js"></script>
|
||||||
|
<script src="script/header.js"></script>
|
||||||
|
<script src="script/notifications.js"></script>
|
||||||
|
<script src="script/events.js"></script>
|
||||||
|
<script src="script/room.js"></script>
|
||||||
|
<script src="script/outside.js"></script>
|
||||||
|
<script src="script/world.js"></script>
|
||||||
|
<script src="script/path.js"></script>
|
||||||
|
<script src="script/ship.js"></script>
|
||||||
|
<script src="script/space.js"></script>
|
||||||
|
<!-- Event modules -->
|
||||||
|
<script src="script/events/global.js"></script>
|
||||||
|
<script src="script/events/room.js"></script>
|
||||||
|
<script src="script/events/outside.js"></script>
|
||||||
|
<script src="script/events/encounters.js"></script>
|
||||||
|
<script src="script/events/setpieces.js"></script>
|
||||||
|
|
||||||
|
<script type='text/javascript'>
|
||||||
|
var oldIE = false;
|
||||||
|
</script>
|
||||||
|
<!-- [if lt IE 9]>
|
||||||
|
<script type="text/javascript">oldIE = true;</script>
|
||||||
|
<![endif]-->
|
||||||
|
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/main.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/room.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/outside.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/path.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/world.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/ship.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/space.css" />
|
||||||
|
|
||||||
|
<!-- Google Analytics -->
|
||||||
|
<script>
|
||||||
|
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||||
|
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||||
|
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||||
|
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||||
|
|
||||||
|
ga('create', 'UA-41314886-1', 'doublespeakgames.com');
|
||||||
|
ga('send', 'pageview');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="wrapper">
|
||||||
|
<div id="saveNotify">saved.</div>
|
||||||
|
<div id="content">
|
||||||
|
<div id="outerSlider">
|
||||||
|
<div id="main">
|
||||||
|
<div id="header"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Vendored
+2
File diff suppressed because one or more lines are too long
@@ -0,0 +1,23 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>A Dark Room</title>
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
width: 960px;
|
||||||
|
margin: auto;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<strong>
|
||||||
|
A Dark Room isn't really mobile-friendly<br/>
|
||||||
|
Sorry about that!<br/>
|
||||||
|
</strong><br/>
|
||||||
|
Of course you can <a href='index.html?ignorebrowser=true'>play anyway</a>, but it probably won't work!
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
var Button = {
|
||||||
|
Button: function(options) {
|
||||||
|
if(typeof options.cooldown == 'number') {
|
||||||
|
this.data_cooldown = options.cooldown;
|
||||||
|
}
|
||||||
|
this.data_remaining = 0;
|
||||||
|
if(typeof options.click == 'function') {
|
||||||
|
this.data_handler = options.click;
|
||||||
|
}
|
||||||
|
|
||||||
|
var el = $('<div>')
|
||||||
|
.attr('id', typeof(options.id) != 'undefined' ? options.id : "BTN_" + Engine.getGuid())
|
||||||
|
.addClass('button')
|
||||||
|
.text(typeof(options.text) != 'undefined' ? options.text : "button")
|
||||||
|
.click(function() {
|
||||||
|
if(!$(this).hasClass('disabled')) {
|
||||||
|
Button.cooldown($(this));
|
||||||
|
$(this).data("handler")($(this));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.data("handler", typeof options.click == 'function' ? options.click : function() { Engine.log("click"); })
|
||||||
|
.data("remaining", 0)
|
||||||
|
.data("cooldown", typeof options.cooldown == 'number' ? options.cooldown : 0);
|
||||||
|
|
||||||
|
el.append($("<div>").addClass('cooldown'));
|
||||||
|
|
||||||
|
if(options.cost) {
|
||||||
|
var ttPos = options.ttPos ? options.ttPos : "bottom right";
|
||||||
|
var costTooltip = $('<div>').addClass('tooltip ' + ttPos);
|
||||||
|
for(var k in options.cost) {
|
||||||
|
$("<div>").addClass('row_key').text(k).appendTo(costTooltip);
|
||||||
|
$("<div>").addClass('row_val').text(options.cost[k]).appendTo(costTooltip);
|
||||||
|
}
|
||||||
|
if(costTooltip.children().length > 0) {
|
||||||
|
costTooltip.appendTo(el);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(options.width) {
|
||||||
|
el.css('width', options.width);
|
||||||
|
}
|
||||||
|
|
||||||
|
return el;
|
||||||
|
},
|
||||||
|
|
||||||
|
setDisabled: function(btn, disabled) {
|
||||||
|
if(btn) {
|
||||||
|
if(!disabled && !btn.data('onCooldown')) {
|
||||||
|
btn.removeClass('disabled');
|
||||||
|
} else if(disabled) {
|
||||||
|
btn.addClass('disabled');
|
||||||
|
}
|
||||||
|
btn.data('disabled', disabled);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
isDisabled: function(btn) {
|
||||||
|
if(btn) {
|
||||||
|
return btn.data('disabled') === true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
cooldown: function(btn) {
|
||||||
|
var cd = btn.data("cooldown");
|
||||||
|
if(cd > 0) {
|
||||||
|
$('div.cooldown', btn).stop(true, true).width("100%").animate({width: '0%'}, cd * 1000, 'linear', function() {
|
||||||
|
var b = $(this).closest('.button');
|
||||||
|
b.data('onCooldown', false);
|
||||||
|
if(!b.data('disabled')) {
|
||||||
|
b.removeClass('disabled');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
btn.addClass('disabled');
|
||||||
|
btn.data('onCooldown', true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
clearCooldown: function(btn) {
|
||||||
|
$('div.cooldown', btn).stop(true, true);
|
||||||
|
btn.data('onCooldown', false);
|
||||||
|
if(!btn.data('disabled')) {
|
||||||
|
btn.removeClass('disabled');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,550 @@
|
|||||||
|
var Engine = {
|
||||||
|
|
||||||
|
/* TODO *** MICHAEL IS A LAZY BASTARD AND DOES NOT WANT TO REFACTOR ***
|
||||||
|
* Here is what he should be doing:
|
||||||
|
* - All updating values (store numbers, incomes, etc...) should be objects that can register listeners to
|
||||||
|
* value-change events. These events should be fired whenever a value (or group of values, I suppose) is updated.
|
||||||
|
* That would be so elegant and awesome.
|
||||||
|
*/
|
||||||
|
SITE_URL: encodeURIComponent("http://adarkroom.doublespeakgames.com"),
|
||||||
|
MAX_STORE: 99999999999999,
|
||||||
|
SAVE_DISPLAY: 30 * 1000,
|
||||||
|
|
||||||
|
Perks: {
|
||||||
|
'boxer': {
|
||||||
|
desc: 'punches do more damage',
|
||||||
|
notify: 'learned to throw punches with purpose'
|
||||||
|
},
|
||||||
|
'martial artist': {
|
||||||
|
desc: 'punches do even more damage.',
|
||||||
|
notify: 'learned to fight quite effectively without weapons'
|
||||||
|
},
|
||||||
|
'unarmed master': {
|
||||||
|
desc: 'punch twice as fast, and with even more force',
|
||||||
|
notify: 'learned to strike faster without weapons'
|
||||||
|
},
|
||||||
|
'barbarian': {
|
||||||
|
desc: 'melee weapons deal more damage',
|
||||||
|
notify: 'learned to swing weapons with force'
|
||||||
|
},
|
||||||
|
'slow metabolism': {
|
||||||
|
desc: 'go twice as far without eating',
|
||||||
|
notify: 'learned how to ignore the hunger'
|
||||||
|
},
|
||||||
|
'desert rat': {
|
||||||
|
desc: 'go twice as far without drinking',
|
||||||
|
notify: 'learned to love the dry air'
|
||||||
|
},
|
||||||
|
'evasive': {
|
||||||
|
desc: 'dodge attacks more effectively',
|
||||||
|
notify: "learned to be where they're not"
|
||||||
|
},
|
||||||
|
'precise': {
|
||||||
|
desc: 'land blows more often',
|
||||||
|
notify: 'learned to predict their movement'
|
||||||
|
},
|
||||||
|
'scout': {
|
||||||
|
desc: 'see farther',
|
||||||
|
notify: 'learned to look ahead'
|
||||||
|
},
|
||||||
|
'stealthy': {
|
||||||
|
desc: 'better avoid conflict in the wild',
|
||||||
|
notify: 'learned how not to be seen'
|
||||||
|
},
|
||||||
|
'gastronome': {
|
||||||
|
desc: 'restore more health when eating',
|
||||||
|
notify: 'learned to make the most of food'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
options: {
|
||||||
|
state: null,
|
||||||
|
debug: false,
|
||||||
|
log: false
|
||||||
|
},
|
||||||
|
|
||||||
|
init: function(options) {
|
||||||
|
this.options = $.extend(
|
||||||
|
this.options,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
this._debug = this.options.debug;
|
||||||
|
this._log = this.options.log;
|
||||||
|
|
||||||
|
// Check for HTML5 support
|
||||||
|
if(!Engine.browserValid()) {
|
||||||
|
window.location = 'browserWarning.html';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for mobile
|
||||||
|
if(Engine.isMobile()) {
|
||||||
|
window.location = 'mobileWarning.html';
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.options.state != null) {
|
||||||
|
window.State = this.options.state;
|
||||||
|
} else {
|
||||||
|
Engine.loadGame();
|
||||||
|
}
|
||||||
|
|
||||||
|
$('<div>').attr('id', 'locationSlider').appendTo('#main');
|
||||||
|
|
||||||
|
$('<span>')
|
||||||
|
.addClass('deleteSave')
|
||||||
|
.text('restart.')
|
||||||
|
.click(Engine.confirmDelete)
|
||||||
|
.appendTo('body');
|
||||||
|
|
||||||
|
$('<div>')
|
||||||
|
.addClass('share')
|
||||||
|
.text('share.')
|
||||||
|
.click(Engine.share)
|
||||||
|
.appendTo('body');
|
||||||
|
|
||||||
|
// Register keypress handlers
|
||||||
|
$('body').off('keydown').keydown(Engine.keyDown);
|
||||||
|
$('body').off('keyup').keyup(Engine.keyUp);
|
||||||
|
|
||||||
|
Notifications.init();
|
||||||
|
Events.init();
|
||||||
|
Room.init();
|
||||||
|
|
||||||
|
if(Engine.storeAvailable('wood')) {
|
||||||
|
Outside.init();
|
||||||
|
}
|
||||||
|
if(Engine.getStore('compass') > 0) {
|
||||||
|
Path.init();
|
||||||
|
}
|
||||||
|
if(State.ship) {
|
||||||
|
Ship.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
Engine.travelTo(Room);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
browserValid: function() {
|
||||||
|
return location.search.indexOf('ignorebrowser=true') >= 0 || (
|
||||||
|
typeof Storage != 'undefined' &&
|
||||||
|
!oldIE);
|
||||||
|
},
|
||||||
|
|
||||||
|
isMobile: function() {
|
||||||
|
return location.search.indexOf('ignorebrowser=true') < 0 &&
|
||||||
|
/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent);
|
||||||
|
},
|
||||||
|
|
||||||
|
saveGame: function() {
|
||||||
|
if(typeof Storage != 'undefined' && localStorage) {
|
||||||
|
if(Engine._saveTimer != null) {
|
||||||
|
clearTimeout(Engine._saveTimer);
|
||||||
|
}
|
||||||
|
if(typeof Engine._lastNotify == 'undefined' || Date.now() - Engine._lastNotify > Engine.SAVE_DISPLAY){
|
||||||
|
$('#saveNotify').css('opacity', 1).animate({opacity: 0}, 1000, 'linear');
|
||||||
|
Engine._lastNotify = Date.now();
|
||||||
|
}
|
||||||
|
localStorage.gameState = JSON.stringify(State);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
loadGame: function() {
|
||||||
|
try {
|
||||||
|
var savedState = JSON.parse(localStorage.gameState);
|
||||||
|
if(savedState) {
|
||||||
|
State = savedState;
|
||||||
|
Engine.upgradeState();
|
||||||
|
Engine.log("loaded save!");
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
State = {
|
||||||
|
version: 1.2,
|
||||||
|
stores: {},
|
||||||
|
perks: {}
|
||||||
|
};
|
||||||
|
Engine.event('progress', 'new game');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
upgradeState: function() {
|
||||||
|
/* Use this function to make old
|
||||||
|
* save games compatible with newer versions */
|
||||||
|
if(typeof State.version != 'number') {
|
||||||
|
Engine.log('upgraded save to v1.0');
|
||||||
|
State.version = 1.0;
|
||||||
|
}
|
||||||
|
if(State.version == 1.0) {
|
||||||
|
// v1.1 introduced the Lodge, so get rid of lodgeless hunters
|
||||||
|
delete State.outside.workers.hunter;
|
||||||
|
delete State.income.hunter;
|
||||||
|
Engine.log('upgraded save to v1.1');
|
||||||
|
State.version = 1.1;
|
||||||
|
}
|
||||||
|
if(State.version == 1.1) {
|
||||||
|
//v1.2 added the Swamp to the map, so add it to already generated maps
|
||||||
|
if(State.world) {
|
||||||
|
World.placeLandmark(15, World.RADIUS * 1.5, World.TILE.SWAMP, State.world.map);
|
||||||
|
}
|
||||||
|
Engine.log('upgraded save to v1.2');
|
||||||
|
State.version = 1.2;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
event: function(cat, act) {
|
||||||
|
if(typeof ga === 'function') {
|
||||||
|
ga('send', 'event', cat, act);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
confirmDelete: function() {
|
||||||
|
Events.startEvent({
|
||||||
|
title: 'Restart?',
|
||||||
|
scenes: {
|
||||||
|
start: {
|
||||||
|
text: ['restart the game?'],
|
||||||
|
buttons: {
|
||||||
|
'yes': {
|
||||||
|
text: 'yes',
|
||||||
|
nextScene: 'end',
|
||||||
|
onChoose: Engine.deleteSave
|
||||||
|
},
|
||||||
|
'no': {
|
||||||
|
text: 'no',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteSave: function() {
|
||||||
|
if(typeof Storage != 'undefined' && localStorage) {
|
||||||
|
localStorage.clear();
|
||||||
|
}
|
||||||
|
location.reload();
|
||||||
|
},
|
||||||
|
|
||||||
|
share: function() {
|
||||||
|
Events.startEvent({
|
||||||
|
title: 'Share',
|
||||||
|
scenes: {
|
||||||
|
start: {
|
||||||
|
text: ['bring your friends.'],
|
||||||
|
buttons: {
|
||||||
|
'facebook': {
|
||||||
|
text: 'facebook',
|
||||||
|
nextScene: 'end',
|
||||||
|
onChoose: function() {
|
||||||
|
window.open('https://www.facebook.com/sharer/sharer.php?u=' + Engine.SITE_URL, 'sharer', 'width=626,height=436,location=no,menubar=no,resizable=no,scrollbars=no,status=no,toolbar=no');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'google': {
|
||||||
|
text:'google+',
|
||||||
|
nextScene: 'end',
|
||||||
|
onChoose: function() {
|
||||||
|
window.open('https://plus.google.com/share?url=' + Engine.SITE_URL, 'sharer', 'width=480,height=436,location=no,menubar=no,resizable=no,scrollbars=no,status=no,toolbar=no');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'twitter': {
|
||||||
|
text: 'twitter',
|
||||||
|
onChoose: function() {
|
||||||
|
window.open('https://twitter.com/intent/tweet?text=A%20Dark%20Room&url=' + Engine.SITE_URL, 'sharer', 'width=660,height=260,location=no,menubar=no,resizable=no,scrollbars=yes,status=no,toolbar=no');
|
||||||
|
},
|
||||||
|
nextScene: 'end'
|
||||||
|
},
|
||||||
|
'reddit': {
|
||||||
|
text: 'reddit',
|
||||||
|
onChoose: function() {
|
||||||
|
window.open('http://www.reddit.com/submit?url=' + Engine.SITE_URL, 'sharer', 'width=960,height=700,location=no,menubar=no,resizable=no,scrollbars=yes,status=no,toolbar=no');
|
||||||
|
},
|
||||||
|
nextScene: 'end'
|
||||||
|
},
|
||||||
|
'close': {
|
||||||
|
text: 'close',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {width: '400px'});
|
||||||
|
},
|
||||||
|
|
||||||
|
// Gets a guid
|
||||||
|
getGuid: function() {
|
||||||
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||||
|
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
|
||||||
|
return v.toString(16);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
activeModule: null,
|
||||||
|
|
||||||
|
travelTo: function(module) {
|
||||||
|
if(Engine.activeModule != module) {
|
||||||
|
var currentIndex = Engine.activeModule ? $('.location').index(Engine.activeModule.panel) : 1;
|
||||||
|
Engine.activeModule = module;
|
||||||
|
$('div.headerButton').removeClass('selected');
|
||||||
|
module.tab.addClass('selected');
|
||||||
|
|
||||||
|
var slider = $('#locationSlider');
|
||||||
|
var panelIndex = $('.location').index(module.panel);
|
||||||
|
var diff = Math.abs(panelIndex - currentIndex);
|
||||||
|
slider.animate({left: -(panelIndex * 700) + 'px'}, 300 * diff);
|
||||||
|
module.onArrival();
|
||||||
|
|
||||||
|
Notifications.printQueue(module);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addPerk: function(name) {
|
||||||
|
if(!State.perks) {
|
||||||
|
State.perks = {};
|
||||||
|
}
|
||||||
|
State.perks[name] = true;
|
||||||
|
Notifications.notify(null, Engine.Perks[name].notify);
|
||||||
|
if(Engine.activeModule == Path) {
|
||||||
|
Path.updatePerks();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
hasPerk: function(name) {
|
||||||
|
return typeof State.perks == 'object' && State.perks[name] == true;
|
||||||
|
},
|
||||||
|
|
||||||
|
setStore: function(name, number) {
|
||||||
|
if(typeof State.stores == 'undefined') {
|
||||||
|
State.stores = {};
|
||||||
|
}
|
||||||
|
if(number > Engine.MAX_STORE) number = Engine.MAX_STORE;
|
||||||
|
State.stores[name] = number;
|
||||||
|
Room.updateStoresView();
|
||||||
|
Room.updateBuildButtons();
|
||||||
|
if(State.outside) {
|
||||||
|
Outside.updateVillage();
|
||||||
|
}
|
||||||
|
Engine.saveGame();
|
||||||
|
},
|
||||||
|
|
||||||
|
setStores: function(list) {
|
||||||
|
if(typeof State.stores == 'undefined') {
|
||||||
|
State.stores = {};
|
||||||
|
}
|
||||||
|
for(k in list) {
|
||||||
|
State.stores[k] = list[k] > Engine.MAX_STORE ? Engine.MAX_STORE : list[k];
|
||||||
|
}
|
||||||
|
Room.updateStoresView();
|
||||||
|
Room.updateBuildButtons();
|
||||||
|
if(State.outside) {
|
||||||
|
Outside.updateVillage();
|
||||||
|
}
|
||||||
|
Engine.saveGame();
|
||||||
|
},
|
||||||
|
|
||||||
|
addStore: function(name, number) {
|
||||||
|
if(typeof State.stores == 'undefined') {
|
||||||
|
State.stores = {};
|
||||||
|
}
|
||||||
|
var num = State.stores[name];
|
||||||
|
if(typeof num != 'number' || isNaN(num) || num < 0) num = 0;
|
||||||
|
num += number;
|
||||||
|
if(num > Engine.MAX_STORE) num = Engine.MAX_STORE;
|
||||||
|
State.stores[name] = num;
|
||||||
|
Room.updateStoresView();
|
||||||
|
Room.updateBuildButtons();
|
||||||
|
Outside.updateVillage();
|
||||||
|
if(Engine.activeModule == Path) {
|
||||||
|
Path.updateOutfitting();
|
||||||
|
}
|
||||||
|
Engine.saveGame();
|
||||||
|
},
|
||||||
|
|
||||||
|
addStores: function(list, ignoreCosts) {
|
||||||
|
if(typeof State.stores == 'undefined') {
|
||||||
|
State.stores = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure any income costs can be paid
|
||||||
|
if(!ignoreCosts) {
|
||||||
|
for(k in list) {
|
||||||
|
var num = State.stores[k];
|
||||||
|
if(typeof num != 'number' || isNaN(num) || num < 0) num = 0;
|
||||||
|
if(num + list[k] < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actually do the update
|
||||||
|
for(k in list) {
|
||||||
|
var num = State.stores[k];
|
||||||
|
if(typeof num != 'number') num = 0;
|
||||||
|
num += list[k];
|
||||||
|
num = num < 0 ? 0 : num;
|
||||||
|
num = num > Engine.MAX_STORE ? Engine.MAX_STORE : num;
|
||||||
|
State.stores[k] = num;
|
||||||
|
}
|
||||||
|
Room.updateStoresView();
|
||||||
|
Room.updateBuildButtons();
|
||||||
|
Outside.updateVillage();
|
||||||
|
if(Engine.activeModule == Path) {
|
||||||
|
Path.updateOutfitting();
|
||||||
|
}
|
||||||
|
Engine.saveGame();
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
storeAvailable: function(name) {
|
||||||
|
return typeof State.stores[name] == 'number';
|
||||||
|
},
|
||||||
|
|
||||||
|
getStore: function(name) {
|
||||||
|
if(typeof State.stores == 'undefined' || typeof State.stores[name] == 'undefined' ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return State.stores[name];
|
||||||
|
},
|
||||||
|
|
||||||
|
setIncome: function(source, options) {
|
||||||
|
if(typeof State.income == 'undefined') {
|
||||||
|
State.income = {};
|
||||||
|
}
|
||||||
|
var existing = State.income[source];
|
||||||
|
if(typeof existing != 'undefined') {
|
||||||
|
options.timeLeft = existing.timeLeft;
|
||||||
|
}
|
||||||
|
State.income[source] = options;
|
||||||
|
},
|
||||||
|
|
||||||
|
getIncome: function(source) {
|
||||||
|
if(typeof State.income == 'undefined') {
|
||||||
|
State.income = {};
|
||||||
|
}
|
||||||
|
var existing = State.income[source];
|
||||||
|
if(typeof existing != 'undefined') {
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
|
||||||
|
removeIncome: function(source) {
|
||||||
|
if(State.income) {
|
||||||
|
delete State.income[source];
|
||||||
|
}
|
||||||
|
Room.updateIncomeView();
|
||||||
|
},
|
||||||
|
|
||||||
|
collectIncome: function() {
|
||||||
|
if(typeof State.income != 'undefined' && Engine.activeModule != Space) {
|
||||||
|
var changed = false;
|
||||||
|
for(var source in State.income) {
|
||||||
|
var income = State.income[source];
|
||||||
|
if(typeof income.timeLeft != 'number')
|
||||||
|
{
|
||||||
|
income.timeLeft = 0;
|
||||||
|
}
|
||||||
|
income.timeLeft--;
|
||||||
|
|
||||||
|
if(income.timeLeft <= 0) {
|
||||||
|
Engine.log('collection income from ' + source);
|
||||||
|
if(source == 'thieves') {
|
||||||
|
Engine.addStolen(income.stores);
|
||||||
|
}
|
||||||
|
changed = Engine.addStores(income.stores) || changed;
|
||||||
|
if(typeof income.delay == 'number') {
|
||||||
|
income.timeLeft = income.delay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(changed) {
|
||||||
|
Room.updateStoresView();
|
||||||
|
Room.updateBuildButtons();
|
||||||
|
Engine.saveGame();
|
||||||
|
if(Events.activeEvent() != null) {
|
||||||
|
Events.updateButtons();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Engine._incomeTimeout = setTimeout(Engine.collectIncome, 1000);
|
||||||
|
},
|
||||||
|
|
||||||
|
openPath: function() {
|
||||||
|
Path.init();
|
||||||
|
Engine.event('progress', 'path');
|
||||||
|
Notifications.notify(Room, 'the compass points ' + World.dir);
|
||||||
|
},
|
||||||
|
|
||||||
|
addStolen: function(stores) {
|
||||||
|
if(!State.stolen) State.stolen = {};
|
||||||
|
for(var k in stores) {
|
||||||
|
if(!State.stolen[k]) State.stolen[k] = 0;
|
||||||
|
State.stolen[k] -= stores[k];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
startThieves: function() {
|
||||||
|
State.thieves = 1;
|
||||||
|
Engine.setIncome('thieves', {
|
||||||
|
delay: 10,
|
||||||
|
stores: {
|
||||||
|
'wood': -10,
|
||||||
|
'fur': -5,
|
||||||
|
'meat': -5
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Room.updateIncomeView();
|
||||||
|
},
|
||||||
|
|
||||||
|
num: function(name, craftable) {
|
||||||
|
switch(craftable.type) {
|
||||||
|
case 'good':
|
||||||
|
case 'tool':
|
||||||
|
case 'weapon':
|
||||||
|
case 'upgrade':
|
||||||
|
return Engine.getStore(name);
|
||||||
|
case 'building':
|
||||||
|
return Outside.numBuilding(name);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
log: function(msg) {
|
||||||
|
if(this._log) {
|
||||||
|
console.log(msg);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
updateSlider: function() {
|
||||||
|
var slider = $('#locationSlider');
|
||||||
|
slider.width((slider.children().length * 700) + 'px');
|
||||||
|
},
|
||||||
|
|
||||||
|
updateOuterSlider: function() {
|
||||||
|
var slider = $('#outerSlider');
|
||||||
|
slider.width((slider.children().length * 700) + 'px');
|
||||||
|
},
|
||||||
|
|
||||||
|
getIncomeMsg: function(num, delay) {
|
||||||
|
return (num > 0 ? "+" : "") + num + " per " + delay + "s";
|
||||||
|
},
|
||||||
|
|
||||||
|
keyDown: function(e) {
|
||||||
|
if(!Engine.keyPressed && !Engine.keyLock) {
|
||||||
|
Engine.pressed = true;
|
||||||
|
if(Engine.activeModule.keyDown) {
|
||||||
|
Engine.activeModule.keyDown(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
keyUp: function(e) {
|
||||||
|
Engine.pressed = false;
|
||||||
|
if(Engine.activeModule.keyUp) {
|
||||||
|
Engine.activeModule.keyUp(e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
Engine.init();
|
||||||
|
});
|
||||||
@@ -0,0 +1,735 @@
|
|||||||
|
/**
|
||||||
|
* Module that handles the random event system
|
||||||
|
*/
|
||||||
|
var Events = {
|
||||||
|
|
||||||
|
_EVENT_TIME_RANGE: [3, 6], // range, in minutes
|
||||||
|
_PANEL_FADE: 200,
|
||||||
|
_FIGHT_SPEED: 100,
|
||||||
|
_EAT_COOLDOWN: 5,
|
||||||
|
STUN_DURATION: 4000,
|
||||||
|
|
||||||
|
init: function(options) {
|
||||||
|
this.options = $.extend(
|
||||||
|
this.options,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
|
||||||
|
// Build the Event Pool
|
||||||
|
Events.EventPool = new Array().concat(
|
||||||
|
Events.Global,
|
||||||
|
Events.Room,
|
||||||
|
Events.Outside
|
||||||
|
);
|
||||||
|
|
||||||
|
Events.eventStack = [];
|
||||||
|
|
||||||
|
Events.scheduleNextEvent();
|
||||||
|
},
|
||||||
|
|
||||||
|
options: {}, // Nothing for now
|
||||||
|
|
||||||
|
activeEvent: null,
|
||||||
|
activeScene: null,
|
||||||
|
eventPanel: null,
|
||||||
|
|
||||||
|
loadScene: function(name) {
|
||||||
|
Engine.log('loading scene: ' + name);
|
||||||
|
Events.activeScene = name;
|
||||||
|
var scene = Events.activeEvent().scenes[name];
|
||||||
|
|
||||||
|
// Scene reward
|
||||||
|
if(scene.reward) {
|
||||||
|
Engine.addStores(scene.reward, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// onLoad
|
||||||
|
if(scene.onLoad) {
|
||||||
|
scene.onLoad();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify the scene change
|
||||||
|
if(scene.notification) {
|
||||||
|
Notifications.notify(null, scene.notification);
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#description', Events.eventPanel()).empty();
|
||||||
|
$('#buttons', Events.eventPanel()).empty();
|
||||||
|
if(scene.combat) {
|
||||||
|
Events.startCombat(scene);
|
||||||
|
} else {
|
||||||
|
Events.startStory(scene);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
startCombat: function(scene) {
|
||||||
|
Engine.event('game event', 'combat');
|
||||||
|
Events.won = false;
|
||||||
|
var desc = $('#description', Events.eventPanel());
|
||||||
|
|
||||||
|
$('<div>').text(scene.notification).appendTo(desc);
|
||||||
|
|
||||||
|
// Draw the wanderer
|
||||||
|
Events.createFighterDiv('@', World.health, World.getMaxHealth()).attr('id', 'wanderer').appendTo(desc);
|
||||||
|
|
||||||
|
// Draw the enemy
|
||||||
|
Events.createFighterDiv(scene.char, scene.health, scene.health).attr('id', 'enemy').appendTo(desc);
|
||||||
|
|
||||||
|
// Draw the action buttons
|
||||||
|
var btns = $('#buttons', Events.eventPanel());
|
||||||
|
|
||||||
|
var numWeapons = 0;
|
||||||
|
for(var k in World.Weapons) {
|
||||||
|
var weapon = World.Weapons[k];
|
||||||
|
if(typeof Path.outfit[k] == 'number' && Path.outfit[k] > 0) {
|
||||||
|
if(typeof weapon.damage != 'number' || weapon.damage == 0) {
|
||||||
|
// Weapons that deal no damage don't count
|
||||||
|
numWeapons--;
|
||||||
|
} else if(weapon.cost){
|
||||||
|
for(var c in weapon.cost) {
|
||||||
|
var num = weapon.cost[c];
|
||||||
|
if(typeof Path.outfit[c] != 'number' || Path.outfit[c] < num) {
|
||||||
|
// Can't use this weapon, so don't count it
|
||||||
|
numWeapons--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
numWeapons++;
|
||||||
|
Events.createAttackButton(k).appendTo(btns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(numWeapons == 0) {
|
||||||
|
// No weapons? You can punch stuff!
|
||||||
|
Events.createAttackButton('fists').prependTo(btns);
|
||||||
|
}
|
||||||
|
|
||||||
|
var eat = new Button.Button({
|
||||||
|
id: 'eat',
|
||||||
|
text: 'eat meat',
|
||||||
|
cooldown: Events._EAT_COOLDOWN,
|
||||||
|
click: Events.eatMeat,
|
||||||
|
cost: { 'cured meat': 1 }
|
||||||
|
}).appendTo(btns);
|
||||||
|
|
||||||
|
if(Path.outfit['cured meat'] == 0) {
|
||||||
|
Button.setDisabled(eat, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up the enemy attack timer
|
||||||
|
Events._enemyAttackTimer = setTimeout(Events.enemyAttack, scene.attackDelay * 1000);
|
||||||
|
},
|
||||||
|
|
||||||
|
createAttackButton: function(weaponName) {
|
||||||
|
var weapon = World.Weapons[weaponName];
|
||||||
|
var cd = weapon.cooldown;
|
||||||
|
if(weapon.type == 'unarmed') {
|
||||||
|
if(Engine.hasPerk('unarmed master')) {
|
||||||
|
cd /= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var btn = new Button.Button({
|
||||||
|
id: 'attack_' + weaponName.replace(' ', '-'),
|
||||||
|
text: weapon.verb,
|
||||||
|
cooldown: cd,
|
||||||
|
click: Events.useWeapon,
|
||||||
|
cost: weapon.cost
|
||||||
|
});
|
||||||
|
if(typeof weapon.damage == 'number' && weapon.damage > 0) {
|
||||||
|
btn.addClass('weaponButton');
|
||||||
|
}
|
||||||
|
|
||||||
|
for(var k in weapon.cost) {
|
||||||
|
if(typeof Path.outfit[k] != 'number' || Path.outfit[k] < weapon.cost[k]) {
|
||||||
|
Button.setDisabled(btn, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return btn;
|
||||||
|
},
|
||||||
|
|
||||||
|
drawFloatText: function(text, parent) {
|
||||||
|
$('<div>').text(text).addClass('damageText').appendTo(parent).animate({
|
||||||
|
'bottom': '50px',
|
||||||
|
'opacity': '0'
|
||||||
|
},
|
||||||
|
300,
|
||||||
|
'linear',
|
||||||
|
function() {
|
||||||
|
$(this).remove();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
eatMeat: function() {
|
||||||
|
if(Events.activeEvent() && Path.outfit['cured meat'] > 0) {
|
||||||
|
Path.outfit['cured meat']--;
|
||||||
|
World.updateSupplies();
|
||||||
|
if(Path.outfit['cured meat'] == 0) {
|
||||||
|
Button.setDisabled($('#eat'), true);
|
||||||
|
}
|
||||||
|
var w = $('#wanderer');
|
||||||
|
var hp = w.data('hp');
|
||||||
|
hp += World.meatHeal();
|
||||||
|
hp = hp > World.getMaxHealth() ? World.getMaxHealth() : hp;
|
||||||
|
w.data('hp', hp);
|
||||||
|
World.setHp(hp);
|
||||||
|
Events.updateFighterDiv(w);
|
||||||
|
Events.drawFloatText('+' + World.meatHeal(), '#wanderer .hp');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
useWeapon: function(btn) {
|
||||||
|
if(Events.activeEvent()) {
|
||||||
|
var weaponName = btn.attr('id').substring(7).replace('-', ' ');
|
||||||
|
var weapon = World.Weapons[weaponName];
|
||||||
|
if(weapon.type == 'unarmed') {
|
||||||
|
if(!State.punches) State.punches = 0;
|
||||||
|
State.punches++;
|
||||||
|
if(State.punches == 50 && !Engine.hasPerk('boxer')) {
|
||||||
|
Engine.addPerk('boxer');
|
||||||
|
} else if(State.punches == 150 && !Engine.hasPerk('martial artist')) {
|
||||||
|
Engine.addPerk('martial artist');
|
||||||
|
} else if(State.punches == 300 && !Engine.hasPerk('unarmed master')) {
|
||||||
|
Engine.addPerk('unarmed master');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if(weapon.cost) {
|
||||||
|
var mod = {};
|
||||||
|
var out = false;
|
||||||
|
for(var k in weapon.cost) {
|
||||||
|
if(typeof Path.outfit[k] != 'number' || Path.outfit[k] < weapon.cost[k]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mod[k] = -weapon.cost[k];
|
||||||
|
if(Path.outfit[k] - weapon.cost[k] < weapon.cost[k]) {
|
||||||
|
out = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(var k in mod) {
|
||||||
|
Path.outfit[k] += mod[k];
|
||||||
|
}
|
||||||
|
if(out) {
|
||||||
|
Button.setDisabled(btn, true);
|
||||||
|
var validWeapons = false;
|
||||||
|
$('.weaponButton').each(function(){
|
||||||
|
if(!Button.isDisabled($(this)) && $(this).attr('id') != 'attack_fists') {
|
||||||
|
validWeapons = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(!validWeapons) {
|
||||||
|
// enable or create the punch button
|
||||||
|
var fists = $('#attack_fists');
|
||||||
|
if(fists.length == 0) {
|
||||||
|
Events.createAttackButton('fists').prependTo('#buttons', Events.eventPanel());
|
||||||
|
} else {
|
||||||
|
Button.setDisabled(fists, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
World.updateSupplies();
|
||||||
|
}
|
||||||
|
var dmg = -1;
|
||||||
|
if(Math.random() <= World.getHitChance()) {
|
||||||
|
dmg = weapon.damage;
|
||||||
|
if(typeof dmg == 'number') {
|
||||||
|
if(weapon.type == 'unarmed' && Engine.hasPerk('boxer')) {
|
||||||
|
dmg *= 2
|
||||||
|
}
|
||||||
|
if(weapon.type == 'unarmed' && Engine.hasPerk('martial artist')) {
|
||||||
|
dmg *= 3;
|
||||||
|
}
|
||||||
|
if(weapon.type == 'unarmed' && Engine.hasPerk('unarmed master')) {
|
||||||
|
dmg *= 2;
|
||||||
|
}
|
||||||
|
if(weapon.type == 'melee' && Engine.hasPerk('barbarian')) {
|
||||||
|
dmg = Math.floor(dmg * 1.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var attackFn = weapon.type == 'ranged' ? Events.animateRanged : Events.animateMelee;
|
||||||
|
attackFn($('#wanderer'), dmg, function() {
|
||||||
|
if($('#enemy').data('hp') <= 0 && !Events.won) {
|
||||||
|
// Success!
|
||||||
|
Events.winFight();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
animateMelee: function(fighter, dmg, callback) {
|
||||||
|
var start, end, enemy;
|
||||||
|
if(fighter.attr('id') == 'wanderer') {
|
||||||
|
start = {'left': '50%'};
|
||||||
|
end = {'left': '25%'};
|
||||||
|
enemy = $('#enemy');
|
||||||
|
} else {
|
||||||
|
start = {'right': '50%'};
|
||||||
|
end = {'right': '25%'};
|
||||||
|
enemy = $('#wanderer');
|
||||||
|
}
|
||||||
|
|
||||||
|
fighter.stop(true, true).animate(start, Events._FIGHT_SPEED, function() {
|
||||||
|
var enemyHp = enemy.data('hp');
|
||||||
|
var msg;
|
||||||
|
if(typeof dmg == 'number') {
|
||||||
|
if(dmg < 0) {
|
||||||
|
msg = 'miss';
|
||||||
|
dmg = 0;
|
||||||
|
} else {
|
||||||
|
msg = '-' + dmg;
|
||||||
|
enemyHp -= dmg;
|
||||||
|
enemy.data('hp', enemyHp);
|
||||||
|
if(fighter.attr('id') == 'enemy') {
|
||||||
|
World.setHp(enemyHp);
|
||||||
|
}
|
||||||
|
Events.updateFighterDiv(enemy);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(dmg == 'stun') {
|
||||||
|
msg = 'stunned';
|
||||||
|
enemy.data('stunned', true);
|
||||||
|
setTimeout(function() {
|
||||||
|
enemy.data('stunned', false);
|
||||||
|
}, Events.STUN_DURATION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Events.drawFloatText(msg, $('.hp', enemy));
|
||||||
|
|
||||||
|
$(this).animate(end, Events._FIGHT_SPEED, callback);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
animateRanged: function(fighter, dmg, callback) {
|
||||||
|
var start, end, enemy;
|
||||||
|
if(fighter.attr('id') == 'wanderer') {
|
||||||
|
start = {'left': '25%'};
|
||||||
|
end = {'left': '50%'};
|
||||||
|
enemy = $('#enemy');
|
||||||
|
} else {
|
||||||
|
start = {'right': '25%'};
|
||||||
|
end = {'right': '50%'};
|
||||||
|
enemy = $('#wanderer');
|
||||||
|
}
|
||||||
|
|
||||||
|
$('<div>').css(start).addClass('bullet').text('o').appendTo('#description')
|
||||||
|
.animate(end, Events._FIGHT_SPEED * 2, 'linear', function() {
|
||||||
|
var enemyHp = enemy.data('hp');
|
||||||
|
var msg;
|
||||||
|
if(typeof dmg == 'number') {
|
||||||
|
if(dmg < 0) {
|
||||||
|
msg = 'miss';
|
||||||
|
dmg = 0;
|
||||||
|
} else {
|
||||||
|
msg = '-' + dmg;
|
||||||
|
enemyHp -= dmg;
|
||||||
|
enemy.data('hp', enemyHp);
|
||||||
|
if(fighter.attr('id') == 'enemy') {
|
||||||
|
World.setHp(enemyHp);
|
||||||
|
}
|
||||||
|
Events.updateFighterDiv(enemy);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(dmg == 'stun') {
|
||||||
|
msg = 'stunned';
|
||||||
|
enemy.data('stunned', true);
|
||||||
|
setTimeout(function() {
|
||||||
|
enemy.data('stunned', false);
|
||||||
|
}, Events.STUN_DURATION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Events.drawFloatText(msg, $('.hp', enemy));
|
||||||
|
|
||||||
|
$(this).remove();
|
||||||
|
if(typeof callback == 'function') {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
enemyAttack: function() {
|
||||||
|
|
||||||
|
var scene = Events.activeEvent().scenes[Events.activeScene];
|
||||||
|
|
||||||
|
if(!$('#enemy').data('stunned')) {
|
||||||
|
var toHit = scene.hit;
|
||||||
|
toHit *= Engine.hasPerk('evasive') ? 0.8 : 1;
|
||||||
|
var dmg = -1;
|
||||||
|
if(Math.random() <= toHit) {
|
||||||
|
dmg = scene.damage;
|
||||||
|
}
|
||||||
|
|
||||||
|
var attackFn = scene.ranged ? Events.animateRanged : Events.animateMelee;
|
||||||
|
|
||||||
|
attackFn($('#enemy'), dmg, function() {
|
||||||
|
if($('#wanderer').data('hp') <= 0) {
|
||||||
|
// Failure!
|
||||||
|
clearTimeout(Events._enemyAttackTimer);
|
||||||
|
Events.endEvent();
|
||||||
|
World.die();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Events._enemyAttackTimer =
|
||||||
|
setTimeout(Events.enemyAttack, scene.attackDelay * 1000);
|
||||||
|
},
|
||||||
|
|
||||||
|
winFight: function() {
|
||||||
|
Events.won = true;
|
||||||
|
clearTimeout(Events._enemyAttackTimer);
|
||||||
|
$('#enemy').animate({opacity: 0}, 300, 'linear', function() {
|
||||||
|
setTimeout(function() {
|
||||||
|
try {
|
||||||
|
var scene = Events.activeEvent().scenes[Events.activeScene];
|
||||||
|
var desc = $('#description', Events.eventPanel());
|
||||||
|
var btns = $('#buttons', Events.eventPanel());
|
||||||
|
desc.empty();
|
||||||
|
btns.empty();
|
||||||
|
$('<div>').text('the ' + scene.enemy + (scene.plural ? ' are' : ' is') + ' dead.').appendTo(desc);
|
||||||
|
|
||||||
|
Events.drawLoot(scene.loot);
|
||||||
|
|
||||||
|
if(scene.buttons) {
|
||||||
|
// Draw the buttons
|
||||||
|
Events.drawButtons(scene);
|
||||||
|
} else {
|
||||||
|
new Button.Button({
|
||||||
|
id: 'leaveBtn',
|
||||||
|
click: function() {
|
||||||
|
var scene = Events.activeEvent().scenes[Events.activeScene];
|
||||||
|
if(scene.nextScene && scene.nextScene != 'end') {
|
||||||
|
Events.loadScene(scene.nextScene);
|
||||||
|
} else {
|
||||||
|
Events.endEvent();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
text: 'leave'
|
||||||
|
}).appendTo(btns);
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
// It is possible to die and win if the timing is perfect. Just let it fail.
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
drawLoot: function(lootList) {
|
||||||
|
var desc = $('#description', Events.eventPanel());
|
||||||
|
var lootButtons = $('<div>').attr('id', 'lootButtons');
|
||||||
|
for(var k in lootList) {
|
||||||
|
var loot = lootList[k];
|
||||||
|
if(Math.random() < loot.chance) {
|
||||||
|
var num = Math.floor(Math.random() * (loot.max - loot.min)) + loot.min;
|
||||||
|
new Button.Button({
|
||||||
|
id: 'loot_' + k.replace(' ', '-'),
|
||||||
|
text: k + ' [' + num + ']',
|
||||||
|
click: Events.getLoot
|
||||||
|
}).data('numLeft', num).appendTo(lootButtons);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$('<div>').addClass('clear').appendTo(lootButtons);
|
||||||
|
if(lootButtons.children().length > 1) {
|
||||||
|
lootButtons.appendTo(desc);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
dropStuff: function(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
var btn = $(this)
|
||||||
|
var thing = btn.data('thing');
|
||||||
|
var num = btn.data('num');
|
||||||
|
var lootButtons = $('#lootButtons');
|
||||||
|
Engine.log('dropping ' + num + ' ' + thing);
|
||||||
|
|
||||||
|
var lootBtn = $('#loot_' + thing.replace(' ', '-'), lootButtons);
|
||||||
|
if(lootBtn.length > 0) {
|
||||||
|
var curNum = lootBtn.data('numLeft');
|
||||||
|
curNum += num;
|
||||||
|
lootBtn.text(thing + ' [' + curNum + ']').data('numLeft', curNum);
|
||||||
|
} else {
|
||||||
|
new Button.Button({
|
||||||
|
id: 'loot_' + thing.replace(' ', '-'),
|
||||||
|
text: thing + ' [' + num + ']',
|
||||||
|
click: Events.getLoot
|
||||||
|
}).data('numLeft', num).insertBefore($('.clear', lootButtons));
|
||||||
|
}
|
||||||
|
Path.outfit[thing] -= num;
|
||||||
|
Events.getLoot(btn.closest('.button'));
|
||||||
|
World.updateSupplies();
|
||||||
|
$('#dropMenu').remove();
|
||||||
|
},
|
||||||
|
|
||||||
|
getLoot: function(btn) {
|
||||||
|
var name = btn.attr('id').substring(5).replace('-', ' ');
|
||||||
|
if(btn.data('numLeft') > 0) {
|
||||||
|
var weight = Path.getWeight(name);
|
||||||
|
var freeSpace = Path.getFreeSpace();
|
||||||
|
if(weight <= freeSpace) {
|
||||||
|
var loot = Events.activeEvent().scenes[Events.activeScene].loot[name];
|
||||||
|
var num = btn.data('numLeft');
|
||||||
|
num--;
|
||||||
|
btn.data('numLeft', num);
|
||||||
|
if(num == 0) {
|
||||||
|
Button.setDisabled(btn);
|
||||||
|
btn.animate({'opacity':0}, 300, 'linear', function() {
|
||||||
|
$(this).remove();
|
||||||
|
if($('#lootButtons').children().length == 1) {
|
||||||
|
$('#lootButtons').remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
btn.text(name + ' [' + num + ']');
|
||||||
|
}
|
||||||
|
var curNum = Path.outfit[name];
|
||||||
|
curNum = typeof curNum == 'number' ? curNum : 0;
|
||||||
|
curNum++;
|
||||||
|
Path.outfit[name] = curNum;
|
||||||
|
World.updateSupplies();
|
||||||
|
} else {
|
||||||
|
// Draw the drop menu
|
||||||
|
Engine.log('drop menu');
|
||||||
|
$('#dropMenu').remove();
|
||||||
|
var dropMenu = $('<div>').attr('id', 'dropMenu');
|
||||||
|
for(var k in Path.outfit) {
|
||||||
|
var itemWeight = Path.getWeight(k);
|
||||||
|
if(itemWeight > 0) {
|
||||||
|
var numToDrop = Math.ceil((weight - freeSpace) / itemWeight);
|
||||||
|
if(numToDrop > Path.outfit[k]) {
|
||||||
|
numToDrop = Path.outfit[k];
|
||||||
|
}
|
||||||
|
if(numToDrop > 0) {
|
||||||
|
var dropRow = $('<div>').attr('id', 'drop_' + k.replace(' ', '-'))
|
||||||
|
.text(k + ' x' + numToDrop)
|
||||||
|
.data('thing', k)
|
||||||
|
.data('num', numToDrop)
|
||||||
|
.click(Events.dropStuff);
|
||||||
|
dropRow.appendTo(dropMenu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dropMenu.appendTo(btn);
|
||||||
|
btn.one("mouseleave", function() {
|
||||||
|
$('#dropMenu').remove();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
createFighterDiv: function(char, hp, maxhp) {
|
||||||
|
var fighter = $('<div>').addClass('fighter').text(char).data('hp', hp).data('maxHp', maxhp);
|
||||||
|
$('<div>').addClass('hp').text(hp+'/'+maxhp).appendTo(fighter);
|
||||||
|
return fighter;
|
||||||
|
},
|
||||||
|
|
||||||
|
updateFighterDiv: function(fighter) {
|
||||||
|
$('.hp', fighter).text(fighter.data('hp') + '/' + fighter.data('maxHp'));
|
||||||
|
},
|
||||||
|
|
||||||
|
startStory: function(scene) {
|
||||||
|
// Write the text
|
||||||
|
var desc = $('#description', Events.eventPanel());
|
||||||
|
for(var i in scene.text) {
|
||||||
|
$('<div>').text(scene.text[i]).appendTo(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw any loot
|
||||||
|
if(scene.loot) {
|
||||||
|
Events.drawLoot(scene.loot);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the buttons
|
||||||
|
Events.drawButtons(scene);
|
||||||
|
},
|
||||||
|
|
||||||
|
drawButtons: function(scene) {
|
||||||
|
var btns = $('#buttons', Events.eventPanel());
|
||||||
|
for(var id in scene.buttons) {
|
||||||
|
var info = scene.buttons[id];
|
||||||
|
var b = new Button.Button({
|
||||||
|
id: id,
|
||||||
|
text: info.text,
|
||||||
|
cost: info.cost,
|
||||||
|
click: Events.buttonClick
|
||||||
|
}).appendTo(btns);
|
||||||
|
if(typeof info.available == 'function' && !info.available()) {
|
||||||
|
Button.setDisabled(b, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Events.updateButtons();
|
||||||
|
},
|
||||||
|
|
||||||
|
updateButtons: function() {
|
||||||
|
var btns = Events.activeEvent().scenes[Events.activeScene].buttons;
|
||||||
|
for(var bId in btns) {
|
||||||
|
var b = btns[bId];
|
||||||
|
var btnEl = $('#'+bId, Events.eventPanel());
|
||||||
|
if(typeof b.available == 'function' && !b.available()) {
|
||||||
|
Button.setDisabled(btnEl, true);
|
||||||
|
} else if(b.cost) {
|
||||||
|
var disabled = false;
|
||||||
|
for(var store in b.cost) {
|
||||||
|
var num = Engine.activeModule == World ? Path.outfit[store] : Engine.getStore(store);
|
||||||
|
if(typeof num != 'number') num = 0;
|
||||||
|
if(num < b.cost[store]) {
|
||||||
|
// Too expensive
|
||||||
|
disabled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button.setDisabled(btnEl, disabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
buttonClick: function(btn) {
|
||||||
|
var info = Events.activeEvent().scenes[Events.activeScene].buttons[btn.attr('id')];
|
||||||
|
// Cost
|
||||||
|
var costMod = {};
|
||||||
|
if(info.cost) {
|
||||||
|
for(var store in info.cost) {
|
||||||
|
var num = Engine.activeModule == World ? Path.outfit[store] : Engine.getStore(store);
|
||||||
|
if(typeof num != 'number') num = 0;
|
||||||
|
if(num < info.cost[store]) {
|
||||||
|
// Too expensive
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
costMod[store] = -info.cost[store];
|
||||||
|
}
|
||||||
|
if(Engine.activeModule == World) {
|
||||||
|
for(var k in costMod) {
|
||||||
|
Path.outfit[k] += costMod[k];
|
||||||
|
}
|
||||||
|
World.updateSupplies();
|
||||||
|
} else {
|
||||||
|
Engine.addStores(costMod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(typeof info.onChoose == 'function') {
|
||||||
|
info.onChoose();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reward
|
||||||
|
if(info.reward) {
|
||||||
|
Engine.addStores(info.reward);
|
||||||
|
}
|
||||||
|
|
||||||
|
Events.updateButtons();
|
||||||
|
|
||||||
|
// Notification
|
||||||
|
if(info.notification) {
|
||||||
|
Notifications.notify(null, info.notification);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next Scene
|
||||||
|
if(info.nextScene) {
|
||||||
|
if(info.nextScene == 'end') {
|
||||||
|
Events.endEvent();
|
||||||
|
} else {
|
||||||
|
var r = Math.random();
|
||||||
|
var lowestMatch = null;
|
||||||
|
for(var i in info.nextScene) {
|
||||||
|
if(r < i && (lowestMatch == null || i < lowestMatch)) {
|
||||||
|
lowestMatch = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(lowestMatch != null) {
|
||||||
|
Events.loadScene(info.nextScene[lowestMatch]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Engine.log('ERROR: no suitable scene found');
|
||||||
|
Events.endEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Makes an event happen!
|
||||||
|
triggerEvent: function() {
|
||||||
|
if(Events.activeEvent() == null) {
|
||||||
|
var possibleEvents = [];
|
||||||
|
for(var i in Events.EventPool) {
|
||||||
|
var event = Events.EventPool[i];
|
||||||
|
if(event.isAvailable()) {
|
||||||
|
possibleEvents.push(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(possibleEvents.length == 0) {
|
||||||
|
Events.scheduleNextEvent(0.5);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
var r = Math.floor(Math.random()*(possibleEvents.length));
|
||||||
|
Events.startEvent(possibleEvents[r]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Events.scheduleNextEvent();
|
||||||
|
},
|
||||||
|
|
||||||
|
triggerFight: function() {
|
||||||
|
var possibleFights = [];
|
||||||
|
for(var i in Events.Encounters) {
|
||||||
|
var fight = Events.Encounters[i];
|
||||||
|
if(fight.isAvailable()) {
|
||||||
|
possibleFights.push(fight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r = Math.floor(Math.random()*(possibleFights.length));
|
||||||
|
Events.startEvent(possibleFights[r]);
|
||||||
|
},
|
||||||
|
|
||||||
|
activeEvent: function() {
|
||||||
|
if(Events.eventStack && Events.eventStack.length > 0) {
|
||||||
|
return Events.eventStack[0];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
eventPanel: function() {
|
||||||
|
return Events.activeEvent().eventPanel;
|
||||||
|
},
|
||||||
|
|
||||||
|
startEvent: function(event, options) {
|
||||||
|
if(event) {
|
||||||
|
Engine.event('game event', 'event');
|
||||||
|
Engine.keyLock = true;
|
||||||
|
Events.eventStack.unshift(event);
|
||||||
|
event.eventPanel = $('<div>').attr('id', 'event').addClass('eventPanel').css('opacity', '0');
|
||||||
|
if(options != null && options.width != null) {
|
||||||
|
Events.eventPanel().css('width', options.width);
|
||||||
|
}
|
||||||
|
$('<div>').addClass('eventTitle').text(Events.activeEvent().title).appendTo(Events.eventPanel());
|
||||||
|
$('<div>').attr('id', 'description').appendTo(Events.eventPanel());
|
||||||
|
$('<div>').attr('id', 'buttons').appendTo(Events.eventPanel());
|
||||||
|
Events.loadScene('start');
|
||||||
|
$('div#wrapper').append(Events.eventPanel());
|
||||||
|
Events.eventPanel().animate({opacity: 1}, Events._PANEL_FADE, 'linear');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
scheduleNextEvent: function(scale) {
|
||||||
|
var nextEvent = Math.floor(Math.random()*(Events._EVENT_TIME_RANGE[1] - Events._EVENT_TIME_RANGE[0])) + Events._EVENT_TIME_RANGE[0];
|
||||||
|
if(scale > 0) { nextEvent *= scale }
|
||||||
|
Engine.log('next event scheduled in ' + nextEvent + ' minutes');
|
||||||
|
Events._eventTimeout = setTimeout(Events.triggerEvent, nextEvent * 60 * 1000);
|
||||||
|
},
|
||||||
|
|
||||||
|
endEvent: function() {
|
||||||
|
Events.eventPanel().animate({opacity:0}, Events._PANEL_FADE, 'linear', function() {
|
||||||
|
Events.eventPanel().remove();
|
||||||
|
Events.activeEvent().eventPanel = null;
|
||||||
|
Events.eventStack.shift();
|
||||||
|
Engine.log(Events.eventStack.length + ' events remaining');
|
||||||
|
Engine.keyLock = false;
|
||||||
|
// Force refocus on the body. I hate you, IE.
|
||||||
|
$('body').focus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,325 @@
|
|||||||
|
/**
|
||||||
|
* Events that can occur when wandering around the world
|
||||||
|
**/
|
||||||
|
Events.Encounters = [
|
||||||
|
/* Tier 1 */
|
||||||
|
{ /* Snarling Beast */
|
||||||
|
title: 'A Snarling Beast',
|
||||||
|
isAvailable: function() {
|
||||||
|
return World.getDistance() <= 10 && World.getTerrain() == World.TILE.FOREST;
|
||||||
|
},
|
||||||
|
scenes: {
|
||||||
|
'start': {
|
||||||
|
combat: true,
|
||||||
|
enemy: 'snarling beast',
|
||||||
|
char: 'B',
|
||||||
|
damage: 1,
|
||||||
|
hit: 0.8,
|
||||||
|
attackDelay: 1,
|
||||||
|
health: 5,
|
||||||
|
loot: {
|
||||||
|
'fur': {
|
||||||
|
min: 1,
|
||||||
|
max: 3,
|
||||||
|
chance: 1
|
||||||
|
},
|
||||||
|
'meat': {
|
||||||
|
min: 1,
|
||||||
|
max: 3,
|
||||||
|
chance: 1
|
||||||
|
},
|
||||||
|
'teeth': {
|
||||||
|
min: 1,
|
||||||
|
max: 3,
|
||||||
|
chance: 0.8
|
||||||
|
}
|
||||||
|
},
|
||||||
|
notification: 'a snarling beast leaps out of the underbrush'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ /* Gaunt Man */
|
||||||
|
title: 'A Gaunt Man',
|
||||||
|
isAvailable: function() {
|
||||||
|
return World.getDistance() <= 10 && World.getTerrain() == World.TILE.BARRENS;
|
||||||
|
},
|
||||||
|
scenes: {
|
||||||
|
'start': {
|
||||||
|
combat: true,
|
||||||
|
enemy: 'gaunt man',
|
||||||
|
char: 'G',
|
||||||
|
damage: 2,
|
||||||
|
hit: 0.8,
|
||||||
|
attackDelay: 2,
|
||||||
|
health: 6,
|
||||||
|
loot: {
|
||||||
|
'cloth': {
|
||||||
|
min: 1,
|
||||||
|
max: 3,
|
||||||
|
chance: 0.8
|
||||||
|
},
|
||||||
|
'teeth': {
|
||||||
|
min: 1,
|
||||||
|
max: 2,
|
||||||
|
chance: 0.8
|
||||||
|
},
|
||||||
|
'leather': {
|
||||||
|
min: 1,
|
||||||
|
max: 2,
|
||||||
|
chance: 0.5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
notification: 'a gaunt man approaches, a crazed look in his eye'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ /* Strange Bird */
|
||||||
|
title: 'A Strange Bird',
|
||||||
|
isAvailable: function() {
|
||||||
|
return World.getDistance() <= 10 && World.getTerrain() == World.TILE.FIELD;
|
||||||
|
},
|
||||||
|
scenes: {
|
||||||
|
'start': {
|
||||||
|
combat: true,
|
||||||
|
enemy: 'strange bird',
|
||||||
|
char: 'B',
|
||||||
|
damage: 3,
|
||||||
|
hit: 0.8,
|
||||||
|
attackDelay: 2,
|
||||||
|
health: 4,
|
||||||
|
loot: {
|
||||||
|
'scales': {
|
||||||
|
min: 1,
|
||||||
|
max: 3,
|
||||||
|
chance: 0.8
|
||||||
|
},
|
||||||
|
'teeth': {
|
||||||
|
min: 1,
|
||||||
|
max: 2,
|
||||||
|
chance: 0.5
|
||||||
|
},
|
||||||
|
'meat': {
|
||||||
|
min: 1,
|
||||||
|
max: 3,
|
||||||
|
chance: 0.8
|
||||||
|
}
|
||||||
|
},
|
||||||
|
notification: 'a strange looking bird speeds across the plains'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/* Tier 2*/
|
||||||
|
{ /* Man-eater */
|
||||||
|
title: 'A Man-Eater',
|
||||||
|
isAvailable: function() {
|
||||||
|
return World.getDistance() > 10 && World.getDistance() <= 20 && World.getTerrain() == World.TILE.FOREST;
|
||||||
|
},
|
||||||
|
scenes: {
|
||||||
|
'start': {
|
||||||
|
combat: true,
|
||||||
|
enemy: 'man-eater',
|
||||||
|
char: 'E',
|
||||||
|
damage: 3,
|
||||||
|
hit: 0.8,
|
||||||
|
attackDelay: 1,
|
||||||
|
health: 25,
|
||||||
|
loot: {
|
||||||
|
'fur': {
|
||||||
|
min: 5,
|
||||||
|
max: 10,
|
||||||
|
chance: 1
|
||||||
|
},
|
||||||
|
'meat': {
|
||||||
|
min: 5,
|
||||||
|
max: 10,
|
||||||
|
chance: 1
|
||||||
|
},
|
||||||
|
'teeth': {
|
||||||
|
min: 5,
|
||||||
|
max: 10,
|
||||||
|
chance: 0.8
|
||||||
|
}
|
||||||
|
},
|
||||||
|
notification: 'a large creature attacks, claws freshly bloodied'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ /* Scavenger */
|
||||||
|
title: 'A Scavenger',
|
||||||
|
isAvailable: function() {
|
||||||
|
return World.getDistance() > 10 && World.getDistance() <= 20 && World.getTerrain() == World.TILE.BARRENS;
|
||||||
|
},
|
||||||
|
scenes: {
|
||||||
|
'start': {
|
||||||
|
combat: true,
|
||||||
|
enemy: 'scavenger',
|
||||||
|
char: 'S',
|
||||||
|
damage: 4,
|
||||||
|
hit: 0.8,
|
||||||
|
attackDelay: 2,
|
||||||
|
health: 30,
|
||||||
|
loot: {
|
||||||
|
'cloth': {
|
||||||
|
min: 5,
|
||||||
|
max: 10,
|
||||||
|
chance: 0.8
|
||||||
|
},
|
||||||
|
'leather': {
|
||||||
|
min: 5,
|
||||||
|
max: 10,
|
||||||
|
chance: 0.8
|
||||||
|
},
|
||||||
|
'iron': {
|
||||||
|
min: 1,
|
||||||
|
max: 5,
|
||||||
|
chance: 0.5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
notification: 'a scavenger draws close, hoping for an easy score'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ /* Huge Lizard */
|
||||||
|
title: 'A Huge Lizard',
|
||||||
|
isAvailable: function() {
|
||||||
|
return World.getDistance() > 10 && World.getDistance() <= 20 && World.getTerrain() == World.TILE.FIELD;
|
||||||
|
},
|
||||||
|
scenes: {
|
||||||
|
'start': {
|
||||||
|
combat: true,
|
||||||
|
enemy: 'lizard',
|
||||||
|
char: 'L',
|
||||||
|
damage: 5,
|
||||||
|
hit: 0.8,
|
||||||
|
attackDelay: 2,
|
||||||
|
health: 20,
|
||||||
|
loot: {
|
||||||
|
'scales': {
|
||||||
|
min: 5,
|
||||||
|
max: 10,
|
||||||
|
chance: 0.8
|
||||||
|
},
|
||||||
|
'teeth': {
|
||||||
|
min: 5,
|
||||||
|
max: 10,
|
||||||
|
chance: 0.5
|
||||||
|
},
|
||||||
|
'meat': {
|
||||||
|
min: 5,
|
||||||
|
max: 10,
|
||||||
|
chance: 0.8
|
||||||
|
}
|
||||||
|
},
|
||||||
|
notification: 'the grass thrashes wildly as a huge lizard pushes through'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/* Tier 3*/
|
||||||
|
{ /* Feral Terror */
|
||||||
|
title: 'A Feral Terror',
|
||||||
|
isAvailable: function() {
|
||||||
|
return World.getDistance() > 20 && World.getTerrain() == World.TILE.FOREST;
|
||||||
|
},
|
||||||
|
scenes: {
|
||||||
|
'start': {
|
||||||
|
combat: true,
|
||||||
|
enemy: 'feral terror',
|
||||||
|
char: 'F',
|
||||||
|
damage: 6,
|
||||||
|
hit: 0.8,
|
||||||
|
attackDelay: 1,
|
||||||
|
health: 45,
|
||||||
|
loot: {
|
||||||
|
'fur': {
|
||||||
|
min: 5,
|
||||||
|
max: 10,
|
||||||
|
chance: 1
|
||||||
|
},
|
||||||
|
'meat': {
|
||||||
|
min: 5,
|
||||||
|
max: 10,
|
||||||
|
chance: 1
|
||||||
|
},
|
||||||
|
'teeth': {
|
||||||
|
min: 5,
|
||||||
|
max: 10,
|
||||||
|
chance: 0.8
|
||||||
|
}
|
||||||
|
},
|
||||||
|
notification: 'a beast, wilder than imagining, erupts out of the foliage'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ /* Soldier */
|
||||||
|
title: 'A Soldier',
|
||||||
|
isAvailable: function() {
|
||||||
|
return World.getDistance() > 20 && World.getTerrain() == World.TILE.BARRENS;
|
||||||
|
},
|
||||||
|
scenes: {
|
||||||
|
'start': {
|
||||||
|
combat: true,
|
||||||
|
enemy: 'soldier',
|
||||||
|
ranged: true,
|
||||||
|
char: 'D',
|
||||||
|
damage: 8,
|
||||||
|
hit: 0.8,
|
||||||
|
attackDelay: 2,
|
||||||
|
health: 50,
|
||||||
|
loot: {
|
||||||
|
'cloth': {
|
||||||
|
min: 5,
|
||||||
|
max: 10,
|
||||||
|
chance: 0.8
|
||||||
|
},
|
||||||
|
'bullets': {
|
||||||
|
min: 1,
|
||||||
|
max: 5,
|
||||||
|
chance: 0.5
|
||||||
|
},
|
||||||
|
'rifle': {
|
||||||
|
min: 1,
|
||||||
|
max: 1,
|
||||||
|
chance: 0.2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
notification: 'a soldier opens fire from across the desert'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ /* Sniper */
|
||||||
|
title: 'A Sniper',
|
||||||
|
isAvailable: function() {
|
||||||
|
return World.getDistance() > 20 && World.getTerrain() == World.TILE.FIELD;
|
||||||
|
},
|
||||||
|
scenes: {
|
||||||
|
'start': {
|
||||||
|
combat: true,
|
||||||
|
enemy: 'sniper',
|
||||||
|
char: 'S',
|
||||||
|
damage: 15,
|
||||||
|
hit: 0.8,
|
||||||
|
attackDelay: 4,
|
||||||
|
health: 30,
|
||||||
|
ranged: true,
|
||||||
|
loot: {
|
||||||
|
'cloth': {
|
||||||
|
min: 5,
|
||||||
|
max: 10,
|
||||||
|
chance: 0.8
|
||||||
|
},
|
||||||
|
'bullets': {
|
||||||
|
min: 1,
|
||||||
|
max: 5,
|
||||||
|
chance: 0.5
|
||||||
|
},
|
||||||
|
'rifle': {
|
||||||
|
min: 1,
|
||||||
|
max: 1,
|
||||||
|
chance: 0.2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
notification: 'a shot rings out, from somewhere in the long grass'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* Events that can occur when any module is active (Except World. It's special.)
|
||||||
|
**/
|
||||||
|
Events.Global = [
|
||||||
|
{ /* The Thief */
|
||||||
|
title: 'The Thief',
|
||||||
|
isAvailable: function() {
|
||||||
|
return (Engine.activeModule == Room || Engine.activeModule == Outside) && State.thieves == 1;
|
||||||
|
},
|
||||||
|
scenes: {
|
||||||
|
'start': {
|
||||||
|
text: [
|
||||||
|
'the villagers haul a filthy man out of the store room.',
|
||||||
|
"say his folk have been skimming the supplies.",
|
||||||
|
'say he should be strung up as an example.'
|
||||||
|
],
|
||||||
|
notification: 'a thief is caught',
|
||||||
|
buttons: {
|
||||||
|
'kill': {
|
||||||
|
text: 'hang him',
|
||||||
|
nextScene: {1: 'hang'}
|
||||||
|
},
|
||||||
|
'spare': {
|
||||||
|
text: 'spare him',
|
||||||
|
nextScene: {1: 'spare'}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'hang': {
|
||||||
|
text: [
|
||||||
|
'the villagers hang the thief high in front of the store room.',
|
||||||
|
'the point is made. in the next few days, the missing supplies are returned.'
|
||||||
|
],
|
||||||
|
onLoad: function() {
|
||||||
|
State.thieves = 2;
|
||||||
|
Engine.removeIncome('thieves');
|
||||||
|
Engine.addStores(State.stolen);
|
||||||
|
},
|
||||||
|
buttons: {
|
||||||
|
'leave': {
|
||||||
|
text: 'leave',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'spare': {
|
||||||
|
text: [
|
||||||
|
"the man says he's grateful. says he won't come around any more.",
|
||||||
|
"shares what he knows about sneaking before he goes."
|
||||||
|
],
|
||||||
|
onLoad: function() {
|
||||||
|
State.thieves = 2;
|
||||||
|
Engine.removeIncome('thieves');
|
||||||
|
Engine.addPerk('stealthy');
|
||||||
|
},
|
||||||
|
buttons: {
|
||||||
|
'leave': {
|
||||||
|
text: 'leave',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
/**
|
||||||
|
* Events that can occur when the Outside module is active
|
||||||
|
**/
|
||||||
|
Events.Outside = [
|
||||||
|
{ /* Ruined traps */
|
||||||
|
title: 'A Ruined Trap',
|
||||||
|
isAvailable: function() {
|
||||||
|
return Engine.activeModule == Outside && Outside.numBuilding('trap') > 0;
|
||||||
|
},
|
||||||
|
scenes: {
|
||||||
|
'start': {
|
||||||
|
text: [
|
||||||
|
'some of the traps have been torn apart.',
|
||||||
|
'large prints lead away, into the forest.'
|
||||||
|
],
|
||||||
|
onLoad: function() {
|
||||||
|
var numWrecked = Math.floor(Math.random() * Outside.numBuilding('trap')) + 1;
|
||||||
|
Outside.addBuilding('trap', -numWrecked);
|
||||||
|
Outside.updateVillage();
|
||||||
|
Outside.updateTrapButton();
|
||||||
|
},
|
||||||
|
notification: 'some traps have been destroyed',
|
||||||
|
buttons: {
|
||||||
|
'track': {
|
||||||
|
text: 'track them',
|
||||||
|
nextScene: {0.5: 'nothing', 1: 'catch'}
|
||||||
|
},
|
||||||
|
'ignore': {
|
||||||
|
text: 'ignore them',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'nothing': {
|
||||||
|
text: [
|
||||||
|
'the tracks disappear after just a few minutes.',
|
||||||
|
'the forest is silent.'
|
||||||
|
],
|
||||||
|
buttons: {
|
||||||
|
'end': {
|
||||||
|
text: 'go home',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'catch': {
|
||||||
|
text: [
|
||||||
|
'not far from the village lies a large beast, its fur matted with blood.',
|
||||||
|
'it puts up little resistance before the knife.'
|
||||||
|
],
|
||||||
|
reward: {
|
||||||
|
fur: 100,
|
||||||
|
meat: 100,
|
||||||
|
teeth: 10
|
||||||
|
},
|
||||||
|
buttons: {
|
||||||
|
'end': {
|
||||||
|
text: 'go home',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{ /* Beast attack */
|
||||||
|
title: 'A Beast Attack',
|
||||||
|
isAvailable: function() {
|
||||||
|
return Engine.activeModule == Outside && Outside.getPopulation() > 0;
|
||||||
|
},
|
||||||
|
scenes: {
|
||||||
|
'start': {
|
||||||
|
text: [
|
||||||
|
'a pack of snarling beasts pours out of the trees.',
|
||||||
|
'the fight is short and bloody, but the beasts are repelled.',
|
||||||
|
'the villagers retreat to mourn the dead.'
|
||||||
|
],
|
||||||
|
onLoad: function() {
|
||||||
|
var numKilled = Math.floor(Math.random() * 10) + 1;
|
||||||
|
Outside.killVillagers(numKilled);
|
||||||
|
},
|
||||||
|
reward: {
|
||||||
|
fur: 100,
|
||||||
|
meat: 100,
|
||||||
|
teeth: 10
|
||||||
|
},
|
||||||
|
buttons: {
|
||||||
|
'end': {
|
||||||
|
text: 'go home',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{ /* Soldier attack */
|
||||||
|
title: 'A Military Raid',
|
||||||
|
isAvailable: function() {
|
||||||
|
return Engine.activeModule == Outside && Outside.getPopulation() > 0 && State.cityCleared;
|
||||||
|
},
|
||||||
|
scenes: {
|
||||||
|
'start': {
|
||||||
|
text: [
|
||||||
|
'a gunshot rings through the trees.',
|
||||||
|
'well armed men charge out of the forest, firing into the crowd.',
|
||||||
|
'after a skirmish they are driven away, but not without losses.'
|
||||||
|
],
|
||||||
|
onLoad: function() {
|
||||||
|
var numKilled = Math.floor(Math.random() * 40) + 1;
|
||||||
|
Outside.killVillagers(numKilled);
|
||||||
|
},
|
||||||
|
reward: {
|
||||||
|
bullets: 10,
|
||||||
|
'cured meat': 50
|
||||||
|
},
|
||||||
|
buttons: {
|
||||||
|
'end': {
|
||||||
|
text: 'go home',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
@@ -0,0 +1,506 @@
|
|||||||
|
/**
|
||||||
|
* Events that can occur when the Room module is active
|
||||||
|
**/
|
||||||
|
Events.Room = [
|
||||||
|
{ /* The Nomad -- Merchant */
|
||||||
|
title: 'The Nomad',
|
||||||
|
isAvailable: function() {
|
||||||
|
return Engine.activeModule == Room && Engine.getStore('fur') > 0;
|
||||||
|
},
|
||||||
|
scenes: {
|
||||||
|
'start': {
|
||||||
|
text: [
|
||||||
|
'a nomad shuffles into view, laden with makeshift bags bound with rough twine.',
|
||||||
|
"won't say from where he came, but it's clear that he's not staying."
|
||||||
|
],
|
||||||
|
notification: 'a nomad arrives, looking to trade',
|
||||||
|
buttons: {
|
||||||
|
'buyScales': {
|
||||||
|
text: 'buy scales',
|
||||||
|
cost: { 'fur': 100 },
|
||||||
|
reward: { 'scales': 1 }
|
||||||
|
},
|
||||||
|
'buyTeeth': {
|
||||||
|
text: 'buy teeth',
|
||||||
|
cost: { 'fur': 200 },
|
||||||
|
reward: { 'teeth': 1 }
|
||||||
|
},
|
||||||
|
'buyBait': {
|
||||||
|
text: 'buy bait',
|
||||||
|
cost: { 'fur': 5 },
|
||||||
|
reward: { 'bait': 1 },
|
||||||
|
notification: 'traps are more effective with bait.'
|
||||||
|
},
|
||||||
|
'buyCompass': {
|
||||||
|
available: function() {
|
||||||
|
return Engine.getStore('compass') < 1;
|
||||||
|
},
|
||||||
|
text: 'buy compass',
|
||||||
|
cost: { fur: 300, scales: 15, teeth: 5 },
|
||||||
|
reward: { 'compass': 1 },
|
||||||
|
notification: 'the old compass is dented and dusty, but it looks to work.',
|
||||||
|
onChoose: Engine.openPath
|
||||||
|
},
|
||||||
|
'goodbye': {
|
||||||
|
text: 'say goodbye',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, { /* Noises Outside -- gain wood/fur */
|
||||||
|
title: 'Noises',
|
||||||
|
isAvailable: function() {
|
||||||
|
return Engine.activeModule == Room && Engine.storeAvailable('wood');
|
||||||
|
},
|
||||||
|
scenes: {
|
||||||
|
'start': {
|
||||||
|
text: [
|
||||||
|
'through the walls, shuffling noises can be heard.',
|
||||||
|
"can't tell what they're up to."
|
||||||
|
],
|
||||||
|
notification: 'strange noises can be heard through the walls',
|
||||||
|
buttons: {
|
||||||
|
'investigate': {
|
||||||
|
text: 'investigate',
|
||||||
|
nextScene: { 0.3: 'stuff', 1: 'nothing' }
|
||||||
|
},
|
||||||
|
'ignore': {
|
||||||
|
text: 'ignore them',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'nothing': {
|
||||||
|
text: [
|
||||||
|
'vague shapes move, just out of sight.',
|
||||||
|
'the sounds stop.'
|
||||||
|
],
|
||||||
|
buttons: {
|
||||||
|
'backinside': {
|
||||||
|
text: 'go back inside',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'stuff': {
|
||||||
|
reward: { wood: 100, fur: 10 },
|
||||||
|
text: [
|
||||||
|
'a bundle of stick lies just beyond the threshold, wrapped in course furs.',
|
||||||
|
'the night is silent.'
|
||||||
|
],
|
||||||
|
buttons: {
|
||||||
|
'backinside': {
|
||||||
|
text: 'go back inside',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ /* Noises Inside -- trade wood for better good */
|
||||||
|
title: 'Noises',
|
||||||
|
isAvailable: function() {
|
||||||
|
return Engine.activeModule == Room && Engine.storeAvailable('wood');
|
||||||
|
},
|
||||||
|
scenes: {
|
||||||
|
start: {
|
||||||
|
text: [
|
||||||
|
'scratching noises can be heard from the store room.',
|
||||||
|
'something\'s in there.'
|
||||||
|
],
|
||||||
|
notification: 'something\'s in the store room',
|
||||||
|
buttons: {
|
||||||
|
'investigate': {
|
||||||
|
text: 'investigate',
|
||||||
|
nextScene: { 0.5: 'scales', 0.8: 'teeth', 1: 'cloth' }
|
||||||
|
},
|
||||||
|
'ignore': {
|
||||||
|
text: 'ignore them',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
text: [
|
||||||
|
'some wood is missing.',
|
||||||
|
'the ground is littered with small scales'
|
||||||
|
],
|
||||||
|
onLoad: function() {
|
||||||
|
var numWood = Engine.getStore('wood');
|
||||||
|
numWood = Math.floor(numWood * 0.1);
|
||||||
|
if(numWood == 0) numWood = 1;
|
||||||
|
var numScales = Math.floor(numWood / 5);
|
||||||
|
if(numScales == 0) numScales = 1;
|
||||||
|
Engine.addStores({wood: -numWood, scales: numScales});
|
||||||
|
},
|
||||||
|
buttons: {
|
||||||
|
'leave': {
|
||||||
|
text: 'leave',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
teeth: {
|
||||||
|
text: [
|
||||||
|
'some wood is missing.',
|
||||||
|
'the ground is littered with small teeth'
|
||||||
|
],
|
||||||
|
onLoad: function() {
|
||||||
|
var numWood = Engine.getStore('wood');
|
||||||
|
numWood = Math.floor(numWood * 0.1);
|
||||||
|
if(numWood == 0) numWood = 1;
|
||||||
|
var numTeeth = Math.floor(numWood / 5);
|
||||||
|
if(numTeeth == 0) numTeeth = 1;
|
||||||
|
Engine.addStores({wood: -numWood, teeth: numTeeth});
|
||||||
|
},
|
||||||
|
buttons: {
|
||||||
|
'leave': {
|
||||||
|
text: 'leave',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
cloth: {
|
||||||
|
text: [
|
||||||
|
'some wood is missing.',
|
||||||
|
'the ground is littered with scraps of cloth'
|
||||||
|
],
|
||||||
|
onLoad: function() {
|
||||||
|
var numWood = Engine.getStore('wood');
|
||||||
|
numWood = Math.floor(numWood * 0.1);
|
||||||
|
if(numWood == 0) numWood = 1;
|
||||||
|
var numCloth = Math.floor(numWood / 5);
|
||||||
|
if(numCloth == 0) numCloth = 1;
|
||||||
|
Engine.addStores({wood: -numWood, cloth: numCloth});
|
||||||
|
},
|
||||||
|
buttons: {
|
||||||
|
'leave': {
|
||||||
|
text: 'leave',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ /* The Beggar -- trade fur for better good */
|
||||||
|
title: 'The Beggar',
|
||||||
|
isAvailable: function() {
|
||||||
|
return Engine.activeModule == Room && Engine.storeAvailable('fur');
|
||||||
|
},
|
||||||
|
scenes: {
|
||||||
|
start: {
|
||||||
|
text: [
|
||||||
|
'a beggar arrives.',
|
||||||
|
'asks for any spare furs to keep him warm at night.'
|
||||||
|
],
|
||||||
|
notification: 'a beggar arrives',
|
||||||
|
buttons: {
|
||||||
|
'50furs': {
|
||||||
|
text: 'give 50',
|
||||||
|
cost: {fur: 50},
|
||||||
|
nextScene: { 0.5: 'scales', 0.8: 'teeth', 1: 'cloth' }
|
||||||
|
},
|
||||||
|
'100furs': {
|
||||||
|
text: 'give 100',
|
||||||
|
cost: {fur: 100},
|
||||||
|
nextScene: { 0.5: 'teeth', 0.8: 'scales', 1: 'cloth' }
|
||||||
|
},
|
||||||
|
'deny': {
|
||||||
|
text: 'turn him away',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
reward: { scales: 20 },
|
||||||
|
text: [
|
||||||
|
'the beggar thanks you.',
|
||||||
|
'leaves a pile of small scales behind.'
|
||||||
|
],
|
||||||
|
buttons: {
|
||||||
|
'leave': {
|
||||||
|
text: 'say goodbye',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
teeth: {
|
||||||
|
reward: { teeth: 20 },
|
||||||
|
text: [
|
||||||
|
'the beggar thanks you.',
|
||||||
|
'leaves a pile of small teeth behind.'
|
||||||
|
],
|
||||||
|
buttons: {
|
||||||
|
'leave': {
|
||||||
|
text: 'say goodbye',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
cloth: {
|
||||||
|
reward: { cloth: 20 },
|
||||||
|
text: [
|
||||||
|
'the beggar thanks you.',
|
||||||
|
'leaves some scraps of cloth behind.'
|
||||||
|
],
|
||||||
|
buttons: {
|
||||||
|
'leave': {
|
||||||
|
text: 'say goodbye',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{ /* Mysterious Wanderer -- wood gambling */
|
||||||
|
title: 'The Mysterious Wanderer',
|
||||||
|
isAvailable: function() {
|
||||||
|
return Engine.activeModule == Room && Engine.storeAvailable('wood');
|
||||||
|
},
|
||||||
|
scenes: {
|
||||||
|
start: {
|
||||||
|
text: [
|
||||||
|
'a wanderer arrives with an empty cart. says if he leaves with wood, he\'ll be back with more.',
|
||||||
|
"builder's not sure he's to be trusted."
|
||||||
|
],
|
||||||
|
notification: 'a mysterious wanderer arrives',
|
||||||
|
buttons: {
|
||||||
|
'100wood': {
|
||||||
|
text: 'give 100',
|
||||||
|
cost: {wood: 100},
|
||||||
|
nextScene: { 1: '100wood'}
|
||||||
|
},
|
||||||
|
'500wood': {
|
||||||
|
text: 'give 500',
|
||||||
|
cost: {wood: 500},
|
||||||
|
nextScene: { 1: '500wood' }
|
||||||
|
},
|
||||||
|
'deny': {
|
||||||
|
text: 'turn him away',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'100wood': {
|
||||||
|
text: [
|
||||||
|
'the wanderer leaves, cart loaded with wood',
|
||||||
|
],
|
||||||
|
onLoad: function() {
|
||||||
|
if(Math.random() < 0.5) {
|
||||||
|
setTimeout(function() {
|
||||||
|
Engine.addStore('wood', 300);
|
||||||
|
Notifications.notify(Room, 'the mysterious wanderer returns, cart piled high with wood.');
|
||||||
|
}, 60 * 1000);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
buttons: {
|
||||||
|
'leave': {
|
||||||
|
text: 'say goodbye',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'500wood': {
|
||||||
|
text: [
|
||||||
|
'the wanderer leaves, cart loaded with wood',
|
||||||
|
],
|
||||||
|
onLoad: function() {
|
||||||
|
if(Math.random() < 0.3) {
|
||||||
|
setTimeout(function() {
|
||||||
|
Engine.addStore('wood', 1500);
|
||||||
|
Notifications.notify(Room, 'the mysterious wanderer returns, cart piled high with wood.');
|
||||||
|
}, 60 * 1000);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
buttons: {
|
||||||
|
'leave': {
|
||||||
|
text: 'say goodbye',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{ /* Mysterious Wanderer -- fur gambling */
|
||||||
|
title: 'The Mysterious Wanderer',
|
||||||
|
isAvailable: function() {
|
||||||
|
return Engine.activeModule == Room && Engine.storeAvailable('fur');
|
||||||
|
},
|
||||||
|
scenes: {
|
||||||
|
start: {
|
||||||
|
text: [
|
||||||
|
'a wanderer arrives with an empty cart. says if she leaves with furs, she\'ll be back with more.',
|
||||||
|
"builder's not sure she's to be trusted."
|
||||||
|
],
|
||||||
|
notification: 'a mysterious wanderer arrives',
|
||||||
|
buttons: {
|
||||||
|
'100fur': {
|
||||||
|
text: 'give 100',
|
||||||
|
cost: {fur: 100},
|
||||||
|
nextScene: { 1: '100fur'}
|
||||||
|
},
|
||||||
|
'500fur': {
|
||||||
|
text: 'give 500',
|
||||||
|
cost: {fur: 500},
|
||||||
|
nextScene: { 1: '500fur' }
|
||||||
|
},
|
||||||
|
'deny': {
|
||||||
|
text: 'turn her away',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'100fur': {
|
||||||
|
text: [
|
||||||
|
'the wanderer leaves, cart loaded with furs',
|
||||||
|
],
|
||||||
|
onLoad: function() {
|
||||||
|
if(Math.random() < 0.5) {
|
||||||
|
setTimeout(function() {
|
||||||
|
Engine.addStore('fur', 300);
|
||||||
|
Notifications.notify(Room, 'the mysterious wanderer returns, cart piled high with furs.');
|
||||||
|
}, 60 * 1000);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
buttons: {
|
||||||
|
'leave': {
|
||||||
|
text: 'say goodbye',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'500fur': {
|
||||||
|
text: [
|
||||||
|
'the wanderer leaves, cart loaded with furs',
|
||||||
|
],
|
||||||
|
onLoad: function() {
|
||||||
|
if(Math.random() < 0.3) {
|
||||||
|
setTimeout(function() {
|
||||||
|
Engine.addStore('fur', 1500);
|
||||||
|
Notifications.notify(Room, 'the mysterious wanderer returns, cart piled high with furs.');
|
||||||
|
}, 60 * 1000);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
buttons: {
|
||||||
|
'leave': {
|
||||||
|
text: 'say goodbye',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{ /* The Scout -- Map Merchant */
|
||||||
|
title: 'The Scout',
|
||||||
|
isAvailable: function() {
|
||||||
|
return Engine.activeModule == Room && typeof State.world == 'object';
|
||||||
|
},
|
||||||
|
scenes: {
|
||||||
|
'start': {
|
||||||
|
text: [
|
||||||
|
"the scout says she's been all over.",
|
||||||
|
"willing to talk about it, for a price."
|
||||||
|
],
|
||||||
|
notification: 'a scout stops for the night',
|
||||||
|
buttons: {
|
||||||
|
'buyMap': {
|
||||||
|
text: 'buy map',
|
||||||
|
cost: { 'fur': 200, 'scales': 10 },
|
||||||
|
notification: 'the map uncovers a bit of the world',
|
||||||
|
onChoose: World.applyMap
|
||||||
|
},
|
||||||
|
'learn': {
|
||||||
|
text: 'learn scouting',
|
||||||
|
cost: { 'fur': 1000, 'scales': 50, 'teeth': 20 },
|
||||||
|
available: function() {
|
||||||
|
return !Engine.hasPerk('scout');
|
||||||
|
},
|
||||||
|
onChoose: function() {
|
||||||
|
Engine.addPerk('scout');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'leave': {
|
||||||
|
text: 'say goodbye',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{ /* The Wandering Master */
|
||||||
|
title: 'The Master',
|
||||||
|
isAvailable: function() {
|
||||||
|
return Engine.activeModule == Room && typeof State.world == 'object';
|
||||||
|
},
|
||||||
|
scenes: {
|
||||||
|
'start': {
|
||||||
|
text: [
|
||||||
|
'an old wanderer arrives.',
|
||||||
|
'he smiles warmly and asks for lodgings for the night.'
|
||||||
|
],
|
||||||
|
notification: 'an old wanderer arrives',
|
||||||
|
buttons: {
|
||||||
|
'agree': {
|
||||||
|
text: 'agree',
|
||||||
|
cost: {
|
||||||
|
'cured meat': 100,
|
||||||
|
'fur': 100,
|
||||||
|
'torch': 1
|
||||||
|
},
|
||||||
|
nextScene: {1: 'agree'}
|
||||||
|
},
|
||||||
|
'deny': {
|
||||||
|
text: 'turn him away',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'agree': {
|
||||||
|
text: [
|
||||||
|
'in exchange, the wanderer offers his wisdom.'
|
||||||
|
],
|
||||||
|
buttons: {
|
||||||
|
'evasion': {
|
||||||
|
text: 'evasion',
|
||||||
|
available: function() {
|
||||||
|
return !Engine.hasPerk('evasive');
|
||||||
|
},
|
||||||
|
onChoose: function() {
|
||||||
|
Engine.addPerk('evasive');
|
||||||
|
},
|
||||||
|
nextScene: 'end'
|
||||||
|
},
|
||||||
|
'precision': {
|
||||||
|
text: 'precision',
|
||||||
|
available: function() {
|
||||||
|
return !Engine.hasPerk('precise');
|
||||||
|
},
|
||||||
|
onChoose: function() {
|
||||||
|
Engine.addPerk('precise');
|
||||||
|
},
|
||||||
|
nextScene: 'end'
|
||||||
|
},
|
||||||
|
'force': {
|
||||||
|
text: 'force',
|
||||||
|
available: function() {
|
||||||
|
return !Engine.hasPerk('barbarian');
|
||||||
|
},
|
||||||
|
onChoose: function() {
|
||||||
|
Engine.addPerk('barbarian');
|
||||||
|
},
|
||||||
|
nextScene: 'end'
|
||||||
|
},
|
||||||
|
'nothing': {
|
||||||
|
text: 'nothing',
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* Module that takes care of header buttons
|
||||||
|
*/
|
||||||
|
var Header = {
|
||||||
|
|
||||||
|
init: function(options) {
|
||||||
|
this.options = $.extend(
|
||||||
|
this.options,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
options: {}, // Nothing for now
|
||||||
|
|
||||||
|
canTravel: function() {
|
||||||
|
return $('div#header div.headerButton').length > 1;
|
||||||
|
},
|
||||||
|
|
||||||
|
addLocation: function(text, id, module) {
|
||||||
|
return $('<div>').attr('id', "location_" + id)
|
||||||
|
.addClass('headerButton')
|
||||||
|
.text(text).click(function() {
|
||||||
|
if(Header.canTravel()) {
|
||||||
|
Engine.travelTo(module);
|
||||||
|
}
|
||||||
|
}).appendTo($('div#header'));
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* Module that registers the notification box and handles messages
|
||||||
|
*/
|
||||||
|
var Notifications = {
|
||||||
|
|
||||||
|
init: function(options) {
|
||||||
|
this.options = $.extend(
|
||||||
|
this.options,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create the notifications box
|
||||||
|
elem = $('<div>').attr({
|
||||||
|
id: 'notifications',
|
||||||
|
className: 'notifications'
|
||||||
|
});
|
||||||
|
// Create the transparency gradient
|
||||||
|
$('<div>').attr('id', 'notifyGradient').appendTo(elem);
|
||||||
|
|
||||||
|
elem.appendTo('div#wrapper');
|
||||||
|
},
|
||||||
|
|
||||||
|
options: {}, // Nothing for now
|
||||||
|
|
||||||
|
elem: null,
|
||||||
|
|
||||||
|
notifyQueue: {},
|
||||||
|
|
||||||
|
// Allow notification to the player
|
||||||
|
notify: function(module, text, noQueue) {
|
||||||
|
if(typeof text == 'undefined') return;
|
||||||
|
if(text.slice(-1) != ".") text += ".";
|
||||||
|
if(module != null && Engine.activeModule != module) {
|
||||||
|
if(!noQueue) {
|
||||||
|
if(typeof this.notifyQueue[module] == 'undefined') {
|
||||||
|
this.notifyQueue[module] = new Array();
|
||||||
|
}
|
||||||
|
this.notifyQueue[module].push(text);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Notifications.printMessage(text);
|
||||||
|
}
|
||||||
|
Engine.saveGame();
|
||||||
|
},
|
||||||
|
|
||||||
|
printMessage: function(text) {
|
||||||
|
var text = $('<div>').addClass('notification').css('opacity', '0').text(text).prependTo('div#notifications');
|
||||||
|
text.animate({opacity: 1}, 500, 'linear');
|
||||||
|
},
|
||||||
|
|
||||||
|
printQueue: function(module) {
|
||||||
|
if(typeof this.notifyQueue[module] != 'undefined') {
|
||||||
|
while(this.notifyQueue[module].length > 0) {
|
||||||
|
Notifications.printMessage(this.notifyQueue[module].shift());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,611 @@
|
|||||||
|
/**
|
||||||
|
* Module that registers the outdoors functionality
|
||||||
|
*/
|
||||||
|
var Outside = {
|
||||||
|
name: "Outside",
|
||||||
|
|
||||||
|
_GATHER_DELAY: 60,
|
||||||
|
_TRAPS_DELAY: 90,
|
||||||
|
_POP_DELAY: [0.5, 3],
|
||||||
|
|
||||||
|
_INCOME: {
|
||||||
|
'gatherer': {
|
||||||
|
delay: 10,
|
||||||
|
stores: {
|
||||||
|
'wood': 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'hunter': {
|
||||||
|
delay: 10,
|
||||||
|
stores: {
|
||||||
|
'fur': 0.5,
|
||||||
|
'meat': 0.5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'trapper': {
|
||||||
|
delay: 10,
|
||||||
|
stores: {
|
||||||
|
'meat': -1,
|
||||||
|
'bait': 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'tanner': {
|
||||||
|
delay: 10,
|
||||||
|
stores: {
|
||||||
|
'fur': -5,
|
||||||
|
'leather': 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'charcutier': {
|
||||||
|
delay: 10,
|
||||||
|
stores: {
|
||||||
|
'meat': -5,
|
||||||
|
'wood': -5,
|
||||||
|
'cured meat': 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'iron miner': {
|
||||||
|
delay: 10,
|
||||||
|
stores: {
|
||||||
|
'cured meat': -1,
|
||||||
|
'iron': 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'coal miner': {
|
||||||
|
delay: 10,
|
||||||
|
stores: {
|
||||||
|
'cured meat': -1,
|
||||||
|
'coal': 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'sulphur miner': {
|
||||||
|
delay: 10,
|
||||||
|
stores: {
|
||||||
|
'cured meat': -1,
|
||||||
|
'sulphur': 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'steelworker': {
|
||||||
|
delay: 10,
|
||||||
|
stores: {
|
||||||
|
'iron': -1,
|
||||||
|
'coal': -1,
|
||||||
|
'steel': 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'armourer': {
|
||||||
|
delay: 10,
|
||||||
|
stores: {
|
||||||
|
'steel': -1,
|
||||||
|
'sulphur': -1,
|
||||||
|
'bullets': 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
TrapDrops: [
|
||||||
|
{
|
||||||
|
rollUnder: 0.5,
|
||||||
|
name: 'fur',
|
||||||
|
message: 'scraps of fur'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rollUnder: 0.75,
|
||||||
|
name: 'meat',
|
||||||
|
message: 'bits of meat'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rollUnder: 0.85,
|
||||||
|
name: 'scales',
|
||||||
|
message: 'strange scales'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rollUnder: 0.93,
|
||||||
|
name: 'teeth',
|
||||||
|
message: 'scattered teeth'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rollUnder: 0.995,
|
||||||
|
name: 'cloth',
|
||||||
|
message: 'tattered cloth'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rollUnder: 1.0,
|
||||||
|
name: 'charm',
|
||||||
|
message: 'a crudely made charm'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
init: function(options) {
|
||||||
|
this.options = $.extend(
|
||||||
|
this.options,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
|
||||||
|
if(Engine._debug) {
|
||||||
|
this._GATHER_DELAY = 0;
|
||||||
|
this._TRAPS_DELAY = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the outside tab
|
||||||
|
this.tab = Header.addLocation("A Silent Forest", "outside", Outside);
|
||||||
|
|
||||||
|
// Create the Outside panel
|
||||||
|
this.panel = $('<div>').attr('id', "outsidePanel")
|
||||||
|
.addClass('location')
|
||||||
|
.appendTo('div#locationSlider');
|
||||||
|
|
||||||
|
if(typeof State.outside == 'undefined') {
|
||||||
|
State.outside = {
|
||||||
|
buildings: {},
|
||||||
|
population: 0,
|
||||||
|
workers: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateVillage();
|
||||||
|
Outside.updateWorkersView();
|
||||||
|
|
||||||
|
Engine.updateSlider();
|
||||||
|
|
||||||
|
// Create the gather button
|
||||||
|
new Button.Button({
|
||||||
|
id: 'gatherButton',
|
||||||
|
text: "gather wood",
|
||||||
|
click: Outside.gatherWood,
|
||||||
|
cooldown: Outside._GATHER_DELAY,
|
||||||
|
width: '80px'
|
||||||
|
}).appendTo('div#outsidePanel');
|
||||||
|
},
|
||||||
|
|
||||||
|
numBuilding: function(bName) {
|
||||||
|
return State.outside &&
|
||||||
|
State.outside.buildings &&
|
||||||
|
State.outside.buildings[bName] ? State.outside.buildings[bName] : 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
addBuilding: function(bName, num) {
|
||||||
|
var cur = State.outside.buildings[bName];
|
||||||
|
if(typeof cur != 'number') cur = 0;
|
||||||
|
cur += num;
|
||||||
|
if(cur < 0) cur = 0;
|
||||||
|
State.outside.buildings[bName] = cur;
|
||||||
|
this.updateVillage();
|
||||||
|
Engine.saveGame();
|
||||||
|
},
|
||||||
|
|
||||||
|
addBuildings: function(list) {
|
||||||
|
for(k in list) {
|
||||||
|
var num = State.outside.buildings[k];
|
||||||
|
if(typeof num != 'number') num = 0;
|
||||||
|
num += list[k];
|
||||||
|
State.outside.buildings[k] = num;
|
||||||
|
}
|
||||||
|
this.updateVillage();
|
||||||
|
Engine.saveGame();
|
||||||
|
},
|
||||||
|
|
||||||
|
getMaxPopulation: function() {
|
||||||
|
return Outside.numBuilding('hut') * 4;
|
||||||
|
},
|
||||||
|
|
||||||
|
getPopulation: function() {
|
||||||
|
if(State.outside && State.outside.population) {
|
||||||
|
return State.outside.population;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
increasePopulation: function() {
|
||||||
|
var space = Outside.getMaxPopulation() - State.outside.population;
|
||||||
|
if(space > 0) {
|
||||||
|
var num = Math.floor(Math.random()*(space/2) + space/2);
|
||||||
|
if(num == 0) num = 1;
|
||||||
|
if(num == 1) {
|
||||||
|
Notifications.notify(null, 'a stranger arrives in the night');
|
||||||
|
} else if(num < 5) {
|
||||||
|
Notifications.notify(null, 'a weathered family takes up in one of the huts.');
|
||||||
|
} else if(num < 10) {
|
||||||
|
Notifications.notify(null, 'a small group arrives, all dust and bones.');
|
||||||
|
} else if(num < 30) {
|
||||||
|
Notifications.notify(null, 'a convoy lurches in, equal parts worry and hope.');
|
||||||
|
} else {
|
||||||
|
Notifications.notify(null, "the town's booming. word does get around.");
|
||||||
|
}
|
||||||
|
Engine.log('population increased by ' + num);
|
||||||
|
State.outside.population += num;
|
||||||
|
Outside.updateVillage();
|
||||||
|
Outside.updateWorkersView();
|
||||||
|
Outside.updateVillageIncome();
|
||||||
|
}
|
||||||
|
Outside.schedulePopIncrease();
|
||||||
|
},
|
||||||
|
|
||||||
|
killVillagers: function(num) {
|
||||||
|
State.outside.population -= num;
|
||||||
|
if(State.outside.population < 0) {
|
||||||
|
State.outside.population = 0;
|
||||||
|
}
|
||||||
|
var remaining = Outside.getNumGatherers();
|
||||||
|
if(remaining < 0) {
|
||||||
|
var gap = -remaining;
|
||||||
|
for(var k in State.outside.workers) {
|
||||||
|
var num = State.outside.workers[k];
|
||||||
|
if(num < gap) {
|
||||||
|
gap -= num;
|
||||||
|
State.outside.workers[k] = 0;
|
||||||
|
} else {
|
||||||
|
State.outside.workers[k] -= gap;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Outside.updateVillage();
|
||||||
|
Outside.updateWorkersView();
|
||||||
|
Outside.updateVillageIncome();
|
||||||
|
},
|
||||||
|
|
||||||
|
schedulePopIncrease: function() {
|
||||||
|
var nextIncrease = Math.floor(Math.random()*(Outside._POP_DELAY[1] - Outside._POP_DELAY[0])) + Outside._POP_DELAY[0];
|
||||||
|
Engine.log('next population increase scheduled in ' + nextIncrease + ' minutes');
|
||||||
|
Outside._popTimeout = setTimeout(Outside.increasePopulation, nextIncrease * 60 * 1000);
|
||||||
|
},
|
||||||
|
|
||||||
|
updateWorkersView: function() {
|
||||||
|
if(State.outside.population == 0) return;
|
||||||
|
var workers = $('div#workers');
|
||||||
|
var needsAppend = false;
|
||||||
|
if(workers.length == 0) {
|
||||||
|
needsAppend = true;
|
||||||
|
workers = $('<div>').attr('id', 'workers').css('opacity', 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
var numGatherers = State.outside.population;
|
||||||
|
var gatherer = $('div#workers_row_gatherer', workers);
|
||||||
|
|
||||||
|
for(var k in State.outside.workers) {
|
||||||
|
var row = $('div#workers_row_' + k.replace(' ', '-'), workers);
|
||||||
|
if(row.length == 0) {
|
||||||
|
row = Outside.makeWorkerRow(k, State.outside.workers[k]);
|
||||||
|
|
||||||
|
var curPrev = null;
|
||||||
|
workers.children().each(function(i) {
|
||||||
|
var child = $(this);
|
||||||
|
var cName = child.attr('id').substring(12).replace('-', ' ');
|
||||||
|
if(cName != 'gatherer') {
|
||||||
|
if(cName < k && (curPrev == null || cName > curPrev)) {
|
||||||
|
curPrev = cName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(curPrev == null && gatherer.length == 0) {
|
||||||
|
row.prependTo(workers);
|
||||||
|
}
|
||||||
|
else if(curPrev == null)
|
||||||
|
{
|
||||||
|
row.insertAfter(gatherer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
row.insertAfter(workers.find('#workers_row_' + curPrev.replace(' ', '-')));
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$('div#' + row.attr('id') + ' > div.row_val > span', workers).text(State.outside.workers[k]);
|
||||||
|
}
|
||||||
|
numGatherers -= State.outside.workers[k];
|
||||||
|
if(State.outside.workers[k] == 0) {
|
||||||
|
$('.dnBtn', row).addClass('disabled');
|
||||||
|
} else {
|
||||||
|
$('.dnBtn', row).removeClass('disabled');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(gatherer.length == 0) {
|
||||||
|
gatherer = Outside.makeWorkerRow('gatherer', numGatherers);
|
||||||
|
gatherer.prependTo(workers);
|
||||||
|
} else {
|
||||||
|
$('div#workers_row_gatherer > div.row_val > span', workers).text(numGatherers);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(numGatherers == 0) {
|
||||||
|
$('.upBtn', '#workers').addClass('disabled');
|
||||||
|
} else {
|
||||||
|
$('.upBtn', '#workers').removeClass('disabled');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(needsAppend && workers.children().length > 0) {
|
||||||
|
workers.appendTo('#outsidePanel').animate({opacity:1}, 300, 'linear');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getNumGatherers: function() {
|
||||||
|
var num = State.outside.population;
|
||||||
|
for(var k in State.outside.workers) {
|
||||||
|
num -= State.outside.workers[k];
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
},
|
||||||
|
|
||||||
|
makeWorkerRow: function(name, num) {
|
||||||
|
var row = $('<div>')
|
||||||
|
.attr('id', 'workers_row_' + name.replace(' ','-'))
|
||||||
|
.addClass('workerRow');
|
||||||
|
$('<div>').addClass('row_key').text(name).appendTo(row);
|
||||||
|
var val = $('<div>').addClass('row_val').appendTo(row);
|
||||||
|
|
||||||
|
$('<span>').text(num).appendTo(val);
|
||||||
|
|
||||||
|
if(name != 'gatherer') {
|
||||||
|
$('<div>').addClass('upBtn').appendTo(val).click(Outside.increaseWorker);
|
||||||
|
$('<div>').addClass('dnBtn').appendTo(val).click(Outside.decreaseWorker);
|
||||||
|
}
|
||||||
|
|
||||||
|
$('<div>').addClass('clear').appendTo(row);
|
||||||
|
|
||||||
|
var tooltip = $('<div>').addClass('tooltip bottom right').appendTo(row);
|
||||||
|
var income = Outside._INCOME[name];
|
||||||
|
for(var s in income.stores) {
|
||||||
|
var r = $('<div>').addClass('storeRow');
|
||||||
|
$('<div>').addClass('row_key').text(s).appendTo(r);
|
||||||
|
$('<div>').addClass('row_val').text(Engine.getIncomeMsg(income.stores[s], income.delay)).appendTo(r);
|
||||||
|
r.appendTo(tooltip);
|
||||||
|
}
|
||||||
|
|
||||||
|
return row;
|
||||||
|
},
|
||||||
|
|
||||||
|
increaseWorker: function(btn) {
|
||||||
|
var worker = $(this).closest('.workerRow').children('.row_key').text();
|
||||||
|
if(Outside.getNumGatherers() > 0) {
|
||||||
|
Engine.log('increasing ' + worker);
|
||||||
|
State.outside.workers[worker]++;
|
||||||
|
Outside.updateVillageIncome();
|
||||||
|
Outside.updateWorkersView();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
decreaseWorker: function(btn) {
|
||||||
|
var worker = $(this).closest('.workerRow').children('.row_key').text();
|
||||||
|
if(State.outside.workers[worker] > 0) {
|
||||||
|
Engine.log('decreasing ' + worker);
|
||||||
|
State.outside.workers[worker]--;
|
||||||
|
Outside.updateVillageIncome();
|
||||||
|
Outside.updateWorkersView();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
updateVillageRow: function(name, num, village) {
|
||||||
|
var id = 'building_row_' + name.replace(' ', '-');
|
||||||
|
var row = $('div#' + id, village);
|
||||||
|
if(row.length == 0 && num > 0) {
|
||||||
|
var row = $('<div>').attr('id', id).addClass('storeRow');
|
||||||
|
$('<div>').addClass('row_key').text(name).appendTo(row);
|
||||||
|
$('<div>').addClass('row_val').text(num).appendTo(row);
|
||||||
|
$('<div>').addClass('clear').appendTo(row);
|
||||||
|
var curPrev = null;
|
||||||
|
village.children().each(function(i) {
|
||||||
|
var child = $(this);
|
||||||
|
if(child.attr('id') != 'population') {
|
||||||
|
var cName = child.attr('id').substring(13).replace('-', ' ');
|
||||||
|
if(cName < name && (curPrev == null || cName > curPrev)) {
|
||||||
|
curPrev = cName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(curPrev == null) {
|
||||||
|
row.prependTo(village);
|
||||||
|
} else {
|
||||||
|
row.insertAfter('#building_row_' + curPrev.replace(' ', '-'));
|
||||||
|
}
|
||||||
|
} else if(num > 0) {
|
||||||
|
$('div#' + row.attr('id') + ' > div.row_val', village).text(num);
|
||||||
|
} else if(num == 0) {
|
||||||
|
row.remove();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
updateVillage: function() {
|
||||||
|
var village = $('div#village');
|
||||||
|
var pop = $('div#population');
|
||||||
|
var needsAppend = false;
|
||||||
|
if(village.length == 0) {
|
||||||
|
needsAppend = true;
|
||||||
|
village = $('<div>').attr('id', 'village').css('opacity', 0);
|
||||||
|
population = $('<div>').attr('id', 'population').appendTo(village);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(var k in State.outside.buildings) {
|
||||||
|
if(k == 'trap') {
|
||||||
|
var numTraps = State.outside.buildings[k];
|
||||||
|
var numBait = Engine.getStore('bait');
|
||||||
|
var traps = numTraps - numBait;
|
||||||
|
traps = traps < 0 ? 0 : traps;
|
||||||
|
Outside.updateVillageRow(k, traps, village);
|
||||||
|
Outside.updateVillageRow('baited trap', numBait > numTraps ? numTraps : numBait, village);
|
||||||
|
} else {
|
||||||
|
if(Outside.checkWorker(k)) {
|
||||||
|
Outside.updateWorkersView();
|
||||||
|
}
|
||||||
|
Outside.updateVillageRow(k, State.outside.buildings[k], village);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
population.text('pop ' + State.outside.population + '/' + this.getMaxPopulation());
|
||||||
|
|
||||||
|
var hasPeeps;
|
||||||
|
if(Outside.numBuilding('hut') == 0) {
|
||||||
|
hasPeeps = false;
|
||||||
|
village.addClass('noHuts');
|
||||||
|
} else {
|
||||||
|
hasPeeps = true;
|
||||||
|
village.removeClass('noHuts');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(needsAppend && village.children().length > 1) {
|
||||||
|
village.appendTo('#outsidePanel');
|
||||||
|
village.animate({opacity:1}, 300, 'linear');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hasPeeps && typeof Outside._popTimeout == 'undefined') {
|
||||||
|
Outside.schedulePopIncrease();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setTitle();
|
||||||
|
},
|
||||||
|
|
||||||
|
checkWorker: function(name) {
|
||||||
|
var jobMap = {
|
||||||
|
'lodge': ['hunter', 'trapper'],
|
||||||
|
'tannery': ['tanner'],
|
||||||
|
'smokehouse': ['charcutier'],
|
||||||
|
'iron mine': ['iron miner'],
|
||||||
|
'coal mine': ['coal miner'],
|
||||||
|
'sulphur mine': ['sulphur miner'],
|
||||||
|
'steelworks': ['steelworker'],
|
||||||
|
'armoury' : ['armourer']
|
||||||
|
}
|
||||||
|
|
||||||
|
var jobs = jobMap[name];
|
||||||
|
var added = false;
|
||||||
|
if(typeof jobs == 'object') {
|
||||||
|
for(var i = 0, len = jobs.length; i < len; i++) {
|
||||||
|
var job = jobs[i];
|
||||||
|
if(typeof State.outside.buildings[name] == 'number' &&
|
||||||
|
typeof State.outside.workers[job] != 'number') {
|
||||||
|
Engine.log('adding ' + job + ' to the workers list')
|
||||||
|
State.outside.workers[job] = 0;
|
||||||
|
added = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return added;
|
||||||
|
},
|
||||||
|
|
||||||
|
updateVillageIncome: function() {
|
||||||
|
for(var worker in Outside._INCOME) {
|
||||||
|
var income = Outside._INCOME[worker];
|
||||||
|
var num = worker == 'gatherer' ? Outside.getNumGatherers() : State.outside.workers[worker];
|
||||||
|
if(typeof num == 'number') {
|
||||||
|
var stores = {};
|
||||||
|
if(num < 0) num = 0;
|
||||||
|
var tooltip = $('.tooltip', 'div#workers_row_' + worker.replace(' ', '-'));
|
||||||
|
tooltip.empty();
|
||||||
|
var needsUpdate = false;
|
||||||
|
var curIncome = Engine.getIncome(worker);
|
||||||
|
for(var store in income.stores) {
|
||||||
|
stores[store] = income.stores[store] * num;
|
||||||
|
if(curIncome[store] != stores[store]) needsUpdate = true;
|
||||||
|
var row = $('<div>').addClass('storeRow');
|
||||||
|
$('<div>').addClass('row_key').text(store).appendTo(row);
|
||||||
|
$('<div>').addClass('row_val').text(Engine.getIncomeMsg(stores[store], income.delay)).appendTo(row);
|
||||||
|
row.appendTo(tooltip);
|
||||||
|
}
|
||||||
|
if(needsUpdate) {
|
||||||
|
Engine.setIncome(worker, {
|
||||||
|
delay: income.delay,
|
||||||
|
stores: stores
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Room.updateIncomeView();
|
||||||
|
},
|
||||||
|
|
||||||
|
updateTrapButton: function() {
|
||||||
|
var btn = $('div#trapsButton');
|
||||||
|
if(Outside.numBuilding('trap') > 0) {
|
||||||
|
if(btn.length == 0) {
|
||||||
|
new Button.Button({
|
||||||
|
id: 'trapsButton',
|
||||||
|
text: "check traps",
|
||||||
|
click: Outside.checkTraps,
|
||||||
|
cooldown: Outside._TRAPS_DELAY,
|
||||||
|
width: '80px'
|
||||||
|
}).appendTo('div#outsidePanel');
|
||||||
|
} else {
|
||||||
|
Button.setDisabled(btn, false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(btn.length > 0) {
|
||||||
|
Button.setDisabled(btn, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setTitle: function() {
|
||||||
|
var numHuts = this.numBuilding('hut');
|
||||||
|
var title;
|
||||||
|
if(numHuts == 0) {
|
||||||
|
title = "A Silent Forest";
|
||||||
|
} else if(numHuts == 1) {
|
||||||
|
title = "A Lonely Hut";
|
||||||
|
} else if(numHuts <= 4) {
|
||||||
|
title = "A Tiny Village";
|
||||||
|
} else if(numHuts <= 8) {
|
||||||
|
title = "A Modest Village";
|
||||||
|
} else if(numHuts <= 14) {
|
||||||
|
title = "A Large Village";
|
||||||
|
} else {
|
||||||
|
title = "A Raucous Village";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Engine.activeModule == this) {
|
||||||
|
document.title = title;
|
||||||
|
}
|
||||||
|
$('#location_outside').text(title);
|
||||||
|
},
|
||||||
|
|
||||||
|
onArrival: function() {
|
||||||
|
Outside.setTitle();
|
||||||
|
if(!State.seenForest) {
|
||||||
|
Notifications.notify(Outside, "the sky is grey and the wind blows relentlessly");
|
||||||
|
State.seenForest = true;
|
||||||
|
}
|
||||||
|
Outside.updateTrapButton();
|
||||||
|
},
|
||||||
|
|
||||||
|
gatherWood: function() {
|
||||||
|
Notifications.notify(Outside, "dry brush and dead branches litter the forest floor")
|
||||||
|
Engine.setStore('wood', Engine.getStore('wood') + (Outside.numBuilding('cart') > 0 ? 50 : 10));
|
||||||
|
},
|
||||||
|
|
||||||
|
checkTraps: function() {
|
||||||
|
var drops = {};
|
||||||
|
var msg = [];
|
||||||
|
var numTraps = Outside.numBuilding('trap');
|
||||||
|
var numBait = Engine.getStore('bait');
|
||||||
|
var numDrops = numTraps + (numBait < numTraps ? numBait : numTraps);
|
||||||
|
for(var i = 0; i < numDrops; i++) {
|
||||||
|
var roll = Math.random();
|
||||||
|
for(var j in Outside.TrapDrops) {
|
||||||
|
var drop = Outside.TrapDrops[j];
|
||||||
|
if(roll < drop.rollUnder) {
|
||||||
|
var num = drops[drop.name]
|
||||||
|
if(typeof num == 'undefined') {
|
||||||
|
num = 0;
|
||||||
|
msg.push(drop.message);
|
||||||
|
}
|
||||||
|
drops[drop.name] = num + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var s = 'the traps contain ';
|
||||||
|
for(var i = 0, len = msg.length; i < len; i++) {
|
||||||
|
if(len > 1 && i > 0 && i < len - 1) {
|
||||||
|
s += ", ";
|
||||||
|
} else if(len > 1 && i == len - 1) {
|
||||||
|
s += " and ";
|
||||||
|
}
|
||||||
|
s += msg[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
var baitUsed = numBait < numTraps ? numBait : numTraps;
|
||||||
|
drops['bait'] = -baitUsed;
|
||||||
|
|
||||||
|
Notifications.notify(Outside, s);
|
||||||
|
Engine.addStores(drops);
|
||||||
|
}
|
||||||
|
}
|
||||||
+280
@@ -0,0 +1,280 @@
|
|||||||
|
var Path = {
|
||||||
|
|
||||||
|
DEFAULT_BAG_SPACE: 10,
|
||||||
|
|
||||||
|
// Everything not in this list weighs 1
|
||||||
|
Weight: {
|
||||||
|
'bone spear': 2,
|
||||||
|
'iron sword': 3,
|
||||||
|
'steel sword': 5,
|
||||||
|
'rifle': 5,
|
||||||
|
'bullets': 0.1,
|
||||||
|
'energy cell': 0.2,
|
||||||
|
'laser rifle': 5,
|
||||||
|
'bolas': 0.5
|
||||||
|
},
|
||||||
|
|
||||||
|
name: 'Path',
|
||||||
|
options: {}, // Nuthin'
|
||||||
|
init: function(options) {
|
||||||
|
this.options = $.extend(
|
||||||
|
this.options,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
|
||||||
|
// Init the World
|
||||||
|
World.init();
|
||||||
|
|
||||||
|
// Create the path tab
|
||||||
|
this.tab = Header.addLocation("A Dusty Path", "path", Path);
|
||||||
|
|
||||||
|
// Create the Path panel
|
||||||
|
this.panel = $('<div>').attr('id', "pathPanel")
|
||||||
|
.addClass('location')
|
||||||
|
.appendTo('div#locationSlider');
|
||||||
|
|
||||||
|
// Add the outfitting area
|
||||||
|
var outfitting = $('<div>').attr('id', 'outfitting').appendTo(this.panel);
|
||||||
|
var bagspace = $('<div>').attr('id', 'bagspace').appendTo(outfitting);
|
||||||
|
|
||||||
|
// Add the embark button
|
||||||
|
new Button.Button({
|
||||||
|
id: 'embarkButton',
|
||||||
|
text: "embark",
|
||||||
|
click: Path.embark,
|
||||||
|
width: '80px',
|
||||||
|
cooldown: World.DEATH_COOLDOWN
|
||||||
|
}).appendTo(this.panel);
|
||||||
|
|
||||||
|
Path.outfit = {};
|
||||||
|
|
||||||
|
Engine.updateSlider();
|
||||||
|
},
|
||||||
|
|
||||||
|
getWeight: function(thing) {
|
||||||
|
var w = Path.Weight[thing];
|
||||||
|
if(typeof w != 'number') w = 1;
|
||||||
|
|
||||||
|
return w;
|
||||||
|
},
|
||||||
|
|
||||||
|
getCapacity: function() {
|
||||||
|
if(Engine.getStore('convoy') > 0) {
|
||||||
|
return Path.DEFAULT_BAG_SPACE + 60;
|
||||||
|
} else if(Engine.getStore('wagon') > 0) {
|
||||||
|
return Path.DEFAULT_BAG_SPACE + 30;
|
||||||
|
} else if(Engine.getStore('rucksack') > 0) {
|
||||||
|
return Path.DEFAULT_BAG_SPACE + 10;
|
||||||
|
}
|
||||||
|
return Path.DEFAULT_BAG_SPACE;
|
||||||
|
},
|
||||||
|
|
||||||
|
getFreeSpace: function() {
|
||||||
|
var num = 0;
|
||||||
|
if(Path.outfit) {
|
||||||
|
for(var k in Path.outfit) {
|
||||||
|
var n = Path.outfit[k];
|
||||||
|
if(isNaN(n)) {
|
||||||
|
// No idea how this happens, but I will fix it here!
|
||||||
|
Path.outfit[k] = n = 0;
|
||||||
|
}
|
||||||
|
num += n * Path.getWeight(k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Path.getCapacity() - num;
|
||||||
|
},
|
||||||
|
|
||||||
|
updatePerks: function() {
|
||||||
|
if(State.perks) {
|
||||||
|
var perks = $('#perks');
|
||||||
|
var needsAppend = false;
|
||||||
|
if(perks.length == 0) {
|
||||||
|
needsAppend = true;
|
||||||
|
perks = $('<div>').attr('id', 'perks');
|
||||||
|
}
|
||||||
|
for(var k in State.perks) {
|
||||||
|
var id = 'perk_' + k.replace(' ', '-');
|
||||||
|
var r = $('#' + id);
|
||||||
|
if(State.perks[k] && r.length == 0) {
|
||||||
|
r = $('<div>').attr('id', id).addClass('perkRow').appendTo(perks);
|
||||||
|
$('<div>').addClass('row_key').text(k).appendTo(r);
|
||||||
|
$('<div>').addClass('tooltip bottom right').text(Engine.Perks[k].desc).appendTo(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(needsAppend && perks.children().length > 0) {
|
||||||
|
perks.appendTo(Path.panel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
updateOutfitting: function() {
|
||||||
|
var outfit = $('div#outfitting');
|
||||||
|
|
||||||
|
if(!Path.outfit) {
|
||||||
|
Path.outfit = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the armour row
|
||||||
|
var armour = "none";
|
||||||
|
if(Engine.getStore('s armour') > 0)
|
||||||
|
armour = "steel";
|
||||||
|
else if(Engine.getStore('i armour') > 0)
|
||||||
|
armour = "iron";
|
||||||
|
else if(Engine.getStore('l armour') > 0)
|
||||||
|
armour = "leather";
|
||||||
|
var aRow = $('#armourRow');
|
||||||
|
if(aRow.length == 0) {
|
||||||
|
aRow = $('<div>').attr('id', 'armourRow').addClass('outfitRow').prependTo(outfit);
|
||||||
|
$('<div>').addClass('row_key').text('armour').appendTo(aRow);
|
||||||
|
$('<div>').addClass('row_val').text(armour).appendTo(aRow);
|
||||||
|
$('<div>').addClass('clear').appendTo(aRow);
|
||||||
|
} else {
|
||||||
|
$('.row_val', aRow).text(armour);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the water row
|
||||||
|
var wRow = $('#waterRow');
|
||||||
|
if(wRow.length == 0) {
|
||||||
|
wRow = $('<div>').attr('id', 'waterRow').addClass('outfitRow').insertAfter(aRow);
|
||||||
|
$('<div>').addClass('row_key').text('water').appendTo(wRow);
|
||||||
|
$('<div>').addClass('row_val').text(World.getMaxWater()).appendTo(wRow);
|
||||||
|
$('<div>').addClass('clear').appendTo(wRow);
|
||||||
|
} else {
|
||||||
|
$('.row_val', wRow).text(World.getMaxWater());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var space = Path.getFreeSpace();
|
||||||
|
var total = 0;
|
||||||
|
// Add the non-craftables to the craftables
|
||||||
|
var carryable = $.extend({
|
||||||
|
'cured meat': { type: 'tool' },
|
||||||
|
'bullets': { type: 'tool' },
|
||||||
|
'grenade': {type: 'weapon' },
|
||||||
|
'bolas': {type: 'weapon' },
|
||||||
|
'laser rifle': {type: 'weapon' },
|
||||||
|
'energy cell': {type: 'tool' },
|
||||||
|
'bayonet': {type: 'weapon' },
|
||||||
|
'charm': {type: 'tool'}
|
||||||
|
}, Room.Craftables);
|
||||||
|
|
||||||
|
for(var k in carryable) {
|
||||||
|
var store = carryable[k];
|
||||||
|
var have = State.stores[k];
|
||||||
|
var num = Path.outfit[k];
|
||||||
|
num = typeof num == 'number' ? num : 0;
|
||||||
|
var numAvailable = Engine.getStore(k);
|
||||||
|
var row = $('div#outfit_row_' + k.replace(' ', '-'), outfit);
|
||||||
|
if((store.type == 'tool' || store.type == 'weapon') && have > 0) {
|
||||||
|
total += num * Path.getWeight(k);
|
||||||
|
if(row.length == 0) {
|
||||||
|
row = Path.createOutfittingRow(k, num);
|
||||||
|
|
||||||
|
var curPrev = null;
|
||||||
|
outfit.children().each(function(i) {
|
||||||
|
var child = $(this);
|
||||||
|
if(child.attr('id').indexOf('outfit_row_') == 0) {
|
||||||
|
var cName = child.attr('id').substring(11).replace('-', ' ');
|
||||||
|
if(cName < k && (curPrev == null || cName > curPrev)) {
|
||||||
|
curPrev = cName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(curPrev == null) {
|
||||||
|
row.insertAfter(wRow);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
row.insertAfter(outfit.find('#outfit_row_' + curPrev.replace(' ', '-')));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$('div#' + row.attr('id') + ' > div.row_val > span', outfit).text(num);
|
||||||
|
$('div#' + row.attr('id') + ' .tooltip .numAvailable', outfit).text(numAvailable - num);
|
||||||
|
}
|
||||||
|
if(num == 0) {
|
||||||
|
$('.dnBtn', row).addClass('disabled');
|
||||||
|
} else {
|
||||||
|
$('.dnBtn', row).removeClass('disabled');
|
||||||
|
}
|
||||||
|
if(num >= numAvailable || space < Path.getWeight(k)) {
|
||||||
|
$('.upBtn', row).addClass('disabled');
|
||||||
|
} else if(space >= Path.getWeight(k)) {
|
||||||
|
$('.upBtn', row).removeClass('disabled');
|
||||||
|
}
|
||||||
|
} else if(have == 0 && row.length > 0) {
|
||||||
|
row.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update bagspace
|
||||||
|
$('#bagspace').text('free ' + Math.floor(Path.getCapacity() - total) + '/' + Path.getCapacity());
|
||||||
|
|
||||||
|
if(Path.outfit['cured meat'] > 0) {
|
||||||
|
Button.setDisabled($('#embarkButton'), false);
|
||||||
|
} else {
|
||||||
|
Button.setDisabled($('#embarkButton'), true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
createOutfittingRow: function(name, num) {
|
||||||
|
var row = $('<div>').attr('id', 'outfit_row_' + name.replace(' ', '-')).addClass('outfitRow');
|
||||||
|
$('<div>').addClass('row_key').text(name).appendTo(row);
|
||||||
|
var val = $('<div>').addClass('row_val').appendTo(row);
|
||||||
|
|
||||||
|
$('<span>').text(num).appendTo(val);
|
||||||
|
$('<div>').addClass('upBtn').appendTo(val).click(Path.increaseSupply);
|
||||||
|
$('<div>').addClass('dnBtn').appendTo(val).click(Path.decreaseSupply);
|
||||||
|
$('<div>').addClass('clear').appendTo(row);
|
||||||
|
|
||||||
|
var numAvailable = Engine.getStore(name);
|
||||||
|
var tt = $('<div>').addClass('tooltip bottom right').appendTo(row);
|
||||||
|
$('<div>').addClass('row_key').text('weight').appendTo(tt);
|
||||||
|
$('<div>').addClass('row_val').text(Path.getWeight(name)).appendTo(tt);
|
||||||
|
$('<div>').addClass('row_key').text('available').appendTo(tt);
|
||||||
|
$('<div>').addClass('row_val').addClass('numAvailable').text(numAvailable).appendTo(tt);
|
||||||
|
|
||||||
|
return row;
|
||||||
|
},
|
||||||
|
|
||||||
|
increaseSupply: function() {
|
||||||
|
var supply = $(this).closest('.outfitRow').children('.row_key').text().replace('-', ' ');
|
||||||
|
Engine.log('increasing ' + supply);
|
||||||
|
var cur = Path.outfit[supply];
|
||||||
|
cur = typeof cur == 'number' ? cur : 0;
|
||||||
|
if(Path.getFreeSpace() >= Path.getWeight(supply) && cur < Engine.getStore(supply)) {
|
||||||
|
Path.outfit[supply] = cur + 1;
|
||||||
|
Path.updateOutfitting();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
decreaseSupply: function() {
|
||||||
|
var supply = $(this).closest('.outfitRow').children('.row_key').text().replace('-', ' ');
|
||||||
|
Engine.log('decreasing ' + supply);
|
||||||
|
var cur = Path.outfit[supply];
|
||||||
|
cur = typeof cur == 'number' ? cur : 0;
|
||||||
|
if(cur > 0) {
|
||||||
|
Path.outfit[supply] = cur - 1;
|
||||||
|
Path.updateOutfitting();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onArrival: function() {
|
||||||
|
Path.setTitle();
|
||||||
|
Path.updateOutfitting();
|
||||||
|
Path.updatePerks();
|
||||||
|
},
|
||||||
|
|
||||||
|
setTitle: function() {
|
||||||
|
document.title = 'A Dusty Path';
|
||||||
|
},
|
||||||
|
|
||||||
|
embark: function() {
|
||||||
|
for(var k in Path.outfit) {
|
||||||
|
Engine.addStore(k, -Path.outfit[k]);
|
||||||
|
}
|
||||||
|
World.onArrival();
|
||||||
|
$('#outerSlider').animate({left: '-700px'}, 300);
|
||||||
|
Engine.activeModule = World;
|
||||||
|
}
|
||||||
|
}
|
||||||
+1058
File diff suppressed because it is too large
Load Diff
+165
@@ -0,0 +1,165 @@
|
|||||||
|
/**
|
||||||
|
* Module that registers the starship!
|
||||||
|
*/
|
||||||
|
var Ship = {
|
||||||
|
LIFTOFF_COOLDOWN: 120,
|
||||||
|
ALLOY_PER_HULL: 1,
|
||||||
|
ALLOY_PER_THRUSTER: 1,
|
||||||
|
BASE_HULL: 0,
|
||||||
|
BASE_THRUSTERS: 1,
|
||||||
|
|
||||||
|
name: "Ship",
|
||||||
|
init: function(options) {
|
||||||
|
this.options = $.extend(
|
||||||
|
this.options,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
|
||||||
|
if(!State.ship) {
|
||||||
|
State.ship = {
|
||||||
|
hull: Ship.BASE_HULL,
|
||||||
|
thrusters: Ship.BASE_THRUSTERS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the Ship tab
|
||||||
|
this.tab = Header.addLocation("An Old Starship", "ship", Ship);
|
||||||
|
|
||||||
|
// Create the Ship panel
|
||||||
|
this.panel = $('<div>').attr('id', "shipPanel")
|
||||||
|
.addClass('location')
|
||||||
|
.appendTo('div#locationSlider');
|
||||||
|
|
||||||
|
Engine.updateSlider();
|
||||||
|
|
||||||
|
// Draw the hull label
|
||||||
|
var hullRow = $('<div>').attr('id', 'hullRow').appendTo('div#shipPanel');
|
||||||
|
$('<div>').addClass('row_key').text('hull:').appendTo(hullRow);
|
||||||
|
$('<div>').addClass('row_val').text(State.ship.hull).appendTo(hullRow);
|
||||||
|
$('<div>').addClass('clear').appendTo(hullRow);
|
||||||
|
|
||||||
|
// Draw the thrusters label
|
||||||
|
var engineRow = $('<div>').attr('id', 'engineRow').appendTo('div#shipPanel');
|
||||||
|
$('<div>').addClass('row_key').text('engine:').appendTo(engineRow);
|
||||||
|
$('<div>').addClass('row_val').text(State.ship.thrusters).appendTo(engineRow);
|
||||||
|
$('<div>').addClass('clear').appendTo(engineRow);
|
||||||
|
|
||||||
|
// Draw the reinforce button
|
||||||
|
new Button.Button({
|
||||||
|
id: 'reinforceButton',
|
||||||
|
text: 'reinforce hull',
|
||||||
|
click: Ship.reinforceHull,
|
||||||
|
width: '100px',
|
||||||
|
cost: {'alien alloy': Ship.ALLOY_PER_HULL}
|
||||||
|
}).appendTo('div#shipPanel');
|
||||||
|
|
||||||
|
// Draw the engine button
|
||||||
|
new Button.Button({
|
||||||
|
id: 'engineButton',
|
||||||
|
text: 'upgrade engine',
|
||||||
|
click: Ship.upgradeEngine,
|
||||||
|
width: '100px',
|
||||||
|
cost: {'alien alloy': Ship.ALLOY_PER_THRUSTER}
|
||||||
|
}).appendTo('div#shipPanel');
|
||||||
|
|
||||||
|
// Draw the lift off button
|
||||||
|
var b = new Button.Button({
|
||||||
|
id: 'liftoffButton',
|
||||||
|
text: 'lift off',
|
||||||
|
click: Ship.checkLiftOff,
|
||||||
|
width: '100px',
|
||||||
|
cooldown: Ship.LIFTOFF_COOLDOWN
|
||||||
|
}).appendTo('div#shipPanel');
|
||||||
|
|
||||||
|
if(State.ship.hull <= 0) {
|
||||||
|
Button.setDisabled(b, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init Space
|
||||||
|
Space.init();
|
||||||
|
},
|
||||||
|
|
||||||
|
options: {}, // Nothing for now
|
||||||
|
|
||||||
|
onArrival: function() {
|
||||||
|
Ship.setTitle();
|
||||||
|
if(!State.seenShip) {
|
||||||
|
Notifications.notify(Ship, 'somewhere above the debris cloud, the wanderer fleet hovers. been on this rock too long.');
|
||||||
|
State.seenShip = true;
|
||||||
|
Engine.saveGame();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setTitle: function() {
|
||||||
|
if(Engine.activeModule == this) {
|
||||||
|
document.title = "An Old Starship";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
reinforceHull: function() {
|
||||||
|
if(Engine.getStore('alien alloy') < Ship.ALLOY_PER_HULL) {
|
||||||
|
Notifications.notify(Ship, "not enough alien alloy");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Engine.addStore('alien alloy', -Ship.ALLOY_PER_HULL);
|
||||||
|
State.ship.hull++;
|
||||||
|
if(State.ship.hull > 0) {
|
||||||
|
Button.setDisabled($('#liftoffButton', Ship.panel), false);
|
||||||
|
}
|
||||||
|
$('#hullRow .row_val', Ship.panel).text(State.ship.hull);
|
||||||
|
},
|
||||||
|
|
||||||
|
upgradeEngine: function() {
|
||||||
|
if(Engine.getStore('alien alloy') < Ship.ALLOY_PER_THRUSTER) {
|
||||||
|
Notifications.notify(Ship, "not enough alien alloy");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Engine.addStore('alien alloy', -Ship.ALLOY_PER_THRUSTER);
|
||||||
|
State.ship.thrusters++;
|
||||||
|
$('#engineRow .row_val', Ship.panel).text(State.ship.thrusters);
|
||||||
|
},
|
||||||
|
|
||||||
|
getMaxHull: function() {
|
||||||
|
return State.ship.hull;
|
||||||
|
},
|
||||||
|
|
||||||
|
checkLiftOff: function() {
|
||||||
|
if(!State.ship.seenWarning) {
|
||||||
|
Events.startEvent({
|
||||||
|
title: 'Ready to Leave?',
|
||||||
|
scenes: {
|
||||||
|
'start': {
|
||||||
|
text: [
|
||||||
|
"time to get out of this place. won't be coming back."
|
||||||
|
],
|
||||||
|
buttons: {
|
||||||
|
'fly': {
|
||||||
|
text: 'lift off',
|
||||||
|
onChoose: function() {
|
||||||
|
State.ship.seenWarning = true;
|
||||||
|
Ship.liftOff();
|
||||||
|
},
|
||||||
|
nextScene: 'end'
|
||||||
|
},
|
||||||
|
'wait': {
|
||||||
|
text: 'linger',
|
||||||
|
onChoose: function() {
|
||||||
|
Button.clearCooldown($('#liftoffButton'));
|
||||||
|
},
|
||||||
|
nextScene: 'end'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Ship.liftOff();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
liftOff: function () {
|
||||||
|
$('#outerSlider').animate({top: '700px'}, 300);
|
||||||
|
Space.onArrival();
|
||||||
|
Engine.activeModule = Space;
|
||||||
|
}
|
||||||
|
};
|
||||||
+453
@@ -0,0 +1,453 @@
|
|||||||
|
/**
|
||||||
|
* Module that registers spaaaaaaaaace!
|
||||||
|
*/
|
||||||
|
var Space = {
|
||||||
|
SHIP_SPEED: 3,
|
||||||
|
BASE_ASTEROID_DELAY: 500,
|
||||||
|
BASE_ASTEROID_SPEED: 1500,
|
||||||
|
FTB_SPEED: 60000,
|
||||||
|
STAR_WIDTH: 3000,
|
||||||
|
STAR_HEIGHT: 3000,
|
||||||
|
NUM_STARS: 200,
|
||||||
|
STAR_SPEED: 60000,
|
||||||
|
FRAME_DELAY: 100,
|
||||||
|
|
||||||
|
stars: null,
|
||||||
|
backStars: null,
|
||||||
|
ship: null,
|
||||||
|
lastMove: null,
|
||||||
|
done: false,
|
||||||
|
shipX: null,
|
||||||
|
shipY: null,
|
||||||
|
|
||||||
|
hull: 0,
|
||||||
|
|
||||||
|
name: "Space",
|
||||||
|
init: function(options) {
|
||||||
|
this.options = $.extend(
|
||||||
|
this.options,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create the Space panel
|
||||||
|
this.panel = $('<div>').attr('id', "spacePanel")
|
||||||
|
.addClass('location')
|
||||||
|
.appendTo('#outerSlider');
|
||||||
|
|
||||||
|
// Create the ship
|
||||||
|
Space.ship = $('<div>').text("@").attr('id', 'ship').appendTo(this.panel);
|
||||||
|
|
||||||
|
// Create the hull display
|
||||||
|
var h = $('<div>').attr('id', 'hullRemaining').appendTo(this.panel);
|
||||||
|
$('<div>').addClass('row_key').text('hull: ').appendTo(h);
|
||||||
|
$('<div>').addClass('row_val').appendTo(h);
|
||||||
|
},
|
||||||
|
|
||||||
|
options: {}, // Nothing for now
|
||||||
|
|
||||||
|
onArrival: function() {
|
||||||
|
Space.done = false;
|
||||||
|
Engine.keyLock = false;
|
||||||
|
Space.hull = Ship.getMaxHull();
|
||||||
|
Space.altitude = 0;
|
||||||
|
Space.setTitle();
|
||||||
|
Space.updateHull();
|
||||||
|
|
||||||
|
Space.up =
|
||||||
|
Space.down =
|
||||||
|
Space.left =
|
||||||
|
Space.right = false;
|
||||||
|
|
||||||
|
Space.ship.css({
|
||||||
|
top: '350px',
|
||||||
|
left: '350px'
|
||||||
|
});
|
||||||
|
Space.startAscent();
|
||||||
|
Space._shipTimer = setInterval(Space.moveShip, 33);
|
||||||
|
},
|
||||||
|
|
||||||
|
setTitle: function() {
|
||||||
|
if(Engine.activeModule == this) {
|
||||||
|
var t;
|
||||||
|
if(Space.altitude < 10) {
|
||||||
|
t = "Troposphere";
|
||||||
|
} else if(Space.altitude < 20) {
|
||||||
|
t = "Stratosphere";
|
||||||
|
} else if(Space.altitude < 30) {
|
||||||
|
t = "Mesosphere";
|
||||||
|
} else if(Space.altitude < 45) {
|
||||||
|
t = "Thermosphere";
|
||||||
|
} else if(Space.altitude < 60){
|
||||||
|
t = "Exosphere";
|
||||||
|
} else {
|
||||||
|
t = "Space";
|
||||||
|
}
|
||||||
|
document.title = t;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getSpeed: function() {
|
||||||
|
return Space.SHIP_SPEED + State.ship.thrusters;
|
||||||
|
},
|
||||||
|
|
||||||
|
updateHull: function() {
|
||||||
|
$('div#hullRemaining div.row_val', Space.panel).text(Space.hull + '/' + Ship.getMaxHull());
|
||||||
|
},
|
||||||
|
|
||||||
|
createAsteroid: function(noNext) {
|
||||||
|
var r = Math.random();
|
||||||
|
var c;
|
||||||
|
if(r < 0.2)
|
||||||
|
c = '#';
|
||||||
|
else if(r < 0.4)
|
||||||
|
c = '$'
|
||||||
|
else if(r < 0.6)
|
||||||
|
c = '%';
|
||||||
|
else if(r < 0.8)
|
||||||
|
c = '&';
|
||||||
|
else
|
||||||
|
c = 'H';
|
||||||
|
|
||||||
|
var x = Math.floor(Math.random() * 700);
|
||||||
|
var a = $('<div>').addClass('asteroid').text(c).appendTo('#spacePanel').css('left', x + 'px')
|
||||||
|
a.data({
|
||||||
|
xMin: x,
|
||||||
|
xMax: x + a.width(),
|
||||||
|
height: a.height()
|
||||||
|
});
|
||||||
|
a.animate({
|
||||||
|
top: '740px'
|
||||||
|
}, {
|
||||||
|
duration: Space.BASE_ASTEROID_SPEED - Math.floor(Math.random() * (Space.BASE_ASTEROID_SPEED * 0.65)),
|
||||||
|
easing: 'linear',
|
||||||
|
progress: function() {
|
||||||
|
// Collision detection
|
||||||
|
var t = $(this);
|
||||||
|
if(t.data('xMin') <= Space.shipX && t.data('xMax') >= Space.shipX) {
|
||||||
|
var aY = t.css('top');
|
||||||
|
aY = parseFloat(aY.substring(0, aY.length - 2));
|
||||||
|
|
||||||
|
if(aY <= Space.shipY && aY + t.data('height') >= Space.shipY) {
|
||||||
|
// Collision
|
||||||
|
Engine.log('collision');
|
||||||
|
t.remove();
|
||||||
|
Space.hull--;
|
||||||
|
Space.updateHull();
|
||||||
|
if(Space.hull == 0) {
|
||||||
|
Space.crash();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
|
$(this).remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(!noNext) {
|
||||||
|
|
||||||
|
// Harder
|
||||||
|
if(Space.altitude > 10) {
|
||||||
|
Space.createAsteroid(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// HARDER
|
||||||
|
if(Space.altitude > 20) {
|
||||||
|
Space.createAsteroid(true);
|
||||||
|
Space.createAsteroid(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// HAAAAAARDERRRRR!!!!1
|
||||||
|
if(Space.altitude > 40) {
|
||||||
|
Space.createAsteroid(true);
|
||||||
|
Space.createAsteroid(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!Space.done) {
|
||||||
|
setTimeout(Space.createAsteroid, 1000 - (Space.altitude * 10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
moveShip: function() {
|
||||||
|
var x = Space.ship.css('left');
|
||||||
|
x = parseFloat(x.substring(0, x.length - 2));
|
||||||
|
var y = Space.ship.css('top');
|
||||||
|
y = parseFloat(y.substring(0, y.length - 2));
|
||||||
|
|
||||||
|
var dx = 0, dy = 0;
|
||||||
|
|
||||||
|
if(Space.up) {
|
||||||
|
dy -= Space.getSpeed();
|
||||||
|
} else if(Space.down) {
|
||||||
|
dy += Space.getSpeed();
|
||||||
|
}
|
||||||
|
if(Space.left) {
|
||||||
|
dx -= Space.getSpeed();
|
||||||
|
} else if(Space.right) {
|
||||||
|
dx += Space.getSpeed();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dx != 0 && dy != 0) {
|
||||||
|
dx = dx / Math.sqrt(2);
|
||||||
|
dy = dy / Math.sqrt(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Space.lastMove != null) {
|
||||||
|
var dt = Date.now() - Space.lastMove;
|
||||||
|
dx *= dt / 33;
|
||||||
|
dy *= dt / 33;
|
||||||
|
}
|
||||||
|
|
||||||
|
x = x + dx;
|
||||||
|
y = y + dy;
|
||||||
|
if(x < 10) {
|
||||||
|
x = 10;
|
||||||
|
} else if(x > 690) {
|
||||||
|
x = 690;
|
||||||
|
}
|
||||||
|
if(y < 10) {
|
||||||
|
y = 10;
|
||||||
|
} else if(y > 690) {
|
||||||
|
y = 690;
|
||||||
|
}
|
||||||
|
|
||||||
|
Space.shipX = x;
|
||||||
|
Space.shipY = y;
|
||||||
|
|
||||||
|
Space.ship.css({
|
||||||
|
left: x + 'px',
|
||||||
|
top: y + 'px',
|
||||||
|
});
|
||||||
|
|
||||||
|
Space.lastMove = Date.now();
|
||||||
|
},
|
||||||
|
|
||||||
|
startAscent: function() {
|
||||||
|
$('body').addClass('noMask').css({backgroundColor: '#FFFFFF'}).animate({
|
||||||
|
backgroundColor: '#000000'
|
||||||
|
}, {
|
||||||
|
duration: Space.FTB_SPEED,
|
||||||
|
easing: 'linear',
|
||||||
|
progress: function() {
|
||||||
|
var cur = $('body').css('background-color');
|
||||||
|
var s = 'linear-gradient(rgba' + cur.substring(3, cur.length - 1) + ', 0) 0%, rgba' +
|
||||||
|
cur.substring(3, cur.length - 1) + ', 1) 100%)';
|
||||||
|
$('#notifyGradient').attr('style', 'background-color:'+cur+';background:-webkit-' + s + ';background:' + s);
|
||||||
|
},
|
||||||
|
complete: Space.endGame
|
||||||
|
});
|
||||||
|
Space.drawStars();
|
||||||
|
Space._timer = setInterval(function() {
|
||||||
|
Space.altitude += 1;
|
||||||
|
if(Space.altitude % 10 == 0) {
|
||||||
|
Space.setTitle();
|
||||||
|
}
|
||||||
|
if(Space.altitude > 60) {
|
||||||
|
clearInterval(Space._timer);
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
$('#spacePanel, .deleteSave, .share').animate({color: 'white'}, 500, 'linear');
|
||||||
|
}, Space.FTB_SPEED / 2);
|
||||||
|
|
||||||
|
Space.createAsteroid();
|
||||||
|
},
|
||||||
|
|
||||||
|
drawStars: function(duration) {
|
||||||
|
var starsContainer = $('<div>').attr('id', 'starsContainer').appendTo('body');
|
||||||
|
Space.stars = $('<div>').css('bottom', '0px').attr('id', 'stars').appendTo(starsContainer);
|
||||||
|
var s1 = $('<div>').css({
|
||||||
|
width: Space.STAR_WIDTH + 'px',
|
||||||
|
height: Space.STAR_HEIGHT + 'px'
|
||||||
|
});
|
||||||
|
var s2 = s1.clone();
|
||||||
|
Space.stars.append(s1).append(s2);
|
||||||
|
Space.drawStarAsync(s1, s2, 0);
|
||||||
|
Space.stars.data('speed', Space.STAR_SPEED);
|
||||||
|
Space.startAnimation(Space.stars);
|
||||||
|
|
||||||
|
Space.starsBack = $('<div>').css('bottom', '0px').attr('id', 'starsBack').appendTo(starsContainer);
|
||||||
|
s1 = $('<div>').css({
|
||||||
|
width: Space.STAR_WIDTH + 'px',
|
||||||
|
height: Space.STAR_HEIGHT + 'px'
|
||||||
|
});
|
||||||
|
s2 = s1.clone();
|
||||||
|
Space.starsBack.append(s1).append(s2);
|
||||||
|
Space.drawStarAsync(s1, s2, 0);
|
||||||
|
Space.starsBack.data('speed', Space.STAR_SPEED * 2);
|
||||||
|
Space.startAnimation(Space.starsBack);
|
||||||
|
},
|
||||||
|
|
||||||
|
startAnimation: function(el) {
|
||||||
|
el.animate({bottom: '-3000px'}, el.data('speed'), 'linear', function() {
|
||||||
|
$(this).css('bottom', '0px');
|
||||||
|
Space.startAnimation($(this));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
drawStarAsync: function(el, el2, num) {
|
||||||
|
var top = Math.floor(Math.random() * Space.STAR_HEIGHT) + 'px';
|
||||||
|
var left = Math.floor(Math.random() * Space.STAR_WIDTH) + 'px';
|
||||||
|
$('<div>').text('.').addClass('star').css({
|
||||||
|
top: top,
|
||||||
|
left: left
|
||||||
|
}).appendTo(el);
|
||||||
|
$('<div>').text('.').addClass('star').css({
|
||||||
|
top: top,
|
||||||
|
left: left
|
||||||
|
}).appendTo(el2);
|
||||||
|
if(num < Space.NUM_STARS) {
|
||||||
|
setTimeout(function() { Space.drawStarAsync(el, el2, num + 1); }, 100);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
crash: function() {
|
||||||
|
if(Space.done) return;
|
||||||
|
Engine.keyLock = true;
|
||||||
|
Space.done = true;
|
||||||
|
clearInterval(Space._timer);
|
||||||
|
clearInterval(Space._shipTimer);
|
||||||
|
|
||||||
|
// Craaaaash!
|
||||||
|
$('body').removeClass('noMask').stop().animate({
|
||||||
|
backgroundColor: '#FFFFFF'
|
||||||
|
}, {
|
||||||
|
duration: 300,
|
||||||
|
progress: function() {
|
||||||
|
var cur = $('body').css('background-color');
|
||||||
|
var s = 'linear-gradient(rgba' + cur.substring(3, cur.length - 1) + ', 0) 0%, rgba' +
|
||||||
|
cur.substring(3, cur.length - 1) + ', 1) 100%)';
|
||||||
|
$('#notifyGradient').attr('style', 'background-color:'+cur+';background:-webkit-' + s + ';background:' + s);
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
|
Space.stars.remove();
|
||||||
|
Space.starsBack.remove();
|
||||||
|
Space.stars = Space.starsBack = null;
|
||||||
|
$('#starsContainer').remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$('#spacePanel, .deleteSave, .share').animate({color: 'black'}, 300, 'linear');
|
||||||
|
$('#outerSlider').animate({top: '0px'}, 300, 'linear');
|
||||||
|
Engine.activeModule = Ship;
|
||||||
|
Ship.onArrival();
|
||||||
|
Button.cooldown($('#liftoffButton'));
|
||||||
|
Engine.event('progress', 'crash');
|
||||||
|
},
|
||||||
|
|
||||||
|
endGame: function() {
|
||||||
|
if(Space.done) return;
|
||||||
|
Engine.event('progress', 'win');
|
||||||
|
Space.done = true;
|
||||||
|
clearInterval(Space._timer);
|
||||||
|
clearInterval(Space._shipTimer);
|
||||||
|
clearTimeout(Engine._saveTimer);
|
||||||
|
clearTimeout(Outside._popTimeout);
|
||||||
|
clearTimeout(Engine._incomeTimeout);
|
||||||
|
clearTimeout(Events._eventTimeout);
|
||||||
|
clearTimeout(Room._fireTimer);
|
||||||
|
clearTimeout(Room._tempTimer);
|
||||||
|
for(var k in Room.Craftables) {
|
||||||
|
Room.Craftables[k].button = null;
|
||||||
|
}
|
||||||
|
for(var k in Room.TradeGoods) {
|
||||||
|
Room.TradeGoods[k].button = null;
|
||||||
|
}
|
||||||
|
delete Outside._popTimeout;
|
||||||
|
|
||||||
|
$('#hullRemaining', Space.panel).animate({opacity: 0}, 500, 'linear');
|
||||||
|
Space.ship.animate({
|
||||||
|
top: '350px',
|
||||||
|
left: '240px'
|
||||||
|
}, 3000, 'linear', function() {
|
||||||
|
setTimeout(function() {
|
||||||
|
Space.ship.animate({
|
||||||
|
top: '-100px'
|
||||||
|
}, 200, 'linear', function() {
|
||||||
|
// Restart everything! Play FOREVER!
|
||||||
|
$('#outerSlider').css({'left': '0px', 'top': '0px'});
|
||||||
|
$('#locationSlider, #worldPanel, #spacePanel, #notifications').remove();
|
||||||
|
$('#header').empty();
|
||||||
|
setTimeout(function() {
|
||||||
|
$('body').removeClass('noMask').stop().animate({
|
||||||
|
opacity: 0,
|
||||||
|
'background-color': '#FFF'
|
||||||
|
}, {
|
||||||
|
duration: 2000,
|
||||||
|
progress: function() {
|
||||||
|
var cur = $('body').css('background-color');
|
||||||
|
var s = 'linear-gradient(rgba' + cur.substring(3, cur.length - 1) + ', 0) 0%, rgba' +
|
||||||
|
cur.substring(3, cur.length - 1) + ', 1) 100%)';
|
||||||
|
$('#notifyGradient').attr('style', 'background-color:'+cur+';background:-webkit-' + s + ';background:' + s);
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
|
$('#starsContainer, .deleteSave, .share').remove();
|
||||||
|
if(typeof Storage != 'undefined' && localStorage) {
|
||||||
|
localStorage.clear();
|
||||||
|
}
|
||||||
|
delete window.State;
|
||||||
|
Engine.options = {};
|
||||||
|
setTimeout(function() {
|
||||||
|
Engine.init();
|
||||||
|
$('body').animate({
|
||||||
|
opacity: 1
|
||||||
|
}, 500, 'linear');
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
keyDown: function(event) {
|
||||||
|
switch(event.which) {
|
||||||
|
case 38: // Up
|
||||||
|
case 87:
|
||||||
|
Space.up = true;
|
||||||
|
Engine.log('up on');
|
||||||
|
break;
|
||||||
|
case 40: // Down
|
||||||
|
case 83:
|
||||||
|
Space.down = true;
|
||||||
|
Engine.log('down on');
|
||||||
|
break;
|
||||||
|
case 37: // Left
|
||||||
|
case 65:
|
||||||
|
Space.left = true;
|
||||||
|
Engine.log('left on');
|
||||||
|
break;
|
||||||
|
case 39: // Right
|
||||||
|
case 68:
|
||||||
|
Space.right = true;
|
||||||
|
Engine.log('right on');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
keyUp: function(event) {
|
||||||
|
switch(event.which) {
|
||||||
|
case 38: // Up
|
||||||
|
case 87:
|
||||||
|
Space.up = false;
|
||||||
|
Engine.log('up off');
|
||||||
|
break;
|
||||||
|
case 40: // Down
|
||||||
|
case 83:
|
||||||
|
Space.down = false;
|
||||||
|
Engine.log('down off');
|
||||||
|
break;
|
||||||
|
case 37: // Left
|
||||||
|
case 65:
|
||||||
|
Space.left = false;
|
||||||
|
Engine.log('left off');
|
||||||
|
break;
|
||||||
|
case 39: // Right
|
||||||
|
case 68:
|
||||||
|
Space.right = false;
|
||||||
|
Engine.log('right off');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
+825
@@ -0,0 +1,825 @@
|
|||||||
|
var World = {
|
||||||
|
|
||||||
|
RADIUS: 30,
|
||||||
|
TILE: {
|
||||||
|
VILLAGE: 'A',
|
||||||
|
IRON_MINE: 'I',
|
||||||
|
COAL_MINE: 'C',
|
||||||
|
SULPHUR_MINE: 'S',
|
||||||
|
FOREST: 'T',
|
||||||
|
FIELD: ',',
|
||||||
|
BARRENS: '.',
|
||||||
|
ROAD: '#',
|
||||||
|
HOUSE: 'H',
|
||||||
|
CAVE: 'V',
|
||||||
|
TOWN: 'O',
|
||||||
|
CITY: 'Y',
|
||||||
|
OUTPOST: 'P',
|
||||||
|
SHIP: 'W',
|
||||||
|
BOREHOLE: 'B',
|
||||||
|
BATTLEFIELD: 'F',
|
||||||
|
SWAMP: 'M'
|
||||||
|
},
|
||||||
|
TILE_PROBS: {},
|
||||||
|
LANDMARKS: {},
|
||||||
|
STICKINESS: 0.5, // 0 <= x <= 1
|
||||||
|
LIGHT_RADIUS: 2,
|
||||||
|
BASE_WATER: 10,
|
||||||
|
MOVES_PER_FOOD: 2,
|
||||||
|
MOVES_PER_WATER: 1,
|
||||||
|
DEATH_COOLDOWN: 120,
|
||||||
|
FIGHT_CHANCE: 0.20,
|
||||||
|
BASE_HEALTH: 10,
|
||||||
|
BASE_HIT_CHANCE: 0.8,
|
||||||
|
MEAT_HEAL: 10,
|
||||||
|
FIGHT_DELAY: 3, // At least three moves between fights
|
||||||
|
|
||||||
|
Weapons: {
|
||||||
|
'fists': {
|
||||||
|
verb: 'punch',
|
||||||
|
type: 'unarmed',
|
||||||
|
damage: 1,
|
||||||
|
cooldown: 2
|
||||||
|
},
|
||||||
|
'bone spear': {
|
||||||
|
verb: 'stab',
|
||||||
|
type: 'melee',
|
||||||
|
damage: 2,
|
||||||
|
cooldown: 2
|
||||||
|
},
|
||||||
|
'iron sword': {
|
||||||
|
verb: 'swing',
|
||||||
|
type: 'melee',
|
||||||
|
damage: 4,
|
||||||
|
cooldown: 2
|
||||||
|
},
|
||||||
|
'steel sword': {
|
||||||
|
verb: 'slash',
|
||||||
|
type: 'melee',
|
||||||
|
damage: 6,
|
||||||
|
cooldown: 2
|
||||||
|
},
|
||||||
|
'bayonet': {
|
||||||
|
verb: 'thrust',
|
||||||
|
type: 'melee',
|
||||||
|
damage: 8,
|
||||||
|
cooldown: 2
|
||||||
|
},
|
||||||
|
'rifle': {
|
||||||
|
verb: 'shoot',
|
||||||
|
type: 'ranged',
|
||||||
|
damage: 5,
|
||||||
|
cooldown: 1,
|
||||||
|
cost: { 'bullets': 1 }
|
||||||
|
},
|
||||||
|
'laser rifle': {
|
||||||
|
verb: 'blast',
|
||||||
|
type: 'ranged',
|
||||||
|
damage: 8,
|
||||||
|
cooldown: 1,
|
||||||
|
cost: { 'energy cell': 1 }
|
||||||
|
},
|
||||||
|
'grenade': {
|
||||||
|
verb: 'lob',
|
||||||
|
type: 'ranged',
|
||||||
|
damage: 15,
|
||||||
|
cooldown: 5,
|
||||||
|
cost: { 'grenade': 1 }
|
||||||
|
},
|
||||||
|
'bolas': {
|
||||||
|
verb: 'tangle',
|
||||||
|
type: 'ranged',
|
||||||
|
damage: 'stun',
|
||||||
|
cooldown: 15,
|
||||||
|
cost: { 'bolas': 1 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
name: 'World',
|
||||||
|
options: {}, // Nothing for now
|
||||||
|
init: function(options) {
|
||||||
|
this.options = $.extend(
|
||||||
|
this.options,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
|
||||||
|
// Setup probabilities. Sum must equal 1.
|
||||||
|
World.TILE_PROBS[World.TILE.FOREST] = 0.15;
|
||||||
|
World.TILE_PROBS[World.TILE.FIELD] = 0.35;
|
||||||
|
World.TILE_PROBS[World.TILE.BARRENS] = 0.5;
|
||||||
|
|
||||||
|
// Setpiece definitions
|
||||||
|
World.LANDMARKS[World.TILE.OUTPOST] = { num: 0, minRadius: 0, maxRadius: 0, scene: 'outpost', label: 'An Outpost' };
|
||||||
|
World.LANDMARKS[World.TILE.IRON_MINE] = { num: 1, minRadius: 5, maxRadius: 5, scene: 'ironmine', label: 'Iron Mine' };
|
||||||
|
World.LANDMARKS[World.TILE.COAL_MINE] = { num: 1, minRadius: 10, maxRadius: 10, scene: 'coalmine', label: 'Coal Mine' };
|
||||||
|
World.LANDMARKS[World.TILE.SULPHUR_MINE] = { num: 1, minRadius: 20, maxRadius: 20, scene: 'sulphurmine', label: 'Sulphur Mine' };
|
||||||
|
World.LANDMARKS[World.TILE.HOUSE] = { num: 10, minRadius: 0, maxRadius: World.RADIUS * 1.5, scene: 'house', label: 'An Old House' };
|
||||||
|
World.LANDMARKS[World.TILE.CAVE] = { num: 5, minRadius: 3, maxRadius: 10, scene: 'cave', label: 'A Damp Cave' };
|
||||||
|
World.LANDMARKS[World.TILE.TOWN] = { num: 10, minRadius: 10, maxRadius: 20, scene: 'town', label: 'An Abandoned Town' };
|
||||||
|
World.LANDMARKS[World.TILE.CITY] = { num: 20, minRadius: 20, maxRadius: World.RADIUS * 1.5, scene: 'city', label: 'A Ruined City' };
|
||||||
|
World.LANDMARKS[World.TILE.SHIP] = {num: 1, minRadius: 28, maxRadius: 28, scene: 'ship', label: 'A Crashed Starship'};
|
||||||
|
World.LANDMARKS[World.TILE.BOREHOLE] = {num: 10, minRadius: 15, maxRadius: World.RADIUS * 1.5, scene: 'borehole', label: 'A Borehole'};
|
||||||
|
World.LANDMARKS[World.TILE.BATTLEFIELD] = {num: 5, minRadius: 18, maxRadius: World.RADIUS * 1.5, scene: 'battlefield', label: 'A Battlefield'};
|
||||||
|
World.LANDMARKS[World.TILE.SWAMP] = {num: 1, minRadius: 15, maxRadius: World.RADIUS * 1.5, scene: 'swamp', label: 'A Murky Swamp'};
|
||||||
|
|
||||||
|
if(typeof State.world == 'undefined') {
|
||||||
|
State.world = {
|
||||||
|
map: World.generateMap(),
|
||||||
|
mask: World.newMask()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the World panel
|
||||||
|
this.panel = $('<div>').attr('id', "worldPanel").addClass('location').appendTo('#outerSlider');
|
||||||
|
|
||||||
|
// Create the shrink wrapper
|
||||||
|
var outer = $('<div>').attr('id', 'worldOuter').appendTo(this.panel);
|
||||||
|
|
||||||
|
// Create the bag panel
|
||||||
|
$('<div>').attr('id', 'bagspace-world').append($('<div>')).appendTo(outer);
|
||||||
|
$('<div>').attr('id', 'backpackTitle').appendTo(outer);
|
||||||
|
$('<div>').attr('id', 'backpackSpace').appendTo(outer);
|
||||||
|
$('<div>').attr('id', 'healthCounter').appendTo(outer);
|
||||||
|
|
||||||
|
Engine.updateOuterSlider();
|
||||||
|
},
|
||||||
|
|
||||||
|
clearDungeon: function() {
|
||||||
|
Engine.event('progress', 'dungeon cleared');
|
||||||
|
World.state.map[World.curPos[0]][World.curPos[1]] = World.TILE.OUTPOST;
|
||||||
|
World.drawRoad();
|
||||||
|
},
|
||||||
|
|
||||||
|
drawRoad: function() {
|
||||||
|
var xDist = World.curPos[0] - World.RADIUS;
|
||||||
|
var yDist = World.curPos[1] - World.RADIUS;
|
||||||
|
var xDir = Math.abs(xDist)/xDist;
|
||||||
|
var yDir = Math.abs(yDist)/yDist;
|
||||||
|
var xIntersect, yIntersect;
|
||||||
|
if(Math.abs(xDist) > Math.abs(yDist)) {
|
||||||
|
xIntersect = World.RADIUS;
|
||||||
|
yIntersect = World.RADIUS + yDist;
|
||||||
|
} else {
|
||||||
|
xIntersect = World.RADIUS + xDist;
|
||||||
|
yIntersect = World.RADIUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(var x = 0; x < Math.abs(xDist); x++) {
|
||||||
|
if(World.isTerrain(World.state.map[World.RADIUS + (xDir*x)][yIntersect])) {
|
||||||
|
World.state.map[World.RADIUS + (xDir*x)][yIntersect] = World.TILE.ROAD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(var y = 0; y < Math.abs(yDist); y++) {
|
||||||
|
if(World.isTerrain(World.state.map[xIntersect][World.RADIUS + (yDir*y)])) {
|
||||||
|
World.state.map[xIntersect][World.RADIUS + (yDir*y)] = World.TILE.ROAD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
World.drawMap();
|
||||||
|
},
|
||||||
|
|
||||||
|
updateSupplies: function() {
|
||||||
|
var supplies = $('div#bagspace-world > div');
|
||||||
|
|
||||||
|
if(!Path.outfit) {
|
||||||
|
Path.outfit = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add water
|
||||||
|
var water = $('div#supply_water');
|
||||||
|
if(World.water > 0 && water.length == 0) {
|
||||||
|
water = World.createItemDiv('water', World.water);
|
||||||
|
water.prependTo(supplies);
|
||||||
|
} else if(World.water > 0) {
|
||||||
|
$('div#supply_water', supplies).text('water:' + World.water);
|
||||||
|
} else {
|
||||||
|
water.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
var total = 0;
|
||||||
|
for(var k in Path.outfit) {
|
||||||
|
var item = $('div#supply_' + k.replace(' ', '-'), supplies);
|
||||||
|
var num = Path.outfit[k];
|
||||||
|
total += num * Path.getWeight(k);
|
||||||
|
if(num > 0 && item.length == 0) {
|
||||||
|
item = World.createItemDiv(k, num);
|
||||||
|
if(k == 'cured meat' && World.water > 0) {
|
||||||
|
item.insertAfter(water);
|
||||||
|
} else if(k == 'cured meat') {
|
||||||
|
item.prependTo(supplies);
|
||||||
|
} else {
|
||||||
|
item.appendTo(supplies);
|
||||||
|
}
|
||||||
|
} else if(num > 0) {
|
||||||
|
$('div#' + item.attr('id'), supplies).text(k + ':' + num);
|
||||||
|
} else {
|
||||||
|
item.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update label
|
||||||
|
var t = 'pockets';
|
||||||
|
if(Engine.getStore('rucksack') > 0) {
|
||||||
|
t = 'rucksack';
|
||||||
|
}
|
||||||
|
$('#backpackTitle').text(t);
|
||||||
|
|
||||||
|
// Update bagspace
|
||||||
|
$('#backpackSpace').text('free ' + Math.floor(Path.getCapacity() - total) + '/' + Path.getCapacity());
|
||||||
|
},
|
||||||
|
|
||||||
|
setWater: function(w) {
|
||||||
|
World.water = w;
|
||||||
|
if(World.water > World.getMaxWater()) {
|
||||||
|
World.water = World.getMaxWater();
|
||||||
|
}
|
||||||
|
World.updateSupplies();
|
||||||
|
},
|
||||||
|
|
||||||
|
setHp: function(hp) {
|
||||||
|
if(typeof hp == 'number' && !isNaN(hp)) {
|
||||||
|
World.health = hp;
|
||||||
|
if(World.health > World.getMaxHealth()) {
|
||||||
|
World.health = World.getMaxHealth();
|
||||||
|
}
|
||||||
|
$('#healthCounter').text('hp: ' + World.health + '/' + World.getMaxHealth());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
createItemDiv: function(name, num) {
|
||||||
|
var div = $('<div>').attr('id', 'supply_' + name.replace(' ', '-'))
|
||||||
|
.addClass('supplyItem')
|
||||||
|
.text(name + ':' + num);
|
||||||
|
|
||||||
|
return div;
|
||||||
|
},
|
||||||
|
|
||||||
|
keyDown: function(event) {
|
||||||
|
var moved = true;
|
||||||
|
var oldTile = World.state.map[World.curPos[0]][World.curPos[1]];
|
||||||
|
switch(event.which) {
|
||||||
|
case 38: // Up
|
||||||
|
case 87:
|
||||||
|
Engine.log('up');
|
||||||
|
if(World.curPos[1] > 0) World.curPos[1]--;
|
||||||
|
break;
|
||||||
|
case 40: // Down
|
||||||
|
case 83:
|
||||||
|
Engine.log('down');
|
||||||
|
if(World.curPos[1] < World.RADIUS * 2) World.curPos[1]++;
|
||||||
|
break;
|
||||||
|
case 37: // Left
|
||||||
|
case 65:
|
||||||
|
Engine.log('left');
|
||||||
|
if(World.curPos[0] > 0) World.curPos[0]--;
|
||||||
|
break;
|
||||||
|
case 39: // Right
|
||||||
|
case 68:
|
||||||
|
Engine.log('right');
|
||||||
|
if(World.curPos[0] < World.RADIUS * 2) World.curPos[0]++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
moved = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(moved) {
|
||||||
|
World.narrateMove(oldTile, World.state.map[World.curPos[0]][World.curPos[1]]);
|
||||||
|
World.lightMap(World.curPos[0], World.curPos[1], World.state.mask);
|
||||||
|
World.drawMap();
|
||||||
|
World.doSpace();
|
||||||
|
if(World.checkDanger()) {
|
||||||
|
if(World.danger) {
|
||||||
|
Notifications.notify(World, 'dangerous to be this far from the village without proper protection')
|
||||||
|
} else {
|
||||||
|
Notifications.notify(World, 'safer here');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
checkDanger: function() {
|
||||||
|
World.danger = typeof World.danger == 'undefined' ? false: World.danger;
|
||||||
|
if(!World.danger) {
|
||||||
|
if(!Engine.getStore('i armour') > 0 && World.getDistance() >= 8) {
|
||||||
|
World.danger = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(!Engine.getStore('s armour') > 0 && World.getDistance() >= 18) {
|
||||||
|
World.danger = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(World.getDistance() < 8) {
|
||||||
|
World.danger = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(World.getDistance < 18 && Engine.getStore('i armour') > 0) {
|
||||||
|
World.danger = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
useSupplies: function() {
|
||||||
|
World.foodMove++;
|
||||||
|
World.waterMove++;
|
||||||
|
// Food
|
||||||
|
var movesPerFood = World.MOVES_PER_FOOD;
|
||||||
|
movesPerFood *= Engine.hasPerk('slow metabolism') ? 2 : 1;
|
||||||
|
if(World.foodMove >= movesPerFood) {
|
||||||
|
World.foodMove = 0;
|
||||||
|
var num = Path.outfit['cured meat'];
|
||||||
|
num--;
|
||||||
|
if(num == 0) {
|
||||||
|
Notifications.notify(World, 'the meat has run out');
|
||||||
|
} else if(num < 0) {
|
||||||
|
// Starvation! Hooray!
|
||||||
|
num = 0;
|
||||||
|
if(!World.starvation) {
|
||||||
|
Notifications.notify(World, 'starvation sets in')
|
||||||
|
World.starvation = true;
|
||||||
|
} else {
|
||||||
|
State.starved = State.starved ? State.starved : 0;
|
||||||
|
State.starved++;
|
||||||
|
if(State.starved >= 10 && !Engine.hasPerk('slow metabolism')) {
|
||||||
|
Engine.addPerk('slow metabolism');
|
||||||
|
}
|
||||||
|
World.die();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
World.starvation = false;
|
||||||
|
World.setHp(World.health + World.meatHeal());
|
||||||
|
}
|
||||||
|
Path.outfit['cured meat'] = num;
|
||||||
|
}
|
||||||
|
// Water
|
||||||
|
var movesPerWater = World.MOVES_PER_WATER;
|
||||||
|
movesPerWater *= Engine.hasPerk('desert rat') ? 2 : 1;
|
||||||
|
if(World.waterMove >= movesPerWater) {
|
||||||
|
World.waterMove = 0;
|
||||||
|
var water = World.water;
|
||||||
|
water--;
|
||||||
|
if(water == 0) {
|
||||||
|
Notifications.notify(World, 'there is no more water');
|
||||||
|
} else if(water < 0) {
|
||||||
|
water = 0;
|
||||||
|
if(!World.thirst) {
|
||||||
|
Notifications.notify(World, 'the thirst becomes unbearable');
|
||||||
|
World.thirst = true;
|
||||||
|
} else {
|
||||||
|
State.dehydrated = State.dehydrated ? State.dehydrated : 0;
|
||||||
|
State.dehydrated++;
|
||||||
|
if(State.dehydrated >= 10 && !Engine.hasPerk('desert rat')) {
|
||||||
|
Engine.addPerk('desert rat');
|
||||||
|
}
|
||||||
|
World.die();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
World.thirst = false;
|
||||||
|
}
|
||||||
|
World.setWater(water);
|
||||||
|
World.updateSupplies();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
meatHeal: function() {
|
||||||
|
return World.MEAT_HEAL * (Engine.hasPerk('gastronome') ? 2 : 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
checkFight: function() {
|
||||||
|
World.fightMove = typeof World.fightMove == 'number' ? World.fightMove : 0;
|
||||||
|
World.fightMove++;
|
||||||
|
if(World.fightMove > World.FIGHT_DELAY) {
|
||||||
|
var chance = World.FIGHT_CHANCE;
|
||||||
|
chance *= Engine.hasPerk('stealthy') ? 0.5 : 1;
|
||||||
|
if(Math.random() < chance) {
|
||||||
|
World.fightMove = 0;
|
||||||
|
Events.triggerFight();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
doSpace: function() {
|
||||||
|
var curTile = World.state.map[World.curPos[0]][World.curPos[1]];
|
||||||
|
|
||||||
|
if(curTile == World.TILE.VILLAGE) {
|
||||||
|
World.goHome();
|
||||||
|
} else if(typeof World.LANDMARKS[curTile] != 'undefined') {
|
||||||
|
if(curTile != World.TILE.OUTPOST || !World.outpostUsed()) {
|
||||||
|
Events.startEvent(Events.Setpieces[World.LANDMARKS[curTile].scene]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(World.useSupplies()) {
|
||||||
|
World.checkFight();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getDistance: function() {
|
||||||
|
return Math.abs(World.curPos[0] - World.RADIUS) + Math.abs(World.curPos[1] - World.RADIUS);
|
||||||
|
},
|
||||||
|
|
||||||
|
getTerrain: function() {
|
||||||
|
return World.state.map[World.curPos[0]][World.curPos[1]];
|
||||||
|
},
|
||||||
|
|
||||||
|
narrateMove: function(oldTile, newTile) {
|
||||||
|
var msg = null;
|
||||||
|
switch(oldTile) {
|
||||||
|
case World.TILE.FOREST:
|
||||||
|
switch(newTile) {
|
||||||
|
case World.TILE.FIELD:
|
||||||
|
msg = "the trees yield to dry grass. the yellowed brush rustles in the wind.";
|
||||||
|
break;
|
||||||
|
case World.TILE.BARRENS:
|
||||||
|
msg = "the trees are gone. parched earth and blowing dust are poor replacements.";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case World.TILE.FIELD:
|
||||||
|
switch(newTile) {
|
||||||
|
case World.TILE.FOREST:
|
||||||
|
msg = "trees loom on the horizon. grasses gradually yield to a forest floor of dry branches and fallen leaves.";
|
||||||
|
break;
|
||||||
|
case World.TILE.BARRENS:
|
||||||
|
msg = "the grasses thin. soon, only dust remains.";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case World.TILE.BARRENS:
|
||||||
|
switch(newTile) {
|
||||||
|
case World.TILE.FIELD:
|
||||||
|
msg = "the barrens break at a sea of dying grass, swaying in the arid breeze.";
|
||||||
|
break;
|
||||||
|
case World.TILE.FOREST:
|
||||||
|
msg = "a wall of gnarled trees rises from the dust. their branches twist into a skeletal canopy overhead.";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(msg != null) {
|
||||||
|
Notifications.notify(World, msg);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
newMask: function() {
|
||||||
|
var mask = new Array(World.RADIUS * 2 + 1);
|
||||||
|
for(var i = 0; i <= World.RADIUS * 2; i++) {
|
||||||
|
mask[i] = new Array(World.RADIUS * 2 + 1);
|
||||||
|
}
|
||||||
|
World.lightMap(World.RADIUS, World.RADIUS, mask);
|
||||||
|
return mask;
|
||||||
|
},
|
||||||
|
|
||||||
|
lightMap: function(x, y, mask) {
|
||||||
|
var r = World.LIGHT_RADIUS;
|
||||||
|
r *= Engine.hasPerk('scout') ? 2 : 1;
|
||||||
|
World.uncoverMap(x, y, r, mask);
|
||||||
|
return mask;
|
||||||
|
},
|
||||||
|
|
||||||
|
uncoverMap: function(x, y, r, mask) {
|
||||||
|
mask[x][y] = true;
|
||||||
|
for(var i = -r; i <= r; i++) {
|
||||||
|
for(var j = -r + Math.abs(i); j <= r - Math.abs(i); j++) {
|
||||||
|
if(y + j >= 0 && y + j <= World.RADIUS * 2 &&
|
||||||
|
x + i <= World.RADIUS * 2 &&
|
||||||
|
x + i >= 0) {
|
||||||
|
mask[x+i][y+j] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
applyMap: function() {
|
||||||
|
var x = Math.floor(Math.random() * (World.RADIUS * 2) + 1);
|
||||||
|
var y = Math.floor(Math.random() * (World.RADIUS * 2) + 1);
|
||||||
|
World.uncoverMap(x, y, 5, State.world.mask);
|
||||||
|
},
|
||||||
|
|
||||||
|
generateMap: function() {
|
||||||
|
var map = new Array(World.RADIUS * 2 + 1);
|
||||||
|
for(var i = 0; i <= World.RADIUS * 2; i++) {
|
||||||
|
map[i] = new Array(World.RADIUS * 2 + 1);
|
||||||
|
}
|
||||||
|
// The Village is always at the exact center
|
||||||
|
// Spiral out from there
|
||||||
|
map[World.RADIUS][World.RADIUS] = World.TILE.VILLAGE;
|
||||||
|
for(var r = 1; r <= World.RADIUS; r++) {
|
||||||
|
for(t = 0; t < r * 8; t++) {
|
||||||
|
var x, y;
|
||||||
|
if(t < 2 * r) {
|
||||||
|
x = World.RADIUS - r + t;
|
||||||
|
y = World.RADIUS - r;
|
||||||
|
} else if(t < 4 * r) {
|
||||||
|
x = World.RADIUS + r;
|
||||||
|
y = World.RADIUS - (3 * r) + t;
|
||||||
|
} else if(t < 6 * r) {
|
||||||
|
x = World.RADIUS + (5 * r) - t;
|
||||||
|
y = World.RADIUS + r;
|
||||||
|
} else {
|
||||||
|
x = World.RADIUS - r;
|
||||||
|
y = World.RADIUS + (7 * r) - t;
|
||||||
|
}
|
||||||
|
|
||||||
|
map[x][y] = World.chooseTile(x, y, map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place landmarks
|
||||||
|
for(var k in World.LANDMARKS) {
|
||||||
|
var landmark = World.LANDMARKS[k];
|
||||||
|
for(var i = 0; i < landmark.num; i++) {
|
||||||
|
var pos = World.placeLandmark(landmark.minRadius, landmark.maxRadius, k, map);
|
||||||
|
if(k == World.TILE.SHIP) {
|
||||||
|
var dx = pos[0] - World.RADIUS, dy = pos[1] - World.RADIUS;
|
||||||
|
var horz = dx < 0 ? 'west' : 'east';
|
||||||
|
var vert = dy < 0 ? 'north' : 'south';
|
||||||
|
if(Math.abs(dx) / 2 > Math.abs(dy)) {
|
||||||
|
World.dir = horz;
|
||||||
|
} else if(Math.abs(dy) / 2 > Math.abs(dx)){
|
||||||
|
World.dir = vert;
|
||||||
|
} else {
|
||||||
|
World.dir = vert + horz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
},
|
||||||
|
|
||||||
|
placeLandmark: function(minRadius, maxRadius, landmark, map) {
|
||||||
|
|
||||||
|
var x = World.RADIUS, y = World.RADIUS;
|
||||||
|
while(!World.isTerrain(map[x][y])) {
|
||||||
|
var r = Math.floor(Math.random() * (maxRadius - minRadius)) + minRadius;
|
||||||
|
var xDist = Math.floor(Math.random() * r);
|
||||||
|
var yDist = r - xDist;
|
||||||
|
if(Math.random() < 0.5) xDist = -xDist;
|
||||||
|
if(Math.random() < 0.5) yDist = -yDist;
|
||||||
|
x = World.RADIUS + xDist;
|
||||||
|
if(x < 0) x = 0;
|
||||||
|
if(x > World.RADIUS * 2) x = World.RADIUS * 2;
|
||||||
|
y = World.RADIUS + yDist;
|
||||||
|
if(y < 0) y = 0;
|
||||||
|
if(y > World.RADIUS * 2) y = World.RADIUS * 2;
|
||||||
|
}
|
||||||
|
map[x][y] = landmark;
|
||||||
|
return [x, y];
|
||||||
|
},
|
||||||
|
|
||||||
|
isTerrain: function(tile) {
|
||||||
|
return tile == World.TILE.FOREST || tile == World.TILE.FIELD || tile == World.TILE.BARRENS;
|
||||||
|
},
|
||||||
|
|
||||||
|
chooseTile: function(x, y, map) {
|
||||||
|
|
||||||
|
var log = x == World.RADIUS + 1 && y == World.RADIUS + 1;
|
||||||
|
|
||||||
|
var adjacent = [
|
||||||
|
y > 0 ? map[x][y-1] : null,
|
||||||
|
y < World.RADIUS * 2 ? map[x][y+1] : null,
|
||||||
|
x < World.RADIUS * 2 ? map[x+1][y] : null,
|
||||||
|
x > 0 ? map[x-1][y] : null
|
||||||
|
];
|
||||||
|
|
||||||
|
var chances = {};
|
||||||
|
var nonSticky = 1;
|
||||||
|
for(var i in adjacent) {
|
||||||
|
if(adjacent[i] == World.TILE.VILLAGE) {
|
||||||
|
// Village must be in a forest to maintain thematic consistency, yo.
|
||||||
|
return World.TILE.FOREST;
|
||||||
|
} else if(typeof adjacent[i] == 'string') {
|
||||||
|
var cur = chances[adjacent[i]];
|
||||||
|
cur = typeof cur == 'number' ? cur : 0;
|
||||||
|
chances[adjacent[i]] = cur + World.STICKINESS;
|
||||||
|
nonSticky -= World.STICKINESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(var t in World.TILE) {
|
||||||
|
var tile = World.TILE[t];
|
||||||
|
if(World.isTerrain(tile)) {
|
||||||
|
var cur = chances[tile];
|
||||||
|
cur = typeof cur == 'number' ? cur : 0;
|
||||||
|
cur += World.TILE_PROBS[tile] * nonSticky;
|
||||||
|
chances[tile] = cur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var list = [];
|
||||||
|
for(var t in chances) {
|
||||||
|
list.push(chances[t] + '' + t);
|
||||||
|
}
|
||||||
|
list.sort(function(a, b) {
|
||||||
|
var n1 = parseFloat(a.substring(0, a.length - 1));
|
||||||
|
var n2 = parseFloat(b.substring(0, b.length - 1));
|
||||||
|
return n2 - n1;
|
||||||
|
});
|
||||||
|
|
||||||
|
var c = 0;
|
||||||
|
var r = Math.random();
|
||||||
|
for(var i in list) {
|
||||||
|
var prob = list[i];
|
||||||
|
c += parseFloat(prob.substring(0,prob.length - 1));
|
||||||
|
if(r < c) {
|
||||||
|
return prob.charAt(prob.length - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return World.TILE.BARRENS;
|
||||||
|
},
|
||||||
|
|
||||||
|
markVisited: function(x, y) {
|
||||||
|
World.state.map[x][y] = World.state.map[x][y] + '!';
|
||||||
|
},
|
||||||
|
|
||||||
|
drawMap: function() {
|
||||||
|
var map = $('#map');
|
||||||
|
if(map.length == 0) {
|
||||||
|
map = new $('<div>').attr('id', 'map').appendTo('#worldOuter');
|
||||||
|
}
|
||||||
|
var mapString = "";
|
||||||
|
for(var j = 0; j <= World.RADIUS * 2; j++) {
|
||||||
|
for(var i = 0; i <= World.RADIUS * 2; i++) {
|
||||||
|
var ttClass = "";
|
||||||
|
if(i > World.RADIUS) {
|
||||||
|
ttClass += " left";
|
||||||
|
} else {
|
||||||
|
ttClass += " right";
|
||||||
|
}
|
||||||
|
if(j > World.RADIUS) {
|
||||||
|
ttClass += " top";
|
||||||
|
} else {
|
||||||
|
ttClass += " bottom";
|
||||||
|
}
|
||||||
|
if(World.curPos[0] == i && World.curPos[1] == j) {
|
||||||
|
mapString += '<span class="landmark">@<div class="tooltip ' + ttClass + '">Wanderer</div></span>';
|
||||||
|
} else if(World.state.mask[i][j]) {
|
||||||
|
var c = World.state.map[i][j];
|
||||||
|
switch(c) {
|
||||||
|
case World.TILE.VILLAGE:
|
||||||
|
mapString += '<span class="landmark">' + c + '<div class="tooltip' + ttClass + '">The Village</div></span>';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if(typeof World.LANDMARKS[c] != 'undefined' && (c != World.TILE.OUTPOST || !World.outpostUsed(i, j))) {
|
||||||
|
mapString += '<span class="landmark">' + c + '<div class="tooltip' + ttClass + '">' + World.LANDMARKS[c].label + '</div></span>';
|
||||||
|
} else {
|
||||||
|
if(c.length > 1) {
|
||||||
|
c = c[0];
|
||||||
|
}
|
||||||
|
mapString += c;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mapString += ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mapString += '<br/>';
|
||||||
|
}
|
||||||
|
map.html(mapString);
|
||||||
|
},
|
||||||
|
|
||||||
|
die: function() {
|
||||||
|
if(!World.dead) {
|
||||||
|
World.dead = true;
|
||||||
|
Engine.log('player death');
|
||||||
|
Engine.event('game event', 'death');
|
||||||
|
Engine.keyLock = true;
|
||||||
|
// Dead! Discard any world changes and go home
|
||||||
|
Notifications.notify(World, 'the world fades');
|
||||||
|
World.state = null;
|
||||||
|
Path.outfit = {};
|
||||||
|
$('#outerSlider').animate({opacity: '0'}, 600, 'linear', function() {
|
||||||
|
$('#outerSlider').css('left', '0px');
|
||||||
|
$('#locationSlider').css('left', '0px');
|
||||||
|
Engine.activeModule = Room;
|
||||||
|
$('div.headerButton').removeClass('selected');
|
||||||
|
Room.tab.addClass('selected');
|
||||||
|
setTimeout(function(){
|
||||||
|
Room.onArrival();
|
||||||
|
$('#outerSlider').animate({opacity:'1'}, 600, 'linear');
|
||||||
|
Button.cooldown($('#embarkButton'));
|
||||||
|
Engine.keyLock = false;
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
goHome: function() {
|
||||||
|
// Home safe! Commit the changes.
|
||||||
|
State.world = World.state;
|
||||||
|
if(World.state.sulphurmine && Outside.numBuilding('sulphur mine') == 0) {
|
||||||
|
Outside.addBuilding('sulphur mine', 1);
|
||||||
|
Engine.event('progress', 'sulphur mine');
|
||||||
|
}
|
||||||
|
if(World.state.ironmine && Outside.numBuilding('iron mine') == 0) {
|
||||||
|
Outside.addBuilding('iron mine', 1);
|
||||||
|
Engine.event('progress', 'iron mine');
|
||||||
|
}
|
||||||
|
if(World.state.coalmine && Outside.numBuilding('coal mine') == 0) {
|
||||||
|
Outside.addBuilding('coal mine', 1);
|
||||||
|
Engine.event('progress', 'coal mine');
|
||||||
|
}
|
||||||
|
if(World.state.ship && !State.ship) {
|
||||||
|
Ship.init();
|
||||||
|
Engine.event('progress', 'ship');
|
||||||
|
}
|
||||||
|
World.state = null;
|
||||||
|
|
||||||
|
// Clear the embark cooldown
|
||||||
|
var btn = Button.clearCooldown($('#embarkButton'));
|
||||||
|
if(Path.outfit['cured meat'] > 0) {
|
||||||
|
Button.setDisabled(btn, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(var k in Path.outfit) {
|
||||||
|
Engine.addStore(k, Path.outfit[k]);
|
||||||
|
if(World.leaveItAtHome(k)) {
|
||||||
|
Path.outfit[k] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#outerSlider').animate({left: '0px'}, 300);
|
||||||
|
Engine.activeModule = Path;
|
||||||
|
Path.onArrival();
|
||||||
|
},
|
||||||
|
|
||||||
|
leaveItAtHome: function(thing) {
|
||||||
|
return thing != 'cured meat' && thing != 'bullets' && thing != 'energy cell' && thing != 'charm'
|
||||||
|
&& typeof World.Weapons[thing] == 'undefined' && typeof Room.Craftables[thing] == 'undefined';
|
||||||
|
},
|
||||||
|
|
||||||
|
getMaxHealth: function() {
|
||||||
|
if(Engine.getStore('s armour') > 0) {
|
||||||
|
return World.BASE_HEALTH + 35;
|
||||||
|
} else if(Engine.getStore('i armour') > 0) {
|
||||||
|
return World.BASE_HEALTH + 15;
|
||||||
|
} else if(Engine.getStore('l armour') > 0) {
|
||||||
|
return World.BASE_HEALTH + 5;
|
||||||
|
}
|
||||||
|
return World.BASE_HEALTH;
|
||||||
|
},
|
||||||
|
|
||||||
|
getHitChance: function() {
|
||||||
|
if(Engine.hasPerk('precise')) {
|
||||||
|
return World.BASE_HIT_CHANCE + 0.1;
|
||||||
|
}
|
||||||
|
return World.BASE_HIT_CHANCE;
|
||||||
|
},
|
||||||
|
|
||||||
|
getMaxWater: function() {
|
||||||
|
if(Engine.getStore('water tank') > 0) {
|
||||||
|
return World.BASE_WATER + 50;
|
||||||
|
} else if(Engine.getStore('cask') > 0) {
|
||||||
|
return World.BASE_WATER + 20;
|
||||||
|
} else if(Engine.getStore('waterskin') > 0) {
|
||||||
|
return World.BASE_WATER + 10;
|
||||||
|
}
|
||||||
|
return World.BASE_WATER;
|
||||||
|
},
|
||||||
|
|
||||||
|
outpostUsed: function(x, y) {
|
||||||
|
x = typeof x == 'number' ? x : World.curPos[0];
|
||||||
|
y = typeof y == 'number' ? y : World.curPos[1];
|
||||||
|
var used = World.usedOutposts[x + ',' + y];
|
||||||
|
return typeof used != 'undefined' && used == true;
|
||||||
|
},
|
||||||
|
|
||||||
|
useOutpost: function() {
|
||||||
|
Notifications.notify(null, 'water replenished');
|
||||||
|
World.setWater(World.getMaxWater());
|
||||||
|
// Save progress at outposts
|
||||||
|
State.world = World.state;
|
||||||
|
// Mark this outpost as used
|
||||||
|
World.usedOutposts[World.curPos[0] + ',' + World.curPos[1]] = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
onArrival: function() {
|
||||||
|
Engine.keyLock = false;
|
||||||
|
// Explore in a temporary world-state. We'll commit the changes if you return home safe.
|
||||||
|
World.state = $.extend(true, {}, State.world);
|
||||||
|
World.setWater(World.getMaxWater());
|
||||||
|
World.setHp(World.getMaxHealth());
|
||||||
|
World.foodMove = 0;
|
||||||
|
World.waterMove = 0;
|
||||||
|
World.starvation = false;
|
||||||
|
World.thirst = false;
|
||||||
|
World.usedOutposts = {};
|
||||||
|
World.curPos = [World.RADIUS, World.RADIUS];
|
||||||
|
World.drawMap();
|
||||||
|
World.setTitle();
|
||||||
|
World.dead = false;
|
||||||
|
$('div#bagspace-world > div').empty();
|
||||||
|
World.updateSupplies();
|
||||||
|
$('#bagspace-world').width($('#map').width());
|
||||||
|
},
|
||||||
|
|
||||||
|
setTitle: function() {
|
||||||
|
document.title = 'A Barren World';
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user