OSDN Git Service

push github
[wolvez/wolvez.git] / trunk / lib / ms / village.rb
1 class Vil
2         MesRegex = /^<div class="message"><div class="([a-z]+)(\d+)">/
3         ExtRegex = /^<div class="message"><!--([a-z]+)(\d+)-->/
4
5         attr_reader :name, :date, :vid, :state, :players, :rule
6         attr_reader :userid, :winner, :phase, :rooms, :voting
7         attr_reader :first_restart, :guard
8
9         attr_accessor :update_time
10
11         def initialize(name, vid, userid, update_time)
12                 @name, @vid, @date, @state = name, vid, 0, 0
13                 @userid, @update_time = userid, update_time
14                 @first_restart = false
15
16                 @players = Players.new
17                 @rooms = Rooms.new
18                 @period = S[:std_period] # minute
19                 # night_period = @period / 2
20                 @phase = Phase::Sun
21                 @prevote = true
22                 @voting = []
23         end
24
25         def start
26                 addlog(announce(OPENING))
27
28                 player = Player.new(1, MASTER, 0)
29                 #2011/02/23 mod:tkt for anniversary start
30                 add_player(player, specified_start_message('GERT_ENTRY'))
31                 #2011/02/23 mod:tkt for anniversary end
32         end
33
34         def restart
35                 return if @state >= State::Progress
36
37                 if discussions(@date, @players.player(1)).size > S[:log_max]
38                         do_quit()
39                         change_state_sync(State::End)
40                 else
41                         pl_dels = []
42                         @players.all.each {|p|
43                                 next if p.pid == 1
44
45                                 if (p.lastmsg_time && \
46                                          p.lastmsg_time < Time.now() - (S[:restart_minute] * 60))
47
48                                         pl_dels << p.name
49                                         @players.exit(p)
50                                 end
51                                 change_state_sync(State::Welcome)
52                         }
53
54                         #addlog(wsystem(c(AUTO_PARTING, pl_dels.join('、')))) if pl_dels != [] mod 2009/01/17
55                         addlog(wsystem(c(AUTO_PARTING, pl_dels.join('、'),Time.now.strftime(PARTING_TIME)))) if pl_dels != []
56                         
57                         while @update_time < Time.now do
58                                 @update_time += S[:restart_minute] * 60
59                         end
60
61                         DB::Villages.restart(@vid, @update_time)
62                 end
63         end
64
65         def add_player(player, message)
66                 @players.add(player)
67                 change_state_sync(State::Ready) if @players.size == @players.max
68
69                 addlog(wsystem(c(JOINING, player.name)))
70                 record("say", player, message)
71         end
72
73         def delete_player(player)
74                 #addlog(wsystem(c(PARTING, player.name))) mod 2009/01/17 tkt
75                 addlog(wsystem(c(PARTING, player.name,Time.now.strftime(PARTING_TIME))))
76
77                 @players.exit(player)
78                 change_state_sync(State::Welcome)
79         end
80
81         def change_state_sync(st)
82                 @state = st
83                 DB::Villages.change_state(@vid, st)
84         end
85
86         def need_sync?
87                 (@state < State::End && @update_time.to_i < Time.now.to_i)
88         end
89
90         def sync
91                 if (@state == State::Welcome && !@players.adv_ready?)
92                         if (@first_restart && @players.ready?)
93                                 update()
94                         else
95                                 @first_restart = true
96                                 restart()
97                         end
98                 else
99                         update()
100                 end
101         end
102
103         def timeline
104                 (0..@date).collect {|i| datestr(i) }
105         end
106
107         def discussion_size(date)  # use this, prologue only.
108                 IO.readlines("db/vil/#{@vid}_#{date}.html").size
109         end
110
111         def discussions(date, player, reverse = false)
112                 ary = IO.readlines("db/vil/#{@vid}_#{date}.html")
113                 ary.reverse! if reverse
114
115                 ary.collect {|line|
116                         if (@state < State::Party && (line =~ MesRegex || line =~ ExtRegex))
117                                 next if (!player && $1 != 'say')
118
119                                 if (player && !player.admin?)
120                                         pid = $2.to_i
121                                         # night pid is room-number
122                                         case $1
123                                         when 'whisper' then next unless player.can_whisper
124                                         when 'god'     then next unless (player.pid == pid || player.can_whisper)
125                                         when 'groan'   then next unless player.dead?
126                                         when 'night'   then next unless @rooms.in?(date, pid, player.pid)
127                                         when 'nextra'  then next unless @rooms.in?(date, pid, player.pid)
128                                         end
129                                 end
130                         end
131                         line.chomp + "\n"
132                 }.compact
133         end
134
135         def now_voting?
136                 !@voting.empty? && @phase != Phase::Apology
137         end
138         private :now_voting?
139
140         def record(type, player, msg, face = nil)
141                 face = "face#{player.color}" if !face
142                 player.cnt[@date] += 1 if (@phase == Phase::Sun && type == 'say')
143                 player.lastmsg_time = Time.now() if @state < State::Progress
144
145                 # PreVote || Vote || FinalVote || Room || AfterRoom || Morning
146                 if (player.live? && (type == 'say' || type == 'night') && [1, 2, 4, 5, 6, 8].index(@phase))
147                         raise ErrorMsg.new('フェイズと発言種類が合致しません')
148                 end
149
150                 type = 'night' if (@phase == Phase::Night && type == 'say')
151                 type = 'groan' if (player.dead? && (type == 'say' || type =='night'))
152                 type = 'say' if (player.live? && type == 'groan')
153                 type = 'say' if (@state >= State::Party && type != 'say')
154
155                 c = player.pid
156                 if type == 'night'
157                         @rooms.last.each_with_index {|ary, i|
158                                 c  = i if ary.index(player.pid)
159                         }
160                 end
161                 typec = type + c.to_s
162
163                 # don't insert \n in message, cause this line in convert to JSON.
164                 s = \
165                 %Q(<div class="#{typec}">) + \
166                 %Q(<div class="#{type}">#{player.name}) + \
167                 %Q(<table class="message_box"><tr>) + \
168                 %Q(<td width="40"><img src="#{S[:char_image_dir]}#{face}.jpg"></td>) + \
169                 %Q(<td width="16"><img src="#{S[:image_dir]}#{type}00.jpg"></td>) + \
170                 %Q(<td><div class="mes_#{type}_body0">) + \
171                 %Q(<div class="mes_#{type}_body1">#{msg}</div>) + \
172                 %Q(</div></td>) + \
173                 %Q(</tr></table></div></div>\n)
174
175                 raise ErrorMsg.new('夜ではありません') if (@phase != Phase::Night && type == 'night')
176
177                 addlog(message(s))
178         end
179
180         def vtargets
181                 @_targets || @players.lives()
182         end
183
184
185         private
186
187         # End or Quit
188         #######################################################
189
190         def do_quit
191                 addlog(announce(SYSTEM_EXIT))
192                 a = Array.new
193
194                 @players.all().each {|p|
195                         alive = (p.dead == 0) ? '生存' : '死亡'
196                         sk = (@date == 0) ? '役職決定前' : p.skill.name
197
198                         a.push(c(TRUTH, p.name, p.userid, alive, sk))
199                 }
200
201                 addlog(announce(a.join('<br>')))
202                 do_end()
203         end
204
205         def do_end
206                 @date += 1
207                 addlog(announce('終了しました'))
208                 DB::Villages.finish(@vid, @players.keys.size)
209                 DB::Users.registlast(@vid, @players.keys)
210                 Sweeper.sweep(self)
211         end
212
213
214         # Internal periodic work methods
215         #######################################################
216
217         def up_sudden_death
218                 @players.silents().each {|p|
219                         p.sudden_death(@date)
220                         addlog(announce(c(SUDDEN_DEATH, p.name)))
221                 }
222         end
223
224         def up_vote()
225                 s, votes = [], {}
226                 max = 0
227                 @players.votes.each {|ary|
228                         p, t = ary
229                         s << [p.name, t.name].join(' &raquo; ')
230                         votes[t] = votes[t].to_i + 1
231                         max = votes[t] if (votes[t] > max)
232                 }
233
234                 s << ''
235                 result = votes.select {|k, v| v == max }
236                 result.collect! {|ary| ary[0] }
237                 votes.each_pair {|p, n| s << c(ANON_VOTING, n, p.name) }
238                 addlog(announce(s.join('<br>')))
239
240                 result
241         end
242
243         def up_gameover
244                 do_end = false
245
246                 wcnt = @players.wolves().size
247                 vcnt = @players.villagers().size
248
249                 if (wcnt == 0 || vcnt == 0)
250                         if (@players.select_skill(7).size > 0)
251                                 w = (wcnt == 0) ? YOKO_WIN_F : YOKO_WIN_W
252                                 @winner = '妖魔'
253                                 addlog(announce(w))
254                         elsif (wcnt == 0)
255                                 @winner = '村人'
256                                 addlog(announce(FOLK_WIN))
257                         else
258                                 @winner = '人狼'
259                                 addlog(announce(WOLF_WIN))
260                         end
261                         do_end = true
262                 elsif @date == @guard
263                         @winner = '村人'
264                         addlog(announce(GUARD_WIN))
265                         do_end = true
266                 elsif @players.lives().size < 3
267                         exe = @players.select_skill(Skill::Exorcist)
268                         pas = @players.select_skill(Skill::Pastor)
269
270                         if ((exe.empty? || exe.first.skill.pass == false) && \
271                                 ((pas.empty? || pas.first.skill.pass == false) || \
272                                  (pas.first.skill.pass && @date + 1 != @guard)))
273
274                                 @winner = '人狼'
275                                 addlog(announce(WOLF_WIN))
276                         else
277                                 @winner = '村人'
278                                 addlog(announce(FOLK_WIN))
279                         end
280                         do_end = true
281                 end
282                 
283                 if do_end
284                         change_state_sync(State::Party)
285
286                         a = Array.new
287                         @players.all().each {|p|
288                                 alive = (p.dead == 0) ? '生存' : '死亡'
289                                 a.push(c(TRUTH, p.name, p.userid, alive, p.skill.name))
290                         }
291                         addlog(announce(a.join('<br>')))
292
293                         @players.open_party()
294                 
295                         #2011/02/23 add:tkt for anniversary start
296                         if specified_lost?
297                                 addlog(wsystem(c(specified_message('GUARD_DATE'), @guard - 1, @guard)))
298                         end
299                         #2011/02/23 add:tkt for anniversary end
300                 end
301         end
302
303         def up_showlives(include_gert = true)
304                 # Players@show_lives(), wtls
305                 pls = @players.lives()
306                 pls.delete(@players.player(1)) unless include_gert
307                 s = c(LIVES, pls.collect {|p| p.name }.join('、'), pls.size)
308                 addlog(announce(s))
309         end
310
311         def up_uptime(period = @period)
312                 $logger.debug('from: ' + @update_time.inspect)
313                 if @update_time > Time.now
314                         @update_time = Time.now + (period * 60)
315                 else
316                         @update_time += period * 60
317                 end
318                 while (@update_time && @update_time.to_i < Time.now.to_i) do
319                         @update_time += period * 60
320                 end
321                 $logger.debug('to: ' + @update_time.inspect)
322         end
323
324
325         # Update methods
326         #######################################################
327
328         def update(nocnt = nil)
329                 return if (@state == State::End)
330
331                 if (@state == State::Party || nocnt)
332                         change_state_sync(State::End)
333                         (nocnt) ? do_quit() : do_end()
334                         up_uptime()
335                         return
336                 end
337
338                 (@date == 0) ? first_update() : _update()
339         end
340         public :update
341
342         def _update
343                 case @phase
344                 when Phase::Sun
345                         end_sun()
346                         if @date == 1
347                                 start_room()
348                         elsif @prevote
349                                 start_prevote()
350                         else
351                                 start_vote()
352                         end
353                 when Phase::PreVote
354                         do_prevote()
355                         if @voting.empty?
356                                 end_prevote()
357                                 (@prevote) ? start_room() : start_vote()
358                         end
359                 when Phase::Vote
360                         do_vote()
361                         if @voting.empty?
362                                 picked = end_vote()
363
364                                 if picked.size > 1
365                                         if picked.size == @players.lives().size
366                                                 addlog(announce(STOP_EXECUTION))
367                                                 start_room()
368                                         else
369                                                 @_targets = picked.dup
370                                                 if ((@players.lives().size - picked.size) % 2) == 0
371                                                         start_apology(picked)
372                                                 else
373                                                         start_finalvote()
374                                                 end
375                                         end
376                                 else
377                                         start_room()
378                                 end
379                         end
380                 when Phase::Apology
381                         do_apology()
382                         if @voting.empty?
383                                 end_apology()
384                                 start_finalvote()
385                         end
386                 when Phase::FinalVote
387                         do_finalvote()
388                         if @voting.empty?
389                                 end_finalvote()
390                                 start_room()
391                         end
392                 when Phase::Room
393                         if @voting.empty?
394                                 end_room()
395                                 start_afterroom()
396                         else
397                                 do_room()
398
399                                 if @voting.size <= 3
400                                         finalize_room()
401                                         end_room()
402                                         start_afterroom()
403                                 end
404                         end
405                 when Phase::AfterRoom
406                         end_afterroom()
407                         start_night()
408                 when Phase::Night
409                         end_night()
410                         if @state == State::Party
411                                 start_sun()
412                         elsif @players.lives().size > 2
413                                 start_morning()
414                         else
415                                 start_sun()
416                         end
417                 when Phase::Morning
418                         end_morning()
419                         start_sun()
420                 end
421         end
422
423         def first_update
424                 up_uptime()
425                 @date += 1
426                 @players.reset_count(@date)
427
428                 @players.skill_mapping()
429                 #2011/02/23 mod:tkt for anniversary start
430                 @guard = guard_date()
431                 #2011/02/23 mod:tkt for anniversary end
432                 @rule = Regulation.rule(@players.size)
433                 change_state_sync(State::Progress)
434
435                 #2011/02/23 mod:tkt for anniversary start
436                 addlog(announce(specified_message('START')))
437                 #2011/02/23 mod:tkt for anniversary end
438                 up_showlives(false)
439                 
440                 #2011/02/23 mod:tkt for anniversary start
441                 $logger.debug("specified?(#{specified?}) specified_lost?(#{specified_lost?}) guard(#{@guard})  date(#{@date}) limit(#{(@guard - @date)}->#{(@guard - @date + 1)})")
442                 record('say', @players.player(1), c(specified_message('GERT_FIRST'), @guard - @date, @guard - @date + 1))
443                 #2011/02/23 mod:tkt for anniversary end
444                 @players.player(1).dead = 1  # die, not use Player#kill()
445
446                 wolves = @players.wolves()
447                 whisper = (wolves.size == 1) ? FIRST_WHISPER_LW : FIRST_WHISPER
448                 wolves.each {|w| record('whisper', w, whisper) }
449         end
450
451
452         # Phase methods
453         #######################################################
454
455         def start_sun
456                 #mod 2008/11/08 tkt : for epilogue time change, yes, i know this code is not good...
457                 #to-do attached plyaers.size and period time
458                 #period = (@state == State::Party) ? S[:epilogue_period] : @period
459                 period = @period
460                 if @state == State::Party
461                         period = 1 * @players.size * (@date - 1)
462                         $logger.debug("epilogue_period#{period}  plaersize#{@players.size} date#{(@date - 1)}")
463                         if period < S[:epilogue_period_min]
464                                 period = S[:epilogue_period_min]
465                         elsif (@players.size >= 8 || (period > S[:epilogue_period]))
466                                 period = S[:epilogue_period]
467                         end
468                         #period = (@state == State::Party) ? period_epi : @period               
469                 end
470                 
471                 #mod 2008/11/08 end
472                 
473                 up_uptime(period)
474                 # up_uptime(@period)
475                 @phase = Phase::Sun
476                 unless @state == State::Party
477                         limit = @guard - @date
478                         #2011/02/23 mod:tkt for anniversary start
479                         addlog(wsystem(c(specified_message('SUN_PHASE'), limit)))
480                         #2011/02/23 mod:tkt for anniversary end
481                 end
482         end
483
484         def end_sun
485                 up_sudden_death() unless $DEBUG
486                 addlog(wsystem(SUNSET_PHASE))
487         end
488
489         def start_prevote
490                 up_uptime(S[:vote_period])
491                 @phase = Phase::PreVote
492                 @voting = @players.lives().shuffle
493                 addlog(wsystem(c(PREVOTE_PHASE, @voting.collect {|p| p.sname }.join(' &raquo; '))))
494                 addlog(vote(c(ANN_VOTING, @voting.first.name)))
495         end
496
497         def do_prevote
498                 up_uptime(S[:vote_period])
499                 pl = @voting.shift
500                 res = (pl.prevote) ? '賛成' : '反対'
501                 @players.vote_map([pl, res])
502                 addlog(vote_res(c(VOTING, pl.name, res)))
503                 addlog(vote(c(ANN_VOTING, @voting.first.name))) unless @voting.empty?
504         end
505
506         def end_prevote
507                 result = @players.collect_prevote()
508                 vote = result.pop
509                 @prevote = (vote['result']) ? false : true
510
511                 s = ''
512                 @players.votes.each {|pl, |
513                         t = (pl.prevote) ? '賛成した' : '反対した'
514                         s << %Q(#{pl.name}は、投票に#{t}<br />)
515                 }
516                 s << "<br />賛成に#{vote['approve']}票、反対に#{vote['object']}票、"
517                 t = (vote['result']) ? '処刑を実施することになった。' : '処刑は保留された。'
518                 s << t + '<br />'
519
520                 addlog(announce(s))
521         end
522
523         def start_vote
524                 up_uptime(S[:vote_period])
525                 @players.reset_cmd()
526                 @phase = Phase::Vote
527                 @voting = @players.lives().shuffle
528                 addlog(wsystem(c(VOTE_PHASE, @voting.collect {|p| p.sname }.join(' &raquo; '))))
529                 addlog(vote(c(ANN_VOTING, @voting.first.name)))
530         end
531
532         def do_vote
533                 up_uptime(S[:vote_period])
534                 pl = @voting.shift
535                 pl.vote_suffle(@players.lives()) unless pl.vote
536                 target = @players.player(pl.vote)
537                 @players.vote_map([pl, target])
538                 addlog(vote_res(c(VOTING, pl.name, target.name)))
539                 addlog(vote(c(ANN_VOTING, @voting.first.name))) unless @voting.empty?
540         end
541
542         def end_vote
543                 picked = up_vote()
544
545                 if picked.size == 1
546                         addlog(announce(c(EXECUTION, picked.first.name)))
547                         picked.first.execute(@date)
548                 end
549
550                 picked
551         end
552
553         def start_apology(targets)
554                 up_uptime(@period / 3.0)
555                 @phase = Phase::Apology
556                 @voting = @_targets.shuffle
557                 x = targets.collect {|t| t.name}.join('と、')
558                 addlog(wsystem(c(APOLOGY_PHASE, x, @voting.collect {|p| p.sname }.join(' &raquo; '))))
559                 addlog(apology(c(APOLOGY_START, @voting.first.name)))
560         end
561
562         def do_apology
563                 up_uptime(@period / 3.0)
564                 @voting.shift
565                 addlog(apology(c(APOLOGY_START, @voting.first.name))) unless @voting.empty?
566         end
567
568         def end_apology
569         end
570
571         def start_finalvote
572                 up_uptime(S[:vote_period])
573                 @players.reset_cmd()
574                 @phase = Phase::FinalVote
575                 @voting = @players.lives().shuffle - @_targets
576                 x = @_targets.collect {|t| t.name}.join('と、')
577                 addlog(wsystem(c(FINALVOTE_PHASE, x, @voting.collect {|p| p.sname }.join(' &raquo; '))))
578                 addlog(vote(c(ANN_VOTING, @voting.first.name)))
579         end
580
581         def do_finalvote
582                 up_uptime(S[:vote_period])
583                 pl = @voting.shift
584                 pl.vote_suffle(vtargets()) unless pl.vote
585                 target = @players.player(pl.vote)
586                 @players.vote_map([pl, target])
587                 addlog(vote_res(c(VOTING, pl.name, target.name)))
588                 addlog(vote(c(ANN_VOTING, @voting.first.name))) unless @voting.empty?
589         end
590
591         def end_finalvote
592                 picked = up_vote()
593
594                 if picked.size == 1
595                         addlog(announce(c(EXECUTION, picked.first.name)))
596                         picked.first.execute(@date)
597                 else
598                         addlog(announce(STOP_EXECUTION))
599                 end
600
601                 @_targets = nil
602         end
603
604         def start_room
605                 @phase = Phase::Room
606                 @players.reset_cmd()
607                 @voting = @players.lives().shuffle
608                 addlog(wsystem(c(ROOM_PHASE, @voting.collect {|p| p.sname }.join(' &raquo; '))))
609                 if @voting.size <= 3
610                         finalize_room()
611                         end_room()
612                         start_afterroom()
613                 else
614                         up_uptime(S[:vote_period])
615                         addlog(room(c(ANN_ROOM_VOTING, @voting.first.name)))
616                 end
617         end
618
619         def do_room
620                 pl = @voting.shift
621                 if (!pl.vote || pl.vote == pl.pid)
622                         targets = @voting.select {|t| !pl.yesterday_mate.index(t.pid) }
623                         pl.vote_suffle(targets)
624                 end
625                 mate = @players.player(pl.vote)
626                 addlog(room_res(c(ROOM_VOTING, pl.name, mate.name)))
627
628                 @voting.delete(mate)
629                 #if (@rule == Rule::Standard || @date != 1) mod 2008/11/08 tkt:change rule for 3 members room
630                 if (@date != 1 || (@rule == Rule::Standard && (@players.size % 2 == 0)))
631                         @players.room_map([pl, mate])
632                 else # Advance
633                         last_room = @players.mates.last
634                         if (last_room && last_room.size == 2)
635                                 lr = last_room.dup
636                                 lr.push(mate)
637                                 names = lr.map {|pl| pl.name }
638                                 addlog(room_res2(c(ROOM_RESULT_ADV, names.join('と、'))))
639                                 @players.room_remap(lr)
640                                 # last room mate added, go next
641                         else
642                                 @players.room_map([pl, mate])
643                                 @voting.unshift(mate) unless @voting.size < 3
644                                 # not filled in the room
645                         end
646                 end
647
648                 unless (@voting.empty? || @voting.size <= 3)
649                         up_uptime(S[:vote_period])
650                         addlog(room(c(ANN_ROOM_VOTING, @voting.first.name)))
651                 end
652                 @players.vote_suffle(@voting) unless @voting.empty? 
653         end
654
655         def finalize_room
656                 @players.room_map(@voting.dup)
657                 x = @voting.collect {|p| p.name}.join('と、')
658                 addlog(room_res(c(BUSH_ROOM, x)))
659                 last = nil
660
661                 until @voting.empty?
662                         if @voting.size == 1
663                                 pl = @voting.shift
664                                 pl.vote = last.pid
665                         else
666                                 pl = @voting.shift
667                                 mate = @voting.shift
668                                 pl.vote = mate.pid
669                                 mate.vote = pl.pid
670
671                                 last = mate
672                         end
673                 end
674         end
675
676         def end_room
677                 @rooms.push([])
678                 result = @players.room_mapping()
679                 result.each {|room_mates| @rooms.last << room_mates.collect {|x| x.pid } }
680
681                 s = ROOM_RESULT
682                 last = result.pop
683                 result.each {|room_mates|
684                         s << room_mates.collect {|x| x.name }.join(' &raquo; ') + '<br />'
685                 }
686                 s << last.collect {|x| x.name }.join('、') + '<br />'
687
688                 addlog(announce(s))
689         end
690
691         def start_afterroom
692                 up_uptime(S[:vote_period])
693                 @phase = Phase::AfterRoom
694                 addlog(wsystem(AFTERROOM_PHASE))
695         end
696
697         def end_afterroom
698         end
699
700         def start_night
701                 up_uptime()
702                 @phase = Phase::Night
703                 addlog(wsystem(NIGHT_PHASE))
704         end
705
706         def end_night
707                 @players.end_action(self)
708                 logremap()
709
710                 @date += 1
711                 @players.reset_count(@date)
712                 @prevote = false if (@prevote && @players.deads().size > 1)
713
714                 s = ROOM_YESTERDAY
715                 yesterday_room = @rooms[@date - 2].dup
716                 last = yesterday_room.pop
717                 yesterday_room.each {|room_mates|
718                         s << room_mates.collect {|x| @players.player(x).name }.join(' &raquo; ') + '<br />'
719                 }
720                 s << last.collect {|x| @players.player(x).name }.join('、') + '<br />'
721
722                 addlog(wsystem(s))
723
724                 deads = @players.killed(@date-1)
725                 if deads.empty?
726                         addlog(announce(KILLMISS))
727                 else
728                         _ = deads.collect {|pl| pl.name }.join('と、')
729                         addlog(announce(c(KILLED, _)))
730                 end
731
732                 up_gameover()
733
734                 return if @state == 3
735
736                 up_showlives()
737         end
738
739         def start_morning
740                 up_uptime(S[:vote_period] + 0.2)
741                 @phase = Phase::Morning
742                 addlog(wsystem(MORNING_PHASE))
743         end
744
745         def end_morning
746         end
747
748
749         # Misc methods
750         #######################################################
751
752         def addlog(msg)
753                 File.open("db/vil/#{@vid}_#{@date}.html", 'a') {|of|
754                         of.flock(File::LOCK_EX)
755                         of.print(msg)
756                         of.flock(File::LOCK_UN)
757                 }
758         end
759         public :addlog  # FIXME! ==> sysrecord
760
761         def logremap
762                 $logger.debug('restructuring log...')
763                 s = File.read("db/vil/#{@vid}_#{@date}.html")
764                 msgs = _logremap(s)
765
766                 File.open("db/vil/#{@vid}_#{@date}.html", 'w') {|of|
767                         of.flock(File::LOCK_EX)
768                         of.print(msgs)
769                         of.flock(File::LOCK_UN)
770                 }
771         end
772         
773         def _logremap(str)
774                 _ = ''
775                 ary = str.split("\n")
776                 loop {
777                         line = ary.shift
778                         _ << line + "\n"
779
780                         break if line =~ /^<div class="message"><div class="system">#{NIGHT_PHASE}/o
781                 }
782
783                 night_hash = _logremap_night(ary)
784                 keys = night_hash.keys
785                 keys.delete('groan')
786                 keys.sort.each {|key|
787                         members = @rooms.members(@date, key).collect {|i| @players.player(i).name }
788                         _ << wsystem(c(ROOM_HEAD, members.join('、'))) + "\n"
789                         _ << night_hash[key].join("\n") + "\n"
790                 }
791                 _ << wsystem(GROAN_HEAD) + "\n"
792                 _ << night_hash['groan'].join("\n") + "\n"
793                 _
794         end
795
796         def _logremap_night(night_ary)
797                 h = {'groan' => []}
798                 night_ary.each {|line|
799                         if (line =~ MesRegex || line =~ ExtRegex)
800                                 pid = $2.to_i
801                                 case $1
802                                 when /(night)|(nextra)/
803                                         h[pid] = [] unless h.has_key?(pid)
804                                         h[pid] << line
805                                 when /(whisper)|(god)/
806                                         num = @rooms.number(@date, pid)
807                                         h[num] = [] unless h.has_key?(num)
808                                         h[num] << line
809                                 when 'groan'
810                                         h['groan'] << line
811                                 when 'say'
812                                         $logger.debug('state lock bug?')
813                                         $logger.debug(line)
814                                         # raise 'Must not happen.'
815                                 end
816                         else
817                                 $logger.debug('multiple logremap bug?')
818                                 $logger.debug(line)
819                                 # raise 'Must not happen.'
820                         end
821                 }
822                 h
823         end
824
825         def datestr(date)
826                 if date == 0
827                         'プロローグ'
828                 elsif (@state == State::End && date + 1 >= @date)
829                         (date == @date) ? '終了' : 'エピローグ'
830                 elsif (@state == State::Party && date == @date)
831                         'エピローグ'
832                 else
833                         "#{date}日目"
834                 end
835         end
836         
837         #2011/02/23 add:tkt for anniversary start
838         def specified?
839                 S[:specified_vils].index(@vid.to_s) != nil
840         end
841         
842         def specified_lost?
843                 S[:specified_lost] && specified?
844         end
845         
846         def specified_message(default)
847                 if @rule == Rule::Advance
848                         specified_start_message(default)
849                 else
850                         eval(default)
851                 end
852         end
853         
854         def specified_start_message(default)
855                 if specified_lost?
856                         eval(default + '_LOST')
857                 else
858                         eval(default)
859                 end
860         end
861         
862         def guard_date
863                 date = Regulation.guard(@players.size, @players.wolves().size)
864                 if specified?
865                         date += rand(2)
866                 end
867                 
868                 date
869         end
870
871         #2011/02/23 add:tkt for anniversary end
872
873 end