Idea: damage calculator

This commit is contained in:
dan63047 2024-09-22 02:11:31 +03:00
parent b56d534cb3
commit cbfb00490e
2 changed files with 302 additions and 33 deletions

View File

@ -217,3 +217,63 @@ List<DateTime> seasonStarts = [
List<DateTime> seasonEnds = [
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]
};

View File

@ -1,5 +1,6 @@
import 'dart:async';
import 'dart:ui' as ui;
import 'dart:math';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart' hide Badge;
@ -222,6 +223,76 @@ class DestinationCalculator extends StatefulWidget{
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> {
double? apm;
double? pps;
@ -233,6 +304,10 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
TextEditingController apmController = TextEditingController();
TextEditingController vsController = TextEditingController();
List<ClearData> clears = [];
int combo = -1;
int b2b = -1;
@override
void initState() {
super.initState();
@ -257,8 +332,13 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
}
}
@override
Widget build(BuildContext context) {
void calcDamage(){
for (ClearData lineclear in clears){
}
}
Widget getCalculator(){
return SingleChildScrollView(
child: Column(
children: [
@ -274,36 +354,42 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
),
Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
padding: const EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 8.0),
child: Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.only(right: 12),
child: TextField(
onSubmitted: (value) => calc(),
controller: apmController,
keyboardType: TextInputType.number,
decoration: const InputDecoration(suffix: Text("APM"), alignLabelWithHint: true, hintText: "Enter your APM"),
),
)),
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(12.0, 0.0, 12.0, 0.0),
child: TextField(
onSubmitted: (value) => calc(),
controller: ppsController,
keyboardType: TextInputType.number,
decoration: const InputDecoration(suffix: Text("PPS"), alignLabelWithHint: true, hintText: "Enter your PPS"),
)),
onSubmitted: (value) => calc(),
controller: apmController,
keyboardType: TextInputType.number,
decoration: const InputDecoration(suffix: Text("APM"), alignLabelWithHint: true, hintText: "Enter your APM"),
),
)
),
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 12),
child: TextField(
onSubmitted: (value) => calc(),
controller: vsController,
keyboardType: TextInputType.number,
decoration: const InputDecoration(suffix: Text("VS"), alignLabelWithHint: true, hintText: "Enter your VS"),
child: Padding(
padding: const EdgeInsets.fromLTRB(12.0, 0.0, 12.0, 0.0),
child: TextField(
onSubmitted: (value) => calc(),
controller: ppsController,
keyboardType: TextInputType.number,
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(
onPressed: () => calc(),
child: Text(t.calc),
@ -312,19 +398,142 @@ class _DestinationCalculatorState extends State<DestinationCalculator> {
),
),
),
if (nerdStats != null && playstyle != null) Card(
child: Row(
children: [
Expanded(child: NerdStatsThingy(nerdStats: nerdStats!)),
Expanded(child: GraphsThingy(nerdStats: nerdStats!, playstyle: playstyle!, apm: apm!, pps: pps!, vs: vs!))
],
),
if (nerdStats != null) Card(
child: NerdStatsThingy(nerdStats: nerdStats!)
),
if (playstyle != null) Card(
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{