From 1a23cf07ccc1e7959ca7ebae6206d6ec1ed260d9 Mon Sep 17 00:00:00 2001
From: Louis Capitanchik <contact@louiscap.co>
Date: Sat, 13 Jul 2019 15:34:50 +0100
Subject: [PATCH] Add win logic and flags

---
 public/flag-text.png     |   3 +
 public/flag.png          |   3 +
 public/win-text.png      |   3 +
 src/App.js               |  15 +-
 src/data/testlevel2.json | 325 +++++++++++++++++++++++++++++++++++++++
 src/game/Entity.js       |   5 +
 src/game/Level.js        |   4 +
 src/render/Level.js      |  10 +-
 8 files changed, 361 insertions(+), 7 deletions(-)
 create mode 100644 public/flag-text.png
 create mode 100644 public/flag.png
 create mode 100644 public/win-text.png
 create mode 100644 src/data/testlevel2.json

diff --git a/public/flag-text.png b/public/flag-text.png
new file mode 100644
index 0000000..e6a8b1d
--- /dev/null
+++ b/public/flag-text.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8fc4de7822af18989aa12814d6986f84c3e4f7bf700e9ade5019ef2d22bfdefb
+size 1338
diff --git a/public/flag.png b/public/flag.png
new file mode 100644
index 0000000..2aeef25
--- /dev/null
+++ b/public/flag.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ba08aa3e9b53669b0be73ddbbe1d046c7f90f8871639474416d60a8645894163
+size 1993
diff --git a/public/win-text.png b/public/win-text.png
new file mode 100644
index 0000000..29e8575
--- /dev/null
+++ b/public/win-text.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6af1528d2aba3c774c519a8c3f74e153aaa316f9f2a3d3d58bb41b0217704ebe
+size 977
diff --git a/src/App.js b/src/App.js
index db68c93..c104d6e 100644
--- a/src/App.js
+++ b/src/App.js
@@ -2,7 +2,7 @@ import React, {Component} from 'react'
 import './App.css';
 import Level from './render/Level'
 import LevelData from './game/Level'
-import testLevel from './data/testlevel1'
+import testLevel from './data/testlevel2'
 
 import Editor from './editor/Editor'
 
