Multiples fixes in the drop script

Development for CoPaP
Chassagne
Planar Sage
Posts: 73
Joined: Tue Dec 02, 2003 2:38 pm

Multiples fixes in the drop script

Post by Chassagne »

Following some wrong drops seen in Hala, I corrected some flaws in the nw_o2_coinclude script. I'm not sure if we have the last version in Hala, at least it's a recent one. I think I'll post the whole script when I'm sure it's entirely fixed. There's something bothering me in the way a random item is chosen among a few.

There some flaws in the treasure table too, preventing certain items to drop : MISCELANEOUS / LOCKPICK instead of MISCELANEOUS / THIEF, and KIT / HEALING instead of KIT / HEALER.
Khaelindra
Groundling
Posts: 94
Joined: Wed Jan 21, 2004 5:48 am
Location: Deventer, the Netherlands

Post by Khaelindra »

That is strange, because i'm sure i found both lockpicks and healing kits as loot on Hala the last weeks... :?
Chassagne
Planar Sage
Posts: 73
Joined: Tue Dec 02, 2003 2:38 pm

Post by Chassagne »

It may come from something else. Someone dropped a Greater swordsman belt, and item which is not in the treasure table... But there was a bunch of used uninitialized variables in that script. There's supposed to be set to 0 or "", but I wouldnt bet on that, this NWNServer is so buggy...

And btw, there are two ways of dropping this kind of items. One was buggy, maybe you dropped them with the other one.
Orleron
Multiverse Scholar
Posts: 1247
Joined: Mon Nov 10, 2003 11:15 am
Location: Avlis
Contact:

Post by Orleron »

Chass, it just so happens that we got the idea to re-evaluate this script also on the Avlis Team. Vanor is looking at it with Aloro. Perhaps you can contact them so we can coordinate this change, and we can get your fixes as well. If we work on it together we can probably also get it done faster.
Avlis: http://www.avlis.org

"My name is Orleron...a dungeonmaster...two years ago I got shot through a game client...I'm in a distant part of the internet aboard these servers of escaped mental patients...my players. I've made enemies, stupid, and annoying...now all I want to do is make CoPaP a reality, to warn Earth...Look inward(to your monitor) and share the newbies I've seen..."
Vanor
Planewalker
Posts: 31
Joined: Tue Nov 25, 2003 10:51 am

Post by Vanor »

Chas, I agreed to do the bulk of the monkey work for this on Avlis.

Right now we're working towards altering the coininclude slightly, or at least I think slightly... To be more like the tables in the DMG, with better DB support for items that can drop.

PM me or something and you, Aloro and I can hammer something out that would work out rather well I think.
Chassagne
Planar Sage
Posts: 73
Joined: Tue Dec 02, 2003 2:38 pm

Post by Chassagne »

I didnt changed the "rules" that are used in this script. I just rewrote parts that were badly written, with too much tests and too much computation. There's still some work to be done, as many of the options available in that scripts are in fact not used.

I also fixed some SQL requests and some uninitialized variables.

As soon as this process is finished I'll post what I've done here. Maybe this could be a basis of the "rules" modifications you want to implement ?
Vanor
Planewalker
Posts: 31
Joined: Tue Nov 25, 2003 10:51 am

Post by Vanor »

Chassagne wrote:As soon as this process is finished I'll post what I've done here. Maybe this could be a basis of the "rules" modifications you want to implement ?
The rules won't change all that much really. But anything you do will be most welcome.

The biggest change will be in what's stored in the DB... With fairly minor changes to the script itself.

But if that's something you're interested in helping with, let me know and I'll try to fill you in with what we have in mind.
Chassagne
Planar Sage
Posts: 73
Joined: Tue Dec 02, 2003 2:38 pm

Post by Chassagne »

The fully cleaned version on this script is currently on test on the Hala server. I'll put it here as soon as I'm sure there's no bug left in it, no later than tomorrow.

The script was 1600+ lines, it's less than 1200 now. I dont know who wrote it (Brent ?), but someone should really remove the copy / paste feature on this guy's machine ;)

Bytheway, I left the unused options in it, if they are really obsolete, there's more to remove and optimize.
Orleron
Multiverse Scholar
Posts: 1247
Joined: Mon Nov 10, 2003 11:15 am
Location: Avlis
Contact:

Post by Orleron »

Cool, thanks Chass.

Vanor, make sure you use that as your starting point for any table changes you make to nw_o2_coninclude. Once you make the changes, you can run them by Chass for optomization. This will take some work off of Aloro's plate, which is good.
Avlis: http://www.avlis.org

"My name is Orleron...a dungeonmaster...two years ago I got shot through a game client...I'm in a distant part of the internet aboard these servers of escaped mental patients...my players. I've made enemies, stupid, and annoying...now all I want to do is make CoPaP a reality, to warn Earth...Look inward(to your monitor) and share the newbies I've seen..."
Vanor
Planewalker
Posts: 31
Joined: Tue Nov 25, 2003 10:51 am

Post by Vanor »

Orleron wrote:Vanor, make sure you use that as your starting point for any table changes you make to nw_o2_coninclude.
Will do.

Right now, I'm focused more on updating the DB, then the script... So it will be a bit before I'm going to look at making any sort of change to any scripts.
Chassagne
Planar Sage
Posts: 73
Joined: Tue Dec 02, 2003 2:38 pm

Post by Chassagne »

Here is the beast, it ran fine all day in Hala, no strange drop.

Just a few comments.

I put the area instead of the server name in the DB tracking code. We only have one server in Hala, and the area is a valuable information to find a buggy drop.

There is a double logging system. First, each drop (yes *each*) is logged in the DB, table item_tracking, I havent touched its structure. Second, each drop is logged in the server log file, with a bit more info, and infos in case of a buggy read in the DB.

To switch off server logs, one needs to comment all the WriteStamped... lines. To switch off DB logs, one needs to comment the call to the addTrackingItem function call.

Here is the SQL request that must be launched to get the drops with the items names and values.

Code: Select all

select date_format(DateTimeStamp, '%e %b %Y %T') Date,
 player, charname, hd, t1.resref resref, t1.name name, t1.value value
FROM treasure t1, item_tracking t2
where t1.resref = t2.resref
order by DateTimeStamp desc
Any comment / question / suggestion welcomed, of course :)

Code: Select all

#include "aps_include"

//::///////////////////////////////////////////////
//:: NW_O2_CONINCLUDE.nss
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
  This include file handles the random treasure
  distribution for treasure from creatures and containers

 [ ] Documented
*/
//:://////////////////////////////////////////////
//:: Created By:  Brent, Andrew
//:: Created On:  November - May
//:://////////////////////////////////////////////
// :: MODS
// April 23 2002: Removed animal parts. They were silly.
// May 6 2002: Added Undead to the EXCLUSION treasure list (they drop nothing now)
//  - redistributed treasure (to lessen amoun   t of armor and increase 'class specific treasure'
//  - Rangers with heavy armor prof. will be treated as Fighters else as Barbarians
//  - Gave wizards, druids and monk their own function
// MAY 29 2002: Removed the heal potion from treasure
//              Moved nymph cloak +4 to treasure bracket 6
//              Added Monk Enhancement items to random treasure

//:://////////////////////////////////////////////
//:: Modified By:  Colon, Adam (silk@blackdagger.com)
//:: Modified On:  February 2003
//:://////////////////////////////////////////////
// :: MODS
// February 20, 2003: Rewrote all Treasure Generators to use the Treasure Tables in the External Database using NWNX

// * ---------
// * CONSTANTS
// * ---------

// * tweaking constants

// * SIX LEVEL RANGES
int RANGE_1_MIN = 0;
int RANGE_1_MAX = 5;
int RANGE_2_MIN = 6;
int RANGE_2_MAX = 8;

int RANGE_3_MIN = 9;
int RANGE_3_MAX = 10;

int RANGE_4_MIN = 11;
int RANGE_4_MAX = 13;

int RANGE_5_MIN = 14;
int RANGE_5_MAX = 16;

int RANGE_6_MIN = 17;
int RANGE_6_MAX = 100;

// * NUMBER OF ITEMS APPEARING
int NUMBER_LOW_ONE   = 100; int NUMBER_MED_ONE    = 60; int NUMBER_HIGH_ONE   = 40;  int NUMBER_BOSS_ONE = 100;
int NUMBER_LOW_TWO   = 0;   int NUMBER_MED_TWO    = 30; int NUMBER_HIGH_TWO   = 40;  int NUMBER_BOSS_TWO = 0;
int NUMBER_LOW_THREE = 0;   int NUMBER_MED_THREE  = 10; int NUMBER_HIGH_THREE = 20;  int NUMBER_BOSS_THREE = 0;

