summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/files.cc
diff options
context:
space:
mode:
authordshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2007-03-15 20:10:20 +0000
committerdshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2007-03-15 20:10:20 +0000
commit621bd9ce58cc45ce9cfcc3cf1f576882b40a426d (patch)
treeadc2b3b4faed06c535b2bec690cf362af40c7fa5 /crawl-ref/source/files.cc
parent83559fff8232481cbc68731b7527dd2154c0bd88 (diff)
downloadcrawl-ref-621bd9ce58cc45ce9cfcc3cf1f576882b40a426d.tar.gz
crawl-ref-621bd9ce58cc45ce9cfcc3cf1f576882b40a426d.zip
Cleaned up ghost and Pandemonium demon handling.
Can now have multiple ghosts or Pandemonium demons on a level. Ghosts and Pan demons can coexist. (D:9 and later are eligible for >1 ghost.) Enabled loading ghosts in Pandemonium. Pandemonium demons can now be created outside Pan. Not that you'd want to do it, but you can. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1043 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source/files.cc')
-rw-r--r--crawl-ref/source/files.cc745
1 files changed, 173 insertions, 572 deletions
diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc
index 463cc14603..a45f76a32c 100644
--- a/crawl-ref/source/files.cc
+++ b/crawl-ref/source/files.cc
@@ -84,79 +84,16 @@
#define DO_CHMOD_PRIVATE(x) // empty command
#endif
-void save_level(int level_saved, bool was_a_labyrinth, char where_were_you);
-
-/*
- Order for looking for conjurations for the 1st & 2nd spell slots,
- when finding spells to be remembered by a player's ghost:
- */
-unsigned char search_order_conj[] = {
- SPELL_LEHUDIBS_CRYSTAL_SPEAR,
- SPELL_BOLT_OF_DRAINING,
- SPELL_AGONY,
- SPELL_DISINTEGRATE,
- SPELL_LIGHTNING_BOLT,
- SPELL_STICKY_FLAME,
- SPELL_ISKENDERUNS_MYSTIC_BLAST,
- SPELL_BOLT_OF_MAGMA,
- SPELL_ICE_BOLT,
- SPELL_BOLT_OF_FIRE,
- SPELL_BOLT_OF_COLD,
- SPELL_FIREBALL,
- SPELL_DELAYED_FIREBALL,
- SPELL_VENOM_BOLT,
- SPELL_BOLT_OF_IRON,
- SPELL_STONE_ARROW,
- SPELL_THROW_FLAME,
- SPELL_THROW_FROST,
- SPELL_PAIN,
- SPELL_STING,
- SPELL_SHOCK,
- SPELL_MAGIC_DART,
- SPELL_NO_SPELL, // end search
-};
-
-/*
- Order for looking for summonings and self-enchants for the 3rd spell slot:
- */
-unsigned char search_order_third[] = {
-/* 0 */
- SPELL_SYMBOL_OF_TORMENT,
- SPELL_SUMMON_GREATER_DEMON,
- SPELL_SUMMON_WRAITHS,
- SPELL_SUMMON_HORRIBLE_THINGS,
- SPELL_SUMMON_DEMON,
- SPELL_DEMONIC_HORDE,
- SPELL_HASTE,
- SPELL_ANIMATE_DEAD,
- SPELL_INVISIBILITY,
- SPELL_CALL_IMP,
- SPELL_SUMMON_SMALL_MAMMAL,
-/* 10 */
- SPELL_CONTROLLED_BLINK,
- SPELL_BLINK,
- SPELL_NO_SPELL, // end search
-};
+// file locking stuff
+#ifdef USE_FILE_LOCKING
+static bool lock_file_handle( FILE *handle, int type );
+static bool unlock_file_handle( FILE *handle );
+#endif // USE_FILE_LOCKING
-/*
- Order for looking for enchants for the 4th + 5th spell slot. If fails, will
- go through conjs.
- Note: Dig must be in misc2 (5th) position to work.
- */
-unsigned char search_order_misc[] = {
-/* 0 */
- SPELL_AGONY,
- SPELL_BANISHMENT,
- SPELL_PARALYZE,
- SPELL_CONFUSE,
- SPELL_SLOW,
- SPELL_POLYMORPH_OTHER,
- SPELL_TELEPORT_OTHER,
- SPELL_DIG,
- SPELL_NO_SPELL, // end search
-};
+void save_level(int level_saved, bool was_a_labyrinth, char where_were_you);
-/* Last slot (emergency) can only be teleport self or blink. */
+#define GHOST_MINOR_VERSION 1
+#define LEVEL_MINOR_VERSION 1
static void redraw_all(void)
{
@@ -173,16 +110,6 @@ static void redraw_all(void)
you.redraw_status_flags = REDRAW_LINE_1_MASK | REDRAW_LINE_2_MASK | REDRAW_LINE_3_MASK;
}
-struct ghost_struct ghost;
-
-unsigned char translate_spell(unsigned char spel);
-unsigned char search_third_list(unsigned char ignore_spell);
-unsigned char search_second_list(unsigned char ignore_spell);
-unsigned char search_first_list(unsigned char ignore_spell);
-
-void add_spells( struct ghost_struct &gs );
-void generate_random_demon();
-
static bool determine_version( FILE *restoreFile,
char &majorVersion, char &minorVersion );
@@ -720,31 +647,21 @@ void load( unsigned char stair_taken, int load_mode, bool was_a_labyrinth,
was_a_labyrinth = false;
}
- // clear out ghost/demon lord information:
- strcpy( ghost.name, "" );
- for (int ic = 0; ic < NUM_GHOST_VALUES; ++ic)
- ghost.values[ic] = 0;
-
// Try to open level savefile.
FILE *levelFile = fopen(cha_fil.c_str(), "rb");
// GENERATE new level when the file can't be opened:
if (levelFile == NULL)
- {
- strcpy(ghost.name, "");
-
- for (int imn = 0; imn < NUM_GHOST_VALUES; ++imn)
- ghost.values[imn] = 0;
-
+ {
builder( you.your_level, you.level_type );
just_created_level = true;
- if (you.level_type == LEVEL_PANDEMONIUM)
- generate_random_demon();
- else if (you.your_level > 1
- && one_chance_in(3)
- && you.level_type != LEVEL_LABYRINTH)
- load_ghost(); // no ghosts in Pan or Labyrinth
+ if (you.your_level > 1
+ && one_chance_in(3)
+ && you.level_type != LEVEL_LABYRINTH)
+ {
+ load_ghost(); // no ghosts in Labyrinth
+ }
}
else
{
@@ -1149,7 +1066,8 @@ void save_level(int level_saved, bool was_a_labyrinth, char where_were_you)
// nail all items to the ground
fix_item_coordinates();
- write_tagged_file( saveFile, SAVE_MAJOR_VERSION, 0, TAGTYPE_LEVEL );
+ write_tagged_file( saveFile, SAVE_MAJOR_VERSION,
+ LEVEL_MINOR_VERSION, TAGTYPE_LEVEL );
fclose(saveFile);
@@ -1264,8 +1182,6 @@ void load_ghost(void)
{
char majorVersion;
char minorVersion;
- int imn;
- int i;
std::string cha_fil = make_filename("bones", you.your_level,
you.where_are_you,
@@ -1289,6 +1205,16 @@ void load_ghost(void)
return;
}
+ if (majorVersion != SAVE_MAJOR_VERSION
+ || minorVersion != GHOST_MINOR_VERSION)
+ {
+
+ fclose(gfile);
+ unlink(cha_fil.c_str());
+ return;
+ }
+
+ ghosts.clear();
restore_ghost_version(gfile, majorVersion, minorVersion);
// sanity check - EOF
@@ -1313,44 +1239,15 @@ void load_ghost(void)
unlink(cha_fil.c_str());
// translate ghost to monster and place.
- for (imn = 0; imn < MAX_MONSTERS - 10; imn++)
+ for (int imn = 0; imn < MAX_MONSTERS - 10 && !ghosts.empty(); imn++)
{
if (menv[imn].type != -1)
continue;
- menv[imn].type = MONS_PLAYER_GHOST;
- menv[imn].hit_dice = ghost.values[ GVAL_EXP_LEVEL ];
- menv[imn].hit_points = ghost.values[ GVAL_MAX_HP ];
- menv[imn].max_hit_points = ghost.values[ GVAL_MAX_HP ];
- menv[imn].ac = ghost.values[ GVAL_AC];
- menv[imn].ev = ghost.values[ GVAL_EV ];
- menv[imn].speed = 10;
- menv[imn].speed_increment = 70;
- menv[imn].attitude = ATT_HOSTILE;
- menv[imn].behaviour = BEH_WANDER;
- menv[imn].flags = 0;
- menv[imn].foe = MHITNOT;
- menv[imn].foe_memory = 0;
- menv[imn].colour = mons_class_colour(MONS_PLAYER_GHOST);
- menv[imn].number = 250;
- mons_load_spells(&menv[imn], MST_GHOST);
-
- for (i = 0; i < NUM_MONSTER_SLOTS; i++)
- menv[imn].inv[i] = NON_ITEM;
-
- for (i = 0; i < NUM_MON_ENCHANTS; i++)
- menv[imn].enchantment[i] = ENCH_NONE;
-
- do
- {
- menv[imn].x = random2(GXM - 20) + 10;
- menv[imn].y = random2(GYM - 20) + 10;
- }
- while ((grd[menv[imn].x][menv[imn].y] != DNGN_FLOOR)
- || (mgrd[menv[imn].x][menv[imn].y] != NON_MONSTER));
-
- mgrd[menv[imn].x][menv[imn].y] = imn;
- break;
+ menv[imn].set_ghost(ghosts[0]);
+ menv[imn].ghost_init();
+
+ ghosts.erase(ghosts.begin());
}
}
@@ -1561,18 +1458,16 @@ static void restore_ghost_version( FILE *ghostFile,
{
switch(majorVersion)
{
- case SAVE_MAJOR_VERSION:
- restore_tagged_file(ghostFile, TAGTYPE_GHOST, minorVersion);
- break;
- default:
- break;
+ case SAVE_MAJOR_VERSION:
+ restore_tagged_file(ghostFile, TAGTYPE_GHOST, minorVersion);
+ break;
+ default:
+ break;
}
}
void save_ghost( bool force )
{
- const int wpn = you.equip[EQ_WEAPON];
-
if (!force && (you.your_level < 2 || you.is_undead))
return;
@@ -1590,82 +1485,21 @@ void save_ghost( bool force )
return;
}
- snprintf(ghost.name, sizeof ghost.name, "%s", you.your_name);
-
- ghost.values[ GVAL_MAX_HP ] = ((you.hp_max >= 150) ? 150 : you.hp_max);
- ghost.values[ GVAL_EV ] = player_evasion();
- ghost.values[ GVAL_AC ] = player_AC();
- ghost.values[ GVAL_SEE_INVIS ] = player_see_invis();
- ghost.values[ GVAL_RES_FIRE ] = player_res_fire();
- ghost.values[ GVAL_RES_COLD ] = player_res_cold();
- ghost.values[ GVAL_RES_ELEC ] = player_res_electricity();
-
- /* note - as ghosts, automatically get res poison + prot_life */
-
- int d = 4;
- int e = 0;
-
- if (wpn != -1)
- {
- if (you.inv[wpn].base_type == OBJ_WEAPONS
- || you.inv[wpn].base_type == OBJ_STAVES)
- {
- d = property( you.inv[wpn], PWPN_DAMAGE );
-
- d *= 25 + you.skills[weapon_skill( you.inv[wpn].base_type,
- you.inv[wpn].sub_type )];
- d /= 25;
-
- if (you.inv[wpn].base_type == OBJ_WEAPONS)
- {
- if (is_random_artefact( you.inv[wpn] ))
- e = randart_wpn_property( you.inv[wpn], RAP_BRAND );
- else
- e = you.inv[wpn].special;
- }
- }
- }
- else
- {
- /* Unarmed combat */
- if (you.species == SP_TROLL)
- d += you.experience_level;
-
- d += you.skills[SK_UNARMED_COMBAT];
- }
-
- d *= 30 + you.skills[SK_FIGHTING];
- d /= 30;
-
- d += you.strength / 4;
-
- if (d > 50)
- d = 50;
-
- ghost.values[ GVAL_DAMAGE ] = d;
- ghost.values[ GVAL_BRAND ] = e;
- ghost.values[ GVAL_SPECIES ] = you.species;
- ghost.values[ GVAL_BEST_SKILL ] = best_skill(SK_FIGHTING, (NUM_SKILLS - 1), 99);
- ghost.values[ GVAL_SKILL_LEVEL ] = you.skills[best_skill(SK_FIGHTING, (NUM_SKILLS - 1), 99)];
- ghost.values[ GVAL_EXP_LEVEL ] = you.experience_level;
- ghost.values[ GVAL_CLASS ] = you.char_class;
-
- add_spells(ghost);
-
- gfile = fopen(cha_fil.c_str(), "wb");
+ ghosts = ghost_demon::find_ghosts();
+
+ gfile = lk_open("wb", cha_fil);
if (gfile == NULL)
{
- snprintf(info, INFO_SIZE, "Error creating ghost file: %s",
- cha_fil.c_str());
- mpr(info);
+ mprf("Error creating ghost file: %s", cha_fil.c_str());
more();
return;
}
- write_tagged_file( gfile, SAVE_MAJOR_VERSION, 0, TAGTYPE_GHOST );
+ write_tagged_file( gfile, SAVE_MAJOR_VERSION,
+ GHOST_MINOR_VERSION, TAGTYPE_GHOST );
- fclose(gfile);
+ lk_close(gfile, "wb", cha_fil);
#if DEBUG_DIAGNOSTICS
mpr( "Saved ghost.", MSGCH_DIAGNOSTICS );
@@ -1674,211 +1508,10 @@ void save_ghost( bool force )
DO_CHMOD_PRIVATE(cha_fil.c_str());
} // end save_ghost()
-/*
- Used when creating ghosts: goes through and finds spells for the ghost to
- cast. Death is a traumatic experience, so ghosts only remember a few spells.
- */
-void add_spells( struct ghost_struct &gs )
-{
- int i = 0;
-
- for (i = GVAL_SPELL_1; i <= GVAL_SPELL_6; i++)
- gs.values[i] = SPELL_NO_SPELL;
-
- gs.values[ GVAL_SPELL_1 ] = search_first_list(SPELL_NO_SPELL);
- gs.values[ GVAL_SPELL_2 ] = search_first_list(gs.values[GVAL_SPELL_1]);
- gs.values[ GVAL_SPELL_3 ] = search_second_list(SPELL_NO_SPELL);
- gs.values[ GVAL_SPELL_4 ] = search_third_list(SPELL_NO_SPELL);
-
- if (gs.values[ GVAL_SPELL_4 ] == SPELL_NO_SPELL)
- gs.values[ GVAL_SPELL_4 ] = search_first_list(SPELL_NO_SPELL);
-
- gs.values[ GVAL_SPELL_5 ] = search_first_list(gs.values[GVAL_SPELL_4]);
-
- if (gs.values[ GVAL_SPELL_5 ] == SPELL_NO_SPELL)
- gs.values[ GVAL_SPELL_5 ] = search_first_list(gs.values[GVAL_SPELL_4]);
-
- if (player_has_spell( SPELL_DIG ))
- gs.values[ GVAL_SPELL_5 ] = SPELL_DIG;
-
- /* Looks for blink/tport for emergency slot */
- if (player_has_spell( SPELL_CONTROLLED_BLINK )
- || player_has_spell( SPELL_BLINK ))
- {
- gs.values[ GVAL_SPELL_6 ] = SPELL_CONTROLLED_BLINK;
- }
-
- if (player_has_spell( SPELL_TELEPORT_SELF ))
- gs.values[ GVAL_SPELL_6 ] = SPELL_TELEPORT_SELF;
-
- for (i = GVAL_SPELL_1; i <= GVAL_SPELL_6; i++)
- gs.values[i] = translate_spell( gs.values[i] );
-} // end add_spells()
-
-unsigned char search_first_list(unsigned char ignore_spell)
-{
- for (int i = 0; i < 20; i++)
- {
- if (search_order_conj[i] == SPELL_NO_SPELL)
- return SPELL_NO_SPELL;
-
- if (search_order_conj[i] == ignore_spell)
- continue;
-
- if (player_has_spell(search_order_conj[i]))
- return search_order_conj[i];
- }
-
- return SPELL_NO_SPELL;
-} // end search_first_list()
-
-unsigned char search_second_list(unsigned char ignore_spell)
-{
- for (int i = 0; i < 20; i++)
- {
- if (search_order_third[i] == SPELL_NO_SPELL)
- return SPELL_NO_SPELL;
-
- if (search_order_third[i] == ignore_spell)
- continue;
-
- if (player_has_spell(search_order_third[i]))
- return search_order_third[i];
- }
-
- return SPELL_NO_SPELL;
-} // end search_second_list()
-unsigned char search_third_list(unsigned char ignore_spell)
-{
- for (int i = 0; i < 20; i++)
- {
- if (search_order_misc[i] == SPELL_NO_SPELL)
- return SPELL_NO_SPELL;
-
- if (search_order_misc[i] == ignore_spell)
- continue;
-
- if (player_has_spell(search_order_misc[i]))
- return search_order_misc[i];
- }
-
- return SPELL_NO_SPELL;
-} // end search_third_list()
-
-
-/*
- When passed the number for a player spell, returns the equivalent monster
- spell. Returns SPELL_NO_SPELL on failure (no equiv).
- */
-unsigned char translate_spell(unsigned char spel)
-{
- switch (spel)
- {
- case SPELL_TELEPORT_SELF:
- return (MS_TELEPORT);
- case SPELL_ICE_BOLT:
- return (MS_ICE_BOLT);
- case SPELL_SHOCK:
- return (MS_SHOCK);
- case SPELL_BOLT_OF_MAGMA:
- return (MS_MAGMA);
- case SPELL_MAGIC_DART:
- return (MS_MMISSILE);
- case SPELL_FIREBALL:
- case SPELL_DELAYED_FIREBALL:
- return (MS_FIREBALL);
- case SPELL_DIG:
- return (MS_DIG);
- case SPELL_BOLT_OF_FIRE:
- return (MS_FIRE_BOLT);
- case SPELL_BOLT_OF_COLD:
- return (MS_COLD_BOLT);
- case SPELL_LIGHTNING_BOLT:
- return (MS_LIGHTNING_BOLT);
- case SPELL_POLYMORPH_OTHER:
- return (MS_MUTATION);
- case SPELL_SLOW:
- return (MS_SLOW);
- case SPELL_HASTE:
- return (MS_HASTE);
- case SPELL_PARALYZE:
- return (MS_PARALYSIS);
- case SPELL_CONFUSE:
- return (MS_CONFUSE);
- case SPELL_INVISIBILITY:
- return (MS_INVIS);
- case SPELL_THROW_FLAME:
- return (MS_FLAME);
- case SPELL_THROW_FROST:
- return (MS_FROST);
- case SPELL_CONTROLLED_BLINK:
- return (MS_BLINK); /* approximate */
-/* case FREEZING_CLOUD: return ; no freezing/mephitic cloud yet
- case MEPHITIC_CLOUD: return ; */
- case SPELL_VENOM_BOLT:
- return (MS_VENOM_BOLT);
- case SPELL_POISON_ARROW:
- return (MS_POISON_ARROW);
- case SPELL_TELEPORT_OTHER:
- return (MS_TELEPORT_OTHER);
- case SPELL_SUMMON_SMALL_MAMMAL:
- return (MS_SUMMON_SMALL_MAMMALS);
- case SPELL_BOLT_OF_DRAINING:
- return (MS_NEGATIVE_BOLT);
- case SPELL_LEHUDIBS_CRYSTAL_SPEAR:
- return (MS_CRYSTAL_SPEAR);
- case SPELL_BLINK:
- return (MS_BLINK);
- case SPELL_ISKENDERUNS_MYSTIC_BLAST:
- return (MS_ORB_ENERGY);
- case SPELL_SUMMON_HORRIBLE_THINGS:
- return (MS_LEVEL_SUMMON); /* approximate */
- case SPELL_SHADOW_CREATURES:
- return (MS_LEVEL_SUMMON); /* approximate */
- case SPELL_ANIMATE_DEAD:
- return (MS_ANIMATE_DEAD);
- case SPELL_PAIN:
- return (MS_PAIN);
- case SPELL_SUMMON_WRAITHS:
- return (MS_SUMMON_UNDEAD); /* approximate */
- case SPELL_STICKY_FLAME:
- return (MS_STICKY_FLAME);
- case SPELL_CALL_IMP:
- return (MS_SUMMON_DEMON_LESSER);
- case SPELL_BANISHMENT:
- return (MS_BANISHMENT);
- case SPELL_STING:
- return (MS_STING);
- case SPELL_SUMMON_DEMON:
- return (MS_SUMMON_DEMON);
- case SPELL_DEMONIC_HORDE:
- return (MS_SUMMON_DEMON_LESSER);
- case SPELL_SUMMON_GREATER_DEMON:
- return (MS_SUMMON_DEMON_GREATER);
- case SPELL_BOLT_OF_IRON:
- return (MS_IRON_BOLT);
- case SPELL_STONE_ARROW:
- return (MS_STONE_ARROW);
- case SPELL_DISINTEGRATE:
- return (MS_DISINTEGRATE);
- case SPELL_AGONY:
- /* Too powerful to give ghosts Torment for Agony? Nah. */
- return (MS_TORMENT);
- case SPELL_SYMBOL_OF_TORMENT:
- return (MS_TORMENT);
- default:
- break;
- }
-
- return (MS_NO_SPELL);
-}
-
-void generate_random_demon(void)
+void generate_random_demon()
{
int rdem = 0;
- int i = 0;
-
for (rdem = 0; rdem < MAX_MONSTERS + 1; rdem++)
{
if (rdem == MAX_MONSTERS)
@@ -1888,166 +1521,10 @@ void generate_random_demon(void)
break;
}
- char st_p[ITEMNAME_SIZE];
-
- make_name(random_int(), false, st_p);
- strcpy(ghost.name, st_p);
-
- // hp - could be defined below (as could ev, AC etc). Oh well, too late:
- ghost.values[ GVAL_MAX_HP ] = 100 + roll_dice( 3, 50 );
-
- ghost.values[ GVAL_EV ] = 5 + random2(20);
- ghost.values[ GVAL_AC ] = 5 + random2(20);
-
- ghost.values[ GVAL_SEE_INVIS ] = (one_chance_in(10) ? 0 : 1);
-
- if (!one_chance_in(3))
- ghost.values[ GVAL_RES_FIRE ] = (coinflip() ? 2 : 3);
- else
- {
- ghost.values[ GVAL_RES_FIRE ] = 0; /* res_fire */
-
- if (one_chance_in(10))
- ghost.values[ GVAL_RES_FIRE ] = -1;
- }
-
- if (!one_chance_in(3))
- ghost.values[ GVAL_RES_COLD ] = 2;
- else
- {
- ghost.values[ GVAL_RES_COLD ] = 0; /* res_cold */
-
- if (one_chance_in(10))
- ghost.values[ GVAL_RES_COLD ] = -1;
- }
-
- // demons, like ghosts, automatically get poison res. and life prot.
-
- // resist electricity:
- ghost.values[ GVAL_RES_ELEC ] = (!one_chance_in(3) ? 1 : 0);
-
- // HTH damage:
- ghost.values[ GVAL_DAMAGE ] = 20 + roll_dice( 2, 20 );
-
- // special attack type (uses weapon brand code):
- ghost.values[ GVAL_BRAND ] = SPWPN_NORMAL;
-
- if (!one_chance_in(3))
- {
- do {
- ghost.values[ GVAL_BRAND ] = random2(17);
- /* some brands inappropriate (eg holy wrath) */
- } while (ghost.values[ GVAL_BRAND ] == SPWPN_HOLY_WRATH
- || ghost.values[ GVAL_BRAND ] == SPWPN_ORC_SLAYING
- || ghost.values[ GVAL_BRAND ] == SPWPN_PROTECTION
- || ghost.values[ GVAL_BRAND ] == SPWPN_FLAME
- || ghost.values[ GVAL_BRAND ] == SPWPN_FROST
- || ghost.values[ GVAL_BRAND ] == SPWPN_DISRUPTION);
- }
-
- // is demon a spellcaster?
- // upped from one_chance_in(3)... spellcasters are more interesting
- // and I expect named demons to typically have a trick or two -- bwr
- ghost.values[GVAL_DEMONLORD_SPELLCASTER] = (one_chance_in(10) ? 0 : 1);
-
- // does demon fly? (0 = no, 1 = fly, 2 = levitate)
- ghost.values[GVAL_DEMONLORD_FLY] = (one_chance_in(3) ? 0 :
- one_chance_in(5) ? 2 : 1);
-
- // vacant <ghost best skill level>:
- ghost.values[GVAL_DEMONLORD_UNUSED] = 0;
-
- // hit dice:
- ghost.values[GVAL_DEMONLORD_HIT_DICE] = 10 + roll_dice(2, 10);
-
- // does demon cycle colours?
- ghost.values[GVAL_DEMONLORD_CYCLE_COLOUR] = (one_chance_in(10) ? 1 : 0);
-
- menv[rdem].hit_dice = ghost.values[ GVAL_DEMONLORD_HIT_DICE ];
- menv[rdem].hit_points = ghost.values[ GVAL_MAX_HP ];
- menv[rdem].max_hit_points = ghost.values[ GVAL_MAX_HP ];
- menv[rdem].ac = ghost.values[ GVAL_AC ];
- menv[rdem].ev = ghost.values[ GVAL_EV ];
- menv[rdem].speed = (one_chance_in(3) ? 10 : 6 + roll_dice(2, 9));
- menv[rdem].speed_increment = 70;
- menv[rdem].colour = random_colour(); // demon's colour
-
- for (i = GVAL_SPELL_1; i <= GVAL_SPELL_6; i++)
- ghost.values[i] = SPELL_NO_SPELL;
-
- /* This bit uses the list of player spells to find appropriate spells
- for the demon, then converts those spells to the monster spell indices.
- Some special monster-only spells are at the end. */
- if (ghost.values[ GVAL_DEMONLORD_SPELLCASTER ] == 1)
- {
-#define RANDOM_ARRAY_ELEMENT(x) x[random2(sizeof(x) / sizeof(x[0]))]
-
- if (coinflip())
- ghost.values[GVAL_SPELL_1]=RANDOM_ARRAY_ELEMENT(search_order_conj);
-
- // Might duplicate the first spell, but that isn't a problem.
- if (coinflip())
- ghost.values[GVAL_SPELL_2]=RANDOM_ARRAY_ELEMENT(search_order_conj);
-
- if (!one_chance_in(4))
- ghost.values[GVAL_SPELL_3]=RANDOM_ARRAY_ELEMENT(search_order_third);
-
- if (coinflip())
- ghost.values[GVAL_SPELL_4]=RANDOM_ARRAY_ELEMENT(search_order_misc);
-
- if (coinflip())
- ghost.values[GVAL_SPELL_5]=RANDOM_ARRAY_ELEMENT(search_order_misc);
-
-#undef RANDOM_ARRAY_ELEMENT
-
- if (coinflip())
- ghost.values[ GVAL_SPELL_6 ] = SPELL_BLINK;
- if (coinflip())
- ghost.values[ GVAL_SPELL_6 ] = SPELL_TELEPORT_SELF;
-
- /* Converts the player spell indices to monster spell ones */
- for (i = GVAL_SPELL_1; i <= GVAL_SPELL_6; i++)
- ghost.values[i] = translate_spell( ghost.values[i] );
-
- /* give demon a chance for some monster-only spells: */
- /* and demon-summoning should be fairly common: */
- if (one_chance_in(25))
- ghost.values[GVAL_SPELL_1] = MS_HELLFIRE_BURST;
- if (one_chance_in(25))
- ghost.values[GVAL_SPELL_1] = MS_METAL_SPLINTERS;
- if (one_chance_in(25))
- ghost.values[GVAL_SPELL_1] = MS_ENERGY_BOLT; /* eye of devas */
-
- if (one_chance_in(25))
- ghost.values[GVAL_SPELL_2] = MS_STEAM_BALL;
- if (one_chance_in(25))
- ghost.values[GVAL_SPELL_2] = MS_PURPLE_BLAST;
- if (one_chance_in(25))
- ghost.values[GVAL_SPELL_2] = MS_HELLFIRE;
-
- if (one_chance_in(25))
- ghost.values[GVAL_SPELL_3] = MS_SMITE;
- if (one_chance_in(25))
- ghost.values[GVAL_SPELL_3] = MS_HELLFIRE_BURST;
- if (one_chance_in(12))
- ghost.values[GVAL_SPELL_3] = MS_SUMMON_DEMON_GREATER;
- if (one_chance_in(12))
- ghost.values[GVAL_SPELL_3] = MS_SUMMON_DEMON;
-
- if (one_chance_in(20))
- ghost.values[GVAL_SPELL_4] = MS_SUMMON_DEMON_GREATER;
- if (one_chance_in(20))
- ghost.values[GVAL_SPELL_4] = MS_SUMMON_DEMON;
-
- /* at least they can summon demons */
- if (ghost.values[GVAL_SPELL_4] == SPELL_NO_SPELL)
- ghost.values[GVAL_SPELL_4] = MS_SUMMON_DEMON;
-
- if (one_chance_in(15))
- ghost.values[GVAL_SPELL_5] = MS_DIG;
-
- mons_load_spells(&menv[rdem], MST_GHOST);
- }
+ ghost_demon pandemon;
+ pandemon.init_random_demon();
+ menv[rdem].set_ghost(pandemon);
+ menv[rdem].pandemon_init();
} // end generate_random_demon()
// Largest string we'll save
@@ -2127,3 +1604,127 @@ long readLong(FILE *file)
return ((long) (unsigned short) readShort(file)) << 16 |
(long) (unsigned short) readShort(file);
}
+
+////////////////////////////////////////////////////////////////////////////
+// Locking for multiuser systems
+
+// first, some file locking stuff for multiuser crawl
+#ifdef USE_FILE_LOCKING
+
+static bool lock_file_handle( FILE *handle, int type )
+{
+ struct flock lock;
+ int status;
+
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+ lock.l_type = type;
+
+#ifdef USE_BLOCKING_LOCK
+
+ status = fcntl( fileno( handle ), F_SETLKW, &lock );
+
+#else
+
+ for (int i = 0; i < 30; i++)
+ {
+ status = fcntl( fileno( handle ), F_SETLK, &lock );
+
+ // success
+ if (status == 0)
+ break;
+
+ // known failure
+ if (status == -1 && (errno != EACCES && errno != EAGAIN))
+ break;
+
+ perror( "Problems locking file... retrying..." );
+ delay( 1000 );
+ }
+
+#endif
+
+ return (status == 0);
+}
+
+static bool unlock_file_handle( FILE *handle )
+{
+ struct flock lock;
+ int status;
+
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+ lock.l_type = F_UNLCK;
+
+#ifdef USE_BLOCKING_LOCK
+
+ status = fcntl( fileno( handle ), F_SETLKW, &lock );
+
+#else
+
+ for (int i = 0; i < 30; i++)
+ {
+ status = fcntl( fileno( handle ), F_SETLK, &lock );
+
+ // success
+ if (status == 0)
+ break;
+
+ // known failure
+ if (status == -1 && (errno != EACCES && errno != EAGAIN))
+ break;
+
+ perror( "Problems unlocking file... retrying..." );
+ delay( 1000 );
+ }
+
+#endif
+
+ return (status == 0);
+}
+
+#endif
+
+FILE *lk_open(const char *mode, const std::string &file)
+{
+ FILE *handle = fopen(file.c_str(), mode);
+#ifdef SHARED_FILES_CHMOD_PUBLIC
+ chmod(file.c_str(), SHARED_FILES_CHMOD_PUBLIC);
+#endif
+
+#ifdef USE_FILE_LOCKING
+ int locktype = F_RDLCK;
+ if (mode && mode[0] != 'r')
+ locktype = F_WRLCK;
+
+ if (handle && !lock_file_handle( handle, locktype ))
+ {
+ perror( "Could not lock file... " );
+ fclose( handle );
+ handle = NULL;
+ }
+#endif
+ return handle;
+}
+
+void lk_close(FILE *handle, const char *mode, const std::string &file)
+{
+ UNUSED( mode );
+
+ if (handle == NULL || handle == stdin)
+ return;
+
+#ifdef USE_FILE_LOCKING
+ unlock_file_handle( handle );
+#endif
+
+ // actually close
+ fclose(handle);
+
+#ifdef SHARED_FILES_CHMOD_PUBLIC
+ if (mode && mode[0] == 'w')
+ chmod(file.c_str(), SHARED_FILES_CHMOD_PUBLIC);
+#endif
+}