0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2025-12-27 00:42:40 +00:00

setting up a default monster manual and encoutners

This commit is contained in:
Scott Tolksdorf
2015-11-23 12:46:19 -05:00
parent 65127885c5
commit fa8818cfcc
11 changed files with 203 additions and 129 deletions

View File

@@ -0,0 +1,42 @@
module.exports = {
goblin : {
hp : 40,
mov: 30,
ac : 13,
attr : {
str : 8,
con : 8,
dex : 8,
int : 8,
wis : 8,
cha : 8
},
attacks : {
dagger : {
atk : "1d20-5",
dmg : "1d4+5",
type : "pierce",
notes : "Super cool"
},
bow : {
atk : "1d20+2",
dmg : "6d6",
rng : "30"
}
},
spells : {
fireball: {
dmg : "6d6",
uses : 4
},
"healing bolt" : {
heal : "2d8+4",
uses : 6
}
},
abilities : {
"pack tactics" : "Does a thing"
},
items : ['healing_potion', 'healing_potion', 'ring']
}
}

View File

@@ -127,6 +127,14 @@ var MonsterCard = React.createClass({
})
},
renderAbilities : function(){
return _.map(this.props.abilities, function(text, name){
return <div className='ability' key={name}>
<span className='name'>{name}</span>: {text}
</div>
});
},
renderItems : function(){
var self = this;
var usedItems = this.state.usedItems.slice(0);
@@ -172,7 +180,7 @@ var MonsterCard = React.createClass({
</div>
<div className='abilitiesContainer'>
{this.props.abilities}
{this.renderAbilities()}
</div>
<div className='itemContainer'>
<i className='fa fa-flask' />

View File

@@ -104,10 +104,16 @@
}
}
.abilitiesContainer{
margin-top : 5px;
margin-top : 10px;
.ability{
font-size: 0.7em;
.name{
font-weight: 800;
}
}
}
.itemContainer{
margin-top : 5px;
margin-top : 10px;
i{
font-size : 0.7em;
}

View File

@@ -2,12 +2,9 @@ var React = require('react');
var _ = require('lodash');
var cx = require('classnames');
var Sidebar = require('./sidebar/sidebar.jsx');
var Encounter = require('./encounter/encounter.jsx');
var encounters = [
{
name : 'The Big Bad',
@@ -47,46 +44,7 @@ var encounters = [
];
var monsterManual = {
'goblin' : {
"hp" : 40,
"mov": 30,
"ac" : 13,
"attr" : {
"str" : 8,
"con" : 8,
"dex" : 8,
"int" : 8,
"wis" : 8,
"cha" : 8
},
"attacks" : {
"dagger" : {
"atk" : "1d20-5",
"dmg" : "1d4+5",
"type" : "pierce",
"notes" : "Super cool"
},
"bow" : {
"atk" : "1d20+2",
"dmg" : "6d6",
"rng" : "30"
}
},
"spells" : {
"fireball": {
"dmg" : "6d6",
"uses" : 4
},
"healing_bolt" : {
"heal" : "2d8+4",
"uses" : 6
}
},
"abilities" : ["pack tactics"],
"items" : ['healing_potion', 'healing_potion', 'ring']
}
}
var defaultMonsterManual = require('./defaultMonsterManual.js');
var attrMod = function(attr){
return Math.floor(attr/2) - 5;
@@ -100,7 +58,7 @@ var NaturalCrit = React.createClass({
return {
selectedEncounterIndex : 0,
encounters : JSON.parse(localStorage.getItem('encounters')) || encounters,
monsterManual : JSON.parse(localStorage.getItem('monsterManual')) || monsterManual,
monsterManual : JSON.parse(localStorage.getItem('monsterManual')) || defaultMonsterManual,
players : localStorage.getItem('players') || 'jasper 13\nzatch 19'
@@ -128,6 +86,7 @@ var NaturalCrit = React.createClass({
localStorage.setItem("players", e.target.value);
},
handleSelectedEncounterChange : function(encounterIndex){
console.log(encounterIndex);
this.setState({
selectedEncounterIndex : encounterIndex
});
@@ -146,7 +105,9 @@ var NaturalCrit = React.createClass({
return encounter.name == self.state.selectedEncounter;
});
if(this.state.selectedEncounterIndex != null){
if(this.state.selectedEncounterIndex != null && selectedEncounter != null){
var selectedEncounter = this.state.encounters[this.state.selectedEncounterIndex]
return <Encounter
key={selectedEncounter.name}

View File

View File

@@ -1,5 +1,10 @@
.dmDice{
h3{
color : white;
background-color: @teal;
}
.roll{
cursor: pointer;
.noselect();
@@ -21,8 +26,7 @@
}
&:hover{
background-color: fade(@red, 20%);
background-color: fade(@teal, 20%);
}
}
}

View File

@@ -2,13 +2,70 @@ var React = require('react');
var _ = require('lodash');
var cx = require('classnames');
var JSONFileEditor = require('naturalCrit/jsonFileEditor/jsonFileEditor.jsx');
var Encounters = React.createClass({
getDefaultProps: function() {
return {
encounters : [],
selectedEncounter : 0,
onJSONChange : function(encounterIndex, json){},
onSelectEncounter : function(encounterIndex){},
onRemoveEncounter : function(encounterIndex){}
};
},
handleJSONChange : function(encounterIndex, json){
this.props.onJSONChange(encounterIndex, json);
},
handleSelectEncounter : function(encounterIndex){
this.props.onSelectEncounter(encounterIndex);
},
handleRemoveEncounter : function(encounterIndex){
this.props.onRemoveEncounter(encounterIndex);
},
renderEncounters : function(){
var self = this;
return _.map(this.props.encounters, function(encounter, index){
var isSelected = self.props.selectedEncounter == index;
return <div className={cx('encounter' , {'selected' : isSelected})} key={index}>
<i onClick={self.handleSelectEncounter.bind(self, index)} className={cx('select', 'fa', {
'fa-square-o' : !isSelected,
'fa-check-square-o' : isSelected,
})} />
<JSONFileEditor
name={encounter.name}
json={encounter}
onJSONChange={self.handleJSONChange.bind(self, index)}
/>
<i onClick={self.handleRemoveEncounter.bind(self, index)} className='remove fa fa-times' />
</div>
})
},
render : function(){
var self = this;
return(
<div className='encounters'>
Encounters Ready!
<h3>
<i className='fa fa-flag' /> Encounters
<button className='addEncounter'>
<i className='fa fa-plus' />
</button>
</h3>
{this.renderEncounters()}
<div className='controls'>
</div>
</div>
);
}

View File

@@ -1,3 +1,53 @@
.encounters{
.encounters{
margin-bottom : 20px;
h3{
background-color : @red;
color : white;
button{
.animate(color);
float : right;
cursor : pointer;
background-color : transparent;
border : none;
outline : none;
&:hover{
color : white;
}
}
}
.encounter{
position : relative;
padding-left : 15px;
border-left : 0px solid @teal;
.animateAll();
&:hover{
i.remove{
opacity : 1;
}
}
i.remove{
.animate(opacity);
position : absolute;
top : 3px;
right : 3px;
cursor : pointer;
opacity : 0;
font-size : 0.6em;
color : #333;
&:hover{
color : @red;
}
}
i.select{
cursor : pointer;
}
.jsonFileEditor{
display : inline-block;
}
&.selected{
//background-color : fade(@green, 30%);
border-left : 8px solid @teal;
}
}
}

View File

@@ -40,16 +40,8 @@ var Sidebar = React.createClass({
})
},
handleJSONChange : function(encounterIndex, json){
this.props.onJSONChange(encounterIndex, json);
},
handleSelectEncounter : function(encounterIndex){
this.props.onSelectEncounter(encounterIndex);
},
handleRemoveEncounter : function(encounterIndex){
this.props.onRemoveEncounter(encounterIndex);
},
/*
renderEncounters : function(){
var self = this;
@@ -74,7 +66,7 @@ var Sidebar = React.createClass({
</div>
})
},
*/
render : function(){
var self = this;
return(
@@ -82,7 +74,8 @@ var Sidebar = React.createClass({
<div className='logo'>
<svg onClick={this.handleLogoClick} version="1.1" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 100 100"><path d="M80.644,87.982l16.592-41.483c0.054-0.128,0.088-0.26,0.108-0.394c0.006-0.039,0.007-0.077,0.011-0.116 c0.007-0.087,0.008-0.174,0.002-0.26c-0.003-0.046-0.007-0.091-0.014-0.137c-0.014-0.089-0.036-0.176-0.063-0.262 c-0.012-0.034-0.019-0.069-0.031-0.103c-0.047-0.118-0.106-0.229-0.178-0.335c-0.004-0.006-0.006-0.012-0.01-0.018L67.999,3.358 c-0.01-0.013-0.003-0.026-0.013-0.04L68,3.315V4c0,0-0.033,0-0.037,0c-0.403-1-1.094-1.124-1.752-0.976 c0,0.004-0.004-0.012-0.007-0.012C66.201,3.016,66.194,3,66.194,3H66.19h-0.003h-0.003h-0.004h-0.003c0,0-0.004,0-0.007,0 s-0.003-0.151-0.007-0.151L20.495,15.227c-0.025,0.007-0.046-0.019-0.071-0.011c-0.087,0.028-0.172,0.041-0.253,0.083 c-0.054,0.027-0.102,0.053-0.152,0.085c-0.051,0.033-0.101,0.061-0.147,0.099c-0.044,0.036-0.084,0.073-0.124,0.113 c-0.048,0.048-0.093,0.098-0.136,0.152c-0.03,0.039-0.059,0.076-0.085,0.117c-0.046,0.07-0.084,0.145-0.12,0.223 c-0.011,0.023-0.027,0.042-0.036,0.066L2.911,57.664C2.891,57.715,3,57.768,3,57.82v0.002c0,0.186,0,0.375,0,0.562 c0,0.004,0,0.004,0,0.008c0,0,0,0,0,0.002c0,0,0,0,0,0.004v0.004v0.002c0,0.074-0.002,0.15,0.012,0.223 C3.015,58.631,3,58.631,3,58.633c0,0.004,0,0.004,0,0.008c0,0,0,0,0,0.002c0,0,0,0,0,0.004v0.004c0,0,0,0,0,0.002v0.004 c0,0.191-0.046,0.377,0.06,0.545c0-0.002-0.03,0.004-0.03,0.004c0,0.004-0.03,0.004-0.03,0.004c0,0.002,0,0.002,0,0.002 l-0.045,0.004c0.03,0.047,0.036,0.09,0.068,0.133l29.049,37.359c0.002,0.004,0,0.006,0.002,0.01c0.002,0.002,0,0.004,0.002,0.008 c0.006,0.008,0.014,0.014,0.021,0.021c0.024,0.029,0.052,0.051,0.078,0.078c0.027,0.029,0.053,0.057,0.082,0.082 c0.03,0.027,0.055,0.062,0.086,0.088c0.026,0.02,0.057,0.033,0.084,0.053c0.04,0.027,0.081,0.053,0.123,0.076 c0.005,0.004,0.01,0.008,0.016,0.01c0.087,0.051,0.176,0.09,0.269,0.123c0.042,0.014,0.082,0.031,0.125,0.043 c0.021,0.006,0.041,0.018,0.062,0.021c0.123,0.027,0.249,0.043,0.375,0.043c0.099,0,0.202-0.012,0.304-0.027l45.669-8.303 c0.057-0.01,0.108-0.021,0.163-0.037C79.547,88.992,79.562,89,79.575,89c0.004,0,0.004,0,0.004,0c0.021,0,0.039-0.027,0.06-0.035 c0.041-0.014,0.08-0.034,0.12-0.052c0.021-0.01,0.044-0.019,0.064-0.03c0.017-0.01,0.026-0.015,0.033-0.017 c0.014-0.008,0.023-0.021,0.037-0.028c0.14-0.078,0.269-0.174,0.38-0.285c0.014-0.016,0.024-0.034,0.038-0.048 c0.109-0.119,0.201-0.252,0.271-0.398c0.006-0.01,0.016-0.018,0.021-0.029c0.004-0.008,0.008-0.017,0.011-0.026 c0.002-0.004,0.003-0.006,0.005-0.01C80.627,88.021,80.635,88.002,80.644,87.982z M77.611,84.461L48.805,66.453l32.407-25.202 L77.611,84.461z M46.817,63.709L35.863,23.542l43.818,14.608L46.817,63.709z M84.668,40.542l8.926,5.952l-11.902,29.75 L84.668,40.542z M89.128,39.446L84.53,36.38l-6.129-12.257L89.128,39.446z M79.876,34.645L37.807,20.622L65.854,6.599L79.876,34.645 z M33.268,19.107l-6.485-2.162l23.781-6.487L33.268,19.107z M21.92,18.895l8.67,2.891L10.357,47.798L21.92,18.895z M32.652,24.649 l10.845,39.757L7.351,57.178L32.652,24.649z M43.472,67.857L32.969,92.363L8.462,60.855L43.472,67.857z M46.631,69.09l27.826,17.393 l-38.263,6.959L46.631,69.09z"></path></svg>
<span className='name'>
Natural<span className='crit'>Crit</span>
<div>Natural<span className='crit'>Crit</span></div>
<small>Combat Manager</small>
</span>
</div>
<div className='contents'>
@@ -95,21 +88,16 @@ var Sidebar = React.createClass({
/>
</div>
<div className='encounterContainer'>
<h3>
<i className='fa fa-flag' /> Encounters
<button className='addEncounter'>
<i className='fa fa-plus' />
</button>
</h3>
{this.renderEncounters()}
<div className='controls'>
<Encounters
encounters={this.props.encounters}
selectedEncounter={this.props.selectedEncounter}
</div>
</div>
onJSONChange={this.props.onJSONChange}
onSelectEncounter={this.props.onSelectEncounter}
onRemoveEncounter={this.props.onRemoveEncounter}
<Encounters />
/>
<div className='addPlayers'>
<h3> <i className='fa fa-group' /> Players </h3>

View File

@@ -45,12 +45,20 @@
span.name{
.animateAll();
position : absolute;
top : 13px;
top : 15px;
left : 50px;
opacity : 1;
font-size: 0.9em;
line-height: 0.5em;
span.crit{
font-family : 'CodeBold';
}
small{
font-size: 0.3em;
font-family : 'Open Sans';
font-weight: 800;
text-transform: uppercase;
}
}
}
.contents{
@@ -66,49 +74,6 @@
font-weight : 800;
text-transform : uppercase;
}
.encounterContainer{
margin-bottom : 20px;
h3{
background-color : @red;
color : white;
button{
outline: none;
border : none;
cursor: pointer;
background-color: transparent;
.animate(color);
float : right;
&:hover{
color : white;
}
}
}
.encounter{
padding-left: 20px;
position: relative;
i.remove{
position: absolute;
top : 3px;
right : 3px;
font-size: 0.6em;
cursor: pointer;
color : #333;
&:hover{
color: @red;
}
}
i.select{
cursor: pointer;
}
.jsonFileEditor{
display: inline-block;
}
&.selected{
background-color : fade(@green, 30%);
}
}
}
.addPlayers{
h3{
color : white;
@@ -121,12 +86,5 @@
}
}
.dmDice{
h3{
color : white;
background-color: @teal;
}
}
}
}

View File

@@ -7,6 +7,9 @@
.jsonEditor{
display : initial;
}
button.showEditor{
color: @red;
}
}
.jsonEditor{
position : absolute;
@@ -26,9 +29,6 @@
.controls{
display: inline-block;
float: right;
//position : absolute;
//top : 0px;
//right : 0px;
button{
outline: none;