int NUMBER_BOOK_ONE   = 75;
int NUMBER_BOOK_TWO   = 20;
int NUMBER_BOOK_THREE = 5;

// * AMOUNT OF GOLD BY VALUE
float LOW_MOD_GOLD    = GetLocalFloat(GetModule(), "LowModGold"); // 5
float MEDIUM_MOD_GOLD = GetLocalFloat(GetModule(), "MedModGold"); // 8
float HIGH_MOD_GOLD   = GetLocalFloat(GetModule(), "HiModGold");  // 10

// * limites pour les categories de mobs
int HD_BOSS = 30 ;
int HD_HIGH = 20 ;
int HD_MEDIUM = 10 ;

// * FREQUENCY OF ITEM TYPE APPEARING BY TREASURE TYPE
int LOW_PROB_BOOK    =  1;  int MEDIUM_PROB_BOOK   =  1; int HIGH_PROB_BOOK   =  1;
int LOW_PROB_ANIMAL  =  0;  int MEDIUM_PROB_ANIMAL =  0; int HIGH_PROB_ANIMAL =  0;
int LOW_PROB_JUNK    =  0;  int MEDIUM_PROB_JUNK   =  0; int HIGH_PROB_JUNK   =  0;
int LOW_PROB_GOLD    = 45;  int MEDIUM_PROB_GOLD   = 35; int HIGH_PROB_GOLD   = 15;
int LOW_PROB_GEM     = 19;  int MEDIUM_PROB_GEM    = 25; int HIGH_PROB_GEM    = 36;
int LOW_PROB_JEWEL   =  9;  int MEDIUM_PROB_JEWEL  =  6; int HIGH_PROB_JEWEL  = 15;
int LOW_PROB_ARCANE  =  3;  int MEDIUM_PROB_ARCANE =  3; int HIGH_PROB_ARCANE =  3;
int LOW_PROB_DIVINE  =  3;  int MEDIUM_PROB_DIVINE =  3; int HIGH_PROB_DIVINE =  3;
int LOW_PROB_AMMO    = 10;  int MEDIUM_PROB_AMMO   =  5; int HIGH_PROB_AMMO   =  3;
int LOW_PROB_KIT     =  5;  int MEDIUM_PROB_KIT    =  5; int HIGH_PROB_KIT    =  5;
int LOW_PROB_POTION  = 12;  int MEDIUM_PROB_POTION = 10; int HIGH_PROB_POTION =  9;
int LOW_PROB_TABLE2  =  2;  int MEDIUM_PROB_TABLE2 =  5; int HIGH_PROB_TABLE2 = 10;


// * readability constants

int TREASURE_LOW    = 1;
int TREASURE_MEDIUM = 2;
int TREASURE_HIGH   = 3;
int TREASURE_BOSS   = 4;
int TREASURE_BOOK   = 5;


// * JUMP_LEVEL is used in a Specific item function
// * in the case where a generic item is called for within that function
// * it will create a generic item by adding JUMP_LEVEL to the character's
// * hit die for the purposes of the treasure evaluation.
// * May 2002: Lowered JUMP_LEVEL from 3 to 2

int JUMP_LEVEL = 0;


//* Declarations
void CreateGold(object oTarget, object oAdventurer, int nTreasureType, int nModifier = 0);
void CreateGenericExotic(object oTarget, object oAdventurer, int nModifier = 0);
void CreateGenericMonkWeapon(object oTarget, object oAdventurer, int nModifier = 0);
void CreateSpecificMonkWeapon(object oTarget, object oAdventurer, int nModifier = 0);
void CreateGenericDruidWeapon(object oTarget, object oAdventurer, int nModifier = 0);
void CreateSpecificDruidWeapon(object oTarget, object oAdventurer, int nModifier = 0);
void CreateGenericWizardWeapon(object oTarget, object oAdventurer, int nModifier = 0);
void CreateSpecificWizardWeapon(object oTarget, object oAdventurer, int nModifier = 0);
int nDetermineClassToUse(object oCharacter);


// *
// * IMPLEMENTATION
// *

// Add item to Database
void addTrackingItem(string sAccount, string sName, string sServer, string sHitDice, string sResRef){
  string sSQL;

  sAccount = SQLEncodeSpecialChars(sAccount) ;
  sName = SQLEncodeSpecialChars(sName) ;

  sSQL = "INSERT INTO item_tracking (player,charname,server,hd,resref) VALUES ";
  sSQL += "('" + sAccount + "'";
  sSQL += ",'" + sName + "'";
  sSQL += ",'" + sServer + "'";
  sSQL += "," + sHitDice;
  sSQL += ",'" + sResRef + "')";

  WriteTimestampedLogEntry("Item tracking : " + sSQL) ;
  SQLExecDirect(sSQL);
}

//* made this function to help with debugging
void dbCreateItemOnObject(string sItemTemplate, object oPlayer, object oTarget = OBJECT_SELF, int nStackSize = 1) {
  if (sItemTemplate == "")
    WriteTimestampedLogEntry("Probleme : blank item passed into dbCreateItemOnObject.") ;

  if (nStackSize == 1) {
    // * checks to see if this is an arrow or throwing item and if it is
    // * it creates more

    string sRoot = GetSubString(sItemTemplate, 0, 6);
    if (GetStringLowerCase(sRoot) == "nw_wam" || GetStringLowerCase(sRoot) == "nw_wth")
      nStackSize = Random(30) + 1;
  }

  object oItem = CreateItemOnObject(sItemTemplate, oTarget, nStackSize);

  // Item Tracking Code
  if (GetIsPC(oPlayer)) {
    string sAccount = GetPCPlayerName(oPlayer);
    string sName = GetName(oPlayer);
    string sHitDice = IntToString(GetHitDice(oPlayer));
    string sArea = GetName(GetArea(oPlayer)) ;
    WriteTimestampedLogEntry("Treasure Drop, " + sName + "[" + sAccount + "] in " + sArea + " : " + sItemTemplate) ;

    addTrackingItem(sAccount, sName, sArea, sHitDice, sItemTemplate) ;
  } else {
    string sName = GetName(oPlayer);
    string sArea = GetName(GetArea(oPlayer)) ;
    WriteTimestampedLogEntry("Treasure Drop, " + sName + " in " + sArea + " : " + sItemTemplate) ;

    addTrackingItem("", sName, sArea, "", sItemTemplate) ;
  }
}


// *
// * GET FUNCTIONS
// *

// * Returns the object that either last opened the container or destroyed it
object GetLastOpener() {
  if (GetIsObjectValid(GetLastOpenedBy()) == TRUE)
    return GetLastOpenedBy();
  else if (GetIsObjectValid(GetLastKiller()) == TRUE)
    return GetLastKiller();

  return OBJECT_INVALID;
}

//::///////////////////////////////////////////////
//:: GetRange
//:: Copyright (c) 2002 Bioware Corp.
//:://////////////////////////////////////////////
/*
    Returns true if nHD matches the correct
    level range for the indicated nCategory.
    (i.e., First to Fourth level characters
    are considered Range1)
*/
//:://////////////////////////////////////////////
//:: Created By:  Brent
//:: Created On:
//:://////////////////////////////////////////////
int GetRange(int nCategory, int nHD) {
  int nMin = 0; int nMax = 0;
  switch (nCategory) {
    case 6: nMin = RANGE_6_MIN; nMax = RANGE_6_MAX; break;
    case 5: nMin = RANGE_5_MIN; nMax = RANGE_5_MAX; break;
    case 4: nMin = RANGE_4_MIN; nMax = RANGE_4_MAX; break;
    case 3: nMin = RANGE_3_MIN; nMax = RANGE_3_MAX; break;
    case 2: nMin = RANGE_2_MIN; nMax = RANGE_2_MAX; break;
    case 1: nMin = RANGE_1_MIN; nMax = RANGE_1_MAX;
  }

  return nHD >= nMin && nHD <= nMax ;
}

//::///////////////////////////////////////////////
//:: GetNumberOfItems
//:: Copyright (c) 2002 Bioware Corp.
//:://////////////////////////////////////////////
/*
    Returns the number of items to create.
*/
//:://////////////////////////////////////////////
//:: Created By:  Brent
//:: Created On:
//:://////////////////////////////////////////////
int GetNumberOfItems(int nTreasureType) {
  int nRandom = d100();

  if (nTreasureType == TREASURE_LOW) {
    if      (nRandom <= NUMBER_LOW_THREE) return 3 ;
    else if (nRandom <= NUMBER_LOW_TWO)   return 2 ;
    else return 1 ;

  } else if (nTreasureType == TREASURE_MEDIUM) {
    if      (nRandom <= NUMBER_MED_THREE) return 3 ;
    else if (nRandom <= NUMBER_MED_TWO)   return 2 ;
    else return 1 ;

  } else if (nTreasureType == TREASURE_HIGH) {
    if      (nRandom <= NUMBER_HIGH_THREE) return 3 ;
    else if (nRandom <= NUMBER_HIGH_TWO)   return 2 ;
    else return 1 ;

  } else if (nTreasureType == TREASURE_BOSS) {
    if      (nRandom <= NUMBER_BOSS_THREE) return 3 ;
    else if (nRandom <= NUMBER_BOSS_TWO)   return 2 ;
    else return 1 ;

  } else if (nTreasureType == TREASURE_BOOK) {
    if      (nRandom <= NUMBER_BOOK_THREE) return 3 ;
    else if (nRandom <= NUMBER_BOOK_TWO)   return 2 ;
    else return 1 ;
  }

  return 1 ;
}


// *
// * TREASURE GENERATION FUNCTIONS
// *
// * ---------
// * Start Code Additions by Adam Colon
// * ---------
string TREASURE_DBNAME = "treasure";
int TREASURE_VALUE_MAX_LOW    =  1700;
int TREASURE_VALUE_MAX_MEDIUM =  8000;
int TREASURE_VALUE_MAX_HIGH   = 12500;
int TREASURE_VALUE_MAX_BOSS   = 23500;

string GetRandomFromTreasureTable(string sWhere) {
  string sSQL ;
  string sRes = "" ;

  sWhere += " AND dropable=1";
  string sSQLCount = "SELECT count(*) FROM " + TREASURE_DBNAME + " " + sWhere + " ;" ;

  SQLExecDirect(sSQLCount);
  int rc = SQLFirstRow();

  if (rc == SQL_SUCCESS) {
    int iCount = StringToInt(SQLGetData(1));

    if (iCount > 0){
      int iRandom = Random(iCount);
      sSQL = "SELECT resref FROM " + TREASURE_DBNAME + " " +
             sWhere + " order by name LIMIT " + IntToString(iRandom) + ", 1 ;" ;

      SQLExecDirect(sSQL);
      rc = SQLFirstRow();

      if (rc == SQL_SUCCESS) {
        sRes = SQLGetData(1) ;
      }
    }
  }

  if (sRes == "") {
    WriteTimestampedLogEntry("Probleme lecture table de loot") ;
    WriteTimestampedLogEntry("   sSQLCount = " + sSQLCount) ;
    WriteTimestampedLogEntry("   sSQL      = " + sSQL) ;
    sRes = "NW_IT_GOLD001" ;
  }

  return sRes;
}

// Determine Treasure modifier, valued doubled on 2/23/03
int GetTreasureModifier(int nHD) {
  if (nHD >= RANGE_6_MIN) return 12 ;
  if (nHD >= RANGE_5_MIN) return 10 ;
  if (nHD >= RANGE_4_MIN) return 8 ;
  if (nHD >= RANGE_3_MIN) return 6 ;
  if (nHD >= RANGE_2_MIN) return 4 ;
  return 2 ;
}

int GetTreasureMaxValueByHD(object oTarget) {
  int nHD = GetHitDice(oTarget);
  if (nHD >= HD_BOSS)   return TREASURE_VALUE_MAX_BOSS ;
  if (nHD >= HD_HIGH)   return TREASURE_VALUE_MAX_HIGH ;
  if (nHD >= HD_MEDIUM) return TREASURE_VALUE_MAX_MEDIUM ;
  return TREASURE_VALUE_MAX_LOW ;
}

void CreateItemFinal(object oTarget, object oAdventurer, int nModifier, string sWhere) {
  int iMaxValue = GetTreasureMaxValueByHD(oTarget) ;
  sWhere += IntToString(iMaxValue) ;
  string sRes = GetRandomFromTreasureTable(sWhere);

  dbCreateItemOnObject(sRes, oAdventurer, oTarget);
}

void CreateItemByClass(object oTarget, object oAdventurer, int nModifier, string sClass) {
  string sWhere = "WHERE class LIKE '%" + sClass + "%' AND value < " ;
  CreateItemFinal(oTarget, oAdventurer, nModifier, sWhere) ;
}


// * ---------
// * End Code Additions by Adam Colon
// * ---------

// *
// * Non-Scaling Treasure
// *
void CreateBook(object oTarget, object oPlayer) {
  string sWhere = "WHERE type='BOOK' ";
  string sRes = GetRandomFromTreasureTable(sWhere);

  dbCreateItemOnObject(sRes, oPlayer, oTarget);
}

void CreateAnimalPart(object oTarget, object oPlayer) {
  string sWhere = "WHERE type='ANIMAL_PART' ";
  string sRes = GetRandomFromTreasureTable(sWhere);

  dbCreateItemOnObject(sRes, oPlayer, oTarget) ;
}

void CreateJunk(object oTarget, object oPlayer) {
  string sWhere = "WHERE type='MISCELLANEOUS' ";
  string sRes = GetRandomFromTreasureTable(sWhere);

  dbCreateItemOnObject(sRes, oPlayer, oTarget);
}

// *
// * Scaling Treasure
// *
void CreateGold(object oTarget, object oAdventurer, int nTreasureType, int nModifier = 0) {
  int nHD = GetHitDice(oAdventurer) + nModifier;
  int iTreasureModifier = GetTreasureModifier(nHD);
  int nAmount = d20(iTreasureModifier);

  float nMod = LOW_MOD_GOLD ;
  if (nTreasureType == TREASURE_MEDIUM)
    nMod = MEDIUM_MOD_GOLD;
  else if (nTreasureType == TREASURE_HIGH)
    nMod = HIGH_MOD_GOLD;

  // * always at least 1gp is created
  nAmount = FloatToInt(nAmount * nMod) ;
  nAmount = (nAmount > 0) ? nAmount : 1 ;

  dbCreateItemOnObject("NW_IT_GOLD001", oAdventurer, oTarget, nAmount);
}

void CreateGem(object oTarget, object oAdventurer, int nTreasureType, int nModifier = 0) {
  string sWhere = "WHERE type = 'GEM' AND value < " ;
  CreateItemFinal(oTarget, oAdventurer, nModifier, sWhere) ;
}

void CreateJewel(object oTarget, object oAdventurer, int nTreasureType, int nModifier = 0) {
  string sWhere = "WHERE type = 'JEWEL' AND value < " ;
  CreateItemFinal(oTarget, oAdventurer, nModifier, sWhere) ;
}

// * returns the valid upper limit for any arcane spell scroll
int TrimLevel(int nScroll, int nLevel) {
  int nMax = 5;

  switch (nLevel) {
    case 0: nMax = 4; break;
    case 1: nMax = 13; break;
    case 2: nMax = 21; break;
    case 3: nMax = 15; break;
    case 4: nMax = 17; break;
    case 5: nMax = 13; break;
    case 6: nMax = 14; break;
    case 7: nMax = 8; break;
    case 8: nMax = 9; break;
    case 9: nMax = 12;
  }

  return (nScroll < nMax) ? nScroll : nMax;
}

// * nModifier is to 'raise' the level of the oAdventurer
void CreateArcaneScroll(object oTarget, object oAdventurer, int nModifier = 0) {
  string sWhere = "WHERE type = 'SCROLL' AND subtype like '%ARCANE%' AND value < " ;
  CreateItemFinal(oTarget, oAdventurer, nModifier, sWhere) ;
}

void CreateDivineScroll(object oTarget, object oAdventurer, int nModifier=0){
  string sWhere = "WHERE type = 'SCROLL' AND subtype like '%DIVINE%' AND value < " ;
  CreateItemFinal(oTarget, oAdventurer, nModifier, sWhere) ;
}

void CreateAmmo(object oTarget, object oAdventurer, int nModifier=0) {
  string sWhere = "WHERE type = 'AMMUNITION' AND value < " ;
  CreateItemFinal(oTarget, oAdventurer, nModifier, sWhere) ;
}

