--- deliantra/server/common/treasure.C 2007/04/16 15:36:22 1.44 +++ deliantra/server/common/treasure.C 2007/05/12 18:14:47 1.60 @@ -1,5 +1,5 @@ /* - * CrossFire, A Multiplayer game for X-windows + * CrossFire, A Multiplayer game * * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team * Copyright (C) 2002 Mark Wedel & Crossfire Development Team @@ -56,28 +56,6 @@ static tl_map_t tl_map; /* - * Initialize global archtype pointers: - */ -void -init_archetype_pointers () -{ - int prev_warn = warn_archetypes; - - warn_archetypes = 1; - - if (ring_arch == NULL) - ring_arch = archetype::find ("ring"); - if (amulet_arch == NULL) - amulet_arch = archetype::find ("amulet"); - if (staff_arch == NULL) - staff_arch = archetype::find ("staff"); - if (crown_arch == NULL) - crown_arch = archetype::find ("crown"); - - warn_archetypes = prev_warn; -} - -/* * Searches for the given treasurelist */ treasurelist * @@ -86,7 +64,7 @@ if (!name) return 0; - AUTODECL (i, tl_map.find (name)); + auto (i, tl_map.find (name)); if (i == tl_map.end ()) return 0; @@ -130,29 +108,46 @@ tl->total_chance = 0; } +#ifdef TREASURE_DEBUG +/* recursived checks the linked list. Treasurelist is passed only + * so that the treasure name can be printed out + */ +static void +check_treasurelist (const treasure *t, const treasurelist * tl) +{ + if (t->chance >= 100 && t->next_yes && (t->next || t->next_no)) + LOG (llevError, "Treasurelist %s has element that has 100%% generation, next_yes field as well as next or next_no\n", &tl->name); + + if (t->next) + check_treasurelist (t->next, tl); + + if (t->next_yes) + check_treasurelist (t->next_yes, tl); + + if (t->next_no) + check_treasurelist (t->next_no, tl); +} +#endif + /* * Reads the lib/treasure file from disk, and parses the contents * into an internal treasure structure (very linked lists) */ static treasure * -load_treasure (object_thawer &f) +read_treasure (object_thawer &f) { treasure *t = new treasure; - int value; - nroftreasures++; + f.next (); for (;;) { - coroapi::cede_every (10); - - f.next (); + coroapi::cede_to_tick_every (10); switch (f.kw) { case KW_arch: - if (!(t->item = archetype::find (f.get_str ()))) - LOG (llevError, "%s:%d treasure references unknown archetype '%s', skipping.\n", f.name, f.linenum, f.get_str ()); + t->item = archetype::get (f.get_str ()); break; case KW_list: f.get (t->name); break; @@ -163,124 +158,62 @@ case KW_nrof: f.get (t->nrof); break; case KW_magic: f.get (t->magic); break; - case KW_yes: t->next_yes = load_treasure (f); break; - case KW_no: t->next_no = load_treasure (f); break; + case KW_yes: t->next_yes = read_treasure (f); continue; + case KW_no: t->next_no = read_treasure (f); continue; case KW_end: + f.next (); return t; case KW_more: - t->next = load_treasure (f); + t->next = read_treasure (f); return t; default: - if (!f.parse_error ("treasure list")) - return t; // error + if (!f.parse_error ("treasurelist", t->name)) + return 0; return t; } - } -} - -#ifdef TREASURE_DEBUG -/* recursived checks the linked list. Treasurelist is passed only - * so that the treasure name can be printed out - */ -static void -check_treasurelist (const treasure *t, const treasurelist * tl) -{ - if (t->chance >= 100 && t->next_yes && (t->next || t->next_no)) - LOG (llevError, "Treasurelist %s has element that has 100%% generation, next_yes field as well as next or next_no\n", &tl->name); - - if (t->next) - check_treasurelist (t->next, tl); - if (t->next_yes) - check_treasurelist (t->next_yes, tl); - - if (t->next_no) - check_treasurelist (t->next_no, tl); + f.next (); + } } -#endif /* - * Opens LIBDIR/treasure and reads all treasure-declarations from it. * Each treasure is parsed with the help of load_treasure(). */ -bool -load_treasure_file (const char *filename) +treasurelist * +treasurelist::read (object_thawer &f) { - treasure *t; - int comp, line = 0; - - object_thawer f (filename); + assert (f.kw == KW_treasure || f.kw == KW_treasureone); - if (!f) - { - LOG (llevError, "Can't open treasure file.\n"); - return false; - } - - f.next (); + bool one = f.kw == KW_treasureone; + treasurelist *tl = treasurelist::get (f.get_str ()); + clear (tl); + tl->items = read_treasure (f); + if (!tl->items) + return 0; - for (;;) + /* This is a one of the many items on the list should be generated. + * Add up the chance total, and check to make sure the yes & no + * fields of the treasures are not being used. + */ + if (one) { - switch (f.kw) + for (treasure *t = tl->items; t; t = t->next) { - case KW_treasure: - case KW_treasureone: + if (t->next_yes || t->next_no) { - bool one = f.kw == KW_treasureone; - treasurelist *tl = treasurelist::get (f.get_str ()); - - clear (tl); - tl->items = load_treasure (f); - - if (!tl->items) - return false; - - /* This is a one of the many items on the list should be generated. - * Add up the chance total, and check to make sure the yes & no - * fields of the treasures are not being used. - */ - if (one) - { - for (t = tl->items; t; t = t->next) - { -#ifdef TREASURE_DEBUG - if (t->next_yes || t->next_no) - { - LOG (llevError, "Treasure %s is one item, but on treasure %s\n", &tl->name, t->item ? &t->item->name : &t->name); - LOG (llevError, " the next_yes or next_no field is set\n"); - } -#endif - tl->total_chance += t->chance; - } - } + LOG (llevError, "Treasure %s is one item, but on treasure %s\n", &tl->name, t->item ? &t->item->name : &t->name); + LOG (llevError, " the next_yes or next_no field is set\n"); } - break; - case KW_EOF: -#ifdef TREASURE_DEBUG - /* Perform some checks on how valid the treasure data actually is. - * verify that list transitions work (ie, the list that it is supposed - * to transition to exists). Also, verify that at least the name - * or archetype is set for each treasure element. - */ - for (treasurelist *tl = first_treasurelist; tl; tl = tl->next) - check_treasurelist (tl->items, tl); -#endif - return true; - - default: - if (!f.parse_error ("treasure lists")) - return false; - - break; + tl->total_chance += t->chance; } - - f.next (); } + + return tl; } /* @@ -297,17 +230,29 @@ static void put_treasure (object *op, object *creator, int flags) { - object *tmp; - - /* Bit of a hack - spells should never be put onto the map. The entire - * treasure stuff is a problem - there is no clear idea of knowing - * this is the original object, or if this is an object that should be created - * by another object. - */ - if (flags & GT_ENVIRONMENT && op->type != SPELL) + if (flags & GT_ENVIRONMENT) { - SET_FLAG (op, FLAG_OBJ_ORIGINAL); - op->insert_at (creator, creator, INS_NO_MERGE | INS_NO_WALK_ON); + /* Bit of a hack - spells should never be put onto the map. The entire + * treasure stuff is a problem - there is no clear idea of knowing + * this is the original object, or if this is an object that should be created + * by another object. + */ + //TODO: flag such as objects... as such (no drop, anybody?) + if (op->type == SPELL) + { + op->destroy (); + return; + } + + op->expand_tail (); + + if (ob_blocked (op, creator->map, creator->x, creator->y)) + op->destroy (); + else + { + SET_FLAG (op, FLAG_OBJ_ORIGINAL); + op->insert_at (creator, creator, INS_NO_MERGE | INS_NO_WALK_ON); + } } else { @@ -316,8 +261,9 @@ if ((flags & GT_APPLY) && QUERY_FLAG (creator, FLAG_MONSTER)) monster_check_apply (creator, op); - if ((flags & GT_UPDATE_INV) && (tmp = creator->in_player ())) - esrv_send_item (tmp, op); + if (flags & GT_UPDATE_INV) + if (object *tmp = creator->in_player ()) + esrv_send_item (tmp, op); } } @@ -349,7 +295,10 @@ if (t->name) { if (difficulty >= t->magic) - create_treasure (treasurelist::find (t->name), op, flag, difficulty, tries); + if (treasurelist *tl = treasurelist::find (t->name)) + create_treasure (tl, op, flag, difficulty, tries); + else + LOG (llevError, "create_all_treasures: undefined reference to treasurelist '%s'.\n", &t->name); } else { @@ -424,6 +373,12 @@ } } +void +object::create_treasure (treasurelist *tl, int flags) +{ + ::create_treasure (tl, this, flags, map ? map->difficulty : 0); +} + /* This calls the appropriate treasure creation function. tries is passed * to determine how many list transitions or attempts to create treasure * have been made. It is really in place to prevent infinite loops with @@ -444,6 +399,15 @@ return; } + if (op->flag [FLAG_TREASURE_ENV]) + { + // do not generate items when there already is something above the object + if (op->flag [FLAG_IS_FLOOR] && op->above) + return; + + flag |= GT_ENVIRONMENT; + } + if (tl->total_chance) create_one_treasure (tl, op, flag, difficulty, tries); else @@ -460,13 +424,13 @@ { difficulty = clamp (difficulty, 1, settings.max_level); - object *ob = object::create (), *tmp; + object *ob = object::create (); create_treasure (tl, ob, 0, difficulty, 0); /* Don't want to free the object we are about to return */ - tmp = ob->inv; - if (tmp != NULL) + object *tmp = ob->inv; + if (tmp) tmp->remove (); if (ob->inv) @@ -484,7 +448,6 @@ */ static int difftomagic_list[DIFFLEVELS][MAXMAGIC + 1] = { - // chance of magic difficulty // +0 +1 +2 +3 +4 {95, 2, 2, 1, 0}, // 1 @@ -520,14 +483,12 @@ { 0, 0, 0, 0, 100}, // 31 }; - /* calculate the appropriate level for wands staves and scrolls. * This code presumes that op has had its spell object created (in op->inv) * * elmex Wed Aug 9 17:44:59 CEST 2006: * Removed multiplicator, too many high-level items were generated on low-difficulty maps. */ - int level_for_item (const object *op, int difficulty) { @@ -689,7 +650,7 @@ case 4: case 5: case 6: - set_attr_value (&op->stats, r, (signed char) (bonus + get_attr_value (&op->stats, r))); + op->stats.stat (r) += bonus; break; case 7: @@ -847,10 +808,7 @@ if (op->randomitems && op->type != SPELL) { - create_treasure (op->randomitems, op, flags, difficulty, 0); - if (!op->inv) - LOG (llevDebug, "fix_generated_item: Unable to generate treasure for %s\n", op->debug_desc ()); - + create_treasure (op->randomitems, op, flags & ~GT_ENVIRONMENT, difficulty, 0); /* So the treasure doesn't get created again */ op->randomitems = 0; } @@ -1356,10 +1314,7 @@ { case KW_allowed: if (!art) - { - art = get_empty_artifact (); - nrofartifacts++; - } + art = get_empty_artifact (); { if (!strcmp (f.get_str (), "all")) @@ -1369,8 +1324,6 @@ do { - nrofallowedstr++; - if ((next = strchr (cp, ','))) *next++ = '\0'; @@ -1395,6 +1348,8 @@ case KW_object: { art->item = object::create (); + f.get (art->item->name); + f.next (); if (!art->item->parse_kv (f)) LOG (llevError, "Init_Artifacts: Could not load object.\n"); @@ -1430,6 +1385,8 @@ done: for (al = first_artifactlist; al; al = al->next) { + al->total_chance = 0; + for (art = al->items; art; art = art->next) { if (!art->chance) @@ -1445,12 +1402,10 @@ LOG (llevDebug, "done.\n"); } - /* * Used in artifact generation. The bonuses of the first object * is modified by the bonuses of the second object. */ - void add_abilities (object *op, object *change) { @@ -1465,7 +1420,7 @@ } for (i = 0; i < NUM_STATS; i++) - change_attr_value (&(op->stats), i, get_attr_value (&(change->stats), i)); + change_attr_value (&(op->stats), i, change->stats.stat (i)); op->attacktype |= change->attacktype; op->path_attuned |= change->path_attuned; @@ -1639,14 +1594,15 @@ } static int -legal_artifact_combination (object *op, artifact * art) +legal_artifact_combination (object *op, artifact *art) { int neg, success = 0; linked_char *tmp; const char *name; - if (art->allowed == (linked_char *) NULL) + if (!art->allowed) return 1; /* Ie, "all" */ + for (tmp = art->allowed; tmp; tmp = tmp->next) { #ifdef TREASURE_VERBOSE @@ -1667,6 +1623,7 @@ else if (neg) success = 1; } + return success; } @@ -1813,7 +1770,6 @@ } /* special_potion() - so that old potion code is still done right. */ - int special_potion (object *op) {