readnpcs.cc

Go to the documentation of this file.
00001 /*
00002  *  readnpcs.cc - Read in NPC's from npc.dat & schedule.dat.  Also writes npc.dat back out.
00003  *
00004  *  Copyright (C) 1999  Jeffrey S. Freedman
00005  *  Copyright (C) 2000-2004  The Exult Team
00006  *
00007  *  This program is free software; you can redistribute it and/or modify
00008  *  it under the terms of the GNU General Public License as published by
00009  *  the Free Software Foundation; either version 2 of the License, or
00010  *  (at your option) any later version.
00011  *
00012  *  This program is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *  GNU General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU General Public License
00018  *  along with this program; if not, write to the Free Software
00019  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00020  */
00021 
00022 #ifdef HAVE_CONFIG_H
00023 #  include <config.h>
00024 #endif
00025 
00026 #ifndef ALPHA_LINUX_CXX
00027 #  include <cstring>
00028 #endif
00029 #include "gamewin.h"
00030 #include "game.h"
00031 #include "monsters.h"
00032 #include "ucmachine.h"
00033 #include "utils.h"
00034 #include "fnames.h"
00035 #include "schedule.h"
00036 #include "databuf.h"
00037 //#include "items.h"      /* Debugging only */
00038 
00039 #ifndef UNDER_CE
00040 using std::cerr;
00041 using std::cout;
00042 using std::endl;
00043 using std::ifstream;
00044 using std::ios;
00045 using std::memset;
00046 using std::ofstream;
00047 #endif
00048 
00049 /*
00050  *  Read in the NPC's, plus the monster info.
00051  */
00052 
00053 void Game_window::read_npcs
00054   (
00055   )
00056 {
00057   npcs.resize(1);     // Create main actor.
00058   camera_actor = npcs[0] = main_actor = new Main_actor("", 0);
00059   ifstream nfile_stream;
00060   StreamDataSource nfile(&nfile_stream);
00061   int num_npcs;
00062   bool fix_unused = false;  // Get set for old savegames.
00063   try
00064     {
00065     U7open(nfile_stream, NPC_DAT);
00066     num_npcs1 = nfile.read2();  // Get counts.
00067     num_npcs = num_npcs1 + nfile.read2();
00068     main_actor->read(&nfile, 0, false, fix_unused);
00069     }
00070   catch(exult_exception &e)
00071     {
00072     if (!Game::is_editing())
00073       throw e;
00074     num_npcs1 = num_npcs = 1; 
00075     if (Game::get_avname())
00076       main_actor->set_npc_name(Game::get_avname());
00077     main_actor->set_shape(721); // FOR NOW.
00078     main_actor->set_invalid();  // Put in middle of world.
00079     main_actor->move(c_num_tiles/2, c_num_tiles/2, 0);
00080     }
00081   npcs.resize(num_npcs);
00082   bodies.resize(num_npcs);
00083   int i;
00084 
00085   // Don't like it... no i don't.
00086   center_view(main_actor->get_tile());
00087   for (i = 1; i < num_npcs; i++)  // Create the rest.
00088   {
00089     npcs[i] = new Npc_actor("", 0);
00090     npcs[i]->read(&nfile, i, i < num_npcs1, fix_unused);
00091     if (npcs[i]->is_unused())
00092       {   // Not part of the game.
00093       npcs[i]->remove_this(1);
00094       npcs[i]->set_schedule_type(Schedule::wait);
00095       }
00096     else
00097       npcs[i]->restore_schedule();
00098     CYCLE_RED_PLASMA();
00099   }
00100   nfile_stream.close();
00101   main_actor->set_actor_shape();
00102   try
00103   {
00104     U7open(nfile_stream, MONSNPCS); // Monsters.
00105     // (Won't exist the first time; in this case U7open throws
00106     int cnt = nfile.read2();
00107     char tmp = nfile.read1();// Read 1 ahead to test.
00108     int okay = nfile_stream.good();
00109     nfile.skip(-1);
00110     while (okay && cnt--)
00111     {
00112           // Read ahead to get shape.
00113       nfile.skip(2);
00114       unsigned short shnum = nfile.read2()&0x3ff;
00115       okay = nfile_stream.good();
00116       nfile.skip(-4);
00117       ShapeID sid(shnum, 0);
00118       if (!okay || sid.get_num_frames() < 16)
00119         break;  // Watch for corrupted file.
00120       Monster_actor *act = Monster_actor::create(shnum);
00121       act->read(&nfile, -1, false, fix_unused);
00122       act->restore_schedule();
00123       CYCLE_RED_PLASMA();
00124     }
00125   }
00126   catch(exult_exception &e) {
00127 #ifdef DEBUG
00128     cerr << "Error reading saved monsters.  Clearing list." << endl;
00129 #endif
00130     Monster_actor::give_up();
00131   }
00132   if (moving_barge)   // Gather all NPC's on barge.
00133   {
00134     Barge_object *b = moving_barge;
00135     moving_barge = 0;
00136     set_moving_barge(b);
00137   }
00138   read_schedules();   // Now get their schedules.
00139   center_view(main_actor->get_tile());
00140 }
00141 
00142 /*
00143  *  Write NPC (and monster) data back out.
00144  *
00145  *  Output: false if error, already reported.
00146  */
00147 
00148 void Game_window::write_npcs
00149   (
00150   )
00151   {
00152   int num_npcs = npcs.size();
00153   ofstream nfile_stream;
00154   U7open(nfile_stream, NPC_DAT);
00155   StreamDataSource nfile(&nfile_stream);
00156 
00157   nfile.write2(num_npcs1);  // Start with counts.
00158   nfile.write2(num_npcs - num_npcs1);
00159   int i;
00160   for (i = 0; i < num_npcs; i++)
00161     npcs[i]->write(&nfile);
00162   nfile_stream.flush();
00163   bool result = nfile_stream.good();
00164   if (!result)
00165     throw file_write_exception(NPC_DAT);
00166   nfile_stream.close();
00167   write_schedules();    // Write schedules
00168           // Now write out monsters in world.
00169   U7open(nfile_stream, MONSNPCS);
00170   int cnt = 0;
00171   nfile.write2(0);    // Write 0 as a place holder.
00172   for (Monster_actor *mact = Monster_actor::get_first_in_world();
00173           mact; mact = mact->get_next_in_world())
00174     if (!mact->is_dead()) // Alive?
00175       {
00176       mact->write(&nfile);
00177       cnt++;
00178       }
00179   nfile.seek(0);      // Back to start.
00180   nfile.write2(cnt);    // Write actual count.
00181   nfile_stream.flush();
00182   result = nfile_stream.good();
00183   nfile_stream.close();
00184   if (!result)
00185     throw file_write_exception(NPC_DAT);
00186   }
00187 
00188 /*
00189  *  Read NPC schedules.
00190  */
00191 
00192 void Game_window::read_schedules
00193   (
00194   )
00195   {
00196   ifstream sfile_stream;
00197   int num_npcs = 0;
00198   try
00199   {
00200     U7open(sfile_stream, GSCHEDULE);
00201   }
00202   catch(exult_exception e)
00203   {
00204 #ifdef DEBUG
00205     cerr << "Couldn't open " << GSCHEDULE << ". Falling back to "
00206        << SCHEDULE_DAT << "." << endl;
00207 #endif
00208     try
00209     {
00210       U7open(sfile_stream, SCHEDULE_DAT);
00211     }
00212     catch(exult_exception e1)
00213     {
00214     if (!Game::is_editing())
00215       throw e1;
00216     else
00217       return;
00218     }
00219   }
00220   StreamDataSource sfile(&sfile_stream);
00221 
00222   num_npcs = sfile.read4(); // # of NPC's, not include Avatar.
00223 
00224   short *offsets = new short[num_npcs];
00225   int i;        // Read offsets with list of scheds.
00226   for (i = 0; i < num_npcs; i++)
00227     offsets[i] = sfile.read2();
00228   for (i = 0; i < num_npcs - 1; i++)  // Do each NPC, except Avatar.
00229     {
00230           // Avatar isn't included here.
00231     Actor *npc = npcs[i + 1];
00232     int cnt = offsets[i + 1] - offsets[i];
00233           // Read schedules into this array.
00234     Schedule_change *schedules = cnt?new Schedule_change[cnt]:0;
00235     
00236     for (int j = 0; j < cnt; j++)
00237       {
00238       unsigned char ent[4];
00239       sfile.read(reinterpret_cast<char*>(ent), 4);
00240       schedules[j].set(ent);
00241       }
00242           // Store in NPC.
00243     if (npc)
00244       npc->set_schedules(schedules, cnt);
00245     else
00246       delete schedules;
00247     CYCLE_RED_PLASMA();
00248     }
00249   delete [] offsets;    // Done with this.
00250   cout.flush();
00251   }
00252 
00253 
00254 /*
00255  *  Write NPC schedules.
00256  */
00257 
00258 void Game_window::write_schedules ()
00259 {
00260 
00261   ofstream sfile_stream;
00262   Schedule_change *schedules;
00263   int cnt;
00264   short offset = 0;
00265   int i;
00266   int num;
00267 
00268   // So do I allow for all NPCs (type1 and type2) - Yes i will
00269   num = npcs.size();
00270 
00271   U7open(sfile_stream, GSCHEDULE);
00272   StreamDataSource sfile(&sfile_stream);
00273 
00274   sfile.write4(num);    // # of NPC's, not include Avatar.
00275   sfile.write2(0);    // First offfset
00276 
00277   for (i = 1; i < num; i++) // write offsets with list of scheds.
00278   {
00279     npcs[i]->get_schedules(schedules, cnt);
00280     offset += cnt;
00281     sfile.write2(offset);
00282   }
00283 
00284   for (i = 1; i < num; i++) // Do each NPC, except Avatar.
00285   {
00286     npcs[i]->get_schedules(schedules, cnt);
00287     for (int j = 0; j < cnt; j++)
00288     {
00289       unsigned char ent[4];
00290       schedules[j].get(ent);
00291       sfile.write(reinterpret_cast<char*>(ent), 4);
00292     }
00293   }
00294 }
00295 
00296 void Game_window::revert_schedules(Actor *npc)
00297 {
00298   // Can't do this if <= 0
00299   if (npc->get_npc_num() <= 0) return;
00300 
00301   int i;
00302   ifstream sfile_stream;
00303 
00304   U7open(sfile_stream, SCHEDULE_DAT);
00305   StreamDataSource sfile(&sfile_stream);
00306 
00307   // # of NPC's, not include Avatar.
00308   int num_npcs = sfile.read4();
00309   short *offsets = new short[num_npcs];
00310   for (i = 0; i < num_npcs; i++) offsets[i] = sfile.read2();
00311 
00312   // Seek to the right place
00313   sfile.skip(offsets[npc->get_npc_num()-1]*4);
00314 
00315   // Get the count that we want to use
00316   int cnt = offsets[npc->get_npc_num()] - offsets[npc->get_npc_num()-1];
00317 
00318   // Read schedules into this array.
00319   Schedule_change *schedules = cnt?new Schedule_change[cnt]:0;
00320 
00321   for (i = 0; i < cnt; i++)
00322   {
00323     unsigned char ent[4];
00324     sfile.read(reinterpret_cast<char*>(ent), 4);
00325     schedules[i].set(ent);
00326   }
00327   // Store in NPC.
00328   npc->set_schedules(schedules, cnt);
00329 
00330   // Done
00331   delete [] offsets;
00332 }
00333 

Generated on Mon Jul 9 14:42:49 2007 for ExultEngine by  doxygen 1.5.1