1 /*
2  *  Abuse - dark 2D side-scrolling platform game
3  *  Copyright (c) 1995 Crack dot Com
4  *  Copyright (c) 2005-2011 Sam Hocevar <sam@hocevar.net>
5  *
6  *  This software was released into the Public Domain. As with most public
7  *  domain software, no warranty is made or implied by Crack dot Com, by
8  *  Jonathan Clark, or by Sam Hocevar.
9  */
10 
11 #if defined HAVE_CONFIG_H
12 #   include "config.h"
13 #endif
14 
15 #include "common.h"
16 
17 #include "game.h"
18 
19 #include "demo.h"
20 #include "specs.h"
21 #include "jwindow.h"
22 #include "dprint.h"
23 #include "dev.h"
24 #include "jrand.h"
25 #include "lisp.h"
26 #include "clisp.h"
27 #include "netface.h"
28 
29 
30 demo_manager demo_man;
31 int last_demo_mx,last_demo_my,last_demo_mbut;
32 extern base_memory_struct *base;   // points to shm_addr
33 extern int idle_ticks;
34 
35 extern void net_receive();
36 extern void net_send(int force);
37 extern void fade_in(image *im, int steps);
38 extern void fade_out(int steps);
39 
get_event(event & ev)40 void get_event(event &ev)
41 { wm->get_event(ev);
42   switch (ev.type)
43   {
44     case EV_KEY :
45     {
46       if (demo_man.state==demo_manager::PLAYING)
47         demo_man.set_state(demo_manager::NORMAL);
48       else if (ev.key==JK_ENTER && demo_man.state==demo_manager::RECORDING)
49       {
50         demo_man.set_state(demo_manager::NORMAL);
51     the_game->show_help("Finished recording");
52       }
53     } break;
54   }
55 
56   last_demo_mx=ev.mouse_move.x;
57   last_demo_my=ev.mouse_move.y;
58   last_demo_mbut=ev.mouse_button;
59   idle_ticks=0;
60 }
61 
event_waiting()62 int event_waiting()
63 { return wm->event_waiting(); }
64 
65 
start_recording(char * filename)66 int demo_manager::start_recording(char *filename)
67 {
68   if (!current_level) return 0;
69 
70   record_file=open_file(filename,"wb");
71   if (record_file->open_failure()) { delete record_file; return 0; }
72 
73   char name[100];
74   strcpy(name,current_level->name());
75 
76   the_game->load_level(name);
77   record_file->write((void *)"DEMO,VERSION:2",14);
78   record_file->write_uint8(strlen(name)+1);
79   record_file->write(name,strlen(name)+1);
80 
81 
82   if (DEFINEDP(symbol_value(l_difficulty)))
83   {
84     if (symbol_value(l_difficulty)==l_easy) record_file->write_uint8(0);
85     else if (symbol_value(l_difficulty)==l_medium) record_file->write_uint8(1);
86     else if (symbol_value(l_difficulty)==l_hard) record_file->write_uint8(2);
87     else record_file->write_uint8(3);
88   } else record_file->write_uint8(3);
89 
90 
91   state=RECORDING;
92 
93   reset_game();
94 
95   return 1;
96 }
97 
do_inputs()98 void demo_manager::do_inputs()
99 {
100   switch (state)
101   {
102     case RECORDING :
103     {
104       base->packet.packet_reset();       // reset input buffer
105       view *p=player_list;               // get current inputs
106       for (; p; p=p->next)
107         if (p->local_player())
108           p->get_input();
109 
110       base->packet.write_uint8(SCMD_SYNC);
111       base->packet.write_uint16(make_sync());
112       demo_man.save_packet(base->packet.packet_data(),base->packet.packet_size());
113       process_packet_commands(base->packet.packet_data(),base->packet.packet_size());
114 
115     } break;
116     case PLAYING :
117     {
118       uint8_t buf[1500];
119       int size;
120       if (get_packet(buf,size))              // get starting inputs
121       {
122         process_packet_commands(buf,size);
123     int32_t mx,my;
124     the_game->game_to_mouse(player_list->pointer_x,player_list->pointer_y,player_list,mx,my);
125     wm->set_mouse_position(small_render ? mx*2 : mx, small_render ? my*2 : my);
126       }
127       else
128       {
129     set_state(NORMAL);
130     return ;
131       }
132     } break;
133     default :
134       break;
135   }
136 }
137 
reset_game()138 void demo_manager::reset_game()
139 {
140   if (dev&EDIT_MODE) toggle_edit_mode();
141   the_game->set_state(RUN_STATE);
142   rand_on=0;
143 
144   view *v=player_list;
145   for (; v; v=v->next) { if (v->focus) v->reset_player(); }
146 
147   last_demo_mx=last_demo_my=last_demo_mbut=0;
148   current_level->set_tick_counter(0);
149 
150 }
151 
start_playing(char * filename)152 int demo_manager::start_playing(char *filename)
153 {
154   uint8_t sig[15];
155   record_file=open_file(filename,"rb");
156   if (record_file->open_failure()) { delete record_file; return 0; }
157   char name[100],nsize,diff;
158   if (record_file->read(sig,14)!=14        ||
159       memcmp(sig,"DEMO,VERSION:2",14)!=0   ||
160       record_file->read(&nsize,1)!=1       ||
161       record_file->read(name,nsize)!=nsize ||
162       record_file->read(&diff,1)!=1)
163   { delete record_file; return 0; }
164 
165   char tname[100],*c;
166   strcpy(tname,name);
167   c=tname;
168   while (*c) { if (*c=='\\') *c='/'; c++; }
169 
170   bFILE *probe=open_file(tname,"rb");   // see if the level still exsist?
171   if (probe->open_failure()) { delete record_file; delete probe; return 0; }
172   delete probe;
173 
174   the_game->load_level(tname);
175   initial_difficulty = l_difficulty;
176 
177   switch (diff)
178   {
179     case 0: l_difficulty->SetValue(l_easy); break;
180     case 1: l_difficulty->SetValue(l_medium); break;
181     case 2: l_difficulty->SetValue(l_hard); break;
182     case 3: l_difficulty->SetValue(l_extreme); break;
183   }
184 
185   state=PLAYING;
186   reset_game();
187 
188 
189 
190   return 1;
191 }
192 
set_state(demo_state new_state,char * filename)193 int demo_manager::set_state(demo_state new_state, char *filename)
194 {
195   if (new_state==state) return 1;
196 
197   switch (state)
198   {
199     case RECORDING :
200     { delete record_file; } break;
201     case PLAYING :
202     {
203 /*
204       fade_in(cache.img(cache.reg("art/help.spe","sell6",SPEC_IMAGE,1)),8);
205       Timer now; now.WaitMs(2000);
206       fade_out(8);
207 */
208       delete record_file;
209       l_difficulty = initial_difficulty;
210       the_game->set_state(MENU_STATE);
211       wm->push_event(new event(ID_NULL,NULL));
212 
213       view *v=player_list;
214       for (; v; v=v->next)  // reset all the players
215       { if (v->focus) { v->reset_player(); v->focus->set_aistate(0); } }
216       delete current_level;
217       current_level=NULL;
218       the_game->reset_keymap();
219       base->input_state=INPUT_PROCESSING;
220 
221 
222     } break;
223     default :
224       break;
225   }
226 
227   switch (new_state)
228   {
229     case RECORDING :
230     { return start_recording(filename); } break;
231     case PLAYING :
232     { return start_playing(filename); } break;
233     case NORMAL :
234     { state=NORMAL; } break;
235   }
236 
237   return 1;
238 }
239 
save_packet(void * packet,int packet_size)240 int demo_manager::save_packet(void *packet, int packet_size)   // returns non 0 if actually saved
241 {
242   if (state==RECORDING)
243   {
244     uint16_t ps=lstl(packet_size);
245     if (record_file->write(&ps,2)!=2 ||
246     record_file->write(packet,packet_size)!=packet_size)
247     {
248       set_state(NORMAL);
249       return 0;
250     }
251     return 1;
252   } else return 0;
253 }
254 
get_packet(void * packet,int & packet_size)255 int demo_manager::get_packet(void *packet, int &packet_size)   // returns non 0 if actually loaded
256 {
257   if (state==PLAYING)
258   {
259     uint16_t ps;
260     if (record_file->read(&ps,2)!=2)
261     {
262       set_state(NORMAL);
263       return 0;
264     }
265     ps=lstl(ps);
266 
267     if (record_file->read(packet,ps)!=ps)
268     {
269       set_state(NORMAL);
270       return 0;
271     }
272 
273     packet_size=ps;
274     return 1;
275   }
276   return 0;
277 }
278 
279