diff --git a/_module/ifo/module.ifo.json b/_module/ifo/module.ifo.json index 50d8db37..98050ddf 100644 --- a/_module/ifo/module.ifo.json +++ b/_module/ifo/module.ifo.json @@ -1894,7 +1894,7 @@ }, "Mod_ID": { "type": "void", - "value": "Kx¢!’'±éÍ#¯1\u0026*¯»" + "value": "ÿÿÿÿ\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000«\u0000\u0000\u0000" }, "Mod_IsSaveGame": { "type": "byte", diff --git a/_module/ncs/3fireperround.ncs b/_module/ncs/3fireperround.ncs index 32f0ee0a..59c767a8 100644 Binary files a/_module/ncs/3fireperround.ncs and b/_module/ncs/3fireperround.ncs differ diff --git a/_module/ncs/3statsspawndoor.ncs b/_module/ncs/3statsspawndoor.ncs index ba197a5c..37083db1 100644 Binary files a/_module/ncs/3statsspawndoor.ncs and b/_module/ncs/3statsspawndoor.ncs differ diff --git a/_module/ncs/69_client_enter.ncs b/_module/ncs/69_client_enter.ncs index 3b46eecc..8bcd1c73 100644 Binary files a/_module/ncs/69_client_enter.ncs and b/_module/ncs/69_client_enter.ncs differ diff --git a/_module/ncs/69_client_exit.ncs b/_module/ncs/69_client_exit.ncs index e9b51f25..7e62ea36 100644 Binary files a/_module/ncs/69_client_exit.ncs and b/_module/ncs/69_client_exit.ncs differ diff --git a/_module/ncs/69_hen_combat.ncs b/_module/ncs/69_hen_combat.ncs index b99e3272..5d897a69 100644 Binary files a/_module/ncs/69_hen_combat.ncs and b/_module/ncs/69_hen_combat.ncs differ diff --git a/_module/ncs/69_hen_conv.ncs b/_module/ncs/69_hen_conv.ncs index 318c99a5..ceef1d73 100644 Binary files a/_module/ncs/69_hen_conv.ncs and b/_module/ncs/69_hen_conv.ncs differ diff --git a/_module/ncs/69_hen_death.ncs b/_module/ncs/69_hen_death.ncs index 13d03914..372dc694 100644 Binary files a/_module/ncs/69_hen_death.ncs and b/_module/ncs/69_hen_death.ncs differ diff --git a/_module/ncs/69_hen_percep.ncs b/_module/ncs/69_hen_percep.ncs index 1413ff50..9782a794 100644 Binary files a/_module/ncs/69_hen_percep.ncs and b/_module/ncs/69_hen_percep.ncs differ diff --git a/_module/ncs/69_hench_canlvl.ncs b/_module/ncs/69_hench_canlvl.ncs index 8f0116a4..1e3b778a 100644 Binary files a/_module/ncs/69_hench_canlvl.ncs and b/_module/ncs/69_hench_canlvl.ncs differ diff --git a/_module/ncs/69_hench_crtrsmn.ncs b/_module/ncs/69_hench_crtrsmn.ncs index edc39ec8..ef0f5128 100644 Binary files a/_module/ncs/69_hench_crtrsmn.ncs and b/_module/ncs/69_hench_crtrsmn.ncs differ diff --git a/_module/ncs/69_hench_crtruns.ncs b/_module/ncs/69_hench_crtruns.ncs index 9f3dd114..3eb87862 100644 Binary files a/_module/ncs/69_hench_crtruns.ncs and b/_module/ncs/69_hench_crtruns.ncs differ diff --git a/_module/ncs/69_hench_eqmelee.ncs b/_module/ncs/69_hench_eqmelee.ncs index 5fd46881..f0560ffc 100644 Binary files a/_module/ncs/69_hench_eqmelee.ncs and b/_module/ncs/69_hench_eqmelee.ncs differ diff --git a/_module/ncs/69_hench_fire.ncs b/_module/ncs/69_hench_fire.ncs index 8660b202..73452107 100644 Binary files a/_module/ncs/69_hench_fire.ncs and b/_module/ncs/69_hench_fire.ncs differ diff --git a/_module/ncs/69_hench_gomelee.ncs b/_module/ncs/69_hench_gomelee.ncs index 8e8c67b3..3b6c79cd 100644 Binary files a/_module/ncs/69_hench_gomelee.ncs and b/_module/ncs/69_hench_gomelee.ncs differ diff --git a/_module/ncs/69_hench_hire.ncs b/_module/ncs/69_hench_hire.ncs index f529c0e2..a67adb9e 100644 Binary files a/_module/ncs/69_hench_hire.ncs and b/_module/ncs/69_hench_hire.ncs differ diff --git a/_module/ncs/69_hench_identfy.ncs b/_module/ncs/69_hench_identfy.ncs index 2fe2b404..2ea70a30 100644 Binary files a/_module/ncs/69_hench_identfy.ncs and b/_module/ncs/69_hench_identfy.ncs differ diff --git a/_module/ncs/69_hench_level.ncs b/_module/ncs/69_hench_level.ncs index 301e4f0f..2bd20118 100644 Binary files a/_module/ncs/69_hench_level.ncs and b/_module/ncs/69_hench_level.ncs differ diff --git a/_module/ncs/69_hench_pickup.ncs b/_module/ncs/69_hench_pickup.ncs index 4ee66f97..ebe20efe 100644 Binary files a/_module/ncs/69_hench_pickup.ncs and b/_module/ncs/69_hench_pickup.ncs differ diff --git a/_module/ncs/69_hench_quit.ncs b/_module/ncs/69_hench_quit.ncs index cdc3b999..57514320 100644 Binary files a/_module/ncs/69_hench_quit.ncs and b/_module/ncs/69_hench_quit.ncs differ diff --git a/_module/ncs/69_hench_switch.ncs b/_module/ncs/69_hench_switch.ncs index 3c21004a..1844e584 100644 Binary files a/_module/ncs/69_hench_switch.ncs and b/_module/ncs/69_hench_switch.ncs differ diff --git a/_module/ncs/69_henchstr_exit.ncs b/_module/ncs/69_henchstr_exit.ncs index d6d2def2..b11e1727 100644 Binary files a/_module/ncs/69_henchstr_exit.ncs and b/_module/ncs/69_henchstr_exit.ncs differ diff --git a/_module/ncs/69_o0_death.ncs b/_module/ncs/69_o0_death.ncs index 31184a5a..624ed9d7 100644 Binary files a/_module/ncs/69_o0_death.ncs and b/_module/ncs/69_o0_death.ncs differ diff --git a/_module/ncs/69_o0_dying.ncs b/_module/ncs/69_o0_dying.ncs index bb283d59..2420b6cb 100644 Binary files a/_module/ncs/69_o0_dying.ncs and b/_module/ncs/69_o0_dying.ncs differ diff --git a/_module/ncs/69_o0_levelup.ncs b/_module/ncs/69_o0_levelup.ncs index 8384555e..5ba88ed1 100644 Binary files a/_module/ncs/69_o0_levelup.ncs and b/_module/ncs/69_o0_levelup.ncs differ diff --git a/_module/ncs/69_onactivate.ncs b/_module/ncs/69_onactivate.ncs index ac1d3720..e1b2009f 100644 Binary files a/_module/ncs/69_onactivate.ncs and b/_module/ncs/69_onactivate.ncs differ diff --git a/_module/ncs/agycrypt.ncs b/_module/ncs/agycrypt.ncs index 62e02edc..df070525 100644 Binary files a/_module/ncs/agycrypt.ncs and b/_module/ncs/agycrypt.ncs differ diff --git a/_module/ncs/agypyramid.ncs b/_module/ncs/agypyramid.ncs index f729221e..23d4f53f 100644 Binary files a/_module/ncs/agypyramid.ncs and b/_module/ncs/agypyramid.ncs differ diff --git a/_module/ncs/at_001.ncs b/_module/ncs/at_001.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_001.ncs and b/_module/ncs/at_001.ncs differ diff --git a/_module/ncs/at_002.ncs b/_module/ncs/at_002.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_002.ncs and b/_module/ncs/at_002.ncs differ diff --git a/_module/ncs/at_007.ncs b/_module/ncs/at_007.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_007.ncs and b/_module/ncs/at_007.ncs differ diff --git a/_module/ncs/at_008.ncs b/_module/ncs/at_008.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_008.ncs and b/_module/ncs/at_008.ncs differ diff --git a/_module/ncs/at_009.ncs b/_module/ncs/at_009.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_009.ncs and b/_module/ncs/at_009.ncs differ diff --git a/_module/ncs/at_010.ncs b/_module/ncs/at_010.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_010.ncs and b/_module/ncs/at_010.ncs differ diff --git a/_module/ncs/at_011.ncs b/_module/ncs/at_011.ncs index 546a2ace..6b04efcb 100644 Binary files a/_module/ncs/at_011.ncs and b/_module/ncs/at_011.ncs differ diff --git a/_module/ncs/at_013.ncs b/_module/ncs/at_013.ncs index 546a2ace..6b04efcb 100644 Binary files a/_module/ncs/at_013.ncs and b/_module/ncs/at_013.ncs differ diff --git a/_module/ncs/at_014.ncs b/_module/ncs/at_014.ncs index 12b9e302..9a2e0ec2 100644 Binary files a/_module/ncs/at_014.ncs and b/_module/ncs/at_014.ncs differ diff --git a/_module/ncs/at_017.ncs b/_module/ncs/at_017.ncs index fcd9dc9d..f5ec9a63 100644 Binary files a/_module/ncs/at_017.ncs and b/_module/ncs/at_017.ncs differ diff --git a/_module/ncs/at_019.ncs b/_module/ncs/at_019.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_019.ncs and b/_module/ncs/at_019.ncs differ diff --git a/_module/ncs/at_020.ncs b/_module/ncs/at_020.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_020.ncs and b/_module/ncs/at_020.ncs differ diff --git a/_module/ncs/at_024.ncs b/_module/ncs/at_024.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_024.ncs and b/_module/ncs/at_024.ncs differ diff --git a/_module/ncs/at_025.ncs b/_module/ncs/at_025.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_025.ncs and b/_module/ncs/at_025.ncs differ diff --git a/_module/ncs/at_026.ncs b/_module/ncs/at_026.ncs index c27c464b..05a3123f 100644 Binary files a/_module/ncs/at_026.ncs and b/_module/ncs/at_026.ncs differ diff --git a/_module/ncs/at_027.ncs b/_module/ncs/at_027.ncs index 5bac12c1..f9220812 100644 Binary files a/_module/ncs/at_027.ncs and b/_module/ncs/at_027.ncs differ diff --git a/_module/ncs/at_028.ncs b/_module/ncs/at_028.ncs index 40ed6360..c14a1e35 100644 Binary files a/_module/ncs/at_028.ncs and b/_module/ncs/at_028.ncs differ diff --git a/_module/ncs/at_031.ncs b/_module/ncs/at_031.ncs index 3be863a1..18b8cf7a 100644 Binary files a/_module/ncs/at_031.ncs and b/_module/ncs/at_031.ncs differ diff --git a/_module/ncs/at_032.ncs b/_module/ncs/at_032.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_032.ncs and b/_module/ncs/at_032.ncs differ diff --git a/_module/ncs/at_033.ncs b/_module/ncs/at_033.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_033.ncs and b/_module/ncs/at_033.ncs differ diff --git a/_module/ncs/at_034.ncs b/_module/ncs/at_034.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_034.ncs and b/_module/ncs/at_034.ncs differ diff --git a/_module/ncs/at_035.ncs b/_module/ncs/at_035.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_035.ncs and b/_module/ncs/at_035.ncs differ diff --git a/_module/ncs/at_036.ncs b/_module/ncs/at_036.ncs index 81e063b6..acf861df 100644 Binary files a/_module/ncs/at_036.ncs and b/_module/ncs/at_036.ncs differ diff --git a/_module/ncs/at_037.ncs b/_module/ncs/at_037.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_037.ncs and b/_module/ncs/at_037.ncs differ diff --git a/_module/ncs/at_038.ncs b/_module/ncs/at_038.ncs index 4ec4f420..854078c9 100644 Binary files a/_module/ncs/at_038.ncs and b/_module/ncs/at_038.ncs differ diff --git a/_module/ncs/at_043.ncs b/_module/ncs/at_043.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_043.ncs and b/_module/ncs/at_043.ncs differ diff --git a/_module/ncs/at_044.ncs b/_module/ncs/at_044.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_044.ncs and b/_module/ncs/at_044.ncs differ diff --git a/_module/ncs/at_045.ncs b/_module/ncs/at_045.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_045.ncs and b/_module/ncs/at_045.ncs differ diff --git a/_module/ncs/at_046.ncs b/_module/ncs/at_046.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_046.ncs and b/_module/ncs/at_046.ncs differ diff --git a/_module/ncs/at_048.ncs b/_module/ncs/at_048.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_048.ncs and b/_module/ncs/at_048.ncs differ diff --git a/_module/ncs/at_049.ncs b/_module/ncs/at_049.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_049.ncs and b/_module/ncs/at_049.ncs differ diff --git a/_module/ncs/at_051.ncs b/_module/ncs/at_051.ncs index 3d720c46..94f0c6ec 100644 Binary files a/_module/ncs/at_051.ncs and b/_module/ncs/at_051.ncs differ diff --git a/_module/ncs/at_052.ncs b/_module/ncs/at_052.ncs index 976054d8..946600df 100644 Binary files a/_module/ncs/at_052.ncs and b/_module/ncs/at_052.ncs differ diff --git a/_module/ncs/at_053.ncs b/_module/ncs/at_053.ncs index 54849bfd..d4c51691 100644 Binary files a/_module/ncs/at_053.ncs and b/_module/ncs/at_053.ncs differ diff --git a/_module/ncs/at_054.ncs b/_module/ncs/at_054.ncs index 367d9fc2..f8d20549 100644 Binary files a/_module/ncs/at_054.ncs and b/_module/ncs/at_054.ncs differ diff --git a/_module/ncs/at_055.ncs b/_module/ncs/at_055.ncs index 31756428..e6e1feeb 100644 Binary files a/_module/ncs/at_055.ncs and b/_module/ncs/at_055.ncs differ diff --git a/_module/ncs/at_056.ncs b/_module/ncs/at_056.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_056.ncs and b/_module/ncs/at_056.ncs differ diff --git a/_module/ncs/at_057.ncs b/_module/ncs/at_057.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_057.ncs and b/_module/ncs/at_057.ncs differ diff --git a/_module/ncs/at_058.ncs b/_module/ncs/at_058.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_058.ncs and b/_module/ncs/at_058.ncs differ diff --git a/_module/ncs/at_059.ncs b/_module/ncs/at_059.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_059.ncs and b/_module/ncs/at_059.ncs differ diff --git a/_module/ncs/at_060.ncs b/_module/ncs/at_060.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_060.ncs and b/_module/ncs/at_060.ncs differ diff --git a/_module/ncs/at_061.ncs b/_module/ncs/at_061.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_061.ncs and b/_module/ncs/at_061.ncs differ diff --git a/_module/ncs/at_062.ncs b/_module/ncs/at_062.ncs index 08b8626a..48bb2ff5 100644 Binary files a/_module/ncs/at_062.ncs and b/_module/ncs/at_062.ncs differ diff --git a/_module/ncs/at_063.ncs b/_module/ncs/at_063.ncs index 486729a8..78dd18d0 100644 Binary files a/_module/ncs/at_063.ncs and b/_module/ncs/at_063.ncs differ diff --git a/_module/ncs/at_064.ncs b/_module/ncs/at_064.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_064.ncs and b/_module/ncs/at_064.ncs differ diff --git a/_module/ncs/at_066.ncs b/_module/ncs/at_066.ncs index a0ca2be6..595fa758 100644 Binary files a/_module/ncs/at_066.ncs and b/_module/ncs/at_066.ncs differ diff --git a/_module/ncs/at_068.ncs b/_module/ncs/at_068.ncs index 7951be48..d845ef94 100644 Binary files a/_module/ncs/at_068.ncs and b/_module/ncs/at_068.ncs differ diff --git a/_module/ncs/at_069.ncs b/_module/ncs/at_069.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_069.ncs and b/_module/ncs/at_069.ncs differ diff --git a/_module/ncs/at_070.ncs b/_module/ncs/at_070.ncs index 7951be48..d845ef94 100644 Binary files a/_module/ncs/at_070.ncs and b/_module/ncs/at_070.ncs differ diff --git a/_module/ncs/at_071.ncs b/_module/ncs/at_071.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_071.ncs and b/_module/ncs/at_071.ncs differ diff --git a/_module/ncs/at_072.ncs b/_module/ncs/at_072.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_072.ncs and b/_module/ncs/at_072.ncs differ diff --git a/_module/ncs/at_073.ncs b/_module/ncs/at_073.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_073.ncs and b/_module/ncs/at_073.ncs differ diff --git a/_module/ncs/at_074.ncs b/_module/ncs/at_074.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_074.ncs and b/_module/ncs/at_074.ncs differ diff --git a/_module/ncs/at_076.ncs b/_module/ncs/at_076.ncs index 58344bd6..22cf8c22 100644 Binary files a/_module/ncs/at_076.ncs and b/_module/ncs/at_076.ncs differ diff --git a/_module/ncs/at_077.ncs b/_module/ncs/at_077.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_077.ncs and b/_module/ncs/at_077.ncs differ diff --git a/_module/ncs/at_079.ncs b/_module/ncs/at_079.ncs index 276d9120..fa1fab31 100644 Binary files a/_module/ncs/at_079.ncs and b/_module/ncs/at_079.ncs differ diff --git a/_module/ncs/at_080.ncs b/_module/ncs/at_080.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_080.ncs and b/_module/ncs/at_080.ncs differ diff --git a/_module/ncs/at_081.ncs b/_module/ncs/at_081.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_081.ncs and b/_module/ncs/at_081.ncs differ diff --git a/_module/ncs/at_082.ncs b/_module/ncs/at_082.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_082.ncs and b/_module/ncs/at_082.ncs differ diff --git a/_module/ncs/at_084.ncs b/_module/ncs/at_084.ncs index 221085a4..557af72c 100644 Binary files a/_module/ncs/at_084.ncs and b/_module/ncs/at_084.ncs differ diff --git a/_module/ncs/at_086.ncs b/_module/ncs/at_086.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_086.ncs and b/_module/ncs/at_086.ncs differ diff --git a/_module/ncs/at_087.ncs b/_module/ncs/at_087.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_087.ncs and b/_module/ncs/at_087.ncs differ diff --git a/_module/ncs/at_088.ncs b/_module/ncs/at_088.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_088.ncs and b/_module/ncs/at_088.ncs differ diff --git a/_module/ncs/at_089.ncs b/_module/ncs/at_089.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_089.ncs and b/_module/ncs/at_089.ncs differ diff --git a/_module/ncs/at_090.ncs b/_module/ncs/at_090.ncs index c3c9cf6d..e51101b8 100644 Binary files a/_module/ncs/at_090.ncs and b/_module/ncs/at_090.ncs differ diff --git a/_module/ncs/at_091.ncs b/_module/ncs/at_091.ncs index ed6bdfe6..b8b39a44 100644 Binary files a/_module/ncs/at_091.ncs and b/_module/ncs/at_091.ncs differ diff --git a/_module/ncs/at_092.ncs b/_module/ncs/at_092.ncs index e08e0265..d83f0e91 100644 Binary files a/_module/ncs/at_092.ncs and b/_module/ncs/at_092.ncs differ diff --git a/_module/ncs/at_094.ncs b/_module/ncs/at_094.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_094.ncs and b/_module/ncs/at_094.ncs differ diff --git a/_module/ncs/at_095.ncs b/_module/ncs/at_095.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_095.ncs and b/_module/ncs/at_095.ncs differ diff --git a/_module/ncs/at_096.ncs b/_module/ncs/at_096.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_096.ncs and b/_module/ncs/at_096.ncs differ diff --git a/_module/ncs/at_097.ncs b/_module/ncs/at_097.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_097.ncs and b/_module/ncs/at_097.ncs differ diff --git a/_module/ncs/at_101.ncs b/_module/ncs/at_101.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_101.ncs and b/_module/ncs/at_101.ncs differ diff --git a/_module/ncs/at_104.ncs b/_module/ncs/at_104.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_104.ncs and b/_module/ncs/at_104.ncs differ diff --git a/_module/ncs/at_105.ncs b/_module/ncs/at_105.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_105.ncs and b/_module/ncs/at_105.ncs differ diff --git a/_module/ncs/at_107.ncs b/_module/ncs/at_107.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_107.ncs and b/_module/ncs/at_107.ncs differ diff --git a/_module/ncs/at_108.ncs b/_module/ncs/at_108.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_108.ncs and b/_module/ncs/at_108.ncs differ diff --git a/_module/ncs/at_110.ncs b/_module/ncs/at_110.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_110.ncs and b/_module/ncs/at_110.ncs differ diff --git a/_module/ncs/at_111.ncs b/_module/ncs/at_111.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_111.ncs and b/_module/ncs/at_111.ncs differ diff --git a/_module/ncs/at_112.ncs b/_module/ncs/at_112.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_112.ncs and b/_module/ncs/at_112.ncs differ diff --git a/_module/ncs/at_113.ncs b/_module/ncs/at_113.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_113.ncs and b/_module/ncs/at_113.ncs differ diff --git a/_module/ncs/at_114.ncs b/_module/ncs/at_114.ncs index 63922d08..eb6e2492 100644 Binary files a/_module/ncs/at_114.ncs and b/_module/ncs/at_114.ncs differ diff --git a/_module/ncs/at_115.ncs b/_module/ncs/at_115.ncs index 14e20f49..dfcfdead 100644 Binary files a/_module/ncs/at_115.ncs and b/_module/ncs/at_115.ncs differ diff --git a/_module/ncs/at_116.ncs b/_module/ncs/at_116.ncs index fdbb7566..a5706aba 100644 Binary files a/_module/ncs/at_116.ncs and b/_module/ncs/at_116.ncs differ diff --git a/_module/ncs/at_117.ncs b/_module/ncs/at_117.ncs index fdbb7566..a5706aba 100644 Binary files a/_module/ncs/at_117.ncs and b/_module/ncs/at_117.ncs differ diff --git a/_module/ncs/at_118.ncs b/_module/ncs/at_118.ncs index 8e8dc4f2..b4e9e9e8 100644 Binary files a/_module/ncs/at_118.ncs and b/_module/ncs/at_118.ncs differ diff --git a/_module/ncs/at_119.ncs b/_module/ncs/at_119.ncs index aaf24865..78f46451 100644 Binary files a/_module/ncs/at_119.ncs and b/_module/ncs/at_119.ncs differ diff --git a/_module/ncs/at_120.ncs b/_module/ncs/at_120.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_120.ncs and b/_module/ncs/at_120.ncs differ diff --git a/_module/ncs/at_121.ncs b/_module/ncs/at_121.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_121.ncs and b/_module/ncs/at_121.ncs differ diff --git a/_module/ncs/at_122.ncs b/_module/ncs/at_122.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_122.ncs and b/_module/ncs/at_122.ncs differ diff --git a/_module/ncs/at_123.ncs b/_module/ncs/at_123.ncs index cbb03e59..48dce70a 100644 Binary files a/_module/ncs/at_123.ncs and b/_module/ncs/at_123.ncs differ diff --git a/_module/ncs/at_125.ncs b/_module/ncs/at_125.ncs index 8fcc1ec6..1b87cbd8 100644 Binary files a/_module/ncs/at_125.ncs and b/_module/ncs/at_125.ncs differ diff --git a/_module/ncs/at_126.ncs b/_module/ncs/at_126.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_126.ncs and b/_module/ncs/at_126.ncs differ diff --git a/_module/ncs/at_127.ncs b/_module/ncs/at_127.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_127.ncs and b/_module/ncs/at_127.ncs differ diff --git a/_module/ncs/at_129.ncs b/_module/ncs/at_129.ncs index 5593113e..0b2a025a 100644 Binary files a/_module/ncs/at_129.ncs and b/_module/ncs/at_129.ncs differ diff --git a/_module/ncs/at_130.ncs b/_module/ncs/at_130.ncs index 69259ab0..462e22f6 100644 Binary files a/_module/ncs/at_130.ncs and b/_module/ncs/at_130.ncs differ diff --git a/_module/ncs/at_131.ncs b/_module/ncs/at_131.ncs index 85573c1a..1ab87724 100644 Binary files a/_module/ncs/at_131.ncs and b/_module/ncs/at_131.ncs differ diff --git a/_module/ncs/at_132.ncs b/_module/ncs/at_132.ncs index 5d0953b2..8cd8e620 100644 Binary files a/_module/ncs/at_132.ncs and b/_module/ncs/at_132.ncs differ diff --git a/_module/ncs/at_133.ncs b/_module/ncs/at_133.ncs index 3f1d8dfd..7096bce8 100644 Binary files a/_module/ncs/at_133.ncs and b/_module/ncs/at_133.ncs differ diff --git a/_module/ncs/at_134.ncs b/_module/ncs/at_134.ncs index 20c91e6e..9e72c0bf 100644 Binary files a/_module/ncs/at_134.ncs and b/_module/ncs/at_134.ncs differ diff --git a/_module/ncs/at_135.ncs b/_module/ncs/at_135.ncs index d0b368cf..c3a40ec3 100644 Binary files a/_module/ncs/at_135.ncs and b/_module/ncs/at_135.ncs differ diff --git a/_module/ncs/at_136.ncs b/_module/ncs/at_136.ncs index 9eef059e..9368551b 100644 Binary files a/_module/ncs/at_136.ncs and b/_module/ncs/at_136.ncs differ diff --git a/_module/ncs/at_137.ncs b/_module/ncs/at_137.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_137.ncs and b/_module/ncs/at_137.ncs differ diff --git a/_module/ncs/at_139.ncs b/_module/ncs/at_139.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_139.ncs and b/_module/ncs/at_139.ncs differ diff --git a/_module/ncs/at_140.ncs b/_module/ncs/at_140.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_140.ncs and b/_module/ncs/at_140.ncs differ diff --git a/_module/ncs/at_141.ncs b/_module/ncs/at_141.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_141.ncs and b/_module/ncs/at_141.ncs differ diff --git a/_module/ncs/at_142.ncs b/_module/ncs/at_142.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_142.ncs and b/_module/ncs/at_142.ncs differ diff --git a/_module/ncs/at_148.ncs b/_module/ncs/at_148.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_148.ncs and b/_module/ncs/at_148.ncs differ diff --git a/_module/ncs/at_150.ncs b/_module/ncs/at_150.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_150.ncs and b/_module/ncs/at_150.ncs differ diff --git a/_module/ncs/at_152.ncs b/_module/ncs/at_152.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_152.ncs and b/_module/ncs/at_152.ncs differ diff --git a/_module/ncs/at_155.ncs b/_module/ncs/at_155.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_155.ncs and b/_module/ncs/at_155.ncs differ diff --git a/_module/ncs/at_156.ncs b/_module/ncs/at_156.ncs index 7e5e6ba1..e3c03a0f 100644 Binary files a/_module/ncs/at_156.ncs and b/_module/ncs/at_156.ncs differ diff --git a/_module/ncs/at_157.ncs b/_module/ncs/at_157.ncs index c46fb040..3141bcb4 100644 Binary files a/_module/ncs/at_157.ncs and b/_module/ncs/at_157.ncs differ diff --git a/_module/ncs/at_161.ncs b/_module/ncs/at_161.ncs index 8e0623ce..b86437ab 100644 Binary files a/_module/ncs/at_161.ncs and b/_module/ncs/at_161.ncs differ diff --git a/_module/ncs/at_167.ncs b/_module/ncs/at_167.ncs index fd0f138f..7896ce59 100644 Binary files a/_module/ncs/at_167.ncs and b/_module/ncs/at_167.ncs differ diff --git a/_module/ncs/at_168.ncs b/_module/ncs/at_168.ncs index fd0f138f..7896ce59 100644 Binary files a/_module/ncs/at_168.ncs and b/_module/ncs/at_168.ncs differ diff --git a/_module/ncs/at_169.ncs b/_module/ncs/at_169.ncs index fd0f138f..7896ce59 100644 Binary files a/_module/ncs/at_169.ncs and b/_module/ncs/at_169.ncs differ diff --git a/_module/ncs/at_170.ncs b/_module/ncs/at_170.ncs index 0f49ccf9..f19d676b 100644 Binary files a/_module/ncs/at_170.ncs and b/_module/ncs/at_170.ncs differ diff --git a/_module/ncs/at_171.ncs b/_module/ncs/at_171.ncs index 0f49ccf9..f19d676b 100644 Binary files a/_module/ncs/at_171.ncs and b/_module/ncs/at_171.ncs differ diff --git a/_module/ncs/at_173.ncs b/_module/ncs/at_173.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_173.ncs and b/_module/ncs/at_173.ncs differ diff --git a/_module/ncs/at_174.ncs b/_module/ncs/at_174.ncs index 4939098c..11871cc6 100644 Binary files a/_module/ncs/at_174.ncs and b/_module/ncs/at_174.ncs differ diff --git a/_module/ncs/at_180.ncs b/_module/ncs/at_180.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_180.ncs and b/_module/ncs/at_180.ncs differ diff --git a/_module/ncs/at_181.ncs b/_module/ncs/at_181.ncs index 03896ff1..ef5ff67e 100644 Binary files a/_module/ncs/at_181.ncs and b/_module/ncs/at_181.ncs differ diff --git a/_module/ncs/at_182.ncs b/_module/ncs/at_182.ncs index 03896ff1..ef5ff67e 100644 Binary files a/_module/ncs/at_182.ncs and b/_module/ncs/at_182.ncs differ diff --git a/_module/ncs/at_185.ncs b/_module/ncs/at_185.ncs index 913511ea..0c3488a6 100644 Binary files a/_module/ncs/at_185.ncs and b/_module/ncs/at_185.ncs differ diff --git a/_module/ncs/at_187.ncs b/_module/ncs/at_187.ncs index 241ac0bc..80bd7406 100644 Binary files a/_module/ncs/at_187.ncs and b/_module/ncs/at_187.ncs differ diff --git a/_module/ncs/at_193.ncs b/_module/ncs/at_193.ncs index 1294be20..2be174ce 100644 Binary files a/_module/ncs/at_193.ncs and b/_module/ncs/at_193.ncs differ diff --git a/_module/ncs/at_196.ncs b/_module/ncs/at_196.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_196.ncs and b/_module/ncs/at_196.ncs differ diff --git a/_module/ncs/at_198.ncs b/_module/ncs/at_198.ncs index 55e13cb8..2976dc4b 100644 Binary files a/_module/ncs/at_198.ncs and b/_module/ncs/at_198.ncs differ diff --git a/_module/ncs/at_199.ncs b/_module/ncs/at_199.ncs index 611b3f65..2911b3c6 100644 Binary files a/_module/ncs/at_199.ncs and b/_module/ncs/at_199.ncs differ diff --git a/_module/ncs/at_200.ncs b/_module/ncs/at_200.ncs index 2f977ac2..6e46d9e6 100644 Binary files a/_module/ncs/at_200.ncs and b/_module/ncs/at_200.ncs differ diff --git a/_module/ncs/at_202.ncs b/_module/ncs/at_202.ncs index b14d617c..cf977eb7 100644 Binary files a/_module/ncs/at_202.ncs and b/_module/ncs/at_202.ncs differ diff --git a/_module/ncs/at_203.ncs b/_module/ncs/at_203.ncs index ba032803..f140b180 100644 Binary files a/_module/ncs/at_203.ncs and b/_module/ncs/at_203.ncs differ diff --git a/_module/ncs/at_204.ncs b/_module/ncs/at_204.ncs index 7e5e6ba1..e3c03a0f 100644 Binary files a/_module/ncs/at_204.ncs and b/_module/ncs/at_204.ncs differ diff --git a/_module/ncs/at_205.ncs b/_module/ncs/at_205.ncs index 955839fe..11eff85e 100644 Binary files a/_module/ncs/at_205.ncs and b/_module/ncs/at_205.ncs differ diff --git a/_module/ncs/at_206.ncs b/_module/ncs/at_206.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_206.ncs and b/_module/ncs/at_206.ncs differ diff --git a/_module/ncs/at_207.ncs b/_module/ncs/at_207.ncs index 45585574..73d4f29d 100644 Binary files a/_module/ncs/at_207.ncs and b/_module/ncs/at_207.ncs differ diff --git a/_module/ncs/at_211.ncs b/_module/ncs/at_211.ncs index 3881dc9e..82bea73a 100644 Binary files a/_module/ncs/at_211.ncs and b/_module/ncs/at_211.ncs differ diff --git a/_module/ncs/at_212.ncs b/_module/ncs/at_212.ncs index d53c79fb..ef8470e1 100644 Binary files a/_module/ncs/at_212.ncs and b/_module/ncs/at_212.ncs differ diff --git a/_module/ncs/at_213.ncs b/_module/ncs/at_213.ncs index 49eeb272..5a3fa2b4 100644 Binary files a/_module/ncs/at_213.ncs and b/_module/ncs/at_213.ncs differ diff --git a/_module/ncs/at_217.ncs b/_module/ncs/at_217.ncs index 4b87b7e6..3598ef73 100644 Binary files a/_module/ncs/at_217.ncs and b/_module/ncs/at_217.ncs differ diff --git a/_module/ncs/at_218.ncs b/_module/ncs/at_218.ncs index cffc9d18..e7a51295 100644 Binary files a/_module/ncs/at_218.ncs and b/_module/ncs/at_218.ncs differ diff --git a/_module/ncs/at_219.ncs b/_module/ncs/at_219.ncs index fe5cea51..23e3dd3a 100644 Binary files a/_module/ncs/at_219.ncs and b/_module/ncs/at_219.ncs differ diff --git a/_module/ncs/at_222.ncs b/_module/ncs/at_222.ncs index 4d23ab57..ad5f73a5 100644 Binary files a/_module/ncs/at_222.ncs and b/_module/ncs/at_222.ncs differ diff --git a/_module/ncs/at_223.ncs b/_module/ncs/at_223.ncs index eaf1e99c..6190d014 100644 Binary files a/_module/ncs/at_223.ncs and b/_module/ncs/at_223.ncs differ diff --git a/_module/ncs/at_224.ncs b/_module/ncs/at_224.ncs index ed2f019b..17afd4fe 100644 Binary files a/_module/ncs/at_224.ncs and b/_module/ncs/at_224.ncs differ diff --git a/_module/ncs/at_225.ncs b/_module/ncs/at_225.ncs index ae439226..094fa9c8 100644 Binary files a/_module/ncs/at_225.ncs and b/_module/ncs/at_225.ncs differ diff --git a/_module/ncs/at_226.ncs b/_module/ncs/at_226.ncs index 3155c767..29ee860b 100644 Binary files a/_module/ncs/at_226.ncs and b/_module/ncs/at_226.ncs differ diff --git a/_module/ncs/at_227.ncs b/_module/ncs/at_227.ncs index a4fbce56..b5adf4fa 100644 Binary files a/_module/ncs/at_227.ncs and b/_module/ncs/at_227.ncs differ diff --git a/_module/ncs/at_228.ncs b/_module/ncs/at_228.ncs index b7752ee7..7c24ba64 100644 Binary files a/_module/ncs/at_228.ncs and b/_module/ncs/at_228.ncs differ diff --git a/_module/ncs/at_229.ncs b/_module/ncs/at_229.ncs index 7aa4768f..8488d253 100644 Binary files a/_module/ncs/at_229.ncs and b/_module/ncs/at_229.ncs differ diff --git a/_module/ncs/at_231.ncs b/_module/ncs/at_231.ncs index 461dd29d..7a3b7280 100644 Binary files a/_module/ncs/at_231.ncs and b/_module/ncs/at_231.ncs differ diff --git a/_module/ncs/at_232.ncs b/_module/ncs/at_232.ncs index 978667b6..98087b94 100644 Binary files a/_module/ncs/at_232.ncs and b/_module/ncs/at_232.ncs differ diff --git a/_module/ncs/at_233.ncs b/_module/ncs/at_233.ncs index e6d09529..3a24b5ef 100644 Binary files a/_module/ncs/at_233.ncs and b/_module/ncs/at_233.ncs differ diff --git a/_module/ncs/at_234.ncs b/_module/ncs/at_234.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_234.ncs and b/_module/ncs/at_234.ncs differ diff --git a/_module/ncs/at_235.ncs b/_module/ncs/at_235.ncs index 3d0e3e49..f507d30c 100644 Binary files a/_module/ncs/at_235.ncs and b/_module/ncs/at_235.ncs differ diff --git a/_module/ncs/at_236.ncs b/_module/ncs/at_236.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_236.ncs and b/_module/ncs/at_236.ncs differ diff --git a/_module/ncs/at_237.ncs b/_module/ncs/at_237.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_237.ncs and b/_module/ncs/at_237.ncs differ diff --git a/_module/ncs/at_238.ncs b/_module/ncs/at_238.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_238.ncs and b/_module/ncs/at_238.ncs differ diff --git a/_module/ncs/at_239.ncs b/_module/ncs/at_239.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_239.ncs and b/_module/ncs/at_239.ncs differ diff --git a/_module/ncs/at_240.ncs b/_module/ncs/at_240.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_240.ncs and b/_module/ncs/at_240.ncs differ diff --git a/_module/ncs/at_241.ncs b/_module/ncs/at_241.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_241.ncs and b/_module/ncs/at_241.ncs differ diff --git a/_module/ncs/at_243.ncs b/_module/ncs/at_243.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_243.ncs and b/_module/ncs/at_243.ncs differ diff --git a/_module/ncs/at_244.ncs b/_module/ncs/at_244.ncs index 3ec9704b..78172b90 100644 Binary files a/_module/ncs/at_244.ncs and b/_module/ncs/at_244.ncs differ diff --git a/_module/ncs/at_245.ncs b/_module/ncs/at_245.ncs index 21235a91..df96007d 100644 Binary files a/_module/ncs/at_245.ncs and b/_module/ncs/at_245.ncs differ diff --git a/_module/ncs/at_246.ncs b/_module/ncs/at_246.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_246.ncs and b/_module/ncs/at_246.ncs differ diff --git a/_module/ncs/at_247.ncs b/_module/ncs/at_247.ncs index f4c77888..d2bd8a5b 100644 Binary files a/_module/ncs/at_247.ncs and b/_module/ncs/at_247.ncs differ diff --git a/_module/ncs/at_248.ncs b/_module/ncs/at_248.ncs index 88df8d86..765f5816 100644 Binary files a/_module/ncs/at_248.ncs and b/_module/ncs/at_248.ncs differ diff --git a/_module/ncs/at_249.ncs b/_module/ncs/at_249.ncs index e12b870c..8405a551 100644 Binary files a/_module/ncs/at_249.ncs and b/_module/ncs/at_249.ncs differ diff --git a/_module/ncs/at_250.ncs b/_module/ncs/at_250.ncs index e12b870c..8405a551 100644 Binary files a/_module/ncs/at_250.ncs and b/_module/ncs/at_250.ncs differ diff --git a/_module/ncs/at_256.ncs b/_module/ncs/at_256.ncs index 934990e1..9f513a91 100644 Binary files a/_module/ncs/at_256.ncs and b/_module/ncs/at_256.ncs differ diff --git a/_module/ncs/at_257.ncs b/_module/ncs/at_257.ncs index 934990e1..9f513a91 100644 Binary files a/_module/ncs/at_257.ncs and b/_module/ncs/at_257.ncs differ diff --git a/_module/ncs/at_258.ncs b/_module/ncs/at_258.ncs index b398410b..2f71dda4 100644 Binary files a/_module/ncs/at_258.ncs and b/_module/ncs/at_258.ncs differ diff --git a/_module/ncs/at_259.ncs b/_module/ncs/at_259.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_259.ncs and b/_module/ncs/at_259.ncs differ diff --git a/_module/ncs/at_260.ncs b/_module/ncs/at_260.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_260.ncs and b/_module/ncs/at_260.ncs differ diff --git a/_module/ncs/at_262.ncs b/_module/ncs/at_262.ncs index aafb33d5..8b56d8b8 100644 Binary files a/_module/ncs/at_262.ncs and b/_module/ncs/at_262.ncs differ diff --git a/_module/ncs/at_266.ncs b/_module/ncs/at_266.ncs index d9d3fe38..96963885 100644 Binary files a/_module/ncs/at_266.ncs and b/_module/ncs/at_266.ncs differ diff --git a/_module/ncs/at_268.ncs b/_module/ncs/at_268.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/at_268.ncs and b/_module/ncs/at_268.ncs differ diff --git a/_module/ncs/at_273.ncs b/_module/ncs/at_273.ncs index 8df72b65..6159f69a 100644 Binary files a/_module/ncs/at_273.ncs and b/_module/ncs/at_273.ncs differ diff --git a/_module/ncs/attackpc.ncs b/_module/ncs/attackpc.ncs index 0472b03a..9867bb32 100644 Binary files a/_module/ncs/attackpc.ncs and b/_module/ncs/attackpc.ncs differ diff --git a/_module/ncs/attpcnofact.ncs b/_module/ncs/attpcnofact.ncs index f48da487..7f1fa6ab 100644 Binary files a/_module/ncs/attpcnofact.ncs and b/_module/ncs/attpcnofact.ncs differ diff --git a/_module/ncs/belgos.ncs b/_module/ncs/belgos.ncs index b0bcde9c..bbf80a84 100644 Binary files a/_module/ncs/belgos.ncs and b/_module/ncs/belgos.ncs differ diff --git a/_module/ncs/ceonopen.ncs b/_module/ncs/ceonopen.ncs index b718e5c7..b09a8b75 100644 Binary files a/_module/ncs/ceonopen.ncs and b/_module/ncs/ceonopen.ncs differ diff --git a/_module/ncs/convevil10.ncs b/_module/ncs/convevil10.ncs index ba4e5eff..4f428f04 100644 Binary files a/_module/ncs/convevil10.ncs and b/_module/ncs/convevil10.ncs differ diff --git a/_module/ncs/convgood1.ncs b/_module/ncs/convgood1.ncs index ad499d41..33886d46 100644 Binary files a/_module/ncs/convgood1.ncs and b/_module/ncs/convgood1.ncs differ diff --git a/_module/ncs/convgood10.ncs b/_module/ncs/convgood10.ncs index 4a07e50d..c9acda09 100644 Binary files a/_module/ncs/convgood10.ncs and b/_module/ncs/convgood10.ncs differ diff --git a/_module/ncs/convgood100.ncs b/_module/ncs/convgood100.ncs index 8928bc57..1ea6ec9c 100644 Binary files a/_module/ncs/convgood100.ncs and b/_module/ncs/convgood100.ncs differ diff --git a/_module/ncs/cryptchaos.ncs b/_module/ncs/cryptchaos.ncs index 591e47f3..a04dd07b 100644 Binary files a/_module/ncs/cryptchaos.ncs and b/_module/ncs/cryptchaos.ncs differ diff --git a/_module/ncs/cryptevil.ncs b/_module/ncs/cryptevil.ncs index 7f5f5a86..2e4b4bb9 100644 Binary files a/_module/ncs/cryptevil.ncs and b/_module/ncs/cryptevil.ncs differ diff --git a/_module/ncs/demilichcomes.ncs b/_module/ncs/demilichcomes.ncs index c49c2dca..454d75ef 100644 Binary files a/_module/ncs/demilichcomes.ncs and b/_module/ncs/demilichcomes.ncs differ diff --git a/_module/ncs/doplchange.ncs b/_module/ncs/doplchange.ncs index eeb25d1f..9377b922 100644 Binary files a/_module/ncs/doplchange.ncs and b/_module/ncs/doplchange.ncs differ diff --git a/_module/ncs/drownitem.ncs b/_module/ncs/drownitem.ncs new file mode 100644 index 00000000..524dd4e9 Binary files /dev/null and b/_module/ncs/drownitem.ncs differ diff --git a/_module/ncs/entranhumani.ncs b/_module/ncs/entranhumani.ncs index 69e7e30e..e0974f29 100644 Binary files a/_module/ncs/entranhumani.ncs and b/_module/ncs/entranhumani.ncs differ diff --git a/_module/ncs/fireonheartbeat.ncs b/_module/ncs/fireonheartbeat.ncs index 32f0ee0a..59c767a8 100644 Binary files a/_module/ncs/fireonheartbeat.ncs and b/_module/ncs/fireonheartbeat.ncs differ diff --git a/_module/ncs/g_fireworks.ncs b/_module/ncs/g_fireworks.ncs index 3b1e6c51..835a514a 100644 Binary files a/_module/ncs/g_fireworks.ncs and b/_module/ncs/g_fireworks.ncs differ diff --git a/_module/ncs/g_fireworksfinal.ncs b/_module/ncs/g_fireworksfinal.ncs index 65d6629b..ec58f9b1 100644 Binary files a/_module/ncs/g_fireworksfinal.ncs and b/_module/ncs/g_fireworksfinal.ncs differ diff --git a/_module/ncs/g_larfireworks.ncs b/_module/ncs/g_larfireworks.ncs index 3827a0e0..3b4c86cf 100644 Binary files a/_module/ncs/g_larfireworks.ncs and b/_module/ncs/g_larfireworks.ncs differ diff --git a/_module/ncs/g_medfireworks.ncs b/_module/ncs/g_medfireworks.ncs index b6144b8a..b3b88a7c 100644 Binary files a/_module/ncs/g_medfireworks.ncs and b/_module/ncs/g_medfireworks.ncs differ diff --git a/_module/ncs/g_missile.ncs b/_module/ncs/g_missile.ncs index 36f3e77e..08175f67 100644 Binary files a/_module/ncs/g_missile.ncs and b/_module/ncs/g_missile.ncs differ diff --git a/_module/ncs/g_smallfirework2.ncs b/_module/ncs/g_smallfirework2.ncs index 377989ba..c66adf12 100644 Binary files a/_module/ncs/g_smallfirework2.ncs and b/_module/ncs/g_smallfirework2.ncs differ diff --git a/_module/ncs/g_smallfireworks.ncs b/_module/ncs/g_smallfireworks.ncs index 7704ce9a..a9cc8fea 100644 Binary files a/_module/ncs/g_smallfireworks.ncs and b/_module/ncs/g_smallfireworks.ncs differ diff --git a/_module/ncs/g_startfireworks.ncs b/_module/ncs/g_startfireworks.ncs index 94d1cbf8..4ba9b606 100644 Binary files a/_module/ncs/g_startfireworks.ncs and b/_module/ncs/g_startfireworks.ncs differ diff --git a/_module/ncs/givekey.ncs b/_module/ncs/givekey.ncs index 85cc671a..e4404140 100644 Binary files a/_module/ncs/givekey.ncs and b/_module/ncs/givekey.ncs differ diff --git a/_module/ncs/grezneckteleport.ncs b/_module/ncs/grezneckteleport.ncs index 54eee9ef..56c44c52 100644 Binary files a/_module/ncs/grezneckteleport.ncs and b/_module/ncs/grezneckteleport.ncs differ diff --git a/_module/ncs/henchlvl_assasta.ncs b/_module/ncs/henchlvl_assasta.ncs index 64300aea..3390b176 100644 Binary files a/_module/ncs/henchlvl_assasta.ncs and b/_module/ncs/henchlvl_assasta.ncs differ diff --git a/_module/ncs/henchlvl_blackta.ncs b/_module/ncs/henchlvl_blackta.ncs index a5530f08..e58faeb6 100644 Binary files a/_module/ncs/henchlvl_blackta.ncs and b/_module/ncs/henchlvl_blackta.ncs differ diff --git a/_module/ncs/henchlvl_drgdsta.ncs b/_module/ncs/henchlvl_drgdsta.ncs index 0b25feb0..5fe463b7 100644 Binary files a/_module/ncs/henchlvl_drgdsta.ncs and b/_module/ncs/henchlvl_drgdsta.ncs differ diff --git a/_module/ncs/henchlvl_harpeta.ncs b/_module/ncs/henchlvl_harpeta.ncs index 40273089..3af1fd62 100644 Binary files a/_module/ncs/henchlvl_harpeta.ncs and b/_module/ncs/henchlvl_harpeta.ncs differ diff --git a/_module/ncs/henchlvl_shadota.ncs b/_module/ncs/henchlvl_shadota.ncs index 7faf4ee4..50f54673 100644 Binary files a/_module/ncs/henchlvl_shadota.ncs and b/_module/ncs/henchlvl_shadota.ncs differ diff --git a/_module/ncs/henchlvl_wpnmsta.ncs b/_module/ncs/henchlvl_wpnmsta.ncs index fa58e2c6..bb6aedc8 100644 Binary files a/_module/ncs/henchlvl_wpnmsta.ncs and b/_module/ncs/henchlvl_wpnmsta.ncs differ diff --git a/_module/ncs/hermitquest1.ncs b/_module/ncs/hermitquest1.ncs index d0dcbae5..7b47a026 100644 Binary files a/_module/ncs/hermitquest1.ncs and b/_module/ncs/hermitquest1.ncs differ diff --git a/_module/ncs/ironflask.ncs b/_module/ncs/ironflask.ncs index 79a77353..61b0681b 100644 Binary files a/_module/ncs/ironflask.ncs and b/_module/ncs/ironflask.ncs differ diff --git a/_module/ncs/j_ai_destroyself.ncs b/_module/ncs/j_ai_destroyself.ncs index 44ce350b..a0ca5127 100644 Binary files a/_module/ncs/j_ai_destroyself.ncs and b/_module/ncs/j_ai_destroyself.ncs differ diff --git a/_module/ncs/j_ai_detercombat.ncs b/_module/ncs/j_ai_detercombat.ncs index 480277d5..b4bbc3b0 100644 Binary files a/_module/ncs/j_ai_detercombat.ncs and b/_module/ncs/j_ai_detercombat.ncs differ diff --git a/_module/ncs/j_ai_heart_aimat.ncs b/_module/ncs/j_ai_heart_aimat.ncs index 107b0fc3..d60bce1e 100644 Binary files a/_module/ncs/j_ai_heart_aimat.ncs and b/_module/ncs/j_ai_heart_aimat.ncs differ diff --git a/_module/ncs/j_ai_heart_buff.ncs b/_module/ncs/j_ai_heart_buff.ncs index c22db2c6..489ce096 100644 Binary files a/_module/ncs/j_ai_heart_buff.ncs and b/_module/ncs/j_ai_heart_buff.ncs differ diff --git a/_module/ncs/j_ai_onblocked.ncs b/_module/ncs/j_ai_onblocked.ncs new file mode 100644 index 00000000..7006c19e Binary files /dev/null and b/_module/ncs/j_ai_onblocked.ncs differ diff --git a/_module/ncs/j_ai_oncombatrou.ncs b/_module/ncs/j_ai_oncombatrou.ncs new file mode 100644 index 00000000..9bf4aa6f Binary files /dev/null and b/_module/ncs/j_ai_oncombatrou.ncs differ diff --git a/_module/ncs/j_ai_onconversat.ncs b/_module/ncs/j_ai_onconversat.ncs new file mode 100644 index 00000000..62a59bd3 Binary files /dev/null and b/_module/ncs/j_ai_onconversat.ncs differ diff --git a/_module/ncs/j_ai_ondamaged.ncs b/_module/ncs/j_ai_ondamaged.ncs new file mode 100644 index 00000000..1b41226f Binary files /dev/null and b/_module/ncs/j_ai_ondamaged.ncs differ diff --git a/_module/ncs/j_ai_ondeath.ncs b/_module/ncs/j_ai_ondeath.ncs new file mode 100644 index 00000000..7f7bd582 Binary files /dev/null and b/_module/ncs/j_ai_ondeath.ncs differ diff --git a/_module/ncs/j_ai_ondisturbed.ncs b/_module/ncs/j_ai_ondisturbed.ncs new file mode 100644 index 00000000..0dce0517 Binary files /dev/null and b/_module/ncs/j_ai_ondisturbed.ncs differ diff --git a/_module/ncs/j_ai_onheartbeat.ncs b/_module/ncs/j_ai_onheartbeat.ncs new file mode 100644 index 00000000..6bc030f4 Binary files /dev/null and b/_module/ncs/j_ai_onheartbeat.ncs differ diff --git a/_module/ncs/j_ai_onpercieve.ncs b/_module/ncs/j_ai_onpercieve.ncs new file mode 100644 index 00000000..4cf6f0b5 Binary files /dev/null and b/_module/ncs/j_ai_onpercieve.ncs differ diff --git a/_module/ncs/j_ai_onphiattack.ncs b/_module/ncs/j_ai_onphiattack.ncs new file mode 100644 index 00000000..6614d639 Binary files /dev/null and b/_module/ncs/j_ai_onphiattack.ncs differ diff --git a/_module/ncs/j_ai_onrest.ncs b/_module/ncs/j_ai_onrest.ncs new file mode 100644 index 00000000..7ed76368 Binary files /dev/null and b/_module/ncs/j_ai_onrest.ncs differ diff --git a/_module/ncs/j_ai_onspawn.ncs b/_module/ncs/j_ai_onspawn.ncs new file mode 100644 index 00000000..c5e7e2f6 Binary files /dev/null and b/_module/ncs/j_ai_onspawn.ncs differ diff --git a/_module/ncs/j_ai_onspellcast.ncs b/_module/ncs/j_ai_onspellcast.ncs new file mode 100644 index 00000000..2cc781b2 Binary files /dev/null and b/_module/ncs/j_ai_onspellcast.ncs differ diff --git a/_module/ncs/j_ai_onuserdef.ncs b/_module/ncs/j_ai_onuserdef.ncs new file mode 100644 index 00000000..4999d881 Binary files /dev/null and b/_module/ncs/j_ai_onuserdef.ncs differ diff --git a/_module/ncs/j_ai_setweapons.ncs b/_module/ncs/j_ai_setweapons.ncs index 1c1b5961..2f681d98 100644 Binary files a/_module/ncs/j_ai_setweapons.ncs and b/_module/ncs/j_ai_setweapons.ncs differ diff --git a/_module/ncs/j_ai_walkwaypoin.ncs b/_module/ncs/j_ai_walkwaypoin.ncs index 6a0d3685..329769b9 100644 Binary files a/_module/ncs/j_ai_walkwaypoin.ncs and b/_module/ncs/j_ai_walkwaypoin.ncs differ diff --git a/_module/ncs/j_ai_wingbuffet.ncs b/_module/ncs/j_ai_wingbuffet.ncs index 794ddf70..3e11a5c7 100644 Binary files a/_module/ncs/j_ai_wingbuffet.ncs and b/_module/ncs/j_ai_wingbuffet.ncs differ diff --git a/_module/ncs/j_ai_wingflying.ncs b/_module/ncs/j_ai_wingflying.ncs index 1f78b9a2..188a7b43 100644 Binary files a/_module/ncs/j_ai_wingflying.ncs and b/_module/ncs/j_ai_wingflying.ncs differ diff --git a/_module/ncs/jcmarthekk.ncs b/_module/ncs/jcmarthekk.ncs index da4557f4..5acfed52 100644 Binary files a/_module/ncs/jcmarthekk.ncs and b/_module/ncs/jcmarthekk.ncs differ diff --git a/_module/ncs/lightrayconv1.ncs b/_module/ncs/lightrayconv1.ncs index 420c3765..3fd07d92 100644 Binary files a/_module/ncs/lightrayconv1.ncs and b/_module/ncs/lightrayconv1.ncs differ diff --git a/_module/ncs/losexponresp.ncs b/_module/ncs/losexponresp.ncs index e7e39e55..2b5393a8 100644 Binary files a/_module/ncs/losexponresp.ncs and b/_module/ncs/losexponresp.ncs differ diff --git a/_module/ncs/menaktombtel1.ncs b/_module/ncs/menaktombtel1.ncs index 8e6fde67..8e5bab47 100644 Binary files a/_module/ncs/menaktombtel1.ncs and b/_module/ncs/menaktombtel1.ncs differ diff --git a/_module/ncs/mmheart.ncs b/_module/ncs/mmheart.ncs index 99f51d8e..9c2757d9 100644 Binary files a/_module/ncs/mmheart.ncs and b/_module/ncs/mmheart.ncs differ diff --git a/_module/ncs/mmlife.ncs b/_module/ncs/mmlife.ncs index eff73942..ec35ee41 100644 Binary files a/_module/ncs/mmlife.ncs and b/_module/ncs/mmlife.ncs differ diff --git a/_module/ncs/mmlife1.ncs b/_module/ncs/mmlife1.ncs index dcb9dffc..ffd2f657 100644 Binary files a/_module/ncs/mmlife1.ncs and b/_module/ncs/mmlife1.ncs differ diff --git a/_module/ncs/mmmind.ncs b/_module/ncs/mmmind.ncs index b2d438c2..a35ca931 100644 Binary files a/_module/ncs/mmmind.ncs and b/_module/ncs/mmmind.ncs differ diff --git a/_module/ncs/nw_c2_default1.ncs b/_module/ncs/nw_c2_default1.ncs index d314ab26..6bc030f4 100644 Binary files a/_module/ncs/nw_c2_default1.ncs and b/_module/ncs/nw_c2_default1.ncs differ diff --git a/_module/ncs/nw_c2_default2.ncs b/_module/ncs/nw_c2_default2.ncs index 7f4eed85..4cf6f0b5 100644 Binary files a/_module/ncs/nw_c2_default2.ncs and b/_module/ncs/nw_c2_default2.ncs differ diff --git a/_module/ncs/nw_c2_default3.ncs b/_module/ncs/nw_c2_default3.ncs index f0df1a77..9bf4aa6f 100644 Binary files a/_module/ncs/nw_c2_default3.ncs and b/_module/ncs/nw_c2_default3.ncs differ diff --git a/_module/ncs/nw_c2_default4.ncs b/_module/ncs/nw_c2_default4.ncs index f6d5fca9..62a59bd3 100644 Binary files a/_module/ncs/nw_c2_default4.ncs and b/_module/ncs/nw_c2_default4.ncs differ diff --git a/_module/ncs/nw_c2_default5.ncs b/_module/ncs/nw_c2_default5.ncs index 6096b1e5..6614d639 100644 Binary files a/_module/ncs/nw_c2_default5.ncs and b/_module/ncs/nw_c2_default5.ncs differ diff --git a/_module/ncs/nw_c2_default6.ncs b/_module/ncs/nw_c2_default6.ncs index e4aaa258..1b41226f 100644 Binary files a/_module/ncs/nw_c2_default6.ncs and b/_module/ncs/nw_c2_default6.ncs differ diff --git a/_module/ncs/nw_c2_default7.ncs b/_module/ncs/nw_c2_default7.ncs index 1de4cbf3..7f7bd582 100644 Binary files a/_module/ncs/nw_c2_default7.ncs and b/_module/ncs/nw_c2_default7.ncs differ diff --git a/_module/ncs/nw_c2_default8.ncs b/_module/ncs/nw_c2_default8.ncs index 56ca3801..0dce0517 100644 Binary files a/_module/ncs/nw_c2_default8.ncs and b/_module/ncs/nw_c2_default8.ncs differ diff --git a/_module/ncs/nw_c2_default9.ncs b/_module/ncs/nw_c2_default9.ncs index b15581c4..c5e7e2f6 100644 Binary files a/_module/ncs/nw_c2_default9.ncs and b/_module/ncs/nw_c2_default9.ncs differ diff --git a/_module/ncs/nw_c2_defaulta.ncs b/_module/ncs/nw_c2_defaulta.ncs index cc763bee..7ed76368 100644 Binary files a/_module/ncs/nw_c2_defaulta.ncs and b/_module/ncs/nw_c2_defaulta.ncs differ diff --git a/_module/ncs/nw_c2_defaultb.ncs b/_module/ncs/nw_c2_defaultb.ncs index 1d5b8bf0..2cc781b2 100644 Binary files a/_module/ncs/nw_c2_defaultb.ncs and b/_module/ncs/nw_c2_defaultb.ncs differ diff --git a/_module/ncs/nw_c2_defaultd.ncs b/_module/ncs/nw_c2_defaultd.ncs index cc361c7b..4999d881 100644 Binary files a/_module/ncs/nw_c2_defaultd.ncs and b/_module/ncs/nw_c2_defaultd.ncs differ diff --git a/_module/ncs/nw_c2_defaulte.ncs b/_module/ncs/nw_c2_defaulte.ncs index 9ff8fc6b..7006c19e 100644 Binary files a/_module/ncs/nw_c2_defaulte.ncs and b/_module/ncs/nw_c2_defaulte.ncs differ diff --git a/_module/ncs/nw_c2_dropin9.ncs b/_module/ncs/nw_c2_dropin9.ncs index 56cc7f1e..0aaec806 100644 Binary files a/_module/ncs/nw_c2_dropin9.ncs and b/_module/ncs/nw_c2_dropin9.ncs differ diff --git a/_module/ncs/nw_c2_herbivore.ncs b/_module/ncs/nw_c2_herbivore.ncs index 47c7d6f3..51f1652f 100644 Binary files a/_module/ncs/nw_c2_herbivore.ncs and b/_module/ncs/nw_c2_herbivore.ncs differ diff --git a/_module/ncs/nw_c2_lycan_9.ncs b/_module/ncs/nw_c2_lycan_9.ncs index b2dbcc8a..7ed36dca 100644 Binary files a/_module/ncs/nw_c2_lycan_9.ncs and b/_module/ncs/nw_c2_lycan_9.ncs differ diff --git a/_module/ncs/nw_c2_omnivore.ncs b/_module/ncs/nw_c2_omnivore.ncs index 75af2ff1..cd44e472 100644 Binary files a/_module/ncs/nw_c2_omnivore.ncs and b/_module/ncs/nw_c2_omnivore.ncs differ diff --git a/_module/ncs/nw_s0_curcrwn.ncs b/_module/ncs/nw_s0_curcrwn.ncs index 077ce51b..37c385c3 100644 Binary files a/_module/ncs/nw_s0_curcrwn.ncs and b/_module/ncs/nw_s0_curcrwn.ncs differ diff --git a/_module/ncs/nw_s0_curlgtw.ncs b/_module/ncs/nw_s0_curlgtw.ncs index 6ae17c21..c5cb52d2 100644 Binary files a/_module/ncs/nw_s0_curlgtw.ncs and b/_module/ncs/nw_s0_curlgtw.ncs differ diff --git a/_module/ncs/nw_s0_curminw.ncs b/_module/ncs/nw_s0_curminw.ncs index 1f87c22f..c06da48c 100644 Binary files a/_module/ncs/nw_s0_curminw.ncs and b/_module/ncs/nw_s0_curminw.ncs differ diff --git a/_module/ncs/nw_s0_curmodw.ncs b/_module/ncs/nw_s0_curmodw.ncs index 6ab21612..c4742e20 100644 Binary files a/_module/ncs/nw_s0_curmodw.ncs and b/_module/ncs/nw_s0_curmodw.ncs differ diff --git a/_module/ncs/nw_s0_harm.ncs b/_module/ncs/nw_s0_harm.ncs index c6034b30..ce16ba3d 100644 Binary files a/_module/ncs/nw_s0_harm.ncs and b/_module/ncs/nw_s0_harm.ncs differ diff --git a/_module/ncs/nw_s0_heal.ncs b/_module/ncs/nw_s0_heal.ncs index 008e6457..a85060e4 100644 Binary files a/_module/ncs/nw_s0_heal.ncs and b/_module/ncs/nw_s0_heal.ncs differ diff --git a/_module/ncs/nw_s0_healcirc.ncs b/_module/ncs/nw_s0_healcirc.ncs index dc504eb9..f1f68511 100644 Binary files a/_module/ncs/nw_s0_healcirc.ncs and b/_module/ncs/nw_s0_healcirc.ncs differ diff --git a/_module/ncs/nw_s0_raisdead.ncs b/_module/ncs/nw_s0_raisdead.ncs index 88c60964..bc3b6e26 100644 Binary files a/_module/ncs/nw_s0_raisdead.ncs and b/_module/ncs/nw_s0_raisdead.ncs differ diff --git a/_module/ncs/nw_s0_resserec.ncs b/_module/ncs/nw_s0_resserec.ncs index 22e4cfc6..26caa938 100644 Binary files a/_module/ncs/nw_s0_resserec.ncs and b/_module/ncs/nw_s0_resserec.ncs differ diff --git a/_module/ncs/nw_s2_layonhand.ncs b/_module/ncs/nw_s2_layonhand.ncs index 974049d0..53370690 100644 Binary files a/_module/ncs/nw_s2_layonhand.ncs and b/_module/ncs/nw_s2_layonhand.ncs differ diff --git a/_module/ncs/nw_s3_balordeth.ncs b/_module/ncs/nw_s3_balordeth.ncs index d3e55302..77392015 100644 Binary files a/_module/ncs/nw_s3_balordeth.ncs and b/_module/ncs/nw_s3_balordeth.ncs differ diff --git a/_module/ncs/orctohecstat.ncs b/_module/ncs/orctohecstat.ncs index 78ffb8b4..d7147ddb 100644 Binary files a/_module/ncs/orctohecstat.ncs and b/_module/ncs/orctohecstat.ncs differ diff --git a/_module/ncs/pillarscript.ncs b/_module/ncs/pillarscript.ncs index 19c8dcc0..3c6a4e19 100644 Binary files a/_module/ncs/pillarscript.ncs and b/_module/ncs/pillarscript.ncs differ diff --git a/_module/ncs/portarenatopil.ncs b/_module/ncs/portarenatopil.ncs index a00f2013..57c0b63a 100644 Binary files a/_module/ncs/portarenatopil.ncs and b/_module/ncs/portarenatopil.ncs differ diff --git a/_module/ncs/rakshasachange.ncs b/_module/ncs/rakshasachange.ncs new file mode 100644 index 00000000..f660b8b9 Binary files /dev/null and b/_module/ncs/rakshasachange.ncs differ diff --git a/_module/ncs/resptownport.ncs b/_module/ncs/resptownport.ncs index 918da2f2..f10ef59d 100644 Binary files a/_module/ncs/resptownport.ncs and b/_module/ncs/resptownport.ncs differ diff --git a/_module/ncs/sc_004.ncs b/_module/ncs/sc_004.ncs index c860b113..a0f7c926 100644 Binary files a/_module/ncs/sc_004.ncs and b/_module/ncs/sc_004.ncs differ diff --git a/_module/ncs/sc_006.ncs b/_module/ncs/sc_006.ncs index 742d5765..bc7f65e2 100644 Binary files a/_module/ncs/sc_006.ncs and b/_module/ncs/sc_006.ncs differ diff --git a/_module/ncs/sc_007.ncs b/_module/ncs/sc_007.ncs index b92e5631..f3d84189 100644 Binary files a/_module/ncs/sc_007.ncs and b/_module/ncs/sc_007.ncs differ diff --git a/_module/ncs/sc_008.ncs b/_module/ncs/sc_008.ncs index b92e5631..f3d84189 100644 Binary files a/_module/ncs/sc_008.ncs and b/_module/ncs/sc_008.ncs differ diff --git a/_module/ncs/sc_012.ncs b/_module/ncs/sc_012.ncs index e393292a..32aaa7dc 100644 Binary files a/_module/ncs/sc_012.ncs and b/_module/ncs/sc_012.ncs differ diff --git a/_module/ncs/sc_013.ncs b/_module/ncs/sc_013.ncs index e9f38327..33908114 100644 Binary files a/_module/ncs/sc_013.ncs and b/_module/ncs/sc_013.ncs differ diff --git a/_module/ncs/sc_017.ncs b/_module/ncs/sc_017.ncs index b92e5631..f3d84189 100644 Binary files a/_module/ncs/sc_017.ncs and b/_module/ncs/sc_017.ncs differ diff --git a/_module/ncs/sc_018.ncs b/_module/ncs/sc_018.ncs index b92e5631..f3d84189 100644 Binary files a/_module/ncs/sc_018.ncs and b/_module/ncs/sc_018.ncs differ diff --git a/_module/ncs/sc_019.ncs b/_module/ncs/sc_019.ncs index b92e5631..f3d84189 100644 Binary files a/_module/ncs/sc_019.ncs and b/_module/ncs/sc_019.ncs differ diff --git a/_module/ncs/sc_020.ncs b/_module/ncs/sc_020.ncs index b92e5631..f3d84189 100644 Binary files a/_module/ncs/sc_020.ncs and b/_module/ncs/sc_020.ncs differ diff --git a/_module/ncs/sc_021.ncs b/_module/ncs/sc_021.ncs index b92e5631..f3d84189 100644 Binary files a/_module/ncs/sc_021.ncs and b/_module/ncs/sc_021.ncs differ diff --git a/_module/ncs/sc_022.ncs b/_module/ncs/sc_022.ncs index b92e5631..f3d84189 100644 Binary files a/_module/ncs/sc_022.ncs and b/_module/ncs/sc_022.ncs differ diff --git a/_module/ncs/sc_025.ncs b/_module/ncs/sc_025.ncs index e970660b..83594a7f 100644 Binary files a/_module/ncs/sc_025.ncs and b/_module/ncs/sc_025.ncs differ diff --git a/_module/ncs/sc_031.ncs b/_module/ncs/sc_031.ncs index e3b481b0..e539b3b4 100644 Binary files a/_module/ncs/sc_031.ncs and b/_module/ncs/sc_031.ncs differ diff --git a/_module/ncs/sc_100.ncs b/_module/ncs/sc_100.ncs index f38d93b1..fff42862 100644 Binary files a/_module/ncs/sc_100.ncs and b/_module/ncs/sc_100.ncs differ diff --git a/_module/ncs/scorpeggs1.ncs b/_module/ncs/scorpeggs1.ncs index 14cb3392..073205f7 100644 Binary files a/_module/ncs/scorpeggs1.ncs and b/_module/ncs/scorpeggs1.ncs differ diff --git a/_module/ncs/searchstatue.ncs b/_module/ncs/searchstatue.ncs index a9da48ad..43adaf4f 100644 Binary files a/_module/ncs/searchstatue.ncs and b/_module/ncs/searchstatue.ncs differ diff --git a/_module/ncs/secretcoffin.ncs b/_module/ncs/secretcoffin.ncs index 6135c5fe..e67d86eb 100644 Binary files a/_module/ncs/secretcoffin.ncs and b/_module/ncs/secretcoffin.ncs differ diff --git a/_module/ncs/spawnscramge.ncs b/_module/ncs/spawnscramge.ncs index ef1c431b..1954a75f 100644 Binary files a/_module/ncs/spawnscramge.ncs and b/_module/ncs/spawnscramge.ncs differ diff --git a/_module/ncs/statue.ncs b/_module/ncs/statue.ncs new file mode 100644 index 00000000..7e235d81 Binary files /dev/null and b/_module/ncs/statue.ncs differ diff --git a/_module/ncs/statuedwarfscrip.ncs b/_module/ncs/statuedwarfscrip.ncs index 1d6100dc..ccc9a304 100644 Binary files a/_module/ncs/statuedwarfscrip.ncs and b/_module/ncs/statuedwarfscrip.ncs differ diff --git a/_module/ncs/sumcorrak.ncs b/_module/ncs/sumcorrak.ncs index 14426179..81b5a3c3 100644 Binary files a/_module/ncs/sumcorrak.ncs and b/_module/ncs/sumcorrak.ncs differ diff --git a/_module/ncs/summon4glabs.ncs b/_module/ncs/summon4glabs.ncs index c513ca2f..686a334f 100644 Binary files a/_module/ncs/summon4glabs.ncs and b/_module/ncs/summon4glabs.ncs differ diff --git a/_module/ncs/summondemi.ncs b/_module/ncs/summondemi.ncs index a2c36bf2..4725b7f1 100644 Binary files a/_module/ncs/summondemi.ncs and b/_module/ncs/summondemi.ncs differ diff --git a/_module/ncs/summonrtroll.ncs b/_module/ncs/summonrtroll.ncs index 56109c3c..fd71a80d 100644 Binary files a/_module/ncs/summonrtroll.ncs and b/_module/ncs/summonrtroll.ncs differ diff --git a/_module/ncs/teleportationsto.ncs b/_module/ncs/teleportationsto.ncs index cc6420c0..a3613959 100644 Binary files a/_module/ncs/teleportationsto.ncs and b/_module/ncs/teleportationsto.ncs differ diff --git a/_module/ncs/tribitzend.ncs b/_module/ncs/tribitzend.ncs index a550d86a..074e6e67 100644 Binary files a/_module/ncs/tribitzend.ncs and b/_module/ncs/tribitzend.ncs differ diff --git a/_module/ncs/vampscome.ncs b/_module/ncs/vampscome.ncs index cce52a09..7b4a7944 100644 Binary files a/_module/ncs/vampscome.ncs and b/_module/ncs/vampscome.ncs differ diff --git a/_module/ncs/wallclose.ncs b/_module/ncs/wallclose.ncs index 477787b4..a6e65724 100644 Binary files a/_module/ncs/wallclose.ncs and b/_module/ncs/wallclose.ncs differ diff --git a/_module/ncs/wisright2.ncs b/_module/ncs/wisright2.ncs index 288328bb..36eec235 100644 Binary files a/_module/ncs/wisright2.ncs and b/_module/ncs/wisright2.ncs differ diff --git a/_module/ncs/wisright3.ncs b/_module/ncs/wisright3.ncs index f866f18c..46be9702 100644 Binary files a/_module/ncs/wisright3.ncs and b/_module/ncs/wisright3.ncs differ diff --git a/_module/ncs/wiswrong1.ncs b/_module/ncs/wiswrong1.ncs index 98fabc1b..d03fc73c 100644 Binary files a/_module/ncs/wiswrong1.ncs and b/_module/ncs/wiswrong1.ncs differ diff --git a/_module/ncs/wiswrong2.ncs b/_module/ncs/wiswrong2.ncs index f98a712d..c03108be 100644 Binary files a/_module/ncs/wiswrong2.ncs and b/_module/ncs/wiswrong2.ncs differ diff --git a/_module/ncs/wiswrong3.ncs b/_module/ncs/wiswrong3.ncs index ad9bb0e4..afef1513 100644 Binary files a/_module/ncs/wiswrong3.ncs and b/_module/ncs/wiswrong3.ncs differ diff --git a/_module/ncs/x0_s0_inflict.ncs b/_module/ncs/x0_s0_inflict.ncs index 3783eed2..234da84f 100644 Binary files a/_module/ncs/x0_s0_inflict.ncs and b/_module/ncs/x0_s0_inflict.ncs differ diff --git a/_module/ncs/x2_act_ws_makeme.ncs b/_module/ncs/x2_act_ws_makeme.ncs index 3cce5ca5..63f2ad28 100644 Binary files a/_module/ncs/x2_act_ws_makeme.ncs and b/_module/ncs/x2_act_ws_makeme.ncs differ diff --git a/_module/nss/drownitem.nss b/_module/nss/drownitem.nss index d4e0ba5a..3aa48ccb 100644 --- a/_module/nss/drownitem.nss +++ b/_module/nss/drownitem.nss @@ -1,3 +1,5 @@ +#include "drownud" + void main() { object oCurrentObject = GetFirstObjectInArea(); diff --git a/_module/nss/g_startfireworks.nss b/_module/nss/g_startfireworks.nss index 30c56322..e967262d 100644 --- a/_module/nss/g_startfireworks.nss +++ b/_module/nss/g_startfireworks.nss @@ -23,7 +23,7 @@ effects come in. void main() { //Edit Settings here /////////////////////////////////////////////////////// - float z = 14; //How High the fireworks go before exploding + float z = 14.0; //How High the fireworks go before exploding //DO NOT EDIT BELOW THIS LINE ////////////////////////////////////////////// object oArea = GetArea(OBJECT_SELF); object oTarget = GetObjectByTag("FireworksSource"); diff --git a/_module/nss/j_ai_destroyself.nss b/_module/nss/j_ai_destroyself.nss index ffddafb1..f1ce16a1 100644 --- a/_module/nss/j_ai_destroyself.nss +++ b/_module/nss/j_ai_destroyself.nss @@ -1,6 +1,6 @@ -/************************ [Destroy Ourself] ************************************ +/*/////////////////////// [Destroy Ourself] //////////////////////////////////// Filename: J_AI_DestroySelf -************************* [Destroy Ourself] ************************************ +///////////////////////// [Destroy Ourself] //////////////////////////////////// This is executed OnDeath to clean up the corpse. It helps - clears all non-droppable stuff. @@ -10,22 +10,23 @@ Oh, if this is executed any other time when they are dead, they are destroyed instantly. -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.3 - Added to replace a include function for death. - No locals are destroyed. The game should do that anyway. Items are, though. -************************* [Workings] ******************************************* + 1.4 - +///////////////////////// [Workings] /////////////////////////////////////////// this, if ever fired, will destroy the creature. It is not deleayed - there is a special function in the death script to check the whole "Did I get raised?" stuff. I suppose you can edit this to put a corpse in :-D -************************* [Arguments] ****************************************** +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: N/A - none needed. -************************* [Destroy Ourself] ***********************************/ +///////////////////////// [Destroy Ourself] //////////////////////////////////*/ // Exectued from death, to speed things up. -#include "j_inc_constants" +#include "J_INC_CONSTANTS" // This will delete all un-droppable items, before they fade out. void DeleteAllThings(); diff --git a/_module/nss/j_ai_detercombat.nss b/_module/nss/j_ai_detercombat.nss index b78088b5..2a55c846 100644 --- a/_module/nss/j_ai_detercombat.nss +++ b/_module/nss/j_ai_detercombat.nss @@ -1,6 +1,6 @@ -/************************ [Execute Combat Action] ****************************** +/*/////////////////////// [Execute Combat Action] ////////////////////////////// Filename: J_AI_DeterCombat -************************* [Execute Combat Action] ****************************** +///////////////////////// [Execute Combat Action] ////////////////////////////// Fired from other scripts, this runs an actual actions. It also contains the Pre-combat and Post-combat action events. In essense @@ -10,10 +10,12 @@ Therefore, they only fire if the default AI is being used :-) Do NOT mess with this file, please. :-D -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.3 - AI Include only fired from here. This script is executed from others, as the default in place of custom AI scripts. -************************* [Workings] ******************************************* + 1.4 - Mainly See the generic AI include file for changes. This is just + what calls DetermineCombatRound() and associated things. +///////////////////////// [Workings] /////////////////////////////////////////// This is simple: - We execute it if there is no other AI files. @@ -25,11 +27,11 @@ It cleans things up, and is the only script in the whole set that has j_inc_generic_ai in, reducing file size, and compile times. AI is more manageable too! -************************* [Arguments] ****************************************** - Arguments: See J_Inc_Generic_AI -************************* [Execute Combat Action] *****************************/ +///////////////////////// [Arguments] ////////////////////////////////////////// + Arguments: See J_INC_GENERIC_AI +///////////////////////// [Execute Combat Action] ////////////////////////////*/ -#include "j_inc_generic_ai" +#include "J_INC_GENERIC_AI" void main() { @@ -41,8 +43,12 @@ void main() // Check: Are we imputting a target? We imputt it even if invalid object oTarget = GetLocalObject(OBJECT_SELF, AI_TEMP_SET_TARGET); - // Speak combat round speakstring - SpeakArrayString(AI_TALK_ON_COMBAT_ROUND, TRUE); + // * Don't speak when dead. 1.4 change (an obvious one to make) + if(CanSpeak()) + { + // Speak combat round speakstring + SpeakArrayString(AI_TALK_ON_COMBAT_ROUND, TRUE); + } // Call combat round using include AI_DetermineCombatRound(oTarget); diff --git a/_module/nss/j_ai_heart_aimat.nss b/_module/nss/j_ai_heart_aimat.nss index 7b91e20a..cdc37c9c 100644 --- a/_module/nss/j_ai_heart_aimat.nss +++ b/_module/nss/j_ai_heart_aimat.nss @@ -1,27 +1,26 @@ -/************************ [On Heartbeat - Animations] ************************** +/*/////////////////////// [On Heartbeat - Animations] ////////////////////////// Filename: J_AI_Heart_aimat -************************* [On Heartbeat - Animations] ************************** +///////////////////////// [On Heartbeat - Animations] ////////////////////////// To keep the heartbeat small, I've divided all the bits that MIGHT fire into other scripts. This makes it smaller, and faster. I've also shortened the perception script too - and along with the heartbeat is the largest, Out-Of-Combat script. It isn't divided up by execute scripts, but should be leaner. -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.3 - Added to speed up heartbeat and keep filesize down on un-used parts. -************************* [Workings] ******************************************* + 1.4 - Changed to nw_i0_generic, as to include all animations, whatever NwN version. +///////////////////////// [Workings] /////////////////////////////////////////// This is executed as file HEARTBEAT_ANIMATIONS_FILE, from the heartbeat script (Default1, or onheartbeat). It can run by itself, using the SoU animations - better then me changing and making my own, as they are vastly improved from NwN! +///////////////////////// [Arguments] ////////////////////////////////////////// + Arguments: N/A +///////////////////////// [On Heartbeat - Animations] ////////////////////////*/ - It is Not called if AI_VALID_ANIMATIONS AI Integer is not set. -************************* [Arguments] ****************************************** - Arguments: -************************* [On Heartbeat - Animations] *************************/ - -// SoU Animations file. -#include "x0_i0_anims" +// Generic Include File. This contains animations whatever NwN version it is. +#include "NW_I0_GENERIC" void main() { @@ -37,8 +36,4 @@ void main() { PlayImmobileAmbientAnimations(); } - else - { - DeleteLocalInt(OBJECT_SELF, "AI_INTEGER" + "AI_VALID_ANIMATIONS"); - } } diff --git a/_module/nss/j_ai_heart_buff.nss b/_module/nss/j_ai_heart_buff.nss index d41cbe39..8361f7b9 100644 --- a/_module/nss/j_ai_heart_buff.nss +++ b/_module/nss/j_ai_heart_buff.nss @@ -1,46 +1,57 @@ -/************************ [On Heartbeat - Buff] ******************************** +/*/////////////////////// [On Heartbeat - Buff] //////////////////////////////// Filename: j_ai_heart_buff -************************* [On Heartbeat - Buff] ******************************** +///////////////////////// [On Heartbeat - Buff] //////////////////////////////// This is ExecuteScript'ed from the heartbeat file, if they want to buff themselves with spells to be prepared for any battle coming up. -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.3 - Added -************************* [Workings] ******************************************* + 1.4 - Will Add all the appropriate Hordes spells, notably the missing epic ones. +///////////////////////// [Workings] /////////////////////////////////////////// This contains Advance Buffing - IE quick protection spells. I've done what ones I think are useful - IE most protection ones & summons! - This doesn't include any which are very short duration: + + This doesn't include any which are (potentionally) very short duration (IE: + 1 round/level, or a set value): Elemntal shield/Wounding whispers (though you can add all of these!) Aid, bless, aura of vitality, aura of glory, blood frenzy, prayer, divine* Range (Power, Might, Shield, Favor), Expeditious retreat, holy/unholy aura (or protection from /magic circle against), - natures balance, one with the land, shield of faith, virtue, war cry. -************************* [Arguments] ****************************************** + natures balance, one with the land, shield of faith, virtue, war cry, dirge, + death armor, mestals acid sheath. +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: N/A -************************* [On Heartbeat - Buff] *******************************/ +///////////////////////// [On Heartbeat - Buff] //////////////////////////////*/ + +// Constants for some unconstantanated spells +#include "J_INC_CONSTANTS" // Wrapper, to stop repeating the same lines! :-) -int BuffCastSpell(int iSpell); +int BuffCastSpell(int nSpell); void main() { // For summons counter. - int nCnt, iBreak; + int nCnt, bBreak; // FAST BUFF SELF // Stop what we are doing first, to perform the actions. ClearAllActions(); - //Combat Protections + // Always cast "Epic Warding" and "Epic Mage Armor". + BuffCastSpell(FEAT_EPIC_SPELL_EPIC_WARDING); + BuffCastSpell(FEAT_EPIC_SPELL_MAGE_ARMOUR); + + // Combat Protections if(!BuffCastSpell(SPELL_PREMONITION)) if(!BuffCastSpell(SPELL_GREATER_STONESKIN)) BuffCastSpell(SPELL_STONESKIN); - //Visage Protections + // Visage Protections if(!BuffCastSpell(SPELL_SHADOW_SHIELD)) if(!BuffCastSpell(SPELL_ETHEREAL_VISAGE)) BuffCastSpell(SPELL_GHOSTLY_VISAGE); - //Mantle Protections + // Mantle Protections if(!BuffCastSpell(SPELL_GREATER_SPELL_MANTLE)) if(!BuffCastSpell(SPELL_SPELL_MANTLE)) BuffCastSpell(SPELL_LESSER_SPELL_MANTLE); @@ -49,13 +60,13 @@ void main() if(BuffCastSpell(SPELL_TRUE_SEEING)) BuffCastSpell(SPELL_SEE_INVISIBILITY); - //Elemental Protections. 4 lots. From 40/- to 10/- + // Elemental Protections. 4 lots. From 40/- to 10/- if(!BuffCastSpell(SPELL_ENERGY_BUFFER)) if(!BuffCastSpell(SPELL_PROTECTION_FROM_ELEMENTS)) if(!BuffCastSpell(SPELL_RESIST_ELEMENTS)) BuffCastSpell(SPELL_ENDURE_ELEMENTS); - //Mental Protections + // Mental Protections if(!BuffCastSpell(SPELL_MIND_BLANK)) if(!BuffCastSpell(SPELL_LESSER_MIND_BLANK)) BuffCastSpell(SPELL_CLARITY); @@ -64,7 +75,7 @@ void main() if(!BuffCastSpell(SPELL_GLOBE_OF_INVULNERABILITY)) BuffCastSpell(SPELL_MINOR_GLOBE_OF_INVULNERABILITY); - //Invisibility + // Invisibility // Note: Improved has 50% consealment, etherealness has just invisiblity. if(!BuffCastSpell(SPELL_IMPROVED_INVISIBILITY)) BuffCastSpell(SPELL_DISPLACEMENT);//50% consealment @@ -82,21 +93,22 @@ void main() BuffCastSpell(SPELL_EAGLE_SPLEDOR); if(!BuffCastSpell(SPELL_GREATER_FOXS_CUNNING)) BuffCastSpell(SPELL_FOXS_CUNNING); - if(!BuffCastSpell(SPELL_GREATER_OWLS_WISDOM)) - BuffCastSpell(SPELL_OWLS_WISDOM); if(!BuffCastSpell(SPELL_GREATER_ENDURANCE)) BuffCastSpell(SPELL_ENDURANCE); + if(!BuffCastSpell(AI_SPELL_OWLS_INSIGHT)) + if(!BuffCastSpell(SPELL_GREATER_OWLS_WISDOM)) + BuffCastSpell(SPELL_OWLS_WISDOM); // Mage armor or shield. Don't stack them. if(!BuffCastSpell(SPELL_SHIELD)) BuffCastSpell(SPELL_MAGE_ARMOR); + // Entropic Shield (20% consealment, 1 turn/level) + BuffCastSpell(SPELL_ENTROPIC_SHIELD); + // Protection from negative energy if(!BuffCastSpell(SPELL_UNDEATHS_ETERNAL_FOE)) BuffCastSpell(SPELL_DEATH_WARD); //Misc Protections which have no more powerful. -// Low durations (Rounds per caster level) -// if(!BuffCastSpell(SPELL_ELEMENTAL_SHIELD)) -// BuffCastSpell(SPELL_WOUNDING_WHISPERS); BuffCastSpell(SPELL_BARKSKIN); BuffCastSpell(SPELL_ENTROPIC_SHIELD); BuffCastSpell(SPELL_PROTECTION_FROM_SPELLS); @@ -105,6 +117,12 @@ void main() BuffCastSpell(SPELL_REGENERATE); BuffCastSpell(SPELL_SPELL_RESISTANCE); BuffCastSpell(SPELL_FREEDOM_OF_MOVEMENT); + BuffCastSpell(SPELL_FREEDOM_OF_MOVEMENT); + +// Low durations (Rounds per caster level) +// if(!BuffCastSpell(SPELL_ELEMENTAL_SHIELD)) +// BuffCastSpell(SPELL_WOUNDING_WHISPERS); +// BuffCastSpell(SPELL_DEATH_ARMOR); //Summon Ally. @@ -125,13 +143,13 @@ void main() { // 8, 7, 6, 5. for(nCnt = SPELL_SUMMON_CREATURE_VIII; - (nCnt >= SPELL_SUMMON_CREATURE_V && iBreak != TRUE); + (nCnt >= SPELL_SUMMON_CREATURE_V && bBreak != TRUE); nCnt--) { - if(BuffCastSpell(nCnt)) iBreak = TRUE; + if(BuffCastSpell(nCnt)) bBreak = TRUE; } // Then undead - if(iBreak != TRUE) + if(bBreak != TRUE) { if(!BuffCastSpell(SPELL_CREATE_GREATER_UNDEAD)) { @@ -141,7 +159,7 @@ void main() { // Lastly, the 4-1 ones. for(nCnt = SPELL_SUMMON_CREATURE_IV; - (nCnt >= SPELL_SUMMON_CREATURE_I); + nCnt >= SPELL_SUMMON_CREATURE_I; nCnt--) { if(BuffCastSpell(nCnt)) break; @@ -159,11 +177,11 @@ void main() } // Wrapper, to stop repeating the same lines! :-) -int BuffCastSpell(int iSpell) +int BuffCastSpell(int nSpell) { - if(GetHasSpell(iSpell)) + if(GetHasSpell(nSpell)) { - ActionCastSpellAtObject(iSpell, OBJECT_SELF, METAMAGIC_ANY, FALSE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE); + ActionCastSpellAtObject(nSpell, OBJECT_SELF, METAMAGIC_ANY, FALSE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE); return TRUE; } return FALSE; diff --git a/_module/nss/j_ai_heart_serch.nss b/_module/nss/j_ai_heart_serch.nss index e0b4fa68..b0d29641 100644 --- a/_module/nss/j_ai_heart_serch.nss +++ b/_module/nss/j_ai_heart_serch.nss @@ -1,35 +1,36 @@ -/************************ [On Heartbeat - Move Nearer PC] ********************** - Filename: j_ai_heart_serch -************************* [On Heartbeat - Move Nearer PC] ********************** +/*/////////////////////// [On Heartbeat - Move Nearer PC] ////////////////////// + Filename: J_AI_Heart_Serch +///////////////////////// [On Heartbeat - Move Nearer PC] ////////////////////// This is fired to perform moving nearer the PC, or searching towards them. Yes, like the Henchmen and Battle AI code. I am sure they won't mind - if they do, I will remove it :-) -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.3 - Added -************************* [Workings] ******************************************* + 1.4 - Reformatted as with the rest of the AI +///////////////////////// [Workings] /////////////////////////////////////////// This makes the NPC move nearer to a PC. Fires if the spawn condition is on and the timer is not, and only 1/4 heartbeats to lessen the effect. -************************* [Arguments] ****************************************** +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: N/A -************************* [On Heartbeat - Move Nearer PC] *********************/ +///////////////////////// [On Heartbeat - Move Nearer PC] ////////////////////*/ -#include "j_inc_constants" +#include "J_INC_CONSTANTS" void main() { object oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC); if(GetIsObjectValid(oPC) && GetIsEnemy(oPC) && GetDistanceToObject(oPC) < - IntToFloat(GetBoundriedAIInteger(AI_SEARCH_IF_ENEMIES_NEAR_RANGE, i25, i50, i5))) + IntToFloat(GetBoundriedAIInteger(AI_SEARCH_IF_ENEMIES_NEAR_RANGE, 25, 50, 5))) { vector vPC = GetPosition(oPC); // Whats the distance we use to move a bit nearer? - int iRandom = i10 + Random(i10); + int nRandom = 10 + Random(10); // Randomise a point nearby. - vPC.x += IntToFloat(iRandom - (Random(i2 * iRandom + i1))); - vPC.y += IntToFloat(iRandom - (Random(i2 * iRandom + i1))); - vPC.z += IntToFloat(iRandom - (Random(i2 * iRandom + i1))); + vPC.x += IntToFloat(nRandom - (Random(2 * nRandom + 1))); + vPC.y += IntToFloat(nRandom - (Random(2 * nRandom + 1))); + vPC.z += IntToFloat(nRandom - (Random(2 * nRandom + 1))); // Define the location location lNew = Location(GetArea(oPC), vPC, IntToFloat(Random(359))); SetLocalTimer(AI_TIMER_SEARCHING, GetDistanceToObject(oPC)); diff --git a/_module/nss/j_ai_onblocked.nss b/_module/nss/j_ai_onblocked.nss new file mode 100644 index 00000000..f7301cc8 --- /dev/null +++ b/_module/nss/j_ai_onblocked.nss @@ -0,0 +1,332 @@ +/*/////////////////////// [On Blocked] ///////////////////////////////////////// + Filename: J_AI_OnBlocked or nw_c2_defaulte +///////////////////////// [On Blocked] ///////////////////////////////////////// + Added in user defined constant - won't open any doors. + 0 = Default (even if not set) opens as appropriate + 1 = Always bashes the door. + 2 = Never open any doors + 3 = Never opens plot doors + + They will: (int is intellgience needed) + 1. Open if not trapped (7 int) + 2. Unlock if possible, and rank is high enough, and it needs no key and is not trapped (7 int) + 3. Untrap the door, if possible, if trapped (7 int) + 4. Else, if has high enough stats, try Knock. (10 int) + 6. Else Equip appropriate weapons and bash (5 int) + + Note: This also fires for blocking via. creatures. It is optimised, and + works by re-targeting and doing a few small things to do with blocking. +///////////////////////// [History] //////////////////////////////////////////// + 1.0 - Opens with Knock. Unlocks door. Ignores trapped doors. + 1.3 - Debug messages. + - New events, even if the change of using them is small! + - No ClearAllactions so any previous movings will carry on once the door is gone. + - Removed debug messages + - Added Creature reaction code + 1.4 - Need to add a "hands" check (done on spawn, to set a setting to not + open doors at all, IE: We do NOT have hands, do not open doors), so + its a little more realistic "out of the box" + - Fixed an instance of GetObjectSeen being repeated. + - Fixed the variable AI_DOOR_INTELLIGENCE not being got via GetAIInteger(). + - Removed unneeded else statement. +///////////////////////// [Workings] /////////////////////////////////////////// + Uses simple code to deal with a door in the best way possible. + + Uses DoDoorAction, which is added to the top of an action queue and doesn't, + therefore, delete any ActionAttack's and so on below it. (Or I hope it + is like this) + + Creatures are reacted by with ClearAllActions usually. +///////////////////////// [Arguments] ////////////////////////////////////////// + Arguments: GetBlockingDoor, GetIsDoorActionPossible, GetLocked, GetLockKeyRequired + GetLockKeyTag, GetLockUnlockDC, GetPlotFlag, DoDoorAction +///////////////////////// [On Blocked] ///////////////////////////////////////*/ + +#include "J_INC_OTHER_AI" + +// Fires the end-blocked event. +void FireBlockedEvent(); +// Range attack oTarget. +int RangedAttack(object oTarget = OBJECT_INVALID); + +void main() +{ + // Pre-on blocked-event. Returns TRUE if we interrupt this script call. + if(FirePreUserEvent(AI_FLAG_UDE_ON_BLOCKED_PRE_EVENT, EVENT_ON_BLOCKED_PRE_EVENT)) return; + + // AI status check. Is the AI on? + if(GetAIOff()) return; + + // This CAN return a blocking creature. + object oBlocker = GetBlockingDoor(); + int nBlockerType = GetObjectType(oBlocker); + + if(!GetIsObjectValid(oBlocker)) return; + + // Anyone blocked by an enemy will re-target them (and attack them), blocked + // by someone they cannot get they will cast seeing spells and react, and if + // blocked by a friend, they may run back and use a ranged weapon if they + // have one. + if(nBlockerType == OBJECT_TYPE_CREATURE) + { + // Are we doing something that should not be overriden? (even fleeing, + // if stuck, we can't do anything else then move again on heartbeat!) + if(GetIsPerformingSpecialAction()) return; + + // Blocked timer, we normally do an action. A small timer stops a lot + // of lag. + if(GetLocalTimer(AI_TIMER_BLOCKED)) return; + + // Set the timer for 1 second + SetLocalTimer(AI_TIMER_BLOCKED, 1.0); + + // Is it an enemy? + if(GetIsEnemy(oBlocker)) + { + // Check if seen or heard + if(GetObjectSeen(oBlocker) || GetObjectHeard(oBlocker)) + { + // Enemy :-) We can re-target (as know of thier presence), using + // them as a target. + // - This overrides even casting a spell - basically, as we should + // be moving, this will re-cast it at someone or something in range + SetAIObject(AI_ATTACK_SPECIFIC_OBJECT, oBlocker); + + // Check if we can do combat - if we cannot, we can re-do combat + // next time + if(!GetIsBusyWithAction()) + { + // Attacks if we are not attacking + ClearAllActions(); + DetermineCombatRound(oBlocker); + return; + } + } + else + { + // Invisible? Not there? Some odd error? We set that we know of + // someone invisible, and will attack if not in combat. + if(GetHasEffect(EFFECT_TYPE_INVISIBILITY, oBlocker) || + GetStealthMode(oBlocker) == STEALTH_MODE_ACTIVATED) + { + SetAIObject(AI_LAST_TO_GO_INVISIBLE, oBlocker); + } + // Shout to allies + AISpeakString(AI_SHOUT_CALL_TO_ARMS); + + // Check if we can do combat + if(!GetIsBusyWithAction()) + { + // Attacks if we are not attacking + ClearAllActions(); + DetermineCombatRound(); + return; + } + } + } + // Else is non-enemy, a friend or neutral + else + { + // As we are blocked by them, we re-do combat - we have a choice of + // either using a Bow to attack our target (if that was what + // we were doing) and move back a little, or re-initiate combat + + // Were we attacking in combat? + object oPrevious = GetAttackTarget(); + + // Check action + if(GetCurrentAction() == ACTION_ATTACKOBJECT) + { + // This gets set to FALSE if we can cutthrough attack, + // or whatever. + + int bPreviousAttackFailed = FALSE; + // Check if we can see our previous target + if(GetObjectSeen(oPrevious) || + (GetObjectHeard(oPrevious) && LineOfSightObject(OBJECT_SELF, oPrevious))) + { + // We can! see if we can re-attack with ranged weapon, else + // doesn't matter we can see them + bPreviousAttackFailed = RangedAttack(oPrevious); + } + + // If we havn't added an action yet... + if(bPreviousAttackFailed == FALSE) + { + // We have not stopped the script - so determine combat + // round against nearest seen or heard enemy! + if(!RangedAttack()) + { + // Else normal round to try and get a new target + ClearAllActions(); + DetermineCombatRound(); + } + } + // Action attack, normally means melee attack. If we can, we + // attack our previous target if seen, ELSE we will re-initate + // combat. + AISpeakString(AI_SHOUT_I_WAS_ATTACKED); + + // Fire the On blocked event as normal + FireBlockedEvent(); + return; + } + else // if(nAction == ACTION_CASTSPELL and others) + { + // Reinitate combat, but don't attack oPrevious + ClearAllActions(); + DetermineCombatRound(); + + // Action attack, normally means melee attack. If we can, we + // attack our previous target if seen, ELSE we will re-initate + // combat. + AISpeakString(AI_SHOUT_I_WAS_ATTACKED); + + // Fire the On blocked event as normal + FireBlockedEvent(); + return; + } + } + } + // Placeable - Currently not returned, however, added just in case! + else if(nBlockerType == OBJECT_TYPE_PLACEABLE) + { + // Check for plot, and therefore attack it to bring it down. + // - Remember, ActionAttack will re-initiate when combat round fires + // again in 3 or 6 seconds (or less, if we just were moving) + if(!GetPlotFlag(oBlocker) && + GetIsPlaceableObjectActionPossible(oBlocker, PLACEABLE_ACTION_BASH)) + { + // Do placeable action + DoPlaceableObjectAction(oBlocker, PLACEABLE_ACTION_BASH); + FireBlockedEvent(); + return; + } + return; + } + // Door behaviour + else if(nBlockerType == OBJECT_TYPE_DOOR) + { + int nDoorIntelligence = GetAIInteger(AI_DOOR_INTELLIGENCE); + int nInt = GetAbilityScore(OBJECT_SELF, ABILITY_INTELLIGENCE); + if(nDoorIntelligence == 1)// 1 = Always bashes the doors, plot, locked or anything. + { + DoDoorAction(oBlocker, DOOR_ACTION_BASH); + // We re-initiate combat. + FireBlockedEvent(); + return; + } + else if(nDoorIntelligence == 2)// 2 = Never open anything, bashing or not. + { + FireBlockedEvent(); + return; + } + else if(nDoorIntelligence == 3)// 3 = Never tries anything against plot doors. + { + if(GetPlotFlag(oBlocker)) + { + FireBlockedEvent(); + return; + } + } + if(nInt >= 5) + { + // Need some intelligence :-) + if(nInt >= 7) + { + // Right, first, we may...shock...open it!!! + // Checks Key, lock, trap and if the action is possible. + if(GetIsDoorActionPossible(oBlocker, DOOR_ACTION_OPEN) && + !GetLocked(oBlocker) && + !GetIsTrapped(oBlocker) && + (!GetLockKeyRequired(oBlocker) || + (GetLockKeyRequired(oBlocker) && GetItemPossessor(GetObjectByTag(GetLockKeyTag(oBlocker))) == OBJECT_SELF))) + { + DoDoorAction(oBlocker, DOOR_ACTION_OPEN); + FireBlockedEvent(); + return; + } + // Unlock it with the skill, if it is not trapped and we can :-P + // We take 20 off the door DC, thats our minimum roll, after all. + if(GetLocked(oBlocker) && + !GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_OPENING_LOCKED_DOORS, AI_OTHER_COMBAT_MASTER) && + !GetLockKeyRequired(oBlocker) && GetHasSkill(SKILL_OPEN_LOCK) && + GetIsDoorActionPossible(oBlocker, DOOR_ACTION_UNLOCK) && !GetIsTrapped(oBlocker) && + (GetSkillRank(SKILL_OPEN_LOCK) >= (GetLockLockDC(oBlocker) - 20))) + { + DoDoorAction(oBlocker, DOOR_ACTION_UNLOCK); + FireBlockedEvent(); + return; + } + // Specilist thing - knock + if(nInt >= 10) + { + if((GetIsDoorActionPossible(oBlocker, DOOR_ACTION_KNOCK)) && + GetLockUnlockDC(oBlocker) <= 25 && + !GetLockKeyRequired(oBlocker) && GetHasSpell(SPELL_KNOCK)) + { + DoDoorAction(oBlocker, DOOR_ACTION_KNOCK); + FireBlockedEvent(); + return; + } + } + } + // If Our Int is over 5, we will bash after everything else. + if(GetIsDoorActionPossible(oBlocker, DOOR_ACTION_BASH) && !GetPlotFlag(oBlocker)) + { + if(GetAttackTarget() != oBlocker) + { + DoDoorAction(oBlocker, DOOR_ACTION_BASH); + } + FireBlockedEvent(); + return; + } + } + } + // Fire Blocked event + FireBlockedEvent(); +} +// Fires the end-blocked event. +void FireBlockedEvent() +{ + // Fire End-blocked-UDE + FireUserEvent(AI_FLAG_UDE_ON_BLOCKED_EVENT, EVENT_ON_BLOCKED_EVENT); +} +// Range attack oTarget. +int RangedAttack(object oTarget) +{ + // If we are primarily melee, don't use this + if(!GetSpawnInCondition(AI_FLAG_COMBAT_BETTER_AT_HAND_TO_HAND, AI_COMBAT_MASTER)) return FALSE; + + object oRangedTarget = oTarget; + if(!GetIsObjectValid(oRangedTarget)) + { + oRangedTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE); + if(!GetIsObjectValid(oTarget)) + { + oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD, CREATURE_TYPE_IS_ALIVE, TRUE); + // heard must be in LOS to attack, as we are probably stuck + if(!GetIsObjectValid(oTarget) && LineOfSightObject(OBJECT_SELF, oRangedTarget)) + { + return FALSE; + } + } + } + // Ranged weapon attack against oTarget + // doesn't matter we can see them + object oRanged = GetAIObject(AI_WEAPON_RANGED); + int nAmmo = GetAIInteger(AI_WEAPON_RANGED_AMMOSLOT); + + // Check ammo and validness + if(GetIsObjectValid(oRanged) && (nAmmo == INVENTORY_SLOT_RIGHTHAND || + GetIsObjectValid(GetItemInSlot(nAmmo)))) + { + // Attack with it + ClearAllActions(); + ActionEquipItem(oRanged, INVENTORY_SLOT_RIGHTHAND); + ActionAttack(oRangedTarget); + // Stop + return TRUE; + } + return FALSE; +} diff --git a/_module/nss/j_ai_oncombatrou.nss b/_module/nss/j_ai_oncombatrou.nss new file mode 100644 index 00000000..49589ab5 --- /dev/null +++ b/_module/nss/j_ai_oncombatrou.nss @@ -0,0 +1,37 @@ +/*/////////////////////// [On Combat Round End] //////////////////////////////// + Filename: nw_c2_default3 or J_AI_OnCombatrou +///////////////////////// [On Combat Round End] //////////////////////////////// + This is run every 3 or 6 seconds, if the creature is in combat. It is + executed only in combat automatically. + + It runs what the AI should do, bascially. +///////////////////////// [History] //////////////////////////////////////////// + 1.3 - Executes same script as the other parts of the AI to cuase a new action + 1.4 - +///////////////////////// [Workings] /////////////////////////////////////////// + Calls the combat AI file using the J_INC_OTHER_AI include function, + DetermineCombatRound. +///////////////////////// [Arguments] ////////////////////////////////////////// + Arguments: GetAttackTarget, GetLastHostileActor, GetAttemptedAttackTarget, + GetAttemptedSpellTarget (Or these are useful at least!) +///////////////////////// [On Combat Round End] //////////////////////////////*/ + +#include "J_INC_OTHER_AI" + +void main() +{ + // Pre-combat-round-event. Returns TRUE if we interrupt this script call. + if(FirePreUserEvent(AI_FLAG_UDE_END_COMBAT_ROUND_PRE_EVENT, EVENT_END_COMBAT_ROUND_PRE_EVENT)) return; + + // AI status check. Is the AI on? + if(GetAIOff()) return; + + // It is our normal call (every 3 or 6 seconds, when we can change actions) + // so no need to delete, and we fire the UDE's. + + // Determine combat round against an invalid target (as default) + DetermineCombatRound(); + + // Fire End of end combat round event + FireUserEvent(AI_FLAG_UDE_END_COMBAT_ROUND_EVENT, EVENT_END_COMBAT_ROUND_EVENT); +} diff --git a/_module/nss/j_ai_onconversat.nss b/_module/nss/j_ai_onconversat.nss new file mode 100644 index 00000000..d1ef2e5f --- /dev/null +++ b/_module/nss/j_ai_onconversat.nss @@ -0,0 +1,160 @@ +/*/////////////////////// [On Conversation] //////////////////////////////////// + Filename: J_AI_OnConversat or nw_c2_default4 +///////////////////////// [On Conversation] //////////////////////////////////// + OnConversation/ Listen to shouts. + Documented, and checked. -Working- + + Added spawn in condition - Never clear actions when talking. +///////////////////////// [History] //////////////////////////////////////////// + 1.3 - Added in conversation thing - IE we can set speakstrings, no need for conversation file. + - Sorted more shouts out. + - Should work right, and not cause too many actions (as we ignore + shouts for normally 12 or so seconds before letting them affect us again). + 1.4 - Deafness incorpreated. +///////////////////////// [Workings] /////////////////////////////////////////// + Uses RespondToShout to react to allies' shouts, and just attacks any enemy + who speaks, or at least moves to them. (OK, dumb if they are invisible, but + oh well, they shouldn't talk so loud!) + + Remember, whispers are never heard if too far away, speakstrings don't go + through walls, and shouts are always heard (so we don't go off to anyone + not in our area, remember) + + Deafness causes us to never hear battle, so unless we see the target speaking + we do not react. Doesn't apply to normal conversations - although if we cannot + talk (also restricted by deafness) then so be it. +///////////////////////// [Arguments] ////////////////////////////////////////// + Arguments: GetListenPatternNumber, GetLastSpeaker, TestStringAgainstPattern, + GetMatchedSubstring +///////////////////////// [On Conversation] //////////////////////////////////*/ + +#include "J_INC_OTHER_AI" + +void main() +{ + // Pre-conversation-event. Returns TRUE if we interrupt this script call. + if(FirePreUserEvent(AI_FLAG_UDE_ON_DIALOGUE_PRE_EVENT, EVENT_ON_DIALOGUE_PRE_EVENT)) return; + + // AI status check. Is the AI on? + if(GetAIOff()) return; + + // Declarations + int nMatch = GetListenPatternNumber(); + object oShouter = GetLastSpeaker(); + string sSpoken = GetMatchedSubstring(0); + + // We can ignore everything under special cases - EG no valid shouter, + // we are fleeing, its us, or we are not in the same area. + // - We break out of the script if this happens. + if(!GetIsObjectValid(oShouter) || /* Must be a valid speaker! */ + oShouter == OBJECT_SELF || /* Not us! */ + GetIsPerformingSpecialAction() || /* Not fleeing */ + GetIgnore(oShouter) || /* Not ignoring the shouter */ + GetArea(oShouter) != GetArea(OBJECT_SELF))/* Same area (Stops loud yellow shouts getting NPCs) */ + { + // Fire End of Dialogue event + FireUserEvent(AI_FLAG_UDE_ON_DIALOGUE_EVENT, EVENT_ON_DIALOGUE_EVENT); + return; + } + + // Conversation if not a shout. + if(nMatch == -1) + { + // * Don't speak when dead. 1.4 change (an obvious one to make) + if(CanSpeak()) + { + // Make sure it is a PC and we are not fighting. + if(!GetIsFighting() && (GetIsPC(oShouter) || GetIsDMPossessed(oShouter))) + { + // If we have something random (or not) to say instead of + // the conversation, we will say that. + if(GetLocalInt(OBJECT_SELF, ARRAY_SIZE + AI_TALK_ON_CONVERSATION)) + { + ClearAllActions();// Stop + SetFacingPoint(GetPosition(oShouter));// Face + SpeakArrayString(AI_TALK_ON_CONVERSATION);// Speak string + PlayAnimation(ANIMATION_LOOPING_TALK_NORMAL, 1.0, 3.0);// "Talk", then resume potitions. + ActionDoCommand(ExecuteScript(FILE_WALK_WAYPOINTS, OBJECT_SELF)); + } + else + { + // If we are set to NOT clear all actions, we won't. + if(!GetSpawnInCondition(AI_FLAG_OTHER_NO_CLEAR_ACTIONS_BEFORE_CONVERSATION, AI_OTHER_MASTER)) + { + ClearAllActions(); + } + BeginConversation(); + } + } + } + } + // If it is a valid shout...and a valid shouter. + // - Not a DM. Not ignoring shouting. Not a Debug String. + else if(!GetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID) &&// Not listening (IE heard already) + !GetIsDM(oShouter) && FindSubString(sSpoken, "[Debug]") == -1 && + // 1.4 - Deafness (or they are seen) check, for fun. + (!GetHasEffect(EFFECT_TYPE_DEAF) || GetObjectSeen(oShouter))) + { + if(GetIsFriend(oShouter) || GetFactionEqual(oShouter)) + { + // If they are a friend, not a PC, and a valid number, react. + // In the actual RespondToShout call, we do check to see if we bother. + // - Is PC - or is...master? + // - Shouts which are not negative, and not AI_ANYTHING_SAID_CONSTANT. + if(nMatch >= 0 && nMatch != AI_SHOUT_ANYTHING_SAID_CONSTANT && + !GetIsPC(oShouter) && !GetIsPC(GetMaster(oShouter))) + { + // Respond to the shout + RespondToShout(oShouter, nMatch); + } + // Else either is PC or is shout 0 (everything!) + // - not if we are in combat, or they are not. + else if(!CannotPerformCombatRound() && + GetIsInCombat(oShouter) && + GetObjectType(oShouter) == OBJECT_TYPE_CREATURE) + { + // 57: "[Shout] Friend (may be PC) in combat. Attacking! [Friend] " + GetName(oShouter) + DebugActionSpeakByInt(57, oShouter); + + // Respond to oShouter + IWasAttackedResponse(oShouter); + } + } + else if(GetIsEnemy(oShouter) && GetObjectType(oShouter) == OBJECT_TYPE_CREATURE) + { + // If we hear anything said by an enemy, and are not fighting, attack them! + if(!CannotPerformCombatRound()) + // the negatives are associate shouts, Normally (!) + // 0+ are my shouts. 0 is anything + { + // We make sure it isn't an emote (set by default) + if(nMatch == AI_SHOUT_ANYTHING_SAID_CONSTANT && + GetSpawnInCondition(AI_FLAG_OTHER_DONT_RESPOND_TO_EMOTES, AI_OTHER_MASTER)) + { + // Jump out if its an emote - "*Nods*" + if(GetStringLeft(sSpoken, 1) == EMOTE_STAR && + GetStringRight(sSpoken, 1) == EMOTE_STAR) + { + // Fire End of Dialogue event + FireUserEvent(AI_FLAG_UDE_ON_DIALOGUE_EVENT, EVENT_ON_DIALOGUE_EVENT); + return; + } + } + // 58: "[Shout] Responding to shout [Enemy] " + GetName(oShouter) + " Who has spoken!" + DebugActionSpeakByInt(58, oShouter); + + // Short non-respond + SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, 6.0); + + // Attack the enemy! + ClearAllActions(); + DetermineCombatRound(oShouter); + + // Shout to allies to attack the shouter + AISpeakString(AI_SHOUT_I_WAS_ATTACKED); + } + } + } + // Fire End of Dialogue event + FireUserEvent(AI_FLAG_UDE_ON_DIALOGUE_EVENT, EVENT_ON_DIALOGUE_EVENT); +} diff --git a/_module/nss/j_ai_ondamaged.nss b/_module/nss/j_ai_ondamaged.nss new file mode 100644 index 00000000..596caa3e --- /dev/null +++ b/_module/nss/j_ai_ondamaged.nss @@ -0,0 +1,241 @@ +/*/////////////////////// [On Damaged] ///////////////////////////////////////// + Filename: nw_c2_default6 or J_AI_OnDamaged +///////////////////////// [On Damaged] ///////////////////////////////////////// + We attack any damager if same area (and not already fighting + then search for enemies (defaults to searching if there are no enemies left). +///////////////////////// [History] //////////////////////////////////////////// + 1.3 - If we have a damager, not equal faction, and not a DM... + - We set Max Elemental damage. + - Sets the highest damager and amount (if the new damager is seen/heard) + - Polymorph improved a little + - Hide check + - Morale penalty (if set) + 1.4 - Elemental damage fixed with bugfixed introduced in later patches. + - Moved things around, more documentation, a little more ordered. + - Added the missing silent shout strings to get allies to attack. + - Damaged taunting will not happen if we are dead. +///////////////////////// [Workings] /////////////////////////////////////////// + Now with fixes, we can correctly set physical damage done (and elemental + damage). + + Otherwise, this acts like a hositile spell, or a normal attack or pickpocket + attempt would - and attack the damn person who dares damage us! +///////////////////////// [Arguments] ////////////////////////////////////////// + Arguments: GetTotalDamageDealt, GetLastDamager, GetCurrentHitPoints (and max), + GetDamageDealtByType (must be done seperatly for each, doesn't count melee damage) +///////////////////////// [On Damaged] ///////////////////////////////////////*/ + +#include "J_INC_OTHER_AI" + +void main() +{ + // Pre-damaged-event. Returns TRUE if we interrupt this script call. + if(FirePreUserEvent(AI_FLAG_UDE_DAMAGED_PRE_EVENT, EVENT_DAMAGED_PRE_EVENT)) return; + + // AI status check. Is the AI on? + if(GetAIOff()) return; + + // Define Objects/Integers. + int nDamage = GetTotalDamageDealt(); + object oDamager = GetLastDamager(); + // Check to see if we will polymorph. + int nPolymorph = GetAIConstant(AI_POLYMORPH_INTO); + + // Total up the physical damage + + // Polymorph check. + if(nPolymorph >= 0) + { + // We won't polymorph if already so + if(!GetHasEffect(EFFECT_TYPE_POLYMORPH)) + { + // Polymorph into the requested shape. Cannot be dispelled. + effect eShape = SupernaturalEffect(EffectPolymorph(nPolymorph)); + effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD); + DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_PERMANENT, eShape, OBJECT_SELF)); + DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, OBJECT_SELF)); + } + DeleteAIConstant(AI_POLYMORPH_INTO);// We set it to invalid (sets to 0). + } + // First, we check AOE spells... + if(GetObjectType(oDamager) == OBJECT_TYPE_AREA_OF_EFFECT) + { + // Set the damage done by it (the last damage) + // Set to the tag of the AOE, prefixed AI style to be sure. + // - Note, doesn't matter about things like + if(nDamage > 0) + { + // Set it to object to string, which we will delete later anywho. + SetAIInteger(ObjectToString(oDamager), nDamage); + } + } + // Hostile attacker...but it doesn't matter (at the moment) if they even + // did damage. + // * GetIgnoreNoFriend() wrappers DM, Validity, Faction Equal and Dead checks in one + else if(!GetIgnoreNoFriend(oDamager)) + { + // Adjust automatically if set. (and not an AOE) + if(GetSpawnInCondition(AI_FLAG_OTHER_CHANGE_FACTIONS_TO_HOSTILE_ON_ATTACK, AI_OTHER_MASTER)) + { + if(!GetIsEnemy(oDamager) && !GetFactionEqual(oDamager)) + { + AdjustReputation(oDamager, OBJECT_SELF, -100); + } + } + + // Turn of hiding, a timer to activate Hiding in the main file. This is + // done in each of the events, with the opposition checking seen/heard. + TurnOffHiding(oDamager); + + // Did they do damage to use? (IE: No DR) Some things are inapproprate + // to check if no damage was actually done. + if(nDamage > 0) + { + // Speak the damaged string, if applicable. + // * Don't speak when dead. 1.4 change (an obvious one to make) + if(CanSpeak()) + { + SpeakArrayString(AI_TALK_ON_DAMAGED); + } + // 1.4 note: These two variables are currently *unused* apart from + // healing. When healing a being (even another NPC) they are checked + // for massive damage. Can not bother to set the highest damager for now. + // NEW: + int nHighestDamage = GetAIInteger(AI_HIGHEST_DAMAGE_AMOUNT); + if(nDamage >= nHighestDamage) + { + SetAIInteger(AI_HIGHEST_DAMAGE_AMOUNT, nDamage); + } + + /* OLD: + + // Get the previous highest damager, and highest damage amount + object oHighestDamager = GetAIObject(AI_HIGHEST_DAMAGER); + int nHighestDamage = GetAIInteger(AI_HIGHEST_DAMAGE_AMOUNT); + // Set the highest damager, if they are seen or heard, and have done loads. + if((GetObjectSeen(oDamager) || GetObjectHeard(oDamager)) && + nDamage >= nHighestDamage || !GetIsObjectValid(oHighestDamager)) + { + SetAIObject(AI_HIGHEST_DAMAGER, oDamager); + SetAIInteger(AI_HIGHEST_DAMAGE_AMOUNT, nDamage); + } + // Else, if the original was not valid...or not seen/heard, we + // delete it so we don't bother to use it later. + else if(!GetIsObjectValid(oHighestDamager) || + (!GetObjectSeen(oHighestDamager) && !GetObjectHeard(oHighestDamager))) + { + DeleteAIObject(AI_HIGHEST_DAMAGER); + DeleteAIInteger(AI_HIGHEST_DAMAGE_AMOUNT); + } + */ + + // Get all the physical damage. Elemental damage is then nDamage minus + // the physical damage. + int nPhysical = GetDamageDealtByType(DAMAGE_TYPE_BASE_WEAPON | + DAMAGE_TYPE_BLUDGEONING | + DAMAGE_TYPE_PIERCING | + DAMAGE_TYPE_SLASHING); + // If they are all -1, then we make nPhysical 0. + if(nPhysical <= -1) nPhysical = 0; + + // Physical damage - only sets if the last damager is the last attacker. + if(GetAIObject(AI_STORED_LAST_ATTACKER) == oDamager) + { + // Get the previous highest damage and test it + if(nPhysical > GetAIInteger(AI_HIGHEST_PHISICAL_DAMAGE_AMOUNT)) + { + // If higher, and was a melee/ranged attacker, set it. + // This does include other additional physical damage - EG: + // weapon property: Bonus Damage. + SetAIInteger(AI_HIGHEST_PHISICAL_DAMAGE_AMOUNT, nPhysical); + } + } + + // Set the max elemental damage done, for better use of elemental + // protections. This is set for the most damage...so it could be + // 1 (for a +1 fire weapon, any number of hits) or over 50 (good + // fireball/flame storm etc.) + int nElemental = nDamage - nPhysical; + if(nElemental > GetAIInteger(MAX_ELEMENTAL_DAMAGE)) + { + SetAIInteger(MAX_ELEMENTAL_DAMAGE, nElemental); + } + // Set the last damage done, may set to 0 of course :-P + // * This is only set if they did damage us at all, however. + SetAIInteger(LAST_ELEMENTAL_DAMAGE, nElemental); + + // Morale: We may get a penalty if it does more than a cirtain amount of HP damage. + // Other: We set highest damager and amount. + if(!GetSpawnInCondition(AI_FLAG_FLEEING_FEARLESS, AI_TARGETING_FLEE_MASTER)) + { + // Get penalty and how much damage at once needs to be done + int nPenalty = GetBoundriedAIInteger(AI_DAMAGE_AT_ONCE_PENALTY, 6, 50, 1); + int nToDamage = GetBoundriedAIInteger(AI_DAMAGE_AT_ONCE_FOR_MORALE_PENALTY, GetMaxHitPoints()/6, GetMaxHitPoints(), 1); + if(nDamage > nToDamage) + { + // 61: "[Damaged] Morale Penalty for 600 seconds [Penalty]" + IntToString(iPenalty) + DebugActionSpeakByInt(61, OBJECT_INVALID, nPenalty); + // Apply penalty + SetMoralePenalty(nPenalty, 300.0); + } + } + } + // If we are not attacking anything, and not in combat, react! + if(!CannotPerformCombatRound()) + { + // 62: "[Damaged] Not in combat: DCR [Damager]" + GetName(oDamager) + DebugActionSpeakByInt(62, oDamager); + + // Check if they are in the same area. Can be a left AOE spell. + // Don't attack purposly across area's. + if(GetArea(oDamager) == GetArea(OBJECT_SELF)) + { + // Shout to allies to attack the enemy who attacked me + AISpeakString(AI_SHOUT_I_WAS_ATTACKED); + + DetermineCombatRound(oDamager); + } + else + { + // Shout to allies to attack, or be prepared. + AISpeakString(AI_SHOUT_CALL_TO_ARMS); + + DetermineCombatRound(); + } + } + else + { + // Shout to allies to attack, or be prepared. + AISpeakString(AI_SHOUT_CALL_TO_ARMS); + } + } + // Else it is friendly, or invalid damager + else + { + // Still will react - eg: A left AOE spell (which might mean a battle + // just happened) + if(!CannotPerformCombatRound()) + { + // Shout to allies to attack generally. No target to specifically attack, + // as it is an ally. + AISpeakString(AI_SHOUT_CALL_TO_ARMS); + + // 63: [Damaged] Not in combat: DCR. Ally hit us. [Damager(Ally?)]" + GetName(oDamager) + DebugActionSpeakByInt(63, oDamager); + DetermineCombatRound(); + } + else + { + // Shout to allies to attack, or be prepared. + AISpeakString(AI_SHOUT_CALL_TO_ARMS); + } + } + // User defined event - for normally immoral creatures. + if(GetCurrentHitPoints() == 1) + { + // Fire the immortal damaged at 1 HP event. + FireUserEvent(AI_FLAG_UDE_DAMAGED_AT_1_HP, EVENT_DAMAGED_AT_1_HP); + } + // Fire End of Damaged event + FireUserEvent(AI_FLAG_UDE_DAMAGED_EVENT, EVENT_DAMAGED_EVENT); +} diff --git a/_module/nss/j_ai_ondeath.nss b/_module/nss/j_ai_ondeath.nss new file mode 100644 index 00000000..c8fcf672 --- /dev/null +++ b/_module/nss/j_ai_ondeath.nss @@ -0,0 +1,164 @@ +/*/////////////////////// [On Death] /////////////////////////////////////////// + Filename: J_AI_OnDeath or nw_c2_default7 +///////////////////////// [On Death] /////////////////////////////////////////// + Speeded up no end, when compiling, with seperate Include. + Cleans up all un-droppable items, all ints and all local things when destroyed. + + Check down near the bottom for a good place to add XP or corpse lines ;-) +///////////////////////// [History] //////////////////////////////////////////// + 1.3 - Added in Turn of corpses toggle + - Added in appropriate space for XP awards, marked with ideas (effect death) + 1.4 - Removed the redudnant notes on the "You have gained 0 experience" message +///////////////////////// [Workings] /////////////////////////////////////////// + You can edit this for experience, there is a seperate section for it. + + It will use DeathCheck to execute a cleanup-and-destroy script, that removes + any coprse, named "j_ai_destroyself". +///////////////////////// [Arguments] ////////////////////////////////////////// + Arguments: GetLastKiller. +///////////////////////// [On Death] /////////////////////////////////////////*/ + +// We only require the constants/debug file. We have 1 function, not worth another include. +#include "J_INC_CONSTANTS" + +// We need a wrapper. If the amount of deaths, got in this, is not equal to iDeaths, +// we don't execute the script, else we do. :-P +void DeathCheck(int nDeaths); + +void main() +{ + // If we are set to, don't fire this script at all + if(GetAIInteger(I_AM_TOTALLY_DEAD)) return; + + // Pre-death-event. Returns TRUE if we interrupt this script call. + if(FirePreUserEvent(AI_FLAG_UDE_DEATH_PRE_EVENT, EVENT_DEATH_PRE_EVENT)) return; + + // Note: No AI on/off check here. + + // Who killed us? (alignment changing, debug, XP). + object oKiller = GetLastKiller(); + + // Stops if we just applied EffectDeath to ourselves. + if(GetLocalTimer(AI_TIMER_DEATH_EFFECT_DEATH)) return; + + // Special: To stop giving out multiple amounts of XP, we use EffectDeath + // to change the killer, so the XP systems will NOT award MORE XP. + // - Even the default one suffers from this! + if(GetAIInteger(WE_HAVE_DIED_ONCE)) + { + if(!GetLocalTimer(AI_TIMER_DEATH_EFFECT_DEATH)) + { + // Don't apply effect death to self more then once per 2 seconds. + SetLocalTimer(AI_TIMER_DEATH_EFFECT_DEATH, 2.0); + // This should make the last killer us. + ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectResurrection(), OBJECT_SELF); + ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(GetMaxHitPoints()), OBJECT_SELF); + } + } + else if(oKiller != OBJECT_SELF) + { + // Set have died once, stops giving out mulitple amounts of XP. + SetAIInteger(WE_HAVE_DIED_ONCE, TRUE); + +/*/////////////////////// [Experience] ///////////////////////////////////////// + THIS is the place for it, below this comment. + + It is useful to use GetFirstFactionMember (and Next), GiveXPToCreature, + GetXP, SetXP, GetChallengeRating (of self) all are really useful. + + Bug note: GetFirstFactionMember/Next with the PC parameter means either ONLY PC, + and so NPC henchmen, unless FALSE is used, will not be even recognised. +///////////////////////// [Experience] ///////////////////////////////////////*/ + // Do XP things (Use object "oKiller" for who killed us). + + + +/*/////////////////////// [Experience] ///////////////////////////////////////*/ + } + + // Note: Here we do a simple way of checking how many times we have died. + // Nothing special. Debugging most useful aspect. + int nDeathCounterNew = GetAIInteger(AMOUNT_OF_DEATHS); + nDeathCounterNew++; + SetAIInteger(AMOUNT_OF_DEATHS, nDeathCounterNew); + + // Here is the last time (in game seconds) we died. It is used in the executed script + // to make sure we don't prematurly remove areselves. + + // We may want some sort of visual effect - like implosion or something, to fire. + int nDeathEffect = GetAIConstant(AI_DEATH_VISUAL_EFFECT); + + // Valid constants from 0 and up. Apply to our location (not to us, who will go!) + if(nDeathEffect >= 0) + { + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(nDeathEffect), GetLocation(OBJECT_SELF)); + } + // Default Commoner alignment changing. (If the commoner is not evil!) + if(GetLevelByClass(CLASS_TYPE_COMMONER) > 0 && + GetAlignmentGoodEvil(OBJECT_SELF) != ALIGNMENT_EVIL && + !GetSpawnInCondition(AI_FLAG_OTHER_NO_COMMONER_ALIGNMENT_CHANGE, AI_OTHER_MASTER)) + { + if(GetIsPC(oKiller)) + { + AdjustAlignment(oKiller, ALIGNMENT_EVIL, 5); + } + else + { + // If it is a summon, henchmen or familar of a PC, we adust the PC itself + // Clever, eh? + object oMaster = GetMaster(oKiller); + if(GetIsObjectValid(oMaster) && GetIsPC(oMaster)) + { + AdjustAlignment(oMaster, ALIGNMENT_EVIL, 5); + } + } + } + // Always shout when we are killed. Reactions - Morale penalty, and + // attack the killer. + AISpeakString(AI_SHOUT_I_WAS_KILLED); + + // Speaks the set death speak, like "AGGGGGGGGGGGGGGGGGGG!! NOOOO!" for instance :-) + // Note for 1.4: No need for "CanSpeak()" for this, of course. + SpeakArrayString(AI_TALK_ON_DEATH); + + // First check - do we use "destroyable corpses" or not? (default, yes) + if(!GetSpawnInCondition(AI_FLAG_OTHER_TURN_OFF_CORPSES, AI_OTHER_MASTER)) + { + // We will actually dissapear after 30.0 seconds if not raised. + int nTime = GetAIInteger(AI_CORPSE_DESTROY_TIME); + if(nTime == 0) // Error checking + { + nTime = 30; + } + // 64: "[Death] Checking corpse status in " + IntToString(nTime) + " [Killer] " + GetName(oKiller) + " [Times Died Now] " + IntToString(nDeathCounterNew) + DebugActionSpeakByInt(64, oKiller, nTime, IntToString(nDeathCounterNew)); + // Delay check + DelayCommand(IntToFloat(nTime), DeathCheck(nDeathCounterNew)); + } + else + { +/************************ [Alternative Corpses] ******************************** + This is where you can add some alternative corpse code - EG looting + and so on, without disrupting the rest of the AI (as the corpses + are turned off). +************************* [Alternative Corpses] *******************************/ + // Add alternative corpse code here + + +/************************ [Alternative Corpses] *******************************/ + } + // Signal the death event. + FireUserEvent(AI_FLAG_UDE_DEATH_EVENT, EVENT_DEATH_EVENT); +} + +// We need a wrapper. If the amount of deaths, got in this, is not equal to iDeaths, +// we don't execute the script, else we do. :-P +void DeathCheck(int nDeaths) +{ + // Do the deaths imputted equal the amount we have suffered? + if(GetAIInteger(AMOUNT_OF_DEATHS) == nDeaths) + { + // - This now includes a check for Bioware's lootable functions and using them. + ExecuteScript(FILE_DEATH_CLEANUP, OBJECT_SELF); + } +} diff --git a/_module/nss/j_ai_ondisturbed.nss b/_module/nss/j_ai_ondisturbed.nss new file mode 100644 index 00000000..1eb8f908 --- /dev/null +++ b/_module/nss/j_ai_ondisturbed.nss @@ -0,0 +1,85 @@ +/*/////////////////////// [On Disturbed] /////////////////////////////////////// + Filename: J_AI_OnDisturbed or nw_c2_default8 +///////////////////////// [On Disturbed] /////////////////////////////////////// + This will attack pickpockets, and inventory disturbers. Note: Stupidly, Bioware + made this only affect the creature by stealing. Still, oh well :-( + + This means that the only event which fires it is pickpocketing. +///////////////////////// [History] //////////////////////////////////////////// + 1.3 - Changed why we determine combat round + - Any change in inventory will trigger appropriate SetWeapons again. + - Added turn of hide things. + 1.4 - Cleaned up a bit. Removed unused declared variable. +///////////////////////// [Workings] /////////////////////////////////////////// + Only fired by stealing, great. Oh well, it will attack any disturber anyway. + + It *might* not be fired if the natural spot check to notice a theft doesn't + work. No idea personally. +///////////////////////// [Arguments] ////////////////////////////////////////// + Arguments: GetInventoryDisturbItem, GetLastDisturbed, + GetInventoryDisturbType (I think it is always be stolen :-( ). +///////////////////////// [On Disturbed] /////////////////////////////////////*/ + +#include "J_INC_OTHER_AI" + +void main() +{ + // Pre-disturbed-event. Returns TRUE if we interrupt this script call. + if(FirePreUserEvent(AI_FLAG_UDE_DISTURBED_PRE_EVENT, EVENT_DISTURBED_PRE_EVENT)) return; + + // AI status check. Is the AI on? + if(GetAIOff()) return; + + // Declare major variables + object oDisturber = GetLastDisturbed(); + object oItem = GetInventoryDisturbItem(); + int nType = GetInventoryDisturbType(); + int nBase = GetBaseItemType(oItem); + + // We will reset weapons if it is a weapon. + // Reset weapons, or specifically healers kits. + if(GetIsObjectValid(oItem)) + { + // Kits + if(nBase == BASE_ITEM_HEALERSKIT) + { + SetLocalInt(OBJECT_SELF, AI_WEAPONSETTING_SETWEAPONS, 2); + ExecuteScript(FILE_RE_SET_WEAPONS, OBJECT_SELF); + } + else // Think it is a weapon. Saves time :-) + { + SetLocalInt(OBJECT_SELF, AI_WEAPONSETTING_SETWEAPONS, 1); + ExecuteScript(FILE_RE_SET_WEAPONS, OBJECT_SELF); + } + } + // Fight! Or search! + if(!GetIgnoreNoFriend(oDisturber) && + (nType == INVENTORY_DISTURB_TYPE_STOLEN || GetIsEnemy(oDisturber))) + { + // Turn of hiding, a timer to activate Hiding in the main file. This is + // done in each of the events, with the opposition checking seen/heard. + TurnOffHiding(oDisturber); + + // Can we attack? + if(!CannotPerformCombatRound()) + { + // Someone specific to attack + AISpeakString(AI_SHOUT_I_WAS_ATTACKED); + + // One debug speak. We always do one. + // 65: "[Disturbed] (pickpocket) Attacking Enemy Distrube [Disturber] " + GetName(oTarget) + " [Type] " + IntToString(iType) + DebugActionSpeakByInt(65, oDisturber, nType); + + // Attack the disturber + DetermineCombatRound(oDisturber); + } + else + { + // Get allies interested. + AISpeakString(AI_SHOUT_CALL_TO_ARMS); + } + } + + // Fire End-heartbeat-UDE + FireUserEvent(AI_FLAG_UDE_DISTURBED_EVENT, EVENT_DISTURBED_EVENT); +} diff --git a/_module/nss/j_ai_onheartbeat.nss b/_module/nss/j_ai_onheartbeat.nss new file mode 100644 index 00000000..e32ef925 --- /dev/null +++ b/_module/nss/j_ai_onheartbeat.nss @@ -0,0 +1,114 @@ +/*/////////////////////// [On Heartbeat] /////////////////////////////////////// + Filename: nw_c2_default1 or J_AI_OnHeartbeat +///////////////////////// [On Heartbeat] /////////////////////////////////////// + Removed stupid stuff, special behaviour, sleep. + + Also, note please, I removed waypoints and day/night posting from this. + It can be re-added if you like, but it does reduce heartbeats. + + Added in better checks to see if we should fire this script. Stops early if + some conditions (like we can't move, low AI settings) are set. + + Hint: If nothing is used within this script, either remove it from creatures + or create one witch is blank, with just a "void main(){}" at the top. + + Hint 2: You could add this very small file to your catche of scripts in the + module properties, as it runs on every creature every 6 seconds (ow!) + + This also uses a system of Execute Script :-D This means the heartbeat, when + compiled, should be very tiny. + + Note: NO Debug strings! + Note 2: Remember, I use default SoU Animations/normal animations. As it is + executed, we can check the prerequisists here, and then do it VIA + execute script. + + -Working- Best possible, fast compile. +///////////////////////// [History] //////////////////////////////////////////// + 1.3 - Added more "buffs" to fast buff. + - Fixed animations (they both WORK and looping ones do loop right!) + - Loot behaviour! + - Randomly moving nearer a PC in 25M if set. + - Removed silly day/night optional setting. Anything we can remove, is a good idea. + 1.4 - Removed AI level setting. Not good to use, I mistakenly added it. +///////////////////////// [Workings] /////////////////////////////////////////// + This fires off every 6 seconds (with PCs in the area, or AI_LEVEL_HIGH without) + and therefore is intensive. + + It fires of ExecutesScript things for the different parts - saves CPU stuff + if the bits are not used. +///////////////////////// [Arguments] ////////////////////////////////////////// + Arguments: Basically, none. Nothing activates this script. Fires every 6 seconds. +///////////////////////// [On Heartbeat] /////////////////////////////////////*/ + +// - This includes J_Inc_Constants +#include "J_INC_HEARTBEAT" + +void main() +{ + // Special - Runner from the leader shouts, each heartbeat, to others to get thier + // attention that they are being attacked. + // - Includes fleeing making sure (so it resets the ActionMoveTo each 6 seconds - + // this is not too bad) + // - Includes door bashing stop heartbeat + if(PerformSpecialAction()) return; + + // Pre-heartbeat-event. Returns TRUE if we interrupt this script call. + if(FirePreUserEvent(AI_FLAG_UDE_HEARTBEAT_PRE_EVENT, EVENT_HEARTBEAT_PRE_EVENT)) return; + + // AI status check. Is the AI on? + if(GetAIOff() || GetSpawnInCondition(AI_FLAG_OTHER_LAG_IGNORE_HEARTBEAT, AI_OTHER_MASTER)) return; + + // Define the enemy and player to use. + object oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY); + object oPlayer = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC); + + // We can skip to the end if we are in combat, or something... + if(!JumpOutOfHeartBeat() && // We don't stop due to effects. + !GetIsInCombat() && // We are not in combat. + !GetIsObjectValid(GetAttackTarget()) && // Second combat check. + !GetObjectSeen(oEnemy)) // Nearest enemy is not seen. + { + // Fast buffing...if we have the spawn in condition... + if(GetSpawnInCondition(AI_FLAG_COMBAT_FLAG_FAST_BUFF_ENEMY, AI_COMBAT_MASTER) && + GetIsObjectValid(oEnemy) && GetDistanceToObject(oEnemy) <= 40.0) + { + // ...we may do an advanced buff. If we cannot see/hear oEnemy, but oEnemy + // is within 40M, we cast many defensive spells instantly... + ExecuteScript(FILE_HEARTBEAT_TALENT_BUFF, OBJECT_SELF); + //...if TRUE (IE it does something) we turn of future calls. + DeleteSpawnInCondition(AI_FLAG_COMBAT_FLAG_FAST_BUFF_ENEMY, AI_COMBAT_MASTER); + // This MUST STOP the heartbeat event - else, the actions may be interrupted. + return; + } + // Execute waypoints file if we have waypoints set up. + if(GetWalkCondition(NW_WALK_FLAG_CONSTANT)) + { + ExecuteScript(FILE_WALK_WAYPOINTS, OBJECT_SELF); + } + // We can't have any waypoints for the other things + else + { + // We must have animations set, and not be "paused", so doing a + // longer looping one + // - Need a valid player. + if(GetIsObjectValid(oPlayer) && !IsInConversation(OBJECT_SELF)) + { + // We may search for PC enemies, 25% chance to move closer to PC's + if(GetSpawnInCondition(AI_FLAG_OTHER_SEARCH_IF_ENEMIES_NEAR, AI_OTHER_MASTER) && + !GetLocalTimer(AI_TIMER_SEARCHING) && d4() == 1) + { + ExecuteScript(FILE_HEARTBEAT_WALK_TO_PC, OBJECT_SELF); + } + // Else, Do we have any animations to speak of? + // If we have a nearby PC, we do animations. + else if(GetHasValidAnimations()) + { + ExecuteScript(FILE_HEARTBEAT_ANIMATIONS, OBJECT_SELF); + } + } + } + } + // Fire End-heartbeat-UDE + FireUserEvent(AI_FLAG_UDE_HEARTBEAT_EVENT, EVENT_HEARTBEAT_EVENT); +} diff --git a/_module/nss/j_ai_onpercieve.nss b/_module/nss/j_ai_onpercieve.nss new file mode 100644 index 00000000..99987231 --- /dev/null +++ b/_module/nss/j_ai_onpercieve.nss @@ -0,0 +1,220 @@ +/*/////////////////////// [On Percieve] //////////////////////////////////////// + Filename: J_AI_OnPercieve or nw_c2_default2 +///////////////////////// [On Percieve] //////////////////////////////////////// + If the target is an enemy, attack + Will determine combat round on that person, is an enemy, basically. + Includes shouting for a big radius - if the spawn in condition is set to this. + + NOTE: Debug strings in this file will be uncommented for speed by default. + - It is one of the most intensive scripts as it runs so often. + - Attempted to optimise as much as possible. +///////////////////////// [History] //////////////////////////////////////////// + 1.3 - We include j_inc_other_ai to initiate combat (or go into combat again) + - j_inc_other_ai holds all other needed functions/integers ETC. + - Turn off hide things. + - Added "Only attack if attacked" + - Removed special conversation things. Almost no one uses them, and the taunt system is easier. + - Should now search around if they move to a dead body, and only once they get there. + 1.4 - TO DO: + + 1. Perception needs checking - attacking outside perception ranges! + 2. Vanishing targets, etc. test, improve. + 3. Problems with dispelling invisibility. Maybe either do change the line to create placable, or, of course, cast at location (dispells cannot be metamagiked or whatever) Source + 4. No Effect Type Ethereal. Source +///////////////////////// [Workings] /////////////////////////////////////////// + It fires: + + - When a creature enters it perception range (Set in creature properties) and + is seen or heard. + * Tests show (and in general) it fires HEARD first, then immediantly SEEN if, + of course, they are visible. Odd really, but true. + - When a creature uses invisiblity/leaves the area in the creatures perception + range + - When a creature appears suddenly, already in the perception range (not + the other way round, normally) + - When a creature moves out of the creatures perception range, and therefore + becomes unseen. +///////////////////////// [Arguments] ////////////////////////////////////////// + Arguments: GetLastPerceived, GetLastPerceptionSeen, GetLastPerceptionHeard, + GetLastPerceptionVanished, GetLastPerceptionInaudible. +///////////////////////// [On Percieve] //////////////////////////////////////*/ + +#include "J_INC_OTHER_AI" + +void main() +{ + // Pre-percieve-event. Returns TRUE if we interrupt this script call. + if(FirePreUserEvent(AI_FLAG_UDE_PERCIEVE_PRE_EVENT, EVENT_PERCIEVE_PRE_EVENT)) return; + + // AI status check. Is the AI on? + if(GetAIOff()) return; + + // Declare main things. + // - We declare OUTSIDE if's JUST IN CASE! + object oPerceived = GetLastPerceived(); + object oAttackTarget = GetAttackTarget(); + // 1.4: Very rarely is our attack target valid, so we will set it to + // what we would have melee attacked when DCR was called. + if(GetIgnoreNoFriend(oAttackTarget) || oAttackTarget == OBJECT_SELF) + { + oAttackTarget = GetAIObject(AI_LAST_MELEE_TARGET); + } + int bSeen = GetLastPerceptionSeen(); + int bHeard = GetLastPerceptionHeard(); + int bVanished = GetLastPerceptionVanished(); + int bInaudiable = GetLastPerceptionInaudible(); + + // Debug + DebugActionSpeak("*** PER ***: " + GetName(oPerceived) + "| SEEN: " + IntToString(bSeen) + + "| HEARD: " + IntToString(bHeard) + "| VANISHED: " + IntToString(bVanished) + + "| INAUDIABLE: " + IntToString(bInaudiable)); + + // Need to be valid and not ignorable. + if(GetIsObjectValid(oPerceived) && + !GetIsDM(oPerceived) && + !GetIgnore(oPerceived)) + { + // First, easy enemy checks. + if(GetIsEnemy(oPerceived) && !GetFactionEqual(oPerceived)) + { + DebugActionSpeak("*** PER *** ENEMY"); + + // Turn of hiding, a timer to activate Hiding in the main file. This is + // done in each of the events, with the opposition checking seen/heard. + TurnOffHiding(oPerceived); + + // Well, are we both inaudible and vanished? + // * the GetLastPerception should only say what specific event has fired! + if(bVanished || bInaudiable) + { + DebugActionSpeak("*** PER *** VANISHED OR INAUDIBLE"); + // If they just became invisible because of the spell + // invisiblity, or improved invisiblity...we set a local object. + // - Beta: Added in ethereal as well. + if(GetHasEffect(EFFECT_TYPE_INVISIBILITY, oPerceived) || + GetHasEffect(EFFECT_TYPE_SANCTUARY, oPerceived) || + GetStealthMode(oPerceived) == STEALTH_MODE_ACTIVATED) + { + // Set object, AND the location they went invisible! + SetAIObject(AI_LAST_TO_GO_INVISIBLE, oPerceived); + // We also set thier location for AOE dispelling - same name + SetAILocation(AI_LAST_TO_GO_INVISIBLE, GetLocation(oPerceived)); + } + + // If they were our target, follow! >:-D + // - Optional, on spawn option, for following through areas. + if(oAttackTarget == oPerceived) + { + DebugActionSpeak("*** PER *** VANISHED OR INAUDIBLE AND IS CURRENT TARGET"); + // This means they have exited the area! follow! + if(GetArea(oPerceived) != GetArea(OBJECT_SELF)) + { + ClearAllActions(); + // 51: "[Perception] Our Enemy Target changed areas. Stopping, moving too...and attack... [Percieved] " + GetName(oPerceived) + DebugActionSpeakByInt(51, oPerceived); + // Call to stop silly moving to enemies if we are fleeing + ActionMoveToEnemy(oPerceived); + } + // - Added check for not casting a spell. If we are, we finnish + // (EG: AOE spell) and automatically carry on. + // 1.4: If we are using a targetted spell, we do cancle our + // spellcasting if it is them. + else if(GetCurrentAction() != ACTION_CASTSPELL || + GetAttackTarget() == oPerceived) + { + ClearAllActions(); + // 52: "[Perception] Enemy Vanished (Same area) Retargeting/Searching [Percieved] " + GetName(oPerceived) + DebugActionSpeakByInt(52, oPerceived); + DetermineCombatRound(oPerceived); + } + } + }// End if just gone out of perception + // ELSE they have been SEEN or HEARD. We don't check specifics. + else //if(bSeen || bHeard) + { + // If they have been made seen, and they are our attack target, + // we must re-do combat round - unless we are casting a spell. + if(bSeen && GetCurrentAction() != ACTION_CASTSPELL && + (oAttackTarget == oPerceived || !GetObjectSeen(oAttackTarget))) + { + // 53: "[Perception] Enemy seen, and was old enemy/cannot see current. Re-evaluating (no spell) [Percieved] " + GetName(oPerceived) + DebugActionSpeakByInt(53, oPerceived); + DetermineCombatRound(oPerceived); + + // Shout to allies to attack oPerceived + AISpeakString(AI_SHOUT_I_WAS_ATTACKED); + } + // Else We check if we are already attacking. + else if(!CannotPerformCombatRound() && + !GetSpawnInCondition(AI_FLAG_OTHER_ONLY_ATTACK_IF_ATTACKED, AI_OTHER_MASTER)) + { + // * Don't speak when dead. 1.4 change (an obvious one to make) + if(CanSpeak()) + { + // Special shout, d1000 though! + SpeakArrayString(AI_TALK_ON_PERCIEVE_ENEMY, TRUE); + } + + // Stop stuff because of facing point - New enemy + HideOrClear(); + + // Get all allies in 60M to come to thier aid. Talkvolume silent + // shout does not seem to work well. + // - void function. Checks for the spawn int. in it. + // - Turns it off in it too (5 minutes - 1.4) + // - Variable range On Spawn + ShoutBossShout(oPerceived); + + // 54: "[Perception] Enemy Seen. Not in combat, attacking. [Percieved] " + GetName(oPerceived) + DebugActionSpeakByInt(54, oPerceived); + + // 1.4 change: SetFacingPoint(GetPosition(oPerceived)); + // Is now part of DetermineCombatRound(). + // * This means other events will work similarily. + DetermineCombatRound(oPerceived); + + // Warn others + AISpeakString(AI_SHOUT_I_WAS_ATTACKED); + } + } + } + // Else, they are an equal faction, or not an enemy (or both) + else + { + // If they are dead, or fighting, eg: we saw something on + // waypoints, we charge in to investigate. + // * Higher intelligence will buff somewhat as well! + if((GetIsDead(oPerceived) || GetIsInCombat(oPerceived)) && + (bSeen || bHeard)) + { + if(GetIsDead(oPerceived)) + { + // 55: "[Perception] Percieved Dead Friend! Moving into investigate [Percieved] " + GetName(oPerceived) + DebugActionSpeakByInt(55, oPerceived); + } + else + { + // 56: "[Perception] Percieved Alive Fighting Friend! Moving to and attacking. [Percieved] " + GetName(oPerceived) + DebugActionSpeakByInt(56, oPerceived); + } + // Check if we can attack + if(!CannotPerformCombatRound()) + { + // Hide or clear actions + HideOrClear(); + + // If we were called to arms, react + CallToArmsResponse(oPerceived); + } + else + { + // Warn others even if we don't, or cannot, attack + AISpeakString(AI_SHOUT_CALL_TO_ARMS); + } + } + } + } + + // Fire End of Percieve event + FireUserEvent(AI_FLAG_UDE_PERCIEVE_EVENT, EVENT_PERCIEVE_EVENT); +} diff --git a/_module/nss/j_ai_onphiattack.nss b/_module/nss/j_ai_onphiattack.nss new file mode 100644 index 00000000..d529a447 --- /dev/null +++ b/_module/nss/j_ai_onphiattack.nss @@ -0,0 +1,136 @@ +/*/////////////////////// [On Phisical Attacked] /////////////////////////////// + Filename: J_AI_OnPhiAttack or nw_c2_default5 +///////////////////////// [On Phisical Attacked] /////////////////////////////// + On Attacked + No checking for fleeing or warnings. + Very boring really! +///////////////////////// [History] //////////////////////////////////////////// + 1.3 - Added hiding things + 1.4 - Missing Silent Shouts have been added. +///////////////////////// [Workings] /////////////////////////////////////////// + Got some simple Knockdown timer, so that we use heal sooner if we keep getting + a creature who is attempting to knock us down. +///////////////////////// [Arguments] ////////////////////////////////////////// + Arguments: GetLastAttacker, GetLastWeaponUsed, GetLastAttackMode, GetLastAttackType +///////////////////////// [On Phisical Attacked] /////////////////////////////*/ + +#include "J_INC_OTHER_AI" + +void main() +{ + // Pre-attacked-event. Returns TRUE if we interrupt this script call. + if(FirePreUserEvent(AI_FLAG_UDE_ATTACK_PRE_EVENT, EVENT_ATTACK_PRE_EVENT)) return; + + // AI status check. Is the AI on? + if(GetAIOff()) return; + + // Set up objects. + object oAttacker = GetLastAttacker(); + object oWeapon = GetLastWeaponUsed(oAttacker); + //int nMode = GetLastAttackMode(oAttacker); // Currently unused + int nAttackType = GetLastAttackType(oAttacker); + + // Check if they are valid, a DM, we are ignoring them, they are dead now, or invalid + if(!GetIgnoreNoFriend(oAttacker)) + { + // Adjust automatically if set. + if(GetSpawnInCondition(AI_FLAG_OTHER_CHANGE_FACTIONS_TO_HOSTILE_ON_ATTACK, AI_OTHER_MASTER)) + { + if(!GetIsEnemy(oAttacker)) + { + AdjustReputation(oAttacker, OBJECT_SELF, -100); + } + } + + // If we were attacked by knockdown, for a timer of X seconds, we make + // sure we attempt healing at a higher level. + if(!GetLocalTimer(AI_TIMER_KNOCKDOWN) && + (nAttackType == SPECIAL_ATTACK_IMPROVED_KNOCKDOWN || + nAttackType == SPECIAL_ATTACK_KNOCKDOWN) && + !GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_KNOCKDOWN) && + GetBaseAttackBonus(oAttacker) + 20 >= GetAC(OBJECT_SELF)) + { + SetLocalTimer(AI_TIMER_KNOCKDOWN, 30.0); + } + + // Set last hostile, valid attacker (Used in the On Damaged event) + SetAIObject(AI_STORED_LAST_ATTACKER, oAttacker); + + // * Don't speak when dead. 1.4 change (an obvious one to make) + if(CanSpeak()) + { + // Speak the phisically attacked string, if applicable. + // Speak the damaged string, if applicable. + SpeakArrayString(AI_TALK_ON_PHISICALLY_ATTACKED); + } + + // Turn of hiding, a timer to activate Hiding in the main file. This is + // done in each of the events, with the opposition checking seen/heard. + TurnOffHiding(oAttacker); + + // We set if we are attacked in HTH onto a low-delay timer. + // - Not currently used + /*if(!GetLocalTimer(AI_TIMER_ATTACKED_IN_HTH)) + { + // If the weapon is not ranged, or is not valid, set the timer. + if(!GetIsObjectValid(oWeapon) || + !GetWeaponRanged(oWeapon)) + { + SetLocalTimer(AI_TIMER_ATTACKED_IN_HTH, f18); + } + }*/ + + // If we are not fighting, and they are in the area, attack. Else, determine anyway. + if(!CannotPerformCombatRound()) + { + // Must be in our area to go after now. + if(GetArea(oAttacker) == GetArea(OBJECT_SELF)) + { + // 59: "[Phisically Attacked] Attacking back. [Attacker(enemy)] " + GetName(oAttacker) + DebugActionSpeakByInt(59, oAttacker); + + // Attack the attacker + DetermineCombatRound(oAttacker); + + // Shout to allies to attack the enemy who attacked me + AISpeakString(AI_SHOUT_I_WAS_ATTACKED); + } + else + { + // Shout to allies to attack, or be prepared. + AISpeakString(AI_SHOUT_CALL_TO_ARMS); + + // 60: "[Phisically Attacked] Not same area. [Attacker(enemy)] " + GetName(oAttacker) + DebugActionSpeakByInt(60, oAttacker); + + // May find another hostile to attack... + DetermineCombatRound(); + } + } + else + { + // Shout to allies to attack, or be prepared. + AISpeakString(AI_SHOUT_CALL_TO_ARMS); + } + } + // Else, invalid, DM, ally, etc...must be prepared at least (could be + // they are charmed or something!) + else + { + // If we are not fighting, prepare for battle. Something bad must have + // happened. + if(!CannotPerformCombatRound()) + { + // Respond to oAttacker as if they shouted for help. + IWasAttackedResponse(oAttacker); + } + else + { + // Shout to allies to attack, or be prepared. + AISpeakString(AI_SHOUT_CALL_TO_ARMS); + } + } + + // Fire End of Attacked event + FireUserEvent(AI_FLAG_UDE_ATTACK_EVENT, EVENT_ATTACK_EVENT); +} diff --git a/_module/nss/j_ai_onrest.nss b/_module/nss/j_ai_onrest.nss new file mode 100644 index 00000000..42015fd0 --- /dev/null +++ b/_module/nss/j_ai_onrest.nss @@ -0,0 +1,84 @@ +/*/////////////////////// [On Rested] ////////////////////////////////////////// + Filename: J_AI_OnRest or nw_c2_defaulta +///////////////////////// [On Rested] ////////////////////////////////////////// + This will play the sitting animation for 6 seconds, just something for resting. + Also, walks waypoints (as resting would stop this) :-) and signals event (if so be) + Feel free to edit. + + It does have the spell trigger information resetting, however. This can + only be removed if they have no spell triggers, although it is hardly worth it. +///////////////////////// [History] //////////////////////////////////////////// + 1.3 - Added sitting. + 1.4 - Will be editing this down. No need to reset anything on rest, for a + better working AI. + IDEA: Change so that we will work through all spells/feats in order. + If, at cirtain levels, we do not have any spells to cast from that + level (set in a global stored integer in the general AI) we ignore all + spells in that level. Same for each talent category (no need to use + talents for them in the spawn script). + + If not in combat (EG: In heartbeat) we reset the integers saying "don't + bother checking those spells" to false. +///////////////////////// [Workings] /////////////////////////////////////////// + This fires once, at the END of resting. + + If ClearAllActions is added, the resting is actually stopped, or so it seems. + + It doesn't fire more then once. +///////////////////////// [Arguments] ////////////////////////////////////////// + Arguments: None, it seems. +///////////////////////// [On Rested] ////////////////////////////////////////*/ + +#include "J_INC_CONSTANTS" + +// Resets all spell triggers used for sString +void LoopResetTriggers(string sString, object oTrigger); + +void main() +{ + // Pre-rest-event. Returns TRUE if we interrupt this script call. + if(FirePreUserEvent(AI_FLAG_UDE_RESTED_PRE_EVENT, EVENT_RESTED_PRE_EVENT)) return; + + // AI status check. Is the AI on? + if(GetAIOff()) return; + + // Simple debug. + // 66: "[Rested] Resting. Type: " + IntToString(GetLastRestEventType()) + DebugActionSpeakByInt(66, OBJECT_INVALID, GetLastRestEventType()); + + // Reset all spell triggers. + // Set all triggers + object oTrigger = GetAIObject(AI_SPELL_TRIGGER_CREATURE); + if(GetIsObjectValid(oTrigger)) + { + LoopResetTriggers(SPELLTRIGGER_NOT_GOT_FIRST_SPELL, oTrigger); + LoopResetTriggers(SPELLTRIGGER_DAMAGED_AT_PERCENT, oTrigger); + LoopResetTriggers(SPELLTRIGGER_IMMOBILE, oTrigger); + LoopResetTriggers(SPELLTRIGGER_START_OF_COMBAT, oTrigger); + } + // Some sitting for a few seconds. + ActionPlayAnimation(ANIMATION_LOOPING_SIT_CROSS, 1.0, 6.0); + DelayCommand(9.0, ExecuteScript(FILE_WALK_WAYPOINTS, OBJECT_SELF)); + + // Fire End-heartbeat-UDE + FireUserEvent(AI_FLAG_UDE_RESTED_EVENT, EVENT_RESTED_EVENT); +} + +// Resets all spell triggers used for sString +void LoopResetTriggers(string sString, object oTrigger) +{ + int nCnt, bBreak, bUsed; + for(nCnt = 1; bBreak != TRUE; nCnt++) + { + // Check max for this setting + bUsed = GetLocalInt(oTrigger, sString + USED); + if(bUsed) + { + DeleteLocalInt(oTrigger, sString + USED); + } + else + { + bBreak = TRUE; + } + } +} diff --git a/_module/nss/j_ai_onspawn.nss b/_module/nss/j_ai_onspawn.nss new file mode 100644 index 00000000..522036b5 --- /dev/null +++ b/_module/nss/j_ai_onspawn.nss @@ -0,0 +1,644 @@ +/*/////////////////////// [On Spawn] /////////////////////////////////////////// + Filename: J_AI_OnSpawn or nw_c2_default9 +///////////////////////// [On Spawn] /////////////////////////////////////////// + This file contains options that will determine some AI behaviour, and a lot + of toggles for turning things on/off. A big read, but might be worthwhile. + + The documentation is actually fully in the readme files, under the name + "On Spawn.html", under "AI File Explanations". + + The order of the options: + + - Important Spawn Settings N/A + - Targeting & Fleeing (AI_TARGETING_FLEE_MASTER) + - Fighting & Spells (AI_COMBAT_MASTER) + - Other Combat - Healing, Skills & Bosses (AI_OTHER_COMBAT_MASTER) + - Other - Death corpses, minor things (AI_OTHER_MASTER) + - User Defined (AI_UDE_MASTER) + - Shouts N/A + - Default Bioware settings (WP's, Anims) (NW_GENERIC_MASTER) + + The OnSpawn file is a settings file. These things are set onto a creature, to + define cirtain actions. If more than one creature has this script, they all + use the settings, unless If/Else statements are used somehow. There is also + the process of setting any spells/feats availible, and hiding and walk waypoints + are started. + + Other stuff: + - Targeting is imporant :-D + - If you delete this script, there is a template for the On Spawn file + in the zip it came in, for use in the "scripttemplate" directory. +///////////////////////// [History] //////////////////////////////////////////// + Note: I have removed: + - Default "Teleporting" and exit/return (this seemed bugged anyway, or useless) + - Spawn in animation. This can be, of course, re-added. + - Day/night posting. This is uneeded, with a changed walk waypoints that does it automatically. + + 1.0-1.2 - Used short amount of spawn options. + 1.3 - All constants names are changed, I am afraid. + - Added Set/Delete/GetAIInteger/Constant/Object. This makes sure that the AI + doesn't ever interfere with other things - it pre-fixes all stored things + with AI_INTEGER_ (and so on) + 1.4 - TO DO: Clear up some old non-working ones + - Added in User Defined part of the script, an auto-turn-off-spells for + Ranger and Paladin classes. Need to test - perhaps 1.64 fixed it? + + + Spawn options changed: + - Removed AI level settings (can still be done manually) + - Added optional (and off by default) fear-visual for fleeing + + +///////////////////////// [Workings] /////////////////////////////////////////// + Note: You can do without all the comments (it may be that you don't want + the extra KB it adds or something, although it does not at all slow down a module) + so as long as you have these at the end: + + AI_SetUpEndOfSpawn(); + DelayCommand(2.0, SpawnWalkWayPoints()); + + Oh, and the include file (Below, "j_inc_spawnin") must be at the top like + here. Also recommended is the AI_INTELLIGENCE and AI_MORALE being set (if + not using custom AI). +///////////////////////// [Arguments] ////////////////////////////////////////// + Arguments: GetIsEncounterCreature +///////////////////////// [On Spawn] /////////////////////////////////////////*/ + +// Treasure Includes - See end of spawn for uncomment options. + +//#include "nw_o2_coninclude" +// Uncomment this if you want default NwN Treasure - Uses line "GenerateNPCTreasure()" at the end of spawn. +// - This generates random things from the default pallet based on the creatures level + race + +//#include "x0_i0_treasure" +// Uncomment this if you want the SoU Treasure - Uses line "CTG_GenerateNPCTreasure()" at the end of spawn. +// - This will spawn treasure based on chests placed in the module. See "x0_i0_treasure" for more information. + +// This is required for all spawn in options! +#include "J_INC_SPAWNIN" + +void main() +{ +/************************ [Important Spawn Settings] **************************/ + SetAIInteger(AI_INTELLIGENCE, 10); + // Intelligence value of the creauture. Can be 1-10, read readme's for help. + SetAIInteger(AI_MORALE, 10); + // Will save (See readme). Remember: -1 or below means they always flee. + //SetCustomAIFileName("CUSTOM_AI_FILE"); + // Sets our custom AI file. Really, only animation settings will apply when this is set. + // - Can sort actions against a imputted target (EG: On Percieved enemy) by + // "GetLocalObject(OBJECT_SELF, "AI_TEMP_SET_TARGET");" +/************************ [Important Spawn Settings] **************************/ + +/************************ [Targeting] ****************************************** + All targeting settings. +************************* [Targeting] *****************************************/ + //SetSpawnInCondition(AI_FLAG_TARGETING_LIKE_LOWER_HP, AI_TARGETING_FLEE_MASTER); + // We only attack the lowest current HP. + //SetSpawnInCondition(AI_FLAG_TARGETING_LIKE_LOWER_AC, AI_TARGETING_FLEE_MASTER); + // We only attack the lowest AC (as in 1.2). + //SetSpawnInCondition(AI_FLAG_TARGETING_LIKE_LOWER_HD, AI_TARGETING_FLEE_MASTER); + // Target the lowest hit dice + //SetSpawnInCondition(AI_FLAG_TARGETING_LIKE_MAGE_CLASSES, AI_TARGETING_FLEE_MASTER); + // We go straight for mages/sorcerors. Nearest one. + //SetSpawnInCondition(AI_FLAG_TARGETING_LIKE_ARCHERS, AI_TARGETING_FLEE_MASTER); + // We go for the nearest enemy with a ranged weapon equipped. + //SetSpawnInCondition(AI_FLAG_TARGETING_LIKE_PCS, AI_TARGETING_FLEE_MASTER); + // We go for the nearest seen PC enemy. + + //SetAIConstant(AI_FAVOURED_ENEMY_RACE, RACIAL_TYPE_HUMAN); + // The AI attacks the nearest enemy, seen, of this race. Use the RACIAL_* constants. + //SetAIConstant(AI_FAVOURED_ENEMY_CLASS, CLASS_TYPE_BARD); + // The AI attacks the nearest enemy, seen, of this class. Use the CLASS_* constants. + + // Target changing - see readme for info. + //SetAIInteger(AI_MAX_TURNS_TO_ATTACK_ONE_TARGET, 6); + // Maximum rounds to attack the current target, before re-checking. + // % Chance to re-set each target type each round (Could result in current target still) + //SetAIInteger(AI_MELEE_LAST_TO_NEW_TARGET_CHANCE, 20); + //SetAIInteger(AI_RANGED_LAST_TO_NEW_TARGET_CHANCE, 20); + //SetAIInteger(AI_SPELL_LAST_TO_NEW_TARGET_CHANCE, 20); + + // We only target PC's if there are any in range if this is set + //SetSpawnInCondition(AI_FLAG_TARGETING_FILTER_FOR_PC_TARGETS, AI_TARGETING_FLEE_MASTER); + + // Main explanation of AI_SetAITargetingValues, see the AI readme (spawn file) + // - Remember, uncommenting one will just ignore it (so will never check target's + // AC without TARGETING_AC on) + + AI_SetAITargetingValues(TARGETING_MANTALS, TARGET_LOWER, 1, 12); + // Spell mantals are checked only for the spell target. Either Absense of or got any. + AI_SetAITargetingValues(TARGETING_RANGE, TARGET_HIGHER, 2, 9); + // Range - very imporant! Basis for all ranged/spell attacks. + AI_SetAITargetingValues(TARGETING_AC, TARGET_LOWER, 2, 6); + // AC is used for all phisical attacks. Lower targets lower (By default). + AI_SetAITargetingValues(TARGETING_SAVES, TARGET_LOWER, 2, 4); + // Used for spell attacks. Saves are sorta a AC versus spells. + + // Phisical protections. Used by spells, ranged and melee. + // Jasperre - simple check if we are a fighter (hit lower phisicals) or a + // mage (attack higher!) + if(GetBaseAttackBonus(OBJECT_SELF) > ((GetHitDice(OBJECT_SELF)/2) + 1)) + { + // Fighter/Clerics (It is over a mages BAB + 1 (IE 0.5 BAB/Level) target lower + AI_SetAITargetingValues(TARGETING_PHISICALS, TARGET_LOWER, 2, 6); + } + else + { + // Mages target higher (so dispel/elemental attack those who fighters + // cannot hit as much). (the lowest BAB, under half our hit dice in BAB) + AI_SetAITargetingValues(TARGETING_PHISICALS, TARGET_HIGHER, 1, 5); + } + // Base attack bonus. Used for spells and phisical attacks. Checked with GetBaseAttackBonus. + AI_SetAITargetingValues(TARGETING_BAB, TARGET_LOWER, 1, 4); + // Hit dice - how powerful in levels the enemy is. Used for all checks. + AI_SetAITargetingValues(TARGETING_HITDICE, TARGET_LOWER, 1, 3); + + //AI_SetAITargetingValues(TARGETING_HP_PERCENT, TARGET_LOWER, 1, 3); + //AI_SetAITargetingValues(TARGETING_HP_CURRENT, TARGET_LOWER, 1, 3); + //AI_SetAITargetingValues(TARGETING_HP_MAXIMUM, TARGET_LOWER, 1, 3); + // The HP's are the last thing to choose a target with. +/************************ [Targeting] *****************************************/ + +/************************ [Fleeing] ******************************************** + Fleeing - these are toggled on/off by FEARLESS flag. + + 3 or under intelligence will just run away. 4 or more will know where allies + are, and if there are none, will not run. +************************* [Fleeing] *******************************************/ + SetSpawnInCondition(AI_FLAG_FLEEING_FEARLESS, AI_TARGETING_FLEE_MASTER); + // Forces them to not flee. This may be set with AI_SetMaybeFearless at the end. + //SetSpawnInCondition(AI_FLAG_FLEEING_NEVER_FIGHT_IMPOSSIBLE_ODDS, AI_TARGETING_FLEE_MASTER); + // This will make the creature never fight against impossible odds (8HD+ different) + //SetSpawnInCondition(AI_FLAG_FLEEING_TURN_OFF_GROUP_MORALE, AI_TARGETING_FLEE_MASTER); + // This turns OFF any sort of group morale bonuses. + + //SetAIInteger(AMOUNT_OF_HD_DIFFERENCE_TO_CHECK, -2); + // If enemy is within this amount of HD, we do not check morale. + //SetAIInteger(BASE_MORALE_SAVE, 20); + // Base DC of the will save. It is set to 20 + HD difference - Morale - Group morale mod. + //SetAIInteger(HP_PERCENT_TO_CHECK_AT, 80); + // %HP needed to be at to check morale. This doesn't affect "Never fight impossible odds" + //SetSpawnInCondition(AI_FLAG_FLEEING_NO_OVERRIDING_HP_AMOUNT, AI_TARGETING_FLEE_MASTER); + // This will turn off overriding HP checks. AI may decide to run even + // not at the %HP above, this turns the checks off. + + //SetAIInteger(AI_DAMAGE_AT_ONCE_FOR_MORALE_PENALTY, GetMaxHitPoints()/6); + // Damage needed to be done at once to get a massive morale penalty (Below) + //SetAIInteger(AI_DAMAGE_AT_ONCE_PENALTY, 6); + // Penalty for the above, set for some time to negativly affect morale. Added to save DC for fleeing. + + //SetSpawnInCondition(AI_FLAG_FLEEING_FLEE_TO_NEAREST_NONE_SEEN, AI_TARGETING_FLEE_MASTER); + // If set, just runs to nearest non-seen ally, and removes the loop for a good group of allies to run to. + + //SetSpawnInCondition(AI_FLAG_FLEEING_FLEE_TO_OBJECT, AI_TARGETING_FLEE_MASTER); + // They will flee to the nearest object of the tag below, if set. + //SetLocalString(OBJECT_SELF, AI_FLEE_OBJECT, "BOSS_TAG_OR_WHATEVER"); + // This needs setting if the above is to work. + + //SetSpawnInCondition(AI_FLAG_FLEEING_USE_VISUAL_EFFECT, AI_TARGETING_FLEE_MASTER); + // If this is on, we play a visual effect while we flee. +/************************ [Fleeing] *******************************************/ + +/************************ [Combat - Fighters] ********************************** + Fighter (Phiscal attacks, really) specific stuff - disarmed weapons, better + at hand to hand, and archer behaviour. +************************* [Combat - Fighters] *********************************/ + SetSpawnInCondition(AI_FLAG_COMBAT_PICK_UP_DISARMED_WEAPONS, AI_COMBAT_MASTER); + // This sets to pick up weapons which are disarmed. + + //SetAIInteger(AI_RANGED_WEAPON_RANGE, 3); + // This is the range at which they go into melee (from using a ranged weapon). Default is 3 or 5. + + //SetSpawnInCondition(AI_FLAG_COMBAT_BETTER_AT_HAND_TO_HAND, AI_COMBAT_MASTER); + // Set if you want them to move forwards into HTH sooner. Will always + // if the enemy is a mage/archer, else % based on range. + + //SetSpawnInCondition(AI_FLAG_COMBAT_ARCHER_ATTACKING, AI_COMBAT_MASTER); + // For archers. If they have ally support, they'd rather move back & shoot then go into HTH. + //SetSpawnInCondition(AI_FLAG_COMBAT_ARCHER_ALWAYS_MOVE_BACK, AI_COMBAT_MASTER); + // This forces the move back from attackers, and shoot bows. Very small chance to go melee. + //SetSpawnInCondition(AI_FLAG_COMBAT_ARCHER_ALWAYS_USE_BOW, AI_COMBAT_MASTER); + // This will make the creature ALWAYs use any bows it has. ALWAYS. + + //SetSpawnInCondition(AI_FLAG_COMBAT_NO_GO_FOR_THE_KILL, AI_COMBAT_MASTER); + // Turns off any attempts to kill dying PCs, or attack low hit point people. + // This is only ever attempted at 9 or 10 intelligence anyway. +/************************ [Combat - Fighters] *********************************/ + +/************************ [Combat - Spell Casters] ***************************** + Spellcaster AI has been improved significantly. As well as adding all new spells, + now spellcasters more randomly choose spells from the same level (EG: they + may choose not to cast magic missile, and cast negative energy ray instead). + + There are also options here for counterspelling, fast buffing, Cheat cast spells, + dispelling, spell triggers, long ranged spells first, immunity toggles, and AOE settings. +************************* [Combat - Spell Casters] ****************************/ + + //SetSpawnInCondition(AI_FLAG_COMBAT_LONGER_RANGED_SPELLS_FIRST, AI_COMBAT_MASTER); + // Casts spells only if the caster would not move into range to cast them. + // IE long range spells, then medium, then short (unless the enemy comes to us!) + //SetSpawnInCondition(AI_FLAG_COMBAT_FLAG_FAST_BUFF_ENEMY, AI_COMBAT_MASTER); + // When an enemy comes in 40M, we fast-cast many defensive spells, as if prepared. + //SetSpawnInCondition(AI_FLAG_COMBAT_SUMMON_FAMILIAR, AI_COMBAT_MASTER); + // The caster summons thier familiar/animal companion. Either a nameless Bat or Badger respectivly. + + // Counterspelling/Dispelling... + // It checks for these classes within the 20M counterspell range. + //SetSpawnInCondition(AI_FLAG_COMBAT_COUNTER_SPELL_ARCANE, AI_COMBAT_MASTER); + // If got dispels, it counterspells Arcane (Mage/Sorceror) spellcasters. + //SetSpawnInCondition(AI_FLAG_COMBAT_COUNTER_SPELL_DIVINE, AI_COMBAT_MASTER); + // If got dispels, it counterspells Divine (Cleric/Druid) spellcasters. + //SetSpawnInCondition(AI_FLAG_COMBAT_COUNTER_SPELL_ONLY_IN_GROUP, AI_COMBAT_MASTER); + // Recommended. Only counterspells with 5+ allies in group. + + //SetSpawnInCondition(AI_FLAG_COMBAT_DISPEL_MAGES_MORE, AI_COMBAT_MASTER); + // Targets seen mages to dispel, else uses normal spell target. + SetSpawnInCondition(AI_FLAG_COMBAT_DISPEL_IN_ORDER, AI_COMBAT_MASTER); + // This will make the mage not dispel just anything all the time, but important (spell-stopping) + // things first, others later, after some spells. If off, anything is dispelled. + + // AOE's + //SetSpawnInCondition(AI_FLAG_COMBAT_NEVER_HIT_ALLIES, AI_COMBAT_MASTER); + // Override toggle. Forces to never cast AOE's if it will hit an ally + harm them. + //SetSpawnInCondition(AI_FLAG_COMBAT_AOE_DONT_MIND_IF_THEY_SURVIVE, AI_COMBAT_MASTER); + // Allies who will survive the blast are ignored for calculating best target. + //SetAIInteger(AI_AOE_ALLIES_LOWEST_IN_AOE, 3); + // Defualt: 3. If amount of allies in blast radius are equal or more then + // this, then that location is ignored. + //SetAIInteger(AI_AOE_HD_DIFFERENCE, -8); + // Very weak allies (who are not comparable to us) are ignored if we would hit them. + + // For these 2, if neither are set, the AI will choose AOE more if there are + // lots of enemies, or singles if there are not many. + //SetSpawnInCondition(AI_FLAG_COMBAT_SINGLE_TARGETING, AI_COMBAT_MASTER); + // For Same-level spells, single target spells are used first. + //SetSpawnInCondition(AI_FLAG_COMBAT_MANY_TARGETING, AI_COMBAT_MASTER); + // For Same-level spells, AOE spells are used first. + + SetSpawnInCondition(AI_FLAG_COMBAT_IMPROVED_INSTANT_DEATH_SPELLS, AI_COMBAT_MASTER); + // A few Death spells may be cast top-prioritory if the enemy will always fail saves. + SetSpawnInCondition(AI_FLAG_COMBAT_IMPROVED_SUMMON_TARGETING, AI_COMBAT_MASTER); + // Will use a better target to summon a creature at (EG: Ranged attacker) + SetSpawnInCondition(AI_FLAG_COMBAT_IMPROVED_IMMUNITY_CHECKING, AI_COMBAT_MASTER); + // Turns On "GetIsImmune" checks. Auto on for 7+ Intel. + SetSpawnInCondition(AI_FLAG_COMBAT_IMPROVED_SPECIFIC_SPELL_IMMUNITY, AI_COMBAT_MASTER); + // Turns On checks for Globes & levels of spells. Auto on for 9+ Intel. + + //SetSpawnInCondition(AI_FLAG_COMBAT_MORE_ALLY_BUFFING_SPELLS, AI_COMBAT_MASTER); + // This will make the caster buff more allies - or, in fact, use spells + // to buff allies which they might have not used before. + + //SetSpawnInCondition(AI_FLAG_COMBAT_USE_ALL_POTIONS, AI_COMBAT_MASTER); + // Uses all buffing spells before melee. + + //SetAICheatCastSpells(SPELL_MAGIC_MISSILE, SPELL_ICE_DAGGER, SPELL_HORIZIKAULS_BOOM, SPELL_MELFS_ACID_ARROW, SPELL_NEGATIVE_ENERGY_RAY, SPELL_FLAME_ARROW); + // Special: Mages cast for ever with this set. + + // Spell triggers + //SetSpellTrigger(SPELLTRIGGER_NOT_GOT_FIRST_SPELL, FALSE, 1, SPELL_PREMONITION); + // This is just an example. See readme for more info. + +/************************ [Combat - Spell Casters] ****************************/ + +/************************ [Combat - Dragons] *********************************** + I have a fondness for dragons - in NWN they are deprived of many abilities. Here + are some new ones for your enjoyment! Switches and flying for ANYTHING! :-) +************************* [Combat - Dragons] **********************************/ + + //SetSpawnInCondition(AI_FLAG_COMBAT_NO_WING_BUFFET, AI_COMBAT_MASTER); + //This sets so there is no Dragon wing buffet. Readme has details of it. + //SetAIInteger(AI_DRAGON_FREQUENCY_OF_BUFFET, 3); + // Min. Amount of Rounds between each buffet. See readme for counter defaults. Def: 3 + //SetAIInteger(AI_DRAGON_FREQUENCY_OF_BREATH, 3); + // Min. Amount of Rounds between each breath use. See readme for counter defaults. Def: 3 + + // Default checks for dragon flying automatic turning on of flying. + if(GetLevelByClass(CLASS_TYPE_DRAGON) || GetRacialType(OBJECT_SELF) == RACIAL_TYPE_DRAGON) + { + SetSpawnInCondition(AI_FLAG_COMBAT_FLYING, AI_COMBAT_MASTER); + // This turns ON combat flying. I think anything winged looks A-OK. See readme for info. + } +/************************ [Combat - Dragons] **********************************/ + +/************************ [Combat Other - Healers/Healing] ********************* + Healing behaviour - not specifically clerics. See readme. +************************* [Combat Other - Healers/Healing] ********************/ + //SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_HEAL_AT_PERCENT_NOT_AMOUNT, AI_OTHER_COMBAT_MASTER); + // if this is set, we ignore the amount we need to be damaged, as long + // as we are under AI_HEALING_US_PERCENT. + //SetAIInteger(AI_HEALING_US_PERCENT, 50); + // % of HP we need to be at until we heal us at all. Default: 50 + //SetAIInteger(AI_HEALING_ALLIES_PERCENT, 60); + // % of HP allies would need to be at to heal them Readme = info. Default: 60 + SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_WILL_RAISE_ALLIES_IN_BATTLE, AI_OTHER_COMBAT_MASTER); + // Turns on rasing dead with Resurrection/Raise dead. + //SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_CURING, AI_OTHER_COMBAT_MASTER); + // This turns off all healing. + //SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_ONLY_CURE_SELF, AI_OTHER_COMBAT_MASTER); + // This turns off ally healing. + //SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_ONLY_RESTORE_SELF, AI_OTHER_COMBAT_MASTER); + // This turns off ally restoring (Remove/Restoration). + //SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_USE_BAD_HEALING_SPELLS, AI_OTHER_COMBAT_MASTER); + // This forces all cure spells to be used, check readme. + //SetAIInteger(SECONDS_BETWEEN_STATUS_CHECKS, 30); + // Seconds between when we loop everyone for bad effects like Fear/stun ETC. If not set, done each round. + //SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_GIVE_POTIONS_TO_HELP, AI_OTHER_COMBAT_MASTER); + // ActionGiveItem standard healing potion's to allies who need them, if they possess them. + +/************************ [Combat Other - Healers/Healing] ********************/ + +/************************ [Combat Other - Skills] ****************************** + Skills are a part of fighting - EG Taunt. These are mainly on/off switches. + A creature will *may* use it if they are not set to "NO_" for the skill. +************************* [Combat Other - Skills] *****************************/ + + // "NO" - This is for forcing the skill NEVER to be used by the combat AI. + // "FORCE" - This forces it on (and to be used), except if they have no got the skill. + + //SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_PICKPOCKETING, AI_OTHER_COMBAT_MASTER); + //SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_PICKPOCKETING, AI_OTHER_COMBAT_MASTER); + //SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_TAUNTING, AI_OTHER_COMBAT_MASTER); + //SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_TAUNTING, AI_OTHER_COMBAT_MASTER); + //SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_EMPATHY, AI_OTHER_COMBAT_MASTER); + //SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_EMPATHY, AI_OTHER_COMBAT_MASTER); + //SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_HIDING, AI_OTHER_COMBAT_MASTER); + //SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_HIDING, AI_OTHER_COMBAT_MASTER); + //SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_OPENING_LOCKED_DOORS, AI_OTHER_COMBAT_MASTER); + //SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_OPENING_LOCKED_DOORS, AI_OTHER_COMBAT_MASTER); + //SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_USING_HEALING_KITS, AI_OTHER_COMBAT_MASTER); + //SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_PARRYING, AI_OTHER_COMBAT_MASTER); + //SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_PARRYING, AI_OTHER_COMBAT_MASTER); + //SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_SEARCH, AI_OTHER_COMBAT_MASTER); + //SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_SEARCH, AI_OTHER_COMBAT_MASTER); + // - Concentration - special notes in the readme + //SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_CONCENTRATION, AI_OTHER_COMBAT_MASTER); + //SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_CONCENTRATION, AI_OTHER_COMBAT_MASTER); + +/************************ [Combat Other - Skills] *****************************/ + +/************************ [Combat Other - Leaders] ***************************** + Leaders/Bosses can be set to issue some orders and inspire more morale - and bring + a lot of allies to a battle at once! +************************* [Combat Other - Leaders] ****************************/ + //SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_GROUP_LEADER, AI_OTHER_COMBAT_MASTER); + // Special leader. Can issuse some orders. See readme for details. + + //SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_BOSS_MONSTER_SHOUT, AI_OTHER_COMBAT_MASTER); + // Boss shout. 1 time use - calls all creatures in X meters (below) for battle! + //SetAIInteger(AI_BOSS_MONSTER_SHOUT_RANGE, 60); + // Defaults to a 60 M range. This can change it. Note: 1 toolset square = 10M. + +/************************ [Combat Other - Leaders] ****************************/ + +/************************ [Other - Behaviour/Generic] ************************** + This is generic behaviours - alright, really it is all things that cannot + really be categorised. +************************* [Other - Behaviour/Generic] *************************/ + + //SetSpawnInCondition(AI_FLAG_OTHER_NO_CLEAR_ACTIONS_BEFORE_CONVERSATION, AI_OTHER_MASTER); + // No ClearAllActions() before BeginConversation. May keep a creature sitting. + //SetSpawnInCondition(AI_FLAG_OTHER_NO_POLYMORPHING, AI_OTHER_MASTER); + // This will stop all polymorphing spells feats from being used. + //SetSpawnInCondition(AI_FLAG_OTHER_CHEAT_MORE_POTIONS, AI_OTHER_MASTER); + // If at low HP, and no potion, create one and use it. + //SetAIConstant(AI_POLYMORPH_INTO, POLYMORPH_TYPE_WEREWOLF); + // Polymorph to this creature when damaged (once, natural effect). + + //AI_CreateRandomStats(-3, 3, 6); + // Create (Effect-applied) random statistics. + //AI_CreateRandomOther(-2, 2, -2, 2, -2, 2, -2, 2); + // Create (Effect-applied) random HP, saves, AC. + + //SetSpawnInCondition(AI_FLAG_OTHER_RETURN_TO_SPAWN_LOCATION, AI_OTHER_MASTER); + // This will store our spawn location, and then move back there after combat. + SetSpawnInCondition(AI_FLAG_OTHER_DONT_RESPOND_TO_EMOTES, AI_OTHER_MASTER); + // This will ignore ALL chat by PC's (Enemies) who speak actions in Stars - *Bow* + + //SetSpawnInCondition(AI_FLAG_OTHER_DONT_SHOUT, AI_OTHER_MASTER); + // Turns off all silent talking NPC's do to other NPC's. + + //SetSpawnInCondition(AI_FLAG_OTHER_SEARCH_IF_ENEMIES_NEAR, AI_OTHER_MASTER); + // Move randomly closer to enemies in range set below. + //SetAIInteger(AI_SEARCH_IF_ENEMIES_NEAR_RANGE, 25); + // This is the range creatures use, in metres. + + //SetSpawnInCondition(AI_FLAG_OTHER_ONLY_ATTACK_IF_ATTACKED, AI_OTHER_MASTER); + // One shot. We won't instantly attack a creature we see. See readme. + + //SetAIInteger(AI_DOOR_INTELLIGENCE, 1); + // 3 Special "What to do with Doors" settings. See readme. Good for animals. + + //SetSpawnInCondition(AI_FLAG_OTHER_REST_AFTER_COMBAT, AI_OTHER_MASTER); + // When combat is over, creature rests. Useful for replenising health. + + //SetSpawnInCondition(AI_FLAG_OTHER_NO_PLAYING_VOICE_CHAT, AI_OTHER_MASTER); + // Stops any use of "PlayVoiceChat". Use with Custom speakstrings. + + /*** Death settings - still under AI_OTHER_MASTER ***/ + + //AI_SetDeathResRef("Resref Here"); + // Creates a creature from the string set. Instantly destroys this creatures body on death. + + //SetAIConstant(AI_DEATH_VISUAL_EFFECT, VFX_FNF_IMPLOSION); + // Fires this visual effect number instantly on death. Use FNF and IMP ones. + + //SetAIInteger(AI_CORPSE_DESTROY_TIME, 30); + // Seconds before body finally gets destroyed. Used for Clerical Raise Dead on NPC's. + + //SetSpawnInCondition(AI_FLAG_OTHER_TURN_OFF_CORPSES, AI_OTHER_MASTER); + // This turns off the SetDestroyable() usually performed, and the above timer. + + //SetSpawnInCondition(AI_FLAG_OTHER_USE_BIOWARE_LOOTING, AI_OTHER_MASTER); + // Makes the death file use Bioware's cool SetLootable() feature when corpses would disappear. + + /*** Lag and a few performance settings - still under AI_OTHER_MASTER ***/ + + //SetSpawnInCondition(AI_FLAG_OTHER_LAG_NO_ITEMS, AI_OTHER_MASTER); + // The creature doesn't check for, or use any items that cast spells. + //SetSpawnInCondition(AI_FLAG_OTHER_LAG_NO_SPELLS, AI_OTHER_MASTER); + //The creature doesn't ever cast spells (and never checks them) + //SetSpawnInCondition(AI_FLAG_OTHER_LAG_NO_LISTENING, AI_OTHER_MASTER); + // The creature doesn't have SetListening() set. Turns of the basic listening for shouts. + //SetSpawnInCondition(AI_FLAG_OTHER_LAG_EQUIP_MOST_DAMAGING, AI_OTHER_MASTER); + // Uses EquipMostDamaging(), like Bioware code. No shield/second weapon equipped. + //SetSpawnInCondition(AI_FLAG_OTHER_LAG_NO_CURING_ALLIES, AI_OTHER_MASTER); + // This will stop checks for and curing of allies ailments. + //SetSpawnInCondition(AI_FLAG_OTHER_LAG_IGNORE_HEARTBEAT, AI_OTHER_MASTER); + // Stops the heartbeat running (Except Pre-Heartbeat-event). + //SetSpawnInCondition(AI_FLAG_OTHER_LAG_TARGET_NEAREST_ENEMY, AI_OTHER_MASTER); + // Ignores targeting settings. VERY good for lag/bad AI. Attacks nearest seen enemy. + +/************************ [Other - Behaviour/Generic] *************************/ + +/************************ [User Defined and Shouts] **************************** + The user defined events, set up to fire here. + - New "Start combat attack" and "End Combat Attack" events + - New "Pre" events. Use these to optionally stop a script from firing + under cirtain circumstances as well! (Read nw_c2_defaultd or j_ai_onuserdef) + (User Defined Event = UDE) +************************* [User Defined and Shouts] ***************************/ + + // This is REQUIRED if we use any Pre-events. If not there, it will default + // to the default User Defined Event script for the default AI. + SetCustomUDEFileName("k_ai_onuserdef"); + + //SetSpawnInCondition(AI_FLAG_UDE_HEARTBEAT_EVENT, AI_UDE_MASTER); // UDE 1001 + //SetSpawnInCondition(AI_FLAG_UDE_HEARTBEAT_PRE_EVENT, AI_UDE_MASTER); // UDE 1021 + //SetSpawnInCondition(AI_FLAG_UDE_PERCIEVE_EVENT, AI_UDE_MASTER); // UDE 1002 + //SetSpawnInCondition(AI_FLAG_UDE_PERCIEVE_PRE_EVENT, AI_UDE_MASTER); // UDE 1022 + //SetSpawnInCondition(AI_FLAG_UDE_END_COMBAT_ROUND_EVENT, AI_UDE_MASTER); // UDE 1003 + //SetSpawnInCondition(AI_FLAG_UDE_END_COMBAT_ROUND_PRE_EVENT, AI_UDE_MASTER); // UDE 1023 + //SetSpawnInCondition(AI_FLAG_UDE_ON_DIALOGUE_EVENT, AI_UDE_MASTER); // UDE 1004 + //SetSpawnInCondition(AI_FLAG_UDE_ON_DIALOGUE_PRE_EVENT, AI_UDE_MASTER); // UDE 1024 + //SetSpawnInCondition(AI_FLAG_UDE_ATTACK_EVENT, AI_UDE_MASTER); // UDE 1005 + //SetSpawnInCondition(AI_FLAG_UDE_ATTACK_PRE_EVENT, AI_UDE_MASTER); // UDE 1025 + //SetSpawnInCondition(AI_FLAG_UDE_DAMAGED_EVENT, AI_UDE_MASTER); // UDE 1006 + //SetSpawnInCondition(AI_FLAG_UDE_DAMAGED_PRE_EVENT, AI_UDE_MASTER); // UDE 1026 + //SetSpawnInCondition(AI_FLAG_UDE_DEATH_EVENT, AI_UDE_MASTER); // UDE 1007 + //SetSpawnInCondition(AI_FLAG_UDE_DEATH_PRE_EVENT, AI_UDE_MASTER); // UDE 1027 + //SetSpawnInCondition(AI_FLAG_UDE_DISTURBED_EVENT, AI_UDE_MASTER); // UDE 1008 + //SetSpawnInCondition(AI_FLAG_UDE_DISTURBED_PRE_EVENT, AI_UDE_MASTER); // UDE 1028 + //SetSpawnInCondition(AI_FLAG_UDE_RESTED_EVENT, AI_UDE_MASTER); // UDE 1009 + //SetSpawnInCondition(AI_FLAG_UDE_RESTED_PRE_EVENT, AI_UDE_MASTER); // UDE 1029 + //SetSpawnInCondition(AI_FLAG_UDE_SPELL_CAST_AT_EVENT, AI_UDE_MASTER); // UDE 1011 + //SetSpawnInCondition(AI_FLAG_UDE_SPELL_CAST_AT_PRE_EVENT, AI_UDE_MASTER); // UDE 1031 + //SetSpawnInCondition(AI_FLAG_UDE_ON_BLOCKED_EVENT, AI_UDE_MASTER); // UDE 1015 + //SetSpawnInCondition(AI_FLAG_UDE_ON_BLOCKED_PRE_EVENT, AI_UDE_MASTER); // UDE 1035 + + //SetSpawnInCondition(AI_FLAG_UDE_COMBAT_ACTION_EVENT, AI_UDE_MASTER); // UDE 1012 + // Fires when we have finnished all combat actions. + //SetSpawnInCondition(AI_FLAG_UDE_COMBAT_ACTION_PRE_EVENT, AI_UDE_MASTER); // UDE 1032 + // This fires at the start of DetermineCombatRound() *IF they can do an action*. + //SetSpawnInCondition(AI_FLAG_UDE_DAMAGED_AT_1_HP, AI_UDE_MASTER); // UDE 1014 + // Fires when we are damaged, and are at 1 HP. Use for immortal-flagged creatures. + + /*** Speakstrings - as it were, said under cirtain conditions % chance each time ***/ + + //AI_SetSpawnInSpeakArray(AI_TALK_ON_CONVERSATION, 100, 4, "Hello there", "I hope you enjoy your stay", "Do you work here too?", "*Hic*"); + // On Conversation - see readme. Replaces BeginConversation(). + + // Morale + //AI_SetSpawnInSpeakArray(AI_TALK_ON_MORALE_BREAK, 100, 3, "No more!", "I'm outta here!", "Catch me if you can!"); + // Spoken at running point, if they run to a group of allies. + //AI_SetSpawnInSpeakArray(AI_TALK_ON_CANNOT_RUN, 100, 3, "Never give up! Never surrender!", "I've no where to run, so make my day!", "RRRAAAAA!!!"); + // Spoken at running point, if they can find no ally to run to, and 4+ Intelligence. See readme + //AI_SetSpawnInSpeakValue(AI_TALK_ON_STUPID_RUN, "Ahhhhgggg! NO MORE! Run!!"); + // As above, when morale breaks + no ally, but they panic and run from enemy at 3 or less intelligence. + + // Combat + //AI_SetSpawnInSpeakArray(AI_TALK_ON_COMBAT_ROUND_EQUAL, 5, 4, "Come on!", "You won't win!", "We are not equals! I am better!", "Nothing will stop me!"); + //AI_SetSpawnInSpeakArray(AI_TALK_ON_COMBAT_ROUND_THEM_OVER_US, 5, 4, "I'll try! try! and try again!", "Tough man, are we?", "Trying out your 'skills'? Pathetic excuse!", "Nothing good will come from killing me!"); + //AI_SetSpawnInSpeakArray(AI_TALK_ON_COMBAT_ROUND_US_OVER_THEM, 5, 4, "My strength is mighty then yours!", "You will definatly die!", "NO chance for you!", "No mercy! Not for YOU!"); + // Spoken each DetermineCombatRound. % is /1000. See readme for Equal/Over/Under values. + //AI_SetSpawnInSpeakArray(AI_TALK_ON_TAUNT, 100, 3, "You're going down!", "No need to think, let my blade do it for you!", "Time to meet your death!"); + // If the creature uses thier skill, taunt, on an enemy this will be said. + + // Event-driven. + //AI_SetSpawnInSpeakArray(AI_TALK_ON_PERCIEVE_ENEMY, 70, 6, "Stand and fight, lawbreaker!", "Don't run from the law!", "I have my orders!", "I am ready for violence!", "CHARGE!", "Time you died!"); + // This is said when they see/hear a new enemy, and start attacking them. + //AI_SetSpawnInSpeakArray(AI_TALK_ON_DAMAGED, 20, 2, "Ouch, damn you!", "Haha! Nothing will stop me!"); + // A random value is set to speak when damaged, and may fire same time as below ones. + //AI_SetSpawnInSpeakArray(AI_TALK_ON_PHISICALLY_ATTACKED, 20, 2, "Hah! Mear weapons won't defeat me!", "Pah! You cannot defeat me with such rubbish!"); + // This is said when an enemy attacks the creature with a melee/ranged weapon. + //AI_SetSpawnInSpeakArray(AI_TALK_ON_HOSTILE_SPELL_CAST_AT, 20, 2, "No one spell will stop me!", "Is that all you have!?!"); + // This is said when an enemy attacks the creature with a hostile spell. + //AI_SetSpawnInSpeakValue(AI_TALK_ON_DEATH, "Agggggg!"); + // This will ALWAYS be said, whenever the creature dies. + + // Specific potion ones. + //AI_SetSpawnInSpeakValue(AI_TALK_WE_PASS_POTION, "Here! Catch!"); + // This will be spoken when the creature passes a potion to an ally. See readme. + //AI_SetSpawnInSpeakValue(AI_TALK_WE_GOT_POTION, "Got it!"); + // This will be spoken by the creature we pass the potion too, using AssignCommand(). + + // Leader ones + //AI_SetSpawnInSpeakValue(AI_TALK_ON_LEADER_SEND_RUNNER, "Quickly! We need help!"); + // This will be said when the leader, if this creature, sends a runner. + //AI_SetSpawnInSpeakValue(AI_TALK_ON_LEADER_ATTACK_TARGET, "Help attack this target!"); + // When the leader thinks target X should be attacked, it will say this. + //AI_SetSpawnInSpeakValue(AI_TALK_ON_LEADER_BOSS_SHOUT, "Come my minions! To battle!"); + // This will be said when the leader, if this creature, sees an enemy and uses his "Boss Monster Shout", if turned on. + + +/************************ [User Defined and Shouts] ***************************/ + +/************************ [Bioware: Animations/Waypoints/Treasure] ************* + All Bioware Stuff. I'd check out "x0_c2_spwn_def" for the SoU/Hordes revisions. +************************* [Bioware: Animations/Waypoints/Treasure] ************/ + + // SetSpawnInCondition(NW_FLAG_STEALTH, NW_GENERIC_MASTER); + // SetSpawnInCondition(NW_FLAG_SEARCH, NW_GENERIC_MASTER); + // Uses said skill while WalkWaypoints() + + // SetSpawnInCondition(NW_FLAG_DAY_NIGHT_POSTING, NW_GENERIC_MASTER); + // Separate the NPC's waypoints into day & night. See comment in "nw_i0_generic" for use. + + // SetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS, NW_GENERIC_MASTER); + // This will cause an NPC to use common animations it possesses, + // and use social ones to any other nearby friendly NPCs. + // SetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS, NW_GENERIC_MASTER); + // Same as above, except NPC will wander randomly around the area. + + // SetAnimationCondition(NW_ANIM_FLAG_IS_CIVILIZED); + // Interacts with placeables + More civilized actions. See Readme. + // SetAnimationCondition(NW_ANIM_FLAG_CHATTER); + // Will use random voicechats during animations, if Civilized + // SetAnimationCondition(NW_ANIM_FLAG_IS_MOBILE_CLOSE_RANGE); + // Will move around the area a bit more, if using Immobile Animations. See readme. + + // Treasure generating. + //CTG_GenerateNPCTreasure(); + // SoU. Requires "x0_i0_treasure" to be uncommented. See readme. + //GenerateNPCTreasure(); + // Default NwN. Requires "nw_o2_coninclude" to be uncommented. See readme. + +/************************ [Bioware: Animations/Waypoints/Treasure] ************/ + + // AI Behaviour. DO NOT CHANGE! DO NOT CHANGE!!! + AI_SetUpEndOfSpawn(); + // This MUST be called. It fires these events: + // SetUpSpells, SetUpSkillToUse, SetListeningPatterns, SetWeapons, AdvancedAuras. + // These MUST be called! the AI might fail to work correctly if they don't fire! + +/************************ [User] *********************************************** + This is the ONLY place you should add user things, on spawn, such as + visual effects or anything, as it is after SetUpEndOfSpawn. By default, this + does have encounter animations on. This is here, so is easily changed :-D + + Be careful otherwise. + + Notes: + - SetListening is already set to TRUE, unless AI_FLAG_OTHER_LAG_NO_LISTENING is on. + - SetListenPattern's are set from 0 to 7. + - You can use the wrappers AI_SpawnInInstantVisual and AI_SpawnInPermamentVisual + for visual effects (Instant/Permament as appropriate). +************************* [User] **********************************************/ + // Example (and default) of user addition: + // - If we are from an encounter, set mobile (move around) animations. + if(GetIsEncounterCreature()) + { + SetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS, NW_GENERIC_MASTER); + } + // Leave this in if you use the variable for creature attacks, as for golems. Bioware's code. + int nNumber = GetLocalInt(OBJECT_SELF, "CREATURE_VAR_NUMBER_OF_ATTACKS"); + if(nNumber > 0) + { + SetBaseAttackBonus(nNumber); + } + + // If we are a ranger or paladin class, do not cast spells. This can be + // manually removed if wished. To get the spells they have working correctly, + // remove this, and use Monster Abilties instead of thier normal class spells. +// if(GetLevelByClass(CLASS_TYPE_RANGER) >= 1 || GetLevelByClass(CLASS_TYPE_PALADIN) >= 1) +// { +// SetSpawnInCondition(AI_FLAG_OTHER_LAG_NO_SPELLS, AI_OTHER_MASTER); +// } + +/************************ [User] **********************************************/ + + // Note: You shouldn't really remove this, even if they have no waypoints. + DelayCommand(2.0, SpawnWalkWayPoints()); + // Delayed walk waypoints, as to not upset instant combat spawning. + // This will also check if to change to day/night posts during the walking, no heartbeats. +} diff --git a/_module/nss/j_ai_onspellcast.nss b/_module/nss/j_ai_onspellcast.nss new file mode 100644 index 00000000..6bee0e66 --- /dev/null +++ b/_module/nss/j_ai_onspellcast.nss @@ -0,0 +1,493 @@ +/*/////////////////////// [On Spell Cast At] /////////////////////////////////// + Filename: j_ai_onspellcast or nw_c2_defaultb +///////////////////////// [On Spell Cast At] /////////////////////////////////// + What does this do? Well... + - Any AOE spell effects are set in a timer, so we can react to them right + - Reacts to hostile casters, or allies in combat + + And the normal attack :-) +///////////////////////// [History] //////////////////////////////////////////// + 1.3 - Added special AOE checks. + - Hide checks. + 1.4 - Added more silent shouts. Edited the formatting. Moved a few things around. +///////////////////////// [Workings] /////////////////////////////////////////// + This is fired when EventSpellCastAt(object oCaster, int nSpell, int bHarmful=TRUE) + is signaled on the creature. + + GetLastSpellCaster() = oCaster (Door, Placeable, Creature who cast it) + GetLastSpell() = nSpell (The spell cast at us) + GetLastSpellHarmful()= bHarmful (If it is harmful!) +///////////////////////// [Arguments] ////////////////////////////////////////// + Arguments: GetLastSpellCaster, GetLastSpellHarmful GetLastSpell() +///////////////////////// [On Spell Cast At] /////////////////////////////////*/ + +#include "J_INC_OTHER_AI" + +// Sets a local timer if the spell is an AOE one +void SetAOESpell(int nSpellCast, object oCaster); +// Gets the nearest AOE cast by oCaster, of sTag. +object GetNearestAOECastBy(string sTag, object oCaster); +// Gets the amount of protections we have - IE globes +int GetOurSpellLevelImmunity(); + +void main() +{ + // Pre-spell cast at-event. Returns TRUE if we interrupt this script call. + if(FirePreUserEvent(AI_FLAG_UDE_SPELL_CAST_AT_PRE_EVENT, EVENT_SPELL_CAST_AT_PRE_EVENT)) return; + + // AI status check. Is the AI on? + if(GetAIOff()) return; + + object oCaster = GetLastSpellCaster(); + int bHarmful = GetLastSpellHarmful(); + int nSpellCast = GetLastSpell(); + object oAttackerOfCaster; + + // If harmful, we set the spell to a timer, if an AOE one. + if(bHarmful && GetIsObjectValid(oCaster)) + { + // Might set AOE spell to cast. + SetAOESpell(nSpellCast, oCaster); + } + // If not a creature, probably an AOE or trap. + if(GetObjectType(oCaster) != OBJECT_TYPE_CREATURE) + { + // 67: "[Spell] Caster isn't a creature! May look for target [Caster] " + GetName(oCaster) + DebugActionSpeakByInt(67, oCaster); + + // Shout to allies to attack, or be prepared. + AISpeakString(AI_SHOUT_CALL_TO_ARMS); + + // Attack anyone else around + if(!CannotPerformCombatRound()) + { + // Determine Combat Round + DetermineCombatRound(); + } + } + // If a friend, or dead, or a DM, or invalid, or self, we ignore them. + else if(!GetIgnoreNoFriend(oCaster) && oCaster != OBJECT_SELF) + { + // 1.3 changes here: + // - We do NOT need to know if it is hostile or not, except if it is hostile + // and they are not our faction! We do, however, use bHarmful for speakstrings. + + // If harmful, we attack anyone! (and if is enemy) + // 1.4: Faction equal check in GetIgnoreNoFriend() + if(bHarmful || GetIsEnemy(oCaster)) + { + // Spawn in condition hostile thingy + if(GetSpawnInCondition(AI_FLAG_OTHER_CHANGE_FACTIONS_TO_HOSTILE_ON_ATTACK, AI_OTHER_MASTER)) + { + if(!GetIsEnemy(oCaster)) + { + AdjustReputation(oCaster, OBJECT_SELF, -100); + } + } + + if(bHarmful) + { + // * Don't speak when dead. 1.4 change (an obvious one to make) + if(CanSpeak()) + { + // Hostile spell speaksting, if set. + SpeakArrayString(AI_TALK_ON_HOSTILE_SPELL_CAST_AT); + } + } + + // Turn of hiding check + TurnOffHiding(oCaster); + + // We attack + if(!CannotPerformCombatRound()) + { + // 68: "[Spell:Enemy/Hostile] Not in combat. Attacking: [Caster] " + GetName(oCaster) + DebugActionSpeakByInt(68, oCaster); + DetermineCombatRound(oCaster); + } + + // Shout to allies to attack the enemy who attacked me, got via. Last Hostile Actor. + AISpeakString(AI_SHOUT_I_WAS_ATTACKED); + } + // Else, was neutral perhaps. Don't attack them anyway. + else + { + // 69: "[Spell] (ally). Not in combat. May Attack/Move [Caster] " + GetName(oCaster) + DebugActionSpeakByInt(69, oCaster); + + // Set special action to investigate - as if this event was triggered + // by I_WAS_ATTACKED. + + // If we are already attacking, we do not move + if(CannotPerformCombatRound()) + { + // Shout to allies to attack, or be prepared. + AISpeakString(AI_SHOUT_CALL_TO_ARMS); + } + else + { + // We react as if the caster, a neutral, called for help ala + // I_WAS_ATTACKED (they might not have, might just be + // preperation for something), but normally, this is a neutral + // casting a spell. Do not respond to PC's. + if(!GetIsPC(oCaster)) + { + IWasAttackedResponse(oCaster); + } + } + } + } + // If they are not a faction equal, and valid, we help them. + else if(GetIsObjectValid(oCaster) && GetFactionEqual(oCaster)) + { + IWasAttackedResponse(oCaster); + } + // Fire End-spell cast at-UDE + FireUserEvent(AI_FLAG_UDE_SPELL_CAST_AT_EVENT, EVENT_SPELL_CAST_AT_EVENT); +} + +// Sets a local timer if the spell is an AOE one +void SetAOESpell(int nSpellCast, object oCaster) +{ + // Check it is one we can check + int bStop = TRUE; + switch(nSpellCast) + { + case SPELL_ACID_FOG: + case SPELL_MIND_FOG: + case SPELL_STORM_OF_VENGEANCE: + case SPELL_GREASE: + case SPELL_CREEPING_DOOM: + case SPELL_SILENCE: + case SPELL_BLADE_BARRIER: + case SPELL_CLOUDKILL: + case SPELL_STINKING_CLOUD: + case SPELL_WALL_OF_FIRE: + case SPELL_INCENDIARY_CLOUD: + case SPELL_ENTANGLE: + case SPELL_EVARDS_BLACK_TENTACLES: + case SPELL_CLOUD_OF_BEWILDERMENT: + case SPELL_STONEHOLD: + case SPELL_VINE_MINE: + case SPELL_SPIKE_GROWTH: + case SPELL_VINE_MINE_HAMPER_MOVEMENT: + case SPELL_VINE_MINE_ENTANGLE: + { + bStop = FALSE; + } + break; + } + // Check immune level + int nImmuneLevel = GetOurSpellLevelImmunity(); + if(nImmuneLevel >= 9) + { + bStop = TRUE; + } + // Check + if(bStop == TRUE) + { + return; + } + // We do use intelligence here... + int nAIInt = GetBoundriedAIInteger(AI_INTELLIGENCE); + int bIgnoreSaves; + int bIgnoreImmunities; + object oAOE; + + // If it is low, we ignore all things that we could ignore with it... + if(nAIInt <= 3) + { + bIgnoreSaves = TRUE; + bIgnoreImmunities = TRUE; + } + // Average ignores saves + else if(nAIInt <= 7) + { + bIgnoreSaves = TRUE; + bIgnoreImmunities = FALSE; + } + // Else, we do both. + else + { + bIgnoreSaves = FALSE; + bIgnoreImmunities = FALSE; + } + + int bSetAOE = FALSE;// TRUE means set to timer + int nSaveDC = 11; + + // Get the caster DC, the most out of WIS, INT or CHA... + int nInt = GetAbilityModifier(ABILITY_INTELLIGENCE, oCaster); + int nWis = GetAbilityModifier(ABILITY_WISDOM, oCaster); + int nCha = GetAbilityModifier(ABILITY_CHARISMA, oCaster); + + if(nInt > nWis && nInt > nCha) + { + nSaveDC += nInt; + } + else if(nWis > nCha) + { + nSaveDC += nWis; + } + else + { + nSaveDC += nCha; + } + // Note: + // - No reaction type/friendly checks. Signal Event is only fired if the + // spell WILL pierce any PvP/Friendly/Area settings + + // We check immunities here, please note... + switch(nSpellCast) + { + // First: IS GetIsReactionTypeHostile ones. + case SPELL_EVARDS_BLACK_TENTACLES: + // Fortitude save, but if we are immune to the hits, its impossible to hurt us + { + // If save immune OR AC immune, we ignore this. + if(25 >= GetAC(OBJECT_SELF) && nImmuneLevel < 4 && + ((GetFortitudeSavingThrow(OBJECT_SELF) < nSaveDC + 2) || bIgnoreSaves)) + { + bSetAOE = TRUE; + // Nearest string of tag + oAOE = GetNearestAOECastBy(AI_AOE_PER_EVARDS_BLACK_TENTACLES, oCaster); + } + } + case SPELL_SPIKE_GROWTH: + case SPELL_VINE_MINE_HAMPER_MOVEMENT: + // d4 damage. LOTS of speed loss. + // Reflex save, or immunity, would stop the speed + { + if(nImmuneLevel < 3 && + (!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_MOVEMENT_SPEED_DECREASE) || bIgnoreImmunities) && + ((GetReflexSavingThrow(OBJECT_SELF) < nSaveDC + 5) || bIgnoreSaves)) + { + bSetAOE = TRUE; + // Both use ENTANGLE AOE's + oAOE = GetNearestAOECastBy(AI_AOE_PER_ENTANGLE, oCaster); + } + } + break; + case SPELL_ENTANGLE: + case SPELL_VINE_MINE_ENTANGLE: + { + if(nImmuneLevel < 1 && + (!GetHasFeat(FEAT_WOODLAND_STRIDE) || bIgnoreImmunities) && + (!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_ENTANGLE) || bIgnoreImmunities) && + ((GetReflexSavingThrow(OBJECT_SELF) < nSaveDC + 4) || bIgnoreSaves)) + { + bSetAOE = TRUE; + // Both use ENTANGLE AOE's + oAOE = GetNearestAOECastBy(AI_AOE_PER_ENTANGLE, oCaster); + } + } + break; + case SPELL_WEB: + { + if(nImmuneLevel < 1 && + (!GetHasFeat(FEAT_WOODLAND_STRIDE) || bIgnoreImmunities) && + (!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_ENTANGLE) || bIgnoreImmunities) && + ((GetReflexSavingThrow(OBJECT_SELF) < nSaveDC + 4) || bIgnoreSaves)) + { + bSetAOE = TRUE; + // Web AOE + oAOE = GetNearestAOECastBy(AI_AOE_PER_WEB, oCaster); + } + } + break; + // Fort save + case SPELL_STINKING_CLOUD: + { + if(nImmuneLevel < 3 && + (!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_POISON) || bIgnoreImmunities) && + (!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_DAZED) || bIgnoreImmunities) && + ((GetFortitudeSavingThrow(OBJECT_SELF) < nSaveDC + 6) || bIgnoreSaves)) + { + bSetAOE = TRUE; + // Stinking cloud persistant AOE. + oAOE = GetNearestAOECastBy(AI_AOE_PER_FOGSTINK, oCaster); + } + } + break; + // Fort save + case SPELL_CLOUD_OF_BEWILDERMENT: + { + if(nImmuneLevel < 2 && + ((GetFortitudeSavingThrow(OBJECT_SELF) < nSaveDC + 7) || bIgnoreSaves)) + { + bSetAOE = TRUE; + // Bewilderment cloud persistant AOE. + oAOE = GetNearestAOECastBy(AI_AOE_PER_FOGBEWILDERMENT, oCaster); + } + } + break; + // Special: Mind save is the effect. + case SPELL_STONEHOLD: + { + if(nImmuneLevel < 6 && + (!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_MIND_SPELLS) || bIgnoreImmunities) && + ((GetWillSavingThrow(OBJECT_SELF) < nSaveDC + 7) || bIgnoreSaves)) + { + bSetAOE = TRUE; + // Stonehold persistant AOE. + oAOE = GetNearestAOECastBy(AI_AOE_PER_STONEHOLD, oCaster); + } + } + break; + // Special: EFFECT_TYPE_SAVING_THROW_DECREASE is the effect. + case SPELL_MIND_FOG: + { + if(nImmuneLevel < 5 && + (!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_SAVING_THROW_DECREASE) || bIgnoreImmunities) && + ((GetWillSavingThrow(OBJECT_SELF) < nSaveDC + 6) || bIgnoreSaves)) + { + bSetAOE = TRUE; + // Mind fog + oAOE = GetNearestAOECastBy(AI_AOE_PER_FOGMIND, oCaster); + } + } + break; + // Special: Feats, knockdown + case SPELL_GREASE: + { + if(nImmuneLevel < 1 && + (!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_KNOCKDOWN) || bIgnoreImmunities) && + (!GetHasFeat(FEAT_WOODLAND_STRIDE, OBJECT_SELF) || bIgnoreImmunities) && + ((GetReflexSavingThrow(OBJECT_SELF) < nSaveDC + 2) || bIgnoreSaves)) + { + bSetAOE = TRUE; + // Grease + oAOE = GetNearestAOECastBy(AI_AOE_PER_GREASE, oCaster); + } + } + break; + // All other ReactionType ones. Some have different saves though! + case SPELL_BLADE_BARRIER: // Reflex + case SPELL_INCENDIARY_CLOUD:// reflex + case SPELL_WALL_OF_FIRE:// Reflex + { + if(nImmuneLevel < 6 && + (((GetReflexSavingThrow(OBJECT_SELF) < nSaveDC + 6) && + !GetHasFeat(FEAT_IMPROVED_EVASION) && + !GetHasFeat(FEAT_EVASION)) || bIgnoreSaves)) + { + bSetAOE = TRUE; + if(nSpellCast == SPELL_BLADE_BARRIER) + { + // BB + oAOE = GetNearestAOECastBy(AI_AOE_PER_WALLBLADE, oCaster); + } + else if(nSpellCast == SPELL_INCENDIARY_CLOUD) + { + // Fog of fire + oAOE = GetNearestAOECastBy(AI_AOE_PER_FOGFIRE, oCaster); + } + else if(nSpellCast == SPELL_WALL_OF_FIRE) + { + // Wall of fire + oAOE = GetNearestAOECastBy(AI_AOE_PER_WALLFIRE, oCaster); + } + } + } + break; + case SPELL_ACID_FOG: // Fort: Half. No check, always damages. + case SPELL_CLOUDKILL:// No save! + case SPELL_CREEPING_DOOM: // No save! + { + if(nImmuneLevel < 6) + { + bSetAOE = TRUE; + if(nSpellCast == SPELL_ACID_FOG) + { + // Acid fog + oAOE = GetNearestAOECastBy(AI_AOE_PER_FOGACID, oCaster); + } + else if(nSpellCast == SPELL_CLOUDKILL) + { + // Cloud Kill + oAOE = GetNearestAOECastBy(AI_AOE_PER_FOGKILL, oCaster); + } + else if(nSpellCast == SPELL_CREEPING_DOOM) + { + // Creeping doom + oAOE = GetNearestAOECastBy(AI_AOE_PER_CREEPING_DOOM, oCaster); + } + } + } + // Storm - because the AI likes it, we stay in it if it is ours :-) + case SPELL_STORM_OF_VENGEANCE: // Reflex partial. No check, always damages. + { + if(oCaster != OBJECT_SELF && nImmuneLevel < 9) + { + bSetAOE = TRUE; + // Storm of vengance + oAOE = GetNearestAOECastBy(AI_AOE_PER_STORM, oCaster); + } + } + } + if(bSetAOE) + { + if(!GetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(nSpellCast))) + { + SetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(nSpellCast), 18.0); + // Set nearest AOE + if(GetIsObjectValid(oAOE)) + { + // Set nearest AOE of this spell to the local + object oNearest = GetAIObject(AI_TIMER_AOE_SPELL_EVENT + IntToString(nSpellCast)); + if(GetDistanceToObject(oAOE) < GetDistanceToObject(oNearest) || + !GetIsObjectValid(oNearest)) + { + SetAIObject(AI_TIMER_AOE_SPELL_EVENT + IntToString(nSpellCast), oAOE); + } + } + } + } +} +// Gets the nearest AOE cast by oCaster, of sTag. +object GetNearestAOECastBy(string sTag, object oCaster) +{ + int nCnt = 1; + object oAOE = GetNearestObjectByTag(sTag, OBJECT_SELF, nCnt); + object oReturn = OBJECT_INVALID; + // Loop + while(GetIsObjectValid(oAOE) && !GetIsObjectValid(oReturn)) + { + // Check creator + if(GetAreaOfEffectCreator(oAOE) == oCaster) + { + oReturn = oAOE; + } + nCnt++; + oAOE = GetNearestObjectByTag(sTag, OBJECT_SELF, nCnt); + } + return oReturn; +} + +// Gets the amount of protections we have - IE globes +int GetOurSpellLevelImmunity() +{ + int nNatural = GetLocalInt(OBJECT_SELF, AI_SPELL_IMMUNE_LEVEL); + // Stop here, if natural is over 4 + if(nNatural > 4) return nNatural; + + // Big globe affects 4 or lower spells + if(GetHasSpellEffect(SPELL_GLOBE_OF_INVULNERABILITY, OBJECT_SELF) || nNatural >= 4) + return 4; + // Minor globe is 3 or under + if(GetHasSpellEffect(SPELL_MINOR_GLOBE_OF_INVULNERABILITY, OBJECT_SELF) || + // Shadow con version + GetHasSpellEffect(SPELL_GREATER_SHADOW_CONJURATION_MINOR_GLOBE, OBJECT_SELF) || + nNatural >= 3) + return 3; + // 2 and under is ethereal visage. + if(GetHasSpellEffect(SPELL_ETHEREAL_VISAGE, OBJECT_SELF) || nNatural >= 2) + return 2; + // Ghostly Visarge affects 1 or 0 level spells, and any spell immunity. + if(GetHasSpellEffect(SPELL_GHOSTLY_VISAGE, OBJECT_SELF) || nNatural >= 1 || + // Or shadow con version. + GetHasSpellEffect(SPELL_GREATER_SHADOW_CONJURATION_MIRROR_IMAGE, OBJECT_SELF)) + return 1; + // Return nNatural, which is 0-9 + return FALSE; +} diff --git a/_module/nss/j_ai_onuserdef.nss b/_module/nss/j_ai_onuserdef.nss new file mode 100644 index 00000000..f676cf33 --- /dev/null +++ b/_module/nss/j_ai_onuserdef.nss @@ -0,0 +1,326 @@ +/*/////////////////////// [On User Defined] //////////////////////////////////// + Filename: J_AI_OnUserDef or nw_c2_defaultd +///////////////////////// [Workings] /////////////////////////////////////////// + 1.4 Adds proper Pre-event functionality. Use this to make sure you keep the + AI working, but making small additions using this event. + + Can be deleted to save space if you want :-) + + How to use user defined events (brief): + + There are a set of optional Spawn In values you can set within the spawn file. + If you set one of the Events to fire, it will activate this script. Then, + under the correct choice (EG I choose the Pre-Heartbeat event, then I + uncomment the line "SetSpawnInCondition(AI_FLAG_UDE_HEARTBEAT_PRE_EVENT, AI_UDE_MASTER);" + and find, in this file, the section with EVENT_HEARTBEAT_PRE_EVENT above it). + add in whatever to do. + + With my Pre-heartbeat example, if I wanted it to check for a PC, then + check for a combat dummy, and attack it, I'd add this between the brackets: + + // Code: + + // Not in combat, of course! + if(!GetIsInCombat()) + { + // Function in j_inc_npc_attack to get nearest PC + object oPC = GetNearestPCCreature(); + // Why check for a PC? Well, it saves memory + if(GetIsObjectValid(oPC) && GetDistanceToObject(oPC) <= 40.0) + { + object oDummy = GetNearestObjectByTag("DUMMY"); + if(GetIsObjectValid(oDummy)) + { + ClearAllActions(); + ActionAttack(oDummy); + // Exit (Stop the rest of the script) + SetToExitFromUDE(EVENT_HEARTBEAT_PRE_EVENT); + // Stop rest of script + return; + } + } + } + + // End code + + Simple, no? + + You can delete sections you don't need, and is recommended as long as you know + how to use User Defined events. +///////////////////////// [History] //////////////////////////////////////////// + 1.3 - Added in with some documentation + 1.4 - Changed Pre-events. Now, it uses Execute Script. Will need to set + a special string on the creature to now what script to fire. + - It means they work correctly, however! +///////////////////////// [Arguments] ////////////////////////////////////////// + Arguments: Dependant on event. See seperate event scripts. +///////////////////////// [On User Defined] //////////////////////////////////*/ + +// This contains a lot of useful things. +// - Combat starting +// - Constant values +// - Get/Set spawn in values. +#include "J_INC_OTHER_AI" +// This contains some useful things to get NPC's to attack and so on. +#include "J_INC_NPC_ATTACK" + +/************************ [UDE Values] ***************************************** + These are uneeded, but here for reference. Use the constants in the file + "j_inc_constants" like "EVENT_HEARTBEAT_PRE_EVENT" which is classed as 1021. + * The normal death event might not fire before the creature has vanished. + Use the Pre-event (but with no stopping the death event) if you want a special + death event to happen. + + Name Normal-End event - Pre-Event + Heartbeat Event 1001 1021 + Percieve Event 1002 1022 + Combat Round Event 1003 1023 + Dialog Event 1004 1024 + Attack Event 1005 1025 + Damaged Event 1006 1026 + Death Event 1007 1027 + Disturbed Event 1008 1028 + Rested Event 1009 1029 + Spell Cast At Event 1011 1031 + Combat Action Event 1012 1032 + Damaged 1HP Event 1014 - + Blocked Event 1015 1035 +************************* [UDE Values] ****************************************/ + +void main() +{ + // Get the user defined number. + // * NOTE: YOU MUST USE AI_GetUDENumber(), not GetUserDefinedEventNumber()! + int nEvent = AI_GetUDENumber(); + + // Events. + switch(nEvent) + { + // Event Heartbeat + // Arguments: Basically, none. Nothing activates this script. Fires every 6 seconds. + case EVENT_HEARTBEAT_PRE_EVENT: + { + // This fires before the rest of the On Heartbeat file does + + // Exit (Stop the rest of the script) + SetToExitFromUDE(EVENT_HEARTBEAT_PRE_EVENT); + } + break; + case EVENT_HEARTBEAT_EVENT: + { + // This fires after the rest of the On Heartbeat file does + + } + break; + + // Event Percieve + // Arguments: GetLastPerceived, GetLastPerceptionSeen, GetLastPerceptionHeard, + // GetLastPerceptionVanished, GetLastPerceptionInaudible. + case EVENT_PERCIEVE_PRE_EVENT: + { + // This fires before the rest of the On Percieve file does + + // Exit (Stop the rest of the script) + SetToExitFromUDE(EVENT_PERCIEVE_PRE_EVENT); + } + break; + case EVENT_PERCIEVE_EVENT: + { + // This fires after the rest of the On Percieve file does + + } + break; + + // Event Combat Round End + // Arguments: GetAttackTarget, GetLastHostileActor, GetAttemptedAttackTarget, + // GetAttemptedSpellTarget (Or these are useful at least!) + case EVENT_END_COMBAT_ROUND_PRE_EVENT: + { + // This fires before the rest of the On Combat Round End file does + + // Exit (Stop the rest of the script) + SetToExitFromUDE(EVENT_END_COMBAT_ROUND_PRE_EVENT); + } + break; + case EVENT_END_COMBAT_ROUND_EVENT: + { + // This fires after the rest of the On Combat Round End file does + + } + break; + + // Event Dialogue + // Arguments: GetListenPatternNumber, GetLastSpeaker, TestStringAgainstPattern, + // GetMatchedSubstring (I think), + case EVENT_ON_DIALOGUE_PRE_EVENT: + { + // This fires before the rest of the dialog file does + + // Exit (Stop the rest of the script) + SetToExitFromUDE(EVENT_ON_DIALOGUE_PRE_EVENT); + } + break; + case EVENT_ON_DIALOGUE_EVENT: + { + // This fires after the rest of the dialog file does + + } + break; + + // Event Attacked + // Arguments: GetLastAttacker, GetLastWeaponUsed, GetLastAttackMode, + // GetLastAttackType + case EVENT_ATTACK_PRE_EVENT: + { + // This fires before the rest of the Attacked file does + + // Exit (Stop the rest of the script) + SetToExitFromUDE(EVENT_ATTACK_PRE_EVENT); + } + break; + case EVENT_ATTACK_EVENT: + { + // This fires after the rest of the Attacked file does + + } + break; + + // Event Damaged + // Arguments: GetTotalDamageDealt, GetLastDamager, GetCurrentHitPoints + // (and max), GetDamageDealtByType + case EVENT_DAMAGED_PRE_EVENT: + { + // This fires before the rest of the damaged file does + + // Exit (Stop the rest of the script) + SetToExitFromUDE(EVENT_DAMAGED_PRE_EVENT); + } + break; + case EVENT_DAMAGED_EVENT: + { + // This fires after the rest of the damaged file does + + } + break; + + // Event Death + // Arguments: GetLastKiller + case EVENT_DEATH_PRE_EVENT: + { + // This fires before the rest of the death file does + + // Exit (Stop the rest of the script) + SetToExitFromUDE(EVENT_DEATH_PRE_EVENT); + } + break; + case EVENT_DEATH_EVENT: + { + // This fires after the rest of the death file does + + } + break; + + // Event Distrubed + // Arguments: GetInventoryDisturbItem, GetLastDisturbed, + // GetInventoryDisturbType (should always be stolen :-( ). + case EVENT_DISTURBED_PRE_EVENT: + { + // This fires before the rest of the disturbed file does + + // Exit (Stop the rest of the script) + SetToExitFromUDE(EVENT_DISTURBED_PRE_EVENT); + } + break; + case EVENT_DISTURBED_EVENT: + { + // This fires after the rest of the disturbed file does + + } + break; + + // Event Rested + // Arguments: None + // Note: Not sure if this fires at the end of rest event, but the actual + // duration of the rest is 0, so you never "see" it. + case EVENT_RESTED_PRE_EVENT: + { + // This fires before the rest of the rested file does + + // Exit (Stop the rest of the script) + SetToExitFromUDE(EVENT_RESTED_PRE_EVENT); + } + break; + case EVENT_RESTED_EVENT: + { + // This fires after the rest of the rested file does + + } + break; + + // Event Spell cast at + // Arguments: GetLastSpellCaster, GetLastSpellHarmful GetLastSpell() + case EVENT_SPELL_CAST_AT_PRE_EVENT: + { + // This fires before the rest of the Spell Cast At file does + + // Exit (Stop the rest of the script) + SetToExitFromUDE(EVENT_SPELL_CAST_AT_PRE_EVENT); + } + break; + case EVENT_SPELL_CAST_AT_EVENT: + { + // This fires after the rest of the Spell Cast At End file does + + } + break; + + // Event Blocked + // Arguements: GetBlockingDoor, GetIsDoorActionPossible, GetLocked, + // GetLockKeyRequired, GetLockKeyTag, GetLockUnlockDC, GetPlotFlag. + case EVENT_ON_BLOCKED_PRE_EVENT: + { + // This fires before the rest of the on blocked file does + + // Exit (Stop the rest of the script) + SetToExitFromUDE(EVENT_ON_BLOCKED_PRE_EVENT); + } + break; + case EVENT_ON_BLOCKED_EVENT: + { + // This fires after the rest of the on blocked file does + + } + break; + + // Event Combat Action + // Arguments: GetAttackTarget(), and lots of others. + // Note: Fires when DetermineCombatRound runs to perform an action. + case EVENT_COMBAT_ACTION_PRE_EVENT: + { + // This fires before the rest of the Determine Combat Round call does + + // Exit (Stop the rest of the script) + SetToExitFromUDE(EVENT_COMBAT_ACTION_PRE_EVENT); + } + break; + case EVENT_COMBAT_ACTION_EVENT: + { + // This fires after the rest of the Determine Combat Round call does + // Calling ClearAllActions should stop any actions added in the call. + + } + break; + + // Event Damaged at 1 HP. + // Arguments: None really. + // Note: Fires OnDamaged, when we have exactly 1HP. Use for Immortal Creatures. + case EVENT_DAMAGED_AT_1_HP: + { + // This fires after the rest of the On Combat Round End file does + + } + break; + + // End all in-built events. Add more in here, if you wish. + } +} diff --git a/_module/nss/j_ai_setweapons.nss b/_module/nss/j_ai_setweapons.nss index e7d764b5..b5dd79e7 100644 --- a/_module/nss/j_ai_setweapons.nss +++ b/_module/nss/j_ai_setweapons.nss @@ -1,19 +1,21 @@ -/************************ [Set Weapons] **************************************** - Filename: j_ai_setweapons -************************* [Set Weapons] **************************************** +/*/////////////////////// [Set Weapons] //////////////////////////////////////// + Filename: J_AI_SetWeapons +///////////////////////// [Set Weapons] //////////////////////////////////////// Executed to re-set any weapons, or set them at spawn, using ExecuteScript. It isn't included in the generic AI or onspawn to try and speed it up a little -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.3 - Added to a new file, removed from spawn include. -************************* [Workings] ******************************************* + 1.4 - Nothing changed here. Include file might have changed however. +///////////////////////// [Workings] /////////////////////////////////////////// It can be easily re-added to the spawn include, however, the generic AI calls it so little, that it may well be useful to keep a seperate file anyway. -************************* [Arguments] ****************************************** +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: RESET_HEALING_KITS -************************* [Set Weapons] ***************************************/ +///////////////////////// [Set Weapons] //////////////////////////////////////*/ + +#include "J_INC_SETWEAPONS" -#include "j_inc_setweapons" void main() { if(GetAIInteger(RESET_HEALING_KITS)) diff --git a/_module/nss/j_ai_walkwaypoin.nss b/_module/nss/j_ai_walkwaypoin.nss index 3b4fc5f4..530dce28 100644 --- a/_module/nss/j_ai_walkwaypoin.nss +++ b/_module/nss/j_ai_walkwaypoin.nss @@ -1,17 +1,18 @@ -/************************ [Resume Waypoint Walking] **************************** +/*/////////////////////// [Resume Waypoint Walking] //////////////////////////// Filename: j_ai_walkwaypoin -************************* [Resume Waypoint Walking] **************************** +///////////////////////// [Resume Waypoint Walking] //////////////////////////// Executed On Spawn, and from the end of combat, to resume walking Notes: Needed my own file as to execute and be sure it exsisted. This means the Non-override version will not use 2 different waypoint files most of the time. -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.0 - Added 1.3 - Changed to SoU waypoints. fired from End of Spawn and heartbeat. It also returns to start location if set. -************************* [Workings] ******************************************* + 1.4 - +///////////////////////// [Workings] /////////////////////////////////////////// Might change to SoU waypoints, this, at the moment, will just walk normal waypoints. @@ -48,18 +49,21 @@ Waypoints can be between areas and creatures will move there, if you set a global integer variable called X2_SWITCH_CROSSAREA_WALKWAYPOINTS on your module to 1. -************************* [Arguments] ****************************************** +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: WAYPOINT_RUN, WAYPOINT_PAUSE are set On Spawn to remember the pause/run actions. -************************* [Resume Waypoint Walking] ***************************/ +///////////////////////// [Resume Waypoint Walking] //////////////////////////*/ -#include "j_inc_debug" #include "NW_I0_GENERIC" +#include "J_INC_DEBUG" const string WAYPOINT_RUN = "WAYPOINT_RUN"; const string WAYPOINT_PAUSE = "WAYPOINT_PAUSE"; const int AI_FLAG_OTHER_RETURN_TO_SPAWN_LOCATION = 0x00020000; const string AI_OTHER_MASTER = "AI_OTHER_MASTER"; +const string AI_LOCATION = "AI_LOCATION"; +const string AI_RETURN_TO_POINT = "AI_RETURN_TO_POINT"; + // For return to. int AI_GetSpawnInCondition(int nCondition, string sName, object oTarget = OBJECT_SELF); @@ -69,7 +73,7 @@ void main() // FIRST, if we are meant to move back to the start location, do it. if(AI_GetSpawnInCondition(AI_FLAG_OTHER_RETURN_TO_SPAWN_LOCATION, AI_OTHER_MASTER)) { - location lReturnPoint = GetLocalLocation(OBJECT_SELF, "AI_RETURN_TO_POINT"); + location lReturnPoint = GetLocalLocation(OBJECT_SELF, AI_LOCATION + AI_RETURN_TO_POINT); object oReturnArea = GetAreaFromLocation(lReturnPoint); if(GetIsObjectValid(oReturnArea)) { diff --git a/_module/nss/j_ai_wingbuffet.nss b/_module/nss/j_ai_wingbuffet.nss index 8c1a1502..c919d160 100644 --- a/_module/nss/j_ai_wingbuffet.nss +++ b/_module/nss/j_ai_wingbuffet.nss @@ -1,6 +1,6 @@ -/************************ [Dragon Wing Buffet] ********************************* +/*/////////////////////// [Ability - Dragon Wing Buffet] /////////////////////// Filename: J_AI_WingBuffet -************************* [Dragon Wing Buffet] ********************************* +///////////////////////// [Ability - Dragon Wing Buffet] /////////////////////// "The dragon will launch into the air, knockdown all opponents who fail a Reflex Save and then land on one of those opponents doing damage @@ -9,71 +9,90 @@ This is modified by Jasperre for use by Dragons in the AI. Instead of crashing, using effect appear, disspear, it just uses effect appear. -************************* [History] ******************************************** - Version 1.3 changes - - Made the "action attack" work better, getting the nearest - seen and heard instead of the nearest (which may not be seen or heard). - - Added in random damage for each target! - - Faction Equal as well as GetIsFriend check. -************************* [Workings] ******************************************* +///////////////////////// [History] //////////////////////////////////////////// + 1.3 - Made the "action attack" work better, getting the nearest + seen and heard instead of the nearest (which may not be seen or heard). + - Added in random damage for each target! + - Faction Equal as well as GetIsFriend check. + 1.4 - Cleaned it up a bit, to be more readable. +///////////////////////// [Workings] /////////////////////////////////////////// Executed via. ExecuteScript from the AI file, it is seperate because it is almost a new AI ability. -************************* [Arguments] ****************************************** +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: N/A -************************* [Dragon Wing Buffet] ********************************/ +///////////////////////// [Ability - Dragon Wing Buffet] /////////////////////*/ void main() { - //Declare major variables + // Stop the creature's actions. ClearAllActions();// To rid errors. - effect eKnockDown = EffectKnockdown(); + + // Declare major variables int nDamage; int nDC = GetHitDice(OBJECT_SELF); - effect eDam; - effect eVis = EffectVisualEffect(VFX_IMP_PULSE_WIND); - // Use a delay based on range, - float fDelay; location lSelf = GetLocation(OBJECT_SELF); string sMessage = GetName(OBJECT_SELF) + " is using its wing buffet against you!"; location lTarget; float fRandomKnockdown; + // Use a delay based on range, + float fDelay; + + // Declare effects + effect eDam; + effect eKnockDown = EffectKnockdown(); + effect eVis = EffectVisualEffect(VFX_IMP_PULSE_WIND); + // Pulse of wind applied... ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, lSelf); - //Apply the VFX impact and effects - //Get first target in spell area + + // Get first target in spell area object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_GARGANTUAN, lSelf); while(GetIsObjectValid(oTarget)) { + // Get thier location (for visual) and the delay. lTarget = GetLocation(oTarget); fDelay = GetDistanceToObject(oTarget)/20.0; + // Wind pulse to all DelayCommand(fDelay, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, lTarget)); - //Get next target in spell area + // Do not effect allies. if(!GetIsFriend(oTarget) && !GetFactionEqual(oTarget)) { + // Send a message about the wing buffet (allies do not see this) SendMessageToPC(oTarget, sMessage); + + // Huge creatures (IE: Dragon size) are not affected. if(GetCreatureSize(oTarget) != CREATURE_SIZE_HUGE) { + // A standard (not spell) reflex save negates the damage and knockdown if(!ReflexSave(oTarget, nDC)) { // Randomise damage. (nDC = Hit dice) nDamage = Random(nDC) + 11; + + // Define the damage eDam = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING); - // Randomise knockdown, to minimum of 6.0 (1.0/2 = 0.5. + 5.5 = 6.0) + + // Randomise knockdown duration, to minimum of 6.0 (1.0/2 = 0.5. + 5.5 = 6.0) fRandomKnockdown = 5.5 + ((IntToFloat(Random(30)) + 1.0)/10.0); + // We'll have a windy effect..depending on range DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)); DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eKnockDown, oTarget, fRandomKnockdown)); } } } + // Get next target in spell area oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_GARGANTUAN, lSelf); } + // Do a great flapping wings on land effect. effect eAppear = EffectAppear(); ApplyEffectToObject(DURATION_TYPE_INSTANT, eAppear, OBJECT_SELF); - // Attack the nearest seen (so not to stand there for 6 seconds). + + // Attack the nearest seen (so not to stand there for 6 seconds, but get + // back in the action!). object oNearest = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE); if(GetIsObjectValid(oNearest)) { diff --git a/_module/nss/j_ai_wingflying.nss b/_module/nss/j_ai_wingflying.nss index c149a70f..3f8f8b31 100644 --- a/_module/nss/j_ai_wingflying.nss +++ b/_module/nss/j_ai_wingflying.nss @@ -1,6 +1,6 @@ -/************************ [Dragon Flying] ************************************** +/*/////////////////////// [Ability - Dragon Flying] //////////////////////////// Filename: J_AI_WingFlying -************************* [Dragon Flying] ************************************** +///////////////////////// [Ability - Dragon Flying] //////////////////////////// Hey, a dragon can fly (if we are set to, mind you!) this is executed from the default AI, using local objects to "fly" to, a duration based on the distance between the 2 places. @@ -13,10 +13,11 @@ - Can be used with NPC's who are not dragons, but if they are not huge, the damage is not done (only the pulses at thier location and the target location) -************************* [History] ******************************************** - Version 1.3 - - Added -************************* [Workings] ******************************************* +///////////////////////// [History] //////////////////////////////////////////// + 1.3 - Added + 1.4 - Added an actual spell event fire for the damage. It might not have + registered with some hostile monsters otherwise! (EG: DR) +///////////////////////// [Workings] /////////////////////////////////////////// Executed via. ExecuteScript from the AI file, it is seperate because it is almost a new AI ability. @@ -24,11 +25,11 @@ 1M between targets. Not too much, but enough. Does damage to landing and taking off sites too :-) -************************* [Arguments] ****************************************** +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: N/A -************************* [Dragon Flying] *************************************/ +///////////////////////// [Ability - Dragon Flying] //////////////////////////*/ -#include "j_inc_constants" +#include "J_INC_CONSTANTS" // Damages area with blast of flying void DoDamageToArea(location lLocation); @@ -55,7 +56,7 @@ void main() if(GetCreatureSize(OBJECT_SELF) == CREATURE_SIZE_HUGE) { // Damage instantly - DelayCommand(f1, DoDamageToArea(lSelf)); + DelayCommand(1.0, DoDamageToArea(lSelf)); // Delay the jump down damage - a little extra delay mind you. DelayCommand(fDuration + 1.2, DoDamageToArea(lJumpTo)); } @@ -64,7 +65,7 @@ void main() // Visual effects only effect eImpact = EffectVisualEffect(VFX_IMP_PULSE_WIND); // Pulse of wind applied... - DelayCommand(f1, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpact, lSelf)); + DelayCommand(1.0, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpact, lSelf)); // Delay the new wind DelayCommand(fDuration + 1.2, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpact, lJumpTo)); } @@ -72,7 +73,7 @@ void main() DelayCommand(fDuration + 1.5, ActionAttack(oJumpTo)); effect eFly = EffectDisappearAppear(lJumpTo); - DelayCommand(f1, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eFly, OBJECT_SELF, fDuration - f1)); + DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eFly, OBJECT_SELF, fDuration - 1.0)); } // Damages area with blast of flying @@ -109,6 +110,10 @@ void DoDamageToArea(location lLocation) // Can't knock over huge things! if(GetCreatureSize(oTarget) != CREATURE_SIZE_HUGE) { + // Signal spell cast at event + // * Using: SPELLABILITY_DRAGON_WING_BUFFET - just so something is used + SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELLABILITY_DRAGON_WING_BUFFET)); + // Reflex save for damage if(!ReflexSave(oTarget, nDC)) { diff --git a/_module/nss/j_inc_constants.nss b/_module/nss/j_inc_constants.nss index 5da97986..2fe4fd58 100644 --- a/_module/nss/j_inc_constants.nss +++ b/_module/nss/j_inc_constants.nss @@ -1,13 +1,22 @@ -/************************ [Constants] ****************************************** - Filename: j_inc_constants -************************* [Constants] ****************************************** +/*/////////////////////// [Include - Constants] //////////////////////////////// + Filename: J_INC_Constants +///////////////////////// [Include - Constants] //////////////////////////////// This file just holds many constants, and many common functions (EG: Set and Get spawn in conditions) to stop repeating code. See workings for more information. -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.3 - Added to make sure things are not repeated + constants in one place -************************* [Workings] ******************************************* + 1.4 - Removed the silly (well, now I think it is silly) definitions of + i1, i2 etc. It looks annoying anyway. Won't save much code (or any) + as the constants mearly put the 1 to where i1 is in the code anyway. + - TO DO: + - Sort out constants. Add new ones for sea hag, and other new abilities. + + - Fixed a few minor errors. + - Formatted correctly now + - Removed all i0, i1 etc. And make sure the AI has all of them removed. +///////////////////////// [Workings] /////////////////////////////////////////// By using the SoU implimented way of defining static variables, "const" means I can have a whole include which will include all used variables - this keeps it all uniformed, and compiles better - as in all variable names @@ -21,13 +30,13 @@ - To Do - Impliment better Debug system (see j_inc_debug) which you can uncomment them long debug strings so that they don't get added to compiled scripts if not used. -************************* [Arguments] ****************************************** +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: N/A -************************* [Constants] *****************************************/ +///////////////////////// [Include - Constants] //////////////////////////////*/ // This makes most scripts have debug anyway, and so its there :-). // Multiple includes are ignored anyway :-D -#include "j_inc_debug" +#include "J_INC_DEBUG" // This is a seperate script from all others. It is executed if a creature wants // to DetermineCombatRound. It must be seperate to have override and non-override @@ -54,82 +63,21 @@ const string FILE_HEARTBEAT_WALK_TO_PC = "j_ai_heart_serch"; const string FILE_DRAGON_WING_BUFFET = "j_ai_wingbuffet"; const string FILE_FLY_ATTACK = "j_ai_wingflying"; +// Special for "I_WAS_OPENED" shout. +const string FILE_SET_OPENER = "j_ai_setopener"; + // Spell trigger creation file const string FILE_SPELLTRIGGER_START = "j_ai_spelltrig1"; +// Default User Defined Event file name - for the default AI file +const string FILE_DEFAULT_UDE = "nw_c2_defaultd"; + // Special: custom AI script set to a standard local string to this: const string AI_CUSTOM_AI_SCRIPT = "AI_CUSTOM_AI_SCRIPT"; /******************************************************************************/ -// Simple constants to save re-typing ETC. +// Special constants /******************************************************************************/ -// Just trying this. It won't harm anything, as with the const word, if the -// numbers are not used, they are not added, but if they are, getting them from -// these might be better. -// - Especially used for imputting the spell talent numbers, and required -// INT, WIS or CHA for that spell. :-D -const int iM10 = -10;// Dying threshold - die at -11 -const int iM1 = -1; -const int i0 = 0; -const int i1 = 1; -const int i2 = 2; -const int i3 = 3; -const int i4 = 4; -const int i5 = 5; -const int i6 = 6; -const int i7 = 7; -const int i8 = 8; -const int i9 = 9; -const int i10 = 10; -const int i11 = 11; -const int i12 = 12; -const int i13 = 13; -const int i14 = 14; -const int i15 = 15; -const int i16 = 16; -const int i17 = 17; -const int i18 = 18; -const int i19 = 19; -const int i20 = 20; -const int i21 = 21; -const int i22 = 22; -const int i23 = 23;// SpellAllSpells -const int i24 = 24; -const int i25 = 25; -const int i30 = 30; -const int i35 = 35; -const int i40 = 40;// Here onwards are normally %'s -const int i50 = 50; -const int i60 = 60; -const int i70 = 70; -const int i80 = 80; -const int i90 = 90; -const int i99 = 99; -const int i100 = 100; -const int i150 = 150;// Limit for PW Stun - -const float f0 = 0.0; -const float f1 = 1.0; -const float f2 = 2.0; -const float f3 = 3.0; -const float f4 = 4.0; -const float f5 = 5.0; -const float f6 = 6.0;// 1 heartbeat/round -const float f8 = 8.0;// Useful...for some reason -const float f9 = 9.0; -const float f10 = 10.0; -const float f11 = 11.0;// Range for some spell cones -const float f12 = 12.0;// 2 heartbeats/rounds -const float f15 = 15.0; -const float f16 = 16.0;// Double f8, the range of summon spells. -const float f18 = 18.0;// 3 heartbeats/rounds -const float f20 = 20.0; -const float f24 = 24.0;// 4 heartbeats/rounds -const float f30 = 30.0; -const float f35 = 35.0; -const float f40 = 40.0; -const float f50 = 50.0; -const float f60 = 60.0; // Ranges for spells - from Ranges.2da const float fTouchRange = 2.25; @@ -140,7 +88,7 @@ const float fLongRange = 40.0; // Types: // S. = Stored // FILENAME -// CONSTANT + // S.CONSTANT // S.INTEGER // S.OBJECT @@ -150,11 +98,34 @@ const float fLongRange = 40.0; // Global overriding actions /******************************************************************************/ // Leader thing -const int AI_SPECIAL_ACTIONS_ME_RUNNER = 1; // CONSTANT +const int AI_SPECIAL_ACTIONS_ME_RUNNER = 1; // Fleeing -const int AI_SPECIAL_ACTIONS_FLEE = 2; // CONSTANT +const int AI_SPECIAL_ACTIONS_FLEE = 2; // Moving out of a pre-set AOE. -const int AI_SPECIAL_ACTIONS_MOVE_OUT_OF_AOE = 3; // CONSTANT +const int AI_SPECIAL_ACTIONS_MOVE_OUT_OF_AOE = 3; +// Searching around after combat. +const int AI_SPECIAL_ACTIONS_SEARCH_AROUND = 4; +// Move to combat - we buff (and only buff again after 1 minute of running) +// and either follow the person who wants us to help them, or we will run to the +// location set. +// * Can be set via. most shouts. +const int AI_SPECIAL_ACTIONS_MOVE_TO_COMBAT = 5; + +// Special for "move to combat". If there was something who called to us, we will +// follow them - or at least move to them - if there is no location to move to. +const string AI_MOVE_TO_COMBAT_OBJECT = "AI_MOVE_TO_COMBAT_OBJECT"; +// Another special. This will be set to the location that can be used for +// the "special actions move to combat" action. +const string AI_MOVE_TO_COMBAT_LOCATION = "AI_MOVE_TO_COMBAT_LOCATION"; +// Timer constant - set for 60 seconds to stop lots of spells being cast before +// we move, but we do cast 1. +const string AI_TIMER_MOVE_TO_COMBAT_BUFF = "AI_TIMER_MOVE_TO_COMBAT_BUFF"; + +// Needed for overriding search action: +// * Amount of rounds left to search using special action on heartbeat +const string AI_SEARCH_ROUNDS_REMAINING = "AI_SEARCH_ROUNDS_REMAINING"; +// * Target (dead body?) to move near to search around +const string AI_SEARCH_TARGET = "AI_SEARCH_TARGET"; // This is trap thing. If we (on heartbeat) start disarming a trap, can we // ignore it in combat? @@ -163,10 +134,12 @@ const string TRAP_CAN_IGNORE_IN_COMBAT = "TRAP_CAN_IGNORE_IN_COMBAT // Override for all AI scripts const string AI_TOGGLE = "AI_TOGGLE"; // INTEGER -// Set to a local int... -// 1 = Beholder AI -// 2 = Mindflayer AI +// Set to a local int...special AI executed like Bioware's const string AI_SPECIAL_AI = "AI_SPECIAL_AI"; +// 1 = Beholder AI +const int AI_SPECIAL_AI_BEHOLDER = 1; +// 2 = Mindflayer AI +const int AI_SPECIAL_AI_MINDFLAYER = 2; // Set to the last AI spell category cast. const string ITEM_TALENT_VALUE = "ITEM_TALENT_VALUE"; // S.CONSTANT @@ -197,11 +170,6 @@ const string AI_SPELL_IMMUNE_LEVEL = "AI_SPELL_IMMUNE_LEVEL"; const string AI_EFFECT_HEX = "AI_EFFECT_HEX"; const string AI_SPELL_HEX = "AI_SPELL_HEX"; const string AI_ABILITY_DECREASE = "AI_ABILITY_DECREASE"; -// Timer for resetting PC effects -const string AI_TIMER_EFFECT_SET = "AI_TIMER_EFFECT_SET"; -// This is not a timer, but if 1, it means the NPC uses Jasperre's AI and sets -// thier own effects -const string AI_JASPERRES_EFFECT_SET = "AI_JASPERRES_EFFECT_SET"; // This is a timer for checking allies for spell effects, for buffing. // - If TRUE, it won't loop around until it finds one to cast at. // AI_TIMER_BUFF_ALLY_SPELL + IntToString(iSpell); @@ -260,53 +228,25 @@ const string AI_SPELLTRIG_PREFIX = "AI_SPELLTRIG_PREFIX"; // FEATS // THese are the forgotten ones. Others are remembered. // I have left OUT the ones which we cannot "use" +// 1.4: Removed ones now added in 1.64. Added some needed for AI_ActionUseSpellLikeFeat(). // These are blackguard. Note that they are under spell abilities, but I'd rather // use them as ActionUseFeat. -const int AI_FEAT_BG_CREATE_UNDEAD = 474; // CONSTANT -const int AI_FEAT_BG_FIENDISH_SERVANT = 475; // CONSTANT -// Othes -const int AI_FEAT_PM_CREATE_UNDEAD = 890; -const int AI_FEAT_PM_ANIMATE_DEAD = 889; -const int AI_FEAT_PM_CREATE_GREATER_UNDEAD = 895; - -// Polymorphing ones missing -const int AI_FEAT_EPIC_WILD_SHAPE_UNDEAD = 872; -const int AI_FEAT_EPIC_WILD_SHAPE_DRAGON = 873; -const int AI_FEAT_GREATER_WILDSHAPE_1 = 898; -const int AI_FEAT_GREATER_WILDSHAPE_2 = 900; -const int AI_FEAT_GREATER_WILDSHAPE_3 = 901; -const int AI_FEAT_HUMANOID_SHAPE = 902; -const int AI_FEAT_GREATER_WILDSHAPE_4 = 903; - -const int AI_FEAT_EPIC_OUTSIDER_SHAPE = 1060; -const int AI_FEAT_EPIC_CONSTRUCT_SHAPE = 1061; -const int AI_FEAT_EPIC_SHIFTER_INFINITE_WILDSHAPE_1 = 1062; -const int AI_FEAT_EPIC_SHIFTER_INFINITE_WILDSHAPE_2 = 1063; -const int AI_FEAT_EPIC_SHIFTER_INFINITE_WILDSHAPE_3 = 1064; -const int AI_FEAT_EPIC_SHIFTER_INFINITE_WILDSHAPE_4 = 1065; -const int AI_FEAT_EPIC_SHIFTER_INFINITE_HUMANOID_SHAPE = 1066; -const int AI_FEAT_EPIC_DRUID_INFINITE_WILDSHAPE = 1068; -const int AI_FEAT_EPIC_DRUID_INFINITE_ELEMENTAL_SHAPE = 1069; - -const int AI_FEAT_EPIC_PLANAR_TURNING = 854; +// 1.64: BG_CREATE_UNDEAD still under constant FEAT_INFLICT_LIGHT_WOUNDS +const int AI_FEAT_BG_CREATE_UNDEAD = 474; +// 1.64: Still under FEAT_INFLICT_MODERATE_WOUNDS. +const int AI_FEAT_BG_FIENDISH_SERVANT = 475; // Used in tunr undead checking. Faster then looping effects - GetHasSpellEffect(AI_SPELL_FEAT_TURN_UNDEAD); const int AI_SPELL_FEAT_TURN_UNDEAD = 308; - -const int AI_SPELL_EVIL_BLIGHT = 566; const int AI_SPELL_FEAT_PLANAR_TURNING = 643; +// We are missing the feat for planar turning *still* in 1.64 +const int AI_FEAT_EPIC_PLANAR_TURNING = 854; -// Epic spells are feats, but act like spells. -const int AI_FEAT_EPIC_SPELL_MUMMY_DUST = 874; -// SPELL_EPIC_MUMMY_DUST -const int AI_FEAT_EPIC_SPELL_DRAGON_KNIGHT = 875; -// SPELL_EPIC_DRAGON_KNIGHT -const int AI_FEAT_EPIC_SPELL_HELLBALL = 876; -const int AI_FEAT_EPIC_SPELL_EPIC_MAGE_ARMOR = 877; -const int AI_FEAT_EPIC_SPELL_RUIN = 878; -const int AI_FEAT_EPIC_SPELL_EPIC_WARDING = 990; +// Missing *actual* spell constant, still missing in 1.64. +const int AI_SPELL_EVIL_BLIGHT = 566; +// Epic constants. 1.64: Only the spell for Epic Warding is missing. const int AI_SPELL_EPIC_WARDING = 695; // healing ones missed @@ -314,24 +254,34 @@ const int AI_SPELL_EPIC_WARDING = 695; const int AI_SPELLABILITY_UNDEAD_HARM_SELF = 759; // Cure Others Critical Wounds const int AI_SPELLABILITY_CURE_CRITICAL_WOUNDS_OTHER= 567; +// Restoration others +const int AI_SPELLABILITY_RESTORATION_OTHERS = 568; +// 1.4: WHAT IS THIS?!??!? // Subspell set to this: const string AI_SPELL_SUB_SPELL_CAST = "AI_SPELL_SUB_SPELL_CAST"; +// All invalid spell instances are -1. +const int AI_SPELL_INVALID = -1; + // For checking if they have this spell's effects. Most are feats, if not all. -const int AI_SPELL_BARD_SONG = 411; // CONSTANT -const int AI_SPELL_CURSE_SONG = 644; // CONSTANT +const int AI_SPELLABILITY_BARD_SONG = 411; +// * 1.4: Curse song is now under SPELLABILITY_EPIC_CURSE_SONG. // - hordes - still not in! -const int AI_SPELL_OWLS_INSIGHT = 438; // CONSTANT +const int AI_SPELL_OWLS_INSIGHT = 438; // These are not anywhere, even though blackguard and AA ones are -const int AI_SPELL_HARPER_CATS_GRACE = 481; -const int AI_SPELL_HARPER_EAGLE_SPLEDOR = 482; +const int AI_SPELLABILITY_HARPER_SLEEP = 480; +const int AI_SPELLABILITY_HARPER_CATS_GRACE = 481; +const int AI_SPELLABILITY_HARPER_EAGLE_SPLEDOR = 482; +const int AI_SPELLABILITY_HARPER_INVISIBILITY = 483; // Shifter only spells (monster abilities) that are limited +const int AI_SPELLABILITY_BLINDING_SPEED = 647; const int AI_SPELLABILITY_GWILDSHAPE_STONEGAZE = 687; const int AI_SPELLABILITY_GWILDSHAPE_DRIDER_DARKNESS= 688; +const int AI_SPELLABILITY_DIS_BREATH = 690;// Dragon Disciple breath. const int AI_SPELLABILITY_GWILDSHAPE_SPIKES = 692;// Manticore Spikes - no limit const int AI_SPELLABILITY_GWILDSHAPE_MINDBLAST = 693;// GWildShape_Mindblast const int AI_SPELLABILITY_VAMPIRE_DOMINATION_GAZE = 800;// Dom gaze. @@ -345,8 +295,9 @@ const int AI_SPELLABILITY_EYEBALL_RAY_1 = 711;// EyeballRay1 const int AI_SPELLABILITY_EYEBALL_RAY_2 = 712;// EyeballRay2 const int AI_SPELLABILITY_MINDFLAYER_MINDBLAST_10 = 713;// Mindflayer Mindblast 10 const int AI_SPELLABILITY_MINDFLAYER_PARAGON_MINDBLAST = 714;// Mindflayer Paragon Mindblast -const int AI_SPELLABILITY_GOLEM_RANGED_SLAM = 715; +const int AI_SPELLABILITY_GOLEM_RANGED_SLAM = 715;// Ranged slam, pretty neat. const int AI_SPELLABILITY_SUCKBRAIN = 716;// SuckBrain +const int AI_SPELLABILITY_ETHEREALNESS = 724;// Missing constant - and a monster ability only! const int AI_SPELLABILITY_BEHOLDER_MAGIC_CONE = 727;// Beholder_Anti_Magic_Cone const int AI_SPELLABILITY_BEBELITH_WEB = 731;// Bebelith Web const int AI_SPELLABILITY_BEHOLDER_ALLRAYS = 736;// Beholder_Special_Spell_AI @@ -357,10 +308,10 @@ const int AI_SPELLABILITY_HELL_INFERNO = 762;// Hell Inferno - wors const int AI_SPELLABILITY_PSIONIC_MASS_CONCUSSION = 763;// Damage to AOE - psiconic mass concussion const int AI_SPELLABILITY_SHADOW_ATTACK = 769;// SHIFTER Shadow Attack - also shifter const int AI_SPELLABILITY_SLAAD_CHAOS_SPITTLE = 770;// SHIFTER Slaad Chaos Spittle - also shifter -const int AI_SPELLABILITY_BATTLE_BOULDER_TOSS = 773; +const int AI_SPELLABILITY_BATTLE_BOULDER_TOSS = 773;// Battle - hordes only, but added as it is an actual thing const int AI_SPELLABILITY_PRISMATIC_DEFLECTING_FORCE= 774;// Deflecting_Force -const int AI_SPELLABILITY_GIANT_HURL_ROCK = 775; -const int AI_SPELLABILITY_ILLITHID_MINDBLAST = 789; +const int AI_SPELLABILITY_GIANT_HURL_ROCK = 775;// Cool - Giant hurls a large rock +const int AI_SPELLABILITY_ILLITHID_MINDBLAST = 789;// Ilithid mindblast. const int AI_SPELLABILITY_VAMPIRE_INVISIBILITY = 799;// SHIFTER Vampire Invis. const int AI_SPELLABILITY_AZER_FIRE_BLAST = 801;// SHIFTER Fire Blast. const int AI_SPELLABILITY_SHIFTER_SPECTRE_ATTACK = 802;// SHIFTER Spectire Attack. @@ -383,8 +334,9 @@ const string AI_AOE_PER_STONEHOLD = "VFX_PER_STONEHOLD"; const string AI_AOE_PER_WEB = "VFX_PER_WEB"; // When we ActionAttack -const int AI_NORMAL_MELEE_ATTACK = 1000; // CONSTANT -const int AI_PARRY_ATTACK = 2000; // CONSTANT +const int AI_NORMAL_MELEE_ATTACK = 1000; +const int AI_NORMAL_RANGED_ATTACK = 1500; +const int AI_PARRY_ATTACK = 2000; /******************************************************************************/ // The ignore string. If a creature has this set to anything but 0, then the AI ignores them. @@ -417,37 +369,44 @@ const string AI_VALID_HEALING_KIT_OBJECT = "AI_VALID_HEALING_KIT_OBJE const string AI_VALID_HEALING_KITS = "AI_VALID_HEALING_KITS"; // S.INTEGER // Set to TRUE before re-setting things, it ignores weapons, only does healing kits. const string RESET_HEALING_KITS = "RESET_HEALING_KITS"; // S.INTEGER -// TRUE if any of the SoU animations are valid. -const string AI_VALID_ANIMATIONS = "AI_VALID_ANIMATIONS"; // The amounts set to these are waypoint things const string WAYPOINT_RUN = "WAYPOINT_RUN"; const string WAYPOINT_PAUSE = "WAYPOINT_PAUSE"; -// S.FLOAT /******************************************************************************/ // Shout strings. /******************************************************************************/ +// 0 - Anything said +const int AI_SHOUT_ANYTHING_SAID_CONSTANT = 0; // 1 - I was attacked. :-P -const string I_WAS_ATTACKED = "I_WAS_ATTACKED"; // CONSTANT +const int AI_SHOUT_I_WAS_ATTACKED_CONSTANT = 1; +const string AI_SHOUT_I_WAS_ATTACKED = "I_WAS_ATTACKED"; // 2 is blocked NWN thingy +const int AI_SHOUT_BLOCKER_CONSTANT = 2; // 3 - Call to arms - Determines combat round -const string CALL_TO_ARMS = "CALL_TO_ARMS"; // CONSTANT +const int AI_SHOUT_CALL_TO_ARMS_CONSTANT = 3; +const string AI_SHOUT_CALL_TO_ARMS = "CALL_TO_ARMS"; // 4 - Runner shout (shouts on heartbeat if running) -const string HELP_MY_FRIEND = "HELP_MY_FRIEND"; // CONSTANT -// 5 - Leader flee now -const string LEADER_FLEE_NOW = "LEADER_FLEE_NOW"; // CONSTANT +const int AI_SHOUT_HELP_MY_FRIEND_CONSTANT = 4; +const string AI_SHOUT_HELP_MY_FRIEND = "HELP_MY_FRIEND"; +// 5 - Leader flee now. Does what it says on the tin. +const int AI_SHOUT_LEADER_FLEE_NOW_CONSTANT = 5; +const string AI_SHOUT_LEADER_FLEE_NOW = "LEADER_FLEE_NOW"; // 6 - Attack target X (specific target) -const string LEADER_ATTACK_TARGET = "LEADER_ATTACK_TARGET"; // CONSTANT +const int AI_SHOUT_LEADER_ATTACK_TARGET_CONSTANT = 6; +const string AI_SHOUT_LEADER_ATTACK_TARGET = "LEADER_ATTACK_TARGET"; // 7 - I was killed - May flee if lots die! -const string I_WAS_KILLED = "I_WAS_KILLED"; // CONSTANT +const int AI_SHOUT_I_WAS_KILLED_CONSTANT = 7; +const string AI_SHOUT_I_WAS_KILLED = "I_WAS_KILLED"; // 8 - 1.3 - PLaceables/doors which shout this get responded to! -const string I_WAS_OPENED = "I_WAS_OPENED"; // CONSTANT +const int AI_SHOUT_I_WAS_OPENED_CONSTANT = 8; +const string AI_SHOUT_I_WAS_OPENED = "I_WAS_OPENED"; // Extra - runner location variable (local location) const string AI_HELP_MY_FRIEND_LOCATION = "AI_HELP_MY_FRIEND_LOCATION";// LOCATION // Set on a placeable, by the placeable - thier last opener. -const string PLACEABLE_LAST_OPENED_BY = "PLACEABLE_LAST_OPENED_BY";// Object +const string AI_PLACEABLE_LAST_OPENED_BY = "AI_PLACEABLE_LAST_OPENED_BY";// Object /******************************************************************************/ // All timers (the end bits. Not the prefixes.) @@ -467,9 +426,6 @@ const string AI_TIMER_AOE_SPELL_EVENT = "AI_TIMER_AOE_SPELL_EVENT" const string AI_TIMER_FLEE = "AI_TIMER_FLEE"; const string AI_TIMER_LEADER_SENT_RUNNER = "AI_TIMER_LEADER_SENT_RUNNER"; -// Special search timer - stops calling Search() -const string AI_TIMER_SEARCH = "AI_TIMER_SEARCH_TIMER"; // S.INTEGER - // On phisical attacked - if knockdown adn they can hit us (and not doofing the AI) // then we use healing sooner as, basically, we may be knockdowned too much! const string AI_TIMER_KNOCKDOWN = "AI_TIMER_KNOCKDOWN_TIMER"; @@ -500,6 +456,7 @@ const string AI_TALK_ON_TAUNT = "AI_TALK_ON_TAUNT"; const string AI_TALK_ON_LEADER_SEND_RUNNER = "AI_TALK_ON_LEADER_SEND_RUNNER"; const string AI_TALK_ON_LEADER_ATTACK_TARGET = "AI_TALK_ON_LEADER_ATTACK_TARGET"; +const string AI_TALK_ON_LEADER_BOSS_SHOUT = "AI_TALK_ON_LEADER_BOSS_SHOUT"; // Constant for the Size of the a string array - the prefix. const string ARRAY_SIZE = "ARRAY_SIZE_"; // S.STRING const string ARRAY_PERCENT = "ARRAY_PER_"; // S.STRING @@ -554,8 +511,8 @@ const string AI_WEAPON_RANGED_IS_UNLIMITED = "AI_WEAPON_RANGED_IS_UNLIM const string AI_WEAPON_SHIELD = "AI_WEAPON_SHIELD"; // S.OBJECT const string AI_WEAPON_SHIELD_2 = "AI_WEAPON_SHIELD_2"; // S.OBJECT // End post-fixs as it were -const string WEAP_SIZE = "AI_WEAP_SIZE"; // CONSTANT -const string WEAP_DAMAGE = "AI_WEAP_DAMAGE"; // CONSTANT +const string WEAP_SIZE = "AI_WEAP_SIZE"; +const string WEAP_DAMAGE = "AI_WEAP_DAMAGE"; /******************************************************************************* Constants for spawn options @@ -581,6 +538,8 @@ const string WEAP_DAMAGE = "AI_WEAP_DAMAGE"; /******************************************************************************/ const string AI_UDE_MASTER = "AI_UDE_MASTER"; const string EXIT_UDE_PREFIX_ = "EXIT_UDE_PREFIX_";// Exit string, like EXIT_UDE_PREFIX_1001 is the heartbeat exit +const string AI_PRE_EVENT_NUMBER = "AI_PRE_EVENT_NUMBER";// Set if it is a pre-event +const string AI_UDE_SCRIPT_NAME = "AI_UDE_SCRIPT_NAME";// The script that User Defined Events are run /******************************************************************************/ /******************************************************************************/ @@ -691,6 +650,8 @@ const int AI_FLAG_FLEEING_NEVER_FIGHT_IMPOSSIBLE_ODDS = 0x00000800; const int AI_FLAG_FLEEING_TURN_OFF_GROUP_MORALE = 0x00001000; // Stops the overriding of HP% we'd need to test our morale. const int AI_FLAG_FLEEING_NO_OVERRIDING_HP_AMOUNT = 0x00002000; +// If this is ON, we will use a visual effect when we are fleeing battle +const int AI_FLAG_FLEEING_USE_VISUAL_EFFECT = 0x00004000; // Stored integer, base morale save (Default 10) const string BASE_MORALE_SAVE = "BASE_MORALE_SAVE";// S.INTEGER @@ -917,6 +878,8 @@ const int AI_FLAG_OTHER_COMBAT_GROUP_LEADER = 0x04000000; const string AI_BOSS_MONSTER_SHOUT_RANGE = "AI_BOSS_MONSTER_SHOUT_RANGE"; // counter - adds 1, when 4+, we may shout for people to attack our target. const string AI_LEADER_SHOUT_COUNT = "AI_LEADER_SHOUT_COUNT"; +// This will be a timer for disabling the boss shout *tempoarily* for 5 minutes +const string AI_TIMER_BOSS_SHOUT_COOLDOWN = "AI_TIMER_BOSS_SHOUT_COOLDOWN"; /******************************************************************************/ /******************************************************************************/ @@ -1024,11 +987,6 @@ const int AI_FLAG_OTHER_LAG_IGNORE_HEARTBEAT = 0x00004000; // Go for the nearest seen enemy always const int AI_FLAG_OTHER_LAG_TARGET_NEAREST_ENEMY = 0x00008000; -// SetAI level things. -const string LAG_AI_LEVEL_NO_PC_OR_ENEMY_50M = "LAG_AI_LEVEL_NO_PC_OR_ENEMY_50M"; -const string LAG_AI_LEVEL_YES_PC_OR_ENEMY_50M = "LAG_AI_LEVEL_YES_PC_OR_ENEMY_50M"; -const string LAG_AI_LEVEL_COMBAT = "LAG_AI_LEVEL_COMBAT"; - /******************************************************************************/ // Other settings /******************************************************************************/ @@ -1059,7 +1017,7 @@ const string AI_VALID_SPELLS = "AI_VALID_SPELLS"; /******************************************************************************/ // Max CR used OnSpawn or other GetCreatureTalentBest places const int MAXCR = 20; - +/* // Doesn't set what they are, only if they exsist. const int AI_VALID_TALENT_HARMFUL_AREAEFFECT_DISCRIMINANT = 0x00000001;// 1 - This is the constant number added to AI_VALID_SPELLS spawn settings. const int AI_VALID_TALENT_HARMFUL_RANGED = 0x00000002;// 2 @@ -1090,6 +1048,7 @@ const int AI_VALID_ANY_SPELL = 0x80000000 // Unused. This is mearly to not use talents if we don't have any! //const string AI_TALENT_HARMFUL_MELEE = "AI_TALENT_HM"; +*/ /******************************************************************************/ // Other file constants (default1, 2, 4-9, a, b, e /******************************************************************************/ @@ -1100,11 +1059,10 @@ const string AI_TIMER = "AI_TIMER_"; // Prefix const string AI_CONSTANT = "AI_CONSTANT_"; // Prefix for constansts const string AI_INTEGER = "AI_INTEGER_"; // Prefix for integers const string AI_OBJECT = "AI_OBJECT_"; // Prefix for objects +const string AI_LOCATION = "AI_LOCATION"; // Prefix for local locations // Array constants const string MAXINT_ = "MAXINT_"; -const string s1 = "1"; -const string s0 = "0";// Used mainly for spell triggers const string ARRAY_TEMP_ENEMIES = "ARRAY_TEMP_ENEMIES"; const string ARRAY_TEMP_ALLIES = "ARRAY_TEMP_ALLIES"; @@ -1152,6 +1110,10 @@ void DeleteSpawnInCondition(int nCondition, string sName); // * sName - The name its stored under // * oTarget - The target to look at (Ususally ourselves) int GetSpawnInCondition(int nCondition, string sName, object oTarget = OBJECT_SELF); +// Tests a spawn in condition. +// * nCondition - A condition to test for. +// * nTestAgains - An already got (via. local integer) integer to test nCondition against. +int CheckSpawnCondition(int nCondition, int nTestAgainst); // We can only ever set ONE special action. These are special things, such as // fleeing (that are a mixture of special things). @@ -1167,29 +1129,31 @@ int GetCurrentSetAction(); // Sets a local constant to sName, adding one to set right (so values of 0 become 1). // * Use GetLocalConstant to return original value set. // (To stop local's going awary, we set them with pre-fixes.) -void SetAIConstant(string sName, int iConstant); +void SetAIConstant(string sName, int nConstant); // Returns a constant set to sName (Takes one away). // * Therefore, returns -1 on error. // (To stop local's going awary, we set them with pre-fixes.) int GetAIConstant(string sName); // Deletes a constant set to sName. // (To stop local's going awary, we set them with pre-fixes.) -int DeleteAIConstant(string sName); +// * Note: Fixed, now "void" +void DeleteAIConstant(string sName); // Sets a local AI integers to ourselves. // (To stop local's going awary, we set them with pre-fixes.) -void SetAIInteger(string sName, int iValue); +void SetAIInteger(string sName, int nValue); // Gets a local AI integers from ourselves. // (To stop local's going awary, we set them with pre-fixes.) int GetAIInteger(string sName); // Gets a local AI integers from ourselves. // - We can define boundries for what it returns. // (To stop local's going awary, we set them with pre-fixes.) -// If X is < iBottom or > iTop, return iDefault. -int GetBoundriedAIInteger(string sName, int iDefault = 10, int iTop = 10, int iBottom = 1); +// If X is < nBottom or > nTop, return iDefault. +int GetBoundriedAIInteger(string sName, int nDefault = 10, int nTop = 10, int nBottom = 1); // Deletes a local AI integers from ourselves. // (To stop local's going awary, we set them with pre-fixes.) -int DeleteAIInteger(string sName); +// * Note: Fixed, now "void" +void DeleteAIInteger(string sName); // Sets a local AI object to ourselves. // (To stop local's going awary, we set them with pre-fixes.) @@ -1199,8 +1163,19 @@ void SetAIObject(string sName, object oObject); object GetAIObject(string sName); // Deletes a local AI object from ourselves. // (To stop local's going awary, we set them with pre-fixes.) +// * Note: Fixed, now "void" void DeleteAIObject(string sName); +// Sets a local AI location to ourselves. +// (To stop local's going awary, we set them with pre-fixes.) +void SetAILocation(string sName, location lLocation); +// Gets a local AI location from ourselves. +// (To stop local's going awary, we set them with pre-fixes.) +location GetAILocation(string sName); +// Deletes a local AI location from ourselves. +// (To stop local's going awary, we set them with pre-fixes.) +void DeleteAILocation(string sName); + // Sets up a timer. // * sName - the variable name (Adds a pre-fix). // * fDuration - the time until it is removed. @@ -1212,13 +1187,13 @@ int GetLocalTimer(string sName); // Sets a local INTEGER array on ourselves. // * sArray - the array name. // * oObjectArray - The object we will set. -// * iValue - The value to check. It is done HIGHEST to LOWEST. -void SetArrayIntegerValue(string sArray, object oObjectArray, int iValue); +// * nValue - The value to check. It is done HIGHEST to LOWEST. +void SetArrayIntegerValue(string sArray, object oObjectArray, int nValue); // This will move all integer values from a point back a position // * sArray - the array name. -// * iNumberStart - The value to start at. -// * iMax - The old-highest (or highest in the order) of the array (EG the 10th of 10) -void MoveArrayIntegerBackOne(string sArray, int iNumberStart, int iMax); +// * nNumberStart - The value to start at. +// * nMax - The old-highest (or highest in the order) of the array (EG the 10th of 10) +void MoveArrayIntegerBackOne(string sArray, int nNumberStart, int nMax); // Sets a local FLOAT array on ourselves. // * sArray - the array name. @@ -1227,9 +1202,9 @@ void MoveArrayIntegerBackOne(string sArray, int iNumberStart, int iMax); void SetArrayFloatValue(string sArray, object oObjectArray, float fValue); // This will move all float values from a point back a position // * sArray - the array name. -// * iNumberStart - The value to start at. -// * iMax - The old-highest (or highest in the order) of the array (EG the 10th of 10) -void MoveArrayFloatBackOne(string sArray, int iNumberStart, int iMax); +// * nNumberStart - The value to start at. +// * nMax - The old-highest (or highest in the order) of the array (EG the 10th of 10) +void MoveArrayFloatBackOne(string sArray, int nNumberStart, int nMax); // Deletes all the things in an array...set to sArray void DeleteArray(string sArray); @@ -1241,24 +1216,29 @@ void SetIgnore(object oTarget); // * The AI ignores, and shouldn't intentioally target, the creature. int GetIgnore(object oTarget); // This gets if the oTarget can be targeted as an enemy. -// * Returns if a DM, is faction Equal, is dead or the ignore variable. +// * Returns TRUE if a DM, is faction Equal, is dead, invalid, or the ignore variable. int GetIgnoreNoFriend(object oTarget); // Fires a User Defined Event. -// * iSpawnValue - The spawn value (like NW_FLAG_PERCIEVE_PRE_EVENT) -// * iNumber - The number to fire (like EVENT_PERCIEVE_PRE_EVENT) +// * nSpawnValue - The spawn value (like NW_FLAG_PERCIEVE_PRE_EVENT) +// * nNumber - The number to fire (like EVENT_PERCIEVE_PRE_EVENT) // Returns TRUE if the event fires. -int FireUserEvent(int iSpawnValue, int iNumber); +int FireUserEvent(int nSpawnValue, int nNumber); +// Fire the pre-event, and return TRUE if it interrupts the rest of the +// event. It uses FireUserEvent() and ExitFromUDE(). +int FirePreUserEvent(int nSpawnValue, int nNumber); // This sets to exit the script. Use in the defaultd (On User Defined) file. // For example: We want to not attack PC's with the item "ROCK" (Tag). We // therefore use the event EVENT_PERCIEVE_PRE_EVENT to exit if they have that item // because we go friendly to them. -// * iNumber - The user defined number to exit from. -void SetToExitFromUDE(int iNumber); +// * nNumber - The user defined number to exit from. +void SetToExitFromUDE(int nNumber); // This is used for Pre-events. If we exit from EVENT_PERCIEVE_PRE_EVENT, and // use SetToExitFromUDE, this returns TRUE (ONCE!) -// * iNumber - The user defined number to exit from. -int ExitFromUDE(int iNumber); +// * nNumber - The user defined number to exit from. +int ExitFromUDE(int nNumber); +// Get the user defined event number - includes Pre-events. +int AI_GetUDENumber(); // We check if we are attacking anything // * Checks Attempted* Targets, Get the AttackTarget of us. @@ -1275,15 +1255,8 @@ int GetIsBusyWithAction(); // * IE it adds GetIsBusyWithAction with GetIsFighting to give 0, 1 or 2. // * Checks if we are fleeing too int CannotPerformCombatRound(); -// This will SpeakString a value from sName's array. i1000 uses a d1000 for % chance -void SpeakArrayString(string sName, int i1000 = FALSE); -// This is used in combat (at the end thereof) and when something shouts, and is a placeable. -// * oTarget - The target which may have shouted, or similar. Moves to and closes normally. -// If no oTarget, it still searches -void Search(object oTarget = OBJECT_INVALID); -// Used in Search(). This apply Trueseeing, See invisibility, or Invisiblity purge -// if we have neither of the 3 on us. -void SearchSpells(); +// This will SpeakString a value from sName's array. b1000 uses a d1000 for % chance +void SpeakArrayString(string sName, int b1000 = FALSE); // Returns our custom AI file (if any) // - Blank string if not set @@ -1294,6 +1267,9 @@ string GetCustomAIFileName(); // - Can sort actions against a imputted target (EG: On Percieved enemy) by // "GetLocalObject(OBJECT_SELF, AI_TEMP_SET_TARGET)" void SetCustomAIFileName(string sAIFileName); +// Sets our User Defined Event file. +// * Should be called if we are using pre-events. By default, it is called. +void SetCustomUDEFileName(string sUDEFileName); // This is still used - we just set a local object and execute script. // Set the script to use by COMBAT_FILE constant @@ -1303,11 +1279,47 @@ void DetermineCombatRound(object oTarget = OBJECT_INVALID); // - Returns FALSE if none of them are performed // Use this to make sure that an ActionMoveTo or DCR doesn't fire if we are fleeing. // - This does not perform any actions. +// * Doesn't include a check for Search. This can be interrupted. +// * Note: 1.4: If we are not doing something that combat cannot interrupt (EG: +// if we are, say, moving to combat...but not if we were fleeing) we will delete +// what special action we were doing. int GetIsPerformingSpecialAction(); // This will, if we are set that we can, shout the string. void AISpeakString(string sString); +// This will apply the fear visual for fleeing, if the variable +// AI_FLAG_FLEEING_USE_VISUAL_EFFECT is on. +void ApplyFleeingVisual(); +// This will remove the fear visual for fleeing. +void RemoveFleeingVisual(); + +// ETHEREALNESS: +// Can be SEEN through with TRUESEEING. If we see a ETHEREAL person, we cannot +// DIRECTLY attack them. +// Soooo...we will never target them as spell targets (AOE ones are fine!) nor +// as attack targets, but they are counted and recognised - and can be used +// as AOE targets. +// Best way is to leave most checks as normal, but make sure DetermineCombatRound() +// works correctly - it recognises (and will attempt to dispel too!), but will +// never target those. + +// Add check here for GetIsEthereal() + +// 1.4 addition: See J_INC_CONSTANT, under "ETHEREALNESS:", it explains how +// etherealness and trueseing now work with later patches. +// * Special use in DetermineCombatRound() makes the AI never target ethereal people, +// but take account of them for cirtain things (IE: They exsist). +// NOTE: If oTarget is OBJECT_SELF, we return FALSE. +int GetIsEthereal(object oTarget); + +// This will be for array speakstrings (IE: Taunts), and will make sure +// we are commandable, not dead, not deaf, and not silenced. +int CanSpeak(); +// Checks the target for a specific EFFECT_TYPE constant value +// Returns TRUE or FALSE. Used On Damaged for polymorph checking. +int GetHasEffect(int nEffectType, object oTarget = OBJECT_SELF); + /*:://///////////////////////////////////////////// //:: Name: AI ON, or OFF. //:://///////////////////////////////////////////// @@ -1354,6 +1366,13 @@ void DeleteSpawnInCondition(int nCondition, string sName) { SetLocalInt(OBJECT_SELF, sName, (GetLocalInt(OBJECT_SELF, sName) & ~nCondition)); } +// Tests a spawn in condition. +// * nCondition - A condition to test for. +// * nTestAgains - An already got (via. local integer) integer to test nCondition against. +int CheckSpawnCondition(int nCondition, int nTestAgainst) +{ + return (nTestAgainst & nCondition); +} /*:://///////////////////////////////////////////// //:: Name: SetCurrentAction, ResetCurrentAction, GetCurrentSetAction. //:://///////////////////////////////////////////// @@ -1396,51 +1415,52 @@ int GetLocalTimer(string sName) // Sets a local INTEGER array on ourselves. // * sArray - the array name. // * oObjectArray - The object we will set. -// * iValue - The value to check. It is done HIGHEST to LOWEST. -void SetArrayIntegerValue(string sArray, object oObjectArray, int iValue) +// * nValue - The value to check. It is done HIGHEST to LOWEST. +void SetArrayIntegerValue(string sArray, object oObjectArray, int nValue) { - int iValueAtPosition, iMax, i; + int nValueAtPosition, nMax, nCnt; // Get the current size - iMax = GetLocalInt(OBJECT_SELF, MAXINT_ + sArray); + nMax = GetLocalInt(OBJECT_SELF, MAXINT_ + sArray); string sArrayStore = sArray; // Special - IE no valid array values at the start. - if(iMax < i1) + if(nMax < 1) { - sArrayStore += s1; - SetLocalInt(OBJECT_SELF, sArray + s1, iValue); - SetLocalObject(OBJECT_SELF, sArray + s1, oObjectArray); - SetLocalInt(OBJECT_SELF, MAXINT_ + sArray, i1); // always the first. + sArrayStore += "1"; + SetLocalInt(OBJECT_SELF, sArray + "1", nValue); + SetLocalObject(OBJECT_SELF, sArray + "1", oObjectArray); + SetLocalInt(OBJECT_SELF, MAXINT_ + sArray, 1); // always the first. } // Else, we will set it in the array. else { // Loop through the items stored already. - for(i = i1; i <= iMax; i++) + for(nCnt = 1; nCnt <= nMax; nCnt++) { // Get the value of the item. - iValueAtPosition = GetLocalInt(OBJECT_SELF, sArray + IntToString(i)); + nValueAtPosition = GetLocalInt(OBJECT_SELF, sArray + IntToString(nCnt)); // If imput is greater than stored...move all of them back one. - if(iValue > iValueAtPosition) + if(nValue > nValueAtPosition) { // Move all values from this point onwards back one. - MoveArrayIntegerBackOne(sArray, i, iMax); + MoveArrayIntegerBackOne(sArray, nCnt, nMax); // Set the local object and the local integer. - sArrayStore += IntToString(i); - SetLocalInt(OBJECT_SELF, sArrayStore, iValue); + sArrayStore += IntToString(nCnt); + SetLocalInt(OBJECT_SELF, sArrayStore, nValue); SetLocalObject(OBJECT_SELF, sArrayStore, oObjectArray); - // Set max values we have (IE add one!) 1.3beta - changed from iMax++ - SetLocalInt(OBJECT_SELF, MAXINT_ + sArray, ++iMax); + // Set max values we have (IE add one!) + // 1.3 beta - changed from nMax++ + SetLocalInt(OBJECT_SELF, MAXINT_ + sArray, ++nMax); break; } // If at end, just add at end. - else if(i == iMax) + else if(nCnt == nMax) { // Set the local object and the local integer. - sArrayStore += IntToString(i + i1); - SetLocalInt(OBJECT_SELF, sArrayStore, iValue); + sArrayStore += IntToString(nCnt + 1); + SetLocalInt(OBJECT_SELF, sArrayStore, nValue); SetLocalObject(OBJECT_SELF, sArrayStore, oObjectArray); // Set max values we have (IE add one!) - SetLocalInt(OBJECT_SELF, MAXINT_ + sArray, ++iMax); + SetLocalInt(OBJECT_SELF, MAXINT_ + sArray, ++nMax); break; } } @@ -1448,29 +1468,29 @@ void SetArrayIntegerValue(string sArray, object oObjectArray, int iValue) } // This will move all integer values from a point back a position // * sArray - the array name. -// * iNumberStart - The value to start at. -// * iMax - The old-highest (or highest in the order) of the array (EG the 10th of 10) -void MoveArrayIntegerBackOne(string sArray, int iNumberStart, int iMax) +// * nNumberStart - The value to start at. +// * nMax - The old-highest (or highest in the order) of the array (EG the 10th of 10) +void MoveArrayIntegerBackOne(string sArray, int nNumberStart, int nMax) { // Objects, the old name for that value and the new one. object oObjectAtNumber; string sCurrentName, sNewName; - int iArrayAtNumberValue, i; + int nArrayAtNumberValue, nCnt; // Move it from the back, back one, then then next... // Start at value 5 (Max) and move it to 6, then move to 4, move it - // to 5 and so on down to iNumber Start, say, 3, so we get to 3, move it to 4, + // to 5 and so on down to nNumber Start, say, 3, so we get to 3, move it to 4, // and space 3 is free. - for(i = iMax; i >= iNumberStart; i--) + for(nCnt = nMax; nCnt >= nNumberStart; nCnt--) { // Sets the name up right. - sCurrentName = sArray + IntToString(i); // The current name to get values. - sNewName = sArray + IntToString(i + i1); // Move back = Add one + sCurrentName = sArray + IntToString(nCnt); // The current name to get values. + sNewName = sArray + IntToString(nCnt + 1); // Move back = Add one // Set the things up in the right parts. oObjectAtNumber = GetLocalObject(OBJECT_SELF, sCurrentName); - iArrayAtNumberValue = GetLocalInt(OBJECT_SELF, sCurrentName); - // To the NEW name - we add one to the i value. + nArrayAtNumberValue = GetLocalInt(OBJECT_SELF, sCurrentName); + // To the NEW name - we add one to the nCnt value. SetLocalObject(OBJECT_SELF, sNewName, oObjectAtNumber); - SetLocalInt(OBJECT_SELF, sNewName, iArrayAtNumberValue); + SetLocalInt(OBJECT_SELF, sNewName, nArrayAtNumberValue); } } // Sets a local FLOAT array on ourselves. @@ -1479,48 +1499,48 @@ void MoveArrayIntegerBackOne(string sArray, int iNumberStart, int iMax) // * fValue - The value to check. It is done LOWEST (nearest) to HIGHEST (fathest). void SetArrayFloatValue(string sArray, object oObjectArray, float fValue) { - int iMax, i; - iMax = GetLocalInt(OBJECT_SELF, MAXINT_ + sArray); + int nMax, nCnt; + nMax = GetLocalInt(OBJECT_SELF, MAXINT_ + sArray); string sArrayStore = sArray; float fValueAtPosition; // Special - IE no valid array values at the start. - if(iMax <= FALSE) + if(nMax <= FALSE) { - sArrayStore = sArray + s1; + sArrayStore = sArray + "1"; SetLocalFloat(OBJECT_SELF, sArrayStore, fValue); SetLocalObject(OBJECT_SELF, sArrayStore, oObjectArray); - SetLocalInt(OBJECT_SELF, MAXINT_ + sArray, i1); // always the first. + SetLocalInt(OBJECT_SELF, MAXINT_ + sArray, 1); // always the first. } // Else, we will set it in the array. else { // Loop through the items stored already. - for(i = i1; i <= iMax; i++) + for(nCnt = 1; nCnt <= nMax; nCnt++) { // Get the value of the item. - fValueAtPosition = GetLocalFloat(OBJECT_SELF, sArray + IntToString(i)); + fValueAtPosition = GetLocalFloat(OBJECT_SELF, sArray + IntToString(nCnt)); // If imput is LESS (nearer) than stored...move all of them back one. if(fValue < fValueAtPosition) { // Move all values from this point onwards back one. - MoveArrayFloatBackOne(sArray, i, iMax); + MoveArrayFloatBackOne(sArray, nCnt, nMax); // Set the local object and the local integer. - sArrayStore = sArray + IntToString(i); + sArrayStore = sArray + IntToString(nCnt); SetLocalFloat(OBJECT_SELF, sArrayStore, fValue); SetLocalObject(OBJECT_SELF, sArrayStore, oObjectArray); - // Set max values we have (IE add one!) 1.3 beta - it was iMax++ - SetLocalInt(OBJECT_SELF, MAXINT_ + sArray, ++iMax); + // Set max values we have (IE add one!) 1.3 beta - it was nMax++ + SetLocalInt(OBJECT_SELF, MAXINT_ + sArray, ++nMax); break; } - // Else, if it is the end value (iMax) we set it at the end - else if(i == iMax) + // Else, if it is the end value (nMax) we set it at the end + else if(nCnt == nMax) { // Set the local object and the local integer. - sArrayStore = sArray + IntToString(i + i1); + sArrayStore = sArray + IntToString(nCnt + 1); SetLocalFloat(OBJECT_SELF, sArrayStore, fValue); SetLocalObject(OBJECT_SELF, sArrayStore, oObjectArray); // Set max values we have (IE add one!) - SetLocalInt(OBJECT_SELF, MAXINT_ + sArray, ++iMax); + SetLocalInt(OBJECT_SELF, MAXINT_ + sArray, ++nMax); break; } } @@ -1528,21 +1548,21 @@ void SetArrayFloatValue(string sArray, object oObjectArray, float fValue) } // This will move all float values from a point back a position // * sArray - the array name. -// * iNumberStart - The value to start at. -// * iMax - The old-highest (or highest in the order) of the array (EG the 10th of 10) -void MoveArrayFloatBackOne(string sArray, int iNumberStart, int iMax) +// * nNumberStart - The value to start at. +// * nMax - The old-highest (or highest in the order) of the array (EG the 10th of 10) +void MoveArrayFloatBackOne(string sArray, int nNumberStart, int nMax) { // Objects, the old name for that value and the new one. object oObjectAtNumber; string sCurrentName, sNewName; - int i; + int nCnt; float fArrayAtNumberValue; // Move it from the back, back one, then then next... - for(i = iMax; i >= iNumberStart; i--) + for(nCnt = nMax; nCnt >= nNumberStart; nCnt--) { // Sets the name up right. - sCurrentName = sArray + IntToString(i); // The current name to get values. - sNewName = sArray + IntToString(i + i1); // Move back = Add one + sCurrentName = sArray + IntToString(nCnt); // The current name to get values. + sNewName = sArray + IntToString(nCnt + 1); // Move back = Add one // Set the things up in the right parts. oObjectAtNumber = GetLocalObject(OBJECT_SELF, sCurrentName); fArrayAtNumberValue = GetLocalFloat(OBJECT_SELF, sCurrentName); @@ -1554,15 +1574,15 @@ void MoveArrayFloatBackOne(string sArray, int iNumberStart, int iMax) // Deletes all the things in an array...set to sArray void DeleteArray(string sArray) { - int i, iMax; + int nCnt, nMax; string sNewName; // Max values, if any - iMax = GetLocalInt(OBJECT_SELF, MAXINT_ + sArray); - if(iMax) + nMax = GetLocalInt(OBJECT_SELF, MAXINT_ + sArray); + if(nMax) { - for(i = i1; i <= iMax; i++) + for(nCnt = 1; nCnt <= nMax; nCnt++) { - sNewName = sArray + IntToString(i); + sNewName = sArray + IntToString(nCnt); DeleteLocalObject(OBJECT_SELF, sNewName);// Object DeleteLocalInt(OBJECT_SELF, sNewName);// Value DeleteLocalFloat(OBJECT_SELF, sNewName);// Value @@ -1587,10 +1607,12 @@ int GetIgnore(object oTarget) { return GetLocalInt(oTarget, AI_IGNORE_TOGGLE); } +// This gets if the oTarget can be targeted as an enemy. +// * Returns if a DM, is faction Equal, is dead, invalid, or the ignore variable. int GetIgnoreNoFriend(object oTarget) { - if(GetLocalInt(oTarget, AI_IGNORE_TOGGLE) || GetFactionEqual(oTarget) || - GetIsDM(oTarget) || GetIsDead(oTarget)) + if(!GetIsObjectValid(oTarget) || GetLocalInt(oTarget, AI_IGNORE_TOGGLE) || + GetFactionEqual(oTarget) || GetIsDM(oTarget) || GetIsDead(oTarget)) { return TRUE; } @@ -1601,13 +1623,13 @@ int GetIgnoreNoFriend(object oTarget) //:://///////////////////////////////////////////// Sets a constant (from nwscript.nss) //::////////////////////////////////////////////*/ -void SetAIConstant(string sName, int iConstant) +void SetAIConstant(string sName, int nConstant) { - SetLocalInt(OBJECT_SELF, AI_CONSTANT + sName, iConstant + i1); + SetLocalInt(OBJECT_SELF, AI_CONSTANT + sName, nConstant + 1); } int GetAIConstant(string sName) { - return GetLocalInt(OBJECT_SELF, AI_CONSTANT + sName) - i1; + return GetLocalInt(OBJECT_SELF, AI_CONSTANT + sName) - 1; } void DeleteAIConstant(string sName) { @@ -1618,23 +1640,27 @@ void DeleteAIConstant(string sName) //:://///////////////////////////////////////////// To stop local's going awary, we set them with pre-fixes. //::////////////////////////////////////////////*/ -void SetAIInteger(string sName, int iValue) +void SetAIInteger(string sName, int nValue) { - SetLocalInt(OBJECT_SELF, AI_INTEGER + sName, iValue); + SetLocalInt(OBJECT_SELF, AI_INTEGER + sName, nValue); } int GetAIInteger(string sName) { return GetLocalInt(OBJECT_SELF, AI_INTEGER + sName); } -int GetBoundriedAIInteger(string sName, int iDefault, int iTop, int iBottom) +// Gets a local AI integers from ourselves. +// - We can define boundries for what it returns. +// (To stop local's going awary, we set them with pre-fixes.) +// If X is < nBottom or > nTop, return iDefault. +int GetBoundriedAIInteger(string sName, int nDefault = 10, int nTop = 10, int nBottom = 1) { - int iReturn = GetAIInteger(sName); + int nReturn = GetAIInteger(sName); // Boundries - if(iReturn < iBottom || iReturn > iTop) + if(nReturn < nBottom || nReturn > nTop) { - iReturn = iDefault; + nReturn = nDefault; } - return iReturn; + return nReturn; } void DeleteAIInteger(string sName) { @@ -1657,26 +1683,66 @@ void DeleteAIObject(string sName) { DeleteLocalObject(OBJECT_SELF, AI_OBJECT + sName); } - +/*:://///////////////////////////////////////////// +//:: Name: SetAILocation, GetAILocation, DeleteAILocation +//:://///////////////////////////////////////////// + To stop local's going awary, we set them with pre-fixes. +//::////////////////////////////////////////////*/ +void SetAILocation(string sName, location lLocation) +{ + SetLocalLocation(OBJECT_SELF, AI_LOCATION + sName, lLocation); +} +location GetAILocation(string sName) +{ + return GetLocalLocation(OBJECT_SELF, AI_LOCATION + sName); +} +void DeleteAILocation(string sName) +{ + DeleteLocalLocation(OBJECT_SELF, AI_LOCATION + sName); +} /*:://///////////////////////////////////////////// //:: Name: FireUserEvent //:://///////////////////////////////////////////// // Fires a User Defined Event. -// * iSpawnValue - The spawn value (like NW_FLAG_PERCIEVE_PRE_EVENT) -// * iNumber - The number to fire (like EVENT_PERCIEVE_PRE_EVENT) +// * nSpawnValue - The spawn value (like NW_FLAG_PERCIEVE_PRE_EVENT) +// * nNumber - The number to fire (like EVENT_PERCIEVE_PRE_EVENT) // Returns TRUE if the event fires. //::////////////////////////////////////////////*/ -int FireUserEvent(int iSpawnValue, int iNumber) +int FireUserEvent(int nSpawnValue, int nNumber) { // Check spawn in condition - if(GetSpawnInCondition(iSpawnValue, AI_UDE_MASTER)) + if(GetSpawnInCondition(nSpawnValue, AI_UDE_MASTER)) { // Signal event (and return TRUE) - SignalEvent(OBJECT_SELF, EventUserDefined(iNumber)); + SignalEvent(OBJECT_SELF, EventUserDefined(nNumber)); return TRUE; } return FALSE; } +// Fire the pre-event, and return TRUE if it interrupts the rest of the +// event. It uses FireUserEvent() and ExitFromUDE(). +int FirePreUserEvent(int nSpawnValue, int nNumber) +{ + // If we fire the event... + if(GetSpawnInCondition(nSpawnValue, AI_UDE_MASTER)) + { + // "Signal" the event + SetAIInteger(AI_PRE_EVENT_NUMBER, TRUE); + + // Execute the script + string sScript = GetLocalString(OBJECT_SELF, AI_UDE_SCRIPT_NAME); + + // Default the file to FILE_DEFAULT_UDE + if(sScript == "") sScript = FILE_DEFAULT_UDE; + + // Execute it + ExecuteScript(sScript, OBJECT_SELF); + + // Return TRUE or FALSE depending on ExitFromUDE(); + return ExitFromUDE(nNumber); + } + return FALSE; +} /*:://///////////////////////////////////////////// //:: Name: SetToExitFromUDE //:://///////////////////////////////////////////// @@ -1684,23 +1750,23 @@ int FireUserEvent(int iSpawnValue, int iNumber) // For example: We want to not attack PC's with the item "ROCK" (Tag). We // therefore use the event EVENT_PERCIEVE_PRE_EVENT to exit if they have that item // because we go friendly to them. -// * iNumber - The user defined number to exit from. +// * nNumber - The user defined number to exit from. //::////////////////////////////////////////////*/ -void SetToExitFromUDE(int iNumber) +void SetToExitFromUDE(int nNumber) { - SetLocalInt(OBJECT_SELF, EXIT_UDE_PREFIX_ + IntToString(iNumber), TRUE); + SetLocalInt(OBJECT_SELF, EXIT_UDE_PREFIX_ + IntToString(nNumber), TRUE); } /*:://///////////////////////////////////////////// //:: Name: ExitFromUDE //:://///////////////////////////////////////////// // This is used for Pre-events. If we exit from EVENT_PERCIEVE_PRE_EVENT, and // use SetToExitFromUDE, this returns TRUE (ONCE!) -// * iNumber - The user defined number to exit from. +// * nNumber - The user defined number to exit from. //::////////////////////////////////////////////*/ -int ExitFromUDE(int iNumber) +int ExitFromUDE(int nNumber) { // Set up string to delete/check - string sCheck = EXIT_UDE_PREFIX_ + IntToString(iNumber); + string sCheck = EXIT_UDE_PREFIX_ + IntToString(nNumber); // Check local value if(GetLocalInt(OBJECT_SELF, sCheck)) { @@ -1710,6 +1776,21 @@ int ExitFromUDE(int iNumber) } return FALSE; } +// Get the user defined event number - includes Pre-events. +int AI_GetUDENumber() +{ + // Check for pre-event + int nPre = GetAIInteger(AI_PRE_EVENT_NUMBER); + + if(nPre > 0) + { + // return nPre, and we delete it so it doesn't interfere later. + DeleteAIInteger(AI_PRE_EVENT_NUMBER); + return nPre; + } + // By default, return the normal event number used + return GetUserDefinedEventNumber(); +} /*:://///////////////////////////////////////////// //:: Name: GetIsFighting, GetIsBusyWithAction, CanPerformCombatRound @@ -1740,75 +1821,83 @@ int GetIsFighting() int GetIsBusyWithAction() { // Set up actions. - int iAction = GetCurrentAction(); - // Common dropout ones to speed it up. - if(iAction == ACTION_INVALID || - iAction == ACTION_WAIT || - iAction == ACTION_FOLLOW || - iAction == ACTION_MOVETOPOINT || - iAction == ACTION_DIALOGOBJECT || - iAction == ACTION_REST || - iAction == ACTION_USEOBJECT || - iAction == ACTION_COUNTERSPELL || - iAction == ACTION_DISABLETRAP || - iAction == ACTION_EXAMINETRAP || - iAction == ACTION_FLAGTRAP || - iAction == ACTION_RECOVERTRAP) + int nAction = GetCurrentAction(); + switch(nAction) { - return FALSE; - } - else - if(iAction == ACTION_ATTACKOBJECT)// Very common. Could be a door as well as a creature! - { - // This is a special thing...if we are attacking a non-creature, we - // return FALSE anyway, to attack the creature. - - // Therefore, if we are attacking a creature though, we return TRUE as - // we do not want to change objects. :-P - int iAttackObjectType = GetObjectType(GetAttackTarget()); - // Note: as this returns -1 on error, its easier to just use an if/else - // checking the integers, with a -1 dropout. - if(iAttackObjectType != -1) + // Very common. Could be a door as well as a creature! + case ACTION_ATTACKOBJECT: { - // We never stop attacking one creature - if(iAttackObjectType == OBJECT_TYPE_CREATURE) + // This is a special thing...if we are attacking a non-creature, we + // return FALSE anyway, to attack the creature. + + // Therefore, if we are attacking a creature though, we return TRUE as + // we do not want to change objects. :-P + int nAttackObjectType = GetObjectType(GetAttackTarget()); + // Note: as this returns -1 on error, its easier to just use an if/else + // checking the integers, with a -1 dropout. + if(nAttackObjectType != -1) { - return TRUE; + // We never stop attacking one creature + if(nAttackObjectType == OBJECT_TYPE_CREATURE) + { + return TRUE; + } + // we may stop attacking a door if we are not fleeing though + // But if we are attacking a door and fleeing, don't react. + else if(nAttackObjectType == OBJECT_TYPE_DOOR && + !GetIsObjectValid(GetAIObject(AI_FLEE_TO))) + { + return TRUE; + } } - // we may stop attacking a door if we are not fleeing though - // But if we are attacking a door and fleeing, don't react. - else if(iAttackObjectType == OBJECT_TYPE_DOOR && - !GetIsObjectValid(GetAIObject(AI_FLEE_TO))) + } + break; + // We are opening a door... (or unlocking one) + case ACTION_OPENDOOR: // Opening a door! + case ACTION_OPENLOCK: // The AI only unlocks doors + { + // It may be that we want to always unlock doors and open them as we + // are fleeing. + if(!GetIsObjectValid(GetAIObject(AI_FLEE_TO))) { return TRUE; } } - } - // We are opening a door... (or unlocking one) - else - if(iAction == ACTION_OPENDOOR || // Opening a door! - iAction == ACTION_OPENLOCK) // The AI only unlocks doors - { - // It may be that we want to always unlock doors and open them as we - // are fleeing. - if(!GetIsObjectValid(GetAIObject(AI_FLEE_TO))) + break; + // If we are using a cirtain skill or similar, don't try and attack. + // We probably are already! + case ACTION_ANIMALEMPATHY: // An "attack" skill we use + case ACTION_CASTSPELL: // Casting a spell shouldn't be interrupted. + case ACTION_HEAL: // Heal skill. A very important way to heal and not to override + case ACTION_ITEMCASTSPELL: // Scrolls, potions ETC. + case ACTION_LOCK: // Won't be used. Added for completeness. + case ACTION_PICKPOCKET: // Sometimes used in combat. Nifty! + case ACTION_PICKUPITEM: // We may be picking up lost weapons (disarmed ones) + case ACTION_SETTRAP: // Can't seem to work it :-/ Well, here for completeness + case ACTION_TAUNT: // Taunt shouldn't be interrupted. { return TRUE; } - } - // If we are using a cirtain skill or similar, don't try and attack. - else - if(iAction == ACTION_ANIMALEMPATHY || // An "attack" skill we use - iAction == ACTION_CASTSPELL || // Casting a spell shouldn't be interrupted. - iAction == ACTION_HEAL || // Heal skill. A very important way to heal and not to override - iAction == ACTION_ITEMCASTSPELL || // Scrolls, potions ETC. - iAction == ACTION_LOCK || // Won't be used. Added for completeness. - iAction == ACTION_PICKPOCKET || // Sometimes used in combat. Nifty! - iAction == ACTION_PICKUPITEM || // We may be picking up lost weapons (disarmed ones) - iAction == ACTION_SETTRAP || // Can't seem to work it :-/ Well, here for completeness - iAction == ACTION_TAUNT) // Taunt shouldn't be interrupted. - { - return TRUE; + break; + // These common ones which we will interrupt are covered by "default:" + // and are here for reference + default: + { + /* nAction == ACTION_INVALID || + nAction == ACTION_WAIT || + nAction == ACTION_FOLLOW || + nAction == ACTION_MOVETOPOINT || + nAction == ACTION_DIALOGOBJECT || + nAction == ACTION_REST || + nAction == ACTION_USEOBJECT || + nAction == ACTION_COUNTERSPELL || + nAction == ACTION_DISABLETRAP || + nAction == ACTION_EXAMINETRAP || + nAction == ACTION_FLAGTRAP || + nAction == ACTION_RECOVERTRAP */ + return FALSE; + } + break; } return FALSE; } @@ -1822,12 +1911,12 @@ int CannotPerformCombatRound() return GetIsPerformingSpecialAction() + GetIsBusyWithAction() + GetIsFighting(); } -// This will SpeakString a value from sName's array. i1000 uses a d1000 for % chance -void SpeakArrayString(string sName, int i1000 = FALSE) +// This will SpeakString a value from sName's array. b1000 uses a d1000 for % chance +void SpeakArrayString(string sName, int b1000 = FALSE) { // Need a valid array (arrays of 1 are just that - 1 value to choose from.) - int iSize = GetLocalInt(OBJECT_SELF, ARRAY_SIZE + sName); - if(iSize > i0) + int nSize = GetLocalInt(OBJECT_SELF, ARRAY_SIZE + sName); + if(nSize > 0) { // Make sure we are not dead (unless we should be) if(sName != AI_TALK_ON_DEATH) @@ -1835,35 +1924,35 @@ void SpeakArrayString(string sName, int i1000 = FALSE) if(GetIsDead(OBJECT_SELF)) return; } // Do we carry on? - int iCarryOn = FALSE; - if(i1000 == TRUE) + int bCarryOn = FALSE; + if(b1000 == TRUE) { // Do the % check now. Values 1-1000 randomised. - if((Random(1000) + i1) <= GetLocalInt(OBJECT_SELF, ARRAY_PERCENT + sName)) iCarryOn = TRUE; + if((Random(1000) + 1) <= GetLocalInt(OBJECT_SELF, ARRAY_PERCENT + sName)) bCarryOn = TRUE; } else { // 100 normal one. - if(d100() <= GetLocalInt(OBJECT_SELF, ARRAY_PERCENT + sName)) iCarryOn = TRUE; + if(d100() <= GetLocalInt(OBJECT_SELF, ARRAY_PERCENT + sName)) bCarryOn = TRUE; } - if(iCarryOn) + if(bCarryOn) { - int iRandomOne = i1; - if(iSize > i1) + int nRandomOne = 1; + if(nSize > 1) { // Randomise - we add one, so instead of 0-2 (for 3 values) it goes 1-3. - iRandomOne = Random(iSize) + i1; + nRandomOne = Random(nSize) + 1; } // Now, to choose one... - string sSpeak = GetLocalString(OBJECT_SELF, sName + IntToString(iRandomOne)); + string sSpeak = GetLocalString(OBJECT_SELF, sName + IntToString(nRandomOne)); // And speak! // - Added random delay for 0.1 to 1.2 seconds to add some variety, // if it is used for n1000 if(sSpeak != "") { - // Code sorta taken from NW_I0_Spells, the random stuff. + // Code sorta taken from NW_i0_Spells, the random stuff. // FloatToInt(15);/FloatToInt(fRandom * 10.0); - if(i1000 == TRUE) + if(b1000 == TRUE) { float fDelay = IntToFloat(Random(15) + 1) / 10.0; DelayCommand(fDelay, SpeakString(sSpeak)); @@ -1877,148 +1966,6 @@ void SpeakArrayString(string sName, int i1000 = FALSE) } } } -// Used in Search(). This apply Trueseeing, See invisibility, or Invisiblity purge -// if we have neither of the 3 on us. -void SearchSpells() -{ - effect eCheck = GetFirstEffect(OBJECT_SELF); - int iEffectType, iBreak; - while(GetIsEffectValid(eCheck) && iBreak == FALSE) - { - iEffectType = GetEffectType(eCheck); - if(iEffectType == EFFECT_TYPE_TRUESEEING || - iEffectType == EFFECT_TYPE_SEEINVISIBLE) - { - iBreak = TRUE; - } - eCheck = GetNextEffect(OBJECT_SELF); - } - // We have effects, stop. - if(iBreak == TRUE && !GetHasSpellEffect(SPELL_INVISIBILITY_PURGE)) - { - return; - } - // Else we apply the best spell we have. - if(GetHasSpell(SPELL_TRUE_SEEING)) - { - ActionCastSpellAtObject(SPELL_TRUE_SEEING, OBJECT_SELF); - return; - } - if(GetHasSpell(SPELL_SEE_INVISIBILITY)) - { - ActionCastSpellAtObject(SPELL_SEE_INVISIBILITY, OBJECT_SELF); - return; - } - if(GetHasSpell(SPELL_INVISIBILITY_PURGE)) - { - ActionCastSpellAtObject(SPELL_INVISIBILITY_PURGE, OBJECT_SELF); - return; - } -} -// This is used in combat (at the end thereof) and when something shouts, and is a placeable. -// * oTarget - The target which may have shouted, or similar. Moves to and closes normally. -// If no oTarget, it still searches -void Search(object oTarget = OBJECT_INVALID) -{ - if(GetIsObjectValid(GetAttemptedSpellTarget()) || - GetIsObjectValid(GetAttemptedAttackTarget()) || - GetIsObjectValid(GetAttackTarget()) || - GetLocalTimer(AI_TIMER_SEARCH)) - { - return; - } - else - { - // Stop now - ClearAllActions(); - // Rest after combat? - if(GetSpawnInCondition(AI_FLAG_OTHER_REST_AFTER_COMBAT, AI_OTHER_MASTER)) - { - // 71: "[Search] Resting" - DebugActionSpeakByInt(71); - ForceRest(OBJECT_SELF); - ActionWait(f1); - } - // Determine the amount of time to search if there is antone else around. - int iIntelligence = GetBoundriedAIInteger(AI_INTELLIGENCE, i10, i10, i1); - float fTime = IntToFloat(iIntelligence * i3); - // Set local timer for a minimum of 4 seconds - SetLocalTimer(AI_TIMER_SEARCH, f4); - // Check some spells. Cast one if we have no true seeing ETC. - SearchSpells(); - // Stealth/search. - int iStealth = GetStealthMode(OBJECT_SELF); - int iSearch = GetDetectMode(OBJECT_SELF); - // We perfere to hide again if we search if set to...sneaky! - if(GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_HIDING, AI_OTHER_COMBAT_MASTER)) - { - if(iStealth != STEALTH_MODE_ACTIVATED) - { - SetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH, TRUE); - } - } - else - { - // If we are hiding, stop to search (we shouldn't be - who knows?) - if(iStealth == STEALTH_MODE_ACTIVATED) - { - SetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH, FALSE); - } - // And search! - if(iSearch != DETECT_MODE_ACTIVE && !GetHasFeat(FEAT_KEEN_SENSE)) - { - SetActionMode(OBJECT_SELF, ACTION_MODE_DETECT, TRUE); - } - } - // We check around the target, if there is one. - if(GetIsObjectValid(oTarget)) - { - ActionMoveToLocation(GetLocation(oTarget)); - // If it is a chest ETC. We close it. - if(GetIsOpen(oTarget)) - { - if(GetObjectType(oTarget) == OBJECT_TYPE_DOOR) - { - ActionCloseDoor(oTarget); - } - else - { - // Close it - ActionDoCommand(DoPlaceableObjectAction(oTarget, PLACEABLE_ACTION_USE)); - } - } - } - // We will get nearest enemy at the very least - else - { - // Use nearest heard - object oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, - OBJECT_SELF, i1, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD); - if(GetIsObjectValid(oEnemy)) - { - // Move to location - ActionMoveToLocation(GetLocation(oEnemy)); - } - } - // Note: Here, we will return to spawn location after moving to the - // object, if it is a valid setting, else we do the normal randomwalk - if(GetSpawnInCondition(AI_FLAG_OTHER_RETURN_TO_SPAWN_LOCATION, AI_OTHER_MASTER)) - { - ActionMoveToLocation(GetLocalLocation(OBJECT_SELF, AI_RETURN_TO_POINT)); - } - else - { - // 72: "[Search] Searching, No one to attack. [Time] " + FloatToString(fTime, i3, i2) - DebugActionSpeakByInt(72, OBJECT_INVALID, FALSE, FloatToString(fTime, i3, i2)); - // Randomly walk. - ActionRandomWalk(); - // Clear all actions stops Random Walk - DelayCommand((fTime - f1), ClearAllActions()); - // Delay a 30 second walk waypoints (which stops ActionRandomWalk). - DelayCommand(fTime, ExecuteScript(FILE_WALK_WAYPOINTS, OBJECT_SELF)); - } - } -} // Returns our custom AI file (if any) // - Blank string if not set @@ -2035,6 +1982,12 @@ void SetCustomAIFileName(string sAIFileName) { SetLocalString(OBJECT_SELF, AI_CUSTOM_AI_SCRIPT, sAIFileName); } +// Sets our User Defined Event file. +// * Should be called if we are using pre-events. By default, it is called. +void SetCustomUDEFileName(string sUDEFileName) +{ + SetLocalString(OBJECT_SELF, AI_UDE_SCRIPT_NAME, sUDEFileName); +} /*:://///////////////////////////////////////////// //:: Name: DetermineCombatRound @@ -2076,15 +2029,20 @@ void DetermineCombatRound(object oTarget = OBJECT_INVALID) // This checks the current special action (fleeing, runner, door smashing) // - Returns FALSE if none of them are performed // Use this to make sure that an ActionMoveTo or DCR doesn't fire if we are fleeing. +// * Note: 1.4: If we are not doing something that combat cannot interrupt (EG: +// if we are, say, moving to combat...but not if we were fleeing) we will delete +// what special action we were doing. int GetIsPerformingSpecialAction() { - int iAction = GetCurrentSetAction(); + int nAction = GetCurrentSetAction(); object oTarget = GetAttackTarget(); object oRunTarget; - switch(iAction) + switch(nAction) { + // We are running to get help case AI_SPECIAL_ACTIONS_ME_RUNNER: { + // Get who we are running too. oRunTarget = GetAIObject(AI_RUNNER_TARGET); if(GetIsObjectValid(oRunTarget)) { @@ -2101,6 +2059,7 @@ int GetIsPerformingSpecialAction() } } break; + // We are fleeing battle case AI_SPECIAL_ACTIONS_FLEE: { oRunTarget = GetAIObject(AI_FLEE_TO); @@ -2121,12 +2080,12 @@ int GetIsPerformingSpecialAction() { // Check if we have bad intellgence, and we will run away // from the nearest enemy if heard. - if(GetAIInteger(AI_INTELLIGENCE) <= i3) + if(GetAIInteger(AI_INTELLIGENCE) <= 3) { - oRunTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, i1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE); + oRunTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE); if(!GetIsObjectValid(oRunTarget)) { - oRunTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, i1, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD, CREATURE_TYPE_IS_ALIVE, TRUE); + oRunTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD, CREATURE_TYPE_IS_ALIVE, TRUE); if(!GetIsObjectValid(oRunTarget)) { oRunTarget = GetLastHostileActor(); @@ -2144,6 +2103,7 @@ int GetIsPerformingSpecialAction() } } break; + // We are moving out of a bad AOE case AI_SPECIAL_ACTIONS_MOVE_OUT_OF_AOE: { // We must be X distance away from a cirtain AOE, if we are not, we @@ -2164,6 +2124,16 @@ int GetIsPerformingSpecialAction() } } break; + default: + { + // We reset stuff - eg: Move to fighting or Search routines, + // because now we will (or should) initiate combat! + ResetCurrentAction(); + + // Return false to carry on a normal DCR or move to enemy. + return FALSE; + } + break; } // Return false to carry on a normal DCR or move to enemy. return FALSE; @@ -2180,6 +2150,91 @@ void AISpeakString(string sString) SpeakString(sString, TALKVOLUME_SILENT_TALK); } } +// This will apply the fear visual for fleeing, if the variable +// AI_FLAG_FLEEING_USE_VISUAL_EFFECT is on. +void ApplyFleeingVisual() +{ + if(GetSpawnInCondition(AI_FLAG_FLEEING_USE_VISUAL_EFFECT, AI_TARGETING_FLEE_MASTER)) + { + // Supernatural effect. + effect eFear = SupernaturalEffect(EffectVisualEffect(VFX_DUR_MIND_AFFECTING_FEAR)); + ApplyEffectToObject(DURATION_TYPE_PERMANENT, eFear, OBJECT_SELF); + } +} +// This will remove the fear visual for fleeing. +void RemoveFleeingVisual() +{ + // Get first effect + effect eCheck = GetFirstEffect(OBJECT_SELF); + while(GetIsEffectValid(eCheck)) + { + // Must be: Not from a spell + if(GetEffectSpellId(eCheck) == AI_SPELL_INVALID) + { + // * Supernatural only, a visual effect, permanent, applied by us. + if(GetEffectType(eCheck) == EFFECT_TYPE_VISUALEFFECT && + GetEffectSubType(eCheck) == SUBTYPE_SUPERNATURAL && + GetEffectCreator(eCheck) == OBJECT_SELF && + GetEffectDurationType(eCheck) == DURATION_TYPE_PERMANENT) + { + // Remove all effects which match this. + RemoveEffect(OBJECT_SELF, eCheck); + } + } + // Get next effect + eCheck = GetNextEffect(OBJECT_SELF); + } +} + +// 1.4 addition: See J_INC_CONSTANT, under "ETHEREALNESS:", it explains how +// etherealness and trueseing now work with later patches. +// * Special use in DetermineCombatRound() makes the AI never target ethereal people, +// but take account of them for cirtain things (IE: They exsist). +// NOTE: If oTarget is OBJECT_SELF, we return FALSE. +int GetIsEthereal(object oTarget) +{ + // Return FALSE. + if(oTarget == OBJECT_SELF) return FALSE; + + // Check for the 2 spells which might apply this. + return (GetHasSpellEffect(SPELL_ETHEREALNESS, oTarget) || + GetHasSpellEffect(AI_SPELLABILITY_ETHEREALNESS, oTarget)); +} + +// This will be for array speakstrings (IE: Taunts), and will make sure +// we are commandable, not dead, not deaf, and not silenced. +int CanSpeak() +{ + // If dead, we cannot speak + if(GetIsDead(OBJECT_SELF)) return FALSE; + + // If uncommandable, same + if(!GetCommandable()) return FALSE; + + // If silenced, cannot speak, and if deaf, we cannot hear ourselves speak + if(GetHasEffect(EFFECT_TYPE_SILENCE) || + GetHasEffect(EFFECT_TYPE_DEAF)) return FALSE; + + // We CAN speak, return TRUE + return TRUE; +} +// Get Has Effect +// Checks to see if the target has a given +// effect, usually from a spell. Really useful this is. +int GetHasEffect(int nEffectType, object oTarget = OBJECT_SELF) +{ + effect eCheck = GetFirstEffect(oTarget); + while(GetIsEffectValid(eCheck)) + { + if(GetEffectType(eCheck) == nEffectType) + { + return TRUE; + } + eCheck = GetNextEffect(oTarget); + } + return FALSE; +} + // Debug: To compile this script full, uncomment all of the below. /* - Add two "/"'s at the start of this line void main() diff --git a/_module/nss/j_inc_debug.nss b/_module/nss/j_inc_debug.nss index 802ab9c7..2fb4a03c 100644 --- a/_module/nss/j_inc_debug.nss +++ b/_module/nss/j_inc_debug.nss @@ -1,28 +1,27 @@ -/************************ [Debug] ********************************************** +/*/////////////////////// [Include - Debugging] //////////////////////////////// Filename: J_Inc_Debug -************************* [Debug] ********************************************** +///////////////////////// [Include - Debugging] //////////////////////////////// This contains DebugActionSpeak, the debug function. Makes it easier to uncomment debug lines. -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.3 - Added -************************* [Workings] ******************************************* + - In beta, changed it so this file controls all debug strings. Just + uncomment them and recompile to turn it on/off. + 1.4 - TO DO: Added some more debug strings I use +///////////////////////// [Workings] /////////////////////////////////////////// DebugActionSpeak normally writes a timestamped log entry, and speak a silent string Server Admins can hear. - To Do: Might make it more generic debug lines, where you can uncomment all - "XX" lines HERE, not in the files, so it compiles without them, and only - need an integer to speak one. - 1.3 added: - DebugActionSpeakByInt(int iInteger); - Removes many strings into this file - Can easily comment out all string so they are not added to compiled scripts if debugging unused (This saves space on compiled files :-D ) - Always uncomment the right bits if not using any debugging. -************************* [Arguments] ****************************************** +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: N/A -************************* [Debug] *********************************************/ +///////////////////////// [Include - Debugging] //////////////////////////////*/ // This will speak a cirtain integer number string (similar to a dialog reference). // - I (Jass) have just moved all strings I used all the time into here, so @@ -30,7 +29,7 @@ // - The numbers have no reference to much really. // - Calls DebugActionSpeak! // - See J_INC_DEBUG to uncomment/recomment in -void DebugActionSpeakByInt(int iInteger, object oInput = OBJECT_INVALID, int iInput = FALSE, string sInput = ""); +void DebugActionSpeakByInt(int iInteger, object oInput = OBJECT_INVALID, int nInput = FALSE, string sInput = ""); // Speaks and stamps a debug string. // - See J_INC_DEBUG to uncomment/recomment the debug strings. @@ -43,13 +42,13 @@ void DebugActionSpeak(string sString); // - The numbers have no reference to much really. // - Calls DebugActionSpeak! // - See J_INC_DEBUG to uncomment/recomment in -void DebugActionSpeakByInt(int iInteger, object oInput = OBJECT_INVALID, int iInput = FALSE, string sInput = "") +void DebugActionSpeakByInt(int iInteger, object oInput = OBJECT_INVALID, int nInput = FALSE, string sInput = "") { // TO UNCOMMENT/COMMENT: // - Add/Remove in "//" before the next lines "/*" // - Recompile all files - /* + ///* string sDebug; switch(iInteger) @@ -58,22 +57,22 @@ void DebugActionSpeakByInt(int iInteger, object oInput = OBJECT_INVALID, int iIn case 1: sDebug = "[DCR:Melee] Most Damaging Weapon. Target: " + GetName(oInput); break; case 2: sDebug = "[DCR:Melee] Most Damaging as Not Effective"; break; case 3: sDebug = "[DCR:Melee] Melee Code. No valid melee target/Dead. Exiting"; break; - case 4: sDebug = "[DCR:Melee] Melee attack. [Target] " + GetName(oInput) + " [Feat/Attack] " + IntToString(iInput); break; + case 4: sDebug = "[DCR:Melee] Melee attack. [Target] " + GetName(oInput) + " [Feat/Attack] " + IntToString(nInput); break; case 5: sDebug = "[DCR:Caster] Defensive Casting Mode ON [Enemy] " + GetName(oInput); break; case 6: sDebug = "[DCR:Caster] Moving away from AOO's. [Enemy] " + GetName(oInput); break; - case 7: sDebug = "[DCR:Casting] Talent(item) [TalentID] " + IntToString(iInput) + " [Target] " + GetName(oInput) + " [Location] " + sInput; break; - case 8: sDebug = "[DCR:Casting] Workaround for Spontaeous [SpellID] " + IntToString(iInput) + " [Target] " + GetName(oInput); break; - case 9: sDebug = "[DCR:Casting] NormalSpell [ID] " + IntToString(iInput) + " [Target] " + GetName(oInput) + " [Location] " + sInput; break; - case 10: sDebug = "[DCR:Casting] TalentSpell. [ID] " + IntToString(iInput) + " [Target] " + GetName(oInput) + " [Location] " + sInput; break; - case 11: sDebug = "[DCR:Casting] SubSpecialSpell. [ID] " + IntToString(iInput) + " [Target] " + GetName(oInput) + " [Location] " + sInput; break; - case 12: sDebug = "[DCR:Casting] NormalRandomSpell. [ID] " + IntToString(iInput) + " [Target] " + GetName(oInput) + " [Location] " + sInput; break; - case 13: sDebug = "[DCR:Casting] Backup spell caught: " + IntToString(iInput); break; - case 14: sDebug = "[DCR:Feat] [ID] " + IntToString(iInput) + " [Enemy] " + GetName(oInput); break; - case 15: sDebug = "[DCR:Casting] Grenade [ID] " + IntToString(iInput) + " [Target] " + GetName(oInput) + " [Location] " + sInput; break; + case 7: sDebug = "[DCR:Casting] Talent(item) [TalentID] " + IntToString(nInput) + " [Target] " + GetName(oInput) + " [Location] " + sInput; break; + case 8: sDebug = "[DCR:Casting] Workaround for Spontaeous [SpellID] " + IntToString(nInput) + " [Target] " + GetName(oInput); break; + case 9: sDebug = "[DCR:Casting] NormalSpell [ID] " + IntToString(nInput) + " [Target] " + GetName(oInput) + " [Location] " + sInput; break; + case 10: sDebug = "[DCR:Casting] TalentSpell. [ID] " + IntToString(nInput) + " [Target] " + GetName(oInput) + " [Location] " + sInput; break; + case 11: sDebug = "[DCR:Casting] SubSpecialSpell. [ID] " + IntToString(nInput) + " [Target] " + GetName(oInput) + " [Location] " + sInput; break; + case 12: sDebug = "[DCR:Casting] NormalRandomSpell. [ID] " + IntToString(nInput) + " [Target] " + GetName(oInput) + " [Location] " + sInput; break; + case 13: sDebug = "[DCR:Casting] Backup spell caught: " + IntToString(nInput); break; + case 14: sDebug = "[DCR:Feat] [ID] " + IntToString(nInput) + " [Enemy] " + GetName(oInput); break; + case 15: sDebug = "[DCR:Casting] Grenade [ID] " + IntToString(nInput) + " [Target] " + GetName(oInput) + " [Location] " + sInput; break; case 16: sDebug = "[AOE Call] Moving out of/Dispeling an AOE. [Tag] " + GetTag(oInput); break; case 17: sDebug = "[DCR:Special] Darkness + Caster. No seen enemy. Dispel/Move."; break; - case 18: sDebug = "[DRC:Talent] Using Talent (Healing). [TalentID] " + IntToString(iInput) + " [Target] " + GetName(oInput); break; - case 19: sDebug = "[DCR:Healing] (Should) Healing [Target]" + GetName(oInput) + " [CurrentHP|Max|ID|Rank|Power] " + IntToString(iInput); break; + case 18: sDebug = "[DRC:Talent] Using Talent (Healing). [TalentID] " + IntToString(nInput) + " [Target] " + GetName(oInput); break; + case 19: sDebug = "[DCR:Healing] (Should) Healing [Target]" + GetName(oInput) + " [CurrentHP|Max|ID|Rank|Power] " + IntToString(nInput); break; case 20: sDebug = "[DCR Healing] Boss Action, create Critical Wounds potion"; break; case 21: sDebug = "[DCR:Casting] Healing self with healing kit, [Kit] " + GetName(oInput); break; case 22: sDebug = "[DCR:Feat] Summoning my familiar"; break; @@ -86,18 +85,18 @@ void DebugActionSpeakByInt(int iInteger, object oInput = OBJECT_INVALID, int iIn case 29: sDebug = "[DCR:Bard Song] Using"; break; case 30: sDebug = "[DCR:Bard Curse Song] Using"; break; case 31: sDebug = "[DCR:All Spells] Error! No casting (No spells, items, target Etc)."; break; - case 32: sDebug = "[DCR:All Spells] [Modifier|BaseDC|SRA] " + IntToString(iInput); break; - case 33: sDebug = "[DCR:Casting] Cheat Spell. End of Spells. [Spell] " + IntToString(iInput) + "[Target]" + GetName(oInput); break; + case 32: sDebug = "[DCR:All Spells] [Modifier|BaseDC|SRA] " + IntToString(nInput); break; + case 33: sDebug = "[DCR:Casting] Cheat Spell. End of Spells. [Spell] " + IntToString(nInput) + "[Target]" + GetName(oInput); break; case 34: sDebug = "[DCR:All Spells] Ranged Spells. Should use closer spells/move nearer"; break; - case 35: sDebug = "[DCR:Dragon] Breath weapon & attacking [Breath ID] " + IntToString(iInput) + " [Target] " + GetName(oInput); break; + case 35: sDebug = "[DCR:Dragon] Breath weapon & attacking [Breath ID] " + IntToString(nInput) + " [Target] " + GetName(oInput); break; case 36: sDebug = "[DCR:Dragon] Wing Buffet [Target] " + GetName(oInput); break; case 37: sDebug = "[DCR:Beholder] Teleport"; break; case 38: sDebug = "[DCR:Beholder] Rays"; break; case 39: sDebug = "[DCR:Targeting] No valid enemies in sight, moving to allies target's. [Target] " + GetName(oInput); break; case 40: sDebug = "[DCR:Targeting] Override Target Seen. [Name]" + GetName(oInput); break; case 41: sDebug = "[DCR:Targeting] No seen in LOS, Attempting to MOVE to something [Target]" + GetName(oInput); break; - case 42: sDebug = "[DCR:Skill] Using agressive skill (+Attack). [Skill] " + IntToString(iInput) + " [Enemy]" + GetName(oInput); break; - case 43: sDebug = "[DCR:Pre-Melee Spells] All Potions Using. [Spell ID] " + IntToString(iInput); break; + case 42: sDebug = "[DCR:Skill] Using agressive skill (+Attack). [Skill] " + IntToString(nInput) + " [Enemy]" + GetName(oInput); break; + case 43: sDebug = "[DCR:Pre-Melee Spells] All Potions Using. [Spell ID] " + IntToString(nInput); break; case 44: sDebug = "[DCR:Pre-Melee Spells] True Strike Emptive attack [Target] " + GetName(oInput); break; case 45: sDebug = "[DCR:CounterSpell] Counterspelling. [Target] " + GetName(oInput); break; case 46: sDebug = "[DRC] START [Intruder]" + GetName(oInput); break; @@ -119,26 +118,26 @@ void DebugActionSpeakByInt(int iInteger, object oInput = OBJECT_INVALID, int iIn case 59: sDebug = "[Phisically Attacked] Attacking back. [Attacker(enemy)] " + GetName(oInput); break; case 60: sDebug = "[Phisically Attacked] Not same area. [Attacker(enemy)] " + GetName(oInput); break; // Damaged - case 61: sDebug = "[Damaged] Morale Penalty for 600 seconds [Penalty]" + IntToString(iInput); break; + case 61: sDebug = "[Damaged] Morale Penalty for 600 seconds [Penalty]" + IntToString(nInput); break; case 62: sDebug = "[Damaged] Not in combat: DCR [Damager]" + GetName(oInput); break; case 63: sDebug = "[Damaged] Not in combat: DCR. Ally hit us. [Damager(Ally?)]" + GetName(oInput); break; // Death - case 64: sDebug = "[Death] Checking corpse status in " + IntToString(iInput) + " [Killer] " + GetName(oInput) + " [Times Died Now] " + sInput; break; + case 64: sDebug = "[Death] Checking corpse status in " + IntToString(nInput) + " [Killer] " + GetName(oInput) + " [Times Died Now] " + sInput; break; // Disturbed - case 65: sDebug = "[Disturbed] (pickpocket) Attacking Enemy [Disturber] " + GetName(oInput) + " [Type] " + IntToString(iInput); break; + case 65: sDebug = "[Disturbed] (pickpocket) Attacking Enemy [Disturber] " + GetName(oInput) + " [Type] " + IntToString(nInput); break; // Rest - case 66: sDebug = "[Rested] Resting. [Type(should be invalid)] " + IntToString(iInput); break; + case 66: sDebug = "[Rested] Resting. [Type(should be invalid)] " + IntToString(nInput); break; // Spell Cast at case 67: sDebug = "[Spell] Caster isn't a creature! May look for target [Caster] " + GetName(oInput); break; case 68: sDebug = "[Spell:Enemy/Hostile] Not in combat. Attacking: [Caster] " + GetName(oInput); break; case 69: sDebug = "[Spell] (ally). Not in combat. May Attack/Move [Caster] " + GetName(oInput); break; // Spell Other AI // - Shouts - case 70: sDebug = "[Shout] Reacting To Shout. [ShoutNo.] " + IntToString(iInput) + " [Shouter] " + GetName(oInput); break; + case 70: sDebug = "[Shout] Reacting To Shout. [ShoutNo.] " + IntToString(nInput) + " [Shouter] " + GetName(oInput); break; // Constants // - Search case 71: sDebug = "[Search] Resting"; break; - case 72: sDebug = "[Search] Searching, No one to attack. [Time] " + sInput; break; + case 72: sDebug = "[Search] Searching, No one to attack. [Rounds Remaining] " + IntToString(nInput) + ". [Possible target] " + GetName(oInput); break; // - DCR case 73: sDebug = "[Call for DCR] Default AI [Pre-Set Target]" + GetName(oInput); break; case 74: sDebug = "[Call for DCR] Custom AI [" + sInput + "] [Pre-Set Target]" + GetName(oInput); break; @@ -160,14 +159,14 @@ void DebugActionSpeakByInt(int iInteger, object oInput = OBJECT_INVALID, int iIn void DebugActionSpeak(string sString) { // You MUST uncomment this line, IF you use either of the below things - //string sNew = "[Debug]" + GetName(OBJECT_SELF) + "[ObjectID]" + ObjectToString(OBJECT_SELF) + " [Debug] " + sString; + string sNew = "[Debug]" + GetName(OBJECT_SELF) + "[ObjectID]" + ObjectToString(OBJECT_SELF) + " [Debug] " + sString; // Note, uncomment this, so that DM's can hear the debug speaks, normally it is // only server admins who can hear the debug. If you are not testing, it might // be best to keep this uncommented. // Futher: - Must have debug mode set to 1 // - Only the server admin can seem to see this. - //SpeakString(sNew, TALKVOLUME_SILENT_TALK); +// SpeakString(sNew, TALKVOLUME_TALK); // Note, uncomment this line to send a message to the first PC in the module. // - Useful for singleplayer testing @@ -176,13 +175,13 @@ void DebugActionSpeak(string sString) // This writes the entry to the log, very important, if debugging // Futher: - If left up for a long time, logs can get very big with the AI // - Use to find problems in the AI and report to me :-D (Jasperre) - //WriteTimestampedLogEntry(sNew); + WriteTimestampedLogEntry(sNew); } // Debug: To compile this script full, uncomment all of the below. -/* +/* - Add two "/"'s at the start of this line void main() { - DebugActionSpeak("Test"); + return; } -*/ +//*/ diff --git a/_module/nss/j_inc_generic_ai.nss b/_module/nss/j_inc_generic_ai.nss index cb508c51..703920d5 100644 --- a/_module/nss/j_inc_generic_ai.nss +++ b/_module/nss/j_inc_generic_ai.nss @@ -1,6 +1,6 @@ -/************************ [Combat Include File] ******************************** - Filename: J_INC_GENERIC_AI -************************* [Combat Include File] ******************************** +/*/////////////////////// [Include - Combat] /////////////////////////////////// + Filename: J_INC_Generic_AI +///////////////////////// [Include - Combat] /////////////////////////////////// This is included in j_ai_detercombat, and executed via the main call AI_DetermineCombatRound, to determine a hostile action to do against the enemy. @@ -15,15 +15,49 @@ - Spells - Feats (For combat, like Bulls Strength) - Melee attack (Ranged and Melee) -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.3 - All functions prefixed to AI_ - Lot more documentation - All parts changed, mainly: - Better targeting - Different Effect Setting - More randomised spellcasting -************************* [Workings] ******************************************* - This is included in "j_ai_detercombat". It is the main combat include file + 1.4 - Bugfixes. Quite a few minor, usually. Some major ones. + - Sub-spells merged into normal spell routines, it was a waste of space spliting. + - Ethereal creatures can be sometimes seen (but not attacked). + This is now taken into account. AI_GetTargetSanityCheck includes it, + and a new function handles behaviour when faced with *just* 1 ethereal enemy + - Removed quite a few Global* variables already - some were not even used + and some used once or twice! + - AI_ActionCastSpell() behaviour changed. New global variables track + if it is now pointless (for a time) to check cirtain levels of spells, + and delay checking again for 3 minutes. Increase in lag compensated by + a much better bit of code and less global variables. IE: IGNORE TALENTS + - Removed redudant AI_ActionUseFeatOnObject(). Added new + AI_ActionUseSpellLikeFeat() which replaced all of its uses (and should fix + some feat related bugs with the AI). Hardly any ActionUseFeat() calls + are now used, except for Combat offensive feats (EG: Knockdown) which + are without scripts. + + ADDIONTAL: + - Need to therefore sort out casting spells from items, and potion usage. both + have been removed from this version so far - will be put back in better later. + + - TO DO: + - See bugs file + - Stuff to optimise + - Sort out items! + - AI_ActionCastSpellRandom should be streamlined into AI_ActionCastSpell, but + add another integer thingy. Makes it much easier. CAn have a new constant + like "NOT_RANDOM = -1", so randomness is ignored. + - Better allied buffing strategies and stuff. Stay invisible and use + spells appropriate to level and range of allies. Such things like mage + armor can be useful too (if we have it, AC increase are always good!) + TEMP: + - Until solved, removed all checks for AI_VALID_SPELLS things. + +///////////////////////// [Workings] /////////////////////////////////////////// + This is included in "J_AI_DeterCombat". It is the main combat include file and determines what to do by checking a lot of conditions. It has 2 User-defined Events: @@ -33,15 +67,15 @@ Useful to check special things, and can be used to override default AI actions, or to change them once they have happened. See the user defined file for workings of the Pre events. -************************* [Arguments] ****************************************** +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: Global* Objects/Integers/Toggles, GetSpawnInCondition, GetCommandable, AI_ActionCast* AI_ActionUse* (Other AI_Action* things) ClearAllActions, GetAC, GetCurrentHitPoints, GetMaxHitPoints, GetHitDice, GetCurrentAction (and lots more...). -************************* [Combat Include File] *******************************/ +///////////////////////// [Include - Combat] /////////////////////////////////*/ -/************************ [Intelligence Documentation] ************************* +/*/////////////////////// [Intelligence Documentation] ///////////////////////// Intelligence in·tel·li·gence ( P ) Pronunciation Key (n-tl-jns) @@ -74,12 +108,12 @@ -************************* [Intelligence Documentation] ************************/ +///////////////////////// [Intelligence Documentation] ///////////////////////*/ // Include: All constants. Also contains Get/Set/Delete Spawn In Conditions. -#include "j_inc_constants" +#include "J_INC_CONSTANTS" // Sets effects. This doesn't have to be seperate, but I like it seperate. -#include "j_inc_seteffects" +#include "J_INC_SETEFFECTS" /******************************************************************************/ // Combat include, spell effect/immune constants @@ -106,20 +140,19 @@ const int GlobalImmunityDeath = 0x00000800; const int GlobalImmunityNegativeEnergy = 0x00001000; const int GlobalImmunityMantalProtection = 0x00002000; // Its own immunity, checked sometimes. const int GlobalImmunityPetrify = 0x00004000; -const int GlobalImmunityFlying = 0x00008000; // Earthquake ETC. +//const int GlobalImmunityFlying = 0x00008000; // Earthquake ETC. const int GlobalImmunitySlow = 0x00010000; /*************************** Globals set-up ******************************** We set up all spells and categories, as well as all targets we may use (its - much easier than imputting countless entries into function headers). Any + much easier than inputting countless entries into function headers). Any sort of globals that are required are also added here - anything that would pop up in more than one place, or would change from one or more event. **************************** Globals set-up *******************************/ // OUR GLOBAL CONSTANTS -int GlobalIntelligence, GlobalOurHitDice, GlobalOurSize, GlobalOurAC, +int GlobalIntelligence, GlobalOurHitDice, GlobalOurAC, GlobalOurBaseAttackBonus, // Used and set for melee. USes GetBaseAttackBonus, as weapons are not set. - GlobalOurRace, GlobalOurGoodEvil, GlobalSilenceSoItems, // This is set to TRUE if we are affected with silence // - meaning no proper spells! ALWAYS off if we have auto-silence. GlobalInTimeStop,// This is used a LOT to see if we are in time stop @@ -129,15 +162,12 @@ int GlobalIntelligence, GlobalOurHitDice, GlobalOurSize, GlobalOurAC, // for lower casters - they may cast even if the enemy always saves! GlobalSpellPenetrationRoll, // SR penetration roll. GlobalOurCurrentHP, GlobalOurMaxHP, GlobalOurPercentHP,// HP globals. - GlobalOurAppearance,// Used normally to stop dragon breaths against same dragons! - SRA, // "Spell range attacking", mage behaviour, used for constant checking. + SRA, // "Spell range attacking", mage behavnOur, used for constant checking. GlobalWeAreSorcerorBard,// Just is GetLevelByClass(CLASS_TYPE_SORCERER/BARD), // but a global. With summoning, it won't summon a similar one if the old is at low HP GlobalCanSummonSimilarLevel,// Checked for when set up. If a level over 0, we may // Summon another spell monster at a similar level. // The level is set when we cast a spell of it. - GlobalBestSpontaeousHealingSpell,// This is set to the best spell we could - // Spontaeously cast. Set up as talents below. GlobalTimeStopArraySize, GlobalLastSpellValid, // Random spells, if this is set to > 0, it casts it after random chances of others GlobalRandomCastModifier,// Random casting, the extra % added - 2xIntelligence @@ -154,14 +184,8 @@ object GlobalMeleeTarget, // Set from either a ranged or melee target :-) GlobalDispelTarget, // Used for breaching too GlobalNearestEnemySeen, GlobalNearestEnemyHeard, GlobalNearestSeenAlly, GlobalNearestAlly, - GlobalNearestLeader, GlobalThisArea, - GlobalBuffAlly, GlobalHealingKit, - /* GlobalPreviousTarget,*/ - // - Global Spell targets - // - One target, but a float for range to. - // Right == Ranged slot, non-shield slot. - // Left == Torch slot, secondary slot, shield slot. - GlobalLeftHandWeapon, GlobalRightHandWeapon; + GlobalNearestLeader, + GlobalBuffAlly; // ENEMY/ALLY INTEGERS, VLAIDS ETC. @@ -172,13 +196,13 @@ int GlobalAnyValidTargetObject, GlobalEnemiesIn4Meters, GlobalTotalSeenHeardEnemies, // Ranged/Melee Attackers. Ranged attackers = Attackers with bows. GlobalMeleeAttackers, GlobalRangedAttackers, - // Total allies + People. We don't count ourselves. - GlobalTotalPeople, GlobalTotalAllies, + // Total allies. We don't count ourselves. 1.4: Removed Total People, never needed! + GlobalTotalAllies, // Average's - BAB, HDs. GlobalAverageEnemyBAB, GlobalAverageEnemyHD, GlobalAverageFriendlyHD, // Melee target things... - GlobalMeleeTargetAC, GlobalMeleeTargetBAB, + GlobalMeleeTargetAC, // Any VALID objects. GetIsObjectValid. GlobalValidLeader, GlobalValidAlly, GlobalValidSeenAlly, GlobalValidNearestSeenEnemy, GlobalValidNearestHeardEnemy, @@ -206,93 +230,15 @@ int GlobalAnyValidTargetObject, float GlobalRangeToMeleeTarget, GlobalSpellTargetRange, GlobalRangeToNearestEnemy, GlobalRangeToAlly, GlobalOurReach, GlobalRangeToFuthestEnemy, GlobalBuffRangeAddon; -// One location - GlobalSummonLocation - for summon location :-) -location GlobalSummonLocation; - -/* This is the set values of spells that the talent actually is. - How it works (for the above). We set if we have items, or potions. - Then, we check the respective talent category. If the spell stored matches, it is true. - then, we go into a special silence check - we get the talent again. It *should* be the - same, and if so, use it! - - Shows what spells are valid, which categories, to skip some GetHasSpell's - Format: - (Other)ther (Special - Darkness, light and silence)(Aura - auras/spells like it). (Rage = Rage) - (Allies) Obtain Allies - summon creature. - (Con)ditional,(Enh)ancement, (Pro)tection - (Harm)armful. - For (B)- (Self) Self. (SinTar)Single Target, (Are)Area effect, - For (H)- (Breath) Breath, (AreaDis) Discriminate, (AreaInd) Indiscriminate -*/ -int -/*1*/ SpellHostAreaDis, ItemHostAreaDis, -/*2*/ SpellHostRanged, ItemHostRanged, -/*3*/ SpellHostTouch, ItemHostTouch, - -/*6*/ SpellConAre, ItemConAre, -/*7*/ SpellConSinTar, ItemConSinTar, -/*8*/ SpellEnhAre, ItemEnhAre, -/*9*/ SpellEnhSinTar, ItemEnhSinTar, -/*10*/ SpellEnhSelf, ItemEnhSelf, -/*11*/ SpellHostAreaInd, ItemHostAreaInd, -/*12*/ SpellProSelf, ItemProSelf, -/*13*/ SpellProSinTar, ItemProSinTar, -/*14*/ SpellProAre, ItemProAre, -/*15*/ SpellAllies, ItemAllies, -/*16*/ SpellAura, - -/*18*/ PotionCon, -/*19*/ SpellHostBreath, -/*20*/ PotionPro, -/*21*/ PotionEnh, - -/*23*/ SpellOtherSpell, -// Special: validness - SpellAnySpellValid, - // Feats - ValidFeats, -// Do we have items (wands) avalible? Or potions? To check spells, we -// make sure that - GobalOtherItemsValid, GobalPotionsValid; - -talent tPotionCon, tPotionPro, tPotionEnh; // These are general talents, Always set - // because we can use these parrallel to spells. +// New constant ACTION_MODE_ for "AI_SetMeleeMode()" default value. 0 and upwards +// are used. +const int ACTION_MODE_ALL_OFF = -1; /*************************** Functions to order **************************** This should be empty each patch. If you start adding your own things, adding them here makes changes easy to know about, if you like. I do, anyway :-P **************************** Functions to order ***************************/ - -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -//@@@@@@@@@@@@@@@@@ SETUP OF THINGS @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -// This is a group of local variables that are set to 0 each time here, and -// used each round. This is better than local ints to use. - -//*1*/ SpellHostAreaDis, ItemHostAreaDis, -//*2*/ SpellHostRanged, ItemHostRanged, -//*3*/ SpellHostTouch, ItemHostTouch, -// -//*6*/ SpellConAre, ItemConAre, -//*7*/ SpellConSinTar, ItemConSinTar, -//*8*/ SpellEnhAre, ItemEnhAre, -//*9*/ SpellEnhSinTar, ItemEnhSinTar, -//*10*/ SpellEnhSelf, ItemEnhSelf, -//*11*/ SpellHostAreaInd, ItemHostAreaInd, -//*12*/ SpellProSelf, ItemProSelf, -//*13*/ SpellProSinTar, ItemProSinTar, -//*14*/ SpellProAre, ItemProAre, -//*15*/ SpellAllies, ItemAllies, -//*16*/ SpellAura, -// -//*18*/ PotionCon, -//*19*/ SpellHostBreath, -//*20*/ PotionPro, -//*21*/ PotionEnh, -// -//*23*/ SpellOtherSpell - //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //@@@@@@@@@@@@@@@@@ CORE AI FUNCTIONS @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@ -305,17 +251,26 @@ void AI_DetermineCombatRound(object oIntruder = OBJECT_INVALID); // These all have the pre-name AttemptX - as they can return TRUE or FALSE //***************************** AttemptSpell *********************************** -// This attempts to cast a spell, running down the lists. -// The only variable is iLowest and iBAB level's, targets are globally set. -// - iLowestSpellLevel - If it is set to more than 1, then all spells of that +// Called from AI_AttemptAllSpells, this will run through the spell lists, until +// it casts on, else it will return FALSE. +// * nLowestSpellLevel - If it is set to more than 1, then all spells of that // level and lower are just ignored. Used for dragons. Default 0. -// - iBABCheckHighestLevel - We check our BAB to see if attacking them would probably +// * nBABCheckHighestLevel - We check our BAB to see if attacking them would probably +// be a better thing to do. Default 3, it adds 5DC for each level. +// * bFirstRunThrough - used for personal spells (cast on us) like the ranged checks, for SRA. +// * bRangeLongValid etc - used for ranged spell attacking. bFirstRunThrough is a personal version. +// * bSingleSpellsFirst - Check AI_AttemptAllSpells(). +// See AI_AttemptAllSpells() for more info. +int AI_RunThroughSpells(int nLowestSpellLevel, int nBABCheckHighestLevel, int bSingleSpellsFirst, int bSingleSpellOverride, int bMultiSpellOverride, int bFirstRunThrough = TRUE, int bRangeLongValid = FALSE, int bRangeMediumValid = FALSE, int bRangeShortValid = FALSE, int bRangeTouchValid = FALSE); +// This will attempt to cast a spell from all the spells we know. +// It calls AI_RunThroughSpells() to work. +// * nLowestSpellLevel - If it is set to more than 1, then all spells of that +// level and lower are just ignored. Used for dragons. Default 0. +// * nBABCheckHighestLevel - We check our BAB to see if attacking them would probably // be a better thing to do. Default 3, it adds 5DC for each level. -// - iLastCheckedRange - Ranged attacking. Starts at 1, and goes to 4 max. -// - Range: Long 40, Medium: 20, Short: 10, Touch: 2.25 (Game meters). Personal = 0 // NOTE 1: If GlobalItemsOnly is set, we only check for item talents! // NOTE 2: It uses the SAME target, but for ranged attacking, we use a float range to check range :-) -int AI_AttemptAllSpells(int iLowestSpellLevel = 0, int iBABCheckHighestLevel = 3, int iLastCheckedRange = 1, int InputRangeLongValid = FALSE, int InputRangeMediumValid = FALSE, int InputRangeShortValid = FALSE, int InputRangeTouchValid = FALSE); +int AI_AttemptAllSpells(int nLowestSpellLevel = 0, int nBABCheckHighestLevel = 3); // Returns TRUE if we counterspell a counter spell target, only does it // if we have Dispels, and if set to want to be in a group, we are in one :-) int AI_AttemptCounterSpell(); @@ -361,10 +316,13 @@ int AI_AttemptMindflayerCombat(); //****************************** AttemptFeat *********************************** -// GlobalUseTurning is set if we do have things we can turn (And not already!). -// It uses it here if so. +// Turning will be attempted in this function. It checks if we have any turning +// left, then will check if we want to turn (we don't turn every round constantly) +// then we check for creatures to turn - if there are any, we turn undead. int AI_AttemptFeatTurning(); -// This will use bard song, or damage with curse song! +// This will use bard song, or damage with curse song! Both have special +// cases for the deafness and silence (introduced in later patches) and some +// other stuff. int AI_AttemptFeatBardSong(); // Runs through summoning a familiar - uses the feat if it has it. // INCLUDES companion as well! Will attack at range with a bow if possible. @@ -380,10 +338,10 @@ int AI_AttemptFeatCombatHostile(); // This will fire any aura's they have, quickened cast, and added to the top of // thier action queue. void AI_ActionAbilityAura(); -// This will check if we do not have iSpellID's effects, have got iSpellID, and +// This will check if we do not have nSpellID's effects, have got nSpellID, and // cheat-instant cast the spell if we do. This means that we can use it unlimited -// times (incase it gets dispelled!) -void AI_AttemptCastAuraSpell(int iSpellID); +// times (incase it gets dnSpelled!) +void AI_AttemptCastAuraSpell(int nSpellID); // Runs though several basic checks. True, if any are performed // 1 - Darkness. If so, dispel (inc. Ultravision) or move out (INT>=4) // 2 - AOE spells. Move away from enemy if got effects (more so if no one near) (INT>=3) @@ -402,9 +360,9 @@ int AI_AttemptConcentrationCheck(object oTarget); int AI_AttemptArcherRetreat(); // Will polymorph Self if not already so. Will return TRUE if it casts best on self. int AI_AttemptPolyMorph(); -// This will cheat-cast iSpell at oTarget. Note that we will know if we have it +// This will cheat-cast nSpell at oTarget. Note that we will know if we have it // by checking what appearance we have. -void AI_ActionCastShifterSpell(int iSpell, object oTarget = OBJECT_SELF); +void AI_ActionCastShifterSpell(int nSpell, object oTarget = OBJECT_SELF); //**************************** AttemptSpecial ********************************** //**************************** AttemptSkills *********************************** @@ -453,62 +411,66 @@ object AI_GetDismissalTarget(); // - We may cast many on allies too int AI_ActionCastWhenInvisible(); // This will loop seen allies in a cirtain distance, and get the first one without -// the spells effects of iSpell1 to iSpell4 (and do not have the spells). -// - Quite expensive loop. Only used if we have the spell (iSpellToUse1+) -// in the first place (no items!) and not the timer which stops it for a few rounds (on iSpellToUse1) -// - TRUE if it casts its any of iSpellToUseX's. +// the spells effects of nSpell1 to nSpell4 (and do not have the spells). +// - Quite expensive loop. Only used if we have the spell (nSpellToUse1+) +// in the first place (no items!) and not the timer which stops it for a few rounds (on nSpellToUse1) +// - TRUE if it casts its any of nSpellToUseX's. // * It has only a % chance to cast if GlobalWeAreBuffer is not TRUE. -int AI_ActionCastAllyBuffSpell(float fMaxRange, int iPercent, int iSpellToUse1, int iSpellToUse2 = -1, int iSpellToUse3 = -1, int iSpellToUse4 = -1, int iSpellOther1 = -1, int iSpellOther2 = -1); +int AI_ActionCastAllyBuffSpell(float fMaxRange, int nPercent, int nSpellToUse1, int nSpellToUse2 = AI_SPELL_INVALID, int nSpellToUse3 = AI_SPELL_INVALID, int nSpellToUse4 = AI_SPELL_INVALID, int nSpellOther1 = AI_SPELL_INVALID, int nSpellOther2 = AI_SPELL_INVALID); // This will shout, maybe, some commands to allies. Or just command them! void AI_ActionLeaderActions(); // Dispels or moves out of the oAOE. -// - If we have >= iMax AND <= iDamage HP... -// AND under iPercent total HP... +// - If we have >= nMax AND <= nDamage HP... +// AND under nPercent total HP... // - We Dispel, or move out of the AOE. Move if friendly. -// - Use local object set to iSpell, which should be the nearest of the spell. -int AI_ActionDispelAOE(int iSpell, int iDamageOnly, float fRange, int iDamage, int iMax, int iPercent); +// - Use local object set to nSpell, which should be the nearest of the spell. +int AI_ActionDispelAOE(int nSpell, int bDamageOnly, float fRange, int nDamage, int nMax, int nPercent); // Casts the breach range of spells on GlobalDispelTarget. TRUE if any are cast. int AI_ActionCastBreach(); // Casts the dispel range of spells on GlobalDispelTarget. TRUE if any are cast. int AI_ActionCastDispel(); +// This wrappers AI_ActionCastBreach() and AI_ActionCastDispel(). Input +// nValue for 1 (Lowest priority) to 5, to see if we'll use them. Returns +// TRUE if any are cast. +int AI_ActionAttemptDispel(int nValue, int bRangeMediumValid); // Wrappers Premonition, Greater Stoneskin and Stoneskin. // Includes Shades Stoneskin too. SPELL_SHADES_STONESKIN -// - iLowest - 8 = Prem, 6 = Greater, 4 = Stoneskin +// - nLowest - 8 = Prem, 6 = Greater, 4 = Stoneskin // - Checks AI_GetAIHaveSpellsEffect(GlobalHasStoneSkinProtections) -int AI_SpellWrapperPhisicalProtections(int iLowest = 1); +int AI_SpellWrapperPhisicalProtections(int nLowest = 1); // Wrappers Energy Buffer, Protection From Elements, Resist Elements, Endure elements -// - iLowest - Goes 5, 3, 2, 1. +// - nLowest - Goes 5, 3, 2, 1. // - Checks AI_GetAIHaveSpellsEffect(GlobalHasElementalProtections) -int AI_SpellWrapperElementalProtections(int iLowest = 1); +int AI_SpellWrapperElementalProtections(int nLowest = 1); // Wrappers Haste and Mass Haste. -// - iLowest - 6 = Mass, 3 = Haste +// - nLowest - 6 = Mass, 3 = Haste // - Checks AI_GetAIHaveSpellsEffect(GlobalHasStoneSkinProtections) -int AI_SpellWrapperHasteEnchantments(int iLowest = 1); +int AI_SpellWrapperHasteEnchantments(int nLowest = 1); // Wrappers Shadow Shield, Ethereal Visage and Ghostly Visage. // Includes Greater Shadow Conjuration Ghostly Visage (SPELL_GREATER_SHADOW_CONJURATION_MIRROR_IMAGE -// - iLowest - 7 = Shadow, 6 = Ethereal 2 = Ghostly +// - nLowest - 7 = Shadow, 6 = Ethereal 2 = Ghostly // - Checks AI_GetAIHaveSpellsEffect(GlobalHasVisageProtections) -int AI_SpellWrapperVisageProtections(int iLowest = 1); +int AI_SpellWrapperVisageProtections(int nLowest = 1); // Wrappers All Mantals (Greater, Normal, Lesser) (Spell Mantals) -// - iLowest - 9 = Greater, 7 = Normal. 5 = Lesser +// - nLowest - 9 = Greater, 7 = Normal. 5 = Lesser // - Checks AI_GetAIHaveSpellsEffect(GlobalHasMantalProtections) -int AI_SpellWrapperMantalProtections(int iLowest = 1); +int AI_SpellWrapperMantalProtections(int nLowest = 1); // Wrappers All Globes (Greater, Shadow Conjuration, Minor) -// - iLowest - 6 = Greater, 4 = Shadow/Minor +// - nLowest - 6 = Greater, 4 = Shadow/Minor // - Checks AI_GetAIHaveSpellsEffect(GlobalHasGlobeProtections) -int AI_SpellWrapperGlobeProtections(int iLowest = 1); +int AI_SpellWrapperGlobeProtections(int nLowest = 1); // Wrappers All Shields - Elemental Shield, Wounding Whispers -// - iLowest - 4 = Elemental, 3 = Wounding, Acid Sheath, 2 = Death Armor. +// - nLowest - 4 = Elemental, 3 = Wounding, Acid Sheath, 2 = Death Armor. // - Checks AI_GetAIHaveSpellsEffect(GlobalHasElementalShieldSpell) -int AI_SpellWrapperShieldProtections(int iLowest = 1); +int AI_SpellWrapperShieldProtections(int nLowest = 1); // Wrappers All Mind resistance spells - Mind blank, Lesser and Clarity. bioware likes 3's... -// - iLowest - 8 = Mind Blank, 5 = Lesser, 2 = Clarity +// - nLowest - 8 = Mind Blank, 5 = Lesser, 2 = Clarity // - Checks AI_GetAIHaveSpellsEffect(GlobalHasMindResistanceProtections) -int AI_SpellWrapperMindResistanceProtections(int iLowest = 1); +int AI_SpellWrapperMindResistanceProtections(int nLowest = 1); // Wrappers All Consealment spells - Improved Invisiblity. Displacement. -// - iLowest - 4 = Improved Invisiblit, 3 = Displacement +// - nLowest - 4 = Improved Invisiblit, 3 = Displacement // - Checks !AI_GetAIHaveEffect(GlobalEffectInvisible, oTarget) && !AI_GetAIHaveSpellsEffect(GlobalHasConsealmentSpells, oTarget) -int AI_SpellWrapperConsealmentEnhancements(object oTarget, int iLowest = 1); +int AI_SpellWrapperConsealmentEnhancements(object oTarget, int nLowest = 1); // Shades darkness, assassin feat, normal spell. int AI_SpellWrapperDarknessSpells(object oTarget); // Invisibility spells + feats @@ -522,7 +484,9 @@ int AI_SpellWrapperNormalInvisibilitySpells(); //*************************** AttemptHealing *********************************** // If our current HP is under the percent given, it will check things to heal itself, and use them. // Used for animals ETC as well. They just don't use potions. -// This will also check levels, for appropriate healing. Set iMyHD to higher to use lower level spells. +// This will also check levels, for appropriate healing. +// Set nMyHD to higher to use lower level spells. +// * Will un-polymorph if we are heavily damaged and can heal ourselves. int AI_AttemptHealingSelf(); // Raises dead, and casts healing spells to heal allies. // Leaders are checked first. @@ -532,7 +496,9 @@ int AI_AttemptHealingAlly(); // - Just does best spell. // - May use spontaneous ones as well. :-) // - Called from AI_AttemptHealing_Self and AI_AttemptHealing_Ally -int AI_ActionHealObject(object oTarget); +// * bPotionsValid is only used if oTarget is OBJECT_SELF, IE: We put it in, so +// not to use potions as an invalid race. if oTarget != OBJECT_SELF, it is ignored +int AI_ActionHealObject(object oTarget, int bPotionsValid = FALSE); // Heals oTarget using undead negative energy type spells // More basic then the normal healing routines. // TRUE if it casts anything. @@ -548,16 +514,15 @@ int AI_AttemptCureCondition(); // - Then checks leader // - Then loops seen allies within 20M. // See: AI_AttemptCureCondition -object AI_GetNearestAllyWithEffect(int iEffectHex); -// Returns the nearest ally with iMin effects, and X more based on HD. -// - Checks us first. True if (HD/6) Effects and (iMin - 1) effects -// - Checks leader next. True if (HD/5) Effects and (iMin - 2) effects -// - Checks allies after. True if (HD/4) Effects and (iMin) effects -object AI_GetNearestAllyWithRestoreEffects(int iMin); +object AI_GetNearestAllyWithEffect(int nEffectHex); +// Returns the nearest ally with nMin effects, and X more based on HD. +// - Checks us first. True if (HD/6) Effects and (nMin - 1) effects +// - Checks leader next. True if (HD/5) Effects and (nMin - 2) effects +// - Checks allies after. True if (HD/4) Effects and (nMin) effects +object AI_GetNearestAllyWithRestoreEffects(int nMin); // This will return the best spontaeous healing spell, so: -// - It uses just normal GetHasSpell for the clerical healing spells. -// - It gets set up at the start to the global "GlobalBestSpontaeousHealingSpell" +// * It uses just normal GetHasSpell for the clerical healing spells. int AI_GetBestSpontaeousHealingSpell(); //*************************** AttemptHealing *********************************** @@ -573,82 +538,75 @@ int AI_GetBestSpontaeousHealingSpell(); // uses the item, if it is an equal talent. // - Will call a Shile Equip // Returns TRUE if we did find the right talent, and it was cast. -int AI_ActionCastItemEqualTo(object oTarget, int iSpellID, int iLocation); +int AI_ActionCastItemEqualTo(object oTarget, int nSpellID, int bLocation); // This attempts to check the talent TALENT_CATEGORY_HARMFUL_RANGED, 2, which // holds grenades. Easy checks. // - TRUE if they fire a grenade. int AI_AttemptGrenadeThrowing(object oTarget); // This will cast the spell of ID in this order [Note: Always adds to time stop, as it will be on self, and benifical): -// 1. If they have the spell normally -// 2. If they have an item with the spell. -// 3. If they have a potion of the right type. -// - We always attack with a bow at ranged, but may attack normally after the spell. -// - If nTalent is 0, we do not cast it unless iRequirement is also 0. -// - If iRequirement is 0, it is considered innate. -// - Imput iItemTalentValue and iPotionTalentValue to check item talents. -1 == No item. -int AI_ActionCastSpell(int iSpellID, int nTalent = 0, object oTarget = OBJECT_SELF, int iRequirement = 0, int iLocation = FALSE, int iItemTalentValue = -1, int iPotionTalentValue = -1); +// 1. If they have the spell normally. +// * We always attack with a bow at ranged, but may attack normally after the spell. +// * If nRequirement is 0, it is considered innate. +// * If bSubspell is TRUE, we will cheat-cast and derement it. +int AI_ActionCastSpell(int nSpellID, object oTarget = OBJECT_SELF, int nRequirement = 0, int bLocation = FALSE, int bSubSpell = FALSE); // This is used for INFLICT/CURE spells, as GetHasSpell also can return 1+ for // any extra castings - like if we had 2 light wounds and 2 blesses, it'd return // 4. // This, when cast, removes one of the spell being cast, after cheat casting it. // - DecrementRemainingSpells will work this way quite well, but no choice in // what to remove, it is faster then 1.3 beta which modified the spell scripts. -int AI_ActionCastSpontaeousSpell(int iSpellID, int nTalent, object oTarget); -// This will cast the shadow conjuration/protection version of the spell, -// via. Cheat Casting, and Decrement Spell Uses. -// - We always attack with a bow at ranged, but may attack normally after the spell. -// - If nTalent is 0, we do not cast it unless iRequirement is also 0. -// - If iRequirement is 0, it is considered innate. -// - Imput iItemTalentValue to check item talents. -int AI_ActionCastSubSpell(int iSubSpell, int nTalent = 0, object oTarget = OBJECT_SELF, int iRequirement = 0, int iLocation = FALSE, int iItemTalentValue = -1, int iPotionTalentValue = -1); +int AI_ActionCastSpontaeousSpell(int nSpellID, object oTarget); // This will cast the spell of ID in this order [Note: Always adds to time stop, as it will be on self, and benifical): -// 0. If d100() is <= iRandom. +// 0. If d100() is <= nRandom. // 1. If they have the spell normally // 2. If they have an item with the spell. // 3. If they have a potion of the right type. // - If we are at range from nearest enemy, we attack with a ranged weapon, else do nothing more. // - If nTalent is -1, we do not check items. -// - Sets GlobalLastSpellValid to iSpellID if we can cast it, but don't randomly. -int AI_ActionCastSpellRandom(int iSpellID, int nTalent, int iRandom, object oTarget = OBJECT_SELF, int iRequirement = 0, int iLocation = FALSE, int iItemTalentValue = -1, int iPotionTalentValue = -1); -// This will cast the spell/feat iThing, depending if it is a spell or a feat, +// - Sets GlobalLastSpellValid to nSpellID if we can cast it, but don't randomly. +int AI_ActionCastSpellRandom(int nSpellID, int nRandom, object oTarget = OBJECT_SELF, int nRequirement = 0, int bLocation = FALSE); +// This will cast the spell/feat nSpellId (Or with nFeat), depending if it is a spell or a feat, // at the summon location chosen before. Works similar to normal spells but // at a special location. -// * If iRequirement is -1, it is a feat. If 0, it is innate (as spells) -int AI_ActionCastSummonSpell(int iThingID, int iRequirement = 0, int iSummonLevel = 0); -// This willcast iFirst -> iFirst + iAmount polymorph spell. It will check -// if we have iMaster (Either by feat or spell, depending on iFeat). +// * If it is a feat, we use nFeat to define the feat, and nSpellId to define the +// spellability to use. +// * If nRequirement is -1, it is a feat. If 0, it is innate (as spells) +int AI_ActionCastSummonSpell(int nSpellId, int nRequirement = 0, int nSummonLevel = 0, int nFeat = 0); +// This willcast nFirst -> nFirst + nAmount polymorph spell. It will check +// if we have nMaster (Either by feat or spell, depending on bFeat). // TRUE if we polymorph. -// * Only decrements if iRemove is TRUE -int AI_ActionPolymorph(int iMaster, int iFirstSpell, int iAmount, int iFeat = FALSE, int iRemove = TRUE); +// * Only decrements if bRemove is TRUE +int AI_ActionPolymorph(int nMaster, int nFirstSpell, int nAmount, int bFeat = FALSE, int bRemove = TRUE); // Used with GlobalLastSpellValid. If GlobalLastSpellValid is 0, sets locals for // use later, and sets GlobalLastSpellValid to the spell in question. -void AI_SetBackupCastingSpellValues(int iSpellID, int nTalent, object oTarget, int iLocation, int iRequirement, int iItemTalentValue, int iPotionTalentValue); +void AI_SetBackupCastingSpellValues(int nSpellID, object oTarget, int bLocation, int nRequirement); // This will used a stored GlobalLastSpellValid to see if it should cast that // spell (or attempt to!) as a backup. Uses stored targets from when it did know // it was valid. int AI_ActionCastBackupRandomSpell(); -// If they have the feat, they will use it on the target, and return TRUE -// * iFeat - Feat ID to use -// * oObject - object to use it on (Can't target locations in the AI - not worth it) -int AI_ActionUseFeatOnObject(int iFeat, object oObject = OBJECT_SELF); // If they have nFeat, they cheat-cast nSpell at oTarget. -// - This is a workaround, as some epic spells, for some reason, won't work with -// a standard ActionUseFeatOnObject()! Dammit. Beta 3 addition. -int AI_ActionUseEpicSpell(int nFeat, int nSpell, object oTarget = OBJECT_SELF); +// - This is a workaround for any feat, which acts as a spell, IE: A spell like feat, +// (a feat with casting times and so on) and more importantly, also will cast +// the nSpell if they have it anyway! so is useful for any feat.2da which +// references the spells.2da for its effects. +// 1.4: Added the fact they can be normal spells. +int AI_ActionUseSpellLikeFeat(int nFeat, int nSpell, object oTarget = OBJECT_SELF); // Wrappers action Use Talent with debug string +// * Used in healing, to cast "Heal" range before other healing spells. +// Might well remove! void AI_ActionUseTalentDebug(talent tChosenTalent, object oTarget); // Wrapper to check all dragon breaths, against oTarget -int AI_ActionDragonBreath(object oTarget, int iWingCounter); +int AI_ActionDragonBreath(object oTarget, int nWingCounter); // Uses tBreath if they are not immune // - TRUE if used. -int AI_ActionUseBreath(object oTarget, talent tBreath, int iSpellID); +int AI_ActionUseBreath(object oTarget, talent tBreath, int nSpellID); +// This tests breath attacks or the use of the Wing Buffet, randomised each round +// and not used constantly. +// * oTarget - target to breath on (ouch, bad breath!) +int AI_DragonBreathOrWing(object oTarget); -// Special: Apply Item Start -void AI_SpecialActionApplyItem(); -// Special: Remove the effect (immobilize) -void AI_SpecialActionRemoveItem(); // Only TRUE if we have a flee object. // - Uses sArray to debug and speak int AI_ActionFlee(string sArray); @@ -658,17 +616,12 @@ int AI_ActionFlee(string sArray); //@@@@@@@@@@@@@@@@@ ALL INFO FUNCTIONS @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -// Gets a item talent value, applies EffectCutsceneImmobilize then removes it. -// - iTalent, 1-21. -void AI_SetItemTalentValue(int iTalent); -// This checks if nTalent is one that will be checked for by items. -int AI_GetSpellCategoryHasItem(int nTalent); - // Equips the best shield we have. // - Used before we cast a spell so casters can gain maximum AC. void AI_EquipBestShield(); -// Turns on/off all melee things (not stealth or search!) but not iMode. -void AI_SetMeleeMode(int iMode = -1); +// Turns on/off all melee things (not stealth or search!) but not nMode. +// * Use ACTION_MODE_ALL_OFF if you want all things off. +void AI_SetMeleeMode(int nMode = ACTION_MODE_ALL_OFF); // GETTING ENEMY INFO @@ -677,7 +630,7 @@ void AI_SetMeleeMode(int iMode = -1); // - Uses oIntruder (to attack or move near) if anything. // - We return TRUE if it ActionAttack's, or moves to an enemy - basically // that we cannot do an action, but shouldn't search. False if normal. -int AI_SetUpAllObjects(object oImputBackup); +int AI_SetUpAllObjects(object oInputBackup); // This sets up US, the user! :-) // - Determines class to use, dragon or not. // - And some other things that don't need to check allies/enemies for. @@ -687,23 +640,28 @@ void AI_SetUpUs(); void AI_SetUpUsEffects(); // Using the array ARRAY_ENEMY_RANGE, we return a % of seen/heard people who // DO have any of the spells which see through the invisiblity spells. -// * iLimit - when we get to this number of people who have invisiblity, we stop and return 100% +// * nLimit - when we get to this number of people who have invisiblity, we stop and return 100% // If ANY of the people are attacking us and have the effect, we return +30% for each. -int AI_GetSpellWhoCanSeeInvis(int iLimit); +int AI_GetSpellWhoCanSeeInvis(int nLimit); // Returns the object to the specifications: // * fRange - Within fRange (fTouchRange 2.25, fShortRange 8.0, fMediumRange 20.0, fLongRange = 40.0) // * fSpread - Radius Size - RADIUS_SIZE_* constants (1.67 to 10.0M) // * nLevel - Used for saving throws/globe checks. Level of the spell added to save checks -// * iSaveType = FALSE - SAVING_THROW_FORT/REFLEX/WILL. Not type, but the main save applied with it. +// * nSaveType = FALSE - SAVING_THROW_FORT/REFLEX/WILL. Not type, but the main save applied with it. // * nShape = SHAPE_SPHERE - SHAPE_* constants. -// * nFriendlyFire = FALSE - Can this hurt allies? Best thing is to put +// * bFriendlyFire = FALSE - Can this hurt allies? Best thing is to put // GlobalFriendlyFireHostile - GetIsReactionTypeHostile(oTarget) == TRUE // GlobalFriendlyFireFriendly - GetIsReactionTypeFriendly(oTarget) == FALSE // FALSE - Cannot hurt allies (GetIsEnemy/!GetIsFriend used) -// * iDeathImmune = FALSE - Does it use a death save? (!GetIsImmune) -// * iNecromanticSpell = FALSE - Is it a necromancy spell? Undead are also checked in this. -object AI_GetBestAreaSpellTarget(float fRange, float fSpread, int nLevel, int iSaveType = FALSE, int nShape = SHAPE_SPHERE, int nFriendlyFire = FALSE, int iDeathImmune = FALSE, int iNecromanticSpell = FALSE); +// * bDeathImmune = FALSE - Does it use a death save? (!GetIsImmune) +// * bNecromanticSpell = FALSE - Is it a necromancy spell? Undead are also checked in this. +object AI_GetBestAreaSpellTarget(float fRange, float fSpread, int nLevel, int nSaveType = FALSE, int nShape = SHAPE_SPHERE, int bFriendlyFire = FALSE, int bDeathImmune = FALSE, int bNecromanticSpell = FALSE); + +// Gets an approprate summoning location. If we are set to summon better, we +// should get a good location between us and an enemy, else, it'll just return +// our location. +location AI_GetSummonLocation(); // Returns the object to the specifications: // Within nRange (float) @@ -716,35 +674,41 @@ int AI_GetWeaponSize(object oItem); // This returns TRUE if the target will always resist the spell given the parameters. // - Uses GlobalOurChosenClassLevel for our level check. int AI_SpellResistanceImmune(object oTarget); -// If the target will always save against iSaveType, and will take no damage, returns TRUE +// If the target will always save against nSaveType, and will take no damage, returns TRUE // * Target is GlobalSpellTarget. Save is GlobalSpellTargetWill ETC. -// * iSaveType - SAVING_THROW WILL/REFLEX/FORTITUDE -// * iSpellLevel - Level of the spell being cast. -int AI_SaveImmuneSpellTarget(int iSaveType, int iSpellLevel); -// If the target will always save against iSaveType, and will take no damage, returns TRUE +// * nSaveType - SAVING_THROW WILL/REFLEX/FORTITUDE +// * nSpellLevel - Level of the spell being cast. +int AI_SaveImmuneSpellTarget(int nSaveType, int nSpellLevel); +// If the target will always save against nSaveType, and will take no damage, returns TRUE // * oTarget - who saving against spell. -// * iSaveType - SAVING_THROW WILL/REFLEX/FORTITUDE +// * nSaveType - SAVING_THROW WILL/REFLEX/FORTITUDE // * The save used is GetReflexSavingThrow* ETC. -// * iSpellLevel - Level of the spell being cast. -int AI_SaveImmuneAOE(object oTarget, int iSaveType, int iSpellLevel); -// Gets the percent, of X vs Y, iNumber/iTotal * 100 = %. -int AI_GetPercentOf(int iNumber, int iTotal); +// * nSpellLevel - Level of the spell being cast. +int AI_SaveImmuneAOE(object oTarget, int nSaveType, int nSpellLevel); +// Gets the percent, of X vs Y, nNumber/nTotal * 100 = %. +int AI_GetPercentOf(int nNumber, int nTotal); // This returns a number, 1-4. This number is the levels // of spell they will be totally immune to. int AI_GetSpellLevelEffect(object oTarget); -// Imput oTarget and iLevel and it will check if they are automatically +// Input oTarget and nLevel and it will check if they are automatically // immune to the spell being cast. -int AI_GetSpellLevelEffectAOE(object oTarget, int iLevel = 9); +int AI_GetSpellLevelEffectAOE(object oTarget, int nLevel = 9); // Returns TRUE if any of the checks the oGroupTarget is immune to. -int AI_AOEDeathNecroCheck(object oGroupTarget, int iNecromanticSpell, int iDeathImmune); -// This will do 1 of two things, with the spell ID -// 1. If iHealAmount is FALSE, it will return what number (rank) in order, which is also used for level checking -// 2. If TRUE, it will return the average damage it will heal. -// iSelf - Used for the odd spells "cure other"'s -int AI_ReturnHealingInfo(int iSpellID, int iSelf = FALSE, int iHealAmount = FALSE); +int AI_AOEDeathNecroCheck(object oGroupTarget, int bNecromanticSpell, int bDeathImmune); +// Returns the healing "Rank" of nSpellId (made up by me) which the spell is. +// Used in healing, Heal (+Mass Heal) is done seperatly in the healing routines. +// * Returns a default of 0 if no valid healing spell is found (Or was a Heal spell) +// * Use bSelf to be TRUE if you want to include "Cure Other" spells in Hordes +int AI_GetHealingSpellRank(int nSpellId, int bSelf = FALSE); +// This will return the average amount healed by nSpellId, determined as if they +// were the minimum level used to cast it, and average rolls were performed. +// * Used in healing to check if we should bother using the spell yet, eg: +// a 50HP person with a ciritical wounds potion might take it at 10HP, not 25HP, +// because it heals a lot. +int AI_GetHealingSpellPower(int nSpellId); // TRUE if the spell is one recorded as being cast before in time stop. // - Checks Global "Are we in time stop?" and returns FALSE if not in time stop -int AI_CompareTimeStopStored(int nSpell, int nSpell2 = 0, int nSpell3 = 0, int nSpell4 = 0); +int AI_CompareTimeStopStored(int nSpell1, int nSpell2 = AI_SPELL_INVALID, int nSpell3 = AI_SPELL_INVALID, int nSpell4 = AI_SPELL_INVALID); // Sets the spell to be stored in our time stop array. void AI_SetTimeStopStored(int nSpell); // Deletes all time stopped stored numbers. @@ -766,52 +730,50 @@ int AI_StopWhatWeAreDoing(); void AI_ActionTurnOffHiding(); // Simple return TRUE if it matches hex GlobalTargetImmunitiesHex -int AI_GetSpellTargetImmunity(int iImmunityHex); -// Sets iImmunityHex to GlobalTargetImmunitiesHex. -void AI_SetSpellTargetImmunity(int iImmunityHex); +int AI_GetSpellTargetImmunity(int nImmunityHex); +// Sets nImmunityHex to GlobalTargetImmunitiesHex. +void AI_SetSpellTargetImmunity(int nImmunityHex); // This returns an object, not seen not heard ally, who we // might flee to. Uses a loop, and runs only when we are going to flee for sure. object AI_GetNearbyFleeObject(); // This returns the best primary or secondary weapon from sArray. // It actually returns the number value, IE the place it is at. Easy to get all info from there. -// - Use iType... +// - Use nType... // - 0 = Highest Value :-) // - 1 = Highest Damage // - 2 = Biggest // - 3 = Smallest -int AI_GetWeaponArray(string sArray, object oCannotBe = OBJECT_INVALID, int iType = 0); +int AI_GetWeaponArray(string sArray, object oCannotBe = OBJECT_INVALID, int nType = 0); // Just sorts out sOriginalArrayName to sNewArrayName based on range only. // - Also sets maxint to MAXINT_ + sNewArrayName // - Closest to futhest void AI_TargetingArrayDistanceStore(string sOriginalArrayName, string sNewArrayName); -// Just sorts out sOriginalArrayName to sNewArrayName based on iType. -// iType 1 = AC, iType 2 = Total Saves, iType 3 = Phisical Protections, -// iType 4 = BAB, iType 5 = Hit Dice, iType 6 = Percent HP, iType 7 = Current HP, -// iType 8 = Maximum HP. 9 = Attacking us or not. 10 = Is a PC. -void AI_TargetingArrayIntegerStore(int iType, string sOriginalArrayName); +// Just sorts out sOriginalArrayName to sNewArrayName based on nType. +// nType 1 = AC, nType 2 = Total Saves, nType 3 = Phisical Protections, +// nType 4 = BAB, nType 5 = Hit Dice, nType 6 = Percent HP, nType 7 = Current HP, +// nType 8 = Maximum HP. 9 = Attacking us or not. 10 = Is a PC. +void AI_TargetingArrayIntegerStore(int nType, string sOriginalArrayName); // This sets ARRAY_TEMP_ARRAY of integer values to sNewArrayName. -// - iTypeOfTarget, used TARGET_LOWER, TARGET_HIGHER. -// - We work until iMinimum is filled, or we get to iMinimum and we get to -// a target with value > iImputMinimum. (20 - 25 > X?) +// - nTypeOfTarget, used TARGET_LOWER, TARGET_HIGHER. +// - We work until nMinimum is filled, or we get to nMinimum and we get to +// a target with value > iInputMinimum. (20 - 25 > X?) // Returns the amount of targets set in sNewArrayName. -int AI_TargetingArrayLimitTargets(string sNewArrayName, int iTypeOfTarget, int iImputMinLimit, int iMinLoop, int iMaxLoop); +int AI_TargetingArrayLimitTargets(string sNewArrayName, int nTypeOfTarget, int iInputMinLimit, int nMinLoop, int nMaxLoop); // This sets ARRAY_TEMP_ARRAY of float values to sNewArrayName. -// - iTypeOfTarget, used TARGET_LOWER, TARGET_HIGHER. -// - We work until iMinimum is filled, or we get to iMinimum and we get to -// a target with value > iImputMinimum. (20.0 - 25.0 > X?) +// - nTypeOfTarget, used TARGET_LOWER, TARGET_HIGHER. +// - We work until nMinimum is filled, or we get to nMinimum and we get to +// a target with value > iInputMinimum. (20.0 - 25.0 > X?) // Returns the amount of targets set in sNewArrayName. -int AI_TargetingArrayLimitTargetsFloat(string sNewArrayName, int iTypeOfTarget, float fImputMinLimit, int iMinLoop, int iMaxLoop); +int AI_TargetingArrayLimitTargetsFloat(string sNewArrayName, int nTypeOfTarget, float fInputMinLimit, int nMinLoop, int nMaxLoop); // Deletes all FLoats, Integers and Objects set to sArray for valid // objects got by GetLocalObject to sArray. void AI_TargetingArrayDelete(string sArray); -// Makes sure oTarget isn't: -// - Dead -// - Petrified -// - AI Ignore ON -// - DM -// Must be: Seen or heard -// Returns: TRUE if any of these are true. +// Check if oTarget is: +// - Dead, Petrified, AI Ignore ON, A DM, Invalid +// - Not: Seen or heard (IE: We cannot see or hear them) +// Returns: TRUE if it is SANE to attack oTarget +// Returns: FALSE if oTarget is currently ethereal. That is handled in a seperate place. int AI_GetTargetSanityCheck(object oTarget); /*:://///////////////////////////////////////////// @@ -822,14 +784,14 @@ int AI_GetTargetSanityCheck(object oTarget); // Simple return TRUE if it matches hex. // - Uses GlobalSpellTarget for target object -int AI_GetSpellTargetImmunity(int iImmunityHex) +int AI_GetSpellTargetImmunity(int nImmunityHex) { - return (GlobalTargetImmunitiesHex & iImmunityHex); + return (GlobalTargetImmunitiesHex & nImmunityHex); } -// Sets iImmunityHex to GlobalTargetImmunitiesHex. -void AI_SetSpellTargetImmunity(int iImmunityHex) +// Sets nImmunityHex to GlobalTargetImmunitiesHex. +void AI_SetSpellTargetImmunity(int nImmunityHex) { - GlobalTargetImmunitiesHex = GlobalTargetImmunitiesHex | iImmunityHex; + GlobalTargetImmunitiesHex = GlobalTargetImmunitiesHex | nImmunityHex; } /*:://///////////////////////////////////////////// //:: Name: AI_SetUpUsEffects @@ -839,60 +801,15 @@ void AI_SetSpellTargetImmunity(int iImmunityHex) //:://///////////////////////////////////////////*/ void AI_SetUpUsEffects() { - // SetLocal to stop other AI casters ETC from setting effect - SetLocalInt(OBJECT_SELF, AI_JASPERRES_EFFECT_SET, TRUE); // Set locals and whatever on self. AI_SetEffectsOnTarget(); // Set global time stop GlobalInTimeStop = AI_GetAIHaveEffect(GlobalEffectTimestop); } -// Gets the percent, of X vs Y, iNumber/iTotal * 100 = %. -int AI_GetPercentOf(int iNumber, int iTotal) +// Gets the percent, of X vs Y, nNumber/nTotal * 100 = %. +int AI_GetPercentOf(int nNumber, int nTotal) { - return FloatToInt((IntToFloat(iNumber)/IntToFloat(iTotal)) * i100); -} -// Special: Apply EffectCutsceneImmobilize -void AI_SpecialActionApplyItem() -{ - ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectCutsceneImmobilize(), OBJECT_SELF); -} -// Special: Remove EffectCutsceneImmobilize -void AI_SpecialActionRemoveItem() -{ - effect eCheck = GetFirstEffect(OBJECT_SELF); - while(GetIsEffectValid(eCheck)) - { - if(GetEffectType(eCheck) == EFFECT_TYPE_CUTSCENEIMMOBILIZE && - GetEffectSpellId(eCheck) == iM1) RemoveEffect(OBJECT_SELF, eCheck); - eCheck = GetNextEffect(OBJECT_SELF); - } -} -// Gets a item talent value, applies EffectCutsceneImmobilize then removes it. -// - iTalent, 1-21. -void AI_SetItemTalentValue(int iTalent) -{ - // Apply EffectCutsceneImmobilize - AI_SpecialActionApplyItem(); - - // Simply get the best. - talent tCheck = GetCreatureTalentBest(iTalent, i20); - int iValue = GetIdFromTalent(tCheck); - - // Set to constant - SetAIConstant(ITEM_TALENT_VALUE + IntToString(iTalent), iValue); - - // Remove EffectCutsceneImmobilize - AI_SpecialActionRemoveItem(); -} -// This checks if nTalent is one that will be checked for by items. -int AI_GetSpellCategoryHasItem(int nTalent) -{ - // 1, 2, 3, - , 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 - if(nTalent == i4 || nTalent == i5 || nTalent >= i16 || nTalent < i1) - { - return FALSE; - } - return TRUE; + return FloatToInt((IntToFloat(nNumber)/IntToFloat(nTotal)) * 100); } /*:://///////////////////////////////////////////// //:: Name: AI_SetTimeStopStored @@ -903,13 +820,13 @@ void AI_SetTimeStopStored(int nSpell) { // Time stop check if(!GlobalInTimeStop) return; - if(GlobalTimeStopArraySize < i0) + if(GlobalTimeStopArraySize < 0) { - GlobalTimeStopArraySize = i1;// Size is now 1 - SetAIConstant(TIME_STOP_LAST_ + IntToString(i1), nSpell); + GlobalTimeStopArraySize = 1;// Size is now 1 + SetAIConstant(TIME_STOP_LAST_ + IntToString(1), nSpell); SetAIInteger(TIME_STOP_LAST_ARRAY_SIZE, GlobalTimeStopArraySize); } - else if(GlobalTimeStopArraySize == i0) + else if(GlobalTimeStopArraySize == 0) { GlobalTimeStopArraySize = GetAIInteger(TIME_STOP_LAST_ARRAY_SIZE); GlobalTimeStopArraySize++; @@ -933,14 +850,14 @@ void AI_DeleteTimeStopStored() GlobalTimeStopArraySize = GetAIInteger(TIME_STOP_LAST_ARRAY_SIZE); if(GlobalTimeStopArraySize) { - int iCnt; - for(iCnt = i1; iCnt <= GlobalTimeStopArraySize; iCnt++) + int nCnt; + for(nCnt = 1; nCnt <= GlobalTimeStopArraySize; nCnt++) { - DeleteAIConstant(TIME_STOP_LAST_ + IntToString(iCnt)); + DeleteAIConstant(TIME_STOP_LAST_ + IntToString(nCnt)); } } DeleteAIInteger(TIME_STOP_LAST_ARRAY_SIZE); - GlobalTimeStopArraySize = iM1; + GlobalTimeStopArraySize = -1; } /*:://///////////////////////////////////////////// //:: Name: GetWeaponSize @@ -952,7 +869,8 @@ int AI_GetWeaponSize(object oItem) // Ignore invalid weapons if(!GetIsObjectValid(oItem)) return FALSE; - // Returns shields as 0 + // Returns shields as 0, the default return value of weapons not found in + // this. switch(GetBaseItemType(oItem)) { // Tiny @@ -960,14 +878,13 @@ int AI_GetWeaponSize(object oItem) case BASE_ITEM_DAGGER: case BASE_ITEM_KUKRI: case BASE_ITEM_SHURIKEN: - return i1;// WEAPON_SIZE_TINY + return 1;// WEAPON_SIZE_TINY break; // Small // 0, 7, 9, 14, 31, 37, 38, 40, 60, 61, 63 case BASE_ITEM_SHORTSWORD: case BASE_ITEM_LIGHTCROSSBOW: case BASE_ITEM_LIGHTMACE: -// case BASE_ITEM_SMALLSHIELD: case BASE_ITEM_DART: case BASE_ITEM_LIGHTHAMMER: case BASE_ITEM_HANDAXE: @@ -976,13 +893,10 @@ int AI_GetWeaponSize(object oItem) case BASE_ITEM_SLING: case BASE_ITEM_THROWINGAXE: case BASE_ITEM_WHIP: // Hordes - return i2;// WEAPON_SIZE_SMALL + return 2;// WEAPON_SIZE_SMALL break; // Medium // 1, 2, 3, 4, 5, 6, 11, 28, 41, 47, 51, 53, 56 - // 1-6 = - // BASE_ITEM_LONGSWORD, BASE_ITEM_BATTLEAXE, BASE_ITEM_BASTARDSWORD - // BASE_ITEM_LIGHTFLAIL, BASE_ITEM_WARHAMMER, BASE_ITEM_HEAVYCROSSBOW case BASE_ITEM_LONGSWORD: case BASE_ITEM_BATTLEAXE: case BASE_ITEM_BASTARDSWORD: @@ -995,9 +909,8 @@ int AI_GetWeaponSize(object oItem) case BASE_ITEM_MORNINGSTAR: case BASE_ITEM_RAPIER: case BASE_ITEM_SCIMITAR: -// case BASE_ITEM_LARGESHIELD: case BASE_ITEM_DWARVENWARAXE: // Hordes - return i3;// WEAPON_SIZE_MEDIUM; + return 3;// WEAPON_SIZE_MEDIUM; break; // Large weapons // 8, 10, 12, 13, 18, 32, 33, 35, 45, 50, 55, 57, 58 @@ -1012,9 +925,8 @@ int AI_GetWeaponSize(object oItem) case BASE_ITEM_MAGICSTAFF: case BASE_ITEM_QUARTERSTAFF: case BASE_ITEM_SCYTHE: -// case BASE_ITEM_TOWERSHIELD: case BASE_ITEM_SHORTSPEAR: - return i4;// WEAPON_SIZE_LARGE; + return 4;// WEAPON_SIZE_LARGE; break; } return FALSE; @@ -1024,7 +936,7 @@ int AI_GetWeaponSize(object oItem) //:://///////////////////////////////////////////// This returns the best primary or secondary weapon from sArray. It actually returns the number value, IE the place it is at. Easy to get all info from there. - - Use iType... + - Use nType... - 0 = Highest Value :-) - 1 = Highest Damage - 2 = Biggest @@ -1032,98 +944,108 @@ int AI_GetWeaponSize(object oItem) //:://///////////////////////////////////////////// //:: Created By: Jasperre //:://///////////////////////////////////////////*/ -int AI_GetWeaponArray(string sArray, object oCannotBe = OBJECT_INVALID, int iType = 0) +int AI_GetWeaponArray(string sArray, object oCannotBe = OBJECT_INVALID, int nType = 0) { - int iMax = GetLocalInt(OBJECT_SELF, MAXINT_ + sArray); - int i, iReturn, iLastValue, iCurrentValue; + int nMax = GetLocalInt(OBJECT_SELF, MAXINT_ + sArray); + int nCnt, nReturn, nLastValue, nCurrentValue; string sCurrentName; object oCurrentWeapon; - if(iMax) + if(nMax) { - for(i = i1; i <= iMax; i++) // uses: "break;" to break early. + for(nCnt = 1; nCnt <= nMax; nCnt++) // uses: "break;" to break early. { - sCurrentName = sArray + IntToString(i); + sCurrentName = sArray + IntToString(nCnt); oCurrentWeapon = GetLocalObject(OBJECT_SELF, sCurrentName);// Object if(GetIsObjectValid(oCurrentWeapon) && oCurrentWeapon != oCannotBe) { - // Highest value - if(iType == i0) + // Highest value (But cannot be oCannotBe of course) + if(nType == 0) { - iReturn = i;// It is highest to lowest value anyway + nReturn = nCnt;// It is highest to lowest value anyway break; } // 1 = Highest Damage - else if(iType == i1) + else if(nType == 1) { - iCurrentValue = GetLocalInt(OBJECT_SELF, sCurrentName + WEAP_DAMAGE); + // Get the current item value - the damage done by a weapon + nCurrentValue = GetLocalInt(OBJECT_SELF, sCurrentName + WEAP_DAMAGE); // > because if only equal, one was higher value - if(iCurrentValue > iLastValue) + if(nCurrentValue > nLastValue) { - iLastValue = iCurrentValue; - iReturn = i; + nLastValue = nCurrentValue; + nReturn = nCnt; } } // 2 = Biggest // 3 = Smallest else { - iCurrentValue = GetLocalInt(OBJECT_SELF, sCurrentName + WEAP_SIZE); - if(iType == i2) + // Get the current item value - that is, the size value + nCurrentValue = GetLocalInt(OBJECT_SELF, sCurrentName + WEAP_SIZE); + // Biggest weapon first (Primary weapon usually) + if(nType == 2) { - if(iCurrentValue > iLastValue)// > because if only equal, one was higher value + if(nCurrentValue > nLastValue)// > because if only equal, one was higher value { - iLastValue = iCurrentValue; - iReturn = i; + nLastValue = nCurrentValue; + nReturn = nCnt; } } - else // if(iType == i3) + // Smallest weapon first (Off-hand weapon ususally) + else // if(nType == 3) { - if(iCurrentValue < iLastValue)// > because if only equal, one was higher value + if(nCurrentValue < nLastValue)// > because if only equal, one was higher value { - iLastValue = iCurrentValue; - iReturn = i; + nLastValue = nCurrentValue; + nReturn = nCnt; } } } } } } - return iReturn; + return nReturn; } // Equips the best shield we have. // - Used before we cast a spell so casters can gain maximum AC. void AI_EquipBestShield() { + // Get the shield to use/equip (we might have it equipped already) object oShield = GetAIObject(AI_WEAPON_SHIELD); + // Test for equipping - we check if it is valid, if we have it, and if + // it is even equipped already, of course. This is only called just before + // an action - might add in a "reset shield" if it is invalid or lost + // from us, somehow. if(GetIsObjectValid(oShield) && GetItemPossessor(oShield) == OBJECT_SELF && - GlobalLeftHandWeapon != oShield) + GetItemInSlot(INVENTORY_SLOT_LEFTHAND) != oShield) { + // Equip it. No need for anything else. Lefthand == Offhand (or Shield hand) ActionEquipItem(oShield, INVENTORY_SLOT_LEFTHAND); } } -// Turns on/off all melee things (not stealth or search!) but not iMode. -void AI_SetMeleeMode(int iMode = -1) +// Turns on/off all melee things (not stealth or search!) but not nMode. +void AI_SetMeleeMode(int nMode = ACTION_MODE_ALL_OFF) { - if(iMode != iM1) + if(nMode != ACTION_MODE_ALL_OFF) { - if(!GetActionMode(OBJECT_SELF, iMode)) + if(!GetActionMode(OBJECT_SELF, nMode)) { - SetActionMode(OBJECT_SELF, iMode, TRUE); + SetActionMode(OBJECT_SELF, nMode, TRUE); } } // Turn off all the rest - int iCnt; - // 0 = stealth, 1 = stealth (ignore these 2), 3 = parry. 11 = DF. - for(iCnt = ACTION_MODE_PARRY; iCnt <= ACTION_MODE_DIRTY_FIGHTING; iCnt++) + int nCnt; + // 0 = stealth, 1 = search (ignore these 2), 3 = parry. 11 = DF. + for(nCnt = ACTION_MODE_PARRY; nCnt <= ACTION_MODE_DIRTY_FIGHTING; nCnt++) { - if(iCnt != iMode) + if(nCnt != nMode) { - if(GetActionMode(OBJECT_SELF, iCnt)) + if(GetActionMode(OBJECT_SELF, nCnt)) { - SetActionMode(OBJECT_SELF, iCnt, FALSE); + SetActionMode(OBJECT_SELF, nCnt, FALSE); } } } @@ -1135,14 +1057,16 @@ void AI_SetMeleeMode(int iMode = -1) // we need to move. void AI_ActionTurnOffHiding() { + // 1.4: Changed both the checks to use GetActionMode. Looks cleaner. // Turn of searching and hiding here, if we want to! - if(!GetHasFeat(FEAT_KEEN_SENSE) && GetDetectMode(OBJECT_SELF) == DETECT_MODE_ACTIVE) + if(!GetHasFeat(FEAT_KEEN_SENSE) && + !GetActionMode(OBJECT_SELF, ACTION_MODE_DETECT)) { SetActionMode(OBJECT_SELF, ACTION_MODE_DETECT, FALSE); } // Turn of hiding if we have been seen lately. if(GetLocalTimer(AI_TIMER_TURN_OFF_HIDE) && - GetStealthMode(OBJECT_SELF) == STEALTH_MODE_ACTIVATED) + !GetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH)) { SetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH, FALSE); } @@ -1161,16 +1085,17 @@ void AI_ActionTurnOffHiding() int AI_EquipAndAttack() { // Taunt the enemy! + // 5% chance each round. A d20 roll of 1. if(!GetSpawnInCondition(AI_FLAG_OTHER_NO_PLAYING_VOICE_CHAT, AI_OTHER_MASTER) - && d100() < i7) + && d20() == 1) { int iVoice = VOICE_CHAT_ATTACK;// Default - switch(Random(i6)) // Random will do 0-5, so more chance of ATTACK + switch(Random(6)) // Random will do 0-5, so more chance of ATTACK { - case i0: iVoice = VOICE_CHAT_LAUGH; break; - case i1: iVoice = VOICE_CHAT_BATTLECRY1; break; - case i2: iVoice = VOICE_CHAT_BATTLECRY2; break; - case i3: iVoice = VOICE_CHAT_BATTLECRY3; break; + case 0: iVoice = VOICE_CHAT_LAUGH; break; + case 1: iVoice = VOICE_CHAT_BATTLECRY1; break; + case 2: iVoice = VOICE_CHAT_BATTLECRY2; break; + case 3: iVoice = VOICE_CHAT_BATTLECRY3; break; default: iVoice = VOICE_CHAT_ATTACK; break;// Default } // Random delay for 0.0 to 1.0 seconds. @@ -1179,7 +1104,7 @@ int AI_EquipAndAttack() } // - Flying - if(GlobalRangeToMeleeTarget > f8 && + if(GlobalRangeToMeleeTarget > 8.0 && GetSpawnInCondition(AI_FLAG_COMBAT_FLYING, AI_COMBAT_MASTER)) { SetAIObject(AI_FLYING_TARGET, GlobalMeleeTarget); @@ -1189,23 +1114,23 @@ int AI_EquipAndAttack() // Set up the range to use weapons at, before moving into HTH // Default is 5.0 (+ Some for creature size) with no changes... - float fRange = f5; + float fRange = 5.0; // Might have some pre-set range OnSpawn - int iRangeFromSetup = GetAIInteger(AI_RANGED_WEAPON_RANGE); - if(iRangeFromSetup >= i1) + int nRangeFromSetup = GetAIInteger(AI_RANGED_WEAPON_RANGE); + if(nRangeFromSetup >= 1) { - fRange = IntToFloat(iRangeFromSetup); + fRange = IntToFloat(nRangeFromSetup); } // If our intelligence is enough, we make it 3.0. - else if(GlobalIntelligence >= i5) + else if(GlobalIntelligence >= 5) { - fRange = f3; + fRange = 3.0; } // We add a base of X for monster sizes - fRange += (IntToFloat(GlobalOurSize)/f4); + fRange += (IntToFloat(GetCreatureSize(OBJECT_SELF))/4.0); - // iRangedAttack = TRUE, then equip ranged weapons - int iRangedAttack = FALSE; + // bRangedAttack = TRUE, then equip ranged weapons + int bRangedAttack = FALSE; // Now check for it... // If range to melee target is OVER fRange... @@ -1213,54 +1138,62 @@ int AI_EquipAndAttack() if(GlobalRangeToMeleeTarget > fRange || GetSpawnInCondition(AI_FLAG_COMBAT_ARCHER_ALWAYS_USE_BOW, AI_COMBAT_MASTER)) { - iRangedAttack = TRUE; + bRangedAttack = TRUE; } // Special check for AI_FLAG_COMBAT_BETTER_AT_HAND_TO_HAND. // Either a % chance, or that they have no enemy in X distance, and we are // in Y distance. // We always run in at 8 or less M too. - if(iRangedAttack == TRUE && GetSpawnInCondition(AI_FLAG_COMBAT_BETTER_AT_HAND_TO_HAND, AI_COMBAT_MASTER)) + if(bRangedAttack == TRUE && GetSpawnInCondition(AI_FLAG_COMBAT_BETTER_AT_HAND_TO_HAND, AI_COMBAT_MASTER)) { // If they are under 8M away, always run in - 80% chance - if(GlobalRangeToMeleeTarget < f8 && d10() <= i8) + if(GlobalRangeToMeleeTarget < 8.0 && d10() <= 8) { - iRangedAttack = FALSE; + bRangedAttack = FALSE; } else { // Get distance from melee target to nearest ally to it. - float fAllyToMelee = GetDistanceBetween(GlobalMeleeTarget, GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, GlobalMeleeTarget, i1, CREATURE_TYPE_IS_ALIVE, TRUE)); + float fAllyToMelee = GetDistanceBetween(GlobalMeleeTarget, GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, GlobalMeleeTarget, 1, CREATURE_TYPE_IS_ALIVE, TRUE)); // Check thier range to ours // - Basically, if GlobalRangeToMeleeTarget - fAllyToMelee, is // a difference of Random(4) + 4;, we move in. // + 60% chance! - if((GlobalRangeToMeleeTarget - fAllyToMelee) <= (IntToFloat(Random(i4) + i4)) && - d10() <= i6) + if((GlobalRangeToMeleeTarget - fAllyToMelee) <= (IntToFloat(Random(4) + 4)) && + d10() <= 6) { - iRangedAttack = FALSE; + bRangedAttack = FALSE; } } } // Declare everything - object oEquipped, oMainWeapon, oMainPossessor, oPrimary, oSecondary, oTwohanded; - int iPickUpDisarmed, iRanged, iShield, iValidAmmo, iStrength, iPrimaryNum, - iSecondaryNum, iValidPrimary, iValidSecondary, iValidTwoHanded, iPrimaryDamage, - iEquippedShield, iShieldInSlotAlready, iEquippedMostDamaging, + object oEquipped, oMainWeapon, oMainPossessor, oPrimary, oSecondary, + oTwohanded, oRightWeapon, oLeftWeapon; + int bPickUpDisarmed, bRanged, bShield, nValidAmmoSlot, nStrength, nPrimaryNum, + nSecondaryNum, bValidPrimary, bValidSecondary, bValidTwoHanded, nPrimaryDamage, + bEquippedShield, nShieldInSlotAlready, bEquippedMostDamaging, // Done in melee attacking, if we want more AC - IE expertise. - iNeedMoreAC; + bNeedMoreAC; float fRangeToWeapon; - iShieldInSlotAlready = GetBaseItemType(GlobalLeftHandWeapon); + // Weapons already in slots + // Right == Ranged slot, non-shield slot. + // Left == Torch slot, secondary slot, shield slot. + oRightWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND); + oLeftWeapon = GetItemInSlot(INVENTORY_SLOT_LEFTHAND); + + // Shield already in our left hand + nShieldInSlotAlready = GetBaseItemType(oLeftWeapon); // Here...we determine wether to try for melee or ranged attacks. // This is TRUE if we did ActionEquipMostDamaging... - iEquippedMostDamaging = FALSE; + bEquippedMostDamaging = FALSE; object oShield = GetAIObject(AI_WEAPON_SHIELD); - int iValidShield = GetIsObjectValid(oShield); + int bValidShield = GetIsObjectValid(oShield); // SPECIAL: We will just use default calls FIRST and stop IF we have this set // same checks to choose between them though :-P if(AI_GetAIHaveEffect(GlobalEffectPolymorph) || @@ -1268,8 +1201,8 @@ int AI_EquipAndAttack() { // 1: "[DCR:Melee] Most Damaging Weapon. Target: " + GetName(GlobalMeleeTarget) DebugActionSpeakByInt(1, GlobalMeleeTarget); - // iRangedAttack = 1 then ranged. - if(iRangedAttack) + // bRangedAttack = 1 then ranged. + if(bRangedAttack) { ActionEquipMostDamagingRanged(GlobalMeleeTarget); } @@ -1281,42 +1214,42 @@ int AI_EquipAndAttack() // Spcial - if we are set to always move back, 1/10 times we don't equip HTH. // BUT we will attack in HTH if the last target was this target. else if(GetSpawnInCondition(AI_FLAG_COMBAT_ARCHER_ALWAYS_MOVE_BACK, AI_COMBAT_MASTER) - && d10() != i1) + && d10() != 1) { ActionEquipMostDamagingRanged(GlobalMeleeTarget); } // Else we should always be in HTH range. - else // if(!iRangedAttack) + else // if(!bRangedAttack) { ActionEquipMostDamagingMelee(GlobalMeleeTarget, TRUE); } // Always do... - iEquippedMostDamaging = TRUE; + bEquippedMostDamaging = TRUE; } // Else normal weapons, IE we check stored ones :-P else if(!AI_GetAIHaveEffect(GlobalEffectPolymorph)) { // Declaring // Toggle: Do we pick up any disarmed weapons? - iPickUpDisarmed = GetSpawnInCondition(AI_FLAG_COMBAT_PICK_UP_DISARMED_WEAPONS, AI_COMBAT_MASTER); + bPickUpDisarmed = GetSpawnInCondition(AI_FLAG_COMBAT_PICK_UP_DISARMED_WEAPONS, AI_COMBAT_MASTER); // We may, if at the right range (and got a ranged weapon) equip it. oMainWeapon = GetAIObject(AI_WEAPON_RANGED); oMainPossessor = GetItemPossessor(oMainWeapon); - // iRanged = TRUE if we equip a ranged weapon after checks. - // iShield = TRUE if we should equip a shield - // Is the ranged weapon valid? And iRangedAttack == TRUE + // bRanged = TRUE if we equip a ranged weapon after checks. + // bShield = TRUE if we should equip a shield + // Is the ranged weapon valid? And bRangedAttack == TRUE // We need valid ammo, else we eqip nothing! - iValidAmmo = GetAIInteger(AI_WEAPON_RANGED_AMMOSLOT); - if(iValidAmmo == INVENTORY_SLOT_RIGHTHAND) + nValidAmmoSlot = GetAIInteger(AI_WEAPON_RANGED_AMMOSLOT); + if(nValidAmmoSlot == INVENTORY_SLOT_RIGHTHAND) { - iValidAmmo = TRUE; + nValidAmmoSlot = TRUE; } else { - iValidAmmo = GetIsObjectValid(GetItemInSlot(iValidAmmo)); + nValidAmmoSlot = GetIsObjectValid(GetItemInSlot(nValidAmmoSlot)); } // Ranged attack...valid? - if(iRangedAttack && iValidAmmo && GetIsObjectValid(oMainWeapon)) + if(bRangedAttack && nValidAmmoSlot && GetIsObjectValid(oMainWeapon)) { // Is the possessor valid? (could be us or someone else) if(GetIsObjectValid(oMainPossessor)) @@ -1324,13 +1257,13 @@ int AI_EquipAndAttack() // Check if it is us or not... if(oMainPossessor == OBJECT_SELF) { - if(GlobalRightHandWeapon != oMainWeapon) + if(oRightWeapon != oMainWeapon) { // Ranged weapons then equipped in the righthand :-D ActionEquipItem(oMainWeapon, INVENTORY_SLOT_RIGHTHAND); } oEquipped = oMainWeapon; - iRanged = TRUE;// only ranged feats. + bRanged = TRUE;// only ranged feats. } // Else, we delete it and check for secondary one :-) else if(GetIsObjectValid(GetAIObject(AI_WEAPON_RANGED_2))) @@ -1344,7 +1277,7 @@ int AI_EquipAndAttack() { ActionEquipItem(oMainWeapon, INVENTORY_SLOT_RIGHTHAND); oEquipped = oMainWeapon; - iRanged = TRUE;// only ranged feats. + bRanged = TRUE;// only ranged feats. } } else // Else, delete the ranged thing, someone else has it. @@ -1353,17 +1286,17 @@ int AI_EquipAndAttack() } } // Else, it is on the ground. If near, we pick it up. - else if(iPickUpDisarmed) + else if(bPickUpDisarmed) { fRangeToWeapon = GetDistanceToObject(oMainWeapon); - if((fRangeToWeapon < f5 && fRangeToWeapon > f0)|| + if((fRangeToWeapon < 5.0 && fRangeToWeapon > 0.0)|| !GlobalMeleeAttackers) { // We should attempt to pick it up... ActionPickUpItem(oMainWeapon); ActionEquipItem(oMainWeapon, INVENTORY_SLOT_RIGHTHAND); oEquipped = oMainWeapon; - iRanged = TRUE;// only ranged feats. + bRanged = TRUE;// only ranged feats. } else // Else, we can't or won't get it. { @@ -1379,7 +1312,7 @@ int AI_EquipAndAttack() { ActionEquipItem(oMainWeapon, INVENTORY_SLOT_RIGHTHAND); oEquipped = oMainWeapon; - iRanged = TRUE;// only ranged feats. + bRanged = TRUE;// only ranged feats. } } } @@ -1387,14 +1320,14 @@ int AI_EquipAndAttack() } // This is set to the items AC value, to take away simulating taking it off when // we check AC against other things... :-) - if(iShieldInSlotAlready == BASE_ITEM_TOWERSHIELD || - iShieldInSlotAlready == BASE_ITEM_SMALLSHIELD || - iShieldInSlotAlready == BASE_ITEM_LARGESHIELD) + if(nShieldInSlotAlready == BASE_ITEM_TOWERSHIELD || + nShieldInSlotAlready == BASE_ITEM_SMALLSHIELD || + nShieldInSlotAlready == BASE_ITEM_LARGESHIELD) { - iShieldInSlotAlready = GetItemACValue(GlobalLeftHandWeapon); + nShieldInSlotAlready = GetItemACValue(oLeftWeapon); } // NOTE: shields cannot be disarmed! If we don't have it, though, we act as if it isnt valid - if(!iValidShield || GetItemPossessor(oShield) != OBJECT_SELF) + if(!bValidShield || GetItemPossessor(oShield) != OBJECT_SELF) { // If the second is valid, we re-set weapons. if(GetIsObjectValid(GetAIObject(AI_WEAPON_SHIELD_2))) @@ -1402,22 +1335,22 @@ int AI_EquipAndAttack() // If valid, we re-set weapons! Because we cannot pick up the other. ExecuteScript(FILE_RE_SET_WEAPONS, OBJECT_SELF); } - // iValidShield is 1 if valid, and now on us. + // bValidShield is 1 if valid, and now on us. oShield = GetAIObject(AI_WEAPON_SHIELD); - iValidShield = GetIsObjectValid(oShield); + bValidShield = GetIsObjectValid(oShield); } - // iEquippedShield is TRUE if we equip a shield. + // bEquippedShield is TRUE if we equip a shield. // If something has been equipped, we arm a shield...here - if(iRanged) + if(bRanged) { // Need a vlaid shield AND able to equip one. - if(iValidShield && GetAIInteger(AI_WEAPON_RANGED_SHIELD)) + if(bValidShield && GetAIInteger(AI_WEAPON_RANGED_SHIELD)) { if(oShield != GetItemInSlot(INVENTORY_SLOT_LEFTHAND)) { ActionEquipItem(oShield, INVENTORY_SLOT_LEFTHAND); } - iEquippedShield = TRUE; + bEquippedShield = TRUE; } } else // Else, equip the best combo of HTH weapons! @@ -1426,31 +1359,32 @@ int AI_EquipAndAttack() // What do we have? // Get things... // First: Primary. If that is valid, we check secondary. These are arrays. - iPrimaryNum = AI_GetWeaponArray(AI_WEAPON_PRIMARY); - if(iPrimaryNum) + nPrimaryNum = AI_GetWeaponArray(AI_WEAPON_PRIMARY); + if(nPrimaryNum) { - oPrimary = GetLocalObject(OBJECT_SELF, AI_WEAPON_PRIMARY + IntToString(iPrimaryNum)); - iValidPrimary = GetIsObjectValid(oPrimary); - if(iValidPrimary) + oPrimary = GetLocalObject(OBJECT_SELF, AI_WEAPON_PRIMARY + IntToString(nPrimaryNum)); + bValidPrimary = GetIsObjectValid(oPrimary); + if(bValidPrimary) { // We want the smallest... - iSecondaryNum = AI_GetWeaponArray(AI_WEAPON_SECONDARY, oPrimary, i3); - if(iSecondaryNum) + nSecondaryNum = AI_GetWeaponArray(AI_WEAPON_SECONDARY, oPrimary, 3); + if(nSecondaryNum) { - oSecondary = GetLocalObject(OBJECT_SELF, AI_WEAPON_SECONDARY + IntToString(iSecondaryNum)); - iValidSecondary = GetIsObjectValid(oSecondary); + oSecondary = GetLocalObject(OBJECT_SELF, AI_WEAPON_SECONDARY + IntToString(nSecondaryNum)); + bValidSecondary = GetIsObjectValid(oSecondary); } } } // 2 handed - oTwohanded = GetAIObject(AI_WEAPON_TWO_HANDED); - iValidTwoHanded = GetIsObjectValid(oTwohanded); + // * Fix, 1.4, thanks Chris, this is not a GetAIObject()! It is like above lines. + oTwohanded = GetLocalObject(OBJECT_SELF, AI_WEAPON_TWO_HANDED + "1"); + bValidTwoHanded = GetIsObjectValid(oTwohanded); // Shield is done above. // Now, are any valid? - if(!iValidPrimary && !iValidTwoHanded) + if(!bValidPrimary && !bValidTwoHanded) { ActionEquipMostDamagingMelee(GlobalMeleeTarget, TRUE); - iEquippedMostDamaging = TRUE; + bEquippedMostDamaging = TRUE; } else { @@ -1459,67 +1393,67 @@ int AI_EquipAndAttack() // Globals: // GlobalOurAC, GlobalOurHitDice, GlobalOurBaseAttackBonus, GlobalMeleeAttackers // GlobalAverageEnemyHD, GlobalAverageEnemyBAB - iStrength = GetAbilityModifier(ABILITY_STRENGTH); + nStrength = GetAbilityModifier(ABILITY_STRENGTH); // Check one: Is a lot more AC better? Or keep shield equipped, even? // 1. Is our AC below 2x our HD? (IE under 20 at level 10) - if((GlobalOurAC < GlobalOurHitDice * i2) || + if((GlobalOurAC < GlobalOurHitDice * 2) || // 2. Our AC with no shield is under average melee BAB + 6 (a badish roll) - (GlobalOurAC - iShieldInSlotAlready < GlobalAverageEnemyBAB + i6 && - GlobalAverageEnemyHD >= GlobalOurHitDice - i5) || + (GlobalOurAC - nShieldInSlotAlready < GlobalAverageEnemyBAB + 6 && + GlobalAverageEnemyHD >= GlobalOurHitDice - 5) || // 3. Melee attackers are great, over 1/4th of our HD + 2, and enemy HD is comparable toughness - (GlobalMeleeAttackers > ((GlobalOurHitDice / i4) + i2) && - GlobalAverageEnemyHD >= GlobalOurHitDice - i3)) + (GlobalMeleeAttackers > ((GlobalOurHitDice / 4) + 2) && + GlobalAverageEnemyHD >= GlobalOurHitDice - 3)) { // We need more AC! - iNeedMoreAC = TRUE; + bNeedMoreAC = TRUE; // Valid primary, for the shield... - if(iValidPrimary) + if(bValidPrimary) { oEquipped = oPrimary;// May change though... // If we have a shield (which is the point) we equip any not in slots. - if(iValidShield) + if(bValidShield) { - iEquippedShield = TRUE; - if(GlobalRightHandWeapon != oPrimary) + bEquippedShield = TRUE; + if(oRightWeapon != oPrimary) { ActionEquipItem(oPrimary, INVENTORY_SLOT_RIGHTHAND); } - if(GlobalLeftHandWeapon != oShield) + if(oLeftWeapon != oShield) { ActionEquipItem(oShield, INVENTORY_SLOT_LEFTHAND); } } - else if(iValidTwoHanded) + else if(bValidTwoHanded) { oEquipped = oTwohanded; - if(GlobalRightHandWeapon != oTwohanded) + if(oRightWeapon != oTwohanded) { ActionEquipItem(oTwohanded, INVENTORY_SLOT_RIGHTHAND); } } - else if(iValidSecondary) + else if(bValidSecondary) { - if(GlobalRightHandWeapon != oPrimary) + if(oRightWeapon != oPrimary) { ActionEquipItem(oPrimary, INVENTORY_SLOT_RIGHTHAND); } - if(GlobalLeftHandWeapon != oSecondary) + if(oLeftWeapon != oSecondary) { ActionEquipItem(oSecondary, INVENTORY_SLOT_LEFTHAND); } } else { - if(GlobalRightHandWeapon != oPrimary) + if(oRightWeapon != oPrimary) { ActionEquipItem(oPrimary, INVENTORY_SLOT_RIGHTHAND); } } } - else if(iValidTwoHanded) + else if(bValidTwoHanded) { oEquipped = oTwohanded; - if(GlobalRightHandWeapon != oTwohanded) + if(oRightWeapon != oTwohanded) { ActionEquipItem(oTwohanded, INVENTORY_SLOT_RIGHTHAND); } @@ -1528,46 +1462,46 @@ int AI_EquipAndAttack() // Check two: If we have a good hitting chance, we might equip a 2handed first. // 1. We have a decent strength mod, which adds damage to many 2 handed. // This is AND things... - else if((iStrength >= (GlobalOurHitDice / i4 + i2)) && + else if((nStrength >= (GlobalOurHitDice / 4 + 2)) && // 2. Greater strength then dexterity - (iStrength > GetAbilityModifier(ABILITY_DEXTERITY) + Random(i3))) + (nStrength > GetAbilityModifier(ABILITY_DEXTERITY) + Random(3))) { - if(iValidTwoHanded) + if(bValidTwoHanded) { oEquipped = oTwohanded; - if(GlobalRightHandWeapon != oTwohanded) + if(oRightWeapon != oTwohanded) { ActionEquipItem(oTwohanded, INVENTORY_SLOT_RIGHTHAND); } } - else if(iValidPrimary) + else if(bValidPrimary) { oEquipped = oPrimary; // Secondary first, rather then shield. - if(iValidSecondary) + if(bValidSecondary) { - if(GlobalRightHandWeapon != oPrimary) + if(oRightWeapon != oPrimary) { ActionEquipItem(oPrimary, INVENTORY_SLOT_RIGHTHAND); } - if(GlobalLeftHandWeapon != oSecondary) + if(oLeftWeapon != oSecondary) { ActionEquipItem(oSecondary, INVENTORY_SLOT_LEFTHAND); } } - else if(iValidShield) + else if(bValidShield) { - iEquippedShield = TRUE; - if(GlobalRightHandWeapon != oPrimary) + bEquippedShield = TRUE; + if(oRightWeapon != oPrimary) { ActionEquipItem(oPrimary, INVENTORY_SLOT_RIGHTHAND); } - if(GlobalLeftHandWeapon != oShield) + if(oLeftWeapon != oShield) { ActionEquipItem(oShield, INVENTORY_SLOT_LEFTHAND); } } - else if(GlobalRightHandWeapon != oPrimary) + else if(oRightWeapon != oPrimary) { ActionEquipItem(oPrimary, INVENTORY_SLOT_RIGHTHAND); } @@ -1577,42 +1511,42 @@ int AI_EquipAndAttack() // In essense, for 2 weapons, it is less damage more times, as it were (if we hit!) else { - if(iValidPrimary) + if(bValidPrimary) { oEquipped = oPrimary; // Secondary first, rather then shield. - if(iValidSecondary) + if(bValidSecondary) { - if(GlobalRightHandWeapon != oPrimary) + if(oRightWeapon != oPrimary) { ActionEquipItem(oPrimary, INVENTORY_SLOT_RIGHTHAND); } - if(GlobalLeftHandWeapon != oSecondary) + if(oLeftWeapon != oSecondary) { ActionEquipItem(oSecondary, INVENTORY_SLOT_LEFTHAND); } } - else if(iValidShield) + else if(bValidShield) { - iEquippedShield = TRUE; - if(GlobalRightHandWeapon != oPrimary) + bEquippedShield = TRUE; + if(oRightWeapon != oPrimary) { ActionEquipItem(oPrimary, INVENTORY_SLOT_RIGHTHAND); } - if(GlobalLeftHandWeapon != oShield) + if(oLeftWeapon != oShield) { ActionEquipItem(oShield, INVENTORY_SLOT_LEFTHAND); } } - else if(GlobalRightHandWeapon != oPrimary) + else if(oRightWeapon != oPrimary) { ActionEquipItem(oPrimary, INVENTORY_SLOT_RIGHTHAND); } } - else if(iValidTwoHanded) + else if(bValidTwoHanded) { oEquipped = oTwohanded; - if(GlobalRightHandWeapon != oTwohanded) + if(oRightWeapon != oTwohanded) { ActionEquipItem(oTwohanded, INVENTORY_SLOT_RIGHTHAND); } @@ -1624,8 +1558,8 @@ int AI_EquipAndAttack() // We check for weapon effective here, if we didn't equip most damaging // - We only do this if we are attacking the target for more then 1 round. - if(!iEquippedMostDamaging && !iRangedAttack && - GetAIInteger(AI_MELEE_TURNS_ATTACKING) >= i2) + if(!bEquippedMostDamaging && !bRangedAttack && + GetAIInteger(AI_MELEE_TURNS_ATTACKING) >= 2) { // If neither weapon can damage the target...and no most damaging... if(!GetWeaponRanged(oEquipped) && @@ -1635,7 +1569,7 @@ int AI_EquipAndAttack() // 2: "[DCR:Melee] Most Damaging as Not Effective" DebugActionSpeakByInt(2); // We equip a shield (if not already) - if(!iEquippedShield && iValidShield) + if(!bEquippedShield && bValidShield) { if(oShield != GetItemInSlot(INVENTORY_SLOT_LEFTHAND)) { @@ -1647,16 +1581,15 @@ int AI_EquipAndAttack() } } // Now, we should have equipped something :-D - // GlobalLeftHandWeapon, GlobalRightHandWeapon - // GlobalOurSize, GlobalOurBaseAttackBonus, GlobalMeleeTargetAC, GlobalMeleeTargetBAB + // GlobalMeleeTargetAC // We randomly hit, determined by our intelligence. // If we have higher intelligence, we take our rolls to be higher, so we use feats more. - int iOurHit; + int nOurHit; // add a base value...so 18 for Int. 10. 0 for Int. 1. - iOurHit = GlobalOurBaseAttackBonus + ((GlobalIntelligence * i2) - i2); + nOurHit = GlobalOurBaseAttackBonus + ((GlobalIntelligence * 2) - 2); // Randomise...should never get results over 20 now. (0-20 for INT 1, 0-2 for INT 10) - iOurHit += Random(i20 - ((GlobalIntelligence - i1) * i2)); + nOurHit += Random(20 - ((GlobalIntelligence - 1) * 2)); // 1.3 - Add Dexterity to ranged feat checking, strength to melee @@ -1668,82 +1601,92 @@ int AI_EquipAndAttack() Classes: All. A successful check allows the character to resist any combat feat - (Disarm, Called Shot, or Knockdown).n). + (Disarm, Called Shot, or Knockdown). Check: The DC is equal to the attacker's attack roll. Use: Automatic. */ // We therefore make ValidFeat mean FALSE if the target has too much // disipline (by a margin) - if(GlobalIntelligence >= i8) + int bDisciplineFeats = TRUE; + if(GlobalIntelligence >= 8) { // If thier rank - 20 is over our BAB + XX, then no go, as it is very // likely they'll pass the check. - if(GetSkillRank(SKILL_DISCIPLINE) - i20 >= iOurHit) + // * Was no second parameter (thusly OBJECT_SELF). 1.4 fix - change to + // opponents skill! + if(GetSkillRank(SKILL_DISCIPLINE, GlobalMeleeTarget) - 25 >= nOurHit) { // No feats - ValidFeats = FALSE; + bDisciplineFeats = FALSE; } } // Note: If we can only hit on a 20, and have 7+ Intelligence, we make it // use ANY feat (as they will have the same chance of hitting - a critical - // as a normal attack) - if(GlobalOurBaseAttackBonus + i20 <= GlobalMeleeTargetAC) + if(GlobalOurBaseAttackBonus + 20 <= GlobalMeleeTargetAC) { - iOurHit = GlobalOurBaseAttackBonus + i100;// Massive amount - we act as if we rolled 100! + nOurHit = GlobalOurBaseAttackBonus + 100;// Massive amount - we act as if we rolled 100! } // We turn off hiding/searching as we will at least do ActionAttack... AI_ActionTurnOffHiding(); // Ranged weapon? - if(iRanged && ValidFeats && !AI_GetAIHaveEffect(GlobalEffectPolymorph)) + if(bRanged && !AI_GetAIHaveEffect(GlobalEffectPolymorph)) { // RANGED: Add dexterity - iOurHit += GetAbilityModifier(ABILITY_DEXTERITY); + nOurHit += GetAbilityModifier(ABILITY_DEXTERITY); + int nAC = GetAC(GlobalRangedTarget); // We see if it is a weapon which we can use power attack with >:-D if(GetBaseItemType(oEquipped) == BASE_ITEM_THROWINGAXE) { - if((iOurHit - i5) >= GlobalMeleeTargetAC)// Power attack + if((nOurHit - 5) >= nAC)// Power attack { - if((iOurHit - i10) >= GlobalMeleeTargetAC)// Improved power attack + if((nOurHit - 10) >= GlobalMeleeTargetAC)// Improved power attack { AI_SetMeleeMode(ACTION_MODE_IMPROVED_POWER_ATTACK); - ActionAttack(GlobalMeleeTarget); + ActionAttack(GlobalRangedTarget); return FEAT_IMPROVED_POWER_ATTACK; } AI_SetMeleeMode(ACTION_MODE_POWER_ATTACK); - ActionAttack(GlobalMeleeTarget); + ActionAttack(GlobalRangedTarget); return FEAT_POWER_ATTACK; } } // Rapid shot - This provides another attack, at -2 to hit. - if((iOurHit - i2) >= GlobalMeleeTargetAC && GetHasFeat(FEAT_RAPID_SHOT)) + else if((nOurHit - 2) >= GlobalMeleeTargetAC && GetHasFeat(FEAT_RAPID_SHOT)) { AI_SetMeleeMode(ACTION_MODE_RAPID_SHOT); - ActionAttack(GlobalMeleeTarget); + ActionAttack(GlobalRangedTarget); return FEAT_RAPID_SHOT; } // Called shot is -4, but some good things...does it work though? Uncommented till sure - if(((iOurHit - i4) >= GlobalMeleeTargetAC) && - GetHasFeat(FEAT_CALLED_SHOT) && - !GetHasFeatEffect(FEAT_CALLED_SHOT, GlobalMeleeTarget)) + else if(((nOurHit - 4) >= nAC) && + GetHasFeat(FEAT_CALLED_SHOT) && bDisciplineFeats && + !GetHasFeatEffect(FEAT_CALLED_SHOT, GlobalRangedTarget)) { AI_SetMeleeMode(); - ActionUseFeat(FEAT_CALLED_SHOT, GlobalMeleeTarget); + ActionUseFeat(FEAT_CALLED_SHOT, GlobalRangedTarget); return FEAT_CALLED_SHOT; } + else + { + // Normal (Ranged) attack + ActionAttack(GlobalRangedTarget); + return AI_NORMAL_RANGED_ATTACK; + } } // Parry the enemy, if we have only 1 target attacking us, and have // decent skill. - else if(!iRanged && !GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_PARRYING, AI_OTHER_COMBAT_MASTER) && + else if(!bRanged && !GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_PARRYING, AI_OTHER_COMBAT_MASTER) && // 1 attacker, and the melee target is attacking us. - GlobalMeleeAttackers <= i1 && GetAttackTarget(GlobalMeleeTarget) == OBJECT_SELF && + GlobalMeleeAttackers <= 1 && GetAttackTarget(GlobalMeleeTarget) == OBJECT_SELF && // Not got a ranged weapon - enemy target that is !GetWeaponRanged(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, GlobalMeleeTarget)) && // Got skill rank of at least our hit dice + 4. - ((GetSkillRank(SKILL_PARRY) >= (GlobalOurHitDice + i4)) || + ((GetSkillRank(SKILL_PARRY) >= (GlobalOurHitDice + 4)) || // Or forced GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_PARRYING, AI_OTHER_COMBAT_MASTER))) { @@ -1752,13 +1695,13 @@ int AI_EquipAndAttack() ActionAttack(GlobalMeleeTarget); return AI_PARRY_ATTACK; } - else if(!iRanged) + else if(!bRanged) { // Death attack - if we are hidden, or we have invisiblity effects // - A basic "seen or heard" check, backwards (slightly cheating!) if(GetHasFeat(FEAT_PRESTIGE_DEATH_ATTACK_1) && (!GetObjectSeen(OBJECT_SELF, GlobalMeleeTarget) || - !GetObjectHeard(OBJECT_SELF, GlobalMeleeTarget))) + !GetObjectSeen(OBJECT_SELF, GlobalMeleeTarget))) { // This doesn't seem to be "useable" and is meant to be automatic. // However, using something that decreases our attack will be silly @@ -1767,71 +1710,58 @@ int AI_EquipAndAttack() return FEAT_PRESTIGE_DEATH_ATTACK_1; } // Check for defensive stance - if(GlobalRangeToMeleeTarget < f3 && + if(GetHasFeat(FEAT_DWARVEN_DEFENDER_DEFENSIVE_STANCE) && + !GetHasFeatEffect(FEAT_DWARVEN_DEFENDER_DEFENSIVE_STANCE) && + GlobalRangeToMeleeTarget < 3.0 && GetLastAttackMode() != COMBAT_MODE_DEFENSIVE_STANCE) { // Use defensive stance on self (Hopefully these checks won't override each other) - AI_ActionUseFeatOnObject(FEAT_DWARVEN_DEFENDER_DEFENSIVE_STANCE); + ActionUseFeat(FEAT_DWARVEN_DEFENDER_DEFENSIVE_STANCE, OBJECT_SELF); // Note - fall through and carry on } - // Added check here for valid feats, because of defensive stance. - if(!ValidFeats) - { - // If we have not used any, well...oh well! Attack!! - ActionAttack(GlobalMeleeTarget); - return AI_NORMAL_MELEE_ATTACK; - } // MELEE // - Add strength - iOurHit += GetAbilityModifier(ABILITY_STRENGTH); + nOurHit += GetAbilityModifier(ABILITY_STRENGTH); // More things to declare. - int iTargetWeaponSize, iTargetCreatureSize, iTargetCreatureRace, iOurWeaponSize, - iCanUseMonks, iTargetAlignment, iAddingModifier, iMonkLevels; + int nTargetWeaponSize, nTargetCreatureRace, nOurWeaponSize, + bCanUseMonks, nTargetAlignment, nAddingModifier, nMonkLevels; // Monk levels - iMonkLevels = GetLevelByClass(CLASS_TYPE_MONK); - if(!iMonkLevels) iMonkLevels = i1; - iTargetCreatureRace = GetRacialType(GlobalMeleeTarget);//done later. - iTargetAlignment = GetAlignmentGoodEvil(GlobalMeleeTarget); + nMonkLevels = GetLevelByClass(CLASS_TYPE_MONK); + if(!nMonkLevels) nMonkLevels = 1; + nTargetCreatureRace = GetRacialType(GlobalMeleeTarget);//done later. + nTargetAlignment = GetAlignmentGoodEvil(GlobalMeleeTarget); // Now, monk, can it be done... if((!GetIsObjectValid(oEquipped) || GetBaseItemType(oEquipped) == BASE_ITEM_KAMA) && - iTargetCreatureRace != RACIAL_TYPE_CONSTRUCT && - iTargetCreatureRace != RACIAL_TYPE_UNDEAD) + nTargetCreatureRace != RACIAL_TYPE_CONSTRUCT && + nTargetCreatureRace != RACIAL_TYPE_UNDEAD) { - iCanUseMonks = TRUE; + bCanUseMonks = TRUE; } // Smite good, or evil! - if(iTargetAlignment != ALIGNMENT_NEUTRAL) + if(nTargetAlignment != ALIGNMENT_NEUTRAL) { // For use against them evil pests! Top - one use only anyway. - if(iTargetAlignment == ALIGNMENT_EVIL && GetHasFeat(FEAT_SMITE_EVIL)) + if(nTargetAlignment == ALIGNMENT_EVIL && GetHasFeat(FEAT_SMITE_EVIL)) { AI_SetMeleeMode(); ActionUseFeat(FEAT_SMITE_EVIL, GlobalMeleeTarget); return FEAT_SMITE_EVIL; } // For use against them evil pests! Top - one use only anyway. - else if(iTargetAlignment == ALIGNMENT_GOOD && GetHasFeat(FEAT_SMITE_GOOD)) + else if(nTargetAlignment == ALIGNMENT_GOOD && GetHasFeat(FEAT_SMITE_GOOD)) { AI_SetMeleeMode(); ActionUseFeat(FEAT_SMITE_GOOD, GlobalMeleeTarget); return FEAT_SMITE_GOOD; } } - // Ki damage :-) max roll of damage for weapons for Weapon Master - Hordes - // - Note that this a lot of uses. Test for usefulness! - if(GetHasFeat(FEAT_KI_DAMAGE)) - { - AI_SetMeleeMode(); - ActionUseFeat(FEAT_KI_DAMAGE, GlobalMeleeTarget); - return FEAT_KI_DAMAGE; - } // We may use Expertiese if we are being attacked, and above we tried // to equip a shield... // - Need more help around us (some allies) and people atually attacking us, or low HP. - if((GlobalOurPercentHP <= i20) || - (iNeedMoreAC && GlobalMeleeAttackers && GlobalTotalAllies >= i2)) + if((GlobalOurPercentHP <= 20) || + (bNeedMoreAC && GlobalMeleeAttackers && GlobalTotalAllies >= 2)) { // +10 AC, -10 BAB if(GetHasFeat(FEAT_IMPROVED_EXPERTISE)) @@ -1847,15 +1777,15 @@ int AI_EquipAndAttack() } // First, we have the little-known-about monk powerful feats... // Instant death, what can be better? >:-D - if(iCanUseMonks && GetHasFeat(FEAT_QUIVERING_PALM) && - iOurHit + i5 >= GlobalMeleeTargetAC && + if(bCanUseMonks && GetHasFeat(FEAT_QUIVERING_PALM) && + nOurHit + 5 >= GlobalMeleeTargetAC && GlobalOurHitDice >= GetHitDice(GlobalMeleeTarget)) { // Ok, not too random. Thier roll is not d20 + fort save, it is random(15) + 5. // - Our hit is 10 + Monk class/2 + Wisdom... - if((i10 + (iMonkLevels / i2) + GetAbilityModifier(ABILITY_WISDOM)) >= + if((10 + (nMonkLevels / 2) + GetAbilityModifier(ABILITY_WISDOM)) >= // - This must be over thier Fortitude save, add 5 and 0-15. - (GetFortitudeSavingThrow(GlobalMeleeTarget) + i5 + Random(i15))) + (GetFortitudeSavingThrow(GlobalMeleeTarget) + 5 + Random(15))) { AI_SetMeleeMode(); ActionUseFeat(FEAT_QUIVERING_PALM, GlobalMeleeTarget); @@ -1868,14 +1798,14 @@ int AI_EquipAndAttack() // If we don't have 5 or more, we use some of the better single target // feats before. This requires no BAB check - it is done at max BAB if(// 90% chance of using it with 6+ melee attackers, and 8+ enemies in 4M - (d10() <= i9 && (GlobalEnemiesIn4Meters >= i8 || - GlobalMeleeAttackers >= i6)) || + (d10() <= 9 && (GlobalEnemiesIn4Meters >= 8 || + GlobalMeleeAttackers >= 6)) || // OR, 70% chance of using if we'll get more attacks if we used // whirlwind then if we used - (d10() <= i7 && (GlobalOurBaseAttackBonus/i5 < (GlobalEnemiesIn4Meters - i1))) || + (d10() <= 7 && (GlobalOurBaseAttackBonus/5 < (GlobalEnemiesIn4Meters - 1))) || // Lastly 40% chance if we have 4+ melee, or 5+ in range - (d10() <= i4 && (GlobalEnemiesIn4Meters >= i5 || - GlobalMeleeAttackers >= i4))) + (d10() <= 4 && (GlobalEnemiesIn4Meters >= 5 || + GlobalMeleeAttackers >= 4))) { // - Free attack to all in 10'! This should be anyone in 6.6M or so. if(GetHasFeat(FEAT_IMPROVED_WHIRLWIND)) @@ -1910,29 +1840,34 @@ int AI_EquipAndAttack() Use: Selected. */ if(!GetHasFeatEffect(FEAT_SAP, GlobalMeleeTarget) && GetHasFeat(FEAT_SAP) && - iOurHit - i4 >= GlobalMeleeTargetAC) + nOurHit - 4 >= GlobalMeleeTargetAC && + !AI_GetAIHaveEffect(GlobalEffectUncommandable, GlobalMeleeTarget) && + !AI_GetAIHaveEffect(GlobalEffectDazed, GlobalMeleeTarget)) { AI_SetMeleeMode(); ActionUseFeat(FEAT_SAP, GlobalMeleeTarget); return FEAT_SAP; } // Knockdown is great! One of the best ever!(and VERY, VERY overpowered) - if(!GetHasFeatEffect(FEAT_KNOCKDOWN, GlobalMeleeTarget) && - !GetHasFeatEffect(FEAT_IMPROVED_KNOCKDOWN, GlobalMeleeTarget)) + if(bDisciplineFeats && !GetHasFeatEffect(FEAT_KNOCKDOWN, GlobalMeleeTarget) && + !GetHasFeatEffect(FEAT_IMPROVED_KNOCKDOWN, GlobalMeleeTarget) && + !AI_GetAIHaveEffect(GlobalEffectUncommandable, GlobalMeleeTarget) && + !AI_GetAIHaveEffect(GlobalEffectDazed, GlobalMeleeTarget)) { // These return 1-5, based on size. - iTargetCreatureSize = GetCreatureSize(GlobalMeleeTarget); + int nTargetCreatureSize = GetCreatureSize(GlobalMeleeTarget); + int nOurSize = GetCreatureSize(OBJECT_SELF); // By far the BEST feat to use - knocking them down lets you freely attack them! if(GetHasFeat(FEAT_IMPROVED_KNOCKDOWN)) { // Imporved affects like if we were 1 size larger - thus we can affect 2 sizes bigger targets - if((GlobalOurSize + i2) >= iTargetCreatureSize) + if((nOurSize + 2) >= nTargetCreatureSize) { // Modifier, adds anything from -4 to 0 to 4. // Test: Us, size 3, them size 1. 3 - 1 = 2. 2 * 4 = +8 to hit. - iAddingModifier = (GlobalOurSize - iTargetCreatureSize) * i4; + nAddingModifier = (nOurSize - nTargetCreatureSize) * 4; // We are 1 size bigger, so its evens (we add 4 onto -4) - if(iAddingModifier + iOurHit >= GlobalMeleeTargetAC) + if(nAddingModifier + nOurHit >= GlobalMeleeTargetAC) { AI_SetMeleeMode(); ActionUseFeat(FEAT_IMPROVED_KNOCKDOWN, GlobalMeleeTarget); @@ -1944,12 +1879,12 @@ int AI_EquipAndAttack() else if(GetHasFeat(FEAT_KNOCKDOWN)) { // Only works on our size, above 1, or smaller. - if((GlobalOurSize + i1) >= iTargetCreatureSize) + if((nOurSize + 1) >= nTargetCreatureSize) { // Same as above, but we always take 4 more. - iAddingModifier = ((GlobalOurSize - iTargetCreatureSize) * i4) - (i4); + nAddingModifier = ((nOurSize - nTargetCreatureSize) * 4) - (4); // Calculate - if(iAddingModifier + iOurHit >= GlobalMeleeTargetAC) + if(nAddingModifier + nOurHit >= GlobalMeleeTargetAC) { AI_SetMeleeMode(); ActionUseFeat(FEAT_KNOCKDOWN, GlobalMeleeTarget); @@ -1958,23 +1893,33 @@ int AI_EquipAndAttack() } } } + // Ki damage :-) max roll of damage for weapons for Weapon Master - Hordes + // - Note that this a lot of uses. Test for usefulness! + // 1.4: Moved below "disabling" combat feats. This is more useful if they + // cannot move. + if(GetHasFeat(FEAT_KI_DAMAGE)) + { + AI_SetMeleeMode(); + ActionUseFeat(FEAT_KI_DAMAGE, GlobalMeleeTarget); + return FEAT_KI_DAMAGE; + } // Define sizes of weapons, ETC. // Check if they are disarmable. - if(GetIsCreatureDisarmable(GlobalMeleeTarget)) + if(bDisciplineFeats && GetIsCreatureDisarmable(GlobalMeleeTarget)) { - iOurWeaponSize = AI_GetWeaponSize(oEquipped); - iTargetWeaponSize = AI_GetWeaponSize(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, GlobalMeleeTarget)); + nOurWeaponSize = AI_GetWeaponSize(oEquipped); + nTargetWeaponSize = AI_GetWeaponSize(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, GlobalMeleeTarget)); // No AOO, and only a -4 penalty to hit. if(GetHasFeat(FEAT_IMPROVED_DISARM)) { // We need to have valid sizes, so no odd weapons or shields to attack with... - if(iOurWeaponSize && iTargetWeaponSize)// Are both != 0? + if(nOurWeaponSize && nTargetWeaponSize)// Are both != 0? { // Apply weapon size penalites/bonuses to check - Use right weapons. // We times it by 4. // Test: Us, size 3, them size 1. (3 - 1 = 2) then (2 * 4 = 8) So +8 to hit. - iAddingModifier = (iOurWeaponSize - iTargetWeaponSize) * i4; - if((iAddingModifier + iOurHit - i4) >= GlobalMeleeTargetAC) + nAddingModifier = (nOurWeaponSize - nTargetWeaponSize) * 4; + if((nAddingModifier + nOurHit - 4) >= GlobalMeleeTargetAC) { AI_SetMeleeMode(); ActionUseFeat(FEAT_IMPROVED_DISARM, GlobalMeleeTarget); @@ -1987,12 +1932,12 @@ int AI_EquipAndAttack() else if(GetHasFeat(FEAT_DISARM)) { // We need to have valid sizes, so no odd weapons or shields to attack with... - if(iOurWeaponSize && iTargetWeaponSize)// Are both != 0? + if(nOurWeaponSize && nTargetWeaponSize)// Are both != 0? { // Apply weapon size penalites/bonuses to check - Use left weapons. - iAddingModifier = (iOurWeaponSize - iTargetWeaponSize) * i4; + nAddingModifier = (nOurWeaponSize - nTargetWeaponSize) * 4; // We take 6 and then 1 per melee attacker (AOOs) - if((iAddingModifier + iOurHit - i6 - GlobalMeleeAttackers) >= GlobalMeleeTargetAC) + if((nAddingModifier + nOurHit - 6 - GlobalMeleeAttackers) >= GlobalMeleeTargetAC) { AI_SetMeleeMode(); ActionUseFeat(FEAT_DISARM, GlobalMeleeTarget); @@ -2004,20 +1949,20 @@ int AI_EquipAndAttack() // Next, stunning fist. // Stuns the target, making them unable to move. -4 attack. // DC (fort) of 10 + HD/2 + wis mod. - if(iCanUseMonks && - !GetHasFeatEffect(FEAT_STUNNING_FIST, GlobalMeleeTarget) && - GetHasFeat(FEAT_STUNNING_FIST)) + if(bCanUseMonks && GetHasFeat(FEAT_STUNNING_FIST) && + !AI_GetAIHaveEffect(GlobalEffectUncommandable, GlobalMeleeTarget) && + !AI_GetAIHaveEffect(GlobalEffectDazed, GlobalMeleeTarget)) { // Start adding modifier at 0. - iAddingModifier = i0; + nAddingModifier = 0; // If not a monk, its -4 to hit. Monk levels defaults to 1 if 0 - if(iMonkLevels == TRUE) iAddingModifier - i4; + if(nMonkLevels == TRUE) nAddingModifier - 4; // We hit ETC. // Save is above - if(iOurHit >= GlobalMeleeTargetAC && + if(nOurHit >= GlobalMeleeTargetAC && // Save - (i10 + (GlobalOurHitDice / i2) + GetAbilityModifier(ABILITY_WISDOM) - >= GetFortitudeSavingThrow(GlobalMeleeTarget) + i5 + Random(i15))) + (10 + (GlobalOurHitDice / 2) + GetAbilityModifier(ABILITY_WISDOM) + >= GetFortitudeSavingThrow(GlobalMeleeTarget) + 5 + Random(15))) { AI_SetMeleeMode(); ActionUseFeat(FEAT_STUNNING_FIST, GlobalMeleeTarget); @@ -2029,7 +1974,7 @@ int AI_EquipAndAttack() // - We may use it later at 2 or more. :-) // If we don't have 5 or more, we use some of the better single target // feats before. This requires no BAB check - it is done at max BAB - if(GlobalEnemiesIn4Meters >= i2) + if(GlobalEnemiesIn4Meters >= 2) { // - Free attack to all in 10'! This should be anyone in 6.6M or so. if(GetHasFeat(FEAT_IMPROVED_WHIRLWIND)) @@ -2047,8 +1992,7 @@ int AI_EquipAndAttack() } } // Next, flurry of blows... - if(iCanUseMonks && - iOurHit - i2 >= GlobalMeleeTargetAC && + if(bCanUseMonks && nOurHit - 2 >= GlobalMeleeTargetAC && GetHasFeat(FEAT_FLURRY_OF_BLOWS)) { AI_SetMeleeMode(ACTION_MODE_FLURRY_OF_BLOWS); @@ -2061,9 +2005,10 @@ int AI_EquipAndAttack() { // Our hit is over thier AC, and thier BAB hits us all the time... // OR when there are 3+ - if((iOurHit >= GlobalMeleeTargetAC && - GlobalMeleeTargetBAB + i5 >= GlobalOurAC) || // Add 5 to thier hit - GlobalMeleeAttackers >= i3) + if((nOurHit >= GlobalMeleeTargetAC && + // Add 5 to thier hit + GetBaseAttackBonus(GlobalMeleeTarget) + 5 >= GlobalOurAC) || + GlobalMeleeAttackers >= 3) { AI_SetMeleeMode(ACTION_MODE_IMPROVED_EXPERTISE); ActionAttack(GlobalMeleeTarget); @@ -2075,9 +2020,10 @@ int AI_EquipAndAttack() // Expertise, we may use even if we can hit only sometimes, and // they always hit up sometiems (50% time) // OR when there are 1 + 1/2HD attackers. - if((iOurHit >= GlobalMeleeTargetAC && - GlobalMeleeTargetBAB + i10 >= GlobalOurAC) || // Add 10 to thier hit - GlobalMeleeAttackers >= i2) + if((nOurHit >= GlobalMeleeTargetAC && + // Add 10 to thier hit + GetBaseAttackBonus(GlobalMeleeTarget) + 10 >= GlobalOurAC) || + GlobalMeleeAttackers >= 2) { AI_SetMeleeMode(ACTION_MODE_EXPERTISE); ActionAttack(GlobalMeleeTarget); @@ -2085,7 +2031,7 @@ int AI_EquipAndAttack() } } // At a -2 to hit, this can disarm the arms or legs...speed or attack bonus - if((iOurHit - i4) >= GlobalMeleeTargetAC && + if((nOurHit - 4) >= GlobalMeleeTargetAC && bDisciplineFeats && GetHasFeat(FEAT_CALLED_SHOT) && !GetHasFeatEffect(FEAT_CALLED_SHOT, GlobalMeleeTarget)) { @@ -2105,8 +2051,8 @@ int AI_EquipAndAttack() // is a -5 to hit. Uses random 5, to randomise a bit, // I guess. Still means a massive BAB will use it. // Uses base attack bonus, no additions. - if( GetHasFeat(FEAT_POWER_ATTACK) && - ((GlobalOurBaseAttackBonus + Random(i5)) >= GlobalMeleeTargetAC)) + if(GetHasFeat(FEAT_POWER_ATTACK) && + ((GlobalOurBaseAttackBonus + Random(5)) >= GlobalMeleeTargetAC)) { AI_SetMeleeMode(ACTION_MODE_POWER_ATTACK); ActionAttack(GlobalMeleeTarget); @@ -2114,8 +2060,8 @@ int AI_EquipAndAttack() } // Either: Bad chance to hit, or only one attack, we use this for 1d4 more damage if(GetHasFeat(FEAT_DIRTY_FIGHTING) && - GlobalOurBaseAttackBonus / i5 < i1 || - GlobalOurBaseAttackBonus + i15 < GlobalMeleeTargetAC) + GlobalOurBaseAttackBonus / 5 < 1 || + GlobalOurBaseAttackBonus + 15 < GlobalMeleeTargetAC) { AI_SetMeleeMode(ACTION_MODE_DIRTY_FIGHTING); ActionAttack(GlobalMeleeTarget); @@ -2139,40 +2085,10 @@ int AI_AttemptMeleeAttackWrapper() DebugActionSpeakByInt(3); return FALSE; } - int iFeat = AI_EquipAndAttack(); - // 4: "[DCR:Melee] Melee attack. [Target] " + GetName(GlobalMeleeTarget) + " [Feat/Attack] " + IntToString(iFeat) - DebugActionSpeakByInt(4, GlobalMeleeTarget, iFeat); - return iFeat; -} -// Used with GlobalLastSpellValid. If GlobalLastSpellValid is 0, sets locals for -// use later, and sets GlobalLastSpellValid to the spell in question. -void AI_SetBackupCastingSpellValues(int iSpellID, int nTalent, object oTarget, int iLocation, int iRequirement, int iItemTalentValue, int iPotionTalentValue) -{ - if(GlobalLastSpellValid <= FALSE) - { - // Set last spell - GlobalLastSpellValid = iSpellID; - // Set values using 1 name, + a number - int iCnt = i1; - // SET... - // talent - SetAIInteger(GLOBAL_LAST_SPELL_INFORMATION + IntToString(iCnt), nTalent); - // target - iCnt++; - SetAIObject(GLOBAL_LAST_SPELL_INFORMATION + IntToString(iCnt), oTarget); - // location - iCnt++; - SetAIInteger(GLOBAL_LAST_SPELL_INFORMATION + IntToString(iCnt), iLocation); - // Requirements - iCnt++; - SetAIInteger(GLOBAL_LAST_SPELL_INFORMATION + IntToString(iCnt), iRequirement); - // item - iCnt++; - SetAIInteger(GLOBAL_LAST_SPELL_INFORMATION + IntToString(iCnt), iItemTalentValue); - // potion - iCnt++; - SetAIInteger(GLOBAL_LAST_SPELL_INFORMATION + IntToString(iCnt), iPotionTalentValue); - } + int nFeat = AI_EquipAndAttack(); + // 4: "[DCR:Melee] Melee attack. [Target] " + GetName(GlobalMeleeTarget) + " [Feat/Attack] " + IntToString(nFeat) + DebugActionSpeakByInt(4, GlobalMeleeTarget, nFeat); + return nFeat; } /*:://///////////////////////////////////////////// //:: Spell casting functions @@ -2181,6 +2097,27 @@ void AI_SetBackupCastingSpellValues(int iSpellID, int nTalent, object oTarget, i //:://///////////////////////////////////////////// //:: Created by : Jasperre //:://///////////////////////////////////////////*/ +// Used with GlobalLastSpellValid. If GlobalLastSpellValid is 0, sets locals for +// use later, and sets GlobalLastSpellValid to the spell in question. +void AI_SetBackupCastingSpellValues(int nSpellID, object oTarget, int bLocation, int nRequirement) +{ + if(GlobalLastSpellValid <= FALSE) + { + // Set last spell + GlobalLastSpellValid = nSpellID; + // Set values using 1 name, + a number + int nCnt = 1; + // SET... + // target + SetAIObject(GLOBAL_LAST_SPELL_INFORMATION + IntToString(nCnt), oTarget); + // location + nCnt++; + SetAIInteger(GLOBAL_LAST_SPELL_INFORMATION + IntToString(nCnt), bLocation); + // Requirements + nCnt++; + SetAIInteger(GLOBAL_LAST_SPELL_INFORMATION + IntToString(nCnt), nRequirement); + } +} /*:://///////////////////////////////////////////// //:: Name AttemptSpecialConcentrationCheck @@ -2206,17 +2143,21 @@ int AI_AttemptConcentrationCheck(object oTarget) { return FALSE; } + // DEFENSIVE CASTING: + // This stops AOO's (normal damage concentration checks from attacks still applies) + // This is useful for stopping a lot of extra attacks. + // Jump out if we use defensive casting! if(GetHasSkill(SKILL_CONCENTRATION) && // If we have 15 + 9 skill (for a level 9 spell) so we'll never fail, we // always turn it on. - ((GetSkillRank(SKILL_CONCENTRATION) >= i24) || + ((GetSkillRank(SKILL_CONCENTRATION) >= 24) || // Else we'll turn it on based on our class level. Over class level - (((GetSkillRank(SKILL_CONCENTRATION) >= GlobalOurHitDice + i6) || + (((GetSkillRank(SKILL_CONCENTRATION) >= GlobalOurHitDice + 6) || // Else, we'll turn it on if we have many melee attackers - the damage from // them will be pretty high otherwise. (ONLY if they are a comparable level!) - ((GlobalMeleeAttackers >= i4 && GlobalAverageEnemyBAB + i15 >= GlobalOurAC) || - (GlobalMeleeAttackers >= i7)))))) + ((GlobalMeleeAttackers >= 4 && GlobalAverageEnemyBAB + 15 >= GlobalOurAC) || + (GlobalMeleeAttackers >= 7)))))) { // Turn it on // 5: "[DCR:Caster] Defensive Casting Mode ON [Enemy] " + GetName(GlobalSpellTarget) @@ -2240,9 +2181,9 @@ int AI_AttemptConcentrationCheck(object oTarget) // - May change !AI_GetAIHaveSpellsEffect(GlobalHasStoneSkinProtections) && // We have an ally in 4M - GlobalValidAlly && GlobalRangeToAlly < f4 && + GlobalValidAlly && GlobalRangeToAlly < 4.0 && // Intelligence AND class mage - ((GlobalIntelligence >= i4 && + ((GlobalIntelligence >= 4 && (GlobalOurChosenClass == CLASS_TYPE_WIZARD || GlobalOurChosenClass == CLASS_TYPE_SORCERER || GlobalOurChosenClass == CLASS_TYPE_FEY)) || @@ -2250,7 +2191,7 @@ int AI_AttemptConcentrationCheck(object oTarget) GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_CONCENTRATION, AI_OTHER_MASTER))) { // First - checks concentration... - int iConcentration = GetSkillRank(SKILL_CONCENTRATION); + int nConcentration = GetSkillRank(SKILL_CONCENTRATION); // If we have 0 concentration, we always run! @@ -2267,27 +2208,27 @@ int AI_AttemptConcentrationCheck(object oTarget) // they are of comparable BAB (Consider average AC and average BAB) // We always move back if low concentration...under half our hit dice. - if(iConcentration <= GlobalOurHitDice/i2 || + if(nConcentration <= GlobalOurHitDice/2 || // Or that the average HD is quite high (compared to 2/3 our HD) - GlobalAverageEnemyHD >= ((GlobalOurHitDice * i3) / i2) || + GlobalAverageEnemyHD >= ((GlobalOurHitDice * 3) / 2) || // Or that the average BAB is quite high (compared to 2/3 our AC) - GlobalAverageEnemyBAB >= ((GlobalOurAC * i3) / i2)) + GlobalAverageEnemyBAB >= ((GlobalOurAC * 3) / 2)) { // We check the counter - int iCounter = GetAIInteger(AI_CONCENTRATIONMOVE_COUNTER); - iCounter++; - SetAIInteger(AI_CONCENTRATIONMOVE_COUNTER, iCounter); + int nCounter = GetAIInteger(AI_CONCENTRATIONMOVE_COUNTER); + nCounter++; + SetAIInteger(AI_CONCENTRATIONMOVE_COUNTER, nCounter); // If the counter is <= 5, we will move back, else we've been moving // back for 5 turns already! Stop and do something useful... - if(iCounter <= i5) + if(nCounter <= 5) { ClearAllActions(); // 6: "[DCR:Caster] Moving away from AOO's. [Enemy] " + GetName(GlobalSpellTarget) DebugActionSpeakByInt(6, GlobalSpellTarget); - ActionMoveAwayFromLocation(GetLocation(GlobalMeleeTarget), TRUE, f10); + ActionMoveAwayFromLocation(GetLocation(GlobalMeleeTarget), TRUE, 10.0); return TRUE; } - else if(iCounter >= i10) + else if(nCounter >= 10) { // Reset once we get to 10 rounds. DeleteAIInteger(AI_CONCENTRATIONMOVE_COUNTER); @@ -2303,108 +2244,125 @@ int AI_AttemptConcentrationCheck(object oTarget) } return FALSE; } -// Special case - it checks the talent again, in EffectCutsceneImmobilize (if not already so) and -// uses the item, if it is an equal talent. -int AI_ActionCastItemEqualTo(object oTarget, int iSpellID, int iLocation) -{ - // We need to get what one is actually the talent number :-D - // This is actually faster, as we know that iSpellID equals one of them :-D - // Set to local integers - int iCnt, nTalent, iReturn; - talent tBestOfIt; - for(iCnt = i1; iCnt <= i21; iCnt++) - { - // Check match... - if(GetAIConstant(ITEM_TALENT_VALUE + IntToString(iCnt)) == iSpellID) - { - // We break with set one. - nTalent = iCnt; - break; - } - } - // Check for valid talent (1+) - if(nTalent >= i1) - { - // Apply EffectCutsceneImmobilize. It only removes ones with no spell ID anyway :-D - AI_SpecialActionApplyItem(); - - tBestOfIt = GetCreatureTalentBest(nTalent, i20); - // JUST to make sure! - if(GetIsTalentValid(tBestOfIt) && - GetIdFromTalent(tBestOfIt) == iSpellID && - GetTypeFromTalent(tBestOfIt) == TALENT_TYPE_SPELL) - { - AI_SetTimeStopStored(iSpellID); - // 7: "[DCR:Casting] Talent(item) [TalentID] " + IntToString(GetIdFromTalent(tBestOfIt)) + " [Target] " + GetName(oTarget) + " [Location] " + IntToString(iLocation) - DebugActionSpeakByInt(7, oTarget, GetIdFromTalent(tBestOfIt), IntToString(iLocation)); - // Sets a sub spell whatever, just in case. - SetLocalInt(OBJECT_SELF, AI_SPELL_SUB_SPELL_CAST, iSpellID); - // Equip the best shield we have - AI_EquipBestShield(); - // Use this only for items, so we should not have the spell. - if(iLocation) - { - ActionUseTalentAtLocation(tBestOfIt, GetLocation(oTarget)); - } - else //if(!GetObjectSeen(oTarget)) // Should be seen - checked before. - { - ActionUseTalentOnObject(tBestOfIt, oTarget); - } - iReturn = TRUE; - } - // remove the EffectCutsceneImmobilize, if so. - AI_SpecialActionRemoveItem(); - } - // Return TRUE or FALSE. - return iReturn; -} // This is used for INFLICT spells, as GetHasSpell also can return 1+ for // any extra castings - like if we had 2 light wounds and 2 blesses, it'd return // 4. -// Imput the iSpellID, oTarget in to cast the spell. TRUE if casted. No items checked. -int AI_ActionCastSpontaeousSpell(int iSpellID, int nTalent, object oTarget) +// Input the nSpellID, oTarget in to cast the spell. TRUE if casted. No items checked. +int AI_ActionCastSpontaeousSpell(int nSpellID, object oTarget) { - if(nTalent > i0 && GetHasSpell(iSpellID) && GetObjectSeen(oTarget)) + if(GetHasSpell(nSpellID) && GetObjectSeen(oTarget)) { // Note: Not stored or used in time stop - // 8: "[DCR: Casting] Workaround for Spontaeous [SpellID] " + IntToString(iSpellID) + " [Target] " + GetName(oTarget) - DebugActionSpeakByInt(8, oTarget, iSpellID); + // 8: "[DCR: Casting] Workaround for Spontaeous [SpellID] " + IntToString(nSpellID) + " [Target] " + GetName(oTarget) + DebugActionSpeakByInt(8, oTarget, nSpellID); // Equip the best shield we have AI_EquipBestShield(); + // 1.4 tested this. Just casting the spell doesn't work, sillily. Still + // stands there! + // Decrement the spell being cast by one as we cheat cast it - DecrementRemainingSpellUses(OBJECT_SELF, iSpellID); + DecrementRemainingSpellUses(OBJECT_SELF, nSpellID); // Cheat cast, it'll remove inflict wounds if it is an inflict spell anyway. - ActionCastSpellAtObject(iSpellID, oTarget, METAMAGIC_NONE, TRUE); + ActionCastSpellAtObject(nSpellID, oTarget, METAMAGIC_NONE, TRUE); + return TRUE; + } + return FALSE; +} + +// This will cast the spell of ID in this order [Note: Always adds to time stop, as it will be on self, and benifical): +// 1. If they have the spell normally. +// * We always attack with a bow at ranged, but may attack normally after the spell. +// * If nTalent is 0, we do not cast it unless nRequirement is also 0. +// * If nRequirement is 0, it is considered innate. +// * Input nItemTalentValue and nPotionTalentValue to check item talents. -1 == No item. +// * If bSubspell is TRUE, we will cheat-cast and derement it. +int AI_ActionCastSpell(int nSpellID, object oTarget = OBJECT_SELF, int nRequirement = 0, int bLocation = FALSE, int bSubSpell = FALSE) +{ + // If it is not ever cast at location, but the target is ethreal, stop NOW + if(bLocation == FALSE && (GetIsEthereal(oTarget) || !GetObjectSeen(oTarget))) return FALSE; + + // Check GetHasSpell as long as we are not silenced, and have right modifier, and + // the object is seen (this is a backup for it!) + if(!GlobalSilenceSoItems && + (!nRequirement || GlobalSpellAbilityModifier >= nRequirement) && + GetHasSpell(nSpellID)) + { + // Make sure it is a spell, not an ability + if(nRequirement > FALSE) + { + // Attempt Concentration Check (Casting a spell, not an item) + if(AI_AttemptConcentrationCheck(oTarget)) return TRUE; + } + else + { + // Turn off all modes - remember, we can't use expertise with spellcasting! + AI_SetMeleeMode(); + } + // Set time stop stored to this spell. + AI_SetTimeStopStored(nSpellID); + + // 9: "[DCR:Casting] NormalSpell [ID] " + IntToString(nSpellID) + " [Target] " + GetName(oTarget) + " [Location] " + IntToString(bLocation) + DebugActionSpeakByInt(9, oTarget, nSpellID, IntToString(bLocation)); + + // We turn off hiding/searching + AI_ActionTurnOffHiding(); + + // Equip the best shield we have + AI_EquipBestShield(); + + // Note: 1.3 fix. Action Cast At Object will be used if we can see + // the target, even if it is a location spell + if(GetObjectSeen(oTarget) && !GetIsEthereal(oTarget)) + { + // aim at the object directly! + // - See 1.3 fix below. Basically, this should use Meta Magic normally + ActionCastSpellAtObject(nSpellID, oTarget, METAMAGIC_ANY, bSubSpell); + } + // If location... + else //if(bLocation) + { + // Fire ActionSpellAtLocation at the given location + // 1.3 fix - Until ActionCastSpellAtLocation works with METAMAGIC + // it will cheat-cast, and decrement the spell by one, with no metamagic. + //ActionCastSpellAtLocation(nSpellID, GetLocation(oTarget), METAMAGIC_NONE, TRUE); + //DecrementRemainingSpellUses(OBJECT_SELF, nSpellID); + // 1.4 attempted check fix + ActionCastSpellAtLocation(nSpellID, GetLocation(oTarget), METAMAGIC_ANY, bSubSpell); + } + // If bSubSpell was true, so we cheat-cast it, decrement the spell by 1 + if(bSubSpell == TRUE) + { + DecrementRemainingSpellUses(OBJECT_SELF, nSpellID); + } + // Alway stop - we use else here, so we always do an action! :-D return TRUE; } return FALSE; } // This will cast the spell of ID in this order [Note: Always adds to time stop, as it will be on self, and benifical): +// 0. If d100() is <= nRandom. // 1. If they have the spell normally // 2. If they have an item with the spell. // 3. If they have a potion of the right type. -// - We always attack with a bow at ranged, but may attack normally after the spell. -// - If nTalent is 0, we do not check items. -// - If iRequirement is 0, it is considered innate. -// - Imput iItemTalentValue and iPotionTalentValue to check item talents. -// - iSummonLevel can be 0, but if 1+, it is set to AI_LAST_SUMMONED_LEVEL -int AI_ActionCastSpell(int iSpellID, int nTalent = 0, object oTarget = OBJECT_SELF, int iRequirement = 0, int iLocation = FALSE, int iItemTalentValue = -1, int iPotionTalentValue = -1) +// - If we are at range from nearest enemy, we attack with a ranged weapon, else do nothing more. +// - If nTalent is -1, we do not check items. +// - Sets GlobalLastSpellValid to nSpellID if we can cast it, but don't randomly. +// Then you can use AI_ActionCastBackupRandomSpell to see if we can cast it later. +int AI_ActionCastSpellRandom(int nSpellID, int nRandom, object oTarget = OBJECT_SELF, int nRequirement = 0, int bLocation = FALSE) { - // 1. We need nTalent to be over 0. -1 means an invalid spell for that talent, - // IE no spell for that talent - // - If iRequirement is 0, we consider it innate and no talent category for some - // reason. - if(nTalent > i0 || !iRequirement) + // If it is not ever cast at location, but the target is ethreal, stop NOW + if(bLocation == FALSE && (GetIsEthereal(oTarget) || !GetObjectSeen(oTarget))) return FALSE; + + // Check GetHasSpell as long as we are not silenced, and have right modifier, and + // the object is seen (this is a backup for it!) + if(!GlobalSilenceSoItems && + (!nRequirement || GlobalSpellAbilityModifier >= nRequirement) && + GetHasSpell(nSpellID)) { - // Check GetHasSpell as long as we are not silenced, and have right modifier, and - // the object is seen (this is a backup for it!) - if(!GlobalSilenceSoItems && - (!iRequirement || GlobalSpellAbilityModifier >= iRequirement) && - GetHasSpell(iSpellID) && - (iLocation || GetObjectSeen(oTarget))) + if(d100() <= nRandom + GlobalRandomCastModifier) { // Make sure it is a spell, not an ability - if(iRequirement > FALSE) + if(nRequirement > FALSE) { // Attempt Concentration Check (Casting a spell, not an item) if(AI_AttemptConcentrationCheck(oTarget)) return TRUE; @@ -2415,244 +2373,40 @@ int AI_ActionCastSpell(int iSpellID, int nTalent = 0, object oTarget = OBJECT_SE AI_SetMeleeMode(); } // Set time stop stored to this spell. - AI_SetTimeStopStored(iSpellID); - // 9: "[DCR:Casting] NormalSpell [ID] " + IntToString(iSpellID) + " [Target] " + GetName(oTarget) + " [Location] " + IntToString(iLocation) - DebugActionSpeakByInt(9, oTarget, iSpellID, IntToString(iLocation)); + AI_SetTimeStopStored(nSpellID); + // 12: "[DCR:Casting] NormalRandomSpell. [ID] " + IntToString(nSpellID) + " [Target] " + GetName(oTarget) + " [Location] " + IntToString(bLocation) + DebugActionSpeakByInt(12, oTarget, nSpellID, IntToString(bLocation)); // We turn off hiding/searching AI_ActionTurnOffHiding(); // Equip the best shield we have AI_EquipBestShield(); // Note: 1.3 fix. Action Cast At Object will be used if we can see // the target, even if it is a location spell - if(GetObjectSeen(oTarget)) + if(GetObjectSeen(oTarget) && !GetIsEthereal(oTarget)) { // aim at the object directly! // - See 1.3 fix below. Basically, this should use Meta Magic normally - ActionCastSpellAtObject(iSpellID, oTarget); + ActionCastSpellAtObject(nSpellID, oTarget); } // If location... - else //if(iLocation) + else //if(bLocation) { // Fire ActionSpellAtLocation at the given location // 1.3 fix - Until ActionCastSpellAtLocation works with METAMAGIC // it will cheat-cast, and decrement the spell by one, with no metamagic. - ActionCastSpellAtLocation(iSpellID, GetLocation(oTarget), METAMAGIC_NONE, TRUE); - DecrementRemainingSpellUses(OBJECT_SELF, iSpellID); - } - // Lasts...recheck items - if(AI_GetSpellCategoryHasItem(nTalent)) - { - ActionDoCommand(AI_SetItemTalentValue(nTalent)); + //ActionCastSpellAtLocation(nSpellID, GetLocation(oTarget), METAMAGIC_NONE, TRUE); + //DecrementRemainingSpellUses(OBJECT_SELF, nSpellID); + // 1.4 attempted fix. + ActionCastSpellAtLocation(nSpellID, GetLocation(oTarget)); } // Alway stop - we use else here, so we always do an action! :-D return TRUE; } - // 2. Cast from potions, or items! - // This is made simpler by adding in iItemTalentValue and iPotionTalentValue - } - // Basic items - Wands, Scrolls that might pop up - Potions too - if(iItemTalentValue == iSpellID || - iPotionTalentValue == iSpellID) - { - if(AI_ActionCastItemEqualTo(oTarget, iSpellID, iLocation)) - { - // Lasts...recheck items - if(AI_GetSpellCategoryHasItem(nTalent)) - { - ActionDoCommand(AI_SetItemTalentValue(nTalent)); - } - return TRUE; - } - } - return FALSE; -} -// This will cast the shadow conjuration/protection version of the spell, always if they have it. -// 1. If they have the spell normally (Using the iUpperSpell spell) -// 2. If they have an item with the spell -// - We always attack with a bow at ranged, but may attack normally after the spell. -// - If nTalent is 0, we do not check items. -// - If iRequirement is 0, it is considered innate. -// - Imput iItemTalentValue to check item talents. -int AI_ActionCastSubSpell(int iSubSpell, int nTalent = 0, object oTarget = OBJECT_SELF, int iRequirement = 0, int iLocation = FALSE, int iItemTalentValue = -1, int iPotionTalentValue = -1) -{ - // 1. We need nTalent to be over 0. -1 means an invalid spell for that talent, - // IE no spell for that talent - // - If iRequirement is 0, we consider it innate and no talent category for some - // reason. - if(nTalent > i0 || !iRequirement) - { - // Check GetHasSpell as long as we are not silenced, and have right modifier, and - // the object is seen (this is a backup for it!) - if(!GlobalSilenceSoItems && - (!iRequirement || GlobalSpellAbilityModifier >= iRequirement) && - GetHasSpell(iSubSpell) && - (iLocation || GetObjectSeen(oTarget))) - { - // Make sure it is a spell, not an ability - if(iRequirement > FALSE) - { - // Attempt Concentration Check (Casting a spell, not an item) - if(AI_AttemptConcentrationCheck(oTarget)) return TRUE; - } - else - { - // Turn off all modes - remember, we can't use expertise with spellcasting! - AI_SetMeleeMode(); - } - // Set time stop stored to this spell. - AI_SetTimeStopStored(iSubSpell); - // 11: "[DCR:Casting] SubSpecialSpell. [ID] " + IntToString(iSubSpell) + " [Target] " + GetName(oTarget) + " [Location] " + IntToString(iLocation) - DebugActionSpeakByInt(11, oTarget, iSubSpell, IntToString(iLocation)); - // We turn off hiding/searching - AI_ActionTurnOffHiding(); - // Equip the best shield we have - AI_EquipBestShield(); - // See 1.3 fix notes about metamagic not being used correctly with - // cast spell at location. - if(GetObjectSeen(oTarget)) - { - // Aim at the object directly! - ActionCastSpellAtObject(iSubSpell, oTarget, METAMAGIC_ANY, TRUE); - } - // If location... - else// if(iLocation) - { - // Fire ActionSpellAtLocation at the given location - ActionCastSpellAtLocation(iSubSpell, GetLocation(oTarget), METAMAGIC_NONE, TRUE); - } - // Decrement - DecrementRemainingSpellUses(OBJECT_SELF, iSubSpell); - // Lasts...recheck items - if(AI_GetSpellCategoryHasItem(nTalent)) - { - ActionDoCommand(AI_SetItemTalentValue(nTalent)); - } - // Alway stop - we use else here, so we always do an action! :-D - return TRUE; - } - // 2. Cast from potions, or items! - // This is made simpler by adding in iItemTalentValue and iPotionTalentValue - } - // Basic items - Wands, Scrolls that might pop up - Potions too - if(iItemTalentValue == iSubSpell || - iPotionTalentValue == iSubSpell) - { - if(AI_ActionCastItemEqualTo(oTarget, iSubSpell, iLocation)) - { - // Lasts...recheck items - if(AI_GetSpellCategoryHasItem(nTalent)) - { - ActionDoCommand(AI_SetItemTalentValue(nTalent)); - } - return TRUE; - } - } - return FALSE; -} -// This will cast the spell of ID in this order [Note: Always adds to time stop, as it will be on self, and benifical): -// 0. If d100() is <= iRandom. -// 1. If they have the spell normally -// 2. If they have an item with the spell. -// 3. If they have a potion of the right type. -// - If we are at range from nearest enemy, we attack with a ranged weapon, else do nothing more. -// - If nTalent is -1, we do not check items. -// - Sets GlobalLastSpellValid to iSpellID if we can cast it, but don't randomly. -// Then you can use AI_ActionCastBackupRandomSpell to see if we can cast it later. -int AI_ActionCastSpellRandom(int iSpellID, int nTalent, int iRandom, object oTarget = OBJECT_SELF, int iRequirement = 0, int iLocation = FALSE, int iItemTalentValue = -1, int iPotionTalentValue = -1) -{ - // 1. We need nTalent to be over 0. -1 means an invalid spell for that talent, - // IE no spell for that talent - // - If iRequirement is 0, we consider it innate and no talent category for some - // reason. - if(nTalent > i0 || !iRequirement) - { - // Check GetHasSpell as long as we are not silenced, and have right modifier, and - // the object is seen (this is a backup for it!) - if(!GlobalSilenceSoItems && - (!iRequirement || GlobalSpellAbilityModifier >= iRequirement) && - GetHasSpell(iSpellID) && - (iLocation || GetObjectSeen(oTarget))) - { - if(d100() <= iRandom + GlobalRandomCastModifier) - { - // Make sure it is a spell, not an ability - if(iRequirement > FALSE) - { - // Attempt Concentration Check (Casting a spell, not an item) - if(AI_AttemptConcentrationCheck(oTarget)) return TRUE; - } - else - { - // Turn off all modes - remember, we can't use expertise with spellcasting! - AI_SetMeleeMode(); - } - // Set time stop stored to this spell. - AI_SetTimeStopStored(iSpellID); - // 12: "[DCR:Casting] NormalRandomSpell. [ID] " + IntToString(iSpellID) + " [Target] " + GetName(oTarget) + " [Location] " + IntToString(iLocation) - DebugActionSpeakByInt(12, oTarget, iSpellID, IntToString(iLocation)); - // We turn off hiding/searching - AI_ActionTurnOffHiding(); - // Equip the best shield we have - AI_EquipBestShield(); - // Note: 1.3 fix. Action Cast At Object will be used if we can see - // the target, even if it is a location spell - if(GetObjectSeen(oTarget)) - { - // aim at the object directly! - // - See 1.3 fix below. Basically, this should use Meta Magic normally - ActionCastSpellAtObject(iSpellID, oTarget); - } - // If location... - else //if(iLocation) - { - // Fire ActionSpellAtLocation at the given location - // 1.3 fix - Until ActionCastSpellAtLocation works with METAMAGIC - // it will cheat-cast, and decrement the spell by one, with no metamagic. - ActionCastSpellAtLocation(iSpellID, GetLocation(oTarget), METAMAGIC_NONE, TRUE); - DecrementRemainingSpellUses(OBJECT_SELF, iSpellID); - } - // Lasts...recheck items - if(AI_GetSpellCategoryHasItem(nTalent)) - { - ActionDoCommand(AI_SetItemTalentValue(nTalent)); - } - // Alway stop - we use else here, so we always do an action! :-D - return TRUE; - } - else - { - // Don't use acid fog as this (Spell 0). If we have one already set, - // this is a worse spell :-) - AI_SetBackupCastingSpellValues(iSpellID, nTalent, oTarget, iLocation, iRequirement, iItemTalentValue, iPotionTalentValue); - - // Always return FALSE. - return FALSE; - } - } - // 2. Cast from potions, or items! - // This is made simpler by adding in iItemTalentValue and iPotionTalentValue - } - // Basic items - Wands, Scrolls that might pop up. Potions too. - if(iItemTalentValue == iSpellID || - iPotionTalentValue == iSpellID) - { - if(d100() <= iRandom + GlobalRandomCastModifier) - { - if(AI_ActionCastItemEqualTo(oTarget, iSpellID, iLocation)) - { - // Lasts...recheck items - if(AI_GetSpellCategoryHasItem(nTalent)) - { - ActionDoCommand(AI_SetItemTalentValue(nTalent)); - } - return TRUE; - } - } else { // Don't use acid fog as this (Spell 0). If we have one already set, // this is a worse spell :-) - AI_SetBackupCastingSpellValues(iSpellID, nTalent, oTarget, iLocation, iRequirement, iItemTalentValue, iPotionTalentValue); + AI_SetBackupCastingSpellValues(nSpellID, oTarget, bLocation, nRequirement); // Always return FALSE. return FALSE; @@ -2669,66 +2423,61 @@ int AI_ActionCastBackupRandomSpell() if(GlobalLastSpellValid > FALSE) { object oTarget; - int iSpell, iTalent, iLocation, iItem, iPotion, iRequirement; - iSpell = GlobalLastSpellValid; + int nSpell, bLocation, nRequirement; + nSpell = GlobalLastSpellValid; // Delete again for other castings GlobalLastSpellValid = FALSE; - // 13: "[DCR:Casting] Backup spell caught: " + IntToString(iSpell) - DebugActionSpeakByInt(13, OBJECT_INVALID, iSpell); + // 13: "[DCR:Casting] Backup spell caught: " + IntToString(nSpell) + DebugActionSpeakByInt(13, OBJECT_INVALID, nSpell); // Get things from GLOBAL_LAST_SPELL_INFORMATION1 to GLOBAL...ATION5 - int iCnt = i1; + int nCnt = 1; // GET... - // talent - iTalent = GetAIInteger(GLOBAL_LAST_SPELL_INFORMATION + IntToString(iCnt)); // target - iCnt++; - oTarget = GetAIObject(GLOBAL_LAST_SPELL_INFORMATION + IntToString(iCnt)); + oTarget = GetAIObject(GLOBAL_LAST_SPELL_INFORMATION + IntToString(nCnt)); // location - iCnt++; - iLocation = GetAIInteger(GLOBAL_LAST_SPELL_INFORMATION + IntToString(iCnt)); + nCnt++; + bLocation = GetAIInteger(GLOBAL_LAST_SPELL_INFORMATION + IntToString(nCnt)); // reqirement - iCnt++; - iRequirement = GetAIInteger(GLOBAL_LAST_SPELL_INFORMATION + IntToString(iCnt)); - // item - iCnt++; - iItem = GetAIInteger(GLOBAL_LAST_SPELL_INFORMATION + IntToString(iCnt)); - // potion - iCnt++; - iPotion = GetAIInteger(GLOBAL_LAST_SPELL_INFORMATION + IntToString(iCnt)); + nCnt++; + nRequirement = GetAIInteger(GLOBAL_LAST_SPELL_INFORMATION + IntToString(nCnt)); - // Cast spell at 100% chance, and innate (already checked iRequirement) + // Cast spell at 100% chance, and innate (already checked nRequirement) // - Should cast. - if(AI_ActionCastSpell(iSpell, iTalent, oTarget, iRequirement, iLocation, iItem, iPotion)) return TRUE; + if(AI_ActionCastSpell(nSpell, oTarget, nRequirement, bLocation)) return TRUE; } return FALSE; } - -int AI_ActionCastSummonSpell(int iThingID, int iRequirement = 0, int iSummonLevel = 0) +// This will cast the spell/feat nSpellId (Or with nFeat), depending if it is a spell or a feat, +// at the summon location chosen before. Works similar to normal spells but +// at a special location. +// * If it is a feat, we use nFeat to define the feat, and nSpellId to define the +// spellability to use. +// * If nRequirement is -1, it is a feat. If 0, it is innate (as spells) +int AI_ActionCastSummonSpell(int nSpellId, int nRequirement = 0, int nSummonLevel = 0, int nFeat = 0) { // Feat - if(iRequirement == iM1) + if(nRequirement == -1) { - if(GetHasFeat(iThingID)) + // Use the new function for 1.4, to encompass spell-like-feats. + if(AI_ActionUseSpellLikeFeat(nFeat, nSpellId)) { - // 14: "[DCR:Feat] [ID] " + IntToString(iFeat) + " [Enemy] " + GetName(oObject) - DebugActionSpeakByInt(14, OBJECT_SELF, iThingID); - // talent tFeat doesn't work. - ActionUseFeat(iThingID, OBJECT_SELF); - SetAIInteger(AI_LAST_SUMMONED_LEVEL, iSummonLevel); + // 14: "[DCR:Feat] [ID] " + IntToString(nFeat) + " [Enemy] " + GetName(oObject) + DebugActionSpeakByInt(14, OBJECT_SELF, nFeat); + SetAIInteger(AI_LAST_SUMMONED_LEVEL, nSummonLevel); return TRUE; } } - else if(SpellAllies) + else { // Check GetHasSpell as long as we are not silenced, and have right modifier, and // the object is seen (this is a backup for it!) if(!GlobalSilenceSoItems && - (iRequirement == FALSE || GlobalSpellAbilityModifier >= iRequirement) && - GetHasSpell(iThingID)) + (nRequirement == FALSE || GlobalSpellAbilityModifier >= nRequirement) && + GetHasSpell(nSpellId)) { // Make sure it is a spell, not an ability - if(iRequirement > FALSE) + if(nRequirement > FALSE) { // Attempt Concentration Check (Casting a spell, not an item) if(AI_AttemptConcentrationCheck(GlobalSpellTarget)) return TRUE; @@ -2739,111 +2488,119 @@ int AI_ActionCastSummonSpell(int iThingID, int iRequirement = 0, int iSummonLeve AI_SetMeleeMode(); } // Set time stop stored to this spell. - AI_SetTimeStopStored(iThingID); - // 9: "[DCR:Casting] NormalSpell [ID] " + IntToString(iSpellID) + " [Target] " + GetName(oTarget) + " [Location] " + IntToString(iLocation) - DebugActionSpeakByInt(9, GlobalSpellTarget, iThingID); + AI_SetTimeStopStored(nSpellId); + + // 9: "[DCR:Casting] NormalSpell [ID] " + IntToString(nSpellId) + " [Target] " + GetName(oTarget) + " [Location] " + IntToString(bLocation) + DebugActionSpeakByInt(9, GlobalSpellTarget, nSpellId); + // We turn off hiding/searching AI_ActionTurnOffHiding(); // Equip the best shield we have AI_EquipBestShield(); + + // Target a special location. + location lTarget = AI_GetSummonLocation(); + // Fire ActionSpellAtLocation at the given location // 1.3 fix - Until ActionCastSpellAtLocation works with METAMAGIC // it will cheat-cast, and decrement the spell by one, with no metamagic. - ActionCastSpellAtLocation(iThingID, GlobalSummonLocation, METAMAGIC_NONE, TRUE); - DecrementRemainingSpellUses(OBJECT_SELF, iThingID); - // Lasts...recheck items - if(AI_GetSpellCategoryHasItem(SpellAllies)) - { - ActionDoCommand(AI_SetItemTalentValue(SpellAllies)); - } + ActionCastSpellAtLocation(nSpellId, lTarget, METAMAGIC_NONE, TRUE); + DecrementRemainingSpellUses(OBJECT_SELF, nSpellId); // Alway stop - we use else here, so we always do an action! :-D return TRUE; } } - // Basic items - Wands, Scrolls that might pop up - else if(ItemAllies == iThingID) - { - // We need to get what one is actually the talent number :-D - // This is actually faster, as we know that iSpellID equals one of them :-D - // Set to local integers - int nTalent, iReturn; - if(GetAIConstant(ITEM_TALENT_VALUE + IntToString(TALENT_CATEGORY_BENEFICIAL_OBTAIN_ALLIES)) == iThingID) - { - nTalent = ItemAllies; - } - // Check for valid talent (1+) - if(nTalent >= i1) - { - // Apply EffectCutsceneImmobilize. It only removes ones with no spell ID anyway :-D - AI_SpecialActionApplyItem(); - - talent tBestOfIt = GetCreatureTalentBest(nTalent, i20); - // JUST to make sure! - if(GetIsTalentValid(tBestOfIt) && - GetIdFromTalent(tBestOfIt) == iThingID && - GetTypeFromTalent(tBestOfIt) == TALENT_TYPE_SPELL) - { - AI_SetTimeStopStored(iThingID); - // 7: "[DCR:Casting] Talent(item) [TalentID] " + IntToString(GetIdFromTalent(tBestOfIt)) + " [Target] " + GetName(oTarget) + " [Location] " + IntToString(iLocation) - DebugActionSpeakByInt(7, GlobalSpellTarget, GetIdFromTalent(tBestOfIt)); - // Equip the best shield we have - AI_EquipBestShield(); - // Use this only for items, so we should not have the spell. - ActionUseTalentAtLocation(tBestOfIt, GlobalSummonLocation); - iReturn = TRUE; - } - // remove the EffectCutsceneImmobilize, if so. - AI_SpecialActionRemoveItem(); - // Lasts...recheck items - if(AI_GetSpellCategoryHasItem(nTalent)) - { - ActionDoCommand(AI_SetItemTalentValue(nTalent)); - } - return iReturn; - } - } // No summon created return FALSE; } - - -// If they have the feat, they will use it on the target, and return TRUE -// * iFeat - Feat ID to use -// * oObject - object to use it on (Can't target locations in the AI - not worth it) -// * iSummonLevel - when using a summoning feat (EG: blackguard undead) use a number here. If false, its ignored -int AI_ActionUseFeatOnObject(int iFeat, object oObject = OBJECT_SELF) +// Gets an approprate summoning location. If we are set to summon better, we +// should get a good location between us and an enemy, else, it'll just return +// our location. +location AI_GetSummonLocation() { - if(GetHasFeat(iFeat) && GetIsObjectValid(oObject)) + // Get the location to cast the summoning spell at. + // It will be a location between us and our melee target, or + // our last hostile actor, if not in 5 M, or else us + location lTarget; + // - Summon spells have a 8M, short, range. + object oTarget = OBJECT_INVALID; + if(GetSpawnInCondition(AI_FLAG_COMBAT_IMPROVED_SUMMON_TARGETING, AI_COMBAT_MASTER)) { - if(!GetHasFeatEffect(iFeat, oObject)) + oTarget = GetLastHostileActor(); + if(AI_GetTargetSanityCheck(oTarget) && GetDistanceToObject(oTarget) <= 16.0) { - // 14: "[DCR:Feat] [ID] " + IntToString(iFeat) + " [Enemy] " + GetName(oObject) - DebugActionSpeakByInt(14, oObject, iFeat); - // We turn off hiding/searching - AI_ActionTurnOffHiding(); - ActionUseFeat(iFeat, oObject); - if(oObject == OBJECT_SELF) - { - if(GetIsObjectValid(GlobalMeleeTarget)) ActionAttack(GlobalMeleeTarget); - } - return TRUE; + // Use oTarget (Last hostile actor) + // oTarget = oTarget; + } + else if(GetDistanceToObject(GlobalRangedTarget) <= 16.0) + { + // Use our GlobalRangedTarget + oTarget = GlobalRangedTarget; + } + if(GetDistanceToObject(GlobalMeleeTarget) <= 16.0) + { + // Use our GlobalMeleeTarget + oTarget = GlobalMeleeTarget; + } + else + { + // Just cast it at ourselves. + return GetLocation(OBJECT_SELF); } } - return FALSE; + else + { + // Just cast it at ourselves. + return GetLocation(OBJECT_SELF); + } + + // Taken from bioware's summon allies - half way between the targets. + // Because we get a maximum range of 16, it means the range will be 8. + vector vTarget = GetPosition(oTarget); + vector vSource = GetPosition(OBJECT_SELF); + vector vDirection = vTarget - vSource; + float fDistance = VectorMagnitude(vDirection) / 2.0; + vector vPoint = VectorNormalize(vDirection) * fDistance + vSource; + lTarget = Location(GetArea(OBJECT_SELF), vPoint, DIRECTION_NORTH); + + // Return lTarget. + return lTarget; } // If they have nFeat, they cheat-cast nSpell at oTarget. -// - This is a workaround, as some epic spells, for some reason, won't work with -// a standard ActionUseFeatOnObject()! Dammit. Beta 3 addition. -int AI_ActionUseEpicSpell(int nFeat, int nSpell, object oTarget = OBJECT_SELF) +// - This is a workaround for any feat, which acts as a spell, IE: A spell like feat, +// (a feat with casting times and so on) and more importantly, also will cast +// the nSpell if they have it anyway! so is useful for any feat.2da which +// references the spells.2da for its effects. +// 1.4: Added the fact they can be normal spells. +int AI_ActionUseSpellLikeFeat(int nFeat, int nSpell, object oTarget = OBJECT_SELF) { - if(GetHasFeat(nFeat)) + // Check for nSpell's and nFeat's effect. nSpell is probably the more important. + if(GetHasSpellEffect(nSpell, oTarget) || GetHasFeatEffect(nFeat, oTarget)) return FALSE; + + // If they have the spell (or monster ability version) + if(GetHasSpell(nSpell)) + { + // Cast it as a normal spell. Can be assigned via. monster abilties. + // Cheat cast the spell + + // We turn off hiding/searching + AI_ActionTurnOffHiding(); + + // Cast it normally. + ActionCastSpellAtObject(nSpell, oTarget); + return TRUE; + } + else if(GetHasFeat(nFeat)) { // 14: "[DCR:Feat] [ID] " + IntToString(nFeat) + " [Enemy] " + GetName(oTarget) DebugActionSpeakByInt(14, oTarget, nFeat); + // We turn off hiding/searching AI_ActionTurnOffHiding(); + // Cheat cast the spell ActionCastSpellAtObject(nSpell, oTarget, METAMAGIC_NONE, TRUE); + // Decrement casting of it. DecrementRemainingFeatUses(OBJECT_SELF, nFeat); return TRUE; @@ -2856,7 +2613,10 @@ int AI_ActionUseEpicSpell(int nFeat, int nSpell, object oTarget = OBJECT_SELF) // TRUE if they fire a grenade. int AI_AttemptGrenadeThrowing(object oTarget) { - int iReturn = FALSE; + // 1.4 Pre-beta - no items for now. + return FALSE; +/* + int bReturn = FALSE; // Check if the items is a grenade: // SPELL_GRENADE_ACID - 1d6 Acid Damge/Target, or 1 splash. // SPELL_GRENADE_CALTROPS - Up to 25 normal damage, at 1 Damage/round to an AOE @@ -2885,26 +2645,26 @@ int AI_AttemptGrenadeThrowing(object oTarget) // We fire the spell at the target if they are seen // - If SpellTargetSeen is TRUE, fire at them - int iLocation = FALSE; + int bLocation = FALSE; if(!GlobalSeenSpell) { - iLocation = TRUE; + bLocation = TRUE; } // Apply EffectCutsceneImmobilize. It only removes ones with no spell ID anyway :-D AI_SpecialActionApplyItem(); - talent tBestOfIt = GetCreatureTalentBest(TALENT_CATEGORY_HARMFUL_RANGED, i20); + talent tBestOfIt = GetCreatureTalentBest(TALENT_CATEGORY_HARMFUL_RANGED, 20); // JUST to make sure! if(GetIsTalentValid(tBestOfIt) && GetIdFromTalent(tBestOfIt) == ItemHostRanged) { - // 15: "[DCR:Casting] Grenade [ID] " + IntToString(ItemHostRanged) + " [Target] " + GetName(oTarget) + " [Location] " + IntToString(iLocation) - DebugActionSpeakByInt(15, GlobalSpellTarget, ItemHostRanged, IntToString(iLocation)); + // 15: "[DCR:Casting] Grenade [ID] " + IntToString(ItemHostRanged) + " [Target] " + GetName(oTarget) + " [Location] " + IntToString(bLocation) + DebugActionSpeakByInt(15, GlobalSpellTarget, IntToString(bLocation)); // Equip the best shield we have AI_EquipBestShield(); // Use this only for items, so we should not have the spell. - if(iLocation) + if(bLocation) { ActionUseTalentAtLocation(tBestOfIt, GetLocation(oTarget)); } @@ -2912,7 +2672,7 @@ int AI_AttemptGrenadeThrowing(object oTarget) { ActionUseTalentOnObject(tBestOfIt, oTarget); } - iReturn = TRUE; + bReturn = TRUE; } // remove the EffectCutsceneImmobilize, if so. AI_SpecialActionRemoveItem(); @@ -2921,14 +2681,13 @@ int AI_AttemptGrenadeThrowing(object oTarget) // TALENT_CATEGORY_HARMFUL_RANGED is always checked for items. ActionDoCommand(AI_SetItemTalentValue(TALENT_CATEGORY_HARMFUL_RANGED)); } - return iReturn; + return bReturn;*/ } /*:://///////////////////////////////////////////// //:: Name: GetBestSpontaeousHealingSpell //:://///////////////////////////////////////////// // This will return the best spontaeous healing spell, so: // - It uses just normal GetHasSpell for the clerical healing spells. -// - It gets set up at the start to the global "GlobalBestSpontaeousHealingSpell" //:://///////////////////////////////////////////// //:: Created By: Jasperre //::////////////////////////////////////////////*/ @@ -2968,38 +2727,30 @@ int AI_GetBestSpontaeousHealingSpell() //:://///////////////////////////////////////////*/ void AI_SetUpUs() { - int iLastSpellType, nClass1, nClass2, nClass3, nLevel1, nLevel2, nLevel3, - nState1, nState2, nState3, nUseClass, iCurrent; + int nLastSpellType, nClass1, nClass2, nClass3, nLevel1, nLevel2, nLevel3, + nState1, nState2, nState3, nUseClass, nCurrent; object oSummon; float fTotal; // We set up what intelligence we have (level). See OnSpawn for more info // Default is 10, top 10, bottom 1. - GlobalIntelligence = GetBoundriedAIInteger(AI_INTELLIGENCE, i10, i10, i1); + GlobalIntelligence = GetBoundriedAIInteger(AI_INTELLIGENCE, 10, 10, 1); // Checks the 3 classes, and returns one of them randomly based on how many they // have in that level compared to the other 2. GlobalOurHitDice = GetHitDice(OBJECT_SELF); - GlobalThisArea = GetArea(OBJECT_SELF); - GlobalOurRace = GetRacialType(OBJECT_SELF); // HP GlobalOurCurrentHP = GetCurrentHitPoints(); GlobalOurMaxHP = GetMaxHitPoints(); // Use Floats to get Decimal places. GlobalOurPercentHP = AI_GetPercentOf(GlobalOurCurrentHP, GlobalOurMaxHP); - GlobalOurSize = GetCreatureSize(OBJECT_SELF); // AI - just normal. More added/subtracted be;pw GlobalOurAC = GetAC(OBJECT_SELF); - switch(GlobalOurSize) + switch(GetCreatureSize(OBJECT_SELF)) { - case CREATURE_SIZE_TINY: GlobalOurAC += i2; break; - case CREATURE_SIZE_SMALL: GlobalOurAC += i1; break; - case CREATURE_SIZE_LARGE: GlobalOurAC -= i1; break; - case CREATURE_SIZE_HUGE: GlobalOurAC -= i2; break; + case CREATURE_SIZE_TINY: GlobalOurAC += 2; break; + case CREATURE_SIZE_SMALL: GlobalOurAC += 1; break; + case CREATURE_SIZE_LARGE: GlobalOurAC -= 1; break; + case CREATURE_SIZE_HUGE: GlobalOurAC -= 2; break; } - GlobalOurAppearance = GetAppearanceType(OBJECT_SELF); - GlobalOurGoodEvil = GetAlignmentGoodEvil(OBJECT_SELF);// Used for alignment prot. Spells. - // Weapons (in places) or objects :-P - GlobalLeftHandWeapon = GetItemInSlot(INVENTORY_SLOT_LEFTHAND); - GlobalRightHandWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND); GlobalOurBaseAttackBonus = GetBaseAttackBonus(OBJECT_SELF); // Spell Ranged Attacking if(GetSpawnInCondition(AI_FLAG_COMBAT_LONGER_RANGED_SPELLS_FIRST, AI_COMBAT_MASTER)) @@ -3007,7 +2758,7 @@ void AI_SetUpUs() SRA = TRUE; } // Set up the extra % to random cast - GlobalRandomCastModifier = GlobalIntelligence * i2; + GlobalRandomCastModifier = GlobalIntelligence * 2; // - 2% extra at 1, 20% at 10 :-) // Set if we are a global buffer @@ -3028,49 +2779,63 @@ void AI_SetUpUs() } // Our reach is the distance we can immediantly attack, normally. - GlobalOurReach = IntToFloat(GlobalOurSize * i4) + f1; + GlobalOurReach = IntToFloat(GetCreatureSize(OBJECT_SELF) * 4) + 1.0; // Sets up the class to use. fTotal = IntToFloat(GlobalOurHitDice); - nClass1 = GetClassByPosition(i1); - nClass2 = GetClassByPosition(i2); - nClass3 = GetClassByPosition(i3); - nLevel1 = GetLevelByClass(nClass1); - nLevel2 = GetLevelByClass(nClass2); - nLevel3 = GetLevelByClass(nClass3); - // Set up how much % each class occupies. - nState1 = FloatToInt((IntToFloat(nLevel1) / fTotal) * i100); - nState2 = FloatToInt((IntToFloat(nLevel2) / fTotal) * i100) + nState1; - nState3 = FloatToInt((IntToFloat(nLevel3) / fTotal) * i100) + nState2; - // Randomise the % we pick - nUseClass = d100(); - // Set the class, and that classes level. - if(nUseClass <= nState1) + nClass1 = GetClassByPosition(1); + nClass2 = GetClassByPosition(2); + nClass3 = GetClassByPosition(3); + + // If we only have one class, we buckle out here. + if(nClass2 == CLASS_TYPE_INVALID) { GlobalOurChosenClass = nClass1; - GlobalOurChosenClassLevel = nLevel1; - } - else if(nUseClass > nState1 && nUseClass <= nState2) - { - GlobalOurChosenClass = nClass2; - GlobalOurChosenClassLevel = nLevel2; + GlobalOurChosenClassLevel = GetLevelByClass(nClass1); } else { - GlobalOurChosenClass = nClass3; - GlobalOurChosenClassLevel = nLevel3; + // Else, we DO do this each round, because if we have more then one + // class, we randomly choose which one we "are", for cirtain (although + // not many) choices made in the AI. + nLevel1 = GetLevelByClass(nClass1); + nLevel2 = GetLevelByClass(nClass2); + nLevel3 = GetLevelByClass(nClass3); + // Set up how much % each class occupies. + nState1 = FloatToInt((IntToFloat(nLevel1) / fTotal) * 100); + nState2 = FloatToInt((IntToFloat(nLevel2) / fTotal) * 100) + nState1; + nState3 = FloatToInt((IntToFloat(nLevel3) / fTotal) * 100) + nState2; + // Randomise the % we pick + nUseClass = d100(); + // Set the class, and that classes level. + if(nUseClass <= nState1) + { + GlobalOurChosenClass = nClass1; + GlobalOurChosenClassLevel = nLevel1; + } + else if(nUseClass > nState1 && nUseClass <= nState2) + { + GlobalOurChosenClass = nClass2; + GlobalOurChosenClassLevel = nLevel2; + } + else + { + GlobalOurChosenClass = nClass3; + GlobalOurChosenClassLevel = nLevel3; + } } + // Intelligence based spellcaster. if(GlobalOurChosenClass == CLASS_TYPE_WIZARD) { GlobalSpellAbilityModifier = GetAbilityScore(OBJECT_SELF, ABILITY_INTELLIGENCE); - GlobalSpellBaseSaveDC = i10 + GetAbilityModifier(ABILITY_INTELLIGENCE); + GlobalSpellBaseSaveDC = 10 + GetAbilityModifier(ABILITY_INTELLIGENCE); } // Wisdom based spellcaster else if(GlobalOurChosenClass == CLASS_TYPE_DRUID || GlobalOurChosenClass == CLASS_TYPE_CLERIC) { GlobalSpellAbilityModifier = GetAbilityScore(OBJECT_SELF, ABILITY_WISDOM); - GlobalSpellBaseSaveDC = i10 + GetAbilityModifier(ABILITY_WISDOM); + GlobalSpellBaseSaveDC = 10 + GetAbilityModifier(ABILITY_WISDOM); } // Charisma else if(GlobalOurChosenClass == CLASS_TYPE_BARD || @@ -3081,41 +2846,39 @@ void AI_SetUpUs() GlobalWeAreSorcerorBard = TRUE; // Charisma based spellcaster GlobalSpellAbilityModifier = GetAbilityScore(OBJECT_SELF, ABILITY_CHARISMA); - GlobalSpellBaseSaveDC = i10 + GetAbilityModifier(ABILITY_CHARISMA); + GlobalSpellBaseSaveDC = 10 + GetAbilityModifier(ABILITY_CHARISMA); } else // Monster { // - We set ability modifier to 25, so that they cast all spells // and monster abilties - GlobalSpellAbilityModifier = i25; - GlobalSpellBaseSaveDC = i10 + GetAbilityModifier(ABILITY_CHARISMA); + GlobalSpellAbilityModifier = 25; + GlobalSpellBaseSaveDC = 10 + GetAbilityModifier(ABILITY_CHARISMA); } // Set up GlobalSaveStupidity, 10 - Intelligence // 0 is better then 10! Bascially, if they are immune (EG: Massive fortitude // fighter VS death save) then taking 10 from thier save stat means a lower // intelligence caster will fire it against immune beings. // - Also used in AOE checking. - GlobalSaveStupidity = i10 - GlobalIntelligence; - // Spontaeous healing spell - GlobalBestSpontaeousHealingSpell = AI_GetBestSpontaeousHealingSpell(); + GlobalSaveStupidity = 10 - GlobalIntelligence; // Set up SR roll // - 20 + Class level + 2 for spell penetration, +4 for greater. // - We always take it as a 20 - but we set this for a huge amount. // NOTE: we check HD only - because of monster abilities. - GlobalSpellPenetrationRoll = GlobalOurHitDice + i20; + GlobalSpellPenetrationRoll = GlobalOurHitDice + 20; // Check for feats if(GetHasFeat(FEAT_EPIC_SPELL_PENETRATION)) { - GlobalSpellPenetrationRoll += i6; + GlobalSpellPenetrationRoll += 6; } else if(GetHasFeat(FEAT_GREATER_SPELL_PENETRATION)) { - GlobalSpellPenetrationRoll += i4; + GlobalSpellPenetrationRoll += 4; } else if(GetHasFeat(FEAT_SPELL_PENETRATION)) { - GlobalSpellPenetrationRoll += i2; + GlobalSpellPenetrationRoll += 2; } // Summon checking (special) // Used for summoned creatures. @@ -3123,26 +2886,26 @@ void AI_SetUpUs() if(GetIsObjectValid(oSummon) && !GetIsDead(oSummon)) { // If valid, we can use the level of the last cast to check if valid. - int iCurrentSummonLevel = GetAIInteger(AI_LAST_SUMMONED_LEVEL); + int nCurrentSummonLevel = GetAIInteger(AI_LAST_SUMMONED_LEVEL); // - Never replace epic, or elemental sparm, or balors (10, 11/12) // - Never replace sorcerors or bards - if(!GlobalWeAreSorcerorBard && iCurrentSummonLevel <= i9) + if(!GlobalWeAreSorcerorBard && nCurrentSummonLevel <= 9) { // We check thier HP. If they are under x6% and under 30HP, we may summon // a summon over this one that exsists. - iCurrent = GetCurrentHitPoints(oSummon); - if(((iCurrent * i6) < GetMaxHitPoints(oSummon)) && (iCurrent <= i30)) + nCurrent = GetCurrentHitPoints(oSummon); + if(((nCurrent * 6) < GetMaxHitPoints(oSummon)) && (nCurrent <= 30)) { // Make it -1, so that we will say, summon a level 5 summon // over a damaged level 6, but never a level 2 summon in replacement. - GlobalCanSummonSimilarLevel = iCurrentSummonLevel - i1; + GlobalCanSummonSimilarLevel = nCurrentSummonLevel - 1; } } // If we have not set GlobalCanSummonSimilarLevel, we set it so we // should not summon anything at all! if(!GlobalCanSummonSimilarLevel) { - GlobalCanSummonSimilarLevel = i100; + GlobalCanSummonSimilarLevel = 100; } } else @@ -3151,112 +2914,6 @@ void AI_SetUpUs() DeleteAIInteger(AI_LAST_SUMMONED_LEVEL); GlobalCanSummonSimilarLevel = FALSE; } - - // Right: - // - If we have valid category, we will set it to the talent value. - // - We then use this in the spells, tightens up some things :-) - // - Use 16 as another "any other" category. This isn't checked for items/ - - // Sets each one to TRUE if we have any of that category (and a spell) - int iLocalSpellInteger = GetLocalInt(OBJECT_SELF, AI_VALID_SPELLS); - // Any? - if(iLocalSpellInteger & AI_VALID_OTHER_SPELL) SpellOtherSpell = i23;// New one - // Conditional - if(iLocalSpellInteger & AI_VALID_TALENT_BENEFICIAL_CONDITIONAL_AREAEFFECT) SpellConSinTar = TALENT_CATEGORY_BENEFICIAL_CONDITIONAL_SINGLE; - if(iLocalSpellInteger & AI_VALID_TALENT_BENEFICIAL_CONDITIONAL_SINGLE) SpellConAre = TALENT_CATEGORY_BENEFICIAL_CONDITIONAL_AREAEFFECT; - // Enchancement - if(iLocalSpellInteger & AI_VALID_TALENT_BENEFICIAL_ENHANCEMENT_AREAEFFECT) SpellEnhAre = TALENT_CATEGORY_BENEFICIAL_ENHANCEMENT_AREAEFFECT; - if(iLocalSpellInteger & AI_VALID_TALENT_BENEFICIAL_ENHANCEMENT_SELF) SpellEnhSelf = TALENT_CATEGORY_BENEFICIAL_ENHANCEMENT_SELF; - if(iLocalSpellInteger & AI_VALID_TALENT_BENEFICIAL_ENHANCEMENT_SINGLE) SpellEnhSinTar = TALENT_CATEGORY_BENEFICIAL_ENHANCEMENT_SINGLE; - // Other - if(iLocalSpellInteger & AI_VALID_TALENT_BENEFICIAL_OBTAIN_ALLIES) SpellAllies = TALENT_CATEGORY_BENEFICIAL_OBTAIN_ALLIES; - if(iLocalSpellInteger & AI_VALID_TALENT_PERSISTENT_AREA_OF_EFFECT) SpellAura = TALENT_CATEGORY_PERSISTENT_AREA_OF_EFFECT; - // Protection - if(iLocalSpellInteger & AI_VALID_TALENT_BENEFICIAL_PROTECTION_AREAEFFECT) SpellProAre = TALENT_CATEGORY_BENEFICIAL_PROTECTION_AREAEFFECT; - if(iLocalSpellInteger & AI_VALID_TALENT_BENEFICIAL_PROTECTION_SELF) SpellProSelf = TALENT_CATEGORY_BENEFICIAL_PROTECTION_SELF; - if(iLocalSpellInteger & AI_VALID_TALENT_BENEFICIAL_PROTECTION_SINGLE) SpellProSinTar = TALENT_CATEGORY_BENEFICIAL_PROTECTION_SINGLE; - // Hostile/Harmful. - if(iLocalSpellInteger & AI_VALID_TALENT_HARMFUL_AREAEFFECT_DISCRIMINANT) SpellHostAreaDis = TALENT_CATEGORY_HARMFUL_AREAEFFECT_DISCRIMINANT; - if(iLocalSpellInteger & AI_VALID_TALENT_HARMFUL_AREAEFFECT_INDISCRIMINANT) SpellHostAreaInd = TALENT_CATEGORY_HARMFUL_AREAEFFECT_INDISCRIMINANT; - if(iLocalSpellInteger & AI_VALID_TALENT_HARMFUL_RANGED) SpellHostRanged = TALENT_CATEGORY_HARMFUL_RANGED; - if(iLocalSpellInteger & AI_VALID_TALENT_HARMFUL_TOUCH) SpellHostTouch = TALENT_CATEGORY_HARMFUL_TOUCH; - - // Breath weapon - if(iLocalSpellInteger & AI_VALID_TALENT_DRAGONS_BREATH) SpellHostBreath = TALENT_CATEGORY_DRAGONS_BREATH; - - // ANY spells valid? - if(iLocalSpellInteger & AI_VALID_ANY_SPELL) SpellAnySpellValid = TRUE; - - // Hostile feats - if(iLocalSpellInteger & AI_VALID_TALENT_HARMFUL_MELEE) ValidFeats = TRUE; - - // Now, what about, say, ITEMS?!?! - // Items/Spells to reduce lag. - - // If no items, then we will set iLastSpellType to 0 so that none are reset - if(!GetSpawnInCondition(AI_FLAG_OTHER_LAG_NO_ITEMS, AI_OTHER_MASTER)) - { -//*1*/ SpellHostAreaDis, ItemHostAreaDis, - ItemHostAreaDis = GetAIConstant(ITEM_TALENT_VALUE + IntToString(TALENT_CATEGORY_HARMFUL_AREAEFFECT_DISCRIMINANT)); -//*2*/ SpellHostRanged, ItemHostRanged, - ItemHostRanged = GetAIConstant(ITEM_TALENT_VALUE + IntToString(TALENT_CATEGORY_HARMFUL_RANGED)); -//*3*/ SpellHostTouch, ItemHostTouch, - ItemHostTouch = GetAIConstant(ITEM_TALENT_VALUE + IntToString(TALENT_CATEGORY_HARMFUL_TOUCH)); -//*6*/ SpellConAre, ItemConAre, - ItemConAre = GetAIConstant(ITEM_TALENT_VALUE + IntToString(TALENT_CATEGORY_BENEFICIAL_CONDITIONAL_AREAEFFECT)); -//*7*/ SpellConSinTar, ItemConSinTar, - ItemConSinTar = GetAIConstant(ITEM_TALENT_VALUE + IntToString(TALENT_CATEGORY_BENEFICIAL_CONDITIONAL_SINGLE)); -//*8*/ SpellEnhAre, ItemEnhAre, - ItemEnhAre = GetAIConstant(ITEM_TALENT_VALUE + IntToString(TALENT_CATEGORY_BENEFICIAL_ENHANCEMENT_AREAEFFECT)); -//*9*/ SpellEnhSinTar, ItemEnhSinTar, - ItemEnhSinTar = GetAIConstant(ITEM_TALENT_VALUE + IntToString(TALENT_CATEGORY_BENEFICIAL_ENHANCEMENT_SINGLE)); -//*10*/ SpellEnhSelf, ItemEnhSelf, - ItemEnhSelf = GetAIConstant(ITEM_TALENT_VALUE + IntToString(TALENT_CATEGORY_BENEFICIAL_ENHANCEMENT_SELF)); -//*11*/ SpellHostAreaInd, ItemHostAreaInd, - ItemHostAreaInd = GetAIConstant(ITEM_TALENT_VALUE + IntToString(TALENT_CATEGORY_HARMFUL_AREAEFFECT_INDISCRIMINANT)); -//*12*/ SpellProSelf, ItemProSelf, - ItemProSelf = GetAIConstant(ITEM_TALENT_VALUE + IntToString(TALENT_CATEGORY_BENEFICIAL_PROTECTION_SELF)); -//*13*/ SpellProSinTar, ItemProSinTar, - ItemProSinTar = GetAIConstant(ITEM_TALENT_VALUE + IntToString(TALENT_CATEGORY_BENEFICIAL_PROTECTION_SINGLE)); -//*14*/ SpellProAre, ItemProAre, - ItemProAre = GetAIConstant(ITEM_TALENT_VALUE + IntToString(TALENT_CATEGORY_BENEFICIAL_PROTECTION_AREAEFFECT)); -//*15*/ SpellAllies, ItemAllies, - ItemAllies = GetAIConstant(ITEM_TALENT_VALUE + IntToString(TALENT_CATEGORY_BENEFICIAL_OBTAIN_ALLIES)); -//*18*/ PotionCon, -//*20*/ PotionPro, -//*21*/ PotionEnh, - // These are general talents, Always set because we can use these parrallel to spells. - tPotionCon = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_CONDITIONAL_POTION, i20); - tPotionPro = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_PROTECTION_POTION, i20); - tPotionEnh = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_ENHANCEMENT_POTION, i20); - // Potions. We do use talents for these to be safe! - // No worries if it is 0 or nothing, we compare them not to acid fog ever. - PotionCon = GetIdFromTalent(tPotionCon); - PotionPro = GetIdFromTalent(tPotionPro); - PotionEnh = GetIdFromTalent(tPotionEnh); - } - - // We got any potions? - if(PotionCon || PotionPro || PotionEnh) GobalPotionsValid = TRUE; - - // We got any items? - if(ItemAllies || ItemConSinTar || ItemConAre || ItemProSelf || ItemProSinTar || - ItemProAre || ItemEnhSelf || ItemEnhSinTar || ItemEnhAre || ItemHostAreaDis || - ItemHostAreaInd || ItemHostRanged || ItemHostTouch) GobalOtherItemsValid = TRUE; - - // Healing Kits - int iHealLeft = GetAIInteger(AI_VALID_HEALING_KITS); - if(iHealLeft) - { - // Get the kit - GlobalHealingKit = GetAIObject(AI_VALID_HEALING_KIT_OBJECT); - // Oh, if we don't have one, re-set them, and only them. - if(!GetIsObjectValid(GlobalHealingKit) && iHealLeft >= i2) - { - SetAIInteger(RESET_HEALING_KITS, TRUE); - ExecuteScript(FILE_RE_SET_WEAPONS, OBJECT_SELF); - } - } } /*:://///////////////////////////////////////////// //:: Name: AI_GetNearbyFleeObject @@ -3267,12 +2924,12 @@ void AI_SetUpUs() object AI_GetNearbyFleeObject() { object oReturn, oGroup, oEndReturn; - int iCnt; + int nCnt; string sCheck; if(GetSpawnInCondition(AI_FLAG_FLEEING_FLEE_TO_NEAREST_NONE_SEEN, AI_TARGETING_FLEE_MASTER)) { oReturn = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, - OBJECT_SELF, i1, + OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_NOT_SEEN_AND_NOT_HEARD, CREATURE_TYPE_IS_ALIVE, TRUE); if(GetIsObjectValid(oReturn)) // Need LOS check @@ -3287,19 +2944,19 @@ object AI_GetNearbyFleeObject() { // We need to get the nearest of sCheck objects we cannot see nor hear, and // over 6 meters just in case. - iCnt = i1; - oReturn = GetNearestObjectByTag(sCheck, OBJECT_SELF, iCnt); + nCnt = 1; + oReturn = GetNearestObjectByTag(sCheck, OBJECT_SELF, nCnt); while(GetIsObjectValid(oReturn)) { // this should be simple enough to break when the object is valid. if(!GetObjectSeen(oReturn) && !GetObjectHeard(oReturn) && - GetDistanceToObject(oReturn) > f6) // (must be same area) + GetDistanceToObject(oReturn) > 6.0) // (must be same area) { // Stop if valid return oReturn; } - iCnt++; - oReturn = GetNearestObjectByTag(sCheck, OBJECT_SELF, iCnt); + nCnt++; + oReturn = GetNearestObjectByTag(sCheck, OBJECT_SELF, nCnt); } if(!GetIsObjectValid(oReturn)) { @@ -3320,33 +2977,34 @@ object AI_GetNearbyFleeObject() // At 4-7, we run to the best ally group, within 35M, or an ally who is +5 our HD. // At 8+, we run to the best group, in 70M, or an ally who is +8 our HD, and we shout for help (HB) - if(GlobalIntelligence <= i3) + if(GlobalIntelligence <= 3) { // Don't care if not valid! oReturn = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, - OBJECT_SELF, i1, + OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_NOT_SEEN_AND_NOT_HEARD, CREATURE_TYPE_IS_ALIVE, TRUE); return oReturn; } // Counters ETC - int iBestAllyGroupTotal, iCurrentGroupHD, nCnt, iGroupCnt, IfHigherBreak; + int nBestAllyGroupTotal, nCurrentGroupHD, nGroupCnt, nIfHigherBreak; // Set floats float fMaxCheckForGroup, fMaxGroupRange; // Check range (Ie people we get near to us, need to be in this range) fMaxCheckForGroup = 100.0;// 10 tiles - if(GlobalIntelligence >= i8) fMaxCheckForGroup *= i2; // Double check range. - fMaxGroupRange = f15;// Default. No need to change. + if(GlobalIntelligence >= 8) fMaxCheckForGroup *= 2; // Double check range. + fMaxGroupRange = 15.0;// Default. No need to change. // We break when we have a group totaling some value of our HD... // It goes up as intelligence does.(IE 4, 5, 6, 7, 8, 9 or 10 * HD/2 + 1) - IfHigherBreak = GlobalOurHitDice * ((GlobalIntelligence / i2) + i1); + nIfHigherBreak = GlobalOurHitDice * ((GlobalIntelligence / 2) + 1); // Note to self: THis means highest intelligence runs futhest away, hopefully smarter. - // Note: Need an acceptable limit. 10 * 20 is 200, max 100 though. - if(IfHigherBreak > i100) IfHigherBreak = i100; + // Note: Need an acceptable limit. 10 * 20 is 200, now max 140 with + // level 40 creatures running around. + if(nIfHigherBreak > 140) nIfHigherBreak = 140; - nCnt = i1;// Start at 1 nearest. + nCnt = 1;// Start at 1 nearest. // Nearest ally is got...we use not seen/not heard, not PC and friendly. // Making it oReturn might return something at the very least. oReturn = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, @@ -3357,36 +3015,36 @@ object AI_GetNearbyFleeObject() while(GetIsObjectValid(oReturn) && GetDistanceToObject(oReturn) <= fMaxCheckForGroup) { // Loop the people around him, - iCurrentGroupHD = GetHitDice(oReturn); - iGroupCnt = i1; + nCurrentGroupHD = GetHitDice(oReturn); + nGroupCnt = 1; oGroup = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, - oReturn, iGroupCnt, + oReturn, nGroupCnt, CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_NOT_PC, CREATURE_TYPE_PERCEPTION, PERCEPTION_NOT_SEEN_AND_NOT_HEARD); - // Remeber 15M range limit. + // Remember 15M range limit. while(GetIsObjectValid(oGroup) && GetDistanceBetween(oReturn, oGroup) <= fMaxGroupRange) { - iCurrentGroupHD += GetHitDice(oGroup); + nCurrentGroupHD += GetHitDice(oGroup); // Get next group object - iGroupCnt++; + nGroupCnt++; oGroup = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, - oReturn, iGroupCnt, + oReturn, nGroupCnt, CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_NOT_PC, CREATURE_TYPE_PERCEPTION, PERCEPTION_NOT_SEEN_AND_NOT_HEARD); } - // Sets the ally, if got lots of allies. (Or a mass of HD) - if(iCurrentGroupHD > iBestAllyGroupTotal) + // Break time. + // It is (Int * HD/2 + 1), max 140. Shouldn't be too bad. + if(nCurrentGroupHD > nIfHigherBreak) { - iBestAllyGroupTotal = iCurrentGroupHD; + // Return this person + return oReturn; + } + // Sets the ally, if got lots of allies. (Or a mass of HD) + else if(nCurrentGroupHD > nBestAllyGroupTotal) + { + nBestAllyGroupTotal = nCurrentGroupHD; oEndReturn = oReturn; - // Break time. - // It is (Int * HD/2 + 1), max 100. Shouldn't be too bad. - if(iCurrentGroupHD >= IfHigherBreak) - { - // Return the object - return oReturn; - } } nCnt++; oReturn = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, @@ -3403,31 +3061,31 @@ object AI_GetNearbyFleeObject() TRUE if the spell is one recorded as being cast before in time stop. - Checks Global "Are we in time stop?" and returns FALSE if not in time stop //:://///////////////////////////////////////////*/ -int AI_CompareTimeStopStored(int nSpell, int nSpell2 = 0, int nSpell3 = 0, int nSpell4 = 0) +int AI_CompareTimeStopStored(int nSpell1, int nSpell2 = AI_SPELL_INVALID, int nSpell3 = AI_SPELL_INVALID, int nSpell4 = AI_SPELL_INVALID) { // Set array size is under 0, IE no array, stop. - if(GlobalTimeStopArraySize < i0) return FALSE; + if(GlobalTimeStopArraySize < 0) return FALSE; if(GlobalInTimeStop) { - int iSpell = iM1; - int iCnt; - if(GlobalTimeStopArraySize == i0) + int nSpell = AI_SPELL_INVALID; + int nCnt; + if(GlobalTimeStopArraySize == 0) { GlobalTimeStopArraySize = GetAIInteger(TIME_STOP_LAST_ARRAY_SIZE); - if(GlobalTimeStopArraySize == i0) + if(GlobalTimeStopArraySize == 0) { - GlobalTimeStopArraySize = iM1; + GlobalTimeStopArraySize = -1; } } - if(GlobalTimeStopArraySize > i0) + if(GlobalTimeStopArraySize > 0) { - for(iCnt = i1; iCnt <= GlobalTimeStopArraySize; iCnt++) + for(nCnt = 1; nCnt <= GlobalTimeStopArraySize; nCnt++) { - iSpell = GetAIConstant(TIME_STOP_LAST_ + IntToString(iCnt)); - if(iSpell == nSpell || - iSpell == nSpell2 || - iSpell == nSpell3 || - iSpell == nSpell4) + nSpell = GetAIConstant(TIME_STOP_LAST_ + IntToString(nCnt)); + if(nSpell == nSpell1 || + nSpell == nSpell2 || + nSpell == nSpell3 || + nSpell == nSpell4) { return TRUE; } @@ -3448,11 +3106,11 @@ int AI_CompareTimeStopStored(int nSpell, int nSpell2 = 0, int nSpell3 = 0, int n object AI_GetBestFriendyAreaSpellTarget(float fRange, float fSpread, int nShape) { object oGroupies, oSpellTarget, oTarget; - int iCountOnPerson, iMostOnPerson, nCnt; + int nCountOnPerson, nMostOnPerson, nCnt; location lTarget; // Will always at least return ourselves. oSpellTarget = OBJECT_SELF; - nCnt = i1; + nCnt = 1; // Gets the nearest friend...the loops takes care of range. oTarget = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN + IntToString(nCnt)); // Start loop. Checks range here. @@ -3460,7 +3118,7 @@ object AI_GetBestFriendyAreaSpellTarget(float fRange, float fSpread, int nShape) { lTarget = GetLocation(oTarget); // Starts the count at 0, as first object in shape will also include the target. - iCountOnPerson = i0; + nCountOnPerson = 0; // Reset/Start counting the spread on oTarget. oGroupies = GetFirstObjectInShape(nShape, fSpread, lTarget); // If oGroupies is invalid, nothing. @@ -3469,13 +3127,13 @@ object AI_GetBestFriendyAreaSpellTarget(float fRange, float fSpread, int nShape) // Only add one if the person is an friend if(GetIsFriend(oGroupies)) { - iCountOnPerson++; + nCountOnPerson++; } oGroupies = GetNextObjectInShape(nShape, fSpread, lTarget); } - if(iCountOnPerson > iMostOnPerson) + if(nCountOnPerson > nMostOnPerson) { - iMostOnPerson = iCountOnPerson; + nMostOnPerson = nCountOnPerson; oSpellTarget = oTarget; } nCnt++; @@ -3484,66 +3142,66 @@ object AI_GetBestFriendyAreaSpellTarget(float fRange, float fSpread, int nShape) // Will always return self if anything return oSpellTarget; } END UNCOMMENT*/ -// If the target will always save against iSaveType, and will take no damage, returns TRUE +// If the target will always save against nSaveType, and will take no damage, returns TRUE // * Target is GlobalSpellTarget. Save is GlobalSpellTargetWill ETC. -// * iSaveType - SAVING_THROW WILL/REFLEX/FORTITUDE -// * iSpellLevel - Level of the spell being cast. -int AI_SaveImmuneSpellTarget(int iSaveType, int iSpellLevel) +// * nSaveType - SAVING_THROW WILL/REFLEX/FORTITUDE +// * nSpellLevel - Level of the spell being cast. +int AI_SaveImmuneSpellTarget(int nSaveType, int nSpellLevel) { - if(iSaveType == SAVING_THROW_FORT) + if(nSaveType == SAVING_THROW_FORT) { // Basic one here. Some addition and comparison. - if(GlobalSpellTargetFort - GlobalSaveStupidity >= (GlobalSpellBaseSaveDC + iSpellLevel)) return TRUE; + if(GlobalSpellTargetFort - GlobalSaveStupidity >= (GlobalSpellBaseSaveDC + nSpellLevel)) return TRUE; } - else if(iSaveType == SAVING_THROW_REFLEX) + else if(nSaveType == SAVING_THROW_REFLEX) { // Evasion - full damaged saved if the save is sucessful. if(GetHasFeat(FEAT_EVASION, GlobalSpellTarget) || GetHasFeat(FEAT_IMPROVED_EVASION, GlobalSpellTarget)) { - if(GlobalSpellTargetReflex - GlobalSaveStupidity >= (GlobalSpellBaseSaveDC + iSpellLevel)) return TRUE; + if(GlobalSpellTargetReflex - GlobalSaveStupidity >= (GlobalSpellBaseSaveDC + nSpellLevel)) return TRUE; } } - else if(iSaveType == SAVING_THROW_WILL) + else if(nSaveType == SAVING_THROW_WILL) { // Slippery mind has a re-roll. 1.3 - Ignore - if(GlobalSpellTargetWill - GlobalSaveStupidity >= (GlobalSpellBaseSaveDC + iSpellLevel)) + if(GlobalSpellTargetWill - GlobalSaveStupidity >= (GlobalSpellBaseSaveDC + nSpellLevel)) { return TRUE; } } return FALSE; } -// If the target will always save against iSaveType, and will take no damage, returns TRUE +// If the target will always save against nSaveType, and will take no damage, returns TRUE // * oTarget - who saving against spell. -// * iSaveType - SAVING_THROW WILL/REFLEX/FORTITUDE +// * nSaveType - SAVING_THROW WILL/REFLEX/FORTITUDE // * The save used is GetReflexSavingThrow* ETC. -// * iSpellLevel - Level of the spell being cast. -int AI_SaveImmuneAOE(object oTarget, int iSaveType, int iSpellLevel) +// * nSpellLevel - Level of the spell being cast. +int AI_SaveImmuneAOE(object oTarget, int nSaveType, int nSpellLevel) { // GlobalSaveStupidity = 10 - Intelligence. Basically, lower intellgence // will fire spells which may do nothing more often. // Return if no level (innate ability normally) - if(iSpellLevel == FALSE) return FALSE; - if(iSaveType == SAVING_THROW_FORT) + if(nSpellLevel == FALSE) return FALSE; + if(nSaveType == SAVING_THROW_FORT) { // Basic one here. Some addition and comparison. - if(GetFortitudeSavingThrow(oTarget) - GlobalSaveStupidity >= (GlobalSpellBaseSaveDC + iSpellLevel)) return TRUE; + if(GetFortitudeSavingThrow(oTarget) - GlobalSaveStupidity >= (GlobalSpellBaseSaveDC + nSpellLevel)) return TRUE; } - else if(iSaveType == SAVING_THROW_REFLEX) + else if(nSaveType == SAVING_THROW_REFLEX) { // Evasion - full damaged saved if the save is sucessful. if(GetHasFeat(FEAT_EVASION, oTarget) || GetHasFeat(FEAT_IMPROVED_EVASION, oTarget)) { - if(GetReflexSavingThrow(oTarget)- GlobalSaveStupidity >= (GlobalSpellBaseSaveDC + iSpellLevel)) return TRUE; + if(GetReflexSavingThrow(oTarget)- GlobalSaveStupidity >= (GlobalSpellBaseSaveDC + nSpellLevel)) return TRUE; } } - else if(iSaveType == SAVING_THROW_WILL) + else if(nSaveType == SAVING_THROW_WILL) { // Slippery mind has a re-roll. We ignore in 1.3 - if(GetWillSavingThrow(oTarget) - GlobalSaveStupidity >= (GlobalSpellBaseSaveDC + iSpellLevel)) + if(GetWillSavingThrow(oTarget) - GlobalSaveStupidity >= (GlobalSpellBaseSaveDC + nSpellLevel)) { return TRUE; } @@ -3564,26 +3222,9 @@ int AI_SpellResistanceImmune(object oTarget) { return TRUE; } - // Note: REmoved monk feat, and spell resistance spell, but not sure if + // Note: Removed monk feat, and spell resistance spell, but not sure if // it checks alignment-orientated SR's... -/* if(GlobalOurGoodEvil != ALIGNMENT_NEUTRAL) - { - // Alinment protection (highest) is a SR 25 - if(GlobalOurGoodEvil == ALIGNMENT_GOOD) - { - if(GetHasSpellEffect(SPELL_UNHOLY_AURA)) - { - if(i25 >= GlobalSpellPenetrationRoll) return TRUE; - } - } - else if(GlobalOurGoodEvil == ALIGNMENT_EVIL) - { - if(GetHasSpellEffect(SPELL_HOLY_AURA)) - { - if(i25 >= GlobalSpellPenetrationRoll) return TRUE; - } - } - } */ + // 1.4: Removed redudant code. Even if it isn't checked, not much is lost. return FALSE; } /*:://///////////////////////////////////////////// @@ -3594,60 +3235,61 @@ int AI_SpellResistanceImmune(object oTarget) //::////////////////////////////////////////////*/ int AI_GetSpellLevelEffect(object oTarget) { - int iNatural = GetLocalInt(oTarget, AI_SPELL_IMMUNE_LEVEL); + int nNatural = GetLocalInt(oTarget, AI_SPELL_IMMUNE_LEVEL); // Stop here, if natural is over 4 - if(iNatural > i4) return iNatural; + if(nNatural > 4) return nNatural; // Big globe affects 4 or lower spells - if(GetHasSpellEffect(SPELL_GLOBE_OF_INVULNERABILITY, oTarget) || iNatural >= i4) - return i4; + if(GetHasSpellEffect(SPELL_GLOBE_OF_INVULNERABILITY, oTarget) || nNatural >= 4) + return 4; // Minor globe is 3 or under if(GetHasSpellEffect(SPELL_MINOR_GLOBE_OF_INVULNERABILITY, oTarget) || // Shadow con version GetHasSpellEffect(SPELL_GREATER_SHADOW_CONJURATION_MINOR_GLOBE, oTarget) || - iNatural >= i3) - return i3; + nNatural >= 3) + return 3; // 2 and under is ethereal visage. - if(GetHasSpellEffect(SPELL_ETHEREAL_VISAGE, oTarget) || iNatural >= i2) - return i2; + if(GetHasSpellEffect(SPELL_ETHEREAL_VISAGE, oTarget) || nNatural >= 2) + return 2; // Ghostly Visarge affects 1 or 0 level spells, and any spell immunity. - if(GetHasSpellEffect(SPELL_GHOSTLY_VISAGE, oTarget) || iNatural >= i1 || + if(GetHasSpellEffect(SPELL_GHOSTLY_VISAGE, oTarget) || nNatural >= 1 || // Or shadow con version. GetHasSpellEffect(SPELL_GREATER_SHADOW_CONJURATION_MIRROR_IMAGE, oTarget)) - return i1; - // Return iNatural, which is 0-9 + return 1; + // Return nNatural, which is 0-9 return FALSE; } - -int AI_GetSpellLevelEffectAOE(object oTarget, int iLevel = 9) +// Input oTarget and nLevel and it will check if they are automatically +// immune to the spell being cast. +int AI_GetSpellLevelEffectAOE(object oTarget, int nLevel = 9) { // Return if no level (innate ability normally) - if(iLevel == FALSE) return FALSE; + if(nLevel == FALSE) return FALSE; // Checks any NPC natural total spell immunities (like globes, but on hides) // - On PC's, the local will return 0. this saves an extra !GetIsPC check. - if(iLevel <= GetLocalInt(oTarget, AI_SPELL_IMMUNE_LEVEL)) + if(nLevel <= GetLocalInt(oTarget, AI_SPELL_IMMUNE_LEVEL)) { return TRUE; } // Big globe affects 4 or lower spells - if(iLevel <= i4 && GetHasSpellEffect(SPELL_GLOBE_OF_INVULNERABILITY, oTarget)) + if(nLevel <= 4 && GetHasSpellEffect(SPELL_GLOBE_OF_INVULNERABILITY, oTarget)) { return TRUE; } // Minor globe is 3 or under - if(iLevel <= i3 && (GetHasSpellEffect(SPELL_MINOR_GLOBE_OF_INVULNERABILITY, oTarget) || + if(nLevel <= 3 && (GetHasSpellEffect(SPELL_MINOR_GLOBE_OF_INVULNERABILITY, oTarget) || // Shadow con version GetHasSpellEffect(SPELL_GREATER_SHADOW_CONJURATION_MINOR_GLOBE, oTarget))) { return TRUE; } // 2 and under is ethereal visage. - if(iLevel <= i2 && GetHasSpellEffect(SPELL_ETHEREAL_VISAGE, oTarget)) + if(nLevel <= 2 && GetHasSpellEffect(SPELL_ETHEREAL_VISAGE, oTarget)) { return TRUE; } // 1 and under is ghostly visage. - if(iLevel <= i1 && (GetHasSpellEffect(SPELL_GHOSTLY_VISAGE, oTarget) || + if(nLevel <= 1 && (GetHasSpellEffect(SPELL_GHOSTLY_VISAGE, oTarget) || GetHasSpellEffect(SPELL_GREATER_SHADOW_CONJURATION_MIRROR_IMAGE))) { return TRUE; @@ -3657,13 +3299,14 @@ int AI_GetSpellLevelEffectAOE(object oTarget, int iLevel = 9) } // Returns TRUE if any of the checks the oGroupTarget is immune to. -int AI_AOEDeathNecroCheck(object oGroupTarget, int iNecromanticSpell, int iDeathImmune) +int AI_AOEDeathNecroCheck(object oGroupTarget, int bNecromanticSpell, int bDeathImmune) { - if(iNecromanticSpell) + if(bNecromanticSpell) { - if(AI_GetAIHaveSpellsEffect(GlobalHasDeathWardSpell, oGroupTarget)) return TRUE; + if(GetHasSpellEffect(SPELL_DEATH_WARD, oGroupTarget) || + GetHasSpellEffect(SPELL_UNDEATHS_ETERNAL_FOE, oGroupTarget)) return TRUE; } - if(iDeathImmune) + if(bDeathImmune) { return GetIsImmune(oGroupTarget, IMMUNITY_TYPE_DEATH); } @@ -3677,22 +3320,31 @@ int AI_AOEDeathNecroCheck(object oGroupTarget, int iNecromanticSpell, int iDeath * fRange - Within fRange (fTouchRange 2.25, fShortRange 8.0, fMediumRange 20.0, fLongRange = 40.0) * fSpread - Radius Size - RADIUS_SIZE_* constants (1.67 to 10.0M) * nLevel - Used for saving throws/globe checks. Level of the spell added to save checks - * iSaveType = FALSE - SAVING_THROW_FORT/REFLEX/WILL. Not type, but the main save applied with it. + * nSaveType = FALSE - SAVING_THROW_FORT/REFLEX/WILL. Not type, but the main save applied with it. * nShape = SHAPE_SPHERE - SHAPE_* constants. - * nFriendlyFire = FALSE - Can this hurt allies? Best thing is to put + * bFriendlyFire = FALSE - Can this hurt allies? Best thing is to put GlobalFriendlyFireHostile - GetIsReactionTypeHostile(oTarget) == TRUE GlobalFriendlyFireFriendly - GetIsReactionTypeFriendly(oTarget) == FALSE FALSE - Cannot hurt allies (GetIsEnemy/!GetIsFriend used) - * iDeathImmune = FALSE - Does it use a death save? (!GetIsImmune) - * iNecromanticSpell = FALSE - Is it a necromancy spell? Undead are also checked in this. + * bDeathImmune = FALSE - Does it use a death save? (!GetIsImmune) + * bNecromanticSpell = FALSE - Is it a necromancy spell? Undead are also checked in this. + + 1.4 change: Cones ignore bFriendlyFire. + 1.4: MAYBE: should make it so fRange is ignored - since if we want SRA, we + will loop the SpellAllSpells() up to 4 times. //::////////////////////////////////////////////// //:: Created By: Jasperre //::////////////////////////////////////////////*/ -object AI_GetBestAreaSpellTarget(float fRange, float fSpread, int nLevel, int iSaveType = FALSE, int nShape = SHAPE_SPHERE, int nFriendlyFire = FALSE, int iDeathImmune = FALSE, int iNecromanticSpell = FALSE) +object AI_GetBestAreaSpellTarget(float fRange, float fSpread, int nLevel, int nSaveType = FALSE, int nShape = SHAPE_SPHERE, int bFriendlyFire = FALSE, int bDeathImmune = FALSE, int bNecromanticSpell = FALSE) { + // If it is a cone, we ignore bFriendlyFire and set it to FALSE + if(nShape == SHAPE_CONE || nShape == SHAPE_SPELLCONE) + { + bFriendlyFire = FALSE; + } // Before we start, if it can harm us, we don't fire it if there are no // enemies out of the blast, if it was centered on us - if(nFriendlyFire) + if(bFriendlyFire) { if(GlobalRangeToFuthestEnemy <= fSpread) return OBJECT_INVALID; } @@ -3701,8 +3353,8 @@ object AI_GetBestAreaSpellTarget(float fRange, float fSpread, int nLevel, int iS // and oGroupTarget is GetFirst/Next in nShape around oTarget) object oTarget, oReturnTarget, oGroupTarget; // Delcare Integers - int iCnt, iCntEnemiesOnTarget, iCntAlliesOnTarget, iNoHittingAllies, - iMostOnPerson, iMaxAlliesToHit, iOurToughness; + int nCnt, nCntEnemiesOnTarget, nCntAlliesOnTarget, iNoHittingAllies, + nMostOnPerson, nMaxAlliesToHit, nOurToughness; // Declare Booleans int bWillHitAlly, bNoHittingAllies, bCheckAlliesHP; location lTarget; @@ -3711,23 +3363,23 @@ object AI_GetBestAreaSpellTarget(float fRange, float fSpread, int nLevel, int iS // - We don't check specific immunities with cirtain properties/settings // If we have NOT got the setting and <= 6 int - if(GlobalIntelligence <= i6 && + if(GlobalIntelligence <= 6 && !GetSpawnInCondition(AI_FLAG_COMBAT_IMPROVED_IMMUNITY_CHECKING, AI_COMBAT_MASTER)) { - iDeathImmune = FALSE; - iNecromanticSpell = FALSE; + bDeathImmune = FALSE; + bNecromanticSpell = FALSE; } // NOT got extra checks in. if(!GetSpawnInCondition(AI_FLAG_COMBAT_IMPROVED_SPECIFIC_SPELL_IMMUNITY, AI_COMBAT_MASTER)) { - nLevel = i5; // This makes the spell think it gets past globes. + nLevel = 5; // This makes the spell think it gets past globes. // - Problem is that the save DC will increase. Won't affect much. } // We set up the distance that oTarget must be away from us, if it is // no friendly fire, it will be 0.0 meters, so we always use them. // - defaults to 0.0 meters unless FF is on - if(nFriendlyFire) + if(bFriendlyFire) { fTargetMustBeFrom = fSpread + 0.3; } @@ -3738,21 +3390,25 @@ object AI_GetBestAreaSpellTarget(float fRange, float fSpread, int nLevel, int iS bCheckAlliesHP = GetSpawnInCondition(AI_FLAG_COMBAT_AOE_DONT_MIND_IF_THEY_SURVIVE, AI_COMBAT_MASTER); // We will subtract all non-enemies within -8 challenge, upwards. - iOurToughness = GlobalOurHitDice - GetBoundriedAIInteger(AI_AOE_HD_DIFFERENCE, -8, i0, -30); + nOurToughness = GlobalOurHitDice - GetBoundriedAIInteger(AI_AOE_HD_DIFFERENCE, -8, 0, -30); // The maximum number of allies we can hit... - iMaxAlliesToHit = GetBoundriedAIInteger(AI_AOE_ALLIES_LOWEST_IN_AOE, i3, i1, i90); + nMaxAlliesToHit = GetBoundriedAIInteger(AI_AOE_ALLIES_LOWEST_IN_AOE, 4, 90, 1); // The target to return - set to invalid to start oReturnTarget = OBJECT_INVALID; - iCnt = i1; + nCnt = 1; // - 1.3 Change - made to target only creatures (trying to better performance) - oTarget = GetNearestObject(OBJECT_TYPE_CREATURE, OBJECT_SELF, iCnt); + oTarget = GetNearestObject(OBJECT_TYPE_CREATURE, OBJECT_SELF, nCnt); // Need distance a lot. fDistance = GetDistanceToObject(oTarget); // Need to see the target, within nRange around self. while(GetIsObjectValid(oTarget) && fDistance <= fRange) { // Need seen/heard target + // * The actual target can be a dead person, or anything, just something + // with a valid location. We thusly do not use AI_GetTargetSanityCheck() + // * NOTE: Ethereal checks NOT here, we can target any ethereal persons + // location (which might be better!) if(GetObjectSeen(oTarget) || GetObjectHeard(oTarget)) { // Will not fire on self, if it is too near. @@ -3761,8 +3417,8 @@ object AI_GetBestAreaSpellTarget(float fRange, float fSpread, int nLevel, int iS // Reset Targets // - The person starts the spread at 0, because the object in shape // will return the target as well. - iCntEnemiesOnTarget = FALSE; - iCntAlliesOnTarget = FALSE; + nCntEnemiesOnTarget = FALSE; + nCntAlliesOnTarget = FALSE; bWillHitAlly = FALSE; // Must sue this - needs to use the correct shape // This only gets creatures in shape to check. @@ -3773,38 +3429,39 @@ object AI_GetBestAreaSpellTarget(float fRange, float fSpread, int nLevel, int iS { // Sanity check for checking oGroupTarget if(oGroupTarget != OBJECT_SELF && - !GetIsDead(oGroupTarget) && !GetPlotFlag(oGroupTarget) && - !GetIgnore(oGroupTarget) && !GetIsDM(oGroupTarget) && + // * This adds a check for seen or heard, which makes it more + // realistic! + AI_GetTargetSanityCheck(oGroupTarget) && !AI_SpellResistanceImmune(oGroupTarget)) { // Check necromancy immunity, and death immunity. // + Save check // + Level Immunity check - if(!AI_AOEDeathNecroCheck(oGroupTarget, iNecromanticSpell, iDeathImmune) && - !AI_SaveImmuneAOE(oGroupTarget, iSaveType, nLevel) && + if(!AI_AOEDeathNecroCheck(oGroupTarget, bNecromanticSpell, bDeathImmune) && + !AI_SaveImmuneAOE(oGroupTarget, nSaveType, nLevel) && !AI_GetSpellLevelEffectAOE(oGroupTarget, nLevel)) { if(GetIsEnemy(oGroupTarget)) { // Only add one if the person is an enemy, // and the spell will affect them - iCntEnemiesOnTarget++; + nCntEnemiesOnTarget++; } // But else if friendly fire, we will subract // similar non-allies. - else if(nFriendlyFire && + else if(bFriendlyFire && (GetIsFriend(oGroupTarget) || GetFactionEqual(oGroupTarget)) && - GetHitDice(oGroupTarget) >= iOurToughness) + GetHitDice(oGroupTarget) >= nOurToughness) { if(bNoHittingAllies) { bWillHitAlly = TRUE; } // We ignore if not got the setting to check HP, - // else, we take one from the iCntEnemiesOnTarget. - else if(bCheckAlliesHP && GetCurrentHitPoints(oGroupTarget) < i50) + // else, we take one from the nCntEnemiesOnTarget. + else if(bCheckAlliesHP && GetCurrentHitPoints(oGroupTarget) < 50) { - iCntAlliesOnTarget++; + nCntAlliesOnTarget++; } } } @@ -3814,18 +3471,18 @@ object AI_GetBestAreaSpellTarget(float fRange, float fSpread, int nLevel, int iS } // Make the spell target oTarget if so. // If it is >= then we set it - it is a futher away target! - if(bWillHitAlly != TRUE && iCntEnemiesOnTarget >= i1 && - iCntAlliesOnTarget < iMaxAlliesToHit && - ((iCntEnemiesOnTarget - iCntAlliesOnTarget) >= iMostOnPerson)) + if(bWillHitAlly != TRUE && nCntEnemiesOnTarget >= 1 && + nCntAlliesOnTarget <= nMaxAlliesToHit && + ((nCntEnemiesOnTarget - nCntAlliesOnTarget) >= nMostOnPerson)) { - iMostOnPerson = iCntEnemiesOnTarget - iCntAlliesOnTarget; + nMostOnPerson = nCntEnemiesOnTarget - nCntAlliesOnTarget; oReturnTarget = oTarget; } } } // Gets the next nearest. - iCnt++; - oTarget = GetNearestObject(OBJECT_TYPE_CREATURE, OBJECT_SELF, iCnt); + nCnt++; + oTarget = GetNearestObject(OBJECT_TYPE_CREATURE, OBJECT_SELF, nCnt); fDistance = GetDistanceToObject(oTarget); } // Will OBJECT_INVALID, or the best target in range. @@ -3843,6 +3500,10 @@ void AI_SortSpellImmunities() { // Error checking if(!GetIsObjectValid(GlobalSpellTarget)) return; + // Get our good/evil alignment, for the purposes of the mind immunity + // commonly employed via. Protection From Alignment + int nGoodEvil = GetAlignmentGoodEvil(OBJECT_SELF); + // Check effects of GlobalSpellTarget effect eCheck = GetFirstEffect(GlobalSpellTarget); while(GetIsEffectValid(eCheck)) @@ -3900,6 +3561,7 @@ void AI_SortSpellImmunities() break; // All case EFFECT_TYPE_PETRIFY: + // * This should never be set, we do not target petrified people! AI_SetSpellTargetImmunity(GlobalImmunityPetrify); break; // Defualt, check spell ID @@ -3936,12 +3598,12 @@ void AI_SortSpellImmunities() case SPELL_UNHOLY_AURA: case SPELL_MAGIC_CIRCLE_AGAINST_GOOD: case SPELL_PROTECTION_FROM_GOOD:// New one SoU - if(GlobalOurGoodEvil == ALIGNMENT_GOOD) AI_SetSpellTargetImmunity(GlobalImmunityMind); + if(nGoodEvil == ALIGNMENT_GOOD) AI_SetSpellTargetImmunity(GlobalImmunityMind); break; case SPELL_HOLY_AURA: case SPELL_PROTECTION_FROM_EVIL: case SPELL_MAGIC_CIRCLE_AGAINST_EVIL:// New one SoU - if(GlobalOurGoodEvil == ALIGNMENT_EVIL) AI_SetSpellTargetImmunity(GlobalImmunityMind); + if(nGoodEvil == ALIGNMENT_EVIL) AI_SetSpellTargetImmunity(GlobalImmunityMind); break; } } @@ -3951,12 +3613,19 @@ void AI_SortSpellImmunities() } // Immunity Things // We only use these if 7+ Intelligence - if(GlobalIntelligence >= i7 || + if(GlobalIntelligence >= 7 || GetSpawnInCondition(AI_FLAG_COMBAT_IMPROVED_IMMUNITY_CHECKING, AI_COMBAT_MASTER)) { + // Necromancy immune if undead + if(!AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && + (GlobalSpellTargetRace == RACIAL_TYPE_UNDEAD || + GlobalSpellTargetRace == RACIAL_TYPE_CONSTRUCT)) + AI_SetSpellTargetImmunity(GlobalImmunityNecromancy); // Death immunity if(!AI_GetSpellTargetImmunity(GlobalImmunityDeath) && - GetIsImmune(GlobalSpellTarget, IMMUNITY_TYPE_DEATH)) + (GetIsImmune(GlobalSpellTarget, IMMUNITY_TYPE_DEATH) || + GlobalSpellTargetRace == RACIAL_TYPE_UNDEAD || + GlobalSpellTargetRace == RACIAL_TYPE_CONSTRUCT)) AI_SetSpellTargetImmunity(GlobalImmunityDeath); // confusion immunity if(!AI_GetSpellTargetImmunity(GlobalImmunityConfusion) && @@ -4042,9 +3711,8 @@ void AI_SortSpellImmunities() } } } - int iApperance = GetAppearanceType(GlobalSpellTarget); // We won't use petrify on those immune, though. This is taken from - // x0_i0_spells. Stops silly basalisks or something. :-) + // x0_0_spells. Stops silly basalisks or something. :-) // - ANY intelligence if(!AI_GetSpellTargetImmunity(GlobalImmunityPetrify)) { @@ -4102,8 +3770,8 @@ void AI_SortSpellImmunities() //:: Name: AI_ActionDispelAOE //:://///////////////////////////////////////////// Dispels or moves out of the oAOE. - - If we have >= iMax AND <= iDamage HP... - AND under iPercent total HP... + - If we have >= nMax AND <= nDamage HP... + AND under nPercent total HP... - We Dispel, or move out of the AOE. Move if friendly. Note: We get nearest AOE of sAOE tag. Must be valid as well. @@ -4111,21 +3779,21 @@ void AI_SortSpellImmunities() //:://///////////////////////////////////////////// //:: Created By: Jasperre //:://///////////////////////////////////////////*/ -int AI_ActionDispelAOE(int iSpell, int iDamageOnly, float fRange, int iDamage, int iMax, int iPercent) +int AI_ActionDispelAOE(int nSpell, int bDamageOnly, float fRange, int nDamage, int nMax, int nPercent) { - object oAOE = GetAIObject(AI_TIMER_AOE_SPELL_EVENT + IntToString(iSpell)); + object oAOE = GetAIObject(AI_TIMER_AOE_SPELL_EVENT + IntToString(nSpell)); // Get damage done - int iLastDamage = GetAIInteger(ObjectToString(oAOE)); + int nLastDamage = GetAIInteger(ObjectToString(oAOE)); // Delete/clean up DeleteAIInteger(ObjectToString(oAOE)); // Check we will be affected, or are affected, by the AOE at all! if(GetIsObjectValid(oAOE) && GetDistanceToObject(oAOE) <= fRange && // + Damaged from that AOE, or affected by that AOE. - (iLastDamage >= TRUE || (GetHasSpellEffect(iSpell) && !iDamageOnly))) + (nLastDamage >= TRUE || (GetHasSpellEffect(nSpell) && !bDamageOnly))) { - // Either Under iMax AND under - if((GlobalOurMaxHP >= iMax && GlobalOurCurrentHP <= iDamage) || - GlobalOurPercentHP <= iPercent || !GlobalAnyValidTargetObject) + // Either Under nMax AND under + if((GlobalOurMaxHP >= nMax && GlobalOurCurrentHP <= nDamage) || + GlobalOurPercentHP <= nPercent || !GlobalAnyValidTargetObject) { // 16: "[AOE Call] Moving out of/Dispeling an AOE. [Tag] " + GetTag(oAOE) DebugActionSpeakByInt(16, oAOE); @@ -4134,13 +3802,13 @@ int AI_ActionDispelAOE(int iSpell, int iDamageOnly, float fRange, int iDamage, i { // 11 = Harmful AOE indis. 2 = Harmful ranged. // Gust of Wind. Level 3 (Bard/Mage) Dispels all AOE's in radius, and save VS fort for 3 round knockdown. - if(AI_ActionCastSpell(SPELL_GUST_OF_WIND, SpellHostAreaInd, oAOE, i13, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpell(SPELL_GUST_OF_WIND, oAOE, 13, TRUE)) return TRUE; // Worst to best, then move...wind gust best! // - Note that they have a % chance to remove stuff... - if(AI_ActionCastSpell(SPELL_LESSER_DISPEL, SpellHostAreaInd, oAOE, i12, TRUE, ItemHostAreaInd)) return TRUE; - if(AI_ActionCastSpell(SPELL_DISPEL_MAGIC, SpellHostRanged, oAOE, i13, TRUE, ItemHostRanged)) return TRUE; - if(AI_ActionCastSpell(SPELL_GREATER_DISPELLING, SpellHostRanged, oAOE, i16, TRUE, ItemHostRanged)) return TRUE; - if(AI_ActionCastSpell(SPELL_MORDENKAINENS_DISJUNCTION, SpellHostAreaInd, oAOE, i19, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpell(SPELL_LESSER_DISPEL, oAOE, 12, TRUE)) return TRUE; + if(AI_ActionCastSpell(SPELL_DISPEL_MAGIC, oAOE, 13, TRUE)) return TRUE; + if(AI_ActionCastSpell(SPELL_GREATER_DISPELLING, oAOE, 16, TRUE)) return TRUE; + if(AI_ActionCastSpell(SPELL_MORDENKAINENS_DISJUNCTION, oAOE, 19, TRUE)) return TRUE; } // Else move. We force this until we are out of the AOE SetAIObject(AI_AOE_FLEE_FROM, oAOE); @@ -4172,12 +3840,12 @@ int AI_AttemptSpecialChecks() !AI_GetAIHaveEffect(GlobalEffectUltravision) && !AI_GetAIHaveEffect(GlobalEffectTrueSeeing)) // Check nearest enemy with darkness effect. Use heard only (they won't be seen!) - || GetIsObjectValid(GetNearestCreature(CREATURE_TYPE_HAS_SPELL_EFFECT, SPELL_DARKVISION, OBJECT_SELF, i1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD))) + || GetIsObjectValid(GetNearestCreature(CREATURE_TYPE_HAS_SPELL_EFFECT, SPELL_DARKVISION, OBJECT_SELF, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD))) { // Ultravision - Talent category 10 (Benificial enchancement Self). - if(AI_ActionCastSpell(SPELL_DARKVISION, SpellEnhSelf, OBJECT_SELF, i13, FALSE, ItemEnhSelf, PotionEnh)) return TRUE; + if(AI_ActionCastSpell(SPELL_DARKVISION, OBJECT_SELF, 13, FALSE)) return TRUE; // 1.30/SoU trueeing should Dispel it. (Benificial conditional AOE) - if(AI_ActionCastSpell(SPELL_TRUE_SEEING, SpellConAre, OBJECT_SELF, i16, FALSE, ItemConAre, PotionCon)) return TRUE; + if(AI_ActionCastSpell(SPELL_TRUE_SEEING, OBJECT_SELF, 16, FALSE)) return TRUE; // If we are a rubbish fightingclass OR we cannot hear any enemy to attack...move or something. if(!GlobalValidNearestSeenEnemy && @@ -4191,12 +3859,12 @@ int AI_AttemptSpecialChecks() // Dispel it - trying nearest creature, if has darkness as well // 11 = Harmful AOE indis. 2 = Harmful ranged. // WORST to BEST as all of them never check caster levels for AOEs (Silly bioware!) - if(AI_ActionCastSpell(SPELL_LESSER_DISPEL, SpellHostAreaInd, OBJECT_SELF, i12, TRUE, ItemHostAreaInd)) return TRUE; - if(AI_ActionCastSpell(SPELL_DISPEL_MAGIC, SpellHostRanged, OBJECT_SELF, i13, TRUE, ItemHostRanged)) return TRUE; - if(AI_ActionCastSpell(SPELL_GREATER_DISPELLING, SpellHostRanged, OBJECT_SELF, i16, TRUE, ItemHostRanged)) return TRUE; - if(AI_ActionCastSpell(SPELL_MORDENKAINENS_DISJUNCTION, SpellHostAreaInd, OBJECT_SELF, i19, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpell(SPELL_LESSER_DISPEL, OBJECT_SELF, 12, TRUE)) return TRUE; + if(AI_ActionCastSpell(SPELL_DISPEL_MAGIC, OBJECT_SELF, 13, TRUE)) return TRUE; + if(AI_ActionCastSpell(SPELL_GREATER_DISPELLING, OBJECT_SELF, 16, TRUE)) return TRUE; + if(AI_ActionCastSpell(SPELL_MORDENKAINENS_DISJUNCTION, OBJECT_SELF, 19, TRUE)) return TRUE; - ActionMoveAwayFromLocation(GetLocation(OBJECT_SELF), TRUE, f6); + ActionMoveAwayFromLocation(GetLocation(OBJECT_SELF), TRUE, 6.0); return TRUE; } } @@ -4204,42 +3872,62 @@ int AI_AttemptSpecialChecks() DeleteAIObject(AI_LAST_TO_GO_INVISIBLE); // Intelligence: 8+ means HIPS check. There is a 80% chance. if((!GetIsObjectValid(oInvisible) || GetObjectSeen(oInvisible)) && - GlobalIntelligence >= i8 && d10() <= i8) + GlobalIntelligence >= 8 && d10() <= 8) { // Makes the AI cast seeing spells against shadowdancers who will HIPS - oInvisible = GetNearestCreature(CREATURE_TYPE_CLASS, CLASS_TYPE_SHADOWDANCER, OBJECT_SELF, i1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, CREATURE_TYPE_IS_ALIVE, TRUE); - DeleteLocalLocation(OBJECT_SELF, AI_LAST_TO_GO_INVISIBLE); + oInvisible = GetNearestCreature(CREATURE_TYPE_CLASS, CLASS_TYPE_SHADOWDANCER, OBJECT_SELF, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, CREATURE_TYPE_IS_ALIVE, TRUE); + DeleteAILocation(AI_LAST_TO_GO_INVISIBLE); } // If we have a previously set invisible enemy or if high intelligence, a shadowdancer in range. if(GetIsObjectValid(oInvisible)) { // 1.30/SoU trueeing should Dispel it. (Benificial conditional AOE) - if(AI_ActionCastSpell(SPELL_TRUE_SEEING, SpellConAre, OBJECT_SELF, i16, FALSE, ItemConAre, PotionCon)) return TRUE; + if(AI_ActionCastSpell(SPELL_TRUE_SEEING, OBJECT_SELF, 16, FALSE)) return TRUE; // Invisiblity purge! SpellConAre - if(AI_ActionCastSpell(SPELL_INVISIBILITY_PURGE, SpellConAre, OBJECT_SELF, i14, FALSE, ItemConAre, PotionCon)) return TRUE; + if(AI_ActionCastSpell(SPELL_INVISIBILITY_PURGE, OBJECT_SELF, 14, FALSE)) return TRUE; // This should work well as well! SpellConSinTar - if(AI_ActionCastSpell(SPELL_SEE_INVISIBILITY, SpellConSinTar, OBJECT_SELF, i12, FALSE, ItemConSinTar, PotionCon)) return TRUE; + if(AI_ActionCastSpell(SPELL_SEE_INVISIBILITY, OBJECT_SELF, 12, FALSE)) return TRUE; - location lTarget = GetLocalLocation(OBJECT_SELF, AI_LAST_TO_GO_INVISIBLE); - DeleteLocalLocation(OBJECT_SELF, AI_LAST_TO_GO_INVISIBLE); + location lTarget = GetAILocation(AI_LAST_TO_GO_INVISIBLE); + DeleteAILocation(AI_LAST_TO_GO_INVISIBLE); // Check location validness if(GetIsObjectValid(GetAreaFromLocation(lTarget))) { // We will cast at thier previous location, using a temp object we actually // create there for a few seconds. - oInvisible = CreateObject(OBJECT_TYPE_PLACEABLE, "", GetLocalLocation(OBJECT_SELF, AI_LAST_TO_GO_INVISIBLE)); + oInvisible = CreateObject(OBJECT_TYPE_PLACEABLE, "", lTarget); // Check range if(GetIsObjectValid(oInvisible) && - GetDistanceToObject(oInvisible) < f40) + GetDistanceToObject(oInvisible) < 40.0) { + // 1.4: Temp: Cast at location with the base spells only + if(GetHasSpell(SPELL_MORDENKAINENS_DISJUNCTION)) + { + ActionCastSpellAtLocation(SPELL_MORDENKAINENS_DISJUNCTION, lTarget); + return TRUE; + } + else if(GetHasSpell(SPELL_GREATER_DISPELLING)) + { + ActionCastSpellAtLocation(SPELL_GREATER_DISPELLING, lTarget); + return TRUE; + } + else if(GetHasSpell(SPELL_DISPEL_MAGIC)) + { + ActionCastSpellAtLocation(SPELL_DISPEL_MAGIC, lTarget); + return TRUE; + } + else if(GetHasSpell(SPELL_LESSER_DISPEL)) + { + ActionCastSpellAtLocation(SPELL_LESSER_DISPEL, lTarget); + return TRUE; + } + // Best to worst - if(AI_ActionCastSpell(SPELL_MORDENKAINENS_DISJUNCTION, SpellHostAreaInd, oInvisible, i19, TRUE, ItemHostAreaInd)) return TRUE; - if(AI_ActionCastSpell(SPELL_GREATER_DISPELLING, SpellHostRanged, oInvisible, i16, TRUE, ItemHostRanged)) return TRUE; - if(AI_ActionCastSpell(SPELL_DISPEL_MAGIC, SpellHostRanged, oInvisible, i13, TRUE, ItemHostRanged)) return TRUE; - if(AI_ActionCastSpell(SPELL_LESSER_DISPEL, SpellHostAreaInd, oInvisible, i12, TRUE, ItemHostAreaInd)) return TRUE; - // Destroy the placeable after we have got the location ETC. - DestroyObject(oInvisible); + //if(AI_ActionCastSpell(SPELL_MORDENKAINENS_DISJUNCTION, oInvisible, 19, TRUE)) return TRUE; + //if(AI_ActionCastSpell(SPELL_GREATER_DISPELLING, oInvisible, 16, TRUE)) return TRUE; + //if(AI_ActionCastSpell(SPELL_DISPEL_MAGIC, oInvisible, 13, TRUE)) return TRUE; + //if(AI_ActionCastSpell(SPELL_LESSER_DISPEL, oInvisible, 12, TRUE)) return TRUE; } } } @@ -4258,23 +3946,23 @@ int AI_AttemptSpecialChecks() float fDistance = GetDistanceToObject(oAOE); // First check: We randomly check this if INT 1-5, and always check 6+ - if(GlobalIntelligence >= (i6 - d6()) && + if(GlobalIntelligence >= (6 - d6()) && // Second: Need a valid AOE, of course! GetIsObjectValid(oAOE) && // Third: Needs to be in 10.0 M fDistance <= RADIUS_SIZE_COLOSSAL) { - int iElemental = AI_GetAIHaveSpellsEffect(GlobalHasElementalProtections); - int iPhisical = AI_GetAIHaveSpellsEffect(GlobalHasStoneSkinProtections); + int bElemental = AI_GetAIHaveSpellsEffect(GlobalHasElementalProtections); + int bPhisical = AI_GetAIHaveSpellsEffect(GlobalHasStoneSkinProtections); // We can check the timers added to spells, to check for AOEs we are in. // Long range ones...already made sure of collosal range! // Storm of vengance...a lot of damage (so we need only 30HP left) // Stats: Raduis 10! d6(3) , Get Is Friend/Friendly. // Either: Electical (reflex) and stun (failed save), else Acid, d6(6). - if(GetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(SPELL_STORM_OF_VENGEANCE)) && !iElemental) + if(GetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(SPELL_STORM_OF_VENGEANCE)) && !bElemental) { - if(AI_ActionDispelAOE(SPELL_STORM_OF_VENGEANCE, TRUE, RADIUS_SIZE_COLOSSAL, i30, i50, i20)) return TRUE; + if(AI_ActionDispelAOE(SPELL_STORM_OF_VENGEANCE, TRUE, RADIUS_SIZE_COLOSSAL, 30, 50, 20)) return TRUE; } // Next range...6.7 if(fDistance <= RADIUS_SIZE_HUGE) @@ -4283,9 +3971,9 @@ int AI_AttemptSpecialChecks() // This can get a lot of damage. We might check the counter status... // Stats: Radius 6.7. Initial d20 damage (can't stop), Slow as well. Reaction Type Friendly. // d6(Amount of rounds in effect) each round after that, HURTS! (up to 1000) - if(GetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(SPELL_CREEPING_DOOM)) && !iPhisical) + if(GetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(SPELL_CREEPING_DOOM)) && !bPhisical) { - if(AI_ActionDispelAOE(SPELL_CREEPING_DOOM, TRUE, RADIUS_SIZE_HUGE, GetLocalInt(oAOE, "NW_SPELL_CONSTANT_CREEPING_DOOM1" + ObjectToString(GetAreaOfEffectCreator(oAOE))) * i6, i40, i40)) return TRUE; + if(AI_ActionDispelAOE(SPELL_CREEPING_DOOM, TRUE, RADIUS_SIZE_HUGE, GetLocalInt(oAOE, "NW_SPELL_CONSTANT_CREEPING_DOOM1" + ObjectToString(GetAreaOfEffectCreator(oAOE))) * 6, 40, 40)) return TRUE; } // Stinking cloud! // No damage, only daze. If we are immune to it - fine. @@ -4294,28 +3982,28 @@ int AI_AttemptSpecialChecks() // Only fortitude save. if(GetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(SPELL_STINKING_CLOUD))) { - if(AI_ActionDispelAOE(SPELL_STINKING_CLOUD, TRUE, RADIUS_SIZE_HUGE, i25, i60, i35)) return TRUE; + if(AI_ActionDispelAOE(SPELL_STINKING_CLOUD, TRUE, RADIUS_SIZE_HUGE, 25, 60, 35)) return TRUE; } // Grease // Stats: Radius 6. (count as 6.7) We get slowed (unless Woodland Stride) in it always. // On a reflex save each round, knockdown effect (4 seconds). Reaction Type Friendly. if(GetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(SPELL_GREASE))) { - if(AI_ActionDispelAOE(SPELL_GREASE, FALSE, RADIUS_SIZE_HUGE, i10, i25, i15)) return TRUE; + if(AI_ActionDispelAOE(SPELL_GREASE, FALSE, RADIUS_SIZE_HUGE, 10, 25, 15)) return TRUE; } // Wall of fire... // Stats: 10M x 2M rectangle. d6(4) Fire damage (Reflex save). // Notes: level 5/6 spell. Not bad, up to 24 damage! Reaction Type Frendly. - if(GetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(SPELL_WALL_OF_FIRE)) && !iElemental) + if(GetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(SPELL_WALL_OF_FIRE)) && !bElemental) { - if(AI_ActionDispelAOE(SPELL_WALL_OF_FIRE, TRUE, RADIUS_SIZE_HUGE, i20, i50, i25)) return TRUE; + if(AI_ActionDispelAOE(SPELL_WALL_OF_FIRE, TRUE, RADIUS_SIZE_HUGE, 20, 50, 25)) return TRUE; } // Blade Barrier (special shape!) // Stats: 10M x 1M rectangle. d6(CasterLevel) Piercing damage (Reflex save). // Notes: LOTs of damage! warning about this one! Reaction Type friendly. - if(GetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(SPELL_BLADE_BARRIER)) && !iPhisical) + if(GetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(SPELL_BLADE_BARRIER)) && !bPhisical) { - if(AI_ActionDispelAOE(SPELL_BLADE_BARRIER, TRUE, RADIUS_SIZE_HUGE, i30, i50, i35)) return TRUE; + if(AI_ActionDispelAOE(SPELL_BLADE_BARRIER, TRUE, RADIUS_SIZE_HUGE, 30, 50, 35)) return TRUE; } // Next range...5.0 if(fDistance <= RADIUS_SIZE_LARGE) @@ -4323,18 +4011,18 @@ int AI_AttemptSpecialChecks() // Acid Fog spell // Stats: Radius 5. Damage: d6(2), Fort/2. Slow on failed Fort save (On Enter) // Notes: Level 6 spell. Uses ReactionType, not GetFriend. - if(GetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(SPELL_ACID_FOG))) + if(GetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(SPELL_ACID_FOG)) && !bElemental) { // Ignore slowing effect - if(AI_ActionDispelAOE(SPELL_ACID_FOG, TRUE, RADIUS_SIZE_HUGE, i20, i40, i25)) return TRUE; + if(AI_ActionDispelAOE(SPELL_ACID_FOG, TRUE, RADIUS_SIZE_HUGE, 20, 40, 25)) return TRUE; } // Inceniary Cloud spell // Stats: Radius 5. Damage: d6(4), Reflex. Slow always. // Notes: Level 8 spell. Uses ReactionTypeFriendly, not GetFriend. - if(GetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(SPELL_INCENDIARY_CLOUD)) && !iElemental) + if(GetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(SPELL_INCENDIARY_CLOUD)) && !bElemental) { // Ignore slow - if(AI_ActionDispelAOE(SPELL_INCENDIARY_CLOUD, TRUE, RADIUS_SIZE_HUGE, i30, i50, i35)) return TRUE; + if(AI_ActionDispelAOE(SPELL_INCENDIARY_CLOUD, TRUE, RADIUS_SIZE_HUGE, 30, 50, 35)) return TRUE; } // Cloudkill spell // Stats: Radius 5. Under 3HD Die. 4-7 Save VS Death (Fort) @@ -4342,14 +4030,14 @@ int AI_AttemptSpecialChecks() if(GetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(SPELL_CLOUDKILL))) { // Damage only - if(AI_ActionDispelAOE(SPELL_CLOUDKILL, TRUE, RADIUS_SIZE_HUGE, i15, i30, i25)) return TRUE; + if(AI_ActionDispelAOE(SPELL_CLOUDKILL, TRUE, RADIUS_SIZE_HUGE, 15, 30, 25)) return TRUE; } // Evards Black Tenticals. // Stats: Radius 5. 1d6 damage if d20 + 5 hits the target. (Reaction Type Hostile) // May paralize them as well, on a fort save. Up to 5 of these tenticals BTW. - if(GetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(SPELL_EVARDS_BLACK_TENTACLES)) && !iPhisical) + if(GetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(SPELL_EVARDS_BLACK_TENTACLES)) && !bPhisical) { - if(AI_ActionDispelAOE(SPELL_EVARDS_BLACK_TENTACLES, TRUE, RADIUS_SIZE_HUGE, i15, i30, i25)) return TRUE; + if(AI_ActionDispelAOE(SPELL_EVARDS_BLACK_TENTACLES, TRUE, RADIUS_SIZE_HUGE, 15, 30, 25)) return TRUE; } // Mind Fog spell // Stats: Radius 5. @@ -4358,7 +4046,7 @@ int AI_AttemptSpecialChecks() GetLocalInt(OBJECT_SELF, AI_ABILITY_DECREASE) > FALSE) { // No damage - if(AI_ActionDispelAOE(SPELL_MIND_FOG, FALSE, RADIUS_SIZE_HUGE, i15, i30, i25)) return TRUE; + if(AI_ActionDispelAOE(SPELL_MIND_FOG, FALSE, RADIUS_SIZE_HUGE, 15, 30, 25)) return TRUE; } // Entangle // Stats: Radius 5. Reaction Type hostile used. @@ -4367,7 +4055,7 @@ int AI_AttemptSpecialChecks() AI_GetAIHaveEffect(GlobalEffectEntangle)) { // No damage - if(AI_ActionDispelAOE(SPELL_ENTANGLE, FALSE, RADIUS_SIZE_HUGE, i15, i30, i25)) return TRUE; + if(AI_ActionDispelAOE(SPELL_ENTANGLE, FALSE, RADIUS_SIZE_HUGE, 15, 30, 25)) return TRUE; } // Vine mine // Stats: Radius as Entangle - Radius 5 @@ -4375,13 +4063,13 @@ int AI_AttemptSpecialChecks() AI_GetAIHaveEffect(GlobalEffectEntangle)) { // " " - if(AI_ActionDispelAOE(SPELL_VINE_MINE_ENTANGLE, FALSE, RADIUS_SIZE_HUGE, i15, i30, i25)) return TRUE; + if(AI_ActionDispelAOE(SPELL_VINE_MINE_ENTANGLE, FALSE, RADIUS_SIZE_HUGE, 15, 30, 25)) return TRUE; } // Hamper movement one if(GetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(SPELL_VINE_MINE_HAMPER_MOVEMENT)) && AI_GetAIHaveEffect(GlobalEffectMovementSpeedDecrease)) { - if(AI_ActionDispelAOE(SPELL_VINE_MINE_HAMPER_MOVEMENT, FALSE, RADIUS_SIZE_HUGE, i15, i30, i25)) return TRUE; + if(AI_ActionDispelAOE(SPELL_VINE_MINE_HAMPER_MOVEMENT, FALSE, RADIUS_SIZE_HUGE, 15, 30, 25)) return TRUE; } } // Web @@ -4390,7 +4078,7 @@ int AI_AttemptSpecialChecks() if(GetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(SPELL_WEB)) && AI_GetAIHaveEffect(GlobalEffectEntangle)) { - if(AI_ActionDispelAOE(SPELL_WEB, FALSE, RADIUS_SIZE_HUGE, i30, i50, i35)) return TRUE; + if(AI_ActionDispelAOE(SPELL_WEB, FALSE, RADIUS_SIZE_HUGE, 30, 50, 35)) return TRUE; } } } @@ -4398,82 +4086,95 @@ int AI_AttemptSpecialChecks() return FALSE; } /*:://///////////////////////////////////////////// -//:: ReturnHealingInfo +//:: AI_GetHealingSpellRank, AI_GetHealingSpellPower //:://///////////////////////////////////////////// - This will do 1 of two things, with the spell ID - 1. If iHealAmount is FALSE, it will return what number (rank) in order, which is also used for level checking - 2. If TRUE, it will return the average damage it will heal. + Returns the rank (the first) and the spell power/average healing (the latter) //:://///////////////////////////////////////////// //:: Created by: Jasperre //:://///////////////////////////////////////////*/ -int AI_ReturnHealingInfo(int iSpellID, int iSelf = FALSE, int iHealAmount = FALSE) +// Returns the healing "Rank" of nSpellId (made up by me) which the spell is. +// Used in healing, Heal (+Mass Heal) is done seperatly in the healing routines. +// * Returns a default of 0 if no valid healing spell is found (Or was a Heal spell) +// * Use bSelf to be TRUE if you want to include "Cure Other" spells in Hordes +int AI_GetHealingSpellRank(int nSpellId, int bSelf = FALSE) { // On error - return 0 rank, or 0 heal. - if(iSpellID <= FALSE) return FALSE; - switch(iSpellID) + if(nSpellId <= FALSE) return FALSE; + switch(nSpellId) + { + // Each spell has a specific rank, such as Heal is highest, Cure Minor is + // lowest. + // Critical: Rank 10 + case SPELL_CURE_CRITICAL_WOUNDS: return 10; break; + // Cure light wounds (Lesser Body Adjustment is the same script) is rank 2 + case SPELLABILITY_LESSER_BODY_ADJUSTMENT: + case SPELL_CURE_LIGHT_WOUNDS: + return 2; + break; + // Cure minor - lowest, rank 1. + case SPELL_CURE_MINOR_WOUNDS: return 1; break; + // Moderate rank 3. + case SPELL_CURE_MODERATE_WOUNDS: return 3; break; + // Serious rank 4. + case SPELL_CURE_SERIOUS_WOUNDS: return 4; break; + // Healing circle, rank 4. AOE healing isn't returned in the same talent + // as Single Target healing. + case SPELL_HEALING_CIRCLE: return 4; break; + // Cure Critical Wounds other depends on if bSelf is FALSE. + case AI_SPELLABILITY_CURE_CRITICAL_WOUNDS_OTHER: return 9; break; + } + // On error - return 0 rank + return FALSE; +} + +// This will return the average amount healed by nSpellId, determined as if they +// were the minimum level used to cast it, and average rolls were performed. +// * Used in healing to check if we should bother using the spell yet, eg: +// a 50HP person with a ciritical wounds potion might take it at 10HP, not 25HP, +// because it heals a lot. +int AI_GetHealingSpellPower(int nSpellId) +{ + // On error - return 0 rank, or 0 heal. + if(nSpellId <= FALSE) return FALSE; + switch(nSpellId) { // RANK - NAME = D8 AMOUNTs + RANGE OF CLERIC LEVELS ADDED. MAX. // AVERAGE OF DICE. ABOUT 2/3 OF MODIFIERS. - case SPELL_CURE_CRITICAL_WOUNDS: - { - // 20 - Critical = 4d8 + 7-20. Max of 32. Take as 24. Take modifiers as 10. - if(iHealAmount){ return i35; } else { return i10; } - } - break; + + // 20 - Critical = 4d8 + 7-20. Max of 32. Take as 24. Take modifiers as 10. + case SPELL_CURE_CRITICAL_WOUNDS: return 35; break; + // 10 - Lesser Bodily Adjustment = 1d8 + 1-5. Max of 8. Take as 6. Take modifiers as 3. + // NOTE: same spell script as Cure Light Wounds, but no concentration check! + // 8 - Light = 1d8 + 2-5. Max of 8. Take as 6. Take modifiers as 3. case SPELLABILITY_LESSER_BODY_ADJUSTMENT: case SPELL_CURE_LIGHT_WOUNDS: - { - // 10 - Lesser Bodily Adjustment = 1d8 + 1-5. Max of 8. Take as 6. Take modifiers as 3. - // NOTE: same spell script as Cure Light Wounds, but no concentration check! - // 8 - Light = 1d8 + 2-5. Max of 8. Take as 6. Take modifiers as 3. - if(iHealAmount){ return i9; } else { return i2; } - } - break; - case SPELL_CURE_MINOR_WOUNDS: - { - // 4 - Minor = 1. Max of 1. Take as 1. Take modifiers as 0. - // No need for check - healing and rank are both 1. - return i1; - } - break; - case SPELL_CURE_MODERATE_WOUNDS: - { - // 12 - Moderate = 2d8 + 3-10. Max of 16. Take as 12. Take modifiers as 5. - if(iHealAmount){ return i17; } else { return i3; } - } - break; - case SPELL_CURE_SERIOUS_WOUNDS: - { - // 16 - Serious = 3d8 + 5-15. Max of 24. Take as 18. Take modifiers as 7. - if(iHealAmount){ return i25; } else { return i4; } - } - break; - case SPELL_HEALING_CIRCLE: - { - // 14 - Healing circle = 1d8 + 9-20. Max of 8. Take as 8. Take modifiers as 10. - if(iHealAmount){ return i18; } else { return i4; } - } - break; - case AI_SPELLABILITY_CURE_CRITICAL_WOUNDS_OTHER: - { - // As cure critical wounds, but cures another and damages us... - // No idea.. :-) - if(iSelf == TRUE) - { - // 20 - Critical = 4d8 + 7-20. Max of 32. Take as 24. Take modifiers as 9. - if(iHealAmount){ return i35; } else { return i9; } - } - } + return 9; break; + // 4 - Minor = 1. Max of 1. Take as 1. Take modifiers as 0. + case SPELL_CURE_MINOR_WOUNDS: return 1; break; + // 12 - Moderate = 2d8 + 3-10. Max of 16. Take as 12. Take modifiers as 5. + case SPELL_CURE_MODERATE_WOUNDS: return 17; break; + // 16 - Serious = 3d8 + 5-15. Max of 24. Take as 18. Take modifiers as 7. + case SPELL_CURE_SERIOUS_WOUNDS: return 25; break; + // 14 - Healing circle = 1d8 + 9-20. Max of 8. Take as 8. Take modifiers as 10. + case SPELL_HEALING_CIRCLE: return 18; break; + // As cure critical wounds, but cures another and damages us... + // Rank is 0 if this spell is put in and the target isn't us. We don't + // need a bSelf check therefore. + // 20 - Critical = 4d8 + 7-20. Max of 32. Take as 24. Take modifiers as 9. + case AI_SPELLABILITY_CURE_CRITICAL_WOUNDS_OTHER: return 35; break; } // On error - return 0 rank, or 0 heal. return FALSE; } + // Wrappers action Use Talent with debug string void AI_ActionUseTalentDebug(talent tChosenTalent, object oTarget) { // 18: "[DRC:Talent] Using Talent (Healing). [TalentID] " + IntToString(GetIdFromTalent(tChosenTalent)) + " [Target] " + GetName(oTarget) DebugActionSpeakByInt(18, oTarget, GetIdFromTalent(tChosenTalent)); + // Moved Equip best shield in here + AI_EquipBestShield(); ActionUseTalentOnObject(tChosenTalent, oTarget); } /*:://///////////////////////////////////////////// @@ -4487,193 +4188,172 @@ void AI_ActionUseTalentDebug(talent tChosenTalent, object oTarget) //:://///////////////////////////////////////////// //:: Created By: Jasperre //::////////////////////////////////////////////*/ -int AI_ActionHealObject(object oTarget) +int AI_ActionHealObject(object oTarget, int bPotionsValid = FALSE) { // Set healing talents talent tAOEHealing, tTouchHealing, tPotionHealing; // These are left at 0 if we have no SpawnInCondition setting them. - int iAOEHealingValue, iTouchHealingValue, iPotionValue; + int nAOEHealingValue, nTouchHealingValue, nPotionValue; // We set up OnSpawn if any of the 3 talents are valid - if(GetSpawnInCondition(AI_VALID_TALENT_BENEFICIAL_HEALING_AREAEFFECT, AI_VALID_SPELLS)) - { - tAOEHealing = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_HEALING_AREAEFFECT, i20); - iAOEHealingValue = GetIdFromTalent(tAOEHealing); - } - if(GetSpawnInCondition(AI_VALID_TALENT_BENEFICIAL_HEALING_TOUCH, AI_VALID_SPELLS)) - { - tTouchHealing = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_HEALING_TOUCH, i20); - iTouchHealingValue = GetIdFromTalent(tTouchHealing); - } + tAOEHealing = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_HEALING_AREAEFFECT, 20); + nAOEHealingValue = GetIdFromTalent(tAOEHealing); + + // Touch healing (Cure XXX wounds, Heal...) + tTouchHealing = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_HEALING_TOUCH, 20); + nTouchHealingValue = GetIdFromTalent(tTouchHealing); + // First, we check for heal spells in the talents we have. They are special cases! - // We set this to the right value if the target is us. - int iTargetCurrentHP = GlobalOurCurrentHP; - int iTargetMaxHP = GlobalOurMaxHP; - int iTargetPercentHP = GlobalOurPercentHP; - int iTargetSelf = TRUE; - // Check...might still be minus one, anyway. + int nTargetCurrentHP, nTargetMaxHP, nTargetPercentHP, bTargetSelf; + // If the target is ourselves... if(oTarget == OBJECT_SELF) { - tPotionHealing = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_HEALING_POTION, i20); - iPotionValue = GetIdFromTalent(tPotionHealing); + nTargetCurrentHP = GlobalOurCurrentHP; + nTargetMaxHP = GlobalOurMaxHP; + nTargetPercentHP = GlobalOurPercentHP; + bTargetSelf = TRUE; + // We might use potions + if(bPotionsValid == TRUE) + { + tPotionHealing = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_HEALING_POTION, 20); + nPotionValue = GetIdFromTalent(tPotionHealing); + } } - else // If not us, we don't know HP values. + // Something else + else { - iTargetCurrentHP = GetCurrentHitPoints(oTarget); - iTargetMaxHP = GetMaxHitPoints(oTarget); + // If not us, we don't know HP values. + nTargetCurrentHP = GetCurrentHitPoints(oTarget); + nTargetMaxHP = GetMaxHitPoints(oTarget); // Percent = Current/Max * 100 - iTargetPercentHP = AI_GetPercentOf(iTargetCurrentHP, iTargetMaxHP); - iTargetSelf = FALSE; + nTargetPercentHP = AI_GetPercentOf(nTargetCurrentHP, nTargetMaxHP); + bTargetSelf = FALSE; } // Check for heal amounts, oTarget might have to be X damaged. // - If we have someone using knockdown on us, we make SURE we cast it sooner - if(iTargetCurrentHP < i25 || iTargetPercentHP < i30 || + if(nTargetCurrentHP < 25 || nTargetPercentHP < 30 || // High damage at once for target (over 40) - (GetLocalInt(oTarget, AI_INTEGER + AI_HIGHEST_DAMAGE_AMOUNT) > i40 && iTargetPercentHP < i40) || - // Had knockdown used on us lately + (GetLocalInt(oTarget, AI_INTEGER + AI_HIGHEST_DAMAGE_AMOUNT) > 40 && nTargetPercentHP < 40) || + // Had knockdown used on us lately - we'll heal allies sooner if this is + // the case too! (GetLocalTimer(AI_TIMER_KNOCKDOWN) && - (iTargetCurrentHP < i40 || iTargetPercentHP < i40))) + (nTargetCurrentHP < 40 || nTargetPercentHP < 40))) { - if(iPotionValue == SPELL_HEAL) + // If we have heal, we will use it now. + // * Potion, then Touch, then Mass heal. + if(bPotionsValid && nPotionValue == SPELL_HEAL) { - AI_EquipBestShield(); // Potion spell AI_ActionUseTalentDebug(tPotionHealing, OBJECT_SELF); return TRUE; } - else if(iTouchHealingValue == SPELL_HEAL) + else if(nTouchHealingValue == SPELL_HEAL) { - AI_EquipBestShield(); // Touch heal spell AI_ActionUseTalentDebug(tTouchHealing, oTarget); return TRUE; } - else if(iAOEHealingValue == SPELL_MASS_HEAL) + else if(nAOEHealingValue == SPELL_MASS_HEAL) { - AI_EquipBestShield(); // Mass heal spell AI_ActionUseTalentDebug(tAOEHealing, oTarget); return TRUE; } } // Else, another talent - IE critical wounds and under. + int nSponteousHealingValue = AI_GetBestSpontaeousHealingSpell(); // Are any of them valid? - if(GlobalBestSpontaeousHealingSpell >= i1 || - iAOEHealingValue >= i1 || iTouchHealingValue >= i1 || iPotionValue >= i1) + if(nSponteousHealingValue >= 1 || + nAOEHealingValue >= 1 || nTouchHealingValue >= 1 || nPotionValue >= 1) { // We must work out the rank of each thing we can use, IE 10 best, // 1 worst or whatever :-D - int iSpontaeousRank, iPotionRank, iAOERank, iTouchRank, iRank, - iDamageNeededToBeDone, iRankOfSpell, // iRank must be 0, which it starts at. + int nSpontaeousRank, nPotionRank, nAOERank, nTouchRank, nRank, + nDamageNeededToBeDone, nRankOfSpell, // nRank must be 0, which it starts at. // Spontaeous or a talent? 1 = Talent, 2 = Spontaeous, 0 = Error/none - iTalentOrSpon; + nTalentOrSpon; // What talent should we use? talent tToUse; - // We check if we have a spon. spell, and set its rank. Same with others. - iSpontaeousRank = AI_ReturnHealingInfo(GlobalBestSpontaeousHealingSpell, iTargetSelf); - iAOERank = AI_ReturnHealingInfo(iAOEHealingValue, iTargetSelf); - iTouchRank = AI_ReturnHealingInfo(iTouchHealingValue, iTargetSelf); - iPotionRank = AI_ReturnHealingInfo(iPotionValue, iTargetSelf); + + // Set the healing ranks. + nSpontaeousRank = AI_GetHealingSpellRank(nSponteousHealingValue, bTargetSelf); + nAOERank = AI_GetHealingSpellRank(nAOEHealingValue, bTargetSelf); + nTouchRank = AI_GetHealingSpellRank(nTouchHealingValue, bTargetSelf); + nPotionRank = AI_GetHealingSpellRank(nPotionValue, bTargetSelf); // Need a valid rank - we COULD get healing feats with these talents - if(iAOERank >= i1 || iAOERank >= i1 || iPotionRank >= i1 || iSpontaeousRank >= i1) + if(nAOERank >= 1 || nAOERank >= 1 || nPotionRank >= 1 || nSpontaeousRank >= 1) { // Determine what to use... - // Potion VS area. - if(iPotionRank >= iAOERank && iPotionRank >= i1)// Make sure we have a potion rank + // 1.4 - Cleaned this up. Less lines. + // A Potion? We like these...a lot. No concentration checks! + if(bPotionsValid && nPotionRank >= nAOERank && + nPotionRank >= nSpontaeousRank && nPotionRank >= nTouchRank) { - // Potion VS touch and so on. - if(iPotionRank >= iTouchRank) - { - if(iPotionRank >= iSpontaeousRank)// IE beats all 3 - { - iTalentOrSpon = i1; - tToUse = tPotionHealing; - iRank = iPotionRank; - iDamageNeededToBeDone = AI_ReturnHealingInfo(iPotionValue, iTargetSelf, TRUE); - } - else if(iSpontaeousRank >= i1) - { - iTalentOrSpon = i2; - iRank = iSpontaeousRank; - iDamageNeededToBeDone = AI_ReturnHealingInfo(GlobalBestSpontaeousHealingSpell, iTargetSelf, TRUE); - } - } - else if(iTouchRank >= iSpontaeousRank && iTouchRank >= i1)// Make sure we have a touch rank - { - iTalentOrSpon = i1; - tToUse = tTouchHealing; - iRank = iTouchRank; - iDamageNeededToBeDone = AI_ReturnHealingInfo(iTouchHealingValue, iTargetSelf, TRUE); - } - else if(iSpontaeousRank >= i1) - { - iTalentOrSpon = i2; - iRank = iSpontaeousRank; - iDamageNeededToBeDone = AI_ReturnHealingInfo(GlobalBestSpontaeousHealingSpell, iTargetSelf, TRUE); - } + // 1 = Talent + nTalentOrSpon = 1; + // Use a potion, so get the potion information + tToUse = tPotionHealing; + nRank = nPotionRank; + nDamageNeededToBeDone = AI_GetHealingSpellPower(nPotionValue); } - // Area VS Touch - else if(iAOERank >= iTouchRank && iAOERank >= i1)// Make sure we have an AOE rank + // Test touch rank + else if(nTouchRank >= nAOERank && nTouchRank >= nSpontaeousRank) { - if(iAOERank >= iSpontaeousRank) - { - iTalentOrSpon = i1; - tToUse = tAOEHealing; - iRank = iPotionRank; - iDamageNeededToBeDone = AI_ReturnHealingInfo(iAOEHealingValue, iTargetSelf, TRUE); - } - else if(GlobalBestSpontaeousHealingSpell) - { - iTalentOrSpon = i2; - iRank = iSpontaeousRank; - iDamageNeededToBeDone = AI_ReturnHealingInfo(GlobalBestSpontaeousHealingSpell, iTargetSelf, TRUE); - } - } - // Touch VS Spontaeous - else if(iTouchRank >= iSpontaeousRank && iTouchRank >= i1) - { - iTalentOrSpon = i1; + // 1 = Talent + nTalentOrSpon = 1; + // Use a touch healing spell tToUse = tTouchHealing; - iRank = iTouchRank; - iDamageNeededToBeDone = AI_ReturnHealingInfo(iTouchHealingValue, iTargetSelf, TRUE); + nRank = nTouchRank; + nDamageNeededToBeDone = AI_GetHealingSpellPower(nTouchHealingValue); } - // It should be Spontaeous at the very end, BUT, we need to make sure its valid - else if(iSpontaeousRank >= i1) + // Test AOE rank + else if(nAOERank >= nSpontaeousRank) { - iTalentOrSpon = i2; - iRank = iSpontaeousRank; - iDamageNeededToBeDone = AI_ReturnHealingInfo(GlobalBestSpontaeousHealingSpell, iTargetSelf, TRUE); + // 1 = Talent + nTalentOrSpon = 1; + // Use a AOE healing spell + tToUse = tAOEHealing; + nRank = nPotionRank; + nDamageNeededToBeDone = AI_GetHealingSpellPower(nAOEHealingValue); + } + else if(nSpontaeousRank >= 1) + { + // 2 = Spontaeous + nTalentOrSpon = 2; + // Use a spontaeous healing spell + nRank = nSpontaeousRank; + nDamageNeededToBeDone = AI_GetHealingSpellPower(nSponteousHealingValue); } // Now, have we a talent or spell to use? - if(iTalentOrSpon && iRank >= i1) + if(nTalentOrSpon >= 1 && nRank >= 1) { // If the current HP is under the damage that is healed, // or under 25% left :-) - if(iTargetCurrentHP <= (iTargetMaxHP - iDamageNeededToBeDone) || - (iTargetPercentHP < i25)) + if(nTargetCurrentHP <= (nTargetMaxHP - nDamageNeededToBeDone) || + (nTargetPercentHP < 25)) { // Level check. Our HD must be a suitble amount, or no melee attackers. // Even if we are healing others - we don't bother with bad healing // Rank of the spell, can be in a range over our HD -5. - if(((iRank - GlobalOurHitDice) >= -i5) || + if(((nRank - GlobalOurHitDice) >= -5) || // OR Rank of 16+ (critical wounds or more) are always done. - (iRank >= i16) || + (nRank >= 16) || // OR no valid nearest enemy. (!GlobalAnyValidTargetObject) || // OR 0 Melee attackers, and a larger range (up to -10 our HD) - ((GlobalMeleeAttackers < i1) && ((iRank - GlobalOurHitDice) >= -10))) + ((GlobalMeleeAttackers < 1) && ((nRank - GlobalOurHitDice) >= -10))) { // Use it...and attack with a bow. Always return TRUE. // Need only one debug :-P - // 19: "[DCR:Healing] (Should) Healing [Target]" + GetName(oTarget) + " [CurrentHP|Max|ID|Rank|Power] " + IntToString((10000 * iTargetCurrentHP) + (1000 * iTargetMaxHP) + (100 * GetIdFromTalent(tToUse)) + (10 * iRank) + (iDamageNeededToBeDone)) - DebugActionSpeakByInt(19, oTarget, ((10000 * iTargetCurrentHP) + (1000 * iTargetMaxHP) + (100 * GetIdFromTalent(tToUse)) + (10 * iRank) + (iDamageNeededToBeDone))); + // 19: "[DCR:Healing] (Should) Healing [Target]" + GetName(oTarget) + " [CurrentHP|Max|ID|Rank|Power] " + IntToString((10000 * nTargetCurrentHP) + (1000 * nTargetMaxHP) + (100 * GetIdFromTalent(tToUse)) + (10 * iRank) + (nDamageNeededToBeDone)) + DebugActionSpeakByInt(19, oTarget, ((10000 * nTargetCurrentHP) + (1000 * nTargetMaxHP) + (100 * GetIdFromTalent(tToUse)) + (10 * nRank) + (nDamageNeededToBeDone))); // Talent! - if(iTalentOrSpon == i1) + if(nTalentOrSpon == 1) { if(GetIsTalentValid(tToUse)) { @@ -4685,10 +4365,10 @@ int AI_ActionHealObject(object oTarget) } } // Spontaeous Spell! - else //if(iTalentOrSpon == i2) // (is always 2 or 1 or 0) + else //if(nTalentOrSpon == 2) // (is always 2 or 1 or 0) { // Use the same thing as the inflict spell - if(AI_ActionCastSpontaeousSpell(GlobalBestSpontaeousHealingSpell, TRUE, oTarget)) return TRUE; + if(AI_ActionCastSpontaeousSpell(nSponteousHealingValue, oTarget)) return TRUE; } } } @@ -4699,14 +4379,16 @@ int AI_ActionHealObject(object oTarget) // Check if it is us and so on. // If it is us, and we have no potion spell, if(oTarget == OBJECT_SELF && - GlobalOurPercentHP < i40 && !iPotionRank && + GlobalOurPercentHP < 40 && !nPotionRank && GetSpawnInCondition(AI_FLAG_OTHER_CHEAT_MORE_POTIONS, AI_OTHER_MASTER)) { if(!GetIsObjectValid(GetItemPossessedBy(OBJECT_SELF, "nw_it_mpotion003"))) { // 20: "[DCR Healing] Boss Action, create Critical Wounds potion" DebugActionSpeakByInt(20); - CreateItemOnObject("nw_it_mpotion003"); + // 1.4 - This is now made undroppable, so will not be looted. + object oPotion = CreateItemOnObject("nw_it_mpotion003"); + SetDroppableFlag(oPotion, FALSE); } } } @@ -4723,53 +4405,58 @@ int AI_ActionHealObject(object oTarget) int AI_ActionHealUndeadObject(object oTarget) { // First, we check for heal spells in the talents we have. They are special cases! - // We set this to the right value if the target is us. - int iTargetCurrentHP = GlobalOurCurrentHP; - int iTargetMaxHP = GlobalOurMaxHP; - int iTargetPercentHP = GlobalOurPercentHP; - // If not us, we don't know HP values. - if(oTarget != OBJECT_SELF) + int nTargetCurrentHP, nTargetMaxHP, nTargetPercentHP; + // Test if we are targeting ourselves. + if(oTarget == OBJECT_SELF) { - iTargetCurrentHP = GetCurrentHitPoints(oTarget); - iTargetMaxHP = GetMaxHitPoints(oTarget); + // We set this to the right value if the target is us. + nTargetCurrentHP = GlobalOurCurrentHP; + nTargetMaxHP = GlobalOurMaxHP; + nTargetPercentHP = GlobalOurPercentHP; + } + else + { + // If not us, we don't know HP values. + nTargetCurrentHP = GetCurrentHitPoints(oTarget); + nTargetMaxHP = GetMaxHitPoints(oTarget); // Percent = Current/Max * 100 - iTargetPercentHP = AI_GetPercentOf(iTargetCurrentHP, iTargetMaxHP); + nTargetPercentHP = AI_GetPercentOf(nTargetCurrentHP, nTargetMaxHP); } // Check for Harm amounts, oTarget might have to be X damaged. - if(iTargetCurrentHP < i25 || iTargetPercentHP < i30 || + if(nTargetCurrentHP < 25 || nTargetPercentHP < 30 || // High damage at once for target (over 40) - (GetLocalInt(oTarget, AI_INTEGER + AI_HIGHEST_DAMAGE_AMOUNT) > i40 && iTargetPercentHP < i40) || + (GetLocalInt(oTarget, AI_INTEGER + AI_HIGHEST_DAMAGE_AMOUNT) > 40 && nTargetPercentHP < 40) || // Had knockdown used on us lately (GetLocalTimer(AI_TIMER_KNOCKDOWN) && - (iTargetCurrentHP < i40 || iTargetPercentHP < i40))) + (nTargetCurrentHP < 40 || nTargetPercentHP < 40))) { // If us, use harm self if(oTarget == OBJECT_SELF) { // Innate ability. Under healing self, so leave as innate. - if(AI_ActionCastSpell(AI_SPELLABILITY_UNDEAD_HARM_SELF, FALSE, oTarget)) return TRUE; + if(AI_ActionCastSpell(AI_SPELLABILITY_UNDEAD_HARM_SELF, oTarget)) return TRUE; } - // Use it...if we have it...and attack with a bow. - if(AI_ActionCastSpell(SPELL_HARM, SpellHostTouch, oTarget, i16, FALSE, ItemHostTouch)) return TRUE; + // Use it...if we have it. Healing with harm rocks! + if(AI_ActionCastSpell(SPELL_HARM, oTarget, 16, FALSE)) return TRUE; } // Other Under things! // Inflict range...always use top 2. - if(AI_ActionCastSpontaeousSpell(SPELL_INFLICT_CRITICAL_WOUNDS, SpellHostTouch, oTarget)) return TRUE; - if(AI_ActionCastSpontaeousSpell(SPELL_INFLICT_SERIOUS_WOUNDS, SpellOtherSpell, oTarget)) return TRUE; + if(AI_ActionCastSpontaeousSpell(SPELL_INFLICT_CRITICAL_WOUNDS, oTarget)) return TRUE; + if(AI_ActionCastSpontaeousSpell(SPELL_INFLICT_SERIOUS_WOUNDS, oTarget)) return TRUE; // Circle of doom: d8 + Caster level heal. Category 1. - if(AI_ActionCastSpell(SPELL_CIRCLE_OF_DEATH, SpellHostRanged, oTarget, i15, TRUE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpell(SPELL_CIRCLE_OF_DEATH, oTarget, 15, TRUE)) return TRUE; // Negative Energy Burst...this is good enough to always use normally...same as Circle of doom! (d8 + caster) - if(AI_ActionCastSpell(SPELL_NEGATIVE_ENERGY_BURST, SpellHostRanged, oTarget, i13, TRUE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpell(SPELL_NEGATIVE_ENERGY_BURST, oTarget, 13, TRUE)) return TRUE; // Lower ones ain't too good for some HD (ours!) - if(!GlobalAnyValidTargetObject || GlobalOurHitDice <= i12) + if(!GlobalAnyValidTargetObject || GlobalOurHitDice <= 12) { - if(AI_ActionCastSpontaeousSpell(SPELL_INFLICT_MODERATE_WOUNDS, SpellOtherSpell, oTarget)) return TRUE; - if(!GlobalAnyValidTargetObject || GlobalOurHitDice <= i6) + if(AI_ActionCastSpontaeousSpell(SPELL_INFLICT_MODERATE_WOUNDS, oTarget)) return TRUE; + if(!GlobalAnyValidTargetObject || GlobalOurHitDice <= 6) { - if(AI_ActionCastSpontaeousSpell(SPELL_INFLICT_LIGHT_WOUNDS, SpellOtherSpell, oTarget)) return TRUE; - if(!GlobalAnyValidTargetObject || GlobalOurHitDice <= i2) + if(AI_ActionCastSpontaeousSpell(SPELL_INFLICT_LIGHT_WOUNDS, oTarget)) return TRUE; + if(!GlobalAnyValidTargetObject || GlobalOurHitDice <= 2) { - if(AI_ActionCastSpontaeousSpell(SPELL_INFLICT_MINOR_WOUNDS, SpellOtherSpell, oTarget)) return TRUE; + if(AI_ActionCastSpontaeousSpell(SPELL_INFLICT_MINOR_WOUNDS, oTarget)) return TRUE; } } } @@ -4790,74 +4477,95 @@ int AI_ActionHealUndeadObject(object oTarget) //:://///////////////////////////////////////////*/ int AI_AttemptHealingSelf() { + // Flag for "Do not heal anyone". Useful also for stopping non-healers + // even checking. if(GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_CURING, AI_OTHER_COMBAT_MASTER)) return FALSE; + // If we are polymorphed, cannot heal anyone - thats cheating. Using our + // class feats we shouldn't have access to also isn't a nice idea. + if(AI_GetAIHaveEffect(GlobalEffectPolymorph)) return FALSE; + // Determine what we should heal at... - int iPercent = GetBoundriedAIInteger(AI_HEALING_US_PERCENT, i50, i100, i1); + int nPercent = GetBoundriedAIInteger(AI_HEALING_US_PERCENT, 50, 100, 1); + int nRace = GetRacialType(OBJECT_SELF); // What % are we at? It is GlobalOurPercentHP // Are we under the right %? - if(GlobalOurPercentHP < iPercent) + if(GlobalOurPercentHP <= nPercent) { // We can't be a silly race! - if(GlobalOurRace != RACIAL_TYPE_UNDEAD && - GlobalOurRace != RACIAL_TYPE_CONSTRUCT) + if(nRace != RACIAL_TYPE_UNDEAD && + nRace != RACIAL_TYPE_CONSTRUCT) { int nWillHeal; // If we can heal self with feats...use them! No AOO if(GetHasFeat(FEAT_WHOLENESS_OF_BODY) && - ((GlobalOurCurrentHP <= GetLevelByClass(CLASS_TYPE_MONK, OBJECT_SELF) * i2) || - GlobalOurPercentHP < i20)) + ((GlobalOurCurrentHP <= GetLevelByClass(CLASS_TYPE_MONK, OBJECT_SELF) * 2) || + GlobalOurPercentHP < 20)) { - if(AI_ActionUseFeatOnObject(FEAT_WHOLENESS_OF_BODY)) return TRUE; + if(AI_ActionUseSpellLikeFeat(FEAT_WHOLENESS_OF_BODY, SPELLABILITY_WHOLENESS_OF_BODY)) return TRUE; } // Only use this on ourselves. if(GetHasFeat(FEAT_LAY_ON_HANDS)) { // This does the actual formula...note, putting ones to stop DIVIDE BY ZERO errors int nChr = GetAbilityModifier(ABILITY_CHARISMA); - if(nChr < i1) nChr = i1;// Error checking + if(nChr < 1) nChr = 1;// Error checking int nLevel = GetLevelByClass(CLASS_TYPE_PALADIN); - if(nLevel < i1) nLevel = i1;// Error checking + if(nLevel < 1) nLevel = 1;// Error checking //Caluclate the amount needed to be at, to use. int nHeal = nLevel * nChr; - if(nHeal < i1) nHeal = i1;// Error checking + if(nHeal < 1) nHeal = 1;// Error checking // We can be under the amount healed, or under 30 if(GlobalOurCurrentHP < nHeal || - GlobalOurPercentHP < i30) + GlobalOurPercentHP < 30) { - if(AI_ActionUseFeatOnObject(FEAT_LAY_ON_HANDS)) return TRUE; + if(AI_ActionUseSpellLikeFeat(FEAT_LAY_ON_HANDS, SPELLABILITY_LAY_ON_HANDS)) return TRUE; } } // Note: Feat Lesser Bodily Adjustment uses cure light wounds spell script. // Odd classes mean no potions. - int iPotions = TRUE; - if(GlobalOurRace == RACIAL_TYPE_ABERRATION || - GlobalOurRace == RACIAL_TYPE_BEAST || GlobalOurRace == RACIAL_TYPE_ELEMENTAL || - GlobalOurRace == RACIAL_TYPE_VERMIN || GlobalOurRace == RACIAL_TYPE_MAGICAL_BEAST || - GlobalOurRace == RACIAL_TYPE_DRAGON || GlobalOurRace == RACIAL_TYPE_ANIMAL) - iPotions = FALSE; + int bPotions = TRUE; + if(nRace == RACIAL_TYPE_ABERRATION || + nRace == RACIAL_TYPE_BEAST || nRace == RACIAL_TYPE_ELEMENTAL || + nRace == RACIAL_TYPE_VERMIN || nRace == RACIAL_TYPE_MAGICAL_BEAST || + nRace == RACIAL_TYPE_DRAGON || nRace == RACIAL_TYPE_ANIMAL) + bPotions = FALSE; // Lets see if we can use a healing kit! Only a valid race (as potions) - if(iPotions && GetAIInteger(AI_VALID_HEALING_KITS) && + if(bPotions && GetAIInteger(AI_VALID_HEALING_KITS) && !GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_USING_HEALING_KITS, AI_OTHER_COMBAT_MASTER)) { - // Need a valid kit and skill to be worth using :-) - if(GetIsObjectValid(GlobalHealingKit) && - (GetSkillRank(SKILL_HEAL) >= (GlobalOurHitDice / i3) || - GlobalOurPercentHP < i30)) + // Healing Kits + int nHealLeft = GetAIInteger(AI_VALID_HEALING_KITS); + object oKit; + // We have a healing kit? + if(nHealLeft > 0) { - AI_EquipBestShield(); - // 21: "[DCR:Casting] Healing self with healing kit, [Kit] " + GetName(GlobalHealingKit) - DebugActionSpeakByInt(21, GlobalHealingKit); - ActionUseSkill(SKILL_HEAL, OBJECT_SELF, i0, GlobalHealingKit); - return TRUE; + // Get the kit + object oKit = GetAIObject(AI_VALID_HEALING_KIT_OBJECT); + // Oh, if we don't have one, re-set them, and only them. + if(!GetIsObjectValid(oKit) && nHealLeft >= 2) + { + SetAIInteger(RESET_HEALING_KITS, TRUE); + ExecuteScript(FILE_RE_SET_WEAPONS, OBJECT_SELF); + } + // Need a valid kit and skill to be worth using :-) + if((GetSkillRank(SKILL_HEAL) >= (GlobalOurHitDice / 3) || + GlobalOurPercentHP < 30)) + { + AI_EquipBestShield(); + // 21: "[DCR:Casting] Healing self with healing kit, [Kit] " + GetName(oKit) + DebugActionSpeakByInt(21, oKit); + ActionUseSkill(SKILL_HEAL, OBJECT_SELF, 0, oKit); + return TRUE; + } } } // Finally, heal self with potions, spells or whatever. - return AI_ActionHealObject(OBJECT_SELF); + return AI_ActionHealObject(OBJECT_SELF, bPotions); } - else if(GlobalOurRace == RACIAL_TYPE_UNDEAD) + else if(nRace == RACIAL_TYPE_UNDEAD) { // Undead can cast some spells to heal... return AI_ActionHealUndeadObject(OBJECT_SELF); @@ -4865,68 +4573,6 @@ int AI_AttemptHealingSelf() } return FALSE; } -// Get the nearest seen ally creature with the effect. -// - Checks us first -// - Then checks leader -// - Then loops seen allies within 20M. -object AI_GetNearestAllyWithEffect(int iEffectHex) -{ - // Check self - if(AI_GetAIHaveEffect(iEffectHex)) return OBJECT_SELF; - // Check leader - if(AI_GetAIHaveEffect(iEffectHex, GlobalNearestLeader)) return GlobalNearestLeader; - - // Check seen allies in 20M - int iCnt = i1; - object oAlly = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN + IntToString(iCnt)); - while(GetIsObjectValid(oAlly) && GetDistanceToObject(oAlly) <= f20) - { - // Don't target undead - if(GetRacialType(oAlly) != RACIAL_TYPE_UNDEAD) - { - // Has it got the effect? - // - Stop and return oAlly. - if(AI_GetAIHaveEffect(iEffectHex, oAlly)) return oAlly; - } - // Carry on loop - iCnt++; - oAlly = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN + IntToString(iCnt)); - } - return OBJECT_INVALID; -} -// Returns the nearest ally with iMin effects, and X more based on HD. -// - Checks us first. True if (HD/6) Effects and (iMin - 1) effects -// - Checks leader next. True if (HD/5) Effects and (iMin - 2) effects -// - Checks allies after. True if (HD/4) Effects and (iMin) effects -object AI_GetNearestAllyWithRestoreEffects(int iMin) -{ - // Check self /6 (need much less) - int iAmount = GetLocalInt(OBJECT_SELF, AI_ABILITY_DECREASE); - if(iAmount >= iMin - i1 && iAmount >= GlobalOurHitDice / i6) return OBJECT_SELF; - // Check leader - /5 (need less) - if(GlobalValidLeader) - { - iAmount = GetLocalInt(GlobalNearestLeader, AI_ABILITY_DECREASE); - if(iAmount >= iMin - i2 && iAmount >= GetHitDice(GlobalNearestLeader) / i5) return GlobalNearestLeader; - } - // Check seen allies in 20M - until we get one with /2 effects, minimum 4. - int iCnt = i1; - object oAlly = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN + IntToString(iCnt)); - while(GetIsObjectValid(oAlly) && GetDistanceToObject(oAlly) <= f20) - { - // Don't target undead - if(GetRacialType(oAlly) != RACIAL_TYPE_UNDEAD) - { - // Check ally - iAmount = GetLocalInt(oAlly, AI_ABILITY_DECREASE); - if(iAmount >= iMin && iAmount >= GetHitDice(oAlly) / i4) return oAlly; - } - // Carry on loop - iCnt++; - oAlly = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN + IntToString(iCnt)); - } - return OBJECT_INVALID; -} /*:://///////////////////////////////////////////// //:: Name: TalentCureCondition //:://///////////////////////////////////////////// @@ -4941,168 +4587,324 @@ object AI_GetNearestAllyWithRestoreEffects(int iMin) int AI_AttemptCureCondition() { // Set OnSpawn if we have any of the spells we use. - if(!GetSpawnInCondition(AI_VALID_CURE_CONDITION_SPELLS, AI_VALID_SPELLS) || + if(/*!GetSpawnInCondition(AI_VALID_CURE_CONDITION_SPELLS, AI_VALID_SPELLS) ||*/ GetSpawnInCondition(AI_FLAG_OTHER_LAG_NO_CURING_ALLIES, AI_OTHER_MASTER) || GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_CURING, AI_OTHER_COMBAT_MASTER)) return FALSE; + // If we are polymorphed, cannot heal anyone - thats cheating. Using our + // class feats we shouldn't have access to also isn't a nice idea. + if(AI_GetAIHaveEffect(GlobalEffectPolymorph)) return FALSE; + // Check timer if(GetLocalTimer(AI_TIMER_CURE_CONDITION)) return FALSE; - int iTimer = GetAIInteger(SECONDS_BETWEEN_STATUS_CHECKS); - if(iTimer >= i1) + int nTimer = GetAIInteger(SECONDS_BETWEEN_STATUS_CHECKS); + if(nTimer >= 1) { // Set timer - SetLocalTimer(AI_TIMER_CURE_CONDITION, IntToFloat(iTimer)); + SetLocalTimer(AI_TIMER_CURE_CONDITION, IntToFloat(nTimer)); } - // Cure spells in order: + // Cure spells: // SPELL_GREATER_RESTORATION - Ability Decrease, AC decrease, Attack decrease, - // Damage Decrease, Damage Immunity Decrease, Saving Throw Decrease, Spell - // resistance Decrease, Skill decrease, Blindness, Deaf, Curse, Disease, Poison, - // Charmed, Dominated, Dazed, Confused, Frightened, Negative level, Paralyze, - // Slow, Stunned. - // SPELL_FREEDOM - Paralyze, Entangle, Slow, Movement speed decrease. (+Immunity!) + // Damage Decrease, Damage Immunity Decrease, Saving Throw Decrease, + // Spell resistance Decrease, Skill decrease, Blindness, Deaf, Curse, Disease, + // Poison, Charmed, Dominated, Dazed, Confused, Frightened, Negative level, + // Paralyze, Slow, Stunned. // SPELL_RESTORATION - Ability Decrease, AC decrease, Attack Decrease, // Damage Decrease, Damage Immunity Decrease, Saving Throw Decrease, // Spell Resistance Decrease, Skill Decrease, Blindess, Deaf, Paralyze, Negative level + // SPELL_LESSER_RESTORATION - Ability Decrease, AC decrease, Attack Decrease, + // Damage Decrease, Damage Immunity Decrease, Saving throw Decrease, + // Spell Resistance Decrease, Skill decrease. + // - More Specific ones. + // SPELL_FREEDOM - Paralyze, Entangle, Slow, Movement speed decrease. (+Immunity!) // SPELL_REMOVE_BLINDNESS_AND_DEAFNESS - Blindess, Deaf. // SPELL_NEUTRALIZE_POISON - Poison // SPELL_REMOVE_DISEASE - Disease // SPELL_REMOVE_CURSE - Curse - // SPELL_LESSER_RESTORATION - Ability Decrease, AC decrease, Attack Decrease, - // Damage Decrease, Damage Immunity Decrease, Saving throw Decrease, - // Spell Resistance Decrease, Skill decrease. // Note: We like to dispel anything that stuns us - EG paralyze effects, // stunning, confusion, dazedness VIA Greater Restoration, after that, // blindness (A great inhibiter) and then poison disease and curse. + // Check seen allies in 20M + // Work in a loop of all creatures to check the loop only once. + + // To prioritise (IE: Ignore our poison, but heal someone who is petrified) + // we loop all targets, and set them to variable objects for this function. + int bPetrify, bParalsis, bDazed, bBlind, bNegative, nAbilityDamage, + bSlow, bEntangle,/* Set bEntangle to bSpeedDecrease too */ bDeaf, + bCurse, bDisease, bPoison, bFear, bStun; + // Objects which have those effects + object oPetrify, oParalsis, oDazed, oBlind, oNegative, oAbilityDamage, + oSlow, oEntangle,/* Set oEntangle to oSpeedDecrease too */ oDeaf, + oCurse, oDisease, oPoison, oFear, oStun; + + // THOUGHTS: + + // Perhaps have heal self, then check very bad conditoins (paralysis, petrify) + // unless a really damaged ally is nearby, then heal, then remove the not so + // bad effects. + + // However, start with us! + int nCnt = 0;// When we add 1, we'll get the first target. + int nEffectHex, nAbility; + object oHeal = OBJECT_SELF; + while(GetIsObjectValid(oHeal) && GetDistanceToObject(oHeal) <= 20.0) + { + // Don't target undead + if(GetRacialType(oHeal) != RACIAL_TYPE_UNDEAD) + { + // Go through possible effects in priority order. + nEffectHex = GetLocalInt(oHeal, AI_EFFECT_HEX); + if(bPetrify != TRUE && (nEffectHex & GlobalEffectPetrify)) + { + oPetrify = oHeal; + bPetrify = TRUE; + } + // Paralsis + if(bParalsis != TRUE && (nEffectHex & GlobalEffectParalyze)) + { + oParalsis = oHeal; + bParalsis = TRUE; + } + // Stun + if(bStun != TRUE && (nEffectHex & GlobalEffectStun)) + { + oStun = oHeal; + bStun = TRUE; + } + // Fear + if(bFear != TRUE && (nEffectHex & GlobalEffectFear)) + { + oFear = oHeal; + bFear = TRUE; + } + // Dazed + if(bDazed != TRUE && (nEffectHex & GlobalEffectDazed)) + { + oDazed = oHeal; + bDazed = TRUE; + } + // Blindness + if(bBlind != TRUE && (nEffectHex & GlobalEffectBlindness)) + { + oBlind = oHeal; + bBlind = TRUE; + } + // Negative level is tough + if(bNegative != TRUE && (nEffectHex & GlobalEffectNegativeLevel)) + { + oNegative = oHeal; + bNegative = TRUE; + } + // Slow - only set if they are not hasted. It'd be a waste otherwise. + if(bSlow != TRUE && (nEffectHex & GlobalEffectSlowed) && + !AI_GetAIHaveEffect(GlobalEffectHaste, oHeal)) + { + oSlow = oHeal; + bSlow = TRUE; + } + // Entangle OR movement slowed. + if(bEntangle != TRUE && ((nEffectHex & GlobalEffectSlowed) || + (nEffectHex & GlobalEffectMovementSpeedDecrease))) + { + oEntangle = oHeal; + bEntangle = TRUE; + } + // Deafness + if(bDeaf != TRUE && (nEffectHex & GlobalEffectDeaf)) + { + oDeaf = oHeal; + bDeaf = TRUE; + } + // Curse + if(bCurse != TRUE && (nEffectHex & GlobalEffectCurse)) + { + oCurse = oHeal; + bCurse = TRUE; + } + // Disease + if(bDisease != TRUE && (nEffectHex & GlobalEffectDisease)) + { + oDisease = oHeal; + bDisease = TRUE; + } + // Poison + if(bPoison != TRUE && (nEffectHex & GlobalEffectPoison)) + { + oPoison = oHeal; + bPoison = TRUE; + } + // Lots of negative effects. + // Set all 3 here. + + // Returns the nearest ally with nMin effects, and X more based on HD. + // - Checks us first. True if (HD/6) Effects and (nMin - 1) effects + // - Checks leader next. True if (HD/5) Effects and (nMin - 2) effects + // - Checks allies after. True if (HD/4) Effects and (nMin) effects + nAbility = GetLocalInt(oHeal, AI_ABILITY_DECREASE); + + // Must have more ability decreases then the last one checked, and + // more damage then a cirtain amount compared to the hit dice, or + // at least 10. + // A LOT more simple then before. + if(nAbility > nAbilityDamage && nAbility >= 10 && + nAbility >= GetHitDice(oHeal) / 4) + { + nAbilityDamage = nAbility; + oAbilityDamage = oHeal; + } + } + // If we are blind, we cannot target others to heal them. We must only + // target ourselves (if anyone!) + if(AI_GetAIHaveEffect(GlobalEffectBlindness, OBJECT_SELF)) + { + // Break. + break; + } + // Carry on loop + nCnt++; + oHeal = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN + IntToString(nCnt)); + } + + // Lastly, ability damage ETC can come in after the stuns, or right at // the end, depending on the amount. - object oHeal; - // Petrify! - oHeal = AI_GetNearestAllyWithEffect(GlobalEffectPetrify); - if(GetIsObjectValid(oHeal)) + + // Petrify - remove it first. + if(bPetrify) { // Only one - if(AI_ActionCastSpell(SPELL_STONE_TO_FLESH, FALSE, oHeal)) return TRUE; + if(AI_ActionCastSpell(SPELL_STONE_TO_FLESH, oPetrify)) return TRUE; } - // First, Paralysis should be removed. - oHeal = AI_GetNearestAllyWithEffect(GlobalEffectParalyze); - if(GetIsObjectValid(oHeal)) + // First, Paralysis should be removed (Includes stunning) + if(bParalsis) { // Freedom first - if(AI_ActionCastSpell(SPELL_FREEDOM_OF_MOVEMENT, FALSE, oHeal)) return TRUE; - if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, FALSE, oHeal)) return TRUE; + if(AI_ActionCastSpell(SPELL_FREEDOM_OF_MOVEMENT, oParalsis)) return TRUE; + if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, oParalsis)) return TRUE; + } + // Stun - only G.Restoration removes this. + if(bStun) + { + if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, oStun)) return TRUE; } // Daze - oHeal = AI_GetNearestAllyWithEffect(GlobalEffectDazed); - if(GetIsObjectValid(oHeal)) + if(bDazed) { // Freedom first - if(AI_ActionCastSpell(SPELL_FREEDOM_OF_MOVEMENT, FALSE, oHeal)) return TRUE; - if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, FALSE, oHeal)) return TRUE; + if(AI_ActionCastSpell(SPELL_FREEDOM_OF_MOVEMENT, oDazed)) return TRUE; + if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, oDazed)) return TRUE; + } + // Fear + if(bFear) + { + // Freedom first + if(AI_ActionCastSpell(SPELL_REMOVE_FEAR, oFear)) return TRUE; + if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, oFear)) return TRUE; } // Next? blindness - oHeal = AI_GetNearestAllyWithEffect(GlobalEffectBlindness); - if(GetIsObjectValid(oHeal)) + if(bBlind) { // Remove first - if(AI_ActionCastSpell(SPELL_REMOVE_BLINDNESS_AND_DEAFNESS, FALSE, oHeal)) return TRUE; - if(AI_ActionCastSpell(SPELL_FREEDOM_OF_MOVEMENT, FALSE, oHeal)) return TRUE; - if(AI_ActionCastSpell(SPELL_RESTORATION, FALSE, oHeal)) return TRUE; - if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, FALSE, oHeal)) return TRUE; + if(AI_ActionCastSpell(SPELL_REMOVE_BLINDNESS_AND_DEAFNESS, oBlind)) return TRUE; + if(AI_ActionCastSpell(SPELL_FREEDOM_OF_MOVEMENT, oBlind)) return TRUE; + if(AI_ActionCastSpell(SPELL_RESTORATION, oBlind)) return TRUE; + if(AI_ActionCastSpell(AI_SPELLABILITY_RESTORATION_OTHERS, oBlind)) return TRUE; + if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, oBlind)) return TRUE; } // Lots of negative effects. - oHeal = AI_GetNearestAllyWithRestoreEffects(i7); - if(GetIsObjectValid(oHeal)) + if(nAbilityDamage >= 7) { // Only these can remove ability decreases ETC. - if(AI_ActionCastSpell(SPELL_LESSER_RESTORATION, FALSE, oHeal)) return TRUE; - if(AI_ActionCastSpell(SPELL_RESTORATION, FALSE, oHeal)) return TRUE; - if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, FALSE, oHeal)) return TRUE; + if(AI_ActionCastSpell(SPELL_LESSER_RESTORATION, oAbilityDamage)) return TRUE; + if(AI_ActionCastSpell(SPELL_RESTORATION, oAbilityDamage)) return TRUE; + if(AI_ActionCastSpell(AI_SPELLABILITY_RESTORATION_OTHERS, oAbilityDamage)) return TRUE; + if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, oAbilityDamage)) return TRUE; } // Negative level is tough - oHeal = AI_GetNearestAllyWithEffect(GlobalEffectNegativeLevel); - if(GetIsObjectValid(oHeal)) + if(bNegative) { // Only these can remove it - if(AI_ActionCastSpell(SPELL_RESTORATION, FALSE, oHeal)) return TRUE; - if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, FALSE, oHeal)) return TRUE; + if(AI_ActionCastSpell(SPELL_RESTORATION, oNegative)) return TRUE; + if(AI_ActionCastSpell(AI_SPELLABILITY_RESTORATION_OTHERS, oNegative)) return TRUE; + if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, oNegative)) return TRUE; } // Slow - oHeal = AI_GetNearestAllyWithEffect(GlobalEffectSlowed); - if(GetIsObjectValid(oHeal) && !AI_GetAIHaveEffect(GlobalEffectHaste, oHeal)) + if(bSlow) { // haste - we don't set we have this OnSpawn, because if we have not // got any other healing cure spells, we're probably not meant to cast it on slowed people. - if(AI_ActionCastSpell(SPELL_MASS_HASTE, FALSE, oHeal)) return TRUE; - if(AI_ActionCastSpell(SPELL_HASTE, FALSE, oHeal)) return TRUE; + if(AI_ActionCastSpell(SPELL_MASS_HASTE, oSlow)) return TRUE; + if(AI_ActionCastSpell(SPELL_HASTE, oSlow)) return TRUE; } - // Entangle/Move slowdown - oHeal = AI_GetNearestAllyWithEffect(GlobalEffectEntangle); - if(!GetIsObjectValid(oHeal)) + // Heal things with freedom of movement/greater restoration + if(bSlow) { - oHeal = AI_GetNearestAllyWithEffect(GlobalEffectMovementSpeedDecrease); + oHeal = oSlow; } - if(GetIsObjectValid(oHeal)) + else if(bEntangle) + { + oHeal = oSlow; + } + // If got either, then oHeal will be the appropriate one to heal ith FoM + if(bSlow || bEntangle) { // Freedom first - if(AI_ActionCastSpell(SPELL_FREEDOM_OF_MOVEMENT, FALSE, oHeal)) return TRUE; - if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, FALSE, oHeal)) return TRUE; + if(AI_ActionCastSpell(SPELL_FREEDOM_OF_MOVEMENT, oHeal)) return TRUE; + if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, oHeal)) return TRUE; } // Deafness - oHeal = AI_GetNearestAllyWithEffect(GlobalEffectDeaf); - if(GetIsObjectValid(oHeal)) + if(bDeaf) { // Remove first - if(AI_ActionCastSpell(SPELL_REMOVE_BLINDNESS_AND_DEAFNESS, FALSE, oHeal)) return TRUE; - if(AI_ActionCastSpell(SPELL_FREEDOM_OF_MOVEMENT, FALSE, oHeal)) return TRUE; - if(AI_ActionCastSpell(SPELL_RESTORATION, FALSE, oHeal)) return TRUE; - if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, FALSE, oHeal)) return TRUE; + if(AI_ActionCastSpell(SPELL_REMOVE_BLINDNESS_AND_DEAFNESS, oDeaf)) return TRUE; + if(AI_ActionCastSpell(SPELL_FREEDOM_OF_MOVEMENT, oDeaf)) return TRUE; + if(AI_ActionCastSpell(SPELL_RESTORATION, oDeaf)) return TRUE; + if(AI_ActionCastSpell(AI_SPELLABILITY_RESTORATION_OTHERS, oDeaf)) return TRUE; + if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, oDeaf)) return TRUE; } - // Quite a few negative effects. - oHeal = AI_GetNearestAllyWithRestoreEffects(i5); - if(GetIsObjectValid(oHeal)) + // Quite a few negative effects (5 or more) + if(nAbilityDamage >= 5) { // Only these can remove ability decreases ETC. - if(AI_ActionCastSpell(SPELL_LESSER_RESTORATION, FALSE, oHeal)) return TRUE; - if(AI_ActionCastSpell(SPELL_RESTORATION, FALSE, oHeal)) return TRUE; - if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, FALSE, oHeal)) return TRUE; + if(AI_ActionCastSpell(SPELL_LESSER_RESTORATION, oAbilityDamage)) return TRUE; + if(AI_ActionCastSpell(SPELL_RESTORATION, oAbilityDamage)) return TRUE; + if(AI_ActionCastSpell(AI_SPELLABILITY_RESTORATION_OTHERS, oBlind)) return TRUE; + if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, oAbilityDamage)) return TRUE; } // Curse - oHeal = AI_GetNearestAllyWithEffect(GlobalEffectCurse); - if(GetIsObjectValid(oHeal)) + if(bCurse) { // Remove first - if(AI_ActionCastSpell(SPELL_REMOVE_CURSE, FALSE, oHeal)) return TRUE; - if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, FALSE, oHeal)) return TRUE; + if(AI_ActionCastSpell(SPELL_REMOVE_CURSE, oCurse)) return TRUE; + if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, oCurse)) return TRUE; } // Disease - oHeal = AI_GetNearestAllyWithEffect(GlobalEffectDisease); - if(GetIsObjectValid(oHeal)) + if(bDisease) { // Remove first - if(AI_ActionCastSpell(SPELL_REMOVE_DISEASE, FALSE, oHeal)) return TRUE; - if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, FALSE, oHeal)) return TRUE; + if(AI_ActionCastSpell(SPELL_REMOVE_DISEASE, oDisease)) return TRUE; + if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, oDisease)) return TRUE; } // Poison - oHeal = AI_GetNearestAllyWithEffect(GlobalEffectPoison); - if(GetIsObjectValid(oHeal)) + if(bPoison) { // Remove first - if(AI_ActionCastSpell(SPELL_NEUTRALIZE_POISON, FALSE, oHeal)) return TRUE; - if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, FALSE, oHeal)) return TRUE; + if(AI_ActionCastSpell(SPELL_NEUTRALIZE_POISON, oPoison)) return TRUE; + if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, oPoison)) return TRUE; } // See if there is anyone with a decent amount of effects. - // Some negative effects. - oHeal = AI_GetNearestAllyWithRestoreEffects(i3); - if(GetIsObjectValid(oHeal)) + // Some negative effects (3 or more) + if(nAbilityDamage >= 3) { // Only these can remove ability decreases ETC. - if(AI_ActionCastSpell(SPELL_LESSER_RESTORATION, FALSE, oHeal)) return TRUE; - if(AI_ActionCastSpell(SPELL_RESTORATION, FALSE, oHeal)) return TRUE; - if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, FALSE, oHeal)) return TRUE; + if(AI_ActionCastSpell(SPELL_LESSER_RESTORATION, oAbilityDamage)) return TRUE; + if(AI_ActionCastSpell(SPELL_RESTORATION, oAbilityDamage)) return TRUE; + if(AI_ActionCastSpell(AI_SPELLABILITY_RESTORATION_OTHERS, oAbilityDamage)) return TRUE; + if(AI_ActionCastSpell(SPELL_GREATER_RESTORATION, oAbilityDamage)) return TRUE; } return FALSE; } @@ -5117,8 +4919,12 @@ int AI_AttemptCureCondition() //::////////////////////////////////////////////*/ int AI_AttemptHealingAlly() { + // If we are polymorphed, cannot heal anyone - thats cheating. Using our + // class feats we shouldn't have access to also isn't a nice idea. + if(AI_GetAIHaveEffect(GlobalEffectPolymorph)) return FALSE; + // Are we able to raise allies? - if(GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_WILL_RAISE_ALLIES_IN_BATTLE, AI_OTHER_COMBAT_MASTER) && SpellConSinTar) + if(GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_WILL_RAISE_ALLIES_IN_BATTLE, AI_OTHER_COMBAT_MASTER)) { // Leader - if dead, make sure we raise them! if(GetIsObjectValid(GlobalNearestLeader) && @@ -5126,24 +4932,31 @@ int AI_AttemptHealingAlly() !GetLocalInt(GlobalNearestLeader, AI_INTEGER + I_AM_TOTALLY_DEAD)) { // Talent 7 - Conditional single. - if(AI_ActionCastSpell(SPELL_RESURRECTION, SpellConSinTar, GlobalNearestLeader, i17, FALSE, ItemConSinTar)) return TRUE; - if(AI_ActionCastSpell(SPELL_RAISE_DEAD, SpellConSinTar, GlobalNearestLeader, i15, FALSE, ItemConSinTar)) return TRUE; + if(AI_ActionCastSpell(SPELL_RESURRECTION, GlobalNearestLeader, 17, FALSE)) return TRUE; + if(AI_ActionCastSpell(SPELL_RAISE_DEAD, GlobalNearestLeader, 15, FALSE)) return TRUE; } // Get the nearest ally, seen, who is dead // - This can cause problems as no looping dead people, as there is a // "totally dead" flag, used for bioware's lootable corpses. - object oDead = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, FALSE, - OBJECT_SELF, i1, - CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, - CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN); - if(GetIsObjectValid(oDead) && !GetIgnore(oDead) && - !GetLocalInt(oDead, AI_INTEGER + I_AM_TOTALLY_DEAD)) + int nCnt = 1; + object oDead = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, FALSE, OBJECT_SELF, nCnt, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN); + // Loop the dead people we see (allied ones) if we test just one - it/ + // can go wrong. + while(GetIsObjectValid(oDead)) { - if(AI_ActionCastSpell(SPELL_RESURRECTION, SpellConSinTar, oDead, i17, FALSE, ItemConSinTar)) return TRUE; - if(AI_ActionCastSpell(SPELL_RAISE_DEAD, SpellConSinTar, oDead, i15, FALSE, ItemConSinTar)) return TRUE; + if(GetIsObjectValid(oDead) && !GetIgnore(oDead) && + !GetLocalInt(oDead, AI_INTEGER + I_AM_TOTALLY_DEAD)) + { + if(AI_ActionCastSpell(SPELL_RESURRECTION, oDead, 17, FALSE)) return TRUE; + if(AI_ActionCastSpell(SPELL_RAISE_DEAD, oDead, 15, FALSE)) return TRUE; + } + // Get next dead seen ally + nCnt++; + oDead = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, FALSE, OBJECT_SELF, nCnt, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN); } } - // Do we heal allies? + // Do we heal allies? Spawn toggles for this. Only cure self means we don't + // target others at all. if(!GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_ONLY_CURE_SELF, AI_OTHER_COMBAT_MASTER) && !GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_CURING, AI_OTHER_COMBAT_MASTER)) { @@ -5157,57 +4970,57 @@ int AI_AttemptHealingAlly() else if(GlobalValidSeenAlly) { // We run through a loop, and get who we might heal ;-) - int iNeedToBeAt = GetBoundriedAIInteger(AI_HEALING_ALLIES_PERCENT, i60, i100, i1); + int nNeedToBeAt = GetBoundriedAIInteger(AI_HEALING_ALLIES_PERCENT, 60, 100, 1); object oAllyToHeal, oLoopTarget; - int iCnt, iPercentHitPoints, iChosenPercentHitPoints; + int nCnt, nPercentHitPoints, nChosenPercentHitPoints; float fDistance, fChosenLastDistance; - // iSummonHeal will be TRUE to heal associates only if we have <= 3 allies in total - int iSummonHeal = FALSE; - if(GlobalTotalAllies <= i3) + // bSummonHeal will be TRUE to heal associates only if we have <= 3 allies in total + int bSummonHeal = FALSE; + if(GlobalTotalAllies <= 3) { - iSummonHeal = TRUE; + bSummonHeal = TRUE; } - fChosenLastDistance = f60;// So 1st target in health band gets picked - iCnt = i1; - oLoopTarget = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN + IntToString(iCnt)); + fChosenLastDistance = 60.0;// So 1st target in health band gets picked + nCnt = 1; + oLoopTarget = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN + IntToString(nCnt)); while(GetIsObjectValid(oLoopTarget)) { if(GetRacialType(oLoopTarget) != RACIAL_TYPE_CONSTRUCT && - (GetAssociateType(oLoopTarget) == ASSOCIATE_TYPE_NONE || iSummonHeal == TRUE)) + (GetAssociateType(oLoopTarget) == ASSOCIATE_TYPE_NONE || bSummonHeal == TRUE)) { // We do actually not ALWAYS use the nearest dead person, nor // the most damaged in 20M or so. We use a mixture - the most // damaged in a cirtain range. - iPercentHitPoints = AI_GetPercentOf(GetCurrentHitPoints(oLoopTarget), GetMaxHitPoints(oLoopTarget)); + nPercentHitPoints = AI_GetPercentOf(GetCurrentHitPoints(oLoopTarget), GetMaxHitPoints(oLoopTarget)); // Do we consider them needing healing? - if(iPercentHitPoints <= iNeedToBeAt) + if(nPercentHitPoints <= nNeedToBeAt) { // Distance to them - we may not just heal the nearest under 60% fDistance = GetDistanceToObject(oLoopTarget); if(fDistance < fChosenLastDistance || - (fDistance < (fChosenLastDistance + f5) && - iPercentHitPoints < iChosenPercentHitPoints - i10)) + (fDistance < (fChosenLastDistance + 5.0) && + nPercentHitPoints < nChosenPercentHitPoints - 10)) { oAllyToHeal = oLoopTarget; fChosenLastDistance = fDistance; - iChosenPercentHitPoints = iPercentHitPoints; + nChosenPercentHitPoints = nPercentHitPoints; } } } - iCnt++; - oLoopTarget = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN + IntToString(iCnt)); + nCnt++; + oLoopTarget = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN + IntToString(nCnt)); } // Did we find someone to heal? - if(iChosenPercentHitPoints > i0) + if(nChosenPercentHitPoints > 0) { - int iAllyHealRace = GetRacialType(oAllyToHeal); + int nAllyHealRace = GetRacialType(oAllyToHeal); // Undead - negative energy heals! - if(iAllyHealRace == RACIAL_TYPE_UNDEAD) + if(nAllyHealRace == RACIAL_TYPE_UNDEAD) { // Stop now whatever, true or false. return AI_ActionHealUndeadObject(oAllyToHeal); } - else //if(iAllyHealRace != RACIAL_TYPE_CONSTRUCT) // Checked earlier + else //if(nAllyHealRace != RACIAL_TYPE_CONSTRUCT) // Checked earlier { if(AI_ActionHealObject(oAllyToHeal)) { @@ -5219,10 +5032,10 @@ int AI_AttemptHealingAlly() // There are extra speakstrings for these events. else if(GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_GIVE_POTIONS_TO_HELP, AI_OTHER_COMBAT_MASTER) && // Can they use potions anyway? - iAllyHealRace != RACIAL_TYPE_ABERRATION && iAllyHealRace != RACIAL_TYPE_BEAST && - iAllyHealRace != RACIAL_TYPE_ELEMENTAL && iAllyHealRace != RACIAL_TYPE_VERMIN && - iAllyHealRace != RACIAL_TYPE_MAGICAL_BEAST && iAllyHealRace != RACIAL_TYPE_DRAGON && - iAllyHealRace != RACIAL_TYPE_ANIMAL) + nAllyHealRace != RACIAL_TYPE_ABERRATION && nAllyHealRace != RACIAL_TYPE_BEAST && + nAllyHealRace != RACIAL_TYPE_ELEMENTAL && nAllyHealRace != RACIAL_TYPE_VERMIN && + nAllyHealRace != RACIAL_TYPE_MAGICAL_BEAST && nAllyHealRace != RACIAL_TYPE_DRAGON && + nAllyHealRace != RACIAL_TYPE_ANIMAL) { // So we pass over a potion. Obviously, we do not need healing, // so any potion is good! @@ -5268,12 +5081,12 @@ int AI_AttemptHealingAlly() // Pass it over with ActionGiveItem ActionGiveItem(oPotionToPass, oAllyToHeal); // Speak arrays. - string sSpeak = GetLocalString(OBJECT_SELF, AI_TALK_WE_PASS_POTION + s1); + string sSpeak = GetLocalString(OBJECT_SELF, AI_TALK_WE_PASS_POTION + "1"); if(sSpeak != "") { SpeakString(sSpeak); } - sSpeak = GetLocalString(OBJECT_SELF, AI_TALK_WE_GOT_POTION + s1); + sSpeak = GetLocalString(OBJECT_SELF, AI_TALK_WE_GOT_POTION + "1"); if(sSpeak != "") { AssignCommand(oAllyToHeal, SpeakString(sSpeak)); @@ -5300,20 +5113,28 @@ int AI_AttemptFeatSummonFamiliar() { if(GetSpawnInCondition(AI_FLAG_COMBAT_SUMMON_FAMILIAR, AI_COMBAT_MASTER)) { - if(GetHasFeat(FEAT_SUMMON_FAMILIAR) && !GetIsObjectValid(GetAssociate(ASSOCIATE_TYPE_FAMILIAR))) + // Summon our familiar (Bat) first. + if(!GetIsObjectValid(GetAssociate(ASSOCIATE_TYPE_FAMILIAR))) { - // 1: "[DCR:Feat] Summoning my familiar" - DebugActionSpeakByInt(22); - // We do not bother turning off hiding/searching - ActionUseFeat(FEAT_SUMMON_FAMILIAR, OBJECT_SELF); - return TRUE; + // We use the new function. We use the spellability, as to not + // cause any errors (hopefully) + if(AI_ActionUseSpellLikeFeat(FEAT_SUMMON_FAMILIAR, SPELLABILITY_SUMMON_FAMILIAR)) + { + // 22: "[DCR:Feat] Summoning my familiar" + DebugActionSpeakByInt(22); + return TRUE; + } } - else if(GetHasFeat(FEAT_ANIMAL_COMPANION) && !GetIsObjectValid(GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION))) + // Else, check for our companion (Badger) + else if(!GetIsObjectValid(GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION))) { - // 23: "[DCR:Feat] Summoning my animal companion" - DebugActionSpeakByInt(23); - ActionUseFeat(FEAT_ANIMAL_COMPANION, OBJECT_SELF); - return TRUE; + // Same as above for Summoning my Animal Companion. + if(AI_ActionUseSpellLikeFeat(FEAT_ANIMAL_COMPANION, SPELLABILITY_SUMMON_ANIMAL_COMPANION)) + { + // 23: "[DCR:Feat] Summoning my animal companion" + DebugActionSpeakByInt(23); + return TRUE; + } } } return FALSE; @@ -5330,11 +5151,18 @@ void AI_ActionFleeScared() { // Sets to flee mode SetCurrentAction(AI_SPECIAL_ACTIONS_FLEE); - SpeakArrayString(AI_TALK_ON_STUPID_RUN); + // * Don't speak when silenced or deaf, 1.4 change. + if(!AI_GetAIHaveEffect(GlobalEffectDeaf) && !AI_GetAIHaveEffect(GlobalEffectSilenced)) + { + SpeakArrayString(AI_TALK_ON_STUPID_RUN); + } ClearAllActions(); // 24: "[DCR:Fleeing] Stupid/Panic/Flee moving from enemies/position - We are a commoner/no morale/failed < 3 int" DebugActionSpeakByInt(24); + // Turn on fleeing visual effect + ApplyFleeingVisual(); + // Get a target, or run from position object oTarget = GlobalNearestEnemySeen; if(!GetIsObjectValid(oTarget)) @@ -5343,15 +5171,18 @@ void AI_ActionFleeScared() if(!GetIsObjectValid(oTarget)) { oTarget = GetLastHostileActor(); - if(!GetIsObjectValid(oTarget) || GetIsDead(oTarget)) + // Sanity check checks seen or heard too. + if(AI_GetTargetSanityCheck(oTarget)) { - // Away from position - ActionMoveAwayFromLocation(GetLocation(OBJECT_SELF), TRUE, f50); + // Away from position (EG: Away from an hostile AOE spell) + ActionMoveAwayFromLocation(GetLocation(OBJECT_SELF), TRUE, 50.0); return;// Stop, no move away from enemy } } } - ActionMoveAwayFromObject(oTarget, TRUE, f50); + // Default action is to move away from the nearest seen enemy - in this case, + // it is valid. + ActionMoveAwayFromObject(oTarget, TRUE, 50.0); } /*:://///////////////////////////////////////////// //:: Name Flee @@ -5388,11 +5219,20 @@ int AI_ActionFlee(string sArray) if(GetIsObjectValid(oToFlee)) { // Speak string... - if(sArray != "") SpeakArrayString(sArray); + if(sArray != "") + { + // * Don't speak when silenced or deaf, 1.4 change. + if(!AI_GetAIHaveEffect(GlobalEffectDeaf) && !AI_GetAIHaveEffect(GlobalEffectSilenced)) + { + SpeakArrayString(sArray); + } + } // Set it so we will not return for a bit. SetAIObject(AI_FLEE_TO, oToFlee); // Sets to flee mode SetCurrentAction(AI_SPECIAL_ACTIONS_FLEE); + // Turn on fleeing visual effect + ApplyFleeingVisual(); // 25: [DCR:Fleeing] Fleeing to allies. [ID Array] " + sArray + " [Ally] " + GetName(oToFlee) DebugActionSpeakByInt(25, oToFlee, FALSE, sArray); // Move too them. @@ -5408,94 +5248,104 @@ int AI_ActionFlee(string sArray) // - Leaders help! And all is intelligence based. int AI_AttemptMoraleFlee() { - int iMoraleValue = GetAIInteger(AI_MORALE); - // Commoner flee - if(iMoraleValue < FALSE) + // If we are immune to fleeing somehow, break + if(GetSpawnInCondition(AI_FLAG_FLEEING_FEARLESS, AI_TARGETING_FLEE_MASTER)) return FALSE; + + // Get our morale value (Higher = Break less often) + int nMoraleValue = GetAIInteger(AI_MORALE); + // Commoner flee. Commoners have AI_MORALE set to -1. + if(nMoraleValue < FALSE) { AI_ActionFleeScared(); return TRUE; } // Declare vaiables... // We only flee every few rounds, or at least check too! - // - This is set On Spawn if we are fearless by race or immunity - if(!GetSpawnInCondition(AI_FLAG_FLEEING_FEARLESS, AI_TARGETING_FLEE_MASTER) && // - Its on a timer. - (!GetLocalTimer(AI_TIMER_FLEE) || + if(!GetLocalTimer(AI_TIMER_FLEE) || // - We check each round if under 40 and under 10% HP - (GlobalOurCurrentHP <= i40 && GlobalOurPercentHP <= i10))) + (GlobalOurCurrentHP <= 40 && GlobalOurPercentHP <= 10)) { // Re-set timer even if we don't do the morale check. if(!GetLocalTimer(AI_TIMER_FLEE)) { - SetLocalTimer(AI_TIMER_FLEE, f20); + SetLocalTimer(AI_TIMER_FLEE, 20.0); } // Bosses, when they flee, make others flee. - int iBoss = GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_GROUP_LEADER, AI_OTHER_COMBAT_MASTER); + int bBoss = GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_GROUP_LEADER, AI_OTHER_COMBAT_MASTER); // Specials first: Never fight against impossible odds...or leader sense. - if(GlobalAverageEnemyHD > GlobalOurHitDice + i8) + if(GlobalAverageEnemyHD > GlobalOurHitDice + 8) { - if(GetSpawnInCondition(AI_FLAG_FLEEING_NEVER_FIGHT_IMPOSSIBLE_ODDS, AI_TARGETING_FLEE_MASTER) || iBoss) + // If we don't fight against impossible odds, we will flee given that + // they are very powerful (compared to us). Bosses automatically + // have this Spawn condition set (IE: Says || bBoss) + if(GetSpawnInCondition(AI_FLAG_FLEEING_NEVER_FIGHT_IMPOSSIBLE_ODDS, AI_TARGETING_FLEE_MASTER) || bBoss) { // You see, if there is no valid object ,we stop the script so not to call GetNearbyFleeObject more then once if(AI_ActionFlee(AI_TALK_ON_MORALE_BREAK)) { - if(iBoss) + // Are we a boss? If we are, and we want to flee, we force + // the men we command to run away too! + if(bBoss) { // AI command - makes everyone flee. - AISpeakString(LEADER_FLEE_NOW); + // * This isn't spoken, just generally "Done", as we + // normally see in the movies and so on... + AISpeakString(AI_SHOUT_LEADER_FLEE_NOW); } return TRUE; } else { + // Didn't want to flee, don't do anything special. return FALSE; } } } // HP check - int iHPBeAt = GetBoundriedAIInteger(HP_PERCENT_TO_CHECK_AT, i80, i100, i1); + int nHPBeAt = GetBoundriedAIInteger(HP_PERCENT_TO_CHECK_AT, 80, 100, 1); // Do the check - if(GlobalOurPercentHP <= iHPBeAt || + if(GlobalOurPercentHP <= nHPBeAt || // Either HP OR one of these: (!GetSpawnInCondition(AI_FLAG_FLEEING_NO_OVERRIDING_HP_AMOUNT, AI_TARGETING_FLEE_MASTER) && // - If the enemy is very strong, we do a will save (8 HD over us) - (GlobalAverageEnemyHD > GlobalOurHitDice + i8 || + (GlobalAverageEnemyHD > GlobalOurHitDice + 8 || // - If we have a morerate morale penalty (Set by massive damage/many deaths around us) // - We are alone - GetAIInteger(AI_MORALE_PENALTY) >= i10 || - GlobalTotalAllies < i1))) + GetAIInteger(AI_MORALE_PENALTY) >= 10 || + GlobalTotalAllies < 1))) { // Difference of HD to cancle out check... - int iDifference = GetBoundriedAIInteger(AMOUNT_OF_HD_DIFFERENCE_TO_CHECK, -2, -50, i50);// Default to -2. - int iAlliesBonus = FALSE; + int nDifference = GetBoundriedAIInteger(AMOUNT_OF_HD_DIFFERENCE_TO_CHECK, -2, -50, 50);// Default to -2. + int nAlliesBonus = FALSE; // We add X amount per ally present. // - We can add up to a minimum of 6, maximum of our hit dice/2. if(!GetSpawnInCondition(AI_FLAG_FLEEING_TURN_OFF_GROUP_MORALE, AI_TARGETING_FLEE_MASTER) && - GlobalTotalAllies >= i1) + GlobalTotalAllies >= 1) { - if(GlobalTotalAllies > i6) + if(GlobalTotalAllies > 6) { - iAlliesBonus = i6; + nAlliesBonus = 6; } - else if(iAlliesBonus > GlobalOurHitDice/i2) + else if(nAlliesBonus > GlobalOurHitDice/2) { - iAlliesBonus = GlobalOurHitDice/i2; + nAlliesBonus = GlobalOurHitDice/2; } else { - iAlliesBonus = GlobalTotalAllies; + nAlliesBonus = GlobalTotalAllies; } - iMoraleValue += iAlliesBonus; + nMoraleValue += nAlliesBonus; } // Double value if leader present! - if(GlobalValidLeader) iMoraleValue *= i2; + if(GlobalValidLeader) nMoraleValue *= 2; // Check... - if((GlobalOurHitDice - iDifference) < GlobalAverageEnemyHD) + if((GlobalOurHitDice - nDifference) < GlobalAverageEnemyHD) { // Save DC from 0 to 50. Default 20. This is the base. - int iSaveDC = GetBoundriedAIInteger(BASE_MORALE_SAVE, i20, i100, i1); + int nSaveDC = GetBoundriedAIInteger(BASE_MORALE_SAVE, 20, 100, 1); // Change it as with our leader, morale and group morale bonuses. - iSaveDC -= iMoraleValue; + nSaveDC -= nMoraleValue; // Note we will add DC based on difference in HD between us // and our Global Melee Target (as the fact is, it is normally // the nearest, and is always valid. Also, if you are fighting @@ -5504,13 +5354,16 @@ int AI_AttemptMoraleFlee() // you were levle 5 or so. // Add thiers to DC, take ours. Basically Ours - Theres added on. - iSaveDC += GetHitDice(GlobalMeleeTarget); - iSaveDC -= GlobalOurHitDice; + nSaveDC += GetHitDice(GlobalMeleeTarget); + nSaveDC -= GlobalOurHitDice; // If we have a save DC of over 1...we check! - if(iSaveDC >= i1) + if(nSaveDC >= 1) { - if(!WillSave(OBJECT_SELF, iSaveDC, SAVING_THROW_TYPE_FEAR, GlobalMeleeTarget)) + // This reports the will save to the enemy - who we check against, + // and thusly might well be immune to fear (such as via. + // protection from evil and so on). + if(!WillSave(OBJECT_SELF, nSaveDC, SAVING_THROW_TYPE_FEAR, GlobalMeleeTarget)) { // If we fail the will save, VS fear... // You see, if there is no valid object ,we stop the script so not to call GetNearbyFleeObject more then once @@ -5520,7 +5373,7 @@ int AI_AttemptMoraleFlee() } // Intelligence 1-3 runs when we fail and no allies. // 4+ means we don't run, and stay and fight (IE FALSE) - else if(GlobalIntelligence <= i3) + else if(GlobalIntelligence <= 3) { // Stupid run AI_ActionFleeScared(); @@ -5529,7 +5382,11 @@ int AI_AttemptMoraleFlee() else // Higher intelligence don't run from them, but does say something { - SpeakArrayString(AI_TALK_ON_CANNOT_RUN); + // * Don't speak when silenced or deaf, 1.4 change. + if(!AI_GetAIHaveEffect(GlobalEffectDeaf) && !AI_GetAIHaveEffect(GlobalEffectSilenced)) + { + SpeakArrayString(AI_TALK_ON_CANNOT_RUN); + } } return FALSE; } @@ -5552,51 +5409,55 @@ int AI_AttemptGoForTheKill() { // Turn off script if(GetSpawnInCondition(AI_FLAG_COMBAT_NO_GO_FOR_THE_KILL, AI_COMBAT_MASTER) || - GlobalIntelligence <= i8) + GlobalIntelligence <= 8) { return FALSE; } - int nSleepingOnly = FALSE; - // Finnish off a dead PC, or dying one, out of combat. + // TRUE means melee only + int bSleepingOnly = FALSE; + // Finish off a dead PC, or dying one, out of combat. object oTempEnemy = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, - OBJECT_SELF, i1, + OBJECT_SELF, 1, CREATURE_TYPE_IS_ALIVE, FALSE, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN); // Check if valid. If not, check for one with the spell "sleep" on them. - if(!GetIsObjectValid(oTempEnemy)) + if(!GetIsObjectValid(oTempEnemy) || AI_GetAIHaveEffect(GlobalEffectPetrify, oTempEnemy) || + GetCurrentHitPoints(oTempEnemy) <= -10) { // This means we only attack in melee (no spells, no ranged) - nSleepingOnly = TRUE; + bSleepingOnly = TRUE; oTempEnemy = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, - OBJECT_SELF, i1, + OBJECT_SELF, 1, CREATURE_TYPE_HAS_SPELL_EFFECT, SPELL_SLEEP, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN); // Dragon sleep breath - if(!GetIsObjectValid(oTempEnemy)) + if(!GetIsObjectValid(oTempEnemy) || GetHitDice(oTempEnemy) > 4 || + AI_GetAIHaveEffect(GlobalEffectPetrify, oTempEnemy)) { oTempEnemy = GetNearestCreature( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, - OBJECT_SELF, i1, + OBJECT_SELF, 1, CREATURE_TYPE_HAS_SPELL_EFFECT, SPELLABILITY_DRAGON_BREATH_SLEEP, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN); + // Could add something about Paralyzed people here... } } float fDistance = GetDistanceToObject(oTempEnemy); // Valid, and is not "dead dead" if(GetIsObjectValid(oTempEnemy) && - // -11 is TOTALLY dead. - GetCurrentHitPoints(oTempEnemy) > iM10 && + // -10 is TOTALLY dead. + GetCurrentHitPoints(oTempEnemy) > -10 && // Intelligence 9+. 10 will attack with many enemies, 9 with 1 or under - ((GlobalMeleeAttackers <= i3 && - GlobalIntelligence >= i10) || - GlobalMeleeAttackers <= i1) && + ((GlobalMeleeAttackers <= 3 && + GlobalIntelligence >= 10) || + GlobalMeleeAttackers <= 1) && // Make sure it isn't too far, and they are only sleeping - (nSleepingOnly == FALSE || - fDistance < f6) && + (bSleepingOnly == FALSE || + fDistance < 6.0) && // Big AC check, but mages with +1, VS ac of 30 won't hit :-) - GlobalOurBaseAttackBonus >= GetAC(oTempEnemy) - i25) + GlobalOurBaseAttackBonus >= GetAC(oTempEnemy) - 25) { // 26: "[DCR:GFTK] Attacking a PC who is dying/asleep! [Enemy]" + GetName(oTempEnemy) DebugActionSpeakByInt(26, oTempEnemy); @@ -5623,27 +5484,27 @@ int AI_AttemptGoForTheKill() if(GetIsObjectValid(oTempEnemy)) { // From 1-6, or 1-10 HP they need. - int iHP = GetCurrentHitPoints(oTempEnemy); - int iBeBelow = i6 + Random(i4); - int iHTH = FALSE;// TRUE = melee + int nHP = GetCurrentHitPoints(oTempEnemy); + int nBeBelow = 6 + Random(4); + int bHTH = FALSE;// TRUE = melee fDistance = GetDistanceToObject(oTempEnemy); // If in melee range, we set to melee, and add stength to what we can knock off! - if(fDistance <= f4) + if(fDistance <= 4.0) { - iHTH = TRUE; - iBeBelow += GetAbilityModifier(ABILITY_STRENGTH); + bHTH = TRUE; + nBeBelow += GetAbilityModifier(ABILITY_STRENGTH); } // Check... - if(GetCurrentHitPoints(oTempEnemy) <= iBeBelow && - GetMaxHitPoints(oTempEnemy) >= i20) + if(GetCurrentHitPoints(oTempEnemy) <= nBeBelow && + GetMaxHitPoints(oTempEnemy) >= 20) { // We also need to check if we can hit them to kill them! // - Either high BAB against thier AC (take roll as 15+) - if(GlobalOurBaseAttackBonus >= GetAC(oTempEnemy) - i15 || + if(GlobalOurBaseAttackBonus >= GetAC(oTempEnemy) - 15 || // - or it is 0.75 of our hit dice (IE cleric or better). - GlobalOurBaseAttackBonus >= ((GetHitDice(oTempEnemy) * i3) / i2)) + GlobalOurBaseAttackBonus >= ((GetHitDice(oTempEnemy) * 3) / 2)) { - if(iHTH) + if(bHTH) { ActionEquipMostDamagingMelee(oTempEnemy); } @@ -5667,49 +5528,52 @@ int AI_AttemptGoForTheKill() else { // This stops us being unprotected, as there may be melee attackers. - if(!iHTH || GlobalMeleeAttackers < i3) + if(!bHTH || GlobalMeleeAttackers < 3) { // Spells are done with little consideration for immunities. // - Saves power, and shows fury to knock out. // - All auto-hit, no-save spells. // - No items. // - Checks immunity level, incase of globes. - int iImmuneLevel = AI_GetSpellLevelEffect(oTempEnemy); + int nImmuneLevel = AI_GetSpellLevelEffect(oTempEnemy); - // Issacs storms are long range beasts! + // Isaacs storms are long range beasts! // Greater Missile Storm. Level 6 (Wizard). 2d6 * Caster level dice up to 20, divided between targets. - if(AI_ActionCastSpell(SPELL_ISAACS_GREATER_MISSILE_STORM, SpellHostRanged, oTempEnemy, i16)) return TRUE; + if(AI_ActionCastSpell(SPELL_ISAACS_GREATER_MISSILE_STORM, oTempEnemy, 16)) return TRUE; - if(iImmuneLevel < i4) + if(nImmuneLevel < 4) { // Lesser Missile Storm. Level 4 (Wizard). 1d6 * Caster level dice up to 10, divided between targets. - if(AI_ActionCastSpell(SPELL_ISAACS_LESSER_MISSILE_STORM, SpellHostRanged, oTempEnemy, i14)) return TRUE; + if(AI_ActionCastSpell(SPELL_ISAACS_LESSER_MISSILE_STORM, oTempEnemy, 14)) return TRUE; - if(iImmuneLevel < i3) + if(nImmuneLevel < 3) { // Searing light. Level 3 (Cleric). Full level: 1-10d6 VS undead. Half Level: 1-5d6 VS constructs. 1-5d8 VS Others. - if(AI_ActionCastSpell(SPELL_SEARING_LIGHT, SpellHostRanged, oTempEnemy, i13)) return TRUE; + if(AI_ActionCastSpell(SPELL_SEARING_LIGHT, oTempEnemy, 13)) return TRUE; - if(iImmuneLevel < i2) + if(nImmuneLevel < 2) { // Acid arrow. Level 2 (Wizard). 3d6 damage on hit. 1d6 for more rounds after. - if(AI_ActionCastSpell(SPELL_MELFS_ACID_ARROW, SpellHostRanged, oTempEnemy, i12)) return TRUE; + if(AI_ActionCastSpell(SPELL_MELFS_ACID_ARROW, oTempEnemy, 12)) return TRUE; - if(iImmuneLevel < i1) + if(nImmuneLevel < 1) { // Magic missile. Good knockout spell. Shield stops it. if(!GetHasSpellEffect(SPELL_SHIELD, oTempEnemy)) { + // Shad. conjuration version. + if(AI_ActionCastSpell(SPELL_SHADOW_CONJURATION_MAGIC_MISSILE, oTempEnemy, 11, FALSE, TRUE)) return TRUE; + // Magic Missile. Level 1 (Wizard). 1-5 missiles, 1-9 levels. 1d4+1 damage/missile. - if(AI_ActionCastSpell(SPELL_MAGIC_MISSILE, SpellHostRanged, oTempEnemy, i11)) return TRUE; + if(AI_ActionCastSpell(SPELL_MAGIC_MISSILE, oTempEnemy, 11)) return TRUE; } // Negative energy ray - note will save! if(fDistance < fMediumRange && - !AI_SaveImmuneAOE(oTempEnemy, SAVING_THROW_WILL, i1)) + !AI_SaveImmuneAOE(oTempEnemy, SAVING_THROW_WILL, 1)) { // Negative Energy Ray. Level 1 (Mage) 2 (Cleric) 1d6(CasterLevel/2) to 5d6 negative damage. - if(AI_ActionCastSpell(SPELL_NEGATIVE_ENERGY_RAY, SpellHostRanged, oTempEnemy, i11)) return TRUE; + if(AI_ActionCastSpell(SPELL_NEGATIVE_ENERGY_RAY, oTempEnemy, 11)) return TRUE; } } } @@ -5724,63 +5588,64 @@ int AI_AttemptGoForTheKill() /*:://///////////////////////////////////////////// //:: Name: AbilityAura //:://///////////////////////////////////////////// - This will use all abilties. + This will use all aura (or "Persistant") abilties. Note: - They are cheat cast. If removed, as DMG, they are instantly re-applied as a free action! - - They are cast instantly. - - + - They are cast instantly for the above reason, and cheat-cast. //:://///////////////////////////////////////////// //:: Created By: Jasperre //::////////////////////////////////////////////*/ -void AI_AttemptCastAuraSpell(int iSpellID) +void AI_AttemptCastAuraSpell(int nSpellID) { - if(GetHasSpell(iSpellID) && !GetHasSpellEffect(iSpellID)) + if(GetHasSpell(nSpellID) && !GetHasSpellEffect(nSpellID)) { // Cheat/fast cast the aura. - ActionCastSpellAtObject(iSpellID, OBJECT_SELF, METAMAGIC_NONE, TRUE, i20, PROJECTILE_PATH_TYPE_DEFAULT, TRUE); + ActionCastSpellAtObject(nSpellID, OBJECT_SELF, METAMAGIC_NONE, TRUE, 20, PROJECTILE_PATH_TYPE_DEFAULT, TRUE); } } - +// This will fire any aura's they have, quickened cast, and added to the top of +// thier action queue. void AI_ActionAbilityAura() { - if(SpellAura) + int nCnt; + // We can loop around a few: + // 195 AURA_BLINDING + // 196 Aura_Cold + // 197 Aura_Electricity + // 198 Aura_Fear + // 199 Aura_Fire + // 200 Aura_Menace + // 201 Aura_Protection + // 202 Aura_Stun + // 203 Aura_Unearthly_Visage + // 204 Aura_Unnatural + for(nCnt = SPELLABILITY_AURA_BLINDING; nCnt <= SPELLABILITY_AURA_UNNATURAL; nCnt++) { - int iCnt; - // We can loop around a few: - // 195 AURA_BLINDING - // 196 Aura_Cold - // 197 Aura_Electricity - // 198 Aura_Fear - // 199 Aura_Fire - // 200 Aura_Menace - // 201 Aura_Protection - // 202 Aura_Stun - // 203 Aura_Unearthly_Visage - // 204 Aura_Unnatural - for(iCnt = SPELLABILITY_AURA_BLINDING; iCnt <= SPELLABILITY_AURA_UNNATURAL; iCnt++) - { - // Wrapper function. - AI_AttemptCastAuraSpell(iCnt); - } - // Other auras we would have unlimited uses in - AI_AttemptCastAuraSpell(SPELLABILITY_DRAGON_FEAR); - AI_AttemptCastAuraSpell(SPELLABILITY_TYRANT_FOG_MIST); - AI_AttemptCastAuraSpell(AI_SPELLABILITY_AURA_OF_HELLFIRE); - - // Then, ones that are limited duration, or limited uses. - if(!GetHasSpellEffect(SPELLABILITY_MUMMY_BOLSTER_UNDEAD) && - GetHasSpell(SPELLABILITY_MUMMY_BOLSTER_UNDEAD)) - { - ActionCastSpellAtObject(SPELLABILITY_MUMMY_BOLSTER_UNDEAD, OBJECT_SELF); - } - if(!GetHasSpellEffect(SPELLABILITY_EMPTY_BODY) && GetHasFeat(FEAT_EMPTY_BODY)) - { - ActionUseFeat(FEAT_EMPTY_BODY, OBJECT_SELF); - } + // Wrapper function. + AI_AttemptCastAuraSpell(nCnt); } + // Other auras we would have unlimited uses in + AI_AttemptCastAuraSpell(SPELLABILITY_DRAGON_FEAR); + AI_AttemptCastAuraSpell(SPELLABILITY_TYRANT_FOG_MIST); + AI_AttemptCastAuraSpell(AI_SPELLABILITY_AURA_OF_HELLFIRE); + AI_AttemptCastAuraSpell(SPELLABILITY_AURA_HORRIFICAPPEARANCE); + + // Then, ones that are limited duration, or limited uses. + if(!GetHasSpellEffect(SPELLABILITY_MUMMY_BOLSTER_UNDEAD) && + GetHasSpell(SPELLABILITY_MUMMY_BOLSTER_UNDEAD)) + { + ActionCastSpellAtObject(SPELLABILITY_MUMMY_BOLSTER_UNDEAD, OBJECT_SELF); + } + // This acts like an ability - well, from my perspective. We add actions + // after it, and it is important to keep up. + // * Quick note: requires at least 1 monk level to work. + // * Note 2: Uses the new spell-like-feat abilties function, which did the + // same stuff as before, but is easier to debug etc. (although, empty body + // was a feat which worked fine). + AI_ActionUseSpellLikeFeat(FEAT_EMPTY_BODY, SPELLABILITY_EMPTY_BODY); } /*:://///////////////////////////////////////////// //:: Name LeaderActions @@ -5797,75 +5662,76 @@ void AI_ActionLeaderActions() { // Does the enemy out class us by a random amount? (2-6 HD difference). // Sends a runner. - if(GlobalAverageEnemyHD > (GlobalAverageFriendlyHD + d4() + i2)) + if(GlobalAverageEnemyHD > (GlobalAverageFriendlyHD + d4() + 2)) { if(GlobalValidAlly && !GetLocalTimer(AI_TIMER_LEADER_SENT_RUNNER)) { object oBestAllies = AI_GetNearbyFleeObject(); if(GetIsObjectValid(oBestAllies)) // Send a runner... { - // Speak array. - SpeakArrayString(AI_TALK_ON_LEADER_SEND_RUNNER); + // * Don't speak when silenced or deaf, 1.4 change. + if(!AI_GetAIHaveEffect(GlobalEffectDeaf) && !AI_GetAIHaveEffect(GlobalEffectSilenced)) + { + // Speak array. + SpeakArrayString(AI_TALK_ON_LEADER_SEND_RUNNER); + } // All we need to do is set an action on the nearest ally, // and the object to run to. SetLocalObject(GlobalNearestAlly, AI_OBJECT + AI_RUNNER_TARGET, oBestAllies); // Set action. SetLocalInt(GlobalNearestAlly, AI_CURRENT_ACTION, AI_SPECIAL_ACTIONS_ME_RUNNER); // Don't send another for 50 seconds. - SetLocalTimer(AI_TIMER_LEADER_SENT_RUNNER, f50); + SetLocalTimer(AI_TIMER_LEADER_SENT_RUNNER, 50.0); } } } // Second, we shout for people to target this person - IF we need help // - Example, low HP us, high HP them. // - Uses melee target. - int iLeaderCountForShout = GetAIInteger(AI_LEADER_SHOUT_COUNT); - iLeaderCountForShout++; - if(iLeaderCountForShout > i4) + int nLeaderCountForShout = GetAIInteger(AI_LEADER_SHOUT_COUNT); + nLeaderCountForShout++; + if(nLeaderCountForShout >= 5) { // Check HD difference - if(GetHitDice(GlobalMeleeTarget) - i5 > GlobalAverageEnemyHD) + if(GetHitDice(GlobalMeleeTarget) - 5 > GlobalAverageEnemyHD) { // Set who we want them to attack. SetAIObject(AI_ATTACK_SPECIFIC_OBJECT, GlobalMeleeTarget); // Shout counter re-set - iLeaderCountForShout = FALSE; - // Speak random custom shout (like "You lot, attack this one!") - SpeakArrayString(AI_TALK_ON_LEADER_ATTACK_TARGET); + nLeaderCountForShout = FALSE; + + // * Don't speak when silenced or deaf, 1.4 change. + if(!AI_GetAIHaveEffect(GlobalEffectDeaf) && !AI_GetAIHaveEffect(GlobalEffectSilenced)) + { + // Speak random custom shout (like "You lot, attack this one!") + SpeakArrayString(AI_TALK_ON_LEADER_ATTACK_TARGET); + } // Speak a silent AI shout - AISpeakString(LEADER_ATTACK_TARGET); + AISpeakString(AI_SHOUT_LEADER_ATTACK_TARGET); } } - SetAIInteger(AI_LEADER_SHOUT_COUNT, iLeaderCountForShout); + SetAIInteger(AI_LEADER_SHOUT_COUNT, nLeaderCountForShout); } } /*:://///////////////////////////////////////////// //:: Name ArcherRetreat //:://///////////////////////////////////////////// - This may make the archer retreat - if they are set to, and have a ranged weapon - and don't have point blank shot, and has a nearby ally. (INT>=1 if set to does - it more if higher). + This may make the archer retreat - if we have an ally helping, and + we have a nearby enemy. Means the loss of AOO's. //:://///////////////////////////////////////////// //:: Created By: Jasperre //::////////////////////////////////////////////*/ int AI_AttemptArcherRetreat() { - //SetSpawnInCondition(AI_FLAG_COMBAT_ARCHER_ATTACKING, AI_COMBAT_MASTER); - // This is quite specifically for archers - ones good at using bows. - // They will, quite often (with support from others) retreat to use - // bows much better (IE no AOO). they perfere ranged combat, and only - // draw HTH weapons (If they have any, else they use thier bow) in the end. - // Note: Below, you can set it to ALWAYs move back, if an archer. - //SetSpawnInCondition(AI_FLAG_COMBAT_ARCHER_ALWAYS_MOVE_BACK, AI_COMBAT_MASTER); - // Many conditions - we must have it to start! if(GetSpawnInCondition(AI_FLAG_COMBAT_ARCHER_ATTACKING, AI_COMBAT_MASTER) || GetSpawnInCondition(AI_FLAG_COMBAT_ARCHER_ALWAYS_MOVE_BACK, AI_COMBAT_MASTER)) { // Enemy range must be close (HTH distance, roughly) and we must have // a close ally. ELSE we'll just get lots of AOO and die running (pointless) - if((GlobalEnemiesIn4Meters > i1 && GlobalValidAlly && GlobalRangeToAlly < f4) || + // * Was > 1, now >= 1, 1.4 fix. + if((GlobalEnemiesIn4Meters >= 1 && GlobalValidAlly && GlobalRangeToAlly < 4.0) || GetSpawnInCondition(AI_FLAG_COMBAT_ARCHER_ALWAYS_MOVE_BACK, AI_COMBAT_MASTER)) { // We may, if at the right range (and got a ranged weapon) equip it. @@ -5873,11 +5739,11 @@ int AI_AttemptArcherRetreat() if(GetIsObjectValid(oRanged) && GetItemPossessor(oRanged) == OBJECT_SELF) { - // Is the ranged weapon valid? And iRangedAttack == TRUE + // Is the ranged weapon valid? // We need valid ammo, else we eqip nothing! - int iValidAmmo = GetAIInteger(AI_WEAPON_RANGED_AMMOSLOT); - if(iValidAmmo == INVENTORY_SLOT_RIGHTHAND || - GetIsObjectValid(GetItemInSlot(iValidAmmo))) + int bValidAmmo = GetAIInteger(AI_WEAPON_RANGED_AMMOSLOT); + if(bValidAmmo == INVENTORY_SLOT_RIGHTHAND || + GetIsObjectValid(GetItemInSlot(bValidAmmo))) { // 27: "[DCR:Moving] Archer Retreating back from the enemy [Enemy]" + GetName(GlobalMeleeTarget) DebugActionSpeakByInt(27, GlobalMeleeTarget); @@ -5886,7 +5752,9 @@ int AI_AttemptArcherRetreat() { ActionEquipItem(oRanged, INVENTORY_SLOT_RIGHTHAND); } - ActionMoveAwayFromObject(GlobalMeleeTarget, TRUE, f15); + // This action will cancle next round if we are far enough + // away from enemies. + ActionMoveAwayFromObject(GlobalMeleeTarget, TRUE, 15.0); return TRUE; } } @@ -5907,13 +5775,13 @@ int AI_AttemptFeatTurning() { // We loop the targets and see who we come up with to hit! // - Use ranged enemy checks, seen/heard and only if we have any - // valid races in the area. + // valid races in the area. if(GetHasFeat(FEAT_TURN_UNDEAD)) { // The turn level is set OnSpawn if we have FEAT_TURN_UNDEAD int nTurnLevel = GetAIInteger(AI_TURNING_LEVEL); // Error checking - if(nTurnLevel <= i0) return FALSE; + if(nTurnLevel <= 0) return FALSE; // We then loop through targets nearby, up to 20M. We can easily use // GetHasSpellEffect(AI_SPELL_FEAT_TURN_UNDEAD) @@ -5922,40 +5790,41 @@ int AI_AttemptFeatTurning() // Ok, so how does turning work? // - Basically, all undead/virmin/elementals or outsiders are turned, - // with constructs being damaged. + // with constructs being damaged (which still rocks!) // - Works agasints non-friends. // - If we have nClassLevel/2 >= nHD (nHD = GetHitDice(oTarget) + GetTurnResistanceHD(oTarget) // then kill, else turn. // - Only can turn if nHD <= nTurnLevel. // - 20M range. // Flags for bonus turning types - int nElemental = GetHasFeat(FEAT_AIR_DOMAIN_POWER) + GetHasFeat(FEAT_EARTH_DOMAIN_POWER) + GetHasFeat(FEAT_FIRE_DOMAIN_POWER) + GetHasFeat(FEAT_WATER_DOMAIN_POWER); - int nVermin = GetHasFeat(FEAT_PLANT_DOMAIN_POWER) + GetHasFeat(FEAT_ANIMAL_COMPANION); - int nConstructs = GetHasFeat(FEAT_DESTRUCTION_DOMAIN_POWER); - int nPlanarTurning = GetHasFeat(AI_FEAT_EPIC_PLANAR_TURNING); + int bElemental = GetHasFeat(FEAT_AIR_DOMAIN_POWER) + GetHasFeat(FEAT_EARTH_DOMAIN_POWER) + GetHasFeat(FEAT_FIRE_DOMAIN_POWER) + GetHasFeat(FEAT_WATER_DOMAIN_POWER); + int bVermin = GetHasFeat(FEAT_PLANT_DOMAIN_POWER) + GetHasFeat(FEAT_ANIMAL_COMPANION); + int bConstructs = GetHasFeat(FEAT_DESTRUCTION_DOMAIN_POWER); + int bPlanarTurning = GetHasFeat(AI_FEAT_EPIC_PLANAR_TURNING); // Outsiders can be turned via. Epic Planar Turning too. - int nOutsider = GetHasFeat(FEAT_GOOD_DOMAIN_POWER) + GetHasFeat(FEAT_EVIL_DOMAIN_POWER) + nPlanarTurning; - int nHD, nRacial, iValid; + int bOutsider = bPlanarTurning + GetHasFeat(FEAT_GOOD_DOMAIN_POWER) + GetHasFeat(FEAT_EVIL_DOMAIN_POWER); + int nHD, nRacial, bValid; // Loop, using a sort of loop used for the turning check. - // - Add GetObjectSeen/GetObjectHeard. + // - Same GetNearestCreature() as 1.64 has: Alive + Seen. // - We stop if, when we would use it, it'd re-apply effects to one // already turned. // - We stop if we get to something we can turn! - int nCnt = i1; - object oTarget = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_NOT_PC , OBJECT_SELF, nCnt); - while(GetIsObjectValid(oTarget) && iValid == FALSE && GetDistanceToObject(oTarget) <= f20) + int nCnt = 1; + object oTarget = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, TRUE, OBJECT_SELF, nCnt, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN); + while(GetIsObjectValid(oTarget) && bValid == FALSE && GetDistanceToObject(oTarget) <= 20.0) { - if(!GetIsFriend(oTarget) && (GetObjectSeen(oTarget) || GetObjectHeard(oTarget))) + // Same check as in turn undead script. + if(!GetIsFriend(oTarget)) { nHD = GetHitDice(oTarget) + GetTurnResistanceHD(oTarget); nRacial = GetRacialType(oTarget); // Planar creatures add spell resistance (don't bother if can't turn them) - if(nRacial == RACIAL_TYPE_OUTSIDER && nOutsider) + if(nRacial == RACIAL_TYPE_OUTSIDER && bOutsider) { - if(nPlanarTurning) + if(bPlanarTurning) { // Half with the epic feat - nHD += (GetSpellResistance(oTarget)/i2); + nHD += (GetSpellResistance(oTarget)/2); } else { @@ -5970,30 +5839,31 @@ int AI_AttemptFeatTurning() if(GetHasSpellEffect(AI_SPELL_FEAT_TURN_UNDEAD, oTarget) || GetHasSpellEffect(AI_SPELL_FEAT_PLANAR_TURNING, oTarget)) { - iValid = i2; + bValid = 2; } // Else Check the various domain turning types else if(nRacial == RACIAL_TYPE_UNDEAD || - (nRacial == RACIAL_TYPE_VERMIN && nVermin) || - (nRacial == RACIAL_TYPE_ELEMENTAL && nElemental) || - (nRacial == RACIAL_TYPE_CONSTRUCT && nConstructs) || - (nRacial == RACIAL_TYPE_OUTSIDER && nOutsider)) + (nRacial == RACIAL_TYPE_VERMIN && bVermin) || + (nRacial == RACIAL_TYPE_ELEMENTAL && bElemental) || + (nRacial == RACIAL_TYPE_CONSTRUCT && bConstructs) || + (nRacial == RACIAL_TYPE_OUTSIDER && bOutsider)) { - iValid = TRUE; + bValid = TRUE; } } } + // Next alive, seen creature. nCnt++; - oTarget = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_NOT_PC, OBJECT_SELF, nCnt); + oTarget = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, TRUE, OBJECT_SELF, nCnt, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN); } // If valid, use it - if(iValid == TRUE) + if(bValid == TRUE) { // 28: "[DCR:Turning] Using Turn Undead" DebugActionSpeakByInt(28); // We do not bother turning off hiding/searching - but we do check // expertise! - if(GlobalIntelligence >= i4) + if(GlobalIntelligence >= 4) { if(GetHasFeat(FEAT_IMPROVED_EXPERTISE)) { @@ -6004,6 +5874,8 @@ int AI_AttemptFeatTurning() AI_SetMeleeMode(ACTION_MODE_EXPERTISE); } } + // Note: No equipping shield, do it ASAP. Usually a shield is + // already equipped anyway, if we had one. ActionUseFeat(FEAT_TURN_UNDEAD, OBJECT_SELF); return TRUE; } @@ -6024,15 +5896,16 @@ int AI_AttemptFeatBardSong() // Got it and not silenced if(GetHasFeat(FEAT_BARD_SONGS) && !AI_GetAIHaveEffect(GlobalEffectSilenced)) { - // the spell script used is 411 + // The spell script used is 411 - it is also now named in the AI constant file // Get nearest without this spell's effect to check too - object oSonged = GetNearestCreature(CREATURE_TYPE_DOES_NOT_HAVE_SPELL_EFFECT, AI_SPELL_BARD_SONG, OBJECT_SELF, i1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN); - if((!GetHasSpellEffect(AI_SPELL_BARD_SONG) && - !GetHasFeatEffect(FEAT_BARD_SONGS) && + object oSonged = GetNearestCreature(CREATURE_TYPE_DOES_NOT_HAVE_SPELL_EFFECT, AI_SPELLABILITY_BARD_SONG, OBJECT_SELF, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN); + if((/* 1.4: Noticed no need for below check + !GetHasSpellEffect(AI_SPELLABILITY_BARD_SONG, oSonged) && */ + !GetHasFeatEffect(FEAT_BARD_SONGS, oSonged) && // Do not use if we are deaf... !AI_GetAIHaveEffect(GlobalEffectDeaf, oSonged)) || - // ...but we could use it if we have an undeaf ally in 5M - (GetIsObjectValid(oSonged) && GetDistanceToObject(oSonged) < f5 && + // ...but we could use it if we have an undeaf ally in 8M + (GetIsObjectValid(oSonged) && GetDistanceToObject(oSonged) < 8.0 && !AI_GetAIHaveEffect(GlobalEffectDeaf, oSonged))) { // 29: "[DCR:Bard Song] Using" @@ -6045,10 +5918,11 @@ int AI_AttemptFeatBardSong() else if(GetHasFeat(FEAT_CURSE_SONG)) { // get nearest without this spell's effect - oSonged = GetNearestCreature(CREATURE_TYPE_DOES_NOT_HAVE_SPELL_EFFECT, AI_SPELL_CURSE_SONG, OBJECT_SELF, i1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN); - // If they are not cursed, IE valid, in 6M, and not deaf, we try it. + oSonged = GetNearestCreature(CREATURE_TYPE_DOES_NOT_HAVE_SPELL_EFFECT, SPELLABILITY_EPIC_CURSE_SONG, OBJECT_SELF, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN); + // If they are not cursed, IE valid, in 8M (1.4 change: was 6), + // and not deaf, we try it. if(GetIsObjectValid(oSonged) && - GetDistanceToObject(oSonged) <= f6 && + GetDistanceToObject(oSonged) <= 8.0 && !AI_GetAIHaveEffect(GlobalEffectDeaf, oSonged)) { // 30: "[DCR:Bard Curse Song] Using" @@ -6062,64 +5936,90 @@ int AI_AttemptFeatBardSong() return FALSE; } +// Wrappers for spellcasting groups of spells. + // Wrappers Greater and Lesser spell breach. int AI_ActionCastBreach() { // Greater Spell Breach. Level 6 (Wizard). Dispels cirtain protections automatically + lowers spell resistance - if(AI_ActionCastSpell(SPELL_GREATER_SPELL_BREACH, SpellHostRanged, GlobalDispelTarget, i16, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpell(SPELL_GREATER_SPELL_BREACH, GlobalDispelTarget, 16, FALSE)) return TRUE; // Lesser Spell Breach. Level 4 (Wizard) Dispels cirtain protections automatically + lowers spell resistance - if(AI_ActionCastSpell(SPELL_LESSER_SPELL_BREACH, SpellHostRanged, GlobalDispelTarget, i14, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpell(SPELL_LESSER_SPELL_BREACH, GlobalDispelTarget, 14, FALSE)) return TRUE; return FALSE; } // Wrappers all dispel spells int AI_ActionCastDispel() { // Mordenkainens Disjunction. Level 9 (Wizard). Acts like a breach, dispel AND lowers SR, in a big area. - if(AI_ActionCastSpell(SPELL_MORDENKAINENS_DISJUNCTION, SpellHostAreaInd, GlobalDispelTarget, i19, FALSE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpell(SPELL_MORDENKAINENS_DISJUNCTION, GlobalDispelTarget, 19, FALSE)) return TRUE; // Greater Dispeling. Level 5 (Bard/Innate) 6 (Cleric/Druid/Mage) General dispel up to 15 caster levels. - if(AI_ActionCastSpell(SPELL_GREATER_DISPELLING, SpellHostRanged, GlobalDispelTarget, i16, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpell(SPELL_GREATER_DISPELLING, GlobalDispelTarget, 16, FALSE)) return TRUE; // Dispel Magic. Level 3 (Bard/Cleric/Paladin/Mage/Innate) 6 (Druid) General dispel up to 10 caster levels. - if(AI_ActionCastSpell(SPELL_DISPEL_MAGIC, SpellHostRanged, GlobalDispelTarget, i13, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpell(SPELL_DISPEL_MAGIC, GlobalDispelTarget, 13, FALSE)) return TRUE; // Only lesser if under 15 HD, because it may not be worth it (DC wise) - if(GlobalAverageEnemyHD < i15) + if(GlobalAverageEnemyHD < 15) { // Lesser Dispel. Level 1 (Bard) 2 (Cleric/Druid/Mage/Innate). General dispel up to 5 caster levels. - if(AI_ActionCastSpell(SPELL_LESSER_DISPEL, SpellHostAreaInd, GlobalDispelTarget, i12, FALSE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpell(SPELL_LESSER_DISPEL, GlobalDispelTarget, 12, FALSE)) return TRUE; } return FALSE; } +// This wrappers AI_ActionCastBreach() and AI_ActionCastDispel(). Input +// nValue for 1 (Lowest priority) to 5, to see if we'll use them. Returns +// TRUE if any are cast. +int AI_ActionAttemptDispel(int nValue, int bRangeMediumValid) +{ + // All range medium spells. Shouldn't use them in Time Stop. + if(bRangeMediumValid && !GlobalInTimeStop) + { + // Dispel number need to be nValue at least to use a breach + if(GlobalDispelTargetHighestBreach >= nValue) + { + // Wrapers Greater and Lesser Breach. + if(AI_ActionCastBreach()) return TRUE; + } + // Dispel >= nValue + if(GlobalDispelTargetHighestDispel >= nValue) + { + // Wrappers the dispel spells + if(AI_ActionCastDispel()) return TRUE; + } + } + // No dispels cast. + return FALSE; +} // Wrappers Premonition, Greater Stoneskin and Stoneskin. // Includes Shades Stoneskin too. SPELL_SHADES_STONESKIN -// - iLowest - 8 = Prem, 6 = Greater, 4 = Stoneskin +// - nLowest - 8 = Prem, 6 = Greater, 4 = Stoneskin // - Checks AI_GetAIHaveSpellsEffect(GlobalHasStoneSkinProtections) -int AI_SpellWrapperPhisicalProtections(int iLowest = 1) +int AI_SpellWrapperPhisicalProtections(int nLowest = 1) { // Stoneskin - protection from attackers. if(!AI_GetAIHaveSpellsEffect(GlobalHasStoneSkinProtections)) { // Epic Warding (Mage Only) - Damage reduction 50/+20. Lasts 1 round per level. - if(AI_ActionUseEpicSpell(AI_FEAT_EPIC_SPELL_EPIC_WARDING, AI_SPELL_EPIC_WARDING)) return TRUE; + if(AI_ActionUseSpellLikeFeat(FEAT_EPIC_SPELL_EPIC_WARDING, AI_SPELL_EPIC_WARDING)) return TRUE; // Psionic Inertial Barrier - if(AI_ActionCastSpell(AI_SPELLABILITY_PSIONIC_INERTIAL_BARRIER, SpellProSelf)) return TRUE; + if(AI_ActionCastSpell(AI_SPELLABILITY_PSIONIC_INERTIAL_BARRIER)) return TRUE; - if(iLowest <= i8) + if(nLowest <= 8) { // Preminition is 30/+5 damage resistance. Level 8 spell. Always class // as level 9. (Mage) - if(AI_ActionCastSpell(SPELL_PREMONITION, SpellProSelf, OBJECT_SELF, i18, FALSE, ItemProSelf, PotionPro)) return TRUE; - if(iLowest <= i6) + if(AI_ActionCastSpell(SPELL_PREMONITION, OBJECT_SELF, 18, FALSE)) return TRUE; + if(nLowest <= 6) { // Then, greater stoneskin protects a lot of damage - 20/+5. // We also consider this to be a high-level spell. Level 6 (Mage) 7 (druid) - if(AI_ActionCastSpell(SPELL_GREATER_STONESKIN, SpellProSelf, OBJECT_SELF, i16, FALSE, ItemProSelf, PotionPro)) return TRUE; - if(iLowest <= i4) + if(AI_ActionCastSpell(SPELL_GREATER_STONESKIN, OBJECT_SELF, 16, FALSE)) return TRUE; + if(nLowest <= 4) { - // Shades stoneskin. SPELL_SHADES_STONESKIN - if(AI_ActionCastSubSpell(SPELL_SHADES_STONESKIN, SpellProSinTar, OBJECT_SELF, i16, FALSE, ItemProSinTar)) return TRUE; + // Shades stoneskin. SPELL_SHADES_STONESKIN (Cast via. subspell) + if(AI_ActionCastSpell(SPELL_SHADES_STONESKIN, OBJECT_SELF, 16, FALSE, TRUE)) return TRUE; // Stoneskin is next, level 4, but 10/+5 resistance Level 4 (Mage) 5 (Druid) - if(AI_ActionCastSpell(SPELL_STONESKIN, SpellProSinTar, OBJECT_SELF, i14, FALSE, ItemProSinTar, PotionPro)) return TRUE; + if(AI_ActionCastSpell(SPELL_STONESKIN, OBJECT_SELF, 14, FALSE)) return TRUE; } } } @@ -6127,28 +6027,28 @@ int AI_SpellWrapperPhisicalProtections(int iLowest = 1) return FALSE; } // Wrappers Energy Buffer, Protection From Elements, Resist Elements, Endure elements -// - iLowest - Goes 5, 3, 2, 1. +// - nLowest - Goes 5, 3, 2, 1. // - Checks AI_GetAIHaveSpellsEffect(GlobalHasElementalProtections) -int AI_SpellWrapperElementalProtections(int iLowest = 1) +int AI_SpellWrapperElementalProtections(int nLowest = 1) { // Elemental protections (fireball ETC) - if(!AI_GetAIHaveSpellsEffect(GlobalHasElementalProtections) && iLowest <= i5) + if(!AI_GetAIHaveSpellsEffect(GlobalHasElementalProtections) && nLowest <= 5) { // Energy buffer - 40/- resistance to the damage. // 6 for druids ETC, but 5 Mage/Innate. - if(AI_ActionCastSpell(SPELL_ENERGY_BUFFER, SpellProSinTar, OBJECT_SELF, i15, FALSE, ItemProSinTar, PotionPro)) return TRUE; - if(iLowest <= i3) + if(AI_ActionCastSpell(SPELL_ENERGY_BUFFER, OBJECT_SELF, 15, FALSE)) return TRUE; + if(nLowest <= 3) { // Protection from elements - 30/- resistance to the damage. Level 3 - if(AI_ActionCastSpell(SPELL_PROTECTION_FROM_ELEMENTS, SpellProSinTar, OBJECT_SELF, i13, FALSE, ItemProSinTar, PotionPro)) return TRUE; - if(iLowest <= i2) + if(AI_ActionCastSpell(SPELL_PROTECTION_FROM_ELEMENTS, OBJECT_SELF, 13, FALSE)) return TRUE; + if(nLowest <= 2) { // Resist elements - 20/- resistance to the damage. Level 2 - if(AI_ActionCastSpell(SPELL_RESIST_ELEMENTS, SpellProSinTar, OBJECT_SELF, i12, FALSE, ItemProSinTar, PotionPro)) return TRUE; - if(iLowest <= i1) + if(AI_ActionCastSpell(SPELL_RESIST_ELEMENTS, OBJECT_SELF, 12, FALSE)) return TRUE; + if(nLowest <= 1) { // Endure elements - 10/- resistance to the damage. Level 1 - if(AI_ActionCastSpell(SPELL_ENDURE_ELEMENTS, SpellProSinTar, OBJECT_SELF, i11, FALSE, ItemProSinTar, PotionPro)) return TRUE; + if(AI_ActionCastSpell(SPELL_ENDURE_ELEMENTS, OBJECT_SELF, 11, FALSE)) return TRUE; } } } @@ -6156,155 +6056,157 @@ int AI_SpellWrapperElementalProtections(int iLowest = 1) return FALSE; } // Wrappers Haste and Mass Haste. -// - iLowest - 6 = Mass, 3 = Haste +// - nLowest - 6 = Mass, 3 = Haste // - Checks AI_GetAIHaveSpellsEffect(GlobalHasStoneSkinProtections) -int AI_SpellWrapperHasteEnchantments(int iLowest = 1) +int AI_SpellWrapperHasteEnchantments(int nLowest = 1) { // Excelent to cast this normally - +4AC. Probably normally best after protections from // phisical attacks. - if(!AI_GetAIHaveEffect(GlobalEffectHaste) && iLowest <= i6) + if(!AI_GetAIHaveEffect(GlobalEffectHaste) && nLowest <= 6) { // The feat, for haste, called blinding speed. - if(AI_ActionUseFeatOnObject(FEAT_EPIC_BLINDING_SPEED)) return TRUE; + if(AI_ActionUseSpellLikeFeat(FEAT_EPIC_BLINDING_SPEED, AI_SPELLABILITY_BLINDING_SPEED)) return TRUE; // Mass haste, level 6 spell. (Mage/Bard) Affects allies, and adds +1 action, +4 AC and +150% move - if(AI_ActionCastSpell(SPELL_MASS_HASTE, SpellEnhAre, OBJECT_SELF, i16, FALSE, ItemEnhAre, PotionEnh)) return TRUE; - if(iLowest <= i3) + if(AI_ActionCastSpell(SPELL_MASS_HASTE, OBJECT_SELF, 16, FALSE)) return TRUE; + + if(nLowest <= 3) { - // Haste, Level 3 spell. (Mage/Bard) - if(AI_ActionCastSpell(SPELL_HASTE, SpellEnhSinTar, OBJECT_SELF, i13, FALSE, ItemEnhSinTar, PotionEnh)) return TRUE; + // Haste, Level 3 spell. (Mage/Bard), see mass haste. + if(AI_ActionCastSpell(SPELL_HASTE, OBJECT_SELF, 13, FALSE)) return TRUE; } } return FALSE; } // Wrappers Shadow Shield, Ethereal Visage and Ghostly Visage. // Includes Greater Shadow Conjuration Ghostly Visage (SPELL_GREATER_SHADOW_CONJURATION_MIRROR_IMAGE -// - iLowest - 7 = Shadow, 6 = Ethereal 2 = Ghostly +// - nLowest - 7 = Shadow, 6 = Ethereal 2 = Ghostly // - Checks AI_GetAIHaveSpellsEffect(GlobalHasVisageProtections) -int AI_SpellWrapperVisageProtections(int iLowest = 1) +int AI_SpellWrapperVisageProtections(int nLowest = 1) { // Visages are generally lower DR, with some spell-resisting or effect-immunty extras. - if(!AI_GetAIHaveSpellsEffect(GlobalHasVisageProtections) && iLowest <= i7) + if(!AI_GetAIHaveSpellsEffect(GlobalHasVisageProtections) && nLowest <= 7) { // Shadow Shield - has 10/+3 damage reduction // Level 7 (Mage) - if(AI_ActionCastSpell(SPELL_SHADOW_SHIELD, SpellProSelf, OBJECT_SELF, i17, FALSE, ItemProSelf, PotionPro)) return TRUE; - if(iLowest <= i6) + if(AI_ActionCastSpell(SPELL_SHADOW_SHIELD, OBJECT_SELF, 17, FALSE)) return TRUE; + if(nLowest <= 6) { // Ethereal Visage (level 6 (Mage)) is 20/+3 damage reduction - no limit! // + Immunity to level 2, 1, 0 level spells. - if(AI_ActionCastSpell(SPELL_ETHEREAL_VISAGE, SpellEnhSelf, OBJECT_SELF, i16, FALSE, ItemEnhSelf, PotionEnh)) return TRUE; - if(iLowest <= i2) + if(AI_ActionCastSpell(SPELL_ETHEREAL_VISAGE, OBJECT_SELF, 16, FALSE)) return TRUE; + if(nLowest <= 2) { // This is the shadow dancer evade - if(AI_ActionUseFeatOnObject(FEAT_SHADOW_EVADE)) return TRUE; + if(AI_ActionUseSpellLikeFeat(FEAT_SHADOW_EVADE, SPELL_SHADOW_EVADE)) return TRUE; // This is the assassin ghostly visage. - if(AI_ActionUseFeatOnObject(FEAT_PRESTIGE_SPELL_GHOSTLY_VISAGE)) return TRUE; + if(AI_ActionUseSpellLikeFeat(FEAT_PRESTIGE_SPELL_GHOSTLY_VISAGE, SPELLABILITY_AS_GHOSTLY_VISAGE)) return TRUE; // This is ghostly visage, dispite the spell constant name. G.Shadow conjuration - if(AI_ActionCastSubSpell(SPELL_GREATER_SHADOW_CONJURATION_MIRROR_IMAGE, SpellProSinTar, OBJECT_SELF, i15, FALSE, ItemProSinTar)) return TRUE; + // * Cast as a sub-spell. + if(AI_ActionCastSpell(SPELL_GREATER_SHADOW_CONJURATION_MIRROR_IMAGE, OBJECT_SELF, 15, FALSE, TRUE)) return TRUE; // Ghostly Visage is only 5/+1, but could work at the lower levels! Immunity to 1-0 spells too. // Level 2 (Mage). - if(AI_ActionCastSpell(SPELL_GHOSTLY_VISAGE, SpellProSelf, OBJECT_SELF, i12, FALSE, ItemProSelf, PotionPro)) return TRUE; + if(AI_ActionCastSpell(SPELL_GHOSTLY_VISAGE, OBJECT_SELF, 12, FALSE)) return TRUE; } } } return FALSE; } // Wrappers All Mantals (Greater, Normal, Lesser) (Spell Mantals) -// - iLowest - 9 = Greater, 7 = Normal. 5 = Lesser +// - nLowest - 9 = Greater, 7 = Normal. 5 = Lesser // - Checks AI_GetAIHaveSpellsEffect(GlobalHasMantalProtections) -int AI_SpellWrapperMantalProtections(int iLowest = 1) +int AI_SpellWrapperMantalProtections(int nLowest = 1) { // Provides total spell immunity (for most spells, say, 99%) until runs out/dispeled. - if(!AI_GetAIHaveSpellsEffect(GlobalHasMantalProtections) && iLowest <= i9) + if(!AI_GetAIHaveSpellsEffect(GlobalHasMantalProtections) && nLowest <= 9) { // Greater Spell mantal. Level 9 (Mage), for d12() + 10 spell levels protected. - if(AI_ActionCastSpell(SPELL_GREATER_SPELL_MANTLE, SpellProSelf, OBJECT_SELF, i19, FALSE, ItemProSelf, PotionPro)) return TRUE; - if(iLowest <= i7) + if(AI_ActionCastSpell(SPELL_GREATER_SPELL_MANTLE, OBJECT_SELF, 19, FALSE)) return TRUE; + if(nLowest <= 7) { // Normal, level 7 spell (Mage). d6() + 8 spell levels protected. - if(AI_ActionCastSpell(SPELL_SPELL_MANTLE, SpellProSelf, OBJECT_SELF, i17, FALSE, ItemProSelf, PotionPro)) return TRUE; - if(iLowest <= i5) + if(AI_ActionCastSpell(SPELL_SPELL_MANTLE, OBJECT_SELF, 17, FALSE)) return TRUE; + if(nLowest <= 5) { // Lesser, level 5 spell (Mage). d4() + 6 spell levels protected. - if(AI_ActionCastSpell(SPELL_LESSER_SPELL_MANTLE, SpellProSelf, OBJECT_SELF, i15, FALSE, ItemProSelf, PotionPro)) return TRUE; + if(AI_ActionCastSpell(SPELL_LESSER_SPELL_MANTLE, OBJECT_SELF, 15, FALSE)) return TRUE; } } } return FALSE; } // Wrappers All Globes (Greater, Shadow Conjuration, Minor) -// - iLowest - 6 = Greater, 4 = Shadow/Minor +// - nLowest - 6 = Greater, 4 = Shadow/Minor // - Checks AI_GetAIHaveSpellsEffect(GlobalHasGlobeProtections) -int AI_SpellWrapperGlobeProtections(int iLowest = 1) +int AI_SpellWrapperGlobeProtections(int nLowest = 1) { // Immunity to most spells of X or under. Good because level 4 spells have a large selection of AOE ones. - if(!AI_GetAIHaveSpellsEffect(GlobalHasGlobeProtections) && iLowest <= i6) + if(!AI_GetAIHaveSpellsEffect(GlobalHasGlobeProtections) && nLowest <= 6) { // Normal globe, level 6 spell (Mage). Protects vurses 4 or lower spells. - if(AI_ActionCastSpell(SPELL_GLOBE_OF_INVULNERABILITY, SpellProSinTar, OBJECT_SELF, i16, FALSE, ItemProSinTar, PotionPro)) return TRUE; + if(AI_ActionCastSpell(SPELL_GLOBE_OF_INVULNERABILITY, OBJECT_SELF, 16, FALSE)) return TRUE; // Note! Ethereal Visage protects VS 0, 1, 2 levels spells. - if(iLowest <= i4) + if(nLowest <= 4) { // SPELL_GREATER_SHADOW_CONJURATION_MINOR_GLOBE. - // As Minor globe, except shadow version - if(AI_ActionCastSubSpell(SPELL_GREATER_SHADOW_CONJURATION_MINOR_GLOBE, SpellProSelf, OBJECT_SELF, i15, FALSE, ItemProSelf, PotionPro)) return TRUE; + // As Minor globe, except shadow version. Cast as sub-spell. + if(AI_ActionCastSpell(SPELL_GREATER_SHADOW_CONJURATION_MINOR_GLOBE, OBJECT_SELF, 15, FALSE, TRUE)) return TRUE; // Minor globe, level 4 spell (Mage). Protects vurses 3 or lower spells. - if(AI_ActionCastSpell(SPELL_MINOR_GLOBE_OF_INVULNERABILITY, SpellProSelf, OBJECT_SELF, i14, FALSE, ItemProSelf, PotionPro)) return TRUE; + if(AI_ActionCastSpell(SPELL_MINOR_GLOBE_OF_INVULNERABILITY, OBJECT_SELF, 14, FALSE)) return TRUE; } } return FALSE; } // Wrappers All Shields - Elemental Shield, Wounding Whispers -// - iLowest - 4 = Elemental, 3 = Wounding. +// - nLowest - 4 = Elemental, 3 = Wounding. // - Checks AI_GetAIHaveSpellsEffect(GlobalHasElementalShieldSpell) -int AI_SpellWrapperShieldProtections(int iLowest = 1) +int AI_SpellWrapperShieldProtections(int nLowest = 1) { // These help deflect damage :-D - if(!AI_GetAIHaveEffect(GlobalEffectDamageShield) && iLowest <= i4) + if(!AI_GetAIHaveEffect(GlobalEffectDamageShield) && nLowest <= 4) { // Elemental Shield. Level 4 (Mage). Does some damage to melee attackers (Casterlvl + d6(), Fire). +50% cold/fire resistance. - if(AI_ActionCastSpell(SPELL_ELEMENTAL_SHIELD, SpellProSinTar, OBJECT_SELF, i14, FALSE, ItemProSinTar, PotionPro)) return TRUE; - if(iLowest <= i3) + if(AI_ActionCastSpell(SPELL_ELEMENTAL_SHIELD, OBJECT_SELF, 14, FALSE)) return TRUE; + if(nLowest <= 3) { // Acid Sheath. Level 3 (Mage) Does some damage to melee attackers (2 * CasterLvl + 1d6, Acid). - if(AI_ActionCastSpell(SPELL_MESTILS_ACID_SHEATH, SpellProSinTar, OBJECT_SELF, i13, FALSE, ItemProSinTar, PotionPro)) return TRUE; + if(AI_ActionCastSpell(SPELL_MESTILS_ACID_SHEATH, OBJECT_SELF, 13, FALSE)) return TRUE; // Wounding Whispers. Level 3 (bard) Does some damage to melee attackers (Casterlvl + d6(), Sonic). - if(AI_ActionCastSpell(SPELL_WOUNDING_WHISPERS, SpellProSinTar, OBJECT_SELF, i13, FALSE, ItemProSinTar, PotionPro)) return TRUE; + if(AI_ActionCastSpell(SPELL_WOUNDING_WHISPERS, OBJECT_SELF, 13, FALSE)) return TRUE; - if(iLowest <= i2) + if(nLowest <= 2) { // Death Armor. Level 2 (Mage) Does some damage to melee attackers (Caster Level/2 (to +5) + 1d4, Magical) - if(AI_ActionCastSpell(SPELL_DEATH_ARMOR, SpellProSinTar, OBJECT_SELF, i13, FALSE, ItemProSinTar, PotionPro)) return TRUE; + if(AI_ActionCastSpell(SPELL_DEATH_ARMOR, OBJECT_SELF, 13, FALSE)) return TRUE; } } } return FALSE; } // Wrappers All Mind resistance spells - Mind blank, Lesser and Clarity. bioware likes 3's... -// - iLowest - 8 = Mind Blank, 5 = Lesser, 2 = Clarity +// - nLowest - 8 = Mind Blank, 5 = Lesser, 2 = Clarity // - Checks AI_GetAIHaveSpellsEffect(GlobalHasMindResistanceProtections) -int AI_SpellWrapperMindResistanceProtections(int iLowest = 1) +int AI_SpellWrapperMindResistanceProtections(int nLowest = 1) { // immunties against mind - cool :-D (but not 100% useful). // Might add more "if they cast a mind spell, we cast this to stop more" in sometime - if(!AI_GetAIHaveSpellsEffect(GlobalHasMindResistanceProtections) && iLowest <= i8) + if(!AI_GetAIHaveSpellsEffect(GlobalHasMindResistanceProtections) && nLowest <= 8) { // Mind Blank. Level 8 (Mage) Mind immunity (and clean up) - if(AI_ActionCastSpell(SPELL_MIND_BLANK, SpellEnhSinTar, OBJECT_SELF, i18, FALSE, ItemEnhSinTar, PotionEnh)) return TRUE; - if(iLowest <= i5) + if(AI_ActionCastSpell(SPELL_MIND_BLANK, OBJECT_SELF, 18, FALSE)) return TRUE; + if(nLowest <= 5) { // Lesser Mind Blank. Level 5 (Mage) Mind immunity (and clean up) - if(AI_ActionCastSpell(SPELL_LESSER_MIND_BLANK, SpellEnhSinTar, OBJECT_SELF, i15, FALSE, ItemEnhSinTar, PotionEnh)) return TRUE; - if(iLowest <= i2) + if(AI_ActionCastSpell(SPELL_LESSER_MIND_BLANK, OBJECT_SELF, 15, FALSE)) return TRUE; + if(nLowest <= 2) { // Clarity. Level 2 (Bard/Innate) 3 (Cleric/Mage) Mind immunity (and clean up) - if(AI_ActionCastSpell(SPELL_CLARITY, SpellEnhSinTar, OBJECT_SELF, i12, FALSE, ItemEnhSinTar, PotionEnh)) return TRUE; + if(AI_ActionCastSpell(SPELL_CLARITY, OBJECT_SELF, 12, FALSE)) return TRUE; } } } @@ -6312,28 +6214,32 @@ int AI_SpellWrapperMindResistanceProtections(int iLowest = 1) } // Wrappers All Consealment spells - Improved Invisiblity. Displacement. -// - iLowest - 4 = Improved Invisiblit, 3 = Displacement +// - nLowest - 4 = Improved Invisiblit, 3 = Displacement // - Checks !AI_GetAIHaveEffect(GlobalEffectInvisible, oTarget) && !AI_GetAIHaveSpellsEffect(GlobalHasConsealmentSpells, oTarget) -int AI_SpellWrapperConsealmentEnhancements(object oTarget, int iLowest = 1) +int AI_SpellWrapperConsealmentEnhancements(object oTarget, int nLowest = 1) { if(!AI_GetAIHaveEffect(GlobalEffectInvisible, oTarget) && - !AI_GetAIHaveSpellsEffect(GlobalHasConsealmentSpells, oTarget)) + !GetHasSpellEffect(SPELL_DISPLACEMENT, oTarget)) { - // Shadow dragon special consealment - if(AI_ActionCastSpell(AI_SPELLABILITY_SHADOWBLEND)) return TRUE; - - if(iLowest <= i4) + if(oTarget == OBJECT_SELF) { - // Improved Invis - assassin - if(AI_ActionUseFeatOnObject(FEAT_PRESTIGE_INVISIBILITY_2)) return TRUE; - + // Shadow dragon special consealment + if(AI_ActionCastSpell(AI_SPELLABILITY_SHADOWBLEND)) return TRUE; + } + if(nLowest <= 4) + { + if(oTarget == OBJECT_SELF) + { + // Improved Invis - assassin + if(AI_ActionUseSpellLikeFeat(FEAT_PRESTIGE_INVISIBILITY_2, SPELLABILITY_AS_IMPROVED_INVISIBLITY)) return TRUE; + } // Improved Invis. Level 4 (Bard, Mage). 50% consealment + invisibility. - if(AI_ActionCastSpell(SPELL_IMPROVED_INVISIBILITY, SpellEnhSinTar, OBJECT_SELF, i14, FALSE, ItemEnhSinTar, PotionEnh)) return TRUE; + if(AI_ActionCastSpell(SPELL_IMPROVED_INVISIBILITY, oTarget, 14, FALSE)) return TRUE; - if(iLowest <= i3) + if(nLowest <= 3) { // Displacement. Level 3 (Mage). 50% consealment. - if(AI_ActionCastSpell(SPELL_DISPLACEMENT, SpellEnhSinTar, OBJECT_SELF, i13, FALSE, ItemEnhSinTar, PotionEnh)) return TRUE; + if(AI_ActionCastSpell(SPELL_DISPLACEMENT, oTarget, 13, FALSE)) return TRUE; } } } @@ -6343,101 +6249,105 @@ int AI_SpellWrapperConsealmentEnhancements(object oTarget, int iLowest = 1) int AI_SpellWrapperDarknessSpells(object oTarget) { // Special Assassin Version - if(AI_ActionUseFeatOnObject(FEAT_PRESTIGE_DARKNESS, oTarget)) return TRUE; - // Shades one - if(AI_ActionCastSubSpell(SPELL_SHADOW_CONJURATION_DARKNESS, SpellOtherSpell, oTarget, i14, TRUE)) return TRUE; + if(AI_ActionUseSpellLikeFeat(FEAT_PRESTIGE_DARKNESS, SPELLABILITY_AS_DARKNESS, oTarget)) return TRUE; + // Shades one. Cast as sub-spell. + if(AI_ActionCastSpell(SPELL_SHADOW_CONJURATION_DARKNESS, oTarget, 14, TRUE, TRUE)) return TRUE; // Darkness. Area of consealment. Level 2 (Cleric/Bard/Mage) Specail Assassin. - if(AI_ActionCastSpell(SPELL_DARKNESS, SpellOtherSpell, oTarget, i12, TRUE)) return TRUE; + if(AI_ActionCastSpell(SPELL_DARKNESS, oTarget, 12, TRUE)) return TRUE; return FALSE; } // Invisibility spells + feats int AI_SpellWrapperNormalInvisibilitySpells() { - // Special Harper Version - if(AI_ActionUseFeatOnObject(FEAT_HARPER_INVISIBILITY)) return TRUE; - // Special Assassin Version - if(AI_ActionUseFeatOnObject(FEAT_PRESTIGE_INVISIBILITY_1)) return TRUE; + // Special Harper Version - Normal invisibility. + if(AI_ActionUseSpellLikeFeat(FEAT_HARPER_INVISIBILITY, AI_SPELLABILITY_HARPER_INVISIBILITY)) return TRUE; + // Special Assassin Version - Normal invisibility. + if(AI_ActionUseSpellLikeFeat(FEAT_PRESTIGE_INVISIBILITY_1, SPELLABILITY_AS_INVISIBILITY)) return TRUE; // Cast invisiblity spells! // Invisiblity Sphere. Level 3 (Bard, Mage). Invisibility till attacked for an area! - if(AI_ActionCastSpell(SPELL_INVISIBILITY_SPHERE, SpellEnhAre, OBJECT_SELF, i13, FALSE, ItemEnhAre)) return TRUE; - // Shad. conjuration - if(AI_ActionCastSubSpell(SPELL_SHADOW_CONJURATION_INIVSIBILITY, SpellEnhSinTar, OBJECT_SELF, i12, FALSE, ItemEnhSinTar, PotionEnh)) return TRUE; + if(AI_ActionCastSpell(SPELL_INVISIBILITY_SPHERE, OBJECT_SELF, 13, FALSE)) return TRUE; + // Shad. conjuration. Cast as sub-spell. + if(AI_ActionCastSpell(SPELL_SHADOW_CONJURATION_INIVSIBILITY, OBJECT_SELF, 12, FALSE, TRUE)) return TRUE; // Invisiblity. Level 2 (Bard, Mage). Invisibility till attacked. - if(AI_ActionCastSpell(SPELL_INVISIBILITY, SpellEnhSinTar, OBJECT_SELF, i12, FALSE, ItemEnhSinTar, PotionEnh)) return TRUE; + if(AI_ActionCastSpell(SPELL_INVISIBILITY, OBJECT_SELF, 12, FALSE)) return TRUE; return FALSE; } // This will loop seen allies in a cirtain distance, and get the first one without -// the spells effects of iSpell1 to iSpell4 (and do not have the spells). -// - Quite expensive loop. Only used if we have the spell (iSpellToUse1+) -// in the first place (no items!) and not the timer which stops it for a few rounds (on iSpellToUse1) -// - TRUE if it casts its any of iSpellToUseX's. +// the spells effects of nSpell1 to nSpell4 (and do not have the spells). +// - Quite expensive loop. Only used if we have the spell (nSpellToUse1+) +// in the first place (no items!) and not the timer which stops it for a few rounds (on nSpellToUse1) +// - TRUE if it casts its any of nSpellToUseX's. // * It has only a % chance to cast if GlobalWeAreBuffer is not TRUE. -int AI_ActionCastAllyBuffSpell(float fMaxRange, int iPercent, int iSpellToUse1, int iSpellToUse2 = -1, int iSpellToUse3 = -1, int iSpellToUse4 = -1, int iSpellOther1 = -1, int iSpellOther2 = -1) +int AI_ActionCastAllyBuffSpell(float fMaxRange, int nPercent, int nSpellToUse1, int nSpellToUse2 = AI_SPELL_INVALID, int nSpellToUse3 = AI_SPELL_INVALID, int nSpellToUse4 = AI_SPELL_INVALID, int nSpellOther1 = AI_SPELL_INVALID, int nSpellOther2 = AI_SPELL_INVALID) { // Not in time stop if(GlobalInTimeStop) return FALSE; // Check buff ally is valid - if(!GetIsObjectValid(GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN_BUFF + s1))) return FALSE; + if(!GetIsObjectValid(GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN_BUFF + "1"))) return FALSE; // Check % (buffers add 150, so always pass this) - if(d100() > (iPercent + // Default % - (i150 * GlobalWeAreBuffer) - // Always cast if buffer - (GlobalWeAreSorcerorBard * i50) + // Much less (50%) if sorceror/bard + if(d100() > (nPercent + // Default % + (150 * GlobalWeAreBuffer) - // Always cast if buffer + (GlobalWeAreSorcerorBard * 50) + // Much less (50%) if sorceror/bard (FloatToInt(GlobalRangeToMeleeTarget))// Add a little for range to melee target )) return FALSE; // Check local timer for the top spell to cast against the ally. Only the // top spell is timed. - if(GetLocalTimer(AI_TIMER_BUFF_ALLY_SPELL + IntToString(iSpellToUse1))) return FALSE; + if(GetLocalTimer(AI_TIMER_BUFF_ALLY_SPELL + IntToString(nSpellToUse1))) return FALSE; // Set local timer to not use it for a while - SetLocalTimer(AI_TIMER_BUFF_ALLY_SPELL + IntToString(iSpellToUse1), f18); + SetLocalTimer(AI_TIMER_BUFF_ALLY_SPELL + IntToString(nSpellToUse1), 18.0); // Check if we have the spell - if(!GetHasSpell(iSpellToUse1) && !GetHasSpell(iSpellToUse2) && - !GetHasSpell(iSpellToUse3) && !GetHasSpell(iSpellToUse4)) return FALSE; + if(!GetHasSpell(nSpellToUse1) && !GetHasSpell(nSpellToUse2) && + !GetHasSpell(nSpellToUse3) && !GetHasSpell(nSpellToUse4)) return FALSE; // - This lets real-hardcode buffers go to a longer range. float fRangeToGoTo = fMaxRange + GlobalBuffRangeAddon; // Loop nearest to futhest allies - int iCnt = i1; - object oAlly = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN_BUFF + IntToString(iCnt)); + int nCnt = 1; + object oAlly = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN_BUFF + IntToString(nCnt)); // Loop Targets - // - iCnt is our breaker. We only check 10 nearest allies, and set to 20 if break. - while(GetIsObjectValid(oAlly) && iCnt <= i10 && GetDistanceToObject(oAlly) <= fRangeToGoTo) + // - nCnt is our breaker. We only check 10 nearest allies, and set to 20 if break. + while(GetIsObjectValid(oAlly) && nCnt <= 10 && GetDistanceToObject(oAlly) <= fRangeToGoTo) { // Check for thier effects - if((iSpellToUse1 == iM1 || !GetHasSpellEffect(iSpellToUse1, oAlly)) && - (iSpellToUse2 == iM1 || !GetHasSpellEffect(iSpellToUse2, oAlly)) && - (iSpellToUse3 == iM1 || !GetHasSpellEffect(iSpellToUse3, oAlly)) && - (iSpellToUse4 == iM1 || !GetHasSpellEffect(iSpellToUse4, oAlly)) && - (iSpellOther1 == iM1 || !GetHasSpellEffect(iSpellOther1, oAlly)) && - (iSpellOther2 == iM1 || !GetHasSpellEffect(iSpellOther2, oAlly)) && - !GetHasSpell(iSpellToUse1, oAlly) && !GetHasSpell(iSpellToUse2, oAlly) && - !GetHasSpell(iSpellToUse3, oAlly) && !GetHasSpell(iSpellToUse4, oAlly)) + if((nSpellToUse1 == AI_SPELL_INVALID || !GetHasSpellEffect(nSpellToUse1, oAlly)) && + (nSpellToUse2 == AI_SPELL_INVALID || !GetHasSpellEffect(nSpellToUse2, oAlly)) && + (nSpellToUse3 == AI_SPELL_INVALID || !GetHasSpellEffect(nSpellToUse3, oAlly)) && + (nSpellToUse4 == AI_SPELL_INVALID || !GetHasSpellEffect(nSpellToUse4, oAlly)) && + (nSpellOther1 == AI_SPELL_INVALID || !GetHasSpellEffect(nSpellOther1, oAlly)) && + (nSpellOther2 == AI_SPELL_INVALID || !GetHasSpellEffect(nSpellOther2, oAlly)) && + !GetHasSpell(nSpellToUse1, oAlly) && !GetHasSpell(nSpellToUse2, oAlly) && + !GetHasSpell(nSpellToUse3, oAlly) && !GetHasSpell(nSpellToUse4, oAlly)) { // Break with this ally as target - iCnt = i20; + nCnt = 20; } else { // Get Next ally - iCnt++; - oAlly = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN_BUFF + IntToString(iCnt)); + nCnt++; + oAlly = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN_BUFF + IntToString(nCnt)); } } // If valid, cast at the target and return TRUE. - if(iCnt == i20) + if(nCnt == 20) { // oAlly is our buff target - cast the best to worst on it! - if(AI_ActionCastSpell(iSpellToUse1, FALSE, oAlly)) return TRUE; - if(AI_ActionCastSpell(iSpellToUse2, FALSE, oAlly)) return TRUE; - if(AI_ActionCastSpell(iSpellToUse3, FALSE, oAlly)) return TRUE; - if(AI_ActionCastSpell(iSpellToUse4, FALSE, oAlly)) return TRUE; + if(nSpellToUse1 != AI_SPELL_INVALID) + if(AI_ActionCastSpell(nSpellToUse1, oAlly)) return TRUE; + if(nSpellToUse2 != AI_SPELL_INVALID) + if(AI_ActionCastSpell(nSpellToUse2, oAlly)) return TRUE; + if(nSpellToUse3 != AI_SPELL_INVALID) + if(AI_ActionCastSpell(nSpellToUse3, oAlly)) return TRUE; + if(nSpellToUse4 != AI_SPELL_INVALID) + if(AI_ActionCastSpell(nSpellToUse4, oAlly)) return TRUE; } // Return FALSE - no spell cast return FALSE; @@ -6506,29 +6416,29 @@ int AI_ActionCastWhenInvisible() // Much lower % as sorceror or bard. // Try stoneskins as a main one - if(AI_ActionCastAllyBuffSpell(f6, i100, SPELL_GREATER_STONESKIN, SPELL_STONESKIN)) return TRUE; + if(AI_ActionCastAllyBuffSpell(6.0, 100, SPELL_GREATER_STONESKIN, SPELL_STONESKIN)) return TRUE; // Hastes! - if(AI_ActionCastAllyBuffSpell(f8, i100, SPELL_HASTE, SPELL_MASS_HASTE)) return TRUE; + if(AI_ActionCastAllyBuffSpell(8.0, 100, SPELL_HASTE, SPELL_MASS_HASTE)) return TRUE; // Consealment spells - if(AI_ActionCastAllyBuffSpell(f6, i100, SPELL_IMPROVED_INVISIBILITY, SPELL_DISPLACEMENT)) return TRUE; + if(AI_ActionCastAllyBuffSpell(6.0, 100, SPELL_IMPROVED_INVISIBILITY, SPELL_DISPLACEMENT)) return TRUE; // Elemental protections - if(AI_ActionCastAllyBuffSpell(f6, i100, SPELL_ENERGY_BUFFER, SPELL_PROTECTION_FROM_ELEMENTS, SPELL_RESIST_ELEMENTS, SPELL_ENDURE_ELEMENTS)) return TRUE; + if(AI_ActionCastAllyBuffSpell(6.0, 100, SPELL_ENERGY_BUFFER, SPELL_PROTECTION_FROM_ELEMENTS, SPELL_RESIST_ELEMENTS, SPELL_ENDURE_ELEMENTS)) return TRUE; // If we have the setting to buff allies, we carry on buffing with some // other spells. if(GlobalWeAreBuffer) { // Some AC protections - if(AI_ActionCastAllyBuffSpell(f6, i100, SPELL_MAGE_ARMOR, SPELL_BARKSKIN)) return TRUE; + if(AI_ActionCastAllyBuffSpell(6.0, 100, SPELL_MAGE_ARMOR, SPELL_BARKSKIN)) return TRUE; // Bulls Strength, Cats Grace, Endurance - if(AI_ActionCastAllyBuffSpell(f10, i100, SPELL_ENDURANCE, SPELL_CATS_GRACE, SPELL_ENDURANCE, iM1, SPELL_GREATER_BULLS_STRENGTH, SPELL_GREATER_CATS_GRACE)) return TRUE; + if(AI_ActionCastAllyBuffSpell(10.0, 100, SPELL_ENDURANCE, SPELL_CATS_GRACE, SPELL_ENDURANCE, -1, SPELL_GREATER_BULLS_STRENGTH, SPELL_GREATER_CATS_GRACE)) return TRUE; // Bless, Aid - if(AI_ActionCastAllyBuffSpell(f6, i100, SPELL_AID, SPELL_BLESS)) return TRUE; + if(AI_ActionCastAllyBuffSpell(6.0, 100, SPELL_AID, SPELL_BLESS)) return TRUE; } // Return FALSE - nothing cast return FALSE; @@ -6536,45 +6446,45 @@ int AI_ActionCastWhenInvisible() // Using the array ARRAY_ENEMY_RANGE, we return a % of seen/heard people who // DO have any of the spells which see through the invisiblity spells. -// * iLimit - when we get to this number of people who have invisiblity, we stop and return 100% +// * nLimit - when we get to this number of people who have invisiblity, we stop and return 100% // If ANY of the people are attacking us and have the effect, we return +30% for each. -int AI_GetSpellWhoCanSeeInvis(int iLimit) +int AI_GetSpellWhoCanSeeInvis(int nLimit) { // Loop LOS range enemies. - int iCnt = i1; - int iHasSeeingTotal, iTotal, iAdditional; + int nCnt = 1; + int nHasSeeingTotal, nTotal, nAdditional; // Loop start - object oEnemy = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(iCnt)); - while(GetIsObjectValid(oEnemy) && iAdditional < i100) + object oEnemy = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(nCnt)); + while(GetIsObjectValid(oEnemy) && nAdditional < 100) { // Seen/heard check is already done // Add one to total. - iTotal++; + nTotal++; // Make this the total of any seeing spells. if(GetHasSpellEffect(SPELL_SEE_INVISIBILITY, oEnemy) || GetHasSpellEffect(SPELL_TRUE_SEEING, oEnemy) || // - We obviously can tell with creatures with true seeing hides. Only checking hides! GetItemHasItemProperty(GetItemInSlot(INVENTORY_SLOT_CARMOUR, oEnemy), ITEM_PROPERTY_TRUE_SEEING)) { - iHasSeeingTotal++; + nHasSeeingTotal++; // Limit checking - if(iHasSeeingTotal >= iLimit) + if(nHasSeeingTotal >= nLimit) { - iAdditional += i100; + nAdditional += 100; } // Special: If they are attacking us (with it) we add 30% // to outcome, and add 1. else if(GetAttackTarget(oEnemy) == OBJECT_SELF) { - iAdditional += i30; + nAdditional += 30; } } - iCnt++; - oEnemy = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(iCnt)); + nCnt++; + oEnemy = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(nCnt)); } - if(iHasSeeingTotal > FALSE) + if(nHasSeeingTotal > FALSE) { - return AI_GetPercentOf(iHasSeeingTotal, iTotal) + iAdditional; + return AI_GetPercentOf(nHasSeeingTotal, nTotal) + nAdditional; } return FALSE; } @@ -6585,11 +6495,11 @@ int AI_GetSpellWhoCanSeeInvis(int iLimit) object AI_GetDismissalTarget() { object oMaster, oReturn; - int iCnt = i1; - string sCnt = IntToString(iCnt); + int nCnt = 1; + string sCnt = IntToString(nCnt); object oLoopTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + sCnt); float fDistance = GetLocalFloat(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + sCnt); - while(GetIsObjectValid(oLoopTarget) && fDistance <= f10) + while(GetIsObjectValid(oLoopTarget) && fDistance <= 10.0) { // Check if they are a valid summon/familar/comapnion oMaster = GetMaster(oLoopTarget); @@ -6607,8 +6517,8 @@ object AI_GetDismissalTarget() } } // Get next target - iCnt++; - sCnt = IntToString(iCnt); + nCnt++; + sCnt = IntToString(nCnt); fDistance = GetLocalFloat(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + sCnt); oLoopTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + sCnt); } @@ -6648,12 +6558,12 @@ object AI_GetDismissalTarget() best! This attempts to cast a spell, running down the lists. - The only variable is iLowest and iBAB level's, targets are globally set. - - iLowestSpellLevel - If it is set to more than 1, then all spells of that + The only variable is nLowest and iBAB level's, targets are globally set. + - nLowestSpellLevel - If it is set to more than 1, then all spells of that level and lower are just ignored. Used for dragons. Default 0. - - iBABCheckHighestLevel - We check our BAB to see if attacking them would probably + - nBABCheckHighestLevel - We check our BAB to see if attacking them would probably be a better thing to do. Default 3, it adds 5DC for each level. - - iLastCheckedRange - 1 = Minimum, 4 = Longest. If it runs through once, and + - nLastCheckedRange - 1 = Minimum, 4 = Longest. If it runs through once, and with "ranged attacking", doesn't find any spells to cast at the "long" range, then it will attempt to see if there are any spells for "meduim" etc. - Range: Long 40, Medium: 20, Short: 10, Touch: 2.25 (Game meters). Personal = 0 @@ -6674,16 +6584,25 @@ object AI_GetDismissalTarget() //:://///////////////////////////////////////////// //:: Created By: Jugulator, Modified (very) Heavily: Jasperre //::////////////////////////////////////////////*/ -int AI_AttemptAllSpells(int iLowestSpellLevel = 0, int iBABCheckHighestLevel = 3, int iLastCheckedRange = 1, int InputRangeLongValid = FALSE, int InputRangeMediumValid = FALSE, int InputRangeShortValid = FALSE, int InputRangeTouchValid = FALSE) + +// This will attempt to cast a spell from all the spells we know. +// It calls AI_RunThroughSpells() to work. +// * nLowestSpellLevel - If it is set to more than 1, then all spells of that +// level and lower are just ignored. Used for dragons. Default 0. +// * nBABCheckHighestLevel - We check our BAB to see if attacking them would probably +// be a better thing to do. Default 3, it adds 5DC for each level. +// NOTE 1: If GlobalItemsOnly is set, we only check for item talents! +// NOTE 2: It uses the SAME target, but for ranged attacking, we use a float range to check range :-) +int AI_AttemptAllSpells(int nLowestSpellLevel = 0, int nBABCheckHighestLevel = 3) { + // Invalid time to cast spells? // Checks for valid numbers, ETC. if(AI_GetAIHaveEffect(GlobalEffectPolymorph) || - (GlobalSpellAbilityModifier < i10 && !GobalOtherItemsValid && !GobalPotionsValid) || GetSpawnInCondition(AI_FLAG_OTHER_LAG_NO_SPELLS, AI_OTHER_MASTER) || // Do we have any spells to cast? - (GlobalSilenceSoItems && !GobalOtherItemsValid && !GobalPotionsValid) || - (!SpellAnySpellValid && !GobalOtherItemsValid && !GobalPotionsValid) || - !GetIsObjectValid(GlobalSpellTarget) || GetIsDead(GlobalSpellTarget)) +// (GlobalSilenceSoItems && !GobalOtherItemsValid && !GobalPotionsValid) || +// (!SpellAnySpellValid && !GobalOtherItemsValid && !GobalPotionsValid) || + !GetIsObjectValid(GlobalSpellTarget)) { // 31: "[DCR: All Spells] Error! No casting (No spells, items, target Etc)." DebugActionSpeakByInt(31); @@ -6691,112 +6610,182 @@ int AI_AttemptAllSpells(int iLowestSpellLevel = 0, int iBABCheckHighestLevel = 3 } // 11: "[DCR: All Spells] [Modifier|BaseDC|SRA] " + IntToString(iInput) // Input: 100 * GlobalSpellAbilityModifier) + 10 * GlobalSpellBaseSaveDC + SRA - DebugActionSpeakByInt(32, OBJECT_INVALID, (i100 * GlobalSpellAbilityModifier) + (i10 * GlobalSpellBaseSaveDC) + (SRA)); + DebugActionSpeakByInt(32, OBJECT_INVALID, (100 * GlobalSpellAbilityModifier) + (10 * GlobalSpellBaseSaveDC) + (SRA)); + // All the inputs (plus for SRA a few extra ones) for the spells function + // we calculate now. SRA is quite common, so useful not to do repetitive + // code. + int bRangeLongValid, bRangeMediumValid, bRangeShortValid, bRangeTouchValid, + bDoneMedium, bDoneShort, bDoneTouch, bSingleSpellsFirst, + bSingleSpellOverride, bMultiSpellOverride; + + // This forces the use of AOE spells over single target spells. + bMultiSpellOverride = GetSpawnInCondition(AI_FLAG_COMBAT_MANY_TARGETING, AI_COMBAT_MASTER); + // This forices the use single target spells before multiple target spells. + bSingleSpellOverride = GetSpawnInCondition(AI_FLAG_COMBAT_SINGLE_TARGETING, AI_COMBAT_MASTER); + + // if bSingleSpellsFirst == TRUE, we try our single spells before the + // AOE spells. If false, don't bother. Not set if not seen target. + // 1.4: More realistic checking. Test: + // * Must be 4 or less enemies seen to do single ones first + // * Have to have: + // - A lot of allies compared to enemies + // - Only one enemy seen + if(GlobalSeenSpell && GlobalTotalSeenHeardEnemies <= 4 && + (GlobalTotalSeenHeardEnemies - 2 <= (GlobalTotalAllies) || + GlobalTotalSeenHeardEnemies <= 1)) + { + bSingleSpellsFirst = TRUE; + } + // Else, it might set to TRUE because of the spawn setting for it. + else if(bSingleSpellOverride) + { + // Might be forced via. the setting, to use single target spells before + // multiple target spells. + bSingleSpellsFirst = TRUE; + } + + // Check which ranges are valid + // - Range: Long 40, Medium: 20, Short: 10, Touch: 2.25 (Game meters). Personal = 0 + // If spell ranged attacking is NOT on, we will always use all ranges. + if(!SRA) + { + bRangeLongValid = TRUE; + bRangeMediumValid = TRUE; + bRangeShortValid = TRUE; + bRangeTouchValid = TRUE; + } + // Ranges... + // If set to TRUE, we will cast spells that use that range. + // If set to FALSE, we will ignore spells that use that range. + // First run through! + else + { + // Long + // * Always (to start with) set this to TRUE + bRangeLongValid = TRUE; + // Note: if there was a bDoneLong, it'd always be TRUE + + // Check medium range + if(GlobalSpellTargetRange <= fMediumRange) + { + bRangeMediumValid = TRUE; + bDoneMedium = TRUE; + + // Check short range + if(GlobalSpellTargetRange <= fShortRange) + { + bRangeShortValid = TRUE; + bDoneShort = TRUE; + + // Check touch range + if(GlobalSpellTargetRange <= fTouchRange) + { + bRangeTouchValid = TRUE; + bDoneTouch = TRUE; + } + } + } + } + + // Start by casting them all normally + // * IE: bFirstRunThrough is TRUE, all ranges valid are as above. + int bResult = AI_RunThroughSpells(nLowestSpellLevel, nBABCheckHighestLevel, bSingleSpellsFirst, bSingleSpellOverride, bMultiSpellOverride, TRUE, bRangeLongValid, bRangeMediumValid, bRangeShortValid, bRangeTouchValid); + + // If bResult is FALSE, and SRA is ON, we might run it again with medium + // range now set to TRUE (unles it was already!) + if(bResult == FALSE && SRA == TRUE) + { + // Check if we have done all the ranges. + if(bDoneMedium && bDoneShort && bDoneTouch) + { + // Cannot do any more + return FALSE; + } + else + { + // We will now be able to flip medium range. + if(bDoneMedium == FALSE) + { + // Do a new loop. Took out the ones we have already done :-) + // 34: "[DCR: All Spells] Ranged Spells. Should use closer spells/move nearer" + DebugActionSpeakByInt(34); + bDoneMedium = TRUE; + bResult = AI_RunThroughSpells(nLowestSpellLevel, nBABCheckHighestLevel, bSingleSpellsFirst, bSingleSpellOverride, bMultiSpellOverride, FALSE, FALSE, TRUE); + } + } + } + // If bResult is FALSE, and SRA is ON, we might run it again with shout range. + if(bResult == FALSE && SRA == TRUE) + { + // Check if we have done all the ranges. + if(bDoneMedium && bDoneShort && bDoneTouch) + { + // Cannot do any more + return FALSE; + } + else + { + // We will now be able to flip short range. + if(bDoneShort == FALSE) + { + // Do a new loop. Took out the ones we have already done :-) + // 34: "[DCR: All Spells] Ranged Spells. Should use closer spells/move nearer" + DebugActionSpeakByInt(34); + bDoneShort = TRUE; + bResult = AI_RunThroughSpells(nLowestSpellLevel, nBABCheckHighestLevel, bSingleSpellsFirst, bSingleSpellOverride, bMultiSpellOverride, FALSE, FALSE, FALSE, TRUE); + } + } + } + // If bResult is FALSE, and SRA is ON, we might run it again with touch range. + if(bResult == FALSE && SRA == TRUE) + { + // Check if we have done all the ranges. + if(bDoneMedium && bDoneShort && bDoneTouch) + { + // Cannot do any more + return FALSE; + } + else + { + // We will now be able to flip short range. + if(bDoneTouch == FALSE) + { + // Do a new loop. Took out the ones we have already done :-) + // 34: "[DCR: All Spells] Ranged Spells. Should use closer spells/move nearer" + DebugActionSpeakByInt(34); + bDoneTouch = TRUE; + bResult = AI_RunThroughSpells(nLowestSpellLevel, nBABCheckHighestLevel, bSingleSpellsFirst, bSingleSpellOverride, bMultiSpellOverride, FALSE, FALSE, FALSE, FALSE, TRUE); + } + } + } + // Return bResult. + return bResult; +} + +// Called from AI_AttemptAllSpells, this will run through the spell lists, until +// it casts on, else it will return FALSE. +// * nLowestSpellLevel - If it is set to more than 1, then all spells of that +// level and lower are just ignored. Used for dragons. Default 0. +// * nBABCheckHighestLevel - We check our BAB to see if attacking them would probably +// be a better thing to do. Default 3, it adds 5DC for each level. +// * bFirstRunThrough - used for personal spells (cast on us) like the ranged checks, for SRA. +// * bRangeLongValid etc - used for ranged spell attacking. bFirstRunThrough is a personal version. +// See AI_AttemptAllSpells() for more info. +int AI_RunThroughSpells(int nLowestSpellLevel, int nBABCheckHighestLevel, int bSingleSpellsFirst, int bSingleSpellOverride, int bMultiSpellOverride, int bFirstRunThrough = TRUE, int bRangeLongValid = FALSE, int bRangeMediumValid = FALSE, int bRangeShortValid = FALSE, int bRangeTouchValid = FALSE) +{ // Sets up AOE target object to get. object oAOE, oRandomSpellNotUsedAOE, oPurge; // (oRandomSpellNotUsedAOE is set when we radomise a spell, and the spell // isn't cast, but could be!) - // Notes on targets: - // Uses 1. - // - Ranged attacking may IGNORE shorter ranged spells IF they are not in range. - - // - Range: Long 40, Medium: 20, Short: 10, Touch: 2.25 (Game meters). Personal = 0 - // Range valids: - int RangeLongValid, RangeMediumValid, RangeShortValid, RangeTouchValid, - iCnt, iBreak, /* Counter things */ - iPercentWhoSeeInvis, iNeedToBeBelow, SingleSpellsFirst, - SingleSpellOverride, MultiSpellOverride, IsFirstRunThrough; - // Range LONG should ALWAYS be used, IE we can't get a longer ranged spell than that! - // SRA! - - if(!SRA) - { - RangeLongValid = TRUE; - RangeMediumValid = TRUE; - RangeShortValid = TRUE; - RangeTouchValid = TRUE; - } - // We stop if all set to TRUE, IE, already checked. - else if(InputRangeLongValid && InputRangeMediumValid && - InputRangeShortValid && InputRangeTouchValid) - { - // All done, stop - return FALSE; - } - // Ranges... - // If set to TRUE, it is ignored. - // If set to FALSE, we check the pass number or the range, and set to true. - else - { - // Long - if(InputRangeLongValid == i0) - { - // No range check, RangeLongValid is of course always true. - RangeLongValid = TRUE; - } - // At 1, we do not do anything, and ignore long range spells. - // Medium - if(InputRangeMediumValid == i0) - { - // Range check for medium - or if the run is at number 2+ - if(GlobalSpellTargetRange <= fMediumRange || - iLastCheckedRange >= i2) - { - RangeMediumValid = TRUE; - } - } - // At 1, we ignore medium - // Short - if(InputRangeShortValid == i0) - { - // Range check for short - or if it is >= pass 3 - if(GlobalSpellTargetRange <= fShortRange || - iLastCheckedRange >= i3) - { - RangeShortValid = TRUE; - } - } - // At 1, we ignore short ranged spells - // Touch - if(InputRangeTouchValid == i0) - { - // Range check for touch - or >= pass 4 - if(GlobalSpellTargetRange <= fTouchRange || - iLastCheckedRange >= i4) - { - RangeTouchValid = TRUE; - } - } - // At 1, we ignore touch ranged spells - } - - // IsFirstRunThrough is TRUE if this is the first run through, if - // last checked range is == 1 - // - Used, if TRUE, for defensive spells to stop checking the same things - // up to 4 times! - if(iLastCheckedRange == i1) - { - IsFirstRunThrough = TRUE; - } - - // these force the use of AOE spells, or single spells, over the other. - SingleSpellOverride = GetSpawnInCondition(AI_FLAG_COMBAT_SINGLE_TARGETING, AI_COMBAT_MASTER); - MultiSpellOverride = GetSpawnInCondition(AI_FLAG_COMBAT_MANY_TARGETING, AI_COMBAT_MASTER); + // Declare integers + int nCnt, bBreak, /* Counter things */ + nPercentWhoSeeInvis, nNeedToBeBelow; // Saves. Stops them firing spells they would ALWAYs save against. // GlobalSpellTargetWill, GobalSpellTargetFort, GlobalSpellTargetReflex. - // SingleSpellsFirst = if TRUE, we try our single spells before the - // AOE spells. If false, don't bother. Not set if not seen target. - if(GlobalSeenSpell && (GlobalTotalSeenHeardEnemies < (GlobalOurHitDice / i3) || - GlobalTotalSeenHeardEnemies < i2 || - // Single targeting override. - SingleSpellOverride)) - { - SingleSpellsFirst = TRUE; - } // There is also the case of people immune to normal spells (such as // Fireball) but not spells like Gaze of Death. @@ -6835,8 +6824,8 @@ int AI_AttemptAllSpells(int iLowestSpellLevel = 0, int iBABCheckHighestLevel = 3 H [Epic Mage Armor] - +5 of the 4 different AC types. Just +5 dodge is a great asset. H [Hellball] - Long range AOE - 10d6 sonic, acid, fire and lightning damage to all in area. Reflex only halves. H [Ruin] - 35d6 divine damage, fort save for half. -H [Mummy Dust] - Powerful summon that cannot be dispelled. 24 Hours. -H [Dragon Knight] - Powerful dragon summon that cannot be dispelled. 20 rounds. +H [Mummy Dust] - Powerful summon that cannot be dnSpelled. 24 Hours. +H [Dragon Knight] - Powerful dragon summon that cannot be dnSpelled. 20 rounds. H [Epic Warding] - Damage reduction 50/+20. Lasts 1 round per level. AOE: @@ -6877,9 +6866,9 @@ H [Black Blade of Disaster] - A powerful greatsword fights. Please note: AI ab Same with [Haste]/[Mass Haste]. These are almost too good to miss! -S [Etherealness] is a VERY powerful spell - if we cast this, we can normally - cast defensive spells while invisible - cool :-) - - We cast quite a few invisible-based spells near the top of our list. +S [Greater Sanctuary (Etherealness)] is a VERY powerful spell - if we cast + this, we can normally cast defensive spells while invisible - cool :-) + - We cast quite a few invisible-based spells near the top of our list. [Time stop] is a special case - we cast it first if we have 2 or more, cast haste, then we are able to cast it again and get the maximum, safe, usage @@ -6902,30 +6891,30 @@ H [Crumble] - Constructs only. // No BAB check. // Not in time stop - if(IsFirstRunThrough && !GlobalInTimeStop && GlobalIntelligence >= (i6 - d4())) + if(bFirstRunThrough && !GlobalInTimeStop && GlobalIntelligence >= (6 - d4())) { - // We do this once, mind you, when we start at iLastCheckedRange == 4. + // We do this once, mind you, when we start at nLastCheckedRange == 4. // Get a nearby enemy summon - 10M range. oAOE = AI_GetDismissalTarget(); // Is it valid? if(GetIsObjectValid(oAOE)) { // Banishment. Level 6 (Cleric/Innate) 7 (Mage). Destroys outsiders as well as all summons in area around caster (10M) - if(AI_ActionCastSpell(SPELL_BANISHMENT, SpellHostAreaInd, OBJECT_SELF, i17, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpell(SPELL_BANISHMENT, OBJECT_SELF, 17, TRUE)) return TRUE; // Dismissal is short range anyway. Enemy must be within 5M to be targeted. // Dismissal. Level 4 (Bard/Cleric/Innate) 5 (Mage). At a will save (VS DC + 6) destroy summons/familiars/companions in area. - if(AI_ActionCastSpell(SPELL_DISMISSAL, SpellHostAreaDis, oAOE, i15, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpell(SPELL_DISMISSAL, oAOE, 15, TRUE)) return TRUE; } } // Time Stop - Never casts again in a timestop // This will cast it very first if we have 2 or more (Sorceror) - if(IsFirstRunThrough && !GlobalInTimeStop && GlobalIntelligence >= i10 && - GetHasSpell(SPELL_TIME_STOP) >= i2) + if(bFirstRunThrough && !GlobalInTimeStop && GlobalIntelligence >= 10 && + GetHasSpell(SPELL_TIME_STOP) >= 2) { // Time Stop. Level 9 (Mage). 9 Seconds (by default. Meant to be 1d4 + 1) of frozen time for caster. Meant to be a rare spell. - if(AI_ActionCastSpell(SPELL_TIME_STOP, SpellHostAreaDis, OBJECT_SELF, i19, FALSE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpell(SPELL_TIME_STOP, OBJECT_SELF, 19, FALSE)) return TRUE; } // Special case - Lots of phisical damage requires maximum protectoin. @@ -6933,64 +6922,63 @@ H [Crumble] - Constructs only. // if we have no stoneskins :-D // - We cast this if we have many melee attackers or total attackers. // - To save time stop checking, we don't do this in time stop. - if(GlobalIntelligence >= i7 && !GlobalInTimeStop && IsFirstRunThrough && + if(GlobalIntelligence >= 7 && !GlobalInTimeStop && bFirstRunThrough && !AI_GetAIHaveSpellsEffect(GlobalHasStoneSkinProtections) && !AI_GetAIHaveSpellsEffect(GlobalHasVisageProtections) && // Formula - IE They do 40 damage, we must be level 10 or less. :-) // - As this is mainly for mages, we don't bother about how much HP left. - (GetAIInteger(AI_HIGHEST_PHISICAL_DAMAGE_AMOUNT) >= GlobalOurHitDice * i4 || + (GetAIInteger(AI_HIGHEST_PHISICAL_DAMAGE_AMOUNT) >= GlobalOurHitDice * 4 || // - Do we have anyone in 20M? - (GlobalRangeToNearestEnemy <= f20 && + (GlobalRangeToNearestEnemy <= 20.0 && // BAB check as well - GlobalAverageEnemyBAB >= GlobalOurHitDice / i2))) + GlobalAverageEnemyBAB >= GlobalOurHitDice / 2))) { // Stoneskins and so forth first, then visages. // We think that Stoneskin (which has /+5) is better then 15/+3 - if(AI_SpellWrapperPhisicalProtections(iLowestSpellLevel)) return TRUE; + if(AI_SpellWrapperPhisicalProtections(nLowestSpellLevel)) return TRUE; // Visage - lowest of Ethereal (6) however. Ghostly? Don't bother - if(iLowestSpellLevel <= i6) + if(nLowestSpellLevel <= 6) { - if(AI_SpellWrapperVisageProtections(i6)) return TRUE; + if(AI_SpellWrapperVisageProtections(6)) return TRUE; } } // END phisical protections override check // Haste - First. Good one, I suppose. Should check for close (non-hasted) // allies, to choose between them. - if(IsFirstRunThrough && !AI_GetAIHaveEffect(GlobalEffectHaste) && + if(bFirstRunThrough && !AI_GetAIHaveEffect(GlobalEffectHaste) && !AI_CompareTimeStopStored(SPELL_HASTE, SPELL_MASS_HASTE)) { // I don't want to bother checking for allies for MASS_HASTE because // mass haste is a good duration/harder to Dispel compared to haste // anyway. // - Should this be moved down? - if(AI_SpellWrapperHasteEnchantments(iLowestSpellLevel)) return TRUE; + if(AI_SpellWrapperHasteEnchantments(nLowestSpellLevel)) return TRUE; } // Now the normal time stop. Power to the lords of time! (sorry, a bit over the top!) // - Top prioritory. If you don't want it to cast it first, don't give it to them! - if(IsFirstRunThrough && !GlobalInTimeStop) + if(bFirstRunThrough && !GlobalInTimeStop) { // Time Stop. Level 9 (Mage). 9 Seconds (by default. Meant to be 1d4 + 1) of frozen time for caster. Meant to be a rare spell. - if(AI_ActionCastSpell(SPELL_TIME_STOP, SpellHostAreaDis, OBJECT_SELF, i19, FALSE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpell(SPELL_TIME_STOP, OBJECT_SELF, 19, FALSE)) return TRUE; } // Special case - if lots of damage has been done elemetally wise, we will // cast elemental protections (if not cast already). // - To save time stop checking, we don't do this in time stop. // - Only done if 4 or more intelligence. - if(SpellProSinTar /*Extra check here.*/ && - !AI_GetAIHaveSpellsEffect(GlobalHasElementalProtections) && - !GlobalInTimeStop && IsFirstRunThrough && GlobalIntelligence >= i4 && + if(!AI_GetAIHaveSpellsEffect(GlobalHasElementalProtections) && + !GlobalInTimeStop && bFirstRunThrough && GlobalIntelligence >= 4 && // Formula - IE They do 40 damage, we must be level 10 or less. :-) // - As this is mainly for mages, we don't bother about how much HP left. - (GetAIInteger(MAX_ELEMENTAL_DAMAGE) >= GlobalOurHitDice * i4 || + (GetAIInteger(MAX_ELEMENTAL_DAMAGE) >= GlobalOurHitDice * 4 || // OR last hit was major compared to total HP - GetAIInteger(LAST_ELEMENTAL_DAMAGE) >= GlobalOurMaxHP/i4)) + GetAIInteger(LAST_ELEMENTAL_DAMAGE) >= GlobalOurMaxHP/4)) { - if(AI_SpellWrapperElementalProtections(iLowestSpellLevel)) + if(AI_SpellWrapperElementalProtections(nLowestSpellLevel)) { // Reset and return, if we cast something! DeleteAIInteger(MAX_ELEMENTAL_DAMAGE); @@ -7001,10 +6989,10 @@ H [Crumble] - Constructs only. // Epic mage armor after specials. Not the best place... // +20 AC is good, normally. - if(IsFirstRunThrough && !AI_GetAIHaveSpellsEffect(GlobalHasOtherACSpell)) + if(bFirstRunThrough && !AI_GetAIHaveSpellsEffect(GlobalHasOtherACSpell)) { // Epic Mage Armor. (Mage only) +5 of the 4 different AC types. Just +5 dodge is a great asset. - if(AI_ActionUseEpicSpell(AI_FEAT_EPIC_SPELL_EPIC_MAGE_ARMOR, SPELL_EPIC_MAGE_ARMOR)) return TRUE; + if(AI_ActionUseSpellLikeFeat(FEAT_EPIC_SPELL_MAGE_ARMOUR, SPELL_EPIC_MAGE_ARMOR)) return TRUE; } // Visibility Protections - going invisible! @@ -7013,7 +7001,7 @@ H [Crumble] - Constructs only. // - We must be of a decnt intelligence (5+) // - We must make sure we don't already have all the protections listed // - We MUST have not run through this once already. - if(!GlobalInTimeStop && GlobalIntelligence >= i5 && IsFirstRunThrough) + if(!GlobalInTimeStop && GlobalIntelligence >= 5 && bFirstRunThrough) { // First, check if we already have any effects. // - If we have GlobalEffectEthereal, then we cast all (non-see through) @@ -7048,7 +7036,7 @@ H [Crumble] - Constructs only. !AI_GetAIHaveSpellsEffect(GlobalHasElementalProtections) || !AI_GetAIHaveSpellsEffect(GlobalHasStoneSkinProtections) || !AI_GetAIHaveSpellsEffect(GlobalHasMantalProtections) || - GlobalOurPercentHP >= i100) + GlobalOurPercentHP >= 100) { // Is it a good time? (EG we want to flee, or want more protections :-) ). // - Do we HAVE THE SPELLS?! @@ -7057,15 +7045,17 @@ H [Crumble] - Constructs only. // * Fleeing that uses this does it in the flee section (not in yet) // * More protections for concentation is done in that section (not in yet) - // 1. Etherealness. + // 1. Greater Sanctuary (Etherealness). // This is easily the best one there is! always works 100%%%! // Etherealness. Total invisibility! Level 6 (Cleric) 8 (Mage) 7 (Innate). - if(AI_ActionCastSpell(SPELL_ETHEREALNESS, SpellOtherSpell, OBJECT_SELF, i17)) return TRUE; + if(AI_ActionCastSpell(SPELL_ETHEREALNESS, OBJECT_SELF, 17)) return TRUE; + // Monster ability - Actually called Etherealness. + if(AI_ActionCastSpell(AI_SPELLABILITY_ETHEREALNESS)) return TRUE; // 2. Darkness // We cast this hopefully most of the time. We will cast it a lot if we have // many melee attackers, else we'll cast it if we have ultravision/trueseeing - if(GlobalMeleeAttackers >= GlobalOurHitDice / i3 || + if(GlobalMeleeAttackers >= GlobalOurHitDice / 3 || AI_GetAIHaveEffect(GlobalEffectUltravision) || AI_GetAIHaveEffect(GlobalEffectTrueSeeing) || GetHasSpell(SPELL_DARKVISION) || GetHasSpell(SPELL_TRUE_SEEING)) @@ -7076,47 +7066,47 @@ H [Crumble] - Constructs only. // 3. Normal invisiblity. // We need to make sure it won't be Dispeled by invis purge. oPurge = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, - OBJECT_SELF, i1, + OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_HAS_SPELL_EFFECT, SPELL_INVISIBILITY_PURGE); - if(!GetIsObjectValid(oPurge) || GetDistanceToObject(oPurge) > f10) + if(!GetIsObjectValid(oPurge) || GetDistanceToObject(oPurge) > 10.0) { // Also, we can't go invisible if any enemies who are attacking us, // can see us. We also won't if over 50 (or whatever)% of the enemy have got // seeing spells. // What % though? MORE if we have limited, selected spell (non-sorceror/bard) // LESS if we do have other spells to take its place. - iPercentWhoSeeInvis = AI_GetSpellWhoCanSeeInvis(i4); + nPercentWhoSeeInvis = AI_GetSpellWhoCanSeeInvis(4); // Here, we make sure it is less then 80% for mages, and less then // 30% for sorcerors or bards. - iNeedToBeBelow = i80; + nNeedToBeBelow = 80; // Use global - if(GlobalWeAreSorcerorBard) iNeedToBeBelow = i30; + if(GlobalWeAreSorcerorBard) nNeedToBeBelow = 30; - if(iPercentWhoSeeInvis <= iNeedToBeBelow + d20()) + if(nPercentWhoSeeInvis <= nNeedToBeBelow + d20()) { // If within d20 of the needed amount, we do cast improved // invisibility. - // Special Assassin Version - if(AI_ActionUseFeatOnObject(FEAT_PRESTIGE_INVISIBILITY_2)) + // Improved Invis - assassin + if(AI_ActionUseSpellLikeFeat(FEAT_PRESTIGE_INVISIBILITY_2, SPELLABILITY_AS_IMPROVED_INVISIBLITY)) { - SetLocalTimer(AI_TIMER_JUST_CAST_INVISIBILITY, f12); + SetLocalTimer(AI_TIMER_JUST_CAST_INVISIBILITY, 12.0); return TRUE; } // Improved Invis. Level 4 (Bard, Mage). 50% consealment + invisibility. - if(AI_ActionCastSpell(SPELL_IMPROVED_INVISIBILITY, SpellEnhSinTar, OBJECT_SELF, i14, FALSE, ItemEnhSinTar, PotionEnh)) + if(AI_ActionCastSpell(SPELL_IMPROVED_INVISIBILITY, OBJECT_SELF, 14, FALSE)) { - SetLocalTimer(AI_TIMER_JUST_CAST_INVISIBILITY, f12); + SetLocalTimer(AI_TIMER_JUST_CAST_INVISIBILITY, 12.0); return TRUE; } // Other invisibilities. - if(iPercentWhoSeeInvis <= iNeedToBeBelow) + if(nPercentWhoSeeInvis <= nNeedToBeBelow) { // Invisibility if(AI_SpellWrapperNormalInvisibilitySpells()) { - SetLocalTimer(AI_TIMER_JUST_CAST_INVISIBILITY, f12); + SetLocalTimer(AI_TIMER_JUST_CAST_INVISIBILITY, 12.0); return TRUE; } } @@ -7128,41 +7118,41 @@ H [Crumble] - Constructs only. // Massive summoning spells // Normally, no...always, these are only owned by intelligent creatures, no // need to random cast or anything. - if(IsFirstRunThrough && GlobalCanSummonSimilarLevel <= i12) + if(bFirstRunThrough && GlobalCanSummonSimilarLevel <= 12) { - // Dragon Knight - Powerful dragon summon that cannot be dispelled. 20 rounds. - if(AI_ActionUseEpicSpell(AI_FEAT_EPIC_SPELL_DRAGON_KNIGHT, SPELL_EPIC_DRAGON_KNIGHT)) + // Dragon Knight - Powerful dragon summon that cannot be dnSpelled. 20 rounds. + if(AI_ActionUseSpellLikeFeat(FEAT_EPIC_SPELL_DRAGON_KNIGHT, SPELL_EPIC_DRAGON_KNIGHT)) { // Set level to 12 - SetAIInteger(AI_LAST_SUMMONED_LEVEL, i12); + SetAIInteger(AI_LAST_SUMMONED_LEVEL, 12); return TRUE; } } - if(IsFirstRunThrough && GlobalCanSummonSimilarLevel <= i11) + if(bFirstRunThrough && GlobalCanSummonSimilarLevel <= 11) { - // Mummy Dust - Powerful summon that cannot be dispelled. 24 Hours. - if(AI_ActionUseEpicSpell(AI_FEAT_EPIC_SPELL_MUMMY_DUST, SPELL_EPIC_MUMMY_DUST)) + // Mummy Dust - Powerful summon that cannot be dnSpelled. 24 Hours. + if(AI_ActionUseSpellLikeFeat(FEAT_EPIC_SPELL_MUMMY_DUST, SPELL_EPIC_MUMMY_DUST)) { // Set level to 11 - SetAIInteger(AI_LAST_SUMMONED_LEVEL, i11); + SetAIInteger(AI_LAST_SUMMONED_LEVEL, 11); return TRUE; } } // This is POWERFUL! - if(IsFirstRunThrough && GlobalCanSummonSimilarLevel <= i10) + if(bFirstRunThrough && GlobalCanSummonSimilarLevel <= 10) { // Black Blade of Disaster. Level 9 (Mage) A powerful greatsword fights. Please note: AI abuses the "concentration" rules for it! - if(AI_ActionCastSummonSpell(SPELL_BLACK_BLADE_OF_DISASTER, i19, i10)) return TRUE; + if(AI_ActionCastSummonSpell(SPELL_BLACK_BLADE_OF_DISASTER, 19, 10)) return TRUE; } // If we are in time stop, or no enemy in 4 m, we will buff our appropriate stat. - // Level 2 spells. GLOBALINTELLIGENCE >= 6 + // Level 2 spells. GlobalIntelligence >= 6 // NOte: CHANGE TO RANDOM ROLL, MORE CHANCE AT INT 10 // Put just above first hostile spells. // - Always cast if we have stoneskin effects. - if((GlobalInTimeStop || GlobalRangeToNearestEnemy > f4 || + if((GlobalInTimeStop || GlobalRangeToNearestEnemy > 4.0 || AI_GetAIHaveSpellsEffect(GlobalHasStoneSkinProtections)) && - !GlobalIntelligence >= i6 && IsFirstRunThrough && + !GlobalIntelligence >= 6 && bFirstRunThrough && !AI_CompareTimeStopStored(SPELL_FOXS_CUNNING, SPELL_OWLS_WISDOM, SPELL_EAGLE_SPLEDOR)) { @@ -7173,9 +7163,9 @@ H [Crumble] - Constructs only. { // Greater first. This provides +2d4 + 1. // foxes cunning :-) - No items, innate. - if(AI_ActionCastSpell(SPELL_GREATER_FOXS_CUNNING, SpellEnhSinTar)) return TRUE; + if(AI_ActionCastSpell(SPELL_GREATER_FOXS_CUNNING)) return TRUE; // Lesser one - but we have items for it. - if(AI_ActionCastSpell(SPELL_FOXS_CUNNING, SpellEnhSinTar, OBJECT_SELF, i12, ItemEnhSinTar, PotionEnh)) return TRUE; + if(AI_ActionCastSpell(SPELL_FOXS_CUNNING, OBJECT_SELF, 12)) return TRUE; } } else if(GlobalOurChosenClass == CLASS_TYPE_DRUID || GlobalOurChosenClass == CLASS_TYPE_CLERIC) @@ -7185,12 +7175,12 @@ H [Crumble] - Constructs only. { // Owls insight is cool - 2x caster level in wisdom = +plenty of DC. // Owls Insight. Level 5 (Druid). - if(AI_ActionCastSpell(AI_SPELL_OWLS_INSIGHT, SpellEnhSinTar, OBJECT_SELF, i15, ItemEnhSinTar, PotionEnh)) return TRUE; + if(AI_ActionCastSpell(AI_SPELL_OWLS_INSIGHT, OBJECT_SELF, 15)) return TRUE; // Greater first. This provides +2d4 + 1. // owls wisdom :-) - if(AI_ActionCastSpell(SPELL_GREATER_OWLS_WISDOM, SpellEnhSinTar)) return TRUE; + if(AI_ActionCastSpell(SPELL_GREATER_OWLS_WISDOM)) return TRUE; // Lesser one - but we have items for it. - if(AI_ActionCastSpell(SPELL_OWLS_WISDOM, SpellEnhSinTar, OBJECT_SELF, i12, ItemEnhSinTar, PotionEnh)) return TRUE; + if(AI_ActionCastSpell(SPELL_OWLS_WISDOM, OBJECT_SELF, 12)) return TRUE; } } else // Monsters probably benifit from this as well. @@ -7200,45 +7190,45 @@ H [Crumble] - Constructs only. { // Greater first. This provides +2d4 + 1. // eagles splendor :-) - if(AI_ActionCastSpell(SPELL_GREATER_EAGLE_SPLENDOR, SpellEnhSinTar)) return TRUE; + if(AI_ActionCastSpell(SPELL_GREATER_EAGLE_SPLENDOR)) return TRUE; // Lesser one - but we have items for it. - if(AI_ActionCastSpell(SPELL_EAGLE_SPLEDOR, SpellEnhSinTar, OBJECT_SELF, i12, ItemEnhSinTar, PotionEnh)) return TRUE; + if(AI_ActionCastSpell(SPELL_EAGLE_SPLEDOR, OBJECT_SELF, 12)) return TRUE; } } } - // Special behaviour: Constructs... + // Special behavnOur: Constructs... // - These are bastards, and have either total immunity to spells or massive // SR. // - GlobalNormalSpellNoEffectLevel will already be set. - if(IsFirstRunThrough && GlobalIntelligence >= i5 && + if(bFirstRunThrough && GlobalIntelligence >= 5 && GlobalSpellTargetRace == CLASS_TYPE_CONSTRUCT) { // These spells go through any ristances (I mean, "Spell Immunity: Level 9 or lower") // Ruin - (Epic) - 35d6 divine damage, fort save for half. - if(AI_ActionUseFeatOnObject(AI_FEAT_EPIC_SPELL_RUIN, GlobalSpellTarget)) return TRUE; + if(AI_ActionUseSpellLikeFeat(FEAT_EPIC_SPELL_RUIN, SPELL_EPIC_RUIN, GlobalSpellTarget)) return TRUE; // Crumble. Level 6 (Druid) - Up to 15d6 damage to a construct. - if(AI_ActionCastSpell(SPELL_CRUMBLE, SpellHostRanged, GlobalSpellTarget, i16, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpell(SPELL_CRUMBLE, GlobalSpellTarget, 16, FALSE)) return TRUE; } // Cast prismatic AC bonus spell - defective force if(!GetHasSpellEffect(AI_SPELLABILITY_PRISMATIC_DEFLECTING_FORCE)) { // Deflecting Force - adds charisma bonus to defeltection AC. - if(AI_ActionCastSpell(AI_SPELLABILITY_PRISMATIC_DEFLECTING_FORCE, SpellProSinTar)) return TRUE; + if(AI_ActionCastSpell(AI_SPELLABILITY_PRISMATIC_DEFLECTING_FORCE)) return TRUE; } // Try a finger/destruction spell, if their fortitude save is really, really low. // Will not use these 2 twice in time stop, as they *should* die instantly - if(GlobalNormalSpellsNoEffectLevel < i7 && IsFirstRunThrough && + if(GlobalNormalSpellsNoEffectLevel < 7 && bFirstRunThrough && GetSpawnInCondition(AI_FLAG_COMBAT_IMPROVED_INSTANT_DEATH_SPELLS, AI_COMBAT_MASTER) && - GlobalSeenSpell && RangeShortValid && + GlobalSeenSpell && bRangeShortValid && !AI_CompareTimeStopStored(SPELL_DESTRUCTION, SPELL_FINGER_OF_DEATH)) { // Check low saves, IE always fails, no immunities and no mantals. - if((GlobalSpellTargetFort + i20) <= (GlobalSpellBaseSaveDC + i7) && + if((GlobalSpellTargetFort + 20) <= (GlobalSpellBaseSaveDC + 7) && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && !AI_GetSpellTargetImmunity(GlobalImmunityDeath) && !AI_GetSpellTargetImmunity(GlobalImmunityMantalProtection)) @@ -7246,61 +7236,61 @@ H [Crumble] - Constructs only. // Note: No items, because it will be a much lower save. // Destruction, level 7 (Cleric). Fort (Death) for Death if fail, or 10d6 damage if pass. - if(AI_ActionCastSpell(SPELL_DESTRUCTION, SpellHostRanged, GlobalSpellTarget, i17)) return TRUE; + if(AI_ActionCastSpell(SPELL_DESTRUCTION, GlobalSpellTarget, 17)) return TRUE; // Finger of Death. Leve 7 (Mage). Fort (Death) for death if fail, or d6(3) + nCasterLvl damage if pass. - if(AI_ActionCastSpell(SPELL_FINGER_OF_DEATH, SpellHostRanged, GlobalSpellTarget, i17)) return TRUE; + if(AI_ActionCastSpell(SPELL_FINGER_OF_DEATH, GlobalSpellTarget, 17)) return TRUE; } } // Now will cast mantal if not got one and nearest enemy is a spellcaster... - if(GlobalMeleeAttackers <= i1 /*We won't cast it with melee attackers - cast phisicals first*/ && - !GlobalInTimeStop && GlobalIntelligence >= i7 && IsFirstRunThrough && + if(GlobalMeleeAttackers <= 1 /*We won't cast it with melee attackers - cast phisicals first*/ && + !GlobalInTimeStop && GlobalIntelligence >= 7 && bFirstRunThrough && !AI_GetAIHaveSpellsEffect(GlobalHasMantalProtections) && /* Check for mage classes...spell target only */ - (GetLevelByClass(CLASS_TYPE_WIZARD, GlobalSpellTarget) >= GlobalSpellTargetHitDice/i3) && - (GetLevelByClass(CLASS_TYPE_SORCERER, GlobalSpellTarget) >= GlobalSpellTargetHitDice/i3)) + (GetLevelByClass(CLASS_TYPE_WIZARD, GlobalSpellTarget) >= GlobalSpellTargetHitDice/3) && + (GetLevelByClass(CLASS_TYPE_SORCERER, GlobalSpellTarget) >= GlobalSpellTargetHitDice/3)) { // Cast mantals, or spell resistance...or Protection from spells. if(AI_SpellWrapperMantalProtections()) return TRUE; // Protection from spells. Level 7 (Mage), for +8 on all saves (Area effect too!) - if(AI_ActionCastSpell(SPELL_PROTECTION_FROM_SPELLS, SpellProAre, OBJECT_SELF, i17, FALSE, ItemProAre)) return TRUE; + if(AI_ActionCastSpell(SPELL_PROTECTION_FROM_SPELLS, OBJECT_SELF, 17, FALSE)) return TRUE; // Spell resistance. Level 5 (Cleric/Druid) 12 + Caster level (no limit) in spell resistance. - if(AI_ActionCastSpell(SPELL_SPELL_RESISTANCE, SpellProSinTar, OBJECT_SELF, i15, FALSE, ItemProSinTar, PotionPro)) return TRUE; + if(AI_ActionCastSpell(SPELL_SPELL_RESISTANCE, OBJECT_SELF, 15, FALSE)) return TRUE; } - if(IsFirstRunThrough) + if(bFirstRunThrough) { // Haste for allies // - 60% chance of casting. More below somewhere (near stoneskin - if(AI_ActionCastAllyBuffSpell(f6, i60, SPELL_MASS_HASTE, SPELL_HASTE)) return TRUE; + if(AI_ActionCastAllyBuffSpell(6.0, 60, SPELL_MASS_HASTE, SPELL_HASTE)) return TRUE; // Ultravision for allies // - 90% chance of casting. // - Only cast if a valid enemy in darkness is near - if(GetIsObjectValid(GetNearestCreature(CREATURE_TYPE_HAS_SPELL_EFFECT, SPELL_DARKVISION, OBJECT_SELF, i1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD))) + if(GetIsObjectValid(GetNearestCreature(CREATURE_TYPE_HAS_SPELL_EFFECT, SPELL_DARKVISION, OBJECT_SELF, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD))) { // Darkvision (Ultravision) but not trueseeing, is cast. - if(AI_ActionCastAllyBuffSpell(f8, i90, SPELL_DARKVISION, iM1, iM1, iM1, SPELL_TRUE_SEEING)) return TRUE; + if(AI_ActionCastAllyBuffSpell(8.0, 90, SPELL_DARKVISION, SPELL_TRUE_SEEING)) return TRUE; } } // Epic killing spells. Hellball is very important to fire off! // - We fire this off at the futhest target in 40M // Futhest one away. - if(IsFirstRunThrough && GlobalSeenSpell) + if(bFirstRunThrough && GlobalSeenSpell) { // Hellball. (Epic) Long range AOE - 10d6 sonic, acid, fire and lightning damage to all in area. Reflex only halves. // We just use spell target. Tough luck, we probably will be in the AOE // whatever target we want! - if(AI_ActionUseEpicSpell(AI_FEAT_EPIC_SPELL_HELLBALL, SPELL_EPIC_HELLBALL, GlobalSpellTarget)) return TRUE; + if(AI_ActionUseSpellLikeFeat(FEAT_EPIC_SPELL_HELLBALL, SPELL_EPIC_HELLBALL, GlobalSpellTarget)) return TRUE; // Ruin - a lot of damage, no SR, and only a half save thing for damage - if(AI_ActionUseEpicSpell(AI_FEAT_EPIC_SPELL_RUIN, SPELL_EPIC_RUIN, GlobalSpellTarget)) return TRUE; + if(AI_ActionUseSpellLikeFeat(FEAT_EPIC_SPELL_RUIN, SPELL_EPIC_RUIN, GlobalSpellTarget)) return TRUE; } // These 3 will not be wasted on mantals. - if(IsFirstRunThrough && GlobalNormalSpellsNoEffectLevel < i9 &&// PW kill is level 9 + if(bFirstRunThrough && GlobalNormalSpellsNoEffectLevel < 9 &&// PW kill is level 9 !AI_GetSpellTargetImmunity(GlobalImmunityMantalProtection) && !AI_CompareTimeStopStored(SPELL_CLOUDKILL, SPELL_POWER_WORD_KILL, SPELL_CIRCLE_OF_DEATH)) { @@ -7314,45 +7304,45 @@ H [Crumble] - Constructs only. // Cloudkill here - if average HD is < 7 // Random is < 7, always if under 4 // Damage, slow, long range. Also, AOE :-) - if(RangeLongValid && (GlobalAverageEnemyHD < i4) || - ((GlobalAverageEnemyHD < i7) && (d10() < i4)) && - GlobalNormalSpellsNoEffectLevel < i5) + if(bRangeLongValid && (GlobalAverageEnemyHD < 4) || + ((GlobalAverageEnemyHD < 7) && (d10() < 4)) && + GlobalNormalSpellsNoEffectLevel < 5) { // Cloud Kill. Level 5 (Mage). Kills if under level 7, else acid damage. - if(AI_ActionCastSpell(SPELL_CLOUDKILL, SpellHostAreaInd, GlobalSpellTarget, i15, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpell(SPELL_CLOUDKILL, GlobalSpellTarget, 15, TRUE)) return TRUE; } // Power Word: Kill // If improved, will check HP, else just casts it. - if(RangeShortValid && GlobalSpellTargetCurrentHitPoints < i100) + if(bRangeShortValid && GlobalSpellTargetCurrentHitPoints < 100) { // Power Word Kill. Level 9 (Mage). If target has less then 100HP, dies. - if(AI_ActionCastSpell(SPELL_POWER_WORD_KILL, SpellHostAreaInd, GlobalSpellTarget, i19, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpell(SPELL_POWER_WORD_KILL, GlobalSpellTarget, 19, TRUE)) return TRUE; } } // Circle of Death // CONDITION: Average enemy party hd less than 10 // This spell only effects level 1-9 people. Good cleaner for lower monsters! // Meduim ranged spell. - if(RangeMediumValid && GlobalAverageEnemyHD <= i9 && - GlobalNormalSpellsNoEffectLevel < i6) + if(bRangeMediumValid && GlobalAverageEnemyHD <= 9 && + GlobalNormalSpellsNoEffectLevel < 6) { // Circle of death. Level 6 (Mage). Medium ranged, Large AOE, kills 10HD or less people (to d4(casterlevel)). - if(AI_ActionCastSpell(SPELL_CIRCLE_OF_DEATH, SpellHostAreaDis, GlobalSpellTarget, i16, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpell(SPELL_CIRCLE_OF_DEATH, GlobalSpellTarget, 16, TRUE)) return TRUE; } } - if(IsFirstRunThrough) + if(bFirstRunThrough) { // Physical Damage Protections (Self) // Stoneskins, (Greater, normal) + Premonition provide instant damage reduction. - if(AI_SpellWrapperPhisicalProtections(iLowestSpellLevel)) return TRUE; + if(AI_SpellWrapperPhisicalProtections(nLowestSpellLevel)) return TRUE; } // Do not check spell resistance (GlobalNormalSpellsNoEffectLevel) here. // We only use pulses 80% of the time. - if(RangeTouchValid && !GlobalInTimeStop && - GlobalSpellTargetRange < fTouchRange && d10() <= i8) + if(bRangeTouchValid && !GlobalInTimeStop && + GlobalSpellTargetRange < fTouchRange && d10() <= 8) { /* These are the pulses. Not much I can be bothered to check for. All good stuff! 281 | Pulse_Drown - None Constructs, Undeads, Elementals DIE if fail a fort check, DC: 20. @@ -7371,130 +7361,117 @@ H [Crumble] - Constructs only. 294 | Pulse_Ability_Drain_Dexterity - Large. -(HD/5) DEX, if fail fort save VS: 10 + HD. 295 | Pulse_Ability_Drain_Strength - Large. -(HD/5) STR, if fail fort save VS: 10 + HD. 296 | Pulse_Ability_Drain_Wisdom - Large. -(HD/5) WIS, if fail fort save VS: 10 + HD. - 297 | Pulse_Poison - Varying Poison instantly applied. Check nw_s1_pulspois.nss, and poison.2da files. + 297 | Pulse_Poison - Varying Poison instantly applied. Check nw_"1"_pulspois.nss, and poison.2da files. 298 | Pulse_Disease - Varying Save. See diseases.2da, and it is based on the race of the caster, below are the diseases applied: Vermin = Vermin Madness. Undead = Filth Fever. Outsider = Demon Fever. Magical Beast = Soldier Shakes. Aberration = Blinding Sickness. ANYTHING ELSE = Mindfire. */ - for(iCnt = SPELLABILITY_PULSE_DROWN/*281*/; iCnt <= SPELLABILITY_PULSE_DISEASE/*289*/; iCnt++) + for(nCnt = SPELLABILITY_PULSE_DROWN/*281*/; nCnt <= SPELLABILITY_PULSE_DISEASE/*289*/; nCnt++) { // All innate, so no matter about talents really. - if(AI_ActionCastSpell(iCnt)) return TRUE; + if(AI_ActionCastSpell(nCnt)) return TRUE; } } // Then harm/heal. (Needs 20 HP, and be challenging to us). - if((GlobalAverageEnemyHD >= (GlobalOurHitDice - i5)) && - GlobalSpellTargetCurrentHitPoints > i20 && RangeTouchValid && + if((GlobalAverageEnemyHD >= (GlobalOurHitDice - 5)) && + GlobalSpellTargetCurrentHitPoints > 20 && bRangeTouchValid && !AI_CompareTimeStopStored(SPELL_HARM, SPELL_MASS_HEAL, SPELL_HEAL) && - GlobalNormalSpellsNoEffectLevel < i8)// Mass heal = 8. + GlobalNormalSpellsNoEffectLevel < 8)// Mass heal = 8. { if(GlobalSeenSpell && GlobalSpellTargetRace != RACIAL_TYPE_UNDEAD && GlobalSpellTargetRace != RACIAL_TYPE_CONSTRUCT && GlobalSpellTargetRace != RACIAL_TYPE_INVALID) { // If we are undead, we make sure we leave at least 1 for our own healing. - if(GlobalNormalSpellsNoEffectLevel < i6 && - (GlobalOurRace != RACIAL_TYPE_UNDEAD || GetHasSpell(SPELL_HARM) >= i2)) + if(GlobalNormalSpellsNoEffectLevel < 6 && + (GetRacialType(OBJECT_SELF) != RACIAL_TYPE_UNDEAD || + GetHasSpell(SPELL_HARM) >= 2)) { // Harm // CONDITION: 6+ hit dice and NOT undead! :) Also checks HP // Harm Level 6 (Cleric) 7 (Druid) Makes the target go down to 1d4HP (or heals undead as heal) - if(AI_ActionCastSpell(SPELL_HARM, SpellHostTouch, GlobalSpellTarget, i16, FALSE, ItemHostTouch)) return TRUE; + if(AI_ActionCastSpell(SPELL_HARM, GlobalSpellTarget, 16, FALSE)) return TRUE; } } // (Mass) Heal (used as Harm for undead) // CONDITION: Undead at 4+ hd. Never casts twice in time stop, and not over 20 HP. else if(GlobalSpellTargetRace == RACIAL_TYPE_UNDEAD && - GlobalIntelligence >= i7) + GlobalIntelligence >= 7) { // Really, talent 4, heal area effect, no items are set in this though. // Mass Heal. Level 8 (Cleric) 9 (Druid) mass "heal" damage/healing. - if(AI_ActionCastSpell(SPELL_MASS_HEAL, FALSE, GlobalSpellTarget, i18, TRUE)) return TRUE; + if(AI_ActionCastSpell(SPELL_MASS_HEAL, GlobalSpellTarget, 18, TRUE)) return TRUE; // Never use last 2 heals for harming. Level 6 (Cleric) 7 (Druid) // - 1.3, changed to 3+ only, because, basically, healing self will - // probably be better. Undead + Constructs ignore this and use all of them. - if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < i6 && - (GetHasSpell(SPELL_HEAL) >= i3 || GlobalOurRace == RACIAL_TYPE_UNDEAD || - GlobalOurRace != RACIAL_TYPE_CONSTRUCT)) + // probably be better. Undead and constructs also keep it, it must + // be for healing allies. + if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < 6 && + GetHasSpell(SPELL_HEAL) >= 3) { // Heal. Level 6 (Cleric) 7 (Druid). For undead: As harm, else full healing. - if(AI_ActionCastSpell(SPELL_HEAL, FALSE, GlobalSpellTarget, i16)) return TRUE; + if(AI_ActionCastSpell(SPELL_HEAL, GlobalSpellTarget, 16)) return TRUE; } } } - // Power Word: Stun + // Power Word: Stun. Special "knock out them" spell. // Is not immune to mind spell (I think this is a valid check) and not already stunned. // Really, if under < 151 HP to be affected // Wierdly, this is considered a "Area effect" spell. Nope - jsut a VERY nice normal one. (I like it!) // - We can cast this later. Here, we only cast if low amount of enemies :-D - if(GlobalSpellTargetCurrentHitPoints <= i150 && - GlobalNormalSpellsNoEffectLevel < i7 && - GlobalTotalSeenHeardEnemies < i3 && GlobalAverageEnemyHD > i10 && - GlobalSeenSpell && RangeTouchValid && + if(GlobalSpellTargetCurrentHitPoints <= 150 && + GlobalNormalSpellsNoEffectLevel < 7 && + GlobalTotalSeenHeardEnemies < 3 && GlobalAverageEnemyHD > 10 && + GlobalSeenSpell && bRangeTouchValid && !AI_GetSpellTargetImmunity(GlobalImmunityStun) && !AI_GetSpellTargetImmunity(GlobalImmunityMind) && !AI_CompareTimeStopStored(SPELL_POWER_WORD_STUN)) { // Power Word Stun. Level 7 (Wizard). Stun duration based on HP. - if(AI_ActionCastSpell(SPELL_POWER_WORD_STUN, SpellHostAreaInd, GlobalSpellTarget, i17, FALSE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpell(SPELL_POWER_WORD_STUN, GlobalSpellTarget, 17, FALSE)) return TRUE; } // Elemental shield here, if over 0 melee attackers (and 30% chace) or // over 1-4 attackers (level based). Doesn't double cast, and not more then 1 at once. - if(IsFirstRunThrough && + if(bFirstRunThrough && // - Checks if we have the effects or not in a second - ((GlobalMeleeAttackers > (GlobalOurHitDice / i4) || - (GlobalMeleeAttackers > i0 && d10() > i6))) && + ((GlobalMeleeAttackers > (GlobalOurHitDice / 4) || + (GlobalMeleeAttackers > 0 && d10() > 6))) && !AI_CompareTimeStopStored(SPELL_ELEMENTAL_SHIELD, SPELL_WOUNDING_WHISPERS, SPELL_DEATH_ARMOR, SPELL_MESTILS_ACID_SHEATH)) { - if(AI_SpellWrapperShieldProtections(iLowestSpellLevel)) return TRUE; + if(AI_SpellWrapperShieldProtections(nLowestSpellLevel)) return TRUE; } // Dispel Good spells on the enemy. // - Dispel Level 5 here. // Basically, level 5 spells are mantals and spell-stoppers, or an alful // lot of lower level spells. - if(RangeMediumValid && !GlobalInTimeStop)// All medium spells. - { - // Dispel number need to be 5 for breach - if(GlobalDispelTargetHighestBreach >= i5) - { - // Wrapers Greater and Lesser Breach. - if(AI_ActionCastBreach()) return TRUE; - } - // Dispel >= 5 - if(GlobalDispelTargetHighestDispel >= i5) - { - // Wrappers the dispel spells - if(AI_ActionCastDispel()) return TRUE; - } - } + if(AI_ActionAttemptDispel(5, bRangeMediumValid)) return TRUE; // Consealment Protections // We do displacement then blindness/deafness. We only attempt blindness/deafness // if we are not a sorceror/bard mind you. - if(IsFirstRunThrough && !GlobalInTimeStop && // No Consealment in time stop. - GetObjectSeen(OBJECT_SELF, GlobalSpellTarget) && + if(bFirstRunThrough && !GlobalInTimeStop && // No Consealment in time stop. + GlobalSeenSpell && !AI_GetAIHaveEffect(GlobalEffectInvisible) && !AI_GetAIHaveSpellsEffect(GlobalHasConsealmentSpells)) { // Imp. Invis and displacement... - if(AI_SpellWrapperConsealmentEnhancements(OBJECT_SELF, iLowestSpellLevel)) return TRUE; + if(AI_SpellWrapperConsealmentEnhancements(OBJECT_SELF, nLowestSpellLevel)) return TRUE; // Cast darkness on any enemy in range, if we have ultravision (or its // effects) // Need range check, with SRA, of course - if(RangeLongValid && (AI_GetAIHaveEffect(GlobalEffectUltravision) || + if(bRangeLongValid && (AI_GetAIHaveEffect(GlobalEffectUltravision) || AI_GetAIHaveEffect(GlobalEffectTrueSeeing) || GetHasSpell(SPELL_DARKVISION) || GetHasSpell(SPELL_TRUE_SEEING))) { // Cast at nearest without darkness! - oAOE = GetNearestCreature(CREATURE_TYPE_DOES_NOT_HAVE_SPELL_EFFECT, SPELL_DARKVISION, OBJECT_SELF, i1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN); + oAOE = GetNearestCreature(CREATURE_TYPE_DOES_NOT_HAVE_SPELL_EFFECT, SPELL_DARKVISION, OBJECT_SELF, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN); if(GetIsObjectValid(oAOE) && !GetHasSpellEffect(SPELL_TRUE_SEEING, oAOE) && !GetHasSpellEffect(SPELL_DARKVISION, oAOE)) { @@ -7504,97 +7481,97 @@ H [Crumble] - Constructs only. } // Blindness/deafness. No casting in time stop is simpler. - if(RangeMediumValid && GlobalNormalSpellsNoEffectLevel < i8 && + if(bRangeMediumValid && GlobalNormalSpellsNoEffectLevel < 8 && !AI_GetSpellTargetImmunity(GlobalImmunityBlindDeaf) && !GlobalWeAreSorcerorBard && - !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, i8)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, 8)) { // Mass Blindness and Deafness. Level 8 (Mage) AOE fort save, enemies only, who save or are blinded and deafened. - if(AI_ActionCastSpell(SPELL_MASS_BLINDNESS_AND_DEAFNESS, SpellHostAreaDis, GlobalSpellTarget, i18, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpell(SPELL_MASS_BLINDNESS_AND_DEAFNESS, GlobalSpellTarget, 18, TRUE)) return TRUE; } } // Ally spells. A great variety that we cast above. - if(IsFirstRunThrough) + if(bFirstRunThrough) { // Haste again - 90% chance - if(AI_ActionCastAllyBuffSpell(f6, i90, SPELL_MASS_HASTE, SPELL_HASTE)) return TRUE; + if(AI_ActionCastAllyBuffSpell(6.0, 90, SPELL_MASS_HASTE, SPELL_HASTE)) return TRUE; // Cast phisical stoneskins on allies - 80% chance, as it is quite good. - if(AI_ActionCastAllyBuffSpell(f6, i80, SPELL_GREATER_STONESKIN, SPELL_STONESKIN)) return TRUE; + if(AI_ActionCastAllyBuffSpell(6.0, 80, SPELL_GREATER_STONESKIN, SPELL_STONESKIN)) return TRUE; // Consealment spells - if(AI_ActionCastAllyBuffSpell(f6, i60, SPELL_IMPROVED_INVISIBILITY, SPELL_DISPLACEMENT)) return TRUE; + if(AI_ActionCastAllyBuffSpell(6.0, 60, SPELL_IMPROVED_INVISIBILITY, SPELL_DISPLACEMENT)) return TRUE; } //Gate //CONDITION: Protection from Evil active on self // Balors rock, literally! If not, I kill dem all!! >:-D - if(IsFirstRunThrough && GlobalCanSummonSimilarLevel <= i10 && - SpellAllies && AI_GetAIHaveSpellsEffect(GlobalHasProtectionEvilSpell)) + if(bFirstRunThrough && GlobalCanSummonSimilarLevel <= 10 && + AI_GetAIHaveSpellsEffect(GlobalHasProtectionEvilSpell)) { // Gate. Level 9 (Mage/Innate). Summons a balor, who would normally attack caster if not protected from evil, else powerful summon - if(AI_ActionCastSummonSpell(SPELL_GATE, i19, i10)) return TRUE; + if(AI_ActionCastSummonSpell(SPELL_GATE, 19, 10)) return TRUE; } //Protection from Evil / Magic Circle Against Evil // ... in preparation for Gate! - if(IsFirstRunThrough &&GetHasSpell(SPELL_GATE) && + if(bFirstRunThrough && GetHasSpell(SPELL_GATE) && !AI_GetAIHaveSpellsEffect(GlobalHasProtectionEvilSpell)) { // Magic Circle against Alignment. Level 3 (Mage/Cleric/Bard/Paladin/Innate). +2 AC, mind spell immunity VS them. - if(AI_ActionCastSubSpell(SPELL_MAGIC_CIRCLE_AGAINST_EVIL, SpellEnhAre, OBJECT_SELF, i13, FALSE, ItemEnhAre)) return TRUE; + if(AI_ActionCastSpell(SPELL_MAGIC_CIRCLE_AGAINST_EVIL, OBJECT_SELF, 13, FALSE, TRUE)) return TRUE; // Protection From Evil. Level 1(Mage/Cleric/Bard/Paladin/Innate). +4 AC, mind spell immunity VS them. - if(AI_ActionCastSubSpell(SPELL_PROTECTION_FROM_EVIL, SpellProSinTar, OBJECT_SELF, i11, FALSE, ItemProSelf, PotionPro)) return TRUE; + if(AI_ActionCastSpell(SPELL_PROTECTION_FROM_EVIL, OBJECT_SELF, 11, FALSE, TRUE)) return TRUE; } // None for allies. Won't bother (unless it is a problem!). // - If adding, we will get the nearest without the spells effects. // GlobalCanSummonSimilarLevel can be 1-12. (10 is elemental swarm, balor) (11, 12 epic) - if(IsFirstRunThrough && GlobalCanSummonSimilarLevel <= i9) + if(bFirstRunThrough && GlobalCanSummonSimilarLevel <= 9) { // Elemental swarm. Level 9 (Druid) Never replaced until no summon left - summons consecutive 4 huge elementals - if(AI_ActionCastSummonSpell(SPELL_ELEMENTAL_SWARM, i19, i10)) return TRUE; + if(AI_ActionCastSummonSpell(SPELL_ELEMENTAL_SWARM, 19, 10)) return TRUE; // Summon an eldar elemental. - if(AI_ActionCastSummonSpell(SPELL_SUMMON_CREATURE_IX, i19, i9)) return TRUE; + if(AI_ActionCastSummonSpell(SPELL_SUMMON_CREATURE_IX, 19, 9)) return TRUE; // No-concentration summoned creatures. - if(AI_ActionCastSummonSpell(AI_SPELLABILITY_SUMMON_BAATEZU, FALSE, i9)) return TRUE; - if(AI_ActionCastSummonSpell(SPELLABILITY_SUMMON_TANARRI, FALSE, i9)) return TRUE; - if(AI_ActionCastSummonSpell(SPELLABILITY_SUMMON_SLAAD, FALSE, i9)) return TRUE; - if(AI_ActionCastSummonSpell(SPELLABILITY_SUMMON_CELESTIAL, FALSE, i9)) return TRUE; - if(AI_ActionCastSummonSpell(SPELLABILITY_SUMMON_MEPHIT, FALSE, i9)) return TRUE; - if(AI_ActionCastSummonSpell(SPELLABILITY_NEGATIVE_PLANE_AVATAR, FALSE, i9)) return TRUE; + if(AI_ActionCastSummonSpell(AI_SPELLABILITY_SUMMON_BAATEZU, FALSE, 9)) return TRUE; + if(AI_ActionCastSummonSpell(SPELLABILITY_SUMMON_TANARRI, FALSE, 9)) return TRUE; + if(AI_ActionCastSummonSpell(SPELLABILITY_SUMMON_SLAAD, FALSE, 9)) return TRUE; + if(AI_ActionCastSummonSpell(SPELLABILITY_SUMMON_CELESTIAL, FALSE, 9)) return TRUE; + if(AI_ActionCastSummonSpell(SPELLABILITY_SUMMON_MEPHIT, FALSE, 9)) return TRUE; + if(AI_ActionCastSummonSpell(SPELLABILITY_NEGATIVE_PLANE_AVATAR, FALSE, 9)) return TRUE; } // Dominate spells // - Dominate monster is level 9. Others are worth casting if valid. // Needs to not be immune, and be of right race for DOM PERSON // No time stop, and a valid will save to even attempt. - if(!GlobalInTimeStop && GlobalSeenSpell && RangeMediumValid && + if(!GlobalInTimeStop && GlobalSeenSpell && bRangeMediumValid && !AI_GetSpellTargetImmunity(GlobalImmunityMind) && !AI_GetSpellTargetImmunity(GlobalImmunityDomination) && - (GlobalOurHitDice - GlobalAverageEnemyHD) <= i8) + (GlobalOurHitDice - GlobalAverageEnemyHD) <= 8) { // Will save VS mind spells. - if(GlobalNormalSpellsNoEffectLevel < i9 && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i9)) + if(GlobalNormalSpellsNoEffectLevel < 9 && + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 9)) { // Dominate Monster. Level 9 (Mage) Dominates (VS. Mind will save) ANYTHING! - if(AI_ActionCastSpell(SPELL_DOMINATE_MONSTER, SpellHostRanged, GlobalSpellTarget, i19, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpell(SPELL_DOMINATE_MONSTER, GlobalSpellTarget, 19, FALSE)) return TRUE; - if(GlobalNormalSpellsNoEffectLevel < i5 && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i5)) + if(GlobalNormalSpellsNoEffectLevel < 5 && + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 5)) { // Dominate person if(!GetIsPlayableRacialType(GlobalSpellTarget)) { // Dominate Person. Level 5 (Mage). Only affects PC races. Dominate on failed will. - if(AI_ActionCastSpell(SPELL_DOMINATE_PERSON, SpellHostRanged, GlobalSpellTarget, i15, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpell(SPELL_DOMINATE_PERSON, GlobalSpellTarget, 15, FALSE)) return TRUE; } // Mass charm. sorcerors/bards have better things (20% casting chance) - if(!GlobalWeAreSorcerorBard || d10() <= i2) + if(!GlobalWeAreSorcerorBard || d10() <= 2) { // For mass charm, we don't bother if they don't have a decent chance to fail (ues as level 5 spell for save DC) // Mass Charm. Level 8 (Mage) 1 Round/2caster levels of charm. Affects PC races only + humanoids. - if(AI_ActionCastSpell(SPELL_MASS_CHARM, SpellHostAreaDis, GlobalSpellTarget, i18, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpell(SPELL_MASS_CHARM, GlobalSpellTarget, 18, TRUE)) return TRUE; } } } @@ -7604,21 +7581,21 @@ H [Crumble] - Constructs only. // - CONDITION: Enemies less than 5 levels below me (powerful enemies) // - CONDITION 2: At least 1 ally // - We cast this lower down if we don't cast it here. - if(IsFirstRunThrough && - (((GlobalOurHitDice - GlobalAverageEnemyHD) <= i5 && - GlobalValidSeenAlly && GlobalRangeToAlly < f5) || - ((GlobalOurHitDice - GlobalAverageEnemyHD) <= i10))) + if(bFirstRunThrough && + (((GlobalOurHitDice - GlobalAverageEnemyHD) <= 5 && + GlobalValidSeenAlly && GlobalRangeToAlly < 5.0) || + ((GlobalOurHitDice - GlobalAverageEnemyHD) <= 10))) { - if(AI_ActionCastSpell(SPELL_PROTECTION_FROM_SPELLS, SpellProAre, OBJECT_SELF, i17, FALSE, ItemProAre)) return TRUE; + if(AI_ActionCastSpell(SPELL_PROTECTION_FROM_SPELLS, OBJECT_SELF, 17, FALSE)) return TRUE; } //Mantle Protections //CONDITION: Enemies less than 5 levels below me (powerful enemies) // Will chance casting these anyway, if no melee attackers, and the enemy has a valid talent. // Yes, talents include items...ahh well. - if(IsFirstRunThrough && ((GlobalOurHitDice - GlobalAverageEnemyHD) <= i5)) + if(bFirstRunThrough && ((GlobalOurHitDice - GlobalAverageEnemyHD) <= 5)) { - if(AI_SpellWrapperMantalProtections(iLowestSpellLevel)) return TRUE; + if(AI_SpellWrapperMantalProtections(nLowestSpellLevel)) return TRUE; } // All these are short-ranged death! @@ -7636,7 +7613,7 @@ H [Crumble] - Constructs only. // - Meteor Storm is like a huge fireball based on the caster, 20d6 damage. // Single target spells first check - if(SingleSpellsFirst && GlobalNormalSpellsNoEffectLevel < i9) + if(bSingleSpellsFirst && GlobalNormalSpellsNoEffectLevel < 9) { // Crushing hand is indefinatly better, but depends...I think energy drain // has its merits of being permament! :-D @@ -7649,77 +7626,74 @@ H [Crumble] - Constructs only. // 70% chance of Crushing Hand. // We try and not cast it twice on the same target (for a starter, wasting spells) - if(RangeLongValid && !GetHasSpellEffect(SPELL_BIGBYS_CRUSHING_HAND, GlobalSpellTarget)) + if(bRangeLongValid && !GetHasSpellEffect(SPELL_BIGBYS_CRUSHING_HAND, GlobalSpellTarget)) { // Bigby's Crushing Hand. Level 9 (Mage). 2d6 + 12 damage/round. - if(AI_ActionCastSpellRandom(SPELL_BIGBYS_CRUSHING_HAND, SpellHostRanged, i60, GlobalSpellTarget, i19, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_BIGBYS_CRUSHING_HAND, 60, GlobalSpellTarget, 19, FALSE)) return TRUE; } - if(RangeShortValid && GlobalSpellTargetRace != RACIAL_TYPE_UNDEAD && + if(bRangeShortValid && GlobalSpellTargetRace != RACIAL_TYPE_UNDEAD && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, i9)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, 9)) { // 40% chance of energy drain, as we think single target spells are better. // Energy Drain. Level 9 (Mage). 2d4 negative levels! -BAB, Saves, Stats! :-) - if(AI_ActionCastSpellRandom(SPELL_ENERGY_DRAIN, SpellHostRanged, i40, GlobalSpellTarget, i19, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_ENERGY_DRAIN, 40, GlobalSpellTarget, 19, FALSE)) return TRUE; } // Single spell override backup casting - if(SingleSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; + if(bSingleSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; } // AOE targets. Most...but not all...are short-range spells. - if(RangeShortValid) // No GlobalNormalSpellsNoEffectLevel for this. AOE spells may affect someone who is not immune! + if(bRangeShortValid) // No GlobalNormalSpellsNoEffectLevel for this. AOE spells may affect someone who is not immune! { // Storm - a very good AOE spell. May as well use here! // AOE is 10M across. // - May add in elemental protections check. // 40% chance (especially as it is only a clerical spell) - if(!GlobalInTimeStop && GlobalSpellTargetRange < f6) + if(!GlobalInTimeStop && GlobalSpellTargetRange < 6.0) { - if(AI_ActionCastSpellRandom(SPELL_STORM_OF_VENGEANCE, SpellHostAreaDis, i40, OBJECT_SELF, i19, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_STORM_OF_VENGEANCE, 40, OBJECT_SELF, 19, TRUE)) return TRUE; } // Implosion - great spell! Instant death on a +3 save (!). Short range. - if(SpellHostAreaInd && (GetHasSpell(SPELL_IMPLOSION) || - ItemHostAreaInd == SPELL_IMPLOSION)) + if(GetHasSpell(SPELL_IMPLOSION)) { // Its save is at 9 + 3 = 12 DC. Death save, and can kill allies not in PvP // - Note that because we check natural "globes" in this, the level is set to 9. - oAOE = AI_GetBestAreaSpellTarget(fShortRange, RADIUS_SIZE_MEDIUM, i9, SAVING_THROW_FORT, SHAPE_SPHERE, GlobalFriendlyFireFriendly, TRUE); + oAOE = AI_GetBestAreaSpellTarget(fShortRange, RADIUS_SIZE_MEDIUM, 9, SAVING_THROW_FORT, SHAPE_SPHERE, GlobalFriendlyFireFriendly, TRUE); // If valid, 40% chance of casting this one before others. if(GetIsObjectValid(oAOE)) { // Implosion. Level 9 (Cleric). Instant death at +3 save. Note: Medium radius (others are collosal) - if(AI_ActionCastSpellRandom(SPELL_IMPLOSION, SpellHostAreaInd, i30, oAOE, i19, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_IMPLOSION, 30, oAOE, 19, TRUE)) return TRUE; } } // Wail of the Banshee // Fort save, else death, and it never affects us, but can kill allies. - if(SpellHostAreaDis && (GetHasSpell(SPELL_WAIL_OF_THE_BANSHEE) || - ItemHostAreaDis == SPELL_WAIL_OF_THE_BANSHEE)) + if(GetHasSpell(SPELL_WAIL_OF_THE_BANSHEE)) { // Collosal range, fortitude, necromancy and death saves. - oAOE = AI_GetBestAreaSpellTarget(fShortRange, RADIUS_SIZE_COLOSSAL, i9, SAVING_THROW_FORT, SHAPE_SPHERE, GlobalFriendlyFireFriendly, TRUE, TRUE); + oAOE = AI_GetBestAreaSpellTarget(fShortRange, RADIUS_SIZE_COLOSSAL, 9, SAVING_THROW_FORT, SHAPE_SPHERE, GlobalFriendlyFireFriendly, TRUE, TRUE); // If valid, 40% of firing. if(GetIsObjectValid(oAOE)) { // Wail of the Banshee. Level 9 (Mage/Innate). Caster cries out, kills everything that cannot save in area affected. - if(AI_ActionCastSpellRandom(SPELL_WAIL_OF_THE_BANSHEE, SpellHostAreaDis, i30, oAOE, i19, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_WAIL_OF_THE_BANSHEE, 30, oAOE, 19, TRUE)) return TRUE; } } // Weird - item immunity fear? Need to test // Never affects allies. Will save type - if the will is always // saved, it does nothing at all. - if(SpellHostAreaDis && (GetHasSpell(SPELL_WEIRD) || - ItemHostAreaDis == SPELL_WEIRD)) + if(GetHasSpell(SPELL_WEIRD)) { // Get AOE object - this is a small (8M) range, collosal size, doesn't affect allies. - oAOE = AI_GetBestAreaSpellTarget(fShortRange, RADIUS_SIZE_COLOSSAL, i9, SAVING_THROW_WILL); + oAOE = AI_GetBestAreaSpellTarget(fShortRange, RADIUS_SIZE_COLOSSAL, 9, SAVING_THROW_WILL); // Is it valid? 40% chance of casting. if(GetIsObjectValid(oAOE)) { // Wierd. Level 9 (Wizard/Innate). 2 saves (will/fort) against death. Doesn't kill allies! (Illusion) - if(AI_ActionCastSpellRandom(SPELL_WEIRD, SpellHostAreaDis, i30, oAOE, i19, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_WEIRD, 30, oAOE, 19, TRUE)) return TRUE; } } //Meteor Swarm @@ -7727,35 +7701,35 @@ H [Crumble] - Constructs only. // Changed to 10M ... the collosal sized actially used (on self) // But only if the enemy is. Removed enemy fire, for now. // 40% chance. - if(GlobalSpellTargetRange < f5) + if(GlobalSpellTargetRange < 5.0) { - if(AI_ActionCastSpellRandom(SPELL_METEOR_SWARM, SpellHostAreaDis, i30, OBJECT_SELF, i19, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_METEOR_SWARM, 30, OBJECT_SELF, 19, TRUE)) return TRUE; } } // Multi spell override backup casting - if(MultiSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; + if(bMultiSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; // Finally, the single target spells again. IE cast them after the AOE ones // if we don't choose an AOE one. - if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < i9) + if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < 9) { // 50% chance of Crushing Hand. // We try and not cast it twice on the same target (for a starter, wasting spells) - if(RangeLongValid && !GetHasSpellEffect(SPELL_BIGBYS_CRUSHING_HAND, GlobalSpellTarget)) + if(bRangeLongValid && !GetHasSpellEffect(SPELL_BIGBYS_CRUSHING_HAND, GlobalSpellTarget)) { // Bigby's Crushing Hand. Level 9 (Mage). 2d6 + 12 damage/round. - if(AI_ActionCastSpellRandom(SPELL_BIGBYS_CRUSHING_HAND, SpellHostRanged, i40, GlobalSpellTarget, i19, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_BIGBYS_CRUSHING_HAND, 40, GlobalSpellTarget, 19, FALSE)) return TRUE; } // Short range, not undead ETC. - if(RangeShortValid && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && + if(bRangeShortValid && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && GlobalSpellTargetRace != RACIAL_TYPE_UNDEAD && - !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, i9)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, 9)) { // 30% chance of energy drain // Energy Drain. Level 9 (Mage). 2d4 negative levels! -BAB, Saves, Stats! :-) - if(AI_ActionCastSpellRandom(SPELL_ENERGY_DRAIN, SpellHostRanged, i30, GlobalSpellTarget, i19, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_ENERGY_DRAIN, 30, GlobalSpellTarget, 19, FALSE)) return TRUE; } } @@ -7763,14 +7737,14 @@ H [Crumble] - Constructs only. // fails the 40% check. Might sitll have the item/spell though! if(AI_ActionCastBackupRandomSpell()) return TRUE; - if(IsFirstRunThrough) + if(bFirstRunThrough) { // Finally, we might as well cast that new (SoU) cleric spell which stops // many negative effects :-) // Undeath's Eternal Foe. Stops negative damage, ability score draining, // negative levels, immunity poisons, immunity diseases. // Level 9 (Cleric) - if(AI_ActionCastSpell(SPELL_UNDEATHS_ETERNAL_FOE, SpellEnhSinTar, OBJECT_SELF, i19, FALSE, ItemEnhSinTar, PotionEnh)) return TRUE; + if(AI_ActionCastSpell(SPELL_UNDEATHS_ETERNAL_FOE, OBJECT_SELF, 19, FALSE)) return TRUE; } /*::8888888888888888888888888888888888888888888888888888888888888888888888888888 Level 8 Spells. @@ -7799,7 +7773,7 @@ S [Bigby's Clenched Fist] - Attack Each Round. 1d8 + 12 damage/round. Fort VS [Aura Versus Alignment] - d6 + d8 damage shield, 25SR, 4Saves, 4AC, mind immune VS alignemnt X [Premonition] - 30/+5 DR. Cast up above this, though. X [Mind blank] - Mind immunity/cleansing. Not cast normally, except in invisbility. -S X [Etherealness] - Total invisiblity (Bugged I say). Cast above. +S X [Greater Sanctuary (Etherealness)] - Total invisiblity (Bugged I say). Cast above. Summon: [Create Greater Undead] - Create Vampire, Doom knight, Lich, Mummy Cleric. @@ -7816,54 +7790,54 @@ S X [Etherealness] - Total invisiblity (Bugged I say). Cast above. //::88888888888888888888888888888888888888888888888888888888888888888888888888*/ // Jump out if we don't want to cast level 8 spells/abilities. - if(iLowestSpellLevel > i8) return FALSE; + if(nLowestSpellLevel > 8) return FALSE; - int iEnemyAlignment = GetAlignmentGoodEvil(GlobalSpellTarget); - if(IsFirstRunThrough) + int nEnemyAlignment = GetAlignmentGoodEvil(GlobalSpellTarget); + if(bFirstRunThrough) { // Aura Vs. Alignment. d6 + d8 damage shield, 25SR, 4Saves, 4AC, mind immune VS alignemnt if(GetAlignmentGoodEvil(GlobalSpellTarget) == ALIGNMENT_EVIL) { - // Holy: Versus Evil. Level 8 (Cleric) - if(AI_ActionCastSubSpell(SPELL_HOLY_AURA, SpellEnhSelf, OBJECT_SELF, i18, FALSE, ItemEnhSelf)) return TRUE; + // Holy: Versus Evil. Level 8 (Cleric). Cast as subspell. + if(AI_ActionCastSpell(SPELL_HOLY_AURA, OBJECT_SELF, 18, FALSE, TRUE)) return TRUE; } - else if(iEnemyAlignment == ALIGNMENT_GOOD) + else if(nEnemyAlignment == ALIGNMENT_GOOD) { - // Unholy Holy: Versus Good. Level 8 (Cleric) - if(AI_ActionCastSubSpell(SPELL_UNHOLY_AURA, SpellEnhSelf, OBJECT_SELF, i18, FALSE, ItemEnhSelf)) return TRUE; + // Unholy Holy: Versus Good. Level 8 (Cleric), Cast as subspell. + if(AI_ActionCastSpell(SPELL_UNHOLY_AURA, OBJECT_SELF, 18, FALSE, TRUE)) return TRUE; } } // Cast regeneration + Natures Balance here if we are lacking HP. - if(IsFirstRunThrough && GlobalOurPercentHP <= i70) + if(bFirstRunThrough && GlobalOurPercentHP <= 70) { if(!GetHasSpellEffect(SPELL_REGENERATE)) { // Regeneration. Level 6 (Druid) 7 (Cleric). 6HP/Round. Good for persistant healing. - if(AI_ActionCastSpell(SPELL_REGENERATE, SpellEnhSelf, OBJECT_SELF, i17, FALSE, ItemEnhSelf, PotionEnh)) return TRUE; + if(AI_ActionCastSpell(SPELL_REGENERATE, OBJECT_SELF, 17, FALSE)) return TRUE; } // Cast at us, might as well. // Natures Balance. Level 8 (Druid). Lowers SR of enemies by 1d4(CasterLevel/5) + Healing (3d6 + CasterLevel) for allies. - if(AI_ActionCastSpell(SPELL_NATURES_BALANCE, SpellHostAreaDis, OBJECT_SELF, i18, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpell(SPELL_NATURES_BALANCE, OBJECT_SELF, 18, TRUE)) return TRUE; } // Undead spells. We can cast sunbeam/sunburst (VERY similar!) and Searing Light. // We do cast this against non-undead, but later on. // We only do this if at 5+ intelligence. Those below are stupid :-) if(GlobalSpellTargetRace == RACIAL_TYPE_UNDEAD && - GlobalIntelligence >= i5 && GlobalNormalSpellsNoEffectLevel < i8) + GlobalIntelligence >= 5 && GlobalNormalSpellsNoEffectLevel < 8) { // First, Undead to Death - Slays 1d4HD worth of undead/level. // (Max 20d4). Lowest first. // - Will save! // - 20M radius (but this we can ignore) // - Takes into account all SR and so forth. - if(GlobalNormalSpellsNoEffectLevel < i6 && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i6) && - RangeMediumValid) + if(GlobalNormalSpellsNoEffectLevel < 6 && + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 6) && + bRangeMediumValid) { // Undead to Death. Level 6 (Cleric) Slays 1d4HD worth of undead/level. (Max 20d4). Lowest first. - if(AI_ActionCastSpell(SPELL_UNDEATH_TO_DEATH, SpellHostAreaDis, GlobalSpellTarget, i16, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpell(SPELL_UNDEATH_TO_DEATH, GlobalSpellTarget, 16, TRUE)) return TRUE; } // SUNBURST: 6d6 to non-undead. Kills vampires. Blindness. Limit of 25 dice for undead damage. Medium range/colosal size // SUNBEAM: 3d6 to non-undead. Blindness. Limit of 20 dice for undead damage. Medium range/colosal size @@ -7872,34 +7846,34 @@ S X [Etherealness] - Total invisiblity (Bugged I say). Cast above. // vampires, and does 6d6 damage to non-undead, so marginally better. // Won't even randomly choose between them. Not worth it. - if(RangeShortValid) + if(bRangeShortValid) { // Sunburst. Level 8 (Druid/Mage) 6d6 to non-undead. Kills vampires. Blindness. Limit of 25 dice for undead damage. Medium range/colosal size - if(AI_ActionCastSpell(SPELL_SUNBURST, SpellHostAreaDis, GlobalSpellTarget, i18, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpell(SPELL_SUNBURST, GlobalSpellTarget, 18, TRUE)) return TRUE; // Sunbeam. Level 8 (Cleric/Druid) 3d6 to non-undead. Blindness. Limit of 20 dice for undead damage. Medium range/colosal size - if(AI_ActionCastSpell(SPELL_SUNBEAM, SpellHostAreaDis, GlobalSpellTarget, i18, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpell(SPELL_SUNBEAM, GlobalSpellTarget, 18, TRUE)) return TRUE; // If we can't destroy them, dominate them! - if(GlobalSpellTargetHitDice < GlobalOurChosenClassLevel * i3 && - GlobalNormalSpellsNoEffectLevel < i8 && + if(GlobalSpellTargetHitDice < GlobalOurChosenClassLevel * 3 && + GlobalNormalSpellsNoEffectLevel < 8 && GlobalSeenSpell && !GetIsObjectValid(GetAssociate(ASSOCIATE_TYPE_DOMINATED))) { // Control undead. Level 6 (Cleric) 7 (Mage). Dominates 1 undead up to 3x Caster level. - if(AI_ActionCastSpell(SPELL_CONTROL_UNDEAD, SpellHostRanged, GlobalSpellTarget, i17, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpell(SPELL_CONTROL_UNDEAD, GlobalSpellTarget, 17, FALSE)) return TRUE; } } // Medium spell - if(GlobalNormalSpellsNoEffectLevel < i3) + if(GlobalNormalSpellsNoEffectLevel < 3 && GlobalSeenSpell) { // Searing light. Level 3 (Cleric). Full level: 1-10d6 VS undead. Half Level: 1-5d6 VS constructs. 1-5d8 VS Others. - if(AI_ActionCastSpell(SPELL_SEARING_LIGHT, SpellHostRanged, GlobalSpellTarget, i13, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpell(SPELL_SEARING_LIGHT, GlobalSpellTarget, 13, FALSE)) return TRUE; } } // Gazes have short ranges - 80% chance. // Why this high? (compared to say, fire storm?) because they are innate // and so no concentration checks, and pretty good DC's. - if(RangeShortValid && d10() <= i8) // No GlobalNormalSpellsNoEffectLevel check + if(bRangeShortValid && d10() <= 8) // No GlobalNormalSpellsNoEffectLevel check { // We cast all of these, but randomly. It works through with most powerful // getting the highest %'s of course :-) @@ -7907,30 +7881,30 @@ S X [Etherealness] - Total invisiblity (Bugged I say). Cast above. { // Death gazes first - Golem one is the most deadly! // 50% chance of either. - if(AI_ActionCastSpellRandom(SPELLABILITY_GOLEM_BREATH_GAS, FALSE, i40, GlobalSpellTarget, FALSE, TRUE)) return TRUE; - if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_DEATH, FALSE, i40, GlobalSpellTarget, FALSE, TRUE)) return TRUE; + if(AI_ActionCastSpellRandom(SPELLABILITY_GOLEM_BREATH_GAS, 40, GlobalSpellTarget, FALSE, TRUE)) return TRUE; + if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_DEATH, 40, GlobalSpellTarget, FALSE, TRUE)) return TRUE; } // Petrify - SoU. 50% chance (almost like death!) if(!AI_GetSpellTargetImmunity(GlobalImmunityPetrify)) { - if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_PETRIFY, FALSE, i40, GlobalSpellTarget, FALSE, TRUE)) return TRUE; + if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_PETRIFY, 40, GlobalSpellTarget, FALSE, TRUE)) return TRUE; } // Destroy X are powerful. 50% chance each. They are basically as DEATH but for alignments. - if(iEnemyAlignment == ALIGNMENT_GOOD) + if(nEnemyAlignment == ALIGNMENT_GOOD) { - if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_DESTROY_GOOD, FALSE, i40, GlobalSpellTarget, FALSE, TRUE)) return TRUE; + if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_DESTROY_GOOD, 40, GlobalSpellTarget, FALSE, TRUE)) return TRUE; } - else if(iEnemyAlignment == ALIGNMENT_EVIL) + else if(nEnemyAlignment == ALIGNMENT_EVIL) { - if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_DESTROY_EVIL, FALSE, i40, GlobalSpellTarget, FALSE, TRUE)) return TRUE; + if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_DESTROY_EVIL, 40, GlobalSpellTarget, FALSE, TRUE)) return TRUE; } if(GetAlignmentLawChaos(GlobalSpellTarget) == ALIGNMENT_CHAOTIC) { - if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_DESTROY_CHAOS, FALSE, i40, GlobalSpellTarget, FALSE, TRUE)) return TRUE; + if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_DESTROY_CHAOS, 40, GlobalSpellTarget, FALSE, TRUE)) return TRUE; } else if(GetAlignmentLawChaos(GlobalSpellTarget) == ALIGNMENT_LAWFUL) { - if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_DESTROY_LAW, FALSE, i40, GlobalSpellTarget, FALSE, TRUE)) return TRUE; + if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_DESTROY_LAW, 40, GlobalSpellTarget, FALSE, TRUE)) return TRUE; } // Can't be immune to mind if(!AI_GetSpellTargetImmunity(GlobalImmunityMind)) @@ -7938,36 +7912,36 @@ S X [Etherealness] - Total invisiblity (Bugged I say). Cast above. // Fear (and fixed: Added Krenshar Scare) 30% if(!AI_GetSpellTargetImmunity(GlobalImmunityFear)) { - if(AI_ActionCastSpellRandom(SPELLABILITY_KRENSHAR_SCARE, FALSE, i30, GlobalSpellTarget, FALSE, TRUE)) return TRUE; - if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_FEAR, FALSE, i30, GlobalSpellTarget, FALSE, TRUE)) return TRUE; + if(AI_ActionCastSpellRandom(SPELLABILITY_KRENSHAR_SCARE, 30, GlobalSpellTarget, FALSE, TRUE)) return TRUE; + if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_FEAR, 30, GlobalSpellTarget, FALSE, TRUE)) return TRUE; } // Domination/Charm 30% if(!AI_GetSpellTargetImmunity(GlobalImmunityDomination)) { - if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_DOMINATE, FALSE, i30, GlobalSpellTarget, FALSE, TRUE)) return TRUE; - if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_CHARM, FALSE, i30, GlobalSpellTarget, FALSE, TRUE)) return TRUE; + if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_DOMINATE, 30, GlobalSpellTarget, FALSE, TRUE)) return TRUE; + if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_CHARM, 30, GlobalSpellTarget, FALSE, TRUE)) return TRUE; } // Other random mind things - if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_PARALYSIS, FALSE, i30, GlobalSpellTarget, FALSE, TRUE)) return TRUE; - if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_STUNNED, FALSE, i30, GlobalSpellTarget, FALSE, TRUE)) return TRUE; - if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_CONFUSION, FALSE, i30, GlobalSpellTarget, FALSE, TRUE)) return TRUE; - if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_DOOM, FALSE, i30, GlobalSpellTarget, FALSE, TRUE)) return TRUE; + if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_PARALYSIS, 30, GlobalSpellTarget, FALSE, TRUE)) return TRUE; + if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_STUNNED, 30, GlobalSpellTarget, FALSE, TRUE)) return TRUE; + if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_CONFUSION, 30, GlobalSpellTarget, FALSE, TRUE)) return TRUE; + if(AI_ActionCastSpellRandom(SPELLABILITY_GAZE_DOOM, 30, GlobalSpellTarget, FALSE, TRUE)) return TRUE; } } // Level 8 summons. 20HD or under, or 2 melee enemy and under. - if(IsFirstRunThrough && GlobalCanSummonSimilarLevel <= i8 && - (GlobalOurHitDice <= i20 || GlobalMeleeAttackers <= i2)) + if(bFirstRunThrough && GlobalCanSummonSimilarLevel <= 8 && + (GlobalOurHitDice <= 20 || GlobalMeleeAttackers <= 2)) { - // Create Greater undead - Pale Master - if(AI_ActionCastSummonSpell(AI_FEAT_PM_CREATE_GREATER_UNDEAD, iM1, i8)) return TRUE; + // Pale Master's Summon Greater undead + if(AI_ActionCastSummonSpell(SPELLABILITY_PM_SUMMON_GREATER_UNDEAD, -1, 8, FEAT_SUMMON_GREATER_UNDEAD)) return TRUE; // Create Greater Undead. Level 8 (Cleric) Create Vampire, Doom knight, Lich, Mummy Cleric. - if(AI_ActionCastSummonSpell(SPELL_CREATE_GREATER_UNDEAD, i18, i8)) return TRUE; + if(AI_ActionCastSummonSpell(SPELL_CREATE_GREATER_UNDEAD, 18, 8)) return TRUE; // Summon an Greater elemental. Summon 8 - Druid/Cleric/Bard/Mage. - if(AI_ActionCastSummonSpell(SPELL_SUMMON_CREATURE_VIII, i18, i8)) return TRUE; + if(AI_ActionCastSummonSpell(SPELL_SUMMON_CREATURE_VIII, 18, 8)) return TRUE; // Greater Planar Binding. Level 8 (Mage) Death Slaad (Evil) Vrock (Neutral) Trumpet Archon (Good) - if(AI_ActionCastSummonSpell(SPELL_GREATER_PLANAR_BINDING, i18, i8)) return TRUE; + if(AI_ActionCastSummonSpell(SPELL_GREATER_PLANAR_BINDING, 18, 8)) return TRUE; } // Level 8 general attack spells. @@ -7985,123 +7959,118 @@ S X [Etherealness] - Total invisiblity (Bugged I say). Cast above. // Is it best to cast Single Spells First? // 70% if favourable. - if(SingleSpellsFirst && GlobalNormalSpellsNoEffectLevel < i8) + if(bSingleSpellsFirst && GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < 8) { if(!GetHasSpellEffect(SPELL_BIGBYS_CLENCHED_FIST, GlobalSpellTarget) && !AI_CompareTimeStopStored(SPELL_BIGBYS_CLENCHED_FIST) && - RangeLongValid) + bRangeLongValid) { // Bigby's Clenched Fist. Level 8 (Mage) Attack Each Round. 1d8 + 12 damage/round. Fort VS stunning as well. - if(AI_ActionCastSpellRandom(SPELL_BIGBYS_CLENCHED_FIST, SpellHostRanged, i60, GlobalSpellTarget, i18, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_BIGBYS_CLENCHED_FIST, 60, GlobalSpellTarget, 18, FALSE)) return TRUE; } // No other single spells for level 8. // Single spell override backup casting - if(SingleSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; + if(bSingleSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; } // Area of effect spells. Go through - some do have higher %'s then othres. // Fire storm - cast on self with a 10M range around caster (circle). 60% chance. - if(RangeShortValid && GlobalSpellTargetRange <= f8 && - GlobalNormalSpellsNoEffectLevel < i8 && - !AI_SaveImmuneSpellTarget(SAVING_THROW_REFLEX, i8)) + if(bRangeShortValid && GlobalSpellTargetRange <= 8.0 && + GlobalNormalSpellsNoEffectLevel < 8 && + !AI_SaveImmuneSpellTarget(SAVING_THROW_REFLEX, 8)) { // Fire storm. Level 8 (Cleric). 1d6(Caster level) in fire/divine damage. No allies. collosal over caster. - if(AI_ActionCastSpellRandom(SPELL_FIRE_STORM, SpellHostAreaDis, i50, OBJECT_SELF, i18, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_FIRE_STORM, 50, OBJECT_SELF, 18, TRUE)) return TRUE; } // Horrid Wilting // Never affects allies. Fortitude - necromancy spell too. Lots of damage. - if(SpellHostAreaDis && RangeMediumValid && - (GetHasSpell(SPELL_HORRID_WILTING) || ItemHostAreaDis == SPELL_HORRID_WILTING)) + if(GetHasSpell(SPELL_HORRID_WILTING)) { // Won't cast if got lots of undead. 20M range, huge radius. - oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_HUGE, i8, SAVING_THROW_FORT, SHAPE_SPHERE, FALSE, FALSE, TRUE); + oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_HUGE, 8, SAVING_THROW_FORT, SHAPE_SPHERE, FALSE, FALSE, TRUE); // Is it valid? 60% chance of casting. if(GetIsObjectValid(oAOE)) { // Horrid Wilting. Level 8 (Mage). d8(CasterLevel) in negative energy. Fort for half. Necromancy. - if(AI_ActionCastSpellRandom(SPELL_HORRID_WILTING, SpellHostAreaDis, i50, oAOE, i18, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_HORRID_WILTING, 50, oAOE, 18, TRUE)) return TRUE; } } // Bombardment. Similar to the above. Long range, relfex save, not affect allies. - if(SpellHostAreaInd && RangeLongValid && - (GetHasSpell(SPELL_BOMBARDMENT) || ItemHostAreaInd == SPELL_BOMBARDMENT)) + if(GetHasSpell(SPELL_BOMBARDMENT)) { // 40M range, collosal area. Relfex save. - oAOE = AI_GetBestAreaSpellTarget(fLongRange, RADIUS_SIZE_COLOSSAL, i8, SAVING_THROW_REFLEX); + oAOE = AI_GetBestAreaSpellTarget(fLongRange, RADIUS_SIZE_COLOSSAL, 8, SAVING_THROW_REFLEX); // Is it valid? 60% chance of casting. if(GetIsObjectValid(oAOE)) { // Bombardment. Level 8 (Druid) 1d8(caster level) in fire damage. Like Horrid Wilting. Reflex save/long range/collosal - if(AI_ActionCastSpellRandom(SPELL_BOMBARDMENT, SpellHostAreaInd, i50, oAOE, i18, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_BOMBARDMENT, 50, oAOE, 18, TRUE)) return TRUE; } } // Earthquake. No SR, long range, affects anyone except caster. - if(SpellHostAreaInd && RangeLongValid && - (GetHasSpell(SPELL_EARTHQUAKE) || ItemHostAreaInd == SPELL_EARTHQUAKE)) + if(GetHasSpell(SPELL_EARTHQUAKE)) { // 40M range, collosal area. Relfex save. - oAOE = AI_GetBestAreaSpellTarget(fLongRange, RADIUS_SIZE_COLOSSAL, i8, SAVING_THROW_REFLEX); + oAOE = AI_GetBestAreaSpellTarget(fLongRange, RADIUS_SIZE_COLOSSAL, 8, SAVING_THROW_REFLEX); // Is it valid? 50% chance of casting. if(GetIsObjectValid(oAOE)) { // Earthquake] - 1d6(caster level) (to 10d6) in damage to AOE, except caster. - if(AI_ActionCastSpellRandom(SPELL_EARTHQUAKE, SpellHostAreaInd, i40, oAOE, i18, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_EARTHQUAKE, 40, oAOE, 18, TRUE)) return TRUE; } } // Incendiary Cloud. Long range, the AOE is 5.0M across. 4d6Damage/round is quite good. - if(SpellHostAreaInd && RangeLongValid && - !AI_CompareTimeStopStored(SPELL_INCENDIARY_CLOUD) && - (GetHasSpell(SPELL_INCENDIARY_CLOUD) || ItemHostAreaInd == SPELL_INCENDIARY_CLOUD)) + if(!AI_CompareTimeStopStored(SPELL_INCENDIARY_CLOUD) && + GetHasSpell(SPELL_INCENDIARY_CLOUD)) { // 40M range, lagre (5.0 across) area. Relfex saves. - oAOE = AI_GetBestAreaSpellTarget(fLongRange, RADIUS_SIZE_LARGE, i8, SAVING_THROW_REFLEX); + oAOE = AI_GetBestAreaSpellTarget(fLongRange, RADIUS_SIZE_LARGE, 8, SAVING_THROW_REFLEX); // Is it valid? 50% chance of casting. if(GetIsObjectValid(oAOE)) { // Earthquake] - 1d6(caster level) (to 10d6) in damage to AOE, except caster. - if(AI_ActionCastSpellRandom(SPELL_INCENDIARY_CLOUD, SpellHostAreaInd, i40, oAOE, i18, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_INCENDIARY_CLOUD, 40, oAOE, 18, TRUE)) return TRUE; } } // Sunbeam and burst. Very similar spells and if they are not undead, then // there should be very little chance of casting it. // - Won't bother getting nearest undead. - if(SpellHostAreaInd && !GlobalInTimeStop && RangeLongValid && - (GetHasSpell(SPELL_SUNBEAM) || GetHasSpell(SPELL_SUNBURST) || - ItemHostAreaDis == SPELL_SUNBEAM || ItemHostAreaDis == SPELL_SUNBURST)) + if(GlobalInTimeStop && bRangeLongValid && + (GetHasSpell(SPELL_SUNBEAM) || GetHasSpell(SPELL_SUNBURST))) { // 40M range, lagre (5.0 across) area. Relfex saves. - oAOE = AI_GetBestAreaSpellTarget(fLongRange, RADIUS_SIZE_LARGE, i8, SAVING_THROW_REFLEX); + oAOE = AI_GetBestAreaSpellTarget(fLongRange, RADIUS_SIZE_LARGE, 8, SAVING_THROW_REFLEX); // Is it valid? 20% chance of casting. if(GetIsObjectValid(oAOE)) { // Sunburst. Level 8 (Druid/Mage) 6d6 to non-undead. Kills vampires. Blindness. Limit of 25 dice for undead damage. Medium range/colosal size - if(AI_ActionCastSpellRandom(SPELL_SUNBURST, SpellHostAreaDis, i10, oAOE, i18, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_SUNBURST, 10, oAOE, 18, TRUE)) return TRUE; // Sunbeam. Level 8 (Cleric/Druid) 3d6 to non-undead. Blindness. Limit of 20 dice for undead damage. Medium range/colosal size - if(AI_ActionCastSpellRandom(SPELL_SUNBEAM, SpellHostAreaDis, i10, oAOE, i18, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_SUNBEAM, 10, oAOE, 18, TRUE)) return TRUE; } } // Multi spell override backup casting - if(MultiSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; + if(bMultiSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; // Single spells at end - if(SingleSpellsFirst && GlobalNormalSpellsNoEffectLevel < i8) + if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < 8) { // 40% chance if(!GetHasSpellEffect(SPELL_BIGBYS_CLENCHED_FIST, GlobalSpellTarget) && !AI_CompareTimeStopStored(SPELL_BIGBYS_CLENCHED_FIST) && - RangeLongValid) + bRangeLongValid) { // Bigby's Clenched Fist. Level 8 (Mage) Attack Each Round. 1d8 + 12 damage/round. Fort VS stunning as well. - if(AI_ActionCastSpellRandom(SPELL_BIGBYS_CLENCHED_FIST, SpellHostRanged, i30, GlobalSpellTarget, i18, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_BIGBYS_CLENCHED_FIST, 30, GlobalSpellTarget, 18, FALSE)) return TRUE; } // No other single spells for level 8. // Single spell override backup casting - if(SingleSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; + if(bSingleSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; } // Check if we had any of the above we didn't cast based on the % @@ -8151,48 +8120,48 @@ S [Bigby's Grasping Hand] - Hold target if sucessful grapple //::77777777777777777777777777777777777777777777777777777777777777777777777777*/ // Jump out if we don't want to cast level 7 spells. - if(iLowestSpellLevel > i7) return FALSE; + if(nLowestSpellLevel > 7) return FALSE; // Cast Shadow Shield only first. Good protections really :-) // Visages are generally lower DR, with some spell-resisting or effect-immunty extras. - if(IsFirstRunThrough) + if(bFirstRunThrough) { // Shadow Shield - has 10/+3 damage reduction + lots of stuff. Level 7 (Mage) - if(AI_SpellWrapperVisageProtections(i7)) return TRUE; + if(AI_SpellWrapperVisageProtections(7)) return TRUE; // Protection From Spells. if(!AI_GetAIHaveSpellsEffect(GlobalHasProtectionSpellsSpell)) { // Protection from spells. Level 7 (Mage), for +8 on all saves (Area effect too!) - if(AI_ActionCastSpell(SPELL_PROTECTION_FROM_SPELLS, SpellProAre, OBJECT_SELF, i17, FALSE, ItemProAre)) return TRUE; + if(AI_ActionCastSpell(SPELL_PROTECTION_FROM_SPELLS, OBJECT_SELF, 17, FALSE)) return TRUE; } } // Palemaster death touch // DC 17 + (Pale Master - 10) /2. - if(RangeTouchValid) + if(bRangeTouchValid && GlobalSeenSpell) { // Cannot affect creatures over large size // - Module switch, but always checked here. if(GetCreatureSize(GlobalSpellTarget) <= CREATURE_SIZE_LARGE && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && !AI_GetSpellTargetImmunity(GlobalImmunityDeath) && - // Fort save DC 17 - GlobalSpellTargetFort <= i16) + // Fort save DC 17 + 1 per level over 10 (epic levels). Keep this test. + GlobalSpellTargetFort <= 16) { // Use the feat - if(AI_ActionUseFeatOnObject(FEAT_DEATHLESS_MASTER_TOUCH, GlobalSpellTarget)) return TRUE; + if(AI_ActionUseSpellLikeFeat(FEAT_DEATHLESS_MASTER_TOUCH, SPELLABILITY_PM_DEATHLESS_MASTER_TOUCH, GlobalSpellTarget)) return TRUE; } // Undead graft paralyzes! if(GlobalSpellTargetRace != RACIAL_TYPE_ELF && // Fort save - 14 + Palemaster levels / 2 - !GlobalSpellTargetFort < (i14 + GetLevelByClass(CLASS_TYPE_PALEMASTER)/i2)) + !GlobalSpellTargetFort < (14 + GetLevelByClass(CLASS_TYPE_PALEMASTER)/2)) { // Use the feat - if(AI_ActionUseFeatOnObject(FEAT_UNDEAD_GRAFT_1, GlobalSpellTarget)) return TRUE; + if(AI_ActionUseSpellLikeFeat(FEAT_UNDEAD_GRAFT_1, SPELLABILITY_PM_UNDEAD_GRAFT_1, GlobalSpellTarget)) return TRUE; // 2 versions - if(AI_ActionUseFeatOnObject(FEAT_UNDEAD_GRAFT_2, GlobalSpellTarget)) return TRUE; + if(AI_ActionUseSpellLikeFeat(FEAT_UNDEAD_GRAFT_2, SPELLABILITY_PM_UNDEAD_GRAFT_2, GlobalSpellTarget)) return TRUE; } } @@ -8213,42 +8182,42 @@ S [Bigby's Grasping Hand] - Hold target if sucessful grapple // Is it best to target with single-target spells first? Most are pretty good :-D // 60-70% if favourable. - if(SingleSpellsFirst && GlobalNormalSpellsNoEffectLevel < i7) + if(bSingleSpellsFirst && GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < 7) { // Killing spells. These, if sucessful, rend all status-effect spells redundant. // - Only fired if they are not immune :-D - if(RangeShortValid && !AI_CompareTimeStopStored(SPELL_DESTRUCTION, SPELL_FINGER_OF_DEATH) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, i7) && + if(bRangeShortValid && !AI_CompareTimeStopStored(SPELL_DESTRUCTION, SPELL_FINGER_OF_DEATH) && + !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, 7) && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && !AI_GetSpellTargetImmunity(GlobalImmunityDeath)) { // Destruction, level 7 (Cleric). Fort (Death) for Death if fail, or 10d6 damage if pass. - if(AI_ActionCastSpellRandom(SPELL_DESTRUCTION, SpellHostRanged, i60, GlobalSpellTarget, i17, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_DESTRUCTION, 60, GlobalSpellTarget, 17, FALSE)) return TRUE; // Finger of Death. Level 7 (Mage). Fort (Death) for death if fail, or d6(3) + nCasterLvl damage if pass. - if(AI_ActionCastSpellRandom(SPELL_FINGER_OF_DEATH, SpellHostRanged, i50, GlobalSpellTarget, i17, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_FINGER_OF_DEATH, 50, GlobalSpellTarget, 17, FALSE)) return TRUE; } // Is not immune to mind spell (I think this is a valid check) and not already stunned. - // Really, if under < 151 HP to be affected - short ranged - if (GlobalSpellTargetCurrentHitPoints <= i150 && RangeShortValid && + // Really, if under < 151 HP to be affected - short ranged, and seen. + if (GlobalSpellTargetCurrentHitPoints <= 150 && bRangeShortValid && !AI_GetSpellTargetImmunity(GlobalImmunityStun) && !AI_GetSpellTargetImmunity(GlobalImmunityMind) && !AI_CompareTimeStopStored(SPELL_POWER_WORD_STUN)) { // Power Word Stun. Level 7 (Wizard). Stun duration based on HP. - if(AI_ActionCastSpellRandom(SPELL_POWER_WORD_STUN, SpellHostAreaInd, i60, GlobalSpellTarget, i17, FALSE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_POWER_WORD_STUN, 60, GlobalSpellTarget, 17, FALSE)) return TRUE; } // Bigbiy's Grasping hand last. We don't bother checking for grapple checks - // they mainly work anyway, if anything. Powerful in its own right, as // it holds on a sucessful check. - if(RangeLongValid && !GetHasSpellEffect(SPELL_BIGBYS_GRASPING_HAND, GlobalSpellTarget) && + if(bRangeLongValid && !GetHasSpellEffect(SPELL_BIGBYS_GRASPING_HAND, GlobalSpellTarget) && !AI_CompareTimeStopStored(SPELL_BIGBYS_GRASPING_HAND) && !AI_GetSpellTargetImmunity(GlobalImmunityStun)) { // Bigby's Grasping Hand. Level 7 (Mage) Hold target if sucessful grapple - if(AI_ActionCastSpellRandom(SPELL_BIGBYS_GRASPING_HAND, SpellHostRanged, i40, GlobalSpellTarget, i18, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_BIGBYS_GRASPING_HAND, 40, GlobalSpellTarget, 18, FALSE)) return TRUE; } // Single spell override backup casting - if(SingleSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; + if(bSingleSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; } // AOE spells now. @@ -8260,143 +8229,138 @@ S [Bigby's Grasping Hand] - Hold target if sucessful grapple // Word of faith // Doesn't hurt allies, will-based save, at the very least blindness :-D Medium range, collosal size - if(SpellHostAreaDis && RangeMediumValid && - (GetHasSpell(SPELL_WORD_OF_FAITH) || ItemHostAreaDis == SPELL_WORD_OF_FAITH)) + if(bRangeMediumValid && GetHasSpell(SPELL_WORD_OF_FAITH)) { // 20M medium range, colossal size, will save to deflect. - oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_COLOSSAL, i7, SAVING_THROW_WILL); + oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_COLOSSAL, 7, SAVING_THROW_WILL); // Is it valid? 70% chance of casting. if(GetIsObjectValid(oAOE)) { // Word of Faith. Level 7 (Cleric) Enemies only affected. 4 Or Down die. 4+ [Confuse|Stun|Blind]. 8+ [Stun|Blind]. 12+ [Blind]. (1Round/2Casterlevels) outsiders killed. - if(AI_ActionCastSpellRandom(SPELL_WORD_OF_FAITH, SpellHostAreaDis, i60, oAOE, i17, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_WORD_OF_FAITH, 60, oAOE, 17, TRUE)) return TRUE; } } // Creeping Doom // Damage to all in AOE, to 1000 damage. d6(rounds in it) basically. Good AOE spell. // Only 50% chance of casting, to not cast too many. - if(SpellHostAreaDis && RangeMediumValid && !GlobalInTimeStop && - (GetHasSpell(SPELL_CREEPING_DOOM) || ItemHostAreaDis == SPELL_CREEPING_DOOM)) + if(bRangeMediumValid && !GlobalInTimeStop && GetHasSpell(SPELL_CREEPING_DOOM)) { // 20M medium range, we'll say a huge size. No save can stop all damage ;-) - oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_HUGE, i7, FALSE, SHAPE_SPHERE, GlobalFriendlyFireFriendly); + oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_HUGE, 7, FALSE, SHAPE_SPHERE, GlobalFriendlyFireFriendly); // Is it valid? 50% chance of casting. if(GetIsObjectValid(oAOE)) { // Creeping Doom. Level 7 (Druid) Until 1000 damage, d6 + d6/round stayed in damage in an AOE. - if(AI_ActionCastSpellRandom(SPELL_CREEPING_DOOM, SpellHostAreaDis, i40, oAOE, i17, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_CREEPING_DOOM, 40, oAOE, 17, TRUE)) return TRUE; } } // Delayed Fireball Blast. Big fireball. Lots of fire damage - reflex saves. - if(SpellHostAreaInd && RangeMediumValid && - !AI_CompareTimeStopStored(SPELL_DELAYED_BLAST_FIREBALL, SPELL_FIREBALL) && - (GetHasSpell(SPELL_DELAYED_BLAST_FIREBALL) || ItemHostAreaInd == SPELL_DELAYED_BLAST_FIREBALL)) + if(bRangeMediumValid && GetHasSpell(SPELL_DELAYED_BLAST_FIREBALL) && + !AI_CompareTimeStopStored(SPELL_DELAYED_BLAST_FIREBALL, SPELL_FIREBALL)) { // 20M medium range, blast is RADIUS_SIZE_HUGE, lower then Fireball, but more deadly (both save + damage) - oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_HUGE, i7, SAVING_THROW_REFLEX, SHAPE_SPHERE, GlobalFriendlyFireFriendly); + oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_HUGE, 7, SAVING_THROW_REFLEX, SHAPE_SPHERE, GlobalFriendlyFireFriendly); // Is it valid? 60% chance of casting. if(GetIsObjectValid(oAOE)) { // Delayed Fireball Blast. Level 7 (Mage) Up to 20d6 fire reflex damage. Can be set up as a trap (heh, nah!) - if(AI_ActionCastSpellRandom(SPELL_DELAYED_BLAST_FIREBALL, SpellHostAreaInd, i50, oAOE, i17, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_DELAYED_BLAST_FIREBALL, 50, oAOE, 17, TRUE)) return TRUE; } } // Great Thunderclap is OK, but doesn't really do too much. If anything, the // 3 saves are cool :-P - if(SpellHostAreaInd && RangeMediumValid && - !AI_CompareTimeStopStored(SPELL_GREAT_THUNDERCLAP) && - (GetHasSpell(SPELL_GREAT_THUNDERCLAP) || ItemHostAreaInd == SPELL_GREAT_THUNDERCLAP)) + if(bRangeMediumValid && !AI_CompareTimeStopStored(SPELL_GREAT_THUNDERCLAP) && + GetHasSpell(SPELL_GREAT_THUNDERCLAP)) { // 20M medium range, hits a gargantuan area. // - We ignore saves for this. // - Doesn't actually hit ourselves. Won't bother checking this though. - oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_GARGANTUAN, i7, SAVING_THROW_ALL, SHAPE_SPHERE, GlobalFriendlyFireFriendly); + oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_GARGANTUAN, 7, SAVING_THROW_ALL, SHAPE_SPHERE, GlobalFriendlyFireFriendly); // Is it valid? 50% chance of casting. if(GetIsObjectValid(oAOE)) { // Great Thunderclap. Level 7 (Mage) Will VS 1 round stun. Fort VS 1 Turn Deaf. Reflex VS 1 Round Knockdown. - if(AI_ActionCastSpellRandom(SPELL_GREAT_THUNDERCLAP, SpellHostAreaInd, i40, oAOE, i17, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_GREAT_THUNDERCLAP, 40, oAOE, 17, TRUE)) return TRUE; } } // Lastly, AOE wise, it is prismatic spray. Comparable, if a little (or very!) // erratic. We might as well cast this whatever (So if they all are immune // to the delay fireballs we have, this does good damage compared to 0!) - if(SpellHostAreaInd && RangeShortValid && - !AI_CompareTimeStopStored(SPELL_PRISMATIC_SPRAY) && - (GetHasSpell(SPELL_PRISMATIC_SPRAY) || ItemHostAreaInd == SPELL_PRISMATIC_SPRAY)) + if(bRangeShortValid && !AI_CompareTimeStopStored(SPELL_PRISMATIC_SPRAY) && + GetHasSpell(SPELL_PRISMATIC_SPRAY)) { // 8M short range, blast is a cone, and no save. Spell script has fSpread at 11.0 - oAOE = AI_GetBestAreaSpellTarget(fShortRange, f11, i7, FALSE, SHAPE_SPELLCONE, GlobalFriendlyFireFriendly); + oAOE = AI_GetBestAreaSpellTarget(fShortRange, 11.0, 7, FALSE, SHAPE_SPELLCONE, GlobalFriendlyFireFriendly); // Is it valid? 40% chance of casting. if(GetIsObjectValid(oAOE)) { // Prismatic Spray. Level 7 (Mage) Random damage/effects. Chance of doing double amount of effects. - if(AI_ActionCastSpellRandom(SPELL_PRISMATIC_SPRAY, SpellHostAreaInd, i30, oAOE, i17, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_PRISMATIC_SPRAY, 30, oAOE, 17, TRUE)) return TRUE; } } // Multi spell override backup casting - if(MultiSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; + if(bMultiSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; // Level 7 summon spells. Also cast the unique class-based summons (like // a blackguards undead, a shadowdancers shadow ETC). - if(IsFirstRunThrough && GlobalCanSummonSimilarLevel <= i7) + if(bFirstRunThrough && GlobalCanSummonSimilarLevel <= 7) { // Always use our feat-based ones (not level dependant) as they increase // with level. - // - Shadow based on level - if(AI_ActionCastSummonSpell(FEAT_SUMMON_SHADOW, iM1, i7)) return TRUE; + // - Shadow based on level (Shadowdancer Shadow) + if(AI_ActionCastSummonSpell(SPELL_SUMMON_SHADOW, -1, 7, FEAT_SUMMON_SHADOW)) return TRUE; // - Undead warrior (EG: doomknight) based on level - if(AI_ActionCastSummonSpell(AI_FEAT_BG_CREATE_UNDEAD, iM1, i7)) return TRUE; + if(AI_ActionCastSummonSpell(SPELLABILITY_BG_CREATEDEAD, -1, 7, AI_FEAT_BG_CREATE_UNDEAD)) return TRUE; // - Shadow based on level - if(AI_ActionCastSummonSpell(AI_FEAT_BG_FIENDISH_SERVANT, iM1, i7)) return TRUE; - // Pale master - if(AI_ActionCastSummonSpell(AI_FEAT_PM_CREATE_UNDEAD, iM1, i7)) return TRUE; + if(AI_ActionCastSummonSpell(SPELLABILITY_BG_FIENDISH_SERVANT, -1, 7, AI_FEAT_BG_FIENDISH_SERVANT)) return TRUE; + // Pale master - Summon Undead feat. + if(AI_ActionCastSummonSpell(SPELLABILITY_PM_SUMMON_UNDEAD, -1, 7, FEAT_SUMMON_UNDEAD)) return TRUE; // Then, the normal summons. - if(GlobalOurHitDice <= i18 || GlobalMeleeAttackers <= i2) + if(GlobalOurHitDice <= 18 || GlobalMeleeAttackers <= 2) { // Mordenkainen's Sword Level 7 (Mage). Good, nay, very good hitting summon. - if(AI_ActionCastSummonSpell(SPELL_MORDENKAINENS_SWORD, i17, i7)) return TRUE; + if(AI_ActionCastSummonSpell(SPELL_MORDENKAINENS_SWORD, 17, 7)) return TRUE; // Summon Monster VII (7). Level 7 (Cleric, Mage, Druid, etc) Huge elemental - if(AI_ActionCastSummonSpell(SPELL_SUMMON_CREATURE_VII, i17, i7)) return TRUE; + if(AI_ActionCastSummonSpell(SPELL_SUMMON_CREATURE_VII, 17, 7)) return TRUE; } } // Now, back to single spell targets again. - if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < i7) + if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < 7) { // Killing spells. These, if sucessful, rend all status-effect spells redundant. // - Only fired if they are not immune :-D - if(RangeShortValid && !AI_CompareTimeStopStored(SPELL_DESTRUCTION, SPELL_FINGER_OF_DEATH) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, i7) && + if(bRangeShortValid && !AI_CompareTimeStopStored(SPELL_DESTRUCTION, SPELL_FINGER_OF_DEATH) && + !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, 7) && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && !AI_GetSpellTargetImmunity(GlobalImmunityDeath)) { // Destruction, level 7 (Cleric). Fort (Death) for Death if fail, or 10d6 damage if pass. - if(AI_ActionCastSpellRandom(SPELL_DESTRUCTION, SpellHostRanged, i30, GlobalSpellTarget, i17, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_DESTRUCTION, 30, GlobalSpellTarget, 17, FALSE)) return TRUE; // Finger of Death. Leve 7 (Mage). Fort (Death) for death if fail, or d6(3) + nCasterLvl damage if pass. - if(AI_ActionCastSpellRandom(SPELL_FINGER_OF_DEATH, SpellHostRanged, i20, GlobalSpellTarget, i17, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_FINGER_OF_DEATH, 20, GlobalSpellTarget, 17, FALSE)) return TRUE; } // Bigbiy's Grasping hand last. We don't bother checking for grapple checks - // they mainly work anyway, if anything. Powerful in its own right, as // it holds on a sucessful check. - if(RangeLongValid && !GetHasSpellEffect(SPELL_BIGBYS_GRASPING_HAND, GlobalSpellTarget) && + if(bRangeLongValid && !GetHasSpellEffect(SPELL_BIGBYS_GRASPING_HAND, GlobalSpellTarget) && !AI_CompareTimeStopStored(SPELL_BIGBYS_GRASPING_HAND) && !AI_GetSpellTargetImmunity(GlobalImmunityStun)) { // Bigby's Grasping Hand. Level 7 (Mage) Hold target if sucessful grapple - if(AI_ActionCastSpellRandom(SPELL_BIGBYS_GRASPING_HAND, SpellHostRanged, i20, GlobalSpellTarget, i18, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_BIGBYS_GRASPING_HAND, 20, GlobalSpellTarget, 18, FALSE)) return TRUE; } // Is not immune to mind spell (I think this is a valid check) and not already stunned. // Really, if under < 151 HP to be affected - short ranged - if (GlobalSpellTargetCurrentHitPoints <= i150 && RangeShortValid && + if (GlobalSpellTargetCurrentHitPoints <= 150 && bRangeShortValid && !AI_GetSpellTargetImmunity(GlobalImmunityStun) && !AI_GetSpellTargetImmunity(GlobalImmunityMind) && !AI_CompareTimeStopStored(SPELL_POWER_WORD_STUN)) { // Power Word Stun. Level 7 (Wizard). Stun duration based on HP. - if(AI_ActionCastSpellRandom(SPELL_POWER_WORD_STUN, SpellHostAreaInd, i20, GlobalSpellTarget, i17, FALSE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_POWER_WORD_STUN, 20, GlobalSpellTarget, 17, FALSE)) return TRUE; } } @@ -8470,29 +8434,31 @@ XXXX[Legend Lore] - Lots of lore. Never cast. We check if we can cast Golem Ranged Slam here too. Trying to do dragon diciple breath too! :-) + + Hag horrific eye, from the hag in 1.62, added in as well. //::66666666666666666666666666666666666666666666666666666666666666666666666666*/ // Jump out if we don't want to cast level 6 spells. - if(iLowestSpellLevel > i6) return FALSE; + if(nLowestSpellLevel > 6) return FALSE; - if(IsFirstRunThrough) + if(bFirstRunThrough) { // Best elemental protection (maybe % chance here...and later do it 100%) - if(AI_SpellWrapperElementalProtections(iLowestSpellLevel)) return TRUE; + if(AI_SpellWrapperElementalProtections(nLowestSpellLevel)) return TRUE; // Visage - eathereal :-) // Ethereal Visage. Level 6 (Mage) 25% consealment. 20/+3 DR. 0/1/2 spells immune to. - if(AI_SpellWrapperVisageProtections(i6)) return TRUE; + if(AI_SpellWrapperVisageProtections(6)) return TRUE; // Globe of Invunrability. We cast minor globe if we have under 10HD (Else we'll try // it lower down anyway) - if(GlobalOurHitDice <= i10) + if(GlobalOurHitDice <= 10) { - if(AI_SpellWrapperGlobeProtections(iLowestSpellLevel)) return TRUE; + if(AI_SpellWrapperGlobeProtections(nLowestSpellLevel)) return TRUE; } else { - if(AI_SpellWrapperGlobeProtections(i6)) return TRUE; + if(AI_SpellWrapperGlobeProtections(6)) return TRUE; } // Cast Greater Stoneskin if not got the specific greater stoneskin spell @@ -8502,106 +8468,99 @@ XXXX[Legend Lore] - Lots of lore. Never cast. { // Then, greater stoneskin protects a lot of damage - // Greater Stoneskin. Level 6 (Mage) 7 (druid) 20/+5 phiscial damage reduction - if(AI_ActionCastSpell(SPELL_GREATER_STONESKIN, SpellProSelf, OBJECT_SELF, i16, FALSE, ItemProSelf, PotionPro)) return TRUE; + if(AI_ActionCastSpell(SPELL_GREATER_STONESKIN, OBJECT_SELF, 16, FALSE)) return TRUE; } } // Dispel level 4 protections (Hastes, regenerates, tensors...) - if(RangeMediumValid && !GlobalInTimeStop)// All medium spells. - { - // Dispel number need to be 4 for breach - if(GlobalDispelTargetHighestBreach >= i4) - { - // Wrapers Greater and Lesser Breach. - if(AI_ActionCastBreach()) return TRUE; - } - // Dispel >= 4 - if(GlobalDispelTargetHighestDispel >= i4) - { - // Wrappers the dispel spells - if(AI_ActionCastDispel()) return TRUE; - } - } + if(AI_ActionAttemptDispel(4, bRangeMediumValid)) return TRUE; - if(IsFirstRunThrough) + if(bFirstRunThrough) { // Cast more buff spells // Buffing spells (energy buffer and downwards) // 40% chance. - if(AI_ActionCastAllyBuffSpell(f6, i40, SPELL_ENERGY_BUFFER, SPELL_PROTECTION_FROM_ELEMENTS, SPELL_RESIST_ELEMENTS, SPELL_ENDURE_ELEMENTS)) return TRUE; + if(AI_ActionCastAllyBuffSpell(6.0, 40, SPELL_ENERGY_BUFFER, SPELL_PROTECTION_FROM_ELEMENTS, SPELL_RESIST_ELEMENTS, SPELL_ENDURE_ELEMENTS)) return TRUE; } // Dirge. // - Cast always, basically. Boring :-) but its an OK spell - if(IsFirstRunThrough && !GetHasSpellEffect(SPELL_DIRGE)) + if(bFirstRunThrough && !GetHasSpellEffect(SPELL_DIRGE)) { // Dirge. Level 6 (Bard). Continual Strength Damage to those in the AOE (Mobile, on self) - if(AI_ActionCastSpell(SPELL_DIRGE, SpellHostAreaInd, GlobalSpellTarget, i15, FALSE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpell(SPELL_DIRGE, GlobalSpellTarget, 15, FALSE)) return TRUE; } // Golem ranged slam. 80% chance of using. - if(RangeLongValid && GlobalSeenSpell && d10() <= i8) + if(bRangeLongValid && GlobalSeenSpell && d10() <= 8) { // Golem Ranged Slam. Long ranged, Random(30) + 30 Blud damage. Can do knockdown too. - if(AI_ActionCastSpell(AI_SPELLABILITY_GOLEM_RANGED_SLAM, SpellHostRanged, GlobalSpellTarget)) return TRUE; + if(AI_ActionCastSpell(AI_SPELLABILITY_GOLEM_RANGED_SLAM, GlobalSpellTarget)) return TRUE; + } + + // Evil eye. DC 11 Fort save, or big ability damage. 60% chance of casting. + if(bRangeShortValid && GlobalSeenSpell && GlobalSpellTargetFort <= 30 && d10() <= 6) + { + // Evil eye, short range. 5 ability damage to str. and con., and 1/5 possibly of doing all 6 damage. Fort for none (DC 11) + if(AI_ActionCastSpell(SPELLABILITY_SEAHAG_EVILEYE, GlobalSpellTarget)) return TRUE; } // Dragon Diciple breath. - if(RangeTouchValid && + if(bRangeTouchValid && // Reflex save. 19 + 1 per 4 levels after 10. - GlobalSpellTargetReflex < (i19 + (GetLevelByClass(CLASS_TYPE_DRAGONDISCIPLE) - i10)/i4)) + GlobalSpellTargetReflex < (19 + (GetLevelByClass(CLASS_TYPE_DRAGONDISCIPLE) - 10)/4)) { // Dragon diciple breath - x2_s2_descbreath - if(AI_ActionUseFeatOnObject(FEAT_DRAGON_DIS_BREATH, GlobalSpellTarget)) return TRUE; + if(AI_ActionUseSpellLikeFeat(FEAT_DRAGON_DIS_BREATH, AI_SPELLABILITY_DIS_BREATH, GlobalSpellTarget)) return TRUE; } // Howl! HOOOOOOOOWWWWWWWWWWWLLLLLLLLL! Collosal range on self. // Most are decent enough to cast as level 6 spells, centred on self, 80% chance to cast. // We also randomly choose one (and always cast one if we can cast one :-) ) - if(RangeTouchValid && GlobalSeenSpell && d10() <= i8) + if(bRangeTouchValid && GlobalSeenSpell && d10() <= 8) { // We cast all of these, but randomly. It works through with most powerful // getting the highest %'s of course :-) if(!AI_GetSpellTargetImmunity(GlobalImmunityDeath)) { // 50% chance of death howl. - if(AI_ActionCastSpellRandom(SPELLABILITY_HOWL_DEATH, SpellHostAreaInd, i40)) return TRUE; + if(AI_ActionCastSpellRandom(SPELLABILITY_HOWL_DEATH, 40)) return TRUE; } // Sonic damage is powerful - 40% // Fortitude save or sonic damage d6(HD/4) :-) - if(AI_ActionCastSpellRandom(SPELLABILITY_HOWL_SONIC, SpellHostAreaInd, i30)) return TRUE; + if(AI_ActionCastSpellRandom(SPELLABILITY_HOWL_SONIC, 30)) return TRUE; // Can't be immune to mind for most of the rest if(!AI_GetSpellTargetImmunity(GlobalImmunityMind)) { // Mind blast - if(AI_ActionCastSpellRandom(AI_SPELLABILITY_MINDFLAYER_MINDBLAST_10, SpellHostAreaInd, i20)) return TRUE; + if(AI_ActionCastSpellRandom(AI_SPELLABILITY_MINDFLAYER_MINDBLAST_10, 20)) return TRUE; // Other one - if(AI_ActionCastSpellRandom(AI_SPELLABILITY_MINDFLAYER_PARAGON_MINDBLAST, SpellHostAreaInd, i20)) return TRUE; + if(AI_ActionCastSpellRandom(AI_SPELLABILITY_MINDFLAYER_PARAGON_MINDBLAST, 20)) return TRUE; // Other one 2 - if(AI_ActionCastSpellRandom(AI_SPELLABILITY_PSIONIC_MASS_CONCUSSION, SpellHostAreaInd, i20)) return TRUE; + if(AI_ActionCastSpellRandom(AI_SPELLABILITY_PSIONIC_MASS_CONCUSSION, 20)) return TRUE; // Fear howl. 40% chance if(!AI_GetSpellTargetImmunity(GlobalImmunityFear)) { - if(AI_ActionCastSpellRandom(SPELLABILITY_HOWL_FEAR, SpellHostAreaInd, i20)) return TRUE; + if(AI_ActionCastSpellRandom(SPELLABILITY_HOWL_FEAR, 20)) return TRUE; } // Paralisis and daze (mind effects, and stunning ones) if(!AI_GetSpellTargetImmunity(GlobalImmunityStun)) { - if(AI_ActionCastSpellRandom(SPELLABILITY_HOWL_PARALYSIS, SpellHostAreaInd, i20)) return TRUE; - if(AI_ActionCastSpellRandom(SPELLABILITY_HOWL_DAZE, SpellHostAreaInd, i20)) return TRUE; + if(AI_ActionCastSpellRandom(SPELLABILITY_HOWL_PARALYSIS, 20)) return TRUE; + if(AI_ActionCastSpellRandom(SPELLABILITY_HOWL_DAZE, 20)) return TRUE; } } // Doom last. -X's amounts of stats. Also note, don't cast if already // affected :-) if(!GetHasSpellEffect(SPELLABILITY_HOWL_DOOM)) { - if(AI_ActionCastSpellRandom(SPELLABILITY_HOWL_DOOM, SpellHostAreaInd, i20)) return TRUE; + if(AI_ActionCastSpellRandom(SPELLABILITY_HOWL_DOOM, 20)) return TRUE; } // Harpy song. - if(AI_ActionCastSpellRandom(AI_SPELLABILITY_HARPYSONG, SpellHostAreaInd, i20)) return TRUE; + if(AI_ActionCastSpellRandom(AI_SPELLABILITY_HARPYSONG, 20)) return TRUE; // Finally, if we got the 80% chance of using one, and none of them // random cast, backup with this. @@ -8625,48 +8584,48 @@ XXXX[Legend Lore] - Lots of lore. Never cast. // Is it best to target with single-target spells first? Flesh to stone // alone makes single target level 6 spells decent enough :-) // 60-70% if favourable. - if(SingleSpellsFirst && GlobalNormalSpellsNoEffectLevel < i6) + if(bSingleSpellsFirst && GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < 6) { // Drown! We don't do this if they are under 30HP already. // 80% chance to cast if we have it, and not immune to the save. - if(RangeMediumValid && !AI_CompareTimeStopStored(SPELL_DROWN) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, i6) && - GlobalSpellTargetCurrentHitPoints >= i30) + if(bRangeMediumValid && !AI_CompareTimeStopStored(SPELL_DROWN) && + !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, 6) && + GlobalSpellTargetCurrentHitPoints >= 30) { // Drown. level 6 (Druid) Up to 90% of current HP damage done. Fort save for none. - if(AI_ActionCastSpellRandom(SPELL_DROWN, SpellHostRanged, i70, GlobalSpellTarget, i16, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_DROWN, 70, GlobalSpellTarget, 16, FALSE)) return TRUE; } // Flesh to Stone is a good spell - petrify attack. // 70% chance to cast if we have it, and not immune to the save. - if(RangeMediumValid && !AI_CompareTimeStopStored(SPELL_FLESH_TO_STONE) && + if(bRangeMediumValid && !AI_CompareTimeStopStored(SPELL_FLESH_TO_STONE) && !AI_GetSpellTargetImmunity(GlobalImmunityPetrify) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, i6)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, 6)) { // Flesh to Stone. - Petrifies a target on a fortitude save. - if(AI_ActionCastSpellRandom(SPELL_FLESH_TO_STONE, SpellHostRanged, i60, GlobalSpellTarget, i16, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_FLESH_TO_STONE, 60, GlobalSpellTarget, 16, FALSE)) return TRUE; } // Evil Blight. This is an AOE curse, but note that we cannot check // if an AOE already has it. - if(RangeMediumValid && !AI_CompareTimeStopStored(AI_SPELL_EVIL_BLIGHT) && + if(bRangeMediumValid && !AI_CompareTimeStopStored(AI_SPELL_EVIL_BLIGHT) && !AI_GetSpellTargetImmunity(GlobalImmunityCurse) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i6)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 6)) { // Evil Blight. Level 6 (Mage) -3 Curse to all in AOE (Will save) - if(AI_ActionCastSpellRandom(AI_SPELL_EVIL_BLIGHT, SpellHostTouch, i60, GlobalSpellTarget, i16, FALSE, ItemHostTouch)) return TRUE; + if(AI_ActionCastSpellRandom(AI_SPELL_EVIL_BLIGHT, 60, GlobalSpellTarget, 16, FALSE)) return TRUE; } // Bigby's Forceful hand. No need to check for bullrush attack. It // will knockdown and daze a target :-) Quite powerful as no save. // (Count as stun for immunity - that is anyting that stops them moving (daze included)) // - Should affect mind-immune people. Bioware will fix this, been told. No mind check - if(RangeLongValid && !GetHasSpellEffect(SPELL_BIGBYS_FORCEFUL_HAND, GlobalSpellTarget) && + if(bRangeLongValid && !GetHasSpellEffect(SPELL_BIGBYS_FORCEFUL_HAND, GlobalSpellTarget) && !AI_CompareTimeStopStored(SPELL_BIGBYS_FORCEFUL_HAND) && !AI_GetSpellTargetImmunity(GlobalImmunityStun)) { // Bigby's Forceful Hand. Level 6 (Mage) Bullrush to make the target Knockdowned and Dazed all in one. - if(AI_ActionCastSpellRandom(SPELL_BIGBYS_FORCEFUL_HAND, SpellHostRanged, i30, GlobalSpellTarget, i16, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_BIGBYS_FORCEFUL_HAND, 30, GlobalSpellTarget, 16, FALSE)) return TRUE; } // Single spell override backup casting - if(SingleSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; + if(bSingleSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; } // AOE spells - including the now-infamous Isaac's Greater Missile Storm! // [Acid Fog] - Acid damage in an AOE, including slow in AOE. 1d6/round in fog. @@ -8681,89 +8640,89 @@ XXXX[Legend Lore] - Lots of lore. Never cast. // long anyway!) or better (more in AOE) targets. 80% chance of casting. // Cast at ground. - if(RangeLongValid && GlobalNormalSpellsNoEffectLevel < i6) + if(bRangeLongValid && GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < 6) { // Isaac's Greater Missile Storm. Level 6 (Mage) !!! To 20 missiles, 2d6 Damage/Missile, hits only enemies in AOE around target. No save! - if(AI_ActionCastSpellRandom(SPELL_ISAACS_GREATER_MISSILE_STORM, SpellHostRanged, i70, GlobalSpellTarget, i16, TRUE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_ISAACS_GREATER_MISSILE_STORM, 70, GlobalSpellTarget, 16, TRUE)) return TRUE; } // Chain lightning is a decent-damage, no, good-damage spell, like fireball, // but a better way - it damages all enemies only :-D // Because it damages enemies only, we aim it at the current spell target, - // because it needs a target. - if(RangeLongValid && !AI_CompareTimeStopStored(SPELL_CHAIN_LIGHTNING) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_REFLEX, i6)) + // because it needs a target (and it must be a seen one!) + if(bRangeLongValid && GlobalSeenSpell && + !AI_CompareTimeStopStored(SPELL_CHAIN_LIGHTNING) && + !AI_SaveImmuneSpellTarget(SAVING_THROW_REFLEX, 6)) { // Collosal area, long range, reflex throw. 60% chance of casting. // Chain Lightning. Level 6 (Mage). Target enemies only. Up to 20d6 for primary, 10d6 for secondary in reflex electical damage. - if(AI_ActionCastSpellRandom(SPELL_CHAIN_LIGHTNING, SpellHostAreaDis, i50, GlobalSpellTarget, i16, FALSE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_CHAIN_LIGHTNING, 50, GlobalSpellTarget, 16, FALSE)) return TRUE; } // Blade Barrier - lots of damage, up to 20d6 damage to targets :-) // Wierd shape, however. It is 2M across one way, but 10M long, retangle. // We just target a large (5.0) area, and as long as it hits an enemy object, // it is great! - if(SpellHostAreaInd && RangeMediumValid && - !AI_CompareTimeStopStored(SPELL_BLADE_BARRIER) && - (GetHasSpell(SPELL_BLADE_BARRIER) || SpellHostAreaInd == SPELL_BLADE_BARRIER)) + if(bRangeMediumValid && !AI_CompareTimeStopStored(SPELL_BLADE_BARRIER) && + GetHasSpell(SPELL_BLADE_BARRIER)) { // 20M medium range, large area we'll say. Reflex save - oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_LARGE, i6, SAVING_THROW_REFLEX); + oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_LARGE, 6, SAVING_THROW_REFLEX); // Is it valid? 50% chance of casting. if(GetIsObjectValid(oAOE)) { // Blade Barrier. Level 6 (Cleric) Lots of spikes = Lots of damage (to 20d6). Piercing, relfex saves. - if(AI_ActionCastSpellRandom(SPELL_BLADE_BARRIER, SpellHostAreaInd, i40, oAOE, i16, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_BLADE_BARRIER, 40, oAOE, 16, TRUE)) return TRUE; } } // Level 6 summons - if(IsFirstRunThrough && GlobalCanSummonSimilarLevel <= i6 && - (GlobalOurHitDice <= i16 || GlobalMeleeAttackers <= i2)) + if(bFirstRunThrough && GlobalCanSummonSimilarLevel <= 6 && + (GlobalOurHitDice <= 16 || GlobalMeleeAttackers <= 2)) { // Summon Monster VI (6). Level 6 (Most classes) Dire Tiger - if(AI_ActionCastSummonSpell(SPELL_SUMMON_CREATURE_VI, i16, i6)) return TRUE; + if(AI_ActionCastSummonSpell(SPELL_SUMMON_CREATURE_VI, 16, 6)) return TRUE; // Planar Binding. Level 6 (Mage). Summons Subbucus (Evil), Hound Arcon (Good), Green Slaad (Neutral). AI won't target outsiders specifically. - if(AI_ActionCastSummonSpell(SPELL_PLANAR_BINDING, i16, i6)) return TRUE; + if(AI_ActionCastSummonSpell(SPELL_PLANAR_BINDING, 16, 6)) return TRUE; // Create Undead. Level 6 (Cleric) 8 (Mage). Creates a lowish undead to aid the caster. - if(AI_ActionCastSummonSpell(SPELL_SUMMON_CREATURE_VI, i16, i6)) return TRUE; + if(AI_ActionCastSummonSpell(SPELL_SUMMON_CREATURE_VI, 16, 6)) return TRUE; // Planar Ally. Level 6 (Cleric) - Waoh! Same as planar binding! Exactly! :-) (except no stopping outsiders) - if(AI_ActionCastSummonSpell(SPELL_PLANAR_ALLY, i16, i6)) return TRUE; + if(AI_ActionCastSummonSpell(SPELL_PLANAR_ALLY, 16, 6)) return TRUE; } // Multi spell override backup casting - if(MultiSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; + if(bMultiSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; // Lastly, the single-target spells again :-) - if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < i6) + if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < 6) { // Flesh to Stone is a good spell - petrify attack. // 50% chance to cast if we have it, and not immune to the save. - if(RangeMediumValid && !AI_CompareTimeStopStored(SPELL_FLESH_TO_STONE) && + if(bRangeMediumValid && !AI_CompareTimeStopStored(SPELL_FLESH_TO_STONE) && !AI_GetSpellTargetImmunity(GlobalImmunityPetrify) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, i6)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, 6)) { // Flesh to Stone. - Petrifies a target on a fortitude save. - if(AI_ActionCastSpellRandom(SPELL_FLESH_TO_STONE, SpellHostRanged, i40, GlobalSpellTarget, i16, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_FLESH_TO_STONE, 40, GlobalSpellTarget, 16, FALSE)) return TRUE; } // Evil Blight. This is an AOE curse, but note that we cannot check // if an AOE already has it. - if(RangeMediumValid && !AI_CompareTimeStopStored(AI_SPELL_EVIL_BLIGHT) && + if(bRangeMediumValid && !AI_CompareTimeStopStored(AI_SPELL_EVIL_BLIGHT) && !AI_GetSpellTargetImmunity(GlobalImmunityCurse) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i6)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 6)) { // Evil Blight. Level 6 (Mage) -3 Curse to all in AOE (Will save) - if(AI_ActionCastSpellRandom(AI_SPELL_EVIL_BLIGHT, SpellHostTouch, i30, GlobalSpellTarget, i16, FALSE, ItemHostTouch)) return TRUE; + if(AI_ActionCastSpellRandom(AI_SPELL_EVIL_BLIGHT, 30, GlobalSpellTarget, 16, FALSE)) return TRUE; } // Bigby's Forceful hand. No need to check for bullrush attack. It // will knockdown and daze a target :-) Quite powerful as no save. // (Count as stun for immunity - that is anyting that stops them moving (daze included)) // - Should affect mind-immune people. Bioware will fix this, been told. No mind check - if(RangeLongValid && !GetHasSpellEffect(SPELL_BIGBYS_FORCEFUL_HAND, GlobalSpellTarget) && + if(bRangeLongValid && !GetHasSpellEffect(SPELL_BIGBYS_FORCEFUL_HAND, GlobalSpellTarget) && !AI_CompareTimeStopStored(SPELL_BIGBYS_FORCEFUL_HAND) && !AI_GetSpellTargetImmunity(GlobalImmunityStun)) { // Bigby's Forceful Hand. Level 6 (Mage) Bullrush to make the target Knockdowned and Dazed all in one. - if(AI_ActionCastSpellRandom(SPELL_BIGBYS_FORCEFUL_HAND, SpellHostRanged, i20, GlobalSpellTarget, i16, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_BIGBYS_FORCEFUL_HAND, 20, GlobalSpellTarget, 16, FALSE)) return TRUE; } } @@ -8773,16 +8732,15 @@ XXXX[Legend Lore] - Lots of lore. Never cast. // Acid fog - slow, and damage in acid fog. // Decent..but ...well, its alright :-) // THIS is spell 0 spell :-) we cast 100% and no backup casting. - if(RangeLongValid && SpellHostAreaInd && !GlobalInTimeStop && - (GetHasSpell(SPELL_ACID_FOG) || SpellHostAreaInd == SPELL_ACID_FOG)) + if(bRangeLongValid && !GlobalInTimeStop && GetHasSpell(SPELL_ACID_FOG)) { // 40M spell range, 5M radius (large) fortitude save, but doesn't stop damage. - oAOE = AI_GetBestAreaSpellTarget(fLongRange, RADIUS_SIZE_LARGE, i6); + oAOE = AI_GetBestAreaSpellTarget(fLongRange, RADIUS_SIZE_LARGE, 6); // Is it valid? 40% chance of casting. if(GetIsObjectValid(oAOE)) { // Acid Fog. Level 6 (Mage) Acid damage in an AOE, including slow in AOE. 1d6/round in fog. - if(AI_ActionCastSpell(SPELL_ACID_FOG, SpellHostAreaInd, oAOE, i16, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpell(SPELL_ACID_FOG, oAOE, 16, TRUE)) return TRUE; } } @@ -8845,94 +8803,80 @@ H [Monsterous Regeneration] - +3 Regeneration for CasterLevel/2 + 1. //::55555555555555555555555555555555555555555555555555555555555555555555555555*/ // Jump out if we don't want to cast level 5 spells. - if(iLowestSpellLevel > i5) return FALSE; + if(nLowestSpellLevel > 5) return FALSE; // Monsterous Regeneration if we have 70% or less HP - if(IsFirstRunThrough && GlobalOurPercentHP <= i70 && + if(bFirstRunThrough && GlobalOurPercentHP <= 70 && !GetHasSpellEffect(SPELL_MONSTROUS_REGENERATION)) { // Monsterous Regeneration. Level 5 (Cleric/Druid) +3 Regeneration for CasterLevel/2 + 1. - if(AI_ActionCastSpell(SPELL_MONSTROUS_REGENERATION, SpellProSinTar, OBJECT_SELF, i15, FALSE, ItemProSinTar)) return TRUE; + if(AI_ActionCastSpell(SPELL_MONSTROUS_REGENERATION, OBJECT_SELF, 15, FALSE)) return TRUE; } // Spell reistance - feel the vibes :-) Cast above also if mages around, or need spell protections. - if(IsFirstRunThrough && !AI_GetAIHaveSpellsEffect(GlobalHasSpellResistanceSpell)) + if(bFirstRunThrough && !AI_GetAIHaveSpellsEffect(GlobalHasSpellResistanceSpell)) { // Spell Resistance. Level 5 (Druid/Cleric) 12 + Caster Level in spell resistance. - if(AI_ActionCastSpell(SPELL_SPELL_RESISTANCE, SpellProSinTar, OBJECT_SELF, i15, FALSE, ItemProSinTar)) return TRUE; + if(AI_ActionCastSpell(SPELL_SPELL_RESISTANCE, OBJECT_SELF, 15, FALSE)) return TRUE; } // Dispel level 3 protections (Hastes, regenerates, tensors...) - if(RangeMediumValid && !GlobalInTimeStop)// All medium spells. - { - // Dispel number need to be 3 for breach - if(GlobalDispelTargetHighestBreach >= i3) - { - // Wrapers Greater and Lesser Breach. - if(AI_ActionCastBreach()) return TRUE; - } - // Dispel >= 3 - if(GlobalDispelTargetHighestDispel >= i3) - { - // Wrappers the dispel spells - if(AI_ActionCastDispel()) return TRUE; - } - } + if(AI_ActionAttemptDispel(3, bRangeMediumValid)) return TRUE; // Battletide is not bad. Level 5 (Cleric) // - Oddly classed under SpellHostAreaDis - if(IsFirstRunThrough && !GetHasSpellEffect(SPELL_BATTLETIDE)) + if(bFirstRunThrough && !GetHasSpellEffect(SPELL_BATTLETIDE)) { // Battletide. Level 5 (Cleric). -2 Attack/Saves/damage to enemies who come in. +2 to same for caster. - if(AI_ActionCastSpell(SPELL_BATTLETIDE, SpellHostAreaDis, GlobalSpellTarget, i15, FALSE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpell(SPELL_BATTLETIDE, GlobalSpellTarget, 15, FALSE)) return TRUE; } // Giant Hurl Rock - if(RangeLongValid && GlobalSeenSpell) + if(bRangeLongValid && GlobalSeenSpell) { // Giant Hurl Rock is for d6(HD/5) + Str. Damage. Huge AOE and bludgeoning damage. - if(AI_ActionCastSpell(AI_SPELLABILITY_GIANT_HURL_ROCK, SpellHostRanged, GlobalSpellTarget, FALSE, TRUE)) return TRUE; + if(AI_ActionCastSpell(AI_SPELLABILITY_GIANT_HURL_ROCK, GlobalSpellTarget, FALSE, TRUE)) return TRUE; // Battle Boulder Toss - from Campaign, but is an ability too. d6(3)+5 Bud dam. - if(AI_ActionCastSpell(AI_SPELLABILITY_BATTLE_BOULDER_TOSS, SpellHostRanged, GlobalSpellTarget, FALSE, TRUE)) return TRUE; + if(AI_ActionCastSpell(AI_SPELLABILITY_BATTLE_BOULDER_TOSS, GlobalSpellTarget, FALSE, TRUE)) return TRUE; } // Monster cones - these ignore the GlobalNormalSpellsNoEffectLevel toggle. - if(RangeShortValid) + if(bRangeShortValid) { // Small-distance, cone-based spell. // - Take it as no level, and no save. These scale up with the HD of the // monster, so on average should be used all the time. - oAOE = AI_GetBestAreaSpellTarget(fShortRange, f11, FALSE, SAVING_THROW_ALL, SHAPE_SPELLCONE, GlobalFriendlyFireFriendly); + oAOE = AI_GetBestAreaSpellTarget(fShortRange, 11.0, FALSE, SAVING_THROW_ALL, SHAPE_SPELLCONE, GlobalFriendlyFireFriendly); // Is it valid? 50% for each. if(GetIsObjectValid(oAOE)) { // Cones // Uses the AOE object for cone of cold. // These are the "Cones". Appropriate to put it here, don'tca think? - for(iCnt = SPELLABILITY_CONE_ACID; iCnt <= SPELLABILITY_CONE_SONIC; iCnt++) + for(nCnt = SPELLABILITY_CONE_ACID; nCnt <= SPELLABILITY_CONE_SONIC; nCnt++) { - if(AI_ActionCastSpellRandom(iCnt, SpellHostAreaInd, i40, oAOE, FALSE, TRUE)) return TRUE; + if(AI_ActionCastSpellRandom(nCnt, 40, oAOE, FALSE, TRUE)) return TRUE; } - if(AI_ActionCastSpellRandom(SPELLABILITY_HELL_HOUND_FIREBREATH, SpellHostAreaInd, i40, oAOE, FALSE, TRUE)) return TRUE; + if(AI_ActionCastSpellRandom(SPELLABILITY_HELL_HOUND_FIREBREATH, 40, oAOE, FALSE, TRUE)) return TRUE; } } // Mind fog cast here, lower prioritory, if the spell target has high will. // Long range. - if(RangeLongValid && (GlobalSpellTargetWill / i2 >= GlobalSpellAbilityModifier)) + if(bRangeLongValid && (GlobalSpellTargetWill / 2 >= GlobalSpellAbilityModifier)) { // Mind Fog. Level 5 (Mage/Bard) - Minus 10 to all will saves within the AOE. - if(AI_ActionCastSpell(SPELL_MIND_BLANK, SpellHostAreaInd, GlobalSpellTarget, i15, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpell(SPELL_MIND_BLANK, GlobalSpellTarget, 15, TRUE)) return TRUE; } // Feeblemind is Good if in medium range, and is a mage :-) - if(RangeMediumValid && GlobalSeenSpell && - GetLevelByClass(CLASS_TYPE_WIZARD, GlobalSpellTarget) >= GlobalOurHitDice/i4) + if(bRangeMediumValid && GlobalSeenSpell && + GetLevelByClass(CLASS_TYPE_WIZARD, GlobalSpellTarget) >= GlobalOurHitDice/4) { // Feeblemind. Level 5 (Mage) 1d4/4 caster levels in intelligence decrease, if fail will save. - if(AI_ActionCastSpell(SPELL_FEEBLEMIND, SpellHostRanged, GlobalSpellTarget, i15, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpell(SPELL_FEEBLEMIND, GlobalSpellTarget, 15, FALSE)) return TRUE; } // Randomise one of the many level 5 spells. // AOE: @@ -8951,46 +8895,46 @@ H [Monsterous Regeneration] - +3 Regeneration for CasterLevel/2 + 1. // Is it best to target with single-target spells first? Some pretty // good level 5 spells - Hold monster and Slay Living are useful :-) // 60-70% if favourable. - if(SingleSpellsFirst && GlobalNormalSpellsNoEffectLevel < i5) + if(bSingleSpellsFirst && GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < 5) { // Slay living. 60% chance to cast - it is a touch spell. - if(RangeTouchValid && !AI_CompareTimeStopStored(SPELL_SLAY_LIVING) && + if(bRangeTouchValid && !AI_CompareTimeStopStored(SPELL_SLAY_LIVING) && !AI_GetSpellTargetImmunity(GlobalImmunityDeath) && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, i5)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, 5)) { // Slay Living. Level 5 (Cleric). Touch attack + Fortitude Save, creature dies, else d6(3) negative damage. - if(AI_ActionCastSpellRandom(SPELL_SLAY_LIVING, SpellHostRanged, i50, GlobalSpellTarget, i15, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_SLAY_LIVING, 50, GlobalSpellTarget, 15, FALSE)) return TRUE; } // Hold monster - Paralyze's an enemy monster (any race) // Decent enough, if not stunned already - 60% - if(RangeMediumValid && !AI_CompareTimeStopStored(SPELL_HOLD_MONSTER) && + if(bRangeMediumValid && !AI_CompareTimeStopStored(SPELL_HOLD_MONSTER) && !AI_GetSpellTargetImmunity(GlobalImmunityStun) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i5)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 5)) { // Hold monster - Paralyze's an enemy monster (any race) - if(AI_ActionCastSpellRandom(SPELL_HOLD_MONSTER, SpellHostRanged, i50, GlobalSpellTarget, i15, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_HOLD_MONSTER, 50, GlobalSpellTarget, 15, FALSE)) return TRUE; } // Inferno - the Druids Acid Arrow (more damage, however, each round). // ---- No save!! - if(RangeShortValid && !GetHasSpellEffect(SPELL_INFERNO)) + if(bRangeShortValid && !GetHasSpellEffect(SPELL_INFERNO)) { // Inferno. Level 5 (Druid) 2d6 Fire damage/round like acid arrow. No save, only SR. - if(AI_ActionCastSpellRandom(SPELL_INFERNO, SpellHostRanged, i50, GlobalSpellTarget, i15, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_INFERNO, 50, GlobalSpellTarget, 15, FALSE)) return TRUE; } // Bigby's Interposing Hand. No save, only SR. -10 attack rolls for them // is good if they have highish BAB. Check here. // (Count as stun for immunity - that is anyting that stops them moving (daze included)) // - Should affect mind-immune people. Bioware will fix this, been told. No mind check - if(RangeLongValid && !AI_CompareTimeStopStored(SPELL_BIGBYS_INTERPOSING_HAND) && + if(bRangeLongValid && !AI_CompareTimeStopStored(SPELL_BIGBYS_INTERPOSING_HAND) && !GetHasSpellEffect(SPELL_BIGBYS_INTERPOSING_HAND, GlobalSpellTarget) && - GetBaseAttackBonus(GlobalSpellTarget) >= GlobalOurHitDice/i2) + GetBaseAttackBonus(GlobalSpellTarget) >= GlobalOurHitDice/2) { // Bigby's Interposing Hand. Level 5 (Mage) No save, only SR. -10 attack rolls for target - if(AI_ActionCastSpellRandom(SPELL_BIGBYS_INTERPOSING_HAND, SpellHostRanged, i50, GlobalSpellTarget, i16, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_BIGBYS_INTERPOSING_HAND, 50, GlobalSpellTarget, 16, FALSE)) return TRUE; } // Single spell override backup casting - if(SingleSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; + if(bSingleSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; } // AOE: // [Cloudkill] - Acid damage, and kills level 7s or below. AOE. @@ -9002,135 +8946,130 @@ H [Monsterous Regeneration] - +3 Regeneration for CasterLevel/2 + 1. // Firebrand - good, because it hits only enemies (up to 15! thats plenty) // and 1d6 damage each. Mainly, it doesn't hit allies :-D - if(SpellHostRanged && RangeMediumValid && !AI_CompareTimeStopStored(SPELL_FIREBRAND) && - (GetHasSpell(SPELL_FIREBRAND) || ItemHostRanged == SPELL_FIREBRAND)) + if(bRangeMediumValid && !AI_CompareTimeStopStored(SPELL_FIREBRAND) && + GetHasSpell(SPELL_FIREBRAND)) { // 20M medium range, colossal area. Reflex save - doesn't hit allies too. - oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_COLOSSAL, i5, SAVING_THROW_REFLEX); + oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_COLOSSAL, 5, SAVING_THROW_REFLEX); // Is it valid? 60% chance of casting. if(GetIsObjectValid(oAOE)) { // Firebrand Level 5 (Mage) Missile storm - hits enemies up to caster level (max 15) for 1d6 fire reflex damage. - if(AI_ActionCastSpellRandom(SPELL_FIREBRAND, SpellHostRanged, i50, oAOE, i15, TRUE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_FIREBRAND, 50, oAOE, 15, TRUE)) return TRUE; } } // Ball lightning - Medium spell, and missile storm. We cast this at the target. - if(RangeMediumValid && GlobalSeenSpell && - !AI_SaveImmuneSpellTarget(SAVING_THROW_REFLEX, i5)) + if(bRangeMediumValid && GlobalSeenSpell && + !AI_SaveImmuneSpellTarget(SAVING_THROW_REFLEX, 5)) { // Ball Lightning. Level 5 (Mage) 1d6/missile, to 15 missiles. Reflex based. Cast at singal target (like missile storms) - if(AI_ActionCastSpellRandom(SPELL_BALL_LIGHTNING, SpellHostAreaInd, i40, oAOE, i15, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_BALL_LIGHTNING, 40, oAOE, 15, TRUE)) return TRUE; } - // (Shades) Cone of Cold. Shades = Never hits allies (Still same saves ETC). - if(SpellHostAreaInd && RangeShortValid && - (GetHasSpell(SPELL_SHADES_CONE_OF_COLD) || ItemHostAreaInd == SPELL_SHADES_CONE_OF_COLD || - GetHasSpell(SPELL_CONE_OF_COLD) || ItemHostAreaInd == SPELL_CONE_OF_COLD)) + // (Shades) Cone of Cold. Later patches lets Shades hit allies (grr) + if(bRangeShortValid && + (GetHasSpell(SPELL_SHADES_CONE_OF_COLD) || GetHasSpell(SPELL_CONE_OF_COLD))) { // Small-distance, cone-based spell. Reflex save - oAOE = AI_GetBestAreaSpellTarget(fShortRange, f11, i5, SAVING_THROW_REFLEX, SHAPE_SPELLCONE); + oAOE = AI_GetBestAreaSpellTarget(fShortRange, 11.0, 5, SAVING_THROW_REFLEX, SHAPE_SPELLCONE, GlobalFriendlyFireFriendly); // Is it valid? 100% chance of casting (Can't be bothered to create a special random version of SubSpell) if(GetIsObjectValid(oAOE)) { - // Cone of Cold. Level 5 (Mage). Cone of damage, up to 15d6 to those in the cone. Reflex for none. - // Shades vesion is great though - never affects allies. - if(AI_ActionCastSubSpell(SPELL_SHADES_CONE_OF_COLD, SpellHostAreaInd, oAOE, i17, TRUE, ItemHostAreaInd)) return TRUE; + // Shades Cone of Cold. Level 7 (Mage). Cone of damage, up to 15d6 to those in the cone. Reflex for none. + if(AI_ActionCastSpell(SPELL_SHADES_CONE_OF_COLD, oAOE, 17, TRUE, TRUE)) return TRUE; // Cone of Cold. Level 5 (Mage). Cone of damage, up to 15d6 to those in the cone. Reflex for none. - if(AI_ActionCastSpellRandom(SPELL_CONE_OF_COLD, SpellHostAreaInd, i40, oAOE, i15, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_CONE_OF_COLD, 40, oAOE, 15, TRUE)) return TRUE; } } // Flame Strike - Up to 15d6 in Fire + Divine damage. Reflex based. Medium area. - if(SpellHostAreaInd && RangeMediumValid && - (GetHasSpell(SPELL_FLAME_STRIKE) || ItemHostAreaInd == SPELL_FLAME_STRIKE)) + if(bRangeMediumValid && GetHasSpell(SPELL_FLAME_STRIKE)) { // Small-distance, cone-based spell. Reflex save - oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_MEDIUM, i5, SAVING_THROW_REFLEX, SHAPE_SPHERE, GlobalFriendlyFireFriendly); + oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_MEDIUM, 5, SAVING_THROW_REFLEX, SHAPE_SPHERE, GlobalFriendlyFireFriendly); // Is it valid? 50% chance of casting. if(GetIsObjectValid(oAOE)) { // Flame Strike. Level 5 (Cleric) Up to 15d6 in Fire + Divine damage. Reflex based. Medium area. - if(AI_ActionCastSpellRandom(SPELL_FLAME_STRIKE, SpellHostAreaInd, i40, oAOE, i15, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_FLAME_STRIKE, 40, oAOE, 15, TRUE)) return TRUE; } } // Circle of Doom - 1d8 + 1/caster level in negative damage - if(SpellHostAreaDis && RangeMediumValid && - (GetHasSpell(SPELL_CIRCLE_OF_DOOM) || ItemHostAreaDis == SPELL_CIRCLE_OF_DOOM)) + if(bRangeMediumValid && GetHasSpell(SPELL_CIRCLE_OF_DOOM)) { // Shpere, medium and reflex save. - oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_MEDIUM, i5, SAVING_THROW_REFLEX, SHAPE_SPHERE, GlobalFriendlyFireFriendly); + oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_MEDIUM, 5, SAVING_THROW_REFLEX, SHAPE_SPHERE, GlobalFriendlyFireFriendly); // Is it valid? 50% chance of casting. if(GetIsObjectValid(oAOE)) { // Circle of Doom. Level 5 (Cleric) 1d8 + 1/caster level in negative damage - if(AI_ActionCastSpellRandom(SPELL_CIRCLE_OF_DOOM, SpellHostAreaDis, i40, oAOE, i15, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_CIRCLE_OF_DOOM, 40, oAOE, 15, TRUE)) return TRUE; } } // Cloudkill. Acid damage, and kills level 7s or below. AOE. Quite good persistant damage. - if(SpellHostAreaInd && RangeLongValid && - (GetHasSpell(SPELL_CLOUDKILL) || ItemHostAreaInd == SPELL_CLOUDKILL)) + if(bRangeLongValid && GetHasSpell(SPELL_CLOUDKILL)) { // No save (fortitude only halfs damage) but large (5M across) AOE - and long range - oAOE = AI_GetBestAreaSpellTarget(fLongRange, RADIUS_SIZE_LARGE, i5, FALSE, SHAPE_SPHERE, GlobalFriendlyFireFriendly); + oAOE = AI_GetBestAreaSpellTarget(fLongRange, RADIUS_SIZE_LARGE, 5, FALSE, SHAPE_SPHERE, GlobalFriendlyFireFriendly); // Is it valid? 50% chance of casting. if(GetIsObjectValid(oAOE)) { // Cloudkill. Level 5 (Mage) Acid damage, and kills level 7s or below. AOE. Quite good persistant damage. - if(AI_ActionCastSpellRandom(SPELL_CLOUDKILL, SpellHostAreaInd, i40, oAOE, i15, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_CLOUDKILL, 40, oAOE, 15, TRUE)) return TRUE; } } // Multi spell override backup casting - if(MultiSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; + if(bMultiSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; // Level 5 summons - if(IsFirstRunThrough && GlobalCanSummonSimilarLevel <= i5 && - (GlobalOurHitDice <= i14 || GlobalMeleeAttackers <= i2)) + if(bFirstRunThrough && GlobalCanSummonSimilarLevel <= 5 && + (GlobalOurHitDice <= 14 || GlobalMeleeAttackers <= 2)) { // Summon Monster V (5). Level 5 (Most classes) Dire Bear - if(AI_ActionCastSummonSpell(SPELL_SUMMON_CREATURE_V, i15, i5)) return TRUE; + if(AI_ActionCastSummonSpell(SPELL_SUMMON_CREATURE_V, 15, 5)) return TRUE; // Lesser Planar Binding. Level 5 (Mage). Summons Imp (Evil), Slaad Red (Neutral), Lantern Archon (Good) - if(AI_ActionCastSummonSpell(SPELL_LESSER_PLANAR_BINDING, i15, i5)) return TRUE; + if(AI_ActionCastSummonSpell(SPELL_LESSER_PLANAR_BINDING, 15, 5)) return TRUE; } // Single spells again. - if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < i5) + if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < 5) { // Slay living. 60% chance to cast - it is a touch spell. - if(RangeTouchValid && !AI_CompareTimeStopStored(SPELL_SLAY_LIVING) && + if(bRangeTouchValid && !AI_CompareTimeStopStored(SPELL_SLAY_LIVING) && !AI_GetSpellTargetImmunity(GlobalImmunityDeath) && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, i5)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, 5)) { // Slay Living. Level 5 (Cleric). Touch attack + Fortitude Save, creature dies, else d6(3) negative damage. - if(AI_ActionCastSpellRandom(SPELL_SLAY_LIVING, SpellHostRanged, i30, GlobalSpellTarget, i15, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_SLAY_LIVING, 30, GlobalSpellTarget, 15, FALSE)) return TRUE; } // Hold monster - Paralyze's an enemy monster (any race) // Decent enough, if not stunned already - 60% - if(RangeMediumValid && !AI_CompareTimeStopStored(SPELL_HOLD_MONSTER) && + if(bRangeMediumValid && !AI_CompareTimeStopStored(SPELL_HOLD_MONSTER) && !AI_GetSpellTargetImmunity(GlobalImmunityStun) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i5)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 5)) { // Hold monster - Paralyze's an enemy monster (any race) - if(AI_ActionCastSpellRandom(SPELL_HOLD_MONSTER, SpellHostRanged, i20, GlobalSpellTarget, i15, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_HOLD_MONSTER, 20, GlobalSpellTarget, 15, FALSE)) return TRUE; } // Inferno - the Druids Acid Arrow (more damage, however, each round). // ---- No save!! - if(RangeShortValid) + if(bRangeShortValid) { // Inferno. Level 5 (Druid) 2d6 Fire damage/round like acid arrow. No save, only SR. - if(AI_ActionCastSpellRandom(SPELL_INFERNO, SpellHostRanged, i20, GlobalSpellTarget, i15, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_INFERNO, 20, GlobalSpellTarget, 15, FALSE)) return TRUE; } // Bigby's Interposing Hand. No save, only SR. -10 attack rolls for them // is good if they have highish BAB. Check here. // (Count as stun for immunity - that is anyting that stops them moving (daze included)) // - Should affect mind-immune people. Bioware will fix this, been told. No mind check - if(RangeLongValid && !AI_CompareTimeStopStored(SPELL_BIGBYS_INTERPOSING_HAND) && + if(bRangeLongValid && !AI_CompareTimeStopStored(SPELL_BIGBYS_INTERPOSING_HAND) && !GetHasSpellEffect(SPELL_BIGBYS_INTERPOSING_HAND, GlobalSpellTarget) && - GetBaseAttackBonus(GlobalSpellTarget) >= GlobalOurHitDice/i2) + GetBaseAttackBonus(GlobalSpellTarget) >= GlobalOurHitDice/2) { // Bigby's Interposing Hand. Level 5 (Mage) No save, only SR. -10 attack rolls for target - if(AI_ActionCastSpellRandom(SPELL_BIGBYS_INTERPOSING_HAND, SpellHostRanged, i20, GlobalSpellTarget, i16, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_BIGBYS_INTERPOSING_HAND, 20, GlobalSpellTarget, 16, FALSE)) return TRUE; } } @@ -9143,7 +9082,7 @@ H [Monsterous Regeneration] - +3 Regeneration for CasterLevel/2 + 1. Thoughts -Quite a few decent enough spells here. Nothing to catch your eye, except maybe the overused Ice Storm or Wall of Fire. hammer of the gods is a good clerical AOE spell and phantasmal killer is probably the first - Instant-death spells (but requires 2 saves1). + Instant-death spells (but requires 2 save"1"). AOE: [Confusion] - confuse people Vs Mind Will in an area. @@ -9170,7 +9109,7 @@ S [Inflict Critical Wounds] - 3d8 + 1/caster level to +20, in negative energy. [Elemental Shield] +50% Cold/Fire resistance. 1d6 + Caster level reflected damage to melee attackers. X [Improved Invisibility] +50% consealment, invisiblity (unseen) until hostile action. Cast above to at least conseal [Minor Globe of Invulnerability] - 0/1/2/3 level hostile spells immune to. - [Stoneskin] - 10/+5 DR. We cast this here, sorceror behaviour and backup for greater stoneskin + [Stoneskin] - 10/+5 DR. We cast this here, sorceror behavnOur and backup for greater stoneskin [Death Ward] - Death Immunity - death magic. Summon: @@ -9189,32 +9128,35 @@ H X [Holy Sword] - Paladins sword gains the "Holy Avenger" property - +1d6 divin //::44444444444444444444444444444444444444444444444444444444444444444444444444*/ // Jump out if we don't want to cast level 4 spells. - if(iLowestSpellLevel > i4) return FALSE; + if(nLowestSpellLevel > 4) return FALSE; - if(IsFirstRunThrough) + if(bFirstRunThrough) { // Cast normal stoneskin to prepare for greater stoneskin going down. // as par greater stoneskin, we must also have used level 5, 6, 7 8 and 9 spells // anyway! That, and this is good for sorcerors. - if(!GetHasSpellEffect(SPELL_STONESKIN)) + if(!GetHasSpellEffect(SPELL_STONESKIN) && !GetHasSpellEffect(SPELL_SHADES_STONESKIN)) { + // Shades stoneskin. SPELL_SHADES_STONESKIN (Cast via. subspell) + if(AI_ActionCastSpell(SPELL_SHADES_STONESKIN, OBJECT_SELF, 16, FALSE, TRUE)) return TRUE; + // Stoneskin. Level 4 (Mage) 5 (Druid) 10/+5 phisical damage reduction - if(AI_ActionCastSpell(SPELL_STONESKIN, SpellProSinTar, OBJECT_SELF, i14, FALSE, ItemProSinTar, PotionPro)) return TRUE; + if(AI_ActionCastSpell(SPELL_STONESKIN, OBJECT_SELF, 14, FALSE)) return TRUE; } // Check for Arcane Archer feats here if(GetLevelByClass(CLASS_TYPE_ARCANE_ARCHER)) { // Arrow of death. DC20 or die. - if(AI_ActionUseFeatOnObject(FEAT_PRESTIGE_ARROW_OF_DEATH, GlobalSpellTarget)) return TRUE; + if(AI_ActionUseSpellLikeFeat(FEAT_PRESTIGE_ARROW_OF_DEATH, SPELLABILITY_AA_ARROW_OF_DEATH, GlobalSpellTarget)) return TRUE; // Fireball arrow - won't harm allies - if(AI_ActionUseFeatOnObject(FEAT_PRESTIGE_IMBUE_ARROW, GlobalSpellTarget)) return TRUE; + if(AI_ActionUseSpellLikeFeat(FEAT_PRESTIGE_IMBUE_ARROW, SPELLABILITY_AA_IMBUE_ARROW, GlobalSpellTarget)) return TRUE; // Seeker Arrow is cool - if(AI_ActionUseFeatOnObject(FEAT_PRESTIGE_SEEKER_ARROW_2, GlobalSpellTarget)) return TRUE; + if(AI_ActionUseSpellLikeFeat(FEAT_PRESTIGE_SEEKER_ARROW_2, SPELLABILITY_AA_SEEKER_ARROW_2, GlobalSpellTarget)) return TRUE; // Hail of arrows is neat - if(AI_ActionUseFeatOnObject(FEAT_PRESTIGE_HAIL_OF_ARROWS, GlobalSpellTarget)) return TRUE; + if(AI_ActionUseSpellLikeFeat(FEAT_PRESTIGE_HAIL_OF_ARROWS, SPELLABILITY_AA_HAIL_OF_ARROWS, GlobalSpellTarget)) return TRUE; // Seeker Arrow is cool - if(AI_ActionUseFeatOnObject(FEAT_PRESTIGE_SEEKER_ARROW_1, GlobalSpellTarget)) return TRUE; + if(AI_ActionUseSpellLikeFeat(FEAT_PRESTIGE_SEEKER_ARROW_1, SPELLABILITY_AA_SEEKER_ARROW_1, GlobalSpellTarget)) return TRUE; } // Elemental Shield is a good spell - reflected damage. It is normally @@ -9222,29 +9164,29 @@ H X [Holy Sword] - Paladins sword gains the "Holy Avenger" property - +1d6 divin // (EffectDamageShield()) // Elemental Shield. Level 5 (Mage) +50% Cold/Fire resistance. 1d6 + Caster level reflected damage to melee attackers. - // (Use this but with imput i4) - if(AI_SpellWrapperShieldProtections(i4)) return TRUE; + // (Use this but with Input 4) + if(AI_SpellWrapperShieldProtections(4)) return TRUE; // Minor globe backup casting. - if(AI_SpellWrapperGlobeProtections(iLowestSpellLevel)) return TRUE; + if(AI_SpellWrapperGlobeProtections(nLowestSpellLevel)) return TRUE; // Not bad, immunity to death/ // - Might add in opposing casting if they start casting death spells. if(!AI_GetAIHaveSpellsEffect(GlobalHasDeathWardSpell)) { // Death Ward. Level 4 (Cleric/Paladin) 5 (Druid). Immunity to death (Death-based spells nromally, like Wail). - if(AI_ActionCastSpell(SPELL_DEATH_WARD, SpellEnhSinTar, OBJECT_SELF, i14, FALSE, ItemEnhSinTar, PotionEnh)) return TRUE; + if(AI_ActionCastSpell(SPELL_DEATH_WARD, OBJECT_SELF, 14, FALSE)) return TRUE; } // Some lower end ally buffs // Spell Resistance. - if(AI_ActionCastAllyBuffSpell(f10, i60, SPELL_SPELL_RESISTANCE)) return TRUE; + if(AI_ActionCastAllyBuffSpell(10.0, 60, SPELL_SPELL_RESISTANCE)) return TRUE; - if(GetBaseAttackBonus(GlobalSpellTarget) < GlobalSpellTargetHitDice - i2) + if(GetBaseAttackBonus(GlobalSpellTarget) < GlobalSpellTargetHitDice - 2) { // Death Ward if we can see an enemy spellcaster. - if(AI_ActionCastAllyBuffSpell(f10, i60, SPELL_DEATH_WARD)) return TRUE; + if(AI_ActionCastAllyBuffSpell(10.0, 60, SPELL_DEATH_WARD)) return TRUE; } } @@ -9253,7 +9195,7 @@ H X [Holy Sword] - Paladins sword gains the "Holy Avenger" property - +1d6 divin // normally even mages have a +X to attack, this provides a good indicator // if we are going to easy, or very easily, hit the enemy. // - Clerics, Druids and Bards must be able to hit even better then normal. - if(IsFirstRunThrough && !SRA && + if(bFirstRunThrough && !SRA && GlobalOurChosenClass != CLASS_TYPE_WIZARD && GlobalOurChosenClass != CLASS_TYPE_SORCERER && GlobalOurChosenClass != CLASS_TYPE_FEY) @@ -9265,7 +9207,7 @@ H X [Holy Sword] - Paladins sword gains the "Holy Avenger" property - +1d6 divin GlobalOurChosenClass == CLASS_TYPE_BARD) { // BAB check for level 4 spells. - if(GlobalOurBaseAttackBonus - i5 >= GlobalMeleeTargetAC) return FALSE; + if(GlobalOurBaseAttackBonus - 5 >= GlobalMeleeTargetAC) return FALSE; } // Demons, fighters, anything else really. else @@ -9290,27 +9232,27 @@ H X [Holy Sword] - Paladins sword gains the "Holy Avenger" property - +1d6 divin // 60-70% if favourable. // - We don't cast Bestow Curse, Charm Monster, Poison, or Contagion above // AOE spells. We cast critical wounds only at the very end. - if(SingleSpellsFirst && GlobalNormalSpellsNoEffectLevel < i4 && + if(bSingleSpellsFirst && GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < 4 && // All level 4, all fort saves - !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, i4)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, 4)) { // Phantismal Killer. Will and Fortitude save VS death. :-) - if(RangeMediumValid && !AI_CompareTimeStopStored(SPELL_PHANTASMAL_KILLER) && + if(bRangeMediumValid && !AI_CompareTimeStopStored(SPELL_PHANTASMAL_KILLER) && !AI_GetSpellTargetImmunity(GlobalImmunityDeath) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i4)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 4)) { // Phantasmal Killer. Level 4 (Mage). Will save (Illusion) then fort save, or death. - if(AI_ActionCastSpellRandom(SPELL_PHANTASMAL_KILLER, SpellHostRanged, i50, GlobalSpellTarget, i14, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_PHANTASMAL_KILLER, 50, GlobalSpellTarget, 14, FALSE)) return TRUE; } // Enervation. 1d4 negative levels. Short range - if(RangeMediumValid && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && + if(bRangeMediumValid && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && !AI_GetSpellTargetImmunity(GlobalImmunityNegativeEnergy)) { // Enervation. Level 4 (Mage). 1d4 negative levels, fortitude save - if(AI_ActionCastSpellRandom(SPELL_ENERVATION, SpellHostRanged, i40, GlobalSpellTarget, i14, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_ENERVATION, 40, GlobalSpellTarget, 14, FALSE)) return TRUE; } // Single spell override backup casting - if(SingleSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; + if(bSingleSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; } // AOE: @@ -9323,117 +9265,112 @@ H X [Holy Sword] - Paladins sword gains the "Holy Avenger" property - +1d6 divin // [Hammer of the Gods] - divine damage d8(half caster level) to 5. Can Daze. Will save. // [War Cry] Will save or fear (like a howl) and all allies get +2 attack/damage - if(GlobalNormalSpellsNoEffectLevel < i4) + if(GlobalNormalSpellsNoEffectLevel < 4) { - if(RangeLongValid) + if(bRangeLongValid && GlobalSeenSpell) { // Lesser missile storm. 1d6/missile. 1-10 missiles basically. Enemies only! // Just cast at the enemy. // Isaac's Lesser Missile Storm. Level 4 (Mage) 1d6 per each 1-10 missile divided around enemies in AOE. - if(AI_ActionCastSpellRandom(SPELL_ISAACS_LESSER_MISSILE_STORM, SpellHostRanged, i70, GlobalSpellTarget, i14, TRUE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_ISAACS_LESSER_MISSILE_STORM, 70, GlobalSpellTarget, 14, TRUE)) return TRUE; } // War cry here. No need to check if they run off - helps allies. if(GlobalSpellTargetRange <= RADIUS_SIZE_COLOSSAL) { // War Cry. Level 4 (Bard) Will save or fear (like a howl) and all allies get +2 attack/damage - if(AI_ActionCastSpellRandom(SPELL_WAR_CRY, SpellHostAreaDis, i30, OBJECT_SELF, i14, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_WAR_CRY, 30, OBJECT_SELF, 14, TRUE)) return TRUE; } } // Ice storm. plenty of damage :-) - if(SpellHostAreaInd && RangeLongValid && - (GetHasSpell(SPELL_ICE_STORM) || ItemHostAreaInd == SPELL_ICE_STORM)) + if(bRangeLongValid && GetHasSpell(SPELL_ICE_STORM)) { // Shpere, huge and no save :-) - long range too. - oAOE = AI_GetBestAreaSpellTarget(fLongRange, RADIUS_SIZE_HUGE, i4, FALSE, SHAPE_SPHERE, GlobalFriendlyFireFriendly); + oAOE = AI_GetBestAreaSpellTarget(fLongRange, RADIUS_SIZE_HUGE, 4, FALSE, SHAPE_SPHERE, GlobalFriendlyFireFriendly); // Is it valid? 60% chance of casting. if(GetIsObjectValid(oAOE)) { // Ice Storm. Level 4 (Mage) 5 (Druid) 6 (Bard) - 2d6 (Blud) + 3d6 / 3 caster levels (cold) damage. No save! - if(AI_ActionCastSpellRandom(SPELL_ICE_STORM, SpellHostAreaInd, i50, oAOE, i14, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_ICE_STORM, 50, oAOE, 14, TRUE)) return TRUE; } } // Confusion - confusion! Decent especially against PC's. - if(SpellHostAreaDis && RangeMediumValid && - (GetHasSpell(SPELL_CONFUSION) || ItemHostAreaDis == SPELL_CONFUSION)) + if(bRangeMediumValid && GetHasSpell(SPELL_CONFUSION)) { // Shpere, huge and no save :-) - oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_LARGE, i4, SAVING_THROW_WILL, SHAPE_SPHERE, GlobalFriendlyFireHostile); + oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_LARGE, 4, SAVING_THROW_WILL, SHAPE_SPHERE, GlobalFriendlyFireHostile); // Is it valid? 60% chance of casting. if(GetIsObjectValid(oAOE)) { // Ice Storm. Level 4 (Mage) 5 (Druid) 6 (Bard) - 2d6 (Blud) + 3d6 / 3 caster levels (cold) damage. No save! - if(AI_ActionCastSpellRandom(SPELL_CONFUSION, SpellHostAreaDis, i50, oAOE, i14, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_CONFUSION, 50, oAOE, 14, TRUE)) return TRUE; } } // Hammer of the Gods. Divine damage is good, as well as save VS daze. - if(SpellHostAreaDis && RangeMediumValid && - (GetHasSpell(SPELL_HAMMER_OF_THE_GODS) || ItemHostAreaDis == SPELL_HAMMER_OF_THE_GODS)) + if(bRangeMediumValid && GetHasSpell(SPELL_HAMMER_OF_THE_GODS)) { // Shpere, no friends affected, we cast even if saves VS will. :-) - oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_HUGE, i4); + oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_HUGE, 4); // Is it valid? 50% chance of casting. if(GetIsObjectValid(oAOE)) { // Hammer of the Gods. Level 4 (Cleric). Divine damage d8(half caster level) to 5d8. Can Daze. Will save. - if(AI_ActionCastSpellRandom(SPELL_HAMMER_OF_THE_GODS, SpellHostAreaDis, i40, oAOE, i14, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_HAMMER_OF_THE_GODS, 40, oAOE, 14, TRUE)) return TRUE; } } // Fear - fear! - if(SpellHostAreaDis && RangeMediumValid && - (GetHasSpell(SPELL_FEAR) || ItemHostAreaDis == SPELL_FEAR)) + if(bRangeMediumValid && GetHasSpell(SPELL_FEAR)) { // Shpere, no friends affected, we cast even if saves VS will. :-) - oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_LARGE, i4, SAVING_THROW_WILL, SHAPE_SPHERE, GlobalFriendlyFireHostile); + oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_LARGE, 4, SAVING_THROW_WILL, SHAPE_SPHERE, GlobalFriendlyFireHostile); // Is it valid? 50% chance of casting. if(GetIsObjectValid(oAOE)) { // Fear. Level 4 (Mage) 3 (Bard). Save VS mind will or fear, in an area. - if(AI_ActionCastSpellRandom(SPELL_FEAR, SpellHostAreaDis, i40, oAOE, i14, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_FEAR, 40, oAOE, 14, TRUE)) return TRUE; } } // Wall of Fire. - if(SpellHostAreaInd && RangeMediumValid && - (GetHasSpell(SPELL_WALL_OF_FIRE) || ItemHostAreaInd == SPELL_WALL_OF_FIRE) && - (GetHasSpell(SPELL_SHADES_WALL_OF_FIRE) || ItemHostAreaInd == SPELL_SHADES_WALL_OF_FIRE)) + if(bRangeMediumValid && + (GetHasSpell(SPELL_WALL_OF_FIRE) || GetHasSpell(SPELL_SHADES_WALL_OF_FIRE))) { // Ok, retangle. Take it as a medium sized sphere. - oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_MEDIUM, i4, SAVING_THROW_REFLEX, SHAPE_SPHERE, GlobalFriendlyFireFriendly); + oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_MEDIUM, 4, SAVING_THROW_REFLEX, SHAPE_SPHERE, GlobalFriendlyFireFriendly); // Is it valid? 50% chance of casting. if(GetIsObjectValid(oAOE)) { - // Shades version - if(AI_ActionCastSubSpell(SPELL_SHADES_WALL_OF_FIRE, SpellHostAreaInd, oAOE, i14, TRUE, ItemHostAreaInd)) return TRUE; + // Shades version. Cast as subspell. + if(AI_ActionCastSpell(SPELL_SHADES_WALL_OF_FIRE, oAOE, 14, TRUE, TRUE)) return TRUE; // Wall of Fire. Level 4 (Mage) 5 (Druid) 4d6 fire reflex damage in a retangle persistant AOE - if(AI_ActionCastSpellRandom(SPELL_WALL_OF_FIRE, SpellHostAreaInd, i40, oAOE, i14, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_WALL_OF_FIRE, 40, oAOE, 14, TRUE)) return TRUE; } } // Evard's Black Tentacles. AC attack and damage (fort or paralysis on enter) // Casts if average HD is under 10 - if(SpellHostAreaInd && RangeMediumValid && GlobalAverageEnemyHD <= i10 && - (GetHasSpell(SPELL_EVARDS_BLACK_TENTACLES) || ItemHostAreaInd == SPELL_EVARDS_BLACK_TENTACLES)) + if(bRangeMediumValid && GlobalAverageEnemyHD <= 10 && + GetHasSpell(SPELL_EVARDS_BLACK_TENTACLES)) { // 5M sized AOE spell, medium range. - oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_LARGE, i4, FALSE, SHAPE_SPHERE, GlobalFriendlyFireFriendly); + oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_LARGE, 4, FALSE, SHAPE_SPHERE, GlobalFriendlyFireFriendly); // Is it valid? 40% chance of casting. if(GetIsObjectValid(oAOE)) { // Evard's Black Tentacles. Level 4 (Mage) AC attack and damage (2d6 x 1-5 hits) (fort or paralysis on enter) - if(AI_ActionCastSpellRandom(SPELL_EVARDS_BLACK_TENTACLES, SpellHostAreaInd, i30, oAOE, i14, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_EVARDS_BLACK_TENTACLES, 30, oAOE, 14, TRUE)) return TRUE; } } // Multi spell override backup casting - if(MultiSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; + if(bMultiSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; // Level 4 summons - if(IsFirstRunThrough && GlobalCanSummonSimilarLevel <= i4 && - (GlobalOurHitDice <= i12 || GlobalMeleeAttackers <= i2)) + if(bFirstRunThrough && GlobalCanSummonSimilarLevel <= 4 && + (GlobalOurHitDice <= 12 || GlobalMeleeAttackers <= 2)) { // Summon Monster IV (4). Level 4 (Most classes) Summons a Dire Spider - if(AI_ActionCastSummonSpell(SPELL_SUMMON_CREATURE_IV, i14, i4)) return TRUE; + if(AI_ActionCastSummonSpell(SPELL_SUMMON_CREATURE_IV, 14, 4)) return TRUE; } // [Enervation] - 1d4 negative levels, fortitude save @@ -9446,58 +9383,58 @@ H X [Holy Sword] - Paladins sword gains the "Holy Avenger" property - +1d6 divin // [Contagion] - Disease (Static DC!) if fail fortitude save // All single target spells, even poison and so on. - if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < i4) + if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < 4) { // All but charm are fortitude based. - if(!AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, i4)) + if(!AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, 4)) { // Phantismal Killer. Will and Fortitude save VS death. :-) - if(RangeMediumValid && !AI_CompareTimeStopStored(SPELL_PHANTASMAL_KILLER) && + if(bRangeMediumValid && !AI_CompareTimeStopStored(SPELL_PHANTASMAL_KILLER) && !AI_GetSpellTargetImmunity(GlobalImmunityDeath) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i4)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 4)) { // Phantasmal Killer. Level 4 (Mage). Will save (Illusion) then fort save, or death. - if(AI_ActionCastSpellRandom(SPELL_PHANTASMAL_KILLER, SpellHostRanged, i50, GlobalSpellTarget, i14, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_PHANTASMAL_KILLER, 50, GlobalSpellTarget, 14, FALSE)) return TRUE; } // Enervation. 1d4 negative levels. Short range - if(RangeMediumValid && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && + if(bRangeMediumValid && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && !AI_GetSpellTargetImmunity(GlobalImmunityNegativeEnergy)) { // Enervation. Level 4 (Mage). 1d4 negative levels, fortitude save - if(AI_ActionCastSpellRandom(SPELL_ENERVATION, SpellHostRanged, i40, GlobalSpellTarget, i14, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_ENERVATION, 40, GlobalSpellTarget, 14, FALSE)) return TRUE; } // Contagion. Disease! Quite good, but still check spell save DC at fort above. // Necromancy. - if(RangeTouchValid && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && + if(bRangeTouchValid && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && !AI_GetSpellTargetImmunity(GlobalImmunityDisease)) { // Blackguard Ability - if(AI_ActionUseFeatOnObject(FEAT_CONTAGION, GlobalMeleeTarget)) return TRUE; + if(AI_ActionUseSpellLikeFeat(FEAT_CONTAGION, SPELLABILITY_BG_CONTAGION, GlobalMeleeTarget)) return TRUE; // Contagion. Level 4 (Mage) 3 (Cleric/Bard). Random disease (Set DC's!) against a fortitude saving throw. - if(AI_ActionCastSpellRandom(SPELL_CONTAGION, SpellHostTouch, i40, GlobalSpellTarget, i14, FALSE, ItemHostTouch)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_CONTAGION, 40, GlobalSpellTarget, 14, FALSE)) return TRUE; } // Poison - Inflicts poison (sadly, static fortitude save) Necro spell. - if(RangeTouchValid && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && + if(bRangeTouchValid && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && !AI_GetSpellTargetImmunity(GlobalImmunityPoison)) { // Poison. Level 4 (Cleric) 3 (Druid) Large Scorion Venom poison (Set DC!) against a fortitude saving throw. - if(AI_ActionCastSpellRandom(SPELL_POISON, SpellHostRanged, i40, GlobalSpellTarget, i14, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_POISON, 40, GlobalSpellTarget, 14, FALSE)) return TRUE; } // Bestow Curse - Inflicts poison (sadly, static fortitude save) Necro spell. - if(RangeTouchValid && !AI_GetSpellTargetImmunity(GlobalImmunityCurse)) + if(bRangeTouchValid && !AI_GetSpellTargetImmunity(GlobalImmunityCurse)) { // Bestow Curse. Level 4 (Mage) 3 (Cleric/Bard) -2 to all stats VS Fortitude save. - if(AI_ActionCastSpellRandom(SPELL_BESTOW_CURSE, SpellHostTouch, i40, GlobalSpellTarget, i14, FALSE, ItemHostTouch)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_BESTOW_CURSE, 40, GlobalSpellTarget, 14, FALSE)) return TRUE; } } // Charm Monster. Charms any monster. Will save, mind based. - if(!AI_GetSpellTargetImmunity(GlobalImmunityMind) && RangeShortValid && + if(!AI_GetSpellTargetImmunity(GlobalImmunityMind) && bRangeShortValid && !AI_GetSpellTargetImmunity(GlobalImmunityDomination) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i4)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 4)) { // Charm Monster. Level 4 (mage) 3 (Bard). Charm any monster, will save to resist. - if(AI_ActionCastSpellRandom(SPELL_CHARM_MONSTER, SpellHostRanged, i30, GlobalSpellTarget, i14, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_CHARM_MONSTER, 30, GlobalSpellTarget, 14, FALSE)) return TRUE; } } @@ -9505,15 +9442,24 @@ H X [Holy Sword] - Paladins sword gains the "Holy Avenger" property - +1d6 divin if(AI_ActionCastBackupRandomSpell()) return TRUE; // Critical wounds - damage at a touch attack. - if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < i4 && RangeTouchValid && - !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && - !AI_GetSpellTargetImmunity(GlobalImmunityNegativeEnergy)) + if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < 4 && bRangeTouchValid) { - // Blackguard ability - if(AI_ActionUseFeatOnObject(FEAT_INFLICT_CRITICAL_WOUNDS, GlobalSpellTarget)) return TRUE; + // Cast Cure Critical Wounds (Which acts the same way for undead as + // inflict critical does) + if(GlobalSpellTargetRace == RACIAL_TYPE_UNDEAD) + { + // Cure Critical Wounds. Level 4 (Cleric) 3d8 + 1/caster level to +20, in positive energy. + if(AI_ActionCastSpontaeousSpell(SPELL_CURE_CRITICAL_WOUNDS, GlobalSpellTarget)) return TRUE; + } + if(!AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && + !AI_GetSpellTargetImmunity(GlobalImmunityNegativeEnergy)) + { + // Blackguard ability + if(AI_ActionUseSpellLikeFeat(FEAT_INFLICT_CRITICAL_WOUNDS, SPELLABILITY_BG_INFLICT_CRITICAL_WOUNDS, GlobalSpellTarget)) return TRUE; - // Inflict Critical Wounds. Level 4 (Cleric) 3d8 + 1/caster level to +20, in negative energy. - if(AI_ActionCastSpontaeousSpell(SPELL_INFLICT_CRITICAL_WOUNDS, SpellHostTouch, GlobalSpellTarget)) return TRUE; + // Inflict Critical Wounds. Level 4 (Cleric) 3d8 + 1/caster level to +20, in negative energy. + if(AI_ActionCastSpontaeousSpell(SPELL_INFLICT_CRITICAL_WOUNDS, GlobalSpellTarget)) return TRUE; + } } /*::3333333333333333333333333333333333333333333333333333333333333333333333333333 @@ -9587,33 +9533,19 @@ H X [Darkfire] - +1d6 + 1/caster level (to +10) in fire damage applied to non-ma //::33333333333333333333333333333333333333333333333333333333333333333333333333*/ // Jump out if we don't want to cast level 3 spells. - if(iLowestSpellLevel > i3) return FALSE; + if(nLowestSpellLevel > 3) return FALSE; - // Dispel level 2 protections - if(RangeMediumValid && !GlobalInTimeStop)// All medium spells. - { - // Dispel number need to be 2 for breach - if(GlobalDispelTargetHighestBreach >= i2) - { - // Wrapers Greater and Lesser Breach. - if(AI_ActionCastBreach()) return TRUE; - } - // Dispel >= 2 - if(GlobalDispelTargetHighestDispel >= i2) - { - // Wrappers the dispel spells - if(AI_ActionCastDispel()) return TRUE; - } - } + // Dispel level 2 protections (Hastes, regenerates, tensors...) + if(AI_ActionAttemptDispel(2, bRangeMediumValid)) return TRUE; - if(IsFirstRunThrough) + if(bFirstRunThrough) { // Greater magic fang oAOE = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION); if(GetIsObjectValid(oAOE) && !GetHasSpellEffect(SPELL_GREATER_MAGIC_FANG, oAOE)) { // Greater MAgic fang. Level 3 (Ranger/Druid) +Attack, +DR to animal companion - if(AI_ActionCastSpell(SPELL_GREATER_MAGIC_FANG, SpellProSinTar, oAOE, i13, FALSE, ItemProSinTar)) return TRUE; + if(AI_ActionCastSpell(SPELL_GREATER_MAGIC_FANG, oAOE, 13, FALSE)) return TRUE; } // Divine Shield - a feat, but a damn good one. @@ -9621,7 +9553,7 @@ H X [Darkfire] - +1d6 + 1/caster level (to +10) in fire damage applied to non-ma if(GetHasFeat(FEAT_TURN_UNDEAD)) { // Divine Shield - if(AI_ActionUseFeatOnObject(FEAT_DIVINE_SHIELD)) return TRUE; + if(AI_ActionUseSpellLikeFeat(FEAT_DIVINE_SHIELD, SPELL_DIVINE_SHIELD)) return TRUE; } // Magical vestment - this adds up to +5 AC to armor or shield! @@ -9632,14 +9564,14 @@ H X [Darkfire] - +1d6 + 1/caster level (to +10) in fire damage applied to non-ma { // Cast it at the armor // Magical Vestment. Level 3 (Cleric) Gives 1 suit of armor/shield a +1 AC bonus/3 caster levels (to +5) - if(AI_ActionCastSpell(SPELL_MAGIC_VESTMENT, SpellEnhSinTar, oAOE, i13, FALSE, ItemEnhSinTar)) return TRUE; + if(AI_ActionCastSpell(SPELL_MAGIC_VESTMENT, oAOE, 13, FALSE)) return TRUE; } // Regenerations - if(AI_ActionCastAllyBuffSpell(f10, i50, SPELL_REGENERATE, SPELL_MONSTROUS_REGENERATION)) return TRUE; + if(AI_ActionCastAllyBuffSpell(10.0, 50, SPELL_REGENERATE, SPELL_MONSTROUS_REGENERATION)) return TRUE; // Bulls Strength, Cats Grace, Endurance - if(AI_ActionCastAllyBuffSpell(f10, i50, SPELL_ENDURANCE, SPELL_CATS_GRACE, SPELL_ENDURANCE, iM1, SPELL_GREATER_BULLS_STRENGTH, SPELL_GREATER_CATS_GRACE)) return TRUE; + if(AI_ActionCastAllyBuffSpell(10.0, 50, SPELL_ENDURANCE, SPELL_CATS_GRACE, SPELL_ENDURANCE, -1, SPELL_GREATER_BULLS_STRENGTH, SPELL_GREATER_CATS_GRACE)) return TRUE; } // BAB check @@ -9647,7 +9579,7 @@ H X [Darkfire] - +1d6 + 1/caster level (to +10) in fire damage applied to non-ma // normally even mages have a +X to attack, this provides a good indicator // if we are going to easy, or very easily, hit the enemy. // - Clerics, Druids and Bards must be able to hit even better then normal. - if(IsFirstRunThrough && !SRA && + if(bFirstRunThrough && !SRA && GlobalOurChosenClass != CLASS_TYPE_WIZARD && GlobalOurChosenClass != CLASS_TYPE_SORCERER && GlobalOurChosenClass != CLASS_TYPE_FEY) @@ -9667,48 +9599,48 @@ H X [Darkfire] - +1d6 + 1/caster level (to +10) in fire damage applied to non-ma { // BAB check for level 3 spells. // 75% chance of hitting them outright. - if(GlobalOurBaseAttackBonus + i5 >= GlobalMeleeTargetAC) return FALSE; + if(GlobalOurBaseAttackBonus + 5 >= GlobalMeleeTargetAC) return FALSE; } } // Bolts 80% chance. Not too good, but oh well. - if(GlobalSeenSpell && RangeMediumValid && d10() <= i8) + if(GlobalSeenSpell && bRangeMediumValid && d10() <= 8) { // All ability Draining Bolts. All creature, so no limits. - if(GetAbilityScore(GlobalSpellTarget, ABILITY_DEXTERITY) >= i10) - if(AI_ActionCastSpellRandom(SPELLABILITY_BOLT_ABILITY_DRAIN_DEXTERITY, SpellHostRanged, i30, GlobalSpellTarget)) return TRUE; - if(GetAbilityScore(GlobalSpellTarget, ABILITY_WISDOM) >= i12) - if(AI_ActionCastSpellRandom(SPELLABILITY_BOLT_ABILITY_DRAIN_WISDOM, SpellHostRanged, i30, GlobalSpellTarget)) return TRUE; - if(GetAbilityScore(GlobalSpellTarget, ABILITY_CONSTITUTION) >= i12) - if(AI_ActionCastSpellRandom(SPELLABILITY_BOLT_ABILITY_DRAIN_CONSTITUTION, SpellHostRanged, i30, GlobalSpellTarget)) return TRUE; - if(GetAbilityScore(GlobalSpellTarget, ABILITY_STRENGTH) >= i12) - if(AI_ActionCastSpellRandom(SPELLABILITY_BOLT_ABILITY_DRAIN_STRENGTH, SpellHostRanged, i30, GlobalSpellTarget)) return TRUE; - if(GetAbilityScore(GlobalSpellTarget, ABILITY_CHARISMA) >= i14) - if(AI_ActionCastSpellRandom(SPELLABILITY_BOLT_ABILITY_DRAIN_CHARISMA, SpellHostRanged, i30, GlobalSpellTarget)) return TRUE; - if(GetAbilityScore(GlobalSpellTarget, ABILITY_INTELLIGENCE) >= i14) - if(AI_ActionCastSpellRandom(SPELLABILITY_BOLT_ABILITY_DRAIN_INTELLIGENCE, SpellHostRanged, i30, GlobalSpellTarget)) return TRUE; + if(GetAbilityScore(GlobalSpellTarget, ABILITY_DEXTERITY) >= 10) + if(AI_ActionCastSpellRandom(SPELLABILITY_BOLT_ABILITY_DRAIN_DEXTERITY, 30, GlobalSpellTarget)) return TRUE; + if(GetAbilityScore(GlobalSpellTarget, ABILITY_WISDOM) >= 12) + if(AI_ActionCastSpellRandom(SPELLABILITY_BOLT_ABILITY_DRAIN_WISDOM, 30, GlobalSpellTarget)) return TRUE; + if(GetAbilityScore(GlobalSpellTarget, ABILITY_CONSTITUTION) >= 12) + if(AI_ActionCastSpellRandom(SPELLABILITY_BOLT_ABILITY_DRAIN_CONSTITUTION, 30, GlobalSpellTarget)) return TRUE; + if(GetAbilityScore(GlobalSpellTarget, ABILITY_STRENGTH) >= 12) + if(AI_ActionCastSpellRandom(SPELLABILITY_BOLT_ABILITY_DRAIN_STRENGTH, 30, GlobalSpellTarget)) return TRUE; + if(GetAbilityScore(GlobalSpellTarget, ABILITY_CHARISMA) >= 14) + if(AI_ActionCastSpellRandom(SPELLABILITY_BOLT_ABILITY_DRAIN_CHARISMA, 30, GlobalSpellTarget)) return TRUE; + if(GetAbilityScore(GlobalSpellTarget, ABILITY_INTELLIGENCE) >= 14) + if(AI_ActionCastSpellRandom(SPELLABILITY_BOLT_ABILITY_DRAIN_INTELLIGENCE, 30, GlobalSpellTarget)) return TRUE; // And the damaging bolts/status affecting bolts. // I really can't be bothered to add in a lot of checks for immunities. // Might do later. - for(iCnt = SPELLABILITY_BOLT_ACID; iCnt <= SPELLABILITY_BOLT_WEB; iCnt++) + for(nCnt = SPELLABILITY_BOLT_ACID; nCnt <= SPELLABILITY_BOLT_WEB; nCnt++) { - if(AI_ActionCastSpellRandom(iCnt, SpellHostRanged, i30, GlobalSpellTarget)) return TRUE; + if(AI_ActionCastSpellRandom(nCnt, 30, GlobalSpellTarget)) return TRUE; } // Manticore spikes - if(AI_ActionCastSpellRandom(SPELLABILITY_MANTICORE_SPIKES, SpellHostRanged, i30, GlobalSpellTarget)) return TRUE; + if(AI_ActionCastSpellRandom(SPELLABILITY_MANTICORE_SPIKES, 30, GlobalSpellTarget)) return TRUE; // Shifter one - if(AI_ActionCastSpellRandom(AI_SPELLABILITY_GWILDSHAPE_SPIKES, SpellHostRanged, i30, GlobalSpellTarget)) return TRUE; + if(AI_ActionCastSpellRandom(AI_SPELLABILITY_GWILDSHAPE_SPIKES, 30, GlobalSpellTarget)) return TRUE; // Azer blast - if(AI_ActionCastSpellRandom(AI_SPELLABILITY_AZER_FIRE_BLAST, SpellHostRanged, i30, GlobalSpellTarget)) return TRUE; + if(AI_ActionCastSpellRandom(AI_SPELLABILITY_AZER_FIRE_BLAST, 30, GlobalSpellTarget)) return TRUE; // Shadow attack if(!GetHasSpellEffect(AI_SPELLABILITY_SHADOW_ATTACK, GlobalSpellTarget)) { - if(AI_ActionCastSpellRandom(AI_SPELLABILITY_SHADOW_ATTACK, SpellHostRanged, i30, GlobalSpellTarget)) return TRUE; + if(AI_ActionCastSpellRandom(AI_SPELLABILITY_SHADOW_ATTACK, 30, GlobalSpellTarget)) return TRUE; } // Petrify last. if(!AI_GetSpellTargetImmunity(GlobalImmunityPetrify)) { - if(AI_ActionCastSpellRandom(SPELLABILITY_TOUCH_PETRIFY, SpellHostRanged, i30, GlobalSpellTarget)) return TRUE; + if(AI_ActionCastSpellRandom(SPELLABILITY_TOUCH_PETRIFY, 30, GlobalSpellTarget)) return TRUE; } // Backup casting @@ -9733,49 +9665,55 @@ H X [Darkfire] - +1d6 + 1/caster level (to +10) in fire damage applied to non-ma // Flame arrow, searing light and hold person are quite effective. // 60-70% if favourable. // - We don't cast inflict serious wounds here. GetHasSpell bodges with spontaeous spells. - if(SingleSpellsFirst && GlobalNormalSpellsNoEffectLevel < i3) + if(bSingleSpellsFirst && GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < 3) { // Flame arrow - not THE best spell, but well worth it. Also it is long range. - if(RangeLongValid && !AI_SaveImmuneSpellTarget(SAVING_THROW_REFLEX, i3)) + if(bRangeLongValid && !AI_SaveImmuneSpellTarget(SAVING_THROW_REFLEX, 3)) { // Flame Arrow. Level 3 (Mage) 4d6 Reflex Fire Damage for each missile - 1/4 caster levels. - if(AI_ActionCastSpellRandom(SPELL_FLAME_ARROW, SpellHostRanged, i60, GlobalSpellTarget, i13, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_FLAME_ARROW, 60, GlobalSpellTarget, 13, FALSE)) return TRUE; } // All others are in medium range or smaller - if(RangeMediumValid) + if(bRangeMediumValid) { // Hold Person - must be playable race, of course. Still quite powerful - as it paralyzes. if(!AI_GetSpellTargetImmunity(GlobalImmunityStun) && - !AI_GetSpellTargetImmunity(GlobalImmunityMind) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i3)) + !AI_GetSpellTargetImmunity(GlobalImmunityMind) && + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 3) && + // 1.4 - Added test for correct race. + (GetIsPlayableRacialType(GlobalSpellTarget) || + GlobalSpellTargetRace == RACIAL_TYPE_HUMANOID_GOBLINOID || + GlobalSpellTargetRace == RACIAL_TYPE_HUMANOID_MONSTROUS || + GlobalSpellTargetRace == RACIAL_TYPE_HUMANOID_ORC || + GlobalSpellTargetRace == RACIAL_TYPE_HUMANOID_REPTILIAN)) { // Hold Person. Level 3 (Mage) 2 (Cleric/Bard) Paralyze's 1 humanoid target (Playable Race/humanoid), if they fail a will save. - if(AI_ActionCastSpellRandom(SPELL_HOLD_PERSON, SpellHostRanged, i40, GlobalSpellTarget, i13, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_HOLD_PERSON, 40, GlobalSpellTarget, 13, FALSE)) return TRUE; } // Searing light does good type of damage - divine, and is alright damage amount (up to 5d8) and more importantly, no save! // Searing Light. Level 3 (Cleric). Maxs of 10d6 to undead, 5d8 to others, 5d6 to constructs. Divine damage. Done above (way above) VS undead - if(AI_ActionCastSpellRandom(SPELL_SEARING_LIGHT, SpellHostRanged, i30, GlobalSpellTarget, i13, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_SEARING_LIGHT, 30, GlobalSpellTarget, 13, FALSE)) return TRUE; // Dominate Animal. Must be an animal, duh! Dominates an animal only. Will save. if(!AI_GetSpellTargetImmunity(GlobalImmunityDomination) && - !AI_GetSpellTargetImmunity(GlobalImmunityMind) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i3)) + !AI_GetSpellTargetImmunity(GlobalImmunityMind) && + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 3)) { // Dominate Animal. Level 3 (Druid) Dominates an animal only. Will save. - if(AI_ActionCastSpellRandom(SPELL_DOMINATE_ANIMAL, SpellHostRanged, i30, GlobalSpellTarget, i13, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_DOMINATE_ANIMAL, 30, GlobalSpellTarget, 13, FALSE)) return TRUE; } } - if(RangeShortValid) + if(bRangeShortValid) { // Quillfire. Poison isn't bad, and a little damage :-) if(!AI_GetSpellTargetImmunity(GlobalImmunityDomination) && !AI_GetSpellTargetImmunity(GlobalImmunityMind) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i3)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 3)) { // Quillfire. Level 3 (Mage) 1 quill at 1d8 + 1-5 damage. Scorpion poison too. - if(AI_ActionCastSpellRandom(SPELL_QUILLFIRE, SpellHostRanged, i30, GlobalSpellTarget, i13, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_QUILLFIRE, 30, GlobalSpellTarget, 13, FALSE)) return TRUE; } } - if(RangeTouchValid) + if(bRangeTouchValid) { // These 3 are necromantic if(!AI_GetSpellTargetImmunity(GlobalImmunityNecromancy)) @@ -9784,27 +9722,27 @@ H X [Darkfire] - +1d6 + 1/caster level (to +10) in fire damage applied to non-ma if(!GetHasSpellEffect(SPELL_INFESTATION_OF_MAGGOTS, GlobalSpellTarget)) { // Infestation of Maggots. Level 3 (Druid) 1d4 Temp constitution damage/round. (1 round/caster level) - if(AI_ActionCastSpellRandom(SPELL_INFESTATION_OF_MAGGOTS, SpellHostTouch, i40, GlobalSpellTarget, i13, FALSE, ItemHostTouch)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_INFESTATION_OF_MAGGOTS, 40, GlobalSpellTarget, 13, FALSE)) return TRUE; } // These 2 are negative energy if(!AI_GetSpellTargetImmunity(GlobalImmunityNegativeEnergy)) { // Healing sting isn't too bad. At least no immunities // and levels up OK. Negative energy damage, however. - if(!AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, i3)) + if(!AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, 3)) { // Healing Sting. Level 3 (Druid). 1d6 + 1/Caster evel damage, and healed for that amount. Fort save for none. - if(AI_ActionCastSpellRandom(SPELL_HEALING_STING, SpellHostTouch, i40, GlobalSpellTarget, i13, FALSE, ItemHostTouch)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_HEALING_STING, 40, GlobalSpellTarget, 13, FALSE)) return TRUE; } // Vampiric touch - good spell and scales nicely, and // heals :-D // Vampiric Touch. Level 3 (Mage) 1d6(caster level/2) in negative damage, heals us with temp HP. - if(AI_ActionCastSpellRandom(SPELL_VAMPIRIC_TOUCH, SpellHostTouch, i30, GlobalSpellTarget, i13, FALSE, ItemHostTouch)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_VAMPIRIC_TOUCH, 30, GlobalSpellTarget, 13, FALSE)) return TRUE; } } } // Single spell override backup casting - if(SingleSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; + if(bSingleSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; } // AOE spells // [Fireball] - Up to 10d6 reflex fire damage, in a large AOE hit area. Allies are hit too! (as we all know...) @@ -9819,213 +9757,200 @@ H X [Darkfire] - +1d6 + 1/caster level (to +10) in fire damage applied to non-ma // [Scintillating Sphere] - Explosion of up to 10d6 Damage (Electical) - An electiric fireball (reflex save) // [Glyph of Warding] - AOE, if entered, does up to 1d6/2 caster levels (to 5d6) damage. - // Fireball is fun fun fun! :-D Shadow version first - doesn't hit allies. - if(SpellHostAreaInd && RangeLongValid && - (GetHasSpell(SPELL_SHADES_FIREBALL) || ItemHostAreaInd == SPELL_SHADES_FIREBALL)) - { - // Huge, long ranged, reflex based save. Shades == No enemies hit. - oAOE = AI_GetBestAreaSpellTarget(fLongRange, RADIUS_SIZE_HUGE, i3, SAVING_THROW_REFLEX); - // Is it valid? 100% chance of casting. - if(GetIsObjectValid(oAOE)) - { - // (Shades) Fireball. Level 3 (Mage) Up to 10d6 reflex fire damage, in a large AOE hit area. Allies are hit too! (as we all know...) - if(AI_ActionCastSubSpell(SPELL_SHADES_FIREBALL, SpellHostAreaInd, oAOE, i17, TRUE, ItemHostAreaInd)) return TRUE; - } - } // Real fireball is hot! (Ban pun there...) // Scintillating Sphere is also fire-ball like, but electrical damage *shrugs* - if(SpellHostAreaInd && RangeLongValid && - (GetHasSpell(SPELL_FIREBALL) || ItemHostAreaInd == SPELL_FIREBALL || - GetHasSpell(SPELL_SCINTILLATING_SPHERE) || ItemHostAreaInd == SPELL_SCINTILLATING_SPHERE)) + if(bRangeLongValid && (GetHasSpell(SPELL_FIREBALL) || + GetHasSpell(SPELL_SCINTILLATING_SPHERE) || GetHasSpell(SPELL_SHADES_FIREBALL))) { // Huge, long ranged, reflex based save. Normal = reaction friendly. - oAOE = AI_GetBestAreaSpellTarget(fLongRange, RADIUS_SIZE_HUGE, i3, SAVING_THROW_REFLEX, SHAPE_SPHERE, GlobalFriendlyFireFriendly); + oAOE = AI_GetBestAreaSpellTarget(fLongRange, RADIUS_SIZE_HUGE, 3, SAVING_THROW_REFLEX, SHAPE_SPHERE, GlobalFriendlyFireFriendly); // Is it valid? 70% chance of casting. if(GetIsObjectValid(oAOE)) { + // (Shades) Fireball. Level 7 (Mage) Up to 10d6 reflex fire damage, in a large AOE hit area. Shades now hits allies. + if(AI_ActionCastSpell(SPELL_SHADES_FIREBALL, oAOE, 17, TRUE, TRUE)) return TRUE; + // Fireball. Level 3 (Mage) Up to 10d6 reflex fire damage, in a large AOE hit area. Allies are hit too! (as we all know...) - if(AI_ActionCastSpellRandom(SPELL_FIREBALL, SpellHostAreaInd, i60, oAOE, i13, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_FIREBALL, 60, oAOE, 13, TRUE)) return TRUE; // Scintillating Sphere. Level 3 (Mage) Explosion of up to 10d6 Damage (Electical) - An electiric fireball (reflex save) - if(AI_ActionCastSpellRandom(SPELL_SCINTILLATING_SPHERE, SpellHostAreaInd, i60, oAOE, i13, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_SCINTILLATING_SPHERE, 60, oAOE, 13, TRUE)) return TRUE; } } // Call Lightning - Never hits allies, so excelent to cast :-) - if(SpellHostAreaDis && RangeLongValid && - (GetHasSpell(SPELL_CALL_LIGHTNING) || ItemHostAreaDis == SPELL_CALL_LIGHTNING)) + if(bRangeLongValid && GetHasSpell(SPELL_CALL_LIGHTNING)) { // Huge, long ranged, reflex based save. No enemies hit! - oAOE = AI_GetBestAreaSpellTarget(fLongRange, RADIUS_SIZE_HUGE, i3, SAVING_THROW_REFLEX); + oAOE = AI_GetBestAreaSpellTarget(fLongRange, RADIUS_SIZE_HUGE, 3, SAVING_THROW_REFLEX); // Is it valid? 70% chance of casting. if(GetIsObjectValid(oAOE)) { // Call Lightning. Level 3 (Druid) Lightning damage - To 10d6 reflex electrical. Never hits allies. Smaller AOE then fireball - if(AI_ActionCastSpellRandom(SPELL_CALL_LIGHTNING, SpellHostAreaDis, i60, oAOE, i13, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_CALL_LIGHTNING, 60, oAOE, 13, TRUE)) return TRUE; } } // Mestils acid breath is on the standard 10d6 max damage. Acid + cone - if(SpellHostAreaDis && RangeShortValid && - (GetHasSpell(SPELL_MESTILS_ACID_BREATH) || ItemHostAreaDis == SPELL_MESTILS_ACID_BREATH)) + if(bRangeShortValid && GetHasSpell(SPELL_MESTILS_ACID_BREATH)) { // Short, cone based. - oAOE = AI_GetBestAreaSpellTarget(fShortRange, f11, i3, SAVING_THROW_REFLEX, SHAPE_SPELLCONE, GlobalFriendlyFireFriendly); + oAOE = AI_GetBestAreaSpellTarget(fShortRange, 11.0, 3, SAVING_THROW_REFLEX, SHAPE_SPELLCONE, GlobalFriendlyFireFriendly); // Is it valid? 60% chance of casting. if(GetIsObjectValid(oAOE)) { // Mestals Acid Breath. Level 3 (Mage) A cone of up to 10d6 (acid) damage. Reflex save. - if(AI_ActionCastSpellRandom(SPELL_MESTILS_ACID_BREATH, SpellHostAreaInd, i50, oAOE, i13, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_MESTILS_ACID_BREATH, 50, oAOE, 13, TRUE)) return TRUE; } } // Lightning Bolt. Basically, a fireball in a line. :-) // Requires a target object to hit. - if(SpellHostAreaInd && RangeMediumValid && - (GetHasSpell(SPELL_LIGHTNING_BOLT) || ItemHostAreaInd == SPELL_LIGHTNING_BOLT)) + if(bRangeMediumValid && GetHasSpell(SPELL_LIGHTNING_BOLT)) { // Requries an object. Hits allies. 30 spell cylinder range. - oAOE = AI_GetBestAreaSpellTarget(fMediumRange, f30, i3, SAVING_THROW_REFLEX, SHAPE_SPELLCYLINDER, GlobalFriendlyFireFriendly); + oAOE = AI_GetBestAreaSpellTarget(fMediumRange, 30.0, 3, SAVING_THROW_REFLEX, SHAPE_SPELLCYLINDER, GlobalFriendlyFireFriendly); // Is it valid? 50% chance of casting - only if seen if(GetIsObjectValid(oAOE) && GetObjectSeen(oAOE)) { // Lightning Bolt. Level 3 (Mage) An "oh, other spell" to fireball. Does a different damage type. can be more useful - different shape! Can't hit caster! 10d6 reflex electrical - if(AI_ActionCastSpellRandom(SPELL_LIGHTNING_BOLT, SpellHostAreaInd, i40, oAOE, i13, FALSE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_LIGHTNING_BOLT, 40, oAOE, 13, FALSE)) return TRUE; } } // Slow is a good AOE - hits enemies, and slows them (Will save) - if(SpellHostAreaDis && RangeShortValid && - (GetHasSpell(SPELL_SLOW) || ItemHostAreaDis == SPELL_SLOW)) + if(bRangeShortValid && GetHasSpell(SPELL_SLOW)) { // Slow - doesn't hit allies. Colossal range. - oAOE = AI_GetBestAreaSpellTarget(fShortRange, RADIUS_SIZE_COLOSSAL, i3, SAVING_THROW_WILL); + oAOE = AI_GetBestAreaSpellTarget(fShortRange, RADIUS_SIZE_COLOSSAL, 3, SAVING_THROW_WILL); // Is it valid? 50% chance of casting. if(GetIsObjectValid(oAOE)) { // Slow. Level 3 (Mage/bard) -50% speed, -1 Attack, -4 AC (I think) to those in an AOE - doesn't hit allies. - if(AI_ActionCastSpellRandom(SPELL_SLOW, SpellHostAreaDis, i40, oAOE, i13, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_SLOW, 40, oAOE, 13, TRUE)) return TRUE; } } // Negative Energy Burst. Negative damage (to non-undead) and strength loss. - if(SpellHostAreaDis && RangeMediumValid && - (GetHasSpell(SPELL_NEGATIVE_ENERGY_BURST) || ItemHostAreaDis == SPELL_NEGATIVE_ENERGY_BURST)) + if(bRangeMediumValid && GetHasSpell(SPELL_NEGATIVE_ENERGY_BURST)) { // Necromantic spell, hits allies. - oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_HUGE, i3, FALSE, SHAPE_SPHERE, GlobalFriendlyFireFriendly, FALSE, TRUE); + oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_HUGE, 3, FALSE, SHAPE_SPHERE, GlobalFriendlyFireFriendly, FALSE, TRUE); // Is it valid? 50% chance of casting. if(GetIsObjectValid(oAOE)) { // Negative Energy Burst. Level 3 (Mage) 1d8 + 1-20 (caster level) negative damage, and -1 STR/4 caster levels. Heals undead. - if(AI_ActionCastSpellRandom(SPELL_NEGATIVE_ENERGY_BURST, SpellHostAreaDis, i40, oAOE, i13, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_NEGATIVE_ENERGY_BURST, 40, oAOE, 13, TRUE)) return TRUE; } } // Stinking Cloud. Daze, lots of daze (will based) - if(SpellHostAreaInd && RangeMediumValid && - (GetHasSpell(SPELL_STINKING_CLOUD) || ItemHostAreaInd == SPELL_STINKING_CLOUD)) + if(bRangeMediumValid && GetHasSpell(SPELL_STINKING_CLOUD)) { // Allies are hit, will save to be immune. - oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_LARGE, i3, SAVING_THROW_WILL, SHAPE_SPHERE, GlobalFriendlyFireFriendly); + oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_LARGE, 3, SAVING_THROW_WILL, SHAPE_SPHERE, GlobalFriendlyFireFriendly); // Is it valid? 50% chance of casting. if(GetIsObjectValid(oAOE)) { // Stinking Cloud. Level 3 (Mage) Dazes those in the AOE, if fail VS will. - if(AI_ActionCastSpellRandom(SPELL_STINKING_CLOUD, SpellHostAreaInd, i40, oAOE, i13, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_STINKING_CLOUD, 40, oAOE, 13, TRUE)) return TRUE; } } // Spike Growth. Alright AOE - 30% speed decrease for 24HRS is the best bit. - if(SpellHostAreaInd && RangeMediumValid && - (GetHasSpell(SPELL_SPIKE_GROWTH) || ItemHostAreaInd == SPELL_SPIKE_GROWTH)) + if(bRangeMediumValid && GetHasSpell(SPELL_SPIKE_GROWTH)) { // Allies are hit, will save to be immune. - oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_LARGE, i3, SAVING_THROW_WILL, SHAPE_SPHERE, GlobalFriendlyFireFriendly); + oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_LARGE, 3, SAVING_THROW_WILL, SHAPE_SPHERE, GlobalFriendlyFireFriendly); // Is it valid? 50% chance of casting. if(GetIsObjectValid(oAOE)) { // Spike Growth. Level 3 (Druid) AOE - 30% speed decrease for 24HRS + 1d4 piercing damage/round. - if(AI_ActionCastSpellRandom(SPELL_SPIKE_GROWTH, SpellHostAreaInd, i40, oAOE, i13, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_SPIKE_GROWTH, 40, oAOE, 13, TRUE)) return TRUE; } } // Gust of Wind. Always need 2 of these (1 to dispel AOE's) - if(SpellHostAreaInd && RangeMediumValid && - GetHasSpell(SPELL_GUST_OF_WIND) >= i2) + if(bRangeMediumValid && GetHasSpell(SPELL_GUST_OF_WIND) >= 2) { // Allies are hit, will save to be immune. - oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_HUGE, i3, SAVING_THROW_FORT, SHAPE_SPHERE, GlobalFriendlyFireFriendly); + oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_HUGE, 3, SAVING_THROW_FORT, SHAPE_SPHERE, GlobalFriendlyFireFriendly); // Is it valid? 50% chance of casting. if(GetIsObjectValid(oAOE)) { // Gust of Wind. Level 3 (Bard/Mage) Dispels all AOE's in radius, and save VS fort for 3 round knockdown. - if(AI_ActionCastSpellRandom(SPELL_GUST_OF_WIND, SpellHostAreaInd, i40, oAOE, i13, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_GUST_OF_WIND, 40, oAOE, 13, TRUE)) return TRUE; } } // Glyph of Warding is cast last, lowest %, and just at spell target. // This is because it is good for setting up traps, but not that good // in combat, apart from the damage type. 30% - if(GlobalSeenSpell && RangeShortValid) + if(GlobalSeenSpell && bRangeShortValid) { // Glyph of Warding. Level 3 (Mage) AOE, if entered, does up to 1d6/2 caster levels (to 5d6) damage. - if(AI_ActionCastSpellRandom(SPELL_GLYPH_OF_WARDING, SpellHostAreaInd, i20, GlobalSpellTarget, i13, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_GLYPH_OF_WARDING, 20, GlobalSpellTarget, 13, TRUE)) return TRUE; } // Multi spell override backup casting - if(MultiSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; + if(bMultiSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; // Level 3 summons - if(IsFirstRunThrough && GlobalCanSummonSimilarLevel <= i3 && - (GlobalOurHitDice <= i10 || GlobalMeleeAttackers <= i2)) + if(bFirstRunThrough && GlobalCanSummonSimilarLevel <= 3 && + (GlobalOurHitDice <= 10 || GlobalMeleeAttackers <= 2)) { - // Pale master - if(AI_ActionCastSummonSpell(AI_FEAT_PM_ANIMATE_DEAD, iM1, i3)) return TRUE; + // Pale master - Feat Animate Dead + if(AI_ActionCastSummonSpell(SPELLABILITY_PM_ANIMATE_DEAD, -1, 3, FEAT_ANIMATE_DEAD)) return TRUE; // Animate Dead. Level 3 (Mage). Skeleton or zomie summon. Tough DR, long lasting, but hard to heal. - if(AI_ActionCastSummonSpell(SPELL_ANIMATE_DEAD, i13, i3)) return TRUE; + if(AI_ActionCastSummonSpell(SPELL_ANIMATE_DEAD, 13, 3)) return TRUE; // Summon Monster III (3). Level 3 (Most classes) Summons a Dire Wolf. - if(AI_ActionCastSummonSpell(SPELL_SUMMON_CREATURE_III, i13, i3)) return TRUE; + if(AI_ActionCastSummonSpell(SPELL_SUMMON_CREATURE_III, 13, 3)) return TRUE; } // Single target spells. // - We don't cast inflict serious wounds. GetHasSpell bodges with spontaeous spells. - if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < i3) + if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < 3) { // Flame arrow - not THE best spell, but well worth it. Also it is long range. - if(RangeLongValid && !AI_SaveImmuneSpellTarget(SAVING_THROW_REFLEX, i3)) + if(bRangeLongValid && !AI_SaveImmuneSpellTarget(SAVING_THROW_REFLEX, 3)) { // Flame Arrow. Level 3 (Mage) 4d6 Reflex Fire Damage for each missile - 1/4 caster levels. - if(AI_ActionCastSpellRandom(SPELL_FLAME_ARROW, SpellHostRanged, i30, GlobalSpellTarget, i13, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_FLAME_ARROW, 30, GlobalSpellTarget, 13, FALSE)) return TRUE; } // All others are in medium range or smaller - if(RangeMediumValid) + if(bRangeMediumValid) { // Hold Person - must be playable race, of course. Still quite powerful - as it paralyzes. if(!AI_GetSpellTargetImmunity(GlobalImmunityStun) && - !AI_GetSpellTargetImmunity(GlobalImmunityMind) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i3)) + !AI_GetSpellTargetImmunity(GlobalImmunityMind) && + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 3) && + // 1.4 - Added test for correct race. + (GetIsPlayableRacialType(GlobalSpellTarget) || + GlobalSpellTargetRace == RACIAL_TYPE_HUMANOID_GOBLINOID || + GlobalSpellTargetRace == RACIAL_TYPE_HUMANOID_MONSTROUS || + GlobalSpellTargetRace == RACIAL_TYPE_HUMANOID_ORC || + GlobalSpellTargetRace == RACIAL_TYPE_HUMANOID_REPTILIAN)) { // Hold Person. Level 3 (Mage) 2 (Cleric/Bard) Paralyze's 1 humanoid target (Playable Race/humanoid), if they fail a will save. - if(AI_ActionCastSpellRandom(SPELL_HOLD_PERSON, SpellHostRanged, i20, GlobalSpellTarget, i13, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_HOLD_PERSON, 20, GlobalSpellTarget, 13, FALSE)) return TRUE; } // Searing light does good type of damage - divine, and is alright damage amount (up to 5d8) and more importantly, no save! // Searing Light. Level 3 (Cleric). Maxs of 10d6 to undead, 5d8 to others, 5d6 to constructs. Divine damage. Done above (way above) VS undead - if(AI_ActionCastSpellRandom(SPELL_SEARING_LIGHT, SpellHostRanged, i10, GlobalSpellTarget, i13, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_SEARING_LIGHT, 10, GlobalSpellTarget, 13, FALSE)) return TRUE; // Dominate Animal. Must be an animal, duh! Dominates an animal only. Will save. if(!AI_GetSpellTargetImmunity(GlobalImmunityDomination) && - !AI_GetSpellTargetImmunity(GlobalImmunityMind) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i3)) + !AI_GetSpellTargetImmunity(GlobalImmunityMind) && + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 3)) { // Dominate Animal. Level 3 (Druid) Dominates an animal only. Will save. - if(AI_ActionCastSpellRandom(SPELL_DOMINATE_ANIMAL, SpellHostRanged, i10, GlobalSpellTarget, i13, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_DOMINATE_ANIMAL, 10, GlobalSpellTarget, 13, FALSE)) return TRUE; } } - if(RangeShortValid) + if(bRangeShortValid) { // Quillfire. Poison isn't bad, and a little damage :-) if(!AI_GetSpellTargetImmunity(GlobalImmunityDomination) && !AI_GetSpellTargetImmunity(GlobalImmunityMind) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i3)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 3)) { // Quillfire. Level 3 (Mage) 1 quill at 1d8 + 1-5 damage. Scorpion poison too. - if(AI_ActionCastSpellRandom(SPELL_QUILLFIRE, SpellHostRanged, i10, GlobalSpellTarget, i13, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_QUILLFIRE, 10, GlobalSpellTarget, 13, FALSE)) return TRUE; } } - if(RangeTouchValid) + if(bRangeTouchValid) { // These 3 are necromantic if(!AI_GetSpellTargetImmunity(GlobalImmunityNecromancy)) @@ -10034,22 +9959,22 @@ H X [Darkfire] - +1d6 + 1/caster level (to +10) in fire damage applied to non-ma if(!GetHasSpellEffect(SPELL_INFESTATION_OF_MAGGOTS, GlobalSpellTarget)) { // Infestation of Maggots. Level 3 (Druid) 1d4 Temp constitution damage/round. (1 round/caster level) - if(AI_ActionCastSpellRandom(SPELL_INFESTATION_OF_MAGGOTS, SpellHostTouch, i20, GlobalSpellTarget, i13, FALSE, ItemHostTouch)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_INFESTATION_OF_MAGGOTS, 20, GlobalSpellTarget, 13, FALSE)) return TRUE; } // These 2 are negative energy if(!AI_GetSpellTargetImmunity(GlobalImmunityNegativeEnergy)) { // Healing sting isn't too bad. At least no immunities // and levels up OK. Negative energy damage, however. - if(!AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, i3)) + if(!AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, 3)) { // Healing Sting. Level 3 (Druid). 1d6 + 1/Caster evel damage, and healed for that amount. Fort save for none. - if(AI_ActionCastSpellRandom(SPELL_HEALING_STING, SpellHostTouch, i20, GlobalSpellTarget, i13, FALSE, ItemHostTouch)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_HEALING_STING, 20, GlobalSpellTarget, 13, FALSE)) return TRUE; } // Vampiric touch - good spell and scales nicely, and // heals :-D // Vampiric Touch. Level 3 (Mage) 1d6(caster level/2) in negative damage, heals us with temp HP. - if(AI_ActionCastSpellRandom(SPELL_VAMPIRIC_TOUCH, SpellHostTouch, i10, GlobalSpellTarget, i13, FALSE, ItemHostTouch)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_VAMPIRIC_TOUCH, 10, GlobalSpellTarget, 13, FALSE)) return TRUE; } } } @@ -10059,15 +9984,24 @@ H X [Darkfire] - +1d6 + 1/caster level (to +10) in fire damage applied to non-ma if(AI_ActionCastBackupRandomSpell()) return TRUE; // Serious wounds - damage at a touch attack. - if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < i3 && RangeTouchValid && - !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && - !AI_GetSpellTargetImmunity(GlobalImmunityNegativeEnergy)) + if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < 3 && bRangeTouchValid) { - // Blackguard ability - if(AI_ActionUseFeatOnObject(FEAT_INFLICT_SERIOUS_WOUNDS, GlobalMeleeTarget)) return TRUE; + // Cast Cure Critical Wounds (Which acts the same way for undead as + // inflict critical does) + if(GlobalSpellTargetRace == RACIAL_TYPE_UNDEAD) + { + // Cure Serious Wounds. Level 3 (Cleric) Touch attack, hit means 3d8 + 1-15 positive damage. + if(AI_ActionCastSpontaeousSpell(SPELL_CURE_SERIOUS_WOUNDS, GlobalSpellTarget)) return TRUE; + } + if(!AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && + !AI_GetSpellTargetImmunity(GlobalImmunityNegativeEnergy)) + { + // Blackguard ability + if(AI_ActionUseSpellLikeFeat(FEAT_INFLICT_SERIOUS_WOUNDS, SPELLABILITY_BG_INFLICT_SERIOUS_WOUNDS, GlobalMeleeTarget)) return TRUE; - // Inflict Serious Wounds. Level 3 (Cleric) Touch attack, hit means 3d8 + 1-15 negative damage. - if(AI_ActionCastSpontaeousSpell(SPELL_INFLICT_SERIOUS_WOUNDS, SpellOtherSpell, GlobalSpellTarget)) return TRUE; + // Inflict Serious Wounds. Level 3 (Cleric) Touch attack, hit means 3d8 + 1-15 negative damage. + if(AI_ActionCastSpontaeousSpell(SPELL_INFLICT_SERIOUS_WOUNDS, GlobalSpellTarget)) return TRUE; + } } /*::2222222222222222222222222222222222222222222222222222222222222222222222222222 @@ -10134,20 +10068,27 @@ H X [Aura of Glory] - +4 Char, and allies get +4 VS Fear effects. //::22222222222222222222222222222222222222222222222222222222222222222222222222*/ // Jump out if we don't want to cast level 2 spells. - if(iLowestSpellLevel > i2) return FALSE; + if(nLowestSpellLevel > 2) return FALSE; - if(IsFirstRunThrough) + if(bFirstRunThrough) { // Barkskin (if not already) if(!AI_GetAIHaveSpellsEffect(GlobalHasNaturalACSpell)) { - if(GlobalOurRace == RACIAL_TYPE_UNDEAD) + // This is natural AC, and only for undead. Cast it on ourselves, or + // our summoned undead monster. + if(GetRacialType(OBJECT_SELF) == RACIAL_TYPE_UNDEAD) { // Stone bones - cast if we do not have a natural armor AC spell. - if(AI_ActionCastSpell(SPELL_STONE_BONES, SpellProSinTar, OBJECT_SELF, i12, FALSE, ItemProSinTar, PotionPro)) return TRUE; + if(AI_ActionCastSpell(SPELL_STONE_BONES, OBJECT_SELF, 12, FALSE)) return TRUE; + } + else if(GetRacialType(GlobalBuffAlly) == RACIAL_TYPE_UNDEAD) + { + // Stone bones - cast if we do not have a natural armor AC spell. + if(AI_ActionCastSpell(SPELL_STONE_BONES, GlobalBuffAlly, 12, FALSE)) return TRUE; } // Barkskin. Level 2 (Druid). 1-6 = +3, 7-12 = +4. 13+ = +5 natural armor AC bonus. - if(AI_ActionCastSpell(SPELL_BARKSKIN, SpellProSinTar, OBJECT_SELF, i12, FALSE, ItemProSinTar, PotionPro)) return TRUE; + if(AI_ActionCastSpell(SPELL_BARKSKIN, OBJECT_SELF, 12, FALSE)) return TRUE; } // See AC notes in level 1 spells. @@ -10155,49 +10096,35 @@ H X [Aura of Glory] - +4 Char, and allies get +4 VS Fear effects. if(GlobalWeAreBuffer) { // Some AC protections - if(AI_ActionCastAllyBuffSpell(f6, i100, SPELL_BARKSKIN, SPELL_MAGE_ARMOR)) return TRUE; + if(AI_ActionCastAllyBuffSpell(6.0, 100, SPELL_BARKSKIN, SPELL_MAGE_ARMOR)) return TRUE; } // All visage spells here. - if(AI_SpellWrapperVisageProtections(iLowestSpellLevel)) return TRUE; + if(AI_SpellWrapperVisageProtections(nLowestSpellLevel)) return TRUE; // Eyeball rays. Low stuff, but hey, whatever, eh? // Random cast these. 3 random ones. - if(RangeMediumValid) + if(bRangeMediumValid) { // Random cast. Each one has 30-50 % chance. Doesn't matter which we use! - if(AI_ActionCastSpellRandom(AI_SPELLABILITY_EYEBALL_RAY_0, SpellHostRanged, i40, GlobalSpellTarget)) return TRUE; - if(AI_ActionCastSpellRandom(AI_SPELLABILITY_EYEBALL_RAY_1, SpellHostRanged, i40, GlobalSpellTarget)) return TRUE; - if(AI_ActionCastSpellRandom(AI_SPELLABILITY_EYEBALL_RAY_2, SpellHostRanged, i40, GlobalSpellTarget)) return TRUE; + if(AI_ActionCastSpellRandom(AI_SPELLABILITY_EYEBALL_RAY_0, 40, GlobalSpellTarget)) return TRUE; + if(AI_ActionCastSpellRandom(AI_SPELLABILITY_EYEBALL_RAY_1, 40, GlobalSpellTarget)) return TRUE; + if(AI_ActionCastSpellRandom(AI_SPELLABILITY_EYEBALL_RAY_2, 40, GlobalSpellTarget)) return TRUE; // Backup cast if(AI_ActionCastBackupRandomSpell()) return TRUE; } } - // Dispel level 1 protections - if(RangeMediumValid && !GlobalInTimeStop)// All medium spells. - { - // Dispel number need to be 1 for breach - if(GlobalDispelTargetHighestBreach >= i1) - { - // Wrapers Greater and Lesser Breach. - if(AI_ActionCastBreach()) return TRUE; - } - // Dispel >= 1 - if(GlobalDispelTargetHighestDispel >= i1) - { - // Wrappers the dispel spells - if(AI_ActionCastDispel()) return TRUE; - } - } + // Dispel level 1 protections (Hastes, regenerates, tensors...) + if(AI_ActionAttemptDispel(1, bRangeMediumValid)) return TRUE; // BAB check // - BAB checks check our BASE attack bonus, no modifiers. Basically, as // normally even mages have a +X to attack, this provides a good indicator // if we are going to easy, or very easily, hit the enemy. // - Clerics, Druids and Bards must be able to hit even better then normal. - if(IsFirstRunThrough && !SRA && + if(bFirstRunThrough && !SRA && GlobalOurChosenClass != CLASS_TYPE_WIZARD && GlobalOurChosenClass != CLASS_TYPE_SORCERER && GlobalOurChosenClass != CLASS_TYPE_FEY) @@ -10210,14 +10137,14 @@ H X [Aura of Glory] - +4 Char, and allies get +4 VS Fear effects. { // BAB check for level 3 spells. // Must be able to hit them 75% of the time. - if(GlobalOurBaseAttackBonus + i5 >= GlobalMeleeTargetAC) return FALSE; + if(GlobalOurBaseAttackBonus + 5 >= GlobalMeleeTargetAC) return FALSE; } // Demons, fighters, anything else really. else { // BAB check for level 3 spells. // 50% chance of hitting them outright. - if(GlobalOurBaseAttackBonus + i10 >= GlobalMeleeTargetAC) return FALSE; + if(GlobalOurBaseAttackBonus + 10 >= GlobalMeleeTargetAC) return FALSE; } } @@ -10236,81 +10163,83 @@ H X [Aura of Glory] - +4 Char, and allies get +4 VS Fear effects. // Acid arrow, flame lash all scale well, while blindness/deafness is a good spell too. // 60-70% if favourable. // - We don't cast inflict serious wounds here. GetHasSpell bodges with spontaeous spells. - if(SingleSpellsFirst && GlobalNormalSpellsNoEffectLevel < i2) + if(bSingleSpellsFirst && GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < 2) { // Ghoul Touch. Paralysis is good :-D - if(RangeTouchValid && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, i2)) + if(bRangeTouchValid && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && + !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, 2)) { // Ghoul Touch. Level 2 (Mage) - Fort save VS paralysis and an AOE on target which gives -2 attack/damage to enemies nearby. - if(AI_ActionCastSpellRandom(SPELL_GHOUL_TOUCH, SpellHostTouch, i50, GlobalSpellTarget, i12, FALSE, ItemHostTouch)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_GHOUL_TOUCH, 50, GlobalSpellTarget, 12, FALSE)) return TRUE; } - if(RangeLongValid) + if(bRangeLongValid) { // Greater shadow conjuration - if(d10() <= i6) + // This if statement here is because AI_ActionCastSpellRandom() doesn't have + // support for bSubSpell. Will probably change later. + if(d10() <= 6) { - if(AI_ActionCastSubSpell(SPELL_GREATER_SHADOW_CONJURATION_ACID_ARROW, SpellHostRanged, GlobalSpellTarget, i12, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpell(SPELL_GREATER_SHADOW_CONJURATION_ACID_ARROW, GlobalSpellTarget, 12, FALSE, TRUE)) return TRUE; } // Acid arrow - decent enough, and persistant damage, and no save. Long range too! // Melf's Acid Arrow. Level 2 (Mage) 3d6 Impact and 1d6 damage for up to 7 rounds (caster level/3) after that - if(AI_ActionCastSpellRandom(SPELL_MELFS_ACID_ARROW, SpellHostRanged, i60, GlobalSpellTarget, i12, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_MELFS_ACID_ARROW, 60, GlobalSpellTarget, 12, FALSE)) return TRUE; } // Continual flame isn't a bad spell - touch spell, and does // continual damage (reflex based) - if(RangeTouchValid && !AI_SaveImmuneSpellTarget(SAVING_THROW_REFLEX, i2)) + if(bRangeTouchValid && !AI_SaveImmuneSpellTarget(SAVING_THROW_REFLEX, 2)) { // Continual Flame. Level 2 (Mage) 3 (Cleric) 2d6 + 1 Caster Level (to +10) Fire dam. Reflex save. Every round after, reflex (until sucess) at 1d6 damage. - if(AI_ActionCastSpellRandom(SPELL_CONTINUAL_FLAME, SpellHostTouch, i60, GlobalSpellTarget, i12, FALSE, ItemHostTouch)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_CONTINUAL_FLAME, 60, GlobalSpellTarget, 12, FALSE)) return TRUE; } // Flame Lash is an alright amount of flame damage. - if(RangeShortValid && !AI_SaveImmuneSpellTarget(SAVING_THROW_REFLEX, i2)) + if(bRangeShortValid && !AI_SaveImmuneSpellTarget(SAVING_THROW_REFLEX, 2)) { // [Flame Lash] 2d6 + 1d6/3 caster levels of fire damage. Reflex save. - if(AI_ActionCastSpellRandom(SPELL_FLAME_LASH, SpellHostRanged, i50, GlobalSpellTarget, i12, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_FLAME_LASH, 50, GlobalSpellTarget, 12, FALSE)) return TRUE; } - if(RangeMediumValid) + if(bRangeMediumValid) { // Hold Animal - animals are paralyzed on a will save failure. if(GlobalSpellTargetRace == RACIAL_TYPE_ANIMAL && !AI_GetSpellTargetImmunity(GlobalImmunityStun) && !AI_GetSpellTargetImmunity(GlobalImmunityMind) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i2)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 2)) { // Hold Animal. Level 2 (Druid/Ranger) Paralyze's an amimal race target, if they fail a will save. - if(AI_ActionCastSpellRandom(SPELL_HOLD_PERSON, SpellHostRanged, i50, GlobalSpellTarget, i12, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_HOLD_ANIMAL, 50, GlobalSpellTarget, 12, FALSE)) return TRUE; } // Blindness/Deafness is a pretty good spell. if(!AI_GetSpellTargetImmunity(GlobalImmunityBlindDeaf) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, i2)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, 2)) { // Blindness/Deafness. Level 2 (Mage/Bard) 3 (Cleric) Blindness/deafness on Fort save failure. - if(AI_ActionCastSpellRandom(SPELL_BLINDNESS_AND_DEAFNESS, SpellHostRanged, i50, GlobalSpellTarget, i12, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_BLINDNESS_AND_DEAFNESS, 50, GlobalSpellTarget, 12, FALSE)) return TRUE; } // Tasha's Hideous Laughter is knockdown - not too bad. // - We don't bother with the +4/-4. if(!AI_GetSpellTargetImmunity(GlobalImmunityMind) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i2)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 2)) { // Tasha's Hideous Laughter. Level 2 (Bard/Mage) Knockdown for 1d3 rounds, if fail will save. -4 DC if different races - if(AI_ActionCastSpellRandom(SPELL_TASHAS_HIDEOUS_LAUGHTER, SpellHostRanged, i50, GlobalSpellTarget, i12, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_TASHAS_HIDEOUS_LAUGHTER, 50, GlobalSpellTarget, 12, FALSE)) return TRUE; } } - if(RangeShortValid) + if(bRangeShortValid) { // Charm Person or Animal. Charms an animal, or humanoid, if fail mind will save. if(!AI_GetSpellTargetImmunity(GlobalImmunityDomination) && !AI_GetSpellTargetImmunity(GlobalImmunityMind) && (GetIsPlayableRacialType(GlobalSpellTarget) || GlobalSpellTargetRace == RACIAL_TYPE_ANIMAL) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i2)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 2)) { // Charm Person or Animal. Level 2 (Druid) Charms an animal, or humanoid, if fail mind will save. - if(AI_ActionCastSpellRandom(SPELL_CHARM_PERSON_OR_ANIMAL, SpellHostRanged, i50, GlobalSpellTarget, i12, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_CHARM_PERSON_OR_ANIMAL, 50, GlobalSpellTarget, 12, FALSE)) return TRUE; } } // Single spell override backup casting - if(SingleSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; + if(bSingleSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; } // AOE: @@ -10323,171 +10252,170 @@ H X [Aura of Glory] - +4 Char, and allies get +4 VS Fear effects. // Silence - must be a mage or sorceror. No talent for this, BTW. Also // note: can't have the spell's effects already, and must be over 10M away. - if(RangeLongValid && GlobalSpellTargetRange >= f10 && + if(bRangeLongValid && GlobalSeenSpell && GlobalSpellTargetRange >= 10.0 && !GetHasSpellEffect(SPELL_SILENCE, GlobalSpellTarget) && (GetLevelByClass(CLASS_TYPE_WIZARD, GlobalSpellTarget) || GetLevelByClass(CLASS_TYPE_SORCERER, GlobalSpellTarget) || GetLevelByClass(CLASS_TYPE_CLERIC, GlobalSpellTarget))) { // Silence. Level 2 (Mage/Cleric/Bard) Silence AOE that moves with target. Applies silence to those in the AOE. - if(AI_ActionCastSpellRandom(SPELL_SILENCE, SpellOtherSpell, i60, GlobalSpellTarget, i12)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_SILENCE, 60, GlobalSpellTarget, 12)) return TRUE; } // Gedlee's Electric Loop is a good damaging AOE spell - and the only mage level 2 one. - // - Note, it is set as Discriminate, but is really Indiscriminate (ReactionType) - if(SpellHostAreaDis && RangeShortValid && - (GetHasSpell(SPELL_GEDLEES_ELECTRIC_LOOP) || ItemHostAreaDis == SPELL_GEDLEES_ELECTRIC_LOOP)) + // - Note, it is set as DiscrnMinate, but is really IndiscrnMinate (ReactionType) + if(bRangeShortValid && GetHasSpell(SPELL_GEDLEES_ELECTRIC_LOOP)) { // Small, short ranged, and reflex save based. - oAOE = AI_GetBestAreaSpellTarget(fShortRange, RADIUS_SIZE_SMALL, i2, SAVING_THROW_REFLEX, SHAPE_SPHERE, GlobalFriendlyFireFriendly); + oAOE = AI_GetBestAreaSpellTarget(fShortRange, RADIUS_SIZE_SMALL, 2, SAVING_THROW_REFLEX, SHAPE_SPHERE, GlobalFriendlyFireFriendly); // Is it valid? 70% chance of casting. if(GetIsObjectValid(oAOE)) { // Gedlee's Electric Loop. Level 2 (Mage) All in AOE have 1d6 Electric dam (to 5d6) + will save for 1 round stun. - if(AI_ActionCastSpellRandom(SPELL_GEDLEES_ELECTRIC_LOOP, SpellHostAreaDis, i60, oAOE, i12, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_GEDLEES_ELECTRIC_LOOP, 60, oAOE, 12, TRUE)) return TRUE; } } // Web - sticky stuff. Illusion version first :-D - if(SpellHostAreaInd && RangeMediumValid && - (GetHasSpell(SPELL_WEB) || ItemHostAreaInd == SPELL_WEB || - GetHasSpell(SPELL_GREATER_SHADOW_CONJURATION_WEB) || ItemHostAreaInd == SPELL_GREATER_SHADOW_CONJURATION_WEB)) + if(bRangeMediumValid && (GetHasSpell(SPELL_WEB) || + GetHasSpell(SPELL_GREATER_SHADOW_CONJURATION_WEB) || + GetHasSpell(AI_SPELLABILITY_BEBELITH_WEB))) { // large AOE, medium ranged, reflex based save. Reaction friendly. - oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_LARGE, i2, SAVING_THROW_REFLEX, SHAPE_SPHERE, GlobalFriendlyFireFriendly); + oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_LARGE, 2, SAVING_THROW_REFLEX, SHAPE_SPHERE, GlobalFriendlyFireFriendly); // Is it valid? 70% chance of casting. if(GetIsObjectValid(oAOE)) { - // Shades vesion - shouldn't affect allies. - if(AI_ActionCastSubSpell(SPELL_GREATER_SHADOW_CONJURATION_WEB, SpellHostAreaInd, oAOE, i12, TRUE, ItemHostAreaInd)) return TRUE; - // Beblith version - if(AI_ActionCastSpellRandom(AI_SPELLABILITY_BEBELITH_WEB, SpellHostAreaInd, i60, oAOE)) return TRUE; + if(AI_ActionCastSpellRandom(AI_SPELLABILITY_BEBELITH_WEB, 60, oAOE)) return TRUE; + + // Shades vesion. Shades is Level 6. Cast as subspell. + if(AI_ActionCastSpell(SPELL_GREATER_SHADOW_CONJURATION_WEB, oAOE, 16, TRUE, TRUE)) return TRUE; // Web. Level 2 (Mage) Entangles on reflex sve. - if(AI_ActionCastSpellRandom(SPELL_WEB, SpellHostAreaInd, i60, oAOE, i12, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_WEB, 60, oAOE, 12, TRUE)) return TRUE; } } // Cloud of Bewilderment is an alright AOE - stun and blindness :-) // Note - Only casts if the target is not immune to stun nor blindness! - if(SpellHostAreaInd && RangeMediumValid && + if(bRangeMediumValid && !AI_GetSpellTargetImmunity(GlobalImmunityBlindDeaf) && !AI_GetSpellTargetImmunity(GlobalImmunityStun) && - (GetHasSpell(SPELL_CLOUD_OF_BEWILDERMENT) || ItemHostAreaInd == SPELL_CLOUD_OF_BEWILDERMENT)) + GetHasSpell(SPELL_CLOUD_OF_BEWILDERMENT)) { // 5M radius (large) AOE, short ranged, fort based save. Reaction friendly. - oAOE = AI_GetBestAreaSpellTarget(fShortRange, RADIUS_SIZE_LARGE, i2, SAVING_THROW_FORT, SHAPE_SPHERE, GlobalFriendlyFireFriendly); + oAOE = AI_GetBestAreaSpellTarget(fShortRange, RADIUS_SIZE_LARGE, 2, SAVING_THROW_FORT, SHAPE_SPHERE, GlobalFriendlyFireFriendly); // Is it valid? 60% chance of casting. if(GetIsObjectValid(oAOE)) { // Cloud of Bewilderment. Level 2 (Mage/Bard) Creatures are stunned and blinded in the AOE. Fort save. // Web. Level 2 (Mage) Entangles on reflex sve. - if(AI_ActionCastSpellRandom(SPELL_CLOUD_OF_BEWILDERMENT, SpellHostAreaInd, i50, oAOE, i12, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_CLOUD_OF_BEWILDERMENT, 50, oAOE, 12, TRUE)) return TRUE; } } // Balagarn's Iron Horn is only a 6 second knockdown, not too bad. // Mainly, it has no save. Caster gets +20 on d20, enemy gets strength bonus. // It is a personal, affects us spell :-) - if(GlobalSpellTargetRange <= f5) + if(GlobalSpellTargetRange <= 5.0) { // Balagarn's Iron Horn. Level 2 (Mage) Need to beat (Enemy STR + d20) with 20 + d20. If so, 6 second knockdown - if(AI_ActionCastSpellRandom(SPELL_BALAGARNSIRONHORN, SpellHostAreaDis, i60, OBJECT_SELF, i12, TRUE, ItemHostAreaDis)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_BALAGARNSIRONHORN, 60, OBJECT_SELF, 12, TRUE)) return TRUE; } // Sound burst - best part is the stun! Trust me! Long range too! - if(SpellHostAreaInd && RangeLongValid && - (GetHasSpell(SPELL_SOUND_BURST) || ItemHostAreaInd == SPELL_SOUND_BURST)) + if(bRangeLongValid && GetHasSpell(SPELL_SOUND_BURST)) { // Medium AOE, medium ranged, will based save. Reaction friendly. - oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_MEDIUM, i2, SAVING_THROW_WILL, SHAPE_SPHERE, GlobalFriendlyFireFriendly); + oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_MEDIUM, 2, SAVING_THROW_WILL, SHAPE_SPHERE, GlobalFriendlyFireFriendly); // Is it valid? 60% chance of casting. if(GetIsObjectValid(oAOE)) { // Sound burst. Level 2 (cleric). 1d8 Sonic damage, and if fail will save, stunned for 2 rounds. - if(AI_ActionCastSpellRandom(SPELL_SOUND_BURST, SpellHostAreaInd, i50, oAOE, i12, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_SOUND_BURST, 50, oAOE, 12, TRUE)) return TRUE; } } // Multi spell override backup casting - if(MultiSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; + if(bMultiSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; // Level 2 summons - if(IsFirstRunThrough && GlobalCanSummonSimilarLevel <= i2 && - (GlobalOurHitDice <= i8 || GlobalMeleeAttackers <= i2)) + if(bFirstRunThrough && GlobalCanSummonSimilarLevel <= 2 && + (GlobalOurHitDice <= 8 || GlobalMeleeAttackers <= 2)) { // Summon Monster II (2). Level 2 (Most classes) Summons a Dire Boar. - if(AI_ActionCastSummonSpell(SPELL_SUMMON_CREATURE_II, i12, i2)) return TRUE; + if(AI_ActionCastSummonSpell(SPELL_SUMMON_CREATURE_II, 12, 2)) return TRUE; } // Single spells, lower %'s // - We don't cast inflict serious wounds. GetHasSpell bodges with spontaeous spells. - if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < i2) + if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < 2) { // Ghoul Touch. Paralysis is good :-D - if(RangeTouchValid && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, i2)) + if(bRangeTouchValid && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && + !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, 2)) { // Ghoul Touch. Level 2 (Mage) - Fort save VS paralysis and an AOE on target which gives -2 attack/damage to enemies nearby. - if(AI_ActionCastSpellRandom(SPELL_GHOUL_TOUCH, SpellHostTouch, i30, GlobalSpellTarget, i12, FALSE, ItemHostTouch)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_GHOUL_TOUCH, 30, GlobalSpellTarget, 12, FALSE)) return TRUE; } - if(RangeLongValid) + if(bRangeLongValid) { - if(d10() <= i4) + // Temp addition because ActionCastSpellRandom() doesn't support subspells just yet. + if(d10() <= 4) { // Greater shadow conjuration - if(AI_ActionCastSubSpell(SPELL_GREATER_SHADOW_CONJURATION_ACID_ARROW, SpellHostRanged, GlobalSpellTarget, i12, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpell(SPELL_GREATER_SHADOW_CONJURATION_ACID_ARROW, GlobalSpellTarget, 12, FALSE, TRUE)) return TRUE; } // Acid arrow - decent enough, and persistant damage, and no save. Long range too! // Melf's Acid Arrow. Level 2 (Mage) 3d6 Impact and 1d6 damage for up to 7 rounds (caster level/3) after that - if(AI_ActionCastSpellRandom(SPELL_MELFS_ACID_ARROW, SpellHostRanged, i30, GlobalSpellTarget, i12, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_MELFS_ACID_ARROW, 30, GlobalSpellTarget, 12, FALSE)) return TRUE; } // Continual flame isn't a bad spell - touch spell, and does // continual damage (reflex based) - if(RangeTouchValid && !AI_SaveImmuneSpellTarget(SAVING_THROW_REFLEX, i2)) + if(bRangeTouchValid && !AI_SaveImmuneSpellTarget(SAVING_THROW_REFLEX, 2)) { // Continual Flame. Level 2 (Mage) 3 (Cleric) 2d6 + 1 Caster Level (to +10) Fire dam. Reflex save. Every round after, reflex (until sucess) at 1d6 damage. - if(AI_ActionCastSpellRandom(SPELL_CONTINUAL_FLAME, SpellHostTouch, i30, GlobalSpellTarget, i12, FALSE, ItemHostTouch)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_CONTINUAL_FLAME, 30, GlobalSpellTarget, 12, FALSE)) return TRUE; } // Flame Lash is an alright amount of flame damage. - if(RangeShortValid && !AI_SaveImmuneSpellTarget(SAVING_THROW_REFLEX, i2)) + if(bRangeShortValid && !AI_SaveImmuneSpellTarget(SAVING_THROW_REFLEX, 2)) { // [Flame Lash] 2d6 + 1d6/3 caster levels of fire damage. Reflex save. - if(AI_ActionCastSpellRandom(SPELL_FLAME_LASH, SpellHostRanged, i30, GlobalSpellTarget, i12, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_FLAME_LASH, 30, GlobalSpellTarget, 12, FALSE)) return TRUE; } - if(RangeMediumValid) + if(bRangeMediumValid) { // Hold Animal - animals are paralyzed on a will save failure. if(GlobalSpellTargetRace == RACIAL_TYPE_ANIMAL && !AI_GetSpellTargetImmunity(GlobalImmunityStun) && !AI_GetSpellTargetImmunity(GlobalImmunityMind) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i2)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 2)) { // Hold Animal. Level 2 (Druid/Ranger) Paralyze's an amimal race target, if they fail a will save. - if(AI_ActionCastSpellRandom(SPELL_HOLD_PERSON, SpellHostRanged, i30, GlobalSpellTarget, i12, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_HOLD_PERSON, 30, GlobalSpellTarget, 12, FALSE)) return TRUE; } // Blindness/Deafness is a pretty good spell. if(!AI_GetSpellTargetImmunity(GlobalImmunityBlindDeaf) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, i2)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, 2)) { // Blindness/Deafness. Level 2 (Mage/Bard) 3 (Cleric) Blindness/deafness on Fort save failure. - if(AI_ActionCastSpellRandom(SPELL_BLINDNESS_AND_DEAFNESS, SpellHostRanged, i30, GlobalSpellTarget, i12, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_BLINDNESS_AND_DEAFNESS, 30, GlobalSpellTarget, 12, FALSE)) return TRUE; } // Tasha's Hideous Laughter is knockdown - not too bad. // - We don't bother with the +4/-4. if(!AI_GetSpellTargetImmunity(GlobalImmunityMind) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i2)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 2)) { // Tasha's Hideous Laughter. Level 2 (Bard/Mage) Knockdown for 1d3 rounds, if fail will save. -4 DC if different races - if(AI_ActionCastSpellRandom(SPELL_TASHAS_HIDEOUS_LAUGHTER, SpellHostRanged, i30, GlobalSpellTarget, i12, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_TASHAS_HIDEOUS_LAUGHTER, 30, GlobalSpellTarget, 12, FALSE)) return TRUE; } } - if(RangeShortValid) + if(bRangeShortValid) { // Charm Person or Animal. Charms an animal, or humanoid, if fail mind will save. if(!AI_GetSpellTargetImmunity(GlobalImmunityDomination) && !AI_GetSpellTargetImmunity(GlobalImmunityMind) && (GetIsPlayableRacialType(GlobalSpellTarget) || GlobalSpellTargetRace == RACIAL_TYPE_ANIMAL) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i2)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 2)) { // Charm Person or Animal. Level 2 (Druid) Charms an animal, or humanoid, if fail mind will save. - if(AI_ActionCastSpellRandom(SPELL_CHARM_PERSON_OR_ANIMAL, SpellHostRanged, i20, GlobalSpellTarget, i12, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_CHARM_PERSON_OR_ANIMAL, 20, GlobalSpellTarget, 12, FALSE)) return TRUE; } } } @@ -10496,15 +10424,24 @@ H X [Aura of Glory] - +4 Char, and allies get +4 VS Fear effects. if(AI_ActionCastBackupRandomSpell()) return TRUE; // Moderate wounds - damage at a touch attack. - if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < i2 && RangeTouchValid && - !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && - !AI_GetSpellTargetImmunity(GlobalImmunityNegativeEnergy)) + if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < 3 && bRangeTouchValid) { - // Blackguard ability - if(AI_ActionUseFeatOnObject(FEAT_INFLICT_MODERATE_WOUNDS, GlobalMeleeTarget)) return TRUE; + // Cast Cure Critical Wounds (Which acts the same way for undead as + // inflict critical does) + if(GlobalSpellTargetRace == RACIAL_TYPE_UNDEAD) + { + // Cure Moderate Wounds. Level 2 (Cleric) Touch attack, hit means 2d8 + 1-10 positive damage. + if(AI_ActionCastSpontaeousSpell(SPELL_INFLICT_MODERATE_WOUNDS, GlobalSpellTarget)) return TRUE; + } + if(!AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && + !AI_GetSpellTargetImmunity(GlobalImmunityNegativeEnergy)) + { + // Blackguard ability + if(AI_ActionUseSpellLikeFeat(FEAT_INFLICT_MODERATE_WOUNDS, SPELLABILITY_BG_INFLICT_SERIOUS_WOUNDS, GlobalMeleeTarget)) return TRUE; - // Inflict Moderate Wounds. Level 2 (Cleric) Touch attack, hit means 2d8 + 1-10 negative damage. - if(AI_ActionCastSpontaeousSpell(SPELL_INFLICT_MODERATE_WOUNDS, SpellOtherSpell, GlobalSpellTarget)) return TRUE; + // Inflict Moderate Wounds. Level 2 (Cleric) Touch attack, hit means 2d8 + 1-10 negative damage. + if(AI_ActionCastSpontaeousSpell(SPELL_INFLICT_MODERATE_WOUNDS, GlobalSpellTarget)) return TRUE; + } } /*::1111111111111111111111111111111111111111111111111111111111111111111111111111 @@ -10568,10 +10505,10 @@ H X [Deafening Clang] +1 enchantment. +3 sonic damage. On Hit: Deafness, on a we //::11111111111111111111111111111111111111111111111111111111111111111111111111*/ // Jump out if we don't want to cast level 1 spells. - if(iLowestSpellLevel > i1) return FALSE; + if(nLowestSpellLevel > 1) return FALSE; // Ok, AC increasing/defensive spells first. - if(IsFirstRunThrough) + if(bFirstRunThrough) { // Entropic shield. 20% VS ranged attackers - we need some ranged attackers // OR people far away (After other AC spells). Also no normal consealment spells (they don't stack) @@ -10581,7 +10518,7 @@ H X [Deafening Clang] +1 enchantment. +3 sonic damage. On Hit: Deafness, on a we !AI_GetAIHaveEffect(GlobalEffectInvisible)) { // Entropic Shield. Level 1 (Cleric) 20% Consealment VS ranged attacks. - if(AI_ActionCastSpell(SPELL_ENTROPIC_SHIELD, SpellProSinTar, OBJECT_SELF, i11, FALSE, ItemProSinTar, PotionPro)) return TRUE; + if(AI_ActionCastSpell(SPELL_ENTROPIC_SHIELD, OBJECT_SELF, 11, FALSE)) return TRUE; } // We don't cast AC spells which will not do well over other AC inducing spells @@ -10593,18 +10530,18 @@ H X [Deafening Clang] +1 enchantment. +3 sonic damage. On Hit: Deafness, on a we if(!AI_GetAIHaveSpellsEffect(GlobalHasDeflectionACSpell)) { // Shield. Level 1 (Mage) +4 Armor AC and immunity to magic missile. - if(AI_ActionCastSpell(SPELL_SHIELD, SpellProSinTar, OBJECT_SELF, i11, FALSE, ItemProSinTar, PotionPro)) return TRUE; + if(AI_ActionCastSpell(SPELL_SHIELD, OBJECT_SELF, 11, FALSE)) return TRUE; // Shield of Faith. Level 1 (Cleric) +2 deflection AC bonus, +1 every 6 levels (max +5) - if(AI_ActionCastSpell(SPELL_SHIELD_OF_FAITH, SpellProSinTar, OBJECT_SELF, i11, FALSE, ItemProSinTar, PotionPro)) return TRUE; + if(AI_ActionCastSpell(SPELL_SHIELD_OF_FAITH, OBJECT_SELF, 11, FALSE)) return TRUE; } // If we have not got natural or other AC, we cast mage armor. if(!AI_GetAIHaveSpellsEffect(GlobalHasNaturalACSpell) && !AI_GetAIHaveSpellsEffect(GlobalHasOtherACSpell)) { // Shadow conjuration version - if(AI_ActionCastSubSpell(SPELL_SHADOW_CONJURATION_MAGE_ARMOR, SpellProSinTar, OBJECT_SELF, i11, FALSE, ItemProSinTar, PotionPro)) return TRUE; - // Mage Armor. Level 1 (MagE) +1 Dodge/Armor/Deflection/Natural AC bonuses. (total +4) - if(AI_ActionCastSpell(SPELL_MAGE_ARMOR, SpellProSinTar, OBJECT_SELF, i11, FALSE, ItemProSinTar, PotionPro)) return TRUE; + if(AI_ActionCastSpell(SPELL_SHADOW_CONJURATION_MAGE_ARMOR, OBJECT_SELF, 11, FALSE, TRUE)) return TRUE; + // Mage Armor. Level 1 (Mage) +1 Dodge/Armor/Deflection/Natural AC bonuses. (total +4) + if(AI_ActionCastSpell(SPELL_MAGE_ARMOR, OBJECT_SELF, 11, FALSE)) return TRUE; } // Cast Entropic shield if nearest enemy is over 4 M away. @@ -10614,28 +10551,29 @@ H X [Deafening Clang] +1 enchantment. +3 sonic damage. On Hit: Deafness, on a we !AI_GetAIHaveEffect(GlobalEffectInvisible)) { // Entropic Shield. Level 1 (Cleric) 20% Consealment VS ranged attacks. - if(AI_ActionCastSpell(SPELL_ENTROPIC_SHIELD, SpellProSinTar, OBJECT_SELF, i11, FALSE, ItemProSinTar, PotionPro)) return TRUE; + if(AI_ActionCastSpell(SPELL_ENTROPIC_SHIELD, OBJECT_SELF, 11, FALSE)) return TRUE; } // Cheat and use protection froms. Have to rely upon talents :-/ // as cannot specify using ActionCast - it plain don't wanna work. - if(iEnemyAlignment == ALIGNMENT_GOOD && + // Both cast as subspells. + if(nEnemyAlignment == ALIGNMENT_GOOD && !AI_GetAIHaveSpellsEffect(GlobalHasProtectionGoodSpell)) { // Protection From Alignment. Level 1 (Bard/Cleric/Paladin/Mage). +2 AC, mind immunity from alignment - if(AI_ActionCastSubSpell(SPELL_PROTECTION_FROM_GOOD, SpellProSinTar, OBJECT_SELF, i11, FALSE, ItemProSinTar, PotionPro)) return TRUE; + if(AI_ActionCastSpell(SPELL_PROTECTION_FROM_GOOD, OBJECT_SELF, 11, FALSE, TRUE)) return TRUE; } - else if(iEnemyAlignment == ALIGNMENT_EVIL && + else if(nEnemyAlignment == ALIGNMENT_EVIL && !AI_GetAIHaveSpellsEffect(GlobalHasProtectionEvilSpell)) { - if(AI_ActionCastSubSpell(SPELL_PROTECTION_FROM_EVIL, SpellProSinTar, OBJECT_SELF, i11, FALSE, ItemProSinTar, PotionPro)) return TRUE; + if(AI_ActionCastSpell(SPELL_PROTECTION_FROM_EVIL, OBJECT_SELF, 11, FALSE, TRUE)) return TRUE; } // Ally buff spells if buffer if(GlobalWeAreBuffer) { // Bless, Aid - if(AI_ActionCastAllyBuffSpell(f6, i100, SPELL_AID, SPELL_BLESS)) return TRUE; + if(AI_ActionCastAllyBuffSpell(6.0, 100, SPELL_AID, SPELL_BLESS)) return TRUE; } } @@ -10644,7 +10582,7 @@ H X [Deafening Clang] +1 enchantment. +3 sonic damage. On Hit: Deafness, on a we // normally even mages have a +X to attack, this provides a good indicator // if we are going to easy, or very easily, hit the enemy. // - Clerics, Druids and Bards must be able to hit even better then normal. - if(IsFirstRunThrough && !SRA && + if(bFirstRunThrough && !SRA && GlobalOurChosenClass != CLASS_TYPE_WIZARD && GlobalOurChosenClass != CLASS_TYPE_SORCERER && GlobalOurChosenClass != CLASS_TYPE_FEY) @@ -10656,19 +10594,19 @@ H X [Deafening Clang] +1 enchantment. +3 sonic damage. On Hit: Deafness, on a we GlobalOurChosenClass == CLASS_TYPE_BARD) { // BAB check for level 4 spells. 50% - if(GlobalOurBaseAttackBonus+ i10 >= GlobalMeleeTargetAC) return FALSE; + if(GlobalOurBaseAttackBonus+ 10 >= GlobalMeleeTargetAC) return FALSE; } // Demons, fighters, anything else really. else { // BAB check for level 4 spells. 25% - if(GlobalOurBaseAttackBonus + i15 >= GlobalMeleeTargetAC) return FALSE; + if(GlobalOurBaseAttackBonus + 15 >= GlobalMeleeTargetAC) return FALSE; } } // Try grenades - we always throw these. They are about level 1 standard of DC's // and effects. Not too bad, when NPC's get a chance to use them! :-) - if(RangeMediumValid) + if(bRangeMediumValid) { // - Note, these are also always thrown before melee, if the person has <5 HD. // - Reasons for not casting are really the BAB checks. @@ -10690,26 +10628,27 @@ H X [Deafening Clang] +1 enchantment. +3 sonic damage. On Hit: Deafness, on a we // one target, if there is one target, then the AOE spells usually. // 60-70% if favourable. // - We don't cast inflict light wounds. GetHasSpell bodges with spontaeous spells. - if(SingleSpellsFirst && GlobalNormalSpellsNoEffectLevel < i1) + if(bSingleSpellsFirst && GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < 1) { // Magic Missile - Is a nice long range spell. Can do damage to almost anything. - if(RangeLongValid && !GetHasSpellEffect(SPELL_SHIELD, GlobalSpellTarget)) + if(bRangeLongValid && !GetHasSpellEffect(SPELL_SHIELD, GlobalSpellTarget)) { - if(d10() <= i6) + // as others, AI_ActionCastSpellRandom() ain't got subspell suppor yet. + if(d10() <= 6) { // Shad. conjuration - if(AI_ActionCastSubSpell(SPELL_SHADOW_CONJURATION_MAGIC_MISSILE, SpellHostRanged, GlobalSpellTarget, i11, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpell(SPELL_SHADOW_CONJURATION_MAGIC_MISSILE, GlobalSpellTarget, 11, FALSE, TRUE)) return TRUE; } // Magic Missile. Level 1 (Mage) 1d4 + 1 damage/missile. 1 missile for 2 caster levels. Max 5 at level 9. - if(AI_ActionCastSpellRandom(SPELL_MAGIC_MISSILE, SpellHostRanged, i60, GlobalSpellTarget, i11, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_MAGIC_MISSILE, 60, GlobalSpellTarget, 11, FALSE)) return TRUE; } // Horizikaul's boom is sonic damage - no save! Also, goes also to 5d4 (at level 10 anyway). Comparable to MM! - if(RangeShortValid) + if(bRangeShortValid) { // Horzilkaul's Boom. Level 1 (Mage) 1d4/2 caster levels (to 5d4) sonic damage, + Will VS deafness. - if(AI_ActionCastSpellRandom(SPELL_HORIZIKAULS_BOOM, SpellHostRanged, i50, GlobalSpellTarget, i11, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_HORIZIKAULS_BOOM, 50, GlobalSpellTarget, 11, FALSE)) return TRUE; } - if(RangeMediumValid) + if(bRangeMediumValid) { // Negative energy ray is similar to Magic Missile, but heals undead. can do more dmage then MM, but more random - d6 compared to d4 + 1. if(GlobalSpellTargetRace != RACIAL_TYPE_UNDEAD && @@ -10718,53 +10657,53 @@ H X [Deafening Clang] +1 enchantment. +3 sonic damage. On Hit: Deafness, on a we !AI_GetSpellTargetImmunity(GlobalImmunityNegativeEnergy)) { // Negative Energy Ray. Level 1 (Mage) 2 (Cleric) 1d6(CasterLevel/2) to 5d6 negative damage. - if(AI_ActionCastSpellRandom(SPELL_NEGATIVE_ENERGY_RAY, SpellHostRanged, i50, GlobalSpellTarget, i11, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_NEGATIVE_ENERGY_RAY, 50, GlobalSpellTarget, 11, FALSE)) return TRUE; } // Doom does some...stuff. The damage -2 is best. Will save negates. if(!GetHasSpellEffect(SPELL_DOOM, GlobalSpellTarget) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i1)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 1)) { // Doom. Level 1 (Mage) -2 Saves, Damage, to hit at a mind will save. - if(AI_ActionCastSpellRandom(SPELL_DOOM, SpellHostRanged, i50, GlobalSpellTarget, i11, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_DOOM, 50, GlobalSpellTarget, 11, FALSE)) return TRUE; } } - if(RangeShortValid) + if(bRangeShortValid) { // Damage with Ice Dagger is not bad - it is cirtinly comparable to MM! Saves though... - if(!AI_SaveImmuneSpellTarget(SAVING_THROW_REFLEX, i1)) + if(!AI_SaveImmuneSpellTarget(SAVING_THROW_REFLEX, 1)) { // Ice Dagger. Level 1 (Mage) Reflex-based, 1d4/Level (to 5d4) ice damage. - if(AI_ActionCastSpellRandom(SPELL_ICE_DAGGER, SpellHostRanged, i50, GlobalSpellTarget, i11, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_ICE_DAGGER, 50, GlobalSpellTarget, 11, FALSE)) return TRUE; } // Scare - needs 5HD or under HD if(!AI_GetSpellTargetImmunity(GlobalImmunityFear) && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i1)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 1)) { // Scare. Level 1 (Mage) 1d4 round of fear, saving throw VS will, for 5HD or less creature - if(AI_ActionCastSpellRandom(SPELL_SCARE, SpellHostRanged, i50, GlobalSpellTarget, i11, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_SCARE, 50, GlobalSpellTarget, 11, FALSE)) return TRUE; } // Ray of Enfeeblement pities high strength enemies. d6 + 1-10 str. Loss - if(GetAbilityScore(GlobalSpellTarget, ABILITY_STRENGTH) >= i14 && + if(GetAbilityScore(GlobalSpellTarget, ABILITY_STRENGTH) >= 14 && !GetHasSpellEffect(SPELL_RAY_OF_ENFEEBLEMENT, GlobalSpellTarget) && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, i1)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, 1)) { // Ray of Enfeeblement. Level 1 (Mage) d6 + (Caster level/2) strength damage to d6 + 10. Fort save. - if(AI_ActionCastSpellRandom(SPELL_RAY_OF_ENFEEBLEMENT, SpellHostRanged, i40, GlobalSpellTarget, i11, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_RAY_OF_ENFEEBLEMENT, 40, GlobalSpellTarget, 11, FALSE)) return TRUE; } // Charm Person charms them. Might as well... (Bit bad this spell) if(GetIsPlayableRacialType(GlobalSpellTarget) && !AI_GetSpellTargetImmunity(GlobalImmunityDomination) && !AI_GetSpellTargetImmunity(GlobalImmunityMind) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i2)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 2)) { // Charm Person. Level 1 (Mage/Bard) Charms one humanoid if they fail a mind will save. - if(AI_ActionCastSpellRandom(SPELL_CHARM_PERSON, SpellHostRanged, i30, GlobalSpellTarget, i11, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_CHARM_PERSON, 30, GlobalSpellTarget, 11, FALSE)) return TRUE; } } // Single spell override backup casting - if(SingleSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; + if(bSingleSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; } // Random AOE spell. @@ -10776,123 +10715,118 @@ H X [Deafening Clang] +1 enchantment. +3 sonic damage. On Hit: Deafness, on a we // [Entangle] - Entangles creatures in the AOE so they cannot move, reflex save, every round. // Burning hands - fire reflex damage to a cone - if(SpellHostAreaInd && RangeShortValid && - (GetHasSpell(SPELL_BURNING_HANDS) || ItemHostAreaInd == SPELL_BURNING_HANDS)) + if(bRangeShortValid && GetHasSpell(SPELL_BURNING_HANDS)) { // Cone AOE, short ranged, reflex based save. Reaction friendly. - oAOE = AI_GetBestAreaSpellTarget(fShortRange, f10, i1, SAVING_THROW_REFLEX, SHAPE_SPELLCONE, GlobalFriendlyFireFriendly); + oAOE = AI_GetBestAreaSpellTarget(fShortRange, 10.0, 1, SAVING_THROW_REFLEX, SHAPE_SPELLCONE, GlobalFriendlyFireFriendly); // Is it valid? 70% chance of casting. if(GetIsObjectValid(oAOE)) { // Burning Hands. Level 1 (Mage) 1d4/level to 5d4 Reflex Fire damage to a cone AOE. - if(AI_ActionCastSpellRandom(SPELL_BURNING_HANDS, SpellHostAreaInd, i60, oAOE, i11, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_BURNING_HANDS, 60, oAOE, 11, TRUE)) return TRUE; } } // Color Spray - Does at least blind higher levels. Will save, however, negates - if(SpellHostAreaInd && RangeShortValid && - (GetHasSpell(SPELL_COLOR_SPRAY) || ItemHostAreaInd == SPELL_COLOR_SPRAY)) + if(bRangeShortValid && GetHasSpell(SPELL_COLOR_SPRAY)) { // Cone AOE, short ranged, reflex based save. Reaction friendly. - oAOE = AI_GetBestAreaSpellTarget(fShortRange, f10, i1, SAVING_THROW_WILL, SHAPE_SPELLCONE, GlobalFriendlyFireFriendly); + oAOE = AI_GetBestAreaSpellTarget(fShortRange, 10.0, 1, SAVING_THROW_WILL, SHAPE_SPELLCONE, GlobalFriendlyFireFriendly); // Is it valid? 70% chance of casting. if(GetIsObjectValid(oAOE)) { // Color Spray. Level 1 (Mage) - effect based on HD - Sleep Stun and Blindness if fail will save - if(AI_ActionCastSpellRandom(SPELL_COLOR_SPRAY, SpellHostAreaInd, i50, oAOE, i11, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_COLOR_SPRAY, 50, oAOE, 11, TRUE)) return TRUE; } } // Grease means knockdown - good if they are not immune to knockdown :-P (reflex save) - if(SpellHostAreaInd && RangeLongValid && - (GetHasSpell(SPELL_GREASE) || ItemHostAreaInd == SPELL_GREASE)) + if(bRangeLongValid && GetHasSpell(SPELL_GREASE)) { // Take as Medium AOE, long ranged, reflex based save. Reaction friendly. - oAOE = AI_GetBestAreaSpellTarget(fLongRange, RADIUS_SIZE_MEDIUM, i1, SAVING_THROW_REFLEX, SHAPE_SPHERE, GlobalFriendlyFireFriendly); + oAOE = AI_GetBestAreaSpellTarget(fLongRange, RADIUS_SIZE_MEDIUM, 1, SAVING_THROW_REFLEX, SHAPE_SPHERE, GlobalFriendlyFireFriendly); // Is it valid? 60% chance of casting. if(GetIsObjectValid(oAOE)) { // Grease. Level 1 (Mage) Reflex save or knockdown, and slow in AOE. - if(AI_ActionCastSpellRandom(SPELL_GREASE, SpellHostAreaInd, i50, oAOE, i11, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_GREASE, 50, oAOE, 11, TRUE)) return TRUE; } } // Sleep - 8HD or less average HD for enemy to target this. - if(SpellHostAreaInd && RangeMediumValid && GlobalAverageEnemyHD <= i8 && - (GetHasSpell(SPELL_SLEEP) || GetHasFeat(FEAT_HARPER_SLEEP) || ItemHostAreaInd == SPELL_SLEEP)) + if(bRangeMediumValid && GlobalAverageEnemyHD <= 8 && + (GetHasSpell(SPELL_SLEEP) || GetHasFeat(FEAT_HARPER_SLEEP))) { // Huge AOE, medium ranged, will based save. Reaction type enemy - oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_HUGE, i1, SAVING_THROW_WILL, SHAPE_SPHERE, GlobalFriendlyFireHostile); + oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_HUGE, 1, SAVING_THROW_WILL, SHAPE_SPHERE, GlobalFriendlyFireHostile); // Is it valid? 60% chance of casting. if(GetIsObjectValid(oAOE)) { // The harper sleep - if(AI_ActionUseFeatOnObject(FEAT_HARPER_SLEEP, oAOE)) return TRUE; + if(AI_ActionUseSpellLikeFeat(FEAT_HARPER_SLEEP, AI_SPELLABILITY_HARPER_SLEEP, oAOE)) return TRUE; // Sleep. Level 1 (Mage) 8HD or under creatures, will save VS sleep. Can do more then 1, if total HD affected under d4 + 4. - if(AI_ActionCastSpellRandom(SPELL_SLEEP, SpellHostAreaInd, i50, oAOE, i11, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_SLEEP, 50, oAOE, 11, TRUE)) return TRUE; } } // Bane is...alright, I guess. Will save, however. It doesn't affect allies though! - if(SpellEnhSinTar && RangeLongValid && - (GetHasSpell(SPELL_BANE) || ItemEnhSinTar == SPELL_BANE)) + if(bRangeLongValid && GetHasSpell(SPELL_BANE)) { // collosal AOE, long ranged, will based save. No allies - oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_COLOSSAL, i1, SAVING_THROW_WILL); + oAOE = AI_GetBestAreaSpellTarget(fMediumRange, RADIUS_SIZE_COLOSSAL, 1, SAVING_THROW_WILL); // Is it valid? 60% chance of casting. if(GetIsObjectValid(oAOE)) { // Sleep. Level 1 (Mage) 8HD or under creatures, will save VS sleep. Can do more then 1, if total HD affected under d4 + 4. - if(AI_ActionCastSpellRandom(SPELL_BANE, SpellEnhSinTar, i50, oAOE, i11, TRUE, ItemEnhSinTar)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_BANE, 50, oAOE, 11, TRUE)) return TRUE; } } // Entangle stops them moving - not a bad spell to say the least, I guess - if(SpellHostAreaInd && RangeLongValid && - (GetHasSpell(SPELL_ENTANGLE) || ItemHostAreaInd == SPELL_ENTANGLE)) + if(bRangeLongValid && GetHasSpell(SPELL_ENTANGLE)) { // Huge AOE, Long ranged, reflex based save. Reaction type friendly - oAOE = AI_GetBestAreaSpellTarget(fLongRange, RADIUS_SIZE_HUGE, i1, SAVING_THROW_REFLEX, SHAPE_SPHERE, GlobalFriendlyFireFriendly); + oAOE = AI_GetBestAreaSpellTarget(fLongRange, RADIUS_SIZE_HUGE, 1, SAVING_THROW_REFLEX, SHAPE_SPHERE, GlobalFriendlyFireFriendly); // Is it valid? 60% chance of casting. if(GetIsObjectValid(oAOE)) { // Entangle. Level 1 (Druid/Ranger) Entangles creatures in the AOE so they cannot move, reflex save, every round. - if(AI_ActionCastSpellRandom(SPELL_ENTANGLE, SpellHostAreaInd, i50, oAOE, i11, TRUE, ItemHostAreaInd)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_ENTANGLE, 50, oAOE, 11, TRUE)) return TRUE; } } // Multi spell override backup casting - if(MultiSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; + if(bMultiSpellOverride) if(AI_ActionCastBackupRandomSpell()) return TRUE; // Level 1 summons - if(IsFirstRunThrough && GlobalCanSummonSimilarLevel <= i1 && GlobalOurHitDice <= i10 && - (GlobalOurHitDice <= i6 || GlobalMeleeAttackers <= i2)) + if(bFirstRunThrough && GlobalCanSummonSimilarLevel <= 1 && GlobalOurHitDice <= 10 && + (GlobalOurHitDice <= 6 || GlobalMeleeAttackers <= 2)) { // Shelgarn's Persistant Blade. Level 1 (Mage only) Summons a dagger for the caster. - if(AI_ActionCastSummonSpell(SPELL_SHELGARNS_PERSISTENT_BLADE, i11, i1)) return TRUE; + if(AI_ActionCastSummonSpell(SPELL_SHELGARNS_PERSISTENT_BLADE, 11, 1)) return TRUE; // Summon Monster I (1). Level 1 (Most classes) Summons a Dire Badger. - if(AI_ActionCastSummonSpell(SPELL_SUMMON_CREATURE_I, i11, i1)) return TRUE; + if(AI_ActionCastSummonSpell(SPELL_SUMMON_CREATURE_I, 11, 1)) return TRUE; } // Single spells again // Similar %'s as it is level 1 spells. // - We don't cast inflict light wounds. GetHasSpell bodges with spontaeous spells. - if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < i1) + if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < 1) { // Magic Missile - Is a nice long range spell. Can do damage to almost anything. - if(RangeLongValid && !GetHasSpellEffect(SPELL_SHIELD, GlobalSpellTarget)) + if(bRangeLongValid && !GetHasSpellEffect(SPELL_SHIELD, GlobalSpellTarget)) { // Shad. conjuration - if(d10() <= i4) + if(d10() <= 4) { - if(AI_ActionCastSubSpell(SPELL_SHADOW_CONJURATION_MAGIC_MISSILE, SpellHostRanged, GlobalSpellTarget, i11, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpell(SPELL_SHADOW_CONJURATION_MAGIC_MISSILE, GlobalSpellTarget, 11, FALSE, TRUE)) return TRUE; } // Magic Missile. Level 1 (Mage) 1d4 + 1 damage/missile. 1 missile for 2 caster levels. Max 5 at level 9. - if(AI_ActionCastSpellRandom(SPELL_MAGIC_MISSILE, SpellHostRanged, i30, GlobalSpellTarget, i11, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_MAGIC_MISSILE, 30, GlobalSpellTarget, 11, FALSE)) return TRUE; } // Horizikaul's boom is sonic damage - no save! Also, goes also to 5d4 (at level 10 anyway). Comparable to MM! - if(RangeShortValid) + if(bRangeShortValid) { // Horzilkaul's Boom. Level 1 (Mage) 1d4/2 caster levels (to 5d4) sonic damage, + Will VS deafness. - if(AI_ActionCastSpellRandom(SPELL_HORIZIKAULS_BOOM, SpellHostRanged, i30, GlobalSpellTarget, i11, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_HORIZIKAULS_BOOM, 30, GlobalSpellTarget, 11, FALSE)) return TRUE; } - if(RangeMediumValid) + if(bRangeMediumValid) { // Negative energy ray is similar to Magic Missile, but heals undead. can do more dmage then MM, but more random - d6 compared to d4 + 1. if(GlobalSpellTargetRace != RACIAL_TYPE_UNDEAD && @@ -10901,49 +10835,49 @@ H X [Deafening Clang] +1 enchantment. +3 sonic damage. On Hit: Deafness, on a we !AI_GetSpellTargetImmunity(GlobalImmunityNegativeEnergy)) { // Negative Energy Ray. Level 1 (Mage) 2 (Cleric) 1d6(CasterLevel/2) to 5d6 negative damage. - if(AI_ActionCastSpellRandom(SPELL_NEGATIVE_ENERGY_RAY, SpellHostRanged, i30, GlobalSpellTarget, i11, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_NEGATIVE_ENERGY_RAY, 30, GlobalSpellTarget, 11, FALSE)) return TRUE; } // Doom does some...stuff. The damage -2 is best. Will save negates. if(!GetHasSpellEffect(SPELL_DOOM, GlobalSpellTarget) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i1)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 1)) { // Doom. Level 1 (Mage) -2 Saves, Damage, to hit at a mind will save. - if(AI_ActionCastSpellRandom(SPELL_DOOM, SpellHostRanged, i30, GlobalSpellTarget, i11, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_DOOM, 30, GlobalSpellTarget, 11, FALSE)) return TRUE; } } - if(RangeShortValid) + if(bRangeShortValid) { // Damage with Ice Dagger is not bad - it is cirtinly comparable to MM! Saves though... - if(!AI_SaveImmuneSpellTarget(SAVING_THROW_REFLEX, i1)) + if(!AI_SaveImmuneSpellTarget(SAVING_THROW_REFLEX, 1)) { // Ice Dagger. Level 1 (Mage) Reflex-based, 1d4/Level (to 5d4) ice damage. - if(AI_ActionCastSpellRandom(SPELL_ICE_DAGGER, SpellHostRanged, i30, GlobalSpellTarget, i11, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_ICE_DAGGER, 30, GlobalSpellTarget, 11, FALSE)) return TRUE; } // Scare - needs 5HD or under HD if(!AI_GetSpellTargetImmunity(GlobalImmunityFear) && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i1)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 1)) { // Scare. Level 1 (Mage) 1d4 round of fear, saving throw VS will, for 5HD or less creature - if(AI_ActionCastSpellRandom(SPELL_SCARE, SpellHostRanged, i20, GlobalSpellTarget, i11, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_SCARE, 20, GlobalSpellTarget, 11, FALSE)) return TRUE; } // Ray of Enfeeblement pities high strength enemies. d6 + 1-10 str. Loss - if(GetAbilityScore(GlobalSpellTarget, ABILITY_STRENGTH) >= i14 && + if(GetAbilityScore(GlobalSpellTarget, ABILITY_STRENGTH) >= 14 && !GetHasSpellEffect(SPELL_RAY_OF_ENFEEBLEMENT, GlobalSpellTarget) && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, i1)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, 1)) { // Ray of Enfeeblement. Level 1 (Mage) d6 + (Caster level/2) strength damage to d6 + 10. Fort save. - if(AI_ActionCastSpellRandom(SPELL_RAY_OF_ENFEEBLEMENT, SpellHostRanged, i20, GlobalSpellTarget, i11, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_RAY_OF_ENFEEBLEMENT, 20, GlobalSpellTarget, 11, FALSE)) return TRUE; } // Charm Person charms them. Might as well... (Bit bad this spell) if(GetIsPlayableRacialType(GlobalSpellTarget) && !AI_GetSpellTargetImmunity(GlobalImmunityDomination) && !AI_GetSpellTargetImmunity(GlobalImmunityMind) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i2)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 2)) { // Charm Person. Level 1 (Mage/Bard) Charms one humanoid if they fail a mind will save. - if(AI_ActionCastSpellRandom(SPELL_CHARM_PERSON, SpellHostRanged, i10, GlobalSpellTarget, i11, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_CHARM_PERSON, 10, GlobalSpellTarget, 11, FALSE)) return TRUE; } } } @@ -10952,31 +10886,37 @@ H X [Deafening Clang] +1 enchantment. +3 sonic damage. On Hit: Deafness, on a we if(AI_ActionCastBackupRandomSpell()) return TRUE; // Light wounds - damage at a touch attack. - if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < i1 && RangeTouchValid && - !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && - !AI_GetSpellTargetImmunity(GlobalImmunityNegativeEnergy)) + if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < 3 && bRangeTouchValid) { - // Blackguard ability. - if(AI_ActionUseFeatOnObject(FEAT_INFLICT_LIGHT_WOUNDS, GlobalMeleeTarget)) return TRUE; - - // Inflict Light Wounds. Level 1 (Cleric) Touch attack, hit means 1d8 + 1-5 negative damage. - if(AI_ActionCastSpontaeousSpell(SPELL_INFLICT_LIGHT_WOUNDS, SpellOtherSpell, GlobalSpellTarget)) return TRUE; + // Cast Cure Critical Wounds (Which acts the same way for undead as + // inflict critical does) + if(GlobalSpellTargetRace == RACIAL_TYPE_UNDEAD) + { + // Cure Light Wounds. Level 1 (Cleric) Touch attack, hit means 1d8 + 1-5 positive damage. + if(AI_ActionCastSpontaeousSpell(SPELL_CURE_MODERATE_WOUNDS, GlobalSpellTarget)) return TRUE; + } + if(!AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && + !AI_GetSpellTargetImmunity(GlobalImmunityNegativeEnergy)) + { + // Inflict Light Wounds. Level 1 (Cleric) Touch attack, hit means 1d8 + 1-5 negative damage. + if(AI_ActionCastSpontaeousSpell(SPELL_INFLICT_LIGHT_WOUNDS, GlobalSpellTarget)) return TRUE; + } } // Lastly, cheat cast spells. We cast these if we run out of all others // - Cast ABOVE level 0 spells. - if(GetAIConstant(AI_CHEAT_CAST_SPELL + s1) >= FALSE) + if(GetAIConstant(AI_CHEAT_CAST_SPELL + "1") >= FALSE) { // It is normally 6 spells. It will default to the first if one // we pick is not valid. - int iSpell = GetAIConstant(AI_CHEAT_CAST_SPELL + IntToString(d6())); - if(iSpell <= i0) + int nSpell = GetAIConstant(AI_CHEAT_CAST_SPELL + IntToString(d6())); + if(nSpell <= 0) { - iSpell = GetAIConstant(AI_CHEAT_CAST_SPELL + s1); + nSpell = GetAIConstant(AI_CHEAT_CAST_SPELL + "1"); } - // 33: "[DCR:Casting] Cheat Spell. End of Spells. [Spell] " + IntToString(iSpell) + "[Target]" + GetName(GlobalSpellTarget) - DebugActionSpeakByInt(33, GlobalSpellTarget, iSpell); - ActionCastSpellAtObject(iSpell, GlobalSpellTarget, METAMAGIC_NONE, TRUE); + // 33: "[DCR:Casting] Cheat Spell. End of Spells. [Spell] " + IntToString(nSpell) + "[Target]" + GetName(GlobalSpellTarget) + DebugActionSpeakByInt(33, GlobalSpellTarget, nSpell); + ActionCastSpellAtObject(nSpell, GlobalSpellTarget, METAMAGIC_NONE, TRUE); return TRUE; } @@ -11013,7 +10953,7 @@ S [Inflict Minor Wounds] 1 Negative damage, on a touch attack. Heals undead. //::00000000000000000000000000000000000000000000000000000000000000000000000000*/ // Jump out if we don't want to cast level 0 spells. - if(iLowestSpellLevel > i0) return FALSE; + if(nLowestSpellLevel > 0) return FALSE; // BAB check. if(!SRA && GlobalOurChosenClass != CLASS_TYPE_WIZARD && @@ -11023,17 +10963,17 @@ S [Inflict Minor Wounds] 1 Negative damage, on a touch attack. Heals undead. // BAB check for level 0 spells. if(GlobalOurBaseAttackBonus >= GetAC(GlobalSpellTarget)) return FALSE; // HD check - if(GlobalOurHitDice > i8) return FALSE; + if(GlobalOurHitDice > 8) return FALSE; } - if(IsFirstRunThrough) + if(bFirstRunThrough) { // Need no enemies in 4 meters. if(!GlobalEnemiesIn4Meters) { // Not sure of effectiveness...so acting as a cantrip. // Sanctuary. Level 1 (Cleric). Will save (low DC!) or cannot see target. - if(AI_ActionCastSpell(SPELL_SANCTUARY, SpellEnhSinTar, OBJECT_SELF, i11, FALSE, ItemEnhSinTar, PotionEnh)) return TRUE; + if(AI_ActionCastSpell(SPELL_SANCTUARY, OBJECT_SELF, 11, FALSE)) return TRUE; } // Iron guts are very specifically VS poisoners - I'd see the use if I saw // spiders. I won't bother adding them checks, however, because frankly NPC's @@ -11041,7 +10981,7 @@ S [Inflict Minor Wounds] 1 Negative damage, on a touch attack. Heals undead. if(!GetHasSpellEffect(SPELL_IRONGUTS)) { // Iron Guts. Level 1 (Mage) +4 Saves VS poison. (cast as level 0 spell...this is specilised!) - if(AI_ActionCastSpell(SPELL_IRONGUTS, SpellEnhSinTar, OBJECT_SELF, i11, FALSE, ItemEnhSinTar, PotionEnh)) return TRUE; + if(AI_ActionCastSpell(SPELL_IRONGUTS, OBJECT_SELF, 11, FALSE)) return TRUE; } } @@ -11049,108 +10989,70 @@ S [Inflict Minor Wounds] 1 Negative damage, on a touch attack. Heals undead. // don't care about ranges :-P // Note 2: We have the required amount of stat to 0. We check, On Spawn, // if we can cast spells (IE right stats) and these are the worst we can cast. - if(GlobalNormalSpellsNoEffectLevel < i1 && GlobalSeenSpell) + if(GlobalNormalSpellsNoEffectLevel < 1 && GlobalSeenSpell) { // Random cast one of the 5 hostile cantrip spells // Daze! - if(RangeLongValid && - GlobalSpellTargetHitDice <= i5 && + if(bRangeLongValid && + GlobalSpellTargetHitDice <= 5 && !AI_GetSpellTargetImmunity(GlobalImmunityMind) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, i0)) + !AI_SaveImmuneSpellTarget(SAVING_THROW_WILL, 0)) { // Daze. Level 0 (Mage/Bard) If <= 5 Hit dice, target is dazed on a failed fortitude save. - if(AI_ActionCastSpellRandom(SPELL_DAZE, SpellHostRanged, i50, GlobalSpellTarget, i10, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_DAZE, 50, GlobalSpellTarget, 10, FALSE)) return TRUE; } - if(RangeMediumValid) + if(bRangeMediumValid) { // Minor damage. Moderate range. 60% chance of casting. - if(AI_ActionCastSpellRandom(SPELL_RAY_OF_FROST, SpellHostRanged, i50, GlobalSpellTarget, i10, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_RAY_OF_FROST, 50, GlobalSpellTarget, 10, FALSE)) return TRUE; } - if(RangeLongValid) + if(bRangeLongValid) { // Long range, for Acid Splash and Electric Jolt. Random cast one of them - if(AI_ActionCastSpellRandom(SPELL_ELECTRIC_JOLT, SpellHostRanged, i40, GlobalSpellTarget, i10, FALSE, ItemHostRanged)) return TRUE; - if(AI_ActionCastSpellRandom(SPELL_ACID_SPLASH, SpellHostRanged, i40, GlobalSpellTarget, i10, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_ELECTRIC_JOLT, 40, GlobalSpellTarget, 10, FALSE)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_ACID_SPLASH, 40, GlobalSpellTarget, 10, FALSE)) return TRUE; } // Flare is OK - low 10% cast, but will backup cast at end. - if(RangeMediumValid && !GetHasSpellEffect(SPELL_FLARE, GlobalSpellTarget) && - !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, i0)) + if(bRangeMediumValid && !GetHasSpellEffect(SPELL_FLARE, GlobalSpellTarget) && + !AI_SaveImmuneSpellTarget(SAVING_THROW_FORT, 0)) { // Flare. Level 0 (Bard/Mage) Target gets -1 to attack rolls if they fail a fortitude save - if(AI_ActionCastSpellRandom(SPELL_FLARE, SpellHostRanged, i0, GlobalSpellTarget, i10, FALSE, ItemHostRanged)) return TRUE; + if(AI_ActionCastSpellRandom(SPELL_FLARE, 0, GlobalSpellTarget, 10, FALSE)) return TRUE; } // Backup casting if(AI_ActionCastBackupRandomSpell()) return TRUE; } // Need decent % HP and no enemies in 4 Meters to cast these - if(IsFirstRunThrough && GlobalOurPercentHP >= i60 && !GlobalEnemiesIn4Meters) + if(bFirstRunThrough && GlobalOurPercentHP >= 60 && !GlobalEnemiesIn4Meters) { if(!GetHasSpellEffect(SPELL_VIRTUE)) { // Virtue. Level 0 (Druid/Cleric/Paladin) +1 HP, 1 turn/caster level. - if(AI_ActionCastSpell(SPELL_VIRTUE, SpellEnhSinTar, OBJECT_SELF, i10, FALSE, ItemEnhSinTar)) return TRUE; + if(AI_ActionCastSpell(SPELL_VIRTUE, OBJECT_SELF, 10, FALSE)) return TRUE; } if(!GetHasSpellEffect(SPELL_RESISTANCE)) { // Resistance. Level 0 (Mage/Cleric/Bard/Druid) 1 (Paladin) +1 to all saves for 2 turns - if(AI_ActionCastSpell(SPELL_RESISTANCE, SpellEnhSinTar, OBJECT_SELF, i10, FALSE, ItemEnhSinTar)) return TRUE; + if(AI_ActionCastSpell(SPELL_RESISTANCE, OBJECT_SELF, 10, FALSE)) return TRUE; } // Light if(!GetHasSpellEffect(SPELL_LIGHT)) { // Light. Level 0 (Mage/Cleric/Druid/Bard) 20M of light around the target. - if(AI_ActionCastSpell(SPELL_LIGHT, SpellOtherSpell, OBJECT_SELF, i10)) return TRUE; + if(AI_ActionCastSpell(SPELL_LIGHT, OBJECT_SELF, 10)) return TRUE; } } // Minor wounds - damage at a touch attack. // HARDLY worth it, but use it anyway...if we pass the BAB check that is :-) - if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < i1 && RangeTouchValid && + if(GlobalSeenSpell && GlobalNormalSpellsNoEffectLevel < 1 && bRangeTouchValid && !AI_GetSpellTargetImmunity(GlobalImmunityNecromancy) && !AI_GetSpellTargetImmunity(GlobalImmunityNegativeEnergy)) { // Inflict Minor Wounds. Level 0 (Cleric) Touch attack, hit means 1 negative damage. - if(AI_ActionCastSpontaeousSpell(SPELL_INFLICT_MINOR_WOUNDS, SpellOtherSpell, GlobalSpellTarget)) return TRUE; + if(AI_ActionCastSpontaeousSpell(SPELL_INFLICT_MINOR_WOUNDS, GlobalSpellTarget)) return TRUE; } - // This is when it may loop back, after moving forward a bit - // Ranges: 20, 8, and 2.25. Long range spells are always cast. - if(SRA) - { - // We have integers, set to TRUE or FALSE. - // - 2 sets, one that was passed from last time, one which we - // just used. - - // Just used = RangeLongValid. TRUE = CASTED - // New ones = InputRangeLongValid. TRUE = DO NOT CAST. - - // So, we toggle the RangeLongValid's, and if they are TRUE, we - // put that into the next loop. If it was FALSE, we check - // the InputRangeLongValid to see if we checked it before. - - // If false, set the value to the Input value. - if(RangeLongValid == FALSE) - { - RangeLongValid = InputRangeLongValid; - } - if(RangeMediumValid == FALSE) - { - RangeMediumValid = InputRangeMediumValid; - } - if(RangeShortValid == FALSE) - { - RangeShortValid = InputRangeShortValid; - } - if(RangeTouchValid == FALSE) - { - RangeTouchValid = InputRangeTouchValid; - } - // Do a new loop. Took out the ones we have already done :-) - // 34: "[DCR: All Spells] Ranged Spells. Should use closer spells/move nearer" - DebugActionSpeakByInt(34); - // We go through, reducing amount by 1. - if(AI_AttemptAllSpells(iLowestSpellLevel, iBABCheckHighestLevel, iLastCheckedRange + i1, RangeLongValid, RangeMediumValid, RangeShortValid, RangeTouchValid)) return TRUE; - } // Return false. No spell cast. return FALSE; } @@ -11163,7 +11065,7 @@ S [Inflict Minor Wounds] 1 Negative damage, on a touch attack. Heals undead. 1. They don't have the spell's effects (unless iDamaging is TRUE) 2. We have it! - After it is used, iWingCounter is set, debug message, and re-set counter to 0. + After it is used, nWingCounter is set, debug message, and re-set counter to 0. //:://///////////////////////////////////////////// //:: Created By: Jasperre //:://///////////////////////////////////////////*/ @@ -11178,7 +11080,7 @@ int AI_GetIsDragon() return TRUE; } // Appearance type (includes if we polymorph into one!) - switch(GlobalOurAppearance) + switch(GetAppearanceType(OBJECT_SELF)) { case APPEARANCE_TYPE_DRAGON_BLACK: case APPEARANCE_TYPE_DRAGON_BLUE: @@ -11205,9 +11107,9 @@ int AI_GetIsDragon() case APPEARANCE_TYPE_WYRMLING_SILVER: case APPEARANCE_TYPE_WYRMLING_WHITE: // Hordes ones - case 425: // Dragon_Pris - case 418: // Dragon_Shadow - case 405: // Dracolich + case APPEARANCE_TYPE_DRAGON_PRIS: // Dragon_Pris 425 + case APPEARANCE_TYPE_DRAGON_SHADOW: // Dragon_Shadow 418 + case APPEARANCE_TYPE_DRACOLICH: // Dracolich 405 return TRUE; break; } @@ -11216,11 +11118,11 @@ int AI_GetIsDragon() // Uses tBreath if they are not immune // - TRUE if used. -int AI_ActionUseBreath(object oTarget, talent tBreath, int iSpellID) +int AI_ActionUseBreath(object oTarget, talent tBreath, int nSpellID) { int iImmune = FALSE;// If TRUE, don't use it it // Go through them... - switch(iSpellID) + switch(nSpellID) { case SPELLABILITY_DRAGON_BREATH_FEAR: iImmune = GetIsImmune(oTarget, IMMUNITY_TYPE_FEAR); break; case SPELLABILITY_DRAGON_BREATH_PARALYZE: iImmune = GetIsImmune(oTarget, IMMUNITY_TYPE_PARALYSIS); break; @@ -11231,68 +11133,66 @@ int AI_ActionUseBreath(object oTarget, talent tBreath, int iSpellID) // Use it! if(!iImmune) { - // 35: "[DCR:Dragon] Breath weapon & attacking [Breath ID] " + IntToString(iSpellID) + " [Target] " + GetName(oTarget) - DebugActionSpeakByInt(35, oTarget, iSpellID); + // 35: "[DCR:Dragon] Breath weapon & attacking [Breath ID] " + IntToString(nSpellID) + " [Target] " + GetName(oTarget) + DebugActionSpeakByInt(35, oTarget, nSpellID); ActionUseTalentAtLocation(tBreath, GetLocation(oTarget)); ActionAttack(oTarget); return TRUE; } return FALSE; } -int AI_ActionDragonBreath(object oTarget, int iWingCounter) +int AI_ActionDragonBreath(object oTarget, int nWingCounter) { // Get a random breath... talent tBreath = GetCreatureTalentRandom(TALENT_CATEGORY_DRAGONS_BREATH); if(GetIsTalentValid(tBreath)) { - int iTypeRandom, iTypeBest; + int nTypeRandom, nTypeBest; // Check if it affects them - iTypeRandom = GetIdFromTalent(tBreath); - if(!GetHasSpellEffect(iTypeRandom, oTarget)) + nTypeRandom = GetIdFromTalent(tBreath); + if(!GetHasSpellEffect(nTypeRandom, oTarget)) { - if(AI_ActionUseBreath(oTarget, tBreath, iTypeRandom)) return TRUE; + if(AI_ActionUseBreath(oTarget, tBreath, nTypeRandom)) return TRUE; } else { // Try again...best this time - tBreath = GetCreatureTalentBest(TALENT_CATEGORY_DRAGONS_BREATH, i20); + tBreath = GetCreatureTalentBest(TALENT_CATEGORY_DRAGONS_BREATH, 20); if(GetIsTalentValid(tBreath)) { - iTypeBest = GetIdFromTalent(tBreath); - if(iTypeBest != iTypeRandom && !GetHasSpellEffect(iTypeBest, oTarget)) + nTypeBest = GetIdFromTalent(tBreath); + if(nTypeBest != nTypeRandom && !GetHasSpellEffect(nTypeBest, oTarget)) { - if(AI_ActionUseBreath(oTarget, tBreath, iTypeBest)) return TRUE; + if(AI_ActionUseBreath(oTarget, tBreath, nTypeBest)) return TRUE; } } } } return FALSE; } +// This tests breath attacks or the use of the Wing Buffet, randomised each round +// and not used constantly. +// * oTarget - target to breath on (ouch, bad breath!) int AI_DragonBreathOrWing(object oTarget) { - // We may re-set SpellHostBreath if invalid, and we are polymorphed - if(SpellHostBreath == FALSE && AI_GetAIHaveEffect(GlobalEffectPolymorph)) - { - SpellHostBreath = GetIsTalentValid(GetCreatureTalentBest(TALENT_CATEGORY_DRAGONS_BREATH, MAXCR)); - } - + int bBreath = GetIsTalentValid(GetCreatureTalentBest(TALENT_CATEGORY_DRAGONS_BREATH, MAXCR)); // Breath attack, or wing buffet. Which one?! // Check if we can do either...and that we are huge - IE not persuado dragon! - if(SpellHostBreath || GlobalOurSize >= CREATURE_SIZE_HUGE) + if(bBreath || GetCreatureSize(OBJECT_SELF) >= CREATURE_SIZE_HUGE) { // Adds one to all things, by default, every call. This will randomise when to use things. int nBreath = GetAIInteger(AI_DRAGONS_BREATH); int nWing = GetAIInteger(AI_WING_BUFFET); - int iAboveXBreath = GetBoundriedAIInteger(AI_DRAGON_FREQUENCY_OF_BUFFET, i3); - int iAboveXWing = GetBoundriedAIInteger(AI_DRAGON_FREQUENCY_OF_BREATH, i3); + int nAboveXBreath = GetBoundriedAIInteger(AI_DRAGON_FREQUENCY_OF_BUFFET, 3); + int nAboveXWing = GetBoundriedAIInteger(AI_DRAGON_FREQUENCY_OF_BREATH, 3); // There is a small chance of actuall reducing it for one after it, or // adding another! - if(d20() == i1 && (nWing > FALSE || nBreath > FALSE))// 5% chance of x2 the number! + if(d20() == 1 && (nWing > FALSE || nBreath > FALSE))// 5% chance of x2 the number! { - nWing *= i2; - nBreath *= i2; + nWing *= 2; + nBreath *= 2; } - else if(d20() == i1)// 5% of reducing each by 1. + else if(d20() == 1)// 5% of reducing each by 1. { nWing--; nBreath--; @@ -11307,41 +11207,42 @@ int AI_DragonBreathOrWing(object oTarget) SetAIInteger(AI_WING_BUFFET, nWing); SetAIInteger(AI_DRAGONS_BREATH, nBreath); // Check 1. If breath is over 2 of wing, we may use it. - if(!GetSpawnInCondition(AI_FLAG_COMBAT_NO_WING_BUFFET, AI_COMBAT_MASTER) && SpellHostBreath && - nBreath >= iAboveXBreath && nBreath >= (nWing + i2)) + if(!GetSpawnInCondition(AI_FLAG_COMBAT_NO_WING_BUFFET, AI_COMBAT_MASTER) && + nBreath >= nAboveXBreath && nBreath >= (nWing + 2) && bBreath) { // We don't attack, with breath, our own dragons (IE as 3E rules, and // the factmost dragons do have that immunity to that damage in place) - if(GetAppearanceType(oTarget) != GlobalOurAppearance) + if(GetAppearanceType(oTarget) != GetAppearanceType(OBJECT_SELF)) { if(AI_ActionDragonBreath(oTarget, nWing)) { - SetAIInteger(AI_DRAGONS_BREATH, i0); + SetAIInteger(AI_DRAGONS_BREATH, 0); return TRUE; } } } // Else wing must be higher, or no breath! // So we use wing buffet, re-set that, then try breath to end... - if(nWing >= iAboveXWing && GlobalOurSize >= CREATURE_SIZE_HUGE && + if(nWing >= nAboveXWing && + GetCreatureSize(OBJECT_SELF) >= CREATURE_SIZE_HUGE && GetCreatureSize(oTarget) < CREATURE_SIZE_HUGE) { // 36: "[DCR:Dragon] Wing Buffet [Target] " + GetName(oTarget) DebugActionSpeakByInt(36, oTarget); // Reset wing buffet counter - SetAIInteger(AI_WING_BUFFET, i0); + SetAIInteger(AI_WING_BUFFET, 0); SetAIInteger(AI_DRAGONS_BREATH, nBreath); // - Not action do command, just Execute Script ExecuteScript(FILE_DRAGON_WING_BUFFET, OBJECT_SELF); return TRUE; } // Breath final... - if(SpellHostBreath && nBreath >= iAboveXBreath) + if(bBreath && nBreath >= nAboveXBreath) { // Breaths. if(AI_ActionDragonBreath(oTarget, nWing)) { - SetAIInteger(AI_DRAGONS_BREATH, i0); + SetAIInteger(AI_DRAGONS_BREATH, 0); return TRUE; } } @@ -11364,6 +11265,8 @@ int AI_AttemptDragonCombat() if(AI_AttemptAllSpells()) return TRUE; } + // Dragons can be tiny winey, and so we might attempt more spells in 1.4. + // Now, we use DRAGONS BREATH! MUHAHAHAHAH! // OR wing buffet! Yeehaw! // - This is done on a breath by breath basis, with GetAppearance checking! @@ -11372,7 +11275,7 @@ int AI_AttemptDragonCombat() // Chance each round to use best spells possible. // We, always, love level 9 spells! just great, especially if the dragon has them! - if(AI_AttemptAllSpells(i9)) return TRUE; + if(AI_AttemptAllSpells(9)) return TRUE; // We may attack our GlobalMeleeTarget if they are very weak in the AC // department! @@ -11380,37 +11283,53 @@ int AI_AttemptDragonCombat() // - They have no DR protections // - They have under 50 current hit points // - They are in HTH combat range. - if(GlobalOurBaseAttackBonus - i5 >= GlobalMeleeTargetAC && - !AI_GetAIHaveSpellsEffect(GlobalHasStoneSkinProtections, GlobalMeleeTarget) && - !AI_GetAIHaveSpellsEffect(GlobalHasVisageProtections, GlobalMeleeTarget) && - GetCurrentHitPoints(GlobalMeleeTarget) < i50 && GlobalRangeToMeleeTarget < f4) + if(GlobalOurBaseAttackBonus - 5 >= GlobalMeleeTargetAC && + !GetHasSpellEffect(AI_SPELL_EPIC_WARDING, GlobalMeleeTarget) && + !GetHasSpellEffect(SPELL_STONESKIN, GlobalMeleeTarget) && + !GetHasSpellEffect(SPELL_GREATER_STONESKIN, GlobalMeleeTarget) && + !GetHasSpellEffect(SPELL_PREMONITION, GlobalMeleeTarget) && + !GetHasSpellEffect(SPELL_SHADES_STONESKIN, GlobalMeleeTarget) && + GetCurrentHitPoints(GlobalMeleeTarget) < 50 && GlobalRangeToMeleeTarget < 4.0) { // We then attack with feats, or whatever :-) // - This includes flying AI_AttemptMeleeAttackWrapper(); return TRUE; } - // We will use more spells if there are more enemies - as AOE spells will - // be *maybe* better to use. - int iSpellLowestMinus; - if(GlobalMeleeAttackers > i4 || GlobalTotalSeenHeardEnemies > i6) + + // We will, if a low level dragon (awwwww! cute!) will cast more spells + // then normal. We have already used our breath weapon, but lower level + // dragons have more spells (or may be half-dragons). + if(GlobalOurHitDice <= 8 || (GlobalOurHitDice <= 14 && d100() <= 40)) { - // -6 - iSpellLowestMinus = i6; + // Attempt all spells. + // * Still uses nBABCheckHighestLevel, to not cast the lowest if we have + // a very high BAB. + if(AI_AttemptAllSpells()) return TRUE; } else { - // -2d4 - iSpellLowestMinus = d4(i2); + // We will use more spells if there are more enemies - as AOE spells will + // be *maybe* better to use. + int nSpellLowestMinus; + if(GlobalMeleeAttackers >= 4 || GlobalTotalSeenHeardEnemies >= 6) + { + // -6 + nSpellLowestMinus = 6; + } + else + { + // -2d4 + nSpellLowestMinus = d4(2); + } + // We randomly choose what to use... + if(AI_AttemptAllSpells(9 - nSpellLowestMinus, 0 + Random(6))) + { + // We also ActionAttack the enemy, as to move closer :-) + ActionAttack(GlobalMeleeTarget); + return TRUE; + } } - // We randomly choose what to use... - if(AI_AttemptAllSpells(i9 - iSpellLowestMinus, i0 + Random(i6))) - { - // We also ActionAttack the enemy, as to move closer :-) - ActionAttack(GlobalMeleeTarget); - return TRUE; - } - // We then attack with feats, or whatever :-) // - This includes flying return AI_AttemptMeleeAttackWrapper(); @@ -11418,40 +11337,94 @@ int AI_AttemptDragonCombat() // Beholder teleport attempt. Flees from combat. int AI_ActionBeholderTeleport() { + // By default, we use Bioware's Beholder escape points, but then we check + // for allies to flee too. + // 1.4 adds this. Only FLEES however! It norally is never quicker to go + // nearer... + if(GetLocalInt(OBJECT_SELF,"X2_BEHOLDER_AI_NOJUMP")) + { + return TRUE; + } + + // Get nearest exit point to us + object oExit = GetNearestObjectByTag("X2_WP_BEHOLDER_TUNNEL"); + + if(GetIsObjectValid(oExit)) + { + float fDist = GetDistanceBetween(oExit, GlobalMeleeTarget); + int bJump; + + if((fDist >= 10.0f) && (fDist <= 40.0f)) + { + bJump = TRUE; + } + + if(!bJump) + { + oExit = GetNearestObjectByTag("X2_WP_BEHOLDER_TUNNEL", OBJECT_SELF, 2); + } + if(GetIsObjectValid(oExit)) + { + fDist = GetDistanceBetween(oExit, GlobalMeleeTarget); + + if((fDist >= 8.0f) && (fDist <= 50.0f)) + { + bJump = TRUE; + } + } + + if(bJump) + { + int nAni = GetLocalInt(oExit, "X2_L_BEH_USE_ANI"); + if (nAni == 0) + { + nAni = 1;// Fly "up". + } + effect eAppear = EffectDisappearAppear(GetLocation(oExit), nAni) ; + eAppear = SupernaturalEffect(eAppear); + object oSelf = OBJECT_SELF; + ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eAppear, oSelf, 4.0f); + // make the beholder enter combat again + DelayCommand(4.1, ActionCastSpellAtObject(AI_SPELLABILITY_BEHOLDER_MAGIC_CONE, GlobalSpellTarget, METAMAGIC_ANY, TRUE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE)); + return TRUE; + } + } + // End Bioware + // Go from futhest to nearest seen allies - int iCnt = GetLocalInt(OBJECT_SELF, MAXINT_ + ARRAY_ALLIES_RANGE_SEEN); - if(iCnt <= FALSE) return FALSE; - int iBreak = FALSE; - object oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, i1, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD, CREATURE_TYPE_IS_ALIVE, TRUE); - if(!GetIsObjectValid(oEnemy) || GetDistanceToObject(oEnemy) > f5) return FALSE; + int nCnt = GetLocalInt(OBJECT_SELF, MAXINT_ + ARRAY_ALLIES_RANGE_SEEN); + if(nCnt <= FALSE) return FALSE; + int bBreak = FALSE; + object oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD, CREATURE_TYPE_IS_ALIVE, TRUE); + if(!GetIsObjectValid(oEnemy) || GetDistanceToObject(oEnemy) > 5.0) return FALSE; // Loop futhest to nearest - object oAlly = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN + IntToString(iCnt)); - while(GetIsObjectValid(oAlly) && iBreak != TRUE) + object oAlly = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN + IntToString(nCnt)); + while(GetIsObjectValid(oAlly) && bBreak != TRUE) { // Check nearest enemy to the ally. - oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oAlly, i1, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD, CREATURE_TYPE_IS_ALIVE, TRUE); - if(GetDistanceToObject(oEnemy) > f5) + oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oAlly, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD, CREATURE_TYPE_IS_ALIVE, TRUE); + if(GetDistanceToObject(oEnemy) > 5.0) { - iBreak = TRUE; + bBreak = TRUE; } else { // Next futhest. - iCnt--; - oAlly = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN + IntToString(iCnt)); + nCnt--; + oAlly = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN + IntToString(nCnt)); } } // If true, we run to the ally - if(iBreak) + if(bBreak) { // 37: "[DCR] Beholder Teleport" DebugActionSpeakByInt(37); effect eBeholder = EffectDisappearAppear(GetLocation(oAlly)); - float fTime = f3 + (GetDistanceToObject(oAlly)/f10); + float fTime = 3.0 + (GetDistanceToObject(oAlly)/10.0); // Apply effect ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eBeholder, OBJECT_SELF, fTime); // Determine Combat Round - DelayCommand(fTime + f1, DetermineCombatRound(GlobalMeleeTarget)); + DelayCommand(fTime + 1.0, DetermineCombatRound(GlobalMeleeTarget)); } return FALSE; } @@ -11460,7 +11433,7 @@ int AI_ActionBeholderTeleport() int AI_AttemptBeholderCombat() { // We will randomly teleport away if low HP, then heal - if(GlobalOurPercentHP < GetBoundriedAIInteger(AI_HEALING_US_PERCENT, i50, i100, i1)) + if(GlobalOurPercentHP < GetBoundriedAIInteger(AI_HEALING_US_PERCENT, 50, 100, 1)) { // Randomly teleport directly to an ally with no one near to them. if(AI_ActionBeholderTeleport()) @@ -11477,7 +11450,7 @@ int AI_AttemptBeholderCombat() // We will attempt high-level spells first. // - This will also make them use protections of course // - Only level 9 and 8 spells. - if(AI_AttemptAllSpells(i8)) return TRUE; + if(AI_AttemptAllSpells(8)) return TRUE; // We attempt to fire beholder rays, or do antimagic cone. // 736 Beholder_Special_Spell_AI - Handles Beholder rays @@ -11489,8 +11462,16 @@ int AI_AttemptBeholderCombat() 9 seconds duration No save */ + // Cast the antimagic cone randomly, if the target is nearish. + if(d100() <= 60 && GlobalSpellTargetRange <= 15.0) + { + // 38: "[DCR] Beholder Rays" + DebugActionSpeakByInt(38); + ActionCastSpellAtLocation(AI_SPELLABILITY_BEHOLDER_MAGIC_CONE, GetLocation(GlobalSpellTarget), METAMAGIC_ANY, TRUE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE); + return TRUE; + } // 80% chance of rays if at range (must be seen!) - if(d100() <= i80 && GlobalSeenSpell) + else if(d100() <= 80 && GlobalSeenSpell) { // 38: "[DCR] Beholder Rays" DebugActionSpeakByInt(38); @@ -11503,9 +11484,9 @@ int AI_AttemptBeholderCombat() return TRUE; } // Else there is a 20% chance of melee attack if enemy is at low HP - else if(GetCurrentHitPoints(GlobalMeleeTarget) <= i30 && - GlobalMeleeTargetAC <= i25 && - GlobalRangeToMeleeTarget < f5 && d100() <= i20) + else if(GetCurrentHitPoints(GlobalMeleeTarget) <= 30 && + GlobalMeleeTargetAC <= 25 && + GlobalRangeToMeleeTarget < 5.0 && d100() <= 40) { if(AI_AttemptMeleeAttackWrapper()) { @@ -11519,7 +11500,7 @@ int AI_AttemptBeholderCombat() return TRUE; } } - // Then rays finally + // Then rays finally, as a default thing. else { // 38: "[DCR] Beholder Rays" @@ -11534,15 +11515,12 @@ int AI_AttemptBeholderCombat() // Bioware's implimenation of the Mind Suck. void MindFlayerSuck(object oTarget) { - if(GetDistanceBetween(OBJECT_SELF, oTarget) < 1.5) - { - ActionMoveAwayFromObject(oTarget, FALSE, 1.5); - } - ActionMoveToObject(oTarget, FALSE, 1.5); + // Move closer! + ActionMoveToObject(oTarget, FALSE, 1.0); ActionDoCommand(SetFacingPoint(GetPosition(oTarget))); ActionWait(0.5); // normal brain suck - ActionCastSpellAtObject(AI_SPELLABILITY_SUCKBRAIN, oTarget,METAMAGIC_ANY,TRUE,0,PROJECTILE_PATH_TYPE_DEFAULT); + ActionCastSpellAtObject(AI_SPELLABILITY_SUCKBRAIN, oTarget, METAMAGIC_ANY, TRUE); } // Illithid Use special attacks. // This is set on spawn, or by the user on spawn. @@ -11556,21 +11534,30 @@ int AI_AttemptMindflayerCombat() // Check polymorph if(AI_GetAIHaveEffect(GlobalEffectPolymorph, GlobalMeleeTarget)) return FALSE; - // Stunned, held, uncommandable, it is 100% - if((AI_GetAIHaveEffect(GlobalEffectParalyze, GlobalMeleeTarget) || - AI_GetAIHaveEffect(GlobalEffectUncommandable, GlobalMeleeTarget)) || + // Stunned, held, sleep, etc. uncommandable, it is 100% + if(AI_GetAIHaveEffect(GlobalEffectUncommandable, GlobalMeleeTarget) || // 30% with daze only. - (AI_GetAIHaveEffect(GlobalEffectUncommandable, GlobalMeleeTarget) && d100() <= i30)) + (AI_GetAIHaveEffect(GlobalEffectUncommandable, GlobalMeleeTarget) && d100() <= 30)) { // Bioware function. MindFlayerSuck(GlobalMeleeTarget); return TRUE; } // 70% chance of mind blast - else if(GetDistanceToObject(GlobalMeleeTarget) < f5 && d100() <= i70) + else if(GetDistanceToObject(GlobalMeleeTarget) < 5.0 && d100() <= 70) { // Special mind blast - ActionCastSpellAtObject(551, OBJECT_SELF,METAMAGIC_ANY,TRUE,0,PROJECTILE_PATH_TYPE_DEFAULT); + ActionCastSpellAtObject(SPELLABILITY_MINDBLAST, OBJECT_SELF, METAMAGIC_ANY, TRUE); + return TRUE; + } + // 40% chance of pyionic charm monster + else if(GetDistanceToObject(GlobalMeleeTarget) < 8.0 && d100() <= 40 && + !GetHasSpellEffect(SPELLABILITY_CHARMMONSTER, GlobalMeleeTarget) && + GetHasSpell(SPELLABILITY_CHARMMONSTER)) + { + // Special mind blast + ActionCastSpellAtObject(SPELLABILITY_CHARMMONSTER, GlobalMeleeTarget, METAMAGIC_ANY, TRUE); + return TRUE; } // False means no special mind flayer attacks. return FALSE; @@ -11591,8 +11578,6 @@ void AI_SetDispelableEnchantments() { // We CANNOT dispel any of the epic spells, so we DO NOT check for them // here!!! - // Note that we do not dispel GlobalDispelTarget if they are stopped - // somehow. // Summons dispelling object oMaster = GetMaster(GlobalDispelTarget); @@ -11606,13 +11591,14 @@ void AI_SetDispelableEnchantments() { // Dispel the caster GlobalDispelTarget = oMaster; - GlobalDispelTargetHighestDispel = i5; + GlobalDispelTargetHighestDispel = 5; return; } else { // Else, not seen or heard, so we try and dispel just the sword - GlobalDispelTargetHighestDispel = i5; + // * Its an evil sword and must die! + GlobalDispelTargetHighestDispel = 5; return; } } @@ -11621,65 +11607,31 @@ void AI_SetDispelableEnchantments() { // Dispel the caster GlobalDispelTarget = oMaster; - GlobalDispelTargetHighestDispel = i5; + GlobalDispelTargetHighestDispel = 5; return; } - // Else - normal dispel behaviour. I don't think targeting dispels at + // Else - normal dispel behavour. I don't think targeting dispels at // a summon will kill them! } - // If not, we see if it is appropriate to even try and dispel them. - // - Stun, sleep, fear - if(AI_GetAIHaveEffect(GlobalEffectUncommandable, GlobalDispelTarget) || - // - Petrify - AI_GetAIHaveEffect(GlobalEffectPetrify, GlobalDispelTarget) || - // - Paralyze - AI_GetAIHaveEffect(GlobalEffectParalyze, GlobalDispelTarget) || - // - Plot flag - GetPlotFlag(GlobalDispelTarget)) - { - if(GlobalDispelTarget == GlobalSpellTarget) - { - return; - } - else - { - // We can check GlobalSpellTarget if this target is not a good one - // to target. - GlobalDispelTarget = GlobalSpellTarget; - // Invalid - if(!GetIsObjectValid(GlobalDispelTarget) || - // - Stun, sleep, fear - AI_GetAIHaveEffect(GlobalEffectUncommandable, GlobalDispelTarget) || - // - Petrify - AI_GetAIHaveEffect(GlobalEffectPetrify, GlobalDispelTarget) || - // - Paralyze - AI_GetAIHaveEffect(GlobalEffectParalyze, GlobalDispelTarget) || - // - Plot flag - GetPlotFlag(GlobalDispelTarget)) - { - return; - } - } - } // We check the spell it has been cast from :-) - int iSpellID, iSpellCounter; + int nSpellID, nSpellCounter; // We check all of thier effects. effect eCheck = GetFirstEffect(GlobalDispelTarget); // Loop around valid effects. while(GetIsEffectValid(eCheck) && // Break loop if we are already at 5 - GlobalDispelTargetHighestDispel < i5 && - GlobalDispelTargetHighestBreach < i5) + GlobalDispelTargetHighestDispel < 5 && + GlobalDispelTargetHighestBreach < 5) { - iSpellID = GetEffectSpellId(eCheck); + nSpellID = GetEffectSpellId(eCheck); // Make sure that it is equal, or over, 0 (IE acid fog) // - Must be magical, else DispelMagic will not work. - if(iSpellID >= i0 && GetEffectSubType(eCheck) == SUBTYPE_MAGICAL) + if(nSpellID >= 0 && GetEffectSubType(eCheck) == SUBTYPE_MAGICAL) { // We then switch the spells (I tihnk it is easier to debug :-) ) // and set what level of benifical enchantment it is :-) - switch(iSpellID) + switch(nSpellID) { // * 5 - Dispeled before hostile spells are cast at target // Level 5 Breach Spells - should be Dispeled before attacking. @@ -11689,9 +11641,9 @@ void AI_SetDispelableEnchantments() case SPELL_SHADOW_SHIELD: // Immunity to negative energy, death spells + Necromancy! - so Dispel case SPELL_ENERGY_BUFFER: // 40/- Elemental reistance can stop some level 9 spells! :-) { - if(GlobalDispelTargetHighestDispel < i5) GlobalDispelTargetHighestDispel = i5; - if(GlobalDispelTargetHighestBreach < i5) GlobalDispelTargetHighestBreach = i5; - iSpellCounter++; + if(GlobalDispelTargetHighestDispel < 5) GlobalDispelTargetHighestDispel = 5; + if(GlobalDispelTargetHighestBreach < 5) GlobalDispelTargetHighestBreach = 5; + nSpellCounter++; } break; // Level 5 other spells. @@ -11705,17 +11657,17 @@ void AI_SetDispelableEnchantments() case SPELL_SHAPECHANGE:// VERY Powerful polymorphing. case SPELL_PROTECTION_FROM_SPELLS:// +8 on all saves { - if(GlobalDispelTargetHighestDispel < i5) GlobalDispelTargetHighestDispel = i5; - if(GlobalDispelTargetHighestBreach < i5) GlobalDispelTargetHighestBreach = i5; - iSpellCounter++; + if(GlobalDispelTargetHighestDispel < 5) GlobalDispelTargetHighestDispel = 5; + if(GlobalDispelTargetHighestBreach < 5) GlobalDispelTargetHighestBreach = 5; + nSpellCounter++; } break; // * 4 - Dispeled just before level 7 or so spells. case SPELL_PREMONITION: // Damage reduction 30/+5. Do this for fighters. { - if(GlobalDispelTargetHighestDispel < i4) GlobalDispelTargetHighestDispel = i4; - if(GlobalDispelTargetHighestBreach < i4) GlobalDispelTargetHighestBreach = i4; - iSpellCounter++; + if(GlobalDispelTargetHighestDispel < 4) GlobalDispelTargetHighestDispel = 4; + if(GlobalDispelTargetHighestBreach < 4) GlobalDispelTargetHighestBreach = 4; + nSpellCounter++; } break; // Most other decent protection spells, especially ones which will @@ -11732,8 +11684,8 @@ void AI_SetDispelableEnchantments() case SPELL_BLACK_BLADE_OF_DISASTER: // Black blade case SPELL_SUMMON_CREATURE_VIII:// 8 { - if(GlobalDispelTargetHighestDispel < i4) GlobalDispelTargetHighestDispel = i4; - iSpellCounter++; + if(GlobalDispelTargetHighestDispel < 4) GlobalDispelTargetHighestDispel = 4; + nSpellCounter++; } break; // * 3 - Dispeled just before level 4 or so spells @@ -11741,9 +11693,9 @@ void AI_SetDispelableEnchantments() case SPELL_GREATER_STONESKIN: // 20/+5 DR. Help fighters half-way though spells. case SPELL_RESIST_ELEMENTS: // 20/- Protection { - if(GlobalDispelTargetHighestDispel < i3) GlobalDispelTargetHighestDispel = i3; - if(GlobalDispelTargetHighestBreach < i3) GlobalDispelTargetHighestBreach = i3; - iSpellCounter++; + if(GlobalDispelTargetHighestDispel < 3) GlobalDispelTargetHighestDispel = 3; + if(GlobalDispelTargetHighestBreach < 3) GlobalDispelTargetHighestBreach = 3; + nSpellCounter++; } break; // Increases in abilites, and some which stop level 4, or nearby, spells. @@ -11758,8 +11710,8 @@ void AI_SetDispelableEnchantments() case SPELL_SUMMON_CREATURE_VI: // 6 case SPELL_SUMMON_CREATURE_V: // 5 { - if(GlobalDispelTargetHighestDispel < i3) GlobalDispelTargetHighestDispel = i3; - iSpellCounter++; + if(GlobalDispelTargetHighestDispel < 3) GlobalDispelTargetHighestDispel = 3; + nSpellCounter++; } break; // * 2 - Dispeled just before level 2 or so spells. @@ -11768,10 +11720,11 @@ void AI_SetDispelableEnchantments() case SPELL_ENDURE_ELEMENTS: // 10/- Reduction. SPELL_GHOSTLY_VISAGE case SPELL_GHOSTLY_VISAGE: // 0-1 level spell immunity, and 10% consealment case SPELL_STONESKIN: // 10/+5 DR. Help fighters just before low-end spells. + case SPELL_SHADES_STONESKIN:// Shades version of above. { - if(GlobalDispelTargetHighestDispel < i2) GlobalDispelTargetHighestDispel = i2; - if(GlobalDispelTargetHighestBreach < i2) GlobalDispelTargetHighestBreach = i2; - iSpellCounter++; + if(GlobalDispelTargetHighestDispel < 2) GlobalDispelTargetHighestDispel = 2; + if(GlobalDispelTargetHighestBreach < 2) GlobalDispelTargetHighestBreach = 2; + nSpellCounter++; } break; // Things that stop level 2 or 1 spells, and low-end ones which @@ -11791,8 +11744,8 @@ void AI_SetDispelableEnchantments() case SPELL_SUMMON_CREATURE_IV: // 4 case SPELL_SUMMON_CREATURE_III: // 3 { - if(GlobalDispelTargetHighestDispel < i2) GlobalDispelTargetHighestDispel = i2; - iSpellCounter++; + if(GlobalDispelTargetHighestDispel < 2) GlobalDispelTargetHighestDispel = 2; + nSpellCounter++; } break; // * 1 - Lowest prioritory - Dispeled at the end. @@ -11800,9 +11753,9 @@ void AI_SetDispelableEnchantments() // Before we attack, we Dispel them (and therefore help allies!) case SPELL_MAGE_ARMOR: // +AC { - if(GlobalDispelTargetHighestDispel < i1) GlobalDispelTargetHighestDispel = i1; - if(GlobalDispelTargetHighestBreach < i1) GlobalDispelTargetHighestBreach = i1; - iSpellCounter++; + if(GlobalDispelTargetHighestDispel < 1) GlobalDispelTargetHighestDispel = 1; + if(GlobalDispelTargetHighestBreach < 1) GlobalDispelTargetHighestBreach = 1; + nSpellCounter++; } // Non-breach case SPELL_AID: // +Some HP and attack @@ -11826,24 +11779,28 @@ void AI_SetDispelableEnchantments() case SPELL_SUMMON_CREATURE_II: // 2 case SPELL_SUMMON_CREATURE_I: // 1 { - if(GlobalDispelTargetHighestDispel < i1) GlobalDispelTargetHighestDispel = i1; - iSpellCounter++; + if(GlobalDispelTargetHighestDispel < 1) GlobalDispelTargetHighestDispel = 1; + nSpellCounter++; } break; } } eCheck = GetNextEffect(GlobalDispelTarget); } + // If we cannot see GlobalDispelTarget, set GlobalDispelTargetHighestBreach to + // 0 anyway. Cannot cast Breach against something we cannot see! + if(!GetObjectSeen(GlobalDispelTarget)) GlobalDispelTargetHighestBreach = 0; + // We might dispel anything. if(!GetSpawnInCondition(AI_FLAG_COMBAT_DISPEL_IN_ORDER, AI_COMBAT_MASTER)) { - if(GlobalDispelTargetHighestBreach) GlobalDispelTargetHighestBreach = i5; - if(GlobalDispelTargetHighestDispel) GlobalDispelTargetHighestDispel = i5; + if(GlobalDispelTargetHighestBreach) GlobalDispelTargetHighestBreach = 5; + if(GlobalDispelTargetHighestDispel) GlobalDispelTargetHighestDispel = 5; } // Do we have a ton of spells? We add 1 to the prioritory for every 10 spells // applied. - if(iSpellCounter > i5) GlobalDispelTargetHighestDispel += iSpellCounter / i10; - if(GlobalDispelTargetHighestDispel > i5) GlobalDispelTargetHighestDispel = i5; + if(nSpellCounter > 5) GlobalDispelTargetHighestDispel += nSpellCounter / 10; + if(GlobalDispelTargetHighestDispel > 5) GlobalDispelTargetHighestDispel = 5; } // Just sorts out sOriginalArrayName to sNewArrayName based on range only. @@ -11858,10 +11815,10 @@ void AI_TargetingArrayDistanceStore(string sOriginalArrayName, string sNewArrayN } // Make sure sNewArrayName is cleared DeleteLocalInt(OBJECT_SELF, MAXINT_ + sNewArrayName); - int iCnt = i1; + int nCnt = 1; float fSetUpRange; // Now, we check for things like if to do melee or ranged, or whatever :-) - object oTarget = GetLocalObject(OBJECT_SELF, sOriginalArrayName + IntToString(iCnt)); + object oTarget = GetLocalObject(OBJECT_SELF, sOriginalArrayName + IntToString(nCnt)); while(GetIsObjectValid(oTarget)) { if(!bFilterPC || GetIsPC(oTarget)) @@ -11871,141 +11828,142 @@ void AI_TargetingArrayDistanceStore(string sOriginalArrayName, string sNewArrayN SetArrayFloatValue(sNewArrayName, oTarget, fSetUpRange); } // Next one - iCnt++; - oTarget = GetLocalObject(OBJECT_SELF, sOriginalArrayName + IntToString(iCnt)); + nCnt++; + oTarget = GetLocalObject(OBJECT_SELF, sOriginalArrayName + IntToString(nCnt)); } // If we have no valid targets, and PC's are on, we try again. - if(bFilterPC && !GetIsObjectValid(GetLocalObject(OBJECT_SELF, sNewArrayName + s1))) + if(bFilterPC && !GetIsObjectValid(GetLocalObject(OBJECT_SELF, sNewArrayName + "1"))) { // Re-run again. - iCnt = i1; - oTarget = GetLocalObject(OBJECT_SELF, sOriginalArrayName + IntToString(iCnt)); + nCnt = 1; + oTarget = GetLocalObject(OBJECT_SELF, sOriginalArrayName + IntToString(nCnt)); while(GetIsObjectValid(oTarget)) { fSetUpRange = GetDistanceToObject(oTarget); // We set it to sNewArrayName - highest to lowest. SetArrayFloatValue(sNewArrayName, oTarget, fSetUpRange); // Next one - iCnt++; - oTarget = GetLocalObject(OBJECT_SELF, sOriginalArrayName + IntToString(iCnt)); + nCnt++; + oTarget = GetLocalObject(OBJECT_SELF, sOriginalArrayName + IntToString(nCnt)); } } // delete old ones. int iCheck; - for(iCheck = i1; iCheck <= iCnt; iCheck++) + for(iCheck = 1; iCheck <= nCnt; iCheck++) { // Delete the old one - DeleteLocalObject(OBJECT_SELF, sOriginalArrayName + IntToString(iCnt)); + DeleteLocalObject(OBJECT_SELF, sOriginalArrayName + IntToString(nCnt)); } } -// Just sorts out sOriginalArrayName to sNewArrayName based on iType. -// iType 1 = AC, iType 2 = Total Saves, iType 3 = Phisical Protections, -// iType 4 = BAB, iType 5 = Hit Dice, iType 6 = Percent HP, iType 7 = Current HP, -// iType 8 = Maximum HP. 9 = Attacking us or not. -void AI_TargetingArrayIntegerStore(int iType, string sOriginalArrayName) +// Just sorts out sOriginalArrayName to sNewArrayName based on nType. +// nType 1 = AC, nType 2 = Total Saves, nType 3 = Phisical Protections, +// nType 4 = BAB, nType 5 = Hit Dice, nType 6 = Percent HP, nType 7 = Current HP, +// nType 8 = Maximum HP. 9 = Attacking us or not. +void AI_TargetingArrayIntegerStore(int nType, string sOriginalArrayName) { - int iCnt = i1; - int iValue; + int nCnt = 1; + int nValue; // Now, we check for things like if to do melee or ranged, or whatever :-) - object oTarget = GetLocalObject(OBJECT_SELF, sOriginalArrayName + IntToString(iCnt)); + object oTarget = GetLocalObject(OBJECT_SELF, sOriginalArrayName + IntToString(nCnt)); while(GetIsObjectValid(oTarget)) { - if(iType == i1) + if(nType == 1) { // AC - iValue = GetAC(oTarget); + nValue = GetAC(oTarget); } - else if(iType == i2) + else if(nType == 2) { // Total saving throws. - iValue = GetFortitudeSavingThrow(oTarget) + + nValue = GetFortitudeSavingThrow(oTarget) + GetReflexSavingThrow(oTarget) + GetReflexSavingThrow(oTarget); } - else if(iType == i3) + else if(nType == 3) { // Damage reduction // 30/+5 if(GetHasSpellEffect(SPELL_PREMONITION, oTarget)) { - iValue = i30; + nValue = 30; } // 20/+5, 20/+3 else if(GetHasSpellEffect(SPELL_GREATER_STONESKIN, oTarget) || GetHasSpellEffect(SPELL_ETHEREAL_VISAGE, oTarget)) { - iValue = i20; + nValue = 20; } // 10/+5 10/+3 else if(GetHasSpellEffect(SPELL_SHADOW_SHIELD, oTarget) || - GetHasSpellEffect(SPELL_STONESKIN, oTarget)) + GetHasSpellEffect(SPELL_STONESKIN, oTarget) || + GetHasSpellEffect(SPELL_SHADES_STONESKIN, oTarget)) { - iValue = i10; + nValue = 10; } // 5/+1 else if(GetHasSpellEffect(SPELL_GHOSTLY_VISAGE, oTarget)) { - iValue = i5; + nValue = 5; } else { - iValue = i0; + nValue = 0; } } - else if(iType == i4) + else if(nType == 4) { // BAB - iValue = GetBaseAttackBonus(oTarget); + nValue = GetBaseAttackBonus(oTarget); } - else if(iType == i5) + else if(nType == 5) { // Hit dice - iValue = GetHitDice(oTarget); + nValue = GetHitDice(oTarget); } - else if(iType == i6) + else if(nType == 6) { // %HP - iValue = AI_GetPercentOf(GetCurrentHitPoints(oTarget), GetMaxHitPoints(oTarget)); + nValue = AI_GetPercentOf(GetCurrentHitPoints(oTarget), GetMaxHitPoints(oTarget)); } - else if(iType == i7) + else if(nType == 7) { // Current - iValue = GetCurrentHitPoints(oTarget); + nValue = GetCurrentHitPoints(oTarget); } - else if(iType == i8) + else if(nType == 8) { // Max - iValue = GetMaxHitPoints(oTarget); + nValue = GetMaxHitPoints(oTarget); } - else if(iType == i9) + else if(nType == 9) { // Sneak attack. - iValue = FALSE; + nValue = FALSE; if(GetAttackTarget(oTarget) != OBJECT_SELF && !GetIsImmune(oTarget, IMMUNITY_TYPE_SNEAK_ATTACK)) { - iValue = TRUE; + nValue = TRUE; } } // We set it to the new array name - highest to lowest. - SetArrayIntegerValue(ARRAY_TEMP_ARRAY, oTarget, iValue); + SetArrayIntegerValue(ARRAY_TEMP_ARRAY, oTarget, nValue); // Delete the old one - if(iType != i9)// Sneak attack, if not a valid sneak target, we target normally so don't delete + if(nType != 9)// Sneak attack, if not a valid sneak target, we target normally so don't delete { - DeleteLocalObject(OBJECT_SELF, sOriginalArrayName + IntToString(iCnt)); + DeleteLocalObject(OBJECT_SELF, sOriginalArrayName + IntToString(nCnt)); } // Next target - iCnt++; - oTarget = GetLocalObject(OBJECT_SELF, sOriginalArrayName + IntToString(iCnt)); + nCnt++; + oTarget = GetLocalObject(OBJECT_SELF, sOriginalArrayName + IntToString(nCnt)); } } // Deletes all FLoats, Integers and Objects set to sArray for valid // objects got by GetLocalObject to sArray. void AI_TargetingArrayDelete(string sArray) { - int iCnt = i1; - string sCnt = IntToString(iCnt); + int nCnt = 1; + string sCnt = IntToString(nCnt); object oLocal = GetLocalObject(OBJECT_SELF, sArray + sCnt); while(GetIsObjectValid(oLocal)) { @@ -12014,45 +11972,45 @@ void AI_TargetingArrayDelete(string sArray) DeleteLocalInt(OBJECT_SELF, sArray + sCnt); DeleteLocalObject(OBJECT_SELF, sArray + sCnt); // Get next object - iCnt++; - sCnt = IntToString(iCnt); + nCnt++; + sCnt = IntToString(nCnt); oLocal = GetLocalObject(OBJECT_SELF, sArray + sCnt); } DeleteLocalInt(OBJECT_SELF, MAXINT_ + sArray); } // This sets ARRAY_TEMP_ARRAY of integer values to sNewArrayName. -// - iTypeOfTarget, used TARGET_LOWER, TARGET_HIGHER. -// - We work until iMinimum is filled, or we get to iMinimum and we get to -// a target with value > iImputMinimum. (20 - 25 > X?) -int AI_TargetingArrayLimitTargets(string sNewArrayName, int iTypeOfTarget, int iImputMinLimit, int iMinLoop, int iMaxLoop) +// - nTypeOfTarget, used TARGET_LOWER, TARGET_HIGHER. +// - We work until nMinimum is filled, or we get to nMinimum and we get to +// a target with value > iInputMinimum. (20 - 25 > X?) +int AI_TargetingArrayLimitTargets(string sNewArrayName, int nTypeOfTarget, int iInputMinLimit, int nMinLoop, int nMaxLoop) { - int iAddEachTime, iValue, iCnt, iCnt2, iCnt3, iBreak, iLowestHighestValue; + int iAddEachTime, nValue, nCnt, nCnt2, nCnt3, bBreak, nLowestHighestValue; string sCnt; object oSetUpTarget; // Is it lowest to highest, or highest to lowest? // - 1. Lowest to highest - if(iTypeOfTarget == TARGET_LOWER) + if(nTypeOfTarget == TARGET_LOWER) { - iAddEachTime = i1; - iCnt = i1; + iAddEachTime = 1; + nCnt = 1; } - else // if(iTypeOfTarget == TARGET_HIGHER) + else // if(nTypeOfTarget == TARGET_HIGHER) { // Change to start at top value, and work down. - iAddEachTime = iM1; - iCnt = GetLocalInt(OBJECT_SELF, MAXINT_ + ARRAY_TEMP_ARRAY); + iAddEachTime = -1; + nCnt = GetLocalInt(OBJECT_SELF, MAXINT_ + ARRAY_TEMP_ARRAY); } // Start loop from array based on AC. Overrides exsisting targets // - Use temp enemy array. ARRAY_TEMP_ARRAY - iCnt2 = i0; - sCnt = IntToString(iCnt); + nCnt2 = 0; + sCnt = IntToString(nCnt); oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_TEMP_ARRAY + sCnt); - while(GetIsObjectValid(oSetUpTarget) && iBreak != TRUE) + while(GetIsObjectValid(oSetUpTarget) && bBreak != TRUE) { // We check AC or whatever... - iValue = GetLocalInt(OBJECT_SELF, ARRAY_TEMP_ARRAY + sCnt); + nValue = GetLocalInt(OBJECT_SELF, ARRAY_TEMP_ARRAY + sCnt); // Delete objects DeleteLocalObject(OBJECT_SELF, ARRAY_TEMP_ARRAY + sCnt); DeleteLocalInt(OBJECT_SELF, ARRAY_TEMP_ARRAY + sCnt); @@ -12060,25 +12018,25 @@ int AI_TargetingArrayLimitTargets(string sNewArrayName, int iTypeOfTarget, int i // we check if we have under minimum OR it is under/over X. // As it is in value order, once we get to a point to stop, we // break the loop. - if((iCnt2 < iMaxLoop) && - ((iCnt2 < iMinLoop) /*Default, get minimum targets*/ - || (iValue - iLowestHighestValue < iImputMinLimit && iTypeOfTarget == TARGET_LOWER)// Lowest to highest (20 - 25 < X?) - || (iLowestHighestValue - iValue < iImputMinLimit && iTypeOfTarget == TARGET_HIGHER)))// Highest to lowest (25 - 20 < X?) + if((nCnt2 < nMaxLoop) && + ((nCnt2 < nMinLoop) /*Default, get minimum targets*/ + || (nValue - nLowestHighestValue < iInputMinLimit && nTypeOfTarget == TARGET_LOWER)// Lowest to highest (20 - 25 < X?) + || (nLowestHighestValue - nValue < iInputMinLimit && nTypeOfTarget == TARGET_HIGHER)))// Highest to lowest (25 - 20 < X?) { // Set this as the newest highest/lowest value - iLowestHighestValue = iValue; + nLowestHighestValue = nValue; // Add it to array. - iCnt2++; - sCnt = IntToString(iCnt2); + nCnt2++; + sCnt = IntToString(nCnt2); SetLocalObject(OBJECT_SELF, sNewArrayName + sCnt, oSetUpTarget); - SetLocalInt(OBJECT_SELF, sNewArrayName + sCnt, iValue); + SetLocalInt(OBJECT_SELF, sNewArrayName + sCnt, nValue); } else // else break out. (If got to max targets, got to a target we don't want to target) { - for(iCnt3 = iCnt; iBreak != TRUE; iCnt3 += iAddEachTime) + for(nCnt3 = nCnt; bBreak != TRUE; nCnt3 += iAddEachTime) { // Remove all other values in the loop. - sCnt = IntToString(iCnt3); + sCnt = IntToString(nCnt3); if(GetIsObjectValid(GetLocalObject(OBJECT_SELF, ARRAY_TEMP_ARRAY + sCnt))) { DeleteLocalInt(OBJECT_SELF, ARRAY_TEMP_ARRAY + sCnt); @@ -12086,54 +12044,54 @@ int AI_TargetingArrayLimitTargets(string sNewArrayName, int iTypeOfTarget, int i } else { - iBreak = TRUE; + bBreak = TRUE; } } - iBreak = TRUE; + bBreak = TRUE; } // Get next AC target - we add X, which is either +1 or -1, to // continue a loop going up or down. - iCnt += iAddEachTime; - sCnt = IntToString(iCnt); + nCnt += iAddEachTime; + sCnt = IntToString(nCnt); oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_TEMP_ARRAY + sCnt); } // Start resetting temp array used in the rest. DeleteLocalInt(OBJECT_SELF, MAXINT_ + ARRAY_TEMP_ARRAY); // Returns the amount of targets stored. - return iCnt2; + return nCnt2; } // This sets ARRAY_TEMP_ARRAY of float values to sNewArrayName. -// - iTypeOfTarget, used TARGET_LOWER, TARGET_HIGHER. -// - We work until iMinimum is filled, or we get to iMinimum and we get to -// a target with value > iImputMinimum. (20.0 - 25.0 > X?) +// - nTypeOfTarget, used TARGET_LOWER, TARGET_HIGHER. +// - We work until nMinimum is filled, or we get to nMinimum and we get to +// a target with value > iInputMinimum. (20.0 - 25.0 > X?) // Returns the amount of targets set in sNewArrayName. -int AI_TargetingArrayLimitTargetsFloat(string sNewArrayName, int iTypeOfTarget, float fImputMinLimit, int iMinLoop, int iMaxLoop) +int AI_TargetingArrayLimitTargetsFloat(string sNewArrayName, int nTypeOfTarget, float fInputMinLimit, int nMinLoop, int nMaxLoop) { - int iAddEachTime, iCnt, iCnt2, iCnt3, iBreak; + int iAddEachTime, nCnt, nCnt2, nCnt3, bBreak; float fValue, fLowestHighestValue; string sCnt; object oSetUpTarget; // Is it lowest to highest, or highest to lowest? // - 1. Lowest to highest - if(iTypeOfTarget == TARGET_LOWER) + if(nTypeOfTarget == TARGET_LOWER) { - iAddEachTime = i1; - iCnt = i1; + iAddEachTime = 1; + nCnt = 1; } - else // if(iTypeOfTarget == TARGET_HIGHER) + else // if(nTypeOfTarget == TARGET_HIGHER) { // Change to start at top value, and work down. - iAddEachTime = iM1; - iCnt = GetLocalInt(OBJECT_SELF, MAXINT_ + ARRAY_TEMP_ARRAY); + iAddEachTime = -1; + nCnt = GetLocalInt(OBJECT_SELF, MAXINT_ + ARRAY_TEMP_ARRAY); } // Start loop from array based on AC. Overrides exsisting targets // - Use temp enemy (AC) array. - iCnt2 = FALSE;// Reset counter - iCnt = i1; - sCnt = IntToString(iCnt); + nCnt2 = FALSE;// Reset counter + nCnt = 1; + sCnt = IntToString(nCnt); oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_TEMP_ARRAY + sCnt); - while(GetIsObjectValid(oSetUpTarget) && iBreak != TRUE) + while(GetIsObjectValid(oSetUpTarget) && bBreak != TRUE) { // We check range normally... fValue = GetLocalFloat(OBJECT_SELF, ARRAY_TEMP_ARRAY + sCnt); @@ -12141,25 +12099,25 @@ int AI_TargetingArrayLimitTargetsFloat(string sNewArrayName, int iTypeOfTarget, // we check if we have under minimum OR it is under/over X. // As it is in value order, once we get to a point to stop, we // break the loop. - if((iCnt2 < iMaxLoop) && - ((iCnt2 < iMinLoop) /*Default, get minimum targets*/ - || (fValue - fLowestHighestValue < fImputMinLimit && iTypeOfTarget == TARGET_LOWER)// Lowest to highest (20 - 25 < X?) - || (fLowestHighestValue - fValue < fImputMinLimit && iTypeOfTarget == TARGET_HIGHER)))// Highest to lowest (25 - 20 < X?) + if((nCnt2 < nMaxLoop) && + ((nCnt2 < nMinLoop) /*Default, get minimum targets*/ + || (fValue - fLowestHighestValue < fInputMinLimit && nTypeOfTarget == TARGET_LOWER)// Lowest to highest (20 - 25 < X?) + || (fLowestHighestValue - fValue < fInputMinLimit && nTypeOfTarget == TARGET_HIGHER)))// Highest to lowest (25 - 20 < X?) { // Set fLowestHighestValue fLowestHighestValue = fValue; // Add it to array. - iCnt2++; - sCnt = IntToString(iCnt2); + nCnt2++; + sCnt = IntToString(nCnt2); SetLocalObject(OBJECT_SELF, sNewArrayName + sCnt, oSetUpTarget); SetLocalFloat(OBJECT_SELF, sNewArrayName + sCnt, fValue); } else // else break out. (If got to max targets, got to a target we don't want to target) { - for(iCnt3 = iCnt; iBreak != TRUE; iCnt3 += iAddEachTime) + for(nCnt3 = nCnt; bBreak != TRUE; nCnt3 += iAddEachTime) { // Remove all other values in the loop. - sCnt = IntToString(iCnt3); + sCnt = IntToString(nCnt3); if(GetIsObjectValid(GetLocalObject(OBJECT_SELF, ARRAY_TEMP_ARRAY + sCnt))) { DeleteLocalFloat(OBJECT_SELF, ARRAY_TEMP_ARRAY + sCnt); @@ -12167,45 +12125,48 @@ int AI_TargetingArrayLimitTargetsFloat(string sNewArrayName, int iTypeOfTarget, } else { - iBreak = TRUE; + bBreak = TRUE; } } - iBreak = TRUE; + bBreak = TRUE; } // Delete objects DeleteLocalObject(OBJECT_SELF, ARRAY_TEMP_ARRAY + sCnt); DeleteLocalFloat(OBJECT_SELF, ARRAY_TEMP_ARRAY + sCnt); // Get next AC target - we add X, which is either +1 or -1, to // continue a loop going up or down. - iCnt += iAddEachTime; - sCnt = IntToString(iCnt); + nCnt += iAddEachTime; + sCnt = IntToString(nCnt); oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_TEMP_ARRAY + sCnt); } // Start resetting temp array used in the rest. DeleteLocalInt(OBJECT_SELF, MAXINT_ + ARRAY_TEMP_ARRAY); // Returns the amount of targets stored. - return iCnt2; + return nCnt2; } -// Makes sure oTarget isn't: -// - Dead -// - Petrified -// - AI Ignore ON -// - DM -// Must be: Seen or heard -// Returns: TRUE if any of these are true. +// Check if oTarget is: +// - Dead, Petrified, AI Ignore ON, A DM, Invalid +// - Not: Seen or heard (IE: We cannot see or hear them) +// Returns: TRUE if it is SANE to attack oTarget int AI_GetTargetSanityCheck(object oTarget) { - if(!GetIsObjectValid(oTarget) || // Isn't valid + // Ethereal check + if(GetIsEthereal(oTarget)) return FALSE; + + if(!GetIsObjectValid(oTarget) && // Isn't valid GetIsDead(oTarget) || // Is dead GetIsDM(oTarget) || // Is DM GetIgnore(oTarget) || // Is ignored AI_GetAIHaveEffect(GlobalEffectPetrify, oTarget) || // Is petrified (!GetObjectSeen(oTarget) && !GetObjectHeard(oTarget))) // Is not seen nor heard. { - return TRUE; + // If we cannot see or hear the target, or they are an invalid target, + // it is NOT sane to atack them - return FALSE + return FALSE; } - return FALSE; + // Else, return TRUE - we CAN attack them! + return TRUE; } // We set up targets to Global* variables, GlobalSpellTarget, GlobalRangeTarget, @@ -12213,7 +12174,7 @@ int AI_GetTargetSanityCheck(object oTarget) // - Uses oIntruder (to attack or move near) if anything. // - We return TRUE if it ActionAttack's, or moves to an enemy - basically // that we cannot do an action, but shouldn't search. False if normal. -int AI_SetUpAllObjects(object oImputBackup) +int AI_SetUpAllObjects(object oInputBackup) { // Delete past arrays AI_TargetingArrayDelete(ARRAY_ENEMY_RANGE); @@ -12226,15 +12187,15 @@ int AI_SetUpAllObjects(object oImputBackup) // We always use range as at least 1 of the ways to get best target. float fCurrentRange, fSetMaxWeCanGoTo; location lSelf = GetLocation(OBJECT_SELF); - int iCnt, iCnt2, iCnt3, iBreak;//Counter loop. - int iValue, iMaxTurnsAttackingX, iMaximum, iMinimum, iRemainingTargets, iTypeOfTarget; - string sCnt; // IntToString(iCnt) :-) - object oTempLoopObject, oSetUpTarget, oLastHostile, oLastTarget, oImputBackUpToAttack; + int nCnt, nCnt2, nCnt3, bBreak;//Counter loop. + int nValue, nMaxTurnsAttackingX, nMaximum, nMinimum, nRemainingTargets, nTypeOfTarget; + string sCnt; // IntToString(nCnt) :-) + object oTempLoopObject, oSetUpTarget, oLastTarget, oInputBackUpToAttack; // Note: Here we check if oIntruder is a sane thing to attack. - if(GetIsObjectValid(oImputBackup) && !GetIgnoreNoFriend(oImputBackup)) + if(AI_GetTargetSanityCheck(oInputBackup)) { - oImputBackUpToAttack = oImputBackup; + oInputBackUpToAttack = oInputBackup; } // Note: oIntruder is still used to search near if anything. @@ -12246,24 +12207,32 @@ int AI_SetUpAllObjects(object oImputBackup) GlobalSpellTarget = GlobalNearestEnemySeen; } - // We set up 2 other targets...for testing against ETC. - oLastHostile = GetLastHostileActor(); - iMaxTurnsAttackingX = GetBoundriedAIInteger(AI_MAX_TURNS_TO_ATTACK_ONE_TARGET, i6, i40, i1); + // we have a max amount of rounds to attack one target. + nMaxTurnsAttackingX = GetBoundriedAIInteger(AI_MAX_TURNS_TO_ATTACK_ONE_TARGET, 6, 40, 1); // Start... // Gets all CREATURES within 50M andin LOS. THIS IS THE MAJOR OBJECT LOOP OF THE AI! - GlobalTotalPeople = FALSE;// Reset - oSetUpTarget = GetFirstObjectInShape(SHAPE_SPHERE, f50, lSelf, TRUE); + oSetUpTarget = GetFirstObjectInShape(SHAPE_SPHERE, 50.0, lSelf, TRUE); while(GetIsObjectValid(oSetUpTarget)) { // We totally ignore DM's, and AI_IGNORE people - // - We don't use us as a target - // - We do dead people later, special with GetNearestCreature - if(!GetIgnore(oSetUpTarget) && !GetIsDM(oSetUpTarget) && - !GetIsDead(oSetUpTarget) && oSetUpTarget != OBJECT_SELF) + // * 1.4: We also ignore all Etherealness (even if they are visible). + // A new function is added after targeting to react to the + // ethereal people we *may* see via. trueseeing, and cannot see anything + // else by casting defensive only spells, healing, summoning, + // and making sure we stay in combat! + // * Ignore: + // - Dead + // - Petrified + // - AI Ignore ON + // - DM + // - Invalid + // Must be: Seen or heard + // Else, we ignore them. Special cases can get dead people (raising, + // killing off) but unseen/unheard people are, in the case of the AI, + // unknown about unless we specifically know they went/came invisible + if(AI_GetTargetSanityCheck(oSetUpTarget) && oSetUpTarget != OBJECT_SELF) { - // We count +1 more person in our LOS - GlobalTotalPeople++; // If the target is a friend, we add 1 to targets, and set in array. if(GetIsFriend(oSetUpTarget) || GetFactionEqual(oSetUpTarget)) { @@ -12275,11 +12244,21 @@ int AI_SetUpAllObjects(object oImputBackup) { //SpeakString("Enemy (no dead) in LOS:" + GetName(oSetUpTarget)); // We set up a "Seen or heard" enemies counter below - iCnt++; - SetLocalObject(OBJECT_SELF, ARRAY_TEMP_ENEMIES + IntToString(iCnt), oSetUpTarget); + nCnt++; + SetLocalObject(OBJECT_SELF, ARRAY_TEMP_ENEMIES + IntToString(nCnt), oSetUpTarget); } + // Well, we have enemies in range. We check if we need to re-set constants + // based on a timer. If done, set a timer. + // * 1.4 : Removes the timer! This is now done each time the AI runs, + // and as the Bioware AI does loops of all effects quite often, this, + // even if not a large improvement of performance, is easier for the AI + // and me to write and code. + // * 1.4 changes also fix some remove condition problems of the + // local not being updated. + // Always set up effects - allied, neutral, or enemy! + AI_SetEffectsOnTarget(oSetUpTarget); } - oSetUpTarget = GetNextObjectInShape(SHAPE_SPHERE, f50, lSelf, TRUE); + oSetUpTarget = GetNextObjectInShape(SHAPE_SPHERE, 50.0, lSelf, TRUE); } // The first simple one is therefore done :-) @@ -12304,95 +12283,85 @@ int AI_SetUpAllObjects(object oImputBackup) // Before we start re-setting targets, we do set up an extra 2 arrays based // on seen and heard (one OR the other) arrays for the enemy. These are objects in our LOS. - iCnt = i1; - iCnt2 = FALSE;// Counter for seen - iCnt3 = FALSE;// Counter for heard - iValue = FALSE;// Counter for BAB - iBreak = FALSE;// Counter for HD + nCnt = 1; + nCnt2 = FALSE;// Counter for seen + nCnt3 = FALSE;// Counter for heard + nValue = FALSE;// Counter for BAB + bBreak = FALSE;// Counter for HD GlobalEnemiesIn4Meters = FALSE;// Make sure at 0 GlobalMeleeAttackers = FALSE;// Make sure at 0 GlobalRangedAttackers = FALSE;// Make sure at 0 - oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE + IntToString(iCnt)); + oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE + IntToString(nCnt)); while(GetIsObjectValid(oSetUpTarget)) { - fCurrentRange = GetLocalFloat(OBJECT_SELF, ARRAY_ENEMY_RANGE + IntToString(iCnt)); - // Well, we have enemies in range. We check if we need to re-set constants - // based on a timer. If done, set a timer. - if(!GetLocalInt(oSetUpTarget, AI_JASPERRES_EFFECT_SET) && - !GetLocalInt(oSetUpTarget, AI_TIMER_EFFECT_SET)) + fCurrentRange = GetLocalFloat(OBJECT_SELF, ARRAY_ENEMY_RANGE + IntToString(nCnt)); + + // 1.4 change here. Already checked for dead and petrifed creatures + // in setting all arrays of enemies and allies. + + // Count ranged and melee attackers. + if(GetAttackTarget(oSetUpTarget) == OBJECT_SELF) { - AI_SetEffectsOnTarget(oSetUpTarget); - SetLocalInt(oSetUpTarget, AI_TIMER_EFFECT_SET, TRUE); - // Just set effects every round, not every possible action (2 with haste) - DelayCommand(f5, DeleteLocalInt(oSetUpTarget, AI_TIMER_EFFECT_SET)); + // Melee/ranged attacker? + if(GetWeaponRanged(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oSetUpTarget))) + { + // - 1.3 beta fixed this. I didn't notice I got these mixed up :-P + GlobalRangedAttackers++; + } + else + { + GlobalMeleeAttackers++; + } } - // Don't target things who are petrified. - if(!AI_GetAIHaveEffect(GlobalEffectPetrify, oSetUpTarget) && !GetIsDead(oSetUpTarget)) + // Total enemies in 4M + if(fCurrentRange <= 4.0) { - // Count ranged and melee attackers. - if(GetAttackTarget(oSetUpTarget) == OBJECT_SELF) - { - // Melee/ranged attacker? - if(GetWeaponRanged(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oSetUpTarget))) - { - // - 1.3 beta fixed this. I didn't notice I got these mixed up :-P - GlobalRangedAttackers++; - } - else - { - GlobalMeleeAttackers++; - } - } - // Total enemies in 4M - if(fCurrentRange <= f4) - { - GlobalEnemiesIn4Meters++; - } - // It is nearest to futhest. Just set each one in one of 2 arrays. - if(GetObjectSeen(oSetUpTarget)) - { - // iBreak counts average HD - iBreak += GetHitDice(oSetUpTarget); - // Value counts BAB - iValue += GetBaseAttackBonus(oSetUpTarget); - // Add to total seen/heard enemies - GlobalTotalSeenHeardEnemies++; - // Object seen. - iCnt2++; - SetLocalFloat(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(iCnt2), fCurrentRange); - SetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(iCnt2), oSetUpTarget); - } - else if(GetObjectHeard(oSetUpTarget)) - { - // iBreak counts average HD - iBreak += GetHitDice(oSetUpTarget); - // Value counts BAB - iValue += GetBaseAttackBonus(oSetUpTarget); - // Add to total seen/heard enemies - GlobalTotalSeenHeardEnemies++; - // Object heard. - iCnt3++; - SetLocalFloat(OBJECT_SELF, ARRAY_ENEMY_RANGE_HEARD + IntToString(iCnt3), fCurrentRange); - SetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_HEARD + IntToString(iCnt3), oSetUpTarget); - } + GlobalEnemiesIn4Meters++; + } + // It is nearest to futhest. Just set each one in one of 2 arrays. + if(GetObjectSeen(oSetUpTarget)) + { + // bBreak counts average HD + bBreak += GetHitDice(oSetUpTarget); + // Value counts BAB + nValue += GetBaseAttackBonus(oSetUpTarget); + // Add to total seen/heard enemies + GlobalTotalSeenHeardEnemies++; + // Object seen. + nCnt2++; + SetLocalFloat(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(nCnt2), fCurrentRange); + SetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(nCnt2), oSetUpTarget); + } + else if(GetObjectHeard(oSetUpTarget)) + { + // bBreak counts average HD + bBreak += GetHitDice(oSetUpTarget); + // Value counts BAB + nValue += GetBaseAttackBonus(oSetUpTarget); + // Add to total seen/heard enemies + GlobalTotalSeenHeardEnemies++; + // Object heard. + nCnt3++; + SetLocalFloat(OBJECT_SELF, ARRAY_ENEMY_RANGE_HEARD + IntToString(nCnt3), fCurrentRange); + SetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_HEARD + IntToString(nCnt3), oSetUpTarget); } // Next enemy - iCnt++; - oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE + IntToString(iCnt)); + nCnt++; + oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE + IntToString(nCnt)); } - // set GlobalRangeToFuthestEnemy. + // Set GlobalRangeToFuthestEnemy. // - Using futhest heard should be good enough. - GlobalRangeToFuthestEnemy = GetLocalFloat(OBJECT_SELF, ARRAY_ENEMY_RANGE_HEARD + IntToString(iCnt3)); + GlobalRangeToFuthestEnemy = GetLocalFloat(OBJECT_SELF, ARRAY_ENEMY_RANGE_HEARD + IntToString(nCnt3)); // We need value just above to calcualte these, else leave at 0. - if(GlobalTotalSeenHeardEnemies >= i1 && iBreak >= i1) + if(GlobalTotalSeenHeardEnemies >= 1 && bBreak >= 1) { // Average enemy HD - GlobalAverageEnemyHD = iBreak / GlobalTotalSeenHeardEnemies; - if(GlobalAverageEnemyHD < i1) GlobalAverageEnemyHD = i1; + GlobalAverageEnemyHD = bBreak / GlobalTotalSeenHeardEnemies; + if(GlobalAverageEnemyHD < 1) GlobalAverageEnemyHD = 1; // Average BAB - GlobalAverageEnemyBAB = iValue / GlobalTotalSeenHeardEnemies; - if(GlobalAverageEnemyBAB < i0) GlobalAverageEnemyBAB = i0; + GlobalAverageEnemyBAB = nValue / GlobalTotalSeenHeardEnemies; + if(GlobalAverageEnemyBAB < 0) GlobalAverageEnemyBAB = 0; } /*::////////////////////////////////////////////// @@ -12405,7 +12374,7 @@ int AI_SetUpAllObjects(object oImputBackup) AI_TargetingArrayDistanceStore(ARRAY_TEMP_ALLIES, ARRAY_ALLIES_RANGE); // Spells which affect GetIsReactionType - oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE + s1); + oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE + "1"); // If not valid, use self if(!GetIsObjectValid(oSetUpTarget)) @@ -12425,30 +12394,30 @@ int AI_SetUpAllObjects(object oImputBackup) // 0 Seen/heard. We don't check enemies numbers - they could be hidden. if(!GlobalValidNearestSeenEnemy && !GlobalValidNearestHeardEnemy) { - iBreak = FALSE; + bBreak = FALSE; // Loop allies for ANY target, and move to them! (Attack in HTH, this // lets us re-set targets On Percieve) - iCnt = iM1; + nCnt = -1; // Allys - oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE + IntToString(iCnt)); - while(GetIsObjectValid(oSetUpTarget) && iBreak != TRUE) + oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE + IntToString(nCnt)); + while(GetIsObjectValid(oSetUpTarget) && bBreak != TRUE) { // It is nearest to futhest. oTempLoopObject = GetAttackTarget(oSetUpTarget); if(GetIsObjectValid(oTempLoopObject)) { // If a valid attack object, we stop! - iBreak = TRUE; + bBreak = TRUE; } else { // Next ally - iCnt++; - oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE + IntToString(iCnt)); + nCnt++; + oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE + IntToString(nCnt)); } } // We move to the target if we have one. - if(iBreak) + if(bBreak) { // Just a temp most damaging melee. Normally, it is best to // just Move to the target @@ -12470,84 +12439,84 @@ int AI_SetUpAllObjects(object oImputBackup) { // Set up an array of seen ranged-based allies, for healing and for // healing effects, and for buffing. - iCnt = i1; - iCnt2 = i0; - iCnt3 = i0; - iValue = FALSE; // Just a temp for leader status set - oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE + IntToString(iCnt)); + nCnt = 1; + nCnt2 = 0; + nCnt3 = 0; + nValue = FALSE; // Just a temp for leader status set + oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE + IntToString(nCnt)); while(GetIsObjectValid(oSetUpTarget)) { - iCnt3 += GetHitDice(oSetUpTarget); + nCnt3 += GetHitDice(oSetUpTarget); if(GetObjectSeen(oSetUpTarget)) { - iCnt2++; - SetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN + IntToString(iCnt2), oSetUpTarget); + nCnt2++; + SetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN + IntToString(nCnt2), oSetUpTarget); // Set global nearest seen leader for morale ETC. if(GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_GROUP_LEADER, AI_OTHER_COMBAT_MASTER, oSetUpTarget) - && iValue != TRUE) + && nValue != TRUE) { GlobalNearestLeader = oSetUpTarget; - iValue = TRUE; + nValue = TRUE; } } // Next ally - iCnt++; - oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN + IntToString(iCnt)); + nCnt++; + oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN + IntToString(nCnt)); } - GlobalValidLeader = iValue; - if(iCnt >= i1 && iCnt3 >= i1) + GlobalValidLeader = nValue; + if(nCnt >= 1 && nCnt3 >= 1) { - GlobalAverageFriendlyHD = iCnt3 / iCnt; + GlobalAverageFriendlyHD = nCnt3 / nCnt; } // Set nearest seen ally. - GlobalNearestSeenAlly = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN + s1); + GlobalNearestSeenAlly = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN + "1"); GlobalValidSeenAlly = GetIsObjectValid(GlobalNearestSeenAlly); // We set up buff allies in a new array. // - We may set up summons (or people with masters) if we have under // <= 3 people, or it is of comparable hit dice to us. - iCnt = i1; - iCnt2 = FALSE; - fSetMaxWeCanGoTo = f20; + nCnt = 1; + nCnt2 = FALSE; + fSetMaxWeCanGoTo = 20.0; // we add this onto any ranges we input, so how far we'll move to. GlobalBuffRangeAddon = 0.0; - // iValue is the limit of buff targets + // nValue is the limit of buff targets // - Less if sorceror/bard (very few) // - More if proper buffer - iValue = i5; + nValue = 5; if(GlobalWeAreSorcerorBard) { - iValue = i2; + nValue = 2; } // If we are set to buff allies, we extend the range. if(GetSpawnInCondition(AI_FLAG_COMBAT_MORE_ALLY_BUFFING_SPELLS, AI_COMBAT_MASTER)) { - iValue = i8; - fSetMaxWeCanGoTo = f40; - GlobalBuffRangeAddon = f30; + nValue = 8; + fSetMaxWeCanGoTo = 40.0; + GlobalBuffRangeAddon = 30.0; } - oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN + IntToString(iCnt)); + oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN + IntToString(nCnt)); // Loop allies // - Only up to 10. // - Check masters as above. - while(GetIsObjectValid(oSetUpTarget) && iCnt2 <= iValue && + while(GetIsObjectValid(oSetUpTarget) && nCnt2 <= nValue && GetDistanceToObject(oSetUpTarget) <= fSetMaxWeCanGoTo) { // No arcane spellcasters. if(!GetLevelByClass(CLASS_TYPE_SORCERER, oSetUpTarget) && !GetLevelByClass(CLASS_TYPE_WIZARD, oSetUpTarget) && // - Master check - (GlobalTotalAllies <= i3 || + (GlobalTotalAllies <= 3 || !GetIsObjectValid(GetMaster(oSetUpTarget)) || - GetHitDice(oSetUpTarget) >= GlobalOurHitDice - i5)) + GetHitDice(oSetUpTarget) >= GlobalOurHitDice - 5)) { // Add to new array - iCnt2++; - SetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN_BUFF + IntToString(iCnt2), oSetUpTarget); + nCnt2++; + SetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN_BUFF + IntToString(nCnt2), oSetUpTarget); } // Next seen ally - iCnt++; - oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN + IntToString(iCnt)); + nCnt++; + oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE_SEEN + IntToString(nCnt)); } } @@ -12573,7 +12542,7 @@ int AI_SetUpAllObjects(object oImputBackup) DeleteAIObject(AI_ATTACK_SPECIFIC_OBJECT); // Our specific target to attack // - sanity check just in case - if(!AI_GetTargetSanityCheck(oSetUpTarget)) + if(AI_GetTargetSanityCheck(oSetUpTarget)) { // 40: "[DCR:Targeting] Override Target Seen. [Name]" + GetName(oSetUpTarget) DebugActionSpeakByInt(40, oSetUpTarget); @@ -12583,7 +12552,8 @@ int AI_SetUpAllObjects(object oImputBackup) GlobalSpellTarget = oSetUpTarget; } // Lagbusting, get nearest - else if(GetSpawnInCondition(AI_FLAG_OTHER_LAG_TARGET_NEAREST_ENEMY, AI_TARGETING_FLEE_MASTER)) + // * This is under AI_OTHER_MASTER. 1.4 fix. + else if(GetSpawnInCondition(AI_FLAG_OTHER_LAG_TARGET_NEAREST_ENEMY, AI_OTHER_MASTER)) { if(GetIsObjectValid(GlobalNearestEnemySeen)) { @@ -12599,10 +12569,10 @@ int AI_SetUpAllObjects(object oImputBackup) { // We use this check - inbuilt, automatic, and also is simple! oSetUpTarget = GetFactionMostDamagedMember(GlobalNearestEnemySeen); - if(GetIsObjectValid(oSetUpTarget)) + if(AI_GetTargetSanityCheck(oSetUpTarget)) { - if(GetDistanceToObject(GlobalNearestEnemyHeard) > f4 || - GetDistanceToObject(oSetUpTarget) < f3) + if(GetDistanceToObject(GlobalNearestEnemyHeard) > 4.0 || + GetDistanceToObject(oSetUpTarget) < 3.0) { GlobalMeleeTarget = oSetUpTarget; } @@ -12615,10 +12585,10 @@ int AI_SetUpAllObjects(object oImputBackup) { // We use this check - inbuilt, automatic, and also is simple! oSetUpTarget = GetFactionWeakestMember(GlobalNearestEnemySeen); - if(GetIsObjectValid(oSetUpTarget)) + if(AI_GetTargetSanityCheck(oSetUpTarget)) { - if(GetDistanceToObject(GlobalNearestEnemyHeard) > f4 || - GetDistanceToObject(oSetUpTarget) < f3) + if(GetDistanceToObject(GlobalNearestEnemyHeard) > 4.0 || + GetDistanceToObject(oSetUpTarget) < 3.0) { GlobalMeleeTarget = oSetUpTarget; } @@ -12631,11 +12601,11 @@ int AI_SetUpAllObjects(object oImputBackup) { // We use this check - inbuilt, automatic, and also is simple! oSetUpTarget = GetFactionWorstAC(GlobalNearestEnemySeen); - if(GetIsObjectValid(oSetUpTarget)) + if(AI_GetTargetSanityCheck(oSetUpTarget)) { // Make sure the nearest seen is not in front of the worst AC. - if(GetDistanceToObject(GlobalNearestEnemyHeard) > f4 || - GetDistanceToObject(oSetUpTarget) < f3) + if(GetDistanceToObject(GlobalNearestEnemyHeard) > 4.0 || + GetDistanceToObject(oSetUpTarget) < 3.0) { GlobalMeleeTarget = oSetUpTarget; } @@ -12647,15 +12617,18 @@ int AI_SetUpAllObjects(object oImputBackup) else if(GetSpawnInCondition(AI_FLAG_TARGETING_LIKE_ARCHERS, AI_TARGETING_FLEE_MASTER)) { // Get nearest one who is attacking us. - iCnt = i1; - oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(iCnt)); + nCnt = 1; + oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(nCnt)); while(GetIsObjectValid(oSetUpTarget)) { + // All the array is already sane targets. + // have they got a ranged weapon? if(GetWeaponRanged(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oSetUpTarget))) { - if(GetDistanceToObject(GlobalNearestEnemyHeard) > f4 || - GetDistanceToObject(oSetUpTarget) < f3) + // Only set to melee if quite near. + if(GetDistanceToObject(GlobalNearestEnemyHeard) > 4.0 || + GetDistanceToObject(oSetUpTarget) < 3.0) { GlobalMeleeTarget = oSetUpTarget; } @@ -12663,27 +12636,27 @@ int AI_SetUpAllObjects(object oImputBackup) GlobalSpellTarget = oSetUpTarget; break; } - iCnt++; - oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(iCnt)); + nCnt++; + oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(nCnt)); } } // Mage classes else if(GetSpawnInCondition(AI_FLAG_TARGETING_LIKE_MAGE_CLASSES, AI_TARGETING_FLEE_MASTER)) { // Sorceror - oSetUpTarget = GetNearestCreature(CREATURE_TYPE_CLASS, CLASS_TYPE_SORCERER, OBJECT_SELF, i1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, CREATURE_TYPE_IS_ALIVE, TRUE); - if(!GetIsObjectValid(oSetUpTarget) || - (!GetObjectSeen(oSetUpTarget) && !GetObjectHeard(oSetUpTarget))) + oSetUpTarget = GetNearestCreature(CREATURE_TYPE_CLASS, CLASS_TYPE_SORCERER, OBJECT_SELF, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, CREATURE_TYPE_IS_ALIVE, TRUE); + // If the sorceror isn't sane, we will check for wizards. + if(!AI_GetTargetSanityCheck(oSetUpTarget)) { // Wizard - oSetUpTarget = GetNearestCreature(CREATURE_TYPE_CLASS, CLASS_TYPE_WIZARD, OBJECT_SELF, i1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, CREATURE_TYPE_IS_ALIVE, TRUE); + oSetUpTarget = GetNearestCreature(CREATURE_TYPE_CLASS, CLASS_TYPE_WIZARD, OBJECT_SELF, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, CREATURE_TYPE_IS_ALIVE, TRUE); } // If valid, use - if(GetIsObjectValid(oSetUpTarget) && - (GetObjectSeen(oSetUpTarget) || GetObjectHeard(oSetUpTarget))) + if(AI_GetTargetSanityCheck(oSetUpTarget)) { - if(GetDistanceToObject(GlobalNearestEnemyHeard) > f4 || - GetDistanceToObject(oSetUpTarget) < f3) + // Only set to melee if quite near. + if(GetDistanceToObject(GlobalNearestEnemyHeard) > 4.0 || + GetDistanceToObject(oSetUpTarget) < 3.0) { GlobalMeleeTarget = oSetUpTarget; } @@ -12691,15 +12664,15 @@ int AI_SetUpAllObjects(object oImputBackup) GlobalSpellTarget = oSetUpTarget; } } - iValue = GetAIConstant(AI_FAVOURED_ENEMY_RACE); - if(iValue >= FALSE) + nValue = GetAIConstant(AI_FAVOURED_ENEMY_RACE); + if(nValue >= FALSE) { - oSetUpTarget = GetNearestCreature(CREATURE_TYPE_RACIAL_TYPE, iValue, OBJECT_SELF, i1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN); - if(GetIsObjectValid(oSetUpTarget)) + oSetUpTarget = GetNearestCreature(CREATURE_TYPE_RACIAL_TYPE, nValue, OBJECT_SELF, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN); + if(AI_GetTargetSanityCheck(oSetUpTarget)) { // Make sure the nearest seen is not in front of the worst AC. - if(GetDistanceToObject(GlobalNearestEnemyHeard) > f4 || - GetDistanceToObject(oSetUpTarget) < f3) + if(GetDistanceToObject(GlobalNearestEnemyHeard) > 4.0 || + GetDistanceToObject(oSetUpTarget) < 3.0) { GlobalMeleeTarget = oSetUpTarget; } @@ -12709,15 +12682,15 @@ int AI_SetUpAllObjects(object oImputBackup) } else { - iValue = GetAIConstant(AI_FAVOURED_ENEMY_CLASS); - if(iValue >= FALSE) + nValue = GetAIConstant(AI_FAVOURED_ENEMY_CLASS); + if(nValue >= FALSE) { - oSetUpTarget = GetNearestCreature(CREATURE_TYPE_CLASS, iValue, OBJECT_SELF, i1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN); - if(GetIsObjectValid(oSetUpTarget)) + oSetUpTarget = GetNearestCreature(CREATURE_TYPE_CLASS, nValue, OBJECT_SELF, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN); + if(AI_GetTargetSanityCheck(oSetUpTarget)) { // Make sure the nearest seen is not in front of the worst AC. - if(GetDistanceToObject(GlobalNearestEnemyHeard) > f4 || - GetDistanceToObject(oSetUpTarget) < f3) + if(GetDistanceToObject(GlobalNearestEnemyHeard) > 4.0 || + GetDistanceToObject(oSetUpTarget) < 3.0) { GlobalMeleeTarget = oSetUpTarget; } @@ -12739,10 +12712,10 @@ int AI_SetUpAllObjects(object oImputBackup) // Do we want to change melee targets? oLastTarget = GetAIObject(AI_LAST_MELEE_TARGET); - // iValid is the counter for attacking target X... - iBreak = GetAIInteger(AI_MELEE_TURNS_ATTACKING); - iBreak++; - SetAIInteger(AI_MELEE_TURNS_ATTACKING, iBreak); + // bValid is the counter for attacking target X... + bBreak = GetAIInteger(AI_MELEE_TURNS_ATTACKING); + bBreak++; + SetAIInteger(AI_MELEE_TURNS_ATTACKING, bBreak); // We set this to 0 if we our oSetUpTarget != GlobalMeleeTarget below changing. // Check % @@ -12751,11 +12724,12 @@ int AI_SetUpAllObjects(object oImputBackup) // - No valid override target if(!GetIsObjectValid(GlobalMeleeTarget) && - (AI_GetTargetSanityCheck(oLastTarget) || // Sanity check (dead, valid, ETC) - // And must pass a % roll - d100() <= GetBoundriedAIInteger(AI_MELEE_LAST_TO_NEW_TARGET_CHANCE, i20, i100) || - // OR last target attacked for X rounds - iBreak >= iMaxTurnsAttackingX)) + // 1. If the last target isn't a sane target... + (!AI_GetTargetSanityCheck(oLastTarget) || + // 2. ...Or must pass a % roll to change (or check for new) targets... + d100() <= GetBoundriedAIInteger(AI_MELEE_LAST_TO_NEW_TARGET_CHANCE, 20, 100) || + // 3. ...OR last target attacked for X rounds we limit ourselves to. + bBreak >= nMaxTurnsAttackingX)) { // Loop targets, ETC, and get GlobalMeleeTarget normally. // Set up melee = ARRAY_MELEE_ENEMY @@ -12767,62 +12741,62 @@ int AI_SetUpAllObjects(object oImputBackup) // 1. Nearby SEEN enemies. Obviously nearest to furthest! // IE the maximum and minimum targets for the range checking. - iMinimum = GetBoundriedAIInteger(TARGETING_RANGE + MINIMUM, i2, i40, i1); - iMaximum = GetBoundriedAIInteger(TARGETING_RANGE + MAXIMUM, i8, i40, i1); + nMinimum = GetBoundriedAIInteger(TARGETING_RANGE + MINIMUM, 2, 40, 1); + nMaximum = GetBoundriedAIInteger(TARGETING_RANGE + MAXIMUM, 8, 40, 1); // fSetMaxWeCanGoTo = Maximum range away from us (GetDistanceToObject) that // we can go to. This is increased if we have tumble (compared to level) or // spring attack is king :-D - fSetMaxWeCanGoTo = GlobalOurReach + f1;// Have 1 extra as well + fSetMaxWeCanGoTo = GlobalOurReach + 1.0;// Have 1 extra as well // We add a lot for spring attack - 3d4 (3 to 12) // OR we have 13+ (IE a very high chance of suceeding) in tumble - if(GetHasFeat(FEAT_SPRING_ATTACK) || GetSkillRank(SKILL_TUMBLE) >= i13) + if(GetHasFeat(FEAT_SPRING_ATTACK) || GetSkillRank(SKILL_TUMBLE) >= 13) { - fSetMaxWeCanGoTo += IntToFloat(d4(i3)); + fSetMaxWeCanGoTo += IntToFloat(d4(3)); } else if(GetHasSkill(SKILL_TUMBLE)) { // Else we add some for tumble - iBreak = GetSkillRank(SKILL_TUMBLE) - GlobalOurHitDice; - if(iBreak > FALSE) + bBreak = GetSkillRank(SKILL_TUMBLE) - GlobalOurHitDice; + if(bBreak > FALSE) { // * Basis of Skill Rank - Our Hit Dice. 5 tumble on a level 2 makes +3M Range. - fSetMaxWeCanGoTo += IntToFloat(iBreak); + fSetMaxWeCanGoTo += IntToFloat(bBreak); } } - iBreak = FALSE; + bBreak = FALSE; // Start loop from array based on range. // - Use seen array! // - Break if we have added enough targets to our array. - iRemainingTargets = FALSE; - iCnt = i1; - sCnt = IntToString(iCnt); + nRemainingTargets = FALSE; + nCnt = 1; + sCnt = IntToString(nCnt); oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + sCnt); - while(GetIsObjectValid(oSetUpTarget) && iRemainingTargets < iMaximum) + while(GetIsObjectValid(oSetUpTarget) && nRemainingTargets < nMaximum) { // If seen, we check range... fCurrentRange = GetLocalFloat(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + sCnt); // We start from the closest, so we need to cancle those out which // are too far away. // we check if it is in our reach. If so, we add it. - if(fCurrentRange < fSetMaxWeCanGoTo || iRemainingTargets < iMinimum) + if(fCurrentRange < fSetMaxWeCanGoTo || nRemainingTargets < nMinimum) { - iRemainingTargets++; - sCnt = IntToString(iRemainingTargets); + nRemainingTargets++; + sCnt = IntToString(nRemainingTargets); SetLocalObject(OBJECT_SELF, ARRAY_MELEE_ENEMY + sCnt, oSetUpTarget); SetLocalFloat(OBJECT_SELF, ARRAY_MELEE_ENEMY + sCnt, fCurrentRange); } // Get next nearest SEEN - iCnt++; - sCnt = IntToString(iCnt); + nCnt++; + sCnt = IntToString(nCnt); oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + sCnt); } // 1a. If not valid, just use nearest seen if valid - if(!iRemainingTargets && GlobalValidNearestSeenEnemy) + if(!nRemainingTargets && GlobalValidNearestSeenEnemy) { - iRemainingTargets = i1; - SetLocalObject(OBJECT_SELF, ARRAY_MELEE_ENEMY + s1, GlobalNearestEnemySeen); - SetLocalFloat(OBJECT_SELF, ARRAY_MELEE_ENEMY + s1, GetDistanceToObject(GlobalNearestEnemySeen)); + nRemainingTargets = 1; + SetLocalObject(OBJECT_SELF, ARRAY_MELEE_ENEMY + "1", GlobalNearestEnemySeen); + SetLocalFloat(OBJECT_SELF, ARRAY_MELEE_ENEMY + "1", GetDistanceToObject(GlobalNearestEnemySeen)); } else { @@ -12830,56 +12804,56 @@ int AI_SetUpAllObjects(object oImputBackup) // SEEN OR we have no nearest seen. // Check if we have no seen objects set, or the nearest heard is nearer then the futhest seen by 4M fCurrentRange = GetDistanceToObject(GlobalNearestEnemyHeard); - if(GlobalValidNearestHeardEnemy && (!iRemainingTargets || + if(GlobalValidNearestHeardEnemy && (!nRemainingTargets || // Range to nearest heard is nearer then the melee enemy - (fCurrentRange > f0 && ((fCurrentRange + f4) < + (fCurrentRange > 0.0 && ((fCurrentRange + 4.0) < // Nearest melee range enemy we've set to seen - GetLocalFloat(OBJECT_SELF, ARRAY_MELEE_ENEMY + s1))))) + GetLocalFloat(OBJECT_SELF, ARRAY_MELEE_ENEMY + "1"))))) { // - We half the amount we need for this range check // Maximum - iMaximum /= i2; - if(iMaximum < i1) iMaximum = i1; + nMaximum /= 2; + if(nMaximum < 1) nMaximum = 1; // Minimum - iMinimum /= i2; - if(iMinimum < i1) iMinimum = i1; + nMinimum /= 2; + if(nMinimum < 1) nMinimum = 1; // Start loop from array based on range. Overrides exsisting targets // - Use heard enemy array. - iCnt = i1; - iRemainingTargets = FALSE; - sCnt = IntToString(iCnt); + nCnt = 1; + nRemainingTargets = FALSE; + sCnt = IntToString(nCnt); oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_HEARD + sCnt); - while(GetIsObjectValid(oSetUpTarget) && iRemainingTargets < iMaximum) + while(GetIsObjectValid(oSetUpTarget) && nRemainingTargets < nMaximum) { // If seen, we check range... fCurrentRange = GetLocalFloat(OBJECT_SELF, ARRAY_ENEMY_RANGE_HEARD + sCnt); // We start from the closest, so we need to cancle those out which // are too far away. - if(fCurrentRange < fSetMaxWeCanGoTo || iRemainingTargets < iMinimum) + if(fCurrentRange < fSetMaxWeCanGoTo || nRemainingTargets < nMinimum) { - iRemainingTargets++; - sCnt = IntToString(iRemainingTargets); + nRemainingTargets++; + sCnt = IntToString(nRemainingTargets); SetLocalObject(OBJECT_SELF, ARRAY_MELEE_ENEMY + sCnt, oSetUpTarget); SetLocalFloat(OBJECT_SELF, ARRAY_MELEE_ENEMY + sCnt, fCurrentRange); } // Get next HEARD - iCnt++; - sCnt = IntToString(iCnt); + nCnt++; + sCnt = IntToString(nCnt); oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_HEARD + sCnt); } } } // Now, do we have any Melee Targets? - if(!iRemainingTargets) + if(!nRemainingTargets) { // If not, what can we use? - // - We use the imputted target! + // - We use the Inputted target! // - We use anyone who allies are attacking! // - We use anyone we hear! - // Imputted target (EG last attack that GetObjectSeen doesn't return + // Inputted target (EG last attack that GetObjectSeen doesn't return // for). - oSetUpTarget = oImputBackUpToAttack; + oSetUpTarget = oInputBackUpToAttack; if(!GetIsObjectValid(oSetUpTarget)) { // Anyone we hear @@ -12887,23 +12861,21 @@ int AI_SetUpAllObjects(object oImputBackup) if(!GetIsObjectValid(oSetUpTarget)) { // We get who our allies are attacking - iCnt = i1; - oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE + IntToString(iCnt)); - while(GetIsObjectValid(oSetUpTarget) && iBreak != TRUE) + nCnt = 1; + oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE + IntToString(nCnt)); + while(GetIsObjectValid(oSetUpTarget) && bBreak != TRUE) { // Get the allies attack target. If valid, attack it! oTempLoopObject = GetAttackTarget(oSetUpTarget); - if(GetIsObjectValid(oTempLoopObject) && - !GetFactionEqual(oTempLoopObject) && - !GetIsFriend(oTempLoopObject)) + if(AI_GetTargetSanityCheck(oTempLoopObject)) { oSetUpTarget = oTempLoopObject; - iBreak = TRUE; + bBreak = TRUE; } else { - iCnt++; - oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE + IntToString(iCnt)); + nCnt++; + oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ALLIES_RANGE + IntToString(nCnt)); } } // Don't attack anyone we got in the loop, of course. @@ -12935,11 +12907,11 @@ int AI_SetUpAllObjects(object oImputBackup) return FALSE; } // If only one, choose it - else if(iRemainingTargets == i1) + else if(nRemainingTargets == 1) { - GlobalMeleeTarget = GetLocalObject(OBJECT_SELF, ARRAY_MELEE_ENEMY + s1); + GlobalMeleeTarget = GetLocalObject(OBJECT_SELF, ARRAY_MELEE_ENEMY + "1"); } - else //if(iRemainingTargets > i1) + else //if(nRemainingTargets > 1) { // If we have any set targets (heard/seen ones) then we // will reduce the amount by AC, HP (current Percent/max/current) @@ -12965,121 +12937,121 @@ int AI_SetUpAllObjects(object oImputBackup) { // We normally get the nearest enemy who is not attacking us, and // actually stop! - AI_TargetingArrayIntegerStore(i9, ARRAY_MELEE_ENEMY); + AI_TargetingArrayIntegerStore(9, ARRAY_MELEE_ENEMY); // Get the closest who isn't attacking us. - oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_TEMP_ARRAY + s1); + oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_TEMP_ARRAY + "1"); if(GetAttackTarget(oSetUpTarget) != OBJECT_SELF) { GlobalMeleeTarget = oSetUpTarget; - iRemainingTargets = FALSE; + nRemainingTargets = FALSE; } // If we have trouble using that one, IE they are attacking us, we // just use normal methods. } // 1. AC - iMinimum = GetAIInteger(TARGETING_AC + MINIMUM); + nMinimum = GetAIInteger(TARGETING_AC + MINIMUM); // Do we do AC? And over one target... - // - iCnt2 is the total target stored in the last array. - if(iMinimum && iRemainingTargets >= i2) + // - nCnt2 is the total target stored in the last array. + if(nMinimum && nRemainingTargets >= 2) { // If so, is it lowest or highest? - iTypeOfTarget = GetAIInteger(TARGETING_AC); - iMaximum = GetAIInteger(TARGETING_AC + MAXIMUM); + nTypeOfTarget = GetAIInteger(TARGETING_AC); + nMaximum = GetAIInteger(TARGETING_AC + MAXIMUM); // We then set the array up in a new temp array. 1 = AC. - AI_TargetingArrayIntegerStore(i1, ARRAY_MELEE_ENEMY); + AI_TargetingArrayIntegerStore(1, ARRAY_MELEE_ENEMY); // We loop through all the targets in the temp array (we also // delete the temp array targets!) and set what ones we want to target // based on AC. - // - Continue until iMinimum is reached. - // - Never go over iMaximum - // - After iMinimum we make sure the AC differences is not a major one of + // - Continue until nMinimum is reached. + // - Never go over nMaximum + // - After nMinimum we make sure the AC differences is not a major one of // over 5. - iRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_MELEE_ENEMY, iTypeOfTarget, i5, iMinimum, iMaximum); + nRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_MELEE_ENEMY, nTypeOfTarget, 5, nMinimum, nMaximum); } // Most others are similar (and all integer values so easy to check) // 2. Phisical protections. - iMinimum = GetAIInteger(TARGETING_PHISICALS + MINIMUM); - if(iMinimum && iRemainingTargets >= i2) + nMinimum = GetAIInteger(TARGETING_PHISICALS + MINIMUM); + if(nMinimum && nRemainingTargets >= 2) { // If so, is it lowest or highest? - iTypeOfTarget = GetAIInteger(TARGETING_PHISICALS); - iMaximum = GetAIInteger(TARGETING_PHISICALS + MAXIMUM); + nTypeOfTarget = GetAIInteger(TARGETING_PHISICALS); + nMaximum = GetAIInteger(TARGETING_PHISICALS + MAXIMUM); // We then set the array up in a new temp array. 3 = phisicals. - AI_TargetingArrayIntegerStore(i3, ARRAY_MELEE_ENEMY); + AI_TargetingArrayIntegerStore(3, ARRAY_MELEE_ENEMY); // We loop as AC, basically. As it is stored based on the amount // of DR offered, we set the limit to 6, so if everyone had // 0 DR, and 1 had 5, it'd add the 5 for the hell of it. If everyone // had 20, and one had 25 it'd take the 25 too, but not a 30. - iRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_MELEE_ENEMY, iTypeOfTarget, i6, iMinimum, iMaximum); + nRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_MELEE_ENEMY, nTypeOfTarget, 6, nMinimum, nMaximum); } // 4. BAB - iMinimum = GetAIInteger(TARGETING_BAB + MINIMUM); - if(iMinimum && iRemainingTargets >= i2) + nMinimum = GetAIInteger(TARGETING_BAB + MINIMUM); + if(nMinimum && nRemainingTargets >= 2) { // If so, is it lowest or highest? - iTypeOfTarget = GetAIInteger(TARGETING_BAB); - iMaximum = GetAIInteger(TARGETING_BAB + MAXIMUM); + nTypeOfTarget = GetAIInteger(TARGETING_BAB); + nMaximum = GetAIInteger(TARGETING_BAB + MAXIMUM); // We then set the array up in a new temp array. 4 = BAB - AI_TargetingArrayIntegerStore(i4, ARRAY_MELEE_ENEMY); + AI_TargetingArrayIntegerStore(4, ARRAY_MELEE_ENEMY); // We loop as AC, basically. As it is BAB, IE how much chance // they'll hit us (they might all hit on a 20, but it also shows // who are the best fighters!). Set to 5, like AC. - iRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_MELEE_ENEMY, iTypeOfTarget, i5, iMinimum, iMaximum); + nRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_MELEE_ENEMY, nTypeOfTarget, 5, nMinimum, nMaximum); } // 5. Hit Dice - iMinimum = GetAIInteger(TARGETING_HITDICE + MINIMUM); - if(iMinimum && iRemainingTargets >= i2) + nMinimum = GetAIInteger(TARGETING_HITDICE + MINIMUM); + if(nMinimum && nRemainingTargets >= 2) { // If so, is it lowest or highest? - iTypeOfTarget = GetAIInteger(TARGETING_HITDICE); - iMaximum = GetAIInteger(TARGETING_HITDICE + MAXIMUM); + nTypeOfTarget = GetAIInteger(TARGETING_HITDICE); + nMaximum = GetAIInteger(TARGETING_HITDICE + MAXIMUM); // We then set the array up in a new temp array. 5 = Hit dice - AI_TargetingArrayIntegerStore(i5, ARRAY_MELEE_ENEMY); + AI_TargetingArrayIntegerStore(5, ARRAY_MELEE_ENEMY); // We loop as AC. Hit Dice is even easier. We set the limit to // a max of 4. - iRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_MELEE_ENEMY, iTypeOfTarget, i4, iMinimum, iMaximum); + nRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_MELEE_ENEMY, nTypeOfTarget, 4, nMinimum, nMaximum); } // 6. Percent HP - iMinimum = GetAIInteger(TARGETING_HP_PERCENT + MINIMUM); - if(iMinimum && iRemainingTargets >= i2) + nMinimum = GetAIInteger(TARGETING_HP_PERCENT + MINIMUM); + if(nMinimum && nRemainingTargets >= 2) { // If so, is it lowest or highest? - iTypeOfTarget = GetAIInteger(TARGETING_HP_PERCENT); - iMaximum = GetAIInteger(TARGETING_HP_PERCENT + MAXIMUM); + nTypeOfTarget = GetAIInteger(TARGETING_HP_PERCENT); + nMaximum = GetAIInteger(TARGETING_HP_PERCENT + MAXIMUM); // We then set the array up in a new temp array. 6 = % - AI_TargetingArrayIntegerStore(i6, ARRAY_MELEE_ENEMY); + AI_TargetingArrayIntegerStore(6, ARRAY_MELEE_ENEMY); // We loop as AC. Current Hit Points are easy, and are done // by %ages. We set the % to 15 difference max. - iRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_MELEE_ENEMY, iTypeOfTarget, i15, iMinimum, iMaximum); + nRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_MELEE_ENEMY, nTypeOfTarget, 15, nMinimum, nMaximum); } // 7. Current HP - iMinimum = GetAIInteger(TARGETING_HP_CURRENT + MINIMUM); - if(iMinimum && iRemainingTargets >= i2) + nMinimum = GetAIInteger(TARGETING_HP_CURRENT + MINIMUM); + if(nMinimum && nRemainingTargets >= 2) { // If so, is it lowest or highest? - iTypeOfTarget = GetAIInteger(TARGETING_HP_CURRENT); - iMaximum = GetAIInteger(TARGETING_HP_CURRENT + MAXIMUM); + nTypeOfTarget = GetAIInteger(TARGETING_HP_CURRENT); + nMaximum = GetAIInteger(TARGETING_HP_CURRENT + MAXIMUM); // We then set the array up in a new temp array. 7 = current HP - AI_TargetingArrayIntegerStore(i7, ARRAY_MELEE_ENEMY); + AI_TargetingArrayIntegerStore(7, ARRAY_MELEE_ENEMY); // We loop as AC. Current Hit points? Well, we set this limit to // Our Hit Dice * 2. - iRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_MELEE_ENEMY, iTypeOfTarget, GlobalOurHitDice * i2, iMinimum, iMaximum); + nRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_MELEE_ENEMY, nTypeOfTarget, GlobalOurHitDice * 2, nMinimum, nMaximum); } // 8. Maximum HP - iMinimum = GetAIInteger(TARGETING_HP_MAXIMUM + MINIMUM); - if(iMinimum && iRemainingTargets >= i2) + nMinimum = GetAIInteger(TARGETING_HP_MAXIMUM + MINIMUM); + if(nMinimum && nRemainingTargets >= 2) { // If so, is it lowest or highest? - iTypeOfTarget = GetAIInteger(TARGETING_HP_MAXIMUM); - iMaximum = GetAIInteger(TARGETING_HP_MAXIMUM + MAXIMUM); + nTypeOfTarget = GetAIInteger(TARGETING_HP_MAXIMUM); + nMaximum = GetAIInteger(TARGETING_HP_MAXIMUM + MAXIMUM); // We then set the array up in a new temp array. 8 = maximum - AI_TargetingArrayIntegerStore(i8, ARRAY_MELEE_ENEMY); + AI_TargetingArrayIntegerStore(8, ARRAY_MELEE_ENEMY); // We loop as AC. Max hit Hit points? Well, we set this limit to // Our Hit Dice * 3. - iRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_MELEE_ENEMY, iTypeOfTarget, GlobalOurHitDice * i3, iMinimum, iMaximum); + nRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_MELEE_ENEMY, nTypeOfTarget, GlobalOurHitDice * 3, nMinimum, nMaximum); } // WHEW! // Now we should have 1 or more chosen targets in ARRAY_MELEE_ARRAY. @@ -13087,23 +13059,24 @@ int AI_SetUpAllObjects(object oImputBackup) // one, or the first one if there is only one :-D // If only one, choose it - if(iRemainingTargets == i1) + if(nRemainingTargets == 1) { - GlobalMeleeTarget = GetLocalObject(OBJECT_SELF, ARRAY_MELEE_ENEMY + s1); + GlobalMeleeTarget = GetLocalObject(OBJECT_SELF, ARRAY_MELEE_ENEMY + "1"); } // Check for 2+, if 0, we haven't got one to set! - else if(iRemainingTargets >= i2) + else if(nRemainingTargets >= 2) { // Else Roll dice - iCnt = Random(iRemainingTargets) + i1; + nCnt = Random(nRemainingTargets) + 1; // Set random target - GlobalMeleeTarget = GetLocalObject(OBJECT_SELF, ARRAY_MELEE_ENEMY + IntToString(iCnt)); + GlobalMeleeTarget = GetLocalObject(OBJECT_SELF, ARRAY_MELEE_ENEMY + IntToString(nCnt)); } } } - // Else, it is oLastTarget that will be our target - else + // Else, it is oLastTarget that will be our target, if a sane target! + else if(AI_GetTargetSanityCheck(oLastTarget)) { + // Only set this if oLastTarget is valid. It might not be. Thanks Chris (1.4 fix) GlobalMeleeTarget = oLastTarget; } @@ -13124,62 +13097,62 @@ int AI_SetUpAllObjects(object oImputBackup) // Do we want to change melee targets? oLastTarget = GetAIObject(AI_LAST_RANGED_TARGET); - // iValid is the counter for attacking target X... - iBreak = GetAIInteger(AI_RANGED_TURNS_ATTACKING); - iBreak++; - SetAIInteger(AI_RANGED_TURNS_ATTACKING, iBreak); + // bValid is the counter for attacking target X... + bBreak = GetAIInteger(AI_RANGED_TURNS_ATTACKING); + bBreak++; + SetAIInteger(AI_RANGED_TURNS_ATTACKING, bBreak); // We set this to 0 if we our oLastTarget != GlobalMeleeTarget below changing. // Check % // We use the same temp reset from before, because phisical attacking // would be range or melee ;-) - // - Hey, do we even have a ranged weapon? - // - No valid override target - // - No valid override target + + // - No valid override target, we have got a ranged weapon... if(!GetIsObjectValid(GlobalRangedTarget) && GetIsObjectValid(GetAIObject(AI_WEAPON_RANGED)) && - (AI_GetTargetSanityCheck(oLastTarget) || // Sanity check (dead, valid, ETC) - // And must pass a % roll - d100() <= GetBoundriedAIInteger(AI_RANGED_LAST_TO_NEW_TARGET_CHANCE, i20, i100) || - // OR last target attacked for X rounds - iBreak >= iMaxTurnsAttackingX)) + // 1. If the last target isn't a sane target... + (!AI_GetTargetSanityCheck(oLastTarget) || + // 2. ...Or must pass a % roll to change (or check for new) targets... + d100() <= GetBoundriedAIInteger(AI_RANGED_LAST_TO_NEW_TARGET_CHANCE, 20, 100) || + // 3. ...OR last target attacked for X rounds we limit ourselves to. + bBreak >= nMaxTurnsAttackingX)) { // 1. Set up all seen, else all heard, to the range array. - iCnt = i1; - iRemainingTargets = i0; - oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(iCnt)); + nCnt = 1; + nRemainingTargets = 0; + oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(nCnt)); while(GetIsObjectValid(oSetUpTarget)) { - iRemainingTargets++; - SetLocalObject(OBJECT_SELF, ARRAY_RANGED_ENEMY + IntToString(iRemainingTargets), oSetUpTarget); + nRemainingTargets++; + SetLocalObject(OBJECT_SELF, ARRAY_RANGED_ENEMY + IntToString(nRemainingTargets), oSetUpTarget); // Get Next seen - iCnt++; - oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(iCnt)); + nCnt++; + oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(nCnt)); } // If we don't have any seen, used heard. - if(!iRemainingTargets) + if(!nRemainingTargets) { - iCnt = i1; - iRemainingTargets = i0; - oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_HEARD + IntToString(iCnt)); + nCnt = 1; + nRemainingTargets = 0; + oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_HEARD + IntToString(nCnt)); while(GetIsObjectValid(oSetUpTarget)) { - iRemainingTargets++; - SetLocalObject(OBJECT_SELF, ARRAY_RANGED_ENEMY + IntToString(iRemainingTargets), oSetUpTarget); + nRemainingTargets++; + SetLocalObject(OBJECT_SELF, ARRAY_RANGED_ENEMY + IntToString(nRemainingTargets), oSetUpTarget); // Get Next seen - iCnt++; - oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_HEARD + IntToString(iCnt)); + nCnt++; + oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_HEARD + IntToString(nCnt)); } } // If not valid, set to melee target at the end - // Do we have exactly 1 target? (iRemainingTargets == 1) - if(iRemainingTargets == i1) + // Do we have exactly 1 target? (nRemainingTargets == 1) + if(nRemainingTargets == 1) { // Then we make this our target and end it. - GlobalRangedTarget = GetLocalObject(OBJECT_SELF, ARRAY_RANGED_ENEMY + s1); + GlobalRangedTarget = GetLocalObject(OBJECT_SELF, ARRAY_RANGED_ENEMY + "1"); } // Else we set up using range ETC, if we have more then 1. - else if(iRemainingTargets) + else if(nRemainingTargets) { // Range - they are already in range order. As it is used for // spells, it uses the same function. @@ -13198,14 +13171,14 @@ int AI_SetUpAllObjects(object oImputBackup) { // We normally get the nearest enemy who is not attacking us, and // actually stop! - AI_TargetingArrayIntegerStore(i9, ARRAY_RANGED_ENEMY); + AI_TargetingArrayIntegerStore(9, ARRAY_RANGED_ENEMY); // Get the closest who isn't attacking us. - oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_TEMP_ARRAY + s1); + oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_TEMP_ARRAY + "1"); if(GetAttackTarget(oSetUpTarget) != OBJECT_SELF) { GlobalMeleeTarget = oSetUpTarget; - iRemainingTargets = FALSE; + nRemainingTargets = FALSE; } // If we have trouble using that one, IE they are attacking us, we // just use normal methods. @@ -13213,149 +13186,151 @@ int AI_SetUpAllObjects(object oImputBackup) // Delete temp array AI_TargetingArrayDelete(ARRAY_TEMP_ARRAY); } - iMinimum = GetAIInteger(TARGETING_RANGE + MINIMUM); + nMinimum = GetAIInteger(TARGETING_RANGE + MINIMUM); // 1. Do we do range? - if(iMinimum && iRemainingTargets >= i2) + if(nMinimum && nRemainingTargets >= 2) { // If so, is it lowest or highest? - iTypeOfTarget = GetAIInteger(TARGETING_RANGE); - iMaximum = GetAIInteger(TARGETING_RANGE + MAXIMUM); + nTypeOfTarget = GetAIInteger(TARGETING_RANGE); + nMaximum = GetAIInteger(TARGETING_RANGE + MAXIMUM); // We then set the array up in a new temp array. AI_TargetingArrayDistanceStore(ARRAY_RANGED_ENEMY, ARRAY_TEMP_ARRAY); // We loop range. Maximum one can be from another when got to the // minimum is 5.0 M - iRemainingTargets = AI_TargetingArrayLimitTargetsFloat(ARRAY_RANGED_ENEMY, iTypeOfTarget, f5, iMinimum, iMaximum); + nRemainingTargets = AI_TargetingArrayLimitTargetsFloat(ARRAY_RANGED_ENEMY, nTypeOfTarget, 5.0, nMinimum, nMaximum); } // 2. AC - iMinimum = GetAIInteger(TARGETING_AC + MINIMUM); + nMinimum = GetAIInteger(TARGETING_AC + MINIMUM); // Do we do AC? And over one target... - if(iMinimum && iRemainingTargets >= i2) + if(nMinimum && nRemainingTargets >= 2) { // If so, is it lowest or highest? - iTypeOfTarget = GetAIInteger(TARGETING_AC); - iMaximum = GetAIInteger(TARGETING_AC + MAXIMUM); + nTypeOfTarget = GetAIInteger(TARGETING_AC); + nMaximum = GetAIInteger(TARGETING_AC + MAXIMUM); // We then set the array up in a new temp array. 1 = AC. - AI_TargetingArrayIntegerStore(i1, ARRAY_RANGED_ENEMY); + AI_TargetingArrayIntegerStore(1, ARRAY_RANGED_ENEMY); // We loop through all the targets in the temp array (we also // delete the temp array targets!) and set what ones we want to target // based on AC. - // - Continue until iMinimum is reached. - // - Never go over iMaximum - // - After iMinimum we make sure the AC differences is not a major one of + // - Continue until nMinimum is reached. + // - Never go over nMaximum + // - After nMinimum we make sure the AC differences is not a major one of // over 5. - iRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_RANGED_ENEMY, iTypeOfTarget, i5, iMinimum, iMaximum); + nRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_RANGED_ENEMY, nTypeOfTarget, 5, nMinimum, nMaximum); } // Most others are similar (and all integer values so easy to check) // 3. Phisical protections. - iMinimum = GetAIInteger(TARGETING_PHISICALS + MINIMUM); - if(iMinimum && iRemainingTargets >= i2) + nMinimum = GetAIInteger(TARGETING_PHISICALS + MINIMUM); + if(nMinimum && nRemainingTargets >= 2) { // If so, is it lowest or highest? - iTypeOfTarget = GetAIInteger(TARGETING_PHISICALS); - iMaximum = GetAIInteger(TARGETING_PHISICALS + MAXIMUM); + nTypeOfTarget = GetAIInteger(TARGETING_PHISICALS); + nMaximum = GetAIInteger(TARGETING_PHISICALS + MAXIMUM); // We then set the array up in a new temp array. 3 = phisicals. - AI_TargetingArrayIntegerStore(i3, ARRAY_RANGED_ENEMY); + AI_TargetingArrayIntegerStore(3, ARRAY_RANGED_ENEMY); // We loop as AC, basically. As it is stored based on the amount // of DR offered, limit is 0, not 6. Can't be any different. - iRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_RANGED_ENEMY, iTypeOfTarget, i0, iMinimum, iMaximum); + nRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_RANGED_ENEMY, nTypeOfTarget, 0, nMinimum, nMaximum); } // 4. BAB - iMinimum = GetAIInteger(TARGETING_BAB + MINIMUM); - if(iMinimum && iRemainingTargets >= i2) + nMinimum = GetAIInteger(TARGETING_BAB + MINIMUM); + if(nMinimum && nRemainingTargets >= 2) { // If so, is it lowest or highest? - iTypeOfTarget = GetAIInteger(TARGETING_BAB); - iMaximum = GetAIInteger(TARGETING_BAB + MAXIMUM); + nTypeOfTarget = GetAIInteger(TARGETING_BAB); + nMaximum = GetAIInteger(TARGETING_BAB + MAXIMUM); // We then set the array up in a new temp array. 4 = BAB - AI_TargetingArrayIntegerStore(i4, ARRAY_RANGED_ENEMY); + AI_TargetingArrayIntegerStore(4, ARRAY_RANGED_ENEMY); // We loop as AC, basically. As it is BAB, IE how much chance // they'll hit us (they might all hit on a 20, but it also shows // who are the best fighters!). Set to 5, like AC. - iRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_RANGED_ENEMY, iTypeOfTarget, i5, iMinimum, iMaximum); + nRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_RANGED_ENEMY, nTypeOfTarget, 5, nMinimum, nMaximum); } // 5. Hit Dice - iMinimum = GetAIInteger(TARGETING_HITDICE + MINIMUM); - if(iMinimum && iRemainingTargets >= i2) + nMinimum = GetAIInteger(TARGETING_HITDICE + MINIMUM); + if(nMinimum && nRemainingTargets >= 2) { // If so, is it lowest or highest? - iTypeOfTarget = GetAIInteger(TARGETING_HITDICE); - iMaximum = GetAIInteger(TARGETING_HITDICE + MAXIMUM); + nTypeOfTarget = GetAIInteger(TARGETING_HITDICE); + nMaximum = GetAIInteger(TARGETING_HITDICE + MAXIMUM); // We then set the array up in a new temp array. 5 = Hit dice - AI_TargetingArrayIntegerStore(i5, ARRAY_RANGED_ENEMY); + AI_TargetingArrayIntegerStore(5, ARRAY_RANGED_ENEMY); // We loop as AC. Hit Dice is even easier. We set the limit to // a max of 4. - iRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_RANGED_ENEMY, iTypeOfTarget, i4, iMinimum, iMaximum); + nRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_RANGED_ENEMY, nTypeOfTarget, 4, nMinimum, nMaximum); } // 6. Percent HP - iMinimum = GetAIInteger(TARGETING_HP_PERCENT + MINIMUM); - if(iMinimum && iRemainingTargets >= i2) + nMinimum = GetAIInteger(TARGETING_HP_PERCENT + MINIMUM); + if(nMinimum && nRemainingTargets >= 2) { // If so, is it lowest or highest? - iTypeOfTarget = GetAIInteger(TARGETING_HP_PERCENT); - iMaximum = GetAIInteger(TARGETING_HP_PERCENT + MAXIMUM); + nTypeOfTarget = GetAIInteger(TARGETING_HP_PERCENT); + nMaximum = GetAIInteger(TARGETING_HP_PERCENT + MAXIMUM); // We then set the array up in a new temp array. 5 = Hit dice - AI_TargetingArrayIntegerStore(i6, ARRAY_RANGED_ENEMY); + AI_TargetingArrayIntegerStore(6, ARRAY_RANGED_ENEMY); // We loop as AC. Current Hit Points are easy, and are done // by %ages. We set the % to 15 difference max. - iRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_RANGED_ENEMY, iTypeOfTarget, i15, iMinimum, iMaximum); + nRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_RANGED_ENEMY, nTypeOfTarget, 15, nMinimum, nMaximum); } // 7. Current HP - iMinimum = GetAIInteger(TARGETING_HP_CURRENT + MINIMUM); - if(iMinimum && iRemainingTargets >= i2) + nMinimum = GetAIInteger(TARGETING_HP_CURRENT + MINIMUM); + if(nMinimum && nRemainingTargets >= 2) { // If so, is it lowest or highest? - iTypeOfTarget = GetAIInteger(TARGETING_HP_CURRENT); - iMaximum = GetAIInteger(TARGETING_HP_CURRENT + MAXIMUM); + nTypeOfTarget = GetAIInteger(TARGETING_HP_CURRENT); + nMaximum = GetAIInteger(TARGETING_HP_CURRENT + MAXIMUM); // We then set the array up in a new temp array. 5 = Hit dice - AI_TargetingArrayIntegerStore(i7, ARRAY_RANGED_ENEMY); + AI_TargetingArrayIntegerStore(7, ARRAY_RANGED_ENEMY); // We loop as AC. Current Hit points? Well, we set this limit to // Our Hit Dice * 2. - iRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_RANGED_ENEMY, iTypeOfTarget, GlobalOurHitDice * i2, iMinimum, iMaximum); + nRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_RANGED_ENEMY, nTypeOfTarget, GlobalOurHitDice * 2, nMinimum, nMaximum); } // 8. Maximum HP - iMinimum = GetAIInteger(TARGETING_HP_MAXIMUM + MINIMUM); - if(iMinimum && iRemainingTargets >= i2) + nMinimum = GetAIInteger(TARGETING_HP_MAXIMUM + MINIMUM); + if(nMinimum && nRemainingTargets >= 2) { // If so, is it lowest or highest? - iTypeOfTarget = GetAIInteger(TARGETING_HP_MAXIMUM); - iMaximum = GetAIInteger(TARGETING_HP_MAXIMUM + MAXIMUM); + nTypeOfTarget = GetAIInteger(TARGETING_HP_MAXIMUM); + nMaximum = GetAIInteger(TARGETING_HP_MAXIMUM + MAXIMUM); // We then set the array up in a new temp array. 5 = Hit dice - AI_TargetingArrayIntegerStore(i8, ARRAY_RANGED_ENEMY); + AI_TargetingArrayIntegerStore(8, ARRAY_RANGED_ENEMY); // We loop as AC. Max hit Hit points? Well, we set this limit to // Our Hit Dice * 3. - iRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_RANGED_ENEMY, iTypeOfTarget, GlobalOurHitDice * i3, iMinimum, iMaximum); + nRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_RANGED_ENEMY, nTypeOfTarget, GlobalOurHitDice * 3, nMinimum, nMaximum); } // End narrowing down on ARRAY_RANGED_ENEMY // If only one, choose it - if(iRemainingTargets == i1) + if(nRemainingTargets == 1) { - GlobalRangedTarget = GetLocalObject(OBJECT_SELF, ARRAY_RANGED_ENEMY + s1); + GlobalRangedTarget = GetLocalObject(OBJECT_SELF, ARRAY_RANGED_ENEMY + "1"); } // Check for 2+, if 0, we haven't got one to set! - else if(iRemainingTargets >= i2) + else if(nRemainingTargets >= 2) { // Else Roll dice - iCnt = Random(iRemainingTargets) + i1; + nCnt = Random(nRemainingTargets) + 1; // Set random target - GlobalRangedTarget = GetLocalObject(OBJECT_SELF, ARRAY_RANGED_ENEMY + IntToString(iCnt)); + GlobalRangedTarget = GetLocalObject(OBJECT_SELF, ARRAY_RANGED_ENEMY + IntToString(nCnt)); } } } // Else, it is oLastTarget that will be our target - else + else if(AI_GetTargetSanityCheck(oLastTarget)) { + // Only set this if oLastTarget is valid. It might not be. Thanks Chris (1.4 fix) GlobalRangedTarget = oLastTarget; } - // If not valid, set to melee target - if(!GetIsObjectValid(GlobalRangedTarget)) + // If not valid, set to melee target (Can happen if we have no ranged weapon) + if(!AI_GetTargetSanityCheck(GlobalRangedTarget)) { GlobalRangedTarget = GlobalMeleeTarget; } + // If it is a new target, reset attacking counter to 0 if(GlobalRangedTarget != oLastTarget) { @@ -13375,60 +13350,62 @@ int AI_SetUpAllObjects(object oImputBackup) // Do we want to change melee targets? oLastTarget = GetAIObject(AI_LAST_SPELL_TARGET); - // iValid is the counter for attacking target X... - iBreak = GetAIInteger(AI_SPELL_TURNS_ATTACKING); - iBreak++; - SetAIInteger(AI_SPELL_TURNS_ATTACKING, iBreak); + // bValid is the counter for attacking target X... + bBreak = GetAIInteger(AI_SPELL_TURNS_ATTACKING); + bBreak++; + SetAIInteger(AI_SPELL_TURNS_ATTACKING, bBreak); // We set this to 0 if we our oLastTarget != GlobalMeleeTarget below changing. // - No valid override target - if(!GetIsObjectValid(GlobalSpellTarget) && - (AI_GetTargetSanityCheck(oLastTarget) || // Sanity check (dead, valid, ETC) - // Or the last target was immune to all our spells - GetLocalInt(oLastTarget, AI_SPELL_IMMUNE_LEVEL) >= i9 || - // OR must pass a % roll - d100() <= GetBoundriedAIInteger(AI_SPELL_LAST_TO_NEW_TARGET_CHANCE, i20, i100) || - // OR last target attacked for X rounds - iBreak >= iMaxTurnsAttackingX)) + if(!GetIsObjectValid(GlobalRangedTarget) && + // 1a. If the last target isn't a sane target... + (!AI_GetTargetSanityCheck(oLastTarget) || + // 1b. The last target has an immune level of 9 (we reset targets each possible time + // then) + GetLocalInt(oLastTarget, AI_SPELL_IMMUNE_LEVEL) >= 9 || + // 2. ...Or must pass a % roll to change (or check for new) targets... + d100() <= GetBoundriedAIInteger(AI_SPELL_LAST_TO_NEW_TARGET_CHANCE, 20, 100) || + // 3. ...OR last target attacked for X rounds we limit ourselves to. + bBreak >= nMaxTurnsAttackingX)) { // 1. Set up all seen, else all heard, to the range array. - iCnt = i1; - iRemainingTargets = i0; - oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(iCnt)); + nCnt = 1; + nRemainingTargets = 0; + oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(nCnt)); while(GetIsObjectValid(oSetUpTarget)) { // Totally immune to our spells - ignore! if(!AI_SpellResistanceImmune(oSetUpTarget) && - GetLocalInt(GlobalSpellTarget, AI_SPELL_IMMUNE_LEVEL) < i9) + GetLocalInt(GlobalSpellTarget, AI_SPELL_IMMUNE_LEVEL) < 9) { - iRemainingTargets++; - SetLocalObject(OBJECT_SELF, ARRAY_SPELL_ENEMY + IntToString(iRemainingTargets), oSetUpTarget); + nRemainingTargets++; + SetLocalObject(OBJECT_SELF, ARRAY_SPELL_ENEMY + IntToString(nRemainingTargets), oSetUpTarget); } // Get Next seen - iCnt++; - oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(iCnt)); + nCnt++; + oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(nCnt)); } // If we don't have any seen, used heard. - if(!iRemainingTargets) + if(!nRemainingTargets) { - iCnt = i1; - iRemainingTargets = i0; - oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_HEARD + IntToString(iCnt)); + nCnt = 1; + nRemainingTargets = 0; + oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_HEARD + IntToString(nCnt)); while(GetIsObjectValid(oSetUpTarget)) { // Totally immune to our spells - ignore! if(!AI_SpellResistanceImmune(oSetUpTarget) && - GetLocalInt(GlobalSpellTarget, AI_SPELL_IMMUNE_LEVEL) < i9) + GetLocalInt(GlobalSpellTarget, AI_SPELL_IMMUNE_LEVEL) < 9) { - iRemainingTargets++; - SetLocalObject(OBJECT_SELF, ARRAY_SPELL_ENEMY + IntToString(iRemainingTargets), oSetUpTarget); + nRemainingTargets++; + SetLocalObject(OBJECT_SELF, ARRAY_SPELL_ENEMY + IntToString(nRemainingTargets), oSetUpTarget); } // Get Next seen - iCnt++; - oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_HEARD + IntToString(iCnt)); + nCnt++; + oSetUpTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_HEARD + IntToString(nCnt)); } } - // If not valid, its invalid! As this is the last thing, return iM1. + // If not valid, its invalid! As this is the last thing, return -1. // This CAN happen! // - If we have all targets naturally immune to spells via. spell reistance. // we can set GlobalNormalSpellsNoEffectLevel to 10, below, to stop all spells @@ -13436,14 +13413,14 @@ int AI_SetUpAllObjects(object oImputBackup) // MELEE Targets get checked for LOS, so they should always move // to people we should attack ABOVE - // Do we have exactly 1 target? (iRemainingTargets == 1) - if(iRemainingTargets == i1) + // Do we have exactly 1 target? (nRemainingTargets == 1) + if(nRemainingTargets == 1) { // Then we make this our target and end it. - GlobalSpellTarget = GetLocalObject(OBJECT_SELF, ARRAY_SPELL_ENEMY + s1); + GlobalSpellTarget = GetLocalObject(OBJECT_SELF, ARRAY_SPELL_ENEMY + "1"); } // Else we set up using range ETC, if we have more then 1. - else if(iRemainingTargets > i1) + else if(nRemainingTargets > 1) { // ARRAY_SPELL_ENEMY // Similar to Ranged attacking for range setting :-D @@ -13465,169 +13442,171 @@ int AI_SetUpAllObjects(object oImputBackup) // -1. Is it a PC... // - Type 10 - iMinimum = GetAIInteger(TARGETING_ISPC + MINIMUM); - if(iMinimum && iRemainingTargets >= i2) + nMinimum = GetAIInteger(TARGETING_ISPC + MINIMUM); + if(nMinimum && nRemainingTargets >= 2) { // If so, is it lowest or highest? - iTypeOfTarget = GetAIInteger(TARGETING_ISPC); - iMaximum = GetAIInteger(TARGETING_ISPC + MAXIMUM); + nTypeOfTarget = GetAIInteger(TARGETING_ISPC); + nMaximum = GetAIInteger(TARGETING_ISPC + MAXIMUM); // We then set the array up in a new temp array. 10 = PC. - AI_TargetingArrayIntegerStore(i10, ARRAY_SPELL_ENEMY); + AI_TargetingArrayIntegerStore(10, ARRAY_SPELL_ENEMY); // We loop and set up, with no difference in PC status, IE we should always choose those who are PCs. - iRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_SPELL_ENEMY, iTypeOfTarget, i0, iMinimum, iMaximum); + nRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_SPELL_ENEMY, nTypeOfTarget, 0, nMinimum, nMaximum); } // 0. Mantals // - Type 10 - iMinimum = GetAIInteger(TARGETING_ISPC + MINIMUM); - if(iMinimum && iRemainingTargets >= i2) + nMinimum = GetAIInteger(TARGETING_ISPC + MINIMUM); + if(nMinimum && nRemainingTargets >= 2) { // If so, is it lowest or highest? - iTypeOfTarget = GetAIInteger(TARGETING_ISPC); - iMaximum = GetAIInteger(TARGETING_ISPC + MAXIMUM); + nTypeOfTarget = GetAIInteger(TARGETING_ISPC); + nMaximum = GetAIInteger(TARGETING_ISPC + MAXIMUM); // We then set the array up in a new temp array. 10 = PC. - AI_TargetingArrayIntegerStore(i10, ARRAY_SPELL_ENEMY); + AI_TargetingArrayIntegerStore(10, ARRAY_SPELL_ENEMY); // We loop and set up, with no difference in PC status, IE we should always choose those who are PCs. - iRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_SPELL_ENEMY, iTypeOfTarget, i0, iMinimum, iMaximum); + nRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_SPELL_ENEMY, nTypeOfTarget, 0, nMinimum, nMaximum); } - iMinimum = GetAIInteger(TARGETING_RANGE + MINIMUM); + nMinimum = GetAIInteger(TARGETING_RANGE + MINIMUM); // 1. Do we do range? - if(iMinimum && iRemainingTargets >= i2) + if(nMinimum && nRemainingTargets >= 2) { // If so, is it lowest or highest? - iTypeOfTarget = GetAIInteger(TARGETING_RANGE); - iMaximum = GetAIInteger(TARGETING_RANGE + MAXIMUM); + nTypeOfTarget = GetAIInteger(TARGETING_RANGE); + nMaximum = GetAIInteger(TARGETING_RANGE + MAXIMUM); // We then set the array up in a new temp array AI_TargetingArrayDistanceStore(ARRAY_SPELL_ENEMY, ARRAY_TEMP_ARRAY); // We loop range. Maximum one can be from another when got to the // minimum is 5.0 M - iRemainingTargets = AI_TargetingArrayLimitTargetsFloat(ARRAY_SPELL_ENEMY, iTypeOfTarget, f5, iMinimum, iMaximum); + nRemainingTargets = AI_TargetingArrayLimitTargetsFloat(ARRAY_SPELL_ENEMY, nTypeOfTarget, 5.0, nMinimum, nMaximum); } // 2. Saving Throws - iMinimum = GetAIInteger(TARGETING_SAVES + MINIMUM); + nMinimum = GetAIInteger(TARGETING_SAVES + MINIMUM); // Do we do saves? And over one target... - if(iMinimum && iRemainingTargets >= i2) + if(nMinimum && nRemainingTargets >= 2) { // If so, is it lowest or highest? - iTypeOfTarget = GetAIInteger(TARGETING_SAVES); - iMaximum = GetAIInteger(TARGETING_SAVES + MAXIMUM); + nTypeOfTarget = GetAIInteger(TARGETING_SAVES); + nMaximum = GetAIInteger(TARGETING_SAVES + MAXIMUM); // We then set the array up in a new temp array. 2 = total saves. - AI_TargetingArrayIntegerStore(i2, ARRAY_SPELL_ENEMY); + AI_TargetingArrayIntegerStore(2, ARRAY_SPELL_ENEMY); // Saves are basically a spells' AC, or at least may hamper // spells' power. // - difference of 4 - iRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_SPELL_ENEMY, iTypeOfTarget, i4, iMinimum, iMaximum); + nRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_SPELL_ENEMY, nTypeOfTarget, 4, nMinimum, nMaximum); } // Most others are similar (and all integer values so easy to check) // 3. Phisical protections. - iMinimum = GetAIInteger(TARGETING_PHISICALS + MINIMUM); - if(iMinimum && iRemainingTargets >= i2) + nMinimum = GetAIInteger(TARGETING_PHISICALS + MINIMUM); + if(nMinimum && nRemainingTargets >= 2) { // If so, is it lowest or highest? - iTypeOfTarget = GetAIInteger(TARGETING_PHISICALS); - iMaximum = GetAIInteger(TARGETING_PHISICALS + MAXIMUM); + nTypeOfTarget = GetAIInteger(TARGETING_PHISICALS); + nMaximum = GetAIInteger(TARGETING_PHISICALS + MAXIMUM); // We then set the array up in a new temp array. 3 = phisicals. - AI_TargetingArrayIntegerStore(i3, ARRAY_SPELL_ENEMY); + AI_TargetingArrayIntegerStore(3, ARRAY_SPELL_ENEMY); // We loop as AC, basically. As it is stored based on the amount // of DR offered, limit is 0, not 6. Can't be any different. - iRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_SPELL_ENEMY, iTypeOfTarget, i0, iMinimum, iMaximum); + nRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_SPELL_ENEMY, nTypeOfTarget, 0, nMinimum, nMaximum); } // 4. BAB - iMinimum = GetAIInteger(TARGETING_BAB + MINIMUM); - if(iMinimum && iRemainingTargets >= i2) + nMinimum = GetAIInteger(TARGETING_BAB + MINIMUM); + if(nMinimum && nRemainingTargets >= 2) { // If so, is it lowest or highest? - iTypeOfTarget = GetAIInteger(TARGETING_BAB); - iMaximum = GetAIInteger(TARGETING_BAB + MAXIMUM); + nTypeOfTarget = GetAIInteger(TARGETING_BAB); + nMaximum = GetAIInteger(TARGETING_BAB + MAXIMUM); // We then set the array up in a new temp array. 4 = BAB - AI_TargetingArrayIntegerStore(i4, ARRAY_SPELL_ENEMY); + AI_TargetingArrayIntegerStore(4, ARRAY_SPELL_ENEMY); // We loop as AC, basically. As it is BAB, IE how much chance // they'll hit us (they might all hit on a 20, but it also shows // who are the best fighters!). Set to 5, like AC. - iRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_SPELL_ENEMY, iTypeOfTarget, i5, iMinimum, iMaximum); + nRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_SPELL_ENEMY, nTypeOfTarget, 5, nMinimum, nMaximum); } // 5. Hit Dice - iMinimum = GetAIInteger(TARGETING_HITDICE + MINIMUM); - if(iMinimum && iRemainingTargets >= i2) + nMinimum = GetAIInteger(TARGETING_HITDICE + MINIMUM); + if(nMinimum && nRemainingTargets >= 2) { // If so, is it lowest or highest? - iTypeOfTarget = GetAIInteger(TARGETING_HITDICE); - iMaximum = GetAIInteger(TARGETING_HITDICE + MAXIMUM); + nTypeOfTarget = GetAIInteger(TARGETING_HITDICE); + nMaximum = GetAIInteger(TARGETING_HITDICE + MAXIMUM); // We then set the array up in a new temp array. 5 = Hit dice - AI_TargetingArrayIntegerStore(i5, ARRAY_SPELL_ENEMY); + AI_TargetingArrayIntegerStore(5, ARRAY_SPELL_ENEMY); // We loop as AC. Hit Dice is even easier. We set the limit to // a max of 4. - iRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_SPELL_ENEMY, iTypeOfTarget, i4, iMinimum, iMaximum); + nRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_SPELL_ENEMY, nTypeOfTarget, 4, nMinimum, nMaximum); } // 6. Percent HP - iMinimum = GetAIInteger(TARGETING_HP_PERCENT + MINIMUM); - if(iMinimum && iRemainingTargets >= i2) + nMinimum = GetAIInteger(TARGETING_HP_PERCENT + MINIMUM); + if(nMinimum && nRemainingTargets >= 2) { // If so, is it lowest or highest? - iTypeOfTarget = GetAIInteger(TARGETING_HP_PERCENT); - iMaximum = GetAIInteger(TARGETING_HP_PERCENT + MAXIMUM); + nTypeOfTarget = GetAIInteger(TARGETING_HP_PERCENT); + nMaximum = GetAIInteger(TARGETING_HP_PERCENT + MAXIMUM); // We then set the array up in a new temp array. 6 = % HP - AI_TargetingArrayIntegerStore(i6, ARRAY_SPELL_ENEMY); + AI_TargetingArrayIntegerStore(6, ARRAY_SPELL_ENEMY); // We loop as AC. Current Hit Points are easy, and are done // by %ages. We set the % to 15 difference max. - iRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_SPELL_ENEMY, iTypeOfTarget, i15, iMinimum, iMaximum); + nRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_SPELL_ENEMY, nTypeOfTarget, 15, nMinimum, nMaximum); } // 7. Current HP - iMinimum = GetAIInteger(TARGETING_HP_CURRENT + MINIMUM); - if(iMinimum && iRemainingTargets >= i2) + nMinimum = GetAIInteger(TARGETING_HP_CURRENT + MINIMUM); + if(nMinimum && nRemainingTargets >= 2) { // If so, is it lowest or highest? - iTypeOfTarget = GetAIInteger(TARGETING_HP_CURRENT); - iMaximum = GetAIInteger(TARGETING_HP_CURRENT + MAXIMUM); + nTypeOfTarget = GetAIInteger(TARGETING_HP_CURRENT); + nMaximum = GetAIInteger(TARGETING_HP_CURRENT + MAXIMUM); // We then set the array up in a new temp array. 7 = Current - AI_TargetingArrayIntegerStore(i7, ARRAY_SPELL_ENEMY); + AI_TargetingArrayIntegerStore(7, ARRAY_SPELL_ENEMY); // We loop as AC. Current Hit points? Well, we set this limit to // Our Hit Dice * 2. - iRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_SPELL_ENEMY, iTypeOfTarget, GlobalOurHitDice * i2, iMinimum, iMaximum); + nRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_SPELL_ENEMY, nTypeOfTarget, GlobalOurHitDice * 2, nMinimum, nMaximum); } // 8. Maximum HP - iMinimum = GetAIInteger(TARGETING_HP_MAXIMUM + MINIMUM); - if(iMinimum && iRemainingTargets >= i2) + nMinimum = GetAIInteger(TARGETING_HP_MAXIMUM + MINIMUM); + if(nMinimum && nRemainingTargets >= 2) { // If so, is it lowest or highest? - iTypeOfTarget = GetAIInteger(TARGETING_HP_MAXIMUM); - iMaximum = GetAIInteger(TARGETING_HP_MAXIMUM + MAXIMUM); + nTypeOfTarget = GetAIInteger(TARGETING_HP_MAXIMUM); + nMaximum = GetAIInteger(TARGETING_HP_MAXIMUM + MAXIMUM); // We then set the array up in a new temp array. 8 = Maximum - AI_TargetingArrayIntegerStore(i8, ARRAY_SPELL_ENEMY); + AI_TargetingArrayIntegerStore(8, ARRAY_SPELL_ENEMY); // We loop as AC. Max hit Hit points? Well, we set this limit to // Our Hit Dice * 3. - iRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_SPELL_ENEMY, iTypeOfTarget, GlobalOurHitDice * i3, iMinimum, iMaximum); + nRemainingTargets = AI_TargetingArrayLimitTargets(ARRAY_SPELL_ENEMY, nTypeOfTarget, GlobalOurHitDice * 3, nMinimum, nMaximum); } // End narrowing down on ARRAY_SPELL_ENEMY // If only one, choose it - if(iRemainingTargets == i1) + if(nRemainingTargets == 1) { - GlobalSpellTarget = GetLocalObject(OBJECT_SELF, ARRAY_SPELL_ENEMY + s1); + GlobalSpellTarget = GetLocalObject(OBJECT_SELF, ARRAY_SPELL_ENEMY + "1"); } // Check for 2+, if 0, we haven't got one to set! - else if(iRemainingTargets >= i2) + else if(nRemainingTargets >= 2) { // Else Roll dice - iCnt = Random(iRemainingTargets - i1) + i1; + nCnt = Random(nRemainingTargets - 1) + 1; // Set random target - GlobalSpellTarget = GetLocalObject(OBJECT_SELF, ARRAY_SPELL_ENEMY + IntToString(iCnt)); + GlobalSpellTarget = GetLocalObject(OBJECT_SELF, ARRAY_SPELL_ENEMY + IntToString(nCnt)); } } } // Else, it is oLastTarget that will be our target - else + else if(AI_GetTargetSanityCheck(oLastTarget)) { + // Only set this if oLastTarget is valid. It might not be. Thanks Chris (1.4 fix) GlobalSpellTarget = oLastTarget; } - // If not valid, set to melee target - if(!GetIsObjectValid(GlobalSpellTarget)) + // If not (sane) valid, set to melee target + if(!AI_GetTargetSanityCheck(GlobalSpellTarget)) { GlobalSpellTarget = GlobalMeleeTarget; } + // If it is a new target, reset attacking counter to 0 if(GlobalSpellTarget != oLastTarget) { @@ -13642,7 +13621,6 @@ int AI_SetUpAllObjects(object oImputBackup) // Set Global* things for melee target GlobalRangeToMeleeTarget = GetDistanceToObject(GlobalMeleeTarget); GlobalMeleeTargetAC = GetAC(GlobalMeleeTarget); - GlobalMeleeTargetBAB = GetBaseAttackBonus(GlobalMeleeTarget); // Generic check. // - Set to TRUE, we should always have GlobalMeleeTarget as valid GlobalAnyValidTargetObject = TRUE;//GetIsObjectValid(GlobalMeleeTarget); @@ -13662,11 +13640,16 @@ int AI_SetUpAllObjects(object oImputBackup) // If they are spell resistance immune, we do not cast any normal spells // against them, except if we are a mage class + // * We only obviously get a spell resistance immune person if we + // have no one who is not immune via. SR. If they are immune, we just set + // to not use spells. if(AI_SpellResistanceImmune(GlobalSpellTarget)) { // Note: We set the breach level to max, 5, so that we use breaches // to bring down the SR of an enemy! - GlobalDispelTargetHighestBreach = i5; + // * This 5 number is checked just below, for when GlobalDispelTarget is set. + // To do this, we will breach this target + GlobalDispelTargetHighestBreach = 5; // Class checks. If not a mage caster, we will not use spells if(GlobalOurChosenClass != CLASS_TYPE_WIZARD && @@ -13674,25 +13657,27 @@ int AI_SetUpAllObjects(object oImputBackup) GlobalOurChosenClass != CLASS_TYPE_FEY) { // 10 means we do not want to cast any normal spells - GlobalNormalSpellsNoEffectLevel = i10; + GlobalNormalSpellsNoEffectLevel = 10; } else { // We will set this to 5, level 5 spells and under stopped, if - // we are a mage. - GlobalNormalSpellsNoEffectLevel = i5; + // we are a mage. This is done because SR isn't absolute, and also + // that some spells might get through... + GlobalNormalSpellsNoEffectLevel = 5; } } // Set the value to 10 if we have a 90% or greater chance of failing spells // due to any armor, or any spell failure stuff. - if(GetArcaneSpellFailure(OBJECT_SELF) >= i90 && - GlobalNormalSpellsNoEffectLevel < i9) + if(GetArcaneSpellFailure(OBJECT_SELF) >= 90 && + GlobalNormalSpellsNoEffectLevel < 9) { // Always set to 10 if it is an effect + // * Never cast normal spells (monster abilties are fine!) if(AI_GetAIHaveEffect(GlobalEffectSpellFailure)) { - GlobalNormalSpellsNoEffectLevel = i10; + GlobalNormalSpellsNoEffectLevel = 10; } // - If we have auto-still, Leave it as it is if we can still all spells automatically else if(!GetHasFeat(FEAT_EPIC_AUTOMATIC_STILL_SPELL_3) && @@ -13700,93 +13685,101 @@ int AI_SetUpAllObjects(object oImputBackup) !GetHasFeat(FEAT_EPIC_AUTOMATIC_STILL_SPELL_1)) { // Else do not cast as in armor - GlobalNormalSpellsNoEffectLevel = i10; + GlobalNormalSpellsNoEffectLevel = 10; } } // We may set GlobalNormalSpellsNoEffectLevel to 1-4 if the enemy has some // extra spell immunities. - if(GlobalNormalSpellsNoEffectLevel < i9 && + if(GlobalNormalSpellsNoEffectLevel < 9 && // Global setting needed - (GlobalIntelligence >= i9 || + (GlobalIntelligence >= 9 || GetSpawnInCondition(AI_FLAG_COMBAT_IMPROVED_SPECIFIC_SPELL_IMMUNITY, AI_COMBAT_MASTER))) { // This check now includes natural effect level - iValue = AI_GetSpellLevelEffect(GlobalSpellTarget); - if(GlobalNormalSpellsNoEffectLevel < iValue) + nValue = AI_GetSpellLevelEffect(GlobalSpellTarget); + if(GlobalNormalSpellsNoEffectLevel < nValue) { - GlobalNormalSpellsNoEffectLevel = iValue; + GlobalNormalSpellsNoEffectLevel = nValue; } } + // Important variables regarding GlobalSpellTarget GlobalSpellTargetWill = GetWillSavingThrow(GlobalSpellTarget); GlobalSpellTargetFort = GetFortitudeSavingThrow(GlobalSpellTarget); GlobalSpellTargetReflex = GetReflexSavingThrow(GlobalSpellTarget); GlobalSpellTargetHitDice = GetHitDice(GlobalSpellTarget); GlobalSpellTargetCurrentHitPoints = GetCurrentHitPoints(GlobalSpellTarget); + // This is one of the most important. GlobalSeenSpell = GetObjectSeen(GlobalSpellTarget); GlobalSpellTargetRace = GetRacialType(GlobalSpellTarget); // Range GlobalSpellTargetRange = GetDistanceToObject(GlobalSpellTarget); - // Set up GlobalSummonLocation to a location between targets. - // our last hostile actor, if not in 5 M, or else us - // - Summon spells have a 8M, short, range. - oSetUpTarget = OBJECT_INVALID; - if(GetSpawnInCondition(AI_FLAG_COMBAT_IMPROVED_SUMMON_TARGETING, AI_COMBAT_MASTER)) + // Set dispel target. + // 1.4 - if GlobalDispelTargetHighestBreach is already 5, we want to + // target the SR immune-to-spells person we are targeting. + if(GlobalDispelTargetHighestBreach == 5) { - if(GetIsObjectValid(oLastHostile) && GetDistanceToObject(oLastHostile) <= f16) + // Obviously valid. We only use SR Spell Breach reducing spells, unless + // they have Spell Resistance cast on them + GlobalDispelTarget = GlobalSpellTarget; + + // If they have spell resistance, we will attempt to dispel it normally, + // because it gives a massive boost to SR (11 + Caster level) and should + // make the target targetable for spells like normal. + if(GetHasSpellEffect(SPELL_SPELL_RESISTANCE, GlobalDispelTarget)) { - oSetUpTarget = oLastHostile; - } - if(GetDistanceToObject(GlobalRangedTarget) <= f16) - { - oSetUpTarget = GlobalRangedTarget; + GlobalDispelTargetHighestDispel = 5; } } - // Check summon target - if(GetIsObjectValid(oSetUpTarget)) - { - // Taken from bioware's summon allies - half way between the targets. - // Because we get a maximum range of 16, it means the range will be 8. - vector vTarget = GetPosition(oSetUpTarget); - vector vSource = GetPosition(OBJECT_SELF); - vector vDirection = vTarget - vSource; - float fDistance = VectorMagnitude(vDirection) / f2; - vector vPoint = VectorNormalize(vDirection) * fDistance + vSource; - GlobalSummonLocation = Location(GetArea(OBJECT_SELF), vPoint, DIRECTION_NORTH); - } - // Else self else { - GlobalSummonLocation = GetLocation(OBJECT_SELF); - } + // Should dispel something normally. - // Set dispel target. - if(GetSpawnInCondition(AI_FLAG_COMBAT_DISPEL_MAGES_MORE, AI_COMBAT_MASTER)) - { - // Sorcerors, to mages, to clerics, to druids. - GlobalDispelTarget = GetNearestCreature(CREATURE_TYPE_CLASS, CLASS_TYPE_SORCERER, OBJECT_SELF, i1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY); - if(!GetIsObjectValid(GlobalDispelTarget)) + // * 1.4 - This now checks for if they uncommandable etc. + if(GetSpawnInCondition(AI_FLAG_COMBAT_DISPEL_MAGES_MORE, AI_COMBAT_MASTER)) { - GlobalDispelTarget = GetNearestCreature(CREATURE_TYPE_CLASS, CLASS_TYPE_WIZARD, OBJECT_SELF, i1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY); - if(!GetIsObjectValid(GlobalDispelTarget)) + // Sorcerors, to mages, to clerics, to druids. + GlobalDispelTarget = GetNearestCreature(CREATURE_TYPE_CLASS, CLASS_TYPE_SORCERER, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY); + // Checks for each: If the target is insane to attack, or uncommandable, ignore + if(!AI_GetTargetSanityCheck(GlobalDispelTarget) || + AI_GetAIHaveEffect(GlobalEffectUncommandable, GlobalDispelTarget)) { - GlobalDispelTarget = GetNearestCreature(CREATURE_TYPE_CLASS, CLASS_TYPE_CLERIC, OBJECT_SELF, i1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY); - if(!GetIsObjectValid(GlobalDispelTarget)) + GlobalDispelTarget = GetNearestCreature(CREATURE_TYPE_CLASS, CLASS_TYPE_WIZARD, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY); + if(!AI_GetTargetSanityCheck(GlobalDispelTarget) || + AI_GetAIHaveEffect(GlobalEffectUncommandable, GlobalDispelTarget)) { - GlobalDispelTarget = GetNearestCreature(CREATURE_TYPE_CLASS, CLASS_TYPE_DRUID, OBJECT_SELF, i1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY); + GlobalDispelTarget = GetNearestCreature(CREATURE_TYPE_CLASS, CLASS_TYPE_CLERIC, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY); + if(!AI_GetTargetSanityCheck(GlobalDispelTarget) || + AI_GetAIHaveEffect(GlobalEffectUncommandable, GlobalDispelTarget)) + { + GlobalDispelTarget = GetNearestCreature(CREATURE_TYPE_CLASS, CLASS_TYPE_DRUID, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY); + } } } + // None valid? set to spell target. Even fighters can use potions! + if(!AI_GetTargetSanityCheck(GlobalDispelTarget) || + AI_GetAIHaveEffect(GlobalEffectUncommandable, GlobalDispelTarget)) + { + GlobalDispelTarget = GlobalSpellTarget; + } + } + else + { + // Default to spell target if we don't target wizard classes specifically + GlobalDispelTarget = GlobalSpellTarget; + } + // If it *is* a good choice, we then set up dispelable enchantments. + // If it isn't, we don't, and thusly the global variable for dispel level is + // never set. + // * Already done sanity check + if(GetIsObjectValid(GlobalDispelTarget)) + { + // Set enchantments + AI_SetDispelableEnchantments(); } } - if(!GetIsObjectValid(GlobalDispelTarget)) - { - GlobalDispelTarget = GlobalSpellTarget; - } - // Set enchantments - AI_SetDispelableEnchantments(); - // Delete everything AI_TargetingArrayDelete(ARRAY_TEMP_ENEMIES); AI_TargetingArrayDelete(ARRAY_TEMP_ALLIES); @@ -13795,6 +13788,13 @@ int AI_SetUpAllObjects(object oImputBackup) AI_TargetingArrayDelete(ARRAY_RANGED_ENEMY); AI_TargetingArrayDelete(ARRAY_SPELL_ENEMY); + DebugActionSpeak("*** TARGETING. Input Backup: " + GetName(oInputBackUpToAttack) + + "| MELEE: " + GetName(GlobalMeleeTarget) + "| M.VALID: " + IntToString(AI_GetTargetSanityCheck(GlobalMeleeTarget)) + "| M.SEEN: " + IntToString(GetObjectSeen(GlobalMeleeTarget)) + "| M.HEARD: " + IntToString(GetObjectHeard(GlobalMeleeTarget)) + + "| RANGED: " + GetName(GlobalRangedTarget) + "| R.VALID: " + IntToString(AI_GetTargetSanityCheck(GlobalRangedTarget)) + "| R.SEEN: " + IntToString(GetObjectSeen(GlobalRangedTarget)) + "| R.HEARD: " + IntToString(GetObjectHeard(GlobalRangedTarget)) + + "| SPELL: " + GetName(GlobalSpellTarget) + "| S.VALID: " + IntToString(AI_GetTargetSanityCheck(GlobalSpellTarget)) + "| S.SEEN: " + IntToString(GetObjectSeen(GlobalSpellTarget)) + "| S.HEARD: " + IntToString(GetObjectHeard(GlobalSpellTarget)) + + "| NEAR HEARD: " + GetName(GlobalNearestEnemyHeard) + "| VALID: " + IntToString(AI_GetTargetSanityCheck(GlobalNearestEnemyHeard)) + "| VALID2 " + IntToString(GlobalValidNearestHeardEnemy) + + "| NEAR SEEN: " + GetName(GlobalNearestEnemySeen) + "| VALID: " + IntToString(AI_GetTargetSanityCheck(GlobalNearestEnemySeen)) + "| VALID2 " + IntToString(GlobalValidNearestSeenEnemy)); + // FALSE lets us continue with the script. // - GlobalAnyValidTargetObject is set to TRUE if we want to attack anything. return FALSE; @@ -13823,12 +13823,12 @@ void AI_ActionUseSkillOnMeleeTarget(int iSkill) AI_EquipBestShield(); ActionEquipMostDamagingMelee(GlobalMeleeTarget); ActionUseSkill(iSkill, GlobalMeleeTarget); - ActionWait(f2); + ActionWait(2.0); ActionAttack(GlobalMeleeTarget); } int AI_AttemptHostileSkills() { - if(GlobalRangeToMeleeTarget < f4 && + if(GlobalRangeToMeleeTarget < 4.0 && !GetSpawnInCondition(AI_FLAG_COMBAT_ARCHER_ALWAYS_USE_BOW, AI_COMBAT_MASTER) && !SRA)// Spell ranged attacking = AI_FLAG_COMBAT_LONGER_RANGED_SPELLS_FIRST { @@ -13836,9 +13836,10 @@ int AI_AttemptHostileSkills() int iEmpathyDC, iRace; // Either: Not turned off, and intelligence >= 3, OR forced, and has it. if((!GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_PICKPOCKETING, AI_OTHER_COMBAT_MASTER) && - GlobalIntelligence >= i3) || + GlobalIntelligence >= 3) || GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_PICKPOCKETING, AI_OTHER_COMBAT_MASTER)) { + SpeakString("Seting for NO: " + IntToString(GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_PICKPOCKETING, AI_OTHER_COMBAT_MASTER)) + " YES: " + IntToString(GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_PICKPOCKETING, AI_OTHER_COMBAT_MASTER))); // Need appropriate level of skill, checked On Spawn, or overriden... AI_ActionUseSkillOnMeleeTarget(SKILL_PICK_POCKET); return TRUE; @@ -13847,22 +13848,26 @@ int AI_AttemptHostileSkills() if(!GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_TAUNTING, AI_OTHER_COMBAT_MASTER) && !GetLocalTimer(AI_TIMER_TAUNT)) { - if(GlobalIntelligence >= i2 || + if(GlobalIntelligence >= 2 || GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_TAUNTING, AI_OTHER_COMBAT_MASTER)) { // Random determine if we use it... - if(GetSkillRank(SKILL_TAUNT) + Random(i10) >= - GetSkillRank(SKILL_CONCENTRATION, GlobalMeleeTarget) + Random(i10)) + if(GetSkillRank(SKILL_TAUNT) + Random(10) >= + GetSkillRank(SKILL_CONCENTRATION, GlobalMeleeTarget) + Random(10)) { // If randomly used, we set a timer for longer, and attack with it. - SetLocalTimer(AI_TIMER_TAUNT, f24); - SpeakArrayString(AI_TALK_ON_TAUNT); + SetLocalTimer(AI_TIMER_TAUNT, 24.0); + // * Don't speak when silenced or deaf, 1.4 change. + if(!AI_GetAIHaveEffect(GlobalEffectDeaf) && !AI_GetAIHaveEffect(GlobalEffectSilenced)) + { + SpeakArrayString(AI_TALK_ON_TAUNT); + } AI_ActionUseSkillOnMeleeTarget(SKILL_TAUNT); return TRUE; } else // 2 rounds until next check... { - SetLocalTimer(AI_TIMER_TAUNT, f12); + SetLocalTimer(AI_TIMER_TAUNT, 12.0); } } } @@ -13870,35 +13875,35 @@ int AI_AttemptHostileSkills() if(!GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_EMPATHY, AI_OTHER_COMBAT_MASTER) && !GetLocalTimer(AI_TIMER_EMPATHY)) { - if(GlobalIntelligence >= i3 || + if(GlobalIntelligence >= 3 || GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_EMPATHY, AI_OTHER_COMBAT_MASTER)) { - iEmpathyDC = i20; + iEmpathyDC = 20; iRace = GetRacialType(GlobalMeleeTarget); // we add 4 (to make DC 24 + HD) if a special animal. R_T_ANIMAL is DC 20 if(iRace == RACIAL_TYPE_BEAST || iRace == RACIAL_TYPE_MAGICAL_BEAST) { - iEmpathyDC += i4; + iEmpathyDC += 4; } else if(iRace != RACIAL_TYPE_ANIMAL) { // Else, if we are not a beast, magical beast, nor animal, // we don't use it! - SetLocalTimer(AI_TIMER_EMPATHY, f18); + SetLocalTimer(AI_TIMER_EMPATHY, 18.0); // - Last skill we can use, so just return FALSE. return FALSE; } // We check our skill against it... - if((GetSkillRank(SKILL_ANIMAL_EMPATHY) + i10) >= (GetHitDice(GlobalMeleeTarget) + i20)) + if((GetSkillRank(SKILL_ANIMAL_EMPATHY) + 10) >= (GetHitDice(GlobalMeleeTarget) + 20)) { // If randomly used, we set a timer for longer, and attack with it. - SetLocalTimer(AI_TIMER_EMPATHY, f24); + SetLocalTimer(AI_TIMER_EMPATHY, 24.0); AI_ActionUseSkillOnMeleeTarget(SKILL_ANIMAL_EMPATHY); return TRUE; } else // 2 rounds until next check... { - SetLocalTimer(AI_TIMER_EMPATHY, f12); + SetLocalTimer(AI_TIMER_EMPATHY, 12.0); } } } @@ -13916,137 +13921,144 @@ int AI_AttemptHostileSkills() //::////////////////////////////////////////////*/ int AI_AttemptFeatCombatHostile() { - int iUseSpells = TRUE; - // Don't chance the use of broken paladin and ranger spells. - if(GlobalOurChosenClass == CLASS_TYPE_PALADIN || - GlobalOurChosenClass == CLASS_TYPE_RANGER) - iUseSpells = FALSE; + // Get our right hand (primary) weapon + object oPrimaryWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND); - if(iUseSpells) + // Of course, we use, or attempt to use, our Divine Domain Powers, if + // we have them! They are spells, of no talent (or no talent I want to check) + if(!AI_GetAIHaveSpellsEffect(GlobalHasDomainSpells)) { - // Of course, we use, or attempt to use, our Divine Domain Powers, if - // we have them! They are spells, of no talent (or no talent I want to check) - if(!AI_GetAIHaveSpellsEffect(GlobalHasDomainSpells)) + if(AI_ActionCastSpell(SPELLABILITY_BATTLE_MASTERY)) return TRUE; // STRENGTH domain + if(AI_ActionCastSpell(SPELLABILITY_DIVINE_STRENGTH)) return TRUE; // STRENGTH domain + if(AI_ActionCastSpell(SPELLABILITY_BATTLE_MASTERY)) return TRUE; // WAR domain + if(AI_ActionCastSpell(SPELLABILITY_DIVINE_TRICKERY)) return TRUE; // TRICKERY domain + } + // Special power. Not, I think, a domain one. + if(AI_ActionCastSpell(SPELLABILITY_ROGUES_CUNNING)) return TRUE; + + // These are good-ass strength spells. They are basically + // powerful combat-orientated, strenth-inducing ones :-D + // Divine Power: Category 10, benifical Enhance self. Lvl 4. + if(AI_ActionCastSpell(SPELL_DIVINE_POWER, OBJECT_SELF, 14, FALSE)) return TRUE; + + // We may cast cats grace, if they are 6M or over away, we have + // a ranged weapon equipped or we have lowish AC compared to HD. + if(GlobalOurAC < GlobalOurHitDice + 6 + Random(4) || + GlobalRangeToMeleeTarget > 6.0 || + GetWeaponRanged(oPrimaryWeapon)) + { + // Include harper cats grace. + if(!AI_GetAIHaveSpellsEffect(GlobalHasCatsGraceSpell)) { - if(AI_ActionCastSpell(SPELLABILITY_BATTLE_MASTERY)) return TRUE; // STRENGTH domain - if(AI_ActionCastSpell(SPELLABILITY_DIVINE_STRENGTH)) return TRUE; // STRENGTH domain - if(AI_ActionCastSpell(SPELLABILITY_BATTLE_MASTERY)) return TRUE; // WAR domain - if(AI_ActionCastSpell(SPELLABILITY_DIVINE_TRICKERY)) return TRUE; // TRICKERY domain + // Greater cats grace gives 2d4 + 1 + if(AI_ActionCastSpell(SPELL_GREATER_CATS_GRACE)) return TRUE; + + // Special harper feat version + if(AI_ActionUseSpellLikeFeat(FEAT_HARPER_CATS_GRACE, AI_SPELLABILITY_HARPER_CATS_GRACE)) return TRUE; + + // Cats Grace. Level 2 (Mage/Bard/Ranger). + d4() + 1 dexterity. + if(AI_ActionCastSpell(SPELL_CATS_GRACE, OBJECT_SELF, 12, FALSE)) return TRUE; } - // Special power. Not, I think, a domain one. - if(AI_ActionCastSpell(SPELLABILITY_ROGUES_CUNNING)) return TRUE; + } + // Include blackguard bulls strength. + if(!AI_GetAIHaveSpellsEffect(GlobalHasBullsStrengthSpell)) + { + // Greater version gives 2d4 + 1. + if(AI_ActionCastSpell(SPELL_GREATER_BULLS_STRENGTH)) return TRUE; - // These are good-ass strength spells. They are basically - // powerful combat-orientated, strenth-inducing ones :-D - // Divine Power: Category 10, benifical Enhance self. Lvl 4. - if(AI_ActionCastSpell(SPELL_DIVINE_POWER, SpellEnhSelf, OBJECT_SELF, i14, FALSE, ItemEnhSelf, PotionPro)) return TRUE; + // Blackguard version + if(AI_ActionUseSpellLikeFeat(FEAT_BULLS_STRENGTH, SPELLABILITY_BG_BULLS_STRENGTH)) return TRUE; - // We may cast cats grace, if they are 6M or over away, we have - // a ranged weapon equipped or we have lowish AC compared to HD. - if(GlobalOurAC < GlobalOurHitDice + i6 + Random(i4) || - GlobalRangeToMeleeTarget > f6 || - GetWeaponRanged(GlobalRightHandWeapon)) + // Bulls Strength. Level 2 (Mage/Cleric/Bard/Paladin/Druid). + d4() + 1 strength. + if(AI_ActionCastSpell(SPELL_BULLS_STRENGTH, OBJECT_SELF, 12, FALSE)) return TRUE; + } + + // Other helping spells, lower ranks. If we can't hit much, we cast this. + // - Some help more then others. + // - We ignore some if in HTH and have low HD compared to spell. + if((GlobalOurHitDice < 15 || GlobalMeleeAttackers < 1) && + // We only add 15, as we don't apply strength ETC. at the mo. + (GlobalOurBaseAttackBonus - 15 < GlobalMeleeTargetAC) && + (!AI_GetAIHaveSpellsEffect(GlobalHasAidingSpell))) + { + // Prayer. Level 3 (Paladin/Cleric). +1 Attack, damage, saves to all allies in 10M Including self. + if(AI_ActionCastSpell(SPELL_PRAYER, OBJECT_SELF, 13, FALSE)) return TRUE; + if(GlobalOurHitDice < 14) { - // Include harper cats grace. - if(!AI_GetAIHaveSpellsEffect(GlobalHasCatsGraceSpell)) + // Aid. Level 2 (Cleric/Paladin) 3 (Ranger) +1 Attack Rolls, +1d8 HP + if(AI_ActionCastSpell(SPELL_AID, OBJECT_SELF, 12, FALSE)) return TRUE; + if(GlobalOurHitDice < 12) { - // Cats Grace. Level 2 (Mage/Bard/Ranger). + d4() + 1 dexterity. - if(AI_ActionUseFeatOnObject(FEAT_HARPER_CATS_GRACE)) return TRUE; - if(AI_ActionCastSpell(SPELL_GREATER_CATS_GRACE, SpellEnhSinTar)) return TRUE; - if(AI_ActionCastSpell(SPELL_CATS_GRACE, SpellEnhSinTar, OBJECT_SELF, i12, FALSE, ItemEnhSinTar)) return TRUE; + // Bless. Level 1 (Cleric/Paladin). +1 Saves, +1 Damage, to allies in area. + if(AI_ActionCastSpell(SPELL_BLESS, OBJECT_SELF, 11, FALSE)) return TRUE; } } - // Include blackguard bulls strength. - if(!AI_GetAIHaveSpellsEffect(GlobalHasBullsStrengthSpell)) + } + // Attack bonus spells/feats, that directly add to our attack bonus. + + // Divine might adds charisma bonus to Attack. + if(GetHasFeat(FEAT_TURN_UNDEAD)) + { + // +Cha bonus to attack bonus. + if(AI_ActionUseSpellLikeFeat(FEAT_DIVINE_MIGHT, SPELL_DIVINE_MIGHT)) return TRUE; + } + + // We now cast the spells which will affect our weapon (if we have one!) + // Only cast these if we have a valid right hand weapon. + if(GetIsObjectValid(oPrimaryWeapon) && + // Casts on melee weapons only, except if set to always use range + (!GetWeaponRanged(oPrimaryWeapon) || + GetSpawnInCondition(AI_FLAG_COMBAT_ARCHER_ALWAYS_USE_BOW, AI_COMBAT_MASTER)) && + // We do it VIA. the medium of one integer. + !AI_GetAIHaveSpellsEffect(GlobalHasWeaponHelpSpell)) + { + // Cast best to worst, only one in affect at once, however. + + // Blackstaff. Great stuff for a STAFF ONLY. + if(GetBaseItemType(oPrimaryWeapon) == BASE_ITEM_QUARTERSTAFF) { - // Bulls Strength. Level 2 (Mage/Cleric/Bard/Paladin/Druid). + d4() + 1 strength. - if(AI_ActionCastSpell(SPELL_GREATER_BULLS_STRENGTH, SpellEnhSinTar)) return TRUE; - // Blackguard version - if(AI_ActionUseFeatOnObject(FEAT_BULLS_STRENGTH)) return TRUE; - if(AI_ActionCastSpell(SPELL_BULLS_STRENGTH, SpellEnhSinTar, OBJECT_SELF, i12, FALSE, ItemEnhSinTar)) return TRUE; + // Blackstaff. Level 8 (Mage). Adds +4 enhancement bonus, On Hit: Dispel. + if(AI_ActionCastSpell(SPELL_BLACKSTAFF, oPrimaryWeapon, 18, FALSE)) return TRUE; } - - // Other helping spells, lower ranks. If we can't hit much, we cast this. - // - Some help more then others. - // - We ignore some if in HTH and have low HD compared to spell. - if((GlobalOurHitDice < i15 || GlobalMeleeAttackers < i1) && - // We only add 15, as we don't apply strength ETC. at the mo. - (GlobalOurBaseAttackBonus - i15 < GlobalMeleeTargetAC) && - (!AI_GetAIHaveSpellsEffect(GlobalHasAidingSpell))) + if(!GetItemHasItemProperty(oPrimaryWeapon, ITEM_PROPERTY_ENHANCEMENT_BONUS)) { - // Prayer. Level 3 (Paladin/Cleric). +1 Attack, damage, saves to all allies in 10M Including self. - if(AI_ActionCastSpell(SPELL_PRAYER, SpellEnhAre, OBJECT_SELF, i13, FALSE, ItemEnhAre)) return TRUE; - if(GlobalOurHitDice < i14) - { - // Aid. Level 2 (Cleric/Paladin) 3 (Ranger) +1 Attack Rolls, +1d8 HP - if(AI_ActionCastSpell(SPELL_AID, SpellEnhSinTar, OBJECT_SELF, i12, FALSE, ItemEnhSinTar)) return TRUE; - if(GlobalOurHitDice < i12) - { - // Bless. Level 1 (Cleric/Paladin). +1 Saves, +1 Damage, to allies in area. - if(AI_ActionCastSpell(SPELL_BLESS, SpellEnhSinTar, OBJECT_SELF, i11, FALSE, ItemEnhSinTar)) return TRUE; - } - } - } - // Attack bonus spells/feats, that directly add to our attack bonus. - - // Divine might adds charisma bonus to Attack. - if(GetHasFeat(FEAT_TURN_UNDEAD)) - { - // +Cha bonus to attack bonus. - if(AI_ActionUseFeatOnObject(FEAT_DIVINE_MIGHT)) return TRUE; - } - - // We now cast the spells which will affect our weapon (if we have one!) - // Only cast these if we have a valid right hand weapon. - if(GetIsObjectValid(GlobalRightHandWeapon) && - // Casts on melee weapons only, except if set to always use range - (!GetWeaponRanged(GlobalRightHandWeapon) || - GetSpawnInCondition(AI_FLAG_COMBAT_ARCHER_ALWAYS_USE_BOW, AI_COMBAT_MASTER)) && - // We do it VIA. the medium of one integer. - !AI_GetAIHaveSpellsEffect(GlobalHasWeaponHelpSpell)) - { - // Cast best to worst, only one in affect at once, however. - - // Blackstaff. Great stuff for a STAFF ONLY. - if(GetBaseItemType(GlobalRightHandWeapon) == BASE_ITEM_QUARTERSTAFF) - { - // Blackstaff. Level 8 (Mage). Adds +4 enhancement bonus, On Hit: Dispel. - if(AI_ActionCastSpell(SPELL_BLACKSTAFF, SpellEnhSinTar, GlobalRightHandWeapon, i18, FALSE, ItemEnhSinTar)) return TRUE; - } // Greater Magical Weapon - up to +5 // Greater Magic Weapon. Level 3 (Mage/Bard/Paladin) 4 (Cleric). Grants a +1/3 caster levels (to +5). - if(AI_ActionCastSpell(SPELL_GREATER_MAGIC_WEAPON, SpellEnhSinTar, GlobalRightHandWeapon, i14, FALSE, ItemEnhSinTar)) return TRUE; - - // Blade Thurst - cast on any weapon. No bother to check type. - // Blade Thurst. Level 3 (Ranger). +3 Damage for a slashing weapon. - if(AI_ActionCastSpell(SPELL_BLADE_THIRST, SpellEnhSinTar, GlobalRightHandWeapon, i13, FALSE, ItemEnhSinTar)) return TRUE; - - // Dark Fire. Level 3 (Cleric). 1d6 fire damage +1/level to a maximum of +10. - if(AI_ActionCastSpell(SPELL_DARKFIRE, SpellEnhSinTar, GlobalRightHandWeapon, i13, FALSE, ItemEnhSinTar)) return TRUE; - - // Flame Weapon. Level 2 (Mage). 1d4 fire damage +1/level to a maximum of +10. - if(AI_ActionCastSpell(SPELL_FLAME_WEAPON, SpellEnhSinTar, GlobalRightHandWeapon, i12, FALSE, ItemEnhSinTar)) return TRUE; - - // Not if we are already keen :-) - if(!GetItemHasItemProperty(GlobalRightHandWeapon, ITEM_PROPERTY_KEEN)) - { - // Keen Edge. Level 1 (Bard/Mage/Paladin). Adds the Keen property to a weapon - if(AI_ActionCastSpell(SPELL_BLADE_THIRST, SpellEnhSinTar, GlobalRightHandWeapon, i11, FALSE, ItemEnhSinTar)) return TRUE; - } - - // Magic weapon - +1 - if(!GetItemHasItemProperty(GlobalRightHandWeapon, ITEM_PROPERTY_ENHANCEMENT_BONUS)) - { - // Magic Weapon. Level 1 (Bard/Cleric/Paladin/Ranger/Mage). +1 Enchantment to melee weapon. - if(AI_ActionCastSpell(SPELL_MAGIC_WEAPON, SpellEnhSinTar, GlobalRightHandWeapon, i11, FALSE, ItemEnhSinTar)) return TRUE; - } + if(AI_ActionCastSpell(SPELL_GREATER_MAGIC_WEAPON, oPrimaryWeapon, 14, FALSE)) return TRUE; + } + // Blade Thurst - cast on any weapon. No bother to check type. + // Blade Thurst. Level 3 (Ranger). +3 Damage for a slashing weapon. + if(AI_ActionCastSpell(SPELL_BLADE_THIRST, oPrimaryWeapon, 13, FALSE)) return TRUE; + // Cannot have On Hit property already + if(!GetItemHasItemProperty(oPrimaryWeapon, ITEM_PROPERTY_ON_HIT_PROPERTIES)) + { // Bless weapon if(GetRacialType(GlobalMeleeTarget) == RACIAL_TYPE_UNDEAD) { // Bless weapon. Level 1 (Paladin). +1 Attack Bonus, +2d6 Damage to melee weapon VS undead - if(AI_ActionCastSpell(SPELL_MAGIC_WEAPON, SpellEnhSinTar, GlobalRightHandWeapon, i11, FALSE, ItemEnhSinTar)) return TRUE; + if(AI_ActionCastSpell(SPELL_BLESS_WEAPON, oPrimaryWeapon, 11, FALSE)) return TRUE; } + + // Dark Fire. Level 3 (Cleric). 1d6 fire damage +1/level to a maximum of +10. + if(AI_ActionCastSpell(SPELL_DARKFIRE, oPrimaryWeapon, 13, FALSE)) return TRUE; + + // Flame Weapon. Level 2 (Mage). 1d4 fire damage +1/level to a maximum of +10. + if(AI_ActionCastSpell(SPELL_FLAME_WEAPON, oPrimaryWeapon, 12, FALSE)) return TRUE; + } + + // Not if we are already keen :-) + if(!GetItemHasItemProperty(oPrimaryWeapon, ITEM_PROPERTY_KEEN)) + { + // Keen Edge. Level 1 (Bard/Mage/Paladin). Adds the Keen property to a weapon + if(AI_ActionCastSpell(SPELL_BLADE_THIRST, oPrimaryWeapon, 11, FALSE)) return TRUE; + } + + // Magic weapon - +1 + if(!GetItemHasItemProperty(oPrimaryWeapon, ITEM_PROPERTY_ENHANCEMENT_BONUS)) + { + // Magic Weapon. Level 1 (Bard/Cleric/Paladin/Ranger/Mage). +1 Enchantment to melee weapon. + if(AI_ActionCastSpell(SPELL_MAGIC_WEAPON, oPrimaryWeapon, 11, FALSE)) return TRUE; } } // We also will throw grenades here, if we are at a cirtain HD - 5 or under, @@ -14054,52 +14066,53 @@ int AI_AttemptFeatCombatHostile() // Try grenades - we always throw these. They are about level 1 standard of DC's // and effects. Not too bad, when NPC's get a chance to use them! :-) - if(GlobalOurHitDice <= i5 || + if(GlobalOurHitDice <= 5 || // Will throw at range if under 10 HD - (GlobalRangeToMeleeTarget > f5 && GlobalOurHitDice < i10)) + (GlobalRangeToMeleeTarget > 5.0 && GlobalOurHitDice < 10)) { if(AI_AttemptGrenadeThrowing(GlobalMeleeTarget)) return TRUE; } // Here, we use all potions if set too... - if(GetSpawnInCondition(AI_FLAG_COMBAT_USE_ALL_POTIONS, AI_COMBAT_MASTER)) +/* if(GetSpawnInCondition(AI_FLAG_COMBAT_USE_ALL_POTIONS, AI_COMBAT_MASTER)) { - int iUsed = FALSE; + int nUsed = FALSE; // Check protection potion if(PotionPro > FALSE && !GetHasSpellEffect(PotionPro)) { - iUsed = PotionPro; + nUsed = PotionPro; ActionUseTalentOnObject(tPotionPro, OBJECT_SELF); } // Check enhancement potion else if(PotionEnh > FALSE && !GetHasSpellEffect(PotionEnh)) { - iUsed = PotionEnh; + nUsed = PotionEnh; ActionUseTalentOnObject(tPotionEnh, OBJECT_SELF); } // Check conditional potion else if(PotionCon > FALSE && !GetHasSpellEffect(PotionCon)) { - iUsed = PotionCon; + nUsed = PotionCon; ActionUseTalentOnObject(tPotionCon, OBJECT_SELF); } - if(iUsed > FALSE) + if(nUsed > FALSE) { - // 43 "[DCR:Pre-Melee Spells] All Potions Using. [Spell ID] " + IntToString(iUsed) - DebugActionSpeakByInt(43, OBJECT_INVALID, iUsed); + // 43 "[DCR:Pre-Melee Spells] All Potions Using. [Spell ID] " + IntToString(nUsed) + DebugActionSpeakByInt(43, OBJECT_INVALID, nUsed); return TRUE; } - } + }*/ // Rage - check effects via the set effects.. if(!AI_GetAIHaveSpellsEffect(GlobalHasRageSpells)) { // Rage: either: - // +6, to STR, CON, will. -2 AC. - // or +4, to STR, CON, will. -2 AC. - if(AI_ActionUseFeatOnObject(FEAT_BARBARIAN_RAGE)) return TRUE; + // +6, to STR, CON, +4 will. -2 AC. + // or +4, to STR, CON, +2 will. -2 AC. + if(AI_ActionUseSpellLikeFeat(FEAT_BARBARIAN_RAGE, SPELLABILITY_BARBARIAN_RAGE)) return TRUE; + // Blood frenzy. Level 2 (druid) as rage, for the most part. +2, to STR, CON, Will, -1 AC though. - if(AI_ActionCastSpell(SPELL_BLOOD_FRENZY, SpellOtherSpell, OBJECT_SELF, i12)) return TRUE; + if(AI_ActionCastSpell(SPELL_BLOOD_FRENZY, OBJECT_SELF, 12)) return TRUE; if(AI_ActionCastSpell(SPELLABILITY_RAGE_5)) return TRUE; if(AI_ActionCastSpell(SPELLABILITY_RAGE_4)) return TRUE; if(AI_ActionCastSpell(SPELLABILITY_FEROCITY_3)) return TRUE; @@ -14111,28 +14124,28 @@ int AI_AttemptFeatCombatHostile() if(AI_ActionCastSpell(SPELLABILITY_FEROCITY_1)) return TRUE; } // Cast expeditious retreat if we want to get into combat quicker - if(GlobalRangeToMeleeTarget >= f20 && - !GetWeaponRanged(GlobalRightHandWeapon) && + if(GlobalRangeToMeleeTarget >= 20.0 && + !GetWeaponRanged(oPrimaryWeapon) && !AI_GetAIHaveEffect(GlobalEffectHaste) && !GetHasSpellEffect(SPELL_EXPEDITIOUS_RETREAT)) { // Expeditious Retreat. Level 1 (Bard/Mage). +150% movement speed. - if(AI_ActionCastSpell(SPELL_EXPEDITIOUS_RETREAT, SpellEnhSelf, OBJECT_SELF, i11, FALSE, ItemEnhSelf, PotionEnh)) return TRUE; + if(AI_ActionCastSpell(SPELL_EXPEDITIOUS_RETREAT, OBJECT_SELF, 11, FALSE)) return TRUE; } // Cast true strike if we are RIGHT near the melee target, or are using // a ranged weapon - if((GlobalRangeToMeleeTarget < f3 || - GetWeaponRanged(GlobalRightHandWeapon)) && + if((GlobalRangeToMeleeTarget < 3.0 || + GetWeaponRanged(oPrimaryWeapon)) && !GetHasSpellEffect(SPELL_TRUE_STRIKE)) { // True Strike. Level 1 (Mage). +20 attack bonus for 9 seconds (IE about 1, or 2, attacks) - if(AI_ActionCastSpell(SPELL_TRUE_STRIKE, SpellEnhSelf, OBJECT_SELF, i11, FALSE, ItemEnhSelf, PotionEnh)) + if(AI_ActionCastSpell(SPELL_TRUE_STRIKE, OBJECT_SELF, 11, FALSE)) { // 44: "[DCR:Pre-Melee Spells] True Strike Emptive attack [Target] " + GetName(GlobalMeleeTarget) DebugActionSpeakByInt(44, GlobalMeleeTarget); // Add attack to end of action queue. Should do this next round // anyway - if(GlobalRangeToMeleeTarget <= f4) + if(GlobalRangeToMeleeTarget <= 4.0) { ActionEquipMostDamagingMelee(GlobalMeleeTarget); } @@ -14157,50 +14170,52 @@ int AI_AttemptFeatCombatHostile() //:: Created By: Jasperre //::////////////////////////////////////////////*/ -// This will cheat-cast iSpell at oTarget. Note that we will know if we have it +// This will cheat-cast nSpell at oTarget. Note that we will know if we have it // by checking what appearance we have. -void AI_ActionCastShifterSpell(int iSpell, object oTarget = OBJECT_SELF) +void AI_ActionCastShifterSpell(int nSpell, object oTarget = OBJECT_SELF) { // Cheat cast the spell. We know we must have it. - ActionCastSpellAtObject(iSpell, oTarget, METAMAGIC_NONE, TRUE); + ActionCastSpellAtObject(nSpell, oTarget, METAMAGIC_NONE, TRUE); } -// This willcast iFirst -> iFirst + iAmount polymorph spell. It will check -// if we have iMaster (Either by feat or spell, depending on iFeat). +// This willcast nFirst -> nFirst + nAmount polymorph spell. It will check +// if we have nMaster (Either by feat or spell, depending on bFeat). // TRUE if we polymorph. -int AI_ActionPolymorph(int iMaster, int iFirstSpell, int iAmount, int iFeat = FALSE, int iRemove = TRUE) +// * Only decrements if bRemove is TRUE +int AI_ActionPolymorph(int nMaster, int nFirstSpell, int nAmount, int bFeat = FALSE, int bRemove = TRUE) { - if((iFeat && GetHasFeat(iMaster)) || - (!iFeat && GetHasSpell(iMaster))) + if((bFeat && GetHasFeat(nMaster)) || + (!bFeat && GetHasSpell(nMaster))) { // Randomise - // EG: Got from 300 to 303, so iAmount is 3 and we input 300 as the start one. - int iCast = iFirstSpell + Random(iAmount + i1); + // EG: Got from 300 to 303, so nAmount is 3 and we input 300 as the start one, + // meaning we add 0 (to get 300) 1 (to get 301) or 2 (to get 302, all 3 options covered) + int nCast = nFirstSpell + Random(nAmount); // Debug // 11: "[DCR:Casting] SubSpecialSpell. [ID] " + IntToString(iInput) + " [Target] " + GetName(oInput) + " [Location] " + sInput; break; - DebugActionSpeakByInt(11, OBJECT_SELF, iCast); + DebugActionSpeakByInt(11, OBJECT_SELF, nCast); // If a spell, we concentration check it :-) - if(!iFeat) + if(!bFeat) { AI_AttemptConcentrationCheck(GlobalSpellTarget); } // Cast it - ActionCastSpellAtObject(iCast, OBJECT_SELF, METAMAGIC_NONE, TRUE); + ActionCastSpellAtObject(nCast, OBJECT_SELF, METAMAGIC_NONE, TRUE); - if(iRemove) + if(bRemove) { // Decrement one or the other - if(iFeat) + if(bFeat) { // Feat - DecrementRemainingFeatUses(OBJECT_SELF, iMaster); + DecrementRemainingFeatUses(OBJECT_SELF, nMaster); } else { // Spell - DecrementRemainingSpellUses(OBJECT_SELF, iMaster); + DecrementRemainingSpellUses(OBJECT_SELF, nMaster); } } // Add Action Attack melee target :-D @@ -14226,22 +14241,22 @@ int AI_AttemptPolyMorph() // 707 Greater_Wild_Shape_Red_dragon // 708 Greater_Wild_Shape_Blue_dragon // 709 Greater_Wild_Shape_Green_dragon - if(AI_ActionPolymorph(AI_FEAT_EPIC_WILD_SHAPE_DRAGON, 707, 3, TRUE)) return TRUE; + if(AI_ActionPolymorph(FEAT_EPIC_WILD_SHAPE_DRAGON, 707, 3, TRUE)) return TRUE; // Construct feat // 738 Construct_Shape_StoneGolem // 739 Construct_Shape_DemonFleshGolem // 740 Construct_Shape_IronGolem - if(AI_ActionPolymorph(AI_FEAT_EPIC_CONSTRUCT_SHAPE, 738, 3, TRUE)) return TRUE; + if(AI_ActionPolymorph(FEAT_EPIC_CONSTRUCT_SHAPE, 738, 3, TRUE)) return TRUE; // Outsider shape // 733 Outsider_Shape_Azer // 734 Outsider_Shape_Rakshasa // 735 Outsider_Shape_DeathSlaad - if(AI_ActionPolymorph(AI_FEAT_EPIC_OUTSIDER_SHAPE, 733, 3, TRUE)) return TRUE; + if(AI_ActionPolymorph(FEAT_EPIC_OUTSIDER_SHAPE, 733, 3, TRUE)) return TRUE; // Undead - any of them // 704 Undead_Shape_risen_lord // 705 Undead_Shape_Vampire // 706 Undead_Shape_Spectre - if(AI_ActionPolymorph(AI_FEAT_EPIC_WILD_SHAPE_UNDEAD, 704, 3, TRUE)) return TRUE; + if(AI_ActionPolymorph(FEAT_EPIC_WILD_SHAPE_UNDEAD, 704, 3, TRUE)) return TRUE; // Shapechange // 392 Shapechange_RED_DRAGON // 393 Shapechange_FIRE_GIANT @@ -14254,7 +14269,7 @@ int AI_AttemptPolyMorph() // 398 Elemental_Shape_WATER // 399 Elemental_Shape_EARTH // 400 Elemental_Shape_AIR - if(AI_ActionPolymorph(AI_FEAT_EPIC_DRUID_INFINITE_ELEMENTAL_SHAPE, 397, 4, TRUE, FALSE)) return TRUE; + if(AI_ActionPolymorph(FEAT_EPIC_DRUID_INFINITE_ELEMENTAL_SHAPE, 397, 4, TRUE, FALSE)) return TRUE; if(AI_ActionPolymorph(FEAT_ELEMENTAL_SHAPE, 397, 4, TRUE)) return TRUE; // Wildshape 4 is next best // - Infinite and normal shapes @@ -14264,55 +14279,55 @@ int AI_AttemptPolyMorph() // 691 Greater_Wild_Shape_Mindflayer // 694 Greater_Wild_Shape_DireTiger // Random choose one - int iSpell = 671; + int nSpell = 671; switch(d4()) { - case i1: iSpell = 671; break; - case i2: iSpell = 679; break; - case i3: iSpell = 691; break; - case i4: iSpell = 694; break; + case 1: nSpell = 671; break; + case 2: nSpell = 679; break; + case 3: nSpell = 691; break; + case 4: nSpell = 694; break; } - if(AI_ActionPolymorph(AI_FEAT_EPIC_SHIFTER_INFINITE_WILDSHAPE_4, iSpell, FALSE, TRUE, FALSE)) return TRUE; - if(AI_ActionPolymorph(AI_FEAT_GREATER_WILDSHAPE_4, iSpell, FALSE, TRUE)) return TRUE; + if(AI_ActionPolymorph(FEAT_EPIC_SHIFTER_INFINITE_WILDSHAPE_4, nSpell, FALSE, TRUE, FALSE)) return TRUE; + if(AI_ActionPolymorph(FEAT_GREATER_WILDSHAPE_4, nSpell, TRUE)) return TRUE; // Humanoid shape // 682 Humanoid_Shape_Drow // 683 Humanoid_Shape_Lizardfolk // 684 Humanoid_Shape_KoboldAssa - if(AI_ActionPolymorph(AI_FEAT_EPIC_SHIFTER_INFINITE_HUMANOID_SHAPE, 682, 3, TRUE, FALSE)) return TRUE; - if(AI_ActionPolymorph(AI_FEAT_HUMANOID_SHAPE, 682, 3, TRUE)) return TRUE; + if(AI_ActionPolymorph(FEAT_EPIC_SHIFTER_INFINITE_HUMANOID_SHAPE, 682, 3, TRUE, FALSE)) return TRUE; + if(AI_ActionPolymorph(FEAT_HUMANOID_SHAPE, 682, 3, TRUE)) return TRUE; // 3 - Infinite and normal shapes // 3 - Not in any order (doh!) // 670 Greater_Wild_Shape_Basilisk // 673 Greater_Wild_Shape_Drider // 674 Greater_Wild_Shape_Manticore // Random choose one - iSpell = 670; + nSpell = 670; switch(d3()) { - case i1: iSpell = 670; break; - case i2: iSpell = 673; break; - case i3: iSpell = 674; break; + case 1: nSpell = 670; break; + case 2: nSpell = 673; break; + case 3: nSpell = 674; break; } - if(AI_ActionPolymorph(AI_FEAT_EPIC_SHIFTER_INFINITE_WILDSHAPE_3, iSpell, FALSE, TRUE, FALSE)) return TRUE; - if(AI_ActionPolymorph(AI_FEAT_GREATER_WILDSHAPE_3, iSpell, FALSE, TRUE)) return TRUE; + if(AI_ActionPolymorph(FEAT_EPIC_SHIFTER_INFINITE_WILDSHAPE_3, nSpell, FALSE, TRUE, FALSE)) return TRUE; + if(AI_ActionPolymorph(FEAT_GREATER_WILDSHAPE_3, nSpell, TRUE)) return TRUE; // 2 - Infinite and normal shapes // 2 - Not in any order (doh!) // 672 Greater_Wild_Shape_Harpy // 678 Greater_Wild_Shape_Gargoyle // 680 Greater_Wild_Shape_Minotaur - if(AI_ActionPolymorph(AI_FEAT_EPIC_SHIFTER_INFINITE_WILDSHAPE_2, iSpell, FALSE, TRUE, FALSE)) return TRUE; - if(AI_ActionPolymorph(AI_FEAT_GREATER_WILDSHAPE_2, iSpell, FALSE, TRUE)) return TRUE; + if(AI_ActionPolymorph(FEAT_EPIC_SHIFTER_INFINITE_WILDSHAPE_2, nSpell, FALSE, TRUE, FALSE)) return TRUE; + if(AI_ActionPolymorph(FEAT_GREATER_WILDSHAPE_2, nSpell, TRUE)) return TRUE; // 1 - Infinite and normal shapes - In order // 658 Greater_Wild_Shape_Wyrmling_Red // 659 Greater_Wild_Shape_Wyrmling_Blue // 660 Greater_Wild_Shape_Wyrmling_Black // 661 Greater_Wild_Shape_Wyrmling_White // 662 Greater_Wild_Shape_Wyrmling_Green - if(AI_ActionPolymorph(AI_FEAT_EPIC_SHIFTER_INFINITE_WILDSHAPE_1, 658, 5, TRUE, FALSE)) return TRUE; - if(AI_ActionPolymorph(AI_FEAT_GREATER_WILDSHAPE_1, 658, 5, TRUE)) return TRUE; + if(AI_ActionPolymorph(FEAT_EPIC_SHIFTER_INFINITE_WILDSHAPE_1, 658, 5, TRUE, FALSE)) return TRUE; + if(AI_ActionPolymorph(FEAT_GREATER_WILDSHAPE_1, 658, 5, TRUE)) return TRUE; // We can have items for this polymorph spell :-) - if(AI_ActionCastSpell(SPELL_TENSERS_TRANSFORMATION, SpellEnhSelf, OBJECT_SELF, i16, ItemEnhSelf, PotionEnh)) return TRUE; + if(AI_ActionCastSpell(SPELL_TENSERS_TRANSFORMATION, OBJECT_SELF, 16)) return TRUE; // Animal wildshape // 401 Wild_Shape_BROWN_BEAR @@ -14320,7 +14335,7 @@ int AI_AttemptPolyMorph() // 403 Wild_Shape_WOLF // 404 Wild_Shape_BOAR // 405 Wild_Shape_BADGER - if(AI_ActionPolymorph(AI_FEAT_EPIC_DRUID_INFINITE_WILDSHAPE, 401, 5, TRUE, FALSE)) return TRUE; + if(AI_ActionPolymorph(FEAT_EPIC_DRUID_INFINITE_WILDSHAPE, 401, 5, TRUE, FALSE)) return TRUE; if(AI_ActionPolymorph(FEAT_WILD_SHAPE, 401, 5, TRUE)) return TRUE; // Shapechange into - Troll, Pixie, Uber Hulk, Giant Spider, Zombie @@ -14329,15 +14344,15 @@ int AI_AttemptPolyMorph() // 389 Polymorph_UMBER_HULK // 390 Polymorph_PIXIE // 391 Polymorph_ZOMBIE - if(AI_ActionPolymorph(SPELL_POLYMORPH_SELF, 387, 5, TRUE)) return TRUE; + if(AI_ActionPolymorph(SPELL_POLYMORPH_SELF, 387, 5)) return TRUE; } - else /*Else we have it*/if(d10() <= i6) + else /*Else we have it*/if(d10() <= 6) { // The special abilities VIA. Shapechanger! // - We check our appearance and cast as appropriately. // - 60% base chance of casting an ability or spell. - switch(GlobalOurAppearance) + switch(GetAppearanceType(OBJECT_SELF)) { case APPEARANCE_TYPE_ELEMENTAL_WATER: case APPEARANCE_TYPE_ELEMENTAL_WATER_ELDER: @@ -14345,8 +14360,8 @@ int AI_AttemptPolyMorph() // We can cast Pulse Drown unlimited times/day. // Only use if above 50HP, and enemy has less then 20 Fortitude // and is within 4M - if(GlobalRangeToMeleeTarget < f4 && GlobalOurCurrentHP > i50 && - GetFortitudeSavingThrow(GlobalMeleeTarget) < i18) + if(GlobalRangeToMeleeTarget < 4.0 && GlobalOurCurrentHP > 50 && + GetFortitudeSavingThrow(GlobalMeleeTarget) < 18) { AI_ActionCastShifterSpell(SPELLABILITY_PULSE_DROWN); return TRUE; @@ -14359,7 +14374,7 @@ int AI_AttemptPolyMorph() { // Can use Pulse: Whirlwind unlimited times/day. // DC 14 or knockdown + some damage. - if(GlobalRangeToMeleeTarget < f4 && GetReflexSavingThrow(GlobalMeleeTarget) < i15) + if(GlobalRangeToMeleeTarget < 4.0 && GetReflexSavingThrow(GlobalMeleeTarget) < 15) { AI_ActionCastShifterSpell(SPELLABILITY_PULSE_WHIRLWIND); return TRUE; @@ -14367,14 +14382,14 @@ int AI_AttemptPolyMorph() return FALSE; } break; - // Wyrmling Breath Attacks are in the default dragon behaviour + // Wyrmling Breath Attacks are in the default dragon behavnOur // (we check for dragon appearance and check talents) case APPEARANCE_TYPE_MANTICORE: { // Can use Spike Attack (Greater Wild Shape Version) at // some reflex save or other. - if(GlobalRangeToMeleeTarget < f10 && - GetReflexSavingThrow(GlobalMeleeTarget) < (i18+ d6())) + if(GlobalRangeToMeleeTarget < 10.0 && + GetReflexSavingThrow(GlobalMeleeTarget) < (18+ d6())) { AI_ActionCastShifterSpell(AI_SPELLABILITY_GWILDSHAPE_SPIKES, GlobalMeleeTarget); return TRUE; @@ -14383,11 +14398,11 @@ int AI_AttemptPolyMorph() } break; // Drow/Drider : Don't bother with darkness. - case 491:// Harpy! + case APPEARANCE_TYPE_HARPY:// Harpy! 491 { // Harpysong - charm enemies. Will saving throw. - if(GlobalRangeToMeleeTarget < f4 && - GetWillSavingThrow(GlobalMeleeTarget) < (i14 + d4())) + if(GlobalRangeToMeleeTarget < 4.0 && + GetWillSavingThrow(GlobalMeleeTarget) < (14 + d4())) { AI_ActionCastShifterSpell(AI_SPELLABILITY_HARPYSONG); return TRUE; @@ -14401,8 +14416,8 @@ int AI_AttemptPolyMorph() // Limited petrify gaze attack // Pretty cool. if(GetLocalInt(OBJECT_SELF,"X2_GWILDSHP_LIMIT_" + IntToString(AI_SPELLABILITY_GWILDSHAPE_STONEGAZE)) && - GlobalRangeToMeleeTarget < f4 && - GetFortitudeSavingThrow(GlobalMeleeTarget) < (i14 + d4())) + GlobalRangeToMeleeTarget < 4.0 && + GetFortitudeSavingThrow(GlobalMeleeTarget) < (14 + d4())) { AI_ActionCastShifterSpell(AI_SPELLABILITY_GWILDSHAPE_STONEGAZE, GlobalMeleeTarget); return TRUE; @@ -14410,7 +14425,7 @@ int AI_AttemptPolyMorph() return FALSE; } break; - case 413: // Mind Flayer + case APPEARANCE_TYPE_MINDFLAYER: // Mind Flayer 413 { // Psionic Inertial Barrier ability - unlimited uses. if(!GetHasSpellEffect(AI_SPELLABILITY_PSIONIC_INERTIAL_BARRIER)) @@ -14421,7 +14436,7 @@ int AI_AttemptPolyMorph() // Else, we have Mind Blast. Limited uses, but stuns! else if(!GetHasSpellEffect(AI_SPELLABILITY_GWILDSHAPE_MINDBLAST, GlobalMeleeTarget) && GetLocalInt(OBJECT_SELF,"X2_GWILDSHP_LIMIT_" + IntToString(AI_SPELLABILITY_GWILDSHAPE_MINDBLAST)) && - GlobalRangeToMeleeTarget < f8) + GlobalRangeToMeleeTarget < 8.0) { AI_ActionCastShifterSpell(AI_SPELLABILITY_GWILDSHAPE_MINDBLAST); return TRUE; @@ -14429,14 +14444,14 @@ int AI_AttemptPolyMorph() return FALSE; } break; - // Dragons (ancient) checked for breath via. normal means. + // Vampires have domination gaze (limited uses) case APPEARANCE_TYPE_VAMPIRE_FEMALE: // Vampires case APPEARANCE_TYPE_VAMPIRE_MALE: // Vampires { // Limited Domination Gazes. if(GetLocalInt(OBJECT_SELF, "X2_GWILDSHP_LIMIT_" + IntToString(AI_SPELLABILITY_VAMPIRE_DOMINATION_GAZE)) && !GetHasSpellEffect(AI_SPELLABILITY_VAMPIRE_DOMINATION_GAZE, GlobalMeleeTarget) && - GetWillSavingThrow(GlobalMeleeTarget) < (i14 + d4()) && + GetWillSavingThrow(GlobalMeleeTarget) < (14 + d4()) && // This is a simple check for "have we got a dominated guy already" !AI_GetSpellTargetImmunity(GlobalImmunityDomination)) { @@ -14450,7 +14465,7 @@ int AI_AttemptPolyMorph() { // Unlimited invisibility, and unlimited "spectre attack". // 60% chance of using the spectre attack. - if(d10() <= i6 && GetFortitudeSavingThrow(GlobalMeleeTarget) < (i14 + d10()) && + if(d10() <= 6 && GetFortitudeSavingThrow(GlobalMeleeTarget) < (14 + d10()) && !GetIsImmune(GlobalMeleeTarget, IMMUNITY_TYPE_NEGATIVE_LEVEL)) { AI_ActionCastShifterSpell(AI_SPELLABILITY_SHIFTER_SPECTRE_ATTACK, GlobalMeleeTarget); @@ -14467,7 +14482,8 @@ int AI_AttemptPolyMorph() break; case APPEARANCE_TYPE_WILL_O_WISP: { - // Unlimited invisibility + // Unlimited invisibility. Uses the base 60% chance above to + // cast this. if(!AI_GetAIHaveEffect(GlobalEffectInvisible)) { AI_ActionCastShifterSpell(SPELL_INVISIBILITY); @@ -14476,20 +14492,20 @@ int AI_AttemptPolyMorph() return FALSE; } break; - case 428:// Azer man - case 429:// Azer female + case APPEARANCE_TYPE_AZER_MALE:// Azer man - 428 + case APPEARANCE_TYPE_AZER_FEMALE:// Azer female - 429 { // Unlimited fire attacks. // Burning hands and azer blast. // 80% chance of azer blast - if(GetReflexSavingThrow(GlobalMeleeTarget) < (i14 + d6()) && - d10() <= i8) + if(GetReflexSavingThrow(GlobalMeleeTarget) < (14 + d6()) && + d10() <= 8) { AI_ActionCastShifterSpell(AI_SPELLABILITY_AZER_FIRE_BLAST, GlobalMeleeTarget); return TRUE; } - // Else burning hands - if(GetReflexSavingThrow(GlobalMeleeTarget) < (i12 + d4())) + // Else burning hands might be attempted (also randomly) + if(GetReflexSavingThrow(GlobalMeleeTarget) < (12 + d4())) { AI_ActionCastShifterSpell(SPELL_BURNING_HANDS, GlobalMeleeTarget); return TRUE; @@ -14511,17 +14527,21 @@ int AI_AttemptPolyMorph() // - Dispel Magic // - Ice Storm // - Mestils Acid Breath. - // Randomise each one. Don't bother checking saves. - if(d10() <= i6) + // Randomise each one. + + // Dispel magic against the global dispel target. + if(d10() <= 6 && GlobalDispelTargetHighestDispel >= 1) { - AI_ActionCastShifterSpell(SPELL_DISPEL_MAGIC, GlobalMeleeTarget); + AI_ActionCastShifterSpell(SPELL_DISPEL_MAGIC, GlobalDispelTarget); return TRUE; } - else if(d10() <= i6) + // Ice storm, woo. + else if(d10() <= 6) { - AI_ActionCastShifterSpell(VFX_FNF_ICESTORM, GlobalMeleeTarget); + AI_ActionCastShifterSpell(SPELL_ICE_STORM, GlobalMeleeTarget); return TRUE; } + // Mestils Acid Breath. else { AI_ActionCastShifterSpell(SPELL_MESTILS_ACID_BREATH, GlobalMeleeTarget); @@ -14533,7 +14553,7 @@ int AI_AttemptPolyMorph() case APPEARANCE_TYPE_GOLEM_IRON: { // Unlimited spells Iron Golem Breath. - if(GetFortitudeSavingThrow(GlobalMeleeTarget) < i20) + if(GetFortitudeSavingThrow(GlobalMeleeTarget) < 20) { AI_ActionCastShifterSpell(SPELLABILITY_GOLEM_BREATH_GAS, GlobalMeleeTarget); return TRUE; @@ -14544,7 +14564,7 @@ int AI_AttemptPolyMorph() case APPEARANCE_TYPE_GOLEM_STONE: { // Unlimited spells: Throw rocks - if(GetReflexSavingThrow(GlobalMeleeTarget) < i20 + d6()) + if(GetReflexSavingThrow(GlobalMeleeTarget) < 20 + d6()) { AI_ActionCastShifterSpell(AI_SPELLABILITY_GIANT_HURL_ROCK, GlobalMeleeTarget); return TRUE; @@ -14552,9 +14572,8 @@ int AI_AttemptPolyMorph() return FALSE; } break; - case 302:// Kobold (assassin) + case APPEARANCE_TYPE_KOBOLD_A:// Kobold (assassin)302 { - // Unlimited invisibility // Unlimited invisibility if(!AI_GetAIHaveEffect(GlobalEffectInvisible)) { @@ -14575,7 +14594,7 @@ int AI_AttemptCounterSpell() { // Check for 5+ allies if counter spell in group. If <= 4, return FALSE if(GetSpawnInCondition(AI_FLAG_COMBAT_COUNTER_SPELL_ONLY_IN_GROUP, AI_COMBAT_MASTER) && - GlobalTotalAllies <= i4) + GlobalTotalAllies <= 4) { return FALSE; } @@ -14588,58 +14607,58 @@ int AI_AttemptCounterSpell() return FALSE; } object oLoopTarget, oCounterspellTarget; - int iCnt, iCasterLevels, iHighestLevels; + int nCnt, nCasterLevels, nHighestLevels; float fDistance; // Try and get a Arcane caster to counter if(GetSpawnInCondition(AI_FLAG_COMBAT_COUNTER_SPELL_ARCANE, AI_COMBAT_MASTER)) { // Loop seen enemies - must be within 20M and valid - iCnt = i1; - oLoopTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(iCnt)); - fDistance = GetLocalFloat(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(iCnt)); - while(GetIsObjectValid(oLoopTarget) && fDistance <= f20) + nCnt = 1; + oLoopTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(nCnt)); + fDistance = GetLocalFloat(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(nCnt)); + while(GetIsObjectValid(oLoopTarget) && fDistance <= 20.0) { // Check caster levels - iCasterLevels = GetLevelByClass(CLASS_TYPE_WIZARD, oLoopTarget) + + nCasterLevels = GetLevelByClass(CLASS_TYPE_WIZARD, oLoopTarget) + GetLevelByClass(CLASS_TYPE_SORCERER, oLoopTarget) + GetLevelByClass(CLASS_TYPE_BARD, oLoopTarget); // Check if higher. - if(iCasterLevels > iHighestLevels) + if(nCasterLevels > nHighestLevels) { - iHighestLevels = iCasterLevels; + nHighestLevels = nCasterLevels; oCounterspellTarget = oLoopTarget; } // Get next target - iCnt++; - oLoopTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(iCnt)); - fDistance = GetLocalFloat(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(iCnt)); + nCnt++; + oLoopTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(nCnt)); + fDistance = GetLocalFloat(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(nCnt)); } } // If not valid, might check divine if(!GetIsObjectValid(oCounterspellTarget) && - iHighestLevels >= GlobalOurHitDice / i3 && + nHighestLevels >= GlobalOurHitDice / 3 && GetSpawnInCondition(AI_FLAG_COMBAT_COUNTER_SPELL_DIVINE, AI_COMBAT_MASTER)) { // Loop seen enemies - must be within 20M and valid - iHighestLevels = FALSE; - iCnt = i1; - oLoopTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(iCnt)); - fDistance = GetLocalFloat(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(iCnt)); - while(GetIsObjectValid(oLoopTarget) && fDistance <= f20) + nHighestLevels = FALSE; + nCnt = 1; + oLoopTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(nCnt)); + fDistance = GetLocalFloat(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(nCnt)); + while(GetIsObjectValid(oLoopTarget) && fDistance <= 20.0) { // Check caster levels - iCasterLevels = GetLevelByClass(CLASS_TYPE_CLERIC, oLoopTarget) + + nCasterLevels = GetLevelByClass(CLASS_TYPE_CLERIC, oLoopTarget) + GetLevelByClass(CLASS_TYPE_DRUID, oLoopTarget); // Check if higher. - if(iCasterLevels > iHighestLevels) + if(nCasterLevels > nHighestLevels) { - iHighestLevels = iCasterLevels; + nHighestLevels = nCasterLevels; oCounterspellTarget = oLoopTarget; } // Get next target - iCnt++; - oLoopTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(iCnt)); - fDistance = GetLocalFloat(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(iCnt)); + nCnt++; + oLoopTarget = GetLocalObject(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(nCnt)); + fDistance = GetLocalFloat(OBJECT_SELF, ARRAY_ENEMY_RANGE_SEEN + IntToString(nCnt)); } } // Check if valid @@ -14659,6 +14678,7 @@ int AI_AttemptCounterSpell() int AI_StopWhatWeAreDoing() { // - New wrappered function + // * Includes fleeing and things. if(GetIsPerformingSpecialAction()) { return FALSE; @@ -14669,7 +14689,7 @@ int AI_StopWhatWeAreDoing() !GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_HIDING, AI_OTHER_COMBAT_MASTER)) { // Check for nearest person with trueseeing (which pierces hiding) - if(!GetIsObjectValid(GetNearestCreature(CREATURE_TYPE_HAS_SPELL_EFFECT, SPELL_TRUE_SEEING, OBJECT_SELF, i1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY))) + if(!GetIsObjectValid(GetNearestCreature(CREATURE_TYPE_HAS_SPELL_EFFECT, SPELL_TRUE_SEEING, OBJECT_SELF, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY))) { ClearAllActions(TRUE); SetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH, TRUE); @@ -14724,7 +14744,6 @@ void AI_DetermineCombatRound(object oIntruder = OBJECT_INVALID) // New check - If they are commandable, and no stupid ones. if(AI_GetAIHaveEffect(GlobalEffectUncommandable) || - AI_GetAIHaveEffect(GlobalEffectParalyze) || GetHasFeatEffect(FEAT_IMPROVED_KNOCKDOWN) || GetHasFeatEffect(FEAT_KNOCKDOWN) || GetAIOff()) @@ -14745,19 +14764,20 @@ void AI_DetermineCombatRound(object oIntruder = OBJECT_INVALID) // Equip best shield for most AC AI_EquipBestShield(); // Move away from the nearest heard enemy - GlobalNearestEnemyHeard = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, i1, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD, CREATURE_TYPE_IS_ALIVE, TRUE); - ActionMoveAwayFromObject(GlobalNearestEnemyHeard); + GlobalNearestEnemyHeard = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD, CREATURE_TYPE_IS_ALIVE, TRUE); + if(GetIsObjectValid(GlobalNearestEnemyHeard)) + { + ActionMoveAwayFromObject(GlobalNearestEnemyHeard, TRUE); + } + else + { + ActionMoveAwayFromLocation(GetLocation(OBJECT_SELF), TRUE); + } return; } // Tempory integer - int iTempInt; + int nTempInt; - // Set combat AI level - iTempInt = GetAIConstant(LAG_AI_LEVEL_COMBAT); - if(iTempInt > iM1 && GetAILevel() != iTempInt) - { - SetAILevel(OBJECT_SELF, iTempInt); - } // We stop - ClearAllActions normally // NOTE: This returns FALSE if we don't stop actions - and want to carry on // doing the thing before! like fleeing! (or we do it in the Stop thing). @@ -14768,6 +14788,14 @@ void AI_DetermineCombatRound(object oIntruder = OBJECT_INVALID) return; } + // If oIntruder is valid, we will face them (this helps stops sneak + // attacks if we then cast something on ourselves, ETC). + if(GetIsObjectValid(oIntruder)) + { + // Face the intruder. + SetFacingPoint(GetPosition(oIntruder)); + } + // Then we check all objects. we are going to perform a normal, or fleeing // action this round, or action call. @@ -14775,14 +14803,36 @@ void AI_DetermineCombatRound(object oIntruder = OBJECT_INVALID) AI_SetUpUs(); // We set up 2 other targets...for testing against ETC. - GlobalNearestEnemySeen = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, i1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE); - GlobalNearestEnemyHeard = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, i1, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD, CREATURE_TYPE_IS_ALIVE, TRUE); - // Valids? + // 1.4 - Simple loop here, we need to check AI_GetTargetSanityCheck(). + nTempInt = 1; + object oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, nTempInt); + while(GetIsObjectValid(oEnemy) && + !GetIsObjectValid(GlobalNearestEnemyHeard) && + !GetIsObjectValid(GlobalNearestEnemySeen)) + { + // Make a sanity check to use oEnemy at all. + if(AI_GetTargetSanityCheck(oEnemy)) + { + if(!GetIsObjectValid(GlobalNearestEnemyHeard) && GetObjectHeard(oEnemy)) + { + GlobalNearestEnemyHeard = oEnemy; + } + if(!GetIsObjectValid(GlobalNearestEnemySeen) && GetObjectSeen(oEnemy)) + { + GlobalNearestEnemySeen = oEnemy; + } + } + nTempInt++; + oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, nTempInt); + } + // Valid? GlobalValidNearestSeenEnemy = GetIsObjectValid(GlobalNearestEnemySeen); GlobalValidNearestHeardEnemy = GetIsObjectValid(GlobalNearestEnemyHeard); // Speakstring arrays - if(GlobalValidNearestHeardEnemy) + // * Don't speak when under silence or deafness. + if(GlobalValidNearestHeardEnemy && + !AI_GetAIHaveEffect(GlobalEffectSilenced) && !AI_GetAIHaveEffect(GlobalEffectDeaf)) { // Add in range checking here if(GetDistanceToObject(GlobalNearestEnemyHeard) < GetDistanceToObject(GlobalNearestEnemySeen)) @@ -14794,27 +14844,28 @@ void AI_DetermineCombatRound(object oIntruder = OBJECT_INVALID) GlobalRangeToNearestEnemy = GetDistanceToObject(GlobalNearestEnemySeen); } - iTempInt = GetHitDice(GlobalNearestEnemyHeard); + nTempInt = GetHitDice(GlobalNearestEnemyHeard); // THEM_OVER_US - They have 5+ levels over us. - if(iTempInt - i5 >= GlobalOurHitDice) + if(nTempInt - 5 >= GlobalOurHitDice) { SpeakArrayString(AI_TALK_ON_COMBAT_ROUND_THEM_OVER_US, TRUE); } // US_OVER_THEM - We have 5+ levels over them. - else if(GlobalOurHitDice - i5 >= iTempInt) + else if(GlobalOurHitDice - 5 >= nTempInt) { SpeakArrayString(AI_TALK_ON_COMBAT_ROUND_US_OVER_THEM, TRUE); } // EQUAL - Thier HD is within 4HD of us (EG: Us 10, them 10) - else //if(iTempInt - i4 <= GlobalOurHitDice && iTempInt + i4 >= GlobalOurHitDice) + else //if(iTempInt - 4 <= GlobalOurHitDice && iTempInt + 4 >= GlobalOurHitDice) { SpeakArrayString(AI_TALK_ON_COMBAT_ROUND_EQUAL, TRUE); } } else { - GlobalRangeToNearestEnemy = f0; + GlobalRangeToNearestEnemy = 0.0; } + // We may Dispel AOE's, move out of it, or ignore AOE's, EG Darkness. // Dragons may use this (though small chance) // Done before other things - best get out of some bad spells else they kill us! @@ -14822,12 +14873,44 @@ void AI_DetermineCombatRound(object oIntruder = OBJECT_INVALID) // another action if(AI_AttemptSpecialChecks()){return;} - // Sets up who to attack. - // - Uses oIntruder (to attack or move near) if anything. - // - We return TRUE if it ActionAttack's, or moves to an enemy - basically - // that we cannot do an action, but shouldn't search. False if normal. - // - We do this after AOE checking and special spells. - if(AI_SetUpAllObjects(oIntruder)){return;} + // If this is set to FALSE, we do not set up normal targets. + nTempInt = TRUE; + + // Check for our nearest heard enemy... + if(!GlobalValidNearestHeardEnemy) + { + // If we do not have a valid nearest heard enemy - but have got a seen + // enemy with etherealness - we attack that ethereal creature *now* + oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN); + if(!GetIgnoreNoFriend(oEnemy) && !GetIsEthereal(oEnemy)) + { + // We attack just this enemy. We specially set variables usually + // set in AI_SetUpAllObjects(). + GlobalMeleeTarget = oEnemy; + GlobalSpellTarget = oEnemy; + GlobalRangedTarget = oEnemy; + + // Make sure we cannot see oEnemy + GlobalSeenSpell = FALSE; + + nTempInt = FALSE; + } + else + { + // Else...normal behaviour with no enemy found + } + } + + // If nTempInt was set to FALSE above, we do not set targets normally. + if(nTempInt == TRUE) + { + // Sets up who to attack. + // - Uses oIntruder (to attack or move near) if anything. + // - We return TRUE if it ActionAttack's, or moves to an enemy - basically + // that we cannot do an action, but shouldn't search. False if normal. + // - We do this after AOE checking and special spells. + if(AI_SetUpAllObjects(oIntruder)){return;} + } // We then check if we have anyone to attack :-) This is a global integer. if(GlobalAnyValidTargetObject) @@ -14839,17 +14922,21 @@ void AI_DetermineCombatRound(object oIntruder = OBJECT_INVALID) if(AI_AttemptMoraleFlee()){return;} // Beholder and Mindflayer special AI - iTempInt = GetAIInteger(AI_SPECIAL_AI); - if(iTempInt == i1) + switch(GetAIInteger(AI_SPECIAL_AI)) { - // Beholder attacks. Should always return TRUE. Uses eye rays, - // casts spells, and teleports/flee's. - if(AI_AttemptBeholderCombat()){return;} - } - else if(iTempInt == i2) - { - // Special mindflayer things. This can fall through. - if(AI_AttemptMindflayerCombat()){return;} + case AI_SPECIAL_AI_BEHOLDER: + { + // Beholder attacks. Should always return TRUE. Uses eye rays, + // casts spells, and teleports/flee's. + if(AI_AttemptBeholderCombat()){return;} + } + break; + case AI_SPECIAL_AI_MINDFLAYER: + { + // Special mindflayer things. This can fall through. + if(AI_AttemptMindflayerCombat()){return;} + } + break; } // We will attempt to heal ourselves first as a prioritory. @@ -14905,7 +14992,7 @@ void AI_DetermineCombatRound(object oIntruder = OBJECT_INVALID) if(AI_AttemptMeleeAttackWrapper()){return;} } } - // Else behaviour - we don't have a target. Any healing, extra or anything + // Else behavnOur - we don't have a target. Any healing, extra or anything // here. Then searching, and finally walking waypoints. else { @@ -14930,12 +15017,21 @@ void AI_DetermineCombatRound(object oIntruder = OBJECT_INVALID) DeleteAIObject(AI_LAST_RANGED_TARGET); DeleteLocalObject(OBJECT_SELF, "NW_GENERIC_LAST_ATTACK_TARGET"); - // New: Search. This makes them go into search mode (if not already) and - // wanders around for an amount of time. We will search for AI_SEARCH_COOLDOWN_TIME - // seconds. - // - Search around oIntruder - might be a dead person. - Search(oIntruder); - // Search should activate this after a cirtain amount of time + // 1.4 changes: Search. + + // Search is initilised by just making sure we have a cirtain special + // action set to be done (IE: AI_SPECIAL_ACTIONS_SEARCH_AROUND) + // * The amount of rounds to search is set to AI_SEARCH_ROUNDS_REMAINING, and + // is decreased each round. If a new combat round occurs (usually does!) + // then, of course, this will be reset. + // * We search for nIntelligence rounds + 2. + + // If a Search will occur around a set object, we set it to AI_SEARCH_TARGET, + // and will move to that persons location first. + // * oTarget should be perhaps our last killed person, or somesuch. + SetAIInteger(AI_SEARCH_ROUNDS_REMAINING, GlobalIntelligence + 2); + SetAIObject(AI_SEARCH_TARGET, oIntruder); + SetCurrentAction(AI_SPECIAL_ACTIONS_SEARCH_AROUND); } @@ -14943,6 +15039,6 @@ void AI_DetermineCombatRound(object oIntruder = OBJECT_INVALID) /* - Add two "/"'s at the start of this line void main() { - AI_DetermineCombatRound(); + return; } //*/ diff --git a/_module/nss/j_inc_heartbeat.nss b/_module/nss/j_inc_heartbeat.nss index fa00cfcb..af2b9864 100644 --- a/_module/nss/j_inc_heartbeat.nss +++ b/_module/nss/j_inc_heartbeat.nss @@ -1,19 +1,29 @@ -/************************ [Heartbeat Include] ********************************** - Filename: J_Inc_Heartbeat -************************* [Heartbeat Include] ********************************** +/*/////////////////////// [Include - Heartbeat] //////////////////////////////// + Filename: J_INC_Heartbeat +///////////////////////// [Include - Heartbeat] //////////////////////////////// This contains any heartbeat function calls. Note that the heartbeat uses ExecuteScript for larget behaviours that are better split up so the heartbeat is as tiny as possible. -************************* [History] ******************************************** - 1.3 After Beta - Added -************************* [Workings] ******************************************* - This is included in nw_c2_default1 and j_ai_onheartbeat. +///////////////////////// [History] //////////////////////////////////////////// + 1.3 - After Beta - Added + 1.4 - TO DO + - Add in some function (see rest script) that resets if we are not in + combat + - Some more of the things we should do even if interrupted not the + heartbeat. - Contains things like in j_inc_other_ai -************************* [Arguments] ****************************************** + - Have moved "after combat searching" into here. It isn't long - but + it is more reliable. The special action is cancled if there is combat + going on, of course. +///////////////////////// [Workings] /////////////////////////////////////////// + This is included in nw_c2_default1 and J_AI_OnHeartbeat. + + Contains things like in J_INC_OTHER_AI, but only for the heartbeat event. + Keeps it cleaner to read. +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: N/A -************************* [Heartbeat Include] *********************************/ +///////////////////////// [Include - Heartbeat] //////////////////////////////*/ #include "J_INC_CONSTANTS" @@ -23,8 +33,6 @@ const string sWalkwayVarname = "NW_WALK_CONDITION"; const int NW_WALK_FLAG_CONSTANT = 0x00000002; // Checks: -// * Dead -// * Uncommandable // * No valid location // * Petrified, paralised, ETC. // Note: If sleep is found, it may apply Zzzz randomly, as well as stopping. @@ -42,68 +50,82 @@ int GetWalkCondition(int nCondition, object oCreature=OBJECT_SELF); // - Invisiblity (best) // - Haste/Expeditious Retreat void ActionCastFleeingSpells(); +// Cast fleeing spells. +// - Invisiblity (best) +// - Haste/Expeditious Retreat +void ActionCastMoveToCombatSpells(); -// Attempt to cast iSpell. TRUE if true. -int FleeingSpellCast(int iSpell); +// Attempt to cast nSpell. TRUE if true. +// Searching and fleeing spells use this. +int HeartbeatSpellCast(int nSpell); +// Used in Search(). This apply Trueseeing, See invisibility, or Invisiblity purge +// if we have neither of the 3 on us. +void SearchSpells(); + +// Returns TRUE if any of the animation settings are on. +int GetHasValidAnimations(); + +// Checks: +// * No valid location +// * Petrified, paralised, ETC. +// Note: If sleep is found, it may apply Zzzz randomly, as well as stopping. int JumpOutOfHeartBeat() { // What to return - int iReturn = FALSE; + int bReturn = FALSE; // Checks: - // * Dead + Uncommandable are in GetAIOff // * No valid location // * Petrified, paralised, ETC. // Note: If sleep is found, it may apply Zzzz randomly, as well as stopping. // Effect checking effect eCheck = GetFirstEffect(OBJECT_SELF); - int iEffectType; - while(GetIsEffectValid(eCheck) && iReturn == FALSE) + int nEffectType; + while(GetIsEffectValid(eCheck) && bReturn == FALSE) { - iEffectType = GetEffectType(eCheck); + nEffectType = GetEffectType(eCheck); // Sleep is special - if(iEffectType == EFFECT_TYPE_SLEEP) + if(nEffectType == EFFECT_TYPE_SLEEP) { - iReturn = i2;// This immediantly breaks. + bReturn = 2;// This immediantly breaks. } // ALL these stop heartbeat. - else if(iEffectType == EFFECT_TYPE_PARALYZE || iEffectType == EFFECT_TYPE_STUNNED || - iEffectType == EFFECT_TYPE_FRIGHTENED || /* Removed sleep above */ - iEffectType == EFFECT_TYPE_TURNED || iEffectType == EFFECT_TYPE_PETRIFY || - iEffectType == EFFECT_TYPE_DAZED || iEffectType == EFFECT_TYPE_TIMESTOP || - iEffectType == EFFECT_TYPE_DISAPPEARAPPEAR || iEffectType == EFFECT_TYPE_CHARMED || - iEffectType == EFFECT_TYPE_DOMINATED || iEffectType == EFFECT_TYPE_CONFUSED) + else if(nEffectType == EFFECT_TYPE_PARALYZE || nEffectType == EFFECT_TYPE_STUNNED || + nEffectType == EFFECT_TYPE_FRIGHTENED || /* Removed sleep above */ + nEffectType == EFFECT_TYPE_TURNED || nEffectType == EFFECT_TYPE_PETRIFY || + nEffectType == EFFECT_TYPE_DAZED || nEffectType == EFFECT_TYPE_TIMESTOP || + nEffectType == EFFECT_TYPE_DISAPPEARAPPEAR || nEffectType == EFFECT_TYPE_CHARMED || + nEffectType == EFFECT_TYPE_DOMINATED || nEffectType == EFFECT_TYPE_CONFUSED) { - iReturn = i1;// 1 = No Zzz. We continue to check for Zzz as well. + bReturn = 1;// 1 = No Zzz. We continue to check for Zzz as well. } eCheck = GetNextEffect(OBJECT_SELF); } // Do we fire the heartbeat event? - if(iReturn != FALSE) + if(bReturn != FALSE) { // If it is sleep... Zzzzz sometimes. - if(iReturn == i2 && d6() == i1) + if(bReturn == 2 && d6() == 1) { ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_SLEEP), OBJECT_SELF); } - FireUserEvent( - AI_FLAG_UDE_HEARTBEAT_EVENT, - EVENT_HEARTBEAT_EVENT);// Fire event 1001 + // Fire event 1001 + FireUserEvent(AI_FLAG_UDE_HEARTBEAT_EVENT, EVENT_HEARTBEAT_EVENT); } - return iReturn; + return bReturn; } // This checks fleeing, door bashing and so on, to stop the heartbeat // and perform the override special action, rather then run normal behaviour. int PerformSpecialAction() { - int iAction = GetCurrentSetAction(); + int nAction = GetCurrentSetAction(); object oTarget = GetAttackTarget(); object oRunTarget; - switch(iAction) + switch(nAction) { // - Leader has made me a runner. I must run to a nearby group calling // for help to get more men @@ -116,7 +138,7 @@ int PerformSpecialAction() { // Stop thinking we are a runner if we can see the run target ResetCurrentAction(); - AISpeakString(HELP_MY_FRIEND); + AISpeakString(AI_SHOUT_HELP_MY_FRIEND); return FALSE; } else @@ -124,7 +146,7 @@ int PerformSpecialAction() // Else run to them if(GetObjectHeard(oRunTarget)) { - AISpeakString(HELP_MY_FRIEND); + AISpeakString(AI_SHOUT_HELP_MY_FRIEND); } ClearAllActions(); ActionMoveToObject(oRunTarget, TRUE); @@ -149,26 +171,34 @@ int PerformSpecialAction() // at higher intelligence) things like Expeditious retreat. // - Only used once - one invisibility or haste. Deleted above. ActionCastFleeingSpells(); - ActionForceFollowObject(oRunTarget, f3); + ActionForceFollowObject(oRunTarget, 3.0); } else if(GetObjectSeen(oRunTarget)) { // If we see the flee target, reset targets ResetCurrentAction(); + // We will delete the local int (set to TRUE) which we - // stopped fleeing spells from + // stopped fleeing spells from being used DeleteAIInteger(AI_HEARTBEAT_FLEE_SPELLS); // Speak to allies to come :-) - AISpeakString(HELP_MY_FRIEND); - // Return FALSE. - return FALSE; + AISpeakString(AI_SHOUT_HELP_MY_FRIEND); + + // Also reset visual effect + RemoveFleeingVisual(); + + // And attack/heal self + ClearAllActions(); + DetermineCombatRound(); + // Return TRUE, we attacked + return TRUE; } else { // Else flee! if(GetObjectHeard(oRunTarget)) { - AISpeakString(HELP_MY_FRIEND); + AISpeakString(AI_SHOUT_HELP_MY_FRIEND); } ClearAllActions(); // New - cast fleeing spells. Important (and only used @@ -181,34 +211,53 @@ int PerformSpecialAction() } else { - // Check if we have bad intellgence, and we will run away - // from the nearest enemy if heard. - if(GetAIInteger(AI_INTELLIGENCE) <= i3) + // Check if we have bad intellgence, if we have, we will run away + // from the nearest enemy we can see or hear. + if(GetAIInteger(AI_INTELLIGENCE) <= 3) { - oRunTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, i1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE); + oRunTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE); if(!GetIsObjectValid(oRunTarget)) { - oRunTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, i1, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD, CREATURE_TYPE_IS_ALIVE, TRUE); + oRunTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD, CREATURE_TYPE_IS_ALIVE, TRUE); if(!GetIsObjectValid(oRunTarget)) { oRunTarget = GetLastHostileActor(); if(!GetIsObjectValid(oRunTarget) || GetIsDead(oRunTarget)) { + // If we do not have anyone to run from, stop ResetCurrentAction(); - return FALSE; + // Speak to allies to come :-) + AISpeakString(AI_SHOUT_HELP_MY_FRIEND); + // Also reset visual effect + RemoveFleeingVisual(); + // And attack/heal self + ClearAllActions(); + DetermineCombatRound(); + // Return TRUE, we attacked + return TRUE; } } } - // Run from enemy + // Run from enemy (1.4: Was oTarget, now oRunTarget) ClearAllActions(); - ActionMoveAwayFromObject(oTarget, TRUE, f50); + ActionMoveAwayFromObject(oRunTarget, TRUE, 50.0); return TRUE; } + // If we see the flee target, reset targets ResetCurrentAction(); - return FALSE; + // Speak to allies to come :-) + AISpeakString(AI_SHOUT_HELP_MY_FRIEND); + // Also reset visual effect + RemoveFleeingVisual(); + // And attack/heal self + ClearAllActions(); + DetermineCombatRound(); + // Return TRUE, we attacked/healed + return TRUE; } } break; + // If this is set, we are usually in combat - and must move out of an AOE. case AI_SPECIAL_ACTIONS_MOVE_OUT_OF_AOE: { // We must be X distance away from a cirtain AOE, if we are not, we @@ -233,6 +282,203 @@ int PerformSpecialAction() } } break; + // If this is the one, we will search around for enemies - usually done + // at the end of a combat round, it is more reliable here. + case AI_SPECIAL_ACTIONS_SEARCH_AROUND: + { + // If we are in combat, delete this special thing, and return FALSE + if(GetIsObjectValid(GetAttemptedSpellTarget()) || + GetIsObjectValid(GetAttemptedAttackTarget()) || + GetIsObjectValid(GetAttackTarget())) + { + // Reset, and return FALSE. + ResetCurrentAction(); + return FALSE; + } + // Added this so special actions do not get ignored (EG: healkitting) + // It will not do anything, but no heartbeat will be performed. These + // kind of actions happen at the end of combat (healing self of damage ETC) + // So, basically, will keep in mind it's still searching, but will leave + // it until no busy actions are being done. + else if(GetIsBusyWithAction()) + { + return TRUE; + } + + // We search for a cirtain number of rounds, set in the generic AI + // file, when we first start searching, or restart even. The generic + // AI will not actually do search actions, and if it finds no enemy, + // will probably just increase the integer to do more search rounds. + // * Will be intelligence + 2 to start. + int nRoundsRemaining = GetAIInteger(AI_SEARCH_ROUNDS_REMAINING); + // Decrease rounds remaining + nRoundsRemaining--; + // Set new one onto us to use next time + SetAIInteger(AI_SEARCH_ROUNDS_REMAINING, nRoundsRemaining); + // * Note: If nRoundsRemaining is 0 at the end of this function, we + // will remove this action as the current special one. + + // Get the target to move to/around + // * Can be invalid, but usually the creature we just killed or noticed + // lying on the ground. + object oTarget = GetAIObject(AI_SEARCH_TARGET); + + // Stop now (Small amounts of movement each time seem more cautious) + ClearAllActions(); + + // Check some spells. Cast one if we have no true seeing ETC. + SearchSpells(); + + // Stealth/search. + int bStealth = GetStealthMode(OBJECT_SELF); + int bSearch = GetDetectMode(OBJECT_SELF); + + // We perfere to hide again if we search if set to...sneaky! + if(GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_HIDING, AI_OTHER_COMBAT_MASTER)) + { + if(bStealth != STEALTH_MODE_ACTIVATED) + { + SetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH, TRUE); + } + } + else + { + // If we are hiding, stop to search (we shouldn't be - who knows?) + if(bStealth == STEALTH_MODE_ACTIVATED) + { + SetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH, FALSE); + } + // And search! + if(bSearch != DETECT_MODE_ACTIVE && !GetHasFeat(FEAT_KEEN_SENSE)) + { + SetActionMode(OBJECT_SELF, ACTION_MODE_DETECT, TRUE); + } + } + + // We check around the target, if there is one. + if(GetIsObjectValid(oTarget)) + { + // Move to the location of oTarget + ActionMoveToLocation(GetLocation(oTarget)); + + // If it is a chest ETC. We close it. + if(GetIsOpen(oTarget)) + { + if(GetObjectType(oTarget) == OBJECT_TYPE_DOOR) + { + ActionCloseDoor(oTarget); + } + else + { + // Close it + ActionDoCommand(DoPlaceableObjectAction(oTarget, PLACEABLE_ACTION_USE)); + } + } + } + // We will get nearest enemy at the very least + else + { + // Use nearest heard + object oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, + OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD); + if(GetIsObjectValid(oEnemy)) + { + // Move to location + ActionMoveToLocation(GetLocation(oEnemy)); + } + } + // Note: Here, we will return to spawn location after moving to the + // object, if it is a valid setting, else we do the normal randomwalk + if(GetSpawnInCondition(AI_FLAG_OTHER_RETURN_TO_SPAWN_LOCATION, AI_OTHER_MASTER)) + { + ActionMoveToLocation(GetAILocation(AI_RETURN_TO_POINT)); + } + else + { + // 72: "[Search] Searching, No one to attack. [Rounds Remaining] " + IntToString(nRoundsRemaining) + ". [Possible target] " + GetName(oTarget) + DebugActionSpeakByInt(72, oTarget, nRoundsRemaining); + // Randomly walk. + ActionRandomWalk(); + } + // If we have 0 rounds left of searching time, we turn of this special + // action, walk waypoints, and probably rest. + if(nRoundsRemaining == 0) + { + // Rest after combat? + if(GetSpawnInCondition(AI_FLAG_OTHER_REST_AFTER_COMBAT, AI_OTHER_MASTER)) + { + // 71: "[Search] Resting" + DebugActionSpeakByInt(71); + // Yes - we use ActionRest(). It can possibly still fail if + // enemies are still around! + ActionRest(); + ActionWait(1.0); + } + else + { + // Else, just execute Walk Waypoints + ExecuteScript(FILE_WALK_WAYPOINTS, OBJECT_SELF); + } + // Delete this special action + ResetCurrentAction(); + } + // If we havn't bailed out early and returned FALSE (do normal hb) we + // will return TRUE, we have something to do at least. + return TRUE; + } + break; + // Move to combat - we buff (and only buff again after 1 minute of running) + // and either follow the person who wants us to help them, or we will run to the + // location set. + // * Set only by "AI_HELP_MY_FRIEND_CONSTANT" at the moment. + case AI_SPECIAL_ACTIONS_MOVE_TO_COMBAT: + { + // We get a location to move to first + location lTarget = GetAILocation(AI_MOVE_TO_COMBAT_LOCATION); + object oObject = GetAreaFromLocation(lTarget); + + // Check if the location is valid + if(GetIsObjectValid(oObject) && GetArea(OBJECT_SELF) == oObject) + { + // Just move, rapidly, to lTarget. + ClearAllActions(); + + // Buff up an action + ActionCastMoveToCombatSpells(); + + // Move (fast) to that location + ActionMoveToLocation(lTarget, TRUE); + // If we see/hear combat, we'll attack + return TRUE; + } + else + { + // Get who we should "follow" or move to. + oObject = GetAIObject(AI_MOVE_TO_COMBAT_OBJECT); + + if(GetIsObjectValid(oObject)) + { + // Just move, rapidly, to oTarget. It isn't "real" following, + // but paced. Means it looks OK. Need to test - but should be OK. + ClearAllActions(); + + // Buff up an action + ActionCastMoveToCombatSpells(); + + // Move (fast) to that location + ActionMoveToObject(oTarget, TRUE); + // If we see/hear combat, we'll attack + return TRUE; + } + else + { + // Remove the special action and return FALSE + ResetCurrentAction(); + return FALSE; + } + } + } + break; } // Return false to carry on a normal heartbeat return FALSE; @@ -256,21 +502,103 @@ void ActionCastFleeingSpells() SetAIInteger(AI_HEARTBEAT_FLEE_SPELLS, TRUE); // Invisibilities - if(FleeingSpellCast(SPELL_IMPROVED_INVISIBILITY)) return; - if(FleeingSpellCast(SPELL_INVISIBILITY)) return; + if(HeartbeatSpellCast(SPELL_IMPROVED_INVISIBILITY)) return; + if(HeartbeatSpellCast(SPELL_INVISIBILITY)) return; // Haste - if(FleeingSpellCast(SPELL_MASS_HASTE)) return; - if(FleeingSpellCast(SPELL_HASTE)) return; - if(FleeingSpellCast(SPELL_EXPEDITIOUS_RETREAT)) return; + if(HeartbeatSpellCast(SPELL_MASS_HASTE)) return; + if(HeartbeatSpellCast(SPELL_HASTE)) return; + if(HeartbeatSpellCast(SPELL_EXPEDITIOUS_RETREAT)) return; } - -// Attempt to cast iSpell. TRUE if true. -int FleeingSpellCast(int iSpell) +// Cast fleeing spells. +// - Invisiblity (best) +// - Haste/Expeditious Retreat +void ActionCastMoveToCombatSpells() { - if(GetHasSpell(iSpell)) + // Timer to stop too many spells at once + if(GetLocalTimer(AI_TIMER_MOVE_TO_COMBAT_BUFF)) return; + + // We first will cast a preperation spell before jumping in! + // This is used once per minute. + SetLocalTimer(AI_TIMER_MOVE_TO_COMBAT_BUFF, 60.0); + + // We possibly cast a few spell first - stoneskin range, see + // invisible range, and invisibility range. + // Protection things + // * Cast 1 spell! + if(HeartbeatSpellCast(SPELL_PREMONITION)) return; + if(HeartbeatSpellCast(SPELL_GREATER_STONESKIN)) return; + if(HeartbeatSpellCast(SPELL_STONESKIN)) return; + // Invisibility range + if(HeartbeatSpellCast(SPELL_ETHEREALNESS)) return; + if(HeartbeatSpellCast(SPELL_IMPROVED_INVISIBILITY)) return; + if(HeartbeatSpellCast(SPELL_INVISIBILITY_SPHERE)) return; + if(HeartbeatSpellCast(SPELL_INVISIBILITY)) return; + // See invisible things + if(HeartbeatSpellCast(SPELL_TRUE_SEEING)) return; + if(HeartbeatSpellCast(SPELL_SEE_INVISIBILITY)) return; + + // Stealth! Only if we are good at it, of course. + + // Spawn in conditions for it + if(!GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_HIDING, AI_OTHER_COMBAT_MASTER)) + { + // Need skill or force on + if((GetSkillRank(SKILL_HIDE) - 4 >= GetHitDice(OBJECT_SELF)) || + GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_HIDING, AI_OTHER_COMBAT_MASTER)) + { + // Use hide + SetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH, TRUE); + return; + } + } +} +// Used in Search(). This apply Trueseeing, See invisibility, or Invisiblity purge +// if we have neither of the 3 on us. +void SearchSpells() +{ + effect eCheck = GetFirstEffect(OBJECT_SELF); + int nEffectType, bBreak; + while(GetIsEffectValid(eCheck) && bBreak == FALSE) + { + nEffectType = GetEffectType(eCheck); + if(nEffectType == EFFECT_TYPE_TRUESEEING || + nEffectType == EFFECT_TYPE_SEEINVISIBLE) + { + bBreak = TRUE; + } + eCheck = GetNextEffect(OBJECT_SELF); + } + // We have effects, stop. + if(bBreak == TRUE || GetHasSpellEffect(SPELL_INVISIBILITY_PURGE)) + { + return; + } + // Else we apply the best spell we have. + if(HeartbeatSpellCast(SPELL_TRUE_SEEING)) return; + if(HeartbeatSpellCast(SPELL_SEE_INVISIBILITY)) return; + if(HeartbeatSpellCast(SPELL_INVISIBILITY_PURGE)) return; +} +// Attempt to cast nSpell. TRUE if true. +int HeartbeatSpellCast(int nSpell) +{ + // 1.4: added check to see if has effect already + if(GetHasSpell(nSpell) && !GetHasSpellEffect(nSpell, OBJECT_SELF)) + { + ActionCastSpellAtObject(nSpell, OBJECT_SELF); + return TRUE; + } + return FALSE; +} + +// Returns TRUE if any of the animation settings are on. +int GetHasValidAnimations() +{ + int nCheck = GetLocalInt(OBJECT_SELF, NW_GENERIC_MASTER); + if((nCheck & NW_FLAG_AMBIENT_ANIMATIONS) || + (nCheck & NW_FLAG_AMBIENT_ANIMATIONS_AVIAN) || + (nCheck & NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS)) { - ActionCastSpellAtObject(iSpell, OBJECT_SELF); return TRUE; } return FALSE; diff --git a/_module/nss/j_inc_npc_attack.nss b/_module/nss/j_inc_npc_attack.nss index 0946ff63..572a5c8e 100644 --- a/_module/nss/j_inc_npc_attack.nss +++ b/_module/nss/j_inc_npc_attack.nss @@ -1,6 +1,6 @@ -/************************ [Combat Attack] ************************************** - Filename: j_inc_npc_attack -************************* [Combat Attack] ************************************** +/*/////////////////////// [Include - NPC (Combat) Attack] ////////////////////// + Filename: J_INC_NPC_Attack +///////////////////////// [Include - NPC (Combat) Attack] ////////////////////// What does this do? It is a wrapper/include for getting a creature to attack target X, or do @@ -11,17 +11,20 @@ And it also keeps Combat files SMALL! I uses Execute Script to fire the combat file, not include it here. -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.3 - Added -************************* [Workings] ******************************************* + 1.4 - TO DO: + - Bugfix a few things (copy/paste errors) + - Add example script to use (User defined events) +///////////////////////// [Workings] /////////////////////////////////////////// Include this in any conversation file or whatever, and mearly read the descriptions of the different functions, and it will do what it says :-) -************************* [Arguments] ****************************************** - Arguments: -************************* [Combat Attack] *************************************/ +///////////////////////// [Arguments] ////////////////////////////////////////// + Arguments: N/A +///////////////////////// [Include - NPC (Combat) Attack] ////////////////////*/ // Include the constants for the combat, spawn integers ETC. -#include "j_inc_constants" +#include "J_INC_CONSTANTS" // Hostile amount const int HOSTILE = -100;// Reputation to change to @@ -41,22 +44,22 @@ void DetermineSpeakCombatRoundNotMe(object oTarget, object oAttacker); // This is the main wrapper to get an NPC to attack in conversation. // * fDelay - The delay AFTER adjusting reputation, that we attack and shout -// * iPlot - The plot flag to set to (Usually FALSE). -// * iImmortal - The immortal flag to set to (Usually FALSE). +// * bPlot - The plot flag to set US to (Usually FALSE). +// * bImmortal - The immortal flag US to set to (Usually FALSE). // Example, how to keep flags already set: // HostileAttackPCSpeaker(0.0, GetPlotFlag(), GetImmortal()); -// * iAllAllies - This will determine combat rounds against the target, that are in 50.0M. False = Don't -void HostileAttackPCSpeaker(float fDelay = 0.0, int iPlot = FALSE, int iImmortal = FALSE, int iAllAllies = TRUE); +// * bAllAllies - This will determine combat rounds against the target, that are in 50.0M. False = Don't +void HostileAttackPCSpeaker(float fDelay = 0.0, int bPlot = FALSE, int bImmortal = FALSE, int bAllAllies = TRUE); // This will make our faction hostile to the target, and attack them. // * oTarget - The target object to attack // * fDelay - The delay AFTER adjusting reputation, that we attack and shout -// * iPlot - The plot flag to set to (Usually FALSE). -// * iImmortal - The immortal flag to set to (Usually FALSE). +// * bPlot - The plot flag to set US to (Usually FALSE). +// * bImmortal - The immortal flag US to set to (Usually FALSE). // Example, how to keep flags already set: // HostileAttackObject(oPC, 0.0, GetPlotFlag(), GetImmortal()); -// * iAllAllies - This will determine combat rounds against the target, that are in 50.0M. False = Don't -void HostileAttackObject(object oTarget, float fDelay = 0.0, int iPlot = FALSE, int iImmortal = FALSE, int iAllAllies = TRUE); +// * bAllAllies - This will determine combat rounds against the target, that are in 50.0M. False = Don't +void HostileAttackObject(object oTarget, float fDelay = 0.0, int bPlot = FALSE, int bImmortal = FALSE, int bAllAllies = TRUE); // This will make our faction hostile to the target, and shout. // * oTarget - The target object to shout about. @@ -65,25 +68,25 @@ void HostileAttackObject(object oTarget, float fDelay = 0.0, int iPlot = FALSE, void ShoutAbout(object oTarget); // This will make our faction hostile to ALL(!) PC's...in the area or game or range -// * iType - TYPE_ALL_PCS (1) is all PC's in the world. +// * nType - TYPE_ALL_PCS (1) is all PC's in the world. // - TYPE_ALL_AREA (2) is all PC's in the specific area. // - TYPE_IN_RANGE (3) is all PC's within fRange. -// * iPlot - The plot flag to set to (Usually FALSE). -// * iImmortal - The immortal flag to set to (Usually FALSE). -// * iAllAllies - This will determine combat rounds against the target, that are in 50.0M. False = Don't -void HostileAttackAllPCs(int iType = 1, float fRange = 40.0, int iPlot = FALSE, int iImmortal = FALSE, int iAllAllies = TRUE); +// * bPlot - The plot flag to set US to (Usually FALSE). +// * bImmortal - The immortal flag US to set to (Usually FALSE). +// * bAllAllies - This will determine combat rounds against the target, that are in 50.0M. False = Don't +void HostileAttackAllPCs(int nType = 1, float fRange = 40.0, int bPlot = FALSE, int bImmortal = FALSE, int bAllAllies = TRUE); // This will thier most damaging weapon, and wait to disarm it. // * fDuration - Delay until the weapon is withdrawn. -// * iRanged - if TRUE, it will equip a ranged weapon as a prioritory (EquipRanged call) -void EquipWeaponsDuration(float fDuration, int iRanged = FALSE); +// * bRanged - if TRUE, it will equip a ranged weapon as a prioritory (EquipRanged call) +void EquipWeaponsDuration(float fDuration, int bRanged = FALSE); // Disarms the persons right-hand-weapon void RemoveWeapons(); // Plays talks like "ATTACK!" and "Group Near Me" etc. -// * iLowest, iHighest - the High/Lowest value to use. +// * nLowest, nHighest - the High/Lowest value to use. // 0 = ATTACK, 1 = TAUNT, 2-4 = BATTLE(1-3), 5 = ENEMIES, 6 = GROUP, 7 = HELP. -void PlaySomeTaunt(int iLowest = 0, int iHighest = 7); +void PlaySomeTaunt(int nLowest = 0, int nHighest = 7); // Gets all allies of ourselves to attack oTarget // * oTarget - The target to attack. @@ -156,72 +159,75 @@ void DetermineSpeakCombatRoundNotMe(object oTarget, object oAttacker) } } // This is the main wrapper to get an NPC to attack in conversation. -// * iPlot - The plot flag to set to (Usually FALSE). -// * iImmortal - The immortal flag to set to (Usually FALSE). +// * fDelay - The delay AFTER adjusting reputation, that we attack and shout +// * bPlot - The plot flag to set US to (Usually FALSE). +// * bImmortal - The immortal flag US to set to (Usually FALSE). // Example, how to keep flags already set: -// AttackPCSpeaker(GetPlotFlag(), GetImmortal()); -// * iAllAllies - This will determine combat rounds against the target, that are in 50.0M. False = Don't -void HostileAttackPCSpeaker(float fDelay = 0.0, int iPlot = FALSE, int iImmortal = FALSE, int iAllAllies = TRUE) +// HostileAttackPCSpeaker(0.0, GetPlotFlag(), GetImmortal()); +// * bAllAllies - This will determine combat rounds against the target, that are in 50.0M. False = Don't +void HostileAttackPCSpeaker(float fDelay = 0.0, int bPlot = FALSE, int bImmortal = FALSE, int bAllAllies = TRUE) { // Get the PC object oPC = GetPCSpeaker(); + // Error checking if(!GetIsObjectValid(oPC) || GetIsDM(oPC)) return; - // Change the flags - if(GetPlotFlag() != iPlot) - SetPlotFlag(OBJECT_SELF, iPlot); - if(GetImmortal() != iImmortal) - SetImmortal(OBJECT_SELF, iPlot); + + // Change our flags for plot and immortal (usually turns them off) + SetPlotFlag(OBJECT_SELF, bPlot); + SetImmortal(OBJECT_SELF, bImmortal); // We make them hostile to our faction AdjustReputation(oPC, OBJECT_SELF, HOSTILE); + // Attack them SetLocalObject(OBJECT_SELF, AI_TO_ATTACK, oPC); if(fDelay > 0.0) { // Round start... - DelayCommand(fDelay, DetermineSpeakCombatRound(oPC, I_WAS_ATTACKED)); - if(iAllAllies) - DelayCommand(fDelay, AlliesAttack(oPC)); + DelayCommand(fDelay, DetermineSpeakCombatRound(oPC, AI_SHOUT_I_WAS_ATTACKED)); + if(bAllAllies) DelayCommand(fDelay, AlliesAttack(oPC)); } else { // Round start... - DetermineSpeakCombatRound(oPC, I_WAS_ATTACKED); - if(iAllAllies) AlliesAttack(oPC); + DetermineSpeakCombatRound(oPC, AI_SHOUT_I_WAS_ATTACKED); + if(bAllAllies) AlliesAttack(oPC); } } // This will make our faction hostile to the target, and attack them. // * oTarget - The target object to attack -// * iPlot - The plot flag to set to (Usually FALSE). -// * iImmortal - The immortal flag to set to (Usually FALSE). +// * fDelay - The delay AFTER adjusting reputation, that we attack and shout +// * bPlot - The plot flag to set US to (Usually FALSE). +// * bImmortal - The immortal flag US to set to (Usually FALSE). // Example, how to keep flags already set: -// AttackObject(oPC, GetPlotFlag(), GetImmortal()); -// * iAllAllies - This will determine combat rounds against the target, that are in 50.0M. False = Don't -void HostileAttackObject(object oTarget, float fDelay = 0.0, int iPlot = FALSE, int iImmortal = FALSE, int iAllAllies = TRUE) +// HostileAttackObject(oPC, 0.0, GetPlotFlag(), GetImmortal()); +// * bAllAllies - This will determine combat rounds against the target, that are in 50.0M. False = Don't +void HostileAttackObject(object oTarget, float fDelay = 0.0, int bPlot = FALSE, int bImmortal = FALSE, int bAllAllies = TRUE) { // Error checking if(!GetIsObjectValid(oTarget) || GetIsDM(oTarget)) return; - // Change the flags - if(GetPlotFlag() != iPlot) - SetPlotFlag(OBJECT_SELF, iPlot); - if(GetImmortal() != iImmortal) - SetImmortal(OBJECT_SELF, iPlot); + + // Change our flags for plot and immortal (usually turns them off) + SetPlotFlag(OBJECT_SELF, bPlot); + SetImmortal(OBJECT_SELF, bImmortal); // We make them hostile to our faction AdjustReputation(oTarget, OBJECT_SELF, HOSTILE); + // Attack them SetLocalObject(OBJECT_SELF, AI_TO_ATTACK, oTarget); + if(fDelay > 0.0) { // Round start... - DelayCommand(fDelay, DetermineSpeakCombatRound(oTarget, I_WAS_ATTACKED)); + DelayCommand(fDelay, DetermineSpeakCombatRound(oTarget, AI_SHOUT_I_WAS_ATTACKED)); } else { // Round start... - DetermineSpeakCombatRound(oTarget, I_WAS_ATTACKED); + DetermineSpeakCombatRound(oTarget, AI_SHOUT_I_WAS_ATTACKED); } } @@ -233,23 +239,23 @@ void ShoutAbout(object oTarget) // We make them hostile to our faction AdjustReputation(oTarget, OBJECT_SELF, HOSTILE); // And shout for others to attack - AISpeakString(CALL_TO_ARMS); + AISpeakString(AI_SHOUT_CALL_TO_ARMS); } // This will make our faction hostile to ALL(!) PC's...in the area or game or range -// * iType - TYPE_ALL_PCS (1) is all PC's in the world. +// * nType - TYPE_ALL_PCS (1) is all PC's in the world. // - TYPE_ALL_AREA (2) is all PC's in the specific area. // - TYPE_IN_RANGE (3) is all PC's within fRange. -// * iPlot - The plot flag to set to (Usually FALSE). -// * iImmortal - The immortal flag to set to (Usually FALSE). -// * iAllAllies - This will determine combat rounds against the target, that are in 50.0M. False = Don't -void HostileAttackAllPCs(int iType = 1, float fRange = 40.0, int iPlot = FALSE, int iImmortal = FALSE, int iAllAllies = TRUE) +// * bPlot - The plot flag to set US to (Usually FALSE). +// * bImmortal - The immortal flag US to set to (Usually FALSE). +// * bAllAllies - This will determine combat rounds against the target, that are in 50.0M. False = Don't +void HostileAttackAllPCs(int nType = 1, float fRange = 40.0, int bPlot = FALSE, int bImmortal = FALSE, int bAllAllies = TRUE) { object oPC, oToAttack; - int iShout, iCnt; + int bShout, nCnt; float fNearestEnemy = 10000.0; object oArea = GetArea(OBJECT_SELF); - switch(iType) + switch(nType) { case TYPE_ALL_PCS:// s all PC's in the world. { @@ -267,7 +273,7 @@ void HostileAttackAllPCs(int iType = 1, float fRange = 40.0, int iPlot = FALSE, oToAttack = oPC; } } - iShout = TRUE; + bShout = TRUE; } oPC = GetNextPC(); } @@ -275,8 +281,8 @@ void HostileAttackAllPCs(int iType = 1, float fRange = 40.0, int iPlot = FALSE, break; case TYPE_ALL_AREA:// is all PC's in the specific area. { - iCnt = 1; - oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC); + nCnt = 1; + oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC, OBJECT_SELF, nCnt); while(GetIsObjectValid(oPC)) { // Attack it! (if not a DM!) @@ -290,19 +296,18 @@ void HostileAttackAllPCs(int iType = 1, float fRange = 40.0, int iPlot = FALSE, oToAttack = oPC; } } - iShout = TRUE; + bShout = TRUE; } // Next one - iCnt++; - oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC, - OBJECT_SELF, iCnt); + nCnt++; + oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC, OBJECT_SELF, nCnt); } } break; case TYPE_IN_RANGE:// is all PC's within fRange. { - iCnt = 1; - oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC); + nCnt = 1; + oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC, OBJECT_SELF, nCnt); while(GetIsObjectValid(oPC) && GetDistanceToObject(oPC) <= fRange) { // Attack it! (if not a DM!) @@ -316,12 +321,11 @@ void HostileAttackAllPCs(int iType = 1, float fRange = 40.0, int iPlot = FALSE, oToAttack = oPC; } } - iShout = TRUE; + bShout = TRUE; } // Next one - iCnt++; - oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC, - OBJECT_SELF, iCnt); + nCnt++; + oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC, OBJECT_SELF, nCnt); } } break; @@ -329,17 +333,22 @@ void HostileAttackAllPCs(int iType = 1, float fRange = 40.0, int iPlot = FALSE, // Attack nearest one (if valid) if(GetIsObjectValid(oToAttack)) { + // Change our flags for plot and immortal (usually turns them off) + SetPlotFlag(OBJECT_SELF, bPlot); + SetImmortal(OBJECT_SELF, bImmortal); + DetermineSpeakCombatRound(oToAttack); - if(iAllAllies) AlliesAttack(oToAttack); + if(bAllAllies) AlliesAttack(oToAttack); } // Check if we shout - if(iShout) AISpeakString(CALL_TO_ARMS); + if(bShout) AISpeakString(AI_SHOUT_CALL_TO_ARMS); } -// This will thier most damaging melee weapon, and wait to disarm it. +// This will thier most damaging weapon, and wait to disarm it. // * fDuration - Delay until the weapon is withdrawn. -void EquipWeaponsDuration(float fDuration, int iRanged = FALSE) +// * bRanged - if TRUE, it will equip a ranged weapon as a prioritory (EquipRanged call) +void EquipWeaponsDuration(float fDuration, int bRanged = FALSE) { - if(iRanged) + if(bRanged) { // Equip any most damaging (don't use oVersus, incase it doesn't arm anything) ActionEquipMostDamagingRanged(); @@ -376,23 +385,23 @@ void RemoveWeapons() //:://///////////////////////////////////////////// //:: Created by : Jasperre //:://///////////////////////////////////////////*/ -void PlaySomeTaunt(int iLowest, int iHighest) +void PlaySomeTaunt(int nLowest, int nHighest) { - int iRandom = Random(iHighest) + iLowest; - int iVoice = VOICE_CHAT_ATTACK; - switch (iRandom) + int nRandom = Random(nHighest) + nLowest; + int nVoice = VOICE_CHAT_ATTACK; + switch (nRandom) { - case 0: iVoice = VOICE_CHAT_ATTACK; break; - case 1: iVoice = VOICE_CHAT_TAUNT; break; - case 2: iVoice = VOICE_CHAT_BATTLECRY1; break; - case 3: iVoice = VOICE_CHAT_BATTLECRY2; break; - case 4: iVoice = VOICE_CHAT_BATTLECRY3; break; - case 5: iVoice = VOICE_CHAT_ENEMIES; break; - case 6: iVoice = VOICE_CHAT_GROUP; break; - case 7: iVoice = VOICE_CHAT_HELP; break; - default: iVoice = VOICE_CHAT_ATTACK; break; + case 0: nVoice = VOICE_CHAT_ATTACK; break; + case 1: nVoice = VOICE_CHAT_TAUNT; break; + case 2: nVoice = VOICE_CHAT_BATTLECRY1; break; + case 3: nVoice = VOICE_CHAT_BATTLECRY2; break; + case 4: nVoice = VOICE_CHAT_BATTLECRY3; break; + case 5: nVoice = VOICE_CHAT_ENEMIES; break; + case 6: nVoice = VOICE_CHAT_GROUP; break; + case 7: nVoice = VOICE_CHAT_HELP; break; + default: nVoice = VOICE_CHAT_ATTACK; break; } - PlayVoiceChat(iVoice); + PlayVoiceChat(nVoice); } // Gets all allies of ourselves to attack oTarget @@ -400,16 +409,16 @@ void PlaySomeTaunt(int iLowest, int iHighest) void AlliesAttack(object oTarget) { if(!GetIsObjectValid(oTarget)) return; - int iCnt = 1; - object oAlly = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, OBJECT_SELF, iCnt, CREATURE_TYPE_IS_ALIVE, TRUE); + int nCnt = 1; + object oAlly = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, OBJECT_SELF, nCnt, CREATURE_TYPE_IS_ALIVE, TRUE); while(GetIsObjectValid(oAlly) && GetDistanceToObject(oAlly) <= 50.0) { // A slightly modified way to determine a combat round. // * oTarget - The target to attack // * oAttacker - The NPC who you want to determine a combat round, on oTarget DetermineSpeakCombatRoundNotMe(oTarget, oAlly); - iCnt++; - oAlly = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, OBJECT_SELF, iCnt, CREATURE_TYPE_IS_ALIVE, TRUE); + nCnt++; + oAlly = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, OBJECT_SELF, nCnt, CREATURE_TYPE_IS_ALIVE, TRUE); } } @@ -429,4 +438,10 @@ object GetNearestFriendCreature() return GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND); } -//void main(){} +// Debug: To compile this script full, uncomment all of the below. +/* - Add two "/"'s at the start of this line +void main() +{ + return; +} +//*/ diff --git a/_module/nss/j_inc_other_ai.nss b/_module/nss/j_inc_other_ai.nss index c8d59ba8..3a53669f 100644 --- a/_module/nss/j_inc_other_ai.nss +++ b/_module/nss/j_inc_other_ai.nss @@ -1,6 +1,6 @@ -/************************ [Include - Other AI Functions] *********************** - Filename: j_inc_other_ai -************************* [Include - Other AI Functions] *********************** +/*/////////////////////// [Include - Other AI Functions] /////////////////////// + Filename: J_INC_Other_AI +///////////////////////// [Include - Other AI Functions] /////////////////////// This contains fuctions and calls for these scripts: nw_c2_default2 - Percieve nw_c2_default3 - On Combat round End (For DetermineCombatRound() only) @@ -9,43 +9,44 @@ nw_c2_default6 - Damaged nw_c2_default8 - Disturbed nw_c2_defaultb - Spell cast at - Ones that don't use this use different/No includes. + + Ones that don't use this use different or no includes. HOPEFULLY it will make them faster, if they don't run combat. They use Execute Script to initiate combat. (With the override ones initiating the override version, the normal initiateing the normal). -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.3 - Added to speed up compilings and gather non-combat, or other workings in one place. -************************* [Workings] ******************************************* - This is included, by #include "J_INC_OTHER_AI" in other AI files. + 1.4 - TO DO: + - +///////////////////////// [Workings] /////////////////////////////////////////// + This is included in other AI files. They then use these functions in them scripts. -************************* [Arguments] ****************************************** +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: N/A -************************* Include - Other AI Functions] ***********************/ +///////////////////////// [Include - Other AI Functions] /////////////////////*/ // All constants. -#include "j_inc_constants" +#include "J_INC_CONSTANTS" -// Responds to it (like makinging the callers attacker thier target) +// Responds to it (like makinging the callers attacker thier target) // Called in OnConversation, and thats it. Use "ShouterFriend" To stop repeated GetIsFriend calls. void RespondToShout(object oShouter, int nShoutIndex); -// Gets the attacker or attakee of the target, which should be a friend +// Gets any possible target which is attacking oShouter (and isn't an ally) +// or who oShouter is attacking. oShouter should be a ally. object GetIntruderFromShout(object oShouter); // Shouts, or really brings all people in 60.0M(by default) to the "shouter" void ShoutBossShout(object oEnemy); -// Checks the target for a specific EFFECT_TYPE constant value -// Returns TRUE or FALSE. Used On Damaged for polymorph checking. -int GetHasEffect(int nEffectType, object oTarget = OBJECT_SELF); // This sets a morale penalty, to the exsisting one, if there is one. // It will reduce itself after fDuration (or if we die, ETC, it is deleted). // It is deleted at the end of combat as well. -void SetMoralePenalty(int iPenalty, float fDuration = 0.0); -// Removes iPenalty amount if it can. -void RemoveMoralePenalty(int iPenalty); +void SetMoralePenalty(int nPenalty, float fDuration = 0.0); +// Removes nPenalty amount if it can. +void RemoveMoralePenalty(int nPenalty); // At 5+ intelligence, we fire off any dispells at oPlaceables location void SearchDispells(object oPlaceable); @@ -66,6 +67,18 @@ void ActionMoveToEnemy(object oEnemy); // - They then run! (Badly) int PerceptionFleeFrom(object oEnemy); +// This wrappers commonly used code for a "Call to arms" type response. +// * We know of no enemy, so we will move to oAlly, who either called to +// us, or, well, we know of. +// * Calls out AI_SHOUT_CALL_TO_ARMS too. +void CallToArmsResponse(object oAlly); +// This wrappers commonly used code for a "I was attacked" type response. +// * We know there will be an enemy - or should be - and if we find one to attack +// (using GetIntruderFromShout()) - we attack it (and call another I was attacked) +// else, this will run CallToArmsResponse(oAlly); +// * Calls out AI_SHOUT_I_WAS_ATTACKED, or AI_SHOUT_CALL_TO_ARMS too. +void IWasAttackedResponse(object oAlly); + /*:://///////////////////////////////////////////// //:: Name: ShoutBossShout //:://///////////////////////////////////////////// @@ -74,16 +87,19 @@ int PerceptionFleeFrom(object oEnemy); //:://///////////////////////////////////////////*/ void ShoutBossShout(object oEnemy) { - if(GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_BOSS_MONSTER_SHOUT, AI_OTHER_COMBAT_MASTER)) + // 1.4 - Added a 5 minute cooldown timer for this. Thusly, if the boss lingers, + // so will the big shout they do. + if(GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_BOSS_MONSTER_SHOUT, AI_OTHER_COMBAT_MASTER) && + !GetLocalTimer(AI_TIMER_BOSS_SHOUT_COOLDOWN)) { // Get the range (and default to 60.0 M) - float fRange = IntToFloat(GetBoundriedAIInteger(AI_BOSS_MONSTER_SHOUT_RANGE, i60, 370)); + float fRange = IntToFloat(GetBoundriedAIInteger(AI_BOSS_MONSTER_SHOUT_RANGE, 60, 370)); // We loop through nearest not-seen, not-heard allies and get them // to attack the person. - int Cnt = i1; + int nCnt = 1; // Not seen, not heard... object oAlly = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, - OBJECT_SELF, Cnt, CREATURE_TYPE_IS_ALIVE, TRUE, + OBJECT_SELF, nCnt, CREATURE_TYPE_IS_ALIVE, TRUE, CREATURE_TYPE_PERCEPTION, PERCEPTION_NOT_SEEN_AND_NOT_HEARD); // Get who thier target is. object oThierTarget; @@ -103,13 +119,19 @@ void ShoutBossShout(object oEnemy) ExecuteScript(COMBAT_FILE, oAlly); } } - Cnt++; + nCnt++; oAlly = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, - OBJECT_SELF, Cnt, CREATURE_TYPE_IS_ALIVE, TRUE, + OBJECT_SELF, nCnt, CREATURE_TYPE_IS_ALIVE, TRUE, CREATURE_TYPE_PERCEPTION, PERCEPTION_NOT_SEEN_AND_NOT_HEARD); } - // Remove it :-) - DeleteSpawnInCondition(AI_FLAG_OTHER_COMBAT_BOSS_MONSTER_SHOUT, AI_OTHER_COMBAT_MASTER); + // * Don't speak when dead. 1.4 change (an obvious one to make) + if(CanSpeak()) + { + // Speak a string associated with this action being carried out + SpeakArrayString(AI_TALK_ON_LEADER_BOSS_SHOUT); + } + // Remove it for 5 minutes. + SetLocalTimer(AI_TIMER_BOSS_SHOUT_COOLDOWN, 300.0); } } // This MAY make us set a local timer to turn off hiding. @@ -122,7 +144,7 @@ void TurnOffHiding(object oIntruder) (GetObjectSeen(OBJECT_SELF, oIntruder) || GetObjectHeard(OBJECT_SELF, oIntruder))) { - SetLocalTimer(AI_TIMER_TURN_OFF_HIDE, f18); + SetLocalTimer(AI_TIMER_TURN_OFF_HIDE, 18.0); } } @@ -136,7 +158,8 @@ void HideOrClear() GetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH) == FALSE) { // Need skill or force on - if((GetSkillRank(SKILL_HIDE) - i4 >= GetHitDice(OBJECT_SELF)) || + int nRank = GetSkillRank(SKILL_HIDE); + if((nRank - 4 >= GetHitDice(OBJECT_SELF) && nRank >= 7) || GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_HIDING, AI_OTHER_COMBAT_MASTER)) { // Use hide @@ -173,12 +196,17 @@ void HideOrClear() I_WAS_ATTACKED = 1; If not in combat, attack the attackee of the shouter. Basically the best - way to get people to come and help us. + way to get people to come and help us, if we know of an attacker! + * Call this after we call DetermineCombatRound() to make sure that any + responses know of the attackers. It doesn't matter in actual fact, but + useful anyway. CALL_TO_ARMS = 3; If not in combat, determine combat round. By default, it should check any allies it can see/hear for thier targets and help them too. + * Better if we do not know of a target (and thusly our allies wouldn't know + of them as well) so the allies will move to us. HELP_MY_FRIEND = 4; @@ -208,179 +236,254 @@ void HideOrClear() //:://///////////////////////////////////////////// // Modified almost completely: Jasperre //:://///////////////////////////////////////////*/ -// Gets the attacker or attakee of the target, which should be a friend +// Gets any possible target which is attacking oShouter (and isn't an ally) +// or who oShouter is attacking. oShouter should be a ally. object GetIntruderFromShout(object oShouter) { - object oIntruder = GetAttackTarget(oShouter); - if(!GetIsObjectValid(oIntruder) || - GetIgnoreNoFriend(oIntruder)) + // First, get who they specifically want to attack (IE: Input target the shout + // is usually for) + object oIntruder = GetLocalObject(oShouter, AI_OBJECT + AI_ATTACK_SPECIFIC_OBJECT); + if(GetIgnoreNoFriend(oIntruder) || (!GetObjectSeen(oShouter) && !GetObjectHeard(oShouter))) { - oIntruder = GetLastHostileActor(oShouter); - if(GetIgnoreNoFriend(oIntruder)) + // Or, we look for the last melee target (which, at least, will be set) + oIntruder = GetLocalObject(oShouter, AI_OBJECT + AI_LAST_MELEE_TARGET); + if(GetIgnoreNoFriend(oIntruder) || (!GetObjectSeen(oShouter) && !GetObjectHeard(oShouter))) { - return OBJECT_INVALID; + // Current actual attack target of the shouter + oIntruder = GetAttackTarget(oShouter); + if(GetIgnoreNoFriend(oIntruder) || (!GetObjectSeen(oShouter) && !GetObjectHeard(oShouter))) + { + // Last hostile actor of the shouter + oIntruder = GetLastHostileActor(oShouter); + if(GetIgnoreNoFriend(oIntruder) || (!GetObjectSeen(oShouter) && !GetObjectHeard(oShouter))) + { + return OBJECT_INVALID; + } + } } } return oIntruder; } - +// Responds to it (like makinging the callers attacker thier target) +// Called in OnConversation, and thats it. Use "ShouterFriend" To stop repeated GetIsFriend calls. void RespondToShout(object oShouter, int nShoutIndex) { + // We use oIntruder to set who to attack. object oIntruder; - // Ones we don't care about if we are in combat... - if(nShoutIndex == i6) // "Attack specific object" + // Check nShoutIndex against known constants + switch(nShoutIndex) { - // If a leader, we set it as a local object, nothing more - if(GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_GROUP_LEADER, AI_OTHER_COMBAT_MASTER, oShouter)) + // Note: Not checked in sequential order (especially as they are constants). + // Instead, it is "Ones which if we are in combat, we still check" first. + + // Attack a specific object which the leader shouted about. + case AI_SHOUT_LEADER_ATTACK_TARGET_CONSTANT: { - oIntruder = GetLocalObject(oShouter, AI_ATTACK_SPECIFIC_OBJECT); - if(GetObjectSeen(oIntruder)) + // If a leader, we set it as a local object, nothing more + if(GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_GROUP_LEADER, AI_OTHER_COMBAT_MASTER, oShouter)) { - // Set local object to use in next DetermineCombatRound. - // We do not interrupt current acition (EG: Life saving stoneskins!) to re-direct. - SetAIObject(AI_ATTACK_SPECIFIC_OBJECT, oIntruder); - // 6 second delay. - SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, f6); + // 70. "[Shout] Reacting To Shout. [ShoutNo.] " + IntToString(iInput) + " [Shouter] " + GetName(oInput) + DebugActionSpeakByInt(70, oShouter, nShoutIndex); + + oIntruder = GetLocalObject(oShouter, AI_ATTACK_SPECIFIC_OBJECT); + if(GetObjectSeen(oIntruder)) + { + // Set local object to use in next DetermineCombatRound. + // We do not interrupt current acition (EG: Life saving stoneskins!) to re-direct. + SetAIObject(AI_ATTACK_SPECIFIC_OBJECT, oIntruder); + // 6 second delay. + SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, 6.0); + } } + return; } - return; - } - else if(nShoutIndex == i5)// "leader flee now" - { - // If a leader, we set it as a local object, nothing more - if(GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_GROUP_LEADER, AI_OTHER_COMBAT_MASTER, oShouter)) + break; + // Leader flee now - mass retreat to those who hear it. + case AI_SHOUT_LEADER_FLEE_NOW_CONSTANT: { - oIntruder = GetLocalObject(oShouter, AI_FLEE_TO); - // RUN! If intruder set is over 5.0M or no valid intruder - ClearAllActions(); + // If a leader, we set it as a local object, nothing more + if(GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_GROUP_LEADER, AI_OTHER_COMBAT_MASTER, oShouter)) + { + // Get who we are going to run too + oIntruder = GetLocalObject(oShouter, AI_FLEE_TO); + + // RUN! If intruder set is over 5.0M or no valid intruder + ClearAllActions(); + + // 70. "[Shout] Reacting To Shout. [ShoutNo.] " + IntToString(iInput) + " [Shouter] " + GetName(oInput) + DebugActionSpeakByInt(70, oShouter, nShoutIndex); + + // Set to run + SetCurrentAction(AI_SPECIAL_ACTIONS_FLEE); + // Turn on fleeing visual effect + ApplyFleeingVisual(); + + // Ignore talk for 12 seconds + SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, 12.0); + + // If valid, we run to the intruder + if(GetIsObjectValid(oIntruder)) + { + SetAIObject(AI_FLEE_TO, oIntruder); + ActionMoveToObject(oIntruder); + } + else // Else, we will just follow our leader! + { + SetAIObject(AI_FLEE_TO, oShouter); + ActionForceFollowObject(oShouter, 3.0); + } + } + return; + } + break; + + // All others (IE: We need to not be in combat for these) + // Anything that requires "DetermineCombatRound()" is here. + + // If the shout is number 8, it is "I was opened" and so can only be a + // placeable or door. + case AI_SHOUT_I_WAS_OPENED_CONSTANT: + { + // If we are already attacking, we ignore this shout. + if(CannotPerformCombatRound()) return; + + // We need somewhat complexe here - to get thier opener. + int nType = GetObjectType(oShouter); + // Check object type. If not a placeable nor door - stop script. + if(nType == OBJECT_TYPE_PLACEABLE || + nType == OBJECT_TYPE_DOOR) + { + // 70. "[Shout] Reacting To Shout. [ShoutNo.] " + IntToString(iInput) + " [Shouter] " + GetName(oInput) + DebugActionSpeakByInt(70, oShouter, nShoutIndex); + + // Now, we assign the placeable/door to set thier opener. + // We do this by just executing a script that does it. + ExecuteScript(FILE_SET_OPENER, oShouter); + // We can immediantly get this would-be attacker! + oIntruder = GetLocalObject(oShouter, AI_PLACEABLE_LAST_OPENED_BY); + if(GetIsObjectValid(oIntruder)) + { + // Attack + ClearAllActions(); + DetermineCombatRound(oShouter); + } + else + { + // Move to the object who shouted in detect mode + SetActionMode(OBJECT_SELF, ACTION_MODE_DETECT, TRUE); + ActionMoveToObject(oShouter, TRUE); + } + } + return; + } + break; + + // Call to arms requires nothing special. It is only called if + // There is no target the shouter has to attack specifically, rather then + // "I_WAS_ATTACKED" which would have. + case AI_SHOUT_CALL_TO_ARMS_CONSTANT: + { + // If we are already attacking, we ignore this shout. + if(CannotPerformCombatRound()) return; + + // Ignore for 6 seconds + SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, 6.0); + // 70. "[Shout] Reacting To Shout. [ShoutNo.] " + IntToString(iInput) + " [Shouter] " + GetName(oInput) DebugActionSpeakByInt(70, oShouter, nShoutIndex); - SetCurrentAction(AI_SPECIAL_ACTIONS_FLEE); - SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, f12); - if(GetIsObjectValid(oIntruder)) - { - SetAIObject(AI_FLEE_TO, oIntruder); - ActionMoveToObject(oIntruder); - } - else // Else, we will just follow our leader! - { - SetAIObject(AI_FLEE_TO, oShouter); - ActionForceFollowObject(oShouter, f3); - } + + // do standard Call to Arms response - IE: Move to oShouter + CallToArmsResponse(oShouter); + return; } - return; - } - // If the shout is number 8, it is "I was opened" and so can only be a - // placeable or door. - else if(nShoutIndex == i8)// "I was opened" - { - // We need somewhat complexe here - to get thier opener. - int nType = GetObjectType(oShouter); - // Check object type. If not a placeable nor door - stop script. - if(nType == OBJECT_TYPE_PLACEABLE || - nType == OBJECT_TYPE_DOOR) - { - // Now, we assign the placeable/door to set thier opener. - // - Need to check it works. - AssignCommand(oShouter, SetLocalObject(oShouter, PLACEABLE_LAST_OPENED_BY, GetLastOpenedBy())); - oIntruder = GetLocalObject(oShouter, PLACEABLE_LAST_OPENED_BY); - if(GetIsObjectValid(oIntruder)) - { - // Attack - ClearAllActions(); - DetermineCombatRound(oShouter); - } - } - } - // Else, we must not be in combat for the rest - else if(!CannotPerformCombatRound()) - { - // Call to arms requires nothing special - if(nShoutIndex == i3)// "Call to arms" - { - SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, f6); - // 70. "[Shout] Reacting To Shout. [ShoutNo.] " + IntToString(iInput) + " [Shouter] " + GetName(oInput) - DebugActionSpeakByInt(70, oShouter, nShoutIndex); - DetermineCombatRound(); - } - // Ones we can GetIntruderFromShout(oShouter); - if(nShoutIndex == i1 || // "I was attacked" - nShoutIndex == i4 || // "Help my friend" - nShoutIndex == i7) // "I was killed" - { - // Am not already fighting, and we don't ignore the intruder - oIntruder = GetIntruderFromShout(oShouter); - if(!GetIsObjectValid(oIntruder)) - { - return; - } - } - if(nShoutIndex == i1 || - nShoutIndex == i7) - { - // Morale penalty if they were killed - if(nShoutIndex == i7) - { - SetMoralePenalty((GetHitDice(oShouter)/i4), f18); - } - // Get intruder - // 70. "[Shout] Reacting To Shout. [ShoutNo.] " + IntToString(iInput) + " [Shouter] " + GetName(oInput) - DebugActionSpeakByInt(70, oShouter, nShoutIndex); - if(GetObjectSeen(oIntruder)) - { - // Stop, and attack, if we can see them! - ClearAllActions(); - SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, f9); - DetermineCombatRound(oIntruder); - DelayCommand(f2, AISpeakString(I_WAS_ATTACKED)); - } - else // Else the enemy is not seen - { - // If I can see neither the shouter nor the enemy - // stop what I am doing, and move to the attacker. - // - 1.3 change. They move to the attackers location (IE directed by ally) - ClearAllActions(); - SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, f6); - // This will move to oIntruder if nothing else - DetermineCombatRound(oIntruder); - // Shout to other allies, after a second. - DelayCommand(f2, AISpeakString(HELP_MY_FRIEND)); - } - } - else if(nShoutIndex == i4)// "Help my friend" + break; + // "Help my friend" is when a runner is running off (sorta fleeing) to + // get help. This will move to the location set on them to reinforce. + case AI_SHOUT_HELP_MY_FRIEND_CONSTANT: { + // If we are already attacking, we ignore this shout. + if(CannotPerformCombatRound()) return; + + // Ignore things for 6 seconds + SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, 6.0); + // We move to where the runner/shouter wants us. - location lMoveTo = GetLocalLocation(oShouter, AI_HELP_MY_FRIEND_LOCATION); + location lMoveTo = GetLocalLocation(oShouter, AI_LOCATION + AI_HELP_MY_FRIEND_LOCATION); + // 70. "[Shout] Reacting To Shout. [ShoutNo.] " + IntToString(iInput) + " [Shouter] " + GetName(oInput) DebugActionSpeakByInt(70, oShouter, nShoutIndex); - SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, f6); + + // If the location is valid if(GetIsObjectValid(GetAreaFromLocation(lMoveTo))) { + // New special action, but one that is overrided by combat + SetCurrentAction(AI_SPECIAL_ACTIONS_MOVE_TO_COMBAT); + SetAIObject(AI_MOVE_TO_COMBAT_OBJECT, oShouter); + SetAILocation(AI_MOVE_TO_COMBAT_LOCATION, lMoveTo); + + // Move to the location of the fight, attack. + ClearAllActions(); + // Move to the fights location ActionMoveToLocation(lMoveTo, TRUE); - ActionDoCommand(DetermineCombatRound()); + // When we see someone fighting, we'll DCR + return; } else { - // If we do not know of the friend attacker, we will follow them + // Else, if we do not know of the friends attackers, or the location + // they are at, we will follow them without casting any preperation + // spells. ClearAllActions(); - SetSpawnInCondition(AI_FLAG_COMBAT_FLAG_FAST_BUFF_ENEMY, AI_COMBAT_MASTER); - ActionForceFollowObject(oShouter, f3); - ActionDoCommand(DetermineCombatRound()); + ActionForceFollowObject(oShouter, 3.0); + // When we see an enemy, we'll attack! + return; } + return; } + break; + + // "I was attacked" is called when a creature is hurt or sees an enemy, + // and starts to attack them. This means they know who the enemy is - + // and thusly we can get it from them (Ususally GetLastHostileActor() + // "I was killed" is the same, but applies a morale penalty too + case AI_SHOUT_I_WAS_ATTACKED_CONSTANT: + case AI_SHOUT_I_WAS_KILLED_CONSTANT: + { + // If it was "I was killed", we apply a short morale penatly + // Penalty is "Hit dice / 4 + 1" (so always 1 minimum) for 18 seconds. + if(nShoutIndex == AI_SHOUT_I_WAS_KILLED_CONSTANT) + { + SetMoralePenalty(GetHitDice(oShouter)/4 + 1, 18.0); + } + + // If we are already attacking, we ignore this shout. + if(CannotPerformCombatRound()) return; + + // 70. "[Shout] Reacting To Shout. [ShoutNo.] " + IntToString(iInput) + " [Shouter] " + GetName(oInput) + DebugActionSpeakByInt(70, oShouter, nShoutIndex); + + // Ignore for 6 seconds + SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, 6.0); + + // Respond to oShouter's request for help - find thier target, and + // attack! + IWasAttackedResponse(oShouter); + return; + } + break; } } - +// At 5+ intelligence, we fire off any dispells at oPlaceables location void SearchDispells(object oPlaceable) { // No dispelling at low intelligence. - if(GetBoundriedAIInteger(AI_INTELLIGENCE) < i5) return; + if(GetBoundriedAIInteger(AI_INTELLIGENCE) < 5) return; location lPlace = GetLocation(oPlaceable); // Move closer if not seen. if(!GetObjectSeen(oPlaceable)) { // Move nearer - 6 M is out of the dispell range - ActionMoveToObject(oPlaceable, TRUE, f6); + ActionMoveToObject(oPlaceable, TRUE, 6.0); } // Dispell if we have any - at the location of oPlaceable. if(GetHasSpell(SPELL_LESSER_DISPEL)) @@ -401,41 +504,22 @@ void SearchDispells(object oPlaceable) } } -// Get Has Effect -// Checks to see if the target has a given -// effect, usually from a spell. Really useful this is. -int GetHasEffect(int nEffectType, object oTarget = OBJECT_SELF) -{ - effect eCheck = GetFirstEffect(oTarget); - while(GetIsEffectValid(eCheck)) - { - if(GetEffectType(eCheck) == nEffectType) - { - return TRUE; - break; - } - eCheck = GetNextEffect(oTarget); - } - return FALSE; -} - // This sets a morale penalty, to the exsisting one, if there is one. // It will reduce itself (by the penalty) after fDuration (or if we die, ETC, it is deleted). // It is deleted at the end of combat as well. -void SetMoralePenalty(int iPenalty, float fDuration = 0.0) +void SetMoralePenalty(int nPenalty, float fDuration = 0.0) { - int iOriginal = GetAIInteger(AI_MORALE_PENALTY); - int iNew = iOriginal + iPenalty; - SetAIInteger(AI_MORALE_PENALTY, iNew); - DelayCommand(fDuration, RemoveMoralePenalty(iPenalty)); + int nNewPenalty = GetAIInteger(AI_MORALE_PENALTY) + nPenalty; + SetAIInteger(AI_MORALE_PENALTY, nNewPenalty); + DelayCommand(fDuration, RemoveMoralePenalty(nPenalty)); } -void RemoveMoralePenalty(int iPenalty) +// Removes nPenalty amount if it can. +void RemoveMoralePenalty(int nPenalty) { - int iOriginal = GetAIInteger(AI_MORALE_PENALTY); - int iNew = iOriginal - iPenalty; - if(iNew > 0 && !GetIsDead(OBJECT_SELF)) + int nNewPenalty = GetAIInteger(AI_MORALE_PENALTY) - nPenalty; + if(nNewPenalty > 0 && !GetIsDead(OBJECT_SELF)) { - SetAIInteger(AI_MORALE_PENALTY, iNew); + SetAIInteger(AI_MORALE_PENALTY, nNewPenalty); } else { @@ -478,10 +562,10 @@ int PerceptionFleeFrom(object oEnemy) // Valid run from target if(!GetIsObjectValid(oRunTarget)) { - oRunTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, i1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE); + oRunTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE); if(!GetIsObjectValid(oRunTarget)) { - oRunTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, i1, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD, CREATURE_TYPE_IS_ALIVE, TRUE); + oRunTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD, CREATURE_TYPE_IS_ALIVE, TRUE); if(!GetIsObjectValid(oRunTarget)) { oRunTarget = GetLastHostileActor(); @@ -495,12 +579,140 @@ int PerceptionFleeFrom(object oEnemy) } // Run from enemy ClearAllActions(); - ActionMoveAwayFromObject(oRunTarget, TRUE, f50); + ActionMoveAwayFromObject(oRunTarget, TRUE, 50.0); return TRUE; } // 0 or more morale. return FALSE; } +// This wrappers commonly used code for a "Call to arms" type response. +// * We know of no enemy, so we will move to oAlly, who either called to +// us, or, well, we know of. +// * Calls out AI_SHOUT_CALL_TO_ARMS too. +void CallToArmsResponse(object oAlly) +{ + // Shout to allies to attack, or be prepared. + AISpeakString(AI_SHOUT_CALL_TO_ARMS); + + // If we are over 2 meters away from oShouter, we move to them using + // the special action + if(GetDistanceToObject(oAlly) > 2.0 || !GetObjectSeen(oAlly)) + { + // New special action, but one that is overrided by combat + location lAlly = GetLocation(oAlly); + SetCurrentAction(AI_SPECIAL_ACTIONS_MOVE_TO_COMBAT); + SetAIObject(AI_MOVE_TO_COMBAT_OBJECT, oAlly); + SetAILocation(AI_MOVE_TO_COMBAT_LOCATION, lAlly); + + // Move to the location of the fight, attack. + ClearAllActions(); + // Move to the fights location + ActionMoveToLocation(lAlly, TRUE); + // When we see someone fighting, we'll DCR + return; + } + else + { + // Determine it anyway - we will search around oShouter + // if nothing is found...but we are near to the shouter + DetermineCombatRound(oAlly); + return; + } +} +// This wrappers commonly used code for a "I was attacked" type response. +// * We know there will be an enemy - or should be - and if we find one to attack +// (using GetIntruderFromShout()) - we attack it (and call another I was attacked) +// else, this will run CallToArmsResponse(oAlly); +// * Calls out AI_SHOUT_I_WAS_ATTACKED, or AI_SHOUT_CALL_TO_ARMS too. +void IWasAttackedResponse(object oAlly) +{ + // Get the indruder. This is either who oShouter is currently attacking, + // or the last attacker of them. + object oIntruder = GetIntruderFromShout(oAlly); + + // If valid, of course attack! + if(GetIsObjectValid(oIntruder)) + { + // 1.4 Note: + // * It used to check "Are they seen". Basically, this is redudant + // with the checks used in DetermineCombatRound(). It will do the + // searching using oIntruder whatever. + + // Stop, and attack + ClearAllActions(); + DetermineCombatRound(oIntruder); + + // Shout I was attacked - we've set our intruder now + AISpeakString(AI_SHOUT_I_WAS_ATTACKED); + return; + } + // If invalid, we act as if it was "Call to arms" type thing. + // Call to arms is better to use normally, of course. + else + { + // Shout to allies to attack, or be prepared. + AISpeakString(AI_SHOUT_CALL_TO_ARMS); + + // We see if they are attacking anything: + oIntruder = GetAttackTarget(oAlly); + if(!GetIsObjectValid(oIntruder)) + { + oIntruder = GetLocalObject(oAlly, AI_OBJECT + AI_LAST_MELEE_TARGET); + } + + // If valid, we will move to a point bisecting the intruder and oAlly, or + // move to oAlly. Should get interrupted once we see the attack target. + // * NEED TO TEST + if(GetIsObjectValid(oIntruder)) + { + // New special action, but one that is overrided by combat + vector vTarget = GetPosition(oIntruder); + vector vSource = GetPosition(OBJECT_SELF); + vector vDirection = vTarget - vSource; + float fDistance = VectorMagnitude(vDirection) / 2.0; + vector vPoint = VectorNormalize(vDirection) * fDistance + vSource; + location lTarget = Location(GetArea(OBJECT_SELF), vPoint, DIRECTION_NORTH); + + SetCurrentAction(AI_SPECIAL_ACTIONS_MOVE_TO_COMBAT); + SetAIObject(AI_MOVE_TO_COMBAT_OBJECT, oAlly); + SetAILocation(AI_MOVE_TO_COMBAT_LOCATION, lTarget); + + // Move to the location of the fight, attack. + ClearAllActions(); + // Move to the fights location + ActionMoveToLocation(lTarget, TRUE); + // When we see someone fighting, we'll DCR + return; + } + // If we are over 2 meters away from oShouter, we move to them using + // the special action + else if(GetDistanceToObject(oAlly) > 2.0 || !GetObjectSeen(oAlly)) + { + // New special action, but one that is overrided by combat + location lAlly = GetLocation(oAlly); + SetCurrentAction(AI_SPECIAL_ACTIONS_MOVE_TO_COMBAT); + SetAIObject(AI_MOVE_TO_COMBAT_OBJECT, oAlly); + SetAILocation(AI_MOVE_TO_COMBAT_LOCATION, lAlly); + + // Move to the location of the fight, attack. + ClearAllActions(); + // Move to the fights location + ActionMoveToLocation(lAlly, TRUE); + // When we see someone fighting, we'll DCR + return; + } + else + { + // Determine it anyway - we will search around oShouter + // if nothing is found...but we are near to the shouter + DetermineCombatRound(oAlly); + return; + } + } +} + + + // Debug: To compile this script full, uncomment all of the below. /* - Add two "/"'s at the start of this line diff --git a/_module/nss/j_inc_seteffects.nss b/_module/nss/j_inc_seteffects.nss index 6b48775c..9c0f891f 100644 --- a/_module/nss/j_inc_seteffects.nss +++ b/_module/nss/j_inc_seteffects.nss @@ -1,6 +1,6 @@ -/************************ [Set Effects Include] ******************************** - Filename: -************************* [Set Effects] **************************************** +/*/////////////////////// [Include - Set Effects] ////////////////////////////// + Filename: J_INC_SetEffects +///////////////////////// [Include - Set Effects] ////////////////////////////// This can be executed on a PC or NPC, and sets what thier current effects are - the hostile ones. @@ -9,22 +9,28 @@ It is meant to be more efficient then doing countless checks against other NPCs and PCs for what effects they already have on them. -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.3 - Added -************************* [Workings] ******************************************* + 1.4 - Changed so fear and stun was seperate. + Uncommandable still is now for any uncommandable effects. + + - TO DO + - Make the ability decrease into "light" "major" and so on, about 4 + ratings, each set as more decreases are present. +///////////////////////// [Workings] /////////////////////////////////////////// ExecuteScript - might not work faster. If so, it is easy to add into the generic AI and have oTarget to set to. It searches the code and sets 3 custom integers, but only once (so not during the loop) -************************* [Arguments] ****************************************** +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: N/A -************************* [Set Effects] ***************************************/ +///////////////////////// [Include - Set Effects] ////////////////////////////*/ #include "J_INC_CONSTANTS" // List (use Global to not conflict with the nwscript.nss!) -const int GlobalEffectUncommandable = 0x00000001;// Stun. Sleep. Fear. Turning. +const int GlobalEffectUncommandable = 0x00000001;// Stun. Sleep. Fear. Turning. Paralsis. Petrify. const int GlobalEffectSilenced = 0x00000002;// Eeek! const int GlobalEffectSlowed = 0x00000004;// Stop with haste. const int GlobalEffectUltravision = 0x00000008; @@ -35,7 +41,7 @@ const int GlobalEffectInvisible = 0x00000080; const int GlobalEffectDeaf = 0x00000100;// Ack! const int GlobalEffectHaste = 0x00000200; const int GlobalEffectPolymorph = 0x00000400;// Only attack -const int GlobalEffectBlindness = 0x00000800;// Oh no! +const int GlobalEffectBlindness = 0x00000800;// Oh no! Cannot see others to cast spells. const int GlobalEffectDisease = 0x00001000; const int GlobalEffectPoison = 0x00002000; const int GlobalEffectCurse = 0x00004000; @@ -47,13 +53,15 @@ const int GlobalEffectDazed = 0x00080000;// Special: 1.30 const int GlobalEffectEthereal = 0x00100000; const int GlobalEffectPetrify = 0x00200000; const int GlobalEffectParalyze = 0x00400000;// Divided from Uncommandable for healing of -//const int GlobalEffectAbilityDecrease = 0x00080000;// Ohh! Tingly! const int GlobalEffectSpellFailure = 0x00800000;// Makes sure spells are not cast under high failure. const int GlobalEffectDamageShield = 0x01000000;// All damage shields +const int GlobalEffectFear = 0x02000000;// 1.4. Remove fear + G.Rest. Removes. +const int GlobalEffectStun = 0x04000000;// 1.4. G.Rest. Removes. //int GlobalEffectAbilityDecrease = 0; // In combat include // These are Globals for spell effects, to not csat them on us again, and to // speed things up... +// These are *good* spells. This effect is only set up on us. const int GlobalHasStoneSkinProtections = 0x00000001; const int GlobalHasElementalProtections = 0x00000002; const int GlobalHasVisageProtections = 0x00000004; @@ -80,7 +88,7 @@ const int GlobalHasRegenerateSpell = 0x00400000; const int GlobalHasOwlsWisdomSpell = 0x00800000; const int GlobalHasSpellResistanceSpell = 0x01000000; const int GlobalHasSpellWarCrySpell = 0x02000000; -//const int GlobalHasElementalShieldSpell = 0x04000000; +//const int GlobalHasElementalShieldSpell = 0x04000000;// Is general effect const int GlobalHasDomainSpells = 0x08000000; const int GlobalHasDeflectionACSpell = 0x10000000; const int GlobalHasNaturalACSpell = 0x20000000; @@ -94,154 +102,173 @@ const int GlobalHasWeaponHelpSpell = 0x80000000; int TempEffectHex, TempSpellHex; // Sets up an effects thing to that -void AI_SetWeHaveEffect(int iEffectHex); +void AI_SetTargetHasEffect(int nEffectHex); // Sets we have spell iSpellHex's effects. -void AI_SetWeHaveSpellsEffect(int iSpellHex); +void AI_SetWeHaveSpellsEffect(int nSpellHex); // Sets up effects on oTarget void AI_SetEffectsOnTarget(object oTarget = OBJECT_SELF); // Simple return TRUE if it matches hex. // - Effects tested on oTarget -int AI_GetAIHaveEffect(int iEffectHex, object oTarget = OBJECT_SELF); +int AI_GetAIHaveEffect(int nEffectHex, object oTarget = OBJECT_SELF); // Simple return TRUE if it matches hex. -// - Uses oTarget -int AI_GetAIHaveSpellsEffect(int iSpellHex, object oTarget = OBJECT_SELF); +// * Can only be used on ourself. +int AI_GetAIHaveSpellsEffect(int nSpellHex); // Sets up an effects thing to that -void AI_SetWeHaveEffect(int iEffectHex) +void AI_SetTargetHasEffect(int nEffectHex) { - TempEffectHex = TempEffectHex | iEffectHex; + TempEffectHex = TempEffectHex | nEffectHex; } // Sets we have spell iSpellHex's effects. -void AI_SetWeHaveSpellsEffect(int iSpellHex) +void AI_SetWeHaveSpellsEffect(int nSpellHex) { - TempSpellHex = TempSpellHex | iSpellHex; + TempSpellHex = TempSpellHex | nSpellHex; } // Simple return TRUE if it matches hex. // - Effects tested on oTarget -int AI_GetAIHaveEffect(int iEffectHex, object oTarget = OBJECT_SELF) +int AI_GetAIHaveEffect(int nEffectHex, object oTarget = OBJECT_SELF) { - return (GetLocalInt(oTarget, AI_EFFECT_HEX) & iEffectHex); + return (GetLocalInt(oTarget, AI_EFFECT_HEX) & nEffectHex); } // Simple return TRUE if it matches hex. -// - Uses oTarget -int AI_GetAIHaveSpellsEffect(int iSpellHex, object oTarget = OBJECT_SELF) +// * Can only be used on ourself. +int AI_GetAIHaveSpellsEffect(int nSpellHex) { - return (GetLocalInt(oTarget, AI_SPELL_HEX) & iSpellHex); + return (GetLocalInt(OBJECT_SELF, AI_SPELL_HEX) & nSpellHex); } - +// Sets up effects on oTarget void AI_SetEffectsOnTarget(object oTarget = OBJECT_SELF) { TempEffectHex = FALSE; TempSpellHex = FALSE; // Checks our effects once. effect eCheck = GetFirstEffect(oTarget); - int iEffect, iEffectAbilityDecrease, iSpellID; + int nEffect, nEffectAbilityDecrease, nSpellID; // EFFECTS: // For ALL targets (that we will use), we set up effects on a system of Hexes. // like spawn in things. Replaces GetHasSpellEffect, except genralising - // IE we will NOT cast more than one of the stoneskin type things at once. while(GetIsEffectValid(eCheck)) { - iEffect = GetEffectType(eCheck); - switch(iEffect) + nEffect = GetEffectType(eCheck); + switch(nEffect) { case EFFECT_TYPE_INVALIDEFFECT: case EFFECT_TYPE_VISUALEFFECT: // Don't check these for spell values. break; - case EFFECT_TYPE_PARALYZE: - AI_SetWeHaveEffect(GlobalEffectParalyze); + case EFFECT_TYPE_PARALYZE: // Also makes you uncommandable + { + AI_SetTargetHasEffect(GlobalEffectParalyze); + AI_SetTargetHasEffect(GlobalEffectUncommandable); + } break; - case EFFECT_TYPE_STUNNED: - case EFFECT_TYPE_FRIGHTENED: + case EFFECT_TYPE_STUNNED: // Also makes you uncommandable + { + AI_SetTargetHasEffect(GlobalEffectStun); + AI_SetTargetHasEffect(GlobalEffectUncommandable); + } + break; + case EFFECT_TYPE_FRIGHTENED: // Also makes you uncommandable + { + AI_SetTargetHasEffect(GlobalEffectFear); + AI_SetTargetHasEffect(GlobalEffectUncommandable); + } + break; + // * Cannot remove these, but make you unable to move. case EFFECT_TYPE_SLEEP: case EFFECT_TYPE_TURNED: case EFFECT_TYPE_DISAPPEARAPPEAR:// Added for dragon flying - AI_SetWeHaveEffect(GlobalEffectUncommandable); + case EFFECT_TYPE_CONFUSED:// 1.4 added. wasn't in before + AI_SetTargetHasEffect(GlobalEffectUncommandable); break; case EFFECT_TYPE_DAZED: - AI_SetWeHaveEffect(GlobalEffectDazed); + AI_SetTargetHasEffect(GlobalEffectDazed); break; case EFFECT_TYPE_SILENCE: - AI_SetWeHaveEffect(GlobalEffectSilenced); + AI_SetTargetHasEffect(GlobalEffectSilenced); break; case EFFECT_TYPE_SLOW: - AI_SetWeHaveEffect(GlobalEffectSlowed); + AI_SetTargetHasEffect(GlobalEffectSlowed); break; case EFFECT_TYPE_ULTRAVISION: - AI_SetWeHaveEffect(GlobalEffectUltravision); + AI_SetTargetHasEffect(GlobalEffectUltravision); break; case EFFECT_TYPE_SEEINVISIBLE: - AI_SetWeHaveEffect(GlobalEffectSeeInvisible); + AI_SetTargetHasEffect(GlobalEffectSeeInvisible); break; // Caused by Beholder things mainly, but this stops any spell being // cast, not just, for example, arcane spells cast in armor. case EFFECT_TYPE_SPELL_FAILURE: - AI_SetWeHaveEffect(GlobalEffectSpellFailure); + AI_SetTargetHasEffect(GlobalEffectSpellFailure); break; // Penetrates darkness. case EFFECT_TYPE_TRUESEEING: - AI_SetWeHaveEffect(GlobalEffectTrueSeeing); + AI_SetTargetHasEffect(GlobalEffectTrueSeeing); break; // Timestop - IE don't cast same spell twice. case EFFECT_TYPE_TIMESTOP: - AI_SetWeHaveEffect(GlobalEffectTimestop); + AI_SetTargetHasEffect(GlobalEffectTimestop); break; // Invisibility/Improved (although improved only uses normal in the spell) // Sneak attack/whatever :-) // - include the spell EFFECT_TYPE_ETHEREAL. case EFFECT_TYPE_INVISIBILITY: case EFFECT_TYPE_IMPROVEDINVISIBILITY: - AI_SetWeHaveEffect(GlobalEffectInvisible); + AI_SetTargetHasEffect(GlobalEffectInvisible); break; // Deaf - spell failing of 20%, but still cast. case EFFECT_TYPE_DEAF: - AI_SetWeHaveEffect(GlobalEffectDeaf); + AI_SetTargetHasEffect(GlobalEffectDeaf); break; // Special invis. case EFFECT_TYPE_ETHEREAL: - AI_SetWeHaveEffect(GlobalEffectEthereal); + AI_SetTargetHasEffect(GlobalEffectEthereal); break; // Haste - so don't cast haste again and whatever. case EFFECT_TYPE_HASTE: - AI_SetWeHaveEffect(GlobalEffectHaste); + AI_SetTargetHasEffect(GlobalEffectHaste); break; // Haste - so don't cast haste again and whatever. case EFFECT_TYPE_POLYMORPH: - AI_SetWeHaveEffect(GlobalEffectPolymorph); + AI_SetTargetHasEffect(GlobalEffectPolymorph); break; // Blindness - oh no, can't see, only hear! case EFFECT_TYPE_BLINDNESS: - AI_SetWeHaveEffect(GlobalEffectBlindness); + AI_SetTargetHasEffect(GlobalEffectBlindness); break; // Damage shield = Elemental shield, wounding whispers, Death armor, mestals // sheth and so on. case EFFECT_TYPE_ELEMENTALSHIELD: - AI_SetWeHaveEffect(GlobalEffectDamageShield); + AI_SetTargetHasEffect(GlobalEffectDamageShield); break; // Things we may want to remove VIA cirtain spells, we set here - may as well. // Same setting as any other. // IF we can remove it (not confusion ETC of course) then we set it. case EFFECT_TYPE_DISEASE: - AI_SetWeHaveEffect(GlobalEffectDisease); + AI_SetTargetHasEffect(GlobalEffectDisease); break; case EFFECT_TYPE_POISON: - AI_SetWeHaveEffect(GlobalEffectPoison); + AI_SetTargetHasEffect(GlobalEffectPoison); break; // SoU Petrify + // Note: Also makes them uncommandable case EFFECT_TYPE_PETRIFY: - AI_SetWeHaveEffect(GlobalEffectPetrify); + { + AI_SetTargetHasEffect(GlobalEffectPetrify); + AI_SetTargetHasEffect(GlobalEffectUncommandable); + } break; case EFFECT_TYPE_CURSE: - AI_SetWeHaveEffect(GlobalEffectCurse); + AI_SetTargetHasEffect(GlobalEffectCurse); break; case EFFECT_TYPE_NEGATIVELEVEL: - AI_SetWeHaveEffect(GlobalEffectNegativeLevel); + AI_SetTargetHasEffect(GlobalEffectNegativeLevel); break; case EFFECT_TYPE_ABILITY_DECREASE: case EFFECT_TYPE_AC_DECREASE: @@ -252,24 +279,25 @@ void AI_SetEffectsOnTarget(object oTarget = OBJECT_SELF) case EFFECT_TYPE_SPELL_RESISTANCE_DECREASE: case EFFECT_TYPE_SKILL_DECREASE: // Special - we add one to this, to determine when to use restoration - iEffectAbilityDecrease++; + nEffectAbilityDecrease++; break; case EFFECT_TYPE_ENTANGLE: - AI_SetWeHaveEffect(GlobalEffectEntangle); + AI_SetTargetHasEffect(GlobalEffectEntangle); break; case EFFECT_TYPE_MOVEMENT_SPEED_DECREASE: - AI_SetWeHaveEffect(GlobalEffectMovementSpeedDecrease); + AI_SetTargetHasEffect(GlobalEffectMovementSpeedDecrease); break; case EFFECT_TYPE_DARKNESS: - AI_SetWeHaveEffect(GlobalEffectDarkness); + AI_SetTargetHasEffect(GlobalEffectDarkness); break; default: { - // Check spells we have on...so we don't cast over them! - iSpellID = GetEffectSpellId(eCheck); - if(iSpellID != iM1) + // Check spells *we* (1.4 change: now checks OBJECT_SELF) + // have on...so we don't cast over them! + nSpellID = GetEffectSpellId(eCheck); + if(nSpellID != -1 && oTarget == OBJECT_SELF) { - switch(iSpellID) + switch(nSpellID) { // All weapon things are on one variable. We cast the best. case SPELL_MAGIC_WEAPON: @@ -338,7 +366,7 @@ void AI_SetEffectsOnTarget(object oTarget = OBJECT_SELF) break; case SPELL_CATS_GRACE: case SPELL_GREATER_CATS_GRACE: - case AI_SPELL_HARPER_CATS_GRACE: // Harper + case AI_SPELLABILITY_HARPER_CATS_GRACE: // Harper AI_SetWeHaveSpellsEffect(GlobalHasCatsGraceSpell); break; case SPELL_CLAIRAUDIENCE_AND_CLAIRVOYANCE: @@ -361,7 +389,7 @@ void AI_SetEffectsOnTarget(object oTarget = OBJECT_SELF) break; case SPELL_EAGLE_SPLEDOR: case SPELL_GREATER_EAGLE_SPLENDOR: - case AI_SPELL_HARPER_EAGLE_SPLEDOR: // Harper + case AI_SPELLABILITY_HARPER_EAGLE_SPLEDOR: // Harper AI_SetWeHaveSpellsEffect(GlobalHasEaglesSpledorSpell); break; case SPELL_ENDURANCE: @@ -436,9 +464,13 @@ void AI_SetEffectsOnTarget(object oTarget = OBJECT_SELF) } DeleteLocalInt(oTarget, AI_ABILITY_DECREASE); DeleteLocalInt(oTarget, AI_EFFECT_HEX); - DeleteLocalInt(oTarget, AI_SPELL_HEX); + // Special - only we set spell hexs on ourselves. + if(oTarget == OBJECT_SELF) + { + DeleteLocalInt(oTarget, AI_SPELL_HEX); + SetLocalInt(oTarget, AI_SPELL_HEX, TempSpellHex); + } // Set final ones from temp integers - SetLocalInt(oTarget, AI_ABILITY_DECREASE, iEffectAbilityDecrease); + SetLocalInt(oTarget, AI_ABILITY_DECREASE, nEffectAbilityDecrease); SetLocalInt(oTarget, AI_EFFECT_HEX, TempEffectHex); - SetLocalInt(oTarget, AI_SPELL_HEX, TempSpellHex); } diff --git a/_module/nss/j_inc_setweapons.nss b/_module/nss/j_inc_setweapons.nss index a8f708f5..9e96a4d4 100644 --- a/_module/nss/j_inc_setweapons.nss +++ b/_module/nss/j_inc_setweapons.nss @@ -1,15 +1,23 @@ -/************************ [Include - Set Weapons] ****************************** +/*/////////////////////// [Include - Set Weapons] ////////////////////////////// Filename: J_Inc_Setweapons -************************* [Include - Set Weapons] ****************************** +///////////////////////// [Include - Set Weapons] ////////////////////////////// This holds all the stuff for setting up local objects for weapons we have or have not got - normally the best to worst. -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.0 - Put in include 1.3 - Fixed minor things, added arrays of weapons (for deul wielding) and heal kits and stuff added. Added to OnSpawn. -************************* [Workings] ******************************************* - This is included in "j_ai_setweapons" and executed from other places VIA it. + 1.4 - Removed item checking for wands etc. + TO DO: + - Perhaps remove healing kit code? Check in the general AI at start of combat? + - Perhaps add in the other feats? Maybe not + - Have a setting to allow a cirtain weapon type be favoured/be able to + override the default settings and set a weapon to use, in the spawn + script. + - Redo how potions and item spells are setup! +///////////////////////// [Workings] /////////////////////////////////////////// + This is included in "J_AI_SetWeapons" and executed from other places VIA it. This migth change, but not likely. It could be re-included OnSpawn at least for spawning in. @@ -35,44 +43,22 @@ The lower level ones are taken into account, however! And these are much more common. -************************* [Arguments] ****************************************** +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: N/A -************************* [Include - Set Weapons] *****************************/ +///////////////////////// [Include - Set Weapons] ////////////////////////////*/ -#include "j_inc_constants" +#include "J_INC_CONSTANTS" /*****Structure******/ -// Things we use throughout, saves time (and Get's) putting them here. -int ProfWizard, ProfDruid, ProfMonk, ProfElf, ProfRogue, ProfSimple, - ProfMartial, ProfExotic, ProfShield, -/* -int ProfWizard = FALSE; -int ProfDruid = FALSE; -int ProfMonk = FALSE; -int ProfElf = FALSE; -int ProfRogue = FALSE; -int ProfSimple = FALSE; -int ProfMartial = FALSE; -int ProfExotic = FALSE; -int ProfShield = FALSE; -*/ -// If we set have the right two-weapon fighting feats, this is set -/*int*/ProfTwoWeapons, // = FALSE; -// This contains our current size. -/*int*/CreatureSize, -/*int*/CreatureStrength, // = FALSE; -// This tracks the current item value (so less Get/Set). -/*int*/CurrentItemValue, // = FALSE; -/*int*/CurrentItemIsMighty, // = FALSE; -/*int*/CurrentItemIsUnlimited, // = FALSE; -/*int*/CurrentItemSize, // = FALSE; -/*int*/CurrentItemDamage, // = FALSE; // Special - Damage is set in the bigger arrays. -/*int*/CurrentItemType, // = -1; // Set to -1 in loop anyway. -// I'm scripting, not doing grammer here! -/*int*/HasArrows, // = FALSE; -/*int*/HasBolts, // = FALSE; -/*int*/HasBullets; // = FALSE; +// Things we use throughout, saves time (and Get's) putting them here. +// These are boolean proficiencies. They either have them...or not! +// After those, are other variables like size, strength, and value of the current item. +int bProfWizard, bProfDruid, bProfMonk, bProfElf, bProfRogue, bProfSimple, + bProfMartial, bProfExotic, bProfShield, bProfTwoWeapons, nCreatureSize, + nCreatureStrength, nCurrentItemValue, bCurrentItemIsMighty, bCurrentItemIsUnlimited, + nCurrentItemSize, nCurrentItemDamage, nCurrentItemType, bGotArrows, bGotBolts, + bGotBullets; // String for setting a value integer to an item const string SETWEP_VALUE = "VALUE"; @@ -123,16 +109,16 @@ void StoreShield(object oTarget, object oItem); // Uses right prefix to store the object to oTarget. void SWFinalAIObject(object oTarget, string sName, object oObject); // Uses right prefix to store the iInt to oTarget. -void SWFinalAIInteger(object oTarget, string sName, int iInt); +void SWFinalAIInteger(object oTarget, string sName, int nInt); // Deletes object with Prefix void SWDeleteAIObject(object oTarget, string sName); // Deletes integer with Prefix void SWDeleteAIInteger(object oTarget, string sName); // Sets the weapon to the array, in the right spot... -// If iSecondary is TRUE, it uses the weapon size, and creature size to modifiy -// the value. -void ArrayOfWeapons(string sArray, object oTarget, object oItem, int iValue, int iSecondary = FALSE); +// If bSecondary is TRUE, it uses the weapon size, and creature size to modifiy +// the value, IE: Sets it as the secondary weapon. +void ArrayOfWeapons(string sArray, object oTarget, object oItem, int nValue, int bSecondary = FALSE); // Deletes all the things in an array...set to sArray void DeleteDatabase(object oTarget, string sArray); // Deletes all things, before we start! @@ -161,15 +147,8 @@ void DeleteInts(object oTarget); int GetState(object oTarget); // This is the deletion of the values of weapons. void DeleteValueInts(object oTarget, string sArray); -// This moves the values from iMax to iNumberStart back one in the list. -void MoveArrayBackOne(string sArray, int iNumberStart, object oTarget, int iMax); -// Special: Apply EffectCutsceneImmobilize -void AI_SpecialActionApplyItem(object oTarget); -// Special: Remove EffectCutsceneImmobilize -void AI_SpecialActionRemoveItem(object oTarget); -// Gets a item talent value, no applying of EffectCutsceneImmobilize. -// - iTalent, 1-21. -void AI_SetItemTalentValue(int iTalent); +// This moves the values from nMax to nNumberStart back one in the list. +void MoveArrayBackOne(string sArray, int nNumberStart, object oTarget, int nMax); //:://///////////////////////////////////////////// //:: Name SetWeopens @@ -192,40 +171,28 @@ void SetWeapons(object oTarget = OBJECT_SELF) if(GetSpawnInCondition(AI_FLAG_OTHER_LAG_EQUIP_MOST_DAMAGING, AI_OTHER_MASTER)) return; // Gets the creature size, stores it... - CreatureSize = GetCreatureSize(oTarget); + nCreatureSize = GetCreatureSize(oTarget); // No need to take off strength. It is pulrey for mighty weapons, we // add on this bonus to the value. - CreatureStrength = GetAbilityModifier(ABILITY_STRENGTH, oTarget); - if(CreatureStrength < i0) - { - CreatureStrength = i0; - } + // Thusly, we always make it a minimum of 0. + nCreatureStrength = GetAbilityModifier(ABILITY_STRENGTH, oTarget); + if(nCreatureStrength < 0) nCreatureStrength = 0; + // Ints, globally set. - if(GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oTarget)) - ProfDruid = TRUE; - if(GetHasFeat(FEAT_WEAPON_PROFICIENCY_ELF, oTarget)) - ProfElf = TRUE; - if(GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oTarget)) - ProfExotic = TRUE; - if(GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oTarget)) - ProfMartial = TRUE; - if(GetHasFeat(FEAT_WEAPON_PROFICIENCY_MONK, oTarget)) - ProfMonk = TRUE; - if(GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oTarget)) - ProfRogue = TRUE; - if(GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oTarget)) - ProfSimple = TRUE; - if(GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oTarget)) - ProfWizard = TRUE; - if(GetHasFeat(FEAT_SHIELD_PROFICIENCY, oTarget)) - ProfShield = TRUE; - if(GetHasFeat(FEAT_TWO_WEAPON_FIGHTING, oTarget) || - GetHasFeat(FEAT_AMBIDEXTERITY, oTarget) || - GetHasFeat(FEAT_IMPROVED_TWO_WEAPON_FIGHTING, oTarget)) - { - ProfTwoWeapons = TRUE; - } - // Sorts the inventory, on oTarget, with CreatureSize of creature + bProfDruid = GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oTarget); + bProfElf = GetHasFeat(FEAT_WEAPON_PROFICIENCY_ELF, oTarget); + bProfExotic = GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oTarget); + bProfMartial = GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oTarget); + bProfMonk = GetHasFeat(FEAT_WEAPON_PROFICIENCY_MONK, oTarget); + bProfRogue = GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oTarget); + bProfSimple = GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oTarget); + bProfWizard = GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oTarget); + bProfShield = GetHasFeat(FEAT_SHIELD_PROFICIENCY, oTarget); + bProfTwoWeapons = (GetHasFeat(FEAT_TWO_WEAPON_FIGHTING, oTarget) || + GetHasFeat(FEAT_AMBIDEXTERITY, oTarget) || + GetHasFeat(FEAT_IMPROVED_TWO_WEAPON_FIGHTING, oTarget)); + + // Sorts the inventory, on oTarget, with nCreatureSize of creature SortInventory(oTarget); } @@ -246,41 +213,36 @@ void SortInventory(object oTarget) { // Note to self: Removed potion setting. THis is done each round in AI include // because it is probably better that way. - int nBase, nWeaponSize, iCnt; + int nBase, nWeaponSize, nCnt; object oItem, oHighestKit; - int iHealingKitsAmount, iItemValue; - int iRunningValue = i0; // For kits + int nHealingKitsAmount, nItemValue; + int nRunningValue = 0; // For kits - // Onto the slots - if we are checking them! - // Slots 4 and 5. (HTH weapons) - for(iCnt = INVENTORY_SLOT_RIGHTHAND; // 4 - iCnt <= INVENTORY_SLOT_LEFTHAND; // 5 - iCnt++) + // Slots 11, 12 and 13. (some ammo slots) + for(nCnt = INVENTORY_SLOT_ARROWS; //11 + nCnt <= INVENTORY_SLOT_BOLTS; //13 + nCnt++) { - oItem = GetItemInSlot(iCnt, oTarget); + oItem = GetItemInSlot(nCnt, oTarget); if(GetIsObjectValid(oItem)) { - CurrentItemType = GetBaseItemType(oItem); - CurrentItemSize = GetWeaponSize(oItem); - CurrentItemDamage = FALSE;// Reset - if(CurrentItemSize)// Is over 0 - { - DoEffectsOf(oTarget, oItem); - } + // Sets ammo counters using nCurrentItemType. + nCurrentItemType = GetBaseItemType(oItem); + SetAmmoCounters(oTarget); } } - // Slots 11, 12 and 13. (some ammo slots) - for(iCnt = INVENTORY_SLOT_ARROWS; //11 - iCnt <= INVENTORY_SLOT_BOLTS; //13 - iCnt++) + // Slots 4 and 5. (HTH weapons) + for(nCnt = INVENTORY_SLOT_RIGHTHAND; // 4 + nCnt <= INVENTORY_SLOT_LEFTHAND; // 5 + nCnt++) { - oItem = GetItemInSlot(iCnt, oTarget); + oItem = GetItemInSlot(nCnt, oTarget); if(GetIsObjectValid(oItem)) { - CurrentItemType = GetBaseItemType(oItem); - CurrentItemSize = GetWeaponSize(oItem); - CurrentItemDamage = FALSE;// Reset - if(CurrentItemSize) + nCurrentItemType = GetBaseItemType(oItem); + nCurrentItemSize = GetWeaponSize(oItem); + nCurrentItemDamage = FALSE;// Reset + if(nCurrentItemSize)// Is over 0 { DoEffectsOf(oTarget, oItem); } @@ -291,24 +253,25 @@ void SortInventory(object oTarget) while(GetIsObjectValid(oItem)) { // Added some else statements to speed it up - CurrentItemType = GetBaseItemType(oItem); - if(CurrentItemType == BASE_ITEM_HEALERSKIT) + nCurrentItemType = GetBaseItemType(oItem); + if(nCurrentItemType == BASE_ITEM_HEALERSKIT) { - iHealingKitsAmount++; - iItemValue = GetGoldPieceValue(oItem); + nHealingKitsAmount++; + nItemValue = GetGoldPieceValue(oItem); // Stacked kits be worth what they should be seperatly. - iItemValue = iItemValue/GetNumStackedItems(oItem); - if(iItemValue > iRunningValue) + nItemValue = nItemValue/GetNumStackedItems(oItem); + if(nItemValue > nRunningValue) { - iRunningValue = iItemValue; + nRunningValue = nItemValue; oHighestKit = oItem; } } // Else, is it a arrow, bolt or bullet? - else if(CurrentItemType == BASE_ITEM_ARROW || - CurrentItemType == BASE_ITEM_BOLT || - CurrentItemType == BASE_ITEM_BULLET) + else if(nCurrentItemType == BASE_ITEM_ARROW || + nCurrentItemType == BASE_ITEM_BOLT || + nCurrentItemType == BASE_ITEM_BULLET) { + // Sets ammo counters using nCurrentItemType. SetAmmoCounters(oTarget); } else @@ -316,9 +279,9 @@ void SortInventory(object oTarget) // Likely a weapon, so we check { // Only need current item size, if it is a weapon! - CurrentItemSize = GetWeaponSize(oItem); - CurrentItemDamage = FALSE;// Reset - if(CurrentItemSize)// Is over 0 (valid weapon) + nCurrentItemSize = GetWeaponSize(oItem); + nCurrentItemDamage = FALSE;// Reset + if(nCurrentItemSize)// Is over 0 (valid weapon) { // Do the appropriate enchantment issuse and so on. DoEffectsOf(oTarget, oItem); @@ -331,64 +294,48 @@ void SortInventory(object oTarget) // Set our shield (if any) SetShield(oTarget); // Need some, any! - if(iHealingKitsAmount > i0) + if(nHealingKitsAmount > 0) { // set healing kits (if any) SWFinalAIObject(oTarget, AI_VALID_HEALING_KIT_OBJECT, oHighestKit); // Set amount left - SWFinalAIInteger(oTarget, AI_VALID_HEALING_KITS, iHealingKitsAmount); - } - // Added in item setting functions. apply EffectCutsceneImmobilize, remove at end, but - // in the middle we do item talents. - if(!GetSpawnInCondition(AI_FLAG_OTHER_LAG_NO_ITEMS, AI_OTHER_MASTER, oTarget)) - { - AI_SpecialActionApplyItem(oTarget); - - // Loop talents (not ones we won't set however) - for(iCnt = i1; iCnt <= i15; iCnt++) - { - // Ignore healing ones. - if(iCnt != i4 && iCnt != i5) - { - AI_SetItemTalentValue(iCnt); - } - } - - AI_SpecialActionRemoveItem(oTarget); + SWFinalAIInteger(oTarget, AI_VALID_HEALING_KITS, nHealingKitsAmount); } // Delete things, FINALLY. really! I mean, this is it, it runs, as it is, // and the other things run off it as things are met...! DelayCommand(0.1, DeleteInts(oTarget)); } +// This will take the weapon size, and things, and apply the right base effects. void DoEffectsOf(object oTarget, object oItem) { // 1.3 = changed to switch statement. + // 1.4 - Minor bug (WEAPON_SIZE_SMALL, not CREATURE_SIZE_SMALL) fixed. // Note: Anything not done BaseEffects of cannot even be used by the character. - switch(CurrentItemSize) + switch(nCurrentItemSize) { // Tiny weapons - If we are under large size, and is a dagger or similar case WEAPON_SIZE_TINY: { - if(CreatureSize < CREATURE_SIZE_LARGE) BaseEffects(oTarget, oItem); + if(nCreatureSize < CREATURE_SIZE_LARGE) BaseEffects(oTarget, oItem); } break; // Small Weapons - If we are large (not giant) and size is like a shortsword case CREATURE_SIZE_SMALL: { - if(CreatureSize < CREATURE_SIZE_HUGE) BaseEffects(oTarget, oItem); + if(nCreatureSize < CREATURE_SIZE_HUGE) BaseEffects(oTarget, oItem); } break; // Medium weapons - If we are over tiny, and size is like a longsword case WEAPON_SIZE_MEDIUM: { - if(CreatureSize > CREATURE_SIZE_TINY) BaseEffects(oTarget, oItem); + if(nCreatureSize > CREATURE_SIZE_TINY) BaseEffects(oTarget, oItem); } break; // Large weapons - anything that is over small, and the size is like a spear case WEAPON_SIZE_LARGE: { - if(CreatureSize > WEAPON_SIZE_SMALL) BaseEffects(oTarget, oItem); + if(nCreatureSize > CREATURE_SIZE_SMALL) BaseEffects(oTarget, oItem); } break; } @@ -409,144 +356,144 @@ void DoEffectsOf(object oTarget, object oItem) void BaseEffects(object oTarget, object oItem) { // Reset value - CurrentItemValue = i0; + nCurrentItemValue = 0; if(GetIsObjectValid(oItem)) { if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_ABILITY_BONUS)) - CurrentItemValue += i8; + nCurrentItemValue += 8; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_AC_BONUS)) - CurrentItemValue += i5; + nCurrentItemValue += 5; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_AC_BONUS_VS_ALIGNMENT_GROUP)) - CurrentItemValue += i4; + nCurrentItemValue += 4; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_AC_BONUS_VS_DAMAGE_TYPE)) - CurrentItemValue += i4; + nCurrentItemValue += 4; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_AC_BONUS_VS_RACIAL_GROUP)) - CurrentItemValue += i4; + nCurrentItemValue += 4; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_AC_BONUS_VS_SPECIFIC_ALIGNMENT)) - CurrentItemValue += i3; + nCurrentItemValue += 3; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_ATTACK_BONUS)) - CurrentItemValue += i4; + nCurrentItemValue += 4; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_ATTACK_BONUS_VS_ALIGNMENT_GROUP)) - CurrentItemValue += i3; + nCurrentItemValue += 3; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_ATTACK_BONUS_VS_RACIAL_GROUP)) - CurrentItemValue += i3; + nCurrentItemValue += 3; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_ATTACK_BONUS_VS_SPECIFIC_ALIGNMENT)) - CurrentItemValue += i3; + nCurrentItemValue += 3; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_BASE_ITEM_WEIGHT_REDUCTION)) - CurrentItemValue += i3; + nCurrentItemValue += 3; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_BONUS_FEAT)) - CurrentItemValue += i6; + nCurrentItemValue += 6; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_BONUS_SPELL_SLOT_OF_LEVEL_N)) - CurrentItemValue += i2; + nCurrentItemValue += 2; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_CAST_SPELL)) - CurrentItemValue += i5; + nCurrentItemValue += 5; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_DAMAGE_BONUS)) - CurrentItemValue += i6; + nCurrentItemValue += 6; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_DAMAGE_BONUS_VS_ALIGNMENT_GROUP)) - CurrentItemValue += i4; + nCurrentItemValue += 4; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_DAMAGE_BONUS_VS_RACIAL_GROUP)) - CurrentItemValue += i4; + nCurrentItemValue += 4; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_DAMAGE_BONUS_VS_SPECIFIC_ALIGNMENT)) - CurrentItemValue += i4; + nCurrentItemValue += 4; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_DAMAGE_REDUCTION)) - CurrentItemValue += i8; + nCurrentItemValue += 8; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_DAMAGE_RESISTANCE)) - CurrentItemValue += i8; + nCurrentItemValue += 8; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_DAMAGE_VULNERABILITY)) - CurrentItemValue -= i3; + nCurrentItemValue -= 3; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_DARKVISION)) - CurrentItemValue += i3; + nCurrentItemValue += 3; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_DECREASED_ABILITY_SCORE)) - CurrentItemValue -= i4; + nCurrentItemValue -= 4; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_DECREASED_AC)) - CurrentItemValue -= i4; + nCurrentItemValue -= 4; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_DECREASED_ATTACK_MODIFIER)) - CurrentItemValue -= i3; + nCurrentItemValue -= 3; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_DECREASED_DAMAGE)) - CurrentItemValue -= i3; + nCurrentItemValue -= 3; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_DECREASED_ENHANCEMENT_MODIFIER)) - CurrentItemValue -= i5; + nCurrentItemValue -= 5; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_DECREASED_SAVING_THROWS)) - CurrentItemValue -= i4; + nCurrentItemValue -= 4; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_DECREASED_SAVING_THROWS_SPECIFIC)) - CurrentItemValue -= i3; + nCurrentItemValue -= 3; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_DECREASED_SKILL_MODIFIER)) - CurrentItemValue -= i2; + nCurrentItemValue -= 2; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_ENHANCEMENT_BONUS)) - CurrentItemValue += i7; + nCurrentItemValue += 7; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_ALIGNMENT_GROUP)) - CurrentItemValue += i6; + nCurrentItemValue += 6; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_RACIAL_GROUP)) - CurrentItemValue += i6; + nCurrentItemValue += 6; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_SPECIFIC_ALIGNEMENT)) - CurrentItemValue += i5; + nCurrentItemValue += 5; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_EXTRA_MELEE_DAMAGE_TYPE)) - CurrentItemValue += i1; + nCurrentItemValue += 1; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_EXTRA_RANGED_DAMAGE_TYPE)) - CurrentItemValue += i1; + nCurrentItemValue += 1; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_FREEDOM_OF_MOVEMENT)) - CurrentItemValue += i5; + nCurrentItemValue += 5; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_HASTE)) - CurrentItemValue += i12; + nCurrentItemValue += 12; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_HOLY_AVENGER)) - CurrentItemValue += i10; + nCurrentItemValue += 10; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_IMMUNITY_DAMAGE_TYPE)) - CurrentItemValue += i8; + nCurrentItemValue += 8; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_IMMUNITY_MISCELLANEOUS)) - CurrentItemValue += i10; + nCurrentItemValue += 10; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_IMMUNITY_SPECIFIC_SPELL)) - CurrentItemValue += i8; + nCurrentItemValue += 8; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_IMMUNITY_SPELL_SCHOOL)) - CurrentItemValue += i12; + nCurrentItemValue += 12; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_IMPROVED_EVASION)) - CurrentItemValue += i10; + nCurrentItemValue += 10; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_KEEN)) - CurrentItemValue += i7; + nCurrentItemValue += 7; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_LIGHT)) - CurrentItemValue += i1; + nCurrentItemValue += 1; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_MASSIVE_CRITICALS)) - CurrentItemValue += i2; + nCurrentItemValue += 2; // if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_MIND_BLANK)) -// CurrentItemValue += i4;// Do not think It exsists. +// nCurrentItemValue += 4;// Do not think It exsists. if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_MONSTER_DAMAGE)) - CurrentItemValue += i1; + nCurrentItemValue += 1; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_NO_DAMAGE)) - CurrentItemValue -= i10;// EEEKK! Bad bad bad!! + nCurrentItemValue -= 10;// EEEKK! Bad bad bad!! if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_ON_HIT_PROPERTIES)) - CurrentItemValue += i8;// Includes all vorpal and so on! + nCurrentItemValue += 8;// Includes all vorpal and so on! // if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_ON_MONSTER_HIT)) -// CurrentItemValue += i8;// Can't be on a weapon +// nCurrentItemValue += 8;// Can't be on a weapon if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_POISON)) - CurrentItemValue += i5; + nCurrentItemValue += 5; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_REGENERATION)) - CurrentItemValue += i8; + nCurrentItemValue += 8; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_REGENERATION_VAMPIRIC)) - CurrentItemValue += i6; + nCurrentItemValue += 6; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_SAVING_THROW_BONUS)) - CurrentItemValue += i5; + nCurrentItemValue += 5; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_SAVING_THROW_BONUS_SPECIFIC)) - CurrentItemValue += i4; + nCurrentItemValue += 4; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_SKILL_BONUS)) - CurrentItemValue += i2; + nCurrentItemValue += 2; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_SPELL_RESISTANCE)) - CurrentItemValue += i7; + nCurrentItemValue += 7; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_TRUE_SEEING)) - CurrentItemValue += i11; + nCurrentItemValue += 11; if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_TURN_RESISTANCE)) - CurrentItemValue += i8; + nCurrentItemValue += 8; // if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_VORPAL)) -// CurrentItemValue += i8;// Removed as Bioware will remove this constant. Doesn't exsist. +// nCurrentItemValue += 8;// Removed as Bioware will remove this constant. Doesn't exsist. // if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_WOUNDING)) -// CurrentItemValue += i8;// Removed as Bioware will remove this constant. Doesn't exsist. +// nCurrentItemValue += 8;// Removed as Bioware will remove this constant. Doesn't exsist. // Special cases // Set is unlimited to TRUE or FALSE, add 10 if TRUE. - CurrentItemIsUnlimited = GetItemHasItemProperty(oItem, ITEM_PROPERTY_UNLIMITED_AMMUNITION); - if(CurrentItemIsUnlimited) CurrentItemValue += i10; + bCurrentItemIsUnlimited = GetItemHasItemProperty(oItem, ITEM_PROPERTY_UNLIMITED_AMMUNITION); + if(bCurrentItemIsUnlimited) nCurrentItemValue += 10; // Same as above, for mighty - CurrentItemIsMighty = GetItemHasItemProperty(oItem, ITEM_PROPERTY_MIGHTY); - if(CurrentItemIsMighty) CurrentItemValue += i3; + bCurrentItemIsMighty = GetItemHasItemProperty(oItem, ITEM_PROPERTY_MIGHTY); + if(bCurrentItemIsMighty) nCurrentItemValue += 3; - switch (CurrentItemSize) + switch (nCurrentItemSize) { case WEAPON_SIZE_INVALID:// Invalid Size, stop { @@ -595,29 +542,29 @@ void BaseEffects(object oTarget, object oItem) void BaseLargeWeapons(object oTarget, object oItem) { // No need for weopen size...we know we can use it! - switch(CurrentItemType) + switch(nCurrentItemType) { case BASE_ITEM_DIREMACE: { // This is the only one that needs documenting. All are similar. - if(ProfExotic == TRUE)// We are proficient in exotics... + if(bProfExotic == TRUE)// We are proficient in exotics... { - CurrentItemDamage = i16;// Set max damage. - CurrentItemValue += // We add onto the current value some things... - (CurrentItemDamage + // The damage (maximum) done by it. + nCurrentItemDamage = 16;// Set max damage. + nCurrentItemValue += // We add onto the current value some things... + (nCurrentItemDamage + // The damage (maximum) done by it. (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_DIRE_MACE)) + // Adds 1 if specailised in it - (GetHasFeat(FEAT_IMPROVED_CRITICAL_DIRE_MACE) * i2) +// Adds 2 if can do good criticals in it - (GetHasFeat(FEAT_WEAPON_FOCUS_DIRE_MACE) * i2)); // Adds 2 if we do +2 damage with it + (GetHasFeat(FEAT_IMPROVED_CRITICAL_DIRE_MACE) * 2) +// Adds 2 if can do good criticals in it + (GetHasFeat(FEAT_WEAPON_FOCUS_DIRE_MACE) * 2)); // Adds 2 if we do +2 damage with it // If a very big creature - set as a primary weopen - if(CreatureSize >= CREATURE_SIZE_LARGE)//4+ + if(nCreatureSize >= CREATURE_SIZE_LARGE)//4+ { SetPrimaryWeapon(oTarget, oItem); } // If a medium creature - set as a two-handed weopen - else if(CreatureSize == CREATURE_SIZE_MEDIUM)//=3 + else if(nCreatureSize == CREATURE_SIZE_MEDIUM)//=3 { // Add 16 more for a "second" weapon. - CurrentItemValue += CurrentItemDamage; + nCurrentItemValue += nCurrentItemDamage; SetTwoHandedWeapon(oTarget, oItem); } } @@ -625,21 +572,21 @@ void BaseLargeWeapons(object oTarget, object oItem) break; case BASE_ITEM_DOUBLEAXE: { - if(ProfExotic == TRUE) + if(bProfExotic == TRUE) { - CurrentItemDamage = i16;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 16;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_DOUBLE_AXE)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_DOUBLE_AXE) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_DOUBLE_AXE) * i2)); - if(CreatureSize >= CREATURE_SIZE_LARGE)//4+ + (GetHasFeat(FEAT_IMPROVED_CRITICAL_DOUBLE_AXE) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_DOUBLE_AXE) * 2)); + if(nCreatureSize >= CREATURE_SIZE_LARGE)//4+ { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_MEDIUM)//=3 + else if(nCreatureSize == CREATURE_SIZE_MEDIUM)//=3 { // Add 16 more for a "second" weapon. - CurrentItemValue += i16; + nCurrentItemValue += 16; SetTwoHandedWeapon(oTarget, oItem); } } @@ -647,20 +594,20 @@ void BaseLargeWeapons(object oTarget, object oItem) break; case BASE_ITEM_TWOBLADEDSWORD: { - if(ProfExotic == TRUE) + if(bProfExotic == TRUE) { - CurrentItemDamage = i16;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 16;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_TWO_BLADED_SWORD)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_TWO_BLADED_SWORD) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_TWO_BLADED_SWORD) * i2)); - if(CreatureSize >= CREATURE_SIZE_LARGE) + (GetHasFeat(FEAT_IMPROVED_CRITICAL_TWO_BLADED_SWORD) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_TWO_BLADED_SWORD) * 2)); + if(nCreatureSize >= CREATURE_SIZE_LARGE) { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_MEDIUM) + else if(nCreatureSize == CREATURE_SIZE_MEDIUM) { - CurrentItemValue += CurrentItemDamage; + nCurrentItemValue += nCurrentItemDamage; SetTwoHandedWeapon(oTarget, oItem); } } @@ -668,18 +615,18 @@ void BaseLargeWeapons(object oTarget, object oItem) break; case BASE_ITEM_GREATAXE: { - if(ProfMartial == TRUE) + if(bProfMartial == TRUE) { - CurrentItemDamage = i12;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 12;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_GREAT_AXE)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_GREAT_AXE) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_GREAT_AXE) * i2)); - if(CreatureSize >= CREATURE_SIZE_LARGE) + (GetHasFeat(FEAT_IMPROVED_CRITICAL_GREAT_AXE) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_GREAT_AXE) * 2)); + if(nCreatureSize >= CREATURE_SIZE_LARGE) { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_MEDIUM) + else if(nCreatureSize == CREATURE_SIZE_MEDIUM) { SetTwoHandedWeapon(oTarget, oItem); } @@ -688,18 +635,18 @@ void BaseLargeWeapons(object oTarget, object oItem) break; case BASE_ITEM_GREATSWORD: { - if(ProfMartial == TRUE) + if(bProfMartial == TRUE) { - CurrentItemDamage = i12;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 12;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_GREAT_SWORD)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_GREAT_SWORD) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_GREAT_SWORD) * i2)); - if(CreatureSize >= CREATURE_SIZE_LARGE) + (GetHasFeat(FEAT_IMPROVED_CRITICAL_GREAT_SWORD) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_GREAT_SWORD) * 2)); + if(nCreatureSize >= CREATURE_SIZE_LARGE) { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_MEDIUM) + else if(nCreatureSize == CREATURE_SIZE_MEDIUM) { SetTwoHandedWeapon(oTarget, oItem); } @@ -708,18 +655,18 @@ void BaseLargeWeapons(object oTarget, object oItem) break; case BASE_ITEM_HALBERD: { - if(ProfMartial == TRUE) + if(bProfMartial == TRUE) { - CurrentItemDamage = i10;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 10;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_HALBERD)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_HALBERD) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_HALBERD) * i2)); - if(CreatureSize >= CREATURE_SIZE_LARGE) + (GetHasFeat(FEAT_IMPROVED_CRITICAL_HALBERD) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_HALBERD) * 2)); + if(nCreatureSize >= CREATURE_SIZE_LARGE) { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_MEDIUM) + else if(nCreatureSize == CREATURE_SIZE_MEDIUM) { SetTwoHandedWeapon(oTarget, oItem); } @@ -728,18 +675,18 @@ void BaseLargeWeapons(object oTarget, object oItem) break; case BASE_ITEM_HEAVYFLAIL: { - if(ProfMartial == TRUE) + if(bProfMartial == TRUE) { - CurrentItemDamage = i10;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 10;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_HEAVY_FLAIL)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_HEAVY_FLAIL) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_HEAVY_FLAIL) * i2)); - if(CreatureSize >= CREATURE_SIZE_LARGE) + (GetHasFeat(FEAT_IMPROVED_CRITICAL_HEAVY_FLAIL) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_HEAVY_FLAIL) * 2)); + if(nCreatureSize >= CREATURE_SIZE_LARGE) { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_MEDIUM) + else if(nCreatureSize == CREATURE_SIZE_MEDIUM) { SetTwoHandedWeapon(oTarget, oItem); } @@ -748,18 +695,18 @@ void BaseLargeWeapons(object oTarget, object oItem) break; case BASE_ITEM_SCYTHE: { - if(ProfExotic == TRUE) + if(bProfExotic == TRUE) { - CurrentItemDamage = i10;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 10;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_SCYTHE)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_SCYTHE) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_SCYTHE) * i2)); - if(CreatureSize >= CREATURE_SIZE_LARGE) + (GetHasFeat(FEAT_IMPROVED_CRITICAL_SCYTHE) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_SCYTHE) * 2)); + if(nCreatureSize >= CREATURE_SIZE_LARGE) { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_MEDIUM) + else if(nCreatureSize == CREATURE_SIZE_MEDIUM) { SetTwoHandedWeapon(oTarget, oItem); } @@ -768,18 +715,18 @@ void BaseLargeWeapons(object oTarget, object oItem) break; case BASE_ITEM_SHORTSPEAR: { - if(ProfSimple == TRUE || ProfDruid == TRUE) + if(bProfSimple == TRUE || bProfDruid == TRUE) { - CurrentItemDamage = i8;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 8;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_SPEAR)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_SPEAR) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_SPEAR) * i2)); - if(CreatureSize >= CREATURE_SIZE_LARGE) + (GetHasFeat(FEAT_IMPROVED_CRITICAL_SPEAR) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_SPEAR) * 2)); + if(nCreatureSize >= CREATURE_SIZE_LARGE) { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_MEDIUM) + else if(nCreatureSize == CREATURE_SIZE_MEDIUM) { SetTwoHandedWeapon(oTarget, oItem); } @@ -790,19 +737,19 @@ void BaseLargeWeapons(object oTarget, object oItem) case BASE_ITEM_QUARTERSTAFF: case BASE_ITEM_MAGICSTAFF: { - if(ProfWizard == TRUE || ProfSimple == TRUE || ProfRogue == TRUE || - ProfMonk == TRUE || ProfDruid == TRUE) + if(bProfWizard == TRUE || bProfSimple == TRUE || bProfRogue == TRUE || + bProfMonk == TRUE || bProfDruid == TRUE) { - CurrentItemDamage = i6;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 6;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_STAFF)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_STAFF) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_STAFF) * i2)); - if(CreatureSize >= CREATURE_SIZE_LARGE) + (GetHasFeat(FEAT_IMPROVED_CRITICAL_STAFF) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_STAFF) * 2)); + if(nCreatureSize >= CREATURE_SIZE_LARGE) { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_MEDIUM) + else if(nCreatureSize == CREATURE_SIZE_MEDIUM) { SetTwoHandedWeapon(oTarget, oItem); } @@ -811,25 +758,25 @@ void BaseLargeWeapons(object oTarget, object oItem) break; case BASE_ITEM_LONGBOW: { - if(CreatureSize >= CREATURE_SIZE_MEDIUM && - (ProfMartial == TRUE || ProfElf == TRUE)) + if(nCreatureSize >= CREATURE_SIZE_MEDIUM && + (bProfMartial == TRUE || bProfElf == TRUE)) { - CurrentItemDamage = i8;// Set max damage. - CurrentItemValue += (CurrentItemDamage + - (CurrentItemIsMighty * CreatureStrength) + + nCurrentItemDamage = 8;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + + (bCurrentItemIsMighty * nCreatureStrength) + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_LONGBOW)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_LONGBOW) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_LONGBOW) * i2)); + (GetHasFeat(FEAT_IMPROVED_CRITICAL_LONGBOW) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_LONGBOW) * 2)); StoreRangedWeapon(oTarget, oItem); } } break; case BASE_ITEM_TOWERSHIELD: { - if(ProfShield == TRUE && - CreatureSize >= CREATURE_SIZE_MEDIUM) + if(bProfShield == TRUE && + nCreatureSize >= CREATURE_SIZE_MEDIUM) { - CurrentItemValue += GetItemACValue(oItem); + nCurrentItemValue += GetItemACValue(oItem); StoreShield(oTarget, oItem); } } @@ -850,22 +797,22 @@ void BaseLargeWeapons(object oTarget, object oItem) void BaseMediumWeapons(object oTarget, object oItem) { - switch (CurrentItemType) + switch(nCurrentItemType) { case BASE_ITEM_BASTARDSWORD: { - if(ProfExotic == TRUE) + if(bProfExotic == TRUE) { - CurrentItemDamage = i10;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 10;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_BASTARD_SWORD)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_BASTARD_SWORD) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_BASTARD_SWORD) * i2)); - if(CreatureSize >= CREATURE_SIZE_MEDIUM) + (GetHasFeat(FEAT_IMPROVED_CRITICAL_BASTARD_SWORD) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_BASTARD_SWORD) * 2)); + if(nCreatureSize >= CREATURE_SIZE_MEDIUM) { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_SMALL) + else if(nCreatureSize == CREATURE_SIZE_SMALL) { SetTwoHandedWeapon(oTarget, oItem); } @@ -874,18 +821,18 @@ void BaseMediumWeapons(object oTarget, object oItem) break; case BASE_ITEM_BATTLEAXE: { - if(ProfMartial == TRUE) + if(bProfMartial == TRUE) { - CurrentItemDamage = i8;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 8;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_BATTLE_AXE)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_BATTLE_AXE) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_BATTLE_AXE) * i2)); - if(CreatureSize >= CREATURE_SIZE_MEDIUM) + (GetHasFeat(FEAT_IMPROVED_CRITICAL_BATTLE_AXE) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_BATTLE_AXE) * 2)); + if(nCreatureSize >= CREATURE_SIZE_MEDIUM) { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_SMALL) + else if(nCreatureSize == CREATURE_SIZE_SMALL) { SetTwoHandedWeapon(oTarget, oItem); } @@ -894,18 +841,18 @@ void BaseMediumWeapons(object oTarget, object oItem) break; case BASE_ITEM_DWARVENWARAXE: { - if(ProfExotic == TRUE) + if(bProfExotic == TRUE) { - CurrentItemDamage = i10;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 10;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_DWAXE)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_DWAXE) * i2) + - (GetHasFeat(FEAT_EPIC_WEAPON_FOCUS_DWAXE) * i2)); - if(CreatureSize >= CREATURE_SIZE_MEDIUM) + (GetHasFeat(FEAT_IMPROVED_CRITICAL_DWAXE) * 2) + + (GetHasFeat(FEAT_EPIC_WEAPON_FOCUS_DWAXE) * 2)); + if(nCreatureSize >= CREATURE_SIZE_MEDIUM) { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_SMALL) + else if(nCreatureSize == CREATURE_SIZE_SMALL) { SetTwoHandedWeapon(oTarget, oItem); } @@ -913,19 +860,19 @@ void BaseMediumWeapons(object oTarget, object oItem) } case BASE_ITEM_CLUB: { - if(ProfWizard == TRUE || ProfSimple == TRUE || - ProfMonk == TRUE || ProfDruid == TRUE) + if(bProfWizard == TRUE || bProfSimple == TRUE || + bProfMonk == TRUE || bProfDruid == TRUE) { - CurrentItemDamage = i6;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 6;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_CLUB)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_CLUB) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_CLUB) * i2)); - if(CreatureSize >= CREATURE_SIZE_MEDIUM) + (GetHasFeat(FEAT_IMPROVED_CRITICAL_CLUB) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_CLUB) * 2)); + if(nCreatureSize >= CREATURE_SIZE_MEDIUM) { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_SMALL) + else if(nCreatureSize == CREATURE_SIZE_SMALL) { SetTwoHandedWeapon(oTarget, oItem); } @@ -934,18 +881,18 @@ void BaseMediumWeapons(object oTarget, object oItem) break; case BASE_ITEM_KATANA: { - if(ProfExotic == TRUE) + if(bProfExotic == TRUE) { - CurrentItemDamage = i10;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 10;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_KATANA)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_KATANA) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_KATANA) * i2)); - if(CreatureSize >= CREATURE_SIZE_MEDIUM) + (GetHasFeat(FEAT_IMPROVED_CRITICAL_KATANA) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_KATANA) * 2)); + if(nCreatureSize >= CREATURE_SIZE_MEDIUM) { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_SMALL) + else if(nCreatureSize == CREATURE_SIZE_SMALL) { SetTwoHandedWeapon(oTarget, oItem); } @@ -954,18 +901,18 @@ void BaseMediumWeapons(object oTarget, object oItem) break; case BASE_ITEM_LIGHTFLAIL: { - if(ProfMartial == TRUE) + if(bProfMartial == TRUE) { - CurrentItemDamage = i8;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 8;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_LIGHT_FLAIL)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_LIGHT_FLAIL) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_FLAIL) * i2)); - if(CreatureSize >= CREATURE_SIZE_MEDIUM) + (GetHasFeat(FEAT_IMPROVED_CRITICAL_LIGHT_FLAIL) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_FLAIL) * 2)); + if(nCreatureSize >= CREATURE_SIZE_MEDIUM) { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_SMALL) + else if(nCreatureSize == CREATURE_SIZE_SMALL) { SetTwoHandedWeapon(oTarget, oItem); } @@ -974,18 +921,18 @@ void BaseMediumWeapons(object oTarget, object oItem) break; case BASE_ITEM_LONGSWORD: { - if(ProfMartial == TRUE || ProfElf == TRUE) + if(bProfMartial == TRUE || bProfElf == TRUE) { - CurrentItemDamage = i8;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 8;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_LONG_SWORD)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_LONG_SWORD) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_LONG_SWORD) * i2)); - if(CreatureSize >= CREATURE_SIZE_MEDIUM) + (GetHasFeat(FEAT_IMPROVED_CRITICAL_LONG_SWORD) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_LONG_SWORD) * 2)); + if(nCreatureSize >= CREATURE_SIZE_MEDIUM) { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_SMALL) + else if(nCreatureSize == CREATURE_SIZE_SMALL) { SetTwoHandedWeapon(oTarget, oItem); } @@ -994,18 +941,18 @@ void BaseMediumWeapons(object oTarget, object oItem) break; case BASE_ITEM_MORNINGSTAR: { - if(ProfSimple == TRUE || ProfRogue == TRUE) // Primary only + if(bProfSimple == TRUE || bProfRogue == TRUE) // Primary only { - CurrentItemDamage = i8;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 8;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_MORNING_STAR)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_MORNING_STAR) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_MORNING_STAR) * i2)); - if(CreatureSize >= CREATURE_SIZE_MEDIUM) + (GetHasFeat(FEAT_IMPROVED_CRITICAL_MORNING_STAR) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_MORNING_STAR) * 2)); + if(nCreatureSize >= CREATURE_SIZE_MEDIUM) { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_SMALL) + else if(nCreatureSize == CREATURE_SIZE_SMALL) { SetTwoHandedWeapon(oTarget, oItem); } @@ -1014,18 +961,18 @@ void BaseMediumWeapons(object oTarget, object oItem) break; case BASE_ITEM_RAPIER: { - if(ProfRogue == TRUE || ProfMartial == TRUE || ProfElf == TRUE) + if(bProfRogue == TRUE || bProfMartial == TRUE || bProfElf == TRUE) { - CurrentItemDamage = i6;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 6;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_RAPIER)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_RAPIER) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_RAPIER) * i2)); - if(CreatureSize >= CREATURE_SIZE_MEDIUM) + (GetHasFeat(FEAT_IMPROVED_CRITICAL_RAPIER) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_RAPIER) * 2)); + if(nCreatureSize >= CREATURE_SIZE_MEDIUM) { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_SMALL) + else if(nCreatureSize == CREATURE_SIZE_SMALL) { SetTwoHandedWeapon(oTarget, oItem); } @@ -1034,18 +981,18 @@ void BaseMediumWeapons(object oTarget, object oItem) break; case BASE_ITEM_SCIMITAR: { - if(ProfMartial == TRUE || ProfDruid == TRUE) + if(bProfMartial == TRUE || bProfDruid == TRUE) { - CurrentItemDamage = i6;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 6;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_SCIMITAR)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_SCIMITAR) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_SCIMITAR) * i2)); - if(CreatureSize >= CREATURE_SIZE_MEDIUM) + (GetHasFeat(FEAT_IMPROVED_CRITICAL_SCIMITAR) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_SCIMITAR) * 2)); + if(nCreatureSize >= CREATURE_SIZE_MEDIUM) { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_SMALL) + else if(nCreatureSize == CREATURE_SIZE_SMALL) { SetTwoHandedWeapon(oTarget, oItem); } @@ -1054,18 +1001,18 @@ void BaseMediumWeapons(object oTarget, object oItem) break; case BASE_ITEM_WARHAMMER: { - if(ProfMartial == TRUE) + if(bProfMartial == TRUE) { - CurrentItemDamage = i8;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 8;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + GetHasFeat(FEAT_WEAPON_SPECIALIZATION_WAR_HAMMER) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_WAR_HAMMER) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_WAR_HAMMER) * i2)); - if(CreatureSize >= CREATURE_SIZE_MEDIUM) + (GetHasFeat(FEAT_IMPROVED_CRITICAL_WAR_HAMMER) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_WAR_HAMMER) * 2)); + if(nCreatureSize >= CREATURE_SIZE_MEDIUM) { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_SMALL) + else if(nCreatureSize == CREATURE_SIZE_SMALL) { SetTwoHandedWeapon(oTarget, oItem); } @@ -1074,41 +1021,41 @@ void BaseMediumWeapons(object oTarget, object oItem) break; case BASE_ITEM_HEAVYCROSSBOW: { - if(CreatureSize >= CREATURE_SIZE_SMALL && - (ProfWizard == TRUE || ProfSimple == TRUE || - ProfRogue == TRUE || ProfMonk == TRUE)) + if(nCreatureSize >= CREATURE_SIZE_SMALL && + (bProfWizard == TRUE || bProfSimple == TRUE || + bProfRogue == TRUE || bProfMonk == TRUE)) { - CurrentItemDamage = i10;// Set max damage. - CurrentItemValue += (CurrentItemDamage + - (CurrentItemIsMighty * CreatureStrength) + + nCurrentItemDamage = 10;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + + (bCurrentItemIsMighty * nCreatureStrength) + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_HEAVY_CROSSBOW)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_HEAVY_CROSSBOW) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_HEAVY_CROSSBOW) * i2)); + (GetHasFeat(FEAT_IMPROVED_CRITICAL_HEAVY_CROSSBOW) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_HEAVY_CROSSBOW) * 2)); StoreRangedWeapon(oTarget, oItem); } } break; case BASE_ITEM_SHORTBOW: { - if(CreatureSize >= CREATURE_SIZE_SMALL && - (ProfRogue == TRUE || ProfMartial == TRUE || ProfElf == TRUE)) + if(nCreatureSize >= CREATURE_SIZE_SMALL && + (bProfRogue == TRUE || bProfMartial == TRUE || bProfElf == TRUE)) { - CurrentItemDamage = i6;// Set max damage. - CurrentItemValue += (CurrentItemDamage + - (CurrentItemIsMighty * CreatureStrength) + + nCurrentItemDamage = 6;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + + (bCurrentItemIsMighty * nCreatureStrength) + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_SHORTBOW)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_SHORTBOW) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_SHORTBOW) * i2)); + (GetHasFeat(FEAT_IMPROVED_CRITICAL_SHORTBOW) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_SHORTBOW) * 2)); StoreRangedWeapon(oTarget, oItem); } } break; case BASE_ITEM_LARGESHIELD: { - if(CreatureSize >= CREATURE_SIZE_SMALL && - ProfShield == TRUE) + if(nCreatureSize >= CREATURE_SIZE_SMALL && + bProfShield == TRUE) { - CurrentItemValue += GetItemACValue(oItem); + nCurrentItemValue += GetItemACValue(oItem); StoreShield(oTarget, oItem); } } @@ -1128,23 +1075,23 @@ void BaseMediumWeapons(object oTarget, object oItem) //::////////////////////////////////////////////// void BaseSmallWeapons(object oTarget, object oItem) { - switch (CurrentItemType) + switch (nCurrentItemType) { case BASE_ITEM_HANDAXE: { - if(ProfMonk == TRUE || ProfMartial == TRUE) + if(bProfMonk == TRUE || bProfMartial == TRUE) { - CurrentItemDamage = i6;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 6;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_HAND_AXE)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_HAND_AXE) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_HAND_AXE) * i2)); - if(CreatureSize >= CREATURE_SIZE_SMALL && - CreatureSize <= CREATURE_SIZE_LARGE) + (GetHasFeat(FEAT_IMPROVED_CRITICAL_HAND_AXE) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_HAND_AXE) * 2)); + if(nCreatureSize >= CREATURE_SIZE_SMALL && + nCreatureSize <= CREATURE_SIZE_LARGE) { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_TINY) + else if(nCreatureSize == CREATURE_SIZE_TINY) { SetTwoHandedWeapon(oTarget, oItem); } @@ -1153,19 +1100,19 @@ void BaseSmallWeapons(object oTarget, object oItem) break; case BASE_ITEM_KAMA: { - if(ProfMonk == TRUE || ProfExotic == TRUE) + if(bProfMonk == TRUE || bProfExotic == TRUE) { - CurrentItemDamage = i6;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 6;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_KAMA)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_KAMA) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_KAMA) * i2)); - if(CreatureSize >= CREATURE_SIZE_SMALL && - CreatureSize <= CREATURE_SIZE_LARGE) + (GetHasFeat(FEAT_IMPROVED_CRITICAL_KAMA) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_KAMA) * 2)); + if(nCreatureSize >= CREATURE_SIZE_SMALL && + nCreatureSize <= CREATURE_SIZE_LARGE) { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_TINY) + else if(nCreatureSize == CREATURE_SIZE_TINY) { SetTwoHandedWeapon(oTarget, oItem); } @@ -1174,19 +1121,19 @@ void BaseSmallWeapons(object oTarget, object oItem) break; case BASE_ITEM_LIGHTHAMMER: { - if(ProfMartial == TRUE) + if(bProfMartial == TRUE) { - CurrentItemDamage = i4;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 4;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + GetHasFeat(FEAT_WEAPON_SPECIALIZATION_LIGHT_HAMMER) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_LIGHT_HAMMER) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_HAMMER) * i2)); - if(CreatureSize >= CREATURE_SIZE_SMALL && - CreatureSize <= CREATURE_SIZE_LARGE) + (GetHasFeat(FEAT_IMPROVED_CRITICAL_LIGHT_HAMMER) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_HAMMER) * 2)); + if(nCreatureSize >= CREATURE_SIZE_SMALL && + nCreatureSize <= CREATURE_SIZE_LARGE) { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_TINY) + else if(nCreatureSize == CREATURE_SIZE_TINY) { SetTwoHandedWeapon(oTarget, oItem); } @@ -1195,19 +1142,19 @@ void BaseSmallWeapons(object oTarget, object oItem) break; case BASE_ITEM_LIGHTMACE: { - if(ProfSimple == TRUE || ProfRogue == TRUE) + if(bProfSimple == TRUE || bProfRogue == TRUE) { - CurrentItemDamage = i6;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 6;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_LIGHT_MACE)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_LIGHT_MACE) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_MACE) * i2)); - if(CreatureSize >= CREATURE_SIZE_SMALL && - CreatureSize <= CREATURE_SIZE_LARGE) + (GetHasFeat(FEAT_IMPROVED_CRITICAL_LIGHT_MACE) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_MACE) * 2)); + if(nCreatureSize >= CREATURE_SIZE_SMALL && + nCreatureSize <= CREATURE_SIZE_LARGE) { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_TINY) + else if(nCreatureSize == CREATURE_SIZE_TINY) { SetTwoHandedWeapon(oTarget, oItem); } @@ -1216,19 +1163,19 @@ void BaseSmallWeapons(object oTarget, object oItem) break; case BASE_ITEM_SHORTSWORD: { - if(ProfRogue == TRUE || ProfMartial == TRUE) + if(bProfRogue == TRUE || bProfMartial == TRUE) { - CurrentItemDamage = i6;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 6;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_SHORT_SWORD)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_SHORT_SWORD) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_SHORT_SWORD) * i2)); - if(CreatureSize >= CREATURE_SIZE_SMALL && - CreatureSize <= CREATURE_SIZE_LARGE) + (GetHasFeat(FEAT_IMPROVED_CRITICAL_SHORT_SWORD) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_SHORT_SWORD) * 2)); + if(nCreatureSize >= CREATURE_SIZE_SMALL && + nCreatureSize <= CREATURE_SIZE_LARGE) { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_TINY) + else if(nCreatureSize == CREATURE_SIZE_TINY) { SetTwoHandedWeapon(oTarget, oItem); } @@ -1237,15 +1184,15 @@ void BaseSmallWeapons(object oTarget, object oItem) break; case BASE_ITEM_WHIP: { - if(ProfExotic == TRUE) + if(bProfExotic == TRUE) { - CurrentItemDamage = i2;// Set max damage. - CurrentItemValue += CurrentItemDamage; + nCurrentItemDamage = 2;// Set max damage. + nCurrentItemValue += nCurrentItemDamage; // We add a special amount, 10, as it is only used as a secondary // weapon, and only in the offhand. - CurrentItemValue += i10; - if(CreatureSize >= CREATURE_SIZE_SMALL && - CreatureSize <= CREATURE_SIZE_LARGE) + nCurrentItemValue += 10; + if(nCreatureSize >= CREATURE_SIZE_SMALL && + nCreatureSize <= CREATURE_SIZE_LARGE) { SetPrimaryWeapon(oTarget, oItem); } @@ -1254,19 +1201,19 @@ void BaseSmallWeapons(object oTarget, object oItem) break; case BASE_ITEM_SICKLE: { - if(ProfSimple == TRUE || ProfDruid == TRUE) + if(bProfSimple == TRUE || bProfDruid == TRUE) { - CurrentItemDamage = i6;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 6;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_SICKLE)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_SICKLE) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_SICKLE) * i2)); - if(CreatureSize >= CREATURE_SIZE_SMALL && - CreatureSize <= CREATURE_SIZE_LARGE) + (GetHasFeat(FEAT_IMPROVED_CRITICAL_SICKLE) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_SICKLE) * 2)); + if(nCreatureSize >= CREATURE_SIZE_SMALL && + nCreatureSize <= CREATURE_SIZE_LARGE) { SetPrimaryWeapon(oTarget, oItem); } - else if(CreatureSize == CREATURE_SIZE_TINY) + else if(nCreatureSize == CREATURE_SIZE_TINY) { SetTwoHandedWeapon(oTarget, oItem); } @@ -1276,69 +1223,69 @@ void BaseSmallWeapons(object oTarget, object oItem) case BASE_ITEM_DART: { // Ranged weapons below - if(CreatureSize <= CREATURE_SIZE_LARGE && - (ProfSimple == TRUE || ProfRogue == TRUE || ProfDruid == TRUE)) + if(nCreatureSize <= CREATURE_SIZE_LARGE && + (bProfSimple == TRUE || bProfRogue == TRUE || bProfDruid == TRUE)) { - CurrentItemDamage = i4;// Set max damage. - CurrentItemValue += (CurrentItemDamage + - (CurrentItemIsMighty * CreatureStrength) + + nCurrentItemDamage = 4;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + + (bCurrentItemIsMighty * nCreatureStrength) + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_DART)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_DART) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_DART) * i2)); + (GetHasFeat(FEAT_IMPROVED_CRITICAL_DART) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_DART) * 2)); StoreRangedWeapon(oTarget, oItem); } } break; case BASE_ITEM_LIGHTCROSSBOW: { - if(CreatureSize <= CREATURE_SIZE_LARGE && - (ProfWizard == TRUE || ProfSimple == TRUE || - ProfRogue == TRUE || ProfMonk == TRUE)) + if(nCreatureSize <= CREATURE_SIZE_LARGE && + (bProfWizard == TRUE || bProfSimple == TRUE || + bProfRogue == TRUE || bProfMonk == TRUE)) { - CurrentItemDamage = i8;// Set max damage. - CurrentItemValue += (CurrentItemDamage + - (CurrentItemIsMighty * CreatureStrength) + + nCurrentItemDamage = 8;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + + (bCurrentItemIsMighty * nCreatureStrength) + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_LIGHT_CROSSBOW)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_LIGHT_CROSSBOW) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_CROSSBOW) * i2)); + (GetHasFeat(FEAT_IMPROVED_CRITICAL_LIGHT_CROSSBOW) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_CROSSBOW) * 2)); StoreRangedWeapon(oTarget, oItem); } } break; case BASE_ITEM_SLING: { - if(CreatureSize <= CREATURE_SIZE_LARGE && - (ProfSimple == TRUE || ProfMonk == TRUE || ProfDruid == TRUE)) + if(nCreatureSize <= CREATURE_SIZE_LARGE && + (bProfSimple == TRUE || bProfMonk == TRUE || bProfDruid == TRUE)) { - CurrentItemDamage = i4;// Set max damage. - CurrentItemValue += (CurrentItemDamage + - (CurrentItemIsMighty * CreatureStrength) + + nCurrentItemDamage = 4;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + + (bCurrentItemIsMighty * nCreatureStrength) + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_SLING)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_SLING) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_SLING) * i2)); + (GetHasFeat(FEAT_IMPROVED_CRITICAL_SLING) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_SLING) * 2)); StoreRangedWeapon(oTarget, oItem); } } break; case BASE_ITEM_THROWINGAXE: { - if(CreatureSize <= CREATURE_SIZE_LARGE && ProfMartial == TRUE) + if(nCreatureSize <= CREATURE_SIZE_LARGE && bProfMartial == TRUE) { - CurrentItemDamage = i6;// Set max damage. - CurrentItemValue += (CurrentItemDamage + - (CreatureStrength) + + nCurrentItemDamage = 6;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + + (nCreatureStrength) + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_SLING)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_SLING) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_SLING) * i2)); + (GetHasFeat(FEAT_IMPROVED_CRITICAL_SLING) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_SLING) * 2)); StoreRangedWeapon(oTarget, oItem); } } break; case BASE_ITEM_SMALLSHIELD: { - if(ProfShield) + if(bProfShield) { - CurrentItemValue += GetItemACValue(oItem); + nCurrentItemValue += GetItemACValue(oItem); StoreShield(oTarget, oItem); } } @@ -1359,32 +1306,32 @@ void BaseSmallWeapons(object oTarget, object oItem) void BaseTinyWeapons(object oTarget, object oItem) { - switch (CurrentItemType) + switch (nCurrentItemType) { case BASE_ITEM_DAGGER: { - if(CreatureSize <= CREATURE_SIZE_MEDIUM && - (ProfWizard == TRUE || ProfSimple == TRUE || ProfRogue == TRUE || - ProfMonk == TRUE || ProfDruid == TRUE)) + if(nCreatureSize <= CREATURE_SIZE_MEDIUM && + (bProfWizard == TRUE || bProfSimple == TRUE || bProfRogue == TRUE || + bProfMonk == TRUE || bProfDruid == TRUE)) { - CurrentItemDamage = i4;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 4;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_DAGGER)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_DAGGER) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_DAGGER) * i2)); + (GetHasFeat(FEAT_IMPROVED_CRITICAL_DAGGER) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_DAGGER) * 2)); SetPrimaryWeapon(oTarget, oItem); } } break; case BASE_ITEM_KUKRI: { - if(CreatureSize <= CREATURE_SIZE_MEDIUM && ProfExotic == TRUE) + if(nCreatureSize <= CREATURE_SIZE_MEDIUM && bProfExotic == TRUE) { - CurrentItemDamage = i4;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 4;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_KUKRI)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_KUKRI) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_KUKRI) * i2)); + (GetHasFeat(FEAT_IMPROVED_CRITICAL_KUKRI) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_KUKRI) * 2)); SetPrimaryWeapon(oTarget, oItem); } } @@ -1392,14 +1339,14 @@ void BaseTinyWeapons(object oTarget, object oItem) case BASE_ITEM_SHURIKEN: { // Ranged weapons below - if(CreatureSize <= CREATURE_SIZE_MEDIUM && - (ProfMonk == TRUE || ProfExotic == TRUE)) + if(nCreatureSize <= CREATURE_SIZE_MEDIUM && + (bProfMonk == TRUE || bProfExotic == TRUE)) { - CurrentItemDamage = i3;// Set max damage. - CurrentItemValue += (CurrentItemDamage + + nCurrentItemDamage = 3;// Set max damage. + nCurrentItemValue += (nCurrentItemDamage + (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_SHURIKEN)) + - (GetHasFeat(FEAT_IMPROVED_CRITICAL_SHURIKEN) * i2) + - (GetHasFeat(FEAT_WEAPON_FOCUS_SHURIKEN) * i2)); + (GetHasFeat(FEAT_IMPROVED_CRITICAL_SHURIKEN) * 2) + + (GetHasFeat(FEAT_WEAPON_FOCUS_SHURIKEN) * 2)); StoreRangedWeapon(oTarget, oItem); } } @@ -1426,20 +1373,21 @@ void SetPrimaryWeapon(object oTarget, object oItem) { // We insert the value into an array of all primary weapons, based // on value. - if(CurrentItemType != BASE_ITEM_WHIP) // WHIPs are secondary only - { - ArrayOfWeapons(AI_WEAPON_PRIMARY, oTarget, oItem, CurrentItemValue); - } + // * Any weapon can be primary + ArrayOfWeapons(AI_WEAPON_PRIMARY, oTarget, oItem, nCurrentItemValue); + // We also set up secondary array for all weapons which can be used well // in the off hand. // This takes some value off for size of weapon...depending on our size! // IE to hit is lower, it is a lower value. - if(ProfTwoWeapons == TRUE && - // 4 = Light flail, 47 = Morningstar - NOT a valid second weapon. - CurrentItemType != BASE_ITEM_LIGHTFLAIL && - CurrentItemType != BASE_ITEM_MORNINGSTAR) + if(bProfTwoWeapons == TRUE && + // 4 = Light flail, 47 = Morningstar - NOT a valid second weapon, for + // some bug reason + nCurrentItemType != BASE_ITEM_LIGHTFLAIL && + nCurrentItemType != BASE_ITEM_MORNINGSTAR && + nCurrentItemType != BASE_ITEM_WHIP) // Whips are primary only { - ArrayOfWeapons(AI_WEAPON_SECONDARY, oTarget, oItem, CurrentItemValue, TRUE); + ArrayOfWeapons(AI_WEAPON_SECONDARY, oTarget, oItem, nCurrentItemValue, TRUE); } } //:://///////////////////////////////////////////// @@ -1457,7 +1405,7 @@ void SetTwoHandedWeapon(object oTarget, object oItem) { // We insert the value into an array of all 2 handed weapons, based // on value. - ArrayOfWeapons(AI_WEAPON_TWO_HANDED, oTarget, oItem, CurrentItemValue); + ArrayOfWeapons(AI_WEAPON_TWO_HANDED, oTarget, oItem, nCurrentItemValue); } //:://///////////////////////////////////////////// @@ -1485,31 +1433,31 @@ void StoreRangedWeapon(object oTarget, object oItem) nNth++; string sNth = IntToString(nNth); // Special: If unlimited ammo, we will use regardless of ammo. - SetLocalInt(oItem, SETWEP_IS_UNLIMITED, CurrentItemIsUnlimited); - SetLocalInt(oItem, SETWEP_VALUE, CurrentItemValue); + SetLocalInt(oItem, SETWEP_IS_UNLIMITED, bCurrentItemIsUnlimited); + SetLocalInt(oItem, SETWEP_VALUE, nCurrentItemValue); SetLocalObject(oTarget, SETWEP_DISTANCE + sNth, oItem); SetLocalInt(oTarget, SETWEP_DISTANCE, nNth); } void SetAmmoCounters(object oTarget) { - switch(CurrentItemType) + switch(nCurrentItemType) { case BASE_ITEM_ARROW: { - HasArrows = TRUE; + bGotArrows = TRUE; return; } break; case BASE_ITEM_BOLT: { - HasBolts = TRUE; + bGotBolts = TRUE; return; } break; case BASE_ITEM_BULLET: { - HasBullets = TRUE; + bGotBullets = TRUE; return; } break; @@ -1520,58 +1468,58 @@ void SetRangedWeapon(object oTarget) { // Special: We set 2 weapons. The second just states there is a second // and so we re-set weapons if we get round to using it. - int nNth = i1; + int nNth = 1; string sNth = IntToString(nNth); object oItem = GetLocalObject(oTarget, SETWEP_DISTANCE + sNth); - int nBase, iHighestValueWeapon, iValue, iUnlimited, iShield, - iNextHighestValueWeapon, iHighestUnlimited, iAmmoSlot; + int nBase, nHighestValueWeapon, nValue, bUnlimited, bShield, // TRUE if we can use a shield too + nNextHighestValueWeapon, bHighestUnlimited, nAmmoSlot; object oHighestItem, oNextHighestItem; while(GetIsObjectValid(oItem)) { nBase = GetBaseItemType(oItem); - iValue = GetLocalInt(oItem, SETWEP_VALUE); - iUnlimited = GetLocalInt(oItem, SETWEP_IS_UNLIMITED); + nValue = GetLocalInt(oItem, SETWEP_VALUE); + bUnlimited = GetLocalInt(oItem, SETWEP_IS_UNLIMITED); if(nBase == BASE_ITEM_DART || nBase == BASE_ITEM_SHURIKEN || nBase == BASE_ITEM_THROWINGAXE) // 31 = Dart, 59 = Shuriken, 63 = Throwing axe { //iHighestValueWeapon starts as 0, so - if(iValue > iHighestValueWeapon || - iHighestValueWeapon == i0) + if(nValue > nHighestValueWeapon || + nHighestValueWeapon == 0) { - iHighestValueWeapon = iValue; + nHighestValueWeapon = nValue; oHighestItem = oItem; - iShield = TRUE; + bShield = TRUE; // We set right hand, because it is a throwing weapon - iAmmoSlot = INVENTORY_SLOT_RIGHTHAND; - iHighestUnlimited = iUnlimited; + nAmmoSlot = INVENTORY_SLOT_RIGHTHAND; + bHighestUnlimited = bUnlimited; } - else if(iValue > iNextHighestValueWeapon || - iNextHighestValueWeapon == i0) + else if(nValue > nNextHighestValueWeapon || + nNextHighestValueWeapon == 0) { - iNextHighestValueWeapon = iValue; + nNextHighestValueWeapon = nValue; oNextHighestItem = oItem; } } else if(nBase == BASE_ITEM_HEAVYCROSSBOW || nBase == BASE_ITEM_LIGHTCROSSBOW)// 6 = Heavy, 7 = Light X-bow { - if(HasBolts == TRUE || iUnlimited == TRUE) + if(bGotBolts == TRUE || bUnlimited == TRUE) { - if(iValue > iHighestValueWeapon || - iHighestValueWeapon == i0) + if(nValue > nHighestValueWeapon || + nHighestValueWeapon == 0) { - iHighestValueWeapon = iValue; + nHighestValueWeapon = nValue; oHighestItem = oItem; - iAmmoSlot = INVENTORY_SLOT_BOLTS; - iShield = FALSE; - iHighestUnlimited = iUnlimited; + nAmmoSlot = INVENTORY_SLOT_BOLTS; + bShield = FALSE; + bHighestUnlimited = bUnlimited; } - else if(iValue > iNextHighestValueWeapon || - iNextHighestValueWeapon == i0) + else if(nValue > nNextHighestValueWeapon || + nNextHighestValueWeapon == 0) { - iNextHighestValueWeapon = iValue; + nNextHighestValueWeapon = nValue; oNextHighestItem = oItem; } } @@ -1579,42 +1527,42 @@ void SetRangedWeapon(object oTarget) else if(nBase == BASE_ITEM_LONGBOW || nBase == BASE_ITEM_SHORTBOW)// 8 = Long, 11 = Short bow { - if(HasArrows == TRUE || iUnlimited == TRUE) + if(bGotArrows == TRUE || bUnlimited == TRUE) { - if(iValue > iHighestValueWeapon || - iHighestValueWeapon == i0) + if(nValue > nHighestValueWeapon || + nHighestValueWeapon == 0) { - iHighestValueWeapon = iValue; + nHighestValueWeapon = nValue; oHighestItem = oItem; - iShield = FALSE; - iAmmoSlot = INVENTORY_SLOT_ARROWS; - iHighestUnlimited = iUnlimited; + bShield = FALSE; + nAmmoSlot = INVENTORY_SLOT_ARROWS; + bHighestUnlimited = bUnlimited; } - else if(iValue > iNextHighestValueWeapon || - iNextHighestValueWeapon == i0) + else if(nValue > nNextHighestValueWeapon || + nNextHighestValueWeapon == 0) { - iNextHighestValueWeapon = iValue; + nNextHighestValueWeapon = nValue; oNextHighestItem = oItem; } } } else if(nBase == BASE_ITEM_SLING)// 61 = Sling { - if(HasBullets == TRUE || iUnlimited == TRUE) + if(bGotBullets == TRUE || bUnlimited == TRUE) { - if(iValue > iHighestValueWeapon || - iHighestValueWeapon == i0) + if(nValue > nHighestValueWeapon || + nHighestValueWeapon == 0) { - iHighestValueWeapon = iValue; + nHighestValueWeapon = nValue; oHighestItem = oItem; - iShield = TRUE; - iAmmoSlot = INVENTORY_SLOT_BULLETS; - iHighestUnlimited = iUnlimited; + bShield = TRUE; + nAmmoSlot = INVENTORY_SLOT_BULLETS; + bHighestUnlimited = bUnlimited; } - else if(iValue > iNextHighestValueWeapon || - iNextHighestValueWeapon == i0) + else if(nValue > nNextHighestValueWeapon || + nNextHighestValueWeapon == 0) { - iNextHighestValueWeapon = iValue; + nNextHighestValueWeapon = nValue; oNextHighestItem = oItem; } } @@ -1630,15 +1578,15 @@ void SetRangedWeapon(object oTarget) if(GetIsObjectValid(oHighestItem)) { SWFinalAIObject(oTarget, AI_WEAPON_RANGED, oHighestItem); - SWFinalAIInteger(oTarget, AI_WEAPON_RANGED_AMMOSLOT, iAmmoSlot); - if(iHighestUnlimited) + SWFinalAIInteger(oTarget, AI_WEAPON_RANGED_AMMOSLOT, nAmmoSlot); + if(bHighestUnlimited) { - SWFinalAIInteger(oTarget, AI_WEAPON_RANGED_IS_UNLIMITED, iHighestUnlimited); + SWFinalAIInteger(oTarget, AI_WEAPON_RANGED_IS_UNLIMITED, bHighestUnlimited); } // Can a shield be used with it? Default is 0, we only set non 0 values. - if(iShield) + if(bShield) { - SWFinalAIInteger(oTarget, AI_WEAPON_RANGED_SHIELD, iShield); + SWFinalAIInteger(oTarget, AI_WEAPON_RANGED_SHIELD, bShield); } // No setting if not valid! if(GetIsObjectValid(oNextHighestItem)) @@ -1665,31 +1613,31 @@ void StoreShield(object oTarget, object oItem) nNth++; string sNth = IntToString(nNth); // Set the value, so we can use the top values again. - SetLocalInt(oItem, SETWEP_VALUE, CurrentItemValue); + SetLocalInt(oItem, SETWEP_VALUE, nCurrentItemValue); SetLocalObject(oTarget, SETWEP_SHIELD + sNth, oItem); SetLocalInt(oTarget, SETWEP_SHIELD, nNth); } void SetShield(object oTarget) { - int nNth = i1; + int nNth = 1; string sNth = IntToString(nNth); object oItem = GetLocalObject(oTarget, SETWEP_SHIELD + sNth); - int iHighestValueShield, iValue, iNextHighestValueShield; + int nHighestValueShield, nValue, nNextHighestValueShield; object oHighestShield, oNextHighestShield; while(GetIsObjectValid(oItem)) { - iValue = GetLocalInt(oItem, SETWEP_VALUE); - if(iValue > iHighestValueShield) + nValue = GetLocalInt(oItem, SETWEP_VALUE); + if(nValue > nHighestValueShield) { oHighestShield = oItem; - iHighestValueShield = iValue; + nHighestValueShield = nValue; } - else if(iValue > iNextHighestValueShield) + else if(nValue > nNextHighestValueShield) { oNextHighestShield = oItem; - iNextHighestValueShield = iValue; + nNextHighestValueShield = nValue; } DeleteLocalInt(oItem, SETWEP_VALUE); DeleteLocalObject(oTarget, SETWEP_SHIELD + sNth); @@ -1823,104 +1771,109 @@ void DeleteInts(object oTarget) //:: Created By: Yrean //:: Modified By: Jasperre //::////////////////////////////////////////////// -void ArrayOfWeapons(string sArray, object oTarget, object oItem, int iValue, int iSecondary = FALSE) +// Sets the weapon to the array, in the right spot... +// If bSecondary is TRUE, it uses the weapon size, and creature size to modifiy +// the value, IE: Sets it as the secondary weapon. +void ArrayOfWeapons(string sArray, object oTarget, object oItem, int nValue, int bSecondary = FALSE) { // Check for if it is secondary. // We add some value based on the creature size against weapon size. // - We also may take away some. - int iSetValue = iValue; - if(iSecondary == TRUE) + int nSetValue = nValue; + if(bSecondary == TRUE) { // We take 2 or add 2 for different sizes. Not too much...but enough? - iSetValue += ((CreatureSize - CurrentItemSize) * i2); + nSetValue += ((nCreatureSize - nCurrentItemSize) * 2); } - int iOtherItemsValues, i, iBreak; - int iMax = GetLocalInt(oTarget, MAXINT_ + sArray); + int nOtherItemsValues, nCnt, bBreak; + int nMax = GetLocalInt(oTarget, MAXINT_ + sArray); string sArrayStore; // Special - no max items! - if(iMax < i1) + if(nMax < 1) { - sArrayStore = sArray + s1; - SetLocalInt(oTarget, sArrayStore, iSetValue); - SetLocalInt(oTarget, sArrayStore + WEAP_SIZE, CurrentItemSize); - SetLocalInt(oTarget, sArrayStore + WEAP_DAMAGE, CurrentItemDamage); + sArrayStore = sArray + "1"; + SetLocalInt(oTarget, sArrayStore, nSetValue); + SetLocalInt(oTarget, sArrayStore + WEAP_SIZE, nCurrentItemSize); + SetLocalInt(oTarget, sArrayStore + WEAP_DAMAGE, nCurrentItemDamage); SetLocalObject(oTarget, sArrayStore, oItem); - iMax++; - SetLocalInt(oTarget, MAXINT_ + sArray, iMax); + nMax++; + SetLocalInt(oTarget, MAXINT_ + sArray, nMax); } // Else, we will set it in the array. else { // Loop through the items stored already. - for(i = i1; (i <= iMax && iBreak != TRUE); i++) + for(nCnt = 1; (nCnt <= nMax && bBreak != TRUE); nCnt++) { // Get the value of the item. - iOtherItemsValues = GetLocalInt(oTarget, sArray + IntToString(i)); + nOtherItemsValues = GetLocalInt(oTarget, sArray + IntToString(nCnt)); // If imput is greater than stored...move all of them back one. - if(iValue > iOtherItemsValues) + if(nValue > nOtherItemsValues) { // Set weapon size as well. - sArrayStore = sArray + IntToString(i); - MoveArrayBackOne(sArray, i, oTarget, iMax); - SetLocalInt(oTarget, sArrayStore, iSetValue); - SetLocalInt(oTarget, sArrayStore + WEAP_SIZE, CurrentItemSize); - SetLocalInt(oTarget, sArrayStore + WEAP_DAMAGE, CurrentItemDamage); + sArrayStore = sArray + IntToString(nCnt); + MoveArrayBackOne(sArray, nCnt, oTarget, nMax); + SetLocalInt(oTarget, sArrayStore, nSetValue); + SetLocalInt(oTarget, sArrayStore + WEAP_SIZE, nCurrentItemSize); + SetLocalInt(oTarget, sArrayStore + WEAP_DAMAGE, nCurrentItemDamage); SetLocalObject(oTarget, sArrayStore, oItem); - iMax++; - SetLocalInt(oTarget, MAXINT_ + sArray, iMax); - iBreak = TRUE; + nMax++; + SetLocalInt(oTarget, MAXINT_ + sArray, nMax); + bBreak = TRUE; } // If end, we set to the end :-) - else if(i == iMax) + else if(nCnt == nMax) { // Set weapon size as well. Add one to i to be at the end. - sArrayStore = sArray + IntToString(i + i1); - SetLocalInt(oTarget, sArrayStore, iSetValue); - SetLocalInt(oTarget, sArrayStore + WEAP_SIZE, CurrentItemSize); - SetLocalInt(oTarget, sArrayStore + WEAP_DAMAGE, CurrentItemDamage); + sArrayStore = sArray + IntToString(nCnt + 1); + SetLocalInt(oTarget, sArrayStore, nSetValue); + SetLocalInt(oTarget, sArrayStore + WEAP_SIZE, nCurrentItemSize); + SetLocalInt(oTarget, sArrayStore + WEAP_DAMAGE, nCurrentItemDamage); SetLocalObject(oTarget, sArrayStore, oItem); - iMax++; - SetLocalInt(oTarget, MAXINT_ + sArray, iMax); - iBreak = TRUE; + nMax++; + SetLocalInt(oTarget, MAXINT_ + sArray, nMax); + bBreak = TRUE; } } } } - -void MoveArrayBackOne(string sArray, int iNumberStart, object oTarget, int iMax) +// This moves the values from nMax to nNumberStart back one in the list. +void MoveArrayBackOne(string sArray, int nNumberStart, object oTarget, int nMax) { // Get the first item... object oItemAtNumber; string sCurrentName, sNewName; - int iItemAtNumberValue, i, iCurrentItemSize, iCurrentItemDamage; + int nItemAtNumberValue, nCnt, nCurrentItemSize, nCurrentItemDamage; // Move it from the back, back one, then then next... - for(i = iMax; i >= iNumberStart; i--) + for(nCnt = nMax; nCnt >= nNumberStart; nCnt--) { // Sets the name up right. - sCurrentName = sArray + IntToString(i); - sNewName = sArray + IntToString(i + i1); + sCurrentName = sArray + IntToString(nCnt); + sNewName = sArray + IntToString(nCnt + 1); + // Set the things up in the right parts. oItemAtNumber = GetLocalObject(oTarget, sCurrentName); - iItemAtNumberValue = GetLocalInt(oTarget, sCurrentName); - iCurrentItemSize = GetLocalInt(oTarget, sCurrentName + WEAP_SIZE); - iCurrentItemDamage = GetLocalInt(oTarget, sCurrentName + WEAP_DAMAGE); - // To the NEW name - we add one to the i value. + nItemAtNumberValue = GetLocalInt(oTarget, sCurrentName); + nCurrentItemSize = GetLocalInt(oTarget, sCurrentName + WEAP_SIZE); + nCurrentItemDamage = GetLocalInt(oTarget, sCurrentName + WEAP_DAMAGE); + + // To the NEW name - we add one to the nCnt value. SetLocalObject(oTarget, sNewName, oItemAtNumber); - SetLocalInt(oTarget, sNewName, iItemAtNumberValue); - SetLocalInt(oTarget, sNewName + WEAP_SIZE, iCurrentItemSize); - SetLocalInt(oTarget, sNewName + WEAP_DAMAGE, iCurrentItemSize); + SetLocalInt(oTarget, sNewName, nItemAtNumberValue); + SetLocalInt(oTarget, sNewName + WEAP_SIZE, nCurrentItemSize); + SetLocalInt(oTarget, sNewName + WEAP_DAMAGE, nCurrentItemSize); } } void DeleteDatabase(object oTarget, string sArray) { - int iMax = GetLocalInt(oTarget, MAXINT_ + sArray); - int i; + int nMax = GetLocalInt(oTarget, MAXINT_ + sArray); + int nCnt; string sNewName; - if(iMax) + if(nMax > 0) { - for(i = i1; i <= iMax; i++) + for(nCnt = 1; nCnt <= nMax; nCnt++) { - sNewName = sArray + IntToString(i); + sNewName = sArray + IntToString(nCnt); DeleteLocalObject(oTarget, sNewName);// Object DeleteLocalInt(oTarget, sNewName);// Value DeleteLocalInt(oTarget, sNewName + WEAP_SIZE);// Size @@ -1932,30 +1885,33 @@ void DeleteDatabase(object oTarget, string sArray) } void DeleteValueInts(object oTarget, string sArray) { - int iMax = GetLocalInt(oTarget, MAXINT_ + sArray); - int i; - if(iMax) + int nMax = GetLocalInt(oTarget, MAXINT_ + sArray); + int nCnt; + if(nMax) { - for(i = i1; i <= iMax; i++) + for(nCnt = 1; nCnt <= nMax; nCnt++) { - DeleteLocalInt(oTarget, sArray + IntToString(i)); + DeleteLocalInt(oTarget, sArray + IntToString(nCnt)); } } // Note: We keep the size... } - +// Uses right prefix to store the object to oTarget. void SWFinalAIObject(object oTarget, string sName, object oObject) { SetLocalObject(oTarget, AI_OBJECT + sName, oObject); } -void SWFinalAIInteger(object oTarget, string sName, int iInt) +// Uses right prefix to store the iInt to oTarget. +void SWFinalAIInteger(object oTarget, string sName, int nInt) { - SetLocalInt(oTarget, AI_INTEGER + sName, iInt); + SetLocalInt(oTarget, AI_INTEGER + sName, nInt); } +// Deletes object with Prefix void SWDeleteAIObject(object oTarget, string sName) { DeleteLocalObject(oTarget, AI_OBJECT + sName); } +// Deletes integer with Prefix void SWDeleteAIInteger(object oTarget, string sName) { DeleteLocalInt(oTarget, AI_INTEGER + sName); @@ -1965,33 +1921,33 @@ void SWDeleteAIInteger(object oTarget, string sName) void ResetHealingKits(object oTarget) { object oItem, oHighestKit; - int iHealingKitsAmount, iItemValue; - int iRunningValue = i0; // For kits + int nHealingKitsAmount, nItemValue; + int nRunningValue = 0; // For kits // The inventory oItem = GetFirstItemInInventory(oTarget); while(GetIsObjectValid(oItem)) { if(GetBaseItemType(oItem) == BASE_ITEM_HEALERSKIT) { - iHealingKitsAmount++; - iItemValue = GetGoldPieceValue(oItem); + nHealingKitsAmount++; + nItemValue = GetGoldPieceValue(oItem); // Stacked kits be worth what they should be seperatly. - iItemValue = iItemValue/GetNumStackedItems(oItem); - if(iItemValue > iRunningValue) + nItemValue = nItemValue/GetNumStackedItems(oItem); + if(nItemValue > nRunningValue) { - iRunningValue = iItemValue; + nRunningValue = nItemValue; oHighestKit = oItem; } } oItem = GetNextItemInInventory(oTarget); } // Need some, any! - if(iHealingKitsAmount > i0) + if(nHealingKitsAmount > 0) { // set healing kits (if any) SWFinalAIObject(oTarget, AI_VALID_HEALING_KIT_OBJECT, oHighestKit); // Set amount left - SWFinalAIInteger(oTarget, AI_VALID_HEALING_KITS, iHealingKitsAmount); + SWFinalAIInteger(oTarget, AI_VALID_HEALING_KITS, nHealingKitsAmount); } } @@ -2010,34 +1966,10 @@ void DeleteAllPreviousWeapons(object oTarget) SWDeleteAIObject(oTarget, AI_WEAPON_SHIELD_2); } -// Special: Apply EffectCutsceneImmobilize -void AI_SpecialActionApplyItem(object oTarget) +// Debug: To compile this script full, uncomment all of the below. +/* - Add two "/"'s at the start of this line +void main() { - ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectCutsceneImmobilize(), oTarget); + return; } -// Special: Remove EffectCutsceneImmobilize -void AI_SpecialActionRemoveItem(object oTarget) -{ - effect eCheck = GetFirstEffect(oTarget); - while(GetIsEffectValid(eCheck)) - { - if(GetEffectType(eCheck) == EFFECT_TYPE_CUTSCENEIMMOBILIZE && - GetEffectSpellId(eCheck) == iM1) RemoveEffect(oTarget, eCheck); - eCheck = GetNextEffect(oTarget); - } -} -// Gets a item talent value -// - iTalent, 1-21. -void AI_SetItemTalentValue(int iTalent) -{ - // We are already EffectCutsceneImmobilized - - // Simply get the best. - talent tCheck = GetCreatureTalentBest(iTalent, i20); - int iValue = GetIdFromTalent(tCheck); - - // Set to value. - SetAIConstant(ITEM_TALENT_VALUE + IntToString(iTalent), iValue); -} - -//void main(){ SetWeapons(); } +//*/ diff --git a/_module/nss/j_inc_spawnin.nss b/_module/nss/j_inc_spawnin.nss index 7739f8df..38c742c9 100644 --- a/_module/nss/j_inc_spawnin.nss +++ b/_module/nss/j_inc_spawnin.nss @@ -1,25 +1,32 @@ -/************************ [Spawn In Include] *********************************** +/*/////////////////////// [Include - Spawn In] ///////////////////////////////// Filename: J_Inc_SpawnIn -************************* [Spawn In Include] *********************************** +///////////////////////// [Include - Spawn In] ///////////////////////////////// This contains all the functions used in the spawning process, in one easy and very long file. It also importantly sets up spells we have, or at least talents, so we know if we have any spells from category X. -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.3 - Changed, added a lot of new things (such as constants file) -************************* [Workings] ******************************************* + 1.4 - No more setting talent categories On Spawn. This is too much hassel. + See the On rest script for ideas (remove this when complete!). + + Perhaps set "Items" the first time we enter combat, and reset each time + combat stops. Can be more efficeint maybe. + - Skills set to "use" should have, say, 3 or more skill points to be + used automatically, especially true for hiding. +///////////////////////// [Workings] /////////////////////////////////////////// This doesn't call anything to run the rest, except AI_SetUpEndOfSpawn has a lot of things that the generic AI requires (SetListeningPatterns and skills and waypoints ETC) See the spawn in script for all the actual uses. -************************* [Arguments] ****************************************** +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: N/A see spawn in script -************************* [Spawn In Include] **********************************/ +///////////////////////// [Include - Spawn In] ///////////////////////////////*/ // All constants. -#include "j_inc_setweapons" +#include "J_INC_SETWEAPONS" // Set weapons // - Constants file is in this @@ -39,52 +46,55 @@ const int NW_ANIM_FLAG_IS_MOBILE_CLOSE_RANGE = 0x00000200; // This will activate one aura, very quickly. // If we have more than one...oh well. void AI_AdvancedAuras(); -// Activate the aura number, if it is possible. +// Activate the aura number (IE: Spell number), if it is possible. void AI_ActivateAura(int nAuraNumber); -// This is an attempt to speed up some things. -// We use talents to set general valid categories. -// Levels are also accounted for, checking the spell given and using a switch -// statement to get the level. -void AI_SetUpSpells(); // Base for moving round thier waypoints // - Uses ExectuteScript to run the waypoint walking. -void SpawnWalkWayPoints(int nRun = FALSE, float fPause = 1.0); +// * If bRun is TRUE, we run all the waypoint. +// * fPause is the time delay between walking to the next waypoint (default 1.0) +void SpawnWalkWayPoints(int bRun = FALSE, float fPause = 1.0); // Sets up what we will listen to (everything!) void AI_SetListeningPatterns(); // This will set what creature to create OnDeath. void AI_SetDeathResRef(string sResRef); // This will set the string, sNameOfValue, to sValue. Array size of 1. -// - Use iPercentToSay to determine what % out of 100 it is said. -void AI_SetSpawnInSpeakValue(string sNameOfValue, string sValue, int iPercentToSay = 100); +// - Use nPercentToSay to determine what % out of 100 it is said. +void AI_SetSpawnInSpeakValue(string sNameOfValue, string sValue, int nPercentToSay = 100); // This will choose a random string, using iAmountOfValues, which is // the amount of non-empty strings given. The size of the array is therefore 1. -// - Use iPercentToSay to determine what % out of 100 it is said. -void AI_SetSpawnInSpeakRandomValue(string sNameOfValue, int iPercentToSay, int iAmountOfValues, string sValue1, string sValue2, string sValue3 = "", string sValue4 = "", string sValue5 = "", string sValue6 = "", string sValue7 = "", string sValue8 = "", string sValue9 = "", string sValue10 = "", string sValue11 = "", string sValue12 = ""); +// - Use nPercentToSay to determine what % out of 100 it is said. +void AI_SetSpawnInSpeakRandomValue(string sNameOfValue, int nPercentToSay, int nAmountOfValues, string sValue1, string sValue2, string sValue3 = "", string sValue4 = "", string sValue5 = "", string sValue6 = "", string sValue7 = "", string sValue8 = "", string sValue9 = "", string sValue10 = "", string sValue11 = "", string sValue12 = ""); // This will set an array of values, to sNameOfValue, for one to be chosen to // be said at the right time :-) // - sNameOfValue must be a valid name. // - Use iPercentToSay to determine what % out of 100 it is said. // NOTE: If the sNameOfValue is any combat one, we make that 1/100 to 1/1000. -void AI_SetSpawnInSpeakArray(string sNameOfValue, int iPercentToSay, int iSize, string sValue1, string sValue2, string sValue3 = "", string sValue4 = "", string sValue5 = "", string sValue6 = "", string sValue7 = "", string sValue8 = "", string sValue9 = "", string sValue10 = "", string sValue11 = "", string sValue12 = ""); +void AI_SetSpawnInSpeakArray(string sNameOfValue, int nPercentToSay, int nSize, string sValue1, string sValue2, string sValue3 = "", string sValue4 = "", string sValue5 = "", string sValue6 = "", string sValue7 = "", string sValue8 = "", string sValue9 = "", string sValue10 = "", string sValue11 = "", string sValue12 = ""); // This applies an increase, decrease or no change to the intended stat. -void AI_ApplyStatChange(int iStat, int iAmount); -// This will alter (magically) an ammount of random stats - iAmount -// by a value within iLowest and iHighest. -void AI_CreateRandomStats(int iLowest, int iHighest, int iAmount); +// * Applies the effects INSTANTLY. These CANNOT be removed easily! +void AI_ApplyStatChange(int nStat, int nAmount); +// This will alter (magically) an ammount of random stats - nAmount +// by a value within iLowest and nHighest. +// * Applies the effects INSTANTLY. These CANNOT be removed easily! +void AI_CreateRandomStats(int nLowest, int nHighest, int nAmount); // This will randomise other stats. Put both numbers to 0 to ignore some. -// iHPMin, iHPMax = HP changes. -// iReflexSaveMin, iReflexSaveMax = Reflex Save changes -// iWillSaveMin, iWillSaveMax = Will Save changes -// iFortSaveMin, iFortSaveMax = Fortitude Save changes -// iACMin, iACMax = AC change. -// Use iACType to define the AC type - default AC_DODGE_BONUS -void AI_CreateRandomOther(int iHPMin, int iHPMax, int iReflexSaveMin = 0, int iReflexSaveMax = 0, int iWillSaveMin = 0, int iWillSaveMax = 0, int iFortSaveMin = 0, int iFortSaveMax = 0, int iACMin = 0, int iACMax = 0, int iACType = AC_DODGE_BONUS); +// nHPMin, nHPMax = HP changes. +// nReflexSaveMin, nReflexSaveMax = Reflex Save changes +// nWillSaveMin, nWillSaveMax = Will Save changes +// nFortSaveMin, nFortSaveMax = Fortitude Save changes +// nACMin, nACMax = AC change. +// Use nACType to define the AC type - default AC_DODGE_BONUS +// * Applies the effects INSTANTLY. These CANNOT be removed easily! +void AI_CreateRandomOther(int nHPMin, int nHPMax, int nReflexSaveMin = 0, int nReflexSaveMax = 0, int nWillSaveMin = 0, int nWillSaveMax = 0, int nFortSaveMin = 0, int nFortSaveMax = 0, int nACMin = 0, int nACMax = 0, int nACType = AC_DODGE_BONUS); // Sets up thier selection of skills, to integers, if they would ever use them. // NOTE: it also triggers "hide" if they have enough skill and not stopped. +// * 1.4 Changes: Some skills are turned off automatically when they have very +// low points in that skill (IE: No possibility of doing it sucessfully). Also +// edited other parts of the AI to take this into account. void AI_SetUpSkillToUse(); // Sets the turning level if we have FEAT_TURN_UNDEAD. // - Called from AI_SetUpEndOfSpawn. @@ -94,12 +104,12 @@ void AI_SetTurningLevel(); // These MUST be called! the AI might fail to work correctly if they don't fire! void AI_SetUpEndOfSpawn(); // This will make the visual effect passed play INSTANTLY at the creatures location. -// * iVFX - The visual effect constant number -void AI_SpawnInInstantVisual(int iVFX); +// * nVFX - The visual effect constant number +void AI_SpawnInInstantVisual(int nVFX); // This will make the visual effect passed play PERMAMENTLY. -// * iVFX - The visual effect constant number +// * nVFX - The visual effect constant number // NOTE: They will be made to be SUPERNATUAL, so are not dispelled! -void AI_SpawnInPermamentVisual(int iVFX); +void AI_SpawnInPermamentVisual(int nVFX); // This should not be used! // * called from SetUpEndOfSpawn. void AI_SetMaybeFearless(); @@ -108,9 +118,9 @@ void AI_SetMaybeFearless(); // - If we set it to min of 5, max of 10, for AC, if we cancled 5 targets on having // AC higher then wanted, we will take the highest 5 minimum. // If there are over 10, we take a max of 10 to choose from. -// * iType - must be TARGET_HIGHER or TARGET_LOWER. Defaults to the lowest, so it +// * nType - must be TARGET_HIGHER or TARGET_LOWER. Defaults to the lowest, so it // targets the lowest value for sName. -void AI_SetAITargetingValues(string sName, int iType, int iMinimum, int iMaximum); +void AI_SetAITargetingValues(string sName, int nType, int nMinimum, int nMaximum); // Levels up us. @@ -127,7 +137,7 @@ void AI_LevelLoop(int nClass, int nLevels); // Sets up what random spells to cheat-cast at the end of all known spells. // it does NOT check for immunities, barriers, or anything else. // - You can set spells to more then one of the imputs to have a higher % to cast that one. -void SetAICheatCastSpells(int iSpell1, int iSpell2, int iSpell3, int iSpell4, int iSpell5, int iSpell6); +void SetAICheatCastSpells(int nSpell1, int nSpell2, int nSpell3, int nSpell4, int nSpell5, int nSpell6); // Mark that the given creature has the given condition set for anitmations // * Bioware SoU animations thing. @@ -147,10 +157,10 @@ void SetMindflayerAI(); // SPELLTRIGGER_NOT_GOT_FIRST_SPELL - Makes sure !GetHasSpellEffect(iSpell1) already, // then fires. Checks all in this category each round (first one fires!) // SPELLTRIGGER_START_OF_COMBAT - Triggered always, at the start of DetermineCombatRound. -// * iNumber - can be 1-9, in sequential order of when you want them to fire. -// * iValue - is only required with DAMAGED_AT_PERCENT. -// * iSpellX - Cannot be 0. It should only really be defensive spells. -void SetSpellTrigger(string sType, int iValue, int iNumber, int iSpell1, int iSpell2 = 0, int iSpell3 = 0, int iSpell4 = 0, int iSpell5 = 0, int iSpell6 = 0, int iSpell7 = 0, int iSpell8 = 0, int iSpell9 = 0); +// * nNumber - can be 1-9, in sequential order of when you want them to fire. +// * nValue - is only required with DAMAGED_AT_PERCENT. +// * nSpellX - Cannot be 0. It should only really be defensive spells. +void SetSpellTrigger(string sType, int nValue, int nNumber, int nSpell1, int nSpell2 = 0, int nSpell3 = 0, int nSpell4 = 0, int nSpell5 = 0, int nSpell6 = 0, int nSpell7 = 0, int nSpell8 = 0, int nSpell9 = 0); // Mark that the given creature has the given condition set void SetAnimationCondition(int nCondition, int bValid = TRUE, object oCreature = OBJECT_SELF) @@ -166,14 +176,14 @@ void SetAnimationCondition(int nCondition, int bValid = TRUE, object oCreature = // Sets up what random spells to cheat-cast at the end of all known spells. // it does NOT check for immunities, barriers, or anything else. // - You can set spells to more then one of the imputs to have a higher % to cast that one. -void SetAICheatCastSpells(int iSpell1, int iSpell2, int iSpell3, int iSpell4, int iSpell5, int iSpell6) +void SetAICheatCastSpells(int nSpell1, int nSpell2, int nSpell3, int nSpell4, int nSpell5, int nSpell6) { - SetAIConstant(AI_CHEAT_CAST_SPELL + IntToString(i1), iSpell1); - SetAIConstant(AI_CHEAT_CAST_SPELL + IntToString(i2), iSpell2); - SetAIConstant(AI_CHEAT_CAST_SPELL + IntToString(i3), iSpell3); - SetAIConstant(AI_CHEAT_CAST_SPELL + IntToString(i4), iSpell4); - SetAIConstant(AI_CHEAT_CAST_SPELL + IntToString(i5), iSpell5); - SetAIConstant(AI_CHEAT_CAST_SPELL + IntToString(i6), iSpell6); + SetAIConstant(AI_CHEAT_CAST_SPELL + IntToString(1), nSpell1); + SetAIConstant(AI_CHEAT_CAST_SPELL + IntToString(2), nSpell2); + SetAIConstant(AI_CHEAT_CAST_SPELL + IntToString(3), nSpell3); + SetAIConstant(AI_CHEAT_CAST_SPELL + IntToString(4), nSpell4); + SetAIConstant(AI_CHEAT_CAST_SPELL + IntToString(5), nSpell5); + SetAIConstant(AI_CHEAT_CAST_SPELL + IntToString(6), nSpell6); } @@ -186,16 +196,16 @@ void SetAICheatCastSpells(int iSpell1, int iSpell2, int iSpell3, int iSpell4, in void AI_LevelUpCreature(int nLevel, int nClass, int nClass2 = CLASS_TYPE_INVALID, int nClass3 = CLASS_TYPE_INVALID) { // Divide by 1, 2 or 3 (100%, 50%, 33%) - int iDivideBy = (nClass >= i0) + (nClass2 >= i0) + (nClass3 >= i0); + int nDivideBy = (nClass >= 0) + (nClass2 >= 0) + (nClass3 >= 0); - int iTotalPerClass = nLevel / iDivideBy; + int nTotalPerClass = nLevel / nDivideBy; // Limit and loop - Class 1. - AI_LevelLoop(nClass, iTotalPerClass); + AI_LevelLoop(nClass, nTotalPerClass); // 2 - AI_LevelLoop(nClass2, iTotalPerClass); + AI_LevelLoop(nClass2, nTotalPerClass); // 3 - AI_LevelLoop(nClass3, iTotalPerClass); + AI_LevelLoop(nClass3, nTotalPerClass); } // Used in AI_LevelUpCreature. @@ -220,115 +230,116 @@ void AI_SetDeathResRef(string sResRef) // - Use iPercentToSay to determine what % out of 100 it is said. void AI_SetSpawnInSpeakValue(string sNameOfValue, string sValue, int iPercentToSay) { - SetLocalString(OBJECT_SELF, sNameOfValue + s1, sValue); + SetLocalString(OBJECT_SELF, sNameOfValue + "1", sValue); // The array is 1 big! - SetLocalInt(OBJECT_SELF, ARRAY_SIZE + sNameOfValue, i1); + SetLocalInt(OBJECT_SELF, ARRAY_SIZE + sNameOfValue, 1); SetLocalInt(OBJECT_SELF, ARRAY_PERCENT + sNameOfValue, iPercentToSay); } // This will choose a random string, using iAmountOfValues, which is // the amount of non-empty strings given. The size of the array is therefore 1. // - Use iPercentToSay to determine what % out of 100 it is said. -void AI_SetSpawnInSpeakRandomValue(string sNameOfValue, int iPercentToSay, int iAmountOfValues, string sValue1, string sValue2, string sValue3, string sValue4, string sValue5, string sValue6, string sValue7, string sValue8, string sValue9, string sValue10, string sValue11, string sValue12) +void AI_SetSpawnInSpeakRandomValue(string sNameOfValue, int nPercentToSay, int nAmountOfValues, string sValue1, string sValue2, string sValue3, string sValue4, string sValue5, string sValue6, string sValue7, string sValue8, string sValue9, string sValue10, string sValue11, string sValue12) { // Need a value amount of values! - if(iAmountOfValues) + if(nAmountOfValues) { - int iRandomNum = Random(iAmountOfValues) -1; // take one, as it is 0 - X, not 1 - X + int nRandomNum = Random(nAmountOfValues) - 1; // take one, as it is 0 - X, not 1 - X string sValueToUse; - switch(iRandomNum) + switch(nRandomNum) { - case(i0):{sValueToUse = sValue1;}break; - case(i1):{sValueToUse = sValue2;}break; - case(i2):{sValueToUse = sValue3;}break; - case(i3):{sValueToUse = sValue4;}break; - case(i4):{sValueToUse = sValue5;}break; - case(i5):{sValueToUse = sValue6;}break; - case(i6):{sValueToUse = sValue7;}break; - case(i7):{sValueToUse = sValue8;}break; - case(i8):{sValueToUse = sValue9;}break; - case(i9):{sValueToUse = sValue10;}break; - case(i10):{sValueToUse = sValue11;}break; - case(i11):{sValueToUse = sValue12;}break; + case 0:{sValueToUse = sValue1;}break; + case 1:{sValueToUse = sValue2;}break; + case 2:{sValueToUse = sValue3;}break; + case 3:{sValueToUse = sValue4;}break; + case 4:{sValueToUse = sValue5;}break; + case 5:{sValueToUse = sValue6;}break; + case 6:{sValueToUse = sValue7;}break; + case 7:{sValueToUse = sValue8;}break; + case 8:{sValueToUse = sValue9;}break; + case 9:{sValueToUse = sValue10;}break; + case 10:{sValueToUse = sValue11;}break; + case 11:{sValueToUse = sValue12;}break; } - SetLocalString(OBJECT_SELF, sNameOfValue + s1, sValueToUse); + SetLocalString(OBJECT_SELF, sNameOfValue + "1", sValueToUse); // The array is 1 big! - SetLocalInt(OBJECT_SELF, ARRAY_SIZE + sNameOfValue, i1); - SetLocalInt(OBJECT_SELF, ARRAY_PERCENT + sNameOfValue, iPercentToSay); + SetLocalInt(OBJECT_SELF, ARRAY_SIZE + sNameOfValue, 1); + SetLocalInt(OBJECT_SELF, ARRAY_PERCENT + sNameOfValue, nPercentToSay); } } -void AI_SetSpawnInSpeakArray(string sNameOfValue, int iPercentToSay, int iSize, string sValue1, string sValue2, string sValue3 = "", string sValue4 = "", string sValue5 = "", string sValue6 = "", string sValue7 = "", string sValue8 = "", string sValue9 = "", string sValue10 = "", string sValue11 = "", string sValue12 = "") +void AI_SetSpawnInSpeakArray(string sNameOfValue, int nPercentToSay, int nSize, string sValue1, string sValue2, string sValue3 = "", string sValue4 = "", string sValue5 = "", string sValue6 = "", string sValue7 = "", string sValue8 = "", string sValue9 = "", string sValue10 = "", string sValue11 = "", string sValue12 = "") { - if(iSize >= i1) + if(nSize >= 1) { SetLocalString(OBJECT_SELF, sNameOfValue + "1", sValue1); - if(iSize >= i2) + if(nSize >= 2) { SetLocalString(OBJECT_SELF, sNameOfValue + "2", sValue2); - if(iSize >= i3) + if(nSize >= 3) { SetLocalString(OBJECT_SELF, sNameOfValue + "3", sValue3); - if(iSize >= i4) + if(nSize >= 4) { SetLocalString(OBJECT_SELF, sNameOfValue + "4", sValue4); - if(iSize >= i5) + if(nSize >= 5) { SetLocalString(OBJECT_SELF, sNameOfValue + "5", sValue5); - if(iSize >= i6) + if(nSize >= 6) { SetLocalString(OBJECT_SELF, sNameOfValue + "6", sValue6); - if(iSize >= i7) + if(nSize >= 7) { SetLocalString(OBJECT_SELF, sNameOfValue + "7", sValue7); - if(iSize >= i8) + if(nSize >= 8) { SetLocalString(OBJECT_SELF, sNameOfValue + "8", sValue8); - if(iSize >= i9) + if(nSize >= 9) { SetLocalString(OBJECT_SELF, sNameOfValue + "9", sValue9); - if(iSize >= i10) + if(nSize >= 10) { SetLocalString(OBJECT_SELF, sNameOfValue + "10", sValue10); - if(iSize >= i11) + if(nSize >= 11) { SetLocalString(OBJECT_SELF, sNameOfValue + "11", sValue11); - if(iSize >= i12) + if(nSize >= 12) { SetLocalString(OBJECT_SELF, sNameOfValue + "12", sValue12); // Hehe, this looks not stright if you stare at it! :-P } } } } } } } } } } } } // The array is so big... - SetLocalInt(OBJECT_SELF, ARRAY_SIZE + sNameOfValue, iSize); - SetLocalInt(OBJECT_SELF, ARRAY_PERCENT + sNameOfValue, iPercentToSay); + SetLocalInt(OBJECT_SELF, ARRAY_SIZE + sNameOfValue, nSize); + SetLocalInt(OBJECT_SELF, ARRAY_PERCENT + sNameOfValue, nPercentToSay); } // This applies an increase, decrease or no change to the intended stat. -void AI_ApplyStatChange(int iStat, int iAmount) +// * Applies the effects INSTANTLY. These CANNOT be removed easily! +void AI_ApplyStatChange(int nStat, int nAmount) { - if(iAmount != i0) + if(nAmount != 0) { effect eChange; - if(iAmount < i0) + if(nAmount < 0) { - int iNewAmount = abs(iAmount); - eChange = SupernaturalEffect(EffectAbilityDecrease(iStat, iNewAmount)); - ApplyEffectToObject(DURATION_TYPE_PERMANENT, eChange, OBJECT_SELF); + nAmount = abs(nAmount); + eChange = SupernaturalEffect(EffectAbilityDecrease(nStat, nAmount)); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eChange, OBJECT_SELF); } else { - eChange = SupernaturalEffect(EffectAbilityIncrease(iStat, iAmount)); - ApplyEffectToObject(DURATION_TYPE_PERMANENT, eChange, OBJECT_SELF); + eChange = SupernaturalEffect(EffectAbilityIncrease(nStat, nAmount)); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eChange, OBJECT_SELF); } } } // This will, eventually, choose X number of stats, and change them within the // range given. -void AI_CreateRandomStats(int iLowest, int iHighest, int iAmount) +void AI_CreateRandomStats(int nLowest, int nHighest, int nAmount) { - if(iAmount > i0 && !(iLowest == i0 && iHighest == i0) && iHighest >= iLowest) + if(nAmount > 0 && nHighest != 0 && nLowest != 0 && nHighest >= nLowest) { - int iRange = iHighest - iLowest; - int iNumSlots = iAmount; - if(iNumSlots > i6) iNumSlots = i6; - int iNumLeft = i6; + int nRange = nHighest - nLowest; + int nNumSlots = nAmount; + if(nNumSlots > 6) nNumSlots = 6; + int nNumLeft = 6; // Walk through each stat and figure out what it's chance of being // modified is. As an example, suppose we wanted to have 4 randomized // abilities. We'd look at the first ability and it would have a 4 in 6 @@ -336,102 +347,114 @@ void AI_CreateRandomStats(int iLowest, int iHighest, int iAmount) // have a 3 in 5 chance of being picked. If this next ability wasn't // picked to be changed, the 3rd ability woud have a 3 in 4 chance of // being picked and so on. - int iCnt; - int iChange; - for(iCnt = i0; (iNumSlots > i0) && (iCnt < i6); iCnt++) + int nCnt; + int nChange; + for(nCnt = 0; (nNumSlots > 0 && nCnt < 6); nCnt++) { - if((iNumSlots == iNumLeft) || (Random(iNumLeft) < iNumSlots)) + if((nNumSlots == nNumLeft) || (Random(nNumLeft) < nNumSlots)) { - iChange = Random(iRange) + iLowest; - AI_ApplyStatChange(iCnt, iChange); - iNumSlots--; + nChange = Random(nRange) + nLowest; + AI_ApplyStatChange(nCnt, nChange); + nNumSlots--; } - iNumLeft--; + nNumLeft--; } } } -void AI_CreateRandomOther(int iHPMin, int iHPMax, int iReflexSaveMin = 0, int iReflexSaveMax = 0, int iWillSaveMin = 0, int iWillSaveMax = 0, int iFortSaveMin = 0, int iFortSaveMax = 0, int iACMin = 0, int iACMax = 0, int iACType = AC_DODGE_BONUS) +// This will randomise other stats. Put both numbers to 0 to ignore some. +// nHPMin, nHPMax = HP changes. +// nReflexSaveMin, nReflexSaveMax = Reflex Save changes +// nWillSaveMin, nWillSaveMax = Will Save changes +// nFortSaveMin, nFortSaveMax = Fortitude Save changes +// nACMin, nACMax = AC change. +// Use nACType to define the AC type - default AC_DODGE_BONUS +// * Applies the effects INSTANTLY. These CANNOT be removed easily! +void AI_CreateRandomOther(int nHPMin, int nHPMax, int nReflexSaveMin = 0, int nReflexSaveMax = 0, int nWillSaveMin = 0, int nWillSaveMax = 0, int nFortSaveMin = 0, int nFortSaveMax = 0, int nACMin = 0, int nACMax = 0, int nACType = AC_DODGE_BONUS) { - int iRange, iChange, iNewChange; + int nRange, nChange, nNewChange; effect eChange; - if(!(iHPMin == i0 && iHPMax == i0) && iHPMax >= iHPMin) + if(!(nHPMin == 0 && nHPMax == 0) && nHPMax >= nHPMin) { - iRange = iHPMax - iHPMin; - iChange = Random(iRange) + iHPMin; - if(iChange > i0) + nRange = nHPMax - nHPMin; + nChange = Random(nRange) + nHPMin; + if(nChange > 0) { - eChange = SupernaturalEffect(EffectTemporaryHitpoints(iChange)); - ApplyEffectToObject(DURATION_TYPE_PERMANENT, eChange, OBJECT_SELF); + eChange = SupernaturalEffect(EffectTemporaryHitpoints(nChange)); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eChange, OBJECT_SELF); } - else if(iChange < i0 && GetMaxHitPoints() > i1) + // * Must have 1HP remaining at least. + else if(nChange < 0 && GetMaxHitPoints() > nChange) { - eChange = EffectDamage(iChange, DAMAGE_TYPE_DIVINE, DAMAGE_POWER_PLUS_FIVE); - ApplyEffectToObject(DURATION_TYPE_PERMANENT, eChange, OBJECT_SELF); + eChange = EffectDamage(nChange, DAMAGE_TYPE_DIVINE, DAMAGE_POWER_PLUS_TWENTY); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eChange, OBJECT_SELF); } } - if(!(iReflexSaveMin == i0 && iReflexSaveMax == i0) && iReflexSaveMax >= iReflexSaveMin) + if(!(nReflexSaveMin == 0 && nReflexSaveMax == 0) && nReflexSaveMax >= nReflexSaveMin) { - iRange = iReflexSaveMax - iReflexSaveMin; - iChange = Random(iRange) + iReflexSaveMin; - if(iChange > i0) + nRange = nReflexSaveMax - nReflexSaveMin; + nChange = Random(nRange) + nReflexSaveMin; + if(nChange > 0) { - eChange = SupernaturalEffect(EffectSavingThrowIncrease(SAVING_THROW_REFLEX, iChange)); - ApplyEffectToObject(DURATION_TYPE_PERMANENT, eChange, OBJECT_SELF); + eChange = SupernaturalEffect(EffectSavingThrowIncrease(SAVING_THROW_REFLEX, nChange)); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eChange, OBJECT_SELF); } - else if(iChange < i0 && GetReflexSavingThrow(OBJECT_SELF) > i1) + // Cannot apply 0 change, but can make our saves negative + else if(nChange < 0) { - iNewChange = abs(iChange); - eChange = SupernaturalEffect(EffectSavingThrowDecrease(SAVING_THROW_REFLEX, iNewChange)); - ApplyEffectToObject(DURATION_TYPE_PERMANENT, eChange, OBJECT_SELF); + nNewChange = abs(nChange); + eChange = SupernaturalEffect(EffectSavingThrowDecrease(SAVING_THROW_REFLEX, nNewChange)); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eChange, OBJECT_SELF); } } - if(!(iWillSaveMin == i0 && iWillSaveMax == i0) && iWillSaveMax >= iWillSaveMin) + if(!(nWillSaveMin == 0 && nWillSaveMax == 0) && nWillSaveMax >= nWillSaveMin) { - iRange = iWillSaveMax - iWillSaveMin; - iChange = Random(iRange) + iWillSaveMin; - if(iChange > i0) + nRange = nWillSaveMax - nWillSaveMin; + nChange = Random(nRange) + nWillSaveMin; + if(nChange > 0) { - eChange = SupernaturalEffect(EffectSavingThrowIncrease(SAVING_THROW_WILL, iChange)); - ApplyEffectToObject(DURATION_TYPE_PERMANENT, eChange, OBJECT_SELF); + eChange = SupernaturalEffect(EffectSavingThrowIncrease(SAVING_THROW_WILL, nChange)); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eChange, OBJECT_SELF); } - else if(iChange < i0 && GetWillSavingThrow(OBJECT_SELF) > i1) + // Cannot apply 0 change, but can make our saves negative + else if(nChange < 0) { - iNewChange = abs(iChange); - eChange = SupernaturalEffect(EffectSavingThrowDecrease(SAVING_THROW_WILL, iNewChange)); - ApplyEffectToObject(DURATION_TYPE_PERMANENT, eChange, OBJECT_SELF); + nNewChange = abs(nChange); + eChange = SupernaturalEffect(EffectSavingThrowDecrease(SAVING_THROW_WILL, nNewChange)); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eChange, OBJECT_SELF); } } - if(!(iFortSaveMin == i0 && iFortSaveMax == i0) && iFortSaveMax >= iFortSaveMin) + if(!(nFortSaveMin == 0 && nFortSaveMax == 0) && nFortSaveMax >= nFortSaveMin) { - iRange = iFortSaveMax - iFortSaveMin; - iChange = Random(iRange) + iFortSaveMin; - if(iChange > i0) + nRange = nFortSaveMax - nFortSaveMin; + nChange = Random(nRange) + nFortSaveMin; + if(nChange > 0) { - eChange = SupernaturalEffect(EffectSavingThrowIncrease(SAVING_THROW_FORT, iChange)); - ApplyEffectToObject(DURATION_TYPE_PERMANENT, eChange, OBJECT_SELF); + eChange = SupernaturalEffect(EffectSavingThrowIncrease(SAVING_THROW_FORT, nChange)); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eChange, OBJECT_SELF); } - else if(iChange < i0 && GetFortitudeSavingThrow(OBJECT_SELF) > 1) + // Cannot apply 0 change, but can make our saves negative + else if(nChange < 0) { - iNewChange = abs(iChange); - eChange = SupernaturalEffect(EffectSavingThrowDecrease(SAVING_THROW_FORT, iNewChange)); - ApplyEffectToObject(DURATION_TYPE_PERMANENT, eChange, OBJECT_SELF); + nNewChange = abs(nChange); + eChange = SupernaturalEffect(EffectSavingThrowDecrease(SAVING_THROW_FORT, nNewChange)); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eChange, OBJECT_SELF); } } - if(!(iACMin == i0 && iACMax == i0) && iACMax >= iACMin) + if(!(nACMin == 0 && nACMax == 0) && nACMax >= nACMin) { - iRange = iACMax - iACMin; - iChange = Random(iRange) + iACMin; - if(iChange > i0) + nRange = nACMax - nACMin; + nChange = Random(nRange) + nACMin; + if(nChange > 0) { - eChange = SupernaturalEffect(EffectACIncrease(iChange, iACType)); - ApplyEffectToObject(DURATION_TYPE_PERMANENT, eChange, OBJECT_SELF); + eChange = SupernaturalEffect(EffectACIncrease(nChange, nACType)); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eChange, OBJECT_SELF); } - else if(iChange < i0) + else if(nChange < 0) { - iNewChange = abs(iChange); - eChange = SupernaturalEffect(EffectACDecrease(iNewChange, iACType)); - ApplyEffectToObject(DURATION_TYPE_PERMANENT, eChange, OBJECT_SELF); + nNewChange = abs(nChange); + eChange = SupernaturalEffect(EffectACDecrease(nNewChange, nACType)); + ApplyEffectToObject(DURATION_TYPE_INSTANT, eChange, OBJECT_SELF); } } } @@ -447,52 +470,54 @@ void AI_SetListeningPatterns() // Lag check if(GetSpawnInCondition(AI_FLAG_OTHER_LAG_NO_LISTENING, AI_OTHER_MASTER)) return; SetListening(OBJECT_SELF, TRUE); -// Anyone that can hear it, and is not fighting, comes and helps - SetListenPattern(OBJECT_SELF, I_WAS_ATTACKED, i1); + + // Anyone that can hear it, and is not fighting, comes and helps + SetListenPattern(OBJECT_SELF, AI_SHOUT_I_WAS_ATTACKED, AI_SHOUT_I_WAS_ATTACKED_CONSTANT); + //Set a custom listening pattern for the creature so that placables with //"NW_BLOCKER" + Blocker NPC Tag will correctly call to their blockers. string sBlocker = "NW_BLOCKER_BLK_" + GetTag(OBJECT_SELF); - SetListenPattern(OBJECT_SELF, sBlocker, i2); -// Determines combat round, if not fighting - SetListenPattern(OBJECT_SELF, CALL_TO_ARMS, i3); + SetListenPattern(OBJECT_SELF, sBlocker, AI_SHOUT_BLOCKER_CONSTANT); + + // Determines combat round, if not fighting + SetListenPattern(OBJECT_SELF, AI_SHOUT_CALL_TO_ARMS, AI_SHOUT_CALL_TO_ARMS_CONSTANT); + // These call to allies, to move them to a battle. - SetListenPattern(OBJECT_SELF, HELP_MY_FRIEND, i4); - SetListenPattern(OBJECT_SELF, LEADER_FLEE_NOW, i5); - SetListenPattern(OBJECT_SELF, LEADER_ATTACK_TARGET, i6); + SetListenPattern(OBJECT_SELF, AI_SHOUT_HELP_MY_FRIEND, AI_SHOUT_HELP_MY_FRIEND_CONSTANT); + SetListenPattern(OBJECT_SELF, AI_SHOUT_LEADER_FLEE_NOW, AI_SHOUT_LEADER_FLEE_NOW_CONSTANT); + SetListenPattern(OBJECT_SELF, AI_SHOUT_LEADER_ATTACK_TARGET, AI_SHOUT_LEADER_ATTACK_TARGET_CONSTANT); + // 1.3 - Need a killed one. - SetListenPattern(OBJECT_SELF, I_WAS_KILLED, i7); + SetListenPattern(OBJECT_SELF, AI_SHOUT_I_WAS_KILLED, AI_SHOUT_I_WAS_KILLED_CONSTANT); + // 1.3 - PLaceables/doors which shout this get responded to! - SetListenPattern(OBJECT_SELF, I_WAS_OPENED, i8); -// This will make the listener hear anything, used to react to enemy talking. - SetListenPattern(OBJECT_SELF, "**", i0); + SetListenPattern(OBJECT_SELF, AI_SHOUT_I_WAS_OPENED, AI_SHOUT_I_WAS_OPENED_CONSTANT); + + // This will make the listener hear anything, used to react to enemy talking. + SetListenPattern(OBJECT_SELF, "**", AI_SHOUT_ANYTHING_SAID_CONSTANT); } + // Base for moving round thier waypoints // - Uses ExectuteScript to run the waypoint walking. -void SpawnWalkWayPoints(int nRun = FALSE, float fPause = 1.0) +// * If bRun is TRUE, we run all the waypoint. +// * fPause is the time delay between walking to the next waypoint (default 1.0) +void SpawnWalkWayPoints(int bRun = FALSE, float fPause = 1.0) { - SetLocalInt(OBJECT_SELF, WAYPOINT_RUN, nRun); + SetLocalInt(OBJECT_SELF, WAYPOINT_RUN, bRun); SetLocalFloat(OBJECT_SELF, WAYPOINT_PAUSE, fPause); ExecuteScript(FILE_WALK_WAYPOINTS, OBJECT_SELF); } - +// This MUST be called. It fires these events: +// SetUpSpells, SetUpSkillToUse, SetListeningPatterns, SetWeapons, AdvancedAuras. +// These MUST be called! the AI might fail to work correctly if they don't fire! void AI_SetUpEndOfSpawn() { - // Check if we are using custom AI - this cuts out much of the stuff - // used on spawn. - int bCustomAIFile = FALSE; - - // Check custom AI file - if(GetCustomAIFileName() != "") - { - bCustomAIFile = TRUE; - } - if(GetSpawnInCondition(AI_FLAG_OTHER_RETURN_TO_SPAWN_LOCATION, AI_OTHER_MASTER)) { // This will store thier starting location, and then move back there after combat // Will turn off if there are waypoints. It is set in SetUpEndOfSpawn. - SetLocalLocation(OBJECT_SELF, AI_RETURN_TO_POINT, GetLocation(OBJECT_SELF)); + SetAILocation(AI_RETURN_TO_POINT, GetLocation(OBJECT_SELF)); } // Set up if we are immune to cirtain levels of spells naturally for better @@ -502,39 +527,36 @@ void AI_SetUpEndOfSpawn() if(GetItemHasItemProperty(oHide, ITEM_PROPERTY_IMMUNITY_SPELLS_BY_LEVEL)) { itemproperty eCheck = GetFirstItemProperty(oHide); - int iAmount; + int nAmount; // Check for item properties until we find the level. - while(GetIsItemPropertyValid(eCheck) && iAmount == FALSE) + while(GetIsItemPropertyValid(eCheck) && nAmount == FALSE) { // Check subtype. if(GetItemPropertyType(eCheck) == ITEM_PROPERTY_IMMUNITY_SPELLS_BY_LEVEL) { // Get the amount - iAmount = GetItemPropertyCostTableValue(eCheck); + nAmount = GetItemPropertyCostTableValue(eCheck); } eCheck = GetNextItemProperty(oHide); } // Set it - if(iAmount) + if(nAmount) { - SetLocalInt(OBJECT_SELF, AI_SPELL_IMMUNE_LEVEL, iAmount); + SetLocalInt(OBJECT_SELF, AI_SPELL_IMMUNE_LEVEL, nAmount); } } - // Animations - any valid? - if(GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS, NW_GENERIC_MASTER) || - GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS_AVIAN, NW_GENERIC_MASTER) || - GetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS, NW_GENERIC_MASTER)) - { - SetAIInteger(AI_VALID_ANIMATIONS, TRUE); - } // All things only used by my personal AI. - if(!bCustomAIFile) + // * If we are not using a custom AI file, we do these things. + if(GetCustomAIFileName() == "") { - if(GetLevelByClass(CLASS_TYPE_COMMONER) && GetHitDice(OBJECT_SELF) < i10) + // If we are a commoner of any sort, and under 10 hit dice, we are + // panicy - IE: We set to -1 morale, which triggers the "commoner" fleeing + if(GetLevelByClass(CLASS_TYPE_COMMONER) && GetHitDice(OBJECT_SELF) < 10) { - SetAIInteger(AI_MORALE, iM1); + SetAIInteger(AI_MORALE, -1); } + // If we are not set already to fearless, we might be set to fearless if(!GetSpawnInCondition(AI_FLAG_FLEEING_FEARLESS, AI_TARGETING_FLEE_MASTER)) { AI_SetMaybeFearless(); @@ -542,29 +564,38 @@ void AI_SetUpEndOfSpawn() // Set if we are a beholder or mindflayer switch(GetAppearanceType(OBJECT_SELF)) { - case 401: //beholder - case 402: //beholder - case 403: //beholder - case 472: // Hive mother - SetBeholderAI(); + // Sets we are a Beholder and use Ray attacks, and Animagic Ray. + case APPEARANCE_TYPE_BEHOLDER: // beholder, 401 + case APPEARANCE_TYPE_BEHOLDER_EYEBALL: // beholder, 402 + case APPEARANCE_TYPE_BEHOLDER_MAGE: // beholder, 403 + case APPEARANCE_TYPE_BEHOLDER_MOTHER: // Hive mother, 472 + { + // 1 = beholder + SetAIInteger(AI_SPECIAL_AI, AI_SPECIAL_AI_BEHOLDER); + } break; - case 413: //Mindflayer - case 414: // Mindflayer2 - case 415: // Mindflayer_Alhoon - SetMindflayerAI(); + // Set we are a mindflayer, and uses some special AI for them, IE: + // brain sucking. + case APPEARANCE_TYPE_MINDFLAYER: // Mindflayer, 413 + case APPEARANCE_TYPE_MINDFLAYER_2: // Mindflayer2, 414 + case APPEARANCE_TYPE_MINDFLAYER_ALHOON: // Mindflayer_Alhoon, 415 + { + // 2 = mindflayer + SetAIInteger(AI_SPECIAL_AI, AI_SPECIAL_AI_MINDFLAYER); + } break; } - // This NEEDS to be called - to set up categories of spells the creature - // will use - AI_SetUpSpells(); - // Sets up thier selection of skills, to integers, if they would ever use them. - // NOTE: it also triggers "hide" if they have enough skill and not stopped. + + // This will turn OFF skills we cannot use, so will never attempt them + // at low skill levels anywhere in the AI. AI_SetUpSkillToUse(); - // Sets the turning level if we have FEAT_TURN_UNDEAD. + + // Sets the turning level if we have FEAT_TURN_UNDEAD. AI_SetTurningLevel(); - // This sets what weapons the creature will use. They will use the best, according to a "value" - // Giving a creature the feat Two-weapon-fighting makes them deul wield if appropriate weapons. + + // This sets what weapons the creature will use. They will use the best, according to a "value" + // Giving a creature the feat Two-weapon-fighting makes them deul wield if appropriate weapons. SetWeapons(); } @@ -582,12 +613,11 @@ void AI_SetUpEndOfSpawn() SetIsDestroyable(FALSE, TRUE, TRUE); } - // Goes through and sets up which shouts the NPC will listen to. - // - Custom AI uses this also + // - Custom AI uses this also, or should take advantage of it AI_SetListeningPatterns(); - // This activates the creatures top aura. + // This activates the creatures aura's. if(GetCommandable()) AI_AdvancedAuras(); } @@ -601,25 +631,29 @@ void AI_SetTurningLevel() // We can turn HD up to nTurnLevel (HD = GetHitDice + GetTurnREsistsnceHD of undead) int nTurnLevel = GetLevelByClass(CLASS_TYPE_CLERIC); // Paladins turn at -2 the level of clerics - if(GetLevelByClass(CLASS_TYPE_PALADIN) - i2 > nTurnLevel) + if(GetLevelByClass(CLASS_TYPE_PALADIN) - 2 > nTurnLevel) { - nTurnLevel = GetLevelByClass(CLASS_TYPE_PALADIN) - i2; + nTurnLevel = GetLevelByClass(CLASS_TYPE_PALADIN) - 2; } // Blackguard gets to turn at HITDICE -2 level, not character level, // as it says in NW_S2_TURNDEAD. - if(GetLevelByClass(CLASS_TYPE_BLACKGUARD) > i0 && (GetHitDice(OBJECT_SELF) - i2 > nTurnLevel)) + if(GetLevelByClass(CLASS_TYPE_BLACKGUARD) > 0 && + (GetHitDice(OBJECT_SELF) - 2 > nTurnLevel)) { - nTurnLevel = GetHitDice(OBJECT_SELF) - i2; + nTurnLevel = GetHitDice(OBJECT_SELF) - 2; } // BTW, the number of undead turned is at least nTurnLevel, so we // can always turn one :-D SetAIInteger(AI_TURNING_LEVEL, nTurnLevel); - // Note: Turn undead could be used for FEAT_DIVINE_MIGHT and FEAT_DIVINE_SHIELD + // Note: Turn undead could be used for FEAT_DIVINE_MIGHT and + // FEAT_DIVINE_SHIELD } } - +// This should not be used! +// * called from SetUpEndOfSpawn. void AI_SetMaybeFearless() { + // Cirtain races are immune to fear switch(GetRacialType(OBJECT_SELF)) { case RACIAL_TYPE_CONSTRUCT: @@ -632,6 +666,7 @@ void AI_SetMaybeFearless() } break; } + // If we are immune to fear anyway, we don't care if(GetHasFeat(FEAT_AURA_OF_COURAGE) || GetHasFeat(FEAT_RESIST_NATURES_LURE) || GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_FEAR)) @@ -646,65 +681,74 @@ void AI_ActivateAura(int nAuraNumber) // Just ActionCast - cheat cast, as then we can use it unlmimted times, as books say. if(GetHasSpell(nAuraNumber)) { - ActionCastSpellAtObject(nAuraNumber, OBJECT_SELF, METAMAGIC_NONE, TRUE, i20, PROJECTILE_PATH_TYPE_DEFAULT, TRUE); + ActionCastSpellAtObject(nAuraNumber, OBJECT_SELF, METAMAGIC_NONE, TRUE, 20, PROJECTILE_PATH_TYPE_DEFAULT, TRUE); } } - +// This will activate one aura, very quickly. +// If we have more than one...oh well. void AI_AdvancedAuras() { - if(GetSpawnInCondition(AI_VALID_TALENT_PERSISTENT_AREA_OF_EFFECT, AI_VALID_SPELLS)) - { - // NOTE: - // - All cheat cast. As DMG, they should be always on OR free action to reapply. - ClearAllActions(); - AI_ActivateAura(SPELLABILITY_DRAGON_FEAR); - AI_ActivateAura(SPELLABILITY_AURA_UNEARTHLY_VISAGE); - AI_ActivateAura(SPELLABILITY_AURA_BLINDING); - AI_ActivateAura(SPELLABILITY_AURA_OF_COURAGE); - AI_ActivateAura(SPELLABILITY_AURA_PROTECTION); - AI_ActivateAura(SPELLABILITY_AURA_STUN); - AI_ActivateAura(SPELLABILITY_AURA_FIRE); - AI_ActivateAura(SPELLABILITY_AURA_COLD); - AI_ActivateAura(SPELLABILITY_AURA_ELECTRICITY); - AI_ActivateAura(SPELLABILITY_AURA_UNNATURAL); - AI_ActivateAura(SPELLABILITY_AURA_FEAR); - AI_ActivateAura(SPELLABILITY_AURA_UNNATURAL); - AI_ActivateAura(SPELLABILITY_AURA_MENACE); - AI_ActivateAura(SPELLABILITY_TYRANT_FOG_MIST); - AI_ActivateAura(AI_SPELLABILITY_AURA_OF_HELLFIRE); - } + // Do aura's + + // NOTE: + // - All cheat cast. As DMG, they should be always on OR free action to reapply. + ClearAllActions(); + AI_ActivateAura(SPELLABILITY_DRAGON_FEAR); + AI_ActivateAura(SPELLABILITY_AURA_UNEARTHLY_VISAGE); + AI_ActivateAura(SPELLABILITY_AURA_BLINDING); + AI_ActivateAura(SPELLABILITY_AURA_OF_COURAGE); + AI_ActivateAura(SPELLABILITY_AURA_PROTECTION); + AI_ActivateAura(SPELLABILITY_AURA_STUN); + AI_ActivateAura(SPELLABILITY_AURA_FIRE); + AI_ActivateAura(SPELLABILITY_AURA_COLD); + AI_ActivateAura(SPELLABILITY_AURA_ELECTRICITY); + AI_ActivateAura(SPELLABILITY_AURA_UNNATURAL); + AI_ActivateAura(SPELLABILITY_AURA_FEAR); + AI_ActivateAura(SPELLABILITY_AURA_UNNATURAL); + AI_ActivateAura(SPELLABILITY_AURA_MENACE); + AI_ActivateAura(SPELLABILITY_TYRANT_FOG_MIST); + AI_ActivateAura(AI_SPELLABILITY_AURA_OF_HELLFIRE); + AI_ActivateAura(SPELLABILITY_AURA_HORRIFICAPPEARANCE); } // Sets up thier selection of skills, to integers, if they would ever use them. // NOTE: it also triggers "hide" if they have enough skill and not stopped. void AI_SetUpSkillToUse() { - int iHitDice = GetHitDice(OBJECT_SELF); + // Get our hitdice + int nHitDice = GetHitDice(OBJECT_SELF); + int nRank; // Hiding. We turn off if we have no skill or under 1 skill in it + // * Note: For the AI to decide "oh, we should hide", it requires a minimum + // of 7 points in hide, and Rank - 4 must be >= our HD too. Can be forced. if(!GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_HIDING, AI_OTHER_COMBAT_MASTER)) { if(!GetHasSkill(SKILL_HIDE) || - GetSkillRank(SKILL_HIDE) <= i1) + GetSkillRank(SKILL_HIDE) < 1) { SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_HIDING, AI_OTHER_COMBAT_MASTER); DeleteSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_HIDING, AI_OTHER_COMBAT_MASTER); } } - // Pickpocketing...we only turn it OFF here if low skill (or none) Needs 1/4 HD. + // Pickpocketing...we only turn it OFF here if low skill + // (or none) Needs 1/2 HD or 10 minimum - 10 is probably needed for the DC35 + // check for this skill at all. if(!GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_PICKPOCKETING, AI_OTHER_COMBAT_MASTER)) { + nRank = GetSkillRank(SKILL_PICK_POCKET); if(!GetHasSkill(SKILL_PICK_POCKET) || - GetSkillRank(SKILL_PICK_POCKET) < (iHitDice/i4)) + nRank < nHitDice/2 || nRank < 10) { SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_PICKPOCKETING, AI_OTHER_COMBAT_MASTER); DeleteSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_PICKPOCKETING, AI_OTHER_COMBAT_MASTER); } } - // Taunting. Again, only off if low skill. Needs half of HD + // Taunting. Again, only off if low skill. Needs half of HD, or 3 minimum if(!GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_TAUNTING, AI_OTHER_COMBAT_MASTER)) { + nRank = GetSkillRank(SKILL_TAUNT); if(!GetHasSkill(SKILL_TAUNT) || - GetSkillRank(SKILL_TAUNT) < (iHitDice/i2)) + nRank < nHitDice/2 || nRank < 3) { SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_TAUNTING, AI_OTHER_COMBAT_MASTER); DeleteSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_TAUNTING, AI_OTHER_COMBAT_MASTER); @@ -749,379 +793,22 @@ void AI_SetUpSkillToUse() } } -// This is an attempt to speed up some things. -// We use talents to set general valid categories. -// Levels are also accounted for, checking the spell given and using a switch -// statement to get the level. -void AI_SetUpSpells() -{ - /*************************************************************************** - We use talents, and Get2daString to check levels, and so on... - - We set: - - If the talent is a valid one at all - - If we know it (GetHasSpell) we check the level of the spell. Set if highest. - - We set the actual talent number as a spell. - - // These must match the list in nwscreaturestats.cpp - int TALENT_CATEGORY_HARMFUL_AREAEFFECT_DISCRIMINANT = 1; - int TALENT_CATEGORY_HARMFUL_RANGED = 2; - int TALENT_CATEGORY_HARMFUL_TOUCH = 3; - int TALENT_CATEGORY_BENEFICIAL_HEALING_AREAEFFECT = 4; - int TALENT_CATEGORY_BENEFICIAL_HEALING_TOUCH = 5; - int TALENT_CATEGORY_BENEFICIAL_CONDITIONAL_AREAEFFECT = 6; - int TALENT_CATEGORY_BENEFICIAL_CONDITIONAL_SINGLE = 7; - int TALENT_CATEGORY_BENEFICIAL_ENHANCEMENT_AREAEFFECT = 8; - int TALENT_CATEGORY_BENEFICIAL_ENHANCEMENT_SINGLE = 9; - int TALENT_CATEGORY_BENEFICIAL_ENHANCEMENT_SELF = 10; - int TALENT_CATEGORY_HARMFUL_AREAEFFECT_INDISCRIMINANT = 11; - int TALENT_CATEGORY_BENEFICIAL_PROTECTION_SELF = 12; - int TALENT_CATEGORY_BENEFICIAL_PROTECTION_SINGLE = 13; - int TALENT_CATEGORY_BENEFICIAL_PROTECTION_AREAEFFECT = 14; - int TALENT_CATEGORY_BENEFICIAL_OBTAIN_ALLIES = 15; - int TALENT_CATEGORY_PERSISTENT_AREA_OF_EFFECT = 16; - int TALENT_CATEGORY_BENEFICIAL_HEALING_POTION = 17; - int TALENT_CATEGORY_BENEFICIAL_CONDITIONAL_POTION = 18; - int TALENT_CATEGORY_DRAGONS_BREATH = 19; - int TALENT_CATEGORY_BENEFICIAL_PROTECTION_POTION = 20; - int TALENT_CATEGORY_BENEFICIAL_ENHANCEMENT_POTION = 21; - int TALENT_CATEGORY_HARMFUL_MELEE = 22; - ***************************************************************************/ - talent tCheck; - // This is set to TRUE if any are valid. :-D - int SpellAnySpell; - - - /** TALENT_CATEGORY_HARMFUL_AREAEFFECT_DISCRIMINANT = 1; ***************** - These are *generally* spells which are Harmful, affect many targets in an - area, and don't hit allies. Spells such as Wierd (An illusion fear spell, so - allies would know it wasn't real, but enemies wouldn't) and so on. - ***************************************************************************/ - - tCheck = GetCreatureTalentBest(TALENT_CATEGORY_HARMFUL_AREAEFFECT_DISCRIMINANT, MAXCR); - // Valid? - if(GetIsTalentValid(tCheck)) - { - SpellAnySpell = TRUE; - // Then set we have it - SetSpawnInCondition(AI_VALID_TALENT_HARMFUL_AREAEFFECT_DISCRIMINANT, AI_VALID_SPELLS); - } - /** TALENT_CATEGORY_HARMFUL_RANGED = 2; ***************** - These are classed as single target, short or longer ranged spells. Anything - that affects one target, and isn't a touch spell, is this category. Examples - like Acid Arrow or Finger of Death. - ***************************************************************************/ - - tCheck = GetCreatureTalentBest(TALENT_CATEGORY_HARMFUL_RANGED, MAXCR); - // Valid? - if(GetIsTalentValid(tCheck)) - { - SpellAnySpell = TRUE; - // Then set we have it - SetSpawnInCondition(AI_VALID_TALENT_HARMFUL_RANGED, AI_VALID_SPELLS); - } - /** TALENT_CATEGORY_HARMFUL_TOUCH = 3; ***************** - A limited selection. All touch spells, like Harm. Not much to add but they - only affect one target. Note: Inflict range are also in here (but remember - that GetHasSpell returns TRUE if they can spontaeously cast it as well!) - ***************************************************************************/ - - tCheck = GetCreatureTalentBest(TALENT_CATEGORY_HARMFUL_TOUCH, MAXCR); - // Valid? - if(GetIsTalentValid(tCheck)) - { - SpellAnySpell = TRUE; - // Then set we have it - SetSpawnInCondition(AI_VALID_TALENT_HARMFUL_TOUCH, AI_VALID_SPELLS); - } - /** TALENT_CATEGORY_BENEFICIAL_HEALING_AREAEFFECT = 4; ***************** - Healing area effects. Basically, only Mass Heal and Healing Circle :0P - - ***************************************************************************/ - - tCheck = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_HEALING_AREAEFFECT, MAXCR); - if(GetIsTalentValid(tCheck)) - { - SpellAnySpell = TRUE; - // Then set we have it - SetSpawnInCondition(AI_VALID_TALENT_BENEFICIAL_HEALING_AREAEFFECT, AI_VALID_SPELLS); - } - - /** TALENT_CATEGORY_BENEFICIAL_HEALING_TOUCH = 5; ***************** - These are all the healing spells that touch - Cure X wounds and heal really. - Also, feat Wholeness of Body and Lay on Hands as well. - ***************************************************************************/ - - tCheck = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_HEALING_TOUCH, MAXCR); - // Valid? - if(GetIsTalentValid(tCheck)) - { - SpellAnySpell = TRUE; - // Then set we have it - SetSpawnInCondition(AI_VALID_TALENT_BENEFICIAL_HEALING_TOUCH, AI_VALID_SPELLS); - } - - /** TALENT_CATEGORY_BENEFICIAL_CONDITIONAL_AREAEFFECT = 6; ***************** - These are spells which help people in an area to rid effects, normally. IE - normally, a condition must be met to cast it, like them being stunned. - ***************************************************************************/ - - tCheck = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_CONDITIONAL_AREAEFFECT, MAXCR); - // Valid? - if(GetIsTalentValid(tCheck)) - { - SpellAnySpell = TRUE; - // Then set we have it - SetSpawnInCondition(AI_VALID_TALENT_BENEFICIAL_CONDITIONAL_AREAEFFECT, AI_VALID_SPELLS); - } - - /** TALENT_CATEGORY_BENEFICIAL_CONDITIONAL_SINGLE = 7; ***************** - This is the same as the AOE version, but things like Clarity, single target - ones. - ***************************************************************************/ - - tCheck = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_CONDITIONAL_SINGLE, MAXCR); - // Valid? - if(GetIsTalentValid(tCheck)) - { - SpellAnySpell = TRUE; - // Then set we have it - SetSpawnInCondition(AI_VALID_TALENT_BENEFICIAL_CONDITIONAL_SINGLE, AI_VALID_SPELLS); - } - - /** TALENT_CATEGORY_BENEFICIAL_ENHANCEMENT_AREAEFFECT = 8; ***************** - Enhancing stats, or self or others. Friendly, and usually stat-changing. They - contain all ones that, basically, don't protect and stop damage, but help - defeat enemies. In the AOE ones are things like Invisiblity Sphere. - ***************************************************************************/ - - tCheck = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_ENHANCEMENT_AREAEFFECT, MAXCR); - // Valid? - if(GetIsTalentValid(tCheck)) - { - SpellAnySpell = TRUE; - // Then set we have it - SetSpawnInCondition(AI_VALID_TALENT_BENEFICIAL_ENHANCEMENT_AREAEFFECT, AI_VALID_SPELLS); - } - - /** TALENT_CATEGORY_BENEFICIAL_ENHANCEMENT_SINGLE = 9; ***************** - Enchancing, these are the more single ones, like Bulls Strength. See above as well. - ***************************************************************************/ - - tCheck = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_ENHANCEMENT_SINGLE, MAXCR); - // Valid? - if(GetIsTalentValid(tCheck)) - { - SpellAnySpell = TRUE; - // Then set we have it - SetSpawnInCondition(AI_VALID_TALENT_BENEFICIAL_ENHANCEMENT_SINGLE, AI_VALID_SPELLS); - } - - /** TALENT_CATEGORY_BENEFICIAL_ENHANCEMENT_SELF = 10; **************** - Self-encancing spells, that can't be cast on allies, like Divine Power :-) - ***************************************************************************/ - - tCheck = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_ENHANCEMENT_SELF, MAXCR); - // Valid? - if(GetIsTalentValid(tCheck)) - { - SpellAnySpell = TRUE; - // Then set we have it - SetSpawnInCondition(AI_VALID_TALENT_BENEFICIAL_ENHANCEMENT_SELF, AI_VALID_SPELLS); - } - - /** TALENT_CATEGORY_HARMFUL_AREAEFFECT_INDISCRIMINANT = 11; **************** - This is the AOE spells which never discriminate between allies, and enemies, - such as the well known spell Fireball. - ***************************************************************************/ - - tCheck = GetCreatureTalentBest(TALENT_CATEGORY_HARMFUL_AREAEFFECT_INDISCRIMINANT, MAXCR); - // Valid? - if(GetIsTalentValid(tCheck)) - { - SpellAnySpell = TRUE; - // Then set we have it - SetSpawnInCondition(AI_VALID_TALENT_HARMFUL_AREAEFFECT_INDISCRIMINANT, AI_VALID_SPELLS); - } - - /** TALENT_CATEGORY_BENEFICIAL_PROTECTION_SELF = 12; **************** - Protection spells are usually a Mage's only way to stop instant death. Self - only spells include the likes of Premonition :-) - ***************************************************************************/ - - tCheck = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_PROTECTION_SELF, MAXCR); - // Valid? - if(GetIsTalentValid(tCheck)) - { - SpellAnySpell = TRUE; - // Then set we have it - SetSpawnInCondition(AI_VALID_TALENT_BENEFICIAL_PROTECTION_SELF, AI_VALID_SPELLS); - } - - /** TALENT_CATEGORY_BENEFICIAL_PROTECTION_AREAEFFECT = 14; **************** - Protection spells are usually a Mage's only way to stop instant death. - Area effect ones are the likes of Protection From Spells. Limited ones here. - ***************************************************************************/ - - tCheck = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_PROTECTION_AREAEFFECT, MAXCR); - // Valid? - if(GetIsTalentValid(tCheck)) - { - SpellAnySpell = TRUE; - // Then set we have it - SetSpawnInCondition(AI_VALID_TALENT_BENEFICIAL_PROTECTION_AREAEFFECT, AI_VALID_SPELLS); - } - - /** TALENT_CATEGORY_BENEFICIAL_OBTAIN_ALLIES = 15; **************** - Allies, or obtaining them, is anything they can summon. Basically, all - Summon Monster 1-9, Innate ones like Summon Tanarri and ones like Gate. - ***************************************************************************/ - - tCheck = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_OBTAIN_ALLIES, MAXCR); - // Valid? - if(GetIsTalentValid(tCheck)) - { - SpellAnySpell = TRUE; - // Then set we have it - SetSpawnInCondition(AI_VALID_TALENT_BENEFICIAL_OBTAIN_ALLIES, AI_VALID_SPELLS); - } - - /** TALENT_CATEGORY_PERSISTENT_AREA_OF_EFFECT = 16; **************** - These are NOT AOE spells like acid fog, but rather the Aura's that a monster - can use. Also, oddly, Rage's, Monk's Wholeness of Body and so on are here... - ***************************************************************************/ - - tCheck = GetCreatureTalentBest(TALENT_CATEGORY_PERSISTENT_AREA_OF_EFFECT, MAXCR); - // Valid? - if(GetIsTalentValid(tCheck)) - { - SpellAnySpell = TRUE; - // Then set we have it - SetSpawnInCondition(AI_VALID_TALENT_PERSISTENT_AREA_OF_EFFECT, AI_VALID_SPELLS); - } - - /** TALENT_CATEGORY_DRAGONS_BREATH = 19; **************** - Dragon Breaths. These are all the breaths avalible to Dragons. :-D Nothing else. - - All counted as level 9 innate caster level. Monster ability only :0) - - Contains (By level, innate): - 9. Dragon Breath Acid, Cold, Fear, Fire, Gas, Lightning, Paralyze, Sleep, Slow, Weaken. - ***************************************************************************/ - - tCheck = GetCreatureTalentBest(TALENT_CATEGORY_DRAGONS_BREATH, MAXCR); - // Valid? - if(GetIsTalentValid(tCheck)) - { - // Then set we have it - SetSpawnInCondition(AI_VALID_TALENT_DRAGONS_BREATH, AI_VALID_SPELLS); - } - - /** TALENT_CATEGORY_HARMFUL_MELEE = 22; **************** - We might as well check if we have any valid feats :-P - - Contains: - Called Shot, Disarm, Imp. Power Attack, Knockdown, Power Attack, Rapid Shot, - Sap, Stunning Fist, Flurry of blows, Quivering Palm, Smite Evil, - Expertise (and Imp), Smite Good - Note: - Whirlwind attack (Improved), Dirty Fighting. - ***************************************************************************/ - tCheck = GetCreatureTalentBest(TALENT_CATEGORY_HARMFUL_MELEE, MAXCR); - // Valid? - if(GetIsTalentValid(tCheck) || - GetHasFeat(FEAT_IMPROVED_WHIRLWIND) || - GetHasFeat(FEAT_WHIRLWIND_ATTACK) || - GetHasFeat(FEAT_DIRTY_FIGHTING) || - GetHasFeat(FEAT_KI_DAMAGE)) - { - // Then set we have it. If we don't have any, we never check Knockdown ETC. - SetSpawnInCondition(AI_VALID_TALENT_HARMFUL_MELEE, AI_VALID_SPELLS); - } - - if(SpellAnySpell == TRUE) - { - SetSpawnInCondition(AI_VALID_ANY_SPELL, AI_VALID_SPELLS); - } - // All spells in no category. - if( -// GetHasSpell(SPELL_CLAIRAUDIENCE_AND_CLAIRVOYANCE) || - GetHasSpell(SPELL_DARKNESS) || -// GetHasSpell(71) || // Greater shadow conjuration -// GetHasSpell(SPELL_IDENTIFY) || -// GetHasSpell(SPELL_KNOCK) || - GetHasSpell(SPELL_LIGHT) || - GetHasSpell(SPELL_POLYMORPH_SELF) || -// GetHasSpell(158) || // Shades -// GetHasSpell(159) || // Shadow conjuration - GetHasSpell(SPELL_SHAPECHANGE) || - GetHasSpell(321) || // Protection... - GetHasSpell(322) || // Magic circle... - GetHasSpell(323) || // Aura... -// GetHasSpell(SPELL_LEGEND_LORE) || -// GetHasSpell(SPELL_FIND_TRAPS) || - GetHasSpell(SPELL_CONTINUAL_FLAME) || -// GetHasSpell(SPELL_ONE_WITH_THE_LAND) || -// GetHasSpell(SPELL_CAMOFLAGE) || - GetHasSpell(SPELL_BLOOD_FRENZY) || -// GetHasSpell(SPELL_AMPLIFY) || - GetHasSpell(SPELL_ETHEREALNESS) || - GetHasSpell(SPELL_DIVINE_SHIELD) || - GetHasSpell(SPELL_DIVINE_MIGHT) || - // Added in again 18th nov - GetHasSpell(SPELL_INFLICT_SERIOUS_WOUNDS) || - GetHasSpell(SPELL_INFLICT_MODERATE_WOUNDS) || - GetHasSpell(SPELL_INFLICT_MINOR_WOUNDS) || - GetHasSpell(SPELL_INFLICT_LIGHT_WOUNDS) || - // Feats that will be cast in the spell list. - // MOST are under talents anyway, these are ones which are not - GetHasFeat(FEAT_PRESTIGE_DARKNESS)) - { - SetSpawnInCondition(AI_VALID_OTHER_SPELL, AI_VALID_SPELLS); - SetSpawnInCondition(AI_VALID_ANY_SPELL, AI_VALID_SPELLS); - } - // SPELL_GREATER_RESTORATION - Ability Decrease, AC decrease, Attack decrease, - // Damage Decrease, Damage Immunity Decrease, Saving Throw Decrease, Spell - // resistance Decrease, Skill decrease, Blindness, Deaf, Curse, Disease, Poison, - // Charmed, Dominated, Dazed, Confused, Frightened, Negative level, Paralyze, - // Slow, Stunned. - // SPELL_FREEDOM - Paralyze, Entangle, Slow, Movement speed decrease. (+Immunity!) - // SPELL_RESTORATION - Ability Decrease, AC decrease, Attack Decrease, - // Damage Decrease, Damage Immunity Decrease, Saving Throw Decrease, - // Spell Resistance Decrease, Skill Decrease, Blindess, Deaf, Paralyze, Negative level - // SPELL_REMOVE_BLINDNESS_AND_DEAFNESS - Blindess, Deaf. - // SPELL_NEUTRALIZE_POISON - Poison - // SPELL_REMOVE_DISEASE - Disease - // SPELL_REMOVE_CURSE - Curse - // SPELL_LESSER_RESTORATION - Ability Decrease, AC decrease, Attack Decrease, - // Cure condition spells! :-) - if(GetHasSpell(SPELL_GREATER_RESTORATION) || GetHasSpell(SPELL_FREEDOM_OF_MOVEMENT) || - GetHasSpell(SPELL_RESTORATION) || GetHasSpell(SPELL_REMOVE_BLINDNESS_AND_DEAFNESS) || - GetHasSpell(SPELL_NEUTRALIZE_POISON) || GetHasSpell(SPELL_REMOVE_DISEASE) || - GetHasSpell(SPELL_REMOVE_CURSE) || GetHasSpell(SPELL_LESSER_RESTORATION) || - GetHasSpell(SPELL_STONE_TO_FLESH)) - { - SetSpawnInCondition(AI_VALID_CURE_CONDITION_SPELLS, AI_VALID_SPELLS); - } -} - // This will make the visual effect passed play INSTANTLY at the creatures location. -// * iVFX - The visual effect constant number -void AI_SpawnInInstantVisual(int iVFX) +// * nVFX - The visual effect constant number +void AI_SpawnInInstantVisual(int nVFX) { // Beta 3 change: Made to at location. ApplyEffectAtLocation(DURATION_TYPE_INSTANT, - EffectVisualEffect(iVFX), + EffectVisualEffect(nVFX), GetLocation(OBJECT_SELF)); } // This will make the visual effect passed play PERMAMENTLY. -// * If a VFX is -1, it is ignored. -// * iVFX1-4 - The visual effect constant number +// * nVFX - The visual effect constant number // NOTE: They will be made to be SUPERNATUAL, so are not dispelled! -void AI_SpawnInPermamentVisual(int iVFX) +void AI_SpawnInPermamentVisual(int nVFX) { ApplyEffectToObject(DURATION_TYPE_INSTANT, - SupernaturalEffect(EffectVisualEffect(iVFX)), + SupernaturalEffect(EffectVisualEffect(nVFX)), OBJECT_SELF); } // This will set the MAXIMUM and MINIMUM targets to pass this stage (under sName) @@ -1129,52 +816,39 @@ void AI_SpawnInPermamentVisual(int iVFX) // - If we set it to min of 5, max of 10, for AC, if we cancled 5 targets on having // AC higher then wanted, we will take the highest 5 minimum. // If there are over 10, we take a max of 10 to choose from. -// * iType - must be TARGET_HIGHER or TARGET_LOWER. Defaults to the lowest, so it +// * nType - must be TARGET_HIGHER or TARGET_LOWER. Defaults to the lowest, so it // targets the lowest value for sName. -void AI_SetAITargetingValues(string sName, int iType, int iMinimum, int iMaximum) +void AI_SetAITargetingValues(string sName, int nType, int nMinimum, int nMaximum) { // Error checking - if((iType == TARGET_HIGHER || iType == TARGET_LOWER) && - iMinimum >= i1 && iMaximum >= i1 && iMaximum >= iMinimum) + if((nType == TARGET_HIGHER || nType == TARGET_LOWER) && + nMinimum >= 1 && nMaximum >= 1 && nMaximum >= nMinimum) { // Set the type to sName. // - It is TARGET_HIGHER (1) or TARGET_LOWER (0). - SetAIInteger(sName, iType); + SetAIInteger(sName, nType); // Minimum amount of targets for this? - SetAIInteger(sName + MINIMUM, iMinimum); + SetAIInteger(sName + MINIMUM, nMinimum); // Maximum targets for this? - SetAIInteger(sName + MAXIMUM, iMaximum); + SetAIInteger(sName + MAXIMUM, nMaximum); } } -// Sets we are a Beholder and use Ray attacks, and Animagic Ray. -void SetBeholderAI() -{ - // 1 = beholder - SetAIInteger(AI_SPECIAL_AI, i1); -} -// Set we are a mindflayer, and uses some special AI for them. -void SetMindflayerAI() -{ - // 2 = mindflayer - SetAIInteger(AI_SPECIAL_AI, i2); -} - // This will set a spell trigger up. Under cirtain conditions, spells are released // and cast on the caster. -// Once fired, a spell trigger is only reset by resting. +// Once fired, a spell trigger is only reset by resting. Only 1 of each max is fired at once! // * sType - is specifically: // SPELLTRIGGER_DAMAGED_AT_PERCENT - When damaged, the trigger fires. Use iValue for the %. One at a time is fired. // SPELLTRIGGER_IMMOBILE - Fired when held/paralyzed/sleeping ETC. One at a time is fired. // SPELLTRIGGER_NOT_GOT_FIRST_SPELL - Makes sure !GetHasSpellEffect(iSpell1) already, -// then fires. Checks all in this category each round. -// SPELLTRIGGER_START_OF_COMBAT - All these are all fired at the start of combat. -// * iNumber - can be 1-9, in sequential order of when you want them to fire. -// * iValue - is only required with DAMAGED_AT_PERCENT. Only the first one set is used. -// * iSpellX - Cannot be 0. It should only really be defensive spells. -void SetSpellTrigger(string sType, int iValue, int iNumber, int iSpell1, int iSpell2 = 0, int iSpell3 = 0, int iSpell4 = 0, int iSpell5 = 0, int iSpell6 = 0, int iSpell7 = 0, int iSpell8 = 0, int iSpell9 = 0) +// then fires. Checks all in this category each round (first one fires!) +// SPELLTRIGGER_START_OF_COMBAT - Triggered always, at the start of DetermineCombatRound. +// * nNumber - can be 1-9, in sequential order of when you want them to fire. +// * nValue - is only required with DAMAGED_AT_PERCENT. +// * nSpellX - Cannot be 0. It should only really be defensive spells. +void SetSpellTrigger(string sType, int nValue, int nNumber, int nSpell1, int nSpell2 = 0, int nSpell3 = 0, int nSpell4 = 0, int nSpell5 = 0, int nSpell6 = 0, int nSpell7 = 0, int nSpell8 = 0, int nSpell9 = 0) { // Either get our spell trigger (creature) or create one object oTrigger = GetAIObject(AI_SPELL_TRIGGER_CREATURE); @@ -1188,49 +862,49 @@ void SetSpellTrigger(string sType, int iValue, int iNumber, int iSpell1, int iSp // Local for us to get our spell trigger (should be our henchmen) SetAIObject(AI_SPELL_TRIGGER_CREATURE, oTrigger); } - int iSize = i1; - string sTotalID = sType + IntToString(iNumber); + int nSize = 1; + string sTotalID = sType + IntToString(nNumber); - SetLocalInt(oTrigger, sTotalID + "1", iSpell1); - if(iSpell2 != FALSE) - { iSize = 2; - SetLocalInt(oTrigger, sTotalID + "2", iSpell2); } - if(iSpell3 != FALSE) - { iSize = 3; - SetLocalInt(oTrigger, sTotalID + "3", iSpell3); } - if(iSpell4 != FALSE) - { iSize = 4; - SetLocalInt(oTrigger, sTotalID + "4", iSpell4); } - if(iSpell5 != FALSE) - { iSize = 5; - SetLocalInt(oTrigger, sTotalID + "5", iSpell5); } - if(iSpell6 != FALSE) - { iSize = 6; - SetLocalInt(oTrigger, sTotalID + "6", iSpell6); } - if(iSpell7 != FALSE) - { iSize = 7; - SetLocalInt(oTrigger, sTotalID + "7", iSpell7); } - if(iSpell8 != FALSE) - { iSize = 8; - SetLocalInt(oTrigger, sTotalID + "8", iSpell8); } - if(iSpell9 != FALSE) - { iSize = 9; - SetLocalInt(oTrigger, sTotalID + "9", iSpell9); } + SetLocalInt(oTrigger, sTotalID + "1", nSpell1); + if(nSpell2 != FALSE) + { nSize = 2; + SetLocalInt(oTrigger, sTotalID + "2", nSpell2); } + if(nSpell3 != FALSE) + { nSize = 3; + SetLocalInt(oTrigger, sTotalID + "3", nSpell3); } + if(nSpell4 != FALSE) + { nSize = 4; + SetLocalInt(oTrigger, sTotalID + "4", nSpell4); } + if(nSpell5 != FALSE) + { nSize = 5; + SetLocalInt(oTrigger, sTotalID + "5", nSpell5); } + if(nSpell6 != FALSE) + { nSize = 6; + SetLocalInt(oTrigger, sTotalID + "6", nSpell6); } + if(nSpell7 != FALSE) + { nSize = 7; + SetLocalInt(oTrigger, sTotalID + "7", nSpell7); } + if(nSpell8 != FALSE) + { nSize = 8; + SetLocalInt(oTrigger, sTotalID + "8", nSpell8); } + if(nSpell9 != FALSE) + { nSize = 9; + SetLocalInt(oTrigger, sTotalID + "9", nSpell9); } // Set final sizes ETC. - SetLocalInt(oTrigger, MAXINT_ + sTotalID, iSize); + SetLocalInt(oTrigger, MAXINT_ + sTotalID, nSize); SetLocalInt(oTrigger, sTotalID + USED, FALSE); // Check value - if(iValue > GetLocalInt(oTrigger, VALUE + sType)) + if(nValue > GetLocalInt(oTrigger, VALUE + sType)) { - SetLocalInt(oTrigger, VALUE + sType, iValue); + SetLocalInt(oTrigger, VALUE + sType, nValue); } // Set how many spell triggers we have too - if(iNumber > GetLocalInt(oTrigger, MAXIMUM + sType)) + if(nNumber > GetLocalInt(oTrigger, MAXIMUM + sType)) { - SetLocalInt(oTrigger, MAXIMUM + sType, iNumber); + SetLocalInt(oTrigger, MAXIMUM + sType, nNumber); } } // Debug: To compile this script, uncomment all of the below. diff --git a/_module/nss/jcmarthekk.nss b/_module/nss/jcmarthekk.nss index b4b738dc..8a5d0a37 100644 --- a/_module/nss/jcmarthekk.nss +++ b/_module/nss/jcmarthekk.nss @@ -9,7 +9,7 @@ int StartingConditional() object oPC = GetPCSpeaker(); int nInt; -nInt=GetLocalInt(oPC, "NW_JOURNAL_ENTRYmarthek); +nInt = GetLocalInt(oPC, "NW_JOURNAL_ENTRYmarthek"); if (nInt >= 1) return TRUE; diff --git a/_module/nss/menaktombtel1.nss b/_module/nss/menaktombtel1.nss index c9fbd361..cc4c3b2a 100644 --- a/_module/nss/menaktombtel1.nss +++ b/_module/nss/menaktombtel1.nss @@ -7,14 +7,13 @@ http://nwvault.ign.com/View.php?view=Other.Detail&id=4683&id=625 */ //Put this on action taken in the conversation editor void main() { +object oPC = GetPCSpeaker(); object oItem; oItem = GetItemPossessedBy(oPC, "ScrollofEtherealJaunt"); if (GetIsObjectValid(oItem)) DestroyObject(oItem); -object oPC = GetPCSpeaker(); - object oTarget; location lTarget; oTarget = GetWaypointByTag("menak1"); diff --git a/_module/nss/nw_c2_default1.nss b/_module/nss/nw_c2_default1.nss index 1d82f998..e32ef925 100644 --- a/_module/nss/nw_c2_default1.nss +++ b/_module/nss/nw_c2_default1.nss @@ -1,6 +1,6 @@ -/************************ [On Heartbeat] *************************************** - Filename: nw_c2_default1 or j_ai_onheartbeat -************************* [On Heartbeat] *************************************** +/*/////////////////////// [On Heartbeat] /////////////////////////////////////// + Filename: nw_c2_default1 or J_AI_OnHeartbeat +///////////////////////// [On Heartbeat] /////////////////////////////////////// Removed stupid stuff, special behaviour, sleep. Also, note please, I removed waypoints and day/night posting from this. @@ -24,21 +24,22 @@ execute script. -Working- Best possible, fast compile. -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.3 - Added more "buffs" to fast buff. - Fixed animations (they both WORK and looping ones do loop right!) - Loot behaviour! - Randomly moving nearer a PC in 25M if set. - Removed silly day/night optional setting. Anything we can remove, is a good idea. -************************* [Workings] ******************************************* + 1.4 - Removed AI level setting. Not good to use, I mistakenly added it. +///////////////////////// [Workings] /////////////////////////////////////////// This fires off every 6 seconds (with PCs in the area, or AI_LEVEL_HIGH without) and therefore is intensive. It fires of ExecutesScript things for the different parts - saves CPU stuff if the bits are not used. -************************* [Arguments] ****************************************** +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: Basically, none. Nothing activates this script. Fires every 6 seconds. -************************* [On Heartbeat] **************************************/ +///////////////////////// [On Heartbeat] /////////////////////////////////////*/ // - This includes J_Inc_Constants #include "J_INC_HEARTBEAT" @@ -52,10 +53,8 @@ void main() // - Includes door bashing stop heartbeat if(PerformSpecialAction()) return; - // Pre-heartbeat-event - if(FireUserEvent(AI_FLAG_UDE_HEARTBEAT_PRE_EVENT, EVENT_HEARTBEAT_PRE_EVENT)) - // We may exit if it fires - if(ExitFromUDE(EVENT_HEARTBEAT_PRE_EVENT)) return; + // Pre-heartbeat-event. Returns TRUE if we interrupt this script call. + if(FirePreUserEvent(AI_FLAG_UDE_HEARTBEAT_PRE_EVENT, EVENT_HEARTBEAT_PRE_EVENT)) return; // AI status check. Is the AI on? if(GetAIOff() || GetSpawnInCondition(AI_FLAG_OTHER_LAG_IGNORE_HEARTBEAT, AI_OTHER_MASTER)) return; @@ -63,29 +62,6 @@ void main() // Define the enemy and player to use. object oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY); object oPlayer = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC); - int iTempInt; - - // AI level (re)setting - if(!GetIsInCombat() && !GetIsObjectValid(GetAttackTarget()) && - (GetIsObjectValid(oEnemy) && GetDistanceToObject(oEnemy) <= f50 || - GetIsObjectValid(oPlayer) && GetDistanceToObject(oPlayer) <= f50)) - { - // AI setting, normally higher then normal. - iTempInt = GetAIConstant(LAG_AI_LEVEL_YES_PC_OR_ENEMY_50M); - if(iTempInt > iM1 && GetAILevel() != iTempInt) - { - SetAILevel(OBJECT_SELF, iTempInt); - } - } - else - { - // AI setting, normally higher then normal. - iTempInt = GetAIConstant(LAG_AI_LEVEL_NO_PC_OR_ENEMY_50M); - if(iTempInt > iM1 && GetAILevel() != iTempInt) - { - SetAILevel(OBJECT_SELF, iTempInt); - } - } // We can skip to the end if we are in combat, or something... if(!JumpOutOfHeartBeat() && // We don't stop due to effects. @@ -95,7 +71,7 @@ void main() { // Fast buffing...if we have the spawn in condition... if(GetSpawnInCondition(AI_FLAG_COMBAT_FLAG_FAST_BUFF_ENEMY, AI_COMBAT_MASTER) && - GetIsObjectValid(oEnemy) && GetDistanceToObject(oEnemy) <= f40) + GetIsObjectValid(oEnemy) && GetDistanceToObject(oEnemy) <= 40.0) { // ...we may do an advanced buff. If we cannot see/hear oEnemy, but oEnemy // is within 40M, we cast many defensive spells instantly... @@ -116,21 +92,20 @@ void main() // We must have animations set, and not be "paused", so doing a // longer looping one // - Need a valid player. - if(GetIsObjectValid(oPlayer)) + if(GetIsObjectValid(oPlayer) && !IsInConversation(OBJECT_SELF)) { - // Do we have any animations to speak of? - // If we have a nearby PC, not in conversation, we do animations. - if(!IsInConversation(OBJECT_SELF) && - GetAIInteger(AI_VALID_ANIMATIONS)) - { - ExecuteScript(FILE_HEARTBEAT_ANIMATIONS, OBJECT_SELF); - } - // We may search for PC enemies :-) move closer to PC's - else if(GetSpawnInCondition(AI_FLAG_OTHER_SEARCH_IF_ENEMIES_NEAR, AI_OTHER_MASTER) && - !GetLocalTimer(AI_TIMER_SEARCHING) && d4() == i1) + // We may search for PC enemies, 25% chance to move closer to PC's + if(GetSpawnInCondition(AI_FLAG_OTHER_SEARCH_IF_ENEMIES_NEAR, AI_OTHER_MASTER) && + !GetLocalTimer(AI_TIMER_SEARCHING) && d4() == 1) { ExecuteScript(FILE_HEARTBEAT_WALK_TO_PC, OBJECT_SELF); } + // Else, Do we have any animations to speak of? + // If we have a nearby PC, we do animations. + else if(GetHasValidAnimations()) + { + ExecuteScript(FILE_HEARTBEAT_ANIMATIONS, OBJECT_SELF); + } } } } diff --git a/_module/nss/nw_c2_default2.nss b/_module/nss/nw_c2_default2.nss index 1112e6b2..99987231 100644 --- a/_module/nss/nw_c2_default2.nss +++ b/_module/nss/nw_c2_default2.nss @@ -1,6 +1,6 @@ -/************************ [On Percieve] **************************************** - Filename: j_ai_onpercieve or nw_c2_default2 -************************* [On Percieve] **************************************** +/*/////////////////////// [On Percieve] //////////////////////////////////////// + Filename: J_AI_OnPercieve or nw_c2_default2 +///////////////////////// [On Percieve] //////////////////////////////////////// If the target is an enemy, attack Will determine combat round on that person, is an enemy, basically. Includes shouting for a big radius - if the spawn in condition is set to this. @@ -8,37 +8,43 @@ NOTE: Debug strings in this file will be uncommented for speed by default. - It is one of the most intensive scripts as it runs so often. - Attempted to optimise as much as possible. -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.3 - We include j_inc_other_ai to initiate combat (or go into combat again) - j_inc_other_ai holds all other needed functions/integers ETC. - Turn off hide things. - Added "Only attack if attacked" - Removed special conversation things. Almost no one uses them, and the taunt system is easier. - Should now search around if they move to a dead body, and only once they get there. -************************* [Workings] ******************************************* + 1.4 - TO DO: + + 1. Perception needs checking - attacking outside perception ranges! + 2. Vanishing targets, etc. test, improve. + 3. Problems with dispelling invisibility. Maybe either do change the line to create placable, or, of course, cast at location (dispells cannot be metamagiked or whatever) Source + 4. No Effect Type Ethereal. Source +///////////////////////// [Workings] /////////////////////////////////////////// It fires: - When a creature enters it perception range (Set in creature properties) and is seen or heard. + * Tests show (and in general) it fires HEARD first, then immediantly SEEN if, + of course, they are visible. Odd really, but true. - When a creature uses invisiblity/leaves the area in the creatures perception range - When a creature appears suddenly, already in the perception range (not the other way round, normally) - When a creature moves out of the creatures perception range, and therefore becomes unseen. -************************* [Arguments] ****************************************** +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: GetLastPerceived, GetLastPerceptionSeen, GetLastPerceptionHeard, GetLastPerceptionVanished, GetLastPerceptionInaudible. -************************* [On Percieve] ***************************************/ +///////////////////////// [On Percieve] //////////////////////////////////////*/ -#include "j_inc_other_ai" +#include "J_INC_OTHER_AI" void main() { - // Percieve pre event. - if(FireUserEvent(AI_FLAG_UDE_PERCIEVE_PRE_EVENT, EVENT_PERCIEVE_PRE_EVENT)) - // We may exit if it fires - if(ExitFromUDE(EVENT_PERCIEVE_PRE_EVENT)) return; + // Pre-percieve-event. Returns TRUE if we interrupt this script call. + if(FirePreUserEvent(AI_FLAG_UDE_PERCIEVE_PRE_EVENT, EVENT_PERCIEVE_PRE_EVENT)) return; // AI status check. Is the AI on? if(GetAIOff()) return; @@ -47,8 +53,21 @@ void main() // - We declare OUTSIDE if's JUST IN CASE! object oPerceived = GetLastPerceived(); object oAttackTarget = GetAttackTarget(); + // 1.4: Very rarely is our attack target valid, so we will set it to + // what we would have melee attacked when DCR was called. + if(GetIgnoreNoFriend(oAttackTarget) || oAttackTarget == OBJECT_SELF) + { + oAttackTarget = GetAIObject(AI_LAST_MELEE_TARGET); + } int bSeen = GetLastPerceptionSeen(); int bHeard = GetLastPerceptionHeard(); + int bVanished = GetLastPerceptionVanished(); + int bInaudiable = GetLastPerceptionInaudible(); + + // Debug + DebugActionSpeak("*** PER ***: " + GetName(oPerceived) + "| SEEN: " + IntToString(bSeen) + + "| HEARD: " + IntToString(bHeard) + "| VANISHED: " + IntToString(bVanished) + + "| INAUDIABLE: " + IntToString(bInaudiable)); // Need to be valid and not ignorable. if(GetIsObjectValid(oPerceived) && @@ -58,31 +77,35 @@ void main() // First, easy enemy checks. if(GetIsEnemy(oPerceived) && !GetFactionEqual(oPerceived)) { + DebugActionSpeak("*** PER *** ENEMY"); + // Turn of hiding, a timer to activate Hiding in the main file. This is // done in each of the events, with the opposition checking seen/heard. TurnOffHiding(oPerceived); // Well, are we both inaudible and vanished? // * the GetLastPerception should only say what specific event has fired! - if(GetLastPerceptionInaudible() || GetLastPerceptionVanished()) + if(bVanished || bInaudiable) { + DebugActionSpeak("*** PER *** VANISHED OR INAUDIBLE"); // If they just became invisible because of the spell // invisiblity, or improved invisiblity...we set a local object. // - Beta: Added in ethereal as well. if(GetHasEffect(EFFECT_TYPE_INVISIBILITY, oPerceived) || - GetHasEffect(EFFECT_TYPE_ETHEREAL, oPerceived) || + GetHasEffect(EFFECT_TYPE_SANCTUARY, oPerceived) || GetStealthMode(oPerceived) == STEALTH_MODE_ACTIVATED) { // Set object, AND the location they went invisible! SetAIObject(AI_LAST_TO_GO_INVISIBLE, oPerceived); // We also set thier location for AOE dispelling - same name - SetLocalLocation(OBJECT_SELF, AI_LAST_TO_GO_INVISIBLE, GetLocation(oPerceived)); + SetAILocation(AI_LAST_TO_GO_INVISIBLE, GetLocation(oPerceived)); } // If they were our target, follow! >:-D // - Optional, on spawn option, for following through areas. if(oAttackTarget == oPerceived) { + DebugActionSpeak("*** PER *** VANISHED OR INAUDIBLE AND IS CURRENT TARGET"); // This means they have exited the area! follow! if(GetArea(oPerceived) != GetArea(OBJECT_SELF)) { @@ -94,7 +117,10 @@ void main() } // - Added check for not casting a spell. If we are, we finnish // (EG: AOE spell) and automatically carry on. - else if(GetCurrentAction() != ACTION_CASTSPELL) + // 1.4: If we are using a targetted spell, we do cancle our + // spellcasting if it is them. + else if(GetCurrentAction() != ACTION_CASTSPELL || + GetAttackTarget() == oPerceived) { ClearAllActions(); // 52: "[Perception] Enemy Vanished (Same area) Retargeting/Searching [Percieved] " + GetName(oPerceived) @@ -111,76 +137,79 @@ void main() if(bSeen && GetCurrentAction() != ACTION_CASTSPELL && (oAttackTarget == oPerceived || !GetObjectSeen(oAttackTarget))) { - AISpeakString(I_WAS_ATTACKED); // 53: "[Perception] Enemy seen, and was old enemy/cannot see current. Re-evaluating (no spell) [Percieved] " + GetName(oPerceived) DebugActionSpeakByInt(53, oPerceived); DetermineCombatRound(oPerceived); + + // Shout to allies to attack oPerceived + AISpeakString(AI_SHOUT_I_WAS_ATTACKED); } // Else We check if we are already attacking. else if(!CannotPerformCombatRound() && !GetSpawnInCondition(AI_FLAG_OTHER_ONLY_ATTACK_IF_ATTACKED, AI_OTHER_MASTER)) { - // Special shout, d1000 though! - SpeakArrayString(AI_TALK_ON_PERCIEVE_ENEMY, TRUE); + // * Don't speak when dead. 1.4 change (an obvious one to make) + if(CanSpeak()) + { + // Special shout, d1000 though! + SpeakArrayString(AI_TALK_ON_PERCIEVE_ENEMY, TRUE); + } // Stop stuff because of facing point - New enemy HideOrClear(); - // Face the person (this helps stops sneak attacks if we then - // cast something on ourselves, ETC). - SetFacingPoint(GetPosition(oPerceived)); - // Get all allies in 60M to come to thier aid. Talkvolume silent // shout does not seem to work well. // - void function. Checks for the spawn int. in it. - // - Turns it off in it too + // - Turns it off in it too (5 minutes - 1.4) // - Variable range On Spawn ShoutBossShout(oPerceived); - // Warn others - AISpeakString(I_WAS_ATTACKED); // 54: "[Perception] Enemy Seen. Not in combat, attacking. [Percieved] " + GetName(oPerceived) DebugActionSpeakByInt(54, oPerceived); - // Note: added ActionDoCommand, so that SetFacingPoint is not - // interrupted. - ActionDoCommand(DetermineCombatRound(oPerceived)); + + // 1.4 change: SetFacingPoint(GetPosition(oPerceived)); + // Is now part of DetermineCombatRound(). + // * This means other events will work similarily. + DetermineCombatRound(oPerceived); + + // Warn others + AISpeakString(AI_SHOUT_I_WAS_ATTACKED); } } } // Else, they are an equal faction, or not an enemy (or both) else { - // If they are dead, say we saw something on waypoints, we charge in - // to investigate. + // If they are dead, or fighting, eg: we saw something on + // waypoints, we charge in to investigate. // * Higher intelligence will buff somewhat as well! - if(GetIsDead(oPerceived) && (bSeen || bHeard)) + if((GetIsDead(oPerceived) || GetIsInCombat(oPerceived)) && + (bSeen || bHeard)) { - // Warn others - AISpeakString(I_WAS_ATTACKED); + if(GetIsDead(oPerceived)) + { + // 55: "[Perception] Percieved Dead Friend! Moving into investigate [Percieved] " + GetName(oPerceived) + DebugActionSpeakByInt(55, oPerceived); + } + else + { + // 56: "[Perception] Percieved Alive Fighting Friend! Moving to and attacking. [Percieved] " + GetName(oPerceived) + DebugActionSpeakByInt(56, oPerceived); + } // Check if we can attack if(!CannotPerformCombatRound()) { // Hide or clear actions HideOrClear(); - // 55: "[Perception] Percieved Dead Friend! Moving and Searching [Percieved] " + GetName(oPerceived) - DebugActionSpeakByInt(55, oPerceived); - ActionMoveToLocation(GetLocation(oPerceived), TRUE); - ActionDoCommand(DetermineCombatRound()); + + // If we were called to arms, react + CallToArmsResponse(oPerceived); } - } - else if(GetIsInCombat(oPerceived) && (bSeen || bHeard)) - { - // Warn others - AISpeakString(I_WAS_ATTACKED); - // Only if we can attack. - if(!CannotPerformCombatRound()) + else { - // Hide or clear actions - HideOrClear(); - // 56: "[Perception] Percieved Alive Fighting Friend! Moving to and attacking. [Percieved] " + GetName(oPerceived) - DebugActionSpeakByInt(56, oPerceived); - ActionMoveToLocation(GetLocation(oPerceived), TRUE); - ActionDoCommand(DetermineCombatRound()); + // Warn others even if we don't, or cannot, attack + AISpeakString(AI_SHOUT_CALL_TO_ARMS); } } } diff --git a/_module/nss/nw_c2_default3.nss b/_module/nss/nw_c2_default3.nss index 310dcd95..49589ab5 100644 --- a/_module/nss/nw_c2_default3.nss +++ b/_module/nss/nw_c2_default3.nss @@ -1,28 +1,27 @@ -/************************ [On Combat Round End] ******************************** - Filename: nw_c2_default3 or j_ai_oncombatrou -************************* [On Combat Round End] ******************************** +/*/////////////////////// [On Combat Round End] //////////////////////////////// + Filename: nw_c2_default3 or J_AI_OnCombatrou +///////////////////////// [On Combat Round End] //////////////////////////////// This is run every 3 or 6 seconds, if the creature is in combat. It is executed only in combat automatically. It runs what the AI should do, bascially. -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.3 - Executes same script as the other parts of the AI to cuase a new action -************************* [Workings] ******************************************* + 1.4 - +///////////////////////// [Workings] /////////////////////////////////////////// Calls the combat AI file using the J_INC_OTHER_AI include function, DetermineCombatRound. -************************* [Arguments] ****************************************** +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: GetAttackTarget, GetLastHostileActor, GetAttemptedAttackTarget, GetAttemptedSpellTarget (Or these are useful at least!) -************************* [On Combat Round End] *******************************/ +///////////////////////// [On Combat Round End] //////////////////////////////*/ -#include "j_inc_other_ai" +#include "J_INC_OTHER_AI" void main() { - // Pre-combat-round-event - if(FireUserEvent(AI_FLAG_UDE_END_COMBAT_ROUND_PRE_EVENT, EVENT_END_COMBAT_ROUND_PRE_EVENT)) - // We may exit if it fires - if(ExitFromUDE(EVENT_END_COMBAT_ROUND_PRE_EVENT)) return; + // Pre-combat-round-event. Returns TRUE if we interrupt this script call. + if(FirePreUserEvent(AI_FLAG_UDE_END_COMBAT_ROUND_PRE_EVENT, EVENT_END_COMBAT_ROUND_PRE_EVENT)) return; // AI status check. Is the AI on? if(GetAIOff()) return; diff --git a/_module/nss/nw_c2_default4.nss b/_module/nss/nw_c2_default4.nss index b1371117..d1ef2e5f 100644 --- a/_module/nss/nw_c2_default4.nss +++ b/_module/nss/nw_c2_default4.nss @@ -1,16 +1,17 @@ -/************************ [On Conversation] ************************************ - Filename: j_ai_onconversat or nw_c2_default4 -************************* [On Conversation] ************************************ +/*/////////////////////// [On Conversation] //////////////////////////////////// + Filename: J_AI_OnConversat or nw_c2_default4 +///////////////////////// [On Conversation] //////////////////////////////////// OnConversation/ Listen to shouts. Documented, and checked. -Working- Added spawn in condition - Never clear actions when talking. -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.3 - Added in conversation thing - IE we can set speakstrings, no need for conversation file. - Sorted more shouts out. - Should work right, and not cause too many actions (as we ignore shouts for normally 12 or so seconds before letting them affect us again). -************************* [Workings] ******************************************* + 1.4 - Deafness incorpreated. +///////////////////////// [Workings] /////////////////////////////////////////// Uses RespondToShout to react to allies' shouts, and just attacks any enemy who speaks, or at least moves to them. (OK, dumb if they are invisible, but oh well, they shouldn't talk so loud!) @@ -18,19 +19,21 @@ Remember, whispers are never heard if too far away, speakstrings don't go through walls, and shouts are always heard (so we don't go off to anyone not in our area, remember) -************************* [Arguments] ****************************************** + + Deafness causes us to never hear battle, so unless we see the target speaking + we do not react. Doesn't apply to normal conversations - although if we cannot + talk (also restricted by deafness) then so be it. +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: GetListenPatternNumber, GetLastSpeaker, TestStringAgainstPattern, GetMatchedSubstring -************************* [On Conversation] ***********************************/ +///////////////////////// [On Conversation] //////////////////////////////////*/ -#include "j_inc_other_ai" +#include "J_INC_OTHER_AI" void main() { - // Pre-heartbeat-event - if(FireUserEvent(AI_FLAG_UDE_ON_DIALOGUE_PRE_EVENT, EVENT_ON_DIALOGUE_PRE_EVENT)) - // We may exit if it fires - if(ExitFromUDE(EVENT_ON_DIALOGUE_PRE_EVENT)) return; + // Pre-conversation-event. Returns TRUE if we interrupt this script call. + if(FirePreUserEvent(AI_FLAG_UDE_ON_DIALOGUE_PRE_EVENT, EVENT_ON_DIALOGUE_PRE_EVENT)) return; // AI status check. Is the AI on? if(GetAIOff()) return; @@ -38,17 +41,16 @@ void main() // Declarations int nMatch = GetListenPatternNumber(); object oShouter = GetLastSpeaker(); - string sSpoken = GetMatchedSubstring(i0); + string sSpoken = GetMatchedSubstring(0); // We can ignore everything under special cases - EG no valid shouter, // we are fleeing, its us, or we are not in the same area. // - We break out of the script if this happens. if(!GetIsObjectValid(oShouter) || /* Must be a valid speaker! */ - !GetCommandable() || /* Commandable */ oShouter == OBJECT_SELF || /* Not us! */ GetIsPerformingSpecialAction() || /* Not fleeing */ GetIgnore(oShouter) || /* Not ignoring the shouter */ - GetArea(oShouter) != GetArea(OBJECT_SELF))/* Same area (Stops "SHOUT" getting NPCs */ + GetArea(oShouter) != GetArea(OBJECT_SELF))/* Same area (Stops loud yellow shouts getting NPCs) */ { // Fire End of Dialogue event FireUserEvent(AI_FLAG_UDE_ON_DIALOGUE_EVENT, EVENT_ON_DIALOGUE_EVENT); @@ -56,44 +58,51 @@ void main() } // Conversation if not a shout. - if(nMatch == iM1) + if(nMatch == -1) { - // Make sure it is a PC and we are not fighting. - if(!GetIsFighting() && (GetIsPC(oShouter) || GetIsDMPossessed(oShouter))) + // * Don't speak when dead. 1.4 change (an obvious one to make) + if(CanSpeak()) { - // If we have something random (or not) to say instead of - // the conversation, we will say that. - if(GetLocalInt(OBJECT_SELF, ARRAY_SIZE + AI_TALK_ON_CONVERSATION)) + // Make sure it is a PC and we are not fighting. + if(!GetIsFighting() && (GetIsPC(oShouter) || GetIsDMPossessed(oShouter))) { - ClearAllActions();// Stop - SetFacingPoint(GetPosition(oShouter));// Face - SpeakArrayString(AI_TALK_ON_CONVERSATION);// Speak string - PlayAnimation(ANIMATION_LOOPING_TALK_NORMAL, f1, f3);// "Talk", then resume potitions. - ActionDoCommand(ExecuteScript(FILE_WALK_WAYPOINTS, OBJECT_SELF)); - } - else - { - // If we are set to NOT clear all actions, we won't. - if(!GetSpawnInCondition(AI_FLAG_OTHER_NO_CLEAR_ACTIONS_BEFORE_CONVERSATION, AI_OTHER_MASTER)) + // If we have something random (or not) to say instead of + // the conversation, we will say that. + if(GetLocalInt(OBJECT_SELF, ARRAY_SIZE + AI_TALK_ON_CONVERSATION)) { - ClearAllActions(); + ClearAllActions();// Stop + SetFacingPoint(GetPosition(oShouter));// Face + SpeakArrayString(AI_TALK_ON_CONVERSATION);// Speak string + PlayAnimation(ANIMATION_LOOPING_TALK_NORMAL, 1.0, 3.0);// "Talk", then resume potitions. + ActionDoCommand(ExecuteScript(FILE_WALK_WAYPOINTS, OBJECT_SELF)); + } + else + { + // If we are set to NOT clear all actions, we won't. + if(!GetSpawnInCondition(AI_FLAG_OTHER_NO_CLEAR_ACTIONS_BEFORE_CONVERSATION, AI_OTHER_MASTER)) + { + ClearAllActions(); + } + BeginConversation(); } - BeginConversation(); } } } // If it is a valid shout...and a valid shouter. // - Not a DM. Not ignoring shouting. Not a Debug String. - else if(!GetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID) && // Not listening (IE heard already) - !GetIsDM(oShouter) && FindSubString(sSpoken, "[Debug]") == iM1) + else if(!GetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID) &&// Not listening (IE heard already) + !GetIsDM(oShouter) && FindSubString(sSpoken, "[Debug]") == -1 && + // 1.4 - Deafness (or they are seen) check, for fun. + (!GetHasEffect(EFFECT_TYPE_DEAF) || GetObjectSeen(oShouter))) { if(GetIsFriend(oShouter) || GetFactionEqual(oShouter)) { // If they are a friend, not a PC, and a valid number, react. // In the actual RespondToShout call, we do check to see if we bother. // - Is PC - or is...master? - // - Shouts of 1 or over only. - if(nMatch >= i1 && !GetIsPC(oShouter) && !GetIsPC(GetMaster(oShouter))) + // - Shouts which are not negative, and not AI_ANYTHING_SAID_CONSTANT. + if(nMatch >= 0 && nMatch != AI_SHOUT_ANYTHING_SAID_CONSTANT && + !GetIsPC(oShouter) && !GetIsPC(GetMaster(oShouter))) { // Respond to the shout RespondToShout(oShouter, nMatch); @@ -104,31 +113,27 @@ void main() GetIsInCombat(oShouter) && GetObjectType(oShouter) == OBJECT_TYPE_CREATURE) { - // Only use attack target. - object oIntruder = GetIntruderFromShout(oShouter); - // Valid, and not a friend if a PC speaker - if(GetIsObjectValid(oIntruder) && - !GetFactionEqual(oIntruder) && - !GetIsFriend(oIntruder)) - { - // 57: "[Shout] Friend (may be PC) in combat. Attacking! [Friend] " + GetName(oShouter) - DebugActionSpeakByInt(57, oShouter); - DetermineCombatRound(oIntruder); - } + // 57: "[Shout] Friend (may be PC) in combat. Attacking! [Friend] " + GetName(oShouter) + DebugActionSpeakByInt(57, oShouter); + + // Respond to oShouter + IWasAttackedResponse(oShouter); } } else if(GetIsEnemy(oShouter) && GetObjectType(oShouter) == OBJECT_TYPE_CREATURE) { // If we hear anything said by an enemy, and are not fighting, attack them! if(!CannotPerformCombatRound()) - // the negatives are associate shouts, 0+ are my shouts. 0 is anything + // the negatives are associate shouts, Normally (!) + // 0+ are my shouts. 0 is anything { // We make sure it isn't an emote (set by default) - if(nMatch == i0 && GetSpawnInCondition(AI_FLAG_OTHER_DONT_RESPOND_TO_EMOTES, AI_OTHER_MASTER)) + if(nMatch == AI_SHOUT_ANYTHING_SAID_CONSTANT && + GetSpawnInCondition(AI_FLAG_OTHER_DONT_RESPOND_TO_EMOTES, AI_OTHER_MASTER)) { // Jump out if its an emote - "*Nods*" - if(GetStringLeft(sSpoken, i1) == EMOTE_STAR && - GetStringRight(sSpoken, i1) == EMOTE_STAR) + if(GetStringLeft(sSpoken, 1) == EMOTE_STAR && + GetStringRight(sSpoken, 1) == EMOTE_STAR) { // Fire End of Dialogue event FireUserEvent(AI_FLAG_UDE_ON_DIALOGUE_EVENT, EVENT_ON_DIALOGUE_EVENT); @@ -137,11 +142,16 @@ void main() } // 58: "[Shout] Responding to shout [Enemy] " + GetName(oShouter) + " Who has spoken!" DebugActionSpeakByInt(58, oShouter); + // Short non-respond - SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, f6); + SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, 6.0); + // Attack the enemy! ClearAllActions(); DetermineCombatRound(oShouter); + + // Shout to allies to attack the shouter + AISpeakString(AI_SHOUT_I_WAS_ATTACKED); } } } diff --git a/_module/nss/nw_c2_default5.nss b/_module/nss/nw_c2_default5.nss index e10ee069..d529a447 100644 --- a/_module/nss/nw_c2_default5.nss +++ b/_module/nss/nw_c2_default5.nss @@ -1,26 +1,25 @@ -/************************ [On Phisical Attacked] ******************************* - Filename: j_ai_onphiattack or nw_c2_default5 -************************* [On Phisical Attacked] ******************************* +/*/////////////////////// [On Phisical Attacked] /////////////////////////////// + Filename: J_AI_OnPhiAttack or nw_c2_default5 +///////////////////////// [On Phisical Attacked] /////////////////////////////// On Attacked No checking for fleeing or warnings. Very boring really! -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.3 - Added hiding things -************************* [Workings] ******************************************* + 1.4 - Missing Silent Shouts have been added. +///////////////////////// [Workings] /////////////////////////////////////////// Got some simple Knockdown timer, so that we use heal sooner if we keep getting a creature who is attempting to knock us down. -************************* [Arguments] ****************************************** +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: GetLastAttacker, GetLastWeaponUsed, GetLastAttackMode, GetLastAttackType -************************* [On Phisical Attacked] ******************************/ +///////////////////////// [On Phisical Attacked] /////////////////////////////*/ -#include "j_inc_other_ai" +#include "J_INC_OTHER_AI" void main() { - // Pre-attacked-event - if(FireUserEvent(AI_FLAG_UDE_ATTACK_PRE_EVENT, EVENT_ATTACK_PRE_EVENT)) - // We may exit if it fires - if(ExitFromUDE(EVENT_ATTACK_PRE_EVENT)) return; + // Pre-attacked-event. Returns TRUE if we interrupt this script call. + if(FirePreUserEvent(AI_FLAG_UDE_ATTACK_PRE_EVENT, EVENT_ATTACK_PRE_EVENT)) return; // AI status check. Is the AI on? if(GetAIOff()) return; @@ -28,11 +27,11 @@ void main() // Set up objects. object oAttacker = GetLastAttacker(); object oWeapon = GetLastWeaponUsed(oAttacker); - int iMode = GetLastAttackMode(oAttacker); // Currently unused - int iAttackType = GetLastAttackType(oAttacker); + //int nMode = GetLastAttackMode(oAttacker); // Currently unused + int nAttackType = GetLastAttackType(oAttacker); - if(GetIsObjectValid(oAttacker) && !GetFactionEqual(oAttacker) && - !GetIsDM(oAttacker) && !GetIgnore(oAttacker)) + // Check if they are valid, a DM, we are ignoring them, they are dead now, or invalid + if(!GetIgnoreNoFriend(oAttacker)) { // Adjust automatically if set. if(GetSpawnInCondition(AI_FLAG_OTHER_CHANGE_FACTIONS_TO_HOSTILE_ON_ATTACK, AI_OTHER_MASTER)) @@ -42,23 +41,28 @@ void main() AdjustReputation(oAttacker, OBJECT_SELF, -100); } } + // If we were attacked by knockdown, for a timer of X seconds, we make // sure we attempt healing at a higher level. if(!GetLocalTimer(AI_TIMER_KNOCKDOWN) && - (iAttackType == SPECIAL_ATTACK_IMPROVED_KNOCKDOWN || - iAttackType == SPECIAL_ATTACK_KNOCKDOWN) && + (nAttackType == SPECIAL_ATTACK_IMPROVED_KNOCKDOWN || + nAttackType == SPECIAL_ATTACK_KNOCKDOWN) && !GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_KNOCKDOWN) && - GetBaseAttackBonus(oAttacker) + i20 >= GetAC(OBJECT_SELF)) + GetBaseAttackBonus(oAttacker) + 20 >= GetAC(OBJECT_SELF)) { - SetLocalTimer(AI_TIMER_KNOCKDOWN, f30); + SetLocalTimer(AI_TIMER_KNOCKDOWN, 30.0); } - // Set last hostile attacker. + // Set last hostile, valid attacker (Used in the On Damaged event) SetAIObject(AI_STORED_LAST_ATTACKER, oAttacker); - // Speak the phisically attacked string, if applicable. - // Speak the damaged string, if applicable. - SpeakArrayString(AI_TALK_ON_PHISICALLY_ATTACKED); + // * Don't speak when dead. 1.4 change (an obvious one to make) + if(CanSpeak()) + { + // Speak the phisically attacked string, if applicable. + // Speak the damaged string, if applicable. + SpeakArrayString(AI_TALK_ON_PHISICALLY_ATTACKED); + } // Turn of hiding, a timer to activate Hiding in the main file. This is // done in each of the events, with the opposition checking seen/heard. @@ -79,19 +83,52 @@ void main() // If we are not fighting, and they are in the area, attack. Else, determine anyway. if(!CannotPerformCombatRound()) { + // Must be in our area to go after now. if(GetArea(oAttacker) == GetArea(OBJECT_SELF)) { // 59: "[Phisically Attacked] Attacking back. [Attacker(enemy)] " + GetName(oAttacker) DebugActionSpeakByInt(59, oAttacker); + + // Attack the attacker DetermineCombatRound(oAttacker); + + // Shout to allies to attack the enemy who attacked me + AISpeakString(AI_SHOUT_I_WAS_ATTACKED); } else { + // Shout to allies to attack, or be prepared. + AISpeakString(AI_SHOUT_CALL_TO_ARMS); + // 60: "[Phisically Attacked] Not same area. [Attacker(enemy)] " + GetName(oAttacker) DebugActionSpeakByInt(60, oAttacker); - DetermineCombatRound();// May find another hostile to attack... + + // May find another hostile to attack... + DetermineCombatRound(); } } + else + { + // Shout to allies to attack, or be prepared. + AISpeakString(AI_SHOUT_CALL_TO_ARMS); + } + } + // Else, invalid, DM, ally, etc...must be prepared at least (could be + // they are charmed or something!) + else + { + // If we are not fighting, prepare for battle. Something bad must have + // happened. + if(!CannotPerformCombatRound()) + { + // Respond to oAttacker as if they shouted for help. + IWasAttackedResponse(oAttacker); + } + else + { + // Shout to allies to attack, or be prepared. + AISpeakString(AI_SHOUT_CALL_TO_ARMS); + } } // Fire End of Attacked event diff --git a/_module/nss/nw_c2_default6.nss b/_module/nss/nw_c2_default6.nss index c01d64c8..596caa3e 100644 --- a/_module/nss/nw_c2_default6.nss +++ b/_module/nss/nw_c2_default6.nss @@ -1,53 +1,61 @@ -/************************ [On Damaged] ***************************************** - Filename: nw_c2_default6 or j_ai_ondamaged -************************* [On Damaged] ***************************************** +/*/////////////////////// [On Damaged] ///////////////////////////////////////// + Filename: nw_c2_default6 or J_AI_OnDamaged +///////////////////////// [On Damaged] ///////////////////////////////////////// We attack any damager if same area (and not already fighting then search for enemies (defaults to searching if there are no enemies left). -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.3 - If we have a damager, not equal faction, and not a DM... - We set Max Elemental damage. - Sets the highest damager and amount (if the new damager is seen/heard) - Polymorph improved a little - Hide check - Morale penalty (if set) -************************* [Workings] ******************************************* - GetDamageDealtByType() will not work with proper phisical attacks - a workaround - is GetTotalDamageDealt() - All GetDamageDealtByType(). This means it will - get everything not applied with EffectDamage() which normally fires this - script. -************************* [Arguments] ****************************************** + 1.4 - Elemental damage fixed with bugfixed introduced in later patches. + - Moved things around, more documentation, a little more ordered. + - Added the missing silent shout strings to get allies to attack. + - Damaged taunting will not happen if we are dead. +///////////////////////// [Workings] /////////////////////////////////////////// + Now with fixes, we can correctly set physical damage done (and elemental + damage). + + Otherwise, this acts like a hositile spell, or a normal attack or pickpocket + attempt would - and attack the damn person who dares damage us! +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: GetTotalDamageDealt, GetLastDamager, GetCurrentHitPoints (and max), GetDamageDealtByType (must be done seperatly for each, doesn't count melee damage) -************************* [On Damaged] ****************************************/ +///////////////////////// [On Damaged] ///////////////////////////////////////*/ + +#include "J_INC_OTHER_AI" -#include "j_inc_other_ai" void main() { - // Pre-damaged-event - if(FireUserEvent(AI_FLAG_UDE_DAMAGED_PRE_EVENT, EVENT_DAMAGED_PRE_EVENT)) - // We may exit if it fires - if(ExitFromUDE(EVENT_DAMAGED_PRE_EVENT)) return; + // Pre-damaged-event. Returns TRUE if we interrupt this script call. + if(FirePreUserEvent(AI_FLAG_UDE_DAMAGED_PRE_EVENT, EVENT_DAMAGED_PRE_EVENT)) return; // AI status check. Is the AI on? if(GetAIOff()) return; // Define Objects/Integers. - int iDamage = GetTotalDamageDealt(); + int nDamage = GetTotalDamageDealt(); object oDamager = GetLastDamager(); // Check to see if we will polymorph. - int iPolymorph = GetAIConstant(AI_POLYMORPH_INTO); + int nPolymorph = GetAIConstant(AI_POLYMORPH_INTO); + + // Total up the physical damage // Polymorph check. - if(iPolymorph >= i0) + if(nPolymorph >= 0) { - if(!GetHasEffect(EFFECT_TYPE_POLYMORPH))// We won't polymorph if already so + // We won't polymorph if already so + if(!GetHasEffect(EFFECT_TYPE_POLYMORPH)) { - effect eShape = SupernaturalEffect(EffectPolymorph(iPolymorph)); + // Polymorph into the requested shape. Cannot be dispelled. + effect eShape = SupernaturalEffect(EffectPolymorph(nPolymorph)); effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD); DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_PERMANENT, eShape, OBJECT_SELF)); DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, OBJECT_SELF)); } - SetAIConstant(AI_POLYMORPH_INTO, -1);// We set it to invalid (sets to 0). + DeleteAIConstant(AI_POLYMORPH_INTO);// We set it to invalid (sets to 0). } // First, we check AOE spells... if(GetObjectType(oDamager) == OBJECT_TYPE_AREA_OF_EFFECT) @@ -55,15 +63,16 @@ void main() // Set the damage done by it (the last damage) // Set to the tag of the AOE, prefixed AI style to be sure. // - Note, doesn't matter about things like - if(iDamage > i1) + if(nDamage > 0) { // Set it to object to string, which we will delete later anywho. - SetAIInteger(ObjectToString(oDamager), iDamage); + SetAIInteger(ObjectToString(oDamager), nDamage); } } - // Hostile attacker... - else if(GetIsObjectValid(oDamager) && !GetFactionEqual(oDamager) && - !GetIsDM(oDamager)&& !GetIgnore(oDamager)) + // Hostile attacker...but it doesn't matter (at the moment) if they even + // did damage. + // * GetIgnoreNoFriend() wrappers DM, Validity, Faction Equal and Dead checks in one + else if(!GetIgnoreNoFriend(oDamager)) { // Adjust automatically if set. (and not an AOE) if(GetSpawnInCondition(AI_FLAG_OTHER_CHANGE_FACTIONS_TO_HOSTILE_ON_ATTACK, AI_OTHER_MASTER)) @@ -73,80 +82,101 @@ void main() AdjustReputation(oDamager, OBJECT_SELF, -100); } } - // Set the max elemental damage done, for better use of elemental protections. - // This is set for the most damage...so it could be 1 (for a +1 fire weapon, any - // number of hits) or over 50 (good fireball). - // Need to have protection single (IE including elemental ones) ready. - if(GetSpawnInCondition(AI_VALID_TALENT_BENEFICIAL_PROTECTION_SINGLE, AI_VALID_SPELLS)) - { - // Please make sure | works! By Blind Io! - int iDamageDone = GetDamageDealtByType(DAMAGE_TYPE_ACID | - DAMAGE_TYPE_COLD | DAMAGE_TYPE_ELECTRICAL | - DAMAGE_TYPE_FIRE | DAMAGE_TYPE_SONIC); - if(iDamageDone > GetAIInteger(MAX_ELEMENTAL_DAMAGE)) - { - SetAIInteger(MAX_ELEMENTAL_DAMAGE, iDamageDone); - } - // Set the last damage done, may set to 0 of course :-P - SetAIInteger(LAST_ELEMENTAL_DAMAGE, iDamageDone); - } // Turn of hiding, a timer to activate Hiding in the main file. This is // done in each of the events, with the opposition checking seen/heard. TurnOffHiding(oDamager); - // Speak the damaged string, if applicable. - SpeakArrayString(AI_TALK_ON_DAMAGED); - - // Morale: We may get a penalty if it does more than a cirtain amount of HP damage. - // Other: We set highest damager and amount. - if(iDamage > i0) + // Did they do damage to use? (IE: No DR) Some things are inapproprate + // to check if no damage was actually done. + if(nDamage > 0) { - if(!GetSpawnInCondition(AI_FLAG_FLEEING_FEARLESS, AI_TARGETING_FLEE_MASTER)) + // Speak the damaged string, if applicable. + // * Don't speak when dead. 1.4 change (an obvious one to make) + if(CanSpeak()) { - int iToDamage = GetBoundriedAIInteger(AI_DAMAGE_AT_ONCE_FOR_MORALE_PENALTY, GetMaxHitPoints()/i6, GetMaxHitPoints(), i1); - int iPenalty = GetBoundriedAIInteger(AI_DAMAGE_AT_ONCE_PENALTY, i6, i50, i1); - if(iDamage > iToDamage) - { - // 61: "[Damaged] Morale Penalty for 600 seconds [Penalty]" + IntToString(iPenalty) - DebugActionSpeakByInt(61, OBJECT_INVALID, iPenalty); - // Apply penalty - SetMoralePenalty(iPenalty, 300.0); - } + SpeakArrayString(AI_TALK_ON_DAMAGED); } + // 1.4 note: These two variables are currently *unused* apart from + // healing. When healing a being (even another NPC) they are checked + // for massive damage. Can not bother to set the highest damager for now. + // NEW: + int nHighestDamage = GetAIInteger(AI_HIGHEST_DAMAGE_AMOUNT); + if(nDamage >= nHighestDamage) + { + SetAIInteger(AI_HIGHEST_DAMAGE_AMOUNT, nDamage); + } + + /* OLD: + + // Get the previous highest damager, and highest damage amount object oHighestDamager = GetAIObject(AI_HIGHEST_DAMAGER); - int iHighestDamage = GetAIInteger(AI_HIGHEST_DAMAGE_AMOUNT); - // If the original was not valid...or not seen/heard, we delete it whatever. - if(!GetIsObjectValid(oHighestDamager) || + int nHighestDamage = GetAIInteger(AI_HIGHEST_DAMAGE_AMOUNT); + // Set the highest damager, if they are seen or heard, and have done loads. + if((GetObjectSeen(oDamager) || GetObjectHeard(oDamager)) && + nDamage >= nHighestDamage || !GetIsObjectValid(oHighestDamager)) + { + SetAIObject(AI_HIGHEST_DAMAGER, oDamager); + SetAIInteger(AI_HIGHEST_DAMAGE_AMOUNT, nDamage); + } + // Else, if the original was not valid...or not seen/heard, we + // delete it so we don't bother to use it later. + else if(!GetIsObjectValid(oHighestDamager) || (!GetObjectSeen(oHighestDamager) && !GetObjectHeard(oHighestDamager))) { DeleteAIObject(AI_HIGHEST_DAMAGER); DeleteAIInteger(AI_HIGHEST_DAMAGE_AMOUNT); } - // Set the highest damager. - if((GetObjectSeen(oDamager) || GetObjectHeard(oDamager)) && - iDamage >= iHighestDamage) - { - SetAIObject(AI_HIGHEST_DAMAGER, oDamager); - SetAIInteger(AI_HIGHEST_DAMAGE_AMOUNT, iDamage); - } - // Phisical damage - only sets if the last damager is the last attacker. + */ + + // Get all the physical damage. Elemental damage is then nDamage minus + // the physical damage. + int nPhysical = GetDamageDealtByType(DAMAGE_TYPE_BASE_WEAPON | + DAMAGE_TYPE_BLUDGEONING | + DAMAGE_TYPE_PIERCING | + DAMAGE_TYPE_SLASHING); + // If they are all -1, then we make nPhysical 0. + if(nPhysical <= -1) nPhysical = 0; + + // Physical damage - only sets if the last damager is the last attacker. if(GetAIObject(AI_STORED_LAST_ATTACKER) == oDamager) { - int iHighestPhisicalDamage = GetAIInteger(AI_HIGHEST_PHISICAL_DAMAGE_AMOUNT); - int iPhisicalDamage = iDamage - - // This relies upon the bug that these damage types only return damage - // from EffectDamage, and melee damage is any that remains. Wish it was - // fixed though... - GetDamageDealtByType(DAMAGE_TYPE_ACID | DAMAGE_TYPE_BLUDGEONING | - DAMAGE_TYPE_COLD | DAMAGE_TYPE_DIVINE | - DAMAGE_TYPE_ELECTRICAL | DAMAGE_TYPE_FIRE | - DAMAGE_TYPE_MAGICAL | DAMAGE_TYPE_NEGATIVE | - DAMAGE_TYPE_PIERCING | DAMAGE_TYPE_POSITIVE | - DAMAGE_TYPE_SLASHING | DAMAGE_TYPE_SONIC); - if(iHighestPhisicalDamage < iPhisicalDamage) + // Get the previous highest damage and test it + if(nPhysical > GetAIInteger(AI_HIGHEST_PHISICAL_DAMAGE_AMOUNT)) { - SetAIInteger(AI_HIGHEST_PHISICAL_DAMAGE_AMOUNT, iPhisicalDamage); + // If higher, and was a melee/ranged attacker, set it. + // This does include other additional physical damage - EG: + // weapon property: Bonus Damage. + SetAIInteger(AI_HIGHEST_PHISICAL_DAMAGE_AMOUNT, nPhysical); + } + } + + // Set the max elemental damage done, for better use of elemental + // protections. This is set for the most damage...so it could be + // 1 (for a +1 fire weapon, any number of hits) or over 50 (good + // fireball/flame storm etc.) + int nElemental = nDamage - nPhysical; + if(nElemental > GetAIInteger(MAX_ELEMENTAL_DAMAGE)) + { + SetAIInteger(MAX_ELEMENTAL_DAMAGE, nElemental); + } + // Set the last damage done, may set to 0 of course :-P + // * This is only set if they did damage us at all, however. + SetAIInteger(LAST_ELEMENTAL_DAMAGE, nElemental); + + // Morale: We may get a penalty if it does more than a cirtain amount of HP damage. + // Other: We set highest damager and amount. + if(!GetSpawnInCondition(AI_FLAG_FLEEING_FEARLESS, AI_TARGETING_FLEE_MASTER)) + { + // Get penalty and how much damage at once needs to be done + int nPenalty = GetBoundriedAIInteger(AI_DAMAGE_AT_ONCE_PENALTY, 6, 50, 1); + int nToDamage = GetBoundriedAIInteger(AI_DAMAGE_AT_ONCE_FOR_MORALE_PENALTY, GetMaxHitPoints()/6, GetMaxHitPoints(), 1); + if(nDamage > nToDamage) + { + // 61: "[Damaged] Morale Penalty for 600 seconds [Penalty]" + IntToString(iPenalty) + DebugActionSpeakByInt(61, OBJECT_INVALID, nPenalty); + // Apply penalty + SetMoralePenalty(nPenalty, 300.0); } } } @@ -155,27 +185,53 @@ void main() { // 62: "[Damaged] Not in combat: DCR [Damager]" + GetName(oDamager) DebugActionSpeakByInt(62, oDamager); + + // Check if they are in the same area. Can be a left AOE spell. + // Don't attack purposly across area's. if(GetArea(oDamager) == GetArea(OBJECT_SELF)) { + // Shout to allies to attack the enemy who attacked me + AISpeakString(AI_SHOUT_I_WAS_ATTACKED); + DetermineCombatRound(oDamager); } else { + // Shout to allies to attack, or be prepared. + AISpeakString(AI_SHOUT_CALL_TO_ARMS); + DetermineCombatRound(); } } + else + { + // Shout to allies to attack, or be prepared. + AISpeakString(AI_SHOUT_CALL_TO_ARMS); + } } - else // Else it is friendly, or invalid damager + // Else it is friendly, or invalid damager + else { + // Still will react - eg: A left AOE spell (which might mean a battle + // just happened) if(!CannotPerformCombatRound()) { + // Shout to allies to attack generally. No target to specifically attack, + // as it is an ally. + AISpeakString(AI_SHOUT_CALL_TO_ARMS); + // 63: [Damaged] Not in combat: DCR. Ally hit us. [Damager(Ally?)]" + GetName(oDamager) DebugActionSpeakByInt(63, oDamager); DetermineCombatRound(); } + else + { + // Shout to allies to attack, or be prepared. + AISpeakString(AI_SHOUT_CALL_TO_ARMS); + } } // User defined event - for normally immoral creatures. - if(GetCurrentHitPoints() == i1) + if(GetCurrentHitPoints() == 1) { // Fire the immortal damaged at 1 HP event. FireUserEvent(AI_FLAG_UDE_DAMAGED_AT_1_HP, EVENT_DAMAGED_AT_1_HP); diff --git a/_module/nss/nw_c2_default7.nss b/_module/nss/nw_c2_default7.nss index 98af1008..c8fcf672 100644 --- a/_module/nss/nw_c2_default7.nss +++ b/_module/nss/nw_c2_default7.nss @@ -1,38 +1,37 @@ -/************************ [On Death] ******************************************* - Filename: j_ai_ondeath or nw_c2_default7 -************************* [On Death] ******************************************* +/*/////////////////////// [On Death] /////////////////////////////////////////// + Filename: J_AI_OnDeath or nw_c2_default7 +///////////////////////// [On Death] /////////////////////////////////////////// Speeded up no end, when compiling, with seperate Include. Cleans up all un-droppable items, all ints and all local things when destroyed. Check down near the bottom for a good place to add XP or corpse lines ;-) -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.3 - Added in Turn of corpses toggle - Added in appropriate space for XP awards, marked with ideas (effect death) -************************* [Workings] ******************************************* + 1.4 - Removed the redudnant notes on the "You have gained 0 experience" message +///////////////////////// [Workings] /////////////////////////////////////////// You can edit this for experience, there is a seperate section for it. It will use DeathCheck to execute a cleanup-and-destroy script, that removes any coprse, named "j_ai_destroyself". -************************* [Arguments] ****************************************** +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: GetLastKiller. -************************* [On Death] ******************************************/ +///////////////////////// [On Death] /////////////////////////////////////////*/ // We only require the constants/debug file. We have 1 function, not worth another include. -#include "j_inc_constants" +#include "J_INC_CONSTANTS" // We need a wrapper. If the amount of deaths, got in this, is not equal to iDeaths, // we don't execute the script, else we do. :-P -void DeathCheck(int iDeaths); +void DeathCheck(int nDeaths); void main() { // If we are set to, don't fire this script at all if(GetAIInteger(I_AM_TOTALLY_DEAD)) return; - // Pre-death-event - if(FireUserEvent(AI_FLAG_UDE_DEATH_PRE_EVENT, EVENT_DEATH_PRE_EVENT)) - // We may exit if it fires - if(ExitFromUDE(EVENT_DEATH_PRE_EVENT)) return; + // Pre-death-event. Returns TRUE if we interrupt this script call. + if(FirePreUserEvent(AI_FLAG_UDE_DEATH_PRE_EVENT, EVENT_DEATH_PRE_EVENT)) return; // Note: No AI on/off check here. @@ -50,7 +49,7 @@ void main() if(!GetLocalTimer(AI_TIMER_DEATH_EFFECT_DEATH)) { // Don't apply effect death to self more then once per 2 seconds. - SetLocalTimer(AI_TIMER_DEATH_EFFECT_DEATH, f2); + SetLocalTimer(AI_TIMER_DEATH_EFFECT_DEATH, 2.0); // This should make the last killer us. ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectResurrection(), OBJECT_SELF); ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(GetMaxHitPoints()), OBJECT_SELF); @@ -61,50 +60,47 @@ void main() // Set have died once, stops giving out mulitple amounts of XP. SetAIInteger(WE_HAVE_DIED_ONCE, TRUE); -/************************ [Experience] ***************************************** - THIS is the place for it, below this comment. To reward XP, you might want - to first apply EffectDeath to ourselves (uncomment the example lines) which - will remove the "You recieved 0 Experience" if you have normal XP at 0, as - the On Death event is before the reward, and therefore now our last killer - will be outselves. It will not cause any errors, oKiller is already set. +/*/////////////////////// [Experience] ///////////////////////////////////////// + THIS is the place for it, below this comment. - Anything else, I leave to you. GetFirstFactionMember (and next), GiveXPToCreature, - GetXP, SetXP, GetChallengeRating all are really useful. + It is useful to use GetFirstFactionMember (and Next), GiveXPToCreature, + GetXP, SetXP, GetChallengeRating (of self) all are really useful. - Bug note: GetFirstFactionMember/Next with the PC parameter means either ONLY PC -************************* [Experience] ****************************************/ - // Do XP things (Use object "oKiller"). + Bug note: GetFirstFactionMember/Next with the PC parameter means either ONLY PC, + and so NPC henchmen, unless FALSE is used, will not be even recognised. +///////////////////////// [Experience] ///////////////////////////////////////*/ + // Do XP things (Use object "oKiller" for who killed us). -/************************ [Experience] ****************************************/ +/*/////////////////////// [Experience] ///////////////////////////////////////*/ } // Note: Here we do a simple way of checking how many times we have died. // Nothing special. Debugging most useful aspect. - int iDeathCounterNew = GetAIInteger(AMOUNT_OF_DEATHS); - iDeathCounterNew++; - SetAIInteger(AMOUNT_OF_DEATHS, iDeathCounterNew); + int nDeathCounterNew = GetAIInteger(AMOUNT_OF_DEATHS); + nDeathCounterNew++; + SetAIInteger(AMOUNT_OF_DEATHS, nDeathCounterNew); // Here is the last time (in game seconds) we died. It is used in the executed script // to make sure we don't prematurly remove areselves. // We may want some sort of visual effect - like implosion or something, to fire. - int iDeathEffect = GetAIConstant(AI_DEATH_VISUAL_EFFECT); + int nDeathEffect = GetAIConstant(AI_DEATH_VISUAL_EFFECT); // Valid constants from 0 and up. Apply to our location (not to us, who will go!) - if(iDeathEffect >= i0) + if(nDeathEffect >= 0) { - ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(iDeathEffect), GetLocation(OBJECT_SELF)); + ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(nDeathEffect), GetLocation(OBJECT_SELF)); } // Default Commoner alignment changing. (If the commoner is not evil!) - if(GetLevelByClass(CLASS_TYPE_COMMONER) > i0 && + if(GetLevelByClass(CLASS_TYPE_COMMONER) > 0 && GetAlignmentGoodEvil(OBJECT_SELF) != ALIGNMENT_EVIL && !GetSpawnInCondition(AI_FLAG_OTHER_NO_COMMONER_ALIGNMENT_CHANGE, AI_OTHER_MASTER)) { if(GetIsPC(oKiller)) { - AdjustAlignment(oKiller, ALIGNMENT_EVIL, i5); + AdjustAlignment(oKiller, ALIGNMENT_EVIL, 5); } else { @@ -113,29 +109,31 @@ void main() object oMaster = GetMaster(oKiller); if(GetIsObjectValid(oMaster) && GetIsPC(oMaster)) { - AdjustAlignment(oMaster, ALIGNMENT_EVIL, i5); + AdjustAlignment(oMaster, ALIGNMENT_EVIL, 5); } } } - // Always shout when we are killed. Reactions - Morale penalty, and attack the killer. - AISpeakString(I_WAS_KILLED); + // Always shout when we are killed. Reactions - Morale penalty, and + // attack the killer. + AISpeakString(AI_SHOUT_I_WAS_KILLED); // Speaks the set death speak, like "AGGGGGGGGGGGGGGGGGGG!! NOOOO!" for instance :-) + // Note for 1.4: No need for "CanSpeak()" for this, of course. SpeakArrayString(AI_TALK_ON_DEATH); // First check - do we use "destroyable corpses" or not? (default, yes) if(!GetSpawnInCondition(AI_FLAG_OTHER_TURN_OFF_CORPSES, AI_OTHER_MASTER)) { // We will actually dissapear after 30.0 seconds if not raised. - int iTime = GetAIInteger(AI_CORPSE_DESTROY_TIME); - if(iTime == i0) // Error checking + int nTime = GetAIInteger(AI_CORPSE_DESTROY_TIME); + if(nTime == 0) // Error checking { - iTime = i1; + nTime = 30; } - // 64: "[Death] Checking corpse status in " + IntToString(iTime) + " [Killer] " + GetName(oKiller) + " [Times Died Now] " + IntToString(iDeathCounterNew) - DebugActionSpeakByInt(64, oKiller, iTime, IntToString(iDeathCounterNew)); + // 64: "[Death] Checking corpse status in " + IntToString(nTime) + " [Killer] " + GetName(oKiller) + " [Times Died Now] " + IntToString(nDeathCounterNew) + DebugActionSpeakByInt(64, oKiller, nTime, IntToString(nDeathCounterNew)); // Delay check - DelayCommand(IntToFloat(iTime), DeathCheck(iDeathCounterNew)); + DelayCommand(IntToFloat(nTime), DeathCheck(nDeathCounterNew)); } else { @@ -155,10 +153,10 @@ void main() // We need a wrapper. If the amount of deaths, got in this, is not equal to iDeaths, // we don't execute the script, else we do. :-P -void DeathCheck(int iDeaths) +void DeathCheck(int nDeaths) { // Do the deaths imputted equal the amount we have suffered? - if(GetAIInteger(AMOUNT_OF_DEATHS) == iDeaths) + if(GetAIInteger(AMOUNT_OF_DEATHS) == nDeaths) { // - This now includes a check for Bioware's lootable functions and using them. ExecuteScript(FILE_DEATH_CLEANUP, OBJECT_SELF); diff --git a/_module/nss/nw_c2_default8.nss b/_module/nss/nw_c2_default8.nss index c9587918..1eb8f908 100644 --- a/_module/nss/nw_c2_default8.nss +++ b/_module/nss/nw_c2_default8.nss @@ -1,72 +1,83 @@ -/************************ [On Disturbed] *************************************** - Filename: j_ai_ondisturbed or nw_c2_default8 -************************* [On Disturbed] *************************************** +/*/////////////////////// [On Disturbed] /////////////////////////////////////// + Filename: J_AI_OnDisturbed or nw_c2_default8 +///////////////////////// [On Disturbed] /////////////////////////////////////// This will attack pickpockets, and inventory disturbers. Note: Stupidly, Bioware made this only affect the creature by stealing. Still, oh well :-( This means that the only event which fires it is pickpocketing. -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.3 - Changed why we determine combat round - Any change in inventory will trigger appropriate SetWeapons again. - Added turn of hide things. -************************* [Workings] ******************************************* + 1.4 - Cleaned up a bit. Removed unused declared variable. +///////////////////////// [Workings] /////////////////////////////////////////// Only fired by stealing, great. Oh well, it will attack any disturber anyway. It *might* not be fired if the natural spot check to notice a theft doesn't work. No idea personally. -************************* [Arguments] ****************************************** +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: GetInventoryDisturbItem, GetLastDisturbed, GetInventoryDisturbType (I think it is always be stolen :-( ). -************************* [On Disturbed] **************************************/ +///////////////////////// [On Disturbed] /////////////////////////////////////*/ -#include "j_inc_other_ai" +#include "J_INC_OTHER_AI" void main() { - // Pre-disturbed-event - if(FireUserEvent(AI_FLAG_UDE_DISTURBED_PRE_EVENT, EVENT_DISTURBED_PRE_EVENT)) - // We may exit if it fires - if(ExitFromUDE(EVENT_DISTURBED_PRE_EVENT)) return; + // Pre-disturbed-event. Returns TRUE if we interrupt this script call. + if(FirePreUserEvent(AI_FLAG_UDE_DISTURBED_PRE_EVENT, EVENT_DISTURBED_PRE_EVENT)) return; // AI status check. Is the AI on? if(GetAIOff()) return; - // We will set weapons if it is a weapon. - object oItem = GetInventoryDisturbItem(); - int nBase = GetBaseItemType(oItem); + // Declare major variables object oDisturber = GetLastDisturbed(); - int iType = GetInventoryDisturbType(); - string Middle; + object oItem = GetInventoryDisturbItem(); + int nType = GetInventoryDisturbType(); + int nBase = GetBaseItemType(oItem); + + // We will reset weapons if it is a weapon. // Reset weapons, or specifically healers kits. if(GetIsObjectValid(oItem)) { // Kits if(nBase == BASE_ITEM_HEALERSKIT) { - SetLocalInt(OBJECT_SELF, AI_WEAPONSETTING_SETWEAPONS, i2); + SetLocalInt(OBJECT_SELF, AI_WEAPONSETTING_SETWEAPONS, 2); ExecuteScript(FILE_RE_SET_WEAPONS, OBJECT_SELF); } else // Think it is a weapon. Saves time :-) { - SetLocalInt(OBJECT_SELF, AI_WEAPONSETTING_SETWEAPONS, i1); + SetLocalInt(OBJECT_SELF, AI_WEAPONSETTING_SETWEAPONS, 1); ExecuteScript(FILE_RE_SET_WEAPONS, OBJECT_SELF); } } // Fight! Or search! - if(GetIsObjectValid(oDisturber) && !GetIsDM(oDisturber) && !GetFactionEqual(oDisturber) && - (iType == INVENTORY_DISTURB_TYPE_STOLEN || GetIsEnemy(oDisturber))) + if(!GetIgnoreNoFriend(oDisturber) && + (nType == INVENTORY_DISTURB_TYPE_STOLEN || GetIsEnemy(oDisturber))) { // Turn of hiding, a timer to activate Hiding in the main file. This is // done in each of the events, with the opposition checking seen/heard. TurnOffHiding(oDisturber); + + // Can we attack? if(!CannotPerformCombatRound()) { - AISpeakString(CALL_TO_ARMS); + // Someone specific to attack + AISpeakString(AI_SHOUT_I_WAS_ATTACKED); + // One debug speak. We always do one. // 65: "[Disturbed] (pickpocket) Attacking Enemy Distrube [Disturber] " + GetName(oTarget) + " [Type] " + IntToString(iType) - DebugActionSpeakByInt(65, oDisturber, iType); + DebugActionSpeakByInt(65, oDisturber, nType); + + // Attack the disturber DetermineCombatRound(oDisturber); } + else + { + // Get allies interested. + AISpeakString(AI_SHOUT_CALL_TO_ARMS); + } } // Fire End-heartbeat-UDE diff --git a/_module/nss/nw_c2_default9.nss b/_module/nss/nw_c2_default9.nss index a114b004..522036b5 100644 --- a/_module/nss/nw_c2_default9.nss +++ b/_module/nss/nw_c2_default9.nss @@ -1,6 +1,6 @@ -/************************ [On Spawn] ******************************************* - Filename: j_ai_onspawn or nw_c2_default9 -************************* [On Spawn] ******************************************* +/*/////////////////////// [On Spawn] /////////////////////////////////////////// + Filename: J_AI_OnSpawn or nw_c2_default9 +///////////////////////// [On Spawn] /////////////////////////////////////////// This file contains options that will determine some AI behaviour, and a lot of toggles for turning things on/off. A big read, but might be worthwhile. @@ -28,18 +28,28 @@ - Targeting is imporant :-D - If you delete this script, there is a template for the On Spawn file in the zip it came in, for use in the "scripttemplate" directory. -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// Note: I have removed: - Default "Teleporting" and exit/return (this seemed bugged anyway, or useless) - Spawn in animation. This can be, of course, re-added. - Day/night posting. This is uneeded, with a changed walk waypoints that does it automatically. - Changes from 1.0-1.2: - - All constants names are changed, I am afraid. - - Added Set/Delete/GetAIInteger/Constant/Object. This makes sure that the AI - doesn't ever interfere with other things - it pre-fixes all stored things - with AI_INTEGER_ (and so on) -************************* [Workings] ******************************************* + 1.0-1.2 - Used short amount of spawn options. + 1.3 - All constants names are changed, I am afraid. + - Added Set/Delete/GetAIInteger/Constant/Object. This makes sure that the AI + doesn't ever interfere with other things - it pre-fixes all stored things + with AI_INTEGER_ (and so on) + 1.4 - TO DO: Clear up some old non-working ones + - Added in User Defined part of the script, an auto-turn-off-spells for + Ranger and Paladin classes. Need to test - perhaps 1.64 fixed it? + + + Spawn options changed: + - Removed AI level settings (can still be done manually) + - Added optional (and off by default) fear-visual for fleeing + + +///////////////////////// [Workings] /////////////////////////////////////////// Note: You can do without all the comments (it may be that you don't want the extra KB it adds or something, although it does not at all slow down a module) so as long as you have these at the end: @@ -50,9 +60,9 @@ Oh, and the include file (Below, "j_inc_spawnin") must be at the top like here. Also recommended is the AI_INTELLIGENCE and AI_MORALE being set (if not using custom AI). -************************* [Arguments] ****************************************** +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: GetIsEncounterCreature -************************* [On Spawn] ******************************************/ +///////////////////////// [On Spawn] /////////////////////////////////////////*/ // Treasure Includes - See end of spawn for uncomment options. @@ -65,7 +75,7 @@ // - This will spawn treasure based on chests placed in the module. See "x0_i0_treasure" for more information. // This is required for all spawn in options! -#include "j_inc_spawnin" +#include "J_INC_SPAWNIN" void main() { @@ -116,13 +126,13 @@ void main() // - Remember, uncommenting one will just ignore it (so will never check target's // AC without TARGETING_AC on) - AI_SetAITargetingValues(TARGETING_MANTALS, TARGET_LOWER, i1, i12); + AI_SetAITargetingValues(TARGETING_MANTALS, TARGET_LOWER, 1, 12); // Spell mantals are checked only for the spell target. Either Absense of or got any. - AI_SetAITargetingValues(TARGETING_RANGE, TARGET_HIGHER, i2, i9); + AI_SetAITargetingValues(TARGETING_RANGE, TARGET_HIGHER, 2, 9); // Range - very imporant! Basis for all ranged/spell attacks. - AI_SetAITargetingValues(TARGETING_AC, TARGET_LOWER, i2, i6); + AI_SetAITargetingValues(TARGETING_AC, TARGET_LOWER, 2, 6); // AC is used for all phisical attacks. Lower targets lower (By default). - AI_SetAITargetingValues(TARGETING_SAVES, TARGET_LOWER, i2, i4); + AI_SetAITargetingValues(TARGETING_SAVES, TARGET_LOWER, 2, 4); // Used for spell attacks. Saves are sorta a AC versus spells. // Phisical protections. Used by spells, ranged and melee. @@ -131,22 +141,22 @@ void main() if(GetBaseAttackBonus(OBJECT_SELF) > ((GetHitDice(OBJECT_SELF)/2) + 1)) { // Fighter/Clerics (It is over a mages BAB + 1 (IE 0.5 BAB/Level) target lower - AI_SetAITargetingValues(TARGETING_PHISICALS, TARGET_LOWER, i2, i6); + AI_SetAITargetingValues(TARGETING_PHISICALS, TARGET_LOWER, 2, 6); } else { // Mages target higher (so dispel/elemental attack those who fighters // cannot hit as much). (the lowest BAB, under half our hit dice in BAB) - AI_SetAITargetingValues(TARGETING_PHISICALS, TARGET_HIGHER, i1, i5); + AI_SetAITargetingValues(TARGETING_PHISICALS, TARGET_HIGHER, 1, 5); } // Base attack bonus. Used for spells and phisical attacks. Checked with GetBaseAttackBonus. - AI_SetAITargetingValues(TARGETING_BAB, TARGET_LOWER, i1, i4); + AI_SetAITargetingValues(TARGETING_BAB, TARGET_LOWER, 1, 4); // Hit dice - how powerful in levels the enemy is. Used for all checks. - AI_SetAITargetingValues(TARGETING_HITDICE, TARGET_LOWER, i1, i3); + AI_SetAITargetingValues(TARGETING_HITDICE, TARGET_LOWER, 1, 3); - //AI_SetAITargetingValues(TARGETING_HP_PERCENT, TARGET_LOWER, i1, i3); - //AI_SetAITargetingValues(TARGETING_HP_CURRENT, TARGET_LOWER, i1, i3); - //AI_SetAITargetingValues(TARGETING_HP_MAXIMUM, TARGET_LOWER, i1, i3); + //AI_SetAITargetingValues(TARGETING_HP_PERCENT, TARGET_LOWER, 1, 3); + //AI_SetAITargetingValues(TARGETING_HP_CURRENT, TARGET_LOWER, 1, 3); + //AI_SetAITargetingValues(TARGETING_HP_MAXIMUM, TARGET_LOWER, 1, 3); // The HP's are the last thing to choose a target with. /************************ [Targeting] *****************************************/ @@ -185,6 +195,9 @@ void main() // They will flee to the nearest object of the tag below, if set. //SetLocalString(OBJECT_SELF, AI_FLEE_OBJECT, "BOSS_TAG_OR_WHATEVER"); // This needs setting if the above is to work. + + //SetSpawnInCondition(AI_FLAG_FLEEING_USE_VISUAL_EFFECT, AI_TARGETING_FLEE_MASTER); + // If this is on, we play a visual effect while we flee. /************************ [Fleeing] *******************************************/ /************************ [Combat - Fighters] ********************************** @@ -456,15 +469,6 @@ void main() //SetSpawnInCondition(AI_FLAG_OTHER_LAG_TARGET_NEAREST_ENEMY, AI_OTHER_MASTER); // Ignores targeting settings. VERY good for lag/bad AI. Attacks nearest seen enemy. - /*** AI Level setting - Do not use AI_LEVEL_DEFAULT at all. ***/ - - //SetAIConstant(LAG_AI_LEVEL_NO_PC_OR_ENEMY_50M, AI_LEVEL_VERY_LOW); - // Changes to this AI setting if there is no enemy or PC in 50M. - //SetAIConstant(LAG_AI_LEVEL_YES_PC_OR_ENEMY_50M, AI_LEVEL_LOW); - // Changes to this AI setting if there IS an enemy or PC in 50M. - //SetAIConstant(LAG_AI_LEVEL_COMBAT, AI_LEVEL_NORMAL); - // This OVERRIDES others. Only used when a creature is put into combat. - /************************ [Other - Behaviour/Generic] *************************/ /************************ [User Defined and Shouts] **************************** @@ -475,6 +479,10 @@ void main() (User Defined Event = UDE) ************************* [User Defined and Shouts] ***************************/ + // This is REQUIRED if we use any Pre-events. If not there, it will default + // to the default User Defined Event script for the default AI. + SetCustomUDEFileName("k_ai_onuserdef"); + //SetSpawnInCondition(AI_FLAG_UDE_HEARTBEAT_EVENT, AI_UDE_MASTER); // UDE 1001 //SetSpawnInCondition(AI_FLAG_UDE_HEARTBEAT_PRE_EVENT, AI_UDE_MASTER); // UDE 1021 //SetSpawnInCondition(AI_FLAG_UDE_PERCIEVE_EVENT, AI_UDE_MASTER); // UDE 1002 @@ -549,6 +557,9 @@ void main() // This will be said when the leader, if this creature, sends a runner. //AI_SetSpawnInSpeakValue(AI_TALK_ON_LEADER_ATTACK_TARGET, "Help attack this target!"); // When the leader thinks target X should be attacked, it will say this. + //AI_SetSpawnInSpeakValue(AI_TALK_ON_LEADER_BOSS_SHOUT, "Come my minions! To battle!"); + // This will be said when the leader, if this creature, sees an enemy and uses his "Boss Monster Shout", if turned on. + /************************ [User Defined and Shouts] ***************************/ @@ -616,10 +627,18 @@ void main() SetBaseAttackBonus(nNumber); } + // If we are a ranger or paladin class, do not cast spells. This can be + // manually removed if wished. To get the spells they have working correctly, + // remove this, and use Monster Abilties instead of thier normal class spells. +// if(GetLevelByClass(CLASS_TYPE_RANGER) >= 1 || GetLevelByClass(CLASS_TYPE_PALADIN) >= 1) +// { +// SetSpawnInCondition(AI_FLAG_OTHER_LAG_NO_SPELLS, AI_OTHER_MASTER); +// } + /************************ [User] **********************************************/ // Note: You shouldn't really remove this, even if they have no waypoints. - DelayCommand(f2, SpawnWalkWayPoints()); + DelayCommand(2.0, SpawnWalkWayPoints()); // Delayed walk waypoints, as to not upset instant combat spawning. // This will also check if to change to day/night posts during the walking, no heartbeats. } diff --git a/_module/nss/nw_c2_defaulta.nss b/_module/nss/nw_c2_defaulta.nss index c3f9164e..42015fd0 100644 --- a/_module/nss/nw_c2_defaulta.nss +++ b/_module/nss/nw_c2_defaulta.nss @@ -1,35 +1,43 @@ -/************************ [On Rested] ****************************************** - Filename: j_ai_onrest or nw_c2_defaulta -************************* [On Rested] ****************************************** +/*/////////////////////// [On Rested] ////////////////////////////////////////// + Filename: J_AI_OnRest or nw_c2_defaulta +///////////////////////// [On Rested] ////////////////////////////////////////// This will play the sitting animation for 6 seconds, just something for resting. Also, walks waypoints (as resting would stop this) :-) and signals event (if so be) Feel free to edit. It does have the spell trigger information resetting, however. This can only be removed if they have no spell triggers, although it is hardly worth it. -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.3 - Added sitting. -************************* [Workings] ******************************************* + 1.4 - Will be editing this down. No need to reset anything on rest, for a + better working AI. + IDEA: Change so that we will work through all spells/feats in order. + If, at cirtain levels, we do not have any spells to cast from that + level (set in a global stored integer in the general AI) we ignore all + spells in that level. Same for each talent category (no need to use + talents for them in the spawn script). + + If not in combat (EG: In heartbeat) we reset the integers saying "don't + bother checking those spells" to false. +///////////////////////// [Workings] /////////////////////////////////////////// This fires once, at the END of resting. If ClearAllActions is added, the resting is actually stopped, or so it seems. It doesn't fire more then once. -************************* [Arguments] ****************************************** +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: None, it seems. -************************* [On Rested] *****************************************/ +///////////////////////// [On Rested] ////////////////////////////////////////*/ -#include "j_inc_constants" +#include "J_INC_CONSTANTS" // Resets all spell triggers used for sString void LoopResetTriggers(string sString, object oTrigger); void main() { - // Pre-heartbeat-event - if(FireUserEvent(AI_FLAG_UDE_RESTED_PRE_EVENT, EVENT_RESTED_PRE_EVENT)) - // We may exit if it fires - if(ExitFromUDE(EVENT_RESTED_PRE_EVENT)) return; + // Pre-rest-event. Returns TRUE if we interrupt this script call. + if(FirePreUserEvent(AI_FLAG_UDE_RESTED_PRE_EVENT, EVENT_RESTED_PRE_EVENT)) return; // AI status check. Is the AI on? if(GetAIOff()) return; @@ -49,8 +57,8 @@ void main() LoopResetTriggers(SPELLTRIGGER_START_OF_COMBAT, oTrigger); } // Some sitting for a few seconds. - ActionPlayAnimation(ANIMATION_LOOPING_SIT_CROSS, f1, f6); - DelayCommand(f9, ExecuteScript(FILE_WALK_WAYPOINTS, OBJECT_SELF)); + ActionPlayAnimation(ANIMATION_LOOPING_SIT_CROSS, 1.0, 6.0); + DelayCommand(9.0, ExecuteScript(FILE_WALK_WAYPOINTS, OBJECT_SELF)); // Fire End-heartbeat-UDE FireUserEvent(AI_FLAG_UDE_RESTED_EVENT, EVENT_RESTED_EVENT); @@ -59,18 +67,18 @@ void main() // Resets all spell triggers used for sString void LoopResetTriggers(string sString, object oTrigger) { - int iCnt, iBreak, iUsed; - for(iCnt = i1; iBreak != TRUE; iCnt++) + int nCnt, bBreak, bUsed; + for(nCnt = 1; bBreak != TRUE; nCnt++) { // Check max for this setting - iUsed = GetLocalInt(oTrigger, sString + USED); - if(iUsed) + bUsed = GetLocalInt(oTrigger, sString + USED); + if(bUsed) { DeleteLocalInt(oTrigger, sString + USED); } else { - iBreak = TRUE; + bBreak = TRUE; } } } diff --git a/_module/nss/nw_c2_defaultb.nss b/_module/nss/nw_c2_defaultb.nss index eb142e27..6bee0e66 100644 --- a/_module/nss/nw_c2_defaultb.nss +++ b/_module/nss/nw_c2_defaultb.nss @@ -1,29 +1,30 @@ -/************************ [On Spell Cast At] *********************************** +/*/////////////////////// [On Spell Cast At] /////////////////////////////////// Filename: j_ai_onspellcast or nw_c2_defaultb -************************* [On Spell Cast At] *********************************** +///////////////////////// [On Spell Cast At] /////////////////////////////////// What does this do? Well... - Any AOE spell effects are set in a timer, so we can react to them right - Reacts to hostile casters, or allies in combat And the normal attack :-) -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.3 - Added special AOE checks. - Hide checks. -************************* [Workings] ******************************************* + 1.4 - Added more silent shouts. Edited the formatting. Moved a few things around. +///////////////////////// [Workings] /////////////////////////////////////////// This is fired when EventSpellCastAt(object oCaster, int nSpell, int bHarmful=TRUE) is signaled on the creature. GetLastSpellCaster() = oCaster (Door, Placeable, Creature who cast it) GetLastSpell() = nSpell (The spell cast at us) GetLastSpellHarmful()= bHarmful (If it is harmful!) -************************* [Arguments] ****************************************** +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: GetLastSpellCaster, GetLastSpellHarmful GetLastSpell() -************************* [On Spell Cast At] **********************************/ +///////////////////////// [On Spell Cast At] /////////////////////////////////*/ -#include "j_inc_other_ai" +#include "J_INC_OTHER_AI" // Sets a local timer if the spell is an AOE one -void SetAOESpell(int iSpellCast, object oCaster); +void SetAOESpell(int nSpellCast, object oCaster); // Gets the nearest AOE cast by oCaster, of sTag. object GetNearestAOECastBy(string sTag, object oCaster); // Gets the amount of protections we have - IE globes @@ -31,67 +32,49 @@ int GetOurSpellLevelImmunity(); void main() { - // Pre-heartbeat-event - if(FireUserEvent(AI_FLAG_UDE_SPELL_CAST_AT_PRE_EVENT, EVENT_SPELL_CAST_AT_PRE_EVENT)) - // We may exit if it fires - if(ExitFromUDE(EVENT_SPELL_CAST_AT_PRE_EVENT)) return; + // Pre-spell cast at-event. Returns TRUE if we interrupt this script call. + if(FirePreUserEvent(AI_FLAG_UDE_SPELL_CAST_AT_PRE_EVENT, EVENT_SPELL_CAST_AT_PRE_EVENT)) return; // AI status check. Is the AI on? if(GetAIOff()) return; object oCaster = GetLastSpellCaster(); - int iHarmful = GetLastSpellHarmful(); - int iSpellCast = GetLastSpell(); + int bHarmful = GetLastSpellHarmful(); + int nSpellCast = GetLastSpell(); object oAttackerOfCaster; // If harmful, we set the spell to a timer, if an AOE one. - if(iHarmful && GetIsObjectValid(oCaster)) + if(bHarmful && GetIsObjectValid(oCaster)) { // Might set AOE spell to cast. - SetAOESpell(iSpellCast, oCaster); + SetAOESpell(nSpellCast, oCaster); } // If not a creature, probably an AOE or trap. if(GetObjectType(oCaster) != OBJECT_TYPE_CREATURE) { // 67: "[Spell] Caster isn't a creature! May look for target [Caster] " + GetName(oCaster) DebugActionSpeakByInt(67, oCaster); + + // Shout to allies to attack, or be prepared. + AISpeakString(AI_SHOUT_CALL_TO_ARMS); + // Attack anyone else around if(!CannotPerformCombatRound()) { + // Determine Combat Round DetermineCombatRound(); } } - else if(GetIsObjectValid(oCaster) && !GetIsDM(oCaster) && - !GetIgnore(oCaster) && oCaster != OBJECT_SELF && !GetIsDead(oCaster)) + // If a friend, or dead, or a DM, or invalid, or self, we ignore them. + else if(!GetIgnoreNoFriend(oCaster) && oCaster != OBJECT_SELF) { // 1.3 changes here: // - We do NOT need to know if it is hostile or not, except if it is hostile - // and they are not our faction! We do, however, use iHarmful for speakstrings. - if(!GetFactionEqual(oCaster)) - { - // If harmful, we attack anyone! (and if is enemy) - if(iHarmful || GetIsEnemy(oCaster)) - { - if(iHarmful) - { - // Hostile spell speaksting, if set. - SpeakArrayString(AI_TALK_ON_HOSTILE_SPELL_CAST_AT); - } - // Turn of hiding check - TurnOffHiding(oCaster); - // Attack - AISpeakString(I_WAS_ATTACKED); - // We attack - if(!CannotPerformCombatRound()) - { - // 68: "[Spell:Enemy/Hostile] Not in combat. Attacking: [Caster] " + GetName(oCaster) - DebugActionSpeakByInt(68, oCaster); - DetermineCombatRound(oCaster); - } - } - } - // Else, faction is equal, we normally ignore, and only move to attack. - else + // and they are not our faction! We do, however, use bHarmful for speakstrings. + + // If harmful, we attack anyone! (and if is enemy) + // 1.4: Faction equal check in GetIgnoreNoFriend() + if(bHarmful || GetIsEnemy(oCaster)) { // Spawn in condition hostile thingy if(GetSpawnInCondition(AI_FLAG_OTHER_CHANGE_FACTIONS_TO_HOSTILE_ON_ATTACK, AI_OTHER_MASTER)) @@ -101,43 +84,74 @@ void main() AdjustReputation(oCaster, OBJECT_SELF, -100); } } - // We move to the person, if they are attacking something we cannot see... - AISpeakString(CALL_TO_ARMS); - // Not in combat + if(bHarmful) + { + // * Don't speak when dead. 1.4 change (an obvious one to make) + if(CanSpeak()) + { + // Hostile spell speaksting, if set. + SpeakArrayString(AI_TALK_ON_HOSTILE_SPELL_CAST_AT); + } + } + + // Turn of hiding check + TurnOffHiding(oCaster); + + // We attack if(!CannotPerformCombatRound()) { - // 69: "[Spell] (ally). Not in combat. May Attack/Move [Caster] " + GetName(oCaster) - DebugActionSpeakByInt(69, oCaster); - ClearAllActions(); - // Check thier target. Might not be valid (IE AOE spell at location) - oAttackerOfCaster = GetAttackTarget(oCaster); - // - Faster then DetermineCombatRound(); and looping targets until - // we get this ally, and get this attacker! :-) - if(GetIsObjectValid(oAttackerOfCaster)) + // 68: "[Spell:Enemy/Hostile] Not in combat. Attacking: [Caster] " + GetName(oCaster) + DebugActionSpeakByInt(68, oCaster); + DetermineCombatRound(oCaster); + } + + // Shout to allies to attack the enemy who attacked me, got via. Last Hostile Actor. + AISpeakString(AI_SHOUT_I_WAS_ATTACKED); + } + // Else, was neutral perhaps. Don't attack them anyway. + else + { + // 69: "[Spell] (ally). Not in combat. May Attack/Move [Caster] " + GetName(oCaster) + DebugActionSpeakByInt(69, oCaster); + + // Set special action to investigate - as if this event was triggered + // by I_WAS_ATTACKED. + + // If we are already attacking, we do not move + if(CannotPerformCombatRound()) + { + // Shout to allies to attack, or be prepared. + AISpeakString(AI_SHOUT_CALL_TO_ARMS); + } + else + { + // We react as if the caster, a neutral, called for help ala + // I_WAS_ATTACKED (they might not have, might just be + // preperation for something), but normally, this is a neutral + // casting a spell. Do not respond to PC's. + if(!GetIsPC(oCaster)) { - // Move to the attack target, and wait for a proper on - // perception event (as we are not currently in combat) - ActionMoveToObject(oCaster, TRUE); - } - else - { - // Move to the caster otherwise - ActionMoveToObject(oCaster, TRUE); + IWasAttackedResponse(oCaster); } } } } + // If they are not a faction equal, and valid, we help them. + else if(GetIsObjectValid(oCaster) && GetFactionEqual(oCaster)) + { + IWasAttackedResponse(oCaster); + } // Fire End-spell cast at-UDE FireUserEvent(AI_FLAG_UDE_SPELL_CAST_AT_EVENT, EVENT_SPELL_CAST_AT_EVENT); } // Sets a local timer if the spell is an AOE one -void SetAOESpell(int iSpellCast, object oCaster) +void SetAOESpell(int nSpellCast, object oCaster) { // Check it is one we can check - int iImmuneLevel = GetOurSpellLevelImmunity(); - switch(iSpellCast) + int bStop = TRUE; + switch(nSpellCast) { case SPELL_ACID_FOG: case SPELL_MIND_FOG: @@ -159,81 +173,82 @@ void SetAOESpell(int iSpellCast, object oCaster) case SPELL_VINE_MINE_HAMPER_MOVEMENT: case SPELL_VINE_MINE_ENTANGLE: { - // Pass though, unless we are totally immune. - if(iImmuneLevel >= i9) - { - return; - } - } - break; - // Any other spell - default: - { - return; + bStop = FALSE; } break; } + // Check immune level + int nImmuneLevel = GetOurSpellLevelImmunity(); + if(nImmuneLevel >= 9) + { + bStop = TRUE; + } + // Check + if(bStop == TRUE) + { + return; + } // We do use intelligence here... - int iAIInt = GetBoundriedAIInteger(AI_INTELLIGENCE); - int iIgnoreSaves; - int iIgnoreImmunities; + int nAIInt = GetBoundriedAIInteger(AI_INTELLIGENCE); + int bIgnoreSaves; + int bIgnoreImmunities; object oAOE; // If it is low, we ignore all things that we could ignore with it... - if(iAIInt <= i3) + if(nAIInt <= 3) { - iIgnoreSaves = TRUE; - iIgnoreImmunities = TRUE; + bIgnoreSaves = TRUE; + bIgnoreImmunities = TRUE; } // Average ignores saves - else if(iAIInt <= i7) + else if(nAIInt <= 7) { - iIgnoreSaves = TRUE; - iIgnoreImmunities = FALSE; + bIgnoreSaves = TRUE; + bIgnoreImmunities = FALSE; } // Else, we do both. else { - iIgnoreSaves = FALSE; - iIgnoreImmunities = FALSE; + bIgnoreSaves = FALSE; + bIgnoreImmunities = FALSE; } - int SetAOE = FALSE;// TRUE means set to timer - int iSaveDC = i11; + int bSetAOE = FALSE;// TRUE means set to timer + int nSaveDC = 11; // Get the caster DC, the most out of WIS, INT or CHA... - int iInt = GetAbilityModifier(ABILITY_INTELLIGENCE, oCaster); - int iWis = GetAbilityModifier(ABILITY_WISDOM, oCaster); - int iCha = GetAbilityModifier(ABILITY_CHARISMA, oCaster); + int nInt = GetAbilityModifier(ABILITY_INTELLIGENCE, oCaster); + int nWis = GetAbilityModifier(ABILITY_WISDOM, oCaster); + int nCha = GetAbilityModifier(ABILITY_CHARISMA, oCaster); - if(iInt > iWis && iInt > iCha) + if(nInt > nWis && nInt > nCha) { - iSaveDC += iInt; + nSaveDC += nInt; } - else if(iWis > iCha) + else if(nWis > nCha) { - iSaveDC += iWis; + nSaveDC += nWis; } else { - iSaveDC += iCha; + nSaveDC += nCha; } // Note: // - No reaction type/friendly checks. Signal Event is only fired if the // spell WILL pierce any PvP/Friendly/Area settings // We check immunities here, please note... - switch(iSpellCast) + switch(nSpellCast) { // First: IS GetIsReactionTypeHostile ones. case SPELL_EVARDS_BLACK_TENTACLES: // Fortitude save, but if we are immune to the hits, its impossible to hurt us { // If save immune OR AC immune, we ignore this. - if(i25 >= GetAC(OBJECT_SELF) && iImmuneLevel < i4 && - ((GetFortitudeSavingThrow(OBJECT_SELF) < iSaveDC + i2) || iIgnoreSaves)) + if(25 >= GetAC(OBJECT_SELF) && nImmuneLevel < 4 && + ((GetFortitudeSavingThrow(OBJECT_SELF) < nSaveDC + 2) || bIgnoreSaves)) { - SetAOE = TRUE; + bSetAOE = TRUE; // Nearest string of tag oAOE = GetNearestAOECastBy(AI_AOE_PER_EVARDS_BLACK_TENTACLES, oCaster); } @@ -243,11 +258,11 @@ void SetAOESpell(int iSpellCast, object oCaster) // d4 damage. LOTS of speed loss. // Reflex save, or immunity, would stop the speed { - if(iImmuneLevel < i3 && - (!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_MOVEMENT_SPEED_DECREASE) || iIgnoreImmunities) && - ((GetReflexSavingThrow(OBJECT_SELF) < iSaveDC + i5) || iIgnoreSaves)) + if(nImmuneLevel < 3 && + (!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_MOVEMENT_SPEED_DECREASE) || bIgnoreImmunities) && + ((GetReflexSavingThrow(OBJECT_SELF) < nSaveDC + 5) || bIgnoreSaves)) { - SetAOE = TRUE; + bSetAOE = TRUE; // Both use ENTANGLE AOE's oAOE = GetNearestAOECastBy(AI_AOE_PER_ENTANGLE, oCaster); } @@ -256,12 +271,12 @@ void SetAOESpell(int iSpellCast, object oCaster) case SPELL_ENTANGLE: case SPELL_VINE_MINE_ENTANGLE: { - if(iImmuneLevel < i1 && - (!GetHasFeat(FEAT_WOODLAND_STRIDE) || iIgnoreImmunities) && - (!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_ENTANGLE) || iIgnoreImmunities) && - ((GetReflexSavingThrow(OBJECT_SELF) < iSaveDC + i4) || iIgnoreSaves)) + if(nImmuneLevel < 1 && + (!GetHasFeat(FEAT_WOODLAND_STRIDE) || bIgnoreImmunities) && + (!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_ENTANGLE) || bIgnoreImmunities) && + ((GetReflexSavingThrow(OBJECT_SELF) < nSaveDC + 4) || bIgnoreSaves)) { - SetAOE = TRUE; + bSetAOE = TRUE; // Both use ENTANGLE AOE's oAOE = GetNearestAOECastBy(AI_AOE_PER_ENTANGLE, oCaster); } @@ -269,12 +284,12 @@ void SetAOESpell(int iSpellCast, object oCaster) break; case SPELL_WEB: { - if(iImmuneLevel < i1 && - (!GetHasFeat(FEAT_WOODLAND_STRIDE) || iIgnoreImmunities) && - (!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_ENTANGLE) || iIgnoreImmunities) && - ((GetReflexSavingThrow(OBJECT_SELF) < iSaveDC + i4) || iIgnoreSaves)) + if(nImmuneLevel < 1 && + (!GetHasFeat(FEAT_WOODLAND_STRIDE) || bIgnoreImmunities) && + (!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_ENTANGLE) || bIgnoreImmunities) && + ((GetReflexSavingThrow(OBJECT_SELF) < nSaveDC + 4) || bIgnoreSaves)) { - SetAOE = TRUE; + bSetAOE = TRUE; // Web AOE oAOE = GetNearestAOECastBy(AI_AOE_PER_WEB, oCaster); } @@ -283,12 +298,12 @@ void SetAOESpell(int iSpellCast, object oCaster) // Fort save case SPELL_STINKING_CLOUD: { - if(iImmuneLevel < i3 && - (!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_POISON) || iIgnoreImmunities) && - (!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_DAZED) || iIgnoreImmunities) && - ((GetFortitudeSavingThrow(OBJECT_SELF) < iSaveDC + i6) || iIgnoreSaves)) + if(nImmuneLevel < 3 && + (!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_POISON) || bIgnoreImmunities) && + (!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_DAZED) || bIgnoreImmunities) && + ((GetFortitudeSavingThrow(OBJECT_SELF) < nSaveDC + 6) || bIgnoreSaves)) { - SetAOE = TRUE; + bSetAOE = TRUE; // Stinking cloud persistant AOE. oAOE = GetNearestAOECastBy(AI_AOE_PER_FOGSTINK, oCaster); } @@ -297,10 +312,10 @@ void SetAOESpell(int iSpellCast, object oCaster) // Fort save case SPELL_CLOUD_OF_BEWILDERMENT: { - if(iImmuneLevel < i2 && - ((GetFortitudeSavingThrow(OBJECT_SELF) < iSaveDC + i7) || iIgnoreSaves)) + if(nImmuneLevel < 2 && + ((GetFortitudeSavingThrow(OBJECT_SELF) < nSaveDC + 7) || bIgnoreSaves)) { - SetAOE = TRUE; + bSetAOE = TRUE; // Bewilderment cloud persistant AOE. oAOE = GetNearestAOECastBy(AI_AOE_PER_FOGBEWILDERMENT, oCaster); } @@ -309,11 +324,11 @@ void SetAOESpell(int iSpellCast, object oCaster) // Special: Mind save is the effect. case SPELL_STONEHOLD: { - if(iImmuneLevel < i6 && - (!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_MIND_SPELLS) || iIgnoreImmunities) && - ((GetWillSavingThrow(OBJECT_SELF) < iSaveDC + i7) || iIgnoreSaves)) + if(nImmuneLevel < 6 && + (!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_MIND_SPELLS) || bIgnoreImmunities) && + ((GetWillSavingThrow(OBJECT_SELF) < nSaveDC + 7) || bIgnoreSaves)) { - SetAOE = TRUE; + bSetAOE = TRUE; // Stonehold persistant AOE. oAOE = GetNearestAOECastBy(AI_AOE_PER_STONEHOLD, oCaster); } @@ -322,11 +337,11 @@ void SetAOESpell(int iSpellCast, object oCaster) // Special: EFFECT_TYPE_SAVING_THROW_DECREASE is the effect. case SPELL_MIND_FOG: { - if(iImmuneLevel < i5 && - (!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_SAVING_THROW_DECREASE) || iIgnoreImmunities) && - ((GetWillSavingThrow(OBJECT_SELF) < iSaveDC + i6) || iIgnoreSaves)) + if(nImmuneLevel < 5 && + (!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_SAVING_THROW_DECREASE) || bIgnoreImmunities) && + ((GetWillSavingThrow(OBJECT_SELF) < nSaveDC + 6) || bIgnoreSaves)) { - SetAOE = TRUE; + bSetAOE = TRUE; // Mind fog oAOE = GetNearestAOECastBy(AI_AOE_PER_FOGMIND, oCaster); } @@ -335,12 +350,12 @@ void SetAOESpell(int iSpellCast, object oCaster) // Special: Feats, knockdown case SPELL_GREASE: { - if(iImmuneLevel < i1 && - (!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_KNOCKDOWN) || iIgnoreImmunities) && - (!GetHasFeat(FEAT_WOODLAND_STRIDE, OBJECT_SELF) || iIgnoreImmunities) && - ((GetReflexSavingThrow(OBJECT_SELF) < iSaveDC + i2) || iIgnoreSaves)) + if(nImmuneLevel < 1 && + (!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_KNOCKDOWN) || bIgnoreImmunities) && + (!GetHasFeat(FEAT_WOODLAND_STRIDE, OBJECT_SELF) || bIgnoreImmunities) && + ((GetReflexSavingThrow(OBJECT_SELF) < nSaveDC + 2) || bIgnoreSaves)) { - SetAOE = TRUE; + bSetAOE = TRUE; // Grease oAOE = GetNearestAOECastBy(AI_AOE_PER_GREASE, oCaster); } @@ -351,23 +366,23 @@ void SetAOESpell(int iSpellCast, object oCaster) case SPELL_INCENDIARY_CLOUD:// reflex case SPELL_WALL_OF_FIRE:// Reflex { - if(iImmuneLevel < i6 && - (((GetReflexSavingThrow(OBJECT_SELF) < iSaveDC + i6) && + if(nImmuneLevel < 6 && + (((GetReflexSavingThrow(OBJECT_SELF) < nSaveDC + 6) && !GetHasFeat(FEAT_IMPROVED_EVASION) && - !GetHasFeat(FEAT_EVASION)) || iIgnoreSaves)) + !GetHasFeat(FEAT_EVASION)) || bIgnoreSaves)) { - SetAOE = TRUE; - if(iSpellCast == SPELL_BLADE_BARRIER) + bSetAOE = TRUE; + if(nSpellCast == SPELL_BLADE_BARRIER) { // BB oAOE = GetNearestAOECastBy(AI_AOE_PER_WALLBLADE, oCaster); } - else if(iSpellCast == SPELL_INCENDIARY_CLOUD) + else if(nSpellCast == SPELL_INCENDIARY_CLOUD) { // Fog of fire oAOE = GetNearestAOECastBy(AI_AOE_PER_FOGFIRE, oCaster); } - else if(iSpellCast == SPELL_WALL_OF_FIRE) + else if(nSpellCast == SPELL_WALL_OF_FIRE) { // Wall of fire oAOE = GetNearestAOECastBy(AI_AOE_PER_WALLFIRE, oCaster); @@ -379,20 +394,20 @@ void SetAOESpell(int iSpellCast, object oCaster) case SPELL_CLOUDKILL:// No save! case SPELL_CREEPING_DOOM: // No save! { - if(iImmuneLevel < i6) + if(nImmuneLevel < 6) { - SetAOE = TRUE; - if(iSpellCast == SPELL_ACID_FOG) + bSetAOE = TRUE; + if(nSpellCast == SPELL_ACID_FOG) { // Acid fog oAOE = GetNearestAOECastBy(AI_AOE_PER_FOGACID, oCaster); } - else if(iSpellCast == SPELL_CLOUDKILL) + else if(nSpellCast == SPELL_CLOUDKILL) { // Cloud Kill oAOE = GetNearestAOECastBy(AI_AOE_PER_FOGKILL, oCaster); } - else if(iSpellCast == SPELL_CREEPING_DOOM) + else if(nSpellCast == SPELL_CREEPING_DOOM) { // Creeping doom oAOE = GetNearestAOECastBy(AI_AOE_PER_CREEPING_DOOM, oCaster); @@ -402,28 +417,28 @@ void SetAOESpell(int iSpellCast, object oCaster) // Storm - because the AI likes it, we stay in it if it is ours :-) case SPELL_STORM_OF_VENGEANCE: // Reflex partial. No check, always damages. { - if(oCaster != OBJECT_SELF && iImmuneLevel < i9) + if(oCaster != OBJECT_SELF && nImmuneLevel < 9) { - SetAOE = TRUE; + bSetAOE = TRUE; // Storm of vengance oAOE = GetNearestAOECastBy(AI_AOE_PER_STORM, oCaster); } } } - if(SetAOE) + if(bSetAOE) { - if(!GetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(iSpellCast))) + if(!GetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(nSpellCast))) { - SetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(iSpellCast), f18); + SetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(nSpellCast), 18.0); // Set nearest AOE if(GetIsObjectValid(oAOE)) { // Set nearest AOE of this spell to the local - object oNearest = GetAIObject(AI_TIMER_AOE_SPELL_EVENT + IntToString(iSpellCast)); + object oNearest = GetAIObject(AI_TIMER_AOE_SPELL_EVENT + IntToString(nSpellCast)); if(GetDistanceToObject(oAOE) < GetDistanceToObject(oNearest) || !GetIsObjectValid(oNearest)) { - SetAIObject(AI_TIMER_AOE_SPELL_EVENT + IntToString(iSpellCast), oAOE); + SetAIObject(AI_TIMER_AOE_SPELL_EVENT + IntToString(nSpellCast), oAOE); } } } @@ -432,8 +447,8 @@ void SetAOESpell(int iSpellCast, object oCaster) // Gets the nearest AOE cast by oCaster, of sTag. object GetNearestAOECastBy(string sTag, object oCaster) { - int iCnt = i1; - object oAOE = GetNearestObjectByTag(sTag, OBJECT_SELF, iCnt); + int nCnt = 1; + object oAOE = GetNearestObjectByTag(sTag, OBJECT_SELF, nCnt); object oReturn = OBJECT_INVALID; // Loop while(GetIsObjectValid(oAOE) && !GetIsObjectValid(oReturn)) @@ -443,8 +458,8 @@ object GetNearestAOECastBy(string sTag, object oCaster) { oReturn = oAOE; } - iCnt++; - oAOE = GetNearestObjectByTag(sTag, OBJECT_SELF, iCnt); + nCnt++; + oAOE = GetNearestObjectByTag(sTag, OBJECT_SELF, nCnt); } return oReturn; } @@ -452,27 +467,27 @@ object GetNearestAOECastBy(string sTag, object oCaster) // Gets the amount of protections we have - IE globes int GetOurSpellLevelImmunity() { - int iNatural = GetLocalInt(OBJECT_SELF, AI_SPELL_IMMUNE_LEVEL); + int nNatural = GetLocalInt(OBJECT_SELF, AI_SPELL_IMMUNE_LEVEL); // Stop here, if natural is over 4 - if(iNatural > i4) return iNatural; + if(nNatural > 4) return nNatural; // Big globe affects 4 or lower spells - if(GetHasSpellEffect(SPELL_GLOBE_OF_INVULNERABILITY, OBJECT_SELF) || iNatural >= i4) - return i4; + if(GetHasSpellEffect(SPELL_GLOBE_OF_INVULNERABILITY, OBJECT_SELF) || nNatural >= 4) + return 4; // Minor globe is 3 or under if(GetHasSpellEffect(SPELL_MINOR_GLOBE_OF_INVULNERABILITY, OBJECT_SELF) || // Shadow con version GetHasSpellEffect(SPELL_GREATER_SHADOW_CONJURATION_MINOR_GLOBE, OBJECT_SELF) || - iNatural >= i3) - return i3; + nNatural >= 3) + return 3; // 2 and under is ethereal visage. - if(GetHasSpellEffect(SPELL_ETHEREAL_VISAGE, OBJECT_SELF) || iNatural >= i2) - return i2; + if(GetHasSpellEffect(SPELL_ETHEREAL_VISAGE, OBJECT_SELF) || nNatural >= 2) + return 2; // Ghostly Visarge affects 1 or 0 level spells, and any spell immunity. - if(GetHasSpellEffect(SPELL_GHOSTLY_VISAGE, OBJECT_SELF) || iNatural >= i1 || + if(GetHasSpellEffect(SPELL_GHOSTLY_VISAGE, OBJECT_SELF) || nNatural >= 1 || // Or shadow con version. GetHasSpellEffect(SPELL_GREATER_SHADOW_CONJURATION_MIRROR_IMAGE, OBJECT_SELF)) - return i1; - // Return iNatural, which is 0-9 + return 1; + // Return nNatural, which is 0-9 return FALSE; } diff --git a/_module/nss/nw_c2_defaultd.nss b/_module/nss/nw_c2_defaultd.nss index 8648e08d..f676cf33 100644 --- a/_module/nss/nw_c2_defaultd.nss +++ b/_module/nss/nw_c2_defaultd.nss @@ -1,8 +1,8 @@ -/************************ [On User Defined] ************************************ - Filename: j_ai_onuserdef or nw_c2_defaultd -************************* [Workings] ******************************************* - This is NOT needed, but I have, because of new Pre-events, added it to the - files for completeness and documentation. +/*/////////////////////// [On User Defined] //////////////////////////////////// + Filename: J_AI_OnUserDef or nw_c2_defaultd +///////////////////////// [Workings] /////////////////////////////////////////// + 1.4 Adds proper Pre-event functionality. Use this to make sure you keep the + AI working, but making small additions using this event. Can be deleted to save space if you want :-) @@ -47,23 +47,29 @@ You can delete sections you don't need, and is recommended as long as you know how to use User Defined events. -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.3 - Added in with some documentation -************************* [Arguments] ****************************************** + 1.4 - Changed Pre-events. Now, it uses Execute Script. Will need to set + a special string on the creature to now what script to fire. + - It means they work correctly, however! +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: Dependant on event. See seperate event scripts. -************************* [On User Defined] ***********************************/ +///////////////////////// [On User Defined] //////////////////////////////////*/ // This contains a lot of useful things. // - Combat starting // - Constant values // - Get/Set spawn in values. -#include "j_inc_other_ai" +#include "J_INC_OTHER_AI" // This contains some useful things to get NPC's to attack and so on. -#include "j_inc_npc_attack" +#include "J_INC_NPC_ATTACK" /************************ [UDE Values] ***************************************** These are uneeded, but here for reference. Use the constants in the file "j_inc_constants" like "EVENT_HEARTBEAT_PRE_EVENT" which is classed as 1021. + * The normal death event might not fire before the creature has vanished. + Use the Pre-event (but with no stopping the death event) if you want a special + death event to happen. Name Normal-End event - Pre-Event Heartbeat Event 1001 1021 @@ -84,9 +90,11 @@ void main() { // Get the user defined number. - int iEvent = GetUserDefinedEventNumber(); + // * NOTE: YOU MUST USE AI_GetUDENumber(), not GetUserDefinedEventNumber()! + int nEvent = AI_GetUDENumber(); + // Events. - switch(iEvent) + switch(nEvent) { // Event Heartbeat // Arguments: Basically, none. Nothing activates this script. Fires every 6 seconds. diff --git a/_module/nss/nw_c2_defaulte.nss b/_module/nss/nw_c2_defaulte.nss index 5ef6f5d8..f7301cc8 100644 --- a/_module/nss/nw_c2_defaulte.nss +++ b/_module/nss/nw_c2_defaulte.nss @@ -1,6 +1,6 @@ -/************************ [On Blocked] ***************************************** - Filename: j_ai_onblocked or nw_c2_defaulte -************************* [On Blocked] ***************************************** +/*/////////////////////// [On Blocked] ///////////////////////////////////////// + Filename: J_AI_OnBlocked or nw_c2_defaulte +///////////////////////// [On Blocked] ///////////////////////////////////////// Added in user defined constant - won't open any doors. 0 = Default (even if not set) opens as appropriate 1 = Always bashes the door. @@ -16,14 +16,20 @@ Note: This also fires for blocking via. creatures. It is optimised, and works by re-targeting and doing a few small things to do with blocking. -************************* [History] ******************************************** +///////////////////////// [History] //////////////////////////////////////////// 1.0 - Opens with Knock. Unlocks door. Ignores trapped doors. 1.3 - Debug messages. - New events, even if the change of using them is small! - No ClearAllactions so any previous movings will carry on once the door is gone. - Removed debug messages - 1.3 - Added Creature reaction code -************************* [Workings] ******************************************* + - Added Creature reaction code + 1.4 - Need to add a "hands" check (done on spawn, to set a setting to not + open doors at all, IE: We do NOT have hands, do not open doors), so + its a little more realistic "out of the box" + - Fixed an instance of GetObjectSeen being repeated. + - Fixed the variable AI_DOOR_INTELLIGENCE not being got via GetAIInteger(). + - Removed unneeded else statement. +///////////////////////// [Workings] /////////////////////////////////////////// Uses simple code to deal with a door in the best way possible. Uses DoDoorAction, which is added to the top of an action queue and doesn't, @@ -31,10 +37,10 @@ is like this) Creatures are reacted by with ClearAllActions usually. -************************* [Arguments] ****************************************** +///////////////////////// [Arguments] ////////////////////////////////////////// Arguments: GetBlockingDoor, GetIsDoorActionPossible, GetLocked, GetLockKeyRequired GetLockKeyTag, GetLockUnlockDC, GetPlotFlag, DoDoorAction -************************* [On Blocked] ****************************************/ +///////////////////////// [On Blocked] ///////////////////////////////////////*/ #include "J_INC_OTHER_AI" @@ -45,10 +51,8 @@ int RangedAttack(object oTarget = OBJECT_INVALID); void main() { - // Pre-blocked-event - if(FireUserEvent(AI_FLAG_UDE_ON_BLOCKED_PRE_EVENT, EVENT_ON_BLOCKED_PRE_EVENT)) - // We may exit if it fires - if(ExitFromUDE(EVENT_ON_BLOCKED_PRE_EVENT)) return; + // Pre-on blocked-event. Returns TRUE if we interrupt this script call. + if(FirePreUserEvent(AI_FLAG_UDE_ON_BLOCKED_PRE_EVENT, EVENT_ON_BLOCKED_PRE_EVENT)) return; // AI status check. Is the AI on? if(GetAIOff()) return; @@ -74,19 +78,20 @@ void main() if(GetLocalTimer(AI_TIMER_BLOCKED)) return; // Set the timer for 1 second - SetLocalTimer(AI_TIMER_BLOCKED, f1); + SetLocalTimer(AI_TIMER_BLOCKED, 1.0); // Is it an enemy? if(GetIsEnemy(oBlocker)) { // Check if seen or heard - if(GetObjectSeen(oBlocker) || GetObjectSeen(oBlocker)) + if(GetObjectSeen(oBlocker) || GetObjectHeard(oBlocker)) { // Enemy :-) We can re-target (as know of thier presence), using // them as a target. // - This overrides even casting a spell - basically, as we should // be moving, this will re-cast it at someone or something in range SetAIObject(AI_ATTACK_SPECIFIC_OBJECT, oBlocker); + // Check if we can do combat - if we cannot, we can re-do combat // next time if(!GetIsBusyWithAction()) @@ -106,6 +111,9 @@ void main() { SetAIObject(AI_LAST_TO_GO_INVISIBLE, oBlocker); } + // Shout to allies + AISpeakString(AI_SHOUT_CALL_TO_ARMS); + // Check if we can do combat if(!GetIsBusyWithAction()) { @@ -125,42 +133,62 @@ void main() // Were we attacking in combat? object oPrevious = GetAttackTarget(); + // Check action if(GetCurrentAction() == ACTION_ATTACKOBJECT) { - // Action attack, normally means melee attack. If we can, we - // attack our previous target if seen, ELSE we will re-initate - // combat. - AISpeakString(I_WAS_ATTACKED); + // This gets set to FALSE if we can cutthrough attack, + // or whatever. + int bPreviousAttackFailed = FALSE; // Check if we can see our previous target if(GetObjectSeen(oPrevious) || (GetObjectHeard(oPrevious) && LineOfSightObject(OBJECT_SELF, oPrevious))) { // We can! see if we can re-attack with ranged weapon, else // doesn't matter we can see them - if(RangedAttack(oPrevious)) return; + bPreviousAttackFailed = RangedAttack(oPrevious); } - else - // We have not stopped the script - so determine combat - // round against nearest seen or heard enemy! - if(RangedAttack()) return; - // Else normal round to try and get a new target - ClearAllActions(); - DetermineCombatRound(); + + // If we havn't added an action yet... + if(bPreviousAttackFailed == FALSE) + { + // We have not stopped the script - so determine combat + // round against nearest seen or heard enemy! + if(!RangedAttack()) + { + // Else normal round to try and get a new target + ClearAllActions(); + DetermineCombatRound(); + } + } + // Action attack, normally means melee attack. If we can, we + // attack our previous target if seen, ELSE we will re-initate + // combat. + AISpeakString(AI_SHOUT_I_WAS_ATTACKED); + + // Fire the On blocked event as normal + FireBlockedEvent(); return; } - else // if(iAction == ACTION_CASTSPELL and others) + else // if(nAction == ACTION_CASTSPELL and others) { - // Reinitate combat + // Reinitate combat, but don't attack oPrevious ClearAllActions(); DetermineCombatRound(); + + // Action attack, normally means melee attack. If we can, we + // attack our previous target if seen, ELSE we will re-initate + // combat. + AISpeakString(AI_SHOUT_I_WAS_ATTACKED); + + // Fire the On blocked event as normal + FireBlockedEvent(); return; } } } - // Placeable - Not sure it can be returned, however, we can add it to the - // type if/else check. + // Placeable - Currently not returned, however, added just in case! else if(nBlockerType == OBJECT_TYPE_PLACEABLE) { // Check for plot, and therefore attack it to bring it down. @@ -171,26 +199,29 @@ void main() { // Do placeable action DoPlaceableObjectAction(oBlocker, PLACEABLE_ACTION_BASH); + FireBlockedEvent(); + return; } + return; } // Door behaviour else if(nBlockerType == OBJECT_TYPE_DOOR) { - int iDoorIntelligence = GetLocalInt(OBJECT_SELF, AI_DOOR_INTELLIGENCE); - int iInt = GetAbilityScore(OBJECT_SELF, ABILITY_INTELLIGENCE); - if(iDoorIntelligence == i1)// 1 = Always bashes the doors, plot, locked or anything. + int nDoorIntelligence = GetAIInteger(AI_DOOR_INTELLIGENCE); + int nInt = GetAbilityScore(OBJECT_SELF, ABILITY_INTELLIGENCE); + if(nDoorIntelligence == 1)// 1 = Always bashes the doors, plot, locked or anything. { DoDoorAction(oBlocker, DOOR_ACTION_BASH); // We re-initiate combat. FireBlockedEvent(); return; } - else if(iDoorIntelligence == i2)// 2 = Never open anything, bashing or not. + else if(nDoorIntelligence == 2)// 2 = Never open anything, bashing or not. { FireBlockedEvent(); return; } - else if(iDoorIntelligence == i3)// 3 = Never tries anything against plot doors. + else if(nDoorIntelligence == 3)// 3 = Never tries anything against plot doors. { if(GetPlotFlag(oBlocker)) { @@ -198,10 +229,10 @@ void main() return; } } - if(iInt >= i5) + if(nInt >= 5) { // Need some intelligence :-) - if(iInt >= i7) + if(nInt >= 7) { // Right, first, we may...shock...open it!!! // Checks Key, lock, trap and if the action is possible. @@ -221,17 +252,17 @@ void main() !GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_OPENING_LOCKED_DOORS, AI_OTHER_COMBAT_MASTER) && !GetLockKeyRequired(oBlocker) && GetHasSkill(SKILL_OPEN_LOCK) && GetIsDoorActionPossible(oBlocker, DOOR_ACTION_UNLOCK) && !GetIsTrapped(oBlocker) && - (GetSkillRank(SKILL_OPEN_LOCK) >= (GetLockLockDC(oBlocker) - i20))) + (GetSkillRank(SKILL_OPEN_LOCK) >= (GetLockLockDC(oBlocker) - 20))) { DoDoorAction(oBlocker, DOOR_ACTION_UNLOCK); FireBlockedEvent(); return; } // Specilist thing - knock - if(iInt >= i10) + if(nInt >= 10) { if((GetIsDoorActionPossible(oBlocker, DOOR_ACTION_KNOCK)) && - GetLockUnlockDC(oBlocker) <= i25 && + GetLockUnlockDC(oBlocker) <= 25 && !GetLockKeyRequired(oBlocker) && GetHasSpell(SPELL_KNOCK)) { DoDoorAction(oBlocker, DOOR_ACTION_KNOCK); @@ -239,16 +270,16 @@ void main() return; } } - // If Our Int is over 5, we will bash after everything else. - if(GetIsDoorActionPossible(oBlocker, DOOR_ACTION_BASH) && !GetPlotFlag(oBlocker)) + } + // If Our Int is over 5, we will bash after everything else. + if(GetIsDoorActionPossible(oBlocker, DOOR_ACTION_BASH) && !GetPlotFlag(oBlocker)) + { + if(GetAttackTarget() != oBlocker) { - if(GetAttackTarget() != oBlocker) - { - DoDoorAction(oBlocker, DOOR_ACTION_BASH); - } - FireBlockedEvent(); - return; + DoDoorAction(oBlocker, DOOR_ACTION_BASH); } + FireBlockedEvent(); + return; } } } @@ -284,11 +315,13 @@ int RangedAttack(object oTarget) // Ranged weapon attack against oTarget // doesn't matter we can see them object oRanged = GetAIObject(AI_WEAPON_RANGED); - int iAmmo = GetAIInteger(AI_WEAPON_RANGED_AMMOSLOT); + int nAmmo = GetAIInteger(AI_WEAPON_RANGED_AMMOSLOT); + // Check ammo and validness - if(GetIsObjectValid(oRanged) && (iAmmo == INVENTORY_SLOT_RIGHTHAND || - GetIsObjectValid(GetItemInSlot(iAmmo)))) + if(GetIsObjectValid(oRanged) && (nAmmo == INVENTORY_SLOT_RIGHTHAND || + GetIsObjectValid(GetItemInSlot(nAmmo)))) { + // Attack with it ClearAllActions(); ActionEquipItem(oRanged, INVENTORY_SLOT_RIGHTHAND); ActionAttack(oRangedTarget); diff --git a/_module/nss/nw_c2_herbivore.nss b/_module/nss/nw_c2_herbivore.nss index 9815b07e..40b0abea 100644 --- a/_module/nss/nw_c2_herbivore.nss +++ b/_module/nss/nw_c2_herbivore.nss @@ -29,7 +29,7 @@ void main() // These MUST be called! the AI might fail to work correctly if they don't fire! // Note: You shouldn't really remove this. Also performs hiding ETC. - DelayCommand(f2, SpawnWalkWayPoints()); + DelayCommand(2.0f, SpawnWalkWayPoints()); // Delayed walk waypoints, as to not upset instant combat spawning. // This will also check if to change to day/night posts during the walking, no heartbeats. } diff --git a/_module/nss/nw_c2_lycan_9.nss b/_module/nss/nw_c2_lycan_9.nss index 555b55b9..08d205c8 100644 --- a/_module/nss/nw_c2_lycan_9.nss +++ b/_module/nss/nw_c2_lycan_9.nss @@ -32,7 +32,7 @@ void main() } // Note: You shouldn't really remove this. Also performs hiding ETC. - DelayCommand(f2, SpawnWalkWayPoints()); + DelayCommand(2.0f, SpawnWalkWayPoints()); // Delayed walk waypoints, as to not upset instant combat spawning. // This will also check if to change to day/night posts during the walking, no heartbeats. } diff --git a/_module/nss/nw_c2_omnivore.nss b/_module/nss/nw_c2_omnivore.nss index 3eb227e7..51e1e941 100644 --- a/_module/nss/nw_c2_omnivore.nss +++ b/_module/nss/nw_c2_omnivore.nss @@ -31,7 +31,7 @@ void main() // These MUST be called! the AI might fail to work correctly if they don't fire! // Note: You shouldn't really remove this. Also performs hiding ETC. - DelayCommand(f2, SpawnWalkWayPoints()); + DelayCommand(2.0f, SpawnWalkWayPoints()); // Delayed walk waypoints, as to not upset instant combat spawning. // This will also check if to change to day/night posts during the walking, no heartbeats. } diff --git a/_module/nss/rakshasachange.nss b/_module/nss/rakshasachange.nss index ba40a536..74a69db6 100644 --- a/_module/nss/rakshasachange.nss +++ b/_module/nss/rakshasachange.nss @@ -19,7 +19,7 @@ void main() int nUser = GetUserDefinedEventNumber(); int nChange = GetLocalInt(OBJECT_SELF,"NW_LYCANTHROPE"); - effect eShape = EffectPolymorph(POLYMORPH_TYPE_RAKSHASA); //Use one of the polymorph constants here (WERE_RAT, WERE_WOLF or WERE_CAT) + effect eShape = EffectPolymorph(88); //Use one of the polymorph constants here (WERE_RAT, WERE_WOLF or WERE_CAT) effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD); if(nUser == 1005 && nChange == 0) { diff --git a/_module/nss/statue.nss b/_module/nss/statue.nss index a38778d7..cd6aef10 100644 --- a/_module/nss/statue.nss +++ b/_module/nss/statue.nss @@ -54,3 +54,4 @@ void main() effect eStatue = EffectPetrify(); ApplyEffectToObject(DURATION_TYPE_PERMANENT, eStatue, OBJECT_SELF); +} \ No newline at end of file diff --git a/_module/nss/x2_act_ws_makeme.nss b/_module/nss/x2_act_ws_makeme.nss index b1384021..1836425c 100644 --- a/_module/nss/x2_act_ws_makeme.nss +++ b/_module/nss/x2_act_ws_makeme.nss @@ -11,17 +11,10 @@ //:: Created On: September 2003 //::////////////////////////////////////////////// #include "x2_inc_ws_smith" -//#include "x2_inc_cutscene" - - -//void StartCutscene(object oPC); -//void StartCutscene2(object oPC); void CopyUpgradeItem(object oItem, object oPC); void MakeNewWeapon(object oPC); -//int nCutsceneNumber = 114; - void main() { object oPC = GetPCSpeaker(); @@ -33,273 +26,8 @@ void main() { return; } - - //ActionPauseConversation(); - - //if(GetTag(GetArea(oPC)) != "HellbreathTavern") - { - //Only show the cutscene once - //if (GetLocalInt(oPC, "X2_Chapter2SmithCut") == 1) - //{ - // MakeNewWeapon(oPC); - // return; - // } - // SetLocalInt(oPC, "X2_Chapter2SmithCut", 1); - // DelayCommand(0.7, StartCutscene(oPC)); - //} - //else - //{ - //Only show the cutscene once - //if (GetLocalInt(oPC, "X2_Chapter3SmithCut") == 1) - //{ - //MakeNewWeapon(oPC); - //return; - //} - // SetLocalInt(oPC, "X2_Chapter3SmithCut", 1); - // DelayCommand(0.7, StartCutscene2(oPC)); - //} - - //Set Cutscene 114 as active for all future calls to Cut_ commands - //CutSetActiveCutscene(nCutsceneNumber, CUT_DELAY_TYPE_CONSTANT); - - //AssignCommand(oPC, ClearAllActions()); - //Fade PCs to black - //BlackScreen(oPC); - //CutSetActiveCutsceneForObject(oPC, nCutsceneNumber, TRUE); - //CutDisableAbort(nCutsceneNumber); - - //CutSetCutsceneMode(0.5, oPC, TRUE, TRUE, TRUE, TRUE); // pc invis - keep and freeze associates - - //CutFadeFromBlack(1.5, oPC, FADE_SPEED_MEDIUM, FALSE); - - -//} - -//void StartCutscene(object oPC) -//{ - - //Change the Music - //object oArea = GetArea(oPC); - //MusicBattlePlay(oArea); - // Cutscene actors and objects. - // Invisible creature "takes" item - - //location lLoc = GetLocation(GetNearestObjectByTag("SpawnHere")); - //object oHelper = CreateObject(OBJECT_TYPE_CREATURE, "x2_helper", lLoc); - //object oSmith = OBJECT_SELF; - //object oForge = GetNearestObjectByTag("x2_magic_forge"); - - //CutSetActiveCutsceneForObject(oHelper, nCutsceneNumber); - //CutSetActiveCutsceneForObject(oSmith, nCutsceneNumber); - //CutSetActiveCutsceneForObject(oForge, nCutsceneNumber); - - //CutApplyEffectToObject2(0.0, DURATION_TYPE_PERMANENT, EffectCutsceneGhost(), oHelper); - //Locations - //location lForge = GetLocation(GetNearestObjectByTag("X2_Forge")); - - //Camera waypoints - //object oCamera1 = GetNearestObjectByTag("wp_cut114_camera1"); - //location lCamera1 = GetLocation(GetNearestObjectByTag("wp_cut114_camera1")); - //location lCamera2 = GetLocation(GetNearestObjectByTag("wp_cut114_camera2")); - - //Make a copy of the PC to move about - //location lStart = GetLocation(oPC); - //object oCopy = CutCreatePCCopy(oPC, lStart, "Cut114PCCopy"); - //ChangeToStandardFaction(oCopy, STANDARD_FACTION_COMMONER); - //CutSetActiveCutsceneForObject(oCopy, nCutsceneNumber); - - // Camera movements (includes moving the PC as the camera. - ////////////////////////////////////////////////////////// - //CutJumpToObject(0.0, oPC, oCamera1, TRUE); - //CutSetCamera(0.0, oPC, CAMERA_MODE_TOP_DOWN, 90.0, 10.0, 75.0, - // CAMERA_TRANSITION_TYPE_SNAP); - //CutSetCamera(0.2, oPC, CAMERA_MODE_TOP_DOWN, 150.0, 13.0, 50.0, - //CAMERA_TRANSITION_TYPE_SLOW); - - //CutActionMoveToLocation(0.2, oPC, lCamera2, FALSE, FALSE); - // Smith chants - //CutPlayAnimation(0.7, oSmith, ANIMATION_LOOPING_MEDITATE, 6.0, FALSE); - // CutPlaySound(0.5, oSmith, "al_mg_chntmagic1", FALSE); - - - // * Make creature invisible and non bumpable - // effect eInvis = EffectVisualEffect(VFX_DUR_CUTSCENE_INVISIBILITY); - // ApplyEffectToObject(DURATION_TYPE_PERMANENT, eInvis, oHelper); - //effect eNoBump = EffectCutsceneGhost(); - //CutApplyEffectToObject2(0.0, DURATION_TYPE_PERMANENT, eNoBump, oHelper); - - //object oItem = GetRightHandWeapon(oCopy); - // object oItem2 = GetRightHandWeapon(oPC); - -// SpeakString("OLD " + GetName(oItem)); -// object oNewItem = CopyItem(oItem, oHelper, TRUE); -// SpeakString("NEW " + GetName(oNewItem)); - - //AssignCommand(oPC, ActionUnequipItem(oItem)); // * unequip the item - //object oNewItem = CopyItem(oItem, oCopy, TRUE); - - // DelayCommand(2.0, AssignCommand(oCopy, ActionGiveItem(oNewItem, oHelper))); - - //DestroyObject(oItem, 2.0); - //DestroyObject(oItem2, 2.0); - //CutClearAllActions(1.5, oHelper, FALSE); - //CutActionEquipItem(2.4, oHelper, oNewItem, INVENTORY_SLOT_RIGHTHAND); - - // Runs up to forge - - //CutActionMoveToLocation(3.0, oHelper, lForge, FALSE, FALSE); - - // * Need visual effects to hide the sword moving from you to the object - // Light up Forge - // effect eStrike = EffectVisualEffect(VFX_FNF_STRIKE_HOLY); - //effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_BUMP); - //effect eLink = EffectLinkEffects(eStrike, eShake); - //CutApplyEffectToObject2(5.0, DURATION_TYPE_INSTANT, eLink, oForge); - //CutPlayAnimation(5.0, oForge, ANIMATION_PLACEABLE_ACTIVATE, 5.0, FALSE); - - // effect eRing = EffectVisualEffect(VFX_DUR_ELEMENTAL_SHIELD); - // CutApplyEffectToObject(6.1, DURATION_TYPE_TEMPORARY, VFX_DUR_ELEMENTAL_SHIELD, oHelper, 0.7); - - // Item is enhanced - //DelayCommand(6.0, wsEnhanceItem(oHelper, oPC)); - - //Copy the upgraded item into the PCs inventory - //DelayCommand(7.0, CopyUpgradeItem(oNewItem, oPC)); - - //CutPlayAnimation(6.0, oHelper, ANIMATION_FIREFORGET_VICTORY2, 3.0, FALSE); - - // Weapon Given back to player - //CutClearAllActions(7.5, oHelper, FALSE, FALSE); - //CutActionMoveToObject(8.0, oHelper, oCopy, TRUE); - // DelayCommand(9.7, AssignCommand(oHelper, ActionGiveItem(oNewItem, oCopy))); - //DelayCommand(11.0, AssignCommand(oCopy, ActionEquipItem(oNewItem, INVENTORY_SLOT_RIGHTHAND))); - //CutPlayAnimation(12.0, oCopy, ANIMATION_FIREFORGET_VICTORY2, 2.0); - // End Cutscene - - //CutFadeOutAndIn(13.0, oPC); - - - //Clean up actors... - //CutDestroyObject(14.3, oHelper); - - //CutDisableCutscene(nCutsceneNumber, 14.5, 14.5, RESTORE_TYPE_COPY); - - // * Resume conversation - Cleanup - - //DelayCommand(15.5, ActionResumeConversation()); - } -//void StartCutscene2(object oPC) -{ - //Change the Music - //object oArea = GetArea(oPC); - //MusicBattlePlay(oArea); - // Cutscene actors and objects. - // Invisible creature "takes" item - - //location lLoc = GetLocation(GetNearestObjectByTag("SpawnHere")); - //object oHelper = CreateObject(OBJECT_TYPE_CREATURE, "x2_helper", lLoc); - //object oSmith = OBJECT_SELF; - //object oForge = GetNearestObjectByTag("x2_magic_forge"); - - //CutSetActiveCutsceneForObject(oHelper, nCutsceneNumber); - //CutSetActiveCutsceneForObject(oSmith, nCutsceneNumber); - //CutSetActiveCutsceneForObject(oForge, nCutsceneNumber); - //Locations - // location lForge = GetLocation(GetNearestObjectByTag("X2_Forge")); - - //Camera waypoints - //object oCamera1 = GetNearestObjectByTag("wp_cut114_camera1"); - // location lCamera1 = GetLocation(GetNearestObjectByTag("wp_cut114_camera1")); - //location lCamera2 = GetLocation(GetNearestObjectByTag("wp_cut114_camera2")); - - //Make a copy of the PC to move about - //location lStart = GetLocation(GetNearestObjectByTag("hx_smith_wp", oPC)); - //object oCopy = CutCreatePCCopy(oPC, lStart, "Cut114PCCopy"); - //ChangeToStandardFaction(oCopy, STANDARD_FACTION_COMMONER); - //CutSetActiveCutsceneForObject(oCopy, nCutsceneNumber); - - // Camera movements (includes moving the PC as the camera. - ////////////////////////////////////////////////////////// - //CutJumpToObject(0.0, oPC, oCamera1, TRUE); - //CutSetCamera(0.0, oPC, CAMERA_MODE_TOP_DOWN, 40.0, 6.0, 80.0, - // CAMERA_TRANSITION_TYPE_SNAP); - // CutSetCamera(0.2, oPC, CAMERA_MODE_TOP_DOWN, 40.0, 3.0, 80.0, - // CAMERA_TRANSITION_TYPE_VERY_SLOW); - // Smith chants - //CutPlayAnimation(0.7, oSmith, ANIMATION_LOOPING_MEDITATE, 6.0, FALSE); - //CutPlaySound(0.5, oSmith, "al_mg_chntmagic1", FALSE); - - - // * Make creature invisible and non bumpable - // effect eInvis = EffectVisualEffect(VFX_DUR_CUTSCENE_INVISIBILITY); - // ApplyEffectToObject(DURATION_TYPE_PERMANENT, eInvis, oHelper); - //effect eNoBump = EffectCutsceneGhost(); - // CutApplyEffectToObject2(0.0, DURATION_TYPE_PERMANENT, eNoBump, oHelper); - - // object oItem = GetRightHandWeapon(oCopy); - // object oItem2 = GetRightHandWeapon(oPC); - -// SpeakString("OLD " + GetName(oItem)); -// object oNewItem = CopyItem(oItem, oHelper, TRUE); -// SpeakString("NEW " + GetName(oNewItem)); - - //AssignCommand(oPC, ActionUnequipItem(oItem)); // * unequip the item - //object oNewItem = CopyItem(oItem, oCopy, TRUE); - - // - //DelayCommand(2.0, AssignCommand(oCopy, ActionGiveItem(oNewItem, oHelper))); - - // DestroyObject(oItem, 2.0); - // DestroyObject(oItem2, 2.0); - //CutClearAllActions(1.5, oHelper, FALSE); - //CutActionEquipItem(2.4, oHelper, oNewItem, INVENTORY_SLOT_RIGHTHAND); - - // Runs up to forge - - //CutActionMoveToLocation(3.0, oHelper, lForge, FALSE, FALSE); - - // * Need visual effects to hide the sword moving from you to the object - // Light up Forge - //effect eStrike = EffectVisualEffect(VFX_FNF_STRIKE_HOLY); - //effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_BUMP); - //effect eLink = EffectLinkEffects(eStrike, eShake); - //CutApplyEffectToObject2(5.0, DURATION_TYPE_INSTANT, eLink, oForge); - //CutPlayAnimation(5.0, oForge, ANIMATION_PLACEABLE_ACTIVATE, 5.0, FALSE); - - //effect eRing = EffectVisualEffect(VFX_DUR_ELEMENTAL_SHIELD); - //CutApplyEffectToObject(6.1, DURATION_TYPE_TEMPORARY, VFX_DUR_ELEMENTAL_SHIELD, oHelper, 0.7); - - // Item is enhanced - // DelayCommand(6.0, wsEnhanceItem(oHelper, oPC)); - - //Copy the upgraded item into the PCs inventory - //DelayCommand(7.0, CopyUpgradeItem(oNewItem, oPC)); - - //CutPlayAnimation(6.0, oHelper, ANIMATION_FIREFORGET_VICTORY2, 3.0, FALSE); - - // Weapon Given back to player - //CutClearAllActions(7.5, oHelper, FALSE, FALSE); - //CutActionMoveToObject(8.0, oHelper, oCopy, TRUE); - //DelayCommand(9.7, AssignCommand(oHelper, ActionGiveItem(oNewItem, oCopy))); - //DelayCommand(11.0, AssignCommand(oCopy, ActionEquipItem(oNewItem, INVENTORY_SLOT_RIGHTHAND))); - // CutPlayAnimation(12.0, oCopy, ANIMATION_FIREFORGET_VICTORY2, 2.0); - // End Cutscene - - //CutFadeOutAndIn(13.0, oPC); - - - //Clean up actors... - //CutDestroyObject(14.3, oHelper); - - //CutDisableCutscene(nCutsceneNumber, 14.5, 14.5, RESTORE_TYPE_COPY); - - // * Resume conversation - Cleanup - - // DelayCommand(15.5, ActionResumeConversation()); -//} - void CopyUpgradeItem(object oItem, object oPC) { object oNewItem = CopyItem(oItem, oPC, TRUE); diff --git a/_module/ra_tdog.mod b/_module/ra_tdog.mod index 89605066..df09d841 100644 Binary files a/_module/ra_tdog.mod and b/_module/ra_tdog.mod differ diff --git a/_notes/Maps/1C.jpeg b/_notes/Maps/1C.jpeg new file mode 100644 index 00000000..26bcdc2c Binary files /dev/null and b/_notes/Maps/1C.jpeg differ diff --git a/_notes/Maps/2B.jpeg b/_notes/Maps/2B.jpeg new file mode 100644 index 00000000..2edce508 Binary files /dev/null and b/_notes/Maps/2B.jpeg differ diff --git a/_notes/Maps/3C.jpeg b/_notes/Maps/3C.jpeg new file mode 100644 index 00000000..cfabcdf8 Binary files /dev/null and b/_notes/Maps/3C.jpeg differ diff --git a/_notes/Maps/4B_A.jpeg b/_notes/Maps/4B_A.jpeg new file mode 100644 index 00000000..97059b87 Binary files /dev/null and b/_notes/Maps/4B_A.jpeg differ diff --git a/_notes/Maps/4B_B.jpeg b/_notes/Maps/4B_B.jpeg new file mode 100644 index 00000000..aa9a175f Binary files /dev/null and b/_notes/Maps/4B_B.jpeg differ diff --git a/_notes/Maps/4B_C_Lower_Level.jpeg b/_notes/Maps/4B_C_Lower_Level.jpeg new file mode 100644 index 00000000..140f503d Binary files /dev/null and b/_notes/Maps/4B_C_Lower_Level.jpeg differ diff --git a/_notes/Maps/4B_C_Upper_Level.jpeg b/_notes/Maps/4B_C_Upper_Level.jpeg new file mode 100644 index 00000000..2063a56d Binary files /dev/null and b/_notes/Maps/4B_C_Upper_Level.jpeg differ diff --git a/_notes/Maps/4B_D.jpeg b/_notes/Maps/4B_D.jpeg new file mode 100644 index 00000000..b9218402 Binary files /dev/null and b/_notes/Maps/4B_D.jpeg differ diff --git a/_notes/Maps/4B_E.jpeg b/_notes/Maps/4B_E.jpeg new file mode 100644 index 00000000..792d783b Binary files /dev/null and b/_notes/Maps/4B_E.jpeg differ diff --git a/_notes/Maps/4B_F.jpeg b/_notes/Maps/4B_F.jpeg new file mode 100644 index 00000000..b2f49753 Binary files /dev/null and b/_notes/Maps/4B_F.jpeg differ diff --git a/_notes/Maps/CastleCalaelen.jpeg b/_notes/Maps/CastleCalaelen.jpeg new file mode 100644 index 00000000..72fe7131 Binary files /dev/null and b/_notes/Maps/CastleCalaelen.jpeg differ diff --git a/_notes/Maps/TunnelsOfTerror.jpg b/_notes/Maps/TunnelsOfTerror.jpg new file mode 100644 index 00000000..dc479f15 Binary files /dev/null and b/_notes/Maps/TunnelsOfTerror.jpg differ