diff --git a/elm.json b/elm.json index ac7524b7b39a9a5d8f1776abbaf7fb0092d00fc8..b833272986cbd24784dda6392e9b9eddb0d1cbed 100644 --- a/elm.json +++ b/elm.json @@ -11,6 +11,7 @@ "elm/html": "1.0.0", "elm/http": "2.0.0", "elm/json": "1.1.3", + "elm/random": "1.0.0", "elm/svg": "1.0.1", "elm/url": "1.0.0" }, diff --git a/public/index.html b/public/index.html index 2aa3992dbb269b774c9a915ae0891ef68aafc498..a29effb56bc3d5e660ab67c526f478b65bca30dc 100644 --- a/public/index.html +++ b/public/index.html @@ -37,6 +37,33 @@ .dropdown.is-fullwidth * { width: 100%; } + + /* https://stackoverflow.com/a/46550527 */ + .square-container { + display: flex; + flex-wrap: wrap; + } + .square { + position: relative; + flex-basis: calc(10% - 10px); + margin: 5px; + box-sizing: border-box; + } + .square::before { + content: ''; + display: block; + padding-top: 100%; + } + .square .content { + position: absolute; + top: 0; left: 0; + height: 100%; + width: 100%; + + display: flex; /* added for centered text */ + justify-content: center; /* added for centered text */ + align-items: center; /* added for centered text */ + } </style> </head> <body> diff --git a/public/main.js b/public/main.js index 3e272611a35ebacc8b2bdcb6a445d28183644e90..70db4ccd5288d810c48ed0d0adb10089825af812 100644 --- a/public/main.js +++ b/public/main.js @@ -4545,7 +4545,90 @@ function _Http_track(router, xhr, tracker) size: event.lengthComputable ? $elm$core$Maybe$Just(event.total) : $elm$core$Maybe$Nothing })))); }); -}var $author$project$Main$LinkClicked = function (a) { +} + + +var _Bitwise_and = F2(function(a, b) +{ + return a & b; +}); + +var _Bitwise_or = F2(function(a, b) +{ + return a | b; +}); + +var _Bitwise_xor = F2(function(a, b) +{ + return a ^ b; +}); + +function _Bitwise_complement(a) +{ + return ~a; +}; + +var _Bitwise_shiftLeftBy = F2(function(offset, a) +{ + return a << offset; +}); + +var _Bitwise_shiftRightBy = F2(function(offset, a) +{ + return a >> offset; +}); + +var _Bitwise_shiftRightZfBy = F2(function(offset, a) +{ + return a >>> offset; +}); + + + +function _Time_now(millisToPosix) +{ + return _Scheduler_binding(function(callback) + { + callback(_Scheduler_succeed(millisToPosix(Date.now()))); + }); +} + +var _Time_setInterval = F2(function(interval, task) +{ + return _Scheduler_binding(function(callback) + { + var id = setInterval(function() { _Scheduler_rawSpawn(task); }, interval); + return function() { clearInterval(id); }; + }); +}); + +function _Time_here() +{ + return _Scheduler_binding(function(callback) + { + callback(_Scheduler_succeed( + A2($elm$time$Time$customZone, -(new Date().getTimezoneOffset()), _List_Nil) + )); + }); +} + + +function _Time_getZoneName() +{ + return _Scheduler_binding(function(callback) + { + try + { + var name = $elm$time$Time$Name(Intl.DateTimeFormat().resolvedOptions().timeZone); + } + catch (e) + { + var name = $elm$time$Time$Offset(new Date().getTimezoneOffset()); + } + callback(_Scheduler_succeed(name)); + }); +} +var $author$project$Main$LinkClicked = function (a) { return {$: 'LinkClicked', a: a}; }; var $author$project$Main$UrlChanged = function (a) { @@ -5512,12 +5595,13 @@ var $author$project$Stats$new = _List_fromArray( A2($author$project$Stats$newBackground, 'Wonder', 5) ]); var $author$project$Character$new = {creationPoints: $author$project$Creation$new, name: 'Default Name', stats: $author$project$Stats$new}; +var $author$project$Dice$new = {amount: 1, difficulty: 6, specialty: false, willpower: false}; var $elm$core$Platform$Cmd$batch = _Platform_batch; var $elm$core$Platform$Cmd$none = $elm$core$Platform$Cmd$batch(_List_Nil); var $author$project$Main$init = F3( function (_v0, url, key) { return _Utils_Tuple2( - {activeDropdown: $elm$core$Maybe$Nothing, character: $author$project$Character$new, key: key, modal: $elm$core$Maybe$Nothing, modalValue: '', url: url}, + {activeDropdown: $elm$core$Maybe$Nothing, character: $author$project$Character$new, dice: $author$project$Dice$new, key: key, modal: $elm$core$Maybe$Nothing, modalValue: '', roll: _List_Nil, url: url}, $elm$core$Platform$Cmd$none); }); var $elm$core$Platform$Sub$batch = _Platform_batch; @@ -6769,6 +6853,194 @@ var $author$project$Main$modalValue = F2( return character.name; }); var $elm$browser$Browser$Navigation$pushUrl = _Browser_pushUrl; +var $author$project$Main$RollResult = function (a) { + return {$: 'RollResult', a: a}; +}; +var $elm$random$Random$Generate = function (a) { + return {$: 'Generate', a: a}; +}; +var $elm$random$Random$Seed = F2( + function (a, b) { + return {$: 'Seed', a: a, b: b}; + }); +var $elm$core$Bitwise$shiftRightZfBy = _Bitwise_shiftRightZfBy; +var $elm$random$Random$next = function (_v0) { + var state0 = _v0.a; + var incr = _v0.b; + return A2($elm$random$Random$Seed, ((state0 * 1664525) + incr) >>> 0, incr); +}; +var $elm$random$Random$initialSeed = function (x) { + var _v0 = $elm$random$Random$next( + A2($elm$random$Random$Seed, 0, 1013904223)); + var state1 = _v0.a; + var incr = _v0.b; + var state2 = (state1 + x) >>> 0; + return $elm$random$Random$next( + A2($elm$random$Random$Seed, state2, incr)); +}; +var $elm$time$Time$Name = function (a) { + return {$: 'Name', a: a}; +}; +var $elm$time$Time$Offset = function (a) { + return {$: 'Offset', a: a}; +}; +var $elm$time$Time$Zone = F2( + function (a, b) { + return {$: 'Zone', a: a, b: b}; + }); +var $elm$time$Time$customZone = $elm$time$Time$Zone; +var $elm$time$Time$Posix = function (a) { + return {$: 'Posix', a: a}; +}; +var $elm$time$Time$millisToPosix = $elm$time$Time$Posix; +var $elm$time$Time$now = _Time_now($elm$time$Time$millisToPosix); +var $elm$time$Time$posixToMillis = function (_v0) { + var millis = _v0.a; + return millis; +}; +var $elm$random$Random$init = A2( + $elm$core$Task$andThen, + function (time) { + return $elm$core$Task$succeed( + $elm$random$Random$initialSeed( + $elm$time$Time$posixToMillis(time))); + }, + $elm$time$Time$now); +var $elm$random$Random$step = F2( + function (_v0, seed) { + var generator = _v0.a; + return generator(seed); + }); +var $elm$random$Random$onEffects = F3( + function (router, commands, seed) { + if (!commands.b) { + return $elm$core$Task$succeed(seed); + } else { + var generator = commands.a.a; + var rest = commands.b; + var _v1 = A2($elm$random$Random$step, generator, seed); + var value = _v1.a; + var newSeed = _v1.b; + return A2( + $elm$core$Task$andThen, + function (_v2) { + return A3($elm$random$Random$onEffects, router, rest, newSeed); + }, + A2($elm$core$Platform$sendToApp, router, value)); + } + }); +var $elm$random$Random$onSelfMsg = F3( + function (_v0, _v1, seed) { + return $elm$core$Task$succeed(seed); + }); +var $elm$random$Random$Generator = function (a) { + return {$: 'Generator', a: a}; +}; +var $elm$random$Random$map = F2( + function (func, _v0) { + var genA = _v0.a; + return $elm$random$Random$Generator( + function (seed0) { + var _v1 = genA(seed0); + var a = _v1.a; + var seed1 = _v1.b; + return _Utils_Tuple2( + func(a), + seed1); + }); + }); +var $elm$random$Random$cmdMap = F2( + function (func, _v0) { + var generator = _v0.a; + return $elm$random$Random$Generate( + A2($elm$random$Random$map, func, generator)); + }); +_Platform_effectManagers['Random'] = _Platform_createManager($elm$random$Random$init, $elm$random$Random$onEffects, $elm$random$Random$onSelfMsg, $elm$random$Random$cmdMap); +var $elm$random$Random$command = _Platform_leaf('Random'); +var $elm$random$Random$generate = F2( + function (tagger, generator) { + return $elm$random$Random$command( + $elm$random$Random$Generate( + A2($elm$random$Random$map, tagger, generator))); + }); +var $elm$core$Bitwise$and = _Bitwise_and; +var $elm$core$Bitwise$xor = _Bitwise_xor; +var $elm$random$Random$peel = function (_v0) { + var state = _v0.a; + var word = (state ^ (state >>> ((state >>> 28) + 4))) * 277803737; + return ((word >>> 22) ^ word) >>> 0; +}; +var $elm$random$Random$int = F2( + function (a, b) { + return $elm$random$Random$Generator( + function (seed0) { + var _v0 = (_Utils_cmp(a, b) < 0) ? _Utils_Tuple2(a, b) : _Utils_Tuple2(b, a); + var lo = _v0.a; + var hi = _v0.b; + var range = (hi - lo) + 1; + if (!((range - 1) & range)) { + return _Utils_Tuple2( + (((range - 1) & $elm$random$Random$peel(seed0)) >>> 0) + lo, + $elm$random$Random$next(seed0)); + } else { + var threshhold = (((-range) >>> 0) % range) >>> 0; + var accountForBias = function (seed) { + accountForBias: + while (true) { + var x = $elm$random$Random$peel(seed); + var seedN = $elm$random$Random$next(seed); + if (_Utils_cmp(x, threshhold) < 0) { + var $temp$seed = seedN; + seed = $temp$seed; + continue accountForBias; + } else { + return _Utils_Tuple2((x % range) + lo, seedN); + } + } + }; + return accountForBias(seed0); + } + }); + }); +var $elm$random$Random$listHelp = F4( + function (revList, n, gen, seed) { + listHelp: + while (true) { + if (n < 1) { + return _Utils_Tuple2(revList, seed); + } else { + var _v0 = gen(seed); + var value = _v0.a; + var newSeed = _v0.b; + var $temp$revList = A2($elm$core$List$cons, value, revList), + $temp$n = n - 1, + $temp$gen = gen, + $temp$seed = newSeed; + revList = $temp$revList; + n = $temp$n; + gen = $temp$gen; + seed = $temp$seed; + continue listHelp; + } + } + }); +var $elm$random$Random$list = F2( + function (n, _v0) { + var gen = _v0.a; + return $elm$random$Random$Generator( + function (seed) { + return A4($elm$random$Random$listHelp, _List_Nil, n, gen, seed); + }); + }); +var $author$project$Main$roll = function (dice) { + return A2( + $elm$random$Random$generate, + $author$project$Main$RollResult, + A2( + $elm$random$Random$list, + dice.amount, + A2($elm$random$Random$int, 1, 10))); +}; var $author$project$Stats$setAffinityIfSame = F2( function (sphere, stat) { var _v0 = stat.statType; @@ -6816,6 +7088,9 @@ var $author$project$Character$setAffinity = F2( stats: A2($author$project$Stats$setAffinity, character.stats, stat) }); }); +var $elm$core$List$sort = function (xs) { + return A2($elm$core$List$sortBy, $elm$core$Basics$identity, xs); +}; var $elm$url$Url$addPort = F2( function (maybePort, starter) { if (maybePort.$ === 'Nothing') { @@ -6985,16 +7260,44 @@ var $author$project$Main$update = F2( model, {url: url}), $elm$core$Platform$Cmd$none); - default: + case 'ResetCharacter': return _Utils_Tuple2( _Utils_update( model, {character: $author$project$Character$new}), $elm$core$Platform$Cmd$none); + case 'SetDice': + var dice = msg.a; + return _Utils_Tuple2( + _Utils_update( + model, + {dice: dice}), + $elm$core$Platform$Cmd$none); + case 'Roll': + return _Utils_Tuple2( + model, + $author$project$Main$roll(model.dice)); + case 'RollResult': + var result = msg.a; + return _Utils_Tuple2( + _Utils_update( + model, + { + roll: $elm$core$List$reverse( + $elm$core$List$sort(result)) + }), + $elm$core$Platform$Cmd$none); + default: + return _Utils_Tuple2( + _Utils_update( + model, + {dice: $author$project$Dice$new, roll: _List_Nil}), + $elm$core$Platform$Cmd$none); } }); var $elm$html$Html$div = _VirtualDom_node('div'); var $author$project$Main$CreateCharacter = {$: 'CreateCharacter'}; +var $author$project$Main$RollDice = {$: 'RollDice'}; var $author$project$Main$ViewCharacter = {$: 'ViewCharacter'}; var $author$project$Main$getMode = function (url) { var _v0 = url.fragment; @@ -7005,6 +7308,8 @@ var $author$project$Main$getMode = function (url) { return $author$project$Main$ViewCharacter; case 'create': return $author$project$Main$CreateCharacter; + case 'dice': + return $author$project$Main$RollDice; default: return $author$project$Main$CreateCharacter; } @@ -8363,6 +8668,444 @@ var $author$project$Main$viewCreate = function (model) { $author$project$Main$viewModal(model) ])); }; +var $author$project$Main$Roll = {$: 'Roll'}; +var $author$project$Main$SetDice = function (a) { + return {$: 'SetDice', a: a}; +}; +var $author$project$Dice$changeAmountTo = F2( + function (dice, amount) { + return _Utils_update( + dice, + {amount: amount}); + }); +var $author$project$Dice$changeDifficultyTo = F2( + function (dice, difficulty) { + return _Utils_update( + dice, + { + difficulty: (difficulty > 10) ? 10 : difficulty + }); + }); +var $elm$html$Html$label = _VirtualDom_node('label'); +var $elm$html$Html$Attributes$max = $elm$html$Html$Attributes$stringProperty('max'); +var $elm$html$Html$Attributes$min = $elm$html$Html$Attributes$stringProperty('min'); +var $elm$core$Basics$not = _Basics_not; +var $author$project$Dice$switchSpecialty = function (dice) { + return _Utils_update( + dice, + {specialty: !dice.specialty}); +}; +var $author$project$Dice$switchWillpower = function (dice) { + return _Utils_update( + dice, + {willpower: !dice.willpower}); +}; +var $author$project$Main$viewDiceInput = function (model) { + return A2( + $elm$html$Html$div, + _List_Nil, + _List_fromArray( + [ + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('field is-horizontal') + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('field-label is-normal') + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('label') + ]), + _List_fromArray( + [ + $elm$html$Html$text('Amount') + ])) + ])), + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('field-body') + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('field') + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('control') + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$input, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('input'), + $elm$html$Html$Attributes$type_('number'), + $elm$html$Html$Attributes$min('1'), + $elm$html$Html$Attributes$placeholder('1'), + $elm$html$Html$Events$onInput( + function (x) { + return $author$project$Main$SetDice( + A2( + $author$project$Dice$changeAmountTo, + model.dice, + A2( + $elm$core$Maybe$withDefault, + 1, + $elm$core$String$toInt(x)))); + }) + ]), + _List_Nil) + ])) + ])) + ])) + ])), + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('field is-horizontal') + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('field-label is-normal') + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('label') + ]), + _List_fromArray( + [ + $elm$html$Html$text('Difficulty') + ])) + ])), + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('field-body') + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('field') + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('control') + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$input, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('input'), + $elm$html$Html$Attributes$type_('number'), + $elm$html$Html$Attributes$min('1'), + $elm$html$Html$Attributes$max('10'), + $elm$html$Html$Attributes$placeholder('6'), + $elm$html$Html$Events$onInput( + function (x) { + return $author$project$Main$SetDice( + A2( + $author$project$Dice$changeDifficultyTo, + model.dice, + A2( + $elm$core$Maybe$withDefault, + 6, + $elm$core$String$toInt(x)))); + }) + ]), + _List_Nil) + ])) + ])) + ])) + ])), + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('field') + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$label, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('checkbox') + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$input, + _List_fromArray( + [ + $elm$html$Html$Attributes$type_('checkbox'), + $elm$html$Html$Events$onClick( + $author$project$Main$SetDice( + $author$project$Dice$switchWillpower(model.dice))) + ]), + _List_Nil), + $elm$html$Html$text('Use Willpower') + ])) + ])), + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('field') + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$label, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('checkbox') + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$input, + _List_fromArray( + [ + $elm$html$Html$Attributes$type_('checkbox'), + $elm$html$Html$Events$onClick( + $author$project$Main$SetDice( + $author$project$Dice$switchSpecialty(model.dice))) + ]), + _List_Nil), + $elm$html$Html$text('Is Specialty') + ])) + ])), + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('field is-horizontal') + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('field-body') + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('field') + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('control') + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$button, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('button is-primary is-fullwidth'), + $elm$html$Html$Events$onClick($author$project$Main$Roll) + ]), + _List_fromArray( + [ + $elm$html$Html$text('Roll Dice') + ])) + ])) + ])) + ])) + ])) + ])); +}; +var $elm$core$Basics$ge = _Utils_ge; +var $author$project$Dice$successes = F2( + function (dice, roll) { + var special = dice.specialty ? $elm$core$List$length( + A2( + $elm$core$List$filter, + function (x) { + return x === 10; + }, + roll)) : 0; + var plus = $elm$core$List$length( + A2( + $elm$core$List$filter, + function (x) { + return _Utils_cmp(x, dice.difficulty) > -1; + }, + roll)); + var minus = $elm$core$List$length( + A2( + $elm$core$List$filter, + function (x) { + return x === 1; + }, + A2( + $elm$core$List$filter, + function (x) { + return _Utils_cmp(x, dice.difficulty) < 0; + }, + roll))); + var result = (special + plus) - minus; + return dice.willpower ? ((result < 1) ? 1 : result) : result; + }); +var $author$project$Main$viewResultDie = F2( + function (difficulty, result) { + var color = (_Utils_cmp(result, difficulty) > -1) ? ' is-success' : ((result === 1) ? ' is-danger' : ''); + return A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('square') + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('content notification' + color) + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('label is-large') + ]), + _List_fromArray( + [ + $elm$html$Html$text( + $elm$core$String$fromInt(result)) + ])) + ])) + ])); + }); +var $author$project$Main$viewSuccesses = function (successes) { + var successText = (!successes) ? 'Failure' : ((successes > 0) ? ((successes > 1) ? ($elm$core$String$fromInt(successes) + ' Successes') : '1 Success') : ((_Utils_cmp(successes, -1) < 0) ? ($elm$core$String$fromInt(-successes) + ' Botches') : '1 Botch')); + var color = (successes > 0) ? ' is-success' : ' is-danger'; + return A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('notification' + color) + ]), + _List_fromArray( + [ + $elm$html$Html$text(successText) + ])); +}; +var $author$project$Main$viewDiceRoll = F2( + function (dice, rollResult) { + return ($elm$core$List$length(rollResult) > 0) ? A2( + $elm$html$Html$div, + _List_Nil, + _List_fromArray( + [ + $author$project$Main$viewSuccesses( + A2($author$project$Dice$successes, dice, rollResult)), + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('square-container') + ]), + A2( + $elm$core$List$map, + $author$project$Main$viewResultDie(dice.difficulty), + rollResult)) + ])) : A2($elm$html$Html$div, _List_Nil, _List_Nil); + }); +var $author$project$Main$viewDice = function (model) { + return A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('container') + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('columns is-centered') + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('column is-one-third') + ]), + _List_fromArray( + [ + $author$project$Main$viewDiceInput(model) + ])), + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('column is-two-thirds') + ]), + _List_fromArray( + [ + A2($author$project$Main$viewDiceRoll, model.dice, model.roll) + ])) + ])) + ])); +}; var $author$project$Main$ResetCharacter = {$: 'ResetCharacter'}; var $author$project$Main$ariaExpanded = function (value) { return A2($elm$html$Html$Attributes$attribute, 'aria-expanded', value); @@ -8448,6 +9191,66 @@ var $author$project$Main$viewImport = function (url) { ])) ])); }; +var $author$project$Main$ResetRoll = {$: 'ResetRoll'}; +var $author$project$Main$viewNavbarDice = A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('navbar-end') + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('navbar-item') + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$a, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('button'), + $elm$html$Html$Attributes$href('#dice'), + $elm$html$Html$Events$onClick($author$project$Main$ResetRoll) + ]), + _List_fromArray( + [ + $elm$html$Html$text('Roll Dice') + ])) + ])) + ])); +var $author$project$Main$viewNavbarDiceToChar = A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('navbar-end') + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('navbar-item') + ]), + _List_fromArray( + [ + A2( + $elm$html$Html$a, + _List_fromArray( + [ + $elm$html$Html$Attributes$class('button'), + $elm$html$Html$Attributes$href('#view') + ]), + _List_fromArray( + [ + $elm$html$Html$text('Back to Character') + ])) + ])) + ])); var $author$project$Main$viewNavbarFinish = A2( $elm$html$Html$div, _List_fromArray( @@ -8582,10 +9385,13 @@ var $author$project$Main$viewNavbar = function (model) { ])), function () { var _v0 = $author$project$Main$getMode(model.url); - if (_v0.$ === 'CreateCharacter') { - return $author$project$Main$viewNavbarFinish; - } else { - return A2($elm$html$Html$div, _List_Nil, _List_Nil); + switch (_v0.$) { + case 'CreateCharacter': + return $author$project$Main$viewNavbarFinish; + case 'ViewCharacter': + return $author$project$Main$viewNavbarDice; + default: + return $author$project$Main$viewNavbarDiceToChar; } }() ])) @@ -9614,10 +10420,13 @@ var $author$project$Main$view = function (model) { $author$project$Main$viewNavbar(model), function () { var _v0 = $author$project$Main$getMode(model.url); - if (_v0.$ === 'ViewCharacter') { - return $author$project$Main$viewView(model); - } else { - return $author$project$Main$viewCreate(model); + switch (_v0.$) { + case 'ViewCharacter': + return $author$project$Main$viewView(model); + case 'CreateCharacter': + return $author$project$Main$viewCreate(model); + default: + return $author$project$Main$viewDice(model); } }() ])) diff --git a/src/Dice.elm b/src/Dice.elm new file mode 100644 index 0000000000000000000000000000000000000000..70c31bdc876d8487ffb7c8bcd209b5e93aed7730 --- /dev/null +++ b/src/Dice.elm @@ -0,0 +1,65 @@ +module Dice exposing (..) + +type alias Dice = + { amount : Int + , difficulty : Int + , willpower : Bool + , specialty : Bool + } + +new : Dice +new = + { amount = 1 + , difficulty = 6 + , willpower = False + , specialty = False + } + +changeAmountTo : Dice -> Int -> Dice +changeAmountTo dice amount = + { dice | amount = amount } + +changeDifficultyTo : Dice -> Int -> Dice +changeDifficultyTo dice difficulty = + { dice + | difficulty = + if difficulty > 10 + then 10 + else difficulty + } + +switchWillpower : Dice -> Dice +switchWillpower dice = + { dice | willpower = not dice.willpower } + +switchSpecialty : Dice -> Dice +switchSpecialty dice = + { dice | specialty = not dice.specialty } + +successes : Dice -> List Int -> Int +successes dice roll = + let + special : Int + special = + if dice.specialty + then + roll + |> List.filter ( \x -> x == 10 ) + |> List.length + else 0 + plus : Int + plus = roll + |> List.filter ( \x -> x >= dice.difficulty ) + |> List.length + minus : Int + minus = roll + |> List.filter ( \x -> x < dice.difficulty ) + |> List.filter ( \x -> x == 1 ) + |> List.length + result = special + plus - minus + in + if dice.willpower + then if result < 1 + then 1 + else result + else result \ No newline at end of file diff --git a/src/Main.elm b/src/Main.elm index fb3044818ed0e381e42523c485314eaf813336b1..d0d101081621926dabd35bdc8a0be3cd9675d07c 100644 --- a/src/Main.elm +++ b/src/Main.elm @@ -16,8 +16,8 @@ import Http import Json.Decode import Url import Browser.Navigation as Nav -import Url.Parser exposing (Parser, (</>)) -import Url.Parser.Query +import Dice exposing (Dice) +import Random main : Program () Model Msg main = @@ -38,6 +38,8 @@ init _ url key = , activeDropdown = Nothing , key = key , url = url + , dice = Dice.new + , roll = [] } , Cmd.none ) @@ -49,6 +51,8 @@ type alias Model = , activeDropdown : Maybe ActiveDropdown , key : Nav.Key , url : Url.Url + , dice : Dice + , roll : List Int } type ActiveDropdown @@ -57,6 +61,7 @@ type ActiveDropdown type Mode = CreateCharacter | ViewCharacter + | RollDice type Msg = OpenModal ModalType @@ -72,6 +77,10 @@ type Msg | LinkClicked Browser.UrlRequest | UrlChanged Url.Url | ResetCharacter + | SetDice Dice + | Roll + | RollResult ( List Int ) + | ResetRoll type ModalType = Name @@ -169,6 +178,34 @@ update msg model = } , Cmd.none ) + SetDice dice -> + ( { model + | dice = dice + } + , Cmd.none + ) + Roll -> + ( model + , roll model.dice + ) + RollResult result -> + ( { model + | roll = List.reverse <| List.sort <| result + } + , Cmd.none + ) + ResetRoll -> + ( { model + | roll = [] + , dice = Dice.new + } + , Cmd.none + ) + + +roll : Dice -> Cmd Msg +roll dice = + Random.generate RollResult ( Random.list dice.amount ( Random.int 1 10 ) ) getMode : Url.Url -> Mode getMode url = @@ -177,6 +214,7 @@ getMode url = case fragment of "view" -> ViewCharacter "create" -> CreateCharacter + "dice" -> RollDice _ -> CreateCharacter Nothing -> CreateCharacter @@ -194,6 +232,7 @@ view model = , case getMode model.url of ViewCharacter -> viewView model CreateCharacter -> viewCreate model + RollDice -> viewDice model ] ] } @@ -235,7 +274,8 @@ viewNavbar model = ] , case getMode model.url of CreateCharacter -> viewNavbarFinish - ViewCharacter -> div [] [] + ViewCharacter -> viewNavbarDice + RollDice -> viewNavbarDiceToChar ] ] @@ -251,6 +291,31 @@ viewNavbarFinish = ] ] +viewNavbarDice : Html Msg +viewNavbarDice = + div [ class "navbar-end" ] + [ div [ class "navbar-item" ] + [ a + [ class "button" + , href "#dice" + , onClick ResetRoll + ] + [ text "Roll Dice" ] + ] + ] + +viewNavbarDiceToChar : Html Msg +viewNavbarDiceToChar = + div [ class "navbar-end" ] + [ div [ class "navbar-item" ] + [ a + [ class "button" + , href "#view" + ] + [ text "Back to Character" ] + ] + ] + viewImport : Url.Url -> Html Msg viewImport url = div [ class "navbar-item has-dropdown is-hoverable" ] @@ -974,6 +1039,149 @@ vViewAbilities abilities dotSize = ] ] +viewDice : Model -> Html Msg +viewDice model = + div [ class "container" ] + [ div [ class "columns is-centered" ] + [ div [ class "column is-one-third" ] + [ viewDiceInput model + ] + , div [ class "column is-two-thirds" ] + [ viewDiceRoll model.dice model.roll + ] + ] + ] + +viewDiceInput : Model -> Html Msg +viewDiceInput model = + div [] + [ div [ class "field is-horizontal" ] + [ div [ class "field-label is-normal" ] + [ div [ class "label" ] [ text "Amount" ] ] + , div [ class "field-body" ] + [ div [ class "field" ] + [ div [ class "control" ] + [ input + [ class "input" + , type_ "number" + , Html.Attributes.min "1" + , placeholder "1" + , onInput ( \x -> SetDice ( Dice.changeAmountTo model.dice ( Maybe.withDefault 1 <| String.toInt x ) ) ) + ] [] + ] + ] + ] + ] + , div [ class "field is-horizontal" ] + [ div [ class "field-label is-normal" ] + [ div [ class "label" ] [ text "Difficulty" ] ] + , div [ class "field-body" ] + [ div [ class "field" ] + [ div [ class "control" ] + [ input + [ class "input" + , type_ "number" + , Html.Attributes.min "1" + , Html.Attributes.max "10" + , placeholder "6" + , onInput ( \x -> SetDice ( Dice.changeDifficultyTo model.dice ( Maybe.withDefault 6 <| String.toInt x ) ) ) + ] [] + ] + ] + ] + ] + , div [ class "field" ] + [ label [ class "checkbox" ] + [ input + [ type_ "checkbox" + , onClick ( SetDice ( Dice.switchWillpower model.dice ) ) + ] [] + , text "Use Willpower" + ] + ] + , div [ class "field" ] + [ label [ class "checkbox" ] + [ input + [ type_ "checkbox" + , onClick ( SetDice ( Dice.switchSpecialty model.dice ) ) + ] [] + , text "Is Specialty" + ] + ] + , div [ class "field is-horizontal" ] + [ div [ class "field-body" ] + [ div [ class "field" ] + [ div [ class "control" ] + [ button + [ class "button is-primary is-fullwidth" + , onClick Roll + ] + [ text "Roll Dice" + ] + ] + ] + ] + ] + ] + +viewDiceRoll : Dice -> List Int -> Html Msg +viewDiceRoll dice rollResult = + if List.length rollResult > 0 + then + div [] + [ viewSuccesses ( Dice.successes dice rollResult ) + , div [ class "square-container" ] + ( List.map ( viewResultDie dice.difficulty ) rollResult ) + ] + else + div [] [] + +viewSuccesses : Int -> Html Msg +viewSuccesses successes = + let + color : String + color = + if successes > 0 + then " is-success" + else " is-danger" + successText : String + successText = + if successes == 0 + then "Failure" + else + if successes > 0 + then + if successes > 1 + then ( String.fromInt successes ) ++ " Successes" + else "1 Success" + else + if successes < -1 + then ( String.fromInt <| negate successes ) ++ " Botches" + else "1 Botch" + in + div + [ class ( "notification" ++ color ) ] + [ text successText ] + +viewResultDie : Int -> Int -> Html Msg +viewResultDie difficulty result = + let + color : String + color = + if result >= difficulty + then " is-success" + else + if result == 1 + then " is-danger" + else "" + in + div + [ class "square" ] + [ div [ class ( "content notification" ++ color ) ] + [ div [ class "label is-large" ] [ text ( String.fromInt result ) ] + ] + ] + -- subscriptions subscriptions : Model -> Sub Msg diff --git a/src/Stats.elm b/src/Stats.elm index 28f431867e91c743b72b808cc3120d9c0e2ddd94..d2e34eb4bed69f179db67fa7f5bf04f91f74db80 100644 --- a/src/Stats.elm +++ b/src/Stats.elm @@ -1,7 +1,6 @@ module Stats exposing (..) import BoundedInt exposing (BoundedInt) -import Svg.Attributes exposing (in_) type alias Stat = { name : String