@@ -14,6 +14,7 @@ class App extends Component<{}> {
         rawLevelData: null,
         levelData: null,
         screen: 'game',
+        isWin: false,
     }
 
     componentDidMount() {
@@ -23,7 +24,7 @@ class App extends Component<{}> {
     async loadLevelData(data = this.state.rawLevelData) {
         const levelData = await LevelData.from(data)
         await levelData.tick()
-        this.setState({ levelData, rawLevelData: data })
+        this.setState({ isWin: false, levelData, rawLevelData: data })
     }
 
     render() {
@@ -51,10 +52,12 @@ class App extends Component<{}> {
                         (() => {
                             switch (this.state.screen) {
                                 case 'game':
-                                    if (levelData == null) {
+                                    if (this.state.isWin) {
+                                        return <h2>A winner is you</h2>
+                                    } else if (levelData == null) {
                                         return <span>LOADING</span>
                                     } else {
-                                        return <Level level={levelData} {...opts} />
+                                        return <Level level={levelData} {...opts} onWin={this._win}/>
                                     }
                                 case 'editor': {
                                     return this.state.rawLevelData && (
@@ -76,6 +79,10 @@ class App extends Component<{}> {
         );
     }
 
+    _win = () => {
+        this.setState({ isWin: true })
+    }
+
     set = (name, value = null) => e => {
         const targetValue = e.currentTarget.value
         this.setState(s => ({ [name]: value && value.call ? value(s) : value || targetValue }))
diff --git a/src/data/testlevel2.json b/src/data/testlevel2.json
new file mode 100644
index 0000000..02301cb
--- /dev/null
+++ b/src/data/testlevel2.json
@@ -0,0 +1,325 @@
+{
+  "name": "Ba Ba Test Sheep",
+  "width": 10,
+  "height": 10,
+  "connectors": [
+    {
+      "type": "is",
+      "x": 2,
+      "y": 5
+    },
+    {
+      "type": "is",
+      "x": 2,
+      "y": 2
+    },
+    {
+      "type": "is",
+      "x": 7,
+      "y": 7
+    }
+  ],
+  "nouns": [
+    {
+      "name": "charles",
+      "images": {
+        "text": "/charles-text.png",
+        "entity": "/charles.png"
+      },
+      "text_start_locations": [
+        {
+          "x": 1,
+          "y": 5
+        }
+      ],
+      "entity_start_locations": [
+        {
+          "x": 5,
+          "y": 5
+        }
+      ]
+    },    {
+      "name": "flag",
+      "images": {
+        "text": "/flag-text.png",
+        "entity": "/flag.png"
+      },
+      "text_start_locations": [
+        {
+          "x": 7,
+          "y": 6
+        }
+      ],
+      "entity_start_locations": [
+        {
+          "x": 8,
+          "y": 3
+        }
+      ]
+    },
+    {
+      "name": "wall",
+      "images": {
+        "text": "/wall-text.png",
+        "entity": "/wall.png"
+      },
+      "text_start_locations": [
+        {
+          "x": 1,
+          "y": 2
+        }
+      ],
+      "entity_start_locations": [
+        {
+          "x": 0,
+          "y": 0
+        },
+        {
+          "x": 1,
+          "y": 0
+        },
+        {
+          "x": 2,
+          "y": 0
+        },
+        {
+          "x": 3,
+          "y": 0
+        },
+        {
+          "x": 4,
+          "y": 0
+        },
+        {
+          "x": 5,
+          "y": 0
+        },
+        {
+          "x": 6,
+          "y": 0
+        },
+        {
+          "x": 7,
+          "y": 0
+        },
+        {
+          "x": 8,
+          "y": 0
+        },
+        {
+          "x": 9,
+          "y": 0
+        },
+        {
+          "x": 0,
+          "y": 2
+        },
+        {
+          "x": 0,
+          "y": 1
+        },
+        {
+          "x": 0,
+          "y": 3
+        },
+        {
+          "x": 0,
+          "y": 4
+        },
+        {
+          "x": 0,
+          "y": 5
+        },
+        {
+          "x": 0,
+          "y": 6
+        },
+        {
+          "x": 0,
+          "y": 7
+        },
+        {
+          "x": 0,
+          "y": 8
+        },
+        {
+          "x": 0,
+          "y": 9
+        },
+        {
+          "x": 1,
+          "y": 9
+        },
+        {
+          "x": 2,
+          "y": 9
+        },
+        {
+          "x": 3,
+          "y": 9
+        },
+        {
+          "x": 4,
+          "y": 9
+        },
+        {
+          "x": 6,
+          "y": 9
+        },
+        {
+          "x": 7,
+          "y": 9
+        },
+        {
+          "x": 8,
+          "y": 9
+        },
+        {
+          "x": 9,
+          "y": 9
+        },
+        {
+          "x": 5,
+          "y": 9
+        },
+        {
+          "x": 9,
+          "y": 3
+        },
+        {
+          "x": 9,
+          "y": 1
+        },
+        {
+          "x": 9,
+          "y": 2
+        },
+        {
+          "x": 9,
+          "y": 4
+        },
+        {
+          "x": 9,
+          "y": 5
+        },
+        {
+          "x": 9,
+          "y": 6
+        },
+        {
+          "x": 9,
+          "y": 7
+        },
+        {
+          "x": 9,
+          "y": 8
+        },
+        {
+          "x": 6,
+          "y": 1
+        },
+        {
+          "x": 6,
+          "y": 2
+        },
+        {
+          "x": 6,
+          "y": 3
+        },
+        {
+          "x": 6,
+          "y": 5
+        },
+        {
+          "x": 6,
+          "y": 6
+        },
+        {
+          "x": 6,
+          "y": 4
+        },
+        {
+          "x": 6,
+          "y": 7
+        },
+        {
+          "x": 6,
+          "y": 8
+        }
+      ]
+    }
+  ],
+  "adjectives": [
+    {
+      "name": "you",
+      "source": {
+        "type": "internal",
+        "data": "adjectives/you"
+      },
+      "images": {
+        "text": "/you-text.png"
+      },
+      "text_start_locations": [
+        {
+          "x": 3,
+          "y": 5
+        }
+      ]
+    },
+    {
+      "name": "push",
+      "source": {
+        "type": "internal",
+        "data": "adjectives/push"
+      },
+      "images": {
+        "text": "/push-text.png"
+      },
+      "text_start_locations": [
+        {
+          "x": 3,
+          "y": 7
+        }
+      ]
+    },
+    {
+      "name": "stop",
+      "source": {
+        "type": "inline",
+        "data": {
+          "id": "stop",
+          "interactions": {
+          }
+        }
+      },
+      "images": {
+        "text": "/stop-text.png"
+      },
+      "text_start_locations": [
+        {
+          "x": 3,
+          "y": 2
+        }
+      ]
+    },
+    {
+      "name": "win",
+      "source": {
+        "type": "inline",
+        "data": {
+          "id": "win",
+          "interactions": {}
+        }
+      },
+      "images": {
+        "text": "/win-text.png"
+      },
+      "text_start_locations": [
+        {
+          "x": 7,
+          "y": 8
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/src/game/Entity.js b/src/game/Entity.js
index 0b754d0..c3d703e 100644
--- a/src/game/Entity.js
+++ b/src/game/Entity.js
@@ -1,6 +1,7 @@
 // @flow
 
 import typeof Noun from './Noun'
+import Adjective from "./Adjective";
 
 export default class Entity {
     x: number
@@ -33,4 +34,8 @@ export default class Entity {
         return this.noun.interact(other.noun, this.position, other.position)
     }
 
+    is(adjective: Adjective | string) {
+        return this.noun.adjectives.has(adjective) || Array.from(this.noun.adjectives).some(a => a.id === adjective)
+    }
+
 }
\ No newline at end of file
diff --git a/src/game/Level.js b/src/game/Level.js
index ee4d4a5..fc7d38b 100644
--- a/src/game/Level.js
+++ b/src/game/Level.js
@@ -256,5 +256,9 @@ export default class Level {
                 noun.set(adjectives.filter(Boolean))
             }
         }
+
+        return this.findEntitiesThat('win').some(target => {
+            return this.findEntitiesAt(target.x, target.y, e => e !== target).some(other => other.is('you'))
+        })
     }
 }
\ No newline at end of file
diff --git a/src/render/Level.js b/src/render/Level.js
index dd66268..015f6f3 100644
--- a/src/render/Level.js
+++ b/src/render/Level.js
@@ -50,7 +50,7 @@ export default class Level extends React.Component<Props> {
 
     handleKeyPress = async e => {
         e.preventDefault()
-        if (this.state.active > 0) {
+        if (this.state.isWin || this.state.active > 0) {
             return
         }
         const { key } = e
@@ -79,14 +79,18 @@ export default class Level extends React.Component<Props> {
 
         if (input) {
             this.setState(s => ({ active: s.active + 1 }))
-            await this.props.level.processInput(input)
-            this.setState(s => ({ nonce: Math.random(), active: s.active - 1 }))
+            const isWin = await this.props.level.processInput(input)
+            if (isWin && !this.state.isWin) {
+                this.props.onWin()
+            }
+            this.setState(s => ({ nonce: Math.random(), active: s.active - 1, isWin }))
         }
     }
 
     render() {
         const {scale, size, margin, level} = this.props
         const {width, height} = level
+
         return (
             <div className="level-container">
                 {[...range(width)].map(x =>
-- 
GitLab