void CreateTrapKit(object oTarget, object oAdventurer, int nModifier = 0) {
  string sWhere = "WHERE type = 'KIT' AND subtype = 'TRAP' AND value < " ;
  CreateItemFinal(oTarget, oAdventurer, nModifier, sWhere) ;
}

void CreateHealingKit(object oTarget, object oAdventurer, int nModifier = 0) {
  string sWhere = "WHERE type = 'KIT' AND subtype = 'HEALING' AND value < " ;
  CreateItemFinal(oTarget, oAdventurer, nModifier, sWhere) ;
}

void CreateLockPick(object oTarget, object oAdventurer, int nModifier = 0) {
  string sWhere = "WHERE type = 'MISCELLANEOUS' AND subtype = 'LOCKPICK' AND value < " ;
  CreateItemFinal(oTarget, oAdventurer, nModifier, sWhere) ;
}

void CreateKit(object oTarget, object oAdventurer, int nModifier = 0) {
  switch (Random(8)) {
    case 0: CreateTrapKit(oTarget, oAdventurer, nModifier); break;
    case 1:
    case 2:
    case 3:
    case 4: CreateHealingKit(oTarget, oAdventurer, nModifier); break;
    case 5:
    case 6:
    case 7: CreateLockPick(oTarget, oAdventurer, nModifier);
  }
}

void CreatePotion(object oTarget, object oAdventurer, int nModifier = 0) {
  string sWhere = "WHERE type = 'POTION' AND value < " ;
  CreateItemFinal(oTarget, oAdventurer, nModifier, sWhere) ;
}


//::///////////////////////////////////////////////
//:: CreateTable2GenericItem
//:: Copyright (c) 2002 Bioware Corp.
//:://////////////////////////////////////////////
/*
    Creates an item based upon the class of
    oAdventurer
*/
//:://////////////////////////////////////////////
//:: Created By:  Brent
//:: Created On:
//:://////////////////////////////////////////////
void CreateGenericMiscItem(object oTarget, object oAdventurer, int nModifier=0) {
  string sWhere = "WHERE magical = 0 " ;
  string sRes = GetRandomFromTreasureTable(sWhere);

  dbCreateItemOnObject(sRes, oAdventurer, oTarget);
}

// * this function just returns an item that is more appropriate
// * for this class. Only wizards, sorcerers, clerics, monks, rogues and bards get this
void CreateGenericClassItem(object oTarget, object oAdventurer, int nSpecific =0) {
  switch (GetLevelByPosition(1, oAdventurer)) {
    case CLASS_TYPE_DRUID:
      if (nSpecific == 0)
        CreateGenericDruidWeapon(oTarget, oAdventurer);
      else
        CreateSpecificDruidWeapon(oTarget, oAdventurer);
    break;

    case CLASS_TYPE_WIZARD:
    case CLASS_TYPE_SORCERER:
      // * 30% chance of getting a magic scroll else get a weapon suited for a wizard
      if (Random(100) + 1 > 70)
        // * grab an arcane scroll as if the wizard had +4 levels
        CreateArcaneScroll(oTarget, oAdventurer, 4);
      else if (nSpecific == 0)
        CreateGenericWizardWeapon(oTarget, oAdventurer);
      else
        CreateSpecificWizardWeapon(oTarget, oAdventurer);
    break;

    case CLASS_TYPE_CLERIC:
      CreateHealingKit(oTarget, oAdventurer);
    break;

    case CLASS_TYPE_MONK:
      if (nSpecific == 0)
        CreateGenericMonkWeapon(oTarget, oAdventurer);
      else
        CreateSpecificMonkWeapon(oTarget, oAdventurer);
    break;

    case CLASS_TYPE_ROGUE:
      if (d100() <= 60)
        CreateLockPick(oTarget, oAdventurer);
      else
        CreateItemByClass(oTarget, oAdventurer, 0, "ROGUE");
    break;

    case CLASS_TYPE_BARD:
      if (d100() <= 30)
        CreateLockPick(oTarget, oAdventurer);
      else
        CreateItemByClass(oTarget, oAdventurer, 0, "BARD");
    break;
  }
}

void CreateGenericRodStaffWand(object oTarget, object oAdventurer, int nModifier = 0) {
  string sWhere = "WHERE type = 'WEAPON' AND subtype = 'WAND' OR subtype = 'ROD' OR subtype = 'STAFF' AND value < " ;
  CreateItemFinal(oTarget, oAdventurer, nModifier, sWhere) ;
}

void CreateGenericMonkWeapon(object oTarget, object oAdventurer, int nModifier = 0) {
  string sWhere = "WHERE type = 'WEAPON' AND class LIKE '%MONK%' AND value < " ;
  CreateItemFinal(oTarget, oAdventurer, nModifier, sWhere) ;
}

void CreateSpecificMonkWeapon(object oTarget, object oAdventurer, int nModifier = 0) {
  CreateGenericMonkWeapon(oTarget, oAdventurer, JUMP_LEVEL);
}

void CreateGenericDruidWeapon(object oTarget, object oAdventurer, int nModifier = 0) {
  string sWhere = "WHERE type = 'WEAPON' AND class LIKE '%DRUID%' AND value < " ;
  CreateItemFinal(oTarget, oAdventurer, nModifier, sWhere) ;
}

void CreateSpecificDruidWeapon(object oTarget, object oAdventurer, int nModifier = 0) {
  CreateGenericDruidWeapon(oTarget, oAdventurer, JUMP_LEVEL);
}

void CreateGenericWizardWeapon(object oTarget, object oAdventurer, int nModifier = 0) {
  string sWhere = "WHERE type = 'WEAPON' AND class LIKE '%WIZARD%' OR class LIKE '%SORCERER%' AND value < " ;
  CreateItemFinal(oTarget, oAdventurer, nModifier, sWhere) ;
}

void CreateSpecificWizardWeapon(object oTarget, object oAdventurer, int nModifier = 0) {
  CreateGenericWizardWeapon(oTarget, oAdventurer, JUMP_LEVEL);
}

void CreateGenericSimple(object oTarget, object oAdventurer, int nModifier = 0) {
  string sWhere = "WHERE type = 'WEAPON' AND feat = 'SIMPLE' AND value < " ;
  CreateItemFinal(oTarget, oAdventurer, nModifier, sWhere) ;
}

void CreateGenericMartial(object oTarget, object oAdventurer, int nModifier = 0) {
  string sWhere = "WHERE type = 'WEAPON' AND feat = 'MARTIAL' AND value < " ;
  CreateItemFinal(oTarget, oAdventurer, nModifier, sWhere) ;
}

void CreateGenericExotic(object oTarget, object oAdventurer, int nModifier = 0) {
  string sWhere = "WHERE type = 'WEAPON' AND feat = 'EXOTIC' AND value < " ;
  CreateItemFinal(oTarget, oAdventurer, nModifier, sWhere) ;
}

void CreateGenericLightArmor(object oTarget, object oAdventurer, int nModifier = 0) {
  string sWhere = "WHERE type = 'ARMOR' AND feat = 'LIGHT' AND value < " ;
  CreateItemFinal(oTarget, oAdventurer, nModifier, sWhere) ;
}

void CreateGenericMediumArmor(object oTarget, object oAdventurer, int nModifier = 0) {
  string sWhere = "WHERE type = 'ARMOR' AND feat = 'MEDIUM' AND value < " ;
  CreateItemFinal(oTarget, oAdventurer, nModifier, sWhere) ;
}

void CreateGenericHeavyArmor(object oTarget, object oAdventurer, int nModifier = 0) {
  string sWhere = "WHERE type = 'ARMOR' AND feat = 'HEAVY' AND value < " ;
  CreateItemFinal(oTarget, oAdventurer, nModifier, sWhere) ;
}


// *
// * SPECIC TREASURE ITEMS (re: Named Items)
// *
void CreateSpecificMiscItem(object oTarget,object oAdventurer) {
  CreateGenericMiscItem(oTarget, oAdventurer, JUMP_LEVEL);
}

void CreateSpecificRodStaffWand(object oTarget, object oAdventurer) {
  CreateGenericRodStaffWand(oTarget, oAdventurer, JUMP_LEVEL);
}

void CreateSpecificSimple(object oTarget, object oAdventurer) {
  CreateGenericSimple(oTarget, oAdventurer, JUMP_LEVEL);
}

void CreateSpecificMartial(object oTarget, object oAdventurer) {
  CreateGenericMartial(oTarget, oAdventurer, JUMP_LEVEL);
}

