Improved randomness (part 1) (#7882)

Faster and with no module bias

Removed rnd_init, rnd_uint32 and rnd_uniform
From now on we will only use rnd_value(min, max) for values in range [min, max] and rnd_chance(chance, base) for chances

Fixes #7881
Fixes #7883
Fixes #7884
Fixes #7885

Co-authored-by: Lemongrass3110 <lemongrass@kstp.at>
This commit is contained in:
Lemon
2023-12-20 00:12:15 +01:00
committed by GitHub
parent ad3a2e99eb
commit 7c153416bc
20 changed files with 83 additions and 107 deletions

View File

@@ -3,43 +3,9 @@
#include "random.hpp"
#include <random>
std::mt19937 generator;
std::uniform_int_distribution<int32> int31_distribution;
std::uniform_int_distribution<uint32> uint32_distribution;
/// Initializes the random number generator
void rnd_init( void ){
std::random_device device;
generator = std::mt19937( device() );
int31_distribution = std::uniform_int_distribution<int32>( 0, SINT32_MAX );
uint32_distribution = std::uniform_int_distribution<uint32>( 0, UINT32_MAX );
}
std::uniform_int_distribution<int32> int31_distribution = std::uniform_int_distribution<int32>(0, SINT32_MAX);
/// Generates a random number in the interval [0, SINT32_MAX]
int32 rnd( void ){
return int31_distribution( generator );
}
/// Generates a random number in the interval [0, UINT32_MAX]
uint32 rnd_uint32( void ){
return uint32_distribution( generator );
}
/// Generates a random number in the interval [0.0, 1.0)
/// NOTE: interval is open ended, so 1.0 is excluded
double rnd_uniform( void ){
return rnd_uint32() * ( 1.0 / 4294967296.0 );// divided by 2^32
}
/// Generates a random number in the interval [min, max]
/// Returns min if range is invalid.
int32 rnd_value( int32 min, int32 max ){
if( min >= max ){
return min;
}
return min + (int32)( rnd_uniform() * ( max - min + 1 ) );
}

View File

@@ -4,15 +4,33 @@
#ifndef RANDOM_HPP
#define RANDOM_HPP
#include <type_traits>
#include <random>
#include "cbasetypes.hpp"
void rnd_init(void);
inline std::random_device device;
inline std::mt19937 generator = std::mt19937(device());
int32 rnd(void);// [0, SINT32_MAX]
int32 rnd_value(int32 min, int32 max);// [min, max]
template <typename T> bool rnd_chance( T chance, T base ){
return rnd_value( 0, base ) < chance;
/*
* Generates a random number in the interval [min, max]
* @return random number
*/
template <typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type rnd_value(T min, T max) {
std::uniform_int_distribution<T> dist(min, max);
return dist(generator);
}
/*
* Simulates a chance based on a given probability
* @return true if succeeded / false if it didn't
*/
template <typename T>
typename std::enable_if<std::is_integral<T>::value, bool>::type rnd_chance(T chance, T base) {
return rnd_value<T>(1, base) <= chance;
}
#endif /* RANDOM_HPP */

View File

@@ -159,7 +159,7 @@ namespace rathena {
template <typename K, typename V> V& umap_random( std::unordered_map<K, V>& map ){
auto it = map.begin();
std::advance( it, rnd_value( 0, map.size() - 1 ) );
std::advance( it, rnd_value<size_t>( 0, map.size() - 1 ) );
return it->second;
}
@@ -172,7 +172,7 @@ namespace rathena {
template <typename K> K &vector_random(std::vector<K> &vec) {
auto it = vec.begin();
std::advance(it, rnd_value(0, vec.size() - 1));
std::advance( it, rnd_value<size_t>( 0, vec.size() - 1 ) );
return *it;
}

View File

@@ -403,8 +403,8 @@ int login_mmo_auth(struct login_session_data* sd, bool isServer) {
// update session data
sd->account_id = acc.account_id;
sd->login_id1 = rnd() + 1;
sd->login_id2 = rnd() + 1;
sd->login_id1 = rnd_value(1u, UINT32_MAX);
sd->login_id2 = rnd_value(1u, UINT32_MAX);
safestrncpy(sd->lastlogin, acc.lastlogin, sizeof(sd->lastlogin));
sd->sex = acc.sex;
sd->group_id = acc.group_id;
@@ -846,8 +846,6 @@ bool LoginServer::initialize( int argc, char* argv[] ){
login_lan_config_read(login_config.lanconf_name);
//end config
rnd_init();
do_init_loginclif();
do_init_loginchrif();

View File

@@ -39,8 +39,8 @@ namespace rathena{
///Struct of 1 client connected to login-serv
struct login_session_data {
uint32 account_id; ///also GID
long login_id1;
long login_id2;
uint32 login_id1;
uint32 login_id2;
char sex; /// 'F','M','S'
char userid[NAME_LENGTH]; /// account name

View File

@@ -377,8 +377,7 @@ static int logclif_parse_reqauth(int fd, struct login_session_data *sd, int comm
static int logclif_parse_reqkey(int fd, struct login_session_data *sd){
RFIFOSKIP(fd,2);
{
memset(sd->md5key, '\0', sizeof(sd->md5key));
sd->md5keylen = (uint16)(12 + rnd() % 4);
sd->md5keylen = sizeof( sd->md5key );
MD5_Salt(sd->md5keylen, sd->md5key);
WFIFOHEAD(fd,4 + sd->md5keylen);

View File

@@ -7259,7 +7259,7 @@ ACMD_FUNC(pettalk)
};
int i;
ARR_FIND( 0, ARRAYLENGTH(emo), i, stricmp(message, emo[i]) == 0 );
if( i == ET_DICE1 ) i = rnd()%6 + ET_DICE1; // randomize /dice
if( i == ET_DICE1 ) i = rnd_value<int>(ET_DICE1, ET_DICE6); // randomize /dice
if( i < ARRAYLENGTH(emo) )
{
if (sd->emotionlasttime + 1 >= time(NULL)) { // not more than 1 per second
@@ -8017,7 +8017,7 @@ ACMD_FUNC(hommutate)
}
if (!message || !*message) {
homun_id = 6048 + (rnd() % 4);
homun_id = rnd_value<uint16>(MER_EIRA, MER_ELEANOR);
} else {
homun_id = atoi(message);
}
@@ -9133,8 +9133,8 @@ ACMD_FUNC(clone)
}
do {
x = sd->bl.x + (rnd() % 10 - 5);
y = sd->bl.y + (rnd() % 10 - 5);
x = sd->bl.x + rnd_value(-5, 5);
y = sd->bl.y + rnd_value(-5, 5);
} while (map_getcell(sd->bl.m,x,y,CELL_CHKNOPASS) && i++ < 10);
if (i >= 10) {

View File

@@ -1172,7 +1172,7 @@ void bg_queue_join_multi(const char *name, map_session_data *sd, std::vector <ma
break;
}
bool r = rnd() % 2 != 0;
bool r = rnd_chance(50, 100);
std::vector<map_session_data *> *team = r ? &queue->teamb_members : &queue->teama_members;
if (queue->state == QUEUE_STATE_ACTIVE) {

View File

@@ -23561,11 +23561,11 @@ void clif_parse_laphine_upgrade( int fd, map_session_data* sd ){
item->refine = rnd_value( upgrade->resultRefineMinimum, upgrade->resultRefineMaximum );
}else{
// Otherwise it can only be upgraded until the maximum, but not downgraded
item->refine = rnd_value( item->refine, upgrade->resultRefineMaximum );
item->refine = rnd_value<uint16>( item->refine, upgrade->resultRefineMaximum );
}
}else if( upgrade->resultRefineMinimum > 0 ){
// No maximum has been specified, so it can be anything between minimum and MAX_REFINE
item->refine = rnd_value( upgrade->resultRefineMinimum, MAX_REFINE );
item->refine = rnd_value<uint16>( upgrade->resultRefineMinimum, MAX_REFINE );
}
// Log retrieving the item again -> with the new options

View File

@@ -622,7 +622,7 @@ static int elemental_ai_sub_timer(s_elemental_data *ed, map_session_data *sd, t_
return 1;
}
if( battle_check_range(&ed->bl,target,view_range) && rnd()%100 < 2 ) { // 2% chance to cast attack skill.
if( battle_check_range(&ed->bl,target,view_range) && rnd_chance(2, 100) ) { // 2% chance to cast attack skill.
if( elemental_action(ed,target,tick) )
return 1;
}

View File

@@ -2872,7 +2872,7 @@ std::shared_ptr<s_item_group_entry> get_random_itemsubgroup(std::shared_ptr<s_it
for (size_t j = 0, max = random->data.size() * 3; j < max; j++) {
std::shared_ptr<s_item_group_entry> entry = util::umap_random(random->data);
if (entry->rate == 0 || rnd() % random->total_rate < entry->rate) // always return entry for rate 0 ('must' item)
if (entry->rate == 0 || rnd_chance<uint32>(entry->rate, random->total_rate)) // always return entry for rate 0 ('must' item)
return entry;
}
@@ -2956,9 +2956,9 @@ static void itemdb_pc_get_itemgroup_sub(map_session_data *sd, bool identify, std
if( data->refineMinimum > 0 && data->refineMaximum > 0 ){
tmp.refine = rnd_value( data->refineMinimum, data->refineMaximum );
}else if( data->refineMinimum > 0 ){
tmp.refine = rnd_value( data->refineMinimum, MAX_REFINE );
tmp.refine = rnd_value<uint16>( data->refineMinimum, MAX_REFINE );
}else if( data->refineMaximum > 0 ){
tmp.refine = rnd_value( 1, data->refineMaximum );
tmp.refine = rnd_value<uint16>( 1, data->refineMaximum );
}else{
tmp.refine = 0;
}
@@ -4456,7 +4456,7 @@ void s_random_opt_group::apply( struct item& item ){
for( size_t j = 0, max = this->slots[static_cast<uint16>(i)].size() * 3; j < max; j++ ){
std::shared_ptr<s_random_opt_group_entry> option = util::vector_random( this->slots[static_cast<uint16>(i)] );
if( rnd() % 10000 < option->chance ){
if ( rnd_chance<uint16>(option->chance, 10000) ) {
apply_sub( item.option[i], option );
break;
}
@@ -4481,7 +4481,7 @@ void s_random_opt_group::apply( struct item& item ){
std::shared_ptr<s_random_opt_group_entry> option = util::vector_random( this->random_options );
if( rnd() % 10000 < option->chance ){
if ( rnd_chance<uint16>(option->chance, 10000) ){
apply_sub( item.option[i], option );
}
}

View File

@@ -1669,7 +1669,7 @@ int map_searchrandfreecell(int16 m,int16 *x,int16 *y,int stack) {
}
if(free_cell==0)
return 0;
free_cell = rnd()%free_cell;
free_cell = rnd_value(0, free_cell-1);
*x = free_cells[free_cell][0];
*y = free_cells[free_cell][1];
return 1;
@@ -1697,8 +1697,6 @@ int map_search_freecell(struct block_list *src, int16 m, int16 *x,int16 *y, int1
{
int tries, spawn=0;
int bx, by;
int rx2 = 2*rx+1;
int ry2 = 2*ry+1;
if( !src && (!(flag&1) || flag&2) )
{
@@ -1728,7 +1726,7 @@ int map_search_freecell(struct block_list *src, int16 m, int16 *x,int16 *y, int1
}
if (rx >= 0 && ry >= 0) {
tries = rx2*ry2;
tries = (rx * 2 + 1) * (ry * 2 + 1);
if (tries > 100) tries = 100;
} else {
tries = mapdata->xs*mapdata->ys;
@@ -1736,8 +1734,8 @@ int map_search_freecell(struct block_list *src, int16 m, int16 *x,int16 *y, int1
}
while(tries--) {
*x = (rx >= 0)?(rnd()%rx2-rx+bx):(rnd()%(mapdata->xs-2)+1);
*y = (ry >= 0)?(rnd()%ry2-ry+by):(rnd()%(mapdata->ys-2)+1);
*x = (rx >= 0) ? rnd_value(bx - rx, bx + rx) : rnd_value<int16>(1, mapdata->xs - 1);
*y = (ry >= 0) ? rnd_value(by - ry, by + ry) : rnd_value<int16>(1, mapdata->ys - 1);
if (*x == bx && *y == by)
continue; //Avoid picking the same target tile.
@@ -1860,7 +1858,6 @@ bool map_closest_freecell(int16 m, int16 *x, int16 *y, int type, int flag)
*------------------------------------------*/
int map_addflooritem(struct item *item, int amount, int16 m, int16 x, int16 y, int first_charid, int second_charid, int third_charid, int flags, unsigned short mob_id, bool canShowEffect)
{
int r;
struct flooritem_data *fitem = NULL;
nullpo_ret(item);
@@ -1870,7 +1867,6 @@ int map_addflooritem(struct item *item, int amount, int16 m, int16 x, int16 y, i
if (!map_searchrandfreecell(m,&x,&y,flags&2?1:0))
return 0;
r = rnd();
CREATE(fitem, struct flooritem_data, 1);
fitem->bl.type=BL_ITEM;
@@ -1894,8 +1890,8 @@ int map_addflooritem(struct item *item, int amount, int16 m, int16 x, int16 y, i
memcpy(&fitem->item,item,sizeof(*item));
fitem->item.amount = amount;
fitem->subx = (r&3)*3+3;
fitem->suby = ((r>>2)&3)*3+3;
fitem->subx = rnd_value(1, 4) * 3;
fitem->suby = rnd_value(1, 4) * 3;
fitem->cleartimer = add_timer(gettick()+battle_config.flooritem_lifetime,map_clearflooritem_timer,fitem->bl.id,0);
map_addiddb(&fitem->bl);
@@ -3090,8 +3086,8 @@ int map_random_dir(struct block_list *bl, int16 *x, int16 *y)
if (dist < 1) dist =1;
do {
short j = 1 + 2*(rnd()%4); //Pick a random diagonal direction
short segment = 1+(rnd()%dist); //Pick a random interval from the whole vector in that direction
directions j = static_cast<directions>(1 + 2 * rnd_value(0, 3)); //Pick a random diagonal direction
short segment = rnd_value((short)1, dist); //Pick a random interval from the whole vector in that direction
xi = bl->x + segment*dirx[j];
segment = (short)sqrt((float)(dist2 - segment*segment)); //The complement of the previously picked segment
yi = bl->y + segment*diry[j];
@@ -5181,7 +5177,6 @@ bool MapServer::initialize( int argc, char *argv[] ){
#endif
cli_get_options(argc,argv);
rnd_init();
map_config_read(MAP_CONF_NAME);
if (save_settings == CHARSAVE_NONE)

View File

@@ -421,7 +421,7 @@ bool mercenary_dead(s_mercenary_data *md) {
void mercenary_killbonus(s_mercenary_data *md) {
std::vector<sc_type> scs = { SC_MERC_FLEEUP, SC_MERC_ATKUP, SC_MERC_HPUP, SC_MERC_SPUP, SC_MERC_HITUP };
sc_start(&md->bl,&md->bl, util::vector_random(scs), 100, rnd() % 5, 600000);
sc_start(&md->bl,&md->bl, util::vector_random(scs), 100, rnd_value(1, 5), 600000);
}
/**

View File

@@ -1278,7 +1278,7 @@ int party_share_loot(struct party_data* p, map_session_data* sd, struct item* it
}
while (count > 0) { //Pick a random member.
i = rnd()%count;
i = rnd_value(0, count-1);
if (pc_additem(psd[i],item,item->amount,LOG_TYPE_PICKDROP_PLAYER)) { // Discard this receiver.
psd[i] = psd[count-1];

View File

@@ -106,7 +106,7 @@ int path_blownpos(int16 m,int16 x0,int16 y0,int16 dx,int16 dy,int count)
int fy = ( dy != 0 && map_getcellp(mapdata,x0,y0+dy,CELL_CHKPASS) );
if( fx && fy )
{
if(rnd()&1)
if(rnd_chance(50, 100))
dx=0;
else
dy=0;

View File

@@ -710,7 +710,7 @@ int pet_attackskill(struct pet_data *pd, int target_id)
if (DIFF_TICK(pd->ud.canact_tick, gettick()) > 0)
return 0;
if (rnd()%100 < (pd->a_skill->rate +pd->pet.intimate*pd->a_skill->bonusrate/1000)) { // Skotlex: Use pet's skill
if (rnd_chance((pd->a_skill->rate +pd->pet.intimate*pd->a_skill->bonusrate/1000), 100)) { // Skotlex: Use pet's skill
int inf;
struct block_list *bl;
@@ -782,8 +782,8 @@ int pet_target_check(struct pet_data *pd,struct block_list *bl,int type)
rate = 1;
}
if(rnd()%10000 < rate) {
if(pd->target_id == 0 || rnd()%10000 < pet_db_ptr->change_target_rate)
if(rnd_chance(rate, 10000)) {
if(pd->target_id == 0 || rnd_chance<uint16>(pet_db_ptr->change_target_rate, 10000))
pd->target_id = bl->id;
}
@@ -942,7 +942,7 @@ static int pet_performance(map_session_data *sd, struct pet_data *pd)
val = 1;
pet_stop_walking(pd,2000<<8);
clif_pet_performance(pd, rnd()%val + 1);
clif_pet_performance(pd, rnd_value(1, val));
pet_lootitem_drop(pd,NULL);
return 1;
@@ -1315,7 +1315,7 @@ int pet_catch_process2(map_session_data* sd, int target_id)
if(battle_config.pet_catch_rate != 100)
pet_catch_rate = (pet_catch_rate*battle_config.pet_catch_rate)/100;
if(rnd()%10000 < pet_catch_rate) {
if(rnd_chance(pet_catch_rate, 10000)) {
achievement_update_objective(sd, AG_TAMING, 1, md->mob_id);
unit_remove_map(&md->bl,CLR_OUTSIGHT);
status_kill(&md->bl);
@@ -1672,10 +1672,10 @@ static int pet_randomwalk(struct pet_data *pd,t_tick tick)
d = 5;
for(i = 0; i < retrycount; i++) {
int r = rnd(), x, y;
int x, y;
x = pd->bl.x+r%(d*2+1)-d;
y = pd->bl.y+r/(d*2+1)%(d*2+1)-d;
x = pd->bl.x + rnd_value(-d, d);
y = pd->bl.y + rnd_value(-d, d);
if(map_getcell(pd->bl.m,x,y,CELL_CHKPASS) && unit_walktoxy(&pd->bl,x,y,0)) {
pd->move_fail_count = 0;
@@ -1702,7 +1702,7 @@ static int pet_randomwalk(struct pet_data *pd,t_tick tick)
c += pd->status.speed;
}
pd->next_walktime = tick+rnd()%1000+MIN_RANDOMWALKTIME+c;
pd->next_walktime = tick + MIN_RANDOMWALKTIME + c + rnd_value(0, 999);
return 1;
}

View File

@@ -775,7 +775,7 @@ void quest_update_objective(map_session_data *sd, struct mob_data* md)
for (const auto &it : qi->dropitem) {
if (it->mob_id != 0 && it->mob_id != md->mob_id)
continue;
if (it->rate < 10000 && rnd()%10000 >= it->rate)
if (it->rate < 10000 && !rnd_chance<uint16>(it->rate, 10000))
continue; // TODO: Should this be affected by server rates?
if (!item_db.exists(it->nameid))
continue;

View File

@@ -5582,17 +5582,17 @@ BUILDIN_FUNC(rand)
min = script_getnum(st,2);
if( max < min )
SWAP(min, max);
range = max - min + 1;
range = max;
}
else
{// range
min = 0;
range = script_getnum(st,2);
range = script_getnum( st, 2 ) - 1;
}
if( range <= 1 )
script_pushint(st, min);
else
script_pushint(st, rnd()%range + min);
script_pushint( st, rnd_value( min, range ) );
return SCRIPT_CMD_SUCCESS;
}
@@ -5656,8 +5656,8 @@ static int buildin_areawarp_sub(struct block_list *bl,va_list ap)
// find a suitable map cell
do {
tx = rnd()%(x3-x2+1)+x2;
ty = rnd()%(y3-y2+1)+y2;
tx = rnd_value(x2, x3);
ty = rnd_value(y2, y3);
j++;
} while( map_getcell(m,tx,ty,CELL_CHKNOPASS) && j < max );
@@ -5815,8 +5815,8 @@ BUILDIN_FUNC(warpparty)
i = 0;
do {
x = rnd()%(mapdata->xs - 2) + 1;
y = rnd()%(mapdata->ys - 2) + 1;
x = rnd_value(1, mapdata->xs - 1);
y = rnd_value(1, mapdata->ys - 1);
} while ((map_getcell(m,x,y,CELL_CHKNOPASS) || (!battle_config.teleport_on_portal && npc_check_areanpc(1,m,x,y,1))) && (i++) < 1000);
if (i >= 1000) {
@@ -5881,8 +5881,8 @@ BUILDIN_FUNC(warpparty)
uint8 attempts = 10;
do {
nx = x0 + rnd()%(x1 - x0 + 1);
ny = y0 + rnd()%(y1 - y0 + 1);
nx = x0 + rnd_value(x0, x1);
ny = y0 + rnd_value(y0, y1);
} while ((--attempts) > 0 && !map_getcell(m, nx, ny, CELL_CHKPASS));
if (attempts != 0) { //Keep the original coordinates if fails to find a valid cell within the range
@@ -10693,8 +10693,8 @@ BUILDIN_FUNC(savepoint)
x0 = x - dx, y0 = y - dy;
uint8 n = 10;
do {
x = x0 + rnd()%(x1-x0+1);
y = y0 + rnd()%(y1-y0+1);
x = rnd_value(x0, x1);
y = rnd_value(y0, y1);
} while (m != -1 && (--n) > 0 && !map_getcell(m, x, y, CELL_CHKPASS));
}
@@ -12536,7 +12536,7 @@ BUILDIN_FUNC(homunculus_evolution)
*------------------------------------------*/
BUILDIN_FUNC(homunculus_mutate)
{
int homun_id;
uint16 homun_id;
TBL_PC *sd;
if( !script_rid2sd(sd) || sd->hd == NULL )
@@ -12545,7 +12545,7 @@ BUILDIN_FUNC(homunculus_mutate)
if(script_hasdata(st,2))
homun_id = script_getnum(st,2);
else
homun_id = 6048 + (rnd() % 4);
homun_id = rnd_value<uint16>(MER_EIRA, MER_ELEANOR);
if( sd->hd->homunculus.vaporize == HOM_ST_MORPH ) {
int m_class = hom_class2mapid(sd->hd->homunculus.class_);

View File

@@ -1927,7 +1927,7 @@ int skill_additional_effect( struct block_list* src, struct block_list *bl, uint
break;
case LG_HESPERUSLIT:
if( pc_checkskill(sd,LG_PINPOINTATTACK) > 0 && sc && sc->getSCE(SC_BANDING) && sc->getSCE(SC_BANDING)->val2 > 5 )
skill_castend_damage_id(src,bl,LG_PINPOINTATTACK,rnd_value(1, pc_checkskill(sd,LG_PINPOINTATTACK)),tick,0);
skill_castend_damage_id(src,bl,LG_PINPOINTATTACK, rnd_value<uint16>(1, pc_checkskill(sd,LG_PINPOINTATTACK)),tick,0);
break;
case SR_DRAGONCOMBO:
sc_start(src,bl, SC_STUN, 1 + skill_lv, skill_lv, skill_get_time(skill_id, skill_lv));
@@ -2332,7 +2332,7 @@ int skill_additional_effect( struct block_list* src, struct block_list *bl, uint
uint16 autospl_skill_lv = it.lv ? it.lv : 1;
if (it.flag & AUTOSPELL_FORCE_RANDOM_LEVEL)
autospl_skill_lv = rnd_value( 1, autospl_skill_lv );
autospl_skill_lv = rnd_value<uint16>( 1, autospl_skill_lv );
int rate = (!sd->state.arrow_atk) ? it.rate : it.rate / 2;
@@ -2479,7 +2479,7 @@ int skill_onskillusage(map_session_data *sd, struct block_list *bl, uint16 skill
uint16 skill_lv = it.lv ? it.lv : 1;
if (it.flag & AUTOSPELL_FORCE_RANDOM_LEVEL)
skill_lv = rnd_value( 1, skill_lv ); //random skill_lv
skill_lv = rnd_value<uint16>( 1, skill_lv ); //random skill_lv
e_cast_type type = skill_get_casttype(skill);
@@ -2699,7 +2699,7 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list *
uint16 autospl_skill_id = it.id, autospl_skill_lv = it.lv ? it.lv : 1;
if (it.flag & AUTOSPELL_FORCE_RANDOM_LEVEL)
autospl_skill_lv = rnd_value( 1, autospl_skill_lv );
autospl_skill_lv = rnd_value<uint16>( 1, autospl_skill_lv );
int autospl_rate = it.rate;

View File

@@ -2603,7 +2603,7 @@ int unit_calc_pos(struct block_list *bl, int tx, int ty, uint8 dir)
nullpo_ret(ud);
if(dir > 7)
if(dir >= DIR_MAX || dir <= DIR_CENTER)
return 1;
ud->to_x = tx;
@@ -2630,7 +2630,7 @@ int unit_calc_pos(struct block_list *bl, int tx, int ty, uint8 dir)
int i;
for( i = 0; i < 12; i++ ) {
int k = rnd()%8; // Pick a Random Dir
int k = rnd_value<int>(DIR_NORTH, DIR_NORTHEAST); // Pick a Random Dir
dx = -dirx[k] * 2;
dy = -diry[k] * 2;