2014 Client Support
* Implemented the Roulette Game feature. * Implemented per-character sex change feature. * More info: https://rathena.org/board/topic/102247-2014-client-support/ - Special thanks to HerculesWS/Hercules@239d480 for the base.
This commit is contained in:
parent
5cb90cd1d0
commit
3d9c6e7763
@ -57,3 +57,8 @@ feature.autotrade_sit: 1
|
||||
|
||||
// Delay in miliseconds to open vending/buyingsotre after player logged in.
|
||||
feature.autotrade_open_delay: 5000
|
||||
|
||||
// Roulette (Note 1)
|
||||
// Requires: 2014-10-22bRagexe or later
|
||||
// Off by default while test version is out; enable at your own risk.
|
||||
feature.roulette: off
|
||||
|
@ -139,6 +139,7 @@ mapreg_db: mapreg
|
||||
vending_db: vendings
|
||||
vending_items_db: vending_items
|
||||
market_table: market
|
||||
db_roulette_table: db_roulette
|
||||
|
||||
// Use SQL item_db, mob_db and mob_skill_db for the map server? (yes/no)
|
||||
use_sql_db: no
|
||||
|
@ -8,31 +8,32 @@
|
||||
//--------------------------------------------------------------
|
||||
|
||||
// Enable Logs? (Note 3)
|
||||
// 0x00000 - Don't log at all
|
||||
// 0x00001 - (T) Log trades
|
||||
// 0x00002 - (V) Log vending transactions
|
||||
// 0x00004 - (P) Log items drop/picked by players
|
||||
// 0x00008 - (L) Log items drop/looted by monsters
|
||||
// 0x00010 - (S) Log NPC transactions (buy/sell)
|
||||
// 0x00020 - (N) Log Script transactions (items deleted/acquired through quests)
|
||||
// 0x00040 - (D) Log items stolen from mobs (Steal/Gank)
|
||||
// 0x00080 - (C) Log player-used items (consumables/pet&hom&merc food/items used for skills&attacks)
|
||||
// 0x00100 - (O) Log produced/ingredient items
|
||||
// 0x00200 - (U) Log MVP prize items
|
||||
// 0x00400 - (A) Log player created/deleted items (through @/# commands)
|
||||
// 0x00800 - (R) Log items placed/retrieved from storage.
|
||||
// 0x01000 - (G) Log items placed/retrieved from guild storage.
|
||||
// 0x02000 - (E) Log mail system transactions.
|
||||
// 0x04000 - (I) Log auction system transactions.
|
||||
// 0x08000 - (B) Log buying store transactions
|
||||
// 0x10000 - (X) Log all other transactions (rentals expiring/inserting cards/items removed by item_check/
|
||||
// 0x000000 - Don't log at all
|
||||
// 0x000001 - (T) Log trades
|
||||
// 0x000002 - (V) Log vending transactions
|
||||
// 0x000004 - (P) Log items drop/picked by players
|
||||
// 0x000008 - (L) Log items drop/looted by monsters
|
||||
// 0x000010 - (S) Log NPC transactions (buy/sell)
|
||||
// 0x000020 - (N) Log Script transactions (items deleted/acquired through quests)
|
||||
// 0x000040 - (D) Log items stolen from mobs (Steal/Gank)
|
||||
// 0x000080 - (C) Log player-used items (consumables/pet&hom&merc food/items used for skills&attacks)
|
||||
// 0x000100 - (O) Log produced/ingredient items
|
||||
// 0x000200 - (U) Log MVP prize items
|
||||
// 0x000400 - (A) Log player created/deleted items (through @/# commands)
|
||||
// 0x000800 - (R) Log items placed/retrieved from storage.
|
||||
// 0x001000 - (G) Log items placed/retrieved from guild storage.
|
||||
// 0x002000 - (E) Log mail system transactions.
|
||||
// 0x004000 - (I) Log auction system transactions.
|
||||
// 0x008000 - (B) Log buying store transactions
|
||||
// 0x010000 - (X) Log all other transactions (rentals expiring/inserting cards/items removed by item_check/
|
||||
// rings deleted by divorce/pet egg (un)hatching/pet armor (un)equipping/Weapon Refine skill/Remove Trap skill)
|
||||
// 0x20000 - ($) Log cash transactions
|
||||
// 0x40000 - (K) Log account bank transactions
|
||||
// 0x80000 - (F) Removed bound items when guild/party is broken
|
||||
// 0x020000 - ($) Log cash transactions
|
||||
// 0x040000 - (K) Log account bank transactions
|
||||
// 0x080000 - (F) Removed bound items when guild/party is broken
|
||||
// 0x100000 - (Y) Roulette Lottery
|
||||
// Example: Log trades+vending+script items+created items: 1+2+32+1024 = 1059
|
||||
// Please note that moving items from inventory to cart and back is not logged by design.
|
||||
enable_logs: 0xFFFFF
|
||||
enable_logs: 0xFFFFFF
|
||||
|
||||
// Use MySQL Logs? [SQL Version Only] (Note 1)
|
||||
sql_logs: yes
|
||||
|
@ -1593,5 +1593,8 @@
|
||||
1495: You can't withdraw that much money
|
||||
1496: Banking is disabled
|
||||
|
||||
// Roulette
|
||||
1497: Roulette is disabled
|
||||
|
||||
//Custom translations
|
||||
//import: conf/msg_conf/import/map_msg_eng_conf.txt
|
||||
|
@ -432,6 +432,9 @@ CharMoves 124 1
|
||||
CharRename 125 1
|
||||
Font 126 1
|
||||
BankVault 127 1
|
||||
RouletteBronze 128 1
|
||||
RouletteSilver 129 1
|
||||
RouletteGold 130 1
|
||||
|
||||
bMaxHP 6
|
||||
bMaxSP 8
|
||||
|
@ -2318,5 +2318,82 @@ packet_keys: 0x631C511C,0x111C111C,0x111C111C // [Shakto]
|
||||
0x09D8,2,npcmarketclosed,0
|
||||
0x09DF,7
|
||||
|
||||
//2014-10-16Ragexe
|
||||
packet_ver: 50
|
||||
0x0369,7,actionrequest,2,6
|
||||
0x083C,10,useskilltoid,2,4,6
|
||||
0x0437,5,walktoxy,2
|
||||
0x035F,6,ticksend,2
|
||||
0x0967,5,changedir,2,4
|
||||
0x07E4,6,takeitem,2
|
||||
0x0362,6,dropitem,2,4
|
||||
0x07EC,8,movetokafra,2,4
|
||||
0x022D,8,movefromkafra,2,4
|
||||
0x0438,10,useskilltopos,2,4,6,8
|
||||
0x0366,90,useskilltoposinfo,2,4,6,8,10
|
||||
0x096A,6,getcharnamerequest,2
|
||||
0x0368,6,solvecharname,2
|
||||
0x0838,12,searchstoreinfolistitemclick,2,6,10
|
||||
0x0835,2,searchstoreinfonextpage,0
|
||||
0x0819,-1,searchstoreinfo,2,4,5,9,13,14,15
|
||||
0x0811,-1,reqtradebuyingstore,2,4,8,12
|
||||
0x0360,6,reqclickbuyingstore,2
|
||||
0x0817,2,reqclosebuyingstore,0
|
||||
0x0815,-1,reqopenbuyingstore,2,4,8,9,89
|
||||
0x0365,18,bookingregreq,2,4
|
||||
// 0x0363,8 // CZ_JOIN_BATTLE_FIELD
|
||||
0x0281,-1,itemlistwindowselected,2,4,8
|
||||
0x086E,19,wanttoconnection,2,6,10,14,18
|
||||
0x0802,26,partyinvite,2
|
||||
// 0x0922,4 // CZ_GANGSI_RANK
|
||||
0x094B,26,friendslistadd,2
|
||||
0x0364,5,hommenu,2,4
|
||||
0x0936,36,storagepassword,0
|
||||
0x09DF,7
|
||||
0x0a00,269
|
||||
// Roulette System [Yommy]
|
||||
0x0A19,2,rouletteopen,0 // HEADER_CZ_REQ_OPEN_ROULETTE
|
||||
0x0A1A,23 // HEADER_ZC_ACK_OPEN_ROULETTE
|
||||
0x0A1B,2,rouletteinfo,0 // HEADER_CZ_REQ_ROULETTE_INFO
|
||||
0x0A1C,-1 // HEADER_ZC_ACK_ROULETTE_INFO
|
||||
0x0A1D,2,rouletteclose,0 // HEADER_CZ_REQ_CLOSE_ROULETTE
|
||||
0x0A1E,3 // HEADER_ZC_ACK_CLOSE_ROULETTE
|
||||
0x0A1F,2,roulettegenerate,0 // HEADER_CZ_REQ_GENERATE_ROULETTE
|
||||
0x0A20,21 // HEADER_ZC_ACK_GENERATE_ROULETTE
|
||||
0x0A21,3,rouletterecvitem,2 // HEADER_CZ_RECV_ROULETTE_ITEM
|
||||
0x0A22,5 // HEADER_ZC_RECV_ROULETTE_ITEM
|
||||
|
||||
//2014-10-22bRagexe
|
||||
packet_ver: 51
|
||||
0x0369,7,actionrequest,2,6
|
||||
0x083C,10,useskilltoid,2,4,6
|
||||
0x0437,5,walktoxy,2
|
||||
0x035F,6,ticksend,2
|
||||
0x08AD,5,changedir,2,4
|
||||
0x094E,6,takeitem,2
|
||||
0x087D,6,dropitem,2,4
|
||||
0x0878,8,movetokafra,2,4
|
||||
0x08AA,8,movefromkafra,2,4
|
||||
0x023B,10,useskilltopos,2,4,6,8
|
||||
0x0366,90,useskilltoposinfo,2,4,6,8,10
|
||||
0x096A,6,getcharnamerequest,2
|
||||
0x0368,6,solvecharname,2
|
||||
0x0835,12,searchstoreinfolistitemclick,2,6,10
|
||||
0x0940,2,searchstoreinfonextpage,0
|
||||
0x0819,-1,searchstoreinfo,2,4,5,9,13,14,15
|
||||
0x0811,-1,reqtradebuyingstore,2,4,8,12
|
||||
0x0360,6,reqclickbuyingstore,2
|
||||
0x0817,2,reqclosebuyingstore,0
|
||||
0x0815,-1,reqopenbuyingstore,2,4,8,9,89
|
||||
0x0955,18,bookingregreq,2,4
|
||||
// 0x092B,8 // CZ_JOIN_BATTLE_FIELD
|
||||
0x0281,-1,itemlistwindowselected,2,4,8
|
||||
0x093B,19,wanttoconnection,2,6,10,14,18
|
||||
0x0896,26,partyinvite,2
|
||||
// 0x08AB,4 // CZ_GANGSI_RANK
|
||||
0x091A,26,friendslistadd,2
|
||||
0x0899,5,hommenu,2,4
|
||||
0x0438,36,storagepassword,0
|
||||
|
||||
//Add new packets here
|
||||
//packet_ver: 47
|
||||
//packet_ver: 52
|
||||
|
@ -165,11 +165,11 @@
|
||||
668,Handsei,Red Envelope,2,0,,20,,,,,0xFFFFFFFF,63,2,,,,,,{ set Zeny,Zeny+rand(1000,10000); },{},{}
|
||||
669,Rice_Cake_Soup,Tempting Rice-Cake Soup,0,500,,100,,,,,0xFFFFFFFF,63,2,,,,,,{ percentheal -100,-100; },{},{}
|
||||
670,Gold_Coin_Moneybag,Bag of Gold Coins,3,100000,,400,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
|
||||
671,Gold_Coin,Gold Coin,3,10000,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ /*goldpoint++; (For Roulette game)*/ },{},{}
|
||||
671,Gold_Coin,Gold Coin,3,10000,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ RouletteGold++; },{},{}
|
||||
672,Copper_Coin_Moneybag,Bag of Bronze Coins,3,1000,,400,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
|
||||
673,Copper_Coin,Bronze Coin,3,100,,40,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
|
||||
673,Copper_Coin,Bronze Coin,3,100,,40,,,,,0xFFFFFFFF,63,2,,,,,,{ RouletteBronze++; },{},{}
|
||||
674,Mithril_Coin,Mithril Coin,3,5000,,40,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
|
||||
675,Silver_Coin,Silver Coin,3,5000,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ /*silverpoint++; (For Roulette game)*/ },{},{}
|
||||
675,Silver_Coin,Silver Coin,3,5000,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ RouletteSilver++; },{},{}
|
||||
676,Silver_Coin_Moneybag,Bag of Silver Coins,3,50000,,400,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
|
||||
677,White_Gold_Coin,Platinum Coin,3,2000,,40,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
|
||||
678,Poison_Bottle,Poison Bottle,2,5000,,100,,,,,0xFFFFFFFF,63,2,,,,,,{ if(Class == Job_Assassin_Cross || Class == Job_Guillotine_Cross || Class == Job_Guillotine_Cross_T) { sc_start SC_DPOISON,60000,0; sc_start SC_ASPDPOTION3,60000,9; } else percentheal -100,-100; },{},{}
|
||||
|
@ -4169,6 +4169,20 @@ they will also have their skills reset upon 'changesex'.
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*changecharsex({<char_id>});
|
||||
|
||||
This command will change the gender of the attached character. If it
|
||||
was male, it will become female, if it was female, it will become male. The
|
||||
change will be written to the character server, the player will receive the
|
||||
message: "Need disconnection to perform change-sex request..." and the player
|
||||
will be immediately kicked to the login screen. When they log back in, they will
|
||||
be the opposite sex.
|
||||
|
||||
If the character being changed is a Dancer/Gypsy or Bard/Clown class type,
|
||||
the character will also have their skills reset upon 'changecharsex'.
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*getexp <base xp>,<job xp>{,<char_id>};
|
||||
|
||||
This command will give the invoking character a specified number of base and job
|
||||
|
@ -125,6 +125,7 @@ CREATE TABLE IF NOT EXISTS `char` (
|
||||
`unban_time` int(11) unsigned NOT NULL default '0',
|
||||
`font` tinyint(3) unsigned NOT NULL default '0',
|
||||
`uniqueitem_counter` int(11) unsigned NOT NULL default '0',
|
||||
`sex` ENUM('M','F','U') NOT NULL default 'U',
|
||||
PRIMARY KEY (`char_id`),
|
||||
UNIQUE KEY `name_key` (`name`),
|
||||
KEY `account_id` (`account_id`),
|
||||
@ -637,6 +638,71 @@ CREATE TABLE IF NOT EXISTS `ragsrvinfo` (
|
||||
`drop` int(11) unsigned NOT NULL default '0'
|
||||
) ENGINE=MyISAM;
|
||||
|
||||
--
|
||||
-- Table structure for `db_roulette`
|
||||
--
|
||||
CREATE TABLE `db_roulette` (
|
||||
`level` smallint(5) unsigned NOT NULL,
|
||||
`item_id` smallint(5) unsigned NOT NULL,
|
||||
`amount` smallint(5) unsigned NOT NULL DEFAULT '1',
|
||||
`flag` smallint(5) unsigned NOT NULL DEFAULT '1',
|
||||
PRIMARY KEY (`level`,`item_id`)
|
||||
) ENGINE=MyISAM;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of db_roulette
|
||||
-- ----------------------------
|
||||
-- Info: http://ro.gnjoy.com/news/update/View.asp?seq=157&curpage=1
|
||||
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 1, 675, 1, 1 ); -- Silver_Coin
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 1, 671, 1, 0 ); -- Gold_Coin
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 1, 678, 1, 0 ); -- Poison_Bottle
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 1, 604, 1, 0 ); -- Branch_Of_Dead_Tree
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 1, 522, 1, 0 ); -- Fruit_Of_Mastela
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 1, 671, 1, 0 ); -- Old_Ore_Box
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 1, 12523, 1, 0 ); -- E_Inc_Agi_10_Scroll
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 1, 985, 1, 0 ); -- Elunium
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 1, 984, 1, 0 ); -- Oridecon
|
||||
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 2, 675, 1, 1 ); -- Silver_Coin
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 2, 671, 1, 0 ); -- Gold_Coin
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 2, 603, 1, 0 ); -- Old_Blue_Box
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 2, 608, 1, 0 ); -- Seed_Of_Yggdrasil
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 2, 607, 1, 0 ); -- Yggdrasilberry
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 2, 12522, 1, 0 ); -- E_Blessing_10_Scroll
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 2, 6223, 1, 0 ); -- Carnium
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 2, 6224, 1, 0 ); -- Bradium
|
||||
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 3, 675, 1, 1 ); -- Silver_Coin
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 3, 671, 1, 0 ); -- Gold_Coin
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 3, 12108, 1, 0 ); -- Bundle_Of_Magic_Scroll
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 3, 617, 1, 0 ); -- Old_Violet_Box
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 3, 12514, 1, 0 ); -- E_Abrasive
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 3, 7444, 1, 0 ); -- Treasure_Box
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 3, 969, 1, 0 ); -- Gold
|
||||
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 4, 675, 1, 1 ); -- Silver_Coin
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 4, 671, 1, 0 ); -- Gold_Coin
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 4, 616, 1, 0 ); -- Old_Card_Album
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 4, 12516, 1, 0 ); -- E_Small_Life_Potion
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 4, 22777, 1, 0 ); -- Gift_Buff_Set
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 4, 6231, 1, 0 ); -- Guarantee_Weapon_6Up
|
||||
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 5, 671, 1, 1 ); -- Gold_Coin
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 5, 12246, 1, 0 ); -- Magic_Card_Album
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 5, 12263, 1, 0 ); -- Comp_Battle_Manual
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 5, 671, 1, 0 ); -- Potion_Box
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 5, 6235, 1, 0 ); -- Guarantee_Armor_6Up
|
||||
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 6, 671, 1, 1 ); -- Gold_Coin
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 6, 12766, 1, 0 ); -- Reward_Job_BM25
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 6, 6234, 1, 0 ); -- Guarantee_Armor_7Up
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 6, 6233, 1, 0 ); -- Guarantee_Armor_8Up
|
||||
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 7, 671, 1, 1 ); -- Gold_Coin
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 7, 6233, 1, 0 ); -- Guarantee_Armor_8Up
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 7, 6233, 1, 0 ); -- Guarantee_Armor_8Up // KRO lists this twice
|
||||
|
||||
--
|
||||
-- Table structure for table `skill`
|
||||
--
|
||||
|
63
sql-files/upgrades/upgrade_20150619.sql
Normal file
63
sql-files/upgrades/upgrade_20150619.sql
Normal file
@ -0,0 +1,63 @@
|
||||
ALTER TABLE `char` ADD COLUMN `sex` ENUM('M','F','U') NOT NULL default 'U';
|
||||
|
||||
CREATE TABLE `db_roulette` (
|
||||
`level` smallint(5) unsigned NOT NULL,
|
||||
`item_id` smallint(5) unsigned NOT NULL,
|
||||
`amount` smallint(5) unsigned NOT NULL DEFAULT '1',
|
||||
`flag` smallint(5) unsigned NOT NULL DEFAULT '1',
|
||||
PRIMARY KEY (`level`,`item_id`)
|
||||
) ENGINE=MyISAM;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of db_roulette
|
||||
-- ----------------------------
|
||||
-- Info: http://ro.gnjoy.com/news/update/View.asp?seq=157&curpage=1
|
||||
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 1, 675, 1, 1 ); -- Silver_Coin
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 1, 671, 1, 0 ); -- Gold_Coin
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 1, 678, 1, 0 ); -- Poison_Bottle
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 1, 604, 1, 0 ); -- Branch_Of_Dead_Tree
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 1, 522, 1, 0 ); -- Fruit_Of_Mastela
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 1, 671, 1, 0 ); -- Old_Ore_Box
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 1, 12523, 1, 0 ); -- E_Inc_Agi_10_Scroll
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 1, 985, 1, 0 ); -- Elunium
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 1, 984, 1, 0 ); -- Oridecon
|
||||
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 2, 675, 1, 1 ); -- Silver_Coin
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 2, 671, 1, 0 ); -- Gold_Coin
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 2, 603, 1, 0 ); -- Old_Blue_Box
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 2, 608, 1, 0 ); -- Seed_Of_Yggdrasil
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 2, 607, 1, 0 ); -- Yggdrasilberry
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 2, 12522, 1, 0 ); -- E_Blessing_10_Scroll
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 2, 6223, 1, 0 ); -- Carnium
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 2, 6224, 1, 0 ); -- Bradium
|
||||
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 3, 675, 1, 1 ); -- Silver_Coin
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 3, 671, 1, 0 ); -- Gold_Coin
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 3, 12108, 1, 0 ); -- Bundle_Of_Magic_Scroll
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 3, 617, 1, 0 ); -- Old_Violet_Box
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 3, 12514, 1, 0 ); -- E_Abrasive
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 3, 7444, 1, 0 ); -- Treasure_Box
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 3, 969, 1, 0 ); -- Gold
|
||||
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 4, 675, 1, 1 ); -- Silver_Coin
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 4, 671, 1, 0 ); -- Gold_Coin
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 4, 616, 1, 0 ); -- Old_Card_Album
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 4, 12516, 1, 0 ); -- E_Small_Life_Potion
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 4, 22777, 1, 0 ); -- Gift_Buff_Set
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 4, 6231, 1, 0 ); -- Guarantee_Weapon_6Up
|
||||
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 5, 671, 1, 1 ); -- Gold_Coin
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 5, 12246, 1, 0 ); -- Magic_Card_Album
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 5, 12263, 1, 0 ); -- Comp_Battle_Manual
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 5, 671, 1, 0 ); -- Potion_Box
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 5, 6235, 1, 0 ); -- Guarantee_Armor_6Up
|
||||
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 6, 671, 1, 1 ); -- Gold_Coin
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 6, 12766, 1, 0 ); -- Reward_Job_BM25
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 6, 6234, 1, 0 ); -- Guarantee_Armor_7Up
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 6, 6233, 1, 0 ); -- Guarantee_Armor_8Up
|
||||
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 7, 671, 1, 1 ); -- Gold_Coin
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 7, 6233, 1, 0 ); -- Guarantee_Armor_8Up
|
||||
INSERT INTO `db_roulette`(`level`, `item_id`, `amount`, `flag` ) VALUES ( 7, 6233, 1, 0 ); -- Guarantee_Armor_8Up // KRO lists this twice
|
1
sql-files/upgrades/upgrade_20150619_log.sql
Normal file
1
sql-files/upgrades/upgrade_20150619_log.sql
Normal file
@ -0,0 +1 @@
|
||||
ALTER TABLE `picklog` MODIFY `type` enum('M','P','L','T','V','S','N','C','A','R','G','E','B','O','I','X','D','U','$','F','Y') NOT NULL default 'P',
|
@ -837,6 +837,54 @@ int char_inventory_to_sql(const struct item items[], int max, int id) {
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the correct gender ID for the given character and enum value.
|
||||
*
|
||||
* If the per-character sex is defined but not supported by the current packetver, the database entries are corrected.
|
||||
*
|
||||
* @param sd Character data, if available.
|
||||
* @param p Character status.
|
||||
* @param sex Character sex (database enum)
|
||||
*
|
||||
* @retval SEX_MALE if the per-character sex is male
|
||||
* @retval SEX_FEMALE if the per-character sex is female
|
||||
* @retval 99 if the per-character sex is not defined or the current PACKETVER doesn't support it.
|
||||
*/
|
||||
int char_mmo_gender(const struct char_session_data *sd, const struct mmo_charstatus *p, char sex)
|
||||
{
|
||||
#if PACKETVER >= 20141016
|
||||
(void)sd; (void)p; // Unused
|
||||
switch (sex) {
|
||||
case 'M':
|
||||
return SEX_MALE;
|
||||
case 'F':
|
||||
return SEX_FEMALE;
|
||||
case 'U':
|
||||
default:
|
||||
return 99;
|
||||
}
|
||||
#else
|
||||
if (sex == 'M' || sex == 'F') {
|
||||
if (!sd) {
|
||||
// sd is not available, there isn't much we can do. Just return and print a warning.
|
||||
ShowWarning("Character '%s' (CID: %d, AID: %d) has sex '%c', but PACKETVER does not support per-character sex. Defaulting to 'U'.\n",
|
||||
p->name, p->char_id, p->account_id, sex);
|
||||
return 99;
|
||||
}
|
||||
if ((sex == 'M' && sd->sex == SEX_FEMALE)
|
||||
|| (sex == 'F' && sd->sex == SEX_MALE)) {
|
||||
ShowWarning("Changing sex of character '%s' (CID: %d, AID: %d) to 'U' due to incompatible PACKETVER.\n", p->name, p->char_id, p->account_id);
|
||||
chlogif_parse_ackchangecharsex(p->char_id, sd->sex);
|
||||
} else {
|
||||
ShowInfo("Resetting sex of character '%s' (CID: %d, AID: %d) to 'U' due to incompatible PACKETVER.\n", p->name, p->char_id, p->account_id);
|
||||
}
|
||||
if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `sex` = 'U' WHERE `char_id` = '%d'", schema_config.char_db, p->char_id)) {
|
||||
Sql_ShowDebug(sql_handle);
|
||||
}
|
||||
}
|
||||
return 99;
|
||||
#endif
|
||||
}
|
||||
|
||||
int char_mmo_char_tobuf(uint8* buf, struct mmo_charstatus* p);
|
||||
|
||||
@ -847,16 +895,16 @@ int char_mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) {
|
||||
struct mmo_charstatus p;
|
||||
int j = 0, i;
|
||||
char last_map[MAP_NAME_LENGTH_EXT];
|
||||
char sex[2];
|
||||
|
||||
stmt = SqlStmt_Malloc(sql_handle);
|
||||
if( stmt == NULL )
|
||||
{
|
||||
if( stmt == NULL ) {
|
||||
SqlStmt_ShowDebug(stmt);
|
||||
return 0;
|
||||
}
|
||||
memset(&p, 0, sizeof(p));
|
||||
|
||||
for( i = 0; i < MAX_CHARS; i++ ){
|
||||
for( i = 0; i < MAX_CHARS; i++ ) {
|
||||
sd->found_char[i] = -1;
|
||||
sd->unban_time[i] = 0;
|
||||
}
|
||||
@ -867,7 +915,7 @@ int char_mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) {
|
||||
"`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`,"
|
||||
"`status_point`,`skill_point`,`option`,`karma`,`manner`,`hair`,`hair_color`,"
|
||||
"`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`rename`,`delete_date`,"
|
||||
"`robe`,`moves`,`unban_time`,`font`,`uniqueitem_counter`"
|
||||
"`robe`,`moves`,`unban_time`,`font`,`uniqueitem_counter`,`sex`"
|
||||
" FROM `%s` WHERE `account_id`='%d' AND `char_num` < '%d'", schema_config.char_db, sd->account_id, MAX_CHARS)
|
||||
|| SQL_ERROR == SqlStmt_Execute(stmt)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &p.char_id, 0, NULL, NULL)
|
||||
@ -910,6 +958,7 @@ int char_mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) {
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 37, SQLDT_LONG, &p.unban_time, 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 38, SQLDT_UCHAR, &p.font, 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 39, SQLDT_UINT, &p.uniqueitem_counter, 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 40, SQLDT_ENUM, &sex, sizeof(sex), NULL, NULL)
|
||||
)
|
||||
{
|
||||
SqlStmt_ShowDebug(stmt);
|
||||
@ -922,6 +971,7 @@ int char_mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) {
|
||||
p.last_point.map = mapindex_name2id(last_map);
|
||||
sd->found_char[p.slot] = p.char_id;
|
||||
sd->unban_time[p.slot] = p.unban_time;
|
||||
p.sex = char_mmo_gender(sd, &p, sex[0]);
|
||||
j += char_mmo_char_tobuf(WBUFP(buf, j), &p);
|
||||
|
||||
// Addon System
|
||||
@ -954,6 +1004,7 @@ int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_ev
|
||||
int hotkey_num;
|
||||
#endif
|
||||
StringBuf msg_buf;
|
||||
char sex[2];
|
||||
|
||||
memset(p, 0, sizeof(struct mmo_charstatus));
|
||||
|
||||
@ -973,7 +1024,7 @@ int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_ev
|
||||
"`status_point`,`skill_point`,`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`homun_id`,`elemental_id`,`hair`,"
|
||||
"`hair_color`,`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`last_x`,`last_y`,"
|
||||
"`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`,`robe`, `moves`,"
|
||||
"`unban_time`,`font`,`uniqueitem_counter`"
|
||||
"`unban_time`,`font`,`uniqueitem_counter`,`sex`"
|
||||
" FROM `%s` WHERE `char_id`=? LIMIT 1", schema_config.char_db)
|
||||
|| SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0)
|
||||
|| SQL_ERROR == SqlStmt_Execute(stmt)
|
||||
@ -1033,6 +1084,7 @@ int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_ev
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 53, SQLDT_LONG, &p->unban_time, 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 54, SQLDT_UCHAR, &p->font, 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 55, SQLDT_UINT, &p->uniqueitem_counter, 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 56, SQLDT_ENUM, &sex, sizeof(sex), NULL, NULL)
|
||||
)
|
||||
{
|
||||
SqlStmt_ShowDebug(stmt);
|
||||
@ -1045,6 +1097,7 @@ int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_ev
|
||||
SqlStmt_Free(stmt);
|
||||
return 0;
|
||||
}
|
||||
p->sex = char_mmo_gender(NULL, p, sex[0]);
|
||||
p->last_point.map = mapindex_name2id(last_map);
|
||||
p->save_point.map = mapindex_name2id(save_map);
|
||||
|
||||
@ -1669,7 +1722,13 @@ int char_mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p)
|
||||
WBUFW(buf,48) = min(p->max_sp, INT16_MAX);
|
||||
WBUFW(buf,50) = DEFAULT_WALK_SPEED; // p->speed;
|
||||
WBUFW(buf,52) = p->class_;
|
||||
#if PACKETVER >= 20141022
|
||||
WBUFL(buf,54) = p->hair;
|
||||
offset+=2;
|
||||
buf = WBUFP(buffer,offset);
|
||||
#else
|
||||
WBUFW(buf,54) = p->hair;
|
||||
#endif
|
||||
|
||||
//When the weapon is sent and your option is riding, the client crashes on login!?
|
||||
WBUFW(buf,56) = p->option&(0x20|0x80000|0x100000|0x200000|0x400000|0x800000|0x1000000|0x2000000|0x4000000|0x8000000) ? 0 : p->weapon;
|
||||
@ -1723,6 +1782,10 @@ int char_mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p)
|
||||
WBUFL(buf,136) = ( p->rename > 0 ) ? 1 : 0; // (0 = disabled, otherwise displays "Add-Ons" sidebar)
|
||||
offset += 4;
|
||||
#endif
|
||||
#if PACKETVER >= 20141016
|
||||
WBUFB(buf,140) = p->sex;// sex - (0 = female, 1 = male, 99 = logindefined)
|
||||
offset += 1;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return 106+offset;
|
||||
@ -2890,7 +2953,7 @@ int do_init(int argc, char **argv)
|
||||
add_timer_func_list(char_online_data_cleanup, "online_data_cleanup");
|
||||
add_timer_interval(gettick() + 1000, char_online_data_cleanup, 0, 0, 600 * 1000);
|
||||
|
||||
//chek db tables
|
||||
//check db tables
|
||||
if(charserv_config.char_check_db && char_checkdb() == 0){
|
||||
ShowFatalError("char : A tables is missing in sql-server, please fix it, see (sql-files main.sql for structure) \n");
|
||||
exit(EXIT_FAILURE);
|
||||
|
@ -219,7 +219,7 @@ extern struct fame_list chemist_fame_list[MAX_FAME_LIST];
|
||||
extern struct fame_list taekwon_fame_list[MAX_FAME_LIST];
|
||||
|
||||
#define DEFAULT_AUTOSAVE_INTERVAL 300*1000
|
||||
#define MAX_CHAR_BUF 144 //Max size (for WFIFOHEAD calls)
|
||||
#define MAX_CHAR_BUF 150 //Max size (for WFIFOHEAD calls)
|
||||
|
||||
int char_search_mapserver(unsigned short map, uint32 ip, uint16 port);
|
||||
int char_lan_subnetcheck(uint32 ip);
|
||||
@ -233,6 +233,7 @@ void char_set_all_offline(int id);
|
||||
void char_disconnect_player(uint32 account_id);
|
||||
int char_chardb_waiting_disconnect(int tid, unsigned int tick, int id, intptr_t data);
|
||||
|
||||
int char_mmo_gender(const struct char_session_data *sd, const struct mmo_charstatus *p, char sex);
|
||||
int char_mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p);
|
||||
int char_mmo_char_tosql(uint32 char_id, struct mmo_charstatus* p);
|
||||
int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_everything);
|
||||
|
@ -711,6 +711,7 @@ int chclif_parse_charselect(int fd, struct char_session_data* sd,uint32 ipl){
|
||||
|
||||
//Have to switch over to the DB instance otherwise data won't propagate [Kevin]
|
||||
cd = (struct mmo_charstatus *)idb_get(char_db_, char_id);
|
||||
if (cd->sex == 99)
|
||||
cd->sex = sd->sex;
|
||||
|
||||
if (charserv_config.log_char) {
|
||||
|
@ -340,76 +340,79 @@ int chlogif_parse_keepalive(int fd, struct char_session_data* sd){
|
||||
return 1;
|
||||
}
|
||||
|
||||
int chlogif_parse_ackchangesex(int fd, struct char_session_data* sd){
|
||||
/**
|
||||
* Performs the necessary operations when changing a character's sex, such as
|
||||
* correcting the job class and unequipping items, and propagating the
|
||||
* information to the guild data.
|
||||
*
|
||||
* @param sex The new sex (SEX_MALE or SEX_FEMALE).
|
||||
* @param acc The character's account ID.
|
||||
* @param char_id The character ID.
|
||||
* @param class_ The character's current job class.
|
||||
* @param guild_id The character's guild ID.
|
||||
*/
|
||||
void chlogif_parse_change_sex_sub(int sex, int acc, int char_id, int class_, int guild_id)
|
||||
{
|
||||
// job modification
|
||||
if (class_ == JOB_BARD || class_ == JOB_DANCER)
|
||||
class_ = (sex == SEX_MALE ? JOB_BARD : JOB_DANCER);
|
||||
else if (class_ == JOB_CLOWN || class_ == JOB_GYPSY)
|
||||
class_ = (sex == SEX_MALE ? JOB_CLOWN : JOB_GYPSY);
|
||||
else if (class_ == JOB_BABY_BARD || class_ == JOB_BABY_DANCER)
|
||||
class_ = (sex == SEX_MALE ? JOB_BABY_BARD : JOB_BABY_DANCER);
|
||||
else if (class_ == JOB_MINSTREL || class_ == JOB_WANDERER)
|
||||
class_ = (sex == SEX_MALE ? JOB_MINSTREL : JOB_WANDERER);
|
||||
else if (class_ == JOB_MINSTREL_T || class_ == JOB_WANDERER_T)
|
||||
class_ = (sex == SEX_MALE ? JOB_MINSTREL_T : JOB_WANDERER_T);
|
||||
else if (class_ == JOB_BABY_MINSTREL || class_ == JOB_BABY_WANDERER)
|
||||
class_ = (sex == SEX_MALE ? JOB_BABY_MINSTREL : JOB_BABY_WANDERER);
|
||||
else if (class_ == JOB_KAGEROU || class_ == JOB_OBORO)
|
||||
class_ = (sex == SEX_MALE ? JOB_KAGEROU : JOB_OBORO);
|
||||
|
||||
if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `equip` = '0' WHERE `char_id` = '%d'", schema_config.inventory_db, char_id))
|
||||
Sql_ShowDebug(sql_handle);
|
||||
|
||||
if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class` = '%d', `weapon` = '0', `shield` = '0', `head_top` = '0', `head_mid` = '0', `head_bottom` = '0' WHERE `char_id` = '%d'", schema_config.char_db, class_, char_id))
|
||||
Sql_ShowDebug(sql_handle);
|
||||
if (guild_id) // If there is a guild, update the guild_member data [Skotlex]
|
||||
inter_guild_sex_changed(guild_id, acc, char_id, sex);
|
||||
}
|
||||
|
||||
int chlogif_parse_ackchangesex(int fd, struct char_session_data* sd)
|
||||
{
|
||||
if (RFIFOREST(fd) < 7)
|
||||
return 0;
|
||||
{
|
||||
unsigned char buf[7];
|
||||
|
||||
int acc = RFIFOL(fd,2);
|
||||
int sex = RFIFOB(fd,6);
|
||||
RFIFOSKIP(fd,7);
|
||||
|
||||
if( acc > 0 )
|
||||
{// TODO: Is this even possible?
|
||||
uint32 char_id[MAX_CHARS];
|
||||
int class_[MAX_CHARS];
|
||||
int guild_id[MAX_CHARS];
|
||||
unsigned char num, i;
|
||||
char* data;
|
||||
if (acc > 0) { // TODO: Is this even possible?
|
||||
unsigned char i;
|
||||
int char_id = 0, class_ = 0, guild_id = 0;
|
||||
DBMap* auth_db = char_get_authdb();
|
||||
|
||||
struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc);
|
||||
if( node != NULL )
|
||||
SqlStmt *stmt;
|
||||
|
||||
if (node != NULL)
|
||||
node->sex = sex;
|
||||
|
||||
// get characters
|
||||
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`class`,`guild_id` FROM `%s` WHERE `account_id` = '%d'", schema_config.char_db, acc) )
|
||||
Sql_ShowDebug(sql_handle);
|
||||
for( i = 0; i < MAX_CHARS && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i )
|
||||
{
|
||||
Sql_GetData(sql_handle, 0, &data, NULL); char_id[i] = atoi(data);
|
||||
Sql_GetData(sql_handle, 1, &data, NULL); class_[i] = atoi(data);
|
||||
Sql_GetData(sql_handle, 2, &data, NULL); guild_id[i] = atoi(data);
|
||||
}
|
||||
num = i;
|
||||
for( i = 0; i < num; ++i )
|
||||
{
|
||||
if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER ||
|
||||
class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY ||
|
||||
class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER ||
|
||||
class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER ||
|
||||
class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T ||
|
||||
class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER ||
|
||||
class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO )
|
||||
{
|
||||
// job modification
|
||||
if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER )
|
||||
class_[i] = (sex ? JOB_BARD : JOB_DANCER);
|
||||
else if( class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY )
|
||||
class_[i] = (sex ? JOB_CLOWN : JOB_GYPSY);
|
||||
else if( class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER )
|
||||
class_[i] = (sex ? JOB_BABY_BARD : JOB_BABY_DANCER);
|
||||
else if( class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER )
|
||||
class_[i] = (sex ? JOB_MINSTREL : JOB_WANDERER);
|
||||
else if( class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T )
|
||||
class_[i] = (sex ? JOB_MINSTREL_T : JOB_WANDERER_T);
|
||||
else if( class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER )
|
||||
class_[i] = (sex ? JOB_BABY_MINSTREL : JOB_BABY_WANDERER);
|
||||
else if( class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO )
|
||||
class_[i] = (sex ? JOB_KAGEROU : JOB_OBORO);
|
||||
stmt = SqlStmt_Malloc(sql_handle);
|
||||
if (SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `char_id`, `class`, `guild_id` FROM `%s` WHERE `account_id` = '%d'", schema_config.char_db, acc) || SqlStmt_Execute(stmt)) {
|
||||
SqlStmt_ShowDebug(stmt);
|
||||
SqlStmt_Free(stmt);
|
||||
}
|
||||
|
||||
if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d', `weapon`='0', `shield`='0', `head_top`='0', `head_mid`='0', `head_bottom`='0' WHERE `char_id`='%d'", schema_config.char_db, class_[i], char_id[i]) )
|
||||
Sql_ShowDebug(sql_handle);
|
||||
SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &char_id, 0, NULL, NULL);
|
||||
SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &class_, 0, NULL, NULL);
|
||||
SqlStmt_BindColumn(stmt, 2, SQLDT_INT, &guild_id, 0, NULL, NULL);
|
||||
|
||||
if( guild_id[i] )// If there is a guild, update the guild_member data [Skotlex]
|
||||
inter_guild_sex_changed(guild_id[i], acc, char_id[i], sex);
|
||||
for (i = 0; i < MAX_CHARS && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i) {
|
||||
chlogif_parse_change_sex_sub(sex, acc, char_id, class_, guild_id);
|
||||
}
|
||||
Sql_FreeResult(sql_handle);
|
||||
|
||||
// disconnect player if online on char-server
|
||||
char_disconnect_player(acc);
|
||||
SqlStmt_Free(stmt);
|
||||
}
|
||||
|
||||
// notify all mapservers about this change
|
||||
@ -421,6 +424,54 @@ int chlogif_parse_ackchangesex(int fd, struct char_session_data* sd){
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes a character's sex.
|
||||
* The information is updated on database, and the character is kicked if it
|
||||
* currently is online.
|
||||
*
|
||||
* @param char_id The character's ID.
|
||||
* @param sex The new sex.
|
||||
* @retval 0 in case of success.
|
||||
* @retval 1 in case of failure.
|
||||
*/
|
||||
int chlogif_parse_ackchangecharsex(int char_id, int sex)
|
||||
{
|
||||
int class_ = 0, guild_id = 0, account_id = 0;
|
||||
unsigned char buf[7];
|
||||
char *data;
|
||||
|
||||
// get character data
|
||||
if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`class`,`guild_id` FROM `%s` WHERE `char_id` = '%d'", schema_config.char_db, char_id)) {
|
||||
Sql_ShowDebug(sql_handle);
|
||||
return 1;
|
||||
}
|
||||
if (Sql_NumRows(sql_handle) != 1 || SQL_ERROR == Sql_NextRow(sql_handle)) {
|
||||
Sql_FreeResult(sql_handle);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Sql_GetData(sql_handle, 0, &data, NULL); account_id = atoi(data);
|
||||
Sql_GetData(sql_handle, 1, &data, NULL); class_ = atoi(data);
|
||||
Sql_GetData(sql_handle, 2, &data, NULL); guild_id = atoi(data);
|
||||
Sql_FreeResult(sql_handle);
|
||||
|
||||
if (SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `sex` = '%c' WHERE `char_id` = '%d'", schema_config.char_db, sex == SEX_MALE ? 'M' : 'F', char_id)) {
|
||||
Sql_ShowDebug(sql_handle);
|
||||
return 1;
|
||||
}
|
||||
chlogif_parse_change_sex_sub(sex, account_id, char_id, class_, guild_id);
|
||||
|
||||
// disconnect player if online on char-server
|
||||
char_disconnect_player(account_id);
|
||||
|
||||
// notify all mapservers about this change
|
||||
WBUFW(buf,0) = 0x2b0d;
|
||||
WBUFL(buf,2) = account_id;
|
||||
WBUFB(buf,6) = sex;
|
||||
chmapif_sendall(buf, 7);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int chlogif_parse_ackacc2req(int fd, struct char_session_data* sd){
|
||||
if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
|
||||
return 0;
|
||||
|
@ -30,7 +30,9 @@ int chlogif_parse_ackconnect(int fd, struct char_session_data* sd);
|
||||
int chlogif_parse_ackaccreq(int fd, struct char_session_data* sd);
|
||||
int chlogif_parse_reqaccdata(int fd, struct char_session_data* sd);
|
||||
int chlogif_parse_keepalive(int fd, struct char_session_data* sd);
|
||||
void chlogif_parse_change_sex_sub(int sex, int acc, int char_id, int class_, int guild_id);
|
||||
int chlogif_parse_ackchangesex(int fd, struct char_session_data* sd);
|
||||
int chlogif_parse_ackchangecharsex(int char_id, int sex);
|
||||
int chlogif_parse_ackacc2req(int fd, struct char_session_data* sd);
|
||||
int chlogif_parse_accbannotification(int fd, struct char_session_data* sd);
|
||||
int chlogif_parse_askkick(int fd, struct char_session_data* sd);
|
||||
|
@ -717,7 +717,7 @@ int chmapif_parse_reqnewemail(int fd){
|
||||
|
||||
/**
|
||||
* Forward a change of status for account to login-serv
|
||||
* @param fd: wich fd to parse from
|
||||
* @param fd: which fd to parse from
|
||||
* @return : 0 not enough data received, 1 success
|
||||
*/
|
||||
int chmapif_parse_fwlog_changestatus(int fd){
|
||||
@ -730,14 +730,19 @@ int chmapif_parse_fwlog_changestatus(int fd){
|
||||
|
||||
int aid = RFIFOL(fd,2); // account_id of who ask (-1 if server itself made this request)
|
||||
const char* name = (char*)RFIFOP(fd,6); // name of the target character
|
||||
int operation = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban, 5-changesex, 6-vip
|
||||
int32 timediff = RFIFOL(fd,32);
|
||||
int val1 = RFIFOL(fd,36);
|
||||
//int val2 = RFIFOL(fd,40); // Since BankVault is moved out, this value is unused for now
|
||||
int operation = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban, 5-changesex, 6-vip, 7-changecharsex
|
||||
int32 timediff = 0;
|
||||
int val1 = 0, sex = SEX_MALE;
|
||||
|
||||
if (operation == 2) {
|
||||
timediff = RFIFOL(fd, 32);
|
||||
val1 = RFIFOL(fd, 36);
|
||||
} else if (operation == 7)
|
||||
sex = RFIFOB(fd, 32);
|
||||
RFIFOSKIP(fd,44);
|
||||
|
||||
Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
|
||||
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id` FROM `%s` WHERE `name` = '%s'", schema_config.char_db, esc_name) )
|
||||
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`, `char_id` FROM `%s` WHERE `name` = '%s'", schema_config.char_db, esc_name) )
|
||||
Sql_ShowDebug(sql_handle);
|
||||
else if( Sql_NumRows(sql_handle) == 0 ) {
|
||||
result = 1; // 1-player not found
|
||||
@ -746,10 +751,12 @@ int chmapif_parse_fwlog_changestatus(int fd){
|
||||
Sql_ShowDebug(sql_handle);
|
||||
result = 1;
|
||||
} else {
|
||||
int t_aid; //targit account id
|
||||
int t_aid; // target account id
|
||||
int t_cid; // target char id
|
||||
char* data;
|
||||
|
||||
Sql_GetData(sql_handle, 0, &data, NULL); t_aid = atoi(data);
|
||||
Sql_GetData(sql_handle, 0, &data, NULL); t_cid = atoi(data);
|
||||
Sql_FreeResult(sql_handle);
|
||||
|
||||
if(!chlogif_isconnected())
|
||||
@ -794,16 +801,24 @@ int chmapif_parse_fwlog_changestatus(int fd){
|
||||
WFIFOL(login_fd,2) = t_aid;
|
||||
WFIFOSET(login_fd,6);
|
||||
break;
|
||||
case 6:
|
||||
case 6: // vip
|
||||
answer = (val1&4); // vip_req val1=type, &1 login send return, &2 update timestamp, &4 map send answer
|
||||
chlogif_reqvipdata(t_aid, val1, timediff, fd);
|
||||
break;
|
||||
case 7: // changecharsex
|
||||
answer = false;
|
||||
WFIFOHEAD(login_fd,6);
|
||||
WFIFOW(login_fd,0) = 0x2727;
|
||||
WFIFOL(login_fd,2) = t_aid;
|
||||
WFIFOL(login_fd,6) = t_cid;
|
||||
WFIFOSET(login_fd,10);
|
||||
break;
|
||||
} //end switch operation
|
||||
} //login is connected
|
||||
}
|
||||
|
||||
// send answer if a player asks, not if the server asks
|
||||
if( aid != -1 && answer) { // Don't send answer for changesex
|
||||
if( aid != -1 && answer) { // Don't send answer for changesex/changecharsex
|
||||
WFIFOHEAD(fd,34);
|
||||
WFIFOW(fd, 0) = 0x2b0f;
|
||||
WFIFOL(fd, 2) = aid;
|
||||
@ -817,7 +832,7 @@ int chmapif_parse_fwlog_changestatus(int fd){
|
||||
}
|
||||
|
||||
/**
|
||||
* Transmit the acknolegement of divorce of partner_id1 and partner_id2
|
||||
* Transmit the acknowledgement of divorce of partner_id1 and partner_id2
|
||||
* Update the list associated and transmit the new ranking
|
||||
* @param partner_id1: char id1 divorced
|
||||
* @param partner_id2: char id2 divorced
|
||||
@ -1047,6 +1062,7 @@ int chmapif_parse_reqauth(int fd, int id){
|
||||
node->ip == ip*/ )
|
||||
{// auth ok
|
||||
uint16 mmo_charstatus_len = sizeof(struct mmo_charstatus) + 25;
|
||||
if (cd->sex == 99)
|
||||
cd->sex = sex;
|
||||
|
||||
WFIFOHEAD(fd,mmo_charstatus_len);
|
||||
|
@ -378,7 +378,11 @@ uint32 date2version(int date) {
|
||||
else if(date < 20130717) return 43;
|
||||
else if(date < 20130807) return 44;
|
||||
else if(date < 20131223) return 45;
|
||||
else if(date >= 20131223) return 46;
|
||||
else if(date < 20140212) return 46;
|
||||
else if(date < 20140613) return 47;
|
||||
else if(date < 20141016) return 48;
|
||||
else if(date < 20141022) return 49;
|
||||
else if(date >= 20141022) return 50;
|
||||
|
||||
else return 30; //default
|
||||
}
|
||||
|
@ -6769,17 +6769,43 @@ ACMD_FUNC(uptime)
|
||||
|
||||
/*==========================================
|
||||
* @changesex <sex>
|
||||
* => Changes one's sex. Argument sex can be 0 or 1, m or f, male or female.
|
||||
* => Changes one's account sex. Argument sex can be 0 or 1, m or f, male or female.
|
||||
*------------------------------------------*/
|
||||
ACMD_FUNC(changesex)
|
||||
{
|
||||
int i;
|
||||
|
||||
nullpo_retr(-1, sd);
|
||||
|
||||
pc_resetskill(sd,4);
|
||||
// to avoid any problem with equipment and invalid sex, equipment is unequiped.
|
||||
for( i=0; i<EQI_MAX; i++ )
|
||||
if( sd->equip_index[i] >= 0 ) pc_unequipitem(sd, sd->equip_index[i], 3);
|
||||
chrif_changesex(sd);
|
||||
for (i = 0; i < EQI_MAX; i++) {
|
||||
if (sd->equip_index[i] >= 0)
|
||||
pc_unequipitem(sd, sd->equip_index[i], 3);
|
||||
}
|
||||
|
||||
chrif_changesex(sd, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*==========================================
|
||||
* @changecharsex <sex>
|
||||
* => Changes one's character sex. Argument sex can be 0 or 1, m or f, male or female.
|
||||
*------------------------------------------*/
|
||||
ACMD_FUNC(changecharsex)
|
||||
{
|
||||
int i;
|
||||
|
||||
nullpo_retr(-1, sd);
|
||||
|
||||
pc_resetskill(sd,4);
|
||||
// to avoid any problem with equipment and invalid sex, equipment is unequiped.
|
||||
for (i = 0; i < EQI_MAX; i++) {
|
||||
if (sd->equip_index[i] >= 0)
|
||||
pc_unequipitem(sd, sd->equip_index[i], 3);
|
||||
}
|
||||
|
||||
chrif_changesex(sd, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -9886,6 +9912,7 @@ void atcommand_basecommands(void) {
|
||||
ACMD_DEF(clearweather),
|
||||
ACMD_DEF(uptime),
|
||||
ACMD_DEF(changesex),
|
||||
ACMD_DEF(changecharsex),
|
||||
ACMD_DEF(mute),
|
||||
ACMD_DEF(refresh),
|
||||
ACMD_DEF(refreshall),
|
||||
|
@ -8168,6 +8168,7 @@ static const struct _battle_data {
|
||||
{ "homunculus_evo_intimacy_need", &battle_config.homunculus_evo_intimacy_need, 91100, 0, INT_MAX, },
|
||||
{ "homunculus_evo_intimacy_reset", &battle_config.homunculus_evo_intimacy_reset, 1000, 0, INT_MAX, },
|
||||
{ "monster_loot_search_type", &battle_config.monster_loot_search_type, 1, 0, 1, },
|
||||
{ "feature.roulette", &battle_config.feature_roulette, 1, 0, 1, },
|
||||
};
|
||||
|
||||
#ifndef STATS_OPT_OUT
|
||||
@ -8396,6 +8397,13 @@ void battle_adjust_conf()
|
||||
}
|
||||
#endif
|
||||
|
||||
#if PACKETVER < 20141022
|
||||
if (battle_config.feature_roulette) {
|
||||
ShowWarning("conf/battle/feature.conf roulette is enabled but it requires PACKETVER 2014-10-22 or newer, disabling...\n");
|
||||
battle_config.feature_roulette = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CELL_NOSTACK
|
||||
if (battle_config.custom_cell_stack_limit != 1)
|
||||
ShowWarning("Battle setting 'custom_cell_stack_limit' takes no effect as this server was compiled without Cell Stack Limit support.\n");
|
||||
|
@ -590,6 +590,7 @@ extern struct Battle_Config
|
||||
int homunculus_evo_intimacy_need;
|
||||
int homunculus_evo_intimacy_reset;
|
||||
int monster_loot_search_type;
|
||||
int feature_roulette;
|
||||
} battle_config;
|
||||
|
||||
void do_init_battle(void);
|
||||
|
@ -63,7 +63,7 @@ static const int packet_len_table[0x3d] = { // U - used, F - free
|
||||
//2b0a: Outgoing, chrif_skillcooldown_request -> requesting the list of skillcooldown for char
|
||||
//2b0b: Incoming, chrif_skillcooldown_load -> received the list of cooldown for char
|
||||
//2b0c: Outgoing, chrif_changeemail -> 'change mail address ...'
|
||||
//2b0d: Incoming, chrif_changedsex -> 'Change sex of acc XY'
|
||||
//2b0d: Incoming, chrif_changedsex -> 'Change sex of acc XY' (or char)
|
||||
//2b0e: Outgoing, chrif_req_login_operation -> 'Do some operations (change sex, ban / unban etc)'
|
||||
//2b0f: Incoming, chrif_ack_login_req -> 'answer of the 2b0e'
|
||||
//2b10: Outgoing, chrif_updatefamelist -> 'Update the fame ranking lists and send them'
|
||||
@ -864,17 +864,19 @@ int chrif_req_login_operation(int aid, const char* character_name, unsigned shor
|
||||
|
||||
/**
|
||||
* S 2b0e <accid>.l <name>.24B <operation_type>.w <timediff>L <val1>L <val2>L
|
||||
* Send an account modification (changesex) request to the login server (via char server).
|
||||
* Send a sex change (for account or character) request to the login server (via char server).
|
||||
* @sd : Player requesting operation
|
||||
*/
|
||||
int chrif_changesex(struct map_session_data *sd) {
|
||||
int chrif_changesex(struct map_session_data *sd, bool change_account) {
|
||||
chrif_check(-1);
|
||||
|
||||
WFIFOHEAD(char_fd,44);
|
||||
WFIFOW(char_fd,0) = 0x2b0e;
|
||||
WFIFOL(char_fd,2) = sd->status.account_id;
|
||||
safestrncpy((char*)WFIFOP(char_fd,6), sd->status.name, NAME_LENGTH);
|
||||
WFIFOW(char_fd,30) = CHRIF_OP_LOGIN_CHANGESEX;
|
||||
WFIFOW(char_fd,30) = (change_account ? CHRIF_OP_LOGIN_CHANGESEX : CHRIF_OP_LOGIN_CHANGECHARSEX);
|
||||
if (!change_account)
|
||||
WFIFOB(char_fd,32) = sd->status.sex == SEX_MALE ? SEX_FEMALE : SEX_MALE;
|
||||
WFIFOSET(char_fd,44);
|
||||
|
||||
clif_displaymessage(sd->fd, msg_txt(sd,408)); //"Need disconnection to perform change-sex request..."
|
||||
@ -917,6 +919,9 @@ static void chrif_ack_login_req(int aid, const char* player_name, uint16 type, u
|
||||
case CHRIF_OP_LOGIN_UNBLOCK:
|
||||
case CHRIF_OP_LOGIN_UNBAN:
|
||||
case CHRIF_OP_LOGIN_CHANGESEX:
|
||||
case CHRIF_OP_LOGIN_CHANGECHARSEX:
|
||||
if (type == CHRIF_OP_LOGIN_CHANGECHARSEX)
|
||||
type--; // So we don't have to create a new msgstring.
|
||||
snprintf(action,25,"%s",msg_txt(sd,427+type)); //block|ban|unblock|unban|change the sex of
|
||||
break;
|
||||
case CHRIF_OP_LOGIN_VIP:
|
||||
@ -929,7 +934,7 @@ static void chrif_ack_login_req(int aid, const char* player_name, uint16 type, u
|
||||
break;
|
||||
}
|
||||
|
||||
switch( answer ) {
|
||||
switch (answer) {
|
||||
case 0: sprintf(output, msg_txt(sd,424), action, NAME_LENGTH, player_name); break; //Login-serv has been asked to %s '%.*s'.
|
||||
case 1: sprintf(output, msg_txt(sd,425), NAME_LENGTH, player_name); break;
|
||||
case 2: sprintf(output, msg_txt(sd,426), action, NAME_LENGTH, player_name); break;
|
||||
|
@ -27,6 +27,7 @@ enum chrif_req_op {
|
||||
CHRIF_OP_LOGIN_UNBAN,
|
||||
CHRIF_OP_LOGIN_CHANGESEX,
|
||||
CHRIF_OP_LOGIN_VIP,
|
||||
CHRIF_OP_LOGIN_CHANGECHARSEX,
|
||||
|
||||
// Char-server operation
|
||||
CHRIF_OP_BAN,
|
||||
@ -73,7 +74,7 @@ int chrif_char_offline_nsd(uint32 account_id, uint32 char_id);
|
||||
int chrif_char_reset_offline(void);
|
||||
int send_users_tochar(void);
|
||||
int chrif_char_online(struct map_session_data *sd);
|
||||
int chrif_changesex(struct map_session_data *sd);
|
||||
int chrif_changesex(struct map_session_data *sd, bool change_account);
|
||||
int chrif_chardisconnect(struct map_session_data *sd);
|
||||
int chrif_divorce(int partner_id1, int partner_id2);
|
||||
|
||||
|
274
src/map/clif.c
274
src/map/clif.c
@ -662,6 +662,9 @@ void clif_authok(struct map_session_data *sd)
|
||||
WFIFOB(fd,10) = 5; // ignored
|
||||
#if PACKETVER >= 20080102
|
||||
WFIFOW(fd,11) = sd->status.font;
|
||||
#endif
|
||||
#if PACKETVER >= 20141016
|
||||
WFIFOB(fd,13) = sd->status.sex;
|
||||
#endif
|
||||
WFIFOSET(fd,packet_len(cmd));
|
||||
}
|
||||
@ -5751,6 +5754,11 @@ void clif_displaymessage(const int fd, const char* mes)
|
||||
if (fd == 0)
|
||||
;
|
||||
else {
|
||||
#if PACKETVER == 20141022
|
||||
/** for some reason game client crashes depending on message pattern (only for this packet) **/
|
||||
/** so we redirect to ZC_NPC_CHAT **/
|
||||
clif_colormes(fd, color_table[COLOR_DEFAULT], mes);
|
||||
#else
|
||||
char *message, *line;
|
||||
|
||||
message = aStrdup(mes);
|
||||
@ -5769,6 +5777,7 @@ void clif_displaymessage(const int fd, const char* mes)
|
||||
line = strtok(NULL, "\n");
|
||||
}
|
||||
aFree(message);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -6833,6 +6842,14 @@ void clif_openvending(struct map_session_data* sd, int id, struct s_vending* ven
|
||||
clif_addcards(WFIFOP(fd,22+i*22), &sd->status.cart[index]);
|
||||
}
|
||||
WFIFOSET(fd,WFIFOW(fd,2));
|
||||
|
||||
#if PACKETVER >= 20141022
|
||||
// Should go elsewhere perhaps? It has to be bundled with this however.
|
||||
WFIFOHEAD(fd, 3);
|
||||
WFIFOW(fd, 0) = 0xa28;
|
||||
WFIFOB(fd, 2) = 0; // 1 is failure. Our current responses to failure are working so not yet implemented.
|
||||
WFIFOSET(fd, 3);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -10114,18 +10131,22 @@ void clif_hotkeys_send(struct map_session_data *sd) {
|
||||
#ifdef HOTKEY_SAVING
|
||||
const int fd = sd->fd;
|
||||
int i;
|
||||
int offset = 2;
|
||||
#if PACKETVER < 20090603
|
||||
const int cmd = 0x2b9;
|
||||
#else
|
||||
#elif PACKETVER < 20141022
|
||||
const int cmd = 0x7d9;
|
||||
#else
|
||||
const int cmd = 0xa00;
|
||||
offset = 3;
|
||||
#endif
|
||||
if (!fd) return;
|
||||
WFIFOHEAD(fd, 2+MAX_HOTKEYS*7);
|
||||
WFIFOHEAD(fd, offset + MAX_HOTKEYS * 7);
|
||||
WFIFOW(fd, 0) = cmd;
|
||||
for(i = 0; i < MAX_HOTKEYS; i++) {
|
||||
WFIFOB(fd, 2 + 0 + i * 7) = sd->status.hotkeys[i].type; // type: 0: item, 1: skill
|
||||
WFIFOL(fd, 2 + 1 + i * 7) = sd->status.hotkeys[i].id; // item or skill ID
|
||||
WFIFOW(fd, 2 + 5 + i * 7) = sd->status.hotkeys[i].lv; // skill level
|
||||
WFIFOB(fd, offset + 0 + i * 7) = sd->status.hotkeys[i].type; // type: 0: item, 1: skill
|
||||
WFIFOL(fd, offset + 1 + i * 7) = sd->status.hotkeys[i].id; // item or skill ID
|
||||
WFIFOW(fd, offset + 5 + i * 7) = sd->status.hotkeys[i].lv; // item qty or skill level
|
||||
}
|
||||
WFIFOSET(fd, packet_len(cmd));
|
||||
#endif
|
||||
@ -17729,6 +17750,229 @@ void DumpUnknown(int fd,TBL_PC *sd,int cmd,int packet_len)
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Roulette System
|
||||
/// Author: Yommy
|
||||
|
||||
/**
|
||||
* Opens Roulette window
|
||||
* @param fd
|
||||
* @param sd
|
||||
*/
|
||||
void clif_parse_RouletteOpen(int fd, struct map_session_data* sd)
|
||||
{
|
||||
nullpo_retv(sd);
|
||||
|
||||
if (!battle_config.feature_roulette) {
|
||||
clif_colormes(sd,color_table[COLOR_RED],msg_txt(sd,1497)); //Roulette is disabled
|
||||
return;
|
||||
}
|
||||
|
||||
WFIFOHEAD(fd,packet_len(0xa1a));
|
||||
WBUFW(fd,0) = 0xa1a;
|
||||
WBUFW(fd,2) = 0; // result
|
||||
WBUFL(fd,3) = 0; // serial
|
||||
WBUFW(fd,7) = sd->roulette.stage - 1;
|
||||
WBUFW(fd,8) = (char)sd->roulette.prizeIdx;
|
||||
WBUFW(fd,9) = -1; // TODO
|
||||
WBUFL(fd,11) = sd->roulette_point.gold;
|
||||
WBUFL(fd,15) = sd->roulette_point.silver;
|
||||
WBUFL(fd,19) = sd->roulette_point.bronze;
|
||||
WFIFOSET(fd,packet_len(0xa1a));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates information to be displayed
|
||||
* @param fd
|
||||
* @param sd
|
||||
*/
|
||||
void clif_parse_RouletteInfo(int fd, struct map_session_data* sd)
|
||||
{
|
||||
unsigned short i, j, count = 0;
|
||||
int len = 8 + (42 * 8);
|
||||
|
||||
nullpo_retv(sd);
|
||||
|
||||
if (!battle_config.feature_roulette) {
|
||||
clif_colormes(sd,color_table[COLOR_RED],msg_txt(sd,1497)); //Roulette is disabled
|
||||
return;
|
||||
}
|
||||
|
||||
WFIFOHEAD(fd,len);
|
||||
WBUFW(fd,0) = 0xa1c;
|
||||
WBUFW(fd,2) = len;
|
||||
WBUFL(fd,6) = 1; // serial
|
||||
|
||||
for(i = 0; i < MAX_ROULETTE_LEVEL; i++) {
|
||||
for(j = 0; j < MAX_ROULETTE_COLUMNS - i; j++) {
|
||||
WBUFW(fd,8 + i * 8) = i;
|
||||
WBUFW(fd,8 + i * 8 + 2) = j;
|
||||
WBUFW(fd,8 + i * 8 + 4) = rd.nameid[i][j];
|
||||
WBUFW(fd,8 + i * 8 + 6) = rd.qty[i][j];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
WFIFOSET(fd,len);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes Roulette window
|
||||
* @param fd
|
||||
* @param sd
|
||||
*/
|
||||
void clif_parse_RouletteClose(int fd, struct map_session_data* sd)
|
||||
{
|
||||
nullpo_retv(sd);
|
||||
|
||||
if (!battle_config.feature_roulette) {
|
||||
clif_colormes(sd,color_table[COLOR_RED],msg_txt(sd,1497)); //Roulette is disabled
|
||||
return;
|
||||
}
|
||||
|
||||
/** What do we need this for? (other than state tracking), game client closes the window without our response. **/
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the stage and attempt to give a prize
|
||||
* @param fd
|
||||
* @param sd
|
||||
*/
|
||||
void clif_parse_RouletteGenerate(int fd, struct map_session_data* sd)
|
||||
{
|
||||
unsigned char result = GENERATE_ROULETTE_SUCCESS;
|
||||
short stage = sd->roulette.stage;
|
||||
|
||||
nullpo_retv(sd);
|
||||
|
||||
if (!battle_config.feature_roulette) {
|
||||
clif_colormes(sd,color_table[COLOR_RED],msg_txt(sd,1497)); //Roulette is disabled
|
||||
return;
|
||||
}
|
||||
|
||||
if (sd->roulette.stage >= MAX_ROULETTE_LEVEL)
|
||||
stage = sd->roulette.stage = 0;
|
||||
|
||||
if (!stage) {
|
||||
if (sd->roulette_point.bronze <= 0 && sd->roulette_point.silver < 10 && sd->roulette_point.gold < 10)
|
||||
result = GENERATE_ROULETTE_NO_ENOUGH_POINT;
|
||||
}
|
||||
|
||||
if (result == GENERATE_ROULETTE_SUCCESS) {
|
||||
if (!stage) {
|
||||
if (sd->roulette_point.bronze > 0) {
|
||||
sd->roulette_point.bronze -= 1;
|
||||
} else if (sd->roulette_point.silver > 9) {
|
||||
sd->roulette_point.silver -= 10;
|
||||
stage = sd->roulette.stage = 2;
|
||||
} else if (sd->roulette_point.gold > 9) {
|
||||
sd->roulette_point.gold -= 10;
|
||||
stage = sd->roulette.stage = 4;
|
||||
}
|
||||
}
|
||||
|
||||
sd->roulette.prizeStage = stage;
|
||||
sd->roulette.prizeIdx = rnd()%rd.items[stage];
|
||||
if (sd->roulette.prizeIdx == 0) {
|
||||
struct item it;
|
||||
memset(&it, 0, sizeof(it));
|
||||
|
||||
it.nameid = rd.nameid[stage][0];
|
||||
it.identify = 1;
|
||||
|
||||
pc_additem(sd, &it, rd.qty[stage][0], LOG_TYPE_ROULETTE);
|
||||
|
||||
sd->roulette.stage = 0;
|
||||
result = GENERATE_ROULETTE_LOSING;
|
||||
} else
|
||||
sd->roulette.claimPrize = true;
|
||||
}
|
||||
|
||||
clif_roulette_generate_ack(sd,result,stage,sd->roulette.prizeIdx,0);
|
||||
if (result == GENERATE_ROULETTE_SUCCESS)
|
||||
sd->roulette.stage++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request to cash in prize
|
||||
* @param fd
|
||||
* @param sd
|
||||
*/
|
||||
void clif_parse_RouletteRecvItem(int fd, struct map_session_data* sd)
|
||||
{
|
||||
nullpo_retv(sd);
|
||||
|
||||
if (!battle_config.feature_roulette) {
|
||||
clif_colormes(sd,color_table[COLOR_RED],msg_txt(sd,1497)); //Roulette is disabled
|
||||
return;
|
||||
}
|
||||
|
||||
WFIFOHEAD(fd,packet_len(0xa22));
|
||||
WBUFW(fd,0) = 0xa22;
|
||||
|
||||
if (sd->roulette.claimPrize) {
|
||||
struct item it;
|
||||
memset(&it, 0, sizeof(it));
|
||||
|
||||
it.nameid = rd.nameid[sd->roulette.prizeStage][sd->roulette.prizeIdx];
|
||||
it.identify = 1;
|
||||
|
||||
switch (pc_additem(sd, &it, rd.qty[sd->roulette.prizeStage][sd->roulette.prizeIdx], LOG_TYPE_OTHER)) {
|
||||
case 0:
|
||||
WBUFW(fd,2) = RECV_ITEM_SUCCESS;
|
||||
sd->roulette.claimPrize = false;
|
||||
sd->roulette.prizeStage = 0;
|
||||
sd->roulette.prizeIdx = 0;
|
||||
sd->roulette.stage = 0;
|
||||
break;
|
||||
case 1:
|
||||
case 4:
|
||||
case 5:
|
||||
WBUFW(fd,2) = RECV_ITEM_OVERCOUNT;
|
||||
break;
|
||||
case 2:
|
||||
WBUFW(fd,2) = RECV_ITEM_OVERWEIGHT;
|
||||
break;
|
||||
default:
|
||||
case 7:
|
||||
WBUFW(fd,2) = RECV_ITEM_FAILED;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
WBUFW(fd,2) = RECV_ITEM_FAILED;
|
||||
|
||||
WBUFL(fd,3) = 0; // additional item TODO
|
||||
WFIFOSET(fd,packet_len(0xa22));
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Roulette window with current stats
|
||||
* @param sd
|
||||
* @param result
|
||||
* @param stage
|
||||
* @param prizeIdx
|
||||
* @param bonusItemID
|
||||
*/
|
||||
void clif_roulette_generate_ack(struct map_session_data *sd, unsigned char result, short stage, short prizeIdx, short bonusItemID)
|
||||
{
|
||||
int fd = sd->fd;
|
||||
|
||||
nullpo_retv(sd);
|
||||
|
||||
WFIFOHEAD(fd,packet_len(0xa20));
|
||||
WBUFW(fd,0) = 0xa20;
|
||||
WBUFW(fd,2) = result;
|
||||
WBUFW(fd,3) = stage;
|
||||
WBUFW(fd,5) = prizeIdx;
|
||||
WBUFW(fd,7) = bonusItemID;
|
||||
WBUFL(fd,9) = sd->roulette_point.gold;
|
||||
WBUFL(fd,13) = sd->roulette_point.silver;
|
||||
WBUFL(fd,17) = sd->roulette_point.bronze;
|
||||
WFIFOSET(fd,packet_len(0xa20));
|
||||
}
|
||||
|
||||
/*==========================================
|
||||
* Main client packet processing function
|
||||
*------------------------------------------*/
|
||||
@ -18120,7 +18364,16 @@ void packetdb_readdb(bool reload)
|
||||
//#0x09C0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0,102, 0,
|
||||
0, 0, 0, 0, 2, 0, -1, -1, 2, 0, 0, 0, 0, 0, 0, 7,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 3, 11, 0, 11, -1, 0, 3, 11, 0,
|
||||
0, 11, 12, 11, 0, 0, 0, 0, 0,143, 0, 0, 0, 0, 0, 0,
|
||||
//#0x0a00
|
||||
#if PACKETVER >= 20141022
|
||||
269, 0, 0, 2, 6, 49, 6, 9, 26, 45, 47, 47, 56, -1, 0, 0,
|
||||
#else
|
||||
269, 0, 0, 2, 6, 48, 6, 9, 26, 45, 47, 47, 56, -1, 0, 0,
|
||||
#endif
|
||||
0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 3, 5, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
struct {
|
||||
@ -18344,9 +18597,15 @@ void packetdb_readdb(bool reload)
|
||||
{ clif_parse_client_version, "clientversion"},
|
||||
{ clif_parse_blocking_playcancel, "booking_playcancel"},
|
||||
{ clif_parse_ranklist, "ranklist"},
|
||||
/* Market NPC */
|
||||
// Market NPC
|
||||
{ clif_parse_NPCMarketClosed, "npcmarketclosed" },
|
||||
{ clif_parse_NPCMarketPurchase, "npcmarketpurchase" },
|
||||
// Roulette
|
||||
{ clif_parse_RouletteOpen, "rouletteopen" },
|
||||
{ clif_parse_RouletteInfo, "rouletteinfo" },
|
||||
{ clif_parse_RouletteClose, "rouletteclose" },
|
||||
{ clif_parse_RouletteGenerate, "roulettegenerate" },
|
||||
{ clif_parse_RouletteRecvItem, "rouletterecvitem" },
|
||||
{NULL,NULL}
|
||||
};
|
||||
struct {
|
||||
@ -18591,6 +18850,7 @@ void packetdb_readdb(bool reload)
|
||||
*------------------------------------------*/
|
||||
void do_init_clif(void) {
|
||||
const char* colors[COLOR_MAX] = {
|
||||
"0x00FF00",
|
||||
"0xFF0000",
|
||||
"0xFFFFFF",
|
||||
"0xFFFF00",
|
||||
|
@ -33,9 +33,9 @@ struct party_booking_ad_info;
|
||||
#include <stdarg.h>
|
||||
|
||||
enum { // packet DB
|
||||
MIN_PACKET_DB = 0x0064,
|
||||
MAX_PACKET_DB = 0xf00,
|
||||
MAX_PACKET_VER = 46,
|
||||
MIN_PACKET_DB = 0x064,
|
||||
MAX_PACKET_DB = 0xAFF,
|
||||
MAX_PACKET_VER = 51,
|
||||
MAX_PACKET_POS = 20,
|
||||
};
|
||||
|
||||
@ -80,6 +80,35 @@ enum e_BANKING_WITHDRAW_ACK {
|
||||
BWA_UNKNOWN_ERROR = 0x2,
|
||||
};
|
||||
|
||||
enum RECV_ROULETTE_ITEM_REQ {
|
||||
RECV_ITEM_SUCCESS = 0x0,
|
||||
RECV_ITEM_FAILED = 0x1,
|
||||
RECV_ITEM_OVERCOUNT = 0x2,
|
||||
RECV_ITEM_OVERWEIGHT = 0x3,
|
||||
};
|
||||
|
||||
enum RECV_ROULETTE_ITEM_ACK {
|
||||
RECV_ITEM_NORMAL = 0x0,
|
||||
RECV_ITEM_LOSING = 0x1,
|
||||
};
|
||||
|
||||
enum GENERATE_ROULETTE_ACK {
|
||||
GENERATE_ROULETTE_SUCCESS = 0x0,
|
||||
GENERATE_ROULETTE_FAILED = 0x1,
|
||||
GENERATE_ROULETTE_NO_ENOUGH_POINT = 0x2,
|
||||
GENERATE_ROULETTE_LOSING = 0x3,
|
||||
};
|
||||
|
||||
enum OPEN_ROULETTE_ACK {
|
||||
OPEN_ROULETTE_SUCCESS = 0x0,
|
||||
OPEN_ROULETTE_FAILED = 0x1,
|
||||
};
|
||||
|
||||
enum CLOSE_ROULETTE_ACK {
|
||||
CLOSE_ROULETTE_SUCCESS = 0x0,
|
||||
CLOSE_ROULETTE_FAILED = 0x1,
|
||||
};
|
||||
|
||||
// packet_db[SERVER] is reserved for server use
|
||||
#define SERVER 0
|
||||
#define packet_len(cmd) packet_db[SERVER][cmd].len
|
||||
@ -861,6 +890,14 @@ void clif_cashshop_open( struct map_session_data* sd );
|
||||
|
||||
void clif_display_pinfo(struct map_session_data *sd, int type);
|
||||
|
||||
/// Roulette
|
||||
void clif_roulette_generate_ack(struct map_session_data *sd, unsigned char result, short stage, short prizeIdx, short bonusItemID);
|
||||
void clif_parse_RouletteOpen(int fd, struct map_session_data *sd);
|
||||
void clif_parse_RouletteInfo(int fd, struct map_session_data *sd);
|
||||
void clif_parse_RouletteClose(int fd, struct map_session_data *sd);
|
||||
void clif_parse_RouletteGenerate(int fd, struct map_session_data *sd);
|
||||
void clif_parse_RouletteRecvItem(int fd, struct map_session_data *sd);
|
||||
|
||||
/**
|
||||
* 3CeAM
|
||||
**/
|
||||
@ -892,6 +929,7 @@ void clif_monster_hp_bar( struct mob_data* md, int fd );
|
||||
* Color Table
|
||||
**/
|
||||
enum clif_colors {
|
||||
COLOR_DEFAULT,
|
||||
COLOR_RED,
|
||||
COLOR_WHITE,
|
||||
COLOR_YELLOW,
|
||||
|
102
src/map/itemdb.c
102
src/map/itemdb.c
@ -929,6 +929,7 @@ static int itemdb_combo_split_atoi (char *str, int *val) {
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* <combo{:combo{:combo:{..}}}>,<{ script }>
|
||||
**/
|
||||
@ -1056,7 +1057,101 @@ static void itemdb_read_combos(const char* basedir, bool silent) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process Roulette items
|
||||
*/
|
||||
bool itemdb_parse_roulette_db(void)
|
||||
{
|
||||
int i, j;
|
||||
uint32 count = 0;
|
||||
|
||||
// retrieve all rows from the item database
|
||||
if (SQL_ERROR == Sql_Query(mmysql_handle, "SELECT * FROM `%s`", db_roulette_table)) {
|
||||
Sql_ShowDebug(mmysql_handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_ROULETTE_LEVEL; i++) {
|
||||
rd.items[i] = 0;
|
||||
}
|
||||
|
||||
// process rows one by one
|
||||
while (SQL_SUCCESS == Sql_NextRow(mmysql_handle)) {
|
||||
char* str[4];
|
||||
char* dummy = "";
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_ROULETTE_LEVEL; i++) {
|
||||
struct item_data * data = NULL;
|
||||
|
||||
Sql_GetData(mmysql_handle, i, &str[i], NULL);
|
||||
|
||||
if (str[i] == NULL)
|
||||
str[i] = dummy; // get rid of NULL columns
|
||||
|
||||
if (!(data = itemdb_exists(atoi(str[1])))) {
|
||||
ShowWarning("itemdb_parse_roulette_db: Unknown item_id '%hu' in level '%d'\n", atoi(str[1]), atoi(str[0]));
|
||||
continue;
|
||||
}
|
||||
if (atoi(str[2]) < 1) {
|
||||
ShowWarning("itemdb_parse_roulette_db: Unsupported amount '%hu' for item_id '%hu' in level '%d'\n", atoi(str[2]), atoi(str[1]), atoi(str[0]));
|
||||
continue;
|
||||
}
|
||||
if (atoi(str[3]) < 0 || atoi(str[3]) > 1) {
|
||||
ShowWarning("itemdb_parse_roueltte_db: Unsupported flag '%d' for item_id '%hu' in level '%d'\n", atoi(str[3]), atoi(str[1]), atoi(str[0]));
|
||||
continue;
|
||||
}
|
||||
|
||||
j = rd.items[i];
|
||||
RECREATE(rd.nameid[i], unsigned short, ++rd.items[i]);
|
||||
RECREATE(rd.qty[i], unsigned short, rd.items[i]);
|
||||
RECREATE(rd.flag[i], int, rd.items[i]);
|
||||
|
||||
rd.nameid[i][j] = data->nameid;
|
||||
rd.qty[i][j] = atoi(str[2]);
|
||||
rd.flag[i][j] = atoi(str[3]);
|
||||
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
// free the query result
|
||||
Sql_FreeResult(mmysql_handle);
|
||||
|
||||
for (i = 0; i < MAX_ROULETTE_LEVEL; i++) {
|
||||
int limit = MAX_ROULETTE_COLUMNS - i;
|
||||
|
||||
if (rd.items[i] == limit)
|
||||
continue;
|
||||
|
||||
if (rd.items[i] > limit) {
|
||||
ShowWarning("itemdb_parse_roulette_db: level %d has %d items, only %d supported, capping...\n", i + 1, rd.items[i], limit);
|
||||
rd.items[i] = limit;
|
||||
continue;
|
||||
}
|
||||
|
||||
/** this scenario = rd.items[i] < limit **/
|
||||
ShowWarning("itemdb_parse_roulette_db: Level %d has %d items, %d are required. filling with apples\n", i + 1, rd.items[i], limit);
|
||||
|
||||
rd.items[i] = limit;
|
||||
RECREATE(rd.nameid[i], unsigned short, rd.items[i]);
|
||||
RECREATE(rd.qty[i], unsigned short, rd.items[i]);
|
||||
RECREATE(rd.flag[i], int, rd.items[i]);
|
||||
|
||||
for (j = 0; j < MAX_ROULETTE_COLUMNS - i; j++) {
|
||||
if (rd.qty[i][j])
|
||||
continue;
|
||||
|
||||
rd.nameid[i][j] = ITEMID_APPLE;
|
||||
rd.qty[i][j] = 1;
|
||||
rd.flag[i][j] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, db_roulette_table);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*======================================
|
||||
* Applies gender restrictions according to settings. [Skotlex]
|
||||
@ -1074,6 +1169,7 @@ static char itemdb_gendercheck(struct item_data *id)
|
||||
|
||||
return (battle_config.ignore_items_gender) ? 2 : id->sex;
|
||||
}
|
||||
|
||||
/**
|
||||
* [RRInd]
|
||||
* For backwards compatibility, in Renewal mode, MATK from weapons comes from the atk slot
|
||||
@ -1579,6 +1675,9 @@ void itemdb_reload(void) {
|
||||
itemdb_read();
|
||||
cashshop_reloaddb();
|
||||
|
||||
if (!itemdb_parse_roulette_db())
|
||||
battle_config.feature_roulette = 0;
|
||||
|
||||
//Epoque's awesome @reloaditemdb fix - thanks! [Ind]
|
||||
//- Fixes the need of a @reloadmobdb after a @reloaditemdb to re-link monster drop data
|
||||
for( i = 0; i < MAX_MOB_DB; i++ ) {
|
||||
@ -1649,4 +1748,7 @@ void do_init_itemdb(void) {
|
||||
itemdb_group = uidb_alloc(DB_OPT_BASE);
|
||||
itemdb_create_dummy();
|
||||
itemdb_read();
|
||||
|
||||
if (!itemdb_parse_roulette_db())
|
||||
battle_config.feature_roulette = 0;
|
||||
}
|
||||
|
@ -25,6 +25,9 @@
|
||||
|
||||
#define MAX_ITEMGROUP_RANDGROUP 4 ///Max group for random item (increase this when needed). TODO: Remove this limit and use dynamic size if needed
|
||||
|
||||
#define MAX_ROULETTE_LEVEL 7 /** client-defined value **/
|
||||
#define MAX_ROULETTE_COLUMNS 9 /** client-defined value **/
|
||||
|
||||
#define CARD0_FORGE 0x00FF
|
||||
#define CARD0_CREATE 0x00FE
|
||||
#define CARD0_PET 0x0100
|
||||
@ -39,6 +42,7 @@ enum item_itemid
|
||||
ITEMID_YELLOW_POTION = 503,
|
||||
ITEMID_WHITE_POTION = 504,
|
||||
ITEMID_BLUE_POTION = 505,
|
||||
ITEMID_APPLE = 512,
|
||||
ITEMID_HOLY_WATER = 523,
|
||||
ITEMID_PUMPKIN = 535,
|
||||
ITEMID_RED_SLIM_POTION = 545,
|
||||
@ -371,6 +375,14 @@ struct s_item_group_db
|
||||
struct s_item_group_random random[MAX_ITEMGROUP_RANDGROUP]; //! TODO: Move this fixed array to dynamic size if needed.
|
||||
};
|
||||
|
||||
/// Struct of Roulette db
|
||||
struct {
|
||||
unsigned short *nameid[MAX_ROULETTE_LEVEL], /// Item ID
|
||||
*qty[MAX_ROULETTE_LEVEL]; /// Amount of Item ID
|
||||
int *flag[MAX_ROULETTE_LEVEL]; /// Whether the item is for loss or win
|
||||
int items[MAX_ROULETTE_LEVEL]; /// Number of items in the list for each
|
||||
} rd;
|
||||
|
||||
///Main item data struct
|
||||
struct item_data
|
||||
{
|
||||
@ -513,6 +525,8 @@ struct s_item_group_db *itemdb_group_exists(unsigned short group_id);
|
||||
char itemdb_pc_get_itemgroup(uint16 group_id, struct map_session_data *sd);
|
||||
uint16 itemdb_get_randgroupitem_count(uint16 group_id, uint8 sub_group, unsigned short nameid);
|
||||
|
||||
bool itemdb_parse_roulette_db(void);
|
||||
|
||||
void itemdb_reload(void);
|
||||
|
||||
void do_final_itemdb(void);
|
||||
|
@ -56,7 +56,7 @@ static char log_picktype2char(e_log_pick_type type)
|
||||
{
|
||||
case LOG_TYPE_TRADE: return 'T'; // (T)rade
|
||||
case LOG_TYPE_VENDING: return 'V'; // (V)ending
|
||||
case LOG_TYPE_PICKDROP_PLAYER: return 'P'; // (P)player
|
||||
case LOG_TYPE_PICKDROP_PLAYER: return 'P'; // (P)layer
|
||||
case LOG_TYPE_PICKDROP_MONSTER: return 'M'; // (M)onster
|
||||
case LOG_TYPE_NPC: return 'S'; // NPC (S)hop
|
||||
case LOG_TYPE_SCRIPT: return 'N'; // (N)PC Script
|
||||
@ -75,6 +75,7 @@ static char log_picktype2char(e_log_pick_type type)
|
||||
case LOG_TYPE_OTHER: return 'X'; // Other
|
||||
case LOG_TYPE_CASH: return '$'; // Cash
|
||||
case LOG_TYPE_BOUND_REMOVAL: return 'F'; // Removed bound items when guild/party is broken
|
||||
case LOG_TYPE_ROULETTE: return 'Y'; // Roulette Lotter(Y)
|
||||
}
|
||||
|
||||
// should not get here, fallback
|
||||
|
@ -24,30 +24,31 @@ typedef enum e_log_chat_type
|
||||
typedef enum e_log_pick_type
|
||||
{
|
||||
LOG_TYPE_NONE = 0,
|
||||
LOG_TYPE_TRADE = 0x00001,
|
||||
LOG_TYPE_VENDING = 0x00002,
|
||||
LOG_TYPE_PICKDROP_PLAYER = 0x00004,
|
||||
LOG_TYPE_PICKDROP_MONSTER = 0x00008,
|
||||
LOG_TYPE_NPC = 0x00010,
|
||||
LOG_TYPE_SCRIPT = 0x00020,
|
||||
LOG_TYPE_STEAL = 0x00040,
|
||||
LOG_TYPE_CONSUME = 0x00080,
|
||||
LOG_TYPE_PRODUCE = 0x00100,
|
||||
LOG_TYPE_MVP = 0x00200,
|
||||
LOG_TYPE_COMMAND = 0x00400,
|
||||
LOG_TYPE_STORAGE = 0x00800,
|
||||
LOG_TYPE_GSTORAGE = 0x01000,
|
||||
LOG_TYPE_MAIL = 0x02000,
|
||||
LOG_TYPE_AUCTION = 0x04000,
|
||||
LOG_TYPE_BUYING_STORE = 0x08000,
|
||||
LOG_TYPE_OTHER = 0x10000,
|
||||
LOG_TYPE_CASH = 0x20000,
|
||||
LOG_TYPE_BANK = 0x40000,
|
||||
LOG_TYPE_BOUND_REMOVAL = 0x80000,
|
||||
LOG_TYPE_TRADE = 0x000001,
|
||||
LOG_TYPE_VENDING = 0x000002,
|
||||
LOG_TYPE_PICKDROP_PLAYER = 0x000004,
|
||||
LOG_TYPE_PICKDROP_MONSTER = 0x000008,
|
||||
LOG_TYPE_NPC = 0x000010,
|
||||
LOG_TYPE_SCRIPT = 0x000020,
|
||||
LOG_TYPE_STEAL = 0x000040,
|
||||
LOG_TYPE_CONSUME = 0x000080,
|
||||
LOG_TYPE_PRODUCE = 0x000100,
|
||||
LOG_TYPE_MVP = 0x000200,
|
||||
LOG_TYPE_COMMAND = 0x000400,
|
||||
LOG_TYPE_STORAGE = 0x000800,
|
||||
LOG_TYPE_GSTORAGE = 0x001000,
|
||||
LOG_TYPE_MAIL = 0x002000,
|
||||
LOG_TYPE_AUCTION = 0x004000,
|
||||
LOG_TYPE_BUYING_STORE = 0x008000,
|
||||
LOG_TYPE_OTHER = 0x010000,
|
||||
LOG_TYPE_CASH = 0x020000,
|
||||
LOG_TYPE_BANK = 0x040000,
|
||||
LOG_TYPE_BOUND_REMOVAL = 0x080000,
|
||||
LOG_TYPE_ROULETTE = 0x100000,
|
||||
// combinations
|
||||
LOG_TYPE_LOOT = LOG_TYPE_PICKDROP_MONSTER|LOG_TYPE_CONSUME,
|
||||
// all
|
||||
LOG_TYPE_ALL = 0xFFFFF,
|
||||
LOG_TYPE_ALL = 0xFFFFFF,
|
||||
} e_log_pick_type;
|
||||
|
||||
typedef enum e_log_cash_type
|
||||
|
@ -70,6 +70,7 @@ char mob_skill_db2_db[32] = "mob_skill_db2";
|
||||
char vendings_db[32] = "vendings";
|
||||
char vending_items_db[32] = "vending_items";
|
||||
char market_table[32] = "market";
|
||||
char db_roulette_table[32] = "db_roulette";
|
||||
|
||||
// log database
|
||||
char log_db_ip[32] = "127.0.0.1";
|
||||
@ -3759,7 +3760,9 @@ int inter_config_read(char *cfgName)
|
||||
else if( strcmpi( w1, "vending_db" ) == 0 )
|
||||
strcpy( vendings_db, w2 );
|
||||
else if( strcmpi( w1, "vending_items_db" ) == 0 )
|
||||
strcpy( vending_items_db, w2 );
|
||||
strcpy(vending_items_db, w2);
|
||||
else if( strcmpi(w1, "db_roulette_table") == 0)
|
||||
strcpy(db_roulette_table, w2);
|
||||
else if (strcmpi(w1, "market_table") == 0)
|
||||
strcpy(market_table, w2);
|
||||
else
|
||||
|
@ -459,6 +459,9 @@ enum _sp {
|
||||
SP_CHARRENAME=125,
|
||||
SP_CHARFONT=126,
|
||||
SP_BANK_VAULT = 127,
|
||||
SP_ROULETTE_BRONZE = 128,
|
||||
SP_ROULETTE_SILVER = 129,
|
||||
SP_ROULETTE_GOLD = 130,
|
||||
|
||||
// Mercenaries
|
||||
SP_MERCFLEE=165, SP_MERCKILLS=189, SP_MERCFAITH=190,
|
||||
@ -1006,6 +1009,7 @@ extern char mob_skill_db2_db[32];
|
||||
extern char vendings_db[32];
|
||||
extern char vending_items_db[32];
|
||||
extern char market_table[32];
|
||||
extern char db_roulette_table[32];
|
||||
|
||||
void do_shutdown(void);
|
||||
|
||||
|
21
src/map/pc.c
21
src/map/pc.c
@ -1344,6 +1344,12 @@ void pc_reg_received(struct map_session_data *sd)
|
||||
if (battle_config.feature_banking)
|
||||
sd->bank_vault = pc_readreg2(sd, BANK_VAULT_VAR);
|
||||
|
||||
if (battle_config.feature_roulette) {
|
||||
sd->roulette_point.bronze = pc_readreg2(sd, ROULETTE_BRONZE_VAR);
|
||||
sd->roulette_point.silver = pc_readreg2(sd, ROULETTE_SILVER_VAR);
|
||||
sd->roulette_point.gold = pc_readreg2(sd, ROULETTE_GOLD_VAR);
|
||||
}
|
||||
|
||||
//SG map and mob read [Komurka]
|
||||
for(i=0;i<MAX_PC_FEELHATE;i++) { //for now - someone need to make reading from txt/sql
|
||||
uint16 j;
|
||||
@ -7603,6 +7609,9 @@ int pc_readparam(struct map_session_data* sd,int type)
|
||||
case SP_CHARRENAME: val = sd->status.rename; break;
|
||||
case SP_CHARFONT: val = sd->status.font; break;
|
||||
case SP_BANK_VAULT: val = sd->bank_vault; break;
|
||||
case SP_ROULETTE_BRONZE: val = sd->roulette_point.bronze; break;
|
||||
case SP_ROULETTE_SILVER: val = sd->roulette_point.silver; break;
|
||||
case SP_ROULETTE_GOLD: val = sd->roulette_point.gold; break;
|
||||
case SP_CRITICAL: val = sd->battle_status.cri/10; break;
|
||||
case SP_ASPD: val = (2000-sd->battle_status.amotion)/10; break;
|
||||
case SP_BASE_ATK: val = sd->battle_status.batk; break;
|
||||
@ -7861,6 +7870,18 @@ bool pc_setparam(struct map_session_data *sd,int type,int val)
|
||||
sd->bank_vault = cap_value(val, 0, MAX_BANK_ZENY);
|
||||
pc_setreg2(sd, BANK_VAULT_VAR, sd->bank_vault);
|
||||
return true;
|
||||
case SP_ROULETTE_BRONZE:
|
||||
sd->roulette_point.bronze = val;
|
||||
pc_setreg2(sd, ROULETTE_BRONZE_VAR, sd->roulette_point.bronze);
|
||||
return true;
|
||||
case SP_ROULETTE_SILVER:
|
||||
sd->roulette_point.silver = val;
|
||||
pc_setreg2(sd, ROULETTE_SILVER_VAR, sd->roulette_point.silver);
|
||||
return true;
|
||||
case SP_ROULETTE_GOLD:
|
||||
sd->roulette_point.gold = val;
|
||||
pc_setreg2(sd, ROULETTE_GOLD_VAR, sd->roulette_point.gold);
|
||||
return true;
|
||||
default:
|
||||
ShowError("pc_setparam: Attempted to set unknown parameter '%d'.\n", type);
|
||||
return false;
|
||||
|
14
src/map/pc.h
14
src/map/pc.h
@ -31,6 +31,9 @@
|
||||
#define MAX_SPIRITCHARM 10 /// Max spirit charms
|
||||
|
||||
#define BANK_VAULT_VAR "#BANKVAULT"
|
||||
#define ROULETTE_BRONZE_VAR "RouletteBronze"
|
||||
#define ROULETTE_SILVER_VAR "RouletteSilver"
|
||||
#define ROULETTE_GOLD_VAR "RouletteGold"
|
||||
|
||||
//Update this max as necessary. 55 is the value needed for Super Baby currently
|
||||
//Raised to 84 since Expanded Super Novice needs it.
|
||||
@ -640,6 +643,17 @@ struct map_session_data {
|
||||
#ifdef PACKET_OBFUSCATION
|
||||
unsigned int cryptKey; ///< Packet obfuscation key to be used for the next received packet
|
||||
#endif
|
||||
|
||||
struct {
|
||||
int bronze, silver, gold; ///< Roulette Coin
|
||||
} roulette_point;
|
||||
|
||||
struct {
|
||||
short stage;
|
||||
short prizeIdx;
|
||||
short prizeStage;
|
||||
bool claimPrize;
|
||||
} roulette;
|
||||
};
|
||||
|
||||
struct eri *pc_sc_display_ers; /// Player's SC display table
|
||||
|
@ -10981,9 +10981,9 @@ BUILDIN_FUNC(changebase)
|
||||
}
|
||||
|
||||
/**
|
||||
* Change sec and unequip all item and request for a changesex to char-serv
|
||||
* Change account sex and unequip all item and request for a changesex to char-serv
|
||||
* changesex({<char_id>});
|
||||
**/
|
||||
*/
|
||||
BUILDIN_FUNC(changesex)
|
||||
{
|
||||
int i;
|
||||
@ -10994,12 +10994,42 @@ BUILDIN_FUNC(changesex)
|
||||
|
||||
pc_resetskill(sd,4);
|
||||
// to avoid any problem with equipment and invalid sex, equipment is unequiped.
|
||||
for( i=0; i<EQI_MAX; i++ )
|
||||
if( sd->equip_index[i] >= 0 ) pc_unequipitem(sd, sd->equip_index[i], 3);
|
||||
chrif_changesex(sd);
|
||||
for(i = 0; i < EQI_MAX; i++) {
|
||||
if (sd->equip_index[i] >= 0)
|
||||
pc_unequipitem(sd, sd->equip_index[i], 3);
|
||||
}
|
||||
|
||||
chrif_changesex(sd, true);
|
||||
return SCRIPT_CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change character's sex and unequip all item and request for a changesex to char-serv
|
||||
* changecharsex({<char_id>});
|
||||
*/
|
||||
BUILDIN_FUNC(changecharsex)
|
||||
{
|
||||
#if PACKETVER >= 20141016
|
||||
int i;
|
||||
TBL_PC *sd = NULL;
|
||||
|
||||
if (!script_charid2sd(2,sd))
|
||||
return SCRIPT_CMD_FAILURE;
|
||||
|
||||
pc_resetskill(sd,4);
|
||||
// to avoid any problem with equipment and invalid sex, equipment is unequiped.
|
||||
for (i = 0; i < EQI_MAX; i++) {
|
||||
if (sd->equip_index[i] >= 0)
|
||||
pc_unequipitem(sd, sd->equip_index[i], 3);
|
||||
}
|
||||
|
||||
chrif_changesex(sd, false);
|
||||
return SCRIPT_CMD_SUCCESS;
|
||||
#else
|
||||
return SCRIPT_CMD_FAILURE;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*==========================================
|
||||
* Works like 'announce' but outputs in the common chat window
|
||||
*------------------------------------------*/
|
||||
@ -20486,6 +20516,7 @@ struct script_function buildin_func[] = {
|
||||
BUILDIN_DEF(skillpointcount,"?"),
|
||||
BUILDIN_DEF(changebase,"i?"),
|
||||
BUILDIN_DEF(changesex,"?"),
|
||||
BUILDIN_DEF(changecharsex,"?"),
|
||||
BUILDIN_DEF(waitingroom,"si?????"),
|
||||
BUILDIN_DEF(delwaitingroom,"?"),
|
||||
BUILDIN_DEF2(waitingroomkickall,"kickwaitingroomall","?"),
|
||||
|
Loading…
x
Reference in New Issue
Block a user