Converted player groups to YAML (#6488)
Finally adds import functionality for player groups and therefore atcommand and permission defining. Co-authored-by: Aleos <aleos89@users.noreply.github.com>
This commit is contained in:
parent
6e5461a34e
commit
51ddc63a02
303
conf/groups.conf
303
conf/groups.conf
@ -1,303 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Player groups configuration file
|
|
||||||
---------------------------------
|
|
||||||
|
|
||||||
This file defines "player groups" and their privileges.
|
|
||||||
|
|
||||||
Each group has its id and name, lists of available commands and other
|
|
||||||
permissions, and a list of other groups it inherits from.
|
|
||||||
|
|
||||||
|
|
||||||
Group settings
|
|
||||||
--------------
|
|
||||||
<id>
|
|
||||||
Unique group number. The only required field.
|
|
||||||
|
|
||||||
<name>
|
|
||||||
Any string. If empty, defaults to "Group <id>". It is used in several @who
|
|
||||||
commands.
|
|
||||||
|
|
||||||
<level>
|
|
||||||
Equivalent of GM level, which was used in revisions before r15572. You can
|
|
||||||
set it to any number, but usually it's between 0 (default) and 99. Members of
|
|
||||||
groups with lower level can not perform some actions/commands (like @kick) on
|
|
||||||
members of groups with higher level. It is what script command getgmlevel()
|
|
||||||
returns. Group level can also be used to override trade restrictions
|
|
||||||
(db/item_trade.txt).
|
|
||||||
|
|
||||||
<commands>
|
|
||||||
A group of settings
|
|
||||||
<command name> : <bool>
|
|
||||||
or
|
|
||||||
<commandname> : [ <bool>, <bool> ]
|
|
||||||
First boolean value is for atcommand, second one for charcommand. If set to
|
|
||||||
true, group can use command. If only atcommand value is provided, false is
|
|
||||||
assumed for charcommand. If a command name is not included, false is assumed for
|
|
||||||
both atcommand and charcommand.
|
|
||||||
For a full list of available commands, see: doc/atcommands.txt.
|
|
||||||
Command names must not be aliases.
|
|
||||||
|
|
||||||
<log_commands>
|
|
||||||
Boolean value. If true then all commands used by the group will be logged to
|
|
||||||
atcommandlog. If setting is omitted in a group definition, false is assumed.
|
|
||||||
Requires 'log_commands' to be enabled in 'conf/log_athena.conf'.
|
|
||||||
|
|
||||||
<permissions>
|
|
||||||
A group of settings
|
|
||||||
<permission> : <bool>
|
|
||||||
If a permission is not included, false is assumed.
|
|
||||||
For a full list of available permissions, see: doc/permissions.txt
|
|
||||||
|
|
||||||
<inherit>
|
|
||||||
A list of group names that given group will inherit commands and permissions
|
|
||||||
from. Group names are case-sensitive.
|
|
||||||
|
|
||||||
Inheritance results
|
|
||||||
-------------------
|
|
||||||
Both multiple inheritance (Group 2 -> Group 1 and Group 3 -> Group 1) and
|
|
||||||
recursive inheritance (Group 3 -> Group 2 -> Group 1) are allowed.
|
|
||||||
|
|
||||||
Inheritance rules should not create cycles (eg Group 1 inherits from Group 2,
|
|
||||||
and Group inherits from Group 1 at the same time). Configuration with cycles is
|
|
||||||
considered faulty and can't be processed fully by server.
|
|
||||||
|
|
||||||
Command or permission is inherited ONLY if it's not already defined for the
|
|
||||||
group.
|
|
||||||
If group inherits from multiple groups, and the same command or permission is
|
|
||||||
defined for more than one of these groups, it's undefined which one will be
|
|
||||||
inherited.
|
|
||||||
|
|
||||||
Syntax
|
|
||||||
------
|
|
||||||
This config file uses libconfig syntax:
|
|
||||||
http://www.hyperrealm.com/libconfig/libconfig_manual.html#Configuration-Files
|
|
||||||
|
|
||||||
|
|
||||||
Upgrading from revisions before r15572
|
|
||||||
-------------------------------------
|
|
||||||
http://rathena.org/board/index.php?showtopic=58877
|
|
||||||
*/
|
|
||||||
|
|
||||||
groups: (
|
|
||||||
{
|
|
||||||
id: 0 /* group 0 is the default group for every new account */
|
|
||||||
name: "Player"
|
|
||||||
level: 0
|
|
||||||
inherit: ( /*empty list*/ )
|
|
||||||
commands: {
|
|
||||||
changedress: true
|
|
||||||
resurrect: true
|
|
||||||
}
|
|
||||||
permissions: {
|
|
||||||
/* without this basic permissions regular players could not
|
|
||||||
trade or party */
|
|
||||||
can_trade: true
|
|
||||||
can_party: true
|
|
||||||
attendance: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 1
|
|
||||||
name: "Super Player"
|
|
||||||
inherit: ( "Player" ) /* can do everything Players can and more */
|
|
||||||
level: 0
|
|
||||||
commands: {
|
|
||||||
/* informational commands */
|
|
||||||
commands: true
|
|
||||||
charcommands: true
|
|
||||||
help: true
|
|
||||||
rates: true
|
|
||||||
uptime: true
|
|
||||||
showdelay: true
|
|
||||||
exp: true
|
|
||||||
mobinfo: true
|
|
||||||
iteminfo: true
|
|
||||||
whodrops: true
|
|
||||||
time: true
|
|
||||||
jailtime: true
|
|
||||||
hominfo: true
|
|
||||||
homstats: true
|
|
||||||
showexp: true
|
|
||||||
showzeny: true
|
|
||||||
whereis: true
|
|
||||||
/* feature commands */
|
|
||||||
refresh: true
|
|
||||||
noask: true
|
|
||||||
noks: true
|
|
||||||
autoloot: true
|
|
||||||
alootid: true
|
|
||||||
autoloottype: true
|
|
||||||
autotrade: true
|
|
||||||
request: true
|
|
||||||
go: true
|
|
||||||
breakguild: true
|
|
||||||
channel: true
|
|
||||||
langtype: true
|
|
||||||
}
|
|
||||||
permissions: {
|
|
||||||
attendance: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2
|
|
||||||
name: "Support"
|
|
||||||
inherit: ( "Super Player" )
|
|
||||||
level: 1
|
|
||||||
commands: {
|
|
||||||
version: true
|
|
||||||
where: true
|
|
||||||
jumpto: true
|
|
||||||
who: true
|
|
||||||
who2: true
|
|
||||||
who3: true
|
|
||||||
whomap: true
|
|
||||||
whomap2: true
|
|
||||||
whomap3: true
|
|
||||||
users: true
|
|
||||||
broadcast: true
|
|
||||||
localbroadcast: true
|
|
||||||
}
|
|
||||||
log_commands: true
|
|
||||||
permissions: {
|
|
||||||
receive_requests: true
|
|
||||||
view_equipment: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3
|
|
||||||
name: "Script Manager"
|
|
||||||
inherit: ( "Support" )
|
|
||||||
level: 1
|
|
||||||
commands: {
|
|
||||||
tonpc: true
|
|
||||||
hidenpc: true
|
|
||||||
shownpc: true
|
|
||||||
loadnpc: true
|
|
||||||
unloadnpc: true
|
|
||||||
npcmove: true
|
|
||||||
addwarp: true
|
|
||||||
}
|
|
||||||
log_commands: true
|
|
||||||
permissions: {
|
|
||||||
any_warp: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4
|
|
||||||
name: "Event Manager"
|
|
||||||
inherit: ( "Support" )
|
|
||||||
level: 1
|
|
||||||
commands: {
|
|
||||||
monster: true
|
|
||||||
monstersmall: true
|
|
||||||
monsterbig: true
|
|
||||||
killmonster2: true
|
|
||||||
cleanarea: true
|
|
||||||
cleanmap: true
|
|
||||||
item: [true, true]
|
|
||||||
zeny: [true, true]
|
|
||||||
disguise: [true, true]
|
|
||||||
undisguise: [true, true]
|
|
||||||
size: [true, true]
|
|
||||||
raise: true
|
|
||||||
raisemap: true
|
|
||||||
day: true
|
|
||||||
night: true
|
|
||||||
skillon: true
|
|
||||||
skilloff: true
|
|
||||||
pvpon: true
|
|
||||||
pvpoff: true
|
|
||||||
gvgon: true
|
|
||||||
gvgoff: true
|
|
||||||
allowks: true
|
|
||||||
me: true
|
|
||||||
marry: true
|
|
||||||
divorce: true
|
|
||||||
refreshall: true
|
|
||||||
}
|
|
||||||
log_commands: true
|
|
||||||
permissions: {
|
|
||||||
can_trade: false
|
|
||||||
any_warp: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5
|
|
||||||
name: "VIP"
|
|
||||||
inherit: ( "Player" ) /* can do everything Players can */
|
|
||||||
level: 0
|
|
||||||
commands: {
|
|
||||||
rates: true
|
|
||||||
who: true
|
|
||||||
}
|
|
||||||
permissions: {
|
|
||||||
/* no permissions by default */
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 10
|
|
||||||
name: "Law Enforcement"
|
|
||||||
inherit: ( "Support" )
|
|
||||||
level: 2
|
|
||||||
commands: {
|
|
||||||
hide: true
|
|
||||||
follow: true
|
|
||||||
kick: true
|
|
||||||
disguise: true
|
|
||||||
fakename: true
|
|
||||||
option: true
|
|
||||||
speed: true
|
|
||||||
warp: true
|
|
||||||
kill: true
|
|
||||||
recall: true
|
|
||||||
ban: true
|
|
||||||
block: true
|
|
||||||
jail: true
|
|
||||||
jailfor: true
|
|
||||||
mute: true
|
|
||||||
storagelist: true
|
|
||||||
cartlist: true
|
|
||||||
itemlist: true
|
|
||||||
stats: true
|
|
||||||
}
|
|
||||||
log_commands: true
|
|
||||||
permissions: {
|
|
||||||
join_chat: true
|
|
||||||
kick_chat: true
|
|
||||||
hide_session: true
|
|
||||||
who_display_aid: true
|
|
||||||
hack_info: true
|
|
||||||
any_warp: true
|
|
||||||
view_hpmeter: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 99
|
|
||||||
name: "Admin"
|
|
||||||
level: 99
|
|
||||||
inherit: ( "Support", "Law Enforcement" )
|
|
||||||
commands: {
|
|
||||||
/* not necessary due to all_commands: true */
|
|
||||||
}
|
|
||||||
log_commands: true
|
|
||||||
permissions: {
|
|
||||||
can_trade: true
|
|
||||||
can_party: true
|
|
||||||
command_enable: true
|
|
||||||
all_skill: false
|
|
||||||
all_equipment: false
|
|
||||||
skill_unconditional: false
|
|
||||||
use_check: true
|
|
||||||
use_changemaptype: true
|
|
||||||
all_commands: true
|
|
||||||
channel_admin: true
|
|
||||||
can_trade_bounded: true
|
|
||||||
item_unconditional: false
|
|
||||||
bypass_stat_onclone: true
|
|
||||||
bypass_max_stat: true
|
|
||||||
/* all_permission: true */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
245
conf/groups.yml
Normal file
245
conf/groups.yml
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
# This file is a part of rAthena.
|
||||||
|
# Copyright(C) 2022 rAthena Development Team
|
||||||
|
# https://rathena.org - https://github.com/rathena
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
###########################################################################
|
||||||
|
# Player Group Database
|
||||||
|
###########################################################################
|
||||||
|
#
|
||||||
|
# Player Group Settings
|
||||||
|
#
|
||||||
|
###########################################################################
|
||||||
|
# - Id Group ID.
|
||||||
|
# Name Group name.
|
||||||
|
# Level GM Level used for ranking groups. (Default: 0)
|
||||||
|
# LogCommands Whether atcommands should be logged or not. (Default: false)
|
||||||
|
# Commands: List of atcommands that can be used by this group. (Default: none)
|
||||||
|
# <atcommand name> Whether the specified atcommand can be used by this group or not.
|
||||||
|
# CharCommands: List of charcommands that can be used by this group. (Default: none)
|
||||||
|
# <charcommand name> Whether the specified charcommand can be used by this group or not.
|
||||||
|
# Permissions: List of permissions the group has. (Default: none)
|
||||||
|
# <permission name> Whether the group has this permission or not.
|
||||||
|
# Inherit: List of groups that will be inherited. (Default: none)
|
||||||
|
# <group name> Whether this group will be inherited or not.
|
||||||
|
###########################################################################
|
||||||
|
|
||||||
|
Header:
|
||||||
|
Type: PLAYER_GROUP_DB
|
||||||
|
Version: 1
|
||||||
|
|
||||||
|
Body:
|
||||||
|
- Id: 0
|
||||||
|
# group 0 is the default group for every new account
|
||||||
|
Name: Player
|
||||||
|
Level: 0
|
||||||
|
Commands:
|
||||||
|
changedress: true
|
||||||
|
resurrect: true
|
||||||
|
Permissions:
|
||||||
|
# without this basic permissions regular players could not trade or party
|
||||||
|
can_trade: true
|
||||||
|
can_party: true
|
||||||
|
attendance: true
|
||||||
|
- Id: 1
|
||||||
|
Name: Super Player
|
||||||
|
# Can do everything Players can and more
|
||||||
|
Inherit:
|
||||||
|
Player: true
|
||||||
|
Level: 0
|
||||||
|
Commands:
|
||||||
|
# Informational commands
|
||||||
|
commands: true
|
||||||
|
charcommands: true
|
||||||
|
help: true
|
||||||
|
rates: true
|
||||||
|
uptime: true
|
||||||
|
showdelay: true
|
||||||
|
exp: true
|
||||||
|
mobinfo: true
|
||||||
|
iteminfo: true
|
||||||
|
whodrops: true
|
||||||
|
time: true
|
||||||
|
jailtime: true
|
||||||
|
hominfo: true
|
||||||
|
homstats: true
|
||||||
|
showexp: true
|
||||||
|
showzeny: true
|
||||||
|
whereis: true
|
||||||
|
# Feature commands
|
||||||
|
refresh: true
|
||||||
|
noask: true
|
||||||
|
noks: true
|
||||||
|
autoloot: true
|
||||||
|
alootid: true
|
||||||
|
autoloottype: true
|
||||||
|
autotrade: true
|
||||||
|
request: true
|
||||||
|
go: true
|
||||||
|
breakguild: true
|
||||||
|
channel: true
|
||||||
|
langtype: true
|
||||||
|
Permissions:
|
||||||
|
attendance: false
|
||||||
|
- Id: 2
|
||||||
|
Name: Support
|
||||||
|
Inherit:
|
||||||
|
Super Player: true
|
||||||
|
Level: 1
|
||||||
|
Commands:
|
||||||
|
version: true
|
||||||
|
where: true
|
||||||
|
jumpto: true
|
||||||
|
who: true
|
||||||
|
who2: true
|
||||||
|
who3: true
|
||||||
|
whomap: true
|
||||||
|
whomap2: true
|
||||||
|
whomap3: true
|
||||||
|
users: true
|
||||||
|
broadcast: true
|
||||||
|
localbroadcast: true
|
||||||
|
LogCommands: true
|
||||||
|
Permissions:
|
||||||
|
receive_requests: true
|
||||||
|
view_equipment: true
|
||||||
|
- Id: 3
|
||||||
|
Name: Script Manager
|
||||||
|
Inherit:
|
||||||
|
Support: true
|
||||||
|
Level: 1
|
||||||
|
Commands:
|
||||||
|
tonpc: true
|
||||||
|
hidenpc: true
|
||||||
|
shownpc: true
|
||||||
|
loadnpc: true
|
||||||
|
unloadnpc: true
|
||||||
|
npcmove: true
|
||||||
|
addwarp: true
|
||||||
|
LogCommands: true
|
||||||
|
Permissions:
|
||||||
|
any_warp: true
|
||||||
|
- Id: 4
|
||||||
|
Name: Event Manager
|
||||||
|
Inherit:
|
||||||
|
Support: true
|
||||||
|
Level: 1
|
||||||
|
Commands:
|
||||||
|
monster: true
|
||||||
|
monstersmall: true
|
||||||
|
monsterbig: true
|
||||||
|
killmonster2: true
|
||||||
|
cleanarea: true
|
||||||
|
cleanmap: true
|
||||||
|
item: true
|
||||||
|
zeny: true
|
||||||
|
disguise: true
|
||||||
|
undisguise: true
|
||||||
|
size: true
|
||||||
|
raise: true
|
||||||
|
raisemap: true
|
||||||
|
day: true
|
||||||
|
night: true
|
||||||
|
skillon: true
|
||||||
|
skilloff: true
|
||||||
|
pvpon: true
|
||||||
|
pvpoff: true
|
||||||
|
gvgon: true
|
||||||
|
gvgoff: true
|
||||||
|
allowks: true
|
||||||
|
me: true
|
||||||
|
marry: true
|
||||||
|
divorce: true
|
||||||
|
refreshall: true
|
||||||
|
CharCommands:
|
||||||
|
item: true
|
||||||
|
zeny: true
|
||||||
|
disguise: true
|
||||||
|
undisguise: true
|
||||||
|
size: true
|
||||||
|
LogCommands: true
|
||||||
|
Permissions:
|
||||||
|
can_trade: false
|
||||||
|
any_warp: true
|
||||||
|
- Id: 5
|
||||||
|
Name: VIP
|
||||||
|
# Can do everything Players can
|
||||||
|
Inherit:
|
||||||
|
Player: true
|
||||||
|
Level: 0
|
||||||
|
Commands:
|
||||||
|
rates: true
|
||||||
|
who: true
|
||||||
|
- Id: 10
|
||||||
|
Name: Law Enforcement
|
||||||
|
Inherit:
|
||||||
|
Support: true
|
||||||
|
Level: 2
|
||||||
|
Commands:
|
||||||
|
hide: true
|
||||||
|
follow: true
|
||||||
|
kick: true
|
||||||
|
disguise: true
|
||||||
|
fakename: true
|
||||||
|
option: true
|
||||||
|
speed: true
|
||||||
|
warp: true
|
||||||
|
kill: true
|
||||||
|
recall: true
|
||||||
|
ban: true
|
||||||
|
block: true
|
||||||
|
jail: true
|
||||||
|
jailfor: true
|
||||||
|
mute: true
|
||||||
|
storagelist: true
|
||||||
|
cartlist: true
|
||||||
|
itemlist: true
|
||||||
|
stats: true
|
||||||
|
LogCommands: true
|
||||||
|
Permissions:
|
||||||
|
join_chat: true
|
||||||
|
kick_chat: true
|
||||||
|
hide_session: true
|
||||||
|
who_display_aid: true
|
||||||
|
hack_info: true
|
||||||
|
any_warp: true
|
||||||
|
view_hpmeter: true
|
||||||
|
- Id: 99
|
||||||
|
Name: Admin
|
||||||
|
Level: 99
|
||||||
|
Inherit:
|
||||||
|
Support: true
|
||||||
|
Law Enforcement: true
|
||||||
|
LogCommands: true
|
||||||
|
Permissions:
|
||||||
|
can_trade: true
|
||||||
|
can_party: true
|
||||||
|
command_enable: true
|
||||||
|
all_skill: false
|
||||||
|
all_equipment: false
|
||||||
|
skill_unconditional: false
|
||||||
|
use_check: true
|
||||||
|
use_changemaptype: true
|
||||||
|
all_commands: true
|
||||||
|
channel_admin: true
|
||||||
|
can_trade_bounded: true
|
||||||
|
item_unconditional: false
|
||||||
|
bypass_stat_onclone: true
|
||||||
|
bypass_max_stat: true
|
||||||
|
#all_permission: true
|
||||||
|
|
||||||
|
Footer:
|
||||||
|
Imports:
|
||||||
|
- Path: conf/import/groups.yml
|
41
conf/import-tmpl/groups.yml
Normal file
41
conf/import-tmpl/groups.yml
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# This file is a part of rAthena.
|
||||||
|
# Copyright(C) 2022 rAthena Development Team
|
||||||
|
# https://rathena.org - https://github.com/rathena
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
###########################################################################
|
||||||
|
# Player Group Database
|
||||||
|
###########################################################################
|
||||||
|
#
|
||||||
|
# Player Group Settings
|
||||||
|
#
|
||||||
|
###########################################################################
|
||||||
|
# - Id Group ID.
|
||||||
|
# Name Group name.
|
||||||
|
# Level GM Level used for ranking groups. (Default: 0)
|
||||||
|
# LogCommands Whether atcommands should be logged or not. (Default: false)
|
||||||
|
# Commands: List of atcommands that can be used by this group. (Default: none)
|
||||||
|
# <atcommand name> Whether the specified atcommand can be used by this group or not.
|
||||||
|
# CharCommands: List of charcommands that can be used by this group. (Default: none)
|
||||||
|
# <charcommand name> Whether the specified charcommand can be used by this group or not.
|
||||||
|
# Permissions: List of permissions the group has. (Default: none)
|
||||||
|
# <permission name> Whether the group has this permission or not.
|
||||||
|
# Inherit: List of groups that will be inherited. (Default: none)
|
||||||
|
# <group name> Whether this group will be inherited or not.
|
||||||
|
###########################################################################
|
||||||
|
|
||||||
|
Header:
|
||||||
|
Type: PLAYER_GROUP_DB
|
||||||
|
Version: 1
|
@ -616,7 +616,7 @@ ACMD_FUNC(mapmove)
|
|||||||
if (!map_search_freecell(NULL, m, &x, &y, 10, 10, 1))
|
if (!map_search_freecell(NULL, m, &x, &y, 10, 10, 1))
|
||||||
x = y = 0; //Invalid cell, use random spot.
|
x = y = 0; //Invalid cell, use random spot.
|
||||||
}
|
}
|
||||||
if ((map_getmapflag(m, MF_NOWARPTO) && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) || !pc_job_can_entermap((enum e_job)sd->status.class_, m, sd->group_level)) {
|
if ((map_getmapflag(m, MF_NOWARPTO) && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) || !pc_job_can_entermap((enum e_job)sd->status.class_, m, pc_get_group_level(sd))) {
|
||||||
clif_displaymessage(fd, msg_txt(sd,247)); // You are not authorized to warp to this map.
|
clif_displaymessage(fd, msg_txt(sd,247)); // You are not authorized to warp to this map.
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -794,7 +794,7 @@ ACMD_FUNC(who) {
|
|||||||
case 2: {
|
case 2: {
|
||||||
StringBuf_Printf(&buf, msg_txt(sd,343), pl_sd->status.name); // "Name: %s "
|
StringBuf_Printf(&buf, msg_txt(sd,343), pl_sd->status.name); // "Name: %s "
|
||||||
if (pc_get_group_id(pl_sd) > 0) // Player title, if exists
|
if (pc_get_group_id(pl_sd) > 0) // Player title, if exists
|
||||||
StringBuf_Printf(&buf, msg_txt(sd,344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) "
|
StringBuf_Printf(&buf, msg_txt(sd,344),pl_sd->group->name.c_str()); // "(%s) "
|
||||||
StringBuf_Printf(&buf, msg_txt(sd,347), pl_sd->status.base_level, pl_sd->status.job_level,
|
StringBuf_Printf(&buf, msg_txt(sd,347), pl_sd->status.base_level, pl_sd->status.job_level,
|
||||||
job_name(pl_sd->status.class_)); // "| Lv:%d/%d | Job: %s"
|
job_name(pl_sd->status.class_)); // "| Lv:%d/%d | Job: %s"
|
||||||
break;
|
break;
|
||||||
@ -804,7 +804,7 @@ ACMD_FUNC(who) {
|
|||||||
StringBuf_Printf(&buf, msg_txt(sd,912), pl_sd->status.char_id, pl_sd->status.account_id); // "(CID:%d/AID:%d) "
|
StringBuf_Printf(&buf, msg_txt(sd,912), pl_sd->status.char_id, pl_sd->status.account_id); // "(CID:%d/AID:%d) "
|
||||||
StringBuf_Printf(&buf, msg_txt(sd,343), pl_sd->status.name); // "Name: %s "
|
StringBuf_Printf(&buf, msg_txt(sd,343), pl_sd->status.name); // "Name: %s "
|
||||||
if (pc_get_group_id(pl_sd) > 0) // Player title, if exists
|
if (pc_get_group_id(pl_sd) > 0) // Player title, if exists
|
||||||
StringBuf_Printf(&buf, msg_txt(sd,344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) "
|
StringBuf_Printf(&buf, msg_txt(sd,344), pl_sd->group->name.c_str()); // "(%s) "
|
||||||
StringBuf_Printf(&buf, msg_txt(sd,348), mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); // "| Location: %s %d %d"
|
StringBuf_Printf(&buf, msg_txt(sd,348), mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); // "| Location: %s %d %d"
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -814,7 +814,7 @@ ACMD_FUNC(who) {
|
|||||||
|
|
||||||
StringBuf_Printf(&buf, msg_txt(sd,343), pl_sd->status.name); // "Name: %s "
|
StringBuf_Printf(&buf, msg_txt(sd,343), pl_sd->status.name); // "Name: %s "
|
||||||
if (pc_get_group_id(pl_sd) > 0) // Player title, if exists
|
if (pc_get_group_id(pl_sd) > 0) // Player title, if exists
|
||||||
StringBuf_Printf(&buf, msg_txt(sd,344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) "
|
StringBuf_Printf(&buf, msg_txt(sd,344), pl_sd->group->name.c_str()); // "(%s) "
|
||||||
if (p != NULL)
|
if (p != NULL)
|
||||||
StringBuf_Printf(&buf, msg_txt(sd,345), p->party.name); // " | Party: '%s'"
|
StringBuf_Printf(&buf, msg_txt(sd,345), p->party.name); // " | Party: '%s'"
|
||||||
if (g != NULL)
|
if (g != NULL)
|
||||||
@ -7284,7 +7284,7 @@ ACMD_FUNC(adjgroup)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pc_group_exists(new_group)) {
|
if (!player_group_db.exists(new_group)) {
|
||||||
clif_displaymessage(fd, msg_txt(sd,1227)); // Specified group does not exist.
|
clif_displaymessage(fd, msg_txt(sd,1227)); // Specified group does not exist.
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -9552,11 +9552,11 @@ static void atcommand_commands_sub(struct map_session_data* sd, const int fd, At
|
|||||||
|
|
||||||
switch( type ) {
|
switch( type ) {
|
||||||
case COMMAND_CHARCOMMAND:
|
case COMMAND_CHARCOMMAND:
|
||||||
if( cmd->char_groups[sd->group_pos] == 0 )
|
if( cmd->char_groups[sd->group->index] == 0 )
|
||||||
continue;
|
continue;
|
||||||
break;
|
break;
|
||||||
case COMMAND_ATCOMMAND:
|
case COMMAND_ATCOMMAND:
|
||||||
if( cmd->at_groups[sd->group_pos] == 0 )
|
if( cmd->at_groups[sd->group->index] == 0 )
|
||||||
continue;
|
continue;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -9815,17 +9815,17 @@ ACMD_FUNC(addperm) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( add && (sd->permissions&pc_g_permission_name[i].permission) ) {
|
if( add && pc_has_permission( sd, pc_g_permission_name[i].permission) ){
|
||||||
sprintf(atcmd_output, msg_txt(sd,1381),sd->status.name,pc_g_permission_name[i].name); // User '%s' already possesses the '%s' permission.
|
sprintf(atcmd_output, msg_txt(sd,1381),sd->status.name,pc_g_permission_name[i].name); // User '%s' already possesses the '%s' permission.
|
||||||
clif_displaymessage(fd, atcmd_output);
|
clif_displaymessage(fd, atcmd_output);
|
||||||
return -1;
|
return -1;
|
||||||
} else if ( !add && !(sd->permissions&pc_g_permission_name[i].permission) ) {
|
}else if( !add && !pc_has_permission( sd, pc_g_permission_name[i].permission ) ){
|
||||||
sprintf(atcmd_output, msg_txt(sd,1382),sd->status.name,pc_g_permission_name[i].name); // User '%s' doesn't possess the '%s' permission.
|
sprintf(atcmd_output, msg_txt(sd,1382),sd->status.name,pc_g_permission_name[i].name); // User '%s' doesn't possess the '%s' permission.
|
||||||
clif_displaymessage(fd, atcmd_output);
|
clif_displaymessage(fd, atcmd_output);
|
||||||
sprintf(atcmd_output,msg_txt(sd,1383),sd->status.name); // -- User '%s' Permissions
|
sprintf(atcmd_output,msg_txt(sd,1383),sd->status.name); // -- User '%s' Permissions
|
||||||
clif_displaymessage(fd, atcmd_output);
|
clif_displaymessage(fd, atcmd_output);
|
||||||
for( i = 0; i < perm_size; i++ ) {
|
for( i = 0; i < perm_size; i++ ) {
|
||||||
if( sd->permissions&pc_g_permission_name[i].permission ) {
|
if( pc_has_permission( sd, pc_g_permission_name[i].permission ) ){
|
||||||
sprintf(atcmd_output,"- %s",pc_g_permission_name[i].name);
|
sprintf(atcmd_output,"- %s",pc_g_permission_name[i].name);
|
||||||
clif_displaymessage(fd, atcmd_output);
|
clif_displaymessage(fd, atcmd_output);
|
||||||
}
|
}
|
||||||
@ -9834,10 +9834,11 @@ ACMD_FUNC(addperm) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( add )
|
if( add ){
|
||||||
sd->permissions |= pc_g_permission_name[i].permission;
|
sd->permissions.set( pc_g_permission_name[i].permission );
|
||||||
else
|
}else{
|
||||||
sd->permissions &=~ pc_g_permission_name[i].permission;
|
sd->permissions.reset( pc_g_permission_name[i].permission );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
sprintf(atcmd_output, msg_txt(sd,1384),sd->status.name); // User '%s' permissions updated successfully. The changes are temporary.
|
sprintf(atcmd_output, msg_txt(sd,1384),sd->status.name); // User '%s' permissions updated successfully. The changes are temporary.
|
||||||
@ -11212,7 +11213,7 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message
|
|||||||
return false; // No command found. Display as normal message.
|
return false; // No command found. Display as normal message.
|
||||||
|
|
||||||
info = get_atcommandinfo_byname(atcommand_alias_db.checkAlias(command + 1));
|
info = get_atcommandinfo_byname(atcommand_alias_db.checkAlias(command + 1));
|
||||||
if (!info || info->char_groups[sd->group_pos] == 0) // If we can't use or doesn't exist: don't even display the command failed message
|
if (!info || info->char_groups[sd->group->index] == 0) // If we can't use or doesn't exist: don't even display the command failed message
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -11295,8 +11296,8 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message
|
|||||||
|
|
||||||
// type == 1 : player invoked
|
// type == 1 : player invoked
|
||||||
if (type == 1) {
|
if (type == 1) {
|
||||||
if ((is_atcommand && info->at_groups[sd->group_pos] == 0) ||
|
if ((is_atcommand && info->at_groups[sd->group->index] == 0) ||
|
||||||
(!is_atcommand && info->char_groups[sd->group_pos] == 0) )
|
(!is_atcommand && info->char_groups[sd->group->index] == 0) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if( pc_isdead(sd) && pc_has_permission(sd,PC_PERM_DISABLE_CMD_DEAD) ) {
|
if( pc_isdead(sd) && pc_has_permission(sd,PC_PERM_DISABLE_CMD_DEAD) ) {
|
||||||
@ -11319,29 +11320,22 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void atcommand_db_load_groups(int* group_ids) {
|
void atcommand_db_load_groups(){
|
||||||
DBIterator *iter = db_iterator(atcommand_db);
|
DBIterator *iter = db_iterator(atcommand_db);
|
||||||
AtCommandInfo* cmd;
|
AtCommandInfo* cmd;
|
||||||
int i;
|
int pc_group_max = player_group_db.size();
|
||||||
|
|
||||||
for (cmd = (AtCommandInfo*)dbi_first(iter); dbi_exists(iter); cmd = (AtCommandInfo*)dbi_next(iter)) {
|
for (cmd = (AtCommandInfo*)dbi_first(iter); dbi_exists(iter); cmd = (AtCommandInfo*)dbi_next(iter)) {
|
||||||
cmd->at_groups = (char*)aMalloc( pc_group_max * sizeof(char) );
|
cmd->at_groups = (char*)aMalloc( pc_group_max * sizeof(char) );
|
||||||
cmd->char_groups = (char*)aMalloc( pc_group_max * sizeof(char) );
|
cmd->char_groups = (char*)aMalloc( pc_group_max * sizeof(char) );
|
||||||
for(i = 0; i < pc_group_max; i++) {
|
|
||||||
if( pc_group_can_use_command(group_ids[i], cmd->command, COMMAND_ATCOMMAND ) )
|
for( auto& it : player_group_db ){
|
||||||
cmd->at_groups[i] = 1;
|
cmd->at_groups[it.second->index] = it.second->can_use_command( cmd->command, COMMAND_ATCOMMAND );
|
||||||
else
|
cmd->char_groups[it.second->index] = it.second->can_use_command( cmd->command, COMMAND_CHARCOMMAND );
|
||||||
cmd->at_groups[i] = 0;
|
|
||||||
if( pc_group_can_use_command(group_ids[i], cmd->command, COMMAND_CHARCOMMAND ) )
|
|
||||||
cmd->char_groups[i] = 1;
|
|
||||||
else
|
|
||||||
cmd->char_groups[i] = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dbi_destroy(iter);
|
dbi_destroy(iter);
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
void atcommand_db_clear(void) {
|
void atcommand_db_clear(void) {
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message
|
|||||||
|
|
||||||
void do_init_atcommand(void);
|
void do_init_atcommand(void);
|
||||||
void do_final_atcommand(void);
|
void do_final_atcommand(void);
|
||||||
void atcommand_db_load_groups(int* group_ids);
|
void atcommand_db_load_groups();
|
||||||
|
|
||||||
bool atcommand_exists(const char* name);
|
bool atcommand_exists(const char* name);
|
||||||
|
|
||||||
|
@ -1342,7 +1342,7 @@ int intif_parse_WisEnd(int fd)
|
|||||||
*/
|
*/
|
||||||
static int mapif_parse_WisToGM_sub(struct map_session_data* sd,va_list va)
|
static int mapif_parse_WisToGM_sub(struct map_session_data* sd,va_list va)
|
||||||
{
|
{
|
||||||
int permission = va_arg(va, int);
|
e_pc_permission permission = va_arg(va, e_pc_permission);
|
||||||
char *wisp_name;
|
char *wisp_name;
|
||||||
char *message;
|
char *message;
|
||||||
int len;
|
int len;
|
||||||
|
@ -294,6 +294,7 @@
|
|||||||
<Copy SourceFiles="$(SolutionDir)conf\import-tmpl\atcommands.yml" DestinationFolder="$(SolutionDir)conf\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)conf\import\atcommands.yml')" />
|
<Copy SourceFiles="$(SolutionDir)conf\import-tmpl\atcommands.yml" DestinationFolder="$(SolutionDir)conf\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)conf\import\atcommands.yml')" />
|
||||||
<Copy SourceFiles="$(SolutionDir)conf\import-tmpl\battle_conf.txt" DestinationFolder="$(SolutionDir)conf\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)conf\import\battle_conf.txt')" />
|
<Copy SourceFiles="$(SolutionDir)conf\import-tmpl\battle_conf.txt" DestinationFolder="$(SolutionDir)conf\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)conf\import\battle_conf.txt')" />
|
||||||
<Copy SourceFiles="$(SolutionDir)conf\import-tmpl\char_conf.txt" DestinationFolder="$(SolutionDir)conf\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)conf\import\char_conf.txt')" />
|
<Copy SourceFiles="$(SolutionDir)conf\import-tmpl\char_conf.txt" DestinationFolder="$(SolutionDir)conf\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)conf\import\char_conf.txt')" />
|
||||||
|
<Copy SourceFiles="$(SolutionDir)conf\import-tmpl\groups.yml" DestinationFolder="$(SolutionDir)conf\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)conf\import\groups.yml')" />
|
||||||
<Copy SourceFiles="$(SolutionDir)conf\import-tmpl\inter_conf.txt" DestinationFolder="$(SolutionDir)conf\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)conf\import\inter_conf.txt')" />
|
<Copy SourceFiles="$(SolutionDir)conf\import-tmpl\inter_conf.txt" DestinationFolder="$(SolutionDir)conf\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)conf\import\inter_conf.txt')" />
|
||||||
<Copy SourceFiles="$(SolutionDir)conf\import-tmpl\inter_server.yml" DestinationFolder="$(SolutionDir)conf\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)conf\import\inter_server.yml')" />
|
<Copy SourceFiles="$(SolutionDir)conf\import-tmpl\inter_server.yml" DestinationFolder="$(SolutionDir)conf\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)conf\import\inter_server.yml')" />
|
||||||
<Copy SourceFiles="$(SolutionDir)conf\import-tmpl\log_conf.txt" DestinationFolder="$(SolutionDir)conf\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)conf\import\log_conf.txt')" />
|
<Copy SourceFiles="$(SolutionDir)conf\import-tmpl\log_conf.txt" DestinationFolder="$(SolutionDir)conf\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)conf\import\log_conf.txt')" />
|
||||||
|
@ -1858,7 +1858,7 @@ int npc_touch_areanpc(struct map_session_data* sd, int16 m, int16 x, int16 y, st
|
|||||||
case NPCTYPE_WARP:
|
case NPCTYPE_WARP:
|
||||||
if ((!nd->trigger_on_hidden && (pc_ishiding(sd) || (sd->sc.count && sd->sc.data[SC_CAMOUFLAGE]))) || pc_isdead(sd))
|
if ((!nd->trigger_on_hidden && (pc_ishiding(sd) || (sd->sc.count && sd->sc.data[SC_CAMOUFLAGE]))) || pc_isdead(sd))
|
||||||
break; // hidden or dead chars cannot use warps
|
break; // hidden or dead chars cannot use warps
|
||||||
if (!pc_job_can_entermap((enum e_job)sd->status.class_, map_mapindex2mapid(nd->u.warp.mapindex), sd->group_level))
|
if (!pc_job_can_entermap((enum e_job)sd->status.class_, map_mapindex2mapid(nd->u.warp.mapindex), pc_get_group_level(sd)))
|
||||||
break;
|
break;
|
||||||
if (sd->count_rewarp > 10) {
|
if (sd->count_rewarp > 10) {
|
||||||
ShowWarning("Prevented infinite warp loop for player (%d:%d). Please fix NPC: '%s', path: '%s'\n", sd->status.account_id, sd->status.char_id, nd->exname, nd->path);
|
ShowWarning("Prevented infinite warp loop for player (%d:%d). Please fix NPC: '%s', path: '%s'\n", sd->status.account_id, sd->status.char_id, nd->exname, nd->path);
|
||||||
|
@ -443,7 +443,7 @@ int pc_get_group_id(struct map_session_data *sd) {
|
|||||||
* @return Group Level
|
* @return Group Level
|
||||||
*/
|
*/
|
||||||
int pc_get_group_level(struct map_session_data *sd) {
|
int pc_get_group_level(struct map_session_data *sd) {
|
||||||
return sd->group_level;
|
return sd->group->level;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -12454,9 +12454,12 @@ bool pc_isautolooting(struct map_session_data *sd, t_itemid nameid)
|
|||||||
* @param command Command name without @/# and params
|
* @param command Command name without @/# and params
|
||||||
* @param type is it atcommand or charcommand
|
* @param type is it atcommand or charcommand
|
||||||
*/
|
*/
|
||||||
bool pc_can_use_command(struct map_session_data *sd, const char *command, AtCommandType type)
|
bool pc_can_use_command( struct map_session_data *sd, const char *command, AtCommandType type ){
|
||||||
{
|
return sd->group->can_use_command( command, type );
|
||||||
return pc_group_can_use_command(pc_get_group_id(sd), command, type);
|
}
|
||||||
|
|
||||||
|
bool pc_has_permission( struct map_session_data* sd, e_pc_permission permission ){
|
||||||
|
return sd->permissions.test( permission );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -12464,9 +12467,8 @@ bool pc_can_use_command(struct map_session_data *sd, const char *command, AtComm
|
|||||||
* according to their group setting.
|
* according to their group setting.
|
||||||
* @param sd Player map session data
|
* @param sd Player map session data
|
||||||
*/
|
*/
|
||||||
bool pc_should_log_commands(struct map_session_data *sd)
|
bool pc_should_log_commands( struct map_session_data *sd ){
|
||||||
{
|
return sd->group->log_commands;
|
||||||
return pc_group_should_log_commands(pc_get_group_id(sd));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#ifndef PC_HPP
|
#ifndef PC_HPP
|
||||||
#define PC_HPP
|
#define PC_HPP
|
||||||
|
|
||||||
|
#include <bitset>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -19,6 +20,7 @@
|
|||||||
#include "itemdb.hpp" // MAX_ITEMGROUP
|
#include "itemdb.hpp" // MAX_ITEMGROUP
|
||||||
#include "map.hpp" // RC_ALL
|
#include "map.hpp" // RC_ALL
|
||||||
#include "mob.hpp" //e_size
|
#include "mob.hpp" //e_size
|
||||||
|
#include "pc_groups.hpp" // s_player_group
|
||||||
#include "script.hpp" // struct script_reg, struct script_regstr
|
#include "script.hpp" // struct script_reg, struct script_regstr
|
||||||
#include "searchstore.hpp" // struct s_search_store_info
|
#include "searchstore.hpp" // struct s_search_store_info
|
||||||
#include "status.hpp" // unit_data
|
#include "status.hpp" // unit_data
|
||||||
@ -408,8 +410,9 @@ struct map_session_data {
|
|||||||
} special_state;
|
} special_state;
|
||||||
uint32 login_id1, login_id2;
|
uint32 login_id1, login_id2;
|
||||||
uint64 class_; //This is the internal job ID used by the map server to simplify comparisons/queries/etc. [Skotlex]
|
uint64 class_; //This is the internal job ID used by the map server to simplify comparisons/queries/etc. [Skotlex]
|
||||||
int group_id, group_pos, group_level;
|
int group_id;
|
||||||
unsigned int permissions;/* group permissions */
|
std::shared_ptr<s_player_group> group;
|
||||||
|
std::bitset<PC_PERM_MAX> permissions; // group permissions have to be copied, because they might be adjusted by atcommand addperm
|
||||||
int count_rewarp; //count how many time we being rewarped
|
int count_rewarp; //count how many time we being rewarped
|
||||||
|
|
||||||
int langtype;
|
int langtype;
|
||||||
@ -1238,7 +1241,7 @@ bool pc_can_give_bounded_items(struct map_session_data *sd);
|
|||||||
bool pc_can_trade_item(map_session_data *sd, int index);
|
bool pc_can_trade_item(map_session_data *sd, int index);
|
||||||
|
|
||||||
bool pc_can_use_command(struct map_session_data *sd, const char *command, AtCommandType type);
|
bool pc_can_use_command(struct map_session_data *sd, const char *command, AtCommandType type);
|
||||||
#define pc_has_permission(sd, permission) ( ((sd)->permissions&permission) != 0 )
|
bool pc_has_permission( struct map_session_data* sd, e_pc_permission permission );
|
||||||
bool pc_should_log_commands(struct map_session_data *sd);
|
bool pc_should_log_commands(struct map_session_data *sd);
|
||||||
|
|
||||||
void pc_setrestartvalue(struct map_session_data *sd, char type);
|
void pc_setrestartvalue(struct map_session_data *sd, char type);
|
||||||
|
@ -3,353 +3,343 @@
|
|||||||
|
|
||||||
#include "pc_groups.hpp"
|
#include "pc_groups.hpp"
|
||||||
|
|
||||||
#include "../common/conf.hpp"
|
|
||||||
#include "../common/db.hpp"
|
|
||||||
#include "../common/malloc.hpp"
|
|
||||||
#include "../common/showmsg.hpp"
|
#include "../common/showmsg.hpp"
|
||||||
#include "../common/socket.hpp"
|
#include "../common/socket.hpp" // set_eof
|
||||||
#include "../common/strlib.hpp" // strcmp
|
#include "../common/strlib.hpp" // strcmpi
|
||||||
|
#include "../common/utilities.hpp"
|
||||||
|
|
||||||
#include "atcommand.hpp" // AtCommandType
|
#include "atcommand.hpp" // AtCommandType
|
||||||
#include "pc.hpp" // e_pc_permission
|
#include "pc.hpp" // struct map_session_data
|
||||||
|
|
||||||
typedef struct GroupSettings GroupSettings;
|
using namespace rathena;
|
||||||
|
|
||||||
// Cached config settings/pointers for quick lookup
|
const std::string PlayerGroupDatabase::getDefaultLocation() {
|
||||||
struct GroupSettings {
|
return std::string( conf_path ) + "/groups.yml";
|
||||||
unsigned int id; // groups.[].id
|
|
||||||
int level; // groups.[].level
|
|
||||||
const char *name; // groups.[].name
|
|
||||||
config_setting_t *commands; // groups.[].commands
|
|
||||||
unsigned int e_permissions; // packed groups.[].permissions
|
|
||||||
bool log_commands; // groups.[].log_commands
|
|
||||||
/// Following are used only during config reading
|
|
||||||
config_setting_t *permissions; // groups.[].permissions
|
|
||||||
config_setting_t *inherit; // groups.[].inherit
|
|
||||||
bool inheritance_done; // have all inheritance rules been evaluated?
|
|
||||||
config_setting_t *root; // groups.[]
|
|
||||||
int group_pos;/* pos on load */
|
|
||||||
};
|
|
||||||
|
|
||||||
int pc_group_max; /* known number of groups */
|
|
||||||
|
|
||||||
static config_t pc_group_config;
|
|
||||||
static DBMap* pc_group_db; // id -> GroupSettings
|
|
||||||
static DBMap* pc_groupname_db; // name -> GroupSettings
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @retval NULL if not found
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
static inline GroupSettings* id2group(int group_id)
|
|
||||||
{
|
|
||||||
return (GroupSettings*)idb_get(pc_group_db, group_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
bool PlayerGroupDatabase::parseCommands( const ryml::NodeRef& node, std::vector<std::string>& commands ){
|
||||||
* @retval NULL if not found
|
for( const auto& it : node.children() ){
|
||||||
* @private
|
std::string command;
|
||||||
*/
|
|
||||||
static inline GroupSettings* name2group(const char* group_name)
|
|
||||||
{
|
|
||||||
return (GroupSettings*)strdb_get(pc_groupname_db, group_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
c4::from_chars( it.key(), &command );
|
||||||
* Loads group configuration from config file into memory.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
static void read_config(void)
|
|
||||||
{
|
|
||||||
config_setting_t *groups = NULL;
|
|
||||||
const char *config_filename = "conf/groups.conf"; // FIXME hardcoded name
|
|
||||||
int group_count = 0;
|
|
||||||
|
|
||||||
if (conf_read_file(&pc_group_config, config_filename))
|
|
||||||
return;
|
|
||||||
|
|
||||||
groups = config_lookup(&pc_group_config, "groups");
|
bool allowed;
|
||||||
|
|
||||||
if (groups != NULL) {
|
if( !this->asBool( node, command, allowed ) ){
|
||||||
GroupSettings *group_settings = NULL;
|
return false;
|
||||||
DBIterator *iter = NULL;
|
|
||||||
int i, loop = 0;
|
|
||||||
|
|
||||||
group_count = config_setting_length(groups);
|
|
||||||
for (i = 0; i < group_count; ++i) {
|
|
||||||
int id = 0, level = 0;
|
|
||||||
const char *groupname = NULL;
|
|
||||||
int log_commands = 0;
|
|
||||||
config_setting_t *group = config_setting_get_elem(groups, i);
|
|
||||||
|
|
||||||
if (!config_setting_lookup_int(group, "id", &id)) {
|
|
||||||
ShowConfigWarning(group, "pc_groups:read_config: \"groups\" list member #%d has undefined id, removing...", i);
|
|
||||||
config_setting_remove_elem(groups, i);
|
|
||||||
--i;
|
|
||||||
--group_count;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id2group(id) != NULL) {
|
|
||||||
ShowConfigWarning(group, "pc_groups:read_config: duplicate group id %d, removing...", i);
|
|
||||||
config_setting_remove_elem(groups, i);
|
|
||||||
--i;
|
|
||||||
--group_count;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
config_setting_lookup_int(group, "level", &level);
|
|
||||||
config_setting_lookup_bool(group, "log_commands", &log_commands);
|
|
||||||
|
|
||||||
if (!config_setting_lookup_string(group, "name", &groupname)) {
|
|
||||||
char temp[20];
|
|
||||||
config_setting_t *name = NULL;
|
|
||||||
snprintf(temp, sizeof(temp), "Group %d", id);
|
|
||||||
if ((name = config_setting_add(group, "name", CONFIG_TYPE_STRING)) == NULL ||
|
|
||||||
!config_setting_set_string(name, temp)) {
|
|
||||||
ShowError("pc_groups:read_config: failed to set missing group name, id=%d, skipping... (%s:%d)\n",
|
|
||||||
id, config_setting_source_file(group), config_setting_source_line(group));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
config_setting_lookup_string(group, "name", &groupname); // Retrieve the pointer
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name2group(groupname) != NULL) {
|
|
||||||
ShowConfigWarning(group, "pc_groups:read_config: duplicate group name %s, removing...", groupname);
|
|
||||||
config_setting_remove_elem(groups, i);
|
|
||||||
--i;
|
|
||||||
--group_count;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
CREATE(group_settings, GroupSettings, 1);
|
|
||||||
group_settings->id = id;
|
|
||||||
group_settings->level = level;
|
|
||||||
group_settings->name = groupname;
|
|
||||||
group_settings->log_commands = log_commands != 0;
|
|
||||||
group_settings->inherit = config_setting_get_member(group, "inherit");
|
|
||||||
group_settings->commands = config_setting_get_member(group, "commands");
|
|
||||||
group_settings->permissions = config_setting_get_member(group, "permissions");
|
|
||||||
group_settings->inheritance_done = false;
|
|
||||||
group_settings->root = group;
|
|
||||||
group_settings->group_pos = i;
|
|
||||||
|
|
||||||
strdb_put(pc_groupname_db, groupname, group_settings);
|
|
||||||
idb_put(pc_group_db, id, group_settings);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
group_count = config_setting_length(groups); // Save number of groups
|
|
||||||
|
|
||||||
// Check if all commands and permissions exist
|
|
||||||
iter = db_iterator(pc_group_db);
|
|
||||||
for (group_settings = (GroupSettings *)dbi_first(iter); dbi_exists(iter); group_settings = (GroupSettings *)dbi_next(iter)) {
|
|
||||||
config_setting_t *commands = group_settings->commands, *permissions = group_settings->permissions;
|
|
||||||
int count = 0, j;
|
|
||||||
|
|
||||||
// Make sure there is "commands" group
|
if( !atcommand_exists( command.c_str() ) ){
|
||||||
if (commands == NULL)
|
this->invalidWarning( it, "Unknown atcommand: %s\n", command.c_str() );
|
||||||
commands = group_settings->commands = config_setting_add(group_settings->root, "commands", CONFIG_TYPE_GROUP);
|
return false;
|
||||||
count = config_setting_length(commands);
|
}
|
||||||
|
|
||||||
for (j = 0; j < count; ++j) {
|
util::tolower( command );
|
||||||
config_setting_t *command = config_setting_get_elem(commands, j);
|
|
||||||
const char *name = config_setting_name(command);
|
if( allowed ){
|
||||||
if (!atcommand_exists(name)) {
|
if( util::vector_exists( commands, command ) ){
|
||||||
ShowConfigWarning(command, "pc_groups:read_config: non-existent command name '%s', removing...", name);
|
this->invalidWarning( it, "Group already has command \"%s\". Please check your data.\n", command.c_str() );
|
||||||
config_setting_remove(commands, name);
|
return false;
|
||||||
--j;
|
}else{
|
||||||
--count;
|
commands.push_back( command );
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}else{
|
||||||
// Make sure there is "permissions" group
|
if( !util::vector_exists( commands, command ) ){
|
||||||
if (permissions == NULL)
|
this->invalidWarning( it, "Group does not have command \"%s\". Please check your data.\n", command.c_str() );
|
||||||
permissions = group_settings->permissions = config_setting_add(group_settings->root, "permissions", CONFIG_TYPE_GROUP);
|
return false;
|
||||||
count = config_setting_length(permissions);
|
}else{
|
||||||
|
util::vector_erase_if_exists( commands, command );
|
||||||
for(j = 0; j < count; ++j) {
|
|
||||||
config_setting_t *permission = config_setting_get_elem(permissions, j);
|
|
||||||
const char *name = config_setting_name(permission);
|
|
||||||
int p;
|
|
||||||
|
|
||||||
ARR_FIND(0, ARRAYLENGTH(pc_g_permission_name), p, strcmp(pc_g_permission_name[p].name, name) == 0);
|
|
||||||
if (p == ARRAYLENGTH(pc_g_permission_name)) {
|
|
||||||
ShowConfigWarning(permission, "pc_groups:read_config: non-existent permission name '%s', removing...", name);
|
|
||||||
config_setting_remove(permissions, name);
|
|
||||||
--p;
|
|
||||||
--count;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dbi_destroy(iter);
|
|
||||||
|
|
||||||
// Apply inheritance
|
|
||||||
i = 0; // counter for processed groups
|
|
||||||
while (i < group_count) {
|
|
||||||
iter = db_iterator(pc_group_db);
|
|
||||||
for (group_settings = (GroupSettings *)dbi_first(iter); dbi_exists(iter); group_settings = (GroupSettings *)dbi_next(iter)) {
|
|
||||||
config_setting_t *inherit = NULL,
|
|
||||||
*commands = group_settings->commands,
|
|
||||||
*permissions = group_settings->permissions;
|
|
||||||
int j, inherit_count = 0, done = 0;
|
|
||||||
|
|
||||||
if (group_settings->inheritance_done) // group already processed
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ((inherit = group_settings->inherit) == NULL ||
|
|
||||||
(inherit_count = config_setting_length(inherit)) <= 0) { // this group does not inherit from others
|
|
||||||
++i;
|
|
||||||
group_settings->inheritance_done = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (j = 0; j < inherit_count; ++j) {
|
|
||||||
GroupSettings *inherited_group = NULL;
|
|
||||||
const char *groupname = config_setting_get_string_elem(inherit, j);
|
|
||||||
|
|
||||||
if (groupname == NULL) {
|
|
||||||
ShowConfigWarning(inherit, "pc_groups:read_config: \"inherit\" array member #%d is not a name, removing...", j);
|
|
||||||
config_setting_remove_elem(inherit,j);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ((inherited_group = name2group(groupname)) == NULL) {
|
|
||||||
ShowConfigWarning(inherit, "pc_groups:read_config: non-existent group name \"%s\", removing...", groupname);
|
|
||||||
config_setting_remove_elem(inherit,j);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!inherited_group->inheritance_done)
|
|
||||||
continue; // we need to do that group first
|
|
||||||
|
|
||||||
// Copy settings (commands/permissions) that are not defined yet
|
|
||||||
if (inherited_group->commands != NULL) {
|
|
||||||
int l = 0, commands_count = config_setting_length(inherited_group->commands);
|
|
||||||
for (l = 0; l < commands_count; ++l)
|
|
||||||
config_setting_copy(commands, config_setting_get_elem(inherited_group->commands, l));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inherited_group->permissions != NULL) {
|
|
||||||
int l = 0, permissions_count = config_setting_length(inherited_group->permissions);
|
|
||||||
for (l = 0; l < permissions_count; ++l)
|
|
||||||
config_setting_copy(permissions, config_setting_get_elem(inherited_group->permissions, l));
|
|
||||||
}
|
|
||||||
|
|
||||||
++done; // copied commands and permissions from one of inherited groups
|
|
||||||
}
|
|
||||||
|
|
||||||
if (done == inherit_count) { // copied commands from all of inherited groups
|
|
||||||
++i;
|
|
||||||
group_settings->inheritance_done = true; // we're done with this group
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dbi_destroy(iter);
|
|
||||||
|
|
||||||
if (++loop > group_count) {
|
|
||||||
ShowWarning("pc_groups:read_config: Could not process inheritance rules, check your config '%s' for cycles...\n",
|
|
||||||
config_filename);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} // while(i < group_count)
|
|
||||||
|
|
||||||
// Pack permissions into GroupSettings.e_permissions for faster checking
|
|
||||||
iter = db_iterator(pc_group_db);
|
|
||||||
for (group_settings = (GroupSettings *)dbi_first(iter); dbi_exists(iter); group_settings = (GroupSettings *)dbi_next(iter)) {
|
|
||||||
config_setting_t *permissions = group_settings->permissions;
|
|
||||||
int c, count = config_setting_length(permissions);
|
|
||||||
|
|
||||||
for (c = 0; c < count; ++c) {
|
|
||||||
config_setting_t *perm = config_setting_get_elem(permissions, c);
|
|
||||||
const char *name = config_setting_name(perm);
|
|
||||||
int val = config_setting_get_bool(perm);
|
|
||||||
int j;
|
|
||||||
|
|
||||||
if (val == 0) // does not have this permission
|
|
||||||
continue;
|
|
||||||
ARR_FIND(0, ARRAYLENGTH(pc_g_permission_name), j, strcmp(pc_g_permission_name[j].name, name) == 0);
|
|
||||||
group_settings->e_permissions |= pc_g_permission_name[j].permission;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dbi_destroy(iter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ShowStatus("Done reading '" CL_WHITE "%d" CL_RESET "' groups in '" CL_WHITE "%s" CL_RESET "'.\n", group_count, config_filename);
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64 PlayerGroupDatabase::parseBodyNode( const ryml::NodeRef& node ){
|
||||||
if( ( pc_group_max = group_count ) ) {
|
uint32 groupId;
|
||||||
DBIterator *iter = db_iterator(pc_group_db);
|
|
||||||
GroupSettings *group_settings = NULL;
|
if( !this->asUInt32( node, "Id", groupId ) ){
|
||||||
int* group_ids = (int*)aMalloc( pc_group_max * sizeof(int) );
|
return 0;
|
||||||
int i = 0;
|
|
||||||
for (group_settings = (GroupSettings *)dbi_first(iter); dbi_exists(iter); group_settings = (GroupSettings *)dbi_next(iter)) {
|
|
||||||
group_ids[i++] = group_settings->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
atcommand_db_load_groups(group_ids);
|
|
||||||
|
|
||||||
aFree(group_ids);
|
|
||||||
|
|
||||||
dbi_destroy(iter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<s_player_group> group = this->find( groupId );
|
||||||
|
bool exists = group != nullptr;
|
||||||
|
|
||||||
|
if( !exists ){
|
||||||
|
if( !this->nodesExist( node, { "Name", "Level" })) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
group = std::make_shared<s_player_group>();
|
||||||
|
group->id = groupId;
|
||||||
|
group->permissions.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
if( this->nodeExists( node, "Name" ) ){
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
if( !this->asString( node, "Name", name ) ){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
group->name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( this->nodeExists( node, "Level" ) ){
|
||||||
|
uint32 level;
|
||||||
|
|
||||||
|
if( !this->asUInt32( node, "Level", level ) ){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (level > 99) {
|
||||||
|
this->invalidWarning(node["Level"], "Group level %u exceeds 99, capping.\n", level);
|
||||||
|
level = 99;
|
||||||
|
}
|
||||||
|
|
||||||
|
group->level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( this->nodeExists( node, "LogCommands" ) ){
|
||||||
|
bool log;
|
||||||
|
|
||||||
|
if( !this->asBool( node, "LogCommands", log ) ){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
group->log_commands = log;
|
||||||
|
}else{
|
||||||
|
if( !exists ){
|
||||||
|
group->log_commands = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( this->nodeExists( node, "Commands" ) && !this->parseCommands( node["Commands"], group->commands ) ){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( this->nodeExists( node, "CharCommands" ) && !this->parseCommands( node["CharCommands"], group->char_commands ) ){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( this->nodeExists( node, "Permissions" ) ){
|
||||||
|
const auto& permissions = node["Permissions"];
|
||||||
|
|
||||||
|
for( const auto& it : permissions ){
|
||||||
|
std::string permission;
|
||||||
|
|
||||||
|
c4::from_chars( it.key(), &permission );
|
||||||
|
|
||||||
|
bool allowed;
|
||||||
|
|
||||||
|
if( !this->asBool( permissions, permission, allowed ) ){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* str = permission.c_str();
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
for( const auto& permission_name : pc_g_permission_name ){
|
||||||
|
if( strcmpi( "all_permission", str ) == 0 ){
|
||||||
|
if( allowed ){
|
||||||
|
group->permissions.set();
|
||||||
|
}else{
|
||||||
|
group->permissions.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}else if( strcmpi( permission_name.name, str ) == 0 ){
|
||||||
|
if( allowed ){
|
||||||
|
group->permissions.set( permission_name.permission );
|
||||||
|
}else{
|
||||||
|
group->permissions.reset( permission_name.permission );
|
||||||
|
}
|
||||||
|
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !found ){
|
||||||
|
this->invalidWarning( it, "Unknown permission: %s\n", str );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( this->nodeExists( node, "Inherit" ) ){
|
||||||
|
const auto& inherits = node["Inherit"];
|
||||||
|
|
||||||
|
auto& inheritanceVector = this->inheritance[groupId];
|
||||||
|
|
||||||
|
for( const auto& it : inherits ){
|
||||||
|
std::string inherit;
|
||||||
|
|
||||||
|
c4::from_chars( it.key(), &inherit );
|
||||||
|
|
||||||
|
bool enable;
|
||||||
|
|
||||||
|
if( !this->asBool( inherits, inherit, enable ) ){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
util::tolower( inherit );
|
||||||
|
|
||||||
|
if( enable ){
|
||||||
|
if( !util::vector_exists( inheritanceVector, inherit ) ){
|
||||||
|
inheritanceVector.push_back( inherit );
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if( !util::vector_exists( inheritanceVector, inherit ) ){
|
||||||
|
this->invalidWarning( it, "Trying to remove inheritance of non-inherited group %s\n", inherit.c_str() );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
util::vector_erase_if_exists( inheritanceVector, inherit );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !exists ){
|
||||||
|
this->put( groupId, group );
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void PlayerGroupDatabase::loadingFinished(){
|
||||||
* Removes group configuration from memory.
|
static const int MAX_CYCLES = 10;
|
||||||
* @private
|
int i;
|
||||||
*/
|
|
||||||
static void destroy_config(void)
|
for( i = 0; i < MAX_CYCLES; i++ ){
|
||||||
{
|
auto inheritanceIt = this->inheritance.begin();
|
||||||
config_destroy(&pc_group_config);
|
|
||||||
|
while( inheritanceIt != this->inheritance.end() ){
|
||||||
|
auto& entry = *inheritanceIt;
|
||||||
|
|
||||||
|
if( entry.second.empty() ){
|
||||||
|
inheritanceIt = this->inheritance.erase( inheritanceIt );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<s_player_group> group = this->find( entry.first );
|
||||||
|
|
||||||
|
auto it = entry.second.begin();
|
||||||
|
|
||||||
|
while( it != entry.second.end() ){
|
||||||
|
std::string& otherName = *it;
|
||||||
|
bool found = false;
|
||||||
|
bool inherited = false;
|
||||||
|
|
||||||
|
for( const auto& it : *this ){
|
||||||
|
std::shared_ptr<s_player_group> otherGroup = it.second;
|
||||||
|
// Copy the string
|
||||||
|
std::string otherGroupName = otherGroup->name;
|
||||||
|
|
||||||
|
util::tolower( otherGroupName );
|
||||||
|
|
||||||
|
if( otherName == otherGroupName ){
|
||||||
|
found = true;
|
||||||
|
|
||||||
|
auto* otherGroupInheritance = util::map_find( this->inheritance, otherGroup->id );
|
||||||
|
|
||||||
|
if( otherGroupInheritance != nullptr && !otherGroupInheritance->empty() ){
|
||||||
|
// Try it again in the next cycle
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inherit atcommands
|
||||||
|
for( auto& command : otherGroup->commands ){
|
||||||
|
if( !util::vector_exists( group->commands, command ) ){
|
||||||
|
group->commands.push_back( command );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inherit charcommands
|
||||||
|
for( auto& command : otherGroup->char_commands ){
|
||||||
|
if( !util::vector_exists( group->char_commands, command ) ){
|
||||||
|
group->char_commands.push_back( command );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inherit permissions
|
||||||
|
group->permissions |= otherGroup->permissions;
|
||||||
|
|
||||||
|
inherited = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( inherited ){
|
||||||
|
it = entry.second.erase( it );
|
||||||
|
continue;
|
||||||
|
}else if( !found ){
|
||||||
|
ShowError( "Inherited group \"%s\" for group id %u does not exist.\n", otherName.c_str(), group->id );
|
||||||
|
it = entry.second.erase( it );
|
||||||
|
continue;
|
||||||
|
}else{
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( this->inheritance.empty() ){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( i == MAX_CYCLES && !this->inheritance.empty() ){
|
||||||
|
ShowError( "Could not process inheritance rules, check your config for cycles...\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not needed anymore
|
||||||
|
this->inheritance.clear();
|
||||||
|
|
||||||
|
uint32 index = 0;
|
||||||
|
for( auto& it : *this ){
|
||||||
|
it.second->index = index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize command cache
|
||||||
|
atcommand_db_load_groups();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
PlayerGroupDatabase player_group_db;
|
||||||
* In group configuration file, setting for each command is either
|
|
||||||
* <commandname> : <bool> (only atcommand), or
|
|
||||||
* <commandname> : [ <bool>, <bool> ] ([ atcommand, charcommand ])
|
|
||||||
* Maps AtCommandType enums to indexes of <commandname> value array,
|
|
||||||
* COMMAND_ATCOMMAND (1) being index 0, COMMAND_CHARCOMMAND (2) being index 1.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
static inline int AtCommandType2idx(AtCommandType type) { return (type-1); }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if player group can use @/#command
|
* Checks if player group can use @/#command
|
||||||
* @param group_id ID of the group
|
|
||||||
* @param command Command name without @/# and params
|
* @param command Command name without @/# and params
|
||||||
* @param type enum AtCommanndType { COMMAND_ATCOMMAND = 1, COMMAND_CHARCOMMAND = 2 }
|
* @param type enum AtCommanndType { COMMAND_ATCOMMAND = 1, COMMAND_CHARCOMMAND = 2 }
|
||||||
*/
|
*/
|
||||||
bool pc_group_can_use_command(int group_id, const char *command, AtCommandType type)
|
bool s_player_group::can_use_command( const std::string& command, AtCommandType type ){
|
||||||
{
|
if( this->has_permission( PC_PERM_USE_ALL_COMMANDS ) ){
|
||||||
int result = 0;
|
|
||||||
config_setting_t *commands = NULL;
|
|
||||||
GroupSettings *group = NULL;
|
|
||||||
|
|
||||||
if (pc_group_has_permission(group_id, PC_PERM_USE_ALL_COMMANDS))
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if ((group = id2group(group_id)) == NULL)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
commands = group->commands;
|
|
||||||
if (commands != NULL) {
|
|
||||||
config_setting_t *cmd = NULL;
|
|
||||||
|
|
||||||
// <commandname> : <bool> (only atcommand)
|
|
||||||
if (type == COMMAND_ATCOMMAND && config_setting_lookup_bool(commands, command, &result))
|
|
||||||
return result != 0;
|
|
||||||
|
|
||||||
// <commandname> : [ <bool>, <bool> ] ([ atcommand, charcommand ])
|
|
||||||
if ((cmd = config_setting_get_member(commands, command)) != NULL &&
|
|
||||||
config_setting_is_aggregate(cmd) && config_setting_length(cmd) == 2)
|
|
||||||
return config_setting_get_bool_elem(cmd, AtCommandType2idx(type)) != 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string command_lower = command;
|
||||||
|
|
||||||
|
util::tolower( command_lower );
|
||||||
|
|
||||||
|
switch( type ){
|
||||||
|
case COMMAND_ATCOMMAND:
|
||||||
|
return util::vector_exists( this->commands, command_lower );
|
||||||
|
case COMMAND_CHARCOMMAND:
|
||||||
|
return util::vector_exists( this->char_commands, command_lower );
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load permission for player based on group id
|
* Load permission for player based on group id
|
||||||
* @param sd Player
|
* @param sd Player
|
||||||
*/
|
*/
|
||||||
void pc_group_pc_load(struct map_session_data * sd) {
|
void pc_group_pc_load(struct map_session_data * sd) {
|
||||||
GroupSettings *group = NULL;
|
std::shared_ptr<s_player_group> group = player_group_db.find( sd->group_id );
|
||||||
if ((group = id2group(sd->group_id)) == NULL) {
|
|
||||||
|
if( group == nullptr ){
|
||||||
ShowWarning("pc_group_pc_load: %s (AID:%d) logged in with unknown group id (%d)! kicking...\n",
|
ShowWarning("pc_group_pc_load: %s (AID:%d) logged in with unknown group id (%d)! kicking...\n",
|
||||||
sd->status.name,
|
sd->status.name,
|
||||||
sd->status.account_id,
|
sd->status.account_id,
|
||||||
@ -357,108 +347,50 @@ void pc_group_pc_load(struct map_session_data * sd) {
|
|||||||
set_eof(sd->fd);
|
set_eof(sd->fd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sd->permissions = group->e_permissions;
|
|
||||||
sd->group_pos = group->group_pos;
|
sd->group = group;
|
||||||
sd->group_level = group->level;
|
sd->permissions = group->permissions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if player group has a permission
|
* Checks if player group has a permission
|
||||||
* @param group_id ID of the group
|
|
||||||
* @param permission permission to check
|
* @param permission permission to check
|
||||||
*/
|
*/
|
||||||
bool pc_group_has_permission(int group_id, int permission)
|
bool s_player_group::has_permission( e_pc_permission permission ){
|
||||||
{
|
return this->permissions.test( permission );
|
||||||
GroupSettings *group = NULL;
|
|
||||||
return (group = id2group(group_id)) == NULL ? false : (group->e_permissions&permission) != 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks commands used by player group should be logged
|
* Checks commands used by player group should be logged
|
||||||
* @param group_id ID of the group
|
|
||||||
*/
|
*/
|
||||||
bool pc_group_should_log_commands(int group_id)
|
bool s_player_group::should_log_commands(){
|
||||||
{
|
return this->log_commands;
|
||||||
GroupSettings *group = NULL;
|
|
||||||
return (group = id2group(group_id)) == NULL ? false : group->log_commands;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if player group with given ID exists.
|
* Initialize PC Groups and read config.
|
||||||
* @param group_id group id
|
|
||||||
* @returns true if group exists, false otherwise
|
|
||||||
*/
|
*/
|
||||||
bool pc_group_exists(int group_id)
|
void do_init_pc_groups( void ){
|
||||||
{
|
player_group_db.load();
|
||||||
return idb_exists(pc_group_db, group_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Group ID -> group name lookup. Used only in @who atcommands.
|
* Finalize PC Groups
|
||||||
* @param group_id group id
|
|
||||||
* @return group name
|
|
||||||
* @public
|
|
||||||
*/
|
*/
|
||||||
const char* pc_group_id2name(int group_id)
|
void do_final_pc_groups( void ){
|
||||||
{
|
player_group_db.clear();
|
||||||
GroupSettings *group = id2group(group_id);
|
|
||||||
if (group == NULL)
|
|
||||||
return "Non-existent group!";
|
|
||||||
return group->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Group ID -> group level lookup. A way to provide backward compatibility with GM level system.
|
|
||||||
* @param group id
|
|
||||||
* @return group level
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
int pc_group_id2level(int group_id)
|
|
||||||
{
|
|
||||||
GroupSettings *group = id2group(group_id);
|
|
||||||
if (group == NULL)
|
|
||||||
return 0;
|
|
||||||
return group->level;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize PC Groups: allocate DBMaps and read config.
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
void do_init_pc_groups(void)
|
|
||||||
{
|
|
||||||
pc_group_db = idb_alloc(DB_OPT_RELEASE_DATA);
|
|
||||||
pc_groupname_db = stridb_alloc(DB_OPT_DUP_KEY, 0);
|
|
||||||
read_config();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finalize PC Groups: free DBMaps and config.
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
void do_final_pc_groups(void)
|
|
||||||
{
|
|
||||||
if (pc_group_db != NULL)
|
|
||||||
db_destroy(pc_group_db);
|
|
||||||
if (pc_groupname_db != NULL )
|
|
||||||
db_destroy(pc_groupname_db);
|
|
||||||
destroy_config();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reload PC Groups
|
* Reload PC Groups
|
||||||
* Used in @reloadatcommand
|
* Used in @reloadatcommand
|
||||||
* @public
|
|
||||||
*/
|
*/
|
||||||
void pc_groups_reload(void) {
|
void pc_groups_reload( void ){
|
||||||
struct map_session_data* sd = NULL;
|
player_group_db.reload();
|
||||||
struct s_mapiterator* iter;
|
|
||||||
|
|
||||||
do_final_pc_groups();
|
|
||||||
do_init_pc_groups();
|
|
||||||
|
|
||||||
/* refresh online users permissions */
|
/* refresh online users permissions */
|
||||||
iter = mapit_getallusers();
|
struct s_mapiterator* iter = mapit_getallusers();
|
||||||
for (sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter)) {
|
for( struct map_session_data* sd = (struct map_session_data*)mapit_first(iter); mapit_exists(iter); sd = (struct map_session_data*)mapit_next(iter) ){
|
||||||
pc_group_pc_load(sd);
|
pc_group_pc_load(sd);
|
||||||
}
|
}
|
||||||
mapit_free(iter);
|
mapit_free(iter);
|
||||||
|
@ -4,62 +4,58 @@
|
|||||||
#ifndef PC_GROUPS_HPP
|
#ifndef PC_GROUPS_HPP
|
||||||
#define PC_GROUPS_HPP
|
#define PC_GROUPS_HPP
|
||||||
|
|
||||||
#include "../common/cbasetypes.hpp"
|
#include <bitset>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "../common/cbasetypes.hpp"
|
||||||
|
#include "../common/database.hpp"
|
||||||
|
|
||||||
|
// Forward declaration from atcommands.hpp
|
||||||
enum AtCommandType : uint8;
|
enum AtCommandType : uint8;
|
||||||
|
|
||||||
extern int pc_group_max;
|
|
||||||
|
|
||||||
bool pc_group_exists(int group_id);
|
|
||||||
bool pc_group_can_use_command(int group_id, const char *command, AtCommandType type);
|
|
||||||
bool pc_group_has_permission(int group_id, int permission);
|
|
||||||
bool pc_group_should_log_commands(int group_id);
|
|
||||||
const char* pc_group_id2name(int group_id);
|
|
||||||
int pc_group_id2level(int group_id);
|
|
||||||
void pc_group_pc_load(struct map_session_data *sd);
|
void pc_group_pc_load(struct map_session_data *sd);
|
||||||
|
|
||||||
void do_init_pc_groups(void);
|
void do_init_pc_groups(void);
|
||||||
void do_final_pc_groups(void);
|
void do_final_pc_groups(void);
|
||||||
void pc_groups_reload(void);
|
void pc_groups_reload(void);
|
||||||
|
|
||||||
enum e_pc_permission : uint32 {
|
enum e_pc_permission : uint32 {
|
||||||
PC_PERM_NONE = 0,
|
PC_PERM_TRADE = 0,
|
||||||
PC_PERM_TRADE = 0x00000001,
|
PC_PERM_PARTY,
|
||||||
PC_PERM_PARTY = 0x00000002,
|
PC_PERM_ALL_SKILL,
|
||||||
PC_PERM_ALL_SKILL = 0x00000004,
|
PC_PERM_USE_ALL_EQUIPMENT,
|
||||||
PC_PERM_USE_ALL_EQUIPMENT = 0x00000008,
|
PC_PERM_SKILL_UNCONDITIONAL,
|
||||||
PC_PERM_SKILL_UNCONDITIONAL = 0x00000010,
|
PC_PERM_JOIN_ALL_CHAT,
|
||||||
PC_PERM_JOIN_ALL_CHAT = 0x00000020,
|
PC_PERM_NO_CHAT_KICK,
|
||||||
PC_PERM_NO_CHAT_KICK = 0x00000040,
|
PC_PERM_HIDE_SESSION,
|
||||||
PC_PERM_HIDE_SESSION = 0x00000080,
|
PC_PERM_WHO_DISPLAY_AID,
|
||||||
PC_PERM_WHO_DISPLAY_AID = 0x00000100,
|
PC_PERM_RECEIVE_HACK_INFO,
|
||||||
PC_PERM_RECEIVE_HACK_INFO = 0x00000200,
|
PC_PERM_WARP_ANYWHERE,
|
||||||
PC_PERM_WARP_ANYWHERE = 0x00000400,
|
PC_PERM_VIEW_HPMETER,
|
||||||
PC_PERM_VIEW_HPMETER = 0x00000800,
|
PC_PERM_VIEW_EQUIPMENT,
|
||||||
PC_PERM_VIEW_EQUIPMENT = 0x00001000,
|
PC_PERM_USE_CHECK,
|
||||||
PC_PERM_USE_CHECK = 0x00002000,
|
PC_PERM_USE_CHANGEMAPTYPE,
|
||||||
PC_PERM_USE_CHANGEMAPTYPE = 0x00004000,
|
PC_PERM_USE_ALL_COMMANDS,
|
||||||
PC_PERM_USE_ALL_COMMANDS = 0x00008000,
|
PC_PERM_RECEIVE_REQUESTS,
|
||||||
PC_PERM_RECEIVE_REQUESTS = 0x00010000,
|
PC_PERM_SHOW_BOSS,
|
||||||
PC_PERM_SHOW_BOSS = 0x00020000,
|
PC_PERM_DISABLE_PVM,
|
||||||
PC_PERM_DISABLE_PVM = 0x00040000,
|
PC_PERM_DISABLE_PVP,
|
||||||
PC_PERM_DISABLE_PVP = 0x00080000,
|
PC_PERM_DISABLE_CMD_DEAD,
|
||||||
PC_PERM_DISABLE_CMD_DEAD = 0x00100000,
|
PC_PERM_CHANNEL_ADMIN,
|
||||||
PC_PERM_CHANNEL_ADMIN = 0x00200000,
|
PC_PERM_TRADE_BOUNDED,
|
||||||
PC_PERM_TRADE_BOUNDED = 0x00400000,
|
PC_PERM_ITEM_UNCONDITIONAL,
|
||||||
PC_PERM_ITEM_UNCONDITIONAL = 0x00800000,
|
PC_PERM_ENABLE_COMMAND,
|
||||||
PC_PERM_ENABLE_COMMAND = 0x01000000,
|
PC_PERM_BYPASS_STAT_ONCLONE,
|
||||||
PC_PERM_BYPASS_STAT_ONCLONE = 0x02000000,
|
PC_PERM_BYPASS_MAX_STAT,
|
||||||
PC_PERM_BYPASS_MAX_STAT = 0x04000000,
|
PC_PERM_ATTENDANCE,
|
||||||
PC_PERM_ATTENDANCE = 0x08000000,
|
|
||||||
//.. add other here
|
//.. add other here
|
||||||
PC_PERM_ALLPERMISSION = 0xFFFFFFFF,
|
PC_PERM_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct s_pcg_permission_name {
|
static const struct s_pcg_permission_name {
|
||||||
const char *name;
|
const char *name;
|
||||||
enum e_pc_permission permission;
|
enum e_pc_permission permission;
|
||||||
} pc_g_permission_name[] = {
|
} pc_g_permission_name[PC_PERM_MAX] = {
|
||||||
{ "can_trade", PC_PERM_TRADE },
|
{ "can_trade", PC_PERM_TRADE },
|
||||||
{ "can_party", PC_PERM_PARTY },
|
{ "can_party", PC_PERM_PARTY },
|
||||||
{ "all_skill", PC_PERM_ALL_SKILL },
|
{ "all_skill", PC_PERM_ALL_SKILL },
|
||||||
@ -88,7 +84,39 @@ static const struct s_pcg_permission_name {
|
|||||||
{ "bypass_stat_onclone",PC_PERM_BYPASS_STAT_ONCLONE },
|
{ "bypass_stat_onclone",PC_PERM_BYPASS_STAT_ONCLONE },
|
||||||
{ "bypass_max_stat",PC_PERM_BYPASS_MAX_STAT },
|
{ "bypass_max_stat",PC_PERM_BYPASS_MAX_STAT },
|
||||||
{ "attendance",PC_PERM_ATTENDANCE },
|
{ "attendance",PC_PERM_ATTENDANCE },
|
||||||
{ "all_permission", PC_PERM_ALLPERMISSION },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct s_player_group{
|
||||||
|
uint32 id;
|
||||||
|
std::string name;
|
||||||
|
uint32 level;
|
||||||
|
bool log_commands;
|
||||||
|
std::vector<std::string> commands;
|
||||||
|
std::vector<std::string> char_commands;
|
||||||
|
std::bitset<PC_PERM_MAX> permissions;
|
||||||
|
uint32 index;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool can_use_command( const std::string& command, AtCommandType type );
|
||||||
|
bool has_permission( e_pc_permission permission );
|
||||||
|
bool should_log_commands();
|
||||||
|
};
|
||||||
|
|
||||||
|
class PlayerGroupDatabase : public TypesafeYamlDatabase<uint32, s_player_group>{
|
||||||
|
private:
|
||||||
|
std::map<uint32, std::vector<std::string>> inheritance;
|
||||||
|
bool parseCommands( const ryml::NodeRef& node, std::vector<std::string>& commands );
|
||||||
|
|
||||||
|
public:
|
||||||
|
PlayerGroupDatabase() : TypesafeYamlDatabase( "PLAYER_GROUP_DB", 1 ){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string getDefaultLocation() override;
|
||||||
|
uint64 parseBodyNode( const ryml::NodeRef& node ) override;
|
||||||
|
void loadingFinished() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern PlayerGroupDatabase player_group_db;
|
||||||
|
|
||||||
#endif /* PC_GROUPS_HPP */
|
#endif /* PC_GROUPS_HPP */
|
||||||
|
@ -5833,7 +5833,7 @@ BUILDIN_FUNC(warpparty)
|
|||||||
}
|
}
|
||||||
// Fall through
|
// Fall through
|
||||||
case WARPPARTY_RANDOMALLAREA:
|
case WARPPARTY_RANDOMALLAREA:
|
||||||
if(!mapdata->flag[MF_NORETURN] && !mapdata->flag[MF_NOWARP] && pc_job_can_entermap((enum e_job)pl_sd->status.class_, m, pl_sd->group_level)){
|
if(!mapdata->flag[MF_NORETURN] && !mapdata->flag[MF_NOWARP] && pc_job_can_entermap((enum e_job)pl_sd->status.class_, m, pc_get_group_level(pl_sd))){
|
||||||
if (rx || ry) {
|
if (rx || ry) {
|
||||||
int x1 = x + rx, y1 = y + ry,
|
int x1 = x + rx, y1 = y + ry,
|
||||||
x0 = x - rx, y0 = y - ry,
|
x0 = x - rx, y0 = y - ry,
|
||||||
@ -5853,7 +5853,7 @@ BUILDIN_FUNC(warpparty)
|
|||||||
|
|
||||||
ret = pc_setpos(pl_sd, mapindex, x, y, CLR_TELEPORT);
|
ret = pc_setpos(pl_sd, mapindex, x, y, CLR_TELEPORT);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ret != SETPOS_OK ) {
|
if( ret != SETPOS_OK ) {
|
||||||
@ -5929,7 +5929,7 @@ BUILDIN_FUNC(warpguild)
|
|||||||
pc_setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
|
pc_setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
|
||||||
break;
|
break;
|
||||||
case 3: // m,x,y
|
case 3: // m,x,y
|
||||||
if(!map_getmapflag(pl_sd->bl.m, MF_NORETURN) && !map_getmapflag(pl_sd->bl.m, MF_NOWARP) && pc_job_can_entermap((enum e_job)pl_sd->status.class_, m, pl_sd->group_level))
|
if(!map_getmapflag(pl_sd->bl.m, MF_NORETURN) && !map_getmapflag(pl_sd->bl.m, MF_NOWARP) && pc_job_can_entermap((enum e_job)pl_sd->status.class_, m, pc_get_group_level(pl_sd)))
|
||||||
pc_setpos(pl_sd,mapindex,x,y,CLR_TELEPORT);
|
pc_setpos(pl_sd,mapindex,x,y,CLR_TELEPORT);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -15205,8 +15205,8 @@ int atcommand_sub(struct script_state* st,int type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Init Group ID, Level, & permissions
|
// Init Group ID, Level, & permissions
|
||||||
sd->group_id = sd->group_level = 99;
|
sd->group_id = 99;
|
||||||
sd->permissions |= PC_PERM_ALLPERMISSION;
|
pc_group_pc_load( sd );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_atcommand(fd, sd, cmd, type)) {
|
if (!is_atcommand(fd, sd, cmd, type)) {
|
||||||
@ -24100,7 +24100,7 @@ BUILDIN_FUNC(jobcanentermap) {
|
|||||||
jobid = sd->status.class_;
|
jobid = sd->status.class_;
|
||||||
}
|
}
|
||||||
|
|
||||||
script_pushint(st, pc_job_can_entermap((enum e_job)jobid, m, sd ? sd->group_level : 0));
|
script_pushint(st, pc_job_can_entermap((enum e_job)jobid, m, sd ? pc_get_group_level(sd) : 0));
|
||||||
return SCRIPT_CMD_SUCCESS;
|
return SCRIPT_CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10100,7 +10100,7 @@ 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 ((dstsd = g->member[i].sd) != NULL && sd != dstsd && !dstsd->state.autotrade && !pc_isdead(dstsd)) {
|
||||||
if (map_getmapflag(dstsd->bl.m, MF_NOWARP) && !map_flag_gvg2(dstsd->bl.m))
|
if (map_getmapflag(dstsd->bl.m, MF_NOWARP) && !map_flag_gvg2(dstsd->bl.m))
|
||||||
continue;
|
continue;
|
||||||
if (!pc_job_can_entermap((enum e_job)dstsd->status.class_, src->m, dstsd->group_level))
|
if (!pc_job_can_entermap((enum e_job)dstsd->status.class_, src->m, pc_get_group_level(dstsd)))
|
||||||
continue;
|
continue;
|
||||||
if(map_getcell(src->m,src->x+dx[j],src->y+dy[j],CELL_CHKNOREACH))
|
if(map_getcell(src->m,src->x+dx[j],src->y+dy[j],CELL_CHKNOREACH))
|
||||||
dx[j] = dy[j] = 0;
|
dx[j] = dy[j] = 0;
|
||||||
@ -14990,7 +14990,7 @@ static int skill_unit_onplace(struct skill_unit *unit, struct block_list *bl, t_
|
|||||||
|
|
||||||
sg->val1 = (count<<16)|working;
|
sg->val1 = (count<<16)|working;
|
||||||
|
|
||||||
if (pc_job_can_entermap((enum e_job)sd->status.class_, map_mapindex2mapid(m), sd->group_level))
|
if (pc_job_can_entermap((enum e_job)sd->status.class_, map_mapindex2mapid(m), pc_get_group_level(sd)))
|
||||||
pc_setpos(sd,m,x,y,CLR_TELEPORT);
|
pc_setpos(sd,m,x,y,CLR_TELEPORT);
|
||||||
}
|
}
|
||||||
} else if(bl->type == BL_MOB && battle_config.mob_warp&2) {
|
} else if(bl->type == BL_MOB && battle_config.mob_warp&2) {
|
||||||
@ -20542,13 +20542,13 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap)
|
|||||||
if(group->val1) {
|
if(group->val1) {
|
||||||
sd = map_charid2sd(group->val1);
|
sd = map_charid2sd(group->val1);
|
||||||
group->val1 = 0;
|
group->val1 = 0;
|
||||||
if (sd && !map_getmapflag(sd->bl.m, MF_NOWARP) && pc_job_can_entermap((enum e_job)sd->status.class_, unit->bl.m, sd->group_level))
|
if (sd && !map_getmapflag(sd->bl.m, MF_NOWARP) && pc_job_can_entermap((enum e_job)sd->status.class_, unit->bl.m, pc_get_group_level(sd)))
|
||||||
pc_setpos(sd,map_id2index(unit->bl.m),unit->bl.x,unit->bl.y,CLR_TELEPORT);
|
pc_setpos(sd,map_id2index(unit->bl.m),unit->bl.x,unit->bl.y,CLR_TELEPORT);
|
||||||
}
|
}
|
||||||
if(group->val2) {
|
if(group->val2) {
|
||||||
sd = map_charid2sd(group->val2);
|
sd = map_charid2sd(group->val2);
|
||||||
group->val2 = 0;
|
group->val2 = 0;
|
||||||
if (sd && !map_getmapflag(sd->bl.m, MF_NOWARP) && pc_job_can_entermap((enum e_job)sd->status.class_, unit->bl.m, sd->group_level))
|
if (sd && !map_getmapflag(sd->bl.m, MF_NOWARP) && pc_job_can_entermap((enum e_job)sd->status.class_, unit->bl.m, pc_get_group_level(sd)))
|
||||||
pc_setpos(sd,map_id2index(unit->bl.m),unit->bl.x,unit->bl.y,CLR_TELEPORT);
|
pc_setpos(sd,map_id2index(unit->bl.m),unit->bl.x,unit->bl.y,CLR_TELEPORT);
|
||||||
}
|
}
|
||||||
skill_delunit(unit);
|
skill_delunit(unit);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user