summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsyuilo <syuilotan@yahoo.co.jp>2018-03-11 07:07:17 +0900
committersyuilo <syuilotan@yahoo.co.jp>2018-03-11 07:07:22 +0900
commit98f09ad16c8dbdfedfb1a517203f84e584fb0bee (patch)
treeba136e84adb52a83ea6d5786d0f2e4232799d7a9
parentMerge pull request #1233 from syuilo/othello-lack-of-black-map (diff)
downloadsharkey-98f09ad16c8dbdfedfb1a517203f84e584fb0bee.tar.gz
sharkey-98f09ad16c8dbdfedfb1a517203f84e584fb0bee.tar.bz2
sharkey-98f09ad16c8dbdfedfb1a517203f84e584fb0bee.zip
:v:
-rw-r--r--src/api/models/othello-game.ts2
-rw-r--r--src/api/stream/othello-game.ts76
-rw-r--r--src/web/app/common/views/components/othello.room.vue230
3 files changed, 253 insertions, 55 deletions
diff --git a/src/api/models/othello-game.ts b/src/api/models/othello-game.ts
index a8c3025108..ab90cffa44 100644
--- a/src/api/models/othello-game.ts
+++ b/src/api/models/othello-game.ts
@@ -33,6 +33,8 @@ export interface IGame {
can_put_everywhere: boolean;
looped_board: boolean;
};
+ form1: any;
+ form2: any;
}
/**
diff --git a/src/api/stream/othello-game.ts b/src/api/stream/othello-game.ts
index 5f61f0cc2c..888c599338 100644
--- a/src/api/stream/othello-game.ts
+++ b/src/api/stream/othello-game.ts
@@ -31,6 +31,21 @@ export default function(request: websocket.request, connection: websocket.connec
updateSettings(msg.settings);
break;
+ case 'init-form':
+ if (msg.body == null) return;
+ initForm(msg.body);
+ break;
+
+ case 'update-form':
+ if (msg.id == null || msg.value === undefined) return;
+ updateForm(msg.id, msg.value);
+ break;
+
+ case 'message':
+ if (msg.body == null) return;
+ message(msg.body);
+ break;
+
case 'set':
if (msg.pos == null) return;
set(msg.pos);
@@ -55,6 +70,67 @@ export default function(request: websocket.request, connection: websocket.connec
publishOthelloGameStream(gameId, 'update-settings', settings);
}
+ async function initForm(form) {
+ const game = await Game.findOne({ _id: gameId });
+
+ if (game.is_started) return;
+ if (!game.user1_id.equals(user._id) && !game.user2_id.equals(user._id)) return;
+
+ const set = game.user1_id.equals(user._id) ? {
+ form1: form
+ } : {
+ form2: form
+ };
+
+ await Game.update({ _id: gameId }, {
+ $set: set
+ });
+
+ publishOthelloGameStream(gameId, 'init-form', {
+ user_id: user._id,
+ form
+ });
+ }
+
+ async function updateForm(id, value) {
+ const game = await Game.findOne({ _id: gameId });
+
+ if (game.is_started) return;
+ if (!game.user1_id.equals(user._id) && !game.user2_id.equals(user._id)) return;
+
+ const form = game.user1_id.equals(user._id) ? game.form2 : game.form1;
+
+ const item = form.find(i => i.id == id);
+
+ if (item == null) return;
+
+ item.value = value;
+
+ const set = game.user1_id.equals(user._id) ? {
+ form2: form
+ } : {
+ form1: form
+ };
+
+ await Game.update({ _id: gameId }, {
+ $set: set
+ });
+
+ publishOthelloGameStream(gameId, 'update-form', {
+ user_id: user._id,
+ id,
+ value
+ });
+ }
+
+ async function message(message) {
+ message.id = Math.random();
+ publishOthelloGameStream(gameId, 'message', {
+ user_id: user._id,
+ message
+ });
+ }
+
async function accept(accept: boolean) {
const game = await Game.findOne({ _id: gameId });
diff --git a/src/web/app/common/views/components/othello.room.vue b/src/web/app/common/views/components/othello.room.vue
index dfdc43ef96..bdefcdc49f 100644
--- a/src/web/app/common/views/components/othello.room.vue
+++ b/src/web/app/common/views/components/othello.room.vue
@@ -2,37 +2,77 @@
<div class="root">
<header><b>{{ game.user1.name }}</b> vs <b>{{ game.user2.name }}</b></header>
- <p>ゲームの設定</p>
+ <div>
+ <p>ゲームの設定</p>
- <el-select class="map" v-model="mapName" placeholder="マップを選択" @change="onMapChange">
- <el-option label="ランダム" :value="null"/>
- <el-option-group v-for="c in mapCategories" :key="c" :label="c">
- <el-option v-for="m in maps" v-if="m.category == c" :key="m.name" :label="m.name" :value="m.name">
- <span style="float: left">{{ m.name }}</span>
- <span style="float: right; color: #8492a6; font-size: 13px" v-if="m.author">(by <i>{{ m.author }}</i>)</span>
- </el-option>
- </el-option-group>
- </el-select>
+ <el-card class="map">
+ <div slot="header">
+ <el-select :class="$style.mapSelect" v-model="mapName" placeholder="マップを選択" @change="onMapChange">
+ <el-option label="ランダム" :value="null"/>
+ <el-option-group v-for="c in mapCategories" :key="c" :label="c">
+ <el-option v-for="m in maps" v-if="m.category == c" :key="m.name" :label="m.name" :value="m.name">
+ <span style="float: left">{{ m.name }}</span>
+ <span style="float: right; color: #8492a6; font-size: 13px" v-if="m.author">(by <i>{{ m.author }}</i>)</span>
+ </el-option>
+ </el-option-group>
+ </el-select>
+ </div>
+ <div :class="$style.board" v-if="game.settings.map != null" :style="{ 'grid-template-rows': `repeat(${ game.settings.map.length }, 1fr)`, 'grid-template-columns': `repeat(${ game.settings.map[0].length }, 1fr)` }">
+ <div v-for="(x, i) in game.settings.map.join('')"
+ :class="{ none: x == ' ' }"
+ @click="onPixelClick(i, x)"
+ >
+ <template v-if="x == 'b'">%fa:circle%</template>
+ <template v-if="x == 'w'">%fa:circle R%</template>
+ </div>
+ </div>
+ </el-card>
- <div class="board" v-if="game.settings.map != null" :style="{ 'grid-template-rows': `repeat(${ game.settings.map.length }, 1fr)`, 'grid-template-columns': `repeat(${ game.settings.map[0].length }, 1fr)` }">
- <div v-for="(x, i) in game.settings.map.join('')"
- :class="{ none: x == ' ' }"
- @click="onPixelClick(i, x)"
- >
- <template v-if="x == 'b'">%fa:circle%</template>
- <template v-if="x == 'w'">%fa:circle R%</template>
- </div>
- </div>
-
- <div class="rules">
- <mk-switch v-model="game.settings.is_llotheo" @change="updateSettings" text="石の少ない方が勝ち(ロセオ)"/>
- <mk-switch v-model="game.settings.looped_board" @change="updateSettings" text="ループマップ"/>
- <mk-switch v-model="game.settings.can_put_everywhere" @change="updateSettings" text="どこでも置けるモード"/>
- <div>
+ <el-card class="bw">
+ <div slot="header">
+ <span>先手/後手</span>
+ </div>
<el-radio v-model="game.settings.bw" label="random" @change="updateSettings">ランダム</el-radio>
<el-radio v-model="game.settings.bw" :label="1" @change="updateSettings">{{ game.user1.name }}が黒</el-radio>
<el-radio v-model="game.settings.bw" :label="2" @change="updateSettings">{{ game.user2.name }}が黒</el-radio>
- </div>
+ </el-card>
+
+ <el-card class="rules">
+ <div slot="header">
+ <span>ルール</span>
+ </div>
+ <mk-switch v-model="game.settings.is_llotheo" @change="updateSettings" text="石の少ない方が勝ち(ロセオ)"/>
+ <mk-switch v-model="game.settings.looped_board" @change="updateSettings" text="ループマップ"/>
+ <mk-switch v-model="game.settings.can_put_everywhere" @change="updateSettings" text="どこでも置けるモード"/>
+ </el-card>
+
+ <el-card class="bot-form" v-if="form">
+ <div slot="header">
+ <span>Botの設定</span>
+ </div>
+ <el-alert v-for="message in messages"
+ :title="message.text"
+ :type="message.type"
+ :key="message.id"
+ />
+ <template v-for="item in form">
+ <mk-switch v-if="item.type == 'button'" v-model="item.value" :key="item.id" :text="item.label" @change="onChangeForm($event, item)">{{ item.desc || '' }}</mk-switch>
+
+ <el-card v-if="item.type == 'radio'" :key="item.id">
+ <div slot="header">
+ <span>{{ item.label }}</span>
+ </div>
+ <el-radio v-for="(r, i) in item.items" :key="item.id + ':' + i" v-model="item.value" :label="r.value" @change="onChangeForm($event, item)">{{ r.label }}</el-radio>
+ </el-card>
+
+ <el-card v-if="item.type == 'textbox'" :key="item.id">
+ <div slot="header">
+ <span>{{ item.label }}</span>
+ </div>
+ <el-input v-model="item.value" @change="onChangeForm($event, item)"/>
+ </el-card>
+ </template>
+ </el-card>
</div>
<footer>
@@ -64,7 +104,9 @@ export default Vue.extend({
o: null,
isLlotheo: false,
mapName: maps.eighteight.name,
- maps: maps
+ maps: maps,
+ form: null,
+ messages: []
};
},
@@ -88,11 +130,56 @@ export default Vue.extend({
created() {
this.connection.on('change-accepts', this.onChangeAccepts);
this.connection.on('update-settings', this.onUpdateSettings);
+ this.connection.on('init-form', this.onInitForm);
+ this.connection.on('message', this.onMessage);
+
+ if (this.game.user1_id != (this as any).os.i.id && this.game.settings.form1) this.form = this.game.settings.form1;
+ if (this.game.user2_id != (this as any).os.i.id && this.game.settings.form2) this.form = this.game.settings.form2;
+
+ // for debugging
+ if ((this as any).os.i.username == 'test1') {
+ setTimeout(() => {
+ this.connection.send({
+ type: 'init-form',
+ body: [{
+ id: 'button1',
+ type: 'button',
+ label: 'Enable hoge',
+ value: false
+ }, {
+ id: 'radio1',
+ type: 'radio',
+ label: '強さ',
+ value: 2,
+ items: [{
+ label: '弱',
+ value: 1
+ }, {
+ label: '中',
+ value: 2
+ }, {
+ label: '強',
+ value: 3
+ }]
+ }]
+ });
+
+ this.connection.send({
+ type: 'message',
+ body: {
+ text: 'Hey',
+ type: 'info'
+ }
+ });
+ }, 2000);
+ }
},
beforeDestroy() {
this.connection.off('change-accepts', this.onChangeAccepts);
this.connection.off('update-settings', this.onUpdateSettings);
+ this.connection.off('init-form', this.onInitForm);
+ this.connection.off('message', this.onMessage);
},
methods: {
@@ -135,6 +222,24 @@ export default Vue.extend({
}
},
+ onInitForm(x) {
+ if (x.user_id == (this as any).os.i.id) return;
+ this.form = x.form;
+ },
+
+ onMessage(x) {
+ if (x.user_id == (this as any).os.i.id) return;
+ this.messages.unshift(x.message);
+ },
+
+ onChangeForm(v, item) {
+ this.connection.send({
+ type: 'update-form',
+ id: item.id,
+ value: v
+ });
+ },
+
onMapChange(v) {
if (v == null) {
this.game.settings.map = null;
@@ -168,40 +273,21 @@ export default Vue.extend({
.root
text-align center
+ background #f9f9f9
> header
padding 8px
border-bottom dashed 1px #c4cdd4
- > .map
- width 300px
-
- > .board
- display grid
- grid-gap 4px
- width 300px
- height 300px
- margin 16px auto
+ > div
+ padding 0 16px
- > div
- background transparent
- border solid 2px #ddd
- border-radius 6px
- overflow hidden
- cursor pointer
-
- *
- pointer-events none
- user-select none
- width 100%
- height 100%
-
- &.none
- border-color transparent
-
- > .rules
- max-width 300px
- margin 0 auto 32px auto
+ > .map
+ > .bw
+ > .rules
+ > .bot-form
+ max-width 400px
+ margin 0 auto 16px auto
> footer
position sticky
@@ -213,3 +299,37 @@ export default Vue.extend({
> .status
margin 0 0 16px 0
</style>
+
+<style lang="stylus" module>
+.mapSelect
+ width 100%
+
+.board
+ display grid
+ grid-gap 4px
+ width 300px
+ height 300px
+ margin 0 auto
+
+ > div
+ background transparent
+ border solid 2px #ddd
+ border-radius 6px
+ overflow hidden
+ cursor pointer
+
+ *
+ pointer-events none
+ user-select none
+ width 100%
+ height 100%
+
+ &.none
+ border-color transparent
+
+</style>
+
+<style lang="stylus">
+.el-alert__content
+ position initial !important
+</style>