/* * Abuse - dark 2D side-scrolling platform game * Copyright (c) 1995 Crack dot Com * Copyright (c) 2005-2011 Sam Hocevar <sam@hocevar.net> * * This software was released into the Public Domain. As with most public * domain software, no warranty is made or implied by Crack dot Com, by * Jonathan Clark, or by Sam Hocevar. */ #if defined HAVE_CONFIG_H # include "config.h" #endif #include "common.h" #include "game.h" #include "demo.h" #include "specs.h" #include "jwindow.h" #include "dprint.h" #include "dev.h" #include "jrand.h" #include "lisp.h" #include "clisp.h" #include "netface.h" demo_manager demo_man; int last_demo_mx,last_demo_my,last_demo_mbut; extern base_memory_struct *base; // points to shm_addr extern int idle_ticks; extern void net_receive(); extern void net_send(int force); extern void fade_in(image *im, int steps); extern void fade_out(int steps); void get_event(event &ev) { wm->get_event(ev); switch (ev.type) { case EV_KEY : { if (demo_man.state==demo_manager::PLAYING) demo_man.set_state(demo_manager::NORMAL); else if (ev.key==JK_ENTER && demo_man.state==demo_manager::RECORDING) { demo_man.set_state(demo_manager::NORMAL); the_game->show_help("Finished recording"); } } break; } last_demo_mx=ev.mouse_move.x; last_demo_my=ev.mouse_move.y; last_demo_mbut=ev.mouse_button; idle_ticks=0; } int event_waiting() { return wm->event_waiting(); } int demo_manager::start_recording(char *filename) { if (!current_level) return 0; record_file=open_file(filename,"wb"); if (record_file->open_failure()) { delete record_file; return 0; } char name[100]; strcpy(name,current_level->name()); the_game->load_level(name); record_file->write((void *)"DEMO,VERSION:2",14); record_file->write_uint8(strlen(name)+1); record_file->write(name,strlen(name)+1); if (DEFINEDP(symbol_value(l_difficulty))) { if (symbol_value(l_difficulty)==l_easy) record_file->write_uint8(0); else if (symbol_value(l_difficulty)==l_medium) record_file->write_uint8(1); else if (symbol_value(l_difficulty)==l_hard) record_file->write_uint8(2); else record_file->write_uint8(3); } else record_file->write_uint8(3); state=RECORDING; reset_game(); return 1; } void demo_manager::do_inputs() { switch (state) { case RECORDING : { base->packet.packet_reset(); // reset input buffer view *p=player_list; // get current inputs for (; p; p=p->next) if (p->local_player()) p->get_input(); base->packet.write_uint8(SCMD_SYNC); base->packet.write_uint16(make_sync()); demo_man.save_packet(base->packet.packet_data(),base->packet.packet_size()); process_packet_commands(base->packet.packet_data(),base->packet.packet_size()); } break; case PLAYING : { uint8_t buf[1500]; int size; if (get_packet(buf,size)) // get starting inputs { process_packet_commands(buf,size); int32_t mx,my; the_game->game_to_mouse(player_list->pointer_x,player_list->pointer_y,player_list,mx,my); wm->set_mouse_position(small_render ? mx*2 : mx, small_render ? my*2 : my); } else { set_state(NORMAL); return ; } } break; default : break; } } void demo_manager::reset_game() { if (dev&EDIT_MODE) toggle_edit_mode(); the_game->set_state(RUN_STATE); rand_on=0; view *v=player_list; for (; v; v=v->next) { if (v->focus) v->reset_player(); } last_demo_mx=last_demo_my=last_demo_mbut=0; current_level->set_tick_counter(0); } int demo_manager::start_playing(char *filename) { uint8_t sig[15]; record_file=open_file(filename,"rb"); if (record_file->open_failure()) { delete record_file; return 0; } char name[100],nsize,diff; if (record_file->read(sig,14)!=14 || memcmp(sig,"DEMO,VERSION:2",14)!=0 || record_file->read(&nsize,1)!=1 || record_file->read(name,nsize)!=nsize || record_file->read(&diff,1)!=1) { delete record_file; return 0; } char tname[100],*c; strcpy(tname,name); c=tname; while (*c) { if (*c=='\\') *c='/'; c++; } bFILE *probe=open_file(tname,"rb"); // see if the level still exsist? if (probe->open_failure()) { delete record_file; delete probe; return 0; } delete probe; the_game->load_level(tname); initial_difficulty = l_difficulty; switch (diff) { case 0: l_difficulty->SetValue(l_easy); break; case 1: l_difficulty->SetValue(l_medium); break; case 2: l_difficulty->SetValue(l_hard); break; case 3: l_difficulty->SetValue(l_extreme); break; } state=PLAYING; reset_game(); return 1; } int demo_manager::set_state(demo_state new_state, char *filename) { if (new_state==state) return 1; switch (state) { case RECORDING : { delete record_file; } break; case PLAYING : { /* fade_in(cache.img(cache.reg("art/help.spe","sell6",SPEC_IMAGE,1)),8); Timer now; now.WaitMs(2000); fade_out(8); */ delete record_file; l_difficulty = initial_difficulty; the_game->set_state(MENU_STATE); wm->push_event(new event(ID_NULL,NULL)); view *v=player_list; for (; v; v=v->next) // reset all the players { if (v->focus) { v->reset_player(); v->focus->set_aistate(0); } } delete current_level; current_level=NULL; the_game->reset_keymap(); base->input_state=INPUT_PROCESSING; } break; default : break; } switch (new_state) { case RECORDING : { return start_recording(filename); } break; case PLAYING : { return start_playing(filename); } break; case NORMAL : { state=NORMAL; } break; } return 1; } int demo_manager::save_packet(void *packet, int packet_size) // returns non 0 if actually saved { if (state==RECORDING) { uint16_t ps=lstl(packet_size); if (record_file->write(&ps,2)!=2 || record_file->write(packet,packet_size)!=packet_size) { set_state(NORMAL); return 0; } return 1; } else return 0; } int demo_manager::get_packet(void *packet, int &packet_size) // returns non 0 if actually loaded { if (state==PLAYING) { uint16_t ps; if (record_file->read(&ps,2)!=2) { set_state(NORMAL); return 0; } ps=lstl(ps); if (record_file->read(packet,ps)!=ps) { set_state(NORMAL); return 0; } packet_size=ps; return 1; } return 0; }