✌️
This commit is contained in:
		
							parent
							
								
									f838b482bf
								
							
						
					
					
						commit
						98f09ad16c
					
				
					 3 changed files with 253 additions and 55 deletions
				
			
		| 
						 | 
					@ -33,6 +33,8 @@ export interface IGame {
 | 
				
			||||||
		can_put_everywhere: boolean;
 | 
							can_put_everywhere: boolean;
 | 
				
			||||||
		looped_board: boolean;
 | 
							looped_board: boolean;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
						form1: any;
 | 
				
			||||||
 | 
						form2: any;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,6 +31,21 @@ export default function(request: websocket.request, connection: websocket.connec
 | 
				
			||||||
				updateSettings(msg.settings);
 | 
									updateSettings(msg.settings);
 | 
				
			||||||
				break;
 | 
									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':
 | 
								case 'set':
 | 
				
			||||||
				if (msg.pos == null) return;
 | 
									if (msg.pos == null) return;
 | 
				
			||||||
				set(msg.pos);
 | 
									set(msg.pos);
 | 
				
			||||||
| 
						 | 
					@ -55,6 +70,67 @@ export default function(request: websocket.request, connection: websocket.connec
 | 
				
			||||||
		publishOthelloGameStream(gameId, 'update-settings', settings);
 | 
							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) {
 | 
						async function accept(accept: boolean) {
 | 
				
			||||||
		const game = await Game.findOne({ _id: gameId });
 | 
							const game = await Game.findOne({ _id: gameId });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,9 +2,12 @@
 | 
				
			||||||
<div class="root">
 | 
					<div class="root">
 | 
				
			||||||
	<header><b>{{ game.user1.name }}</b> vs <b>{{ game.user2.name }}</b></header>
 | 
						<header><b>{{ game.user1.name }}</b> vs <b>{{ game.user2.name }}</b></header>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<div>
 | 
				
			||||||
		<p>ゲームの設定</p>
 | 
							<p>ゲームの設定</p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	<el-select class="map" v-model="mapName" placeholder="マップを選択" @change="onMapChange">
 | 
							<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 label="ランダム" :value="null"/>
 | 
				
			||||||
					<el-option-group v-for="c in mapCategories" :key="c" :label="c">
 | 
										<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">
 | 
											<el-option v-for="m in maps" v-if="m.category == c" :key="m.name" :label="m.name" :value="m.name">
 | 
				
			||||||
| 
						 | 
					@ -13,8 +16,8 @@
 | 
				
			||||||
						</el-option>
 | 
											</el-option>
 | 
				
			||||||
					</el-option-group>
 | 
										</el-option-group>
 | 
				
			||||||
				</el-select>
 | 
									</el-select>
 | 
				
			||||||
 | 
								</div>
 | 
				
			||||||
	<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 :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('')"
 | 
									<div v-for="(x, i) in game.settings.map.join('')"
 | 
				
			||||||
					:class="{ none: x == ' ' }"
 | 
										:class="{ none: x == ' ' }"
 | 
				
			||||||
					@click="onPixelClick(i, x)"
 | 
										@click="onPixelClick(i, x)"
 | 
				
			||||||
| 
						 | 
					@ -23,16 +26,53 @@
 | 
				
			||||||
					<template v-if="x == 'w'">%fa:circle R%</template>
 | 
										<template v-if="x == 'w'">%fa:circle R%</template>
 | 
				
			||||||
				</div>
 | 
									</div>
 | 
				
			||||||
			</div>
 | 
								</div>
 | 
				
			||||||
 | 
							</el-card>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	<div class="rules">
 | 
							<el-card class="bw">
 | 
				
			||||||
		<mk-switch v-model="game.settings.is_llotheo" @change="updateSettings" text="石の少ない方が勝ち(ロセオ)"/>
 | 
								<div slot="header">
 | 
				
			||||||
		<mk-switch v-model="game.settings.looped_board" @change="updateSettings" text="ループマップ"/>
 | 
									<span>先手/後手</span>
 | 
				
			||||||
		<mk-switch v-model="game.settings.can_put_everywhere" @change="updateSettings" text="どこでも置けるモード"/>
 | 
								</div>
 | 
				
			||||||
		<div>
 | 
					 | 
				
			||||||
			<el-radio v-model="game.settings.bw" label="random" @change="updateSettings">ランダム</el-radio>
 | 
								<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="1" @change="updateSettings">{{ game.user1.name }}が黒</el-radio>
 | 
				
			||||||
			<el-radio v-model="game.settings.bw" :label="2" @change="updateSettings">{{ game.user2.name }}が黒</el-radio>
 | 
								<el-radio v-model="game.settings.bw" :label="2" @change="updateSettings">{{ game.user2.name }}が黒</el-radio>
 | 
				
			||||||
 | 
							</el-card>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							<el-card class="rules">
 | 
				
			||||||
 | 
								<div slot="header">
 | 
				
			||||||
 | 
									<span>ルール</span>
 | 
				
			||||||
			</div>
 | 
								</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>
 | 
						</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	<footer>
 | 
						<footer>
 | 
				
			||||||
| 
						 | 
					@ -64,7 +104,9 @@ export default Vue.extend({
 | 
				
			||||||
			o: null,
 | 
								o: null,
 | 
				
			||||||
			isLlotheo: false,
 | 
								isLlotheo: false,
 | 
				
			||||||
			mapName: maps.eighteight.name,
 | 
								mapName: maps.eighteight.name,
 | 
				
			||||||
			maps: maps
 | 
								maps: maps,
 | 
				
			||||||
 | 
								form: null,
 | 
				
			||||||
 | 
								messages: []
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -88,11 +130,56 @@ export default Vue.extend({
 | 
				
			||||||
	created() {
 | 
						created() {
 | 
				
			||||||
		this.connection.on('change-accepts', this.onChangeAccepts);
 | 
							this.connection.on('change-accepts', this.onChangeAccepts);
 | 
				
			||||||
		this.connection.on('update-settings', this.onUpdateSettings);
 | 
							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() {
 | 
						beforeDestroy() {
 | 
				
			||||||
		this.connection.off('change-accepts', this.onChangeAccepts);
 | 
							this.connection.off('change-accepts', this.onChangeAccepts);
 | 
				
			||||||
		this.connection.off('update-settings', this.onUpdateSettings);
 | 
							this.connection.off('update-settings', this.onUpdateSettings);
 | 
				
			||||||
 | 
							this.connection.off('init-form', this.onInitForm);
 | 
				
			||||||
 | 
							this.connection.off('message', this.onMessage);
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	methods: {
 | 
						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) {
 | 
							onMapChange(v) {
 | 
				
			||||||
			if (v == null) {
 | 
								if (v == null) {
 | 
				
			||||||
				this.game.settings.map = null;
 | 
									this.game.settings.map = null;
 | 
				
			||||||
| 
						 | 
					@ -168,20 +273,43 @@ export default Vue.extend({
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.root
 | 
					.root
 | 
				
			||||||
	text-align center
 | 
						text-align center
 | 
				
			||||||
 | 
						background #f9f9f9
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	> header
 | 
						> header
 | 
				
			||||||
		padding 8px
 | 
							padding 8px
 | 
				
			||||||
		border-bottom dashed 1px #c4cdd4
 | 
							border-bottom dashed 1px #c4cdd4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	> .map
 | 
						> div
 | 
				
			||||||
		width 300px
 | 
							padding 0 16px
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	> .board
 | 
							> .map
 | 
				
			||||||
 | 
							> .bw
 | 
				
			||||||
 | 
							> .rules
 | 
				
			||||||
 | 
							> .bot-form
 | 
				
			||||||
 | 
								max-width 400px
 | 
				
			||||||
 | 
								margin 0 auto 16px auto
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						> footer
 | 
				
			||||||
 | 
							position sticky
 | 
				
			||||||
 | 
							bottom 0
 | 
				
			||||||
 | 
							padding 16px
 | 
				
			||||||
 | 
							background rgba(255, 255, 255, 0.9)
 | 
				
			||||||
 | 
							border-top solid 1px #c4cdd4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							> .status
 | 
				
			||||||
 | 
								margin 0 0 16px 0
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style lang="stylus" module>
 | 
				
			||||||
 | 
					.mapSelect
 | 
				
			||||||
 | 
						width 100%
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.board
 | 
				
			||||||
	display grid
 | 
						display grid
 | 
				
			||||||
	grid-gap 4px
 | 
						grid-gap 4px
 | 
				
			||||||
	width 300px
 | 
						width 300px
 | 
				
			||||||
	height 300px
 | 
						height 300px
 | 
				
			||||||
		margin 16px auto
 | 
						margin 0 auto
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	> div
 | 
						> div
 | 
				
			||||||
		background transparent
 | 
							background transparent
 | 
				
			||||||
| 
						 | 
					@ -199,17 +327,9 @@ export default Vue.extend({
 | 
				
			||||||
		&.none
 | 
							&.none
 | 
				
			||||||
			border-color transparent
 | 
								border-color transparent
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	> .rules
 | 
					</style>
 | 
				
			||||||
		max-width 300px
 | 
					
 | 
				
			||||||
		margin 0 auto 32px auto
 | 
					<style lang="stylus">
 | 
				
			||||||
 | 
					.el-alert__content
 | 
				
			||||||
	> footer
 | 
						position initial !important
 | 
				
			||||||
		position sticky
 | 
					 | 
				
			||||||
		bottom 0
 | 
					 | 
				
			||||||
		padding 16px
 | 
					 | 
				
			||||||
		background rgba(255, 255, 255, 0.9)
 | 
					 | 
				
			||||||
		border-top solid 1px #c4cdd4
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		> .status
 | 
					 | 
				
			||||||
			margin 0 0 16px 0
 | 
					 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue