diff --git a/data/dfndata/house/house_addons_ml.dfn b/data/dfndata/house/house_addons_ml.dfn new file mode 100644 index 000000000..57d6fe89d --- /dev/null +++ b/data/dfndata/house/house_addons_ml.dfn @@ -0,0 +1,828 @@ +// House Addon - Alchemist Table (East) +[HOUSE 300] +{ +ID=0x14F0 +SPACEX=1 +SPACEY=2 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=alchemisttabledeedeast +HOUSE_ITEM=1000 +HOUSE_ITEM=1001 +} + +// House Addon - Alchemist Table (South) +[HOUSE 301] +{ +ID=0x14F0 +SPACEX=2 +SPACEY=1 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=alchemisttablesouthdeed +HOUSE_ITEM=1002 +HOUSE_ITEM=1003 +} + +// House Addon - Elven Bed (East) +[HOUSE 302] +{ +ID=0x14F0 +SPACEX=2 +SPACEY=1 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=elvenbedeastdeed +HOUSE_ITEM=1004 +HOUSE_ITEM=1005 +} + +// House Addon - Elven Bed (South) +[HOUSE 303] +{ +ID=0x14F0 +SPACEX=1 +SPACEY=2 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=elvenbedsouthdeed +HOUSE_ITEM=1006 +HOUSE_ITEM=1007 +} + +// House Addon - Elven Loveseat (East) +[HOUSE 304] +{ +ID=0x14F0 +SPACEX=2 +SPACEY=1 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=elvenloveseateastdeed +HOUSE_ITEM=1008 +HOUSE_ITEM=1009 +} + +// House Addon - Elven Loveseat (South) +[HOUSE 305] +{ +ID=0x14F0 +SPACEX=1 +SPACEY=2 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=elvenloveseatsouthdeed +HOUSE_ITEM=1010 +HOUSE_ITEM=1011 +} + +// House Addon - Elven Wash Basin (East) +[HOUSE 306] +{ +ID=0x14F0 +SPACEX=1 +SPACEY=2 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=elvenwashbasineastdeed +HOUSE_ITEM=1012 +HOUSE_ITEM=1013 +} + +// House Addon - Elven Wash Basin (South) +[HOUSE 307] +{ +ID=0x14F0 +SPACEX=2 +SPACEY=1 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=elvenwashbasinsouthdeed +HOUSE_ITEM=1014 +HOUSE_ITEM=1015 +} + +// House Addon - Fancy Couch (East) +[HOUSE 308] +{ +ID=0x14F0 +SPACEX=1 +SPACEY=3 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=fancycoucheastdeed +HOUSE_ITEM=1016 +HOUSE_ITEM=1017 +HOUSE_ITEM=1018 +} + +// House Addon - Fancy Couch (North) +[HOUSE 309] +{ +ID=0x14F0 +SPACEX=3 +SPACEY=1 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=fancycouchnorthdeed +HOUSE_ITEM=1019 +HOUSE_ITEM=1020 +HOUSE_ITEM=1021 +} + +// House Addon - Fancy Couch (South) +[HOUSE 310] +{ +ID=0x14F0 +SPACEX=3 +SPACEY=1 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=fancycouchsouthdeed +HOUSE_ITEM=1022 +HOUSE_ITEM=1023 +HOUSE_ITEM=1024 +} + +// House Addon - Fancy Couch (West) +[HOUSE 311] +{ +ID=0x14F0 +SPACEX=1 +SPACEY=3 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=fancycouchwestdeed +HOUSE_ITEM=1025 +HOUSE_ITEM=1026 +HOUSE_ITEM=1027 +} + +// House Addon - Hardwood Table (East) +[HOUSE 312] +{ +ID=0x14F0 +SPACEX=3 +SPACEY=1 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=hardwoodtableeastdeed +HOUSE_ITEM=1028 +HOUSE_ITEM=1029 +HOUSE_ITEM=1030 +} + +// House Addon - Hardwood Table (South) +[HOUSE 313] +{ +ID=0x14F0 +SPACEX=1 +SPACEY=3 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=hardwoodtablesouthdeed +HOUSE_ITEM=1031 +HOUSE_ITEM=1032 +HOUSE_ITEM=1033 +} + +// House Addon - Fancy Loveseat (East) +[HOUSE 314] +{ +ID=0x14F0 +SPACEX=1 +SPACEY=2 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=fancyloveseateastdeed +HOUSE_ITEM=1034 +HOUSE_ITEM=1035 +} + +// House Addon - Fancy Loveseat (North) +[HOUSE 315] +{ +ID=0x14F0 +SPACEX=2 +SPACEY=1 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=fancyloveseatnorthdeed +HOUSE_ITEM=1036 +HOUSE_ITEM=1037 +} + +// House Addon - Fancy Loveseat (South) +[HOUSE 316] +{ +ID=0x14F0 +SPACEX=2 +SPACEY=1 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=fancyloveseatsouthdeed +HOUSE_ITEM=1038 +HOUSE_ITEM=1039 +} + +// House Addon - Fancy Loveseat (West) +[HOUSE 317] +{ +ID=0x14F0 +SPACEX=1 +SPACEY=2 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=fancyloveseatwestdeed +HOUSE_ITEM=1040 +HOUSE_ITEM=1041 +} + +// House Addon - Ornate Table (East) +[HOUSE 318] +{ +ID=0x14F0 +SPACEX=1 +SPACEY=3 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=ornatetableeastdeed +HOUSE_ITEM=1042 +HOUSE_ITEM=1043 +HOUSE_ITEM=1044 +} + +// House Addon - Ornate Table (South) +[HOUSE 319] +{ +ID=0x14F0 +SPACEX=3 +SPACEY=1 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=ornatetablesouthdeed +HOUSE_ITEM=1045 +HOUSE_ITEM=1046 +HOUSE_ITEM=1047 +} + +// House Addon - Plush Loveseat (East) +[HOUSE 320] +{ +ID=0x14F0 +SPACEX=1 +SPACEY=2 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=plushloveseateastdeed +HOUSE_ITEM=1048 +HOUSE_ITEM=1049 +} + +// House Addon - Plush Loveseat (South) +[HOUSE 321] +{ +ID=0x14F0 +SPACEX=2 +SPACEY=1 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=plushloveseatsouthdeed +HOUSE_ITEM=1050 +HOUSE_ITEM=1051 +} + +// House Addon - Tall Elven Bed (East) +[HOUSE 322] +{ +ID=0x14F0 +SPACEX=3 +SPACEY=2 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=tallelvenbedeastdeed +HOUSE_ITEM=1052 +HOUSE_ITEM=1053 +HOUSE_ITEM=1054 +HOUSE_ITEM=1055 +} + +// House Addon - Tall Elven Bed (South) +[HOUSE 323] +{ +ID=0x14F0 +SPACEX=2 +SPACEY=3 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=tallelvenbedsouthdeed +HOUSE_ITEM=1056 +HOUSE_ITEM=1057 +HOUSE_ITEM=1058 +HOUSE_ITEM=1059 +} + +[HOUSE ITEM 1000] +{ alchemist table part 1 (east) +ITEM=0x3077 +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1001] +{ alchemist table part 2 (east) +ITEM=0x3078 +X=0 +Y=-1 +Z=0 +} + +[HOUSE ITEM 1002] +{ alchemist table part 1 (south) +ITEM=0x3079 +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1003] +{ alchemist table part 2 (south) +ITEM=0x307A +X=-1 +Y=0 +Z=0 +} + +[HOUSE ITEM 1004] +{ elven bed part 1 (east) +ITEM=0x304D +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1005] +{ elven bed part 2 (east) +ITEM=0x304C +X=1 +Y=0 +Z=0 +} + +[HOUSE ITEM 1006] +{ elven bed part 1 (south) +ITEM=0x3050 +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1007] +{ +elven bed part 2 (south) +ITEM=0x3051 +X=0 +Y=-1 +Z=0 +} + +[HOUSE ITEM 1008] +{ elven loveseat part 1 (east) +ITEM=0x3089 +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1009] +{ elven loveseat part 2 (east) +ITEM=0x3088 +X=1 +Y=0 +Z=0 +} + +[HOUSE ITEM 1010] +{ elven loveseat part 1 (south) +ITEM=0x308A +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1011] +{ elven loveseat part 2 (south) +ITEM=0x308B +X=0 +Y=-1 +Z=0 +} + +[HOUSE ITEM 1012] +{ elven wash basin part 1 (east) +ITEM=0x30DF +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1013] +{ elven wash basin part 2 (east) +ITEM=0x30E0 +X=0 +Y=1 +Z=0 +} + +[HOUSE ITEM 1014] +{ elven wash basin part 1 (south) +ITEM=0x30E1 +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1015] +{ elven wash basin part 2 (south) +ITEM=0x30E2 +X=1 +Y=0 +Z=0 +} + +[HOUSE ITEM 1016] +{ fancy couch part 1 (east) +ITEM=0x4C8C +X=0 +Y=-1 +Z=0 +} + +[HOUSE ITEM 1017] +{ fancy couch part 2 (east) +ITEM=0x4C8A +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1018] +{ fancy couch part 3 (east) +ITEM=0x4C8B +X=0 +Y=1 +Z=0 +} + +[HOUSE ITEM 1019] +{ fancy couch part 1 (north) +ITEM=0x9C62 +X=-1 +Y=0 +Z=0 +} + +[HOUSE ITEM 1020] +{ fancy couch part 2 (north) +ITEM=0x9C61 +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1021] +{ fancy couch part 3 (north) +ITEM=0x9C60 +X=1 +Y=0 +Z=0 +} + +[HOUSE ITEM 1022] +{ fancy couch part 1 (south) +ITEM=0x4C8D +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1023] +{ fancy couch part 2 (south) +ITEM=0x4C8E +X=-1 +Y=0 +Z=0 +} + +[HOUSE ITEM 1024] +{ fancy couch part 3 (south) +ITEM=0x4C8F +X=1 +Y=0 +Z=0 +} + +[HOUSE ITEM 1025] +{ fancy couch part 1 (west) +ITEM=0x9C5F +X=0 +Y=-1 +Z=0 +} + +[HOUSE ITEM 1026] +{ fancy couch part 2 (west) +ITEM=0x9C5E +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1027] +{ fancy couch part 3 (west) +ITEM=0x9C5D +X=0 +Y=1 +Z=0 +} + +[HOUSE ITEM 1028] +{ hardwood table part 1 (east) +ITEM=0x3094 +X=-1 +Y=0 +Z=0 +} + +[HOUSE ITEM 1029] +{ hardwood table part 2 (east) +ITEM=0x3093 +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1030] +{ hardwood table part 3 (east) +ITEM=0x3092 +X=1 +Y=0 +Z=0 +} + +[HOUSE ITEM 1031] +{ hardwood table part 1 (south) +ITEM=0x3095 +X=0 +Y=1 +Z=0 +} + +[HOUSE ITEM 1032] +{ hardwood table part 2 (south) +ITEM=0x3096 +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1033] +{ hardwood table part 3 (south) +ITEM=0x3097 +X=0 +Y=-1 +Z=0 +} + +[HOUSE ITEM 1034] +{ fancy loveseat part 1 (east) +ITEM=0x4C88 +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1035] +{ fancy loveseat part 2 (east) +ITEM=0x4C89 +X=0 +Y=1 +Z=0 +} + +[HOUSE ITEM 1036] +{ fancy loveseat part 1 (north) +ITEM=0x9C5A +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1037] +{ fancy loveseat part 2 (north) +ITEM=0x9C59 +X=1 +Y=0 +Z=0 +} + +[HOUSE ITEM 1038] +{ fancy loveseat part 1 (south) +ITEM=0x4C87 +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1039] +{ fancy loveseat part 2 (south) +ITEM=0x4C86 +X=1 +Y=0 +Z=0 +} + +[HOUSE ITEM 1040] +{ fancy loveseat part 1 (west) +ITEM=0x9C58 +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1041] +{ fancy loveseat part 2 (west) +ITEM=0x9C57 +X=0 +Y=1 +Z=0 +} + +[HOUSE ITEM 1042] +{ ornate table part 1 (east) +ITEM=0x308F +X=0 +Y=1 +Z=0 +} + +[HOUSE ITEM 1043] +{ ornate table part 2 (east) +ITEM=0x3090 +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1044] +{ ornate table part 3 (east) +ITEM=0x3091 +X=0 +Y=-1 +Z=0 +} + +[HOUSE ITEM 1045] +{ ornate table part 1 (south) +ITEM=0x308E +X=-1 +Y=0 +Z=0 +} + +[HOUSE ITEM 1046] +{ ornate table part 2 (south) +ITEM=0x308D +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1047] +{ ornate table part 3 (south) +ITEM=0x308C +X=1 +Y=0 +Z=0 +} + +[HOUSE ITEM 1048] +{ plush loveseat part 1 (east) +ITEM=0x4C84 +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1049] +{ plush loveseat part 2 (east) +ITEM=0x4C85 +X=0 +Y=1 +Z=0 +} + +[HOUSE ITEM 1050] +{ plush loveseat part 1 (south) +ITEM=0x4C83 +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1051] +{ plush loveseat part 2 (south) +ITEM=0x4C82 +X=1 +Y=0 +Z=0 +} + +[HOUSE ITEM 1052] +{ tall elven bed part 1 (east) +ITEM=0x3054 +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1053] +{ tall elven bed part 2 (east) +ITEM=0x3053 +X=1 +Y=0 +Z=0 +} + +[HOUSE ITEM 1054] +{ tall elven bed part 3 (east) +ITEM=0x3055 +X=2 +Y=-1 +Z=0 +} + +[HOUSE ITEM 1055] +{ tall elven bed part 4 (east) +ITEM=0x3052 +X=2 +Y=0 +Z=0 +} + +[HOUSE ITEM 1056] +{ tall elven bed part 1 (south) +ITEM=0x3058 +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1057] +{ tall elven bed part 2 (south) +ITEM=0x3057 +X=-1 +Y=1 +Z=0 +} + +[HOUSE ITEM 1058] +{ tall elven bed part 3 (south) +ITEM=0x3059 +X=0 +Y=-1 +Z=0 +} + +[HOUSE ITEM 1059] +{ tall elven bed part 4 (south) +ITEM=0x3056 +X=0 +Y=1 +Z=0 +} \ No newline at end of file diff --git a/data/dfndata/house/house_aos.dfn b/data/dfndata/house/house_aos.dfn new file mode 100644 index 000000000..b601740ca --- /dev/null +++ b/data/dfndata/house/house_aos.dfn @@ -0,0 +1,290 @@ +// House Addon - Mini House: Stone and Plaster +[HOUSE 500] +{ +ID=0x14F0 +SPACEX=1 +SPACEY=1 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=stoneandplastermini +HOUSE_ITEM=1500 +} + +// House Addon - Mini House: Field Stone +[HOUSE 501] +{ +ID=0x14F0 +SPACEX=1 +SPACEY=1 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=fieldstonemini +HOUSE_ITEM=1501 +} + +// House Addon - Mini House: Small Brick +[HOUSE 502] +{ +ID=0x14F0 +SPACEX=1 +SPACEY=1 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=smallbrickmini +HOUSE_ITEM=1502 +} + +// House Addon - Mini House: Wooden +[HOUSE 503] +{ +ID=0x14F0 +SPACEX=1 +SPACEY=1 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=woodenmini +HOUSE_ITEM=1503 +} + +// House Addon - Mini House: Wood and Plaster +[HOUSE 504] +{ +ID=0x14F0 +SPACEX=1 +SPACEY=1 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=woodandplastermini +HOUSE_ITEM=1504 +} + +// House Addon - Mini House: Thatched-Roof Cottage +[HOUSE 505] +{ +ID=0x14F0 +SPACEX=1 +SPACEY=1 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=thatchedroofcottage +HOUSE_ITEM=1505 +} + +// House Addon - Mini House: Brick +[HOUSE 506] +{ +ID=0x14F0 +SPACEX=4 +SPACEY=1 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=brickmini +HOUSE_ITEM=1506 +HOUSE_ITEM=1507 +HOUSE_ITEM=1508 +HOUSE_ITEM=1509 +} + +// House Addon - Mini House: Two-Story Wood and Plaster +[HOUSE 507] +{ +ID=0x14F0 +SPACEX=2 +SPACEY=2 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=twostorywoodandplastermini +HOUSE_ITEM=1510 +HOUSE_ITEM=1511 +HOUSE_ITEM=1512 +HOUSE_ITEM=1513 +} + +// House Addon - Mini House: Malas Mountain Pass +[HOUSE 508] +{ +ID=0x14F0 +SPACEX=2 +SPACEY=2 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=malasmountainpassmini +HOUSE_ITEM=1514 +HOUSE_ITEM=1515 +HOUSE_ITEM=1516 +HOUSE_ITEM=1517 +} + +// House Addon - Mini House: Church at Night +[HOUSE 509] +{ +ID=0x14F0 +SPACEX=1 +SPACEY=1 +CHARX=0 +CHARY=0 +CHARZ=0 +HOUSE_DEED=churchatnightmini +HOUSE_ITEM=1518 +} + +[HOUSE ITEM 1500] +{ mini house part 1 (Stone and Plaster) +ITEM=0x22C4 +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1501] +{ mini house part 1 (Field Stone) +ITEM=0x22DE +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1502] +{ mini house part 1 (Small Brick) +ITEM=0x22DF +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1503] +{ mini house part 1 (Wooden) +ITEM=0x22C9 +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1504] +{ mini house part 1 (Wood and Plaster) +ITEM=0x22E0 +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1505] +{ mini house part 1 (Thatched-Roof Cottage) +ITEM=0x22E1 +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1506] +{ mini house part 1 (Brick) +ITEM=0x22CD +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1507] +{ mini house part 2 (Brick) +ITEM=0x22CB +X=1 +Y=0 +Z=0 +} + +[HOUSE ITEM 1508] +{ mini house part 3 (Brick) +ITEM=0x22CC +X=2 +Y=0 +Z=0 +} + +[HOUSE ITEM 1509] +{ mini house part 4 (Brick) +ITEM=0x22CA +X=3 +Y=0 +Z=0 +} + +[HOUSE ITEM 1510] +{ mini house part 1 (Two-Story Wood and Plaster) +ITEM=0x2301 +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1511] +{ mini house part 2 (Two-Story Wood and Plaster) +ITEM=0x2302 +X=1 +Y=0 +Z=0 +} + +[HOUSE ITEM 1512] +{ mini house part 3 (Two-Story Wood and Plaster) +ITEM=0x2304 +X=0 +Y=1 +Z=0 +} + +[HOUSE ITEM 1513] +{ mini house part 4 (Two-Story Wood and Plaster) +ITEM=0x2303 +X=1 +Y=1 +Z=0 +} + +[HOUSE ITEM 1514] +{ mini house part 1 (Malas Mountain Pass) +ITEM=0x2316 +X=0 +Y=0 +Z=0 +} + +[HOUSE ITEM 1515] +{ mini house part 2 (Malas Mountain Pass) +ITEM=0x2315 +X=1 +Y=0 +Z=0 +} + +[HOUSE ITEM 1516] +{ mini house part 3 (Malas Mountain Pass) +ITEM=0x2314 +X=0 +Y=1 +Z=0 +} + +[HOUSE ITEM 1517] +{ mini house part 4 (Malas Mountain Pass) +ITEM=0x2313 +X=1 +Y=1 +Z=0 +} + +[HOUSE ITEM 1518] +{ mini house part 1 (Church at Night) +ITEM=0x2318 +X=0 +Y=0 +Z=0 +} \ No newline at end of file diff --git a/data/dfndata/items/ItemMenu.bulk.dfn b/data/dfndata/items/ItemMenu.bulk.dfn index 0da06b87d..7c3e65809 100644 --- a/data/dfndata/items/ItemMenu.bulk.dfn +++ b/data/dfndata/items/ItemMenu.bulk.dfn @@ -9097,6 +9097,8 @@ ADDITEM=0x0e7c ADDITEM=0x0e40 0x0e41=metal chest ADDITEM=0x0e41 +0x0e41=Puzzle Chest +ADDITEM=puzzlechest <=Previous Menu ITEMMENU=3 } @@ -14253,3 +14255,85 @@ ADDITEM=mapmakerspen <=Previous Menu ITEMMENU=127 } + +[ITEMMENU 260] +{ +Houseaddon_ML_Deeds.dfn +0x14F0=Elven Bed (East) +ADDITEM=elvenbedeastdeed +0x14F0=Elven Bed (South) +ADDITEM=elvenbedsouthdeed +0x14F0=Alchemist Table (East) +ADDITEM=alchemisttabledeedeast +0x14F0=Alchemist Table (South) +ADDITEM=alchemisttablesouthdeed +0x14F0=Elven Loveseat (East) +ADDITEM=elvenloveseateastdeed +0x14F0=Elven Loveseat (South) +ADDITEM=elvenloveseatsouthdeed +0x14F0=Elven Wash Basin (East) +ADDITEM=elvenwashbasineastdeed +0x14F0=Elven Wash Basin (South) +ADDITEM=elvenwashbasinsouthdeed +0x14F0=Fancy Couch (East) +ADDITEM=fancycoucheastdeed +0x14F0=Fancy Couch (North) +ADDITEM=fancycouchnorthdeed +0x14F0=Fancy Couch (South) +ADDITEM=fancycouchsouthdeed +0x14F0=Fancy Couch (West) +ADDITEM=fancycouchwestdeed +0x14F0=Hardwood Table (East) +ADDITEM=hardwoodtableeastdeed +0x14F0=Hardwood Table (South) +ADDITEM=hardwoodtablesouthdeed +0x14F0=Fancy Loveseat (East) +ADDITEM=fancyloveseateastdeed +0x14F0=Fancy Loveseat (North) +ADDITEM=fancyloveseatnorthdeed +0x14F0=Fancy Loveseat (South) +ADDITEM=fancyloveseatsouthdeed +0x14F0=Fancy Loveseat (West) +ADDITEM=fancyloveseatwestdeed +0x14F0=Ornate Table (East) +ADDITEM=ornatetableeastdeed +0x14F0=Ornate Table (South) +ADDITEM=ornatetablesouthdeed +0x14F0=Plush Loveseat (East) +ADDITEM=plushloveseateastdeed +0x14F0=Plush Loveseat (South) +ADDITEM=plushloveseatsouthdeed +0x14F0=Tall Elven Bed (East) +ADDITEM=tallelvenbedeastdeed +0x14F0=Tall Elven Bed (South) +ADDITEM=tallelvenbedsouthdeed +<=Previous Menu +ITEMMENU=4 +} + +[ITEMMENU 261] +{ +minihouseaddon_deeds.dfn +0x14F0=Mini House: Stone and Plaster +ADDITEM=stoneandplastermini +0x14F0=Mini House: Field Stone +ADDITEM=fieldstonemini +0x14F0=Mini House: Small Brick +ADDITEM=smallbrickmini +0x14F0=Mini House: Wooden +ADDITEM=woodenmini +0x14F0=Mini House: Wood and Plaster +ADDITEM=woodandplastermini +0x14F0=Mini House: Thatched-Roof Cottage +ADDITEM=thatchedroofcottage +0x14F0=Mini House: Brick +ADDITEM=brickmini +0x14F0=Mini House: Two-Story Wood and Plaster +ADDITEM=twostorywoodandplastermini +0x14F0=Mini House: Malas Mountain Pass +ADDITEM=malasmountainpassmini +0x14F0=Mini House: Church at Night +ADDITEM=churchatnightmini +<=Previous Menu +ITEMMENU=4 +} diff --git a/data/dfndata/items/ItemMenu.dfn b/data/dfndata/items/ItemMenu.dfn index 7815ab7f7..8b0ffc0ac 100644 --- a/data/dfndata/items/ItemMenu.dfn +++ b/data/dfndata/items/ItemMenu.dfn @@ -303,6 +303,10 @@ ITEMMENU=68 ITEMMENU=69 <=Houseaddon Deeds ITEMMENU=71 +<=Houseaddon ML Deeds +ITEMMENU=260 +<=Mini Houseaddon Deeds +ITEMMENU=261 <=Misc Deeds ITEMMENU=70 <=Previous Menu diff --git a/data/dfndata/items/building/furniture/furniture_ml.dfn b/data/dfndata/items/building/furniture/furniture_ml.dfn new file mode 100644 index 000000000..89bfaff42 --- /dev/null +++ b/data/dfndata/items/building/furniture/furniture_ml.dfn @@ -0,0 +1,539 @@ +// Elven Bed (East) +[0x304D] +{ +get=base_item +name=Elven Bed (East) Part 1 +id=0x304D +weight=1000 +movable=1 +origin=ml +} + +[0x304C] +{ +get=base_item +name=Elven Bed (East) Part 2 +id=0x304C +weight=1000 +movable=1 +origin=ml +} + +// Elven Bed (South) +[0x3050] +{ +get=base_item +name=Elven Bed (South) Part 1 +id=0x3050 +weight=1000 +movable=1 +origin=ml +} + +[0x3051] +{ +get=base_item +name=Elven Bed (South) Part 2 +id=0x3051 +weight=1000 +movable=1 +origin=ml +} + +// Alchemist Table (East) +[0x3077] +{ +get=base_item +name=Alchemist Table (East) Part 1 +id=0x3077 +weight=1000 +movable=1 +origin=ml +} + +[0x3078] +{ +get=base_item +name=Alchemist Table (East) Part 2 +id=0x3078 +weight=1000 +movable=1 +origin=ml +} + +// Alchemist Table (South) +[0x3079] +{ +get=base_item +name=Alchemist Table (South) Part 1 +id=0x3079 +weight=1000 +movable=1 +origin=ml +} + +[0x307A] +{ +get=base_item +name=Alchemist Table (South) Part 2 +id=0x307A +weight=1000 +movable=1 +origin=ml +} + +// Elven Loveseat (East) +[0x3089] +{ +get=base_item +name=Elven Loveseat (East) Part 1 +id=0x3089 +weight=1000 +movable=1 +origin=ml +} + +[0x3088] +{ +get=base_item +name=Elven Loveseat (East) Part 2 +id=0x3088 +weight=1000 +movable=1 +origin=ml +} + +// Elven Loveseat (South) +[0x308A] +{ +get=base_item +name=Elven Loveseat (South) Part 1 +id=0x308A +weight=1000 +movable=1 +origin=ml +} + +[0x308B] +{ +get=base_item +name=Elven Loveseat (South) Part 2 +id=0x308B +weight=1000 +movable=1 +origin=ml +} + +// Elven Wash Basin (East) +[0x30DF] +{ +get=base_item +name=Elven Wash Basin (East) Part 1 +id=0x30DF +weight=1000 +movable=1 +origin=ml +} + +[0x30E0] +{ +get=base_item +name=Elven Wash Basin (East) Part 2 +id=0x30E0 +weight=1000 +movable=1 +origin=ml +} + +// Elven Wash Basin (South) +[0x30E1] +{ +get=base_item +name=Elven Wash Basin (South) Part 1 +id=0x30E1 +weight=1000 +movable=1 +origin=ml +} + +[0x30E2] +{ +get=base_item +name=Elven Wash Basin (South) Part 2 +id=0x30E2 +weight=1000 +movable=1 +origin=ml +} + +// Fancy Couch (East) +[0x4C8C] +{ +get=base_item +name=Fancy Couch (East) Part 1 +id=0x4C8C +weight=1000 +movable=1 +origin=ml +} + +[0x4C8A] +{ +get=base_item +name=Fancy Couch (East) Part 2 +id=0x4C8A +weight=1000 +movable=1 +origin=ml +} + +[0x4C8B] +{ +get=base_item +name=Fancy Couch (East) Part 3 +id=0x4C8B +weight=1000 +movable=1 +origin=ml +} + +// Fancy Couch (North) +[0x9C62] +{ +get=base_item +name=Fancy Couch (North) Part 1 +id=0x9C62 +weight=1000 +movable=1 +origin=ml +} + +[0x9C61] +{ +get=base_item +name=Fancy Couch (North) Part 2 +id=0x9C61 +weight=1000 +movable=1 +origin=ml +} + +[0x9C60] +{ +get=base_item +name=Fancy Couch (North) Part 3 +id=0x9C60 +weight=1000 +movable=1 +origin=ml +} + +// Fancy Couch (South) +[0x4C8D] +{ +get=base_item +name=Fancy Couch (South) Part 1 +id=0x4C8D +weight=1000 +movable=1 +origin=ml +} + +[0x4C8E] +{ +get=base_item +name=Fancy Couch (South) Part 2 +id=0x4C8E +weight=1000 +movable=1 +origin=ml +} + +[0x4C8F] +{ +get=base_item +name=Fancy Couch (South) Part 3 +id=0x4C8F +weight=1000 +movable=1 +origin=ml +} + +// Fancy Couch (West) +[0x9C5F] +{ +get=base_item +name=Fancy Couch (West) Part 1 +id=0x9C5F +weight=1000 +movable=1 +origin=ml +} + +[0x9C5E] +{ +get=base_item +name=Fancy Couch (West) Part 2 +id=0x9C5E +weight=1000 +movable=1 +origin=ml +} + +[0x9C5D] +{ +get=base_item +name=Fancy Couch (West) Part 3 +id=0x9C5D +weight=1000 +movable=1 +origin=ml +} + +// Hardwood Table (East) +[0x3094] +{ +get=base_item +name=Hardwood Table (East) Part 1 +id=0x3094 +weight=1000 +movable=1 +origin=ml +} + +[0x3093] +{ +get=base_item +name=Hardwood Table (East) Part 2 +id=0x3093 +weight=1000 +movable=1 +origin=ml +} + +[0x3092] +{ +get=base_item +name=Hardwood Table (East) Part 3 +id=0x3092 +weight=1000 +movable=1 +origin=ml +} + +// Hardwood Table (South) +[0x3095] +{ +get=base_item +name=Hardwood Table (South) Part 1 +id=0x3095 +weight=1000 +movable=1 +origin=ml +} + +[0x3096] +{ +get=base_item +name=Hardwood Table (South) Part 2 +id=0x3096 +weight=1000 +movable=1 +origin=ml +} + +[0x3097] +{ +get=base_item +name=Hardwood Table (South) Part 3 +id=0x3097 +weight=1000 +movable=1 +origin=ml +} + +// Ornate Table (East) +[0x308F] +{ +get=base_item +name=Ornate Table (East) Part 1 +id=0x308F +weight=1000 +movable=1 +origin=ml +} + +[0x3090] +{ +get=base_item +name=Ornate Table (East) Part 2 +id=0x3090 +weight=1000 +movable=1 +origin=ml +} + +[0x3091] +{ +get=base_item +name=Ornate Table (East) Part 3 +id=0x3091 +weight=1000 +movable=1 +origin=ml +} + +// Ornate Table (South) +[0x308E] +{ +get=base_item +name=Ornate Table (South) Part 1 +id=0x308E +weight=1000 +movable=1 +origin=ml +} + +[0x308D] +{ +get=base_item +name=Ornate Table (South) Part 2 +id=0x308D +weight=1000 +movable=1 +origin=ml +} + +[0x308C] +{ +get=base_item +name=Ornate Table (South) Part 3 +id=0x308C +weight=1000 +movable=1 +origin=ml +} + +// Plush Loveseat (East) +[0x4C84] +{ +get=base_item +name=Plush Loveseat (East) Part 1 +id=0x4C84 +weight=1000 +movable=1 +origin=ml +} + +[0x4C85] +{ +get=base_item +name=Plush Loveseat (East) Part 2 +id=0x4C85 +weight=1000 +movable=1 +origin=ml +} + +// Plush Loveseat (South) +[0x4C83] +{ +get=base_item +name=Plush Loveseat (South) Part 1 +id=0x4C83 +weight=1000 +movable=1 +origin=ml +} + +[0x4C82] +{ +get=base_item +name=Plush Loveseat (South) Part 2 +id=0x4C82 +weight=1000 +movable=1 +origin=ml +} + +// Tall Elven Bed (East) +[0x3054] +{ +get=base_item +name=Tall Elven Bed (East) Part 1 +id=0x3054 +weight=1000 +movable=1 +origin=ml +} + +[0x3053] +{ +get=base_item +name=Tall Elven Bed (East) Part 2 +id=0x3053 +weight=1000 +movable=1 +origin=ml +} + +[0x3055] +{ +get=base_item +name=Tall Elven Bed (East) Part 3 +id=0x3055 +weight=1000 +movable=1 +origin=ml +} + +[0x3052] +{ +get=base_item +name=Tall Elven Bed (East) Part 4 +id=0x3052 +weight=1000 +movable=1 +origin=ml +} + +// Tall Elven Bed (South) +[0x3058] +{ +get=base_item +name=Tall Elven Bed (South) Part 1 +id=0x3058 +weight=1000 +movable=1 +origin=ml +} + +[0x3057] +{ +get=base_item +name=Tall Elven Bed (South) Part 2 +id=0x3057 +weight=1000 +movable=1 +origin=ml +} + +[0x3059] +{ +get=base_item +name=Tall Elven Bed (South) Part 3 +id=0x3059 +weight=1000 +movable=1 +origin=ml +} + +[0x3056] +{ +get=base_item +name=Tall Elven Bed (South) Part 4 +id=0x3056 +weight=1000 +movable=1 +origin=ml +} \ No newline at end of file diff --git a/data/dfndata/items/building/furniture/minihouse_parts.dfn b/data/dfndata/items/building/furniture/minihouse_parts.dfn new file mode 100644 index 000000000..9385ee133 --- /dev/null +++ b/data/dfndata/items/building/furniture/minihouse_parts.dfn @@ -0,0 +1,199 @@ +// Base Item for Mini House: Stone and Plaster +[0x22C4] +{ +get=base_item +name=Mini House: Stone and Plaster +id=0x22C4 +weight=1000 +movable=1 +origin=aos +} + +// Base Item for Mini House: Field Stone +[0x22DE] +{ +get=base_item +name=Mini House: Field Stone +id=0x22DE +weight=1000 +movable=1 +origin=aos +} + +// Base Item for Mini House: Small Brick +[0x22DF] +{ +get=base_item +name=Mini House: Small Brick +id=0x22DF +weight=1000 +movable=1 +origin=aos +} + +// Base Item for Mini House: Wooden +[0x22C9] +{ +get=base_item +name=Mini House: Wooden +id=0x22C9 +weight=1000 +movable=1 +origin=aos +} + +// Base Item for Mini House: Wood and Plaster +[0x22E0] +{ +get=base_item +name=Mini House: Wood and Plaster +id=0x22E0 +weight=1000 +movable=1 +origin=aos +} + +// Base Item for Mini House: Thatched-Roof Cottage +[0x22E1] +{ +get=base_item +name=Mini House: Thatched-Roof Cottage +id=0x22E1 +weight=1000 +movable=1 +origin=aos +} + +// Base Items for Mini House: Brick +[0x22CD] +{ +get=base_item +name=Mini House: Brick Part 1 +id=0x22CD +weight=1000 +movable=1 +origin=aos +} + +[0x22CB] +{ +get=base_item +name=Mini House: Brick Part 2 +id=0x22CB +weight=1000 +movable=1 +origin=aos +} + +[0x22CC] +{ +get=base_item +name=Mini House: Brick Part 3 +id=0x22CC +weight=1000 +movable=1 +origin=aos +} + +[0x22CA] +{ +get=base_item +name=Mini House: Brick Part 4 +id=0x22CA +weight=1000 +movable=1 +origin=aos +} + +// Base Items for Mini House: Two-Story Wood and Plaster +[0x2301] +{ +get=base_item +name=Mini House: Two-Story Wood and Plaster Part 1 +id=0x2301 +weight=1000 +movable=1 +origin=aos +} + +[0x2302] +{ +get=base_item +name=Mini House: Two-Story Wood and Plaster Part 2 +id=0x2302 +weight=1000 +movable=1 +origin=aos +} + +[0x2304] +{ +get=base_item +name=Mini House: Two-Story Wood and Plaster Part 3 +id=0x2304 +weight=1000 +movable=1 +origin=aos +} + +[0x2303] +{ +get=base_item +name=Mini House: Two-Story Wood and Plaster Part 4 +id=0x2303 +weight=1000 +movable=1 +origin=aos +} + +// Base Items for Mini House: Malas Mountain Pass +[0x2316] +{ +get=base_item +name=Mini House: Malas Mountain Pass Part 1 +id=0x2316 +weight=1000 +movable=1 +origin=aos +} + +[0x2315] +{ +get=base_item +name=Mini House: Malas Mountain Pass Part 2 +id=0x2315 +weight=1000 +movable=1 +origin=aos +} + +[0x2314] +{ +get=base_item +name=Mini House: Malas Mountain Pass Part 3 +id=0x2314 +weight=1000 +movable=1 +origin=aos +} + +[0x2313] +{ +get=base_item +name=Mini House: Malas Mountain Pass Part 4 +id=0x2313 +weight=1000 +movable=1 +origin=aos +} + +// Base Item for Mini House: Church at Night +[0x2318] +{ +get=base_item +name=Mini House: Church at Night +id=0x2318 +weight=1000 +movable=1 +origin=aos +} \ No newline at end of file diff --git a/data/dfndata/items/containers/metal.dfn b/data/dfndata/items/containers/metal.dfn index d891d69a2..e4309af33 100644 --- a/data/dfndata/items/containers/metal.dfn +++ b/data/dfndata/items/containers/metal.dfn @@ -134,3 +134,13 @@ maxitems=125 { get=0x0e40 0x0e41 } + +[puzzlechest] +{ +get=base_item +name=metal chest +id=0x0e41 +movable=2 +script=5061 +origin=uor +} diff --git a/data/dfndata/items/deeds/houseaddon_deeds_ml.dfn b/data/dfndata/items/deeds/houseaddon_deeds_ml.dfn new file mode 100644 index 000000000..59ffb2c8e --- /dev/null +++ b/data/dfndata/items/deeds/houseaddon_deeds_ml.dfn @@ -0,0 +1,215 @@ +// Elven Bed (East) Deed +[elvenbedeastdeed] +{ +name=Elven Bed (East) +id=0x14F0 +morex=300 +origin=ml +} + +// Elven Bed (South) Deed +[elvenbedsouthdeed] +{ +name=Elven Bed (South) +id=0x14F0 +morex=301 +origin=ml +} + +// Alchemist Table (East) Deed +[alchemisttabledeedeast] +{ +name=Alchemist Table (East) +id=0x14F0 +morex=300 +origin=ml +} + +// Alchemist Table (South) Deed +[alchemisttablesouthdeed] +{ +name=Alchemist Table (South) +id=0x14F0 +morex=301 +origin=ml +} + +// Elven Loveseat (East) Deed +[elvenloveseateastdeed] +{ +name=Elven Loveseat (East) +id=0x14F0 +morex=304 +origin=ml +} + +// Elven Loveseat (South) Deed +[elvenloveseatsouthdeed] +{ +name=Elven Loveseat (South) +id=0x14F0 +morex=305 +origin=ml +} + +// Elven Wash Basin (East) Deed +[elvenwashbasineastdeed] +{ +name=Elven Wash Basin (East) +id=0x14F0 +morex=306 +origin=ml +} + +// Elven Wash Basin (South) Deed +[elvenwashbasinsouthdeed] +{ +name=Elven Wash Basin (South) +id=0x14F0 +morex=307 +origin=ml +} + +// Fancy Couch (East) Deed +[fancycoucheastdeed] +{ +name=Fancy Couch (East) +id=0x14F0 +morex=308 +origin=ml +} + +// Fancy Couch (North) Deed +[fancycouchnorthdeed] +{ +name=Fancy Couch (North) +id=0x14F0 +morex=309 +origin=ml +} + +// Fancy Couch (South) Deed +[fancycouchsouthdeed] +{ +name=Fancy Couch (South) +id=0x14F0 +morex=310 +origin=ml +} + +// Fancy Couch (West) Deed +[fancycouchwestdeed] +{ +name=Fancy Couch (West) +id=0x14F0 +morex=311 +origin=ml +} + +// Hardwood Table (East) Deed +[hardwoodtableeastdeed] +{ +name=Hardwood Table (East) +id=0x14F0 +morex=312 +origin=ml +} + +// Hardwood Table (South) Deed +[hardwoodtablesouthdeed] +{ +name=Hardwood Table (South) +id=0x14F0 +morex=313 +origin=ml +} + +// Fancy Loveseat (East) Deed +[fancyloveseateastdeed] +{ +name=Fancy Loveseat (East) +id=0x14F0 +morex=314 +origin=ml +} + +// Fancy Loveseat (North) Deed +[fancyloveseatnorthdeed] +{ +name=Fancy Loveseat (North) +id=0x14F0 +morex=315 +origin=ml +} + +// Fancy Loveseat (South) Deed +[fancyloveseatsouthdeed] +{ +name=Fancy Loveseat (South) +id=0x14F0 +morex=316 +origin=ml +} + +// Fancy Loveseat (West) Deed +[fancyloveseatwestdeed] +{ +name=Fancy Loveseat (West) +id=0x14F0 +morex=317 +origin=ml +} + +// Ornate Table (East) Deed +[ornatetableeastdeed] +{ +name=Ornate Table (East) +id=0x14F0 +morex=318 +origin=ml +} + +// Ornate Table (South) Deed +[ornatetablesouthdeed] +{ +name=Ornate Table (South) +id=0x14F0 +morex=319 +origin=ml +} + +// Plush Loveseat (East) Deed +[plushloveseateastdeed] +{ +name=Plush Loveseat (East) +id=0x14F0 +morex=320 +origin=ml +} + +// Plush Loveseat (South) Deed +[plushloveseatsouthdeed] +{ +name=Plush Loveseat (South) +id=0x14F0 +morex=321 +origin=ml +} + +// Tall Elven Bed (East) Deed +[tallelvenbedeastdeed] +{ +name=Tall Elven Bed (East) +id=0x14F0 +morex=322 +origin=ml +} + +// Tall Elven Bed (South) Deed +[tallelvenbedsouthdeed] +{ +name=Tall Elven Bed (South) +id=0x14F0 +morex=323 +origin=ml +} \ No newline at end of file diff --git a/data/dfndata/items/deeds/minihouseaddon_deeds.dfn b/data/dfndata/items/deeds/minihouseaddon_deeds.dfn new file mode 100644 index 000000000..e9fa79f11 --- /dev/null +++ b/data/dfndata/items/deeds/minihouseaddon_deeds.dfn @@ -0,0 +1,89 @@ +// Deed for Stone and Plaster Mini House +[stoneandplastermini] +{ +name=Mini House: Stone and Plaster +id=0x14F0 +morex=500 +origin=aos +} + +// Deed for Field Stone Mini House +[fieldstonemini] +{ +name=Mini House: Field Stone +id=0x14F0 +morex=501 +origin=aos +} + +// Deed for Small Brick Mini House +[smallbrickmini] +{ +name=Mini House: Small Brick +id=0x14F0 +morex=502 +origin=aos +} + +// Deed for Wooden Mini House +[woodenmini] +{ +name=Mini House: Wooden +id=0x14F0 +morex=503 +origin=aos +} + +// Deed for Wood and Plaster Mini House +[woodandplastermini] +{ +name=Mini House: Wood and Plaster +id=0x14F0 +morex=504 +origin=aos +} + +// Deed for Thatched-Roof Cottage Mini House +[thatchedroofcottage] +{ +name=Mini House: Thatched-Roof Cottage +id=0x14F0 +morex=505 +origin=aos +} + +// Deed for Brick Mini House +[brickmini] +{ +name=Mini House: Brick +id=0x14F0 +morex=506 +origin=aos +} + +// Deed for Two-Story Wood and Plaster Mini House +[twostorywoodandplastermini] +{ +name=Mini House: Two-Story Wood and Plaster +id=0x14F0 +morex=507 +origin=aos +} + +// Deed for Malas Mountain Pass Mini House +[malasmountainpassmini] +{ +name=Mini House: Malas Mountain Pass +id=0x14F0 +morex=508 +origin=aos +} + +// Deed for Church at Night Mini House +[churchatnightmini] +{ +name=Mini House: Church at Night +id=0x14F0 +morex=509 +origin=aos +} \ No newline at end of file diff --git a/data/dfndata/items/gmmenu/spawners.dfn b/data/dfndata/items/gmmenu/spawners.dfn index 342ebcb4f..a5fc82e11 100644 --- a/data/dfndata/items/gmmenu/spawners.dfn +++ b/data/dfndata/items/gmmenu/spawners.dfn @@ -7,6 +7,7 @@ interval=1 5 visible=1 decay=0 movable=2 +script=2205 } [orcspawn] diff --git a/data/dfndata/items/lootlists.dfn b/data/dfndata/items/lootlists.dfn index 7a62a53fd..0638b0eee 100644 --- a/data/dfndata/items/lootlists.dfn +++ b/data/dfndata/items/lootlists.dfn @@ -962,4 +962,53 @@ 100|PaintedPlagueMask 100|PaintedDaemonMask 100|PaintedEvilClownMask +} + +// Treasure Map Level 0 +[LOOTLIST TreasureMapLvl0Loot] +{//approximately 1% +990|blank +10|treasuremaplvl0 +} + +// Treasure Map Level 1 +[LOOTLIST TreasureMapLvl1Loot] +{//approximately 1% +990|blank +10|treasuremaplvl1 +} + +// Treasure Map Level 2 +[LOOTLIST TreasureMapLvl2Loot] +{//approximately 1% +990|blank +10|treasuremaplvl2 +} + +// Treasure Map Level 3 +[LOOTLIST TreasureMapLvl3Loot] +{//approximately 1% +990|blank +10|treasuremaplvl3 +} + +// Treasure Map Level 4 +[LOOTLIST TreasureMapLvl4Loot] +{//approximately 1% +990|blank +10|treasuremaplvl4 +} + +// Treasure Map Level 5 +[LOOTLIST TreasureMapLvl5Loot] +{//approximately 1% +990|blank +10|treasuremaplvl5 +} + +// Treasure Map Level 6 +[LOOTLIST TreasureMapLvl6Loot] +{//approximately 1% +990|blank +10|treasuremaplvl6 } \ No newline at end of file diff --git a/data/dfndata/skills/skills.dfn b/data/dfndata/skills/skills.dfn index b28b32a15..28d129929 100644 --- a/data/dfndata/skills/skills.dfn +++ b/data/dfndata/skills/skills.dfn @@ -1206,10 +1206,10 @@ SKILLPOINT=990,5,0 SKILLPOINT=1000,0,0 } -// Imbuing +// Mysticism [SKILL 55] { -NAME=IMBUING +NAME=MYSTICISM STR=0 DEX=0 INT=0 @@ -1227,10 +1227,10 @@ SKILLPOINT=990,5,0 SKILLPOINT=1000,0,0 } -// Mysticism +// Imbuing [SKILL 56] { -NAME=MYSTICISM +NAME=IMBUING STR=0 DEX=0 INT=0 diff --git a/data/dictionaries/dictionary.CSY b/data/dictionaries/dictionary.CSY index d4bd5100f..8f378692a 100644 --- a/data/dictionaries/dictionary.CSY +++ b/data/dictionaries/dictionary.CSY @@ -3431,6 +3431,7 @@ 6301=Z této knihy se může učit pouze velmistr alchymista. 6302=Tyto informace jste se již dozvěděli. 6303=Naučili jste se vyrábět předměty ze skla. K výrobě těchto předmětů budete muset najít horníky, kteří budou těžit jemný písek. +6304=Musíte mít volnou ruku, abyste mohli pít lektvar. // [7000-7499] AI Scripts 7000=Jsi zločinec a nemáš přístup ke své bankovní schránce. 7001=Který předmět si přeješ uložit do své bankovní schránky? @@ -4679,7 +4680,6 @@ 11619=chlebový bochník 11620=pánev sušenek 11621=koláč -11622=muffiny 11622=pečený quiche 11623=pečený masový koláč 11624=pizza s uzeninou @@ -4715,6 +4715,7 @@ 11654=Pro přípravu jídla musíte být v blízkosti zdroje tepla. 11655=Musíte být v blízkosti mlýna, abyste mohli vyrábět mouku. 11656=Musíte být v blízkosti pece, abyste mohli péct jídlo. +11657=muffiny // 11801 - 12000 Dovednost řemeslné výroby // Strana 1 - Dřevěné předměty 11801=Náprava @@ -5345,5 +5346,42 @@ 19140=Nejprve je třeba změkčit nečistoty. 19141=Zasadíte semeno do misky s hlínou. 19142=Musíte použít semínko na misku s nečistotami! +// [19201-19300] Speciální pohyby +19201=K provedení tohoto útoku potřebujete %i zbraň +19202=K provedení tohoto útoku potřebujete %i many +19203=Váš útok proniká jejich pancířem! +19204=Úder pronikl do vašeho brnění! +19205=Váš cíl krvácí! +19206=Ty krvácíš! +19207=Hodně krvácíte +19208=%i silně krvácí +19209=Máte otřes mozku! +19210=Cítíte se dezorientovaný! +19211=Zasadil jsi zdrcující ránu! +19212=Zdrcujícím útokem dostáváte další poškození! +19213=Nemůžete odzbrojit svého protivníka. +19214=Váš cíl již není ozbrojen! +19215=Odzbrojte svou zbraň! +19216=Vaše zbraň byla odzbrojena! +19217=Nemůžete provést tento útok během jízdy nebo letu! +19218=Tento útok funguje pouze na namontované nebo létající cíle +19219=Síla vašeho útoku je vytlačila z jejich koně! +19220=Byli jste sraženi z vašeho koně %i! +19221=Vaše zbraň musí mít dávku jedu, aby mohla provést infekční útok! +19222=Váš přesný zásah zvýšil úroveň jedu o 1 +19223=Jed se zdá být extra účinný! +19224=Otrávili jste svůj cíl: %i +19225=%i : otrávil tě! +19226=Zasadil jsi smrtelnou ránu! +19227=Byl jsi smrtelně zraněn! +19228=Váš cíl odolává paralýze. +19229=Odporujete paralýze. +19230=Útok vás dočasně paralyzoval! +19231=Chybí vám požadované utajení k provedení tohoto útoku +19232=Úder a schováš se ve stínu! +19233=Jste omráčeni útokem a váš útočník zmizí! +19234=Váš zmatek pominul, nyní můžete vyzbrojit zbraň! +19235=Už nejsi smrtelně zraněný. +19236=Krvácející rány se zahojily, už nekrvácíte! } EOF diff --git a/data/dictionaries/dictionary.ENG b/data/dictionaries/dictionary.ENG index 6c7523274..e4e08becc 100644 --- a/data/dictionaries/dictionary.ENG +++ b/data/dictionaries/dictionary.ENG @@ -3431,6 +3431,7 @@ 6301=Only a Grandmaster Alchemist can learn from this book. 6302=You have already learned this information. 6303=You have learned to make items from glass. You will need to find miners to mine fine sand for you to make these items. +6304=You must have a free hand to drink a potion. // [7000-7499] AI Scripts 7000=Thou art a criminal and cannot access thy bank box. 7001=Which item do you wish to deposit in your bank box? @@ -4679,7 +4680,6 @@ 11619=bread loaf 11620=pan of cookies 11621=cake -11622=muffins 11622=baked quiche 11623=baked meat pie 11624=sausage pizza @@ -4715,6 +4715,7 @@ 11654=You must be near a heat source to cook food. 11655=You must be near a mill to create flour. 11656=You must be near an oven to bake food. +11657=muffins // 11801 - 12000 Tinkering Crafting Skill // Page 1 - Wooden Items 11801=Axle @@ -5346,5 +5347,42 @@ 19140=The dirt needs to be softened first. 19141=You plant the seed in the bowl of dirt. 19142=You must use a seed on a bowl of dirt! +// [19201-19300] Special Moves +19201=You need %i weapon skill to perform that attack +19202=You need %i mana to perform that attack +19203=Your attack penetrates their armor! +19204=The blow penetrated your armor! +19205=Your target is bleeding! +19206=You are bleeding! +19207=You are bleeding profusely +19208=%i is bleeding profusely +19209=You have delivered a concussion! +19210=You feel disoriented! +19211=You have delivered a crushing blow! +19212=You take extra damage from the crushing attack! +19213=You cannot disarm your opponent. +19214=Your target is already unarmed! +19215=You disarm their weapon! +19216=Your weapon has been disarmed! +19217=You cannot perform that attack while mounted or flying! +19218=This attack only works on mounted or flying targets +19219=The force of your attack has dislodged them from their mount! +19220=You have been knocked off of your mount by %i ! +19221=Your weapon must have a dose of poison to perform an infectious strike! +19222=Your precise strike has increased the level of the poison by 1 +19223=The poison seems extra effective! +19224=You have poisoned your target : %i +19225=%i : poisoned you! +19226=You deliver a mortal wound! +19227=You have been mortally wounded! +19228=Your target resists paralysis. +19229=You resist paralysis. +19230=The attack has temporarily paralyzed you! +19231=You lack the required stealth to perform that attack +19232=You strike and hide in the shadows! +19233=You are dazed by the attack and your attacker vanishes! +19234=Your confusion has passed, you may now arm a weapon! +19235=You are no longer mortally wounded. +19236=The bleeding wounds have healed, you are no longer bleeding! } EOF diff --git a/data/dictionaries/dictionary.FRE b/data/dictionaries/dictionary.FRE index 43bacc548..3ca36b929 100644 --- a/data/dictionaries/dictionary.FRE +++ b/data/dictionaries/dictionary.FRE @@ -3595,6 +3595,7 @@ 6301=Seul un grand maître alchimiste peut apprendre de ce livre. 6302=Vous avez déjà appris cette information. 6303=Vous avez appris à fabriquer des objets en verre. Vous devrez trouver des mineurs pour extraire du sable fin pour fabriquer ces objets. +6304=Vous devez avoir les mains libres pour boire une potion. // [7000-7499] AI Scripts 7000=Tu es un criminel et tu ne peux pas accéder à ton coffre de banque. 7001=Quel objet souhaitez-vous déposer dans votre coffret bancaire ? @@ -4835,7 +4836,6 @@ 11619=miche de pain 11620=panier de biscuits 11621=gâteau -11622=muffins 11622=quiche au four 11623=tarte à la viande cuite au four 11624=pizza à la saucisse @@ -4871,6 +4871,7 @@ 11654=Il faut être près d'une source de chaleur pour cuire les aliments. 11655=Il faut être près d'un moulin pour créer de la farine. 11656=Il faut être près d'un four pour cuire des aliments. +11657=muffins // 11801 - 12000 Compétence en artisanat de bricolage // Page 1 - Objets en bois 11801=Axe @@ -5501,5 +5502,42 @@ 19140=La saleté doit d'abord être ramollie. 19141=Vous plantez la graine dans le bol de terre. 19142=Vous devez utiliser une graine sur un bol de terre ! +// [19201-19300] Coups spéciaux +19201=Vous avez besoin de %i compétence d'arme pour effectuer cette attaque +19202=Vous avez besoin de %i mana pour effectuer cette attaque +19203=Votre attaque pénètre leur armure ! +19204=Le coup a pénétré votre armure ! +19205=Votre cible saigne ! +19206=Vous saignez ! +19207=Vous saignez abondamment +19208=%i saigne abondamment +19209=Vous avez provoqué une commotion cérébrale ! +19210=Vous vous sentez désorienté ! +19211=Vous avez porté un coup fatal ! +19212=Vous subissez des dégâts supplémentaires grâce à l'attaque écrasante ! +19213=Vous ne pouvez pas désarmer votre adversaire. +19214=Votre cible n'est déjà pas armée ! +19215=Vous désarmez votre arme ! +19216=Votre arme a été désarmée ! +19217=Vous ne pouvez pas effectuer cette attaque en étant monté ou en vol ! +19218=Cette attaque ne fonctionne que sur des cibles montées ou volantes +19219=La force de votre attaque les a déloges de leur monture ! +19220=Vous avez été renversé de votre monture par %i ! +19221=Votre arme doit contenir une dose de poison pour effectuer une frappe contagieuse ! +19222=Votre frappe précise a augmenté le niveau du poison de 1 +19223=Le poison semble très efficace ! +19224=Vous avez empoisonné votre cible : %i +19225=%i : vous a empoisonné ! +19226=Vous infligez une blessure mortelle ! +19227=Vous avez été mortellement blessé ! +19228=Votre cible résiste à la paralysie. +19229=Vous résistez à la paralysie. +19230=L'attaque vous a temporairement paralysé ! +19231=Vous n'avez pas la furtivité requise pour effectuer cette attaque +19232=Vous frappez et vous cachez dans l'ombre ! +19233=Vous êtes étourdi par l'attaque et votre attaquant disparaît ! +19234=Votre confusion est passée, vous pouvez maintenant armer une arme ! +19235=Vous n'êtes plus mortellement blessé. +19236=Les plaies saignantes ont guéri, vous ne saignez plus ! } EOF diff --git a/data/dictionaries/dictionary.GER b/data/dictionaries/dictionary.GER index 859817185..c8cd466f3 100644 --- a/data/dictionaries/dictionary.GER +++ b/data/dictionaries/dictionary.GER @@ -3431,6 +3431,7 @@ 6301=Nur ein Großmeister-Alchemist kann aus diesem Buch lernen. 6302=Sie haben diese Informationen bereits erfahren. 6303=Du hast gelernt, Gegenstände aus Glas herzustellen. Sie müssen Bergleute finden, die feinen Sand abbauen, damit Sie diese Gegenstände herstellen können. +6304=Sie müssen freie Hand haben, um einen Trank zu trinken. // [7000-7499] AI Scripts 7000=Du bist ein Verbrecher und kannst nicht auf dein Bankschließfach zugreifen. 7001=Welchen Gegenstand möchten Sie in Ihr Bankschließfach einzahlen? @@ -4679,7 +4680,6 @@ 11619=Brotlaib 11620=Keksdose 11621=Kuchen -11622=Muffins 11622=gebackene Quiche 11623=gebackene Fleischpastete 11624=Wurstpizza @@ -4715,6 +4715,7 @@ 11654=Du musst in der Nähe einer Wärmequelle sein, um Essen zu kochen. 11655=Du musst in der Nähe einer Mühle sein, um Mehl herzustellen. 11656=Du musst in der Nähe eines Ofens sein, um Essen zu backen. +11657=Muffins // 11801 - 12000 Handwerkliches Geschick // Seite 1 - Hölzerne Gegenstände 11801=Achse @@ -5345,5 +5346,42 @@ 19140=Der Schmutz muss zuerst aufgeweicht werden. 19141=Sie pflanzen den Samen in die Schüssel mit Erde. 19142=Sie müssen einen Samen auf eine Schüssel voller Erde verwenden! +// [19201-19300] Spezialbewegungen +19201=Sie benötigen %i Waffenfähigkeit, um diesen Angriff auszuführen +19202=Du brauchst %i Mana, um diesen Angriff auszuführen +19203=Dein Angriff durchdringt ihre Rüstung! +19204=Der Schlag hat deine Rüstung durchdrungen! +19205=Dein Ziel blutet! +19206=Du blutest! +19207=Sie bluten stark +19208=%i blutet stark +19209=Sie haben sich eine Gehirnerschütterung zugezogen! +19210=Sie fühlen sich desorientiert! +19211=Du hast einen vernichtenden Schlag versetzt! +19212=Du erleidest zusätzlichen Schaden durch den vernichtenden Angriff! +19213=Sie können Ihren Gegner nicht entwaffnen. +19214=Ihr Ziel ist bereits unbewaffnet! +19215=Du entwaffnest ihre Waffe! +19216=Deine Waffe wurde entschärft! +19217=Sie können diesen Angriff nicht ausführen, während Sie reiten oder fliegen! +19218=Dieser Angriff funktioniert nur bei berittenen oder fliegenden Zielen +19219=Die Wucht deines Angriffs hat sie von ihrem Reittier gestoßen! +19220=Du wurdest von %i von deinem Reittier gestoßen! +19221=Ihre Waffe muss über eine Giftdosis verfügen, um einen ansteckenden Schlag auszuführen! +19222=Dein präziser Schlag hat die Giftstufe um 1 erhöht +19223=Das Gift scheint besonders wirksam zu sein! +19224=Sie haben Ihr Ziel vergiftet: %i +19225=%i: hat dich vergiftet! +19226=Du fügst eine tödliche Wunde zu! +19227=Du wurdest tödlich verwundet! +19228=Ihr Ziel widersteht einer Lähmung. +19229=Sie widerstehen einer Lähmung. +19230=Der Angriff hat Sie vorübergehend gelähmt! +19231=Ihnen fehlt die erforderliche Tarnung, um diesen Angriff auszuführen +19232=Du schlägst zu und versteckst dich im Schatten! +19233=Sie sind durch den Angriff benommen und Ihr Angreifer verschwindet! +19234=Ihre Verwirrung ist vorüber, Sie können jetzt eine Waffe bewaffnen! +19235=Sie sind nicht mehr tödlich verwundet. +19236=Die blutenden Wunden sind verheilt, Sie bluten nicht mehr! } EOF diff --git a/data/dictionaries/dictionary.ITA b/data/dictionaries/dictionary.ITA index ff1ce1bc3..388de2822 100644 --- a/data/dictionaries/dictionary.ITA +++ b/data/dictionaries/dictionary.ITA @@ -3431,6 +3431,7 @@ 6301=Solo un Grande Maestro Alchimista può imparare da questo libro. 6302=Hai già appreso questa informazione. 6303=Hai imparato a creare oggetti in vetro. Dovrai trovare minatori che estraggano sabbia fine per poter realizzare questi oggetti. +6304=Devi avere una mano libera per bere una pozione. // [7000-7499] AI Scripts 7000=Tu sei un criminale e non puoi accedere alla tua cassaforte. 7001=Quale oggetto desidera depositare nella sua cassetta di sicurezza? @@ -4679,7 +4680,6 @@ 11619=pagnotta di pane 11620=torta di biscotti 11621=torta -11622=muffin 11622=quiche al forno 11623=pasticcio di carne al forno 11624=pizza con salsiccia @@ -4715,6 +4715,7 @@ 11654=Devi essere vicino a una fonte di calore per cucinare il cibo. 11655=Devi essere vicino a un mulino per creare farina. 11656=Devi essere vicino a un forno per cuocere il cibo. +11657=muffin // 11801 - 12000 Abilità Artigianato Tinkering // Pagina 1 - Oggetti in legno 11801=Assale @@ -5345,5 +5346,42 @@ 19140=Lo sporco deve prima essere ammorbidito. 19141=Pianta il seme nella ciotola di terra. 19142=Devi usare un seme su una ciotola di terra! +// [19201-19300] Mosse speciali +19201=Hai bisogno di %i abilità con l'arma per eseguire quell'attacco +19202=Hai bisogno di %i mana per eseguire quell'attacco +19203=Il tuo attacco penetra la loro armatura! +19204=Il colpo ha penetrato la tua armatura! +19205=Il tuo bersaglio sta sanguinando! +19206=Stai sanguinando! +19207=Stai sanguinando copiosamente +19208=%i sta sanguinando copiosamente +19209=Hai provocato una commozione cerebrale! +19210=Ti senti disorientato! +19211=Hai sferrato un colpo devastante! +19212=Subisci danni extra dall'attacco devastante! +19213=Non puoi disarmare il tuo avversario. +19214=Il tuo bersaglio è già disarmato! +19215=Disarma la loro arma! +19216=La tua arma è stata disarmata! +19217=Non puoi eseguire quell'attacco mentre sei a cavallo o mentre voli! +19218=Questo attacco funziona solo su bersagli montati o volanti +19219=La forza del tuo attacco li ha spostati dalla loro cavalcatura! +19220=Sei stato buttato giù dalla tua cavalcatura da %i! +19221=La tua arma deve avere una dose di veleno per eseguire un colpo infettivo! +19222=Il tuo colpo preciso ha aumentato il livello del veleno di 1 +19223=Il veleno sembra estremamente efficace! +19224=Hai avvelenato il tuo bersaglio: %i +19225=%i: ti ha avvelenato! +19226=Hai procurato una ferita mortale! +19227=Sei stato ferito a morte! +19228=Il tuo bersaglio resiste alla paralisi. +19229=Resisti alla paralisi. +19230=L'attacco ti ha temporaneamente paralizzato! +19231=Non hai la furtività necessaria per eseguire quell'attacco +19232=Colpisci e ti nascondi nell'ombra! +19233=Sei stordito dall'attacco e il tuo aggressore svanisce! +19234=La tua confusione è passata, ora puoi armare un'arma! +19235=Non sei più ferito a morte. +19236=Le ferite sanguinanti sono guarite, non stai più sanguinando! } EOF diff --git a/data/dictionaries/dictionary.POL b/data/dictionaries/dictionary.POL index 11a6ad2eb..63070210e 100644 --- a/data/dictionaries/dictionary.POL +++ b/data/dictionaries/dictionary.POL @@ -3431,6 +3431,7 @@ 6301=Tylko Wielki Mistrz Alchemik może uczyć się z tej książki. 6302=Te informacje już znasz. 6303=Nauczyłeś się robić przedmioty ze szkła. Będziesz musiał znaleźć górników, którzy wydobędą drobny piasek, aby móc wyprodukować te przedmioty. +6304=Musisz mieć wolną rękę, żeby wypić miksturę. // [7000-7499] AI Scripts 7000=Jesteś przestępcą i nie masz dostępu do swojej skrytki bankowej. 7001=Którą pozycję chcesz umieścić w swojej skrytce bankowej? @@ -4679,7 +4680,6 @@ 11619=bochenek chleba 11620=panka ciasteczek 11621=ciasto -11622=muffiny 11622=pieczony quiche 11623=pieczony placek z mięsem 11624=pizza z kiełbasą @@ -4715,6 +4715,7 @@ 11654=Musisz być w pobliżu źródła ciepła, aby gotować jedzenie. 11655=Musisz być w pobliżu młyna, aby wytworzyć mąkę. 11656=Musisz być w pobliżu piekarnika, aby upiec jedzenie. +11657=muffiny // 11801 - 12000 Umiejętność majsterkowania // Strona 1 - Przedmioty z drewna 11801=Oś @@ -5345,5 +5346,42 @@ 19140=Najpierw należy zmiękczyć brud. 19141=Zasiewasz ziarno w misce z ziemią. 19142=Musisz użyć nasion na misce ziemi! +// [19201-19300] Ruchy specjalne +19201=Potrzebujesz %i umiejętności posługiwania się bronią, aby wykonać ten atak +19202=Potrzebujesz %i many, aby wykonać ten atak +19203=Twój atak przebija ich zbroję! +19204=Cios przebił twoją zbroję! +19205=Twój cel krwawi! +19206=Krwawisz! +19207=Obficie krwawisz +19208=%i obficie krwawi +19209=Doznałeś wstrząsu mózgu! +19210=Czujesz się zdezorientowany! +19211=Zadałeś miażdżący cios! +19212=Otrzymujesz dodatkowe obrażenia od miażdżącego ataku! +19213=Nie możesz rozbroić przeciwnika. +19214=Twój cel jest już nieuzbrojony! +19215=Rozbrajasz ich broń! +19216=Twoja broń została rozbrojona! +19217=Nie możesz wykonać tego ataku na koniu lub w locie! +19218=Ten atak działa tylko na cele konne lub latające +19219=Siła twojego ataku zrzuciła ich z wierzchowca! +19220=Zostałeś strącony z wierzchowca przez %i! +19221=Twoja broń musi zawierać dawkę trucizny, aby wykonać zaraźliwy atak! +19222=Twoje precyzyjne uderzenie zwiększyło poziom trucizny o 1 +19223=Trucizna wydaje się wyjątkowo skuteczna! +19224=Otrułeś swój cel: %i +19225=%i: otrułem cię! +19226=Zadajesz śmiertelną ranę! +19227=Zostałeś śmiertelnie ranny! +19228=Twój cel jest odporny na paraliż. +19229=Jesteś odporny na paraliż. +19230=Atak chwilowo cię sparaliżował! +19231=Brakuje Ci wymaganej umiejętności ukrywania się, aby wykonać ten atak +19232=Uderzasz i chowasz się w cieniu! +19233=Jesteś oszołomiony atakiem i twój napastnik znika! +19234=Twoje zamieszanie minęło, możesz teraz uzbroić broń! +19235=Nie jesteś już śmiertelnie ranny. +19236=Krwawiące rany się zagoiły, już nie krwawisz! } EOF diff --git a/data/dictionaries/dictionary.PTG b/data/dictionaries/dictionary.PTG index d1f329c46..d7287d3c3 100644 --- a/data/dictionaries/dictionary.PTG +++ b/data/dictionaries/dictionary.PTG @@ -3431,6 +3431,7 @@ 6301=Apenas um Grão-Mestre Alquimista pode aprender com este livro. 6302=Você já aprendeu esta informação. 6303=Você aprendeu a fazer itens de vidro. Você precisará encontrar mineiros para extrair areia fina para fazer esses itens. +6304=Você deve ter a mão livre para beber uma poção. // [7000-7499] AI Scripts 7000=Tu és um criminoso e não podes aceder à tua caixa bancária. 7001=Que artigo deseja depositar na sua caixa bancária? @@ -4679,7 +4680,6 @@ 11619=pão de pão 11620=panha de biscoitos 11621=bolo -11622=muffins 11622=quiché cozido 11623=torta de carne assada 11624=sausage pizza @@ -4715,6 +4715,7 @@ 11654=É preciso estar perto de uma fonte de calor para cozinhar os alimentos. 11655=Tem de estar perto de um moinho para criar farinha. 11656=Tem de estar perto de um forno para cozer alimentos. +11657=muffins // 11801 - 12000 Habilidade de Artesanato de Sininho // Página 1 - Artigos de madeira 11801=Eixo @@ -5345,5 +5346,42 @@ 19140=A sujeira precisa ser amolecida primeiro. 19141=Você planta a semente na tigela de terra. 19142=Você deve usar uma semente em uma tigela de terra! +// [19201-19300] Movimentos Especiais +19201=Você precisa de %i habilidade com arma para realizar esse ataque +19202=Você precisa de %i mana para realizar esse ataque +19203=Seu ataque penetra na armadura deles! +19204=O golpe penetrou em sua armadura! +19205=Seu alvo está sangrando! +19206=Você está sangrando! +19207=Você está sangrando muito +19208=%i está sangrando profusamente +19209=Você causou uma concussão! +19210=Você se sente desorientado! +19211=Você desferiu um golpe esmagador! +19212=Você sofre dano extra com o ataque esmagador! +19213=Você não pode desarmar seu oponente. +19214=Seu alvo já está desarmado! +19215=Você desarma a arma deles! +19216=Sua arma foi desarmada! +19217=Você não pode realizar esse ataque enquanto estiver montado ou voando! +19218=Este ataque só funciona em alvos montados ou voadores +19219=A força do seu ataque os desalojou da montaria! +19220=Você foi derrubado da montaria por %i! +19221=Sua arma deve ter uma dose de veneno para realizar um ataque infeccioso! +19222=Seu ataque preciso aumentou o nível do veneno em 1 +19223=O veneno parece extremamente eficaz! +19224=Você envenenou seu alvo: %i +19225=%i: envenenou você! +19226=Você causou um ferimento mortal! +19227=Você foi mortalmente ferido! +19228=Seu alvo resiste à paralisia. +19229=Você resiste à paralisia. +19230=O ataque paralisou você temporariamente! +19231=Você não tem a furtividade necessária para realizar esse ataque +19232=Você ataca e se esconde nas sombras! +19233=Você fica atordoado com o ataque e seu atacante desaparece! +19234=Sua confusão passou, agora você pode armar uma arma! +19235=Você não está mais mortalmente ferido. +19236=As feridas sangrentas sararam, você não está mais sangrando! } EOF diff --git a/data/dictionaries/dictionary.SPA b/data/dictionaries/dictionary.SPA index 418c01cf9..f5c16bf63 100644 --- a/data/dictionaries/dictionary.SPA +++ b/data/dictionaries/dictionary.SPA @@ -3431,6 +3431,7 @@ 6301=Sólo un Gran Maestro Alquimista puede aprender de este libro. 6302=Ya has aprendido esta información. 6303=Has aprendido a fabricar objetos de vidrio. Necesitará encontrar mineros que extraigan arena fina para poder fabricar estos artículos. +6304=Debes tener las manos libres para beber una poción. // [7000-7499] Guiones de IA 7000=Eres un delincuente y no puedes acceder a tu caja bancaria. 7001=¿Qué artículo desea depositar en su caja? @@ -4679,7 +4680,6 @@ 11619=pan de pan 11620=pan de galletas 11621=pastel -11622=magdalenas 11622=quiche al horno 11623=pastel de carne al horno 11624=pizza de salchicha @@ -4715,6 +4715,7 @@ 11654=Debes estar cerca de una fuente de calor para cocinar los alimentos. 11655=Debes estar cerca de un molino para crear harina. 11656=Debes estar cerca de un horno para cocer alimentos. +11657=magdalenas // 11801 - 12000 Habilidad de Artesanía // Página 1 - Artículos de madera 11801=Eje @@ -5345,5 +5346,42 @@ 19140=Primero es necesario ablandar la suciedad. 19141=Plantas la semilla en el cuenco de tierra. 19142=¡Debes usar una semilla en un recipiente con tierra! +// [19201-19300] Movimientos especiales +19201=Necesitas %i habilidad con arma para realizar ese ataque +19202=Necesitas %i mana para realizar ese ataque +19203=¡Tu ataque penetra su armadura! +19204=¡El golpe atravesó tu armadura! +19205=¡Tu objetivo está sangrando! +19206=¡Estás sangrando! +19207=Estas sangrando profusamente +19208=%i está sangrando profusamente +19209=¡Has causado una conmoción cerebral! +19210=¡Te sientes desorientado! +19211=¡Has asestado un golpe aplastante! +19212=¡Recibes daño extra por el ataque aplastante! +19213=No puedes desarmar a tu oponente. +19214=¡Tu objetivo ya está desarmado! +19215=¡Desarmas su arma! +19216=¡Tu arma ha sido desarmada! +19217=¡No puedes realizar ese ataque mientras estás montado o volando! +19218=Este ataque sólo funciona en objetivos montados o voladores +19219=¡La fuerza de tu ataque los ha desalojado de su montura! +19220=¡%i te ha derribado de tu montura! +19221=¡Tu arma debe tener una dosis de veneno para realizar un ataque infeccioso! +19222=Tu golpe preciso ha aumentado el nivel del veneno en 1 +19223=¡El veneno parece extra efectivo! +19224=Has envenenado a tu objetivo: %i +19225=%i: ¡te envenenó! +19226=¡Has causado una herida mortal! +19227=¡Has sido herido de muerte! +19228=Tu objetivo resiste la parálisis. +19229=Resistes la parálisis. +19230=¡El ataque te ha paralizado temporalmente! +19231=Te falta el sigilo necesario para realizar ese ataque +19232=¡Atacas y te escondes en las sombras! +19233=¡Estás aturdido por el ataque y tu atacante desaparece! +19234=¡Tu confusión ha pasado, ahora puedes armar un arma! +19235=Ya no estás herido de muerte. +19236=Las heridas sangrantes han sanado, ¡ya no sangras! } EOF diff --git a/data/dictionaries/dictionary.ZRO b/data/dictionaries/dictionary.ZRO index 62cf605eb..dba5d4de1 100644 --- a/data/dictionaries/dictionary.ZRO +++ b/data/dictionaries/dictionary.ZRO @@ -3426,6 +3426,7 @@ 6301=Only a Grandmaster Alchemist can learn from this book. 6302=You have already learned this information. 6303=You have learned to make items from glass. You will need to find miners to mine fine sand for you to make these items. +6304=You must have a free hand to drink a potion. // [7000-7499] AI Scripts 7000=Thou art a criminal and cannot access thy bank box. 7001=Which item do you wish to deposit in your bank box? @@ -4674,7 +4675,6 @@ 11619=bread loaf 11620=pan of cookies 11621=cake -11622=muffins 11622=baked quiche 11623=baked meat pie 11624=sausage pizza @@ -4710,6 +4710,7 @@ 11654=You must be near a heat source to cook food. 11655=You must be near a mill to create flour. 11656=You must be near an oven to bake food. +11657=muffins // 11801 - 12000 Tinkering Crafting Skill // Page 1 - Wooden Items 11801=Axle @@ -5340,5 +5341,42 @@ 19140=The dirt needs to be softened first. 19141=You plant the seed in the bowl of dirt. 19142=You must use a seed on a bowl of dirt! +// [19201-19300] Special Moves +19201=You need %i weapon skill to perform that attack +19202=You need %i mana to perform that attack +19203=Your attack penetrates their armor! +19204=The blow penetrated your armor! +19205=Your target is bleeding! +19206=You are bleeding! +19207=You are bleeding profusely +19208=%i is bleeding profusely +19209=You have delivered a concussion! +19210=You feel disoriented! +19211=You have delivered a crushing blow! +19212=You take extra damage from the crushing attack! +19213=You cannot disarm your opponent. +19214=Your target is already unarmed! +19215=You disarm their weapon! +19216=Your weapon has been disarmed! +19217=You cannot perform that attack while mounted or flying! +19218=This attack only works on mounted or flying targets +19219=The force of your attack has dislodged them from their mount! +19220=You have been knocked off of your mount by %i ! +19221=Your weapon must have a dose of poison to perform an infectious strike! +19222=Your precise strike has increased the level of the poison by 1 +19223=The poison seems extra effective! +19224=You have poisoned your target : %i +19225=%i : poisoned you! +19226=You deliver a mortal wound! +19227=You have been mortally wounded! +19228=Your target resists paralysis. +19229=You resist paralysis. +19230=The attack has temporarily paralyzed you! +19231=You lack the required stealth to perform that attack +19232=You strike and hide in the shadows! +19233=You are dazed by the attack and your attacker vanishes! +19234=Your confusion has passed, you may now arm a weapon! +19235=You are no longer mortally wounded. +19236=The bleeding wounds have healed, you are no longer bleeding! } EOF diff --git a/data/js/combat/blockequip.js b/data/js/combat/blockequip.js new file mode 100644 index 000000000..48c82f700 --- /dev/null +++ b/data/js/combat/blockequip.js @@ -0,0 +1,20 @@ +function onEquipAttempt( pEquipper, iEquipped ) +{ + var blockEquip = pEquipper.GetTempTag( "blockEquip" ); + if( blockEquip == true ) + { + iEquipped.SetTempTag( "charSer", pEquipper.serial.toString() ); + iEquipped.StartTimer( 10 ,1, true ); + return false; + } + + return true; +} + +function onTimer( timerObj, timerID ) +{ + var mChar = CalcCharFromSer(parseInt( timerObj.GetTempTag( "charSer" ))) + timerObj.container = mChar.pack; + timerObj.Refresh(); + timerObj.SetTempTag( "charSer", null ); +} \ No newline at end of file diff --git a/data/js/combat/leechstats.js b/data/js/combat/leechstats.js new file mode 100644 index 000000000..fc1086fdf --- /dev/null +++ b/data/js/combat/leechstats.js @@ -0,0 +1,56 @@ +function onEquip( pEquipper, iEquipped ) +{ + pEquipper.AddScriptTrigger( 7003 ); +} + +// Remove script trigger on unequip +function onUnequip( pUnequipper, iUnequipped ) +{ + pUnequipper.RemoveScriptTrigger( 7003 ); +} + +function onDamageDeal( attacker, damaged, damageValue, damageType ) +{ + // Fetch weapon in main hand or secondary hand + var iWeapon = attacker.FindItemLayer( 0x01 ); + if( !ValidateObject( iWeapon )) + { + iWeapon = attacker.FindItemLayer( 0x02 ); + } + + if( ValidateObject( iWeapon )) + { // Apply leech effects based on weapon properties + ApplyLeech( attacker, damaged, damageValue, iWeapon, 'healthLeech', 30 ); + ApplyLeech( attacker, damaged, damageValue, iWeapon, 'staminaLeech', 100 ); + ApplyLeech( attacker, damaged, damageValue, iWeapon, 'manaLeech', 40 ); + } + + return true; +} + +function ApplyLeech( attacker, damaged, damageValue, weapon, leechType, multiplier ) +{ + // Get the leech amount for the specified leech type from the weapon + var leechPercentVal = weapon[ leechType ]; + if( leechPercentVal > 0 ) + { + // Calculate the percent of health restored to the attacker + var leechAmt = Math.round( damageValue * ( leechPercentVal / 100 ) * ( multiplier/100 )); + + // Apply the leech effect based on the leech type + switch( leechType ) + { + case 'healthLeech': + attacker.Heal( leechAmt ); + break; + case 'staminaLeech': + attacker.stamina += leechAmt; + break; + case 'manaLeech': + attacker.mana += leechAmt; + break; + } + + attacker.SoundEffect( 0x44D, true ); + } +} \ No newline at end of file diff --git a/data/js/combat/special_moves.js b/data/js/combat/special_moves.js new file mode 100644 index 000000000..49dd46e2b --- /dev/null +++ b/data/js/combat/special_moves.js @@ -0,0 +1,883 @@ +function onSpecialMove( pUser, abilityID ) +{ + // Define the array of restricted ability IDs + var restrictedAbilities = [14, 15, 16, 17,18,19,20,21,22,23,24,25,29]; + + // Check if the abilityID is in the array of restricted abilities + if( restrictedAbilities.indexOf( abilityID ) != -1 ) + { + pUser.SysMessage( "This ability is not yet available." ); + TriggerEvent( 2206, "DeactivateSpecialMove", pUser, abilityID ); + return false; + } + + // Check Skills + if( !checkRequiredSkill( pUser, abilityID )) + return true; + + // Check Mana + if( !CheckMana( pUser, abilityID )) + return true; + + if( abilityID >= 1 ) + pUser.SetTempTag( "abilityID", abilityID ); + + return true; +} + +function checkSkillRequirement( pUser, requiredSkillLevel, requiredSkill, skillMessage, abilityID ) +{ + var pSock = pUser.socket; + if( pUser.skills[requiredSkill] < requiredSkillLevel ) + { + pSock.SysMessage( GetDictionaryEntry( 19201, pSock.language), skillMessage); // You need %i weapon skill to perform that attack + + TriggerEvent( 2206, "DeactivateSpecialMove", pUser, abilityID ); + return false; + } + return true; +} + +// archery 31 swordsmansip 40 macefighting 41 fencing 42 wrestling 43 +// Define the RequiredSkill function +function checkRequiredSkill( pUser, abilityID ) +{ + // Define weapon types and their skill requirements and if primary or secondary ability + var weaponTypes = { + "0x0df0": { primary: 13, secondary: 11, reqSkill: 41 }, + "0x0df1": { primary: 13, secondary: 11, reqSkill: 41 }, // Black Staves // WhirlwindAttack, ParalyzingBlow + + "0x0df2": { primary: 6, secondary: 5, reqSkill: 41 }, + "0x0df3": { primary: 6, secondary: 5, reqSkill: 41 }, + "0x0df4": { primary: 6, secondary: 5, reqSkill: 41 }, + "0x0df5": { primary: 6, secondary: 5, reqSkill: 41 }, // wands // Dismount, Disarm + + "0x0e81": { primary: 4, secondary: 5, reqSkill: 41 }, + "0x0e82": { primary: 4, secondary: 5, reqSkill: 41 }, // Shepherd's Crooks // CrushingBlow, Disarm + + "0x0e85": { primary: 7, secondary: 5, reqSkill: 40 }, + "0x0e86": { primary: 7, secondary: 5, reqSkill: 40 }, // pickaxe // DoubleStrike, Disarm + + "0x0e87": { primary: 2, secondary: 6, reqSkill: 42 }, + "0x0e88": { primary: 2, secondary: 6, reqSkill: 42 }, // Pitchforks // BleedAttack, Dismount + + "0x0e89": { primary: 7, secondary: 3, reqSkill: 41 }, + "0x0e8a": { primary: 7, secondary: 3, reqSkill: 41 }, // Quarter Staves // DoubleStrike, ConcussionBlow + + "0x0ec2": { primary: 2, secondary: 8, reqSkill: 40 }, + "0x0ec3": { primary: 2, secondary: 8, reqSkill: 40 }, // Cleavers // BleedAttack, InfectiousStrike + + "0x0ec4": { primary: 12, secondary: 2, reqSkill: 40 }, + "0x0ec5": { primary: 12, secondary: 2, reqSkill: 40 }, // Skinning Knives // ShadowStrike, BleedAttack + + "0x0f43": { primary: 1, secondary: 5, reqSkill: 40 }, + "0x0f44": { primary: 1, secondary: 5, reqSkill: 40 }, // hatchets // ArmorIgnore, Disarm + + "0x0f45": { primary: 2, secondary: 9, reqSkill: 40 }, + "0x0f46": { primary: 2, secondary: 9, reqSkill: 40 }, // Executioner Axes // BleedAttack, MortalStrike + + "0x0f47": { primary: 2, secondary: 3, reqSkill: 40 }, + "0x0f48": { primary: 2, secondary: 3, reqSkill: 40 }, // Battle Axes // BleedAttack, ConcussionBlow + + "0x0f49": { primary: 4, secondary: 6, reqSkill: 40 }, + "0x0f4a": { primary: 4, secondary: 6, reqSkill: 40 }, // Axes // CrushingBlow, Dismount + + "0x0f4b": { primary: 7, secondary: 13, reqSkill: 40 }, + "0x0f4c": { primary: 7, secondary: 13, reqSkill: 40 }, // Double Axe // DoubleStrike, WhirlwindAttack + + "0x0f4e": { primary: 11, secondary: 6, reqSkill: 40 }, + "0x0f4e": { primary: 11, secondary: 6, reqSkill: 40 }, // Bardiches // ParalyzingBlow, Dismount + + "0x0f4f": { primary: 3, secondary: 9, reqSkill: 31 }, + "0x0f50": { primary: 3, secondary: 9, reqSkill: 31 }, // Crossbows // ConcussionBlow, MortalStrike + + "0x0f51": { primary: 8, secondary: 12, reqSkill: 40 }, + "0x0f52": { primary: 8, secondary: 12, reqSkill: 40 }, // Daggers // InfectiousStrike, ShadowStrike + + "0x0f5c": { primary: 3, secondary: 5, reqSkill: 41 }, + "0x0f5d": { primary: 3, secondary: 5, reqSkill: 41 }, // Maces // ConcussionBlow, Disarm + + "0x0f5e": { primary: 4, secondary: 1, reqSkill: 40 }, + "0x0f5f": { primary: 4, secondary: 1, reqSkill: 40 }, // Broadswords // CrushingBlow, ArmorIgnore + + "0x13b7": { primary: 1, secondary: 3, reqSkill: 40 }, + "0x13b8": { primary: 1, secondary: 3, reqSkill: 40 }, + "0x0f60": { primary: 1, secondary: 3, reqSkill: 40 }, + "0x0f61": { primary: 1, secondary: 3, reqSkill: 40 }, // Longswords // ArmorIgnore, ConcussionBlow + + "0x0f62": { primary: 1, secondary: 11, reqSkill: 42 }, + "0x0f63": { primary: 1, secondary: 11, reqSkill: 42 }, // Spears // ArmorIgnore, ParalyzingBlow + + "0x0fb4": { primary: 4, secondary: 12, reqSkill: 41 }, + "0x0fb5": { primary: 4, secondary: 12, reqSkill: 41 }, // Sledge hammers // CrushingBlow, ShadowStrike + + "0x13af": { primary: 1, secondary: 2, reqSkill: 40 }, + "0x13b0": { primary: 1, secondary: 2, reqSkill: 40 }, // War Axes // ArmorIgnore, BleedAttack + + "0x13b1": { primary: 11, secondary: 9, reqSkill: 31 }, + "0x13b2": { primary: 11, secondary: 9, reqSkill: 31 }, // Bows // ParalyzingBlow, MortalStrike + + "0x13b3": { primary: 12, secondary: 6, reqSkill: 41 }, + "0x13b4": { primary: 12, secondary: 6, reqSkill: 41 }, // Clubs // ShadowStrike, Dismount + + "0x13b5": { primary: 7, secondary: 11, reqSkill: 40 }, + "0x13b6": { primary: 7, secondary: 11, reqSkill: 40 }, // Scimitars // DoubleStrike, ParalyzingBlow + + "0x13b9": { primary: 11, secondary: 4, reqSkill: 40 }, + "0x13ba": { primary: 11, secondary: 4, reqSkill: 40 }, // Viking Swords // ParalyzingBlow, CrushingBlow + + "0x13fc": { primary: 10, secondary: 6, reqSkill: 31 }, + "0x13fd": { primary: 10, secondary: 6, reqSkill: 31 }, // Heavy Crossbows // MovingShot, Dismount + + "0x13e3": { primary: 4, secondary: 12, reqSkill: 41 }, + "0x13e4": { primary: 4, secondary: 12, reqSkill: 41 }, // Smith's Hammers // CrushingBlow, ShadowStrike + + "0x13f6": { primary: 8, secondary: 5, reqSkill: 40 }, + "0x13f7": { primary: 8, secondary: 5, reqSkill: 40 }, // Butcher Knives // InfectiousStrike,Disarm + + "0x13f8": { primary: 3, secondary: 0, reqSkill: 41 }, + "0x13f9": { primary: 3, secondary: 0, reqSkill: 41 }, // Gnarled Staves // ConcussionBlow,ForceOfNature + + "0x13fa": { primary: 13, secondary: 2, reqSkill: 40 }, + "0x13fb": { primary: 13, secondary: 2, reqSkill: 40 }, // Large Battle Axes // WhirlwindAttack,BleedAttack + + "0x13fe": { primary: 7, secondary: 1, reqSkill: 40 }, + "0x13ff": { primary: 7, secondary: 1, reqSkill: 40 }, // Katana // DoubleStrike,ArmorIgnore + + "0x1400": { primary: 1, secondary: 8, reqSkill: 42 }, + "0x1401": { primary: 1, secondary: 8, reqSkill: 42 }, // Kryss // ArmorIgnore,InfectiousStrike + + "0x1402": { primary: 12, secondary: 9, reqSkill: 42 }, + "0x1403": { primary: 12, secondary: 9, reqSkill: 42 }, // Short Spears // ShadowStrike,MortalStrike + + "0x1404": { primary: 2, secondary: 5, reqSkill: 42 }, + "0x1405": { primary: 2, secondary: 5, reqSkill: 42 }, // War Forks // BleedAttack,Disarm + + "0x1406": { primary: 4, secondary: 9, reqSkill: 41 }, + "0x1407": { primary: 4, secondary: 9, reqSkill: 41 }, // War Maces // CrushingBlow,MortalStrike + + "0x1438": { primary: 13, secondary: 4, reqSkill: 41 }, + "0x1439": { primary: 13, secondary: 4, reqSkill: 41 }, // War Hammers // WhirlwindAttack,CrushingBlow + + "0x143a": { primary: 7, secondary: 3, reqSkill: 41 }, + "0x143b": { primary: 7, secondary: 3, reqSkill: 41 }, // Mauls // DoubleStrike,ConcussionBlow + + "0x143c": { primary: 1, secondary: 9, reqSkill: 41 }, + "0x143d": { primary: 1, secondary: 9, reqSkill: 41 }, // Hammer Picks // ArmorIgnore,MortalStrike + + "0x143e": { primary: 13, secondary: 3, reqSkill: 40 }, + "0x143f": { primary: 13, secondary: 3, reqSkill: 40 }, // Halberds // WhirlwindAttack,ConcussionBlow + + "0x1440": { primary: 2, secondary: 12, reqSkill: 40 }, + "0x1441": { primary: 2, secondary: 12, reqSkill: 40 }, // Cutlasses // BleedAttack,ShadowStrike + + "0x1442": { primary: 7, secondary: 12, reqSkill: 40 }, + "0x1443": { primary: 7, secondary: 12, reqSkill: 40 } // Two Handed Axes // DoubleStrike,ShadowStrike + }; + + // Get items in user's hands + var itemRHand = pUser.FindItemLayer( 0x01 ); + var itemLHand = pUser.FindItemLayer( 0x02 ); + + // Check if either hand has an item + if( itemRHand != null ) + { + // Check item in the right hand + if( weaponTypes[itemRHand.sectionID] ) + { + var weapon = weaponTypes[itemRHand.sectionID]; + + if( abilityID == weapon.primary ) + { + return checkSkillRequirement( pUser, 700, weapon.reqSkill, "70", abilityID ); + } + else if( abilityID == weapon.secondary ) + { + return checkSkillRequirement( pUser, 900, weapon.reqSkill, "90", abilityID ); + } + } + } + else if( itemLHand != null ) + { + // Check item in the left hand + if( weaponTypes[itemLHand.sectionID] ) + { + var weapon = weaponTypes[itemLHand.sectionID]; + + if( abilityID == weapon.primary ) + { + return checkSkillRequirement( pUser, 700, weapon.reqSkill, "70", abilityID ); + } + else if( abilityID == weapon.secondary ) + { + return checkSkillRequirement( pUser, 900, weapon.reqSkill, "90", abilityID ); + } + } + } + else// checking if both hands null if so, it is a wrestling skill + { + if( abilityID == 5 ) + { + return checkSkillRequirement( pUser, 700, 43, "70" ); + } + else if( abilityID == 11 ) + { + return checkSkillRequirement( pUser, 900, 43, "90" ); + } + } + + return true; +} + +function getAbilityManaTable() +{// Mana is Based off 2003 AOS and 2005 ML + return { + 0: { manaAmount: 0 }, // Cancel Ability Attempt + 1: { manaAmount: 30 }, // Armor Ignore // Start AOS abiltiies + 2: { manaAmount: 30 }, // Bleed Attack + 3: { manaAmount: 30 }, // Concusion Blow + 4: { manaAmount: 30 }, // Crushing Blow + 5: { manaAmount: 20 }, // Disarm + 6: { manaAmount: 20 }, // Dismount + 7: { manaAmount: 30 }, // Double Strike + 8: { manaAmount: 20 }, // Infecting + 9: { manaAmount: 30 }, // Mortal Strike + 10: { manaAmount: 20 }, // Moving Shot + 11: { manaAmount: 35 }, // Paralyzing Blow + 12: { manaAmount: 25 }, // Shadow Strike + 13: { manaAmount: 25 } // Whirlwind Attack // End AOS abilities + /* 14-29 are not available + 14: { manaAmount: 30 }, // Riding Swipe // Start SE abiltiies + 15: { manaAmount: 30 }, // Frenzied Whirlwind + 16: { manaAmount: 30 }, // Block + 17: { manaAmount: 30 }, // Defense Mastery + 18: { manaAmount: 30 }, // Nerve Strike + 19: { manaAmount: 30 }, // Talon Strike + 20: { manaAmount: 30 }, // Feint + 21: { manaAmount: 30 }, // Dual Wield + 22: { manaAmount: 30 }, // Double shot + 23: { manaAmount: 30 }, // Armor Peirce // End SE abilities + 24: { manaAmount: 25 }, // Bladeweave // Start ML abilities + 25: { manaAmount: 15 }, // Force Arrow + 26: { manaAmount: 15 }, // Lightning Arrow + 27: { manaAmount: 25 }, // Psychic Attack + 28: { manaAmount: 35 }, // Serpent Arrow + 29: { manaAmount: 35 } // Force of Nature // End ML abilities*/ + }; +} + +function CheckMana( pUser, abilityID ) +{ + var pSock = pUser.socket; + var abilitieMana = getAbilityManaTable(); + var NextUse = pUser.GetTempTag( "doubleMana" ); + var iTime = GetCurrentClock(); + var Delay = 3000; // If ability is performed within 3 seconds of the last ability, it will then cost double mana + var requiredMana = abilitieMana[abilityID].manaAmount; + + if( NextUse == null ) + { + NextUse = 0; + } + + var isDoubleMana = ( iTime - NextUse ) < Delay; + if( isDoubleMana ) + { + requiredMana *= 2; + } + + if( pUser.mana < requiredMana ) + { + pSock.SysMessage( GetDictionaryEntry( 19202, pSock.language), requiredMana); // You need %i mana to perform that attack + TriggerEvent( 2206, "DeactivateSpecialMove", pUser, abilityID ); + return false; + } + else + { + return true; + } +} + +function DeductMana( pUser, abilityID ) +{ + var abilitieMana = getAbilityManaTable(); + var NextUse = pUser.GetTempTag( "doubleMana" ); + var iTime = GetCurrentClock(); + var Delay = 3000; // If ability is performed within 3 seconds of the last ability, it will then cost double mana + var requiredMana = abilitieMana[abilityID].manaAmount; + + if( NextUse == null ) + { + NextUse = 0; + } + + var isDoubleMana = ( iTime - NextUse ) < Delay; + if( isDoubleMana ) + { + requiredMana *= 2; + } + + pUser.mana -= requiredMana; + pUser.SetTempTag( "doubleMana", iTime.toString() ); +} + +function onCombatDamageCalc( pAttacker, pDefender, fightSkill, hitLoc ) +{ + var abilityID = pAttacker.GetTempTag( "abilityID" ); + var baseDamage = pAttacker.attack; + + if( baseDamage == -1 ) // No damage if weapon breaks + return 0; + + var damage = ApplyDamageBonuses( 1, pAttacker, pDefender, fightSkill, hitLoc, baseDamage ); + + if( damage < 1 ) + return 0; + + // Check if attacker has armor ignore enabled + if( abilityID == 1 ) // armorignore + { + // Armor Ignore ignores defense modifiers, but deals only 90% of potential damage + damage *= 0.9; + + if( fightSkill == 31 ) // Archery + { + // Cap damage from Armor Strike attack at 30 for archery weapons + if( damage > 30 ) + damage = 30; + } + else + { + // For all othe rfighting skills, cap damage from Armor Strike at 35 + if( damage > 35 ) + damage = 35; + } + } + else if( abilityID == 12 )// shadowstrike + { + damage *= 1.25; + } + else if( abilityID == 4 )// crushingblow + { + damage *= 1.5; + } + else if( abilityID == 3 )// ConcussionBlow + { + if( pDefender.maxhp > 0) + { + var hitsPercent = ( pDefender.hp / pDefender.maxhp ) * 100.0; + + var manaPercent = 0; + + if( pDefender.maxmana > 0 ) + manaPercent = ( pDefender.mana / pDefender.maxmana ) * 100.0; + + damage += Math.min(Math.floor(Math.abs(hitsPercent - manaPercent) / 4), 20); + } + } + else + { + // Otherwise, apply normal defense modifiers + damage = ApplyDefenseModifiers( 1, pAttacker, pDefender, fightSkill, hitLoc, damage, true ); + } + + // If damage after defense modifiers is below 0, do a small random amount of damage still + if( damage <= 0 ) + damage = RandomNumber( 0, 4 ); + + // If defender is a player, damage is divided by this modifier from uox.ini + if( pAttacker.npc && !pDefender.npc ) + damage /= GetServerSetting( "NPCDAMAGERATE" ); + + return damage; +} + +function onCombatHit( pAttacker, pDefender ) +{ + var abilityID = pAttacker.GetTempTag( "abilityID" ); + + onAbility( pAttacker, pDefender, abilityID ); +} + +function onAttack( pAttacker, pDefender ) +{ + var abilityID = pAttacker.GetTempTag( "abilityID" ); + + onAbility( pAttacker, pDefender, abilityID ); +} + +function onAbility( pAttacker, pDefender, abilityID ) +{ + var pSockAttacker = pAttacker.socket; + var pSockDefender = pDefender.socket; + + if( abilityID == 1 ) // armnor ignore + { + // Clear out any current ability the player is doing when he switches abilities + if( abilityID != 1 ) + TriggerEvent( 2206, "DeactivateSpecialMove", pAttacker, abilityID ); + + //checking mana + if( CheckMana( pAttacker, abilityID )) + { + DeductMana( pAttacker, abilityID ); + } + + pSockAttacker.SysMessage( GetDictionaryEntry( 19203, pSockAttacker.language ));// Your attack penetrates their armor! + if( pSockDefender != null ) + pSockDefender.SysMessage( GetDictionaryEntry( 19204, pSockDefender.language ));// The blow penetrated your armor! + + pDefender.SoundEffect( 0x0056, true ); + pDefender.StaticEffect( 0x3728, 0x09, 0x06 ); + + TriggerEvent( 2206, "ClearSpecialMove", pAttacker, abilityID );// Clear the Ability after success + } + else if( abilityID == 2 ) // bleedattack + { + // Clear out any current ability the player is doing when he switches abilities + if( abilityID != 2 ) + TriggerEvent( 2206, "DeactivateSpecialMove", pAttacker, abilityID ); + + //checking mana + if( CheckMana( pAttacker, abilityID )) + { + DeductMana( pAttacker, abilityID ); + } + + pSockAttacker.SysMessage( GetDictionaryEntry( 19205, pSockAttacker.language ));// Your target is bleeding! + if( pSockDefender != null ) + { + pSockDefender.SysMessage(GetDictionaryEntry(19206, pSockDefender.language));// You are bleeding! + + pSockDefender.TextMessage(GetDictionaryEntry(19207, pSockDefender.language), false, 0x21);// You are bleeding profusely + pSockDefender.TextMessage(pDefender.name, GetDictionaryEntry(19208, pSockDefender.language), true, 0x21, 1);// %i is bleeding profusely + } + + pDefender.StartTimer( 2000, 9300, 7001 ); // Start 2 second timer for blood and damage last total 10 seconds + pDefender.SetTempTag( "doBleed", true ); + + if( pDefender.socket) + TriggerEvent(50104, "AddBuff", pDefender, 1039, 1075829, 1075830, 10, " 1, 10 ,2" ); + + pAttacker.SoundEffect( 0x133, true ); + pDefender.StaticEffect( 0x377A, 0x09, 0x32 ); + + TriggerEvent( 2206, "ClearSpecialMove", pAttacker, abilityID );// Clear the Ability after success + } + else if( abilityID == 3 ) // ConcussionBlow + { + // Clear out any current ability the player is doing when he switches abilities + if( abilityID != 3 ) + TriggerEvent( 2206, "DeactivateSpecialMove", pAttacker, abilityID ); + + //checking mana + if( CheckMana( pAttacker, abilityID )) + { + DeductMana( pAttacker, abilityID ); + } + + pSockAttacker.SysMessage( GetDictionaryEntry( 19209, pSockAttacker.language ));// You have delivered a concussion! + + if( pSockDefender != null ) + pSockDefender.SysMessage( GetDictionaryEntry( 19210, pSockDefender.language ));// You feel disoriented! + + pAttacker.SoundEffect( 0x213, true ); + pDefender.StaticEffect( 0x377A, 0x09, 0x32 ); + + TriggerEvent( 2206, "ClearSpecialMove", pAttacker, abilityID );// Clear the Ability after success + } + else if( abilityID == 4 ) // crushingblow + { + + // Clear out any current ability the player is doing when he switches abilities + if( abilityID != 4 ) + TriggerEvent( 2206, "DeactivateSpecialMove", pAttacker, abilityID ); + + //checking mana + if( CheckMana( pAttacker, abilityID )) + { + DeductMana( pAttacker, abilityID ); + } + + pSockAttacker.SysMessage( GetDictionaryEntry( 19211, pSockAttacker.language ));// You have delivered a crushing blow! + if( pSockDefender != null ) + pSockDefender.SysMessage( GetDictionaryEntry( 19212, pSockDefender.language ));// You take extra damage from the crushing attack! + + pAttacker.SoundEffect( 0x1E1, true ); + TriggerEvent( 2206, "ClearSpecialMove", pAttacker, abilityID );// Clear the Ability after success + } + else if( abilityID == 5 ) // Disarm + { + var itemRHand = pDefender.FindItemLayer( 0x01 ); + var itemLHand = pDefender.FindItemLayer( 0x02 ); + + if( pDefender.pack == null || itemLHand != null && itemLHand.movable >= 2 || itemRHand != null && itemRHand.movable >= 2 ) + { + pSockAttacker.SysMessage( GetDictionaryEntry( 19213, pSockAttacker.language ));// You cannot disarm your opponent. + TriggerEvent( 2206, "DeactivateSpecialMove", pAttacker, abilityID ); + return false; + } + + if( itemLHand != null && itemLHand.type == 9 || itemRHand != null && itemRHand.type == 9 ) + { + pSockAttacker.SysMessage( GetDictionaryEntry( 19214, pSockAttacker.language ));// Your target is already unarmed! + TriggerEvent( 2206, "DeactivateSpecialMove", pAttacker, abilityID ); + return false; + } + + // Clear out any current ability the player is doing when he switches abilities + if( abilityID != 5 ) + TriggerEvent( 2206, "DeactivateSpecialMove", pAttacker, abilityID ); + + //checking mana + if( CheckMana( pAttacker, abilityID )) + { + DeductMana( pAttacker, abilityID ); + } + + pAttacker.SoundEffect( 0x3B9, true ); + pDefender.StaticEffect( 0x37BE, 0x09, 0x32 ); + + pSockAttacker.SysMessage( GetDictionaryEntry( 19215, pSockAttacker.language ));// You disarm their weapon! + if( pSockDefender != null ) + pSockDefender.SysMessage( GetDictionaryEntry( 19216, pSockDefender.language ));// Your weapon has been disarmed! + + if( itemLHand != null ) + { + itemLHand.container = pDefender.pack; + } + + if( itemRHand != null ) + { + itemRHand.container = pDefender.pack; + } + + pDefender.AddScriptTrigger(7002);//block equip for 5 seconds script added + pDefender.SetTempTag( "blockEquip", true ); + pDefender.StartTimer( 5000, 9100, 7001 ); + + TriggerEvent(50104, "AddBuff", pDefender, 0x3ea, 1075637, 0, 5, " " ); + + TriggerEvent( 2206, "ClearSpecialMove", pAttacker, abilityID );// Clear the Ability after success + } + else if( abilityID == 6 ) // Dismount + { + // Check to see if player is mount or flying. + if( pAttacker.isonhorse || pAttacker.isflying ) + { + pSockAttacker.SysMessage( GetDictionaryEntry( 19217, pSockAttacker.language ));// You cannot perform that attack while mounted or flying! + TriggerEvent( 2206, "DeactivateSpecialMove", pAttacker, abilityID ); + return true; + } + + // Only Can work on players or npcs that is mounted + if( !pDefender.isonhorse || !pDefender.isflying ) + { + pSockAttacker.SysMessage( GetDictionaryEntry( 19218, pSockAttacker.language ));// This attack only works on mounted or flying targets + TriggerEvent( 2206, "DeactivateSpecialMove", pAttacker, abilityID ); + return true; + } + + // Clear out any current ability the player is doing when he switches abilities + if( abilityID != 6 ) + TriggerEvent( 2206, "DeactivateSpecialMove", pAttacker, abilityID ); + + //checking mana + if( CheckMana( pAttacker, abilityID )) + { + DeductMana( pAttacker, abilityID ); + } + + //Lesser Hiryu have an 80% chance of missing this attack needs added + + //This is the Dismount Information sent to Attacker and Defender + pDefender.SoundEffect( 0x140, true ); + pDefender.StaticEffect( 0x3728, 0x09, 0x06 ); + pSockAttacker.SysMessage( GetDictionaryEntry( 19219, pSockAttacker.language ));// The force of your attack has dislodged them from their mount! + pDefender.Dismount(); + + if( pSockDefender != null ) + pSockDefender.SysMessage( GetDictionaryEntry( 19220, pSockDefender.language ), pAttacker.name );// You have been knocked off of your mount by %i ! + + TriggerEvent( 2206, "ClearSpecialMove", pAttacker, abilityID );// Clear the Ability after success + } + else if( abilityID == 7 ) // Double Strike + { + // Clear out any current ability the player is doing when he switches abilities + if( abilityID != 7 ) + TriggerEvent( 2206, "DeactivateSpecialMove", pAttacker, abilityID ); + + //checking mana + if( CheckMana( pAttacker, abilityID )) + { + DeductMana( pAttacker, abilityID ); + } + + TriggerEvent( 2206, "ClearSpecialMove", pAttacker, abilityID );// Clear the Ability after success + } + else if( abilityID == 8 ) // Infectious Strike + { + var itemRHand = pAttacker.FindItemLayer(0x01); + var itemLHand = pAttacker.FindItemLayer(0x02); + + if( itemLHand != null && itemLHand.poison <= 0 || itemRHand != null && itemRHand.poison <= 0 ) + { + pSockAttacker.SysMessage( GetDictionaryEntry( 19221, pSockAttacker.language ));// Your weapon must have a dose of poison to perform an infectious strike! + TriggerEvent( 2206, "DeactivateSpecialMove", pAttacker, abilityID ); + return; + } + + // Clear out any current ability the player is doing when he switches abilities + if( abilityID != 8 ) + TriggerEvent( 2206, "DeactivateSpecialMove", pAttacker, abilityID ); + + //checking mana + if( CheckMana( pAttacker, abilityID )) + { + DeductMana( pAttacker, abilityID ); + } + + var level = 0; + var chance = Math.random(); + if( pAttacker.skills[30] >= 0 && pAttacker.skills[30] <= 199 ) + { + level = 1; + } + else if( pAttacker.skills[30] >= 200 && pAttacker.skills[30] <= 399 ) + { + level = 2; + } + else if( pAttacker.skills[30] >= 400 && pAttacker.skills[30] <= 599 ) + { + level = 3; + } + else if( pAttacker.skills[30] >= 600 && pAttacker.skills[30] <= 1000 ) + { + level = 4; + } + + // Adjust the poison level based on chance + if( chance < 0.2 ) + { + level--; // Decrease the level by 1 + if( level < 0 ) + { + level = 1; // Ensure the level doesn't go below 0 and is always set to least 1 + } + } + else if( chance > 0.8 ) + { + level++; // Increase the level by 1 + pSockAttacker.SysMessage( GetDictionaryEntry( 19222, pSockAttacker.language ));// Your precise strike has increased the level of the poison by 1 + if( pSockDefender != null ) + pSockDefender.SysMessage( GetDictionaryEntry( 19223, pSockDefender.language ));// The poison seems extra effective! + } + + pSockAttacker.SysMessage( GetDictionaryEntry( 19224, pSockAttacker.language), pDefender.name);// You have poisoned your target : + if( pSockDefender != null ) + pSockDefender.SysMessage( pAttacker.name, GetDictionaryEntry( 19225, pSockDefender.language ));// %i : poisoned you! + + pDefender.poison = level; + + pAttacker.SoundEffect( 0xDD, true ); + pDefender.StaticEffect( 0x3728, 0x09, 0x32 ); + TriggerEvent( 2206, "ClearSpecialMove", pAttacker, abilityID );// Clear the Ability after success + } + else if( abilityID == 9 ) // Mortal Strike + { + + // Clear out any current ability the player is doing when he switches abilities + if( abilityID != 9 ) + TriggerEvent( 2206, "DeactivateSpecialMove", pAttacker, abilityID ); + + //checking mana + if( CheckMana( pAttacker, abilityID )) + { + DeductMana( pAttacker, abilityID ); + } + + pSockAttacker.SysMessage( GetDictionaryEntry( 19226, pSockAttacker.language ));// You deliver a mortal wound! + + if( pSockDefender != null ) + pSockDefender.SysMessage( GetDictionaryEntry( 19227, pSockDefender.language ));// You have been mortally wounded! + + pAttacker.SoundEffect( 0x1E1, true ); + pDefender.StaticEffect( 0x37B9, 0x09, 0x32 ); + + pDefender.SetTempTag( "blockHeal", true ); + + var seconds = 6000; // We want this applied to players even if they are "offline" (aka disconnected but not vanished from view yet) + if( pDefender.npc ) + { + seconds = 12000; + } + pDefender.StartTimer(seconds, 9200, true ); + + if( pDefender.socket ) + TriggerEvent( 50104, "AddBuff", pDefender, 1027, 1075810, 1075811, 6, " " ); + + TriggerEvent( 2206, "ClearSpecialMove", pAttacker, abilityID );// Clear the Ability after success + } + else if( abilityID == 10 ) // Moving Shot + { + // Clear out any current ability the player is doing when he switches abilities + if( abilityID != 10 ) + TriggerEvent( 2206, "DeactivateSpecialMove", pAttacker, abilityID ); + + //checking mana + if( CheckMana( pAttacker, abilityID )) + { + DeductMana( pAttacker, abilityID ); + } + + TriggerEvent( 2206, "ClearSpecialMove", pAttacker, abilityID );// Clear the Ability after success + } + else if( abilityID == 11 ) // ParalyzingBlow + { + // Clear out any current ability the player is doing when he switches abilities + if( abilityID != 11 ) + TriggerEvent( 2206, "DeactivateSpecialMove", pAttacker, abilityID ); + + //checking mana + if( CheckMana( pAttacker, abilityID )) + { + DeductMana( pAttacker, abilityID ); + } + + pAttacker.SoundEffect( 0x204, true ); + pDefender.StaticEffect( 0x376A, 0x09, 0x32 ); + var isImmune = pDefender.GetTempTag( "isImmune" ) + + if( isImmune != null && isImmune == true ) + { + pSockAttacker.SysMessage( GetDictionaryEntry( 19228, pSockAttacker.language ));// Your target resists paralysis. + if( pSockDefender != null ) + pSockDefender.SysMessage( GetDictionaryEntry( 19229, pSockDefender.language ));// You resist paralysis. + return true; + } + + var seconds = 3000; // We want this applied to players even if they are "offline" (aka disconnected but not vanished from view yet) + if( pDefender.npc ) + { + seconds = 6000; + } + else if( pDefender.socket ) + { + pSockDefender.TextMessage( GetDictionaryEntry( 19230, pSockDefender.language ), false, 0x3b2, 0, pDefender.serial );// The attack has temporarily paralyzed you! + } + + pDefender.SetTempTag( "isImmune", true ); + pDefender.StartTimer( seconds + 8000, 9000, 7001 ); + pDefender.StartTimer( seconds, 8000, 7001 ); + pDefender.frozen = true; + + if( pAttacker.socket ) + { + pSockAttacker.SysMessage( GetDictionaryEntry( 17702, pAttacker.socket.language), false, 0x3b2, 0, pAttacker.serial );// You deliver a paralyzing blow! + } + TriggerEvent( 2206, "ClearSpecialMove", pAttacker, abilityID );// Clear the Ability after success + } + else if( abilityID == 12 ) // shadowstrike + { + if( pAttacker.skills[47] < 800 ) // Stealth + { + pSockAttacker.SysMessage( GetDictionaryEntry( 19231, pSockAttacker.language ));// "You lack the required stealth to perform that attack + TriggerEvent( 2206, "DeactivateSpecialMove", pAttacker, abilityID ); + return true; + } + + // Clear out any current ability the player is doing when he switches abilities + if( abilityID != 12 ) + TriggerEvent( 2206, "DeactivateSpecialMove", pAttacker, abilityID ); + + //checking mana + if( CheckMana( pAttacker, abilityID )) + { + DeductMana( pAttacker, abilityID ); + } + + pSockAttacker.SysMessage( GetDictionaryEntry( 19232, pSockAttacker.language ));// You strike and hide in the shadows! + if( pSockDefender != null ) + pSockDefender.SysMessage( GetDictionaryEntry( 19233, pSockDefender.language ));// You are dazed by the attack and your attacker vanishes! + + pAttacker.StaticEffect( 0x376A, 0x09, 0x06 ); + + pDefender.SoundEffect( 0x482, true ); + pDefender.StaticEffect( 0x37BE, 0x09, 0x06 ); + + pAttacker.atWar = false; + pDefender.atWar = false; + pAttacker.visible = 1; + + TriggerEvent( 2206, "ClearSpecialMove", pAttacker, abilityID ); + } + else if( abilityID == 13 ) // Whirlwind Attack + { + // Clear out any current ability the player is doing when he switches abilities + if( abilityID != 13 ) + TriggerEvent(2206, "DeactivateSpecialMove", pAttacker, abilityID); + + //checking mana + if( CheckMana(pAttacker, abilityID )) + { + DeductMana( pAttacker, abilityID ); + } + + TriggerEvent( 2206, "ClearSpecialMove", pAttacker, abilityID );// Clear the Ability after success + } +} + +function onTimer( timerObj, timerID ) +{ + var socket = timerObj.socket; + var abilityID = timerObj.GetTempTag( "abilityID" ); + var damage = 31; + + if( timerObj == null || timerObj.dead) + { + timerObj.frozen = false; + timerObj.SetTempTag( "isImmune", null ); + timerObj.RemoveScriptTrigger( 7002 ); + timerObj.SetTempTag( "blockEquip", null ); + timerObj.SetTempTag( "blockHeal", null ); + timerObj.KillJSTimer( 9400, 7001 ); + timerObj.SetTempTag( "doBleed", null ); + TriggerEvent( 2206, "ClearSpecialMove", timerObj, abilityID ); + return; + } + else if( timerID == 8000 ) + { + timerObj.frozen = false; + } + else if( timerID == 9000 ) + { + timerObj.SetTempTag( "isImmune", null ); + } + else if( timerID == 9100 ) + { + timerObj.RemoveScriptTrigger( 7002 ); + timerObj.SetTempTag( "blockEquip", null ); + if( socket != null ) + socket.SysMessage( GetDictionaryEntry( 19234, socket.language ));// Your confusion has passed, you may now arm a weapon! + } + else if( timerID == 9200 ) + { + timerObj.SetTempTag("blockHeal", null ); + socket.SysMessage( GetDictionaryEntry( 19235, socket.language ));// You are no longer mortally wounded. + } + + if( timerID >= 9300 && timerID < 9310 ) + { + var damage = RandomNumber( 1, 10 ); + //timerObj.StaticEffect( 0x122A, 0, 15); // blood effect got to figure how to add it to ground. + timerObj.health -= damage; + timerObj.StartTimer( 2000, 9300 + 1, 7001 );//restart timer every 2 seconds until it shuts off + } + else if( timerID == 9310 ) + { + timerObj.SetTempTag( "doBleed", null ); + timerObj.KillJSTimer( 9400, 7001 ); + if( socket != null ) + socket.SysMessage( GetDictionaryEntry( 19236, socket.language ));// The bleeding wounds have healed, you are no longer bleeding! + } +} diff --git a/data/js/commands/custom/misc-cmd.js b/data/js/commands/custom/misc-cmd.js index 0478985b3..f4ac8589f 100644 --- a/data/js/commands/custom/misc-cmd.js +++ b/data/js/commands/custom/misc-cmd.js @@ -1051,7 +1051,7 @@ function onCallback29( pSock, myTarget ) pSock.SysMessage( tempMsg.replace( /%s/gi, newExpiryTime )); tempMsg = GetDictionaryEntry( 2765, pSock.language ); // // Remaining time: %d seconds - pSock.SysMessage( tempMsg.replace( /%d/gi, (( expiryTime - currentTime ) / 1000 ).toString() )); + pSock.SysMessage(tempMsg.replace(/%d/gi, Math.round(( expiryTime - currentTime ) / 1000 ).toString() )); } else { @@ -1189,9 +1189,10 @@ function onCallback32( socket, ourObj ) var x = socket.GetWord( 11 ); var y = socket.GetWord( 13 ); var z = socket.GetSByte( 16 ); + var StrangeByte = socket.GetWord(1); // If connected with a client lower than v7.0.9, manually add height of targeted tile - if( socket.clientMajorVer <= 7 && socket.clientSubVer < 9 ) + if ((StrangeByte == 0 && ourObj.isItem) || (socket.clientMajorVer <= 7 && socket.clientSubVer < 9)) { z += GetTileHeight( socket.GetWord( 17 )); } @@ -1239,9 +1240,10 @@ function onCallback33( socket, ourObj ) var x = socket.GetWord( 11 ); var y = socket.GetWord( 13 ); var z = socket.GetSByte( 16 ); + var StrangeByte = socket.GetWord(1); // If connected with a client lower than v7.0.9, manually add height of targeted tile - if( socket.clientMajorVer <= 7 && socket.clientSubVer < 9 ) + if ((StrangeByte == 0 && ourObj.isItem) || (socket.clientMajorVer <= 7 && socket.clientSubVer < 9)) { z += GetTileHeight( socket.GetWord( 17 )); } diff --git a/data/js/commands/custom/repeatingcmds.js b/data/js/commands/custom/repeatingcmds.js index da41a6f27..63220f133 100644 --- a/data/js/commands/custom/repeatingcmds.js +++ b/data/js/commands/custom/repeatingcmds.js @@ -301,9 +301,10 @@ function onCallback6( pSock, myTarget ) var targX = pSock.GetWord( 11 ); var targY = pSock.GetWord( 13 ); var targZ = pSock.GetSByte( 16 ); + var StrangeByte = pSock.GetWord(1); // If connected with a client lower than v7.0.9, manually add height of targeted tile - if( pSock.clientMajorVer <= 7 && pSock.clientSubVer < 9 ) + if ((StrangeByte == 0 && myTarget.isItem) || (pSock.clientMajorVer <= 7 && pSock.clientSubVer < 9)) { targZ += GetTileHeight( pSock.GetWord( 17 )); } @@ -466,9 +467,10 @@ function onCallback8( pSock, myTarget ) var targX = pSock.GetWord( 11 ); var targY = pSock.GetWord( 13 ); var targZ = pSock.GetSByte( 16 ); + var StrangeByte = pSock.GetWord(1); // If connected with a client lower than v7.0.9, manually add height of targeted tile - if( pSock.clientMajorVer <= 7 && pSock.clientSubVer < 9 ) + if ((StrangeByte == 0 && myTarget.isItem) || (pSock.clientMajorVer <= 7 && pSock.clientSubVer < 9)) { targZ += GetTileHeight( pSock.GetWord( 17 )); } @@ -548,9 +550,10 @@ function onCallback9( pSock, myTarget ) var targX = pSock.GetWord( 11 ); var targY = pSock.GetWord( 13 ); var targZ = pSock.GetSByte( 16 ); + var StrangeByte = pSock.GetWord(1); // If connected with a client lower than v7.0.9, manually add height of targeted tile - if( pSock.clientMajorVer <= 7 && pSock.clientSubVer < 9 ) + if ((StrangeByte == 0 && myTarget.isItem) || (pSock.clientMajorVer <= 7 && pSock.clientSubVer < 9)) { targZ += GetTileHeight( pSock.GetWord( 17 )); } @@ -585,9 +588,10 @@ function onCallback10( pSock, myTarget ) var targX = pSock.GetWord( 11 ); var targY = pSock.GetWord( 13 ); var targZ = pSock.GetSByte( 16 ); + var StrangeByte = pSock.GetWord(1); // If connected with a client lower than v7.0.9, manually add height of targeted tile - if( pSock.clientMajorVer <= 7 && pSock.clientSubVer < 9 ) + if ((StrangeByte == 0 && myTarget.isItem) || (pSock.clientMajorVer <= 7 && pSock.clientSubVer < 9)) { targZ += GetTileHeight( pSock.GetWord( 17 )); } @@ -628,9 +632,10 @@ function onCallback11( pSock, myTarget ) var targX = pSock.GetWord( 11 ); var targY = pSock.GetWord( 13 ); var targZ = pSock.GetSByte( 16 ); + var StrangeByte = pSock.GetWord(1); // If connected with a client lower than v7.0.9, manually add height of targeted tile - if( pSock.clientMajorVer <= 7 && pSock.clientSubVer < 9 ) + if ((StrangeByte == 0 && myTarget.isItem) || (pSock.clientMajorVer <= 7 && pSock.clientSubVer < 9)) { targZ += GetTileHeight( pSock.GetWord( 17 )); } diff --git a/data/js/commands/targeting/add.js b/data/js/commands/targeting/add.js index c5c3f2d0d..124252826 100644 --- a/data/js/commands/targeting/add.js +++ b/data/js/commands/targeting/add.js @@ -110,9 +110,10 @@ function onCallback0( socket, ourObj ) var x = socket.GetWord( 11 ); var y = socket.GetWord( 13 ); var z = socket.GetSByte( 16 ); + var StrangeByte = socket.GetWord(1); // If connected with a client lower than v7.0.9, manually add height of targeted tile - if( socket.clientMajorVer <= 7 && socket.clientSubVer < 9 ) + if ((StrangeByte == 0 && ourObj.isItem) || (socket.clientMajorVer <= 7 && socket.clientSubVer < 9)) { z += GetTileHeight( socket.GetWord( 17 )); } @@ -183,7 +184,7 @@ function onCallback1( socket, ourObj ) var z = socket.GetSByte( 16 ); // If connected with a client lower than v7.0.9, manually add height of targeted tile - if( socket.clientMajorVer <= 7 && socket.clientSubVer < 9 ) + if ((StrangeByte == 0 && ourObj.isItem) || (socket.clientMajorVer <= 7 && socket.clientSubVer < 9)) { z += GetTileHeight( socket.GetWord( 17 )); } @@ -257,7 +258,7 @@ function onCallback2( socket, ourObj ) var z = socket.GetSByte( 16 ); // If connected with a client lower than v7.0.9, manually add height of targeted tile - if( socket.clientMajorVer <= 7 && socket.clientSubVer < 9 ) + if ((StrangeByte == 0 && ourObj.isItem) || (socket.clientMajorVer <= 7 && socket.clientSubVer < 9)) { z += GetTileHeight( socket.GetWord( 17 )); } @@ -287,9 +288,10 @@ function onCallback3( socket, ourObj ) var x = socket.GetWord( 11 ); var y = socket.GetWord( 13 ); var z = socket.GetSByte( 16 ); + var StrangeByte = socket.GetWord(1); // If connected with a client lower than v7.0.9, manually add height of targeted tile - if( socket.clientMajorVer <= 7 && socket.clientSubVer < 9 ) + if ((StrangeByte == 0 && ourObj.isItem) || (socket.clientMajorVer <= 7 && socket.clientSubVer < 9)) { z += GetTileHeight( socket.GetWord( 17 )); } @@ -324,9 +326,10 @@ function onCallback4( socket, ourObj ) var x = socket.GetWord( 11 ); var y = socket.GetWord( 13 ); var z = socket.GetSByte( 16 ); + var StrangeByte = socket.GetWord(1); // If connected with a client lower than v7.0.9, manually add height of targeted tile - if( socket.clientMajorVer <= 7 && socket.clientSubVer < 9 ) + if ((StrangeByte == 0 && ourObj.isItem) || (socket.clientMajorVer <= 7 && socket.clientSubVer < 9)) { z += GetTileHeight( socket.GetWord( 17 )); } @@ -464,4 +467,6 @@ function AddXItemSpawner( socket, cmdString, itemType ) } } } -} \ No newline at end of file +} + +function _restorecontext_() {} \ No newline at end of file diff --git a/data/js/commands/targeting/get.js b/data/js/commands/targeting/get.js index 365d3a2b3..24ec9a986 100644 --- a/data/js/commands/targeting/get.js +++ b/data/js/commands/targeting/get.js @@ -169,6 +169,9 @@ function onCallback0( socket, ourObj ) case "SECTIONID": socket.SysMessage( ourObj.sectionID ); break; + case "SWINGSPEEDINC": + socket.SysMessage( swingSpeedIncrease ); + break; case "SHOULDSAVE": socket.SysMessage( ourObj.shouldSave ); break; @@ -294,30 +297,30 @@ function HandleGetItem( socket, ourItem, uKey ) case "DESC": socket.SysMessage( ourItem.desc ); break; - case "DEF": - socket.SysMessage( ourItem.Resist( 1 )); - break; case "DEF": case "RESISTARMOR": - socket.SysMessage( ourObj.Resist( 1 )); + socket.SysMessage( ourItem.Resist( 1 )); break; case "RESISTLIGHT": - socket.SysMessage( ourObj.Resist( 2 )); + socket.SysMessage( ourItem.Resist( 2 )); break; case "RESISTWATER": - socket.SysMessage( ourObj.Resist( 3 )); + socket.SysMessage( ourItem.Resist( 3 )); break; case "RESISTCOLD": - socket.SysMessage( ourObj.Resist( 4 )); + socket.SysMessage( ourItem.Resist( 4 )); break; case "RESISTFIRE": - socket.SysMessage( ourObj.Resist( 5 )); + socket.SysMessage( ourItem.Resist( 5 )); break; case "RESISTENERGY": - socket.SysMessage( ourObj.Resist( 6 )); + socket.SysMessage( ourItem.Resist( 6 )); break; case "RESISTPOISON": - socket.SysMessage( ourObj.Resist( 7 )); + socket.SysMessage( ourItem.Resist( 7 )); + break; + case "LOWERSTATREQ": + socket.SysMessage( ourObj.lowerStatReq ); break; case "ARMORCLASS": case "ARMOURCLASS": @@ -598,8 +601,27 @@ function HandleGetChar( socket, ourChar, uKey ) break; case "ARMOUR": case "ARMOR": + case "RESISTARMOR": socket.SysMessage( ourChar.Resist( 1 )); break; + case "RESISTLIGHT": + socket.SysMessage( ourChar.Resist( 2 )); + break; + case "RESISTWATER": + socket.SysMessage( ourChar.Resist( 3 )); + break; + case "RESISTCOLD": + socket.SysMessage( ourChar.Resist( 4 )); + break; + case "RESISTFIRE": + socket.SysMessage( ourChar.Resist( 5 )); + break; + case "RESISTENERGY": + socket.SysMessage( ourChar.Resist( 6 )); + break; + case "RESISTPOISON": + socket.SysMessage( ourChar.Resist( 7 )); + break; case "MAXHP": socket.SysMessage( ourChar.maxhp ); break; diff --git a/data/js/commands/targeting/magic.js b/data/js/commands/targeting/magic.js index a88799299..43aec9093 100644 --- a/data/js/commands/targeting/magic.js +++ b/data/js/commands/targeting/magic.js @@ -52,7 +52,7 @@ function onCallback1( socket, ourObj ) var serialPart4 = ( shipSerial % 256 ); var shipMulti = CalcMultiFromSer( serialPart1, serialPart2, serialPart3, serialPart4 ); - if( ValidateObject( shipMulti ) && shipMulti.isBoat() ) + if( ValidateObject( shipMulti ) && shipMulti.IsBoat() ) { if( shipMulti.worldnumber == socket.currentChar.worldnumber && shipMulti.instanceID == socket.currentChar.instanceID ) { diff --git a/data/js/commands/targeting/set.js b/data/js/commands/targeting/set.js index e9b4f3226..366d8bfcf 100644 --- a/data/js/commands/targeting/set.js +++ b/data/js/commands/targeting/set.js @@ -98,6 +98,10 @@ function onCallback0( socket, ourObj ) ourObj.Resist( 7, nVal ); okMsg( socket ); break; + case "LOWERSTATREQ": + ourItem.lowerStatReq = nVal; + okMsg( socket ); + break; case "HP": case "HEALTH": ourObj.health = nVal; @@ -169,6 +173,10 @@ function onCallback0( socket, ourObj ) ourObj.tempdex = nVal; okMsg( socket ); break; + case "SWINGSPEEDINC": + ourObj.swingSpeedIncrease = nVal; + okMsg( socket ); + break; case "WIPABLE": case "WIPEABLE": ourObj.wipable = ( nVal == 1 ); diff --git a/data/js/commands/targeting/tele.js b/data/js/commands/targeting/tele.js index c8ce29313..a920fa7cd 100644 --- a/data/js/commands/targeting/tele.js +++ b/data/js/commands/targeting/tele.js @@ -60,9 +60,10 @@ function onCallback1( socket, ourObj ) var x = socket.GetWord( 11 ); var y = socket.GetWord( 13 ); var z = socket.GetSByte( 16 ); + var StrangeByte = socket.GetWord(1); // If connected with a client lower than v7.0.9, manually add height of targeted tile - if( socket.clientMajorVer <= 7 && socket.clientSubVer < 9 ) + if ((StrangeByte == 0 && ourObj.isItem) || (socket.clientMajorVer <= 7 && socket.clientSubVer < 9)) { z += GetTileHeight( socket.GetWord( 17 )); } @@ -109,9 +110,10 @@ function onCallback2( socket, ourObj ) targX = socket.GetWord( 11 ); targY = socket.GetWord( 13 ); targZ = socket.GetSByte( 16 ); + var StrangeByte = socket.GetWord(1); // If connected with a client lower than v7.0.9, manually add height of targeted tile - if( socket.clientMajorVer <= 7 && socket.clientSubVer < 9 ) + if ((StrangeByte == 0 && ourObj.isItem) || (socket.clientMajorVer <= 7 && socket.clientSubVer < 9)) { targZ += GetTileHeight( socket.GetWord( 17 )); } diff --git a/data/js/item/equip_effects/weapon_abilities.js b/data/js/item/equip_effects/weapon_abilities.js index 2c18c180c..18f71375a 100644 --- a/data/js/item/equip_effects/weapon_abilities.js +++ b/data/js/item/equip_effects/weapon_abilities.js @@ -14,7 +14,7 @@ function onUnequip( pUnequipper, iUnequipped ) pUnequipper.RemoveScriptTrigger( 5050 ); } -function onAttack( pAttacker, pDefender ) +function onAttack( pAttacker, pDefender, hitStatus, hitLoc, damageDealt ) { const coreShardEra = GetServerSetting( "CoreShardEra" ); var weaponType = TriggerEvent( 2500, "GetWeaponType", pAttacker, null ); diff --git a/data/js/item/holidays/addondeedgump.js b/data/js/item/holidays/addondeedgump.js index 36e94e3e3..1f0851f6e 100644 --- a/data/js/item/holidays/addondeedgump.js +++ b/data/js/item/holidays/addondeedgump.js @@ -181,7 +181,7 @@ function CheckForNearbyDoors( myTarget, itemToCheck, pSocket ) } } - if( myTarget.DistanceTo(itemToCheck) <= 2 ) + if( myTarget.DistanceTo( itemToCheck ) <= 2 ) { return true; } diff --git a/data/js/item/holidays/candy.js b/data/js/item/holidays/candy.js index cbe3cdae9..ed007641a 100644 --- a/data/js/item/holidays/candy.js +++ b/data/js/item/holidays/candy.js @@ -18,7 +18,6 @@ function onUseChecked(pUser, iUsed) } else { - socket.SysMessage("test 1"); if( Acidity <= 30 ) { pUser.SetTempTag( "Acidity", Acidity += 5 ); @@ -26,7 +25,6 @@ function onUseChecked(pUser, iUsed) if ( Toothach == 0) { - socket.SysMessage("test 2"); pUser.SetTempTag( "toothach", 1 ); pUser.StartTimer( 1000, 0, true ); } diff --git a/data/js/item/holidays/halloweenmasks.js b/data/js/item/holidays/halloweenmasks.js index ac1919dd4..f1f031843 100644 --- a/data/js/item/holidays/halloweenmasks.js +++ b/data/js/item/holidays/halloweenmasks.js @@ -3,7 +3,7 @@ function onCreateDFN( objMade, objType ) if( objType == 0 ) { var maskname = ""; - switch(objMade.GetTag( "paintedmask" )) + switch( objMade.GetTag( "paintedmask" )) { case 1: maskname = "A Evil Clown Mask"; break; case 2: maskname = "A Daemon Mask"; break; diff --git a/data/js/item/holidays/headonaspike.js b/data/js/item/holidays/headonaspike.js index 8da857603..44b8b6192 100644 --- a/data/js/item/holidays/headonaspike.js +++ b/data/js/item/holidays/headonaspike.js @@ -4,7 +4,7 @@ function onUseChecked( pUser, iUsed ) var headspike = new Gump; var head = 0; - switch (iUsed.sectionID) + switch( iUsed.sectionID ) { case "MrsTroubleMakersHeadOnASpike": head = 30522; break; case "BrutrinsHeadOnASpike": head = 30522; break; @@ -20,7 +20,7 @@ function onUseChecked( pUser, iUsed ) default: head = 30522; } - headspike.AddGump(100, 100, head); - headspike.Send(pUser); + headspike.AddGump( 100, 100, head ); + headspike.Send( pUser ); headspike.Free(); } \ No newline at end of file diff --git a/data/js/item/holidays/holidaypottedplant.js b/data/js/item/holidays/holidaypottedplant.js index 0cc81122f..df0948203 100644 --- a/data/js/item/holidays/holidaypottedplant.js +++ b/data/js/item/holidays/holidaypottedplant.js @@ -11,14 +11,14 @@ function onUseChecked( pUser, iUsed ) PottedPlantGump( pUser, iUsed ); } -function PottedPlantGump(pUser, iUsed) +function PottedPlantGump( pUser, iUsed ) { var socket = pUser.socket; socket.tempObj = iUsed; var pottedPlant = new Gump; pottedPlant.AddPage( 0 ); - pottedPlant.AddBackground(0, 0, 360, 195, 0xA28); + pottedPlant.AddBackground( 0, 0, 360, 195, 0xA28 ); pottedPlant.AddPage( 1 ); pottedPlant.AddText( 45, 15, 0, "Choose a Potted Plant:" ); @@ -35,7 +35,7 @@ function PottedPlantGump(pUser, iUsed) pottedPlant.Free(); } -function onGumpPress(pSock, pButton, gumpData) +function onGumpPress( pSock, pButton, gumpData ) { var pUser = pSock.currentChar; var iUsed = pSock.tempObj; @@ -48,7 +48,7 @@ function onGumpPress(pSock, pButton, gumpData) } var pottedplant = ""; - if ( pButton >= 1 && pButton <= 5 ) + if( pButton >= 1 && pButton <= 5 ) { var plantIds = [0x11C8, 0x11C9, 0x11CA, 0x11CB, 0x11CC]; pottedplant = "0x" + ( plantIds[pButton - 1] ).toString( 16 ); diff --git a/data/js/item/holidays/pumpkins.js b/data/js/item/holidays/pumpkins.js index e63df2678..6476bf0d3 100644 --- a/data/js/item/holidays/pumpkins.js +++ b/data/js/item/holidays/pumpkins.js @@ -16,7 +16,7 @@ function onCreateDFN( objMade, objType ) if( objMade.id == 0x0C6A || objMade.id == 0x0C6B ) { - objMade.weight = Math.floor(Math.random() * ( 2500 - 1200 + 1 ) + 1200); + objMade.weight = Math.floor( Math.random() * ( 2500 - 1200 + 1 ) + 1200 ); } else if( objMade.id == 0x0C6C ) { @@ -72,22 +72,22 @@ function onUseChecked( pUser, iUsed ) // Randomize countdown length, if enabled if( randomizePumpkinCountdown ) { - iUsed.speed = RandomNumber(iUsed.speed - 1, iUsed.speed + 1); + iUsed.speed = RandomNumber( iUsed.speed - 1, iUsed.speed + 1 ); } // Item's speed forms the basis of the countdownTime var countdownTime = iUsed.speed * 1000; // Start the initial timer that shows the first number over the character/object's head - iUsed.StartTimer(200, 1, true); + iUsed.StartTimer( 200, 1, true ); // Start timers with IDs from 2, and count until we reach item's speed + 1 var iCount = 2; - for (iCount = 2; iCount < (iUsed.speed + 2); iCount++) + for( iCount = 2; iCount < ( iUsed.speed + 2 ); iCount++ ) { - iUsed.StartTimer((iCount - 1) * 1000, iCount, true); + iUsed.StartTimer(( iCount - 1) * 1000, iCount, true ); } - socket.CustomTarget(0, GetDictionaryEntry(1348, socket.language)); //Now would be a good time to throw it! + socket.CustomTarget( 0, GetDictionaryEntry( 1348, socket.language )); //Now would be a good time to throw it! } return false; } @@ -96,7 +96,7 @@ function onCallback0( socket, ourObj ) { var mChar = socket.currentChar; var iUsed = socket.tempObj; - if ( mChar && mChar.isChar && iUsed && iUsed.isItem ) + if( mChar && mChar.isChar && iUsed && iUsed.isItem ) { var StrangeByte = socket.GetWord( 1 ); if( StrangeByte == 0 && ourObj ) @@ -107,7 +107,7 @@ function onCallback0( socket, ourObj ) iUsed.container = null; iUsed.Teleport( ourObj ); } - else + else { socket.SysMessage( GetDictionaryEntry( 1646, socket.language )); // You cannot see that @@ -121,9 +121,10 @@ function onCallback0( socket, ourObj ) var x = socket.GetWord( 11 ); var y = socket.GetWord( 13 ); var z = socket.GetSByte( 16 ); + var StrangeByte = socket.GetWord(1); // If connected with a client lower than v7.0.9, manually add height of targeted tile - if( socket.clientMajorVer <= 7 && socket.clientSubVer < 9 ) + if ((StrangeByte == 0 && ourObj.isItem) || (socket.clientMajorVer <= 7 && socket.clientSubVer < 9)) { z += GetTileHeight( socket.GetWord( 17 )); } @@ -252,7 +253,7 @@ function ApplyExplosionDamage( timerObj, targetChar ) return; // Deal damage, and do criminal check for source character! - targetChar.Damage(RandomNumber( timerObj.lodamage, timerObj.hidamage ), 5, sourceChar, true ); + targetChar.Damage( RandomNumber( timerObj.lodamage, timerObj.hidamage ), 5, sourceChar, true ); // If target is an NPC, make them attack the person who threw the potion! if( targetChar.npc && targetChar.target == null && targetChar.atWar == false ) @@ -299,7 +300,7 @@ function onPickup( iPickedUp, pGrabber, containerObj ) else if( iPickedUp.GetTag( "Named" ) == 0 ) { iPickedUp.name = pGrabber.name + " Pumpkin"; - iPickedUp.SetTag("Named", 1); + iPickedUp.SetTag( "Named", 1 ); } } return true; diff --git a/data/js/item/holidays/snowpile.js b/data/js/item/holidays/snowpile.js index c2e92ecc9..58d289745 100644 --- a/data/js/item/holidays/snowpile.js +++ b/data/js/item/holidays/snowpile.js @@ -59,7 +59,7 @@ function onCallback0( socket, myTarget ) pUser.visible = 0; } - if (!socket.GetWord(1) && myTarget.isChar && myTarget.socket ) + if( !socket.GetWord( 1 ) && myTarget.isChar && myTarget.socket ) { pUser.DoAction( 0x9 ); pUser.SoundEffect( 0x145, true ); @@ -73,10 +73,10 @@ function onCallback0( socket, myTarget ) } } -function onTimer( pUser, timerID ) +function onTimer( pUser, timerID ) { var socket = pUser.socket; - if( pUser.visible == 1 || pUser.visible == 2 ) + if( pUser.visible == 1 || pUser.visible == 2 ) { pUser.visible = 0; } diff --git a/data/js/item/magic_weapon_spell_attack.js b/data/js/item/magic_weapon_spell_attack.js index 26abc0be9..ace1dfa4d 100644 --- a/data/js/item/magic_weapon_spell_attack.js +++ b/data/js/item/magic_weapon_spell_attack.js @@ -7,7 +7,7 @@ const scriptID = 3305; // spells.dfn const useAttackerMagerySkill = false; -function onAttack( mAttacker, mDefender ) +function onAttack( mAttacker, mDefender, hitStatus, hitLoc, damageDealt ) { // Fetch weapon in main hand var iWeapon = mAttacker.FindItemLayer( 0x01 ); diff --git a/data/js/item/potion.js b/data/js/item/potion.js index d92697cfb..23f3de1b4 100644 --- a/data/js/item/potion.js +++ b/data/js/item/potion.js @@ -6,14 +6,25 @@ const alchemyBonusModifier = parseInt( GetServerSetting( "AlchemyBonusModifier" // Other settings const randomizePotionCountdown = false; // If true, add/remove +1/-1 seconds to explosion potion countdowns +const reqFreeHands = true; function onUseChecked( pUser, iUsed ) { var socket = pUser.socket; - if ( pUser.visible == 1 || pUser.visible == 2 ) + var itemRHand = pUser.FindItemLayer( 0x01 ); + var itemLHand = pUser.FindItemLayer( 0x02 ); + + if( reqFreeHands && ( itemRHand != null || itemLHand != null ) ) + { + socket.SysMessage( GetDictionaryEntry( 6304, socket.language ) );// You must have a free hand to drink a potion. + return false; + } + + if( pUser.visible == 1 || pUser.visible == 2 ) { pUser.visible = 0; } + if( socket && iUsed && iUsed.isItem ) { if( pUser.isUsingPotion ) @@ -161,7 +172,7 @@ function onUseChecked( pUser, iUsed ) case 4: // Heal Potion if( pUser.health < pUser.maxhp ) { - if( pUser.poison > 0 ) + if( pUser.poison > 0 || pUser.GetTempTag( "blockHeal" ) == true ) { pUser.SysMessage( GetDictionaryEntry( 9058, socket.language )); // You can not heal yourself in your current state. return; @@ -329,9 +340,10 @@ function onCallback0( socket, ourObj ) var x = socket.GetWord( 11 ); var y = socket.GetWord( 13 ); var z = socket.GetSByte( 16 ); + var StrangeByte = socket.GetWord(1); // If connected with a client lower than v7.0.9, manually add height of targeted tile - if( socket.clientMajorVer <= 7 && socket.clientSubVer < 9 ) + if ((StrangeByte == 0 && ourObj.isItem) || (socket.clientMajorVer <= 7 && socket.clientSubVer < 9)) { z += GetTileHeight( socket.GetWord( 17 )); } diff --git a/data/js/item/puzzlechest.js b/data/js/item/puzzlechest.js new file mode 100644 index 000000000..37e2f5fed --- /dev/null +++ b/data/js/item/puzzlechest.js @@ -0,0 +1,444 @@ +const PuzzleChestCylinder = { + None: 0xE73, + LightBlue: 0x186F, + Blue: 0x186A, + Green: 0x186B, + Orange: 0x186C, + Purple: 0x186D, + Red: 0x186E, + DarkBlue: 0x1869, + Yellow: 0x1870 +}; + +function PuzzleChestSolution( cylinders ) +{ + this.cylinders = cylinders || [ + RandomCylinder(), + RandomCylinder(), + RandomCylinder(), + RandomCylinder(), + RandomCylinder() + ]; +} + +function RandomCylinder() +{ + var randomValue = RandomNumber( 0, 8 ); + switch ( randomValue ) + { + case 0: return PuzzleChestCylinder.LightBlue; + case 1: return PuzzleChestCylinder.Blue; + case 2: return PuzzleChestCylinder.Green; + case 3: return PuzzleChestCylinder.Orange; + case 4: return PuzzleChestCylinder.Purple; + case 5: return PuzzleChestCylinder.Red; + case 6: return PuzzleChestCylinder.DarkBlue; + default: return PuzzleChestCylinder.Yellow; + } +} + +function CompareSolutions( solutionCylinders, guessCylinders ) +{ + var correctCylinders = 0; + var correctColors = 0; + var matchesSrc = [false, false, false, false, false]; + var matchesDst = [false, false, false, false, false]; + + // Check for exact matches ( correct position and color ) + for ( var i = 0; i < solutionCylinders.length; i++ ) + { + if( solutionCylinders[i] == guessCylinders[i] ) + { + correctCylinders++; + matchesSrc[i] = true; + matchesDst[i] = true; + } + } + + // Check for color matches ( wrong position ) + for ( var i = 0; i < solutionCylinders.length; i++ ) + { + if( !matchesSrc[i] ) + { + for ( var j = 0; j < guessCylinders.length; j++ ) + { + if( solutionCylinders[i] == guessCylinders[j] && !matchesDst[j] ) + { + correctColors++; + matchesDst[j] = true; + break; + } + } + } + } + + return { + correctCylinders: correctCylinders, + correctColors: correctColors + }; +} + +function onCreateDFN( objMade, objType ) +{ + if( objType == 0 ) + { + objMade.SetTag( "locked", "true" ); // Lock the chest by default + var solution = new PuzzleChestSolution(); + objMade.SetTag( "solution", SerializeSolution( solution )); // Store the solution as a serialized string + } +} + +function onUseChecked( pUser, pItem ) +{ + var socket = pUser.socket; + socket.tempObj = pItem; + + if( pItem.GetTag( "locked" ) == "true" ) + { + var serializedSolution = pItem.GetTag( "solution" ); + var solution = DeserializeSolution( serializedSolution ); + var lastGuess = pUser.GetTag( "lastGuess" ); + + // Initialize lastGuess if it doesn't exist + if( !lastGuess ) + { + lastGuess = new PuzzleChestSolution(); + pUser.SetTag( "lastGuess", SerializeSolution( lastGuess )); + } + else + { + lastGuess = DeserializeSolution( pUser.GetTag( "lastGuess" )); + } + + // Calculate the number of correct cylinders and colors + var result = CompareSolutions( solution.cylinders, lastGuess.cylinders ); + + // Generate hints based on player's lockpicking skill + var hints = GenerateHints( pUser, result.correctCylinders, result.correctColors ); + + // Show the puzzle gump to the player + ShowPuzzleGump( pUser, pItem, solution, 0 ); // Pass the solution and default check = 0 + } +} + +function onGumpPress( pSock, pButton, gumpData ) +{ + var pUser = pSock.currentChar; + var pItem = pSock.tempObj; // Access the temporary object from the socket + + // Deserialize the puzzle solution and the last guess from the player's tags + var solution = DeserializeSolution( pItem.GetTag( "solution" )); + var lastGuess = DeserializeSolution( pUser.GetTag( "lastGuess" )); + + if( pButton == 1 ) + { + // Submit button ( ID 1 ) + var result = CompareSolutions( solution.cylinders, lastGuess.cylinders ); + if( result.correctCylinders == 5 ) + { + // Unlock the chest ifthe guess is correct + pItem.SetTag( "locked", "false" ); + pUser.SysMessage( "The chest unlocks!" ); + pUser.SoundEffect( 0x241, true ); // Play unlock sound effect + + // Reward the player and clear the puzzle + RewardPlayer( pUser, pItem ); + pUser.SetTag( "lastGuess", null ); + pItem.Delete( ); // Delete the chest after it's unlocked + } + else + { + // Generate hints for incorrect guesses + var hints = GenerateHints( pUser, result.correctCylinders, result.correctColors ); + + // Show a status gump with hints and apply damage for incorrect guess + ShowStatusGump( pUser, result.correctCylinders, result.correctColors, hints.hint1, hints.hint2 ); + DamagePlayer( pUser ); // Apply damage to the player for incorrect guesses + } + } + else if( pButton >= 10 && pButton <= 17 ) + { + // Handle left and right buttons to change cylinder color + var selectedCylinderIndex = gumpData.getButton( 0 ); // Determine which cylinder was selected via radio buttons + + if( selectedCylinderIndex >= 0 && selectedCylinderIndex <= 4 ) + { + // Handle the color change based on which button was pressed ( cylinder color buttons 10-17 ) + switch ( pButton ) + { + case 10: + lastGuess.cylinders[selectedCylinderIndex] = PuzzleChestCylinder.LightBlue; + break; + case 11: + lastGuess.cylinders[selectedCylinderIndex] = PuzzleChestCylinder.Blue; + break; + case 12: + lastGuess.cylinders[selectedCylinderIndex] = PuzzleChestCylinder.Green; + break; + case 13: + lastGuess.cylinders[selectedCylinderIndex] = PuzzleChestCylinder.Orange; + break; + case 14: + lastGuess.cylinders[selectedCylinderIndex] = PuzzleChestCylinder.Purple; + break; + case 15: + lastGuess.cylinders[selectedCylinderIndex] = PuzzleChestCylinder.Red; + break; + case 16: + lastGuess.cylinders[selectedCylinderIndex] = PuzzleChestCylinder.DarkBlue; + break; + case 17: + lastGuess.cylinders[selectedCylinderIndex] = PuzzleChestCylinder.Yellow; + break; + } + } + + // Update the player's last guess + pUser.SetTag( "lastGuess", SerializeSolution( lastGuess )); + + // Redraw the puzzle gump to reflect the updated guess + ShowPuzzleGump( pUser, pItem, lastGuess, selectedCylinderIndex ); + } + else if( pButton == 100 ) + { + // OK button in status gump ( ID 100 ) + // Reshow the puzzle gump after closing the status gump + ShowPuzzleGump( pUser, pItem, lastGuess, 0 ); // Reshow the puzzle with the correct solution + } +} + +function ShowPuzzleGump( pUser, pItem, lastGuess, check ) +{ + var myGump = new Gump; + + // Add the main background and title + myGump.AddBackground( 25, 0, 500, 410, 0x53 ); + myGump.AddGump( 62, 20, 0x67, 0 ); // Title image + myGump.AddHTMLGump( 80, 36, 110, 70, false, false, "A Puzzle Lock" ); + + // Instructions + myGump.AddHTMLGump( 214, 26, 270, 90, false, false, + "Correctly choose the sequence of cylinders needed to open the latch. Each cylinder may potentially be used more than once. Beware! A false attempt could be deadly!" ); + + // Left cylinder buttons + AddLeftCylinderButton( myGump, 62, 130, PuzzleChestCylinder.LightBlue, 10 ); + AddLeftCylinderButton( myGump, 62, 180, PuzzleChestCylinder.Blue, 11 ); + AddLeftCylinderButton( myGump, 62, 230, PuzzleChestCylinder.Green, 12 ); + AddLeftCylinderButton( myGump, 62, 280, PuzzleChestCylinder.Orange, 13 ); + + // Right cylinder buttons + AddRightCylinderButton( myGump, 451, 130, PuzzleChestCylinder.Purple, 14 ); + AddRightCylinderButton( myGump, 451, 180, PuzzleChestCylinder.Red, 15 ); + AddRightCylinderButton( myGump, 451, 230, PuzzleChestCylinder.DarkBlue, 16 ); + AddRightCylinderButton( myGump, 451, 280, PuzzleChestCylinder.Yellow, 17 ); + + var solution = DeserializeSolution( pItem.GetTag( "solution" )); + // Call AddLockpickingHints with the solution from the chest + AddLockpickingHints( myGump, pUser, solution ); + + // Previous guess + var lastGuess = DeserializeSolution( pUser.GetTag( "lastGuess" )); + if( lastGuess ) + { + myGump.AddHTMLGump( 127, 249, 170, 20, false, false, "Thy previous guess:" ); + myGump.AddBackground( 290, 247, 115, 25, 0x13EC ); + + // Add each cylinder of the previous guess + for ( var i = 0; i < lastGuess.cylinders.length; i++ ) + { + AddCylinder( myGump, 281 + ( i * 22 ), 254, lastGuess.cylinders[i] ); + } + } + + // Pedestals for current guess + AddPedestal( myGump, 140, 270, lastGuess.cylinders[0], 0, check == 0 ); + AddPedestal( myGump, 195, 270, lastGuess.cylinders[1], 1, check == 1 ); + AddPedestal( myGump, 250, 270, lastGuess.cylinders[2], 2, check == 2 ); + AddPedestal( myGump, 305, 270, lastGuess.cylinders[3], 3, check == 3 ); + AddPedestal( myGump, 360, 270, lastGuess.cylinders[4], 4, check == 4 ); + + // Submit button + myGump.AddButton( 258, 370, 0xFA5, 0xFA7, 1, 0, 1 ); + + // Send the gump to the player + myGump.Send( pUser ); + myGump.Free( ); // Clear this gump from UOX memory +} + +function AddLockpickingHints( myGump, pUser, pChestSolution ) +{ + var lockpickingSkill = pUser.baseskills.lockpicking; // Lockpicking skill in UOX3 + + if( lockpickingSkill >= 600 ) + { + myGump.AddHTMLGump( 160, 125, 230, 24, false, false, "Lockpicking hint:" ); // Display the hint header + myGump.AddBackground( 159, 150, 230, 95, 0x13EC ); // Hint background + + // Add hints based on lockpicking skill thresholds + if( lockpickingSkill >= 800 ) + { + // Show the first correct cylinder from the chest solution + myGump.AddHTMLGump( 165, 157, 200, 40, false, false, "In the first slot:" ); + AddCylinder( myGump, 350, 165, pChestSolution.cylinders[0] ); // Show the first cylinder + + // Indicate that a cylinder is used in an unknown slot + myGump.AddHTMLGump( 165, 197, 200, 40, false, false, "Used in an unknown slot:" ); + AddCylinder( myGump, 350, 200, pChestSolution.cylinders[1] ); // Show the second cylinder as a hint + + if( lockpickingSkill >= 900 ) + { + // Add a hint for the third correct cylinder + AddCylinder( myGump, 350, 212, pChestSolution.cylinders[2] ); // Add third hint + } + if( lockpickingSkill >= 1000 ) + { + // Add a hint for the fourth correct cylinder + AddCylinder( myGump, 350, 224, pChestSolution.cylinders[3] ); // Add fourth hint + } + } + else + { + // Provide a basic hint ifthe player's skill is between 600-799 + myGump.AddHTMLGump( 165, 157, 200, 40, false, false, "Used in an unknown slot:" ); + AddCylinder( myGump, 350, 160, pChestSolution.cylinders[0] ); // Show the first cylinder as a basic hint + + if( lockpickingSkill >= 700 ) + { + // Add a second hint ifthe player's skill is 700-799 + AddCylinder( myGump, 350, 172, pChestSolution.cylinders[1] ); // Add second hint for 700+ skill + } + } + } +} + +function AddLeftCylinderButton( myGump, x, y, cylinder, buttonID ) +{ + myGump.AddBackground( x, y, 30, 30, 0x13EC ); + AddCylinder( myGump, x - 7, y + 10, cylinder ); + myGump.AddButton( x + 38, y + 9, 0x13A8, 0x13A9, 1, 0, buttonID ); +} + +function AddRightCylinderButton( myGump, x, y, cylinder, buttonID ) +{ + myGump.AddBackground( x, y, 30, 30, 0x13EC ); + AddCylinder( myGump, x - 7, y + 10, cylinder ); + myGump.AddButton( x - 26, y + 9, 0x13A8, 0x13A9, 1, 0, buttonID ); +} + +function AddCylinder( myGump, x, y, cylinder ) +{ + if( cylinder != PuzzleChestCylinder.None ) + { + myGump.AddPicture( x, y, cylinder ); + } + else + { + myGump.AddPicture( x + 9, y, cylinder ); + } +} + +function AddPedestal( myGump, x, y, cylinder, switchID, initialState ) +{ + myGump.AddPicture( x, y, 0xB10 ); + myGump.AddPicture( x - 23, y + 12, 0xB12 ); + myGump.AddPicture( x + 23, y + 12, 0xB13 ); + myGump.AddPicture( x, y + 23, 0xB11 ); + + if( cylinder != PuzzleChestCylinder.None ) + { + myGump.AddPicture( x, y + 2, 0x51A ); + AddCylinder( myGump, x - 1, y + 19, cylinder ); + } else { + myGump.AddPicture( x, y + 2, 0x521 ); + } + + // Use AddRadio to allow selection of one cylinder at a time + myGump.AddRadio( x + 7, y + 65, 0x868, initialState ? 1 : 0, switchID ); +} + +function ShowStatusGump( pUser, correctCylinders, correctColors ) +{ + var myGump = new Gump; + + myGump.AddBackground( 50, 50, 300, 200, 0x13BE ); // Add background + myGump.AddHTMLGump( 60, 60, 250, 25, false, false, "
Incorrect Guess!
" ); // Title text + + // Display number of correct guesses + myGump.AddHTMLGump( 60, 90, 250, 25, false, false, "Correct Cylinders: " + correctCylinders ); + myGump.AddHTMLGump( 60, 120, 250, 25, false, false, "Correct Colors ( wrong position ): " + correctColors ); + + // Add OK button + myGump.AddButton( 150, 170, 0xFA5, 0xFA7, 1, 0, 100 ); // OK button + + // Send the gump to the player + myGump.Send( pUser ); + myGump.Free( ); +} + +function RewardPlayer( pUser, pItem ) +{ + pUser.SysMessage( "You find some treasure inside the chest!" ); + CreateDFNItem( pUser.socket, pUser, "0x0eed", 500, "ITEM", true ); // Drop 500 gold +} + +function GenerateHints( pUser, correctCylinders, correctColors ) +{ + var lockpickingSkill = pUser.CheckSkill( 24, 0, 1000 ); + var hint1 = ""; + var hint2 = ""; + + if( RandomNumber( 0, 1000 ) < lockpickingSkill ) + { + if( correctCylinders > 0 ) + { + hint1 = "One of the cylinders is in the first slot."; + } + if( correctColors > 0 ) + { + hint2 = "Some colors are used, but thou art not certain where."; + } + } + + return { hint1: hint1, hint2: hint2 }; +} + +function DamagePlayer( pUser ) +{ + var randomEffect = RandomNumber( 0, 3 ); + switch ( randomEffect ) + { + case 0: + pUser.SysMessage( "A toxic vapor envelops thee." ); + pUser.Damage( RandomNumber( 10, 40 )); + break; + case 1: + pUser.SysMessage( "Searing heat scorches thy skin." ); + pUser.Damage( RandomNumber( 10, 40 )); + break; + case 2: + pUser.SysMessage( "Pain lances through thee from a sharp metal blade." ); + pUser.Damage( RandomNumber( 10, 40 )); + break; + default: + pUser.SysMessage( "Lightning arcs through thy body." ); + pUser.Damage( RandomNumber( 10, 40 )); + break; + } +} + +function SerializeSolution( solution ) +{ + return solution.cylinders.join( "," ); +} + +function DeserializeSolution( data ) +{ + var cylinderStrings = data.split( "," ); + var cylinders = []; + + for ( var i = 0; i < cylinderStrings.length; i++ ) { + cylinders.push( parseInt( cylinderStrings[i], 10 )); + } + + return new PuzzleChestSolution( cylinders ); +} diff --git a/data/js/item/teleportrune.js b/data/js/item/teleportrune.js index 26ebc39e6..a6b814a6c 100644 --- a/data/js/item/teleportrune.js +++ b/data/js/item/teleportrune.js @@ -37,9 +37,10 @@ function onCallback1( socket, ourObj ) targX = socket.GetWord( 11 ); targY = socket.GetWord( 13 ); targZ = socket.GetSByte( 16 ); + var StrangeByte = socket.GetWord(1); // If connected with a client lower than v7.0.9, manually add height of targeted tile - if( socket.clientMajorVer <= 7 && socket.clientSubVer < 9 ) + if ((StrangeByte == 0 && ourObj.isItem) || (socket.clientMajorVer <= 7 && socket.clientSubVer < 9)) { targZ += GetTileHeight( socket.GetWord( 17 )); } diff --git a/data/js/jse_fileassociations.scp b/data/js/jse_fileassociations.scp index ceeac4c36..84b69d1f9 100644 --- a/data/js/jse_fileassociations.scp +++ b/data/js/jse_fileassociations.scp @@ -99,6 +99,8 @@ 2202=server/misc/warning_trigger.js 2203=server/misc/charges_left_tooltip.js 2204=server/network/0xDF_buffBar.js +2205=server/misc/spawnergump.js +2206=server/network/0xbf_special_move.js // Server Data [2500-2749] 2500=server/data/weapontypes.js @@ -284,6 +286,7 @@ 5058=item/bagofsending.js 5059=item/powderoftranslocation.js 5060=item/elixirofingots.js +5061=item/puzzlechest.js 19100=item/plant_growing/plantsystem.js 19101=item/plant_growing/plantbowl.js @@ -334,12 +337,16 @@ // Combat Scripts [7000-7499] //------------------------------------------- 7000=combat/peacemake_effect.js +7001=combat/special_moves.js +7002=combat/blockequip.js +7003=combat/leechstats.js //------------------------------------------- // Misc Player Scripts [8000-8499] //------------------------------------------- 8000=player/death/return_stolen_items.js 8001=player/young_player.js +8002=player/death/resurrectpenalty.js // House Scripts [15000-15500] 15000=server/house/house.js diff --git a/data/js/jse_objectassociations.scp b/data/js/jse_objectassociations.scp index 93f7c41d5..25cce9751 100644 --- a/data/js/jse_objectassociations.scp +++ b/data/js/jse_objectassociations.scp @@ -580,6 +580,8 @@ 0x10a4=15007 // Swords +0x0EC2=5009 //cleaver +0x0EC3=5009 //cleaver 0x0EC4=5009 //skinning knife 0x0EC5=5009 //skinning knife 0x0F60=5009 //longsword diff --git a/data/js/magic/level1targ.js b/data/js/magic/level1targ.js index a79f92a3c..d8dabced1 100644 --- a/data/js/magic/level1targ.js +++ b/data/js/magic/level1targ.js @@ -95,6 +95,7 @@ function ItemInHandCheck( mChar, mSock, spellType ) } } } + return true; } function onSpellCast( mSock, mChar, directCast, spellNum ) diff --git a/data/js/npc/ai/monster/ethereal_warrior.js b/data/js/npc/ai/monster/ethereal_warrior.js index fca76d2aa..e0c03e32c 100644 --- a/data/js/npc/ai/monster/ethereal_warrior.js +++ b/data/js/npc/ai/monster/ethereal_warrior.js @@ -114,7 +114,7 @@ function SearchForWounded( srcChar, trgChar, pSock ) } // Handle draining of health, stamina and mana on attack -function onAttack( pAttacker, pDefender ) +function onAttack( pAttacker, pDefender, hitStatus, hitLoc, damageDealt ) { if( !ValidateObject( pDefender )) return; diff --git a/data/js/npc/ai/monster/orc_chopper.js b/data/js/npc/ai/monster/orc_chopper.js index eb28a9ab4..003e5fb87 100644 --- a/data/js/npc/ai/monster/orc_chopper.js +++ b/data/js/npc/ai/monster/orc_chopper.js @@ -1,6 +1,6 @@ // Hits all nearby characters when they attack with their axe -function onAttack( pAttacker, pDefender ) +function onAttack( pAttacker, pDefender, hitStatus, hitLoc, damageDealt ) { pAttacker.SetTempTag( "pDefenderSerial", ( pDefender.serial ).toString() ); AreaCharacterFunction( "HitNearbyTargets", pAttacker, 1 ); diff --git a/data/js/npc/ai/vendor_bdo_dispenser.js b/data/js/npc/ai/vendor_bdo_dispenser.js index 0b5739539..9d069ea22 100644 --- a/data/js/npc/ai/vendor_bdo_dispenser.js +++ b/data/js/npc/ai/vendor_bdo_dispenser.js @@ -302,7 +302,7 @@ function onSpeech( myString, pUser, myNPC ) { if( CheckBodTimers( pUser, myNPC.GetTag( "bodType" ) )) { - if( EraStringToNum( GetServerSetting( "CoreShardEra" )) <= EraStringToNum( "lbr" )) + if( EraStringToNum( GetServerSetting( "CoreShardEra" )) >= EraStringToNum( "lbr" )) { myNPC.SetTimer( Timer.MOVETIME, 1000 ); // Pause NPC in their tracks for a second myNPC.TurnToward( pUser ); diff --git a/data/js/npc/special/bola_ability.js b/data/js/npc/special/bola_ability.js index 2736e2314..39c0691e2 100644 --- a/data/js/npc/special/bola_ability.js +++ b/data/js/npc/special/bola_ability.js @@ -1,5 +1,5 @@ // Allows NPC to swing a bola and dismount a mounted player/character -function onAttack( pAttacker, pDefender ) +function onAttack( pAttacker, pDefender, hitStatus, hitLoc, damageDealt ) { // Don't swing bola if attacker is invalid or dead if( !ValidateObject( pAttacker ) || pAttacker.dead ) diff --git a/data/js/npc/special/colossal_blow.js b/data/js/npc/special/colossal_blow.js index 35a50d327..2ab24df59 100644 --- a/data/js/npc/special/colossal_blow.js +++ b/data/js/npc/special/colossal_blow.js @@ -1,5 +1,5 @@ // Handle Colossal Blow special ability - a stunning attack that applies a peacemaking effect -function onAttack( pAttacker, pDefender ) +function onAttack( pAttacker, pDefender, hitStatus, hitLoc, damageDealt ) { // Don't perform scolossal blow if attacker is invalid or dead if( !ValidateObject( pAttacker ) || pAttacker.dead ) diff --git a/data/js/npc/speech/speech_monster.js b/data/js/npc/speech/speech_monster.js index 016cc59a2..78c72c080 100644 --- a/data/js/npc/speech/speech_monster.js +++ b/data/js/npc/speech/speech_monster.js @@ -152,7 +152,7 @@ function searchForPlayers( srcChar, trgChar, pSock ) } // Triggers when NPC attacks -function onAttack( pAttacker, pDefender ) +function onAttack( pAttacker, pDefender, hitStatus, hitLoc, damageDealt ) { // Random chance to speak when killing someone if( ValidateObject( pDefender ) && pDefender.dead ) diff --git a/data/js/player/death/resurrectpenalty.js b/data/js/player/death/resurrectpenalty.js new file mode 100644 index 000000000..33301b094 --- /dev/null +++ b/data/js/player/death/resurrectpenalty.js @@ -0,0 +1,134 @@ +function ResurrectFamePenalty( pUser ) +{ + if( pUser.fame > 0 ) + { + // Calculate 10% of the fame + var amount = Math.floor( pUser.fame / 10 ); + pUser.fame -= amount; + } +} + +// Penalty to karma is disabled by default, but can be enabled +// via a TriggerEvent call in js/item/shrines.js (onGumpPress) +function ResurrectKarmaPenalty( pUser ) +{ + if( pUser.karma > 0 ) + { + // Calculate 10% of the karma + var amount = Math.floor( pUser.karma / 10 ); + pUser.karma -= amount; + } +} + +function ResurrectMurderPenalty( pUser ) +{ + // Ensure the pUser has committed at least 5 short-term murders + if( pUser.murdercount >= 5 ) + { + // Calculate the loss percentage + var loss = ( 100.0 - ( 4.0 + ( pUser.murdercount / 5.0 ))) / 100.0; + + // Clamp the loss percentage between 85% and 95% + if( loss < 0.85 ) + { + loss = 0.85; // Minimum 15% reduction + } + else if( loss > 0.95 ) + { + loss = 0.95; // Maximum 5% reduction + } + + // Apply penalties to strength, intelligence, and dexterity + if( pUser.strength * loss > 10 ) + { + pUser.strength = RandomNumber( 10, pUser.strength * loss ); + } + if( pUser.intelligence * loss > 10 ) + { + pUser.intelligence = RandomNumber( 10, pUser.intelligence * loss ); + } + if( pUser.dexterity * loss > 10 ) + { + pUser.dexterity = RandomNumber( 10, pUser.dexterity * loss ); + } + + // ResurrectSkillPenalty( pUser ); + } +} + +// Penalty to skills is disabled by default, but can be enabled +// by uncommenting call in ResurrectMurderPenalty (for murderers) or +// for all players via a TriggerEvent call in js/item/shrines.js (onGumpPress) +function ResurrectSkillPenalty( pUser ) +{ + // Define the reduction range (89% to 91%) + var reductionMin = 89; + var reductionMax = 91; + + var originalSkills = []; // Array to store original skill values + + // Apply a 10% reduction to all 64 skills + for( var skillID = 0; skillID < 64; skillID++ ) + { + var baseSkill = pUser.Skills[ skillID ]; // Get skill value + var reducedSkill = RandomNumber( + (baseSkill * reductionMin) / 100, + (baseSkill * reductionMax) / 100 + ); + originalSkills.push( baseSkill ); // Store original skill value + pUser.Skills[ skillID ] = reducedSkill; // Apply the reduced skill value + } + + pUser.SetTag( "originalSkills", originalSkills.join( "," )); + + // Start the recovery timer + pUser.StartTimer( 15000, 0, false ); // 15 seconds interval, calls back to the current script + pUser.SetTag( "recoveryCount", 0 ); // Track recovery intervals +} + +// Skill Recovery handler triggered by StartTimer +function onTimer( timerObj, timerID ) +{ + if( timerID == 0 ) + { + var recoveryCount = timerObj.GetTag( "recoveryCount" ); + var maxRecoveryCount = 100; // 100 intervals = 25 minutes + + // Parse the original skills from the tag + var originalSkills = timerObj.GetTag( "originalSkills" ).split( "," ); + + // Iterate through all skills and gradually restore + for( var skillID = 0; skillID < 64; skillID++ ) + { + var reducedSkill = timerObj.Skills[skillID]; + var originalSkill = parseInt( originalSkills[skillID] ); + + if( reducedSkill < originalSkill ) + { + // Randomize recovery by adding between 0.1% and 0.11% of the original value + var recoveryStep = RandomNumber( + (originalSkill * 0.1) / 100, + (originalSkill * 0.11) / 100 + ); + timerObj.Skills[ skillID ] = Math.min( originalSkill, reducedSkill + recoveryStep ); + } + } + + recoveryCount++; + timerObj.SetTag( "recoveryCount", recoveryCount ); + + // If recovery is not complete, restart the timer + if( recoveryCount < maxRecoveryCount ) + { + timerObj.StartTimer( 15000, 0, false ); // 15 seconds interval + } + else + { + // Recovery complete + timerObj.SetTag( "recoveryCount", null ); + timerObj.SetTag( "originalSkills", null ); + } + } +} + +function _restorecontext_() {} diff --git a/data/js/server/data/weapontypes.js b/data/js/server/data/weapontypes.js index 42fe15a2b..0a6940e56 100644 --- a/data/js/server/data/weapontypes.js +++ b/data/js/server/data/weapontypes.js @@ -208,6 +208,10 @@ function GetWeaponType( mChar, itemID ) case 0x48B3: //gargish axe - SA weaponType = "TWOHND_AXES"; break; // Default Maces + case 0x0DF2: // Wand + case 0x0DF3: // Wand + case 0x0DF4: // Wand + case 0x0DF5: // Wand case 0x0FB4: //sledge hammer case 0x0FB5: //sledge hammer case 0x0F5C: //mace diff --git a/data/js/server/global.js b/data/js/server/global.js index c68a778fc..aebb80ae4 100644 --- a/data/js/server/global.js +++ b/data/js/server/global.js @@ -2,6 +2,8 @@ // Supported Events trigger for every character/item, use with care function onLogin( socket, pChar ) { + const coreShardEra = EraStringToNum( GetServerSetting( "CoreShardEra" )); + // Display Admin Welcome Gump for characters on admin account, until a choice has been made if( pChar.accountNum == 0 ) { @@ -37,6 +39,11 @@ function onLogin( socket, pChar ) TriggerEvent( 8001, "CheckYoungStatus", socket, pChar, true ); } + if( coreShardEra >= EraStringToNum( "aos" ) && ( !pChar.npc && !pChar.HasScriptTrigger( 7001 )))// Attach the special moves Book + { + pChar.AddScriptTrigger( 7001 ); + } + // Re-adds Buff for disguise kit if player still has time left. var currentTime = GetCurrentClock(); var disguiseKitTime = pChar.GetJSTimer( 1, 5023 ); @@ -70,6 +77,8 @@ function onLogout( pSock, pChar ) function onCreatePlayer( pChar ) { + const coreShardEra = EraStringToNum( GetServerSetting( "CoreShardEra" )); + // If player character is created on a Young account, give them Young-specific items if( pChar.account.isYoung ) { @@ -81,6 +90,12 @@ function onCreatePlayer( pChar ) TriggerEvent( 8001, "GiveYoungPlayerItems", pChar.socket, pChar ); } + + //Attach the special moves Book + if( coreShardEra >= EraStringToNum( "aos" ) && ( !pChar.npc && !pChar.HasScriptTrigger( 7001 ))) + { + pChar.AddScriptTrigger( 7001 ); + } } // Generic global-script function to look up data in /shared/jsWorldData/ folder diff --git a/data/js/server/house/houseCommands.js b/data/js/server/house/houseCommands.js index e27bef044..2c7afd3f3 100644 --- a/data/js/server/house/houseCommands.js +++ b/data/js/server/house/houseCommands.js @@ -1522,8 +1522,17 @@ function DemolishHouse( pSocket, iMulti ) iMulti.RemoveTrashCont( itemInHouse ); itemInHouse.Delete(); } - else if( itemInHouse.movable == 2 ) // items placed as part of the house itself like forge/anvil in smithy + else if( itemInHouse.movable == 2 || itemInHouse.GetTag( "deed" )) // items placed as part of the house itself like forge/anvil in smithy or the addon deed { + var addonDeed = itemInHouse.GetTag( "deed" ); + if( addonDeed ) + { + var newDeed = CreateDFNItem( pSocket, pSocket.currentChar, addonDeed, 1, "ITEM", true ); + if( newDeed ) + { + pSocket.SysMessage( GetDictionaryEntry( 1970, pSocket.language )); // A deed for the house add-on has been placed in your backpack. + } + } itemInHouse.Delete(); } else if( itemInHouse.isLockedDown ) diff --git a/data/js/server/misc/spawnergump.js b/data/js/server/misc/spawnergump.js new file mode 100644 index 000000000..449f219a7 --- /dev/null +++ b/data/js/server/misc/spawnergump.js @@ -0,0 +1,248 @@ +function onUseChecked( pUser, iUsed ) +{ + var socket = pUser.socket; + var gumpID = 5037 + 0xffff; + + if( socket && iUsed && iUsed.isItem && pUser.isGM ) + { + socket.tempObj = iUsed; + socket.CloseGump( gumpID, 0 ); + spawnerGump( socket, pUser, iUsed ); + } + + return false; +} + +function spawnerGump( socket, pUser, iUsed ) +{ + var spawner = new Gump; + var powerState = ""; + var spawnName = ""; + if( iUsed.sectionalist == true ) + { + powerState = "Enabled"; + if( iUsed.type == 61 ) + { + spawnName = "Item List" + } + else + spawnName = "Npc List" + } + else + { + powerState = "Disabled"; + if( iUsed.type == 61 ) + { + spawnName = "Item" + } + else + spawnName = "Npc" + } + + var typeName = ""; + switch( iUsed.type ) + { + case 61: typeName = "Item"; break + case 62: typeName = "Npc"; break + case 125: typeName = "Escort"; break + } + + var amountLabel = ( iUsed.type != 61 ) ? "Amount" : "Spawn Item DFN"; + var applyLabel = "Apply"; + var minLabel = "Min:"; + var maxLabel = "Max:"; + + spawner.AddPage( 0 ); + + spawner.AddBackground( 40, 80, 413, 134, 5054 ); + spawner.AddCheckerTrans( 40, 80, 413, 134 ); + spawner.AddPicture( 50, 100, 7956 ); + + if( iUsed.type != 61 ) + { + spawner.AddHTMLGump( 310, 100, 178, 22, false, false, amountLabel ); + spawner.AddHTMLGump( 90, 100, 203, 22, false, false, "Spawn " + spawnName + " DFN" ); + + spawner.AddHTMLGump( 255, 155, 140, 22, false, false, "Rename" ); + + spawner.AddButton( 50, 180, 4005, 4007, 1, 0, 1 ); + spawner.AddHTMLGump( 90, 180, 140, 22, false, false, applyLabel ); + + spawner.AddHTMLGump( 80, 152, 140, 22, false, false, minLabel ); + spawner.AddHTMLGump( 160, 152, 140, 22, false, false, maxLabel ); + + spawner.AddCheckbox( 130, 180, 2152, 0, 1 ); + spawner.AddHTMLGump( 160, 185, 140, 22, false, false, "Spawnlist: " + powerState + "" ); + spawner.AddCheckbox( 300, 180, 2152, 0, 2 ); + spawner.AddHTMLGump( 330, 185, 140, 22, false, false, "Spawn Type: " + typeName + "" ); + spawner.AddBackground( 80, 120, 201, 28, 5120 ); + spawner.AddBackground( 305, 120, 134, 28, 5120 ); + spawner.AddBackground( 105, 150, 50, 25, 5120 ); + spawner.AddBackground( 190, 150, 50, 25, 5120 ); + spawner.AddBackground(305, 152, 134, 28, 5120); + + spawner.AddText( 90, 125, 0, iUsed.spawnsection ); + spawner.AddText( 315, 125, 0, iUsed.amount ); + spawner.AddText( 110, 155, 0, iUsed.mininterval ); + spawner.AddText( 195, 155, 0, iUsed.maxinterval ); + spawner.AddText(310, 152, 0, iUsed.name); + + spawner.AddTextEntry( 90, 125, 178, 20, 1153, 0, 8, iUsed.spawnsection ); + spawner.AddTextEntry( 315, 125, 115, 20, 1153, 0, 9, iUsed.amount ); + spawner.AddTextEntry( 110, 155, 40, 20, 1153, 0, 10, iUsed.mininterval ); + spawner.AddTextEntry( 195, 155, 40, 20, 1153, 0, 11, iUsed.maxinterval ); + spawner.AddTextEntry(310, 152, 140, 25, 1153, 0, 12, iUsed.name); + } + else + { + spawner.AddHTMLGump( 90, 100, 203, 22, false, false, "Spawn " + spawnName + " DFN" ); + spawner.AddHTMLGump( 255, 155, 140, 22, false, false, "Rename" ); + spawner.AddButton( 50, 180, 4005, 4007, 1, 0, 1 ); + spawner.AddHTMLGump( 90, 180, 140, 22, false, false, applyLabel ); + + spawner.AddHTMLGump( 80, 152, 140, 22, false, false, minLabel ); + spawner.AddHTMLGump( 160, 152, 140, 22, false, false, maxLabel ); + + spawner.AddCheckbox( 130, 180, 2152, 0, 1 ); + spawner.AddHTMLGump( 160, 185, 140, 22, false, false, "Spawnlist: " + powerState + "" ); + spawner.AddCheckbox( 300, 180, 2152, 0, 2 ); + spawner.AddHTMLGump( 330, 185, 140, 22, false, false, "Spawn Type: " + typeName + "" ); + + spawner.AddBackground( 80, 120, 201, 28, 5120 ); + spawner.AddBackground( 105, 150, 50, 25, 5120 ); + spawner.AddBackground( 190, 150, 50, 25, 5120 ); + spawner.AddBackground(305, 152, 134, 28, 5120); + + spawner.AddText( 90, 125, 0, iUsed.spawnsection ); + spawner.AddText( 110, 155, 0, iUsed.mininterval ); + spawner.AddText( 195, 155, 0, iUsed.maxinterval ); + spawner.AddText( 310, 152, 0, iUsed.name ); + + spawner.AddTextEntry( 90, 125, 178, 20, 1153, 0, 11, iUsed.spawnsection ); + spawner.AddTextEntry( 110, 155, 40, 20, 1153, 0, 13, iUsed.maxinterval ); + spawner.AddTextEntry( 195, 155, 40, 20, 1153, 0, 12, iUsed.mininterval ); + spawner.AddTextEntry( 310, 152, 140, 25, 1153, 0, 10, iUsed.name ); + + } + spawner.Send( socket ); + spawner.Free(); +} + +function onGumpPress( socket, pButton, gumpData ) +{ + var pUser = socket.currentChar; + var iUsed = socket.tempObj; + + var spawn = gumpData.getEdit( 0 ); + if( iUsed.type != 61 ) + { + var num = gumpData.getEdit( 1 ); + var min = gumpData.getEdit( 2 ); + var max = gumpData.getEdit( 3 ); + var name = gumpData.getEdit( 4 ); + } + else + { + var min = gumpData.getEdit( 1 ); + var max = gumpData.getEdit( 2 ); + var name = gumpData.getEdit( 3 ); + } + var OtherButton = gumpData.getButton( 0 ); + switch( pButton ) + { + case 0: + break; + case 1: + if( iUsed.type != 61 ) + { + iUsed.spawnsection = spawn; + iUsed.amount = num; + iUsed.mininterval = min; + iUsed.maxinterval = max; + } + else + { + iUsed.spawnsection = spawn; + iUsed.mininterval = min; + iUsed.maxinterval = max; + } + + if( name == null || name == " " ) + { + socket.SysMessage(GetDictionaryEntry(9270, socket.language)); // That name is too short, or no name was entered. + } + else if( name.length > 50 ) + { + pSocket.SysMessage(GetDictionaryEntry(9271, pSocket.language)); // That name is too long. Maximum 50 chars. + } + else + { + iUsed.name = name; + } + + switch( OtherButton ) + { + case 1: + if( iUsed.sectionalist == true ) + { + pUser.SysMessage( "You have disabled the spawn list. You can now add single DFN." ); + iUsed.sectionalist = false; + } + else + { + pUser.SysMessage( "You have enabled the spawn list. It will now only accept DFN lists." ); + iUsed.sectionalist = true; + } + break; + case 2: + var typeTransitions = { + 61: { nextType: 62, message: "Changed Type to Npc", resetAmount: false }, + 62: { nextType: 125, message: "Changed Type to Escort", resetAmount: false }, + 125: { nextType: 61, message: "Changed Type to Item", resetAmount: true } + }; + + var currentTransition = typeTransitions[iUsed.type]; + if( currentTransition ) + { + iUsed.type = currentTransition.nextType; + if( currentTransition.resetAmount ) + { + iUsed.amount = 0; + } + pUser.SysMessage( currentTransition.message ); + } + break; + } + spawnerGump( socket, pUser, iUsed ); + break; + } +} + +function onTooltip( spawner ) +{ + var typeName = ""; + switch( spawner.type ) + { + case 61: typeName = "Item"; break + case 62: typeName = "Npc"; break + case 125: typeName = "Escort"; break + } + var powerState = ""; + if( spawner.sectionalist == true ) + { + powerState = "Enabled"; + } + else + { + powerState = "Disabled"; + } + + var tooltipText = ""; + tooltipText = "Spawn DFN: " + spawner.spawnsection; + tooltipText += "\n" + "Spawn Type: " + typeName; + tooltipText += "\n" + "Spawn List: " + powerState; + tooltipText += "\n" + "Amount: " + "" + spawner.amount + ""; + tooltipText += "\n" + "Min Interval: " + "" + spawner.mininterval + "" + " Max Interval: " + "" + spawner.maxinterval + ""; + tooltipText += "\n" + "Region: " + "" + spawner.region.name + ""; + return tooltipText; +} \ No newline at end of file diff --git a/data/js/server/network/0xbf_special_move.js b/data/js/server/network/0xbf_special_move.js new file mode 100644 index 000000000..1fc8dae05 --- /dev/null +++ b/data/js/server/network/0xbf_special_move.js @@ -0,0 +1,34 @@ +function ClearSpecialMove( pUser, abilityID ) +{ + var socket = pUser.socket; + var toSend = new Packet; + + toSend.ReserveSize( 7 ) + toSend.WriteByte( 0, 0xbf ); // Packet + toSend.WriteShort( 1, 0x07 ); // Length + toSend.WriteShort( 3, 0x21 ); // SubCmd + toSend.WriteByte( 5, abilityID ); // Ability ID + toSend.WriteByte( 6, 0 ); // On/off + socket.Send( toSend ); + toSend.Free(); + + pUser.SetTempTag( "abilityID", null ); + pUser.SetTempTag( "doubleMana", null ); +} + +function DeactivateSpecialMove( pUser, abilityID ) +{ + var socket = pUser.socket; + var toSend = new Packet; + + toSend.ReserveSize( 7 ) + toSend.WriteByte( 0, 0xbf ); // Packet + toSend.WriteShort( 1, 0x07 ); // Length + toSend.WriteShort( 3, 0x21 ); // SubCmd + toSend.WriteByte( 5, abilityID ); // Ability ID + toSend.WriteByte( 6, 0); // On/off + socket.Send( toSend ); + toSend.Free(); + + pUser.SetTempTag( "abilityID", null ); +} diff --git a/data/js/server/network/0xf1_freeshardServerPoll.js b/data/js/server/network/0xf1_freeshardServerPoll.js index 4b278c240..33e2f1434 100644 --- a/data/js/server/network/0xf1_freeshardServerPoll.js +++ b/data/js/server/network/0xf1_freeshardServerPoll.js @@ -1,6 +1,6 @@ // Handler for Freeshard Server Poll requests from // CUO Web (https://play.classicuo.org) -// Last Updated: 5. September, 2022 +// Last Updated: 3. Decemeber, 2024 function PacketRegistration() { @@ -27,7 +27,18 @@ function onPacketReceive( pSocket, packetNum, subCommand ) else { Console.Print( "Freeshard Server Poll Packet detected, responding..." ); - SendServerPollInfo( pSocket ); + SendServerPollInfoCompact( pSocket ); + } + break; + case 0xFF: + if( !GetServerSetting( "FREESHARDSERVERPOLL" )) + { + Console.Print( "Freeshard Server Poll Packet detected; response disabled via FREESHARDPOLL ini-setting.\n" ); + } + else + { + Console.Print( "Freeshard Server Poll Packet detected, responding..." ); + SendServerPollInfoExtended( pSocket ); } break; default: @@ -36,7 +47,7 @@ function onPacketReceive( pSocket, packetNum, subCommand ) return; } -function SendServerPollInfo( pSocket ) +function SendServerPollInfoCompact( pSocket ) { var uptime = Math.floor( GetCurrentClock() / 1000 ) - Math.floor( GetStartTime() / 1000 ); var totalAccounts = GetAccountCount(); @@ -55,8 +66,31 @@ function SendServerPollInfo( pSocket ) toSend.WriteLong( 15, uptime ); // Server Uptime toSend.WriteLong( 19, memoryHigh ); // Max memory usage - no need to send toSend.WriteLong( 23, memoryLow ); // Min memory usage - no need to send - pSocket.Send( toSend ); + pSocket.Send(toSend); toSend.Free(); Console.Print( "Done!\n" ); Console.Log( "Response sent to Freeshard Server Poll Packet (totalOnline: " + totalOnline + ", upTimeInSeconds: " + uptime ); } + +function SendServerPollInfoExtended( pSocket ) +{ + var protocolVersion = 2; + var shardName = GetServerSetting( "SERVERNAME" ); + var uptime = Math.floor( GetCurrentClock() / 1000 ) - Math.floor( GetStartTime() / 1000 ); + var totalOnline = GetPlayerCount(); + var totalItems = 0; + var totalChars = 0; + var totalMemory = 0; + var statsStr = "UOX3, Name=" + shardName + ", Age=" + Math.round( uptime / 60 / 60 ) + ", Clients=" + totalOnline + ", Items=" + totalItems + ", Chars=" + totalChars + ", Mem=" + totalMemory + "K, Ver=" + protocolVersion; + var toSend = new Packet; + + toSend.ReserveSize( statsStr.length + 2 ); + toSend.WriteByte( 0, 0x53 ); // PacketID + toSend.WriteShort( 1, statsStr.length ); // Length + toSend.WriteString( 3, statsStr, statsStr.length ); + toSend.WriteByte( statsStr.length + 1, 0x00 ); // null terminated + pSocket.Send( toSend ); + toSend.Free(); + Console.Print( "Done!\n" ); + Console.Log( "Response sent to Freeshard Server Poll Packet (totalOnline: " + totalOnline + ", upTimeInSeconds: " + uptime ); +} \ No newline at end of file diff --git a/data/js/skill/craft/cooking.js b/data/js/skill/craft/cooking.js index 654533e8a..1ce12dd8f 100644 --- a/data/js/skill/craft/cooking.js +++ b/data/js/skill/craft/cooking.js @@ -21,7 +21,7 @@ const myPage = [ [ 11611, 11612, 11613, 11614, 11615, 11616, 11617, 11618 ], // Page 3 - Baking - [ 11619, 11620, 11621, 11622, 11623, 11624, 11625, 11626, 11627, 11628, 11629 ], + [11619, 11620, 11621, 11657, 11622, 11623, 11624, 11625, 11626, 11627, 11628, 11629 ], // Page 4 - Barbecue [ 11630, 11631, 11632, 11633, 11634, 11635 ] diff --git a/data/js/skill/craft/itemdetailgump.js b/data/js/skill/craft/itemdetailgump.js index 0f4e1ad20..7ddbe18ee 100644 --- a/data/js/skill/craft/itemdetailgump.js +++ b/data/js/skill/craft/itemdetailgump.js @@ -1525,12 +1525,12 @@ function ItemDetailGump( pUser ) break; case 1501: // Dough createEntry = CreateEntries[1501]; - HARVEST = [11637, 11639]; + HARVEST = [11637, 11638]; mainSkill = parseInt( pUser.skills.cooking ); break; case 1502: // Sweet Dough createEntry = CreateEntries[1502]; - HARVEST = [11607, 11638]; + HARVEST = [11607, 11639]; mainSkill = parseInt( pUser.skills.cooking ); break; case 1503: // Cake Mix diff --git a/data/js/skill/healing.js b/data/js/skill/healing.js index 78010b144..668ae4646 100644 --- a/data/js/skill/healing.js +++ b/data/js/skill/healing.js @@ -241,6 +241,32 @@ function onCallback1( socket, ourObj ) } else // Heal { + + if( ourObj.GetTempTag( "blockHeal" ) == true ) + { + if( ourObj != mChar && ourObj.socket ) + { + socket.SysMessage( "You cannot heal that target in their current state." ); + } + else + { + socket.SysMessage( GetDictionaryEntry( 9058, socket.language ));// You can not heal yourself in your current state. + } + } + else if( ourObj.GetTempTag( "doBleed" ) == true ) + { + if( ourObj != mChar && ourObj.socket ) + { + socket.SysMessage( "You bind the wound and stop the bleeding" ); + } + else + { + socket.SysMessage( "The bleeding wounds have healed, you are no longer bleeding!" ); + } + ourObj.KillJSTimer( 9300, 7001 ); + ourObj.SetTempTag( "doBleed", null ); + } + // Consume some bandages if( bItem.amount > 1 ) { diff --git a/docs/jsdocs.html b/docs/jsdocs.html index b3647694d..5dcbf3acb 100644 --- a/docs/jsdocs.html +++ b/docs/jsdocs.html @@ -431,7 +431,7 @@

January 9th, 2022

Prototype

-

function onAttack( pAttacker, pDefender )

+

function onAttack( pAttacker, pDefender, hitStatus, hitLoc, damageDealt )

Purpose

@@ -443,14 +443,20 @@

January 9th, 2022

Notes

-

After pAttacker's script has been triggered, pDefender's onDefense event also triggers. Note that these events run in addition to hard-coded combat (and/or other combat events), after everything else is done, and do not replace these.

+

After pAttacker's script has been triggered, pDefender's onDefense event also triggers. Note that these events run in addition to hard-coded combat (and/or other combat events), after everything else is done, and do not replace these. hitStatus will be false if attack missed.

Example of usage
-

function onAttack( pAttacker, pDefender )
+
function onAttack( pAttacker, pDefender, hitStatus, hitLoc, damageDealt )
 {
-	pAttacker.TextMessage( "Who lives in that castle?" );
-	pDefender.TextMessage( "Help! Help! I'm being repressed!" );
+    if( hitStatus )
+    {
+	    pAttacker.TextMessage( "Hah! I hit my target for " + damageDealt + "damage" );
+    }
+    else
+    {
+	    pDefender.TextMessage( "Help! Help! I'm being repressed!" );
+    }
 }

@@ -1549,7 +1555,7 @@

January 9th, 2022

Prototype

-

function onDefense( pAttacker, pDefender )

+

function onDefense( pAttacker, pDefender, hitStatus, hitLoc, damageReceived )

Purpose

@@ -1561,14 +1567,20 @@

January 9th, 2022

Notes

-

The event runs at the end of each hard-coded combat "round"

+

The event runs at the end of each hard-coded combat "round". hitStatus will be false if attack missed.

Example of usage
-

function onDefense( pAttacker, pDefender )
+
function onDefense( pAttacker, pDefender, hitStatus, hitLoc, damageReceived  )
 {
-	pAttacker.TextMessage( "Who lives in that castle?" );
-	pDefender.TextMessage( "Help! Help! I'm being repressed!" );
+    if( hitStatus )
+    {
+	    pAttacker.TextMessage( "Hah! I hit my target for " + damageReceived + "damage" );
+    }
+    else
+    {
+	    pDefender.TextMessage( "Help! Help! I'm being repressed!" );
+    }
 }

@@ -4043,7 +4055,7 @@

January 9th, 2022

Prototype

-

function onSpellTargetSelect( pCaster, myTarget, spellID )

+

function onSpellTargetSelect( myTarget, pCaster, spellID )

Purpose

@@ -4068,7 +4080,7 @@

January 9th, 2022

Example of usage

// Script attached to an NPC that's immune to magic, where event returns 2 to reject spell being cast
-function onSpellTargetSelect( pCaster, myTarget, spellID )
+function onSpellTargetSelect( myTarget, pCaster, spellID )
 {
 	var socket = pCaster.socket;
 	if( socket != null )
@@ -5577,6 +5589,35 @@ 

January 9th, 2022

+
+ + +
+
+

Prototype

+

JSBool CheckInstaLog( x, y, world, instanceID );

+
+
+

Purpose

+

Checks if a specific location ( x, y, world, instanceID ) is within an instant logout zone.

+
+
+

Example of usage

+
// Check if the player is in an instant logout zone
+var isInstaLog = CheckInstaLog(targX, targY, worldNumber, instanceID);
+
+if( isInstaLog )
+{
+	// Handle instant logout
+}
+else
+{
+	// Handle other logout scenarios
+}
+
+
+
+
@@ -10055,6 +10096,25 @@

January 9th, 2022

+ +
+ + +
+
+

Prototype

+

void SetRandomColor( colorListID );

+
+
+

Purpose

+

Applies a random color from a specified colorlist to character/item.

+
+
+

Example of usage

+
myChar/myItem.SetRandomColor( "1" ); // Apply random color from Savage Warriors skin or can get random color from items colorlist depending on how its used.
+
+
+
diff --git a/source/CPacketSend.cpp b/source/CPacketSend.cpp index ba30f52d8..448966e33 100644 --- a/source/CPacketSend.cpp +++ b/source/CPacketSend.cpp @@ -70,7 +70,7 @@ using namespace std::string_literals; //| BYTE[2] unknown5 (0x0) //| BYTE[4] unknown6 (0x0) //| -//| Note: Only send once after login. Its mandatory to send it once. +//| Note: Only send once after login. It’s mandatory to send it once. //o------------------------------------------------------------------------------------------------o void CPCharLocBody::Log( std::ostream &outStream, bool fullHeader ) { @@ -1411,7 +1411,7 @@ CPPaperdoll &CPPaperdoll::operator = ( CChar &toCopy ) //| //| Packet Build //| BYTE cmd -//| BYTE type (0x00 It starts to rain, 0x01 A fierce storm approaches., 0x02 It begins to snow, 0x03 - A storm is brewing., 0xFF None (turns off sound effects), 0xFE (no effect?? Set temperature?) +//| BYTE type (0x00 – “It starts to rain”, 0x01 – “A fierce storm approaches.”, 0x02 – “It begins to snow”, 0x03 - “A storm is brewing.”, 0xFF – None (turns off sound effects), 0xFE (no effect?? Set temperature?) //| BYTE num (number of weather effects on screen) //| BYTE temperature //| @@ -1422,8 +1422,8 @@ CPPaperdoll &CPPaperdoll::operator = ( CChar &toCopy ) //| Note: Weather messages are only displayed when weather starts. //| Note: Weather will end automatically after 6 minutes without any weather change packets. //| Note: You can totally end weather (to display a new message) by teleporting. -//| I think its either the 0x78 or 0x20 messages that reset it, though I -//| havent checked to be sure (other possibilities, 0x4F or 0x4E) +//| I think it’s either the 0x78 or 0x20 messages that reset it, though I +//| haven’t checked to be sure (other possibilities, 0x4F or 0x4E) //o------------------------------------------------------------------------------------------------o void CPWeather::InternalReset( void ) { @@ -2043,7 +2043,7 @@ void CPOpenGump::Serial( SERIAL toSet ) //| BYTE unknown (0x00) //| BYTE click zLoc //| BYTE[2] model # (if a static tile, 0 if a map/landscape tile) -//| Note: the model # shouldnt be trusted. +//| Note: the model # shouldn’t be trusted. //o------------------------------------------------------------------------------------------------o CPTargetCursor::CPTargetCursor() { @@ -2601,7 +2601,7 @@ void CPStatWindow::TithingPoints( UI32 value ) //| 0x07 idle //| 0x05 another character is online //| "Another character from this account is currently online in this world. -//| You must either log in as that character or wait for it to time out. +//| You must either log in as that character or wait for it to time out.” //o------------------------------------------------------------------------------------------------o void CPIdleWarning::InternalReset( void ) { @@ -3107,12 +3107,12 @@ CPMultiPlacementView::CPMultiPlacementView( SERIAL toSet ) //| 0 neither T2A NOR LBR, equal to not sending it at all, //| 1 is T2A, chatbutton, //| 2 is LBR without chatbutton, -//| 3 is LBR with chatbutton +//| 3 is LBR with chatbutton… //| 8013 LBR + chatbutton + AOS enabled //| //| Note1: this message is send immediately after login. -//| Note2: on OSI servers this controls features OSI enables/disables via upgrade codes. -//| Note3: a 3 doesnt seem to hurt older (NON LBR) clients. +//| Note2: on OSI servers this controls features OSI enables/disables via “upgrade codes.” +//| Note3: a 3 doesn’t seem to “hurt” older (NON LBR) clients. //o------------------------------------------------------------------------------------------------o CPEnableClientFeatures::CPEnableClientFeatures( CSocket *mSock ) { @@ -6118,7 +6118,7 @@ void CPObjectInfo::Objects( CItem& mItem, CChar& mChar ) //| BYTE[2] Font //| BYTE[4] Language //| BYTE[30] Name -//| BYTE[?][2] Msg Null Terminated (blockSize - 48) +//| BYTE[?][2] Msg – Null Terminated (blockSize - 48) //| //| The various types of text is as follows: //| 0x00 - Normal @@ -6294,7 +6294,7 @@ void CPUnicodeSpeech::GhostIt( [[maybe_unused]] UI08 method ) //| BYTE[2] Font //| BYTE[4] Language //| BYTE[30] Name -//| BYTE[?][2] Msg Null Terminated (blockSize - 48) +//| BYTE[?][2] Msg – Null Terminated (blockSize - 48) //| //| The various types of text is as follows: //| 0x00 - Normal @@ -6572,7 +6572,7 @@ void CPSecureTrading::Name( const std::string& nameFollowing ) //o------------------------------------------------------------------------------------------------o //| Purpose - Handles outgoing packet with server response to all names request //o------------------------------------------------------------------------------------------------o -//| Notes - Packet: 0x98 (All-names 3D) +//| Notes - Packet: 0x98 (All-names “3D”) //| Size: Variable //| //| Packet Build @@ -6588,7 +6588,7 @@ void CPSecureTrading::Name( const std::string& nameFollowing ) //| Client asks for name of object with ID x. //| Server has to reply with ID + name //| Client automatically knows names of items. -//| Hence it only asks only for NPC/Player names nearby, but shows bars of items plus NPCs. +//| Hence it only asks only for NPC/Player names nearby, but shows bars of items plus NPC’s. //| //| Client request has 7 bytes, server-reply 37 //| Triggered by Crtl + Shift. @@ -6641,7 +6641,7 @@ void CPAllNames3D::Object( CBaseObject& obj ) //| BYTE[var] null terminated line //| Note: //| server side: # of pages equals value given in 0x93/0xd4 -//| EACH page # given. If empty: # lines: 0 + terminator (=3 0s) +//| EACH page # given. If empty: # lines: 0 + terminator (=3 0’s) //| client side: # of pages always 1. if 2 pages changed, client generates 2 packets. //o------------------------------------------------------------------------------------------------o void CPBookPage::IncLength( UI08 amount ) @@ -7009,7 +7009,7 @@ bool CPNewSpellBook::ClientCanReceive( CSocket *mSock ) //| BYTE[4] Serial //| BYTE Damage // how much damage was done ? //| -//| Note: displays damage above the npc/players head. +//| Note: displays damage above the npc/player’s head. //o------------------------------------------------------------------------------------------------o void CPDisplayDamage::InternalReset( void ) { @@ -7473,6 +7473,28 @@ void CPToolTip::CopyItemData( CItem& cItem, size_t &totalStringLen, bool addAmou tempEntry.ourText = oldstrutil::number( cItem.GetTempVar( CITV_MOREZ )); FinalizeData( tempEntry, totalStringLen ); } + + if( cItem.GetManaLeech() > 0 ) + { + tempEntry.stringNum = 1060427; // hit mana leech ~1_val~% + tempEntry.ourText = oldstrutil::number( cItem.GetManaLeech() ); + FinalizeData( tempEntry, totalStringLen ); + } + + if( cItem.GetStaminaLeech() > 0 ) + { + tempEntry.stringNum = 1060430; // hit stamina leech ~1_val~% + tempEntry.ourText = oldstrutil::number( cItem.GetStaminaLeech() ); + FinalizeData( tempEntry, totalStringLen ); + } + + if( cItem.GetHealthLeech() > 0 ) + { + tempEntry.stringNum = 1060422; // hit life leech ~1_val~% + tempEntry.ourText = oldstrutil::number( cItem.GetHealthLeech() ); + FinalizeData( tempEntry, totalStringLen ); + } + if( cItem.GetType() == IT_SPELLCHANNELING ) { tempEntry.stringNum = 1060482; // spell channeling @@ -7552,7 +7574,15 @@ void CPToolTip::CopyItemData( CItem& cItem, size_t &totalStringLen, bool addAmou if( cItem.GetSpeed() > 0 ) { tempEntry.stringNum = 1061167; // weapon speed ~1_val~ - tempEntry.ourText = oldstrutil::number( cItem.GetSpeed() ); + if( cwmWorldState->ServerData()->ExpansionCoreShardEra() >= ER_ML ) + { + R64 wpnSpeedInSeconds = std::round(( 40000.0 / ( 200 * cItem.GetSpeed() ) * 0.5 ) * 10 ) / 10; + tempEntry.ourText = oldstrutil::format( "%.1fs", wpnSpeedInSeconds ); + } + else + { + tempEntry.ourText = oldstrutil::number( cItem.GetSpeed() ); + } FinalizeData( tempEntry, totalStringLen ); } @@ -7665,10 +7695,77 @@ void CPToolTip::CopyItemData( CItem& cItem, size_t &totalStringLen, bool addAmou FinalizeData( tempEntry, totalStringLen ); } - if( cItem.GetStrength() > 1 ) + if( cItem.GetSwingSpeedIncrease() > 0 ) + { + tempEntry.stringNum = 1060486; // swing speed increase ~1_val~% + tempEntry.ourText = oldstrutil::number( cItem.GetSwingSpeedIncrease() ); + FinalizeData( tempEntry, totalStringLen ); + } + + if( cItem.GetHitChance() > 0 ) + { + tempEntry.stringNum = 1060415; // hit chance increase ~1_val~% + tempEntry.ourText = oldstrutil::number( cItem.GetHitChance() ); + FinalizeData( tempEntry, totalStringLen ); + } + + if( cItem.GetDefenseChance() > 0 ) + { + tempEntry.stringNum = 1060408; // defense chance increase ~1_val~% + tempEntry.ourText = oldstrutil::number( cItem.GetDefenseChance() ); + FinalizeData( tempEntry, totalStringLen ); + } + + if( cItem.GetHealthBonus() > 0 ) + { + tempEntry.stringNum = 1060431; // hit point increase ~1_val~ + tempEntry.ourText = oldstrutil::number( cItem.GetHealthBonus() ); + FinalizeData( tempEntry, totalStringLen ); + } + + if( cItem.GetStaminaBonus() > 0 ) + { + tempEntry.stringNum = 1060484; // stamina increase ~1_val~ + tempEntry.ourText = oldstrutil::number( cItem.GetStaminaBonus() ); + FinalizeData( tempEntry, totalStringLen ); + } + + if( cItem.GetManaBonus() > 0 ) + { + tempEntry.stringNum = 1060439; // mana increase ~1_val~ + tempEntry.ourText = oldstrutil::number( cItem.GetManaBonus() ); + FinalizeData( tempEntry, totalStringLen ); + } + + const SI16 strReq = ( cItem.GetStrength() * ( 100 - cItem.GetLowerStatReq() )) / 100; + const SI16 dexReq = ( cItem.GetDexterity() * ( 100 - cItem.GetLowerStatReq() )) / 100; + const SI16 intReq = ( cItem.GetIntelligence() * ( 100 - cItem.GetLowerStatReq() )) / 100; + + if( strReq > 0 ) { tempEntry.stringNum = 1061170; // strength requirement ~1_val~ - tempEntry.ourText = oldstrutil::number( cItem.GetStrength() ); + tempEntry.ourText = oldstrutil::number( strReq ); + FinalizeData( tempEntry, totalStringLen ); + } + + if( dexReq > 0 ) + { + tempEntry.stringNum = 1042971; // ~1_NOTHING~ + tempEntry.ourText = oldstrutil::format( "dexterity requirement %s", oldstrutil::number( dexReq ).c_str() ); + FinalizeData( tempEntry, totalStringLen ); + } + + if( intReq > 0 ) + { + tempEntry.stringNum = 1042971; // ~1_NOTHING~ + tempEntry.ourText = oldstrutil::format( "intelligence requirement %s", oldstrutil::number( intReq ).c_str() ); + FinalizeData( tempEntry, totalStringLen ); + } + + if( cItem.GetLowerStatReq() > 0 ) + { + tempEntry.stringNum = 1060435; // lower requirements ~1_val~% + tempEntry.ourText = oldstrutil::number( cItem.GetLowerStatReq() ); FinalizeData( tempEntry, totalStringLen ); } } @@ -8036,9 +8133,9 @@ bool CPSellList::CanSellItems( CChar &mChar, CChar &vendor ) //| BYTE[2] len //| BYTE subcmd //| BYTE[ len - 4 ] submessage -//| Submessage 0 Display Bulletin Board +//| Submessage 0 – Display Bulletin Board //| BYTE[4] Board serial -//| BYTE[22] board name (default is bulletin board, the rest nulls) +//| BYTE[22] board name (default is “bulletin board”, the rest nulls) //| BYTE[4] unknown/ID? //| BYTE[4] zero (0) //o------------------------------------------------------------------------------------------------o @@ -8118,7 +8215,7 @@ CPOpenMessageBoard::CPOpenMessageBoard( CSocket *mSock ) //| BYTE subjectLen //| BYTE[subjectLen] subject (null terminated string) //| BYTE timeLen -//| BYTE[timeLen] time (null terminated string with time of posting) (Day 1 @ 11:28) +//| BYTE[timeLen] time (null terminated string with time of posting) (“Day 1 @ 11:28”) //o------------------------------------------------------------------------------------------------o //| Subcommand: 0x2 (Message Summary) //| Size: Variable @@ -8135,7 +8232,7 @@ CPOpenMessageBoard::CPOpenMessageBoard( CSocket *mSock ) //| BYTE subjectLen //| BYTE[subjectLen] subject (null terminated string) //| BYTE timeLen -//| BYTE[timeLen] time (null terminated string with time of posting) (Day 1 @ 11:28) +//| BYTE[timeLen] time (null terminated string with time of posting) (“Day 1 @ 11:28”) //| BYTE[5] Unknown (01 90 03 F7 00) //| BYTE numlines //| For each line: diff --git a/source/Changelog.txt b/source/Changelog.txt index b0801d426..bb086c7e4 100644 --- a/source/Changelog.txt +++ b/source/Changelog.txt @@ -1,16 +1,130 @@ +21/01/2025 - Dragon Slayer + Fixed damage dealt in combat was incorrectly modified while applying defense modifiers. (combat.cpp) + +15/12/2024 - Dragon Slayer + Added Ressurrect Penalty Script (js/player/death/resurrectpenalty.js) that controls any type of penalty you want on the char after resurrecting via shrines + +07/12/2024 - Dragon Slayer + Updated the packet 0xf1 to reflect the current CUO Web Ping while maintaining backward compatibility with older ping statuses. (0xf1_freeshardServerPoll.js) (Thanks Karasho and Xuri) + +31/10/2024 - Dragon Slayer + Fixed Z calculation in some scripts when targeting dynamic items. (Thanks Xuri) + +27/10/2024 -Dragon Slayer + Corrected a misspelling of IsBoat in magic.js. + Added support for iterating through items in boats using FirstItem(), NextItem() and FinishedItems() methods + +20/10/2024 - Dragon Slayer + Added SetRandomColor("#") to js functions. (Thanks, Xuri) + +14/10/2024 - Dragon Slayer +    Added the CheckInstaLog JS function to allow checking if a specific location is within an instant logout zone (SEFunctions.cpp). (thanks, Xuri) + +12/10/2024 - Dragon Slayer + Added Mini-House Addons from AOS Expansion. + +11/10/2024 - Dragon Slayer + Added ML House Addons. + +10/09/2024 - Dragon Slayer + Added base functionality for Khaldun Puzzle Chests, which can be unlocked by solving a puzzle, with bonus hints for the solution given based on player's lockpicking skill + +13/08/2024 - Dragon Slayer/Xuri + The onAttack/onDefense JS Events have been updated with three new parameters (hitStatus, hitLocation, damage) and will now also trigger when attacks miss. + +12/08/2024 - Dragon Slayer + Fixed an issue where Imbuing and Mysticism skills were listed in wrong order in skills.dfn and enums.h + +05/08/2024 - Dragon Slayer Update + Resolved an issue with cooking functionality. + Fixed a duplicated dictionary number. + Corrected the required items for crafting sweet dough and regular dough. + +04/08/2024 - Dragon Slayer + Added Run a skillcheck for NPC to give them a chance to gain skill - if that option is enabled in ini (xuri) + +16/07/2024 - Dragon Slayer + Added fallback in 'add menu for older clients that don't support buttontileart (Thanks Xuri)(gumps.cpp) + +07/07/2024 - Dragon Slayer + Added Requirement to drink potion hand has to be free, This can be disabled within the potion.js file by switching the reqfreehand to false. (js potion). + +04/07/2024 - Dragon Slayer + Fixed Cleaver ID missing in the jse_objectassociations.scp for carving corpses + +18/06/2024 - Dragon Slayer + Added three new DFN tags for Items: + HEALTHLEECH=# // It gives an attacker the ability to leech health from his opponent every time he successfully delivers a hit adds it to himself. + STAMINALEECH=# // It gives an attacker the ability to leech Stamina from his opponent every time he successfully delivers a hit adds it to himself. + MANALEECH=# // It gives an attacker the ability to leech Mana from his opponent every time he successfully delivers a hit adds it to himself. + These are also available as JS Engine object properties: .healthLeech, .staminaLeech and .manaLeech + Added leechstats.js file that controls the combat for the properties. (script 7003) + To add this script to a weapon only. add in SCRIPT=7003, HEALTHLEECH=# or STAMINALEECH=# or MANALEECH=# it can also be all three on the weapon. + +16/06/2024 - Dragon Slayer/Xuri + Added new DFN tags for Items and Chars: + SPEEDINCREASE=# // item and char property that increases base weapon swing speed by the specified percentage + These are also available as JS Engine object properties: .speedIncrease + Added INI Settings: + SWINGSPEEDINCREASECAP=# // Max cap for for swing speed increase a char can have. + Combat code updated with era-specific weapon swing speed calculations for different eras (LBR or earlier/AoS/ML onwards). + Note that speeds are still defined with flat values in DFNs regardless of era, but for ML and beyond speed + will be displayed as swing delay in seconds in item tooltip. + +14/06/2024 - Dragon Slayer + Added two new DFN tags for Items: + HITCHANCE=# // Increases the player's chance to hit a target with wrestling, melee and ranged weapons. + DEFENSECHANCE=# // Increases the wearer's chance that his opponents' swings (or arrows/bolts) will miss. + These are also available as JS Engine object properties: .hitChance, .defenseChance + +13/06/2024 - Dragon Slayer + Added three More AOS Props + -HEALTHBONUS=# + -MANABONUS=# + -STAMINABONUS=# + Add this properties to any weapon/armor/jewlery will give the player more hp/mana/stam why its equiped. depending on number you add with it + These are also available as JS Engine object properties: .healthBonus, .staminaBonus, .manaBonus + +06/06/2024 - Dragon Slayer + Fixed Accepting bods, When the expansion is to to lbr or later. + +29/05/2024 - Dragon Slayer + House add-on deeds are now returned when an add-on is present in the house on demolish. + +27/05/2024 - Dragon Slayer + Added Missing Wand ID's to combat weapon type in core and in js. + +25/05/2024 - Dragon Slayer + Added special_moves.js There is 12 special aos moves you can find on uoguide.com. + Added blockequip.js This script is used to block reqeuiping weapons. + Thanks to Xuri for making unequipattemp work for chars and not just items. + Added OnCombatHit + -Triggers for character with event attached when someone has taken damage. + 13/05/2024 - Dragon Slayer Added New Shield Type 107 so shield ID's no longer have to be in hard code for shields to work properly +11/05/2024 - Dragon Slayer + Updated 'get command (js/commands/targeting/get.js) to use correct object reference when getting resist values for items, and added support for getting resist values for chars + 09/05/2024 - Dragon Slayer Added ArtifactRarity AOS Property for items -ARTIFACTRARITY=# -Artifact Rarity is an item property that is visible on some artifacts and meant to give players an idea of how rare the item is. Items with rarity 1 are supposed to be common while rarity 12 are extremely scarce. -1/05/2024 - Dragon Slayer/Xuri +05/05/2024 - Dragon Slayer + Added Spawner Gump and attached to the base_spawner, just another option for making editing spawners without using commands. (js spawnergump) + -Just double click any spawner you create from the addmenu or add from spawners.dfn file, gump will appear if you create a spawner with commands you would have to attach the script directly to it. + +01/05/2024 - Dragon Slayer/Xuri Fixed AutoUnequipAttempt function in clumsy.js, createfood.js level1target.js, will no longer fail on casting and return to hardcode. Fixed createfood to check for reagents on cast. Fixed many places missing proper null checks and refresh checks in magic js scripts. +30/04/2024 - Dragon Slayer/Xuri/Maarc + Added Support for new AOS property tag. + -LOWERSTATREQ - Lowers the strength requirements to wear an object. + 27/04/2024 - Dragon Slayer/Xuri Fixed an issue where non-corpse containers - including treasure chests in dungeons - would decay and leave all their contents on the ground. Converted LOOTDECAYSWITHCORPSE ini setting to two new settings, one for player corpses, one for NPC corpses: diff --git a/source/SEFunctions.cpp b/source/SEFunctions.cpp index 1700d8e55..24d815aaa 100644 --- a/source/SEFunctions.cpp +++ b/source/SEFunctions.cpp @@ -287,6 +287,46 @@ JSBool SE_CalcCharFromSer( JSContext *cx, [[maybe_unused]] JSObject *obj, uintN return JS_TRUE; } +//o------------------------------------------------------------------------------------------------o +//| Function - SE_CheckInstaLog() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Checks if a specific location is within an instant logout zone +//o------------------------------------------------------------------------------------------------o +JSBool SE_CheckInstaLog( JSContext *cx, [[maybe_unused]] JSObject *obj, uintN argc, jsval *argv, jsval *rval ) +{ + if( argc != 4 ) + { + ScriptError( cx, "CheckInstaLog: Invalid number of parameters (4)" ); + return JS_FALSE; + } + + SI16 targX = static_cast( JSVAL_TO_INT( argv[0] )); + SI16 targY = static_cast( JSVAL_TO_INT( argv[1] )); + UI08 targWorld = static_cast( JSVAL_TO_INT( argv[2] )); + UI16 targInstanceId = static_cast( JSVAL_TO_INT( argv[3] )); + + auto logLocs = cwmWorldState->logoutLocs; + + *rval = JSVAL_FALSE; + + if( logLocs.size() > 0 ) + { + for( size_t i = 0; i < logLocs.size(); ++i ) + { + if( logLocs[i].worldNum == targWorld && logLocs[i].instanceId == targInstanceId ) + { + if(( targX >= logLocs[i].x1 && targX <= logLocs[i].x2 ) && ( targY >= logLocs[i].y1 && targY <= logLocs[i].y2 )) + { + *rval = JSVAL_TRUE; + return JS_TRUE; + } + } + } + } + + return JS_TRUE; +} + //o------------------------------------------------------------------------------------------------o //| Function - SE_DoMovingEffect() //o------------------------------------------------------------------------------------------------o @@ -5086,6 +5126,9 @@ JSBool SE_GetServerSetting( JSContext *cx, [[maybe_unused]] JSObject *obj, uintN case 349: // LOOTDECAYSWITHPLAYERCORPSE *rval = BOOLEAN_TO_JSVAL( cwmWorldState->ServerData()->NpcCorpseLootDecay() ); break; + case 353: // SWINGSPEEDINCREASECAP + *rval = INT_TO_JSVAL( static_cast( cwmWorldState->ServerData()->SwingSpeedIncreaseCap() )); + break; default: ScriptError( cx, "GetServerSetting: Invalid server setting name provided" ); return false; diff --git a/source/SEFunctions.h b/source/SEFunctions.h index 904a1fabd..adde69ee0 100644 --- a/source/SEFunctions.h +++ b/source/SEFunctions.h @@ -47,6 +47,8 @@ SEngineFunc SE_CalcCharFromSer; // *** SEngineFunc SE_CalcItemFromSer; // *** SEngineFunc SE_CalcMultiFromSer; // *** +SEngineFunc SE_CheckInstaLog; + SEngineFunc SE_MakeItem; // *** SEngineFunc SE_CommandLevelReq; // * diff --git a/source/UOXJSMethods.cpp b/source/UOXJSMethods.cpp index e139beb79..5ae378ae1 100644 --- a/source/UOXJSMethods.cpp +++ b/source/UOXJSMethods.cpp @@ -7155,7 +7155,7 @@ JSBool CBase_FirstItem( JSContext *cx, JSObject *obj, uintN argc, [[maybe_unused { firstItem = ( static_cast( myObj ))->GetContainsList()->First(); } - else if( myObj->GetObjType() == OT_MULTI ) + else if( myObj->GetObjType() == OT_MULTI || myObj->GetObjType() == OT_BOAT ) { firstItem = ( static_cast( myObj ))->GetItemsInMultiList()->First(); } @@ -7206,7 +7206,7 @@ JSBool CBase_NextItem( JSContext *cx, JSObject *obj, uintN argc, [[maybe_unused] { nextItem = ( static_cast( myObj ))->GetContainsList()->Next(); } - else if( myObj->GetObjType() == OT_MULTI ) + else if( myObj->GetObjType() == OT_MULTI || myObj->GetObjType() == OT_BOAT ) { nextItem = ( static_cast( myObj ))->GetItemsInMultiList()->Next(); } @@ -7256,7 +7256,7 @@ JSBool CBase_FinishedItems( JSContext *cx, JSObject *obj, uintN argc, [[maybe_un { *rval = BOOLEAN_TO_JSVAL(( static_cast( myObj ))->GetContainsList()->Finished() ); } - else if( myObj->GetObjType() == OT_MULTI ) + else if( myObj->GetObjType() == OT_MULTI || myObj->GetObjType() == OT_BOAT ) { *rval = BOOLEAN_TO_JSVAL(( static_cast( myObj ))->GetItemsInMultiList()->Finished() ); } @@ -7955,7 +7955,7 @@ JSBool CBase_SetRandomName( JSContext *cx, JSObject *obj, uintN argc, jsval *arg return JS_FALSE; } - CBaseObject *mObj = static_cast( JS_GetPrivate( cx, obj )); + CBaseObject *mObj = static_cast( JS_GetPrivate( cx, obj )); std::string namelist = JS_GetStringBytes( JS_ValueToString( cx, argv[0] )); if( !namelist.empty() ) @@ -7969,6 +7969,35 @@ JSBool CBase_SetRandomName( JSContext *cx, JSObject *obj, uintN argc, jsval *arg return JS_TRUE; } +UI16 AddRandomColor( const std::string& colorlist ); +//o------------------------------------------------------------------------------------------------o +//| Function - CBase_SetRandomColor() +//| Prototype - bool SetRandomColor( "colorlist" ) +//o------------------------------------------------------------------------------------------------o +//| Purpose - Applies a random color from specified colorlist to character or item +//o------------------------------------------------------------------------------------------------o +JSBool CBase_SetRandomColor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ) +{ + if( argc != 1 ) + { + ScriptError( cx, "SetRandomColor: Invalid number of arguments (takes 1, colorlist string)" ); + return JS_FALSE; + } + + CBaseObject *mObj = static_cast( JS_GetPrivate( cx, obj )); + std::string colorlist = JS_GetStringBytes( JS_ValueToString( cx, argv[0] )); + + if( !colorlist.empty() ) + { + mObj->SetColour( AddRandomColor( colorlist )); + *rval = JSVAL_TRUE; + return JS_TRUE; + } + + *rval = JSVAL_FALSE; + return JS_TRUE; +} + //o------------------------------------------------------------------------------------------------o //| Function - CChar_SetSkillByName() //| Prototype - bool SetSkillByName( "skillName", value ) diff --git a/source/UOXJSMethods.h b/source/UOXJSMethods.h index c7a879fc8..447dd5c12 100644 --- a/source/UOXJSMethods.h +++ b/source/UOXJSMethods.h @@ -193,6 +193,7 @@ JSMethodFunc CBase_HasScriptTrigger; JSMethodFunc CBase_RemoveScriptTrigger; JSMethodFunc CBase_Refresh; JSMethodFunc CBase_SetRandomName; +JSMethodFunc CBase_SetRandomColor; // Multi Methods JSMethodFunc CMulti_GetMultiCorner; @@ -431,6 +432,7 @@ inline JSFunctionSpec CChar_Methods[] = { "Recall", CChar_Recall, 1, 0, 0 }, { "Mark", CChar_Mark, 1, 0, 0 }, { "SetRandomName", CBase_SetRandomName, 1, 0, 0 }, + { "SetRandomColor", CBase_SetRandomColor, 1, 0, 0 }, { "SetSkillByName", CChar_SetSkillByName, 2, 0, 0 }, { "Kill", CChar_Kill, 0, 0, 0 }, { "Resurrect", CChar_Resurrect, 0, 0, 0 }, @@ -566,7 +568,8 @@ inline JSFunctionSpec CItem_Methods[] = { "FinishedChars", CMulti_FinishedChars, 1, 0, 0 }, //{ "SetMoreSerial", CBase_SetMoreSerial, 1, 0, 0 }, - { "SetRandomName", CBase_SetRandomName, 1, 0, 0 }, + { "SetRandomName", CBase_SetRandomName, 1, 0, 0 }, + { "SetRandomColor", CBase_SetRandomColor, 1, 0, 0 }, { nullptr, nullptr, 0, 0, 0 } }; diff --git a/source/UOXJSPropertyEnums.h b/source/UOXJSPropertyEnums.h index 45517f28d..874440fb4 100644 --- a/source/UOXJSPropertyEnums.h +++ b/source/UOXJSPropertyEnums.h @@ -339,6 +339,9 @@ enum CC_Properties CCP_SPAWNSERIAL, CCP_SPATTACK, CCP_SPDELAY, + CCP_SWINGSPEEDINCREASE, + CCP_HITCHANCE, + CCP_DEFENSECHANCE, CCP_AITYPE, CCP_SPLIT, CCP_SPLITCHANCE, @@ -445,6 +448,7 @@ enum CI_Properties CIP_DECAYTIME, CIP_LODAMAGE, CIP_HIDAMAGE, + CIP_LOWERSTATREQ, CIP_AC, CIP_DEF, CIP_RESISTCOLD, @@ -461,6 +465,9 @@ enum CI_Properties CIP_DAMAGEPOISON, CIP_DAMAGERAIN, CIP_DAMAGESNOW, + CIP_HITCHANCE, + CIP_DEFENSECHANCE, + CIP_ARTIFACTRARITY, CIP_NAME2, CIP_ISITEM, @@ -496,7 +503,9 @@ enum CI_Properties CIP_SECTIONALIST, CIP_MININTERVAL, CIP_MAXINTERVAL, - + CIP_HEALTHLEECH, + CIP_STAMINALEECH, + CIP_MANALEECH, CIP_ISNEWBIE, CIP_ISDISPELLABLE, CIP_MADEWITH, @@ -517,6 +526,10 @@ enum CI_Properties CIP_ISCONTTYPE, CIP_CARVESECTION, CIP_SPEED, + CIP_SWINGSPEEDINCREASE, + CIP_HEALTHBONUS, + CIP_STAMINABONUS, + CIP_MANABONUS, CIP_MULTI, CIP_AMMOID, CIP_AMMOHUE, @@ -534,7 +547,6 @@ enum CI_Properties CIP_ISITEMHELD, CIP_SECTIONID, CIP_STEALABLE, - CIP_LOCKDDOWNS, CIP_MAXLOCKDOWNS, CIP_TRASHCONTAINERS, diff --git a/source/UOXJSPropertyFuncs.cpp b/source/UOXJSPropertyFuncs.cpp index 5fc2a3a82..9c1dc93f1 100644 --- a/source/UOXJSPropertyFuncs.cpp +++ b/source/UOXJSPropertyFuncs.cpp @@ -675,8 +675,19 @@ JSBool CItemProps_getProperty( JSContext *cx, JSObject *obj, jsval id, jsval *vp case CIP_DAMAGEPOISON: *vp = BOOLEAN_TO_JSVAL( gPriv->GetWeatherDamage( POISON )); break; case CIP_DAMAGERAIN: *vp = BOOLEAN_TO_JSVAL( gPriv->GetWeatherDamage( RAIN )); break; case CIP_DAMAGESNOW: *vp = BOOLEAN_TO_JSVAL( gPriv->GetWeatherDamage( SNOW )); break; + case CIP_SWINGSPEEDINCREASE: *vp = INT_TO_JSVAL( gPriv->GetSwingSpeedIncrease() ); break; case CIP_SPEED: *vp = INT_TO_JSVAL( gPriv->GetSpeed() ); break; + case CIP_LOWERSTATREQ: *vp = INT_TO_JSVAL( gPriv->GetLowerStatReq() ); break; + case CIP_HEALTHLEECH: *vp = INT_TO_JSVAL( gPriv->GetHealthLeech() ); break; + case CIP_STAMINALEECH: *vp = INT_TO_JSVAL( gPriv->GetStaminaLeech() ); break; + case CIP_MANALEECH: *vp = INT_TO_JSVAL( gPriv->GetManaLeech() ); break; + case CIP_HITCHANCE: *vp = INT_TO_JSVAL( gPriv->GetHitChance() ); break; + case CIP_DEFENSECHANCE: *vp = INT_TO_JSVAL( gPriv->GetDefenseChance() ); break; + case CIP_HEALTHBONUS: *vp = INT_TO_JSVAL( gPriv->GetHealthBonus() ); break; + case CIP_STAMINABONUS: *vp = INT_TO_JSVAL( gPriv->GetStaminaBonus() ); break; + case CIP_MANABONUS: *vp = INT_TO_JSVAL( gPriv->GetManaBonus() ); break; case CIP_ARTIFACTRARITY: *vp = INT_TO_JSVAL( gPriv->GetArtifactRarity() ); break; + case CIP_NAME2: tString = JS_NewStringCopyZ( cx, gPriv->GetName2().c_str() ); *vp = STRING_TO_JSVAL( tString ); @@ -1322,7 +1333,18 @@ JSBool CItemProps_setProperty( JSContext *cx, JSObject *obj, jsval id, jsval *vp case CIP_DAMAGERAIN: gPriv->SetWeatherDamage( RAIN, encaps.toBool() ); break; case CIP_DAMAGESNOW: gPriv->SetWeatherDamage( SNOW, encaps.toBool() ); break; case CIP_SPEED: gPriv->SetSpeed( static_cast( encaps.toInt() )); break; + case CIP_LOWERSTATREQ: gPriv->SetLowerStatReq( static_cast( encaps.toInt() )); break; + case CIP_SWINGSPEEDINCREASE: gPriv->SetSwingSpeedIncrease( static_cast( encaps.toInt() )); break; + case CIP_HEALTHLEECH: gPriv->SetHealthLeech( static_cast( encaps.toInt() )); break; + case CIP_STAMINALEECH: gPriv->SetStaminaLeech( static_cast( encaps.toInt() )); break; + case CIP_MANALEECH: gPriv->SetManaLeech( static_cast( encaps.toInt() )); break; + case CIP_HITCHANCE: gPriv->SetHitChance( static_cast( encaps.toInt() )); break; + case CIP_DEFENSECHANCE: gPriv->SetDefenseChance( static_cast( encaps.toInt() )); break; + case CIP_HEALTHBONUS: gPriv->SetHealthBonus( static_cast( encaps.toInt() )); break; + case CIP_STAMINABONUS: gPriv->SetStaminaBonus( static_cast( encaps.toInt() )); break; + case CIP_MANABONUS: gPriv->SetManaBonus( static_cast( encaps.toInt() )); break; case CIP_ARTIFACTRARITY: gPriv->SetArtifactRarity( static_cast( encaps.toInt() )); break; + case CIP_NAME2: gPriv->SetName2( encaps.toString() ); break; case CIP_RACE: gPriv->SetRace( static_cast( encaps.toInt() )); break; case CIP_MAXHP: gPriv->SetMaxHP( static_cast( encaps.toInt() )); break; @@ -1996,6 +2018,9 @@ JSBool CCharacterProps_getProperty( JSContext *cx, JSObject *obj, jsval id, jsva case CCP_HOUSEICONS: *vp = BOOLEAN_TO_JSVAL( gPriv->ViewHouseAsIcon() ); break; case CCP_SPATTACK: *vp = INT_TO_JSVAL( gPriv->GetSpAttack() ); break; case CCP_SPDELAY: *vp = INT_TO_JSVAL( gPriv->GetSpDelay() ); break; + case CCP_SWINGSPEEDINCREASE: *vp = INT_TO_JSVAL( gPriv->GetSwingSpeedIncrease() ); break; + case CCP_HITCHANCE: *vp = INT_TO_JSVAL( gPriv->GetHitChance() ); break; + case CCP_DEFENSECHANCE: *vp = INT_TO_JSVAL( gPriv->GetDefenseChance() ); break; case CCP_AITYPE: *vp = INT_TO_JSVAL( gPriv->GetNpcAiType() ); break; case CCP_SPLIT: *vp = INT_TO_JSVAL( gPriv->GetSplit() ); break; case CCP_SPLITCHANCE: *vp = INT_TO_JSVAL( gPriv->GetSplitChance() ); break; @@ -2501,6 +2526,9 @@ JSBool CCharacterProps_setProperty( JSContext *cx, JSObject *obj, jsval id, jsva case CCP_HOUSEICONS: gPriv->SetViewHouseAsIcon( encaps.toBool() ); break; case CCP_SPATTACK: gPriv->SetSpAttack( static_cast( encaps.toInt() )); break; case CCP_SPDELAY: gPriv->SetSpDelay( static_cast( encaps.toInt() )); break; + case CCP_SWINGSPEEDINCREASE: gPriv->SetSwingSpeedIncrease( static_cast( encaps.toInt() )); break; + case CCP_HITCHANCE: gPriv->SetHitChance( static_cast( encaps.toInt() )); break; + case CCP_DEFENSECHANCE: gPriv->SetDefenseChance( static_cast( encaps.toInt() )); break; case CCP_AITYPE: gPriv->SetNPCAiType( static_cast( encaps.toInt() )); break; case CCP_SPLIT: gPriv->SetSplit( static_cast( encaps.toInt() )); break; case CCP_SPLITCHANCE: gPriv->SetSplitChance( static_cast( encaps.toInt() ));break; diff --git a/source/UOXJSPropertySpecs.h b/source/UOXJSPropertySpecs.h index 8607ffab5..620b4c558 100644 --- a/source/UOXJSPropertySpecs.h +++ b/source/UOXJSPropertySpecs.h @@ -357,6 +357,9 @@ inline JSPropertySpec CCharacterProps[] = { "houseicons", CCP_HOUSEICONS, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "spattack", CCP_SPATTACK, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "spdelay", CCP_SPDELAY, JSPROP_ENUMANDPERM, nullptr, nullptr }, + { "swingSpeedIncrease", CCP_SWINGSPEEDINCREASE, JSPROP_ENUMANDPERM, nullptr, nullptr }, + { "hitChance", CCP_HITCHANCE, JSPROP_ENUMANDPERM, nullptr, nullptr }, + { "defenseChance", CCP_DEFENSECHANCE, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "aitype", CCP_AITYPE, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "split", CCP_SPLIT, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "splitchance", CCP_SPLITCHANCE, JSPROP_ENUMANDPERM, nullptr, nullptr }, @@ -477,6 +480,7 @@ inline JSPropertySpec CItemProps[] = { "damagePoison", CIP_DAMAGEPOISON, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "damageRain", CIP_DAMAGERAIN, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "damageSnow", CIP_DAMAGESNOW, JSPROP_ENUMANDPERM, nullptr, nullptr }, + { "lowerStateReq", CIP_LOWERSTATREQ, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "name2", CIP_NAME2, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "isChar", CIP_ISCHAR, JSPROP_ENUMPERMRO, nullptr, nullptr }, { "isItem", CIP_ISITEM, JSPROP_ENUMPERMRO, nullptr, nullptr }, @@ -535,7 +539,20 @@ inline JSPropertySpec CItemProps[] = { "ammoFXHue", CIP_AMMOFXHUE, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "ammoFXRender", CIP_AMMOFXRENDER, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "speed", CIP_SPEED, JSPROP_ENUMANDPERM, nullptr, nullptr }, + { "swingSpeedIncrease", CIP_SWINGSPEEDINCREASE , JSPROP_ENUMANDPERM, nullptr, nullptr }, + + { "healthLeech", CIP_HEALTHLEECH, JSPROP_ENUMANDPERM, nullptr, nullptr }, + { "staminaLeech", CIP_STAMINALEECH, JSPROP_ENUMANDPERM, nullptr, nullptr }, + { "manaLeech", CIP_MANALEECH, JSPROP_ENUMANDPERM, nullptr, nullptr }, + + { "hitChance", CIP_HITCHANCE, JSPROP_ENUMANDPERM, nullptr, nullptr }, + { "defenseChance", CIP_DEFENSECHANCE, JSPROP_ENUMANDPERM, nullptr, nullptr }, + + { "healthBonus", CIP_HEALTHBONUS, JSPROP_ENUMANDPERM, nullptr, nullptr }, + { "staminaBonus", CIP_STAMINABONUS, JSPROP_ENUMANDPERM, nullptr, nullptr }, + { "manaBonus", CIP_MANABONUS, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "artifactRarity", CIP_ARTIFACTRARITY, JSPROP_ENUMANDPERM, nullptr, nullptr }, + { "multi", CIP_MULTI, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "maxRange", CIP_MAXRANGE, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "baseRange", CIP_BASERANGE, JSPROP_ENUMANDPERM, nullptr, nullptr }, @@ -676,8 +693,8 @@ inline JSPropertySpec CSkillsProps[] = { "bushido", BUSHIDO, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "ninjitsu", NINJITSU, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "spellweaving", SPELLWEAVING, JSPROP_ENUMANDPERM, nullptr, nullptr }, - { "imbuing", IMBUING, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "mysticism", MYSTICISM, JSPROP_ENUMANDPERM, nullptr, nullptr }, + { "imbuing", IMBUING, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "throwing", THROWING, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "allskills", ALLSKILLS, JSPROP_ENUMANDPERM, nullptr, nullptr }, { nullptr, static_cast(0), static_cast(0), nullptr, nullptr } diff --git a/source/boats.cpp b/source/boats.cpp index 8829b2249..0f5df3743 100644 --- a/source/boats.cpp +++ b/source/boats.cpp @@ -7,6 +7,9 @@ #include "cEffects.h" #include "Dictionary.h" #include "StringUtility.hpp" +#include "CJSMapping.h" +#include "cScript.h" +#include "CJSEngine.h" #define XP 0 @@ -898,6 +901,20 @@ void TurnBoat( CBoatObj *b, bool rightTurn, bool disableChecks ) { tSock->Send( &prSend ); } + + auto scriptTriggers = b->GetScriptTriggers(); + for( auto scriptTrig : scriptTriggers ) + { + auto toExecute = JSMapping->GetScript( scriptTrig ); + if( toExecute ) + { + if( toExecute->OnBoatTurn( b, olddir, b->GetDir() ) == 1 ) + { + // A script with the event returned true; prevent other scripts from running + break; + } + } + } } void TurnBoat( CSocket *mSock, CBoatObj *myBoat, CItem *tiller, UI08 dir, bool rightTurn ) diff --git a/source/cBaseObject.cpp b/source/cBaseObject.cpp index 506c247ac..027ba2bc6 100644 --- a/source/cBaseObject.cpp +++ b/source/cBaseObject.cpp @@ -94,6 +94,17 @@ const SI16 DEFBASE_KILLS = 0; const UI16 DEFBASE_RESIST = 0; const bool DEFBASE_NAMEREQUESTACTIVE = 0; const ExpansionRuleset DEFBASE_ORIGIN = ER_UO; +const SI16 DEFBASE_SWINGSPEEDINCREASE = 0; +const SI16 DEFBASE_HEALTHLEECH = 0; +const SI16 DEFBASE_STAMINALEECH = 0; +const SI16 DEFBASE_MANALEECH = 0; + +const SI16 DEFBASE_HITCHANCE = 0; +const SI16 DEFBASE_DEFENSECHANCE = 0; + +const SI16 DEFBASE_HEALTHBONUS = 0; +const SI16 DEFBASE_STAMINABONOS = 0; +const SI16 DEFBASE_MANABONUS = 0; //o------------------------------------------------------------------------------------------------o //| Function - CBaseObject constructor @@ -110,7 +121,9 @@ loDamage( DEFBASE_LODAMAGE ), weight( DEFBASE_WEIGHT ), mana( DEFBASE_MANA ), stamina( DEFBASE_STAMINA ), scriptTrig( DEFBASE_SCPTRIG ), st2( DEFBASE_STR2 ), dx2( DEFBASE_DEX2 ), in2( DEFBASE_INT2 ), FilePosition( DEFBASE_FP ), poisoned( DEFBASE_POISONED ), carve( DEFBASE_CARVE ), oldLocX( 0 ), oldLocY( 0 ), oldLocZ( 0 ), oldTargLocX( 0 ), oldTargLocY( 0 ), -fame( DEFBASE_FAME ), karma( DEFBASE_KARMA ), kills( DEFBASE_KILLS ), subRegion( DEFBASE_SUBREGION ), nameRequestActive( DEFBASE_NAMEREQUESTACTIVE ), origin( DEFBASE_ORIGIN ) +fame( DEFBASE_FAME ), karma( DEFBASE_KARMA ), kills( DEFBASE_KILLS ), subRegion( DEFBASE_SUBREGION ), nameRequestActive( DEFBASE_NAMEREQUESTACTIVE ), origin( DEFBASE_ORIGIN ), +healthBonus( DEFBASE_HEALTHBONUS ),staminaBonus( DEFBASE_STAMINABONOS ), manaBonus( DEFBASE_MANABONUS ), hitChance( DEFBASE_HITCHANCE ), defenseChance( DEFBASE_DEFENSECHANCE ), +healthLeech( DEFBASE_HEALTHLEECH ), staminaLeech( DEFBASE_STAMINALEECH ), manaLeech( DEFBASE_MANALEECH ), swingSpeedIncrease( DEFBASE_SWINGSPEEDINCREASE ) { multis = nullptr; tempMulti = INVALIDSERIAL; @@ -793,6 +806,7 @@ bool CBaseObject::DumpBody( std::ostream &outStream ) const outStream << "Intelligence=" + std::to_string( intelligence ) + "," + std::to_string( temp_in2 ) + newLine; outStream << "Strength=" + std::to_string( strength ) + "," + std::to_string( temp_st2 ) + newLine; outStream << "HitPoints=" + std::to_string( hitpoints ) + newLine; + outStream << "SwingSpeedInc=" + std::to_string( GetSwingSpeedIncrease() ) + newLine; outStream << "Race=" + std::to_string( race ) + newLine; outStream << "Visible=" + std::to_string( visible ) + newLine; outStream << "Disabled=" << ( IsDisabled() ? "1" : "0" ) << newLine; @@ -1036,6 +1050,46 @@ void CBaseObject::IncHP( SI16 amtToChange ) SetHP( hitpoints + amtToChange ); } +//o------------------------------------------------------------------------------------------------o +//| Function - CBaseObject::GetHitChance() +//| CBaseObject::SetHitChance() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets the Defense Chance of the Item(s) Equiped or Character +//o------------------------------------------------------------------------------------------------o +SI16 CBaseObject::GetHitChance( void ) const +{ + return hitChance; +} +void CBaseObject::SetHitChance( SI16 newValue ) +{ + hitChance = newValue; + + if( CanBeObjType( OT_ITEM )) + { + ( static_cast( this ))->UpdateRegion(); + } +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CBaseObject::GetDefenseChance() +//| CBaseObject::SetDefenseChance() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets the Defense Chance of the Item(s) Equiped or Character +//o------------------------------------------------------------------------------------------------o +SI16 CBaseObject::GetDefenseChance( void ) const +{ + return defenseChance; +} +void CBaseObject::SetDefenseChance( SI16 newValue ) +{ + defenseChance = newValue; + + if( CanBeObjType( OT_ITEM )) + { + ( static_cast( this ))->UpdateRegion(); + } +} + //o------------------------------------------------------------------------------------------------o //| Function - CBaseObject::GetDir() //| CBaseObject::SetDir() @@ -1568,6 +1622,27 @@ Point3_st CBaseObject::GetLocation( void ) const return Point3_st( x, y, z ); } +//o------------------------------------------------------------------------------------------------o +//| Function - CBaseObject::GetSwingSpeedIncrease() +//| CBaseObject::SetSwingSpeedBonus() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets the item's Swing Speed Bonus property (in percentage), which +//| adjusts the base swing speed of the equipped weapon, or characters +//o------------------------------------------------------------------------------------------------o +SI16 CBaseObject::GetSwingSpeedIncrease( void ) const +{ + return swingSpeedIncrease; +} +void CBaseObject::SetSwingSpeedIncrease( SI16 newValue ) +{ + swingSpeedIncrease = newValue; + + if( CanBeObjType( OT_ITEM )) + { + ( static_cast( this ))->UpdateRegion(); + } +} + //o------------------------------------------------------------------------------------------------o //| Function - CBaseObject::GetStrength2() //| CBaseObject::SetStrength2() @@ -1631,6 +1706,126 @@ void CBaseObject::SetIntelligence2( SI16 nVal ) } } +//o------------------------------------------------------------------------------------------------o +//| Function - CBaseObject::GetHealthLeech() +//| CBaseObject::SetHealthLeech() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets the Health Leech +//o------------------------------------------------------------------------------------------------o +SI16 CBaseObject::GetHealthLeech( void ) const +{ + return healthLeech; +} +void CBaseObject::SetHealthLeech( SI16 nVal ) +{ + healthLeech = nVal; + + if( CanBeObjType( OT_ITEM )) + { + ( static_cast( this ))->UpdateRegion(); + } +} + +//| Function - CBaseObject::GetHealthBonus() +//| CBaseObject::SetHealthBonus() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets the health max var associated with the object. For chars, it's the +//| bonuses (via armour and such) +//o------------------------------------------------------------------------------------------------o +SI16 CBaseObject::GetHealthBonus( void ) const +{ + return healthBonus; +} +void CBaseObject::SetHealthBonus( SI16 nVal ) +{ + healthBonus = nVal; + + if( CanBeObjType( OT_ITEM )) + { + ( static_cast( this ))->UpdateRegion(); + } +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CBaseObject::GetStaminaLeech() +//| CBaseObject::SetStaminaLeech() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets the Stamina Leech +//o------------------------------------------------------------------------------------------------o +SI16 CBaseObject::GetStaminaLeech( void ) const +{ + return staminaLeech; +} +void CBaseObject::SetStaminaLeech( SI16 nVal ) +{ + staminaLeech = nVal; + + if( CanBeObjType( OT_ITEM )) + { + ( static_cast( this ))->UpdateRegion(); + } +} + +//| Function - CBaseObject::GetStaminaBonus() +//| CBaseObject::SetStaminaBonus() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets the stamina max var associated with the object. For chars, it's the +//| bonuses (via armour and such) +//o------------------------------------------------------------------------------------------------o +SI16 CBaseObject::GetStaminaBonus( void ) const +{ + return staminaBonus; +} +void CBaseObject::SetStaminaBonus( SI16 nVal ) +{ + staminaBonus = nVal; + + if( CanBeObjType( OT_ITEM )) + { + ( static_cast( this ))->UpdateRegion(); + } +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CBaseObject::GetManaLeech() +//| CBaseObject::SetManaLeech() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets the Mana Leech +//o------------------------------------------------------------------------------------------------o +SI16 CBaseObject::GetManaLeech( void ) const +{ + return manaLeech; +} +void CBaseObject::SetManaLeech( SI16 nVal ) +{ + manaLeech = nVal; + + if( CanBeObjType( OT_ITEM )) + { + ( static_cast( this ))->UpdateRegion(); + } +} + +//| Function - CBaseObject::GetManaBonus() +//| CBaseObject::SetManaBonus() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets the Mana max var associated with the object. For chars, it's the +//| bonuses (via armour and such) +//o------------------------------------------------------------------------------------------------o +SI16 CBaseObject::GetManaBonus( void ) const +{ + return manaBonus; +} +void CBaseObject::SetManaBonus( SI16 nVal ) +{ + manaBonus = nVal; + + if( CanBeObjType( OT_ITEM )) + { + ( static_cast( this ))->UpdateRegion(); + } +} + //o------------------------------------------------------------------------------------------------o //| Function - CBaseObject::IncStrength() //o------------------------------------------------------------------------------------------------o @@ -1661,6 +1856,65 @@ void CBaseObject::IncIntelligence( SI16 toInc ) SetIntelligence( intelligence + toInc ); } +//o------------------------------------------------------------------------------------------------o +//| Function - CBaseObject::IncSwingSpeedIncrease() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Increments the object's swing speed bonus value +//o------------------------------------------------------------------------------------------------o +void CBaseObject::IncSwingSpeedIncrease( SI16 toInc ) +{ + SetSwingSpeedIncrease( swingSpeedIncrease + toInc ); +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CBaseObject::IncHealthLeech() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Increments the object's Health Leech Points value +//o------------------------------------------------------------------------------------------------o +void CBaseObject::IncHealthLeech( SI16 toInc ) +{ + SetHealthLeech( healthLeech + toInc ); +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CBaseObject::IncStaminaLeech() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Increments the object's Stamina Leech Points value +//o------------------------------------------------------------------------------------------------o +void CBaseObject::IncStaminaLeech( SI16 toInc ) +{ + SetStaminaLeech( staminaLeech + toInc ); +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CBaseObject::IncManaLeech() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Increments the object's Mana Leech Points value +//o------------------------------------------------------------------------------------------------o +void CBaseObject::IncManaLeech( SI16 toInc ) +{ + SetManaLeech( manaLeech + toInc ); +} + +//| Function - CBaseObject::IncHitChance() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Increments the object's Hit Chance value +//o------------------------------------------------------------------------------------------------o +void CBaseObject::IncHitChance( SI16 toInc ) +{ + SetHitChance( hitChance + toInc ); +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CBaseObject::IncDefenseChance() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Increments the object's Hit Chance value +//o------------------------------------------------------------------------------------------------o +void CBaseObject::IncDefenseChance( SI16 toInc ) +{ + SetDefenseChance( defenseChance + toInc ); +} + //o------------------------------------------------------------------------------------------------o //| Function - CBaseObject::DumpFooter() //o------------------------------------------------------------------------------------------------o @@ -2022,6 +2276,11 @@ bool CBaseObject::HandleLine( std::string &UTag, std::string &data ) { st2 = oldstrutil::value( data ); } + else if( UTag == "SWINGSPEEDINC" ) + { + SetSwingSpeedIncrease( static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 ))); + rValue = true; + } else if( UTag == "SCPTRIG" ) { //scriptTrig = oldstrutil::value(data); @@ -2544,7 +2803,7 @@ void CBaseObject::CopyData( CBaseObject *target ) target->SetIntelligence2( GetIntelligence2() ); target->SetPoisoned( GetPoisoned() ); target->SetWeight( GetWeight() ); - + target->SetSwingSpeedIncrease( GetSwingSpeedIncrease() ); target->SetKarma( karma ); target->SetFame( fame ); target->SetKills( kills ); diff --git a/source/cBaseObject.h b/source/cBaseObject.h index 638e826f7..527f6c3b7 100644 --- a/source/cBaseObject.h +++ b/source/cBaseObject.h @@ -69,16 +69,25 @@ class CBaseObject SI16 dexterity; SI16 intelligence; SI16 hitpoints; + SI16 hitChance; + SI16 defenseChance; VisibleTypes visible; SI16 hiDamage; SI16 loDamage; SI32 weight; SI16 mana; SI16 stamina; + SI16 swingSpeedIncrease; + SI16 healthLeech; + SI16 staminaLeech; + SI16 manaLeech; UI16 scriptTrig; SI16 st2; SI16 dx2; SI16 in2; + SI16 healthBonus; + SI16 staminaBonus; + SI16 manaBonus; mutable SI32 FilePosition; SERIAL tempMulti; std::string name; @@ -223,6 +232,17 @@ class CBaseObject virtual void SetHP( SI16 newValue ); void IncHP( SI16 amtToChange ); + virtual SI16 GetSwingSpeedIncrease( void ) const; + virtual void SetSwingSpeedIncrease( SI16 newValue ); + + void IncSwingSpeedIncrease( SI16 toInc = 1 ); + + virtual SI16 GetHitChance( void ) const; + virtual void SetHitChance( SI16 newValue ); + + virtual SI16 GetDefenseChance( void ) const; + virtual void SetDefenseChance( SI16 newValue ); + void SetDir( UI08 newDir, bool sendUpdate = true ); UI08 GetDir( void ) const; @@ -256,6 +276,32 @@ class CBaseObject void IncDexterity( SI16 toInc = 1 ); void IncIntelligence( SI16 toInc = 1 ); + + SI16 GetHealthLeech( void ) const; + virtual void SetHealthLeech( SI16 nVal ); + + SI16 GetStaminaLeech( void ) const; + virtual void SetStaminaLeech( SI16 nVal ); + + SI16 GetManaLeech( void ) const; + virtual void SetManaLeech( SI16 nVal ); + + void IncHealthLeech( SI16 toInc = 1 ); + void IncStaminaLeech( SI16 toInc = 1 ); + void IncManaLeech( SI16 toInc = 1 ); + + void IncHitChance( SI16 toInc = 1 ); + void IncDefenseChance( SI16 toInc = 1 ); + + SI16 GetHealthBonus( void ) const; + virtual void SetHealthBonus( SI16 nVal ); + + SI16 GetStaminaBonus( void ) const; + virtual void SetStaminaBonus( SI16 nVal ); + + SI16 GetManaBonus( void ) const; + virtual void SetManaBonus( SI16 nVal ); + virtual void PostLoadProcessing( void ); virtual bool LoadRemnants( void ) = 0; diff --git a/source/cChar.cpp b/source/cChar.cpp index 7aa03f6fa..7fee0ca7a 100644 --- a/source/cChar.cpp +++ b/source/cChar.cpp @@ -2411,6 +2411,8 @@ void CChar::CopyData( CChar *target ) target->SetNextAct( nextAct ); target->SetSquelched( GetSquelched() ); target->SetMeditating( IsMeditating() ); + target->SetHitChance( GetHitChance() ); + target->SetDefenseChance( GetDefenseChance() ); target->SetStealth( stealth ); target->SetRunning( running ); target->SetRace( GetRace() ); @@ -2883,6 +2885,7 @@ CItem *CChar::GetItemAtLayer( ItemLayers Layer ) //| Purpose - Wears the item toWear and adjusts the stats if any are //| required to change. Returns true if successfully equipped //o------------------------------------------------------------------------------------------------o +void Bounce( CSocket *bouncer, CItem *bouncing, UI08 mode = 5 ); bool CChar::WearItem( CItem *toWear ) { // Run event prior to equipping item, allowing script to prevent equip @@ -2900,6 +2903,27 @@ bool CChar::WearItem( CItem *toWear ) } } + scriptTriggers.clear(); + scriptTriggers.shrink_to_fit(); + scriptTriggers = this->GetScriptTriggers(); + for( auto i : scriptTriggers ) + { + cScript *tScript = JSMapping->GetScript( i ); + if( tScript != nullptr ) + { + // If script returns false, prevent item from being equipped + if( tScript->OnEquipAttempt( this, toWear ) == 0 ) + { + CSocket *mSock = this->GetSocket(); + if( mSock != nullptr ) + { + Bounce( mSock, toWear ); + } + return false; + } + } + } + bool rValue = true; ItemLayers tLayer = toWear->GetLayer(); if( tLayer != IL_NONE ) // Layer == 0 is a special case, for things like trade windows and such @@ -2920,6 +2944,19 @@ bool CChar::WearItem( CItem *toWear ) IncDexterity2( itemLayers[tLayer]->GetDexterity2() ); IncIntelligence2( itemLayers[tLayer]->GetIntelligence2() ); + IncSwingSpeedIncrease( itemLayers[tLayer]->GetSwingSpeedIncrease() ); + + IncHealthLeech( itemLayers[tLayer]->GetHealthLeech() ); + IncStaminaLeech( itemLayers[tLayer]->GetStaminaLeech() ); + IncManaLeech( itemLayers[tLayer]->GetManaLeech() ); + + IncHitChance( itemLayers[tLayer]->GetHitChance() ); + IncDefenseChance( itemLayers[tLayer]->GetDefenseChance() ); + + IncHealthBonus( itemLayers[tLayer]->GetHealthBonus() ); + IncStaminaBonus( itemLayers[tLayer]->GetStaminaBonus() ); + IncManaBonus( itemLayers[tLayer]->GetManaBonus() ); + if( toWear->IsPostLoaded() ) { if( itemLayers[tLayer]->GetPoisoned() ) @@ -2972,6 +3009,22 @@ bool CChar::TakeOffItem( ItemLayers Layer ) } } + scriptTriggers.clear(); + scriptTriggers.shrink_to_fit(); + scriptTriggers = this->GetScriptTriggers(); + for( auto i : scriptTriggers ) + { + cScript *tScript = JSMapping->GetScript( i ); + if( tScript != nullptr ) + { + // If script returns false, prevent item from being equipped + if( tScript->OnUnequipAttempt( this, itemLayers[Layer] ) == 0 ) + { + return false; + } + } + } + if( Layer == IL_PACKITEM ) // It's our pack! { SetPackItem( nullptr ); @@ -2979,6 +3032,20 @@ bool CChar::TakeOffItem( ItemLayers Layer ) IncStrength2( -itemLayers[Layer]->GetStrength2() ); IncDexterity2( -itemLayers[Layer]->GetDexterity2() ); IncIntelligence2( -itemLayers[Layer]->GetIntelligence2() ); + + IncSwingSpeedIncrease( -itemLayers[Layer]->GetSwingSpeedIncrease() ); + + IncHealthLeech( -itemLayers[Layer]->GetHealthLeech() ); + IncStaminaLeech( -itemLayers[Layer]->GetStaminaLeech() ); + IncManaLeech( -itemLayers[Layer]->GetManaLeech() ); + + IncHitChance( -itemLayers[Layer]->GetHitChance() ); + IncDefenseChance( -itemLayers[Layer]->GetDefenseChance() ); + + IncHealthBonus( -itemLayers[Layer]->GetHealthBonus() ); + IncStaminaBonus( -itemLayers[Layer]->GetStaminaBonus() ); + IncManaBonus( -itemLayers[Layer]->GetManaBonus() ); + if( itemLayers[Layer]->GetPoisoned() ) { if( itemLayers[Layer]->GetPoisoned() > GetPoisoned() ) @@ -3134,6 +3201,8 @@ bool CChar::DumpBody( std::ostream &outStream ) const //------------------------------------------------------------------------------------------- outStream << "CanRun=" + std::to_string((( CanRun() && IsNpc() ) ? 1 : 0 )) + newLine; outStream << "CanAttack=" + std::to_string(( GetCanAttack() ? 1 : 0 )) + newLine; + outStream << "HitChance=" + std::to_string( GetHitChance() ) + newLine; + outStream << "DefChance=" + std::to_string( GetDefenseChance() ) + newLine; outStream << "AllMove=" + std::to_string(( AllMove() ? 1 : 0 )) + newLine; outStream << "IsNpc=" + std::to_string(( IsNpc() ? 1 : 0 )) + newLine; outStream << "IsShop=" + std::to_string(( IsShop() ? 1 : 0 )) + newLine; @@ -3787,7 +3856,7 @@ UI16 CChar::GetMaxHP( void ) oldRace = GetRace(); } - return maxHP; + return maxHP + GetHealthBonus(); } void CChar::SetMaxHP( UI16 newmaxhp, UI16 newoldstr, RACEID newoldrace ) { @@ -3830,7 +3899,7 @@ void CChar::SetFixedMaxHP( SI16 newmaxhp ) SI16 CChar::GetMaxMana( void ) { if(( maxMana_oldint != GetIntelligence() || oldRace != GetRace() ) && !GetMaxManaFixed() ) - //if int/race changed since last calculation, recalculate maxHp + //if int/race changed since last calculation, recalculate maxMana { CRace *pRace = Races->Race( GetRace() ); @@ -3847,7 +3916,7 @@ SI16 CChar::GetMaxMana( void ) oldRace = GetRace(); } - return maxMana; + return maxMana + GetManaBonus(); } void CChar::SetMaxMana( SI16 newmaxmana, UI16 newoldint, RACEID newoldrace ) { @@ -3889,7 +3958,7 @@ void CChar::SetFixedMaxMana( SI16 newmaxmana ) //o------------------------------------------------------------------------------------------------o SI16 CChar::GetMaxStam( void ) { - // If dex/race changed since last calculation, recalculate maxHp + // If dex/race changed since last calculation, recalculate maxStam if(( maxStam_olddex != GetDexterity() || oldRace != GetRace() ) && !GetMaxStamFixed() ) { CRace *pRace = Races->Race( GetRace() ); @@ -3907,7 +3976,7 @@ SI16 CChar::GetMaxStam( void ) oldRace = GetRace(); } - return maxStam; + return maxStam + GetStaminaBonus(); } void CChar::SetMaxStam( SI16 newmaxstam, UI16 newolddex, RACEID newoldrace ) { @@ -4372,6 +4441,11 @@ bool CChar::HandleLine( std::string &UTag, std::string &data ) SetDead(( static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 )) == 1 )); rValue = true; } + else if( UTag == "DEFCHANCE" ) + { + SetDefenseChance( static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 ))); + rValue = true; + } break; case 'E': if( UTag == "EMOTION" ) @@ -4460,7 +4534,12 @@ bool CChar::HandleLine( std::string &UTag, std::string &data ) } break; case 'H': - if( UTag == "HUNGER" ) + if( UTag == "HITCHANCE" ) + { + SetHitChance( static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 ))); + rValue = true; + } + else if( UTag == "HUNGER" ) { SetHunger( static_cast( std::stoi( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 ))); rValue = true; @@ -5593,6 +5672,74 @@ void CChar::SetIntelligence2( SI16 nVal ) UpdateRegion(); } +//o------------------------------------------------------------------------------------------------o +//| Function - CChar::SetHealthBonus() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Sets bonus Hits stat for character +//o------------------------------------------------------------------------------------------------o +void CChar::SetHealthBonus( SI16 nVal ) +{ + CBaseObject::SetHealthBonus( nVal ); + Dirty( UT_HITPOINTS ); + UpdateRegion(); +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CChar::SetStaminaBonus() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Sets bonus Stam stat for character +//o------------------------------------------------------------------------------------------------o +void CChar::SetStaminaBonus( SI16 nVal ) +{ + CBaseObject::SetStaminaBonus( nVal ); + Dirty( UT_STAMINA ); + UpdateRegion(); +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CChar::SetManaBonus() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Sets bonus Mana stat for character +//o------------------------------------------------------------------------------------------------o +void CChar::SetManaBonus( SI16 nVal ) +{ + CBaseObject::SetManaBonus( nVal ); + Dirty( UT_MANA ); + UpdateRegion(); +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CChar::IncHealthBonus() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Increments GetHealthBonus (modifications) by toAdd +//o------------------------------------------------------------------------------------------------o +void CChar::IncHealthBonus( SI16 toAdd ) +{ + SetHealthBonus( static_cast( GetHealthBonus() + toAdd )); +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CChar::IncStaminaBonus() +//| Date - 26 May 2024 +//o------------------------------------------------------------------------------------------------o +//| Purpose - Increments GetBonusStam (modifications) by toAdd +//o------------------------------------------------------------------------------------------------o +void CChar::IncStaminaBonus( SI16 toAdd ) +{ + SetStaminaBonus( static_cast( GetStaminaBonus() + toAdd )); +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CChar::IncManaBonus() +//| Date - 26 May 2024 +//o------------------------------------------------------------------------------------------------o +//| Purpose - Increments GetBonusMana (modifications) by toAdd +//o------------------------------------------------------------------------------------------------o +void CChar::IncManaBonus( SI16 toAdd ) +{ + SetManaBonus( static_cast( GetManaBonus() + toAdd )); +} + //o------------------------------------------------------------------------------------------------o //| Function - CChar::IncStamina() //o------------------------------------------------------------------------------------------------o diff --git a/source/cChar.h b/source/cChar.h index ed4cc90ba..ae387a58c 100644 --- a/source/cChar.h +++ b/source/cChar.h @@ -628,6 +628,15 @@ class CChar : public CBaseObject virtual void SetStrength2( SI16 newValue ) override; virtual void SetDexterity2( SI16 newValue ) override; virtual void SetIntelligence2( SI16 newValue ) override; + + virtual void SetHealthBonus( SI16 newValue ) override; + virtual void SetStaminaBonus( SI16 newValue ) override; + virtual void SetManaBonus( SI16 newValue ) override; + + void IncHealthBonus( SI16 toAdd = 1 ); + void IncStaminaBonus( SI16 toAdd = 1 ); + void IncManaBonus( SI16 toAdd = 1 ); + void IncStamina( SI16 toInc ); void IncMana( SI16 toInc ); void SetMaxLoyalty( UI16 newMaxLoyalty ); diff --git a/source/cItem.cpp b/source/cItem.cpp index 3a2acd106..b668ef29e 100644 --- a/source/cItem.cpp +++ b/source/cItem.cpp @@ -94,6 +94,7 @@ const UI16 DEFITEM_REGIONNUM = 255; const UI16 DEFITEM_TEMPLASTTRADED = 0; const SI08 DEFITEM_STEALABLE = 1; const SI16 DEFITEM_ARTIFACTRARITY = 0; +const SI16 DEFITEM_LOWERSTATREQ = 0; //o------------------------------------------------------------------------------------------------o //| Function - CItem() @@ -108,7 +109,7 @@ spd( DEFITEM_SPEED ), maxHp( DEFITEM_MAXHP ), amount( DEFITEM_AMOUNT ), layer( DEFITEM_LAYER ), type( DEFITEM_TYPE ), offspell( DEFITEM_OFFSPELL ), entryMadeFrom( DEFITEM_ENTRYMADEFROM ), creator( DEFITEM_CREATOR ), gridLoc( DEFITEM_GRIDLOC ), weightMax( DEFITEM_WEIGHTMAX ), baseWeight( DEFITEM_BASEWEIGHT ), maxItems( DEFITEM_MAXITEMS ), maxRange( DEFITEM_MAXRANGE ), baseRange( DEFITEM_BASERANGE ), maxUses( DEFITEM_MAXUSES ), usesLeft( DEFITEM_USESLEFT ), regionNum( DEFITEM_REGIONNUM ), -tempLastTraded( DEFITEM_TEMPLASTTRADED ), stealable( DEFITEM_STEALABLE ), artifactRarity(DEFITEM_ARTIFACTRARITY) +tempLastTraded( DEFITEM_TEMPLASTTRADED ), stealable( DEFITEM_STEALABLE ), artifactRarity( DEFITEM_ARTIFACTRARITY ), lowerStatReq( DEFITEM_LOWERSTATREQ ) { spells[0] = spells[1] = spells[2] = 0; value[0] = value[1] = value[2] = 0; @@ -560,6 +561,23 @@ void CItem::SetArtifactRarity( SI16 newValue ) UpdateRegion(); } +//o------------------------------------------------------------------------------------------------o +//| Function - CItem::GetLowerStatReq() +//| CItem::GetLowerStatReq() +//| Date - 30 April, 2024 +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets the Stat Requirements of the object +//o------------------------------------------------------------------------------------------------o +SI16 CItem::GetLowerStatReq( void ) const +{ + return lowerStatReq; +} +void CItem::SetLowerStatReq( SI16 newValue ) +{ + lowerStatReq = newValue; + UpdateRegion(); +} + //o------------------------------------------------------------------------------------------------o //| Function - CItem::GetName2() //| CItem::SetName2() @@ -1654,13 +1672,20 @@ auto CItem::CopyData( CItem *target ) -> void target->SetRndValueRate( GetRndValueRate() ); target->SetSpawn( GetSpawn() ); target->SetSpeed( GetSpeed() ); + target->SetHitChance( GetHitChance() ); + target->SetDefenseChance( GetDefenseChance() ); + target->SetArtifactRarity( GetArtifactRarity() ); + target->SetSpell( 0, GetSpell( 0 )); target->SetSpell( 1, GetSpell( 1 )); target->SetSpell( 2, GetSpell( 2 )); target->SetStamina( GetStamina() ); target->SetStrength( GetStrength() ); target->SetStrength2( GetStrength2() ); + target->SetHealthLeech( GetHealthLeech() ); + target->SetStaminaLeech( GetStaminaLeech() ); + target->SetManaLeech( GetManaLeech() ); target->SetTitle( GetTitle() ); target->SetType( GetType() ); target->SetBuyValue( GetBuyValue() ); @@ -1671,12 +1696,16 @@ auto CItem::CopyData( CItem *target ) -> void target->SetWeightMax( GetWeightMax() ); target->SetBaseWeight( GetBaseWeight() ); target->SetMaxItems( GetMaxItems() ); + target->SetHealthBonus( GetHealthBonus() ); + target->SetStaminaBonus( GetStaminaBonus() ); + target->SetManaBonus( GetManaBonus() ); //target->SetWipeable( IsWipeable() ); target->SetPriv( GetPriv() ); target->SetBaseRange( GetBaseRange() ); target->SetMaxRange( GetMaxRange() ); target->SetMaxUses( GetMaxUses() ); target->SetUsesLeft( GetUsesLeft() ); + target->SetLowerStatReq( GetLowerStatReq() ); target->SetStealable( GetStealable() ); // Set damage types on new item @@ -1753,10 +1782,15 @@ bool CItem::DumpBody( std::ostream &outStream ) const outStream << "BaseWeight=" + std::to_string( GetBaseWeight() ) + newLine; outStream << "MaxItems=" + std::to_string( GetMaxItems() ) + newLine; outStream << "MaxHP=" + std::to_string( GetMaxHP() ) + newLine; + outStream << "HitChance=" + std::to_string( GetHitChance() ) + newLine; + outStream << "DefenseChance=" + std::to_string( GetDefenseChance() ) + newLine; outStream << "Speed=" + std::to_string( GetSpeed() ) + newLine; + outStream << "BonusStats=" + std::to_string( GetHealthBonus() ) + "," + std::to_string( GetStaminaBonus() ) + "," + std::to_string( GetManaBonus() ) + newLine; outStream << "ArtifactRarity=" + std::to_string( GetArtifactRarity() ) + newLine; outStream << "Movable=" + std::to_string( GetMovable() ) + newLine; outStream << "Priv=" + std::to_string( GetPriv() ) + newLine; + outStream << "LowerStatReq=" + std::to_string( GetLowerStatReq() ) + newLine; + outStream << "LeechStats=" + std::to_string( GetHealthLeech() ) + "," + std::to_string( GetStaminaLeech() ) + "," + std::to_string( GetManaLeech() ) + newLine; outStream << "Value=" + std::to_string( GetBuyValue() ) + "," + std::to_string( GetSellValue() ) + "," + std::to_string( GetVendorPrice() ) + newLine; outStream << "Restock=" + std::to_string( GetRestock() ) + newLine; outStream << "AC=" + std::to_string( GetArmourClass() ) + newLine; @@ -1843,6 +1877,13 @@ bool CItem::HandleLine( std::string &UTag, std::string &data ) bools = static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 )); rValue = true; } + else if( UTag == "BONUSSTATS" ) + { + SetHealthBonus( static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( csecs[0], "//" )), nullptr, 0 ))); + SetStaminaBonus( static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( csecs[1], "//" )), nullptr, 0 ))); + SetManaBonus( static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( csecs[2], "//" )), nullptr, 0 ))); + rValue = true; + } break; case 'C': if( UTag == "CONT" ) @@ -1882,6 +1923,11 @@ bool CItem::HandleLine( std::string &UTag, std::string &data ) SetDye( static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 )) == 1 ); rValue = true; } + else if( UTag == "DEFENSECHANCE" ) + { + SetDefenseChance( static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 ))); + rValue = true; + } break; case 'E': if( UTag == "ENTRYMADEFROM" ) @@ -1928,6 +1974,11 @@ bool CItem::HandleLine( std::string &UTag, std::string &data ) SetWeatherDamage( HEAT, static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 )) == 1 ); rValue = true; } + else if( UTag == "HITCHANCE" ) + { + SetHitChance( static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 ))); + rValue = true; + } break; case 'L': if( UTag == "LAYER" ) @@ -1945,6 +1996,18 @@ bool CItem::HandleLine( std::string &UTag, std::string &data ) SetWeatherDamage( LIGHTNING, static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 )) == 1 ); rValue = true; } + else if( UTag == "LOWERSTATREQ" ) + { + SetLowerStatReq( static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( data, "//" )), nullptr, 0 ))); + rValue = true; + } + else if( UTag == "LEECHSTATS" ) + { + SetHealthLeech( static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( csecs[0], "//" )), nullptr, 0 ))); + SetStaminaLeech( static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( csecs[1], "//" )), nullptr, 0 ))); + SetManaLeech( static_cast( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( csecs[2], "//" )), nullptr, 0 ))); + rValue = true; + } break; case 'M': if( UTag == "MAXITEMS" ) diff --git a/source/cItem.h b/source/cItem.h index 4b220999e..62c7cb13a 100644 --- a/source/cItem.h +++ b/source/cItem.h @@ -49,6 +49,7 @@ class CItem : public CBaseObject SERIAL creator; // Store the serial of the player made this item SI08 gridLoc; SI16 artifactRarity; + SI16 lowerStatReq; SI32 weightMax; // Maximum weight a container can hold SI32 baseWeight; // Base weight of item. Applied when item is created for the first time, based on weight. Primarily used to determine base weight of containers UI16 maxItems; // Maximum amount of items a container can hold @@ -114,6 +115,9 @@ class CItem : public CBaseObject virtual SI16 GetArtifactRarity(void) const; virtual void SetArtifactRarity(SI16 newValue); + SI16 GetLowerStatReq( void ) const; + void SetLowerStatReq( SI16 newValue ); + auto GetStealable() const -> UI08; auto SetStealable( UI08 newValue ) -> void; diff --git a/source/cPlayerAction.cpp b/source/cPlayerAction.cpp index 5d58ccbd5..cf4b217c2 100644 --- a/source/cPlayerAction.cpp +++ b/source/cPlayerAction.cpp @@ -698,15 +698,19 @@ bool CPIEquipItem::Handle( void ) if( k == ourChar ) { bool canWear = false; - if( i->GetStrength() > k->GetStrength() ) + const SI16 scaledStrength = ( i->GetStrength() * ( 100 - i->GetLowerStatReq() )) / 100; + const SI16 scaledDexterity = ( i->GetDexterity() * ( 100 - i->GetLowerStatReq() )) / 100; + const SI16 scaledIntelligence = ( i->GetIntelligence() * ( 100 - i->GetLowerStatReq() )) / 100; + + if( scaledStrength > k->GetStrength() ) { tSock->SysMessage( 1188 ); // You are not strong enough to use that. (NOTE: Should these messages use color 0x096a to stand out and replicate hard coded client message?) } - else if( i->GetDexterity() > k->GetDexterity() ) + else if( scaledDexterity > k->GetDexterity() ) { tSock->SysMessage( 1189 ); // You are not agile enough to use that. } - else if( i->GetIntelligence() > k->GetIntelligence() ) + else if( scaledIntelligence > k->GetIntelligence() ) { tSock->SysMessage( 1190 ); // You are not smart enough to use that. } diff --git a/source/cScript.cpp b/source/cScript.cpp index 88ef1a0e6..82aa93790 100644 --- a/source/cScript.cpp +++ b/source/cScript.cpp @@ -55,6 +55,7 @@ static JSFunctionSpec my_functions[] = { "CalcCharFromSer", SE_CalcCharFromSer, 1, 0, 0 }, { "CalcItemFromSer", SE_CalcItemFromSer, 1, 0, 0 }, { "CalcMultiFromSer", SE_CalcMultiFromSer, 1, 0, 0 }, + { "CheckInstaLog", SE_CheckInstaLog, 4, 0, 0 }, { "GetHour", SE_GetHour, 0, 0, 0 }, { "GetMinute", SE_GetMinute, 0, 0, 0 }, { "GetDay", SE_GetDay, 0, 0, 0 }, @@ -972,40 +973,43 @@ std::string cScript::OnNameRequest( CBaseObject *myObj, CChar *nameRequester, UI } //o------------------------------------------------------------------------------------------------o -//| Function - cScript::OnAttack() +//| Function - cScript::OnAttack() //o------------------------------------------------------------------------------------------------o -//| Purpose - Triggers for character with event attached when attacking someone -//| Will also trigger the onDefense event for the character being attacked +//| Purpose - Triggers for character with event attached when attacking someone +//| Will also trigger the onDefense event for the character being attacked //o------------------------------------------------------------------------------------------------o -bool cScript::OnAttack( CChar *attacker, CChar *defender ) +bool cScript::OnAttack( CChar *attacker, CChar *defender, bool hitStatus, SI08 hitLoc, UI16 damageDealt ) { - if( !ValidateObject( attacker ) || !ValidateObject( defender )) - return false; + if( !ValidateObject( attacker ) || !ValidateObject( defender )) + return false; - if( !ExistAndVerify( seOnAttack, "onAttack" )) - return false; + if( !ExistAndVerify( seOnAttack, "onAttack" )) + return false; - jsval rval, params[2]; - JSObject *attObj = JSEngine->AcquireObject( IUE_CHAR, attacker, runTime ); - JSObject *defObj = JSEngine->AcquireObject( IUE_CHAR, defender, runTime ); + jsval rval, params[5]; + JSObject *attObj = JSEngine->AcquireObject( IUE_CHAR, attacker, runTime ); + JSObject *defObj = JSEngine->AcquireObject( IUE_CHAR, defender, runTime ); - params[0] = OBJECT_TO_JSVAL( attObj ); - params[1] = OBJECT_TO_JSVAL( defObj ); - JSBool retVal = JS_CallFunctionName( targContext, targObject, "onAttack", 2, params, &rval ); - if( retVal == JS_FALSE ) - { - SetEventExists( seOnAttack, false ); - } + params[0] = OBJECT_TO_JSVAL( attObj ); + params[1] = OBJECT_TO_JSVAL( defObj ); + params[2] = BOOLEAN_TO_JSVAL( hitStatus ); + params[3] = INT_TO_JSVAL( hitLoc ); + params[4] = INT_TO_JSVAL( damageDealt ); + JSBool retVal = JS_CallFunctionName( targContext, targObject, "onAttack", 5, params, &rval ); + if( retVal == JS_FALSE ) + { + SetEventExists( seOnAttack, false ); + } - return ( retVal == JS_TRUE ); + return ( retVal == JS_TRUE ); } //o------------------------------------------------------------------------------------------------o -//| Function - cScript::OnDefense() +//| Function - cScript::OnDefense() //o------------------------------------------------------------------------------------------------o -//| Purpose - Triggers for character with event attached when being attacked +//| Purpose - Triggers for character with event attached when being attacked //o------------------------------------------------------------------------------------------------o -bool cScript::OnDefense( CChar *attacker, CChar *defender ) +bool cScript::OnDefense( CChar *attacker, CChar *defender, bool hitStatus, SI08 hitLoc, UI16 damageReceived ) { if( !ValidateObject( attacker ) || !ValidateObject( defender )) return false; @@ -1013,13 +1017,16 @@ bool cScript::OnDefense( CChar *attacker, CChar *defender ) if( !ExistAndVerify( seOnDefense, "onDefense" )) return false; - jsval rval, params[2]; + jsval rval, params[5]; JSObject *attObj = JSEngine->AcquireObject( IUE_CHAR, attacker, runTime ); JSObject *defObj = JSEngine->AcquireObject( IUE_CHAR, defender, runTime ); params[0] = OBJECT_TO_JSVAL( attObj ); params[1] = OBJECT_TO_JSVAL( defObj ); - JSBool retVal = JS_CallFunctionName( targContext, targObject, "onDefense", 2, params, &rval ); + params[2] = BOOLEAN_TO_JSVAL( hitStatus ); + params[3] = INT_TO_JSVAL( hitLoc ); + params[4] = INT_TO_JSVAL( damageReceived ); + JSBool retVal = JS_CallFunctionName( targContext, targObject, "onDefense", 5, params, &rval ); if( retVal == JS_FALSE ) { SetEventExists( seOnDefense, false ); @@ -1624,6 +1631,38 @@ SI08 cScript::OnMultiLogout( CMultiObj *iMulti, CChar *cPlayer ) return TryParseJSVal( rval ); } +//o------------------------------------------------------------------------------------------------o +//| Function - cScript::OnBoatTurn() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Triggers for Boat after it has turned successfully +//o------------------------------------------------------------------------------------------------o +SI08 cScript::OnBoatTurn( CBoatObj *iBoat, UI08 oldDir, UI08 newDir ) +{ + const SI08 RV_NOFUNC = -1; + if( !ValidateObject( iBoat )) + return RV_NOFUNC; + + if( !ExistAndVerify( seOnBoatTurn, "onBoatTurn" )) + return RV_NOFUNC; + + jsval params[3], rval; + JSObject *myBoat = JSEngine->AcquireObject( IUE_ITEM, iBoat, runTime ); + + + params[0] = OBJECT_TO_JSVAL( myBoat ); + params[1] = INT_TO_JSVAL( oldDir ); + params[2] = INT_TO_JSVAL( newDir ); + + JSBool retVal = JS_CallFunctionName( targContext, targObject, "onBoatTurn", 3, params, &rval ); + if( retVal == JS_FALSE ) + { + SetEventExists( seOnBoatTurn, false ); + return RV_NOFUNC; + } + + return TryParseJSVal( rval ); +} + //o------------------------------------------------------------------------------------------------o //| Function - cScript::OnEquipAttempt() //o------------------------------------------------------------------------------------------------o @@ -3871,6 +3910,37 @@ SI08 cScript::OnCombatEnd( CChar *currChar, CChar *targChar ) return TryParseJSVal( rval ); } +//o------------------------------------------------------------------------------------------------o +//| Function - cScript::OnCombatHit() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Triggers for character with event attached when someone has taken damage. +//| +//o------------------------------------------------------------------------------------------------o +SI08 cScript::OnCombatHit( CChar *attacker, CChar *defender ) +{ + const SI08 RV_NOFUNC = -1; + if( !ValidateObject( attacker ) || !ValidateObject( defender )) + return RV_NOFUNC; + + if( !ExistAndVerify( seOnCombatHit, "onCombatHit" )) + return RV_NOFUNC; + + jsval rval, params[2]; + JSObject *attObj = JSEngine->AcquireObject( IUE_CHAR, attacker, runTime ); + JSObject *defObj = JSEngine->AcquireObject( IUE_CHAR, defender, runTime ); + + params[0] = OBJECT_TO_JSVAL( attObj ); + params[1] = OBJECT_TO_JSVAL( defObj ); + JSBool retVal = JS_CallFunctionName( targContext, targObject, "onCombatHit", 2, params, &rval ); + if( retVal == JS_FALSE ) + { + SetEventExists( seOnCombatHit, false ); + return RV_NOFUNC; + } + + return TryParseJSVal( rval ); +} + //o------------------------------------------------------------------------------------------------o //| Function - cScript::OnDeathBlow() //| Date - 8th February, 2006 diff --git a/source/cScript.h b/source/cScript.h index f98e13c70..a37af9705 100644 --- a/source/cScript.h +++ b/source/cScript.h @@ -40,6 +40,7 @@ enum ScriptEvent seOnEntrance, // ** seOnLeaving, // ** seOnMultiLogout, // ** + seOnBoatTurn, // ** seOnEquipAttempt, // ** seOnEquip, // ** seOnUnequipAttempt, // ** @@ -96,6 +97,7 @@ enum ScriptEvent seOnCombatStart, // ** allows overriding what happens when combat is initiated seOnAICombatTarget, // ** allows overriding target selection taking place for regular AI behaviours seOnCombatEnd, // ** allows overriding what happens when combat ends + seOnCombatHit, // ** allows overriding what happens when combat hits seOnDeathBlow, seOnCombatDamageCalc, seOnDamage, @@ -199,8 +201,8 @@ class cScript bool OnStat( void ); std::string OnTooltip( CBaseObject *myObj, CSocket *pSocket ); std::string OnNameRequest( CBaseObject *myObj, CChar *nameRequester, UI08 requestSource ); - bool OnAttack( CChar *attacker, CChar *defender ); - bool OnDefense( CChar *attacker, CChar *defender ); + bool OnAttack( CChar *attacker, CChar *defender, bool hitStatus, SI08 hitLoc, UI16 damageDealt ); + bool OnDefense( CChar *attacker, CChar *defender, bool hitStatus, SI08 hitLoc, UI16 damageReceived ); SI08 OnSkillGain( CChar *player, SI08 skill, UI32 skillAmtGained ); SI08 OnSkillLoss( CChar *player, SI08 skill, UI32 skillAmtLost ); bool OnSkillChange( CChar *player, SI08 skill, SI32 skillAmtChanged ); @@ -216,6 +218,7 @@ class cScript SI08 OnEntrance( CMultiObj *left, CBaseObject *leaving ); SI08 OnLeaving( CMultiObj *left, CBaseObject *leaving ); SI08 OnMultiLogout( CMultiObj* iMulti, CChar* cPlayer ); + SI08 OnBoatTurn( CBoatObj* iMulti, UI08 oldDir, UI08 newDir ); SI08 OnEquipAttempt( CChar *equipper, CItem *equipping ); SI08 OnEquip( CChar *equipper, CItem *equipping ); SI08 OnUnequipAttempt( CChar *equipper, CItem *equipping ); @@ -279,6 +282,7 @@ class cScript SI08 OnSkillGump( CChar *mChar ); SI08 OnUseBandageMacro( CSocket *mSock, CChar *targChar, CItem *bandageItem ); SI08 OnAICombatTarget( CChar *attacker, CChar *target ); + SI08 OnCombatHit( CChar *attacker, CChar *defender ); SI08 OnCombatStart( CChar *attacker, CChar *defender ); SI08 OnCombatEnd( CChar *attacker, CChar *defender ); diff --git a/source/cServerData.cpp b/source/cServerData.cpp index 3f57745a8..baebacaf7 100644 --- a/source/cServerData.cpp +++ b/source/cServerData.cpp @@ -369,7 +369,8 @@ const std::map CServerData::uox3IniCaseValue {"SECRETSHARDKEY"s, 346}, {"MOONGATEFACETS"s, 347}, {"AUTOUNEQUIPPEDCASTING"s, 348}, - {"LOOTDECAYSWITHNPCCORPSE"s, 349} + {"LOOTDECAYSWITHNPCCORPSE"s, 349}, + {"SWINGSPEEDINCREASECAP"s, 353} }; constexpr auto MAX_TRACKINGTARGETS = 128; constexpr auto SKILLTOTALCAP = 7000; @@ -723,6 +724,7 @@ auto CServerData::ResetDefaults() -> void PetCombatTraining( true ); HirelingCombatTraining( true ); NpcCombatTraining( false ); + SwingSpeedIncreaseCap( 60 ); WeaponDamageBonusType( 2 ); CheckPetControlDifficulty( true ); @@ -5196,7 +5198,7 @@ auto CServerData::SaveIni( const std::string &filename ) -> bool ofsOutput << "SHOWITEMRESISTSTATS=" << ( ShowItemResistStats() ? 1 : 0 ) << '\n'; ofsOutput << "SHOWWEAPONDAMAGETYPES=" << ( ShowWeaponDamageTypes() ? 1 : 0 ) << '\n'; ofsOutput << "WEAPONDAMAGEBONUSTYPE=" << static_cast( WeaponDamageBonusType() ) << '\n'; - + ofsOutput << "WEAPONSWINGSPEEDINCREASECAP=" << SwingSpeedIncreaseCap() << '\n'; ofsOutput << "}" << '\n'; ofsOutput << '\n' << "[magic]" << '\n' << "{" << '\n'; @@ -5395,6 +5397,20 @@ auto CServerData::TrackingRedisplayTime( UI16 value ) -> void trackingMsgRedisplayTimer = value; } +//o------------------------------------------------------------------------------------------------o +//| Function - CServerData::SwingSpeedIncreaseCap() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets the for swing speed cap propertie +//o------------------------------------------------------------------------------------------------o +auto CServerData::SwingSpeedIncreaseCap() const -> SI16 +{ + return swingSpeedIncreaseCap; +} +auto CServerData::SwingSpeedIncreaseCap( SI16 value ) -> void +{ + swingSpeedIncreaseCap = value; +} + //o------------------------------------------------------------------------------------------------o //| Function - CServerData::ParseIni() @@ -6565,6 +6581,9 @@ auto CServerData::HandleLine( const std::string& tag, const std::string& value ) case 349: // LOOTDECAYSWITHNPCCORPSE NpcCorpseLootDecay( static_cast( std::stoul( value, nullptr, 0 )) != 0 ); break; + case 353: // SWINGSPEEDINCREASE + SwingSpeedIncreaseCap( std::stof( value )); + break; default: rValue = false; break; diff --git a/source/cServerData.h b/source/cServerData.h index d770645c8..3abf534e0 100644 --- a/source/cServerData.h +++ b/source/cServerData.h @@ -400,6 +400,7 @@ class CServerData SI16 combatNpcBaseFleeAt; // % of HP where an NPC will flee, if it's not defined for them SI16 combatNpcBaseReattackAt; // % of HP where an NPC will resume attacking SI16 combatAttackStamina; // Amount of stamina lost when hitting an opponent + SI16 swingSpeedIncreaseCap; // The Cap for swing speed property // Start & Location Settings std::vector<__STARTLOCATIONDATA__> startlocations; @@ -953,6 +954,9 @@ class CServerData auto BODsFromCraftedItemsOnly( bool value ) -> void; auto BODsFromCraftedItemsOnly() const -> bool; + auto SwingSpeedIncreaseCap( SI16 value ) -> void; + SI16 SwingSpeedIncreaseCap() const; + auto MaxControlSlots( UI08 value ) -> void; UI08 MaxControlSlots() const; diff --git a/source/combat.cpp b/source/combat.cpp index 8817d7b3d..d923465d8 100644 --- a/source/combat.cpp +++ b/source/combat.cpp @@ -801,6 +801,10 @@ UI08 CHandleCombat::GetWeaponType( CItem *i ) case 0x48B3: //gargish axe - SA return TWOHND_AXES; // Default Maces + case 0x0DF2: // Wand + case 0x0DF3: // Wand + case 0x0DF4: // Wand + case 0x0DF5: // Wand case 0x13E3: //smith's hammer case 0x13E4: //smith's hammer case 0x13B3: //club @@ -2645,7 +2649,7 @@ SI16 CHandleCombat::ApplyDefenseModifiers( WeatherType damageType, CChar *mChar, if( getDef > 0 ) { - damage -= static_cast(( static_cast( getDef ) * static_cast( attSkill )) / 750 ); + damage -= static_cast( getDef ); } return static_cast( std::round( damage )); @@ -2877,18 +2881,24 @@ bool CHandleCombat::HandleCombat( CSocket *mSock, CChar& mChar, CChar *ourTarg ) R32 attHitChanceBonus = 0; R32 defDefenseChanceBonus = 0; R32 maxAttHitChanceBonus = 45; + if( cwmWorldState->ServerData()->ExpansionCombatHitChance() >= ER_SA && mChar.GetBodyType() == BT_GARGOYLE ) { // If attacker is a Gargoyle player, and ExpansionCombatHitChance is ER_SA or higher, use 50 as hitchance bonus cap instead of 45 maxAttHitChanceBonus = 50; } - // Fetch bonuses to hitChance/defenseChance from AoS item properties, when implemented - //attHitChanceBonus = GetAttackerHitChanceBonus(); - //defDefenseChanceBonus = GetDefenderDefenseChanceBonus(); + // Fetch bonuses to hitChance/defenseChance from AoS item properties or characters + attHitChanceBonus = mChar.GetHitChance(); + defDefenseChanceBonus = mChar.GetDefenseChance(); + + // Clamp to ensure valid bonus ranges (e.g., no multiplier below 1) + R32 effectiveAttHitChanceBonus = std::max(-99.0f, std::min( attHitChanceBonus, maxAttHitChanceBonus )); // Cap at -99 and maxAttHitChanceBonus + R32 effectiveDefDefenseChanceBonus = std::max(-99.0f, std::min( defDefenseChanceBonus, 45.0f )); // Cap at -99 and 45 - R32 attackerHitChance = ( static_cast( attackSkill / 10 ) + 20 ) * ( 100 + std::min( attHitChanceBonus, static_cast( maxAttHitChanceBonus ))); - R32 defenderDefenseChance = ( static_cast( defendSkill / 10 ) + 20 ) * ( 100 + std::min( defDefenseChanceBonus, static_cast( 45 ))); + // Calculate the attacker's hit chance and defender's defense chance + R32 attackerHitChance = ( static_cast( attackSkill / 10 ) + 20 ) * ( 100 + effectiveAttHitChanceBonus ); + R32 defenderDefenseChance = ( static_cast( defendSkill / 10 ) + 20 ) * ( 100 + effectiveDefDefenseChanceBonus ); hitChance = ( attackerHitChance / ( defenderDefenseChance * 2 )) * 100; // Always leave at least 2% chance to hit @@ -2916,6 +2926,25 @@ bool CHandleCombat::HandleCombat( CSocket *mSock, CChar& mChar, CChar *ourTarg ) } PlayMissedSoundEffect( &mChar ); + + for( auto scriptTrig : scriptTriggers ) + { + cScript *toExecute = JSMapping->GetScript( scriptTrig ); + if( toExecute != nullptr ) + { + toExecute->OnAttack( &mChar, ourTarg, skillPassed, -1, 0 ); + } + } + + std::vector defScriptTriggers = ourTarg->GetScriptTriggers(); + for( auto scriptTrig : defScriptTriggers ) + { + cScript *toExecute = JSMapping->GetScript( scriptTrig ); + if( toExecute != nullptr ) + { + toExecute->OnDefense( &mChar, ourTarg, skillPassed, -1, 0 ); + } + } } else { @@ -2994,6 +3023,15 @@ bool CHandleCombat::HandleCombat( CSocket *mSock, CChar& mChar, CChar *ourTarg ) // Show hit messages, if enabled DoHitMessage( &mChar, ourTarg, hitLoc, ourDamage ); + for( auto scriptTrig : scriptTriggers ) + { + cScript *toExecute = JSMapping->GetScript( scriptTrig ); + if( toExecute != nullptr ) + { + toExecute->OnCombatHit( &mChar, ourTarg ); + } + } + // Interrupt Spellcasting if( !ourTarg->IsNpc() && targSock != nullptr ) { @@ -3035,7 +3073,7 @@ bool CHandleCombat::HandleCombat( CSocket *mSock, CChar& mChar, CChar *ourTarg ) cScript *toExecute = JSMapping->GetScript( scriptTrig ); if( toExecute != nullptr ) { - toExecute->OnAttack( &mChar, ourTarg ); + toExecute->OnAttack( &mChar, ourTarg, skillPassed, hitLoc, ourDamage ); } } @@ -3045,7 +3083,7 @@ bool CHandleCombat::HandleCombat( CSocket *mSock, CChar& mChar, CChar *ourTarg ) cScript *toExecute = JSMapping->GetScript( scriptTrig ); if( toExecute != nullptr ) { - toExecute->OnDefense( &mChar, ourTarg ); + toExecute->OnDefense( &mChar, ourTarg, skillPassed, hitLoc, ourDamage ); } } } @@ -3430,7 +3468,8 @@ R32 CHandleCombat::GetCombatTimeout( CChar *mChar ) } SI32 getOffset = 0; - SI32 baseValue = 15000; + SI32 baseValue = ( cwmWorldState->ServerData()->ExpansionCoreShardEra() <= ER_LBR ) ? 15000 : + (( cwmWorldState->ServerData()->ExpansionCoreShardEra() < ER_ML ) ? 80000 : 40000 ); CChar *ourTarg = mChar->GetTarg(); @@ -3455,18 +3494,49 @@ R32 CHandleCombat::GetCombatTimeout( CChar *mChar ) } } + SI32 speedBonus = mChar->GetSwingSpeedIncrease(); + + // Swing Speed Increase Cap per AOS + if ( speedBonus > cwmWorldState->ServerData()->SwingSpeedIncreaseCap() ) + { + speedBonus = cwmWorldState->ServerData()->SwingSpeedIncreaseCap(); + } + //Allow faster strikes on fleeing targets if( ValidateObject( ourTarg )) { if( ourTarg->GetNpcWander() == WT_FLEE || ourTarg->GetNpcWander() == WT_SCARED ) { - baseValue = 10000; + baseValue = ( cwmWorldState->ServerData()->ExpansionCoreShardEra() <= ER_LBR ) ? 10000 : + (( cwmWorldState->ServerData()->ExpansionCoreShardEra() < ER_ML ) ? 53333 : 26680 ); } } R32 globalAttackSpeed = cwmWorldState->ServerData()->GlobalAttackSpeed(); //Defaults to 1.0 - getDelay = ( baseValue / ( getDelay * getOffset )) / globalAttackSpeed; + R32 speedFactor = 1 + speedBonus / 10.0f; + + // Prevent zero or negative multipliers + if( speedFactor < 0.1f ) + speedFactor = 0.1f; + + + if( cwmWorldState->ServerData()->ExpansionCoreShardEra() <= ER_LBR ) + { + // Weapon swing delay in LBR and earlier + getDelay = baseValue / ( getDelay * getOffset * speedFactor ) / globalAttackSpeed; + } + else if( cwmWorldState->ServerData()->ExpansionCoreShardEra() < ER_ML ) + { + // Weapon swing delay in SE or earlier + getDelay = ( baseValue / ( getDelay * getOffset * speedFactor ) / 4 - 0.5 ) / globalAttackSpeed; + } + else + { + // Weapon swing delay in ML or later + getDelay = ( baseValue / ( getDelay * getOffset * speedFactor ) * 0.5 ) / globalAttackSpeed; + } + return getDelay; } diff --git a/source/enums.h b/source/enums.h index 1383bbd10..16db01f95 100644 --- a/source/enums.h +++ b/source/enums.h @@ -373,8 +373,8 @@ enum Skills BUSHIDO, NINJITSU, SPELLWEAVING, - IMBUING, MYSTICISM, + IMBUING, THROWING, ALLSKILLS, // #skills+1 diff --git a/source/gumps.cpp b/source/gumps.cpp index c655634d2..3b2d56cb0 100644 --- a/source/gumps.cpp +++ b/source/gumps.cpp @@ -669,10 +669,21 @@ void BuildAddMenuGump( CSocket *s, UI16 m ) if( tag.data()[0] != '<' && tag.data()[0] != ' ' ) // it actually has a picture, well bugger me! :> { // Draw a frame for the item to make it stand out a touch more. - toSend.addCommand( oldstrutil::format( "checkertrans %u %u %u %u", xOffset + 7, yOffset + 9, 110, 110 )); - toSend.addCommand( oldstrutil::format( "buttontileart %u %u 0x0a9f 0x0aa1 %u %u %u %u %u %u %u", xOffset, yOffset, 1, 0, buttonnum, std::stoi( tag, nullptr, 0 ), 0, 25, 25 )); - toSend.addCommand( oldstrutil::format( "tooltip 1042971 @%s@", data.c_str() )); - toSend.addCommand( oldstrutil::format( "croppedtext %u %u %u %u %u %u", xOffset + 15, yOffset + 85, 100, 20, 50, linenum++ )); + if( s->ClientVerShort() <= CVS_70160 ) + { + // Fallback for older clients that don't support buttontileart + toSend.addCommand( oldstrutil::format("resizepic %u %u %u %u %u", xOffset, yOffset, 0x53, 65, 100 )); + toSend.addCommand( oldstrutil::format("checkertrans %u %u %u %u", xOffset + 7, yOffset + 9, 52, 82 )); + toSend.addCommand( oldstrutil::format("tilepic %u %u %i", xOffset + 5, yOffset + 10, std::stoi(tag, nullptr, 0) )); + toSend.addCommand( oldstrutil::format("croppedtext %u %u %u %u %u %u", xOffset, yOffset + 65, 65, 20, 55, linenum++ )); + } + else + { + toSend.addCommand( oldstrutil::format( "checkertrans %u %u %u %u", xOffset + 7, yOffset + 9, 110, 110 )); + toSend.addCommand( oldstrutil::format( "buttontileart %u %u 0x0a9f 0x0aa1 %u %u %u %u %u %u %u", xOffset, yOffset, 1, 0, buttonnum, std::stoi( tag, nullptr, 0 ), 0, 25, 25 )); + toSend.addCommand( oldstrutil::format( "tooltip 1042971 @%s@", data.c_str() )); + toSend.addCommand( oldstrutil::format( "croppedtext %u %u %u %u %u %u", xOffset + 15, yOffset + 85, 100, 20, 50, linenum++ )); + } toSend.addText( data ); xOffset += XOFFSET; if( xOffset > 640 ) diff --git a/source/items.cpp b/source/items.cpp index a95e80f70..5951c4a36 100644 --- a/source/items.cpp +++ b/source/items.cpp @@ -139,7 +139,13 @@ auto ApplyItemSection( CItem *applyTo, CScriptSection *toApply, std::string sect } break; case DFNTAG_AC: applyTo->SetArmourClass( static_cast( ndata )); break; + case DFNTAG_HEALTHLEECH: applyTo->SetHealthLeech( static_cast( ndata )); break; + case DFNTAG_STAMINALEECH: applyTo->SetStaminaLeech( static_cast( ndata )); break; + case DFNTAG_MANALEECH: applyTo->SetManaLeech( static_cast( ndata )); break; case DFNTAG_BASERANGE: applyTo->SetBaseRange( static_cast( ndata )); break; + case DFNTAG_HEALTHBONUS: applyTo->SetHealthBonus( static_cast( ndata )); break; + case DFNTAG_STAMINABONUS: applyTo->SetStaminaBonus( static_cast( ndata )); break; + case DFNTAG_MANABONUS: applyTo->SetManaBonus( static_cast( ndata )); break; case DFNTAG_CREATOR: applyTo->SetCreator( ndata ); break; case DFNTAG_COLOUR: applyTo->SetColour( static_cast( ndata )); break; case DFNTAG_COLOURLIST: applyTo->SetColour( AddRandomColor( cdata )); break; @@ -230,6 +236,7 @@ auto ApplyItemSection( CItem *applyTo, CScriptSection *toApply, std::string sect case DFNTAG_DISPELLABLE: applyTo->SetDispellable( true ); break; case DFNTAG_DISABLED: applyTo->SetDisabled( ndata != 0 ); break; case DFNTAG_DOORFLAG: break; + case DFNTAG_DEFENSECHANCE: applyTo->SetDefenseChance( static_cast( ndata )); break; case DFNTAG_GOOD: applyTo->SetGood( static_cast( ndata )); break; case DFNTAG_GLOW: applyTo->SetGlow( ndata ); break; case DFNTAG_GLOWBC: applyTo->SetGlowColour( static_cast( ndata )); break; @@ -339,6 +346,7 @@ auto ApplyItemSection( CItem *applyTo, CScriptSection *toApply, std::string sect } break; case DFNTAG_HIDAMAGE: applyTo->SetHiDamage( static_cast( ndata )); break; + case DFNTAG_HITCHANCE: applyTo->SetHitChance( static_cast( ndata )); break; case DFNTAG_HEAT: applyTo->SetWeatherDamage( HEAT, ndata != 0 ); break; case DFNTAG_ID: // applyTo->SetId( static_cast( ndata )); break; if( ssecs.size() == 1 ) @@ -357,6 +365,7 @@ auto ApplyItemSection( CItem *applyTo, CScriptSection *toApply, std::string sect case DFNTAG_LAYER: applyTo->SetLayer( static_cast( ndata )); break; case DFNTAG_LIGHT: applyTo->SetWeatherDamage( LIGHT, ndata != 0 ); break; case DFNTAG_LIGHTNING: applyTo->SetWeatherDamage( LIGHTNING, ndata != 0 ); break; + case DFNTAG_LOWERSTATREQ: applyTo->SetLowerStatReq( static_cast( ndata )); break; case DFNTAG_MAXHP: applyTo->SetMaxHP( static_cast( ndata )); break; case DFNTAG_MAXITEMS: applyTo->SetMaxItems( static_cast( ndata )); break; case DFNTAG_MAXRANGE: applyTo->SetMaxRange( static_cast( ndata )); break; @@ -549,6 +558,7 @@ auto ApplyItemSection( CItem *applyTo, CScriptSection *toApply, std::string sect case DFNTAG_RAIN: applyTo->SetWeatherDamage( RAIN, ndata != 0 ); break; case DFNTAG_SECTIONID: applyTo->SetSectionId( cdata ); break; case DFNTAG_SK_MADE: applyTo->SetMadeWith( static_cast( ndata )); break; + case DFNTAG_SWINGSPEEDINCREASE: applyTo->SetSwingSpeedIncrease( static_cast( ndata )); break; case DFNTAG_SPD: applyTo->SetSpeed( static_cast( ndata )); break; case DFNTAG_STRENGTH: applyTo->SetStrength( static_cast( ndata )); break; case DFNTAG_STRADD: applyTo->SetStrength2( static_cast( ndata )); break; @@ -1821,7 +1831,8 @@ void cItem::CheckEquipment( CChar *p ) { if( ValidateObject( i )) { - if( i->GetStrength() > StrengthToCompare )//if strength required > character's strength + const SI16 scaledStrength = ( i->GetStrength() * ( 100 - i->GetLowerStatReq() )) / 100; + if( scaledStrength > StrengthToCompare )//if strength required > character's strength { itemsToUnequip.push_back( i ); } diff --git a/source/magic.cpp b/source/magic.cpp index d04ab3f97..7d49c6461 100644 --- a/source/magic.cpp +++ b/source/magic.cpp @@ -4499,6 +4499,11 @@ void CMagic::CastSpell( CSocket *s, CChar *caster ) caster->StopSpell(); return; } + else if( caster->IsNpc() ) + { + // Run a skillcheck for NPC to give them a chance to gain skill - if that option is enabled in ini + Skills->CheckSkill( caster, MAGERY, lowSkill, highSkill ); + } if( curSpell > 63 && static_cast(curSpell) <= spellCount && spellCount <= 70 ) { diff --git a/source/npcs.cpp b/source/npcs.cpp index 36005b420..41536fea6 100644 --- a/source/npcs.cpp +++ b/source/npcs.cpp @@ -1541,6 +1541,8 @@ auto CCharStuff::ApplyNpcSection( CChar *applyTo, CScriptSection *NpcCreation, s case DFNTAG_NAMELIST: SetRandomName( applyTo, cdata ); break; case DFNTAG_NECROMANCY: skillToSet = NECROMANCY; break; case DFNTAG_NINJITSU: skillToSet = NINJITSU; break; + case DFNTAG_HITCHANCE: applyTo->SetHitChance( static_cast( ndata )); break; + case DFNTAG_DEFENSECHANCE: applyTo->SetDefenseChance( static_cast( ndata )); break; case DFNTAG_NPCWANDER: if( !isGate ) { @@ -1583,6 +1585,7 @@ auto CCharStuff::ApplyNpcSection( CChar *applyTo, CScriptSection *NpcCreation, s case DFNTAG_PEACEMAKING: skillToSet = PEACEMAKING; break; case DFNTAG_PROVOCATION: skillToSet = PROVOCATION; break; case DFNTAG_POISONING: skillToSet = POISONING; break; + case DFNTAG_SWINGSPEEDINCREASE: applyTo->SetSwingSpeedIncrease( static_cast( ndata )); break; case DFNTAG_RESISTFIRE: if( ndata >= 0 ) { diff --git a/source/ssection.cpp b/source/ssection.cpp index fae41e7a1..6d89e606f 100644 --- a/source/ssection.cpp +++ b/source/ssection.cpp @@ -67,6 +67,7 @@ const UI08 dfnDataTypes[DFNTAG_COUNTOFTAGS] = DFN_NUMERIC, // DFNTAG_DOORFLAG, DFN_NUMERIC, // DFNTAG_DYE, DFN_NUMERIC, // DFNTAG_DYEBEARD, + DFN_NUMERIC, // DFNTAG_DEFENSECHANCE, DFN_NUMERIC, // DFNTAG_DYEHAIR, DFN_STRING, // DFNTAG_ELEMENTRESIST, DFN_STRING, // DFNTAG_ERBONUS, @@ -112,10 +113,12 @@ const UI08 dfnDataTypes[DFNTAG_COUNTOFTAGS] = DFN_NUMERIC, // DFNTAG_HEAT, DFN_DOUBLENUMERIC, // DFNTAG_HERDING, DFN_NUMERIC, // DFNTAG_HIDAMAGE, + DFN_NUMERIC, // DFNTAG_HITCHANCE, DFN_DOUBLENUMERIC, // DFNTAG_HIDING, DFN_NODATA, // DFNTAG_HIRELING, DFN_DOUBLENUMERIC, // DFNTAG_HP, DFN_DOUBLENUMERIC, // DFNTAG_HPMAX, + DFN_NUMERIC, // DFNTAG_HEALTHLEECH, DFN_UPPERSTRING, // DFNTAG_ID, DFN_DOUBLENUMERIC, // DFNTAG_IMBUING, DFN_NUMERIC, // DFNTAG_INTADD, @@ -131,6 +134,7 @@ const UI08 dfnDataTypes[DFNTAG_COUNTOFTAGS] = DFN_NUMERIC, // DFNTAG_LAYER, DFN_NUMERIC, // DFNTAG_LIGHT, DFN_NUMERIC, // DFNTAG_LIGHTNING, + DFN_NUMERIC, // DFNTAG_LOWERSTATREQ, DFN_NUMERIC, // DFNTAG_LOCKPICKING, DFN_NUMERIC, // DFNTAG_LODAMAGE, DFN_UPPERSTRING, // DFNTAG_LOOT, @@ -141,6 +145,7 @@ const UI08 dfnDataTypes[DFNTAG_COUNTOFTAGS] = DFN_DOUBLENUMERIC, // DFNTAG_MAGICRESISTANCE, DFN_DOUBLENUMERIC, // DFNTAG_MANA, DFN_DOUBLENUMERIC, // DFNTAG_MANAMAX, + DFN_NUMERIC, // DFNTAG_MANALEECH, DFN_NUMERIC, // DFNTAG_MAXHP, DFN_NUMERIC, // DFNTAG_MAXITEMS, DFN_NUMERIC, // DFNTAG_MAXLOYALTY, @@ -216,6 +221,9 @@ const UI08 dfnDataTypes[DFNTAG_COUNTOFTAGS] = DFN_STRING, // DFNTAG_SPAWNOBJ, DFN_STRING, // DFNTAG_SPAWNOBJLIST, DFN_NUMERIC, // DFNTAG_SPD, + DFN_NUMERIC, // DFNTAG_HEALTHBONUS, + DFN_NUMERIC, // DFNTAG_STAMINABONUS, + DFN_NUMERIC, // DFNTAG_MANABONUS, DFN_STRING, // DFNTAG_SPELLS, DFN_DOUBLENUMERIC, // DFNTAG_SPELLWEAVING, DFN_DOUBLENUMERIC, // DFNTAG_SPIRITSPEAK, @@ -223,12 +231,14 @@ const UI08 dfnDataTypes[DFNTAG_COUNTOFTAGS] = DFN_NUMERIC, // DFNTAG_SPLITCHANCE, DFN_DOUBLENUMERIC, // DFNTAG_STAMINA, DFN_DOUBLENUMERIC, // DFNTAG_STAMINAMAX, + DFN_NUMERIC, // DFNTAG_STAMINALEECH, DFN_DOUBLENUMERIC, // DFNTAG_STRENGTH, DFN_NUMERIC, // DFNTAG_STRADD, DFN_NUMERIC, // DFNTAG_STEALABLE, DFN_DOUBLENUMERIC, // DFNTAG_STEALING, DFN_DOUBLENUMERIC, // DFNTAG_STEALTH, DFN_DOUBLENUMERIC, // DFNTAG_SWORDSMANSHIP, + DFN_NUMERIC, // DFNTAG_SWINGSPEEDINCREASE, DFN_DOUBLENUMERIC, // DFNTAG_TACTICS, DFN_DOUBLENUMERIC, // DFNTAG_TAILORING, DFN_DOUBLENUMERIC, // DFNTAG_TAMING, @@ -285,6 +295,9 @@ const std::map strToDFNTag {"BLACKSMITHING"s, DFNTAG_BLACKSMITHING}, {"BOWCRAFT"s, DFNTAG_BOWCRAFT}, {"BUSHIDO"s, DFNTAG_BUSHIDO}, + {"HEALTHBONUS"s, DFNTAG_HEALTHBONUS}, + {"STAMINABONUS"s, DFNTAG_STAMINABONUS}, + {"MANABONUS"s, DFNTAG_MANABONUS}, {"CAMPING"s, DFNTAG_CAMPING}, {"CARPENTRY"s, DFNTAG_CARPENTRY}, {"CARTOGRAPHY"s, DFNTAG_CARTOGRAPHY}, @@ -323,6 +336,7 @@ const std::map strToDFNTag {"DYEABLE"s, DFNTAG_DYE}, {"DYEHAIR"s, DFNTAG_DYEHAIR}, {"DYEBEARD"s, DFNTAG_DYEBEARD}, + {"DEFENSECHANCE"s, DFNTAG_DEFENSECHANCE}, {"ELEMENTRESIST"s, DFNTAG_ELEMENTRESIST}, {"ERBONUS"s, DFNTAG_ERBONUS}, {"EMOTECOLOR"s, DFNTAG_EMOTECOLOUR}, @@ -368,10 +382,12 @@ const std::map strToDFNTag {"HEAT"s, DFNTAG_HEAT}, {"HERDING"s, DFNTAG_HERDING}, {"HIDAMAGE"s, DFNTAG_HIDAMAGE}, + {"HITCHANCE"s, DFNTAG_HITCHANCE}, {"HIDING"s, DFNTAG_HIDING}, {"HIRELING"s, DFNTAG_HIRELING}, {"HP"s, DFNTAG_HP}, {"HPMAX"s, DFNTAG_HPMAX}, + {"HEALTHLEECH"s, DFNTAG_HEALTHLEECH}, {"ID"s, DFNTAG_ID}, {"IMBUING"s, DFNTAG_IMBUING}, {"IN"s, DFNTAG_INTELLIGENCE}, @@ -391,6 +407,7 @@ const std::map strToDFNTag {"LAYER"s, DFNTAG_LAYER}, {"LIGHT"s, DFNTAG_LIGHT}, {"LIGHTNING"s, DFNTAG_LIGHTNING}, + {"LOWERSTATREQ"s, DFNTAG_LOWERSTATREQ}, {"LOCKPICKING"s, DFNTAG_LOCKPICKING}, {"LODAMAGE"s, DFNTAG_LODAMAGE}, {"LOOT"s, DFNTAG_LOOT}, @@ -401,6 +418,7 @@ const std::map strToDFNTag {"MAGICRESISTANCE"s, DFNTAG_MAGICRESISTANCE}, {"MANA"s, DFNTAG_MANA}, {"MANAMAX"s, DFNTAG_MANAMAX}, + {"MANALEECH"s, DFNTAG_MANALEECH}, {"MAXHP"s, DFNTAG_MAXHP}, {"MAXITEMS"s, DFNTAG_MAXITEMS}, {"MAXLOYALTY"s, DFNTAG_MAXLOYALTY}, @@ -477,6 +495,7 @@ const std::map strToDFNTag {"SPAWNOBJLIST"s, DFNTAG_SPAWNOBJLIST}, {"SPD"s, DFNTAG_SPD}, {"SPEED"s, DFNTAG_SPD}, + {"SWINGSPEEDINCREASE"s, DFNTAG_SWINGSPEEDINCREASE}, {"SPELLS"s, DFNTAG_SPELLS}, {"SPELLWEAVING"s, DFNTAG_SPELLWEAVING}, {"SPIRITSPEAK"s, DFNTAG_SPIRITSPEAK}, @@ -485,6 +504,7 @@ const std::map strToDFNTag {"ST"s, DFNTAG_STRENGTH}, {"STAMINA"s, DFNTAG_STAMINA}, {"STAMINAMAX"s, DFNTAG_STAMINAMAX}, + {"STAMINALEECH"s, DFNTAG_STAMINALEECH}, {"STR"s, DFNTAG_STRENGTH}, {"STRENGTH"s, DFNTAG_STRENGTH}, {"ST2"s, DFNTAG_STRADD}, diff --git a/source/ssection.h b/source/ssection.h index c652b9d3b..0c5bcfbbc 100644 --- a/source/ssection.h +++ b/source/ssection.h @@ -72,6 +72,7 @@ enum DFNTAGS DFNTAG_DISPELLABLE, DFNTAG_DISABLED, DFNTAG_DOORFLAG, + DFNTAG_DEFENSECHANCE, DFNTAG_DYE, DFNTAG_DYEBEARD, DFNTAG_DYEHAIR, @@ -119,10 +120,12 @@ enum DFNTAGS DFNTAG_HEAT, DFNTAG_HERDING, DFNTAG_HIDAMAGE, + DFNTAG_HITCHANCE, DFNTAG_HIDING, DFNTAG_HIRELING, DFNTAG_HP, DFNTAG_HPMAX, + DFNTAG_HEALTHLEECH, DFNTAG_ID, DFNTAG_IMBUING, DFNTAG_INTADD, @@ -138,6 +141,7 @@ enum DFNTAGS DFNTAG_LAYER, DFNTAG_LIGHT, DFNTAG_LIGHTNING, + DFNTAG_LOWERSTATREQ, DFNTAG_LOCKPICKING, DFNTAG_LODAMAGE, DFNTAG_LOOT, @@ -148,6 +152,7 @@ enum DFNTAGS DFNTAG_MAGICRESISTANCE, DFNTAG_MANA, DFNTAG_MANAMAX, + DFNTAG_MANALEECH, DFNTAG_MAXHP, DFNTAG_MAXITEMS, DFNTAG_MAXLOYALTY, @@ -222,7 +227,11 @@ enum DFNTAGS DFNTAG_SPATTACK, DFNTAG_SPAWNOBJ, DFNTAG_SPAWNOBJLIST, + DFNTAG_SWINGSPEEDINCREASE, DFNTAG_SPD, + DFNTAG_HEALTHBONUS, + DFNTAG_STAMINABONUS, + DFNTAG_MANABONUS, DFNTAG_SPELLS, DFNTAG_SPELLWEAVING, DFNTAG_SPIRITSPEAK, @@ -230,6 +239,7 @@ enum DFNTAGS DFNTAG_SPLITCHANCE, DFNTAG_STAMINA, DFNTAG_STAMINAMAX, + DFNTAG_STAMINALEECH, DFNTAG_STRENGTH, DFNTAG_STRADD, DFNTAG_STEALABLE,