Initial release: Map X Job restriction (#1526)

* Listed job with matched map zone is restricted to enter the map.
* Added db file `job_noenter_map.txt` with format: `JobID,FlagZone,GroupLevelBypass`.
* Reserved usage for WOE:TE implementation.
* Typo correction, thanks @aleos89 @Lemongrass3110
This commit is contained in:
Cydh Ramdh 2016-08-30 22:09:02 +07:00 committed by GitHub
parent b3b2bab7c5
commit d84d6ba1e5
14 changed files with 229 additions and 13 deletions

View File

@ -0,0 +1,27 @@
// Defines Job(s) that are restricted to enter map (by flag/zones)
//
// Structure of Database:
// JobID,FlagZone,GroupLevelBypass
//
// JobID: See JOB_* constants or use job number
//
// Legend for 'Flag' field (bitmask):
// 1 - restricted in normal maps
// 2 - restricted in PVP
// 4 - restricted in GVG
// 8 - restricted in Battlegrounds
// Restricted zones - configured by 'restricted <number>' mapflag
// 32 - restricted in zone 1
// 64 - restricted in zone 2
// 128 - restricted in zone 3
// 256 - restricted in zone 4
// 512 - restricted in zone 5
// 1024 - restricted in zone 6
// 2048 - restricted in zone 7
// 4096 - restricted in zone 8
//
// GroupLevelBypass: Group Level (groups.conf) to ignore the restriction
//
// NOTES:
// - Restriction will be overwritten for multiple defines with the same Job ID
// - The flag is used by 'jobcanentermap' script.

View File

@ -0,0 +1,27 @@
// Defines Job(s) that are restricted to enter map (by flag/zones)
//
// Structure of Database:
// JobID,FlagZone,GroupLevelBypass
//
// JobID: See JOB_* constants or use job number
//
// Legend for 'Flag' field (bitmask):
// 1 - restricted in normal maps
// 2 - restricted in PVP
// 4 - restricted in GVG
// 8 - restricted in Battlegrounds
// Restricted zones - configured by 'restricted <number>' mapflag
// 32 - restricted in zone 1
// 64 - restricted in zone 2
// 128 - restricted in zone 3
// 256 - restricted in zone 4
// 512 - restricted in zone 5
// 1024 - restricted in zone 6
// 2048 - restricted in zone 7
// 4096 - restricted in zone 8
//
// GroupLevelBypass: Group Level (groups.conf) to ignore the restriction
//
// NOTES:
// - Restriction will be overwritten for multiple defines with the same Job ID
// - The flag is used by 'jobcanentermap' script.

27
db/re/job_noenter_map.txt Normal file
View File

@ -0,0 +1,27 @@
// Defines Job(s) that are restricted to enter map (by flag/zones)
//
// Structure of Database:
// JobID,FlagZone,GroupLevelBypass
//
// JobID: See JOB_* constants or use job number
//
// Legend for 'Flag' field (bitmask):
// 1 - restricted in normal maps
// 2 - restricted in PVP
// 4 - restricted in GVG
// 8 - restricted in Battlegrounds
// Restricted zones - configured by 'restricted <number>' mapflag
// 32 - restricted in zone 1
// 64 - restricted in zone 2
// 128 - restricted in zone 3
// 256 - restricted in zone 4
// 512 - restricted in zone 5
// 1024 - restricted in zone 6
// 2048 - restricted in zone 7
// 4096 - restricted in zone 8
//
// GroupLevelBypass: Group Level (groups.conf) to ignore the restriction
//
// NOTES:
// - Restriction will be overwritten for multiple defines with the same Job ID
// - The flag is used by 'jobcanentermap' script.

View File

@ -4302,6 +4302,17 @@ raise the specified stat from (current value - <val>) to current value.
---------------------------------------
*jobcanentermap("<mapname>"{,<JobID>});
Return true if player (decided by job) can enter the map, false otherwise.
For optional 'JobID', see constant of Job_*, or use player's Class, BaseJob,
and BaseClass. If no player is attached, this param must have a value.
See also db/[pre-]re/job_noenter_map.txt
---------------------------------------
*get_revision()
This command will return the SVN revision number that the server is currently

View File

@ -402,7 +402,7 @@ struct mmo_charstatus {
unsigned int base_exp,job_exp;
int zeny;
short class_;
short class_; ///< Player's JobID
unsigned int status_point,skill_point;
int hp,max_hp,sp,max_sp;
unsigned int option;

View File

@ -475,7 +475,7 @@ ACMD_FUNC(mapmove)
if (!map_search_freecell(NULL, m, &x, &y, 10, 10, 1))
x = y = 0; //Invalid cell, use random spot.
}
if (map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) {
if ((map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) || !pc_job_can_entermap((enum e_job)sd->status.class_, m, sd->group_level)) {
clif_displaymessage(fd, msg_txt(sd,247));
return -1;
}

View File

@ -113,7 +113,7 @@ struct item_cd {
* Converts a class to its array index for CLASS_COUNT defined arrays.
* Note that it does not do a validity check for speed purposes, where parsing
* player input make sure to use a pcdb_checkid first!
* @param class_
* @param class_ Job ID see enum e_job
* @return Class Index
*/
int pc_class2idx(int class_) {
@ -11117,6 +11117,31 @@ static bool pc_readdb_job_param(char* fields[], int columns, int current)
return true;
}
/**
* Read job_noenter_map.txt
**/
static bool pc_readdb_job_noenter_map(char *str[], int columns, int current) {
int idx, class_ = -1;
if (ISDIGIT(str[0][0])) {
class_ = atoi(str[0]);
} else {
if (!script_get_constant(str[0], &class_)) {
ShowError("pc_readdb_job_noenter_map: Invalid job %s specified.\n", str[0]);
return false;
}
}
if (!pcdb_checkid(class_) || (idx = pc_class2idx(class_)) < 0) {
ShowError("pc_readdb_job_noenter_map: Invalid job %d specified.\n", str[0]);
return false;
}
job_info[idx].noenter_map.zone = atoi(str[1]);
job_info[idx].noenter_map.group_lv = atoi(str[2]);
return true;
}
static int pc_read_statsdb(const char *basedir, int last_s, bool silent){
int i=1;
char line[24000]; //FIXME this seem too big
@ -11220,6 +11245,7 @@ void pc_readdb(void) {
sv_readdb(dbsubpath2, "job_basehpsp_db.txt", ',', 4, 4+500, CLASS_COUNT*2, &pc_readdb_job_basehpsp, i); //Make it support until lvl 500!
#endif
sv_readdb(dbsubpath2, "job_param_db.txt", ',', 2, PARAM_MAX+1, CLASS_COUNT, &pc_readdb_job_param, i);
sv_readdb(dbsubpath2, "job_noenter_map.txt", ',', 3, 3, CLASS_COUNT, &pc_readdb_job_noenter_map, i);
aFree(dbsubpath1);
aFree(dbsubpath2);
}
@ -12177,6 +12203,40 @@ void pc_show_questinfo_reinit(struct map_session_data *sd) {
#endif
}
/**
* Check if a job is allowed to enter the map
* @param jobid Job ID see enum e_job or sd->status.class_
* @param m ID -an index- for direct indexing map[] array
* @return 1 if job is allowed, 0 otherwise
**/
bool pc_job_can_entermap(enum e_job jobid, int m, int group_lv) {
uint16 idx = 0;
// Map is other map server.
// !FIXME: Currently, a map-server doesn't recognized map's attributes on other server, so we assume it's fine to warp.
if (m < 0)
return true;
if (m >= MAX_MAP_PER_SERVER || !map[m].cell)
return false;
if (!pcdb_checkid(jobid))
return false;
idx = pc_class2idx(jobid);
if (!job_info[idx].noenter_map.zone || group_lv > job_info[idx].noenter_map.group_lv)
return true;
if ((!map_flag_vs(m) && job_info[idx].noenter_map.zone&1) || // Normal
(map[m].flag.pvp && job_info[idx].noenter_map.zone&2) || // PVP
(map_flag_gvg2(m) && job_info[idx].noenter_map.zone&4) || // GVG
(map[m].flag.battleground && job_info[idx].noenter_map.zone&8) || // Battleground
(map[m].flag.restricted && job_info[idx].noenter_map.zone&(8*map[m].zone)) // Zone restriction
)
return false;
return true;
}
/*==========================================
* pc Init/Terminate

View File

@ -796,6 +796,10 @@ struct {
struct s_params {
uint16 str, agi, vit, int_, dex, luk;
} max_param;
struct s_job_noenter_map {
uint32 zone;
uint8 group_lv;
} noenter_map;
} job_info[CLASS_COUNT];
#define EQP_WEAPON EQP_HAND_R
@ -1262,6 +1266,8 @@ void pc_validate_skill(struct map_session_data *sd);
void pc_show_questinfo(struct map_session_data *sd);
void pc_show_questinfo_reinit(struct map_session_data *sd);
bool pc_job_can_entermap(enum e_job jobid, int m, int group_lv);
#if defined(RENEWAL_DROP) || defined(RENEWAL_EXP)
int pc_level_penalty_mod(int level_diff, uint32 mob_class, enum e_mode mode, int type);
#endif

View File

@ -5633,7 +5633,7 @@ BUILDIN_FUNC(warpparty)
TBL_PC *pl_sd;
struct party_data* p;
int type;
int mapindex;
int mapindex = 0, m = -1;
int i;
const char* str = script_getstr(st,2);
@ -5662,18 +5662,21 @@ BUILDIN_FUNC(warpparty)
return SCRIPT_CMD_FAILURE;
pl_sd = p->data[i].sd;
mapindex = pl_sd->mapindex;
m = map_mapindex2mapid(mapindex);
x = pl_sd->bl.x;
y = pl_sd->bl.y;
break;
case 4:
mapindex = mapindex_name2id(str);
if (!mapindex) {// Invalid map
return SCRIPT_CMD_FAILURE;
}
m = map_mapindex2mapid(mapindex);
break;
case 2:
//"SavePoint" uses save point of the currently attached player
if (( sd = script_rid2sd(st) ) == NULL )
return SCRIPT_CMD_SUCCESS;
default:
mapindex = 0;
break;
}
@ -5704,7 +5707,7 @@ BUILDIN_FUNC(warpparty)
break;
case 3: // Leader
case 4: // m,x,y
if(!map[pl_sd->bl.m].flag.noreturn && !map[pl_sd->bl.m].flag.nowarp)
if(!map[pl_sd->bl.m].flag.noreturn && !map[pl_sd->bl.m].flag.nowarp && pc_job_can_entermap((enum e_job)pl_sd->status.class_, m, pl_sd->group_level))
pc_setpos(pl_sd,mapindex,x,y,CLR_TELEPORT);
break;
}
@ -5723,7 +5726,7 @@ BUILDIN_FUNC(warpguild)
TBL_PC *pl_sd;
struct guild* g;
struct s_mapiterator* iter;
int type;
int type, mapindex = 0, m = -1;
const char* str = script_getstr(st,2);
int x = script_getnum(st,3);
@ -5744,6 +5747,15 @@ BUILDIN_FUNC(warpguild)
return SCRIPT_CMD_SUCCESS;
}
switch (type) {
case 3:
mapindex = mapindex_name2id(str);
if (!mapindex)
return SCRIPT_CMD_FAILURE;
m = map_mapindex2mapid(mapindex);
break;
}
iter = mapit_getallusers();
for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
{
@ -5765,8 +5777,8 @@ BUILDIN_FUNC(warpguild)
pc_setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
break;
case 3: // m,x,y
if(!map[pl_sd->bl.m].flag.noreturn && !map[pl_sd->bl.m].flag.nowarp)
pc_setpos(pl_sd,mapindex_name2id(str),x,y,CLR_TELEPORT);
if(!map[pl_sd->bl.m].flag.noreturn && !map[pl_sd->bl.m].flag.nowarp && pc_job_can_entermap((enum e_job)pl_sd->status.class_, m, pl_sd->group_level))
pc_setpos(pl_sd,mapindex,x,y,CLR_TELEPORT);
break;
}
}
@ -21681,6 +21693,44 @@ BUILDIN_FUNC(needed_status_point) {
script_pushint(st, pc_need_status_point(sd, type, val));
return SCRIPT_CMD_SUCCESS;
}
/**
* jobcanentermap("<mapname>"{,<JobID>});
* Check if (player with) JobID can enter the map.
* @param mapname Map name
* @param JobID Player's JobID (optional)
**/
BUILDIN_FUNC(jobcanentermap) {
const char *mapname = script_getstr(st, 2);
int mapidx = mapindex_name2id(mapname), m = -1;
int jobid = 0;
TBL_PC *sd = NULL;
if (!mapidx) {// Invalid map
script_pushint(st, false);
return SCRIPT_CMD_FAILURE;
}
m = map_mapindex2mapid(mapidx);
if (m == -1) { // Map is on different map server
ShowError("buildin_jobcanentermap: Map '%s' is not found in this server.\n", mapname);
script_pushint(st, false);
return SCRIPT_CMD_FAILURE;
}
if (script_hasdata(st, 3)) {
jobid = script_getnum(st, 3);
} else {
if (!(sd = script_rid2sd(st))) {
script_pushint(st, false);
return SCRIPT_CMD_FAILURE;
}
jobid = sd->status.class_;
}
script_pushint(st, pc_job_can_entermap((enum e_job)jobid, m, sd ? sd->group_level : 0));
return SCRIPT_CMD_SUCCESS;
}
#include "../custom/script.inc"
// declarations that were supposed to be exported from npc_chat.c
@ -22264,6 +22314,7 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(getequiprandomoption, "iii?"),
BUILDIN_DEF(setrandomoption,"iiiii?"),
BUILDIN_DEF(needed_status_point,"ii?"),
BUILDIN_DEF(jobcanentermap,"s?"),
#include "../custom/script_def.inc"

View File

@ -8603,6 +8603,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
if ((dstsd = g->member[i].sd) != NULL && sd != dstsd && !dstsd->state.autotrade && !pc_isdead(dstsd)) {
if (map[dstsd->bl.m].flag.nowarp && !map_flag_gvg2(dstsd->bl.m))
continue;
if (!pc_job_can_entermap((enum e_job)dstsd->status.class_, src->m, dstsd->group_level))
continue;
if(map_getcell(src->m,src->x+dx[j],src->y+dy[j],CELL_CHKNOREACH))
dx[j] = dy[j] = 0;
if (!pc_setpos(dstsd, map_id2index(src->m), src->x+dx[j], src->y+dy[j], CLR_RESPAWN))
@ -13141,7 +13143,8 @@ static int skill_unit_onplace(struct skill_unit *unit, struct block_list *bl, un
sg->val1 = (count<<16)|working;
pc_setpos(sd,m,x,y,CLR_TELEPORT);
if (pc_job_can_entermap((enum e_job)sd->status.class_, map_mapindex2mapid(m), sd->group_level))
pc_setpos(sd,m,x,y,CLR_TELEPORT);
}
} else if(bl->type == BL_MOB && battle_config.mob_warp&2) {
int16 m = map_mapindex2mapid(sg->val3);
@ -18122,13 +18125,13 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap)
if(group->val1) {
sd = map_charid2sd(group->val1);
group->val1 = 0;
if (sd && !map[sd->bl.m].flag.nowarp)
if (sd && !map[sd->bl.m].flag.nowarp && pc_job_can_entermap((enum e_job)sd->status.class_, unit->bl.m, sd->group_level))
pc_setpos(sd,map_id2index(unit->bl.m),unit->bl.x,unit->bl.y,CLR_TELEPORT);
}
if(group->val2) {
sd = map_charid2sd(group->val2);
group->val2 = 0;
if (sd && !map[sd->bl.m].flag.nowarp)
if (sd && !map[sd->bl.m].flag.nowarp && pc_job_can_entermap((enum e_job)sd->status.class_, unit->bl.m, sd->group_level))
pc_setpos(sd,map_id2index(unit->bl.m),unit->bl.x,unit->bl.y,CLR_TELEPORT);
}
skill_delunit(unit);

View File

@ -325,6 +325,7 @@
<Copy SourceFiles="..\db\import-tmpl\job_db2.txt" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\job_db2.txt')" />
<Copy SourceFiles="..\db\import-tmpl\job_exp.txt" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\job_exp.txt')" />
<Copy SourceFiles="..\db\import-tmpl\job_param_db.txt" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\job_param_db.txt')" />
<Copy SourceFiles="..\db\import-tmpl\job_noenter_map.txt" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\job_noenter_map.txt')" />
<Copy SourceFiles="..\db\import-tmpl\level_penalty.txt" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\level_penalty.txt')" />
<Copy SourceFiles="..\db\import-tmpl\magicmushroom_db.txt" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\magicmushroom_db.txt')" />
<Copy SourceFiles="..\db\import-tmpl\map_cache.dat" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\map_cache.dat')" />

View File

@ -329,6 +329,7 @@
<Copy SourceFiles="..\db\import-tmpl\job_db2.txt" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\job_db2.txt')" />
<Copy SourceFiles="..\db\import-tmpl\job_exp.txt" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\job_exp.txt')" />
<Copy SourceFiles="..\db\import-tmpl\job_param_db.txt" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\job_param_db.txt')" />
<Copy SourceFiles="..\db\import-tmpl\job_noenter_map.txt" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\job_noenter_map.txt')" />
<Copy SourceFiles="..\db\import-tmpl\level_penalty.txt" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\level_penalty.txt')" />
<Copy SourceFiles="..\db\import-tmpl\magicmushroom_db.txt" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\magicmushroom_db.txt')" />
<Copy SourceFiles="..\db\import-tmpl\map_cache.dat" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\map_cache.dat')" />

View File

@ -329,6 +329,7 @@
<Copy SourceFiles="..\db\import-tmpl\job_db2.txt" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\job_db2.txt')" />
<Copy SourceFiles="..\db\import-tmpl\job_exp.txt" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\job_exp.txt')" />
<Copy SourceFiles="..\db\import-tmpl\job_param_db.txt" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\job_param_db.txt')" />
<Copy SourceFiles="..\db\import-tmpl\job_noenter_map.txt" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\job_noenter_map.txt')" />
<Copy SourceFiles="..\db\import-tmpl\level_penalty.txt" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\level_penalty.txt')" />
<Copy SourceFiles="..\db\import-tmpl\magicmushroom_db.txt" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\magicmushroom_db.txt')" />
<Copy SourceFiles="..\db\import-tmpl\map_cache.dat" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\map_cache.dat')" />

View File

@ -327,6 +327,7 @@
<Copy SourceFiles="..\db\import-tmpl\job_db2.txt" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\job_db2.txt')" />
<Copy SourceFiles="..\db\import-tmpl\job_exp.txt" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\job_exp.txt')" />
<Copy SourceFiles="..\db\import-tmpl\job_param_db.txt" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\job_param_db.txt')" />
<Copy SourceFiles="..\db\import-tmpl\job_noenter_map.txt" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\job_noenter_map.txt')" />
<Copy SourceFiles="..\db\import-tmpl\level_penalty.txt" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\level_penalty.txt')" />
<Copy SourceFiles="..\db\import-tmpl\magicmushroom_db.txt" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\magicmushroom_db.txt')" />
<Copy SourceFiles="..\db\import-tmpl\map_cache.dat" DestinationFolder="..\db\import\" ContinueOnError="true" Condition="!Exists('..\db\import\map_cache.dat')" />