├── .gitattributes ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── appveyor.yml ├── architecture.png ├── manifest.xml ├── reposplash.png ├── swlSimulator ├── .gitignore ├── 2.1.0 ├── ClientApp │ ├── app │ │ ├── app.module.browser.ts │ │ ├── app.module.server.ts │ │ ├── app.module.shared.ts │ │ ├── components │ │ │ ├── app │ │ │ │ ├── app.component.html │ │ │ │ └── app.component.ts │ │ │ ├── home │ │ │ │ ├── home.component.html │ │ │ │ └── home.component.ts │ │ │ ├── import │ │ │ │ ├── import.component.html │ │ │ │ └── import.component.ts │ │ │ ├── interfaces.ts │ │ │ ├── navmenu │ │ │ │ ├── navmenu.component.css │ │ │ │ ├── navmenu.component.html │ │ │ │ └── navmenu.component.ts │ │ │ ├── result │ │ │ │ ├── result.component.html │ │ │ │ └── result.component.ts │ │ │ └── spellquery │ │ │ │ ├── spellquery.component.html │ │ │ │ └── spellquery.component.ts │ │ └── presets │ │ │ └── weaponPresets.ts │ ├── assets │ │ ├── css │ │ │ ├── components.css │ │ │ ├── core.css │ │ │ ├── icons.css │ │ │ └── responsive.css │ │ ├── fonts │ │ │ ├── FontAwesome.otf │ │ │ ├── Material-Design-Iconic-Font.eot │ │ │ ├── Material-Design-Iconic-Font.svg │ │ │ ├── Material-Design-Iconic-Font.ttf │ │ │ ├── Material-Design-Iconic-Font.woff │ │ │ ├── Simple-Line-Icons.eot │ │ │ ├── Simple-Line-Icons.svg │ │ │ ├── Simple-Line-Icons.ttf │ │ │ ├── Simple-Line-Icons.woff │ │ │ ├── Simple-Line-Icons.woff2 │ │ │ ├── dripicons-v2.eot │ │ │ ├── dripicons-v2.svg │ │ │ ├── dripicons-v2.ttf │ │ │ ├── dripicons-v2.woff │ │ │ ├── fontawesome-webfont.eot │ │ │ ├── fontawesome-webfont.svg │ │ │ ├── fontawesome-webfont.ttf │ │ │ ├── fontawesome-webfont.woff │ │ │ ├── fontawesome-webfont.woff2 │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ ├── glyphicons-halflings-regular.woff2 │ │ │ ├── ionicons.eot │ │ │ ├── ionicons.svg │ │ │ ├── ionicons.ttf │ │ │ ├── ionicons.woff │ │ │ ├── themify.eot │ │ │ ├── themify.svg │ │ │ ├── themify.ttf │ │ │ ├── themify.woff │ │ │ ├── typicons.eot │ │ │ ├── typicons.less │ │ │ ├── typicons.svg │ │ │ ├── typicons.ttf │ │ │ ├── typicons.woff │ │ │ ├── weathericons-regular-webfont.eot │ │ │ ├── weathericons-regular-webfont.svg │ │ │ ├── weathericons-regular-webfont.ttf │ │ │ ├── weathericons-regular-webfont.woff │ │ │ └── weathericons-regular-webfont.woff2 │ │ ├── images │ │ │ ├── agsquare.png │ │ │ ├── big │ │ │ │ ├── bg.jpg │ │ │ │ ├── img1.jpg │ │ │ │ ├── img2.jpg │ │ │ │ ├── img3.jpg │ │ │ │ ├── img4.jpg │ │ │ │ └── img5.jpg │ │ │ ├── download.png │ │ │ ├── favicon.ico │ │ │ ├── headline.png │ │ │ ├── multiple-arrow.png │ │ │ ├── preloader.gif │ │ │ └── sp-loading.gif │ │ └── js │ │ │ ├── Chart.min.js │ │ │ └── jquery-3.2.1.min.js │ ├── boot.browser.ts │ ├── boot.server.ts │ └── test │ │ ├── boot-tests.ts │ │ └── karma.conf.js ├── Controllers │ ├── HomeController.cs │ └── ServiceController.cs ├── Models │ ├── ErrorViewModel.cs │ └── Settings.cs ├── Program.cs ├── Startup.cs ├── Views │ ├── Home │ │ └── Index.cshtml │ ├── Shared │ │ ├── Error.cshtml │ │ └── _Layout.cshtml │ ├── _ViewImports.cshtml │ └── _ViewStart.cshtml ├── api │ ├── Combat │ │ ├── Attack.cs │ │ ├── FightResult.cs │ │ └── RoundResult.cs │ ├── Engine.cs │ ├── Models │ │ ├── AplReader.cs │ │ ├── BuffWrapper.cs │ │ ├── ICombat.cs │ │ ├── IPlayer.cs │ │ └── Player.cs │ ├── Report.cs │ ├── Spells │ │ ├── Blade │ │ │ ├── Active.cs │ │ │ ├── Buffs │ │ │ │ └── Buff.cs │ │ │ └── Passive.cs │ │ ├── Blood │ │ │ ├── Active.cs │ │ │ └── Passive.cs │ │ ├── Buff.cs │ │ ├── Chaos │ │ │ ├── Active.cs │ │ │ └── Passives.cs │ │ ├── Elemental │ │ │ ├── Active.cs │ │ │ └── Passive.cs │ │ ├── Fist │ │ │ ├── Active.cs │ │ │ ├── Buffs │ │ │ │ └── Buff.cs │ │ │ └── Passive.cs │ │ ├── Hammer │ │ │ ├── Active.cs │ │ │ ├── Buffs │ │ │ │ └── Buff.cs │ │ │ └── Passive.cs │ │ ├── IBuff.cs │ │ ├── ISpell.cs │ │ ├── Item.cs │ │ ├── Passive.cs │ │ ├── Passives.cs │ │ ├── Pistol │ │ │ ├── Active.cs │ │ │ ├── Buffs │ │ │ │ └── Buff.cs │ │ │ └── Passive.cs │ │ ├── Rifle │ │ │ ├── Active.cs │ │ │ └── Passive.cs │ │ ├── Shotgun │ │ │ ├── Active.cs │ │ │ ├── Buffs │ │ │ │ └── Buff.cs │ │ │ └── Passive.cs │ │ ├── Spell.cs │ │ └── SpellBook.cs │ ├── Utilities │ │ └── Helper.cs │ └── Weapons │ │ ├── Blade.cs │ │ ├── Blood.cs │ │ ├── Chaos.cs │ │ ├── Elemental.cs │ │ ├── Fist.cs │ │ ├── Hammer.cs │ │ ├── Pistol.cs │ │ ├── Rifle.cs │ │ ├── Shotgun.cs │ │ └── Weapon.cs ├── appsettings.Development.json ├── appsettings.json ├── npm-shrinkwrap.json ├── package.json ├── swlSimulator.csproj ├── tsconfig.json ├── tslint.json ├── webpack.config.js ├── webpack.config.vendor.js └── wwwroot │ └── favicon.ico ├── swlsimNET.Tests ├── BladeTest.cs ├── BloodTest.cs ├── BuffTest.cs ├── ChaosTest.cs ├── ElementalTest.cs ├── FistTest.cs ├── HammerTest.cs ├── PassiveTest.cs ├── PistolTest.cs ├── PlayerTest.cs ├── RifleTest.cs ├── ShotgunTest.cs ├── SpellTest.cs └── swlSimulator.Tests.csproj └── swlsimNET.sln /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /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 the project team at victorvadelius@gmail.com. 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 [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## How to Report a Bug 2 | If something fails then congratulations - you found a bug. Useful bug reports are ones that get bugs fixed. A useful bug report is: 3 | 4 | * Reproducible - if we can't conclusively prove that it exists, we will probably stamp it "WORKSFORME" or "INVALID", and move on to the next bug. 5 | * Specific - the quicker that we can identify the root of the problem, the faster it's likely to get fixed. 6 | 7 | Accordingly, the goals of a bug report are to: 8 | 9 | 1. Pinpoint the bug. 10 | 2. Explain it to us. 11 | 12 | Your job is to figure out exactly what the problem is. 13 | 14 | ## Bug Reporting General Guidelines 15 | 16 | * Avoid duplicates: Search before you file! 17 | * Always test the latest available build. 18 | * One bug per report. 19 | * State useful facts, not opinions or complaints. 20 | * Flag security/privacy vulnerabilities as non-public. 21 | 22 | ## How to Write a Good Bug Report 23 | A good bug report should include the following information: 24 | 25 | #### Summary 26 | The goal of summary is to make the report searchable and uniquely identifiable. 27 | 28 | A bad example: Shit doesn't work. 29 | 30 | A good example: Selecting Hammer & Blade and trying to use Blood spells in APL crashes in Chrome. 31 | 32 | #### Overview/Description 33 | The overview or description of a bug report is to explain the bug to the developer, including: 34 | 35 | * Abstracted summary of behavior (e.g. interpretation of test failures). 36 | * Justifications of why this is a bug. 37 | * Any relevant spec links. 38 | * Interpretation of the spec. 39 | * Information on other implementations. 40 | 41 | #### Steps to Reproduce 42 | 43 | The goal of reproducible steps is to show the developer how to recreate the bug on his own system. It may be as simple as "Load the attached testcase in Browser XYZ". A more complex case may involve multiple steps, such as: 44 | 45 | Step 1: Selecting this & that in the `ImportView`. 46 | 47 | Step 2: Scrolling to the bottom of the page. 48 | 49 | Step 3: Clicking start. 50 | 51 | Step 4: Spamming back/forward. 52 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | ---------------------------------------------------------------------------- 3 | "THE BEER-WARE LICENSE" (Revision 666): 4 | (grem) & (meaniie) wrote this file. 5 | As long as you retain this notice you can do whatever you want with this stuff. 6 | If we meet some day, and you think this stuff is worth it. 7 | You can buy either of us a beer in return. 8 | ---------------------------------------------------------------------------- 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 11 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 12 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 13 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 14 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | ---------------------------------------------------------------------------- 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build status](https://ci.appveyor.com/api/projects/status/4affetky449bixws?svg=true)](https://ci.appveyor.com/project/Vadelius/swlsimnet) 2 | [![Discord](https://img.shields.io/discord/354256701257547776.svg)](https://discord.gg/kCSnKuc) 3 | [![GitHub issues](https://img.shields.io/github/issues/Vadelius/swlsimNET.svg)](https://github.com/Vadelius/swlsimNET/issues) 4 | ![License](https://img.shields.io/badge/license-Beerware-blue.svg) 5 | [![MyGet tenant](https://img.shields.io/badge/.Net%20Core-2.0-blue.svg)]() 6 | # SWLSim.Net 7 | 8 | A combat simulator for the "Secret World Legends" game, written in C#. 9 | 10 | ![results](https://cdn.rawgit.com/Vadelius/swlsimNET/af2e99ed/reposplash.png) 11 | ![architechture](https://cdn.rawgit.com/Vadelius/swlsimNET/74ed0c34/architecture.png) 12 | 13 | ### Features: 14 | 15 | * Total DPS display 16 | * Statistical view of spell breakdown, energy timeline, gimmick timeline and buff breakdown 17 | 18 | ### Requirements: 19 | **1**: .Net Core 2.0 SDK (https://www.microsoft.com/net/download/core) 20 | 21 | **2**: Node.JS (https://nodejs.org/en/download/) 22 | 23 | ### Installation: 24 | 25 | **Step 1**: Clone the repository by visiting this link: 26 | 27 | 28 | 29 | ``` 30 | https://github.com/Vadelius/swlsimNET/archive/master.zip 31 | ``` 32 | or by command line (git required): 33 | ``` 34 | git clone https://github.com/Vadelius/swlsimNET 35 | ``` 36 | 37 | **Step 2**: Unzip the archive 38 | 39 | **Step 3**: Open CMD or Powershell (Press Win+R on your keyboard to open it - then, type cmd or powershell and press Enter) 40 | 41 | **Step 4**: Go to the project root folder/directory in CMD or Powershell (By using the 'cd' and 'dir' command) 42 | 43 | **Step 5** (This requires Node.JS) install all dependencies from package.json 44 | ``` 45 | npm install 46 | ``` 47 | **Step 6**: Run the project: 48 | ``` 49 | dotnet run 50 | ``` 51 | 52 | -> Done! 🎉 Now you have a local build of the repository running on http://localhost:xxxx 53 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | image: Visual Studio 2017 3 | configuration: Release 4 | platform: Any CPU 5 | 6 | pull_requests: 7 | do_not_increment_build_number: true 8 | 9 | environment: 10 | COVERALLS_REPO_TOKEN: 11 | secure: KGgjDf8hoFZW+XtetYeBGvb+Q5K7D5pKprkC164EM7s6+klUTvpJ+9L6qr7bYZHa 12 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 13 | 14 | install: 15 | - ps: Install-Product node 16 | 17 | before_build: 18 | - ps: dotnet --info 19 | - ps: dotnet restore 20 | - ps: cd swlSimulator 21 | - npm install 22 | 23 | build_script: 24 | - ps: cd .. 25 | - ps: dotnet build swlsimNET.sln --configuration Release 26 | - ps: cd swlSimulator 27 | - ps: node node_modules/webpack/bin/webpack.js --config webpack.config.vendor.js --env.prod 28 | - ps: node node_modules/webpack/bin/webpack.js --env.prod 29 | - ps: dotnet publish --configuration Release 30 | - ps: copy ..\manifest.xml "bin\Any CPU\Release\netcoreapp2.0\manifest.xml" 31 | - ps: mkdir C:\projects\swlsimnet\artifacts 32 | 33 | artifacts: 34 | - path: artifacts\swlSimulator.zip 35 | name: swlSimulator 36 | type: WebDeployPackage 37 | 38 | test_script: 39 | - dotnet test "C:\projects\swlsimnet\swlsimNET.Tests\swlSimulator.Tests.csproj 40 | -------------------------------------------------------------------------------- /architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/architecture.png -------------------------------------------------------------------------------- /manifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /reposplash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/reposplash.png -------------------------------------------------------------------------------- /swlSimulator/.gitignore: -------------------------------------------------------------------------------- 1 | /Properties/launchSettings.json 2 | 3 | ## Ignore Visual Studio temporary files, build results, and 4 | ## files generated by popular Visual Studio add-ons. 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | build/ 23 | bld/ 24 | bin/ 25 | Bin/ 26 | obj/ 27 | Obj/ 28 | 29 | # Visual Studio 2015 cache/options directory 30 | .vs/ 31 | /wwwroot/dist/ 32 | /ClientApp/dist/ 33 | 34 | # MSTest test Results 35 | [Tt]est[Rr]esult*/ 36 | [Bb]uild[Ll]og.* 37 | 38 | # NUNIT 39 | *.VisualState.xml 40 | TestResult.xml 41 | 42 | # Build Results of an ATL Project 43 | [Dd]ebugPS/ 44 | [Rr]eleasePS/ 45 | dlldata.c 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | 84 | # Visual Studio profiler 85 | *.psess 86 | *.vsp 87 | *.vspx 88 | *.sap 89 | 90 | # TFS 2012 Local Workspace 91 | $tf/ 92 | 93 | # Guidance Automation Toolkit 94 | *.gpState 95 | 96 | # ReSharper is a .NET coding add-in 97 | _ReSharper*/ 98 | *.[Rr]e[Ss]harper 99 | *.DotSettings.user 100 | 101 | # JustCode is a .NET coding add-in 102 | .JustCode 103 | 104 | # TeamCity is a build add-in 105 | _TeamCity* 106 | 107 | # DotCover is a Code Coverage Tool 108 | *.dotCover 109 | 110 | # NCrunch 111 | _NCrunch_* 112 | .*crunch*.local.xml 113 | nCrunchTemp_* 114 | 115 | # MightyMoose 116 | *.mm.* 117 | AutoTest.Net/ 118 | 119 | # Web workbench (sass) 120 | .sass-cache/ 121 | 122 | # Installshield output folder 123 | [Ee]xpress/ 124 | 125 | # DocProject is a documentation generator add-in 126 | DocProject/buildhelp/ 127 | DocProject/Help/*.HxT 128 | DocProject/Help/*.HxC 129 | DocProject/Help/*.hhc 130 | DocProject/Help/*.hhk 131 | DocProject/Help/*.hhp 132 | DocProject/Help/Html2 133 | DocProject/Help/html 134 | 135 | # Click-Once directory 136 | publish/ 137 | 138 | # Publish Web Output 139 | *.[Pp]ublish.xml 140 | *.azurePubxml 141 | # TODO: Comment the next line if you want to checkin your web deploy settings 142 | # but database connection strings (with potential passwords) will be unencrypted 143 | *.pubxml 144 | *.publishproj 145 | 146 | # NuGet Packages 147 | *.nupkg 148 | # The packages folder can be ignored because of Package Restore 149 | **/packages/* 150 | # except build/, which is used as an MSBuild target. 151 | !**/packages/build/ 152 | # Uncomment if necessary however generally it will be regenerated when needed 153 | #!**/packages/repositories.config 154 | 155 | # Microsoft Azure Build Output 156 | csx/ 157 | *.build.csdef 158 | 159 | # Microsoft Azure Emulator 160 | ecf/ 161 | rcf/ 162 | 163 | # Microsoft Azure ApplicationInsights config file 164 | ApplicationInsights.config 165 | 166 | # Windows Store app package directory 167 | AppPackages/ 168 | BundleArtifacts/ 169 | 170 | # Visual Studio cache files 171 | # files ending in .cache can be ignored 172 | *.[Cc]ache 173 | # but keep track of directories ending in .cache 174 | !*.[Cc]ache/ 175 | 176 | # Others 177 | ClientBin/ 178 | ~$* 179 | *~ 180 | *.dbmdl 181 | *.dbproj.schemaview 182 | *.pfx 183 | *.publishsettings 184 | orleans.codegen.cs 185 | 186 | /node_modules 187 | 188 | /yarn.lock 189 | 190 | # RIA/Silverlight projects 191 | Generated_Code/ 192 | 193 | # Backup & report files from converting an old project file 194 | # to a newer Visual Studio version. Backup files are not needed, 195 | # because we have git ;-) 196 | _UpgradeReport_Files/ 197 | Backup*/ 198 | UpgradeLog*.XML 199 | UpgradeLog*.htm 200 | 201 | # SQL Server files 202 | *.mdf 203 | *.ldf 204 | 205 | # Business Intelligence projects 206 | *.rdl.data 207 | *.bim.layout 208 | *.bim_*.settings 209 | 210 | # Microsoft Fakes 211 | FakesAssemblies/ 212 | 213 | # GhostDoc plugin setting file 214 | *.GhostDoc.xml 215 | 216 | # Node.js Tools for Visual Studio 217 | .ntvs_analysis.dat 218 | 219 | # Visual Studio 6 build log 220 | *.plg 221 | 222 | # Visual Studio 6 workspace options file 223 | *.opt 224 | 225 | # Visual Studio LightSwitch build output 226 | **/*.HTMLClient/GeneratedArtifacts 227 | **/*.DesktopClient/GeneratedArtifacts 228 | **/*.DesktopClient/ModelManifest.xml 229 | **/*.Server/GeneratedArtifacts 230 | **/*.Server/ModelManifest.xml 231 | _Pvt_Extensions 232 | 233 | # Paket dependency manager 234 | .paket/paket.exe 235 | 236 | # FAKE - F# Make 237 | .fake/ 238 | -------------------------------------------------------------------------------- /swlSimulator/2.1.0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/2.1.0 -------------------------------------------------------------------------------- /swlSimulator/ClientApp/app/app.module.browser.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from "@angular/core"; 2 | import { BrowserModule } from "@angular/platform-browser"; 3 | import { AppModuleShared } from "./app.module.shared"; 4 | import { AppComponent } from "./components/app/app.component"; 5 | 6 | require("!style-loader!css-loader!../assets/css/core.css"); 7 | require("!style-loader!css-loader!../assets/css/components.css"); 8 | require("!style-loader!css-loader!../assets/css/responsive.css"); 9 | require("!style-loader!css-loader!../assets/css/icons.css"); 10 | 11 | @NgModule({ 12 | bootstrap: [AppComponent], 13 | imports: [BrowserModule, AppModuleShared], 14 | providers: [{ provide: "BASE_URL", useFactory: getBaseUrl }], 15 | }) 16 | export class AppModule {} 17 | 18 | export function getBaseUrl(): string { 19 | return document.getElementsByTagName("base")[0].href; 20 | } 21 | -------------------------------------------------------------------------------- /swlSimulator/ClientApp/app/app.module.server.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from "@angular/core"; 2 | import { ServerModule } from "@angular/platform-server"; 3 | import { AppModuleShared } from "./app.module.shared"; 4 | import { AppComponent } from "./components/app/app.component"; 5 | 6 | @NgModule({ 7 | bootstrap: [AppComponent], 8 | imports: [ServerModule, AppModuleShared], 9 | }) 10 | export class AppModule {} 11 | -------------------------------------------------------------------------------- /swlSimulator/ClientApp/app/app.module.shared.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from "@angular/common"; 2 | import { NgModule } from "@angular/core"; 3 | import { FormsModule, ReactiveFormsModule } from "@angular/forms"; 4 | import { HttpModule } from "@angular/http"; 5 | import { RouterModule } from "@angular/router"; 6 | import { ChartsModule } from "ng2-charts"; 7 | import { AppComponent } from "./components/app/app.component"; 8 | import { HomeComponent } from "./components/home/home.component"; 9 | import { ImportComponent } from "./components/import/import.component"; 10 | import { NavMenuComponent } from "./components/navmenu/navmenu.component"; 11 | import { ResultComponent } from "./components/result/result.component"; 12 | import { SpellqueryComponent } from "./components/spellquery/spellquery.component"; 13 | 14 | @NgModule({ 15 | declarations: [ 16 | AppComponent, 17 | NavMenuComponent, 18 | ImportComponent, 19 | ResultComponent, 20 | SpellqueryComponent, 21 | HomeComponent, 22 | ], 23 | imports: [ 24 | CommonModule, 25 | HttpModule, 26 | FormsModule, 27 | ChartsModule, 28 | ReactiveFormsModule, 29 | RouterModule.forRoot([ 30 | { path: "", redirectTo: "home", pathMatch: "full" }, 31 | { path: "home", component: HomeComponent }, 32 | { path: "import", component: ImportComponent }, 33 | { path: "result", component: ResultComponent }, 34 | { path: "spellquery", component: SpellqueryComponent }, 35 | { path: "**", redirectTo: "home" }, 36 | ]), 37 | ], 38 | exports: [CommonModule, FormsModule, ReactiveFormsModule], 39 | }) 40 | export class AppModuleShared {} 41 | -------------------------------------------------------------------------------- /swlSimulator/ClientApp/app/components/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |
7 | 8 |
9 |
10 |
-------------------------------------------------------------------------------- /swlSimulator/ClientApp/app/components/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from "@angular/core"; 2 | 3 | @Component({ 4 | selector: "app", 5 | templateUrl: "./app.component.html", 6 | }) 7 | export class AppComponent {} 8 | -------------------------------------------------------------------------------- /swlSimulator/ClientApp/app/components/home/home.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |

DPS Rankings per 10/19/2017:

5 |
6 | 7 |
8 |
9 | 10 |
11 |
-------------------------------------------------------------------------------- /swlSimulator/ClientApp/app/components/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from "@angular/core"; 2 | 3 | @Component({ 4 | selector: "home", 5 | templateUrl: "./home.component.html", 6 | }) 7 | export class HomeComponent { 8 | public barChartOptions: any = { 9 | scaleShowVerticalLines: false, 10 | responsive: true, 11 | scales: { 12 | yAxes: [ 13 | { 14 | ticks: { 15 | beginAtZero: true, 16 | }, 17 | }, 18 | ], 19 | }, 20 | }; 21 | public barChartLabels: string[] = [ 22 | "Rifle", 23 | "Blade", 24 | "Blood", 25 | "Chaos", 26 | "Elemental", 27 | "Fist", 28 | "Hammer", 29 | "Pistol", 30 | "Shotgun", 31 | ]; 32 | public barChartType: string = "bar"; 33 | public barChartLegend: boolean = true; 34 | 35 | public barChartData: any[] = [ 36 | { 37 | data: [12231, 10844, 14779, 11984, 12334, 9932, 14811, 13432, 12901], 38 | label: "~ 1000 IP over 240 seconds", 39 | }, 40 | ]; 41 | 42 | // events 43 | public chartClicked(e: any): void { 44 | console.log(e); 45 | } 46 | 47 | public chartHovered(e: any): void { 48 | console.log(e); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /swlSimulator/ClientApp/app/components/interfaces.ts: -------------------------------------------------------------------------------- 1 | export interface IFormNames { 2 | name: string; 3 | displayName: string; 4 | } 5 | 6 | export interface ISpellBreakdownList { 7 | name: string; 8 | dps: number; 9 | dpsPercent: number; 10 | executes: number; 11 | dpe: number; 12 | ticks: number; 13 | critChance: number; 14 | } 15 | 16 | export interface IBuffBreakdownList { 17 | name: string; 18 | executes: number; 19 | refresh: number; 20 | interval: number; 21 | uptime: number; 22 | } 23 | 24 | export interface IEnergyList { 25 | time: number; 26 | primaryEnergy: number; 27 | secondaryEnergy: number; 28 | } 29 | 30 | export interface IGimmickList { 31 | time: number; 32 | primaryGimmick: number; 33 | secondaryGimmick: number; 34 | } 35 | 36 | export interface IRootObject { 37 | totalCrits: number; 38 | totalHits: number; 39 | totalDamage: number; 40 | totalDps: number; 41 | fightDebug: string; 42 | lowestDps: number; 43 | highestDps: number; 44 | totalSpellExecutes: number; 45 | spellBreakdownList: ISpellBreakdownList[]; 46 | buffBreakdownList: IBuffBreakdownList[]; 47 | energyList: IEnergyList[]; 48 | gimmickList: IGimmickList[]; 49 | } 50 | 51 | export interface IWeaponPreset { 52 | primaryWeapon: string; 53 | primaryAffix: string; 54 | primaryProc: string; 55 | secondaryWeapon: string; 56 | secondaryAffix: string; 57 | secondaryProc: string; 58 | combatPower: number; 59 | criticalChance: number; 60 | criticalPower: number; 61 | basicSignet: number; 62 | powerSignet: number; 63 | eliteSignet: number; 64 | waistSignet: number; 65 | luckSignet: number; 66 | head: string; 67 | neck: string; 68 | luck: string; 69 | gadget: string; 70 | exposed: boolean; 71 | openingShot: boolean; 72 | headCdr: boolean; 73 | waistCdr: boolean; 74 | passive1: string; 75 | passive2: string; 76 | passive3: string; 77 | passive4: string; 78 | passive5: string; 79 | apl: string; 80 | } 81 | -------------------------------------------------------------------------------- /swlSimulator/ClientApp/app/components/navmenu/navmenu.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 | 6 | 7 | 8 | 22 |
23 |
24 | 25 | 48 |
-------------------------------------------------------------------------------- /swlSimulator/ClientApp/app/components/navmenu/navmenu.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from "@angular/core"; 2 | 3 | @Component({ 4 | selector: "nav-menu", 5 | templateUrl: "./navmenu.component.html", 6 | styleUrls: ["./navmenu.component.css"], 7 | }) 8 | export class NavMenuComponent {} 9 | -------------------------------------------------------------------------------- /swlSimulator/ClientApp/app/components/result/result.component.html: -------------------------------------------------------------------------------- 1 | 
2 | 3 |

4 | DPS = {{dps}} 5 |

6 |

Minimum: {{lowestDps}} & Maximum: {{highestDps}}

7 | 8 |
9 |
10 |
11 |

Spell Breakdown

12 | 13 | 14 |
15 |
16 |
17 |
18 |

Energy Timeline

19 | 20 |
21 |
22 |
23 |
24 |

Gimmick Timeline

25 | 26 |
27 |
28 |
29 |
30 |

Spell Breakdown

31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 |
SpellDPSDPS%DPEExecutesTicksCrit%
{{spell.name}}{{spell.dps}}{{spell.dpsPercent}}%{{spell.dpe}}{{spell.executes}}{{spell.ticks}}{{spell.critChance}}%
Total{{dps}}100%N/A{{totalSpellExecutes}}N/A{{averageCrit}}%
68 |
69 |
70 |
71 |

Buff Breakdown

72 |
73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 |
Buff# of CastsRefreshIntervalExecutesUptime%
{{buff.name}}{{buff.executes}}{{buff.refresh}}{{buff.interval}}{{buff.executes}}{{buff.uptime}}
95 |
96 |
97 |
98 |
99 |
100 |
101 |

Sample sequence

102 |
103 | 104 | 105 | 106 | 107 | 108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
-------------------------------------------------------------------------------- /swlSimulator/ClientApp/app/components/result/result.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from "@angular/core"; 2 | import { IRootObject as RootObject } from "../interfaces"; 3 | 4 | @Component({ 5 | selector: "result", 6 | templateUrl: "./result.component.html", 7 | }) 8 | 9 | export class ResultComponent implements OnInit { 10 | spellBreakdownList: any; 11 | buffBreakdownList: any; 12 | averageCrit: string; 13 | totalSpellExecutes: string; 14 | raw: any; 15 | highestDps: string; 16 | lowestDps: string; 17 | dps: string; 18 | totalDps: string; 19 | 20 | primaryEnergy: any[] = []; 21 | secondaryEnergy: any[] = []; 22 | primaryGimmick: any[] = []; 23 | secondaryGimmick: any[] = []; 24 | pieBreakdownLabels: string[] = []; 25 | pieBreakdownData: number[] = []; 26 | pieChartType: string = "pie"; 27 | 28 | pieBgcolors: any[] = [ 29 | { 30 | backgroundColor: [ 31 | "#c44224", 32 | "#3e95cd", 33 | "#c45850", 34 | "#3e95cd", 35 | "#c45850", 36 | "#90A4AE", 37 | "#B0BEC5", 38 | "#CFD8DC", 39 | "#ECEFF1", 40 | "#c45850", 41 | "#90A4AE", 42 | "#B0BEC5", 43 | "#CFD8DC", 44 | "#ECEFF1", 45 | ], 46 | }, 47 | ]; 48 | 49 | energyChartData: any[] = [ 50 | { data: this.primaryEnergy, label: "Primary", borderColor: "#d2290c" , fill: false, cubicInterpolationMode: "default", pointradius: 0}, 51 | { data: this.secondaryEnergy, label: "Secondary", borderColor: "#c44224", fill: false, cubicInterpolationMode: "default", pointradius: 0}, 52 | ]; 53 | 54 | gimmickChartData: any[] = [ 55 | { data: this.primaryGimmick, label: "Primary", borderColor: "#d2290c", fill: false, cubicInterpolationMode: "default", pointradius: 0}, 56 | { data: this.secondaryGimmick, label: "Secondary", borderColor: "#c44224", fill: false, cubicInterpolationMode: "default", pointradius: 0}, 57 | ]; 58 | 59 | lineChartLabels: any[] = []; 60 | lineChartOptions: any = { 61 | responsive: true, 62 | }; 63 | 64 | lineChartLegend: boolean = true; 65 | lineChartType: string = "line"; 66 | 67 | chartClicked(e: any): void {} 68 | chartHovered(e: any): void {} 69 | 70 | ngOnInit() { 71 | const results: any = localStorage.getItem("Results"); 72 | const jsonObj: any = JSON.parse(results); // string to generic object first 73 | const root = jsonObj as RootObject; 74 | this.dps = root.totalDps.toFixed(2); 75 | this.lowestDps = root.lowestDps.toFixed(0); 76 | this.highestDps = root.highestDps.toFixed(0); 77 | this.totalDps = root.totalDamage.toFixed(0); 78 | this.averageCrit = (100 * (root.totalCrits / root.totalHits)).toFixed(2); 79 | this.totalSpellExecutes = root.totalSpellExecutes.toFixed(2); 80 | 81 | this.raw = root.fightDebug; 82 | this.spellBreakdownList = root.spellBreakdownList; 83 | this.buffBreakdownList = root.buffBreakdownList; 84 | 85 | this.pieBreakdownData = root.spellBreakdownList 86 | .filter(spell => spell.dpsPercent > 0) 87 | .map(spell => spell.dpsPercent); 88 | 89 | this.pieBreakdownLabels = root.spellBreakdownList 90 | .filter(spell => spell.dpsPercent > 0) 91 | .map(spell => spell.name); 92 | 93 | this.lineChartLabels = root.energyList.map(time => time.time); 94 | 95 | for (const pEnergy of root.energyList) { 96 | this.primaryEnergy.push(pEnergy.primaryEnergy); 97 | } 98 | for (const sEnergy of root.energyList) { 99 | this.secondaryEnergy.push(sEnergy.secondaryEnergy); 100 | } 101 | 102 | for (const pGimmick of root.gimmickList) { 103 | this.primaryGimmick.push(pGimmick.primaryGimmick); 104 | } 105 | for (const sGimmick of root.gimmickList) { 106 | this.secondaryGimmick.push(sGimmick.secondaryGimmick); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /swlSimulator/ClientApp/app/components/spellquery/spellquery.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from "@angular/core"; 2 | 3 | @Component({ 4 | selector: "spellquery", 5 | templateUrl: "./spellquery.component.html", 6 | }) 7 | export class SpellqueryComponent {} 8 | -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/css/icons.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | @font-face { 4 | font-family: 'FontAwesome'; 5 | src: url('../fonts/fontawesome-webfont.eot?v=4.7.0'); 6 | src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg'); 7 | font-weight: normal; 8 | font-style: normal; 9 | } 10 | /*! 11 | * Material Design Iconic Font 1.0.1 by Sergey Kupletsky (@zavoloklom) - http://zavoloklom.github.io/material-design-iconic-font/ 12 | * License - https://github.com/zavoloklom/material-design-iconic-font/blob/gh-pages/License.md (Attribution-ShareAlike 4.0 International license) 13 | */ 14 | @font-face { 15 | font-family: 'Material Design Iconic Font'; 16 | src: url('../fonts/Material-Design-Iconic-Font.eot?v=1.0.1'); 17 | src: url('../fonts/Material-Design-Iconic-Font.eot?#iefix&v=1.0.1') format('embedded-opentype'), url('../fonts/Material-Design-Iconic-Font.woff?v=1.0.1') format('woff'), url('../fonts/Material-Design-Iconic-Font.ttf?v=1.0.1') format('truetype'), url('../fonts/Material-Design-Iconic-Font.svg?v=1.0.1#Material-Design-Iconic-Font') format('svg'); 18 | font-weight: normal; 19 | font-style: normal; 20 | } 21 | [class^="md-"], 22 | [class*=" md-"] { 23 | display: inline-block; 24 | font: normal normal normal 14px/1 'Material Design Iconic Font'; 25 | font-size: inherit; 26 | speak: none; 27 | text-rendering: auto; 28 | -webkit-font-smoothing: antialiased; 29 | -moz-osx-font-smoothing: grayscale; 30 | } 31 | .md { 32 | line-height: inherit; 33 | vertical-align: bottom; 34 | } 35 | .md-lg { 36 | font-size: 1.5em; 37 | line-height: .5em; 38 | vertical-align: -35%; 39 | } 40 | .md-2x { 41 | font-size: 2em; 42 | } 43 | .md-3x { 44 | font-size: 3em; 45 | } 46 | .md-4x { 47 | font-size: 4em; 48 | } 49 | .md-5x { 50 | font-size: 5em; 51 | } 52 | .md-border { 53 | padding: .2em .25em .15em; 54 | border: solid 0.08em grey; 55 | border-radius: .1em; 56 | } 57 | .md-border-circle { 58 | padding: .2em .25em .15em; 59 | border: solid 0.08em grey; 60 | border-radius: 50%; 61 | } 62 | [class^="md-"].pull-left, 63 | [class*=" md-"].pull-left { 64 | float: left; 65 | margin-right: .3em; 66 | } 67 | [class^="md-"].pull-right, 68 | [class*=" md-"].pull-right { 69 | float: right; 70 | margin-left: .3em; 71 | } 72 | 73 | .md-layers:before { 74 | content: "\f267"; 75 | } 76 | 77 | .md-layers-clear:before { 78 | content: "\f268"; 79 | } 80 | 81 | .md-dashboard:before { 82 | content: "\f01f"; 83 | } 84 | 85 | .md-class:before { 86 | content: "\f01d"; 87 | } 88 | 89 | .md-folder-special:before { 90 | content: "\f2b0"; 91 | } 92 | 93 | .md-star-rate:before { 94 | content: "\f077"; 95 | } -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/css/responsive.css: -------------------------------------------------------------------------------- 1 | /* 2 | Template Name: Ubold Dashboard 3 | Author: CoderThemes 4 | Email: coderthemes@gmail.com 5 | File: Responsive 6 | */ 7 | @media (min-width: 768px) and (max-width: 1024px) { 8 | .email-msg { 9 | display: none; 10 | } 11 | } 12 | @media (min-width: 768px) and (max-width: 991px) { 13 | body { 14 | overflow-x: hidden; 15 | } 16 | } 17 | @media (max-width: 767px) { 18 | body { 19 | overflow-x: hidden; 20 | } 21 | .mobile-sidebar { 22 | left: 0px; 23 | } 24 | .mobile-content { 25 | left: 250px; 26 | right: -250px; 27 | } 28 | .wrapper-page { 29 | width: 90%; 30 | } 31 | .wizard > .steps > ul > li { 32 | width: 100%; 33 | } 34 | .wizard > .content { 35 | padding: 0px !important; 36 | } 37 | .wizard > .content > .body { 38 | float: none; 39 | position: relative; 40 | width: 100%; 41 | height: 100%; 42 | padding: 0%; 43 | } 44 | .wizard.vertical > .steps { 45 | display: inline; 46 | float: none; 47 | width: 100%; 48 | } 49 | .wizard.vertical > .content { 50 | display: inline; 51 | float: none; 52 | margin: 0%; 53 | width: 100%; 54 | } 55 | .navbar-nav .open .dropdown-menu { 56 | background-color: #ffffff; 57 | box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26); 58 | left: auto; 59 | position: absolute; 60 | right: 0; 61 | } 62 | .todo-send { 63 | margin-top: 10px; 64 | padding-left: 15px; 65 | } 66 | .chat-inputbar { 67 | padding-left: 15px; 68 | } 69 | .chat-send { 70 | margin-top: 10px; 71 | padding-left: 15px; 72 | padding-right: 15px; 73 | } 74 | .dataTables_wrapper .col-xs-6 { 75 | width: 100%; 76 | text-align: left; 77 | } 78 | .ms-container { 79 | width: 100%; 80 | } 81 | .email-msg { 82 | display: none; 83 | } 84 | .menu-extras ul.nav { 85 | display: flex; 86 | } 87 | .menu-extras ul.nav li.navbar-c-items { 88 | display: inline-block; 89 | } 90 | } 91 | @media (max-width: 480px) { 92 | .side-menu { 93 | z-index: 10 !important; 94 | } 95 | .button-menu-mobile { 96 | display: block; 97 | } 98 | .search-bar { 99 | display: none !important; 100 | } 101 | .dropdown-menu-lg { 102 | width: 220px !important; 103 | } 104 | .notification-list em { 105 | display: none; 106 | } 107 | .notification-list .media-body { 108 | margin-left: 0 !important; 109 | } 110 | } 111 | @media (max-width: 420px) { 112 | .hide-phone { 113 | display: none !important; 114 | } 115 | } 116 | /* Container-alt */ 117 | @media (min-width: 768px) { 118 | .container-alt { 119 | width: 750px; 120 | } 121 | } 122 | @media (min-width: 992px) { 123 | .container-alt { 124 | width: 970px; 125 | } 126 | } 127 | @media (min-width: 1200px) { 128 | .container-alt { 129 | width: 1170px; 130 | } 131 | } 132 | @media (max-width: 419px) { 133 | .topbar-left { 134 | width: 70px !important; 135 | } 136 | .content-page { 137 | margin-left: 70px; 138 | } 139 | .forced .side-menu.left { 140 | box-shadow: 0 12px 12px rgba(0, 0, 0, 0.1); 141 | } 142 | .enlarged .side-menu.left { 143 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1) !important; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/Material-Design-Iconic-Font.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/Material-Design-Iconic-Font.eot -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/Material-Design-Iconic-Font.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/Material-Design-Iconic-Font.ttf -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/Material-Design-Iconic-Font.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/Material-Design-Iconic-Font.woff -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/Simple-Line-Icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/Simple-Line-Icons.eot -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/Simple-Line-Icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/Simple-Line-Icons.ttf -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/Simple-Line-Icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/Simple-Line-Icons.woff -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/Simple-Line-Icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/Simple-Line-Icons.woff2 -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/dripicons-v2.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/dripicons-v2.eot -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/dripicons-v2.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/dripicons-v2.ttf -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/dripicons-v2.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/dripicons-v2.woff -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/ionicons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/ionicons.eot -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/ionicons.ttf -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/ionicons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/ionicons.woff -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/themify.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/themify.eot -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/themify.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/themify.ttf -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/themify.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/themify.woff -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/typicons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/typicons.eot -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/typicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/typicons.ttf -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/typicons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/typicons.woff -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/weathericons-regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/weathericons-regular-webfont.eot -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/weathericons-regular-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/weathericons-regular-webfont.ttf -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/weathericons-regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/weathericons-regular-webfont.woff -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/fonts/weathericons-regular-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/fonts/weathericons-regular-webfont.woff2 -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/images/agsquare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/images/agsquare.png -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/images/big/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/images/big/bg.jpg -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/images/big/img1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/images/big/img1.jpg -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/images/big/img2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/images/big/img2.jpg -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/images/big/img3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/images/big/img3.jpg -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/images/big/img4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/images/big/img4.jpg -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/images/big/img5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/images/big/img5.jpg -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/images/download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/images/download.png -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/images/favicon.ico -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/images/headline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/images/headline.png -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/images/multiple-arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/images/multiple-arrow.png -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/images/preloader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/images/preloader.gif -------------------------------------------------------------------------------- /swlSimulator/ClientApp/assets/images/sp-loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/ClientApp/assets/images/sp-loading.gif -------------------------------------------------------------------------------- /swlSimulator/ClientApp/boot.browser.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from "@angular/core"; 2 | import { platformBrowserDynamic } from "@angular/platform-browser-dynamic"; 3 | import "bootstrap"; 4 | import "reflect-metadata"; 5 | import "zone.js"; 6 | import { AppModule } from "./app/app.module.browser"; 7 | 8 | if (module.hot) { 9 | module.hot.accept(); 10 | module.hot.dispose(() => { 11 | // Before restarting the app, we create a new root element and dispose the old one 12 | const oldRootElem = document.querySelector("app"); 13 | const newRootElem = document.createElement("app"); 14 | oldRootElem!.parentNode!.insertBefore(newRootElem, oldRootElem); 15 | modulePromise.then(appModule => appModule.destroy()); 16 | }); 17 | } else { 18 | enableProdMode(); 19 | } 20 | 21 | // Note: @ng-tools/webpack looks for the following expression when performing production 22 | // builds. Don't change how this line looks, otherwise you may break tree-shaking. 23 | const modulePromise = platformBrowserDynamic().bootstrapModule(AppModule); 24 | -------------------------------------------------------------------------------- /swlSimulator/ClientApp/boot.server.ts: -------------------------------------------------------------------------------- 1 | import { APP_BASE_HREF } from "@angular/common"; 2 | import { 3 | ApplicationRef, 4 | enableProdMode, 5 | NgZone, 6 | ValueProvider, 7 | } from "@angular/core"; 8 | import { 9 | INITIAL_CONFIG, 10 | platformDynamicServer, 11 | PlatformState, 12 | } from "@angular/platform-server"; 13 | import { createServerRenderer, RenderResult } from "aspnet-prerendering"; 14 | import "reflect-metadata"; 15 | import "rxjs/add/operator/first"; 16 | import "zone.js"; 17 | import { AppModule } from "./app/app.module.server"; 18 | 19 | enableProdMode(); 20 | 21 | export default createServerRenderer(params => { 22 | const providers = [ 23 | { 24 | provide: INITIAL_CONFIG, 25 | useValue: { document: "", url: params.url }, 26 | }, 27 | { provide: APP_BASE_HREF, useValue: params.baseUrl }, 28 | { provide: "BASE_URL", useValue: params.origin + params.baseUrl }, 29 | ]; 30 | 31 | return platformDynamicServer(providers) 32 | .bootstrapModule(AppModule) 33 | .then(moduleRef => { 34 | const appRef: ApplicationRef = moduleRef.injector.get(ApplicationRef); 35 | const state = moduleRef.injector.get(PlatformState); 36 | const zone = moduleRef.injector.get(NgZone); 37 | 38 | return new Promise((resolve, reject) => { 39 | zone.onError.subscribe((errorInfo: any) => reject(errorInfo)); 40 | appRef.isStable.first(isStable => isStable).subscribe(() => { 41 | // Because 'onStable' fires before 'onError', we have to delay slightly before 42 | // completing the request in case there's an error to report 43 | setImmediate(() => { 44 | resolve({ 45 | html: state.renderToString(), 46 | }); 47 | moduleRef.destroy(); 48 | }); 49 | }); 50 | }); 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /swlSimulator/ClientApp/test/boot-tests.ts: -------------------------------------------------------------------------------- 1 | // Load required polyfills and testing libraries 2 | import * as testing from "@angular/core/testing"; 3 | import * as testingBrowser from "@angular/platform-browser-dynamic/testing"; 4 | import "reflect-metadata"; 5 | import "zone.js"; 6 | import "zone.js/dist/async-test"; 7 | import "zone.js/dist/fake-async-test"; 8 | import "zone.js/dist/jasmine-patch"; 9 | import "zone.js/dist/long-stack-trace-zone"; 10 | import "zone.js/dist/proxy.js"; 11 | import "zone.js/dist/sync-test"; 12 | 13 | // There's no typing for the `__karma__` variable. Just declare it as any 14 | declare var __karma__: any; 15 | declare var require: any; 16 | 17 | // Prevent Karma from running prematurely 18 | __karma__.loaded = () => {}; 19 | 20 | // First, initialize the Angular testing environment 21 | testing 22 | .getTestBed() 23 | .initTestEnvironment( 24 | testingBrowser.BrowserDynamicTestingModule, 25 | testingBrowser.platformBrowserDynamicTesting(), 26 | ); 27 | 28 | // Then we find all the tests 29 | const context = require.context("../", true, /\.spec\.ts$/); 30 | 31 | // And load the modules 32 | context.keys().map(context); 33 | 34 | // Finally, start Karma to run the tests 35 | __karma__.start(); 36 | -------------------------------------------------------------------------------- /swlSimulator/ClientApp/test/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/0.13/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: ".", 7 | frameworks: ["jasmine"], 8 | files: [ 9 | "../../wwwroot/dist/vendor.js", 10 | "./**/*.ts" 11 | ], 12 | preprocessors: { 13 | "./**/*.ts": ["webpack"] 14 | }, 15 | reporters: ["progress"], 16 | port: 9876, 17 | colors: true, 18 | logLevel: config.LOG_INFO, 19 | autoWatch: true, 20 | browsers: ["Chrome"], 21 | mime: { "application/javascript": ["ts","tsx"] }, 22 | singleRun: false, 23 | webpack: require("../../webpack.config.js")().filter(config => config.target !== "node"), // Test against client bundle, because tests run in a browser 24 | webpackMiddleware: { stats: "errors-only" } 25 | }); 26 | }; 27 | -------------------------------------------------------------------------------- /swlSimulator/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using Microsoft.AspNetCore.Mvc; 3 | 4 | namespace swlSimulator.Controllers 5 | { 6 | public class HomeController : Controller 7 | { 8 | public IActionResult Index() 9 | { 10 | return View(); 11 | } 12 | 13 | public IActionResult Error() 14 | { 15 | ViewData["RequestId"] = Activity.Current?.Id ?? HttpContext.TraceIdentifier; 16 | return View(); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /swlSimulator/Controllers/ServiceController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | using swlSimulator.api; 7 | using swlSimulator.api.Combat; 8 | using swlSimulator.Models; 9 | 10 | namespace swlSimulator.Controllers 11 | { 12 | [Consumes("application/json")] 13 | [Produces("application/json")] 14 | [Route("/api/values")] 15 | public class ServiceController : Controller 16 | { 17 | private List _iterationFightResults; 18 | private Settings _settings = new Settings(); 19 | 20 | [HttpPost] 21 | public async Task Post([FromBody] Settings settings) 22 | { 23 | if (!ModelState.IsValid) 24 | { 25 | return BadRequest(ModelState); 26 | } 27 | 28 | _settings = settings; 29 | 30 | // Simulation async 31 | var result = await Task.Run(() => StartSimulation()); 32 | if (!result) 33 | { 34 | // Simulation failed 35 | throw new Exception("Grem has not yet fixed this..."); 36 | } 37 | 38 | var report = new Report(); 39 | 40 | result = await Task.Run(() => report.GenerateReportData(_iterationFightResults, settings)); 41 | if (!result) 42 | { 43 | // Report generation failed 44 | throw new Exception("Grem has not yet fixed this..."); 45 | } 46 | 47 | //return View("Results", report); 48 | return Ok(report); 49 | } 50 | 51 | private bool StartSimulation() 52 | { 53 | var engine = new Engine(_settings); 54 | _iterationFightResults = engine.StartIterations(); 55 | 56 | return _iterationFightResults.Any(); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /swlSimulator/Models/ErrorViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace swlSimulator.Models 2 | { 3 | public class ErrorViewModel 4 | { 5 | public string RequestId { get; set; } 6 | 7 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); 8 | } 9 | } -------------------------------------------------------------------------------- /swlSimulator/Models/Settings.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using swlSimulator.api.Combat; 3 | using swlSimulator.api.Spells; 4 | using swlSimulator.api.Weapons; 5 | 6 | namespace swlSimulator.Models 7 | { 8 | public class Settings 9 | { 10 | [JsonProperty("gadget")] 11 | public Gadget Gadget { get; set; } 12 | 13 | [JsonProperty("passive2")] 14 | public string Passive2 { get; set; } 15 | 16 | [JsonProperty("criticalChance")] 17 | public double CriticalChance { get; set; } = 25; 18 | 19 | [JsonProperty("basicSignet")] 20 | public double BasicSignet { get; set; } 21 | 22 | [JsonProperty("apl")] 23 | public string Apl { get; set; } 24 | 25 | [JsonProperty("combatPower")] 26 | public double CombatPower { get; set; } = 1200; 27 | 28 | [JsonProperty("eliteSignet")] 29 | public double EliteSignet { get; set; } 30 | 31 | [JsonProperty("criticalPower")] 32 | public double CritPower { get; set; } = 100; 33 | 34 | [JsonProperty("exposed")] 35 | public bool Exposed { get; set; } 36 | 37 | [JsonProperty("luckSignet")] 38 | public double LuckSignet { get; set; } 39 | 40 | [JsonProperty("headCdr")] 41 | public bool HeadSignetIsCdr { get; set; } 42 | 43 | [JsonProperty("head")] 44 | public HeadTalisman Head { get; set; } 45 | 46 | [JsonProperty("luck")] 47 | public LuckTalisman Luck { get; set; } 48 | 49 | [JsonProperty("openingShot")] 50 | public bool OpeningShot { get; set; } 51 | 52 | [JsonProperty("neck")] 53 | public NeckTalisman Neck { get; set; } 54 | 55 | [JsonProperty("passive1")] 56 | public string Passive1 { get; set; } 57 | 58 | [JsonProperty("powerSignet")] 59 | public double PowerSignet { get; set; } 60 | 61 | [JsonProperty("secondaryAffix")] 62 | public WeaponAffix SecondaryWeaponAffix { get; set; } 63 | 64 | [JsonProperty("passive4")] 65 | public string Passive4 { get; set; } 66 | 67 | [JsonProperty("passive3")] 68 | public string Passive3 { get; set; } 69 | 70 | [JsonProperty("passive5")] 71 | public string Passive5 { get; set; } 72 | 73 | [JsonProperty("primaryProc")] 74 | public WeaponProc PrimaryWeaponProc { get; set; } 75 | 76 | [JsonProperty("primaryAffix")] 77 | public WeaponAffix PrimaryWeaponAffix { get; set; } 78 | 79 | [JsonProperty("primaryWeapon")] 80 | public WeaponType PrimaryWeapon { get; set; } 81 | 82 | [JsonProperty("secondaryWeapon")] 83 | public WeaponType SecondaryWeapon { get; set; } 84 | 85 | [JsonProperty("secondaryProc")] 86 | public WeaponProc SecondaryWeaponProc { get; set; } 87 | 88 | [JsonProperty("waistCdr")] 89 | public bool WaistCdr { get; set; } 90 | 91 | [JsonProperty("wristSignet")] 92 | public object WristSignet { get; set; } 93 | 94 | // Unused atm. 95 | public double GlanceReduction { get; set; } = 30; 96 | 97 | public double Waist { get; set; } 98 | public double WaistSignet { get; set; } 99 | 100 | public bool Savagery { get; set; } = false; 101 | 102 | public int Iterations { get; set; } = 100; 103 | public int FightLength { get; set; } = 240; 104 | 105 | public TargetType TargetType { get; set; } 106 | } 107 | } -------------------------------------------------------------------------------- /swlSimulator/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore; 2 | using Microsoft.AspNetCore.Hosting; 3 | 4 | namespace swlSimulator 5 | { 6 | public class Program 7 | { 8 | public static void Main(string[] args) 9 | { 10 | BuildWebHost(args).Run(); 11 | } 12 | 13 | public static IWebHost BuildWebHost(string[] args) => 14 | WebHost.CreateDefaultBuilder(args) 15 | .UseStartup() 16 | .Build(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /swlSimulator/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.AspNetCore.SpaServices.Webpack; 4 | using Microsoft.Extensions.Configuration; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using System.Collections.Generic; 7 | using System.IO; 8 | 9 | namespace swlSimulator 10 | { 11 | public class Startup 12 | { 13 | public Startup(IConfiguration configuration) 14 | { 15 | Configuration = configuration; 16 | } 17 | 18 | public IConfiguration Configuration { get; } 19 | 20 | // This method gets called by the runtime. Use this method to add services to the container. 21 | public void ConfigureServices(IServiceCollection services) 22 | { 23 | services.AddMvc(); 24 | services.AddScoped>(); 25 | } 26 | 27 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 28 | { 29 | if (env.IsDevelopment()) 30 | { 31 | app.UseDeveloperExceptionPage(); 32 | app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions 33 | { 34 | HotModuleReplacement = true 35 | }); 36 | } 37 | else 38 | { 39 | app.UseExceptionHandler("/Home/Error"); 40 | } 41 | 42 | app.UseStaticFiles(); 43 | 44 | app.Use(async (context, next) => 45 | { 46 | await next(); 47 | if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value)) 48 | { 49 | context.Request.Path = "/index.html"; 50 | await next(); 51 | } 52 | 53 | }); 54 | 55 | app.UseMvc(routes => 56 | { 57 | routes.MapRoute( 58 | name: "default", 59 | template: "{controller=Home}/{action=Index}/{id?}"); 60 | 61 | routes.MapSpaFallbackRoute( 62 | name: "spa-fallback", 63 | defaults: new { controller = "Home", action = "Index" }); 64 | }); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /swlSimulator/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Home Page"; 3 | } 4 | 5 | Loading... 6 | 7 | 8 | @section scripts { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /swlSimulator/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Error"; 3 | } 4 | 5 |

Error.

6 |

An error occurred while processing your request.

7 | 8 | @if (!string.IsNullOrEmpty((string)ViewData["RequestId"])) 9 | { 10 |

11 | Request ID: @ViewData["RequestId"] 12 |

13 | } 14 | 15 |

Development Mode

16 |

17 | Swapping to Development environment will display more detailed information about the error that occurred. 18 |

19 |

20 | Development environment should not be enabled in deployed applications, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the ASPNETCORE_ENVIRONMENT environment variable to Development, and restarting the application. 21 |

22 | -------------------------------------------------------------------------------- /swlSimulator/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | @ViewData["Title"] - swlSimulator 7 | 8 | 9 | 10 | 11 | 12 | @RenderBody() 13 | 14 | @RenderSection("scripts", required: false) 15 | 16 | 17 | -------------------------------------------------------------------------------- /swlSimulator/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using swlSimulator 2 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 3 | @addTagHelper *, Microsoft.AspNetCore.SpaServices 4 | -------------------------------------------------------------------------------- /swlSimulator/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /swlSimulator/api/Combat/Attack.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using swlSimulator.api.Spells; 3 | 4 | namespace swlSimulator.api.Combat 5 | { 6 | public enum TargetType 7 | { 8 | Champion = 3, 9 | Dungeon = 5, 10 | Lair = 18, 11 | Regional = 31, 12 | MegaLairs = 35 13 | } 14 | 15 | public class Attack 16 | { 17 | public string Name => Spell.Name; 18 | public double Damage { get; set; } = 0; 19 | public bool IsCrit { get; set; } = false; 20 | public bool IsHit { get; set; } = false; 21 | 22 | [JsonIgnore] 23 | public ISpell Spell { get; set; } 24 | } 25 | } -------------------------------------------------------------------------------- /swlSimulator/api/Combat/FightResult.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using swlSimulator.api.Models; 3 | using swlSimulator.Models; 4 | 5 | namespace swlSimulator.api.Combat 6 | { 7 | public class FightResult 8 | { 9 | private readonly Settings _settings; 10 | 11 | public FightResult(IPlayer player) 12 | { 13 | _settings = player.Settings; 14 | } 15 | 16 | public int Iteration { get; set; } 17 | public double TotalDamage { get; set; } 18 | public int TotalHits { get; set; } 19 | public int TotalCrits { get; set; } 20 | public double Dps => TotalDamage / _settings.FightLength; 21 | 22 | // Here we want to store each rounds result 23 | public List RoundResults { get; set; } = new List(); 24 | } 25 | } -------------------------------------------------------------------------------- /swlSimulator/api/Combat/RoundResult.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using swlSimulator.api.Spells; 3 | 4 | namespace swlSimulator.api.Combat 5 | { 6 | public class RoundResult 7 | { 8 | public RoundResult() 9 | { 10 | Attacks = new List(); 11 | Buffs = new List(); 12 | } 13 | 14 | public decimal TimeSec { get; set; } 15 | public decimal Interval { get; set; } 16 | 17 | public List Attacks { get; set; } 18 | public List Buffs { get; set; } 19 | 20 | public double TotalDamage { get; set; } 21 | public int TotalHits { get; set; } 22 | public int TotalCrits { get; set; } 23 | 24 | public int PrimaryEnergyStart { get; set; } 25 | public int PrimaryEnergyEnd { get; set; } 26 | public int SecondaryEnergyStart { get; set; } 27 | public int SecondaryEnergyEnd { get; set; } 28 | 29 | public decimal PrimaryGimmickStart { get; set; } 30 | public decimal PrimaryGimmickEnd { get; set; } 31 | public decimal SecondaryGimmickStart { get; set; } 32 | public decimal SecondaryGimmickEnd { get; set; } 33 | } 34 | } -------------------------------------------------------------------------------- /swlSimulator/api/Engine.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using swlSimulator.api.Combat; 5 | using swlSimulator.api.Models; 6 | using swlSimulator.Models; 7 | 8 | namespace swlSimulator.api 9 | { 10 | public class Engine 11 | { 12 | private const decimal Interval = 0.1m; 13 | private readonly Settings _settings; 14 | 15 | public Engine(Settings settings) 16 | { 17 | _settings = settings; 18 | } 19 | 20 | // TODO: @Grem fix progress 21 | public List StartIterations(IProgress progress = null) 22 | { 23 | var iterationResults = new List(); 24 | 25 | // Run iterations 26 | for (var i = 1; i <= _settings.Iterations; i++) 27 | { 28 | var player = new Player(_settings); 29 | var fightResult = StartFight(player); 30 | fightResult.Iteration = i; 31 | 32 | iterationResults.Add(fightResult); 33 | 34 | progress?.Report(i); 35 | } 36 | 37 | return iterationResults; 38 | } 39 | 40 | public FightResult StartFight(Player player) 41 | { 42 | var fightResult = new FightResult(player); 43 | 44 | // Run a complete fight 45 | // Check if we can do something 10 times a second (to account for lag) 46 | for (decimal sec = 0; sec <= _settings.FightLength; sec += Interval) 47 | { 48 | var rr = player.NewRound(sec, Interval); 49 | foreach (var a in rr.Attacks) 50 | { 51 | // non damage attacks never added to report totals for hit/crits 52 | if (a.IsHit && a.Damage > 0) 53 | { 54 | rr.TotalHits++; 55 | } 56 | if (a.IsCrit && a.Damage > 0) 57 | { 58 | rr.TotalCrits++; 59 | } 60 | rr.TotalDamage += a.Damage; 61 | } 62 | 63 | // Only save rounds with any actions 64 | if (rr.Attacks.Any()) 65 | { 66 | fightResult.RoundResults.Add(rr); 67 | fightResult.TotalDamage += rr.TotalDamage; 68 | fightResult.TotalHits += rr.TotalHits; 69 | fightResult.TotalCrits += rr.TotalCrits; 70 | } 71 | } 72 | 73 | return fightResult; 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /swlSimulator/api/Models/AplReader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using swlSimulator.api.Spells; 4 | 5 | namespace swlSimulator.api.Models 6 | { 7 | public class AplReader 8 | { 9 | private readonly string _aplString; 10 | private readonly IPlayer _player; 11 | 12 | public AplReader(IPlayer player, string apl) 13 | { 14 | _player = player; 15 | _aplString = apl; 16 | } 17 | 18 | public List GetApl() 19 | { 20 | var apl = new List(); 21 | var array = _aplString.Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); 22 | 23 | foreach (var item in array) 24 | { 25 | string name; 26 | string expr = null; 27 | 28 | // create new class from name 29 | var charLocation = item.IndexOf(",", StringComparison.Ordinal); 30 | 31 | if (charLocation > 0) 32 | { 33 | name = item.Substring(0, charLocation).Trim(); 34 | expr = item.Substring(charLocation + 1, item.Length - name.Length - 1).Trim(); 35 | } 36 | else 37 | { 38 | name = item.Trim(); 39 | } 40 | 41 | // Name can't contain any spaces at all 42 | name = name.Replace(" ", string.Empty); 43 | 44 | var myType = Type.GetType("swlSimulator.api.Spells." + name, false, true); 45 | var myTypeRage = Type.GetType("swlSimulator.api.Spells." + name + "Rage", false, true); 46 | 47 | // TODO: Show where user input is BAD 48 | if (myType == null) 49 | { 50 | continue; 51 | } 52 | 53 | // TODO: Handle errors here 54 | var spell = (ISpell) Activator.CreateInstance(myType, _player, expr); 55 | apl.Add(spell); 56 | 57 | if (myTypeRage == null) 58 | { 59 | continue; 60 | } 61 | spell = (ISpell) Activator.CreateInstance(myTypeRage, _player, expr); 62 | apl.Add(spell); 63 | } 64 | 65 | return apl; 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /swlSimulator/api/Models/BuffWrapper.cs: -------------------------------------------------------------------------------- 1 | using swlSimulator.api.Spells; 2 | using swlSimulator.api.Weapons; 3 | 4 | namespace swlSimulator.api.Models 5 | { 6 | public class BuffWrapper 7 | { 8 | private readonly Player _player; 9 | 10 | public BuffWrapper(Player player) 11 | { 12 | _player = player; 13 | } 14 | 15 | public IBuff Exposed => _player.GetBuffFromName("Exposed"); 16 | public IBuff OpeningShot => _player.GetBuffFromName("OpeningShot"); 17 | public IBuff Savagery => _player.GetBuffFromName("Savagery"); 18 | public IBuff UnstoppableForce => _player.GetBuffFromName("UnstoppableForce"); 19 | 20 | // Hammer APL specifics 21 | public bool Enraged => _player.Rage >= 50 || _player.GetWeaponFromType(WeaponType.Hammer) is Hammer hammer && 22 | hammer.PneumaticAvailable; 23 | 24 | public bool FastAndFurious => _player.GetWeaponFromType(WeaponType.Hammer) is Hammer 25 | hammer && hammer.FastAndFuriousBonus; 26 | 27 | // Pistol APL specifics 28 | public bool RedChambers => _player.GetWeaponFromType(WeaponType.Pistol) is Pistol pistol && 29 | pistol.LeftChamber == Chamber.Red && pistol.LeftChamber == pistol.RightChamber; 30 | 31 | public bool BlueChambers => _player.GetWeaponFromType(WeaponType.Pistol) is Pistol pistol && 32 | pistol.LeftChamber == Chamber.Blue && pistol.LeftChamber == pistol.RightChamber; 33 | 34 | public bool WhiteChambers => _player.GetWeaponFromType(WeaponType.Pistol) is Pistol pistol && 35 | pistol.LeftChamber == Chamber.White && pistol.LeftChamber == pistol.RightChamber; 36 | 37 | // Fist APL specifics 38 | public bool dd => _player.GetWeaponFromType(WeaponType.Fist) is Fist fist && fist.AllowFrenziedWrathAbilities; 39 | 40 | // TODO: Need to add all buffs here if we cant solve it in another way.. 41 | } 42 | } -------------------------------------------------------------------------------- /swlSimulator/api/Models/ICombat.cs: -------------------------------------------------------------------------------- 1 | using swlSimulator.api.Combat; 2 | using swlSimulator.api.Spells; 3 | 4 | namespace swlSimulator.api.Models 5 | { 6 | public interface ICombat 7 | { 8 | decimal CastTime { get; set; } 9 | decimal CurrentTimeSec { get; } 10 | decimal GCD { get; set; } 11 | Spell CurrentSpell { get; } 12 | RoundResult NewRound(decimal currentSec, decimal intervalSec); 13 | } 14 | } -------------------------------------------------------------------------------- /swlSimulator/api/Models/IPlayer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using swlSimulator.api.Combat; 3 | using swlSimulator.api.Spells; 4 | using swlSimulator.api.Weapons; 5 | using swlSimulator.Models; 6 | 7 | namespace swlSimulator.api.Models 8 | { 9 | public interface IPlayer 10 | { 11 | Settings Settings { get; } 12 | double CombatPower { get; } 13 | double GlanceReduction { get; } 14 | double CriticalChance { get; } 15 | double CritPower { get; } 16 | double BasicSignetBoost { get; } 17 | double PowerSignetBoost { get; } 18 | double EliteSignetBoost { get; } 19 | double WaistSignetBoost { get; } 20 | decimal Interval { get; } 21 | decimal CurrentTimeSec { get; } 22 | 23 | List Spells { get; } 24 | List Buffs { get; } 25 | List AbilityBuffs { get; } 26 | 27 | IBuff GetBuffFromName(string name); 28 | IBuff GetAbilityBuffFromName(string name); 29 | bool HasPassive(string name); 30 | Passive GetPassive(string name); 31 | 32 | Weapon PrimaryWeapon { get; } 33 | Weapon SecondaryWeapon { get; } 34 | 35 | Weapon GetWeaponFromSpell(ISpell spell); 36 | Weapon GetOtherWeaponFromSpell(ISpell spell); 37 | Weapon GetWeaponFromType(WeaponType wtype); 38 | 39 | decimal GetWeaponResourceFromType(WeaponType wtype); 40 | 41 | void AddBonusAttack(RoundResult rr, ISpell spell); 42 | } 43 | } -------------------------------------------------------------------------------- /swlSimulator/api/Spells/Blade/Active.cs: -------------------------------------------------------------------------------- 1 | using swlSimulator.api.Models; 2 | using swlSimulator.api.Weapons; 3 | 4 | namespace swlSimulator.api.Spells.Blade 5 | { 6 | public class FlowingStrike : Spell 7 | { 8 | public FlowingStrike(IPlayer player, string args = null) 9 | { 10 | WeaponType = WeaponType.Blade; 11 | AbilityType = AbilityType.Basic; 12 | BaseDamage = 1.175; 13 | Args = args; 14 | } 15 | } 16 | 17 | public class Hurricane : Spell 18 | { 19 | public Hurricane(IPlayer player, string args = null) 20 | { 21 | WeaponType = WeaponType.Blade; 22 | AbilityType = AbilityType.Power; 23 | BaseDamage = 1.26; 24 | PrimaryCost = 3; 25 | Args = args; 26 | 27 | // TODO: SpellType? 28 | // PBAOE 29 | } 30 | } 31 | 32 | public class Hone : Spell 33 | { 34 | public Hone(IPlayer player, string args = null) 35 | { 36 | WeaponType = WeaponType.Blade; 37 | AbilityType = AbilityType.Special; 38 | SpellType = SpellType.Instant; 39 | PrimaryGain = 2; 40 | BaseDamage = 0; 41 | // Attacks have 20% extra chance to generate CHI for 8 seconds. 42 | Args = args; 43 | } 44 | } 45 | 46 | public class Tsunami : Spell 47 | { 48 | public Tsunami(IPlayer player, string args = null) 49 | { 50 | WeaponType = WeaponType.Blade; 51 | AbilityType = AbilityType.Power; 52 | SpellType = SpellType.Channel; 53 | ChannelTicks = 5; 54 | BaseDamage = 1.04; 55 | PrimaryCost = 5; 56 | Args = args; 57 | } 58 | } 59 | 60 | public class DancingBlade : Spell 61 | { 62 | public DancingBlade(IPlayer player, string args = null) 63 | { 64 | WeaponType = WeaponType.Blade; 65 | AbilityType = AbilityType.Elite; 66 | SpellType = SpellType.Channel; 67 | ChannelTicks = 5; 68 | BaseDamage = 1.52; 69 | PrimaryCost = 4; 70 | Args = args; 71 | } 72 | } 73 | 74 | public class SpiritBlade : Spell // TODO: Two of same spell, exists in blade also? 75 | { 76 | public SpiritBlade(IPlayer player, string args = null) 77 | { 78 | WeaponType = WeaponType.Blade; 79 | AbilityType = AbilityType.Special; 80 | PrimaryGimmickCost = 5; 81 | // Requires & Consumes 5 Chi, The next 10 blade attacks deal additional 1.04 CP per attack (SpiritBlade) 82 | // If used when already forged (Requires 1 chi and will consume all chi if we have more and will generate more SpiritBlade() attacks.) 83 | // All of this is in blade weapon Model. 84 | Args = args; 85 | } 86 | } 87 | 88 | public class SnakesBite : Spell 89 | { 90 | public SnakesBite(IPlayer player, string args = null) 91 | { 92 | WeaponType = WeaponType.Blade; 93 | AbilityType = AbilityType.Special; 94 | PrimaryCost = 2; 95 | BaseDamage = 2.9; 96 | // 3 second stun. 97 | Args = args; 98 | } 99 | } 100 | 101 | public class SupremeHarmony : Spell 102 | { 103 | public SupremeHarmony(IPlayer player, string args = null) 104 | { 105 | WeaponType = WeaponType.Blade; 106 | AbilityType = AbilityType.Elite; 107 | SpellType = SpellType.Instant; 108 | PrimaryCost = 4; 109 | Args = args; 110 | AbilityBuff = player.GetAbilityBuffFromName(Name) as AbilityBuff; 111 | // 8 second buff for 23% blade damage. 112 | } 113 | } 114 | 115 | public class SwallowCut : Spell 116 | { 117 | public SwallowCut(IPlayer player, string args = null) 118 | { 119 | WeaponType = WeaponType.Blade; 120 | AbilityType = AbilityType.Power; 121 | PrimaryCost = 3; 122 | BaseDamage = 2.52; 123 | Args = args; 124 | } 125 | } 126 | 127 | public class Typhoon : Spell 128 | { 129 | public Typhoon(IPlayer player, string args = null) 130 | { 131 | WeaponType = WeaponType.Blade; 132 | AbilityType = AbilityType.Elite; 133 | PrimaryCost = 4; 134 | BaseDamage = 1.28; 135 | Args = args; 136 | // Gives you a 6 second buff that increases blade damage by 6% per target hit.. 137 | } 138 | } 139 | } 140 | 141 | -------------------------------------------------------------------------------- /swlSimulator/api/Spells/Blade/Buffs/Buff.cs: -------------------------------------------------------------------------------- 1 | using swlSimulator.api.Weapons; 2 | 3 | namespace swlSimulator.api.Spells.Blade.Buffs 4 | { 5 | public class SupremeHarmony : AbilityBuff 6 | { 7 | public SupremeHarmony() 8 | { 9 | WeaponType = WeaponType.Blade; 10 | MaxDuration = 8; 11 | MaxBonusDamageMultiplier = 0.23; // TODO: Is it really all damage or only basedamage? 12 | SpecificWeaponTypeBonus = true; 13 | // 8 second buff for 23% blade damage. 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /swlSimulator/api/Spells/Blade/Passive.cs: -------------------------------------------------------------------------------- 1 | using swlSimulator.api.Weapons; 2 | 3 | namespace swlSimulator.api.Spells.Blade 4 | { 5 | public class EyeOfTheStorm : Passive 6 | { 7 | public EyeOfTheStorm() 8 | { 9 | WeaponType = WeaponType.Blade; 10 | SpellTypes.Add(typeof(Hurricane)); 11 | BaseDamage = 0.47; // per channel hit. 12 | } 13 | } 14 | 15 | public class KeenEdge : Passive 16 | { 17 | public KeenEdge() 18 | { 19 | WeaponType = WeaponType.Blade; 20 | SpellTypes.Add(typeof(Hone)); 21 | BaseDamageCritModifier = 0.4; 22 | // Adds 40% critpower buff during hone 23 | } 24 | } 25 | 26 | public class StormSurge : Passive 27 | { 28 | public StormSurge() 29 | { 30 | WeaponType = WeaponType.Blade; 31 | SpellTypes.Add(typeof(Tsunami)); 32 | BaseDamage = 0.47; // per channel hit. 33 | } 34 | } 35 | 36 | public class SoulForgedBlade : Passive 37 | { 38 | public SoulForgedBlade() 39 | { 40 | WeaponType = WeaponType.Blade; 41 | SpellTypes.Add(typeof(DancingBlade)); 42 | // Generates a 3 second Spirit Blade OR 3 spirit blade attacks if spirit blade is up. 43 | } 44 | } 45 | 46 | public class Masterpiece : Passive 47 | { 48 | public Masterpiece() 49 | { 50 | WeaponType = WeaponType.Blade; 51 | SpellTypes.Add(typeof(SpiritBlade)); 52 | // Every 4th blade attack with Spirit Blade up deals an extra 0.78 CP per attack 53 | } 54 | } 55 | 56 | public class MastersFocus : Passive 57 | { 58 | public MastersFocus() 59 | { 60 | WeaponType = WeaponType.Blade; 61 | SpellTypes.Add(typeof(SupremeHarmony)); 62 | // Whenever Chi is gained during Supreme Harmony reduce its CURRENT cooldown by 5% (Like efficiency) 63 | } 64 | } 65 | 66 | public class HardenedBlade : Passive 67 | { 68 | public HardenedBlade() 69 | { 70 | WeaponType = WeaponType.Blade; 71 | SpellTypes.Add(typeof(SwallowCut)); 72 | ModelledInWeapon = true; 73 | // Has 30% chance to not consume a spirit blade attackcharge when used. 74 | } 75 | } 76 | 77 | public class Torrent : Passive 78 | { 79 | public Torrent() 80 | { 81 | WeaponType = WeaponType.Blade; 82 | SpellTypes.Add(typeof(Typhoon)); 83 | // Blade damage bonus for each target hit increased to 9.3% per target (46.5 maximum) ( 5 targets.. ) 84 | } 85 | } 86 | 87 | public class Deluge : Passive 88 | { 89 | public Deluge() 90 | { 91 | WeaponType = WeaponType.Blade; 92 | // Every 6th hit with spirit blade unleashes an AoE of 0.38CP 93 | } 94 | } 95 | 96 | public class DrawSwordDrawBlood : Passive 97 | { 98 | public DrawSwordDrawBlood() 99 | { 100 | WeaponType = WeaponType.Blade; 101 | // When combat starts the next 3 blade attacks does 20% more damage. 102 | // This bonus is also applied once every 10 seconds. (ONE CHARGE, not 3 ?) 103 | } 104 | } 105 | 106 | public class MeasureTwiceCutOnce : Passive 107 | { 108 | public MeasureTwiceCutOnce() 109 | { 110 | WeaponType = WeaponType.Blade; 111 | // If Chi has not been generated in the past 4.5 seconds, the next blade attack will generate 1 chi 112 | // in addition to the normal chi gain chance. 113 | } 114 | } 115 | 116 | public class FocusedBreathing : Passive 117 | { 118 | public FocusedBreathing() 119 | { 120 | WeaponType = WeaponType.Blade; 121 | //1 chi gained every 9 seconds. 122 | } 123 | } 124 | 125 | public class Resonance : Passive 126 | { 127 | public Resonance() 128 | { 129 | WeaponType = WeaponType.Blade; 130 | // Whenever chi is gained do an attack for 0.38 CP 131 | } 132 | } 133 | 134 | public class WarriorsSpirit : Passive 135 | { 136 | public WarriorsSpirit() 137 | { 138 | WeaponType = WeaponType.Blade; 139 | // When the spirit blade is consumed (shattered... RP) gain 1 chi and do 0.67CP in an AoE 140 | } 141 | } 142 | } -------------------------------------------------------------------------------- /swlSimulator/api/Spells/Blood/Passive.cs: -------------------------------------------------------------------------------- 1 | using swlSimulator.api.Models; 2 | using swlSimulator.api.Weapons; 3 | 4 | namespace swlSimulator.api.Spells.Blood 5 | { 6 | public class LingeringCurse : Passive 7 | { 8 | public LingeringCurse() 9 | { 10 | WeaponType = WeaponType.Blood; 11 | SpellTypes.Add(typeof(DreadSigil)); 12 | SpellType = SpellType.Dot; 13 | BaseDamage = 0.78; 14 | DotDuration = 5; 15 | PassiveBonusSpell = this; 16 | 17 | // TODO: Test 18 | // 0.78 CP per sec for 5 seconds DoT whenever DreadSigil is cast. 19 | } 20 | } 21 | 22 | public class Contaminate : Passive 23 | { 24 | public Contaminate() 25 | { 26 | WeaponType = WeaponType.Blood; 27 | SpellTypes.Add(typeof(Reap)); 28 | BaseDamage = 0.31; // + 0.31 CP per sec to a total of 0.56 CP 29 | } 30 | } 31 | 32 | public class Flay : Passive 33 | { 34 | public Flay() 35 | { 36 | WeaponType = WeaponType.Blood; 37 | SpellTypes.Add(typeof(Maleficium)); 38 | BaseDamage = 0.11; // TODO: Make sure it's 0.11 BaseDamage and not 0.11 BaseDamageModifier... 39 | ModelledInWeapon = true; 40 | } 41 | } 42 | 43 | public class Convergence : Passive 44 | { 45 | public Convergence(IPlayer player, string args = null) 46 | { 47 | WeaponType = WeaponType.Blood; 48 | SpellTypes.Add(typeof(SanguineCoalescence)); 49 | // Causes next 4 blood attacks to deal additional 1.93 * CP extra. 50 | } 51 | } 52 | 53 | public class BloodFlow : Passive 54 | { 55 | public BloodFlow(IPlayer player, string args = null) 56 | { 57 | WeaponType = WeaponType.Blood; 58 | SpellTypes.Add(typeof(Rupture)); 59 | // If Corruption(Gimmick) is > 60 we do a dot, dealing 0.36*CP/sec for 6 seconds. 60 | // Causes next 4 blood attacks to deal additional 1.93 * CP extra. 61 | } 62 | } 63 | 64 | public class Defilement : Passive 65 | { 66 | public Defilement() 67 | { 68 | WeaponType = WeaponType.Blood; 69 | SpellTypes.Add(typeof(Desecrate)); 70 | ModelledInWeapon = true; 71 | // Corrution gain during Desecrate is increased by 20% 72 | // If at max corruption we gain 16.5% blood ability damage. 73 | } 74 | } 75 | 76 | public class Paroxysm : Passive 77 | { 78 | public Paroxysm(IPlayer player, string args = null) 79 | { 80 | WeaponType = WeaponType.Blood; 81 | SpellTypes.Add(typeof(RunicHex)); 82 | // When Runic Hex expires we do a shittier Runic Hex for 0.31 * CP for 4 (3+1) seconds 83 | } 84 | } 85 | 86 | public class Desolate : Passive 87 | { 88 | public Desolate() 89 | { 90 | WeaponType = WeaponType.Blood; 91 | SpellTypes.Add(typeof(EldritchScourge)); 92 | BaseDamageModifier = 0.52; 93 | } 94 | } 95 | 96 | public class CurseOfDestruction : Passive 97 | { 98 | public CurseOfDestruction(IPlayer player, string args = null) 99 | { 100 | WeaponType = WeaponType.Blood; 101 | // If Coprrution > 10 && We do a Blood Crit we throw a Curse on %target for 5 sec. 102 | // Curse causes %target to take 0.28 * CP for each crit we do on them. 103 | } 104 | } 105 | 106 | public class CrimsonPulse : Passive 107 | { 108 | public CrimsonPulse() 109 | { 110 | WeaponType = WeaponType.Blood; 111 | BonusSpellOnlyOnCrit = true; 112 | PassiveBonusSpell = this; 113 | SpecificWeaponTypeBonus = true; 114 | BaseDamage = 0.255; // 0.085 for 3 seconds. // TODO: Make dot 115 | // When we crit with blood abilities target suffers 0.085 * CP for 3 seconds. 116 | } 117 | } 118 | 119 | public class Absolution : Passive 120 | { 121 | public Absolution(IPlayer player, string args = null) 122 | { 123 | WeaponType = WeaponType.Blood; 124 | // Whenever Corruption > 60 we set Corruption -= 50; 125 | } 126 | } 127 | 128 | public class SanguineCharm : Passive 129 | { 130 | public SanguineCharm(IPlayer player, string args = null) 131 | { 132 | WeaponType = WeaponType.Blood; 133 | // Whenever we lose and go under a CorruptionGimmick% treshhold 134 | // We gain 9% blood ability damage for 4 seconds. 135 | } 136 | } 137 | } -------------------------------------------------------------------------------- /swlSimulator/api/Spells/Buff.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using swlSimulator.api.Weapons; 3 | 4 | namespace swlSimulator.api.Spells 5 | { 6 | public class Buff : IBuff 7 | { 8 | public string Name => GetType().Name; 9 | public decimal MaxDuration { get; set; } 10 | public decimal Duration { get; set; } = -1; 11 | public decimal MaxCooldown { get; set; } 12 | public decimal Cooldown { get; set; } 13 | public virtual bool Active => Duration > 0; 14 | public List ActivationRounds { get; } = new List(); 15 | public List DeactivationRounds { get; } = new List(); 16 | 17 | public double MaxBonusCritChance { get; set; } 18 | public double MaxBonusCritMultiplier { get; set; } 19 | public double MaxBonusDamageMultiplier { get; set; } 20 | public double MaxBonusBaseDamageMultiplier { get; set; } 21 | 22 | public WeaponType WeaponType { get; set; } 23 | public bool SpecificWeaponTypeBonus { get; set; } 24 | 25 | public double BonusDamageMultiplier { get; set; } 26 | public double BonusBaseDamageMultiplier { get; set; } 27 | public double BonusCritChance { get; set; } 28 | public double BonusCritMultiplier { get; set; } 29 | 30 | public int GimmickGainPerSec { get; set; } 31 | public int EnergyGainPerSec { get; set; } 32 | 33 | public virtual void Activate(decimal round) 34 | { 35 | Cooldown = MaxCooldown; 36 | 37 | // Make it infinite if max duration is 0 38 | Duration = MaxDuration == 0 ? decimal.MaxValue : MaxDuration; 39 | ActivationRounds.Add(round); 40 | 41 | BonusCritChance = MaxBonusCritChance; 42 | BonusCritMultiplier = MaxBonusCritMultiplier; 43 | BonusDamageMultiplier = MaxBonusDamageMultiplier; 44 | BonusBaseDamageMultiplier = MaxBonusBaseDamageMultiplier; 45 | } 46 | 47 | public virtual bool CanActivate() 48 | { 49 | return Cooldown <= 0 && Duration <= 0; 50 | } 51 | 52 | public virtual void Deactivate(decimal round) 53 | { 54 | BonusCritChance = 0; 55 | BonusCritMultiplier = 0; 56 | BonusDamageMultiplier = 0; 57 | BonusBaseDamageMultiplier = 0; 58 | DeactivationRounds.Add(round); 59 | } 60 | } 61 | 62 | public class Debuff : Buff 63 | { 64 | public override void Activate(decimal round) 65 | { 66 | base.Activate(round); 67 | } 68 | 69 | public override bool CanActivate() 70 | { 71 | return base.CanActivate(); 72 | } 73 | 74 | public override void Deactivate(decimal round) 75 | { 76 | base.Deactivate(round); 77 | } 78 | } 79 | 80 | public class AbilityBuff : Buff 81 | { 82 | public override bool Active => Duration >= 0; 83 | 84 | public override void Activate(decimal round) 85 | { 86 | base.Activate(round); 87 | } 88 | 89 | public override bool CanActivate() 90 | { 91 | return false; 92 | } 93 | 94 | public override void Deactivate(decimal round) 95 | { 96 | base.Deactivate(round); 97 | } 98 | } 99 | } -------------------------------------------------------------------------------- /swlSimulator/api/Spells/Chaos/Active.cs: -------------------------------------------------------------------------------- 1 | using swlSimulator.api.Models; 2 | using swlSimulator.api.Weapons; 3 | 4 | namespace swlSimulator.api.Spells.Chaos 5 | { 6 | public class Deconstruct : Spell 7 | { 8 | public Deconstruct(IPlayer player, string args = null) 9 | { 10 | WeaponType = WeaponType.Chaos; 11 | AbilityType = AbilityType.Basic; 12 | BaseDamage = 1.175; 13 | SpellType = SpellType.Channel; 14 | ChannelTicks = 3; 15 | CastTime = 1; 16 | Args = args; 17 | } 18 | } 19 | public class Chism : Spell 20 | { 21 | public Chism(IPlayer player, string args = null) 22 | { 23 | WeaponType = WeaponType.Chaos; 24 | AbilityType = AbilityType.Power; 25 | PrimaryCost = 3; 26 | Args = args; 27 | BaseDamage = 1.26; 28 | 29 | // PBAoE 30 | } 31 | } 32 | public class Entropy : Spell 33 | { 34 | public Entropy(IPlayer player, string args = null) 35 | { 36 | WeaponType = WeaponType.Chaos; 37 | AbilityType = AbilityType.Special; 38 | PrimaryCost = 2; 39 | Args = args; 40 | // 10% Chaos Damage & 8.6% Critpower for 8 seconds. 41 | 42 | // PBAoE 43 | } 44 | } 45 | 46 | public class Breakdown : Spell 47 | { 48 | public Breakdown(IPlayer player, string args = null) 49 | { 50 | WeaponType = WeaponType.Chaos; 51 | AbilityType = AbilityType.Power; 52 | SpellType = SpellType.Channel; 53 | ChannelTicks = 4; 54 | CastTime = 1; 55 | BaseDamage = 0.8575; // 3.43 (4 hits) 56 | PrimaryCost = 5; 57 | Args = args; 58 | } 59 | } 60 | public class Pandemonium : Spell 61 | { 62 | public Pandemonium(IPlayer player, string args = null) 63 | { 64 | WeaponType = WeaponType.Chaos; 65 | AbilityType = AbilityType.Elite; 66 | BaseDamage = 5.8; 67 | PrimaryCost = 4; 68 | MaxCooldown = 20; 69 | Args = args; 70 | // PBAoE 71 | } 72 | } 73 | public class TumultousWhisper : Spell 74 | { 75 | public TumultousWhisper(IPlayer player, string args = null) 76 | { 77 | WeaponType = WeaponType.Chaos; 78 | AbilityType = AbilityType.Special; 79 | BaseDamage = 0.45; 80 | PrimaryCost = 2; 81 | Args = args; 82 | // AoE Purge 2x10m column And damage dealt by this WIKLL ALWAYS BE DIVISIBLE BY EIGHT... 83 | // Resulting in 2-4 paradoxes. (?) WHY? 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /swlSimulator/api/Spells/Chaos/Passives.cs: -------------------------------------------------------------------------------- 1 | using swlSimulator.api.Models; 2 | using swlSimulator.api.Weapons; 3 | 4 | namespace swlSimulator.api.Spells.Chaos 5 | { 6 | public class ParadoxControl : Passive 7 | { 8 | public ParadoxControl(IPlayer player, string args = null) 9 | { 10 | WeaponType = WeaponType.Chaos; 11 | SpellTypes.Add(typeof(Deconstruct)); 12 | // +1 Paradox for each Paradox generated by Schism. 13 | } 14 | } 15 | 16 | public class Dissolution : Passive 17 | { 18 | public Dissolution(IPlayer player, string args = null) 19 | { 20 | WeaponType = WeaponType.Chaos; 21 | SpellTypes.Add(typeof(Entropy)); 22 | // If you generate a paradox via %8 damage Entropy bonus gets set to 24% for the remainder of the duration.. 23 | } 24 | } 25 | 26 | public class Disintegrate : Passive 27 | { 28 | public Disintegrate(IPlayer player, string args = null) 29 | { 30 | WeaponType = WeaponType.Chaos; 31 | SpellTypes.Add(typeof(Breakdown)); 32 | BaseDamage = 0.1475; 33 | } 34 | } 35 | 36 | public class FracturedExistence : Passive 37 | { 38 | public FracturedExistence(IPlayer player, string args = null) 39 | { 40 | WeaponType = WeaponType.Chaos; 41 | SpellTypes.Add(typeof(Pandemonium)); 42 | BaseDamage = 2.75; 43 | } 44 | } 45 | 46 | public class Duality : Passive 47 | { 48 | public Duality(IPlayer player, string args = null) 49 | { 50 | WeaponType = WeaponType.Chaos; 51 | SpellTypes.Add(typeof(TumultousWhisper)); 52 | // If TumultousWHisper causes us to exceed 8 paradoxes... We get a Doppleganger(); 53 | // See chaos weapon modeling. (Weapons.Chaos.Doppleganger) 54 | } 55 | } 56 | 57 | public class ResonantCascade : Passive 58 | { 59 | public ResonantCascade(IPlayer player, string args = null) 60 | { 61 | WeaponType = WeaponType.Chaos; 62 | // (18.5% chance to generate 1 paradox) per second. 63 | } 64 | } 65 | 66 | public class BodyDouble : Passive 67 | { 68 | public BodyDouble(IPlayer player, string args = null) 69 | { 70 | WeaponType = WeaponType.Chaos; 71 | SpellTypes.Add(typeof(Weapons.Chaos.Doppleganger)); 72 | BaseDamageModifier = 1.25; // 125% damage. 73 | } 74 | } 75 | 76 | public class EyeOfTheRuinStorm : Passive 77 | { 78 | public EyeOfTheRuinStorm(IPlayer player, string args = null) 79 | { 80 | WeaponType = WeaponType.Chaos; 81 | SpellTypes.Add(typeof(Weapons.Chaos.Singularity)); 82 | BaseDamage = 1.68; 83 | // Singularity Base Damage increased to 4.35 84 | } 85 | } 86 | 87 | public class ButterflyEffect : Passive 88 | { 89 | public ButterflyEffect(IPlayer player, string args = null) 90 | { 91 | WeaponType = WeaponType.Chaos; 92 | // Whenever you deal damage with chaos abilities - 93 | // we have 10% to deal 0.58 * CP and +1 Paradox 94 | } 95 | } 96 | 97 | public class BlessingOfOcted : Passive 98 | { 99 | public BlessingOfOcted(IPlayer player, string args = null) 100 | { 101 | WeaponType = WeaponType.Chaos; 102 | // The chance of dealing damage divislbe by 8 increases by 6.25% ...... 103 | } 104 | } 105 | } -------------------------------------------------------------------------------- /swlSimulator/api/Spells/Fist/Active.cs: -------------------------------------------------------------------------------- 1 | using swlSimulator.api.Models; 2 | using swlSimulator.api.Weapons; 3 | 4 | namespace swlSimulator.api.Spells.Fist 5 | { 6 | public class Basic : Spell 7 | { 8 | public Basic(IPlayer player, string args = null) 9 | { 10 | WeaponType = WeaponType.Fist; 11 | AbilityType = AbilityType.Basic; 12 | BaseDamage = 1.175; 13 | Args = args; 14 | } 15 | } 16 | 17 | public class Trash : Spell 18 | { 19 | public Trash(IPlayer player, string args = null) 20 | { 21 | WeaponType = WeaponType.Fist; 22 | AbilityType = AbilityType.Basic; 23 | SpellType = SpellType.Channel; 24 | CastTime = 1; 25 | ChannelTicks = 2; 26 | Args = args; 27 | PrimaryGimmickGain = 4; 28 | BaseDamage = 1.175; 29 | // Striking 2 Times 30 | } 31 | } 32 | 33 | public class SavageSweep : Spell 34 | { 35 | public SavageSweep(IPlayer player, string args = null) 36 | { 37 | WeaponType = WeaponType.Fist; 38 | Args = args; 39 | PrimaryCost = 3; 40 | PrimaryGimmickGain = 3; 41 | BaseDamage = 1.26; 42 | } 43 | } 44 | 45 | public class FrenziedWrath : Spell 46 | { 47 | public FrenziedWrath(IPlayer player, string args = null) 48 | { 49 | WeaponType = WeaponType.Fist; 50 | Args = args; 51 | PrimaryGimmickCost = 60; 52 | MaxCooldown = 5; 53 | // TODO: Is there a spell with this name u can activate??? 54 | 55 | // TODO: Activate FrenziedWrath buff 56 | // 2 Self Cleanse 57 | } 58 | } 59 | 60 | public class Ravage : Spell 61 | { 62 | public Ravage(IPlayer player, string args = null) 63 | { 64 | WeaponType = WeaponType.Fist; 65 | Args = args; 66 | BaseDamage = 1.26; 67 | // TODO: 5s Dot 0,59CP 68 | } 69 | } 70 | 71 | public class Shred : Spell 72 | { 73 | public Shred(IPlayer player, string args = null) 74 | { 75 | WeaponType = WeaponType.Fist; 76 | Args = args; 77 | BaseDamage = 1.05; 78 | // TODO: 5s Dot 0,125CP, If maim active 0,42CP PBAoE 79 | } 80 | } 81 | 82 | public class Maim : Spell 83 | { 84 | public Maim(IPlayer player, string args = null) 85 | { 86 | WeaponType = WeaponType.Fist; 87 | Args = args; 88 | PrimaryCost = 4; 89 | MaxCooldown = 15; 90 | BaseDamage = 0.24; 91 | // TODO: 15s Dot 0,386CP 92 | } 93 | } 94 | 95 | public class Mangle : Spell 96 | { 97 | public Mangle(IPlayer player, string args = null) 98 | { 99 | WeaponType = WeaponType.Fist; 100 | Args = args; 101 | PrimaryCost = 5; 102 | PrimaryGimmickGain = 12; 103 | BaseDamage = 3.43; 104 | } 105 | } 106 | 107 | public class Berserk : Spell 108 | { 109 | public Berserk(IPlayer player, string args = null) 110 | { 111 | WeaponType = WeaponType.Fist; 112 | Args = args; 113 | PrimaryCost = 4; 114 | PrimaryGimmickGain = 22; 115 | BaseDamage = 7.10; 116 | // TODO: Exposed, Root, +2 Fury per hit, 2.5s Channel 117 | } 118 | } 119 | 120 | public class Eviscerate : Spell 121 | { 122 | public Eviscerate(IPlayer player, string args = null) 123 | { 124 | WeaponType = WeaponType.Fist; 125 | Args = args; 126 | PrimaryCost = 2; 127 | PrimaryGimmickGain = 3; 128 | MaxCooldown = 20; 129 | BaseDamage = 2.7; 130 | //Exposed, 3s Stun 131 | } 132 | } 133 | 134 | public class Ferocity : Spell 135 | { 136 | public Ferocity(IPlayer player, string args = null) 137 | { 138 | WeaponType = WeaponType.Fist; 139 | Args = args; 140 | PrimaryCost = 2; 141 | MaxCooldown = 20; 142 | BaseDamage = 2.9; 143 | // TODO: Remove all fist dots and cause them to deal their remaining damage 144 | } 145 | } 146 | 147 | public class Savagery : Spell 148 | { 149 | public Savagery(IPlayer player, string args = null) 150 | { 151 | WeaponType = WeaponType.Fist; 152 | SpellType = SpellType.Instant; 153 | Args = args; 154 | PrimaryCost = 2; 155 | PrimaryGimmickGain = 8; 156 | MaxCooldown = 20; 157 | AbilityBuff = player.GetAbilityBuffFromName(Name) as AbilityBuff; 158 | } 159 | } 160 | 161 | public class PrimalInstinct : Spell 162 | { 163 | public PrimalInstinct(IPlayer player, string args = null) 164 | { 165 | WeaponType = WeaponType.Fist; 166 | Args = args; 167 | PrimaryCost = 4; 168 | PrimaryGimmickGain = 18; 169 | MaxCooldown = 20; 170 | // TODO: 6s 215% Dot damage 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /swlSimulator/api/Spells/Fist/Buffs/Buff.cs: -------------------------------------------------------------------------------- 1 | using swlSimulator.api.Weapons; 2 | 3 | namespace swlSimulator.api.Spells.Fist.Buffs 4 | { 5 | public class Savagery : AbilityBuff 6 | { 7 | public Savagery() 8 | { 9 | WeaponType = WeaponType.Fist; 10 | MaxDuration = 6; 11 | MaxCooldown = 20; 12 | MaxBonusBaseDamageMultiplier = 0.15; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /swlSimulator/api/Spells/Fist/Passive.cs: -------------------------------------------------------------------------------- 1 | using swlSimulator.api.Models; 2 | using swlSimulator.api.Weapons; 3 | 4 | namespace swlSimulator.api.Spells.Fist 5 | { 6 | public class Rip : Spell 7 | { 8 | public Rip(IPlayer player, string args = null) 9 | { 10 | WeaponType = WeaponType.Fist; 11 | SpellType = SpellType.Passive; 12 | BaseDamage = 0; 13 | // Savage Sweep: PBAoE 0,077CP Dot every 1s for 5s 14 | } 15 | } 16 | 17 | public class Gore : Spell 18 | { 19 | public Gore(IPlayer player, string args = null) 20 | { 21 | WeaponType = WeaponType.Fist; 22 | SpellType = SpellType.Passive; 23 | BaseDamage = 0; 24 | // New ability in Frenzied Wrath, Charge: 15m must be atleast 1m away, 25 | // TAoE 1.21CP, 0,38CP Dot every 0.5s for 5s 26 | } 27 | } 28 | 29 | public class Maul : Spell 30 | { 31 | public Maul(IPlayer player, string args = null) 32 | { 33 | WeaponType = WeaponType.Fist; 34 | SpellType = SpellType.Passive; 35 | BaseDamage = 0; 36 | // Mangle: 0,11CP Dot every 1s for 5s 37 | } 38 | } 39 | 40 | public class Rampage : Spell 41 | { 42 | public Rampage(IPlayer player, string args = null) 43 | { 44 | WeaponType = WeaponType.Fist; 45 | SpellType = SpellType.Passive; 46 | BaseDamage = 0; 47 | // Berserk: 5s Stun, If fist dot active increase damage to 0.95CP 48 | } 49 | } 50 | 51 | public class Bloodbath : Spell 52 | { 53 | public Bloodbath(IPlayer player, string args = null) 54 | { 55 | WeaponType = WeaponType.Fist; 56 | SpellType = SpellType.Passive; 57 | BaseDamage = 0; 58 | // Eviscerate: If successfull interrupt 0,38CP Dot every 1s for 5s 59 | } 60 | } 61 | 62 | public class Brutality : Spell 63 | { 64 | public Brutality(IPlayer player, string args = null) 65 | { 66 | WeaponType = WeaponType.Fist; 67 | SpellType = SpellType.Passive; 68 | BaseDamage = 0; 69 | // Ferocity: If used in conjunction with fist dot 0,52CP Dot every 1s for 5s 70 | } 71 | } 72 | 73 | public class KillerInstinct : Spell 74 | { 75 | public KillerInstinct(IPlayer player, string args = null) 76 | { 77 | WeaponType = WeaponType.Fist; 78 | SpellType = SpellType.Passive; 79 | BaseDamage = 0; 80 | // 50% Dot Crit BaseDamage during Primal Instinct 81 | } 82 | } 83 | 84 | public class Furor : Spell 85 | { 86 | public Furor(IPlayer player, string args = null) 87 | { 88 | WeaponType = WeaponType.Fist; 89 | SpellType = SpellType.Passive; 90 | BaseDamage = 0; 91 | // Whenever you use 3 Fist power in succession gain 3 Fury 92 | } 93 | } 94 | 95 | public class SecondWind : Spell 96 | { 97 | public SecondWind(IPlayer player, string args = null) 98 | { 99 | WeaponType = WeaponType.Fist; 100 | SpellType = SpellType.Passive; 101 | BaseDamage = 0; 102 | // Whenever Frenzied Wrath ends gain 4 Fist Energy 103 | } 104 | } 105 | 106 | public class SmellFear : Spell 107 | { 108 | public SmellFear(IPlayer player, string args = null) 109 | { 110 | WeaponType = WeaponType.Fist; 111 | SpellType = SpellType.Passive; 112 | BaseDamage = 0; 113 | // Whenever you enter combat and every 8s afterwards sense fear in a nearby enemy, 114 | // Fist Power abilites generates 8 Fury 115 | } 116 | } 117 | 118 | public class BloodyMist : Spell 119 | { 120 | public BloodyMist(IPlayer player, string args = null) 121 | { 122 | WeaponType = WeaponType.Fist; 123 | SpellType = SpellType.Passive; 124 | BaseDamage = 0; 125 | // Whenever you Crit with Fist abilities deal an additional 0.26CP BaseDamage 126 | } 127 | } 128 | 129 | public class PotentWrath : Spell 130 | { 131 | public PotentWrath(IPlayer player, string args = null) 132 | { 133 | WeaponType = WeaponType.Fist; 134 | SpellType = SpellType.Passive; 135 | BaseDamage = 0; 136 | // Whenever Frenzied Wrath ends PBAoE 0,19Cp Dot every 1s for 5s 137 | } 138 | } 139 | 140 | public class KeenSenses : Spell 141 | { 142 | public KeenSenses(IPlayer player, string args = null) 143 | { 144 | WeaponType = WeaponType.Fist; 145 | SpellType = SpellType.Passive; 146 | BaseDamage = 0; 147 | // Enemy health below 35% Deal additional 0,26CP BaseDamage 148 | } 149 | } 150 | 151 | public class WildNature : Passive 152 | { 153 | public WildNature(IPlayer player, string args = null) 154 | { 155 | WeaponType = WeaponType.Fist; 156 | BaseDamage = 0; 157 | PrimaryGain = 1; 158 | 159 | // TODO: 1 Fury per sec in combat 160 | } 161 | } 162 | } -------------------------------------------------------------------------------- /swlSimulator/api/Spells/Hammer/Active.cs: -------------------------------------------------------------------------------- 1 | using swlSimulator.api.Models; 2 | using swlSimulator.api.Weapons; 3 | 4 | namespace swlSimulator.api.Spells.Hammer 5 | { 6 | public class Smash : Spell 7 | { 8 | public Smash(IPlayer player, string args = null) 9 | { 10 | WeaponType = WeaponType.Hammer; 11 | AbilityType = AbilityType.Basic; 12 | BaseDamage = 1.175; 13 | Args = args; 14 | PrimaryGimmickGain = 5; 15 | } 16 | } 17 | public class RazorShards : Spell 18 | { 19 | public RazorShards(IPlayer player, string args = null) 20 | { 21 | WeaponType = WeaponType.Hammer; 22 | Args = args; 23 | PrimaryCost = 3; 24 | PrimaryGimmickGain = 6; // Per Target 25 | BaseDamage = 1.26; 26 | // TODO: 5s Dot 0,89CP 27 | } 28 | } 29 | public class RazorShardsRage : Spell 30 | { 31 | public RazorShardsRage(IPlayer player, string args = null) 32 | { 33 | WeaponType = WeaponType.Hammer; 34 | SpellType = SpellType.Dot; // TODO: No initial dmg only dot? 35 | Args = args; 36 | PrimaryCost = 3; 37 | PrimaryGimmickCost = 50; 38 | BaseDamage = 1; 39 | // TODO: 5s Dot 0,89CP 40 | } 41 | } 42 | 43 | 44 | public class Seethe : Spell 45 | { 46 | public Seethe(IPlayer player, string args = null) 47 | { 48 | WeaponType = WeaponType.Hammer; 49 | SpellType = SpellType.Instant; 50 | Args = args; 51 | PrimaryGain = 4; 52 | MaxCooldown = 20; 53 | } 54 | } 55 | 56 | public class Demolish : Spell 57 | { 58 | public Demolish(IPlayer player, string args = null) 59 | { 60 | WeaponType = WeaponType.Hammer; 61 | AbilityType = AbilityType.Power; 62 | Args = args; 63 | PrimaryCost = 5; 64 | PrimaryGimmickGain = 25; 65 | BaseDamage = 3.43; 66 | } 67 | } 68 | 69 | public class DemolishRage : Spell 70 | { 71 | public DemolishRage(IPlayer player, string args = null) 72 | { 73 | WeaponType = WeaponType.Hammer; 74 | AbilityType = AbilityType.Power; 75 | Args = args; 76 | PrimaryCost = 5; 77 | PrimaryGimmickCost = 50; 78 | BaseDamage = 8.38; 79 | } 80 | } 81 | 82 | public class Eruption : Spell 83 | { 84 | public Eruption(IPlayer player, string args = null) 85 | { 86 | WeaponType = WeaponType.Hammer; 87 | Args = args; 88 | PrimaryCost = 4; 89 | PrimaryGimmickGain = 7; 90 | MaxCooldown = 20; 91 | BaseDamage = 5.6; 92 | // TODO: Stun, Purge, Exposed, +7Rage per target, Column 6 Enemies 93 | } 94 | } 95 | 96 | public class EruptionRage : Spell 97 | { 98 | public EruptionRage(IPlayer player, string args = null) 99 | { 100 | WeaponType = WeaponType.Hammer; 101 | Args = args; 102 | PrimaryCost = 4; 103 | PrimaryGimmickGain = 7; 104 | MaxCooldown = 20; 105 | PrimaryGimmickCost = 50; 106 | BaseDamage = 5.6; 107 | // TODO: Stun, Purge, Exposed, +7 Rage per target, Column 6 Enemies 108 | } 109 | } 110 | 111 | public class Rampage : Spell 112 | { 113 | public Rampage(IPlayer player, string args = null) 114 | { 115 | WeaponType = WeaponType.Hammer; 116 | Args = args; 117 | PrimaryCost = 2; 118 | PrimaryGimmickGain = 9; 119 | MaxCooldown = 20; 120 | BaseDamage = 0.62; 121 | //Exposed, PBAoE 6 Enemies 122 | } 123 | } 124 | 125 | public class UnstoppableForce : Spell 126 | { 127 | public UnstoppableForce(IPlayer player, string args = null) 128 | { 129 | WeaponType = WeaponType.Hammer; 130 | AbilityType = AbilityType.Elite; 131 | SpellType = SpellType.Instant; 132 | Args = args; 133 | PrimaryCost = 4; 134 | MaxCooldown = 20; 135 | AbilityBuff = player.GetAbilityBuffFromName(Name) as AbilityBuff; 136 | } 137 | } 138 | 139 | public class Blindside : Spell 140 | { 141 | public Blindside(IPlayer player, string args = null) 142 | { 143 | WeaponType = WeaponType.Hammer; 144 | Args = args; 145 | PrimaryCost = 2; 146 | PrimaryGimmickGain = 10; 147 | MaxCooldown = 20; 148 | BaseDamage = 2.57; 149 | //Purge, Interrupt 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /swlSimulator/api/Spells/Hammer/Buffs/Buff.cs: -------------------------------------------------------------------------------- 1 | using swlSimulator.api.Weapons; 2 | 3 | namespace swlSimulator.api.Spells.Hammer.Buffs 4 | { 5 | public class UnstoppableForce : AbilityBuff 6 | { 7 | public UnstoppableForce() 8 | { 9 | MaxDuration = 8; 10 | MaxBonusBaseDamageMultiplier = 0.2; 11 | GimmickGainPerSec = 3; 12 | WeaponType = WeaponType.Hammer; 13 | SpecificWeaponTypeBonus = true; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /swlSimulator/api/Spells/IBuff.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using swlSimulator.api.Weapons; 3 | 4 | namespace swlSimulator.api.Spells 5 | { 6 | public interface IBuff 7 | { 8 | string Name { get; } 9 | decimal MaxDuration { get; set; } 10 | decimal Duration { get; set; } 11 | decimal MaxCooldown { get; } 12 | decimal Cooldown { get; set; } 13 | bool Active { get; } 14 | List ActivationRounds { get; } 15 | 16 | WeaponType WeaponType { get; } 17 | bool SpecificWeaponTypeBonus { get; } 18 | 19 | double MaxBonusCritChance { get; } 20 | double MaxBonusCritMultiplier { get; } 21 | double MaxBonusDamageMultiplier { get; } 22 | double MaxBonusBaseDamageMultiplier { get; } 23 | 24 | double BonusCritChance { get; } 25 | double BonusCritMultiplier { get; } 26 | double BonusDamageMultiplier { get; } 27 | double BonusBaseDamageMultiplier { get; } 28 | 29 | int GimmickGainPerSec { get; } 30 | int EnergyGainPerSec { get; } 31 | 32 | void Activate(decimal round); 33 | bool CanActivate(); 34 | void Deactivate(decimal round); 35 | List DeactivationRounds { get; } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /swlSimulator/api/Spells/ISpell.cs: -------------------------------------------------------------------------------- 1 | using swlSimulator.api.Combat; 2 | using swlSimulator.api.Models; 3 | using swlSimulator.api.Weapons; 4 | 5 | namespace swlSimulator.api.Spells 6 | { 7 | public interface ISpell 8 | { 9 | string Name { get; } 10 | double BaseDamage { get; set; } 11 | decimal DotDuration { get; set; } 12 | double DotExpirationBaseDamage { get; set; } 13 | double BaseDamageCrit { get; set; } 14 | WeaponType WeaponType { get; } 15 | SpellType SpellType { get; } 16 | AbilityType AbilityType { get; } 17 | ElementalType ElementalType { get; } 18 | int PrimaryCost { get; set; } 19 | int SecondaryCost { get; set; } 20 | int PrimaryGain { get; set; } 21 | int SecondaryGain { get; set; } 22 | int PrimaryGimmickCost { get; set; } 23 | int PrimaryGimmickReduce { get; set; } 24 | int SecondaryGimmickCost { get; set; } 25 | int SecondaryGimmickReduce { get; set; } 26 | int PrimaryGimmickGain { get; set; } 27 | int SecondaryGimmickGain { get; set; } 28 | int PrimaryGimmickRequirement { get; set; } 29 | int PrimaryGimmickGainOnCrit { get; set; } 30 | decimal MaxCooldown { get; set; } 31 | decimal Cooldown { get; set; } 32 | decimal CastTime { get; set; } 33 | int ChannelTicks { get; set; } 34 | int DotTicks { get; set; } 35 | double BonusCritChance { get; set; } 36 | double BonusCritPower { get; set; } 37 | string Args { get; } 38 | Passive PassiveBonusSpell { get; set; } 39 | AbilityBuff AbilityBuff { get; set; } 40 | Attack Execute(Player player); 41 | bool CanExecute(Player player); 42 | } 43 | } -------------------------------------------------------------------------------- /swlSimulator/api/Spells/Passive.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using swlSimulator.api.Models; 5 | 6 | namespace swlSimulator.api.Spells 7 | { 8 | public class Passive : Spell 9 | { 10 | public override SpellType SpellType { get; set; } = SpellType.Passive; 11 | public List SpellTypes { get; set; } = new List(); 12 | public List SpecificSpellTypes { get; set; } = new List(); 13 | public bool SpecificWeaponTypeBonus { get; set; } 14 | public double BaseDamageModifier { get; set; } 15 | public double BaseDamageCritModifier { get; set; } 16 | public bool BonusSpellOnlyOnCrit { get; set; } 17 | public bool ModelledInWeapon { get; set; } 18 | 19 | public virtual void Init(IPlayer player) 20 | { 21 | } 22 | 23 | public void LoopSpellsFromPassive(IPlayer player) 24 | { 25 | // Get spells that are modified by this passive 26 | foreach (var spellType in SpellTypes) 27 | { 28 | // Since this is APL there can be several instances of each spell. Modify them all. 29 | var spells = player.Spells.Where(s => s.GetType() == spellType); 30 | 31 | foreach (var spell in spells) 32 | ModifySpellWithPassive(spell); 33 | } 34 | } 35 | 36 | public void ModifySpellWithPassive(ISpell spell) 37 | { 38 | // To not add passive bonus spell stats onto the spell itself 39 | if (PassiveBonusSpell != null) 40 | { 41 | spell.PassiveBonusSpell = PassiveBonusSpell; 42 | return; 43 | } 44 | 45 | // ISpell members 46 | spell.PrimaryGimmickCost += PrimaryGimmickCost; 47 | spell.SecondaryGimmickCost += SecondaryGimmickCost; 48 | spell.PrimaryGimmickGain += PrimaryGimmickGain; 49 | spell.SecondaryGimmickGain += SecondaryGimmickGain; 50 | spell.PrimaryGimmickGainOnCrit += PrimaryGimmickGainOnCrit; 51 | spell.BaseDamage += BaseDamage; 52 | spell.BaseDamageCrit += BaseDamageCrit; 53 | spell.PrimaryCost += PrimaryCost; 54 | spell.SecondaryCost += SecondaryCost; 55 | spell.PrimaryGain += PrimaryGain; 56 | spell.SecondaryGain += SecondaryGain; 57 | spell.MaxCooldown += MaxCooldown; 58 | spell.CastTime += CastTime; 59 | spell.ChannelTicks += ChannelTicks; 60 | spell.BonusCritChance += BonusCritChance; 61 | spell.BonusCritPower += BonusCritPower; 62 | //spell.PassiveBonusSpell = PassiveBonusSpell; 63 | 64 | // Passive specials 65 | spell.BaseDamage *= 1 + BaseDamageModifier; 66 | spell.BaseDamageCrit *= 1 + BaseDamageCritModifier; 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /swlSimulator/api/Spells/Passives.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using swlSimulator.api.Spells.Blade; 4 | using swlSimulator.api.Spells.Blood; 5 | using swlSimulator.api.Spells.Hammer; 6 | using swlSimulator.api.Spells.Pistol; 7 | using swlSimulator.api.Spells.Shotgun; 8 | using swlSimulator.Models; 9 | 10 | namespace swlSimulator.api.Spells 11 | { 12 | public static class Passives 13 | { 14 | public static List AllPassives = new List 15 | { 16 | // TODO: Add ALL passives here 17 | 18 | // Blade 19 | new HardenedBlade(), 20 | new EyeOfTheStorm(), 21 | new StormSurge(), 22 | new Deluge(), 23 | 24 | // Hammer 25 | new Outrage(), 26 | new Obliterate(), 27 | new Berserker(), 28 | new Annihilate(), 29 | new UnbridledWrath(), 30 | new LetLoose(), 31 | new FastAndFurious(), 32 | 33 | // Pistol 34 | new FatalShot(), 35 | new DeadlyDance(), 36 | new Jackpot(), 37 | new FixedGame(), 38 | new HeavyCaliberRounds(), 39 | new FullyLoaded(), 40 | new WinStreak(), 41 | new FlechetteRounds(), 42 | new BeginnersLuck(), 43 | new BulletEcho(), 44 | new Holdout(), 45 | new LethalAim(), 46 | 47 | // Blood 48 | new CrimsonPulse(), 49 | new Desolate(), 50 | new Contaminate(), 51 | new Flay(), 52 | new Defilement(), 53 | 54 | // Shotgun 55 | new SalvageExpert(), 56 | new PointBlankShot() 57 | }; 58 | 59 | public static List GetSelectedPassives(Settings settings) 60 | { 61 | var stringPassives = new List 62 | { 63 | settings.Passive1, 64 | settings.Passive2, 65 | settings.Passive3, 66 | settings.Passive4, 67 | settings.Passive5 68 | }; 69 | 70 | return stringPassives.Select(sPassive => AllPassives.Find(p => p.Name == sPassive)) 71 | .Where(passive => passive != null).ToList(); 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /swlSimulator/api/Spells/Pistol/Buffs/Buff.cs: -------------------------------------------------------------------------------- 1 | using swlSimulator.api.Weapons; 2 | 3 | namespace swlSimulator.api.Spells.Pistol.Buffs 4 | { 5 | public class Flourish : AbilityBuff 6 | { 7 | public Flourish() 8 | { 9 | MaxDuration = 6; 10 | MaxBonusBaseDamageMultiplier = 0.15; 11 | WeaponType = WeaponType.Pistol; 12 | SpecificWeaponTypeBonus = true; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /swlSimulator/api/Spells/Rifle/Active.cs: -------------------------------------------------------------------------------- 1 | using swlSimulator.api.Models; 2 | using swlSimulator.api.Weapons; 3 | 4 | namespace swlSimulator.api.Spells.Rifle 5 | { 6 | public class PlacedShot : Spell 7 | { 8 | public PlacedShot(IPlayer player, string args = null) 9 | { 10 | WeaponType = WeaponType.Rifle; 11 | BaseDamage = 1.17; 12 | Args = args; 13 | } 14 | } 15 | 16 | public class FullAuto : Spell 17 | { 18 | public FullAuto(IPlayer player, string args = null) 19 | { 20 | WeaponType = WeaponType.Rifle; 21 | AbilityType = AbilityType.Power; 22 | SpellType = SpellType.Channel; 23 | CastTime = 1; 24 | ChannelTicks = 4; 25 | PrimaryCost = 3; 26 | BaseDamage = 0.31; //Multihit 4times 0.31CP 27 | Args = args; 28 | } // 37.5% Chance to load grenade. 29 | } 30 | 31 | public class LockAndLoad : Spell 32 | { 33 | public LockAndLoad(IPlayer player, string args = null) 34 | { 35 | WeaponType = WeaponType.Rifle; 36 | AbilityType = AbilityType.Special; 37 | SpellType = SpellType.Instant; 38 | PrimaryGain = 4; 39 | MaxCooldown = 20; 40 | Args = args; 41 | } 42 | } 43 | 44 | public class BurstFire : Spell 45 | { 46 | public BurstFire(IPlayer player, string args = null) 47 | { 48 | WeaponType = WeaponType.Rifle; 49 | AbilityType = AbilityType.Power; 50 | SpellType = SpellType.Channel; 51 | CastTime = 1; 52 | ChannelTicks = 3; 53 | PrimaryCost = 5; 54 | BaseDamage = 1.14; //Multihit 3times 1.14CP 55 | Args = args; 56 | } //65% Chance to load grenade. 57 | } 58 | 59 | public class RedMist : Spell 60 | { 61 | public RedMist(IPlayer player, string args = null) 62 | { 63 | WeaponType = WeaponType.Rifle; 64 | AbilityType = AbilityType.Elite; 65 | SpellType = SpellType.Cast; 66 | CastTime = 2.0m; 67 | PrimaryCost = 4; 68 | MaxCooldown = 20; 69 | BaseDamage = 6.97; 70 | Args = args; 71 | } 72 | } 73 | 74 | public class IncendiaryGrenade : Spell 75 | { 76 | public IncendiaryGrenade(IPlayer player, string args = null) 77 | { 78 | WeaponType = WeaponType.Rifle; 79 | AbilityType = AbilityType.Special; 80 | SpellType = SpellType.Dot; 81 | PrimaryCost = 2; 82 | PrimaryGimmickCost = 1; 83 | MaxCooldown = 4; 84 | BaseDamage = 0.51; 85 | DotDuration = 8; 86 | Args = args; 87 | } // Uncooked Damage: 0.13CP, Requires a grenade to activate. GTAoE 88 | } 89 | 90 | public class TacticalRetreat : Spell 91 | { 92 | public TacticalRetreat(IPlayer player, string args = null) 93 | { 94 | WeaponType = WeaponType.Rifle; 95 | AbilityType = AbilityType.Special; 96 | PrimaryCost = 2; 97 | MaxCooldown = 20; 98 | BaseDamage = 4.09; 99 | Args = args; 100 | } // 5m Dash backwards, If used with grenade active distance increased to 10m and CD reduced to 4s(can only happen every 15s) 101 | 102 | // Uncooked Damage: 1.03CP, 70% slow 4s 103 | } 104 | 105 | public class HighExplosiveGrenade : Spell 106 | { 107 | public HighExplosiveGrenade(IPlayer player, string args = null) 108 | { 109 | WeaponType = WeaponType.Rifle; 110 | AbilityType = AbilityType.Elite; 111 | SpellType = SpellType.Dot; 112 | PrimaryCost = 4; 113 | PrimaryGimmickCost = 1; 114 | MaxCooldown = 20; 115 | BaseDamage = 1.48; 116 | DotDuration = 8; 117 | Args = args; 118 | } // Uncooked damage: 0.72CP, Requires a grenade to activate, TAoE 119 | } 120 | } -------------------------------------------------------------------------------- /swlSimulator/api/Spells/Rifle/Passive.cs: -------------------------------------------------------------------------------- 1 | using swlSimulator.api.Models; 2 | using swlSimulator.api.Weapons; 3 | 4 | namespace swlSimulator.api.Spells.Rifle 5 | { 6 | public class ExtendedMagazine : Passive 7 | { 8 | public ExtendedMagazine() 9 | { 10 | WeaponType = WeaponType.Rifle; 11 | SpellTypes.Add(typeof(FullAuto)); 12 | ChannelTicks = 1; 13 | // TODO: Test 14 | // Increase number of hits to 5 from 4 15 | } 16 | } 17 | 18 | public class HeavyPayload : Passive 19 | { 20 | public HeavyPayload(IPlayer player, string args = null) 21 | { 22 | WeaponType = WeaponType.Rifle; 23 | SpellTypes.Add(typeof(LockAndLoad)); 24 | // 41% chance to load a grenade on use 25 | } 26 | } 27 | 28 | public class Stability : Passive 29 | { 30 | public Stability(IPlayer player, string args = null) 31 | { 32 | WeaponType = WeaponType.Rifle; 33 | SpellTypes.Add(typeof(BurstFire)); 34 | // Each successive hit to deal 25% more base damage 35 | } 36 | } 37 | 38 | public class UnerringAccuracy : Passive 39 | { 40 | public UnerringAccuracy() 41 | { 42 | WeaponType = WeaponType.Rifle; 43 | SpellTypes.Add(typeof(RedMist)); 44 | BaseDamageCritModifier = 0.68; 45 | // Critical hits deal 68 % more damage 46 | // TODO: Test and add: Can no longer glance or evade 47 | } 48 | } 49 | 50 | public class SlowBurn : Passive 51 | { 52 | public SlowBurn(IPlayer player, string args = null) 53 | { 54 | WeaponType = WeaponType.Rifle; 55 | SpellTypes.Add(typeof(IncendiaryGrenade)); 56 | DotDuration = 3; 57 | // TODO: Test 58 | // Increasing duration to 11s from 8s 59 | } 60 | } 61 | 62 | public class AutoLoader : Passive 63 | { 64 | public AutoLoader(IPlayer player, string args = null) 65 | { 66 | WeaponType = WeaponType.Rifle; 67 | SpellTypes.Add(typeof(HighExplosiveGrenade)); 68 | // After using High Explosive Grenade next grenade gen ability gets 100% chance to load a grenade 69 | } 70 | } 71 | 72 | public class ExplosivesExpert : Passive 73 | { 74 | public ExplosivesExpert(IPlayer player, string args = null) 75 | { 76 | WeaponType = WeaponType.Rifle; 77 | // Grenade fuse time now 9s and fully cooked with 6s remaining 78 | // If a grenade detonates before launch no selfharm and nearby enemies take 0.44CP 79 | } 80 | } 81 | 82 | public class SecondaryExplosion : Passive 83 | { 84 | public SecondaryExplosion(IPlayer player, string args = null) 85 | { 86 | WeaponType = WeaponType.Rifle; 87 | // Extra explosives 1.5s after every grenade ability dealing 0.44Cp within 2m of original target 88 | } 89 | } 90 | 91 | public class BackupPlan : Passive 92 | { 93 | public BackupPlan(IPlayer player, string args = null) 94 | { 95 | WeaponType = WeaponType.Rifle; 96 | // If you load a grenade while one is already cooking gain 10% AR damage for 4s 97 | } 98 | } 99 | 100 | public class EmergencyLoader : Passive 101 | { 102 | public EmergencyLoader(IPlayer player, string args = null) 103 | { 104 | WeaponType = WeaponType.Rifle; 105 | // Whenever you are below 85% health Chance to load grenades is incresed to 45% 106 | // when using Full Auto and 80% when using Burst Fire 107 | } 108 | } 109 | 110 | public class JungleStyle : Passive 111 | { 112 | public JungleStyle(IPlayer player, string args = null) 113 | { 114 | WeaponType = WeaponType.Rifle; 115 | // Whenever you run out of AR energy you gain 1 AR energy 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /swlSimulator/api/Spells/Shotgun/Active.cs: -------------------------------------------------------------------------------- 1 | using swlSimulator.api.Combat; 2 | using swlSimulator.api.Models; 3 | using swlSimulator.api.Weapons; 4 | 5 | namespace swlSimulator.api.Spells.Shotgun 6 | { 7 | public class PumpAction : Spell 8 | { 9 | public PumpAction(IPlayer player, string args = null) 10 | { 11 | WeaponType = WeaponType.Shotgun; 12 | AbilityType = AbilityType.Basic; 13 | PrimaryGimmickCost = 1; 14 | BaseDamage = 1.17; 15 | Args = args; 16 | } 17 | } 18 | 19 | public class BothBarrels : Spell 20 | { 21 | public BothBarrels(IPlayer player, string args = null) 22 | { 23 | WeaponType = WeaponType.Shotgun; 24 | AbilityType = AbilityType.Power; 25 | PrimaryCost = 3; 26 | PrimaryGimmickCost = 1; 27 | BaseDamage = 1.26; 28 | Args = args; 29 | } 30 | } 31 | 32 | public class OpeningShot : Spell 33 | { 34 | public OpeningShot(IPlayer player, string args = null) 35 | { 36 | WeaponType = WeaponType.Shotgun; 37 | AbilityType = AbilityType.Special; 38 | SpellType = SpellType.Instant; 39 | PrimaryCost = 2; 40 | PrimaryGimmickCost = 1; 41 | MaxCooldown = 20; 42 | Args = args; 43 | } // TODO: 30% Crit Power 8s Entire Group. 44 | } 45 | 46 | public class RagingShot : Spell 47 | { 48 | public RagingShot(IPlayer player, string args = null) 49 | { 50 | WeaponType = WeaponType.Shotgun; 51 | AbilityType = AbilityType.Power; 52 | PrimaryCost = 5; 53 | PrimaryGimmickCost = 1; 54 | BaseDamage = 3.42; 55 | Args = args; 56 | } 57 | } 58 | 59 | public class FullSalvo : Spell 60 | { 61 | public FullSalvo(IPlayer player, string args = null) 62 | { 63 | WeaponType = WeaponType.Shotgun; 64 | AbilityType = AbilityType.Elite; 65 | SpellType = SpellType.Channel; 66 | CastTime = 2.5m; 67 | ChannelTicks = 5; 68 | PrimaryCost = 4; 69 | PrimaryGimmickCost = 5; 70 | MaxCooldown = 20; 71 | BaseDamage = 1.51; // Channel 5 hits 1.51 per hit. 72 | Args = args; 73 | } 74 | } 75 | 76 | public class ShellSalvage : Spell 77 | { 78 | public ShellSalvage(IPlayer player, string args = null) 79 | { 80 | WeaponType = WeaponType.Shotgun; 81 | AbilityType = AbilityType.Special; 82 | SpellType = SpellType.Instant; 83 | // Gain 3-8 Shotgun Energy based on number of Shells Salvaged. 84 | PrimaryGimmickRequirement = 1; 85 | MaxCooldown = 20; 86 | Args = args; 87 | } 88 | 89 | public override Attack Execute(Player player) 90 | { 91 | var spellWeapon = player.GetWeaponFromSpell(this); 92 | 93 | switch (spellWeapon.GimmickResource) 94 | { 95 | case 1: 96 | PrimaryGimmickReduce = 1; 97 | PrimaryGain = 3; 98 | break; 99 | case 2: 100 | PrimaryGimmickReduce = 2; 101 | PrimaryGain = 4; 102 | break; 103 | case 3: 104 | PrimaryGimmickReduce = 3; 105 | PrimaryGain = 5; 106 | break; 107 | case 4: 108 | PrimaryGimmickReduce = 4; 109 | PrimaryGain = 6; 110 | break; 111 | case 5: 112 | PrimaryGimmickReduce = 5; 113 | PrimaryGain = 7; 114 | break; 115 | case 6: 116 | PrimaryGimmickReduce = 6; 117 | PrimaryGain = 8; 118 | break; 119 | } 120 | 121 | return base.Execute(player); 122 | } 123 | } 124 | 125 | public class Bombardment : Spell 126 | { 127 | public Bombardment(IPlayer player, string args = null) 128 | { 129 | WeaponType = WeaponType.Shotgun; 130 | AbilityType = AbilityType.Elite; 131 | PrimaryCost = 4; 132 | PrimaryGimmickCost = 6; 133 | MaxCooldown = 20; 134 | BaseDamage = 0.70; // 10s Ground AoE 0.70CP Every 1.25s for 10s TAoE 3m 0.36CP 135 | Args = args; 136 | } // Exposed 137 | } 138 | 139 | public class Reload : Spell 140 | { 141 | public Reload(IPlayer player, string args = null) 142 | { 143 | WeaponType = WeaponType.Shotgun; 144 | Args = args; 145 | PrimaryGimmickGain = 6; 146 | } 147 | } 148 | } -------------------------------------------------------------------------------- /swlSimulator/api/Spells/Shotgun/Buffs/Buff.cs: -------------------------------------------------------------------------------- 1 | using swlSimulator.api.Weapons; 2 | 3 | namespace swlSimulator.api.Spells.Shotgun.Buffs 4 | { 5 | public class Buff 6 | { 7 | public class IfritanDespoiler : AbilityBuff 8 | { 9 | public IfritanDespoiler() 10 | { 11 | MaxDuration = 4; 12 | BonusCritMultiplier = 0.14; 13 | WeaponType = WeaponType.Shotgun; 14 | SpecificWeaponTypeBonus = true; 15 | } 16 | } 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /swlSimulator/api/Spells/Shotgun/Passive.cs: -------------------------------------------------------------------------------- 1 | using swlSimulator.api.Models; 2 | using swlSimulator.api.Weapons; 3 | 4 | namespace swlSimulator.api.Spells.Shotgun 5 | { 6 | public class BlastBarrels : Passive 7 | { 8 | public BlastBarrels(IPlayer player, string args = null) 9 | { 10 | WeaponType = WeaponType.Shotgun; 11 | SpellTypes.Add(typeof(BothBarrels)); 12 | // Additional hit dealing 0.38CP to each target. 13 | } 14 | } 15 | 16 | public class FireAtWill : Passive 17 | { 18 | public FireAtWill(IPlayer player, string args = null) 19 | { 20 | WeaponType = WeaponType.Shotgun; 21 | SpellTypes.Add(typeof(OpeningShot)); 22 | // Shotgun attacks deal additional 0.21CP until enemy deals daamge to you. Crit hits with Shotgun reloads 1 Shell. 23 | } 24 | } 25 | 26 | public class PointBlankShot : Passive 27 | { 28 | public PointBlankShot() 29 | { 30 | WeaponType = WeaponType.Shotgun; 31 | SpellTypes.Add(typeof(RagingShot)); 32 | BaseDamage = 0.58; 33 | // TODO: Test and implement range??? 34 | // Increase damage to 4.00 to targets within 3m 35 | } 36 | } 37 | 38 | public class WitheringSalvo : Passive 39 | { 40 | public WitheringSalvo(IPlayer player, string args = null) 41 | { 42 | WeaponType = WeaponType.Shotgun; 43 | SpellTypes.Add(typeof(FullSalvo)); 44 | // 40% more base damage on each successive hit. 45 | } 46 | } 47 | 48 | public class SalvageExpert : Passive 49 | { 50 | public SalvageExpert() 51 | { 52 | WeaponType = WeaponType.Shotgun; 53 | SpellTypes.Add(typeof(ShellSalvage)); 54 | SecondaryGain = 5; 55 | // TODO: offer to reload the same type of shell 56 | // Always offer to reload the same type of shell. 57 | } 58 | } 59 | 60 | public class ClusterBombs : Passive 61 | { 62 | public ClusterBombs(IPlayer player, string args = null) 63 | { 64 | WeaponType = WeaponType.Shotgun; 65 | SpellTypes.Add(typeof(Bombardment)); 66 | // On hit break into 3 smaller explosives dealing 0.31CP 67 | } 68 | } 69 | 70 | public class OddsAndEvens : Passive 71 | { 72 | public OddsAndEvens(IPlayer player, string args = null) 73 | { 74 | WeaponType = WeaponType.Shotgun; 75 | // Odd number of shells: Shotgun basic deal 70% more damage, Even number of shells: Shotgun power deal 15% more damage. 76 | } 77 | } 78 | 79 | public class WhitePhosphorusShells : Passive 80 | { 81 | public WhitePhosphorusShells(IPlayer player, string args = null) 82 | { 83 | WeaponType = WeaponType.Shotgun; 84 | // Dragon's Breath Shells damage is improved by 12% 85 | } 86 | } 87 | 88 | public class Enrich : Passive 89 | { 90 | public Enrich(IPlayer player, string args = null) 91 | { 92 | WeaponType = WeaponType.Shotgun; 93 | // Whenever you load Depleted Uranium Shells feed in 2 extra shells 94 | } 95 | } 96 | 97 | public class MunitionsExpert : Passive 98 | { 99 | public MunitionsExpert(IPlayer player, string args = null) 100 | { 101 | WeaponType = WeaponType.Shotgun; 102 | // More opportunities to load Dragon's Breath Shells, Depleted Uranium Shells and Armor-Piercing Shells 103 | } 104 | } 105 | 106 | public class CombatReload : Passive 107 | { 108 | public CombatReload(IPlayer player, string args = null) 109 | { 110 | WeaponType = WeaponType.Shotgun; 111 | // In combat with shells still loaded reload 1 shell every 5s 112 | } 113 | } 114 | } -------------------------------------------------------------------------------- /swlSimulator/api/Spells/SpellBook.cs: -------------------------------------------------------------------------------- 1 | namespace swlSimulator.api.Spells 2 | { 3 | public class OpeningShot : Buff 4 | { 5 | public OpeningShot() 6 | { 7 | MaxDuration = 8; 8 | MaxCooldown = 20; 9 | MaxBonusCritMultiplier = 0.3; 10 | } 11 | } 12 | 13 | public class Savagery : Buff 14 | { 15 | public Savagery() 16 | { 17 | MaxDuration = 6; 18 | MaxCooldown = 20; 19 | MaxBonusBaseDamageMultiplier = 0.15; 20 | } 21 | } 22 | 23 | public class Exposed : Debuff 24 | { 25 | public Exposed() 26 | { 27 | MaxDuration = 0; // uptime 100% 28 | MaxCooldown = 0; 29 | MaxBonusDamageMultiplier = 0.1; 30 | } 31 | } 32 | 33 | // TODO: Add Glaciate 34 | } -------------------------------------------------------------------------------- /swlSimulator/api/Utilities/Helper.cs: -------------------------------------------------------------------------------- 1 | using Expressions; 2 | using swlSimulator.api.Models; 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | namespace swlSimulator.api.Utilities 7 | { 8 | internal static class Helper 9 | { 10 | private static readonly Random Random = new Random(); 11 | private static readonly object SyncLock = new object(); 12 | 13 | public static double RNG() 14 | { 15 | lock (SyncLock) 16 | { 17 | // TODO: Not 100% accurate since it cant return 1 which would be 100%? 18 | return Random.NextDouble(); 19 | } 20 | } 21 | 22 | public static bool IsHit(double targetdifficulty, double hitchance) 23 | { 24 | // TODO: Check if this is correct 25 | return RNG() + targetdifficulty < 1 + hitchance; 26 | } 27 | 28 | public static bool IsCrit(double critchance) 29 | { 30 | var rng = RNG(); 31 | return rng > 1 - critchance; 32 | } 33 | 34 | public static bool EvaluateArgs(string args, Player player, 35 | ExpressionLanguage language = ExpressionLanguage.Csharp) 36 | { 37 | var expression = new DynamicExpression(args, language); 38 | 39 | // Only create context once 40 | if (player.Context == null) 41 | { 42 | player.Context = new ExpressionContext(null, player, true); 43 | player.Context.Variables.Add("Player", player); 44 | 45 | foreach (var spell in player.Spells.DistinctBy(s => s.Name)) 46 | player.Context.Variables.Add(spell.Name, spell); 47 | } 48 | 49 | var res = expression.Invoke(player.Context); 50 | 51 | return (bool)res; 52 | } 53 | 54 | public static IEnumerable DistinctBy 55 | (this IEnumerable source, Func keySelector) 56 | { 57 | HashSet seenKeys = new HashSet(); 58 | foreach (TSource element in source) 59 | { 60 | if (seenKeys.Add(keySelector(element))) 61 | { 62 | yield return element; 63 | } 64 | } 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /swlSimulator/api/Weapons/Chaos.cs: -------------------------------------------------------------------------------- 1 | using swlSimulator.api.Combat; 2 | using swlSimulator.api.Models; 3 | using swlSimulator.api.Spells; 4 | 5 | namespace swlSimulator.api.Weapons 6 | { 7 | public class Chaos : Weapon 8 | { 9 | public Chaos(WeaponType wtype, WeaponAffix waffix) : base(wtype, waffix) 10 | { 11 | _maxGimickResource = 8; 12 | } 13 | 14 | public override void AfterAttack(IPlayer player, ISpell spell, RoundResult rr) 15 | { 16 | var roll = Rnd.Next(1, 11); 17 | var highroller = Rnd.Next(1, 1001); 18 | 19 | if (spell?.Name == "ChaosUnluckySpell") // Unit test 20 | { 21 | return; 22 | } 23 | 24 | // 30% chance of generating paradoxes 25 | if (roll > 3 && spell?.Name != "ChaosLuckySpell") // Unit test 26 | { 27 | return; 28 | } 29 | 30 | //// TODO: Whaaaaat is this? 31 | //roll = Rnd.Next(1, 9); 32 | //{ 33 | // if (roll == 8) 34 | // { 35 | // ParadoxGenerator(player); 36 | // } 37 | //} 38 | 39 | ParadoxGenerator(player, spell); 40 | 41 | if (player.Settings.PrimaryWeaponProc == WeaponProc.WarpedVisage && GimmickResource == 8) 42 | { 43 | player.AddBonusAttack(rr, new Doppleganger()); 44 | } 45 | 46 | if (GimmickResource == 8 || player.Settings.PrimaryWeaponProc == WeaponProc.SovTechParadoxGenerator && 47 | highroller <= 55) 48 | { 49 | ChaoticEffects(player, rr); 50 | } 51 | } 52 | 53 | private void ParadoxGenerator(IPlayer player, ISpell spell) 54 | { 55 | var roll = Rnd.Next(2, 5); 56 | 57 | if (spell?.Name == "ChaosLuckySpell") // Unit test 58 | { 59 | roll = 2; 60 | } 61 | 62 | GimmickResource += roll; 63 | 64 | if (player.Settings.PrimaryWeaponProc == WeaponProc.OtherworldlyArtifact) 65 | { 66 | GimmickResource++; 67 | } 68 | } 69 | 70 | private void ChaoticEffects(IPlayer player, RoundResult rr) 71 | { 72 | // TODO: 30% chance here also??? 73 | var roll = Rnd.Next(1, 11); 74 | 75 | switch (roll) 76 | { 77 | case 1: 78 | player.AddBonusAttack(rr, new Singularity()); 79 | break; 80 | case 2: 81 | player.AddBonusAttack(rr, new Doppleganger()); 82 | break; 83 | case 3: 84 | player.AddBonusAttack(rr, new Enigma()); 85 | break; 86 | } 87 | } 88 | 89 | public class Singularity : Spell 90 | { 91 | public Singularity() 92 | { 93 | WeaponType = WeaponType.Chaos; 94 | SpellType = SpellType.Gimmick; 95 | BaseDamage = 2.67; 96 | // TODO: No cost?? 97 | } 98 | } 99 | 100 | public class Doppleganger : Spell 101 | { 102 | public Doppleganger() 103 | { 104 | WeaponType = WeaponType.Chaos; 105 | SpellType = SpellType.Gimmick; 106 | BaseDamage = 4.33; 107 | // TODO: No cost?? 108 | // On avarage lul. Doppelgangers spawn in pairs, and have: 1/3 chance to deal 2.6CP damage & 1/3 chance to deal 5 * 0.52CP damage 109 | // & 1/3 chance to deal 1.3CP damage for an average of 4.33CP damage 110 | } 111 | } 112 | 113 | public class Enigma : Spell 114 | { 115 | public Enigma() 116 | { 117 | WeaponType = WeaponType.Chaos; 118 | SpellType = SpellType.Gimmick; 119 | // TODO: No cost?? 120 | // Irrelevant for now TODO: Maybe model purgable critpower steal, but otherwise irrelevant to DPS. 121 | } 122 | } 123 | } 124 | } -------------------------------------------------------------------------------- /swlSimulator/api/Weapons/Elemental.cs: -------------------------------------------------------------------------------- 1 | using swlSimulator.api.Combat; 2 | using swlSimulator.api.Models; 3 | using swlSimulator.api.Spells; 4 | 5 | namespace swlSimulator.api.Weapons 6 | { 7 | public class Elemental : Weapon 8 | { 9 | public Elemental(WeaponType wtype, WeaponAffix waffix) : base(wtype, waffix) 10 | { 11 | _maxGimickResource = 100; 12 | } 13 | 14 | private decimal LastElementalSpellTimeStamp { get; set; } 15 | private ISpell LastElementalSpell { get; set; } 16 | private decimal TimeSinceLastElementalSpell { get; set; } 17 | 18 | public override void PreAttack(IPlayer player, RoundResult rr) 19 | { 20 | } 21 | 22 | public override double GetBonusBaseDamageMultiplier(IPlayer player, ISpell spell, decimal heatBeforeCast) 23 | { 24 | var hasFigurine = player.Settings.PrimaryWeaponProc == WeaponProc.FrozenFigurine && 25 | spell.ElementalType == ElementalType.Cold; 26 | LastElementalSpell = spell; 27 | 28 | TimeSinceLastElementalSpell = player.CurrentTimeSec - LastElementalSpellTimeStamp; 29 | 30 | // Set new time stamp for new cast 31 | LastElementalSpellTimeStamp = player.CurrentTimeSec + spell.CastTime; 32 | 33 | if (player.Settings.PrimaryWeaponProc != WeaponProc.FrozenFigurine) 34 | { 35 | Decay(heatBeforeCast); 36 | } 37 | 38 | //HeatStop(); 39 | 40 | // TODO: Add all constants to own file? 41 | if (heatBeforeCast >= 25 && heatBeforeCast <= 50) 42 | { 43 | // GimmickBonusDamage = 1.087; // 8.7% 44 | return hasFigurine ? 0.797 : 0.087; 45 | } 46 | if (heatBeforeCast >= 50 && heatBeforeCast <= 75) 47 | { 48 | // GimmickBonusDamage = 1.174; // 17.4% 49 | return hasFigurine ? 0.884 : 0.174; 50 | } 51 | if (heatBeforeCast >= 75 && heatBeforeCast <= 100) 52 | { 53 | // GimmickBonusDamage = 1.348 // 34.8% 54 | return hasFigurine ? 1.058 : 0.348; 55 | } 56 | 57 | // heatBeforeCast >= 0 && heatBeforeCast <= 25 58 | // Normal damage 59 | return 0; 60 | } 61 | 62 | public override void AfterAttack(IPlayer player, ISpell spell, RoundResult rr) 63 | { 64 | if (player.Settings.PrimaryWeaponProc == WeaponProc.UnstableElectronCore && GimmickResource > 50 && 65 | (spell.ElementalType == ElementalType.Fire || spell.ElementalType == ElementalType.Lightning)) 66 | { 67 | player.AddBonusAttack(rr, new UnstableElectronCore()); 68 | } 69 | if (player.Settings.PrimaryWeaponProc == WeaponProc.CryoChargedConduit && spell.ElementalType == ElementalType.Cold) 70 | { 71 | GimmickResource -= 15; 72 | //TODO: and cause any targets hit to become frostbitten for 6 seconds. Critically hitting a frostbitten enemy with an Elemental attack deals an additional (3.45*Combat Power) magical damage. 73 | //What does it even mean? 74 | } 75 | } 76 | 77 | private void Decay(decimal heatBeforeCast) 78 | { 79 | // Corruption = -4 for each second. 80 | // Only reduce per second, so for example 1.5s = 1s 81 | var time = TimeSinceLastElementalSpell; 82 | var reduce = 0; 83 | 84 | if (heatBeforeCast <= 25) 85 | { 86 | // Heat = -1 per second. 87 | reduce = (int) (time * 1); 88 | } 89 | if (heatBeforeCast >= 26 && heatBeforeCast <= 50) 90 | { 91 | // Heat = -2 per second. 92 | reduce = (int) (time * 2); 93 | } 94 | if (heatBeforeCast >= 51 && heatBeforeCast <= 75) 95 | { 96 | // Heat = -3 per second. 97 | reduce = (int) (time * 3); 98 | } 99 | if (heatBeforeCast >= 76) 100 | { 101 | // Heat = -4 per second. 102 | reduce = (int) (time * 4); 103 | } 104 | 105 | GimmickResource -= reduce; 106 | 107 | if (GimmickResource < 0) 108 | { 109 | GimmickResource = 0; 110 | } 111 | } 112 | 113 | // TODO: Fix HeatStop 114 | //private void HeatStop() 115 | //{ 116 | // if (Player.Heat == 100) 117 | // { 118 | // // Not able to cast any abilities that generates Heat. 119 | // // Casting a cooling ability at 100 heat will immideiatly reduce heat and allow heat generating casts again. 120 | // } 121 | //} 122 | 123 | private class UnstableElectronCore : Spell 124 | { 125 | public UnstableElectronCore() 126 | { 127 | WeaponType = WeaponType.Elemental; 128 | SpellType = SpellType.Procc; 129 | BaseDamage = 0.17; 130 | } 131 | } 132 | } 133 | } -------------------------------------------------------------------------------- /swlSimulator/api/Weapons/Fist.cs: -------------------------------------------------------------------------------- 1 | using swlSimulator.api.Combat; 2 | using swlSimulator.api.Models; 3 | using swlSimulator.api.Spells; 4 | 5 | namespace swlSimulator.api.Weapons 6 | { 7 | public class Fist : Weapon 8 | { 9 | private int _bladedStartBonus = 1; 10 | 11 | public Fist(WeaponType wtype, WeaponAffix waffix) : base(wtype, waffix) 12 | { 13 | _maxGimickResource = 100; 14 | } 15 | 16 | public bool AllowFrenziedWrathAbilities { get; private set; } 17 | 18 | public override void PreAttack(IPlayer player, RoundResult rr) 19 | { 20 | if (player.Settings.PrimaryWeaponProc == WeaponProc.BladedGauntlets && _bladedStartBonus == 1) 21 | { 22 | GimmickResource = +15; // TODO: Grem, =+ ? 23 | _bladedStartBonus = 2; 24 | } 25 | 26 | if (player.Settings.PrimaryWeaponProc == WeaponProc.BladedGauntlets) 27 | { 28 | GimmickResource = +2; // TODO: Grem, =+ ? 29 | } 30 | 31 | if (player.Settings.PrimaryWeaponProc == WeaponProc.TreshingClaws && AllowFrenziedWrathAbilities) 32 | { 33 | player.AddBonusAttack(rr, new TreshingClaws()); 34 | } 35 | } 36 | 37 | public override void AfterAttack(IPlayer player, ISpell spell, RoundResult rr) 38 | { 39 | if (GimmickResource >= 65) 40 | { 41 | // TODO: Set this variable 42 | AllowFrenziedWrathAbilities = true; 43 | } 44 | 45 | if (player.Settings.PrimaryWeaponProc == WeaponProc.BloodDrinkers && spell.SpellType == SpellType.Dot) 46 | { 47 | GimmickResource = +3; // TODO: Grem, =+ ? 48 | } 49 | } 50 | 51 | private sealed class TreshingClaws : Spell 52 | { 53 | public TreshingClaws() 54 | { 55 | WeaponType = WeaponType.Fist; 56 | SpellType = SpellType.Gimmick; 57 | BaseDamage = 0.69; 58 | } 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /swlSimulator/api/Weapons/Rifle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using swlSimulator.api.Combat; 5 | using swlSimulator.api.Models; 6 | using swlSimulator.api.Spells; 7 | 8 | namespace swlSimulator.api.Weapons 9 | { 10 | public class Rifle : Weapon 11 | { 12 | // TODO: Check values, 6s total cooktimer and fully cooked after 3s?? 13 | // TODO: All greande spells have a 4s cooldown 14 | private const decimal FUSE_TIMER = 3; 15 | 16 | private const decimal COOKINGTIMER = 3; 17 | 18 | private readonly List _grenadeGenerators = new List 19 | { 20 | "FullAuto", 21 | "UnveilEssence", 22 | "BurstFire" 23 | }; 24 | 25 | private decimal _cookingReadyTimeSec = decimal.MaxValue; 26 | private bool _infernalLoader; 27 | private bool _init; 28 | 29 | private bool _ksr43; 30 | 31 | private RoundResult _rr; 32 | 33 | public Rifle(WeaponType wtype, WeaponAffix waffix) : base(wtype, waffix) 34 | { 35 | _maxGimickResource = 1; 36 | } 37 | 38 | public decimal FuseTimer { get; private set; } 39 | //public decimal CookingTimer => COOKINGTIMER - FuseTimer; // TODO: Fix cooking timer for APL and remove fusetimer 40 | 41 | public override void PreAttack(IPlayer player, RoundResult rr) 42 | { 43 | // Only on first activation 44 | if (!_init) 45 | { 46 | _init = true; 47 | 48 | // TODO: Not on secondary weapon proc? 49 | _ksr43 = player.Settings.PrimaryWeaponProc == WeaponProc.Ksr43; 50 | _infernalLoader = player.Settings.PrimaryWeaponProc == WeaponProc.InfernalLoader; 51 | } 52 | 53 | if (GimmickResource >= 1) 54 | { 55 | if (_rr == null || rr.TimeSec != _rr.TimeSec) 56 | { 57 | FuseTimer += rr.Interval; 58 | } 59 | 60 | if (FuseTimer > FUSE_TIMER) 61 | { 62 | GimmickResource = 0; 63 | } 64 | } 65 | else if (_cookingReadyTimeSec <= player.CurrentTimeSec) 66 | { 67 | // We can use grenade 68 | GimmickResource = 1; 69 | _cookingReadyTimeSec = decimal.MaxValue; 70 | FuseTimer = 0; 71 | } 72 | 73 | _rr = rr; 74 | } 75 | 76 | public override void AfterAttack(IPlayer player, ISpell spell, RoundResult rr) 77 | { 78 | // TODO: Check values some spells have 37.5% chance and some 65% 79 | if (GimmickResource < 1 && Rnd.Next(1, 101) > 65 80 | && _grenadeGenerators.Contains(spell.Name, StringComparer.CurrentCultureIgnoreCase) 81 | || GimmickResource < 1 && spell.Name == "RifleLoadGrenadeSpell") // Unit test 82 | { 83 | // Start cooking, if KSR43 it can be used directly 84 | if (_ksr43) 85 | { 86 | _cookingReadyTimeSec = decimal.MaxValue; 87 | GimmickResource = 1; 88 | FuseTimer = 0; 89 | } 90 | else if (_cookingReadyTimeSec > player.CurrentTimeSec + COOKINGTIMER) 91 | { 92 | _cookingReadyTimeSec = player.CurrentTimeSec + COOKINGTIMER; 93 | } 94 | } 95 | } 96 | 97 | public override double GetBonusBaseDamage(IPlayer player, ISpell spell, decimal gimmickBeforeCast) 98 | { 99 | double bonusBaseDamage = 0; 100 | 101 | if (_infernalLoader) 102 | { 103 | bonusBaseDamage += 0.075; // +7.5% AR damage 104 | } 105 | 106 | return bonusBaseDamage; 107 | } 108 | } 109 | } -------------------------------------------------------------------------------- /swlSimulator/api/Weapons/Shotgun.cs: -------------------------------------------------------------------------------- 1 | using swlSimulator.api.Combat; 2 | using swlSimulator.api.Models; 3 | using swlSimulator.api.Spells; 4 | using swlSimulator.api.Spells.Shotgun; 5 | 6 | namespace swlSimulator.api.Weapons 7 | { 8 | public class Shotgun : Weapon 9 | { 10 | private int _ifritanDespoilerCounter; 11 | private decimal _shellstamp; 12 | 13 | public Shotgun(WeaponType wtype, WeaponAffix waffix) : base(wtype, waffix) 14 | { 15 | _maxGimickResource = 6; 16 | _gimickResource = 6; 17 | } 18 | 19 | public override void PreAttack(IPlayer player, RoundResult rr) 20 | { 21 | _shellstamp = GimmickResource; 22 | } 23 | 24 | public override void AfterAttack(IPlayer player, ISpell spell, RoundResult rr) 25 | { 26 | var roll = Rnd.Next(1, 6); 27 | 28 | if (player.Settings.PrimaryWeaponProc == WeaponProc.IfritanDespoiler) 29 | { 30 | if (spell.GetType() == typeof(DragonBreath)) 31 | { 32 | _ifritanDespoilerCounter += 2; 33 | } 34 | if (spell.GetType() == typeof(DepletedUranium)) 35 | { 36 | _ifritanDespoilerCounter++; 37 | } 38 | if (_ifritanDespoilerCounter >= 12) 39 | { 40 | player.AddBonusAttack(rr, new IfritanDespoiler(player, "")); 41 | _ifritanDespoilerCounter = 0; 42 | } 43 | } 44 | 45 | if (player.Settings.PrimaryWeaponProc == WeaponProc.Spesc221 && GimmickResource < _shellstamp && roll == 5) 46 | { 47 | player.AddBonusAttack(rr, new SpesC221()); 48 | } 49 | 50 | // Not all spells should procc gimmick 51 | if (spell.GetType() == typeof(Reload) || spell.GetType() == typeof(ShellSalvage)) 52 | { 53 | return; 54 | } 55 | 56 | if (Rnd.Next(1, 3) == 1) 57 | { 58 | // TODO: Check & FIX DOT duration/stacks and assume perfect play by default 59 | // in weapon-model so APL does not have to worry about it at all. 60 | player.AddBonusAttack(rr, new DragonBreath()); 61 | } 62 | else 63 | { 64 | player.AddBonusAttack(rr, new DepletedUranium()); 65 | } 66 | } 67 | 68 | // We assume we will be alternating Dragon's Breath and Depleted Uranium Shells every reload 69 | private class DragonBreath : Spell 70 | { 71 | public DragonBreath() 72 | { 73 | WeaponType = WeaponType.Shotgun; 74 | SpellType = SpellType.Gimmick; 75 | PrimaryGimmickCost = 1; 76 | BaseDamage = 0.147; 77 | // TODO: Stacking dot 78 | // Dragons Breath rounds do 0.147CP per stack with a maximum of 6 stacks 79 | } 80 | } 81 | 82 | private class DepletedUranium : Spell 83 | { 84 | public DepletedUranium() 85 | { 86 | WeaponType = WeaponType.Shotgun; 87 | SpellType = SpellType.Gimmick; 88 | PrimaryGimmickCost = 1; 89 | BaseDamage = 0.97; 90 | // Depleted Uranium rounds do 0.97CP, and will be used with 50% uptime 91 | } 92 | } 93 | 94 | private class ArmorPiercing : Spell 95 | { 96 | public ArmorPiercing() 97 | { 98 | WeaponType = WeaponType.Shotgun; 99 | SpellType = SpellType.Gimmick; 100 | PrimaryGimmickCost = 1; 101 | BaseDamage = 0; // Adds exposed for 10s 102 | } 103 | } 104 | 105 | private class AnimaInfused : Spell 106 | { 107 | public AnimaInfused() 108 | { 109 | WeaponType = WeaponType.Shotgun; 110 | SpellType = SpellType.Gimmick; 111 | PrimaryGimmickCost = 1; 112 | BaseDamage = 0; // 3% HP heal 113 | } 114 | } 115 | 116 | public class IfritanDespoiler : Spell 117 | { 118 | public IfritanDespoiler(IPlayer player, string args = null) 119 | { 120 | WeaponType = WeaponType.Shotgun; 121 | SpellType = SpellType.Instant; 122 | AbilityBuff = player.GetAbilityBuffFromName(Name) as AbilityBuff; 123 | } 124 | } 125 | 126 | private class SpesC221 : Spell 127 | { 128 | public SpesC221() 129 | { 130 | WeaponType = WeaponType.Shotgun; 131 | SpellType = SpellType.Procc; 132 | BaseDamage = 1.5; 133 | } 134 | } 135 | } 136 | } -------------------------------------------------------------------------------- /swlSimulator/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "IncludeScopes": false, 4 | "Debug": { 5 | "LogLevel": { 6 | "Default": "Debug", 7 | "System": "Information", 8 | "Microsoft": "Information" 9 | } 10 | }, 11 | "Console": { 12 | "LogLevel": { 13 | "Default": "Debug", 14 | "System": "Information", 15 | "Microsoft": "Information" 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /swlSimulator/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "IncludeScopes": false, 4 | "Debug": { 5 | "LogLevel": { 6 | "Default": "Warning" 7 | } 8 | }, 9 | "Console": { 10 | "LogLevel": { 11 | "Default": "Warning" 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /swlSimulator/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "swlsimulator", 3 | "private": true, 4 | "version": "0.2.0", 5 | "scripts": { 6 | "test": "karma start ClientApp/test/karma.conf.js", 7 | "format": "prettier --write --trailing-comma \"all\" \"ClientApp/**/*.ts\"", 8 | "lint": "tslint \"ClientApp/**/*.ts\"" 9 | }, 10 | "dependencies": { 11 | "@angular/animations": "4.2.5", 12 | "@angular/common": "4.2.5", 13 | "@angular/compiler": "4.2.5", 14 | "@angular/compiler-cli": "4.2.5", 15 | "@angular/core": "4.2.5", 16 | "@angular/forms": "4.2.5", 17 | "@angular/http": "4.2.5", 18 | "@angular/platform-browser": "4.2.5", 19 | "@angular/platform-browser-dynamic": "4.2.5", 20 | "@angular/platform-server": "4.2.5", 21 | "@angular/router": "4.2.5", 22 | "@aspnet/signalr-client": "1.0.0-alpha1-final", 23 | "@ngtools/webpack": "1.5.0", 24 | "@types/webpack-env": "1.13.0", 25 | "angular2-template-loader": "0.6.2", 26 | "aspnet-prerendering": "^3.0.1", 27 | "aspnet-webpack": "^2.0.1", 28 | "awesome-typescript-loader": "3.2.1", 29 | "bootstrap": "3.3.7", 30 | "chart.js": "https://registry.npmjs.org/chart.js/-/chart.js-2.7.0.tgz", 31 | "css": "2.2.1", 32 | "css-loader": "0.28.4", 33 | "es6-shim": "0.35.3", 34 | "event-source-polyfill": "0.0.9", 35 | "expose-loader": "0.7.3", 36 | "extract-text-webpack-plugin": "2.1.2", 37 | "file-loader": "0.11.2", 38 | "html-loader": "0.4.5", 39 | "isomorphic-fetch": "2.2.1", 40 | "jquery": "3.2.1", 41 | "json-loader": "0.5.4", 42 | "msgpack5": "^3.5.1", 43 | "ng2-charts": "^1.6.0", 44 | "preboot": "4.5.2", 45 | "raw-loader": "0.5.1", 46 | "reflect-metadata": "0.1.10", 47 | "rxjs": "5.4.2", 48 | "style-loader": "0.18.2", 49 | "to-string-loader": "1.1.5", 50 | "url-loader": "0.5.9", 51 | "webpack": "2.5.1", 52 | "webpack-hot-middleware": "2.18.2", 53 | "webpack-merge": "4.1.0", 54 | "zone.js": "0.8.12" 55 | }, 56 | "devDependencies": { 57 | "@angular/cli": "^1.4.7", 58 | "@types/chai": "4.0.1", 59 | "@types/jasmine": "2.5.53", 60 | "chai": "4.0.2", 61 | "jasmine-core": "2.6.4", 62 | "karma": "1.7.0", 63 | "karma-chai": "0.1.0", 64 | "karma-chrome-launcher": "2.2.0", 65 | "karma-cli": "1.0.1", 66 | "karma-jasmine": "1.1.0", 67 | "karma-webpack": "2.0.3", 68 | "prettier": "^1.7.4", 69 | "tslint": "^5.7.0", 70 | "tslint-config-prettier": "^1.6.0", 71 | "typescript": "2.4.1" 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /swlSimulator/swlSimulator.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netcoreapp2.0 4 | true 5 | Latest 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | %(DistFiles.Identity) 45 | PreserveNewest 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /swlSimulator/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "es5", 4 | "moduleResolution": "node", 5 | "target": "es5", 6 | "sourceMap": true, 7 | "experimentalDecorators": true, 8 | "emitDecoratorMetadata": true, 9 | "skipDefaultLibCheck": true, 10 | "skipLibCheck": true, // Workaround for https://github.com/angular/angular/issues/17863. Remove this if you upgrade to a fixed version of Angular. 11 | "lib": ["es6", "dom"], 12 | "types": ["webpack-env"] 13 | }, 14 | "exclude": ["bin", "node_modules"], 15 | "atom": { "rewriteTsconfig": false } 16 | } 17 | -------------------------------------------------------------------------------- /swlSimulator/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "tslint:latest", 4 | "tslint-config-prettier" 5 | ], 6 | "rules": { 7 | "no-var-requires": false, 8 | "no-internal-module": true, 9 | "object-literal-sort-keys": false, 10 | "member-access": false, 11 | "no-submodule-imports": false, 12 | "no-empty": false, 13 | "no-console": false 14 | }, 15 | "defaultSeverity": "warning" 16 | } -------------------------------------------------------------------------------- /swlSimulator/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const webpack = require("webpack"); 3 | const merge = require("webpack-merge"); 4 | const AotPlugin = require("@ngtools/webpack").AotPlugin; 5 | const CheckerPlugin = require("awesome-typescript-loader").CheckerPlugin; 6 | 7 | module.exports = (env) => { 8 | // Configuration in common to both client-side and server-side bundles 9 | const isDevBuild = !(env && env.prod); 10 | const sharedConfig = { 11 | stats: { modules: false }, 12 | context: __dirname, 13 | resolve: { extensions: [ ".js", ".ts" ] }, 14 | output: { 15 | filename: "[name].js", 16 | publicPath: "dist/" // Webpack dev middleware, if enabled, handles requests for this URL prefix 17 | }, 18 | module: { 19 | rules: [ 20 | { test: /\.ts$/, include: /ClientApp/, use: isDevBuild ? ["awesome-typescript-loader?silent=true", "angular2-template-loader"] : "@ngtools/webpack" }, 21 | { test: /\.html$/, use: "html-loader?minimize=false" }, 22 | { test: /\.css$/, use: [ "to-string-loader", isDevBuild ? "css-loader" : "css-loader?minimize" ] }, 23 | { test: /.(png|jpg|jpeg|gif|svg|woff|woff2|eot|ttf)(\?v=\d+\.\d+\.\d+)?$/, loader: "url-loader?limit=100000" } 24 | ] 25 | }, 26 | plugins: [new CheckerPlugin()] 27 | }; 28 | 29 | // Configuration for client-side bundle suitable for running in browsers 30 | const clientBundleOutputDir = "./wwwroot/dist"; 31 | const clientBundleConfig = merge(sharedConfig, { 32 | entry: { "main-client": "./ClientApp/boot.browser.ts" }, 33 | output: { path: path.join(__dirname, clientBundleOutputDir) }, 34 | plugins: [ 35 | new webpack.DllReferencePlugin({ 36 | context: __dirname, 37 | manifest: require("./wwwroot/dist/vendor-manifest.json") 38 | }) 39 | ].concat(isDevBuild ? [ 40 | // Plugins that apply in development builds only 41 | new webpack.SourceMapDevToolPlugin({ 42 | filename: "[file].map", // Remove this line if you prefer inline source maps 43 | moduleFilenameTemplate: path.relative(clientBundleOutputDir, "[resourcePath]") // Point sourcemap entries to the original file locations on disk 44 | }) 45 | ] : [ 46 | // Plugins that apply in production builds only 47 | new webpack.optimize.UglifyJsPlugin(), 48 | new AotPlugin({ 49 | tsConfigPath: "./tsconfig.json", 50 | entryModule: path.join(__dirname, "ClientApp/app/app.module.browser#AppModule"), 51 | exclude: ["./**/*.server.ts"] 52 | }) 53 | ]) 54 | }); 55 | 56 | // Configuration for server-side (prerendering) bundle suitable for running in Node 57 | const serverBundleConfig = merge(sharedConfig, { 58 | resolve: { mainFields: ["main"] }, 59 | entry: { "main-server": "./ClientApp/boot.server.ts" }, 60 | plugins: [ 61 | new webpack.DllReferencePlugin({ 62 | context: __dirname, 63 | manifest: require("./ClientApp/dist/vendor-manifest.json"), 64 | sourceType: "commonjs2", 65 | name: "./vendor" 66 | }) 67 | ].concat(isDevBuild ? [] : [ 68 | // Plugins that apply in production builds only 69 | new AotPlugin({ 70 | tsConfigPath: "./tsconfig.json", 71 | entryModule: path.join(__dirname, "ClientApp/app/app.module.server#AppModule"), 72 | exclude: ["./**/*.browser.ts"] 73 | }) 74 | ]), 75 | output: { 76 | libraryTarget: "commonjs", 77 | path: path.join(__dirname, "./ClientApp/dist") 78 | }, 79 | target: "node", 80 | devtool: "inline-source-map" 81 | }); 82 | 83 | return [clientBundleConfig, serverBundleConfig]; 84 | }; 85 | -------------------------------------------------------------------------------- /swlSimulator/webpack.config.vendor.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const webpack = require("webpack"); 3 | const ExtractTextPlugin = require("extract-text-webpack-plugin"); 4 | const merge = require("webpack-merge"); 5 | const treeShakableModules = [ 6 | "@angular/animations", 7 | "@angular/common", 8 | "@angular/compiler", 9 | "@angular/core", 10 | "@angular/forms", 11 | "@angular/http", 12 | "@angular/platform-browser", 13 | "@angular/platform-browser-dynamic", 14 | "@angular/router", 15 | "zone.js", 16 | ]; 17 | const nonTreeShakableModules = [ 18 | "bootstrap", 19 | "bootstrap/dist/css/bootstrap.css", 20 | "es6-promise", 21 | "es6-shim", 22 | "event-source-polyfill", 23 | "jquery", 24 | ]; 25 | const allModules = treeShakableModules.concat(nonTreeShakableModules); 26 | 27 | module.exports = (env) => { 28 | const extractCSS = new ExtractTextPlugin("vendor.css"); 29 | const isDevBuild = !(env && env.prod); 30 | const sharedConfig = { 31 | stats: { modules: false }, 32 | resolve: { extensions: [ ".js" ] }, 33 | module: { 34 | rules: [ 35 | { test: /\.(png|woff|woff2|eot|ttf|svg)(\?|$)/, use: "url-loader?limit=100000" } 36 | ] 37 | }, 38 | output: { 39 | publicPath: "dist/", 40 | filename: "[name].js", 41 | library: "[name]_[hash]" 42 | }, 43 | plugins: [ 44 | new webpack.ProvidePlugin({ $: "jquery", jQuery: "jquery" }), // Maps these identifiers to the jQuery package (because Bootstrap expects it to be a global variable) 45 | new webpack.ContextReplacementPlugin(/\@angular\b.*\b(bundles|linker)/, path.join(__dirname, "./ClientApp")), // Workaround for https://github.com/angular/angular/issues/11580 46 | new webpack.ContextReplacementPlugin(/angular(\\|\/)core(\\|\/)@angular/, path.join(__dirname, "./ClientApp")), // Workaround for https://github.com/angular/angular/issues/14898 47 | new webpack.IgnorePlugin(/^vertx$/) // Workaround for https://github.com/stefanpenner/es6-promise/issues/100 48 | ] 49 | }; 50 | 51 | const clientBundleConfig = merge(sharedConfig, { 52 | entry: { 53 | // To keep development builds fast, include all vendor dependencies in the vendor bundle. 54 | // But for production builds, leave the tree-shakable ones out so the AOT compiler can produce a smaller bundle. 55 | vendor: isDevBuild ? allModules : nonTreeShakableModules 56 | }, 57 | output: { path: path.join(__dirname, "wwwroot", "dist") }, 58 | module: { 59 | rules: [ 60 | { test: /\.css(\?|$)/, use: extractCSS.extract({ use: isDevBuild ? "css-loader" : "css-loader?minimize" }) } 61 | ] 62 | }, 63 | plugins: [ 64 | extractCSS, 65 | new webpack.DllPlugin({ 66 | path: path.join(__dirname, "wwwroot", "dist", "[name]-manifest.json"), 67 | name: "[name]_[hash]" 68 | }) 69 | ].concat(isDevBuild ? [] : [ 70 | new webpack.optimize.UglifyJsPlugin() 71 | ]) 72 | }); 73 | 74 | const serverBundleConfig = merge(sharedConfig, { 75 | target: "node", 76 | resolve: { mainFields: ["main"] }, 77 | entry: { vendor: allModules.concat(["aspnet-prerendering"]) }, 78 | output: { 79 | path: path.join(__dirname, "ClientApp", "dist"), 80 | libraryTarget: "commonjs2", 81 | }, 82 | module: { 83 | rules: [ { test: /\.css(\?|$)/, use: ["to-string-loader", isDevBuild ? "css-loader" : "css-loader?minimize" ] } ] 84 | }, 85 | plugins: [ 86 | new webpack.DllPlugin({ 87 | path: path.join(__dirname, "ClientApp", "dist", "[name]-manifest.json"), 88 | name: "[name]_[hash]" 89 | }) 90 | ] 91 | }); 92 | 93 | return [clientBundleConfig, serverBundleConfig]; 94 | } 95 | -------------------------------------------------------------------------------- /swlSimulator/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vadelius/swlsimNET/d5c047e994ec8a5b6022a436d4f0f87b5d87b149/swlSimulator/wwwroot/favicon.ico -------------------------------------------------------------------------------- /swlsimNET.Tests/BladeTest.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using swlSimulator.api; 4 | using swlSimulator.api.Combat; 5 | using swlSimulator.api.Models; 6 | using swlSimulator.api.Spells; 7 | using swlSimulator.api.Weapons; 8 | using swlSimulator.Models; 9 | 10 | namespace swlSimulator.Tests 11 | { 12 | [TestClass] 13 | public class BladeTest 14 | { 15 | //[TestMethod] 16 | //public void TestBladeGimmick() 17 | //{ 18 | // var setting = new Settings 19 | // { 20 | // PrimaryWeapon = WeaponType.Blade, 21 | // SecondaryWeapon = WeaponType.Fist, 22 | // FightLength = 3, 23 | // TargetType = TargetType.Champion, 24 | // Apl = "" 25 | // }; 26 | 27 | // var player = new Player(setting); 28 | // var bSpell = new BladeSpell(); 29 | 30 | // player.Spells.Add(bSpell); 31 | 32 | // var engine = new Engine(setting); 33 | // var fight = engine.StartFight(player); 34 | 35 | // var bSpells = fight.RoundResults 36 | // .SelectMany(r => r.Attacks.Where(a => a.Spell is BladeSpell)).Count(); 37 | 38 | // // TODO: ChiGenerator(player); ChiConsumer(); SpiritBladeConsumer(player, rr); SpiritBladeExtender(); Not all in same test ofc 39 | // Assert.IsTrue(false); 40 | //} 41 | 42 | private sealed class BladeSpell : Spell 43 | { 44 | public BladeSpell() 45 | { 46 | PrimaryGimmickGain = 50; 47 | WeaponType = WeaponType.Blade; 48 | SpellType = SpellType.Cast; 49 | BaseDamage = 1; 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /swlsimNET.Tests/BloodTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | using swlSimulator.api; 5 | using swlSimulator.api.Combat; 6 | using swlSimulator.api.Models; 7 | using swlSimulator.api.Spells; 8 | using swlSimulator.api.Weapons; 9 | using swlSimulator.Models; 10 | 11 | namespace swlSimulator.Tests 12 | { 13 | [TestClass] 14 | public class BloodTest 15 | { 16 | [TestMethod] 17 | public void TestBloodGimmick() 18 | { 19 | var setting = new Settings 20 | { 21 | CombatPower = 10, 22 | PrimaryWeapon = WeaponType.Blood, 23 | SecondaryWeapon = WeaponType.Fist, 24 | FightLength = 5, 25 | TargetType = TargetType.Champion, 26 | Apl = "" 27 | }; 28 | 29 | var player = new Player(setting); 30 | var bSpell = new BloodSpell(); 31 | player.Spells.Add(bSpell); 32 | 33 | var engine = new Engine(setting); 34 | var fight = engine.StartFight(player); 35 | 36 | var bSpells = fight.RoundResults 37 | .SelectMany(r => r.Attacks.Where(a => a.Spell is BloodSpell)).Count(); 38 | 39 | var round1 = fight.RoundResults.First(r => r.TimeSec == 1); 40 | var round2 = fight.RoundResults.First(r => r.TimeSec == 2); 41 | var round3 = fight.RoundResults.First(r => r.TimeSec == 3); 42 | var round4 = fight.RoundResults.First(r => r.TimeSec == 4); 43 | var round5 = fight.RoundResults.First(r => r.TimeSec == 5); 44 | 45 | Assert.IsTrue(Math.Abs(round1.TotalDamage - 10) < 0.001); // 0 46 | Assert.IsTrue(Math.Abs(round2.TotalDamage - 11.56) < 0.01); // 30 47 | Assert.IsTrue(Math.Abs(round3.TotalDamage - 11.56) < 0.01); // 60 48 | Assert.IsTrue(Math.Abs(round4.TotalDamage - 13.27) < 0.01); // 90 49 | Assert.IsTrue(Math.Abs(round5.TotalDamage - 15.34) < 0.01); // 100 50 | 51 | Assert.IsTrue(bSpells == 5); 52 | } 53 | 54 | // TODO: Add Decay test 55 | 56 | private sealed class BloodSpell : Spell 57 | { 58 | public BloodSpell() 59 | { 60 | PrimaryGimmickGain = 30; 61 | WeaponType = WeaponType.Blood; 62 | SpellType = SpellType.Cast; 63 | CastTime = 1; 64 | BaseDamage = 1; 65 | BonusCritChance = -100; // no crits plz 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /swlsimNET.Tests/ChaosTest.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using swlSimulator.api; 4 | using swlSimulator.api.Combat; 5 | using swlSimulator.api.Models; 6 | using swlSimulator.api.Spells; 7 | using swlSimulator.api.Weapons; 8 | using swlSimulator.Models; 9 | 10 | namespace swlSimulator.Tests 11 | { 12 | [TestClass] 13 | public class ChaosTest 14 | { 15 | [TestMethod] 16 | public void TestChaosGimmick() 17 | { 18 | var setting = new Settings 19 | { 20 | CombatPower = 10, 21 | PrimaryWeapon = WeaponType.Chaos, 22 | SecondaryWeapon = WeaponType.Fist, 23 | FightLength = 10, 24 | TargetType = TargetType.Champion, 25 | Apl = "" 26 | }; 27 | 28 | var spell = new ChaosUnluckySpell(); 29 | var player = new Player(setting); 30 | player.Spells.Add(spell); 31 | 32 | var engine = new Engine(setting); 33 | var fight = engine.StartFight(player); 34 | 35 | var endTime = fight.RoundResults.Last().TimeSec; 36 | var rounds = fight.RoundResults.Count; 37 | 38 | var spellCount = fight.RoundResults 39 | .SelectMany(r => r.Attacks.Where(a => a.Spell is ChaosUnluckySpell)).Count(); 40 | 41 | Assert.AreEqual(rounds, 10); 42 | Assert.AreEqual(endTime, 10.0m); 43 | Assert.IsTrue(spellCount == 10); 44 | Assert.IsTrue(player.Paradox == 0); 45 | } 46 | 47 | [TestMethod] 48 | public void TestChaosGimmickParadox() 49 | { 50 | var setting = new Settings 51 | { 52 | CombatPower = 10, 53 | PrimaryWeapon = WeaponType.Chaos, 54 | SecondaryWeapon = WeaponType.Fist, 55 | FightLength = 4, 56 | TargetType = TargetType.Champion, 57 | Apl = "" 58 | }; 59 | 60 | var spell = new ChaosLuckySpell(); 61 | var player = new Player(setting); 62 | player.Spells.Add(spell); 63 | 64 | var engine = new Engine(setting); 65 | var fight = engine.StartFight(player); 66 | 67 | var endTime = fight.RoundResults.Last().TimeSec; 68 | var rounds = fight.RoundResults.Count; 69 | 70 | var spellCount = fight.RoundResults 71 | .SelectMany(r => r.Attacks.Where(a => a.Spell is ChaosLuckySpell)).Count(); 72 | 73 | Assert.AreEqual(rounds, 4); 74 | Assert.AreEqual(endTime, 4.0m); 75 | Assert.IsTrue(spellCount == 4); 76 | Assert.IsTrue(player.Paradox == 8); 77 | } 78 | 79 | private sealed class ChaosUnluckySpell : Spell 80 | { 81 | public ChaosUnluckySpell() 82 | { 83 | WeaponType = WeaponType.Chaos; 84 | SpellType = SpellType.Cast; 85 | CastTime = 1; 86 | BaseDamage = 1; 87 | } 88 | } 89 | 90 | private sealed class ChaosLuckySpell : Spell 91 | { 92 | public ChaosLuckySpell() 93 | { 94 | WeaponType = WeaponType.Chaos; 95 | SpellType = SpellType.Cast; 96 | CastTime = 1; 97 | BaseDamage = 8; 98 | } 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /swlsimNET.Tests/FistTest.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using swlSimulator.api; 4 | using swlSimulator.api.Combat; 5 | using swlSimulator.api.Models; 6 | using swlSimulator.api.Spells; 7 | using swlSimulator.api.Weapons; 8 | using swlSimulator.Models; 9 | 10 | namespace swlSimulator.Tests 11 | { 12 | [TestClass] 13 | public class FistTest 14 | { 15 | [TestMethod] 16 | public void TestFistGimmick() 17 | { 18 | var setting = new Settings 19 | { 20 | CombatPower = 10, 21 | PrimaryWeapon = WeaponType.Fist, 22 | SecondaryWeapon = WeaponType.Pistol, 23 | FightLength = 5, 24 | TargetType = TargetType.Champion, 25 | Apl = "" 26 | }; 27 | 28 | var player = new Player(setting); 29 | var spell = new FistSpell(); 30 | player.Spells.Add(spell); 31 | 32 | var engine = new Engine(setting); 33 | var fight = engine.StartFight(player); 34 | 35 | var spells = fight.RoundResults 36 | .SelectMany(r => r.Attacks.Where(a => a.Spell is FistSpell)).Count(); 37 | 38 | var fist = player.Fist; 39 | 40 | Assert.IsTrue(spells == 6); 41 | Assert.IsFalse(fist.AllowFrenziedWrathAbilities); 42 | } 43 | 44 | [TestMethod] 45 | public void TestFistGimmickFrenziedWrath() 46 | { 47 | var setting = new Settings 48 | { 49 | CombatPower = 10, 50 | PrimaryWeapon = WeaponType.Fist, 51 | SecondaryWeapon = WeaponType.Pistol, 52 | FightLength = 6, 53 | TargetType = TargetType.Champion, 54 | Apl = "" 55 | }; 56 | 57 | var player = new Player(setting); 58 | var spell = new FistSpell(); 59 | player.Spells.Add(spell); 60 | 61 | var engine = new Engine(setting); 62 | var fight = engine.StartFight(player); 63 | 64 | var spells = fight.RoundResults 65 | .SelectMany(r => r.Attacks.Where(a => a.Spell is FistSpell)).Count(); 66 | 67 | var fist = player.Fist; 68 | 69 | Assert.IsTrue(spells == 7); 70 | Assert.IsTrue(fist.AllowFrenziedWrathAbilities); 71 | } 72 | 73 | private sealed class FistSpell : Spell 74 | { 75 | public FistSpell() 76 | { 77 | WeaponType = WeaponType.Fist; 78 | SpellType = SpellType.Cast; 79 | CastTime = 0; 80 | PrimaryGimmickGain = 10; 81 | BaseDamage = 1; 82 | BonusCritChance = -100; // no crits plz 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /swlsimNET.Tests/HammerTest.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using swlSimulator.api; 4 | using swlSimulator.api.Combat; 5 | using swlSimulator.api.Models; 6 | using swlSimulator.api.Spells; 7 | using swlSimulator.api.Weapons; 8 | using swlSimulator.Models; 9 | 10 | namespace swlSimulator.Tests 11 | { 12 | [TestClass] 13 | public class HammerTest 14 | { 15 | [TestMethod] 16 | public void TestHammerGimmick() 17 | { 18 | var setting = new Settings 19 | { 20 | PrimaryWeapon = WeaponType.Hammer, 21 | SecondaryWeapon = WeaponType.Fist, 22 | FightLength = 3, 23 | TargetType = TargetType.Champion, 24 | Apl = "" 25 | }; 26 | 27 | var player = new Player(setting); 28 | var hSpell = new HammerSpell(); 29 | var hSpellRage = new HammerSpellRage(); 30 | 31 | player.Spells.Add(hSpell); 32 | player.Spells.Add(hSpellRage); 33 | 34 | var engine = new Engine(setting); 35 | var fight = engine.StartFight(player); 36 | 37 | var endTime = fight.RoundResults.Last().TimeSec; 38 | var rounds = fight.RoundResults.Count; 39 | 40 | var spell = fight.RoundResults 41 | .SelectMany(r => r.Attacks.Where(a => a.Spell is HammerSpell)).Count(); 42 | var spellRage = fight.RoundResults 43 | .SelectMany(r => r.Attacks.Where(a => a.Spell is HammerSpellRage)).Count(); 44 | 45 | Assert.AreEqual(rounds, 4); 46 | Assert.AreEqual(endTime, 3.0m); 47 | Assert.IsTrue(spell == 2); 48 | Assert.IsTrue(spellRage == 2); 49 | } 50 | 51 | [TestMethod] 52 | public void TestHammerEnrage() 53 | { 54 | var setting = new Settings 55 | { 56 | PrimaryWeapon = WeaponType.Hammer, 57 | SecondaryWeapon = WeaponType.Fist, 58 | FightLength = 1, 59 | TargetType = TargetType.Champion, 60 | Apl = "Hammer.Smash, Buff.Enraged" 61 | }; 62 | 63 | var player = new Player(setting); 64 | var engine = new Engine(setting); 65 | var fight = engine.StartFight(player); 66 | 67 | var attacks = fight.RoundResults.Any(); 68 | Assert.IsFalse(attacks); 69 | } 70 | 71 | [TestMethod] 72 | public void TestHammerEnrage2() 73 | { 74 | var setting = new Settings 75 | { 76 | PrimaryWeapon = WeaponType.Hammer, 77 | SecondaryWeapon = WeaponType.Fist, 78 | FightLength = 1, 79 | TargetType = TargetType.Champion, 80 | Apl = "" 81 | }; 82 | 83 | var player = new Player(setting); 84 | var hSpell = new HammerSpell(); 85 | player.Spells.Add(hSpell); 86 | 87 | var engine = new Engine(setting); 88 | var fight = engine.StartFight(player); 89 | 90 | var attacks = fight.RoundResults.Any(); 91 | Assert.IsTrue(attacks); 92 | Assert.IsTrue(player.Buff.Enraged); 93 | } 94 | 95 | private sealed class HammerSpell : Spell 96 | { 97 | public HammerSpell() 98 | { 99 | PrimaryGimmickGain = 50; 100 | WeaponType = WeaponType.Hammer; 101 | SpellType = SpellType.Cast; 102 | BaseDamage = 1; 103 | } 104 | } 105 | 106 | private sealed class HammerSpellRage: Spell 107 | { 108 | public HammerSpellRage() 109 | { 110 | PrimaryGimmickCost = 50; 111 | WeaponType = WeaponType.Hammer; 112 | SpellType = SpellType.Cast; 113 | BaseDamage = 1; 114 | } 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /swlsimNET.Tests/PistolTest.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using swlSimulator.api; 4 | using swlSimulator.api.Combat; 5 | using swlSimulator.api.Models; 6 | using swlSimulator.api.Spells; 7 | using swlSimulator.api.Weapons; 8 | using swlSimulator.Models; 9 | 10 | namespace swlSimulator.Tests 11 | { 12 | [TestClass] 13 | public class PistolTest 14 | { 15 | [TestMethod] 16 | public void TestPistolInitialGimmick() 17 | { 18 | var setting = new Settings 19 | { 20 | CombatPower = 10, 21 | PrimaryWeapon = WeaponType.Pistol, 22 | SecondaryWeapon = WeaponType.Fist, 23 | FightLength = 3, 24 | TargetType = TargetType.Champion, 25 | Apl = "" 26 | }; 27 | 28 | var player = new Player(setting); 29 | var spell = new PistolSpell(); 30 | player.Spells.Add(spell); 31 | 32 | var engine = new Engine(setting); 33 | var fight = engine.StartFight(player); 34 | 35 | var spells = fight.RoundResults 36 | .SelectMany(r => r.Attacks.Where(a => a.Spell is PistolSpell)).Count(); 37 | 38 | var pistol = player.Pistol; 39 | 40 | Assert.IsTrue(spells == 3); 41 | Assert.IsTrue(pistol.LeftChamber == Chamber.White); 42 | Assert.IsTrue(pistol.RightChamber == Chamber.White); 43 | } 44 | 45 | [TestMethod] 46 | public void TestPistolGimmick() 47 | { 48 | var setting = new Settings 49 | { 50 | CombatPower = 10, 51 | PrimaryWeapon = WeaponType.Pistol, 52 | SecondaryWeapon = WeaponType.Fist, 53 | FightLength = 4, 54 | TargetType = TargetType.Champion, 55 | Apl = "" 56 | }; 57 | 58 | var player = new Player(setting); 59 | var spell = new PistolSpell(); 60 | player.Spells.Add(spell); 61 | 62 | var engine = new Engine(setting); 63 | var fight = engine.StartFight(player); 64 | 65 | var spells = fight.RoundResults 66 | .SelectMany(r => r.Attacks.Where(a => a.Spell is PistolSpell)).Count(); 67 | 68 | var pistol = player.Pistol; 69 | 70 | Assert.IsTrue(spells == 4); 71 | Assert.IsTrue(pistol.ChamberLockTimeStamp == 4); 72 | } 73 | 74 | private sealed class PistolSpell : Spell 75 | { 76 | public PistolSpell() 77 | { 78 | WeaponType = WeaponType.Pistol; 79 | SpellType = SpellType.Cast; 80 | CastTime = 1; 81 | BaseDamage = 1; 82 | BonusCritChance = -100; // no crits plz 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /swlsimNET.Tests/PlayerTest.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using swlSimulator.api; 4 | using swlSimulator.api.Combat; 5 | using swlSimulator.api.Models; 6 | using swlSimulator.api.Spells.Hammer; 7 | using swlSimulator.api.Weapons; 8 | using swlSimulator.Models; 9 | 10 | namespace swlSimulator.Tests 11 | { 12 | [TestClass] 13 | public class PlayerTest 14 | { 15 | [TestMethod] 16 | public void AplReaderTest() 17 | { 18 | var setting = TestSettingsHammerFist(); 19 | setting.Apl = "Hammer.Smash, Rage < 50"; 20 | 21 | var player = new Player(setting); 22 | var spell = player.Spells.Find(s => s.GetType() == typeof(Smash)); 23 | 24 | var spellArgs = spell.Args == "Rage < 50"; 25 | 26 | Assert.IsTrue(spell != null && spellArgs); 27 | } 28 | 29 | [TestMethod] 30 | public void AplTest() 31 | { 32 | var setting = TestSettingsHammerFist(); 33 | setting.Apl = "Hammer.Smash, Rage > 50"; 34 | setting.FightLength = 10; 35 | 36 | var player = new Player(setting); 37 | var engine = new Engine(setting); 38 | var fight = engine.StartFight(player); 39 | 40 | var spells = fight.RoundResults 41 | .SelectMany(r => r.Attacks.Where(a => a.Spell is Smash)).Count(); 42 | 43 | Assert.IsTrue(spells == 0); 44 | } 45 | 46 | [TestMethod] 47 | public void WeaponTypes() 48 | { 49 | var setting = TestSettingsHammerFist(); 50 | setting.Apl = "Hammer.Smash"; 51 | var player = new Player(setting); 52 | 53 | Assert.IsInstanceOfType(player.PrimaryWeapon, typeof(Hammer)); 54 | Assert.IsInstanceOfType(player.SecondaryWeapon, typeof(Fist)); 55 | } 56 | 57 | private Settings TestSettingsHammerFist() 58 | { 59 | return new Settings 60 | { 61 | PrimaryWeapon = WeaponType.Hammer, 62 | SecondaryWeapon = WeaponType.Fist, 63 | TargetType = TargetType.Champion 64 | }; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /swlsimNET.Tests/ShotgunTest.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using swlSimulator.api; 4 | using swlSimulator.api.Combat; 5 | using swlSimulator.api.Models; 6 | using swlSimulator.api.Spells; 7 | using swlSimulator.api.Spells.Shotgun; 8 | using swlSimulator.api.Weapons; 9 | using swlSimulator.Models; 10 | 11 | namespace swlSimulator.Tests 12 | { 13 | [TestClass] 14 | public class ShotgunTest 15 | { 16 | [TestMethod] 17 | public void TestShotgunGimmick() 18 | { 19 | var setting = new Settings 20 | { 21 | PrimaryWeapon = WeaponType.Shotgun, 22 | SecondaryWeapon = WeaponType.Fist, 23 | FightLength = 10, 24 | TargetType = TargetType.Champion, 25 | Apl = "" // "Shotgun.Reload, Shells == 0" 26 | }; 27 | 28 | var spell = new ShotgunSpell(); 29 | var player = new Player(setting); 30 | player.Spells.Add(spell); 31 | 32 | var engine = new Engine(setting); 33 | var fight = engine.StartFight(player); 34 | 35 | var endTime = fight.RoundResults.Last().TimeSec; 36 | var rounds = fight.RoundResults.Count; 37 | 38 | var loadCount = fight.RoundResults 39 | .SelectMany(r => r.Attacks.Where(a => a.Spell is Reload)).Count(); 40 | var spellCount = fight.RoundResults 41 | .SelectMany(r => r.Attacks.Where(a => a.Spell is ShotgunSpell)).Count(); 42 | 43 | // 0.0, cast cast: 1 44 | // 1.0, cast cast: 2 45 | // 2.0, cast cast: 3 46 | // 3.0, cast cast: 4 47 | // 4.0, cast cast: 5 48 | // 5.0, cast cast: 6 49 | // 6.0 - 10.0, nothing OUT OF SHELLS 50 | 51 | Assert.AreEqual(rounds, 6); 52 | Assert.AreEqual(endTime, 5.0m); 53 | Assert.IsTrue(loadCount == 0); 54 | Assert.IsTrue(spellCount == 6); 55 | } 56 | 57 | [TestMethod] 58 | public void TestShotgunGimmickReload() 59 | { 60 | var setting = new Settings 61 | { 62 | PrimaryWeapon = WeaponType.Shotgun, 63 | SecondaryWeapon = WeaponType.Fist, 64 | FightLength = 10, 65 | TargetType = TargetType.Champion, 66 | Apl = "Shotgun.Reload, Shells == 0" 67 | }; 68 | 69 | var spell = new ShotgunSpell(); 70 | var player = new Player(setting); 71 | player.Spells.Add(spell); 72 | 73 | var engine = new Engine(setting); 74 | var fight = engine.StartFight(player); 75 | 76 | var endTime = fight.RoundResults.Last().TimeSec; 77 | var rounds = fight.RoundResults.Count; 78 | 79 | var loadCount = fight.RoundResults 80 | .SelectMany(r => r.Attacks.Where(a => a.Spell is Reload)).Count(); 81 | var spellCount = fight.RoundResults 82 | .SelectMany(r => r.Attacks.Where(a => a.Spell is ShotgunSpell)).Count(); 83 | 84 | // 0.0, cast cast: 1 85 | // 1.0, cast cast: 2 86 | // 2.0, cast cast: 3 87 | // 3.0, cast cast: 4 88 | // 4.0, cast cast: 5 89 | // 5.0, cast cast: 6 90 | // 6.0, reload reload: 1 91 | // 7.0, cast cast: 7 92 | // 8.0, cast cast: 8 93 | // 9.0, cast cast: 9 94 | // 10.0, cast cast: 10 95 | 96 | Assert.AreEqual(rounds, 11); 97 | Assert.AreEqual(endTime, 10.0m); 98 | Assert.IsTrue(loadCount == 1); 99 | Assert.IsTrue(spellCount == 10); 100 | } 101 | 102 | private sealed class ShotgunSpell : Spell 103 | { 104 | public ShotgunSpell() 105 | { 106 | WeaponType = WeaponType.Shotgun; 107 | SpellType = SpellType.Cast; 108 | PrimaryGimmickCost = 1; 109 | CastTime = 0; 110 | BaseDamage = 1; 111 | } 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /swlsimNET.Tests/swlSimulator.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.0 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /swlsimNET.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26730.16 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "swlSimulator.Tests", "swlsimNET.Tests\swlSimulator.Tests.csproj", "{897434E7-CFA1-449D-A27B-23628B5534EF}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "swlSimulator", "swlSimulator\swlSimulator.csproj", "{0BE27454-B983-4B85-B4A0-46EF055A4505}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {897434E7-CFA1-449D-A27B-23628B5534EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {897434E7-CFA1-449D-A27B-23628B5534EF}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {897434E7-CFA1-449D-A27B-23628B5534EF}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {897434E7-CFA1-449D-A27B-23628B5534EF}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {0BE27454-B983-4B85-B4A0-46EF055A4505}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {0BE27454-B983-4B85-B4A0-46EF055A4505}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {0BE27454-B983-4B85-B4A0-46EF055A4505}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {0BE27454-B983-4B85-B4A0-46EF055A4505}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {754738D8-3C5C-4CBA-B97C-C6C17922784D} 30 | EndGlobalSection 31 | EndGlobal 32 | --------------------------------------------------------------------------------