From 542cd3de808e3247c15b4741d2d5dd322ec6388f Mon Sep 17 00:00:00 2001
From: Oskar Marquardt <oskar.marquardt@student.uni-halle.de>
Date: Fri, 28 Jun 2024 11:09:07 +0200
Subject: [PATCH] Generalized sphere to stat - Removed Sphere module

---
 public/main.js    | 278 +++++++++++++++++++++++-----------------------
 src/Character.elm |  54 ++++-----
 src/Creation.elm  |   4 +-
 src/Main.elm      | 145 ++++++++++++------------
 src/Sphere.elm    |  45 --------
 src/Stats.elm     | 132 ++++++++++++++--------
 6 files changed, 324 insertions(+), 334 deletions(-)
 delete mode 100644 src/Sphere.elm

diff --git a/public/main.js b/public/main.js
index 676d0e2..01d0578 100644
--- a/public/main.js
+++ b/public/main.js
@@ -5160,64 +5160,37 @@ var $elm$core$Task$perform = F2(
 	});
 var $elm$browser$Browser$document = _Browser_document;
 var $author$project$Creation$new = {freebie: 15, spheres: 6};
+var $author$project$Stats$Arete = {$: 'Arete'};
 var $author$project$BoundedInt$new = F3(
 	function (value, min, max) {
 		return ((_Utils_cmp(value, min) < 0) || ((_Utils_cmp(value, max) > 0) || (_Utils_cmp(min, max) > 0))) ? {max: 0, min: 0, value: 0} : {max: max, min: min, value: value};
 	});
-var $author$project$Sphere$dots = function (value) {
-	return A3($author$project$BoundedInt$new, value, 0, 5);
+var $author$project$Stats$newArete = {
+	dots: A3($author$project$BoundedInt$new, 1, 0, 10),
+	name: 'Arete',
+	statType: $author$project$Stats$Arete
 };
-var $author$project$Stats$new = {
-	arete: A3($author$project$BoundedInt$new, 1, 0, 10),
-	spheres: _List_fromArray(
-		[
-			{
-			affinity: false,
-			dots: $author$project$Sphere$dots(0),
-			name: 'Correspondence'
-		},
-			{
-			affinity: false,
-			dots: $author$project$Sphere$dots(0),
-			name: 'Entropy'
-		},
-			{
-			affinity: false,
-			dots: $author$project$Sphere$dots(0),
-			name: 'Forces'
-		},
-			{
-			affinity: false,
-			dots: $author$project$Sphere$dots(0),
-			name: 'Life'
-		},
-			{
-			affinity: false,
-			dots: $author$project$Sphere$dots(0),
-			name: 'Matter'
-		},
-			{
-			affinity: false,
-			dots: $author$project$Sphere$dots(0),
-			name: 'Mind'
-		},
-			{
-			affinity: false,
-			dots: $author$project$Sphere$dots(0),
-			name: 'Prime'
-		},
-			{
-			affinity: false,
-			dots: $author$project$Sphere$dots(0),
-			name: 'Spirit'
-		},
-			{
-			affinity: false,
-			dots: $author$project$Sphere$dots(0),
-			name: 'Time'
-		}
-		])
+var $author$project$Stats$Sphere = {$: 'Sphere'};
+var $author$project$Stats$newSphere = function (name) {
+	return {
+		dots: A3($author$project$BoundedInt$new, 0, 0, 5),
+		name: name,
+		statType: $author$project$Stats$Sphere
+	};
 };
+var $author$project$Stats$new = _List_fromArray(
+	[
+		$author$project$Stats$newSphere('Correspondence'),
+		$author$project$Stats$newSphere('Entropy'),
+		$author$project$Stats$newSphere('Forces'),
+		$author$project$Stats$newSphere('Life'),
+		$author$project$Stats$newSphere('Matter'),
+		$author$project$Stats$newSphere('Mind'),
+		$author$project$Stats$newSphere('Prime'),
+		$author$project$Stats$newSphere('Spirit'),
+		$author$project$Stats$newSphere('Time'),
+		$author$project$Stats$newArete
+	]);
 var $author$project$Character$new = {creationPoints: $author$project$Creation$new, name: 'Default Name', stats: $author$project$Stats$new};
 var $elm$core$Platform$Cmd$batch = _Platform_batch;
 var $elm$core$Platform$Cmd$none = $elm$core$Platform$Cmd$batch(_List_Nil);
@@ -5237,6 +5210,39 @@ var $author$project$Character$changeName = F2(
 			character,
 			{name: newName});
 	});
