Idea: damage calculator
This commit is contained in:
parent
b56d534cb3
commit
cbfb00490e
|
@ -217,3 +217,63 @@ List<DateTime> seasonStarts = [
|
||||||
List<DateTime> seasonEnds = [
|
List<DateTime> seasonEnds = [
|
||||||
DateTime.utc(2024, DateTime.july, 26, 15) // Source - TETR.IO discord guild
|
DateTime.utc(2024, DateTime.july, 26, 15) // Source - TETR.IO discord guild
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/// Stolen directly from TETR.IO, redone for the sake of me
|
||||||
|
|
||||||
|
enum Lineclears{
|
||||||
|
ZERO,
|
||||||
|
SINGLE,
|
||||||
|
DOUBLE,
|
||||||
|
TRIPLE,
|
||||||
|
QUAD,
|
||||||
|
PENTA,
|
||||||
|
TSPIN_MINI,
|
||||||
|
TSPIN,
|
||||||
|
TSPIN_MINI_SINGLE,
|
||||||
|
TSPIN_SINGLE,
|
||||||
|
TSPIN_MINI_DOUBLE,
|
||||||
|
TSPIN_DOUBLE,
|
||||||
|
TSPIN_MINI_TRIPLE,
|
||||||
|
TSPIN_TRIPLE,
|
||||||
|
TSPIN_MINI_QUAD,
|
||||||
|
TSPIN_QUAD,
|
||||||
|
TSPIN_PENTA,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ComboTables{
|
||||||
|
none,
|
||||||
|
classic,
|
||||||
|
modern
|
||||||
|
}
|
||||||
|
|
||||||
|
const int BACKTOBACK_BONUS = 1;
|
||||||
|
const double BACKTOBACK_BONUS_LOG = .8;
|
||||||
|
const int COMBO_MINIFIER = 1;
|
||||||
|
const double COMBO_MINIFIER_LOG = 1.25;
|
||||||
|
const double COMBO_BONUS = .25;
|
||||||
|
// const int ALL_CLEAR = 10; lol
|
||||||
|
|
||||||
|
const Map<Lineclears, int> garbage = {
|
||||||
|
Lineclears.SINGLE: 0,
|
||||||
|
Lineclears.DOUBLE: 1,
|
||||||
|
Lineclears.TRIPLE: 2,
|
||||||
|
Lineclears.QUAD: 4,
|
||||||
|
Lineclears.PENTA: 5,
|
||||||
|
Lineclears.TSPIN_MINI: 0,
|
||||||
|
Lineclears.TSPIN: 0,
|
||||||
|
Lineclears.TSPIN_MINI_SINGLE: 0,
|
||||||
|
Lineclears.TSPIN_SINGLE: 2,
|
||||||
|
Lineclears.TSPIN_MINI_DOUBLE: 1,
|
||||||
|
Lineclears.TSPIN_DOUBLE: 4,
|
||||||
|
Lineclears.TSPIN_MINI_TRIPLE: 2,
|
||||||
|
Lineclears.TSPIN_TRIPLE: 6,
|
||||||
|
Lineclears.TSPIN_MINI_QUAD: 4,
|
||||||
|
Lineclears.TSPIN_QUAD: 10,
|
||||||
|
Lineclears.TSPIN_PENTA: 12
|
||||||
|
};
|
||||||
|
|
||||||
|
const Map<ComboTables, List<int>> combotable = {
|
||||||
|
ComboTables.none: [0],
|
||||||
|
ComboTables.classic: [0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5],
|
||||||
|
ComboTables.modern: [0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4]
|
||||||
|
};
|
|
@ -1,5 +1,6 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:ui' as ui;
|
import 'dart:ui' as ui;
|
||||||
|
import 'dart:math';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart' hide Badge;
|
import 'package:flutter/material.dart' hide Badge;
|
||||||
|
@ -222,6 +223,76 @@ class DestinationCalculator extends StatefulWidget{
|
||||||
State<DestinationCalculator> createState() => _DestinationCalculatorState();
|
State<DestinationCalculator> createState() => _DestinationCalculatorState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum CalcCards{
|
||||||
|
calc,
|
||||||
|
damage
|
||||||
|
}
|
||||||
|
|
||||||
|
class ClearData{
|
||||||
|
final String title;
|
||||||
|
final Lineclears lineclear;
|
||||||
|
final int lines;
|
||||||
|
final bool miniSpin;
|
||||||
|
final bool spin;
|
||||||
|
bool perfectClear = false;
|
||||||
|
|
||||||
|
ClearData(this.title, this.lineclear, this.lines, this.miniSpin, this.spin);
|
||||||
|
|
||||||
|
bool get difficultClear {
|
||||||
|
if (lines == 0) return false;
|
||||||
|
if (lines >= 4 || miniSpin || spin) return true;
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void togglePC(){
|
||||||
|
perfectClear = !perfectClear;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dealsDamage(int combo, int b2b, ComboTables table,){
|
||||||
|
if (lines == 0) return 0;
|
||||||
|
double damage = 0;
|
||||||
|
if (spin){
|
||||||
|
if (lines <= 5) damage += garbage[lineclear]!;
|
||||||
|
else damage += garbage[Lineclears.TSPIN_PENTA]! + 2 * (lines - 5);
|
||||||
|
} else if (miniSpin){
|
||||||
|
damage += garbage[lineclear]!;
|
||||||
|
} else {
|
||||||
|
if (lines <= 5) damage += garbage[lineclear]!;
|
||||||
|
else damage += garbage[Lineclears.PENTA]! + (lines - 5);
|
||||||
|
}
|
||||||
|
if (difficultClear && b2b > 0){
|
||||||
|
damage += BACKTOBACK_BONUS * ((1 + log((b2b - 1) * BACKTOBACK_BONUS_LOG)).floor() + (b2b - 1 == 1 ? 0 : (1 + log((b2b - 1) * BACKTOBACK_BONUS_LOG) % 1) / 3));;
|
||||||
|
}
|
||||||
|
if (combo > 1){
|
||||||
|
damage += combotable[table]![max(0, min(combo - 2, combotable[table]!.length - 1))];
|
||||||
|
}
|
||||||
|
return damage.floor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, List<ClearData>> clearsExisting = {
|
||||||
|
"No Spin Clears": [
|
||||||
|
ClearData("No lineclear (Break Combo)", Lineclears.ZERO, 0, false, false),
|
||||||
|
ClearData("Single", Lineclears.SINGLE, 1, false, false),
|
||||||
|
ClearData("Double", Lineclears.DOUBLE, 2, false, false),
|
||||||
|
ClearData("Triple", Lineclears.TRIPLE, 3, false, false),
|
||||||
|
ClearData("Quad", Lineclears.QUAD, 4, false, false)
|
||||||
|
],
|
||||||
|
"Spins": [
|
||||||
|
ClearData("Spin Zero", Lineclears.TSPIN, 0, false, true),
|
||||||
|
ClearData("Spin Single", Lineclears.TSPIN_SINGLE, 1, false, true),
|
||||||
|
ClearData("Spin Double", Lineclears.TSPIN_DOUBLE, 2, false, true),
|
||||||
|
ClearData("Spin Spin Triple", Lineclears.TSPIN_TRIPLE, 3, false, true),
|
||||||
|
ClearData("Spin Spin Quad", Lineclears.TSPIN_QUAD, 4, false, true),
|
||||||
|
],
|
||||||
|
"Mini spins": [
|
||||||
|
ClearData("Mini Spin Zero", Lineclears.TSPIN_MINI, 0, true, false),
|
||||||
|
ClearData("Mini Spin Single", Lineclears.TSPIN_MINI_SINGLE, 1, true, false),
|
||||||
|
ClearData("Mini Spin Double", Lineclears.TSPIN_MINI_DOUBLE, 2, true, false),
|
||||||
|
ClearData("Mini Spin Spin Triple", Lineclears.TSPIN_MINI_TRIPLE, 3, true, false),
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
class _DestinationCalculatorState extends State<DestinationCalculator> {
|
class _DestinationCalculatorState extends State<DestinationCalculator> {
|
||||||
double? apm;
|
double? apm;
|
||||||
double? pps;
|
double? pps;
|
||||||
|
@ -233,6 +304,10 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
|
||||||
TextEditingController apmController = TextEditingController();
|
TextEditingController apmController = TextEditingController();
|
||||||
TextEditingController vsController = TextEditingController();
|
TextEditingController vsController = TextEditingController();
|
||||||
|
|
||||||
|
List<ClearData> clears = [];
|
||||||
|
int combo = -1;
|
||||||
|
int b2b = -1;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
@ -257,8 +332,13 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
void calcDamage(){
|
||||||
Widget build(BuildContext context) {
|
for (ClearData lineclear in clears){
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget getCalculator(){
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
|
@ -274,36 +354,42 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
|
||||||
),
|
),
|
||||||
Card(
|
Card(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 8.0),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(right: 12),
|
padding: const EdgeInsets.fromLTRB(12.0, 0.0, 12.0, 0.0),
|
||||||
child: TextField(
|
|
||||||
onSubmitted: (value) => calc(),
|
|
||||||
controller: apmController,
|
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
decoration: const InputDecoration(suffix: Text("APM"), alignLabelWithHint: true, hintText: "Enter your APM"),
|
|
||||||
),
|
|
||||||
)),
|
|
||||||
Expanded(
|
|
||||||
child: TextField(
|
child: TextField(
|
||||||
onSubmitted: (value) => calc(),
|
onSubmitted: (value) => calc(),
|
||||||
controller: ppsController,
|
controller: apmController,
|
||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
decoration: const InputDecoration(suffix: Text("PPS"), alignLabelWithHint: true, hintText: "Enter your PPS"),
|
decoration: const InputDecoration(suffix: Text("APM"), alignLabelWithHint: true, hintText: "Enter your APM"),
|
||||||
)),
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(left: 12),
|
padding: const EdgeInsets.fromLTRB(12.0, 0.0, 12.0, 0.0),
|
||||||
child: TextField(
|
child: TextField(
|
||||||
onSubmitted: (value) => calc(),
|
onSubmitted: (value) => calc(),
|
||||||
controller: vsController,
|
controller: ppsController,
|
||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
decoration: const InputDecoration(suffix: Text("VS"), alignLabelWithHint: true, hintText: "Enter your VS"),
|
decoration: const InputDecoration(suffix: Text("PPS"), alignLabelWithHint: true, hintText: "Enter your PPS"),
|
||||||
|
),
|
||||||
|
)
|
||||||
),
|
),
|
||||||
)),
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(12.0, 0.0, 12.0, 0.0),
|
||||||
|
child: TextField(
|
||||||
|
onSubmitted: (value) => calc(),
|
||||||
|
controller: vsController,
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
decoration: const InputDecoration(suffix: Text("VS"), alignLabelWithHint: true, hintText: "Enter your VS"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => calc(),
|
onPressed: () => calc(),
|
||||||
child: Text(t.calc),
|
child: Text(t.calc),
|
||||||
|
@ -312,19 +398,142 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (nerdStats != null && playstyle != null) Card(
|
if (nerdStats != null) Card(
|
||||||
child: Row(
|
child: NerdStatsThingy(nerdStats: nerdStats!)
|
||||||
children: [
|
),
|
||||||
Expanded(child: NerdStatsThingy(nerdStats: nerdStats!)),
|
if (playstyle != null) Card(
|
||||||
Expanded(child: GraphsThingy(nerdStats: nerdStats!, playstyle: playstyle!, apm: apm!, pps: pps!, vs: vs!))
|
child: GraphsThingy(nerdStats: nerdStats!, playstyle: playstyle!, apm: apm!, pps: pps!, vs: vs!)
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget getDamageCalculator(){
|
||||||
|
List<Widget> rSideWidgets = [];
|
||||||
|
for (var key in clearsExisting.keys){
|
||||||
|
rSideWidgets.add(Text(key));
|
||||||
|
for (ClearData data in clearsExisting[key]!) rSideWidgets.add(Card(
|
||||||
|
child: ListTile(
|
||||||
|
title: Text(data.title),
|
||||||
|
subtitle: Text("${data.dealsDamage(0, 0, ComboTables.modern)} damage${data.difficultClear ? ", difficult" : ""}", style: TextStyle(color: Colors.grey)),
|
||||||
|
trailing: Icon(Icons.arrow_forward_ios),
|
||||||
|
onTap: (){
|
||||||
|
setState((){
|
||||||
|
clears.add(data);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
));
|
||||||
|
rSideWidgets.add(Text("Custom"));
|
||||||
|
rSideWidgets.add(const Divider(color: Color.fromARGB(50, 158, 158, 158)));
|
||||||
|
}
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Card(
|
||||||
|
child: Center(child: Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 8.0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Text("Damage Calucator", style: const TextStyle(fontFamily: "Eurostile Round Extended", fontSize: 42)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: 350.0,
|
||||||
|
child: DefaultTabController(length: 2,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Card(
|
||||||
|
child: TabBar(tabs: [
|
||||||
|
Tab(text: "Actions"),
|
||||||
|
Tab(text: "Rules"),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: widget.constraints.maxHeight - 164,
|
||||||
|
child: TabBarView(children: [
|
||||||
|
SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
children: rSideWidgets,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SingleChildScrollView(
|
||||||
|
child: Card(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
ListTile(
|
||||||
|
title: Text("Doubles"),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: widget.constraints.maxWidth - 350 - 80,
|
||||||
|
child: Card(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
children: [for (ClearData data in clears) ListTile(
|
||||||
|
title: Text(data.title),
|
||||||
|
subtitle: Text("${data.dealsDamage(0, 0, ComboTables.modern)} damage${data.difficultClear ? ", difficult" : ""}", style: TextStyle(color: Colors.grey)),
|
||||||
|
trailing: Text(data.dealsDamage(0, 0, ComboTables.modern).toString()),
|
||||||
|
onTap: (){
|
||||||
|
clears.add(data);
|
||||||
|
},
|
||||||
|
)],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: widget.constraints.maxHeight -32,
|
||||||
|
child: getDamageCalculator(),
|
||||||
|
),
|
||||||
|
SegmentedButton<CalcCards>(
|
||||||
|
showSelectedIcon: false,
|
||||||
|
segments: <ButtonSegment<CalcCards>>[
|
||||||
|
const ButtonSegment<CalcCards>(
|
||||||
|
value: CalcCards.calc,
|
||||||
|
label: Text('Stats Calculator'),
|
||||||
|
),
|
||||||
|
ButtonSegment<CalcCards>(
|
||||||
|
value: CalcCards.damage,
|
||||||
|
label: Text('Damage Calculator'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
selected: <CalcCards>{CalcCards.damage},
|
||||||
|
onSelectionChanged: (Set<CalcCards> newSelection) {
|
||||||
|
setState(() {
|
||||||
|
// cardMod = CardMod.info;
|
||||||
|
// rightCard = newSelection.first;
|
||||||
|
});})
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class FetchCutoffsResults{
|
class FetchCutoffsResults{
|
||||||
|
|
Loading…
Reference in New Issue