void CreateSpecificExotic(object oTarget, object oAdventurer) {
  CreateGenericExotic(oTarget, oAdventurer, JUMP_LEVEL);
}

void CreateSpecificLightArmor(object oTarget, object oAdventurer) {
  CreateGenericLightArmor(oTarget, oAdventurer, JUMP_LEVEL);
}

void CreateSpecificMediumArmor(object oTarget, object oAdventurer) {
  CreateGenericMediumArmor(oTarget, oAdventurer, JUMP_LEVEL);
}

void CreateSpecificHeavyArmor(object oTarget, object oAdventurer) {
  CreateGenericHeavyArmor(oTarget, oAdventurer, JUMP_LEVEL);
}

// * if nSpecific is = 1 then spawn in 'named' items at the higher levels
void CreateTable2Item(object oTarget, object oAdventurer, int nSpecific=0) {
  string sItem          = "NW_IT_GOLD001" ;

  // 2 Means to treat the ranger as a barbarian. A 1 is to treat it as a fighter
  int nSpecialRanger = 0 ;


  // * May 2002: Changed using Preston's multiclass function
  // * it randomly chooses one of your classes
  int nClass =  nDetermineClassToUse(oAdventurer);


  // * SPECIAL RANGER BEHAVIOR
  // * If the ranger has the Heavy Armor proficiency, will treat the ranger
  if ( nClass == CLASS_TYPE_RANGER && GetHasFeat(FEAT_ARMOR_PROFICIENCY_HEAVY))
    nSpecialRanger = 1;
  else if (nClass == CLASS_TYPE_RANGER)
    nSpecialRanger = 2;

  //* SETUP probabilities based on Class
// if ( nClass == CLASS_TYPE_FIGHTER || nClass == CLASS_TYPE_PALADIN || nSpecialRanger == 1) {
  int nProbMisc         = 20;
  int nProbClass        = 0;
  int nProbRodStaffWand = 5;
  int nProbSimple       = 5;
  int nProbMartial      = 20;
  int nProbExotic       = 10;
  int nProbLight        = 5;
  int nProbMedium       = 15;
  int nProbHeavy        = 20;

  if (nClass == CLASS_TYPE_WIZARD || nClass == CLASS_TYPE_SORCERER) {
    nProbMisc         = 40;
    nProbClass        = 30;
    nProbRodStaffWand = 15;
    nProbSimple       = 3;
    nProbMartial      = 3;
    nProbExotic       = 3;
    nProbLight        = 2;
    nProbMedium       = 2;
    nProbHeavy        = 2;
  } else if (nClass == CLASS_TYPE_BARBARIAN || nSpecialRanger == 2) {
    nProbMisc         = 20;
    nProbClass        = 0;
    nProbRodStaffWand = 5;
    nProbSimple       = 17;
    nProbMartial      = 27;
    nProbExotic       = 15;
    nProbLight        = 8;
    nProbMedium       = 5;
    nProbHeavy        = 3;
  } else if (nClass == CLASS_TYPE_CLERIC) {
    nProbMisc         = 20;
    nProbClass        = 10;
    nProbRodStaffWand = 10;
    nProbSimple       = 25;
    nProbMartial      = 7;
    nProbExotic       = 5;
    nProbLight        = 5;
    nProbMedium       = 8;
    nProbHeavy        = 10;
  } else if (nClass == CLASS_TYPE_DRUID) {
    nProbMisc         = 20;
    nProbClass        = 25;
    nProbRodStaffWand = 15;
    nProbSimple       = 10;
    nProbMartial      = 5;
    nProbExotic       = 5;
    nProbLight        = 10;
    nProbMedium       = 5;
    nProbHeavy        = 5;
  } else if (nClass == CLASS_TYPE_MONK) {
    nProbMisc         = 20;
    nProbClass        = 50;
    nProbRodStaffWand = 2;
    nProbSimple       = 7;
    nProbMartial      = 2;
    nProbExotic       = 7;
    nProbLight        = 4;
    nProbMedium       = 4;
    nProbHeavy        = 4;
  } else if (nClass == CLASS_TYPE_ROGUE) {
    nProbMisc         = 25;
    nProbClass        = 10;
    nProbRodStaffWand = 10;
    nProbSimple       = 25;
    nProbMartial      = 5;
    nProbExotic       = 5;
    nProbLight        = 10;
    nProbMedium       = 5;
    nProbHeavy        = 5;
  } else if (nClass == CLASS_TYPE_BARD) {
    nProbMisc         = 25;
    nProbClass        = 5;
    nProbRodStaffWand = 5;
    nProbSimple       = 25;
    nProbMartial      = 10;
    nProbExotic       = 10;
    nProbLight        = 10;
    nProbMedium       = 5;
    nProbHeavy        = 5;
  }

  //* Create Items based on Probabilities
  int nRandom = d100() ;
  if (nRandom <= nProbMisc) {
    if (nSpecific == 0)
      CreateGenericMiscItem(oTarget, oAdventurer);
    else
      CreateSpecificMiscItem(oTarget, oAdventurer);
    return ;
  }

  nRandom -= nProbMisc ;
  if (nRandom <= nProbClass) {
    CreateGenericClassItem(oTarget, oAdventurer, nSpecific);
    return ;
  }

  nRandom -= nProbClass ;
  if (nRandom <= nProbRodStaffWand) {
    if (nSpecific == 0)
      CreateGenericRodStaffWand(oTarget, oAdventurer) ;
    else
      CreateSpecificRodStaffWand(oTarget, oAdventurer);
    return ;
  }

  nRandom -= nProbRodStaffWand ;
  if (nRandom <= nProbSimple) {
    if (nSpecific == 0)
      CreateGenericSimple(oTarget, oAdventurer);
    else
      CreateSpecificSimple(oTarget, oAdventurer);
    return ;
  }

  nRandom -= nProbSimple ;
  if (nRandom <= nProbMartial) {
    if (nSpecific == 0)
      CreateGenericMartial(oTarget, oAdventurer);
    else
      CreateSpecificMartial(oTarget, oAdventurer);
    return ;
  }

  nRandom -= nProbMartial ;
  if (nRandom <= nProbExotic) {
    if (nSpecific == 0)
      CreateGenericExotic(oTarget, oAdventurer);
    else
      CreateSpecificExotic(oTarget, oAdventurer);
    return ;
  }

  nRandom -= nProbExotic ;
  if (nRandom <= nProbLight) {
    if (nSpecific == 0)
      CreateGenericLightArmor(oTarget, oAdventurer);
    else
      CreateSpecificLightArmor(oTarget, oAdventurer);
    return ;
  }

  nRandom -= nProbLight ;
  if (nRandom <= nProbMedium) {
    if (nSpecific == 0)
      CreateGenericMediumArmor(oTarget, oAdventurer);
    else
      CreateSpecificMediumArmor(oTarget, oAdventurer);
    return ;
  }

  nRandom -= nProbMedium ;
  if (nRandom <= nProbHeavy) {
    if (nSpecific == 0)
      CreateGenericHeavyArmor(oTarget, oAdventurer);
    else
      CreateSpecificHeavyArmor(oTarget, oAdventurer);
    return ;
  }
}

//::///////////////////////////////////////////////
//:: GenerateTreasure
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
   Generate Treasure
   NOTE: When used by NPCs, the treasure is scaled
   to how powerful the NPC is.

   If used by containers, it is scaled by how
   powerful the PC is.

   PARAMETERS
   oLastOpener = The creature that opened the container
   oCreateOn = The place to put the treasure. If this is
    invalid then the treasure is placed on oLastOpener


