1 /* -*- Mode: C++; c-basic-offset: 2; tab-width: 2; indent-tabs-mode: nil -*-
2  *
3  * Quadra, an action puzzle game
4  * Copyright (C) 1998-2000  Ludus Design
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 
21 #include "menu.h"
22 
23 #include <stdlib.h>
24 #include "version.h"
25 #include "canvas.h"
26 #include "chat_text.h"
27 #include "color.h"
28 #include "cfgfile.h"
29 #include "crypt.h"
30 #include "dict.h"
31 #include "fonts.h"
32 #include "game.h"
33 #include "game_menu.h"
34 #include "global.h"
35 #include "highscores.h"
36 #include "http_request.h"
37 #include "image_png.h"
38 #include "input.h"
39 #include "inter.h"
40 #include "main.h"
41 #include "menu_demo_central.h"
42 #include "misc.h"
43 #include "multi_player.h"
44 #include "multi_provider.h"
45 #include "net.h"
46 #include "net_server.h"
47 #include "net_stuff.h"
48 #include "overmind.h"
49 #include "pane.h"
50 #include "qserv.h"
51 #include "quadra.h"
52 #include "random.h"
53 #include "recording.h"
54 #include "res_compress.h"
55 #include "sons.h"
56 #include "sprite.h"
57 #include "zone.h"
58 #include "config.h"
59 
60 #ifdef UGS_DIRECTX
61 #include <shellapi.h>
62 #endif
63 
64 using std::vector;
65 
step()66 void Menu_do_nothing::step() {
67   if(quitting)
68     ret();
69 }
70 
Menu_highscore(int hscore,int * playagain,bool show_playb)71 Menu_highscore::Menu_highscore(int hscore, int *playagain, bool show_playb) {
72   play_again = playagain;
73   show_playback = show_playb;
74   int i;
75   for(i=0; i<MAX_SCORE; i++) {
76     playdemo[i] = NULL;
77     playdemog[i] = NULL;
78   }
79 
80   {
81     Res_doze res("hscore.png");
82     Png img(res);
83     bit = new Bitmap(img);
84     pal.load(img);
85   }
86   inter->set_font(new Font(*fonts.normal, pal, 255,255,255, 0, 20, 40));
87   font2 = new Font(*fonts.normal, pal, 255,255,0, 0,20,40);
88   courrier = new Font(*fonts.courrier, pal, 255,255,255, 0,20,40);
89   courrier2 = new Font(*fonts.courrier, pal, 255,255,0, 0,20,40);
90   (void)new Zone_bitmap(inter, bit, 0, 0, true);
91 
92   const char *pic1, *pic2, *pic1s, *pic2s;
93   pic1 = "hscore1.png";
94   pic2 = "hscore2.png";
95   pic1s = "hscore1s.png";
96   pic2s = "hscore2s.png";
97   b_again = b_quit = NULL;
98   if(show_playback) {
99     {
100       Res_doze res1(pic2);
101       Png png1(res1);
102       Res_doze res2(pic2s);
103       Png png2(res2);
104       b_quit = new Zone_menu(inter, png1, 485, 410, png2);
105     }
106     if(play_again) {
107       Res_doze res1(pic1);
108       Png png1(res1);
109       Res_doze res2(pic1s);
110       Png png2(res2);
111       b_again = new Zone_menu(inter, png1, 38, 410, png2);
112     }
113   } else {
114     time_demo = 6000;
115   }
116 
117   int x;
118   if(show_playback)
119     x = 60;
120   else
121     x = 100;
122   int y = 50;
123   (void)new Zone_text(inter, "Hero", x, y);
124   (void)new Zone_text(inter, "Score", x+190, y);
125   (void)new Zone_text(inter, "Lines", x+290, y);
126   (void)new Zone_text(inter, "Level", x+390, y);
127   y += 20;
128   Highscores::load();
129   refresh_global(y); //int&
130 
131   if(show_playback && net->active) {
132     sync = new Zone_text_button2(inter, bit, font2, "�2 Update", x+460, 186);
133     status = new Zone_text_field(inter, "", 30, 186, 470);
134     status->set_val("Click on �2 Update to update worldwide highscores.");
135   } else {
136     sync = NULL;
137     status = NULL;
138   }
139   sync_request = NULL;
140 
141   y = 256;
142   (void)new Zone_text(inter, "Hero", x, y);
143   (void)new Zone_text(inter, "Score", x+190, y);
144   (void)new Zone_text(inter, "Lines", x+290, y);
145   (void)new Zone_text(inter, "Level", x+390, y);
146   y += 20;
147   for(i=0; i<Highscores::numLocal; i++) {
148     if(hscore == i) {
149       (void)new Zone_text(font2, inter, Highscores::bestlocal[i].name, x, y);
150       (void)new Zone_text_numeric(courrier2, inter, &Highscores::bestlocal[i].score, x+160, y, 80);
151       (void)new Zone_text_numeric(courrier2, inter, &Highscores::bestlocal[i].lines, x+260, y, 80);
152       (void)new Zone_text_numeric(courrier2, inter, &Highscores::bestlocal[i].level, x+360, y, 80);
153       sons.levelup->play(0, 0, 11000);
154     } else {
155       (void)new Zone_text(inter, Highscores::bestlocal[i].name, x, y);
156       (void)new Zone_text_numeric(courrier, inter, &Highscores::bestlocal[i].score, x+160, y, 80);
157       (void)new Zone_text_numeric(courrier, inter, &Highscores::bestlocal[i].lines, x+260, y, 80);
158       (void)new Zone_text_numeric(courrier, inter, &Highscores::bestlocal[i].level, x+360, y, 80);
159     }
160     if(show_playback)
161       playdemo[i] = new Zone_text_button2(inter, bit, font2, "Playback", x+460, y);
162     y += 21;
163   }
164 
165   playlast = NULL;
166   if(show_playback) {
167     snprintf(st, sizeof(st) - 1, "%s/last.qrec", quadradir);
168     Res_dos *res = new Res_dos(st, RES_TRY);
169     if(res->exist) {
170       y += 6;
171       (void)new Zone_text(inter, "Replay last single-player game:", x, y);
172       playlast = new Zone_text_button2(inter, bit, font2, "Playback", x+460, y);
173     }
174     delete res;
175   }
176 }
177 
~Menu_highscore()178 Menu_highscore::~Menu_highscore() {
179   delete font2;
180   delete courrier;
181   delete courrier2;
182   if(sync_request)
183     delete sync_request;
184 }
185 
refresh_global(int & y)186 void Menu_highscore::refresh_global(int& y) {
187   int x;
188   if(show_playback)
189     x = 60;
190   else
191     x = 100;
192   list.deleteall();
193   for(int i=0; i<Highscores::numGlobal; i++) {
194     playdemog[i] = NULL;
195     list.zones.push_back(new Zone_text(inter, Highscores::bestglobal[i].name, x, y));
196     list.zones.push_back(new Zone_text_numeric(courrier, inter, &Highscores::bestglobal[i].score, x+160, y, 80));
197     list.zones.push_back(new Zone_text_numeric(courrier, inter, &Highscores::bestglobal[i].lines, x+260, y, 80));
198     list.zones.push_back(new Zone_text_numeric(courrier, inter, &Highscores::bestglobal[i].level, x+360, y, 80));
199     if(show_playback) {
200       playdemog[i] = new Zone_text_button2(inter, bit, font2, "Playback", x+460, y);
201       list.zones.push_back(playdemog[i]);
202     }
203     y += 21;
204   }
205   video->need_paint = 2;
206 }
207 
208 // Very specifically for URL-encoding of base64 buffers, mangles its source in
209 // the process.
fast_plusonly_url_encode(Textbuf & out,Textbuf & in)210 static void fast_plusonly_url_encode(Textbuf& out, Textbuf& in) {
211   char* ptr = in.get();
212   out.reserve(in.len());
213   while (*ptr != '\0') {
214     char* index = strchr(ptr, '+');
215     if (index) {
216       *index = '\0';
217       out.appendraw(ptr);
218       out.appendraw("%2B");
219       ptr = index + 1;
220     } else {
221       out.appendraw(ptr);
222       break;
223     }
224   }
225 }
226 
start_sync()227 void Menu_highscore::start_sync() {
228   sync->set_text("�2 Cancel");
229   video->need_paint = 2;
230   Res_dos *demofile;
231   sync_request = new Qserv();
232   if(Highscores::numLocal>=1) {
233     char st[1024];
234     Highscores::getFilename(st, 0, sizeof(st));
235     demofile=new Res_dos(st, RES_TRY);
236     if(!demofile->exist) {
237       delete demofile;
238       demofile=NULL;
239     }
240   }
241   else
242     demofile=NULL;
243   if(demofile) {
244     Playback *demo=Highscores::bestlocal[0].demo;
245     sync_request->add_data("postdemo\n");
246     sync_request->add_data("name %s\n", demo->player);
247     sync_request->add_data("score %i\n", demo->score);
248     sync_request->add_data("lines %i\n", demo->lines);
249     sync_request->add_data("level %i\n", demo->level);
250     //Add the recording
251     sync_request->add_data("rec ");
252     Textbuf buf;
253     msgbox("Menu_highscore::start_sync: original size=%i\n", demofile->size());
254     Http_request::base64encode((const Byte*)demofile->buf(), buf, demofile->size());
255     msgbox("Menu_highscore::start_sync: encoded size=%i\n", strlen(buf.get()));
256     delete demofile;
257     demofile=NULL;
258     Textbuf safebuf;
259     fast_plusonly_url_encode(safebuf, buf);
260     sync_request->add_data_large(safebuf);
261     sync_request->add_data("\n");
262   }
263   else
264     sync_request->add_data("gethighscores\n");
265 
266   //Expecting MAX_SCORE global highscores in answer
267   sync_request->add_data("num %i\n", MAX_SCORE);
268   sync_request->send();
269   status->set_val("Connecting. Please wait...");
270 }
271 
step_sync()272 void Menu_highscore::step_sync() {
273   bool done = sync_request->done();
274   if(!done) {
275     if(sync_request->isconnected()) {
276       sprintf(st, "Connected. Transfer in progress. %i bytes.", sync_request->getnbrecv());
277       status->set_val(st);
278     }
279     return;
280   }
281 
282   const char *server_status = sync_request->get_status();
283   if(!server_status || (strcmp(server_status, "Ok") && strcmp(server_status, "Error"))) {
284     stop_sync();
285     status->set_val("No Quadra game server found.");
286     return;
287   }
288   Dict *reply=sync_request->get_reply();
289   if(_debug) {
290     reply->dump();
291   }
292   if(strcmp(server_status, "Ok")) {
293 	// qserv returned an "Error" status, display the supplied message
294     const char *msg = reply->find("message");
295 	if(!msg)
296       msg = "???";
297     sprintf(st, "Error: the server returned [%s].", msg);
298     status->set_val(st);
299     stop_sync();
300     return;
301   }
302   int i;
303   for(i=0; i<MAX_SCORE; i++) {
304     char dir[16];
305     sprintf(dir, "high%03i", i);
306     Dict *d=reply->find_sub(dir);
307     if(d) {
308       const char* rec=d->find("rec");
309       if(rec) {
310         char fn[1024];
311         Highscores::getGlobalFilename(fn, i, sizeof(fn));
312         Res_dos res(fn, RES_CREATE);
313         if(res.exist) {
314           Buf out;
315           msgbox("Menu_highscore::step_sync: encoded size=%i\n", strlen(rec));
316           Http_request::base64decode(rec, out, strlen(rec));
317           msgbox("Menu_highscore::step_sync: decoded size=%i\n", out.size());
318           res.write(out.get(), out.size());
319 				}
320       }
321     }
322   }
323   status->set_val("Transfer completed successfully.");
324   Highscores::freemem();
325   Highscores::load();
326   int y=70;
327   refresh_global(y);
328   stop_sync();
329 }
330 
stop_sync()331 void Menu_highscore::stop_sync() {
332   sync->set_text("�2 Update");
333   video->need_paint = 2;
334   delete sync_request;
335   sync_request=NULL;
336 }
337 
step()338 void Menu_highscore::step() {
339   Menu_standard::step();
340   if(show_playback) {
341     if(sync_request)
342       step_sync();
343     if(!result)
344       return;
345 
346     if(!sync_request) {
347       if(play_again) {
348         if(result == b_again) {
349           *play_again = 1;
350           quit = true;
351         }
352       }
353       if(result == b_quit) {
354         quit = true;
355       }
356       if(sync && result == sync) {
357         start_sync();
358       }
359       for(int i=0; i<MAX_SCORE; i++) {
360         if(result == playdemo[i]) {
361           Highscores::getFilename(st, i, sizeof(st));
362           play_demo(st);
363         }
364         if(result == playdemog[i]) {
365           Highscores::getGlobalFilename(st, i, sizeof(st));
366           play_demo(st);
367         }
368       }
369       if(result == playlast) {
370         snprintf(st, sizeof(st) - 1, "%s/last.qrec", quadradir);
371         play_demo(st);
372       }
373     } else {
374       if(result == sync) {
375         stop_sync();
376         status->set_val("Transfer interrupted by user.");
377       }
378     }
379   } else { // demo mode of the main menu
380     time_demo--;
381     if(result || input->last_key.sym != SDLK_UNKNOWN || time_demo == 0)
382       quit = true;
383   }
384 }
385 
play_demo(const char * st)386 void Menu_highscore::play_demo(const char *st) {
387   Res_compress *res = new Res_compress(st, RES_TRY);
388   if(res->exist) {
389     call(new Fade_in(pal));
390     call(new Call_setfont(pal, new Demo_multi_player(res)));
391     call(new Fade_out(pal));
392     // the 'delete res' is done by ~Demo_multi_player
393   } else {
394     msgbox("Menu_highscore::step: Unable to open demo '%s'\n", st);
395     delete res;
396   }
397 }
398 
399 Net_starter* net_starter=NULL;
400 
Net_starter()401 Net_starter::Net_starter() {
402   if(net)
403     fatal_msgbox("Net already started!\n");
404   time_control = TIME_FREEZE;
405   net=new Net(new Quadra_param());
406   if(!net->active) {
407     msgbox("Net_starter::Net_starter: Can't initialise network.");
408     const char *temp = net->last_error;
409     if(temp)
410       msgbox("Error [%s]\n", temp);
411     else
412       msgbox("No error reported.\n");
413     net_exec = NULL;
414   } else {
415     net_exec = new Executor(true);
416     net_exec->add(new Net_module());
417     overmind.start(net_exec);
418     if(chat_text)
419       chat_text->addwatch();
420   }
421 }
422 
~Net_starter()423 Net_starter::~Net_starter() {
424   if(net_exec) {
425     overmind.stop(net_exec);
426     if(chat_text)
427       chat_text->removewatch();
428   }
429   delete net;
430   net=NULL;
431 }
432 
Menu_multi_join(Bitmap * bit,Font * font,Font * font2,const Palette & p,bool plocal)433 Menu_multi_join::Menu_multi_join(Bitmap *bit, Font *font, Font *font2, const Palette& p, bool plocal) {
434   pal = p;
435   bit_ = bit;
436   font2_ = font2;
437   local_net = plocal;
438   inter->set_font(font, false);
439   (void)new Zone_bitmap(inter, bit, 0, 0);
440   (void)new Zone_text(inter, "\"To create or to join, that is the "
441                       "question\" - Rem, 1999", 20);
442   b_create = new Zone_text_button2(inter, bit, font2, "�2 Create a new game",
443                                    50);
444   b_refresh = b_refresh_internet = NULL;
445   if(local_net)
446     b_refresh = new Zone_text_button2(inter, bit, font2,
447                                       "�2 Refresh local games", 80);
448   else
449     b_refresh_internet = new Zone_text_button2(inter, bit, font2,
450                                                "�2 Refresh Internet games",
451                                                80);
452   (void)new Zone_text(fteam[7], inter, "Server list:", 10, 120);
453   selected_game = -1;
454   list_game = new Zone_listbox2(inter, bit, font2, &selected_game, 2, 140, 220, 240);
455   int y = 120;
456   (void)new Zone_text(fteam[7], inter, "Type:", 235, y);
457   z_game_type = new Zone_text_field(inter, "", 480, y, 155); y += 22;
458   (void)new Zone_text(fteam[7], inter, "Level up:", 235, y);
459   z_game_speed = new Zone_text_field(inter, "", 480, y, 155); y += 22;
460   (void)new Zone_text(fteam[7], inter, "Start game at level:", 235, y);
461   z_game_level = new Zone_text_field(inter, "", 480, y, 24); y += 22;
462   (void)new Zone_text(fteam[7], inter, "Smallest offensive line combo:",
463                       235, y);
464   z_game_minimum = new Zone_text_field(inter, "", 480, y, 155); y += 22;
465   (void)new Zone_text(fteam[7], inter, "The game ends when:", 235, y);
466   z_game_end = new Zone_text_field(inter, "", 480, y, 155); y += 22;
467   (void)new Zone_text(fteam[7], inter, "Status:", 235, y);
468   z_game_status = new Zone_text_field(inter, "", 480, y, 155); y += 22;
469   list_player = new Zone_listbox2(inter, bit, font2, NULL, 235, y, 390, 136);
470   b_join = new Zone_text_button2(inter, bit, font2, "�2 Join selected game",
471                                  395);
472 
473   (void)new Zone_text(fteam[7], inter, "Or enter the IP address of the server:",
474                       30, 420);
475   address[0] = 0;
476   (void)new Zone_input_address(this, pal, inter, address, 254, 340, 420, 240);
477   b_info = new Zone_text_button2(inter, bit, font2, "�2 Check IP info",
478                                  35, 450);
479   b_book = NULL;
480   if(!local_net)
481     b_book = new Zone_text_button2(inter, bit, font2, "�2 Address book", 345, 450);
482   cancel = new Zone_text_button2(inter, bit, font2, "Back �0", 560, 450);
483 }
484 
~Menu_multi_join()485 Menu_multi_join::~Menu_multi_join() {
486   removewatch();
487 }
488 
addwatch()489 void Menu_multi_join::addwatch() {
490   net->addwatch(P_GAMEINFO, this);
491 }
492 
removewatch()493 void Menu_multi_join::removewatch() {
494   net->removewatch(P_GAMEINFO, this);
495 }
496 
init()497 void Menu_multi_join::init() {
498   Menu::init();
499   if(!net->active) {
500     exec(new Menu_net_problem(net->last_error,
501                               "You will not be able to play on the Internet.",
502                               bit_, inter->font));
503   } else {
504     net->close_all_udp();
505     net->init_all_udp();
506     refresh();
507   }
508 }
509 
510 class Listgame: public Listable {
511 public:
512   Packet_gameinfo *p;
Listgame(const char * s,Packet_gameinfo * pp)513   Listgame(const char *s, Packet_gameinfo *pp): Listable(s) {
514     p = pp;
515   }
~Listgame()516   virtual ~Listgame() {
517     delete p;
518   }
is_equal(Listable * source)519   virtual bool is_equal(Listable *source) {
520     Listgame *other=(Listgame *) source;
521     return p->from_addr == other->p->from_addr &&
522            p->port == other->p->port;
523   }
524 };
525 
step()526 void Menu_multi_join::step() {
527   Menu::step();
528   if(input->last_key.sym == SDLK_ESCAPE || quitting) {
529     ret();
530     return;
531   }
532 
533   if(!result)
534     return;
535 
536   if(result==b_create) {
537     removewatch();
538     if(address[0] == 0)
539       refresh();
540     call(new Create_game(bit_, inter->font, font2_, pal, true, local_net));
541   }
542   if(result==b_refresh || result==b_refresh_internet) {
543     address[0] = 0; // ignore the IP address written in the box
544     refresh();
545   }
546   if(result==b_info) {
547     call(new Menu_multi_checkip(bit_, inter->font, font2_, pal));
548   }
549   if(result==b_book) {
550     call(new Menu_multi_book(bit_, inter->font, font2_, pal, NULL));
551   }
552   Listgame *lg = (Listgame *) list_game->get_selected();
553   if(lg && list_game->in_listbox(result))
554     refresh_player();
555   if(lg && (list_game->in_listbox(inter->double_clicked) || result==b_join)) {
556     Packet_gameinfo *p = lg->p;
557     if(p->version==20 || p->version==22 || p->version==23 || p->version==Config::net_version) {
558       if(address[0] == 0)
559         refresh();
560       join_game(p->name, p->from_addr, p->port);
561     }
562   }
563   if(result == cancel) {
564     ret();
565     return;
566   }
567 }
568 
join_game(char * nam,Dword adr,int port)569 void Menu_multi_join::join_game(char *nam, Dword adr, int port) {
570   removewatch();
571   call(new Join_game(bit_, inter->font, font2_, pal, nam, adr, port, false));
572 }
573 
refresh()574 void Menu_multi_join::refresh() {
575   call(new Menu_multi_refresh(this));
576 }
577 
clear_game_info()578 void Menu_multi_join::clear_game_info() {
579   list_player->clear();
580   z_game_type->set_val("");
581   z_game_speed->set_val("");
582   z_game_level->set_val("");
583   z_game_minimum->set_val("");
584   z_game_end->set_val("");
585   z_game_status->set_val("");
586 }
587 
refresh_player()588 void Menu_multi_join::refresh_player() {
589   clear_game_info();
590   Listgame *lg = (Listgame *) list_game->get_selected();
591   Packet_gameinfo *p = lg->p;
592 
593 	vector<Net_player*>::const_iterator it;
594   for (it = p->players.begin(); it != p->players.end(); ++it) {
595     char name[256];
596     strcpy(name, (*it)->name);
597     if((*it)->idle==3)
598       strcat(name, " *");
599     list_player->add_item(new Listable(name, fteam[(*it)->team]));
600   }
601 
602   if(p->version >= 20) {
603     const char *gtype = "Free for all";
604     if(p->survivor)
605       gtype = "Survivor";
606     if(p->normal_attack.type == ATTACK_NONE
607        && p->clean_attack.type == ATTACK_NONE)
608       gtype = "Peace";
609     if(p->normal_attack.type == ATTACK_BLIND
610        || p->normal_attack.type == ATTACK_FULLBLIND)
611       gtype = "Blind";
612     if(p->hot_potato)
613       gtype = "Hot potato";
614     z_game_type->set_val(gtype);
615     if(!p->nolevel_up)
616       z_game_speed->set_val("At 15 lines");
617     else
618       z_game_speed->set_val("Disabled");
619     game_level_start = (int) p->level_start;
620     z_game_level->set_val(&game_level_start);
621     if(p->combo_min == 1)
622       z_game_minimum->set_val("Single");
623     else if(p->combo_min == 2)
624       z_game_minimum->set_val("Double");
625     else if(p->combo_min == 3)
626       z_game_minimum->set_val("Triple");
627     else if(p->combo_min == 4)
628       z_game_minimum->set_val("Quad");
629     else {
630       char stbuf[16];
631       snprintf(stbuf, sizeof(stbuf), "%i-lines", p->combo_min);
632       z_game_minimum->set_val(stbuf);
633     }
634     switch(p->game_end) {
635       case 0: z_game_end->set_val("Never"); break;
636       case 1:
637         sprintf(game_end_text, "%i %s", p->game_end_value, "frags.");
638         z_game_end->set_val(game_end_text);
639         break;
640       case 2:
641         sprintf(game_end_text, "%i %s", p->game_end_value / 6000, "minutes.");
642         z_game_end->set_val(game_end_text);
643         break;
644       case 3:
645         sprintf(game_end_text, "%i %s", p->game_end_value, "points.");
646         z_game_end->set_val(game_end_text);
647         break;
648       case 4:
649         sprintf(game_end_text, "%i %s", p->game_end_value, "lines.");
650         z_game_end->set_val(game_end_text);
651         break;
652     }
653     if(p->terminated) {
654       z_game_status->set_val("Terminated");
655     } else {
656       if(p->delay_start)
657         z_game_status->set_val("Not yet started");
658       else
659         z_game_status->set_val("Playing");
660     }
661   }
662 
663   if(p->version < 20/*Config::net_version*/) {
664     z_game_type->set_val("* older version *");
665   }
666   if(p->version > Config::net_version) {
667     z_game_type->set_val("* newer version *");
668   }
669 }
670 
net_call(Packet * p2)671 void Menu_multi_join::net_call(Packet *p2) {
672   Packet_gameinfo *p=(Packet_gameinfo *)p2;
673 //  char ad[256];
674 //  Net::stringaddress(ad, p->from_addr);
675 
676   if(p->name[0])
677     sprintf(st, "%s", p->name);
678   else
679     sprintf(st, "[No name]");
680   Listgame *lg = new Listgame(st, p); // the packet 'p' will be deleted by ~Listgame
681 
682   int deja = list_game->search(lg);
683   if(deja != -1) {
684     list_game->replace_item(deja, lg);
685     if(selected_game != -1)
686       if(list_game->get_selected() == lg)
687         refresh_player();
688   } else {
689     list_game->add_item(lg);
690   }
691 }
692 
lost_focus(int cancel)693 void Zone_input_address::lost_focus(int cancel) {
694   Zone_text_input::lost_focus(cancel);
695   if(!cancel && val[0] != 0) {
696     parent->refresh();
697   }
698 }
699 
Menu_multi_refresh(Menu_multi_join * p)700 Menu_multi_refresh::Menu_multi_refresh(Menu_multi_join *p): Menu(p->inter) {
701   parent = p;
702 }
703 
init()704 void Menu_multi_refresh::init() {
705   Menu::init();
706   parent->list_game->clear();
707   parent->clear_game_info();
708 
709   if(parent->address[0] != 0) {
710     resolve();
711     return;
712   }
713   if(parent->local_net)
714     find_local_games();
715   else
716     find_internet_games();
717 }
718 
find_local_games()719 void Menu_multi_refresh::find_local_games() {
720   Packet_findgame p;
721   Dword to;
722   parent->addwatch();
723   to = INADDR_BROADCAST;
724   net->sendudp(to, &p);
725   const char *error = net->failed();
726   if(error) {
727     call(new Menu_net_problem(error, "You can enter the TCP/IP address of "
728                               "the server instead.", parent->bit_,
729                               inter->font));
730   }
731   ret();
732 }
733 
resolve()734 void Menu_multi_refresh::resolve() {
735   Dword to = net->getaddress(parent->address);
736   if(to > 0) {
737     ret();
738     parent->join_game(NULL, to, net->port_resolve);
739   } else {
740     cancel = NULL;
741     call(new Wait_time(50)); // waits 1/2 second (in case the hosts resolves itself very quickly)
742   }
743 }
744 
find_internet_games()745 void Menu_multi_refresh::find_internet_games() {
746   exec(new Menu_multi_internet(parent));
747 }
748 
step()749 void Menu_multi_refresh::step() {
750   Menu::step();
751   if(!cancel) {
752     (void)new Zone_bitmap(inter, parent->bit_, 0, 0);
753     (void)new Zone_text(fteam[7], inter, "Looking for server name on "
754                         "Internet. This can take several minutes...", 130);
755     cancel = new Zone_text_button2(inter, parent->bit_, parent->font2_,
756                                    "�2 Cancel", 190);
757   }
758   if(net->name_resolve != (unsigned int)-1) {
759     Dword name_temp = net->name_resolve;
760     net->name_resolve = (Dword)-1;
761     if(name_temp == 0) {
762       (void)new Zone_text(fteam[7], inter, "Unable to locate host. Please verify and try again.", 220);
763     } else {
764       int port = net->port_resolve;
765       if(!port)
766         port = config.info.port_number; // default value
767       parent->join_game(NULL, name_temp, port);
768       ret();
769       return;
770     }
771   }
772   if(result == cancel || input->last_key.sym == SDLK_ESCAPE) {
773     net->gethostbyname_cancel();
774     input->last_key.sym = SDLK_UNKNOWN;
775     ret();
776   }
777 }
778 
Menu_multi_internet(Menu_multi_join * p)779 Menu_multi_internet::Menu_multi_internet(Menu_multi_join *p): Menu(p->inter) {
780   parent = p;
781   new Zone_bitmap(inter, parent->bit_, 0, 0);
782   new Zone_text(fteam[7], inter, "Searching for public Internet games...",
783                 130);
784   cancel = new Zone_text_button2(inter, parent->bit_, parent->font2_,
785                                  "�2 Cancel", 190);
786   request = NULL;
787 }
788 
~Menu_multi_internet()789 Menu_multi_internet::~Menu_multi_internet() {
790   if(request)
791     delete request;
792 }
793 
init()794 void Menu_multi_internet::init() {
795   Menu::init();
796   const char *msg;
797 
798   request = new Qserv();
799   request->add_data("getgames\n");
800   request->send();
801   msg = net->failed();
802   if(msg) {
803     exec(new Menu_net_problem(msg, "Either the server is down, or this "
804                               "address isn't a Quadra game server.",
805                               parent->bit_, inter->font));
806     delete request;
807     request = NULL;
808   }
809 }
810 
step()811 void Menu_multi_internet::step() {
812   Menu::step();
813   if(!request)
814     return;
815   bool done = request->done();
816   if(net->failed()) {
817     exec(new Menu_net_problem("No Quadra server found at specified address.",
818                               "Either the server is down, or this address "
819                               "isn't a Quadra game server.", parent->bit_,
820                               inter->font));
821     return;
822   }
823   if(done)
824     parsegames();
825   if(result == cancel || input->last_key.sym == SDLK_ESCAPE) {
826     input->last_key.sym = SDLK_UNKNOWN;
827     ret();
828   }
829 }
830 
parse_attack(const char * s)831 Attack Menu_multi_internet::parse_attack(const char *s) {
832   Attack ret;
833   if(s) {
834     ret.type = (Attack_type) atoi(s);
835     const char *sep=strchr(s, ' ');
836     if(sep)
837       ret.param=atoi(sep+1);
838   }
839   return ret;
840 }
841 
parsegames()842 void Menu_multi_internet::parsegames() {
843   ret();
844   if(!request->get_status() || strcmp(request->get_status(), "Current games"))
845     return;
846 
847   Dict *games=request->get_reply();
848   if(_debug) {
849     games->dump();
850   }
851   unsigned int i, j;
852   for(i = 0; i < games->size(); i++) {
853     const Dict *d = games->get_sub(i);
854     Packet_gameinfo *p=new Packet_gameinfo();
855 
856     p->from = NULL;
857 //    Word port=0;
858     char cip[32];
859     strcpy(cip, d->get_key());
860     char *cport=strchr(cip, ':');
861     if(cport) {
862 //      port=atoi(cport+1);
863       *cport=0; //Cut string at ':' separator
864     }
865     p->from_addr = Net::dotted2addr(cip);
866     const char *temp;
867     temp = d->find("name");
868     if(temp)
869       strcpy(p->name, temp);
870     temp = d->find("version");
871     if(temp)
872       p->version = atoi(temp);
873     temp = d->find("port");
874     if(temp)
875       p->port = atoi(temp);
876 
877     const Dict *players = d->find_sub("players");
878     if(players) {
879       for(j=0; j < players->size(); j++) {
880         const Dict *d2 = players->get_sub(j);
881         const char *name = d2->find("name");
882         temp = d2->find("team");
883         int team=0;
884         if(temp) {
885           team = atoi(temp);
886           if(team<0 || team>7)
887             team=0;
888         }
889         int status = -1;
890         temp = d2->find("status");
891         if(temp) {
892           status = atoi(temp);
893           if(status<0 || status>3)
894             status = -1;
895         }
896         int handicap=0;
897         temp = d2->find("handicap");
898         if(temp) {
899           handicap = atoi(temp);
900           if(handicap<0 || handicap>4)
901             handicap=0;
902         }
903         p->add_player(0, team, name, status, handicap);
904       }
905     }
906 
907     const Dict *end = d->find_sub("end");
908     if(end) {
909       temp = end->find("value");
910       if(temp)
911         p->game_end_value = atoi(temp);
912       temp = end->find("type");
913       if(temp)
914         p->game_end = atoi(temp);
915     }
916 
917     const Dict *rules = d->find_sub("rules");
918     if(rules) {
919       temp = rules->find("levelup");
920       if(temp)
921         p->nolevel_up = atoi(temp) ? false:true;
922       temp = rules->find("levelstart");
923       if(temp)
924         p->level_start = atoi(temp);
925       temp = rules->find("mincombo");
926       if(temp)
927         p->combo_min = atoi(temp);
928       temp = rules->find("allowhandicap");
929       if(temp)
930         p->allow_handicap = atoi(temp) ? true : false;
931       temp = rules->find("survivor");
932       if(temp)
933         p->survivor = atoi(temp) ? true : false;
934       temp = rules->find("hot_potato");
935       if(temp)
936         p->hot_potato = atoi(temp) ? true : false;
937       const Dict *attacks = rules->find_sub("attacks");
938       if(attacks) {
939         temp = attacks->find("normal");
940         p->normal_attack = parse_attack(temp);
941         temp = attacks->find("clean");
942         p->clean_attack = parse_attack(temp);
943         temp = attacks->find("potato_normal");
944         p->potato_normal_attack = parse_attack(temp);
945         temp = attacks->find("potato_clean");
946         p->potato_clean_attack = parse_attack(temp);
947       }
948     }
949 
950     const Dict *status = d->find_sub("status");
951     if(status) {
952       temp = status->find("started");
953       if(temp)
954         p->delay_start = atoi(temp) ? false:true;
955       temp = status->find("terminated");
956       if(temp)
957         p->terminated = atoi(temp) ? true:false;
958     }
959 
960     parent->net_call(p);
961   }
962 }
963 
Menu_single()964 Menu_single::Menu_single() {
965   {
966     Res_doze res("multi.png");
967     Png img(res);
968     bit = new Bitmap(img);
969     pal.load(img);
970   }
971 
972   pal.set_size(256); //Useless but whatever
973   set_fteam_color(pal);
974 
975   inter->set_font(new Font(*fonts.normal, pal, 255,255,255));
976   font2 = new Font(*fonts.normal, pal, 255,255,0);
977   (void)new Zone_bitmap(inter, bit, 0, 0, true);
978   (void)new Zone_text(inter, "Select game type:", 20);
979   normal = new Zone_text_button2(inter, bit, font2, "Normal", 180);
980   sprint = new Zone_text_button2(inter, bit, font2, "Sprint (5 minutes)", 220);
981   cancel = new Zone_text_button2(inter, bit, font2, "Back �0", 560, 450);
982 }
983 
step()984 void Menu_single::step() {
985   Menu_standard::step();
986   if(result == normal) {
987     call(new Fade_in(pal));
988     call(new Single_player(PRESET_SINGLE));
989     call(new Fade_out(pal));
990   }
991   if(result == sprint) {
992     call(new Fade_in(pal));
993     call(new Single_player(PRESET_SINGLE_SPRINT));
994     call(new Fade_out(pal));
995   }
996   if(result == cancel)
997     quit=true;
998 }
999 
~Menu_single()1000 Menu_single::~Menu_single() {
1001   delete font2;
1002 }
1003 
Menu_multi()1004 Menu_multi::Menu_multi() {
1005   {
1006     Res_doze res("multi.png");
1007     Png img(res);
1008     bit = new Bitmap(img);
1009     pal.load(img);
1010   }
1011 
1012   pal.set_size(256); //Useless but whatever
1013   set_fteam_color(pal);
1014 
1015   inter->set_font(new Font(*fonts.normal, pal, 255,255,255));
1016   font2 = new Font(*fonts.normal, pal, 255,255,0);
1017   (void)new Zone_bitmap(inter, bit, 0, 0, true);
1018   (void)new Zone_text(inter, "Please select a connection type:", 20);
1019   local = new Zone_text_button2(inter, bit, font2, "Local game (no network)",
1020                                 180);
1021   net_lan = new Zone_text_button2(inter, bit, font2, "TCP/IP Local "
1022                                   "network (LAN)", 220);
1023   net_internet = new Zone_text_button2(inter, bit, font2, "TCP/IP Internet",
1024                                        260);
1025   cancel = new Zone_text_button2(inter, bit, font2, "Back �0", 560, 450);
1026 }
1027 
step()1028 void Menu_multi::step() {
1029   Menu_standard::step();
1030   if(result == local) {
1031     call(new Create_game(bit, inter->font, font2, pal, false, false));
1032   }
1033   if(result == net_lan) {
1034     call(new Menu_multi_join(bit, inter->font, font2, pal, true));
1035   }
1036   if(result == net_internet) {
1037     call(new Menu_multi_join(bit, inter->font, font2, pal, false));
1038   }
1039   if(result == cancel)
1040     quit=true;
1041 }
1042 
~Menu_multi()1043 Menu_multi::~Menu_multi() {
1044   delete font2;
1045 }
1046 
Menu_setup()1047 Menu_setup::Menu_setup() {
1048   {
1049     Res_doze res("setup.png");
1050     Png img(res);
1051     bit = new Bitmap(img);
1052     pal.load(img);
1053   }
1054   inter->set_font(new Font(*fonts.normal, pal, 255,255,255));
1055   set_fteam_color(pal);
1056   (void)new Zone_bitmap(inter, bit, 0, 0, true);
1057 
1058   Zone_state_text2 *z_setup_player = new Zone_state_text2(inter, &config.info.setup_player, 333, 11);
1059   z_setup_player->add_string("1");
1060   z_setup_player->add_string("2");
1061   z_setup_player->add_string("3");
1062 
1063   z_nameinput = new Zone_text_input(inter, pal, config.player[config.info.setup_player].name, 40, 333, 106, 110, 100);
1064 
1065   z_passwdinput = new Zone_text_input(inter, pal, config.player2[config.info.setup_player].ngPasswd, 64, 333, 132, 200);
1066 
1067   z_shadow = new Zone_state_text2(inter, &config.player[config.info.setup_player].shadow, 333, 161);
1068   z_shadow->add_string("No");
1069   z_shadow->add_string("Yes");
1070 
1071   z_smooth = new Zone_state_text2(inter, &config.player[config.info.setup_player].smooth, 333, 192);
1072   z_smooth->add_string("No");
1073   z_smooth->add_string("Yes");
1074 
1075   z_h_repeat = new Zone_state_text(inter, &config.player2[config.info.setup_player].h_repeat, 333, 220);
1076   z_h_repeat->add_string("Slow");
1077   z_h_repeat->add_string("Normal");
1078   z_h_repeat->add_string("Fast");
1079   z_h_repeat->add_string("Faster");
1080 
1081   z_v_repeat = new Zone_state_text(inter, &config.player2[config.info.setup_player].v_repeat, 333, 252);
1082   z_v_repeat->add_string("Slow");
1083   z_v_repeat->add_string("Normal");
1084   z_v_repeat->add_string("Fast");
1085   z_v_repeat->add_string("Faster");
1086 
1087   z_continuousdown = new Zone_state_text(inter, &config.player2[config.info.setup_player].continuous, 333, 281);
1088   z_continuousdown->add_string("No");
1089   z_continuousdown->add_string("Yes");
1090 
1091   z_key[0] = new Zone_set_key(inter, &config.player[config.info.setup_player].key[0], 148, 347);
1092   z_key[1] = new Zone_set_key(inter, &config.player[config.info.setup_player].key[1], 148, 378);
1093   z_key[3] = new Zone_set_key(inter, &config.player[config.info.setup_player].key[3], 148, 408);
1094   z_key[6] = new Zone_set_key(inter, &config.player2[config.info.setup_player].key[1], 148, 439);
1095   z_key[4] = new Zone_set_key(inter, &config.player[config.info.setup_player].key[4], 513, 350);
1096   z_key[2] = new Zone_set_key(inter, &config.player[config.info.setup_player].key[2], 513, 380);
1097   z_key[5] = new Zone_set_key(inter, &config.player2[config.info.setup_player].key[0], 513, 411);
1098 
1099   b_player = new Zone_menu(inter, bit, "setup0.png", 195, 11);
1100   b_player->set_child(z_setup_player);
1101   (new Zone_menu(inter, bit, "setup1.png", 255, 101))->set_child(z_nameinput);
1102   (new Zone_menu(inter, bit, "setup2.png", 222, 132))->set_child(z_passwdinput);
1103   (new Zone_menu(inter, bit, "setup3.png", 237, 161))->set_child(z_shadow);
1104   (new Zone_menu(inter, bit, "setup4.png", 240, 192))->set_child(z_smooth);
1105   (new Zone_menu(inter, bit, "setup5.png", 157, 220))->set_child(z_h_repeat);
1106   (new Zone_menu(inter, bit, "setup6.png", 184, 252))->set_child(z_v_repeat);
1107   (new Zone_menu(inter, bit, "setup7.png", 153, 281))->set_child(z_continuousdown);
1108   b_key[0] = new Zone_menu(inter, bit, "setup8.png", 45, 347);
1109   b_key[1] = new Zone_menu(inter, bit, "setup9.png", 32, 378);
1110   b_key[3] = new Zone_menu(inter, bit, "setup10.png", 26, 408);
1111   b_key[6] = new Zone_menu(inter, bit, "setup11.png", 19, 439);
1112   b_key[4] = new Zone_menu(inter, bit, "setup12.png", 344, 350);
1113   b_key[2] = new Zone_menu(inter, bit, "setup13.png", 275, 380);
1114   b_key[5] = new Zone_menu(inter, bit, "setup14.png", 382, 411);
1115   b_all_key = new Zone_menu(inter, bit, "setup15.png", 390, 439);
1116 
1117   for(int i=0; i<7; i++)
1118     b_key[i]->set_child(z_key[i]);
1119 
1120   b_quit = new Zone_text_button2(inter, bit, fteam[4], "Back �0", 560, 450);
1121 }
1122 
~Menu_setup()1123 Menu_setup::~Menu_setup() {
1124   int i;
1125   for(i=0; i<3; i++)
1126     if(!config.player[i].name[0]) {
1127       char st[16];
1128       sprintf(st,"#%i", i+1);
1129       strcpy(config.player[i].name, st);
1130     }
1131   config.write();
1132 }
1133 
step()1134 void Menu_setup::step() {
1135   Menu_standard::step();
1136   if(!result) {
1137     return;
1138   }
1139 
1140   if(result == b_quit) {
1141     quit = true;
1142   }
1143   if(result == b_player) {
1144     z_nameinput->set_val(config.player[config.info.setup_player].name);
1145     z_passwdinput->set_val(config.player2[config.info.setup_player].ngPasswd);
1146     z_shadow->set_val(&config.player[config.info.setup_player].shadow);
1147     z_smooth->set_val(&config.player[config.info.setup_player].smooth);
1148     z_h_repeat->set_val(&config.player2[config.info.setup_player].h_repeat);
1149     z_v_repeat->set_val(&config.player2[config.info.setup_player].v_repeat);
1150     z_continuousdown->set_val(&config.player2[config.info.setup_player].continuous);
1151     for(int i=0; i<7; i++)
1152       if(i<5)
1153         z_key[i]->set_val(&config.player[config.info.setup_player].key[i]);
1154       else
1155         z_key[i]->set_val(&config.player2[config.info.setup_player].key[i-5]);
1156   }
1157   if(result == b_all_key) {
1158     call(new Menu_setup_all_key(inter, z_key));
1159   }
1160   for(int i=0; i<7; i++) {
1161     if(result==b_key[i]) {
1162       call(new Menu_setup_key(inter, (Zone_set_key *) z_key[i],
1163                               "Press a key..."));
1164     }
1165   }
1166 }
1167 
Menu_setup_all_key(Inter * in,Zone_set_key * k[])1168 Menu_setup_all_key::Menu_setup_all_key(Inter *in, Zone_set_key *k[]): Menu(in) {
1169   key = k;
1170   quel=0;
1171 }
1172 
step()1173 void Menu_setup_all_key::step() {
1174   const size_t touche[7] = {0, 1, 3, 4, 2, 5, 6};
1175   Menu::step();
1176   if(quel > 6 || input->keys[SDLK_ESCAPE] & PRESSED) {
1177     ret();
1178     return;
1179   }
1180   const char *te = NULL;
1181   switch(touche[quel]) {
1182     case 0: te = "Press a key for left..."; break;
1183     case 1: te = "Right..."; break;
1184     case 2: te = "Rotate counter clock-wise..."; break;
1185     case 3: te = "Down..."; break;
1186     case 4: te = "Rotate clock-wise..."; break;
1187     case 5: te = "Rotate twice..."; break;
1188     case 6: te = "Instant drop..."; break;
1189   }
1190   call(new Menu_setup_key(inter, key[touche[quel]], te));
1191   quel++;
1192 }
1193 
Menu_setup_key(Inter * in,Zone_set_key * k,const char * t)1194 Menu_setup_key::Menu_setup_key(Inter *in, Zone_set_key *k, const char *t): Menu(in) {
1195   new Zone_text_field(inter, t, 180, 315, 280);
1196   key = k;
1197 }
1198 
Menu_setup_key(Inter * in,Zone_set_key * k)1199 Menu_setup_key::Menu_setup_key(Inter *in, Zone_set_key *k): Menu(in) {
1200   key = k;
1201 }
1202 
init()1203 void Menu_setup_key::init() {
1204   input->clear_key();
1205 }
1206 
step()1207 void Menu_setup_key::step() {
1208   Menu::step();
1209   int loop = 0;
1210   for(int i = SDLK_FIRST; i < SDLK_LAST; ++i) {
1211     if(input->keys[i] & PRESSED) {
1212       loop = i;
1213       break;
1214     }
1215   }
1216   if(loop == 0) return;
1217 
1218 	input->last_key.sym = SDLK_UNKNOWN;
1219   // denies Enter (reserved for multiplayer chat)
1220 	if(loop == SDLK_RETURN) return;
1221 	if(loop != SDLK_ESCAPE)
1222 	{
1223 		*(key->val) = loop;
1224 		key->process();
1225 	}
1226 	ret();
1227 }
1228 
Menu_quitgame()1229 Menu_quitgame::Menu_quitgame() {
1230   int y;
1231   for(y=0; y<8; y++)
1232     pal.setcolor(y, y*255/7, y*255/7, y*255/7);
1233   pal.setcolor(255, 255, 255, 255);
1234   inter->set_font(new Font(*fonts.normal, pal, 255,255,255));
1235   for(y=8; y<16; y++)
1236     pal.setcolor(y, 0, 0, y*255/7);
1237   font2 = new Font(*fonts.normal, pal, 0,0,255);
1238 }
1239 
~Menu_quitgame()1240 Menu_quitgame::~Menu_quitgame() {
1241   delete font2;
1242 }
1243 
init()1244 void Menu_quitgame::init() {
1245   Menu_standard::init();
1246   (void)new Zone_clear(inter);
1247   (void)new Zone_text(inter, "Quadra", 0);
1248   (void)new Zone_text(inter, "You have been playing an unregistered "
1249                       "version of Quadra.", 10, 40);
1250   int t,h,m,s;
1251   t = overmind.framecount / 100;
1252   h = t / 60 / 60;
1253   t = t % 3600;
1254   m = t / 60;
1255   s = t % 60;
1256   if(h > 0) {
1257     sprintf(st, "In fact, you played for %i hours and %i minutes!", h, m);
1258   } else if(m > 0) {
1259     sprintf(st, "In fact, you played for %i minutes %i seconds.", m, s);
1260   } else {
1261     sprintf(st, "You spent about %i seconds checking it.", s);
1262   }
1263   (void)new Zone_text(inter, st, 10, 60);
1264   (void)new Zone_text(inter, "Was it enjoyable?  Was it incredibly fun?",
1265                       10, 80);
1266   (void)new Zone_text(inter, "Feel free to distribute Quadra to everyone "
1267                       "you want!", 10, 300);
1268 #ifdef UGS_DIRECTX
1269   (void)new Zone_text(inter, "We even got a Linux version, networkable "
1270                       "with yours!", 10, 360);
1271 #else
1272   (void)new Zone_text(inter, "We even got a Windows version, networkable "
1273                       "with yours!", 10, 360);
1274 #endif
1275   (void)new Zone_text(inter, "So watch out for Ludus Design products, "
1276                       "and remember:", 10, 380);
1277   (void)new Zone_text(font2, inter, "We do great stuff for you!", 20, 410);
1278 }
1279 
step()1280 void Menu_quitgame::step() {
1281   Menu_standard::step();
1282   if(!quit)
1283     call(new Wait_time(24000));
1284   quit=true;
1285 }
1286 
Menu_help()1287 Menu_help::Menu_help() {
1288   Bitmap *bit;
1289   {
1290     Res_doze res("multi.png");
1291     Png img(res);
1292     bit = new Bitmap(img);
1293     pal.load(img);
1294   }
1295   pal.set_size(256);
1296   set_fteam_color(pal);
1297 
1298   inter->set_font(new Font(*fonts.normal, pal, 255,255,255));
1299   font2 = fteam[4];
1300   (void)new Zone_bitmap(inter, bit, 0, 0, true);
1301   b_quit = new Zone_text_button2(inter, NULL, font2, "Back �0", 560, 450);
1302   int y;
1303   (void)new Zone_text(inter, "Thanks for downloading Quadra!", 20);
1304   y = 220;
1305   b_online=NULL;
1306 
1307   Zone_text *temp;
1308   (void)new Zone_text(fteam[3], inter, "The Quadra team:", y); y+=20;
1309   (void)new Zone_text(inter, "R�mi Veilleux: Programming, design, graphics", 10, y); y+=20;
1310   (void)new Zone_text(inter, "St�phane Lajoie: Programming", 10, y); y+=20;
1311   (void)new Zone_text(inter, "Pierre Phaneuf: Linux port", 10, y); y+=20;
1312   (void)new Zone_text(inter, "Sylvain Fortin: Glue", 10, y); y+=20;
1313   (void)new Zone_text(inter, "V�ronique Bruneau: Graphics", 10, y); y+=20;
1314   (void)new Zone_text(inter, "Our web site:", 10, y);
1315   b_www = temp = new Zone_text_select(inter, fteam[4],
1316                                       "http://quadra.sourceforge.net/",
1317                                       160, y);
1318   temp->set_font(fteam[6]);
1319 }
1320 
init()1321 void Menu_help::init() {
1322   Menu_standard::init();
1323   sons.levelup->play(0, 0, 11000);
1324 }
1325 
step()1326 void Menu_help::step() {
1327   Menu_standard::step();
1328   if(!result)
1329     return;
1330   if(result == b_quit)
1331     quit = true;
1332 #ifdef UGS_DIRECTX
1333   if(result == b_www)
1334     call_internet("http://quadra.sourceforge.net/");
1335   if(result == b_online)
1336     call_internet("http://www.ludusdesign.com/quadra/register.html");
1337 #endif
1338 }
1339 
call_internet(const char * s)1340 void Menu_help::call_internet(const char *s) {
1341   call(new Fade_in(pal));
1342   call(new Menu_internet(s));
1343   call(new Fade_to(Palette(), pal));
1344 }
1345 
Menu_option()1346 Menu_option::Menu_option() {
1347   {
1348     Res_doze res("multi.png");
1349     Png img(res);
1350     bit = new Bitmap(img);
1351     pal.load(img);
1352   }
1353   pal.set_size(256);
1354   set_fteam_color(pal);
1355 
1356   Palette ptemp;
1357   {
1358     Res_doze res("fond0.png");
1359     Png png(res);
1360     ptemp.load(png);
1361   }
1362   for(int i=184; i<256; i++) // copies the colors of the blocs from fond0.png
1363     pal.setcolor(i, ptemp.r(i), ptemp.g(i), ptemp.b(i));
1364   inter->set_font(new Font(*fonts.normal, pal, 255,255,255));
1365   set_fteam_color(pal);
1366   font2 = fteam[4];
1367   (void)new Zone_bitmap(inter, bit, 0, 0, true);
1368   (void)new Zone_text(inter, "Game options", 20);
1369   b_quit = new Zone_text_button2(inter, bit, font2, "Back �0", 560, 450);
1370 
1371   // FIXME: Configuration for the removed CD music player. Should be taken out.
1372   (void)new Zone_text(fteam[7], inter, "Select CD playing mode:", 40, 130);
1373   {
1374     Zone_state_text2 *temp =  new Zone_state_text2(inter,
1375                                                    &config.info.cdmusic,
1376                                                    380, 130);
1377     temp->add_string("No music");
1378     temp->add_string("Auto-change track");
1379     temp->add_string("Loop all tracks");
1380   }
1381 
1382   (void)new Zone_text(fteam[7], inter, "Mouse cursor speed (1-255):", 40, 160);
1383   (void)new Zone_input_numeric(inter, &config.info.mouse_speed, 4, 1, 255, pal, 380, 160, 60);
1384   old_port = config.info.port_number;
1385 
1386   (void)new Zone_text(inter, "Advanced options:", 40, 220);
1387 
1388   (void)new Zone_text(fteam[7], inter, "TCP/IP port number (1024-65535):",
1389                       40, 250);
1390   (void)new Zone_input_numeric(inter, &config.info.port_number, 6, 1024, 65535, pal, 380, 250, 60);
1391   (void)new Zone_text(fteam[3], inter, "(Note: you must have the same port "
1392                       "number to connect to another computer)", 40, 274);
1393 
1394   (void)new Zone_text(fteam[7], inter, "Public game server address:", 40, 310);
1395   (void)new Zone_text_input(inter, pal, config.info.game_server_address, 255, 380, 310, 240);
1396   char stbuf[512];
1397   snprintf(stbuf, sizeof(stbuf), "Default server: %s",
1398            config.info3.default_game_server_address);
1399   (void)new Zone_text(fteam[3], inter, stbuf, 40, 334);
1400   strcpy(old_server, config.info.game_server_address);
1401 
1402 	(void)new Zone_text(fteam[7], inter, "HTTP proxy server:", 40, 370);
1403 	(void)new Zone_text_input(inter, pal, config.info2.proxy_address, 127, 380, 370, 240);
1404 	strcpy(old_proxy, config.info2.proxy_address);
1405 }
1406 
~Menu_option()1407 Menu_option::~Menu_option() {
1408   config.write();
1409   if(strcmp(old_server, config.info.game_server_address) || strcmp(old_proxy, config.info2.proxy_address)) {
1410     Qserv::http_addr=0;
1411     Qserv::http_port=0;
1412   }
1413 }
1414 
step()1415 void Menu_option::step() {
1416   Menu_standard::step();
1417   if(result == b_quit)
1418     quit = true;
1419 }
1420 
Menu_intro()1421 Menu_intro::Menu_intro() {
1422   int y;
1423   for(y=0; y<8; y++)
1424     pal.setcolor(y, y*255/7, y*255/7, y*255/7);
1425   for(y=8; y<16; y++)
1426     pal.setcolor(y, 0, y*255/7, y*255/7);
1427   pal.setcolor(255, 255, 255, 255);
1428   inter->set_font(new Font(*fonts.normal, pal, 255,255,255));
1429   font2 = new Font(*fonts.normal, pal, 0,255,255);
1430   (void)new Zone_clear(inter);
1431   (void)new Zone_text(inter, "Quadra(tm) by Ludus Design", 10);
1432   (void)new Zone_text(inter, "Using Universal Game Skelton(tm)", 10, 40);
1433   (void)new Zone_text(font2, inter, "Free version released under the "
1434                       "GNU Lesser General Public License", 10, 80);
1435 
1436   y=130;
1437   warning=0;
1438   if(!sound) {
1439     (void)new Zone_text(inter, "Warning: Failed to initialise sound system",
1440                         10, y);
1441     warning++;
1442     y += 20;
1443   }
1444   if(config.warning == 1) {
1445     (void)new Zone_text(inter, "No configuration file found. Using defaults.", 10, y);
1446     y += 20;
1447   }
1448   if(config.warning == 2) {
1449     (void)new Zone_text(inter, "Warning: Wrong version in configuration "
1450                         "file. Using defaults.", 10, y);
1451     warning++;
1452     y += 20;
1453   }
1454   (void)new Zone_text(inter, "Hit something to continue...", 10, y);
1455 #ifdef ENABLE_VERSION_CHECK
1456   if(strcmp(VERSION_STRING, config.info3.latest_version) != 0)
1457   {
1458     (void)new Zone_text(font2, inter, "A new version of Quadra is available!",
1459                         10, y + 40);
1460     (void)new Zone_text(font2, inter, "Get it at http://quadra.googlecode.com",
1461                         10, y + 60);
1462   }
1463 #endif
1464   (void)new Zone_text(inter, "Quadra, Universal Game Skelton and the "
1465                       "Ludus Design logo are trademarks", 10, 430);
1466   (void)new Zone_text(inter, "of Ludus Design, Copyright (C) 1998-2000. "
1467                       "All rights reserved.", 10, 450);
1468   once = false;
1469 }
1470 
init()1471 void Menu_intro::init() {
1472   Menu::init();
1473   call(new Setpalette(pal));
1474 }
1475 
step()1476 void Menu_intro::step() {
1477   Menu::step();
1478   ret();
1479   call(new Menu_main());
1480   call(new Setpalette(noir));
1481   call(new Wait_time(3000));
1482 }
1483 
~Menu_intro()1484 Menu_intro::~Menu_intro() {
1485   delete font2;
1486 }
1487 
Menu_main()1488 Menu_main::Menu_main():
1489 	version_warning(false)
1490 {
1491   {
1492     Res_doze res("debuto.png");
1493     Png png(res);
1494     pal.load(png);
1495   }
1496   inter->set_font(new Font(*fonts.normal, pal, 255,255,255));
1497   redraw();
1498 }
1499 
redraw()1500 void Menu_main::redraw() {
1501   inter->flush();
1502   Bitmap *background;
1503   {
1504     Res_doze res("debuto.png");
1505     Png png(res);
1506     background = new Bitmap(png);
1507   }
1508   z_back = new Zone_bitmap(inter, background, 0, 0, true);
1509 
1510   b_help = NULL;
1511   b_single = new Zone_menu(inter, background, "debut0.png", 160, 99);
1512   b_multi = new Zone_menu(inter, background, "debut1.png", 166, 139);
1513   b_demo = new Zone_menu(inter, background, "debut2.png", 214, 183);
1514   b_tut = new Zone_menu(inter, background, "debut3.png", 235, 225);
1515   b_setup = new Zone_menu(inter, background, "debut4.png", 221, 267);
1516   b_option = new Zone_menu(inter, background, "debut5.png", 264, 310);
1517   b_help = new Zone_menu(inter, background, "debut6.png", 261, 351);
1518   b_quit = new Zone_menu(inter, background, "debut7.png", 295, 392);
1519 
1520   sprintf(st, "Quadra version %s", VERSION_STRING);
1521   new Zone_text(inter, st, 450, 430);
1522 
1523   b_logo = new Zone_menu(inter, background, "debut8.png", 0, 390);
1524 }
1525 
init()1526 void Menu_main::init() {
1527   Menu::init();
1528   // FIXME: The following line might not be necessary without the music.
1529   call(new Wait_time(6)); // to force the palette being set BEFORE the
1530                           // music starts
1531   call(new Setpalette(pal));
1532   reset_delay();
1533 }
1534 
reset_delay()1535 void Menu_main::reset_delay() {
1536 	delay = 12000;
1537 
1538 	if(!version_warning)
1539 	{
1540 		if(strcmp(VERSION_STRING, config.info3.latest_version) != 0)
1541 		{
1542 			(void)new Zone_text(inter, "New version available", 455, 445);
1543 			(void)new Zone_text(inter, "Get it at http://quadra.googlecode.com", 330, 460);
1544 			version_warning = true;
1545 		}
1546 	}
1547 }
1548 
step()1549 void Menu_main::step() {
1550   Menu::step();
1551   delay--;
1552   if(delay < 0) {
1553     call(new Fade_in(pal));
1554     if(1/*ugs_random.rnd(1) == 0*/) { // always pop a demo (highscore menu sucks)
1555       int i=ugs_random.rnd(3);
1556       char st[20];
1557       sprintf(st, "demo%02i.rec", i);
1558       call(new Call_setfont(pal, new Demo_multi_player(new Res_compress(st, RES_READ, true), true)));
1559     }
1560     else
1561       call(new Menu_highscore());
1562     call(new Fade_out(pal));
1563     reset_delay();
1564   }
1565   if(result == b_quit || input->last_key.sym == SDLK_ESCAPE || quitting) {
1566     input->last_key.sym = SDLK_UNKNOWN;
1567     exec(new Fade_out(pal));
1568   }
1569   if(result == b_tut) {
1570     call(new Fade_in(pal));
1571     call(new Menu_highscore(-1, NULL, true));
1572     call(new Fade_out(pal));
1573   }
1574 #ifdef UGS_DIRECTX
1575   if(result == b_logo) {
1576     call(new Fade_in(pal));
1577     call(new Menu_internet("http://quadra.sourceforge.net/"));
1578     call(new Fade_to(Palette(), pal));
1579   }
1580 #endif
1581   if(result == b_option) {
1582     call(new Fade_in(pal));
1583     call(new Menu_option());
1584     call(new Fade_out(pal));
1585   }
1586   if(result && result == b_help) {
1587     call(new Fade_in(pal));
1588     call(new Menu_help());
1589     call(new Fade_out(pal));
1590   }
1591   if(result == b_setup) {
1592     call(new Fade_in(pal));
1593     call(new Menu_setup());
1594     call(new Fade_out(pal));
1595   }
1596   if(result == b_multi) {
1597     call(new Fade_in(pal));
1598     call(new Menu_multi());
1599     call(new Fade_out(pal));
1600   }
1601   if(result == b_single) {
1602     //-roncli 4/29/01 This doesn't suck anymore. :-D
1603     call(new Fade_in(pal));
1604     call(new Menu_single());
1605     call(new Fade_out(pal));
1606 
1607   }
1608   if(result == b_demo) {
1609     call(new Fade_in(pal));
1610     call(new Menu_demo_central());
1611     call(new Fade_out(pal));
1612   }
1613 //  if(result && result==z_back) {
1614 //    Bulle::test(*z_back->actual);
1615 //    video->need_paint=2;
1616 //  }
1617   if(result)
1618     reset_delay();
1619 }
1620 
Colonne()1621 Menu_stat::Colonne::Colonne() {
1622   sort_me = false;
1623 }
1624 
set_titre(const char * s)1625 void Menu_stat::Colonne::set_titre(const char *s) {
1626   strcpy(titre, s);
1627 }
1628 
Menu_stat()1629 Menu_stat::Menu_stat():
1630 c_start(105), c_gap(4) {
1631   int i;
1632   {
1633     Res_doze res("result.png");
1634     Png raw(res);
1635     bit = new Bitmap(raw);
1636     pal.load(raw);
1637   }
1638   pal.set_size(256);
1639   Palette temp;
1640   {
1641     Res_doze res("fond0.png");
1642     Png png(res);
1643     temp.load(png);
1644   }
1645   for(i=184; i<256; i++) // copie les couleurs des blocs de l'image fond0.png
1646     pal.setcolor(i, temp.r(i), temp.g(i), temp.b(i));
1647 
1648   set_fteam_color(pal);
1649   inter->set_font(new Font(*fonts.normal, pal, 255,255,255));
1650   fcourrier[0] = new Font(*fonts.courrier, pal, 255,125,0);
1651   fcourrier[1] = new Font(*fonts.courrier, pal, 0,225,255);
1652   fcourrier[2] = new Font(*fonts.courrier, pal, 255,0,0);
1653   fcourrier[3] = new Font(*fonts.courrier, pal, 255,0,255);
1654   fcourrier[4] = new Font(*fonts.courrier, pal, 255,255,0);
1655   fcourrier[5] = new Font(*fonts.courrier, pal, 0,255,0);
1656   fcourrier[6] = new Font(*fonts.courrier, pal, 0,0,255);
1657   fcourrier[7] = new Font(*fonts.courrier, pal, 170,170,170);
1658   font2 = fteam[4];
1659   (void)new Zone_bitmap(inter, bit, 0, 0);
1660   b_quit = new Zone_text_button2(inter, bit, font2, "Quit �0", 340, 455);
1661   Zone_text_button *z;
1662   int x(8), wid(105);
1663   z=new Zone_text_button2(inter, bit, font2, "Rank", x, 80, wid-8);
1664   b_page.push_back(z);
1665   x+=wid;
1666   z=new Zone_text_button2(inter, bit, font2, "Speed", x, 80, wid-8);
1667   b_page.push_back(z);
1668   x+=wid;
1669   z=new Zone_text_button2(inter, bit, font2, "Lines", x, 80, wid-8);
1670   b_page.push_back(z);
1671   x+=wid;
1672   z=new Zone_text_button2(inter, bit, font2, "Combos", x, 80, wid-8);
1673   b_page.push_back(z);
1674   x+=wid;
1675 
1676   b_restart = b_stop = NULL;
1677 
1678   init_columns(bit);
1679 
1680   active_sort = -1;
1681   active_page = -1;
1682   change_page(0);
1683 
1684   notify();
1685   (void)new Chat_interface(inter, pal, bit->surface, 427, 47, 212, 410);
1686   if(game)
1687     game->net_list.add_watch(this);
1688 }
1689 
~Menu_stat()1690 Menu_stat::~Menu_stat() {
1691   while (!col.empty()) {
1692     delete col.back();
1693     col.pop_back();
1694   }
1695   if(game)
1696     game->net_list.remove_watch(this);
1697   for(int i=0; i<MAXTEAMS; i++)
1698     delete fcourrier[i];
1699   if(bit)
1700     delete bit;
1701 }
1702 
init_columns(Bitmap * bit)1703 void Menu_stat::init_columns(Bitmap *bit) {
1704   int i, page=0;
1705   Colonne *n;
1706   n=new Colonne();
1707   n->quel_stat = CS::FRAG;
1708   n->width = 70;
1709   n->set_titre("Frags");
1710   col.push_back(n);
1711 
1712   n=new Colonne();
1713   n->quel_stat = CS::DEATH;
1714   n->width = 70;
1715   n->set_titre("Deaths");
1716   col.push_back(n);
1717 
1718   n=new Colonne();
1719   n->quel_stat = CS::SCORE;
1720   n->width = 90;
1721   n->set_titre("Score");
1722   col.push_back(n);
1723 
1724   n=new Colonne();
1725   n->quel_stat = CS::LINESTOT;
1726   n->width = 90;
1727   n->set_titre("Lines");
1728   col.push_back(n);
1729 
1730   int px;
1731   px = c_start;
1732   for(i=0; i<4; i++) {
1733     add_title(*col[i], &px, bit);
1734     col[i]->page = page;
1735   }
1736 
1737   page++;
1738   px = c_start;
1739   n=new Colonne();
1740   n->quel_stat = CS::PPM;
1741   n->width = 150;
1742   n->set_titre("Points per min.");
1743   n->page = page;
1744   add_title(*n, &px, bit);
1745   col.push_back(n);
1746 
1747   n=new Colonne();
1748   n->quel_stat = CS::BPM;
1749   n->width = 150;
1750   n->set_titre("Blocks per min.");
1751   n->page = page;
1752   add_title(*n, &px, bit);
1753   col.push_back(n);
1754 
1755   page++;
1756   px = c_start;
1757   for(i=0; i<8; i++) {
1758     n=new Colonne();
1759     n->quel_stat = CS::clear_trans(i);
1760     n->width = 40;
1761     sprintf(st, "%i", i+1);
1762     n->set_titre(st);
1763     n->page = page;
1764     add_title(*n, &px, bit);
1765     col.push_back(n);
1766   }
1767 
1768   page++;
1769   px = c_start;
1770   for(i=8; i<16; i++) {
1771     n=new Colonne();
1772     n->quel_stat = CS::clear_trans(i);
1773     n->width = 40;
1774     sprintf(st, "%i", i+1);
1775     n->set_titre(st);
1776     n->page = page;
1777     add_title(*n, &px, bit);
1778     col.push_back(n);
1779   }
1780 
1781   page++;
1782   px = c_start;
1783   for(i=0; i<8; i++) {
1784     n=new Colonne();
1785     n->quel_stat = (CS::Stat_type) (CS::COMBO00+i);
1786     n->width = 40;
1787     sprintf(st, "%i", i+1);
1788     n->set_titre(st);
1789     n->page = page;
1790     add_title(*n, &px, bit);
1791     col.push_back(n);
1792   }
1793 
1794   page++;
1795   px = c_start;
1796   for(i=8; i<16; i++) {
1797     n=new Colonne();
1798     n->quel_stat = (CS::Stat_type) (CS::COMBO00+i);
1799     n->width = 40;
1800     sprintf(st, "%i", i+1);
1801     n->set_titre(st);
1802     n->page = page;
1803     add_title(*n, &px, bit);
1804     col.push_back(n);
1805   }
1806 }
1807 
add_title(Colonne & col,int * px,Bitmap * bit)1808 void Menu_stat::add_title(Colonne &col, int *px, Bitmap *bit) {
1809   col.z_titre = new Zone_text_button2(inter, bit, font2, col.titre, *px+3, 120, col.width-6);
1810   col.z_titre->disable();
1811   *px += col.width;
1812 }
1813 
set_sort(int quel)1814 void Menu_stat::set_sort(int quel) {
1815   if(active_sort == quel)
1816     return;
1817   col[quel]->sort_me = true;
1818   col[quel]->z_titre->set_font(fteam[4]);
1819 
1820   if(active_sort != -1) {
1821     col[active_sort]->sort_me = false;
1822     col[active_sort]->z_titre->set_font(inter->font);
1823   }
1824   active_sort = quel;
1825 }
1826 
change_page(int p)1827 void Menu_stat::change_page(int p) {
1828   int i, last_page=0;
1829   for (i=0; i< static_cast<int>(col.size()); ++i) {
1830     if(col[i]->page == active_page) {
1831       col[i]->z_titre->disable();
1832     }
1833     if(col[i]->page>last_page)
1834       last_page = col[i]->page;
1835   }
1836   switch(active_page) {
1837     case 0:
1838     case 1:
1839       b_page[active_page]->set_font(inter->font);
1840       break;
1841     case 2:
1842     case 3:
1843       b_page[2]->set_font(inter->font);
1844       break;
1845     case 4:
1846     case 5:
1847       b_page[3]->set_font(inter->font);
1848       break;
1849   }
1850   switch(p) {
1851     case 0:
1852       active_page=0;
1853       b_page[0]->set_font(fteam[4]);
1854       break;
1855     case 1:
1856       active_page=1;
1857       b_page[1]->set_font(fteam[4]);
1858       break;
1859     case 2:
1860       if(active_page==2)
1861         active_page=3;
1862       else
1863         active_page=2;
1864       b_page[2]->set_font(fteam[4]);
1865       break;
1866     case 3:
1867       if(active_page==4)
1868         active_page=5;
1869       else
1870         active_page=4;
1871       b_page[3]->set_font(fteam[4]);
1872       break;
1873   }
1874   if (active_page > last_page)
1875     active_page = 0;
1876   for (i = 0; i < static_cast<int>(col.size()); ++i)
1877     if (col[i]->page == active_page)
1878       col[i]->z_titre->enable();
1879   notify();
1880 }
1881 
calculate_total(bool force_blit)1882 void Menu_stat::calculate_total(bool force_blit) {
1883   if(!(overmind.framecount&127) || force_blit) {
1884     bool must_reblit = false;
1885     score.updateFromGame();
1886     if(score.team_order_changed || score.order_changed)
1887       must_reblit = true;
1888     if(active_sort!=-1)
1889       score.sort(col[active_sort]->quel_stat);
1890     if(score.team_order_changed || score.order_changed)
1891       must_reblit = true;
1892     if(must_reblit || force_blit)
1893       display();
1894   }
1895 }
1896 
display()1897 void Menu_stat::display() {
1898   list.deleteall();
1899   int y = 145;
1900   for(int loo=0; loo<MAXTEAMS; loo++) {
1901     int team = score.team_order[loo];
1902     for(int loo2=0; loo2<MAXPLAYERS; loo2++) {
1903       int i=score.order[loo2];
1904       if(score.player_team[i]==team) {
1905         Canvas *c = game->net_list.get(i);
1906         if(c && c->color == team) {
1907           list.zones.push_back(new Zone_text(fteam[team], inter, c->long_name(), 2, y));
1908 
1909           Font *color = fcourrier[team];
1910 
1911           int px = c_start;
1912           for(int j = 0; j < static_cast<int>(col.size()); ++j)
1913             if(col[j]->page == active_page) {
1914               list.zones.push_back(new Zone_text_numeric(color, inter, score.stats[i].stats[col[j]->quel_stat].get_address(), px, y, col[j]->width-c_gap));
1915               px += col[j]->width;
1916             }
1917           y += 22;
1918         }
1919       }
1920     }
1921     if(score.player_count[team] > 1) {
1922       list.zones.push_back(new Zone_text(fteam[team], inter, "Total:", 15, y));
1923       int px = c_start;
1924       Font *color = fcourrier[team];
1925       for (int j = 0; j < static_cast<int>(col.size()); ++j)
1926         if (col[j]->page == active_page) {
1927           list.zones.push_back(new Zone_text_numeric(color, inter, score.team_stats[team].stats[col[j]->quel_stat].get_address(), px, y, col[j]->width-c_gap));
1928           px += col[j]->width;
1929         }
1930       y += 34;
1931     } else if(score.player_count[team] == 1) {
1932       y += 12; // leave space between the players/totals of each team
1933     }
1934   }
1935   video->need_paint = 2;
1936 }
1937 
notify()1938 void Menu_stat::notify() {
1939   calculate_total(true);
1940 }
1941 
init()1942 void Menu_stat::init() {
1943   set_fteam_color(pal);
1944   set_sort(0);
1945   Menu_standard::init();
1946 }
1947 
step()1948 void Menu_stat::step() {
1949   Menu_standard::step();
1950   bool force_blit=false;
1951   //Add appropriate button(s)
1952   if(game->server && game->network && !game->terminated && !b_stop)
1953     b_stop = new Zone_text_button2(inter, bit, font2, "�2 End game", 8, 455);
1954   //Remove end-of-game button if already terminated
1955   if(b_stop && game->terminated) {
1956     delete b_stop;
1957     b_stop = NULL;
1958 		// delete the rejoin button when deleting the stop button; it may
1959 		//   be recreated right after but at least it will be in the correct place
1960 		delete b_restart;
1961 		b_restart = NULL;
1962     video->need_paint = 2;
1963   }
1964   if(net->active && !game->server && !net->connected()) {
1965     delete b_restart;
1966     b_restart=NULL;
1967   }
1968   if(!playback && !b_restart) {
1969     if(game->server)
1970 			if(game->terminated)
1971 				b_restart = new Zone_text_button2(inter, bit, font2,
1972                                           "�2 Restart game", 8, 455);
1973 			else
1974 				b_restart = new Zone_text_button2(inter, bit, font2,
1975                                           "�2 Rejoin game",
1976                                           8+(b_stop? b_stop->w+4:0), 455);
1977     else
1978       if(net->active && net->connected())
1979         b_restart = new Zone_text_button2(inter, bit, font2,
1980                                           "�2 Rejoin game", 8, 455);
1981   }
1982   if(result) {
1983     if(result == b_quit)
1984       quit = true;
1985     if(result == b_stop) {
1986       if(!game->terminated)
1987         game->net_list.send_end_signal(false);
1988     }
1989     if(result == b_restart) {
1990       if(game->server) {
1991 				if(game->terminated) {
1992 					game->stop_stuff();
1993 					game->restart();
1994 				}
1995 				else
1996 					game->abort = false;
1997         exec(new Call_setfont(pal, new Multi_player_launcher()));
1998       }
1999       else {
2000         //We're not server but we want to restart, drop all players
2001         int i;
2002         for(i=0; i<MAXPLAYERS; i++) {
2003           if(game->net_list.get(i)) {
2004             Packet_dropplayer p;
2005             p.player=i;
2006             p.reason=DROP_AUTO;
2007             game->net_list.drop_player(&p, false);
2008           }
2009         }
2010         //... and delete the game
2011         delete game;
2012         exec(new Join_game(bit, inter->font, font2, pal, NULL, 0, 0, true));
2013       }
2014     }
2015     for (int i = 0; i < static_cast<int>(col.size()); ++i) {
2016       if (result == col[i]->z_titre) {
2017         set_sort(i);
2018         force_blit = true;
2019         break;
2020       }
2021     }
2022     for (unsigned int i = 0; i < b_page.size(); ++i)
2023       if (result == b_page[i])
2024         change_page(i);
2025   }
2026   calculate_total(force_blit);
2027 }
2028 
Menu_multi_checkip(Bitmap * bit,Font * font,Font * font2,const Palette & p)2029 Menu_multi_checkip::Menu_multi_checkip(Bitmap *bit, Font *font, Font *font2, const Palette& p) {
2030   pal = p;
2031   bit_ = bit;
2032   inter->set_font(font, false);
2033   new Zone_bitmap(inter, bit, 0, 0);
2034   new Zone_text(inter, "IP configuration of this computer", 20);
2035   cancel = new Zone_text_button2(inter, bit, font2, "Back �0", 560, 450);
2036   new Zone_text(inter, "Host name:", 170, 110);
2037   new Zone_text_field(inter, net->host_name, 310, 110, inter->font->width(net->host_name)+8);
2038   new Zone_text(inter, "IP address:", 170, 140);
2039   Zone_listbox *list;
2040   list = new Zone_listbox2(inter, bit, font2, NULL, 310, 140, 160, 200);
2041 	vector<Dword>::const_iterator it;
2042   for (it = net->host_adr.begin(); it != net->host_adr.end(); ++it) {
2043     Net::stringaddress(st, *it);
2044     list->add_item(st);
2045   }
2046 }
2047 
step()2048 void Menu_multi_checkip::step() {
2049   Menu::step();
2050   if(input->last_key.sym == SDLK_ESCAPE || result == cancel) {
2051     input->last_key.sym = SDLK_UNKNOWN;
2052     ret();
2053   }
2054 }
2055 
Menu_multi_book(Bitmap * bit,Font * font,Font * font2,const Palette & p,const char * adr)2056 Menu_multi_book::Menu_multi_book(Bitmap *bit, Font *font, Font *font2, const Palette& p, const char *adr) {
2057   pal = p;
2058   bit_ = bit;
2059   font2_ = font2;
2060   inter->set_font(font, false);
2061   address = adr;
2062   new Zone_bitmap(inter, bit, 0, 0);
2063   cancel = new Zone_text_button2(inter, bit, font2, "Back �0", 560, 450);
2064   if(address) { // if connecting address already provided
2065     new Zone_text(inter, "Connect", 20);
2066   } else {
2067     new Zone_text(inter, "Address book", 20);
2068     for(int i=0; i<10; i++) {
2069       int y = 60 + i*36;
2070       new Zone_text_input(inter, pal, config.info.book[i], 255, 40, y, 460);
2071       b_connect[i] = new Zone_text_button2(inter, bit, font2, "Connect", 520, y);
2072     }
2073   }
2074   status = new Zone_text_field(inter, "", 6, 450, 540);
2075   looking = false;
2076   connect_failed = false;
2077 }
2078 
init()2079 void Menu_multi_book::init() {
2080   Menu::init();
2081   if(address)
2082     call(new Fade_in(pal));
2083 }
2084 
step()2085 void Menu_multi_book::step() {
2086   Menu::step();
2087   if(input->last_key.sym == SDLK_ESCAPE || result == cancel) {
2088     input->last_key.sym = SDLK_UNKNOWN;
2089     if(looking)
2090       net->gethostbyname_cancel();
2091     config.write();
2092     ret();
2093   }
2094   const char *connect_adr=NULL;
2095 
2096   if(address) {
2097     if(!looking && !connect_failed) {
2098       connect_adr = address;
2099     }
2100   } else {
2101     for(int i=0; i<10; i++) {
2102       if(result == b_connect[i] && config.info.book[i][0] != 0) {
2103         connect_adr = config.info.book[i];
2104         break;
2105       }
2106     }
2107   }
2108   if(connect_adr) {
2109     if(looking)
2110       net->gethostbyname_cancel();
2111     Dword adr = net->getaddress(connect_adr);
2112     if(adr > 0) {
2113       call(new Join_game(bit_, inter->font, font2_, pal, NULL, adr, net->port_resolve, false));
2114       if(address)
2115         ret();
2116     } else {
2117       sprintf(st, "Looking for %s...", connect_adr);
2118       status->set_val(st);
2119       looking = true;
2120     }
2121   }
2122   if(looking) {
2123     if(net->name_resolve != (unsigned int)-1) {
2124       if(net->name_resolve == 0) {
2125         status->set_val("Unable to locate host. Please verify and try again.");
2126         looking = false;
2127         connect_failed = true;
2128       } else {
2129         status->set_val("");
2130         looking = false;
2131         call(new Join_game(bit_, inter->font, font2_, pal, NULL, net->name_resolve, net->port_resolve, false));
2132         if(address)
2133           ret();
2134       }
2135       net->name_resolve = (Dword)-1;
2136     }
2137   }
2138 }
2139 
Menu_internet(const char * c)2140 Menu_internet::Menu_internet(const char *c): Menu() {
2141   command = c;
2142   new Zone_clear(inter);
2143 }
2144 
init()2145 void Menu_internet::init() {
2146   Menu::init();
2147 }
2148 
step()2149 void Menu_internet::step() {
2150   Menu::step();
2151 #ifdef UGS_DIRECTX
2152   ShellExecute(0, "open", command, NULL, NULL, SW_SHOWDEFAULT);
2153 #endif
2154   call(new Wait_time(200));
2155   ret();
2156 }
2157 
Menu_startserver()2158 Menu_startserver::Menu_startserver() {
2159   {
2160     Res_doze res("multi.png");
2161     Png img(res);
2162     bit = new Bitmap(img);
2163     pal.load(img);
2164   }
2165   set_fteam_color(pal);
2166 
2167   inter->set_font(new Font(*fonts.normal, pal, 255,255,255));
2168   (void)new Zone_clear(inter);
2169 }
2170 
step()2171 void Menu_startserver::step() {
2172   exec(new Create_game_start(pal, bit, inter->font));
2173 }
2174 
~Menu_startserver()2175 Menu_startserver::~Menu_startserver() {
2176   delete bit;
2177 }
2178 
Menu_startconnect(const char * adr,bool rejoin)2179 Menu_startconnect::Menu_startconnect(const char *adr, bool rejoin) {
2180   {
2181     Res_doze res("multi.png");
2182     Png img(res);
2183     bit = new Bitmap(img);
2184     pal.load(img);
2185   }
2186   set_fteam_color(pal);
2187 
2188   inter->set_font(new Font(*fonts.normal, pal, 255,255,255));
2189   font2 = new Font(*fonts.normal, pal, 255,255,0);
2190   (void)new Zone_clear(inter);
2191   if(rejoin)
2192     module = new Join_game(bit, inter->font, font2, pal, NULL, 0, 0, true);
2193   else
2194     module = new Menu_multi_book(bit, inter->font, font2, pal, adr);
2195 }
2196 
step()2197 void Menu_startconnect::step() {
2198   call(new Fade_out(pal));
2199   exec(module);
2200 }
2201 
~Menu_startconnect()2202 Menu_startconnect::~Menu_startconnect() {
2203   if(bit)
2204     delete bit;
2205   delete font2;
2206 }
2207