diff --git a/.angular-cli.json b/.angular-cli.json index 989773a..2f0f85e 100644 --- a/.angular-cli.json +++ b/.angular-cli.json @@ -9,7 +9,11 @@ "outDir": "dist", "assets": [ "assets", - "favicon.ico" + "favicon.ico", + "crit-spell.json", + "crit-weapon.json", + "fumble-weapon.json", + "fumble-spell.json" ], "index": "index.html", "main": "main.ts", diff --git a/README.md b/README.md index 681f319..690ce0d 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,10 @@ website. http://www.critter-5e.com/ +# GitHub Repo + +https://github.com/allenr98/critter-5e + ## Development server Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. diff --git a/package.json b/package.json index 714058a..0f214ee 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,9 @@ "@angular/platform-browser": "^4.2.4", "@angular/platform-browser-dynamic": "^4.2.4", "@angular/router": "^4.2.4", + "bootstrap": "^4.0.0-alpha.6", "core-js": "^2.4.1", + "font-awesome": "^4.7.0", "rxjs": "^5.4.2", "zone.js": "^0.8.14" }, diff --git a/src/app/app.component.css b/src/app/app.component.css index e69de29..3d2d68e 100644 --- a/src/app/app.component.css +++ b/src/app/app.component.css @@ -0,0 +1,30 @@ +body{margin:40px;} +.btn-circle { + width: 30px; + height: 30px; + text-align: center; + padding: 6px 0; + font-size: 12px; + line-height: 1.428571429; + border-radius: 15px; +} +.btn-circle.btn-lg { + width: 50px; + height: 50px; + padding: 13px 13px; + font-size: 18px; + line-height: 1.33; + border-radius: 25px; +} +.result-text { + font-size: 12px; +} + +.flex, .flex > div[class*='col-'] { + display: -webkit-box; + display: -moz-box; + display: -ms-flexbox; + display: -webkit-flex; + display: flex; + flex:1 0 auto; +} diff --git a/src/app/app.component.html b/src/app/app.component.html index 1932b39..7545eed 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,20 +1,105 @@ -
-

- Welcome to {{title}}! -

- +
+
+

+ Welcome to {{title}}! +

+ Based on the excellent D&D Fifth Edition critical success and failure charts by Questionably + Qualified. +
+
+
+

The RAW(Rules as Written) Critical Hit Rules

+

All critical hits and misses still follow the original 5e rules of rolling another set of the attacks damage + dice. This includes rolling extra dice for abilities that are a part of the attack such as damage from sneak + attack, hex, or the initial strike of green flame blade.

+

Where The Tables Fit In

+

These tables simply contain a list of additional effects that take place on top of the existing critical roll + rules.There are individual tables below for both weapon attacks and spell attacks because let's be honest, there + is a difference between missing with a bow and missing with a scorching ray.

+
+
+ +
+
+
+

Choose the type of attack:

+
+ + + +
+
+
+ + +
+
+
+
+
+
+
+ {{ selectedType }} - {{ selectedFunction }} +
+
+
+
+
+
+
+
+ +
+
+ {{ roll }} +
+
+
+
+
+
+ +
+
+ {{ result.description }} +
+
+
+
+
+
+ +
+
+ {{ result.effect }} +
+
+
+
+
+
+ +
+
+
+
+
+
-

Here are some links to help you start:

- - diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 7b0f672..05136ac 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,10 +1,153 @@ import { Component } from '@angular/core'; +import { FormBuilder, FormGroup } from '@angular/forms'; +import * as critical_data from '../assets/crit-weapon.json'; +import * as fumble_data from '../assets/fumble-weapon.json'; +import * as spell_critical_data from '../assets/crit-spell.json'; +import * as spell_fumble_data from '../assets/fumble-spell.json'; @Component({ selector: 'app-root', templateUrl: './app.component.html', - styleUrls: ['./app.component.css'] + styleUrls: ['./app.component.css'], }) export class AppComponent { - title = 'app'; + title = '5e Critter'; + rForm: FormGroup; + selectedType: 'melee'; + selectedFunction: 'critical'; + roll; + result; + + critWeapon; + critSpell; + fumbleWeapon; + fumbleSpell; + + static getRandom(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + constructor(private formBuilder: FormBuilder) { + + this.critWeapon = (critical_data); + this.fumbleWeapon = (fumble_data); + this.critSpell = (spell_critical_data); + this.fumbleSpell = (spell_fumble_data); + + this.rForm = formBuilder.group({ + selectedType: 'melee', + result: '', + 'validate': '' + }); + + } + + addPost(formPost) { + if (!this.selectedType || this.selectedType == null ) { + this.selectedType = formPost.selectedType; + } + console.log('type: ', this.selectedType); + console.log('func: ', this.selectedFunction); + + // Get a random number between 1 and 100 + this.roll = AppComponent.getRandom(1, 100); + const crit = this.getResult(this.roll, this.selectedType, this.selectedFunction); + this.result = { + 'description': crit.description, + 'effect': crit.effect + }; + } + + getResult(roll, type, func) { + let returnValue = { + 'roll': 'Invalid', + 'description': 'Invalid roll', + 'effect': 'Value: ' + roll + }; + + if (roll >= 1 || roll <= 100) { + if (func === 'critical') { + if (type === 'melee' || type === 'ranged') { + returnValue = this.findInList(roll, this.critWeapon); + } else if (type === 'spell') { + returnValue = this.findInList(roll, this.critSpell); + } else { + returnValue = { + 'roll': 'Invalid', + 'description': 'Invalid attack type', + 'effect': 'Value: ' + type + }; + } + } else if (func === 'fumble') { + if (type === 'melee' || type === 'ranged') { + returnValue = this.findInMultipurposeList(roll, this.fumbleWeapon, type); + } else if (type === 'spell') { + returnValue = this.findInList(roll, this.fumbleSpell); + } else { + returnValue = { + 'roll': 'Invalid', + 'description': 'Invalid attack type', + 'effect': 'Value: ' + type + }; + } + } else { + returnValue = { + 'roll': 'Invalid', + 'description': 'Invalid function selection', + 'effect': 'Value: ' + func + }; + } + } + + return returnValue; + } + + findInList(roll, list) { + let returnValue = { + 'roll': 'n/a', + 'description': 'Not found', + 'effect': 'n/a' + }; + list.forEach(item => { + const splitRange = item.roll.split('-'); + if ( roll >= splitRange[0] && roll <= splitRange[1]) { + returnValue = item; + } + }); + + return returnValue; + } + + findInMultipurposeList(roll, list, type) { + let returnValue = { + 'roll': 'n/a', + 'description': 'Not found', + 'effect': 'n/a' + }; + list.forEach(item => { + const splitRange = item.roll.split('-'); + if ( roll >= splitRange[0] && roll <= splitRange[1] && (item.type === type || item.type === 'both')) { + returnValue = item; + } + }); + + return returnValue; + } + + selectAttackType(value) { + this.selectedType = value; + this.result = { + 'description': '' + }; + } + + selectFunction(value) { + this.selectedFunction = value; + } + + clearResults() { + this.result = { + 'description': '' + }; + } } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index f657163..7d2f968 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -2,13 +2,18 @@ import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; +import {FormsModule, ReactiveFormsModule} from '@angular/forms'; +import {HttpModule} from '@angular/http'; @NgModule({ declarations: [ AppComponent ], imports: [ - BrowserModule + BrowserModule, + FormsModule, + HttpModule, + ReactiveFormsModule ], providers: [], bootstrap: [AppComponent] diff --git a/src/assets/crit-spell.json b/src/assets/crit-spell.json new file mode 100644 index 0000000..466ab13 --- /dev/null +++ b/src/assets/crit-spell.json @@ -0,0 +1,87 @@ +[ + { + "roll": "1-1", + "description": "You feel accomplished, but nothing remarkable happens.", + "effect": "Regular spell critical hit." + }, + { + "roll": "2-5", + "description": "You feel it is imperative to press the advantage no matter the cost.", + "effect": "You can choose to gain advantage on your next attack roll against your target, but all enemies have advantage on their attack rolls against you until the end of your next turn." + }, + { + "roll": "6-9", + "description": "You feel it is imperative to press the advantage, but maintain awareness of your surroundings.", + "effect": "You can choose to gain advantage on your next attack roll against your target, your target has advantage on their attack rolls against you until the end of your next turn." + }, + { + "roll": "10-14", + "description": "As you are fighting, you notice an effective route to escape danger.", + "effect": "You are able to use the disengage action after your attack." + }, + { + "roll": "15-19", + "description": "You feel the eb and flow of the battle, and know where to make your next move.", + "effect": "After your turn you move to the top of the initiative order." + }, + { + "roll": "20-29", + "description": "Your spell cripples your opponent.", + "effect": "Your target's movement speed is cut in half for their next 2 turns." + }, + { + "roll": "30-39", + "description": "Your spell attack knocks your target over.", + "effect": "Your target is knocked prone." + }, + { + "roll": "40-49", + "description": "The light from your spell flashes near your target's eyes", + "effect": "Your target is blinded until the end of their next turn." + }, + { + "roll": "50-59", + "description": "You blast the targets weapons out of their hands.", + "effect": "Your target's weapon is flung 1d6*5 feet away in a random direction." + }, + { + "roll": "60-69", + "description": "The sight of your magic fills the target's heart with fear.", + "effect": "Your target is frightened by you until you stop casting magic. You are able to discern the source of your targets fear." + }, + { + "roll": "70-74", + "description": "The force from your spell stuns your opponent.", + "effect": "Your target is incapacitated until the end of their next turn." + }, + { + "roll": "75-79", + "description": "Your spell is incidentally infused with fey energy.", + "effect": "Roll 10d8. If your targets current health is lower than the number rolled they fall asleep for 1 minute." + }, + { + "roll": "80-84", + "description": "Your spells strike surprises your opponent.", + "effect": "Your target is surprised until the end of their next turn." + }, + { + "roll": "85-89", + "description": "Your spell strikes with great force.", + "effect": "Roll an additional set of spell damage dice above and beyond your normal critical roll." + }, + { + "roll": "90-94", + "description": "Your spell strikes with extreme force.", + "effect": "Roll an additional set of spell damage dice above and beyond your normal critical roll, and the target suffers one unit of exhaustion." + }, + { + "roll": "96-99", + "description": "Your spell strikes with debilitating force.", + "effect": "Roll an additional set of spell damage dice above and beyond your normal critical roll, and the target suffers a permanent injury chose by the DM. The permanent injury can be healed with extended rest of a length determined by the DM, but the attack leaves a scar." + }, + { + "roll": "100-100", + "description": "Your spell strikes with devastating force.", + "effect": "Roll an additional set of spell damage dice above and beyond your normal critical roll, and the target suffers 1 unit of exhaustion, and the target suffers a permanent injury chose by the DM. The permanent injury can be healed with extended rest of a length determined by the DM, but the attack leaves a scar." + } +] diff --git a/src/assets/crit-weapon.json b/src/assets/crit-weapon.json new file mode 100644 index 0000000..8d84947 --- /dev/null +++ b/src/assets/crit-weapon.json @@ -0,0 +1,92 @@ +[ + { + "roll": "1-1", + "description": "You feel accomplished, but nothing remarkable happens.", + "effect": "Regular critical hit." + }, + { + "roll": "2-5", + "description": "You feel it is imperative to press the advantage no matter the cost.", + "effect": "You can choose to gain advantage on all attacks against your target until the end of your next turn, but if you do all enemies have advantage on their attack rolls against you until the end of your next turn." + }, + { + "roll": "6-9", + "description": "You feel it is imperative to press the advantage, but maintain awareness of your surroundings.", + "effect": "You can choose to gain advantage on all attacks against your target next turn, your target has advantage on their attack rolls against you until the end of your next turn." + }, + { + "roll": "10-14", + "description": "You know how to press the advantage.", + "effect": "You gain advantage on all attacks against your target until the end of your next turn." + }, + { + "roll": "15-19", + "description": "As you are fighting, you notice an effective route to escape danger.", + "effect": "You are able to use the disengage action after your attack." + }, + { + "roll": "20-24", + "description": "You feel the eb and flow of the battle, and know where to make your next move.", + "effect": "After your turn you move to the top of the initiative order." + }, + { + "roll": "25-29", + "description": "You begin to recognize patterns in your opponents fighting technique.", + "effect": "You gain +2 to your AC against your target, and advantage on all savings throws from effects originating from your target until your next turn." + }, + { + "roll": "30-39", + "description": "You are able to maneuver towards your opponent while attacking, and attempt to harass them.", + "effect": "After your attack you can choose to attempt to grapple your opponent if you have a free hand, or attempt to shove your opponent if both hands are in use." + }, + { + "roll": "40-49", + "description": "You are able to maneuver towards your opponent while attacking and harass them.", + "effect": "After your attack you can choose to automatically succeed in grappling your opponent if you have a free hand, or shoving your opponent if both hands are in use." + }, + { + "roll": "50-59", + "description": "You attempt to disarm your opponent.", + "effect": "You are able to take the disarm action after your attack" + }, + { + "roll": "60-69", + "description": "You kick your target's weapon out of their hands.", + "effect": "You are able to take the disarm action after your attack, and can steal your opponents weapon if you have a free hand. Otherwise you can knock it up to 20 feet away." + }, + { + "roll": "70-74", + "description": "Your senses heighten and you become aware of threats around the battlefield.", + "effect": "You are able to use the dodge action after your attack." + }, + { + "roll": "75-79", + "description": "Your attack knocks your target over.", + "effect": "Your target is knocked prone." + }, + { + "roll": "80-84", + "description": "Your strike surprises your opponent.", + "effect": "Your target is surprised until the end of their next turn." + }, + { + "roll": "85-89", + "description": "You strike with great force.", + "effect": "Roll an additional set of damage dice above and beyond your normal critical roll." + }, + { + "roll": "90-94", + "description": "You strike with extreme force.", + "effect": "Roll an additional set of damage dice above and beyond your normal critical roll, and the target suffers one unit of exhaustion." + }, + { + "roll": "95-99", + "description": "You strike with debilitating force.", + "effect": "Roll an additional set of damage dice above and beyond your normal critical roll, and the target suffers a permanent injury chosen by the DM. The permanent injury can be healed with extended rest of a length determined by the DM, but the attack leaves a scar." + }, + { + "roll": "100-100", + "description": "You strike with devastating force.", + "effect": "Roll an additional set of damage dice above and beyond your normal critical roll, and the target suffers 1 unit of exhaustion, and the target suffers a permanent injury chosen by the DM. The permanent injury can be healed with extended rest of a length determined by the DM, but the attack leaves a scar." + } +] diff --git a/src/assets/fumble-spell.json b/src/assets/fumble-spell.json new file mode 100644 index 0000000..0dec7cb --- /dev/null +++ b/src/assets/fumble-spell.json @@ -0,0 +1,82 @@ +[ + { + "roll": "1-1", + "description": "You are embarassed by your poor showing, but nothing remarkable happens.", + "effect": "You miss your attack." + }, + { + "roll": "2-5", + "description": "You get wrapped up in your spellcasting and forget to watch your target.", + "effect": "Your target has advantage on their first attack roll against you next round." + }, + { + "roll": "6-9", + "description": "You get wrapped up in your spellcasting and forget to watch your surroundings.", + "effect": "All enemies have advantage on their first attack roll against you next round." + }, + { + "roll": "10-14", + "description": "You are so wrapped up in your spellcasting that you forget you are fighting a battle.", + "effect": "All enemies have advantage on their attack rolls against you until the end of your next turn." + }, + { + "roll": "15-19", + "description": "Your spell creates a large plume of smoke obscuring your location.", + "effect": "The area in a 5 foot radius around your location becomes heavily obscured for 1 minute. A strong breeze can blow away the smoke in 1 round." + }, + { + "roll": "20-29", + "description": "Your spell misfires knocking you over.", + "effect": "You are knocked prone." + }, + { + "roll": "30-39", + "description": "The spell fires in an unexpected manner, causing your confidence in your abilities to falter.", + "effect": "You have disadvantage on any spell attacks, and enemies have advantage against your spell savings throws until the end of your next turn." + }, + { + "roll": "40-49", + "description": "The placement of your spell startles your allies near your target, causing them to drop their guard.", + "effect": "Your target is able to use their reaction to take an attack of opportunity on one of your allies in melee range." + }, + { + "roll": "50-59", + "description": "You scramble the ingredients of your component pouch or your focus becomes overloaded with magical energy and temporarily stops working.", + "effect": "You are unable to perform material components to cast spells until the end of your next turn." + }, + { + "roll": "60-69", + "description": "Your arm cramps as you cast.", + "effect": "You are unable to perform somatic components to cast spells until the end of your next turn." + }, + { + "roll": "70-79", + "description": "You bite your tongue as you cast.", + "effect": "You are unable to use verbal components to cast spells until the end of your next turn." + }, + { + "roll": "80-84", + "description": "Your spell misfires and dazes you, causing you to lose track of the fight.", + "effect": "End your turn and move to the bottom of the initiative order at the start of the next round." + }, + { + "roll": "85-89", + "description": "Your spell misfires causing you to panic.", + "effect": "End your current turn and you are surprised until the end of your next turn." + }, + { + "roll": "90-94", + "description": "Your spell backfires creating a small explosion causing you to fall and bump your head.", + "effect": "You fall prone. Roll a DC 10 constitution save, on failure you take 1d6 bludgeoning damage and are knocked unconscious for 1 minute or until you receive damage from any source. On success take half damage and you remain conscious." + }, + { + "roll": "95-99", + "description": "Your spell backfires creating a large explosion causing you to fall and bump your head.", + "effect": "You fall prone. Roll a DC 15 constitution save, on failure you take 1d6 bludgeoning damage, 1d6 thunder damage, and are knocked unconscious for 1 minute or until you receive damage from any source. On success take half damage and you remain conscious." + }, + { + "roll": "100-100", + "description": "Your spell completely backfires creating a large explosion causing you to fall and bump your head.", + "effect": "You hit yourself with your spell. If the spell effect is instant you take the full effect. If the spell requires concentration the effect persists until the end of your next turn. You also fall prone, take 1d6 bludgeoning damage, 1d6 thunder damage, and become unconscious for 1 minute or until you receive damage from any source." + } +] diff --git a/src/assets/fumble-weapon.json b/src/assets/fumble-weapon.json new file mode 100644 index 0000000..4e928e2 --- /dev/null +++ b/src/assets/fumble-weapon.json @@ -0,0 +1,116 @@ +[ + { + "roll": "1-1", + "type": "both", + "description": "You are embarassed by your poor showing, but nothing remarkable happens.", + "effect": "You miss your attack." + }, + { + "roll": "2-5", + "type": "both", + "description": "You lose your combat footing, exposing yourself to your target.", + "effect": "Your target has advantage on their first attack roll against you next round." + }, + { + "roll": "6-9", + "type": "both", + "description": "You lose your combat footing, exposing yourself to your enemies.", + "effect": "Your enemies have advantage on their first attack roll against you next round." + }, + { + "roll": "10-14", + "type": "both", + "description": "You lose your combat footing, and have difficulty recovering.", + "effect": "Your enemies have advantage on their attack rolls against you until the end of your next turn." + }, + { + "roll": "15-19", + "type": "melee", + "description": "You get tangled with your enemy and fall over.", + "effect": "You are knocked prone and your movement is reduced to 0. Your target must succeed a DC 10 dexterity check or they are also knocked prone." + }, + { + "roll": "15-19", + "type": "ranged", + "description": "You spill your quiver.", + "effect": "You must pick up arrows individually from the ground using your 'environmental interaction', or the 'Use an Object' action to nock your bow." + }, + { + "roll": "20-29", + "type": "both", + "description": "You lose your balance while attacking.", + "effect": "You fall prone and your movement is reduced to 0." + }, + { + "roll": "30-39", + "type": "both", + "description": "As you attack your opponent you begin to fear that they are the superior combatant.", + "effect": "Disadvantage on your next attack roll against your target." + }, + { + "roll": "40-49", + "type": "both", + "description": "You miss an attack and gaze upon the chaos of the battle, causing your confidence to falter.", + "effect": "Disadvantage on your next attack roll against any target." + }, + { + "roll": "50-59", + "type": "both", + "description": "You lose your grip as you attack.", + "effect": "Roll a DC 10 Dexterity Check, on failure you drop your weapon at your feet." + }, + { + "roll": "60-69", + "type": "melee", + "description": "The weapon slips from your hand as you attack.", + "effect": "Roll a DC 10 Dexterity Check, on failure you throw your weapon into your enemy's space. DM determines where the item is thrown on large sized or greater creatures." + }, + { + "roll": "60-69", + "type": "ranged", + "description": "Your ammunition gets lodged in its container.", + "effect": "You must use an action to organize the ammunition in its case before you can make another ranged attack." + }, + { + "roll": "70-79", + "type": "melee", + "description": "You lunge past an enemy exposing yourself to his attack.", + "effect": "Enemy you were attacking is able to use their reaction to perform and attack of opportunity." + }, + { + "roll": "70-79", + "type": "ranged", + "description": "Your missile startles your allies near your target.", + "effect": "the target can perform an opportunity attack on any ally within melee range." + }, + { + "roll": "80-84", + "type": "both", + "description": "Missing what you thought was a critical blow causes you to panic.", + "effect": "End your current turn and you are surprised until the end of your next turn." + }, + { + "roll": "85-89", + "type": "both", + "description": "You attack wildly and lose track of the fight around you.", + "effect": "End your turn and move to the bottom of the initiative order at the start of the next round." + }, + { + "roll": "90-94", + "type": "both", + "description": "You lose your footing while attacking and fall to the ground bumping your head.", + "effect": "You fall prone. Roll a DC 10 constitution save, on failure you take 1d6 damage and are knocked unconscious for 1 minute or until you receive damage from any source. On success take half damage and you remain conscious." + }, + { + "roll": "95-99", + "type": "both", + "description": "You lose your footing while attacking and fall head first.", + "effect": "You fall prone. Roll a DC 15 constitution save, on failure you take 2d6 damage and are knocked unconscious for 1 minute or until you receive damage from any source. On success take half damage and you remain conscious." + }, + { + "roll": "100-100", + "type": "both", + "description": "You lose your footing while attacking and slam your head into the ground.", + "effect": "You fall prone, take 3d6 damage, and become unconscious for 1 minute or until you receive damage from any source." + } +] diff --git a/src/index.html b/src/index.html index 2b35040..a40a9cb 100644 --- a/src/index.html +++ b/src/index.html @@ -2,13 +2,27 @@ - Critter + Fifth Edition Critter + + + + +
+
+ + Written by Rob Allen | made available by the good graces of the questionably fine folks at + Questionably Qualified | report problems to or shower praise on: + master.robbiewan@gmail.com | Code for site on + GitHub. + +


+
diff --git a/src/styles.css b/src/styles.css index 90d4ee0..07cfc65 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1 +1,15 @@ /* You can add global styles to this file, and also import other style files */ +@import "~bootstrap/dist/css/bootstrap.min.css"; +@import "~font-awesome/css/font-awesome.css"; + +body { + font-size: 10pt; +} + +.main-center-div { + width:60%; + margin-left:20%; + background-color: #ffffff; + padding: 15px; + min-height: 100vh; +} diff --git a/src/typings.d.ts b/src/typings.d.ts index ef5c7bd..b58fa33 100644 --- a/src/typings.d.ts +++ b/src/typings.d.ts @@ -3,3 +3,8 @@ declare var module: NodeModule; interface NodeModule { id: string; } + +declare module '*.json' { + const value: any; + export default value; +}