*/
//:://////////////////////////////////////////////
//:: Created By:  Andrew
//:: Created On:
//:://////////////////////////////////////////////
void GenerateTreasure(int nTreasureType, object oLastOpener, object oCreateOn) {
  WriteTimestampedLogEntry("Generation de drop : ") ;
  WriteTimestampedLogEntry("   player = " + GetName(oLastOpener) + " [" + GetPCPlayerName(oLastOpener) + "]") ;
  WriteTimestampedLogEntry("   niveau = " + IntToString(GetHitDice(oLastOpener))) ;
  WriteTimestampedLogEntry("   niveau du mob = " + IntToString(GetHitDice(oCreateOn))) ;

  // * abort treasure if no one opened the container
  if (GetIsObjectValid(oLastOpener) == FALSE) {
    return;
  }

  // * if no valid create on object, then create on oLastOpener
  if (oCreateOn == OBJECT_INVALID) {
    oCreateOn = oLastOpener;
  }

  // * VARIABLES
  int nProbBook   = LOW_PROB_BOOK;
  int nProbAnimal = LOW_PROB_ANIMAL;
  int nProbJunk   = LOW_PROB_JUNK;
  int nProbGold   = LOW_PROB_GOLD;
  int nProbGem    = LOW_PROB_GEM;
  int nProbJewel  = LOW_PROB_JEWEL;
  int nProbArcane = LOW_PROB_ARCANE;
  int nProbDivine = LOW_PROB_DIVINE;
  int nProbAmmo   = LOW_PROB_AMMO ;
  int nProbKit    = LOW_PROB_KIT;
  int nProbPotion = LOW_PROB_POTION;
  int nProbTable2 = LOW_PROB_TABLE2;

  int nSpecific = 0;
  int i = 0;
  int nNumberItems = GetNumberOfItems(nTreasureType);

  // * Set Treasure Type Values
  if (nTreasureType == TREASURE_MEDIUM) {
    nProbBook   = MEDIUM_PROB_BOOK;
    nProbAnimal = MEDIUM_PROB_ANIMAL;
    nProbJunk   = MEDIUM_PROB_JUNK;
    nProbGold   = MEDIUM_PROB_GOLD;
    nProbGem    = MEDIUM_PROB_GEM;
    nProbJewel  = MEDIUM_PROB_JEWEL;
    nProbArcane = MEDIUM_PROB_ARCANE;
    nProbDivine = MEDIUM_PROB_DIVINE;
    nProbAmmo   = MEDIUM_PROB_AMMO ;
    nProbKit    = MEDIUM_PROB_KIT;
    nProbPotion = MEDIUM_PROB_POTION;
    nProbTable2 = MEDIUM_PROB_TABLE2;
  } else if (nTreasureType == TREASURE_HIGH) {
    nProbBook   = HIGH_PROB_BOOK;
    nProbAnimal = HIGH_PROB_ANIMAL;
    nProbJunk   = HIGH_PROB_JUNK;
    nProbGold   = HIGH_PROB_GOLD;
    nProbGem    = HIGH_PROB_GEM;
    nProbJewel  = HIGH_PROB_JEWEL;
    nProbArcane = HIGH_PROB_ARCANE;
    nProbDivine = HIGH_PROB_DIVINE;
    nProbAmmo   = HIGH_PROB_AMMO ;
    nProbKit    = HIGH_PROB_KIT;
    nProbPotion = HIGH_PROB_POTION;
    nProbTable2 = HIGH_PROB_TABLE2;
  } else if (nTreasureType == TREASURE_BOSS) {
    nProbTable2 = 100;
    nSpecific   = 1;
  } else if (nTreasureType == TREASURE_BOOK) {
    nProbBook   = 90;
    nProbArcane = 6;
    nProbDivine = 4;
  }

  for (i = 1; i <= nNumberItems; i++) {
    int nRandom = d100();

    if (nRandom <= nProbAnimal) {
      CreateAnimalPart(oCreateOn, oLastOpener) ;
      return ;
    }

    nRandom -= nProbAnimal ;
    if (nRandom <= nProbJunk) {
      CreateJunk(oCreateOn, oLastOpener) ;
      return ;
    }

    nRandom -= nProbJunk ;
    if (nRandom <= nProbGold + nProbBook) {
      CreateGold(oCreateOn, oLastOpener, nTreasureType);
      return ;
    }

    nRandom -= nProbGold + nProbBook ;
    if (nRandom <= nProbGem) {
      CreateGem(oCreateOn, oLastOpener, nTreasureType) ;
      return ;
    }

    nRandom -= nProbGem ;
    if (nRandom <= nProbJewel) {
      CreateJewel(oCreateOn, oLastOpener, nTreasureType) ;
      return ;
    }

    nRandom -= nProbJewel ;
    if (nRandom <= nProbArcane) {
      CreateArcaneScroll(oCreateOn, oLastOpener, nTreasureType) ;
      return ;
    }

    nRandom -= nProbArcane ;
    if (nRandom <= nProbDivine) {
      CreateDivineScroll(oCreateOn, oLastOpener);
      return ;
    }

    nRandom -= nProbDivine ;
    if (nRandom <= nProbAmmo) {
      CreateAmmo(oCreateOn, oLastOpener);
      return ;
    }

    nRandom -= nProbAmmo ;
    if (nRandom <= nProbKit) {
      CreateKit(oCreateOn, oLastOpener);
      return ;
    }

    nRandom -= nProbKit ;
    if (nRandom <= nProbPotion) {
      CreatePotion(oCreateOn, oLastOpener) ;
      return ;
    }

    nRandom -= nProbTable2 ;
    if (nRandom <= nProbTable2) {
      CreateTable2Item(oCreateOn, oLastOpener, nSpecific) ;
      return ;
    }
  }
}

void GenerateLowTreasure(object oLastOpener, object oCreateOn=OBJECT_INVALID) {
  GenerateTreasure(TREASURE_LOW, oLastOpener, oCreateOn);
}

void GenerateMediumTreasure(object oLastOpener, object oCreateOn=OBJECT_INVALID) {
  GenerateTreasure(TREASURE_MEDIUM, oLastOpener, oCreateOn);
}

void GenerateHighTreasure(object oLastOpener, object oCreateOn=OBJECT_INVALID) {
 GenerateTreasure(TREASURE_HIGH, oLastOpener, oCreateOn);
}

void GenerateBossTreasure(object oLastOpener, object oCreateOn=OBJECT_INVALID) {
  GenerateTreasure(TREASURE_BOSS, oLastOpener, oCreateOn);
}

void GenerateBookTreasure(object oLastOpener, object oCreateOn=OBJECT_INVALID) {
  GenerateTreasure(TREASURE_BOOK, oLastOpener, oCreateOn);
}


//::///////////////////////////////////////////////
//:: GenerateNPCTreasure
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
   Preferrably called from OnSpawn scripts.
   Use the random treasure functions to generate
   appropriate treasure for the creature to drop.
*/
//:://////////////////////////////////////////////
//:: Created By: Brent
//:: Created On: January 2002
//:://////////////////////////////////////////////

void GenerateNPCTreasure(int nTreasureValue=1,
                         object oTreasureGetter=OBJECT_SELF,
                         object oKiller=OBJECT_SELF) {
  //DestroyObject(OBJECT_SELF);
  // * if I am an animal ,then give me animal stuff instead
  if (GetObjectType(oTreasureGetter) == OBJECT_TYPE_CREATURE) {
    if (
        (GetRacialType(oTreasureGetter) == RACIAL_TYPE_UNDEAD) ||
        (GetRacialType(oTreasureGetter) == RACIAL_TYPE_ANIMAL) ||
        (GetRacialType(oTreasureGetter) == RACIAL_TYPE_BEAST) ||
        (GetRacialType(oTreasureGetter) == RACIAL_TYPE_MAGICAL_BEAST) ||
        (GetRacialType(oTreasureGetter) == RACIAL_TYPE_VERMIN)
       ) {
      // CreateAnimalPart(oTreasureGetter);
      // April 23 2002: Removed animal parts. They are silly.
        return ;
    }
  }

  if (nTreasureValue == 1) {
    // April 2002: 30% chance of not getting any treasure now
    // if a creature
    if (Random(100) + 1 >= 75) {
      GenerateTreasure(TREASURE_LOW, oTreasureGetter, oKiller);
    }
  } else if (nTreasureValue == 2) {
    GenerateTreasure(TREASURE_MEDIUM, oTreasureGetter, oKiller);
  } else if (nTreasureValue == 3) {
    GenerateTreasure(TREASURE_HIGH, oTreasureGetter, oKiller);
  } else if (nTreasureValue == 4) {
    GenerateBossTreasure(oKiller, oTreasureGetter);
  }
}

// *
// * Theft Prevention
// *

//::///////////////////////////////////////////////
//:: ShoutDisturbed
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*

*/
//:://////////////////////////////////////////////
//:: Created By:
//:: Created On:
//:://////////////////////////////////////////////

