* Disabled tick cache (to enable it: define TICK_CACHE to the number of calls that should be cached).

* Added a charid2sd database for fast charid searches.
* Reworked the nick cache to only contain offline characters.

Note: The tick cache was causing _some_ of the desync problems in eA. Gameplay should be much smother, but desync problems still exist.

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@11290 54d463be-8e91-2dee-dedb-b68131a5f0ec
This commit is contained in:
FlavioJS 2007-09-25 01:58:31 +00:00
parent c5b8e5d082
commit 52f3681f3d
9 changed files with 182 additions and 112 deletions

View File

@ -3,6 +3,11 @@ Date Added
AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK. AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK.
IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
2007/09/25
* Disabled tick cache (to enable it: define TICK_CACHE to the number of
calls that should be cached).
* Added a charid2sd database for fast charid searches.
* Reworked the nick cache to only contain offline characters. [FlavioJS]
2007/09/24 2007/09/24
* Ignore %MDef bonuses now only reduce target's base MDEF, not MDEF2. * Ignore %MDef bonuses now only reduce target's base MDEF, not MDEF2.
* Updated the 'skills that cause no damage are blocked now if the skill * Updated the 'skills that cause no damage are blocked now if the skill

View File

@ -109,19 +109,21 @@ char* search_timer_func_list(TimerFunc func)
/*---------------------------- /*----------------------------
* Get tick time * Get tick time
*----------------------------*/ *----------------------------*/
static unsigned int gettick_cache;
static int gettick_count;
//////////////////////////////////////////////////////////////////////////
#if defined(TICK_CACHE) && TICK_CACHE > 1
//////////////////////////////////////////////////////////////////////////
// tick is cached for TICK_CACHE calls
unsigned int gettick_nocache(void) unsigned int gettick_nocache(void)
{ {
#ifdef _WIN32 #ifdef WIN32
gettick_count = 256; gettick_count = TICK_CACHE;
return gettick_cache = GetTickCount(); return gettick_cache = GetTickCount();
#else #else
struct timeval tval; struct timeval tval;
gettimeofday(&tval, NULL); gettimeofday(&tval, NULL);
gettick_count = 256; gettick_count = TICK_CACHE;
return gettick_cache = tval.tv_sec * 1000 + tval.tv_usec / 1000; return gettick_cache = tval.tv_sec * 1000 + tval.tv_usec / 1000;
#endif #endif
@ -134,6 +136,23 @@ unsigned int gettick(void)
return gettick_cache; return gettick_cache;
} }
//////////////////////////////
#else
//////////////////////////////
// tick doesn't get cached
unsigned int gettick(void)
{
#ifdef WIN32
return GetTickCount();
#else
struct timeval tval;
gettimeofday(&tval, NULL);
return tval.tv_sec * 1000 + tval.tv_usec / 1000;
#endif
}
//////////////////////////////////////////////////////////////////////////
#endif
//////////////////////////////////////////////////////////////////////////
/*====================================== /*======================================
* CORE : Timer Heap * CORE : Timer Heap

View File

@ -41,7 +41,11 @@ struct TimerData {
// Function prototype declaration // Function prototype declaration
#if defined(TICK_CACHE) && TICK_CACHE > 1
unsigned int gettick_nocache(void); unsigned int gettick_nocache(void);
#else
#define gettick_nocache gettick
#endif
unsigned int gettick(void); unsigned int gettick(void);
int add_timer(unsigned int,TimerFunc f,int,int); int add_timer(unsigned int,TimerFunc f,int,int);

View File

@ -1302,7 +1302,7 @@ int chrif_parse(int fd)
case 0x2b04: chrif_recvmap(fd); break; case 0x2b04: chrif_recvmap(fd); break;
case 0x2b06: chrif_changemapserverack(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14), RFIFOW(fd,18), RFIFOW(fd,20), RFIFOW(fd,22), RFIFOL(fd,24), RFIFOW(fd,28)); break; case 0x2b06: chrif_changemapserverack(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14), RFIFOW(fd,18), RFIFOW(fd,20), RFIFOW(fd,22), RFIFOL(fd,24), RFIFOW(fd,28)); break;
case 0x2b07: clif_updatemaxid(RFIFOL(fd,2), RFIFOL(fd,6)); break; case 0x2b07: clif_updatemaxid(RFIFOL(fd,2), RFIFOL(fd,6)); break;
case 0x2b09: map_addchariddb(RFIFOL(fd,2), (char*)RFIFOP(fd,6)); break; case 0x2b09: map_addnickdb(RFIFOL(fd,2), (char*)RFIFOP(fd,6)); break;
case 0x2b0b: chrif_changedgm(fd); break; case 0x2b0b: chrif_changedgm(fd); break;
case 0x2b0d: chrif_changedsex(fd); break; case 0x2b0d: chrif_changedsex(fd); break;
case 0x2b0f: chrif_char_ask_name_answer(fd); break; case 0x2b0f: chrif_char_ask_name_answer(fd); break;

View File

@ -5160,24 +5160,13 @@ int clif_wis_end(int fd, int flag)
/*========================================== /*==========================================
* ID名前引き結果を送信する * ID名前引き結果を送信する
*------------------------------------------*/ *------------------------------------------*/
int clif_solved_charname(struct map_session_data *sd,int char_id) int clif_solved_charname(int fd, int charid, const char* name)
{ {
char *p= map_charid2nick(char_id);
int fd;
nullpo_retr(0, sd);
fd=sd->fd;
if(p!=NULL){
WFIFOHEAD(fd,packet_len(0x194)); WFIFOHEAD(fd,packet_len(0x194));
WFIFOW(fd,0)=0x194; WFIFOW(fd,0)=0x194;
WFIFOL(fd,2)=char_id; WFIFOL(fd,2)=charid;
memcpy(WFIFOP(fd,6), p, NAME_LENGTH); safestrncpy(WFIFOP(fd,6), name, NAME_LENGTH);
WFIFOSET(fd,packet_len(0x194)); WFIFOSET(fd,packet_len(0x194));
}else{
map_reqchariddb(sd,char_id);
chrif_searchcharid(char_id);
}
return 0; return 0;
} }
@ -6041,23 +6030,16 @@ int clif_movetoattack(struct map_session_data *sd,struct block_list *bl)
*------------------------------------------*/ *------------------------------------------*/
int clif_produceeffect(struct map_session_data* sd,int flag,int nameid) int clif_produceeffect(struct map_session_data* sd,int flag,int nameid)
{ {
int view,fd; int fd;
nullpo_retr(0, sd); nullpo_retr(0, sd);
fd = sd->fd; fd = sd->fd;
// 名前の登録と送信を先にしておく clif_solved_charname(fd, sd->status.char_id, sd->status.name);
if( map_charid2nick(sd->status.char_id)==NULL )
map_addchariddb(sd->status.char_id,sd->status.name);
clif_solved_charname(sd,sd->status.char_id);
WFIFOHEAD(fd,packet_len(0x18f)); WFIFOHEAD(fd,packet_len(0x18f));
WFIFOW(fd, 0)=0x18f; WFIFOW(fd, 0)=0x18f;
WFIFOW(fd, 2)=flag; WFIFOW(fd, 2)=flag;
if((view = itemdb_viewid(nameid)) > 0) WFIFOW(fd, 4)=(itemdb_viewid(nameid)||nameid);
WFIFOW(fd, 4)=view;
else
WFIFOW(fd, 4)=nameid;
WFIFOSET(fd,packet_len(0x18f)); WFIFOSET(fd,packet_len(0x18f));
return 0; return 0;
} }
@ -9915,10 +9897,10 @@ void clif_parse_InsertCard(int fd,struct map_session_data *sd)
*------------------------------------------*/ *------------------------------------------*/
void clif_parse_SolveCharName(int fd, struct map_session_data *sd) void clif_parse_SolveCharName(int fd, struct map_session_data *sd)
{ {
int char_id; int charid;
char_id = RFIFOL(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]); charid = RFIFOL(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]);
clif_solved_charname(sd, char_id); map_reqnickdb(sd, charid);
} }
/*========================================== /*==========================================
@ -11263,7 +11245,7 @@ void clif_parse_PVPInfo(int fd,struct map_session_data *sd)
void clif_parse_Blacksmith(int fd,struct map_session_data *sd) void clif_parse_Blacksmith(int fd,struct map_session_data *sd)
{ {
int i; int i;
char *name; const char* name;
WFIFOHEAD(fd,packet_len(0x219)); WFIFOHEAD(fd,packet_len(0x219));
WFIFOW(fd,0) = 0x219; WFIFOW(fd,0) = 0x219;
@ -11306,7 +11288,7 @@ int clif_fame_blacksmith(struct map_session_data *sd, int points)
void clif_parse_Alchemist(int fd,struct map_session_data *sd) void clif_parse_Alchemist(int fd,struct map_session_data *sd)
{ {
int i; int i;
char *name; const char* name;
WFIFOHEAD(fd,packet_len(0x21a)); WFIFOHEAD(fd,packet_len(0x21a));
WFIFOW(fd,0) = 0x21a; WFIFOW(fd,0) = 0x21a;
@ -11349,7 +11331,7 @@ int clif_fame_alchemist(struct map_session_data *sd, int points)
void clif_parse_Taekwon(int fd,struct map_session_data *sd) void clif_parse_Taekwon(int fd,struct map_session_data *sd)
{ {
int i; int i;
char *name; const char* name;
WFIFOHEAD(fd,packet_len(0x226)); WFIFOHEAD(fd,packet_len(0x226));
WFIFOW(fd,0) = 0x226; WFIFOW(fd,0) = 0x226;

View File

@ -237,7 +237,7 @@ int clif_status_change(struct block_list *bl,int type,int flag);
int clif_wis_message(int fd, const char* nick, const char* mes, int mes_len); int clif_wis_message(int fd, const char* nick, const char* mes, int mes_len);
int clif_wis_end(int fd,int flag); int clif_wis_end(int fd,int flag);
int clif_solved_charname(struct map_session_data *sd,int char_id); int clif_solved_charname(int fd, int charid, const char* name);
int clif_charnameack(int fd, struct block_list *bl); int clif_charnameack(int fd, struct block_list *bl);
int clif_charnameupdate(struct map_session_data *ssd); int clif_charnameupdate(struct map_session_data *ssd);

View File

@ -115,10 +115,11 @@ char *SCRIPT_CONF_NAME;
char *MSG_CONF_NAME; char *MSG_CONF_NAME;
// ‹É—Í staticŃ<C385>?ƒJƒÉ?‚ß‚é // ‹É—Í staticŃ<C385>?ƒJƒÉ?‚ß‚é
static struct dbt * id_db=NULL; static struct dbt * id_db=NULL;// id -> struct block_list
static struct dbt * pc_db=NULL; static struct dbt * pc_db=NULL;// id -> struct map_session_data
static struct dbt * map_db=NULL; static struct dbt * map_db=NULL;
static struct dbt * charid_db=NULL; static struct dbt * nick_db=NULL;// charid -> struct charid2nick (requested names of offline characters)
static struct dbt * charid_db=NULL;// charid -> struct map_session_data
static int map_users=0; static int map_users=0;
static struct block_list *objects[MAX_FLOORITEM]; static struct block_list *objects[MAX_FLOORITEM];
@ -143,9 +144,13 @@ int save_settings = 0xFFFF;
int agit_flag = 0; int agit_flag = 0;
int night_flag = 0; // 0=day, 1=night [Yor] int night_flag = 0; // 0=day, 1=night [Yor]
struct charid_request {
struct charid_request* next;
int charid;// who want to be notified of the nick
};
struct charid2nick { struct charid2nick {
char nick[NAME_LENGTH]; char nick[NAME_LENGTH];
int req_id; struct charid_request* requests;// requests of notification on this nick
}; };
// This is the main header found at the very beginning of the map cache // This is the main header found at the very beginning of the map cache
@ -1589,45 +1594,88 @@ int map_addflooritem(struct item *item_data,int amount,int m,int x,int y,int fir
static void* create_charid2nick(DBKey key, va_list args) static void* create_charid2nick(DBKey key, va_list args)
{ {
struct charid2nick *p; struct charid2nick *p;
p = (struct charid2nick *)aCallocA(1, sizeof (struct charid2nick)); CREATE(p, struct charid2nick, 1);
return p; return p;
} }
/*========================================== /// Adds(or replaces) the nick of charid to nick_db and fullfils pending requests.
* charid_dbへ追加() /// Does nothing if the character is online.
*------------------------------------------*/ void map_addnickdb(int charid, const char* nick)
void map_addchariddb(int charid, char* name)
{ {
struct charid2nick* p; struct charid2nick* p;
int req = 0; struct charid_request* req;
struct map_session_data* sd;
p = idb_ensure(charid_db, charid, create_charid2nick); if( map_charid2sd(charid) )
req = p->req_id; return;// already online
p->req_id = 0;
//We overwrite the nick anyway in case a different one arrived.
memcpy(p->nick, name, NAME_LENGTH);
if (req) { p = idb_ensure(nick_db, charid, create_charid2nick);
struct map_session_data* sd = map_id2sd(req); safestrncpy(p->nick, nick, sizeof(p->nick));
if (sd) clif_solved_charname(sd,charid);
}
}
/*========================================== while( p->requests )
* charid_dbへ追加
*------------------------------------------*/
int map_reqchariddb(struct map_session_data * sd,int charid)
{ {
struct charid2nick *p=NULL; req = p->requests;
p->requests = req->next;
sd = map_charid2sd(req->charid);
if( sd )
clif_solved_charname(sd->fd, charid, p->nick);
aFree(req);
}
}
nullpo_retr(0, sd); /// Removes the nick of charid from nick_db.
/// Sends name to all pending requests on charid.
void map_delnickdb(int charid, const char* name)
{
struct charid2nick* p;
struct charid_request* req;
struct map_session_data* sd;
p = (struct charid2nick*)idb_get(charid_db,charid); p = idb_remove(nick_db, charid);
if(p) return 0; //Nothing to request, we already have the name! if( p == NULL )
p = (struct charid2nick *)aCalloc(1,sizeof(struct charid2nick)); return;
p->req_id=sd->bl.id;
idb_put(charid_db,charid,p); while( p->requests )
return 0; {
req = p->requests;
p->requests = req->next;
sd = map_charid2sd(req->charid);
if( sd )
clif_solved_charname(sd->fd, charid, name);
aFree(req);
}
aFree(p);
}
/// Notifies sd of the nick of charid.
/// Uses the name in the character if online.
/// Uses the name in nick_db if offline.
void map_reqnickdb(struct map_session_data * sd, int charid)
{
struct charid2nick* p;
struct charid_request* req;
struct map_session_data* tsd;
nullpo_retv(sd);
tsd = map_charid2sd(charid);
if( tsd )
{
clif_solved_charname(sd->fd, charid, tsd->status.name);
return;
}
p = (struct charid2nick*)idb_ensure(nick_db, charid, create_charid2nick);
if( *p->nick )
{
clif_solved_charname(sd->fd, charid, p->nick);
return;
}
// not in cache, request it
CREATE(req, struct charid_request, 1);
req->next = p->requests;
p->requests = req;
chrif_searchcharid(charid);
} }
/*========================================== /*==========================================
@ -1638,7 +1686,11 @@ void map_addiddb(struct block_list *bl)
nullpo_retv(bl); nullpo_retv(bl);
if (bl->type == BL_PC) if (bl->type == BL_PC)
idb_put(pc_db,bl->id,bl); {
TBL_PC* sd = (TBL_PC*)bl;
idb_put(pc_db,sd->bl.id,sd);
idb_put(charid_db,sd->status.char_id,sd);
}
idb_put(id_db,bl->id,bl); idb_put(id_db,bl->id,bl);
} }
@ -1650,7 +1702,11 @@ void map_deliddb(struct block_list *bl)
nullpo_retv(bl); nullpo_retv(bl);
if (bl->type == BL_PC) if (bl->type == BL_PC)
idb_remove(pc_db,bl->id); {
TBL_PC* sd = (TBL_PC*)bl;
idb_remove(pc_db,sd->bl.id);
idb_remove(charid_db,sd->status.char_id);
}
idb_remove(id_db,bl->id); idb_remove(id_db,bl->id);
} }
@ -1668,9 +1724,7 @@ int map_quit(struct map_session_data *sd)
//Double login, let original do the cleanups below. //Double login, let original do the cleanups below.
if (sd2 && sd2 != sd) if (sd2 && sd2 != sd)
return 0; return 0;
idb_remove(id_db,sd->bl.id); map_deliddb(&sd->bl);
idb_remove(pc_db,sd->status.account_id);
idb_remove(charid_db,sd->status.char_id);
return 0; return 0;
} }
if(!sd->state.waitingdisconnect) { if(!sd->state.waitingdisconnect) {
@ -1693,8 +1747,6 @@ int map_quit(struct map_session_data *sd)
unit_remove_map(&sd->hd->bl, 0); unit_remove_map(&sd->hd->bl, 0);
} }
//Do we really need to remove the name?
idb_remove(charid_db,sd->status.char_id);
idb_remove(id_db,sd->bl.id); idb_remove(id_db,sd->bl.id);
if(sd->reg) if(sd->reg)
@ -1729,6 +1781,7 @@ void map_quit_ack(struct map_session_data *sd)
{ {
if (sd && sd->state.finalsave) { if (sd && sd->state.finalsave) {
idb_remove(pc_db,sd->status.account_id); idb_remove(pc_db,sd->status.account_id);
idb_remove(charid_db,sd->status.char_id);
aFree(sd); aFree(sd);
} }
} }
@ -1758,31 +1811,28 @@ struct map_session_data * map_id2sd(int id)
return (struct map_session_data*)idb_get(pc_db,id); return (struct map_session_data*)idb_get(pc_db,id);
} }
/*========================================== /// Returns the nick of the target charid or NULL if unknown (requests the nick to the char server).
* char_id番? const char* map_charid2nick(int charid)
*------------------------------------------*/
char * map_charid2nick(int id)
{ {
struct charid2nick *p = (struct charid2nick*)idb_get(charid_db,id); struct charid2nick *p;
struct map_session_data* sd;
if(p==NULL) sd = map_charid2sd(charid);
if( sd )
return sd->status.name;// character is online, return it's name
p = (struct charid2nick*)idb_ensure(nick_db, charid, create_charid2nick);
if( *p->nick )
return p->nick;// name in nick_db
chrif_searchcharid(charid);// request the name
return NULL; return NULL;
return p->nick;
} }
struct map_session_data * map_charid2sd(int id) /// Returns the struct map_session_data of the charid or NULL if the char is not online.
struct map_session_data* map_charid2sd(int charid)
{ {
int i, users; return (struct map_session_data*)idb_get(charid_db, charid);
struct map_session_data **all_sd;
if (id <= 0) return 0;
all_sd = map_getallusers(&users);
for(i = 0; i < users; i++)
if (all_sd[i] && all_sd[i]->status.char_id == id)
return all_sd[i];
return NULL;
} }
/*========================================== /*==========================================
@ -3040,10 +3090,20 @@ int map_db_final(DBKey k,void *d,va_list ap)
return 0; return 0;
} }
int nick_db_final(void *k,void *d,va_list ap) int nick_db_final(DBKey key, void *data, va_list args)
{ {
char *p = (char *) d; struct charid2nick* p = (struct charid2nick*)data;
if (p) aFree(p); struct charid_request* req;
if( p == NULL )
return 0;
while( p->requests )
{
req = p->requests;
p->requests = req->next;
aFree(req);
}
aFree(p);
return 0; return 0;
} }
@ -3161,6 +3221,7 @@ void do_final(void)
id_db->destroy(id_db, NULL); id_db->destroy(id_db, NULL);
pc_db->destroy(pc_db, NULL); pc_db->destroy(pc_db, NULL);
nick_db->destroy(nick_db, nick_db_final);
charid_db->destroy(charid_db, NULL); charid_db->destroy(charid_db, NULL);
#ifndef TXT_ONLY #ifndef TXT_ONLY
@ -3197,7 +3258,7 @@ void do_abort(void)
if (!chrif_isconnected()) if (!chrif_isconnected())
{ {
if (pc_db->size(pc_db)) if (pc_db->size(pc_db))
ShowFatalError("Server has crashed without a connection to the char-server, character data can't be saved!\n"); ShowFatalError("Server has crashed without a connection to the char-server, %u characters can't be saved!\n", pc_db->size(pc_db));
return; return;
} }
ShowError("Server received crash signal! Attempting to save all online characters!\n"); ShowError("Server received crash signal! Attempting to save all online characters!\n");
@ -3339,6 +3400,7 @@ int do_init(int argc, char *argv[])
id_db = db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_BASE,sizeof(int)); id_db = db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_BASE,sizeof(int));
pc_db = db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_BASE,sizeof(int)); //Added for reliable map_id2sd() use. [Skotlex] pc_db = db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_BASE,sizeof(int)); //Added for reliable map_id2sd() use. [Skotlex]
map_db = db_alloc(__FILE__,__LINE__,DB_UINT,DB_OPT_BASE,sizeof(int)); map_db = db_alloc(__FILE__,__LINE__,DB_UINT,DB_OPT_BASE,sizeof(int));
nick_db = db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int));
charid_db = db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int)); charid_db = db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int));
#ifndef TXT_ONLY #ifndef TXT_ONLY
map_sql_init(); map_sql_init();

View File

@ -1327,11 +1327,11 @@ int map_removemobs_timer(int,unsigned int,int,int);
int map_addflooritem(struct item *item_data,int amount,int m,int x,int y,int first_id,int second_id,int third_id,int flags); int map_addflooritem(struct item *item_data,int amount,int m,int x,int y,int first_id,int second_id,int third_id,int flags);
// キャラidキャラ名 変換関連 // キャラidキャラ名 変換関連
void map_addchariddb(int charid,char *name); void map_addnickdb(int charid, const char* nick);
void map_delchariddb(int charid); void map_delnickdb(int charid, const char* nick);
int map_reqchariddb(struct map_session_data * sd,int charid); void map_reqnickdb(struct map_session_data* sd,int charid);
char * map_charid2nick(int); const char* map_charid2nick(int charid);
struct map_session_data * map_charid2sd(int); struct map_session_data* map_charid2sd(int charid);
struct map_session_data * map_id2sd(int); struct map_session_data * map_id2sd(int);
struct block_list * map_id2bl(int); struct block_list * map_id2bl(int);
@ -1346,7 +1346,6 @@ void map_deliddb(struct block_list *bl);
struct map_session_data** map_getallusers(int *users); struct map_session_data** map_getallusers(int *users);
void map_foreachpc(int (*func)(DBKey,void*,va_list),...); void map_foreachpc(int (*func)(DBKey,void*,va_list),...);
int map_foreachiddb(int (*)(DBKey,void*,va_list),...); int map_foreachiddb(int (*)(DBKey,void*,va_list),...);
void map_addnickdb(struct map_session_data *);
struct map_session_data * map_nick2sd(const char*); struct map_session_data * map_nick2sd(const char*);
// その他 // その他

View File

@ -696,8 +696,7 @@ int pc_authok(struct map_session_data *sd, int login_id2, time_t connect_until_t
clif_authok(sd); clif_authok(sd);
map_addiddb(&sd->bl); map_addiddb(&sd->bl);
if (map_charid2nick(sd->status.char_id) == NULL) map_delnickdb(sd->status.char_id, sd->status.name);
map_addchariddb(sd->status.char_id, sd->status.name);
//Prevent S. Novices from getting the no-death bonus just yet. [Skotlex] //Prevent S. Novices from getting the no-death bonus just yet. [Skotlex]
sd->die_counter=-1; sd->die_counter=-1;