+var $elm$core$List$filter = F2(
+	function (isGood, list) {
+		return A3(
+			$elm$core$List$foldr,
+			F2(
+				function (x, xs) {
+					return isGood(x) ? A2($elm$core$List$cons, x, xs) : xs;
+				}),
+			_List_Nil,
+			list);
+	});
+var $elm$core$List$head = function (list) {
+	if (list.b) {
+		var x = list.a;
+		var xs = list.b;
+		return $elm$core$Maybe$Just(x);
+	} else {
+		return $elm$core$Maybe$Nothing;
+	}
+};
+var $author$project$Stats$isArete = function (stat) {
+	return _Utils_eq(stat.statType, $author$project$Stats$Arete);
+};
+var $author$project$Stats$areteInList = function (stats) {
+	var maybeArete = $elm$core$List$head(
+		A2($elm$core$List$filter, $author$project$Stats$isArete, stats));
+	if (maybeArete.$ === 'Just') {
+		var arete = maybeArete.a;
+		return arete;
+	} else {
+		return $author$project$Stats$newArete;
+	}
+};
 var $author$project$Creation$buySphere = F2(
 	function (cp, value) {
 		return _Utils_update(
@@ -5249,100 +5255,85 @@ var $author$project$BoundedInt$changeTo = F2(
 			boundedInt,
 			{value: value});
 	});
-var $author$project$Sphere$changeDotsOfSphereTo = F2(
-	function (sphere, value) {
+var $author$project$Stats$changeDotsTo = F2(
+	function (stat, value) {
 		return _Utils_update(
-			sphere,
+			stat,
 			{
-				dots: A2($author$project$BoundedInt$changeTo, sphere.dots, value)
+				dots: A2($author$project$BoundedInt$changeTo, stat.dots, value)
 			});
 	});
-var $author$project$Sphere$isSphere = F2(
-	function (name, sphere) {
-		return _Utils_eq(sphere.name, name);
+var $author$project$Stats$isStat = F2(
+	function (name, stat) {
+		return _Utils_eq(stat.name, name);
 	});
-var $author$project$Sphere$changeSphere = F2(
-	function (newSphere, sphere) {
-		return A2($author$project$Sphere$isSphere, newSphere.name, sphere) ? newSphere : sphere;
+var $author$project$Stats$changeStatIfSame = F2(
+	function (newStat, oldStat) {
+		return A2($author$project$Stats$isStat, newStat.name, oldStat) ? newStat : oldStat;
 	});
-var $author$project$Sphere$changeSphereInList = F2(
-	function (spheres, sphere) {
+var $author$project$Stats$changeStatInList = F2(
+	function (stats, stat) {
 		return A2(
 			$elm$core$List$map,
-			$author$project$Sphere$changeSphere(sphere),
-			spheres);
-	});
-var $author$project$Stats$changeSphere = F2(
-	function (stats, sphere) {
-		return _Utils_update(
-			stats,
-			{
-				spheres: A2($author$project$Sphere$changeSphereInList, stats.spheres, sphere)
-			});
-	});
-var $elm$core$List$filter = F2(
-	function (isGood, list) {
-		return A3(
-			$elm$core$List$foldr,
-			F2(
-				function (x, xs) {
-					return isGood(x) ? A2($elm$core$List$cons, x, xs) : xs;
-				}),
-			_List_Nil,
-			list);
+			$author$project$Stats$changeStatIfSame(stat),
+			stats);
 	});
-var $elm$core$List$head = function (list) {
-	if (list.b) {
-		var x = list.a;
-		var xs = list.b;
-		return $elm$core$Maybe$Just(x);
-	} else {
-		return $elm$core$Maybe$Nothing;
-	}
-};
-var $author$project$Sphere$getDotsOfSphereInList = F2(
-	function (spheres, name) {
-		var maybeSphere = $elm$core$List$head(
+var $author$project$Stats$dotsOfStatInList = F2(
+	function (stats, name) {
+		var maybeStat = $elm$core$List$head(
 			A2(
 				$elm$core$List$filter,
-				$author$project$Sphere$isSphere(name),
-				spheres));
-		if (maybeSphere.$ === 'Nothing') {
+				$author$project$Stats$isStat(name),
+				stats));
+		if (maybeStat.$ === 'Nothing') {
 			return $elm$core$Maybe$Nothing;
 		} else {
-			var sphere = maybeSphere.a;
-			return $elm$core$Maybe$Just(sphere.dots);
+			var stat = maybeStat.a;
+			return $elm$core$Maybe$Just(stat.dots);
 		}
 	});
 var $elm$core$Basics$min = F2(
 	function (x, y) {
 		return (_Utils_cmp(x, y) < 0) ? x : y;
 	});
-var $author$project$Character$changeSphere = F2(
-	function (character, sphere) {
-		var maybeOldDots = A2($author$project$Sphere$getDotsOfSphereInList, character.stats.spheres, sphere.name);
-		var difference = function () {
+var $author$project$Stats$isSphere = function (stat) {
+	return _Utils_eq(stat.statType, $author$project$Stats$Sphere);
+};
+var $author$project$Stats$spheresInList = function (stats) {
+	return A2($elm$core$List$filter, $author$project$Stats$isSphere, stats);
+};
+var $author$project$Character$changeStat = F2(
+	function (character, stat) {
+		var _v0 = stat.statType;
+		if (_v0.$ === 'Sphere') {
+			var spheres = $author$project$Stats$spheresInList(character.stats);
+			var maybeOldDots = A2($author$project$Stats$dotsOfStatInList, spheres, stat.name);
+			var arete = $author$project$Stats$areteInList(character.stats);
+			var difference = function () {
+				if (maybeOldDots.$ === 'Nothing') {
+					return 0;
+				} else {
+					var oldDots = maybeOldDots.a;
+					return (_Utils_cmp(stat.dots.value, arete.dots.value) > 0) ? (arete.dots.value - oldDots.value) : (stat.dots.value - oldDots.value);
+				}
+			}();
 			if (maybeOldDots.$ === 'Nothing') {
-				return 0;
+				return character;
 			} else {
 				var oldDots = maybeOldDots.a;
-				return (_Utils_cmp(sphere.dots.value, character.stats.arete.value) > 0) ? (character.stats.arete.value - oldDots.value) : (sphere.dots.value - oldDots.value);
+				var buyAmount = A2($elm$core$Basics$min, difference, character.creationPoints.spheres);
+				return _Utils_update(
+					character,
+					{
+						creationPoints: A2($author$project$Creation$buySphere, character.creationPoints, buyAmount),
+						stats: A2(
+							$author$project$Stats$changeStatInList,
+							character.stats,
+							A2($author$project$Stats$changeDotsTo, stat, oldDots.value + buyAmount))
+					});
 			}
-		}();
-		if (maybeOldDots.$ === 'Nothing') {
-			return character;
 		} else {
-			var oldDots = maybeOldDots.a;
-			var buyAmount = A2($elm$core$Basics$min, difference, character.creationPoints.spheres);
-			return _Utils_update(
-				character,
-				{
-					creationPoints: A2($author$project$Creation$buySphere, character.creationPoints, buyAmount),
-					stats: A2(
-						$author$project$Stats$changeSphere,
-						character.stats,
-						A2($author$project$Sphere$changeDotsOfSphereTo, sphere, oldDots.value + buyAmount))
-				});
+			return character;
 		}
 	});
 var $author$project$Main$modalValue = F2(
@@ -5386,12 +5377,12 @@ var $author$project$Main$update = F2(
 						}),
 					$elm$core$Platform$Cmd$none);
 			default:
-				var sphere = msg.a;
+				var stat = msg.a;
 				return _Utils_Tuple2(
 					_Utils_update(
 						model,
 						{
-							character: A2($author$project$Character$changeSphere, model.character, sphere)
+							character: A2($author$project$Character$changeStat, model.character, stat)
 						}),
 					$elm$core$Platform$Cmd$none);
 		}
@@ -5669,8 +5660,8 @@ var $author$project$Main$toDotPosition = F4(
 		var marginalIncrease = (size + gap) / 2;
 		return _Utils_Tuple2((id * marginalIncrease) + offset, (((id + 1) % 2) * marginalIncrease) + offset);
 	});
-var $author$project$Main$ChangeSphere = function (a) {
-	return {$: 'ChangeSphere', a: a};
+var $author$project$Main$ChangeStat = function (a) {
+	return {$: 'ChangeStat', a: a};
 };
 var $author$project$Main$boolAsIntString = function (bool) {
 	return bool ? '1' : '0';
@@ -5740,7 +5731,7 @@ var $author$project$Main$valueOrReset = F2(
 		return _Utils_eq(dots.value, value) ? dots.min : value;
 	});
 var $author$project$Main$viewDot = F6(
-	function (sphere, size, strokeWidth, isFilled, id, position) {
+	function (stat, size, strokeWidth, isFilled, id, position) {
 		return A2(
 			$elm$svg$Svg$polygon,
 			_List_fromArray(
@@ -5781,24 +5772,24 @@ var $author$project$Main$viewDot = F6(
 					$elm$svg$Svg$Attributes$strokeWidth(
 					$elm$core$String$fromFloat(strokeWidth)),
 					$elm$html$Html$Events$onClick(
-					$author$project$Main$ChangeSphere(
+					$author$project$Main$ChangeStat(
 						_Utils_update(
-							sphere,
+							stat,
 							{
 								dots: A2(
 									$author$project$BoundedInt$changeTo,
-									sphere.dots,
-									A2($author$project$Main$valueOrReset, sphere.dots, id + 1))
+									stat.dots,
+									A2($author$project$Main$valueOrReset, stat.dots, id + 1))
 							})))
 				]),
 			_List_Nil);
 	});
 var $elm$svg$Svg$Attributes$width = _VirtualDom_attribute('width');
-var $author$project$Main$viewDots = function (sphere) {
-	var rangeList = A2($elm$core$List$range, 0, sphere.dots.max - 1);
+var $author$project$Main$viewDots = function (stat) {
+	var rangeList = A2($elm$core$List$range, 0, stat.dots.max - 1);
 	var isFilledList = A2(
 		$elm$core$List$map,
-		$elm$core$Basics$gt(sphere.dots.value),
+		$elm$core$Basics$gt(stat.dots.value),
 		rangeList);
 	var dotSize = 12;
 	var dotOutline = 0.05 * dotSize;
@@ -5811,13 +5802,13 @@ var $author$project$Main$viewDots = function (sphere) {
 		_List_fromArray(
 			[
 				$elm$svg$Svg$Attributes$width(
-				$elm$core$String$fromFloat((dotSize + (marginalIncrease * (sphere.dots.max - 1))) + (2 * svgOutlineMargin))),
+				$elm$core$String$fromFloat((dotSize + (marginalIncrease * (stat.dots.max - 1))) + (2 * svgOutlineMargin))),
 				$elm$svg$Svg$Attributes$height(
 				$elm$core$String$fromFloat((dotSize + marginalIncrease) + (2 * svgOutlineMargin)))
 			]),
 		A4(
 			$elm$core$List$map3,
-			A3($author$project$Main$viewDot, sphere, dotSize, dotOutline),
+			A3($author$project$Main$viewDot, stat, dotSize, dotOutline),
 			isFilledList,
 			rangeList,
 			A2(
@@ -5825,7 +5816,7 @@ var $author$project$Main$viewDots = function (sphere) {
 				A3($author$project$Main$toDotPosition, dotSize, dotGap, svgOutlineMargin),
 				rangeList)));
 };
-var $author$project$Main$viewSphere = function (sphere) {
+var $author$project$Main$viewStat = function (stat) {
 	return A2(
 		$elm$html$Html$div,
 		_List_Nil,
@@ -5836,29 +5827,32 @@ var $author$project$Main$viewSphere = function (sphere) {
 				_List_Nil,
 				_List_fromArray(
 					[
-						$elm$html$Html$text(sphere.name)
+						$elm$html$Html$text(stat.name)
 					])),
 				A2(
 				$elm$html$Html$span,
 				_List_Nil,
 				_List_fromArray(
 					[
-						$author$project$Main$viewDots(sphere)
+						$author$project$Main$viewDots(stat)
 					]))
 			]));
 };
-var $author$project$Main$viewSpheres = function (spheres) {
+var $author$project$Main$viewStats = function (stats) {
 	return A2(
 		$elm$html$Html$div,
 		_List_Nil,
-		A2($elm$core$List$map, $author$project$Main$viewSphere, spheres));
+		A2($elm$core$List$map, $author$project$Main$viewStat, stats));
 };
 var $author$project$Main$view = function (model) {
 	return {
 		body: _List_fromArray(
 			[
 				A2($author$project$Main$viewEditableText, $author$project$Main$Name, model.character.name),
-				$author$project$Main$viewSpheres(model.character.stats.spheres),
+				$author$project$Main$viewStats(
+				$author$project$Stats$spheresInList(model.character.stats)),
+				$author$project$Main$viewStat(
+				$author$project$Stats$areteInList(model.character.stats)),
 				$author$project$Main$viewModal(model),
 				A2(
 				$elm$html$Html$div,
diff --git a/src/Character.elm b/src/Character.elm
index 006d7c8..ff02f24 100644
--- a/src/Character.elm
+++ b/src/Character.elm
@@ -1,14 +1,12 @@
 module Character exposing (..)
 
-import Sphere exposing (Sphere)
-import BoundedInt exposing (BoundedInt)
 import Creation exposing (CreationPoints)
-import Stats exposing (Stats)
+import Stats exposing (Stat)
 
 type alias Character =
     { name : String
     , creationPoints : CreationPoints
-    , stats : Stats
+    , stats : List Stat
     }
 
 new : Character
@@ -26,24 +24,30 @@ changeName character newName =
     else
         { character | name = newName }
 
-changeSphere : Character -> Sphere -> Character
-changeSphere character sphere =
-    let
-        maybeOldDots = Sphere.getDotsOfSphereInList character.stats.spheres sphere.name
-        difference = case maybeOldDots of
-            Nothing -> 0
-            Just oldDots ->
-                if sphere.dots.value > character.stats.arete.value
-                then character.stats.arete.value - oldDots.value
-                else sphere.dots.value - oldDots.value
-    in
-        case maybeOldDots of
-            Nothing -> character
-            Just oldDots ->
-                let
-                    buyAmount = min difference character.creationPoints.spheres
-                in
-                    { character
-                    | creationPoints = Creation.buySphere character.creationPoints buyAmount
-                    , stats = Stats.changeSphere character.stats ( Sphere.changeDotsOfSphereTo sphere ( oldDots.value + buyAmount ) )
-                    }
\ No newline at end of file
+changeStat : Character -> Stat -> Character
+changeStat character stat =
+    case stat.statType of
+        Stats.Sphere ->
+            let
+                spheres = Stats.spheresInList character.stats
+                arete = Stats.areteInList character.stats
+
+                maybeOldDots = Stats.dotsOfStatInList spheres stat.name
+                difference = case maybeOldDots of
+                    Nothing -> 0
+                    Just oldDots ->
+                        if stat.dots.value > arete.dots.value
+                        then arete.dots.value - oldDots.value
+                        else stat.dots.value  - oldDots.value
+            in
+                case maybeOldDots of
+                    Nothing -> character
+                    Just oldDots ->
+                        let
+                            buyAmount = min difference character.creationPoints.spheres
+                        in
+                            { character
+                            | creationPoints = Creation.buySphere character.creationPoints buyAmount
+                            , stats = Stats.changeStatInList character.stats ( Stats.changeDotsTo stat ( oldDots.value + buyAmount ) )
+                            }
+        Stats.Arete -> character
\ No newline at end of file
diff --git a/src/Creation.elm b/src/Creation.elm
index 96288f3..242ba6a 100644
--- a/src/Creation.elm
+++ b/src/Creation.elm
@@ -1,7 +1,5 @@
 module Creation exposing (..)
 
-import Sphere exposing (Sphere)
-
 type alias CreationPoints =
     { freebie : Int
     , spheres : Int
@@ -22,4 +20,4 @@ cost =
 
 buySphere : CreationPoints -> Int -> CreationPoints
 buySphere cp value =
-    { cp | spheres = cp.spheres - value }
+    { cp | spheres = cp.spheres - value }
\ No newline at end of file
diff --git a/src/Main.elm b/src/Main.elm
index 020fbd3..e2addf7 100644
--- a/src/Main.elm
+++ b/src/Main.elm
@@ -7,7 +7,7 @@ import Html.Events exposing (..)
 import Svg exposing (svg)
 import Svg.Attributes
 import Character exposing (Character)
-import Sphere exposing (Sphere)
+import Stats exposing (Stat)
 import BoundedInt exposing (BoundedInt)
 
 main : Program () Model Msg
@@ -39,7 +39,7 @@ type Msg
     | CloseModal
     | ChangeModalValue String
     | SaveModalChange ModalType
-    | ChangeSphere Sphere
+    | ChangeStat Stat
 
 type ModalType
     = Name
@@ -71,9 +71,9 @@ update msg model =
                         }
                     , Cmd.none
                     )
-        ChangeSphere sphere ->
-            (   { model
-                | character = Character.changeSphere model.character sphere
+        ChangeStat stat ->
+            (   { model 
+                | character = Character.changeStat model.character stat 
                 }
             , Cmd.none
             )
@@ -83,7 +83,8 @@ view model =
     { title = "Character Sheet"
     , body = 
         [ viewEditableText Name model.character.name
-        , viewSpheres model.character.stats.spheres
+        , viewStats ( Stats.spheresInList model.character.stats )
+        , viewStat  ( Stats.areteInList model.character.stats )
         , viewModal model
         , div [] [ text ( "freebie: " ++ String.fromInt model.character.creationPoints.freebie ) ]
         , div [] [ text ( "spheres: " ++ String.fromInt model.character.creationPoints.spheres ) ]
@@ -106,69 +107,19 @@ viewEditableText modalType content =
             ]
         ]
 
-viewSpheres : List Sphere -> Html Msg
-viewSpheres spheres =
-    div [] ( List.map viewSphere spheres )
+viewStats : List Stat -> Html Msg
+viewStats stats =
+    div [] ( List.map viewStat stats )
 
-viewSphere : Sphere -> Html Msg
-viewSphere sphere =
+viewStat : Stat -> Html Msg
+viewStat stat =
     div []
-        [ span [] [ text sphere.name ]
-        , span [] [ viewDots sphere ]
+        [ span [] [ text stat.name ]
+        , span [] [ viewDots stat ]
         ]
 
-viewModal : Model -> Html Msg
-viewModal model =
-    case model.modal of
-        Nothing -> div [ class "modal" ] []
-        Just modalType ->
-            div [ class "modal is-active" ]
-                [ div 
-                    [ class "modal-background" 
-                    , onClick CloseModal
-                    ] []
-                , div [ class "modal-card" ] 
-                    [ header [ class "modal-card-head" ]
-                        [ p [ class "modal-card-title" ] [ text ( "Change " ++ ( modalTitle modalType ) ) ]
-                        ]
-                    , section [ class "modal-card-body" ] 
-                        [ p [] 
-                            [ input 
-                                [ class "input" 
-                                , type_ "text"
-                                , placeholder ( "Enter New " ++ ( modalTitle modalType ) )
-                                , value model.modalValue
-                                , onInput ( \x -> ChangeModalValue x )
-                                ] []
-                            ]
-                        ]
-                    , footer [ class "modal-card-foot" ] 
-                        [ div [ class "buttons" ] 
-                            [ button 
-                                [ class "button is-success"
-                                , onClick ( SaveModalChange modalType )
-                                ] [ text "Save Changes" ]
-                            , button 
-                                [ class "button"
-                                , onClick CloseModal
-                                ] [ text "Cancel" ]
-                            ]
-                        ]
-                    ]
-                ]
-
-modalTitle : ModalType -> String
-modalTitle modalType =
-    case modalType of
-        Name -> "Character Name"
-
-modalValue : ModalType -> Character -> String
-modalValue modalType character =
-    case modalType of
-        Name -> character.name
-
-viewDots : Sphere -> Html Msg
-viewDots sphere =
+viewDots : Stat -> Html Msg
+viewDots stat =
     let
         dotSize = 12
         dotGap = 4
@@ -176,17 +127,17 @@ viewDots sphere =
         marginalIncrease = ( dotSize + dotGap ) / 2
         svgOutlineMargin = ( sqrt ( 2 * ( dotOutline ^ 2 ) ) ) / 2
 
-        rangeList = List.range 0 ( sphere.dots.max - 1 )
+        rangeList = List.range 0 ( stat.dots.max - 1 )
 
-        isFilledList = rangeList |> List.map ( (>) sphere.dots.value )
+        isFilledList = rangeList |> List.map ( (>) stat.dots.value )
     in
         svg 
-            [ Svg.Attributes.width  ( String.fromFloat ( dotSize + marginalIncrease * toFloat ( sphere.dots.max - 1 ) + 2 * svgOutlineMargin ) )
+            [ Svg.Attributes.width  ( String.fromFloat ( dotSize + marginalIncrease * toFloat ( stat.dots.max - 1 ) + 2 * svgOutlineMargin ) )
             , Svg.Attributes.height ( String.fromFloat ( dotSize + marginalIncrease + 2 * svgOutlineMargin ) )
             ]
             ( rangeList
                 |> List.map ( toDotPosition dotSize dotGap svgOutlineMargin )
-                |> List.map3 ( viewDot sphere dotSize dotOutline ) isFilledList rangeList
+                |> List.map3 ( viewDot stat dotSize dotOutline ) isFilledList rangeList
             )
 
 toDotPosition : Float -> Float -> Float -> Int -> ( Float, Float )
@@ -198,8 +149,8 @@ toDotPosition size gap offset id =
         , toFloat ( remainderBy 2 ( id + 1 ) ) * marginalIncrease + offset
         )
 
-viewDot : Sphere -> Float -> Float -> Bool -> Int -> ( Float, Float ) -> Html Msg
-viewDot sphere size strokeWidth isFilled id position =
+viewDot : Stat -> Float -> Float -> Bool -> Int -> ( Float, Float ) -> Html Msg
+viewDot stat size strokeWidth isFilled id position =
     Svg.polygon 
         [ Svg.Attributes.points 
             (   [ ( 0.5, 0.0 )
@@ -218,7 +169,7 @@ viewDot sphere size strokeWidth isFilled id position =
         , Svg.Attributes.fillOpacity ( boolAsIntString isFilled )
         , Svg.Attributes.stroke "var(--bulma-body-color)"
         , Svg.Attributes.strokeWidth ( String.fromFloat strokeWidth )
-        , onClick ( ChangeSphere { sphere | dots = BoundedInt.changeTo sphere.dots ( valueOrReset sphere.dots ( id + 1 ) ) } )
+        , onClick ( ChangeStat { stat | dots = BoundedInt.changeTo stat.dots ( valueOrReset stat.dots ( id + 1 ) ) } )
         ] []
 
 tupleToString : ( Float, Float ) -> String
@@ -241,6 +192,56 @@ valueOrReset dots value =
     then dots.min
     else value
 
+viewModal : Model -> Html Msg
+viewModal model =
+    case model.modal of
+        Nothing -> div [ class "modal" ] []
+        Just modalType ->
+            div [ class "modal is-active" ]
+                [ div 
+                    [ class "modal-background" 
+                    , onClick CloseModal
+                    ] []
+                , div [ class "modal-card" ] 
+                    [ header [ class "modal-card-head" ]
+                        [ p [ class "modal-card-title" ] [ text ( "Change " ++ ( modalTitle modalType ) ) ]
+                        ]
+                    , section [ class "modal-card-body" ] 
+                        [ p [] 
+                            [ input 
+                                [ class "input" 
+                                , type_ "text"
+                                , placeholder ( "Enter New " ++ ( modalTitle modalType ) )
+                                , value model.modalValue
+                                , onInput ( \x -> ChangeModalValue x )
+                                ] []
+                            ]
+                        ]
+                    , footer [ class "modal-card-foot" ] 
+                        [ div [ class "buttons" ] 
+                            [ button 
+                                [ class "button is-success"
+                                , onClick ( SaveModalChange modalType )
+                                ] [ text "Save Changes" ]
+                            , button 
+                                [ class "button"
+                                , onClick CloseModal
+                                ] [ text "Cancel" ]
+                            ]
+                        ]
+                    ]
+                ]
+
+modalTitle : ModalType -> String
+modalTitle modalType =
+    case modalType of
+        Name -> "Character Name"
+
+modalValue : ModalType -> Character -> String
+modalValue modalType character =
+    case modalType of
+        Name -> character.name
+
 subscriptions : Model -> Sub Msg
 subscriptions _ =
   Sub.none
diff --git a/src/Sphere.elm b/src/Sphere.elm
deleted file mode 100644
index eb57757..0000000
--- a/src/Sphere.elm
+++ /dev/null
@@ -1,45 +0,0 @@
-module Sphere exposing (..)
-
-import BoundedInt exposing (BoundedInt)
-
-type alias Sphere =
-    { name : String
-    , dots : BoundedInt
-    , affinity : Bool
-    }
-
-changeSphereInList : List Sphere -> Sphere -> List Sphere
-changeSphereInList spheres sphere =
-    List.map ( changeSphere sphere ) spheres
-
-changeSphere : Sphere -> Sphere -> Sphere
-changeSphere newSphere sphere =
-    if isSphere newSphere.name sphere
-    then
-        newSphere
-    else
-        sphere
-
-changeDotsOfSphereTo : Sphere -> Int -> Sphere
-changeDotsOfSphereTo sphere value =
-    { sphere | dots = BoundedInt.changeTo sphere.dots value }
-
-isSphere : String -> Sphere -> Bool
-isSphere name sphere =
-    sphere.name == name
-
-getDotsOfSphereInList : List Sphere -> String -> Maybe BoundedInt
-getDotsOfSphereInList spheres name =
-    let
-        maybeSphere = spheres
-            |> List.filter ( isSphere name )
-            |> List.head
-    in
-        case maybeSphere of
-            Nothing -> Nothing
-            Just sphere ->
-                Just sphere.dots
-
-dots : Int -> BoundedInt
-dots value =
-    BoundedInt.new value 0 5
\ No newline at end of file
diff --git a/src/Stats.elm b/src/Stats.elm
index 992d8df..e6dafb4 100644
--- a/src/Stats.elm
+++ b/src/Stats.elm
@@ -1,56 +1,94 @@
 module Stats exposing (..)
 
-import Sphere exposing (Sphere)
 import BoundedInt exposing (BoundedInt)
 
-type alias Stats =
-    { spheres : List Sphere
-    , arete : BoundedInt
+type alias Stat =
+    { name : String
+    , dots : BoundedInt
+    , statType : StatType
     }
 
-new : Stats
+type StatType
+    = Sphere
+    | Arete
+
+new : List Stat
 new =
-    { spheres = 
-        [   { name = "Correspondence"
-            , dots = Sphere.dots 0
-            , affinity = False
-            }
-        ,   { name = "Entropy"
-            , dots = Sphere.dots 0
-            , affinity = False
-            }
-        ,   { name = "Forces"
-            , dots = Sphere.dots 0
-            , affinity = False
-            }
-        ,   { name = "Life"
-            , dots = Sphere.dots 0
-            , affinity = False
-            }
-        ,   { name = "Matter"
-            , dots = Sphere.dots 0
-            , affinity = False
-            }
-        ,   { name = "Mind"
-            , dots = Sphere.dots 0
-            , affinity = False
-            }
-        ,   { name = "Prime"
-            , dots = Sphere.dots 0
-            , affinity = False
-            }
-        ,   { name = "Spirit"
-            , dots = Sphere.dots 0
-            , affinity = False
-            }
-        ,   { name = "Time"
-            , dots = Sphere.dots 0
-            , affinity = False
-            }
-        ]
-    , arete = BoundedInt.new 1 0 10
+    [ newSphere "Correspondence"
+    , newSphere "Entropy"
+    , newSphere "Forces"
+    , newSphere "Life"
+    , newSphere "Matter"
+    , newSphere "Mind"
+    , newSphere "Prime"
+    , newSphere "Spirit"
+    , newSphere "Time"
+    , newArete
+    ]
+
+newSphere : String -> Stat
+newSphere name =
+    { name = name
+    , dots = BoundedInt.new 0 0 5
+    , statType = Sphere
+    }
+
+newArete : Stat
+newArete =
+    { name = "Arete"
+    , dots = BoundedInt.new 1 0 10
+    , statType = Arete
     }
 
-changeSphere : Stats -> Sphere -> Stats
-changeSphere stats sphere =
-    { stats | spheres = Sphere.changeSphereInList stats.spheres sphere }
\ No newline at end of file
+spheresInList : List Stat -> List Stat
+spheresInList stats =
+    List.filter isSphere stats
+
+isSphere : Stat -> Bool
+isSphere stat =
+    stat.statType == Sphere
+
+areteInList : List Stat -> Stat
+areteInList stats =
+    let 
+        maybeArete = List.head ( List.filter isArete stats )
+    in
+        case maybeArete of
+            Just arete -> arete
+            Nothing -> newArete
+
+isArete : Stat -> Bool
+isArete stat =
+    stat.statType == Arete
+
+dotsOfStatInList : List Stat -> String -> Maybe BoundedInt
+dotsOfStatInList stats name =
+    let
+        maybeStat = stats
+            |> List.filter ( isStat name )
+            |> List.head
+    in
+        case maybeStat of
+            Nothing -> Nothing
+            Just stat ->
+                Just stat.dots
+
+isStat : String -> Stat -> Bool
+isStat name stat =
+    stat.name == name
+
+changeStatInList : List Stat -> Stat -> List Stat
+changeStatInList stats stat =
+    List.map ( changeStatIfSame stat ) stats
+
+changeStatIfSame : Stat -> Stat -> Stat
+changeStatIfSame newStat oldStat =
+    if isStat newStat.name oldStat
+    then
+        newStat
+    else
+        oldStat
+
+changeDotsTo : Stat -> Int -> Stat
+changeDotsTo stat value =
+    { stat | dots = BoundedInt.changeTo stat.dots value }
\ No newline at end of file
-- 
GitLab