// * Container shouts if disturbed
void ShoutDisturbed() {
  if (GetIsDead(OBJECT_SELF) == TRUE) {
    object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(OBJECT_SELF), TRUE, OBJECT_TYPE_CREATURE);
    // Cycle through the targets within the spell shape until an invalid object is captured.
    while (GetIsObjectValid(oTarget)) {
      if (GetFactionEqual(oTarget, OBJECT_SELF) == TRUE) {
        // * Make anyone who is a member of my faction hostile if I am violated
        object oAttacker = GetLastAttacker();
        SetIsTemporaryEnemy(oAttacker,oTarget);
        AssignCommand(oTarget, ActionAttack(oAttacker));
      }
      oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(OBJECT_SELF), TRUE, OBJECT_TYPE_CREATURE);
    }
  } else if (GetIsOpen(OBJECT_SELF) == TRUE) {
    object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(OBJECT_SELF), TRUE, OBJECT_TYPE_CREATURE);
    // Cycle through the targets within the spell shape until an invalid object is captured.
    while (GetIsObjectValid(oTarget)) {
      if (GetFactionEqual(oTarget, OBJECT_SELF) == TRUE) {
        // * Make anyone who is a member of my faction hostile if I am violated
        object oAttacker = GetLastOpener();
        SetIsTemporaryEnemy(oAttacker,oTarget);
        AssignCommand(oTarget, ActionAttack(oAttacker));
      }
      oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(OBJECT_SELF), TRUE, OBJECT_TYPE_CREATURE);
    }
  }
}


//::///////////////////////////////////////////////
//:: Determine Class to Use
//:: Copyright (c) 2002 Bioware Corp.
//:://////////////////////////////////////////////
/*
    Determines which of a NPCs three classes to
    use in the random treasure system
*/
//:://////////////////////////////////////////////
//:: Created By: Preston Watamaniuk
//:: Created On: April 4, 2002
//:://////////////////////////////////////////////

int nDetermineClassToUse(object oCharacter) {
  int nClass;
  int nTotal = GetHitDice(oCharacter);

  if (nTotal < 1) {
    nTotal = 1;
  }

  float fTotal = IntToFloat(nTotal) ;

  int nClass1 =  GetClassByPosition(1, oCharacter);
  int nState1 = FloatToInt((IntToFloat(GetLevelByClass(nClass1, oCharacter)) / fTotal) * 100);

  int nClass2 = GetClassByPosition(2, oCharacter);
  int nState2 = FloatToInt((IntToFloat(GetLevelByClass(nClass2, oCharacter)) / fTotal) * 100) + nState1;

  int nClass3 = GetClassByPosition(3, oCharacter);
  int nState3 = FloatToInt((IntToFloat(GetLevelByClass(nClass3, oCharacter)) / fTotal) * 100) + nState2;

  int nUseClass = d100();

  if(nUseClass <= nState1) {
    nClass = nClass1;
  } else if(nUseClass > nState1 && nUseClass <= nState2) {
    nClass = nClass2;
  } else {
    nClass = nClass3;
  }

  return nClass;
}
Khaelindra
Groundling
Posts: 94
Joined: Wed Jan 21, 2004 5:48 am
Location: Deventer, the Netherlands

Post by Khaelindra »

WriteTimestampedLogEntry(" niveau du mob = " + IntToString(GetHitDice(oCreateOn))) ;
:shock:

Parlez-vous Francais? :wink: :lol:

Gosh, must be nice to be able to read this kind of stuff like it was plain text. :D
Chassagne
Planar Sage
Posts: 73
Joined: Tue Dec 02, 2003 2:38 pm

Post by Chassagne »

Err yes sorry, comments and logs are in french... *coughs* So what's wrong ? :wink:
Chassagne
Planar Sage
Posts: 73
Joined: Tue Dec 02, 2003 2:38 pm

Post by Chassagne »

Weird drops are still seen in Hala, less than before (they used to appear by hundreds, there are now one here and there), but still.

People saw a very precise mob, lvl 11, dropping a plate +3. I checked that mob, it's part of an encounter. His OnDeath script is the nw_c2_default7, overwritten, calling the GenerateLowTreasure from the script nw_o2_coninclude that I posted here.
1) The +3 plate should not drop out of a lvl 11 mob
2) This drop is not in the logs, nor in the server logs, nor in the DB logs. So that script has *not* been called to generate the drop, which explains 1).

Have you seen this thing on Avlis or other world ? If yes, any hint on fixing that ? It's really annoying, and I'm pretty sure that +5 items are still being dropped, without being reported.
Orleron
Multiverse Scholar
Posts: 1247
Joined: Mon Nov 10, 2003 11:15 am
Location: Avlis
Contact:

Post by Orleron »

Are you sure that it wasn't a static drop, meaning the NPC was made with the +3 plate in the toolset and the plate was marked as dropable?
Avlis: http://www.avlis.org

"My name is Orleron...a dungeonmaster...two years ago I got shot through a game client...I'm in a distant part of the internet aboard these servers of escaped mental patients...my players. I've made enemies, stupid, and annoying...now all I want to do is make CoPaP a reality, to warn Earth...Look inward(to your monitor) and share the newbies I've seen..."
Chassagne
Planar Sage
Posts: 73
Joined: Tue Dec 02, 2003 2:38 pm

Post by Chassagne »

I'm sure it was not that yes, we've checked everything in parallel with Flakey, and came to the same conclusion.

Bytheway, if it was a static drop from that mob, it should drop it everytime, right ? It doesnt. Currently dozens of this mobs are killed every week, so we should have seen a major drop of the +3 plate price on the market ;)
Orleron
Multiverse Scholar
Posts: 1247
Joined: Mon Nov 10, 2003 11:15 am
Location: Avlis
Contact:

Post by Orleron »

Well, not if you have many similar kinds of mobs grouped into the same encounter. If the encounter has a bunch of different mobs in it, and one of them has the plate, and it is marked "unique", you won't see it as often. Just something to check.
Avlis: http://www.avlis.org

"My name is Orleron...a dungeonmaster...two years ago I got shot through a game client...I'm in a distant part of the internet aboard these servers of escaped mental patients...my players. I've made enemies, stupid, and annoying...now all I want to do is make CoPaP a reality, to warn Earth...Look inward(to your monitor) and share the newbies I've seen..."
Chassagne
Planar Sage
Posts: 73
Joined: Tue Dec 02, 2003 2:38 pm

Post by Chassagne »

Of course we have checked that.
Khaelindra
Groundling
Posts: 94
Joined: Wed Jan 21, 2004 5:48 am
Location: Deventer, the Netherlands

Post by Khaelindra »

Chassagne wrote:It's really annoying, and I'm pretty sure that +5 items are still being dropped, without being reported.
Chass,

i really urge you to put up some sort of check-list on the HALA-boards, or if that becomes too long, some sort of "price-checker" on a few choice locations that can give the nominal value of an item. I for one wouldn't know every time if a drop is legal or not, because it's not a straight +2 yes +3 no system. I found a +5 amulet on Avlis a few months ago, asked the Team, and it was allowed, as apparently the value was lower then a weapon +3. I for one don't know when to ask...Boots of Hardiness +3? Light Crossbow+3? Amulet of Protection +3? An amulet of Willpower +3? A cloak of hiding +3? Somewhere along that line is a border, but the players don't know it.


If this is universal for all worlds using the AVLIS-dropsystem, i suggest this be implremented in other worlds as well. Would save the Teams a lot of questions about items being legal or not.

M.
Chassagne
Planar Sage
Posts: 73
Joined: Tue Dec 02, 2003 2:38 pm

Post by Chassagne »

Ok, I'll post the drop table on the team boards.
Orleron
Multiverse Scholar
Posts: 1247
Joined: Mon Nov 10, 2003 11:15 am
Location: Avlis
Contact:

Post by Orleron »

The other thing I can think of that would do this is an incorrectly given gold value in the database table. One time I had a +3 hammer set to a value of 20 gold pieces, and the thing started dropping like crazy. See if maybe some of your weapons are mis-valued.
Avlis: http://www.avlis.org

"My name is Orleron...a dungeonmaster...two years ago I got shot through a game client...I'm in a distant part of the internet aboard these servers of escaped mental patients...my players. I've made enemies, stupid, and annoying...now all I want to do is make CoPaP a reality, to warn Earth...Look inward(to your monitor) and share the newbies I've seen..."
Chassagne
Planar Sage
Posts: 73
Joined: Tue Dec 02, 2003 2:38 pm

Post by Chassagne »

I've also checked that yesterday. The treasure table is on the Hala team board, so if there's a flaw I didnt see, I guess someone else will...
Titanium Dragon
Clueless Prime
Posts: 18
Joined: Tue Nov 25, 2003 2:39 am

Post by Titanium Dragon »

