Cleaned up map storage type (#3384)

* Fixes #3369, fixes #3370, and fixes #3382.
* Converted maps storage container back to static array.
* Converted mapflag storage containers to unordered_map.
* Removed a lot of redundancy and recursive lookups.
* Fixed a couple short-circuit checks to help with performance.
* Fixed multiple instance creation/destruction issues.
* Fixed PK Mode attempting to set PvP on flags that are already active.
* Getting MF_RESTRICTED will return the map's zone value instead of the state.
* Converted mapflag macros to inline functions.
Thanks to @teededung, @lelouch22, @mazvi, @Lemongrass3110, and @cydh!
This commit is contained in:
Aleos 2018-08-10 13:52:07 -04:00 committed by GitHub
parent 11b255e0e9
commit 48ae1a1e05
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 548 additions and 300 deletions

View File

@ -7038,6 +7038,8 @@ The optional parameter 'zone' is used to remove the zone from restricted mapflag
This command checks the status of a given mapflag and returns the mapflag's state.
0 means OFF, and 1 means ON. See 'setmapflag' for a list of mapflags.
For MF_RESTRICTED, the zone value of the map is returned.
The optional parameter 'type' is used in the 'skill_damage' mapflag:
SKILLDMG_MAX: if mapflag is set (default)
SKILLDMG_PC: damage against players

View File

@ -2087,15 +2087,13 @@ int char_loadName(uint32 char_id, char* name){
// Searches for the mapserver that has a given map (and optionally ip/port, if not -1).
// If found, returns the server's index in the 'server' array (otherwise returns -1).
int char_search_mapserver(unsigned short map, uint32 ip, uint16 port){
int i, j;
for(i = 0; i < ARRAYLENGTH(map_server); i++)
for(int i = 0; i < ARRAYLENGTH(map_server); i++)
{
if (map_server[i].fd > 0
&& (ip == (uint32)-1 || map_server[i].ip == ip)
&& (port == (uint16)-1 || map_server[i].port == port))
{
for (j = 0; map_server[i].map[j]; j++)
for (int j = 0; map_server[i].map[j]; j++)
if (map_server[i].map[j] == map)
return i;
}

View File

@ -32,6 +32,7 @@
#define MAX_HOTKEYS 38
#endif
#define MAX_MAP_PER_SERVER 1500 /// Maximum amount of maps available on a server
#define MAX_INVENTORY 100 ///Maximum items in player inventory
/** Max number of characters per account. Note that changing this setting alone is not enough if the client is not hexed to support more characters as well.
* Max value tested was 265 */

View File

@ -7,6 +7,7 @@
#include <memory>
#include <string>
#include <map>
#include <unordered_map>
#include "cbasetypes.hpp"
@ -57,6 +58,37 @@ namespace rathena {
else
return defaultValue;
}
/**
* Find a key-value pair and return the key value
* @param map: Unordered Map to search through
* @param key: Key wanted
* @return Key value on success or nullptr on failure
*/
template <typename K, typename V> V* umap_find(std::unordered_map<K, V>& map, K key) {
auto it = map.find(key);
if (it != map.end())
return &it->second;
else
return nullptr;
}
/**
* Get a key-value pair and return the key value
* @param map: Unordered Map to search through
* @param key: Key wanted
* @param defaultValue: Value returned if key doesn't exist
* @return Key value on success or defaultValue on failure
*/
template <typename K, typename V> V umap_get(std::unordered_map<K, V>& map, K key, V defaultValue) {
auto it = map.find(key);
if (it != map.end())
return it->second;
else
return defaultValue;
}
}
}

View File

@ -397,8 +397,8 @@ static void warp_get_suggestions(struct map_session_data* sd, const char *name)
suggestions.reserve( MAX_SUGGESTIONS );
// check for maps that contain string
for( auto& pair : map ){
struct map_data *mapdata = &pair.second;
for (int i = 0; i < map_num; i++) {
struct map_data *mapdata = map_getmapdata(i);
// Prevent suggestion of instance mapnames
if( mapdata->instance_id != 0 ){
@ -419,16 +419,18 @@ static void warp_get_suggestions(struct map_session_data* sd, const char *name)
// Levenshtein > 4 is bad
const int LEVENSHTEIN_MAX = 4;
std::map<int, std::vector<const char*>> maps;
std::unordered_map<int, std::vector<const char*>> maps;
for (int i = 0; i < map_num; i++) {
struct map_data *mapdata = map_getmapdata(i);
for( auto& pair : map ){
// Prevent suggestion of instance mapnames
if( pair.second.instance_id != 0 ){
if(mapdata->instance_id != 0 ){
continue;
}
// Calculate the levenshtein distance of the two strings
int distance = levenshtein( pair.second.name, name );
int distance = levenshtein(mapdata->name, name);
// Check if it is above the maximum defined distance
if( distance > LEVENSHTEIN_MAX ){
@ -442,7 +444,7 @@ static void warp_get_suggestions(struct map_session_data* sd, const char *name)
continue;
}
vector.push_back( pair.second.name );
vector.push_back(mapdata->name);
}
for( int distance = 0; distance <= LEVENSHTEIN_MAX; distance++ ){

View File

@ -2191,15 +2191,14 @@ static int battle_skill_damage_skill(struct block_list *src, struct block_list *
if (!(damage->caster&src->type))
return 0;
union u_mapflag_args args = {};
struct map_data *mapdata = map_getmapdata(m);
args.flag_val = SKILLDMG_MAX; // Check if it's enabled first
if ((damage->map&1 && (!map_getmapflag(m, MF_PVP) && !map_flag_gvg2(m) && !map_getmapflag(m, MF_BATTLEGROUND) && !map_getmapflag_sub(m, MF_SKILL_DAMAGE, &args) && !map_getmapflag(m, MF_RESTRICTED))) ||
(damage->map&2 && map_getmapflag(m, MF_PVP)) ||
(damage->map&4 && map_flag_gvg2(m)) ||
(damage->map&8 && map_getmapflag(m, MF_BATTLEGROUND)) ||
(damage->map&16 && map_getmapflag_sub(m, MF_SKILL_DAMAGE, &args)) ||
(map_getmapflag(m, MF_RESTRICTED) && damage->map&(8*map_getmapdata(m)->zone)))
if ((damage->map&1 && (!mapdata->flag[MF_PVP] && !mapdata_flag_gvg2(mapdata) && !mapdata->flag[MF_BATTLEGROUND] && !mapdata->flag[MF_SKILL_DAMAGE] && !mapdata->flag[MF_RESTRICTED])) ||
(damage->map&2 && mapdata->flag[MF_PVP]) ||
(damage->map&4 && mapdata_flag_gvg2(mapdata)) ||
(damage->map&8 && mapdata->flag[MF_BATTLEGROUND]) ||
(damage->map&16 && mapdata->flag[MF_SKILL_DAMAGE]) ||
(damage->map&(8*mapdata->zone) && mapdata->flag[MF_RESTRICTED]))
{
return damage->rate[battle_skill_damage_type(target)];
}
@ -4930,7 +4929,7 @@ struct Damage battle_calc_attack_plant(struct Damage wd, struct block_list *src,
}
if( attack_hits && class_ == MOBID_EMPERIUM ) {
if(target && map_flag_gvg2(target->m) && !battle_can_hit_gvg_target(src,target,skill_id,(skill_id)?BF_SKILL:0)) {
if(target && !battle_can_hit_gvg_target(src,target,skill_id,(skill_id)?BF_SKILL:0) && map_flag_gvg2(target->m)) {
wd.damage = wd.damage2 = 0;
return wd;
}
@ -5061,26 +5060,29 @@ struct Damage battle_calc_attack_gvg_bg(struct Damage wd, struct block_list *src
skill_additional_effect(target, (!d_bl) ? src : d_bl, CR_REFLECTSHIELD, 1, BF_WEAPON|BF_SHORT|BF_NORMAL, ATK_DEF, tick);
}
}
struct map_data *mapdata = map_getmapdata(target->m);
if(!wd.damage2) {
wd.damage = battle_calc_damage(src,target,&wd,wd.damage,skill_id,skill_lv);
if( map_flag_gvg2(target->m) )
if( mapdata_flag_gvg2(mapdata) )
wd.damage=battle_calc_gvg_damage(src,target,wd.damage,skill_id,wd.flag);
else if( map_getmapflag(target->m, MF_BATTLEGROUND) )
else if( mapdata->flag[MF_BATTLEGROUND] )
wd.damage=battle_calc_bg_damage(src,target,wd.damage,skill_id,wd.flag);
}
else if(!wd.damage) {
wd.damage2 = battle_calc_damage(src,target,&wd,wd.damage2,skill_id,skill_lv);
if( map_flag_gvg2(target->m) )
if( mapdata_flag_gvg2(mapdata) )
wd.damage2 = battle_calc_gvg_damage(src,target,wd.damage2,skill_id,wd.flag);
else if( map_getmapflag(target->m, MF_BATTLEGROUND) )
else if( mapdata->flag[MF_BATTLEGROUND] )
wd.damage2 = battle_calc_bg_damage(src,target,wd.damage2,skill_id,wd.flag);
}
else {
int64 d1 = wd.damage + wd.damage2,d2 = wd.damage2;
wd.damage = battle_calc_damage(src,target,&wd,d1,skill_id,skill_lv);
if( map_flag_gvg2(target->m) )
if( mapdata_flag_gvg2(mapdata) )
wd.damage = battle_calc_gvg_damage(src,target,wd.damage,skill_id,wd.flag);
else if( map_getmapflag(target->m, MF_BATTLEGROUND) )
else if( mapdata->flag[MF_BATTLEGROUND] )
wd.damage = battle_calc_bg_damage(src,target,wd.damage,skill_id,wd.flag);
wd.damage2 = (int64)d2*100/d1 * wd.damage/100;
if(wd.damage > 1 && wd.damage2 < 1) wd.damage2 = 1;
@ -6385,10 +6387,12 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
}
#endif
struct map_data *mapdata = map_getmapdata(target->m);
ad.damage = battle_calc_damage(src,target,&ad,ad.damage,skill_id,skill_lv);
if (map_flag_gvg2(target->m))
if (mapdata_flag_gvg2(mapdata))
ad.damage = battle_calc_gvg_damage(src,target,ad.damage,skill_id,ad.flag);
else if (map_getmapflag(target->m, MF_BATTLEGROUND))
else if (mapdata->flag[MF_BATTLEGROUND])
ad.damage = battle_calc_bg_damage(src,target,ad.damage,skill_id,ad.flag);
// Skill damage adjustment
@ -6777,10 +6781,12 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *
break;
}
struct map_data *mapdata = map_getmapdata(target->m);
md.damage = battle_calc_damage(src,target,&md,md.damage,skill_id,skill_lv);
if(map_flag_gvg2(target->m))
if(mapdata_flag_gvg2(mapdata))
md.damage = battle_calc_gvg_damage(src,target,md.damage,skill_id,md.flag);
else if(map_getmapflag(target->m, MF_BATTLEGROUND))
else if(mapdata->flag[MF_BATTLEGROUND])
md.damage = battle_calc_bg_damage(src,target,md.damage,skill_id,md.flag);
// Skill damage adjustment
@ -7651,6 +7657,8 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
}
}
struct map_data *mapdata = map_getmapdata(m);
switch( target->type ) { // Checks on actual target
case BL_PC: {
struct status_change* sc = status_get_sc(src);
@ -7697,7 +7705,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
case NC_AXETORNADO:
case SR_SKYNETBLOW:
// Can only hit traps in PVP/GVG maps
if (!map_getmapflag(m, MF_PVP) && !map_getmapflag(m, MF_GVG))
if (!mapdata->flag[MF_PVP] && !mapdata->flag[MF_GVG])
return 0;
break;
}
@ -7714,7 +7722,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
case NC_AXETORNADO:
case SR_SKYNETBLOW:
// Can only hit icewall in PVP/GVG maps
if (!map_getmapflag(m, MF_PVP) && !map_getmapflag(m, MF_GVG))
if (!mapdata->flag[MF_PVP] && !mapdata->flag[MF_GVG])
return 0;
break;
case HT_CLAYMORETRAP:
@ -7767,7 +7775,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
{
struct mob_data *md = BL_CAST(BL_MOB, t_bl);
if( !map_flag_gvg(m) && md->guardian_data && md->guardian_data->guild_id )
if( md->guardian_data && md->guardian_data->guild_id && !mapdata_flag_gvg(mapdata) )
return 0; // Disable guardians/emperiums owned by Guilds on non-woe times.
break;
}
@ -7818,7 +7826,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
state |= BCT_ENEMY; // Can kill anything
strip_enemy = 0;
}
else if( sd->duel_group && !((!battle_config.duel_allow_pvp && map_getmapflag(m, MF_PVP)) || (!battle_config.duel_allow_gvg && map_flag_gvg(m))) )
else if( sd->duel_group && !((!battle_config.duel_allow_pvp && mapdata->flag[MF_PVP]) || (!battle_config.duel_allow_gvg && mapdata_flag_gvg(mapdata))) )
{
if( t_bl->type == BL_PC && (sd->duel_group == ((TBL_PC*)t_bl)->duel_group) )
return (BCT_ENEMY&flag)?1:-1; // Duel targets can ONLY be your enemy, nothing else.
@ -7826,7 +7834,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
return 0; // You can't target anything out of your duel
}
}
if( map_flag_gvg(m) && !sd->status.guild_id && t_bl->type == BL_MOB && ((TBL_MOB*)t_bl)->mob_id == MOBID_EMPERIUM )
if( !sd->status.guild_id && t_bl->type == BL_MOB && ((TBL_MOB*)t_bl)->mob_id == MOBID_EMPERIUM && mapdata_flag_gvg(mapdata) )
return 0; //If you don't belong to a guild, can't target emperium.
if( t_bl->type != BL_PC )
state |= BCT_ENEMY; //Natural enemy.
@ -7835,7 +7843,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
case BL_MOB:
{
struct mob_data *md = BL_CAST(BL_MOB, s_bl);
if( !map_flag_gvg(m) && md->guardian_data && md->guardian_data->guild_id )
if( md->guardian_data && md->guardian_data->guild_id && !mapdata_flag_gvg(mapdata) )
return 0; // Disable guardians/emperium owned by Guilds on non-woe times.
if( !md->special_state.ai )
@ -7880,10 +7888,10 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
return (flag&state)?1:-1;
}
if( map_flag_vs(m) )
if( mapdata_flag_vs(mapdata) )
{ //Check rivalry settings.
int sbg_id = 0, tbg_id = 0;
if( map_getmapflag(m, MF_BATTLEGROUND) )
if(mapdata->flag[MF_BATTLEGROUND] )
{
sbg_id = bg_team_get_id(s_bl);
tbg_id = bg_team_get_id(t_bl);
@ -7891,7 +7899,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
if( flag&(BCT_PARTY|BCT_ENEMY) )
{
int s_party = status_get_party_id(s_bl);
if( s_party && s_party == status_get_party_id(t_bl) && !(map_getmapflag(m, MF_PVP) && map_getmapflag(m, MF_PVP_NOPARTY)) && !(map_flag_gvg(m) && map_getmapflag(m, MF_GVG_NOPARTY)) && (!map_getmapflag(m, MF_BATTLEGROUND) || sbg_id == tbg_id) )
if( s_party && s_party == status_get_party_id(t_bl) && !(mapdata->flag[MF_PVP] && mapdata->flag[MF_PVP_NOPARTY]) && !(mapdata_flag_gvg(mapdata) && mapdata->flag[MF_GVG_NOPARTY]) && (!mapdata->flag[MF_BATTLEGROUND] || sbg_id == tbg_id) )
state |= BCT_PARTY;
else
state |= BCT_ENEMY;
@ -7900,15 +7908,15 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
{
int s_guild = status_get_guild_id(s_bl);
int t_guild = status_get_guild_id(t_bl);
if( !(map_getmapflag(m, MF_PVP) && map_getmapflag(m, MF_PVP_NOGUILD)) && s_guild && t_guild && (s_guild == t_guild || (!(flag&BCT_SAMEGUILD) && guild_isallied(s_guild, t_guild))) && (!map_getmapflag(m, MF_BATTLEGROUND) || sbg_id == tbg_id) )
if( !(mapdata->flag[MF_PVP] && mapdata->flag[MF_PVP_NOGUILD]) && s_guild && t_guild && (s_guild == t_guild || (!(flag&BCT_SAMEGUILD) && guild_isallied(s_guild, t_guild))) && (!mapdata->flag[MF_BATTLEGROUND] || sbg_id == tbg_id) )
state |= BCT_GUILD;
else
state |= BCT_ENEMY;
}
if( state&BCT_ENEMY && map_getmapflag(m, MF_BATTLEGROUND) && sbg_id && sbg_id == tbg_id )
if( state&BCT_ENEMY && mapdata->flag[MF_BATTLEGROUND] && sbg_id && sbg_id == tbg_id )
state &= ~BCT_ENEMY;
if( state&BCT_ENEMY && battle_config.pk_mode && !map_flag_gvg(m) && s_bl->type == BL_PC && t_bl->type == BL_PC )
if( state&BCT_ENEMY && battle_config.pk_mode && !mapdata_flag_gvg(mapdata) && s_bl->type == BL_PC && t_bl->type == BL_PC )
{ // Prevent novice engagement on pk_mode (feature by Valaris)
TBL_PC *sd = (TBL_PC*)s_bl, *sd2 = (TBL_PC*)t_bl;
if (
@ -7920,7 +7928,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
)
state &= ~BCT_ENEMY;
}
}//end map_flag_vs chk rivality
}//end map_flag_vs chk rivality
else
{ //Non pvp/gvg, check party/guild settings.
if( flag&BCT_PARTY || state&BCT_ENEMY )

View File

@ -395,18 +395,15 @@ int chrif_connect(int fd) {
// sends maps to char-server
int chrif_sendmap(int fd) {
int i = 0, size = 4 + map.size() * 4;
ShowStatus("Sending maps to char server...\n");
// Sending normal maps, not instances
WFIFOHEAD(fd, size);
WFIFOHEAD(fd, 4 + instance_start * 4);
WFIFOW(fd,0) = 0x2afa;
WFIFOW(fd,2) = size;
for( auto& pair : map ){
WFIFOW(fd,4+i*4) = pair.second.index;
i++;
}
WFIFOSET(fd,size);
for (int i = 0; i < instance_start; i++)
WFIFOW(fd, 4 + i * 4) = map[i].index;
WFIFOW(fd, 2) = 4 + instance_start * 4;
WFIFOSET(fd, WFIFOW(fd, 2));
return 0;
}

View File

@ -6343,17 +6343,19 @@ void clif_map_property(struct block_list *bl, enum map_property property, enum s
WBUFW(buf,2)=property;
#if PACKETVER >= 20121010
WBUFL(buf,4) = ((map_getmapflag(bl->m, MF_PVP)?1:0)<<0)| // PARTY - Show attack cursor on non-party members (PvP)
((map_getmapflag(bl->m, MF_BATTLEGROUND) || map_flag_gvg2(bl->m)?1:0)<<1)|// GUILD - Show attack cursor on non-guild members (GvG)
((map_getmapflag(bl->m, MF_BATTLEGROUND) || map_flag_gvg2(bl->m)?1:0)<<2)|// SIEGE - Show emblem over characters heads when in GvG (WoE castle)
((map_getmapflag(bl->m, MF_NOMINEEFFECT) || !map_flag_gvg2(bl->m)?0:1)<<3)| // USE_SIMPLE_EFFECT - Automatically enable /mineffect
((map_getmapflag(bl->m, MF_NOLOCKON) || map_flag_vs(bl->m)?1:0)<<4)| // DISABLE_LOCKON - Only allow attacks on other players with shift key or /ns active
((map_getmapflag(bl->m, MF_PVP)?1:0)<<5)| // COUNT_PK - Show the PvP counter
((map_getmapflag(bl->m, MF_PARTYLOCK)?1:0)<<6)| // NO_PARTY_FORMATION - Prevents party creation/modification (Might be used for instance dungeons)
((map_getmapflag(bl->m, MF_BATTLEGROUND)?1:0)<<7)| // BATTLEFIELD - Unknown (Does something for battlegrounds areas)
((map_getmapflag(bl->m, MF_NOCOSTUME)?1:0)<<8)| // DISABLE_COSTUMEITEM - Disable costume sprites
((map_getmapflag(bl->m, MF_NOUSECART)?0:1)<<9)| // USECART - Allow opening cart inventory (Well force it to always allow it)
((map_getmapflag(bl->m, MF_NOSUNMOONSTARMIRACLE)?0:1)<<10); // SUNMOONSTAR_MIRACLE - Blocks Star Gladiator's Miracle from activating
struct map_data *mapdata = map_getmapdata(bl->m);
WBUFL(buf,4) = ((mapdata->flag[MF_PVP]?1:0)<<0)| // PARTY - Show attack cursor on non-party members (PvP)
((mapdata->flag[MF_BATTLEGROUND] || mapdata_flag_gvg2(mapdata)?1:0)<<1)|// GUILD - Show attack cursor on non-guild members (GvG)
((mapdata->flag[MF_BATTLEGROUND] || mapdata_flag_gvg2(mapdata)?1:0)<<2)|// SIEGE - Show emblem over characters heads when in GvG (WoE castle)
((mapdata->flag[MF_NOMINEEFFECT] || !mapdata_flag_gvg2(mapdata)?0:1)<<3)| // USE_SIMPLE_EFFECT - Automatically enable /mineffect
((mapdata->flag[MF_NOLOCKON] || mapdata_flag_vs(mapdata)?1:0)<<4)| // DISABLE_LOCKON - Only allow attacks on other players with shift key or /ns active
((mapdata->flag[MF_PVP]?1:0)<<5)| // COUNT_PK - Show the PvP counter
((mapdata->flag[MF_PARTYLOCK]?1:0)<<6)| // NO_PARTY_FORMATION - Prevents party creation/modification (Might be used for instance dungeons)
((mapdata->flag[MF_BATTLEGROUND]?1:0)<<7)| // BATTLEFIELD - Unknown (Does something for battlegrounds areas)
((mapdata->flag[MF_NOCOSTUME]?1:0)<<8)| // DISABLE_COSTUMEITEM - Disable costume sprites
((mapdata->flag[MF_NOUSECART]?0:1)<<9)| // USECART - Allow opening cart inventory (Well force it to always allow it)
((mapdata->flag[MF_NOSUNMOONSTARMIRACLE]?0:1)<<10); // SUNMOONSTAR_MIRACLE - Blocks Star Gladiator's Miracle from activating
//(1<<11); // Unused bits. 1 - 10 is 0x1 length and 11 is 0x15 length. May be used for future settings.
#endif
@ -10317,15 +10319,15 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
if(sd->status.guild_id)
guild_send_memberinfoshort(sd,1);
struct map_data *mapdata = map_getmapdata(sd->bl.m);
if(battle_config.pc_invincible_time > 0) {
if(map_flag_gvg(sd->bl.m))
if(mapdata_flag_gvg(mapdata))
pc_setinvincibletimer(sd,battle_config.pc_invincible_time<<1);
else
pc_setinvincibletimer(sd,battle_config.pc_invincible_time);
}
struct map_data *mapdata = map_getmapdata(sd->bl.m);
if( mapdata->users++ == 0 && battle_config.dynamic_mobs )
map_spawnmobs(sd->bl.m);
if( !pc_isinvisible(sd) ) { // increment the number of pvp players on the map
@ -10349,9 +10351,9 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
if( sd->bg_id ) clif_bg_hp(sd); // BattleGround System
if(map_getmapflag(sd->bl.m, MF_PVP) && !pc_isinvisible(sd)) {
if(!pc_isinvisible(sd) && mapdata->flag[MF_PVP]) {
if(!battle_config.pk_mode) { // remove pvp stuff for pk_mode [Valaris]
if (!map_getmapflag(sd->bl.m, MF_PVP_NOCALCRANK))
if (!mapdata->flag[MF_PVP_NOCALCRANK])
sd->pvp_timer = add_timer(gettick()+200, pc_calc_pvprank_timer, sd->bl.id, 0);
sd->pvp_rank = 0;
sd->pvp_lastusers = 0;
@ -10362,9 +10364,9 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
clif_map_property(&sd->bl, MAPPROPERTY_FREEPVPZONE, SELF);
} else if(sd->duel_group) // set flag, if it's a duel [LuzZza]
clif_map_property(&sd->bl, MAPPROPERTY_FREEPVPZONE, SELF);
else if (map_getmapflag(sd->bl.m, MF_GVG_DUNGEON))
else if (mapdata->flag[MF_GVG_DUNGEON])
clif_map_property(&sd->bl, MAPPROPERTY_FREEPVPZONE, SELF); //TODO: Figure out the real packet to send here.
else if( map_flag_gvg(sd->bl.m) )
else if( mapdata_flag_gvg(mapdata) )
clif_map_property(&sd->bl, MAPPROPERTY_AGITZONE, SELF);
else
clif_map_property(&sd->bl, MAPPROPERTY_NOTHING, SELF);
@ -10375,7 +10377,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
// pet
if( sd->pd ) {
if( battle_config.pet_no_gvg && map_flag_gvg(sd->bl.m) ) { //Return the pet to egg. [Skotlex]
if( battle_config.pet_no_gvg && mapdata_flag_gvg(mapdata) ) { //Return the pet to egg. [Skotlex]
clif_displaymessage(sd->fd, msg_txt(sd,666));
pet_menu(sd, 3); //Option 3 is return to egg.
} else {
@ -10461,7 +10463,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
if(hom_is_active(sd->hd))
hom_init_timers(sd->hd);
if (night_flag && map_getmapflag(sd->bl.m, MF_NIGHTENABLED)) {
if (night_flag && mapdata->flag[MF_NIGHTENABLED]) {
sd->state.night = 1;
clif_status_load(&sd->bl, EFST_SKE, 1);
}
@ -10518,11 +10520,13 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
}
if (battle_config.bg_flee_penalty != 100 || battle_config.gvg_flee_penalty != 100) {
if ((sd->state.pmap != 0 && map_getmapdata(sd->state.pmap) != nullptr && (map_flag_gvg(sd->state.pmap) || map_getmapflag(sd->state.pmap, MF_BATTLEGROUND))) || (mapdata != nullptr && (map_flag_gvg(sd->bl.m) || map_getmapflag(sd->bl.m, MF_BATTLEGROUND))))
struct map_data *pmap = map_getmapdata(sd->state.pmap);
if ((pmap != nullptr && (mapdata_flag_gvg(pmap) || pmap->flag[MF_BATTLEGROUND])) || (mapdata != nullptr && (mapdata_flag_gvg(mapdata) || mapdata->flag[MF_BATTLEGROUND])))
status_calc_bl(&sd->bl, SCB_FLEE); //Refresh flee penalty
}
if( night_flag && map_getmapflag(sd->bl.m, MF_NIGHTENABLED) )
if( night_flag && mapdata->flag[MF_NIGHTENABLED] )
{ //Display night.
if( !sd->state.night )
{
@ -10536,14 +10540,14 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
clif_status_load(&sd->bl, EFST_SKE, 0);
}
if( map_getmapflag(sd->bl.m, MF_BATTLEGROUND) )
if( mapdata->flag[MF_BATTLEGROUND] )
{
clif_map_type(sd, MAPTYPE_BATTLEFIELD); // Battleground Mode
if( map_getmapflag(sd->bl.m, MF_BATTLEGROUND) == 2 )
clif_bg_updatescore_single(sd);
}
if( map_getmapflag(sd->bl.m, MF_ALLOWKS) && !map_flag_ks(sd->bl.m) )
if( mapdata->flag[MF_ALLOWKS] && !mapdata_flag_ks(mapdata) )
{
char output[128];
sprintf(output, "[ Kill Steal Protection Disable. KS is allowed in this map ]");
@ -10563,7 +10567,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
if (!sd->state.connect_new &&
!sd->vip.disableshowrate &&
sd->state.pmap != sd->bl.m &&
map_getmapflag(sd->state.pmap, MF_BEXP) != map_getmapflag(sd->bl.m, MF_BEXP)
map_getmapflag(sd->state.pmap, MF_BEXP) != mapdata->flag[MF_BEXP]
)
{
clif_display_pinfo(sd,ZC_PERSONAL_INFOMATION);
@ -10572,7 +10576,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
#endif
// Instances do not need their own channels
if( channel_config.map_tmpl.name[0] && (channel_config.map_tmpl.opt&CHAN_OPT_AUTOJOIN) && !map_getmapflag(sd->bl.m,MF_NOMAPCHANNELAUTOJOIN) && !mapdata->instance_id )
if( channel_config.map_tmpl.name[0] && (channel_config.map_tmpl.opt&CHAN_OPT_AUTOJOIN) && !mapdata->instance_id && !mapdata->flag[MF_NOMAPCHANNELAUTOJOIN] )
channel_mjoin(sd); //join new map
clif_pk_mode_message(sd);
@ -10598,7 +10602,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
}
// Don't trigger NPC event or opening vending/buyingstore will be failed
if(!sd->state.autotrade && map_getmapflag(sd->bl.m, MF_LOADEVENT)) // Lance
if(!sd->state.autotrade && mapdata->flag[MF_LOADEVENT]) // Lance
npc_script_event(sd, NPCE_LOADMAP);
if (pc_checkskill(sd, SG_DEVIL) && pc_is_maxjoblv(sd))
@ -10607,7 +10611,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
if (sd->sc.opt2) //Client loses these on warp.
clif_changeoption(&sd->bl);
if ((sd->sc.data[SC_MONSTER_TRANSFORM] || sd->sc.data[SC_ACTIVE_MONSTER_TRANSFORM]) && battle_config.mon_trans_disable_in_gvg && map_flag_gvg2(sd->bl.m)) {
if ((sd->sc.data[SC_MONSTER_TRANSFORM] || sd->sc.data[SC_ACTIVE_MONSTER_TRANSFORM]) && battle_config.mon_trans_disable_in_gvg && mapdata_flag_gvg2(mapdata)) {
status_change_end(&sd->bl, SC_MONSTER_TRANSFORM, INVALID_TIMER);
status_change_end(&sd->bl, SC_ACTIVE_MONSTER_TRANSFORM, INVALID_TIMER);
clif_displaymessage(sd->fd, msg_txt(sd,731)); // Transforming into monster is not allowed in Guild Wars.

View File

@ -28,6 +28,8 @@
struct instance_data instance_data[MAX_INSTANCE_DATA];
struct eri *instance_maps_ers = NULL; ///< Array of maps per instance
int16 instance_start = 0;
static DBMap *InstanceDB; /// Instance DB: struct instance_db, key: id
static DBMap *InstanceNameDB; /// instance id, key: name
@ -1137,6 +1139,7 @@ void do_init_instance(void) {
InstanceDB = uidb_alloc(DB_OPT_BASE);
InstanceNameDB = strdb_alloc((DBOptions)(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA),0);
instance_start = map_num;
instance_readdb();
memset(instance_data, 0, sizeof(instance_data));
memset(&instance_wait, 0, sizeof(instance_wait));

View File

@ -13,6 +13,8 @@
enum send_target : uint8;
struct block_list;
extern int16 instance_start;
#define MAX_INSTANCE_DATA 300 // Essentially how many instances we can create, but instance creation is primarily decided by MAX_MAP_PER_SERVER
#define MAX_MAP_PER_INSTANCE 255 // Max number of maps per instance (Enter map is counted as one) - Supports up to 255 maps

View File

@ -690,9 +690,14 @@ int intif_party_changemap(struct map_session_data *sd,int online)
if(!sd)
return 0;
if( (m=map_mapindex2mapid(sd->mapindex)) >= 0 && map_getmapdata(m)->instance_id )
mapindex = map_getmapdata(map_getmapdata(m)->instance_src_map)->index;
else
if ((m = map_mapindex2mapid(sd->mapindex)) >= 0) {
struct map_data *mapdata = map_getmapdata(m);
if (mapdata->instance_id)
mapindex = map_getmapdata(mapdata->instance_src_map)->index;
else
mapindex = sd->mapindex;
} else
mapindex = sd->mapindex;
WFIFOHEAD(inter_fd,19);

View File

@ -1581,12 +1581,15 @@ static int itemdb_read_sqldb(void) {
bool itemdb_isNoEquip(struct item_data *id, uint16 m) {
if (!id->flag.no_equip)
return false;
if ((!map_flag_vs2(m) && id->flag.no_equip&1) || // Normal
(map_getmapflag(m, MF_PVP) && id->flag.no_equip&2) || // PVP
(map_flag_gvg2_no_te(m) && id->flag.no_equip&4) || // GVG
(map_getmapflag(m, MF_BATTLEGROUND) && id->flag.no_equip&8) || // Battleground
(map_flag_gvg2_te(m) && id->flag.no_equip&16) || // WOE:TE
(map_getmapflag(m, MF_RESTRICTED) && id->flag.no_equip&(8*map_getmapdata(m)->zone)) // Zone restriction
struct map_data *mapdata = map_getmapdata(m);
if ((id->flag.no_equip&1 && !mapdata_flag_vs2(mapdata)) || // Normal
(id->flag.no_equip&2 && mapdata->flag[MF_PVP]) || // PVP
(id->flag.no_equip&4 && mapdata_flag_gvg2_no_te(mapdata)) || // GVG
(id->flag.no_equip&8 && mapdata->flag[MF_BATTLEGROUND]) || // Battleground
(id->flag.no_equip&16 && mapdata_flag_gvg2_te(mapdata)) || // WOE:TE
(id->flag.no_equip&(8*mapdata->zone) && mapdata->flag[MF_RESTRICTED]) // Zone restriction
)
return true;
return false;

View File

@ -122,7 +122,8 @@ static int bl_list_count = 0;
#define MAP_MAX_MSG 1550
#endif
std::map<int16, map_data> map;
struct map_data map[MAX_MAP_PER_SERVER];
int map_num = 0;
int map_port=0;
@ -188,7 +189,10 @@ int enable_grf = 0; //To enable/disable reading maps from GRF files, bypassing m
*/
struct map_data *map_getmapdata(int16 mapid)
{
return util::map_find(map, mapid);
if (mapid < 0 || mapid >= MAX_MAP_PER_SERVER)
return nullptr;
return &map[mapid];
}
/*==========================================
@ -313,7 +317,6 @@ int map_addblock(struct block_list* bl)
{
int16 m, x, y;
int pos;
struct map_data *mapdata;
nullpo_ret(bl);
@ -328,11 +331,11 @@ int map_addblock(struct block_list* bl)
if( m < 0 )
{
ShowError("map_addblock: invalid map id (%d), only %d are loaded.\n", m, map.size());
ShowError("map_addblock: invalid map id (%d), only %d are loaded.\n", m, map_num);
return 1;
}
mapdata = map_getmapdata(m);
struct map_data *mapdata = map_getmapdata(m);
if( x < 0 || x >= mapdata->xs || y < 0 || y >= mapdata->ys )
{
@ -581,9 +584,7 @@ struct skill_unit* map_find_skill_unit_oncell(struct block_list* target,int16 x,
int16 bx,by;
struct block_list *bl;
struct skill_unit *unit;
struct map_data *mapdata;
mapdata = map_getmapdata(target->m);
struct map_data *mapdata = map_getmapdata(target->m);
if (x < 0 || y < 0 || (x >= mapdata->xs) || (y >= mapdata->ys))
return NULL;
@ -615,14 +616,14 @@ int map_foreachinrangeV(int (*func)(struct block_list*,va_list),struct block_lis
struct block_list *bl;
int blockcount = bl_list_count, i;
int x0, x1, y0, y1;
struct map_data *mapdata;
va_list ap_copy;
m = center->m;
if( m < 0 )
return 0;
mapdata = map_getmapdata(m);
struct map_data *mapdata = map_getmapdata(m);
x0 = i16max(center->x - range, 0);
y0 = i16max(center->y - range, 0);
x1 = i16min(center->x + range, mapdata->xs - 1);
@ -730,7 +731,6 @@ int map_foreachinareaV(int(*func)(struct block_list*, va_list), int16 m, int16 x
int returnCount = 0; //total sum of returned values of func()
struct block_list *bl;
int blockcount = bl_list_count, i;
struct map_data *mapdata;
va_list ap_copy;
if (m < 0)
@ -741,7 +741,8 @@ int map_foreachinareaV(int(*func)(struct block_list*, va_list), int16 m, int16 x
if (y1 < y0)
SWAP(y0, y1);
mapdata = map_getmapdata(m);
struct map_data *mapdata = map_getmapdata(m);
x0 = i16max(x0, 0);
y0 = i16max(y0, 0);
x1 = i16min(x1, mapdata->xs - 1);
@ -900,7 +901,6 @@ int map_forcountinarea(int (*func)(struct block_list*,va_list), int16 m, int16 x
int returnCount = 0; //total sum of returned values of func() [Skotlex]
struct block_list *bl;
int blockcount = bl_list_count, i;
struct map_data *mapdata;
va_list ap;
if ( m < 0 )
@ -911,7 +911,8 @@ int map_forcountinarea(int (*func)(struct block_list*,va_list), int16 m, int16 x
if ( y1 < y0 )
SWAP(y0, y1);
mapdata = map_getmapdata(m);
struct map_data *mapdata = map_getmapdata(m);
x0 = i16max(x0, 0);
y0 = i16max(y0, 0);
x1 = i16min(x1, mapdata->xs - 1);
@ -962,14 +963,15 @@ int map_foreachinmovearea(int (*func)(struct block_list*,va_list), struct block_
struct block_list *bl;
int blockcount = bl_list_count, i;
int16 x0, x1, y0, y1;
struct map_data *mapdata;
va_list ap;
if ( !range ) return 0;
if ( !dx && !dy ) return 0; //No movement.
m = center->m;
mapdata = map_getmapdata(m);
struct map_data *mapdata = map_getmapdata(m);
x0 = center->x - range;
x1 = center->x + range;
y0 = center->y - range;
@ -1168,7 +1170,6 @@ int map_foreachinpath(int (*func)(struct block_list*,va_list),int16 m,int16 x0,i
int magnitude2, len_limit; //The square of the magnitude
int k, xi, yi, xu, yu;
int mx0 = x0, mx1 = x1, my0 = y0, my1 = y1;
struct map_data *mapdata;
va_list ap;
//Avoid needless calculations by not getting the sqrt right away.
@ -1210,7 +1211,8 @@ int map_foreachinpath(int (*func)(struct block_list*,va_list),int16 m,int16 x0,i
if ( my0 > my1 )
SWAP(my0, my1);
mapdata = map_getmapdata(m);
struct map_data *mapdata = map_getmapdata(m);
mx0 = max(mx0, 0);
my0 = max(my0, 0);
mx1 = min(mx1, mapdata->xs - 1);
@ -1329,7 +1331,6 @@ int map_foreachindir(int(*func)(struct block_list*, va_list), int16 m, int16 x0,
uint8 dir = map_calc_dir_xy(x0, y0, x1, y1, 6);
short dx = dirx[dir];
short dy = diry[dir];
struct map_data *mapdata;
va_list ap;
if (m < 0)
@ -1350,7 +1351,8 @@ int map_foreachindir(int(*func)(struct block_list*, va_list), int16 m, int16 x0,
length++;
}
mapdata = map_getmapdata(m);
struct map_data *mapdata = map_getmapdata(m);
//Get area that needs to be checked
mx0 = x0 + dx*(offset / ((dir % 2) + 1));
my0 = y0 + dy*(offset / ((dir % 2) + 1));
@ -2620,11 +2622,26 @@ int map_addinstancemap(const char *name, unsigned short instance_id)
return -2;
}
// Copy the map
int16 dst_m = static_cast<int16>(map.size());
int16 dst_m = -1, i;
for (i = instance_start; i < MAX_MAP_PER_SERVER; i++) {
if (!map[i].name[0])
break;
}
if (i < map_num) // Destination map value overwrites another
dst_m = i;
else if (i < MAX_MAP_PER_SERVER) // Destination map value increments to new map
dst_m = map_num++;
else {
// Out of bounds
ShowError("map_addinstancemap failed. map_num(%d) > map_max(%d)\n", map_num, MAX_MAP_PER_SERVER);
return -3;
}
struct map_data *src_map = map_getmapdata(src_m);
map.insert({ dst_m, *src_map });
// Copy the map
memcpy(&map[dst_m], src_map, sizeof(struct map_data));
// Retrieve new map data
struct map_data *dst_map = map_getmapdata(dst_m);
@ -2747,7 +2764,6 @@ int map_delinstancemap(int m)
mapindex_removemap( mapdata->index );
map_removemapdb(mapdata);
map.erase(m);
return 1;
}
@ -3268,10 +3284,8 @@ bool map_iwall_set(int16 m, int16 x, int16 y, int size, int8 dir, bool shootable
iwall->size = i;
struct map_data *mapdata = map_getmapdata(m);
strdb_put(iwall_db, iwall->wall_name, iwall);
mapdata->iwall_num++;
map_getmapdata(m)->iwall_num++;
return true;
}
@ -3281,9 +3295,8 @@ void map_iwall_get(struct map_session_data *sd) {
DBIterator* iter;
int16 x1, y1;
int i;
struct map_data *mapdata = map_getmapdata(sd->bl.m);
if( mapdata->iwall_num < 1 )
if( map_getmapdata(sd->bl.m)->iwall_num < 1 )
return;
iter = db_iterator(iwall_db);
@ -3480,35 +3493,41 @@ int map_addmap(char* mapname)
{
if( strcmpi(mapname,"clear")==0 )
{
map.clear();
map_num = 0;
instance_start = 0;
return 0;
}
struct map_data entry = {};
if (map_num >= MAX_MAP_PER_SERVER - 1) {
ShowError("Could not add map '" CL_WHITE "%s" CL_RESET "', the limit of maps has been reached.\n", mapname);
return 1;
}
mapindex_getmapname(mapname, entry.name);
map.insert({ static_cast<int16>(map.size()), entry });
mapindex_getmapname(mapname, map[map_num].name);
map_num++;
return 0;
}
static void map_delmapid(int id)
{
ShowNotice("Removing map [ %s ] from maplist" CL_CLL "\n",map_getmapdata(id)->name);
map.erase(id);
ShowNotice("Removing map [ %s ] from maplist" CL_CLL "\n",map[id].name);
for (int i = id; i < map_num - 1; i++)
map[i] = map[i + 1];
map_num--;
}
int map_delmap(char* mapname){
char map_name[MAP_NAME_LENGTH];
if (strcmpi(mapname, "all") == 0) {
map.clear();
map_num = 0;
return 0;
}
mapindex_getmapname(mapname, map_name);
for( auto& pair : map ){
if (strcmp(pair.second.name, map_name) == 0) {
map_delmapid(pair.first);
for (int i = 0; i < map_num; i++) {
if (strcmp(map[i].name, map_name) == 0) {
map_delmapid(i);
return 1;
}
}
@ -3518,26 +3537,26 @@ int map_delmap(char* mapname){
/// Initializes map flags and adjusts them depending on configuration.
void map_flags_init(void){
for( auto& pair : map ){
struct map_data *mapdata = &pair.second;
for (int i = 0; i < map_num; i++) {
struct map_data *mapdata = &map[i];
union u_mapflag_args args = {};
args.flag_val = 100;
// additional mapflag data
mapdata->zone = 0; // restricted mapflag zone
map_setmapflag(pair.first, MF_NOCOMMAND, false); // nocommand mapflag level
map_setmapflag_sub(pair.first, MF_BEXP, true, &args); // per map base exp multiplicator
map_setmapflag_sub(pair.first, MF_JEXP, true, &args); // per map job exp multiplicator
mapdata->flag[MF_NOCOMMAND] = false; // nocommand mapflag level
map_setmapflag_sub(i, MF_BEXP, true, &args); // per map base exp multiplicator
map_setmapflag_sub(i, MF_JEXP, true, &args); // per map job exp multiplicator
// skill damage
mapdata->damage_adjust = {};
// adjustments
if( battle_config.pk_mode )
map_setmapflag(pair.first, MF_PVP, true); // make all maps pvp for pk_mode [Valaris]
if( battle_config.pk_mode && !mapdata->flag[MF_PVP] )
mapdata->flag[MF_PVP] = true; // make all maps pvp for pk_mode [Valaris]
map_free_questinfo(pair.first);
map_free_questinfo(i);
}
}
@ -3674,17 +3693,16 @@ int map_readallmaps (void)
}
}
int i = 0;
std::vector<int16> maps_removed;
int maps_removed = 0;
for( auto &pair : map ){
for (int i = 0; i < map_num; i++) {
size_t size;
bool success = false;
unsigned short idx = 0;
struct map_data *mapdata = &pair.second;
struct map_data *mapdata = &map[i];
// show progress
ShowStatus("Loading maps [%i/%i]: %s" CL_CLL "\r", i++, map.size(), mapdata->name);
ShowStatus("Loading maps [%i/%i]: %s" CL_CLL "\r", i, map_num, mapdata->name);
if( enable_grf ){
// try to load the map
@ -3703,23 +3721,30 @@ int map_readallmaps (void)
}
// The map was not found - remove it
if( !(idx = mapindex_name2id(mapdata->name)) || !success ){
maps_removed.push_back(pair.first);
if (!(idx = mapindex_name2id(mapdata->name)) || !success) {
map_delmapid(i);
maps_removed++;
i--;
continue;
}
mapdata->index = idx;
if (uidb_get(map_db,(unsigned int)mapdata->index) != NULL)
{
if (uidb_get(map_db,(unsigned int)mapdata->index) != NULL) {
ShowWarning("Map %s already loaded!" CL_CLL "\n", mapdata->name);
maps_removed.push_back(pair.first);
if (mapdata->cell) {
aFree(mapdata->cell);
mapdata->cell = NULL;
}
map_delmapid(i);
maps_removed++;
i--;
continue;
}
map_addmap2db(mapdata);
mapdata->m = pair.first;
mapdata->m = i;
memset(mapdata->moblist, 0, sizeof(mapdata->moblist)); //Initialize moblist [Skotlex]
mapdata->mob_delete_timer = INVALID_TIMER; //Initialize timer [Skotlex]
@ -3742,16 +3767,11 @@ int map_readallmaps (void)
aFree(map_cache_buffer[0]);
}
if( !maps_removed.empty() ){
for( auto& id : maps_removed ){
map_delmapid( id );
}
ShowNotice("Maps removed: '" CL_WHITE "%d" CL_RESET "'\n",maps_removed.size());
}
if (maps_removed)
ShowNotice("Maps removed: '" CL_WHITE "%d" CL_RESET "'\n", maps_removed);
// finished map loading
ShowInfo("Successfully loaded '" CL_WHITE "%d" CL_RESET "' maps." CL_CLL "\n",map.size());
ShowInfo("Successfully loaded '" CL_WHITE "%d" CL_RESET "' maps." CL_CLL "\n",map_num);
return 0;
}
@ -4457,7 +4477,7 @@ int map_getmapflag_sub(int16 m, enum e_mapflag mapflag, union u_mapflag_args *ar
return -1;
}
struct map_data *mapdata = map_getmapdata(m);
struct map_data *mapdata = &map[m];
if (mapflag < MF_MIN || mapflag >= MF_MAX) {
ShowWarning("map_getmapflag: Invalid mapflag %d on map %s.\n", mapflag, mapdata->name);
@ -4465,12 +4485,14 @@ int map_getmapflag_sub(int16 m, enum e_mapflag mapflag, union u_mapflag_args *ar
}
switch(mapflag) {
case MF_RESTRICTED:
return mapdata->zone;
case MF_NOLOOT:
return util::map_get(mapdata->flag, MF_NOMOBLOOT, 0) && util::map_get(mapdata->flag, MF_NOMVPLOOT, 0);
return util::umap_get(mapdata->flag, static_cast<int16>(MF_NOMOBLOOT), 0) && util::umap_get(mapdata->flag, static_cast<int16>(MF_NOMVPLOOT), 0);
case MF_NOPENALTY:
return util::map_get(mapdata->flag, MF_NOEXPPENALTY, 0) && util::map_get(mapdata->flag, MF_NOZENYPENALTY, 0);
return util::umap_get(mapdata->flag, static_cast<int16>(MF_NOEXPPENALTY), 0) && util::umap_get(mapdata->flag, static_cast<int16>(MF_NOZENYPENALTY), 0);
case MF_NOEXP:
return util::map_get(mapdata->flag, MF_NOBASEEXP, 0) && util::map_get(mapdata->flag, MF_NOJOBEXP, 0);
return util::umap_get(mapdata->flag, static_cast<int16>(MF_NOBASEEXP), 0) && util::umap_get(mapdata->flag, static_cast<int16>(MF_NOJOBEXP), 0);
case MF_SKILL_DAMAGE:
nullpo_retr(-1, args);
@ -4483,10 +4505,10 @@ int map_getmapflag_sub(int16 m, enum e_mapflag mapflag, union u_mapflag_args *ar
case SKILLDMG_CASTER:
return mapdata->damage_adjust.caster;
default:
return util::map_get(mapdata->flag, mapflag, 0);
return util::umap_get(mapdata->flag, static_cast<int16>(mapflag), 0);
}
default:
return util::map_get(mapdata->flag, mapflag, 0);
return util::umap_get(mapdata->flag, static_cast<int16>(mapflag), 0);
}
}
@ -4505,7 +4527,7 @@ bool map_setmapflag_sub(int16 m, enum e_mapflag mapflag, bool status, union u_ma
return false;
}
struct map_data *mapdata = map_getmapdata(m);
struct map_data *mapdata = &map[m];
if (mapflag < MF_MIN || mapflag >= MF_MAX) {
ShowWarning("map_setmapflag: Invalid mapflag %d on map %s.\n", mapflag, mapdata->name);
@ -4529,28 +4551,28 @@ bool map_setmapflag_sub(int16 m, enum e_mapflag mapflag, bool status, union u_ma
else {
if (!battle_config.pk_mode)
map_foreachinmap(map_mapflag_pvp_sub, m, BL_PC);
if (map_getmapflag(m, MF_GVG)) {
map_setmapflag(m, MF_GVG, false);
if (mapdata->flag[MF_GVG]) {
mapdata->flag[MF_GVG] = false;
ShowWarning("map_setmapflag: Unable to set GvG and PvP flags for the same map! Removing GvG flag from %s.\n", mapdata->name);
}
if (map_getmapflag(m, MF_GVG_TE)) {
map_setmapflag(m, MF_GVG_TE, false);
if (mapdata->flag[MF_GVG_TE]) {
mapdata->flag[MF_GVG_TE] = false;
ShowWarning("map_setmapflag: Unable to set GvG TE and PvP flags for the same map! Removing GvG TE flag from %s.\n", mapdata->name);
}
if (map_getmapflag(m, MF_GVG_DUNGEON)) {
map_setmapflag(m, MF_GVG_DUNGEON, false);
if (mapdata->flag[MF_GVG_DUNGEON]) {
mapdata->flag[MF_GVG_DUNGEON] = false;
ShowWarning("map_setmapflag: Unable to set GvG Dungeon and PvP flags for the same map! Removing GvG Dungeon flag from %s.\n", mapdata->name);
}
if (map_getmapflag(m, MF_GVG_CASTLE)) {
map_setmapflag(m, MF_GVG_CASTLE, false);
if (mapdata->flag[MF_GVG_CASTLE]) {
mapdata->flag[MF_GVG_CASTLE] = false;
ShowWarning("map_setmapflag: Unable to set GvG Castle and PvP flags for the same map! Removing GvG Castle flag from %s.\n", mapdata->name);
}
if (map_getmapflag(m, MF_GVG_TE_CASTLE)) {
map_setmapflag(m, MF_GVG_TE_CASTLE, false);
if (mapdata->flag[MF_GVG_TE_CASTLE]) {
mapdata->flag[MF_GVG_TE_CASTLE] = false;
ShowWarning("map_setmapflag: Unable to set GvG TE Castle and PvP flags for the same map! Removing GvG TE Castle flag from %s.\n", mapdata->name);
}
if (map_getmapflag(m, MF_BATTLEGROUND)) {
map_setmapflag(m, MF_BATTLEGROUND, false);
if (mapdata->flag[MF_BATTLEGROUND]) {
mapdata->flag[MF_BATTLEGROUND] = false;
ShowWarning("map_setmapflag: Unable to set Battleground and PvP flags for the same map! Removing Battleground flag from %s.\n", mapdata->name);
}
}
@ -4562,12 +4584,13 @@ bool map_setmapflag_sub(int16 m, enum e_mapflag mapflag, bool status, union u_ma
clif_map_property_mapall(m, MAPPROPERTY_NOTHING);
else {
clif_map_property_mapall(m, MAPPROPERTY_AGITZONE);
if (map_getmapflag(m, MF_PVP)) {
map_setmapflag(m, MF_PVP, false);
ShowWarning("map_setmapflag: Unable to set PvP and GvG flags for the same map! Removing PvP flag from %s.\n", mapdata->name);
if (mapdata->flag[MF_PVP]) {
mapdata->flag[MF_PVP] = false;
if (!battle_config.pk_mode)
ShowWarning("map_setmapflag: Unable to set PvP and GvG flags for the same map! Removing PvP flag from %s.\n", mapdata->name);
}
if (map_getmapflag(m, MF_BATTLEGROUND)) {
map_setmapflag(m, MF_BATTLEGROUND, false);
if (mapdata->flag[MF_BATTLEGROUND]) {
mapdata->flag[MF_BATTLEGROUND] = false;
ShowWarning("map_setmapflag: Unable to set Battleground and GvG flags for the same map! Removing Battleground flag from %s.\n", mapdata->name);
}
}
@ -4576,37 +4599,39 @@ bool map_setmapflag_sub(int16 m, enum e_mapflag mapflag, bool status, union u_ma
case MF_GVG_CASTLE:
case MF_GVG_TE_CASTLE:
if (status) {
if (mapflag == MF_GVG_CASTLE && map_getmapflag(m, MF_GVG_TE_CASTLE)) {
map_setmapflag(m, MF_GVG_TE_CASTLE, false);
if (mapflag == MF_GVG_CASTLE && mapdata->flag[MF_GVG_TE_CASTLE]) {
mapdata->flag[MF_GVG_TE_CASTLE] = false;
ShowWarning("map_setmapflag: Unable to set GvG TE Castle and GvG Castle flags for the same map! Removing GvG TE Castle flag from %s.\n", mapdata->name);
}
if (mapflag == MF_GVG_TE_CASTLE && map_getmapflag(m, MF_GVG_CASTLE)) {
map_setmapflag(m, MF_GVG_CASTLE, false);
if (mapflag == MF_GVG_TE_CASTLE && mapdata->flag[MF_GVG_CASTLE]) {
mapdata->flag[MF_GVG_CASTLE] = false;
ShowWarning("map_setmapflag: Unable to set GvG Castle and GvG TE Castle flags for the same map! Removing GvG Castle flag from %s.\n", mapdata->name);
}
if (map_getmapflag(m, MF_PVP)) {
map_setmapflag(m, MF_PVP, false);
ShowWarning("npc_parse_mapflag: Unable to set PvP and GvG%s Castle flags for the same map! Removing PvP flag from %s.\n", (mapflag == MF_GVG_CASTLE ? NULL : " TE"), mapdata->name);
if (mapdata->flag[MF_PVP]) {
mapdata->flag[MF_PVP] = false;
if (!battle_config.pk_mode)
ShowWarning("npc_parse_mapflag: Unable to set PvP and GvG%s Castle flags for the same map! Removing PvP flag from %s.\n", (mapflag == MF_GVG_CASTLE ? NULL : " TE"), mapdata->name);
}
}
mapdata->flag[mapflag] = status;
break;
case MF_GVG_DUNGEON:
if (status && map_getmapflag(m, MF_PVP)) {
map_setmapflag(m, MF_PVP, false);
ShowWarning("map_setmapflag: Unable to set PvP and GvG Dungeon flags for the same map! Removing PvP flag from %s.\n", mapdata->name);
if (status && mapdata->flag[MF_PVP]) {
mapdata->flag[MF_PVP] = false;
if (!battle_config.pk_mode)
ShowWarning("map_setmapflag: Unable to set PvP and GvG Dungeon flags for the same map! Removing PvP flag from %s.\n", mapdata->name);
}
mapdata->flag[mapflag] = status;
break;
case MF_NOBASEEXP:
case MF_NOJOBEXP:
if (status) {
if (mapflag == MF_NOBASEEXP && map_getmapflag(m, MF_BEXP) != 100) {
map_setmapflag(m, MF_BEXP, false);
if (mapflag == MF_NOBASEEXP && mapdata->flag[MF_BEXP] != 100) {
mapdata->flag[MF_BEXP] = false;
ShowWarning("map_setmapflag: Unable to set BEXP and No Base EXP flags for the same map! Removing BEXP flag from %s.\n", mapdata->name);
}
if (mapflag == MF_NOJOBEXP && map_getmapflag(m, MF_JEXP) != 100) {
map_setmapflag(m, MF_JEXP, false);
if (mapflag == MF_NOJOBEXP && mapdata->flag[MF_JEXP] != 100) {
mapdata->flag[MF_JEXP] = false;
ShowWarning("map_setmapflag: Unable to set JEXP and No Job EXP flags for the same map! Removing JEXP flag from %s.\n", mapdata->name);
}
}
@ -4652,12 +4677,12 @@ bool map_setmapflag_sub(int16 m, enum e_mapflag mapflag, bool status, union u_ma
if (status) {
nullpo_retr(false, args);
if (mapflag == MF_JEXP && map_getmapflag(m, MF_NOJOBEXP)) {
map_setmapflag(m, MF_NOJOBEXP, false);
if (mapflag == MF_JEXP && mapdata->flag[MF_NOJOBEXP]) {
mapdata->flag[MF_NOJOBEXP] = false;
ShowWarning("map_setmapflag: Unable to set No Job EXP and JEXP flags for the same map! Removing No Job EXP flag from %s.\n", mapdata->name);
}
if (mapflag == MF_BEXP && map_getmapflag(m, MF_NOBASEEXP)) {
map_setmapflag(m, MF_NOBASEEXP, false);
if (mapflag == MF_BEXP && mapdata->flag[MF_NOBASEEXP]) {
mapdata->flag[MF_NOBASEEXP] = false;
ShowWarning("map_setmapflag: Unable to set No Base EXP and BEXP flags for the same map! Removing No Base EXP flag from %s.\n", mapdata->name);
}
mapdata->flag[mapflag] = args->flag_val;
@ -4668,20 +4693,20 @@ bool map_setmapflag_sub(int16 m, enum e_mapflag mapflag, bool status, union u_ma
if (status) {
nullpo_retr(false, args);
if (map_getmapflag(m, MF_PVP)) {
map_setmapflag(m, MF_PVP, false);
if (mapdata->flag[MF_PVP]) {
mapdata->flag[MF_PVP] = false;
ShowWarning("map_setmapflag: Unable to set PvP and Battleground flags for the same map! Removing PvP flag from %s.\n", mapdata->name);
}
if (map_getmapflag(m, MF_GVG)) {
map_setmapflag(m, MF_GVG, false);
if (mapdata->flag[MF_GVG]) {
mapdata->flag[MF_GVG] = false;
ShowWarning("map_setmapflag: Unable to set GvG and Battleground flags for the same map! Removing GvG flag from %s.\n", mapdata->name);
}
if (map_getmapflag(m, MF_GVG_DUNGEON)) {
map_setmapflag(m, MF_GVG_DUNGEON, false);
if (mapdata->flag[MF_GVG_DUNGEON]) {
mapdata->flag[MF_GVG_DUNGEON] = false;
ShowWarning("map_setmapflag: Unable to set GvG Dungeon and Battleground flags for the same map! Removing GvG Dungeon flag from %s.\n", mapdata->name);
}
if (map_getmapflag(m, MF_GVG_CASTLE)) {
map_setmapflag(m, MF_GVG_CASTLE, false);
if (mapdata->flag[MF_GVG_CASTLE]) {
mapdata->flag[MF_GVG_CASTLE] = false;
ShowWarning("map_setmapflag: Unable to set GvG Castle and Battleground flags for the same map! Removing GvG Castle flag from %s.\n", mapdata->name);
}
mapdata->flag[mapflag] = ((args->flag_val <= 0 || args->flag_val > 2) ? 1 : args->flag_val);
@ -4756,13 +4781,14 @@ void do_final(void){
do_clear_npc();
// remove all objects on maps
int i = 0;
for( auto& pair : map ){
ShowStatus("Cleaning up maps [%d/%d]: %s..." CL_CLL "\r", i++, map.size(), pair.second.name);
map_foreachinmap(cleanup_sub, pair.first, BL_ALL);
channel_delete(pair.second.channel,false);
for (int i = 0; i < map_num; i++) {
struct map_data *mapdata = map_getmapdata(i);
ShowStatus("Cleaning up maps [%d/%d]: %s..." CL_CLL "\r", i++, map_num, mapdata->name);
map_foreachinmap(cleanup_sub, i, BL_ALL);
channel_delete(mapdata->channel,false);
}
ShowStatus("Cleaned up %d maps." CL_CLL "\n", map.size());
ShowStatus("Cleaned up %d maps." CL_CLL "\n", map_num);
id_db->foreach(id_db,cleanup_db_sub);
chrif_char_reset_offline();
@ -4802,8 +4828,8 @@ void do_final(void){
map_db->destroy(map_db, map_db_final);
for( auto& pair : map ){
struct map_data *mapdata = &pair.second;
for (int i = 0; i < map_num; i++) {
struct map_data *mapdata = map_getmapdata(i);
if(mapdata->cell) aFree(mapdata->cell);
if(mapdata->block) aFree(mapdata->block);
@ -4814,7 +4840,7 @@ void do_final(void){
for (int j=0; j<MAX_MOB_LIST_PER_MAP; j++)
if (mapdata->moblist[j]) aFree(mapdata->moblist[j]);
}
map_free_questinfo(pair.first);
map_free_questinfo(i);
mapdata->damage_adjust = {};
}

View File

@ -5,8 +5,8 @@
#define _MAP_HPP_
#include <algorithm>
#include <map>
#include <stdarg.h>
#include <unordered_map>
#include <vector>
#include "../common/cbasetypes.hpp"
@ -231,22 +231,6 @@ enum e_mapid {
#define DEFAULT_AUTOSAVE_INTERVAL 5*60*1000
/// Specifies maps where players may hit each other
#define map_flag_vs(m) (map_getmapflag(m, MF_PVP) || map_getmapflag(m, MF_GVG_DUNGEON) ||map_getmapflag(m, MF_GVG) || ((agit_flag || agit2_flag) && map_getmapflag(m, MF_GVG_CASTLE)) || map_getmapflag(m, MF_GVG_TE) || (agit3_flag && map_getmapflag(m, MF_GVG_TE_CASTLE)) || map_getmapflag(m, MF_BATTLEGROUND))
/// Versus map: PVP, BG, GVG, GVG Dungeons, and GVG Castles (regardless of agit_flag status)
#define map_flag_vs2(m) (map_getmapflag(m, MF_PVP) || map_getmapflag(m, MF_GVG_DUNGEON) || map_getmapflag(m, MF_GVG) || map_getmapflag(m, MF_GVG_CASTLE) || map_getmapflag(m, MF_GVG_TE) || map_getmapflag(m, MF_GVG_TE_CASTLE) || map_getmapflag(m, MF_BATTLEGROUND))
/// Specifies maps that have special GvG/WoE restrictions
#define map_flag_gvg(m) (map_getmapflag(m, MF_GVG) || ((agit_flag || agit2_flag) && map_getmapflag(m, MF_GVG_CASTLE)) || map_getmapflag(m, MF_GVG_TE) || (agit3_flag && map_getmapflag(m, MF_GVG_TE_CASTLE)))
/// Specifies if the map is tagged as GvG/WoE (regardless of agit_flag status)
#define map_flag_gvg2(m) (map_getmapflag(m, MF_GVG) || map_getmapflag(m, MF_GVG_TE) || map_getmapflag(m, MF_GVG_CASTLE) || map_getmapflag(m, MF_GVG_TE_CASTLE))
/// No Kill Steal Protection
#define map_flag_ks(m) (map_getmapflag(m, MF_TOWN) || map_getmapflag(m, MF_PVP) || map_getmapflag(m, MF_GVG) || map_getmapflag(m, MF_GVG_TE) || map_getmapflag(m, MF_BATTLEGROUND))
/// WOE:TE Maps (regardless of agit_flag status) [Cydh]
#define map_flag_gvg2_te(m) (map_getmapflag(m, MF_GVG_TE) || map_getmapflag(m, MF_GVG_TE_CASTLE))
/// Check if map is GVG maps exclusion for item, skill, and status restriction check (regardless of agit_flag status) [Cydh]
#define map_flag_gvg2_no_te(m) (map_getmapflag(m, MF_GVG) || map_getmapflag(m, MF_GVG_CASTLE))
//This stackable implementation does not means a BL can be more than one type at a time, but it's
//meant to make it easier to check for multiple types at a time on invocations such as map_foreach* calls [Skotlex]
enum bl_type : uint16{
@ -735,7 +719,7 @@ struct map_data {
int users_pvp;
int iwall_num; // Total of invisible walls in this map
std::map<e_mapflag, int> flag;
std::unordered_map<int16, int> flag;
struct point save;
std::vector<s_drop_list> drop_list;
uint32 zone; // zone number (for item/skill restrictions)
@ -776,7 +760,8 @@ int map_getcellp(struct map_data* m,int16 x,int16 y,cell_chk cellchk);
void map_setcell(int16 m, int16 x, int16 y, cell_t cell, bool flag);
void map_setgatcell(int16 m, int16 x, int16 y, int gat);
extern std::map<int16, map_data> map;
extern struct map_data map[];
extern int map_num;
extern int autosave_interval;
extern int minsave_interval;
@ -790,6 +775,177 @@ extern bool agit2_flag;
extern bool agit3_flag;
#define is_agit_start() (agit_flag || agit2_flag || agit3_flag)
/**
* Specifies maps where players may hit each other
* @param mapdata: Map Data
* @return True on success or false otherwise
*/
inline bool mapdata_flag_vs(struct map_data *mapdata) {
if (mapdata == nullptr)
return false;
if (mapdata->flag[MF_PVP] || mapdata->flag[MF_GVG_DUNGEON] || mapdata->flag[MF_GVG] || ((agit_flag || agit2_flag) && mapdata->flag[MF_GVG_CASTLE]) || mapdata->flag[MF_GVG_TE] || (agit3_flag && mapdata->flag[MF_GVG_TE_CASTLE]) || mapdata->flag[MF_BATTLEGROUND])
return true;
return false;
}
/**
* Versus map: PVP, BG, GVG, GVG Dungeons, and GVG Castles (regardless of agit_flag status)
* @param mapdata: Map Data
* @return True on success or false otherwise
*/
inline bool mapdata_flag_vs2(struct map_data *mapdata) {
if (mapdata == nullptr)
return false;
if (mapdata->flag[MF_PVP] || mapdata->flag[MF_GVG_DUNGEON] || mapdata->flag[MF_GVG] || mapdata->flag[MF_GVG_CASTLE] || mapdata->flag[MF_GVG_TE] || mapdata->flag[MF_GVG_TE_CASTLE] || mapdata->flag[MF_BATTLEGROUND])
return true;
return false;
}
/**
* Specifies maps that have special GvG/WoE restrictions
* @param mapdata: Map Data
* @return True on success or false otherwise
*/
inline bool mapdata_flag_gvg(struct map_data *mapdata) {
if (mapdata == nullptr)
return false;
if (mapdata->flag[MF_GVG] || ((agit_flag || agit2_flag) && mapdata->flag[MF_GVG_CASTLE]) || mapdata->flag[MF_GVG_TE] || (agit3_flag && mapdata->flag[MF_GVG_TE_CASTLE]))
return true;
return false;
}
/**
* Specifies if the map is tagged as GvG/WoE (regardless of agit_flag status)
* @param mapdata: Map Data
* @return True on success or false otherwise
*/
inline bool mapdata_flag_gvg2(struct map_data *mapdata) {
if (mapdata == nullptr)
return false;
if (mapdata->flag[MF_GVG] || mapdata->flag[MF_GVG_TE] || mapdata->flag[MF_GVG_CASTLE] || mapdata->flag[MF_GVG_TE_CASTLE])
return true;
return false;
}
/**
* No Kill Steal Protection
* @param mapdata: Map Data
* @return True on success or false otherwise
*/
inline bool mapdata_flag_ks(struct map_data *mapdata) {
if (mapdata == nullptr)
return false;
if (mapdata->flag[MF_TOWN] || mapdata->flag[MF_PVP] || mapdata->flag[MF_GVG] || mapdata->flag[MF_GVG_TE] || mapdata->flag[MF_BATTLEGROUND])
return true;
return false;
}
/**
* WOE:TE Maps (regardless of agit_flag status)
* @param mapdata: Map Data
* @return True on success or false otherwise
* @author Cydh
*/
inline bool mapdata_flag_gvg2_te(struct map_data *mapdata) {
if (mapdata == nullptr)
return false;
if (mapdata->flag[MF_GVG_TE] || mapdata->flag[MF_GVG_TE_CASTLE])
return true;
return false;
}
/**
* Check if map is GVG maps exclusion for item, skill, and status restriction check (regardless of agit_flag status)
* @param mapdata: Map Data
* @return True on success or false otherwise
* @author Cydh
*/
inline bool mapdata_flag_gvg2_no_te(struct map_data *mapdata) {
if (mapdata == nullptr)
return false;
if (mapdata->flag[MF_GVG] || mapdata->flag[MF_GVG_CASTLE])
return true;
return false;
}
/// Backwards compatibility
inline bool map_flag_vs(int16 m) {
if (m < 0)
return false;
struct map_data *mapdata = &map[m];
return mapdata_flag_vs(mapdata);
}
inline bool map_flag_vs2(int16 m) {
if (m < 0)
return false;
struct map_data *mapdata = &map[m];
return mapdata_flag_vs2(mapdata);
}
inline bool map_flag_gvg(int16 m) {
if (m < 0)
return false;
struct map_data *mapdata = &map[m];
return mapdata_flag_gvg(mapdata);
}
inline bool map_flag_gvg2(int16 m) {
if (m < 0)
return false;
struct map_data *mapdata = &map[m];
return mapdata_flag_gvg2(mapdata);
}
inline bool map_flag_ks(int16 m) {
if (m < 0)
return false;
struct map_data *mapdata = &map[m];
return mapdata_flag_ks(mapdata);
}
inline bool map_flag_gvg2_te(int16 m) {
if (m < 0)
return false;
struct map_data *mapdata = &map[m];
return mapdata_flag_gvg2_te(mapdata);
}
inline bool map_flag_gvg2_no_te(int16 m) {
if (m < 0)
return false;
struct map_data *mapdata = &map[m];
return mapdata_flag_gvg2_no_te(mapdata);
}
extern char motd_txt[];
extern char help_txt[];
extern char help2_txt[];

View File

@ -568,9 +568,10 @@ bool mob_ksprotected (struct block_list *src, struct block_list *target)
do {
struct status_change_entry *sce;
struct map_session_data *pl_sd; // Owner
struct map_data *mapdata = map_getmapdata(md->bl.m);
char output[128];
if( map_getmapflag(md->bl.m, MF_ALLOWKS) || map_flag_ks(md->bl.m) )
if( mapdata->flag[MF_ALLOWKS] || mapdata_flag_ks(mapdata) )
return false; // Ignores GVG, PVP and AllowKS map flags
if( md->db->mexp || md->master_id )
@ -839,8 +840,6 @@ int mob_spawn_guardian(const char* mapname, int16 x, int16 y, const char* mobnam
return 0;
}
struct map_data *mapdata = map_getmapdata(m);
data.m = m;
data.num = 1;
if(mob_id<=0) {
@ -856,13 +855,13 @@ int mob_spawn_guardian(const char* mapname, int16 x, int16 y, const char* mobnam
}
else if( guardian < 0 || guardian >= MAX_GUARDIANS )
{
ShowError("mob_spawn_guardian: Invalid guardian index %d for guardian %d (castle map %s)\n", guardian, mob_id, mapdata->name);
ShowError("mob_spawn_guardian: Invalid guardian index %d for guardian %d (castle map %s)\n", guardian, mob_id, mapname);
return 0;
}
if((x<=0 || y<=0) && !map_search_freecell(NULL, m, &x, &y, -1,-1, 1))
{
ShowWarning("mob_spawn_guardian: Couldn't locate a spawn cell for guardian class %d (index %d) at castle map %s\n",mob_id, guardian, mapdata->name);
ShowWarning("mob_spawn_guardian: Couldn't locate a spawn cell for guardian class %d (index %d) at castle map %s\n",mob_id, guardian, mapname);
return 0;
}
data.x = x;
@ -872,14 +871,14 @@ int mob_spawn_guardian(const char* mapname, int16 x, int16 y, const char* mobnam
if (!mob_parse_dataset(&data))
return 0;
gc=guild_mapname2gc(mapdata->name);
gc=guild_mapname2gc(mapname);
if (gc == NULL)
{
ShowError("mob_spawn_guardian: No castle set at map %s\n", mapdata->name);
ShowError("mob_spawn_guardian: No castle set at map %s\n", mapname);
return 0;
}
if (!gc->guild_id)
ShowWarning("mob_spawn_guardian: Spawning guardian %d on a castle with no guild (castle map %s)\n", mob_id, mapdata->name);
ShowWarning("mob_spawn_guardian: Spawning guardian %d on a castle with no guild (castle map %s)\n", mob_id, mapname);
else
g = guild_search(gc->guild_id);
@ -889,7 +888,7 @@ int mob_spawn_guardian(const char* mapname, int16 x, int16 y, const char* mobnam
if (md2 && md2->bl.type == BL_MOB &&
md2->guardian_data && md2->guardian_data->number == guardian)
{
ShowError("mob_spawn_guardian: Attempted to spawn guardian in position %d which already has a guardian (castle map %s)\n", guardian, mapdata->name);
ShowError("mob_spawn_guardian: Attempted to spawn guardian in position %d which already has a guardian (castle map %s)\n", guardian, mapname);
return 0;
}
}
@ -953,7 +952,7 @@ int mob_spawn_bg(const char* mapname, int16 x, int16 y, const char* mobname, int
data.id = mob_id;
if( (x <= 0 || y <= 0) && !map_search_freecell(NULL, m, &x, &y, -1,-1, 1) )
{
ShowWarning("mob_spawn_bg: Couldn't locate a spawn cell for guardian class %d (bg_id %d) at map %s\n",mob_id, bg_id, map_getmapdata(m)->name);
ShowWarning("mob_spawn_bg: Couldn't locate a spawn cell for guardian class %d (bg_id %d) at map %s\n",mob_id, bg_id, mapname);
return 0;
}

View File

@ -1424,10 +1424,9 @@ static enum e_CASHSHOP_ACK npc_cashshop_process_payment(struct npc_data *nd, int
case NPCTYPE_ITEMSHOP:
{
struct item_data *id = itemdb_exists(nd->u.shop.itemshop_nameid);
struct map_data *mapdata = map_getmapdata(nd->bl.m);
if (!id) { // Item Data is checked at script parsing but in case of item_db reload, check again.
ShowWarning("Failed to find sellitem %hu for itemshop NPC '%s' (%s, %d, %d)!\n", nd->u.shop.itemshop_nameid, nd->exname, mapdata->name, nd->bl.x, nd->bl.y);
ShowWarning("Failed to find sellitem %hu for itemshop NPC '%s' (%s, %d, %d)!\n", nd->u.shop.itemshop_nameid, nd->exname, map_mapid2mapname(nd->bl.m), nd->bl.x, nd->bl.y);
return ERROR_TYPE_PURCHASE_FAIL;
}
if (cost[0] < (price - points)) {
@ -1440,7 +1439,7 @@ static enum e_CASHSHOP_ACK npc_cashshop_process_payment(struct npc_data *nd, int
return ERROR_TYPE_PURCHASE_FAIL;
}
if (pc_delitem(sd, pc_search_inventory(sd, nd->u.shop.itemshop_nameid), price - points, 0, 0, LOG_TYPE_NPC)) {
ShowWarning("Failed to delete item %hu from '%s' at itemshop NPC '%s' (%s, %d, %d)!\n", nd->u.shop.itemshop_nameid, sd->status.name, nd->exname, mapdata->name, nd->bl.x, nd->bl.y);
ShowWarning("Failed to delete item %hu from '%s' at itemshop NPC '%s' (%s, %d, %d)!\n", nd->u.shop.itemshop_nameid, sd->status.name, nd->exname, map_mapid2mapname(nd->bl.m), nd->bl.x, nd->bl.y);
return ERROR_TYPE_PURCHASE_FAIL;
}
}
@ -1680,7 +1679,7 @@ int npc_cashshop_buy(struct map_session_data *sd, unsigned short nameid, int amo
{
ShowWarning("npc_cashshop_buy: Item '%s' (%hu) price overflow attempt!\n", item->name, nameid);
ShowDebug("(NPC:'%s' (%s,%d,%d), player:'%s' (%d/%d), value:%d, amount:%d)\n",
nd->exname, map_getmapdata(nd->bl.m)->name, nd->bl.x, nd->bl.y, sd->status.name, sd->status.account_id, sd->status.char_id, nd->u.shop.shop_item[i].value, amount);
nd->exname, map_mapid2mapname(nd->bl.m), nd->bl.x, nd->bl.y, sd->status.name, sd->status.account_id, sd->status.char_id, nd->u.shop.shop_item[i].value, amount);
return ERROR_TYPE_ITEM_ID;
}
@ -3296,7 +3295,7 @@ int npc_duplicate4instance(struct npc_data *snd, int16 m) {
imap = map_mapname2mapid(map_getmapdata(dm)->name);
if( imap == -1 ) {
ShowError("npc_duplicate4instance: warp (%s) leading to instanced map (%s), but instance map is not attached to current instance.\n", map_getmapdata(dm)->name, snd->exname);
ShowError("npc_duplicate4instance: warp (%s) leading to instanced map (%s), but instance map is not attached to current instance.\n", map_mapid2mapname(dm), snd->exname);
return 1;
}
@ -4058,7 +4057,7 @@ static const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, con
if (sscanf(w4, "%11d", &args.flag_val) == 1)
map_setmapflag_sub(m, MF_RESTRICTED, true, &args);
else // Could not be read, no value defined; don't remove as other restrictions may be set on the map
ShowWarning("npc_parse_mapflag: Zone value not set for the restricted mapflag! Skipped flag from %s (file '%s', line '%d').\n", map_getmapdata(m)->name, filepath, strline(buffer,start-buffer));
ShowWarning("npc_parse_mapflag: Zone value not set for the restricted mapflag! Skipped flag from %s (file '%s', line '%d').\n", map_mapid2mapname(m), filepath, strline(buffer,start-buffer));
} else
map_setmapflag(m, MF_RESTRICTED, false);
break;
@ -4456,9 +4455,9 @@ int npc_reload(void) {
// dynamic check by [random]
if( battle_config.dynamic_mobs ){
for( auto& pair : map ){
for (int i = 0; i < map_num; i++) {
for( int16 i = 0; i < MAX_MOB_LIST_PER_MAP; i++ ){
struct map_data *mapdata = &pair.second;
struct map_data *mapdata = map_getmapdata(i);
if (mapdata->moblist[i] != NULL) {
aFree(mapdata->moblist[i]);
@ -4601,9 +4600,11 @@ static void npc_debug_warps_sub(struct npc_data* nd)
}
static void npc_debug_warps(void){
for( auto& pair : map ){
for( int i = 0; i < pair.second.npc_num; i++ ){
npc_debug_warps_sub( pair.second.npc[i] );
for (int i = 0; i < map_num; i++) {
struct map_data *mapdata = map_getmapdata(i);
for( int i = 0; i < mapdata->npc_num; i++ ){
npc_debug_warps_sub(mapdata->npc[i]);
}
}
}

View File

@ -7973,9 +7973,10 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
if( map_getmapflag( sd->bl.m, MF_PVP_NIGHTMAREDROP ) ) { // Moved this outside so it works when PVP isn't enabled and during pk mode [Ancyker]
for(int j=0;j<MAX_DROP_PER_MAP;j++){
int id = map_getmapdata(sd->bl.m)->drop_list[j].drop_id;
int per = map_getmapdata(sd->bl.m)->drop_list[j].drop_per;
enum e_nightmare_drop_type type = map_getmapdata(sd->bl.m)->drop_list[j].drop_type;
struct map_data *mapdata = map_getmapdata(sd->bl.m);
int id = mapdata->drop_list[j].drop_id;
int per = mapdata->drop_list[j].drop_per;
enum e_nightmare_drop_type type = mapdata->drop_list[j].drop_type;
if(id == 0)
continue;
@ -12489,12 +12490,12 @@ bool pc_job_can_entermap(enum e_job jobid, int m, int group_lv) {
if (!job_info[idx].noenter_map.zone || group_lv > job_info[idx].noenter_map.group_lv)
return true;
if ((!map_flag_vs2(m) && job_info[idx].noenter_map.zone&1) || // Normal
(map_getmapflag(m, MF_PVP) && job_info[idx].noenter_map.zone&2) || // PVP
(map_flag_gvg2_no_te(m) && job_info[idx].noenter_map.zone&4) || // GVG
(map_getmapflag(m, MF_BATTLEGROUND) && job_info[idx].noenter_map.zone&8) || // Battleground
(map_flag_gvg2_te(m) && job_info[idx].noenter_map.zone&16) || // WOE:TE
(map_getmapflag(m, MF_RESTRICTED) && job_info[idx].noenter_map.zone&(8*mapdata->zone)) // Zone restriction
if ((job_info[idx].noenter_map.zone&1 && !mapdata_flag_vs2(mapdata)) || // Normal
(job_info[idx].noenter_map.zone&2 && mapdata->flag[MF_PVP]) || // PVP
(job_info[idx].noenter_map.zone&4 && mapdata_flag_gvg2_no_te(mapdata)) || // GVG
(job_info[idx].noenter_map.zone&8 && mapdata->flag[MF_BATTLEGROUND]) || // Battleground
(job_info[idx].noenter_map.zone&16 && mapdata_flag_gvg2_te(mapdata)) || // WOE:TE
(job_info[idx].noenter_map.zone&(8*mapdata->zone) && mapdata->flag[MF_RESTRICTED]) // Zone restriction
)
return false;

View File

@ -490,18 +490,16 @@ static void script_reportsrc(struct script_state *st)
if( bl == NULL )
return;
struct map_data *mapdata = map_getmapdata(bl->m);
switch( bl->type ) {
case BL_NPC:
if( bl->m >= 0 )
ShowDebug("Source (NPC): %s at %s (%d,%d)\n", ((struct npc_data *)bl)->name, mapdata->name, bl->x, bl->y);
ShowDebug("Source (NPC): %s at %s (%d,%d)\n", ((struct npc_data *)bl)->name, map_mapid2mapname(bl->m), bl->x, bl->y);
else
ShowDebug("Source (NPC): %s (invisible/not on a map)\n", ((struct npc_data *)bl)->name);
break;
default:
if( bl->m >= 0 )
ShowDebug("Source (Non-NPC type %d): name %s at %s (%d,%d)\n", bl->type, status_get_name(bl), mapdata->name, bl->x, bl->y);
ShowDebug("Source (Non-NPC type %d): name %s at %s (%d,%d)\n", bl->type, status_get_name(bl), map_mapid2mapname(bl->m), bl->x, bl->y);
else
ShowDebug("Source (Non-NPC type %d): name %s (invisible/not on a map)\n", bl->type, status_get_name(bl));
break;

View File

@ -693,14 +693,16 @@ bool skill_isNotOk(uint16 skill_id, struct map_session_data *sd)
if( sd->skillitem == skill_id && !sd->skillitem_keep_requirement )
return false;
struct map_data *mapdata = map_getmapdata(m);
skill_nocast = skill_get_nocast(skill_id);
// Check skill restrictions [Celest]
if( (!map_flag_vs2(m) && skill_nocast&1) ||
(map_getmapflag(m, MF_PVP) && skill_nocast&2) ||
(map_flag_gvg2_no_te(m) && skill_nocast&4) ||
(map_getmapflag(m, MF_BATTLEGROUND) && skill_nocast&8) ||
(map_flag_gvg2_te(m) && skill_nocast&16) || // WOE:TE
(map_getmapflag(m, MF_RESTRICTED) && map_getmapdata(m)->zone && skill_nocast&(8*map_getmapdata(m)->zone)) ){
if( (skill_nocast&1 && !mapdata_flag_vs2(mapdata)) ||
(skill_nocast&2 && mapdata->flag[MF_PVP]) ||
(skill_nocast&4 && mapdata_flag_gvg2_no_te(mapdata)) ||
(skill_nocast&8 && mapdata->flag[MF_BATTLEGROUND]) ||
(skill_nocast&16 && mapdata_flag_gvg2_te(mapdata)) || // WOE:TE
(mapdata->zone && skill_nocast&(8*mapdata->zone) && mapdata->flag[MF_RESTRICTED]) ){
clif_msg(sd, SKILL_CANT_USE_AREA); // This skill cannot be used within this area
return true;
}
@ -713,7 +715,7 @@ bool skill_isNotOk(uint16 skill_id, struct map_session_data *sd)
case RETURN_TO_ELDICASTES:
case ALL_GUARDIAN_RECALL:
case ECLAGE_RECALL:
if(map_getmapflag(m, MF_NOWARP)) {
if(mapdata->flag[MF_NOWARP]) {
clif_skill_teleportmessage(sd,0);
return true;
}
@ -723,7 +725,7 @@ bool skill_isNotOk(uint16 skill_id, struct map_session_data *sd)
case SC_DIMENSIONDOOR:
case ALL_ODINS_RECALL:
case WE_CALLALLFAMILY:
if(map_getmapflag(m, MF_NOTELEPORT)) {
if(mapdata->flag[MF_NOTELEPORT]) {
clif_skill_teleportmessage(sd,0);
return true;
}
@ -731,7 +733,7 @@ bool skill_isNotOk(uint16 skill_id, struct map_session_data *sd)
case WE_CALLPARTNER:
case WE_CALLPARENT:
case WE_CALLBABY:
if (map_getmapflag(m, MF_NOMEMO)) {
if (mapdata->flag[MF_NOMEMO]) {
clif_skill_teleportmessage(sd,1);
return true;
}
@ -760,13 +762,13 @@ bool skill_isNotOk(uint16 skill_id, struct map_session_data *sd)
return false; // always allowed
case WZ_ICEWALL:
// noicewall flag [Valaris]
if (map_getmapflag(m, MF_NOICEWALL)) {
if (mapdata->flag[MF_NOICEWALL]) {
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
return true;
}
break;
case GC_DARKILLUSION:
if( map_flag_gvg2(m) ) {
if( mapdata_flag_gvg2(mapdata) ) {
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
return true;
}
@ -775,8 +777,8 @@ bool skill_isNotOk(uint16 skill_id, struct map_session_data *sd)
case GD_ITEMEMERGENCYCALL:
if (
!(battle_config.emergency_call&((is_agit_start())?2:1)) ||
!(battle_config.emergency_call&(map_flag_gvg2(m)?8:4)) ||
(battle_config.emergency_call&16 && map_getmapflag(m, MF_NOWARPTO) && !(map_getmapflag(m, MF_GVG_CASTLE) || map_getmapflag(m, MF_GVG_TE_CASTLE)))
!(battle_config.emergency_call&(mapdata_flag_gvg2(mapdata)?8:4)) ||
(battle_config.emergency_call&16 && mapdata->flag[MF_NOWARPTO] && !(mapdata->flag[MF_GVG_CASTLE] || mapdata->flag[MF_GVG_TE_CASTLE]))
) {
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
return true;
@ -786,7 +788,7 @@ bool skill_isNotOk(uint16 skill_id, struct map_session_data *sd)
case WM_SOUND_OF_DESTRUCTION:
case WM_LULLABY_DEEPSLEEP:
case WM_SATURDAY_NIGHT_FEVER:
if( !map_flag_vs(m) ) {
if( !mapdata_flag_vs(mapdata) ) {
clif_skill_teleportmessage(sd,2); // This skill uses this msg instead of skill fails.
return true;
}
@ -9431,7 +9433,9 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
if (flag&1)
sc_start(src,bl,type,100,skill_lv,skill_get_time(skill_id,skill_lv));
else {
map_foreachinallrange(skill_area_sub,src,skill_get_splash(skill_id, skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,(map_flag_vs(src->m)?BCT_ALL:BCT_ENEMY|BCT_SELF)|flag|1,skill_castend_nodamage_id);
struct map_data *mapdata = map_getmapdata(src->m);
map_foreachinallrange(skill_area_sub,src,skill_get_splash(skill_id, skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,(mapdata_flag_vs(mapdata)?BCT_ALL:BCT_ENEMY|BCT_SELF)|flag|1,skill_castend_nodamage_id);
clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
}
break;
@ -12734,8 +12738,7 @@ struct skill_unit_group *skill_unitsetting(struct block_list *src, uint16 skill_
case GN_HELLS_PLANT:
if( skill_id == GN_HELLS_PLANT && map_getcell(src->m, x, y, CELL_CHKLANDPROTECTOR) )
return NULL;
if (map_flag_vs(src->m) && battle_config.vs_traps_bctall
&& (src->type&battle_config.vs_traps_bctall))
if (battle_config.vs_traps_bctall && (src->type&battle_config.vs_traps_bctall) && map_flag_vs(src->m))
target = BCT_ALL;
break;
case HT_SKIDTRAP:
@ -12770,7 +12773,7 @@ struct skill_unit_group *skill_unitsetting(struct block_list *src, uint16 skill_
req_item = req.itemid[i];
if (skill_id == RL_B_TRAP) // Target type should not change on GvG maps.
break;
if( battle_config.vs_traps_bctall && map_flag_vs(src->m) && (src->type&battle_config.vs_traps_bctall) )
if( battle_config.vs_traps_bctall && (src->type&battle_config.vs_traps_bctall) && map_flag_vs(src->m) )
target = BCT_ALL;
}
break;
@ -13262,7 +13265,9 @@ static int skill_unit_onplace(struct skill_unit *unit, struct block_list *bl, un
//Duration in PVP is: 1st - 4s, 2nd - 8s, 3rd - 12s
int sec = skill_get_time2(sg->skill_id, sg->skill_lv);
const struct TimerData* td;
if (map_flag_vs(bl->m))
struct map_data *mapdata = map_getmapdata(bl->m);
if (mapdata_flag_vs(mapdata))
sec /= 2;
if (sc->data[type]) {
if (sc->data[type]->val2 && sc->data[type]->val3 && sc->data[type]->val4) {
@ -13271,9 +13276,9 @@ static int skill_unit_onplace(struct skill_unit *unit, struct block_list *bl, un
break;
}
//Don't increase val1 here, we need a higher val in status_change_start so it overwrites the old one
if (map_flag_vs(bl->m) && sc->data[type]->val1 < 3)
if (mapdata_flag_vs(mapdata) && sc->data[type]->val1 < 3)
sec *= (sc->data[type]->val1 + 1);
else if(!map_flag_vs(bl->m) && sc->data[type]->val1 < 2)
else if(!mapdata_flag_vs(mapdata) && sc->data[type]->val1 < 2)
sec *= (sc->data[type]->val1 + 1);
//Add group id to status change
if (sc->data[type]->val2 == 0)
@ -20792,11 +20797,13 @@ static bool skill_check_unit_movepos(uint8 check_flag, struct block_list *bl, sh
nullpo_retr(false, bl);
if (check_flag&1 && map_getmapflag(bl->m, MF_BATTLEGROUND))
struct map_data *mapdata = map_getmapdata(bl->m);
if (check_flag&1 && mapdata->flag[MF_BATTLEGROUND])
return false;
if (check_flag&2 && map_flag_gvg(bl->m))
if (check_flag&2 && mapdata_flag_gvg(mapdata))
return false;
if (check_flag&4 && map_flag_gvg2(bl->m))
if (check_flag&4 && mapdata_flag_gvg2(mapdata))
return false;
sc = status_get_sc(bl);

View File

@ -113,7 +113,7 @@ static unsigned int status_calc_maxhpsp_pc(struct map_session_data* sd, unsigned
static int status_get_sc_interval(enum sc_type type);
static bool status_change_isDisabledOnMap_(sc_type type, bool mapIsVS, bool mapIsPVP, bool mapIsGVG, bool mapIsBG, unsigned int mapZone, bool mapIsTE);
#define status_change_isDisabledOnMap(type, m) ( status_change_isDisabledOnMap_((type), map_flag_vs2((m)), map_getmapflag((m), MF_PVP) != 0, map_flag_gvg2_no_te((m)), map_getmapflag((m), MF_BATTLEGROUND) != 0, (map_getmapdata(m)->zone << 3) != 0, map_flag_gvg2_te((m))) )
#define status_change_isDisabledOnMap(type, m) ( status_change_isDisabledOnMap_((type), mapdata_flag_vs2((m)), m->flag[MF_PVP] != 0, mapdata_flag_gvg2_no_te((m)), m->flag[MF_BATTLEGROUND] != 0, (m->zone << 3) != 0, mapdata_flag_gvg2_te((m))) )
/**
* Returns the status change associated with a skill.
@ -6279,9 +6279,11 @@ static signed short status_calc_hit(struct block_list *bl, struct status_change
static signed short status_calc_flee(struct block_list *bl, struct status_change *sc, int flee)
{
if( bl->type == BL_PC ) {
if( map_flag_gvg(bl->m) )
struct map_data *mapdata = map_getmapdata(bl->m);
if( mapdata_flag_gvg(mapdata) )
flee -= flee * battle_config.gvg_flee_penalty/100;
else if( map_getmapflag(bl->m, MF_BATTLEGROUND) )
else if( mapdata->flag[MF_BATTLEGROUND] )
flee -= flee * battle_config.bg_flee_penalty/100;
}
@ -8442,7 +8444,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
if( bl->type != BL_NPC && status_isdead(bl) && ( type != SC_NOCHAT && type != SC_JAILED ) ) // SC_NOCHAT and SC_JAILED should work even on dead characters
return 0;
if (status_change_isDisabledOnMap(type, bl->m))
if (status_change_isDisabledOnMap(type, map_getmapdata(bl->m)))
return 0;
// Uncomment to prevent status adding hp to gvg mob (like bloodylust=hp*3 etc...
@ -14365,13 +14367,14 @@ void status_change_clear_onChangeMap(struct block_list *bl, struct status_change
nullpo_retv(bl);
if (sc && sc->count) {
struct map_data *mapdata = map_getmapdata(bl->m);
unsigned short i;
bool mapIsVS = map_flag_vs2(bl->m);
bool mapIsPVP = map_getmapflag(bl->m, MF_PVP) != 0;
bool mapIsGVG = map_flag_gvg2_no_te(bl->m);
bool mapIsBG = map_getmapflag(bl->m, MF_BATTLEGROUND) != 0;
bool mapIsTE = map_flag_gvg2_te(bl->m);
unsigned int mapZone = map_getmapdata(bl->m)->zone << 3;
bool mapIsVS = mapdata_flag_vs2(mapdata);
bool mapIsPVP = mapdata->flag[MF_PVP] != 0;
bool mapIsGVG = mapdata_flag_gvg2_no_te(mapdata);
bool mapIsBG = mapdata->flag[MF_BATTLEGROUND] != 0;
bool mapIsTE = mapdata_flag_gvg2_te(mapdata);
unsigned int mapZone = mapdata->zone << 3;
for (i = 0; i < SC_MAX; i++) {
if (!sc->data[i] || !SCDisabled[i])