001 /**
002 * Jetrix TetriNET Server
003 * Copyright (C) 2004 Emmanuel Bourg
004 *
005 * This program is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU General Public License
007 * as published by the Free Software Foundation; either version 2
008 * of the License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013 * GNU General Public License for more details.
014 *
015 * You should have received a copy of the GNU General Public License
016 * along with this program; if not, write to the Free Software
017 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
018 */
019
020 package net.jetrix.filter;
021
022 import static java.lang.Math.*;
023 import static net.jetrix.GameState.*;
024
025 import net.jetrix.*;
026 import net.jetrix.config.*;
027 import net.jetrix.messages.channel.*;
028 import net.jetrix.messages.channel.specials.*;
029
030 import java.util.*;
031
032 import org.apache.commons.lang.time.StopWatch;
033
034 /**
035 * Sudden death mode. This filter implements the well known sudden death mode
036 * from tetrinetx: after a given time, lines are added to all players at a
037 * specified rate until the game ends.
038 *
039 * @author Emmanuel Bourg
040 * @version $Revision: 798 $, $Date: 2009-02-18 16:24:28 +0100 (Wed, 18 Feb 2009) $
041 */
042 public class SuddenDeathFilter extends GenericFilter
043 {
044 private StopWatch stopWatch;
045 private Timer timer;
046
047 public void init()
048 {
049 stopWatch = new StopWatch();
050 }
051
052 public void onMessage(StartGameMessage m, List<Message> out)
053 {
054 out.add(m);
055
056 if (getChannel().getGameState() == STOPPED)
057 {
058 stopWatch.reset();
059 stopWatch.start();
060 }
061
062 Settings settings = getChannel().getConfig().getSettings();
063 int time = settings.getSuddenDeathTime() * 1000;
064
065 if (time > 0)
066 {
067 // start the monitoring thread
068 timer = new Timer();
069 timer.schedule(new Task(time), max(0, time - Task.WARNING_DELAY * 1000), 200);
070 }
071 }
072
073 public void onMessage(EndGameMessage m, List<Message> out)
074 {
075 out.add(m);
076
077 if (getChannel().getGameState() != STOPPED)
078 {
079 stopWatch.stop();
080 }
081
082 if (timer != null)
083 {
084 // kill the monitoring thread
085 timer.cancel();
086 timer = null;
087 }
088 }
089
090 public void onMessage(PauseMessage m, List<Message> out)
091 {
092 out.add(m);
093
094 if (getChannel().getGameState() == STARTED)
095 {
096 stopWatch.suspend();
097 }
098 }
099
100 public void onMessage(ResumeMessage m, List<Message> out)
101 {
102 out.add(m);
103
104 if (getChannel().getGameState() == PAUSED)
105 {
106 stopWatch.resume();
107 }
108 }
109
110 private class Task extends TimerTask
111 {
112 public static final int WARNING_DELAY = 60;
113
114 private boolean suddenDeathEnabled;
115 private long nextTriggerTime;
116 private long nextWarningTime;
117
118 public Task(long nextTriggerTime)
119 {
120 this.nextTriggerTime = nextTriggerTime;
121 this.nextWarningTime = nextTriggerTime - WARNING_DELAY * 1000;
122 }
123
124 public void run()
125 {
126 Settings settings = getChannel().getConfig().getSettings();
127
128 if (stopWatch.getTime() >= nextTriggerTime)
129 {
130 if (!suddenDeathEnabled)
131 {
132 // enable the sudden death mode
133 suddenDeathEnabled = true;
134
135 // notify the players
136 GmsgMessage gmsg = new GmsgMessage();
137 String message = settings.getSuddenDeathMessage();
138 if (message.startsWith("key:"))
139 {
140 gmsg.setKey(message.substring(4));
141 }
142 else
143 {
144 gmsg.setText(message);
145 }
146
147 getChannel().send(gmsg);
148
149 GmsgMessage rate = new GmsgMessage();
150 rate.setKey("filter.suddendeath.rate", settings.getSuddenDeathLinesAdded(), settings.getSuddenDeathDelay());
151 getChannel().send(rate);
152 }
153
154 // add the lines
155 sendLines(settings.getSuddenDeathLinesAdded());
156
157 // update the next time the lines will be added
158 nextTriggerTime = nextTriggerTime + settings.getSuddenDeathDelay() * 1000;
159 }
160 else if (stopWatch.getTime() >= nextWarningTime && !suddenDeathEnabled)
161 {
162 // warn the players
163 GmsgMessage gmsg = new GmsgMessage();
164 gmsg.setKey("filter.suddendeath.warning", Math.ceil((nextTriggerTime - stopWatch.getTime()) / 1000d));
165 getChannel().send(gmsg);
166
167 nextWarningTime = nextWarningTime + WARNING_DELAY * 1000;
168 }
169 }
170
171 /**
172 * Add lines to all players in the channel
173 *
174 * @param count the number of lines to add
175 */
176 private void sendLines(int count)
177 {
178 Channel channel = getChannel();
179
180 if (count == 1)
181 {
182 channel.send(new OneLineAddedMessage());
183 }
184 if (count >= 4)
185 {
186 channel.send(new FourLinesAddedMessage());
187 sendLines(count - 4);
188 }
189 else if (count >= 2)
190 {
191 channel.send(new TwoLinesAddedMessage());
192 sendLines(count - 2);
193 }
194 }
195 }
196
197 public String getName()
198 {
199 return "Sudden Death";
200 }
201
202 public String getDescription()
203 {
204 return "Sudden death mode for never ending games";
205 }
206
207 public String getVersion()
208 {
209 return "1.0";
210 }
211
212 public String getAuthor()
213 {
214 return "Emmanuel Bourg";
215 }
216 }