├── .eslintignore ├── .eslintrc.js ├── .github ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── BUG_REPORT.md │ └── FEATURE_REQUEST.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .travis.yml ├── .vimrc ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── package-lock.json ├── package.json ├── src ├── common │ ├── globals.ts │ ├── log.ts │ ├── scripts.ts │ ├── services │ │ ├── settingsService.ts │ │ └── updateService.ts │ └── types │ │ └── files.d.ts ├── main │ └── main.ts └── renderer │ ├── app.tsx │ ├── assets │ └── images │ │ └── d20_transparent.png │ ├── components │ ├── appContainer.tsx │ ├── campaign.tsx │ ├── characterScreen.tsx │ ├── characterScreen │ │ ├── actionTable.tsx │ │ ├── characterSheet.tsx │ │ ├── flagInputBox.tsx │ │ ├── labeledTextbox.tsx │ │ ├── savesPanel.tsx │ │ ├── scoreBar.tsx │ │ └── skillsPanel.tsx │ ├── cities.tsx │ ├── layout │ │ ├── footer.tsx │ │ ├── markdown.tsx │ │ ├── sidebar.tsx │ │ ├── slider.tsx │ │ └── titlebar.tsx │ ├── modals │ │ ├── aboutModal.tsx │ │ ├── changelogModal.tsx │ │ └── licenseModal.tsx │ ├── settings.tsx │ ├── welcome.tsx │ └── worldMaps.tsx │ ├── css │ └── animate.min.css │ └── scss │ ├── _sections.scss │ ├── _variables.scss │ ├── app.scss │ ├── characterSheet.scss │ ├── modal.scss │ ├── sidebar.scss │ ├── slider.scss │ ├── titlebar.scss │ └── welcome.scss ├── static ├── icon.ico └── icon.png ├── tsconfig.json └── webpack.config.js /.eslintignore: -------------------------------------------------------------------------------- 1 | *.css 2 | *.scss 3 | *.png 4 | *.jpg 5 | *.config.js -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "browser": true, 4 | "es6": true, 5 | "node": true 6 | }, 7 | "parser": "@typescript-eslint/parser", 8 | "parserOptions": { 9 | "project": "tsconfig.json", 10 | "sourceType": "module" 11 | }, 12 | "plugins": [ 13 | "@typescript-eslint", 14 | "@typescript-eslint/tslint", 15 | "react-hooks" 16 | ], 17 | "rules": { 18 | "@typescript-eslint/adjacent-overload-signatures": "error", 19 | "@typescript-eslint/array-type": "error", 20 | "@typescript-eslint/ban-types": "off", 21 | "@typescript-eslint/class-name-casing": "error", 22 | "@typescript-eslint/consistent-type-assertions": "off", 23 | "@typescript-eslint/consistent-type-definitions": "off", 24 | "@typescript-eslint/explicit-member-accessibility": [ 25 | "error", 26 | { 27 | "accessibility": "explicit" 28 | } 29 | ], 30 | "@typescript-eslint/indent": [ 31 | "error", 32 | 4, 33 | { 34 | "SwitchCase": 1, 35 | "FunctionDeclaration": { 36 | "parameters": "first" 37 | }, 38 | "FunctionExpression": { 39 | "parameters": "first" 40 | } 41 | } 42 | ], 43 | "@typescript-eslint/member-delimiter-style": [ 44 | "off", 45 | "error", 46 | { 47 | "multiline": { 48 | "delimiter": "none", 49 | "requireLast": true 50 | }, 51 | "singleline": { 52 | "delimiter": "semi", 53 | "requireLast": false 54 | } 55 | } 56 | ], 57 | "@typescript-eslint/member-ordering": "error", 58 | "@typescript-eslint/no-empty-function": "error", 59 | "@typescript-eslint/no-empty-interface": "off", 60 | "@typescript-eslint/no-explicit-any": "off", 61 | "@typescript-eslint/no-misused-new": "error", 62 | "@typescript-eslint/no-namespace": "error", 63 | "@typescript-eslint/no-parameter-properties": "off", 64 | "@typescript-eslint/no-use-before-declare": "off", 65 | "@typescript-eslint/no-var-requires": "off", 66 | "@typescript-eslint/prefer-for-of": "error", 67 | "@typescript-eslint/prefer-function-type": "error", 68 | "@typescript-eslint/prefer-namespace-keyword": "error", 69 | "@typescript-eslint/quotes": [ 70 | "error", 71 | "single", 72 | { 73 | "avoidEscape": true 74 | } 75 | ], 76 | "@typescript-eslint/semi": [ 77 | "off", 78 | null 79 | ], 80 | "@typescript-eslint/triple-slash-reference": "error", 81 | "@typescript-eslint/type-annotation-spacing": "error", 82 | "@typescript-eslint/unified-signatures": "error", 83 | "arrow-body-style": "error", 84 | "arrow-parens": [ 85 | "error", 86 | "always" 87 | ], 88 | "camelcase": "off", 89 | "capitalized-comments": "error", 90 | "complexity": "off", 91 | "constructor-super": "error", 92 | "curly": "off", 93 | "dot-notation": "off", 94 | "eol-last": "error", 95 | "eqeqeq": [ 96 | "error", 97 | "smart" 98 | ], 99 | "guard-for-in": "off", 100 | "id-blacklist": [ 101 | "error", 102 | "any", 103 | "Number", 104 | "number", 105 | "String", 106 | "string", 107 | "Boolean", 108 | "boolean", 109 | "Undefined", 110 | ], 111 | "id-match": "error", 112 | "import/order": "off", 113 | "linebreak-style": ["error", "unix"], 114 | "max-classes-per-file": "off", 115 | "max-len": [ 116 | "error", 117 | { 118 | "code": 160 119 | } 120 | ], 121 | "new-parens": "error", 122 | "no-bitwise": "off", 123 | "no-caller": "error", 124 | "no-cond-assign": "error", 125 | "no-console": "off", 126 | "no-debugger": "error", 127 | "no-empty": "error", 128 | "no-eval": "error", 129 | "no-fallthrough": "off", 130 | "no-invalid-this": "off", 131 | "no-multiple-empty-lines": [ 132 | "error", 133 | { 134 | "max": 4 135 | } 136 | ], 137 | "no-new-wrappers": "error", 138 | "no-shadow": [ 139 | "error", 140 | { 141 | "hoist": "all" 142 | } 143 | ], 144 | "no-throw-literal": "error", 145 | "no-trailing-spaces": "error", 146 | "no-undef-init": "off", 147 | "no-underscore-dangle": "error", 148 | "no-unsafe-finally": "error", 149 | "no-unused-expressions": "error", 150 | "no-unused-labels": "error", 151 | "no-var": "error", 152 | "object-shorthand": "error", 153 | "one-var": [ 154 | "error", 155 | "never" 156 | ], 157 | // "prefer-arrow/prefer-arrow-functions": "error", 158 | "prefer-const": "error", 159 | "quote-props": "off", 160 | "radix": "error", 161 | "react-hooks/rules-of-hooks": "error", // Checks rules of Hooks 162 | "react-hooks/exhaustive-deps": "warn", // Checks effect dependencies 163 | "space-before-function-paren": [ 164 | "error", 165 | { 166 | "anonymous": "never", 167 | "asyncArrow": "always", 168 | "named": "never" 169 | } 170 | ], 171 | "spaced-comment": "error", 172 | "use-isnan": "error", 173 | "valid-typeof": "off", 174 | "@typescript-eslint/tslint/config": [ 175 | "error", 176 | { 177 | "rules": { 178 | "jsdoc-format": true, 179 | "no-reference-import": true, 180 | "one-line": [ 181 | true, 182 | "check-catch", 183 | "check-else", 184 | "check-finally", 185 | "check-open-brace", 186 | "check-whitespace" 187 | ] 188 | } 189 | } 190 | ] 191 | } 192 | }; 193 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting @incomingstick. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [https://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: https://contributor-covenant.org 46 | [version]: https://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to the project 2 | 3 | So you want to know how you can help?? You've come to the right place! 4 | Below you will find many ways you can help. 5 | 6 | ## Contributing Issues 7 | 8 | ### Before Submitting an Issue 9 | First, please do a search in open issues to see if the issue or feature request has already been filed. If there is an issue add your comments to this issue. 10 | 11 | ## Writing Good Bug Reports and Feature Requests 12 | 13 | File a single issue per problem and feature request, do not file combo issues. 14 | 15 | The more information you can provide, the more likely someone will be successful reproducing the issue and finding a fix. Therefore: 16 | 17 | * Provide reproducible steps, what the result of the steps was, and what you would have expected. 18 | * Description of what you expect to happen 19 | * Animated GIFs 20 | * Code that demonstrates the issue 21 | * Version of OpenRPG 22 | * Errors printed to the command line 23 | 24 | ## Contributing Fixes 25 | First and foremost check the [Issues](https://github.com/incomingstick/OpenRPG/issues) page to see what needs to be done. 26 | Once you're ready to start programming see the Programming Standards section. 27 | 28 | I have broken the goals and needs by the "Difficulty" of the task. Beginner tasks 29 | will be more specific, such as working on a certain function or method. Intermediate tasks 30 | will be a little broader, such as creating a specific class or utility. Advanced 31 | tasks will be major milestones that need to be completed. And should only be attempted 32 | by someone that understand the language. 33 | 34 | ## Pull Request 35 | 36 | For something to be considered for merging into master it must be 37 | submitted as a Pull Request to a current developement branch first. 38 | Pull requests must follow the format found in the [Issue Template](https://github.com/incomingstick/OpenRPG/blob/patch-v0.3.0-dev/.github/ISSUE_TEMPLATE.md) 39 | file. 40 | 41 | ## Programming Standards 42 | 43 | ### File Naming 44 | ````c++ 45 | cppFile.cpp 46 | headerFile.h 47 | ```` 48 | 49 | ### Code Blocks 50 | ````c++ 51 | /** 52 | * @desc function description here 53 | * @param arg bar - what purpose this arg will serve 54 | * @return function - what does the function return and why 55 | */ 56 | function Class::foo(arg bar) { 57 | // do stuff 58 | // 4 space tabbed indent 59 | } 60 | ```` 61 | 62 | ### Function and Variable Naming 63 | ````c++ 64 | /** 65 | * @desc function description here 66 | * @param arg variableName - what purpose this arg will serve 67 | * @return function - what does the function return and why 68 | */ 69 | function Class::my_function_name(arg variableName) { 70 | // do stuff 71 | } 72 | ```` 73 | 74 | ### Class Naming 75 | ````c++ 76 | class ClassName { 77 | private: 78 | // private variables and functions here 79 | 80 | public: 81 | // public variables and functions here 82 | }; 83 | ```` 84 | 85 | ### Switch Statements 86 | ````c++ 87 | /* this should be the standard method for 88 | writing a switch statement unless switch 89 | scoping is required */ 90 | switch(c) { 91 | case 'a': { 92 | // case a code here 93 | } break; 94 | 95 | case 'b': { 96 | // case b code here 97 | } break; 98 | 99 | case 'c': { 100 | // case c code here 101 | } break; 102 | 103 | default: { 104 | // catch all code here 105 | } 106 | } 107 | ```` -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/BUG_REPORT.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 4. Run command '....' 18 | 3. Scroll down to '....' 19 | 5. See error 20 | 21 | **Expected behavior** 22 | A clear and concise description of what you expected to happen. 23 | 24 | **Screenshots** 25 | If applicable, add screenshots or gifs to help explain your problem. 26 | 27 | **Desktop (please complete the following information):** 28 | - OS*: [e.g. iOS] 29 | - Browser: [e.g. chrome, safari] 30 | - Version*: [e.g. 22] 31 | 32 | *required 33 | 34 | **Additional context** 35 | Add any other context about the problem here. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | Please describe the change as necessary. 3 | If it's a feature or enhancement please be as detailed as possible. 4 | If it's a bug fix, please link the issue that it fixes or describe the bug in as much detail. 5 | 6 | 7 | ## Specific Changes proposed 8 | Please list the specific changes involved in this pull request. 9 | 10 | ## Requirements Checklist 11 | - [ ] Feature implemented | Bug fixed 12 | - [ ] Reviewed by a Core Contributor 13 | - [ ] Reviewed by: @ 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Compiled Static libraries 17 | *.lai 18 | *.la 19 | *.a 20 | *.lib 21 | 22 | # Executables 23 | *.exe 24 | *.out 25 | *.app 26 | 27 | # Project generated files 28 | Makefile.* 29 | config.h 30 | *_exports.h 31 | *.log 32 | 33 | # Folders and other files 34 | exports/* 35 | [Dd]ebug/* 36 | .settings/* 37 | .project 38 | .cproject 39 | *.out 40 | [Bb]in/* 41 | *.cbp 42 | *.depend 43 | [Bb]uild/* 44 | [Bb]uild32/* 45 | [Bb]uild64/* 46 | [Dd]ist/* 47 | .vscode 48 | [Gg]ifs/* 49 | node_modules/* 50 | *.un~ 51 | *.un 52 | 53 | # packages and archive files 54 | *.zip 55 | *.tar 56 | *.tar.* 57 | *.swp 58 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | package.json 2 | package-lock.json 3 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "always", 3 | "bracketSpacing": true, 4 | "endOfLine": "lf", 5 | "jsxBracketSameLine": true, 6 | "jsxSingleQuote": true, 7 | "printWidth": 120, 8 | "quoteProps": "as-needed", 9 | "trailingComma": "none", 10 | "semi": true, 11 | "singleQuote": true, 12 | "tabWidth": 4, 13 | "useTabs": false 14 | } 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 13.7.0 3 | 4 | os: 5 | - linux 6 | - osx 7 | - windows 8 | 9 | dist: trusty 10 | 11 | notifications: 12 | email: false 13 | 14 | addons: 15 | apt: 16 | packages: 17 | - rpm 18 | 19 | jobs: 20 | include: 21 | - os: linux 22 | stage: Publish 23 | script: 24 | - npm run release 25 | - os: osx 26 | stage: Publish 27 | script: 28 | - npm run release -- --mac 29 | - os: windows 30 | stage: Publish 31 | script: 32 | - npm run release -- --win 33 | 34 | install: 35 | - npm install 36 | 37 | script: 38 | - npm run compile -------------------------------------------------------------------------------- /.vimrc: -------------------------------------------------------------------------------- 1 | set tabstop=4 2 | set softtabstop=4 3 | set shiftwidth=4 4 | set noexpandtab 5 | 6 | set colorcolumn=80 7 | highlight ColorColumn ctermbg=darkgray 8 | 9 | let &path.="include," 10 | 11 | set makeprg=./build.sh 12 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | All notable changes to this project will be documented in this file. 2 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 3 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). However, note that all pre-v0.5.0 releases will have the suffix "-dev" 4 | 5 | ## [Unreleased] 6 | ### Added 7 | - rpm package support 8 | - Added visible boolean member to TitlebarMenu type to allow for conditional rendering of menu items. (i.e hide "Check for Updates..." by setting visible to false on Linux machines because electron-updater does not work on Linux) 9 | - "New Character" option added to Titlebar under File > New Character 10 | - Re-open to the character you last had selected 11 | - View menu with a Reload Window menu item and menu items matching the Sidebar 12 | - New custom Slider component 13 | - New Campaign and Character notes text field in Character Sheets 14 | 15 | ### Changed 16 | - Settings removed from Sidebar and added to Titlebar under File > Settings 17 | - Character sheet split into pages with sliding animation 18 | - Pulled the action/attack table into it's own component `ActionTable` 19 | - `src/renderer/scss/main.scss` renamed to `src/renderer/scss/app.scss` 20 | 21 | ### Fixed 22 | - AutoUpdater should now recognize pre-releases! 23 | - Modals now open exlusively, i.e you cannot open the Changelog and the License at the same time 24 | - List of open character sheets now saved when a new character is added or a tab is closed 25 | 26 | 27 | ### Removed 28 | - Dependancy `uglifyjs-webpack-plugin` marked depricated 29 | - Dependancy `@babel/polyfill` marked depricated 30 | - Dependancy `electron-compile` marked depricated 31 | - Dependancy `electron-prebuilt-compile` marked depricated 32 | - Dependancy `git-validate` no longer needed 33 | - Dependancy `jquery` no longer needed 34 | 35 | ## [v0.5.0] - 2019-11-25 36 | ### Added 37 | - ZoomLevel setting that allows you to adjust the zoom level of the window. The original size is 0 and each increment above (e.g. 1) represents zooming 20% larger 38 | - You can now open multiple character sheets 39 | - Reload last state when you close/reopen OpenRPG, this includes the character sheets you had open 40 | 41 | ### Changed 42 | - Full Divergence from the OpenRPG core repo. This changelog will now JUST handle changes and updates to the OpenRPG Desktop App. All of the below release information (<= v0.4.4-dev) is in reference to [OpenRPG Core](https://github.com/incomingstick/OpenRPG) 43 | - Moved the `electron-gui` branch of the Core repository into it's own repo (this (meta, I know!! xD)) 44 | - Swapped from Javascript and pure HTML to Typescript and React JSX, using Webpack to build the Electron app 45 | - Restructured the filesystem to better adhear to Webpack/React standards 46 | 47 | ### Fixed 48 | - Relative links in this file now point to GitHub! 49 | 50 | ## [v0.4.4-dev] - 2017-11-05 51 | ### Added 52 | - Windows build script: build.bat 53 | - A `help` or `h` command in the orpg console `orpg >` 54 | - A Code of Conduct! See [.github/CODE_OF_CONDUCT.md](https://github.com/incomingstick/OpenRPG-App/tree/master/.github/CODE_OF_CONDUCT.md) 55 | 56 | ### Changed 57 | - Put back the Linux Clang 5.0 build that was hidden in the last patch 58 | - TravisCI builds on OSX will do a brew update, as sometimes they were not up to date for the build we were trying to do... 59 | 60 | ### Removed 61 | - All Unix/POSIX headers to allow for compilation on Windows 62 | - Some redundant headers 63 | - The `get_console_width()` and `get_console_height()` functions 64 | - The TODO's list from the Contributing file, [.github/CONTRIBUTING.md](https://github.com/incomingstick/OpenRPG-App/tree/master/.github/CONTRIBUTING.md) 65 | 66 | 67 | ## [v0.4.3-dev] - 2017-10-14 68 | ### Removed 69 | - TravisCI was failing internally when trying to use Clang 5.0 through the LLVM toolchain on Linux via the truster repository. Specifically it would fail during an apt call, something outside of our control, so we simple will hide this test for now. 70 | 71 | 72 | ## [v0.4.2-dev] - 2017-06-02 73 | ### Added 74 | - A whole suite of new TravisCI builds for testing GCC, LLVM, and Clang compilers on multiple platforms 75 | 76 | ### Changed 77 | - The build compiler is set to c++14 and the individual modules have `CXX_STANDARD` set to 11 in CMake 78 | 79 | 80 | ## [v0.4.1-dev] - 2017-05-31 81 | ### Fixed 82 | - A fatal bug from running `make check` in the Roll Parser test that was calling a function that no longer existed... 83 | 84 | 85 | ## [v0.4.0-dev] - 2017-05-31 86 | ### Added 87 | - `INCLUDE` rule for our `include/` folder in CMakeLists.txt to install the headers with our library when running `make install` 88 | - `build.sh` support for "darwin" (OSX) and "cygwin" builds 89 | - Install rules for TravisCI in .travis.yml 90 | - .gitignore rules updated to block extra api and Rust stuff thanks to [@hurnhu](https://github.com/hurnhu) as well as some web files/folders 91 | - A new constructor in `NameGenerator` that accepts two `std::string`'s, race and gender 92 | - The Character library now contains a constant array, `levels[]`, with 20 integers that contain the experince values used when determining if you should level up 93 | - The traditional alignment grid is expressed via the `Alignment` enum in the Character library 94 | - All of the 5e languages are expressed via the `Language` enum in the Character library 95 | - The Charcter library contains a small `enum Gender` 96 | - An enum exists within the Charcter library that contains the 5e sizes 97 | - Ability scores that are traditionally used in D&D are allocated via a struct called `Ability` 98 | - The 5e Skill list is expressed via the `Skills` struct 99 | - The concept of 5e vision via `enun VisionType` and `struct Vision` in the Character library 100 | - A function `int gen_stat()` that generates an array of stats > 1 && < 20 in the Character library 101 | - A function `int modifier(...)` that returns an integer representation of the passed ability modifier defined as `(abil - 10) / 2` exactly 102 | - Note, this is intended to always round down. Data loss is acceptable, as it is a floor function 103 | - A `Character` class that is the general outline for a 5e character sheet, with a few additions that a programmer may find handy, such as a `static const int ID = 0x0000` 104 | - "Race" classes that are children of the `Character` class that make use of the `Ability` struct to apply racial bonuses: 105 | - `class Human : public Character {...}` 106 | - `class Dwarf : public Character {...}` 107 | - `class HillDwarf : public Dwarf {...}` 108 | - A helper class `CharacterFactory` that helps generate a `Character` object that contains the following functions: 109 | - `Character* NewCharacter(Ability ab = ability_struct())` 110 | - `Character* NewCharacter(int identifier)` 111 | - `Character* NewCharacter(int identifier, Ability ab)` 112 | - `void reset()` 113 | - `std::vector current_options()` 114 | - `bool has_options()` 115 | - `void select_option(int index)` 116 | - `int current_id()` 117 | - Tons of new namelists added to `data/names/` for `NameGenerator` to use thanks to [Hen](hwangcodes@gmail.com): 118 | - goliath/female.lst 119 | - goliath/last.lst 120 | - goliath/male.lst 121 | - halfling/female.lst 122 | - halfling/last.lst 123 | - halfling/male.lst 124 | - kor/female.lst 125 | - kor/male.lst 126 | - minotaur/female.lst 127 | - minotaur/last.lst 128 | - minotaur/male.lst 129 | - tiefling/female.lst 130 | - tiefling/last.lst 131 | - tiefling/male.lst 132 | - aarakocra.lst 133 | - changeling.lst 134 | - warforged.lst 135 | - An API can be built using Rust that interfaces with our compiled binaries thanks to [@hurnhu](https://github.com/hurnhu): 136 | - api/Cargo.toml 137 | - api/main.rs 138 | - api/Rocket.toml 139 | - Discord info in the `CONTRIBUTING.md` file instead of my old tumblr blog 140 | 141 | ### Changed 142 | - Renamed some header guards for better consistancy across the library 143 | - Moved C++ standard back to C++14 144 | - Improved `openrpg -n` call to `NameGenerator` to account for gender and warn when too few arguments are given 145 | - Better error reporting when invalid syntax is provided to `roll` 146 | - Better error reporting when invalid syntax is provided to `name-generator` as well as when it is unable to locate a data file 147 | - Structure of `include/` to better mirror that of other well known libraries, leaning heavily on Boost specifically 148 | - character.h == redefined 149 | - die.h -> roll/die.h 150 | - names.h == redefined 151 | - openrpg.h ++ added 152 | - opt-parser.h -> core/opt-parser.h 153 | - roll-parser.h -> roll/roll-parser.h 154 | - roll.h ++ added 155 | - utils.h -> include/core/utils.h 156 | 157 | ### Fixed 158 | - Segfault caused when anything other than exact syntax is provided, i.e: `$ roll hahahaha -v 2d10+6` 159 | - Errors when a only a race is provided to `name-generator` 160 | 161 | ### Removed 162 | - Cleaned up some CMakeLists.txt logic of irrelevant header logic 163 | - Unnecessary and platform dependant headers project wide 164 | 165 | 166 | ## [v0.3.0-dev] - 2017-04-24 167 | ### Added 168 | - We have our own custom option parser (command line argument parser) fully defined in its own opt-parser header, designed to replace the platform dependant `` 169 | - include/opt-parser.h 170 | - Version number badge located at the top of the README.md 171 | - Our CMake build now has a build type `CMAKE_BUILD_TYPE` 172 | - A new config.h.in preprocessor defition for the build type, pulled fromt the variable `CMAKE_BUILD_TYPE` 173 | - Windows `WIN32` preprocessor checks, because now we can build on Windows, kinda! 174 | - Utils library now has a `gcd(...)` function that computes the greatest common divisor of int args a and b 175 | - Open Gaming License (OGL) located in a new data directory 176 | - data/LICENSE 177 | 178 | ### Changed 179 | - Discord badge color in README.md from blue to 7289da (discords official purple, I [@incomingstick](http://github.com/incomingstick)) think...) 180 | - ASSET_LOC in config.h.in pulls the CMake `DATA_DIR` variable 181 | - Major project filesystem restructuring as noted below: 182 | - Moved the `src/tests/` folder out of `src/ 183 | - src/tests/CMakeLists.txt -> tests/CMakeLists.txt 184 | - src/tests/generator-test.cpp -> src/tests/name-generator-test.cpp 185 | - src/tests/roll-parser-test.cpp -> tests/roll-parser-test.cpp 186 | - Moved all header files into a new `include/` folder structure 187 | - src/lib/utils.h -> include/utils.h 188 | - src/lib/modules/character.h -> include/character.h 189 | - src/lib/modules/names.h -> include/names.h 190 | - src/lib/modules/die.h -> include/die.h 191 | - src/lib/modules/roll-parser.h -> include/roll-parser.h 192 | - Restructured the `src/` folder to remove unnecessary folder layers 193 | - src/lib/utils.cpp -> src/utils.cpp 194 | - src/lib/modules/character/CMakeLists.txt -> src/character/CMakeLists.txt 195 | - src/lib/modules/character/character-generator.cpp -> src/character/character-generator.cpp 196 | - src/lib/modules/character/character.cpp -> src/character/character.cpp 197 | - src/lib/modules/names/CMakeLists.txt -> src/names/CMakeLists.txt 198 | - src/lib/modules/names/names-generator.cpp -> src/names/name-generator.cpp 199 | - src/lib/modules/names/names.cpp -> src/names/names.cpp 200 | - src/lib/modules/roll/CMakeLists.txt -> src/roll/CMakeLists.txt 201 | - src/lib/modules/roll/names-generator.cpp -> src/roll/name-generator.cpp 202 | - src/lib/modules/roll/names.cpp -> src/roll/names.cpp 203 | - Moved all assests into a new `data/` folder structure 204 | - src/assets/banners/welcome_mat1 -> data/banners/welcome_mat1 205 | - src/assets/chatacter_sheets/ -> data/chatacter_sheets/ 206 | - src/assets/dwarf/female -> data/dwarf/female 207 | - src/assets/dwarf/last -> data/dwarf/last 208 | - src/assets/dwarf/male -> data/dwarf/male 209 | - Merged human namelists in a new data directory they were all merged, see Removed section below) 210 | - data/names/human/female 211 | - data/names/human/last 212 | - data/names/human/male 213 | - `NameGenerator` no longer checks for a relative assets folder, instead it checks for a predefind data folder when building 214 | - `roll` CLA's verbose and version V's swapped 215 | - "verbose" = 'v' 216 | - "version" = 'V' 217 | - `character-generator` CLA's verbose and version V's swapped 218 | - "verbose" = 'v' 219 | - "version" = 'V' 220 | 221 | ### Fixed 222 | - Syntax throught the codebase that could be updated to use things provided in C++11 223 | 224 | ### Removed 225 | - Due to folder restructuring, there was no need for some CMakeList.txt files! 226 | - src/lib/CMakeLists.txt 227 | - src/lib/modules/CMakeLists.txt 228 | - `NameGenerator` class constructor no longer calls for a gender string 229 | - Individual Human subrace namelists (they were all merged, see Changed section above) 230 | - src/assets/names/human/calishite/{female, last, male} 231 | - src/assets/names/human/chondathan/{female, last, male} 232 | - src/assets/names/human/damaran/{female, last, male} 233 | - src/assets/names/human/illuskan/{female, last, male} 234 | - src/assets/names/human/mulan/{female, last, male} 235 | - src/assets/names/human/rashemu/{female, last, male} 236 | - src/assets/names/human/shou/{female, last, male} 237 | - src/assets/names/human/truami/{female, last, male} 238 | 239 | 240 | ## [v0.2.1-dev] - 2017-02-25 241 | ### Fixed 242 | - Fatal bug that caused endless loop when running `roll`, always... oops 243 | 244 | 245 | ## [v0.2.0-dev] - 2017-02-18 246 | ### Added 247 | - Linux build scripts via `build.sh` 248 | - Header guards and autogeneration notes in config.h.in and the resulting config.h 249 | - The Names module now has a concept of subraces to allow for the reading of the human namelists 250 | - Added namelist Asset files for Humans thanks to [@bloodredyeti](https://github.com/bloodredyeti) 251 | - src/assets/names/human/calishite/{female, last, male} 252 | - src/assets/names/human/chondathan/{female, last, male} 253 | - src/assets/names/human/damaran/{female, last, male} 254 | - src/assets/names/human/illuskan/{female, last, male} 255 | - src/assets/names/human/mulan/{female, last, male} 256 | - src/assets/names/human/rashemu/{female, last, male} 257 | - src/assets/names/human/shou/{female, last, male} 258 | - src/assets/names/human/truami/{female, last, male} 259 | - First attempts at OSX building via .travis.yml and TravisCI 260 | - ExpressionTree class in the Roll module that will handle all of the heavy lifting for die math parsing (this is the muscle) 261 | - Two new `Character` class constructors that accept Ability and Skill structs 262 | - `Character` class accessor functions for each Ability score's respective modifier 263 | - A function called `passive_stat(...)` that accepts an int and computes what its "passive" value is, and we assume this int is the value of a 5e Skill 264 | - Allowing an extremely rudimentary character sheet to be printed of a `Character` class type via the `to_string()` function 265 | - Layout of what the general character generation process should look like via `character-generator` 266 | - Comments better defined in .github/CONTRIBUTING.md, and added stylizion guide for switch statements 267 | 268 | ### Changed 269 | - Renamed the Die library to the Roll Parser library 270 | - Pulled what was the `Die` class definitions out of die.cpp and put it into the die.h header file as its just so small, this allowed for the renaming of die.cpp to roll-parser.cpp 271 | - src/modules/roll/die.cpp -> src/modules/roll/roll-parser.cpp 272 | - Renamed roll.h to roll-parser.h 273 | - src/modules/roll/roll.h -> src/modules/roll/roll-parser.h 274 | - Renamed the Roll module test to the Roll Parser test 275 | - src/tests/roll-test.cpp -> src/tests/roll-parser-test.cpp 276 | - `openrpg` binary now links to the Names and Roll Parser libraries and no longer uses system calls to run those binaries 277 | - Improved `openrpg` command line argument warnings when taking invalid input and arguments, as well as when using the `orpg >` prompt 278 | - Improved `name-generator` command line argument warnings when taking invalid input and arguments 279 | - Minor warning improvements when `roll` is aborting 280 | - Character module now links to `roll-parser` and `names` libraries when linking during build time 281 | - Expanded the `Character` classes internals to include stats such as current health, max health, level, experience, etc. 282 | 283 | ### Fixed 284 | - `make install` should now properly grab include files 285 | 286 | ### Removed 287 | - Git ignore definition for config.h was added in v0.1.1 but was never removed from source, and now it has 288 | - src/lib/config.h 289 | - `int output(string log, int status)` from the Utils library 290 | - Warnings from the `NameGenerator` class when unable to read from a file 291 | 292 | 293 | ## [v0.1.1-dev] - 2017-02-12 294 | ### Changed 295 | - License changed from GNU/GPLv3+ to the OpenRPG Software License (OSL) - Version 1.0 296 | 297 | ### Fixed 298 | - Now preventing project generated such as Makefiles and config.h from being accidentally committed to the codebase 299 | 300 | ### Removed 301 | - Gutted use of Bison or Flex for a lexer, we will do the heavy lifting ourselves, however this release does not contain that muscle 302 | - src/lib/modules/roll/roll-parser.y 303 | - src/lib/modules/roll/roll-scanner.l 304 | 305 | 306 | ## [v0.1.0-dev] - 2017-01-31 307 | ### Added 308 | - Brand new website and small project branding at https://openrpg.io 309 | - Defined OpenRPGs goals as a library, and software, as well as laid out an initial v1.0 release goal in both README.md and .github/CONTRIBUTING.md 310 | - License information at the bottom of README.md 311 | - Discord badge located at the top of the README.md 312 | - TravisCI build badge located at the top of the README.md 313 | - .travis.yml file for webhooking TravisCI builds whenever we push to GitHub 314 | - Standardized exit codes across the project with flags defined in the Utils library within utils.h 315 | - Initial test files for the Roll module, called when running `make check` 316 | - src/lib/tests/roll-test.cpp 317 | - Utils library now offers a `random(...)` function to give us a standard way to get a random integer between two bounds 318 | - Siginificant overhaul of the Roll module, and first pass at using a lexer for better parsing 319 | - New src/lib/modules/roll-parser.y 320 | - New src/lib/modules/roll-parser.l 321 | - New src/lib/modules/roll.h 322 | - New command line arguments "positive" or 'p', and "sum-series" or 's' 323 | - A total of 16 additional preprocessor definitions for represending types of operations for die math 324 | - POS_FLAG and SUM_FLAG global boolean flag variables 325 | - `read_string(...)` function for flex and bison to parse in a string to yyi 326 | - `parse_node` struct for helping parse die math and a series of functions for building a parse tree 327 | - `character-generator` command and Character module classes and functions, including your standard tabletop Stat block as a struct, the 5e D&D skills list as a struct, and the `Character` class 328 | - src/lib/modules/character/CMakeLists.txt 329 | - src/lib/modules/character/character-generator.cpp 330 | - src/lib/modules/character/character.cpp 331 | - src/lib/modules/character/character.h 332 | - D&D 5e Character sheets as licensed in the OGL by WotC see src/assets/chatacter_sheets/ 333 | 334 | ### Changed 335 | - Clarified in README.md that the install location instructions are optional for building OpenRPG 336 | - Utils now builds as its own separate library, instead of building directly into the `openrpg` binary 337 | - Generator module renamed to Names module and links to the Utils library 338 | - src/lib/modules/generator/CMakeLists.txt -> src/lib/modules/names/CMakeLists.txt 339 | - src/lib/modules/generator/name-generator.cpp -> src/lib/modules/names/name-generator.cpp 340 | - src/lib/modules/generator/generator.cpp -> src/lib/modules/names/names.cpp 341 | - src/lib/modules/generator/generator.h -> src/lib/modules/names/names.h 342 | - Renamed a couple of functions in the Utils library to better align with what they do 343 | - load_file(...) -> file_to_string(...) 344 | - verbose(...) -> output(...) 345 | - Die module converted to using the Utils libraries provided `random(...)` function, as noted above 346 | - src/lib/modules/roll/CMakeLists.txt searches for Bison and Flex to output parser and scanner files for the Roll module 347 | - `Die` is pulled out into its own library 348 | 349 | ### Fixed 350 | - CMake Legacy Cygwin errors hidden when using Cygwin to compile with GNU compilers 351 | 352 | 353 | ## [v0.0.3-dev] - 2017-01-19 354 | ### Added 355 | - Install location `-DCMAKE_INSTALL_PREFIX=/desired/install/location` instructions for CMake in README.md 356 | - `src/lib/modules/CMakeLists.txt` that sets output directories and addes the generator and roll directories to the build tree ([@ShinyHobo](https://github.com/ShinyHobo)) 357 | - `generator` command and Generator module classes and functions, including the `NameGenerator` class, and `make_name()`, `make_first()`, `make_last()` functions. Also its CMake build rules. 358 | - src/lib/modules/generator/CMakeLists.txt 359 | - src/lib/modules/generator/name-generator.cpp 360 | - src/lib/modules/generator/generator.cpp 361 | - src/lib/modules/generator/generator.h 362 | - `roll` command and Roll module classes and functions, including a basic parser of "die math" (i.e 1d6+1), and the `Die` class with the `roll(...)` functions. 363 | - src/lib/modules/roll/CMakeLists.txt 364 | - src/lib/modules/roll/roll.cpp 365 | - src/lib/modules/roll/die.cpp 366 | - src/lib/modules/roll/die.h 367 | - More preprocessor defines in config.h.in including `VERSION`, `AUTHOR`, `COPYRIGHT`, and `ASSET_LOC` 368 | - Parsing of arguments via a `parse_args(...)` function called at the start of each programs main function 369 | - `bool QUIET_FLAG` and `bool VB_FLAG` in the Utils library and defaulting both to `false` 370 | - `print_version_flag()` and `print_help_flag()` functions that adhear to the GNU guidelines for help and version arguments 371 | - `bool print_file(std::string file)` to the Utils library that prints the text contents of the given file 372 | - `int verbose(string log, int status)` to the Utils library that outputs the log string to `stderr` if `VB_FLAG` is set 373 | - `int parse_input(string in)` to the Utils library that parses text input into the console and determines the appropriate response/action such as calling `roll`, or `generator`, from another process 374 | - `TESTING_FLAG` and `TESTING_ASSET_LOC` preprocessor definitions for help distinguishing when testing 375 | - src/lib/config.h from CMake output of config.h.in saved with source ([@ShinyHobo](https://github.com/ShinyHobo)) 376 | 377 | ### Changed 378 | - Made .github/PULL_REQUEST_TEMPLATE.md more concise 379 | - Renamed `src/main.cpp` -> `src/openrpg.cpp` 380 | - Utils `parse(...)` to help the roll module to handle addition and subtraction of all standard D&D dice in additon to D2 and D30 ([@ShinyHobo](https://github.com/ShinyHobo)) 381 | - Moved the `assets/` folder into the `src/` folder ([@ShinyHobo](https://github.com/ShinyHobo)) 382 | - assets/banners/welcome_mat1 -> src/assets/banners/welcome_mat1 383 | - assets/names/dwarf/female -> src/assets/names/dwarf/female 384 | - assets/names/dwarf/last -> src/assets/names/dwarf/last 385 | - assets/names/dwarf/male -> src/assets/names/dwarf/male 386 | - Linking to Generator and Roll modules when building openrpg so we don't have to call system commands from ([@ShinyHobo](https://github.com/ShinyHobo)) 387 | - Building with C++11 as a standard across the project ([@ShinyHobo](https://github.com/ShinyHobo)) 388 | 389 | ### Fixed 390 | - consistant commenting for file headings 391 | - Typos in CMakeLists.txt 392 | - `make check` can now properly be run prior to `make install` 393 | 394 | 395 | ### Removed 396 | - Git CMake package hook as there is no current need for our software to understand its own git versioning 397 | - Post `openrpg` CMake build target that copied the assets folder after building 398 | 399 | 400 | ## [v0.0.2-dev] - 2017-01-08 401 | ### Added 402 | - LICENSE (GNU General Public License, version 3) 403 | - README.md containing a short description and build, integrity check, and install instructions 404 | - GitHub integration files to help make contributing, bug reporting, and pull requests just a little easier 405 | - .gitignore 406 | - .github/CONTRIBUTING.md 407 | - .github/ISSUE_TEMPLATE.md 408 | - .github/PULL_REQUEST_TEMPLATE.md 409 | - Initial CMake build files, build targets for `openrpg` as well as rules for `make install` 410 | - CMakeLists.txt 411 | - config.h.in that generates src/lib/config.h 412 | - Building with C++14 as a standard across the project 413 | - Initial test files for the Generator module and rules for `make check` 414 | - src/tests/CMakeLists.txt 415 | - src/tests/generator-test.cpp 416 | - The `openrpg` command's main C++ source file 417 | - src/main.cpp 418 | - A utilities modules to help with building functions project wide, including file loading, getting console dimensions, and reading safer input from a user 419 | - src/lib/utils.cpp 420 | - src/lib/utils.h 421 | - Added namelist Asset files for Dwarfs 422 | - src/assets/names/dwarf/female 423 | - src/assets/names/dwarf/last 424 | - src/assets/names/dwarf/male 425 | - The `openrpg` command welcome banner 426 | - src/assets/banners/welcome_mat1 427 | 428 | [Unreleased]: https://github.com/incomingstick/OpenRPG-App/compare/v0.5.0...master 429 | [v0.5.0]: https://github.com/incomingstick/OpenRPG-App/releases/tag/v0.5.0 430 | [v0.4.4-dev]: https://github.com/incomingstick/OpenRPG/compare/v0.4.3-dev...v0.4.4-dev 431 | [v0.4.3-dev]: https://github.com/incomingstick/OpenRPG/compare/v0.4.2-dev...v0.4.3-dev 432 | [v0.4.2-dev]: https://github.com/incomingstick/OpenRPG/compare/v0.4.1-dev...v0.4.2-dev 433 | [v0.4.1-dev]: https://github.com/incomingstick/OpenRPG/compare/v0.4.0-dev...v0.4.4-dev 434 | [v0.4.0-dev]: https://github.com/incomingstick/OpenRPG/compare/v0.3.0-dev...v0.4.0-dev 435 | [v0.3.0-dev]: https://github.com/incomingstick/OpenRPG/compare/v0.2.1-dev...v0.3.0-dev 436 | [v0.2.1-dev]: https://github.com/incomingstick/OpenRPG/compare/v0.2.0-dev...v0.2.1-dev 437 | [v0.2.0-dev]: https://github.com/incomingstick/OpenRPG/compare/v0.1.1-dev...v0.2.0-dev 438 | [v0.1.1-dev]: https://github.com/incomingstick/OpenRPG/compare/v0.1.0-dev...v0.1.1-dev 439 | [v0.1.0-dev]: https://github.com/incomingstick/OpenRPG/compare/v0.0.3-dev...v0.1.0-dev 440 | [v0.0.3-dev]: https://github.com/incomingstick/OpenRPG/compare/v0.0.2-dev...v0.0.3-dev 441 | [v0.0.2-dev]: https://github.com/incomingstick/OpenRPG/tree/v0.0.2-dev -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | OpenRPG Software License - Version 1.0 - February 10th, 2017 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | 25 | --- 26 | 27 | OPEN GAME LICENSE Version 1.0a 28 | 29 | THIS LICENSE IS APPROVED FOR GENERAL USE. PERMISSION TO DISTRIBUTE THIS 30 | LICENSE IS MADE BY WIZARDS OF THE COAST! 31 | 32 | The following text is the property of Wizards of the Coast, Inc. and is 33 | Copyright 2000 Wizards of the Coast, Inc ("Wizards"). All Rights Reserved. 34 | 35 | 1. Definitions: (a)"Contributors" means the copyright and/or trademark 36 | owners who have contributed Open Game Content; (b)"Derivative Material" 37 | means copyrighted material including derivative works and translations 38 | (including into other computer languages), potation, modification, 39 | correction, addition, extension, upgrade, improvement, compilation, 40 | abridgment or other form in which an existing work may be recast, 41 | transformed or adapted; (c) "Distribute" means to reproduce, license, rent, 42 | lease, sell, broadcast, publicly display, transmit or otherwise distribute; 43 | (d)"Open Game Content" means the game mechanic and includes the methods, 44 | procedures, processes and routines to the extent such content does not 45 | embody the Product Identity and is an enhancement over the prior art and 46 | any additional content clearly identified as Open Game Content by the 47 | Contributor, and means any work covered by this License, including 48 | translations and derivative works under copyright law, but specifically 49 | excludes Product Identity. (e) "Product Identity" means product and product 50 | line names, logos and identifying marks including trade dress; artifacts; 51 | creatures characters; stories, storylines, plots, thematic elements, 52 | dialogue, incidents, language, artwork, symbols, designs, depictions, 53 | likenesses, formats, poses, concepts, themes and graphic, photographic and 54 | other visual or audio representations; names and descriptions of characters, 55 | spells, enchantments, personalities, teams, personas, likenesses and special 56 | abilities; places, locations, environments, creatures, equipment, magical or 57 | supernatural abilities or effects, logos, symbols, or graphic designs; and 58 | any other trademark or registered trademark clearly identified as Product 59 | identity by the owner of the Product Identity, and which specifically 60 | excludes the Open Game Content; (f) "Trademark" means the logos, names, 61 | mark, sign, motto, designs that are used by a Contributor to identify 62 | itself or its products or the associated products contributed to the Open 63 | Game License by the Contributor (g) "Use", "Used" or "Using" means to use, 64 | Distribute, copy, edit, format, modify, translate and otherwise create 65 | Derivative Material of Open Game Content. (h) "You" or "Your" means the 66 | licensee in terms of this agreement. 67 | 68 | 2. The License: This License applies to any Open Game Content that contains 69 | a notice indicating that the Open Game Content may only be Used under and 70 | in terms of this License. You must affix such a notice to any Open Game 71 | Content that you Use. No terms may be added to or subtracted from this 72 | License except as described by the License itself. No other terms or 73 | conditions may be applied to any Open Game Content distributed using this 74 | License. 75 | 76 | 3. Offer and Acceptance: By Using the Open Game Content You indicate Your 77 | acceptance of the terms of this License. 78 | 79 | 4. Grant and Consideration: In consideration for agreeing to use this 80 | License, the Contributors grant You a perpetual, worldwide, royalty-free, 81 | non-exclusive license with the exact terms of this License to Use, the 82 | Open Game Content. 83 | 84 | 5. Representation of Authority to Contribute: If You are contributing 85 | original material as Open Game Content, You represent that Your 86 | Contributions are Your original creation and/or You have sufficient rights 87 | to grant the rights conveyed by this License. 88 | 89 | 6. Notice of License Copyright: You must update the COPYRIGHT NOTICE 90 | portion of this License to include the exact text of the COPYRIGHT NOTICE 91 | of any Open Game Content You are copying, modifying or distributing, and 92 | You must add the title, the copyright date, and the copyright holder's name 93 | to the COPYRIGHT NOTICE of any original Open Game Content you Distribute. 94 | 95 | 7. Use of Product Identity: You agree not to Use any Product Identity, 96 | including as an indication as to compatibility, except as expressly licensed 97 | in another, independent Agreement with the owner of each element of that 98 | Product Identity. You agree not to indicate compatibility or 99 | co-adaptability with any Trademark or Registered Trademark in conjunction 100 | with a work containing Open Game Content except as expressly licensed in 101 | another, independent Agreement with the owner of such Trademark or 102 | Registered Trademark. The use of any Product Identity in Open Game Content 103 | does not constitute a challenge to the ownership of that Product Identity. 104 | The owner of any Product Identity used in Open Game Content shall retain 105 | all rights, title and interest in and to that Product Identity. 106 | 107 | 8. Identification: If you distribute Open Game Content You must clearly 108 | indicate which portions of the work that you are distributing are Open Game 109 | Content. 110 | 111 | 9. Updating the License: Wizards or its designated Agents may publish 112 | updated versions of this License. You may use any authorized version of 113 | this License to copy, modify and distribute any Open Game Content originally 114 | distributed under any version of this License. 115 | 116 | 10. Copy of this License: You MUST include a copy of this License with 117 | every copy of the Open Game Content You Distribute. 118 | 119 | 11. Use of Contributor Credits: You may not market or advertise the Open 120 | Game Content using the name of any Contributor unless You have written 121 | permission from the Contributor to do so. 122 | 123 | 12. Inability to Comply: If it is impossible for You to comply with any of 124 | the terms of this License with respect to some or all of the Open Game 125 | Content due to statute, judicial order, or governmental regulation then You 126 | may not Use any Open Game Material so affected. 127 | 128 | 13. Termination: This License will terminate automatically if You fail to 129 | comply with all terms herein and fail to cure such breach within 30 days of 130 | becoming aware of the breach. All sublicenses shall survive the termination 131 | of this License. 132 | 133 | 14. Reformation: If any provision of this License is held to be 134 | unenforceable, such provision shall be reformed only to the extent 135 | necessary to make it enforceable. 136 | 137 | 15. COPYRIGHT NOTICE Open Game License v 1.0 Copyright 2000, Wizards of the 138 | Coast, Inc. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NOTE 2 | This repository is for the front end application for OpenRPG. If you are looking for the back end libraries, please visit our sister repository, [here](https://github.com/incomingstick/OpenRPG). 3 | 4 | # OpenRPG App 5 | [![Build Status](https://travis-ci.org/incomingstick/OpenRPG-App.svg?branch=master)](https://travis-ci.org/incomingstick/OpenRPG-App) 6 | ![Version Number](https://img.shields.io/badge/version-v0.5.1-blue.svg) 7 | [![Discord Chat](https://img.shields.io/badge/chat-on%20discord-7289da.svg)](https://discord.gg/xEwaYE5) 8 | 9 | [![NPM](https://nodei.co/npm/openrpg.png)](https://nodei.co/npm/openrpg/) 10 | 11 | OpenRPG is still in its infancy and I want it to do a lot by v1.0.0! 12 | What OpenRPG aims to accomplish two fold. 13 | 14 | First, it will be a tool for someone to use to quickly create content 15 | for a tabletop RPG world. v1.0.0 will focus specifically on the 16 | 5e rules, however I hope to have that expand out to include 17 | Pathfinder and as far back as AD&D. 18 | 19 | Secondly, OpenRPG should be structured in such a way that game developers 20 | that want to emulate the d20 system in a video game could easily implement 21 | our libraries in their games to help speed production of back end tools. 22 | 23 | Some of the features this tool will include by v1.0.0 are: 24 | - A GUI front-end for the CLI tools 25 | - A die simulation tool 26 | - A name generator tool 27 | - A character generator tool (with the option to autofill a character sheet) 28 | - A town generator tool 29 | - An encounter/combat generator tool 30 | - A world generator tool 31 | - A world/town map generator 32 | 33 | ... And more (hopefully)! 34 | 35 | v0.1.0 is a basis for the CLI/developer version, but v1.0.0 will contain a 36 | portable GUI that works on Windows, Linux, and macOS. 37 | 38 | ## Building 39 | This is a node project, and as such you will need `npm` or `yarn` installed. 40 | 41 | Run `npm install` to download all dependancies. 42 | Run `npm start` to run the OpenRPG app. 43 | 44 | 45 | # License 46 | OpenRPG Software License - Version 1.0 - February 10th, 2017 47 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "openrpg", 3 | "version": "0.5.1", 4 | "description": "A tool for someone to use to quickly create content for a tabletop RPG world", 5 | "scripts": { 6 | "start": "electron-webpack dev --hot", 7 | "lint": "eslint \"src/**/*\" --fix", 8 | "test": "echo \"mocha -r ts-node/register src/test/**/*-test.ts\"", 9 | "prettier": "prettier --write \"src/**/*.{ts,tsx,js,jsx,md,css,scss,sass,json}\" !src/static/** !tmp/**", 10 | "pretty-quick": "pretty-quick --staged", 11 | "typecheck": "tsc --pretty --noEmit", 12 | "compile": "electron-webpack", 13 | "dist": "npm run compile && electron-builder", 14 | "dist:dir": "npm run compile && electron-builder --dir -c.compression=store -c.mac.identity=null", 15 | "release": "npm run compile && electron-builder -p always" 16 | }, 17 | "electronWebpack": { 18 | "commonSourceDirectory": "src/common", 19 | "title": "OpenRPG", 20 | "main": { 21 | "sourceDirectory": "src/main" 22 | }, 23 | "renderer": { 24 | "sourceDirectory": "src/renderer" 25 | } 26 | }, 27 | "build": { 28 | "appId": "com.openrpg.app", 29 | "productName": "OpenRPG", 30 | "copyright": "Copyright © 2019 ${author}", 31 | "directories": { 32 | "buildResources": "static/" 33 | }, 34 | "publish": { 35 | "provider": "github", 36 | "owner": "incomingstick", 37 | "repo": "OpenRPG-App" 38 | }, 39 | "mac": { 40 | "category": "public.app-category.utilities" 41 | }, 42 | "linux": { 43 | "target": [ 44 | "AppImage", 45 | "deb", 46 | "rpm", 47 | "tar.gz" 48 | ] 49 | } 50 | }, 51 | "repository": { 52 | "type": "git", 53 | "url": "https://github.com/incomingstick/OpenRPG-App", 54 | "ssh": "git+ssh://git@github.com:incomingstick/OpenRPG-App.git" 55 | }, 56 | "license": "OSL", 57 | "funding": { 58 | "type": "github", 59 | "url": "https://github.com/sponsors/incomingstick" 60 | }, 61 | "author": { 62 | "name": "Nick Gaulke", 63 | "url": "https://github.com/incomingstick", 64 | "email": "incomingstick@gmail.com" 65 | }, 66 | "bugs": { 67 | "url": "https://github.com/incomingstick/OpenRPG-App/issues" 68 | }, 69 | "homepage": "https://openrpg.io", 70 | "website": { 71 | "url": "https://openrpg.io", 72 | "blog": "https://blog.openrpg.io", 73 | "docs": "https://openrpg.io/documentation/introduction/" 74 | }, 75 | "publishConfig": { 76 | "registry": "https://npm.pkg.github.com/" 77 | }, 78 | "dependencies": { 79 | "@fortawesome/fontawesome-svg-core": "^1.2.36", 80 | "@fortawesome/free-brands-svg-icons": "^5.15.4", 81 | "@fortawesome/free-regular-svg-icons": "^5.15.4", 82 | "@fortawesome/free-solid-svg-icons": "^5.15.4", 83 | "@fortawesome/react-fontawesome": "^0.1.18", 84 | "async": "^3.2.3", 85 | "electron-fetch": "^1.7.4", 86 | "electron-log": "^3.0.9", 87 | "electron-settings": "^3.2.0", 88 | "electron-updater": "^4.6.5", 89 | "es6-promisify": "^6.1.1", 90 | "font-awesome": "^4.7.0", 91 | "lodash": "^4.17.21", 92 | "mkpath": "^1.0.0", 93 | "moment": "^2.29.1", 94 | "openrpg-libs": "^0.5.2", 95 | "react": "^16.14.0", 96 | "react-dom": "^16.14.0", 97 | "react-hot-loader": "^4.13.0", 98 | "semantic-ui-css": "^2.4.1", 99 | "semantic-ui-react": "^0.88.2", 100 | "source-map-support": "^0.5.21", 101 | "tslib": "^1.14.1" 102 | }, 103 | "devDependencies": { 104 | "@babel/plugin-proposal-class-properties": "^7.16.7", 105 | "@babel/preset-react": "^7.16.7", 106 | "@babel/preset-typescript": "^7.16.7", 107 | "@types/async": "^3.2.12", 108 | "@types/electron-settings": "^3.1.2", 109 | "@types/jquery": "^3.5.14", 110 | "@types/lodash": "^4.14.180", 111 | "@types/markdown-it": "0.0.9", 112 | "@types/mkpath": "^0.1.29", 113 | "@types/react": "^16.14.24", 114 | "@types/react-dom": "^16.9.14", 115 | "@typescript-eslint/eslint-plugin": "^2.34.0", 116 | "@typescript-eslint/eslint-plugin-tslint": "^2.34.0", 117 | "@typescript-eslint/parser": "^2.34.0", 118 | "clean-webpack-plugin": "^3.0.0", 119 | "electron": "6.1.7", 120 | "electron-builder": "^22.14.13", 121 | "electron-webpack": "^2.8.2", 122 | "electron-webpack-ts": "^4.0.1", 123 | "eslint": "^6.8.0", 124 | "eslint-plugin-react-hooks": "^2.5.1", 125 | "fork-ts-checker-webpack-plugin": "^4.1.6", 126 | "handlebars": "^4.7.7", 127 | "highlight.js": "^9.18.5", 128 | "html-loader": "^0.5.5", 129 | "html-webpack-plugin": "^3.2.0", 130 | "image-webpack-loader": "^6.0.0", 131 | "markdown-it": "^10.0.0", 132 | "markdown-loader": "^5.1.0", 133 | "node-sass": "^4.14.1", 134 | "prettier": "^1.19.1", 135 | "pretty-quick": "^2.0.2", 136 | "raw-loader": "^3.1.0", 137 | "sass-loader": "^8.0.2", 138 | "source-map-loader": "^0.2.4", 139 | "ts-loader": "^6.2.2", 140 | "ts-node": "^8.10.2", 141 | "tslint": "^5.20.1", 142 | "typescript": "^3.9.10", 143 | "webpack": "^4.46.0" 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/common/globals.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Global Variable defintions for the OpenRPG App 3 | * 4 | * TODO(incomingstick): Review this file as the project grows 5 | * 6 | * Project: OpenRPG 7 | * Definitions by: incomingstick 8 | */ 9 | import { website, bugs, version, repository } from '../../package.json'; 10 | import { ORPG_VERSION } from 'openrpg-libs'; 11 | 12 | export const PACKAGE_VERSION = version; 13 | export const LIBS_VERSION = ORPG_VERSION(); 14 | export const NODE_VERSION = process.versions.node; 15 | export const CHROME_VERSION = process.versions.chrome; 16 | export const ELECTRON_VERSION = process.versions.electron; 17 | 18 | // Check if we are a release build or not 19 | export const DEBUG = process.env.NODE_ENV !== 'production'; 20 | export const BUILD_TYPE = DEBUG ? 'development' : 'production'; 21 | 22 | // Get relevant URLS 23 | export const ORPG_URL = website.url; 24 | export const ORPG_BLOG = website.blog; 25 | export const ORPG_BUGS = bugs.url; 26 | export const ORPG_DOCS = website.docs; 27 | export const ORPG_REPO = repository.url; 28 | export const ORPG_ASSET_DIR = ''; 29 | -------------------------------------------------------------------------------- /src/common/log.ts: -------------------------------------------------------------------------------- 1 | import * as log from 'electron-log'; 2 | import { DEBUG } from './globals'; 3 | 4 | log.transports.file.level = DEBUG ? 'debug' : 'warn'; 5 | 6 | export default log; 7 | -------------------------------------------------------------------------------- /src/common/scripts.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Global script defintions for the OpenRPG App 3 | * 4 | * Project: OpenRPG 5 | * Definitions by: incomingstick 6 | */ 7 | import { ExpressionTree } from 'openrpg-libs'; 8 | 9 | // Evaluate a die roll 10 | export const die_eval = (exp: string) => { 11 | const parser = new ExpressionTree(); 12 | 13 | if (parser.set_expression(exp)) { 14 | return parser.parse_expression(); 15 | } 16 | 17 | return -1; 18 | }; 19 | 20 | // Allow drag 21 | export const start_drag = (event: any) => { 22 | if (event == null) return; 23 | event.dataTransfer.setData('src', event.target.id); 24 | 25 | return event; 26 | }; 27 | 28 | // Allow drop 29 | export const allow_drop = (event: any) => { 30 | if (event == null) return; 31 | 32 | event.preventDefault(); 33 | }; 34 | 35 | // Swap two items when dragged on top of 36 | export const swap_drop = (event: any) => { 37 | if (event == null) return; 38 | 39 | event.preventDefault(); 40 | const src = document.getElementById(event.dataTransfer.getData('src')); 41 | const srcParent = src.parentNode; 42 | const target = event.currentTarget.firstElementChild; 43 | 44 | event.currentTarget.replaceChild(src, target); 45 | srcParent.appendChild(target); 46 | }; 47 | -------------------------------------------------------------------------------- /src/common/services/settingsService.ts: -------------------------------------------------------------------------------- 1 | import { app } from 'electron'; 2 | import { EventEmitter } from 'events'; 3 | import * as fs from 'fs'; 4 | import _ from 'lodash'; 5 | import * as os from 'os'; 6 | import * as Path from 'path'; 7 | import log from '../log'; 8 | import { BUILD_TYPE, DEBUG } from '../globals'; 9 | import { CharacterSaveState } from '../../renderer/components/characterScreen'; 10 | 11 | // TODO(incomingstick): Can we take advantage of electron-settings at all here? 12 | 13 | export type SettingsData = { 14 | settingsFormat: string; 15 | appVersion: string; 16 | dataFolder: string; 17 | channel: string; 18 | updateTimerMinutes: number; 19 | hostURL: string; 20 | lastWindow: string; 21 | openCharacters: CharacterSaveState; 22 | zoomLevel?: number; 23 | }; 24 | 25 | // If the settings formats differ then we revert to the original default settings 26 | // TODO(incomingstick): Warn users when this is updated as their settings will reset 27 | const SETTINGS_FORMAT = '2020-02-01'; 28 | 29 | const DEFAULT_SETTINGS: SettingsData = { 30 | settingsFormat: SETTINGS_FORMAT, 31 | appVersion: app.getVersion(), 32 | dataFolder: detectDataFolder(), 33 | channel: BUILD_TYPE, 34 | updateTimerMinutes: 5, 35 | hostURL: '', 36 | lastWindow: '', 37 | openCharacters: { 38 | currIndex: 0, 39 | characters: [] 40 | } 41 | }; 42 | 43 | function isDir(path: string) { 44 | try { 45 | const st = fs.statSync(path); 46 | return st.isDirectory(); 47 | } catch (e) { 48 | return false; 49 | } 50 | } 51 | 52 | // TODO(incomingstick): where does our data go when this app is install. This currently assumes that 53 | // Openrpg-libs are already installed on the system 54 | function detectDataFolder(): string { 55 | const checkFolders: string[] = []; 56 | 57 | if (DEBUG) { 58 | checkFolders.push(Path.join(process.cwd(), '/node_modules/openrpg-libs')); 59 | } 60 | 61 | switch (os.type()) { 62 | case 'Darwin': { 63 | checkFolders.push('/Applications/OpenRPG'); 64 | break; 65 | } 66 | 67 | case 'Windows_NT': { 68 | checkFolders.push('c:/Program Files (x86)/OpenRPG'); 69 | checkFolders.push('c:/Program Files/OpenRPG'); 70 | break; 71 | } 72 | 73 | case 'Linux': { 74 | checkFolders.push('/usr/share/openrpg'); 75 | checkFolders.push('/usr/local/share/openrpg'); 76 | 77 | break; 78 | } 79 | 80 | default: { 81 | log.warn('[Settings] OS Type not Supported. Could not find data folder.'); 82 | break; 83 | } 84 | } 85 | 86 | for (const folder of checkFolders) { 87 | if (isDir(Path.join(folder, 'data'))) { 88 | return folder; 89 | } 90 | } 91 | 92 | return ''; 93 | } 94 | 95 | export interface ISettingsService { 96 | restore(): void; 97 | isLoaded(): void; 98 | restoreDefaults(): void; 99 | save(): void; 100 | get(): SettingsData; 101 | merge(settings: any): void; 102 | clear(): void; 103 | } 104 | 105 | export class SettingsService extends EventEmitter implements ISettingsService { 106 | private settingsData: SettingsData; 107 | private settingsPath: string; 108 | private settingsLoaded: boolean; 109 | 110 | public constructor(path: string) { 111 | super(); 112 | this.settingsData = _.clone(DEFAULT_SETTINGS); 113 | this.settingsPath = path; 114 | this.settingsLoaded = false; 115 | } 116 | 117 | // Public Functions 118 | public restore() { 119 | log.debug(`[Settings] Loading from ${this.settingsPath}`); 120 | try { 121 | const encodedJson = fs.readFileSync(this.settingsPath, 'utf8'); 122 | const parsedJson = JSON.parse(encodedJson); 123 | 124 | log.debug('[Settings] loaded as json: ', parsedJson); 125 | 126 | if (parsedJson.settingsFormat === SETTINGS_FORMAT) { 127 | this.settingsData = _.extend({}, DEFAULT_SETTINGS, parsedJson); 128 | } else { 129 | log.debug( 130 | `[Settings] Settings format has changed. Old = ${parsedJson.settingsFormat}, New = ${DEFAULT_SETTINGS} -- resetting settings` 131 | ); 132 | this.restoreDefaults(); 133 | this.save(); 134 | } 135 | } catch (e) { 136 | log.error('[Settings] Failed to restore settings - loading defaults', e); 137 | this.restoreDefaults(); 138 | this.save(); 139 | } 140 | } 141 | 142 | public isLoaded() { 143 | return this.settingsLoaded; 144 | } 145 | 146 | public restoreDefaults() { 147 | log.debug('[Settings] Restoring defaults'); 148 | this.settingsData = _.clone(DEFAULT_SETTINGS); 149 | } 150 | 151 | public save() { 152 | log.debug('[Settings] Saving...'); 153 | fs.writeFileSync(this.settingsPath, JSON.stringify(this.settingsData, null, 2), 'utf8'); 154 | this.triggerSettingsUpdated(); 155 | } 156 | 157 | public get(): SettingsData { 158 | return this.settingsData; 159 | } 160 | 161 | public merge(settings: any) { 162 | this.settingsData = _.extend(_.clone(DEFAULT_SETTINGS), this.settingsData, settings); 163 | this.triggerSettingsUpdated(); 164 | } 165 | 166 | public clear() { 167 | this.settingsData = _.clone(DEFAULT_SETTINGS); 168 | this.triggerSettingsUpdated(); 169 | } 170 | 171 | // Private functions 172 | private triggerSettingsUpdated() { 173 | log.debug('[Settings] Settings have been updated ...'); 174 | this.emit('updated', this.settingsData); 175 | } 176 | } 177 | 178 | export default function settings_service(callback: any) { 179 | // Save to the user-specific app location. 180 | // 181 | // NOTE: When running in development mode this will be a "Electron" folder, 182 | // But production builds will properly save to an OpenRPG folder. 183 | // See here for more: https://www.bountysource.com/issues/43448486-beta-app-getpath-userdata-returns-electron-default 184 | const path = Path.join(app.getPath('userData'), 'config.json'); 185 | const settings = new SettingsService(path); 186 | settings.restore(); 187 | 188 | callback(null, settings); 189 | } 190 | -------------------------------------------------------------------------------- /src/common/services/updateService.ts: -------------------------------------------------------------------------------- 1 | import log from '../log'; 2 | import * as EventEmitter from 'events'; 3 | 4 | const { autoUpdater } = require('electron-updater'); 5 | 6 | /** 7 | * TODO(incomingstick): keep default settings saved always as the config file, and when a user changes settings 8 | * create a new, user specific settings file 9 | */ 10 | 11 | export interface UpdateService { 12 | isUpdateAvailable(): Promise; 13 | startCheckingForUpdates(): Promise; 14 | pauseCheckingForUpdates(): Promise; 15 | events(): EventEmitter; 16 | } 17 | 18 | export default function updateServiceFactory(callback: any) { 19 | const emitter = new EventEmitter(); 20 | 21 | // TODO time since last update 22 | let updateTimerHandle: any = null; 23 | 24 | autoUpdater.logger = log; 25 | autoUpdater.allowPrerelease = true; 26 | 27 | /** 28 | * PerformUpdateCheck 29 | * 30 | * Performs a single check for whether we shoud download data from the server. 31 | */ 32 | async function performUpdateCheck() { 33 | log.debug('[Update Serviice] called performUpdateCheck'); 34 | emitter.emit('update-check-started'); 35 | 36 | autoUpdater.checkForUpdates(); 37 | 38 | try { 39 | autoUpdater.on('update-not-available', () => { 40 | emitter.emit('update-unavailable'); 41 | }); 42 | 43 | autoUpdater.on('update-available', () => { 44 | emitter.emit('update-available'); 45 | }); 46 | } catch (e) { 47 | emitter.emit('update-failed'); 48 | throw e; 49 | } 50 | } 51 | 52 | let updateInProgress = false; 53 | 54 | const factory = { 55 | events() { 56 | return emitter; 57 | }, 58 | 59 | /** 60 | * StartCheckingForUpdates 61 | * 62 | * Begins the update cycle and starts to sync new data from server to client 63 | */ 64 | async startCheckingForUpdates() { 65 | const updateTimerInMinutes = 5; 66 | 67 | if (updateInProgress) { 68 | return; 69 | } 70 | 71 | log.debug('[Update Serviice] called startCheckingForUpdates'); 72 | if (updateTimerHandle) { 73 | clearTimeout(updateTimerHandle); 74 | updateTimerHandle = null; 75 | } 76 | 77 | updateInProgress = true; 78 | 79 | try { 80 | await performUpdateCheck(); 81 | } catch (e) { 82 | throw e; 83 | } finally { 84 | updateInProgress = false; 85 | updateTimerHandle = setTimeout(() => this.startCheckingForUpdates(), updateTimerInMinutes * 1000 * 60); 86 | } 87 | }, 88 | 89 | /** 90 | * StopCheckingForUpdates 91 | */ 92 | stopCheckingForUpdates() { 93 | log.debug('[Update Serviice] called stopCheckingForUpdates'); 94 | if (updateTimerHandle) { 95 | clearTimeout(updateTimerHandle); 96 | updateTimerHandle = null; 97 | } 98 | } 99 | }; 100 | 101 | callback(null, factory); 102 | } 103 | -------------------------------------------------------------------------------- /src/common/types/files.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This is a small typescript definition script to allow for 3 | * loading of png's and other file types. We should expand this only as needed. 4 | * 5 | * Project: OpenRPG 6 | * Definitions by: incomingstick 7 | */ 8 | declare module '*.png' { 9 | const value: any; 10 | export = value; 11 | } 12 | 13 | declare module '*.md' { 14 | const value: any; 15 | export = value; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/main.ts: -------------------------------------------------------------------------------- 1 | import { autoInject } from 'async'; 2 | import { app, BrowserWindow, ipcMain, shell, dialog } from 'electron'; 3 | import * as log from 'electron-log'; 4 | import * as path from 'path'; 5 | import * as url from 'url'; 6 | import SettingsService from '../common/services/settingsService'; 7 | import UpdateService from '../common/services/updateService'; 8 | import { DEBUG } from '../common/globals'; 9 | 10 | const { autoUpdater } = require('electron-updater'); 11 | 12 | // Keep a global reference of the window object, if you don't, the window will 13 | // Be closed automatically when the JavaScript object is garbage collected. 14 | let win: any = null; 15 | 16 | const createWindow = () => { 17 | // Create the browser window. 18 | win = new BrowserWindow({ 19 | width: 1280, 20 | height: 720, 21 | frame: false, 22 | backgroundColor: '#201019', 23 | webPreferences: { 24 | nodeIntegration: true 25 | } 26 | }); 27 | 28 | if (DEBUG) { 29 | win.loadURL(`http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}`); 30 | 31 | // Open the DevTools. 32 | win.webContents.openDevTools(); 33 | } else { 34 | // And load the index.html of the app. 35 | win.loadURL( 36 | url.format({ 37 | pathname: path.join(__dirname, 'index.html'), 38 | protocol: 'file:', 39 | slashes: true 40 | }) 41 | ); 42 | } 43 | 44 | // Emitted when the window is closed. 45 | win.on('closed', () => { 46 | // Dereference the window object, usually you would store windows 47 | // In an array if your app supports multi windows, this is the time 48 | // When you should delete the corresponding element. 49 | win = null; 50 | }); 51 | } 52 | 53 | // This method will be called when Electron has finished 54 | // Initialization and is ready to create browser windows. 55 | // Some APIs can only be used after this event occurs. 56 | app.on('ready', () => { 57 | createWindow(); 58 | 59 | autoUpdater.logger = log; 60 | 61 | autoUpdater.checkForUpdatesAndNotify(); 62 | 63 | // Resolves the dependencies 64 | autoInject( 65 | // Api 66 | { 67 | settings: SettingsService, 68 | updateService: UpdateService 69 | }, 70 | (err: any, api: any) => { 71 | if (err) { 72 | log.error('[Main]', { err }, 'Dependency loader error'); 73 | return; 74 | } 75 | 76 | log.debug(`[Main] Dependency injection completes with APIs: ${Object.keys(api).join(', ')}`); 77 | 78 | api.settings.on('updated', () => { 79 | if (!win) { 80 | return; 81 | } 82 | 83 | win.webContents.send('settings-load', api.settings.get()); 84 | }); 85 | 86 | // Asynchronously get the settings 87 | ipcMain.on('settings-get', () => { 88 | if (!win) { 89 | return; 90 | } 91 | 92 | win.webContents.send('settings-load', api.settings.get()); 93 | }); 94 | 95 | // Synchronously get the settings 96 | ipcMain.on('sync-settings-get', (event: any) => { 97 | if (!win) { 98 | event.returnValue = {}; 99 | } else { 100 | event.returnValue = api.settings.get(); 101 | } 102 | }); 103 | 104 | ipcMain.on('settings-updated', (event: any, arg: any) => { 105 | api.settings.merge(arg); 106 | api.settings.save(); 107 | }); 108 | 109 | ipcMain.on('check-for-updates', () => { 110 | api.updateService.startCheckingForUpdates(); 111 | }); 112 | 113 | ipcMain.on('open-url', (event: any, externalUrl: string) => { 114 | shell.openExternal(externalUrl); 115 | }); 116 | 117 | // 118 | // Updater Events 119 | // 120 | api.updateService.events().on('update-check-started', () => { 121 | log.debug('[Main] update-check-started'); 122 | win.webContents.send('update-check-started'); 123 | }); 124 | 125 | api.updateService.events().on('update-available', () => { 126 | log.debug('[Main] update-available'); 127 | win.webContents.send('update-available'); 128 | }); 129 | 130 | // FIXME(incomingstick): This does not seem to clear after call, resulting in multiple calls building up 131 | api.updateService.events().on('update-unavailable', () => { 132 | log.debug('[Main] update-unavailable'); 133 | 134 | dialog.showMessageBox({ 135 | type: 'debug', 136 | title: 'OpenRPG', 137 | message: 'Hey, listen! No updates are currently available!' 138 | }); 139 | 140 | win.webContents.send('update-unavailable'); 141 | }); 142 | 143 | api.updateService.events().on('update-progress', (data: any) => { 144 | log.debug('[Main] update-progress', data); 145 | win.webContents.send('update-progress', data); 146 | }); 147 | 148 | api.updateService.events().on('update-completed', (data: any) => { 149 | log.debug('[Main] update-completed', data); 150 | win.webContents.send('update-completed', data); 151 | }); 152 | 153 | api.updateService.events().on('update-failed', (data: any) => { 154 | log.debug('[Main] update-failed', data); 155 | win.webContents.send('update-failed', data); 156 | }); 157 | 158 | // App events 159 | app.on('window-all-closed', () => { 160 | // Save the settings when the App is closed 161 | api.settings.save(); 162 | }); 163 | } 164 | ); 165 | }); 166 | 167 | // Quit when all windows are closed. 168 | app.on('window-all-closed', () => { 169 | // On macOS it is common for applications and their menu bar 170 | // To stay active until the user quits explicitly with Cmd + Q 171 | if (process.platform !== 'darwin') { 172 | app.quit(); 173 | } 174 | }); 175 | 176 | app.on('activate', () => { 177 | // On macOS it's common to re-create a window in the app when the 178 | // Dock icon is clicked and there are no other windows open. 179 | if (win === null) { 180 | createWindow(); 181 | } 182 | }); 183 | 184 | // This is to catch any unhandledRejections from node promises 185 | process.on('unhandledRejection', (reason: any, p: any) => { 186 | log.error('[Main] Unhandled Rejection at: Promise', p, 'reason:', reason); 187 | }); 188 | -------------------------------------------------------------------------------- /src/renderer/app.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { render } from 'react-dom'; 3 | import AppContainer from './components/appContainer'; 4 | 5 | require('semantic-ui-css/semantic.min.css'); 6 | require('./css/animate.min.css'); 7 | require('./scss/app.scss'); 8 | 9 | render(, document.getElementById('app')); 10 | -------------------------------------------------------------------------------- /src/renderer/assets/images/d20_transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/incomingstick/OpenRPG-App/1b969ff1a7ace74a7a527218d3e800744922d5ca/src/renderer/assets/images/d20_transparent.png -------------------------------------------------------------------------------- /src/renderer/components/appContainer.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { hot } from 'react-hot-loader/root'; 3 | import Sidebar from './layout/sidebar'; 4 | import Titlebar, { TTitlebarCallbackData } from './layout/titlebar'; 5 | import CharacterScreen, { CharacterState, CharacterSaveState } from './characterScreen'; 6 | import CampaignScreen from './campaign'; 7 | import CitiesScreen from './cities'; 8 | import SettingsScreen from './settings'; 9 | import WorldMapsScreen from './worldMaps'; 10 | import WelcomeScreen, { WelcomeCallbackData } from './welcome'; 11 | import { ipcRenderer, webFrame, shell } from 'electron'; 12 | import { SettingsData } from '../../common/services/settingsService'; 13 | import log from '../../common/log'; 14 | 15 | type AppContainerState = { 16 | screen: string; 17 | settings: SettingsData; 18 | characterScreenState?: CharacterState; 19 | }; 20 | 21 | export type ControlFunctionMap = { 22 | control: string; 23 | functionAlias: string; 24 | function: (...args: any[]) => void; 25 | }[]; 26 | 27 | // Open links externally by default 28 | document.addEventListener('click', (event: MouseEvent) => { 29 | const target = event.target as HTMLAreaElement; 30 | 31 | if (target.tagName === 'A' && target.href.startsWith('http')) { 32 | console.log(event); 33 | event.preventDefault(); 34 | shell.openExternal(target.href); 35 | } 36 | }); 37 | 38 | class AppContainer extends React.Component { 39 | private characterState: CharacterSaveState; 40 | private controlFuncMap: ControlFunctionMap; 41 | 42 | public constructor(props: any, context?: any) { 43 | super(props, context); 44 | 45 | const settings = ipcRenderer.sendSync('sync-settings-get') as SettingsData; 46 | 47 | this.state = { 48 | settings, 49 | screen: settings.lastWindow !== '' ? settings.lastWindow : 'welcome' 50 | }; 51 | 52 | this.characterState = this.state.settings.openCharacters; 53 | 54 | this.controlFuncMap = [ 55 | { 56 | control: 'characters', 57 | functionAlias: 'newCharacter', 58 | function: () => { 59 | log.debug('[App Container] TODO New Character Modal here!'); 60 | } 61 | } 62 | ]; 63 | } 64 | 65 | public render() { 66 | // Apply settings stuff here 67 | if (this.state.settings.zoomLevel !== undefined) { 68 | const zoomLevel = this.state.settings.zoomLevel; 69 | webFrame.setZoomFactor(1.0 + zoomLevel * 0.2); 70 | } 71 | 72 | return ( 73 | <> 74 | 79 |
80 | 83 | 84 |
85 | 86 |
87 |
88 |
89 |
90 |

TODO Notification stuff here maybe? And chat stuff maybe?

91 |
92 |
93 | 94 | ); 95 | } 96 | 97 | private sidebarCallback = (callbackData: string) => { 98 | ipcRenderer.send('settings-updated', { lastWindow: callbackData }); 99 | 100 | this.setState({ screen: callbackData, settings: ipcRenderer.sendSync('sync-settings-get') as SettingsData }); 101 | }; 102 | 103 | private titleBarCallback = (callbackData: TTitlebarCallbackData) => { 104 | ipcRenderer.send('settings-updated', { lastWindow: callbackData.screen }); 105 | 106 | if (callbackData.action) callbackData.action(); 107 | if (!callbackData.screen) callbackData.screen = 'welcome'; 108 | 109 | if (callbackData.screen === 'settings') { 110 | this.setState({ 111 | screen: callbackData.screen, 112 | settings: ipcRenderer.sendSync('sync-settings-get') as SettingsData 113 | }); 114 | } else { 115 | this.setState({ screen: callbackData.screen }); 116 | } 117 | }; 118 | 119 | private welcomeScreenCallback = (callbackData: WelcomeCallbackData) => { 120 | // TODO(incomingstick): where are we going from the welcome screen? 121 | ipcRenderer.send('settings-updated', { lastWindow: callbackData.screen }); 122 | 123 | if (callbackData.action) callbackData.action(); 124 | 125 | if (callbackData.screen === 'characters') { 126 | this.setState({ screen: callbackData.screen }); 127 | } 128 | }; 129 | 130 | private characterScreenCallback = (state: CharacterSaveState) => { 131 | ipcRenderer.send('settings-updated', { openCharacters: state }); 132 | 133 | this.characterState = state; 134 | }; 135 | 136 | private settingsScreenCallback = () => { 137 | this.setState({ settings: ipcRenderer.sendSync('sync-settings-get') as SettingsData }); 138 | }; 139 | 140 | private CurrentScreen = () => { 141 | if (this.state.screen === 'characters') 142 | return ( 143 | 147 | ); 148 | else if (this.state.screen === 'cities') return ; 149 | else if (this.state.screen === 'world-maps') return ; 150 | else if (this.state.screen === 'campaign') return ; 151 | else if (this.state.screen === 'settings') 152 | // TODO Create settings callback when settings are updated 153 | return ; 154 | else 155 | return ( 156 | 160 | ); 161 | }; 162 | } 163 | 164 | const App = () => ; 165 | 166 | export default hot(App); 167 | -------------------------------------------------------------------------------- /src/renderer/components/campaign.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | export default class CampaignScreen extends React.Component { 4 | public render() { 5 | return ( 6 |
7 |
8 |
9 |

Campaigns

10 |

Your Campaigns

11 |
12 | 13 |
14 |

TODO campaign management stuff here

15 |
16 |
17 |
18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/renderer/components/characterScreen.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Tab, Button, Menu, TabProps, SemanticShorthandItem, TabPaneProps } from 'semantic-ui-react'; 3 | import CharacterSheet from './characterScreen/characterSheet'; 4 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 5 | import { faTimes } from '@fortawesome/free-solid-svg-icons'; 6 | import { Die } from 'openrpg-libs'; 7 | import { die_eval } from '../../common/scripts'; 8 | 9 | require('../scss/characterSheet.scss'); 10 | 11 | export type CharacterSaveState = { 12 | currIndex?: string | number; 13 | characters: string[]; 14 | }; 15 | 16 | export type CharacterProps = { 17 | characterScreenSaveState: CharacterSaveState; 18 | characterScreenSaveCallback: (state: CharacterSaveState) => void; 19 | }; 20 | 21 | export type CharacterState = { 22 | currIndex?: string | number; 23 | panes: PaneItem[]; 24 | }; 25 | 26 | type PaneItem = { 27 | pane?: SemanticShorthandItem; 28 | menuItem?: JSX.Element; 29 | render?: () => React.ReactNode; 30 | }; 31 | 32 | export default class CharacterScreen extends React.Component { 33 | private currKey: number; 34 | private currPanes: PaneItem[]; 35 | 36 | // TODO(incomingstick): research maintaining state after unmount, this HAS to be possible... 37 | public constructor(props: CharacterProps, context?: CharacterState) { 38 | super(props, context); 39 | this.currKey = 0; 40 | this.state = { 41 | currIndex: 0, 42 | panes: [ 43 | { 44 | menuItem: , 45 | render: () => ( 46 | 47 |

48 | TODO Do Character creation stuff here. For now click the button below to add a menu 49 | item. 50 |

51 | 47 | 50 | 51 |
55 | {children.map((child: any, index: number) => ( 56 | {child} 57 | ))} 58 |
59 | 60 | ); 61 | } 62 | 63 | public slidePrev = (e: React.MouseEvent) => { 64 | e.preventDefault(); 65 | 66 | const prev = this.state.currIndex - 1; 67 | 68 | this.setState({ currIndex: prev }); 69 | }; 70 | 71 | public slideNext = (e: React.MouseEvent) => { 72 | e.preventDefault(); 73 | 74 | const next = this.state.currIndex + 1; 75 | 76 | this.setState({ currIndex: next }); 77 | }; 78 | 79 | public onTouchStart = (e: React.TouchEvent) => { 80 | e.preventDefault(); 81 | 82 | // TODO Touch stuff 83 | }; 84 | } 85 | -------------------------------------------------------------------------------- /src/renderer/components/layout/titlebar.tsx: -------------------------------------------------------------------------------- 1 | import * as os from 'os'; 2 | import React from 'react'; 3 | import { remote, shell, ipcRenderer } from 'electron'; 4 | import ORPGLogo from '../../assets/images/d20_transparent.png'; 5 | import { Dropdown, DropdownItemProps } from 'semantic-ui-react'; 6 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 7 | import { faWindowMinimize, faClone, faSquare } from '@fortawesome/free-regular-svg-icons'; 8 | import { faTimes } from '@fortawesome/free-solid-svg-icons'; 9 | import { ORPG_DOCS, ORPG_BUGS } from '../../../common/globals'; 10 | import ChangelogModal from '../modals/changelogModal'; 11 | import LicenseModal from '../modals/licenseModal'; 12 | import AboutModal from '../modals/aboutModal'; 13 | import log from '../../../common/log'; 14 | import { ControlFunctionMap } from '../appContainer'; 15 | 16 | require('../../scss/titlebar.scss'); 17 | 18 | /** 19 | * TODO(incomingstick): 20 | * - Add Documentation callback funtion 21 | * - Add Changelog callback funtion 22 | * - Add Report Issue callback funtion 23 | * - Add View License callback function 24 | * - Add About callback function 25 | * - Add menu hotkey/shortcuts 26 | * - Add the ability to filter menu items out based on build type (i.e hide some items for the release build) 27 | * - Allow mouse to hover across the bar when a single item has been clicked 28 | */ 29 | 30 | type TTitleBarState = { 31 | changelogOpen: boolean; 32 | licenseOpen: boolean; 33 | aboutOpen: boolean; 34 | screen: string; 35 | }; 36 | 37 | export type TTitlebarCallbackData = { 38 | screen?: string; 39 | action?: (...data: any[]) => void; 40 | data?: any; 41 | }; 42 | 43 | type TTitlebarSProps = { 44 | controlFuncMap: ControlFunctionMap; 45 | titlebarCallback: (callbackData: TTitlebarCallbackData) => void; 46 | screen?: string; 47 | }; 48 | 49 | type TitlebarMenu = { 50 | itemLabel: string; 51 | itemCallback?: (event: React.MouseEvent, data: DropdownItemProps) => any; 52 | visible?: boolean; 53 | submenu?: TitlebarMenu; 54 | divider?: boolean; 55 | }[]; 56 | 57 | export default class TitleBar extends React.Component { 58 | /* NOTE(incomingstick): use this to build the titlebar */ 59 | private titlebarMenu: TitlebarMenu = [ 60 | { 61 | itemLabel: 'File', 62 | submenu: [ 63 | { 64 | itemLabel: 'New Character', 65 | itemCallback: () => { 66 | const item = this.props.controlFuncMap.find((obj) => obj.functionAlias === 'newCharacter'); 67 | 68 | this.props.titlebarCallback({ screen: item?.control, action: item?.function }); 69 | 70 | this.setState({ screen: 'characters' }); 71 | }, 72 | divider: true 73 | }, 74 | { 75 | itemLabel: 'Settings', 76 | itemCallback: () => { 77 | this.props.titlebarCallback({ screen: 'settings' }); 78 | 79 | this.setState({ screen: 'settings' }); 80 | }, 81 | divider: true 82 | }, 83 | { 84 | itemLabel: 'Exit', 85 | itemCallback: () => { 86 | remote.getCurrentWindow().close(); 87 | } 88 | } 89 | ] 90 | }, 91 | { 92 | itemLabel: 'View', 93 | submenu: [ 94 | { 95 | itemLabel: 'Home', 96 | itemCallback: () => { 97 | this.props.titlebarCallback({ screen: 'welcome' }); 98 | 99 | this.setState({ screen: 'welcome' }); 100 | }, 101 | divider: true 102 | }, 103 | { 104 | itemLabel: 'Characters', 105 | itemCallback: () => { 106 | this.props.titlebarCallback({ screen: 'characters' }); 107 | 108 | this.setState({ screen: 'characters' }); 109 | } 110 | }, 111 | { 112 | itemLabel: 'Cities', 113 | itemCallback: () => { 114 | this.props.titlebarCallback({ screen: 'cities' }); 115 | 116 | this.setState({ screen: 'cities' }); 117 | } 118 | }, 119 | { 120 | itemLabel: 'World Maps', 121 | itemCallback: () => { 122 | this.props.titlebarCallback({ screen: 'world-maps' }); 123 | 124 | this.setState({ screen: 'world-maps' }); 125 | } 126 | }, 127 | { 128 | itemLabel: 'Campaigns', 129 | itemCallback: () => { 130 | this.props.titlebarCallback({ screen: 'campaign' }); 131 | 132 | this.setState({ screen: 'campaign' }); 133 | }, 134 | divider: true 135 | }, 136 | { 137 | itemLabel: 'Reload Window', 138 | itemCallback: () => { 139 | remote.getCurrentWindow().reload(); 140 | } 141 | } 142 | ] 143 | }, 144 | { 145 | itemLabel: 'Help', 146 | submenu: [ 147 | { 148 | itemLabel: 'Documentation', 149 | itemCallback: () => { 150 | shell.openExternal(ORPG_DOCS); 151 | } 152 | }, 153 | { 154 | itemLabel: 'Changelog', 155 | itemCallback: () => { 156 | if (this.state.changelogOpen === true) this.setState({ changelogOpen: false }); 157 | else this.setState({ changelogOpen: true, licenseOpen: false, aboutOpen: false }); 158 | }, 159 | divider: true 160 | }, 161 | { 162 | itemLabel: 'Report Issue', 163 | itemCallback: () => { 164 | shell.openExternal(ORPG_BUGS); 165 | } 166 | }, 167 | { 168 | itemLabel: 'Toggle Developers Tools', 169 | itemCallback: () => { 170 | const webContents = remote.getCurrentWindow().webContents; 171 | 172 | if (webContents.isDevToolsOpened()) { 173 | // Dev tools are open, close them! 174 | webContents.closeDevTools(); 175 | } else { 176 | // Open them there dev toolz 177 | webContents.openDevTools(); 178 | } 179 | }, 180 | divider: true 181 | }, 182 | { 183 | itemLabel: 'Check for Updates...', 184 | itemCallback: () => { 185 | ipcRenderer.send('check-for-updates'); 186 | }, 187 | visible: os.type() !== 'Linux', 188 | divider: true 189 | }, 190 | { 191 | itemLabel: 'View License', 192 | itemCallback: () => { 193 | if (this.state.licenseOpen === true) this.setState({ licenseOpen: false }); 194 | else this.setState({ changelogOpen: false, licenseOpen: true, aboutOpen: false }); 195 | } 196 | }, 197 | { 198 | itemLabel: 'About', 199 | itemCallback: () => { 200 | if (this.state.aboutOpen === true) this.setState({ aboutOpen: false }); 201 | else this.setState({ changelogOpen: false, licenseOpen: false, aboutOpen: true }); 202 | } 203 | } 204 | ] 205 | } 206 | ]; 207 | 208 | public constructor(props: any, context?: TTitleBarState) { 209 | super(props, context); 210 | this.state = { 211 | changelogOpen: false, 212 | licenseOpen: false, 213 | aboutOpen: false, 214 | screen: this.props.screen !== undefined ? this.props.screen : 'welcome' 215 | }; 216 | } 217 | 218 | public render() { 219 | const win = remote.getCurrentWindow(); 220 | 221 | return ( 222 |
223 | 224 |
{this.buildMenu(this.titlebarMenu)}
225 |
{win.getTitle()}
226 |
227 |
228 | 229 |
230 |
231 | 232 |
233 |
234 | 235 |
236 |
237 | 238 |
239 |
240 | 241 | 242 | 243 | 244 |
245 | ); 246 | } 247 | 248 | private closeChangelog = () => { 249 | this.setState({ changelogOpen: false }); 250 | }; 251 | 252 | private closeLicense = () => { 253 | this.setState({ licenseOpen: false }); 254 | }; 255 | 256 | private closeAbout = () => { 257 | this.setState({ aboutOpen: false }); 258 | }; 259 | 260 | /** 261 | * @desc This function takes in a TitlebarMenu (currently defined only as this.titlebarMenu) and builds a 262 | * SemanticUI Dropdown Menu. To modify the contents of this menu, edit the private member variable titlebarMenu 263 | * above. This function is recursive. 264 | * 265 | * @param input the current TitlebarMenu being passed. The root level is the the member variable titlebarMenu 266 | * 267 | * @return a fully built SemanticUi Dropdown menu system as a JSX.Element 268 | */ 269 | private buildMenu = (input: TitlebarMenu) => { 270 | const retElem: JSX.Element[] = []; 271 | let keyVal = 0; 272 | 273 | for (const item of input) { 274 | if (item.visible !== false) { 275 | if (item.submenu !== undefined) { 276 | retElem.push( 277 | 278 | {this.buildMenu(item.submenu)} 279 | 280 | ); 281 | } else { 282 | retElem.push(); 283 | } 284 | if (item.divider) { 285 | retElem.push(); 286 | } 287 | } 288 | } 289 | 290 | return retElem; 291 | }; 292 | 293 | /** 294 | * @desc This function handles the click event for the Window Control buttons located at the top right corner of our app. 295 | * Depending on which Window Control button was clicked, one of the 4 following things may occur: 296 | * - The app will minimize 297 | * - The app will fill the whole screen 298 | * - The app will restore to its previous state (🐞 see the FIXME below) 299 | * - The app will exit 300 | * 301 | * FIXME(incomingstick): 3/4 of these buttons currently work, however the "restore" function is bugged. This seems to be an 302 | * Electron (or upstream) issue. 303 | */ 304 | private handleWindowControlClick = (e: React.MouseEvent) => { 305 | e.preventDefault(); 306 | 307 | const win = remote.getCurrentWindow(); 308 | 309 | switch (e.currentTarget.id) { 310 | case 'min-button': { 311 | win.minimize(); 312 | break; 313 | } 314 | 315 | case 'max-button': { 316 | win.maximize(); 317 | document.body.classList.add('maximized'); 318 | break; 319 | } 320 | 321 | case 'restore-button': { 322 | win.restore(); 323 | document.body.classList.remove('maximized'); 324 | break; 325 | } 326 | 327 | case 'close-button': { 328 | win.close(); 329 | break; 330 | } 331 | 332 | default: { 333 | log.warn('[Titlebar] Unknown button click in title bar menu'); 334 | } 335 | } 336 | }; 337 | } 338 | -------------------------------------------------------------------------------- /src/renderer/components/modals/aboutModal.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Modal, Button, List } from 'semantic-ui-react'; 3 | import { PACKAGE_VERSION, NODE_VERSION, CHROME_VERSION, ELECTRON_VERSION, LIBS_VERSION } from '../../../common/globals'; 4 | 5 | require('../../scss/modal.scss'); 6 | 7 | type TAboutModalProps = { 8 | closeCallback: () => void; 9 | open: boolean; 10 | }; 11 | 12 | type TAboutModalState = { 13 | aboutOpen: boolean; 14 | }; 15 | 16 | export default class AboutModal extends React.Component { 17 | public constructor(props: TAboutModalProps, context?: any) { 18 | super(props, context); 19 | this.state = { 20 | aboutOpen: false 21 | }; 22 | } 23 | 24 | public render() { 25 | const isOpen = this.props.open; 26 | 27 | return ( 28 | 29 | About OpenRPG 30 | 31 |

32 | OpenRPG is a project created out of years of passion for playing Dungeons and Dragons by RPG 33 | veteran @incomingstick 34 |

35 |

36 | A special thanks to all of our contributors that have provided their time and effort to make 37 | OpenRPG better! 38 |

39 | 40 | 41 | Technical Details 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 |
50 | 51 |