Cross-posted from the Hala Team boards at the request of Chassange:
Chassagne wrote:This is the table used in Avlis. As said, items of value > 23500 are dropped from lvl 30+ mobs, items > 12500 from lvl 20+ mobs etc...
Then the variable names are very misleading; it says MAX when it really should be MIN. :roll: Not saying to change them, but its still misleading.

Also, when was this table taken from Avlis? I'm pretty sure the Thieves' Hood shouldn't be on it anyway, as it is a banned CoPaP item and thus should only be very rarely given out by DMs.
I dont think we have any lvl 30+ mob in Hala. So yes, these +4 and +5 items are in the table, but they are not dropped. The two higher drops the scripted I fixed generated are a Periapt of wisdow +1 and an Amulet of Natural Armor +2. There are spells too, a bit higher : Mordenkainen's Disjunction and Weird.
Yes, but they obviously are dropping. Possible reason: If it generates treasure from any value higher than x, then if you didn't limit the range above as well as below then a level 1 creature could theoretically drop a boss-level item. Not sure if that's the case; I'm still going through the treasue code. Just throwing an idea out there.

Other possible issues:

Is the GenerateNPCTreasure script still used? If so, that could be a source of problems if something has a mismarked nTreasureValue; I can imagine a standard bioware creature might have a preset nTreasureValue if the scripts haven't been changed (just an idea). Also, there is apparently a 25% chance to get treasure from a nTreasureValue=1 creature, but an nTreasureValue>1 creature (i.e. 2, 3, or 4) will always generate treasure in that script. Not sure if that script is still being used, but if it is standard biocreatures that are causing the problems, I'd check out if that script is being called.
// Determine Treasure modifier, valued doubled on 2/23/03
int GetTreasureModifier(int nHD) {
if (nHD >= RANGE_6_MIN) return 12 ;
if (nHD >= RANGE_5_MIN) return 10 ;
if (nHD >= RANGE_4_MIN) return 8 ;
if (nHD >= RANGE_3_MIN) return 6 ;
if (nHD >= RANGE_2_MIN) return 4 ;
return 2 ;
}

int GetTreasureMaxValueByHD(object oTarget) {
int nHD = GetHitDice(oTarget);
if (nHD >= HD_BOSS) return TREASURE_VALUE_MAX_BOSS ;
if (nHD >= HD_HIGH) return TREASURE_VALUE_MAX_HIGH ;
if (nHD >= HD_MEDIUM) return TREASURE_VALUE_MAX_MEDIUM ;
return TREASURE_VALUE_MAX_LOW ;
}
In both those instances it is using the hit dice of the creature rather than the creature's CR. As HD tends to run higher (in some cases, far higher) than CR, you'll end up producing higher-level treasure for monsters that don't really warrant it. A good example of this is the Roc from the Monsterous Manual: It has a CR of 9, but 18 HD. Might be a good change to make, compare to CR rather than HD. A colossal skeleton has 32 HD but only a CR of 9 - this would mean a pretty wussy creature would generate boss level treasure!

Other than that... I dunno. SQL confuses me somewhat; I'll have to read up on it again to check out the most important part (reading off the treasure table itself). Anyway, just my thoughts at the moment.

A lot of it seems to be bio-code that has been edited by two or three people - someone at bioware, Silk, and you.

Thing is, stuff on Hala is dropping at a much higher rate than on Avlis. Fighting bandits tody I was getting many more drops than is usual on Avlis. Thus, whatever problem is occuring with the script frequency is occuring only on Hala; I know I don't get drops at this rate on Avlis. It is probably an issue resulting from this code; how old is it? Has Avlis updated theirs?

As for drops that aren't generated by the treasure script - either you've got another treasure script running side-by-side with this one, or creatures have stuff that is marked as droppable. Those are the only two possibilities. This is assuming it is not a result of incorrect drops which ARE part of the treasure script - I know the Avlis team has seen an influx of a certain item on the treasure table (Ring of Elemental Resistance). Plate +3 is also on there. Idea - put something from us on the tresure table, or better yet, a number of things. If we see them drop incorrectly, then we know the bug is with our treasure generation scripts spawning them incorrectly. If it is a different bug, we won't see them drop.

EDIT: And Chassagne, did you see my comment about

Improved Robes of the Old Order
| 0 |

They shouldn't cost zero gold as they have an enhancement bonus of +2. Thus they must be marked plot incorrectly.
Chassagne
Planar Sage
Posts: 73
Joined: Tue Dec 02, 2003 2:38 pm

Post by Chassagne »

it says MAX when it really should be MIN
It means that the max value of a low level treasure is 1700, which is correct. I think "MAX" is the right thing to use here.

Code: Select all

TREASURE_VALUE_MAX_LOW = 1700; 
TREASURE_VALUE_MAX_MEDIUM = 8000; 
TREASURE_VALUE_MAX_HIGH = 12500; 
TREASURE_VALUE_MAX_BOSS = 23500;
It really seems that you need to tell things 4 or 5 times on this board to get a reasonable chance to be red...
I'm SURE that some drops from well-known mobs in Hala are not generated by this script, as they should. It appears clearly from trustable players reports, crossed by what's in the logs (both DB and server).
Thing is, stuff on Hala is dropping at a much higher rate than on Avlis. Fighting bandits tody I was getting many more drops than is usual on Avlis.
This is a feeling you have, what kind of drops were you getting ? Can you post the exact characteristics of the encounters / mobs you killed (resref of them would be great, so that I can check them). Could it be possible then to make a test on Avlis, in a dummy area, putting this exact same mob (resref wise), go with your char and kill them to see how the Avlis system behave ?
As for drops that aren't generated by the treasure script - either you've got another treasure script running side-by-side with this one, or creatures have stuff that is marked as droppable.
... either there is a server bug that doesnt call our script. As I already said, everything you mention here as been double checked (we are not that dumb you know ?).

All the comments on the rules implemented by the script should be discussed as a CoPaP thing imho.
Titanium Dragon
Clueless Prime
Posts: 18
Joined: Tue Nov 25, 2003 2:39 am

Post by Titanium Dragon »

Chassagne wrote:
it says MAX when it really should be MIN
It means that the max value of a low level treasure is 1700, which is correct. I think "MAX" is the right thing to use here.

Code: Select all

TREASURE_VALUE_MAX_LOW = 1700; 
TREASURE_VALUE_MAX_MEDIUM = 8000; 
TREASURE_VALUE_MAX_HIGH = 12500; 
TREASURE_VALUE_MAX_BOSS = 23500;
That's what I thought, but you said otherwise on the Hala boards. That's why I was confused :P Anyway, if 23.5K is the max, then why are there drops on the table with values above that? Sounds like you're asking for trouble to me with that.
It really seems that you need to tell things 4 or 5 times on this board to get a reasonable chance to be red...
I'm SURE that some drops from well-known mobs in Hala are not generated by this script, as they should. It appears clearly from trustable players reports, crossed by what's in the logs (both DB and server).
If this was an innate problem with NWN we'd know it, as other servers would have reported the same problem. Given the items spawning are on the treasure chart, it is fairly natural to assume there is something going on with the treasure script. Is there any way for those functions to be called outside of the treasure script? Is it possible the scripts are being called independently without going through the logging? Are other drops being logged properly by the script?

If NOT, then what other scripts could be firing? There are only 10 or so scripts on a creature; there are only so many possible causes for the abnormal drops - one of those ten scripts or an ISD on the creature. We know it is not an ISD on the creature, therefore it must be one of those scripts called - on spawn, on perception, ect.
Thing is, stuff on Hala is dropping at a much higher rate than on Avlis. Fighting bandits tody I was getting many more drops than is usual on Avlis.
This is a feeling you have, what kind of drops were you getting ? Can you post the exact characteristics of the encounters / mobs you killed (resref of them would be great, so that I can check them). Could it be possible then to make a test on Avlis, in a dummy area, putting this exact same mob (resref wise), go with your char and kill them to see how the Avlis system behave ?
Its pretty hard to do, given Hala has a far higher concentration of creatures/area than Avlis.
As for drops that aren't generated by the treasure script - either you've got another treasure script running side-by-side with this one, or creatures have stuff that is marked as droppable.
... either there is a server bug that doesnt call our script. As I already said, everything you mention here as been double checked (we are not that dumb you know ?).
A "server bug" must be a script of some sort. Is there some sort of wierd global script on Hala that someone made to randomly place treasure on creatures? If NWN did this at random other servers would have reported this issue a long time ago.
Post Reply